@a5c-ai/babysitter-observer-dashboard 5.0.1-staging.05ee168a
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/BUILD_ID +1 -0
- package/.next/app-path-routes-manifest.json +16 -0
- package/.next/build-manifest.json +23 -0
- package/.next/export-marker.json +6 -0
- package/.next/fallback-build-manifest.json +13 -0
- package/.next/images-manifest.json +68 -0
- package/.next/next-minimal-server.js.nft.json +1 -0
- package/.next/next-server.js.nft.json +1 -0
- package/.next/package.json +1 -0
- package/.next/prerender-manifest.json +114 -0
- package/.next/required-server-files.json +334 -0
- package/.next/routes-manifest.json +139 -0
- package/.next/server/app/_global-error/page/app-paths-manifest.json +3 -0
- package/.next/server/app/_global-error/page/build-manifest.json +19 -0
- package/.next/server/app/_global-error/page/next-font-manifest.json +6 -0
- package/.next/server/app/_global-error/page/react-loadable-manifest.json +1 -0
- package/.next/server/app/_global-error/page/server-reference-manifest.json +4 -0
- package/.next/server/app/_global-error/page.js +9 -0
- package/.next/server/app/_global-error/page.js.map +5 -0
- package/.next/server/app/_global-error/page.js.nft.json +1 -0
- package/.next/server/app/_global-error/page_client-reference-manifest.js +3 -0
- package/.next/server/app/_global-error.html +1 -0
- package/.next/server/app/_global-error.meta +15 -0
- package/.next/server/app/_global-error.rsc +14 -0
- package/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +5 -0
- package/.next/server/app/_global-error.segments/_full.segment.rsc +14 -0
- package/.next/server/app/_global-error.segments/_head.segment.rsc +5 -0
- package/.next/server/app/_global-error.segments/_index.segment.rsc +5 -0
- package/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -0
- package/.next/server/app/_not-found/page/app-paths-manifest.json +3 -0
- package/.next/server/app/_not-found/page/build-manifest.json +19 -0
- package/.next/server/app/_not-found/page/next-font-manifest.json +6 -0
- package/.next/server/app/_not-found/page/react-loadable-manifest.json +1 -0
- package/.next/server/app/_not-found/page/server-reference-manifest.json +4 -0
- package/.next/server/app/_not-found/page.js +13 -0
- package/.next/server/app/_not-found/page.js.map +5 -0
- package/.next/server/app/_not-found/page.js.nft.json +1 -0
- package/.next/server/app/_not-found/page_client-reference-manifest.js +3 -0
- package/.next/server/app/_not-found.html +1 -0
- package/.next/server/app/_not-found.meta +16 -0
- package/.next/server/app/_not-found.rsc +19 -0
- package/.next/server/app/_not-found.segments/_full.segment.rsc +19 -0
- package/.next/server/app/_not-found.segments/_head.segment.rsc +6 -0
- package/.next/server/app/_not-found.segments/_index.segment.rsc +8 -0
- package/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +6 -0
- package/.next/server/app/_not-found.segments/_not-found.segment.rsc +5 -0
- package/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -0
- package/.next/server/app/api/config/route/app-paths-manifest.json +3 -0
- package/.next/server/app/api/config/route/build-manifest.json +9 -0
- package/.next/server/app/api/config/route/server-reference-manifest.json +4 -0
- package/.next/server/app/api/config/route.js +8 -0
- package/.next/server/app/api/config/route.js.map +5 -0
- package/.next/server/app/api/config/route.js.nft.json +1 -0
- package/.next/server/app/api/config/route_client-reference-manifest.js +3 -0
- package/.next/server/app/api/digest/route/app-paths-manifest.json +3 -0
- package/.next/server/app/api/digest/route/build-manifest.json +9 -0
- package/.next/server/app/api/digest/route/server-reference-manifest.json +4 -0
- package/.next/server/app/api/digest/route.js +9 -0
- package/.next/server/app/api/digest/route.js.map +5 -0
- package/.next/server/app/api/digest/route.js.nft.json +1 -0
- package/.next/server/app/api/digest/route_client-reference-manifest.js +3 -0
- package/.next/server/app/api/runs/[runId]/events/route/app-paths-manifest.json +3 -0
- package/.next/server/app/api/runs/[runId]/events/route/build-manifest.json +9 -0
- package/.next/server/app/api/runs/[runId]/events/route/server-reference-manifest.json +4 -0
- package/.next/server/app/api/runs/[runId]/events/route.js +8 -0
- package/.next/server/app/api/runs/[runId]/events/route.js.map +5 -0
- package/.next/server/app/api/runs/[runId]/events/route.js.nft.json +1 -0
- package/.next/server/app/api/runs/[runId]/events/route_client-reference-manifest.js +3 -0
- package/.next/server/app/api/runs/[runId]/route/app-paths-manifest.json +3 -0
- package/.next/server/app/api/runs/[runId]/route/build-manifest.json +9 -0
- package/.next/server/app/api/runs/[runId]/route/server-reference-manifest.json +4 -0
- package/.next/server/app/api/runs/[runId]/route.js +9 -0
- package/.next/server/app/api/runs/[runId]/route.js.map +5 -0
- package/.next/server/app/api/runs/[runId]/route.js.nft.json +1 -0
- package/.next/server/app/api/runs/[runId]/route_client-reference-manifest.js +3 -0
- package/.next/server/app/api/runs/[runId]/tasks/[effectId]/route/app-paths-manifest.json +3 -0
- package/.next/server/app/api/runs/[runId]/tasks/[effectId]/route/build-manifest.json +9 -0
- package/.next/server/app/api/runs/[runId]/tasks/[effectId]/route/server-reference-manifest.json +4 -0
- package/.next/server/app/api/runs/[runId]/tasks/[effectId]/route.js +8 -0
- package/.next/server/app/api/runs/[runId]/tasks/[effectId]/route.js.map +5 -0
- package/.next/server/app/api/runs/[runId]/tasks/[effectId]/route.js.nft.json +1 -0
- package/.next/server/app/api/runs/[runId]/tasks/[effectId]/route_client-reference-manifest.js +3 -0
- package/.next/server/app/api/runs/route/app-paths-manifest.json +3 -0
- package/.next/server/app/api/runs/route/build-manifest.json +9 -0
- package/.next/server/app/api/runs/route/server-reference-manifest.json +4 -0
- package/.next/server/app/api/runs/route.js +9 -0
- package/.next/server/app/api/runs/route.js.map +5 -0
- package/.next/server/app/api/runs/route.js.nft.json +1 -0
- package/.next/server/app/api/runs/route_client-reference-manifest.js +3 -0
- package/.next/server/app/api/stream/route/app-paths-manifest.json +3 -0
- package/.next/server/app/api/stream/route/build-manifest.json +9 -0
- package/.next/server/app/api/stream/route/server-reference-manifest.json +4 -0
- package/.next/server/app/api/stream/route.js +8 -0
- package/.next/server/app/api/stream/route.js.map +5 -0
- package/.next/server/app/api/stream/route.js.nft.json +1 -0
- package/.next/server/app/api/stream/route_client-reference-manifest.js +3 -0
- package/.next/server/app/api/test/route/app-paths-manifest.json +3 -0
- package/.next/server/app/api/test/route/build-manifest.json +9 -0
- package/.next/server/app/api/test/route/server-reference-manifest.json +4 -0
- package/.next/server/app/api/test/route.js +6 -0
- package/.next/server/app/api/test/route.js.map +5 -0
- package/.next/server/app/api/test/route.js.nft.json +1 -0
- package/.next/server/app/api/test/route_client-reference-manifest.js +3 -0
- package/.next/server/app/api/version/route/app-paths-manifest.json +3 -0
- package/.next/server/app/api/version/route/build-manifest.json +9 -0
- package/.next/server/app/api/version/route/server-reference-manifest.json +4 -0
- package/.next/server/app/api/version/route.js +7 -0
- package/.next/server/app/api/version/route.js.map +5 -0
- package/.next/server/app/api/version/route.js.nft.json +1 -0
- package/.next/server/app/api/version/route_client-reference-manifest.js +3 -0
- package/.next/server/app/icon.svg/route/app-paths-manifest.json +3 -0
- package/.next/server/app/icon.svg/route/build-manifest.json +9 -0
- package/.next/server/app/icon.svg/route.js +7 -0
- package/.next/server/app/icon.svg/route.js.map +5 -0
- package/.next/server/app/icon.svg/route.js.nft.json +1 -0
- package/.next/server/app/icon.svg.body +20 -0
- package/.next/server/app/icon.svg.meta +1 -0
- package/.next/server/app/index.html +1 -0
- package/.next/server/app/index.meta +14 -0
- package/.next/server/app/index.rsc +21 -0
- package/.next/server/app/index.segments/__PAGE__.segment.rsc +9 -0
- package/.next/server/app/index.segments/_full.segment.rsc +21 -0
- package/.next/server/app/index.segments/_head.segment.rsc +6 -0
- package/.next/server/app/index.segments/_index.segment.rsc +8 -0
- package/.next/server/app/index.segments/_tree.segment.rsc +2 -0
- package/.next/server/app/page/app-paths-manifest.json +3 -0
- package/.next/server/app/page/build-manifest.json +19 -0
- package/.next/server/app/page/next-font-manifest.json +6 -0
- package/.next/server/app/page/react-loadable-manifest.json +1 -0
- package/.next/server/app/page/server-reference-manifest.json +17 -0
- package/.next/server/app/page.js +15 -0
- package/.next/server/app/page.js.map +5 -0
- package/.next/server/app/page.js.nft.json +1 -0
- package/.next/server/app/page_client-reference-manifest.js +3 -0
- package/.next/server/app/runs/[runId]/page/app-paths-manifest.json +3 -0
- package/.next/server/app/runs/[runId]/page/build-manifest.json +19 -0
- package/.next/server/app/runs/[runId]/page/next-font-manifest.json +6 -0
- package/.next/server/app/runs/[runId]/page/react-loadable-manifest.json +22 -0
- package/.next/server/app/runs/[runId]/page/server-reference-manifest.json +17 -0
- package/.next/server/app/runs/[runId]/page.js +15 -0
- package/.next/server/app/runs/[runId]/page.js.map +5 -0
- package/.next/server/app/runs/[runId]/page.js.nft.json +1 -0
- package/.next/server/app/runs/[runId]/page_client-reference-manifest.js +3 -0
- package/.next/server/app-paths-manifest.json +16 -0
- package/.next/server/chunks/01oi_server_app_api_runs_[runId]_tasks_[effectId]_route_actions_0r72yai.js +3 -0
- package/.next/server/chunks/01oi_server_app_api_runs_[runId]_tasks_[effectId]_route_actions_0r72yai.js.map +1 -0
- package/.next/server/chunks/0h.v__next-internal_server_app_api_runs_[runId]_events_route_actions_0~msldk.js +3 -0
- package/.next/server/chunks/0h.v__next-internal_server_app_api_runs_[runId]_events_route_actions_0~msldk.js.map +1 -0
- package/.next/server/chunks/0h.v__next-internal_server_app_api_runs_[runId]_route_actions_09iz0n6.js +3 -0
- package/.next/server/chunks/0h.v__next-internal_server_app_api_runs_[runId]_route_actions_09iz0n6.js.map +1 -0
- package/.next/server/chunks/0juq_observer-dashboard__next-internal_server_app_api_config_route_actions_0~eypoa.js +3 -0
- package/.next/server/chunks/0juq_observer-dashboard__next-internal_server_app_api_config_route_actions_0~eypoa.js.map +1 -0
- package/.next/server/chunks/0juq_observer-dashboard__next-internal_server_app_api_digest_route_actions_04jj5zs.js +3 -0
- package/.next/server/chunks/0juq_observer-dashboard__next-internal_server_app_api_digest_route_actions_04jj5zs.js.map +1 -0
- package/.next/server/chunks/0juq_observer-dashboard__next-internal_server_app_api_runs_route_actions_0~-t-o4.js +3 -0
- package/.next/server/chunks/0juq_observer-dashboard__next-internal_server_app_api_runs_route_actions_0~-t-o4.js.map +1 -0
- package/.next/server/chunks/0juq_observer-dashboard__next-internal_server_app_api_stream_route_actions_0fkmv2_.js +3 -0
- package/.next/server/chunks/0juq_observer-dashboard__next-internal_server_app_api_stream_route_actions_0fkmv2_.js.map +1 -0
- package/.next/server/chunks/0juq_observer-dashboard__next-internal_server_app_api_test_route_actions_00ugava.js +3 -0
- package/.next/server/chunks/0juq_observer-dashboard__next-internal_server_app_api_test_route_actions_00ugava.js.map +1 -0
- package/.next/server/chunks/0juq_observer-dashboard__next-internal_server_app_api_version_route_actions_0~v3ojm.js +3 -0
- package/.next/server/chunks/0juq_observer-dashboard__next-internal_server_app_api_version_route_actions_0~v3ojm.js.map +1 -0
- package/.next/server/chunks/0juq_observer-dashboard__next-internal_server_app_icon_svg_route_actions_0yypxkm.js +3 -0
- package/.next/server/chunks/0juq_observer-dashboard__next-internal_server_app_icon_svg_route_actions_0yypxkm.js.map +1 -0
- package/.next/server/chunks/[root-of-the-server]__0.6bt.6._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__0.6bt.6._.js.map +1 -0
- package/.next/server/chunks/[root-of-the-server]__08kwev1._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__08kwev1._.js.map +1 -0
- package/.next/server/chunks/[root-of-the-server]__096el.d._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__096el.d._.js.map +1 -0
- package/.next/server/chunks/[root-of-the-server]__0_bmt4z._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__0_bmt4z._.js.map +1 -0
- package/.next/server/chunks/[root-of-the-server]__0_ln2d2._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__0_ln2d2._.js.map +1 -0
- package/.next/server/chunks/[root-of-the-server]__0al3v65._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__0al3v65._.js.map +1 -0
- package/.next/server/chunks/[root-of-the-server]__0gf516b._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__0gf516b._.js.map +1 -0
- package/.next/server/chunks/[root-of-the-server]__0kdfw4x._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__0kdfw4x._.js.map +1 -0
- package/.next/server/chunks/[root-of-the-server]__0pxt00h._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__0pxt00h._.js.map +1 -0
- package/.next/server/chunks/[root-of-the-server]__0rubnza._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__0rubnza._.js.map +1 -0
- package/.next/server/chunks/[root-of-the-server]__0tn9iud._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__0tn9iud._.js.map +1 -0
- package/.next/server/chunks/[root-of-the-server]__0ws5o6i._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__0ws5o6i._.js.map +1 -0
- package/.next/server/chunks/[turbopack]_runtime.js +903 -0
- package/.next/server/chunks/[turbopack]_runtime.js.map +11 -0
- package/.next/server/chunks/node_modules_next_04~_e52._.js +13 -0
- package/.next/server/chunks/node_modules_next_04~_e52._.js.map +1 -0
- package/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_0nyyph-.js +9 -0
- package/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_0nyyph-.js.map +1 -0
- package/.next/server/chunks/packages_observer-dashboard_src_lib_02.vvb.._.js +3 -0
- package/.next/server/chunks/packages_observer-dashboard_src_lib_02.vvb.._.js.map +1 -0
- package/.next/server/chunks/packages_observer-dashboard_src_lib_0rqgpk0._.js +3 -0
- package/.next/server/chunks/packages_observer-dashboard_src_lib_0rqgpk0._.js.map +1 -0
- package/.next/server/chunks/ssr/0juq_observer-dashboard__next-internal_server_app__global-error_page_actions_0ekoxmy.js +3 -0
- package/.next/server/chunks/ssr/0juq_observer-dashboard__next-internal_server_app__global-error_page_actions_0ekoxmy.js.map +1 -0
- package/.next/server/chunks/ssr/0juq_observer-dashboard__next-internal_server_app__not-found_page_actions_09b3ti3.js +3 -0
- package/.next/server/chunks/ssr/0juq_observer-dashboard__next-internal_server_app__not-found_page_actions_09b3ti3.js.map +1 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__006f7~t._.js +4 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__006f7~t._.js.map +1 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__02jgvbi._.js +3 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__02jgvbi._.js.map +1 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__04j8t~1._.js +3 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__04j8t~1._.js.map +1 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__09c~s.0._.js +33 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__09c~s.0._.js.map +1 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__0cpy61n._.js +3 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__0cpy61n._.js.map +1 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__0cwa32j._.js +3 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__0cwa32j._.js.map +1 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__0fk_g0j._.js +19 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__0fk_g0j._.js.map +1 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__0pddpic._.js +3 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__0pddpic._.js.map +1 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__0pvtneq._.js +3 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__0pvtneq._.js.map +1 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__0xc-2vm._.js +3 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__0xc-2vm._.js.map +1 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__10xgshr._.js +33 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__10xgshr._.js.map +1 -0
- package/.next/server/chunks/ssr/[turbopack]_runtime.js +903 -0
- package/.next/server/chunks/ssr/[turbopack]_runtime.js.map +11 -0
- package/.next/server/chunks/ssr/_00yo1im._.js +3 -0
- package/.next/server/chunks/ssr/_00yo1im._.js.map +1 -0
- package/.next/server/chunks/ssr/_03sbc.o._.js +3 -0
- package/.next/server/chunks/ssr/_03sbc.o._.js.map +1 -0
- package/.next/server/chunks/ssr/_04z5ea0._.js +3 -0
- package/.next/server/chunks/ssr/_04z5ea0._.js.map +1 -0
- package/.next/server/chunks/ssr/_0gmb3g_._.js +3 -0
- package/.next/server/chunks/ssr/_0gmb3g_._.js.map +1 -0
- package/.next/server/chunks/ssr/_0okz9j8._.js +6 -0
- package/.next/server/chunks/ssr/_0okz9j8._.js.map +1 -0
- package/.next/server/chunks/ssr/_0wrbwro._.js +6 -0
- package/.next/server/chunks/ssr/_0wrbwro._.js.map +1 -0
- package/.next/server/chunks/ssr/node_modules_09w7yel._.js +33 -0
- package/.next/server/chunks/ssr/node_modules_09w7yel._.js.map +1 -0
- package/.next/server/chunks/ssr/node_modules_next_dist_0avqw4q._.js +3 -0
- package/.next/server/chunks/ssr/node_modules_next_dist_0avqw4q._.js.map +1 -0
- package/.next/server/chunks/ssr/node_modules_next_dist_0h9llsw._.js +6 -0
- package/.next/server/chunks/ssr/node_modules_next_dist_0h9llsw._.js.map +1 -0
- package/.next/server/chunks/ssr/node_modules_next_dist_0i_._k3._.js +3 -0
- package/.next/server/chunks/ssr/node_modules_next_dist_0i_._k3._.js.map +1 -0
- package/.next/server/chunks/ssr/node_modules_next_dist_client_components_0ee1czk._.js +3 -0
- package/.next/server/chunks/ssr/node_modules_next_dist_client_components_0ee1czk._.js.map +1 -0
- package/.next/server/chunks/ssr/node_modules_next_dist_client_components_builtin_global-error_0lgvd_..js +3 -0
- package/.next/server/chunks/ssr/node_modules_next_dist_client_components_builtin_global-error_0lgvd_..js.map +1 -0
- package/.next/server/chunks/ssr/node_modules_next_dist_client_components_builtin_unauthorized_0cjv-23.js +3 -0
- package/.next/server/chunks/ssr/node_modules_next_dist_client_components_builtin_unauthorized_0cjv-23.js.map +1 -0
- package/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0amzg6z.js +4 -0
- package/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0amzg6z.js.map +1 -0
- package/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0dw1x0d.js +4 -0
- package/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0dw1x0d.js.map +1 -0
- package/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0rc3ul_.js +4 -0
- package/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0rc3ul_.js.map +1 -0
- package/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_10iomok.js +4 -0
- package/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_10iomok.js.map +1 -0
- package/.next/server/chunks/ssr/packages_observer-dashboard_0~a2tmu._.js +3 -0
- package/.next/server/chunks/ssr/packages_observer-dashboard_0~a2tmu._.js.map +1 -0
- package/.next/server/chunks/ssr/packages_observer-dashboard_src_0f.ozc-._.js +3 -0
- package/.next/server/chunks/ssr/packages_observer-dashboard_src_0f.ozc-._.js.map +1 -0
- package/.next/server/chunks/ssr/packages_observer-dashboard_src_components_providers_tsx_03_vrrn._.js +7 -0
- package/.next/server/chunks/ssr/packages_observer-dashboard_src_components_providers_tsx_03_vrrn._.js.map +1 -0
- package/.next/server/functions-config-manifest.json +4 -0
- package/.next/server/interception-route-rewrite-manifest.js +1 -0
- package/.next/server/middleware-build-manifest.js +23 -0
- package/.next/server/middleware-manifest.json +6 -0
- package/.next/server/next-font-manifest.js +1 -0
- package/.next/server/next-font-manifest.json +6 -0
- package/.next/server/pages/404.html +1 -0
- package/.next/server/pages/500.html +1 -0
- package/.next/server/pages-manifest.json +4 -0
- package/.next/server/prefetch-hints.json +1 -0
- package/.next/server/server-reference-manifest.js +1 -0
- package/.next/server/server-reference-manifest.json +24 -0
- package/.next/static/EABLIK_sdQGd8BsGP793M/_buildManifest.js +11 -0
- package/.next/static/EABLIK_sdQGd8BsGP793M/_clientMiddlewareManifest.js +1 -0
- package/.next/static/EABLIK_sdQGd8BsGP793M/_ssgManifest.js +1 -0
- package/.next/static/chunks/0.syqclhhnw~3.js +4 -0
- package/.next/static/chunks/01xlw8hd842-c.js +1 -0
- package/.next/static/chunks/034i63v_muq~d.js +1 -0
- package/.next/static/chunks/03mo-6~4pxdio.js +1 -0
- package/.next/static/chunks/03~yq9q893hmn.js +1 -0
- package/.next/static/chunks/04dm5qn77.fc2.js +1 -0
- package/.next/static/chunks/07uz2g0_38qia.js +4 -0
- package/.next/static/chunks/08nqnwvixoxnk.js +2 -0
- package/.next/static/chunks/09fqccrs830-n.js +1 -0
- package/.next/static/chunks/0d3shmwh5_nmn.js +1 -0
- package/.next/static/chunks/0e_wyjw3nx.a..js +1 -0
- package/.next/static/chunks/0jgju7iyqhzfr.js +1 -0
- package/.next/static/chunks/0mstyq17cbf8-.js +1 -0
- package/.next/static/chunks/0ntuxw9.how-q.js +1 -0
- package/.next/static/chunks/0t3uzajv1qzmo.js +1 -0
- package/.next/static/chunks/0tk7tld3z8q_b.js +1 -0
- package/.next/static/chunks/0u~_nwr5-v.xp.js +1 -0
- package/.next/static/chunks/0x6y7yt4kiddp.css +1 -0
- package/.next/static/chunks/0ze4gu236oq96.js +31 -0
- package/.next/static/chunks/0zwozael9msy1.js +1 -0
- package/.next/static/chunks/0~nsmwzvlcp_3.js +1 -0
- package/.next/static/chunks/10qd__0r7a~.l.js +1 -0
- package/.next/static/chunks/11jh_u1ynmatg.js +1 -0
- package/.next/static/chunks/144kcri75qczu.js +1 -0
- package/.next/static/chunks/170fc9ko4~0_4.js +5 -0
- package/.next/static/chunks/turbopack-0-ww6fe7b37qt.js +1 -0
- package/.next/static/media/icon.08ljfy7xai2x_.svg +20 -0
- package/LICENSE +21 -0
- package/README.md +490 -0
- package/next.config.mjs +25 -0
- package/package.json +104 -0
- package/postcss.config.mjs +8 -0
- package/src/app/actions/__tests__/approve-breakpoint.test.ts +246 -0
- package/src/app/actions/approve-breakpoint.ts +145 -0
- package/src/app/api/config/route.ts +137 -0
- package/src/app/api/digest/route.ts +45 -0
- package/src/app/api/runs/[runId]/events/route.ts +56 -0
- package/src/app/api/runs/[runId]/route.ts +84 -0
- package/src/app/api/runs/[runId]/tasks/[effectId]/route.ts +44 -0
- package/src/app/api/runs/route.ts +48 -0
- package/src/app/api/stream/route.ts +136 -0
- package/src/app/api/test/route.ts +1 -0
- package/src/app/api/version/route.ts +57 -0
- package/src/app/globals.css +555 -0
- package/src/app/icon.svg +20 -0
- package/src/app/layout.tsx +39 -0
- package/src/app/not-found.tsx +16 -0
- package/src/app/page.tsx +120 -0
- package/src/app/runs/[runId]/page.tsx +279 -0
- package/src/cli.ts +271 -0
- package/src/components/breakpoint/__tests__/breakpoint-approval.test.tsx +212 -0
- package/src/components/breakpoint/__tests__/breakpoint-panel.test.tsx +130 -0
- package/src/components/breakpoint/__tests__/file-preview.test.tsx +313 -0
- package/src/components/breakpoint/breakpoint-approval.tsx +138 -0
- package/src/components/breakpoint/breakpoint-panel.tsx +95 -0
- package/src/components/breakpoint/file-preview.tsx +215 -0
- package/src/components/dashboard/.gitkeep +0 -0
- package/src/components/dashboard/__tests__/breakpoint-banner.test.tsx +177 -0
- package/src/components/dashboard/__tests__/catch-up-banner.test.tsx +141 -0
- package/src/components/dashboard/__tests__/executive-summary-banner.test.tsx +164 -0
- package/src/components/dashboard/__tests__/kpi-grid.test.tsx +101 -0
- package/src/components/dashboard/__tests__/pagination-controls.test.tsx +125 -0
- package/src/components/dashboard/__tests__/project-accordion.test.tsx +97 -0
- package/src/components/dashboard/__tests__/project-list-view.test.tsx +174 -0
- package/src/components/dashboard/__tests__/project-search-input.test.tsx +110 -0
- package/src/components/dashboard/__tests__/project-section-header.test.tsx +91 -0
- package/src/components/dashboard/__tests__/project-section.test.tsx +151 -0
- package/src/components/dashboard/__tests__/run-card.test.tsx +164 -0
- package/src/components/dashboard/__tests__/run-filter-bar.test.tsx +109 -0
- package/src/components/dashboard/__tests__/run-list.test.tsx +123 -0
- package/src/components/dashboard/__tests__/search-filter.test.tsx +150 -0
- package/src/components/dashboard/__tests__/virtualized-run-list.test.tsx +179 -0
- package/src/components/dashboard/breakpoint-banner.tsx +301 -0
- package/src/components/dashboard/catch-up-banner.tsx +88 -0
- package/src/components/dashboard/executive-summary-banner.tsx +174 -0
- package/src/components/dashboard/global-search.tsx +323 -0
- package/src/components/dashboard/kpi-grid.tsx +140 -0
- package/src/components/dashboard/pagination-controls.tsx +100 -0
- package/src/components/dashboard/project-accordion.tsx +72 -0
- package/src/components/dashboard/project-health-card.tsx +536 -0
- package/src/components/dashboard/project-list-view.tsx +246 -0
- package/src/components/dashboard/project-search-input.tsx +41 -0
- package/src/components/dashboard/project-section-header.tsx +73 -0
- package/src/components/dashboard/project-section.tsx +89 -0
- package/src/components/dashboard/run-card.tsx +218 -0
- package/src/components/dashboard/run-filter-bar.tsx +100 -0
- package/src/components/dashboard/run-list.tsx +77 -0
- package/src/components/dashboard/search-filter.tsx +69 -0
- package/src/components/dashboard/virtualized-run-list.tsx +130 -0
- package/src/components/details/.gitkeep +0 -0
- package/src/components/details/__tests__/agent-panel.test.tsx +236 -0
- package/src/components/details/__tests__/json-tree.test.tsx +347 -0
- package/src/components/details/__tests__/log-viewer.test.tsx +168 -0
- package/src/components/details/__tests__/task-detail.test.tsx +212 -0
- package/src/components/details/__tests__/timing-panel.test.tsx +271 -0
- package/src/components/details/agent-panel.tsx +234 -0
- package/src/components/details/json-tree/categorize.ts +131 -0
- package/src/components/details/json-tree/index.tsx +120 -0
- package/src/components/details/json-tree/json-node.tsx +223 -0
- package/src/components/details/json-tree/smart-summary.tsx +596 -0
- package/src/components/details/json-tree/tree-controls.tsx +47 -0
- package/src/components/details/json-tree.tsx +9 -0
- package/src/components/details/log-viewer.tsx +140 -0
- package/src/components/details/task-detail.tsx +114 -0
- package/src/components/details/timing-panel.tsx +247 -0
- package/src/components/events/.gitkeep +0 -0
- package/src/components/events/__tests__/event-item.test.tsx +211 -0
- package/src/components/events/__tests__/event-stream.test.tsx +225 -0
- package/src/components/events/event-item.tsx +121 -0
- package/src/components/events/event-stream.tsx +260 -0
- package/src/components/notifications/.gitkeep +0 -0
- package/src/components/notifications/__tests__/notification-panel.test.tsx +287 -0
- package/src/components/notifications/__tests__/notification-provider.test.tsx +585 -0
- package/src/components/notifications/__tests__/toast-stack.test.tsx +217 -0
- package/src/components/notifications/notification-panel.tsx +124 -0
- package/src/components/notifications/notification-provider.tsx +175 -0
- package/src/components/notifications/toast-stack.tsx +75 -0
- package/src/components/pipeline/.gitkeep +0 -0
- package/src/components/pipeline/__tests__/parallel-group.test.tsx +88 -0
- package/src/components/pipeline/__tests__/pipeline-view.test.tsx +345 -0
- package/src/components/pipeline/__tests__/step-card.test.tsx +330 -0
- package/src/components/pipeline/parallel-group.tsx +39 -0
- package/src/components/pipeline/pipeline-view.tsx +197 -0
- package/src/components/pipeline/step-card.tsx +166 -0
- package/src/components/providers/event-stream-provider.tsx +29 -0
- package/src/components/providers.tsx +24 -0
- package/src/components/shared/.gitkeep +0 -0
- package/src/components/shared/__tests__/empty-state.test.tsx +49 -0
- package/src/components/shared/__tests__/friendly-id.test.tsx +47 -0
- package/src/components/shared/__tests__/kbd.test.tsx +45 -0
- package/src/components/shared/__tests__/kind-badge.test.tsx +71 -0
- package/src/components/shared/__tests__/metrics-row.test.tsx +74 -0
- package/src/components/shared/__tests__/outcome-banner.test.tsx +71 -0
- package/src/components/shared/__tests__/progress-bar.test.tsx +89 -0
- package/src/components/shared/__tests__/session-pill.test.tsx +62 -0
- package/src/components/shared/__tests__/settings-modal.test.tsx +201 -0
- package/src/components/shared/__tests__/shortcuts-help.test.tsx +103 -0
- package/src/components/shared/__tests__/status-badge.test.tsx +98 -0
- package/src/components/shared/__tests__/theme-provider.test.tsx +100 -0
- package/src/components/shared/__tests__/truncated-id.test.tsx +53 -0
- package/src/components/shared/app-footer.tsx +80 -0
- package/src/components/shared/app-header.tsx +160 -0
- package/src/components/shared/empty-state.tsx +18 -0
- package/src/components/shared/error-boundary.tsx +81 -0
- package/src/components/shared/friendly-id.tsx +48 -0
- package/src/components/shared/kbd.tsx +15 -0
- package/src/components/shared/kind-badge.tsx +51 -0
- package/src/components/shared/metrics-row.tsx +106 -0
- package/src/components/shared/outcome-banner.tsx +56 -0
- package/src/components/shared/progress-bar.tsx +42 -0
- package/src/components/shared/session-pill.tsx +69 -0
- package/src/components/shared/settings-modal.tsx +509 -0
- package/src/components/shared/shortcuts-help.tsx +113 -0
- package/src/components/shared/status-badge.tsx +110 -0
- package/src/components/shared/theme-provider.tsx +46 -0
- package/src/components/shared/truncated-id.tsx +51 -0
- package/src/components/ui/.gitkeep +0 -0
- package/src/components/ui/__tests__/accordion.test.tsx +96 -0
- package/src/components/ui/__tests__/badge.test.tsx +69 -0
- package/src/components/ui/__tests__/button.test.tsx +113 -0
- package/src/components/ui/__tests__/tabs.test.tsx +75 -0
- package/src/components/ui/__tests__/tooltip.test.tsx +90 -0
- package/src/components/ui/accordion.tsx +61 -0
- package/src/components/ui/badge.tsx +25 -0
- package/src/components/ui/button.tsx +40 -0
- package/src/components/ui/card.tsx +21 -0
- package/src/components/ui/scroll-area.tsx +35 -0
- package/src/components/ui/separator.tsx +24 -0
- package/src/components/ui/tabs.tsx +64 -0
- package/src/components/ui/tooltip.tsx +37 -0
- package/src/hooks/.gitkeep +0 -0
- package/src/hooks/__tests__/use-animated-number.test.ts +184 -0
- package/src/hooks/__tests__/use-batched-updates.test.ts +315 -0
- package/src/hooks/__tests__/use-event-stream.test.ts +243 -0
- package/src/hooks/__tests__/use-keyboard.test.ts +217 -0
- package/src/hooks/__tests__/use-notifications.test.ts +230 -0
- package/src/hooks/__tests__/use-polling.test.ts +274 -0
- package/src/hooks/__tests__/use-project-runs.test.ts +163 -0
- package/src/hooks/__tests__/use-projects.test.ts +248 -0
- package/src/hooks/__tests__/use-run-dashboard.test.ts +168 -0
- package/src/hooks/__tests__/use-run-detail.test.ts +273 -0
- package/src/hooks/__tests__/use-smart-polling.test.ts +305 -0
- package/src/hooks/use-animated-number.ts +87 -0
- package/src/hooks/use-batched-updates.ts +150 -0
- package/src/hooks/use-event-stream.ts +150 -0
- package/src/hooks/use-keyboard.ts +45 -0
- package/src/hooks/use-notifications.ts +82 -0
- package/src/hooks/use-persisted-state.ts +60 -0
- package/src/hooks/use-polling.ts +60 -0
- package/src/hooks/use-project-runs.ts +51 -0
- package/src/hooks/use-projects.ts +26 -0
- package/src/hooks/use-run-dashboard.ts +207 -0
- package/src/hooks/use-run-detail.ts +77 -0
- package/src/hooks/use-smart-polling.ts +144 -0
- package/src/lib/.gitkeep +0 -0
- package/src/lib/__tests__/cn.test.ts +69 -0
- package/src/lib/__tests__/config-loader.test.ts +210 -0
- package/src/lib/__tests__/config.test.ts +561 -0
- package/src/lib/__tests__/error-handler.test.ts +143 -0
- package/src/lib/__tests__/fetcher.test.ts +517 -0
- package/src/lib/__tests__/global-registry.test.ts +214 -0
- package/src/lib/__tests__/parser.test.ts +1532 -0
- package/src/lib/__tests__/path-resolver.test.ts +112 -0
- package/src/lib/__tests__/run-cache.test.ts +591 -0
- package/src/lib/__tests__/server-init.test.ts +512 -0
- package/src/lib/__tests__/source-discovery.test.ts +246 -0
- package/src/lib/__tests__/utils.test.ts +160 -0
- package/src/lib/__tests__/watcher.test.ts +227 -0
- package/src/lib/cn.ts +6 -0
- package/src/lib/config-loader.ts +195 -0
- package/src/lib/config.ts +20 -0
- package/src/lib/error-handler.ts +76 -0
- package/src/lib/fetcher.ts +394 -0
- package/src/lib/global-registry.ts +117 -0
- package/src/lib/parser.ts +794 -0
- package/src/lib/path-resolver.ts +16 -0
- package/src/lib/run-cache.ts +404 -0
- package/src/lib/server-init.ts +226 -0
- package/src/lib/services/__tests__/run-query-service.test.ts +819 -0
- package/src/lib/services/run-query-service.ts +286 -0
- package/src/lib/source-discovery.ts +216 -0
- package/src/lib/utils.ts +103 -0
- package/src/lib/watcher.ts +265 -0
- package/src/test/fixtures.ts +269 -0
- package/src/test/mocks/handlers.ts +110 -0
- package/src/test/mocks/server.ts +17 -0
- package/src/test/setup.ts +200 -0
- package/src/test/test-utils.tsx +36 -0
- package/src/types/.gitkeep +0 -0
- package/src/types/breakpoint.ts +17 -0
- package/src/types/index.ts +214 -0
- package/tsconfig.json +50 -0
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
import { getConfig as defaultGetConfig } from "@/lib/config-loader";
|
|
2
|
+
import { discoverAllRunDirs as defaultDiscoverAllRunDirs } from "@/lib/source-discovery";
|
|
3
|
+
import {
|
|
4
|
+
getProjectSummaries as defaultGetProjectSummaries,
|
|
5
|
+
getRunCached as defaultGetRunCached,
|
|
6
|
+
discoverAndCacheAll as defaultDiscoverAndCacheAll,
|
|
7
|
+
} from "@/lib/run-cache";
|
|
8
|
+
import type { Run, ProjectSummary } from "@/types";
|
|
9
|
+
import type { ObserverConfig, WatchSource } from "@/lib/config-loader";
|
|
10
|
+
import type { DiscoveredRun } from "@/lib/source-discovery";
|
|
11
|
+
|
|
12
|
+
// ---------------------------------------------------------------------------
|
|
13
|
+
// Query parameter types
|
|
14
|
+
// ---------------------------------------------------------------------------
|
|
15
|
+
|
|
16
|
+
export type SortMode = "status" | "activity";
|
|
17
|
+
|
|
18
|
+
export interface RunQueryParams {
|
|
19
|
+
limit: number;
|
|
20
|
+
offset: number;
|
|
21
|
+
search: string;
|
|
22
|
+
status: string;
|
|
23
|
+
sort: SortMode;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export type ProjectsQueryParams = Record<string, never>;
|
|
27
|
+
|
|
28
|
+
export interface ProjectRunsQueryParams extends RunQueryParams {
|
|
29
|
+
project: string;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// ---------------------------------------------------------------------------
|
|
33
|
+
// Response types
|
|
34
|
+
// ---------------------------------------------------------------------------
|
|
35
|
+
|
|
36
|
+
/** A run with events stripped to reduce payload size. */
|
|
37
|
+
export interface LightRun extends Omit<Run, "events"> {
|
|
38
|
+
events: never[];
|
|
39
|
+
totalEvents: number;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export interface ProjectsResponse {
|
|
43
|
+
projects: ProjectSummary[];
|
|
44
|
+
recentCompletionWindowMs: number;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export interface RunsListResponse {
|
|
48
|
+
runs: LightRun[];
|
|
49
|
+
totalCount: number;
|
|
50
|
+
project?: string;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// ---------------------------------------------------------------------------
|
|
54
|
+
// Shared utilities
|
|
55
|
+
// ---------------------------------------------------------------------------
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Returns a numeric sort priority for a run:
|
|
59
|
+
* 0 = Active non-stale (waiting/pending where !isStale)
|
|
60
|
+
* 1 = Stale runs (isStale === true)
|
|
61
|
+
* 2 = Failed runs
|
|
62
|
+
* 3 = Completed runs
|
|
63
|
+
*/
|
|
64
|
+
export function runSortPriority(run: Run): number {
|
|
65
|
+
const isActive = run.status === "waiting" || run.status === "pending";
|
|
66
|
+
if (isActive && !run.isStale) return 0;
|
|
67
|
+
if (run.isStale) return 1;
|
|
68
|
+
if (run.status === "failed") return 2;
|
|
69
|
+
return 3;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/** Sort runs in-place based on the chosen sort mode.
|
|
73
|
+
*
|
|
74
|
+
* Uses runId as a final tiebreaker to guarantee deterministic ordering
|
|
75
|
+
* even when multiple runs share the same priority and updatedAt timestamp.
|
|
76
|
+
* This prevents list items from visually jumping positions during rapid
|
|
77
|
+
* updates (the "morning chaos" scenario).
|
|
78
|
+
*/
|
|
79
|
+
export function sortRuns(runs: Run[], sort: SortMode): void {
|
|
80
|
+
if (sort === "activity") {
|
|
81
|
+
// Simple updatedAt DESC -- most recent activity first, no tier grouping.
|
|
82
|
+
// runId tiebreaker ensures stable order for runs with identical timestamps.
|
|
83
|
+
runs.sort((a, b) => {
|
|
84
|
+
const cmp = (b.updatedAt || "").localeCompare(a.updatedAt || "");
|
|
85
|
+
if (cmp !== 0) return cmp;
|
|
86
|
+
return a.runId.localeCompare(b.runId);
|
|
87
|
+
});
|
|
88
|
+
} else {
|
|
89
|
+
// Default: sort by priority tier, then by updatedAt DESC within tier,
|
|
90
|
+
// with runId as a final tiebreaker for deterministic ordering.
|
|
91
|
+
runs.sort((a, b) => {
|
|
92
|
+
const pa = runSortPriority(a);
|
|
93
|
+
const pb = runSortPriority(b);
|
|
94
|
+
if (pa !== pb) return pa - pb;
|
|
95
|
+
const cmp = (b.updatedAt || "").localeCompare(a.updatedAt || "");
|
|
96
|
+
if (cmp !== 0) return cmp;
|
|
97
|
+
return a.runId.localeCompare(b.runId);
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/** Apply search filter -- returns a new array. */
|
|
103
|
+
export function filterBySearch(runs: Run[], search: string): Run[] {
|
|
104
|
+
if (!search) return runs;
|
|
105
|
+
const searchLower = search.toLowerCase();
|
|
106
|
+
return runs.filter(
|
|
107
|
+
(r) =>
|
|
108
|
+
r.runId.toLowerCase().includes(searchLower) ||
|
|
109
|
+
r.processId.toLowerCase().includes(searchLower) ||
|
|
110
|
+
(r.projectName || "").toLowerCase().includes(searchLower) ||
|
|
111
|
+
r.status.toLowerCase().includes(searchLower) ||
|
|
112
|
+
r.tasks.some(
|
|
113
|
+
(t) =>
|
|
114
|
+
t.title.toLowerCase().includes(searchLower) ||
|
|
115
|
+
t.label.toLowerCase().includes(searchLower) ||
|
|
116
|
+
(t.error?.message || "").toLowerCase().includes(searchLower) ||
|
|
117
|
+
(t.error?.name || "").toLowerCase().includes(searchLower)
|
|
118
|
+
)
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/** Apply status filter -- returns a new array. */
|
|
123
|
+
export function filterByStatus(runs: Run[], status: string): Run[] {
|
|
124
|
+
if (!status) return runs;
|
|
125
|
+
return runs.filter((r) => {
|
|
126
|
+
if (status === "waiting") return r.status === "waiting" || r.status === "pending";
|
|
127
|
+
return r.status === status;
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/** Apply retention filter -- keeps active/stale runs regardless of age. */
|
|
132
|
+
export function filterByRetention(runs: Run[], retentionDays: number): Run[] {
|
|
133
|
+
const retentionCutoff = Date.now() - retentionDays * 24 * 60 * 60 * 1000;
|
|
134
|
+
return runs.filter((r) => {
|
|
135
|
+
const isActive = r.status === "waiting" || r.status === "pending" || r.isStale;
|
|
136
|
+
if (isActive) return true;
|
|
137
|
+
return new Date(r.updatedAt || "").getTime() >= retentionCutoff;
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/** Paginate an array: returns a new slice. */
|
|
142
|
+
export function paginate<T>(items: T[], offset: number, limit: number): T[] {
|
|
143
|
+
if (limit > 0) {
|
|
144
|
+
return items.slice(offset, offset + limit);
|
|
145
|
+
}
|
|
146
|
+
return items;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/** Strip events from runs to reduce payload. */
|
|
150
|
+
export function toLightRuns(runs: Run[]): LightRun[] {
|
|
151
|
+
return runs.map(({ events, ...rest }) => ({
|
|
152
|
+
...rest,
|
|
153
|
+
events: [] as never[],
|
|
154
|
+
totalEvents: events.length,
|
|
155
|
+
}));
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// ---------------------------------------------------------------------------
|
|
159
|
+
// Dependency injection interface
|
|
160
|
+
// ---------------------------------------------------------------------------
|
|
161
|
+
|
|
162
|
+
export interface RunQueryDeps {
|
|
163
|
+
getConfig: () => Promise<ObserverConfig>;
|
|
164
|
+
discoverAllRunDirs: () => Promise<DiscoveredRun[]>;
|
|
165
|
+
getProjectSummaries: () => ProjectSummary[];
|
|
166
|
+
getRunCached: (runDir: string, source: WatchSource, projectName: string) => Promise<Run>;
|
|
167
|
+
discoverAndCacheAll: () => Promise<void>;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
const defaultDeps: RunQueryDeps = {
|
|
171
|
+
getConfig: defaultGetConfig,
|
|
172
|
+
discoverAllRunDirs: defaultDiscoverAllRunDirs,
|
|
173
|
+
getProjectSummaries: defaultGetProjectSummaries,
|
|
174
|
+
getRunCached: defaultGetRunCached,
|
|
175
|
+
discoverAndCacheAll: defaultDiscoverAndCacheAll,
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
// ---------------------------------------------------------------------------
|
|
179
|
+
// RunQueryService
|
|
180
|
+
// ---------------------------------------------------------------------------
|
|
181
|
+
|
|
182
|
+
export class RunQueryService {
|
|
183
|
+
private deps: RunQueryDeps;
|
|
184
|
+
|
|
185
|
+
constructor(deps?: Partial<RunQueryDeps>) {
|
|
186
|
+
this.deps = { ...defaultDeps, ...deps };
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Mode: "projects" -- return lightweight project summaries.
|
|
191
|
+
* Always re-discovers to ensure all projects appear (debounced internally).
|
|
192
|
+
*/
|
|
193
|
+
async listProjects(_params?: ProjectsQueryParams): Promise<ProjectsResponse> {
|
|
194
|
+
await this.deps.discoverAndCacheAll();
|
|
195
|
+
const config = await this.deps.getConfig();
|
|
196
|
+
const projects = this.deps.getProjectSummaries();
|
|
197
|
+
|
|
198
|
+
// Filter out hidden projects
|
|
199
|
+
const hiddenSet = new Set(config.hiddenProjects);
|
|
200
|
+
const visibleProjects = projects.filter((p) => !hiddenSet.has(p.projectName));
|
|
201
|
+
|
|
202
|
+
// Apply retention filter: exclude projects whose latest update is older than retentionDays
|
|
203
|
+
const retentionCutoff = Date.now() - config.retentionDays * 24 * 60 * 60 * 1000;
|
|
204
|
+
const retainedProjects = visibleProjects.filter(
|
|
205
|
+
(p) =>
|
|
206
|
+
// Always keep projects with active or stale runs regardless of age
|
|
207
|
+
p.activeRuns > 0 ||
|
|
208
|
+
p.staleRuns > 0 ||
|
|
209
|
+
new Date(p.latestUpdate).getTime() >= retentionCutoff
|
|
210
|
+
);
|
|
211
|
+
|
|
212
|
+
// Sort projects: active runs first, then by latest update, with
|
|
213
|
+
// projectName tiebreaker for deterministic ordering during rapid updates.
|
|
214
|
+
retainedProjects.sort((a, b) => {
|
|
215
|
+
if (a.activeRuns > 0 && b.activeRuns === 0) return -1;
|
|
216
|
+
if (a.activeRuns === 0 && b.activeRuns > 0) return 1;
|
|
217
|
+
const cmp = b.latestUpdate.localeCompare(a.latestUpdate);
|
|
218
|
+
if (cmp !== 0) return cmp;
|
|
219
|
+
return a.projectName.localeCompare(b.projectName);
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
return {
|
|
223
|
+
projects: retainedProjects,
|
|
224
|
+
recentCompletionWindowMs: config.recentCompletionWindowMs,
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* Mode: "project" -- return paginated runs for a specific project.
|
|
230
|
+
*/
|
|
231
|
+
async listProjectRuns(params: ProjectRunsQueryParams): Promise<RunsListResponse> {
|
|
232
|
+
const { project, sort, status, search, limit, offset } = params;
|
|
233
|
+
const config = await this.deps.getConfig();
|
|
234
|
+
const allRuns = await this.deps.discoverAllRunDirs();
|
|
235
|
+
|
|
236
|
+
// Use cached runs for better performance
|
|
237
|
+
const runs = await Promise.all(
|
|
238
|
+
allRuns
|
|
239
|
+
.filter((r) => r.projectName === project)
|
|
240
|
+
.map(async ({ runDir, source, projectName }) => {
|
|
241
|
+
return await this.deps.getRunCached(runDir, source, projectName);
|
|
242
|
+
})
|
|
243
|
+
);
|
|
244
|
+
|
|
245
|
+
// Apply retention, sort, status filter, search, paginate
|
|
246
|
+
let filtered = filterByRetention(runs, config.retentionDays);
|
|
247
|
+
sortRuns(filtered, sort);
|
|
248
|
+
filtered = filterByStatus(filtered, status);
|
|
249
|
+
filtered = filterBySearch(filtered, search);
|
|
250
|
+
|
|
251
|
+
const totalCount = filtered.length;
|
|
252
|
+
const page = paginate(filtered, offset, limit);
|
|
253
|
+
|
|
254
|
+
return {
|
|
255
|
+
runs: toLightRuns(page),
|
|
256
|
+
totalCount,
|
|
257
|
+
project,
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* Default mode -- return all runs with totalCount.
|
|
263
|
+
*/
|
|
264
|
+
async listAllRuns(params: RunQueryParams): Promise<RunsListResponse> {
|
|
265
|
+
const { sort, search, limit, offset } = params;
|
|
266
|
+
const allRuns = await this.deps.discoverAllRunDirs();
|
|
267
|
+
|
|
268
|
+
const runs = await Promise.all(
|
|
269
|
+
allRuns.map(async ({ runDir, source, projectName }) => {
|
|
270
|
+
return await this.deps.getRunCached(runDir, source, projectName);
|
|
271
|
+
})
|
|
272
|
+
);
|
|
273
|
+
|
|
274
|
+
// Sort, search, paginate (no retention filter on "all runs" -- matches original)
|
|
275
|
+
sortRuns(runs, sort);
|
|
276
|
+
let filtered = filterBySearch(runs, search);
|
|
277
|
+
|
|
278
|
+
const totalCount = filtered.length;
|
|
279
|
+
filtered = paginate(filtered, offset, limit);
|
|
280
|
+
|
|
281
|
+
return {
|
|
282
|
+
runs: toLightRuns(filtered),
|
|
283
|
+
totalCount,
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
}
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
import { promises as fs } from "fs";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import { isNotFoundError, getConfig, type WatchSource } from "./config-loader";
|
|
4
|
+
|
|
5
|
+
export interface DiscoveredRun {
|
|
6
|
+
runDir: string;
|
|
7
|
+
source: WatchSource;
|
|
8
|
+
projectName: string; // e.g. "hockey_7_shifts", "podcast-intel"
|
|
9
|
+
projectPath: string; // full path to the project directory
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
// Discover all .a5c/runs/ directories within a source
|
|
13
|
+
async function discoverRunsInSource(source: WatchSource): Promise<string[]> {
|
|
14
|
+
const results: string[] = [];
|
|
15
|
+
|
|
16
|
+
async function scan(dir: string, currentDepth: number) {
|
|
17
|
+
try {
|
|
18
|
+
// Check if this directory itself IS an .a5c/runs dir (depth=0 means direct path)
|
|
19
|
+
if (source.depth === 0) {
|
|
20
|
+
const entries = await fs.readdir(dir, { withFileTypes: true });
|
|
21
|
+
return entries
|
|
22
|
+
.filter((e) => e.isDirectory())
|
|
23
|
+
.map((e) => path.join(dir, e.name));
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Check for .a5c/runs/ at this level
|
|
27
|
+
const runsPath = path.join(dir, ".a5c", "runs");
|
|
28
|
+
try {
|
|
29
|
+
const stat = await fs.stat(runsPath);
|
|
30
|
+
if (stat.isDirectory()) {
|
|
31
|
+
results.push(runsPath);
|
|
32
|
+
}
|
|
33
|
+
} catch {
|
|
34
|
+
// Expected: no .a5c/runs directory at this level — skip silently
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Recurse into subdirectories if within depth
|
|
38
|
+
if (currentDepth < source.depth) {
|
|
39
|
+
const entries = await fs.readdir(dir, { withFileTypes: true });
|
|
40
|
+
for (const entry of entries) {
|
|
41
|
+
if (
|
|
42
|
+
entry.isDirectory() &&
|
|
43
|
+
!entry.name.startsWith(".") &&
|
|
44
|
+
entry.name !== "node_modules"
|
|
45
|
+
) {
|
|
46
|
+
await scan(path.join(dir, entry.name), currentDepth + 1);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
} catch (err) {
|
|
51
|
+
if (!isNotFoundError(err)) {
|
|
52
|
+
console.warn(`[config] Cannot scan directory ${dir} (depth=${currentDepth}):`, err);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (source.depth === 0) {
|
|
58
|
+
// Direct .a5c/runs path — just return runs inside it
|
|
59
|
+
try {
|
|
60
|
+
const entries = await fs.readdir(source.path, { withFileTypes: true });
|
|
61
|
+
return entries
|
|
62
|
+
.filter((e) => e.isDirectory())
|
|
63
|
+
.map((e) => path.join(source.path, e.name));
|
|
64
|
+
} catch (err) {
|
|
65
|
+
console.warn(`[config] Cannot list runs in direct source ${source.path}:`, err);
|
|
66
|
+
return [];
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
await scan(source.path, 0);
|
|
71
|
+
return results;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Extract project name from a .a5c/runs/ path
|
|
75
|
+
function extractProjectName(runsDir: string): { projectName: string; projectPath: string } {
|
|
76
|
+
// runsDir is like /path/to/project/.a5c/runs
|
|
77
|
+
// projectPath is /path/to/project
|
|
78
|
+
const a5cDir = path.dirname(runsDir); // .a5c
|
|
79
|
+
const projectPath = path.dirname(a5cDir); // project dir
|
|
80
|
+
const projectName = path.basename(projectPath);
|
|
81
|
+
return { projectName, projectPath };
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Cache discovery results to avoid repeated filesystem scanning
|
|
85
|
+
let discoveryCache: DiscoveredRun[] = [];
|
|
86
|
+
let discoveryCacheTime = 0;
|
|
87
|
+
const DISCOVERY_CACHE_TTL = 10000; // 10s — watcher handles real-time changes
|
|
88
|
+
|
|
89
|
+
// Force re-discovery on next call (called when new runs are detected by watcher)
|
|
90
|
+
export function invalidateDiscoveryCache(): void {
|
|
91
|
+
discoveryCache = [];
|
|
92
|
+
discoveryCacheTime = 0;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Get all run directories across all sources
|
|
96
|
+
export async function discoverAllRunDirs(): Promise<DiscoveredRun[]> {
|
|
97
|
+
const now = Date.now();
|
|
98
|
+
if (discoveryCache.length > 0 && now - discoveryCacheTime < DISCOVERY_CACHE_TTL) {
|
|
99
|
+
return discoveryCache;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const config = await getConfig();
|
|
103
|
+
const allRuns: DiscoveredRun[] = [];
|
|
104
|
+
|
|
105
|
+
for (const source of config.sources) {
|
|
106
|
+
if (source.depth === 0) {
|
|
107
|
+
// Direct runs directory — list subdirs as individual runs
|
|
108
|
+
// Project name: prefer run.json's projectName, fall back to source label or path
|
|
109
|
+
const fallbackProjectName = source.label || path.basename(source.path);
|
|
110
|
+
try {
|
|
111
|
+
const entries = await fs.readdir(source.path, { withFileTypes: true });
|
|
112
|
+
for (const entry of entries) {
|
|
113
|
+
if (entry.isDirectory()) {
|
|
114
|
+
// Try to read projectName from run.json for more accurate project grouping
|
|
115
|
+
let projectName = fallbackProjectName;
|
|
116
|
+
try {
|
|
117
|
+
const runJsonPath = path.join(source.path, entry.name, "run.json");
|
|
118
|
+
const content = await fs.readFile(runJsonPath, "utf-8");
|
|
119
|
+
const json = JSON.parse(content);
|
|
120
|
+
if (json.projectName) {
|
|
121
|
+
projectName = json.projectName;
|
|
122
|
+
}
|
|
123
|
+
} catch (err) {
|
|
124
|
+
// run.json missing is expected for new runs; warn only on parse/permission errors
|
|
125
|
+
if (!isNotFoundError(err)) {
|
|
126
|
+
console.warn(`[config] Failed to read run.json in ${path.join(source.path, entry.name)} — using fallback project name:`, err);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
allRuns.push({
|
|
130
|
+
runDir: path.join(source.path, entry.name),
|
|
131
|
+
source,
|
|
132
|
+
projectName,
|
|
133
|
+
projectPath: source.path,
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
} catch (err) {
|
|
138
|
+
console.warn(`[config] Source directory not accessible ${source.path}:`, err);
|
|
139
|
+
}
|
|
140
|
+
} else {
|
|
141
|
+
// Discover .a5c/runs/ directories within depth
|
|
142
|
+
const runsDirs = await discoverRunsInSource(source);
|
|
143
|
+
for (const runsDir of runsDirs) {
|
|
144
|
+
const { projectName, projectPath } = extractProjectName(runsDir);
|
|
145
|
+
try {
|
|
146
|
+
const entries = await fs.readdir(runsDir, { withFileTypes: true });
|
|
147
|
+
for (const entry of entries) {
|
|
148
|
+
if (entry.isDirectory()) {
|
|
149
|
+
allRuns.push({
|
|
150
|
+
runDir: path.join(runsDir, entry.name),
|
|
151
|
+
source,
|
|
152
|
+
projectName,
|
|
153
|
+
projectPath,
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
} catch (err) {
|
|
158
|
+
console.warn(`[config] Cannot read runs directory ${runsDir}:`, err);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// Deduplicate by runId (basename of runDir). When the same run ID appears
|
|
165
|
+
// under multiple .a5c/runs/ directories (e.g. a "ghost" .a5c created by a
|
|
166
|
+
// task execution in a subdirectory), keep the first occurrence — which is
|
|
167
|
+
// the shallowest/earliest discovered and typically the one with full data
|
|
168
|
+
// (run.json + journal).
|
|
169
|
+
const seenRunIds = new Map<string, DiscoveredRun>();
|
|
170
|
+
for (const run of allRuns) {
|
|
171
|
+
const runId = path.basename(run.runDir);
|
|
172
|
+
if (!seenRunIds.has(runId)) {
|
|
173
|
+
seenRunIds.set(runId, run);
|
|
174
|
+
} else {
|
|
175
|
+
// Prefer the run directory that has a run.json (i.e. the real one)
|
|
176
|
+
const existing = seenRunIds.get(runId)!;
|
|
177
|
+
const existingHasRunJson = await fs.access(path.join(existing.runDir, "run.json")).then(() => true, () => false);
|
|
178
|
+
if (!existingHasRunJson) {
|
|
179
|
+
const candidateHasRunJson = await fs.access(path.join(run.runDir, "run.json")).then(() => true, () => false);
|
|
180
|
+
if (candidateHasRunJson) {
|
|
181
|
+
seenRunIds.set(runId, run);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
const result = Array.from(seenRunIds.values());
|
|
188
|
+
discoveryCache = result;
|
|
189
|
+
discoveryCacheTime = Date.now();
|
|
190
|
+
return result;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// Discover all .a5c/runs/ parent directories (including empty ones).
|
|
194
|
+
// Used by the watcher to set up watches on directories that don't have runs yet,
|
|
195
|
+
// so that the very first run in a new project is detected immediately.
|
|
196
|
+
export async function discoverAllRunsParentDirs(): Promise<string[]> {
|
|
197
|
+
const config = await getConfig();
|
|
198
|
+
const allDirs: string[] = [];
|
|
199
|
+
|
|
200
|
+
for (const source of config.sources) {
|
|
201
|
+
if (source.depth === 0) {
|
|
202
|
+
// Direct runs path — watch the source path itself
|
|
203
|
+
try {
|
|
204
|
+
await fs.access(source.path);
|
|
205
|
+
allDirs.push(source.path);
|
|
206
|
+
} catch (err) {
|
|
207
|
+
console.warn(`[config] Watch source path not accessible ${source.path}:`, err);
|
|
208
|
+
}
|
|
209
|
+
} else {
|
|
210
|
+
const runsDirs = await discoverRunsInSource(source);
|
|
211
|
+
allDirs.push(...runsDirs);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
return allDirs;
|
|
216
|
+
}
|
package/src/lib/utils.ts
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
export function formatDuration(ms: number | undefined | null): string {
|
|
2
|
+
if (ms == null || ms < 0) return "\u2014";
|
|
3
|
+
if (ms === 0) return "<1s";
|
|
4
|
+
if (ms < 1000) return `${ms}ms`;
|
|
5
|
+
const seconds = Math.floor(ms / 1000);
|
|
6
|
+
if (seconds < 60) return `${seconds}s`;
|
|
7
|
+
const minutes = Math.floor(seconds / 60);
|
|
8
|
+
const remainingSeconds = seconds % 60;
|
|
9
|
+
if (minutes < 60) return `${minutes}m ${remainingSeconds}s`;
|
|
10
|
+
const hours = Math.floor(minutes / 60);
|
|
11
|
+
const remainingMinutes = minutes % 60;
|
|
12
|
+
return `${hours}h ${remainingMinutes}m`;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function formatTimestamp(iso: string | undefined): string {
|
|
16
|
+
if (!iso) return "\u2014";
|
|
17
|
+
try {
|
|
18
|
+
const d = new Date(iso);
|
|
19
|
+
return d.toLocaleTimeString("en-US", {
|
|
20
|
+
hour12: false,
|
|
21
|
+
hour: "2-digit",
|
|
22
|
+
minute: "2-digit",
|
|
23
|
+
second: "2-digit",
|
|
24
|
+
});
|
|
25
|
+
} catch {
|
|
26
|
+
return "\u2014";
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function formatRelativeTime(iso: string | undefined): string {
|
|
31
|
+
if (!iso) return "";
|
|
32
|
+
try {
|
|
33
|
+
const diff = Date.now() - new Date(iso).getTime();
|
|
34
|
+
if (diff < 0) return "just now";
|
|
35
|
+
if (diff < 5000) return "just now";
|
|
36
|
+
if (diff < 60000) return `${Math.floor(diff / 1000)}s ago`;
|
|
37
|
+
if (diff < 3600000) return `${Math.floor(diff / 60000)}m ago`;
|
|
38
|
+
if (diff < 86400000) return `${Math.floor(diff / 3600000)}h ago`;
|
|
39
|
+
return `${Math.floor(diff / 86400000)}d ago`;
|
|
40
|
+
} catch {
|
|
41
|
+
return "";
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function truncateId(id: string, len: number = 12): string {
|
|
46
|
+
if (!id) return "\u2014";
|
|
47
|
+
if (id.length <= len) return id;
|
|
48
|
+
return id.slice(0, len) + "...";
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export function getStatusColor(status: string): string {
|
|
52
|
+
switch (status) {
|
|
53
|
+
case "completed":
|
|
54
|
+
case "resolved":
|
|
55
|
+
case "ok":
|
|
56
|
+
return "text-success";
|
|
57
|
+
case "failed":
|
|
58
|
+
case "error":
|
|
59
|
+
return "text-error";
|
|
60
|
+
case "waiting":
|
|
61
|
+
case "pending":
|
|
62
|
+
return "text-pending";
|
|
63
|
+
case "running":
|
|
64
|
+
case "requested":
|
|
65
|
+
return "text-info";
|
|
66
|
+
default:
|
|
67
|
+
return "text-foreground-muted";
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export function getStatusBg(status: string): string {
|
|
72
|
+
switch (status) {
|
|
73
|
+
case "completed":
|
|
74
|
+
case "resolved":
|
|
75
|
+
case "ok":
|
|
76
|
+
return "bg-success-muted";
|
|
77
|
+
case "failed":
|
|
78
|
+
case "error":
|
|
79
|
+
return "bg-error-muted";
|
|
80
|
+
case "waiting":
|
|
81
|
+
case "pending":
|
|
82
|
+
return "bg-pending-muted";
|
|
83
|
+
case "running":
|
|
84
|
+
case "requested":
|
|
85
|
+
return "bg-info-muted";
|
|
86
|
+
default:
|
|
87
|
+
return "bg-muted";
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export function formatShortId(id: string, chars: number = 4): string {
|
|
92
|
+
if (!id) return '—';
|
|
93
|
+
if (id.length <= chars) return id;
|
|
94
|
+
return '...' + id.slice(-chars);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export function friendlyProcessName(processId: string): string {
|
|
98
|
+
if (!processId) return '';
|
|
99
|
+
return processId
|
|
100
|
+
.split(/[-/]/)
|
|
101
|
+
.map(word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
|
|
102
|
+
.join(' ');
|
|
103
|
+
}
|