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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (368) hide show
  1. package/.next/standalone/.next/BUILD_ID +1 -1
  2. package/.next/standalone/.next/app-path-routes-manifest.json +2 -1
  3. package/.next/standalone/.next/build-manifest.json +3 -3
  4. package/.next/standalone/.next/prerender-manifest.json +3 -3
  5. package/.next/standalone/.next/required-server-files.json +1 -1
  6. package/.next/standalone/.next/routes-manifest.json +6 -0
  7. package/.next/standalone/.next/server/app/_global-error/page/server-reference-manifest.json +1 -1
  8. package/.next/standalone/.next/server/app/_global-error/page.js +3 -1
  9. package/.next/standalone/.next/server/app/_global-error/page.js.nft.json +1 -1
  10. package/.next/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  11. package/.next/standalone/.next/server/app/_global-error.html +1 -1
  12. package/.next/standalone/.next/server/app/_global-error.rsc +7 -7
  13. package/.next/standalone/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +2 -2
  14. package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +7 -7
  15. package/.next/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +3 -3
  16. package/.next/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +3 -3
  17. package/.next/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  18. package/.next/standalone/.next/server/app/_not-found/page/server-reference-manifest.json +1 -1
  19. package/.next/standalone/.next/server/app/_not-found/page.js +3 -1
  20. package/.next/standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
  21. package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  22. package/.next/standalone/.next/server/app/_not-found.html +1 -1
  23. package/.next/standalone/.next/server/app/_not-found.rsc +15 -15
  24. package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +15 -15
  25. package/.next/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +4 -4
  26. package/.next/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +10 -10
  27. package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +2 -2
  28. package/.next/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +3 -3
  29. package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  30. package/.next/standalone/.next/server/app/api/audit/invite/route.js +3 -2
  31. package/.next/standalone/.next/server/app/api/audit/invite/route.js.nft.json +1 -1
  32. package/.next/standalone/.next/server/app/api/audit/run/route.js +4 -3
  33. package/.next/standalone/.next/server/app/api/audit/run/route.js.nft.json +1 -1
  34. package/.next/standalone/.next/server/app/api/audit/status/route.js +1 -1
  35. package/.next/standalone/.next/server/app/api/audit/status/route.js.nft.json +1 -1
  36. package/.next/standalone/.next/server/app/api/auth/login-request/route.js +2 -1
  37. package/.next/standalone/.next/server/app/api/auth/login-request/route.js.nft.json +1 -1
  38. package/.next/standalone/.next/server/app/api/auth/login-verify/route.js +3 -2
  39. package/.next/standalone/.next/server/app/api/auth/login-verify/route.js.nft.json +1 -1
  40. package/.next/standalone/.next/server/app/api/auth/logout/route.js +3 -2
  41. package/.next/standalone/.next/server/app/api/auth/logout/route.js.nft.json +1 -1
  42. package/.next/standalone/.next/server/app/api/auth/reminder/route.js +3 -2
  43. package/.next/standalone/.next/server/app/api/auth/reminder/route.js.nft.json +1 -1
  44. package/.next/standalone/.next/server/app/api/auth/status/route.js +3 -2
  45. package/.next/standalone/.next/server/app/api/auth/status/route.js.nft.json +1 -1
  46. package/.next/standalone/.next/server/app/api/download/[project]/[session]/route.js +1 -1
  47. package/.next/standalone/.next/server/app/api/download/[project]/[session]/route.js.nft.json +1 -1
  48. package/.next/standalone/.next/server/app/audit/page/server-reference-manifest.json +2 -2
  49. package/.next/standalone/.next/server/app/audit/page.js +5 -3
  50. package/.next/standalone/.next/server/app/audit/page.js.nft.json +1 -1
  51. package/.next/standalone/.next/server/app/audit/page_client-reference-manifest.js +1 -1
  52. package/.next/standalone/.next/server/app/index.html +1 -1
  53. package/.next/standalone/.next/server/app/index.rsc +15 -15
  54. package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  55. package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +15 -15
  56. package/.next/standalone/.next/server/app/index.segments/_head.segment.rsc +4 -4
  57. package/.next/standalone/.next/server/app/index.segments/_index.segment.rsc +10 -10
  58. package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -2
  59. package/.next/standalone/.next/server/app/page/server-reference-manifest.json +1 -1
  60. package/.next/standalone/.next/server/app/page.js +3 -1
  61. package/.next/standalone/.next/server/app/page.js.nft.json +1 -1
  62. package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  63. package/.next/standalone/.next/server/app/policies/page/server-reference-manifest.json +10 -10
  64. package/.next/standalone/.next/server/app/policies/page.js +4 -2
  65. package/.next/standalone/.next/server/app/policies/page.js.nft.json +1 -1
  66. package/.next/standalone/.next/server/app/policies/page_client-reference-manifest.js +1 -1
  67. package/.next/standalone/.next/server/app/project/[name]/page/server-reference-manifest.json +1 -1
  68. package/.next/standalone/.next/server/app/project/[name]/page.js +4 -2
  69. package/.next/standalone/.next/server/app/project/[name]/page.js.nft.json +1 -1
  70. package/.next/standalone/.next/server/app/project/[name]/page_client-reference-manifest.js +1 -1
  71. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/react-loadable-manifest.json +2 -2
  72. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/server-reference-manifest.json +2 -2
  73. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page.js +6 -4
  74. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page.js.nft.json +1 -1
  75. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page_client-reference-manifest.js +1 -1
  76. package/.next/standalone/.next/server/app/projects/page/server-reference-manifest.json +1 -1
  77. package/.next/standalone/.next/server/app/projects/page.js +4 -2
  78. package/.next/standalone/.next/server/app/projects/page.js.nft.json +1 -1
  79. package/.next/standalone/.next/server/app/projects/page_client-reference-manifest.js +1 -1
  80. package/.next/standalone/.next/server/app/settings/page/app-paths-manifest.json +3 -0
  81. package/.next/standalone/.next/server/app/settings/page/build-manifest.json +18 -0
  82. package/.next/standalone/.next/server/app/settings/page/next-font-manifest.json +6 -0
  83. package/.next/standalone/.next/server/app/settings/page/react-loadable-manifest.json +1 -0
  84. package/.next/standalone/.next/server/app/settings/page/server-reference-manifest.json +53 -0
  85. package/.next/standalone/.next/server/app/settings/page.js +18 -0
  86. package/.next/standalone/.next/server/app/settings/page.js.map +5 -0
  87. package/.next/standalone/.next/server/app/settings/page.js.nft.json +1 -0
  88. package/.next/standalone/.next/server/app/settings/page_client-reference-manifest.js +3 -0
  89. package/.next/standalone/.next/server/app-paths-manifest.json +2 -1
  90. package/.next/standalone/.next/server/chunks/{[externals]__1nl3dvw._.js → [externals]__0r-zamh._.js} +2 -2
  91. package/.next/standalone/.next/server/chunks/[root-of-the-server]__06hexd0._.js +3 -0
  92. package/.next/standalone/.next/server/chunks/[root-of-the-server]__094p1f1._.js +3 -0
  93. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0_0xu5z._.js +1 -1
  94. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0ed01_d._.js +3 -0
  95. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0g0vcwt._.js +3 -0
  96. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0h3lfmp._.js → [root-of-the-server]__0ky_n0r._.js} +2 -2
  97. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__18d-9oi._.js → [root-of-the-server]__0lk_935._.js} +2 -2
  98. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__1p7s8-d._.js → [root-of-the-server]__0pbp9fe._.js} +2 -2
  99. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0q-v9z2._.js +1 -1
  100. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__10oa-v9._.js → [root-of-the-server]__0v2fpxe._.js} +2 -2
  101. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0sb_5m8._.js → [root-of-the-server]__131ebum._.js} +3 -3
  102. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0-dh5jy._.js → [root-of-the-server]__1_ps0jw._.js} +2 -2
  103. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0l4vuqm._.js → [root-of-the-server]__1a7i2q4._.js} +1 -1
  104. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1ibjy5x._.js +3 -0
  105. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1iny24d._.js +3 -0
  106. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1tvn4wf._.js +1 -1
  107. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1tyedjt._.js +3 -0
  108. package/.next/standalone/.next/server/chunks/_0lxbzdq._.js +5 -0
  109. package/.next/standalone/.next/server/chunks/_1zuiiy3._.js +5 -0
  110. package/.next/standalone/.next/server/chunks/lib_telemetry_ts_0dctyyw._.js +5 -0
  111. package/.next/standalone/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_17k9e3w.js +5 -5
  112. package/.next/standalone/.next/server/chunks/package_json_[json]_cjs_1nxcc4v._.js +1 -1
  113. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__06bp_fg._.js +5 -0
  114. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__074qmkp._.js +3 -0
  115. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0c_qcgp._.js +3 -0
  116. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0kbc9bs._.js +3 -0
  117. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0spkm68._.js +10 -10
  118. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1a2hcb_._.js +3 -0
  119. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0rtdfof._.js → [root-of-the-server]__1rdruw4._.js} +1 -1
  120. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1rv-sc9._.js +3 -0
  121. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1tyf0tc._.js +5 -0
  122. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1u-wx42._.js +4 -0
  123. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1v185mo._.js +3 -0
  124. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0rag5dg._.js → [root-of-the-server]__1yw368c._.js} +2 -2
  125. package/.next/standalone/.next/server/chunks/ssr/_0-yi74u._.js +3 -0
  126. package/.next/standalone/.next/server/chunks/ssr/_04mekdy._.js +3 -0
  127. package/.next/standalone/.next/server/chunks/ssr/_0r-dsre._.js +3 -0
  128. package/.next/standalone/.next/server/chunks/ssr/_0rjgfln._.js +3 -0
  129. package/.next/standalone/.next/server/chunks/ssr/_0se484m._.js +3 -0
  130. package/.next/standalone/.next/server/chunks/ssr/_0uz7o9y._.js +3 -0
  131. package/.next/standalone/.next/server/chunks/ssr/_11_p9y8._.js +1 -1
  132. package/.next/standalone/.next/server/chunks/ssr/_194yh9u._.js +3 -0
  133. package/.next/standalone/.next/server/chunks/ssr/_1fahg9e._.js +3 -0
  134. package/.next/standalone/.next/server/chunks/ssr/_1gmzkwj._.js +5 -0
  135. package/.next/standalone/.next/server/chunks/ssr/_1w8sola._.js +3 -0
  136. package/.next/standalone/.next/server/chunks/ssr/_1w_6p9g._.js +3 -0
  137. package/.next/standalone/.next/server/chunks/ssr/app_audit__components_audit-dashboard_tsx_0p9ud47._.js +2 -2
  138. package/.next/standalone/.next/server/chunks/ssr/app_global-error_tsx_1kp6l3x._.js +1 -1
  139. package/.next/standalone/.next/server/chunks/ssr/app_policies_hooks-client_tsx_19dqvpc._.js +2 -2
  140. package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0dwo94s.js +4 -0
  141. package/.next/standalone/.next/server/chunks/ssr/src_hooks_builtin-policies_ts_09j2ndl._.js +3 -0
  142. package/.next/standalone/.next/server/chunks/ssr/src_hooks_fp-config_ts_04t589g._.js +5 -0
  143. package/.next/standalone/.next/server/middleware-build-manifest.js +3 -3
  144. package/.next/standalone/.next/server/middleware.js +2 -2
  145. package/.next/standalone/.next/server/pages/404.html +1 -1
  146. package/.next/standalone/.next/server/pages/500.html +1 -1
  147. package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
  148. package/.next/standalone/.next/server/server-reference-manifest.json +54 -12
  149. package/.next/standalone/.next/static/chunks/0945ybz3fsvba.js +1 -0
  150. package/.next/standalone/.next/static/chunks/{0cr85wuc9gc9k.js → 0gr76ps8_zm26.js} +1 -1
  151. package/.next/standalone/.next/static/chunks/{2cqk4a9s893oy.js → 0m-m7wgtxdoav.js} +1 -1
  152. package/.next/standalone/.next/static/chunks/{1tp9dex23zs8y.js → 11l6oh9cyb35a.js} +1 -1
  153. package/.next/standalone/.next/static/chunks/166f8qnh03jqc.js +6 -0
  154. package/.next/standalone/.next/static/chunks/1bm0q12hgs22l.css +2 -0
  155. package/.next/standalone/.next/static/chunks/1v1gqvpjk62jm.js +1 -0
  156. package/.next/standalone/.next/static/chunks/{2s9g1dsde_ts1.js → 2aej0vi1fm87m.js} +1 -1
  157. package/.next/standalone/.next/static/chunks/{1bkynffp3q1f7.js → 2bxld6-rym3ah.js} +22 -22
  158. package/.next/standalone/.next/static/chunks/{2v1rpzrh2i1wv.js → 2p2kz4aj1tooj.js} +1 -1
  159. package/.next/standalone/.next/static/chunks/2uvhw57mf9lg_.css +2 -0
  160. package/.next/standalone/.next/static/chunks/36pc3_8fpb6ic.js +1 -0
  161. package/.next/standalone/.next/static/chunks/{2k285z07qce47.js → 3t1wr_kx6brwc.js} +1 -1
  162. package/.next/standalone/app/actions/get-hooks-config.ts +2 -1
  163. package/.next/standalone/app/actions/get-scheduled-audit.ts +70 -0
  164. package/.next/standalone/app/actions/update-scheduled-audit.ts +44 -0
  165. package/.next/standalone/app/api/audit/run/route.ts +28 -0
  166. package/.next/standalone/app/api/audit/status/route.ts +13 -1
  167. package/.next/standalone/app/api/auth/status/route.ts +1 -1
  168. package/.next/standalone/app/audit/_components/auth-dialog.css +159 -0
  169. package/.next/standalone/app/audit/_components/auth-dialog.tsx +3 -0
  170. package/.next/standalone/app/audit/audit-styles.css +6 -149
  171. package/.next/standalone/app/settings/page.tsx +31 -0
  172. package/.next/standalone/app/settings/settings-client.tsx +488 -0
  173. package/.next/standalone/components/navbar.tsx +2 -0
  174. package/.next/standalone/lib/auth/api-server-client.ts +2 -3
  175. package/.next/standalone/lib/auth/auth-store.ts +4 -4
  176. package/.next/standalone/lib/codex-sessions.ts +2 -1
  177. package/.next/standalone/lib/dashboard-host.ts +101 -0
  178. package/.next/standalone/lib/install-check.ts +22 -7
  179. package/.next/standalone/lib/pi-sessions.ts +99 -14
  180. package/.next/standalone/lib/telemetry-enabled.ts +54 -0
  181. package/.next/standalone/lib/telemetry-id.ts +52 -1
  182. package/.next/standalone/lib/telemetry.ts +8 -4
  183. package/.next/standalone/node_modules/react/cjs/react.development.js +1 -1
  184. package/.next/standalone/node_modules/react/cjs/react.production.js +1 -1
  185. package/.next/standalone/node_modules/react/package.json +3 -3
  186. package/.next/standalone/node_modules/react-dom/cjs/react-dom-server-legacy.browser.production.js +1 -1
  187. package/.next/standalone/node_modules/react-dom/cjs/react-dom-server-legacy.node.production.js +1 -1
  188. package/.next/standalone/node_modules/react-dom/cjs/react-dom-server.browser.production.js +3 -3
  189. package/.next/standalone/node_modules/react-dom/cjs/react-dom-server.edge.production.js +3 -3
  190. package/.next/standalone/node_modules/react-dom/cjs/react-dom-server.node.production.js +3 -3
  191. package/.next/standalone/node_modules/react-dom/cjs/react-dom.production.js +1 -1
  192. package/.next/standalone/node_modules/react-dom/package.json +4 -4
  193. package/.next/standalone/package.json +7 -6
  194. package/.next/standalone/proxy.ts +89 -1
  195. package/.next/standalone/server.js +1 -1
  196. package/bin/failproofai.mjs +202 -86
  197. package/dist/cli.mjs +17803 -15346
  198. package/dist/worker.mjs +1620 -257
  199. package/lib/auth/api-server-client.ts +2 -3
  200. package/lib/auth/auth-store.ts +4 -4
  201. package/lib/codex-sessions.ts +2 -1
  202. package/lib/dashboard-host.ts +101 -0
  203. package/lib/install-check.ts +22 -7
  204. package/lib/pi-sessions.ts +99 -14
  205. package/lib/telemetry-enabled.ts +54 -0
  206. package/lib/telemetry-id.ts +52 -1
  207. package/lib/telemetry.ts +8 -4
  208. package/package.json +7 -6
  209. package/scripts/install-telemetry.mjs +8 -1
  210. package/scripts/launch.ts +25 -3
  211. package/scripts/parse-script-args.ts +17 -1
  212. package/scripts/prune-standalone.mjs +20 -0
  213. package/scripts/translate-docs/readme-translator.ts +163 -4
  214. package/scripts/validate-mdx.ts +153 -13
  215. package/src/audit/audit-lock.ts +285 -0
  216. package/src/audit/audit-schedule.ts +111 -0
  217. package/src/audit/cache.ts +18 -4
  218. package/src/audit/cli-adapters/goose.ts +2 -1
  219. package/src/audit/cli-adapters/hermes.ts +28 -10
  220. package/src/audit/cli.ts +191 -35
  221. package/src/audit/dashboard-cache.ts +2 -1
  222. package/src/hooks/builtin-policies.ts +100 -3
  223. package/src/hooks/cloud-connection.ts +160 -14
  224. package/src/hooks/cloud-enrollment-cli.ts +119 -21
  225. package/src/hooks/cloud-enrollment.ts +87 -17
  226. package/src/hooks/cloud-introspect.ts +147 -0
  227. package/src/hooks/cloud-managed-policies.ts +33 -2
  228. package/src/hooks/collector-config.ts +25 -43
  229. package/src/hooks/configure-wizard.ts +750 -318
  230. package/src/hooks/custom-hooks-loader.ts +125 -11
  231. package/src/hooks/daemon-client.ts +83 -17
  232. package/src/hooks/daemon-download.ts +54 -2
  233. package/src/hooks/daemon-service.ts +605 -29
  234. package/src/hooks/first-run-gate.ts +39 -0
  235. package/src/hooks/fp-config.ts +497 -0
  236. package/src/hooks/fp-home.ts +355 -0
  237. package/src/hooks/fp-reset.ts +332 -0
  238. package/src/hooks/handler.ts +42 -1
  239. package/src/hooks/hook-activity-store.ts +35 -20
  240. package/src/hooks/hook-logger.ts +2 -1
  241. package/src/hooks/hook-telemetry.ts +5 -1
  242. package/src/hooks/hooks-config.ts +4 -3
  243. package/src/hooks/loader-utils.ts +166 -5
  244. package/src/hooks/manager.ts +5 -4
  245. package/src/hooks/onboarding-attempt.ts +179 -0
  246. package/src/hooks/onboarding-lock.ts +119 -0
  247. package/src/hooks/policy-types.ts +0 -7
  248. package/src/hooks/session-pause-cli.ts +15 -13
  249. package/src/hooks/session-pause.ts +36 -4
  250. package/src/hooks/setup-state.ts +256 -0
  251. package/src/hooks/tui.ts +4 -4
  252. package/src/hooks/worker-server.ts +53 -1
  253. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0f8nu8d._.js +0 -3
  254. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0szqzl8._.js +0 -3
  255. package/.next/standalone/.next/server/chunks/[root-of-the-server]__17g9wh7._.js +0 -3
  256. package/.next/standalone/.next/server/chunks/[root-of-the-server]__19120tr._.js +0 -3
  257. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1fwl2mz._.js +0 -3
  258. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1myjm-d._.js +0 -3
  259. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1rhmvod._.js +0 -3
  260. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__02r5bgf._.js +0 -4
  261. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__094nop3._.js +0 -3
  262. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0e8sjqm._.js +0 -4
  263. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0lkzqax._.js +0 -4
  264. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0ls0gsr._.js +0 -4
  265. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0n_uvv0._.js +0 -3
  266. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0qucxyj._.js +0 -4
  267. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0u02miy._.js +0 -4
  268. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__14dd6h8._.js +0 -3
  269. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1gak4pd._.js +0 -3
  270. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1j4u3yd._.js +0 -4
  271. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1zqz4v8._.js +0 -4
  272. package/.next/standalone/.next/server/chunks/ssr/_1m_p7pi._.js +0 -3
  273. package/.next/standalone/.next/server/chunks/ssr/node_modules_html-to-image_es_index_12c_2cz.js +0 -3
  274. package/.next/standalone/.next/server/chunks/ssr/src_hooks_1ezd2jf._.js +0 -5
  275. package/.next/standalone/.next/server/chunks/ssr/src_hooks_1tnuifj._.js +0 -5
  276. package/.next/standalone/.next/static/chunks/0h7auy7hzjyhw.js +0 -1
  277. package/.next/standalone/.next/static/chunks/1bw4dfzflelcv.js +0 -1
  278. package/.next/standalone/.next/static/chunks/34sjdw8lv46e3.js +0 -6
  279. package/.next/standalone/.next/static/chunks/3i27c3hcriawq.css +0 -1
  280. package/.next/standalone/.next/static/chunks/3zdwnnthucs_1.css +0 -2
  281. package/.next/standalone/Cargo.lock +0 -2222
  282. package/.next/standalone/Cargo.toml +0 -9
  283. package/.next/standalone/crates/CLOUD_POLICIES.md +0 -136
  284. package/.next/standalone/crates/PROTOCOL.md +0 -122
  285. package/.next/standalone/crates/failproofaid/Cargo.toml +0 -25
  286. package/.next/standalone/crates/failproofaid/src/cloud_client.rs +0 -484
  287. package/.next/standalone/crates/failproofaid/src/cloud_policies.rs +0 -921
  288. package/.next/standalone/crates/failproofaid/src/lock.rs +0 -81
  289. package/.next/standalone/crates/failproofaid/src/main.rs +0 -639
  290. package/.next/standalone/crates/failproofaid/src/paths.rs +0 -201
  291. package/.next/standalone/crates/failproofaid/src/server.rs +0 -502
  292. package/.next/standalone/crates/failproofaid/src/worker.rs +0 -400
  293. package/.next/standalone/crates/failproofaid/tests/daemon_e2e.rs +0 -241
  294. package/.next/standalone/crates/fpai-collect/Cargo.toml +0 -43
  295. package/.next/standalone/crates/fpai-collect/src/config.rs +0 -420
  296. package/.next/standalone/crates/fpai-collect/src/cursor.rs +0 -520
  297. package/.next/standalone/crates/fpai-collect/src/delivery.rs +0 -472
  298. package/.next/standalone/crates/fpai-collect/src/filetail.rs +0 -487
  299. package/.next/standalone/crates/fpai-collect/src/health.rs +0 -369
  300. package/.next/standalone/crates/fpai-collect/src/lib.rs +0 -34
  301. package/.next/standalone/crates/fpai-collect/src/redact.rs +0 -516
  302. package/.next/standalone/crates/fpai-collect/src/sources/claude/mod.rs +0 -279
  303. package/.next/standalone/crates/fpai-collect/src/sources/claude/transform.rs +0 -619
  304. package/.next/standalone/crates/fpai-collect/src/sources/codex/mod.rs +0 -156
  305. package/.next/standalone/crates/fpai-collect/src/sources/codex/transform.rs +0 -715
  306. package/.next/standalone/crates/fpai-collect/src/sources/copilot/mod.rs +0 -158
  307. package/.next/standalone/crates/fpai-collect/src/sources/copilot/transform.rs +0 -512
  308. package/.next/standalone/crates/fpai-collect/src/sources/goose/mod.rs +0 -511
  309. package/.next/standalone/crates/fpai-collect/src/sources/goose/transform.rs +0 -586
  310. package/.next/standalone/crates/fpai-collect/src/sources/hermes/mod.rs +0 -318
  311. package/.next/standalone/crates/fpai-collect/src/sources/hermes/transform.rs +0 -579
  312. package/.next/standalone/crates/fpai-collect/src/sources/hooks/mod.rs +0 -314
  313. package/.next/standalone/crates/fpai-collect/src/sources/hooks/transform.rs +0 -448
  314. package/.next/standalone/crates/fpai-collect/src/sources/mod.rs +0 -23
  315. package/.next/standalone/crates/fpai-collect/src/sources/openclaw/mod.rs +0 -176
  316. package/.next/standalone/crates/fpai-collect/src/sources/openclaw/transform.rs +0 -500
  317. package/.next/standalone/crates/fpai-collect/src/sources/opencode/mod.rs +0 -315
  318. package/.next/standalone/crates/fpai-collect/src/sources/opencode/transform.rs +0 -493
  319. package/.next/standalone/crates/fpai-collect/src/sources/pi/mod.rs +0 -201
  320. package/.next/standalone/crates/fpai-collect/src/sources/pi/transform.rs +0 -533
  321. package/.next/standalone/crates/fpai-collect/src/spool.rs +0 -535
  322. package/.next/standalone/crates/fpai-collect/src/sqlitepoll.rs +0 -390
  323. package/.next/standalone/crates/fpai-collect/src/supervisor.rs +0 -423
  324. package/.next/standalone/crates/fpai-collect/src/uploader.rs +0 -600
  325. package/.next/standalone/crates/fpai-collect/tests/claude_source.rs +0 -739
  326. package/.next/standalone/crates/fpai-collect/tests/claude_subagents.rs +0 -394
  327. package/.next/standalone/crates/fpai-collect/tests/codex_source.rs +0 -976
  328. package/.next/standalone/crates/fpai-collect/tests/config.rs +0 -286
  329. package/.next/standalone/crates/fpai-collect/tests/copilot_source.rs +0 -1020
  330. package/.next/standalone/crates/fpai-collect/tests/delivery.rs +0 -281
  331. package/.next/standalone/crates/fpai-collect/tests/goose_source.rs +0 -1009
  332. package/.next/standalone/crates/fpai-collect/tests/hermes_source.rs +0 -1130
  333. package/.next/standalone/crates/fpai-collect/tests/hooks_source.rs +0 -622
  334. package/.next/standalone/crates/fpai-collect/tests/openclaw_source.rs +0 -855
  335. package/.next/standalone/crates/fpai-collect/tests/opencode_source.rs +0 -1478
  336. package/.next/standalone/crates/fpai-collect/tests/pi_source.rs +0 -1192
  337. package/.next/standalone/crates/fpai-collect/tests/supervisor.rs +0 -290
  338. package/.next/standalone/crates/fpai-collect/tests/uploader.rs +0 -506
  339. package/.next/standalone/crates/fpai-ipc/Cargo.toml +0 -16
  340. package/.next/standalone/crates/fpai-ipc/src/envelope.rs +0 -175
  341. package/.next/standalone/crates/fpai-ipc/src/framing.rs +0 -177
  342. package/.next/standalone/crates/fpai-ipc/src/lib.rs +0 -10
  343. package/.next/standalone/crates/fpai-ipc/src/peer.rs +0 -80
  344. package/.next/standalone/docker-hook-sync/Dockerfile +0 -79
  345. package/.next/standalone/docker-hook-sync/entrypoint.sh +0 -109
  346. package/.next/standalone/integration-suite/Dockerfile +0 -47
  347. package/.next/standalone/integration-suite/README.md +0 -129
  348. package/.next/standalone/integration-suite/canary-policies.mjs +0 -45
  349. package/.next/standalone/integration-suite/capture-tokens.sh +0 -48
  350. package/.next/standalone/integration-suite/ci-entrypoint.sh +0 -179
  351. package/.next/standalone/integration-suite/inject-tokens.sh +0 -44
  352. package/.next/standalone/integration-suite/install-clis.sh +0 -136
  353. package/.next/standalone/integration-suite/probe-cli.sh +0 -248
  354. package/.next/standalone/integration-suite/report.js +0 -120
  355. package/.next/standalone/integration-suite/run.sh +0 -159
  356. package/.next/standalone/openclaw-plugin/index.js +0 -223
  357. package/.next/standalone/openclaw-plugin/openclaw.plugin.json +0 -6
  358. package/.next/standalone/openclaw-plugin/package.json +0 -12
  359. package/.next/standalone/osv-scanner.toml +0 -17
  360. package/.next/standalone/pi-extension/index.ts +0 -524
  361. package/.next/standalone/pi-extension/package.json +0 -12
  362. package/.next/standalone/postcss.config.mjs +0 -8
  363. package/.next/standalone/readme-arch-hq.gif +0 -0
  364. package/.next/standalone/rust-toolchain.toml +0 -4
  365. package/src/auth/cli.ts +0 -371
  366. /package/.next/standalone/.next/static/{LOuwMmfomO6hQYfMQYs4K → LUaLkKg40nSkHrIajexIk}/_buildManifest.js +0 -0
  367. /package/.next/standalone/.next/static/{LOuwMmfomO6hQYfMQYs4K → LUaLkKg40nSkHrIajexIk}/_clientMiddlewareManifest.js +0 -0
  368. /package/.next/standalone/.next/static/{LOuwMmfomO6hQYfMQYs4K → LUaLkKg40nSkHrIajexIk}/_ssgManifest.js +0 -0
