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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (368) hide show
  1. package/.next/standalone/.next/BUILD_ID +1 -1
  2. package/.next/standalone/.next/app-path-routes-manifest.json +2 -1
  3. package/.next/standalone/.next/build-manifest.json +3 -3
  4. package/.next/standalone/.next/prerender-manifest.json +3 -3
  5. package/.next/standalone/.next/required-server-files.json +1 -1
  6. package/.next/standalone/.next/routes-manifest.json +6 -0
  7. package/.next/standalone/.next/server/app/_global-error/page/server-reference-manifest.json +1 -1
  8. package/.next/standalone/.next/server/app/_global-error/page.js +3 -1
  9. package/.next/standalone/.next/server/app/_global-error/page.js.nft.json +1 -1
  10. package/.next/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  11. package/.next/standalone/.next/server/app/_global-error.html +1 -1
  12. package/.next/standalone/.next/server/app/_global-error.rsc +7 -7
  13. package/.next/standalone/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +2 -2
  14. package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +7 -7
  15. package/.next/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +3 -3
  16. package/.next/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +3 -3
  17. package/.next/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  18. package/.next/standalone/.next/server/app/_not-found/page/server-reference-manifest.json +1 -1
  19. package/.next/standalone/.next/server/app/_not-found/page.js +3 -1
  20. package/.next/standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
  21. package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  22. package/.next/standalone/.next/server/app/_not-found.html +1 -1
  23. package/.next/standalone/.next/server/app/_not-found.rsc +15 -15
  24. package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +15 -15
  25. package/.next/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +4 -4
  26. package/.next/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +10 -10
  27. package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +2 -2
  28. package/.next/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +3 -3
  29. package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  30. package/.next/standalone/.next/server/app/api/audit/invite/route.js +3 -2
  31. package/.next/standalone/.next/server/app/api/audit/invite/route.js.nft.json +1 -1
  32. package/.next/standalone/.next/server/app/api/audit/run/route.js +4 -3
  33. package/.next/standalone/.next/server/app/api/audit/run/route.js.nft.json +1 -1
  34. package/.next/standalone/.next/server/app/api/audit/status/route.js +1 -1
  35. package/.next/standalone/.next/server/app/api/audit/status/route.js.nft.json +1 -1
  36. package/.next/standalone/.next/server/app/api/auth/login-request/route.js +2 -1
  37. package/.next/standalone/.next/server/app/api/auth/login-request/route.js.nft.json +1 -1
  38. package/.next/standalone/.next/server/app/api/auth/login-verify/route.js +3 -2
  39. package/.next/standalone/.next/server/app/api/auth/login-verify/route.js.nft.json +1 -1
  40. package/.next/standalone/.next/server/app/api/auth/logout/route.js +3 -2
  41. package/.next/standalone/.next/server/app/api/auth/logout/route.js.nft.json +1 -1
  42. package/.next/standalone/.next/server/app/api/auth/reminder/route.js +3 -2
  43. package/.next/standalone/.next/server/app/api/auth/reminder/route.js.nft.json +1 -1
  44. package/.next/standalone/.next/server/app/api/auth/status/route.js +3 -2
  45. package/.next/standalone/.next/server/app/api/auth/status/route.js.nft.json +1 -1
  46. package/.next/standalone/.next/server/app/api/download/[project]/[session]/route.js +1 -1
  47. package/.next/standalone/.next/server/app/api/download/[project]/[session]/route.js.nft.json +1 -1
  48. package/.next/standalone/.next/server/app/audit/page/server-reference-manifest.json +2 -2
  49. package/.next/standalone/.next/server/app/audit/page.js +5 -3
  50. package/.next/standalone/.next/server/app/audit/page.js.nft.json +1 -1
  51. package/.next/standalone/.next/server/app/audit/page_client-reference-manifest.js +1 -1
  52. package/.next/standalone/.next/server/app/index.html +1 -1
  53. package/.next/standalone/.next/server/app/index.rsc +15 -15
  54. package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  55. package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +15 -15
  56. package/.next/standalone/.next/server/app/index.segments/_head.segment.rsc +4 -4
  57. package/.next/standalone/.next/server/app/index.segments/_index.segment.rsc +10 -10
  58. package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -2
  59. package/.next/standalone/.next/server/app/page/server-reference-manifest.json +1 -1
  60. package/.next/standalone/.next/server/app/page.js +3 -1
  61. package/.next/standalone/.next/server/app/page.js.nft.json +1 -1
  62. package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  63. package/.next/standalone/.next/server/app/policies/page/server-reference-manifest.json +10 -10
  64. package/.next/standalone/.next/server/app/policies/page.js +4 -2
  65. package/.next/standalone/.next/server/app/policies/page.js.nft.json +1 -1
  66. package/.next/standalone/.next/server/app/policies/page_client-reference-manifest.js +1 -1
  67. package/.next/standalone/.next/server/app/project/[name]/page/server-reference-manifest.json +1 -1
  68. package/.next/standalone/.next/server/app/project/[name]/page.js +4 -2
  69. package/.next/standalone/.next/server/app/project/[name]/page.js.nft.json +1 -1
  70. package/.next/standalone/.next/server/app/project/[name]/page_client-reference-manifest.js +1 -1
  71. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/react-loadable-manifest.json +2 -2
  72. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/server-reference-manifest.json +2 -2
  73. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page.js +6 -4
  74. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page.js.nft.json +1 -1
  75. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page_client-reference-manifest.js +1 -1
  76. package/.next/standalone/.next/server/app/projects/page/server-reference-manifest.json +1 -1
  77. package/.next/standalone/.next/server/app/projects/page.js +4 -2
  78. package/.next/standalone/.next/server/app/projects/page.js.nft.json +1 -1
  79. package/.next/standalone/.next/server/app/projects/page_client-reference-manifest.js +1 -1
  80. package/.next/standalone/.next/server/app/settings/page/app-paths-manifest.json +3 -0
  81. package/.next/standalone/.next/server/app/settings/page/build-manifest.json +18 -0
  82. package/.next/standalone/.next/server/app/settings/page/next-font-manifest.json +6 -0
  83. package/.next/standalone/.next/server/app/settings/page/react-loadable-manifest.json +1 -0
  84. package/.next/standalone/.next/server/app/settings/page/server-reference-manifest.json +53 -0
  85. package/.next/standalone/.next/server/app/settings/page.js +18 -0
  86. package/.next/standalone/.next/server/app/settings/page.js.map +5 -0
  87. package/.next/standalone/.next/server/app/settings/page.js.nft.json +1 -0
  88. package/.next/standalone/.next/server/app/settings/page_client-reference-manifest.js +3 -0
  89. package/.next/standalone/.next/server/app-paths-manifest.json +2 -1
  90. package/.next/standalone/.next/server/chunks/{[externals]__1nl3dvw._.js → [externals]__0r-zamh._.js} +2 -2
  91. package/.next/standalone/.next/server/chunks/[root-of-the-server]__06hexd0._.js +3 -0
  92. package/.next/standalone/.next/server/chunks/[root-of-the-server]__094p1f1._.js +3 -0
  93. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0_0xu5z._.js +1 -1
  94. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0ed01_d._.js +3 -0
  95. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0g0vcwt._.js +3 -0
  96. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0h3lfmp._.js → [root-of-the-server]__0ky_n0r._.js} +2 -2
  97. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__18d-9oi._.js → [root-of-the-server]__0lk_935._.js} +2 -2
  98. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__1p7s8-d._.js → [root-of-the-server]__0pbp9fe._.js} +2 -2
  99. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0q-v9z2._.js +1 -1
  100. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__10oa-v9._.js → [root-of-the-server]__0v2fpxe._.js} +2 -2
  101. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0sb_5m8._.js → [root-of-the-server]__131ebum._.js} +3 -3
  102. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0-dh5jy._.js → [root-of-the-server]__1_ps0jw._.js} +2 -2
  103. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0l4vuqm._.js → [root-of-the-server]__1a7i2q4._.js} +1 -1
  104. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1ibjy5x._.js +3 -0
  105. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1iny24d._.js +3 -0
  106. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1tvn4wf._.js +1 -1
  107. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1tyedjt._.js +3 -0
  108. package/.next/standalone/.next/server/chunks/_0lxbzdq._.js +5 -0
  109. package/.next/standalone/.next/server/chunks/_1zuiiy3._.js +5 -0
  110. package/.next/standalone/.next/server/chunks/lib_telemetry_ts_0dctyyw._.js +5 -0
  111. package/.next/standalone/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_17k9e3w.js +5 -5
  112. package/.next/standalone/.next/server/chunks/package_json_[json]_cjs_1nxcc4v._.js +1 -1
  113. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__06bp_fg._.js +5 -0
  114. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__074qmkp._.js +3 -0
  115. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0c_qcgp._.js +3 -0
  116. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0kbc9bs._.js +3 -0
  117. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0spkm68._.js +10 -10
  118. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1a2hcb_._.js +3 -0
  119. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0rtdfof._.js → [root-of-the-server]__1rdruw4._.js} +1 -1
  120. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1rv-sc9._.js +3 -0
  121. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1tyf0tc._.js +5 -0
  122. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1u-wx42._.js +4 -0
  123. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1v185mo._.js +3 -0
  124. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0rag5dg._.js → [root-of-the-server]__1yw368c._.js} +2 -2
  125. package/.next/standalone/.next/server/chunks/ssr/_0-yi74u._.js +3 -0
  126. package/.next/standalone/.next/server/chunks/ssr/_04mekdy._.js +3 -0
  127. package/.next/standalone/.next/server/chunks/ssr/_0r-dsre._.js +3 -0
  128. package/.next/standalone/.next/server/chunks/ssr/_0rjgfln._.js +3 -0
  129. package/.next/standalone/.next/server/chunks/ssr/_0se484m._.js +3 -0
  130. package/.next/standalone/.next/server/chunks/ssr/_0uz7o9y._.js +3 -0
  131. package/.next/standalone/.next/server/chunks/ssr/_11_p9y8._.js +1 -1
  132. package/.next/standalone/.next/server/chunks/ssr/_194yh9u._.js +3 -0
  133. package/.next/standalone/.next/server/chunks/ssr/_1fahg9e._.js +3 -0
  134. package/.next/standalone/.next/server/chunks/ssr/_1gmzkwj._.js +5 -0
  135. package/.next/standalone/.next/server/chunks/ssr/_1w8sola._.js +3 -0
  136. package/.next/standalone/.next/server/chunks/ssr/_1w_6p9g._.js +3 -0
  137. package/.next/standalone/.next/server/chunks/ssr/app_audit__components_audit-dashboard_tsx_0p9ud47._.js +2 -2
  138. package/.next/standalone/.next/server/chunks/ssr/app_global-error_tsx_1kp6l3x._.js +1 -1
  139. package/.next/standalone/.next/server/chunks/ssr/app_policies_hooks-client_tsx_19dqvpc._.js +2 -2
  140. package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0dwo94s.js +4 -0
  141. package/.next/standalone/.next/server/chunks/ssr/src_hooks_builtin-policies_ts_09j2ndl._.js +3 -0
  142. package/.next/standalone/.next/server/chunks/ssr/src_hooks_fp-config_ts_04t589g._.js +5 -0
  143. package/.next/standalone/.next/server/middleware-build-manifest.js +3 -3
  144. package/.next/standalone/.next/server/middleware.js +2 -2
  145. package/.next/standalone/.next/server/pages/404.html +1 -1
  146. package/.next/standalone/.next/server/pages/500.html +1 -1
  147. package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
  148. package/.next/standalone/.next/server/server-reference-manifest.json +54 -12
  149. package/.next/standalone/.next/static/chunks/0945ybz3fsvba.js +1 -0
  150. package/.next/standalone/.next/static/chunks/{0cr85wuc9gc9k.js → 0gr76ps8_zm26.js} +1 -1
  151. package/.next/standalone/.next/static/chunks/{2cqk4a9s893oy.js → 0m-m7wgtxdoav.js} +1 -1
  152. package/.next/standalone/.next/static/chunks/{1tp9dex23zs8y.js → 11l6oh9cyb35a.js} +1 -1
  153. package/.next/standalone/.next/static/chunks/166f8qnh03jqc.js +6 -0
  154. package/.next/standalone/.next/static/chunks/1bm0q12hgs22l.css +2 -0
  155. package/.next/standalone/.next/static/chunks/1v1gqvpjk62jm.js +1 -0
  156. package/.next/standalone/.next/static/chunks/{2s9g1dsde_ts1.js → 2aej0vi1fm87m.js} +1 -1
  157. package/.next/standalone/.next/static/chunks/{1bkynffp3q1f7.js → 2bxld6-rym3ah.js} +22 -22
  158. package/.next/standalone/.next/static/chunks/{2v1rpzrh2i1wv.js → 2p2kz4aj1tooj.js} +1 -1
  159. package/.next/standalone/.next/static/chunks/2uvhw57mf9lg_.css +2 -0
  160. package/.next/standalone/.next/static/chunks/36pc3_8fpb6ic.js +1 -0
  161. package/.next/standalone/.next/static/chunks/{2k285z07qce47.js → 3t1wr_kx6brwc.js} +1 -1
  162. package/.next/standalone/app/actions/get-hooks-config.ts +2 -1
  163. package/.next/standalone/app/actions/get-scheduled-audit.ts +70 -0
  164. package/.next/standalone/app/actions/update-scheduled-audit.ts +44 -0
  165. package/.next/standalone/app/api/audit/run/route.ts +28 -0
  166. package/.next/standalone/app/api/audit/status/route.ts +13 -1
  167. package/.next/standalone/app/api/auth/status/route.ts +1 -1
  168. package/.next/standalone/app/audit/_components/auth-dialog.css +159 -0
  169. package/.next/standalone/app/audit/_components/auth-dialog.tsx +3 -0
  170. package/.next/standalone/app/audit/audit-styles.css +6 -149
  171. package/.next/standalone/app/settings/page.tsx +31 -0
  172. package/.next/standalone/app/settings/settings-client.tsx +488 -0
  173. package/.next/standalone/components/navbar.tsx +2 -0
  174. package/.next/standalone/lib/auth/api-server-client.ts +2 -3
  175. package/.next/standalone/lib/auth/auth-store.ts +4 -4
  176. package/.next/standalone/lib/codex-sessions.ts +2 -1
  177. package/.next/standalone/lib/dashboard-host.ts +101 -0
  178. package/.next/standalone/lib/install-check.ts +22 -7
  179. package/.next/standalone/lib/pi-sessions.ts +99 -14
  180. package/.next/standalone/lib/telemetry-enabled.ts +54 -0
  181. package/.next/standalone/lib/telemetry-id.ts +52 -1
  182. package/.next/standalone/lib/telemetry.ts +8 -4
  183. package/.next/standalone/node_modules/react/cjs/react.development.js +1 -1
  184. package/.next/standalone/node_modules/react/cjs/react.production.js +1 -1
  185. package/.next/standalone/node_modules/react/package.json +3 -3
  186. package/.next/standalone/node_modules/react-dom/cjs/react-dom-server-legacy.browser.production.js +1 -1
  187. package/.next/standalone/node_modules/react-dom/cjs/react-dom-server-legacy.node.production.js +1 -1
  188. package/.next/standalone/node_modules/react-dom/cjs/react-dom-server.browser.production.js +3 -3
  189. package/.next/standalone/node_modules/react-dom/cjs/react-dom-server.edge.production.js +3 -3
  190. package/.next/standalone/node_modules/react-dom/cjs/react-dom-server.node.production.js +3 -3
  191. package/.next/standalone/node_modules/react-dom/cjs/react-dom.production.js +1 -1
  192. package/.next/standalone/node_modules/react-dom/package.json +4 -4
  193. package/.next/standalone/package.json +7 -6
  194. package/.next/standalone/proxy.ts +89 -1
  195. package/.next/standalone/server.js +1 -1
  196. package/bin/failproofai.mjs +202 -86
  197. package/dist/cli.mjs +17803 -15346
  198. package/dist/worker.mjs +1620 -257
  199. package/lib/auth/api-server-client.ts +2 -3
  200. package/lib/auth/auth-store.ts +4 -4
  201. package/lib/codex-sessions.ts +2 -1
  202. package/lib/dashboard-host.ts +101 -0
  203. package/lib/install-check.ts +22 -7
  204. package/lib/pi-sessions.ts +99 -14
  205. package/lib/telemetry-enabled.ts +54 -0
  206. package/lib/telemetry-id.ts +52 -1
  207. package/lib/telemetry.ts +8 -4
  208. package/package.json +7 -6
  209. package/scripts/install-telemetry.mjs +8 -1
  210. package/scripts/launch.ts +25 -3
  211. package/scripts/parse-script-args.ts +17 -1
  212. package/scripts/prune-standalone.mjs +20 -0
  213. package/scripts/translate-docs/readme-translator.ts +163 -4
  214. package/scripts/validate-mdx.ts +153 -13
  215. package/src/audit/audit-lock.ts +285 -0
  216. package/src/audit/audit-schedule.ts +111 -0
  217. package/src/audit/cache.ts +18 -4
  218. package/src/audit/cli-adapters/goose.ts +2 -1
  219. package/src/audit/cli-adapters/hermes.ts +28 -10
  220. package/src/audit/cli.ts +191 -35
  221. package/src/audit/dashboard-cache.ts +2 -1
  222. package/src/hooks/builtin-policies.ts +100 -3
  223. package/src/hooks/cloud-connection.ts +160 -14
  224. package/src/hooks/cloud-enrollment-cli.ts +119 -21
  225. package/src/hooks/cloud-enrollment.ts +87 -17
  226. package/src/hooks/cloud-introspect.ts +147 -0
  227. package/src/hooks/cloud-managed-policies.ts +33 -2
  228. package/src/hooks/collector-config.ts +25 -43
  229. package/src/hooks/configure-wizard.ts +750 -318
  230. package/src/hooks/custom-hooks-loader.ts +125 -11
  231. package/src/hooks/daemon-client.ts +83 -17
  232. package/src/hooks/daemon-download.ts +54 -2
  233. package/src/hooks/daemon-service.ts +605 -29
  234. package/src/hooks/first-run-gate.ts +39 -0
  235. package/src/hooks/fp-config.ts +497 -0
  236. package/src/hooks/fp-home.ts +355 -0
  237. package/src/hooks/fp-reset.ts +332 -0
  238. package/src/hooks/handler.ts +42 -1
  239. package/src/hooks/hook-activity-store.ts +35 -20
  240. package/src/hooks/hook-logger.ts +2 -1
  241. package/src/hooks/hook-telemetry.ts +5 -1
  242. package/src/hooks/hooks-config.ts +4 -3
  243. package/src/hooks/loader-utils.ts +166 -5
  244. package/src/hooks/manager.ts +5 -4
  245. package/src/hooks/onboarding-attempt.ts +179 -0
  246. package/src/hooks/onboarding-lock.ts +119 -0
  247. package/src/hooks/policy-types.ts +0 -7
  248. package/src/hooks/session-pause-cli.ts +15 -13
  249. package/src/hooks/session-pause.ts +36 -4
  250. package/src/hooks/setup-state.ts +256 -0
  251. package/src/hooks/tui.ts +4 -4
  252. package/src/hooks/worker-server.ts +53 -1
  253. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0f8nu8d._.js +0 -3
  254. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0szqzl8._.js +0 -3
  255. package/.next/standalone/.next/server/chunks/[root-of-the-server]__17g9wh7._.js +0 -3
  256. package/.next/standalone/.next/server/chunks/[root-of-the-server]__19120tr._.js +0 -3
  257. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1fwl2mz._.js +0 -3
  258. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1myjm-d._.js +0 -3
  259. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1rhmvod._.js +0 -3
  260. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__02r5bgf._.js +0 -4
  261. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__094nop3._.js +0 -3
  262. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0e8sjqm._.js +0 -4
  263. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0lkzqax._.js +0 -4
  264. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0ls0gsr._.js +0 -4
  265. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0n_uvv0._.js +0 -3
  266. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0qucxyj._.js +0 -4
  267. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0u02miy._.js +0 -4
  268. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__14dd6h8._.js +0 -3
  269. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1gak4pd._.js +0 -3
  270. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1j4u3yd._.js +0 -4
  271. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1zqz4v8._.js +0 -4
  272. package/.next/standalone/.next/server/chunks/ssr/_1m_p7pi._.js +0 -3
  273. package/.next/standalone/.next/server/chunks/ssr/node_modules_html-to-image_es_index_12c_2cz.js +0 -3
  274. package/.next/standalone/.next/server/chunks/ssr/src_hooks_1ezd2jf._.js +0 -5
  275. package/.next/standalone/.next/server/chunks/ssr/src_hooks_1tnuifj._.js +0 -5
  276. package/.next/standalone/.next/static/chunks/0h7auy7hzjyhw.js +0 -1
  277. package/.next/standalone/.next/static/chunks/1bw4dfzflelcv.js +0 -1
  278. package/.next/standalone/.next/static/chunks/34sjdw8lv46e3.js +0 -6
  279. package/.next/standalone/.next/static/chunks/3i27c3hcriawq.css +0 -1
  280. package/.next/standalone/.next/static/chunks/3zdwnnthucs_1.css +0 -2
  281. package/.next/standalone/Cargo.lock +0 -2222
  282. package/.next/standalone/Cargo.toml +0 -9
  283. package/.next/standalone/crates/CLOUD_POLICIES.md +0 -136
  284. package/.next/standalone/crates/PROTOCOL.md +0 -122
  285. package/.next/standalone/crates/failproofaid/Cargo.toml +0 -25
  286. package/.next/standalone/crates/failproofaid/src/cloud_client.rs +0 -484
  287. package/.next/standalone/crates/failproofaid/src/cloud_policies.rs +0 -921
  288. package/.next/standalone/crates/failproofaid/src/lock.rs +0 -81
  289. package/.next/standalone/crates/failproofaid/src/main.rs +0 -639
  290. package/.next/standalone/crates/failproofaid/src/paths.rs +0 -201
  291. package/.next/standalone/crates/failproofaid/src/server.rs +0 -502
  292. package/.next/standalone/crates/failproofaid/src/worker.rs +0 -400
  293. package/.next/standalone/crates/failproofaid/tests/daemon_e2e.rs +0 -241
  294. package/.next/standalone/crates/fpai-collect/Cargo.toml +0 -43
  295. package/.next/standalone/crates/fpai-collect/src/config.rs +0 -420
  296. package/.next/standalone/crates/fpai-collect/src/cursor.rs +0 -520
  297. package/.next/standalone/crates/fpai-collect/src/delivery.rs +0 -472
  298. package/.next/standalone/crates/fpai-collect/src/filetail.rs +0 -487
  299. package/.next/standalone/crates/fpai-collect/src/health.rs +0 -369
  300. package/.next/standalone/crates/fpai-collect/src/lib.rs +0 -34
  301. package/.next/standalone/crates/fpai-collect/src/redact.rs +0 -516
  302. package/.next/standalone/crates/fpai-collect/src/sources/claude/mod.rs +0 -279
  303. package/.next/standalone/crates/fpai-collect/src/sources/claude/transform.rs +0 -619
  304. package/.next/standalone/crates/fpai-collect/src/sources/codex/mod.rs +0 -156
  305. package/.next/standalone/crates/fpai-collect/src/sources/codex/transform.rs +0 -715
  306. package/.next/standalone/crates/fpai-collect/src/sources/copilot/mod.rs +0 -158
  307. package/.next/standalone/crates/fpai-collect/src/sources/copilot/transform.rs +0 -512
  308. package/.next/standalone/crates/fpai-collect/src/sources/goose/mod.rs +0 -511
  309. package/.next/standalone/crates/fpai-collect/src/sources/goose/transform.rs +0 -586
  310. package/.next/standalone/crates/fpai-collect/src/sources/hermes/mod.rs +0 -318
  311. package/.next/standalone/crates/fpai-collect/src/sources/hermes/transform.rs +0 -579
  312. package/.next/standalone/crates/fpai-collect/src/sources/hooks/mod.rs +0 -314
  313. package/.next/standalone/crates/fpai-collect/src/sources/hooks/transform.rs +0 -448
  314. package/.next/standalone/crates/fpai-collect/src/sources/mod.rs +0 -23
  315. package/.next/standalone/crates/fpai-collect/src/sources/openclaw/mod.rs +0 -176
  316. package/.next/standalone/crates/fpai-collect/src/sources/openclaw/transform.rs +0 -500
  317. package/.next/standalone/crates/fpai-collect/src/sources/opencode/mod.rs +0 -315
  318. package/.next/standalone/crates/fpai-collect/src/sources/opencode/transform.rs +0 -493
  319. package/.next/standalone/crates/fpai-collect/src/sources/pi/mod.rs +0 -201
  320. package/.next/standalone/crates/fpai-collect/src/sources/pi/transform.rs +0 -533
  321. package/.next/standalone/crates/fpai-collect/src/spool.rs +0 -535
  322. package/.next/standalone/crates/fpai-collect/src/sqlitepoll.rs +0 -390
  323. package/.next/standalone/crates/fpai-collect/src/supervisor.rs +0 -423
  324. package/.next/standalone/crates/fpai-collect/src/uploader.rs +0 -600
  325. package/.next/standalone/crates/fpai-collect/tests/claude_source.rs +0 -739
  326. package/.next/standalone/crates/fpai-collect/tests/claude_subagents.rs +0 -394
  327. package/.next/standalone/crates/fpai-collect/tests/codex_source.rs +0 -976
  328. package/.next/standalone/crates/fpai-collect/tests/config.rs +0 -286
  329. package/.next/standalone/crates/fpai-collect/tests/copilot_source.rs +0 -1020
  330. package/.next/standalone/crates/fpai-collect/tests/delivery.rs +0 -281
  331. package/.next/standalone/crates/fpai-collect/tests/goose_source.rs +0 -1009
  332. package/.next/standalone/crates/fpai-collect/tests/hermes_source.rs +0 -1130
  333. package/.next/standalone/crates/fpai-collect/tests/hooks_source.rs +0 -622
  334. package/.next/standalone/crates/fpai-collect/tests/openclaw_source.rs +0 -855
  335. package/.next/standalone/crates/fpai-collect/tests/opencode_source.rs +0 -1478
  336. package/.next/standalone/crates/fpai-collect/tests/pi_source.rs +0 -1192
  337. package/.next/standalone/crates/fpai-collect/tests/supervisor.rs +0 -290
  338. package/.next/standalone/crates/fpai-collect/tests/uploader.rs +0 -506
  339. package/.next/standalone/crates/fpai-ipc/Cargo.toml +0 -16
  340. package/.next/standalone/crates/fpai-ipc/src/envelope.rs +0 -175
  341. package/.next/standalone/crates/fpai-ipc/src/framing.rs +0 -177
  342. package/.next/standalone/crates/fpai-ipc/src/lib.rs +0 -10
  343. package/.next/standalone/crates/fpai-ipc/src/peer.rs +0 -80
  344. package/.next/standalone/docker-hook-sync/Dockerfile +0 -79
  345. package/.next/standalone/docker-hook-sync/entrypoint.sh +0 -109
  346. package/.next/standalone/integration-suite/Dockerfile +0 -47
  347. package/.next/standalone/integration-suite/README.md +0 -129
  348. package/.next/standalone/integration-suite/canary-policies.mjs +0 -45
  349. package/.next/standalone/integration-suite/capture-tokens.sh +0 -48
  350. package/.next/standalone/integration-suite/ci-entrypoint.sh +0 -179
  351. package/.next/standalone/integration-suite/inject-tokens.sh +0 -44
  352. package/.next/standalone/integration-suite/install-clis.sh +0 -136
  353. package/.next/standalone/integration-suite/probe-cli.sh +0 -248
  354. package/.next/standalone/integration-suite/report.js +0 -120
  355. package/.next/standalone/integration-suite/run.sh +0 -159
  356. package/.next/standalone/openclaw-plugin/index.js +0 -223
  357. package/.next/standalone/openclaw-plugin/openclaw.plugin.json +0 -6
  358. package/.next/standalone/openclaw-plugin/package.json +0 -12
  359. package/.next/standalone/osv-scanner.toml +0 -17
  360. package/.next/standalone/pi-extension/index.ts +0 -524
  361. package/.next/standalone/pi-extension/package.json +0 -12
  362. package/.next/standalone/postcss.config.mjs +0 -8
  363. package/.next/standalone/readme-arch-hq.gif +0 -0
  364. package/.next/standalone/rust-toolchain.toml +0 -4
  365. package/src/auth/cli.ts +0 -371
  366. /package/.next/standalone/.next/static/{LOuwMmfomO6hQYfMQYs4K → LUaLkKg40nSkHrIajexIk}/_buildManifest.js +0 -0
  367. /package/.next/standalone/.next/static/{LOuwMmfomO6hQYfMQYs4K → LUaLkKg40nSkHrIajexIk}/_clientMiddlewareManifest.js +0 -0
  368. /package/.next/standalone/.next/static/{LOuwMmfomO6hQYfMQYs4K → LUaLkKg40nSkHrIajexIk}/_ssgManifest.js +0 -0
