failproofai 1.0.0-beta.0 → 1.0.0-beta.10

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 (357) hide show
  1. package/.next/standalone/.next/BUILD_ID +1 -1
  2. package/.next/standalone/.next/app-path-routes-manifest.json +2 -1
  3. package/.next/standalone/.next/build-manifest.json +6 -6
  4. package/.next/standalone/.next/prerender-manifest.json +3 -3
  5. package/.next/standalone/.next/required-server-files.json +1 -1
  6. package/.next/standalone/.next/routes-manifest.json +6 -0
  7. package/.next/standalone/.next/server/app/_global-error/page/build-manifest.json +3 -3
  8. package/.next/standalone/.next/server/app/_global-error/page/server-reference-manifest.json +1 -1
  9. package/.next/standalone/.next/server/app/_global-error/page.js +3 -1
  10. package/.next/standalone/.next/server/app/_global-error/page.js.nft.json +1 -1
  11. package/.next/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  12. package/.next/standalone/.next/server/app/_global-error.html +1 -1
  13. package/.next/standalone/.next/server/app/_global-error.rsc +7 -7
  14. package/.next/standalone/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +2 -2
  15. package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +7 -7
  16. package/.next/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +3 -3
  17. package/.next/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +3 -3
  18. package/.next/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  19. package/.next/standalone/.next/server/app/_not-found/page/build-manifest.json +3 -3
  20. package/.next/standalone/.next/server/app/_not-found/page/server-reference-manifest.json +1 -1
  21. package/.next/standalone/.next/server/app/_not-found/page.js +3 -1
  22. package/.next/standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
  23. package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  24. package/.next/standalone/.next/server/app/_not-found.html +1 -1
  25. package/.next/standalone/.next/server/app/_not-found.rsc +15 -15
  26. package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +15 -15
  27. package/.next/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +4 -4
  28. package/.next/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +10 -10
  29. package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +2 -2
  30. package/.next/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +3 -3
  31. package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  32. package/.next/standalone/.next/server/app/api/audit/invite/route.js +3 -2
  33. package/.next/standalone/.next/server/app/api/audit/invite/route.js.nft.json +1 -1
  34. package/.next/standalone/.next/server/app/api/audit/run/route.js +4 -3
  35. package/.next/standalone/.next/server/app/api/audit/run/route.js.nft.json +1 -1
  36. package/.next/standalone/.next/server/app/api/audit/status/route.js +1 -1
  37. package/.next/standalone/.next/server/app/api/audit/status/route.js.nft.json +1 -1
  38. package/.next/standalone/.next/server/app/api/auth/login-request/route.js +2 -1
  39. package/.next/standalone/.next/server/app/api/auth/login-request/route.js.nft.json +1 -1
  40. package/.next/standalone/.next/server/app/api/auth/login-verify/route.js +3 -2
  41. package/.next/standalone/.next/server/app/api/auth/login-verify/route.js.nft.json +1 -1
  42. package/.next/standalone/.next/server/app/api/auth/logout/route.js +3 -2
  43. package/.next/standalone/.next/server/app/api/auth/logout/route.js.nft.json +1 -1
  44. package/.next/standalone/.next/server/app/api/auth/reminder/route.js +3 -2
  45. package/.next/standalone/.next/server/app/api/auth/reminder/route.js.nft.json +1 -1
  46. package/.next/standalone/.next/server/app/api/auth/status/route.js +3 -2
  47. package/.next/standalone/.next/server/app/api/auth/status/route.js.nft.json +1 -1
  48. package/.next/standalone/.next/server/app/api/download/[project]/[session]/route.js +1 -1
  49. package/.next/standalone/.next/server/app/api/download/[project]/[session]/route.js.nft.json +1 -1
  50. package/.next/standalone/.next/server/app/audit/page/build-manifest.json +3 -3
  51. package/.next/standalone/.next/server/app/audit/page/server-reference-manifest.json +2 -2
  52. package/.next/standalone/.next/server/app/audit/page.js +5 -3
  53. package/.next/standalone/.next/server/app/audit/page.js.nft.json +1 -1
  54. package/.next/standalone/.next/server/app/audit/page_client-reference-manifest.js +1 -1
  55. package/.next/standalone/.next/server/app/index.html +1 -1
  56. package/.next/standalone/.next/server/app/index.rsc +15 -15
  57. package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  58. package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +15 -15
  59. package/.next/standalone/.next/server/app/index.segments/_head.segment.rsc +4 -4
  60. package/.next/standalone/.next/server/app/index.segments/_index.segment.rsc +10 -10
  61. package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -2
  62. package/.next/standalone/.next/server/app/page/build-manifest.json +3 -3
  63. package/.next/standalone/.next/server/app/page/server-reference-manifest.json +1 -1
  64. package/.next/standalone/.next/server/app/page.js +3 -1
  65. package/.next/standalone/.next/server/app/page.js.nft.json +1 -1
  66. package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  67. package/.next/standalone/.next/server/app/policies/page/build-manifest.json +3 -3
  68. package/.next/standalone/.next/server/app/policies/page/server-reference-manifest.json +30 -18
  69. package/.next/standalone/.next/server/app/policies/page.js +5 -3
  70. package/.next/standalone/.next/server/app/policies/page.js.nft.json +1 -1
  71. package/.next/standalone/.next/server/app/policies/page_client-reference-manifest.js +1 -1
  72. package/.next/standalone/.next/server/app/project/[name]/page/build-manifest.json +3 -3
  73. package/.next/standalone/.next/server/app/project/[name]/page/server-reference-manifest.json +1 -1
  74. package/.next/standalone/.next/server/app/project/[name]/page.js +4 -2
  75. package/.next/standalone/.next/server/app/project/[name]/page.js.nft.json +1 -1
  76. package/.next/standalone/.next/server/app/project/[name]/page_client-reference-manifest.js +1 -1
  77. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/build-manifest.json +3 -3
  78. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/react-loadable-manifest.json +2 -2
  79. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/server-reference-manifest.json +2 -2
  80. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page.js +6 -4
  81. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page.js.nft.json +1 -1
  82. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page_client-reference-manifest.js +1 -1
  83. package/.next/standalone/.next/server/app/projects/page/build-manifest.json +3 -3
  84. package/.next/standalone/.next/server/app/projects/page/server-reference-manifest.json +1 -1
  85. package/.next/standalone/.next/server/app/projects/page.js +4 -2
  86. package/.next/standalone/.next/server/app/projects/page.js.nft.json +1 -1
  87. package/.next/standalone/.next/server/app/projects/page_client-reference-manifest.js +1 -1
  88. package/.next/standalone/.next/server/app/settings/page/app-paths-manifest.json +3 -0
  89. package/.next/standalone/.next/server/app/settings/page/build-manifest.json +18 -0
  90. package/.next/standalone/.next/server/app/settings/page/next-font-manifest.json +6 -0
  91. package/.next/standalone/.next/server/app/settings/page/react-loadable-manifest.json +1 -0
  92. package/.next/standalone/.next/server/app/settings/page/server-reference-manifest.json +53 -0
  93. package/.next/standalone/.next/server/app/settings/page.js +18 -0
  94. package/.next/standalone/.next/server/app/settings/page.js.map +5 -0
  95. package/.next/standalone/.next/server/app/settings/page.js.nft.json +1 -0
  96. package/.next/standalone/.next/server/app/settings/page_client-reference-manifest.js +3 -0
  97. package/.next/standalone/.next/server/app-paths-manifest.json +2 -1
  98. package/.next/standalone/.next/server/chunks/[externals]__0h9_83k._.js +3 -0
  99. package/.next/standalone/.next/server/chunks/{[externals]__1nl3dvw._.js → [externals]__0r-zamh._.js} +2 -2
  100. package/.next/standalone/.next/server/chunks/[externals]__1ifpkx-._.js +3 -0
  101. package/.next/standalone/.next/server/chunks/[root-of-the-server]__06hexd0._.js +3 -0
  102. package/.next/standalone/.next/server/chunks/[root-of-the-server]__094p1f1._.js +3 -0
  103. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0_0xu5z._.js +1 -1
  104. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0ed01_d._.js +3 -0
  105. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0g0vcwt._.js +3 -0
  106. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0h3lfmp._.js → [root-of-the-server]__0ky_n0r._.js} +2 -2
  107. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__18d-9oi._.js → [root-of-the-server]__0lk_935._.js} +2 -2
  108. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__16le-kd._.js → [root-of-the-server]__0pbp9fe._.js} +2 -2
  109. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0q-v9z2._.js +1 -1
  110. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__10oa-v9._.js → [root-of-the-server]__0v2fpxe._.js} +2 -2
  111. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0sb_5m8._.js → [root-of-the-server]__131ebum._.js} +3 -3
  112. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0-dh5jy._.js → [root-of-the-server]__1_ps0jw._.js} +2 -2
  113. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0l4vuqm._.js → [root-of-the-server]__1a7i2q4._.js} +2 -2
  114. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1ibjy5x._.js +3 -0
  115. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1iny24d._.js +3 -0
  116. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1tvn4wf._.js +1 -1
  117. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1tyedjt._.js +3 -0
  118. package/.next/standalone/.next/server/chunks/_0lxbzdq._.js +5 -0
  119. package/.next/standalone/.next/server/chunks/_1zuiiy3._.js +5 -0
  120. package/.next/standalone/.next/server/chunks/lib_telemetry_ts_0dctyyw._.js +5 -0
  121. package/.next/standalone/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_17k9e3w.js +5 -5
  122. package/.next/standalone/.next/server/chunks/node_modules_posthog-node_dist_entrypoints_index_node_mjs_01r25oi._.js +2 -1
  123. package/.next/standalone/.next/server/chunks/node_modules_posthog-node_dist_entrypoints_index_node_mjs_09z9-p7._.js +2 -1
  124. package/.next/standalone/.next/server/chunks/package_json_[json]_cjs_1nxcc4v._.js +1 -1
  125. package/.next/standalone/.next/server/chunks/ssr/[externals]__1aq139v._.js +3 -0
  126. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__04pwh4t._.js +3 -0
  127. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__06bp_fg._.js +5 -0
  128. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__074qmkp._.js +3 -0
  129. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__170799-._.js → [root-of-the-server]__0spkm68._.js} +11 -11
  130. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__10butu6._.js +3 -0
  131. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1a2hcb_._.js +3 -0
  132. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1qapotl._.js +1 -1
  133. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__1apb7k_._.js → [root-of-the-server]__1rdruw4._.js} +2 -2
  134. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1rv-sc9._.js +3 -0
  135. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1tyf0tc._.js +5 -0
  136. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1u-wx42._.js +4 -0
  137. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1v185mo._.js +3 -0
  138. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__01od0m6._.js → [root-of-the-server]__1yw368c._.js} +2 -2
  139. package/.next/standalone/.next/server/chunks/ssr/_0-yi74u._.js +3 -0
  140. package/.next/standalone/.next/server/chunks/ssr/_04mekdy._.js +3 -0
  141. package/.next/standalone/.next/server/chunks/ssr/_0r-dsre._.js +3 -0
  142. package/.next/standalone/.next/server/chunks/ssr/_0rjgfln._.js +3 -0
  143. package/.next/standalone/.next/server/chunks/ssr/_0se484m._.js +3 -0
  144. package/.next/standalone/.next/server/chunks/ssr/_0uz7o9y._.js +3 -0
  145. package/.next/standalone/.next/server/chunks/ssr/_11_p9y8._.js +1 -1
  146. package/.next/standalone/.next/server/chunks/ssr/_1e19atl._.js +1 -1
  147. package/.next/standalone/.next/server/chunks/ssr/_1fahg9e._.js +3 -0
  148. package/.next/standalone/.next/server/chunks/ssr/_1gmzkwj._.js +5 -0
  149. package/.next/standalone/.next/server/chunks/ssr/_1w8sola._.js +3 -0
  150. package/.next/standalone/.next/server/chunks/ssr/_1w_6p9g._.js +3 -0
  151. package/.next/standalone/.next/server/chunks/ssr/_1y4qr7u._.js +3 -0
  152. package/.next/standalone/.next/server/chunks/ssr/app_audit__components_audit-dashboard_tsx_0p9ud47._.js +2 -2
  153. package/.next/standalone/.next/server/chunks/ssr/app_global-error_tsx_1kp6l3x._.js +1 -1
  154. package/.next/standalone/.next/server/chunks/ssr/app_policies_hooks-client_tsx_19dqvpc._.js +2 -2
  155. package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0dwo94s.js +4 -0
  156. package/.next/standalone/.next/server/chunks/ssr/node_modules_posthog-node_dist_entrypoints_index_node_mjs_11bnuzn._.js +2 -1
  157. package/.next/standalone/.next/server/chunks/ssr/src_hooks_builtin-policies_ts_09j2ndl._.js +3 -0
  158. package/.next/standalone/.next/server/chunks/ssr/src_hooks_fp-config_ts_04t589g._.js +5 -0
  159. package/.next/standalone/.next/server/middleware-build-manifest.js +6 -6
  160. package/.next/standalone/.next/server/middleware.js +2 -2
  161. package/.next/standalone/.next/server/pages/404.html +1 -1
  162. package/.next/standalone/.next/server/pages/500.html +1 -1
  163. package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
  164. package/.next/standalone/.next/server/server-reference-manifest.json +74 -20
  165. package/.next/standalone/.next/static/chunks/00adubtgov21s.js +1 -0
  166. package/.next/standalone/.next/static/chunks/{03fmihek9n986.js → 06zgzyh3wv1ig.js} +1 -1
  167. package/.next/standalone/.next/static/chunks/{1hdhteui932bq.js → 0qmo2t50kpb30.js} +1 -1
  168. package/.next/standalone/.next/static/chunks/{1grd7y94-igz9.js → 0yudogeqddpzr.js} +1 -1
  169. package/.next/standalone/.next/static/chunks/16p68cybetr31.js +1 -0
  170. package/.next/standalone/.next/static/chunks/1bm0q12hgs22l.css +2 -0
  171. package/.next/standalone/.next/static/chunks/{1d6ncspjagm53.js → 1fu90ch80qngv.js} +1 -1
  172. package/.next/standalone/.next/static/chunks/{2vr7aazw6k2-n.js → 1m416lie3qwsj.js} +1 -1
  173. package/.next/standalone/.next/static/chunks/1v1gqvpjk62jm.js +1 -0
  174. package/.next/standalone/.next/static/chunks/1ypqzvoal8j56.js +6 -0
  175. package/.next/standalone/.next/static/chunks/23kev26by1e4f.js +1 -0
  176. package/.next/standalone/.next/static/chunks/{29k6ef49zppxj.js → 2h4sbmp0ad78w.js} +1 -1
  177. package/.next/standalone/.next/static/chunks/2obwg4tterjpa.js +1 -0
  178. package/.next/standalone/.next/static/chunks/2uvhw57mf9lg_.css +2 -0
  179. package/.next/standalone/.next/static/chunks/{29ydr-8q0zis6.js → 30ufy4_e2n78e.js} +22 -22
  180. package/.next/standalone/.next/static/chunks/31coz11ia5vc4.js +1 -0
  181. package/.next/standalone/.next/static/chunks/{1s-_swlc80y43.js → 3p4j0l1o_p-nm.js} +1 -1
  182. package/.next/standalone/.next/static/chunks/{0ip1n8xmgxarv.js → 3uxnxwxcctyj0.js} +1 -1
  183. package/.next/standalone/.next/static/chunks/{turbopack-1lsv92x7klwrn.js → turbopack-3diub4ctvn1n0.js} +1 -1
  184. package/.next/standalone/app/actions/get-active-pauses.ts +16 -0
  185. package/.next/standalone/app/actions/get-hooks-config.ts +2 -1
  186. package/.next/standalone/app/actions/get-scheduled-audit.ts +70 -0
  187. package/.next/standalone/app/actions/update-scheduled-audit.ts +44 -0
  188. package/.next/standalone/app/api/audit/run/route.ts +28 -0
  189. package/.next/standalone/app/api/audit/status/route.ts +13 -1
  190. package/.next/standalone/app/api/auth/status/route.ts +1 -1
  191. package/.next/standalone/app/audit/_components/auth-dialog.css +159 -0
  192. package/.next/standalone/app/audit/_components/auth-dialog.tsx +3 -0
  193. package/.next/standalone/app/audit/audit-styles.css +6 -149
  194. package/.next/standalone/app/components/pause-notices.tsx +111 -0
  195. package/.next/standalone/app/policies/hooks-client.tsx +81 -6
  196. package/.next/standalone/app/settings/page.tsx +31 -0
  197. package/.next/standalone/app/settings/settings-client.tsx +488 -0
  198. package/.next/standalone/components/navbar.tsx +2 -0
  199. package/.next/standalone/lib/auth/api-server-client.ts +2 -3
  200. package/.next/standalone/lib/auth/auth-store.ts +4 -4
  201. package/.next/standalone/lib/codex-sessions.ts +2 -1
  202. package/.next/standalone/lib/dashboard-host.ts +101 -0
  203. package/.next/standalone/lib/install-check.ts +22 -7
  204. package/.next/standalone/lib/pi-sessions.ts +99 -14
  205. package/.next/standalone/lib/telemetry-enabled.ts +54 -0
  206. package/.next/standalone/lib/telemetry-id.ts +52 -1
  207. package/.next/standalone/lib/telemetry.ts +8 -4
  208. package/.next/standalone/node_modules/react/cjs/react.development.js +1 -1
  209. package/.next/standalone/node_modules/react/cjs/react.production.js +1 -1
  210. package/.next/standalone/node_modules/react/package.json +3 -3
  211. package/.next/standalone/node_modules/react-dom/cjs/react-dom-server-legacy.browser.production.js +1 -1
  212. package/.next/standalone/node_modules/react-dom/cjs/react-dom-server-legacy.node.production.js +1 -1
  213. package/.next/standalone/node_modules/react-dom/cjs/react-dom-server.browser.production.js +3 -3
  214. package/.next/standalone/node_modules/react-dom/cjs/react-dom-server.edge.production.js +3 -3
  215. package/.next/standalone/node_modules/react-dom/cjs/react-dom-server.node.production.js +3 -3
  216. package/.next/standalone/node_modules/react-dom/cjs/react-dom.production.js +1 -1
  217. package/.next/standalone/node_modules/react-dom/package.json +4 -4
  218. package/.next/standalone/package.json +17 -10
  219. package/.next/standalone/proxy.ts +89 -1
  220. package/.next/standalone/server.js +1 -1
  221. package/bin/failproofai.mjs +518 -79
  222. package/dist/cli.mjs +11484 -6046
  223. package/dist/worker.mjs +2019 -272
  224. package/lib/auth/api-server-client.ts +2 -3
  225. package/lib/auth/auth-store.ts +4 -4
  226. package/lib/codex-sessions.ts +2 -1
  227. package/lib/dashboard-host.ts +101 -0
  228. package/lib/install-check.ts +22 -7
  229. package/lib/pi-sessions.ts +99 -14
  230. package/lib/telemetry-enabled.ts +54 -0
  231. package/lib/telemetry-id.ts +52 -1
  232. package/lib/telemetry.ts +8 -4
  233. package/package.json +17 -10
  234. package/scripts/build-daemon-packages.mjs +210 -0
  235. package/scripts/daemon-platforms.mjs +42 -0
  236. package/scripts/install-telemetry.mjs +8 -1
  237. package/scripts/launch.ts +25 -3
  238. package/scripts/parse-script-args.ts +17 -1
  239. package/scripts/prune-standalone.mjs +26 -0
  240. package/scripts/publish-aliases.mjs +62 -41
  241. package/scripts/repro-npm-install.sh +155 -0
  242. package/scripts/translate-docs/readme-translator.ts +163 -4
  243. package/scripts/validate-mdx.ts +153 -13
  244. package/src/audit/audit-lock.ts +285 -0
  245. package/src/audit/audit-schedule.ts +111 -0
  246. package/src/audit/cache.ts +18 -4
  247. package/src/audit/cli-adapters/goose.ts +2 -1
  248. package/src/audit/cli-adapters/hermes.ts +28 -10
  249. package/src/audit/cli.ts +191 -35
  250. package/src/audit/dashboard-cache.ts +2 -1
  251. package/src/hooks/backfill-cli.ts +247 -0
  252. package/src/hooks/builtin-policies.ts +390 -2
  253. package/src/hooks/cloud-connection.ts +354 -0
  254. package/src/hooks/cloud-enrollment-cli.ts +325 -0
  255. package/src/hooks/cloud-enrollment.ts +243 -0
  256. package/src/hooks/cloud-introspect.ts +147 -0
  257. package/src/hooks/cloud-managed-policies.ts +169 -0
  258. package/src/hooks/collector-config.ts +234 -0
  259. package/src/hooks/configure-wizard.ts +915 -158
  260. package/src/hooks/custom-hooks-loader.ts +191 -33
  261. package/src/hooks/daemon-client.ts +136 -17
  262. package/src/hooks/daemon-download.ts +192 -30
  263. package/src/hooks/daemon-service.ts +1190 -92
  264. package/src/hooks/first-run-gate.ts +50 -0
  265. package/src/hooks/fp-config.ts +497 -0
  266. package/src/hooks/fp-home.ts +375 -0
  267. package/src/hooks/fp-reset.ts +464 -0
  268. package/src/hooks/handler.ts +185 -6
  269. package/src/hooks/hook-activity-store.ts +85 -20
  270. package/src/hooks/hook-logger.ts +2 -1
  271. package/src/hooks/hook-telemetry.ts +5 -1
  272. package/src/hooks/hooks-config.ts +4 -3
  273. package/src/hooks/loader-utils.ts +171 -8
  274. package/src/hooks/manager.ts +5 -4
  275. package/src/hooks/onboarding-attempt.ts +179 -0
  276. package/src/hooks/onboarding-lock.ts +119 -0
  277. package/src/hooks/policy-types.ts +28 -0
  278. package/src/hooks/session-pause-cli.ts +159 -0
  279. package/src/hooks/session-pause.ts +268 -0
  280. package/src/hooks/setup-state.ts +256 -0
  281. package/src/hooks/tui.ts +119 -4
  282. package/src/hooks/uninstall-cli.ts +345 -0
  283. package/src/hooks/worker-server.ts +65 -3
  284. package/.next/standalone/.next/server/chunks/[externals]__14odj07._.js +0 -3
  285. package/.next/standalone/.next/server/chunks/[externals]__1s61mel._.js +0 -3
  286. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0id_xf7._.js +0 -3
  287. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0longh-._.js +0 -3
  288. package/.next/standalone/.next/server/chunks/[root-of-the-server]__17g9wh7._.js +0 -3
  289. package/.next/standalone/.next/server/chunks/[root-of-the-server]__19120tr._.js +0 -3
  290. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1fwl2mz._.js +0 -3
  291. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1myjm-d._.js +0 -3
  292. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1rhmvod._.js +0 -3
  293. package/.next/standalone/.next/server/chunks/ssr/[externals]__1_g_b3t._.js +0 -3
  294. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0114ewg._.js +0 -4
  295. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0259h38._.js +0 -3
  296. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__02r5bgf._.js +0 -4
  297. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0e8sjqm._.js +0 -4
  298. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0lkzqax._.js +0 -4
  299. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0qucxyj._.js +0 -4
  300. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0u02miy._.js +0 -4
  301. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0uno39i._.js +0 -3
  302. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__14dd6h8._.js +0 -3
  303. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1ath6v_._.js +0 -4
  304. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1zj-87g._.js +0 -3
  305. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1zqz4v8._.js +0 -4
  306. package/.next/standalone/.next/server/chunks/ssr/_1m_p7pi._.js +0 -3
  307. package/.next/standalone/.next/server/chunks/ssr/node_modules_html-to-image_es_index_1-upb14.js +0 -3
  308. package/.next/standalone/.next/server/chunks/ssr/src_hooks_1ezd2jf._.js +0 -5
  309. package/.next/standalone/.next/server/chunks/ssr/src_hooks_1tnuifj._.js +0 -5
  310. package/.next/standalone/.next/static/chunks/0h7auy7hzjyhw.js +0 -1
  311. package/.next/standalone/.next/static/chunks/0u9hc6oxx-gpj.js +0 -6
  312. package/.next/standalone/.next/static/chunks/0zbxssxh53n-3.js +0 -1
  313. package/.next/standalone/.next/static/chunks/2mazwb1qmur1p.js +0 -1
  314. package/.next/standalone/.next/static/chunks/2pujpnfx4pws6.css +0 -2
  315. package/.next/standalone/.next/static/chunks/33u59vf_8xpd-.js +0 -1
  316. package/.next/standalone/.next/static/chunks/3i27c3hcriawq.css +0 -1
  317. package/.next/standalone/.next/static/chunks/3wrgbih-516uj.js +0 -1
  318. package/.next/standalone/Cargo.lock +0 -428
  319. package/.next/standalone/Cargo.toml +0 -9
  320. package/.next/standalone/crates/PROTOCOL.md +0 -122
  321. package/.next/standalone/crates/failproofaid/Cargo.toml +0 -18
  322. package/.next/standalone/crates/failproofaid/src/lock.rs +0 -81
  323. package/.next/standalone/crates/failproofaid/src/main.rs +0 -83
  324. package/.next/standalone/crates/failproofaid/src/paths.rs +0 -172
  325. package/.next/standalone/crates/failproofaid/src/server.rs +0 -502
  326. package/.next/standalone/crates/failproofaid/src/worker.rs +0 -400
  327. package/.next/standalone/crates/failproofaid/tests/daemon_e2e.rs +0 -241
  328. package/.next/standalone/crates/fpai-ipc/Cargo.toml +0 -16
  329. package/.next/standalone/crates/fpai-ipc/src/envelope.rs +0 -175
  330. package/.next/standalone/crates/fpai-ipc/src/framing.rs +0 -177
  331. package/.next/standalone/crates/fpai-ipc/src/lib.rs +0 -10
  332. package/.next/standalone/crates/fpai-ipc/src/peer.rs +0 -80
  333. package/.next/standalone/docker-hook-sync/Dockerfile +0 -79
  334. package/.next/standalone/docker-hook-sync/entrypoint.sh +0 -109
  335. package/.next/standalone/integration-suite/Dockerfile +0 -47
  336. package/.next/standalone/integration-suite/README.md +0 -129
  337. package/.next/standalone/integration-suite/canary-policies.mjs +0 -45
  338. package/.next/standalone/integration-suite/capture-tokens.sh +0 -48
  339. package/.next/standalone/integration-suite/ci-entrypoint.sh +0 -179
  340. package/.next/standalone/integration-suite/inject-tokens.sh +0 -44
  341. package/.next/standalone/integration-suite/install-clis.sh +0 -136
  342. package/.next/standalone/integration-suite/probe-cli.sh +0 -248
  343. package/.next/standalone/integration-suite/report.js +0 -120
  344. package/.next/standalone/integration-suite/run.sh +0 -159
  345. package/.next/standalone/openclaw-plugin/index.js +0 -223
  346. package/.next/standalone/openclaw-plugin/openclaw.plugin.json +0 -6
  347. package/.next/standalone/openclaw-plugin/package.json +0 -12
  348. package/.next/standalone/osv-scanner.toml +0 -17
  349. package/.next/standalone/pi-extension/index.ts +0 -524
  350. package/.next/standalone/pi-extension/package.json +0 -12
  351. package/.next/standalone/postcss.config.mjs +0 -8
  352. package/.next/standalone/readme-arch-hq.gif +0 -0
  353. package/.next/standalone/rust-toolchain.toml +0 -4
  354. package/src/auth/cli.ts +0 -371
  355. /package/.next/standalone/.next/static/{7Lxtd352rSaHB-pmm6G8M → pBBcTvE6_VueYGbacy1kg}/_buildManifest.js +0 -0
  356. /package/.next/standalone/.next/static/{7Lxtd352rSaHB-pmm6G8M → pBBcTvE6_VueYGbacy1kg}/_clientMiddlewareManifest.js +0 -0
  357. /package/.next/standalone/.next/static/{7Lxtd352rSaHB-pmm6G8M → pBBcTvE6_VueYGbacy1kg}/_ssgManifest.js +0 -0
