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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (369) hide show
  1. package/.next/standalone/.next/BUILD_ID +1 -1
  2. package/.next/standalone/.next/app-path-routes-manifest.json +2 -1
  3. package/.next/standalone/.next/build-manifest.json +3 -3
  4. package/.next/standalone/.next/prerender-manifest.json +3 -3
  5. package/.next/standalone/.next/required-server-files.json +1 -1
  6. package/.next/standalone/.next/routes-manifest.json +6 -0
  7. package/.next/standalone/.next/server/app/_global-error/page/server-reference-manifest.json +1 -1
  8. package/.next/standalone/.next/server/app/_global-error/page.js +3 -1
  9. package/.next/standalone/.next/server/app/_global-error/page.js.nft.json +1 -1
  10. package/.next/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  11. package/.next/standalone/.next/server/app/_global-error.html +1 -1
  12. package/.next/standalone/.next/server/app/_global-error.rsc +7 -7
  13. package/.next/standalone/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +2 -2
  14. package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +7 -7
  15. package/.next/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +3 -3
  16. package/.next/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +3 -3
  17. package/.next/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  18. package/.next/standalone/.next/server/app/_not-found/page/server-reference-manifest.json +1 -1
  19. package/.next/standalone/.next/server/app/_not-found/page.js +3 -1
  20. package/.next/standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
  21. package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  22. package/.next/standalone/.next/server/app/_not-found.html +1 -1
  23. package/.next/standalone/.next/server/app/_not-found.rsc +15 -15
  24. package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +15 -15
  25. package/.next/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +4 -4
  26. package/.next/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +10 -10
  27. package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +2 -2
  28. package/.next/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +3 -3
  29. package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  30. package/.next/standalone/.next/server/app/api/audit/invite/route.js +3 -2
  31. package/.next/standalone/.next/server/app/api/audit/invite/route.js.nft.json +1 -1
  32. package/.next/standalone/.next/server/app/api/audit/run/route.js +4 -3
  33. package/.next/standalone/.next/server/app/api/audit/run/route.js.nft.json +1 -1
  34. package/.next/standalone/.next/server/app/api/audit/status/route.js +1 -1
  35. package/.next/standalone/.next/server/app/api/audit/status/route.js.nft.json +1 -1
  36. package/.next/standalone/.next/server/app/api/auth/login-request/route.js +2 -1
  37. package/.next/standalone/.next/server/app/api/auth/login-request/route.js.nft.json +1 -1
  38. package/.next/standalone/.next/server/app/api/auth/login-verify/route.js +3 -2
  39. package/.next/standalone/.next/server/app/api/auth/login-verify/route.js.nft.json +1 -1
  40. package/.next/standalone/.next/server/app/api/auth/logout/route.js +3 -2
  41. package/.next/standalone/.next/server/app/api/auth/logout/route.js.nft.json +1 -1
  42. package/.next/standalone/.next/server/app/api/auth/reminder/route.js +3 -2
  43. package/.next/standalone/.next/server/app/api/auth/reminder/route.js.nft.json +1 -1
  44. package/.next/standalone/.next/server/app/api/auth/status/route.js +3 -2
  45. package/.next/standalone/.next/server/app/api/auth/status/route.js.nft.json +1 -1
  46. package/.next/standalone/.next/server/app/api/download/[project]/[session]/route.js +1 -1
  47. package/.next/standalone/.next/server/app/api/download/[project]/[session]/route.js.nft.json +1 -1
  48. package/.next/standalone/.next/server/app/audit/page/server-reference-manifest.json +2 -2
  49. package/.next/standalone/.next/server/app/audit/page.js +5 -3
  50. package/.next/standalone/.next/server/app/audit/page.js.nft.json +1 -1
  51. package/.next/standalone/.next/server/app/audit/page_client-reference-manifest.js +1 -1
  52. package/.next/standalone/.next/server/app/index.html +1 -1
  53. package/.next/standalone/.next/server/app/index.rsc +15 -15
  54. package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  55. package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +15 -15
  56. package/.next/standalone/.next/server/app/index.segments/_head.segment.rsc +4 -4
  57. package/.next/standalone/.next/server/app/index.segments/_index.segment.rsc +10 -10
  58. package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -2
  59. package/.next/standalone/.next/server/app/page/server-reference-manifest.json +1 -1
  60. package/.next/standalone/.next/server/app/page.js +3 -1
  61. package/.next/standalone/.next/server/app/page.js.nft.json +1 -1
  62. package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  63. package/.next/standalone/.next/server/app/policies/page/server-reference-manifest.json +10 -10
  64. package/.next/standalone/.next/server/app/policies/page.js +4 -2
  65. package/.next/standalone/.next/server/app/policies/page.js.nft.json +1 -1
  66. package/.next/standalone/.next/server/app/policies/page_client-reference-manifest.js +1 -1
  67. package/.next/standalone/.next/server/app/project/[name]/page/server-reference-manifest.json +1 -1
  68. package/.next/standalone/.next/server/app/project/[name]/page.js +4 -2
  69. package/.next/standalone/.next/server/app/project/[name]/page.js.nft.json +1 -1
  70. package/.next/standalone/.next/server/app/project/[name]/page_client-reference-manifest.js +1 -1
  71. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/react-loadable-manifest.json +2 -2
  72. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/server-reference-manifest.json +2 -2
  73. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page.js +6 -4
  74. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page.js.nft.json +1 -1
  75. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page_client-reference-manifest.js +1 -1
  76. package/.next/standalone/.next/server/app/projects/page/server-reference-manifest.json +1 -1
  77. package/.next/standalone/.next/server/app/projects/page.js +4 -2
  78. package/.next/standalone/.next/server/app/projects/page.js.nft.json +1 -1
  79. package/.next/standalone/.next/server/app/projects/page_client-reference-manifest.js +1 -1
  80. package/.next/standalone/.next/server/app/settings/page/app-paths-manifest.json +3 -0
  81. package/.next/standalone/.next/server/app/settings/page/build-manifest.json +18 -0
  82. package/.next/standalone/.next/server/app/settings/page/next-font-manifest.json +6 -0
  83. package/.next/standalone/.next/server/app/settings/page/react-loadable-manifest.json +1 -0
  84. package/.next/standalone/.next/server/app/settings/page/server-reference-manifest.json +53 -0
  85. package/.next/standalone/.next/server/app/settings/page.js +18 -0
  86. package/.next/standalone/.next/server/app/settings/page.js.map +5 -0
  87. package/.next/standalone/.next/server/app/settings/page.js.nft.json +1 -0
  88. package/.next/standalone/.next/server/app/settings/page_client-reference-manifest.js +3 -0
  89. package/.next/standalone/.next/server/app-paths-manifest.json +2 -1
  90. package/.next/standalone/.next/server/chunks/{[externals]__1nl3dvw._.js → [externals]__0r-zamh._.js} +2 -2
  91. package/.next/standalone/.next/server/chunks/[root-of-the-server]__06hexd0._.js +3 -0
  92. package/.next/standalone/.next/server/chunks/[root-of-the-server]__094p1f1._.js +3 -0
  93. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0_0xu5z._.js +1 -1
  94. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0ed01_d._.js +3 -0
  95. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0g0vcwt._.js +3 -0
  96. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0h3lfmp._.js → [root-of-the-server]__0ky_n0r._.js} +2 -2
  97. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__18d-9oi._.js → [root-of-the-server]__0lk_935._.js} +2 -2
  98. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__1p7s8-d._.js → [root-of-the-server]__0pbp9fe._.js} +2 -2
  99. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0q-v9z2._.js +1 -1
  100. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__10oa-v9._.js → [root-of-the-server]__0v2fpxe._.js} +2 -2
  101. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0sb_5m8._.js → [root-of-the-server]__131ebum._.js} +3 -3
  102. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0-dh5jy._.js → [root-of-the-server]__1_ps0jw._.js} +2 -2
  103. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0l4vuqm._.js → [root-of-the-server]__1a7i2q4._.js} +1 -1
  104. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1ibjy5x._.js +3 -0
  105. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1iny24d._.js +3 -0
  106. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1tvn4wf._.js +1 -1
  107. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1tyedjt._.js +3 -0
  108. package/.next/standalone/.next/server/chunks/_0lxbzdq._.js +5 -0
  109. package/.next/standalone/.next/server/chunks/_1zuiiy3._.js +5 -0
  110. package/.next/standalone/.next/server/chunks/lib_telemetry_ts_0dctyyw._.js +5 -0
  111. package/.next/standalone/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_17k9e3w.js +5 -5
  112. package/.next/standalone/.next/server/chunks/package_json_[json]_cjs_1nxcc4v._.js +1 -1
  113. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__06bp_fg._.js +5 -0
  114. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__074qmkp._.js +3 -0
  115. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0spkm68._.js +10 -10
  116. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1_a_gwn._.js +3 -0
  117. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1a2hcb_._.js +3 -0
  118. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1e7-pa7._.js +3 -0
  119. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0rtdfof._.js → [root-of-the-server]__1rdruw4._.js} +1 -1
  120. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1rv-sc9._.js +3 -0
  121. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1tyf0tc._.js +5 -0
  122. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1u-wx42._.js +4 -0
  123. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1v185mo._.js +3 -0
  124. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0rag5dg._.js → [root-of-the-server]__1yw368c._.js} +2 -2
  125. package/.next/standalone/.next/server/chunks/ssr/_0-yi74u._.js +3 -0
  126. package/.next/standalone/.next/server/chunks/ssr/_04mekdy._.js +3 -0
  127. package/.next/standalone/.next/server/chunks/ssr/_0igtyj5._.js +3 -0
  128. package/.next/standalone/.next/server/chunks/ssr/_0r-dsre._.js +3 -0
  129. package/.next/standalone/.next/server/chunks/ssr/_0rjgfln._.js +3 -0
  130. package/.next/standalone/.next/server/chunks/ssr/_0se484m._.js +3 -0
  131. package/.next/standalone/.next/server/chunks/ssr/_0uz7o9y._.js +3 -0
  132. package/.next/standalone/.next/server/chunks/ssr/_11_p9y8._.js +1 -1
  133. package/.next/standalone/.next/server/chunks/ssr/_1fahg9e._.js +3 -0
  134. package/.next/standalone/.next/server/chunks/ssr/_1gmzkwj._.js +5 -0
  135. package/.next/standalone/.next/server/chunks/ssr/_1w8sola._.js +3 -0
  136. package/.next/standalone/.next/server/chunks/ssr/_1w_6p9g._.js +3 -0
  137. package/.next/standalone/.next/server/chunks/ssr/app_audit__components_audit-dashboard_tsx_0p9ud47._.js +2 -2
  138. package/.next/standalone/.next/server/chunks/ssr/app_global-error_tsx_1kp6l3x._.js +1 -1
  139. package/.next/standalone/.next/server/chunks/ssr/app_policies_hooks-client_tsx_19dqvpc._.js +2 -2
  140. package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0dwo94s.js +4 -0
  141. package/.next/standalone/.next/server/chunks/ssr/src_hooks_builtin-policies_ts_09j2ndl._.js +3 -0
  142. package/.next/standalone/.next/server/chunks/ssr/src_hooks_fp-config_ts_04t589g._.js +5 -0
  143. package/.next/standalone/.next/server/middleware-build-manifest.js +3 -3
  144. package/.next/standalone/.next/server/middleware.js +2 -2
  145. package/.next/standalone/.next/server/pages/404.html +1 -1
  146. package/.next/standalone/.next/server/pages/500.html +1 -1
  147. package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
  148. package/.next/standalone/.next/server/server-reference-manifest.json +54 -12
  149. package/.next/standalone/.next/static/chunks/{2c90h1g6x8z8y.js → 0_2n13i94rnw5.js} +1 -1
  150. package/.next/standalone/.next/static/chunks/1bm0q12hgs22l.css +2 -0
  151. package/.next/standalone/.next/static/chunks/1v1gqvpjk62jm.js +1 -0
  152. package/.next/standalone/.next/static/chunks/23557z4e6dtsr.js +1 -0
  153. package/.next/standalone/.next/static/chunks/28zkwzu50puki.js +1 -0
  154. package/.next/standalone/.next/static/chunks/2uvhw57mf9lg_.css +2 -0
  155. package/.next/standalone/.next/static/chunks/3081gykdubv8b.js +1 -0
  156. package/.next/standalone/.next/static/chunks/{06jakt_xhoolk.js → 34fa65k0cldkj.js} +1 -1
  157. package/.next/standalone/.next/static/chunks/35v07j9gc1pvr.js +6 -0
  158. package/.next/standalone/.next/static/chunks/{2zb3m1tzq6h98.js → 3f_939wi3kfnx.js} +22 -22
  159. package/.next/standalone/.next/static/chunks/{31cqiv_cpgj9m.js → 3p1vpm2_-tfwm.js} +1 -1
  160. package/.next/standalone/.next/static/chunks/{0ue9ak_xexiqh.js → 3rbpw_waieafm.js} +1 -1
  161. package/.next/standalone/.next/static/chunks/40ffnfpkeyvb0.js +1 -0
  162. package/.next/standalone/app/actions/get-hooks-config.ts +2 -1
  163. package/.next/standalone/app/actions/get-scheduled-audit.ts +70 -0
  164. package/.next/standalone/app/actions/update-scheduled-audit.ts +44 -0
  165. package/.next/standalone/app/api/audit/run/route.ts +28 -0
  166. package/.next/standalone/app/api/audit/status/route.ts +13 -1
  167. package/.next/standalone/app/api/auth/status/route.ts +1 -1
  168. package/.next/standalone/app/audit/_components/auth-dialog.css +159 -0
  169. package/.next/standalone/app/audit/_components/auth-dialog.tsx +3 -0
  170. package/.next/standalone/app/audit/audit-styles.css +6 -149
  171. package/.next/standalone/app/settings/page.tsx +31 -0
  172. package/.next/standalone/app/settings/settings-client.tsx +488 -0
  173. package/.next/standalone/components/navbar.tsx +2 -0
  174. package/.next/standalone/lib/auth/api-server-client.ts +2 -3
  175. package/.next/standalone/lib/auth/auth-store.ts +4 -4
  176. package/.next/standalone/lib/codex-sessions.ts +2 -1
  177. package/.next/standalone/lib/dashboard-host.ts +101 -0
  178. package/.next/standalone/lib/install-check.ts +22 -7
  179. package/.next/standalone/lib/pi-sessions.ts +99 -14
  180. package/.next/standalone/lib/telemetry-enabled.ts +54 -0
  181. package/.next/standalone/lib/telemetry-id.ts +52 -1
  182. package/.next/standalone/lib/telemetry.ts +8 -4
  183. package/.next/standalone/node_modules/react/cjs/react.development.js +1 -1
  184. package/.next/standalone/node_modules/react/cjs/react.production.js +1 -1
  185. package/.next/standalone/node_modules/react/package.json +3 -3
  186. package/.next/standalone/node_modules/react-dom/cjs/react-dom-server-legacy.browser.production.js +1 -1
  187. package/.next/standalone/node_modules/react-dom/cjs/react-dom-server-legacy.node.production.js +1 -1
  188. package/.next/standalone/node_modules/react-dom/cjs/react-dom-server.browser.production.js +3 -3
  189. package/.next/standalone/node_modules/react-dom/cjs/react-dom-server.edge.production.js +3 -3
  190. package/.next/standalone/node_modules/react-dom/cjs/react-dom-server.node.production.js +3 -3
  191. package/.next/standalone/node_modules/react-dom/cjs/react-dom.production.js +1 -1
  192. package/.next/standalone/node_modules/react-dom/package.json +4 -4
  193. package/.next/standalone/package.json +7 -6
  194. package/.next/standalone/proxy.ts +89 -1
  195. package/.next/standalone/server.js +1 -1
  196. package/bin/failproofai.mjs +197 -80
  197. package/dist/cli.mjs +17699 -15345
  198. package/dist/worker.mjs +1620 -257
  199. package/lib/auth/api-server-client.ts +2 -3
  200. package/lib/auth/auth-store.ts +4 -4
  201. package/lib/codex-sessions.ts +2 -1
  202. package/lib/dashboard-host.ts +101 -0
  203. package/lib/install-check.ts +22 -7
  204. package/lib/pi-sessions.ts +99 -14
  205. package/lib/telemetry-enabled.ts +54 -0
  206. package/lib/telemetry-id.ts +52 -1
  207. package/lib/telemetry.ts +8 -4
  208. package/package.json +7 -6
  209. package/scripts/install-telemetry.mjs +8 -1
  210. package/scripts/launch.ts +25 -3
  211. package/scripts/parse-script-args.ts +17 -1
  212. package/scripts/prune-standalone.mjs +20 -0
  213. package/scripts/translate-docs/readme-translator.ts +163 -4
  214. package/scripts/validate-mdx.ts +153 -13
  215. package/src/audit/audit-lock.ts +285 -0
  216. package/src/audit/audit-schedule.ts +111 -0
  217. package/src/audit/cache.ts +18 -4
  218. package/src/audit/cli-adapters/goose.ts +2 -1
  219. package/src/audit/cli-adapters/hermes.ts +28 -10
  220. package/src/audit/cli.ts +191 -35
  221. package/src/audit/dashboard-cache.ts +2 -1
  222. package/src/hooks/builtin-policies.ts +100 -3
  223. package/src/hooks/cloud-connection.ts +163 -14
  224. package/src/hooks/cloud-enrollment-cli.ts +119 -21
  225. package/src/hooks/cloud-enrollment.ts +87 -17
  226. package/src/hooks/cloud-introspect.ts +147 -0
  227. package/src/hooks/cloud-managed-policies.ts +33 -2
  228. package/src/hooks/collector-config.ts +32 -40
  229. package/src/hooks/configure-wizard.ts +696 -318
  230. package/src/hooks/custom-hooks-loader.ts +125 -11
  231. package/src/hooks/daemon-client.ts +83 -17
  232. package/src/hooks/daemon-download.ts +54 -2
  233. package/src/hooks/daemon-service.ts +595 -27
  234. package/src/hooks/first-run-gate.ts +39 -0
  235. package/src/hooks/fp-config.ts +497 -0
  236. package/src/hooks/fp-home.ts +342 -0
  237. package/src/hooks/fp-reset.ts +332 -0
  238. package/src/hooks/handler.ts +42 -1
  239. package/src/hooks/hook-activity-store.ts +35 -20
  240. package/src/hooks/hook-logger.ts +2 -1
  241. package/src/hooks/hook-telemetry.ts +5 -1
  242. package/src/hooks/hooks-config.ts +4 -3
  243. package/src/hooks/loader-utils.ts +166 -5
  244. package/src/hooks/manager.ts +5 -4
  245. package/src/hooks/onboarding-lock.ts +119 -0
  246. package/src/hooks/policy-types.ts +0 -7
  247. package/src/hooks/session-pause-cli.ts +15 -13
  248. package/src/hooks/session-pause.ts +36 -4
  249. package/src/hooks/setup-state.ts +256 -0
  250. package/src/hooks/tui.ts +4 -4
  251. package/src/hooks/worker-server.ts +53 -1
  252. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0f8nu8d._.js +0 -3
  253. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0szqzl8._.js +0 -3
  254. package/.next/standalone/.next/server/chunks/[root-of-the-server]__17g9wh7._.js +0 -3
  255. package/.next/standalone/.next/server/chunks/[root-of-the-server]__19120tr._.js +0 -3
  256. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1fwl2mz._.js +0 -3
  257. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1myjm-d._.js +0 -3
  258. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1rhmvod._.js +0 -3
  259. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__02r5bgf._.js +0 -4
  260. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0cmdyn_._.js +0 -3
  261. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0e8sjqm._.js +0 -4
  262. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0lkzqax._.js +0 -4
  263. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0ls0gsr._.js +0 -4
  264. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0n_uvv0._.js +0 -3
  265. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0qucxyj._.js +0 -4
  266. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0sdrz-j._.js +0 -3
  267. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0u02miy._.js +0 -4
  268. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__14dd6h8._.js +0 -3
  269. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1j4u3yd._.js +0 -4
  270. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1zqz4v8._.js +0 -4
  271. package/.next/standalone/.next/server/chunks/ssr/_1m_p7pi._.js +0 -3
  272. package/.next/standalone/.next/server/chunks/ssr/node_modules_html-to-image_es_index_1q9xxca.js +0 -3
  273. package/.next/standalone/.next/server/chunks/ssr/src_hooks_1ezd2jf._.js +0 -5
  274. package/.next/standalone/.next/server/chunks/ssr/src_hooks_1tnuifj._.js +0 -5
  275. package/.next/standalone/.next/static/chunks/0h7auy7hzjyhw.js +0 -1
  276. package/.next/standalone/.next/static/chunks/0oe2-hp0_2tzs.js +0 -6
  277. package/.next/standalone/.next/static/chunks/1fw3pxobk_otl.js +0 -1
  278. package/.next/standalone/.next/static/chunks/3h5_3u46gu9jx.js +0 -1
  279. package/.next/standalone/.next/static/chunks/3i27c3hcriawq.css +0 -1
  280. package/.next/standalone/.next/static/chunks/3zdwnnthucs_1.css +0 -2
  281. package/.next/standalone/.next/static/chunks/43a1ywqsg9bq9.js +0 -1
  282. package/.next/standalone/Cargo.lock +0 -2222
  283. package/.next/standalone/Cargo.toml +0 -9
  284. package/.next/standalone/crates/CLOUD_POLICIES.md +0 -136
  285. package/.next/standalone/crates/PROTOCOL.md +0 -122
  286. package/.next/standalone/crates/failproofaid/Cargo.toml +0 -25
  287. package/.next/standalone/crates/failproofaid/src/cloud_client.rs +0 -484
  288. package/.next/standalone/crates/failproofaid/src/cloud_policies.rs +0 -921
  289. package/.next/standalone/crates/failproofaid/src/lock.rs +0 -81
  290. package/.next/standalone/crates/failproofaid/src/main.rs +0 -532
  291. package/.next/standalone/crates/failproofaid/src/paths.rs +0 -201
  292. package/.next/standalone/crates/failproofaid/src/server.rs +0 -502
  293. package/.next/standalone/crates/failproofaid/src/worker.rs +0 -400
  294. package/.next/standalone/crates/failproofaid/tests/daemon_e2e.rs +0 -241
  295. package/.next/standalone/crates/fpai-collect/Cargo.toml +0 -43
  296. package/.next/standalone/crates/fpai-collect/src/config.rs +0 -412
  297. package/.next/standalone/crates/fpai-collect/src/cursor.rs +0 -520
  298. package/.next/standalone/crates/fpai-collect/src/delivery.rs +0 -472
  299. package/.next/standalone/crates/fpai-collect/src/filetail.rs +0 -484
  300. package/.next/standalone/crates/fpai-collect/src/health.rs +0 -369
  301. package/.next/standalone/crates/fpai-collect/src/lib.rs +0 -34
  302. package/.next/standalone/crates/fpai-collect/src/redact.rs +0 -516
  303. package/.next/standalone/crates/fpai-collect/src/sources/claude/mod.rs +0 -279
  304. package/.next/standalone/crates/fpai-collect/src/sources/claude/transform.rs +0 -619
  305. package/.next/standalone/crates/fpai-collect/src/sources/codex/mod.rs +0 -156
  306. package/.next/standalone/crates/fpai-collect/src/sources/codex/transform.rs +0 -715
  307. package/.next/standalone/crates/fpai-collect/src/sources/copilot/mod.rs +0 -158
  308. package/.next/standalone/crates/fpai-collect/src/sources/copilot/transform.rs +0 -512
  309. package/.next/standalone/crates/fpai-collect/src/sources/goose/mod.rs +0 -511
  310. package/.next/standalone/crates/fpai-collect/src/sources/goose/transform.rs +0 -586
  311. package/.next/standalone/crates/fpai-collect/src/sources/hermes/mod.rs +0 -318
  312. package/.next/standalone/crates/fpai-collect/src/sources/hermes/transform.rs +0 -579
  313. package/.next/standalone/crates/fpai-collect/src/sources/hooks/mod.rs +0 -310
  314. package/.next/standalone/crates/fpai-collect/src/sources/hooks/transform.rs +0 -448
  315. package/.next/standalone/crates/fpai-collect/src/sources/mod.rs +0 -23
  316. package/.next/standalone/crates/fpai-collect/src/sources/openclaw/mod.rs +0 -176
  317. package/.next/standalone/crates/fpai-collect/src/sources/openclaw/transform.rs +0 -500
  318. package/.next/standalone/crates/fpai-collect/src/sources/opencode/mod.rs +0 -315
  319. package/.next/standalone/crates/fpai-collect/src/sources/opencode/transform.rs +0 -493
  320. package/.next/standalone/crates/fpai-collect/src/sources/pi/mod.rs +0 -201
  321. package/.next/standalone/crates/fpai-collect/src/sources/pi/transform.rs +0 -533
  322. package/.next/standalone/crates/fpai-collect/src/spool.rs +0 -458
  323. package/.next/standalone/crates/fpai-collect/src/sqlitepoll.rs +0 -387
  324. package/.next/standalone/crates/fpai-collect/src/supervisor.rs +0 -423
  325. package/.next/standalone/crates/fpai-collect/src/uploader.rs +0 -600
  326. package/.next/standalone/crates/fpai-collect/tests/claude_source.rs +0 -738
  327. package/.next/standalone/crates/fpai-collect/tests/claude_subagents.rs +0 -393
  328. package/.next/standalone/crates/fpai-collect/tests/codex_source.rs +0 -975
  329. package/.next/standalone/crates/fpai-collect/tests/config.rs +0 -286
  330. package/.next/standalone/crates/fpai-collect/tests/copilot_source.rs +0 -1019
  331. package/.next/standalone/crates/fpai-collect/tests/delivery.rs +0 -281
  332. package/.next/standalone/crates/fpai-collect/tests/goose_source.rs +0 -1008
  333. package/.next/standalone/crates/fpai-collect/tests/hermes_source.rs +0 -1129
  334. package/.next/standalone/crates/fpai-collect/tests/hooks_source.rs +0 -621
  335. package/.next/standalone/crates/fpai-collect/tests/openclaw_source.rs +0 -854
  336. package/.next/standalone/crates/fpai-collect/tests/opencode_source.rs +0 -1478
  337. package/.next/standalone/crates/fpai-collect/tests/pi_source.rs +0 -1191
  338. package/.next/standalone/crates/fpai-collect/tests/supervisor.rs +0 -290
  339. package/.next/standalone/crates/fpai-collect/tests/uploader.rs +0 -506
  340. package/.next/standalone/crates/fpai-ipc/Cargo.toml +0 -16
  341. package/.next/standalone/crates/fpai-ipc/src/envelope.rs +0 -175
  342. package/.next/standalone/crates/fpai-ipc/src/framing.rs +0 -177
  343. package/.next/standalone/crates/fpai-ipc/src/lib.rs +0 -10
  344. package/.next/standalone/crates/fpai-ipc/src/peer.rs +0 -80
  345. package/.next/standalone/docker-hook-sync/Dockerfile +0 -79
  346. package/.next/standalone/docker-hook-sync/entrypoint.sh +0 -109
  347. package/.next/standalone/integration-suite/Dockerfile +0 -47
  348. package/.next/standalone/integration-suite/README.md +0 -129
  349. package/.next/standalone/integration-suite/canary-policies.mjs +0 -45
  350. package/.next/standalone/integration-suite/capture-tokens.sh +0 -48
  351. package/.next/standalone/integration-suite/ci-entrypoint.sh +0 -179
  352. package/.next/standalone/integration-suite/inject-tokens.sh +0 -44
  353. package/.next/standalone/integration-suite/install-clis.sh +0 -136
  354. package/.next/standalone/integration-suite/probe-cli.sh +0 -248
  355. package/.next/standalone/integration-suite/report.js +0 -120
  356. package/.next/standalone/integration-suite/run.sh +0 -159
  357. package/.next/standalone/openclaw-plugin/index.js +0 -223
  358. package/.next/standalone/openclaw-plugin/openclaw.plugin.json +0 -6
  359. package/.next/standalone/openclaw-plugin/package.json +0 -12
  360. package/.next/standalone/osv-scanner.toml +0 -17
  361. package/.next/standalone/pi-extension/index.ts +0 -524
  362. package/.next/standalone/pi-extension/package.json +0 -12
  363. package/.next/standalone/postcss.config.mjs +0 -8
  364. package/.next/standalone/readme-arch-hq.gif +0 -0
  365. package/.next/standalone/rust-toolchain.toml +0 -4
  366. package/src/auth/cli.ts +0 -371
  367. /package/.next/standalone/.next/static/{StV6Lay7Q1cU4ysYCFJmH → Ptn8aBQl_cnNgOd0ebyv0}/_buildManifest.js +0 -0
  368. /package/.next/standalone/.next/static/{StV6Lay7Q1cU4ysYCFJmH → Ptn8aBQl_cnNgOd0ebyv0}/_clientMiddlewareManifest.js +0 -0
  369. /package/.next/standalone/.next/static/{StV6Lay7Q1cU4ysYCFJmH → Ptn8aBQl_cnNgOd0ebyv0}/_ssgManifest.js +0 -0
