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,715 +0,0 @@
1
- //! Codex CLI rollout line → AgentEye events.
2
- //!
3
- //! Every function here is pure in `(line, ctx, offset, state)`, which is what
4
- //! makes a live tail and a full re-read byte-identical and therefore
5
- //! dedup-collapsible. Nothing may consult the clock, a counter, or anything
6
- //! outside its arguments.
7
- //!
8
- //! Record shapes verified against the 6,520 lines of the 13 real rollouts under
9
- //! `~/.codex/sessions/` on this machine (Codex CLI 0.145.0 / 0.146.0):
10
- //!
11
- //! ```text
12
- //! envelope {timestamp, type, payload} — exactly these three keys, always
13
- //! type session_meta | turn_context | response_item | event_msg
14
- //! | world_state | compacted
15
- //!
16
- //! session_meta {id, session_id, cwd, cli_version, originator, source,
17
- //! git:{branch,commit_hash,repository_url}, parent_thread_id?}
18
- //! turn_context {model, cwd, approval_policy, sandbox_policy, …}
19
- //! response_item {type:"message", role, content:[{type:"input_text"
20
- //! |"output_text", text}]}
21
- //! {type:"function_call", call_id, name, arguments:"<json>"}
22
- //! {type:"custom_tool_call", call_id, name, input:"<js>"}
23
- //! {type:"function_call_output"|"custom_tool_call_output",
24
- //! call_id, output:<string | [{type,text}]>}
25
- //! {type:"reasoning", encrypted_content, summary:[]}
26
- //! event_msg {type:"token_count", info:{last_token_usage:{…}}}
27
- //! {type:"user_message"|"agent_message", message}
28
- //! {type:"task_started"|"task_complete"|"turn_aborted"
29
- //! |"patch_apply_end"|"thread_settings_applied", …}
30
- //! ```
31
- //!
32
- //! Two things the shape above contradicts in the format notes this was written
33
- //! from, both confirmed by grepping every rollout on disk:
34
- //!
35
- //! * There is **no `exec_command_end` event** carrying `aggregated_output` and
36
- //! a `{secs,nanos}` duration — zero occurrences. On 0.145/0.146 a tool result
37
- //! is always the `*_call_output` response item.
38
- //! * `custom_tool_call` outnumbers `function_call` **1130 to 133**, and its
39
- //! `input` is a JavaScript snippet rather than a JSON string. Treating only
40
- //! `function_call` as a tool call would miss 89% of this machine's tool use.
41
- //!
42
- //! # Timestamps
43
- //!
44
- //! Every line carries `timestamp` as `YYYY-MM-DDTHH:MM:SS.mmmZ` — millisecond
45
- //! precision, no exceptions across 6,520 lines. [`with_index`] pads that to the
46
- //! six-digit microsecond form ingest expects, so codex events sort correctly
47
- //! against the hook source's events on a shared session timeline.
48
-
49
- use serde_json::{Map, Value, json};
50
-
51
- use crate::cursor::TailState;
52
- use crate::filetail::Ctx;
53
-
54
- /// Longest derived id component.
55
- const MAX_ID_PART: usize = 48;
56
- /// Longest session goal carried on `agent_start`.
57
- const MAX_GOAL_CHARS: usize = 1024;
58
-
59
- /// Make a derived id component safe and bounded.
60
- ///
61
- /// Deliberately byte-identical to the hook source's private copy (and Claude's)
62
- /// rather than shared: the three must agree or a hook event and the transcript
63
- /// events for the same run land under two agent ids that look unrelated, so a
64
- /// test asserts the agreement instead of an import enforcing it.
65
- pub fn sanitize_id_part(s: &str) -> String {
66
- let cleaned: String = s
67
- .chars()
68
- .map(|c| {
69
- if c.is_ascii_alphanumeric() || c == '.' || c == '_' {
70
- c
71
- } else {
72
- '-'
73
- }
74
- })
75
- .collect();
76
- cleaned
77
- .split('-')
78
- .filter(|p| !p.is_empty())
79
- .collect::<Vec<_>>()
80
- .join("-")
81
- .chars()
82
- .take(MAX_ID_PART)
83
- .collect()
84
- }
85
-
86
- /// Normalize a rollout timestamp to the microsecond form ingest expects,
87
- /// offset by `index` microseconds.
88
- ///
89
- /// The offset is what keeps several events derived from ONE line in order: the
90
- /// server sorts by `(ts, random id)`, so events sharing a timestamp come back
91
- /// shuffled without it. Index 0 is untouched, so the primary event of a line
92
- /// keeps the line's exact time.
93
- ///
94
- /// Saturates within the second rather than carrying, so an offset can never
95
- /// reorder an event past a genuinely later line.
96
- pub fn with_index(ts: &str, index: usize) -> Option<String> {
97
- let body = ts.strip_suffix('Z')?;
98
- let (main, frac) = match body.rsplit_once('.') {
99
- Some((m, f)) => (m, f),
100
- None => (body, ""),
101
- };
102
- // Codex writes milliseconds; pad to microseconds so every event has one
103
- // shape and sorts against the hook source's events correctly. A longer
104
- // fraction (a future release could widen it) is truncated rather than
105
- // rejected — losing sub-microsecond precision beats dropping the line.
106
- let mut micros: u32 = if frac.is_empty() {
107
- 0
108
- } else {
109
- let padded = format!("{frac:0<6}");
110
- padded.get(..6)?.parse().ok()?
111
- };
112
- micros = (micros + index.min(999) as u32).min(999_999);
113
- Some(format!("{main}.{micros:06}Z"))
114
- }
115
-
116
- /// The envelope every emitted event carries.
117
- ///
118
- /// `codex_line_offset` is the dedup discriminator: two identical events from
119
- /// different lines must hash differently, or the server collapses them. A
120
- /// rollout file is one session, so a byte offset is unique within it by
121
- /// construction and stable across a re-read.
122
- fn base(ctx: &Ctx, kind: &str, ts: &str, index: usize, offset: u64) -> Option<Map<String, Value>> {
123
- let mut m = Map::new();
124
- m.insert("timestamp".into(), json!(with_index(ts, index)?));
125
- m.insert("session_id".into(), json!(ctx.session_id));
126
- m.insert("agent_id".into(), json!(ctx.agent_id));
127
- m.insert("type".into(), json!(kind));
128
- m.insert("environment".into(), json!(ctx.environment));
129
- m.insert("codex_line_offset".into(), json!(offset));
130
- if index > 0 {
131
- m.insert("codex_block_index".into(), json!(index));
132
- }
133
- Some(m)
134
- }
135
-
136
- /// The three envelope fields, or `None` for a line that is not a rollout record.
137
- fn envelope(line: &str) -> Option<(String, String, Value)> {
138
- let v: Value = serde_json::from_str(line).ok()?;
139
- let ts = v.get("timestamp")?.as_str()?.to_string();
140
- // A timestamp we cannot place on the timeline is worse than no line at all:
141
- // it would seed `agent_end` with a value the server cannot parse.
142
- with_index(&ts, 0)?;
143
- let kind = v.get("type")?.as_str()?.to_string();
144
- let payload = v.get("payload").cloned().unwrap_or(Value::Null);
145
- Some((ts, kind, payload))
146
- }
147
-
148
- fn payload_type(p: &Value) -> Option<&str> {
149
- p.get("type")?.as_str()
150
- }
151
-
152
- /// Build the session's `agent_start` from its header lines.
153
- ///
154
- /// **Always emits an `agent_start`, never an `agent_end`.** The upstream
155
- /// collector's codex source had a fallback path that emitted an `agent_end`
156
- /// here while still latching the "started" flag; the server selects sessions on
157
- /// `agent_start`, so such a session never appears in `GET /sessions` at all —
158
- /// and because the flag was latched it could never start, and because it never
159
- /// started it could never end either. One wrong constant made the whole session
160
- /// invisible and unrecoverable.
161
- ///
162
- /// The `session_meta` line is preferred because it carries the provenance, but
163
- /// a rollout whose header is truncated or unreadable still anchors on the first
164
- /// line with a usable timestamp rather than going uncollected.
165
- pub fn agent_start(header: &[String], ctx: &Ctx, offset: u64) -> Option<(Value, Option<String>)> {
166
- let mut first_ts: Option<String> = None;
167
- let mut meta: Option<(String, Value)> = None;
168
- let mut cwd: Option<String> = None;
169
- let mut goal: Option<String> = None;
170
-
171
- for line in header {
172
- let Some((ts, kind, payload)) = envelope(line) else {
173
- continue;
174
- };
175
- if first_ts.is_none() {
176
- first_ts = Some(ts.clone());
177
- }
178
- match kind.as_str() {
179
- "session_meta" if meta.is_none() => {
180
- if let Some(c) = payload.get("cwd").and_then(|c| c.as_str()) {
181
- cwd = Some(c.to_string());
182
- }
183
- meta = Some((ts, payload));
184
- }
185
- // `turn_context` repeats the working directory, so a rollout whose
186
- // `session_meta` is unreadable still files under the right project.
187
- "turn_context" if cwd.is_none() => {
188
- if let Some(c) = payload.get("cwd").and_then(|c| c.as_str()) {
189
- cwd = Some(c.to_string());
190
- }
191
- }
192
- // The session's goal is the human's first typed prompt. Taken from
193
- // `event_msg.user_message` rather than the `response_item` user
194
- // messages around it: those also carry the injected AGENTS.md and
195
- // permission preamble (145 user response items vs 127 real prompts
196
- // on this machine), so the response-item stream would make a
197
- // config file the session's goal.
198
- "event_msg" if goal.is_none() && payload_type(&payload) == Some("user_message") => {
199
- if let Some(text) = payload.get("message").and_then(|m| m.as_str())
200
- && !text.is_empty()
201
- {
202
- goal = Some(text.chars().take(MAX_GOAL_CHARS).collect());
203
- }
204
- }
205
- _ => {}
206
- }
207
- }
208
-
209
- let (ts, payload) = match meta {
210
- Some((ts, payload)) => (ts, payload),
211
- None => (first_ts?, Value::Null),
212
- };
213
- let mut m = base(ctx, "agent_start", &ts, 0, offset)?;
214
- if let Some(g) = goal {
215
- m.insert("goal".into(), json!(g));
216
- }
217
- if let Some(c) = cwd {
218
- m.insert("codex_cwd".into(), json!(c));
219
- }
220
- if let Some(v) = payload.get("cli_version").and_then(|v| v.as_str()) {
221
- m.insert("codex_cli_version".into(), json!(v));
222
- }
223
- if let Some(v) = payload
224
- .get("git")
225
- .and_then(|g| g.get("branch"))
226
- .and_then(|b| b.as_str())
227
- {
228
- m.insert("codex_git_branch".into(), json!(v));
229
- }
230
- // A subagent or resumed thread records its parent here. Worth carrying:
231
- // `session_meta.session_id` is the PARENT's id on those rollouts, not this
232
- // file's, which is exactly why the session id comes off the filename.
233
- for key in ["parent_thread_id", "forked_from_id"] {
234
- if !m.contains_key("parent_id")
235
- && let Some(v) = payload.get(key).and_then(|v| v.as_str())
236
- {
237
- m.insert("parent_id".into(), json!(v));
238
- }
239
- }
240
- Some((Value::Object(m), Some(ts)))
241
- }
242
-
243
- /// The single `agent_end`, derived deterministically from the last timestamp
244
- /// and the file size (used as its offset, so it is unique per session).
245
- ///
246
- /// Index 999 puts it after every content event sharing that timestamp — the
247
- /// server's tie-break is a random id, so without this a session can appear to
248
- /// end before its last turn. Codex writes a `token_count` line in the same
249
- /// millisecond as the tool output it bills, so ties are the normal case here,
250
- /// not an edge one.
251
- pub fn agent_end(ctx: &Ctx, last_ts: &str, size: u64) -> Value {
252
- match base(ctx, "agent_end", last_ts, 999, size) {
253
- Some(m) => Value::Object(m),
254
- // `base` only fails on an unparseable timestamp, which cannot happen
255
- // here: `last_ts` came from a line `envelope` already normalized.
256
- None => json!({
257
- "timestamp": last_ts,
258
- "session_id": ctx.session_id,
259
- "agent_id": ctx.agent_id,
260
- "type": "agent_end",
261
- "environment": ctx.environment,
262
- }),
263
- }
264
- }
265
-
266
- /// One content line to its timestamp and the events it yields.
267
- ///
268
- /// Every branch falls through to "no events" rather than enumerating what to
269
- /// ignore, so `world_state`, `compacted`, `thread_settings_applied` and
270
- /// whatever the next Codex release adds cost nothing. The timestamp is still
271
- /// returned for those lines: they are real activity, and `agent_end` should
272
- /// reflect when the file last moved rather than when its last *interesting*
273
- /// record was written.
274
- pub fn transform_line(
275
- line: &str,
276
- ctx: &Ctx,
277
- offset: u64,
278
- state: &mut TailState,
279
- ) -> (Option<String>, Vec<Value>) {
280
- let Some((ts, kind, payload)) = envelope(line) else {
281
- return (None, Vec::new());
282
- };
283
-
284
- let events = match kind.as_str() {
285
- // Not emitted; carries the active model forward for every later event.
286
- // Codex writes it before the first human prompt in all 13 rollouts
287
- // measured, which is why this source needs no `seed_state` and so
288
- // avoids the live-tail-vs-re-read hazard documented on that hook.
289
- "turn_context" => {
290
- if let Some(model) = payload.get("model").and_then(|m| m.as_str()) {
291
- state.last_model = Some(model.to_string());
292
- }
293
- Vec::new()
294
- }
295
- "response_item" => response_item_events(&payload, ctx, &ts, offset, state),
296
- "event_msg" => event_msg_events(&payload, ctx, &ts, offset, state),
297
- // `session_meta` is the engine's `agent_start`; emitting it here too
298
- // would give the session two start events at the same offset.
299
- _ => Vec::new(),
300
- };
301
- (Some(ts), events)
302
- }
303
-
304
- /// A `response_item` is one item of an OpenAI Responses API turn.
305
- ///
306
- /// Codex writes exactly one item per line — verified across all 6,520 lines —
307
- /// so every branch here yields at most one event and the block index stays 0.
308
- /// The plumbing for a non-zero index is still in [`base`] because the shape is
309
- /// not guaranteed: `agent_end` uses it today, and a future Codex that batches
310
- /// items onto one line would otherwise ship them in random order.
311
- fn response_item_events(
312
- p: &Value,
313
- ctx: &Ctx,
314
- ts: &str,
315
- offset: u64,
316
- state: &mut TailState,
317
- ) -> Vec<Value> {
318
- match payload_type(p) {
319
- Some("message") => message_events(p, ctx, ts, offset, state),
320
- Some("function_call") => tool_use(
321
- ctx,
322
- ts,
323
- offset,
324
- state,
325
- p,
326
- named(p, "tool"),
327
- parse_arguments(p.get("arguments")),
328
- ),
329
- Some("custom_tool_call") => tool_use(
330
- ctx,
331
- ts,
332
- offset,
333
- state,
334
- p,
335
- named(p, "tool"),
336
- parse_arguments(p.get("input")),
337
- ),
338
- // Responses-API item types that produce a `*_call_output` result like
339
- // any other tool. Not observed in the rollouts on this machine, but
340
- // omitting the CALL while still emitting its RESULT is precisely the
341
- // blank-tool-name row this source exists to avoid, so they are carried.
342
- Some("local_shell_call") => tool_use(
343
- ctx,
344
- ts,
345
- offset,
346
- state,
347
- p,
348
- "local_shell".into(),
349
- p.get("action").cloned().unwrap_or(Value::Null),
350
- ),
351
- Some("web_search_call") => tool_use(
352
- ctx,
353
- ts,
354
- offset,
355
- state,
356
- p,
357
- "web_search".into(),
358
- p.get("action").cloned().unwrap_or(Value::Null),
359
- ),
360
- Some("function_call_output") | Some("custom_tool_call_output") => {
361
- tool_result(ctx, ts, offset, state, p)
362
- }
363
- // `reasoning` carries `encrypted_content` and, in every one of the
364
- // 1,018 on disk, an EMPTY `summary` with no `content` — so an event
365
- // built from it is a blank assistant row with nothing in it.
366
- _ => Vec::new(),
367
- }
368
- }
369
-
370
- /// A `message` item: the conversation itself.
371
- ///
372
- /// Assistant messages become a `model_response`, everything else (user,
373
- /// developer) a `model_request`. Content is an array of parts of ONE message,
374
- /// so the parts are joined rather than split into several events — the largest
375
- /// on this machine has 52 of them, which as separate rows would bury the turn
376
- /// it belongs to.
377
- fn message_events(p: &Value, ctx: &Ctx, ts: &str, offset: u64, state: &TailState) -> Vec<Value> {
378
- let role = p.get("role").and_then(|r| r.as_str()).unwrap_or("user");
379
- let Some(blocks) = p.get("content").and_then(|c| c.as_array()) else {
380
- return Vec::new();
381
- };
382
- let texts: Vec<&str> = blocks
383
- .iter()
384
- .filter_map(|b| b.get("text").and_then(|t| t.as_str()))
385
- .filter(|t| !t.is_empty())
386
- .collect();
387
- if texts.is_empty() {
388
- return Vec::new();
389
- }
390
-
391
- if role == "assistant" {
392
- let Some(mut m) = base(ctx, "model_response", ts, 0, offset) else {
393
- return Vec::new();
394
- };
395
- m.insert("role".into(), json!("assistant"));
396
- m.insert("content".into(), json!(texts.join("\n")));
397
- insert_model(&mut m, state);
398
- return vec![Value::Object(m)];
399
- }
400
-
401
- let Some(mut m) = base(ctx, "model_request", ts, 0, offset) else {
402
- return Vec::new();
403
- };
404
- // One entry per content part: `messages` is an array by shape, so the parts
405
- // survive individually without needing an event each.
406
- let messages: Vec<Value> = texts
407
- .iter()
408
- .map(|t| json!({ "role": role, "content": t }))
409
- .collect();
410
- m.insert("messages".into(), json!(messages));
411
- insert_model(&mut m, state);
412
- vec![Value::Object(m)]
413
- }
414
-
415
- /// An `event_msg` is Codex's UI-facing stream, mostly duplicating the
416
- /// `response_item` records.
417
- fn event_msg_events(p: &Value, ctx: &Ctx, ts: &str, offset: u64, state: &TailState) -> Vec<Value> {
418
- match payload_type(p) {
419
- // The accounting record of one model response, written on its own line
420
- // in the same millisecond as the item it bills. Attaching it to that
421
- // item would need cross-line buffering, which is exactly what breaks
422
- // the "one line in, same events out" invariant a re-read depends on —
423
- // so it becomes its own event instead.
424
- Some("token_count") => {
425
- let Some(usage) = p.get("info").and_then(|i| i.get("last_token_usage")) else {
426
- return Vec::new();
427
- };
428
- let Some(mut m) = base(ctx, "model_response", ts, 0, offset) else {
429
- return Vec::new();
430
- };
431
- if let Some(n) = usage.get("input_tokens").and_then(|x| x.as_u64()) {
432
- m.insert("input_tokens".into(), json!(n));
433
- }
434
- if let Some(n) = usage.get("output_tokens").and_then(|x| x.as_u64()) {
435
- m.insert("output_tokens".into(), json!(n));
436
- }
437
- m.insert("codex_usage".into(), usage.clone());
438
- m.insert("codex_kind".into(), json!("token_count"));
439
- insert_model(&mut m, state);
440
- vec![Value::Object(m)]
441
- }
442
- // `user_message` / `agent_message` restate the `response_item` message
443
- // lines Codex writes for the same turn — measured 127 vs 145 user and
444
- // 284 vs 292 assistant, i.e. the response-item stream is a superset.
445
- // Emitting both would double every prompt and every reply.
446
- //
447
- // `patch_apply_end` looks like a tool result but its `call_id` is an
448
- // internal `exec-<uuid>` that matches NO tool call on disk (checked for
449
- // all 130 of them), so it would render as an orphan row with no tool
450
- // name; the apply_patch call's own `*_call_output` already carries the
451
- // outcome.
452
- _ => Vec::new(),
453
- }
454
- }
455
-
456
- fn insert_model(m: &mut Map<String, Value>, state: &TailState) {
457
- if let Some(model) = &state.last_model {
458
- m.insert("model".into(), json!(model));
459
- }
460
- }
461
-
462
- /// A tool's name, defaulted rather than omitted — a nameless row in the product
463
- /// is indistinguishable from a broken one.
464
- fn named(p: &Value, fallback: &str) -> String {
465
- p.get("name")
466
- .and_then(|n| n.as_str())
467
- .filter(|n| !n.is_empty())
468
- .unwrap_or(fallback)
469
- .to_string()
470
- }
471
-
472
- /// `call_id` is what a result quotes back; `id` is the item's own id and only
473
- /// a fallback.
474
- fn call_id_of(p: &Value) -> Option<String> {
475
- for key in ["call_id", "id"] {
476
- if let Some(v) = p.get(key).and_then(|v| v.as_str())
477
- && !v.is_empty()
478
- {
479
- return Some(v.to_string());
480
- }
481
- }
482
- None
483
- }
484
-
485
- fn tool_use(
486
- ctx: &Ctx,
487
- ts: &str,
488
- offset: u64,
489
- state: &mut TailState,
490
- p: &Value,
491
- name: String,
492
- input: Value,
493
- ) -> Vec<Value> {
494
- let Some(mut m) = base(ctx, "tool_use", ts, 0, offset) else {
495
- return Vec::new();
496
- };
497
- // Fall back to an offset-derived id so a call with no id cannot hash-
498
- // collapse into another one; a rollout line is unique by its offset.
499
- let id = call_id_of(p).unwrap_or_else(|| format!("codex-{offset}"));
500
- // The result line names no tool. Without carrying it from here, every tool
501
- // result is a blank row in the product.
502
- state.remember_tool(id.clone(), name.clone());
503
- m.insert("tool_name".into(), json!(name));
504
- m.insert("tool_call_id".into(), json!(id));
505
- if !input.is_null() {
506
- m.insert("input".into(), input);
507
- }
508
- insert_model(&mut m, state);
509
- vec![Value::Object(m)]
510
- }
511
-
512
- fn tool_result(ctx: &Ctx, ts: &str, offset: u64, state: &TailState, p: &Value) -> Vec<Value> {
513
- let Some(mut m) = base(ctx, "tool_result", ts, 0, offset) else {
514
- return Vec::new();
515
- };
516
- if let Some(id) = call_id_of(p) {
517
- m.insert("tool_call_id".into(), json!(id));
518
- // The remembered name wins over the payload's own: on disk
519
- // `function_call_output.name` is literally `null` and
520
- // `custom_tool_call_output` has no `name` key at all, so the payload is
521
- // only consulted in case a later Codex starts filling it in.
522
- let name = state
523
- .tool_name(&id)
524
- .map(str::to_string)
525
- .or_else(|| p.get("name").and_then(|n| n.as_str()).map(str::to_string))
526
- .filter(|n| !n.is_empty());
527
- if let Some(name) = name {
528
- m.insert("tool_name".into(), json!(name));
529
- }
530
- }
531
- if let Some(output) = p.get("output") {
532
- m.insert("output".into(), json!(stringify(output)));
533
- }
534
- vec![Value::Object(m)]
535
- }
536
-
537
- /// Render a tool result payload as text. Codex uses a bare string, or an array
538
- /// of `{type:"input_text", text}` blocks (a wall-time preamble plus the real
539
- /// output, in the rollouts measured).
540
- fn stringify(v: &Value) -> String {
541
- match v {
542
- Value::String(s) => s.clone(),
543
- Value::Array(items) => items
544
- .iter()
545
- .filter_map(|b| b.get("text").and_then(|t| t.as_str()))
546
- .collect::<Vec<_>>()
547
- .join("\n"),
548
- other => other.to_string(),
549
- }
550
- }
551
-
552
- /// Normalise a tool call's serialized arguments into structured JSON.
553
- ///
554
- /// Codex serialises them as a *string*, and the two tool families disagree
555
- /// about what is in it. Measured over every tool call on this machine:
556
- ///
557
- /// | shape | whole-string JSON | lifted `{…}` | kept raw |
558
- /// |---|---|---|---|
559
- /// | `function_call.arguments` | 133 | 0 | 0 |
560
- /// | `custom_tool_call.input` | 0 | 989 | 141 |
561
- ///
562
- /// So a plain `serde_json::from_str` — which is all the format notes describe —
563
- /// recovers the arguments of 133 of 1,263 calls and leaves 89% of this
564
- /// machine's tool use rendering as an opaque blob of JavaScript. The raw string
565
- /// is kept when nothing parses, so no branch here can lose information.
566
- fn parse_arguments(arg: Option<&Value>) -> Value {
567
- match arg {
568
- None | Some(Value::Null) => Value::Null,
569
- Some(Value::String(s)) => {
570
- if let Ok(v) = serde_json::from_str::<Value>(s) {
571
- v
572
- } else if let Some(v) = lift_json_object(s) {
573
- v
574
- } else {
575
- json!({ "raw": s })
576
- }
577
- }
578
- Some(other) => other.clone(),
579
- }
580
- }
581
-
582
- /// Scan successive balanced `{…}` substrings and return the first that reads as
583
- /// a JSON object, repairing JavaScript object-literal keys if needed.
584
- ///
585
- /// `custom_tool_call.input` is a JS snippet like
586
- /// `const r = await tools.exec_command({cmd:"ls","workdir":"/x"})`, so the
587
- /// arguments are an inner brace group, and the model quotes keys inconsistently
588
- /// *within the same object*. Trying successive groups is what handles a snippet
589
- /// that opens with a destructuring pattern — `let{output,...rest}=await …` puts
590
- /// the real arguments in the SECOND group.
591
- ///
592
- /// Pure and deterministic, so a re-read reproduces the same value.
593
- fn lift_json_object(s: &str) -> Option<Value> {
594
- let bytes = s.as_bytes();
595
- let mut search = 0usize;
596
- while let Some(rel) = s[search..].find('{') {
597
- let start = search + rel;
598
- let Some(end) = balanced_end(bytes, start) else {
599
- break; // unbalanced from here on; no later group can close either
600
- };
601
- // `start`/`end` sit on ASCII braces, so the slice is char-safe.
602
- let candidate = &s[start..=end];
603
- if let Ok(v @ Value::Object(_)) = serde_json::from_str::<Value>(candidate) {
604
- return Some(v);
605
- }
606
- if let Ok(v @ Value::Object(_)) = serde_json::from_str::<Value>(&quote_bare_keys(candidate))
607
- {
608
- return Some(v);
609
- }
610
- search = start + 1; // that group was not JSON — try the next one
611
- }
612
- None
613
- }
614
-
615
- /// Index of the `}` closing the group that opens at `start`, honouring string
616
- /// literals and backslash escapes.
617
- ///
618
- /// Byte-wise is safe: `{`, `}`, `"` and `\` are ASCII, and no UTF-8
619
- /// continuation byte can equal an ASCII value.
620
- fn balanced_end(bytes: &[u8], start: usize) -> Option<usize> {
621
- let mut depth = 0i32;
622
- let mut in_str = false;
623
- let mut escaped = false;
624
- for (i, &c) in bytes.iter().enumerate().skip(start) {
625
- if in_str {
626
- if escaped {
627
- escaped = false;
628
- } else if c == b'\\' {
629
- escaped = true;
630
- } else if c == b'"' {
631
- in_str = false;
632
- }
633
- continue;
634
- }
635
- match c {
636
- b'"' => in_str = true,
637
- b'{' => depth += 1,
638
- b'}' => {
639
- depth -= 1;
640
- if depth == 0 {
641
- return Some(i);
642
- }
643
- }
644
- _ => {}
645
- }
646
- }
647
- None
648
- }
649
-
650
- /// Quote bare identifier keys so a JavaScript object literal parses as JSON.
651
- ///
652
- /// Only rewrites an identifier that is BOTH at a key position (directly after
653
- /// `{` or `,`, whitespace aside) AND followed by `:`. That leaves values,
654
- /// spread patterns (`{output,...rest}`) and anything inside a string literal
655
- /// untouched — and an already-quoted key can never match, so valid JSON passes
656
- /// through byte-identical. Callers only use the result when the unrepaired
657
- /// candidate failed to parse, so a mangled repair costs nothing.
658
- fn quote_bare_keys(s: &str) -> String {
659
- let mut out = String::with_capacity(s.len() + 16);
660
- let mut in_str = false;
661
- let mut escaped = false;
662
- let mut at_key = false;
663
- let mut chars = s.char_indices().peekable();
664
-
665
- while let Some((i, c)) = chars.next() {
666
- if in_str {
667
- out.push(c);
668
- if escaped {
669
- escaped = false;
670
- } else if c == '\\' {
671
- escaped = true;
672
- } else if c == '"' {
673
- in_str = false;
674
- }
675
- continue;
676
- }
677
- match c {
678
- '"' => {
679
- in_str = true;
680
- at_key = false;
681
- out.push(c);
682
- }
683
- '{' | ',' => {
684
- at_key = true;
685
- out.push(c);
686
- }
687
- _ if c.is_whitespace() => out.push(c),
688
- _ if at_key && (c.is_ascii_alphabetic() || c == '_' || c == '$') => {
689
- let mut end = i + c.len_utf8();
690
- while let Some(&(j, d)) = chars.peek() {
691
- if d.is_ascii_alphanumeric() || d == '_' || d == '$' {
692
- end = j + d.len_utf8();
693
- chars.next();
694
- } else {
695
- break;
696
- }
697
- }
698
- let ident = &s[i..end];
699
- if s[end..].trim_start().starts_with(':') {
700
- out.push('"');
701
- out.push_str(ident);
702
- out.push('"');
703
- } else {
704
- out.push_str(ident);
705
- }
706
- at_key = false;
707
- }
708
- _ => {
709
- at_key = false;
710
- out.push(c);
711
- }
712
- }
713
- }
714
- out
715
- }