failproofai 1.0.0 → 1.0.1-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (238) hide show
  1. package/.next/standalone/.next/BUILD_ID +1 -1
  2. package/.next/standalone/.next/app-path-routes-manifest.json +0 -1
  3. package/.next/standalone/.next/build-manifest.json +3 -3
  4. package/.next/standalone/.next/prerender-manifest.json +5 -5
  5. package/.next/standalone/.next/required-server-files.json +1 -1
  6. package/.next/standalone/.next/routes-manifest.json +0 -6
  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 +4 -3
  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 +6 -6
  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/_tree.segment.rsc +1 -1
  16. package/.next/standalone/.next/server/app/_not-found/page/server-reference-manifest.json +1 -1
  17. package/.next/standalone/.next/server/app/_not-found/page.js +4 -3
  18. package/.next/standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
  19. package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  20. package/.next/standalone/.next/server/app/_not-found.html +1 -1
  21. package/.next/standalone/.next/server/app/_not-found.rsc +15 -15
  22. package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +15 -15
  23. package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +14 -14
  24. package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  25. package/.next/standalone/.next/server/app/api/audit/invite/route.js +2 -2
  26. package/.next/standalone/.next/server/app/api/audit/invite/route.js.nft.json +1 -1
  27. package/.next/standalone/.next/server/app/api/audit/run/route.js +3 -3
  28. package/.next/standalone/.next/server/app/api/audit/run/route.js.nft.json +1 -1
  29. package/.next/standalone/.next/server/app/api/audit/status/route.js +2 -2
  30. package/.next/standalone/.next/server/app/api/audit/status/route.js.nft.json +1 -1
  31. package/.next/standalone/.next/server/app/api/auth/login-request/route.js +4 -3
  32. package/.next/standalone/.next/server/app/api/auth/login-request/route.js.nft.json +1 -1
  33. package/.next/standalone/.next/server/app/api/auth/login-verify/route.js +2 -2
  34. package/.next/standalone/.next/server/app/api/auth/login-verify/route.js.nft.json +1 -1
  35. package/.next/standalone/.next/server/app/api/auth/logout/route.js +3 -2
  36. package/.next/standalone/.next/server/app/api/auth/logout/route.js.nft.json +1 -1
  37. package/.next/standalone/.next/server/app/api/auth/status/route.js +4 -3
  38. package/.next/standalone/.next/server/app/api/auth/status/route.js.nft.json +1 -1
  39. package/.next/standalone/.next/server/app/api/download/[project]/[session]/route.js.nft.json +1 -1
  40. package/.next/standalone/.next/server/app/audit/page/server-reference-manifest.json +2 -2
  41. package/.next/standalone/.next/server/app/audit/page.js +5 -3
  42. package/.next/standalone/.next/server/app/audit/page.js.nft.json +1 -1
  43. package/.next/standalone/.next/server/app/audit/page_client-reference-manifest.js +1 -1
  44. package/.next/standalone/.next/server/app/index.html +1 -1
  45. package/.next/standalone/.next/server/app/index.rsc +15 -15
  46. package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +14 -14
  47. package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +15 -15
  48. package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -2
  49. package/.next/standalone/.next/server/app/page/server-reference-manifest.json +1 -1
  50. package/.next/standalone/.next/server/app/page.js +4 -3
  51. package/.next/standalone/.next/server/app/page.js.nft.json +1 -1
  52. package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  53. package/.next/standalone/.next/server/app/policies/page/server-reference-manifest.json +10 -10
  54. package/.next/standalone/.next/server/app/policies/page.js +6 -5
  55. package/.next/standalone/.next/server/app/policies/page.js.nft.json +1 -1
  56. package/.next/standalone/.next/server/app/policies/page_client-reference-manifest.js +1 -1
  57. package/.next/standalone/.next/server/app/project/[name]/page/server-reference-manifest.json +1 -1
  58. package/.next/standalone/.next/server/app/project/[name]/page.js +5 -4
  59. package/.next/standalone/.next/server/app/project/[name]/page.js.nft.json +1 -1
  60. package/.next/standalone/.next/server/app/project/[name]/page_client-reference-manifest.js +1 -1
  61. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/react-loadable-manifest.json +2 -2
  62. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/server-reference-manifest.json +2 -2
  63. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page.js +6 -4
  64. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page.js.nft.json +1 -1
  65. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page_client-reference-manifest.js +1 -1
  66. package/.next/standalone/.next/server/app/projects/page/server-reference-manifest.json +1 -1
  67. package/.next/standalone/.next/server/app/projects/page.js +5 -4
  68. package/.next/standalone/.next/server/app/projects/page.js.nft.json +1 -1
  69. package/.next/standalone/.next/server/app/projects/page_client-reference-manifest.js +1 -1
  70. package/.next/standalone/.next/server/app/settings/page/server-reference-manifest.json +4 -4
  71. package/.next/standalone/.next/server/app/settings/page.js +6 -4
  72. package/.next/standalone/.next/server/app/settings/page.js.nft.json +1 -1
  73. package/.next/standalone/.next/server/app/settings/page_client-reference-manifest.js +1 -1
  74. package/.next/standalone/.next/server/app-paths-manifest.json +0 -1
  75. package/.next/standalone/.next/server/chunks/[root-of-the-server]__05ja_05._.js +3 -0
  76. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0agdw2a._.js +3 -0
  77. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0d1u_na._.js +1 -1
  78. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0nne229._.js +3 -0
  79. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0ny9q5d._.js +1 -1
  80. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0oy4kxb._.js +3 -0
  81. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0zf034w._.js +3 -0
  82. package/.next/standalone/.next/server/chunks/[root-of-the-server]__17g9wh7._.js +3 -0
  83. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1hstmft._.js +3 -0
  84. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1p8poxd._.js +3 -0
  85. package/.next/standalone/.next/server/chunks/_0lxbzdq._.js +1 -1
  86. package/.next/standalone/.next/server/chunks/_1ek68ln._.js +1 -1
  87. package/.next/standalone/.next/server/chunks/_1zuiiy3._.js +1 -1
  88. package/.next/standalone/.next/server/chunks/lib_telemetry_ts_0dctyyw._.js +1 -1
  89. package/.next/standalone/.next/server/chunks/{node_modules_posthog-node_dist_entrypoints_index_node_mjs_0jx6cp6._.js → node_modules_posthog-node_dist_entrypoints_index_node_mjs_0f-x2b0._.js} +1 -1
  90. package/.next/standalone/.next/server/chunks/{node_modules_posthog-node_dist_entrypoints_index_node_mjs_1f290jp._.js → node_modules_posthog-node_dist_entrypoints_index_node_mjs_0hwvl7e._.js} +1 -1
  91. package/.next/standalone/.next/server/chunks/{node_modules_posthog-node_dist_entrypoints_index_node_mjs_1g2ji1t._.js → node_modules_posthog-node_dist_entrypoints_index_node_mjs_1ctjdzl._.js} +1 -1
  92. package/.next/standalone/.next/server/chunks/package_json_[json]_cjs_1nxcc4v._.js +1 -1
  93. package/.next/standalone/.next/server/chunks/src_hooks_fp-home_ts_09kv0bn._.js +3 -0
  94. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__03eykvd._.js +5 -0
  95. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__07175vb._.js → [root-of-the-server]__07oh8b5._.js} +1 -1
  96. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0cxe_2_._.js +1 -1
  97. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0g2rg69._.js +3 -0
  98. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0kgy9da._.js +4 -0
  99. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0m98kzy._.js +4 -0
  100. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0oa1lav._.js +3 -0
  101. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0sjzdjg._.js +3 -0
  102. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0spkm68._.js +2 -2
  103. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0v5_91z._.js +4 -0
  104. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1-a3135._.js +4 -0
  105. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__1hvwiw8._.js → [root-of-the-server]__11z_299._.js} +1 -1
  106. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__1apc90t._.js → [root-of-the-server]__15c_z97._.js} +1 -1
  107. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__1wmno1q._.js → [root-of-the-server]__17d_ffl._.js} +1 -1
  108. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1_dfocn._.js +4 -0
  109. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1e5g_ur._.js +4 -0
  110. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1hmqefd._.js +4 -0
  111. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1jiwfsj._.js +1 -1
  112. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1kzapg5._.js +6 -0
  113. package/.next/standalone/.next/server/chunks/ssr/_04j57fb._.js +3 -0
  114. package/.next/standalone/.next/server/chunks/ssr/_05enntk._.js +3 -0
  115. package/.next/standalone/.next/server/chunks/ssr/_08x1r5t._.js +3 -0
  116. package/.next/standalone/.next/server/chunks/ssr/_0hom1s1._.js +3 -0
  117. package/.next/standalone/.next/server/chunks/ssr/_1nq-35m._.js +23 -0
  118. package/.next/standalone/.next/server/chunks/ssr/_1q7j05x._.js +3 -0
  119. package/.next/standalone/.next/server/chunks/ssr/_1ylae7o._.js +3 -0
  120. package/.next/standalone/.next/server/chunks/ssr/app_audit__components_audit-dashboard_tsx_0p9ud47._.js +2 -2
  121. package/.next/standalone/.next/server/chunks/ssr/app_global-error_tsx_1kp6l3x._.js +1 -1
  122. package/.next/standalone/.next/server/chunks/ssr/app_policies_hooks-client_tsx_19dqvpc._.js +2 -2
  123. package/.next/standalone/.next/server/chunks/ssr/app_settings_settings-client_tsx_20lq-mq._.js +3 -0
  124. package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_1n3w9lb._.js +1 -1
  125. package/.next/standalone/.next/server/chunks/ssr/src_hooks_builtin-policies_ts_09j2ndl._.js +1 -1
  126. package/.next/standalone/.next/server/chunks/ssr/src_hooks_fp-config_ts_04t589g._.js +4 -0
  127. package/.next/standalone/.next/server/chunks/ssr/src_hooks_fp-home_ts_0je3xkv._.js +3 -0
  128. package/.next/standalone/.next/server/middleware-build-manifest.js +3 -3
  129. package/.next/standalone/.next/server/pages/404.html +1 -1
  130. package/.next/standalone/.next/server/pages/500.html +1 -1
  131. package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
  132. package/.next/standalone/.next/server/server-reference-manifest.json +15 -15
  133. package/.next/standalone/.next/static/chunks/00q6cfzuzpc85.js +1 -0
  134. package/.next/standalone/.next/static/chunks/{0zm3_8jpqitxy.js → 054eg7y_cjyf9.js} +22 -22
  135. package/.next/standalone/.next/static/chunks/{2ouq44jv_0x04.js → 0mjufa_0xxz75.js} +1 -1
  136. package/.next/standalone/.next/static/chunks/0u64yey446k4f.css +1 -0
  137. package/.next/standalone/.next/static/chunks/{0zi8zjav5a4rq.js → 1-oz4co31nvc5.js} +1 -1
  138. package/.next/standalone/.next/static/chunks/13--2yvqek_s1.js +1 -0
  139. package/.next/standalone/.next/static/chunks/136ldjmzxhush.js +1 -0
  140. package/.next/standalone/.next/static/chunks/18fqy3doo2ial.js +6 -0
  141. package/.next/standalone/.next/static/chunks/1eyl7fzkmnkf_.js +1 -0
  142. package/.next/standalone/.next/static/chunks/{31k3yxpy57_fy.js → 1o5sxp_mdaoci.js} +1 -1
  143. package/.next/standalone/.next/static/chunks/29-iqnp9v_axt.css +1 -0
  144. package/.next/standalone/.next/static/chunks/{2676v-lyzgo91.js → 2es4z1ei90vsv.js} +1 -1
  145. package/.next/standalone/.next/static/chunks/2k9f4tyv04809.css +1 -0
  146. package/.next/standalone/.next/static/chunks/3peix2vxzj7eh.js +1 -0
  147. package/.next/standalone/.next/static/chunks/3qfoeqhy5l10x.js +1 -0
  148. package/.next/standalone/.next/static/chunks/{0km-jn9o5xyqs.css → 3wq9x0c-7ld5d.css} +1 -1
  149. package/.next/standalone/app/actions/get-scheduled-audit.ts +65 -6
  150. package/.next/standalone/app/actions/update-scheduled-audit.ts +90 -17
  151. package/.next/standalone/app/api/auth/status/route.ts +7 -17
  152. package/.next/standalone/app/audit/_components/audit-dashboard.tsx +2 -6
  153. package/.next/standalone/app/audit/_components/come-back-better-section.tsx +101 -281
  154. package/.next/standalone/app/audit/_components/empty-state.tsx +2 -2
  155. package/.next/standalone/app/audit/_components/run-progress.tsx +1 -1
  156. package/.next/standalone/app/audit/audit-styles.css +150 -26
  157. package/.next/standalone/app/globals.css +39 -1
  158. package/.next/standalone/app/settings/page.tsx +38 -21
  159. package/.next/standalone/app/settings/settings-client.tsx +583 -392
  160. package/.next/standalone/app/settings/settings.css +354 -0
  161. package/.next/standalone/components/navbar.tsx +33 -4
  162. package/.next/standalone/lib/auth/api-server-client.ts +51 -29
  163. package/.next/standalone/lib/auth/auth-store.ts +44 -59
  164. package/.next/standalone/package.json +12 -10
  165. package/.next/standalone/server.js +1 -1
  166. package/bin/failproofai.mjs +6 -0
  167. package/bin/failproofaid-shim.mjs +0 -0
  168. package/dist/cli.mjs +1889 -426
  169. package/dist/worker.mjs +27 -5
  170. package/lib/auth/api-server-client.ts +51 -29
  171. package/lib/auth/auth-store.ts +44 -59
  172. package/package.json +12 -10
  173. package/scripts/docs-audit.ts +493 -0
  174. package/scripts/translate-docs/cli.ts +16 -2
  175. package/scripts/translate-docs/mdx-translator.ts +6 -1
  176. package/scripts/translate-docs/readme-translator.ts +4 -2
  177. package/src/audit/cli-login.ts +330 -0
  178. package/src/audit/cli.ts +124 -6
  179. package/src/audit/dashboard-cache.ts +44 -8
  180. package/src/audit/harm-report.ts +260 -0
  181. package/src/audit/machine-store.ts +120 -0
  182. package/src/audit/redact-example.ts +312 -0
  183. package/src/audit/report-harm.ts +167 -0
  184. package/src/audit/schedule-cli.ts +352 -0
  185. package/src/hooks/builtin-policies.ts +26 -0
  186. package/src/hooks/daemon-service.ts +76 -0
  187. package/src/hooks/fp-config.ts +96 -5
  188. package/src/hooks/fp-home.ts +118 -8
  189. package/src/hooks/fp-reset.ts +79 -9
  190. package/src/hooks/migrations.ts +241 -4
  191. package/src/hooks/tui.ts +61 -3
  192. package/.next/standalone/.next/server/app/api/auth/reminder/route/app-paths-manifest.json +0 -3
  193. package/.next/standalone/.next/server/app/api/auth/reminder/route/build-manifest.json +0 -12
  194. package/.next/standalone/.next/server/app/api/auth/reminder/route/server-reference-manifest.json +0 -4
  195. package/.next/standalone/.next/server/app/api/auth/reminder/route.js +0 -9
  196. package/.next/standalone/.next/server/app/api/auth/reminder/route.js.map +0 -5
  197. package/.next/standalone/.next/server/app/api/auth/reminder/route.js.nft.json +0 -1
  198. package/.next/standalone/.next/server/app/api/auth/reminder/route_client-reference-manifest.js +0 -3
  199. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0-xggru._.js +0 -3
  200. package/.next/standalone/.next/server/chunks/[root-of-the-server]__00ds05_._.js +0 -3
  201. package/.next/standalone/.next/server/chunks/[root-of-the-server]__094p1f1._.js +0 -3
  202. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1dxagv_._.js +0 -3
  203. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1fgqj1_._.js +0 -3
  204. package/.next/standalone/.next/server/chunks/_084toou._.js +0 -3
  205. package/.next/standalone/.next/server/chunks/_0g4t8c9._.js +0 -3
  206. package/.next/standalone/.next/server/chunks/_0km521a._.js +0 -3
  207. package/.next/standalone/.next/server/chunks/_0t8kefc._.js +0 -3
  208. package/.next/standalone/.next/server/chunks/_16dwkfn._.js +0 -3
  209. package/.next/standalone/.next/server/chunks/_1phm9ui._.js +0 -3
  210. package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_auth_reminder_route_actions_1kjgxf8.js +0 -3
  211. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0dk8r_l._.js +0 -3
  212. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0kviq2m._.js +0 -3
  213. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0ogyhu0._.js +0 -3
  214. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1-rfu32._.js +0 -5
  215. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1mmefsr._.js +0 -5
  216. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1t62w37._.js +0 -3
  217. package/.next/standalone/.next/server/chunks/ssr/_032wo7w._.js +0 -3
  218. package/.next/standalone/.next/server/chunks/ssr/_08840em._.js +0 -3
  219. package/.next/standalone/.next/server/chunks/ssr/_0gl2ujp._.js +0 -3
  220. package/.next/standalone/.next/server/chunks/ssr/_0j0ggkc._.js +0 -3
  221. package/.next/standalone/.next/server/chunks/ssr/_0kbv5-q._.js +0 -3
  222. package/.next/standalone/.next/server/chunks/ssr/_0r1jgvp._.js +0 -3
  223. package/.next/standalone/.next/server/chunks/ssr/_0t5xq1b._.js +0 -3
  224. package/.next/standalone/.next/server/chunks/ssr/_0w_be0g._.js +0 -3
  225. package/.next/standalone/.next/server/chunks/ssr/_15gba46._.js +0 -5
  226. package/.next/standalone/.next/server/chunks/ssr/_1qyhb9r._.js +0 -23
  227. package/.next/standalone/.next/server/chunks/ssr/_1vel2ey._.js +0 -3
  228. package/.next/standalone/.next/static/chunks/0wd503tv801gy.js +0 -1
  229. package/.next/standalone/.next/static/chunks/1hfocb0sdl85c.js +0 -1
  230. package/.next/standalone/.next/static/chunks/1v1gqvpjk62jm.js +0 -1
  231. package/.next/standalone/.next/static/chunks/2kopjq_or743g.js +0 -6
  232. package/.next/standalone/.next/static/chunks/2uvhw57mf9lg_.css +0 -2
  233. package/.next/standalone/.next/static/chunks/2ynl0-6aqng_b.js +0 -1
  234. package/.next/standalone/.next/static/chunks/3xvtgz6arztp_.js +0 -1
  235. package/.next/standalone/app/api/auth/reminder/route.ts +0 -213
  236. /package/.next/standalone/.next/static/{Aulh3DRWwRfwh2POCvZR_ → jSKB7CQQSNTX-uSbY2bUs}/_buildManifest.js +0 -0
  237. /package/.next/standalone/.next/static/{Aulh3DRWwRfwh2POCvZR_ → jSKB7CQQSNTX-uSbY2bUs}/_clientMiddlewareManifest.js +0 -0
  238. /package/.next/standalone/.next/static/{Aulh3DRWwRfwh2POCvZR_ → jSKB7CQQSNTX-uSbY2bUs}/_ssgManifest.js +0 -0
package/dist/cli.mjs CHANGED
@@ -19,7 +19,7 @@ var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
19
19
  var __require = /* @__PURE__ */ createRequire(import.meta.url);
20
20
 
21
21
  // package.json
