failproofai 1.0.0-beta.4 → 1.0.0-beta.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.next/standalone/.next/BUILD_ID +1 -1
- package/.next/standalone/.next/app-path-routes-manifest.json +2 -1
- package/.next/standalone/.next/build-manifest.json +3 -3
- package/.next/standalone/.next/prerender-manifest.json +3 -3
- package/.next/standalone/.next/required-server-files.json +1 -1
- package/.next/standalone/.next/routes-manifest.json +6 -0
- package/.next/standalone/.next/server/app/_global-error/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/_global-error/page.js +3 -1
- package/.next/standalone/.next/server/app/_global-error/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/_global-error.html +1 -1
- package/.next/standalone/.next/server/app/_global-error.rsc +7 -7
- package/.next/standalone/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +7 -7
- package/.next/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_not-found/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/_not-found/page.js +3 -1
- package/.next/standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/_not-found.html +1 -1
- package/.next/standalone/.next/server/app/_not-found.rsc +15 -15
- package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +15 -15
- package/.next/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +4 -4
- package/.next/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +10 -10
- package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/api/audit/invite/route.js +3 -2
- package/.next/standalone/.next/server/app/api/audit/invite/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/audit/run/route.js +4 -3
- package/.next/standalone/.next/server/app/api/audit/run/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/audit/status/route.js +1 -1
- package/.next/standalone/.next/server/app/api/audit/status/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/auth/login-request/route.js +2 -1
- package/.next/standalone/.next/server/app/api/auth/login-request/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/auth/login-verify/route.js +3 -2
- package/.next/standalone/.next/server/app/api/auth/login-verify/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/auth/logout/route.js +3 -2
- package/.next/standalone/.next/server/app/api/auth/logout/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/auth/reminder/route.js +3 -2
- package/.next/standalone/.next/server/app/api/auth/reminder/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/auth/status/route.js +3 -2
- package/.next/standalone/.next/server/app/api/auth/status/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/download/[project]/[session]/route.js +1 -1
- package/.next/standalone/.next/server/app/api/download/[project]/[session]/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/audit/page/server-reference-manifest.json +2 -2
- package/.next/standalone/.next/server/app/audit/page.js +5 -3
- package/.next/standalone/.next/server/app/audit/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/audit/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/index.html +1 -1
- package/.next/standalone/.next/server/app/index.rsc +15 -15
- package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +15 -15
- package/.next/standalone/.next/server/app/index.segments/_head.segment.rsc +4 -4
- package/.next/standalone/.next/server/app/index.segments/_index.segment.rsc +10 -10
- package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/page.js +3 -1
- package/.next/standalone/.next/server/app/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/policies/page/server-reference-manifest.json +10 -10
- package/.next/standalone/.next/server/app/policies/page.js +4 -2
- package/.next/standalone/.next/server/app/policies/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/policies/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/project/[name]/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/project/[name]/page.js +4 -2
- package/.next/standalone/.next/server/app/project/[name]/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/project/[name]/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/react-loadable-manifest.json +2 -2
- package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/server-reference-manifest.json +2 -2
- package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page.js +6 -4
- package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/projects/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/projects/page.js +4 -2
- package/.next/standalone/.next/server/app/projects/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/projects/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/settings/page/app-paths-manifest.json +3 -0
- package/.next/standalone/.next/server/app/settings/page/build-manifest.json +18 -0
- package/.next/standalone/.next/server/app/settings/page/next-font-manifest.json +6 -0
- package/.next/standalone/.next/server/app/settings/page/react-loadable-manifest.json +1 -0
- package/.next/standalone/.next/server/app/settings/page/server-reference-manifest.json +53 -0
- package/.next/standalone/.next/server/app/settings/page.js +18 -0
- package/.next/standalone/.next/server/app/settings/page.js.map +5 -0
- package/.next/standalone/.next/server/app/settings/page.js.nft.json +1 -0
- package/.next/standalone/.next/server/app/settings/page_client-reference-manifest.js +3 -0
- package/.next/standalone/.next/server/app-paths-manifest.json +2 -1
- package/.next/standalone/.next/server/chunks/{[externals]__1nl3dvw._.js → [externals]__0r-zamh._.js} +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__06hexd0._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__094p1f1._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0_0xu5z._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0ed01_d._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0g0vcwt._.js +3 -0
- package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0h3lfmp._.js → [root-of-the-server]__0ky_n0r._.js} +2 -2
- package/.next/standalone/.next/server/chunks/{[root-of-the-server]__18d-9oi._.js → [root-of-the-server]__0lk_935._.js} +2 -2
- package/.next/standalone/.next/server/chunks/{[root-of-the-server]__1p7s8-d._.js → [root-of-the-server]__0pbp9fe._.js} +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0q-v9z2._.js +1 -1
- package/.next/standalone/.next/server/chunks/{[root-of-the-server]__10oa-v9._.js → [root-of-the-server]__0v2fpxe._.js} +2 -2
- package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0sb_5m8._.js → [root-of-the-server]__131ebum._.js} +3 -3
- package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0-dh5jy._.js → [root-of-the-server]__1_ps0jw._.js} +2 -2
- package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0l4vuqm._.js → [root-of-the-server]__1a7i2q4._.js} +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1ibjy5x._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1iny24d._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1tvn4wf._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1tyedjt._.js +3 -0
- package/.next/standalone/.next/server/chunks/_0lxbzdq._.js +5 -0
- package/.next/standalone/.next/server/chunks/_1zuiiy3._.js +5 -0
- package/.next/standalone/.next/server/chunks/lib_telemetry_ts_0dctyyw._.js +5 -0
- package/.next/standalone/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_17k9e3w.js +5 -5
- package/.next/standalone/.next/server/chunks/package_json_[json]_cjs_1nxcc4v._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__06bp_fg._.js +5 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__074qmkp._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0spkm68._.js +10 -10
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1_a_gwn._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1a2hcb_._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1e7-pa7._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0rtdfof._.js → [root-of-the-server]__1rdruw4._.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1rv-sc9._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1tyf0tc._.js +5 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1u-wx42._.js +4 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1v185mo._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0rag5dg._.js → [root-of-the-server]__1yw368c._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/_0-yi74u._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_04mekdy._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_0igtyj5._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_0r-dsre._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_0rjgfln._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_0se484m._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_0uz7o9y._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_11_p9y8._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_1fahg9e._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_1gmzkwj._.js +5 -0
- package/.next/standalone/.next/server/chunks/ssr/_1w8sola._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_1w_6p9g._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/app_audit__components_audit-dashboard_tsx_0p9ud47._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/app_global-error_tsx_1kp6l3x._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/app_policies_hooks-client_tsx_19dqvpc._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0dwo94s.js +4 -0
- package/.next/standalone/.next/server/chunks/ssr/src_hooks_builtin-policies_ts_09j2ndl._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/src_hooks_fp-config_ts_04t589g._.js +5 -0
- package/.next/standalone/.next/server/middleware-build-manifest.js +3 -3
- package/.next/standalone/.next/server/middleware.js +2 -2
- package/.next/standalone/.next/server/pages/404.html +1 -1
- package/.next/standalone/.next/server/pages/500.html +1 -1
- package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/server-reference-manifest.json +54 -12
- package/.next/standalone/.next/static/chunks/{2c90h1g6x8z8y.js → 0_2n13i94rnw5.js} +1 -1
- package/.next/standalone/.next/static/chunks/1bm0q12hgs22l.css +2 -0
- package/.next/standalone/.next/static/chunks/1v1gqvpjk62jm.js +1 -0
- package/.next/standalone/.next/static/chunks/23557z4e6dtsr.js +1 -0
- package/.next/standalone/.next/static/chunks/28zkwzu50puki.js +1 -0
- package/.next/standalone/.next/static/chunks/2uvhw57mf9lg_.css +2 -0
- package/.next/standalone/.next/static/chunks/3081gykdubv8b.js +1 -0
- package/.next/standalone/.next/static/chunks/{06jakt_xhoolk.js → 34fa65k0cldkj.js} +1 -1
- package/.next/standalone/.next/static/chunks/35v07j9gc1pvr.js +6 -0
- package/.next/standalone/.next/static/chunks/{2zb3m1tzq6h98.js → 3f_939wi3kfnx.js} +22 -22
- package/.next/standalone/.next/static/chunks/{31cqiv_cpgj9m.js → 3p1vpm2_-tfwm.js} +1 -1
- package/.next/standalone/.next/static/chunks/{0ue9ak_xexiqh.js → 3rbpw_waieafm.js} +1 -1
- package/.next/standalone/.next/static/chunks/40ffnfpkeyvb0.js +1 -0
- package/.next/standalone/app/actions/get-hooks-config.ts +2 -1
- package/.next/standalone/app/actions/get-scheduled-audit.ts +70 -0
- package/.next/standalone/app/actions/update-scheduled-audit.ts +44 -0
- package/.next/standalone/app/api/audit/run/route.ts +28 -0
- package/.next/standalone/app/api/audit/status/route.ts +13 -1
- package/.next/standalone/app/api/auth/status/route.ts +1 -1
- package/.next/standalone/app/audit/_components/auth-dialog.css +159 -0
- package/.next/standalone/app/audit/_components/auth-dialog.tsx +3 -0
- package/.next/standalone/app/audit/audit-styles.css +6 -149
- package/.next/standalone/app/settings/page.tsx +31 -0
- package/.next/standalone/app/settings/settings-client.tsx +488 -0
- package/.next/standalone/components/navbar.tsx +2 -0
- package/.next/standalone/lib/auth/api-server-client.ts +2 -3
- package/.next/standalone/lib/auth/auth-store.ts +4 -4
- package/.next/standalone/lib/codex-sessions.ts +2 -1
- package/.next/standalone/lib/dashboard-host.ts +101 -0
- package/.next/standalone/lib/install-check.ts +22 -7
- package/.next/standalone/lib/pi-sessions.ts +99 -14
- package/.next/standalone/lib/telemetry-enabled.ts +54 -0
- package/.next/standalone/lib/telemetry-id.ts +52 -1
- package/.next/standalone/lib/telemetry.ts +8 -4
- package/.next/standalone/node_modules/react/cjs/react.development.js +1 -1
- package/.next/standalone/node_modules/react/cjs/react.production.js +1 -1
- package/.next/standalone/node_modules/react/package.json +3 -3
- package/.next/standalone/node_modules/react-dom/cjs/react-dom-server-legacy.browser.production.js +1 -1
- package/.next/standalone/node_modules/react-dom/cjs/react-dom-server-legacy.node.production.js +1 -1
- package/.next/standalone/node_modules/react-dom/cjs/react-dom-server.browser.production.js +3 -3
- package/.next/standalone/node_modules/react-dom/cjs/react-dom-server.edge.production.js +3 -3
- package/.next/standalone/node_modules/react-dom/cjs/react-dom-server.node.production.js +3 -3
- package/.next/standalone/node_modules/react-dom/cjs/react-dom.production.js +1 -1
- package/.next/standalone/node_modules/react-dom/package.json +4 -4
- package/.next/standalone/package.json +7 -6
- package/.next/standalone/proxy.ts +89 -1
- package/.next/standalone/server.js +1 -1
- package/bin/failproofai.mjs +197 -80
- package/dist/cli.mjs +17699 -15345
- package/dist/worker.mjs +1620 -257
- package/lib/auth/api-server-client.ts +2 -3
- package/lib/auth/auth-store.ts +4 -4
- package/lib/codex-sessions.ts +2 -1
- package/lib/dashboard-host.ts +101 -0
- package/lib/install-check.ts +22 -7
- package/lib/pi-sessions.ts +99 -14
- package/lib/telemetry-enabled.ts +54 -0
- package/lib/telemetry-id.ts +52 -1
- package/lib/telemetry.ts +8 -4
- package/package.json +7 -6
- package/scripts/install-telemetry.mjs +8 -1
- package/scripts/launch.ts +25 -3
- package/scripts/parse-script-args.ts +17 -1
- package/scripts/prune-standalone.mjs +20 -0
- package/scripts/translate-docs/readme-translator.ts +163 -4
- package/scripts/validate-mdx.ts +153 -13
- package/src/audit/audit-lock.ts +285 -0
- package/src/audit/audit-schedule.ts +111 -0
- package/src/audit/cache.ts +18 -4
- package/src/audit/cli-adapters/goose.ts +2 -1
- package/src/audit/cli-adapters/hermes.ts +28 -10
- package/src/audit/cli.ts +191 -35
- package/src/audit/dashboard-cache.ts +2 -1
- package/src/hooks/builtin-policies.ts +100 -3
- package/src/hooks/cloud-connection.ts +163 -14
- package/src/hooks/cloud-enrollment-cli.ts +119 -21
- package/src/hooks/cloud-enrollment.ts +87 -17
- package/src/hooks/cloud-introspect.ts +147 -0
- package/src/hooks/cloud-managed-policies.ts +33 -2
- package/src/hooks/collector-config.ts +32 -40
- package/src/hooks/configure-wizard.ts +696 -318
- package/src/hooks/custom-hooks-loader.ts +125 -11
- package/src/hooks/daemon-client.ts +83 -17
- package/src/hooks/daemon-download.ts +54 -2
- package/src/hooks/daemon-service.ts +595 -27
- package/src/hooks/first-run-gate.ts +39 -0
- package/src/hooks/fp-config.ts +497 -0
- package/src/hooks/fp-home.ts +342 -0
- package/src/hooks/fp-reset.ts +332 -0
- package/src/hooks/handler.ts +42 -1
- package/src/hooks/hook-activity-store.ts +35 -20
- package/src/hooks/hook-logger.ts +2 -1
- package/src/hooks/hook-telemetry.ts +5 -1
- package/src/hooks/hooks-config.ts +4 -3
- package/src/hooks/loader-utils.ts +166 -5
- package/src/hooks/manager.ts +5 -4
- package/src/hooks/onboarding-lock.ts +119 -0
- package/src/hooks/policy-types.ts +0 -7
- package/src/hooks/session-pause-cli.ts +15 -13
- package/src/hooks/session-pause.ts +36 -4
- package/src/hooks/setup-state.ts +256 -0
- package/src/hooks/tui.ts +4 -4
- package/src/hooks/worker-server.ts +53 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0f8nu8d._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0szqzl8._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__17g9wh7._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__19120tr._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1fwl2mz._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1myjm-d._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1rhmvod._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__02r5bgf._.js +0 -4
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0cmdyn_._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0e8sjqm._.js +0 -4
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0lkzqax._.js +0 -4
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0ls0gsr._.js +0 -4
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0n_uvv0._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0qucxyj._.js +0 -4
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0sdrz-j._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0u02miy._.js +0 -4
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__14dd6h8._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1j4u3yd._.js +0 -4
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1zqz4v8._.js +0 -4
- package/.next/standalone/.next/server/chunks/ssr/_1m_p7pi._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/node_modules_html-to-image_es_index_1q9xxca.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/src_hooks_1ezd2jf._.js +0 -5
- package/.next/standalone/.next/server/chunks/ssr/src_hooks_1tnuifj._.js +0 -5
- package/.next/standalone/.next/static/chunks/0h7auy7hzjyhw.js +0 -1
- package/.next/standalone/.next/static/chunks/0oe2-hp0_2tzs.js +0 -6
- package/.next/standalone/.next/static/chunks/1fw3pxobk_otl.js +0 -1
- package/.next/standalone/.next/static/chunks/3h5_3u46gu9jx.js +0 -1
- package/.next/standalone/.next/static/chunks/3i27c3hcriawq.css +0 -1
- package/.next/standalone/.next/static/chunks/3zdwnnthucs_1.css +0 -2
- package/.next/standalone/.next/static/chunks/43a1ywqsg9bq9.js +0 -1
- package/.next/standalone/Cargo.lock +0 -2222
- package/.next/standalone/Cargo.toml +0 -9
- package/.next/standalone/crates/CLOUD_POLICIES.md +0 -136
- package/.next/standalone/crates/PROTOCOL.md +0 -122
- package/.next/standalone/crates/failproofaid/Cargo.toml +0 -25
- package/.next/standalone/crates/failproofaid/src/cloud_client.rs +0 -484
- package/.next/standalone/crates/failproofaid/src/cloud_policies.rs +0 -921
- package/.next/standalone/crates/failproofaid/src/lock.rs +0 -81
- package/.next/standalone/crates/failproofaid/src/main.rs +0 -532
- package/.next/standalone/crates/failproofaid/src/paths.rs +0 -201
- package/.next/standalone/crates/failproofaid/src/server.rs +0 -502
- package/.next/standalone/crates/failproofaid/src/worker.rs +0 -400
- package/.next/standalone/crates/failproofaid/tests/daemon_e2e.rs +0 -241
- package/.next/standalone/crates/fpai-collect/Cargo.toml +0 -43
- package/.next/standalone/crates/fpai-collect/src/config.rs +0 -412
- package/.next/standalone/crates/fpai-collect/src/cursor.rs +0 -520
- package/.next/standalone/crates/fpai-collect/src/delivery.rs +0 -472
- package/.next/standalone/crates/fpai-collect/src/filetail.rs +0 -484
- package/.next/standalone/crates/fpai-collect/src/health.rs +0 -369
- package/.next/standalone/crates/fpai-collect/src/lib.rs +0 -34
- package/.next/standalone/crates/fpai-collect/src/redact.rs +0 -516
- package/.next/standalone/crates/fpai-collect/src/sources/claude/mod.rs +0 -279
- package/.next/standalone/crates/fpai-collect/src/sources/claude/transform.rs +0 -619
- package/.next/standalone/crates/fpai-collect/src/sources/codex/mod.rs +0 -156
- package/.next/standalone/crates/fpai-collect/src/sources/codex/transform.rs +0 -715
- package/.next/standalone/crates/fpai-collect/src/sources/copilot/mod.rs +0 -158
- package/.next/standalone/crates/fpai-collect/src/sources/copilot/transform.rs +0 -512
- package/.next/standalone/crates/fpai-collect/src/sources/goose/mod.rs +0 -511
- package/.next/standalone/crates/fpai-collect/src/sources/goose/transform.rs +0 -586
- package/.next/standalone/crates/fpai-collect/src/sources/hermes/mod.rs +0 -318
- package/.next/standalone/crates/fpai-collect/src/sources/hermes/transform.rs +0 -579
- package/.next/standalone/crates/fpai-collect/src/sources/hooks/mod.rs +0 -310
- package/.next/standalone/crates/fpai-collect/src/sources/hooks/transform.rs +0 -448
- package/.next/standalone/crates/fpai-collect/src/sources/mod.rs +0 -23
- package/.next/standalone/crates/fpai-collect/src/sources/openclaw/mod.rs +0 -176
- package/.next/standalone/crates/fpai-collect/src/sources/openclaw/transform.rs +0 -500
- package/.next/standalone/crates/fpai-collect/src/sources/opencode/mod.rs +0 -315
- package/.next/standalone/crates/fpai-collect/src/sources/opencode/transform.rs +0 -493
- package/.next/standalone/crates/fpai-collect/src/sources/pi/mod.rs +0 -201
- package/.next/standalone/crates/fpai-collect/src/sources/pi/transform.rs +0 -533
- package/.next/standalone/crates/fpai-collect/src/spool.rs +0 -458
- package/.next/standalone/crates/fpai-collect/src/sqlitepoll.rs +0 -387
- package/.next/standalone/crates/fpai-collect/src/supervisor.rs +0 -423
- package/.next/standalone/crates/fpai-collect/src/uploader.rs +0 -600
- package/.next/standalone/crates/fpai-collect/tests/claude_source.rs +0 -738
- package/.next/standalone/crates/fpai-collect/tests/claude_subagents.rs +0 -393
- package/.next/standalone/crates/fpai-collect/tests/codex_source.rs +0 -975
- package/.next/standalone/crates/fpai-collect/tests/config.rs +0 -286
- package/.next/standalone/crates/fpai-collect/tests/copilot_source.rs +0 -1019
- package/.next/standalone/crates/fpai-collect/tests/delivery.rs +0 -281
- package/.next/standalone/crates/fpai-collect/tests/goose_source.rs +0 -1008
- package/.next/standalone/crates/fpai-collect/tests/hermes_source.rs +0 -1129
- package/.next/standalone/crates/fpai-collect/tests/hooks_source.rs +0 -621
- package/.next/standalone/crates/fpai-collect/tests/openclaw_source.rs +0 -854
- package/.next/standalone/crates/fpai-collect/tests/opencode_source.rs +0 -1478
- package/.next/standalone/crates/fpai-collect/tests/pi_source.rs +0 -1191
- package/.next/standalone/crates/fpai-collect/tests/supervisor.rs +0 -290
- package/.next/standalone/crates/fpai-collect/tests/uploader.rs +0 -506
- package/.next/standalone/crates/fpai-ipc/Cargo.toml +0 -16
- package/.next/standalone/crates/fpai-ipc/src/envelope.rs +0 -175
- package/.next/standalone/crates/fpai-ipc/src/framing.rs +0 -177
- package/.next/standalone/crates/fpai-ipc/src/lib.rs +0 -10
- package/.next/standalone/crates/fpai-ipc/src/peer.rs +0 -80
- package/.next/standalone/docker-hook-sync/Dockerfile +0 -79
- package/.next/standalone/docker-hook-sync/entrypoint.sh +0 -109
- package/.next/standalone/integration-suite/Dockerfile +0 -47
- package/.next/standalone/integration-suite/README.md +0 -129
- package/.next/standalone/integration-suite/canary-policies.mjs +0 -45
- package/.next/standalone/integration-suite/capture-tokens.sh +0 -48
- package/.next/standalone/integration-suite/ci-entrypoint.sh +0 -179
- package/.next/standalone/integration-suite/inject-tokens.sh +0 -44
- package/.next/standalone/integration-suite/install-clis.sh +0 -136
- package/.next/standalone/integration-suite/probe-cli.sh +0 -248
- package/.next/standalone/integration-suite/report.js +0 -120
- package/.next/standalone/integration-suite/run.sh +0 -159
- package/.next/standalone/openclaw-plugin/index.js +0 -223
- package/.next/standalone/openclaw-plugin/openclaw.plugin.json +0 -6
- package/.next/standalone/openclaw-plugin/package.json +0 -12
- package/.next/standalone/osv-scanner.toml +0 -17
- package/.next/standalone/pi-extension/index.ts +0 -524
- package/.next/standalone/pi-extension/package.json +0 -12
- package/.next/standalone/postcss.config.mjs +0 -8
- package/.next/standalone/readme-arch-hq.gif +0 -0
- package/.next/standalone/rust-toolchain.toml +0 -4
- package/src/auth/cli.ts +0 -371
- /package/.next/standalone/.next/static/{StV6Lay7Q1cU4ysYCFJmH → Ptn8aBQl_cnNgOd0ebyv0}/_buildManifest.js +0 -0
- /package/.next/standalone/.next/static/{StV6Lay7Q1cU4ysYCFJmH → Ptn8aBQl_cnNgOd0ebyv0}/_clientMiddlewareManifest.js +0 -0
- /package/.next/standalone/.next/static/{StV6Lay7Q1cU4ysYCFJmH → Ptn8aBQl_cnNgOd0ebyv0}/_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>("e_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
|
-
}
|