@@ -0,0 +1,159 @@
1
+ /* Styles for <AuthDialog> — co-located with the component and imported by it,
2
+ * NOT living in a route stylesheet.
3
+ *
4
+ * Why here: the dialog was first used only on /audit, so these rules used to sit
5
+ * in audit-styles.css (route-scoped to /audit). The /settings page reuses the
6
+ * same component to lead a signed-out user into the existing OTP login flow, and
7
+ * a route stylesheet would not load there — the modal would render unstyled.
8
+ * Importing this file from auth-dialog.tsx makes the CSS travel with the
9
+ * component to every route that renders it. Every var below is defined in
10
+ * globals.css :root, so it resolves anywhere.
11
+ */
12
+
13
+ .auth-dialog-backdrop {
14
+ position: fixed; inset: 0; z-index: 10000;
15
+ display: grid; place-items: center;
16
+ padding: 32px 16px;
17
+ background: rgba(8,8,10,0.7);
18
+ backdrop-filter: blur(6px);
19
+ -webkit-backdrop-filter: blur(6px);
20
+ }
21
+
22
+ .auth-dialog {
23
+ position: relative;
24
+ width: 100%;
25
+ max-width: 420px;
26
+ padding: 28px 28px 24px;
27
+ border: 1px solid var(--line-2);
28
+ background: var(--bg-2);
29
+ font-family: var(--font-mono);
30
+ color: var(--ink);
31
+ }
32
+
33
+ .auth-close {
34
+ position: absolute; top: 12px; right: 14px;
35
+ font-family: var(--font-mono); font-size: 20px;
36
+ line-height: 1;
37
+ color: var(--dim);
38
+ background: transparent; border: none; padding: 4px 8px;
39
+ cursor: pointer;
40
+ transition: color 120ms;
41
+ }
42
+ .auth-close:hover { color: var(--accent-pink); }
43
+ .auth-close:disabled { color: var(--line-2); cursor: not-allowed; }
44
+
45
+ .auth-headline {
46
+ font-family: var(--font-mono);
47
+ font-size: 18px;
48
+ font-weight: 600;
49
+ letter-spacing: 0;
50
+ line-height: 1.3;
51
+ text-transform: none;
52
+ color: var(--ink);
53
+ margin: 0 0 8px;
54
+ }
55
+
56
+ .auth-sub {
57
+ font-family: var(--font-mono); font-size: 12px;
58
+ line-height: 1.55; color: var(--ink-2);
59
+ margin: 0 0 18px;
60
+ }
61
+ .auth-sub .auth-email {
62
+ color: var(--accent-pink);
63
+ }
64
+ .auth-sub .auth-ok {
65
+ color: var(--accent-green);
66
+ margin-right: 6px;
67
+ }
68
+
69
+ .auth-form { display: flex; flex-direction: column; gap: 10px; }
70
+
71
+ .auth-field-label {
72
+ font-family: var(--font-mono); font-size: 10px;
73
+ letter-spacing: 0.22em; text-transform: uppercase;
74
+ color: var(--accent-green);
75
+ }
76
+
77
+ .auth-input {
78
+ width: 100%;
79
+ padding: 11px 14px;
80
+ background: var(--bg);
81
+ border: 1px solid var(--line-2);
82
+ color: var(--ink);
83
+ font-family: var(--font-mono); font-size: 14px;
84
+ letter-spacing: 0.03em;
85
+ outline: none;
86
+ transition: border-color 120ms, box-shadow 120ms;
87
+ }
88
+ .auth-input:focus {
89
+ border-color: var(--accent-pink);
90
+ box-shadow: 0 0 0 1px var(--accent-pink-soft);
91
+ }
92
+ .auth-input:disabled {
93
+ opacity: 0.55; cursor: not-allowed;
94
+ }
95
+ .auth-input-code {
96
+ letter-spacing: 0.5em;
97
+ text-align: center;
98
+ font-size: 18px;
99
+ font-variant-numeric: tabular-nums;
100
+ }
101
+ .auth-input::placeholder { color: var(--dim); }
102
+
103
+ .auth-error {
104
+ font-family: var(--font-mono); font-size: 12px;
105
+ color: var(--accent-pink);
106
+ padding: 8px 12px;
107
+ background: var(--accent-pink-bg);
108
+ border: 1px solid var(--accent-pink);
109
+ border-left-width: 3px;
110
+ letter-spacing: 0.02em;
111
+ margin-top: 4px;
112
+ }
113
+
114
+ .auth-actions {
115
+ display: flex; gap: 10px; flex-wrap: wrap;
116
+ margin-top: 14px;
117
+ }
118
+
119
+ .auth-btn {
120
+ display: inline-flex; align-items: center; gap: 8px;
121
+ padding: 10px 16px;
122
+ font-family: var(--font-mono); font-size: 12px;
123
+ letter-spacing: 0.06em;
124
+ background: transparent;
125
+ border: 1px solid var(--line-2);
126
+ color: var(--ink);
127
+ cursor: pointer;
128
+ transition: all 120ms ease;
129
+ }
130
+ .auth-btn:hover:not(:disabled) {
131
+ border-color: var(--ink); background: rgba(255,255,255,0.04);
132
+ }
133
+ .auth-btn:disabled { opacity: 0.45; cursor: not-allowed; }
134
+ .auth-btn.primary {
135
+ border-color: var(--accent-pink);
136
+ color: var(--accent-pink);
137
+ background: var(--accent-pink-bg);
138
+ }
139
+ .auth-btn.primary:hover:not(:disabled) {
140
+ background: var(--accent-pink); color: var(--bg);
141
+ }
142
+
143
+ .auth-back {
144
+ align-self: flex-start;
145
+ margin-top: 4px;
146
+ background: transparent; border: none; padding: 6px 0;
147
+ font-family: var(--font-mono); font-size: 11px;
148
+ letter-spacing: 0.1em; color: var(--dim);
149
+ cursor: pointer;
150
+ transition: color 120ms;
151
+ }
152
+ .auth-back:hover:not(:disabled) { color: var(--ink-2); }
153
+ .auth-back:disabled { opacity: 0.45; cursor: not-allowed; }
154
+
155
+ @media (max-width: 520px) {
156
+ .auth-dialog { padding: 26px 22px 22px; }
157
+ .auth-actions { flex-direction: column; align-items: stretch; }
158
+ .auth-btn { justify-content: center; }
159
+ }
@@ -16,6 +16,9 @@
16
16
  import React, { useCallback, useEffect, useRef, useState } from "react";