@@ -1,81 +0,0 @@
1
- //! Single-instance guard: at most one `failproofaid` per OS user.
2
- //!
3
- //! Uses an advisory `flock()` on a dedicated lock file rather than a
4
- //! PID file — a PID file has to be checked-then-trusted (the PID could
5
- //! have been reused by an unrelated process since), whereas `flock` is
6
- //! released automatically by the kernel when the holding process exits or
7
- //! is killed, for any reason, with no stale-file cleanup required.
8
-
9
- use std::fs::{File, OpenOptions};
10
- use std::io;
11
- use std::os::unix::io::AsRawFd;
12
- use std::path::Path;
13
-
14
- pub struct SingletonLock {
15
- // Held for the guard's lifetime; the flock is released when this File
16
- // (and its underlying fd) is dropped.
17
- _file: File,
18
- }
19
-
20
- #[derive(Debug)]
21
- pub enum LockError {
22
- Io(io::Error),
23
- AlreadyRunning,
24
- }
25
-
26
- impl std::fmt::Display for LockError {
27
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
28
- match self {
29
- LockError::Io(e) => write!(f, "io error acquiring daemon lock: {e}"),
30
- LockError::AlreadyRunning => {
31
- write!(f, "another failproofaid is already running for this user")
32
- }
33
- }
34
- }
35
- }
36
-
37
- impl std::error::Error for LockError {}
38
-
39
- /// Tries to acquire the singleton lock at `path`, creating the file if
40
- /// needed. Returns [`LockError::AlreadyRunning`] immediately (non-blocking)
41
- /// if another live process already holds it.
42
- pub fn acquire(path: &Path) -> Result<SingletonLock, LockError> {
43
- let file = OpenOptions::new()
44
- .create(true)
45
- .truncate(false)
46
- .write(true)
47
- .open(path)
48
- .map_err(LockError::Io)?;
49
-
50
- let ret = unsafe { libc::flock(file.as_raw_fd(), libc::LOCK_EX | libc::LOCK_NB) };
51
- if ret != 0 {
52
- let err = io::Error::last_os_error();
53
- return match err.raw_os_error() {
54
- Some(libc::EWOULDBLOCK) => Err(LockError::AlreadyRunning),
55
- _ => Err(LockError::Io(err)),
56
- };
57
- }
58
- Ok(SingletonLock { _file: file })
59
- }
60
-
61
- #[cfg(test)]
62
- mod tests {
63
- use super::*;
64
-
65
- #[test]
66
- fn a_second_acquire_in_the_same_process_fails_while_the_first_is_held() {
67
- let tmp = std::env::temp_dir().join(format!(
68
- "failproofaid-lock-test-{}-{}",
69
- std::process::id(),
70
- line!()
71
- ));
72
- let first = acquire(&tmp).expect("first acquire should succeed");
73
- let second = acquire(&tmp);
74
- assert!(matches!(second, Err(LockError::AlreadyRunning)));
75
- drop(first);
76
- // Once released, a fresh acquire succeeds again.
77
- let third = acquire(&tmp);
78
- assert!(third.is_ok());
79
- std::fs::remove_file(&tmp).ok();
80
- }
81
- }
@@ -1,532 +0,0 @@
1
- mod cloud_client;
2
- pub mod cloud_policies;
3
- mod lock;
4
- mod paths;
5
- mod server;
6
- mod worker;
7
-
8
- use std::sync::Arc;
9
- use std::sync::atomic::{AtomicBool, Ordering};
10
- use std::time::Duration;
11
-
12
- fn main() {
13
- let args: Vec<String> = std::env::args().collect();
14
- if args.iter().any(|a| a == "--version" || a == "-v") {
15
- println!("failproofaid {}", env!("CARGO_PKG_VERSION"));
16
- return;
17
- }
18
-
19
- if let Err(err) = run() {
20
- eprintln!("[failproofaid] {err}");
21
- std::process::exit(1);
22
- }
23
- }
24
-
25
- /// Install a log subscriber, or the collector's diagnostics go nowhere.
26
- ///
27
- /// `tracing` drops every event when no subscriber is registered, silently. The
28
- /// uploader reports "the server accepted the request but stored NONE of its
29
- /// events" through it — the single most important signal that a transform is
30
- /// systematically malformed — so without this that failure is invisible.
31
- ///
32
- /// Writes to stderr, which is where the daemon's existing `eprintln!` output
33
- /// already goes and what systemd/launchd capture. `RUST_LOG` overrides the
34
- /// default level.
35
- fn init_logging() {
36
- use tracing_subscriber::EnvFilter;
37
- let filter = EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("info"));
38
- let _ = tracing_subscriber::fmt()
39
- .with_env_filter(filter)
40
- .with_writer(std::io::stderr)
41
- .try_init();
42
- }
43
-
44
- fn run() -> Result<(), Box<dyn std::error::Error>> {
45
- init_logging();
46
- let lock_path = paths::lock_path()?;
47
- paths::ensure_run_dir()?;
48
- let _singleton = lock::acquire(&lock_path)?;
49
-
50
- let socket_path = paths::socket_path()?;
51
- let worker_socket_path = paths::worker_socket_path()?;
52
- let worker = Arc::new(worker::Worker::new(
53
- worker_socket_path,
54
- worker::WorkerCommand::from_env(),
55
- ));
56
- // Pre-warm off the startup path: the socket must be accepting
57
- // connections promptly (a service manager / health check shouldn't wait
58
- // on a Node cold start), but a request that arrives before warm-up
59
- // finishes still gets a correct, just slightly slower, answer — `call()`
60
- // -> `ensure_started()` shares the same lock and simply waits for
61
- // whichever spawn (this one or its own) is already in flight.
62
- {
63
- let warm_worker = worker.clone();
64
- std::thread::spawn(move || warm_worker.warm());
65
- }
66
- // The shutdown flag and its signal handler are installed BEFORE anything
67
- // long-running starts, so the collector below can observe the same flag
68
- // the socket server does. One SIGTERM then stops both; a second signal
69
- // path would be one more thing to get wrong during shutdown.
70
- let shutdown = Arc::new(AtomicBool::new(false));
71
- install_signal_handler(shutdown.clone());
72
-
73
- // Cloud policy integrity is a maintenance-lane responsibility, never a
74
- // hook-path operation. The monitor is useful before cloud transport lands:
75
- // it keeps the active generation and content-addressed artifact cache in
76
- // agreement and reports when both verified copies have been lost.
77
- let cloud_policy_store = cloud_policies::PolicyStore::new(paths::cloud_managed_policy_dir()?);
78
- // One lane, resolving enrolment per tick rather than once at startup.
79
- // `failproofai config --connect` writes its credential file without root,
80
- // and this is a SYSTEM unit — so noticing it only on restart would put
81
- // `sudo systemctl restart` back into a flow built to avoid it. The lane
82
- // also does integrity repair whether or not the machine is enrolled.
83
- let cloud_monitor = cloud_client::spawn_maintenance(
84
- cloud_policy_store,
85
- shutdown.clone(),
86
- cloud_client::poll_interval_from_env(),
87
- cloud_policy_reconcile_interval(),
88
- );
89
-
90
- // Log/hook collection. Runs on its own thread with its own Tokio runtime
91
- // so it can never share fate with the accept loop — this daemon fails
92
- // closed, so a collector fault would otherwise deny every tool call on the
93
- // machine (see fpai_collect::supervisor). It observes the same `shutdown`
94
- // flag the server and the cloud monitor do, so one SIGTERM stops all three.
95
- //
96
- // INERT until ingest is configured: `collector_tasks()` returns an empty
97
- // list, `spawn_supervised` then declines to start a thread or a runtime at
98
- // all, and the daemon behaves byte-for-byte as it did before this existed.
99
- let collector = fpai_collect::spawn_supervised(collector_tasks(), shutdown.clone());
100
-
101
- let srv = server::Server::bind(&socket_path, worker)?;
102
- eprintln!("[failproofaid] listening on {}", socket_path.display());
103
-
104
- let run_result = srv.run_until(shutdown);
105
-
106
- // Drain both background workers before returning. The collector gets a
107
- // bounded budget rather than an unbounded join: process exit must not wait
108
- // on a task that has wedged. Done before `?` so a server error still gets
109
- // the collector a chance to flush instead of dropping buffered events.
110
- if let Some(collector) = collector {
111
- collector.join_with_flush(fpai_collect::DEFAULT_FLUSH_BUDGET);
112
- }
113
- let _ = cloud_monitor.join();
114
-
115
- run_result?;
116
- Ok(())
117
- }
118
-
119
- /// The collector tasks to supervise for this process.
120
- ///
121
- /// Returns an empty list — and therefore starts no thread and no runtime —
122
- /// unless an ingest credential is configured AND at least one stream is
123
- /// enabled. That is the normal state, so an install that has not opted in
124
- /// pays nothing for this code path existing.
125
- ///
126
- /// A configuration error is logged and treated as "off" rather than being
127
- /// propagated: collection failing to start must never stop the daemon from
128
- /// serving the socket, because the CLI fails closed and a daemon that refused
129
- /// to boot over a malformed `ingest.json` would deny every tool call on the
130
- /// machine. The error is loud so it is fixable, not silent.
131
- fn collector_tasks() -> Vec<fpai_collect::TaskSpec> {
132
- let home = match paths::failproofai_home() {
133
- Ok(home) => home,
134
- Err(err) => {
135
- eprintln!("[failproofaid] collector disabled: {err}");
136
- return Vec::new();
137
- }
138
- };
139
-
140
- let cfg = match fpai_collect::config::load(&home) {
141
- Ok(cfg) => cfg,
142
- Err(err) => {
143
- eprintln!("[failproofaid] collector disabled: {err}");
144
- return Vec::new();
145
- }
146
- };
147
-
148
- if !cfg.is_enabled() {
149
- return Vec::new();
150
- }
151
-
152
- // `is_enabled()` already established there is one.
153
- let Some(ingest) = cfg.ingest.clone() else {
154
- return Vec::new();
155
- };
156
-
157
- let uploader = match fpai_collect::Uploader::new(
158
- ingest.url.clone(),
159
- ingest.key.clone(),
160
- cfg.failed_dir.clone(),
161
- ) {
162
- Ok(u) => std::sync::Arc::new(u),
163
- Err(err) => {
164
- eprintln!("[failproofaid] collector disabled: {err}");
165
- return Vec::new();
166
- }
167
- };
168
-
169
- eprintln!(
170
- "[failproofaid] collector enabled: sessions={} hooks={} ({:?}) -> {}",
171
- cfg.settings.sessions, cfg.settings.hooks, cfg.settings.hooks_verbosity, ingest.url,
172
- );
173
-
174
- // One `Delivery` shared by both tasks, so they share an upload semaphore
175
- // and an in-flight set. Separate ones would let the watcher and a
176
- // concurrent sweep POST the same batch twice.
177
- let delivery = std::sync::Arc::new(fpai_collect::Delivery::new(uploader));
178
-
179
- let watch_delivery = delivery.clone();
180
- let watch_dirs = cfg.spool_dirs.clone();
181
- let sweep_delivery = delivery;
182
- let sweep_dirs = cfg.spool_dirs.clone();
183
- let failed_dir = cfg.failed_dir.clone();
184
-
185
- let mut tasks = Vec::new();
186
-
187
- // Install the process health registry BEFORE any source starts, so no poll
188
- // reports into a registry that does not exist yet. The writer publishes it
189
- // on an interval and deletes it on clean shutdown — absence means "no
190
- // daemon", where a stale file makes a stopped daemon look like a running
191
- // one whose sources all went quiet.
192
- let health = std::sync::Arc::new(fpai_collect::Health::new());
193
- fpai_collect::health::install(health.clone());
194
- let health_file = fpai_collect::health_path(&home);
195
- tasks.push(fpai_collect::TaskSpec::new("health", move |sd| {
196
- fpai_collect::health::writer_task(
197
- health.clone(),
198
- health_file.clone(),
199
- fpai_collect::health::WRITE_INTERVAL,
200
- sd,
201
- )
202
- }));
203
-
204
- if cfg.settings.hooks {
205
- // Hook activity: one source covering every CLI failproofai is
206
- // installed in, because the store is CLI-agnostic — each row names its
207
- // own integration. Reads the same store the dashboard's activity tab
208
- // does, and never writes to it.
209
- let store_dir = home.join("cache").join("hook-activity");
210
- let state_dir = home.join("cursors").join("hooks");
211
- let spool_dir = cfg.own_spool_dir.clone();
212
- let verbosity = cfg.settings.hooks_verbosity;
213
- let environment = cfg.settings.environment.clone();
214
- tasks.push(fpai_collect::TaskSpec::new("hook-activity", move |sd| {
215
- fpai_collect::sources::hooks::run(
216
- store_dir.clone(),
217
- state_dir.clone(),
218
- spool_dir.clone(),
219
- verbosity,
220
- environment.clone(),
221
- sd,
222
- )
223
- }));
224
- }
225
-
226
- if cfg.settings.sessions {
227
- // Session transcripts, gated on the `sessions` opt-in because — unlike
228
- // hook activity — these carry prompts, file contents and whatever was
229
- // pasted into a terminal.
230
- //
231
- // Every source is registered the same way regardless of which engine it
232
- // uses, so adding one is a row here plus its own module.
233
- let spool = cfg.own_spool_dir.clone();
234
- let env = cfg.settings.environment.clone();
235
- let cursors = home.join("cursors");
236
-
237
- use fpai_collect::sources::{claude, codex, copilot, openclaw, pi};
238
- file_source(
239
- &mut tasks,
240
- "claude",
241
- claude::FORMAT,
242
- vec![claude_projects_root()],
243
- claude::DEFAULT_AGENT_ID,
244
- &spool,
245
- &cursors,
246
- &env,
247
- );
248
- // Subagent transcripts live under the SAME root, claimed by a second
249
- // format. A separate source, not a second predicate: `is_source_file`
250
- // is a bare fn, and each source needs its own cursor store — one store
251
- // writes its whole map atomically, so two sharing a file would clobber
252
- // each other and the loser would re-ship from zero after every restart.
253
- file_source(
254
- &mut tasks,
255
- "claude-subagent",
256
- claude::SUBAGENT_FORMAT,
257
- vec![claude_projects_root()],
258
- claude::SUBAGENT_DEFAULT_AGENT_ID,
259
- &spool,
260
- &cursors,
261
- &env,
262
- );
263
- file_source(
264
- &mut tasks,
265
- "codex",
266
- codex::FORMAT,
267
- vec![codex_sessions_root()],
268
- codex::DEFAULT_AGENT_ID,
269
- &spool,
270
- &cursors,
271
- &env,
272
- );
273
- file_source(
274
- &mut tasks,
275
- "copilot",
276
- copilot::FORMAT,
277
- vec![copilot::session_state_root()],
278
- copilot::DEFAULT_AGENT_ID,
279
- &spool,
280
- &cursors,
281
- &env,
282
- );
283
- file_source(
284
- &mut tasks,
285
- "openclaw",
286
- openclaw::FORMAT,
287
- openclaw::default_roots(),
288
- openclaw::DEFAULT_AGENT_ID,
289
- &spool,
290
- &cursors,
291
- &env,
292
- );
293
- file_source(
294
- &mut tasks,
295
- "pi",
296
- pi::FORMAT,
297
- vec![pi::sessions_root()],
298
- pi::DEFAULT_AGENT_ID,
299
- &spool,
300
- &cursors,
301
- &env,
302
- );
303
-
304
- use fpai_collect::sources::{goose, hermes, opencode};
305
- sqlite_source(
306
- &mut tasks,
307
- "goose",
308
- goose::FORMAT,
309
- goose::db_path(),
310
- goose::DEFAULT_AGENT_ID,
311
- &spool,
312
- cursors.join("goose"),
313
- &env,
314
- );
315
- sqlite_source(
316
- &mut tasks,
317
- "opencode",
318
- opencode::FORMAT,
319
- opencode::default_db_path(),
320
- opencode::DEFAULT_AGENT_ID,
321
- &spool,
322
- cursors.join("opencode"),
323
- &env,
324
- );
325
-
326
- // Hermes profiles are SEPARATE databases, and the SQLite poller keys its
327
- // cursor on a fixed synthetic id — so two profiles sharing one state
328
- // directory would clobber each other's watermark and each would re-read
329
- // from zero after every restart. Each database gets its own.
330
- for (i, db) in hermes::default_db_paths().into_iter().enumerate() {
331
- let state = cursors.join("hermes").join(profile_dir_name(&db, i));
332
- sqlite_source(
333
- &mut tasks,
334
- "hermes",
335
- hermes::FORMAT,
336
- db,
337
- hermes::DEFAULT_AGENT_ID,
338
- &spool,
339
- state,
340
- &env,
341
- );
342
- }
343
- }
344
-
345
- tasks.extend([
346
- // Latency: delivers a batch within milliseconds of it being published.
347
- fpai_collect::TaskSpec::new("spool-watcher", move |sd| {
348
- fpai_collect::delivery::watch(watch_delivery.clone(), watch_dirs.clone(), sd)
349
- }),
350
- // Guarantee: delivers anything the watcher never saw — published while
351
- // the daemon was stopped, or on a filesystem with no event support —
352
- // and retries parked batches on a much slower cadence.
353
- fpai_collect::TaskSpec::new("spool-sweeper", move |sd| {
354
- fpai_collect::delivery::sweep(
355
- sweep_delivery.clone(),
356
- sweep_dirs.clone(),
357
- failed_dir.clone(),
358
- sd,
359
- )
360
- }),
361
- ]);
362
-
363
- tasks
364
- }
365
-
366
- /// Where Claude Code keeps its transcripts.
367
- ///
368
- /// `CLAUDE_PROJECTS_PATH` overrides it, matching the env var the TypeScript
369
- /// side already honours, so a machine that has moved the directory is captured
370
- /// by both halves rather than one.
371
- fn claude_projects_root() -> std::path::PathBuf {
372
- if let Some(p) = std::env::var_os("CLAUDE_PROJECTS_PATH") {
373
- return std::path::PathBuf::from(p);
374
- }
375
- let home = std::env::var_os("HOME")
376
- .map(std::path::PathBuf::from)
377
- .unwrap_or_default();
378
- home.join(".claude").join("projects")
379
- }
380
-
381
- /// Register one file-tailing source.
382
- #[allow(clippy::too_many_arguments)]
383
- fn file_source(
384
- tasks: &mut Vec<fpai_collect::TaskSpec>,
385
- name: &'static str,
386
- format: fpai_collect::filetail::Format,
387
- roots: Vec<std::path::PathBuf>,
388
- default_agent_id: &'static str,
389
- spool_dir: &std::path::Path,
390
- cursor_root: &std::path::Path,
391
- environment: &str,
392
- ) {
393
- let spool_dir = spool_dir.to_path_buf();
394
- // One cursor store per source, never shared: the store writes its whole map
395
- // atomically, so two sources sharing a file would clobber each other and the
396
- // loser would re-read from zero after every restart.
397
- let state_dir = cursor_root.join(name);
398
- let environment = environment.to_string();
399
- tasks.push(fpai_collect::TaskSpec::new(name, move |sd| {
400
- fpai_collect::filetail::run(
401
- fpai_collect::filetail::Spec {
402
- format,
403
- roots: roots.clone(),
404
- spool_dir: spool_dir.clone(),
405
- state_dir: state_dir.clone(),
406
- poll_interval: std::time::Duration::from_secs(2),
407
- params: fpai_collect::filetail::Params {
408
- agent_id: default_agent_id.to_string(),
409
- environment: environment.clone(),
410
- end_idle_mins: 10,
411
- max_read_bytes: 32 * 1024 * 1024,
412
- max_batch_bytes: fpai_collect::spool::DEFAULT_MAX_BATCH_BYTES,
413
- // Never the whole history by default. A normal machine holds
414
- // hundreds of megabytes of transcripts, and shipping all of
415
- // it on first start is not a reasonable default.
416
- since_days: Some(7),
417
- },
418
- },
419
- sd,
420
- )
421
- }));
422
- }
423
-
424
- /// Register one SQLite-polling source.
425
- #[allow(clippy::too_many_arguments)]
426
- fn sqlite_source(
427
- tasks: &mut Vec<fpai_collect::TaskSpec>,
428
- name: &'static str,
429
- format: fpai_collect::sqlitepoll::SqliteFormat,
430
- db_path: std::path::PathBuf,
431
- default_agent_id: &'static str,
432
- spool_dir: &std::path::Path,
433
- state_dir: std::path::PathBuf,
434
- environment: &str,
435
- ) {
436
- let spool_dir = spool_dir.to_path_buf();
437
- let environment = environment.to_string();
438
- tasks.push(fpai_collect::TaskSpec::new(name, move |sd| {
439
- fpai_collect::sqlitepoll::run(
440
- fpai_collect::sqlitepoll::Spec {
441
- format,
442
- db_path: db_path.clone(),
443
- spool_dir: spool_dir.clone(),
444
- state_dir: state_dir.clone(),
445
- poll_interval: std::time::Duration::from_secs(5),
446
- params: fpai_collect::sqlitepoll::Params {
447
- agent_id: default_agent_id.to_string(),
448
- environment: environment.clone(),
449
- max_rows_per_poll: 2000,
450
- max_batch_bytes: fpai_collect::spool::DEFAULT_MAX_BATCH_BYTES,
451
- max_drain_passes: 20,
452
- },
453
- },
454
- sd,
455
- )
456
- }));
457
- }
458
-
459
- /// A stable, filesystem-safe directory name for one Hermes profile database.
460
- ///
461
- /// Derived from the profile directory rather than an index alone, so adding a
462
- /// profile cannot renumber an existing one and silently reset its watermark.
463
- fn profile_dir_name(db: &std::path::Path, index: usize) -> String {
464
- let name = db
465
- .parent()
466
- .and_then(|p| p.file_name())
467
- .and_then(|n| n.to_str())
468
- .unwrap_or("default");
469
- let safe: String = name
470
- .chars()
471
- .map(|c| if c.is_ascii_alphanumeric() { c } else { '-' })
472
- .take(32)
473
- .collect();
474
- if safe.trim_matches('-').is_empty() {
475
- format!("profile-{index}")
476
- } else {
477
- safe
478
- }
479
- }
480
-
481
- /// Where OpenAI Codex keeps its rollout logs.
482
- fn codex_sessions_root() -> std::path::PathBuf {
483
- if let Some(p) = std::env::var_os("CODEX_HOME") {
484
- return std::path::PathBuf::from(p).join("sessions");
485
- }
486
- let home = std::env::var_os("HOME")
487
- .map(std::path::PathBuf::from)
488
- .unwrap_or_default();
489
- home.join(".codex").join("sessions")
490
- }
491
-
492
- fn cloud_policy_reconcile_interval() -> Duration {
493
- const DEFAULT_MS: u64 = 30_000;
494
- const MINIMUM_MS: u64 = 100;
495
- let configured = std::env::var("FAILPROOFAI_CLOUD_POLICY_RECONCILE_MS")
496
- .ok()
497
- .and_then(|value| value.parse::<u64>().ok())
498
- .unwrap_or(DEFAULT_MS);
499
- Duration::from_millis(configured.max(MINIMUM_MS))
500
- }
501
-
502
- /// Requests a clean shutdown (socket file removal, lock release via Drop)
503
- /// on SIGTERM/SIGINT instead of dying mid-accept-loop — this is how a
504
- /// systemd `stop`/launchd unload is expected to end the process.
505
- fn install_signal_handler(shutdown: Arc<AtomicBool>) {
506
- static SHUTDOWN_REQUESTED: AtomicBool = AtomicBool::new(false);
507
-
508
- extern "C" fn handle_signal(_sig: libc::c_int) {
509
- SHUTDOWN_REQUESTED.store(true, Ordering::Relaxed);
510
- }
511
-
512
- unsafe {
513
- libc::signal(
514
- libc::SIGTERM,
515
- handle_signal as *const () as libc::sighandler_t,
516
- );
517
- libc::signal(
518
- libc::SIGINT,
519
- handle_signal as *const () as libc::sighandler_t,
520
- );
521
- }
522
-
523
- std::thread::spawn(move || {
524
- loop {
525
- if SHUTDOWN_REQUESTED.load(Ordering::Relaxed) {
526
- shutdown.store(true, Ordering::Relaxed);
527
- return;
528
- }
529
- std::thread::sleep(std::time::Duration::from_millis(50));
530
- }
531
- });
532
- }