22
- var version2 = "1.0.0", package_default;
22
+ var version2 = "1.0.1-beta.0", package_default;
23
23
  var init_package = __esm(() => {
24
24
  package_default = {
25
25
  name: "failproofai",
@@ -63,7 +63,8 @@ var init_package = __esm(() => {
63
63
  "translate:docs": "bun scripts/translate-docs/cli.ts --docs-only",
64
64
  "translate:dry-run": "bun scripts/translate-docs/cli.ts --dry-run",
65
65
  "translate:validate": "bun scripts/translate-docs/cli.ts --validate",
66
- "validate:mdx": "bun scripts/validate-mdx.ts"
66
+ "validate:mdx": "bun scripts/validate-mdx.ts",
67
+ "docs:audit": "bun scripts/docs-audit.ts"
67
68
  },
68
69
  keywords: [
69
70
  "claude",
@@ -127,6 +128,7 @@ var init_package = __esm(() => {
127
128
  yaml: "^2.9.0"
128
129
  },
129
130
  overrides: {
131
+ nanoid: "3.3.18",
130
132
  postcss: "8.5.26",
131
133
  "eslint-plugin-react-hooks": "7.0.1",
132
134
  vite: "8.0.16",
@@ -135,16 +137,16 @@ var init_package = __esm(() => {
135
137
  sharp: "0.35.0"
136
138
  },
137
139
  optionalDependencies: {
138
- "@failproofai/failproofaid-linux-x64": "1.0.0",
139
- "@failproofai/failproofaid-linux-arm64": "1.0.0",
140
- "@failproofai/failproofaid-darwin-x64": "1.0.0",
141
- "@failproofai/failproofaid-darwin-arm64": "1.0.0"
140
+ "@failproofai/failproofaid-linux-x64": "1.0.1-beta.0",
141
+ "@failproofai/failproofaid-linux-arm64": "1.0.1-beta.0",
142
+ "@failproofai/failproofaid-darwin-x64": "1.0.1-beta.0",
143
+ "@failproofai/failproofaid-darwin-arm64": "1.0.1-beta.0"
142
144
  },
143
145
  failproofaidBinaries: {
144
- "linux-x64": "67d9404812145b8b13dc97debd33cd667a5de347989b2c9c47bbdfcb5e99344c",
145
- "linux-arm64": "ca003a2ca755f5d696e2d6f4ddd8eedc0f8c4914f972101aa9803986ec409000",
146
- "darwin-x64": "53f1ed8710da69c2e3d3668d3b62380383a46328471870093936f53fc0a4fb05",
147
- "darwin-arm64": "682c22084906877760285e925b232d3563a1874a7a1f42c4c27deb1b7b74fb6f"
146
+ "linux-x64": "8259a934de6ae1302e49a7e7d81e7caac533fa8437167fddc2a9b36d05745ce2",
147
+ "linux-arm64": "c9a4e90c94c23c78973ddb26740f39ab4d3368da5567cebe475e805049c158e9",
148
+ "darwin-x64": "cf0c70a0dab9f737a9ffde27b3ab3fb18ef159b851656ef778ed193a0a72a476",
149
+ "darwin-arm64": "f4d4e300339acc7557251a96500c24e8d675f934febc9d587560cf0544d3eef1"
148
150
  }
149
151
  };
150
152
  });
@@ -175,6 +177,7 @@ function retiredLayoutPaths() {
175
177
  legacy.lastVersion(),
176
178
  legacy.auditDashboard(),
177
179
  legacy.auditCacheDir(),
180
+ legacy.auditReminder(),
178
181
  legacy.codexSessionPaths(),
179
182
  legacy.spoolDir(),
180
183
  legacy.failedDir(),
@@ -186,7 +189,7 @@ function retiredLayoutPaths() {
186
189
  legacy.localPoliciesDir()
187
190
  ];
188
191
  }
189
- var LAYOUT_VERSION = 3, at = (...parts) => resolve(failproofaiHome(), ...parts), atHome = (home, ...parts) => home ? resolve(failproofaiHome(home), ...parts) : at(...parts), versionFile = (home) => atHome(home, "VERSION"), configFile = (home) => atHome(home, "config.json"), credentialsFile = (home) => atHome(home, "credentials.json"), binDir = (home) => atHome(home, "bin"), policiesDir = (home) => atHome(home, "policies"), customPoliciesDir, globalPolicyConfigFile = (home) => atHome(home, "policies-config.json"), cloudPoliciesDir = (home) => resolve(policiesDir(home), "cloud-policies"), cursorsDir = (source, home) => source ? resolve(atHome(home, "cursors"), source) : atHome(home, "cursors"), customAgentsDir = (home) => atHome(home, "custom-agents"), auditDir = (home) => atHome(home, "audit"), auditDashboardFile = (home) => resolve(auditDir(home), "dashboard.json"), auditCacheDir = (home) => resolve(auditDir(home), "cache"), hookActivityDir = (home) => atHome(home, "hook-activity"), runDir = (home) => atHome(home, "run"), daemonSocket = () => process.env.FAILPROOFAI_DAEMON_SOCKET || resolve(runDir(), "failproofaid.sock"), auditLockFile = (home) => resolve(runDir(home), "audit.lock"), stateDir = (home) => atHome(home, "state"), shimsDir = (home) => resolve(stateDir(home), "shims"), spoolDir = (home) => resolve(stateDir(home), "spool"), failedDir = (home) => resolve(stateDir(home), "failed"), collectorHealthFile = (home) => resolve(stateDir(home), "collector-health.json"), sessionPauseDir = () => resolve(stateDir(), "sessions"), auditScheduleFile = (home) => resolve(stateDir(home), "audit-schedule.json"), telemetryIdFile = (home) => resolve(stateDir(home), "telemetry-id"), launcherMarker = (home) => resolve(stateDir(home), "launcher-configured"), onboardingAttemptFile = (home) => resolve(stateDir(home), "onboarding-attempt.json"), lastVersionFile = (home) => resolve(stateDir(home), "last-version"), onboardingLockFile = (home) => resolve(stateDir(home), "onboarding.lock"), codexSessionPathsFile = (home) => resolve(stateDir(home), "codex-session-paths.json"), logsDir = (home) => atHome(home, "logs"), migrationsDir = (home) => atHome(home, "migrations"), migrationLedgerFile = (home) => resolve(migrationsDir(home), "applied.json"), migrationBackupDir = (layout, home) => resolve(migrationsDir(home), `backup-layout${layout}`), HOME_CLASSES, legacy;
192
+ var LAYOUT_VERSION = 4, at = (...parts) => resolve(failproofaiHome(), ...parts), atHome = (home, ...parts) => home ? resolve(failproofaiHome(home), ...parts) : at(...parts), versionFile = (home) => atHome(home, "VERSION"), configFile = (home) => atHome(home, "config.json"), credentialsFile = (home) => atHome(home, "credentials.json"), binDir = (home) => atHome(home, "bin"), policiesDir = (home) => atHome(home, "policies"), customPoliciesDir, globalPolicyConfigFile = (home) => atHome(home, "policies-config.json"), cloudPoliciesDir = (home) => resolve(policiesDir(home), "cloud-policies"), cursorsDir = (source, home) => source ? resolve(atHome(home, "cursors"), source) : atHome(home, "cursors"), customAgentsDir = (home) => atHome(home, "custom-agents"), auditDir = (home) => atHome(home, "audit"), auditDashboardFile = (home) => resolve(auditDir(home), "dashboard.json"), auditCacheDir = (home) => resolve(auditDir(home), "cache"), auditSessionFile = (home) => resolve(auditDir(home), "session.json"), auditMachineFile = (home) => resolve(auditDir(home), "machine.json"), hookActivityDir = (home) => atHome(home, "hook-activity"), runDir = (home) => atHome(home, "run"), daemonSocket = () => process.env.FAILPROOFAI_DAEMON_SOCKET || resolve(runDir(), "failproofaid.sock"), auditLockFile = (home) => resolve(runDir(home), "audit.lock"), stateDir = (home) => atHome(home, "state"), shimsDir = (home) => resolve(stateDir(home), "shims"), spoolDir = (home) => resolve(stateDir(home), "spool"), failedDir = (home) => resolve(stateDir(home), "failed"), collectorHealthFile = (home) => resolve(stateDir(home), "collector-health.json"), sessionPauseDir = () => resolve(stateDir(), "sessions"), auditScheduleFile = (home) => resolve(auditDir(home), "schedule.json"), telemetryIdFile = (home) => resolve(stateDir(home), "telemetry-id"), launcherMarker = (home) => resolve(stateDir(home), "launcher-configured"), onboardingAttemptFile = (home) => resolve(stateDir(home), "onboarding-attempt.json"), lastVersionFile = (home) => resolve(stateDir(home), "last-version"), onboardingLockFile = (home) => resolve(stateDir(home), "onboarding.lock"), codexSessionPathsFile = (home) => resolve(stateDir(home), "codex-session-paths.json"), logsDir = (home) => atHome(home, "logs"), migrationsDir = (home) => atHome(home, "migrations"), migrationLedgerFile = (home) => resolve(migrationsDir(home), "applied.json"), migrationBackupDir = (layout, home) => resolve(migrationsDir(home), `backup-layout${layout}`), HOME_CLASSES, legacy;
190
193
  var init_fp_home = __esm(() => {
191
194
  customPoliciesDir = policiesDir;
192
195
  HOME_CLASSES = [
@@ -194,6 +197,7 @@ var init_fp_home = __esm(() => {
194
197
  { path: configFile, class: "user-typed" },
195
198
  { path: globalPolicyConfigFile, class: "user-typed" },
196
199
  { path: policiesDir, class: "user-typed" },
200
+ { path: auditSessionFile, class: "user-typed" },
197
201
  { path: spoolDir, class: "undelivered" },
198
202
  { path: failedDir, class: "undelivered" },
199
203
  { path: customAgentsDir, class: "undelivered" },
@@ -205,9 +209,11 @@ var init_fp_home = __esm(() => {
205
209
  { path: (home) => resolve(stateDir(home), "daemon-telemetry-id"), class: "identity" },
206
210
  { path: versionFile, class: "identity" },
207
211
  { path: migrationsDir, class: "identity" },
208
- { path: auditDir, class: "derived" },
209
- { path: collectorHealthFile, class: "derived" },
212
+ { path: auditMachineFile, class: "identity" },
213
+ { path: auditDashboardFile, class: "derived" },
214
+ { path: auditCacheDir, class: "derived" },
210
215
  { path: auditScheduleFile, class: "derived" },
216
+ { path: collectorHealthFile, class: "derived" },
211
217
  { path: codexSessionPathsFile, class: "derived" },
212
218
  { path: shimsDir, class: "derived" },
213
219
  { path: sessionPauseDir, class: "derived" },
@@ -233,6 +239,10 @@ var init_fp_home = __esm(() => {
233
239
  launcherMarker: () => at(".launcher-configured"),
234
240
  lastVersion: () => at("last-version"),
235
241
  auditDashboard: () => at("audit-dashboard.json"),
242
+ authJson: () => at("auth.json"),
243
+ nextAudit: () => at("next-audit.json"),
244
+ auditReminder: () => at("audit", "reminder.json"),
245
+ auditSchedule: () => at("state", "audit-schedule.json"),
236
246
  cacheDir: () => at("cache"),
237
247
  hookActivityDir: () => at("cache", "hook-activity"),
238
248
  auditCacheDir: () => at("cache", "audit"),
@@ -257,10 +267,17 @@ function detectLayout() {
257
267
  return raw.layout > LAYOUT_VERSION ? { kind: "future", found: raw.layout } : { kind: "stale", found: raw.layout };
258
268
  }
259
269
  if (existsSync(configFile())) {
270
+ const layoutThreePositions = [
271
+ legacy.authJson(),
272
+ legacy.nextAudit(),
273
+ legacy.auditSchedule()
274
+ ];
275
+ if (layoutThreePositions.some((p) => existsSync(p)))
276
+ return { kind: "stale", found: 3 };
260
277
  return { kind: "current", version: { layout: LAYOUT_VERSION, cli: "" }, inferred: true };
261
278
  }
262
279
  if (existsSync(legacy.configToml()))
263
- return { kind: "stale", found: LAYOUT_VERSION - 1 };
280
+ return { kind: "stale", found: 2 };
264
281
  const layoutOneMarkers = [
265
282
  legacy.policyConfig(),
266
283
  legacy.cacheDir(),
@@ -303,7 +320,7 @@ function readVersionFile() {
303
320
  function writeVersionFile(v = {}) {
304
321
  const existing = readVersionFile();
305
322
  const next = {
306
- layout: LAYOUT_VERSION,
323
+ layout: v.layout ?? LAYOUT_VERSION,
307
324
  cli: v.cli ?? version2,
308
325
  daemon: v.clearDaemon ? undefined : v.daemon ?? existing?.daemon
309
326
  };
@@ -372,7 +389,11 @@ function projectConfig(parsed) {
372
389
  sources: readSources(collector.sources)
373
390
  },
374
391
  telemetry: { enabled: telemetry.enabled !== false },
375
- audit: { auto: audit.auto === true, intervalDays: readIntervalDays(audit.interval_days) }
392
+ audit: {
393
+ auto: audit.auto === true,
394
+ intervalDays: readIntervalDays(audit.interval_days),
395
+ reportsConsentedAt: typeof audit.reports_consented_at === "number" && Number.isFinite(audit.reports_consented_at) ? audit.reports_consented_at : undefined
396
+ }
376
397
  };
377
398
  }
378
399
  }
@@ -421,7 +442,11 @@ function writeConfig(config, raw) {
421
442
  } : {}
422
443
  },
423
444
  ...config.telemetry.enabled ? {} : { telemetry: { enabled: false } },
424
- audit: { auto: config.audit.auto, interval_days: config.audit.intervalDays }
445
+ audit: {
446
+ auto: config.audit.auto,
447
+ interval_days: config.audit.intervalDays,
448
+ ...config.audit.reportsConsentedAt === undefined ? {} : { reports_consented_at: config.audit.reportsConsentedAt }
449
+ }
425
450
  };
426
451
  const merged = structuredClone(raw ?? readConfigRaw().raw);
427
452
  for (const path of OWNED_CONFIG_KEYS)
@@ -567,7 +592,8 @@ var init_fp_config = __esm(() => {
567
592
  ["collector", "sources", "*", "extra_paths"],
568
593
  ["telemetry", "enabled"],
569
594
  ["audit", "auto"],
570
- ["audit", "interval_days"]
595
+ ["audit", "interval_days"],
596
+ ["audit", "reports_consented_at"]
571
597
  ];
572
598
  OWNED_CREDENTIAL_KEYS = [
573
599
  ["cloud", "url"],
@@ -2910,7 +2936,7 @@ function registerBuiltinPolicies(enabledNames) {
2910
2936
  }
2911
2937
  }
2912
2938
  }
2913
- var isClaudeInternalPath, isClaudeSettingsFile, SHELL_OPERATORS, SHELL_METACHAR_RE, JWT_RE, API_KEY_PATTERNS, CONNECTION_STRING_RE, PRIVATE_KEY_RE, BEARER_TOKEN_RE, SQL_TOOL_RE, DESTRUCTIVE_SQL_RE, DELETE_NO_WHERE_RE, SQL_WHERE_RE, SCHEMA_ALTER_RE, PUBLISH_CMD_RE, ENV_PRINTENV_RE, ECHO_ENV_RE, EXPORT_RE, PS_ENV_VAR_RE, PS_CHILDITEM_ENV_RE, DOTNET_GETENV_RE, CMD_ECHO_ENV_RE, ENV_FILE_PATH_RE, ENV_CMD_RE, PS_ELEVATION_RE, RUNAS_RE, CURL_PIPE_SH_RE, SEGMENT_SEPARATORS, COMMAND_PREFIX_TOKENS, SELF_BINARY_TOKEN_RE, CONFIG_SUBCOMMAND_RE, PAUSE_FLAG_RE, ENV_ASSIGNMENT_RE, RUNNER_OPERAND_RE, PS_WEB_PIPE_RE, SHORT_FLAG_BUNDLE_RE, SAFE_FORCE_PREFIXES, SECRET_FILE_RE, SECRET_FILE_ID_RSA_RE, SECRET_FILE_CREDENTIALS_RE, GIT_COMMIT_MERGE_RE, FAILPROOFAI_CLI_RE, FAILPROOFAI_UNINSTALL_RE, GIT_AMEND_RE, GIT_STASH_DROP_RE, GIT_ADD_ALL_RE, NPM_GLOBAL_RE, YARN_GLOBAL_RE, PNPM_GLOBAL_RE, BUN_GLOBAL_RE, CARGO_INSTALL_RE, PIP_SYSTEM_RE, PKG_MANAGER_DETECTORS, NOHUP_RE, SCREEN_DETACH_RE, TMUX_DETACH_RE, DISOWN_RE, BACKGROUND_AMPERSAND_RE, KUBECTL_RE, TERRAFORM_RE, AWS_CLI_RE, GCLOUD_RE, AZ_CLI_RE, HELM_RE, GH_PIPELINE_RE, gitBranchCache, GIT_BRANCH_CACHE_MAX_ENTRIES = 500, EVAL_FLAG_RE, HOME_PREFIX_RE, RM_CMD_RE, FIND_CMD_RE, FIND_EXEC_RE, FIND_GLOBAL_OPT_RE, FIND_EXPR_START_RE, SCRATCH_ROOTS, CATASTROPHIC_DEPTH = 2, READ_LIKE_CMDS, TOOL_CALL_TRACKER_MAX_BYTES = 65536, SEGMENT_SPLIT_RE, BUILTIN_POLICIES;
2939
+ var isClaudeInternalPath, isClaudeSettingsFile, SHELL_OPERATORS, SHELL_METACHAR_RE, JWT_RE, API_KEY_PATTERNS, CONNECTION_STRING_RE, PRIVATE_KEY_RE, BEARER_TOKEN_RE, SECRET_PATTERNS, SQL_TOOL_RE, DESTRUCTIVE_SQL_RE, DELETE_NO_WHERE_RE, SQL_WHERE_RE, SCHEMA_ALTER_RE, PUBLISH_CMD_RE, ENV_PRINTENV_RE, ECHO_ENV_RE, EXPORT_RE, PS_ENV_VAR_RE, PS_CHILDITEM_ENV_RE, DOTNET_GETENV_RE, CMD_ECHO_ENV_RE, ENV_FILE_PATH_RE, ENV_CMD_RE, PS_ELEVATION_RE, RUNAS_RE, CURL_PIPE_SH_RE, SEGMENT_SEPARATORS, COMMAND_PREFIX_TOKENS, SELF_BINARY_TOKEN_RE, CONFIG_SUBCOMMAND_RE, PAUSE_FLAG_RE, ENV_ASSIGNMENT_RE, RUNNER_OPERAND_RE, PS_WEB_PIPE_RE, SHORT_FLAG_BUNDLE_RE, SAFE_FORCE_PREFIXES, SECRET_FILE_RE, SECRET_FILE_ID_RSA_RE, SECRET_FILE_CREDENTIALS_RE, GIT_COMMIT_MERGE_RE, FAILPROOFAI_CLI_RE, FAILPROOFAI_UNINSTALL_RE, GIT_AMEND_RE, GIT_STASH_DROP_RE, GIT_ADD_ALL_RE, NPM_GLOBAL_RE, YARN_GLOBAL_RE, PNPM_GLOBAL_RE, BUN_GLOBAL_RE, CARGO_INSTALL_RE, PIP_SYSTEM_RE, PKG_MANAGER_DETECTORS, NOHUP_RE, SCREEN_DETACH_RE, TMUX_DETACH_RE, DISOWN_RE, BACKGROUND_AMPERSAND_RE, KUBECTL_RE, TERRAFORM_RE, AWS_CLI_RE, GCLOUD_RE, AZ_CLI_RE, HELM_RE, GH_PIPELINE_RE, gitBranchCache, GIT_BRANCH_CACHE_MAX_ENTRIES = 500, EVAL_FLAG_RE, HOME_PREFIX_RE, RM_CMD_RE, FIND_CMD_RE, FIND_EXEC_RE, FIND_GLOBAL_OPT_RE, FIND_EXPR_START_RE, SCRATCH_ROOTS, CATASTROPHIC_DEPTH = 2, READ_LIKE_CMDS, TOOL_CALL_TRACKER_MAX_BYTES = 65536, SEGMENT_SPLIT_RE, BUILTIN_POLICIES;
2914
2940
  var init_builtin_policies = __esm(() => {
2915
2941
  init_hook_logger();
2916
2942
  isClaudeInternalPath = isAgentInternalPath;
@@ -2932,6 +2958,13 @@ var init_builtin_policies = __esm(() => {
2932
2958
  CONNECTION_STRING_RE = /(?:postgresql|postgres|mysql|mongodb(?:\+srv)?|redis|amqps?|smtps?):\/\/[^@\s]+@/;
2933
2959
  PRIVATE_KEY_RE = /-----BEGIN (?:[A-Z]+ )?PRIVATE KEY-----/;
2934
2960
  BEARER_TOKEN_RE = /Authorization:\s*Bearer\s+[A-Za-z0-9\-._~+/]{20,}/i;
2961
+ SECRET_PATTERNS = [
2962
+ [PRIVATE_KEY_RE, "private key"],
2963
+ [JWT_RE, "JWT"],
2964
+ [BEARER_TOKEN_RE, "bearer token"],
2965
+ [CONNECTION_STRING_RE, "database credentials"],
2966
+ ...API_KEY_PATTERNS
2967
+ ];
2935
2968
  SQL_TOOL_RE = /\b(?:psql|mysql|sqlite3|pgcli|clickhouse-client)\b/;
2936
2969
  DESTRUCTIVE_SQL_RE = /\b(?:DROP\s+(?:TABLE|DATABASE|SCHEMA)|TRUNCATE\b)/i;
2937
2970
  DELETE_NO_WHERE_RE = /\bDELETE\s+FROM\b/i;
@@ -11432,7 +11465,7 @@ function readCarriedLegacyCredentials() {
11432
11465
  const creds = projectCredentials(raw);
11433
11466
  return Object.keys(creds).length > 0 ? creds : null;
11434
11467
  }
11435
- function resetHome(from) {
11468
+ function resetHome(from, to = LAYOUT_VERSION) {
11436
11469
  const migrated = migrateConventionPolicies();
11437
11470
  const activity = migrateHookActivity();
11438
11471
  const pendingPolicyConfig = readCarriedPolicyConfig();
@@ -11457,7 +11490,7 @@ function resetHome(from) {
11457
11490
  writeConfig(pendingConfig);
11458
11491
  if (telemetryOptOut)
11459
11492
  updateConfig({ telemetry: { enabled: false } });
11460
- writeVersionFile();
11493
+ writeVersionFile({ layout: to });
11461
11494
  return { removed, migrated, activity, policyConfig, spooled, from };
11462
11495
  }
11463
11496
  function layoutWarningForHook() {
@@ -12033,14 +12066,71 @@ __export(exports_migrations, {
12033
12066
  runMigrations: () => runMigrations,
12034
12067
  restoreBackup: () => restoreBackup,
12035
12068
  readLedger: () => readLedger,
12069
+ pruneMigratedCredentials: () => pruneMigratedCredentials,
12036
12070
  planMigration: () => planMigration,
12037
12071
  migrationCoverageGap: () => migrationCoverageGap,
12038
12072
  describePlan: () => describePlan,
12039
12073
  backupBeforeMigrating: () => backupBeforeMigrating,
12040
12074
  MIGRATIONS: () => MIGRATIONS
12041
12075
  });
12042
- import { copyFileSync as copyFileSync2, existsSync as existsSync21, mkdirSync as mkdirSync12, readFileSync as readFileSync16, rmSync as rmSync7, writeFileSync as writeFileSync10 } from "node:fs";
12043
- import { basename as basename4, dirname as dirname10, resolve as resolve16 } from "node:path";
12076
+ import {
12077
+ chmodSync as chmodSync4,
12078
+ copyFileSync as copyFileSync2,
12079
+ existsSync as existsSync21,
12080
+ mkdirSync as mkdirSync12,
12081
+ readFileSync as readFileSync16,
12082
+ renameSync as renameSync6,
12083
+ rmSync as rmSync7,
12084
+ writeFileSync as writeFileSync10
12085
+ } from "node:fs";
12086
+ import { basename as basename4, dirname as dirname10, join as join29, resolve as resolve16 } from "node:path";
12087
+ function migrateToLayout4() {
12088
+ const moves = [
12089
+ { from: legacy.authJson(), to: auditSessionFile() },
12090
+ { from: legacy.nextAudit(), to: legacy.auditReminder() },
12091
+ { from: legacy.auditSchedule(), to: auditScheduleFile() }
12092
+ ];
12093
+ const authDirOverride = process.env.FAILPROOFAI_AUTH_DIR;
12094
+ if (authDirOverride) {
12095
+ moves.push({ from: join29(authDirOverride, "auth.json"), to: join29(authDirOverride, "session.json") }, {
12096
+ from: join29(authDirOverride, "next-audit.json"),
12097
+ to: join29(authDirOverride, "reminder.json")
12098
+ });
12099
+ }
12100
+ const migrated = [];
12101
+ for (const { from, to } of moves) {
12102
+ if (!existsSync21(from))
12103
+ continue;
12104
+ if (existsSync21(to)) {
12105
+ rmSync7(from, { force: true });
12106
+ continue;
12107
+ }
12108
+ mkdirSync12(dirname10(to), { recursive: true });
12109
+ try {
12110
+ renameSync6(from, to);
12111
+ } catch {
12112
+ try {
12113
+ copyFileSync2(from, to);
12114
+ } catch (err) {
12115
+ try {
12116
+ rmSync7(to, { force: true });
12117
+ } catch {}
12118
+ throw err;
12119
+ }
12120
+ rmSync7(from, { force: true });
12121
+ }
12122
+ migrated.push(`${basename4(from)} → audit/${basename4(to)}`);
12123
+ }
12124
+ for (const secret of [auditSessionFile()]) {
12125
+ if (!existsSync21(secret))
12126
+ continue;
12127
+ try {
12128
+ chmodSync4(secret, 384);
12129
+ } catch {}
12130
+ }
12131
+ writeVersionFile({ layout: 4 });
12132
+ return { removed: [], migrated, activity: [], policyConfig: [], spooled: [], from: 3 };
12133
+ }
12044
12134
  function planMigration(from, registry = MIGRATIONS) {
12045
12135
  if (from >= LAYOUT_VERSION)
12046
12136
  return [];
@@ -12095,6 +12185,23 @@ function appendLedger(entry) {
12095
12185
  function backupNameOf(f) {
12096
12186
  return f.as ?? basename4(f.at());
12097
12187
  }
12188
+ function pruneMigratedCredentials(from) {
12189
+ const pruned = [];
12190
+ for (let layout = from;layout < LAYOUT_VERSION; layout++) {
12191
+ for (const { as, landsAt } of PRUNED_AFTER_SUCCESS) {
12192
+ try {
12193
+ if (!existsSync21(landsAt()))
12194
+ continue;
12195
+ const copy = resolve16(migrationBackupDir(layout), as);
12196
+ if (!existsSync21(copy))
12197
+ continue;
12198
+ rmSync7(copy, { force: true });
12199
+ pruned.push(as);
12200
+ } catch {}
12201
+ }
12202
+ }
12203
+ return pruned;
12204
+ }
12098
12205
  function filesToBackUp() {
12099
12206
  const seen = new Map;
12100
12207
  for (const f of [...BACKED_UP, ...BACKED_UP_LEGACY]) {
@@ -12156,6 +12263,11 @@ function runMigrations(from, chain = planMigration(from)) {
12156
12263
  });
12157
12264
  } catch (err) {
12158
12265
  steps.push({ from: step.from, to: step.to, ok: false });
12266
+ try {
12267
+ const marker = readVersionFile();
12268
+ if (marker && marker.layout >= LAYOUT_VERSION)
12269
+ writeVersionFile({ layout: step.from });
12270
+ } catch {}
12159
12271
  failed = {
12160
12272
  from: step.from,
12161
12273
  to: step.to,
@@ -12172,6 +12284,8 @@ function runMigrations(from, chain = planMigration(from)) {
12172
12284
  break;
12173
12285
  }
12174
12286
  }
12287
+ if (!failed)
12288
+ pruneMigratedCredentials(from);
12175
12289
  return { from, steps, backedUp, outcome, failed };
12176
12290
  }
12177
12291
  function describePlan(from) {
@@ -12214,23 +12328,30 @@ function restoreBackup(layout) {
12214
12328
  }
12215
12329
  return restored.sort((a, b) => a.localeCompare(b));
12216
12330
  }
12217
- var MIGRATIONS, BACKED_UP, BACKED_UP_LEGACY;
12331
+ var MIGRATIONS, BACKED_UP, BACKED_UP_LEGACY, PRUNED_AFTER_SUCCESS;
12218
12332
  var init_migrations = __esm(() => {
12219
12333
  init_package();
12220
12334
  init_fp_home();
12335
+ init_fp_config();
12221
12336
  init_fp_reset();
12222
12337
  MIGRATIONS = [
12223
12338
  {
12224
12339
  from: 1,
12225
12340
  to: 3,
12226
12341
  describe: "layout 1 → 3: carry the decision log out of cache/, keep the policy config in place, drop the layout-1 credential files",
12227
- run: () => resetHome(1)
12342
+ run: () => resetHome(1, 3)
12228
12343
  },
12229
12344
  {
12230
12345
  from: 2,
12231
12346
  to: 3,
12232
12347
  describe: "layout 2 → 3: carry config.toml and credentials.toml into JSON, move custom-policies/ back up into policies/, nest the policy config at the root",
12233
- run: () => resetHome(2)
12348
+ run: () => resetHome(2, 3)
12349
+ },
12350
+ {
12351
+ from: 3,
12352
+ to: 4,
12353
+ describe: "layout 3 → 4: gather the audit's files under audit/ — auth.json becomes audit/session.json, next-audit.json becomes audit/reminder.json, state/audit-schedule.json becomes audit/schedule.json",
12354
+ run: migrateToLayout4
12234
12355
  }
12235
12356
  ];
12236
12357
  BACKED_UP = [
@@ -12245,7 +12366,13 @@ var init_migrations = __esm(() => {
12245
12366
  { at: legacy.policyConfig },
12246
12367
  { at: legacy.localPolicyConfig, as: "local-policies-policies-config.json" },
12247
12368
  { at: legacy.cloudCredentials },
12248
- { at: legacy.ingestCredentials }
12369
+ { at: legacy.ingestCredentials },
12370
+ { at: legacy.authJson },
12371
+ { at: legacy.nextAudit },
12372
+ { at: legacy.auditSchedule }
12373
+ ];
12374
+ PRUNED_AFTER_SUCCESS = [
12375
+ { as: basename4(legacy.authJson()), landsAt: auditSessionFile }
12249
12376
  ];
12250
12377
  });
12251
12378
 
@@ -12272,7 +12399,7 @@ import {
12272
12399
  mkdirSync as mkdirSync13,
12273
12400
  readFileSync as readFileSync17,
12274
12401
  readdirSync as readdirSync16,
12275
- renameSync as renameSync6,
12402
+ renameSync as renameSync7,
12276
12403
  rmSync as rmSync8,
12277
12404
  rmdirSync as rmdirSync2,
12278
12405
  statSync as statSync17,
@@ -12304,7 +12431,7 @@ function migrateConventionPolicies2() {
12304
12431
  const name = `${prefix}${entry.name}`;
12305
12432
  if (!existsSync22(target)) {
12306
12433
  try {
12307
- renameSync6(source, target);
12434
+ renameSync7(source, target);
12308
12435
  moved.push(name);
12309
12436
  } catch {}
12310
12437
  continue;
@@ -12341,7 +12468,7 @@ function migrateLegacySpool2() {
12341
12468
  while (existsSync22(resolve17(to, name)))
12342
12469
  name = `legacy-${n++}-${entry.name}`;
12343
12470
  try {
12344
- renameSync6(resolve17(from, entry.name), resolve17(to, name));
12471
+ renameSync7(resolve17(from, entry.name), resolve17(to, name));
12345
12472
  moved.push(name);
12346
12473
  } catch {
12347
12474
  try {
@@ -12376,7 +12503,7 @@ function migrateHookActivity2() {
12376
12503
  target = resolve17(to, name);
12377
12504
  }
12378
12505
  try {
12379
- renameSync6(source, target);
12506
+ renameSync7(source, target);
12380
12507
  moved.push(name);
12381
12508
  } catch {
12382
12509
  try {
@@ -12584,7 +12711,7 @@ function readCarriedLegacyCredentials2() {
12584
12711
  const creds = projectCredentials(raw);
12585
12712
  return Object.keys(creds).length > 0 ? creds : null;
12586
12713
  }
12587
- function resetHome2(from) {
12714
+ function resetHome2(from, to = LAYOUT_VERSION) {
12588
12715
  const migrated = migrateConventionPolicies2();
12589
12716
  const activity = migrateHookActivity2();
12590
12717
  const pendingPolicyConfig = readCarriedPolicyConfig2();
@@ -12609,7 +12736,7 @@ function resetHome2(from) {
12609
12736
  writeConfig(pendingConfig);
12610
12737
  if (telemetryOptOut)
12611
12738
  updateConfig({ telemetry: { enabled: false } });
12612
- writeVersionFile();
12739
+ writeVersionFile({ layout: to });
12613
12740
  return { removed, migrated, activity, policyConfig, spooled, from };
12614
12741
  }
12615
12742
  async function drainSpoolAfterMigrating() {
@@ -12647,6 +12774,7 @@ async function checkLayoutForCli() {
12647
12774
  const run = runMigrations2(state.found);
12648
12775
  const { removed, migrated, activity } = run.outcome;
12649
12776
  const pending3 = await drainSpoolAfterMigrating();
12777
+ const daemonHint = staleDaemonHint();
12650
12778
  return {
12651
12779
  state,
12652
12780
  fatal: false,
@@ -12678,7 +12806,8 @@ async function checkLayoutForCli() {
12678
12806
  `Step ${run.failed.from} → ${run.failed.to} did not finish: ${run.failed.error}`,
12679
12807
  `The home is still marked layout ${state.found} and will be retried. Copies of`,
12680
12808
  `your settings and enrolment were saved first, in ${migrationBackupDir(state.found)}.`
12681
- ] : []
12809
+ ] : [],
12810
+ ...daemonHint.length > 0 ? ["", ...daemonHint] : []
12682
12811
  ]
12683
12812
  };
12684
12813
  }
@@ -12743,8 +12872,23 @@ function staleDaemonHint() {
12743
12872
  const skew = daemonVersionSkew();
12744
12873
  if (!skew)
12745
12874
  return [];
12875
+ let requiresDaemon = false;
12876
+ try {
12877
+ requiresDaemon = readConfig().daemon.configured;
12878
+ } catch {}
12879
+ if (requiresDaemon) {
12880
+ return [
12881
+ `[failproofai] daemon is ${skew.installed}, CLI is ${skew.expected}.`,
12882
+ `This machine is configured to REQUIRE the daemon. A daemon built against a`,
12883
+ `different on-disk layout refuses to start, and this version moved it — so the`,
12884
+ `next reboot or restart can leave the service down, which denies every tool`,
12885
+ `call until it is fixed.`,
12886
+ `Run \`failproofai update\` now to bring the daemon in line.`,
12887
+ ``
12888
+ ];
12889
+ }
12746
12890
  return [
12747
- `[failproofai] daemon is ${skew.installed}, CLI is ${skew.expected} — ` + `run \`failproofai config\` to update it.`,
12891
+ `[failproofai] daemon is ${skew.installed}, CLI is ${skew.expected} — ` + `run \`failproofai update\` to update it.`,
12748
12892
  ``
12749
12893
  ];
12750
12894
  } catch {
@@ -12785,13 +12929,13 @@ import { createHmac, randomUUID as randomUUID2 } from "node:crypto";
12785
12929
  import { execSync as execSync4 } from "node:child_process";
12786
12930
  import { readFileSync as readFileSync18, writeFileSync as writeFileSync12, mkdirSync as mkdirSync14 } from "node:fs";
12787
12931
  import { homedir as homedir20, platform, arch, hostname, cpus } from "node:os";
12788
- import { join as join29 } from "node:path";
12932
+ import { join as join30 } from "node:path";
12789
12933
  function hashToId3(raw) {
12790
12934
  return createHmac("sha256", NAMESPACE3).update(raw).digest("hex");
12791
12935
  }
12792
12936
  function getInstanceId3() {
12793
- const idDir = join29(homedir20(), ".failproofai");
12794
- const idFile = join29(idDir, "instance-id");
12937
+ const idDir = join30(homedir20(), ".failproofai");
12938
+ const idFile = join30(idDir, "instance-id");
12795
12939
  try {
12796
12940
  const existing = readFileSync18(idFile, "utf-8").trim();
12797
12941
  if (existing)
@@ -13187,6 +13331,27 @@ function renderLaunchBanner(version3, stdout = process.stdout) {
13187
13331
  ""
13188
13332
  ];
13189
13333
  }
13334
+ function step(message, summary, stdout = process.stdout) {
13335
+ const c = paint(colorsEnabled(stdout));
13336
+ const rows = summary === undefined ? [] : Array.isArray(summary) ? summary : [summary];
13337
+ if (!stdout.isTTY) {
13338
+ if (rows.length)
13339
+ stdout.write(`${message}: ${rows.join(" ")}
13340
+ `);
13341
+ return;
13342
+ }
13343
+ const cols = stdout.columns || 80;
13344
+ const lines = [c.dim(BAR), truncate(`${c.dim(STEP_DONE)} ${message}`, cols - 1)];
13345
+ for (const r of rows)
13346
+ lines.push(truncate(`${c.dim(BAR)} ${c.dim(r)}`, cols - 1));
13347
+ writeLines(stdout, lines);
13348
+ }
13349
+ function stepOpen(message, stdout = process.stdout) {
13350
+ const c = paint(colorsEnabled(stdout));
13351
+ if (!stdout.isTTY)
13352
+ return;
13353
+ writeLines(stdout, [c.dim(BAR), `${c.guide(STEP_ACTIVE)} ${c.bold(message)}`]);
13354
+ }
13190
13355
  function outro(message, opts = {}, stdout = process.stdout) {
13191
13356
  const c = paint(colorsEnabled(stdout));
13192
13357
  const ok = opts.ok !== false;
@@ -13449,10 +13614,10 @@ function promptText(opts) {
13449
13614
  const draw = (error) => {
13450
13615
  const cols = stdout.columns || 80;
13451
13616
  const shown = opts.mask ? "•".repeat(value.length) : value;
13452
- const hint = opts.hint ? ` ${c.dim(opts.hint)}` : "";
13453
- const line = truncate(`${c.bold(opts.message)} ${shown}${hint}`, cols - 1);
13617
+ const hint = opts.hint && value.length === 0 ? ` ${c.dim(opts.hint)}` : "";
13618
+ const line = truncate(`${opts.prefix ?? ""}${c.bold(opts.message)} ${shown}${hint}`, cols - 1);
13454
13619
  const err = error ? `
13455
- ${truncate(c.warn(error), cols - 3)}` : "";
13620
+ ${opts.prefix ?? " "}${truncate(c.warn(error), cols - 3)}` : "";
13456
13621
  stdout.write(`\r\x1B[2K${line}${err}`);
13457
13622
  if (err)
13458
13623
  stdout.write("\x1B[1A");
@@ -23469,7 +23634,7 @@ var init_onboarding_lock = __esm(() => {
23469
23634
 
23470
23635
  // lib/claude-sessions.ts
23471
23636
  import { readdirSync as readdirSync17, statSync as statSync19, existsSync as existsSync29 } from "node:fs";
23472
- import { join as join30, basename as basename6 } from "node:path";
23637
+ import { join as join31, basename as basename6 } from "node:path";
23473
23638
  function getClaudeProjectsRoot() {
23474
23639
  return getClaudeProjectsPath();
23475
23640
  }
@@ -23484,7 +23649,7 @@ function listClaudeProjects() {
23484
23649
  return entries.filter((e) => e.isDirectory()).map((e) => ({
23485
23650
  name: e.name,
23486
23651
  cwd: decodeFolderName(e.name),
23487
- path: join30(root, e.name)
23652
+ path: join31(root, e.name)
23488
23653
  }));
23489
23654
  }
23490
23655
  function listClaudeTranscripts(project) {
@@ -23500,7 +23665,7 @@ function listClaudeTranscripts(project) {
23500
23665
  const sessionId = entry.name.slice(0, -".jsonl".length);
23501
23666
  if (!UUID_RE2.test(sessionId))
23502
23667
  continue;
23503
- const transcriptPath = join30(project.path, entry.name);
23668
+ const transcriptPath = join31(project.path, entry.name);
23504
23669
  try {
23505
23670
  const s = statSync19(transcriptPath);
23506
23671
  out.push({
@@ -23514,7 +23679,7 @@ function listClaudeTranscripts(project) {
23514
23679
  });
23515
23680
  } catch {}
23516
23681
  } else if (entry.isDirectory() && UUID_RE2.test(entry.name)) {
23517
- const subDir = join30(project.path, entry.name, "subagents");
23682
+ const subDir = join31(project.path, entry.name, "subagents");
23518
23683
  if (!existsSync29(subDir))
23519
23684
  continue;
23520
23685
  let subEntries;
@@ -23527,7 +23692,7 @@ function listClaudeTranscripts(project) {
23527
23692
  if (!sub.isFile() || !sub.name.endsWith(".jsonl"))
23528
23693
  continue;
23529
23694
  const agentId = sub.name.slice(0, -".jsonl".length);
23530
- const transcriptPath = join30(subDir, sub.name);
23695
+ const transcriptPath = join31(subDir, sub.name);
23531
23696
  try {
23532
23697
  const s = statSync19(transcriptPath);
23533
23698
  out.push({
@@ -24790,8 +24955,8 @@ var init_features = __esm(() => {
24790
24955
 
24791
24956
  // src/audit/cache.ts
24792
24957
  import { createHash as createHash6 } from "node:crypto";
24793
- import { existsSync as existsSync30, mkdirSync as mkdirSync19, readFileSync as readFileSync24, writeFileSync as writeFileSync17, chmodSync as chmodSync4 } from "node:fs";
24794
- import { join as join31 } from "node:path";
24958
+ import { existsSync as existsSync30, mkdirSync as mkdirSync19, readFileSync as readFileSync24, writeFileSync as writeFileSync17, chmodSync as chmodSync5 } from "node:fs";
24959
+ import { join as join32 } from "node:path";
24795
24960
  function getEngineVersion() {
24796
24961
  if (cachedEngineVersion)
24797
24962
  return cachedEngineVersion;
@@ -24811,7 +24976,7 @@ function getDetectorVersion() {
24811
24976
  function getCachePathFor(transcriptPath) {
24812
24977
  const root = auditCacheDir();
24813
24978
  const key = createHash6("sha1").update(transcriptPath).digest("hex");
24814
- return join31(root, `${key}.json`);
24979
+ return join32(root, `${key}.json`);
24815
24980
  }
24816
24981
  function readCachedTranscriptResult(transcriptPath, mtimeMs, sizeBytes) {
24817
24982
  if (sizeBytes === 0)
@@ -24856,7 +25021,7 @@ function writeCachedTranscriptResult(transcriptPath, mtimeMs, sizeBytes, result)
24856
25021
  };
24857
25022
  writeFileSync17(cachePath, JSON.stringify(entry), { encoding: "utf-8", mode: 384 });
24858
25023
  try {
24859
- chmodSync4(cachePath, 384);
25024
+ chmodSync5(cachePath, 384);
24860
25025
  } catch {}
24861
25026
  } catch {}
24862
25027
  }
@@ -25343,6 +25508,7 @@ var init_audit_lock = __esm(() => {
25343
25508
  });
25344
25509
 
25345
25510
  // src/audit/dashboard-cache.ts
25511
+ import { existsSync as existsSync31, readFileSync as readFileSync26 } from "node:fs";
25346
25512
  function getCachePath() {
25347
25513
  return auditDashboardFile();
25348
25514
  }
@@ -25360,6 +25526,27 @@ function writeDashboardCache(params, result) {
25360
25526
  return false;
25361
25527
  }
25362
25528
  }
25529
+ function readDashboardCacheMeta() {
25530
+ const cachePath = getCachePath();
25531
+ if (!existsSync31(cachePath))
25532
+ return null;
25533
+ try {
25534
+ const raw = readFileSync26(cachePath, "utf-8");
25535
+ const entry = JSON.parse(raw);
25536
+ if (!entry || entry.schemaVersion !== DASHBOARD_CACHE_SCHEMA_VERSION || typeof entry.cachedAt !== "string" || Number.isNaN(new Date(entry.cachedAt).getTime()))
25537
+ return null;
25538
+ const result = entry.result;
25539
+ const count = (v) => typeof v === "number" && Number.isFinite(v) ? v : null;
25540
+ return {
25541
+ cachedAt: entry.cachedAt,
25542
+ findings: count(result?.totals?.hits),
25543
+ sessionsScanned: count(result?.transcripts?.scanned),
25544
+ eventsScanned: count(result?.eventsScanned)
25545
+ };
25546
+ } catch {
25547
+ return null;
25548
+ }
25549
+ }
25363
25550
  var DASHBOARD_CACHE_TTL_MINUTES, DASHBOARD_CACHE_SCHEMA_VERSION = 2;
25364
25551
  var init_dashboard_cache = __esm(() => {
25365
25552
  init_atomic_write();
@@ -25434,160 +25621,1095 @@ function openWhenReady(port, path3) {
25434
25621
  var POLL_INTERVAL_MS = 150, POLL_TIMEOUT_MS = 30000;
25435
25622
  var init_open_browser = () => {};
25436
25623
 
25437
- // scripts/parse-script-args.ts
25438
- import { resolve as resolve22 } from "path";
25439
- function parseStringFlag(flagName, errorLabel, inlineValue, args, index, options) {
25440
- const raw = inlineValue ?? args[index + 1];
25441
- if (raw === undefined || inlineValue === null && raw.startsWith("-")) {
25442
- console.error(`Error: ${flagName} requires ${errorLabel}`);
25443
- process.exit(1);
25444
- }
25445
- const value = options?.resolve ? resolve22(raw) : raw;
25446
- return { value, spliceCount: inlineValue !== null ? 1 : 2 };
25624
+ // lib/telemetry.ts
25625
+ function trackEvent(name, properties) {
25626
+ if (!isTelemetryEnabled())
25627
+ return;
25628
+ const client = globalThis.__FAILPROOFAI_POSTHOG__;
25629
+ if (!client)
25630
+ return;
25631
+ client.capture({
25632
+ distinctId: getInstanceId2(),
25633
+ event: name,
25634
+ properties: { ...properties, $lib: "failproofai", failproofai_version: version2, product: POSTHOG_PRODUCT }
25635
+ });
25447
25636
  }
25448
- function parseScriptArgs(argv) {
25449
- const args = [...argv];
25450
- let loggingLevel;
25451
- let disableTelemetry = false;
25452
- let allowedDevOrigins;
25453
- let host;
25454
- for (let i = 0;i < args.length; i++) {
25455
- const arg = args[i];
25456
- const eqIdx = arg.indexOf("=");
25457
- const flag = eqIdx >= 0 ? arg.slice(0, eqIdx) : arg;
25458
- const inlineValue = eqIdx >= 0 ? arg.slice(eqIdx + 1) : null;
25459
- if (flag === "--logging") {
25460
- const raw = inlineValue ?? args[i + 1];
25461
- if (raw === undefined || inlineValue === null && raw.startsWith("-")) {
25462
- console.error("Error: --logging requires a level (info, warn, error)");
25463
- process.exit(1);
25464
- }
25465
- const val = raw.toLowerCase();
25466
- if (val !== "info" && val !== "warn" && val !== "error") {
25467
- console.error("Error: --logging must be one of: info, warn, error");
25468
- process.exit(1);
25469
- }
25470
- loggingLevel = val;
25471
- args.splice(i, inlineValue !== null ? 1 : 2);
25472
- i--;
25473
- continue;
25474
- }
25475
- if (flag === "--disable-telemetry") {
25476
- disableTelemetry = true;
25477
- args.splice(i, 1);
25478
- i--;
25479
- continue;
25480
- }
25481
- if (flag === "--allowed-origins") {
25482
- const { value, spliceCount } = parseStringFlag(flag, "a comma-separated list of origins", inlineValue, args, i);
25483
- allowedDevOrigins = value.split(",").map((s) => s.trim()).filter(Boolean);
25484
- args.splice(i, spliceCount);
25485
- i--;
25486
- continue;
25637
+ var init_telemetry = __esm(() => {
25638
+ init_telemetry_id2();
25639
+ init_telemetry_enabled();
25640
+ init_package();
25641
+ });
25642
+
25643
+ // lib/auth/api-server-client.ts
25644
+ function getApiBase() {
25645
+ const raw = process.env.FAILPROOF_API_URL ?? process.env.FAILPROOFAI_API_URL ?? DEFAULT_API_BASE;
25646
+ return raw.replace(/\/+$/, "");
25647
+ }
25648
+ async function parseError(res) {
25649
+ let body = {};
25650
+ try {
25651
+ body = await res.json();
25652
+ } catch {}
25653
+ const code = body.code ?? `http_${res.status}`;
25654
+ const message = body.message ?? body.detail ?? res.statusText ?? "request failed";
25655
+ let retryAfterSecs = body.retry_after_secs;
25656
+ if (retryAfterSecs === undefined) {
25657
+ const h = res.headers.get("retry-after");
25658
+ if (h) {
25659
+ const n = Number(h);
25660
+ if (Number.isFinite(n))
25661
+ retryAfterSecs = n;
25487
25662
  }
25488
- if (flag === "--host" || flag === "-H" || flag === "--hostname") {
25489
- const { value, spliceCount } = parseStringFlag(flag, "an address to bind (e.g. 127.0.0.1)", inlineValue, args, i);
25490
- host = value;
25491
- args.splice(i, spliceCount);
25492
- i--;
25493
- continue;
25663
+ }
25664
+ if (retryAfterSecs !== undefined) {
25665
+ retryAfterSecs = Math.max(0, Math.min(86400, retryAfterSecs));
25666
+ }
25667
+ return new AuthApiError(res.status, code, message, retryAfterSecs);
25668
+ }
25669
+ function timeoutSignal(extra) {
25670
+ const t = AbortSignal.timeout(REQUEST_TIMEOUT_MS);
25671
+ if (!extra)
25672
+ return t;
25673
+ const anyFn = AbortSignal.any;
25674
+ if (anyFn)
25675
+ return anyFn([t, extra]);
25676
+ const composed = new AbortController;
25677
+ const onAbort = (s) => composed.abort(s.reason);
25678
+ if (t.aborted)
25679
+ onAbort(t);
25680
+ else
25681
+ t.addEventListener("abort", () => onAbort(t), { once: true });
25682
+ if (extra.aborted)
25683
+ onAbort(extra);
25684
+ else
25685
+ extra.addEventListener("abort", () => onAbort(extra), { once: true });
25686
+ return composed.signal;
25687
+ }
25688
+ function pathFromUrl(url) {
25689
+ try {
25690
+ return new URL(url).pathname;
25691
+ } catch {
25692
+ return url;
25693
+ }
25694
+ }
25695
+ async function fetchWithTimeout2(url, init) {
25696
+ try {
25697
+ return await fetch(url, { ...init, signal: timeoutSignal(init.signal ?? undefined) });
25698
+ } catch (err) {
25699
+ const isTimeout = isAbortError(err);
25700
+ trackEvent("api_server_unreachable", {
25701
+ kind: isTimeout ? "timeout" : "network",
25702
+ path: pathFromUrl(url),
25703
+ method: typeof init.method === "string" ? init.method : "GET"
25704
+ });
25705
+ if (isTimeout) {
25706
+ throw new AuthApiError(0, "timeout", `request to ${url} timed out after ${REQUEST_TIMEOUT_MS}ms`);
25494
25707
  }
25708
+ throw err;
25495
25709
  }
25496
- return { loggingLevel, disableTelemetry, allowedDevOrigins, host, remainingArgs: args };
25497
25710
  }
25498
- var init_parse_script_args = () => {};
25711
+ async function postJson(path3, body, init) {
25712
+ const headers = { "content-type": "application/json" };
25713
+ if (init?.accessToken)
25714
+ headers["authorization"] = `Bearer ${init.accessToken}`;
25715
+ const res = await fetchWithTimeout2(`${getApiBase()}${path3}`, {
25716
+ method: "POST",
25717
+ headers,
25718
+ body: JSON.stringify(body)
25719
+ });
25720
+ if (res.status === 204)
25721
+ return;
25722
+ if (!res.ok)
25723
+ throw await parseError(res);
25724
+ return await res.json();
25725
+ }
25726
+ async function requestLoginCode(email) {
25727
+ return postJson("/v0/auth/login/request", { email });
25728
+ }
25729
+ async function verifyLoginCode(email, code) {
25730
+ return postJson("/v0/auth/login/verify", { email, code });
25731
+ }
25732
+ async function refreshAccessToken(refreshToken) {
25733
+ return postJson("/v0/auth/token/refresh", {
25734
+ refresh_token: refreshToken
25735
+ });
25736
+ }
25737
+ async function submitAuditReport(accessToken, body) {
25738
+ return postJson("/v0/audit-reports", body, { accessToken });
25739
+ }
25740
+ var DEFAULT_API_BASE = "https://api.befailproof.ai", AuthApiError, REQUEST_TIMEOUT_MS = 1e4;
25741
+ var init_api_server_client = __esm(() => {
25742
+ init_telemetry();
25743
+ AuthApiError = class AuthApiError extends Error {
25744
+ status;
25745
+ code;
25746
+ retryAfterSecs;
25747
+ constructor(status, code, message, retryAfterSecs) {
25748
+ super(message);
25749
+ this.status = status;
25750
+ this.code = code;
25751
+ this.retryAfterSecs = retryAfterSecs;
25752
+ this.name = "AuthApiError";
25753
+ }
25754
+ };
25755
+ });
25499
25756
 
25500
- // scripts/install-diagnosis.mjs
25501
- import { existsSync as existsSync31, readFileSync as readFileSync26, realpathSync as realpathSync3 } from "node:fs";
25502
- import { dirname as dirname16, resolve as resolve23 } from "node:path";
25503
- import { homedir as homedir25, platform as platform4 } from "node:os";
25504
- import { spawnSync } from "node:child_process";
25505
- function findPackageRoot(start) {
25757
+ // lib/auth/auth-store.ts
25758
+ import { existsSync as existsSync32, readFileSync as readFileSync27, readdirSync as readdirSync18, rmSync as rmSync12 } from "node:fs";
25759
+ import { join as join33, resolve as resolve22 } from "node:path";
25760
+ function getAuthFilePath() {
25761
+ const override = process.env.FAILPROOFAI_AUTH_DIR;
25762
+ return override ? join33(override, "session.json") : auditSessionFile();
25763
+ }
25764
+ function readAuth() {
25765
+ const p = getAuthFilePath();
25766
+ if (!existsSync32(p))
25767
+ return null;
25506
25768
  try {
25507
- let dir = realpathSync3(start);
25508
- if (existsSync31(dir) && !existsSync31(resolve23(dir, "package.json"))) {
25509
- dir = dirname16(dir);
25769
+ const raw = readFileSync27(p, "utf-8");
25770
+ const parsed = JSON.parse(raw);
25771
+ if (typeof parsed.access_token !== "string" || typeof parsed.refresh_token !== "string" || typeof parsed.access_expires_at !== "number" || typeof parsed.user !== "object" || !parsed.user || typeof parsed.user.id !== "string" || typeof parsed.user.email !== "string") {
25772
+ return null;
25510
25773
  }
25511
- while (true) {
25512
- const pkgPath = resolve23(dir, "package.json");
25513
- if (existsSync31(pkgPath)) {
25514
- try {
25515
- const pkg = JSON.parse(readFileSync26(pkgPath, "utf8"));
25516
- if (pkg.name === PKG_NAME)
25517
- return dir;
25518
- } catch {}
25774
+ return {
25775
+ access_token: parsed.access_token,
25776
+ refresh_token: parsed.refresh_token,
25777
+ access_expires_at: parsed.access_expires_at,
25778
+ refresh_expires_at: typeof parsed.refresh_expires_at === "number" ? parsed.refresh_expires_at : parsed.access_expires_at,
25779
+ user: {
25780
+ id: parsed.user.id,
25781
+ email: parsed.user.email
25519
25782
  }
25520
- const parent = dirname16(dir);
25521
- if (parent === dir)
25522
- return null;
25523
- dir = parent;
25524
- }
25783
+ };
25525
25784
  } catch {
25526
25785
  return null;
25527
25786
  }
25528
25787
  }
25529
- function readPackageVersion(packageRoot) {
25530
- if (!packageRoot)
25531
- return null;
25788
+ function writeAuth(auth) {
25789
+ writeJsonAtomically(getAuthFilePath(), auth);
25790
+ }
25791
+ function deleteAuth() {
25792
+ const p = getAuthFilePath();
25793
+ if (existsSync32(p))
25794
+ rmSync12(p, { force: true });
25532
25795
  try {
25533
- const pkg = JSON.parse(readFileSync26(resolve23(packageRoot, "package.json"), "utf8"));
25534
- return typeof pkg.version === "string" ? pkg.version : null;
25535
- } catch {
25536
- return null;
25796
+ const root = migrationsDir();
25797
+ if (!existsSync32(root))
25798
+ return;
25799
+ for (const entry of readdirSync18(root)) {
25800
+ if (!entry.startsWith("backup-layout"))
25801
+ continue;
25802
+ const copy = resolve22(root, entry, "auth.json");
25803
+ if (existsSync32(copy))
25804
+ rmSync12(copy, { force: true });
25805
+ }
25806
+ } catch {}
25807
+ }
25808
+ function authFromTokenResponse(token, existingUser) {
25809
+ const now = Math.floor(Date.now() / 1000);
25810
+ const user = token.user ?? existingUser;
25811
+ if (!user) {
25812
+ throw new Error("authFromTokenResponse: missing user identity");
25537
25813
  }
25814
+ return {
25815
+ access_token: token.access_token,
25816
+ refresh_token: token.refresh_token,
25817
+ access_expires_at: now + token.access_expires_in,
25818
+ refresh_expires_at: now + token.refresh_expires_in,
25819
+ user
25820
+ };
25538
25821
  }
25539
- function resolvePathFirstBinary() {
25822
+ async function dedupedRefresh(auth) {
25823
+ const existing = inFlightRefreshes.get(auth.refresh_token);
25824
+ if (existing)
25825
+ return existing;
25826
+ const p = (async () => {
25827
+ const refreshed = await refreshAccessToken(auth.refresh_token);
25828
+ const next = authFromTokenResponse(refreshed, auth.user);
25829
+ writeAuth(next);
25830
+ return next;
25831
+ })();
25832
+ inFlightRefreshes.set(auth.refresh_token, p);
25540
25833
  try {
25541
- const isWin = platform4() === "win32";
25542
- const res = isWin ? spawnSync("where", [PKG_NAME], { encoding: "utf8" }) : spawnSync("sh", ["-c", `command -v ${PKG_NAME}`], { encoding: "utf8" });
25543
- if (res.status !== 0)
25544
- return null;
25545
- const first = (res.stdout || "").split(/\r?\n/).find((l) => l.trim().length > 0);
25546
- return first ? first.trim() : null;
25547
- } catch {
25548
- return null;
25834
+ return await p;
25835
+ } finally {
25836
+ inFlightRefreshes.delete(auth.refresh_token);
25549
25837
  }
25550
25838
  }
25551
- function locateNpmGlobal() {
25839
+ async function getValidAccessToken() {
25840
+ const auth = readAuth();
25841
+ if (!auth)
25842
+ return null;
25843
+ const now = Math.floor(Date.now() / 1000);
25844
+ if (auth.access_expires_at - now > REFRESH_LEEWAY_SECS)
25845
+ return auth;
25552
25846
  try {
25553
- const res = spawnSync("npm", ["root", "-g"], { encoding: "utf8" });
25554
- if (res.status !== 0)
25555
- return null;
25556
- const root = (res.stdout || "").trim();
25557
- if (!root)
25847
+ return await dedupedRefresh(auth);
25848
+ } catch (err) {
25849
+ if (err instanceof AuthApiError && err.status === 401) {
25850
+ deleteAuth();
25558
25851
  return null;
25559
- const candidate = resolve23(root, PKG_NAME);
25560
- return existsSync31(resolve23(candidate, "package.json")) ? candidate : null;
25561
- } catch {
25852
+ }
25562
25853
  return null;
25563
25854
  }
25564
25855
  }
25565
- function locateBunGlobal() {
25566
- try {
25567
- const candidate = resolve23(homedir25(), ".bun", "install", "global", "node_modules", PKG_NAME);
25568
- return existsSync31(resolve23(candidate, "package.json")) ? candidate : null;
25569
- } catch {
25570
- return null;
25856
+ var REFRESH_LEEWAY_SECS = 60, inFlightRefreshes;
25857
+ var init_auth_store = __esm(() => {
25858
+ init_atomic_write();
25859
+ init_fp_home();
25860
+ init_api_server_client();
25861
+ inFlightRefreshes = new Map;
25862
+ });
25863
+
25864
+ // src/audit/redact-example.ts
25865
+ import { homedir as homedir25 } from "node:os";
25866
+ function maskTruncatedSecret(input) {
25867
+ for (const [pattern, label] of SECRET_PREFIXES) {
25868
+ if (pattern.test(input)) {
25869
+ return input.replace(pattern, `[REDACTED: ${label}]`);
25870
+ }
25571
25871
  }
25872
+ return input;
25572
25873
  }
25573
- function buildRecommendation(pathFirstBin) {
25574
- if (!pathFirstBin)
25575
- return null;
25576
- const bunBinPrefix = resolve23(homedir25(), ".bun", "bin") + "/";
25577
- const bunGlobalPrefix = resolve23(homedir25(), ".bun", "install", "global") + "/";
25578
- const isBun = pathFirstBin.startsWith(bunBinPrefix) || pathFirstBin.startsWith(bunGlobalPrefix);
25579
- if (isBun) {
25580
- return `rm -f ~/.bun/bin/${PKG_NAME} && rm -rf ~/.bun/install/global/node_modules/${PKG_NAME}`;
25874
+ function isSecretName(name) {
25875
+ const upper = name.toUpperCase();
25876
+ if (SECRET_NAME_SUBSTRINGS.some((word) => upper.includes(word)))
25877
+ return true;
25878
+ return upper.split("_").some((part) => SECRET_NAME_COMPONENTS.includes(part));
25879
+ }
25880
+ function maskAssignedSecrets(input) {
25881
+ let out = input.replace(ASSIGNMENT_RE, (match, name, value) => {
25882
+ if (!isSecretName(name))
25883
+ return match;
25884
+ if (value.startsWith("[REDACTED"))
25885
+ return match;
25886
+ return `${name}=[REDACTED: assigned secret]`;
25887
+ });
25888
+ out = out.replace(URL_CREDENTIALS_RE, "$1[REDACTED: URL credentials]@");
25889
+ out = out.replace(BASIC_AUTH_FLAG_RE, "$1[REDACTED: basic auth]");
25890
+ return out;
25891
+ }
25892
+ function maskSecrets(input) {
25893
+ let out = input;
25894
+ for (const [pattern, label] of SECRET_PATTERNS) {
25895
+ const global = new RegExp(pattern.source, pattern.flags.includes("g") ? pattern.flags : `${pattern.flags}g`);
25896
+ out = out.replace(global, `[REDACTED: ${label}]`);
25581
25897
  }
25582
- return `npm rm -g ${PKG_NAME}`;
25898
+ return out;
25583
25899
  }
25584
- function diagnoseShadow(self) {
25585
- const selfPackageRoot = (() => {
25586
- try {
25587
- return self?.selfPackageRoot ? realpathSync3(self.selfPackageRoot) : null;
25588
- } catch {
25589
- return self?.selfPackageRoot ?? null;
25590
- }
25900
+ function shortenPaths(input, home = homedir25()) {
25901
+ const homeRoot = home.replace(/\/+$/, "");
25902
+ return input.replace(ABSOLUTE_PATH_RE, (match, offset, whole) => {
25903
+ if (PUBLIC_PATH_ROOTS.some((root2) => match.startsWith(root2)))
25904
+ return match;
25905
+ if (offset > 0 && whole[offset - 1] === "/" && /[a-z][a-z0-9+.\-]*:$/i.test(whole.slice(0, offset - 1))) {
25906
+ const urlSegments = match.split("/").filter(Boolean);
25907
+ if (urlSegments.length <= 1)
25908
+ return match;
25909
+ const host = urlSegments[0];
25910
+ const leaf = urlSegments[urlSegments.length - 1];
25911
+ const elided = urlSegments.length > 2 ? "/…" : "";
25912
+ return `/${host}${elided}/${leaf}${match.endsWith("/") ? "/" : ""}`;
25913
+ }
25914
+ const trailingSlash = match.endsWith("/");
25915
+ const segments = match.split("/").filter(Boolean);
25916
+ if (segments.length === 0)
25917
+ return match;
25918
+ const basename7 = segments[segments.length - 1];
25919
+ const kept = segments.slice(Math.max(0, segments.length - 1 - KEPT_PARENT_SEGMENTS), segments.length - 1);
25920
+ const matchRoot = match.replace(/\/+$/, "");
25921
+ const underHome = homeRoot.length > 0 && (matchRoot === homeRoot || matchRoot.startsWith(`${homeRoot}/`));
25922
+ if (matchRoot === homeRoot && homeRoot.length > 0) {
25923
+ return trailingSlash ? "~/" : "~";
25924
+ }
25925
+ const root = underHome ? "~" : "";
25926
+ const middle = segments.length - kept.length - 1 > 0 ? "/…" : "";
25927
+ const tail = [...kept, basename7].join("/");
25928
+ return `${root}${middle}/${tail}${trailingSlash ? "/" : ""}`;
25929
+ });
25930
+ }
25931
+ function redactExample(input, home = homedir25()) {
25932
+ const masked = maskAssignedSecrets(maskTruncatedSecret(maskSecrets(input)));
25933
+ const shortened = shortenPaths(masked, home);
25934
+ const collapsed = shortened.replace(/\s+/g, " ").trim();
25935
+ return collapsed.length > REDACTED_EXAMPLE_MAX_CHARS ? `${collapsed.slice(0, REDACTED_EXAMPLE_MAX_CHARS - 1)}…` : collapsed;
25936
+ }
25937
+ var REDACTED_EXAMPLE_MAX_CHARS = 160, KEPT_PARENT_SEGMENTS = 0, ABSOLUTE_PATH_RE, PUBLIC_PATH_ROOTS, SECRET_PREFIXES, SECRET_NAME_SUBSTRINGS, SECRET_NAME_COMPONENTS, ASSIGNMENT_RE, URL_CREDENTIALS_RE, BASIC_AUTH_FLAG_RE;
25938
+ var init_redact_example = __esm(() => {
25939
+ init_builtin_policies();
25940
+ ABSOLUTE_PATH_RE = /(?:\/[\w.\-@+]+){2,}\/?/g;
25941
+ PUBLIC_PATH_ROOTS = ["/dev/", "/proc/", "/sys/"];
25942
+ SECRET_PREFIXES = [
25943
+ [/(?<!\w)(?:Authorization:\s*)?Bearer\s+\S*$/i, "bearer token"],
25944
+ [/(?<!\w)sk-ant-\S*$/, "Anthropic API key"],
25945
+ [/(?<!\w)sk-proj-\S*$/, "OpenAI project API key"],
25946
+ [/(?<!\w)sk-\S*$/, "OpenAI API key"],
25947
+ [/(?<!\w)ghp_\S*$/, "GitHub personal access token"],
25948
+ [/(?<!\w)github_pat_\S*$/, "GitHub fine-grained token"],
25949
+ [/(?<!\w)AKIA\S*$/, "AWS access key ID"],
25950
+ [/(?<!\w)sk_live_\S*$/, "Stripe live secret key"],
25951
+ [/(?<!\w)sk_test_\S*$/, "Stripe test secret key"],
25952
+ [/(?<!\w)AIza\S*$/, "Google API key"],
25953
+ [/-----BEGIN\s[A-Z ]*$/, "private key"]
25954
+ ];
25955
+ SECRET_NAME_SUBSTRINGS = [
25956
+ "TOKEN",
25957
+ "SECRET",
25958
+ "PASSWORD",
25959
+ "PASSWD",
25960
+ "CREDENTIAL",
25961
+ "APIKEY",
25962
+ "PRIVATEKEY"
25963
+ ];
25964
+ SECRET_NAME_COMPONENTS = ["KEY", "PASS", "AUTH", "PAT", "SIG", "SIGNATURE", "SESSION", "COOKIE"];
25965
+ ASSIGNMENT_RE = /\b([A-Za-z_][A-Za-z0-9_]*)=("[^"]*"|'[^']*'|[^\s;|&"']+)/g;
25966
+ URL_CREDENTIALS_RE = /([a-z][a-z0-9+.\-]*:\/\/)[^\s/:@]+:[^\s/@]+@/gi;
25967
+ BASIC_AUTH_FLAG_RE = /((?:^|\s)(?:-u|--user)[\s=])\S+:\S+/g;
25968
+ });
25969
+
25970
+ // src/audit/harm-report.ts
25971
+ function shortName2(name) {
25972
+ const slash = name.indexOf("/");
25973
+ return slash === -1 ? name : name.slice(slash + 1);
25974
+ }
25975
+ function isHarmful(count) {
25976
+ if (count.source !== "builtin")
25977
+ return false;
25978
+ const short = shortName2(count.name);
25979
+ return HARMFUL_SEVERITIES.has(count.severity) || ALSO_HARMFUL.has(short);
25980
+ }
25981
+ function ts(value) {
25982
+ if (!value)
25983
+ return null;
25984
+ const n = Date.parse(value);
25985
+ return Number.isFinite(n) ? n : null;
25986
+ }
25987
+ function selectHarmful(result, from, to, opts = {}) {
25988
+ const includeUnplaceable = opts.includeUnplaceable ?? from === undefined;
25989
+ const fromMs = from ? from.getTime() : null;
25990
+ const toMs2 = to.getTime();
25991
+ const out = [];
25992
+ for (const count of result.results) {
25993
+ if (!isHarmful(count))
25994
+ continue;
25995
+ const last = ts(count.lastSeen);
25996
+ const first = ts(count.firstSeen);
25997
+ if (fromMs !== null && last !== null && last <= fromMs)
25998
+ continue;
25999
+ if (first !== null && first > toMs2)
26000
+ continue;
26001
+ const inWindow = count.examples.filter((e) => {
26002
+ const at2 = ts(e.timestamp);
26003
+ if (at2 === null)
26004
+ return includeUnplaceable;
26005
+ if (fromMs !== null && at2 <= fromMs)
26006
+ return false;
26007
+ return at2 <= toMs2;
26008
+ });
26009
+ const unplaceable = last === null && first === null;
26010
+ if (unplaceable && !includeUnplaceable)
26011
+ continue;
26012
+ const afterLowerEdge = fromMs === null || first !== null && first > fromMs;
26013
+ const beforeUpperEdge = last !== null && last <= toMs2;
26014
+ const wholly = unplaceable || afterLowerEdge && beforeUpperEdge;
26015
+ const floor = beforeUpperEdge ? 1 : 0;
26016
+ const hits = wholly ? count.hits : Math.max(inWindow.length, floor);
26017
+ if (hits <= 0)
26018
+ continue;
26019
+ out.push({
26020
+ policy: shortName2(count.name),
26021
+ category: count.category,
26022
+ title: count.displayTitle ?? "",
26023
+ hits,
26024
+ first_seen: count.firstSeen,
26025
+ last_seen: count.lastSeen,
26026
+ examples: inWindow.map((e) => redactExample(e.example)).filter((e) => e.length > 0)
26027
+ });
26028
+ }
26029
+ out.sort((a, b) => b.hits - a.hits);
26030
+ return out;
26031
+ }
26032
+ function buildHarmReport(result, lastReportedAt, intervalDays) {
26033
+ const to = new Date(Date.parse(result.scannedAt));
26034
+ const windowTo = Number.isFinite(to.getTime()) ? to : new Date;
26035
+ const watermark = ts(lastReportedAt);
26036
+ const isFirstReport = watermark === null;
26037
+ const oneInterval = Math.max(1, intervalDays) * 86400000;
26038
+ const fallbackFrom = windowTo.getTime() - oneInterval;
26039
+ const from = new Date(isFirstReport || watermark >= windowTo.getTime() ? fallbackFrom : watermark);
26040
+ return {
26041
+ window_from: from.toISOString(),
26042
+ window_to: windowTo.toISOString(),
26043
+ harmful: selectHarmful(result, from, windowTo, { includeUnplaceable: isFirstReport })
26044
+ };
26045
+ }
26046
+ var HARMFUL_SEVERITIES, ALSO_HARMFUL;
26047
+ var init_harm_report = __esm(() => {
26048
+ init_redact_example();
26049
+ HARMFUL_SEVERITIES = new Set(["deny", "sanitize"]);
26050
+ ALSO_HARMFUL = new Set(["protect-env-vars"]);
26051
+ });
26052
+
26053
+ // src/audit/machine-store.ts
26054
+ import { existsSync as existsSync33, readFileSync as readFileSync28, rmSync as rmSync13 } from "node:fs";
26055
+ import { hostname as hostname5 } from "node:os";
26056
+ import { randomUUID as randomUUID4 } from "node:crypto";
26057
+ function readMachineIdentity(home) {
26058
+ const path3 = auditMachineFile(home);
26059
+ if (!existsSync33(path3))
26060
+ return null;
26061
+ try {
26062
+ const parsed = JSON.parse(readFileSync28(path3, "utf8"));
26063
+ if (typeof parsed.machine_id !== "string" || !parsed.machine_id)
26064
+ return null;
26065
+ return {
26066
+ machine_id: parsed.machine_id,
26067
+ last_reported_at: typeof parsed.last_reported_at === "string" ? parsed.last_reported_at : undefined,
26068
+ created_at: typeof parsed.created_at === "string" ? parsed.created_at : new Date(0).toISOString()
26069
+ };
26070
+ } catch {
26071
+ return null;
26072
+ }
26073
+ }
26074
+ function ensureMachineIdentity(home) {
26075
+ const existing = readMachineIdentity(home);
26076
+ if (existing)
26077
+ return existing;
26078
+ const fresh = {
26079
+ machine_id: randomUUID4(),
26080
+ created_at: new Date().toISOString()
26081
+ };
26082
+ writeJsonAtomically(auditMachineFile(home), fresh);
26083
+ return fresh;
26084
+ }
26085
+ function recordReportWatermark(nextWindowFrom, home) {
26086
+ const current = ensureMachineIdentity(home);
26087
+ writeJsonAtomically(auditMachineFile(home), {
26088
+ ...current,
26089
+ last_reported_at: nextWindowFrom
26090
+ });
26091
+ }
26092
+ function machineLabel() {
26093
+ try {
26094
+ const h = hostname5().trim();
26095
+ return h.length > 0 ? h : undefined;
26096
+ } catch {
26097
+ return;
26098
+ }
26099
+ }
26100
+ var init_machine_store = __esm(() => {
26101
+ init_atomic_write();
26102
+ init_fp_home();
26103
+ });
26104
+
26105
+ // src/audit/report-harm.ts
26106
+ async function reportHarm(result) {
26107
+ let auto = false;
26108
+ let consentedAt;
26109
+ let intervalDays = 7;
26110
+ try {
26111
+ const config = readConfig();
26112
+ auto = config.audit.auto;
26113
+ consentedAt = config.audit.reportsConsentedAt;
26114
+ intervalDays = config.audit.intervalDays;
26115
+ } catch {
26116
+ return { kind: "disabled" };
26117
+ }
26118
+ if (!auto)
26119
+ return { kind: "disabled" };
26120
+ if (consentedAt === undefined)
26121
+ return { kind: "consent-required" };
26122
+ const auth = await getValidAccessToken();
26123
+ if (!auth) {
26124
+ return { kind: "signed-out" };
26125
+ }
26126
+ let identity2;
26127
+ try {
26128
+ identity2 = ensureMachineIdentity();
26129
+ } catch (err) {
26130
+ return { kind: "failed", error: err instanceof Error ? err.message : String(err) };
26131
+ }
26132
+ const report = buildHarmReport(result, identity2.last_reported_at, intervalDays);
26133
+ const hits = report.harmful.reduce((n, p) => n + p.hits, 0);
26134
+ try {
26135
+ const res = await submitAuditReport(auth.access_token, {
26136
+ machine_id: identity2.machine_id,
26137
+ label: machineLabel(),
26138
+ platform: process.platform,
26139
+ window_from: report.window_from,
26140
+ window_to: report.window_to,
26141
+ harmful: report.harmful
26142
+ });
26143
+ try {
26144
+ recordReportWatermark(res.next_window_from);
26145
+ } catch {}
26146
+ return res.emailed ? { kind: "sent", hits } : { kind: "held", hits, reason: res.reason ?? "not_sent" };
26147
+ } catch (err) {
26148
+ const error = err instanceof AuthApiError ? `${err.code}: ${err.message}` : err instanceof Error ? err.message : String(err);
26149
+ return { kind: "failed", error };
26150
+ }
26151
+ }
26152
+ function describeOutcome2(outcome) {
26153
+ switch (outcome.kind) {
26154
+ case "disabled":
26155
+ return null;
26156
+ case "consent-required":
26157
+ return "failproofai: scheduled scans are on, but emailing what they find needs a fresh opt-in — run `failproofai audit --schedule` (or visit /settings) to turn digests on";
26158
+ case "signed-out":
26159
+ return "failproofai: emailed reports are on but this machine is signed out — run `failproofai audit --schedule` or visit /settings to resume them";
26160
+ case "sent":
26161
+ return `failproofai: emailed a harm digest (${outcome.hits} finding${outcome.hits === 1 ? "" : "s"})`;
26162
+ case "held":
26163
+ return `failproofai: ${outcome.hits} finding${outcome.hits === 1 ? "" : "s"} reported, no email (${outcome.reason})`;
26164
+ case "failed":
26165
+ return `failproofai: could not send the harm report: ${outcome.error}`;
26166
+ }
26167
+ }
26168
+ var init_report_harm = __esm(() => {
26169
+ init_auth_store();
26170
+ init_api_server_client();
26171
+ init_fp_config();
26172
+ init_harm_report();
26173
+ init_machine_store();
26174
+ });
26175
+
26176
+ // src/audit/audit-schedule.ts
26177
+ import { readFileSync as readFileSync29 } from "node:fs";
26178
+ function readAuditSchedule(home) {
26179
+ let raw;
26180
+ try {
26181
+ raw = readFileSync29(auditScheduleFile(home), "utf8");
26182
+ } catch {
26183
+ return null;
26184
+ }
26185
+ let parsed;
26186
+ try {
26187
+ parsed = JSON.parse(raw);
26188
+ } catch {
26189
+ return null;
26190
+ }
26191
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed))
26192
+ return null;
26193
+ const obj = parsed;
26194
+ const num = (v) => typeof v === "number" && Number.isFinite(v) ? v : null;
26195
+ const schema = num(obj.schema);
26196
+ return {
26197
+ schema,
26198
+ nextDueAtMs: num(obj.next_due_at_ms),
26199
+ lastAttemptAtMs: num(obj.last_attempt_at_ms),
26200
+ lastRunAtMs: num(obj.last_run_at_ms),
26201
+ lastExitCode: num(obj.last_exit_code),
26202
+ schemaAhead: schema !== null && schema > AUDIT_SCHEDULE_SCHEMA
26203
+ };
26204
+ }
26205
+ var AUDIT_SCHEDULE_SCHEMA = 1;
26206
+ var init_audit_schedule = __esm(() => {
26207
+ init_fp_home();
26208
+ });
26209
+
26210
+ // src/audit/cli-login.ts
26211
+ var exports_cli_login = {};
26212
+ __export(exports_cli_login, {
26213
+ runLogin: () => runLogin,
26214
+ invalidEmail: () => invalidEmail,
26215
+ extractCode: () => extractCode,
26216
+ ensureSignedIn: () => ensureSignedIn,
26217
+ canPrompt: () => canPrompt,
26218
+ LoginError: () => LoginError
26219
+ });
26220
+ function spine() {
26221
+ return colorsEnabled(process.stdout) ? `${ANSI_DIM_BAR}${BAR}${ANSI_RESET} ` : "";
26222
+ }
26223
+ function extractCode(raw) {
26224
+ const trimmed = raw.trim();
26225
+ if (/^\d+$/.test(trimmed))
26226
+ return trimmed;
26227
+ const runs = trimmed.match(/\d+/g) ?? [];
26228
+ if (runs.length === 0)
26229
+ return trimmed;
26230
+ const whole = runs.find((run) => run.length >= CODE_MIN);
26231
+ if (whole)
26232
+ return whole;
26233
+ return runs.join("");
26234
+ }
26235
+ function canPrompt() {
26236
+ return Boolean(process.stdin.isTTY && process.stdout.isTTY);
26237
+ }
26238
+ function sessionStillValid(auth) {
26239
+ if (!auth)
26240
+ return null;
26241
+ return auth.refresh_expires_at * 1000 > Date.now() ? auth : null;
26242
+ }
26243
+ async function ensureSignedIn(preset) {
26244
+ const existing = sessionStillValid(readAuth());
26245
+ if (existing) {
26246
+ if (preset && !sameAddress(preset, existing.user.email)) {
26247
+ throw new LoginError(`This machine is already signed in as ${existing.user.email}.
26248
+ ` + `To report as ${preset.trim().toLowerCase()} instead, sign out first — ` + `from the dashboard, or by removing ~/.failproofai/audit/session.json.`);
26249
+ }
26250
+ return { user: existing.user, prompted: false };
26251
+ }
26252
+ if (!canPrompt()) {
26253
+ throw new LoginError(`Signing in needs an interactive terminal, and this one is not.
26254
+ ` + "Run `failproofai audit --schedule` from a shell you are sitting at,\n" + "or sign in from the dashboard — both write the same session file.");
26255
+ }
26256
+ return { user: await runLogin(preset), prompted: true };
26257
+ }
26258
+ function sameAddress(a, b) {
26259
+ return a.trim().toLowerCase() === b.trim().toLowerCase();
26260
+ }
26261
+ function invalidEmail(address) {
26262
+ return EMAIL_RE.test(address.trim()) ? null : `\`--email\` needs an email address (got: ${address}).`;
26263
+ }
26264
+ async function runLogin(preset) {
26265
+ intro("scheduled audits need somewhere to send the report");
26266
+ let address;
26267
+ if (preset) {
26268
+ address = preset.trim().toLowerCase();
26269
+ step("your email", address);
26270
+ } else {
26271
+ const email = await promptText({
26272
+ prefix: spine(),
26273
+ message: "your email",
26274
+ hint: "you@yourdomain.com",
26275
+ validate: (v) => EMAIL_RE.test(v.trim()) ? null : "that doesn't look like an email"
26276
+ });
26277
+ if (email === null) {
26278
+ outro("Cancelled — nothing was changed.", { ok: false });
26279
+ throw new LoginError("Cancelled.");
26280
+ }
26281
+ address = email.trim().toLowerCase();
26282
+ }
26283
+ let expiresInMin = 10;
26284
+ try {
26285
+ const sent = await requestLoginCode(address);
26286
+ expiresInMin = Math.max(1, Math.ceil(sent.expires_in / 60));
26287
+ } catch (err) {
26288
+ outro("Could not send a login code.", { ok: false });
26289
+ throw new LoginError(describeAuthError(err, "Could not send a login code"));
26290
+ }
26291
+ step("code sent", `to ${address} · expires in ${expiresInMin} min`);
26292
+ const ATTEMPTS = 3;
26293
+ for (let attempt = 1;attempt <= ATTEMPTS; attempt += 1) {
26294
+ stepOpen(attempt === 1 ? "the code from that email" : "try that code again");
26295
+ const typed = await promptText({
26296
+ prefix: spine(),
26297
+ message: "code",
26298
+ hint: attempt === 1 ? "123456 · paste the whole line if you like" : `attempt ${attempt} of ${ATTEMPTS}`,
26299
+ validate: (v) => {
26300
+ if (!/\d/.test(v))
26301
+ return "a code is digits — paste the line from the email";
26302
+ const code = extractCode(v);
26303
+ if (code.length < CODE_MIN)
26304
+ return "that looks too short to be the code";
26305
+ if (code.length > CODE_MAX)
26306
+ return "that looks too long — paste just the code";
26307
+ return null;
26308
+ }
26309
+ });
26310
+ if (typed === null) {
26311
+ outro("Cancelled — nothing was changed.", { ok: false });
26312
+ throw new LoginError("Cancelled.");
26313
+ }
26314
+ try {
26315
+ const tokens = await verifyLoginCode(address, extractCode(typed));
26316
+ writeAuth(authFromTokenResponse(tokens));
26317
+ step("signed in", tokens.user.email);
26318
+ return { id: tokens.user.id, email: tokens.user.email };
26319
+ } catch (err) {
26320
+ const wrongCode = err instanceof AuthApiError && err.code === "invalid_code";
26321
+ if (wrongCode && attempt < ATTEMPTS) {
26322
+ step("that code was wrong or expired", `${ATTEMPTS - attempt} more ${ATTEMPTS - attempt === 1 ? "try" : "tries"} before it asks for a new one`);
26323
+ continue;
26324
+ }
26325
+ outro("Could not verify that code.", { ok: false });
26326
+ throw new LoginError(describeAuthError(err, "Could not verify that code"));
26327
+ }
26328
+ }
26329
+ outro("Too many wrong codes.", { ok: false });
26330
+ throw new LoginError("Too many wrong codes. Run the command again for a fresh one.");
26331
+ }
26332
+ function describeAuthError(err, prefix) {
26333
+ if (err instanceof AuthApiError) {
26334
+ if (err.code === "rate_limited") {
26335
+ const wait = err.retryAfterSecs;
26336
+ return `${prefix}: too many attempts.${wait ? ` Try again in ${wait}s.` : ""}`;
26337
+ }
26338
+ if (err.status === 0 || err.code === "timeout") {
26339
+ return `${prefix}: the api-server did not respond.
26340
+ ` + `It is at ${apiBaseForMessage()} — check that it is running,
26341
+ ` + `or set FAILPROOF_API_URL to point somewhere else.`;
26342
+ }
26343
+ return `${prefix}: ${err.message}`;
26344
+ }
26345
+ return `${prefix}: ${err instanceof Error ? err.message : String(err)}`;
26346
+ }
26347
+ function apiBaseForMessage() {
26348
+ return process.env.FAILPROOF_API_URL ?? process.env.FAILPROOFAI_API_URL ?? "https://api.befailproof.ai";
26349
+ }
26350
+ var EMAIL_RE, CODE_MIN = 4, CODE_MAX = 12, ANSI_DIM_BAR = "\x1B[2m", LoginError;
26351
+ var init_cli_login = __esm(() => {
26352
+ init_api_server_client();
26353
+ init_auth_store();
26354
+ init_tui();
26355
+ EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
26356
+ LoginError = class LoginError extends Error {
26357
+ };
26358
+ });
26359
+
26360
+ // src/audit/schedule-cli.ts
26361
+ var exports_schedule_cli = {};
26362
+ __export(exports_schedule_cli, {
26363
+ runScheduleStatus: () => runScheduleStatus,
26364
+ runScheduleOn: () => runScheduleOn,
26365
+ runScheduleOff: () => runScheduleOff,
26366
+ asScheduleError: () => asScheduleError,
26367
+ ScheduleCliError: () => ScheduleCliError
26368
+ });
26369
+ function row(label, value, note) {
26370
+ const gap = " ".repeat(Math.max(1, LABEL_WIDTH - label.length));
26371
+ return `${rail()} ${dim(label)}${gap}${value}${note ? ` ${dim(note)}` : ""}`;
26372
+ }
26373
+ async function runScheduleOn(daysArg, emailArg) {
26374
+ let days;
26375
+ if (daysArg !== undefined) {
26376
+ const parsed = Number(daysArg);
26377
+ if (!Number.isFinite(parsed) || !Number.isInteger(parsed)) {
26378
+ throw new ScheduleCliError(`\`--schedule\` takes a whole number of days (got: ${daysArg}).`);
26379
+ }
26380
+ if (parsed < MIN_DAYS || parsed > MAX_DAYS) {
26381
+ throw new ScheduleCliError(`\`--schedule\` must be between ${MIN_DAYS} and ${MAX_DAYS} days (got: ${parsed}).`);
26382
+ }
26383
+ days = parsed;
26384
+ }
26385
+ if (emailArg !== undefined) {
26386
+ const bad = invalidEmail(emailArg);
26387
+ if (bad)
26388
+ throw new ScheduleCliError(bad);
26389
+ }
26390
+ const { user, prompted } = await ensureSignedIn(emailArg);
26391
+ const next = updateConfig({
26392
+ audit: {
26393
+ auto: true,
26394
+ reportsConsentedAt: Date.now(),
26395
+ ...days !== undefined ? { intervalDays: days } : {}
26396
+ }
26397
+ });
26398
+ const interval = next.audit.intervalDays;
26399
+ const summary = [
26400
+ `every ${interval} day${interval === 1 ? "" : "s"} · reports to ${user.email}`,
26401
+ "you only hear from it when a scan finds something harmful",
26402
+ "each report sends: finding counts, redacted example commands, this machine's name"
26403
+ ];
26404
+ if (prompted) {
26405
+ step("scheduled audits are on", summary);
26406
+ } else {
26407
+ process.stdout.write(`
26408
+ ${green("✓")} ${bold("scheduled audits are on")}
26409
+ ` + summary.map((r) => ` ${dim(r)}
26410
+ `).join(""));
26411
+ }
26412
+ warnIfDaemonWontRun();
26413
+ if (prompted) {
26414
+ outro("failproofai audit --status · when the next scan is due");
26415
+ } else {
26416
+ process.stdout.write(dim(`
26417
+ failproofai audit --status when the next scan is due
26418
+
26419
+ `));
26420
+ }
26421
+ }
26422
+ function runScheduleOff() {
26423
+ const before = readConfig().audit.auto;
26424
+ const next = updateConfig({ audit: { auto: false } });
26425
+ if (next.audit.auto) {
26426
+ process.stdout.write(`Could not turn scheduled audits off.
26427
+ `);
26428
+ return;
26429
+ }
26430
+ if (!before) {
26431
+ process.stdout.write(dim(`
26432
+ Scheduled audits were already off.
26433
+
26434
+ `));
26435
+ return;
26436
+ }
26437
+ process.stdout.write(`
26438
+ ${green("✓")} ${bold("scheduled audits are off")}
26439
+ ` + ` ${dim("nothing runs on a timer and nothing is sent")}
26440
+ ` + ` ${dim("your session is untouched — sign out from the dashboard for that")}
26441
+
26442
+ `);
26443
+ }
26444
+ function runScheduleStatus() {
26445
+ const config = readConfig();
26446
+ const auth = readAuth();
26447
+ const sched = readAuditSchedule();
26448
+ const meta = readDashboardCacheMeta();
26449
+ const machine = readMachineIdentity();
26450
+ const daemon = daemonServiceStatus();
26451
+ const on = config.audit.auto;
26452
+ const out = [""];
26453
+ out.push(`${rail()} ${bold("scheduled audit")} ${on ? green("on") : dim("off")}` + (on ? dim(` every ${config.audit.intervalDays} days`) : ""));
26454
+ out.push(rail());
26455
+ const live = auth && auth.refresh_expires_at * 1000 > Date.now() ? auth : null;
26456
+ out.push(row("reports to", live ? live.user.email : dim("— signed out")));
26457
+ if (on && !live) {
26458
+ out.push(row("", pink("scans continue; digests are paused until you sign in")));
26459
+ } else if (on && config.audit.reportsConsentedAt === undefined) {
26460
+ out.push(row("", pink("scans continue; digests need a fresh opt-in — run `--schedule` to turn them on")));
26461
+ }
26462
+ out.push(row("daemon", describeDaemon(daemon)));
26463
+ if (sched?.nextDueAtMs != null && on) {
26464
+ out.push(row("next scan", untilPhrase(sched.nextDueAtMs)));
26465
+ }
26466
+ if (sched?.lastRunAtMs != null) {
26467
+ const exit = sched.lastExitCode;
26468
+ out.push(row("last scheduled", agoPhrase(sched.lastRunAtMs), exit != null && exit !== 0 && exit !== 75 ? pink(`exit ${exit}`) : undefined));
26469
+ }
26470
+ out.push(row("last result", meta?.cachedAt ? agoPhrase(Date.parse(meta.cachedAt)) : dim("none yet")));
26471
+ if (machine?.last_reported_at) {
26472
+ out.push(row("last reported", agoPhrase(Date.parse(machine.last_reported_at))));
26473
+ }
26474
+ out.push("");
26475
+ process.stdout.write(out.join(`
26476
+ `));
26477
+ }
26478
+ function describeDaemon(status) {
26479
+ switch (status) {
26480
+ case "running":
26481
+ return green("running");
26482
+ case "stopped":
26483
+ return pink("stopped — run `failproofai config` to repair it");
26484
+ case "not-installed":
26485
+ return pink("not installed — run `failproofai config`");
26486
+ case "condition-failed":
26487
+ return pink("installed but its binary is missing — run `failproofai config`");
26488
+ default:
26489
+ return isDaemonSupportedPlatform() ? dim(String(status)) : dim("unavailable on this platform");
26490
+ }
26491
+ }
26492
+ function warnIfDaemonWontRun() {
26493
+ const status = daemonServiceStatus();
26494
+ if (status === "running")
26495
+ return;
26496
+ if (status === "unknown")
26497
+ return;
26498
+ if (!isDaemonSupportedPlatform()) {
26499
+ process.stderr.write(`
26500
+ ${pink("!")} The background service is not available on this platform,
26501
+ ` + ` so nothing will run on the timer here. \`failproofai audit\` still works.
26502
+ `);
26503
+ return;
26504
+ }
26505
+ process.stderr.write(`
26506
+ ${pink("!")} The background service is ${status.replace("-", " ")}, ` + `so nothing will run on the timer yet.
26507
+ ` + ` Run \`failproofai config\` to install or repair it.
26508
+ `);
26509
+ }
26510
+ function untilPhrase(ms) {
26511
+ const diff = ms - Date.now();
26512
+ if (diff <= 0)
26513
+ return "due now";
26514
+ const d = Math.floor(diff / 86400000);
26515
+ const h = Math.floor(diff % 86400000 / 3600000);
26516
+ if (d > 0)
26517
+ return `in ${d}d${h > 0 ? ` ${h}h` : ""}`;
26518
+ if (h > 0)
26519
+ return `in ${h}h`;
26520
+ return `in ${Math.max(1, Math.floor(diff / 60000))}m`;
26521
+ }
26522
+ function agoPhrase(ms) {
26523
+ if (!Number.isFinite(ms))
26524
+ return "unknown";
26525
+ const diff = Date.now() - ms;
26526
+ if (diff < 0)
26527
+ return "just now";
26528
+ const d = Math.floor(diff / 86400000);
26529
+ const h = Math.floor(diff / 3600000);
26530
+ const m = Math.floor(diff / 60000);
26531
+ if (d > 0)
26532
+ return `${d}d ago`;
26533
+ if (h > 0)
26534
+ return `${h}h ago`;
26535
+ if (m > 0)
26536
+ return `${m}m ago`;
26537
+ return "just now";
26538
+ }
26539
+ function asScheduleError(err) {
26540
+ if (err instanceof LoginError || err instanceof ScheduleCliError) {
26541
+ throw new ScheduleCliError(err.message);
26542
+ }
26543
+ throw err;
26544
+ }
26545
+ var MIN_DAYS = 1, MAX_DAYS = 90, ScheduleCliError, styled = () => colorsEnabled(process.stdout), wrap = (open2, s) => styled() ? `${open2}${s}${ANSI_RESET}` : s, pink = (s) => wrap(brandAnsi("pink"), s), green = (s) => wrap(brandAnsi("guide"), s), dim = (s) => wrap(ANSI_DIM, s), bold = (s) => wrap(ANSI_BOLD, s), rail = () => " ", LABEL_WIDTH = 15;
26546
+ var init_schedule_cli = __esm(() => {
26547
+ init_fp_config();
26548
+ init_daemon_service();
26549
+ init_auth_store();
26550
+ init_audit_schedule();
26551
+ init_dashboard_cache();
26552
+ init_machine_store();
26553
+ init_cli_login();
26554
+ init_tui();
26555
+ ScheduleCliError = class ScheduleCliError extends Error {
26556
+ };
26557
+ });
26558
+
26559
+ // scripts/parse-script-args.ts
26560
+ import { resolve as resolve23 } from "path";
26561
+ function parseStringFlag(flagName, errorLabel, inlineValue, args, index, options) {
26562
+ const raw = inlineValue ?? args[index + 1];
26563
+ if (raw === undefined || inlineValue === null && raw.startsWith("-")) {
26564
+ console.error(`Error: ${flagName} requires ${errorLabel}`);
26565
+ process.exit(1);
26566
+ }
26567
+ const value = options?.resolve ? resolve23(raw) : raw;
26568
+ return { value, spliceCount: inlineValue !== null ? 1 : 2 };
26569
+ }
26570
+ function parseScriptArgs(argv) {
26571
+ const args = [...argv];
26572
+ let loggingLevel;
26573
+ let disableTelemetry = false;
26574
+ let allowedDevOrigins;
26575
+ let host;
26576
+ for (let i = 0;i < args.length; i++) {
26577
+ const arg = args[i];
26578
+ const eqIdx = arg.indexOf("=");
26579
+ const flag = eqIdx >= 0 ? arg.slice(0, eqIdx) : arg;
26580
+ const inlineValue = eqIdx >= 0 ? arg.slice(eqIdx + 1) : null;
26581
+ if (flag === "--logging") {
26582
+ const raw = inlineValue ?? args[i + 1];
26583
+ if (raw === undefined || inlineValue === null && raw.startsWith("-")) {
26584
+ console.error("Error: --logging requires a level (info, warn, error)");
26585
+ process.exit(1);
26586
+ }
26587
+ const val = raw.toLowerCase();
26588
+ if (val !== "info" && val !== "warn" && val !== "error") {
26589
+ console.error("Error: --logging must be one of: info, warn, error");
26590
+ process.exit(1);
26591
+ }
26592
+ loggingLevel = val;
26593
+ args.splice(i, inlineValue !== null ? 1 : 2);
26594
+ i--;
26595
+ continue;
26596
+ }
26597
+ if (flag === "--disable-telemetry") {
26598
+ disableTelemetry = true;
26599
+ args.splice(i, 1);
26600
+ i--;
26601
+ continue;
26602
+ }
26603
+ if (flag === "--allowed-origins") {
26604
+ const { value, spliceCount } = parseStringFlag(flag, "a comma-separated list of origins", inlineValue, args, i);
26605
+ allowedDevOrigins = value.split(",").map((s) => s.trim()).filter(Boolean);
26606
+ args.splice(i, spliceCount);
26607
+ i--;
26608
+ continue;
26609
+ }
26610
+ if (flag === "--host" || flag === "-H" || flag === "--hostname") {
26611
+ const { value, spliceCount } = parseStringFlag(flag, "an address to bind (e.g. 127.0.0.1)", inlineValue, args, i);
26612
+ host = value;
26613
+ args.splice(i, spliceCount);
26614
+ i--;
26615
+ continue;
26616
+ }
26617
+ }
26618
+ return { loggingLevel, disableTelemetry, allowedDevOrigins, host, remainingArgs: args };
26619
+ }
26620
+ var init_parse_script_args = () => {};
26621
+
26622
+ // scripts/install-diagnosis.mjs
26623
+ import { existsSync as existsSync34, readFileSync as readFileSync30, realpathSync as realpathSync3 } from "node:fs";
26624
+ import { dirname as dirname16, resolve as resolve24 } from "node:path";
26625
+ import { homedir as homedir26, platform as platform4 } from "node:os";
26626
+ import { spawnSync } from "node:child_process";
26627
+ function findPackageRoot(start) {
26628
+ try {
26629
+ let dir = realpathSync3(start);
26630
+ if (existsSync34(dir) && !existsSync34(resolve24(dir, "package.json"))) {
26631
+ dir = dirname16(dir);
26632
+ }
26633
+ while (true) {
26634
+ const pkgPath = resolve24(dir, "package.json");
26635
+ if (existsSync34(pkgPath)) {
26636
+ try {
26637
+ const pkg = JSON.parse(readFileSync30(pkgPath, "utf8"));
26638
+ if (pkg.name === PKG_NAME)
26639
+ return dir;
26640
+ } catch {}
26641
+ }
26642
+ const parent = dirname16(dir);
26643
+ if (parent === dir)
26644
+ return null;
26645
+ dir = parent;
26646
+ }
26647
+ } catch {
26648
+ return null;
26649
+ }
26650
+ }
26651
+ function readPackageVersion(packageRoot) {
26652
+ if (!packageRoot)
26653
+ return null;
26654
+ try {
26655
+ const pkg = JSON.parse(readFileSync30(resolve24(packageRoot, "package.json"), "utf8"));
26656
+ return typeof pkg.version === "string" ? pkg.version : null;
26657
+ } catch {
26658
+ return null;
26659
+ }
26660
+ }
26661
+ function resolvePathFirstBinary() {
26662
+ try {
26663
+ const isWin = platform4() === "win32";
26664
+ const res = isWin ? spawnSync("where", [PKG_NAME], { encoding: "utf8" }) : spawnSync("sh", ["-c", `command -v ${PKG_NAME}`], { encoding: "utf8" });
26665
+ if (res.status !== 0)
26666
+ return null;
26667
+ const first = (res.stdout || "").split(/\r?\n/).find((l) => l.trim().length > 0);
26668
+ return first ? first.trim() : null;
26669
+ } catch {
26670
+ return null;
26671
+ }
26672
+ }
26673
+ function locateNpmGlobal() {
26674
+ try {
26675
+ const res = spawnSync("npm", ["root", "-g"], { encoding: "utf8" });
26676
+ if (res.status !== 0)
26677
+ return null;
26678
+ const root = (res.stdout || "").trim();
26679
+ if (!root)
26680
+ return null;
26681
+ const candidate = resolve24(root, PKG_NAME);
26682
+ return existsSync34(resolve24(candidate, "package.json")) ? candidate : null;
26683
+ } catch {
26684
+ return null;
26685
+ }
26686
+ }
26687
+ function locateBunGlobal() {
26688
+ try {
26689
+ const candidate = resolve24(homedir26(), ".bun", "install", "global", "node_modules", PKG_NAME);
26690
+ return existsSync34(resolve24(candidate, "package.json")) ? candidate : null;
26691
+ } catch {
26692
+ return null;
26693
+ }
26694
+ }
26695
+ function buildRecommendation(pathFirstBin) {
26696
+ if (!pathFirstBin)
26697
+ return null;
26698
+ const bunBinPrefix = resolve24(homedir26(), ".bun", "bin") + "/";
26699
+ const bunGlobalPrefix = resolve24(homedir26(), ".bun", "install", "global") + "/";
26700
+ const isBun = pathFirstBin.startsWith(bunBinPrefix) || pathFirstBin.startsWith(bunGlobalPrefix);
26701
+ if (isBun) {
26702
+ return `rm -f ~/.bun/bin/${PKG_NAME} && rm -rf ~/.bun/install/global/node_modules/${PKG_NAME}`;
26703
+ }
26704
+ return `npm rm -g ${PKG_NAME}`;
26705
+ }
26706
+ function diagnoseShadow(self) {
26707
+ const selfPackageRoot = (() => {
26708
+ try {
26709
+ return self?.selfPackageRoot ? realpathSync3(self.selfPackageRoot) : null;
26710
+ } catch {
26711
+ return self?.selfPackageRoot ?? null;
26712
+ }
25591
26713
  })();
25592
26714
  const selfVersion = self?.selfVersion ?? null;
25593
26715
  const pathFirstBin = resolvePathFirstBinary();
@@ -25649,8 +26771,8 @@ function makeSkewLogFilter() {
25649
26771
  }
25650
26772
 
25651
26773
  // lib/dashboard-host.ts
25652
- function isLoopbackHostname(hostname5) {
25653
- const h = hostname5.trim().toLowerCase();
26774
+ function isLoopbackHostname(hostname6) {
26775
+ const h = hostname6.trim().toLowerCase();
25654
26776
  if (!h)
25655
26777
  return false;
25656
26778
  if (LOOPBACK_HOSTNAMES.has(h))
@@ -25672,8 +26794,8 @@ __export(exports_launch, {
25672
26794
  launch: () => launch
25673
26795
  });
25674
26796
  import { spawn as spawn2 } from "child_process";
25675
- import { realpathSync as realpathSync4, existsSync as existsSync32 } from "node:fs";
25676
- import { resolve as resolve24, dirname as dirname17 } from "node:path";
26797
+ import { realpathSync as realpathSync4, existsSync as existsSync35 } from "node:fs";
26798
+ import { resolve as resolve25, dirname as dirname17 } from "node:path";
25677
26799
  import { fileURLToPath as fileURLToPath2 } from "node:url";
25678
26800
  import { createInterface } from "node:readline";
25679
26801
  function launch(mode) {
@@ -25697,9 +26819,9 @@ function launch(mode) {
25697
26819
  process.env.PORT = port;
25698
26820
  process.env.HOSTNAME = bindHost;
25699
26821
  cmd = "node";
25700
- const packageRoot = process.env.FAILPROOFAI_PACKAGE_ROOT ?? resolve24(dirname17(realpathSync4(fileURLToPath2(import.meta.url))), "..");
25701
- const serverJsPath = resolve24(packageRoot, ".next/standalone/server.js");
25702
- if (!existsSync32(serverJsPath)) {
26822
+ const packageRoot = process.env.FAILPROOFAI_PACKAGE_ROOT ?? resolve25(dirname17(realpathSync4(fileURLToPath2(import.meta.url))), "..");
26823
+ const serverJsPath = resolve25(packageRoot, ".next/standalone/server.js");
26824
+ if (!existsSync35(serverJsPath)) {
25703
26825
  let shadowMessage = null;
25704
26826
  try {
25705
26827
  const diag = diagnoseShadow({ selfPackageRoot: packageRoot, selfVersion: version2 });
@@ -25961,6 +27083,13 @@ async function runScheduledAudit() {
25961
27083
  }
25962
27084
  process.stdout.write(`failproofai: audit complete — ${num(result.eventsScanned)} tool calls across ` + `${num(result.transcripts.scanned)} sessions, ${num(result.totals.hits)} hits
25963
27085
  `);
27086
+ const outcome = await reportHarm(result);
27087
+ const line = describeOutcome2(outcome);
27088
+ if (line) {
27089
+ const stream = outcome.kind === "sent" ? process.stdout : process.stderr;
27090
+ stream.write(`${line}
27091
+ `);
27092
+ }
25964
27093
  return 0;
25965
27094
  } finally {
25966
27095
  attempt.lock.release();
@@ -26025,15 +27154,71 @@ async function runAuditCli(args) {
26025
27154
  die(`\`audit --scheduled\` takes no other arguments (got: ${extra}).`);
26026
27155
  process.exit(await runScheduledAudit());
26027
27156
  }
27157
+ if (args.includes("--status")) {
27158
+ const extra = args.find((a) => a !== "--status");
27159
+ if (extra)
27160
+ die(`\`audit --status\` takes no other arguments (got: ${extra}).`);
27161
+ const { runScheduleStatus: runScheduleStatus2 } = await Promise.resolve().then(() => (init_schedule_cli(), exports_schedule_cli));
27162
+ runScheduleStatus2();
27163
+ process.exit(0);
27164
+ }
27165
+ if (args.includes("--no-schedule")) {
27166
+ const extra = args.find((a) => a !== "--no-schedule");
27167
+ if (extra)
27168
+ die(`\`audit --no-schedule\` takes no other arguments (got: ${extra}).`);
27169
+ const { runScheduleOff: runScheduleOff2 } = await Promise.resolve().then(() => (init_schedule_cli(), exports_schedule_cli));
27170
+ runScheduleOff2();
27171
+ process.exit(0);
27172
+ }
27173
+ const scheduleAt = args.indexOf("--schedule");
27174
+ if (scheduleAt !== -1) {
27175
+ let days;
27176
+ let email;
27177
+ for (let i = 0;i < args.length; i += 1) {
27178
+ const a = args[i];
27179
+ if (a === "--schedule") {
27180
+ const next = args[i + 1];
27181
+ if (next !== undefined && !next.startsWith("-")) {
27182
+ days = next;
27183
+ i += 1;
27184
+ }
27185
+ continue;
27186
+ }
27187
+ if (a === "--email" || a.startsWith("--email=")) {
27188
+ if (a.startsWith("--email=")) {
27189
+ email = a.slice("--email=".length);
27190
+ } else {
27191
+ email = args[i + 1];
27192
+ i += 1;
27193
+ }
27194
+ if (email === undefined || email.length === 0 || email.startsWith("-")) {
27195
+ die("`--email` needs an address, e.g. `--email you@yourdomain.com`.");
27196
+ }
27197
+ continue;
27198
+ }
27199
+ die(`\`audit --schedule\` does not take ${a}.`);
27200
+ }
27201
+ const { runScheduleOn: runScheduleOn2, ScheduleCliError: ScheduleCliError2 } = await Promise.resolve().then(() => (init_schedule_cli(), exports_schedule_cli));
27202
+ const { LoginError: LoginError2 } = await Promise.resolve().then(() => (init_cli_login(), exports_cli_login));
27203
+ try {
27204
+ await runScheduleOn2(days, email);
27205
+ } catch (err) {
27206
+ if (err instanceof ScheduleCliError2 || err instanceof LoginError2)
27207
+ die(err.message);
27208
+ throw err;
27209
+ }
27210
+ process.exit(0);
27211
+ }
26028
27212
  const stray = args.find((a) => a !== "--help" && a !== "-h");
26029
27213
  if (stray) {
26030
- die(`\`audit\` takes no arguments yet (got: ${stray}).
26031
- ` + `Run \`failproofai audit\` to scan your history and open the dashboard.`);
27214
+ die(`\`audit\` does not take ${stray}.
27215
+ Run \`failproofai audit\` to scan your history and open the dashboard,
27216
+ or \`failproofai audit --help\` for the scheduling commands.`);
26032
27217
  }
26033
27218
  const attempt = acquireAuditLock("cli");
26034
27219
  if (!attempt.ok) {
26035
27220
  process.stderr.write(`Error: ${heldByLine(attempt.heldBy)}.
26036
- ` + `Two audits write the same cache files, so this one won't start. Try again shortly.
27221
+ Two audits write the same cache files, so this one won't start. Try again shortly.
26037
27222
  `);
26038
27223
  process.exit(EXIT_AUDIT_ALREADY_RUNNING);
26039
27224
  }
@@ -26057,7 +27242,7 @@ async function runAuditCli(args) {
26057
27242
  if (result.eventsScanned === 0) {
26058
27243
  process.stdout.write(`
26059
27244
  ${c(DIM, "no agent sessions found yet.")}
26060
- ` + ` install hooks with ${c(CYAN, "failproofai policies --install")} ` + `${c(DIM, "and come back after using your agent.")}
27245
+ install hooks with ${c(CYAN, "failproofai policies --install")} ${c(DIM, "and come back after using your agent.")}
26061
27246
 
26062
27247
  `);
26063
27248
  process.exit(0);
@@ -26072,8 +27257,8 @@ async function runAuditCli(args) {
26072
27257
  const url = `http://localhost:${DASHBOARD_PORT}/audit`;
26073
27258
  process.stdout.write(`
26074
27259
  ${c(DIM, "starting the dashboard…")}
26075
- ` + ` ${c(PINK, "✦")} ${c(BOLD, "here's your audit")} ${c(DIM, "→")} ${c(CYAN, url)}
26076
- ` + ` ${c(DIM, "(opening in your browser — press Ctrl+C to stop the server)")}
27260
+ ${c(PINK, "✦")} ${c(BOLD, "here's your audit")} ${c(DIM, "→")} ${c(CYAN, url)}
27261
+ ${c(DIM, "(opening in your browser — press Ctrl+C to stop the server)")}
26077
27262
 
26078
27263
  `);
26079
27264
  openWhenReady(DASHBOARD_PORT, "/audit");
@@ -26089,6 +27274,7 @@ var init_cli = __esm(() => {
26089
27274
  init_telemetry_id2();
26090
27275
  init_telemetry_sanitize();
26091
27276
  init_open_browser();
27277
+ init_report_harm();
26092
27278
  init_tui();
26093
27279
  AUDIT_STAGES = [
26094
27280
  { label: "discovering transcripts", detail: "walking ~/.claude, ~/.codex, ~/.cursor, …" },
@@ -26110,14 +27296,34 @@ USAGE
26110
27296
  server. This is what a scheduled audit runs; exit
26111
27297
  75 means another audit already had the lock.
26112
27298
 
27299
+ SCHEDULING
27300
+ failproofai audit --schedule [days] [--email you@yourdomain.com]
27301
+ Scan on a timer in the background (default 7 days,
27302
+ 1-90), and email you when a scan finds something
27303
+ harmful. Signs you in the first time — the report
27304
+ has to go somewhere. Pass --email to answer that
27305
+ up front and go straight to entering the code.
27306
+ failproofai audit --no-schedule
27307
+ Stop scanning on a timer. Leaves you signed in.
27308
+ failproofai audit --status
27309
+ What this machine is doing: whether scheduling is
27310
+ on, where reports go, the daemon's state, and when
27311
+ the next scan is due.
27312
+
27313
+ These write the same ~/.failproofai/config.json the dashboard's settings page
27314
+ writes, through the same function — so the two are always in step.
27315
+
26113
27316
  WHAT IT DOES
26114
27317
  1. Scans past sessions from every installed agent CLI (Claude, Codex, Cursor,
26115
27318
  Copilot, OpenCode, Pi) — entirely on your machine.
26116
27319
  2. Starts the local dashboard and opens
26117
27320
  http://localhost:${DASHBOARD_PORT}/audit with your results.
26118
27321
 
26119
- Runs fully offline — no account or network required. Press Ctrl+C to stop the
26120
- dashboard server when you're done.
27322
+ A bare "failproofai audit" needs no account, and nothing from your sessions
27323
+ leaves this machine — anonymous usage counts still apply unless you set
27324
+ FAILPROOFAI_TELEMETRY_DISABLED=1. Scheduling is the exception: it emails you
27325
+ what it finds, so it needs an address.
27326
+ Press Ctrl+C to stop the dashboard server when you're done.
26121
27327
  `.trimStart();
26122
27328
  RESET = ANSI_RESET;
26123
27329
  DIM = ANSI_DIM;
@@ -26147,16 +27353,16 @@ __export(exports_configure_wizard, {
26147
27353
  buildCompletionSummary: () => buildCompletionSummary,
26148
27354
  buildAgentChoices: () => buildAgentChoices
26149
27355
  });
26150
- import { existsSync as existsSync33, mkdirSync as mkdirSync21, writeFileSync as writeFileSync19, readFileSync as readFileSync27 } from "node:fs";
26151
- import { homedir as homedir26 } from "node:os";
26152
- import { dirname as dirname18, resolve as resolve25, sep as sep5 } from "node:path";
27356
+ import { existsSync as existsSync36, mkdirSync as mkdirSync21, writeFileSync as writeFileSync19, readFileSync as readFileSync31 } from "node:fs";
27357
+ import { homedir as homedir27 } from "node:os";
27358
+ import { dirname as dirname18, resolve as resolve26, sep as sep5 } from "node:path";
26153
27359
  async function emit(event, props) {
26154
27360
  try {
26155
27361
  await trackHookEvent2(getInstanceId2(), event, props);
26156
27362
  } catch {}
26157
27363
  }
26158
27364
  function homeify2(p) {
26159
- const home = homedir26();
27365
+ const home = homedir27();
26160
27366
  if (p === home)
26161
27367
  return "~";
26162
27368
  if (p.startsWith(home + sep5))
@@ -26280,8 +27486,8 @@ function setCustomPoliciesEnabled(scope, cwd, enabled) {
26280
27486
  const path3 = getConfigPathForScope(scope, cwd);
26281
27487
  let config = {};
26282
27488
  try {
26283
- if (existsSync33(path3))
26284
- config = JSON.parse(readFileSync27(path3, "utf8"));
27489
+ if (existsSync36(path3))
27490
+ config = JSON.parse(readFileSync31(path3, "utf8"));
26285
27491
  } catch {
26286
27492
  return;
26287
27493
  }
@@ -26321,7 +27527,7 @@ function describeCustomPolicies(cwd) {
26321
27527
  const scopes = [];
26322
27528
  let fileCount = 0;
26323
27529
  const dirs = [
26324
- { dir: resolve25(cwd, ".failproofai", "policies"), label: "project" },
27530
+ { dir: resolve26(cwd, ".failproofai", "policies"), label: "project" },
26325
27531
  { dir: customPoliciesDir(), label: "global" }
26326
27532
  ];
26327
27533
  for (const { dir, label } of dirs) {
@@ -26332,7 +27538,7 @@ function describeCustomPolicies(cwd) {
26332
27538
  fileCount += found.length;
26333
27539
  }
26334
27540
  for (const name of findSkippedPolicyFiles(dir)) {
26335
- warnings.push(`! ${homeify2(resolve25(dir, name))} is NOT loaded — rename to ` + `${name.replace(/\.(js|mjs|ts)$/, "-policies.$1")}`);
27541
+ warnings.push(`! ${homeify2(resolve26(dir, name))} is NOT loaded — rename to ` + `${name.replace(/\.(js|mjs|ts)$/, "-policies.$1")}`);
26336
27542
  }
26337
27543
  }
26338
27544
  return { active, warnings, fileCount, scopes };
@@ -26438,7 +27644,7 @@ function firstRunMarkerPath() {
26438
27644
  return launcherMarker();
26439
27645
  }
26440
27646
  function hasSeenLauncher() {
26441
- return existsSync33(firstRunMarkerPath());
27647
+ return existsSync36(firstRunMarkerPath());
26442
27648
  }
26443
27649
  function markLauncherSeen() {
26444
27650
  try {
@@ -26740,7 +27946,7 @@ refreshed. Re-run \`failproofai config\` once you can use sudo.
26740
27946
  let url = null;
26741
27947
  let token = null;
26742
27948
  let machineId = resolveMachineId();
26743
- let machineLabel = existing?.machineLabel ?? resolveMachineLabel();
27949
+ let machineLabel2 = existing?.machineLabel ?? resolveMachineLabel();
26744
27950
  if (existing) {
26745
27951
  const reuse = await selectOne({
26746
27952
  message: `Use this machine's existing connection to ${existing.url}?`,
@@ -26761,7 +27967,7 @@ refreshed. Re-run \`failproofai config\` once you can use sudo.
26761
27967
  url = existing.url;
26762
27968
  token = existing.token;
26763
27969
  machineId = existing.machineId;
26764
- machineLabel = existing.machineLabel ?? machineLabel;
27970
+ machineLabel2 = existing.machineLabel ?? machineLabel2;
26765
27971
  }
26766
27972
  }
26767
27973
  if (url === null) {
@@ -26815,13 +28021,13 @@ That did not work: ${probe.reason}
26815
28021
  if (retry === "skip") {
26816
28022
  stdout.write("Staying local. Connect later with `failproofai config --connect`.\n\n");
26817
28023
  } else {
26818
- connect = { url, token, machineId, machineLabel };
28024
+ connect = { url, token, machineId, machineLabel: machineLabel2 };
26819
28025
  }
26820
28026
  } else {
26821
28027
  stdout.write(`looks good.
26822
28028
 
26823
28029
  `);
26824
- connect = { url, token, machineId, machineLabel };
28030
+ connect = { url, token, machineId, machineLabel: machineLabel2 };
26825
28031
  }
26826
28032
  }
26827
28033
  }
@@ -27024,17 +28230,17 @@ __export(exports_flush_cli2, {
27024
28230
  flushRequestPath: () => flushRequestPath2,
27025
28231
  DEFAULT_FLUSH_TIMEOUT_SECS: () => DEFAULT_FLUSH_TIMEOUT_SECS2
27026
28232
  });
27027
- import { existsSync as existsSync34, mkdirSync as mkdirSync22, writeFileSync as writeFileSync20, readdirSync as readdirSync18 } from "node:fs";
27028
- import { dirname as dirname19, join as join32 } from "node:path";
28233
+ import { existsSync as existsSync37, mkdirSync as mkdirSync22, writeFileSync as writeFileSync20, readdirSync as readdirSync19 } from "node:fs";
28234
+ import { dirname as dirname19, join as join34 } from "node:path";
27029
28235
  function flushRequestPath2(home) {
27030
- return join32(failproofaiHome(home), "state", "flush-request.json");
28236
+ return join34(failproofaiHome(home), "state", "flush-request.json");
27031
28237
  }
27032
28238
  function spoolDirs2(home) {
27033
28239
  const root = spoolDir(home);
27034
- if (!existsSync34(root))
28240
+ if (!existsSync37(root))
27035
28241
  return [];
27036
28242
  try {
27037
- return readdirSync18(root, { withFileTypes: true }).filter((e) => e.isDirectory() && e.name !== "failed").map((e) => join32(root, e.name));
28243
+ return readdirSync19(root, { withFileTypes: true }).filter((e) => e.isDirectory() && e.name !== "failed").map((e) => join34(root, e.name));
27038
28244
  } catch {
27039
28245
  return [];
27040
28246
  }
@@ -27043,7 +28249,7 @@ function pendingBatches2(home) {
27043
28249
  let n = 0;
27044
28250
  for (const dir of spoolDirs2(home)) {
27045
28251
  try {
27046
- n += readdirSync18(dir).filter((f) => f.endsWith(".jsonl")).length;
28252
+ n += readdirSync19(dir).filter((f) => f.endsWith(".jsonl")).length;
27047
28253
  } catch {}
27048
28254
  }
27049
28255
  return n;
@@ -27138,16 +28344,16 @@ __export(exports_backfill_cli, {
27138
28344
  backfillRequestPath: () => backfillRequestPath,
27139
28345
  DEFAULT_BACKFILL_DAYS: () => DEFAULT_BACKFILL_DAYS
27140
28346
  });
27141
- import { existsSync as existsSync35, mkdirSync as mkdirSync23, writeFileSync as writeFileSync21, readdirSync as readdirSync19, statSync as statSync24 } from "node:fs";
27142
- import { dirname as dirname20, join as join33 } from "node:path";
28347
+ import { existsSync as existsSync38, mkdirSync as mkdirSync23, writeFileSync as writeFileSync21, readdirSync as readdirSync20, statSync as statSync24 } from "node:fs";
28348
+ import { dirname as dirname20, join as join35 } from "node:path";
27143
28349
  function backfillRequestPath(home) {
27144
- return join33(failproofaiHome(home), "state", "backfill-request.json");
28350
+ return join35(failproofaiHome(home), "state", "backfill-request.json");
27145
28351
  }
27146
28352
  function surveySessions(sinceMs, homeDir) {
27147
28353
  const out = [];
27148
28354
  for (const { cli, dir } of SESSION_DIRS) {
27149
- const root = join33(homeDir, dir);
27150
- if (!existsSync35(root))
28355
+ const root = join35(homeDir, dir);
28356
+ if (!existsSync38(root))
27151
28357
  continue;
27152
28358
  let files = 0;
27153
28359
  let newest = 0;
@@ -27156,12 +28362,12 @@ function surveySessions(sinceMs, homeDir) {
27156
28362
  return;
27157
28363
  let entries;
27158
28364
  try {
27159
- entries = readdirSync19(d, { withFileTypes: true });
28365
+ entries = readdirSync20(d, { withFileTypes: true });
27160
28366
  } catch {
27161
28367
  return;
27162
28368
  }
27163
28369
  for (const e of entries) {
27164
- const p = join33(d, e.name);
28370
+ const p = join35(d, e.name);
27165
28371
  if (e.isDirectory()) {
27166
28372
  walk(p, depth + 1);
27167
28373
  continue;
@@ -27185,7 +28391,7 @@ function runBackfillCommand(opts = {}) {
27185
28391
  const now = opts.now ?? Date.now();
27186
28392
  const sinceMs = opts.sinceMs ?? now - DEFAULT_BACKFILL_DAYS * 24 * 60 * 60 * 1000;
27187
28393
  const home = failproofaiHome();
27188
- if (!existsSync35(home)) {
28394
+ if (!existsSync38(home)) {
27189
28395
  return {
27190
28396
  exitCode: 1,
27191
28397
  lines: [`No failproofai home at ${home}. Run \`failproofai config\` first.`]
@@ -27291,8 +28497,8 @@ __export(exports_harness_cli, {
27291
28497
  addPath: () => addPath,
27292
28498
  HARNESS_KEYS: () => HARNESS_KEYS
27293
28499
  });
27294
- import { homedir as homedir27 } from "node:os";
27295
- import { resolve as resolve26 } from "node:path";
28500
+ import { homedir as homedir28 } from "node:os";
28501
+ import { resolve as resolve27 } from "node:path";
27296
28502
  function unknownHarness(name) {
27297
28503
  return fail([
27298
28504
  `Unknown harness: ${name}`,
@@ -27335,8 +28541,8 @@ function comparableLabel(raw) {
27335
28541
  return raw.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
27336
28542
  }
27337
28543
  function comparablePath(raw) {
27338
- const home = homedir27();
27339
- const expanded = raw === "~" ? home : raw.startsWith("~/") ? resolve26(home, raw.slice(2)) : raw;
28544
+ const home = homedir28();
28545
+ const expanded = raw === "~" ? home : raw.startsWith("~/") ? resolve27(home, raw.slice(2)) : raw;
27340
28546
  return expanded.replace(/\/+$/, "");
27341
28547
  }
27342
28548
  function effectiveLabel(entry) {
@@ -27523,7 +28729,7 @@ __export(exports_fp_config, {
27523
28729
  DEFAULT_CONFIG: () => DEFAULT_CONFIG2,
27524
28730
  DEFAULT_AUDIT_INTERVAL_DAYS: () => DEFAULT_AUDIT_INTERVAL_DAYS2
27525
28731
  });
27526
- import { chmodSync as chmodSync5, existsSync as existsSync36, mkdirSync as mkdirSync24, readFileSync as readFileSync28, statSync as statSync25, writeFileSync as writeFileSync22 } from "node:fs";
28732
+ import { chmodSync as chmodSync6, existsSync as existsSync39, mkdirSync as mkdirSync24, readFileSync as readFileSync32, statSync as statSync25, writeFileSync as writeFileSync22 } from "node:fs";
27527
28733
  import { dirname as dirname21 } from "node:path";
27528
28734
  function detectLayout2() {
27529
28735
  const raw = readVersionFile2();
@@ -27532,11 +28738,18 @@ function detectLayout2() {
27532
28738
  return { kind: "current", version: raw };
27533
28739
  return raw.layout > LAYOUT_VERSION ? { kind: "future", found: raw.layout } : { kind: "stale", found: raw.layout };
27534
28740
  }
27535
- if (existsSync36(configFile())) {
28741
+ if (existsSync39(configFile())) {
28742
+ const layoutThreePositions = [
28743
+ legacy.authJson(),
28744
+ legacy.nextAudit(),
28745
+ legacy.auditSchedule()
28746
+ ];
28747
+ if (layoutThreePositions.some((p) => existsSync39(p)))
28748
+ return { kind: "stale", found: 3 };
27536
28749
  return { kind: "current", version: { layout: LAYOUT_VERSION, cli: "" }, inferred: true };
27537
28750
  }
27538
- if (existsSync36(legacy.configToml()))
27539
- return { kind: "stale", found: LAYOUT_VERSION - 1 };
28751
+ if (existsSync39(legacy.configToml()))
28752
+ return { kind: "stale", found: 2 };
27540
28753
  const layoutOneMarkers = [
27541
28754
  legacy.policyConfig(),
27542
28755
  legacy.cacheDir(),
@@ -27546,7 +28759,7 @@ function detectLayout2() {
27546
28759
  legacy.ingestCredentials(),
27547
28760
  legacy.auditDashboard()
27548
28761
  ];
27549
- return layoutOneMarkers.some((p) => existsSync36(p)) ? { kind: "stale", found: 1 } : { kind: "absent" };
28762
+ return layoutOneMarkers.some((p) => existsSync39(p)) ? { kind: "stale", found: 1 } : { kind: "absent" };
27550
28763
  }
27551
28764
  function readLegacyTomlVersion2(text) {
27552
28765
  const layout = Number(/^\s*layout\s*=\s*(\d+)\s*$/m.exec(text)?.[1]);
@@ -27558,7 +28771,7 @@ function readLegacyTomlVersion2(text) {
27558
28771
  function readVersionFile2() {
27559
28772
  let text;
27560
28773
  try {
27561
- text = readFileSync28(versionFile(), "utf8");
28774
+ text = readFileSync32(versionFile(), "utf8");
27562
28775
  } catch {
27563
28776
  return null;
27564
28777
  }
@@ -27579,7 +28792,7 @@ function readVersionFile2() {
27579
28792
  function writeVersionFile2(v = {}) {
27580
28793
  const existing = readVersionFile2();
27581
28794
  const next = {
27582
- layout: LAYOUT_VERSION,
28795
+ layout: v.layout ?? LAYOUT_VERSION,
27583
28796
  cli: v.cli ?? version2,
27584
28797
  daemon: v.clearDaemon ? undefined : v.daemon ?? existing?.daemon
27585
28798
  };
@@ -27613,7 +28826,7 @@ function readSources2(raw) {
27613
28826
  function readConfigRaw2() {
27614
28827
  let raw = {};
27615
28828
  try {
27616
- const parsed = JSON.parse(readFileSync28(configFile(), "utf8"));
28829
+ const parsed = JSON.parse(readFileSync32(configFile(), "utf8"));
27617
28830
  if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
27618
28831
  raw = parsed;
27619
28832
  }
@@ -27622,7 +28835,7 @@ function readConfigRaw2() {
27622
28835
  }
27623
28836
  function readConfig2() {
27624
28837
  try {
27625
- const parsed = JSON.parse(readFileSync28(configFile(), "utf8"));
28838
+ const parsed = JSON.parse(readFileSync32(configFile(), "utf8"));
27626
28839
  return projectConfig2(parsed);
27627
28840
  } catch {
27628
28841
  return structuredClone(DEFAULT_CONFIG2);
@@ -27648,7 +28861,11 @@ function projectConfig2(parsed) {
27648
28861
  sources: readSources2(collector.sources)
27649
28862
  },
27650
28863
  telemetry: { enabled: telemetry.enabled !== false },
27651
- audit: { auto: audit.auto === true, intervalDays: readIntervalDays2(audit.interval_days) }
28864
+ audit: {
28865
+ auto: audit.auto === true,
28866
+ intervalDays: readIntervalDays2(audit.interval_days),
28867
+ reportsConsentedAt: typeof audit.reports_consented_at === "number" && Number.isFinite(audit.reports_consented_at) ? audit.reports_consented_at : undefined
28868
+ }
27652
28869
  };
27653
28870
  }
27654
28871
  }
@@ -27697,7 +28914,11 @@ function writeConfig2(config, raw) {
27697
28914
  } : {}
27698
28915
  },
27699
28916
  ...config.telemetry.enabled ? {} : { telemetry: { enabled: false } },
27700
- audit: { auto: config.audit.auto, interval_days: config.audit.intervalDays }
28917
+ audit: {
28918
+ auto: config.audit.auto,
28919
+ interval_days: config.audit.intervalDays,
28920
+ ...config.audit.reportsConsentedAt === undefined ? {} : { reports_consented_at: config.audit.reportsConsentedAt }
28921
+ }
27701
28922
  };
27702
28923
  const merged = structuredClone(raw ?? readConfigRaw2().raw);
27703
28924
  for (const path3 of OWNED_CONFIG_KEYS2)
@@ -27721,7 +28942,7 @@ function updateConfig2(patch) {
27721
28942
  function readCredentialsRaw2() {
27722
28943
  let raw = {};
27723
28944
  try {
27724
- const parsed = JSON.parse(readFileSync28(credentialsFile(), "utf8"));
28945
+ const parsed = JSON.parse(readFileSync32(credentialsFile(), "utf8"));
27725
28946
  if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
27726
28947
  raw = parsed;
27727
28948
  }
@@ -27730,7 +28951,7 @@ function readCredentialsRaw2() {
27730
28951
  }
27731
28952
  function readCredentials2() {
27732
28953
  try {
27733
- return projectCredentials2(JSON.parse(readFileSync28(credentialsFile(), "utf8")));
28954
+ return projectCredentials2(JSON.parse(readFileSync32(credentialsFile(), "utf8")));
27734
28955
  } catch {
27735
28956
  return {};
27736
28957
  }
@@ -27742,8 +28963,8 @@ function projectCredentials2(parsed) {
27742
28963
  const auth = parsed.auth;
27743
28964
  const out = {};
27744
28965
  if (cloud && typeof cloud.url === "string" && typeof cloud.machine_id === "string" && typeof cloud.token === "string" && cloud.url && cloud.token) {
27745
- const machineLabel = typeof cloud.machine_label === "string" && cloud.machine_label ? cloud.machine_label : undefined;
27746
- out.cloud = { url: cloud.url, machineId: cloud.machine_id, token: cloud.token, machineLabel };
28966
+ const machineLabel2 = typeof cloud.machine_label === "string" && cloud.machine_label ? cloud.machine_label : undefined;
28967
+ out.cloud = { url: cloud.url, machineId: cloud.machine_id, token: cloud.token, machineLabel: machineLabel2 };
27747
28968
  }
27748
28969
  const org = parsed.org;
27749
28970
  if (org) {
@@ -27802,12 +29023,12 @@ function writeCredentials2(creds, raw) {
27802
29023
  mkdirSync24(home, { recursive: true });
27803
29024
  try {
27804
29025
  if (statSync25(home).mode & 63)
27805
- chmodSync5(home, 448);
29026
+ chmodSync6(home, 448);
27806
29027
  } catch {}
27807
29028
  writeFileSync22(credentialsFile(), `${JSON.stringify(merged, null, 2)}
27808
29029
  `, { mode: 384 });
27809
29030
  try {
27810
- chmodSync5(credentialsFile(), 384);
29031
+ chmodSync6(credentialsFile(), 384);
27811
29032
  } catch {}
27812
29033
  }
27813
29034
  function hasCloudCredentials() {
@@ -27847,7 +29068,8 @@ var init_fp_config2 = __esm(() => {
27847
29068
  ["collector", "sources", "*", "extra_paths"],
27848
29069
  ["telemetry", "enabled"],
27849
29070
  ["audit", "auto"],
27850
- ["audit", "interval_days"]
29071
+ ["audit", "interval_days"],
29072
+ ["audit", "reports_consented_at"]
27851
29073
  ];
27852
29074
  OWNED_CREDENTIAL_KEYS2 = [
27853
29075
  ["cloud", "url"],
@@ -27906,7 +29128,9 @@ __export(exports_fp_home, {
27906
29128
  codexSessionPathsFile: () => codexSessionPathsFile2,
27907
29129
  cloudPoliciesDir: () => cloudPoliciesDir2,
27908
29130
  binDir: () => binDir2,
29131
+ auditSessionFile: () => auditSessionFile2,
27909
29132
  auditScheduleFile: () => auditScheduleFile2,
29133
+ auditMachineFile: () => auditMachineFile2,
27910
29134
  auditLockFile: () => auditLockFile2,
27911
29135
  auditDir: () => auditDir2,
27912
29136
  auditDashboardFile: () => auditDashboardFile2,
@@ -27914,12 +29138,12 @@ __export(exports_fp_home, {
27914
29138
  LAYOUT_VERSION: () => LAYOUT_VERSION2,
27915
29139
  HOME_CLASSES: () => HOME_CLASSES2
27916
29140
  });
27917
- import { homedir as homedir28 } from "node:os";
27918
- import { resolve as resolve27 } from "node:path";
29141
+ import { homedir as homedir29 } from "node:os";
29142
+ import { resolve as resolve28 } from "node:path";
27919
29143
  function failproofaiHome2(home) {
27920
29144
  if (home)
27921
- return resolve27(home, ".failproofai");
27922
- return process.env.FAILPROOFAI_HOME || resolve27(homedir28(), ".failproofai");
29145
+ return resolve28(home, ".failproofai");
29146
+ return process.env.FAILPROOFAI_HOME || resolve28(homedir29(), ".failproofai");
27923
29147
  }
27924
29148
  function resettablePaths2() {
27925
29149
  return [
@@ -27936,6 +29160,7 @@ function retiredLayoutPaths2() {
27936
29160
  legacy2.lastVersion(),
27937
29161
  legacy2.auditDashboard(),
27938
29162
  legacy2.auditCacheDir(),
29163
+ legacy2.auditReminder(),
27939
29164
  legacy2.codexSessionPaths(),
27940
29165
  legacy2.spoolDir(),
27941
29166
  legacy2.failedDir(),
@@ -27947,7 +29172,7 @@ function retiredLayoutPaths2() {
27947
29172
  legacy2.localPoliciesDir()
27948
29173
  ];
27949
29174
  }
27950
- var LAYOUT_VERSION2 = 3, at2 = (...parts) => resolve27(failproofaiHome2(), ...parts), atHome2 = (home, ...parts) => home ? resolve27(failproofaiHome2(home), ...parts) : at2(...parts), versionFile2 = (home) => atHome2(home, "VERSION"), configFile2 = (home) => atHome2(home, "config.json"), credentialsFile2 = (home) => atHome2(home, "credentials.json"), binDir2 = (home) => atHome2(home, "bin"), daemonBinary = (version3, home) => resolve27(binDir2(home), `failproofaid-${version3}`), policiesDir2 = (home) => atHome2(home, "policies"), customPoliciesDir2, globalPolicyConfigFile2 = (home) => atHome2(home, "policies-config.json"), cloudPoliciesDir2 = (home) => resolve27(policiesDir2(home), "cloud-policies"), cursorsDir2 = (source, home) => source ? resolve27(atHome2(home, "cursors"), source) : atHome2(home, "cursors"), customAgentsDir2 = (home) => atHome2(home, "custom-agents"), customAgentsEventsDir = (home) => resolve27(customAgentsDir2(home), "events"), customAgentsFailedDir = (home) => resolve27(customAgentsDir2(home), "failed"), auditDir2 = (home) => atHome2(home, "audit"), auditDashboardFile2 = (home) => resolve27(auditDir2(home), "dashboard.json"), auditCacheDir2 = (home) => resolve27(auditDir2(home), "cache"), hookActivityDir2 = (home) => atHome2(home, "hook-activity"), runDir2 = (home) => atHome2(home, "run"), daemonSocket2 = () => process.env.FAILPROOFAI_DAEMON_SOCKET || resolve27(runDir2(), "failproofaid.sock"), workerSocket = (home) => resolve27(runDir2(home), "worker.sock"), daemonLock = (home) => resolve27(runDir2(home), "failproofaid.lock"), auditLockFile2 = (home) => resolve27(runDir2(home), "audit.lock"), stateDir2 = (home) => atHome2(home, "state"), shimsDir2 = (home) => resolve27(stateDir2(home), "shims"), spoolDir2 = (home) => resolve27(stateDir2(home), "spool"), failedDir2 = (home) => resolve27(stateDir2(home), "failed"), collectorHealthFile2 = (home) => resolve27(stateDir2(home), "collector-health.json"), sessionPauseDir2 = () => resolve27(stateDir2(), "sessions"), auditScheduleFile2 = (home) => resolve27(stateDir2(home), "audit-schedule.json"), telemetryIdFile2 = (home) => resolve27(stateDir2(home), "telemetry-id"), launcherMarker2 = (home) => resolve27(stateDir2(home), "launcher-configured"), onboardingAttemptFile2 = (home) => resolve27(stateDir2(home), "onboarding-attempt.json"), lastVersionFile2 = (home) => resolve27(stateDir2(home), "last-version"), onboardingLockFile2 = (home) => resolve27(stateDir2(home), "onboarding.lock"), codexSessionPathsFile2 = (home) => resolve27(stateDir2(home), "codex-session-paths.json"), logsDir2 = (home) => atHome2(home, "logs"), migrationsDir2 = (home) => atHome2(home, "migrations"), migrationLedgerFile2 = (home) => resolve27(migrationsDir2(home), "applied.json"), migrationBackupDir2 = (layout, home) => resolve27(migrationsDir2(home), `backup-layout${layout}`), HOME_CLASSES2, legacy2;
29175
+ var LAYOUT_VERSION2 = 4, at2 = (...parts) => resolve28(failproofaiHome2(), ...parts), atHome2 = (home, ...parts) => home ? resolve28(failproofaiHome2(home), ...parts) : at2(...parts), versionFile2 = (home) => atHome2(home, "VERSION"), configFile2 = (home) => atHome2(home, "config.json"), credentialsFile2 = (home) => atHome2(home, "credentials.json"), binDir2 = (home) => atHome2(home, "bin"), daemonBinary = (version3, home) => resolve28(binDir2(home), `failproofaid-${version3}`), policiesDir2 = (home) => atHome2(home, "policies"), customPoliciesDir2, globalPolicyConfigFile2 = (home) => atHome2(home, "policies-config.json"), cloudPoliciesDir2 = (home) => resolve28(policiesDir2(home), "cloud-policies"), cursorsDir2 = (source, home) => source ? resolve28(atHome2(home, "cursors"), source) : atHome2(home, "cursors"), customAgentsDir2 = (home) => atHome2(home, "custom-agents"), customAgentsEventsDir = (home) => resolve28(customAgentsDir2(home), "events"), customAgentsFailedDir = (home) => resolve28(customAgentsDir2(home), "failed"), auditDir2 = (home) => atHome2(home, "audit"), auditDashboardFile2 = (home) => resolve28(auditDir2(home), "dashboard.json"), auditCacheDir2 = (home) => resolve28(auditDir2(home), "cache"), auditSessionFile2 = (home) => resolve28(auditDir2(home), "session.json"), auditMachineFile2 = (home) => resolve28(auditDir2(home), "machine.json"), hookActivityDir2 = (home) => atHome2(home, "hook-activity"), runDir2 = (home) => atHome2(home, "run"), daemonSocket2 = () => process.env.FAILPROOFAI_DAEMON_SOCKET || resolve28(runDir2(), "failproofaid.sock"), workerSocket = (home) => resolve28(runDir2(home), "worker.sock"), daemonLock = (home) => resolve28(runDir2(home), "failproofaid.lock"), auditLockFile2 = (home) => resolve28(runDir2(home), "audit.lock"), stateDir2 = (home) => atHome2(home, "state"), shimsDir2 = (home) => resolve28(stateDir2(home), "shims"), spoolDir2 = (home) => resolve28(stateDir2(home), "spool"), failedDir2 = (home) => resolve28(stateDir2(home), "failed"), collectorHealthFile2 = (home) => resolve28(stateDir2(home), "collector-health.json"), sessionPauseDir2 = () => resolve28(stateDir2(), "sessions"), auditScheduleFile2 = (home) => resolve28(auditDir2(home), "schedule.json"), telemetryIdFile2 = (home) => resolve28(stateDir2(home), "telemetry-id"), launcherMarker2 = (home) => resolve28(stateDir2(home), "launcher-configured"), onboardingAttemptFile2 = (home) => resolve28(stateDir2(home), "onboarding-attempt.json"), lastVersionFile2 = (home) => resolve28(stateDir2(home), "last-version"), onboardingLockFile2 = (home) => resolve28(stateDir2(home), "onboarding.lock"), codexSessionPathsFile2 = (home) => resolve28(stateDir2(home), "codex-session-paths.json"), logsDir2 = (home) => atHome2(home, "logs"), migrationsDir2 = (home) => atHome2(home, "migrations"), migrationLedgerFile2 = (home) => resolve28(migrationsDir2(home), "applied.json"), migrationBackupDir2 = (layout, home) => resolve28(migrationsDir2(home), `backup-layout${layout}`), HOME_CLASSES2, legacy2;
27951
29176
  var init_fp_home2 = __esm(() => {
27952
29177
  customPoliciesDir2 = policiesDir2;
27953
29178
  HOME_CLASSES2 = [
@@ -27955,20 +29180,23 @@ var init_fp_home2 = __esm(() => {
27955
29180
  { path: configFile2, class: "user-typed" },
27956
29181
  { path: globalPolicyConfigFile2, class: "user-typed" },
27957
29182
  { path: policiesDir2, class: "user-typed" },
29183
+ { path: auditSessionFile2, class: "user-typed" },
27958
29184
  { path: spoolDir2, class: "undelivered" },
27959
29185
  { path: failedDir2, class: "undelivered" },
27960
29186
  { path: customAgentsDir2, class: "undelivered" },
27961
29187
  { path: hookActivityDir2, class: "undelivered" },
27962
- { path: (home) => resolve27(stateDir2(home), "flush-request.json"), class: "undelivered" },
27963
- { path: (home) => resolve27(stateDir2(home), "backfill-request.json"), class: "undelivered" },
29188
+ { path: (home) => resolve28(stateDir2(home), "flush-request.json"), class: "undelivered" },
29189
+ { path: (home) => resolve28(stateDir2(home), "backfill-request.json"), class: "undelivered" },
27964
29190
  { path: cursorsDir2, class: "identity" },
27965
29191
  { path: telemetryIdFile2, class: "identity" },
27966
- { path: (home) => resolve27(stateDir2(home), "daemon-telemetry-id"), class: "identity" },
29192
+ { path: (home) => resolve28(stateDir2(home), "daemon-telemetry-id"), class: "identity" },
27967
29193
  { path: versionFile2, class: "identity" },
27968
29194
  { path: migrationsDir2, class: "identity" },
27969
- { path: auditDir2, class: "derived" },
27970
- { path: collectorHealthFile2, class: "derived" },
29195
+ { path: auditMachineFile2, class: "identity" },
29196
+ { path: auditDashboardFile2, class: "derived" },
29197
+ { path: auditCacheDir2, class: "derived" },
27971
29198
  { path: auditScheduleFile2, class: "derived" },
29199
+ { path: collectorHealthFile2, class: "derived" },
27972
29200
  { path: codexSessionPathsFile2, class: "derived" },
27973
29201
  { path: shimsDir2, class: "derived" },
27974
29202
  { path: sessionPauseDir2, class: "derived" },
@@ -27994,6 +29222,10 @@ var init_fp_home2 = __esm(() => {
27994
29222
  launcherMarker: () => at2(".launcher-configured"),
27995
29223
  lastVersion: () => at2("last-version"),
27996
29224
  auditDashboard: () => at2("audit-dashboard.json"),
29225
+ authJson: () => at2("auth.json"),
29226
+ nextAudit: () => at2("next-audit.json"),
29227
+ auditReminder: () => at2("audit", "reminder.json"),
29228
+ auditSchedule: () => at2("state", "audit-schedule.json"),
27997
29229
  cacheDir: () => at2("cache"),
27998
29230
  hookActivityDir: () => at2("cache", "hook-activity"),
27999
29231
  auditCacheDir: () => at2("cache", "audit"),
@@ -28013,26 +29245,83 @@ __export(exports_migrations2, {
28013
29245
  runMigrations: () => runMigrations2,
28014
29246
  restoreBackup: () => restoreBackup2,
28015
29247
  readLedger: () => readLedger2,
29248
+ pruneMigratedCredentials: () => pruneMigratedCredentials2,
28016
29249
  planMigration: () => planMigration2,
28017
29250
  migrationCoverageGap: () => migrationCoverageGap2,
28018
29251
  describePlan: () => describePlan2,
28019
29252
  backupBeforeMigrating: () => backupBeforeMigrating2,
28020
29253
  MIGRATIONS: () => MIGRATIONS2
28021
29254
  });
28022
- import { copyFileSync as copyFileSync4, existsSync as existsSync37, mkdirSync as mkdirSync25, readFileSync as readFileSync29, rmSync as rmSync12, writeFileSync as writeFileSync23 } from "node:fs";
28023
- import { basename as basename7, dirname as dirname22, resolve as resolve28 } from "node:path";
29255
+ import {
29256
+ chmodSync as chmodSync7,
29257
+ copyFileSync as copyFileSync4,
29258
+ existsSync as existsSync40,
29259
+ mkdirSync as mkdirSync25,
29260
+ readFileSync as readFileSync33,
29261
+ renameSync as renameSync8,
29262
+ rmSync as rmSync14,
29263
+ writeFileSync as writeFileSync23
29264
+ } from "node:fs";
29265
+ import { basename as basename7, dirname as dirname22, join as join36, resolve as resolve29 } from "node:path";
29266
+ function migrateToLayout42() {
29267
+ const moves = [
29268
+ { from: legacy.authJson(), to: auditSessionFile() },
29269
+ { from: legacy.nextAudit(), to: legacy.auditReminder() },
29270
+ { from: legacy.auditSchedule(), to: auditScheduleFile() }
29271
+ ];
29272
+ const authDirOverride = process.env.FAILPROOFAI_AUTH_DIR;
29273
+ if (authDirOverride) {
29274
+ moves.push({ from: join36(authDirOverride, "auth.json"), to: join36(authDirOverride, "session.json") }, {
29275
+ from: join36(authDirOverride, "next-audit.json"),
29276
+ to: join36(authDirOverride, "reminder.json")
29277
+ });
29278
+ }
29279
+ const migrated = [];
29280
+ for (const { from, to } of moves) {
29281
+ if (!existsSync40(from))
29282
+ continue;
29283
+ if (existsSync40(to)) {
29284
+ rmSync14(from, { force: true });
29285
+ continue;
29286
+ }
29287
+ mkdirSync25(dirname22(to), { recursive: true });
29288
+ try {
29289
+ renameSync8(from, to);
29290
+ } catch {
29291
+ try {
29292
+ copyFileSync4(from, to);
29293
+ } catch (err) {
29294
+ try {
29295
+ rmSync14(to, { force: true });
29296
+ } catch {}
29297
+ throw err;
29298
+ }
29299
+ rmSync14(from, { force: true });
29300
+ }
29301
+ migrated.push(`${basename7(from)} → audit/${basename7(to)}`);
29302
+ }
29303
+ for (const secret of [auditSessionFile()]) {
29304
+ if (!existsSync40(secret))
29305
+ continue;
29306
+ try {
29307
+ chmodSync7(secret, 384);
29308
+ } catch {}
29309
+ }
29310
+ writeVersionFile({ layout: 4 });
29311
+ return { removed: [], migrated, activity: [], policyConfig: [], spooled: [], from: 3 };
29312
+ }
28024
29313
  function planMigration2(from, registry = MIGRATIONS2) {
28025
29314
  if (from >= LAYOUT_VERSION)
28026
29315
  return [];
28027
29316
  const chain = [];
28028
29317
  let at3 = from;
28029
29318
  while (at3 < LAYOUT_VERSION) {
28030
- const step = registry.find((m) => m.from === at3);
28031
- if (!step) {
29319
+ const step2 = registry.find((m) => m.from === at3);
29320
+ if (!step2) {
28032
29321
  throw new Error(`no migration from layout ${at3} to ${LAYOUT_VERSION} — this build cannot upgrade that home`);
28033
29322
  }
28034
- chain.push(step);
28035
- at3 = step.to;
29323
+ chain.push(step2);
29324
+ at3 = step2.to;
28036
29325
  }
28037
29326
  return chain;
28038
29327
  }
@@ -28058,7 +29347,7 @@ function migrationCoverageGap2(registry = MIGRATIONS2) {
28058
29347
  }
28059
29348
  function readLedger2() {
28060
29349
  try {
28061
- const parsed = JSON.parse(readFileSync29(migrationLedgerFile(), "utf8"));
29350
+ const parsed = JSON.parse(readFileSync33(migrationLedgerFile(), "utf8"));
28062
29351
  return Array.isArray(parsed) ? parsed : [];
28063
29352
  } catch {
28064
29353
  return [];
@@ -28075,11 +29364,28 @@ function appendLedger2(entry) {
28075
29364
  function backupNameOf2(f) {
28076
29365
  return f.as ?? basename7(f.at());
28077
29366
  }
29367
+ function pruneMigratedCredentials2(from) {
29368
+ const pruned = [];
29369
+ for (let layout = from;layout < LAYOUT_VERSION; layout++) {
29370
+ for (const { as, landsAt } of PRUNED_AFTER_SUCCESS2) {
29371
+ try {
29372
+ if (!existsSync40(landsAt()))
29373
+ continue;
29374
+ const copy = resolve29(migrationBackupDir(layout), as);
29375
+ if (!existsSync40(copy))
29376
+ continue;
29377
+ rmSync14(copy, { force: true });
29378
+ pruned.push(as);
29379
+ } catch {}
29380
+ }
29381
+ }
29382
+ return pruned;
29383
+ }
28078
29384
  function filesToBackUp2() {
28079
29385
  const seen = new Map;
28080
29386
  for (const f of [...BACKED_UP2, ...BACKED_UP_LEGACY2]) {
28081
29387
  const path3 = f.at();
28082
- if (existsSync37(path3))
29388
+ if (existsSync40(path3))
28083
29389
  seen.set(path3, backupNameOf2(f));
28084
29390
  }
28085
29391
  return [...seen].map(([path3, as]) => ({ path: path3, as }));
@@ -28088,14 +29394,14 @@ function backupBeforeMigrating2(from) {
28088
29394
  const dir = migrationBackupDir(from);
28089
29395
  const saved = [];
28090
29396
  try {
28091
- rmSync12(dir, { recursive: true, force: true });
29397
+ rmSync14(dir, { recursive: true, force: true });
28092
29398
  mkdirSync25(dir, { recursive: true });
28093
29399
  } catch {
28094
29400
  return [];
28095
29401
  }
28096
29402
  for (const { path: source, as } of filesToBackUp2()) {
28097
29403
  try {
28098
- copyFileSync4(source, resolve28(dir, as));
29404
+ copyFileSync4(source, resolve29(dir, as));
28099
29405
  saved.push(as);
28100
29406
  } catch {}
28101
29407
  }
@@ -28113,19 +29419,19 @@ function runMigrations2(from, chain = planMigration2(from)) {
28113
29419
  from
28114
29420
  };
28115
29421
  let failed;
28116
- for (const step of chain) {
29422
+ for (const step2 of chain) {
28117
29423
  const startedAt = Date.now();
28118
29424
  try {
28119
- const result = step.run();
29425
+ const result = step2.run();
28120
29426
  outcome.removed.push(...result.removed);
28121
29427
  outcome.migrated.push(...result.migrated);
28122
29428
  outcome.activity.push(...result.activity);
28123
29429
  outcome.policyConfig.push(...result.policyConfig);
28124
29430
  outcome.spooled.push(...result.spooled);
28125
- steps.push({ from: step.from, to: step.to, ok: true });
29431
+ steps.push({ from: step2.from, to: step2.to, ok: true });
28126
29432
  appendLedger2({
28127
- from: step.from,
28128
- to: step.to,
29433
+ from: step2.from,
29434
+ to: step2.to,
28129
29435
  cli: version2,
28130
29436
  at: new Date(startedAt).toISOString(),
28131
29437
  durationMs: Date.now() - startedAt,
@@ -28135,15 +29441,20 @@ function runMigrations2(from, chain = planMigration2(from)) {
28135
29441
  activity: result.activity.length
28136
29442
  });
28137
29443
  } catch (err) {
28138
- steps.push({ from: step.from, to: step.to, ok: false });
29444
+ steps.push({ from: step2.from, to: step2.to, ok: false });
29445
+ try {
29446
+ const marker = readVersionFile();
29447
+ if (marker && marker.layout >= LAYOUT_VERSION)
29448
+ writeVersionFile({ layout: step2.from });
29449
+ } catch {}
28139
29450
  failed = {
28140
- from: step.from,
28141
- to: step.to,
29451
+ from: step2.from,
29452
+ to: step2.to,
28142
29453
  error: err instanceof Error ? err.message : String(err)
28143
29454
  };
28144
29455
  appendLedger2({
28145
- from: step.from,
28146
- to: step.to,
29456
+ from: step2.from,
29457
+ to: step2.to,
28147
29458
  cli: version2,
28148
29459
  at: new Date(startedAt).toISOString(),
28149
29460
  durationMs: Date.now() - startedAt,
@@ -28152,6 +29463,8 @@ function runMigrations2(from, chain = planMigration2(from)) {
28152
29463
  break;
28153
29464
  }
28154
29465
  }
29466
+ if (!failed)
29467
+ pruneMigratedCredentials2(from);
28155
29468
  return { from, steps, backedUp, outcome, failed };
28156
29469
  }
28157
29470
  function describePlan2(from) {
@@ -28178,13 +29491,13 @@ function describePlan2(from) {
28178
29491
  }
28179
29492
  function restoreBackup2(layout) {
28180
29493
  const dir = migrationBackupDir(layout);
28181
- if (!existsSync37(dir))
29494
+ if (!existsSync40(dir))
28182
29495
  return [];
28183
29496
  const restored = [];
28184
29497
  for (const f of [...BACKED_UP2, ...BACKED_UP_LEGACY2]) {
28185
29498
  const target = f.at();
28186
- const source = resolve28(dir, backupNameOf2(f));
28187
- if (!existsSync37(source))
29499
+ const source = resolve29(dir, backupNameOf2(f));
29500
+ if (!existsSync40(source))
28188
29501
  continue;
28189
29502
  try {
28190
29503
  mkdirSync25(dirname22(target), { recursive: true });
@@ -28194,23 +29507,30 @@ function restoreBackup2(layout) {
28194
29507
  }
28195
29508
  return restored.sort((a, b) => a.localeCompare(b));
28196
29509
  }
28197
- var MIGRATIONS2, BACKED_UP2, BACKED_UP_LEGACY2;
29510
+ var MIGRATIONS2, BACKED_UP2, BACKED_UP_LEGACY2, PRUNED_AFTER_SUCCESS2;
28198
29511
  var init_migrations2 = __esm(() => {
28199
29512
  init_package();
28200
29513
  init_fp_home();
29514
+ init_fp_config();
28201
29515
  init_fp_reset();
28202
29516
  MIGRATIONS2 = [
28203
29517
  {
28204
29518
  from: 1,
28205
29519
  to: 3,
28206
29520
  describe: "layout 1 → 3: carry the decision log out of cache/, keep the policy config in place, drop the layout-1 credential files",
28207
- run: () => resetHome(1)
29521
+ run: () => resetHome(1, 3)
28208
29522
  },
28209
29523
  {
28210
29524
  from: 2,
28211
29525
  to: 3,
28212
29526
  describe: "layout 2 → 3: carry config.toml and credentials.toml into JSON, move custom-policies/ back up into policies/, nest the policy config at the root",
28213
- run: () => resetHome(2)
29527
+ run: () => resetHome(2, 3)
29528
+ },
29529
+ {
29530
+ from: 3,
29531
+ to: 4,
29532
+ describe: "layout 3 → 4: gather the audit's files under audit/ — auth.json becomes audit/session.json, next-audit.json becomes audit/reminder.json, state/audit-schedule.json becomes audit/schedule.json",
29533
+ run: migrateToLayout42
28214
29534
  }
28215
29535
  ];
28216
29536
  BACKED_UP2 = [
@@ -28225,7 +29545,13 @@ var init_migrations2 = __esm(() => {
28225
29545
  { at: legacy.policyConfig },
28226
29546
  { at: legacy.localPolicyConfig, as: "local-policies-policies-config.json" },
28227
29547
  { at: legacy.cloudCredentials },
28228
- { at: legacy.ingestCredentials }
29548
+ { at: legacy.ingestCredentials },
29549
+ { at: legacy.authJson },
29550
+ { at: legacy.nextAudit },
29551
+ { at: legacy.auditSchedule }
29552
+ ];
29553
+ PRUNED_AFTER_SUCCESS2 = [
29554
+ { as: basename7(legacy.authJson()), landsAt: auditSessionFile }
28229
29555
  ];
28230
29556
  });
28231
29557
 
@@ -28237,6 +29563,7 @@ __export(exports_daemon_service, {
28237
29563
  upgradedServiceDefinition: () => upgradedServiceDefinition2,
28238
29564
  uninstallDaemonService: () => uninstallDaemonService2,
28239
29565
  systemdUnitContents: () => systemdUnitContents2,
29566
+ startedAtFromMonotonic: () => startedAtFromMonotonic,
28240
29567
  setDaemonConfigured: () => setDaemonConfigured2,
28241
29568
  resolveWorkerCommand: () => resolveWorkerCommand2,
28242
29569
  resolveFailproofaidBinaryPath: () => resolveFailproofaidBinaryPath2,
@@ -28253,6 +29580,7 @@ __export(exports_daemon_service, {
28253
29580
  ensureDaemonServiceCurrent: () => ensureDaemonServiceCurrent2,
28254
29581
  daemonVersionSkew: () => daemonVersionSkew2,
28255
29582
  daemonStatusCommand: () => daemonStatusCommand2,
29583
+ daemonStartedAtMs: () => daemonStartedAtMs,
28256
29584
  daemonServiceStatus: () => daemonServiceStatus2,
28257
29585
  daemonServiceNeedsUpgrade: () => daemonServiceNeedsUpgrade2,
28258
29586
  daemonServiceFilePath: () => daemonServiceFilePath2,
@@ -28260,16 +29588,16 @@ __export(exports_daemon_service, {
28260
29588
  canElevate: () => canElevate2
28261
29589
  });
28262
29590
  import {
28263
- existsSync as existsSync38,
29591
+ existsSync as existsSync41,
28264
29592
  mkdirSync as mkdirSync26,
28265
29593
  mkdtempSync as mkdtempSync2,
28266
- readFileSync as readFileSync30,
29594
+ readFileSync as readFileSync34,
28267
29595
  writeFileSync as writeFileSync24,
28268
29596
  unlinkSync as unlinkSync5,
28269
- rmSync as rmSync13
29597
+ rmSync as rmSync15
28270
29598
  } from "node:fs";
28271
- import { homedir as homedir29, tmpdir as tmpdir3, userInfo as userInfo2 } from "node:os";
28272
- import { resolve as resolve29 } from "node:path";
29599
+ import { homedir as homedir30, tmpdir as tmpdir3, userInfo as userInfo2 } from "node:os";
29600
+ import { resolve as resolve30 } from "node:path";
28273
29601
  import { execFileSync as execFileSync5 } from "node:child_process";
28274
29602
  function setDaemonConfigured2(value, installedVersion) {
28275
29603
  try {
@@ -28291,13 +29619,13 @@ function resolveFailproofaidBinaryPath2() {
28291
29619
  if (process.env.FAILPROOFAI_DAEMON_BINARY)
28292
29620
  return process.env.FAILPROOFAI_DAEMON_BINARY;
28293
29621
  const downloaded = installedBinaryPath();
28294
- if (existsSync38(downloaded))
29622
+ if (existsSync41(downloaded))
28295
29623
  return downloaded;
28296
29624
  const packageRoot = process.env.FAILPROOFAI_PACKAGE_ROOT;
28297
29625
  if (packageRoot) {
28298
29626
  for (const profile of ["release", "debug"]) {
28299
- const candidate = resolve29(packageRoot, "target", profile, "failproofaid");
28300
- if (existsSync38(candidate))
29627
+ const candidate = resolve30(packageRoot, "target", profile, "failproofaid");
29628
+ if (existsSync41(candidate))
28301
29629
  return candidate;
28302
29630
  }
28303
29631
  }
@@ -28327,8 +29655,8 @@ function resolveWorkerCommand2() {
28327
29655
  const packageRoot = process.env.FAILPROOFAI_PACKAGE_ROOT;
28328
29656
  if (!packageRoot)
28329
29657
  return null;
28330
- const workerScript = resolve29(packageRoot, "dist", "worker.mjs");
28331
- if (!existsSync38(workerScript))
29658
+ const workerScript = resolve30(packageRoot, "dist", "worker.mjs");
29659
+ if (!existsSync41(workerScript))
28332
29660
  return null;
28333
29661
  return `${shellQuote2(process.execPath)} ${shellQuote2(workerScript)}`;
28334
29662
  }
@@ -28338,8 +29666,8 @@ function resolveCliCommand2() {
28338
29666
  const packageRoot = process.env.FAILPROOFAI_PACKAGE_ROOT;
28339
29667
  if (!packageRoot)
28340
29668
  return null;
28341
- const cliScript = resolve29(packageRoot, "dist", "cli.mjs");
28342
- if (!existsSync38(cliScript))
29669
+ const cliScript = resolve30(packageRoot, "dist", "cli.mjs");
29670
+ if (!existsSync41(cliScript))
28343
29671
  return null;
28344
29672
  return `${shellQuote2(process.execPath)} ${shellQuote2(cliScript)}`;
28345
29673
  }
@@ -28352,8 +29680,8 @@ function workerScriptPath2() {
28352
29680
  const packageRoot = process.env.FAILPROOFAI_PACKAGE_ROOT;
28353
29681
  if (!packageRoot)
28354
29682
  return null;
28355
- const workerScript = resolve29(packageRoot, "dist", "worker.mjs");
28356
- return existsSync38(workerScript) ? workerScript : null;
29683
+ const workerScript = resolve30(packageRoot, "dist", "worker.mjs");
29684
+ return existsSync41(workerScript) ? workerScript : null;
28357
29685
  }
28358
29686
  function assertUnitSafe2(value, field) {
28359
29687
  if (UNIT_UNSAFE_RE2.test(value)) {
@@ -28379,10 +29707,10 @@ function systemdUnitDir2() {
28379
29707
  return process.env.FAILPROOFAI_SYSTEMD_DIR || "/etc/systemd/system";
28380
29708
  }
28381
29709
  function systemdUnitPath2(user = serviceUser2()) {
28382
- return resolve29(systemdUnitDir2(), systemdUnitName2(user));
29710
+ return resolve30(systemdUnitDir2(), systemdUnitName2(user));
28383
29711
  }
28384
29712
  function legacySystemdUserUnitPath2() {
28385
- return resolve29(homedir29(), ".config", "systemd", "user", "failproofaid.service");
29713
+ return resolve30(homedir30(), ".config", "systemd", "user", "failproofaid.service");
28386
29714
  }
28387
29715
  function launchdLabel2(user = serviceUser2()) {
28388
29716
  return `ai.failproof.failproofaid.${user}`;
@@ -28391,7 +29719,7 @@ function launchdPlistPath2(user = serviceUser2()) {
28391
29719
  return `/Library/LaunchDaemons/${launchdLabel2(user)}.plist`;
28392
29720
  }
28393
29721
  function legacyLaunchAgentPlistPath2() {
28394
- return resolve29(homedir29(), "Library", "LaunchAgents", "ai.failproof.failproofaid.plist");
29722
+ return resolve30(homedir30(), "Library", "LaunchAgents", "ai.failproof.failproofaid.plist");
28395
29723
  }
28396
29724
  function legacySharedLaunchDaemonPath2() {
28397
29725
  return "/Library/LaunchDaemons/ai.failproof.failproofaid.plist";
@@ -28439,20 +29767,20 @@ function runPrivileged2(command, args) {
28439
29767
  execFileSync5(cmd, argv, { stdio: "ignore", timeout: SERVICE_CMD_TIMEOUT_MS2 });
28440
29768
  }
28441
29769
  function writePrivilegedFile2(destination, contents, mode = "0644") {
28442
- const stagingDir = mkdtempSync2(resolve29(tmpdir3(), "failproofaid-stage-"));
28443
- const staging = resolve29(stagingDir, "service-definition");
29770
+ const stagingDir = mkdtempSync2(resolve30(tmpdir3(), "failproofaid-stage-"));
29771
+ const staging = resolve30(stagingDir, "service-definition");
28444
29772
  try {
28445
29773
  writeFileSync24(staging, contents, "utf8");
28446
29774
  runPrivileged2("install", ["-m", mode, staging, destination]);
28447
29775
  } finally {
28448
- rmSync13(stagingDir, { recursive: true, force: true });
29776
+ rmSync15(stagingDir, { recursive: true, force: true });
28449
29777
  }
28450
29778
  }
28451
29779
  function removeLegacyUserService2() {
28452
29780
  try {
28453
29781
  if (process.platform === "linux") {
28454
29782
  const legacy3 = legacySystemdUserUnitPath2();
28455
- if (!existsSync38(legacy3))
29783
+ if (!existsSync41(legacy3))
28456
29784
  return;
28457
29785
  try {
28458
29786
  execFileSync5("systemctl", ["--user", "disable", "--now", "failproofaid.service"], {
@@ -28469,7 +29797,7 @@ function removeLegacyUserService2() {
28469
29797
  } catch {}
28470
29798
  } else {
28471
29799
  const legacyAgent = legacyLaunchAgentPlistPath2();
28472
- if (existsSync38(legacyAgent)) {
29800
+ if (existsSync41(legacyAgent)) {
28473
29801
  try {
28474
29802
  execFileSync5("launchctl", ["unload", "-w", legacyAgent], {
28475
29803
  stdio: "ignore",
@@ -28479,7 +29807,7 @@ function removeLegacyUserService2() {
28479
29807
  unlinkSync5(legacyAgent);
28480
29808
  }
28481
29809
  const legacyDaemon = legacySharedLaunchDaemonPath2();
28482
- if (existsSync38(legacyDaemon)) {
29810
+ if (existsSync41(legacyDaemon)) {
28483
29811
  try {
28484
29812
  runPrivileged2("launchctl", ["unload", "-w", legacyDaemon]);
28485
29813
  } catch {}
@@ -28495,8 +29823,8 @@ function systemdUnitContents2(binaryPath, workerCmd, cliCmd = null) {
28495
29823
  `).join("");
28496
29824
  const user = assertUnitSafe2(serviceUser2(), "User");
28497
29825
  assertUnitSafe2(binaryPath, "ExecStart");
28498
- assertUnitSafe2(homedir29(), "HOME");
28499
- const conditionPaths = [binaryPath, workerScriptPath2()].filter((p) => typeof p === "string" && existsSync38(p));
29826
+ assertUnitSafe2(homedir30(), "HOME");
29827
+ const conditionPaths = [binaryPath, workerScriptPath2()].filter((p) => typeof p === "string" && existsSync41(p));
28500
29828
  const conditionLines = conditionPaths.map((p) => `ConditionPathExists=${assertUnitSafe2(p, "ConditionPathExists")}
28501
29829
  `).join("");
28502
29830
  return `[Unit]
@@ -28509,7 +29837,7 @@ User=${user}
28509
29837
  # Set explicitly rather than relying on systemd deriving it from User=:
28510
29838
  # failproofaid stores per-user state and refuses to start without HOME, so this
28511
29839
  # required variable is not left to a version-dependent default.
28512
- Environment="HOME=${homedir29()}"
29840
+ Environment="HOME=${homedir30()}"
28513
29841
  ${envLines}ExecStart=${binaryPath}
28514
29842
  Restart=on-failure
28515
29843
  RestartSec=2
@@ -28557,9 +29885,9 @@ ${env.map(([key, value]) => ` <key>${key}</key>
28557
29885
  <key>UserName</key>
28558
29886
  <string>${escapeXml2(serviceUser2())}</string>
28559
29887
  ${envBlock} <key>StandardOutPath</key>
28560
- <string>${escapeXml2(resolve29(logDir2, "failproofaid.log"))}</string>
29888
+ <string>${escapeXml2(resolve30(logDir2, "failproofaid.log"))}</string>
28561
29889
  <key>StandardErrorPath</key>
28562
- <string>${escapeXml2(resolve29(logDir2, "failproofaid.err.log"))}</string>
29890
+ <string>${escapeXml2(resolve30(logDir2, "failproofaid.err.log"))}</string>
28563
29891
  </dict>
28564
29892
  </plist>
28565
29893
  `;
@@ -28691,10 +30019,10 @@ function readInstalledServiceDefinition2() {
28691
30019
  if (!isDaemonSupportedPlatform2())
28692
30020
  return null;
28693
30021
  const path3 = daemonServiceFilePath2();
28694
- if (!path3 || !existsSync38(path3))
30022
+ if (!path3 || !existsSync41(path3))
28695
30023
  return null;
28696
30024
  try {
28697
- return readFileSync30(path3, "utf8");
30025
+ return readFileSync34(path3, "utf8");
28698
30026
  } catch {
28699
30027
  return null;
28700
30028
  }
@@ -28855,7 +30183,7 @@ async function uninstallDaemonService2() {
28855
30183
  try {
28856
30184
  if (process.platform === "linux") {
28857
30185
  const unitPath = systemdUnitPath2();
28858
- if (!existsSync38(unitPath))
30186
+ if (!existsSync41(unitPath))
28859
30187
  return;
28860
30188
  try {
28861
30189
  runPrivileged2("systemctl", ["disable", "--now", systemdUnitName2()]);
@@ -28866,7 +30194,7 @@ async function uninstallDaemonService2() {
28866
30194
  } catch {}
28867
30195
  } else {
28868
30196
  const plistPath = launchdPlistPath2();
28869
- if (!existsSync38(plistPath))
30197
+ if (!existsSync41(plistPath))
28870
30198
  return;
28871
30199
  try {
28872
30200
  runPrivileged2("launchctl", ["unload", "-w", plistPath]);
@@ -28883,7 +30211,7 @@ function daemonVersionSkew2() {
28883
30211
  const recorded = readVersionFile()?.daemon;
28884
30212
  if (!recorded)
28885
30213
  return null;
28886
- if (!existsSync38(installedBinaryPath(recorded)))
30214
+ if (!existsSync41(installedBinaryPath(recorded)))
28887
30215
  return null;
28888
30216
  return recorded === version2 ? null : { installed: recorded, expected: version2 };
28889
30217
  }
@@ -28901,7 +30229,7 @@ function daemonServiceStatus2() {
28901
30229
  if (!isDaemonSupportedPlatform2())
28902
30230
  return "unsupported-platform";
28903
30231
  if (process.platform === "linux") {
28904
- if (!existsSync38(systemdUnitPath2()))
30232
+ if (!existsSync41(systemdUnitPath2()))
28905
30233
  return "not-installed";
28906
30234
  try {
28907
30235
  const out = execFileSync5("systemctl", ["is-active", systemdUnitName2()], {
@@ -28914,7 +30242,7 @@ function daemonServiceStatus2() {
28914
30242
  }
28915
30243
  }
28916
30244
  const plistPath = launchdPlistPath2();
28917
- if (!existsSync38(plistPath))
30245
+ if (!existsSync41(plistPath))
28918
30246
  return "not-installed";
28919
30247
  try {
28920
30248
  const root = typeof process.getuid === "function" && process.getuid() === 0;
@@ -28933,6 +30261,28 @@ function daemonServiceStatus2() {
28933
30261
  return "stopped";
28934
30262
  }
28935
30263
  }
30264
+ function daemonStartedAtMs() {
30265
+ if (process.platform !== "linux")
30266
+ return null;
30267
+ if (!existsSync41(systemdUnitPath2()))
30268
+ return null;
30269
+ try {
30270
+ const raw = execFileSync5("systemctl", ["show", systemdUnitName2(), "-p", "ActiveEnterTimestampMonotonic", "--value"], { stdio: ["ignore", "pipe", "ignore"], timeout: SERVICE_CMD_TIMEOUT_MS2 }).toString().trim();
30271
+ return startedAtFromMonotonic(Number(raw), Math.floor(Number(process.hrtime.bigint()) / 1000), Date.now());
30272
+ } catch {
30273
+ return null;
30274
+ }
30275
+ }
30276
+ function startedAtFromMonotonic(activeEnterMonotonicUs, monotonicNowUs, nowMs) {
30277
+ if (!Number.isFinite(activeEnterMonotonicUs) || activeEnterMonotonicUs <= 0)
30278
+ return null;
30279
+ if (!Number.isFinite(monotonicNowUs) || monotonicNowUs <= 0)
30280
+ return null;
30281
+ const activeForMs = (monotonicNowUs - activeEnterMonotonicUs) / 1000;
30282
+ if (activeForMs < 0)
30283
+ return null;
30284
+ return Math.round(nowMs - activeForMs);
30285
+ }
28936
30286
  var SERVICE_CMD_TIMEOUT_MS2 = 1e4, SERVICE_START_TIMEOUT_MS2 = 5000, SERVICE_START_POLL_MS2 = 100, SERVICE_SETTLE_MS2 = 750, SUDO_PROMPT_TIMEOUT_MS2 = 120000, UNIT_UNSAFE_RE2, DAEMON_PROBE_TIMEOUT_MS2 = 5000, DAEMON_PROBE_READY_TIMEOUT_MS2 = 1e4, DAEMON_PROBE_RETRY_MS2 = 150;
28937
30287
  var init_daemon_service2 = __esm(() => {
28938
30288
  init_hook_logger();
@@ -28949,7 +30299,7 @@ __export(exports_uninstall_cli, {
28949
30299
  serviceStateLabel: () => serviceStateLabel,
28950
30300
  runUninstallCommand: () => runUninstallCommand
28951
30301
  });
28952
- import { existsSync as existsSync39, rmSync as rmSync14 } from "node:fs";
30302
+ import { existsSync as existsSync42, rmSync as rmSync16 } from "node:fs";
28953
30303
  function survey(cwd) {
28954
30304
  const clis = [];
28955
30305
  for (const id of listInstallableIds()) {
@@ -28970,9 +30320,9 @@ function survey(cwd) {
28970
30320
  return {
28971
30321
  clis,
28972
30322
  servicePath,
28973
- serviceInstalled: !!servicePath && existsSync39(servicePath),
30323
+ serviceInstalled: !!servicePath && existsSync42(servicePath),
28974
30324
  daemonConfigured,
28975
- homeExists: existsSync39(failproofaiHome())
30325
+ homeExists: existsSync42(failproofaiHome())
28976
30326
  };
28977
30327
  }
28978
30328
  async function runUninstallCommand(opts = {}) {
@@ -29070,7 +30420,7 @@ async function runUninstallCommand(opts = {}) {
29070
30420
  } catch {}
29071
30421
  try {
29072
30422
  await uninstallDaemonService();
29073
- if (found.servicePath && existsSync39(found.servicePath)) {
30423
+ if (found.servicePath && existsSync42(found.servicePath)) {
29074
30424
  failures.push(`the service at ${found.servicePath} is still there (most often: no sudo). ` + `Remove it with the commands below.`);
29075
30425
  } else {
29076
30426
  lines.push(`✓ stopped and removed the daemon service`);
@@ -29082,7 +30432,7 @@ async function runUninstallCommand(opts = {}) {
29082
30432
  }
29083
30433
  if (opts.purge && found.homeExists) {
29084
30434
  try {
29085
- rmSync14(failproofaiHome(), { recursive: true, force: true });
30435
+ rmSync16(failproofaiHome(), { recursive: true, force: true });
29086
30436
  purged = true;
29087
30437
  lines.push(`✓ deleted ${failproofaiHome()}`);
29088
30438
  } catch (err) {
@@ -29093,7 +30443,7 @@ async function runUninstallCommand(opts = {}) {
29093
30443
  lines.push(``, `Not everything could be removed:`);
29094
30444
  for (const f of failures)
29095
30445
  lines.push(` ✗ ${f}`);
29096
- if (found.servicePath && existsSync39(found.servicePath)) {
30446
+ if (found.servicePath && existsSync42(found.servicePath)) {
29097
30447
  lines.push(``, `To remove the service by hand:`, ...manualServiceRemoval(found.servicePath), ``, `(\`${daemonStatusCommand()}\` shows its current state.)`);
29098
30448
  }
29099
30449
  return { exitCode: 1, lines, planLines, purged };
@@ -29136,6 +30486,8 @@ var exports_tui = {};
29136
30486
  __export(exports_tui, {
29137
30487
  truncate: () => truncate2,
29138
30488
  summarize: () => summarize2,
30489
+ stepOpen: () => stepOpen2,
30490
+ step: () => step2,
29139
30491
  selectOne: () => selectOne2,
29140
30492
  renderLaunchBanner: () => renderLaunchBanner2,
29141
30493
  renderBrandLogo: () => renderBrandLogo2,
@@ -29172,11 +30524,11 @@ function truecolorEnabled2() {
29172
30524
  }
29173
30525
  function paint2(on) {
29174
30526
  const tc = on && truecolorEnabled2();
29175
- const mk = (h, bold = false) => (s) => {
30527
+ const mk = (h, bold2 = false) => (s) => {
29176
30528
  if (!on)
29177
30529
  return s;
29178
30530
  const code = tc ? `38;2;${h.rgb[0]};${h.rgb[1]};${h.rgb[2]}` : h.basic;
29179
- return `${ESC2}[${bold ? "1;" : ""}${code}m${s}${ESC2}[0m`;
30531
+ return `${ESC2}[${bold2 ? "1;" : ""}${code}m${s}${ESC2}[0m`;
29180
30532
  };
29181
30533
  return {
29182
30534
  bold: (s) => on ? `${ESC2}[1m${s}${ESC2}[0m` : s,
@@ -29282,19 +30634,40 @@ function intro2(message, stdout = process.stdout) {
29282
30634
  }
29283
30635
  function renderLaunchBanner2(version3, stdout = process.stdout) {
29284
30636
  const c2 = paint2(colorsEnabled2(stdout));
29285
- const row = (label, value) => ` ${c2.guide(label.padEnd(9))}${value}`;
30637
+ const row2 = (label, value) => ` ${c2.guide(label.padEnd(9))}${value}`;
29286
30638
  const header = stdout.isTTY ? renderBrandLogo2(stdout) : [" failproof ai", ` ${TAGLINE2}`];
29287
30639
  return [
29288
30640
  "",
29289
30641
  ...header,
29290
30642
  "",
29291
- row("version", c2.pink(version3)),
29292
- row("star", c2.dim("https://github.com/failproofai/failproofai")),
29293
- row("docs", c2.dim("https://docs.befailproof.ai/introduction")),
29294
- row("discord", c2.dim("https://discord.befailproof.ai/")),
30643
+ row2("version", c2.pink(version3)),
30644
+ row2("star", c2.dim("https://github.com/failproofai/failproofai")),
30645
+ row2("docs", c2.dim("https://docs.befailproof.ai/introduction")),
30646
+ row2("discord", c2.dim("https://discord.befailproof.ai/")),
29295
30647
  ""
29296
30648
  ];
29297
30649
  }
30650
+ function step2(message, summary, stdout = process.stdout) {
30651
+ const c2 = paint2(colorsEnabled2(stdout));
30652
+ const rows = summary === undefined ? [] : Array.isArray(summary) ? summary : [summary];
30653
+ if (!stdout.isTTY) {
30654
+ if (rows.length)
30655
+ stdout.write(`${message}: ${rows.join(" ")}
30656
+ `);
30657
+ return;
30658
+ }
30659
+ const cols = stdout.columns || 80;
30660
+ const lines = [c2.dim(BAR2), truncate2(`${c2.dim(STEP_DONE2)} ${message}`, cols - 1)];
30661
+ for (const r of rows)
30662
+ lines.push(truncate2(`${c2.dim(BAR2)} ${c2.dim(r)}`, cols - 1));
30663
+ writeLines2(stdout, lines);
30664
+ }
30665
+ function stepOpen2(message, stdout = process.stdout) {
30666
+ const c2 = paint2(colorsEnabled2(stdout));
30667
+ if (!stdout.isTTY)
30668
+ return;
30669
+ writeLines2(stdout, [c2.dim(BAR2), `${c2.guide(STEP_ACTIVE2)} ${c2.bold(message)}`]);
30670
+ }
29298
30671
  function outro2(message, opts = {}, stdout = process.stdout) {
29299
30672
  const c2 = paint2(colorsEnabled2(stdout));
29300
30673
  const ok2 = opts.ok !== false;
@@ -29364,11 +30737,11 @@ function runPrompt2(p) {
29364
30737
  lines.push(`${c2.dim(BAR2)} ${c2.dim(`↑ ${above} more`)}`);
29365
30738
  const budget = Math.max(6, cols - nameCol - 10);
29366
30739
  for (let ri = start;ri < end; ri++) {
29367
- const row = rows[ri];
29368
- if (row.kind === "header") {
29369
- lines.push(`${c2.dim(BAR2)} ${c2.dim(row.text)}`);
30740
+ const row2 = rows[ri];
30741
+ if (row2.kind === "header") {
30742
+ lines.push(`${c2.dim(BAR2)} ${c2.dim(row2.text)}`);
29370
30743
  } else {
29371
- lines.push(`${c2.dim(BAR2)} ${p.renderRow(row.index, row.index === cursor2, budget)}`);
30744
+ lines.push(`${c2.dim(BAR2)} ${p.renderRow(row2.index, row2.index === cursor2, budget)}`);
29372
30745
  }
29373
30746
  }
29374
30747
  if (below > 0)
@@ -29387,7 +30760,7 @@ function runPrompt2(p) {
29387
30760
  `${c2.dim(BAR2)} ${c2.dim(summary)}`
29388
30761
  ]);
29389
30762
  };
29390
- return new Promise((resolve30) => {
30763
+ return new Promise((resolve31) => {
29391
30764
  hideCursor2(stdout);
29392
30765
  repaint2(stdout, region, build());
29393
30766
  readline3.emitKeypressEvents(stdin);
@@ -29403,7 +30776,7 @@ function runPrompt2(p) {
29403
30776
  const finish = (result) => {
29404
30777
  cleanup();
29405
30778
  collapse(result);
29406
- resolve30(result);
30779
+ resolve31(result);
29407
30780
  };
29408
30781
  function onKey(_s, key) {
29409
30782
  if (!key)
@@ -29533,7 +30906,7 @@ function promptText2(opts) {
29533
30906
  return error ? { ok: false, error } : { ok: true, value };
29534
30907
  };
29535
30908
  if (!stdin.isTTY) {
29536
- return new Promise((resolve30) => {
30909
+ return new Promise((resolve31) => {
29537
30910
  let buf = "";
29538
30911
  const onData = (chunk) => {
29539
30912
  buf += String(chunk);
@@ -29546,21 +30919,21 @@ function promptText2(opts) {
29546
30919
  stdin.removeListener("end", done);
29547
30920
  const r = accept(buf.split(`
29548
30921
  `)[0] ?? "");
29549
- resolve30(r.ok ? r.value : null);
30922
+ resolve31(r.ok ? r.value : null);
29550
30923
  };
29551
30924
  stdin.on("data", onData);
29552
30925
  stdin.on("end", done);
29553
30926
  });
29554
30927
  }
29555
- return new Promise((resolve30) => {
30928
+ return new Promise((resolve31) => {
29556
30929
  let value = "";
29557
30930
  const draw = (error) => {
29558
30931
  const cols = stdout.columns || 80;
29559
30932
  const shown = opts.mask ? "•".repeat(value.length) : value;
29560
- const hint = opts.hint ? ` ${c2.dim(opts.hint)}` : "";
29561
- const line = truncate2(`${c2.bold(opts.message)} ${shown}${hint}`, cols - 1);
30933
+ const hint = opts.hint && value.length === 0 ? ` ${c2.dim(opts.hint)}` : "";
30934
+ const line = truncate2(`${opts.prefix ?? ""}${c2.bold(opts.message)} ${shown}${hint}`, cols - 1);
29562
30935
  const err = error ? `
29563
- ${truncate2(c2.warn(error), cols - 3)}` : "";
30936
+ ${opts.prefix ?? " "}${truncate2(c2.warn(error), cols - 3)}` : "";
29564
30937
  stdout.write(`\r\x1B[2K${line}${err}`);
29565
30938
  if (err)
29566
30939
  stdout.write("\x1B[1A");
@@ -29582,14 +30955,14 @@ function promptText2(opts) {
29582
30955
  return;
29583
30956
  if (key.ctrl && (key.name === "c" || key.name === "d") || key.name === "escape") {
29584
30957
  cleanup();
29585
- resolve30(null);
30958
+ resolve31(null);
29586
30959
  return;
29587
30960
  }
29588
30961
  if (key.name === "return" || key.name === "enter") {
29589
30962
  const r = accept(value);
29590
30963
  if (r.ok) {
29591
30964
  cleanup();
29592
- resolve30(r.value);
30965
+ resolve31(r.value);
29593
30966
  } else {
29594
30967
  draw(r.error);
29595
30968
  }
@@ -29657,9 +31030,9 @@ __export(exports_manager, {
29657
31030
  getSettingsPath: () => getSettingsPath2
29658
31031
  });
29659
31032
  import { execSync as execSync7 } from "node:child_process";
29660
- import { existsSync as existsSync40 } from "node:fs";
29661
- import { resolve as resolve30, basename as basename8 } from "node:path";
29662
- import { platform as platform5, arch as arch4, release as release3, hostname as hostname5 } from "node:os";
31033
+ import { existsSync as existsSync43 } from "node:fs";
31034
+ import { resolve as resolve31, basename as basename8 } from "node:path";
31035
+ import { platform as platform5, arch as arch4, release as release3, hostname as hostname6 } from "node:os";
29663
31036
  function getSettingsPath2(scope, cwd) {
29664
31037
  return claudeCode.getSettingsPath(scope, cwd);
29665
31038
  }
@@ -29766,9 +31139,9 @@ async function installHooksImpl2(policyNames, scope = "user", cwd, includeBeta =
29766
31139
  delete configToWrite.customPoliciesPath;
29767
31140
  delete configToWrite.customPoliciesPaths;
29768
31141
  } else if (customPoliciesPath && (typeof customPoliciesPath === "string" || customPoliciesPath.length > 0)) {
29769
- const incoming = (typeof customPoliciesPath === "string" ? [customPoliciesPath] : customPoliciesPath).map((path3) => resolve30(path3));
29770
- const carried = (previousConfig.customPoliciesPaths ?? (previousConfig.customPoliciesPath ? [previousConfig.customPoliciesPath] : [])).map((path3) => resolve30(path3)).filter((path3) => {
29771
- if (existsSync40(path3))
31142
+ const incoming = (typeof customPoliciesPath === "string" ? [customPoliciesPath] : customPoliciesPath).map((path3) => resolve31(path3));
31143
+ const carried = (previousConfig.customPoliciesPaths ?? (previousConfig.customPoliciesPath ? [previousConfig.customPoliciesPath] : [])).map((path3) => resolve31(path3)).filter((path3) => {
31144
+ if (existsSync43(path3))
29772
31145
  return true;
29773
31146
  console.log(`Dropping custom policies path (file no longer exists): ${path3}`);
29774
31147
  return false;
@@ -29854,7 +31227,7 @@ Enabled ${selectedPolicies.length} policy(ies): ${selectedPolicies.join(", ")}
29854
31227
  platform: platform5(),
29855
31228
  arch: arch4(),
29856
31229
  os_release: release3(),
29857
- hostname_hash: hashToId2(hostname5()),
31230
+ hostname_hash: hashToId2(hostname6()),
29858
31231
  has_custom_hooks_path: !!(configToWrite.customPoliciesPaths?.length || configToWrite.customPoliciesPath),
29859
31232
  has_policy_params: !!(configToWrite.policyParams && Object.keys(configToWrite.policyParams).length > 0),
29860
31233
  param_policy_names: configToWrite.policyParams ? Object.keys(configToWrite.policyParams) : [],
@@ -29945,7 +31318,7 @@ async function removeHooks2(policyNames, scope = "user", cwd, opts) {
29945
31318
  platform: platform5(),
29946
31319
  arch: arch4(),
29947
31320
  os_release: release3(),
29948
- hostname_hash: hashToId2(hostname5())
31321
+ hostname_hash: hashToId2(hostname6())
29949
31322
  });
29950
31323
  } catch {}
29951
31324
  console.log(`Disabled ${policyNames.length - notEnabled.length} policy(ies).`);
@@ -29960,7 +31333,7 @@ async function removeHooks2(policyNames, scope = "user", cwd, opts) {
29960
31333
  const scopesToRemove = scope === "all" ? [...integration.scopes] : integration.scopes.includes(scope) ? [scope] : [];
29961
31334
  for (const s of scopesToRemove) {
29962
31335
  const settingsPaths = settingsPathsFor(integration, s, cwd);
29963
- const existing = settingsPaths.filter((p) => existsSync40(p));
31336
+ const existing = settingsPaths.filter((p) => existsSync43(p));
29964
31337
  if (existing.length === 0) {
29965
31338
  if (scope !== "all" && selectedClis.length === 1) {
29966
31339
  console.log("No settings file found. Nothing to remove.");
@@ -30010,7 +31383,7 @@ async function removeHooks2(policyNames, scope = "user", cwd, opts) {
30010
31383
  platform: platform5(),
30011
31384
  arch: arch4(),
30012
31385
  os_release: release3(),
30013
- hostname_hash: hashToId2(hostname5())
31386
+ hostname_hash: hashToId2(hostname6())
30014
31387
  });
30015
31388
  } catch {}
30016
31389
  if (scope === "all") {
@@ -30109,16 +31482,16 @@ Failproof AI Hook Policies
30109
31482
  console.log(` ${"─".repeat(scopeHeaderWidth)}${"─".repeat(nameColWidth)}${"─".repeat(38)}`);
30110
31483
  const printMultiScopeRow = (policy) => {
30111
31484
  const enabled = enabledSet.has(policy.name);
30112
- let row = " ";
31485
+ let row2 = " ";
30113
31486
  for (const _scope of installedScopes) {
30114
31487
  if (enabled) {
30115
- row += `\x1B[32m✓ ON\x1B[0m` + " ".repeat(COL - 4);
31488
+ row2 += `\x1B[32m✓ ON\x1B[0m` + " ".repeat(COL - 4);
30116
31489
  } else {
30117
- row += " OFF" + " ".repeat(COL - 5);
31490
+ row2 += " OFF" + " ".repeat(COL - 5);
30118
31491
  }
30119
31492
  }
30120
- row += policy.name.padEnd(nameColWidth) + policy.description;
30121
- console.log(row);
31493
+ row2 += policy.name.padEnd(nameColWidth) + policy.description;
31494
+ console.log(row2);
30122
31495
  printParamsSummary(policy.name, ` ${" ".repeat(scopeHeaderWidth)}`);
30123
31496
  };
30124
31497
  for (const policy of regularPolicies)
@@ -30159,9 +31532,9 @@ Failproof AI Hook Policies
30159
31532
  console.log(`
30160
31533
  ── Custom Policies ───────────────────────`);
30161
31534
  for (const path3 of explicitPaths) {
30162
- const absPath = resolve30(findProjectConfigDir(cwd ?? process.cwd()), path3);
31535
+ const absPath = resolve31(findProjectConfigDir(cwd ?? process.cwd()), path3);
30163
31536
  console.log(` ${absPath}`);
30164
- if (!existsSync40(absPath)) {
31537
+ if (!existsSync43(absPath)) {
30165
31538
  console.log(` \x1B[31m✗ File not found: ${absPath}\x1B[0m`);
30166
31539
  continue;
30167
31540
  }
@@ -30180,7 +31553,7 @@ Failproof AI Hook Policies
30180
31553
  console.log();
30181
31554
  }
30182
31555
  const base = findProjectConfigDir(cwd ?? process.cwd());
30183
- const projectDir = resolve30(base, ".failproofai", "policies");
31556
+ const projectDir = resolve31(base, ".failproofai", "policies");
30184
31557
  const userDir = customPoliciesDir();
30185
31558
  const sameDir = userDir === projectDir;
30186
31559
  const conventionDirs = [
@@ -30393,32 +31766,32 @@ async function promptCliTargetSelection(detected, action = "install") {
30393
31766
  cursorHidden = false;
30394
31767
  }
30395
31768
  }
30396
- const { dim, bold, guide: teal, pink, pinkBold } = paint(!process.env.NO_COLOR);
31769
+ const { dim: dim2, bold: bold2, guide: teal, pink: pink2, pinkBold } = paint(!process.env.NO_COLOR);
30397
31770
  const heading = action === "uninstall" ? "Remove failproofai hooks" : "Install failproofai hooks";
30398
31771
  function render() {
30399
31772
  const cols = process.stdout.columns || 100;
30400
31773
  hideCursor3();
30401
- const g = dim(BAR);
30402
- const lines = [g, `${teal(STEP_ACTIVE)} ${bold(heading)}`];
30403
- for (const row of buildDisplayRows()) {
30404
- if (row.kind === "blank") {
31774
+ const g = dim2(BAR);
31775
+ const lines = [g, `${teal(STEP_ACTIVE)} ${bold2(heading)}`];
31776
+ for (const row2 of buildDisplayRows()) {
31777
+ if (row2.kind === "blank") {
30405
31778
  lines.push(g);
30406
31779
  continue;
30407
31780
  }
30408
- if (row.kind === "header") {
30409
- const hint = row.hint ? ` ${dim("· " + row.hint)}` : "";
30410
- lines.push(`${g} ${dim(row.title)}${hint}`);
31781
+ if (row2.kind === "header") {
31782
+ const hint = row2.hint ? ` ${dim2("· " + row2.hint)}` : "";
31783
+ lines.push(`${g} ${dim2(row2.title)}${hint}`);
30411
31784
  continue;
30412
31785
  }
30413
- const opt = row.option;
30414
- const isActive = row.itemIndex === cursor2;
30415
- const caret = isActive ? pink("❯") : " ";
30416
- const marker = opt.isAll ? teal("★") : opt.detected ? pink("●") : dim("○");
30417
- const label = isActive ? pinkBold(opt.label) : opt.detected ? opt.label : dim(opt.label);
31786
+ const opt = row2.option;
31787
+ const isActive = row2.itemIndex === cursor2;
31788
+ const caret = isActive ? pink2("❯") : " ";
31789
+ const marker = opt.isAll ? teal("★") : opt.detected ? pink2("●") : dim2("○");
31790
+ const label = isActive ? pinkBold(opt.label) : opt.detected ? opt.label : dim2(opt.label);
30418
31791
  lines.push(`${g} ${caret} ${marker} ${label}`);
30419
31792
  }
30420
31793
  lines.push(g);
30421
- lines.push(`${g} ${dim("↑/↓ move · ↵ select · esc cancel")}`);
31794
+ lines.push(`${g} ${dim2("↑/↓ move · ↵ select · esc cancel")}`);
30422
31795
  if (lastLineCount > 0) {
30423
31796
  process.stdout.write(`\x1B[${lastLineCount}A\x1B[J`);
30424
31797
  }
@@ -30428,7 +31801,7 @@ async function promptCliTargetSelection(detected, action = "install") {
30428
31801
  lastLineCount = lines.length;
30429
31802
  }
30430
31803
  const itemCount = options.length;
30431
- return new Promise((resolve31) => {
31804
+ return new Promise((resolve32) => {
30432
31805
  render();
30433
31806
  readline4.emitKeypressEvents(process.stdin);
30434
31807
  const wasRaw = process.stdin.isRaw;
@@ -30461,7 +31834,7 @@ async function promptCliTargetSelection(detected, action = "install") {
30461
31834
  cleanup();
30462
31835
  process.stdout.write(`
30463
31836
  `);
30464
- resolve31(options[cursor2].value);
31837
+ resolve32(options[cursor2].value);
30465
31838
  }
30466
31839
  }
30467
31840
  process.stdin.on("keypress", onKey);
@@ -30487,7 +31860,7 @@ async function promptPolicySelection2(preSelected, options = {}) {
30487
31860
  const WINDOW_SIZE = 10;
30488
31861
  const useColor = !process.env.NO_COLOR;
30489
31862
  const c2 = paint(useColor);
30490
- const { dim, bold } = c2;
31863
+ const { dim: dim2, bold: bold2 } = c2;
30491
31864
  const stepMark = c2.guide;
30492
31865
  const activeName = c2.pinkBold;
30493
31866
  const selectedMark = c2.pink;
@@ -30556,24 +31929,24 @@ async function promptPolicySelection2(preSelected, options = {}) {
30556
31929
  if (shown > 0 && cursor2 >= shown)
30557
31930
  cursor2 = shown - 1;
30558
31931
  const selectedCount = items.filter((i) => i.selected).length;
30559
- const g = dim(BAR);
31932
+ const g = dim2(BAR);
30560
31933
  const lines = [];
30561
31934
  lines.push(g);
30562
- lines.push(`${stepMark(STEP_ACTIVE)} ${bold("Choose the policies to enable")} ${dim("·")} ` + `${stepMark(String(selectedCount))} ${dim("selected")}`);
31935
+ lines.push(`${stepMark(STEP_ACTIVE)} ${bold2("Choose the policies to enable")} ${dim2("·")} ` + `${stepMark(String(selectedCount))} ${dim2("selected")}`);
30563
31936
  const blockCursor = useColor ? "\x1B[7m \x1B[0m" : "_";
30564
- const countLabel = search ? dim(`${shown}/${total} shown`) : dim(`${total} policies`);
30565
- lines.push(`${g} ${dim("filter ›")} ${search}${blockCursor} ${countLabel}`);
31937
+ const countLabel = search ? dim2(`${shown}/${total} shown`) : dim2(`${total} policies`);
31938
+ lines.push(`${g} ${dim2("filter ›")} ${search}${blockCursor} ${countLabel}`);
30566
31939
  lines.push(g);
30567
31940
  if (shown === 0) {
30568
- lines.push(`${g} ${dim(`no policies match “${search}”`)}`);
31941
+ lines.push(`${g} ${dim2(`no policies match “${search}”`)}`);
30569
31942
  for (let i = 0;i < WINDOW_SIZE + 1; i++)
30570
31943
  lines.push(g);
30571
31944
  } else {
30572
31945
  const displayRows3 = buildDisplayRows(filtered);
30573
31946
  let cursorDisplayRow = 0;
30574
31947
  for (let i = 0;i < displayRows3.length; i++) {
30575
- const row = displayRows3[i];
30576
- if (row.kind === "item" && row.filteredIndex === cursor2) {
31948
+ const row2 = displayRows3[i];
31949
+ if (row2.kind === "item" && row2.filteredIndex === cursor2) {
30577
31950
  cursorDisplayRow = i;
30578
31951
  break;
30579
31952
  }
@@ -30583,30 +31956,30 @@ async function promptPolicySelection2(preSelected, options = {}) {
30583
31956
  windowStart = Math.min(windowStart, Math.max(0, displayRows3.length - WINDOW_SIZE));
30584
31957
  const windowEnd = Math.min(displayRows3.length, windowStart + WINDOW_SIZE);
30585
31958
  const aboveItems = displayRows3.slice(0, windowStart).filter((r) => r.kind === "item").length;
30586
- lines.push(aboveItems > 0 ? `${g} ${dim(`↑ ${aboveItems} more`)}` : g);
31959
+ lines.push(aboveItems > 0 ? `${g} ${dim2(`↑ ${aboveItems} more`)}` : g);
30587
31960
  for (let i = windowStart;i < windowEnd; i++) {
30588
- const row = displayRows3[i];
30589
- if (row.kind === "header") {
30590
- lines.push(`${g} ${dim(row.category.toUpperCase())} ${dim(`${row.enabledCount}/${row.totalCount}`)}`);
31961
+ const row2 = displayRows3[i];
31962
+ if (row2.kind === "header") {
31963
+ lines.push(`${g} ${dim2(row2.category.toUpperCase())} ${dim2(`${row2.enabledCount}/${row2.totalCount}`)}`);
30591
31964
  } else {
30592
- const item = row.item;
30593
- const active = row.filteredIndex === cursor2;
30594
- const box = item.selected ? selectedMark(CHECK_ON) : dim(CHECK_OFF);
31965
+ const item = row2.item;
31966
+ const active = row2.filteredIndex === cursor2;
31967
+ const box = item.selected ? selectedMark(CHECK_ON) : dim2(CHECK_OFF);
30595
31968
  const rawName = item.name.padEnd(NAME_COL);
30596
- const name = active ? activeName(rawName) : item.selected ? rawName : dim(rawName);
31969
+ const name = active ? activeName(rawName) : item.selected ? rawName : dim2(rawName);
30597
31970
  const beta = item.beta ? ` ${betaTag("beta")}` : "";
30598
31971
  const descWidth = Math.max(8, cols - NAME_COL - 8 - (item.beta ? 5 : 0));
30599
- const desc = dim(truncate(item.description, descWidth));
31972
+ const desc = dim2(truncate(item.description, descWidth));
30600
31973
  lines.push(`${g} ${box} ${name}${beta} ${desc}`);
30601
31974
  }
30602
31975
  }
30603
31976
  for (let i = windowEnd - windowStart;i < WINDOW_SIZE; i++)
30604
31977
  lines.push(g);
30605
31978
  const belowItems = displayRows3.slice(windowEnd).filter((r) => r.kind === "item").length;
30606
- lines.push(belowItems > 0 ? `${g} ${dim(`↓ ${belowItems} more`)}` : g);
31979
+ lines.push(belowItems > 0 ? `${g} ${dim2(`↓ ${belowItems} more`)}` : g);
30607
31980
  }
30608
31981
  lines.push(g);
30609
- lines.push(`${g} ${dim("↑/↓ move · space select · ctrl+a all · ↵ save · type to filter · esc clear")}`);
31982
+ lines.push(`${g} ${dim2("↑/↓ move · space select · ctrl+a all · ↵ save · type to filter · esc clear")}`);
30610
31983
  if (lastLineCount > 0)
30611
31984
  process.stdout.write(`\x1B[${lastLineCount}A\x1B[J`);
30612
31985
  process.stdout.write(lines.map((l) => truncate(l, cols)).join(`
@@ -30614,7 +31987,7 @@ async function promptPolicySelection2(preSelected, options = {}) {
30614
31987
  `);
30615
31988
  lastLineCount = lines.length;
30616
31989
  }
30617
- return new Promise((resolve31) => {
31990
+ return new Promise((resolve32) => {
30618
31991
  render();
30619
31992
  process.stdin.setRawMode(true);
30620
31993
  process.stdin.resume();
@@ -30647,11 +32020,11 @@ async function promptPolicySelection2(preSelected, options = {}) {
30647
32020
  const selected = items.filter((i) => i.selected).map((i) => i.name);
30648
32021
  if (lastLineCount > 0)
30649
32022
  process.stdout.write(`\x1B[${lastLineCount}A\x1B[J`);
30650
- process.stdout.write(`${dim(BAR)}
30651
- ${dim(STEP_DONE)} Policies
30652
- ${dim(BAR)} ${dim(`${selected.length} selected`)}
32023
+ process.stdout.write(`${dim2(BAR)}
32024
+ ${dim2(STEP_DONE)} Policies
32025
+ ${dim2(BAR)} ${dim2(`${selected.length} selected`)}
30653
32026
  `);
30654
- resolve31(selected);
32027
+ resolve32(selected);
30655
32028
  } else if (key.name === "escape") {
30656
32029
  search = "";
30657
32030
  cursor2 = 0;
@@ -30874,6 +32247,13 @@ async function runScheduledAudit2() {
30874
32247
  }
30875
32248
  process.stdout.write(`failproofai: audit complete — ${num2(result.eventsScanned)} tool calls across ` + `${num2(result.transcripts.scanned)} sessions, ${num2(result.totals.hits)} hits
30876
32249
  `);
32250
+ const outcome = await reportHarm(result);
32251
+ const line = describeOutcome2(outcome);
32252
+ if (line) {
32253
+ const stream = outcome.kind === "sent" ? process.stdout : process.stderr;
32254
+ stream.write(`${line}
32255
+ `);
32256
+ }
30877
32257
  return 0;
30878
32258
  } finally {
30879
32259
  attempt.lock.release();
@@ -30938,15 +32318,71 @@ async function runAuditCli2(args) {
30938
32318
  die2(`\`audit --scheduled\` takes no other arguments (got: ${extra}).`);
30939
32319
  process.exit(await runScheduledAudit2());
30940
32320
  }
32321
+ if (args.includes("--status")) {
32322
+ const extra = args.find((a) => a !== "--status");
32323
+ if (extra)
32324
+ die2(`\`audit --status\` takes no other arguments (got: ${extra}).`);
32325
+ const { runScheduleStatus: runScheduleStatus2 } = await Promise.resolve().then(() => (init_schedule_cli(), exports_schedule_cli));
32326
+ runScheduleStatus2();
32327
+ process.exit(0);
32328
+ }
32329
+ if (args.includes("--no-schedule")) {
32330
+ const extra = args.find((a) => a !== "--no-schedule");
32331
+ if (extra)
32332
+ die2(`\`audit --no-schedule\` takes no other arguments (got: ${extra}).`);
32333
+ const { runScheduleOff: runScheduleOff2 } = await Promise.resolve().then(() => (init_schedule_cli(), exports_schedule_cli));
32334
+ runScheduleOff2();
32335
+ process.exit(0);
32336
+ }
32337
+ const scheduleAt = args.indexOf("--schedule");
32338
+ if (scheduleAt !== -1) {
32339
+ let days;
32340
+ let email;
32341
+ for (let i = 0;i < args.length; i += 1) {
32342
+ const a = args[i];
32343
+ if (a === "--schedule") {
32344
+ const next = args[i + 1];
32345
+ if (next !== undefined && !next.startsWith("-")) {
32346
+ days = next;
32347
+ i += 1;
32348
+ }
32349
+ continue;
32350
+ }
32351
+ if (a === "--email" || a.startsWith("--email=")) {
32352
+ if (a.startsWith("--email=")) {
32353
+ email = a.slice("--email=".length);
32354
+ } else {
32355
+ email = args[i + 1];
32356
+ i += 1;
32357
+ }
32358
+ if (email === undefined || email.length === 0 || email.startsWith("-")) {
32359
+ die2("`--email` needs an address, e.g. `--email you@yourdomain.com`.");
32360
+ }
32361
+ continue;
32362
+ }
32363
+ die2(`\`audit --schedule\` does not take ${a}.`);
32364
+ }
32365
+ const { runScheduleOn: runScheduleOn2, ScheduleCliError: ScheduleCliError2 } = await Promise.resolve().then(() => (init_schedule_cli(), exports_schedule_cli));
32366
+ const { LoginError: LoginError2 } = await Promise.resolve().then(() => (init_cli_login(), exports_cli_login));
32367
+ try {
32368
+ await runScheduleOn2(days, email);
32369
+ } catch (err) {
32370
+ if (err instanceof ScheduleCliError2 || err instanceof LoginError2)
32371
+ die2(err.message);
32372
+ throw err;
32373
+ }
32374
+ process.exit(0);
32375
+ }
30941
32376
  const stray = args.find((a) => a !== "--help" && a !== "-h");
30942
32377
  if (stray) {
30943
- die2(`\`audit\` takes no arguments yet (got: ${stray}).
30944
- ` + `Run \`failproofai audit\` to scan your history and open the dashboard.`);
32378
+ die2(`\`audit\` does not take ${stray}.
32379
+ Run \`failproofai audit\` to scan your history and open the dashboard,
32380
+ or \`failproofai audit --help\` for the scheduling commands.`);
30945
32381
  }
30946
32382
  const attempt = acquireAuditLock("cli");
30947
32383
  if (!attempt.ok) {
30948
32384
  process.stderr.write(`Error: ${heldByLine2(attempt.heldBy)}.
30949
- ` + `Two audits write the same cache files, so this one won't start. Try again shortly.
32385
+ Two audits write the same cache files, so this one won't start. Try again shortly.
30950
32386
  `);
30951
32387
  process.exit(EXIT_AUDIT_ALREADY_RUNNING2);
30952
32388
  }
@@ -30970,7 +32406,7 @@ async function runAuditCli2(args) {
30970
32406
  if (result.eventsScanned === 0) {
30971
32407
  process.stdout.write(`
30972
32408
  ${c2(DIM2, "no agent sessions found yet.")}
30973
- ` + ` install hooks with ${c2(CYAN2, "failproofai policies --install")} ` + `${c2(DIM2, "and come back after using your agent.")}
32409
+ install hooks with ${c2(CYAN2, "failproofai policies --install")} ${c2(DIM2, "and come back after using your agent.")}
30974
32410
 
30975
32411
  `);
30976
32412
  process.exit(0);
@@ -30985,8 +32421,8 @@ async function runAuditCli2(args) {
30985
32421
  const url = `http://localhost:${DASHBOARD_PORT2}/audit`;
30986
32422
  process.stdout.write(`
30987
32423
  ${c2(DIM2, "starting the dashboard…")}
30988
- ` + ` ${c2(PINK2, "✦")} ${c2(BOLD2, "here's your audit")} ${c2(DIM2, "→")} ${c2(CYAN2, url)}
30989
- ` + ` ${c2(DIM2, "(opening in your browser — press Ctrl+C to stop the server)")}
32424
+ ${c2(PINK2, "✦")} ${c2(BOLD2, "here's your audit")} ${c2(DIM2, "→")} ${c2(CYAN2, url)}
32425
+ ${c2(DIM2, "(opening in your browser — press Ctrl+C to stop the server)")}
30990
32426
 
30991
32427
  `);
30992
32428
  openWhenReady(DASHBOARD_PORT2, "/audit");
@@ -31002,6 +32438,7 @@ var init_cli2 = __esm(() => {
31002
32438
  init_telemetry_id2();
31003
32439
  init_telemetry_sanitize();
31004
32440
  init_open_browser();
32441
+ init_report_harm();
31005
32442
  init_tui();
31006
32443
  AUDIT_STAGES2 = [
31007
32444
  { label: "discovering transcripts", detail: "walking ~/.claude, ~/.codex, ~/.cursor, …" },
@@ -31023,14 +32460,34 @@ USAGE
31023
32460
  server. This is what a scheduled audit runs; exit
31024
32461
  75 means another audit already had the lock.
31025
32462
 
32463
+ SCHEDULING
32464
+ failproofai audit --schedule [days] [--email you@yourdomain.com]
32465
+ Scan on a timer in the background (default 7 days,
32466
+ 1-90), and email you when a scan finds something
32467
+ harmful. Signs you in the first time — the report
32468
+ has to go somewhere. Pass --email to answer that
32469
+ up front and go straight to entering the code.
32470
+ failproofai audit --no-schedule
32471
+ Stop scanning on a timer. Leaves you signed in.
32472
+ failproofai audit --status
32473
+ What this machine is doing: whether scheduling is
32474
+ on, where reports go, the daemon's state, and when
32475
+ the next scan is due.
32476
+
32477
+ These write the same ~/.failproofai/config.json the dashboard's settings page
32478
+ writes, through the same function — so the two are always in step.
32479
+
31026
32480
  WHAT IT DOES
31027
32481
  1. Scans past sessions from every installed agent CLI (Claude, Codex, Cursor,
31028
32482
  Copilot, OpenCode, Pi) — entirely on your machine.
31029
32483
  2. Starts the local dashboard and opens
31030
32484
  http://localhost:${DASHBOARD_PORT2}/audit with your results.
31031
32485
 
31032
- Runs fully offline — no account or network required. Press Ctrl+C to stop the
31033
- dashboard server when you're done.
32486
+ A bare "failproofai audit" needs no account, and nothing from your sessions
32487
+ leaves this machine — anonymous usage counts still apply unless you set
32488
+ FAILPROOFAI_TELEMETRY_DISABLED=1. Scheduling is the exception: it emails you
32489
+ what it finds, so it needs an address.
32490
+ Press Ctrl+C to stop the dashboard server when you're done.
31034
32491
  `.trimStart();
31035
32492
  RESET2 = ANSI_RESET;
31036
32493
  DIM2 = ANSI_DIM;
@@ -31051,10 +32508,10 @@ __export(exports_cloud_enrollment_cli, {
31051
32508
  describeMachine: () => describeMachine,
31052
32509
  connectionStatusLines: () => connectionStatusLines
31053
32510
  });
31054
- function describeMachine(machineId, machineLabel, full = false) {
31055
- if (!machineLabel || machineLabel === machineId)
32511
+ function describeMachine(machineId, machineLabel2, full = false) {
32512
+ if (!machineLabel2 || machineLabel2 === machineId)
31056
32513
  return machineId;
31057
- return full ? `${machineLabel} (${machineId})` : `${machineLabel} (${machineId.slice(0, 8)})`;
32514
+ return full ? `${machineLabel2} (${machineId})` : `${machineLabel2} (${machineId.slice(0, 8)})`;
31058
32515
  }
31059
32516
  function daemonWarning(status) {
31060
32517
  if (status === "running")
@@ -31113,13 +32570,13 @@ async function runConnectCommand(opts) {
31113
32570
  if (!validated.ok)
31114
32571
  return { exitCode: 1, lines: [validated.reason] };
31115
32572
  const machineId = resolveMachineId(opts.machineId);
31116
- const machineLabel = resolveMachineLabel(opts.machineLabel ?? opts.defaultMachineId);
31117
- const shownAs = describeMachine(machineId, machineLabel);
32573
+ const machineLabel2 = resolveMachineLabel(opts.machineLabel ?? opts.defaultMachineId);
32574
+ const shownAs = describeMachine(machineId, machineLabel2);
31118
32575
  const outcome = await connectToCloud({
31119
32576
  url: validated.url,
31120
32577
  token: opts.token,
31121
32578
  machineId,
31122
- machineLabel,
32579
+ machineLabel: machineLabel2,
31123
32580
  sessions: opts.sessions,
31124
32581
  environment: opts.environment,
31125
32582
  verifyPolicy: opts.verify,
@@ -31365,8 +32822,8 @@ __export(exports_launch2, {
31365
32822
  launch: () => launch2
31366
32823
  });
31367
32824
  import { spawn as spawn3 } from "child_process";
31368
- import { realpathSync as realpathSync5, existsSync as existsSync41 } from "node:fs";
31369
- import { resolve as resolve31, dirname as dirname23 } from "node:path";
32825
+ import { realpathSync as realpathSync5, existsSync as existsSync44 } from "node:fs";
32826
+ import { resolve as resolve32, dirname as dirname23 } from "node:path";
31370
32827
  import { fileURLToPath as fileURLToPath3 } from "node:url";
31371
32828
  import { createInterface as createInterface2 } from "node:readline";
31372
32829
  function launch2(mode) {
@@ -31390,9 +32847,9 @@ function launch2(mode) {
31390
32847
  process.env.PORT = port;
31391
32848
  process.env.HOSTNAME = bindHost;
31392
32849
  cmd = "node";
31393
- const packageRoot = process.env.FAILPROOFAI_PACKAGE_ROOT ?? resolve31(dirname23(realpathSync5(fileURLToPath3(import.meta.url))), "..");
31394
- const serverJsPath = resolve31(packageRoot, ".next/standalone/server.js");
31395
- if (!existsSync41(serverJsPath)) {
32850
+ const packageRoot = process.env.FAILPROOFAI_PACKAGE_ROOT ?? resolve32(dirname23(realpathSync5(fileURLToPath3(import.meta.url))), "..");
32851
+ const serverJsPath = resolve32(packageRoot, ".next/standalone/server.js");
32852
+ if (!existsSync44(serverJsPath)) {
31396
32853
  let shadowMessage = null;
31397
32854
  try {
31398
32855
  const diag = diagnoseShadow({ selfPackageRoot: packageRoot, selfVersion: version2 });
@@ -31489,17 +32946,17 @@ var init_cli_error2 = __esm(() => {
31489
32946
 
31490
32947
  // bin/failproofai.mjs
31491
32948
  import { realpathSync as realpathSync6 } from "fs";
31492
- import { dirname as dirname24, resolve as resolve32 } from "path";
32949
+ import { dirname as dirname24, resolve as resolve33 } from "path";
31493
32950
  import { fileURLToPath as fileURLToPath4 } from "url";
31494
32951
  // package.json
31495
- var version = "1.0.0";
32952
+ var version = "1.0.1-beta.0";
31496
32953
 
31497
32954
  // bin/failproofai.mjs
31498
32955
  if (!process.env.FAILPROOFAI_PACKAGE_ROOT) {
31499
- process.env.FAILPROOFAI_PACKAGE_ROOT = resolve32(dirname24(realpathSync6(fileURLToPath4(import.meta.url))), "..");
32956
+ process.env.FAILPROOFAI_PACKAGE_ROOT = resolve33(dirname24(realpathSync6(fileURLToPath4(import.meta.url))), "..");
31500
32957
  }
31501
32958
  if (!process.env.FAILPROOFAI_DIST_PATH) {
31502
- process.env.FAILPROOFAI_DIST_PATH = resolve32(dirname24(realpathSync6(fileURLToPath4(import.meta.url))), "..", "dist");
32959
+ process.env.FAILPROOFAI_DIST_PATH = resolve33(dirname24(realpathSync6(fileURLToPath4(import.meta.url))), "..", "dist");
31503
32960
  }
31504
32961
  var args = process.argv.slice(2);
31505
32962
  if (args[0] === "p")
@@ -31682,6 +33139,12 @@ COMMANDS
31682
33139
 
31683
33140
  audit Audit your agent's behavior, then open the
31684
33141
  dashboard at http://localhost:8020/audit
33142
+ audit --schedule [days] Audit on a timer (default 7 days) and email you
33143
+ what it finds. Signs you in the first time;
33144
+ --email <address> skips that question
33145
+ audit --no-schedule Stop auditing on a timer
33146
+ audit --status Whether scheduling is on, where reports go, and
33147
+ when the next scan is due
31685
33148
  audit --help, -h Show this help for the audit command
31686
33149
 
31687
33150
  backfill Re-send history the collector already read past
@@ -32069,8 +33532,8 @@ Run \`failproofai migrate --help\` for usage.`);
32069
33532
  return;
32070
33533
  }
32071
33534
  const run = runMigrations3(from);
32072
- for (const step of run.steps) {
32073
- console.log(`${step.ok ? "migrated" : "FAILED "} layout ${step.from} \u2192 ${step.to}`);
33535
+ for (const step3 of run.steps) {
33536
+ console.log(`${step3.ok ? "migrated" : "FAILED "} layout ${step3.from} \u2192 ${step3.to}`);
32074
33537
  }
32075
33538
  if (run.backedUp.length > 0) {
32076
33539
  console.log(`Saved first: ${run.backedUp.join(", ")}`);
@@ -32140,8 +33603,8 @@ Run \`failproofai update --help\` for usage.`);
32140
33603
  const run = runMigrations3(state.found);
32141
33604
  migrationsRan = run.steps.length;
32142
33605
  migrationFailed = Boolean(run.failed);
32143
- for (const step of run.steps) {
32144
- console.log(`${step.ok ? "migrated" : "FAILED "} layout ${step.from} \u2192 ${step.to}`);
33606
+ for (const step3 of run.steps) {
33607
+ console.log(`${step3.ok ? "migrated" : "FAILED "} layout ${step3.from} \u2192 ${step3.to}`);
32145
33608
  }
32146
33609
  if (run.backedUp.length > 0)
32147
33610
  console.log(`Saved first: ${run.backedUp.join(", ")}`);
@@ -32678,14 +34141,14 @@ PAUSING ENFORCEMENT (one session, always time-boxed)
32678
34141
  const { runDisconnectCommand: runDisconnectCommand2 } = await Promise.resolve().then(() => (init_cloud_enrollment_cli(), exports_cloud_enrollment_cli));
32679
34142
  result2 = runDisconnectCommand2();
32680
34143
  } else {
32681
- const { hostname: hostname6 } = await import("os");
34144
+ const { hostname: hostname7 } = await import("os");
32682
34145
  const { runConnectCommand: runConnectCommand2 } = await Promise.resolve().then(() => (init_cloud_enrollment_cli(), exports_cloud_enrollment_cli));
32683
34146
  result2 = await runConnectCommand2({
32684
34147
  url: valueAfter("--connect"),
32685
34148
  token: valueAfter("--token"),
32686
34149
  machineId: valueAfter("--machine-id"),
32687
34150
  machineLabel: valueAfter("--machine-label"),
32688
- defaultMachineId: hostname6(),
34151
+ defaultMachineId: hostname7(),
32689
34152
  sessions: !args.includes("--no-transcripts")
32690
34153
  });
32691
34154
  }