@sleep2agi/agent-network-dashboard 0.4.6-preview.3 → 0.4.6-preview.30
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 -1
- package/.next/app-path-routes-manifest.json +1 -0
- package/.next/build/chunks/{node_modules_13sb.px._.js → 00jm_02mlcew._.js} +167 -167
- package/.next/build/chunks/00jm_02mlcew._.js.map +47 -0
- package/.next/build/chunks/{[root-of-the-server]__0ubbtyl._.js → [root-of-the-server]__0tgc-8p._.js} +3 -3
- package/.next/build/chunks/{[root-of-the-server]__0d-m0h0._.js → [root-of-the-server]__13z64y.._.js} +7 -7
- package/.next/build/chunks/{[root-of-the-server]__0d-m0h0._.js.map → [root-of-the-server]__13z64y.._.js.map} +2 -2
- package/.next/build/chunks/[turbopack-node]_transforms_postcss_ts_0r4x5ys._.js +13 -0
- package/.next/build/chunks/[turbopack]_runtime.js +1 -1
- package/.next/build/postcss.js +4 -4
- package/.next/build-manifest.json +8 -8
- package/.next/diagnostics/route-bundle-stats.json +157 -143
- package/.next/fallback-build-manifest.json +3 -3
- package/.next/next-minimal-server.js.nft.json +1 -1
- package/.next/next-server.js.nft.json +1 -1
- package/.next/prerender-manifest.json +3 -3
- package/.next/required-server-files.js +4 -4
- package/.next/required-server-files.json +4 -4
- package/.next/routes-manifest.json +6 -0
- package/.next/server/app/_global-error/page/build-manifest.json +5 -5
- package/.next/server/app/_global-error/page.js +9 -9
- package/.next/server/app/_global-error/page.js.nft.json +1 -1
- package/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
- package/.next/server/app/_global-error.html +1 -1
- package/.next/server/app/_global-error.rsc +8 -8
- package/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +2 -2
- package/.next/server/app/_global-error.segments/_full.segment.rsc +8 -8
- package/.next/server/app/_global-error.segments/_head.segment.rsc +4 -4
- package/.next/server/app/_global-error.segments/_index.segment.rsc +3 -3
- package/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/.next/server/app/_not-found/page/build-manifest.json +5 -5
- package/.next/server/app/_not-found/page/next-font-manifest.json +1 -1
- package/.next/server/app/_not-found/page.js +12 -12
- package/.next/server/app/_not-found/page.js.nft.json +1 -1
- package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/.next/server/app/_not-found.html +2 -2
- package/.next/server/app/_not-found.rsc +12 -12
- package/.next/server/app/_not-found.segments/_full.segment.rsc +12 -12
- package/.next/server/app/_not-found.segments/_head.segment.rsc +4 -4
- package/.next/server/app/_not-found.segments/_index.segment.rsc +7 -7
- package/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +2 -2
- package/.next/server/app/_not-found.segments/_not-found.segment.rsc +3 -3
- package/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/admin/page/build-manifest.json +5 -5
- package/.next/server/app/admin/page/next-font-manifest.json +1 -1
- package/.next/server/app/admin/page.js +13 -13
- package/.next/server/app/admin/page.js.nft.json +1 -1
- package/.next/server/app/admin/page_client-reference-manifest.js +1 -1
- package/.next/server/app/admin.html +2 -2
- package/.next/server/app/admin.rsc +14 -14
- package/.next/server/app/admin.segments/_full.segment.rsc +14 -14
- package/.next/server/app/admin.segments/_head.segment.rsc +4 -4
- package/.next/server/app/admin.segments/_index.segment.rsc +7 -7
- package/.next/server/app/admin.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/admin.segments/admin/__PAGE__.segment.rsc +4 -4
- package/.next/server/app/admin.segments/admin.segment.rsc +3 -3
- package/.next/server/app/api/anet/config/route.js +6 -6
- package/.next/server/app/api/anet/config/route.js.nft.json +1 -1
- package/.next/server/app/api/auth/login/route.js +7 -7
- package/.next/server/app/api/auth/login/route.js.nft.json +1 -1
- package/.next/server/app/api/auth/logout/route.js +7 -7
- package/.next/server/app/api/auth/logout/route.js.nft.json +1 -1
- package/.next/server/app/api/auth/v3/route.js +7 -7
- package/.next/server/app/api/auth/v3/route.js.nft.json +1 -1
- package/.next/server/app/api/hub/audit-log/route.js +6 -6
- package/.next/server/app/api/hub/audit-log/route.js.nft.json +1 -1
- package/.next/server/app/api/hub/auth/route.js +7 -7
- package/.next/server/app/api/hub/auth/route.js.nft.json +1 -1
- package/.next/server/app/api/hub/broadcast/route.js +6 -6
- package/.next/server/app/api/hub/broadcast/route.js.nft.json +1 -1
- package/.next/server/app/api/hub/events/route.js +6 -6
- package/.next/server/app/api/hub/events/route.js.nft.json +1 -1
- package/.next/server/app/api/hub/health/route.js +6 -6
- package/.next/server/app/api/hub/health/route.js.nft.json +1 -1
- package/.next/server/app/api/hub/inbox/route.js +6 -6
- package/.next/server/app/api/hub/inbox/route.js.nft.json +1 -1
- package/.next/server/app/api/hub/license/route.js +6 -6
- package/.next/server/app/api/hub/license/route.js.nft.json +1 -1
- package/.next/server/app/api/hub/messages/route.js +6 -6
- package/.next/server/app/api/hub/messages/route.js.nft.json +1 -1
- package/.next/server/app/api/hub/networks/route.js +6 -6
- package/.next/server/app/api/hub/networks/route.js.nft.json +1 -1
- package/.next/server/app/api/hub/nodes/route.js +6 -6
- package/.next/server/app/api/hub/nodes/route.js.nft.json +1 -1
- package/.next/server/app/api/hub/register/route.js +6 -6
- package/.next/server/app/api/hub/register/route.js.nft.json +1 -1
- package/.next/server/app/api/hub/send/route.js +6 -6
- package/.next/server/app/api/hub/send/route.js.nft.json +1 -1
- package/.next/server/app/api/hub/server-logs/route.js +6 -6
- package/.next/server/app/api/hub/server-logs/route.js.nft.json +1 -1
- package/.next/server/app/api/hub/servers/route/app-paths-manifest.json +3 -0
- package/.next/server/app/api/hub/servers/route/build-manifest.json +9 -0
- package/.next/server/app/api/hub/servers/route/server-reference-manifest.json +4 -0
- package/.next/server/app/api/hub/servers/route.js +7 -0
- package/.next/server/app/api/hub/servers/route.js.map +5 -0
- package/.next/server/app/api/hub/servers/route.js.nft.json +1 -0
- package/.next/server/app/api/hub/servers/route_client-reference-manifest.js +3 -0
- package/.next/server/app/api/hub/session/route.js +6 -6
- package/.next/server/app/api/hub/session/route.js.nft.json +1 -1
- package/.next/server/app/api/hub/stats/route.js +6 -6
- package/.next/server/app/api/hub/stats/route.js.nft.json +1 -1
- package/.next/server/app/api/hub/status/route.js +6 -6
- package/.next/server/app/api/hub/status/route.js.nft.json +1 -1
- package/.next/server/app/api/hub/task-events/route.js +6 -6
- package/.next/server/app/api/hub/task-events/route.js.nft.json +1 -1
- package/.next/server/app/api/hub/tasks/route.js +6 -6
- package/.next/server/app/api/hub/tasks/route.js.nft.json +1 -1
- package/.next/server/app/api/hub/tmux/route.js +6 -6
- package/.next/server/app/api/hub/tmux/route.js.nft.json +1 -1
- package/.next/server/app/api/hub/tokens/route.js +6 -6
- package/.next/server/app/api/hub/tokens/route.js.nft.json +1 -1
- package/.next/server/app/favicon.ico/route.js +6 -6
- package/.next/server/app/favicon.ico/route.js.nft.json +1 -1
- package/.next/server/app/index.html +2 -2
- package/.next/server/app/index.rsc +14 -14
- package/.next/server/app/index.segments/__PAGE__.segment.rsc +4 -4
- package/.next/server/app/index.segments/_full.segment.rsc +14 -14
- package/.next/server/app/index.segments/_head.segment.rsc +4 -4
- package/.next/server/app/index.segments/_index.segment.rsc +7 -7
- package/.next/server/app/index.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/login/page/build-manifest.json +5 -5
- package/.next/server/app/login/page/next-font-manifest.json +1 -1
- package/.next/server/app/login/page.js +13 -13
- package/.next/server/app/login/page.js.nft.json +1 -1
- package/.next/server/app/login/page_client-reference-manifest.js +1 -1
- package/.next/server/app/login.html +2 -2
- package/.next/server/app/login.rsc +14 -14
- package/.next/server/app/login.segments/_full.segment.rsc +14 -14
- package/.next/server/app/login.segments/_head.segment.rsc +4 -4
- package/.next/server/app/login.segments/_index.segment.rsc +7 -7
- package/.next/server/app/login.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/login.segments/login/__PAGE__.segment.rsc +4 -4
- package/.next/server/app/login.segments/login.segment.rsc +3 -3
- package/.next/server/app/logs/page/build-manifest.json +5 -5
- package/.next/server/app/logs/page/next-font-manifest.json +1 -1
- package/.next/server/app/logs/page.js +13 -13
- package/.next/server/app/logs/page.js.nft.json +1 -1
- package/.next/server/app/logs/page_client-reference-manifest.js +1 -1
- package/.next/server/app/logs.html +2 -2
- package/.next/server/app/logs.rsc +14 -14
- package/.next/server/app/logs.segments/_full.segment.rsc +14 -14
- package/.next/server/app/logs.segments/_head.segment.rsc +4 -4
- package/.next/server/app/logs.segments/_index.segment.rsc +7 -7
- package/.next/server/app/logs.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/logs.segments/logs/__PAGE__.segment.rsc +4 -4
- package/.next/server/app/logs.segments/logs.segment.rsc +3 -3
- package/.next/server/app/messages/page/build-manifest.json +5 -5
- package/.next/server/app/messages/page/next-font-manifest.json +1 -1
- package/.next/server/app/messages/page.js +13 -13
- package/.next/server/app/messages/page.js.nft.json +1 -1
- package/.next/server/app/messages/page_client-reference-manifest.js +1 -1
- package/.next/server/app/messages.html +2 -2
- package/.next/server/app/messages.rsc +14 -14
- package/.next/server/app/messages.segments/_full.segment.rsc +14 -14
- package/.next/server/app/messages.segments/_head.segment.rsc +4 -4
- package/.next/server/app/messages.segments/_index.segment.rsc +7 -7
- package/.next/server/app/messages.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/messages.segments/messages/__PAGE__.segment.rsc +4 -4
- package/.next/server/app/messages.segments/messages.segment.rsc +3 -3
- package/.next/server/app/node/page/build-manifest.json +5 -5
- package/.next/server/app/node/page/next-font-manifest.json +1 -1
- package/.next/server/app/node/page.js +13 -13
- package/.next/server/app/node/page.js.nft.json +1 -1
- package/.next/server/app/node/page_client-reference-manifest.js +1 -1
- package/.next/server/app/node.html +2 -2
- package/.next/server/app/node.rsc +14 -14
- package/.next/server/app/node.segments/_full.segment.rsc +14 -14
- package/.next/server/app/node.segments/_head.segment.rsc +4 -4
- package/.next/server/app/node.segments/_index.segment.rsc +7 -7
- package/.next/server/app/node.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/node.segments/node/__PAGE__.segment.rsc +4 -4
- package/.next/server/app/node.segments/node.segment.rsc +3 -3
- package/.next/server/app/nodes/page/build-manifest.json +5 -5
- package/.next/server/app/nodes/page/next-font-manifest.json +1 -1
- package/.next/server/app/nodes/page.js +13 -13
- package/.next/server/app/nodes/page.js.nft.json +1 -1
- package/.next/server/app/nodes/page_client-reference-manifest.js +1 -1
- package/.next/server/app/nodes.html +2 -2
- package/.next/server/app/nodes.rsc +14 -14
- package/.next/server/app/nodes.segments/_full.segment.rsc +14 -14
- package/.next/server/app/nodes.segments/_head.segment.rsc +4 -4
- package/.next/server/app/nodes.segments/_index.segment.rsc +7 -7
- package/.next/server/app/nodes.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/nodes.segments/nodes/__PAGE__.segment.rsc +4 -4
- package/.next/server/app/nodes.segments/nodes.segment.rsc +3 -3
- package/.next/server/app/page/build-manifest.json +5 -5
- package/.next/server/app/page/next-font-manifest.json +1 -1
- package/.next/server/app/page.js +13 -13
- package/.next/server/app/page.js.nft.json +1 -1
- package/.next/server/app/page_client-reference-manifest.js +1 -1
- package/.next/server/app/server-logs/page/build-manifest.json +5 -5
- package/.next/server/app/server-logs/page/next-font-manifest.json +1 -1
- package/.next/server/app/server-logs/page.js +13 -13
- package/.next/server/app/server-logs/page.js.nft.json +1 -1
- package/.next/server/app/server-logs/page_client-reference-manifest.js +1 -1
- package/.next/server/app/server-logs.html +2 -2
- package/.next/server/app/server-logs.rsc +14 -14
- package/.next/server/app/server-logs.segments/_full.segment.rsc +14 -14
- package/.next/server/app/server-logs.segments/_head.segment.rsc +4 -4
- package/.next/server/app/server-logs.segments/_index.segment.rsc +7 -7
- package/.next/server/app/server-logs.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/server-logs.segments/server-logs/__PAGE__.segment.rsc +4 -4
- package/.next/server/app/server-logs.segments/server-logs.segment.rsc +3 -3
- package/.next/server/app/settings/networks/page/build-manifest.json +5 -5
- package/.next/server/app/settings/networks/page/next-font-manifest.json +1 -1
- package/.next/server/app/settings/networks/page.js +13 -13
- package/.next/server/app/settings/networks/page.js.nft.json +1 -1
- package/.next/server/app/settings/networks/page_client-reference-manifest.js +1 -1
- package/.next/server/app/settings/networks.html +2 -2
- package/.next/server/app/settings/networks.rsc +14 -14
- package/.next/server/app/settings/networks.segments/_full.segment.rsc +14 -14
- package/.next/server/app/settings/networks.segments/_head.segment.rsc +4 -4
- package/.next/server/app/settings/networks.segments/_index.segment.rsc +7 -7
- package/.next/server/app/settings/networks.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/settings/networks.segments/settings/networks/__PAGE__.segment.rsc +4 -4
- package/.next/server/app/settings/networks.segments/settings/networks.segment.rsc +3 -3
- package/.next/server/app/settings/networks.segments/settings.segment.rsc +3 -3
- package/.next/server/app/settings/page/build-manifest.json +5 -5
- package/.next/server/app/settings/page/next-font-manifest.json +1 -1
- package/.next/server/app/settings/page.js +13 -13
- package/.next/server/app/settings/page.js.nft.json +1 -1
- package/.next/server/app/settings/page_client-reference-manifest.js +1 -1
- package/.next/server/app/settings/tokens/page/build-manifest.json +5 -5
- package/.next/server/app/settings/tokens/page/next-font-manifest.json +1 -1
- package/.next/server/app/settings/tokens/page.js +13 -13
- package/.next/server/app/settings/tokens/page.js.nft.json +1 -1
- package/.next/server/app/settings/tokens/page_client-reference-manifest.js +1 -1
- package/.next/server/app/settings/tokens.html +2 -2
- package/.next/server/app/settings/tokens.rsc +14 -14
- package/.next/server/app/settings/tokens.segments/_full.segment.rsc +14 -14
- package/.next/server/app/settings/tokens.segments/_head.segment.rsc +4 -4
- package/.next/server/app/settings/tokens.segments/_index.segment.rsc +7 -7
- package/.next/server/app/settings/tokens.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/settings/tokens.segments/settings/tokens/__PAGE__.segment.rsc +4 -4
- package/.next/server/app/settings/tokens.segments/settings/tokens.segment.rsc +3 -3
- package/.next/server/app/settings/tokens.segments/settings.segment.rsc +3 -3
- package/.next/server/app/settings.html +2 -2
- package/.next/server/app/settings.rsc +14 -14
- package/.next/server/app/settings.segments/_full.segment.rsc +14 -14
- package/.next/server/app/settings.segments/_head.segment.rsc +4 -4
- package/.next/server/app/settings.segments/_index.segment.rsc +7 -7
- package/.next/server/app/settings.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/settings.segments/settings/__PAGE__.segment.rsc +4 -4
- package/.next/server/app/settings.segments/settings.segment.rsc +3 -3
- package/.next/server/app/tasks/[id]/page/build-manifest.json +5 -5
- package/.next/server/app/tasks/[id]/page/next-font-manifest.json +1 -1
- package/.next/server/app/tasks/[id]/page.js +13 -13
- package/.next/server/app/tasks/[id]/page.js.nft.json +1 -1
- package/.next/server/app/tasks/[id]/page_client-reference-manifest.js +1 -1
- package/.next/server/app/tasks/page/build-manifest.json +5 -5
- package/.next/server/app/tasks/page/next-font-manifest.json +1 -1
- package/.next/server/app/tasks/page.js +13 -13
- package/.next/server/app/tasks/page.js.nft.json +1 -1
- package/.next/server/app/tasks/page_client-reference-manifest.js +1 -1
- package/.next/server/app/tasks.html +2 -2
- package/.next/server/app/tasks.rsc +14 -14
- package/.next/server/app/tasks.segments/_full.segment.rsc +14 -14
- package/.next/server/app/tasks.segments/_head.segment.rsc +4 -4
- package/.next/server/app/tasks.segments/_index.segment.rsc +7 -7
- package/.next/server/app/tasks.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/tasks.segments/tasks/__PAGE__.segment.rsc +4 -4
- package/.next/server/app/tasks.segments/tasks.segment.rsc +3 -3
- package/.next/server/app-paths-manifest.json +1 -0
- package/.next/server/chunks/00jm_next_04f3gac._.js +10 -0
- package/.next/server/chunks/00jm_next_04f3gac._.js.map +1 -0
- package/.next/server/chunks/00jm_next_dist_esm_build_templates_app-route_02f430o.js +3 -0
- package/.next/server/chunks/00jm_next_dist_esm_build_templates_app-route_02f430o.js.map +1 -0
- package/.next/server/chunks/0ci9_nt-network-dashboard__next-internal_server_app_api_auth_v3_route_actions_0f5nbzr.js +3 -0
- package/.next/server/chunks/0ci9_nt-network-dashboard__next-internal_server_app_favicon_ico_route_actions_0t0eu9r.js +3 -0
- package/.next/server/chunks/0ykm__next-internal_server_app_api_anet_config_route_actions_0a~v55_.js +3 -0
- package/.next/server/chunks/0ykm__next-internal_server_app_api_auth_login_route_actions_0xnxfs4.js +3 -0
- package/.next/server/chunks/0ykm__next-internal_server_app_api_auth_logout_route_actions_0p8p0rn.js +3 -0
- package/.next/server/chunks/0ykm__next-internal_server_app_api_hub_audit-log_route_actions_06uquwi.js +3 -0
- package/.next/server/chunks/0ykm__next-internal_server_app_api_hub_auth_route_actions_0f_y1ey.js +3 -0
- package/.next/server/chunks/0ykm__next-internal_server_app_api_hub_broadcast_route_actions_0ao3j43.js +3 -0
- package/.next/server/chunks/0ykm__next-internal_server_app_api_hub_events_route_actions_0_5ndld.js +3 -0
- package/.next/server/chunks/0ykm__next-internal_server_app_api_hub_health_route_actions_0mpzl74.js +3 -0
- package/.next/server/chunks/0ykm__next-internal_server_app_api_hub_inbox_route_actions_0stoyto.js +3 -0
- package/.next/server/chunks/0ykm__next-internal_server_app_api_hub_license_route_actions_0a4.fuh.js +3 -0
- package/.next/server/chunks/0ykm__next-internal_server_app_api_hub_messages_route_actions_059rw1o.js +3 -0
- package/.next/server/chunks/0ykm__next-internal_server_app_api_hub_networks_route_actions_03sehpn.js +3 -0
- package/.next/server/chunks/0ykm__next-internal_server_app_api_hub_nodes_route_actions_11fbp28.js +3 -0
- package/.next/server/chunks/0ykm__next-internal_server_app_api_hub_register_route_actions_0l.d7~n.js +3 -0
- package/.next/server/chunks/0ykm__next-internal_server_app_api_hub_send_route_actions_0.p82vy.js +3 -0
- package/.next/server/chunks/0ykm__next-internal_server_app_api_hub_server-logs_route_actions_05~c5lb.js +3 -0
- package/.next/server/chunks/0ykm__next-internal_server_app_api_hub_servers_route_actions_08-m-cs.js +3 -0
- package/.next/server/chunks/0ykm__next-internal_server_app_api_hub_session_route_actions_0b9ef2i.js +3 -0
- package/.next/server/chunks/0ykm__next-internal_server_app_api_hub_stats_route_actions_03u65u0.js +3 -0
- package/.next/server/chunks/0ykm__next-internal_server_app_api_hub_status_route_actions_0_71ear.js +3 -0
- package/.next/server/chunks/0ykm__next-internal_server_app_api_hub_task-events_route_actions_07md_ee.js +3 -0
- package/.next/server/chunks/0ykm__next-internal_server_app_api_hub_tasks_route_actions_0er3uvk.js +3 -0
- package/.next/server/chunks/0ykm__next-internal_server_app_api_hub_tmux_route_actions_0o_1-8u.js +3 -0
- package/.next/server/chunks/0ykm__next-internal_server_app_api_hub_tokens_route_actions_09doluz.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__0-2le8-._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__0-2le8-._.js.map +1 -0
- package/.next/server/chunks/[root-of-the-server]__0-g~15e._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__0-g~15e._.js.map +1 -0
- package/.next/server/chunks/[root-of-the-server]__00194.t._.js +3 -0
- package/.next/server/chunks/{[root-of-the-server]__03ueci3._.js.map → [root-of-the-server]__00194.t._.js.map} +1 -1
- package/.next/server/chunks/[root-of-the-server]__02p2n3n._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__02p2n3n._.js.map +1 -0
- package/.next/server/chunks/[root-of-the-server]__02y-i-p._.js +6 -0
- package/.next/server/chunks/[root-of-the-server]__02y-i-p._.js.map +1 -0
- package/.next/server/chunks/[root-of-the-server]__043tnx2._.js +3 -0
- package/.next/server/chunks/{[root-of-the-server]__0o4qfn9._.js.map → [root-of-the-server]__043tnx2._.js.map} +1 -1
- package/.next/server/chunks/[root-of-the-server]__04z62zk._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__04z62zk._.js.map +1 -0
- package/.next/server/chunks/[root-of-the-server]__06p6kkp._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__06p6kkp._.js.map +1 -0
- package/.next/server/chunks/[root-of-the-server]__07ztet2._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__07ztet2._.js.map +1 -0
- package/.next/server/chunks/[root-of-the-server]__08uyvdq._.js +20 -0
- package/.next/server/chunks/[root-of-the-server]__08uyvdq._.js.map +1 -0
- package/.next/server/chunks/[root-of-the-server]__0b7v51y._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__0b7v51y._.js.map +1 -0
- package/.next/server/chunks/[root-of-the-server]__0e3ucl1._.js +3 -0
- package/.next/server/chunks/{[root-of-the-server]__0rg9ifx._.js.map → [root-of-the-server]__0e3ucl1._.js.map} +1 -1
- package/.next/server/chunks/[root-of-the-server]__0e6yail._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__0e6yail._.js.map +1 -0
- package/.next/server/chunks/[root-of-the-server]__0gx2_6a._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__0gx2_6a._.js.map +1 -0
- package/.next/server/chunks/[root-of-the-server]__0hcnyp.._.js +3 -0
- package/.next/server/chunks/{[root-of-the-server]__0o29v8c._.js.map → [root-of-the-server]__0hcnyp.._.js.map} +1 -1
- package/.next/server/chunks/[root-of-the-server]__0hg3_8r._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__0hg3_8r._.js.map +1 -0
- package/.next/server/chunks/[root-of-the-server]__0mxw4vb._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__0mxw4vb._.js.map +1 -0
- package/.next/server/chunks/[root-of-the-server]__0mzopco._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__0mzopco._.js.map +1 -0
- package/.next/server/chunks/[root-of-the-server]__0o45a4q._.js +3 -0
- package/.next/server/chunks/{[root-of-the-server]__0p6tutt._.js.map → [root-of-the-server]__0o45a4q._.js.map} +1 -1
- package/.next/server/chunks/[root-of-the-server]__0q-teo6._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__0q-teo6._.js.map +1 -0
- package/.next/server/chunks/[root-of-the-server]__0qcxxzf._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__0qcxxzf._.js.map +1 -0
- package/.next/server/chunks/[root-of-the-server]__0rovr5-._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__0rovr5-._.js.map +1 -0
- package/.next/server/chunks/[root-of-the-server]__0tx8s8i._.js +3 -0
- package/.next/server/chunks/{[root-of-the-server]__0~h2uqi._.js.map → [root-of-the-server]__0tx8s8i._.js.map} +1 -1
- package/.next/server/chunks/[root-of-the-server]__0xtp-et._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__0xtp-et._.js.map +1 -0
- package/.next/server/chunks/[root-of-the-server]__10pvabe._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__10pvabe._.js.map +1 -0
- package/.next/server/chunks/[root-of-the-server]__10t11zq._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__10t11zq._.js.map +1 -0
- package/.next/server/chunks/[root-of-the-server]__12r~omy._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__12r~omy._.js.map +1 -0
- package/.next/server/chunks/[root-of-the-server]__1389~cs._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__1389~cs._.js.map +1 -0
- package/.next/server/chunks/[root-of-the-server]__13n8t..._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__13n8t..._.js.map +1 -0
- package/.next/server/chunks/[turbopack]_runtime.js +1 -1
- package/.next/server/chunks/ssr/{node_modules_0r_.s40._.js → 00jm_03rn9vn._.js} +2 -2
- package/.next/server/chunks/ssr/00jm_03rn9vn._.js.map +1 -0
- package/.next/server/chunks/ssr/{node_modules_09w7yel._.js → 00jm_059ns68._.js} +3 -3
- package/.next/server/chunks/ssr/00jm_059ns68._.js.map +1 -0
- package/.next/server/chunks/ssr/00jm_09ae-q0._.js +3 -0
- package/.next/server/chunks/ssr/00jm_09ae-q0._.js.map +1 -0
- package/.next/server/chunks/ssr/00jm_0j7__z.._.js +3 -0
- package/.next/server/chunks/ssr/00jm_0j7__z.._.js.map +1 -0
- package/.next/server/chunks/ssr/00jm_next_01-0urn._.js +6 -0
- package/.next/server/chunks/ssr/00jm_next_01-0urn._.js.map +1 -0
- package/.next/server/chunks/ssr/00jm_next_dist_05rlh5d._.js +6 -0
- package/.next/server/chunks/ssr/00jm_next_dist_05rlh5d._.js.map +1 -0
- package/.next/server/chunks/ssr/00jm_next_dist_client_components_0gkudcq._.js +3 -0
- package/.next/server/chunks/ssr/00jm_next_dist_client_components_0gkudcq._.js.map +1 -0
- package/.next/server/chunks/ssr/00jm_next_dist_client_components_builtin_forbidden_0ecus3e.js +3 -0
- package/.next/server/chunks/ssr/00jm_next_dist_client_components_builtin_forbidden_0ecus3e.js.map +1 -0
- package/.next/server/chunks/ssr/00jm_next_dist_client_components_builtin_global-error_07n8pg2.js +3 -0
- package/.next/server/chunks/ssr/00jm_next_dist_client_components_builtin_global-error_07n8pg2.js.map +1 -0
- package/.next/server/chunks/ssr/00jm_next_dist_client_components_builtin_unauthorized_0r0uq4j.js +3 -0
- package/.next/server/chunks/ssr/00jm_next_dist_client_components_builtin_unauthorized_0r0uq4j.js.map +1 -0
- package/.next/server/chunks/ssr/{node_modules_next_dist_esm_build_templates_app-page_002l7yi.js → 00jm_next_dist_esm_build_templates_app-page_0..ddwm.js} +3 -3
- package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_0..ddwm.js.map +1 -0
- package/.next/server/chunks/ssr/{node_modules_next_dist_esm_build_templates_app-page_0qm1-a1.js → 00jm_next_dist_esm_build_templates_app-page_02bxi6j.js} +3 -3
- package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_02bxi6j.js.map +1 -0
- package/.next/server/chunks/ssr/{node_modules_next_dist_esm_build_templates_app-page_02suzhc.js → 00jm_next_dist_esm_build_templates_app-page_05oassd.js} +3 -3
- package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_05oassd.js.map +1 -0
- package/.next/server/chunks/ssr/{node_modules_next_dist_esm_build_templates_app-page_0dm~kj8.js → 00jm_next_dist_esm_build_templates_app-page_05vxtby.js} +3 -3
- package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_05vxtby.js.map +1 -0
- package/.next/server/chunks/ssr/{node_modules_next_dist_esm_build_templates_app-page_0uccf9z.js → 00jm_next_dist_esm_build_templates_app-page_05~eml4.js} +3 -3
- package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_05~eml4.js.map +1 -0
- package/.next/server/chunks/ssr/{node_modules_next_dist_esm_build_templates_app-page_0l-fh0i.js → 00jm_next_dist_esm_build_templates_app-page_0_-g_q2.js} +3 -3
- package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_0_-g_q2.js.map +1 -0
- package/.next/server/chunks/ssr/{node_modules_next_dist_esm_build_templates_app-page_0uv6jyc.js → 00jm_next_dist_esm_build_templates_app-page_0_ec0xu.js} +3 -3
- package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_0_ec0xu.js.map +1 -0
- package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_0czb6wz.js +4 -0
- package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_0czb6wz.js.map +1 -0
- package/.next/server/chunks/ssr/{node_modules_next_dist_esm_build_templates_app-page_13s07li.js → 00jm_next_dist_esm_build_templates_app-page_0e-cn.p.js} +3 -3
- package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_0e-cn.p.js.map +1 -0
- package/.next/server/chunks/ssr/{node_modules_next_dist_esm_build_templates_app-page_0o9vt1n.js → 00jm_next_dist_esm_build_templates_app-page_0k8_sr8.js} +3 -3
- package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_0k8_sr8.js.map +1 -0
- package/.next/server/chunks/ssr/{node_modules_next_dist_esm_build_templates_app-page_0nsg22r.js → 00jm_next_dist_esm_build_templates_app-page_0lt_3bw.js} +3 -3
- package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_0lt_3bw.js.map +1 -0
- package/.next/server/chunks/ssr/{node_modules_next_dist_esm_build_templates_app-page_0d2yq5t.js → 00jm_next_dist_esm_build_templates_app-page_0uyh3yt.js} +3 -3
- package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_0uyh3yt.js.map +1 -0
- package/.next/server/chunks/ssr/{node_modules_next_dist_esm_build_templates_app-page_0foejvu.js → 00jm_next_dist_esm_build_templates_app-page_0v-a2ps.js} +3 -3
- package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_0v-a2ps.js.map +1 -0
- package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_12.4r9~.js +4 -0
- package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_12.4r9~.js.map +1 -0
- package/.next/server/chunks/ssr/{node_modules_next_dist_esm_build_templates_app-page_07uu-xq.js → 00jm_next_dist_esm_build_templates_app-page_13mqkay.js} +3 -3
- package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_13mqkay.js.map +1 -0
- package/.next/server/chunks/ssr/0dwh_ent-network-dashboard__next-internal_server_app_server-logs_page_actions_0hkk815.js +3 -0
- package/.next/server/chunks/ssr/0yas_gent-network-dashboard__next-internal_server_app__not-found_page_actions_0u.f-rz.js +3 -0
- package/.next/server/chunks/ssr/0yas_gent-network-dashboard__next-internal_server_app_tasks_[id]_page_actions_0r3~lho.js +3 -0
- package/.next/server/chunks/ssr/0ykm__next-internal_server_app__global-error_page_actions_100fxls.js +3 -0
- package/.next/server/chunks/ssr/0ykm__next-internal_server_app_settings_networks_page_actions_0jgy57m.js +3 -0
- package/.next/server/chunks/ssr/0ykm__next-internal_server_app_settings_tokens_page_actions_0l5h.k~.js +3 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__030vg4n._.js +3 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__030vg4n._.js.map +1 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__03b.f76._.js +3 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__03b.f76._.js.map +1 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__063~dul._.js +3 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__063~dul._.js.map +1 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__07io.d8._.js +3 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__07io.d8._.js.map +1 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__08d6lp4._.js +3 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__08d6lp4._.js.map +1 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__09f1wn6._.js +3 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__09f1wn6._.js.map +1 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__0c4xtkg._.js +3 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__0c4xtkg._.js.map +1 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__0erfzjn._.js +3 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__0erfzjn._.js.map +1 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__0ezjwje._.js +3 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__0ezjwje._.js.map +1 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__0fhoq8i._.js +3 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__0fhoq8i._.js.map +1 -0
- package/.next/server/chunks/ssr/{[root-of-the-server]__08qr2ji._.js → [root-of-the-server]__0gc.4uk._.js} +3 -3
- package/.next/server/chunks/ssr/[root-of-the-server]__0gc.4uk._.js.map +1 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__0h_p~-4._.js +19 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__0h_p~-4._.js.map +1 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__0jdr1e5._.js +3 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__0jdr1e5._.js.map +1 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__0lw16mu._.js +3 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__0lw16mu._.js.map +1 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__0mjly~-._.js +33 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__0mjly~-._.js.map +1 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__0nw~zhp._.js +3 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__0nw~zhp._.js.map +1 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__0p-95r_._.js +3 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__0p-95r_._.js.map +1 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__0u5aqkk._.js +8 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__0u5aqkk._.js.map +1 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__0ue5.fy._.js +3 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__0ue5.fy._.js.map +1 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__0uggxvx._.js +3 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__0uggxvx._.js.map +1 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__0zjk5ro._.js +3 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__0zjk5ro._.js.map +1 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__0zz3v7a._.js +3 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__0zz3v7a._.js.map +1 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__0~y12ef._.js +3 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__0~y12ef._.js.map +1 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__129sc_9._.js +3 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__129sc_9._.js.map +1 -0
- package/.next/server/chunks/ssr/[turbopack]_runtime.js +1 -1
- package/.next/server/chunks/ssr/agent-network-dashboard_09kk21a._.js +3 -0
- package/.next/server/chunks/ssr/agent-network-dashboard_09kk21a._.js.map +1 -0
- package/.next/server/chunks/ssr/agent-network-dashboard__next-internal_server_app_admin_page_actions_0i~.x~j.js +3 -0
- package/.next/server/chunks/ssr/agent-network-dashboard__next-internal_server_app_login_page_actions_0frwl15.js +3 -0
- package/.next/server/chunks/ssr/agent-network-dashboard__next-internal_server_app_logs_page_actions_0xa2ox_.js +3 -0
- package/.next/server/chunks/ssr/agent-network-dashboard__next-internal_server_app_messages_page_actions_10j3tg4.js +3 -0
- package/.next/server/chunks/ssr/agent-network-dashboard__next-internal_server_app_node_page_actions_0sl4ntd.js +3 -0
- package/.next/server/chunks/ssr/agent-network-dashboard__next-internal_server_app_nodes_page_actions_0cpgkfs.js +3 -0
- package/.next/server/chunks/ssr/agent-network-dashboard__next-internal_server_app_page_actions_08nuo36.js +3 -0
- package/.next/server/chunks/ssr/agent-network-dashboard__next-internal_server_app_settings_page_actions_0iv.lmk.js +3 -0
- package/.next/server/chunks/ssr/agent-network-dashboard__next-internal_server_app_tasks_page_actions_08c7qlx.js +3 -0
- package/.next/server/chunks/ssr/agent-network-dashboard__next-internal_server_app_tasks_page_actions_08c7qlx.js.map +1 -0
- package/.next/server/chunks/ssr/agent-network-dashboard_app_01jhlxz._.js +3 -0
- package/.next/server/chunks/ssr/agent-network-dashboard_app_01jhlxz._.js.map +1 -0
- package/.next/server/chunks/ssr/agent-network-dashboard_app_057q.ne._.js +3 -0
- package/.next/server/chunks/ssr/agent-network-dashboard_app_057q.ne._.js.map +1 -0
- package/.next/server/chunks/ssr/agent-network-dashboard_app_09d29my._.js +3 -0
- package/.next/server/chunks/ssr/agent-network-dashboard_app_09d29my._.js.map +1 -0
- package/.next/server/chunks/ssr/agent-network-dashboard_app_0_d45-d._.js +3 -0
- package/.next/server/chunks/ssr/agent-network-dashboard_app_0_d45-d._.js.map +1 -0
- package/.next/server/chunks/ssr/agent-network-dashboard_app_0i3759l._.js +3 -0
- package/.next/server/chunks/ssr/agent-network-dashboard_app_0i3759l._.js.map +1 -0
- package/.next/server/chunks/ssr/{app_0izi28j._.js → agent-network-dashboard_app_0xgney8._.js} +2 -2
- package/.next/server/chunks/ssr/agent-network-dashboard_app_0xgney8._.js.map +1 -0
- package/.next/server/chunks/ssr/{app_0_agk0r._.js → agent-network-dashboard_app_10hjgv4._.js} +2 -2
- package/.next/server/chunks/ssr/agent-network-dashboard_app_10hjgv4._.js.map +1 -0
- package/.next/server/chunks/ssr/{app_0.zbtn5._.js → agent-network-dashboard_app_1153xeb._.js} +2 -2
- package/.next/server/chunks/ssr/agent-network-dashboard_app_1153xeb._.js.map +1 -0
- package/.next/server/chunks/ssr/{app_04n78pr._.js → agent-network-dashboard_app_12l4oto._.js} +2 -2
- package/.next/server/chunks/ssr/agent-network-dashboard_app_12l4oto._.js.map +1 -0
- package/.next/server/chunks/ssr/{app_components_08ys5y3._.js → agent-network-dashboard_app_components_0mvyi-4._.js} +3 -3
- package/.next/server/chunks/ssr/agent-network-dashboard_app_components_0mvyi-4._.js.map +1 -0
- package/.next/server/chunks/ssr/{app_server-logs_page_tsx_0_kpp1p._.js → agent-network-dashboard_app_server-logs_page_tsx_0dg.l_8._.js} +2 -2
- package/.next/server/chunks/ssr/agent-network-dashboard_app_server-logs_page_tsx_0dg.l_8._.js.map +1 -0
- package/.next/server/chunks/ssr/agent-network-dashboard_app_tasks_page_tsx_0mwxy4z._.js +3 -0
- package/.next/server/chunks/ssr/agent-network-dashboard_app_tasks_page_tsx_0mwxy4z._.js.map +1 -0
- package/.next/server/middleware-build-manifest.js +8 -8
- package/.next/server/middleware.js +3 -3
- package/.next/server/middleware.js.nft.json +1 -1
- package/.next/server/next-font-manifest.js +1 -1
- package/.next/server/next-font-manifest.json +14 -14
- package/.next/server/pages/404.html +2 -2
- package/.next/server/pages/500.html +1 -1
- package/.next/server/server-reference-manifest.js +1 -1
- package/.next/server/server-reference-manifest.json +1 -1
- package/.next/static/chunks/0-7iowzu4.798.js +1 -0
- package/.next/static/chunks/{0gtbwcilfu6b7.js → 0.66f3.rtcybb.js} +1 -1
- package/.next/static/chunks/02t5jr4shh.hy.js +1 -0
- package/.next/static/chunks/039-b.v_9-_rm.js +1 -0
- package/.next/static/chunks/05oi25hh7b81r.js +31 -0
- package/.next/static/chunks/07~8sx3_5uiox.js +1 -0
- package/.next/static/chunks/09nd.t_hd.y6t.css +2 -0
- package/.next/static/chunks/{0pqt~8bl3ukh4.js → 0_pxg.4pebw__.js} +2 -2
- package/.next/static/chunks/0_qfg5s5uzs7..js +7 -0
- package/.next/static/chunks/0b8wnt4put-5n.js +2 -0
- package/.next/static/chunks/0elalb9n_.~di.js +1 -0
- package/.next/static/chunks/{01xlw8hd842-c.js → 0eov~nkwaf-qa.js} +1 -1
- package/.next/static/chunks/0j_q__o8p6g83.js +1 -0
- package/.next/static/chunks/0jl6_w50zh4l5.js +1 -0
- package/.next/static/chunks/{0w1zwt8kq_7nb.js → 0ku0fjqlm9mca.js} +1 -1
- package/.next/static/chunks/0nguf50i8enay.js +1 -0
- package/.next/static/chunks/{0-hlcuoemhe7w.js → 0pl7l_.2im.j0.js} +2 -2
- package/.next/static/chunks/0r4q73.-1bkyl.js +1 -0
- package/.next/static/chunks/0r_c8eccg3z2o.js +1 -0
- package/.next/static/chunks/0tvn2l1pc.h65.js +1 -0
- package/.next/static/chunks/0u3b93reo9xci.js +1 -0
- package/.next/static/chunks/0v5rym8-nhetp.js +1 -0
- package/.next/static/chunks/10oi7l-tycgl9.js +1 -0
- package/.next/static/chunks/11.s_mjm-snyc.js +1 -0
- package/.next/static/chunks/11uk1izuv3~0t.js +1 -0
- package/.next/static/chunks/{turbopack-01f1xs~cq_~si.js → turbopack-0.7dvsf9rllt0.js} +1 -1
- package/.next/trace +2 -2
- package/.next/trace-build +1 -1
- package/.next/types/routes.d.ts +2 -1
- package/.next/types/validator.ts +9 -0
- package/app/api/hub/servers/route.ts +39 -0
- package/app/components/AppShell.tsx +2 -0
- package/app/components/ChatPopover.tsx +6 -6
- package/app/components/ServersDrawer.tsx +206 -0
- package/app/components/TaskChatPanel.tsx +39 -39
- package/app/components/TopoGraph.tsx +726 -161
- package/app/components/types.ts +7 -0
- package/app/lib/vendorIdentity.ts +145 -0
- package/app/page.tsx +18 -1
- package/package.json +1 -1
- package/scripts/chat-popover-test.mjs +2 -0
- package/scripts/chat-theme-test.mjs +98 -0
- package/scripts/servers-drawer-live-test.mjs +96 -0
- package/scripts/topo-arrow-tier-test.mjs +61 -0
- package/scripts/topo-chat-focus-ring-test.mjs +77 -0
- package/scripts/topo-click-ripple-test.mjs +66 -0
- package/scripts/topo-group-count-test.mjs +63 -0
- package/scripts/topo-group-hover-test.mjs +82 -0
- package/scripts/topo-groupbox-test.mjs +118 -0
- package/scripts/topo-label-scale-test.mjs +78 -0
- package/scripts/topo-layout-test.mjs +1 -0
- package/scripts/topo-offline-dim-test.mjs +70 -0
- package/scripts/topo-overlap-test.mjs +137 -0
- package/scripts/topo-p0round-test.mjs +166 -0
- package/scripts/topo-pan-cursor-test.mjs +62 -0
- package/scripts/topo-rename-test.mjs +107 -0
- package/scripts/topo-vendor-test.mjs +97 -0
- package/scripts/topo-zoom-keys-test.mjs +89 -0
- package/.next/build/chunks/[turbopack-node]_transforms_postcss_ts_06e.r3r._.js +0 -13
- package/.next/build/chunks/node_modules_13sb.px._.js.map +0 -47
- package/.next/server/chunks/[root-of-the-server]__0-mykaf._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__0-mykaf._.js.map +0 -1
- package/.next/server/chunks/[root-of-the-server]__0.d_kqy._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__0.d_kqy._.js.map +0 -1
- package/.next/server/chunks/[root-of-the-server]__02pocyg._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__02pocyg._.js.map +0 -1
- package/.next/server/chunks/[root-of-the-server]__03ueci3._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__04aud7x._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__04aud7x._.js.map +0 -1
- package/.next/server/chunks/[root-of-the-server]__05fnt3n._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__05fnt3n._.js.map +0 -1
- package/.next/server/chunks/[root-of-the-server]__077tsd.._.js +0 -20
- package/.next/server/chunks/[root-of-the-server]__077tsd.._.js.map +0 -1
- package/.next/server/chunks/[root-of-the-server]__08wy1jr._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__08wy1jr._.js.map +0 -1
- package/.next/server/chunks/[root-of-the-server]__0adhu1m._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__0adhu1m._.js.map +0 -1
- package/.next/server/chunks/[root-of-the-server]__0aqv02v._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__0aqv02v._.js.map +0 -1
- package/.next/server/chunks/[root-of-the-server]__0cawhfq._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__0cawhfq._.js.map +0 -1
- package/.next/server/chunks/[root-of-the-server]__0d_-_k.._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__0d_-_k.._.js.map +0 -1
- package/.next/server/chunks/[root-of-the-server]__0f6bxfl._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__0f6bxfl._.js.map +0 -1
- package/.next/server/chunks/[root-of-the-server]__0h15edq._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__0h15edq._.js.map +0 -1
- package/.next/server/chunks/[root-of-the-server]__0k.vegl._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__0k.vegl._.js.map +0 -1
- package/.next/server/chunks/[root-of-the-server]__0kltbce._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__0kltbce._.js.map +0 -1
- package/.next/server/chunks/[root-of-the-server]__0mn04fw._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__0mn04fw._.js.map +0 -1
- package/.next/server/chunks/[root-of-the-server]__0o29v8c._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__0o4qfn9._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__0o7ya7r._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__0o7ya7r._.js.map +0 -1
- package/.next/server/chunks/[root-of-the-server]__0p3fo6l._.js +0 -6
- package/.next/server/chunks/[root-of-the-server]__0p3fo6l._.js.map +0 -1
- package/.next/server/chunks/[root-of-the-server]__0p6tutt._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__0pn3wsx._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__0pn3wsx._.js.map +0 -1
- package/.next/server/chunks/[root-of-the-server]__0rg9ifx._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__0x.-194._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__0x.-194._.js.map +0 -1
- package/.next/server/chunks/[root-of-the-server]__0x.a_yh._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__0x.a_yh._.js.map +0 -1
- package/.next/server/chunks/[root-of-the-server]__0~h2uqi._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__139~d6a._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__139~d6a._.js.map +0 -1
- package/.next/server/chunks/_next-internal_server_app_api_anet_config_route_actions_0xzy73j.js +0 -3
- package/.next/server/chunks/_next-internal_server_app_api_auth_login_route_actions_0zukc38.js +0 -3
- package/.next/server/chunks/_next-internal_server_app_api_auth_logout_route_actions_0fm~3ij.js +0 -3
- package/.next/server/chunks/_next-internal_server_app_api_auth_v3_route_actions_0ndzs5l.js +0 -3
- package/.next/server/chunks/_next-internal_server_app_api_hub_audit-log_route_actions_11k8fqt.js +0 -3
- package/.next/server/chunks/_next-internal_server_app_api_hub_auth_route_actions_0gs7ttk.js +0 -3
- package/.next/server/chunks/_next-internal_server_app_api_hub_broadcast_route_actions_0ads-kd.js +0 -3
- package/.next/server/chunks/_next-internal_server_app_api_hub_events_route_actions_0opktby.js +0 -3
- package/.next/server/chunks/_next-internal_server_app_api_hub_health_route_actions_0tzzt~x.js +0 -3
- package/.next/server/chunks/_next-internal_server_app_api_hub_inbox_route_actions_0xvslrg.js +0 -3
- package/.next/server/chunks/_next-internal_server_app_api_hub_license_route_actions_0i3tlr3.js +0 -3
- package/.next/server/chunks/_next-internal_server_app_api_hub_messages_route_actions_08-gi-s.js +0 -3
- package/.next/server/chunks/_next-internal_server_app_api_hub_networks_route_actions_02vejq2.js +0 -3
- package/.next/server/chunks/_next-internal_server_app_api_hub_nodes_route_actions_0nx8ryn.js +0 -3
- package/.next/server/chunks/_next-internal_server_app_api_hub_register_route_actions_086wi_3.js +0 -3
- package/.next/server/chunks/_next-internal_server_app_api_hub_send_route_actions_0-ga_ug.js +0 -3
- package/.next/server/chunks/_next-internal_server_app_api_hub_server-logs_route_actions_00euexv.js +0 -3
- package/.next/server/chunks/_next-internal_server_app_api_hub_session_route_actions_041wa62.js +0 -3
- package/.next/server/chunks/_next-internal_server_app_api_hub_stats_route_actions_1242~od.js +0 -3
- package/.next/server/chunks/_next-internal_server_app_api_hub_status_route_actions_0aml09a.js +0 -3
- package/.next/server/chunks/_next-internal_server_app_api_hub_task-events_route_actions_02v1tmm.js +0 -3
- package/.next/server/chunks/_next-internal_server_app_api_hub_tasks_route_actions_0nl77v4.js +0 -3
- package/.next/server/chunks/_next-internal_server_app_api_hub_tmux_route_actions_0u~aaza.js +0 -3
- package/.next/server/chunks/_next-internal_server_app_api_hub_tokens_route_actions_09hzf_1.js +0 -3
- package/.next/server/chunks/_next-internal_server_app_favicon_ico_route_actions_095lj93.js +0 -3
- package/.next/server/chunks/node_modules_next_11synfn._.js +0 -10
- package/.next/server/chunks/node_modules_next_11synfn._.js.map +0 -1
- package/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_0yubv2d.js +0 -3
- package/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_0yubv2d.js.map +0 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__014uja_._.js +0 -3
- package/.next/server/chunks/ssr/[root-of-the-server]__014uja_._.js.map +0 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__02hi65f._.js +0 -3
- package/.next/server/chunks/ssr/[root-of-the-server]__02hi65f._.js.map +0 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__02xqa5z._.js +0 -3
- package/.next/server/chunks/ssr/[root-of-the-server]__02xqa5z._.js.map +0 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__04ph1de._.js +0 -3
- package/.next/server/chunks/ssr/[root-of-the-server]__04ph1de._.js.map +0 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__05wc5-z._.js +0 -3
- package/.next/server/chunks/ssr/[root-of-the-server]__05wc5-z._.js.map +0 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__06-2p1a._.js +0 -33
- package/.next/server/chunks/ssr/[root-of-the-server]__06-2p1a._.js.map +0 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__08qr2ji._.js.map +0 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__09l8xaa._.js +0 -3
- package/.next/server/chunks/ssr/[root-of-the-server]__09l8xaa._.js.map +0 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__09z7o2x._.js +0 -19
- package/.next/server/chunks/ssr/[root-of-the-server]__09z7o2x._.js.map +0 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__0a0ffmv._.js +0 -3
- package/.next/server/chunks/ssr/[root-of-the-server]__0a0ffmv._.js.map +0 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__0b7uu-_._.js +0 -3
- package/.next/server/chunks/ssr/[root-of-the-server]__0b7uu-_._.js.map +0 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__0bl_wqk._.js +0 -3
- package/.next/server/chunks/ssr/[root-of-the-server]__0bl_wqk._.js.map +0 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__0ft0rpu._.js +0 -3
- package/.next/server/chunks/ssr/[root-of-the-server]__0ft0rpu._.js.map +0 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__0i~g-2t._.js +0 -3
- package/.next/server/chunks/ssr/[root-of-the-server]__0i~g-2t._.js.map +0 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__0jl4ukn._.js +0 -3
- package/.next/server/chunks/ssr/[root-of-the-server]__0jl4ukn._.js.map +0 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__0mook08._.js +0 -3
- package/.next/server/chunks/ssr/[root-of-the-server]__0mook08._.js.map +0 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__0n46s~k._.js +0 -3
- package/.next/server/chunks/ssr/[root-of-the-server]__0n46s~k._.js.map +0 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__0qchqb~._.js +0 -3
- package/.next/server/chunks/ssr/[root-of-the-server]__0qchqb~._.js.map +0 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__0rrm~-q._.js +0 -3
- package/.next/server/chunks/ssr/[root-of-the-server]__0rrm~-q._.js.map +0 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__0w2ay2h._.js +0 -3
- package/.next/server/chunks/ssr/[root-of-the-server]__0w2ay2h._.js.map +0 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__0xjish~._.js +0 -3
- package/.next/server/chunks/ssr/[root-of-the-server]__0xjish~._.js.map +0 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__0xm3h9x._.js +0 -3
- package/.next/server/chunks/ssr/[root-of-the-server]__0xm3h9x._.js.map +0 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__0ywihy_._.js +0 -8
- package/.next/server/chunks/ssr/[root-of-the-server]__0ywihy_._.js.map +0 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__12ad1n.._.js +0 -3
- package/.next/server/chunks/ssr/[root-of-the-server]__12ad1n.._.js.map +0 -1
- package/.next/server/chunks/ssr/_0nne7mz._.js +0 -3
- package/.next/server/chunks/ssr/_0nne7mz._.js.map +0 -1
- package/.next/server/chunks/ssr/_next-internal_server_app__global-error_page_actions_0k77kol.js +0 -3
- package/.next/server/chunks/ssr/_next-internal_server_app__not-found_page_actions_0eq97pa.js +0 -3
- package/.next/server/chunks/ssr/_next-internal_server_app_admin_page_actions_0ycnu8f.js +0 -3
- package/.next/server/chunks/ssr/_next-internal_server_app_login_page_actions_02kefem.js +0 -3
- package/.next/server/chunks/ssr/_next-internal_server_app_logs_page_actions_0rvsl~d.js +0 -3
- package/.next/server/chunks/ssr/_next-internal_server_app_messages_page_actions_0gsqep_.js +0 -3
- package/.next/server/chunks/ssr/_next-internal_server_app_node_page_actions_0wd8cgl.js +0 -3
- package/.next/server/chunks/ssr/_next-internal_server_app_nodes_page_actions_0-.rv67.js +0 -3
- package/.next/server/chunks/ssr/_next-internal_server_app_page_actions_09-gtaw.js +0 -3
- package/.next/server/chunks/ssr/_next-internal_server_app_server-logs_page_actions_0g1gb5c.js +0 -3
- package/.next/server/chunks/ssr/_next-internal_server_app_settings_networks_page_actions_09uw.sw.js +0 -3
- package/.next/server/chunks/ssr/_next-internal_server_app_settings_page_actions_0mr68ai.js +0 -3
- package/.next/server/chunks/ssr/_next-internal_server_app_settings_tokens_page_actions_0yi54x8.js +0 -3
- package/.next/server/chunks/ssr/_next-internal_server_app_tasks_[id]_page_actions_0k_hm9g.js +0 -3
- package/.next/server/chunks/ssr/_next-internal_server_app_tasks_page_actions_0_2o_cr.js +0 -3
- package/.next/server/chunks/ssr/app_0.zbtn5._.js.map +0 -1
- package/.next/server/chunks/ssr/app_01y-~mp._.js +0 -3
- package/.next/server/chunks/ssr/app_01y-~mp._.js.map +0 -1
- package/.next/server/chunks/ssr/app_04n78pr._.js.map +0 -1
- package/.next/server/chunks/ssr/app_0_agk0r._.js.map +0 -1
- package/.next/server/chunks/ssr/app_0aenxef._.js +0 -3
- package/.next/server/chunks/ssr/app_0aenxef._.js.map +0 -1
- package/.next/server/chunks/ssr/app_0aum_g5._.js +0 -3
- package/.next/server/chunks/ssr/app_0aum_g5._.js.map +0 -1
- package/.next/server/chunks/ssr/app_0emvkn2._.js +0 -3
- package/.next/server/chunks/ssr/app_0emvkn2._.js.map +0 -1
- package/.next/server/chunks/ssr/app_0esuljp._.js +0 -3
- package/.next/server/chunks/ssr/app_0esuljp._.js.map +0 -1
- package/.next/server/chunks/ssr/app_0izi28j._.js.map +0 -1
- package/.next/server/chunks/ssr/app_components_08ys5y3._.js.map +0 -1
- package/.next/server/chunks/ssr/app_server-logs_page_tsx_0_kpp1p._.js.map +0 -1
- package/.next/server/chunks/ssr/app_tasks_page_tsx_0z-d6mp._.js +0 -3
- package/.next/server/chunks/ssr/app_tasks_page_tsx_0z-d6mp._.js.map +0 -1
- package/.next/server/chunks/ssr/node_modules_09w7yel._.js.map +0 -1
- package/.next/server/chunks/ssr/node_modules_0ck2~9g._.js +0 -3
- package/.next/server/chunks/ssr/node_modules_0ck2~9g._.js.map +0 -1
- package/.next/server/chunks/ssr/node_modules_0r_.s40._.js.map +0 -1
- package/.next/server/chunks/ssr/node_modules_0vtdjw7._.js +0 -3
- package/.next/server/chunks/ssr/node_modules_0vtdjw7._.js.map +0 -1
- package/.next/server/chunks/ssr/node_modules_next_0w2y7fz._.js +0 -6
- package/.next/server/chunks/ssr/node_modules_next_0w2y7fz._.js.map +0 -1
- package/.next/server/chunks/ssr/node_modules_next_dist_0e1izl_._.js +0 -6
- package/.next/server/chunks/ssr/node_modules_next_dist_0e1izl_._.js.map +0 -1
- package/.next/server/chunks/ssr/node_modules_next_dist_client_components_0inhx6q._.js +0 -3
- package/.next/server/chunks/ssr/node_modules_next_dist_client_components_0inhx6q._.js.map +0 -1
- package/.next/server/chunks/ssr/node_modules_next_dist_client_components_builtin_forbidden_0ghu-f7.js +0 -3
- package/.next/server/chunks/ssr/node_modules_next_dist_client_components_builtin_forbidden_0ghu-f7.js.map +0 -1
- package/.next/server/chunks/ssr/node_modules_next_dist_client_components_builtin_global-error_0lgvd_..js +0 -3
- package/.next/server/chunks/ssr/node_modules_next_dist_client_components_builtin_global-error_0lgvd_..js.map +0 -1
- package/.next/server/chunks/ssr/node_modules_next_dist_client_components_builtin_unauthorized_0cjv-23.js +0 -3
- package/.next/server/chunks/ssr/node_modules_next_dist_client_components_builtin_unauthorized_0cjv-23.js.map +0 -1
- package/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_002l7yi.js.map +0 -1
- package/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_02suzhc.js.map +0 -1
- package/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_07uu-xq.js.map +0 -1
- package/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0d2yq5t.js.map +0 -1
- package/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0dm~kj8.js.map +0 -1
- package/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0foejvu.js.map +0 -1
- package/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0l-fh0i.js.map +0 -1
- package/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0nsg22r.js.map +0 -1
- package/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0o9vt1n.js.map +0 -1
- package/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0qm1-a1.js.map +0 -1
- package/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0uccf9z.js.map +0 -1
- package/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0uv6jyc.js.map +0 -1
- package/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_10~~o-h.js +0 -4
- package/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_10~~o-h.js.map +0 -1
- package/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_13leyhk.js +0 -4
- package/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_13leyhk.js.map +0 -1
- package/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_13s07li.js.map +0 -1
- package/.next/static/chunks/0218jmcfde~9s.js +0 -1
- package/.next/static/chunks/0257pdz1-imal.js +0 -2
- package/.next/static/chunks/02_zpo7taex9o.js +0 -7
- package/.next/static/chunks/06n3d~fbbtagk.js +0 -1
- package/.next/static/chunks/07eba1lz2u3p4.js +0 -1
- package/.next/static/chunks/09n9xs.6dvvo2.css +0 -2
- package/.next/static/chunks/0av2~0.96~d~g.js +0 -1
- package/.next/static/chunks/0c1bp~g7.8ru..js +0 -1
- package/.next/static/chunks/0e-.zgw81gela.js +0 -31
- package/.next/static/chunks/0g9aof0ob_fcj.js +0 -1
- package/.next/static/chunks/0s8jo6jypzkx5.js +0 -1
- package/.next/static/chunks/0u359llqm1_01.js +0 -1
- package/.next/static/chunks/0ubqqhhpsaez4.js +0 -1
- package/.next/static/chunks/0z1xslnw3jx1s.js +0 -1
- package/.next/static/chunks/0~qw9kxksr1v2.js +0 -1
- package/.next/static/chunks/12gprw3l0kvvf.js +0 -1
- package/.next/static/chunks/12yuo353giomx.js +0 -1
- package/.next/static/chunks/13j9vr8_l9ket.js +0 -1
- package/.next/static/chunks/14bsg3_-taiw4.js +0 -1
- /package/.next/build/chunks/{[root-of-the-server]__0ubbtyl._.js.map → [root-of-the-server]__0tgc-8p._.js.map} +0 -0
- /package/.next/build/chunks/{[turbopack-node]_transforms_postcss_ts_06e.r3r._.js.map → [turbopack-node]_transforms_postcss_ts_0r4x5ys._.js.map} +0 -0
- /package/.next/server/chunks/{_next-internal_server_app_api_anet_config_route_actions_0xzy73j.js.map → 0ci9_nt-network-dashboard__next-internal_server_app_api_auth_v3_route_actions_0f5nbzr.js.map} +0 -0
- /package/.next/server/chunks/{_next-internal_server_app_api_auth_login_route_actions_0zukc38.js.map → 0ci9_nt-network-dashboard__next-internal_server_app_favicon_ico_route_actions_0t0eu9r.js.map} +0 -0
- /package/.next/server/chunks/{_next-internal_server_app_api_auth_logout_route_actions_0fm~3ij.js.map → 0ykm__next-internal_server_app_api_anet_config_route_actions_0a~v55_.js.map} +0 -0
- /package/.next/server/chunks/{_next-internal_server_app_api_auth_v3_route_actions_0ndzs5l.js.map → 0ykm__next-internal_server_app_api_auth_login_route_actions_0xnxfs4.js.map} +0 -0
- /package/.next/server/chunks/{_next-internal_server_app_api_hub_audit-log_route_actions_11k8fqt.js.map → 0ykm__next-internal_server_app_api_auth_logout_route_actions_0p8p0rn.js.map} +0 -0
- /package/.next/server/chunks/{_next-internal_server_app_api_hub_auth_route_actions_0gs7ttk.js.map → 0ykm__next-internal_server_app_api_hub_audit-log_route_actions_06uquwi.js.map} +0 -0
- /package/.next/server/chunks/{_next-internal_server_app_api_hub_broadcast_route_actions_0ads-kd.js.map → 0ykm__next-internal_server_app_api_hub_auth_route_actions_0f_y1ey.js.map} +0 -0
- /package/.next/server/chunks/{_next-internal_server_app_api_hub_events_route_actions_0opktby.js.map → 0ykm__next-internal_server_app_api_hub_broadcast_route_actions_0ao3j43.js.map} +0 -0
- /package/.next/server/chunks/{_next-internal_server_app_api_hub_health_route_actions_0tzzt~x.js.map → 0ykm__next-internal_server_app_api_hub_events_route_actions_0_5ndld.js.map} +0 -0
- /package/.next/server/chunks/{_next-internal_server_app_api_hub_inbox_route_actions_0xvslrg.js.map → 0ykm__next-internal_server_app_api_hub_health_route_actions_0mpzl74.js.map} +0 -0
- /package/.next/server/chunks/{_next-internal_server_app_api_hub_license_route_actions_0i3tlr3.js.map → 0ykm__next-internal_server_app_api_hub_inbox_route_actions_0stoyto.js.map} +0 -0
- /package/.next/server/chunks/{_next-internal_server_app_api_hub_messages_route_actions_08-gi-s.js.map → 0ykm__next-internal_server_app_api_hub_license_route_actions_0a4.fuh.js.map} +0 -0
- /package/.next/server/chunks/{_next-internal_server_app_api_hub_networks_route_actions_02vejq2.js.map → 0ykm__next-internal_server_app_api_hub_messages_route_actions_059rw1o.js.map} +0 -0
- /package/.next/server/chunks/{_next-internal_server_app_api_hub_nodes_route_actions_0nx8ryn.js.map → 0ykm__next-internal_server_app_api_hub_networks_route_actions_03sehpn.js.map} +0 -0
- /package/.next/server/chunks/{_next-internal_server_app_api_hub_register_route_actions_086wi_3.js.map → 0ykm__next-internal_server_app_api_hub_nodes_route_actions_11fbp28.js.map} +0 -0
- /package/.next/server/chunks/{_next-internal_server_app_api_hub_send_route_actions_0-ga_ug.js.map → 0ykm__next-internal_server_app_api_hub_register_route_actions_0l.d7~n.js.map} +0 -0
- /package/.next/server/chunks/{_next-internal_server_app_api_hub_server-logs_route_actions_00euexv.js.map → 0ykm__next-internal_server_app_api_hub_send_route_actions_0.p82vy.js.map} +0 -0
- /package/.next/server/chunks/{_next-internal_server_app_api_hub_session_route_actions_041wa62.js.map → 0ykm__next-internal_server_app_api_hub_server-logs_route_actions_05~c5lb.js.map} +0 -0
- /package/.next/server/chunks/{_next-internal_server_app_api_hub_stats_route_actions_1242~od.js.map → 0ykm__next-internal_server_app_api_hub_servers_route_actions_08-m-cs.js.map} +0 -0
- /package/.next/server/chunks/{_next-internal_server_app_api_hub_status_route_actions_0aml09a.js.map → 0ykm__next-internal_server_app_api_hub_session_route_actions_0b9ef2i.js.map} +0 -0
- /package/.next/server/chunks/{_next-internal_server_app_api_hub_task-events_route_actions_02v1tmm.js.map → 0ykm__next-internal_server_app_api_hub_stats_route_actions_03u65u0.js.map} +0 -0
- /package/.next/server/chunks/{_next-internal_server_app_api_hub_tasks_route_actions_0nl77v4.js.map → 0ykm__next-internal_server_app_api_hub_status_route_actions_0_71ear.js.map} +0 -0
- /package/.next/server/chunks/{_next-internal_server_app_api_hub_tmux_route_actions_0u~aaza.js.map → 0ykm__next-internal_server_app_api_hub_task-events_route_actions_07md_ee.js.map} +0 -0
- /package/.next/server/chunks/{_next-internal_server_app_api_hub_tokens_route_actions_09hzf_1.js.map → 0ykm__next-internal_server_app_api_hub_tasks_route_actions_0er3uvk.js.map} +0 -0
- /package/.next/server/chunks/{_next-internal_server_app_favicon_ico_route_actions_095lj93.js.map → 0ykm__next-internal_server_app_api_hub_tmux_route_actions_0o_1-8u.js.map} +0 -0
- /package/.next/server/chunks/{ssr/_next-internal_server_app__global-error_page_actions_0k77kol.js.map → 0ykm__next-internal_server_app_api_hub_tokens_route_actions_09doluz.js.map} +0 -0
- /package/.next/server/chunks/ssr/{_next-internal_server_app__not-found_page_actions_0eq97pa.js.map → 0dwh_ent-network-dashboard__next-internal_server_app_server-logs_page_actions_0hkk815.js.map} +0 -0
- /package/.next/server/chunks/ssr/{_next-internal_server_app_admin_page_actions_0ycnu8f.js.map → 0yas_gent-network-dashboard__next-internal_server_app__not-found_page_actions_0u.f-rz.js.map} +0 -0
- /package/.next/server/chunks/ssr/{_next-internal_server_app_login_page_actions_02kefem.js.map → 0yas_gent-network-dashboard__next-internal_server_app_tasks_[id]_page_actions_0r3~lho.js.map} +0 -0
- /package/.next/server/chunks/ssr/{_next-internal_server_app_logs_page_actions_0rvsl~d.js.map → 0ykm__next-internal_server_app__global-error_page_actions_100fxls.js.map} +0 -0
- /package/.next/server/chunks/ssr/{_next-internal_server_app_messages_page_actions_0gsqep_.js.map → 0ykm__next-internal_server_app_settings_networks_page_actions_0jgy57m.js.map} +0 -0
- /package/.next/server/chunks/ssr/{_next-internal_server_app_node_page_actions_0wd8cgl.js.map → 0ykm__next-internal_server_app_settings_tokens_page_actions_0l5h.k~.js.map} +0 -0
- /package/.next/server/chunks/ssr/{_next-internal_server_app_nodes_page_actions_0-.rv67.js.map → agent-network-dashboard__next-internal_server_app_admin_page_actions_0i~.x~j.js.map} +0 -0
- /package/.next/server/chunks/ssr/{_next-internal_server_app_page_actions_09-gtaw.js.map → agent-network-dashboard__next-internal_server_app_login_page_actions_0frwl15.js.map} +0 -0
- /package/.next/server/chunks/ssr/{_next-internal_server_app_server-logs_page_actions_0g1gb5c.js.map → agent-network-dashboard__next-internal_server_app_logs_page_actions_0xa2ox_.js.map} +0 -0
- /package/.next/server/chunks/ssr/{_next-internal_server_app_settings_networks_page_actions_09uw.sw.js.map → agent-network-dashboard__next-internal_server_app_messages_page_actions_10j3tg4.js.map} +0 -0
- /package/.next/server/chunks/ssr/{_next-internal_server_app_settings_page_actions_0mr68ai.js.map → agent-network-dashboard__next-internal_server_app_node_page_actions_0sl4ntd.js.map} +0 -0
- /package/.next/server/chunks/ssr/{_next-internal_server_app_settings_tokens_page_actions_0yi54x8.js.map → agent-network-dashboard__next-internal_server_app_nodes_page_actions_0cpgkfs.js.map} +0 -0
- /package/.next/server/chunks/ssr/{_next-internal_server_app_tasks_[id]_page_actions_0k_hm9g.js.map → agent-network-dashboard__next-internal_server_app_page_actions_08nuo36.js.map} +0 -0
- /package/.next/server/chunks/ssr/{_next-internal_server_app_tasks_page_actions_0_2o_cr.js.map → agent-network-dashboard__next-internal_server_app_settings_page_actions_0iv.lmk.js.map} +0 -0
- /package/.next/static/{kXeBUTKSdNooA8p2BTTfp → SjGVu8dTaZVySLlXjmaar}/_buildManifest.js +0 -0
- /package/.next/static/{kXeBUTKSdNooA8p2BTTfp → SjGVu8dTaZVySLlXjmaar}/_clientMiddlewareManifest.js +0 -0
- /package/.next/static/{kXeBUTKSdNooA8p2BTTfp → SjGVu8dTaZVySLlXjmaar}/_ssgManifest.js +0 -0
|
@@ -4,6 +4,7 @@ import { useEffect, useMemo, useRef, useState } from 'react';
|
|
|
4
4
|
import { Session } from './types';
|
|
5
5
|
import { aliasAvatarColors, aliasInitial } from './AliasAvatar';
|
|
6
6
|
import { ChatPopover } from './ChatPopover';
|
|
7
|
+
import { vendorForModel, runtimeIdentity, identityLine } from '../lib/vendorIdentity';
|
|
7
8
|
|
|
8
9
|
interface MessageFlow {
|
|
9
10
|
from_alias: string;
|
|
@@ -15,6 +16,9 @@ interface MessageFlow {
|
|
|
15
16
|
interface TopoGraphProps {
|
|
16
17
|
sessions: Session[];
|
|
17
18
|
sseSessions: Record<string, number>;
|
|
19
|
+
// #84: a node.renamed event from the Overview's SSE listener. When the
|
|
20
|
+
// currently open chat popover targets `from`, it follows the rename to `to`.
|
|
21
|
+
renameSignal?: { from: string; to: string; ts: number } | null;
|
|
18
22
|
}
|
|
19
23
|
|
|
20
24
|
interface Point {
|
|
@@ -28,6 +32,9 @@ interface FlowLink {
|
|
|
28
32
|
to: string;
|
|
29
33
|
count: number;
|
|
30
34
|
content: string;
|
|
35
|
+
/** ISO timestamp of the most recent message on this edge — drives
|
|
36
|
+
* the Round 10 freshness fade so dormant links recede visually. */
|
|
37
|
+
last_at: string;
|
|
31
38
|
}
|
|
32
39
|
|
|
33
40
|
const cx = 500;
|
|
@@ -81,36 +88,52 @@ function truncate(value: string, max: number) {
|
|
|
81
88
|
return value.length > max ? `${value.slice(0, max - 1)}...` : value;
|
|
82
89
|
}
|
|
83
90
|
|
|
91
|
+
/** Round 12 / Loop: status trio audit.
|
|
92
|
+
*
|
|
93
|
+
* Each (status × theme) cell returns a {primary, halo, text} trio. The trio
|
|
94
|
+
* invariant — keep it when adding states or tweaking shades:
|
|
95
|
+
*
|
|
96
|
+
* light: primary = <hue>-600 halo = <hue>-100 * text = <hue>-800/900
|
|
97
|
+
* dark: primary = <hue>-400/500 halo = <hue>-900 text = <hue>-100
|
|
98
|
+
*
|
|
99
|
+
* * offline.halo light deviates intentionally to slate-200 (#e2e8f0):
|
|
100
|
+
* slate-100 (#f1f5f9) is too close to the panel bg (#f8fafc) and the
|
|
101
|
+
* halo would vanish. The other three rows keep the 100-shade.
|
|
102
|
+
*
|
|
103
|
+
* Audit caught one cross-family drift before this round: online-other halo
|
|
104
|
+
* light was #dbeafe (blue-100) while its primary (#0284c7 sky-600) and text
|
|
105
|
+
* (#0c4a6e sky-900) were sky-family — now sky-100 (#e0f2fe). Tiny visual
|
|
106
|
+
* difference; large hygiene win — every trio is now mono-hue. */
|
|
84
107
|
function nodeStatus(session: Session, isOnline: boolean, isLight: boolean) {
|
|
85
108
|
if (!isOnline) {
|
|
86
109
|
return {
|
|
87
110
|
label: 'offline',
|
|
88
|
-
primary: isLight ? '#94a3b8' : '#6b7280',
|
|
89
|
-
halo: isLight ? '#e2e8f0' : '#111827',
|
|
90
|
-
text: isLight ? '#475569' : '#9ca3af',
|
|
111
|
+
primary: isLight ? '#94a3b8' : '#6b7280', // slate-400 / gray-500
|
|
112
|
+
halo: isLight ? '#e2e8f0' : '#111827', // slate-200* / gray-900
|
|
113
|
+
text: isLight ? '#475569' : '#9ca3af', // slate-600 / gray-400
|
|
91
114
|
};
|
|
92
115
|
}
|
|
93
116
|
if (session.status === 'working') {
|
|
94
117
|
return {
|
|
95
118
|
label: 'working',
|
|
96
|
-
primary: isLight ? '#059669' : '#22c55e',
|
|
97
|
-
halo: isLight ? '#d1fae5' : '#14532d',
|
|
98
|
-
text: isLight ? '#065f46' : '#dcfce7',
|
|
119
|
+
primary: isLight ? '#059669' : '#22c55e', // emerald-600 / green-500
|
|
120
|
+
halo: isLight ? '#d1fae5' : '#14532d', // emerald-100 / green-900
|
|
121
|
+
text: isLight ? '#065f46' : '#dcfce7', // emerald-800 / green-100
|
|
99
122
|
};
|
|
100
123
|
}
|
|
101
124
|
if (session.status === 'idle') {
|
|
102
125
|
return {
|
|
103
126
|
label: 'idle',
|
|
104
|
-
primary: isLight ? '#0d9488' : '#2dd4bf',
|
|
105
|
-
halo: isLight ? '#ccfbf1' : '#134e4a',
|
|
106
|
-
text: isLight ? '#115e59' : '#ccfbf1',
|
|
127
|
+
primary: isLight ? '#0d9488' : '#2dd4bf', // teal-600 / teal-400
|
|
128
|
+
halo: isLight ? '#ccfbf1' : '#134e4a', // teal-100 / teal-900
|
|
129
|
+
text: isLight ? '#115e59' : '#ccfbf1', // teal-800 / teal-100
|
|
107
130
|
};
|
|
108
131
|
}
|
|
109
132
|
return {
|
|
110
133
|
label: session.status || 'online',
|
|
111
|
-
primary: isLight ? '#0284c7' : '#38bdf8',
|
|
112
|
-
halo: isLight ? '#
|
|
113
|
-
text: isLight ? '#0c4a6e' : '#e0f2fe',
|
|
134
|
+
primary: isLight ? '#0284c7' : '#38bdf8', // sky-600 / sky-400
|
|
135
|
+
halo: isLight ? '#e0f2fe' : '#0c4a6e', // sky-100 / sky-900 (was blue-100 — drift fixed Round 12)
|
|
136
|
+
text: isLight ? '#0c4a6e' : '#e0f2fe', // sky-900 / sky-100
|
|
114
137
|
};
|
|
115
138
|
}
|
|
116
139
|
|
|
@@ -236,22 +259,59 @@ function commonPrefix(a: string, b: string): string {
|
|
|
236
259
|
return a.slice(0, i);
|
|
237
260
|
}
|
|
238
261
|
|
|
239
|
-
|
|
240
|
-
|
|
262
|
+
/** #83 + #111: group nodes that share a ≥2-char alias prefix OR a project_dir
|
|
263
|
+
* ("either criterion → same group", Vincent 4724). Union-find over the
|
|
264
|
+
* sessions; the component label prefers the shared project_dir's basename,
|
|
265
|
+
* else the common alias prefix. Returns alias → groupKey. */
|
|
266
|
+
function computeGroups(sessions: { alias: string; project_dir?: string | null }[]): Record<string, string> {
|
|
267
|
+
const n = sessions.length;
|
|
268
|
+
const parent = sessions.map((_, i) => i);
|
|
269
|
+
const find = (i: number): number => {
|
|
270
|
+
while (parent[i] !== i) { parent[i] = parent[parent[i]]; i = parent[i]; }
|
|
271
|
+
return i;
|
|
272
|
+
};
|
|
273
|
+
const union = (a: number, b: number) => {
|
|
274
|
+
const ra = find(a), rb = find(b);
|
|
275
|
+
if (ra !== rb) parent[ra] = rb;
|
|
276
|
+
};
|
|
277
|
+
|
|
278
|
+
// union by shared project_dir
|
|
279
|
+
const byDir: Record<string, number[]> = {};
|
|
280
|
+
sessions.forEach((s, i) => {
|
|
281
|
+
const d = s.project_dir?.trim();
|
|
282
|
+
if (d) (byDir[d] ||= []).push(i);
|
|
283
|
+
});
|
|
284
|
+
for (const idxs of Object.values(byDir)) {
|
|
285
|
+
for (let k = 1; k < idxs.length; k++) union(idxs[0], idxs[k]);
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
// union by shared ≥2-char alias prefix — sort, link adjacent pairs
|
|
289
|
+
const order = sessions.map((_, i) => i).sort((a, b) => sessions[a].alias.localeCompare(sessions[b].alias));
|
|
290
|
+
for (let k = 0; k + 1 < order.length; k++) {
|
|
291
|
+
if (commonPrefix(sessions[order[k]].alias, sessions[order[k + 1]].alias).length >= 2) {
|
|
292
|
+
union(order[k], order[k + 1]);
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
// label each connected component
|
|
297
|
+
const comps: Record<number, number[]> = {};
|
|
298
|
+
for (let i = 0; i < n; i++) (comps[find(i)] ||= []).push(i);
|
|
241
299
|
const keys: Record<string, string> = {};
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
const
|
|
248
|
-
if (
|
|
249
|
-
|
|
250
|
-
|
|
300
|
+
for (const members of Object.values(comps)) {
|
|
301
|
+
let label: string;
|
|
302
|
+
if (members.length === 1) {
|
|
303
|
+
label = sessions[members[0]].alias;
|
|
304
|
+
} else {
|
|
305
|
+
const dirs = new Set(members.map(i => sessions[i].project_dir?.trim()).filter(Boolean) as string[]);
|
|
306
|
+
if (dirs.size === 1) {
|
|
307
|
+
const d = [...dirs][0];
|
|
308
|
+
label = d.split('/').filter(Boolean).pop() || d;
|
|
309
|
+
} else {
|
|
310
|
+
label = members.map(i => sessions[i].alias).reduce((a, b) => commonPrefix(a, b));
|
|
311
|
+
if (label.length < 2) label = sessions[members[0]].alias;
|
|
312
|
+
}
|
|
251
313
|
}
|
|
252
|
-
const
|
|
253
|
-
for (let k = i; k <= j; k++) keys[sorted[k]] = key;
|
|
254
|
-
i = j + 1;
|
|
314
|
+
for (const i of members) keys[sessions[i].alias] = label;
|
|
255
315
|
}
|
|
256
316
|
return keys;
|
|
257
317
|
}
|
|
@@ -271,19 +331,27 @@ function buildFlowLinks(messages: MessageFlow[], positions: Record<string, Point
|
|
|
271
331
|
const key = `${message.from_alias}->${message.to_alias}`;
|
|
272
332
|
const current = links.get(key);
|
|
273
333
|
|
|
334
|
+
// Keep the most-recent timestamp per pair so the render can fade
|
|
335
|
+
// dormant edges (Round 10 freshness fade).
|
|
336
|
+
const incoming = message.created_at || '';
|
|
337
|
+
const last_at = !current
|
|
338
|
+
? incoming
|
|
339
|
+
: (incoming > current.last_at ? incoming : current.last_at);
|
|
340
|
+
|
|
274
341
|
links.set(key, {
|
|
275
342
|
key,
|
|
276
343
|
from: message.from_alias,
|
|
277
344
|
to: message.to_alias,
|
|
278
345
|
count: (current?.count || 0) + 1,
|
|
279
346
|
content: current?.content || message.content,
|
|
347
|
+
last_at,
|
|
280
348
|
});
|
|
281
349
|
});
|
|
282
350
|
|
|
283
351
|
return [...links.values()].slice(0, 18);
|
|
284
352
|
}
|
|
285
353
|
|
|
286
|
-
export function TopoGraph({ sessions, sseSessions }: TopoGraphProps) {
|
|
354
|
+
export function TopoGraph({ sessions, sseSessions, renameSignal }: TopoGraphProps) {
|
|
287
355
|
const theme = useTheme();
|
|
288
356
|
const isLight = theme === 'light';
|
|
289
357
|
const pal = isLight ? LIGHT_PALETTE : DARK_PALETTE;
|
|
@@ -306,6 +374,20 @@ export function TopoGraph({ sessions, sseSessions }: TopoGraphProps) {
|
|
|
306
374
|
try { localStorage.setItem('anet-topo-layout', next); } catch {}
|
|
307
375
|
return next;
|
|
308
376
|
});
|
|
377
|
+
// Issue #113: node size scale (Vincent 4727 — nodes too big / crowded at
|
|
378
|
+
// ~22 nodes). S/M/L → 0.7/0.84/1.0; default M (one notch down from the old
|
|
379
|
+
// fixed size). Persisted like the layout toggle.
|
|
380
|
+
const [nodeScale, setNodeScale] = useState(0.84);
|
|
381
|
+
useEffect(() => {
|
|
382
|
+
try {
|
|
383
|
+
const saved = parseFloat(localStorage.getItem('anet-topo-nodescale') || '');
|
|
384
|
+
if (saved === 0.7 || saved === 0.84 || saved === 1) setNodeScale(saved);
|
|
385
|
+
} catch {}
|
|
386
|
+
}, []);
|
|
387
|
+
const pickNodeScale = (v: number) => {
|
|
388
|
+
setNodeScale(v);
|
|
389
|
+
try { localStorage.setItem('anet-topo-nodescale', String(v)); } catch {}
|
|
390
|
+
};
|
|
309
391
|
|
|
310
392
|
useEffect(() => {
|
|
311
393
|
const fetchMessages = async () => {
|
|
@@ -332,6 +414,7 @@ export function TopoGraph({ sessions, sseSessions }: TopoGraphProps) {
|
|
|
332
414
|
flowLinks,
|
|
333
415
|
activeAliases,
|
|
334
416
|
groupKeys,
|
|
417
|
+
groupBoxes,
|
|
335
418
|
} = useMemo(() => {
|
|
336
419
|
const sseCount = (s: { alias: string; network_id?: string }) =>
|
|
337
420
|
(s.network_id ? sseSessions[`${s.network_id}:${s.alias}`] : undefined) ?? sseSessions[s.alias];
|
|
@@ -341,36 +424,123 @@ export function TopoGraph({ sessions, sseSessions }: TopoGraphProps) {
|
|
|
341
424
|
// index, so contiguous-in-array becomes contiguous-in-ring, i.e.
|
|
342
425
|
// each team visually clusters. localeCompare keeps CJK ordering sane.
|
|
343
426
|
const byAlias = (a: Session, b: Session) => a.alias.localeCompare(b.alias);
|
|
427
|
+
// #112 umbrella: ghost age-out — an offline node not seen for over a day
|
|
428
|
+
// is almost certainly a deleted node the server `/api/status` still
|
|
429
|
+
// returns (#74 root cause is server-side; this is the dashboard-side
|
|
430
|
+
// fallback so stale ghosts stop cluttering the topology). A missing
|
|
431
|
+
// last_seen_at is kept (conservative — could be a legitimately new node).
|
|
432
|
+
const GHOST_MS = 24 * 60 * 60 * 1000;
|
|
433
|
+
const now = Date.now();
|
|
434
|
+
const isGhost = (s: Session) => {
|
|
435
|
+
if (s.status !== 'offline' || sseCount(s) || !s.last_seen_at) return false;
|
|
436
|
+
const t = Date.parse(s.last_seen_at);
|
|
437
|
+
return !Number.isNaN(t) && now - t > GHOST_MS;
|
|
438
|
+
};
|
|
344
439
|
const online = sessions.filter(s => s.status !== 'offline' || sseCount(s)).sort(byAlias);
|
|
345
|
-
const offline = sessions.filter(s => s.status === 'offline' && !sseCount(s)).sort(byAlias);
|
|
440
|
+
const offline = sessions.filter(s => s.status === 'offline' && !sseCount(s) && !isGhost(s)).sort(byAlias);
|
|
346
441
|
const positions: Record<string, Point> = {};
|
|
347
442
|
|
|
348
443
|
if (layout === 'grid') {
|
|
349
|
-
// Issue #87:
|
|
350
|
-
//
|
|
351
|
-
//
|
|
352
|
-
//
|
|
444
|
+
// Issue #87 + #111: group-banded grid. Nodes are sorted by alias so
|
|
445
|
+
// same-prefix aliases are adjacent; each multi-member prefix group then
|
|
446
|
+
// gets its OWN row(s) starting at column 0, while singletons pack into
|
|
447
|
+
// shared rows. Group-banded placement keeps every group's bounding box
|
|
448
|
+
// (#111) a clean rectangle — no box ever overlaps another group's.
|
|
353
449
|
const all = [...online, ...offline];
|
|
354
|
-
const
|
|
355
|
-
const cols = Math.max(1, Math.ceil(Math.sqrt(
|
|
356
|
-
|
|
357
|
-
|
|
450
|
+
const groupKeys = computeGroups(all);
|
|
451
|
+
const cols = Math.max(1, Math.ceil(Math.sqrt(all.length)));
|
|
452
|
+
// #112: gy0 starts below the (now compact) recent-signal / legend
|
|
453
|
+
// overlay panels — their max bottom edge is y≈112 — so grid row 0 is
|
|
454
|
+
// never occluded; gy1 extends near the canvas bottom for breathing room.
|
|
455
|
+
const gx0 = 150, gx1 = 850, gy0 = 126, gy1 = 652;
|
|
358
456
|
const cellW = (gx1 - gx0) / cols;
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
457
|
+
// largest node radius at the current size scale — drives the group
|
|
458
|
+
// label band + the row-height floor so nothing ever overlaps.
|
|
459
|
+
const nodeR = Math.round(26 * nodeScale);
|
|
460
|
+
|
|
461
|
+
// ordered runs of consecutive same-group-key nodes (≥2 = real group)
|
|
462
|
+
const runs: { key: string; members: Session[] }[] = [];
|
|
463
|
+
for (const s of all) {
|
|
464
|
+
const gk = groupKeys[s.alias];
|
|
465
|
+
const last = runs[runs.length - 1];
|
|
466
|
+
if (last && last.key === gk) last.members.push(s);
|
|
467
|
+
else runs.push({ key: gk, members: [s] });
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
// Pass 1 — assign each run to a band: a multi-member group owns its
|
|
471
|
+
// rows (left-aligned, so its bounding box is a tidy rect); contiguous
|
|
472
|
+
// singletons pack into shared rows (centred). Collect total row count.
|
|
473
|
+
type Band = { members: Session[]; startRow: number; centred: boolean; isGroup: boolean };
|
|
474
|
+
const bands: Band[] = [];
|
|
475
|
+
let row = 0;
|
|
476
|
+
let i = 0;
|
|
477
|
+
while (i < runs.length) {
|
|
478
|
+
if (runs[i].members.length >= 2) {
|
|
479
|
+
bands.push({ members: runs[i].members, startRow: row, centred: false, isGroup: true });
|
|
480
|
+
row += Math.ceil(runs[i].members.length / cols);
|
|
481
|
+
i++;
|
|
482
|
+
} else {
|
|
483
|
+
const singles: Session[] = [];
|
|
484
|
+
while (i < runs.length && runs[i].members.length < 2) {
|
|
485
|
+
singles.push(runs[i].members[0]);
|
|
486
|
+
i++;
|
|
487
|
+
}
|
|
488
|
+
bands.push({ members: singles, startRow: row, centred: true, isGroup: false });
|
|
489
|
+
row += Math.ceil(singles.length / cols);
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
const totalRows = Math.max(1, row);
|
|
493
|
+
// #112: the group label sits in a band ABOVE the topmost node, so the
|
|
494
|
+
// band must clear the node radius — GROUP_TOP is node-relative, never
|
|
495
|
+
// cellH-derived (cellH-derived was the label↔node overlap bug Vincent
|
|
496
|
+
// hit). cellH then floors at GROUP_TOP + 30 so the label band + bottom
|
|
497
|
+
// padding always fit and stacked group boxes never touch; past the
|
|
498
|
+
// floor the grid overflows and zoom/pan handles it.
|
|
499
|
+
const GROUP_TOP = nodeR + 20;
|
|
500
|
+
// Row-height floor = the tightest of: a node + its label below it
|
|
501
|
+
// (2·nodeR + ~22), and the label band + min box padding (GROUP_TOP + 12).
|
|
502
|
+
// Below this, rows would overlap; past it the grid overflows and
|
|
503
|
+
// zoom/pan covers the rest.
|
|
504
|
+
const cellH = Math.max(2 * nodeR + 22, GROUP_TOP + 12, Math.min(100, (gy1 - gy0) / totalRows));
|
|
505
|
+
|
|
506
|
+
// Pass 2 — place each band's members.
|
|
507
|
+
for (const band of bands) {
|
|
508
|
+
band.members.forEach((s, idx) => {
|
|
509
|
+
const rowInBand = Math.floor(idx / cols);
|
|
510
|
+
const c = idx % cols;
|
|
511
|
+
const inRow = Math.min(cols, band.members.length - rowInBand * cols);
|
|
512
|
+
const inset = band.centred ? ((cols - inRow) * cellW) / 2 : 0;
|
|
513
|
+
positions[s.alias] = {
|
|
514
|
+
x: gx0 + inset + (c + 0.5) * cellW,
|
|
515
|
+
y: gy0 + (band.startRow + rowInBand + 0.5) * cellH,
|
|
516
|
+
};
|
|
517
|
+
});
|
|
518
|
+
}
|
|
519
|
+
|
|
370
520
|
const links = buildFlowLinks(messages, positions);
|
|
371
521
|
const active = new Set<string>();
|
|
372
522
|
links.forEach(link => { active.add(link.from); active.add(link.to); });
|
|
373
|
-
|
|
523
|
+
// #111: one bounding box per multi-member group (Vincent 4722). Each
|
|
524
|
+
// group owns its rows; GROUP_PAD fills the row space left below the
|
|
525
|
+
// nodes after the label band, so stacked group boxes always have a
|
|
526
|
+
// gap between them (GROUP_TOP is defined above, with cellH).
|
|
527
|
+
const GROUP_PAD = Math.max(8, Math.min(26, cellH - GROUP_TOP - 8)); // side/bottom
|
|
528
|
+
const groupBoxes = bands
|
|
529
|
+
.filter(b => b.isGroup)
|
|
530
|
+
.map(band => {
|
|
531
|
+
const pts = band.members.map(s => positions[s.alias]).filter(Boolean);
|
|
532
|
+
const xs = pts.map(p => p.x);
|
|
533
|
+
const ys = pts.map(p => p.y);
|
|
534
|
+
const minX = Math.min(...xs), minY = Math.min(...ys);
|
|
535
|
+
return {
|
|
536
|
+
key: band.members.length ? groupKeys[band.members[0].alias] : '',
|
|
537
|
+
count: band.members.length,
|
|
538
|
+
x: minX - GROUP_PAD,
|
|
539
|
+
y: minY - GROUP_TOP,
|
|
540
|
+
w: Math.max(...xs) - minX + GROUP_PAD * 2,
|
|
541
|
+
h: Math.max(...ys) - minY + GROUP_TOP + GROUP_PAD,
|
|
542
|
+
};
|
|
543
|
+
});
|
|
374
544
|
return {
|
|
375
545
|
onlineNodes: online,
|
|
376
546
|
offlineNodes: offline,
|
|
@@ -378,6 +548,7 @@ export function TopoGraph({ sessions, sseSessions }: TopoGraphProps) {
|
|
|
378
548
|
flowLinks: links,
|
|
379
549
|
activeAliases: active,
|
|
380
550
|
groupKeys,
|
|
551
|
+
groupBoxes,
|
|
381
552
|
};
|
|
382
553
|
}
|
|
383
554
|
|
|
@@ -448,7 +619,7 @@ export function TopoGraph({ sessions, sseSessions }: TopoGraphProps) {
|
|
|
448
619
|
});
|
|
449
620
|
|
|
450
621
|
// Round 106 (issue #83): group key per alias → shared hue per team.
|
|
451
|
-
const groupKeys =
|
|
622
|
+
const groupKeys = computeGroups([...online, ...offline]);
|
|
452
623
|
|
|
453
624
|
return {
|
|
454
625
|
onlineNodes: online,
|
|
@@ -457,15 +628,36 @@ export function TopoGraph({ sessions, sseSessions }: TopoGraphProps) {
|
|
|
457
628
|
flowLinks: links,
|
|
458
629
|
activeAliases: active,
|
|
459
630
|
groupKeys,
|
|
631
|
+
// #111: group boxes are a grid-layout feature only — radially scattered
|
|
632
|
+
// ring nodes can't be cleanly boxed. Ring keeps the #83 prefix hue.
|
|
633
|
+
groupBoxes: [] as { key: string; count: number; x: number; y: number; w: number; h: number }[],
|
|
460
634
|
};
|
|
461
|
-
}, [messages, sessions, sseSessions, layout]);
|
|
635
|
+
}, [messages, sessions, sseSessions, layout, nodeScale]);
|
|
462
636
|
|
|
463
637
|
const workingCount = onlineNodes.filter(s => s.status === 'working').length;
|
|
638
|
+
// Round 6 / Loop: vendor distribution for the header chip — at a glance
|
|
639
|
+
// "what's in the fleet" (A:5 M:2 O:8 书:12 …) without opening a node.
|
|
640
|
+
// Sorted by count desc; "unknown" vendors collapse into a "?" bucket.
|
|
641
|
+
const vendorDist = useMemo(() => {
|
|
642
|
+
const tally = new Map<string, { initial: string; count: number; color: string }>();
|
|
643
|
+
for (const s of [...onlineNodes, ...offlineNodes]) {
|
|
644
|
+
const v = vendorForModel(s.model);
|
|
645
|
+
const key = v.id === 'unknown' ? '?' : v.initial;
|
|
646
|
+
const cur = tally.get(key);
|
|
647
|
+
if (cur) cur.count++;
|
|
648
|
+
else tally.set(key, { initial: key, count: 1, color: v.mono.text });
|
|
649
|
+
}
|
|
650
|
+
return [...tally.values()].sort((a, b) => b.count - a.count);
|
|
651
|
+
}, [onlineNodes, offlineNodes]);
|
|
464
652
|
// Round 109 (Vincent 4582 P0): hover-gated labels above this node count
|
|
465
653
|
// so dense fleets show clean avatars instead of a wall of overlapping
|
|
466
654
|
// label cards. 16 ≈ where the triple-tier rings start to crowd.
|
|
467
655
|
const denseLayout = onlineNodes.length + offlineNodes.length > 16;
|
|
468
656
|
const [hoveredAlias, setHoveredAlias] = useState<string | null>(null);
|
|
657
|
+
// Round 8 / Loop: which group is currently focused. Nodes outside this
|
|
658
|
+
// group + other group boxes fade so the eye locks onto the team you're
|
|
659
|
+
// pointing at. Singletons use their own alias as the group key.
|
|
660
|
+
const hoveredGroup = hoveredAlias ? (groupKeys[hoveredAlias] ?? hoveredAlias) : null;
|
|
469
661
|
|
|
470
662
|
// --- Round 103 (issue #81): fullscreen + zoom + pan interaction layer ---
|
|
471
663
|
// DIY native (no d3 / svg-pan-zoom): wrap the topology content in a single
|
|
@@ -485,6 +677,25 @@ export function TopoGraph({ sessions, sseSessions }: TopoGraphProps) {
|
|
|
485
677
|
// Issue #100: singleton chat popover. One alias at a time — clicking
|
|
486
678
|
// another node swaps the target and the conversation switches in place.
|
|
487
679
|
const [chatAlias, setChatAlias] = useState<string | null>(null);
|
|
680
|
+
// Round 14 / Loop: one-shot click ripple — fades outward from the clicked
|
|
681
|
+
// node so the click registers physically before the popover snaps in.
|
|
682
|
+
// Pairs with the Round 11 chat-focus ring: ripple expands, ring locks on.
|
|
683
|
+
// Keyed by ts so re-clicking the same node remounts the <circle> and the
|
|
684
|
+
// SMIL <animate> replays. Cleared 600ms after click (longer than the
|
|
685
|
+
// 500ms animation so a final frame at opacity 0 is still in the tree).
|
|
686
|
+
const [clickRipple, setClickRipple] = useState<{
|
|
687
|
+
ts: number; x: number; y: number; r0: number; color: string;
|
|
688
|
+
} | null>(null);
|
|
689
|
+
// #84: when a node is renamed while its chat popover is open, follow the
|
|
690
|
+
// rename so the conversation keeps targeting a live alias.
|
|
691
|
+
useEffect(() => {
|
|
692
|
+
if (renameSignal && renameSignal.from === chatAlias) {
|
|
693
|
+
setChatAlias(renameSignal.to);
|
|
694
|
+
}
|
|
695
|
+
// chatAlias intentionally omitted — only react to a new rename signal,
|
|
696
|
+
// not to the user opening/closing the popover.
|
|
697
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
698
|
+
}, [renameSignal]);
|
|
488
699
|
|
|
489
700
|
useEffect(() => { viewRef.current = view; }, [view]);
|
|
490
701
|
|
|
@@ -546,6 +757,12 @@ export function TopoGraph({ sessions, sseSessions }: TopoGraphProps) {
|
|
|
546
757
|
return () => svg.removeEventListener('wheel', onWheel);
|
|
547
758
|
}, []);
|
|
548
759
|
|
|
760
|
+
// Round 21 / Loop: pan-aware cursor. Static `grab` gave no tactile cue
|
|
761
|
+
// that the canvas was actually being dragged — "grabbing" while
|
|
762
|
+
// dragRef.current.active = true tells the hand it's moving the
|
|
763
|
+
// viewport. Mirroring dragRef.active into state is the only way to
|
|
764
|
+
// re-render the SVG style; the ref itself doesn't trigger renders.
|
|
765
|
+
const [isPanning, setIsPanning] = useState(false);
|
|
549
766
|
const onPointerDown = (e: React.PointerEvent<SVGSVGElement>) => {
|
|
550
767
|
if (e.button !== 0) return;
|
|
551
768
|
(e.currentTarget as Element).setPointerCapture?.(e.pointerId);
|
|
@@ -556,6 +773,7 @@ export function TopoGraph({ sessions, sseSessions }: TopoGraphProps) {
|
|
|
556
773
|
baseX: viewRef.current.x,
|
|
557
774
|
baseY: viewRef.current.y,
|
|
558
775
|
};
|
|
776
|
+
setIsPanning(true);
|
|
559
777
|
};
|
|
560
778
|
const onPointerMove = (e: React.PointerEvent<SVGSVGElement>) => {
|
|
561
779
|
const d = dragRef.current;
|
|
@@ -570,6 +788,7 @@ export function TopoGraph({ sessions, sseSessions }: TopoGraphProps) {
|
|
|
570
788
|
const onPointerUp = (e: React.PointerEvent<SVGSVGElement>) => {
|
|
571
789
|
if (!dragRef.current.active) return;
|
|
572
790
|
dragRef.current.active = false;
|
|
791
|
+
setIsPanning(false);
|
|
573
792
|
try {
|
|
574
793
|
(e.currentTarget as Element).releasePointerCapture?.(e.pointerId);
|
|
575
794
|
} catch {}
|
|
@@ -587,6 +806,30 @@ export function TopoGraph({ sessions, sseSessions }: TopoGraphProps) {
|
|
|
587
806
|
};
|
|
588
807
|
const resetView = () => setView({ zoom: 1, x: 0, y: 0 });
|
|
589
808
|
|
|
809
|
+
// Round 22 / Loop: keyboard zoom — +/= zoom in, - zoom out, 0 reset.
|
|
810
|
+
// Listen on window so the user doesn't need to focus the SVG first,
|
|
811
|
+
// but only act when no text input has focus (otherwise typing "-" in
|
|
812
|
+
// a chat would zoom the topology — surprising and bad). Modifier keys
|
|
813
|
+
// pass through so Cmd/Ctrl combos still hit their owners. The button
|
|
814
|
+
// titles below document these shortcuts so users discover them.
|
|
815
|
+
useEffect(() => {
|
|
816
|
+
const onKey = (e: KeyboardEvent) => {
|
|
817
|
+
if (e.ctrlKey || e.metaKey || e.altKey) return;
|
|
818
|
+
const ae = document.activeElement as HTMLElement | null;
|
|
819
|
+
if (ae) {
|
|
820
|
+
const tag = ae.tagName;
|
|
821
|
+
if (tag === 'INPUT' || tag === 'TEXTAREA' || tag === 'SELECT' || ae.isContentEditable) return;
|
|
822
|
+
}
|
|
823
|
+
if (e.key === '+' || e.key === '=') { zoomBy(1.2); e.preventDefault(); }
|
|
824
|
+
else if (e.key === '-' || e.key === '_') { zoomBy(1 / 1.2); e.preventDefault(); }
|
|
825
|
+
else if (e.key === '0') { resetView(); e.preventDefault(); }
|
|
826
|
+
};
|
|
827
|
+
window.addEventListener('keydown', onKey);
|
|
828
|
+
return () => window.removeEventListener('keydown', onKey);
|
|
829
|
+
// zoomBy / resetView are stable wrt setView callback; safe to omit deps
|
|
830
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
831
|
+
}, []);
|
|
832
|
+
|
|
590
833
|
const toggleFullscreen = () => {
|
|
591
834
|
const el = containerRef.current;
|
|
592
835
|
if (!el) return;
|
|
@@ -632,6 +875,19 @@ export function TopoGraph({ sessions, sseSessions }: TopoGraphProps) {
|
|
|
632
875
|
<span className="px-2.5 py-1 rounded-md bg-cyan-500/10 text-cyan-300 border border-cyan-500/20">
|
|
633
876
|
{onlineNodes.length} online
|
|
634
877
|
</span>
|
|
878
|
+
{vendorDist.length > 1 && (
|
|
879
|
+
<span
|
|
880
|
+
className="inline-flex items-center gap-2 px-2.5 py-1 rounded-md bg-gray-500/10 text-gray-400 border border-gray-500/20 font-mono"
|
|
881
|
+
title="Fleet by model vendor"
|
|
882
|
+
>
|
|
883
|
+
{vendorDist.map(v => (
|
|
884
|
+
<span key={v.initial} className="inline-flex items-baseline gap-0.5">
|
|
885
|
+
<span style={{ color: v.color }}>{v.initial}</span>
|
|
886
|
+
<span className="text-gray-500">:{v.count}</span>
|
|
887
|
+
</span>
|
|
888
|
+
))}
|
|
889
|
+
</span>
|
|
890
|
+
)}
|
|
635
891
|
<span className="px-2.5 py-1 rounded-md bg-gray-500/10 text-gray-400 border border-gray-500/20">
|
|
636
892
|
{flowLinks.length} active links
|
|
637
893
|
</span>
|
|
@@ -654,7 +910,7 @@ export function TopoGraph({ sessions, sseSessions }: TopoGraphProps) {
|
|
|
654
910
|
onPointerMove={onPointerMove}
|
|
655
911
|
onPointerUp={onPointerUp}
|
|
656
912
|
onPointerLeave={onPointerUp}
|
|
657
|
-
style={{ cursor: 'grab', touchAction: 'none' }}
|
|
913
|
+
style={{ cursor: isPanning ? 'grabbing' : 'grab', touchAction: 'none' }}
|
|
658
914
|
>
|
|
659
915
|
<defs>
|
|
660
916
|
<linearGradient id="topo-panel" x1="0" x2="1" y1="0" y2="1">
|
|
@@ -676,9 +932,37 @@ export function TopoGraph({ sessions, sseSessions }: TopoGraphProps) {
|
|
|
676
932
|
</feMerge>
|
|
677
933
|
</filter>
|
|
678
934
|
)}
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
935
|
+
{/* Round 16 / Loop: 3-tier flow-link arrow markers.
|
|
936
|
+
The single marker had `markerUnits` defaulting to
|
|
937
|
+
`strokeWidth`, so heavy edges (stroke=7) rendered 35-user-
|
|
938
|
+
unit arrowheads — visually dominant, the head outweighed
|
|
939
|
+
the line. Switching to `userSpaceOnUse` decouples arrow
|
|
940
|
+
size from stroke; binning by count gives a clearer
|
|
941
|
+
hierarchy than continuous linear scaling:
|
|
942
|
+
s (count 1-2) → 12 user units
|
|
943
|
+
m (count 3-4) → 16 user units (alias for `topo-arrow`)
|
|
944
|
+
l (count 5+) → 22 user units
|
|
945
|
+
`topo-arrow` stays bound to the medium tier so the legend
|
|
946
|
+
swatch (line ~1500) renders without change. */}
|
|
947
|
+
{[
|
|
948
|
+
{ id: 'topo-arrow-s', size: 12 },
|
|
949
|
+
{ id: 'topo-arrow', size: 16 },
|
|
950
|
+
{ id: 'topo-arrow-l', size: 22 },
|
|
951
|
+
].map(m => (
|
|
952
|
+
<marker
|
|
953
|
+
key={m.id}
|
|
954
|
+
id={m.id}
|
|
955
|
+
viewBox="0 0 10 10"
|
|
956
|
+
refX="8"
|
|
957
|
+
refY="5"
|
|
958
|
+
markerWidth={m.size}
|
|
959
|
+
markerHeight={m.size}
|
|
960
|
+
markerUnits="userSpaceOnUse"
|
|
961
|
+
orient="auto-start-reverse"
|
|
962
|
+
>
|
|
963
|
+
<path d="M 0 0 L 10 5 L 0 10 z" fill={pal.arrowFill} />
|
|
964
|
+
</marker>
|
|
965
|
+
))}
|
|
682
966
|
{/* Round 45: radial radar sweep gradient — bright at center
|
|
683
967
|
(where it meets the hub) fading to leading edge. */}
|
|
684
968
|
<radialGradient id="topo-sweep" cx="0%" cy="50%" r="100%">
|
|
@@ -806,16 +1090,89 @@ export function TopoGraph({ sessions, sseSessions }: TopoGraphProps) {
|
|
|
806
1090
|
);
|
|
807
1091
|
})}
|
|
808
1092
|
|
|
1093
|
+
{/* #111: prefix-group boundary boxes (Vincent 4722). Grid layout
|
|
1094
|
+
only — groupBoxes is empty in ring mode. Rendered behind the
|
|
1095
|
+
flow links + nodes; pointer-events off so they never intercept
|
|
1096
|
+
a node click. Restrained dashed container + group-name label. */}
|
|
1097
|
+
{groupBoxes.map(box => {
|
|
1098
|
+
const isHovered = hoveredGroup === box.key;
|
|
1099
|
+
// Round 18 / Loop: group-box hover linkage. The Round 8 fade
|
|
1100
|
+
// already dropped OUT-of-focus groups to 0.28, but the IN-focus
|
|
1101
|
+
// group sat at its baseline appearance — no positive emphasis.
|
|
1102
|
+
// Hovering now upgrades the box to an "accent" treatment:
|
|
1103
|
+
// solid stroke (not dashed), thicker, accent-coloured; brighter
|
|
1104
|
+
// text and slightly stronger fill. Label and box read as one
|
|
1105
|
+
// selected unit. Geometry unchanged → overlap test untouched.
|
|
1106
|
+
return (
|
|
1107
|
+
<g
|
|
1108
|
+
key={`grp-${box.key}`}
|
|
1109
|
+
data-group={box.key}
|
|
1110
|
+
className="transition-opacity"
|
|
1111
|
+
style={{ pointerEvents: 'none', opacity: !hoveredGroup || isHovered ? 1 : 0.28 }}
|
|
1112
|
+
>
|
|
1113
|
+
<rect
|
|
1114
|
+
x={box.x}
|
|
1115
|
+
y={box.y}
|
|
1116
|
+
width={box.w}
|
|
1117
|
+
height={box.h}
|
|
1118
|
+
rx="14"
|
|
1119
|
+
fill={isLight ? '#0f172a' : '#a5b4fc'}
|
|
1120
|
+
fillOpacity={isHovered ? (isLight ? 0.05 : 0.09) : (isLight ? 0.025 : 0.045)}
|
|
1121
|
+
stroke={isHovered ? pal.legendAccent : pal.ringStroke}
|
|
1122
|
+
strokeWidth={isHovered ? 2 : 1.5}
|
|
1123
|
+
strokeDasharray={isHovered ? 'none' : '6 6'}
|
|
1124
|
+
style={{ transition: 'stroke 200ms ease-out, stroke-width 200ms ease-out, fill-opacity 200ms ease-out' }}
|
|
1125
|
+
/>
|
|
1126
|
+
<text
|
|
1127
|
+
x={box.x + 12}
|
|
1128
|
+
y={box.y + 14}
|
|
1129
|
+
fill={isHovered ? pal.legendHeadline : pal.legendText}
|
|
1130
|
+
fontSize="13"
|
|
1131
|
+
fontFamily="monospace"
|
|
1132
|
+
fontWeight="700"
|
|
1133
|
+
style={{ transition: 'fill 200ms ease-out' }}
|
|
1134
|
+
>
|
|
1135
|
+
{box.key}
|
|
1136
|
+
{/* Round 19 / Loop: member-count chip. Inline tspan stays
|
|
1137
|
+
in the single <text> bbox the overlap test reads, so
|
|
1138
|
+
the node↔label guard still catches if the chip ever
|
|
1139
|
+
pushes the label far enough right to clip a node.
|
|
1140
|
+
Smaller + lighter weight reads as metadata, not name. */}
|
|
1141
|
+
<tspan dx="6" fill={pal.legendText} fontSize="11" fontWeight="400">· {box.count}</tspan>
|
|
1142
|
+
</text>
|
|
1143
|
+
</g>
|
|
1144
|
+
);
|
|
1145
|
+
})}
|
|
1146
|
+
|
|
809
1147
|
{/* directed message flows */}
|
|
810
1148
|
{flowLinks.map((link, index) => {
|
|
811
1149
|
const from = nodePositions[link.from];
|
|
812
1150
|
const to = nodePositions[link.to];
|
|
813
1151
|
if (!from || !to) return null;
|
|
814
1152
|
|
|
815
|
-
|
|
1153
|
+
// Round 7 / Loop: lift now scales with distance so short links
|
|
1154
|
+
// aren't over-bent (long links keep the ~36px hump), and the
|
|
1155
|
+
// particle period shortens with link.count so busier edges
|
|
1156
|
+
// visibly pulse faster — instant info density on top of the
|
|
1157
|
+
// existing stroke-width-by-count chip.
|
|
1158
|
+
const dist = Math.hypot(to.x - from.x, to.y - from.y);
|
|
1159
|
+
const lift = (index % 2 === 0 ? 1 : -1) * Math.min(36, dist * 0.18);
|
|
816
1160
|
const path = curvePath(from, to, lift);
|
|
817
1161
|
const width = Math.min(2 + link.count, 7);
|
|
818
|
-
const duration = 2.
|
|
1162
|
+
const duration = Math.max(0.9, 2.6 / Math.sqrt(link.count));
|
|
1163
|
+
// Round 10 / Loop: freshness fade. An edge that fired ≤30s ago
|
|
1164
|
+
// stays at full intensity; over 5 minutes it decays to ~35%.
|
|
1165
|
+
// Surfaces "what's happening now" vs background chatter without
|
|
1166
|
+
// hiding old flow entirely (some context still useful). `now`
|
|
1167
|
+
// captured at useMemo-recompute time (every 5s message refresh)
|
|
1168
|
+
// — accuracy is within the poll interval, plenty.
|
|
1169
|
+
const ageMs = link.last_at ? Math.max(0, Date.now() - Date.parse(link.last_at)) : 0;
|
|
1170
|
+
const fresh = Math.max(0.35, 1 - ageMs / (5 * 60 * 1000));
|
|
1171
|
+
// Round 16 arrow-tier binning — keep `topo-arrow` as the
|
|
1172
|
+
// medium tier id so the legend swatch picks it up unchanged.
|
|
1173
|
+
const arrowId = link.count <= 2 ? 'topo-arrow-s'
|
|
1174
|
+
: link.count <= 4 ? 'topo-arrow'
|
|
1175
|
+
: 'topo-arrow-l';
|
|
819
1176
|
|
|
820
1177
|
return (
|
|
821
1178
|
<g key={link.key}>
|
|
@@ -824,9 +1181,10 @@ export function TopoGraph({ sessions, sseSessions }: TopoGraphProps) {
|
|
|
824
1181
|
fill="none"
|
|
825
1182
|
stroke={pal.flowEdge}
|
|
826
1183
|
strokeWidth={width}
|
|
827
|
-
opacity={isLight ? 0.22 : 0.28}
|
|
1184
|
+
opacity={(isLight ? 0.22 : 0.28) * fresh}
|
|
828
1185
|
filter={isLight ? undefined : 'url(#topo-glow)'}
|
|
829
|
-
markerEnd=
|
|
1186
|
+
markerEnd={`url(#${arrowId})`}
|
|
1187
|
+
className="transition-opacity duration-500"
|
|
830
1188
|
/>
|
|
831
1189
|
<path
|
|
832
1190
|
id={`flow-path-${index}`}
|
|
@@ -835,37 +1193,37 @@ export function TopoGraph({ sessions, sseSessions }: TopoGraphProps) {
|
|
|
835
1193
|
stroke={pal.flowPath}
|
|
836
1194
|
strokeWidth="1"
|
|
837
1195
|
strokeDasharray="2 12"
|
|
838
|
-
opacity={isLight ? 0.4 : 0.75}
|
|
1196
|
+
opacity={(isLight ? 0.4 : 0.75) * fresh}
|
|
1197
|
+
className="transition-opacity duration-500"
|
|
839
1198
|
/>
|
|
840
|
-
<circle r="4" fill={pal.flowParticle} filter={isLight ? undefined : 'url(#topo-glow)'}>
|
|
1199
|
+
<circle r="4" fill={pal.flowParticle} filter={isLight ? undefined : 'url(#topo-glow)'} opacity={fresh}>
|
|
841
1200
|
<animateMotion dur={`${duration}s`} repeatCount="indefinite" path={path} />
|
|
842
1201
|
</circle>
|
|
843
1202
|
</g>
|
|
844
1203
|
);
|
|
845
1204
|
})}
|
|
846
1205
|
|
|
847
|
-
{/* center hub — round 39
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
the
|
|
1206
|
+
{/* center hub — round 39 sized + round 13 restraint.
|
|
1207
|
+
The hub is the control-plane anchor. r39 gave it two outward
|
|
1208
|
+
pulses (r 10→38, 2.4s, double-phase) which read as "loudest
|
|
1209
|
+
node in the room" — wrong semantics: anchors don't emit,
|
|
1210
|
+
they hold. r13 swaps the kinetic pulse for a slow opacity
|
|
1211
|
+
breath on the static halo (4s, ±15% from base), so the hub
|
|
1212
|
+
stays alive without throwing kinetic energy outward. The
|
|
1213
|
+
dual-circle "lit lamp" core is unchanged. */}
|
|
853
1214
|
{layout === 'ring' && (<g>
|
|
854
|
-
{/*
|
|
1215
|
+
{/* grounding halo — now breathes in opacity, no expansion */}
|
|
855
1216
|
<circle
|
|
856
1217
|
cx={cx} cy={cy} r="18"
|
|
857
1218
|
fill={isLight ? '#d1fae5' : '#10b981'}
|
|
858
|
-
opacity={isLight ? 0.
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
<circle cx={cx} cy={cy} r="10" fill="none" stroke="#10b981" strokeWidth="1.5" opacity="0">
|
|
867
|
-
<animate attributeName="r" values="10;38;10" dur="2.4s" begin="1.2s" repeatCount="indefinite" />
|
|
868
|
-
<animate attributeName="opacity" values="0.45;0;0.45" dur="2.4s" begin="1.2s" repeatCount="indefinite" />
|
|
1219
|
+
opacity={isLight ? 0.42 : 0.12}
|
|
1220
|
+
>
|
|
1221
|
+
<animate
|
|
1222
|
+
attributeName="opacity"
|
|
1223
|
+
values={isLight ? '0.32;0.52;0.32' : '0.08;0.16;0.08'}
|
|
1224
|
+
dur="4s"
|
|
1225
|
+
repeatCount="indefinite"
|
|
1226
|
+
/>
|
|
869
1227
|
</circle>
|
|
870
1228
|
{/* core — 20px diameter, larger inner highlight reads as a "lit lamp" */}
|
|
871
1229
|
<circle cx={cx} cy={cy} r="10" fill={isLight ? '#059669' : '#10b981'} />
|
|
@@ -873,7 +1231,7 @@ export function TopoGraph({ sessions, sseSessions }: TopoGraphProps) {
|
|
|
873
1231
|
</g>)}
|
|
874
1232
|
|
|
875
1233
|
{/* agent nodes */}
|
|
876
|
-
{[...onlineNodes, ...offlineNodes].map(session => {
|
|
1234
|
+
{[...onlineNodes, ...offlineNodes].map((session, nodeIdx) => {
|
|
877
1235
|
const pos = nodePositions[session.alias];
|
|
878
1236
|
if (!pos) return null;
|
|
879
1237
|
|
|
@@ -881,7 +1239,9 @@ export function TopoGraph({ sessions, sseSessions }: TopoGraphProps) {
|
|
|
881
1239
|
const isOnline = session.status !== 'offline' || !!sseCountFor;
|
|
882
1240
|
const status = nodeStatus(session, isOnline, isLight);
|
|
883
1241
|
const isActive = activeAliases.has(session.alias);
|
|
884
|
-
|
|
1242
|
+
// #113: node size scales with the S/M/L control; halos, labels,
|
|
1243
|
+
// badge and avatar all derive from `radius` so they follow.
|
|
1244
|
+
const radius = Math.round((isOnline ? 26 : 18) * nodeScale);
|
|
885
1245
|
// Round 109/110 (Vincent 4582 + 4583 P0): at high node counts
|
|
886
1246
|
// the 100px opaque label cards overlapped each other and
|
|
887
1247
|
// covered neighbouring avatars. But hiding text entirely went
|
|
@@ -891,12 +1251,48 @@ export function TopoGraph({ sessions, sseSessions }: TopoGraphProps) {
|
|
|
891
1251
|
// occlude an avatar), and the full card appears only for the
|
|
892
1252
|
// hovered node or once zoomed in past 1.4×.
|
|
893
1253
|
const showFullLabel = !denseLayout || hoveredAlias === session.alias || view.zoom >= 1.4;
|
|
1254
|
+
// Round 8: when a node in another group is hovered, fade this
|
|
1255
|
+
// one. Same-group nodes (incl. singletons matching the hovered
|
|
1256
|
+
// alias) stay full. Pure visual focus, geometry unchanged.
|
|
1257
|
+
const inFocus = !hoveredGroup || (groupKeys[session.alias] ?? session.alias) === hoveredGroup;
|
|
894
1258
|
|
|
895
1259
|
return (
|
|
896
1260
|
<g
|
|
897
1261
|
key={session.alias}
|
|
898
|
-
|
|
899
|
-
|
|
1262
|
+
data-node={session.alias}
|
|
1263
|
+
// Round 3 / Loop: `anet-fade-in` runs once when the <g>
|
|
1264
|
+
// mounts — a new session entering the fleet (or the topology
|
|
1265
|
+
// first rendering) eases in instead of popping. Re-renders of
|
|
1266
|
+
// an existing node don't re-trigger (React preserves the <g>
|
|
1267
|
+
// via the alias key), so status changes don't flicker. The
|
|
1268
|
+
// global prefers-reduced-motion sweep already neutralises it.
|
|
1269
|
+
className="group transition-opacity anet-fade-in"
|
|
1270
|
+
style={{
|
|
1271
|
+
cursor: 'pointer',
|
|
1272
|
+
// Round 17 / Loop: offline nodes drop to 0.6 at rest so
|
|
1273
|
+
// online nodes pop without losing the offline-as-ghost
|
|
1274
|
+
// information. The dashed stroke + smaller radius already
|
|
1275
|
+
// say "offline"; dimming the whole group strengthens the
|
|
1276
|
+
// online-vs-offline hierarchy at first glance. Exempt the
|
|
1277
|
+
// chat-focused node — if the user explicitly opened a
|
|
1278
|
+
// popover targeting an offline alias, that node stays
|
|
1279
|
+
// full-brightness so the focus ring + popover read as one
|
|
1280
|
+
// selected thing rather than a dimmed selection. Group-
|
|
1281
|
+
// hover fade (Round 8) still wins when inFocus is false.
|
|
1282
|
+
opacity: !inFocus
|
|
1283
|
+
? 0.32
|
|
1284
|
+
: chatAlias === session.alias
|
|
1285
|
+
? 1
|
|
1286
|
+
: isOnline ? 1 : 0.6,
|
|
1287
|
+
// Round 9 / Loop: stagger the anet-fade-in so the topology
|
|
1288
|
+
// reveals as a wave on first paint instead of one big pop.
|
|
1289
|
+
// Cap at 24 indices (≈600ms tail) so 50-node fleets still
|
|
1290
|
+
// finish revealing within a beat. CSS animation-delay only
|
|
1291
|
+
// applies during the keyframe — re-renders without a new
|
|
1292
|
+
// mount (same alias key) don't replay, so status changes
|
|
1293
|
+
// never trigger the stagger again.
|
|
1294
|
+
animationDelay: `${Math.min(nodeIdx, 24) * 25}ms`,
|
|
1295
|
+
}}
|
|
900
1296
|
// Stop the pointerdown from reaching the SVG pan handler: the
|
|
901
1297
|
// SVG calls setPointerCapture, and a captured pointer makes
|
|
902
1298
|
// Chromium fire the follow-up `click` on the SVG instead of
|
|
@@ -904,17 +1300,86 @@ export function TopoGraph({ sessions, sseSessions }: TopoGraphProps) {
|
|
|
904
1300
|
// Side effect (intended): you pan from empty canvas, not by
|
|
905
1301
|
// grabbing a node.
|
|
906
1302
|
onPointerDown={(e) => e.stopPropagation()}
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
1303
|
+
// Track hover globally (not just under denseLayout) so the
|
|
1304
|
+
// Round 8 group-focus fade works at any fleet size.
|
|
1305
|
+
onPointerEnter={() => setHoveredAlias(session.alias)}
|
|
1306
|
+
onPointerLeave={() => setHoveredAlias(prev => (prev === session.alias ? null : prev))}
|
|
1307
|
+
onClick={() => {
|
|
1308
|
+
setChatAlias(session.alias);
|
|
1309
|
+
// Round 14 ripple — capture position, radius and status
|
|
1310
|
+
// colour at click time so the one-shot circle is self-
|
|
1311
|
+
// contained (no re-render-time recomputation needed).
|
|
1312
|
+
setClickRipple({
|
|
1313
|
+
ts: Date.now(),
|
|
1314
|
+
x: pos.x, y: pos.y, r0: radius,
|
|
1315
|
+
color: status.primary,
|
|
1316
|
+
});
|
|
1317
|
+
setTimeout(() => setClickRipple(prev =>
|
|
1318
|
+
prev && Date.now() - prev.ts >= 590 ? null : prev), 600);
|
|
1319
|
+
}}
|
|
910
1320
|
>
|
|
1321
|
+
{/* Issue #96: native hover tooltip — "Vendor · model · Runtime".
|
|
1322
|
+
Falls back to just the alias when the node reports no
|
|
1323
|
+
model/runtime. */}
|
|
1324
|
+
<title>{identityLine(session.model, session.runtime) || session.alias}</title>
|
|
1325
|
+
{/* Round 2 / Loop: hover ring — a thin outer stroke that fades
|
|
1326
|
+
in when the cursor enters the node, signalling clickability
|
|
1327
|
+
(real-user feedback for the chat-popover open). Pure CSS via
|
|
1328
|
+
Tailwind group-hover, so it costs nothing per frame and
|
|
1329
|
+
respects prefers-reduced-motion via the global media query. */}
|
|
1330
|
+
<circle
|
|
1331
|
+
cx={pos.x}
|
|
1332
|
+
cy={pos.y}
|
|
1333
|
+
r={radius + 12}
|
|
1334
|
+
fill="none"
|
|
1335
|
+
stroke={status.primary}
|
|
1336
|
+
// strokeWidth must NOT be 1.5 (offline status ring) or 3
|
|
1337
|
+
// (online status ring) — the overlap test selects by those
|
|
1338
|
+
// exact widths and would mis-count this invisible hover
|
|
1339
|
+
// ring as a node footprint.
|
|
1340
|
+
strokeWidth="2"
|
|
1341
|
+
className="opacity-0 group-hover:opacity-70 transition-opacity duration-150"
|
|
1342
|
+
style={{ pointerEvents: 'none' }}
|
|
1343
|
+
/>
|
|
1344
|
+
{/* Round 11 / Loop: chat-focus ring — when the ChatPopover is
|
|
1345
|
+
open targeting this node, anchor a persistent ring around
|
|
1346
|
+
it so the floating popover visibly links back to its source
|
|
1347
|
+
node. Static (not pulsing) so it reads as "selected state"
|
|
1348
|
+
rather than "this node is active". strokeWidth=2.5 stays
|
|
1349
|
+
clear of the overlap-test selectors (1.5 / 3). Sits just
|
|
1350
|
+
outside the halo radius+8 so it never overlaps a neighbour
|
|
1351
|
+
(halos already pack flush in dense grids). */}
|
|
1352
|
+
{chatAlias === session.alias && (
|
|
1353
|
+
<circle
|
|
1354
|
+
cx={pos.x}
|
|
1355
|
+
cy={pos.y}
|
|
1356
|
+
r={radius + 14}
|
|
1357
|
+
fill="none"
|
|
1358
|
+
stroke={status.primary}
|
|
1359
|
+
strokeWidth="2.5"
|
|
1360
|
+
opacity={isLight ? 0.85 : 0.95}
|
|
1361
|
+
filter={!isLight ? 'url(#topo-glow)' : undefined}
|
|
1362
|
+
className="transition-opacity duration-200"
|
|
1363
|
+
style={{ pointerEvents: 'none' }}
|
|
1364
|
+
/>
|
|
1365
|
+
)}
|
|
911
1366
|
{isActive && (
|
|
912
1367
|
<circle cx={pos.x} cy={pos.y} r={radius + 14} fill={status.primary} opacity={isLight ? 0.08 : 0.12}>
|
|
913
1368
|
<animate attributeName="r" values={`${radius + 8};${radius + 22};${radius + 8}`} dur="2.4s" repeatCount="indefinite" />
|
|
914
1369
|
<animate attributeName="opacity" values={isLight ? '0.12;0.02;0.12' : '0.18;0.04;0.18'} dur="2.4s" repeatCount="indefinite" />
|
|
915
1370
|
</circle>
|
|
916
1371
|
)}
|
|
917
|
-
|
|
1372
|
+
{/* Round 4 / Loop: transition-[fill,stroke,opacity] smooths
|
|
1373
|
+
status colour changes so idle↔working↔offline doesn't snap
|
|
1374
|
+
— task replies / node-rename / SSE updates ease in. */}
|
|
1375
|
+
<circle
|
|
1376
|
+
cx={pos.x}
|
|
1377
|
+
cy={pos.y}
|
|
1378
|
+
r={radius + 8}
|
|
1379
|
+
fill={status.halo}
|
|
1380
|
+
opacity={isOnline ? (isLight ? 0.85 : 0.65) : (isLight ? 0.4 : 0.25)}
|
|
1381
|
+
className="transition-[fill,opacity] duration-300 ease-out"
|
|
1382
|
+
/>
|
|
918
1383
|
<circle
|
|
919
1384
|
cx={pos.x}
|
|
920
1385
|
cy={pos.y}
|
|
@@ -924,34 +1389,28 @@ export function TopoGraph({ sessions, sseSessions }: TopoGraphProps) {
|
|
|
924
1389
|
strokeWidth={isOnline ? 3 : 1.5}
|
|
925
1390
|
strokeDasharray={isOnline ? 'none' : '5 5'}
|
|
926
1391
|
filter={isOnline && !isLight ? 'url(#topo-glow)' : undefined}
|
|
1392
|
+
className="transition-[fill,stroke] duration-300 ease-out"
|
|
927
1393
|
/>
|
|
928
|
-
{/*
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
1394
|
+
{/* Issue #96: node "avatar" is now driven by the model
|
|
1395
|
+
vendor. Decision order:
|
|
1396
|
+
1. ?brand=intern flag, or an intern-aliased node with
|
|
1397
|
+
no model field → 书生 coin (preserves #79).
|
|
1398
|
+
2. vendor has a packaged logo asset → that logo image
|
|
1399
|
+
(intern-s1-* models land here via vendorForModel).
|
|
1400
|
+
3. known vendor, logo asset not shipped yet → a
|
|
1401
|
+
vendor-tinted monogram (spec-mandated fallback).
|
|
1402
|
+
4. unknown vendor / null model → the prefix-group
|
|
1403
|
+
hue-hashed initial (#83/#99 behaviour, unchanged). */}
|
|
935
1404
|
{(() => {
|
|
936
|
-
const ar = isOnline ? 14 : 10;
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
// forces the coin on every node (full brand showcase).
|
|
943
|
-
const isInternNode = isIntern || /书生|书小生|intern/i.test(session.alias);
|
|
944
|
-
if (isInternNode) {
|
|
945
|
-
// Round 102: self-contained "avatar coin" — 书小生 figure
|
|
946
|
-
// keyed off its white background and composited onto a
|
|
947
|
-
// cream circular backplate. The cream coin gives the
|
|
948
|
-
// dark-haired figure consistent contrast on BOTH the
|
|
949
|
-
// dark cyber theme and light theme. Render at the node
|
|
950
|
-
// diameter so the coin fills inside the status ring.
|
|
951
|
-
const size = radius * 2;
|
|
1405
|
+
const ar = Math.round((isOnline ? 14 : 10) * nodeScale);
|
|
1406
|
+
const size = radius * 2;
|
|
1407
|
+
const vendor = vendorForModel(session.model);
|
|
1408
|
+
const internByAlias = /书生|书小生|intern/i.test(session.alias);
|
|
1409
|
+
|
|
1410
|
+
if (isIntern || internByAlias || vendor.logo) {
|
|
952
1411
|
return (
|
|
953
1412
|
<image
|
|
954
|
-
href=
|
|
1413
|
+
href={vendor.logo ?? '/intern_avatar.png'}
|
|
955
1414
|
x={pos.x - size / 2}
|
|
956
1415
|
y={pos.y - size / 2}
|
|
957
1416
|
width={size}
|
|
@@ -960,12 +1419,25 @@ export function TopoGraph({ sessions, sseSessions }: TopoGraphProps) {
|
|
|
960
1419
|
/>
|
|
961
1420
|
);
|
|
962
1421
|
}
|
|
1422
|
+
if (vendor.id !== 'unknown') {
|
|
1423
|
+
// Known model house, logo asset not in public/vendors/
|
|
1424
|
+
// yet — vendor-tinted monogram stands in.
|
|
1425
|
+
return (
|
|
1426
|
+
<>
|
|
1427
|
+
<circle cx={pos.x} cy={pos.y} r={ar} fill={vendor.mono.bg} stroke={vendor.mono.ring} strokeWidth="1" />
|
|
1428
|
+
<text
|
|
1429
|
+
x={pos.x} y={pos.y} dy="0.34em" textAnchor="middle"
|
|
1430
|
+
fill={vendor.mono.text} fontSize={ar}
|
|
1431
|
+
fontFamily="monospace" fontWeight="700"
|
|
1432
|
+
>
|
|
1433
|
+
{vendor.initial}
|
|
1434
|
+
</text>
|
|
1435
|
+
</>
|
|
1436
|
+
);
|
|
1437
|
+
}
|
|
963
1438
|
// Round 106 (issue #83): hue keyed to the prefix group,
|
|
964
|
-
// not the full alias — every 通信* node shares one color
|
|
965
|
-
// every 研究员* another, so teams cluster visually even
|
|
966
|
-
// when the tier layout spreads them across rings.
|
|
1439
|
+
// not the full alias — every 通信* node shares one color.
|
|
967
1440
|
const c = aliasAvatarColors(groupKeys[session.alias] || session.alias);
|
|
968
|
-
const fs = isOnline ? 14 : 10;
|
|
969
1441
|
return (
|
|
970
1442
|
<>
|
|
971
1443
|
<circle cx={pos.x} cy={pos.y} r={ar} fill={c.bg} stroke={c.ring} strokeWidth="1" />
|
|
@@ -975,7 +1447,7 @@ export function TopoGraph({ sessions, sseSessions }: TopoGraphProps) {
|
|
|
975
1447
|
dy="0.34em"
|
|
976
1448
|
textAnchor="middle"
|
|
977
1449
|
fill={c.text}
|
|
978
|
-
fontSize={
|
|
1450
|
+
fontSize={ar}
|
|
979
1451
|
fontFamily="monospace"
|
|
980
1452
|
fontWeight="700"
|
|
981
1453
|
>
|
|
@@ -984,12 +1456,32 @@ export function TopoGraph({ sessions, sseSessions }: TopoGraphProps) {
|
|
|
984
1456
|
</>
|
|
985
1457
|
);
|
|
986
1458
|
})()}
|
|
1459
|
+
{/* Issue #96: runtime badge — small corner glyph marking the
|
|
1460
|
+
execution shell (CLI / SDK / HTTP API). Sits bottom-right
|
|
1461
|
+
of the avatar; colours kept off the working/idle/offline
|
|
1462
|
+
status hues. Absent when the node reports no runtime. */}
|
|
1463
|
+
{(() => {
|
|
1464
|
+
const rt = runtimeIdentity(session.runtime);
|
|
1465
|
+
if (!rt) return null;
|
|
1466
|
+
const br = isOnline ? 7 : 5.5;
|
|
1467
|
+
const bx = pos.x + radius * 0.72;
|
|
1468
|
+
const by = pos.y + radius * 0.72;
|
|
1469
|
+
const icon = br * 2 * 0.62;
|
|
1470
|
+
return (
|
|
1471
|
+
<g style={{ pointerEvents: 'none' }}>
|
|
1472
|
+
<circle cx={bx} cy={by} r={br} fill={pal.containerBg} stroke={rt.color} strokeWidth="1.5" />
|
|
1473
|
+
<g transform={`translate(${bx - icon / 2} ${by - icon / 2}) scale(${icon / 24})`}>
|
|
1474
|
+
<path d={rt.iconPath} fill="none" stroke={rt.color} strokeWidth="2.4" strokeLinecap="round" strokeLinejoin="round" />
|
|
1475
|
+
</g>
|
|
1476
|
+
</g>
|
|
1477
|
+
);
|
|
1478
|
+
})()}
|
|
987
1479
|
{session.status === 'working' && (
|
|
988
1480
|
// working pulse — small dot just inside the status ring,
|
|
989
1481
|
// above the avatar text. Was a 18px horizontal bar at
|
|
990
1482
|
// y+11 which now collides with the avatar; the dot reads
|
|
991
1483
|
// as the same "active" cue without occluding the initial.
|
|
992
|
-
<circle cx={pos.x} cy={pos.y - (
|
|
1484
|
+
<circle cx={pos.x} cy={pos.y - (radius - 6)} r="2.5" fill={pal.flowParticle}>
|
|
993
1485
|
<animate attributeName="opacity" values="1;0.25;1" dur="1.1s" repeatCount="indefinite" />
|
|
994
1486
|
</circle>
|
|
995
1487
|
)}
|
|
@@ -998,61 +1490,112 @@ export function TopoGraph({ sessions, sseSessions }: TopoGraphProps) {
|
|
|
998
1490
|
Round 109/110 (Vincent P0): full opaque card below the
|
|
999
1491
|
density threshold / on hover / when zoomed; otherwise a
|
|
1000
1492
|
lightweight plain-text alias that keeps every node
|
|
1001
|
-
labelled without an opaque box covering its neighbours.
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1493
|
+
labelled without an opaque box covering its neighbours.
|
|
1494
|
+
Round 15 / Loop: when nodeScale=S the node shrinks 30%
|
|
1495
|
+
but the label card was staying full-size, so the label
|
|
1496
|
+
visually outweighed the small node. Tighten the card
|
|
1497
|
+
frame, alias / sub fontSize, drop-offset and truncate
|
|
1498
|
+
length specifically for S; M and L keep their existing
|
|
1499
|
+
sizes (M ≈ L for labels by design — the S user is the
|
|
1500
|
+
one who explicitly asked for a denser view). */}
|
|
1501
|
+
{(() => {
|
|
1502
|
+
const isSmall = nodeScale < 0.8;
|
|
1503
|
+
const cardW = isSmall ? 88 : 100;
|
|
1504
|
+
const cardH = isSmall ? 36 : 42;
|
|
1505
|
+
const cardTopY = isSmall ? -12 : -14;
|
|
1506
|
+
const aliasFs = isSmall ? 11 : 12;
|
|
1507
|
+
const subFs = isSmall ? 8 : 9;
|
|
1508
|
+
const subY = isSmall ? 15 : 17;
|
|
1509
|
+
const dropY = isSmall ? 18 : 22;
|
|
1510
|
+
const fullMax = isSmall ? 11 : 12;
|
|
1511
|
+
const denseFs = isSmall ? 9 : 10;
|
|
1512
|
+
const denseDrop = isSmall ? 12 : 14;
|
|
1513
|
+
return showFullLabel ? (
|
|
1514
|
+
<g transform={`translate(${pos.x}, ${pos.y + radius + dropY})`} style={{ pointerEvents: 'none' }}>
|
|
1515
|
+
<rect x={-cardW / 2} y={cardTopY} width={cardW} height={cardH} rx="6" fill={pal.labelBox.fill} stroke={pal.labelBox.stroke} opacity={isLight ? 1 : 0.94} />
|
|
1516
|
+
<text x="0" y="1" textAnchor="middle" fill={status.text} fontSize={aliasFs} fontFamily="monospace" fontWeight="700">
|
|
1517
|
+
{truncate(session.alias, fullMax)}
|
|
1518
|
+
</text>
|
|
1519
|
+
<text x="0" y={subY} textAnchor="middle" fill={status.primary} fontSize={subFs} fontFamily="monospace">
|
|
1520
|
+
{status.label}{isOnline && sseCountFor != null ? ` sse:${sseCountFor}` : ''}
|
|
1521
|
+
</text>
|
|
1522
|
+
</g>
|
|
1523
|
+
) : (
|
|
1524
|
+
<text
|
|
1525
|
+
x={pos.x}
|
|
1526
|
+
y={pos.y + radius + denseDrop}
|
|
1527
|
+
textAnchor="middle"
|
|
1528
|
+
fill={status.text}
|
|
1529
|
+
fontSize={denseFs}
|
|
1530
|
+
fontFamily="monospace"
|
|
1531
|
+
fontWeight="700"
|
|
1532
|
+
opacity={0.9}
|
|
1533
|
+
style={{ pointerEvents: 'none', paintOrder: 'stroke' }}
|
|
1534
|
+
stroke={pal.containerBg}
|
|
1535
|
+
strokeWidth="3"
|
|
1536
|
+
>
|
|
1537
|
+
{truncate(session.alias, isSmall ? 9 : 10)}
|
|
1010
1538
|
</text>
|
|
1011
|
-
|
|
1012
|
-
)
|
|
1013
|
-
<text
|
|
1014
|
-
x={pos.x}
|
|
1015
|
-
y={pos.y + radius + 14}
|
|
1016
|
-
textAnchor="middle"
|
|
1017
|
-
fill={status.text}
|
|
1018
|
-
fontSize="10"
|
|
1019
|
-
fontFamily="monospace"
|
|
1020
|
-
fontWeight="700"
|
|
1021
|
-
opacity={0.9}
|
|
1022
|
-
style={{ pointerEvents: 'none', paintOrder: 'stroke' }}
|
|
1023
|
-
stroke={pal.containerBg}
|
|
1024
|
-
strokeWidth="3"
|
|
1025
|
-
>
|
|
1026
|
-
{truncate(session.alias, 10)}
|
|
1027
|
-
</text>
|
|
1028
|
-
)}
|
|
1539
|
+
);
|
|
1540
|
+
})()}
|
|
1029
1541
|
</g>
|
|
1030
1542
|
);
|
|
1031
1543
|
})}
|
|
1032
1544
|
|
|
1545
|
+
{/* Round 14 / Loop: click ripple — one-shot expanding ring from
|
|
1546
|
+
the clicked node, ~500ms, status-coloured. Sits inside the
|
|
1547
|
+
zoom/pan <g> so it scales / pans with the topology. Keyed by
|
|
1548
|
+
ts so a re-click on any node (same or different) remounts the
|
|
1549
|
+
<circle> and the SMIL <animate> elements replay from t=0.
|
|
1550
|
+
strokeWidth=2 doesn't match the overlap-test selectors. */}
|
|
1551
|
+
{clickRipple && (
|
|
1552
|
+
<circle
|
|
1553
|
+
key={clickRipple.ts}
|
|
1554
|
+
cx={clickRipple.x}
|
|
1555
|
+
cy={clickRipple.y}
|
|
1556
|
+
r={clickRipple.r0 + 4}
|
|
1557
|
+
fill="none"
|
|
1558
|
+
stroke={clickRipple.color}
|
|
1559
|
+
strokeWidth="2"
|
|
1560
|
+
opacity="0"
|
|
1561
|
+
style={{ pointerEvents: 'none' }}
|
|
1562
|
+
>
|
|
1563
|
+
<animate attributeName="r" values={`${clickRipple.r0 + 4};${clickRipple.r0 + 30}`} dur="0.5s" fill="freeze" />
|
|
1564
|
+
<animate attributeName="opacity" values="0.7;0" dur="0.5s" fill="freeze" />
|
|
1565
|
+
</circle>
|
|
1566
|
+
)}
|
|
1567
|
+
|
|
1568
|
+
</g>
|
|
1569
|
+
|
|
1570
|
+
{/* #112: overlay panels (recent-signal + legend) render OUTSIDE the
|
|
1571
|
+
zoom/pan <g> so they stay fixed while the topology pans/zooms.
|
|
1572
|
+
They're sized + tucked into the top corners so every corner of
|
|
1573
|
+
each panel is >325px from the canvas centre — i.e. fully outside
|
|
1574
|
+
the outermost (offline) ring. No node on any ring can reach the
|
|
1575
|
+
corner triangles, so the panels never overlap a node, in ring
|
|
1576
|
+
OR grid layout (Vincent 4727 zero-overlap criterion). */}
|
|
1033
1577
|
{/* latest flow labels */}
|
|
1034
|
-
<g transform="translate(
|
|
1035
|
-
<rect x="0" y="0" width="
|
|
1036
|
-
<text x="
|
|
1037
|
-
<text x="
|
|
1038
|
-
{flowLinks.slice(0,
|
|
1039
|
-
<text key={link.key} x="
|
|
1040
|
-
{truncate(link.from,
|
|
1578
|
+
<g transform="translate(16, 16)">
|
|
1579
|
+
<rect x="0" y="0" width="230" height="84" rx="10" fill={pal.legendBox.fill} stroke={pal.legendBox.stroke} opacity={isLight ? 0.97 : 0.92} />
|
|
1580
|
+
<text x="13" y="21" fill={pal.legendHeadline} fontSize="12" fontFamily="monospace" fontWeight="700">recent signal</text>
|
|
1581
|
+
<text x="150" y="21" fill={pal.legendAccent} fontSize="10" fontFamily="monospace">{messages.length} msgs</text>
|
|
1582
|
+
{flowLinks.slice(0, 3).map((link, index) => (
|
|
1583
|
+
<text key={link.key} x="13" y={38 + index * 16} fill={pal.legendText} fontSize="9" fontFamily="monospace">
|
|
1584
|
+
{truncate(link.from, 6)} {'->'} {truncate(link.to, 6)} / {link.count} / {truncate(link.content, 12)}
|
|
1041
1585
|
</text>
|
|
1042
1586
|
))}
|
|
1043
1587
|
</g>
|
|
1044
1588
|
|
|
1045
1589
|
{/* legend */}
|
|
1046
|
-
<g transform="translate(
|
|
1047
|
-
<rect x="0" y="0" width="
|
|
1048
|
-
<circle cx="
|
|
1049
|
-
<text x="
|
|
1050
|
-
<circle cx="
|
|
1051
|
-
<text x="
|
|
1052
|
-
<circle cx="
|
|
1053
|
-
<text x="
|
|
1054
|
-
<path d="
|
|
1055
|
-
</g>
|
|
1590
|
+
<g transform="translate(760, 16)">
|
|
1591
|
+
<rect x="0" y="0" width="224" height="96" rx="10" fill={pal.legendBox.fill} stroke={pal.legendBox.stroke} opacity={isLight ? 0.97 : 0.92} />
|
|
1592
|
+
<circle cx="16" cy="24" r="5.5" fill={isLight ? '#059669' : '#22c55e'} />
|
|
1593
|
+
<text x="30" y="28" fill={pal.legendText} fontSize="11" fontFamily="monospace">working node</text>
|
|
1594
|
+
<circle cx="16" cy="48" r="5.5" fill={isLight ? '#0d9488' : '#2dd4bf'} />
|
|
1595
|
+
<text x="30" y="52" fill={pal.legendText} fontSize="11" fontFamily="monospace">online idle</text>
|
|
1596
|
+
<circle cx="16" cy="72" r="5.5" fill={isLight ? '#94a3b8' : '#6b7280'} />
|
|
1597
|
+
<text x="30" y="76" fill={pal.legendText} fontSize="11" fontFamily="monospace">offline / no SSE</text>
|
|
1598
|
+
<path d="M140,72 Q164,48 196,72" fill="none" stroke={pal.flowEdge} strokeWidth="3" markerEnd="url(#topo-arrow)" />
|
|
1056
1599
|
</g>
|
|
1057
1600
|
</svg>
|
|
1058
1601
|
|
|
@@ -1063,6 +1606,26 @@ export function TopoGraph({ sessions, sseSessions }: TopoGraphProps) {
|
|
|
1063
1606
|
Split into a plain % readout + an explicit reset button with
|
|
1064
1607
|
its own icon + tooltip. */}
|
|
1065
1608
|
<div className="absolute bottom-3 right-3 flex items-center gap-1.5 text-xs select-none">
|
|
1609
|
+
{/* #113: node size — S / M / L segmented control (Vincent 4727). */}
|
|
1610
|
+
<div
|
|
1611
|
+
className="flex items-center rounded-md border overflow-hidden"
|
|
1612
|
+
style={{ background: pal.legendBox.fill, borderColor: pal.containerBorder }}
|
|
1613
|
+
role="group"
|
|
1614
|
+
aria-label="Node size"
|
|
1615
|
+
>
|
|
1616
|
+
{([['S', 0.7], ['M', 0.84], ['L', 1]] as const).map(([lbl, v], idx) => (
|
|
1617
|
+
<button
|
|
1618
|
+
key={lbl}
|
|
1619
|
+
onClick={() => pickNodeScale(v)}
|
|
1620
|
+
aria-pressed={nodeScale === v}
|
|
1621
|
+
title={`Node size: ${lbl === 'S' ? 'small' : lbl === 'M' ? 'medium' : 'large'}`}
|
|
1622
|
+
className={`px-2 py-1 transition-colors ${idx > 0 ? 'border-l' : ''} ${nodeScale === v ? 'bg-cyan-500/15 text-cyan-300' : 'hover:bg-white/5'}`}
|
|
1623
|
+
style={{ color: nodeScale === v ? undefined : pal.legendText, borderColor: pal.containerBorder }}
|
|
1624
|
+
>
|
|
1625
|
+
{lbl}
|
|
1626
|
+
</button>
|
|
1627
|
+
))}
|
|
1628
|
+
</div>
|
|
1066
1629
|
<div
|
|
1067
1630
|
className="flex items-center rounded-md border overflow-hidden"
|
|
1068
1631
|
style={{ background: pal.legendBox.fill, borderColor: pal.containerBorder }}
|
|
@@ -1072,6 +1635,7 @@ export function TopoGraph({ sessions, sseSessions }: TopoGraphProps) {
|
|
|
1072
1635
|
className="px-2 py-1 hover:bg-white/5 transition-colors"
|
|
1073
1636
|
style={{ color: pal.legendText }}
|
|
1074
1637
|
aria-label="Zoom out"
|
|
1638
|
+
title="Zoom out (−)"
|
|
1075
1639
|
>
|
|
1076
1640
|
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" aria-hidden><path d="M5 12h14" /></svg>
|
|
1077
1641
|
</button>
|
|
@@ -1087,6 +1651,7 @@ export function TopoGraph({ sessions, sseSessions }: TopoGraphProps) {
|
|
|
1087
1651
|
className="px-2 py-1 hover:bg-white/5 transition-colors"
|
|
1088
1652
|
style={{ color: pal.legendText }}
|
|
1089
1653
|
aria-label="Zoom in"
|
|
1654
|
+
title="Zoom in (+)"
|
|
1090
1655
|
>
|
|
1091
1656
|
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" aria-hidden><path d="M12 5v14M5 12h14" /></svg>
|
|
1092
1657
|
</button>
|
|
@@ -1096,7 +1661,7 @@ export function TopoGraph({ sessions, sseSessions }: TopoGraphProps) {
|
|
|
1096
1661
|
className="p-1.5 rounded-md border hover:bg-white/5 transition-colors"
|
|
1097
1662
|
style={{ background: pal.legendBox.fill, borderColor: pal.containerBorder, color: pal.legendText }}
|
|
1098
1663
|
aria-label="Reset view"
|
|
1099
|
-
title="Reset zoom + pan (or double-click the canvas)"
|
|
1664
|
+
title="Reset zoom + pan (0, or double-click the canvas)"
|
|
1100
1665
|
>
|
|
1101
1666
|
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden>
|
|
1102
1667
|
<path d="M3 12a9 9 0 1 0 9-9 9 9 0 0 0-6.4 2.6L3 8" />
|