17
17
  import { usePostHog } from "@/contexts/PostHogContext";
18
18
  import { fetchWithTimeout, isAbortError } from "@/lib/fetch-with-timeout";
19
+ // Co-located so the dialog is styled on EVERY route that renders it (/audit and
20
+ // /settings), not only the one route stylesheet these rules used to live in.
21
+ import "./auth-dialog.css";
19
22
 
20
23
  export interface AuthedUser {
21
24
  id: string;
@@ -255,155 +255,12 @@
255
255
  margin-right: 6px;
256
256
  }
257
257
 
258
- /* ───────────────────────── auth dialog (set-a-reminder gate) ───────────────────────── */
259
-
260
- .auth-dialog-backdrop {
261
- position: fixed; inset: 0; z-index: 10000;
262
- display: grid; place-items: center;
263
- padding: 32px 16px;
264
- background: rgba(8,8,10,0.7);
265
- backdrop-filter: blur(6px);
266
- -webkit-backdrop-filter: blur(6px);
267
- }
268
-
269
- .auth-dialog {
270
- position: relative;
271
- width: 100%;
272
- max-width: 420px;
273
- padding: 28px 28px 24px;
274
- border: 1px solid var(--line-2);
275
- background: var(--bg-2);
276
- font-family: var(--font-mono);
277
- color: var(--ink);
278
- }
279
-
280
- .auth-close {
281
- position: absolute; top: 12px; right: 14px;
282
- font-family: var(--font-mono); font-size: 20px;
283
- line-height: 1;
284
- color: var(--dim);
285
- background: transparent; border: none; padding: 4px 8px;
286
- cursor: pointer;
287
- transition: color 120ms;
288
- }
289
- .auth-close:hover { color: var(--accent-pink); }
290
- .auth-close:disabled { color: var(--line-2); cursor: not-allowed; }
291
-
292
- .auth-headline {
293
- font-family: var(--font-mono);
294
- font-size: 18px;
295
- font-weight: 600;
296
- letter-spacing: 0;
297
- line-height: 1.3;
298
- text-transform: none;
299
- color: var(--ink);
300
- margin: 0 0 8px;
301
- }
302
-
303
- .auth-sub {
304
- font-family: var(--font-mono); font-size: 12px;
305
- line-height: 1.55; color: var(--ink-2);
306
- margin: 0 0 18px;
307
- }
308
- .auth-sub .auth-email {
309
- color: var(--accent-pink);
310
- }
311
- .auth-sub .auth-ok {
312
- color: var(--accent-green);
313
- margin-right: 6px;
314
- }
315
-
316
- .auth-form { display: flex; flex-direction: column; gap: 10px; }
317
-
318
- .auth-field-label {
319
- font-family: var(--font-mono); font-size: 10px;
320
- letter-spacing: 0.22em; text-transform: uppercase;
321
- color: var(--accent-green);
322
- }
323
-
324
- .auth-input {
325
- width: 100%;
326
- padding: 11px 14px;
327
- background: var(--bg);
328
- border: 1px solid var(--line-2);
329
- color: var(--ink);
330
- font-family: var(--font-mono); font-size: 14px;
331
- letter-spacing: 0.03em;
332
- outline: none;
333
- transition: border-color 120ms, box-shadow 120ms;
334
- }
335
- .auth-input:focus {
336
- border-color: var(--accent-pink);
337
- box-shadow: 0 0 0 1px var(--accent-pink-soft);
338
- }
339
- .auth-input:disabled {
340
- opacity: 0.55; cursor: not-allowed;
341
- }
342
- .auth-input-code {
343
- letter-spacing: 0.5em;
344
- text-align: center;
345
- font-size: 18px;
346
- font-variant-numeric: tabular-nums;
347
- }
348
- .auth-input::placeholder { color: var(--dim); }
349
-
350
- .auth-error {
351
- font-family: var(--font-mono); font-size: 12px;
352
- color: var(--accent-pink);
353
- padding: 8px 12px;
354
- background: var(--accent-pink-bg);
355
- border: 1px solid var(--accent-pink);
356
- border-left-width: 3px;
357
- letter-spacing: 0.02em;
358
- margin-top: 4px;
359
- }
360
-
361
- .auth-actions {
362
- display: flex; gap: 10px; flex-wrap: wrap;
363
- margin-top: 14px;
364
- }
365
-
366
- .auth-btn {
367
- display: inline-flex; align-items: center; gap: 8px;
368
- padding: 10px 16px;
369
- font-family: var(--font-mono); font-size: 12px;
370
- letter-spacing: 0.06em;
371
- background: transparent;
372
- border: 1px solid var(--line-2);
373
- color: var(--ink);
374
- cursor: pointer;
375
- transition: all 120ms ease;
376
- }
377
- .auth-btn:hover:not(:disabled) {
378
- border-color: var(--ink); background: rgba(255,255,255,0.04);
379
- }
380
- .auth-btn:disabled { opacity: 0.45; cursor: not-allowed; }
381
- .auth-btn.primary {
382
- border-color: var(--accent-pink);
383
- color: var(--accent-pink);
384
- background: var(--accent-pink-bg);
385
- }
386
- .auth-btn.primary:hover:not(:disabled) {
387
- background: var(--accent-pink); color: var(--bg);
388
- }
389
-
390
- .auth-back {
391
- align-self: flex-start;
392
- margin-top: 4px;
393
- background: transparent; border: none; padding: 6px 0;
394
- font-family: var(--font-mono); font-size: 11px;
395
- letter-spacing: 0.1em; color: var(--dim);
396
- cursor: pointer;
397
- transition: color 120ms;
398
- }
399
- .auth-back:hover:not(:disabled) { color: var(--ink-2); }
400
- .auth-back:disabled { opacity: 0.45; cursor: not-allowed; }
401
-
402
- @media (max-width: 520px) {
403
- .auth-dialog { padding: 26px 22px 22px; }
404
- .auth-actions { flex-direction: column; align-items: stretch; }
405
- .auth-btn { justify-content: center; }
406
- }
258
+ /* ───────────────────────── auth dialog (set-a-reminder gate) ─────────────────────────
259
+ * The dialog's own styles moved to app/audit/_components/auth-dialog.css, which
260
+ * <AuthDialog> imports directly, so the modal is styled on every route that
261
+ * renders it (/audit and now /settings) rather than only this route stylesheet.
262
+ * The `.auth-status-pill` below stays here — it belongs to the /audit return
263
+ * CTA (come-back-better-section), not the dialog. */
407
264
 