@@ -1,487 +0,0 @@
1
- //! Generic tailer for agents that keep sessions in append-structured JSONL.
2
- //!
3
- //! Everything format-specific lives behind [`Format`], a table of pure
4
- //! functions each source supplies. The engine itself knows nothing about any
5
- //! transcript grammar.
6
- //!
7
- //! # The invariant everything rests on
8
- //!
9
- //! **Every event is a pure function of one line plus its byte offset.** Nothing
10
- //! is folded or aggregated across a poll window. So a live tail that happens to
11
- //! split a turn across two polls produces byte-identical events to a single
12
- //! full re-read, which is what lets the server's content-hash dedup collapse a
13
- //! re-read instead of storing it twice. Any cross-line state a format needs is
14
- //! persisted in the cursor ([`TailState`]) precisely so it holds the same value
15
- //! at the same offset either way.
16
- //!
17
- //! # Not every source is append-only, and the ones that aren't lie quietly
18
- //!
19
- //! A byte cursor is correct only where files are strictly appended. Probing the
20
- //! real CLIs showed two that are not, and neither announces itself:
21
- //!
22
- //! * **factory/droid** rewrites its first line in place when it names a
23
- //! session, changing that line's length and shifting every later offset. Same
24
- //! inode, and on a manual rename it restores the mtime — so neither
25
- //! inode-watching nor a size+mtime check notices.
26
- //! * **cursor** rewrites the whole file on the first write of every turn.
27
- //!
28
- //! [`RereadPolicy`] is how a format declares which of those it is, so the
29
- //! engine can do the right thing instead of silently desyncing.
30
-
31
- use std::path::{Path, PathBuf};
32
-
33
- use serde_json::Value;
34
- use tokio::io::{AsyncReadExt, AsyncSeekExt};
35
-
36
- use crate::cursor::{CursorStore, FileCursor, TailState, identity};
37
- use crate::spool::SpoolWriter;
38
- use crate::supervisor::{Shutdown, TaskError};
39
-
40
- /// Leading lines read once per file, and reused for every question that needs
41
- /// the head of the transcript: the session's start event, its agent id, and any
42
- /// state a format seeds before transforming its first line.
43
- pub const HEADER_LINES: usize = 64;
44
- /// Cap on the header read, so a transcript whose first line is enormous cannot
45
- /// pull an unbounded amount into memory.
46
- const HEADER_MAX_BYTES: u64 = 1024 * 1024;
47
-
48
- /// How a format's files change after they are written.
49
- #[derive(Debug, Clone, Copy, PartialEq, Eq)]
50
- pub enum RereadPolicy {
51
- /// Strictly appended. A byte offset is sufficient.
52
- ByteCursor,
53
- /// Appended, but the first line may be rewritten in place, moving every
54
- /// later offset. The engine re-reads line 1 each poll and rebases the
55
- /// cursor by the difference before reading further.
56
- ValidatePrefix,
57
- }
58
-
59
- /// Identity shared by every event of one session. Immutable for the session's
60
- /// life and persisted in the cursor, so it is identical across polls and
61
- /// restarts.
62
- #[derive(Debug, Clone, Default)]
63
- pub struct Ctx {
64
- pub session_id: String,
65
- pub agent_id: String,
66
- pub environment: String,
67
- }
68
-
69
- /// The per-format adapter: a table of pure functions.
70
- ///
71
- /// Function items coerce to these `fn` pointers, so a source declares a
72
- /// `Format` const wiring its own helpers — no trait objects, no generics
73
- /// rippling through the engine.
74
- #[derive(Clone, Copy)]
75
- pub struct Format {
76
- /// Source kind. Becomes the derived batch filename prefix and log tag.
77
- pub kind: &'static str,
78
- /// True if this path is one of the format's transcripts.
79
- ///
80
- /// The directory walk is recursive, so this predicate carries the whole
81
- /// filter — including excluding sibling files that must never be tailed.
82
- pub is_source_file: fn(&Path) -> bool,
83
- /// Session id from the path. `None` falls back to a synthetic id derived
84
- /// from the inode, with a warning.
85
- pub session_id_from_path: fn(&Path) -> Option<String>,
86
- /// Agent id from the path and/or the header lines.
87
- ///
88
- /// Takes the header because a path is not always enough: several CLIs
89
- /// encode their working directory into a folder name lossily, and the real
90
- /// value is inside the file.
91
- pub agent_id_from_path: fn(&Path, &[String]) -> Option<String>,
92
- /// Build the session's `agent_start` from its header lines, plus the
93
- /// timestamp that seeds the cursor.
94
- ///
95
- /// Must produce one whenever the file is a real session: the server selects
96
- /// sessions on this event, so a session without one never appears in the
97
- /// product at all, and its `agent_end` is gated on the same flag.
98
- pub agent_start: AgentStartFn,
99
- /// Prime carried state from the header before the first line is
100
- /// transformed.
101
- ///
102
- /// ⚠️ Not dedup-safe between a live tail and a later full re-read: this
103
- /// runs when the file is first discovered, which for a live session is
104
- /// while it is nearly empty, so it seeds nothing — whereas re-reading the
105
- /// finished file seeds from a header that has since grown. Only wire it up
106
- /// where a blank first row is worse than an occasional duplicate.
107
- pub seed_state: fn(&[String], &mut TailState),
108
- /// The single `agent_end`, derived deterministically from the last
109
- /// timestamp and the file size.
110
- pub agent_end: fn(&Ctx, &str, u64) -> Value,
111
- /// One content line to its timestamp and the events it yields.
112
- ///
113
- /// `None` for the timestamp means the line was skipped. Must stay a pure
114
- /// function of `(line, ctx, offset, state)`.
115
- pub transform_line: TransformLineFn,
116
- pub reread: RereadPolicy,
117
- }
118
-
119
- /// Builds a session's `agent_start` from its header, plus the timestamp that
120
- /// seeds the cursor.
121
- pub type AgentStartFn = fn(&[String], &Ctx, u64) -> Option<(Value, Option<String>)>;
122
- /// Transforms one content line into its timestamp and the events it yields.
123
- pub type TransformLineFn = fn(&str, &Ctx, u64, &mut TailState) -> (Option<String>, Vec<Value>);
124
-
125
- /// A format that carries no cross-line state.
126
- pub fn no_seed_state(_lines: &[String], _state: &mut TailState) {}
127
-
128
- /// Runtime knobs, built by a source from its resolved config.
129
- #[derive(Debug, Clone)]
130
- pub struct Params {
131
- pub agent_id: String,
132
- pub environment: String,
133
- /// Machine this daemon runs on, stamped on every event. See `SpoolWriter`.
134
- pub machine_id: Option<String>,
135
- /// Minutes a file must be idle at EOF before `agent_end` is emitted.
136
- pub end_idle_mins: u64,
137
- pub max_read_bytes: u64,
138
- pub max_batch_bytes: u64,
139
- /// Skip files older than this many days on first discovery. `None` reads
140
- /// everything, which on a normal machine is gigabytes of history.
141
- pub since_days: Option<u64>,
142
- }
143
-
144
- pub struct Spec {
145
- pub format: Format,
146
- pub roots: Vec<PathBuf>,
147
- pub spool_dir: PathBuf,
148
- pub state_dir: PathBuf,
149
- pub poll_interval: std::time::Duration,
150
- pub params: Params,
151
- }
152
-
153
- /// Tail every discovered file until shutdown.
154
- pub async fn run(spec: Spec, sd: Shutdown) -> Result<(), TaskError> {
155
- let mut cursors = CursorStore::load(spec.state_dir.clone());
156
-
157
- // Log which roots actually exist. Without this an absent root is
158
- // indistinguishable from a quiet one, and a source that captures nothing
159
- // reads exactly as healthy as one that captures everything.
160
- for root in &spec.roots {
161
- tracing::info!(
162
- source = spec.format.kind,
163
- root = %root.display(),
164
- present = root.exists(),
165
- "file source root"
166
- );
167
- }
168
- tracing::info!(
169
- source = spec.format.kind,
170
- resumed = cursors.len(),
171
- "file source started"
172
- );
173
-
174
- loop {
175
- match poll_once(&spec, &mut cursors).await {
176
- Ok(events) => crate::health::report_poll(
177
- spec.format.kind,
178
- spec.roots.iter().any(|r| r.exists()),
179
- events,
180
- cursors.len() as u64,
181
- ),
182
- Err(err) => {
183
- tracing::warn!(source = spec.format.kind, %err, "poll failed; retrying next tick");
184
- crate::health::report_error(spec.format.kind, &err.to_string());
185
- }
186
- }
187
- if !sd.sleep(spec.poll_interval).await {
188
- return Ok(());
189
- }
190
- }
191
- }
192
-
193
- /// One pass. Returns how many events were spooled, for the health record.
194
- async fn poll_once(spec: &Spec, cursors: &mut CursorStore) -> Result<u64, TaskError> {
195
- let files = discover(&spec.roots, spec.format.is_source_file).await;
196
- let mut events = 0u64;
197
- for path in files {
198
- match process_file(spec, cursors, &path).await {
199
- Ok(n) => events += n,
200
- // Per-file, so one malformed transcript cannot stop the others.
201
- Err(err) => tracing::warn!(file = %path.display(), %err, "could not process file"),
202
- }
203
- }
204
- cursors.retain_existing();
205
- cursors.save().map_err(io_err)?;
206
- Ok(events)
207
- }
208
-
209
- /// Tail one file. Returns how many events it spooled, for the health record.
210
- async fn process_file(
211
- spec: &Spec,
212
- cursors: &mut CursorStore,
213
- path: &Path,
214
- ) -> Result<u64, TaskError> {
215
- let meta = tokio::fs::metadata(path).await.map_err(io_err)?;
216
- let (dev, inode) = identity(&meta);
217
- let size = meta.len();
218
-
219
- let mut cursor = match cursors.resume(dev, inode, path) {
220
- Some(c) => c.clone(),
221
- None => match new_cursor(spec, path, dev, inode, &meta).await? {
222
- Some(c) => c,
223
- None => return Ok(0), // outside the backfill window
224
- },
225
- };
226
- cursor.path = path.to_path_buf();
227
-
228
- // A file that shrank was replaced or truncated; its offsets mean nothing.
229
- if size < cursor.offset {
230
- tracing::warn!(file = %path.display(), size, offset = cursor.offset, "file shrank; re-reading");
231
- cursor.offset = 0;
232
- cursor.state = TailState::default();
233
- }
234
-
235
- if spec.format.reread == RereadPolicy::ValidatePrefix {
236
- rebase_on_first_line(path, &mut cursor).await;
237
- }
238
-
239
- let ctx = Ctx {
240
- session_id: cursor.session_id.clone().unwrap_or_default(),
241
- agent_id: cursor
242
- .agent_id
243
- .clone()
244
- .unwrap_or_else(|| spec.params.agent_id.clone()),
245
- environment: spec.params.environment.clone(),
246
- };
247
-
248
- let mut writer = SpoolWriter::new(
249
- spec.spool_dir.clone(),
250
- spec.params.max_batch_bytes,
251
- spec.format.kind,
252
- &ctx.session_id,
253
- )
254
- .with_machine_id(spec.params.machine_id.clone());
255
- let mut emitted = 0u64;
256
-
257
- // A session with no start event never appears in the product, so retry it
258
- // on every poll until it succeeds rather than only at discovery.
259
- if !cursor.agent_start_emitted {
260
- let header = read_header(path).await.unwrap_or_default();
261
- if let Some((event, ts)) = (spec.format.agent_start)(&header, &ctx, 0) {
262
- writer.push(event).await.map_err(io_err)?;
263
- emitted += 1;
264
- cursor.agent_start_emitted = true;
265
- if cursor.last_ts.is_none() {
266
- cursor.last_ts = ts;
267
- }
268
- }
269
- }
270
-
271
- // Growth resumes a session that had already ended, so it can end again
272
- // rather than freezing at its first end time.
273
- if cursor.ended && size > cursor.size_seen {
274
- cursor.ended = false;
275
- }
276
-
277
- let mut consumed = 0u64;
278
- if size > cursor.offset {
279
- let read_end = size.min(cursor.offset + spec.params.max_read_bytes);
280
- let chunk = read_range(path, cursor.offset, read_end)
281
- .await
282
- .map_err(io_err)?;
283
-
284
- // Hold back a partial final line: half a JSON object parses as nothing,
285
- // and consuming it would skip the record when it completes.
286
- if let Some(last_nl) = chunk.iter().rposition(|b| *b == b'\n') {
287
- let usable = &chunk[..=last_nl];
288
- let mut line_offset = cursor.offset;
289
- for line in usable.split_inclusive(|b| *b == b'\n') {
290
- let at = line_offset;
291
- line_offset += line.len() as u64;
292
- let Ok(text) = std::str::from_utf8(line) else {
293
- continue;
294
- };
295
- let text = text.trim();
296
- if text.is_empty() {
297
- continue;
298
- }
299
- let (ts, events) = (spec.format.transform_line)(text, &ctx, at, &mut cursor.state);
300
- if let Some(ts) = ts {
301
- cursor.last_ts = Some(ts);
302
- }
303
- for e in events {
304
- writer.push(e).await.map_err(io_err)?;
305
- emitted += 1;
306
- }
307
- }
308
- consumed = usable.len() as u64;
309
- }
310
- }
311
-
312
- // `agent_end` once the file is fully read, has actually started, and has
313
- // been idle long enough that more writes are unlikely.
314
- let at_eof = cursor.offset + consumed >= size;
315
- if !cursor.ended
316
- && at_eof
317
- && cursor.agent_start_emitted
318
- && let Some(last_ts) = cursor.last_ts.clone()
319
- && is_idle(&meta, spec.params.end_idle_mins)
320
- {
321
- writer
322
- .push((spec.format.agent_end)(&ctx, &last_ts, size))
323
- .await
324
- .map_err(io_err)?;
325
- cursor.ended = true;
326
- }
327
-
328
- // Flush BEFORE advancing the cursor. A crash between the two costs a
329
- // re-ship the server dedups; the other order loses events outright.
330
- writer.flush().await.map_err(io_err)?;
331
-
332
- cursor.offset += consumed;
333
- cursor.size_seen = size;
334
- cursors.set(cursor);
335
- Ok(emitted)
336
- }
337
-
338
- /// Build a cursor for a newly discovered file, or `None` to skip it.
339
- async fn new_cursor(
340
- spec: &Spec,
341
- path: &Path,
342
- dev: u64,
343
- inode: u64,
344
- meta: &std::fs::Metadata,
345
- ) -> Result<Option<FileCursor>, TaskError> {
346
- if let Some(days) = spec.params.since_days
347
- && !within_days(meta, days)
348
- {
349
- return Ok(None);
350
- }
351
-
352
- let header = read_header(path).await.unwrap_or_default();
353
- let session_id = (spec.format.session_id_from_path)(path).unwrap_or_else(|| {
354
- // A synthetic id keeps the session distinct rather than merging it with
355
- // another, but it will not match anything else, so say so.
356
- tracing::warn!(
357
- file = %path.display(),
358
- "no session id in the path; using a synthetic one that will not correlate"
359
- );
360
- format!("{}-{dev}-{inode}", spec.format.kind)
361
- });
362
- let agent_id = (spec.format.agent_id_from_path)(path, &header)
363
- .unwrap_or_else(|| spec.params.agent_id.clone());
364
-
365
- let mut state = TailState::default();
366
- (spec.format.seed_state)(&header, &mut state);
367
-
368
- Ok(Some(FileCursor {
369
- path: path.to_path_buf(),
370
- dev,
371
- inode,
372
- offset: 0,
373
- size_seen: 0,
374
- session_id: Some(session_id),
375
- agent_id: Some(agent_id),
376
- agent_start_emitted: false,
377
- ended: false,
378
- last_ts: None,
379
- first_line_len: first_line_len(&header),
380
- state,
381
- }))
382
- }
383
-
384
- /// Re-read line 1 and shift the cursor by any change in its length.
385
- ///
386
- /// factory/droid rewrites that line in place when it names a session. The file
387
- /// keeps growing normally, but every offset past line 1 moves — so a cursor
388
- /// left alone resumes mid-record and produces garbage from then on. Observed
389
- /// live: line 1 grew 191 → 268 bytes while the file grew 191 → 9145.
390
- async fn rebase_on_first_line(path: &Path, cursor: &mut FileCursor) {
391
- let Ok(header) = read_header(path).await else {
392
- return;
393
- };
394
- let Some(now_len) = first_line_len(&header) else {
395
- return;
396
- };
397
- let Some(was_len) = cursor.first_line_len else {
398
- cursor.first_line_len = Some(now_len);
399
- return;
400
- };
401
- if now_len == was_len {
402
- return;
403
- }
404
-
405
- let delta = now_len as i64 - was_len as i64;
406
- let rebased = (cursor.offset as i64 + delta).max(0) as u64;
407
- tracing::info!(
408
- file = %path.display(),
409
- was_len, now_len, delta,
410
- old_offset = cursor.offset, new_offset = rebased,
411
- "first line was rewritten in place; rebasing the cursor"
412
- );
413
- cursor.offset = rebased;
414
- cursor.first_line_len = Some(now_len);
415
- }
416
-
417
- fn first_line_len(header: &[String]) -> Option<u64> {
418
- header.first().map(|l| l.len() as u64 + 1) // +1 for the newline
419
- }
420
-
421
- /// Files under `roots` matching `predicate`, walked iteratively.
422
- ///
423
- /// Missing or unreadable directories are skipped silently: the agent may
424
- /// simply not be installed, which is not an error.
425
- async fn discover(roots: &[PathBuf], predicate: fn(&Path) -> bool) -> Vec<PathBuf> {
426
- let mut out = Vec::new();
427
- let mut stack: Vec<PathBuf> = roots.to_vec();
428
- while let Some(dir) = stack.pop() {
429
- let Ok(mut rd) = tokio::fs::read_dir(&dir).await else {
430
- continue;
431
- };
432
- while let Ok(Some(entry)) = rd.next_entry().await {
433
- let path = entry.path();
434
- match entry.file_type().await {
435
- Ok(ft) if ft.is_dir() => stack.push(path),
436
- Ok(ft) if ft.is_file() && predicate(&path) => out.push(path),
437
- _ => {}
438
- }
439
- }
440
- }
441
- out.sort();
442
- out
443
- }
444
-
445
- async fn read_header(path: &Path) -> std::io::Result<Vec<String>> {
446
- let chunk = read_range(path, 0, HEADER_MAX_BYTES).await?;
447
- Ok(String::from_utf8_lossy(&chunk)
448
- .lines()
449
- .take(HEADER_LINES)
450
- .map(|s| s.to_string())
451
- .collect())
452
- }
453
-
454
- /// Read `[from, to)`, tolerating a file shorter than `to`.
455
- async fn read_range(path: &Path, from: u64, to: u64) -> std::io::Result<Vec<u8>> {
456
- let mut f = tokio::fs::File::open(path).await?;
457
- f.seek(std::io::SeekFrom::Start(from)).await?;
458
- let mut buf = Vec::new();
459
- f.take(to.saturating_sub(from))
460
- .read_to_end(&mut buf)
461
- .await?;
462
- Ok(buf)
463
- }
464
-
465
- fn is_idle(meta: &std::fs::Metadata, mins: u64) -> bool {
466
- let Ok(modified) = meta.modified() else {
467
- return false;
468
- };
469
- std::time::SystemTime::now()
470
- .duration_since(modified)
471
- .map(|d| d.as_secs() >= mins.saturating_mul(60))
472
- .unwrap_or(false)
473
- }
474
-
475
- fn within_days(meta: &std::fs::Metadata, days: u64) -> bool {
476
- let Ok(modified) = meta.modified() else {
477
- return true; // unreadable mtime: include rather than silently drop
478
- };
479
- std::time::SystemTime::now()
480
- .duration_since(modified)
481
- .map(|d| d.as_secs() <= days.saturating_mul(86_400))
482
- .unwrap_or(true)
483
- }
484
-
485
- fn io_err(e: std::io::Error) -> TaskError {
486
- TaskError::from(e.to_string())
487
- }