@@ -0,0 +1,179 @@
1
+ /**
2
+ * Why the last first-run setup stopped, and whether it is worth offering again.
3
+ *
4
+ * # The problem this exists for
5
+ *
6
+ * Setup is deliberately all-or-nothing: every abort path writes NOTHING, so a
7
+ * machine that could not be configured is left exactly as it was found rather
8
+ * than carrying half a configuration (a `daemonConfigured` flag with no daemon
9
+ * behind it denies every tool call across all twelve CLIs). That invariant is
10
+ * right and is not changed here.
11
+ *
12
+ * But it left onboarding with no memory. `isConfigured()` reads three signals —
13
+ * a global policy config, live user-scope hooks, the legacy marker — and an
14
+ * abort sets none of them, so "never tried" and "tried twenty times and could
15
+ * not finish" are indistinguishable. On a machine without passwordless sudo,
16
+ * every single command relaunched the whole wizard, forever.
17
+ *
18
+ * # What this is NOT
19
+ *
20
+ * Not a fourth "configured" signal. Nothing here may make `isConfigured()` true.
21
+ * A machine that failed setup is unconfigured and must keep saying so — to the
22
+ * hook path, to `--status`, and to the wizard when it is asked for by name.
23
+ * This only changes whether the wizard is *offered unprompted*.
24
+ *
25
+ * # Re-offering
26
+ *
27
+ * A hint that never becomes an offer again is its own failure: the common case
28
+ * is someone who hits the sudo prompt, gives up, and comes back later able to
29
+ * elevate. So each reason carries a cheap local check for whether its blocker
30
+ * is gone, and the wizard offers itself again the moment one is:
31
+ *
32
+ * needs_root -> elevation is now possible without a prompt
33
+ * daemon_failed -> the service manager now reports something different
34
+ * cancelled -> the CLI version changed; an upgrade is a fair moment to
35
+ * ask again, and nothing else about a deliberate cancel
36
+ * should re-nag
37
+ *
38
+ * Every probe is local and takes milliseconds. None of them runs on the hook
39
+ * path — `--hook` never reaches the first-run gate at all.
40
+ */
41
+ import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
42
+ import { dirname } from "node:path";
43
+ import { onboardingAttemptFile } from "./fp-home";
44
+ import type { WizardAbort } from "./configure-wizard";
45
+
46
+ /** Bumped only for a deliberate shape change; an unreadable record is ignored. */
47
+ const SCHEMA_VERSION = 1;
48
+
49
+ export interface OnboardingAttempt {
50
+ schemaVersion: number;
51
+ /** Why the wizard stopped. */
52
+ reason: WizardAbort;
53
+ /** The CLI that made the attempt, so an upgrade can re-offer. */
54
+ cliVersion: string;
55
+ /**
56
+ * What the service manager said at the time. Compared, never trusted — the
57
+ * point is only whether it has CHANGED since.
58
+ */
59
+ daemonStatus: string;
60
+ /** Epoch ms, for support and for nothing else. */
61
+ at: number;
62
+ }
63
+
64
+ export function readOnboardingAttempt(): OnboardingAttempt | null {
65
+ const path = onboardingAttemptFile();
66
+ if (!existsSync(path)) return null;
67
+ try {
68
+ const raw = JSON.parse(readFileSync(path, "utf8")) as Partial<OnboardingAttempt>;
69
+ if (raw.schemaVersion !== SCHEMA_VERSION) return null;
70
+ if (typeof raw.reason !== "string" || typeof raw.cliVersion !== "string") return null;
71
+ return {
72
+ schemaVersion: SCHEMA_VERSION,
73
+ reason: raw.reason as WizardAbort,
74
+ cliVersion: raw.cliVersion,
75
+ daemonStatus: typeof raw.daemonStatus === "string" ? raw.daemonStatus : "",
76
+ at: typeof raw.at === "number" ? raw.at : 0,
77
+ };
78
+ } catch {
79
+ // A corrupt record reads as "no record", which degrades to today's
80
+ // behaviour — offering the wizard. Never to "configured".
81
+ return null;
82
+ }
83
+ }
84
+
85
+ /** Best-effort: a machine that cannot record this simply keeps being offered. */
86
+ export function recordOnboardingAttempt(
87
+ reason: WizardAbort,
88
+ cliVersion: string,
89
+ daemonStatus: string,
90
+ now: number = Date.now(),
91
+ ): void {
92
+ try {
93
+ const path = onboardingAttemptFile();
94
+ mkdirSync(dirname(path), { recursive: true });
95
+ const record: OnboardingAttempt = {
96
+ schemaVersion: SCHEMA_VERSION,
97
+ reason,
98
+ cliVersion,
99
+ daemonStatus,
100
+ at: now,
101
+ };
102
+ writeFileSync(path, JSON.stringify(record, null, 2), "utf8");
103
+ } catch {
104
+ // best-effort
105
+ }
106
+ }
107
+
108
+ /**
109
+ * Called on a completed apply. A stale record would keep suppressing the offer
110
+ * on a machine that has since been reconfigured by hand and un-configured again.
111
+ */
112
+ export function clearOnboardingAttempt(): void {
113
+ try {
114
+ rmSync(onboardingAttemptFile(), { force: true });
115
+ } catch {
116
+ // best-effort
117
+ }
118
+ }
119
+
120
+ export interface RetryProbe {
121
+ /** Elevation is possible without prompting. */
122
+ canElevate: () => boolean;
123
+ /** What the service manager says right now. */
124
+ daemonStatus: () => string;
125
+ /** This CLI's version. */
126
+ cliVersion: string;
127
+ }
128
+
129
+ /**
130
+ * Whether the thing that stopped setup last time has since changed.
131
+ *
132
+ * `true` means offer the wizard again; `false` means a one-line hint. An
133
+ * unrecognised reason returns `true` — an unknown blocker is one we cannot
134
+ * prove is still present, and the safe direction is offering setup rather than
135
+ * silently withholding it.
136
+ */
137
+ export function blockerCleared(attempt: OnboardingAttempt, probe: RetryProbe): boolean {
138
+ switch (attempt.reason) {
139
+ case "needs_root":
140
+ return probe.canElevate();
141
+ case "daemon_failed":
142
+ // Any movement at all: not-installed -> stopped, stopped -> running, or a
143
+ // platform that has gained a service manager. Comparing rather than
144
+ // demanding "running" is what lets a partially-repaired machine be
145
+ // offered setup again instead of waiting for a state it cannot reach on
146
+ // its own.
147
+ return probe.daemonStatus() !== attempt.daemonStatus || probe.canElevate();
148
+ case "cancelled":
149
+ // A deliberate stop. Re-asking on the next command is exactly the nagging
150
+ // this module removes — but an upgrade is a new thing to say, so it is
151
+ // allowed to ask once more.
152
+ return probe.cliVersion !== attempt.cliVersion;
153
+ case "not_a_tty":
154
+ case "running_as_sudo":
155
+ // Both are properties of the invocation, not of the machine, so the next
156
+ // one may well be fine.
157
+ return true;
158
+ default:
159
+ return true;
160
+ }
161
+ }
162
+
163
+ /** The one line shown instead of relaunching the wizard. */
164
+ export function attemptHintLines(attempt: OnboardingAttempt): string[] {
165
+ const why: Record<string, string> = {
166
+ needs_root: "it needs root to install the failproofaid service",
167
+ daemon_failed: "the failproofaid service could not be started",
168
+ cancelled: "it was cancelled",
169
+ not_a_tty: "there was no terminal to ask in",
170
+ running_as_sudo: "it was run under sudo",
171
+ };
172
+ const detail = why[attempt.reason] ?? "it did not finish";
173
+ return [
174
+ ``,
175
+ `[failproofai] Setup is not finished — ${detail}.`,
176
+ ` Run \`failproofai config\` when you are ready.`,
177
+ ``,
178
+ ];
179
+ }
@@ -0,0 +1,119 @@
1
+ /**
2
+ * A single-holder guard around first-run onboarding.
3
+ *
4
+ * Onboarding used to fire only on a bare `failproofai`. It now fires on any
5
+ * command an unconfigured machine runs, which makes concurrent runs a real
6
+ * shape rather than a theoretical one: two terminals, `failproofai audit` in
7
+ * each, and both draw a wizard. They would then race on the same settings
8
+ * files and, worse, both try to install the system service — two `sudo`
9
+ * prompts and two `systemctl enable` calls against one unit.
10
+ *
11
+ * ## Why liveness, not a timeout
12
+ *
13
+ * The obvious lock carries a timestamp and is treated as stale after N
14
+ * seconds. That cannot work here: the holder is a human answering questions,
15
+ * so any N short enough to recover promptly from a crash is also short enough
16
+ * to evict someone who walked away mid-setup. So the lock records a PID and is
17
+ * considered held only while that process is actually alive — which recovers
18
+ * instantly from a crash or a Ctrl-C, and never evicts a live wizard no matter
19
+ * how long it sits.
20
+ *
21
+ * ## Failure direction
22
+ *
23
+ * Every failure here resolves to "do not onboard". A lock we cannot take is
24
+ * indistinguishable from one already held, and skipping onboarding costs a
25
+ * user one printed hint, where wrongly proceeding costs a duplicated install.
26
+ * The command the user typed always runs either way.
27
+ */
28
+ import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
29
+ import { homedir } from "node:os";
30
+ import { resolve } from "node:path";
31
+ import { onboardingLockFile, stateDir } from "./fp-home";
32
+
33
+ interface LockBody {
34
+ pid: number;
35
+ startedAt: number;
36
+ }
37
+
38
+ export function onboardingLockPath(home: string = homedir()): string {
39
+ return onboardingLockFile(home);
40
+ }
41
+
42
+ /**
43
+ * Whether `pid` is a live process this user can signal.
44
+ *
45
+ * `kill(pid, 0)` performs the permission and existence checks without
46
+ * delivering a signal. `EPERM` means the process exists but belongs to another
47
+ * user — still alive, so still holding the lock.
48
+ */
49
+ function processAlive(pid: number): boolean {
50
+ if (!Number.isInteger(pid) || pid <= 0) return false;
51
+ try {
52
+ process.kill(pid, 0);
53
+ return true;
54
+ } catch (err) {
55
+ return (err as NodeJS.ErrnoException)?.code === "EPERM";
56
+ }
57
+ }
58
+
59
+ function readLock(path: string): LockBody | null {
60
+ try {
61
+ const parsed = JSON.parse(readFileSync(path, "utf8")) as Partial<LockBody>;
62
+ if (typeof parsed.pid !== "number") return null;
63
+ return { pid: parsed.pid, startedAt: Number(parsed.startedAt) || 0 };
64
+ } catch {
65
+ // Absent, unreadable, or truncated by a crash mid-write. All three mean
66
+ // "no live holder we can prove", and the liveness check below is what
67
+ // actually decides.
68
+ return null;
69
+ }
70
+ }
71
+
72
+ export interface OnboardingLock {
73
+ /** Release the lock. Safe to call more than once. */
74
+ release(): void;
75
+ }
76
+
77
+ /**
78
+ * Take the onboarding lock, or return `null` if another live process holds it.
79
+ *
80
+ * There is a small window between the liveness check and the write in which
81
+ * two processes could both decide the lock is free. That is accepted
82
+ * deliberately: closing it needs `O_EXCL` plus stale-file recovery, which
83
+ * reintroduces exactly the timeout problem this design avoids — and the
84
+ * consequence of losing that race is two wizards, which is the situation
85
+ * before this existed, not something worse.
86
+ */
87
+ export function acquireOnboardingLock(home: string = homedir()): OnboardingLock | null {
88
+ const path = onboardingLockPath(home);
89
+ try {
90
+ const held = readLock(path);
91
+ // Our own PID appearing here means a previous run in this same process
92
+ // already holds it — re-entering is fine and must not deadlock.
93
+ if (held && held.pid !== process.pid && processAlive(held.pid)) return null;
94
+
95
+ mkdirSync(stateDir(home), { recursive: true });
96
+ const body: LockBody = { pid: process.pid, startedAt: Date.now() };
97
+ writeFileSync(path, JSON.stringify(body), "utf8");
98
+
99
+ let released = false;
100
+ return {
101
+ release() {
102
+ if (released) return;
103
+ released = true;
104
+ try {
105
+ // Only remove a lock still recorded as ours: if this process was
106
+ // evicted as dead and another wizard took over, deleting the file
107
+ // would release someone else's lock.
108
+ const current = readLock(path);
109
+ if (!current || current.pid === process.pid) rmSync(path, { force: true });
110
+ } catch {
111
+ /* best effort — a stray lock is reclaimed by the liveness check */
112
+ }
113
+ },
114
+ };
115
+ } catch {
116
+ // Unwritable home, read-only filesystem, whatever it is: treat as held.
117
+ return null;
118
+ }
119
+ }
@@ -126,13 +126,6 @@ export interface HooksConfig {
126
126
  * Only ever written explicitly as `false`.
127
127
  */
128
128
  customPoliciesEnabled?: boolean;
129
- /**
130
- * Upper bound, in ms, on how long `failproofai config --pause` may suspend
131
- * enforcement. Only ever LOWERS the built-in 8h ceiling — a value above it is
132
- * clamped back down, because a ceiling a project can raise is not a ceiling.
133
- * Absent means the built-in ceiling applies.
134
- */
135
- maxPauseMs?: number;
136
129
  /**
137
130
  * Record of the convention policies (`.failproofai/policies/*policies.mjs`)
138
131
  * discovered at this scope the last time a failproofai command ran.
@@ -17,7 +17,6 @@ import {
17
17
  writePause,
18
18
  type ActivePause,
19
19
  } from "./session-pause";
20
- import { readMergedHooksConfig } from "./hooks-config";
21
20
 
22
21
  export interface PauseCommandOptions {
23
22
  action: "pause" | "resume" | "status";
@@ -39,18 +38,21 @@ export interface PauseCommandResult {
39
38
  }
40
39
 
41
40
  /**
42
- * The ceiling, after any config lowering. A project may tighten this; nothing
43
- * may loosen it, so a config asking for 24h still gets 8h.
41
+ * The ceiling on a single `--pause`.
42
+ *
43
+ * Took a `cwd` and consulted `readMergedHooksConfig(cwd).maxPauseMs` to let a
44
+ * project LOWER it. That path was dead: the merge in `hooks-config.ts` builds
45
+ * its result field by field and never emits `maxPauseMs`, so the lookup could
46
+ * only ever read `undefined` — and the two tests that claimed to cover it
47
+ * `vi.mock`ed `readMergedHooksConfig` to return a field the real function
48
+ * cannot produce, which is why the gap survived. The knob is removed rather
49
+ * than wired up: nothing documented it, nothing could have used it, and the
50
+ * hard ceiling was doing all the work already.
51
+ *
52
+ * Kept as a function, and still the only thing `--pause` measures against, so
53
+ * reinstating a config lowering later is a change in one place.
44
54
  */
45
- export function effectiveCeilingMs(cwd?: string): number {
46
- try {
47
- const configured = readMergedHooksConfig(cwd).maxPauseMs;
48
- if (typeof configured === "number" && Number.isFinite(configured) && configured > 0) {
49
- return Math.min(configured, PAUSE_CEILING_MS);
50
- }
51
- } catch {
52
- // An unreadable config must not remove the ceiling.
53
- }
55
+ export function effectiveCeilingMs(): number {
54
56
  return PAUSE_CEILING_MS;
55
57
  }
56
58
 
@@ -109,7 +111,7 @@ export function runPauseCommand(opts: PauseCommandOptions): PauseCommandResult {
109
111
  // pause
110
112
  let durationMs: number;
111
113
  try {
112
- durationMs = parsePauseDuration(opts.duration, effectiveCeilingMs(cwd));
114
+ durationMs = parsePauseDuration(opts.duration, effectiveCeilingMs());
113
115
  } catch (err) {
114
116
  return { exitCode: 1, lines: [err instanceof Error ? err.message : String(err)], affected: 0 };
115
117
  }
@@ -27,6 +27,7 @@ import { createHash } from "node:crypto";
27
27
  import { join, resolve } from "node:path";
28
28
  import { writeJsonAtomically } from "../../lib/atomic-write";
29
29
  import { getAllHookActivityEntries } from "./hook-activity-store";
30
+ import { sessionPauseDir } from "./fp-home";
30
31
 
31
32
  const SCHEMA_VERSION = 1;
32
33
 
@@ -44,6 +45,19 @@ export interface ActivePause {
44
45
  sessionId: string;
45
46
  /** Epoch ms. */
46
47
  pausedAt: number;
48
+ /**
49
+ * Epoch ms of the FIRST pause in this unbroken run, which the ceiling is
50
+ * measured from.
51
+ *
52
+ * `pausedAt` moves to now on every renewal, so a ceiling measured from it is
53
+ * not a ceiling at all: `--pause 8h` every seven hours suspends enforcement
54
+ * indefinitely, one legal command at a time, and each individual pause passes
55
+ * every check. This field is what makes 8h mean 8h. Carried forward by
56
+ * `writePause` while a pause is still live, and reset once one has expired —
57
+ * the limit is on how long enforcement can stay off in one stretch, not a
58
+ * daily quota.
59
+ */
60
+ firstPausedAt: number;
47
61
  /** Epoch ms. Always finite — there is no unbounded pause. */
48
62
  expiresAt: number;
49
63
  /** Free-form provenance, e.g. "cli". Recorded so the activity log can say who. */
@@ -59,7 +73,7 @@ interface StoredPause extends ActivePause {
59
73
  export function pauseStateDir(): string {
60
74
  const override = process.env.FAILPROOFAI_STATE_DIR;
61
75
  if (override) return resolve(override, "sessions");
62
- return join(homedir(), ".failproofai", "state", "sessions");
76
+ return sessionPauseDir();
63
77
  }
64
78
 
65
79
  /**
@@ -119,11 +133,22 @@ function parseStored(raw: unknown): StoredPause | null {
119
133
  if (p.schemaVersion !== SCHEMA_VERSION) return null;
120
134
  if (typeof p.sessionId !== "string" || p.sessionId.length === 0) return null;
121
135
  if (!Number.isFinite(p.pausedAt) || !Number.isFinite(p.expiresAt)) return null;
136
+ const pausedAt = p.pausedAt as number;
137
+ // A file written before this field existed measures its ceiling from the
138
+ // only start it recorded. Same meaning for a pause that was never renewed.
139
+ const firstPausedAt = Number.isFinite(p.firstPausedAt) ? (p.firstPausedAt as number) : pausedAt;
122
140
  return {
123
141
  schemaVersion: SCHEMA_VERSION,
124
142
  sessionId: p.sessionId,
125
- pausedAt: p.pausedAt as number,
126
- expiresAt: p.expiresAt as number,
143
+ pausedAt,
144
+ firstPausedAt,
145
+ // Clamped at READ time, not only at write. The ceiling has to hold against
146
+ // a file this process did not write: `~/.failproofai/state/sessions/` is
147
+ // owner-writable by design, and an `expiresAt` a year out would otherwise
148
+ // be honoured on every subsequent tool call forever. Enforcing it here
149
+ // means the bound is a property of the pause, not of the path that created
150
+ // it.
151
+ expiresAt: Math.min(p.expiresAt as number, firstPausedAt + PAUSE_CEILING_MS),
127
152
  setBy: typeof p.setBy === "string" ? p.setBy : "unknown",
128
153
  ...(typeof p.cwd === "string" ? { cwd: p.cwd } : {}),
129
154
  };
@@ -159,10 +184,17 @@ export function writePause(opts: {
159
184
  now?: number;
160
185
  }): ActivePause {
161
186
  const now = opts.now ?? Date.now();
187
+ // Carry the run's original start forward while a pause is still live, so a
188
+ // renewal extends the same stretch rather than starting a fresh ceiling.
189
+ const existing = readActivePause(opts.sessionId, now);
190
+ const firstPausedAt = existing?.firstPausedAt ?? now;
162
191
  const pause: ActivePause = {
163
192
  sessionId: opts.sessionId,
164
193
  pausedAt: now,
165
- expiresAt: now + opts.durationMs,
194
+ firstPausedAt,
195
+ // The requested duration, but never past the ceiling measured from the
196
+ // start of the run. A renewal can shorten a pause; it cannot outrun 8h.
197
+ expiresAt: Math.min(now + opts.durationMs, firstPausedAt + PAUSE_CEILING_MS),
166
198
  setBy: opts.setBy ?? "cli",
167
199
  ...(opts.cwd ? { cwd: opts.cwd } : {}),
168
200
  };