408
265
  /* status pill in the return CTA: shows current logged-in email */
409
266
  .auth-status-pill {
@@ -0,0 +1,111 @@
1
+ "use client";
2
+
3
+ /**
4
+ * The dashboard's rendering of a paused machine.
5
+ *
6
+ * Split out of `hooks-client.tsx` because these are the pieces that keep the
7
+ * activity view honest: a row evaluated during a pause looks identical to one
8
+ * where every policy ran and allowed, and without saying so the log asserts a
9
+ * clean window over exactly the window that was not enforced.
10
+ */
11
+ import React, { useEffect, useState } from "react";
12
+ import { ShieldAlert, TriangleAlert } from "lucide-react";
13
+ import type { ActivePause } from "@/src/hooks/session-pause";
14
+
15
+ /** Compact "time left" for a future timestamp. */
16
+ export function formatRemaining(ms: number): string {
17
+ if (ms <= 0) return "expiring now";
18
+ // Sub-minute is checked before rounding: Math.round(30s) is "1m", which tells
19
+ // someone they have more time than they do. On a countdown to enforcement
20
+ // coming back, never round up.
21
+ if (ms < 60_000) return "under a minute";
22
+ const minutes = Math.round(ms / 60_000);
23
+ if (minutes < 60) return `${minutes}m`;
24
+ const hours = Math.floor(minutes / 60);
25
+ const rest = minutes % 60;
26
+ return rest === 0 ? `${hours}h` : `${hours}h${rest}m`;
27
+ }
28
+
29
+ /**
30
+ * Live state, not history: enforcement is paused RIGHT NOW.
31
+ *
32
+ * The rows below cannot carry this on their own — a pause set seconds ago has
33
+ * produced none yet, and that is precisely when someone needs telling that the
34
+ * machine is unguarded. An absent banner has to mean "enforcing", so this is fed
35
+ * from live pause state rather than inferred from whatever is on screen.
36
+ */
37
+ export function PausedBanner({ pauses, now: nowProp }: { pauses: ActivePause[]; now?: number }) {
38
+ const [tick, setTick] = useState(() => Date.now());
39
+ // Re-render on a timer so "22m left" does not sit frozen while the pause
40
+ // silently drains away.
41
+ useEffect(() => {
42
+ const id = setInterval(() => setTick(Date.now()), 30_000);
43
+ return () => clearInterval(id);
44
+ }, []);
45
+ const now = nowProp ?? tick;
46
+
47
+ // Filter again here rather than trusting the fetch: the list was accurate
48
+ // when it arrived, and a short pause can expire between polls.
49
+ const live = pauses.filter((p) => p.expiresAt > now);
50
+ if (live.length === 0) return null;
51
+ const soonest = live.reduce((a, b) => (a.expiresAt < b.expiresAt ? a : b));
52
+
53
+ return (
54
+ <div
55
+ role="status"
56
+ className="mb-4 flex items-start gap-2.5 rounded border border-amber-500/40 bg-amber-500/[0.07] px-3 py-2.5"
57
+ >
58
+ <ShieldAlert className="h-4 w-4 shrink-0 text-amber-500 mt-0.5" aria-hidden="true" />
59
+ <div className="text-xs leading-relaxed">
60
+ <p className="font-medium text-foreground">
61
+ Enforcement is paused for {live.length} session{live.length === 1 ? "" : "s"} —{" "}
62
+ {formatRemaining(soonest.expiresAt - now)} left
63
+ {live.length > 1 ? " on the next to expire" : ""}.
64
+ </p>
65
+ <p className="text-muted-foreground mt-0.5">
66
+ Builtin, custom and convention policies are suspended for{" "}
67
+ {live.length === 1 ? "that session" : "those sessions"}; cloud-managed policies keep
68
+ enforcing. It lifts on its own — or run{" "}
69
+ <span className="font-mono text-foreground">failproofai config --resume</span>.
70
+ </p>
71
+ </div>
72
+ </div>
73
+ );
74
+ }
75
+
76
+ /** Marks a row that was evaluated while enforcement was paused. */
77
+ export function PausedPill() {
78
+ return (
79
+ <span
80
+ title="Enforcement was paused for this session — local policies did not run"
81
+ className="ml-1.5 inline-flex items-center rounded px-1.5 py-0.5 text-[0.6rem] font-medium uppercase tracking-wide border border-amber-500/40 bg-amber-500/10 text-amber-600 dark:text-amber-500"
82
+ >
83
+ paused
84
+ </span>
85
+ );
86
+ }
87
+
88
+ /** Why an `allow` on this row proves nothing. */
89
+ export function PausedNote({
90
+ item,
91
+ }: {
92
+ item: { pausedBy?: string; pauseExpiresAt?: number };
93
+ }) {
94
+ if (!item.pausedBy) return null;
95
+ const lifted =
96
+ typeof item.pauseExpiresAt === "number"
97
+ ? new Date(item.pauseExpiresAt).toLocaleTimeString()
98
+ : null;
99
+ return (
100
+ <div className="sm:col-span-2 lg:col-span-3 mt-1 flex items-start gap-2 rounded border border-amber-500/30 bg-amber-500/5 px-2.5 py-2">
101
+ <TriangleAlert className="h-3.5 w-3.5 shrink-0 text-amber-500/80 mt-0.5" aria-hidden="true" />
102
+ <p className="text-[0.7rem] leading-relaxed text-muted-foreground">
103
+ <span className="font-medium text-foreground">Not enforced — paused.</span> Enforcement was
104
+ suspended for this session
105
+ {item.pausedBy === "cli" ? " from the CLI" : ` by ${item.pausedBy}`}
106
+ {lifted ? `, lifting at ${lifted}` : ""}. Builtin, custom and convention policies did not
107
+ run for this event; cloud-managed policies did.
108
+ </p>
109
+ </div>
110
+ );
111
+ }
@@ -7,6 +7,9 @@ import { Check, ChevronDown, Code, Copy, Settings, Shield, ShieldAlert, ShieldCh
7
7
  import PaginationControls from "@/app/components/pagination-controls";
8
8
  import { getHookActivityAction, searchHookActivityAction } from "@/app/actions/get-hook-activity";
9
9
  import type { HookActivityPayload } from "@/app/actions/get-hook-activity";
10
+ import { getActivePausesAction } from "@/app/actions/get-active-pauses";
11
+ import type { ActivePause } from "@/src/hooks/session-pause";
12
+ import { PausedBanner, PausedNote, PausedPill } from "@/app/components/pause-notices";
10
13
  import { getHooksConfigAction } from "@/app/actions/get-hooks-config";
11
14
  import type { HooksConfigPayload, PolicyInfo, CustomPolicyInfo } from "@/app/actions/get-hooks-config";
12
15
  import type { IntegrationType } from "@/src/hooks/types";
@@ -386,7 +389,27 @@ function DetailPanel({
386
389
  event detail
387
390
  </span>
388
391
  <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-x-8 gap-y-2">
392
+ <PausedNote item={item} />
389
393
  <EnforcementNote item={item} />
394
+ {item.policySource && (
395
+ <div>
396
+ <span className="text-muted-foreground">Decided by: </span>
397
+ <span className="font-mono text-foreground">
398
+ {item.policySource === "cloud" && item.cloudPolicyId
399
+ ? `cloud · ${item.cloudPolicyId} rev ${item.cloudRevision}`
400
+ : item.policySource}
401
+ </span>
402
+ </div>
403
+ )}
404
+ {item.cloudGeneration !== undefined && (
405
+ <div>
406
+ {/* Present on every row of a managed machine, not just cloud
407
+ decisions — it is what separates a rollout that changed no
408
+ outcomes from one that never arrived. */}
409
+ <span className="text-muted-foreground">Cloud generation: </span>
410
+ <span className="font-mono text-foreground">{item.cloudGeneration}</span>
411
+ </div>
412
+ )}
390
413
  <div>
391
414
  <span className="text-muted-foreground">Session ID: </span>
392
415
  <span className="font-mono text-foreground">
@@ -443,6 +466,7 @@ function ActivityTab({
443
466
 
444
467
  const [page, setPage] = useState(() => paramToPage(url.get("page")));
445
468
  const [data, setData] = useState<HookActivityPayload | null>(null);
469
+ const [activePauses, setActivePauses] = useState<ActivePause[]>([]);
446
470
  const [expandedRow, setExpandedRow] = useState<number | null>(null);
447
471
 
448
472
  const [filterDecision, setFilterDecision] = useState<"" | "allow" | "deny" | "instruct">(() => {
@@ -456,10 +480,14 @@ function ActivityTab({
456
480
  const v = url.get("cli");
457
481
  return isKnownCli(v) ? v : "";
458
482
  });
483
+ const [filterSource, setFilterSource] = useState<"" | "builtin" | "custom" | "convention" | "cloud">(() => {
484
+ const v = url.get("source");
485
+ return v === "builtin" || v === "custom" || v === "convention" || v === "cloud" ? v : "";
486
+ });
459
487
  const debounceRef = useRef<ReturnType<typeof setTimeout> | null>(null);
460
488
  const filterTelemetryFirstRunRef = useRef(true);
461
- const filtersRef = useRef({ filterDecision, filterEventType, filterPolicy, filterSessionId, filterCli });
462
- filtersRef.current = { filterDecision, filterEventType, filterPolicy, filterSessionId, filterCli };
489
+ const filtersRef = useRef({ filterDecision, filterEventType, filterPolicy, filterSessionId, filterCli, filterSource });
490
+ filtersRef.current = { filterDecision, filterEventType, filterPolicy, filterSessionId, filterCli, filterSource };
463
491
 
464
492
  useEffect(() => {
465
493
  if (!mountedRef.current) {
@@ -472,17 +500,18 @@ function ActivityTab({
472
500
  policy: filterPolicy || undefined,
473
501
  session: filterSessionId || undefined,
474
502
  cli: filterCli || undefined,
503
+ source: filterSource || undefined,
475
504
  page: pageToParam(page),
476
505
  });
477
506
  // eslint-disable-next-line react-hooks/exhaustive-deps
478
- }, [filterDecision, filterEventType, filterPolicy, filterSessionId, filterCli, page]);
507
+ }, [filterDecision, filterEventType, filterPolicy, filterSessionId, filterCli, filterSource, page]);
479
508
 
480
- const hasActiveFilters = filterDecision !== "" || filterEventType !== "" || filterPolicy !== "" || filterSessionId !== "" || filterCli !== "";
509
+ const hasActiveFilters = filterDecision !== "" || filterEventType !== "" || filterPolicy !== "" || filterSessionId !== "" || filterCli !== "" || filterSource !== "";
481
510
 
482
511
  const fetchData = useCallback(async (p: number) => {
483
512
  try {
484
- const { filterDecision: fd, filterEventType: fe, filterPolicy: fp, filterSessionId: fs, filterCli: fc } = filtersRef.current;
485
- const active = fd !== "" || fe !== "" || fp !== "" || fs !== "" || fc !== "";
513
+ const { filterDecision: fd, filterEventType: fe, filterPolicy: fp, filterSessionId: fs, filterCli: fc, filterSource: fsrc } = filtersRef.current;
514
+ const active = fd !== "" || fe !== "" || fp !== "" || fs !== "" || fc !== "" || fsrc !== "";
486
515
  let result: HookActivityPayload;
487
516
  if (active) {
488
517
  result = await searchHookActivityAction(
@@ -492,6 +521,7 @@ function ActivityTab({
492
521
  policyName: fp || undefined,
493
522
  sessionId: fs || undefined,
494
523
  integration: fc || undefined,
524
+ source: fsrc || undefined,
495
525
  },
496
526
  p,
497
527
  );
@@ -511,6 +541,22 @@ function ActivityTab({
511
541
  return () => clearInterval(id);
512
542
  }, [page, fetchData, intervalSec]);
513
543
 
544
+ // Pause state is polled independently of the activity page: it is live
545
+ // machine state, not a property of whichever rows are on screen, and it must
546
+ // keep updating while the user sits on page 3 of history.
547
+ useEffect(() => {
548
+ let cancelled = false;
549
+ const load = () => {
550
+ getActivePausesAction()
551
+ .then((p) => { if (!cancelled) setActivePauses(p); })
552
+ .catch(() => { /* non-critical: the banner simply stays hidden */ });
553
+ };
554
+ load();
555
+ const ms = intervalSec > 0 ? intervalSec * 1000 : 5000;
556
+ const id = setInterval(load, ms);
557
+ return () => { cancelled = true; clearInterval(id); };
558
+ }, [intervalSec]);
559
+
514
560
  useEffect(() => {
515
561
  if (debounceRef.current) clearTimeout(debounceRef.current);
516
562
  debounceRef.current = setTimeout(() => {
@@ -565,6 +611,10 @@ function ActivityTab({
565
611
 
566
612
  return (
567
613
  <>
614
+ {/* Above the stats, deliberately: a paused machine is the most important
615
+ thing on this screen, and the numbers below it are being produced with
616
+ local enforcement switched off. */}
617
+ <PausedBanner pauses={activePauses} />
568
618
  {data?.stats && data.stats.totalEvents > 0 && (
569
619
  <div style={{ marginBottom: 18 }}>
570
620
  <StatsBar stats={data.stats} />
@@ -593,6 +643,29 @@ function ActivityTab({
593
643
  <option value="PermissionRequest">PermissionRequest</option>
594
644
  </select>
595
645
  </div>
646
+ <div className="filter-group">
647
+ {/* "What did my organization's policies decide here?" is the
648
+ question cloud rollout reporting rests on, and it is
649
+ unanswerable while the source is only a prefix on a name. */}
650
+ <span className="filter-label">source</span>
651
+ <select
652
+ value={filterSource}
653
+ onChange={(e) => {
654
+ const v = e.target.value;
655
+ setFilterSource(
656
+ v === "builtin" || v === "custom" || v === "convention" || v === "cloud" ? v : "",
657
+ );
658
+ }}
659
+ className="filter-input"
660
+ aria-label="Filter by policy source"
661
+ >
662
+ <option value="">all sources</option>
663
+ <option value="builtin">builtin</option>
664
+ <option value="custom">custom</option>
665
+ <option value="convention">convention</option>
666
+ <option value="cloud">cloud</option>
667
+ </select>
668
+ </div>
596
669
  <div className="filter-group">
597
670
  <span className="filter-label">cli</span>
598
671
  <select
@@ -642,6 +715,7 @@ function ActivityTab({
642
715
  setFilterCli("");
643
716
  setFilterPolicy("");
644
717
  setFilterSessionId("");
718
+ setFilterSource("");
645
719
  }}
646
720
  aria-label="Clear all filters"
647
721
  >
@@ -744,6 +818,7 @@ function ActivityTab({
744
818
  </td>
745
819
  <td className="px-3 py-2">
746
820
  <DecisionBadge decision={item.decision} />
821
+ {item.pausedBy && <PausedPill />}
747
822
  </td>
748
823
  <td className="px-3 py-2">
749
824
  <EventTypeBadge eventType={item.eventType} />
@@ -0,0 +1,31 @@
1
+ /**
2
+ * /settings — one page, sections. The single home for the machine-level
3
+ * controls the design plan collected here: the scheduled local audit and
4
+ * emailed audit reports.
5
+ *
6
+ * Deliberately NOT a home for telemetry: the product decision is that telemetry
7
+ * is documented but not advertised in-product, so there is no telemetry control
8
+ * or status on this page. `config.toml` plus the docs are the whole story.
9
+ *
10
+ * Thin server wrapper (Suspense boundary + the disabled-pages gate every route
11
+ * uses); all the reads/writes live in the client and its server actions.
12
+ */
13
+ import { Suspense } from "react";
14
+ import { notFound } from "next/navigation";
15
+ import SettingsClient from "./settings-client";
16
+
17
+ export const dynamic = "force-dynamic";
18
+
19
+ export default async function SettingsPage() {
20
+ const disabled = (process.env.FAILPROOFAI_DISABLE_PAGES ?? "")
21
+ .split(",")
22
+ .map((s) => s.trim())
23
+ .filter(Boolean);
24
+ if (disabled.includes("settings")) notFound();
25
+
26
+ return (
27
+ <Suspense>
28
+ <SettingsClient />
29
+ </Suspense>
30
+ );
31
+ }