fleetlens 0.4.1 → 0.6.0
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/app/apps/web/.next/BUILD_ID +1 -1
- package/app/apps/web/.next/app-path-routes-manifest.json +16 -7
- package/app/apps/web/.next/build-manifest.json +7 -7
- package/app/apps/web/.next/prerender-manifest.json +3 -3
- package/app/apps/web/.next/required-server-files.json +2 -1
- package/app/apps/web/.next/routes-manifest.json +86 -24
- package/app/apps/web/.next/server/app/_global-error/page/build-manifest.json +4 -4
- package/app/apps/web/.next/server/app/_global-error/page.js +1 -1
- package/app/apps/web/.next/server/app/_global-error/page.js.nft.json +1 -1
- package/app/apps/web/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
- package/app/apps/web/.next/server/app/_global-error.html +1 -1
- package/app/apps/web/.next/server/app/_global-error.rsc +7 -7
- package/app/apps/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +2 -2
- package/app/apps/web/.next/server/app/_global-error.segments/_full.segment.rsc +7 -7
- package/app/apps/web/.next/server/app/_global-error.segments/_head.segment.rsc +3 -3
- package/app/apps/web/.next/server/app/_global-error.segments/_index.segment.rsc +3 -3
- package/app/apps/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/app/apps/web/.next/server/app/_not-found/page/build-manifest.json +4 -4
- package/app/apps/web/.next/server/app/_not-found/page.js +5 -4
- package/app/apps/web/.next/server/app/_not-found/page.js.nft.json +1 -1
- package/app/apps/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/app/apps/web/.next/server/app/api/digest/day/[date]/route/app-paths-manifest.json +3 -0
- package/app/apps/web/.next/server/app/api/digest/day/[date]/route.js +9 -0
- package/app/apps/web/.next/server/app/api/{insights/saved/[key] → digest/day/[date]}/route.js.nft.json +1 -1
- package/app/apps/web/.next/server/app/api/digest/day/[date]/route_client-reference-manifest.js +3 -0
- package/app/apps/web/.next/server/app/api/digest/month/[yearMonth]/route/app-paths-manifest.json +3 -0
- package/app/apps/web/.next/server/app/api/digest/month/[yearMonth]/route.js +9 -0
- package/app/apps/web/.next/server/app/api/digest/month/[yearMonth]/route.js.nft.json +1 -0
- package/app/apps/web/.next/server/app/api/digest/month/[yearMonth]/route_client-reference-manifest.js +3 -0
- package/app/apps/web/.next/server/app/api/digest/month-index/route/app-paths-manifest.json +3 -0
- package/app/apps/web/.next/server/app/api/digest/month-index/route.js +7 -0
- package/app/apps/web/.next/server/app/api/{insights/months-index → digest/month-index}/route.js.nft.json +1 -1
- package/app/apps/web/.next/server/app/api/{insights/pdf/[key] → digest/month-index}/route_client-reference-manifest.js +1 -1
- package/app/apps/web/.next/server/app/api/digest/week/[startDate]/route/app-paths-manifest.json +3 -0
- package/app/apps/web/.next/server/app/api/digest/week/[startDate]/route.js +9 -0
- package/app/apps/web/.next/server/app/api/digest/week/[startDate]/route.js.nft.json +1 -0
- package/app/apps/web/.next/server/app/api/digest/week/[startDate]/route_client-reference-manifest.js +3 -0
- package/app/apps/web/.next/server/app/api/digest/week-index/route/app-paths-manifest.json +3 -0
- package/app/apps/web/.next/server/app/api/digest/week-index/route.js +7 -0
- package/app/apps/web/.next/server/app/api/{insights/weeks-index → digest/week-index}/route.js.nft.json +1 -1
- package/app/apps/web/.next/server/app/api/digest/week-index/route_client-reference-manifest.js +3 -0
- package/app/apps/web/.next/server/app/api/jobs/route/app-paths-manifest.json +3 -0
- package/app/apps/web/.next/server/app/api/jobs/route.js +6 -0
- package/app/apps/web/.next/server/app/api/jobs/route.js.nft.json +1 -0
- package/app/apps/web/.next/server/app/api/jobs/route_client-reference-manifest.js +3 -0
- package/app/apps/web/.next/server/app/api/runs/[runId]/route/app-paths-manifest.json +3 -0
- package/app/apps/web/.next/server/app/api/runs/[runId]/route/build-manifest.json +9 -0
- package/app/apps/web/.next/server/app/api/runs/[runId]/route.js +6 -0
- package/app/apps/web/.next/server/app/api/{insights/saved → runs/[runId]}/route.js.nft.json +1 -1
- package/app/apps/web/.next/server/app/api/runs/[runId]/route_client-reference-manifest.js +3 -0
- package/app/apps/web/.next/server/app/api/runs/[runId]/stream/route/app-paths-manifest.json +3 -0
- package/app/apps/web/.next/server/app/api/runs/[runId]/stream/route/build-manifest.json +9 -0
- package/app/apps/web/.next/server/app/api/runs/[runId]/stream/route/server-reference-manifest.json +4 -0
- package/app/apps/web/.next/server/app/api/runs/[runId]/stream/route.js +6 -0
- package/app/apps/web/.next/server/app/api/runs/[runId]/stream/route.js.map +5 -0
- package/app/apps/web/.next/server/app/api/{insights/pdf/[key] → runs/[runId]/stream}/route.js.nft.json +1 -1
- package/app/apps/web/.next/server/app/api/runs/[runId]/stream/route_client-reference-manifest.js +3 -0
- package/app/apps/web/.next/server/app/api/runs/route/app-paths-manifest.json +3 -0
- package/app/apps/web/.next/server/app/api/runs/route/build-manifest.json +9 -0
- package/app/apps/web/.next/server/app/api/runs/route/server-reference-manifest.json +4 -0
- package/app/apps/web/.next/server/app/api/runs/route.js +6 -0
- package/app/apps/web/.next/server/app/api/runs/route.js.map +5 -0
- package/app/apps/web/.next/server/app/api/{insights → runs}/route.js.nft.json +1 -1
- package/app/apps/web/.next/server/app/api/runs/route_client-reference-manifest.js +3 -0
- package/app/apps/web/.next/server/app/api/settings/route/app-paths-manifest.json +3 -0
- package/app/apps/web/.next/server/app/api/settings/route/build-manifest.json +9 -0
- package/app/apps/web/.next/server/app/api/settings/route/server-reference-manifest.json +4 -0
- package/app/apps/web/.next/server/app/api/settings/route.js +10 -0
- package/app/apps/web/.next/server/app/api/settings/route.js.map +5 -0
- package/app/apps/web/.next/server/app/api/settings/route.js.nft.json +1 -0
- package/app/apps/web/.next/server/app/api/{insights → settings}/route_client-reference-manifest.js +1 -1
- package/app/apps/web/.next/server/app/day/[date]/page/app-paths-manifest.json +3 -0
- package/app/apps/web/.next/server/app/{insights/print/[key] → day/[date]}/page/build-manifest.json +4 -4
- package/app/apps/web/.next/server/app/day/[date]/page/server-reference-manifest.json +4 -0
- package/app/apps/web/.next/server/app/day/[date]/page.js +18 -0
- package/app/apps/web/.next/server/app/day/[date]/page.js.map +5 -0
- package/app/apps/web/.next/server/app/day/[date]/page.js.nft.json +1 -0
- package/app/apps/web/.next/server/app/day/[date]/page_client-reference-manifest.js +3 -0
- package/app/apps/web/.next/server/app/day/page/app-paths-manifest.json +3 -0
- package/app/apps/web/.next/server/app/day/page/build-manifest.json +17 -0
- package/app/apps/web/.next/server/app/day/page/next-font-manifest.json +6 -0
- package/app/apps/web/.next/server/app/day/page/react-loadable-manifest.json +1 -0
- package/app/apps/web/.next/server/app/day/page/server-reference-manifest.json +4 -0
- package/app/apps/web/.next/server/app/{insights/print/[key] → day}/page.js +11 -10
- package/app/apps/web/.next/server/app/day/page.js.map +5 -0
- package/app/apps/web/.next/server/app/day/page.js.nft.json +1 -0
- package/app/apps/web/.next/server/app/day/page_client-reference-manifest.js +3 -0
- package/app/apps/web/.next/server/app/digest/[date]/page/app-paths-manifest.json +3 -0
- package/app/apps/web/.next/server/app/digest/[date]/page/build-manifest.json +17 -0
- package/app/apps/web/.next/server/app/digest/[date]/page/next-font-manifest.json +6 -0
- package/app/apps/web/.next/server/app/digest/[date]/page/react-loadable-manifest.json +1 -0
- package/app/apps/web/.next/server/app/digest/[date]/page/server-reference-manifest.json +4 -0
- package/app/apps/web/.next/server/app/digest/[date]/page.js +17 -0
- package/app/apps/web/.next/server/app/digest/[date]/page.js.map +5 -0
- package/app/apps/web/.next/server/app/digest/[date]/page.js.nft.json +1 -0
- package/app/apps/web/.next/server/app/digest/[date]/page_client-reference-manifest.js +3 -0
- package/app/apps/web/.next/server/app/digest/page/app-paths-manifest.json +3 -0
- package/app/apps/web/.next/server/app/digest/page/build-manifest.json +17 -0
- package/app/apps/web/.next/server/app/digest/page/next-font-manifest.json +6 -0
- package/app/apps/web/.next/server/app/digest/page/react-loadable-manifest.json +1 -0
- package/app/apps/web/.next/server/app/digest/page/server-reference-manifest.json +4 -0
- package/app/apps/web/.next/server/app/digest/page.js +17 -0
- package/app/apps/web/.next/server/app/digest/page.js.map +5 -0
- package/app/apps/web/.next/server/app/digest/page.js.nft.json +1 -0
- package/app/apps/web/.next/server/app/digest/page_client-reference-manifest.js +3 -0
- package/app/apps/web/.next/server/app/insights/[key]/page/build-manifest.json +4 -4
- package/app/apps/web/.next/server/app/insights/[key]/page.js +7 -5
- package/app/apps/web/.next/server/app/insights/[key]/page.js.nft.json +1 -1
- package/app/apps/web/.next/server/app/insights/[key]/page_client-reference-manifest.js +1 -1
- package/app/apps/web/.next/server/app/insights/page/build-manifest.json +4 -4
- package/app/apps/web/.next/server/app/insights/page.js +7 -5
- package/app/apps/web/.next/server/app/insights/page.js.nft.json +1 -1
- package/app/apps/web/.next/server/app/insights/page_client-reference-manifest.js +1 -1
- package/app/apps/web/.next/server/app/page/build-manifest.json +4 -4
- package/app/apps/web/.next/server/app/page.js +7 -6
- package/app/apps/web/.next/server/app/page.js.nft.json +1 -1
- package/app/apps/web/.next/server/app/page_client-reference-manifest.js +1 -1
- package/app/apps/web/.next/server/app/parallelism/page/build-manifest.json +4 -4
- package/app/apps/web/.next/server/app/parallelism/page.js +6 -5
- package/app/apps/web/.next/server/app/parallelism/page.js.nft.json +1 -1
- package/app/apps/web/.next/server/app/parallelism/page_client-reference-manifest.js +1 -1
- package/app/apps/web/.next/server/app/projects/[slug]/page/build-manifest.json +4 -4
- package/app/apps/web/.next/server/app/projects/[slug]/page.js +6 -5
- package/app/apps/web/.next/server/app/projects/[slug]/page.js.nft.json +1 -1
- package/app/apps/web/.next/server/app/projects/[slug]/page_client-reference-manifest.js +1 -1
- package/app/apps/web/.next/server/app/projects/page/build-manifest.json +4 -4
- package/app/apps/web/.next/server/app/projects/page.js +5 -4
- package/app/apps/web/.next/server/app/projects/page.js.nft.json +1 -1
- package/app/apps/web/.next/server/app/projects/page_client-reference-manifest.js +1 -1
- package/app/apps/web/.next/server/app/runs/page/app-paths-manifest.json +3 -0
- package/app/apps/web/.next/server/app/runs/page/build-manifest.json +17 -0
- package/app/apps/web/.next/server/app/runs/page/next-font-manifest.json +6 -0
- package/app/apps/web/.next/server/app/runs/page/react-loadable-manifest.json +1 -0
- package/app/apps/web/.next/server/app/runs/page/server-reference-manifest.json +4 -0
- package/app/apps/web/.next/server/app/runs/page.js +17 -0
- package/app/apps/web/.next/server/app/runs/page.js.map +5 -0
- package/app/apps/web/.next/server/app/runs/page.js.nft.json +1 -0
- package/app/apps/web/.next/server/app/runs/page_client-reference-manifest.js +3 -0
- package/app/apps/web/.next/server/app/sessions/[id]/page/build-manifest.json +4 -4
- package/app/apps/web/.next/server/app/sessions/[id]/page.js +5 -4
- package/app/apps/web/.next/server/app/sessions/[id]/page.js.nft.json +1 -1
- package/app/apps/web/.next/server/app/sessions/[id]/page_client-reference-manifest.js +1 -1
- package/app/apps/web/.next/server/app/sessions/page/build-manifest.json +4 -4
- package/app/apps/web/.next/server/app/sessions/page.js +5 -4
- package/app/apps/web/.next/server/app/sessions/page.js.nft.json +1 -1
- package/app/apps/web/.next/server/app/sessions/page_client-reference-manifest.js +1 -1
- package/app/apps/web/.next/server/app/settings/page/app-paths-manifest.json +3 -0
- package/app/apps/web/.next/server/app/settings/page/build-manifest.json +17 -0
- package/app/apps/web/.next/server/app/settings/page/next-font-manifest.json +6 -0
- package/app/apps/web/.next/server/app/settings/page/react-loadable-manifest.json +1 -0
- package/app/apps/web/.next/server/app/settings/page/server-reference-manifest.json +4 -0
- package/app/apps/web/.next/server/app/settings/page.js +18 -0
- package/app/apps/web/.next/server/app/settings/page.js.map +5 -0
- package/app/apps/web/.next/server/app/settings/page.js.nft.json +1 -0
- package/app/apps/web/.next/server/app/settings/page_client-reference-manifest.js +3 -0
- package/app/apps/web/.next/server/app/usage/page/build-manifest.json +4 -4
- package/app/apps/web/.next/server/app/usage/page.js +6 -5
- package/app/apps/web/.next/server/app/usage/page.js.nft.json +1 -1
- package/app/apps/web/.next/server/app/usage/page_client-reference-manifest.js +1 -1
- package/app/apps/web/.next/server/app-paths-manifest.json +16 -7
- package/app/apps/web/.next/server/chunks/02dz_web__next-internal_server_app_api_digest_week_[startDate]_route_actions_0klqqsh.js +3 -0
- package/app/apps/web/.next/server/chunks/09og__next-internal_server_app_api_digest_month_[yearMonth]_route_actions_0i4ielu.js +3 -0
- package/app/apps/web/.next/server/chunks/[externals]__0o43ejh._.js +3 -0
- package/app/apps/web/.next/server/chunks/[root-of-the-server]__0-vgrh1._.js +3 -0
- package/app/apps/web/.next/server/chunks/[root-of-the-server]__00n3f9y._.js +3 -0
- package/app/apps/web/.next/server/chunks/[root-of-the-server]__02zukjw._.js +3 -0
- package/app/apps/web/.next/server/chunks/[root-of-the-server]__067~im1._.js +6 -0
- package/app/apps/web/.next/server/chunks/[root-of-the-server]__06b4cj-._.js +3 -0
- package/app/apps/web/.next/server/chunks/[root-of-the-server]__0_8zh-i._.js +9 -0
- package/app/apps/web/.next/server/chunks/[root-of-the-server]__0e8n_x4._.js +3 -0
- package/app/apps/web/.next/server/chunks/[root-of-the-server]__0ej_p3s._.js +9 -0
- package/app/apps/web/.next/server/chunks/[root-of-the-server]__0jprdks._.js +9 -0
- package/app/apps/web/.next/server/chunks/apps_web__next-internal_server_app_api_digest_day_[date]_route_actions_09sxie5.js +3 -0
- package/app/apps/web/.next/server/chunks/apps_web__next-internal_server_app_api_digest_month-index_route_actions_0wldpbu.js +3 -0
- package/app/apps/web/.next/server/chunks/apps_web__next-internal_server_app_api_digest_week-index_route_actions_12c2wj2.js +3 -0
- package/app/apps/web/.next/server/chunks/apps_web__next-internal_server_app_api_jobs_route_actions_08kx~8-.js +3 -0
- package/app/apps/web/.next/server/chunks/apps_web__next-internal_server_app_api_runs_[runId]_route_actions_0dfcghc.js +3 -0
- package/app/apps/web/.next/server/chunks/apps_web__next-internal_server_app_api_runs_[runId]_stream_route_actions_0.8e8-k.js +3 -0
- package/app/apps/web/.next/server/chunks/apps_web__next-internal_server_app_api_runs_route_actions_0xyx82f.js +3 -0
- package/app/apps/web/.next/server/chunks/apps_web__next-internal_server_app_api_settings_route_actions_0.xv7sx.js +3 -0
- package/app/apps/web/.next/server/chunks/node_modules_next_036my~r._.js +49 -0
- package/app/apps/web/.next/server/chunks/packages_0e7q9u_._.js +3 -0
- package/app/apps/web/.next/server/chunks/packages_0n6p2ot._.js +3 -0
- package/app/apps/web/.next/server/chunks/packages_entries_dist_node_0bckr7-.js +379 -0
- package/app/apps/web/.next/server/chunks/packages_parser_dist_fs_0bc7ptm.js +1 -1
- package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0-1_njm._.js +3 -0
- package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0-94ji~._.js +3 -0
- package/app/apps/web/.next/server/chunks/ssr/{[root-of-the-server]__13xpdx0._.js → [root-of-the-server]__03uoeiw._.js} +2 -2
- package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0_6.inc._.js +1 -1
- package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0d~2~le._.js +8 -0
- package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0gio_ck._.js +1 -1
- package/app/apps/web/.next/server/chunks/ssr/{[root-of-the-server]__08.d5ia._.js → [root-of-the-server]__0jdyefm._.js} +10 -10
- package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0ln9jsw._.js +3 -0
- package/app/apps/web/.next/server/chunks/ssr/{[root-of-the-server]__0z45d0g._.js → [root-of-the-server]__0lz4a~g._.js} +2 -48
- package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0o1_g.~._.js +3 -0
- package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0r4tks8._.js +3 -0
- package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0rvzdnx._.js +3 -0
- package/app/apps/web/.next/server/chunks/ssr/{[root-of-the-server]__0euu8sa._.js → [root-of-the-server]__0u39afl._.js} +2 -2
- package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0u5d7de._.js +12 -0
- package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0w52fbc._.js +3 -3
- package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0wwa6gh._.js +3 -0
- package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0xy1qim._.js +3 -0
- package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0~_8vff._.js +3 -0
- package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__10srpu0._.js +3 -0
- package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__11v.eqw._.js +1 -1
- package/app/apps/web/.next/server/chunks/ssr/_02s1n-x._.js +8 -0
- package/app/apps/web/.next/server/chunks/ssr/_0fjbf--._.js +3 -0
- package/app/apps/web/.next/server/chunks/ssr/_0jw2sm7._.js +3 -0
- package/app/apps/web/.next/server/chunks/ssr/_0wj750k._.js +3 -0
- package/app/apps/web/.next/server/chunks/ssr/_0woap-3._.js +1 -1
- package/app/apps/web/.next/server/chunks/ssr/{_0xies90._.js → _0xu2pvc._.js} +2 -2
- package/app/apps/web/.next/server/chunks/ssr/apps_web__next-internal_server_app_day_[date]_page_actions_0u2kxb..js +3 -0
- package/app/apps/web/.next/server/chunks/ssr/apps_web__next-internal_server_app_day_page_actions_1042maj.js +3 -0
- package/app/apps/web/.next/server/chunks/ssr/apps_web__next-internal_server_app_digest_[date]_page_actions_0olu967.js +3 -0
- package/app/apps/web/.next/server/chunks/ssr/apps_web__next-internal_server_app_digest_page_actions_0bl.eil.js +3 -0
- package/app/apps/web/.next/server/chunks/ssr/apps_web__next-internal_server_app_runs_page_actions_0485qy7.js +3 -0
- package/app/apps/web/.next/server/chunks/ssr/apps_web__next-internal_server_app_settings_page_actions_0f6epye.js +3 -0
- package/app/apps/web/.next/server/chunks/ssr/apps_web_app_day_[date]_day-view_tsx_0wjoe1u._.js +3 -0
- package/app/apps/web/.next/server/chunks/ssr/apps_web_app_settings_ai-features-form_tsx_01p699p._.js +3 -0
- package/app/apps/web/.next/server/chunks/ssr/apps_web_components_0b-4-4j._.js +1 -1
- package/app/apps/web/.next/server/chunks/ssr/apps_web_components_0ly1xes._.js +6 -0
- package/app/apps/web/.next/server/chunks/ssr/apps_web_components_0txtsv5._.js +16 -0
- package/app/apps/web/.next/server/chunks/ssr/apps_web_components_0xs658s._.js +10 -0
- package/app/apps/web/.next/server/chunks/ssr/apps_web_components_runs-live-board_tsx_0r6dkdq._.js +3 -0
- package/app/apps/web/.next/server/chunks/ssr/apps_web_components_usage-charts-dashboard_tsx_0bgr_uv._.js +1 -1
- package/app/apps/web/.next/server/chunks/ssr/apps_web_lib_usage-data_ts_0xtv99n._.js +3 -0
- package/app/apps/web/.next/server/chunks/ssr/node_modules_0i2xw~e._.js +3 -0
- package/app/apps/web/.next/server/chunks/ssr/node_modules_next_dist_0e1izl_._.js +1 -1
- package/app/apps/web/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0d3d4wn.js +4 -0
- package/app/apps/web/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0edz1ko.js +4 -0
- package/app/apps/web/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0eq.n-n.js +4 -0
- package/app/apps/web/.next/server/chunks/ssr/{node_modules_next_dist_esm_build_templates_app-page_0vz7_px.js → node_modules_next_dist_esm_build_templates_app-page_0hcvt-s.js} +3 -3
- package/app/apps/web/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0nd5zu0.js +4 -0
- package/app/apps/web/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_11j1qy0.js +4 -0
- package/app/apps/web/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_12n1lw_.js +1 -1
- package/app/apps/web/.next/server/chunks/ssr/packages_entries_dist_node_0_271yr.js +3 -0
- package/app/apps/web/.next/server/chunks/ssr/packages_parser_dist_0-jvt~a._.js +1 -1
- package/app/apps/web/.next/server/functions-config-manifest.json +11 -6
- package/app/apps/web/.next/server/middleware-build-manifest.js +7 -7
- package/app/apps/web/.next/server/pages/500.html +1 -1
- package/app/apps/web/.next/server/server-reference-manifest.js +1 -1
- package/app/apps/web/.next/server/server-reference-manifest.json +1 -1
- package/app/apps/web/.next/static/chunks/0-yc2_pjxwwuq.js +1 -0
- package/app/apps/web/.next/static/chunks/0257pdz1-imal.js +2 -0
- package/app/apps/web/.next/static/chunks/05m.oz3kmf1p7.js +1 -0
- package/app/apps/web/.next/static/chunks/{0pqt~8bl3ukh4.js → 073081qv4uyn8.js} +1 -1
- package/app/apps/web/.next/static/chunks/{0018dy-m-kusj.js → 07lbm-sdh9c2j.js} +1 -1
- package/app/apps/web/.next/static/chunks/0858bgw2i4vob.js +1 -0
- package/app/apps/web/.next/static/chunks/0_7303jr0sf0w.js +10 -0
- package/app/apps/web/.next/static/chunks/0byz8fqw.exef.js +1 -0
- package/app/apps/web/.next/static/chunks/0coa1800xqgfj.js +1 -0
- package/app/apps/web/.next/static/chunks/0fs3gxea5h0s3.css +1 -0
- package/app/apps/web/.next/static/chunks/0k1psab.bybh9.js +14 -0
- package/app/apps/web/.next/static/chunks/0k9pksi_i.odf.js +1 -0
- package/app/apps/web/.next/static/chunks/0m62vx92~0_0d.js +1 -0
- package/app/apps/web/.next/static/chunks/0mc8aa8z.0-5l.js +8 -0
- package/app/apps/web/.next/static/chunks/0mykrrv810ra-.js +31 -0
- package/app/apps/web/.next/static/chunks/0o9ayt8sknubd.js +1 -0
- package/app/apps/web/.next/static/chunks/0osdgl2.9cl1q.js +6 -0
- package/app/apps/web/.next/static/chunks/0xfu09fn_358k.js +4 -0
- package/app/apps/web/.next/static/chunks/171za22fv684..js +6 -0
- package/app/apps/web/.next/static/chunks/17u2ww8ya5dv1.js +6 -0
- package/app/apps/web/.next/static/chunks/{turbopack-169w-1._23ra_.js → turbopack-0_p36yduv.waj.js} +1 -1
- package/app/apps/web/app/api/digest/day/[date]/route.ts +152 -0
- package/app/apps/web/app/api/digest/month/[yearMonth]/route.ts +147 -0
- package/app/apps/web/app/api/digest/month-index/route.ts +103 -0
- package/app/apps/web/app/api/digest/week/[startDate]/route.ts +149 -0
- package/app/apps/web/app/api/{insights/weeks-index → digest/week-index}/route.ts +45 -33
- package/app/apps/web/app/api/jobs/route.ts +8 -0
- package/app/apps/web/app/api/runs/[runId]/route.ts +64 -0
- package/app/apps/web/app/api/runs/[runId]/stream/route.ts +154 -0
- package/app/apps/web/app/api/runs/route.ts +266 -0
- package/app/apps/web/app/api/settings/route.ts +35 -0
- package/app/apps/web/app/day/[date]/day-view.tsx +193 -0
- package/app/apps/web/app/day/[date]/page.tsx +175 -0
- package/app/apps/web/app/day/page.tsx +8 -0
- package/app/apps/web/app/digest/[date]/page.tsx +15 -0
- package/app/apps/web/app/digest/page.tsx +7 -0
- package/app/apps/web/app/insights/[key]/page.tsx +106 -48
- package/app/apps/web/app/insights/page.tsx +133 -3
- package/app/apps/web/app/layout.tsx +23 -3
- package/app/apps/web/app/page.tsx +33 -4
- package/app/apps/web/app/parallelism/gantt-chart.tsx +67 -1
- package/app/apps/web/app/parallelism/page.tsx +8 -278
- package/app/apps/web/app/projects/[slug]/page.tsx +153 -0
- package/app/apps/web/app/projects/page.tsx +49 -4
- package/app/apps/web/app/projects/projects-view.tsx +79 -68
- package/app/apps/web/app/runs/page.tsx +21 -0
- package/app/apps/web/app/sessions/[id]/page.tsx +12 -1
- package/app/apps/web/app/sessions/[id]/session-view.tsx +119 -0
- package/app/apps/web/app/sessions/page.tsx +19 -3
- package/app/apps/web/app/sessions/sessions-grid.tsx +172 -131
- package/app/apps/web/app/settings/ai-features-form.tsx +45 -0
- package/app/apps/web/app/settings/page.tsx +20 -0
- package/app/apps/web/app/usage/page.tsx +45 -3
- package/app/apps/web/components/auto-generate-yesterday.tsx +96 -0
- package/app/apps/web/components/backfill-drawer.tsx +309 -0
- package/app/apps/web/components/dashboard-view.tsx +4 -2
- package/app/apps/web/components/date-nav.tsx +385 -0
- package/app/apps/web/components/day-digest-view.tsx +180 -0
- package/app/apps/web/components/day-digest.tsx +489 -0
- package/app/apps/web/components/flag-chip.tsx +54 -0
- package/app/apps/web/components/goal-bar.tsx +63 -0
- package/app/apps/web/components/heatmap.tsx +78 -1
- package/app/apps/web/components/helpfulness-sparkline.tsx +82 -0
- package/app/apps/web/components/insights-history.tsx +211 -0
- package/app/apps/web/components/insights-top-bar.tsx +216 -0
- package/app/apps/web/components/job-queue-widget.tsx +274 -0
- package/app/apps/web/components/live-sessions-widget.tsx +38 -3
- package/app/apps/web/components/month-digest-view.tsx +138 -0
- package/app/apps/web/components/month-digest.tsx +216 -0
- package/app/apps/web/components/outcome-mix-row.tsx +37 -0
- package/app/apps/web/components/outcome-pill.tsx +101 -0
- package/app/apps/web/components/previous-cycles-trend.tsx +155 -0
- package/app/apps/web/components/recent-days-panel.tsx +83 -0
- package/app/apps/web/components/runs-live-board.tsx +513 -0
- package/app/apps/web/components/sidebar.tsx +38 -4
- package/app/apps/web/components/usage-chart-range.tsx +58 -6
- package/app/apps/web/components/usage-chart.tsx +94 -7
- package/app/apps/web/components/usage-charts-dashboard.tsx +20 -1
- package/app/apps/web/components/week-digest-view.tsx +226 -0
- package/app/apps/web/components/week-digest.tsx +2128 -0
- package/app/apps/web/components/yesterday-hero.tsx +110 -0
- package/app/apps/web/lib/auto-week-fire.ts +37 -0
- package/app/apps/web/lib/calibration-data.ts +171 -0
- package/app/apps/web/lib/entries-index.ts +174 -0
- package/app/apps/web/lib/entries.ts +72 -0
- package/app/apps/web/lib/inflight-coalesce.test.ts +43 -0
- package/app/apps/web/lib/inflight-coalesce.ts +19 -0
- package/app/apps/web/lib/jobs.ts +170 -0
- package/app/apps/web/lib/usage-data.ts +37 -0
- package/app/apps/web/lib/validate-settings.test.ts +25 -0
- package/app/apps/web/lib/validate-settings.ts +9 -0
- package/app/apps/web/next.config.ts +1 -1
- package/app/apps/web/package.json +4 -2
- package/app/apps/web/server.js +1 -1
- package/app/apps/web/tsconfig.tsbuildinfo +1 -1
- package/app/apps/web/vitest.config.ts +9 -0
- package/dist/daemon-worker.js +1937 -979
- package/dist/index.js +11210 -1877
- package/package.json +4 -1
- package/app/apps/web/.next/server/app/api/insights/months-index/route/app-paths-manifest.json +0 -3
- package/app/apps/web/.next/server/app/api/insights/months-index/route.js +0 -7
- package/app/apps/web/.next/server/app/api/insights/months-index/route_client-reference-manifest.js +0 -3
- package/app/apps/web/.next/server/app/api/insights/pdf/[key]/route/app-paths-manifest.json +0 -3
- package/app/apps/web/.next/server/app/api/insights/pdf/[key]/route.js +0 -6
- package/app/apps/web/.next/server/app/api/insights/route/app-paths-manifest.json +0 -3
- package/app/apps/web/.next/server/app/api/insights/route.js +0 -8
- package/app/apps/web/.next/server/app/api/insights/saved/[key]/route/app-paths-manifest.json +0 -3
- package/app/apps/web/.next/server/app/api/insights/saved/[key]/route.js +0 -6
- package/app/apps/web/.next/server/app/api/insights/saved/[key]/route_client-reference-manifest.js +0 -3
- package/app/apps/web/.next/server/app/api/insights/saved/route/app-paths-manifest.json +0 -3
- package/app/apps/web/.next/server/app/api/insights/saved/route.js +0 -6
- package/app/apps/web/.next/server/app/api/insights/saved/route_client-reference-manifest.js +0 -3
- package/app/apps/web/.next/server/app/api/insights/weeks-index/route/app-paths-manifest.json +0 -3
- package/app/apps/web/.next/server/app/api/insights/weeks-index/route.js +0 -7
- package/app/apps/web/.next/server/app/api/insights/weeks-index/route_client-reference-manifest.js +0 -3
- package/app/apps/web/.next/server/app/insights/print/[key]/page/app-paths-manifest.json +0 -3
- package/app/apps/web/.next/server/app/insights/print/[key]/page.js.nft.json +0 -1
- package/app/apps/web/.next/server/app/insights/print/[key]/page_client-reference-manifest.js +0 -3
- package/app/apps/web/.next/server/chunks/02dz_web__next-internal_server_app_api_insights_months-index_route_actions_0~h~zci.js +0 -3
- package/app/apps/web/.next/server/chunks/02dz_web__next-internal_server_app_api_insights_saved_[key]_route_actions_0a5j9yw.js +0 -3
- package/app/apps/web/.next/server/chunks/02dz_web__next-internal_server_app_api_insights_weeks-index_route_actions_0hh-1c7.js +0 -3
- package/app/apps/web/.next/server/chunks/[root-of-the-server]__0.hmj0z._.js +0 -3
- package/app/apps/web/.next/server/chunks/[root-of-the-server]__01h_g-p._.js +0 -3
- package/app/apps/web/.next/server/chunks/[root-of-the-server]__0nh-z10._.js +0 -3
- package/app/apps/web/.next/server/chunks/[root-of-the-server]__0ri7q~r._.js +0 -3
- package/app/apps/web/.next/server/chunks/[root-of-the-server]__0rr1~~x._.js +0 -3
- package/app/apps/web/.next/server/chunks/[root-of-the-server]__0s0gv.0._.js +0 -3
- package/app/apps/web/.next/server/chunks/apps_web__next-internal_server_app_api_insights_pdf_[key]_route_actions_0lu-lnx.js +0 -3
- package/app/apps/web/.next/server/chunks/apps_web__next-internal_server_app_api_insights_route_actions_0h8l5lz.js +0 -3
- package/app/apps/web/.next/server/chunks/apps_web__next-internal_server_app_api_insights_saved_route_actions_13rlblw.js +0 -3
- package/app/apps/web/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_00t2xj6.js +0 -68
- package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0.tsxpj._.js +0 -3
- package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__00z7zlm._.js +0 -3
- package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__08pen0k._.js +0 -3
- package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0b323~k._.js +0 -8
- package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0gx-4qa._.js +0 -3
- package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0wv27wt._.js +0 -3
- package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__13itnvx._.js +0 -3
- package/app/apps/web/.next/server/chunks/ssr/_09n75_5._.js +0 -8
- package/app/apps/web/.next/server/chunks/ssr/_0r~__0v._.js +0 -12
- package/app/apps/web/.next/server/chunks/ssr/apps_web__next-internal_server_app_insights_print_[key]_page_actions_0a853fw.js +0 -3
- package/app/apps/web/.next/server/chunks/ssr/apps_web_app_parallelism_08vub.0._.js +0 -3
- package/app/apps/web/.next/server/chunks/ssr/apps_web_components_06j3c.0._.js +0 -8
- package/app/apps/web/.next/server/chunks/ssr/apps_web_components_0bbo_pd._.js +0 -8
- package/app/apps/web/.next/server/chunks/ssr/apps_web_components_insight-report_tsx_13q2a-c._.js +0 -12
- package/app/apps/web/.next/server/chunks/ssr/apps_web_components_insights-view_tsx_11730ta._.js +0 -6
- package/app/apps/web/.next/server/chunks/ssr/node_modules_lucide-react_dist_esm_icons_0nqz8dw._.js +0 -3
- package/app/apps/web/.next/server/chunks/ssr/node_modules_next_dist_0t-hj0x._.js +0 -3
- package/app/apps/web/.next/server/chunks/ssr/packages_parser_dist_analytics_0k4dgst.js +0 -3
- package/app/apps/web/.next/static/chunks/028_pmk40b69_.js +0 -6
- package/app/apps/web/.next/static/chunks/03.mv4y4.w-vb.js +0 -6
- package/app/apps/web/.next/static/chunks/03_7xtpi9sv4g.js +0 -4
- package/app/apps/web/.next/static/chunks/08c1pcrocqq5s.js +0 -6
- package/app/apps/web/.next/static/chunks/0e-wrhqh4h3r5.js +0 -2
- package/app/apps/web/.next/static/chunks/0fc6dk2qtokwh.js +0 -1
- package/app/apps/web/.next/static/chunks/0i7er7_bfab36.js +0 -10
- package/app/apps/web/.next/static/chunks/0ipytyi01h0ta.js +0 -1
- package/app/apps/web/.next/static/chunks/0lsznd4_avzhv.js +0 -6
- package/app/apps/web/.next/static/chunks/0lty3v_i9mde7.js +0 -1
- package/app/apps/web/.next/static/chunks/0u-n8fz-ms.ee.js +0 -6
- package/app/apps/web/.next/static/chunks/0vekjjj4pidlz.css +0 -1
- package/app/apps/web/.next/static/chunks/137uw2-qbro07.js +0 -31
- package/app/apps/web/.next/static/chunks/15w5_bct86ut6.js +0 -10
- package/app/apps/web/app/api/insights/months-index/route.ts +0 -80
- package/app/apps/web/app/api/insights/pdf/[key]/route.ts +0 -45
- package/app/apps/web/app/api/insights/route.ts +0 -508
- package/app/apps/web/app/api/insights/saved/[key]/route.ts +0 -11
- package/app/apps/web/app/api/insights/saved/route.ts +0 -9
- package/app/apps/web/app/insights/print/[key]/page.tsx +0 -73
- package/app/apps/web/components/insight-report.tsx +0 -1031
- package/app/apps/web/components/insights-view.tsx +0 -647
- package/app/apps/web/lib/ai/insights-prompt.ts +0 -71
- package/app/apps/web/lib/ai/saved-reports.ts +0 -83
- /package/app/apps/web/.next/server/app/api/{insights/months-index → digest/day/[date]}/route/build-manifest.json +0 -0
- /package/app/apps/web/.next/server/app/api/{insights/months-index → digest/day/[date]}/route/server-reference-manifest.json +0 -0
- /package/app/apps/web/.next/server/app/api/{insights/months-index → digest/day/[date]}/route.js.map +0 -0
- /package/app/apps/web/.next/server/app/api/{insights → digest/month/[yearMonth]}/route/build-manifest.json +0 -0
- /package/app/apps/web/.next/server/app/api/{insights → digest/month/[yearMonth]}/route/server-reference-manifest.json +0 -0
- /package/app/apps/web/.next/server/app/api/{insights → digest/month/[yearMonth]}/route.js.map +0 -0
- /package/app/apps/web/.next/server/app/api/{insights/pdf/[key] → digest/month-index}/route/build-manifest.json +0 -0
- /package/app/apps/web/.next/server/app/api/{insights/pdf/[key] → digest/month-index}/route/server-reference-manifest.json +0 -0
- /package/app/apps/web/.next/server/app/api/{insights/pdf/[key] → digest/month-index}/route.js.map +0 -0
- /package/app/apps/web/.next/server/app/api/{insights/saved → digest/week/[startDate]}/route/build-manifest.json +0 -0
- /package/app/apps/web/.next/server/app/api/{insights/saved → digest/week/[startDate]}/route/server-reference-manifest.json +0 -0
- /package/app/apps/web/.next/server/app/api/{insights/saved → digest/week/[startDate]}/route.js.map +0 -0
- /package/app/apps/web/.next/server/app/api/{insights/saved/[key] → digest/week-index}/route/build-manifest.json +0 -0
- /package/app/apps/web/.next/server/app/api/{insights/saved/[key] → digest/week-index}/route/server-reference-manifest.json +0 -0
- /package/app/apps/web/.next/server/app/api/{insights/saved/[key] → digest/week-index}/route.js.map +0 -0
- /package/app/apps/web/.next/server/app/api/{insights/weeks-index → jobs}/route/build-manifest.json +0 -0
- /package/app/apps/web/.next/server/app/api/{insights/weeks-index → jobs}/route/server-reference-manifest.json +0 -0
- /package/app/apps/web/.next/server/app/api/{insights/weeks-index → jobs}/route.js.map +0 -0
- /package/app/apps/web/.next/server/app/{insights/print/[key]/page → api/runs/[runId]/route}/server-reference-manifest.json +0 -0
- /package/app/apps/web/.next/server/app/{insights/print/[key]/page.js.map → api/runs/[runId]/route.js.map} +0 -0
- /package/app/apps/web/.next/server/app/{insights/print/[key] → day/[date]}/page/next-font-manifest.json +0 -0
- /package/app/apps/web/.next/server/app/{insights/print/[key] → day/[date]}/page/react-loadable-manifest.json +0 -0
- /package/app/apps/web/.next/static/{95-RytHk7ZQtfpZj5BLST → 8tTWPvUhtatZEoocIhamh}/_buildManifest.js +0 -0
- /package/app/apps/web/.next/static/{95-RytHk7ZQtfpZj5BLST → 8tTWPvUhtatZEoocIhamh}/_clientMiddlewareManifest.js +0 -0
- /package/app/apps/web/.next/static/{95-RytHk7ZQtfpZj5BLST → 8tTWPvUhtatZEoocIhamh}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,513 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { useEffect, useMemo, useRef, useState } from "react";
|
|
4
|
+
|
|
5
|
+
type ActiveRun = { pid: number; kind: string; model: string; elapsed_s: number; cpu_time: string };
|
|
6
|
+
|
|
7
|
+
type TraceSummary = {
|
|
8
|
+
run_id: string;
|
|
9
|
+
kind: string;
|
|
10
|
+
model: string;
|
|
11
|
+
pid: number | null;
|
|
12
|
+
started_at: string;
|
|
13
|
+
ended_at: string | null;
|
|
14
|
+
elapsed_ms: number | null;
|
|
15
|
+
exit_code: number | null;
|
|
16
|
+
status: "running" | "ok" | "error" | "unknown";
|
|
17
|
+
content_chars: number | null;
|
|
18
|
+
output_tokens: number | null;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
type RunsResponse = {
|
|
22
|
+
generated_at: string;
|
|
23
|
+
active: ActiveRun[];
|
|
24
|
+
totals: { ops: number; input_tokens: number; output_tokens: number; cost_usd: number };
|
|
25
|
+
by_kind: Record<string, { ops: number; input_tokens: number; output_tokens: number; cost_usd: number }>;
|
|
26
|
+
traces: TraceSummary[];
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
type StreamEvent =
|
|
30
|
+
| { sseType: "connected"; data: { run_id: string; path: string } }
|
|
31
|
+
| { sseType: "meta"; data: { _meta: { type: string; [k: string]: unknown } } }
|
|
32
|
+
| { sseType: "event"; data: Record<string, unknown> }
|
|
33
|
+
| { sseType: "done"; data: { reason: string } }
|
|
34
|
+
| { sseType: "raw"; data: { line: string } }
|
|
35
|
+
| { sseType: "stream_error"; data: { message: string } };
|
|
36
|
+
|
|
37
|
+
function fmtElapsed(ms: number | null): string {
|
|
38
|
+
if (ms == null) return "—";
|
|
39
|
+
const s = Math.round(ms / 100) / 10;
|
|
40
|
+
if (s < 60) return `${s.toFixed(1)}s`;
|
|
41
|
+
const m = Math.floor(s / 60);
|
|
42
|
+
const r = (s - m * 60).toFixed(0);
|
|
43
|
+
return `${m}m${r.padStart(2, "0")}s`;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function fmtAge(iso: string): string {
|
|
47
|
+
if (!iso) return "—";
|
|
48
|
+
const ms = Date.now() - new Date(iso).getTime();
|
|
49
|
+
if (ms < 0) return "now";
|
|
50
|
+
const s = Math.floor(ms / 1000);
|
|
51
|
+
if (s < 60) return `${s}s ago`;
|
|
52
|
+
const m = Math.floor(s / 60);
|
|
53
|
+
if (m < 60) return `${m}m ago`;
|
|
54
|
+
const h = Math.floor(m / 60);
|
|
55
|
+
if (h < 24) return `${h}h ago`;
|
|
56
|
+
return `${Math.floor(h / 24)}d ago`;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const STATUS_BADGE: Record<TraceSummary["status"], { bg: string; fg: string; label: string }> = {
|
|
60
|
+
running: { bg: "rgba(59, 130, 246, 0.15)", fg: "#3b82f6", label: "running" },
|
|
61
|
+
ok: { bg: "rgba(34, 197, 94, 0.15)", fg: "#16a34a", label: "ok" },
|
|
62
|
+
error: { bg: "rgba(239, 68, 68, 0.15)", fg: "#dc2626", label: "error" },
|
|
63
|
+
unknown: { bg: "rgba(148, 163, 184, 0.15)", fg: "#64748b", label: "?" },
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
const KIND_COLOR: Record<string, string> = {
|
|
67
|
+
week_digest: "#a855f7",
|
|
68
|
+
month_digest: "#ec4899",
|
|
69
|
+
day_digest: "#06b6d4",
|
|
70
|
+
top_session: "#f59e0b",
|
|
71
|
+
entry_enrich: "#10b981",
|
|
72
|
+
unknown: "#94a3b8",
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
export function RunsLiveBoard() {
|
|
76
|
+
const [data, setData] = useState<RunsResponse | null>(null);
|
|
77
|
+
const [selected, setSelected] = useState<string | null>(null);
|
|
78
|
+
const [error, setError] = useState<string | null>(null);
|
|
79
|
+
|
|
80
|
+
// Poll the snapshot every 3s while the page is open.
|
|
81
|
+
useEffect(() => {
|
|
82
|
+
let cancelled = false;
|
|
83
|
+
async function tick() {
|
|
84
|
+
try {
|
|
85
|
+
const r = await fetch("/api/runs?since=24h&trace_limit=40", { cache: "no-store" });
|
|
86
|
+
if (!r.ok) throw new Error(`/api/runs ${r.status}`);
|
|
87
|
+
const j = (await r.json()) as RunsResponse;
|
|
88
|
+
if (!cancelled) {
|
|
89
|
+
setData(j);
|
|
90
|
+
setError(null);
|
|
91
|
+
// Auto-select latest if nothing selected yet.
|
|
92
|
+
if (!cancelled && !selected && j.traces.length > 0) {
|
|
93
|
+
setSelected(j.traces[0]!.run_id);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
} catch (e) {
|
|
97
|
+
if (!cancelled) setError((e as Error).message);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
tick();
|
|
101
|
+
const id = setInterval(tick, 3000);
|
|
102
|
+
return () => { cancelled = true; clearInterval(id); };
|
|
103
|
+
}, [selected]);
|
|
104
|
+
|
|
105
|
+
return (
|
|
106
|
+
<div style={{ display: "grid", gridTemplateColumns: "minmax(380px, 1fr) minmax(0, 2.4fr)", gap: 16 }}>
|
|
107
|
+
<div style={{ display: "flex", flexDirection: "column", gap: 12 }}>
|
|
108
|
+
<SnapshotPanel data={data} error={error} />
|
|
109
|
+
<RunsList traces={data?.traces ?? []} active={data?.active ?? []} selected={selected} onSelect={setSelected} />
|
|
110
|
+
</div>
|
|
111
|
+
<div>
|
|
112
|
+
{selected ? <RunDetail runId={selected} /> : <Placeholder text="Select a run to see its prompt + live events." />}
|
|
113
|
+
</div>
|
|
114
|
+
</div>
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function Card({ children, padding = 14 }: { children: React.ReactNode; padding?: number }) {
|
|
119
|
+
return (
|
|
120
|
+
<div
|
|
121
|
+
style={{
|
|
122
|
+
background: "var(--af-card)",
|
|
123
|
+
border: "1px solid var(--af-border)",
|
|
124
|
+
borderRadius: 10,
|
|
125
|
+
padding,
|
|
126
|
+
}}
|
|
127
|
+
>
|
|
128
|
+
{children}
|
|
129
|
+
</div>
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function Placeholder({ text }: { text: string }) {
|
|
134
|
+
return (
|
|
135
|
+
<Card>
|
|
136
|
+
<div style={{ color: "var(--af-text-tertiary)", fontSize: 13, textAlign: "center", padding: "60px 0" }}>{text}</div>
|
|
137
|
+
</Card>
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function SnapshotPanel({ data, error }: { data: RunsResponse | null; error: string | null }) {
|
|
142
|
+
if (error) {
|
|
143
|
+
return <Card><div style={{ color: "#dc2626", fontSize: 12 }}>error: {error}</div></Card>;
|
|
144
|
+
}
|
|
145
|
+
if (!data) return <Card><div style={{ color: "var(--af-text-tertiary)", fontSize: 12 }}>loading…</div></Card>;
|
|
146
|
+
const { active, totals, by_kind } = data;
|
|
147
|
+
return (
|
|
148
|
+
<Card>
|
|
149
|
+
<div style={{ display: "flex", alignItems: "baseline", justifyContent: "space-between", marginBottom: 8 }}>
|
|
150
|
+
<strong style={{ fontSize: 13 }}>{active.length === 0 ? "no active runs" : `${active.length} running`}</strong>
|
|
151
|
+
<span style={{ fontSize: 11, color: "var(--af-text-tertiary)" }}>{totals.ops} completed · last 24h</span>
|
|
152
|
+
</div>
|
|
153
|
+
{active.length > 0 && (
|
|
154
|
+
<ul style={{ listStyle: "none", padding: 0, margin: "0 0 10px 0", display: "flex", flexDirection: "column", gap: 4 }}>
|
|
155
|
+
{active.map(r => (
|
|
156
|
+
<li key={r.pid} style={{ fontSize: 12, fontFamily: "var(--font-mono, ui-monospace)" }}>
|
|
157
|
+
<KindDot kind={r.kind} /> pid {r.pid} · {r.kind} · {r.model} · {r.elapsed_s}s
|
|
158
|
+
</li>
|
|
159
|
+
))}
|
|
160
|
+
</ul>
|
|
161
|
+
)}
|
|
162
|
+
<div style={{ display: "flex", gap: 6, flexWrap: "wrap" }}>
|
|
163
|
+
{Object.entries(by_kind).map(([k, v]) => (
|
|
164
|
+
<span key={k} style={{ fontSize: 11, padding: "2px 8px", background: "var(--af-bg-soft, rgba(0,0,0,0.04))", borderRadius: 6, color: "var(--af-text-secondary)" }}>
|
|
165
|
+
<KindDot kind={k} /> {k}: {v.ops}
|
|
166
|
+
</span>
|
|
167
|
+
))}
|
|
168
|
+
</div>
|
|
169
|
+
</Card>
|
|
170
|
+
);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
function KindDot({ kind }: { kind: string }) {
|
|
174
|
+
return <span style={{ display: "inline-block", width: 8, height: 8, borderRadius: "50%", background: KIND_COLOR[kind] ?? KIND_COLOR.unknown, marginRight: 6, verticalAlign: "middle" }} />;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
function RunsList({
|
|
178
|
+
traces, active, selected, onSelect,
|
|
179
|
+
}: {
|
|
180
|
+
traces: TraceSummary[];
|
|
181
|
+
active: ActiveRun[];
|
|
182
|
+
selected: string | null;
|
|
183
|
+
onSelect: (id: string) => void;
|
|
184
|
+
}) {
|
|
185
|
+
const activePids = useMemo(() => new Set(active.map(a => a.pid)), [active]);
|
|
186
|
+
return (
|
|
187
|
+
<Card padding={0}>
|
|
188
|
+
<div style={{ padding: "10px 14px", borderBottom: "1px solid var(--af-border)" }}>
|
|
189
|
+
<strong style={{ fontSize: 13 }}>Recent runs</strong>
|
|
190
|
+
<span style={{ fontSize: 11, color: "var(--af-text-tertiary)", marginLeft: 8 }}>{traces.length}</span>
|
|
191
|
+
</div>
|
|
192
|
+
<ul style={{ listStyle: "none", padding: 0, margin: 0, maxHeight: 600, overflow: "auto" }}>
|
|
193
|
+
{traces.map(t => {
|
|
194
|
+
const isActive = t.pid != null && activePids.has(t.pid);
|
|
195
|
+
const status: TraceSummary["status"] = isActive ? "running" : t.status;
|
|
196
|
+
const badge = STATUS_BADGE[status];
|
|
197
|
+
const isSelected = selected === t.run_id;
|
|
198
|
+
return (
|
|
199
|
+
<li
|
|
200
|
+
key={t.run_id}
|
|
201
|
+
onClick={() => onSelect(t.run_id)}
|
|
202
|
+
style={{
|
|
203
|
+
padding: "10px 14px",
|
|
204
|
+
cursor: "pointer",
|
|
205
|
+
borderBottom: "1px solid var(--af-border)",
|
|
206
|
+
background: isSelected ? "var(--af-bg-soft, rgba(59,130,246,0.08))" : "transparent",
|
|
207
|
+
}}
|
|
208
|
+
>
|
|
209
|
+
<div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", gap: 8 }}>
|
|
210
|
+
<div style={{ minWidth: 0, flex: 1 }}>
|
|
211
|
+
<div style={{ fontSize: 12, fontWeight: 500, display: "flex", alignItems: "center", gap: 6 }}>
|
|
212
|
+
<KindDot kind={t.kind} />
|
|
213
|
+
<span style={{ overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>
|
|
214
|
+
{t.kind} · {t.model}
|
|
215
|
+
</span>
|
|
216
|
+
</div>
|
|
217
|
+
<div style={{ fontSize: 10, color: "var(--af-text-tertiary)", marginTop: 2, fontFamily: "var(--font-mono, ui-monospace)" }}>
|
|
218
|
+
{t.run_id.slice(0, 19)}…{t.run_id.slice(-8)}
|
|
219
|
+
</div>
|
|
220
|
+
</div>
|
|
221
|
+
<span style={{ fontSize: 10, padding: "2px 7px", borderRadius: 5, background: badge.bg, color: badge.fg, fontWeight: 600 }}>
|
|
222
|
+
{badge.label}
|
|
223
|
+
</span>
|
|
224
|
+
</div>
|
|
225
|
+
<div style={{ display: "flex", justifyContent: "space-between", marginTop: 4, fontSize: 10, color: "var(--af-text-tertiary)" }}>
|
|
226
|
+
<span>{t.started_at ? fmtAge(t.started_at) : "—"}</span>
|
|
227
|
+
<span>
|
|
228
|
+
{t.elapsed_ms != null ? fmtElapsed(t.elapsed_ms) : "…"}
|
|
229
|
+
{t.output_tokens != null ? ` · ${t.output_tokens.toLocaleString()} out` : ""}
|
|
230
|
+
</span>
|
|
231
|
+
</div>
|
|
232
|
+
</li>
|
|
233
|
+
);
|
|
234
|
+
})}
|
|
235
|
+
</ul>
|
|
236
|
+
</Card>
|
|
237
|
+
);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
function RunDetail({ runId }: { runId: string }) {
|
|
241
|
+
const [events, setEvents] = useState<StreamEvent[]>([]);
|
|
242
|
+
const [open, setOpen] = useState(false);
|
|
243
|
+
const [closed, setClosed] = useState<string | null>(null);
|
|
244
|
+
const eventsBoxRef = useRef<HTMLDivElement>(null);
|
|
245
|
+
const [showPrompts, setShowPrompts] = useState(false);
|
|
246
|
+
|
|
247
|
+
// Reset + reconnect when the user picks a different run.
|
|
248
|
+
useEffect(() => {
|
|
249
|
+
setEvents([]);
|
|
250
|
+
setOpen(false);
|
|
251
|
+
setClosed(null);
|
|
252
|
+
setShowPrompts(false);
|
|
253
|
+
const es = new EventSource(`/api/runs/${runId}/stream`);
|
|
254
|
+
// EventSource has built-in `open` and `error` DOM events that fire with no
|
|
255
|
+
// `data`. Server-side we deliberately use `connected` / `stream_error` for
|
|
256
|
+
// our payloads to avoid collision; this listener handles the DOM open.
|
|
257
|
+
es.onopen = () => setOpen(true);
|
|
258
|
+
const safeParse = (raw: unknown): unknown => {
|
|
259
|
+
if (typeof raw !== "string" || raw === "") return null;
|
|
260
|
+
try { return JSON.parse(raw); } catch { return null; }
|
|
261
|
+
};
|
|
262
|
+
es.addEventListener("connected", e => {
|
|
263
|
+
const d = safeParse((e as MessageEvent).data) as { run_id: string; path: string } | null;
|
|
264
|
+
if (d) setEvents(prev => [...prev, { sseType: "connected", data: d }]);
|
|
265
|
+
});
|
|
266
|
+
es.addEventListener("meta", e => {
|
|
267
|
+
const d = safeParse((e as MessageEvent).data) as { _meta: { type: string; [k: string]: unknown } } | null;
|
|
268
|
+
if (d) setEvents(prev => [...prev, { sseType: "meta", data: d }]);
|
|
269
|
+
});
|
|
270
|
+
es.addEventListener("event", e => {
|
|
271
|
+
const d = safeParse((e as MessageEvent).data) as Record<string, unknown> | null;
|
|
272
|
+
if (d) setEvents(prev => [...prev, { sseType: "event", data: d }]);
|
|
273
|
+
});
|
|
274
|
+
es.addEventListener("done", e => {
|
|
275
|
+
const d = safeParse((e as MessageEvent).data) as { reason: string } | null;
|
|
276
|
+
if (d) {
|
|
277
|
+
setEvents(prev => [...prev, { sseType: "done", data: d }]);
|
|
278
|
+
setClosed(d.reason);
|
|
279
|
+
}
|
|
280
|
+
es.close();
|
|
281
|
+
});
|
|
282
|
+
es.addEventListener("stream_error", e => {
|
|
283
|
+
const d = safeParse((e as MessageEvent).data) as { message: string } | null;
|
|
284
|
+
if (d) setEvents(prev => [...prev, { sseType: "stream_error", data: d }]);
|
|
285
|
+
});
|
|
286
|
+
es.onerror = () => {
|
|
287
|
+
// EventSource auto-retries on transport errors; mark as closed only if
|
|
288
|
+
// we never managed to open the connection in the first place.
|
|
289
|
+
setOpen(currentOpen => {
|
|
290
|
+
if (!currentOpen) setClosed("connect-error");
|
|
291
|
+
return currentOpen;
|
|
292
|
+
});
|
|
293
|
+
};
|
|
294
|
+
return () => { es.close(); };
|
|
295
|
+
}, [runId]);
|
|
296
|
+
|
|
297
|
+
// Auto-scroll to bottom when new events arrive.
|
|
298
|
+
useEffect(() => {
|
|
299
|
+
if (eventsBoxRef.current) eventsBoxRef.current.scrollTop = eventsBoxRef.current.scrollHeight;
|
|
300
|
+
}, [events.length]);
|
|
301
|
+
|
|
302
|
+
// Pull out the payload meta for the prompt panel.
|
|
303
|
+
const payloadEvent = events.find(e => e.sseType === "meta" && (e.data as { _meta: { type: string } })._meta.type === "payload");
|
|
304
|
+
const startEvent = events.find(e => e.sseType === "meta" && (e.data as { _meta: { type: string } })._meta.type === "start");
|
|
305
|
+
const endEvent = events.find(e => e.sseType === "meta" && (e.data as { _meta: { type: string } })._meta.type === "end");
|
|
306
|
+
const payload = payloadEvent ? (payloadEvent.data as { _meta: { system_prompt: string; user_prompt: string; reminder: string | null } })._meta : null;
|
|
307
|
+
const startMeta = startEvent ? (startEvent.data as { _meta: { kind: string; model: string; ts: string } })._meta : null;
|
|
308
|
+
const endMeta = endEvent ? (endEvent.data as { _meta: { elapsed_ms: number; exit_code: number; content_chars: number; output_tokens: number; input_tokens: number; stderr_tail: string | null } })._meta : null;
|
|
309
|
+
|
|
310
|
+
// Compute live token counts from streamed assistant events.
|
|
311
|
+
const liveTokens = useMemo(() => {
|
|
312
|
+
let inT = 0, outT = 0, cacheCreate = 0, cacheRead = 0, contentChars = 0;
|
|
313
|
+
for (const ev of events) {
|
|
314
|
+
if (ev.sseType !== "event") continue;
|
|
315
|
+
const obj = ev.data as { type?: string; message?: { content?: Array<{ type?: string; text?: string }>; usage?: { input_tokens?: number; output_tokens?: number; cache_creation_input_tokens?: number; cache_read_input_tokens?: number } } };
|
|
316
|
+
if (obj.type === "assistant" && obj.message) {
|
|
317
|
+
const u = obj.message.usage;
|
|
318
|
+
if (u) {
|
|
319
|
+
inT = u.input_tokens ?? inT;
|
|
320
|
+
outT = u.output_tokens ?? outT;
|
|
321
|
+
cacheCreate = u.cache_creation_input_tokens ?? cacheCreate;
|
|
322
|
+
cacheRead = u.cache_read_input_tokens ?? cacheRead;
|
|
323
|
+
}
|
|
324
|
+
const content = obj.message.content;
|
|
325
|
+
if (Array.isArray(content)) {
|
|
326
|
+
for (const blk of content) {
|
|
327
|
+
if (blk.type === "text" && typeof blk.text === "string") contentChars += blk.text.length;
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
return { inT, outT, cacheCreate, cacheRead, contentChars };
|
|
333
|
+
}, [events]);
|
|
334
|
+
|
|
335
|
+
return (
|
|
336
|
+
<div style={{ display: "flex", flexDirection: "column", gap: 12 }}>
|
|
337
|
+
{/* Header */}
|
|
338
|
+
<Card>
|
|
339
|
+
<div style={{ display: "flex", alignItems: "baseline", justifyContent: "space-between", gap: 8, flexWrap: "wrap" }}>
|
|
340
|
+
<div>
|
|
341
|
+
<div style={{ fontSize: 13, fontWeight: 600 }}>
|
|
342
|
+
{startMeta ? (
|
|
343
|
+
<>
|
|
344
|
+
<KindDot kind={startMeta.kind} /> {startMeta.kind} · <span style={{ color: "var(--af-text-secondary)" }}>{startMeta.model}</span>
|
|
345
|
+
</>
|
|
346
|
+
) : (
|
|
347
|
+
"loading…"
|
|
348
|
+
)}
|
|
349
|
+
</div>
|
|
350
|
+
<div style={{ fontSize: 10, color: "var(--af-text-tertiary)", fontFamily: "var(--font-mono, ui-monospace)", marginTop: 3 }}>
|
|
351
|
+
{runId}
|
|
352
|
+
</div>
|
|
353
|
+
</div>
|
|
354
|
+
<div style={{ fontSize: 11, color: "var(--af-text-tertiary)", textAlign: "right" }}>
|
|
355
|
+
{open && !closed && <span style={{ color: "#3b82f6" }}>● live</span>}
|
|
356
|
+
{closed && <span style={{ color: closed === "end" ? "#16a34a" : "#dc2626" }}>● {closed}</span>}
|
|
357
|
+
</div>
|
|
358
|
+
</div>
|
|
359
|
+
<div style={{ marginTop: 8, fontSize: 11, display: "flex", gap: 14, flexWrap: "wrap", color: "var(--af-text-secondary)" }}>
|
|
360
|
+
<span>in: <strong>{liveTokens.inT.toLocaleString()}</strong></span>
|
|
361
|
+
<span>out: <strong>{liveTokens.outT.toLocaleString()}</strong></span>
|
|
362
|
+
<span>cache_create: <strong>{liveTokens.cacheCreate.toLocaleString()}</strong></span>
|
|
363
|
+
<span>cache_read: <strong>{liveTokens.cacheRead.toLocaleString()}</strong></span>
|
|
364
|
+
<span>chars: <strong>{liveTokens.contentChars.toLocaleString()}</strong></span>
|
|
365
|
+
{endMeta && <span>elapsed: <strong>{fmtElapsed(endMeta.elapsed_ms)}</strong></span>}
|
|
366
|
+
{endMeta && endMeta.exit_code !== 0 && <span style={{ color: "#dc2626" }}>exit: {endMeta.exit_code}</span>}
|
|
367
|
+
</div>
|
|
368
|
+
{endMeta && endMeta.stderr_tail && (
|
|
369
|
+
<pre style={{ marginTop: 8, padding: 8, background: "rgba(239, 68, 68, 0.08)", border: "1px solid rgba(239,68,68,0.2)", borderRadius: 6, fontSize: 11, whiteSpace: "pre-wrap", color: "#dc2626", maxHeight: 120, overflow: "auto" }}>
|
|
370
|
+
{endMeta.stderr_tail}
|
|
371
|
+
</pre>
|
|
372
|
+
)}
|
|
373
|
+
</Card>
|
|
374
|
+
|
|
375
|
+
{/* Prompt panel — collapsed by default, this is what was actually sent */}
|
|
376
|
+
<Card>
|
|
377
|
+
<button
|
|
378
|
+
onClick={() => setShowPrompts(s => !s)}
|
|
379
|
+
style={{ background: "transparent", border: "none", padding: 0, cursor: "pointer", color: "var(--af-text-secondary)", fontSize: 12, display: "flex", alignItems: "center", gap: 6 }}
|
|
380
|
+
>
|
|
381
|
+
{showPrompts ? "▾" : "▸"} Prompts ({payload ? `${payload.system_prompt.length + payload.user_prompt.length + (payload.reminder?.length ?? 0)} chars` : "—"})
|
|
382
|
+
</button>
|
|
383
|
+
{showPrompts && payload && (
|
|
384
|
+
<div style={{ marginTop: 10, display: "flex", flexDirection: "column", gap: 10 }}>
|
|
385
|
+
<PromptBlock label="System prompt" content={payload.system_prompt} />
|
|
386
|
+
<PromptBlock label="User prompt" content={payload.user_prompt} />
|
|
387
|
+
{payload.reminder && <PromptBlock label="Reminder (retry)" content={payload.reminder} />}
|
|
388
|
+
</div>
|
|
389
|
+
)}
|
|
390
|
+
</Card>
|
|
391
|
+
|
|
392
|
+
{/* Streamed events */}
|
|
393
|
+
<Card>
|
|
394
|
+
<div style={{ display: "flex", alignItems: "baseline", justifyContent: "space-between", marginBottom: 8 }}>
|
|
395
|
+
<strong style={{ fontSize: 13 }}>Stream events</strong>
|
|
396
|
+
<span style={{ fontSize: 11, color: "var(--af-text-tertiary)" }}>{events.length} msgs</span>
|
|
397
|
+
</div>
|
|
398
|
+
<div
|
|
399
|
+
ref={eventsBoxRef}
|
|
400
|
+
style={{
|
|
401
|
+
maxHeight: 480,
|
|
402
|
+
overflow: "auto",
|
|
403
|
+
background: "var(--af-bg-soft, rgba(0,0,0,0.04))",
|
|
404
|
+
borderRadius: 6,
|
|
405
|
+
padding: 8,
|
|
406
|
+
fontSize: 11,
|
|
407
|
+
fontFamily: "var(--font-mono, ui-monospace)",
|
|
408
|
+
display: "flex",
|
|
409
|
+
flexDirection: "column",
|
|
410
|
+
gap: 6,
|
|
411
|
+
}}
|
|
412
|
+
>
|
|
413
|
+
{events.map((ev, i) => <EventRow key={i} ev={ev} />)}
|
|
414
|
+
</div>
|
|
415
|
+
</Card>
|
|
416
|
+
</div>
|
|
417
|
+
);
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
function PromptBlock({ label, content }: { label: string; content: string }) {
|
|
421
|
+
return (
|
|
422
|
+
<div>
|
|
423
|
+
<div style={{ fontSize: 11, color: "var(--af-text-tertiary)", marginBottom: 4 }}>
|
|
424
|
+
{label} · {content.length.toLocaleString()} chars
|
|
425
|
+
</div>
|
|
426
|
+
<pre style={{ margin: 0, padding: 8, background: "var(--af-bg-soft, rgba(0,0,0,0.04))", borderRadius: 6, fontSize: 11, lineHeight: 1.5, whiteSpace: "pre-wrap", maxHeight: 280, overflow: "auto" }}>
|
|
427
|
+
{content}
|
|
428
|
+
</pre>
|
|
429
|
+
</div>
|
|
430
|
+
);
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
function EventRow({ ev }: { ev: StreamEvent }) {
|
|
434
|
+
if (ev.sseType === "connected") {
|
|
435
|
+
const d = ev.data;
|
|
436
|
+
return <Row tone="info"><b>connected</b> {d.run_id} ({d.path})</Row>;
|
|
437
|
+
}
|
|
438
|
+
if (ev.sseType === "done") {
|
|
439
|
+
return <Row tone="info"><b>done</b> reason={ev.data.reason}</Row>;
|
|
440
|
+
}
|
|
441
|
+
if (ev.sseType === "raw") {
|
|
442
|
+
return <Row tone="warn"><b>raw</b> {ev.data.line.slice(0, 200)}</Row>;
|
|
443
|
+
}
|
|
444
|
+
if (ev.sseType === "stream_error") {
|
|
445
|
+
return <Row tone="error"><b>stream_error</b> {ev.data.message}</Row>;
|
|
446
|
+
}
|
|
447
|
+
if (ev.sseType === "meta") {
|
|
448
|
+
const meta = ev.data._meta;
|
|
449
|
+
return <Row tone="meta"><b>{meta.type}</b> {summarizeMeta(meta)}</Row>;
|
|
450
|
+
}
|
|
451
|
+
// event from claude stream-json
|
|
452
|
+
const obj = ev.data as { type?: string; message?: { content?: Array<{ type?: string; text?: string; thinking?: string }>; model?: string }; rate_limit_info?: { status?: string; rateLimitType?: string; resetsAt?: number } };
|
|
453
|
+
if (obj.type === "system") {
|
|
454
|
+
return <Row tone="info"><b>system.init</b> tools={(obj as unknown as { tools?: unknown[] }).tools?.length ?? 0} mcp={(obj as unknown as { mcp_servers?: unknown[] }).mcp_servers?.length ?? 0}</Row>;
|
|
455
|
+
}
|
|
456
|
+
if (obj.type === "assistant" && obj.message?.content) {
|
|
457
|
+
const blocks = obj.message.content;
|
|
458
|
+
const summary = blocks.map(b => b.type === "text" ? `text(${(b.text ?? "").length})` : b.type === "thinking" ? `thinking(${(b.thinking ?? "").length})` : b.type ?? "?").join("+");
|
|
459
|
+
return <Row tone="ok"><b>assistant</b> {summary}</Row>;
|
|
460
|
+
}
|
|
461
|
+
if (obj.type === "rate_limit_event") {
|
|
462
|
+
const r = obj.rate_limit_info;
|
|
463
|
+
return <Row tone="warn"><b>rate_limit</b> status={r?.status} type={r?.rateLimitType} {r?.resetsAt ? `resets=${new Date(r.resetsAt * 1000).toLocaleTimeString()}` : ""}</Row>;
|
|
464
|
+
}
|
|
465
|
+
if (obj.type === "result") {
|
|
466
|
+
return <Row tone="ok"><b>result</b> {summarizeResult(obj as unknown as Record<string, unknown>)}</Row>;
|
|
467
|
+
}
|
|
468
|
+
return <Row tone="default"><b>{obj.type ?? "?"}</b> {JSON.stringify(obj).slice(0, 160)}</Row>;
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
function Row({ children, tone }: { children: React.ReactNode; tone: "info" | "ok" | "warn" | "error" | "meta" | "default" }) {
|
|
472
|
+
const colors: Record<typeof tone, string> = {
|
|
473
|
+
info: "var(--af-text-secondary)",
|
|
474
|
+
ok: "#16a34a",
|
|
475
|
+
warn: "#d97706",
|
|
476
|
+
error: "#dc2626",
|
|
477
|
+
meta: "#a855f7",
|
|
478
|
+
default: "var(--af-text-secondary)",
|
|
479
|
+
};
|
|
480
|
+
return <div style={{ color: colors[tone], lineHeight: 1.5 }}>{children}</div>;
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
function summarizeMeta(meta: { type: string; [k: string]: unknown }): string {
|
|
484
|
+
const { type, ...rest } = meta;
|
|
485
|
+
if (type === "payload") {
|
|
486
|
+
const m = rest as { system_prompt?: string; user_prompt?: string; reminder?: string | null };
|
|
487
|
+
return `system=${m.system_prompt?.length ?? 0}c user=${m.user_prompt?.length ?? 0}c reminder=${m.reminder?.length ?? 0}c`;
|
|
488
|
+
}
|
|
489
|
+
if (type === "spawned") return `pid=${(rest as { pid?: number }).pid}`;
|
|
490
|
+
if (type === "start") {
|
|
491
|
+
const m = rest as { kind?: string; model?: string; user_prompt_chars?: number };
|
|
492
|
+
return `${m.kind} ${m.model} user=${m.user_prompt_chars}c`;
|
|
493
|
+
}
|
|
494
|
+
if (type === "end") {
|
|
495
|
+
const m = rest as { elapsed_ms?: number; exit_code?: number; output_tokens?: number; content_chars?: number };
|
|
496
|
+
return `elapsed=${m.elapsed_ms}ms exit=${m.exit_code} out=${m.output_tokens}t chars=${m.content_chars}`;
|
|
497
|
+
}
|
|
498
|
+
return JSON.stringify(rest).slice(0, 200);
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
function summarizeResult(r: Record<string, unknown>): string {
|
|
502
|
+
const usage = r.usage as { input_tokens?: number; output_tokens?: number; cache_creation_input_tokens?: number; cache_read_input_tokens?: number } | undefined;
|
|
503
|
+
const cost = r.total_cost_usd as number | undefined;
|
|
504
|
+
const dur = r.duration_ms as number | undefined;
|
|
505
|
+
const parts: string[] = [];
|
|
506
|
+
if (dur != null) parts.push(`${dur}ms`);
|
|
507
|
+
if (usage?.input_tokens != null) parts.push(`in=${usage.input_tokens}`);
|
|
508
|
+
if (usage?.output_tokens != null) parts.push(`out=${usage.output_tokens}`);
|
|
509
|
+
if (usage?.cache_creation_input_tokens) parts.push(`cache_create=${usage.cache_creation_input_tokens.toLocaleString()}`);
|
|
510
|
+
if (usage?.cache_read_input_tokens) parts.push(`cache_read=${usage.cache_read_input_tokens.toLocaleString()}`);
|
|
511
|
+
if (cost != null) parts.push(`cost=$${cost.toFixed(4)}`);
|
|
512
|
+
return parts.join(" ");
|
|
513
|
+
}
|
|
@@ -14,6 +14,9 @@ import {
|
|
|
14
14
|
Activity,
|
|
15
15
|
Gauge,
|
|
16
16
|
Lightbulb,
|
|
17
|
+
Radio,
|
|
18
|
+
Settings,
|
|
19
|
+
CalendarDays,
|
|
17
20
|
} from "lucide-react";
|
|
18
21
|
import { formatRelative, prettyProjectName } from "@/lib/format";
|
|
19
22
|
import { ThemeToggle } from "@/components/theme-toggle";
|
|
@@ -181,11 +184,17 @@ export function Sidebar({
|
|
|
181
184
|
Projects
|
|
182
185
|
</NavLink>
|
|
183
186
|
<NavLink
|
|
184
|
-
href="/
|
|
185
|
-
active={
|
|
186
|
-
|
|
187
|
+
href="/day"
|
|
188
|
+
active={
|
|
189
|
+
pathname === "/day" ||
|
|
190
|
+
pathname.startsWith("/day/") ||
|
|
191
|
+
pathname === "/digest" ||
|
|
192
|
+
pathname.startsWith("/digest/") ||
|
|
193
|
+
pathname === "/parallelism"
|
|
194
|
+
}
|
|
195
|
+
icon={<CalendarDays size={15} />}
|
|
187
196
|
>
|
|
188
|
-
|
|
197
|
+
Day
|
|
189
198
|
</NavLink>
|
|
190
199
|
<NavLink
|
|
191
200
|
href="/usage"
|
|
@@ -201,6 +210,13 @@ export function Sidebar({
|
|
|
201
210
|
>
|
|
202
211
|
Insights
|
|
203
212
|
</NavLink>
|
|
213
|
+
<NavLink
|
|
214
|
+
href="/runs"
|
|
215
|
+
active={pathname === "/runs" || pathname.startsWith("/runs/")}
|
|
216
|
+
icon={<Radio size={15} />}
|
|
217
|
+
>
|
|
218
|
+
Runs
|
|
219
|
+
</NavLink>
|
|
204
220
|
</nav>
|
|
205
221
|
|
|
206
222
|
{/* Projects search + list */}
|
|
@@ -267,6 +283,24 @@ export function Sidebar({
|
|
|
267
283
|
<span style={{ flex: 1, minWidth: 0 }}>
|
|
268
284
|
{totalSessions} sessions · {projects.length} projects
|
|
269
285
|
</span>
|
|
286
|
+
<Link
|
|
287
|
+
href="/settings"
|
|
288
|
+
aria-label="Settings"
|
|
289
|
+
title="Settings"
|
|
290
|
+
style={{
|
|
291
|
+
display: "inline-flex",
|
|
292
|
+
alignItems: "center",
|
|
293
|
+
justifyContent: "center",
|
|
294
|
+
width: 24,
|
|
295
|
+
height: 24,
|
|
296
|
+
borderRadius: 6,
|
|
297
|
+
color: pathname === "/settings" ? "var(--af-text)" : "var(--af-text-tertiary)",
|
|
298
|
+
background: pathname === "/settings" ? "var(--af-surface-hover)" : "transparent",
|
|
299
|
+
textDecoration: "none",
|
|
300
|
+
}}
|
|
301
|
+
>
|
|
302
|
+
<Settings size={14} />
|
|
303
|
+
</Link>
|
|
270
304
|
<ThemeToggle />
|
|
271
305
|
</div>
|
|
272
306
|
</aside>
|
|
@@ -76,6 +76,7 @@ export function UsageChartRange({
|
|
|
76
76
|
endMs,
|
|
77
77
|
windowMs,
|
|
78
78
|
colorVar,
|
|
79
|
+
predictedSeries,
|
|
79
80
|
}: {
|
|
80
81
|
snapshots: UsageSnapshot[];
|
|
81
82
|
seriesKey: SeriesKey;
|
|
@@ -84,6 +85,10 @@ export function UsageChartRange({
|
|
|
84
85
|
/** Window duration in ms — 5h or 7d depending on seriesKey */
|
|
85
86
|
windowMs: number;
|
|
86
87
|
colorVar: string;
|
|
88
|
+
/** JSONL-derived utilization estimates (one per snapshot timestamp).
|
|
89
|
+
* Drawn per cycle as a dashed overlay so historical cycles can be
|
|
90
|
+
* compared against the prediction. */
|
|
91
|
+
predictedSeries?: { capturedAt: number; util: number }[];
|
|
87
92
|
}) {
|
|
88
93
|
const width = 1280;
|
|
89
94
|
const height = 320;
|
|
@@ -100,12 +105,17 @@ export function UsageChartRange({
|
|
|
100
105
|
}
|
|
101
106
|
if (valid.length === 0) return null;
|
|
102
107
|
|
|
103
|
-
// 2. Group into cycles by resets_at.
|
|
104
|
-
//
|
|
105
|
-
|
|
108
|
+
// 2. Group into cycles by resets_at. Anthropic jitters resets_at by
|
|
109
|
+
// milliseconds across snapshots in the same cycle, so we hour-round
|
|
110
|
+
// the bucket key — without this, "complete cycles" inflates from
|
|
111
|
+
// ~4 to ~2000 over a 30-day window.
|
|
112
|
+
const HOUR = 3_600_000;
|
|
113
|
+
const byReset = new Map<number, typeof valid>();
|
|
106
114
|
for (const p of valid) {
|
|
107
115
|
if (!p.resetsAt) continue;
|
|
108
|
-
const
|
|
116
|
+
const ms = new Date(p.resetsAt).getTime();
|
|
117
|
+
if (Number.isNaN(ms)) continue;
|
|
118
|
+
const key = Math.round(ms / HOUR) * HOUR;
|
|
109
119
|
let bucket = byReset.get(key);
|
|
110
120
|
if (!bucket) {
|
|
111
121
|
bucket = [];
|
|
@@ -115,8 +125,7 @@ export function UsageChartRange({
|
|
|
115
125
|
}
|
|
116
126
|
|
|
117
127
|
const cycles: CycleData[] = [];
|
|
118
|
-
for (const [
|
|
119
|
-
const resetsAtMs = new Date(resetsAtIso).getTime();
|
|
128
|
+
for (const [resetsAtMs, points] of byReset) {
|
|
120
129
|
const cycleStartMs = resetsAtMs - windowMs;
|
|
121
130
|
// Sort points by time
|
|
122
131
|
points.sort((a, b) => a.t - b.t);
|
|
@@ -439,6 +448,49 @@ export function UsageChartRange({
|
|
|
439
448
|
);
|
|
440
449
|
})}
|
|
441
450
|
|
|
451
|
+
{/* Predicted overlay — single continuous path across the visible
|
|
452
|
+
* range, broken when pred drops >= 50pp (= cycle reset). One path
|
|
453
|
+
* covers daemon-backed AND cold-start periods uniformly, so a
|
|
454
|
+
* 30D / 90D zoomout shows the prediction over its whole span. */}
|
|
455
|
+
{(() => {
|
|
456
|
+
const pred = (predictedSeries ?? [])
|
|
457
|
+
.filter((p) => p.capturedAt >= startMs && p.capturedAt <= endMs)
|
|
458
|
+
.sort((a, b) => a.capturedAt - b.capturedAt);
|
|
459
|
+
if (pred.length < 2) return null;
|
|
460
|
+
const parts: string[] = [];
|
|
461
|
+
let inSeg = false;
|
|
462
|
+
let prevUtil = pred[0]!.util;
|
|
463
|
+
for (let i = 0; i < pred.length; i++) {
|
|
464
|
+
const p = pred[i]!;
|
|
465
|
+
const u = Math.max(0, Math.min(100, p.util));
|
|
466
|
+
const remaining = 100 - u;
|
|
467
|
+
const drop = prevUtil - u;
|
|
468
|
+
const isReset = i > 0 && drop >= 50;
|
|
469
|
+
// Predicted series is sampled at 30-min granularity by the
|
|
470
|
+
// calibrator (vs 5-min for daemon snapshots), so the snapshot
|
|
471
|
+
// gap threshold rejects every adjacent pair as a "gap" and the
|
|
472
|
+
// line never connects. Use 60 min instead — anything beyond
|
|
473
|
+
// that is a genuine missing range.
|
|
474
|
+
const isGap = i > 0 && p.capturedAt - pred[i - 1]!.capturedAt > 60 * 60 * 1000;
|
|
475
|
+
const cmd = !inSeg || isReset || isGap ? "M" : "L";
|
|
476
|
+
parts.push(`${cmd} ${xScale(p.capturedAt).toFixed(1)} ${yScale(remaining).toFixed(1)}`);
|
|
477
|
+
inSeg = true;
|
|
478
|
+
prevUtil = u;
|
|
479
|
+
}
|
|
480
|
+
return (
|
|
481
|
+
<path
|
|
482
|
+
d={parts.join(" ")}
|
|
483
|
+
fill="none"
|
|
484
|
+
stroke="#ff7a00"
|
|
485
|
+
strokeOpacity="0.85"
|
|
486
|
+
strokeWidth="1.5"
|
|
487
|
+
strokeLinecap="round"
|
|
488
|
+
strokeLinejoin="round"
|
|
489
|
+
strokeDasharray="5 4"
|
|
490
|
+
/>
|
|
491
|
+
);
|
|
492
|
+
})()}
|
|
493
|
+
|
|
442
494
|
{/* Current-time vertical marker */}
|
|
443
495
|
{Date.now() >= startMs && Date.now() <= endMs && (
|
|
444
496
|
<line
|