@sleep2agi/agent-network-dashboard 0.4.6-preview.17 → 0.4.6-preview.170
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-manifest.json +3 -3
- package/.next/diagnostics/route-bundle-stats.json +41 -41
- package/.next/fallback-build-manifest.json +3 -3
- package/.next/prerender-manifest.json +3 -3
- package/.next/routes-manifest.json +6 -0
- package/.next/server/app/_global-error.html +1 -1
- package/.next/server/app/_global-error.rsc +1 -1
- package/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
- package/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/.next/server/app/_global-error.segments/_tree.segment.rsc +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_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/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/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_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_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_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_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_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_client-reference-manifest.js +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_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_client-reference-manifest.js +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_client-reference-manifest.js +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/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_servers_route_actions_08-m-cs.js.map +1 -0
- package/.next/server/chunks/[root-of-the-server]__0tx8s8i._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__0tx8s8i._.js.map +1 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__03b.f76._.js +1 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__03b.f76._.js.map +1 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__0fhoq8i._.js +1 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__0fhoq8i._.js.map +1 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__0nw~zhp._.js +1 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__0nw~zhp._.js.map +1 -1
- package/.next/server/chunks/ssr/agent-network-dashboard_09kk21a._.js +4 -1
- package/.next/server/chunks/ssr/agent-network-dashboard_09kk21a._.js.map +1 -1
- package/.next/server/chunks/ssr/agent-network-dashboard_app_01jhlxz._.js +1 -1
- package/.next/server/chunks/ssr/agent-network-dashboard_app_01jhlxz._.js.map +1 -1
- package/.next/server/chunks/ssr/agent-network-dashboard_app_057q.ne._.js +1 -1
- package/.next/server/chunks/ssr/agent-network-dashboard_app_057q.ne._.js.map +1 -1
- package/.next/server/chunks/ssr/agent-network-dashboard_app_09d29my._.js +1 -1
- package/.next/server/chunks/ssr/agent-network-dashboard_app_09d29my._.js.map +1 -1
- package/.next/server/chunks/ssr/agent-network-dashboard_app_0_d45-d._.js +1 -1
- package/.next/server/chunks/ssr/agent-network-dashboard_app_0_d45-d._.js.map +1 -1
- package/.next/server/chunks/ssr/agent-network-dashboard_app_0i3759l._.js +1 -1
- package/.next/server/chunks/ssr/agent-network-dashboard_app_0i3759l._.js.map +1 -1
- package/.next/server/chunks/ssr/agent-network-dashboard_app_0xgney8._.js +1 -1
- package/.next/server/chunks/ssr/agent-network-dashboard_app_0xgney8._.js.map +1 -1
- package/.next/server/chunks/ssr/agent-network-dashboard_app_10hjgv4._.js +1 -1
- package/.next/server/chunks/ssr/agent-network-dashboard_app_10hjgv4._.js.map +1 -1
- package/.next/server/chunks/ssr/agent-network-dashboard_app_1153xeb._.js +1 -1
- package/.next/server/chunks/ssr/agent-network-dashboard_app_1153xeb._.js.map +1 -1
- package/.next/server/chunks/ssr/agent-network-dashboard_app_12l4oto._.js +1 -1
- package/.next/server/chunks/ssr/agent-network-dashboard_app_12l4oto._.js.map +1 -1
- package/.next/server/chunks/ssr/agent-network-dashboard_app_components_0mvyi-4._.js +1 -1
- package/.next/server/chunks/ssr/agent-network-dashboard_app_components_0mvyi-4._.js.map +1 -1
- package/.next/server/middleware-build-manifest.js +3 -3
- 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-mpa_947ipeq.js +1 -0
- package/.next/static/chunks/01lmbsd37fybu.js +1 -0
- package/.next/static/chunks/03o.h6kvmw4l_.js +1 -0
- package/.next/static/chunks/03~~oirxz7~vc.js +1 -0
- package/.next/static/chunks/050s9ndkk07i9.js +1 -0
- package/.next/static/chunks/05uk96gc~9mni.js +1 -0
- package/.next/static/chunks/08kf-.bgs10ze.js +1 -0
- package/.next/static/chunks/0d7u.7_u.l9sh.js +4 -0
- package/.next/static/chunks/0ggj5ummw2a84.js +7 -0
- package/.next/static/chunks/0glmrdj9112tc.js +7 -0
- package/.next/static/chunks/0gvra4akqlit0.js +1 -0
- package/.next/static/chunks/0otgjhpse~amj.css +2 -0
- package/.next/static/chunks/0rxrez_cjn.eh.js +1 -0
- package/.next/static/chunks/0x8x.29hkju5a.js +1 -0
- package/.next/static/chunks/174re5ar~kxne.js +1 -0
- 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/ChatPopover.tsx +38 -2
- package/app/components/CommandPalette.tsx +107 -0
- package/app/components/HelpOverlay.tsx +126 -0
- package/app/components/ServersDrawer.tsx +64 -27
- package/app/components/TopoGraph.tsx +3338 -241
- package/app/components/utils.ts +8 -7
- package/app/globals.css +75 -5
- package/app/lib/time.ts +36 -0
- package/package.json +1 -1
- package/scripts/help-overlay-topo-test.mjs +44 -0
- package/scripts/servers-drawer-live-test.mjs +96 -0
- package/scripts/topo-active-filter-pill-test.mjs +101 -0
- package/scripts/topo-active-links-chip-hover-test.mjs +103 -0
- package/scripts/topo-active-links-chip-nav-test.mjs +117 -0
- package/scripts/topo-active-links-chip-test.mjs +73 -0
- package/scripts/topo-active-links-freshness-test.mjs +113 -0
- package/scripts/topo-active-links-tooltip-test.mjs +79 -0
- package/scripts/topo-arrival-ping-test.mjs +87 -0
- package/scripts/topo-arrow-tier-test.mjs +61 -0
- package/scripts/topo-auto-fit-test.mjs +73 -0
- package/scripts/topo-canvas-aria-test.mjs +108 -0
- package/scripts/topo-chat-focus-ring-test.mjs +77 -0
- package/scripts/topo-chat-target-breath-test.mjs +84 -0
- package/scripts/topo-chip-focus-test.mjs +95 -0
- package/scripts/topo-chip-pin-mirror-test.mjs +113 -0
- package/scripts/topo-chrome-a11y-test.mjs +107 -0
- package/scripts/topo-click-ripple-test.mjs +66 -0
- package/scripts/topo-cmdk-edge-clear-test.mjs +109 -0
- package/scripts/topo-cmdk-layout-view-test.mjs +108 -0
- package/scripts/topo-cmdk-pin-test.mjs +123 -0
- package/scripts/topo-cmdk-vendor-clear-test.mjs +133 -0
- package/scripts/topo-cmdk-vendor-pin-test.mjs +103 -0
- package/scripts/topo-cwd-tooltip-test.mjs +64 -0
- package/scripts/topo-dblclick-reset-test.mjs +74 -0
- package/scripts/topo-dispatch-pulse-test.mjs +83 -0
- package/scripts/topo-edge-badge-click-pin-test.mjs +94 -0
- package/scripts/topo-edge-badge-hot-test.mjs +115 -0
- package/scripts/topo-edge-badge-hover-test.mjs +85 -0
- package/scripts/topo-edge-count-badge-test.mjs +86 -0
- package/scripts/topo-edge-endpoint-highlight-test.mjs +111 -0
- package/scripts/topo-edge-focus-test.mjs +113 -0
- package/scripts/topo-edge-hover-test.mjs +93 -0
- package/scripts/topo-edge-pill-hot-test.mjs +129 -0
- package/scripts/topo-edge-pill-test.mjs +105 -0
- package/scripts/topo-edge-tooltip-test.mjs +70 -0
- package/scripts/topo-endpoint-ring-test.mjs +93 -0
- package/scripts/topo-esc-clears-pin-test.mjs +98 -0
- package/scripts/topo-filter-pill-aliases-test.mjs +121 -0
- package/scripts/topo-filter-pill-body-click-test.mjs +112 -0
- package/scripts/topo-filter-pill-count-test.mjs +110 -0
- package/scripts/topo-filter-pill-mobile-test.mjs +90 -0
- package/scripts/topo-fit-key-test.mjs +106 -0
- package/scripts/topo-freshness-chip-test.mjs +74 -0
- package/scripts/topo-group-box-pinned-state-test.mjs +95 -0
- package/scripts/topo-group-count-test.mjs +68 -0
- package/scripts/topo-group-hover-test.mjs +82 -0
- package/scripts/topo-group-label-a11y-test.mjs +113 -0
- package/scripts/topo-group-label-hover-test.mjs +119 -0
- package/scripts/topo-group-label-tint-test.mjs +99 -0
- package/scripts/topo-group-label-title-test.mjs +83 -0
- package/scripts/topo-group-pin-test.mjs +119 -0
- package/scripts/topo-group-status-pips-test.mjs +103 -0
- package/scripts/topo-groupbox-hover-lift-test.mjs +127 -0
- package/scripts/topo-groupbox-live-test.mjs +100 -0
- package/scripts/topo-groupbox-march-busyness-test.mjs +155 -0
- package/scripts/topo-groupbox-test.mjs +4 -2
- package/scripts/topo-help-overlay-r109-test.mjs +67 -0
- package/scripts/topo-help-overlay-r118-test.mjs +69 -0
- package/scripts/topo-help-overlay-r123-test.mjs +69 -0
- package/scripts/topo-help-overlay-r134-test.mjs +74 -0
- package/scripts/topo-help-overlay-r137-test.mjs +81 -0
- package/scripts/topo-help-overlay-r141-test.mjs +86 -0
- package/scripts/topo-help-overlay-r153-test.mjs +85 -0
- package/scripts/topo-help-overlay-r59-test.mjs +67 -0
- package/scripts/topo-help-overlay-r65-test.mjs +64 -0
- package/scripts/topo-help-overlay-r70-test.mjs +63 -0
- package/scripts/topo-help-overlay-r78-test.mjs +59 -0
- package/scripts/topo-help-overlay-r81-test.mjs +58 -0
- package/scripts/topo-help-overlay-r87-test.mjs +64 -0
- package/scripts/topo-help-overlay-r91-test.mjs +65 -0
- package/scripts/topo-hub-a11y-test.mjs +112 -0
- package/scripts/topo-hub-busyness-test.mjs +100 -0
- package/scripts/topo-hub-click-fit-test.mjs +137 -0
- package/scripts/topo-hub-hover-ring-test.mjs +82 -0
- package/scripts/topo-hub-title-test.mjs +93 -0
- package/scripts/topo-hub-working-count-test.mjs +99 -0
- package/scripts/topo-ingroup-edge-test.mjs +103 -0
- package/scripts/topo-label-lift-test.mjs +119 -0
- package/scripts/topo-label-scale-test.mjs +78 -0
- package/scripts/topo-lastseen-tooltip-test.mjs +59 -0
- package/scripts/topo-layout-key-test.mjs +91 -0
- package/scripts/topo-layout-toggle-test.mjs +131 -0
- package/scripts/topo-legend-count-test.mjs +88 -0
- package/scripts/topo-legend-hover-test.mjs +113 -0
- package/scripts/topo-legend-panel-header-test.mjs +83 -0
- package/scripts/topo-legend-pin-test.mjs +128 -0
- package/scripts/topo-legend-row-hover-lift-test.mjs +109 -0
- package/scripts/topo-legend-row-tint-test.mjs +95 -0
- package/scripts/topo-legend-row-title-test.mjs +102 -0
- package/scripts/topo-minimap-a11y-test.mjs +101 -0
- package/scripts/topo-minimap-test.mjs +68 -0
- package/scripts/topo-mobile-chips-test.mjs +103 -0
- package/scripts/topo-node-a11y-test.mjs +107 -0
- package/scripts/topo-node-hover-lift-test.mjs +85 -0
- package/scripts/topo-node-title-peers-test.mjs +107 -0
- package/scripts/topo-node-title-test.mjs +101 -0
- package/scripts/topo-offline-dim-test.mjs +70 -0
- package/scripts/topo-online-chip-nav-test.mjs +143 -0
- package/scripts/topo-orbit-busyness-test.mjs +96 -0
- package/scripts/topo-overlap-test.mjs +32 -5
- package/scripts/topo-pan-cursor-test.mjs +62 -0
- package/scripts/topo-panel-elevation-test.mjs +76 -0
- package/scripts/topo-panel-hover-elevation-test.mjs +118 -0
- package/scripts/topo-particle-stagger-test.mjs +82 -0
- package/scripts/topo-pin-intersection-empty-test.mjs +129 -0
- package/scripts/topo-pin-intersection-test.mjs +121 -0
- package/scripts/topo-pin-persistence-test.mjs +105 -0
- package/scripts/topo-popover-meta-test.mjs +78 -0
- package/scripts/topo-pressure-bar-test.mjs +69 -0
- package/scripts/topo-pressure-hover-test.mjs +123 -0
- package/scripts/topo-pressure-pin-test.mjs +119 -0
- package/scripts/topo-pressure-seg-tooltip-test.mjs +98 -0
- package/scripts/topo-pulse-rate-test.mjs +71 -0
- package/scripts/topo-recent-panel-count-freshness-test.mjs +109 -0
- package/scripts/topo-recent-panel-count-test.mjs +72 -0
- package/scripts/topo-recent-panel-hot-header-test.mjs +132 -0
- package/scripts/topo-recent-panel-more-nav-test.mjs +127 -0
- package/scripts/topo-recent-panel-more-test.mjs +106 -0
- package/scripts/topo-recent-row-freshness-test.mjs +102 -0
- package/scripts/topo-recent-row-hot-test.mjs +110 -0
- package/scripts/topo-recent-row-hover-lift-test.mjs +128 -0
- package/scripts/topo-recent-row-hover-test.mjs +122 -0
- package/scripts/topo-recent-row-pin-test.mjs +126 -0
- package/scripts/topo-recent-row-tint-test.mjs +91 -0
- package/scripts/topo-recent-row-title-test.mjs +112 -0
- package/scripts/topo-recent-row-ts-test.mjs +95 -0
- package/scripts/topo-recent-row-typography-test.mjs +119 -0
- package/scripts/topo-recent-signal-empty-hint-test.mjs +73 -0
- package/scripts/topo-recent-signal-empty-test.mjs +63 -0
- package/scripts/topo-reduced-motion-test.mjs +77 -0
- package/scripts/topo-spoke-busyness-test.mjs +110 -0
- package/scripts/topo-status-chip-hover-test.mjs +101 -0
- package/scripts/topo-status-chip-tooltip-test.mjs +95 -0
- package/scripts/topo-svg-focus-test.mjs +112 -0
- package/scripts/topo-sweep-busyness-test.mjs +94 -0
- package/scripts/topo-tier-ring-occupancy-test.mjs +87 -0
- package/scripts/topo-tier-ring-test.mjs +69 -0
- package/scripts/topo-tier-ring-tint-test.mjs +110 -0
- package/scripts/topo-tier-stagger-test.mjs +89 -0
- package/scripts/topo-tz-ghost-test.mjs +69 -0
- package/scripts/topo-vendor-chip-hover-test.mjs +111 -0
- package/scripts/topo-vendor-letter-tooltip-test.mjs +92 -0
- package/scripts/topo-vendor-pill-test.mjs +125 -0
- package/scripts/topo-vendor-pin-test.mjs +125 -0
- package/scripts/topo-wheel-zoom-test.mjs +79 -0
- package/scripts/topo-working-chip-pin-test.mjs +148 -0
- package/scripts/topo-working-halo-breath-test.mjs +86 -0
- package/scripts/topo-zoom-keys-test.mjs +89 -0
- package/.next/static/chunks/0-7iowzu4.798.js +0 -1
- package/.next/static/chunks/02t5jr4shh.hy.js +0 -1
- package/.next/static/chunks/096hkjkwj4hb3.js +0 -1
- package/.next/static/chunks/0_qfg5s5uzs7..js +0 -7
- package/.next/static/chunks/0d6xn54cd2zo-.js +0 -1
- package/.next/static/chunks/0elalb9n_.~di.js +0 -1
- package/.next/static/chunks/0fqy_0wj_1xa7.js +0 -7
- package/.next/static/chunks/0iv2-b3po~sbg.js +0 -1
- package/.next/static/chunks/0j_q__o8p6g83.js +0 -1
- package/.next/static/chunks/0jl6_w50zh4l5.js +0 -1
- package/.next/static/chunks/0r4q73.-1bkyl.js +0 -1
- package/.next/static/chunks/0r_c8eccg3z2o.js +0 -1
- package/.next/static/chunks/10oi7l-tycgl9.js +0 -1
- package/.next/static/chunks/11uk1izuv3~0t.js +0 -1
- package/.next/static/chunks/13vw-ubg-9pjp.css +0 -2
- /package/.next/static/{TBtREVf7o4zYSqGqq3QT5 → m3FtdjT1mdUIOaZp0o9gq}/_buildManifest.js +0 -0
- /package/.next/static/{TBtREVf7o4zYSqGqq3QT5 → m3FtdjT1mdUIOaZp0o9gq}/_clientMiddlewareManifest.js +0 -0
- /package/.next/static/{TBtREVf7o4zYSqGqq3QT5 → m3FtdjT1mdUIOaZp0o9gq}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/* Round 42 verification: "X active links" chip in the header includes
|
|
2
|
+
* "· last <relative>" when flow links exist, drops the `· last …` tail
|
|
3
|
+
* when no flow links are present, and renders singular/plural correctly. */
|
|
4
|
+
import { chromium } from 'playwright';
|
|
5
|
+
import { readFileSync } from 'node:fs';
|
|
6
|
+
|
|
7
|
+
const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
|
|
8
|
+
const browser = await chromium.launch({ headless: true });
|
|
9
|
+
|
|
10
|
+
async function probe({ msgs }) {
|
|
11
|
+
const ctx = await browser.newContext({ viewport: { width: 1400, height: 1000 } });
|
|
12
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
13
|
+
await ctx.addInitScript(() => {
|
|
14
|
+
try {
|
|
15
|
+
localStorage.setItem('anet-theme', 'cyber');
|
|
16
|
+
localStorage.setItem('anet-topo-layout', 'grid');
|
|
17
|
+
sessionStorage.setItem('anet_v3_auth', '1');
|
|
18
|
+
} catch {}
|
|
19
|
+
});
|
|
20
|
+
const fresh = new Date(Date.now() - 60 * 1000).toISOString();
|
|
21
|
+
await ctx.route('**/api/hub/status*', async (route) => {
|
|
22
|
+
const r = await route.fetch();
|
|
23
|
+
const b = await r.json();
|
|
24
|
+
const nid = (b.sessions || [])[0]?.network_id || 'default';
|
|
25
|
+
const sessions = ['alpha', 'beta', 'gamma'].map(a => ({
|
|
26
|
+
alias: a, status: 'idle', network_id: nid, project_dir: null,
|
|
27
|
+
created_at: fresh, updated_at: fresh, last_seen_at: fresh,
|
|
28
|
+
}));
|
|
29
|
+
await route.fulfill({ response: r, json: { ...b, sessions } });
|
|
30
|
+
});
|
|
31
|
+
await ctx.route('**/api/hub/messages*', (route) => route.fulfill({ json: { messages: msgs } }));
|
|
32
|
+
await ctx.route('**/api/hub/tasks*', (route) => route.fulfill({ json: { tasks: [] } }));
|
|
33
|
+
const page = await ctx.newPage();
|
|
34
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
|
|
35
|
+
await page.waitForSelector('svg[viewBox="0 0 1000 680"]', { timeout: 30000 });
|
|
36
|
+
await page.waitForTimeout(500);
|
|
37
|
+
const text = await page.evaluate(() => {
|
|
38
|
+
// The active-links chip is the LAST chip in the topo header row (after
|
|
39
|
+
// pressure-bar + vendor + working/online). Match by `active link`.
|
|
40
|
+
const spans = [...document.querySelectorAll('span')];
|
|
41
|
+
return spans.find(s => /active link/.test(s.textContent || ''))?.textContent?.replace(/\s+/g, ' ').trim() || null;
|
|
42
|
+
});
|
|
43
|
+
await ctx.close();
|
|
44
|
+
return text;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// 1. No messages → 0 active links, no "· last X" tail
|
|
48
|
+
const empty = await probe({ msgs: [] });
|
|
49
|
+
// 2. One message just now → 1 active link · last Ns ago
|
|
50
|
+
const recent = await probe({ msgs: [
|
|
51
|
+
{ from_alias: 'alpha', to_alias: 'beta', content: 'hi', created_at: new Date(Date.now() - 30 * 1000).toISOString() },
|
|
52
|
+
] });
|
|
53
|
+
// 3. Five messages, latest 4 min ago → 5 active links · last 4m ago (singular link uses "link", plural "links")
|
|
54
|
+
const fourMinAgo = new Date(Date.now() - 4 * 60 * 1000).toISOString();
|
|
55
|
+
const eightMinAgo = new Date(Date.now() - 8 * 60 * 1000).toISOString();
|
|
56
|
+
const five = await probe({ msgs: [
|
|
57
|
+
{ from_alias: 'alpha', to_alias: 'beta', content: '1', created_at: eightMinAgo },
|
|
58
|
+
{ from_alias: 'alpha', to_alias: 'gamma', content: '2', created_at: eightMinAgo },
|
|
59
|
+
{ from_alias: 'alpha', to_alias: 'gamma', content: '3', created_at: eightMinAgo },
|
|
60
|
+
{ from_alias: 'beta', to_alias: 'gamma', content: '4', created_at: eightMinAgo },
|
|
61
|
+
{ from_alias: 'beta', to_alias: 'gamma', content: '5', created_at: fourMinAgo }, // latest
|
|
62
|
+
] });
|
|
63
|
+
|
|
64
|
+
await browser.close();
|
|
65
|
+
const results = {
|
|
66
|
+
emptyChipHasNoTail: empty === '0 active links',
|
|
67
|
+
recentSingularChip: recent !== null && /^1 active link · last \d+s ago$/.test(recent),
|
|
68
|
+
pluralChipShowsLatest: five !== null && /active links · last [34]m ago/.test(five),
|
|
69
|
+
};
|
|
70
|
+
const ok = Object.values(results).every(Boolean);
|
|
71
|
+
console.log(`${ok ? '✅' : '❌'} active-links chip:`, JSON.stringify(results),
|
|
72
|
+
`\n empty=${JSON.stringify(empty)}\n recent=${JSON.stringify(recent)}\n five=${JSON.stringify(five)}`);
|
|
73
|
+
process.exit(ok ? 0 : 1);
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/* Round 161 verification: active-links chip bullet picks up
|
|
2
|
+
* the R160 freshness vocabulary.
|
|
3
|
+
*
|
|
4
|
+
* R10 fades canvas flow edges by freshness. R160 brought that
|
|
5
|
+
* vocabulary to the recent-signal panel rows via a 1.6-px cyan
|
|
6
|
+
* pip at row left edge. R161 extends it one more scope — up to
|
|
7
|
+
* the fleet-aggregate active-links chip in the chip-row.
|
|
8
|
+
*
|
|
9
|
+
* The chip text was already "3 active links · last 5s ago" but
|
|
10
|
+
* the " · " separator was dead gray. R161 colors that bullet
|
|
11
|
+
* by freshness using the same alpha ramp:
|
|
12
|
+
* ageSec ≤ 30 → 1.0 (fully fresh)
|
|
13
|
+
* 30-300s → 1.0 → 0.25 smooth decay
|
|
14
|
+
* > 300s → 0.25 stale floor
|
|
15
|
+
*
|
|
16
|
+
* Three nested scopes now share one freshness ladder:
|
|
17
|
+
* canvas edge fade (R10) — per-edge visual
|
|
18
|
+
* row pip (R160) — per-flow row in recent-signal
|
|
19
|
+
* chip bullet (R161) — fleet aggregate in chip-row
|
|
20
|
+
*
|
|
21
|
+
* Test scenarios (one page load each):
|
|
22
|
+
* A. fresh most-recent flow (5s ago) → alpha ≈ 1.0, fontWeight 700
|
|
23
|
+
* B. mid recency (90s ago) → alpha ≈ 0.83
|
|
24
|
+
* C. stale (360s ago) → alpha ≈ 0.25 (floor)
|
|
25
|
+
*
|
|
26
|
+
* Color parses out of `rgba(34, 211, 238, 1)` cyber theme.
|
|
27
|
+
*/
|
|
28
|
+
import { chromium } from 'playwright';
|
|
29
|
+
import { readFileSync } from 'node:fs';
|
|
30
|
+
|
|
31
|
+
const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
|
|
32
|
+
const browser = await chromium.launch({ headless: true });
|
|
33
|
+
|
|
34
|
+
const ctx = await browser.newContext({ viewport: { width: 1500, height: 1500 } });
|
|
35
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
36
|
+
await ctx.addInitScript(() => {
|
|
37
|
+
try { localStorage.setItem('anet-theme', 'cyber'); sessionStorage.setItem('anet_v3_auth', '1'); } catch {}
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
async function probe(msgAgeSec) {
|
|
41
|
+
const fresh = new Date(Date.now() - 60 * 1000).toISOString();
|
|
42
|
+
await ctx.unroute('**/api/hub/status*').catch(() => {});
|
|
43
|
+
await ctx.unroute('**/api/hub/messages*').catch(() => {});
|
|
44
|
+
await ctx.unroute('**/api/hub/tasks*').catch(() => {});
|
|
45
|
+
await ctx.route('**/api/hub/status*', async (route) => {
|
|
46
|
+
const r = await route.fetch();
|
|
47
|
+
const b = await r.json();
|
|
48
|
+
const nid = (b.sessions || [])[0]?.network_id || 'default';
|
|
49
|
+
const mk = (alias) => ({
|
|
50
|
+
alias, status: 'working', model: 'claude-opus-4', runtime: 'cli-claude-code',
|
|
51
|
+
network_id: nid, project_dir: null,
|
|
52
|
+
created_at: fresh, updated_at: fresh, last_seen_at: fresh,
|
|
53
|
+
});
|
|
54
|
+
await route.fulfill({ response: r, json: { ...b, sessions: [mk('alpha'), mk('beta')] } });
|
|
55
|
+
});
|
|
56
|
+
await ctx.route('**/api/hub/messages*', (route) => route.fulfill({ json: { messages: [
|
|
57
|
+
{ id: 'x', from_alias: 'alpha', to_alias: 'beta', content: 'hi',
|
|
58
|
+
network_id: 'default', created_at: new Date(Date.now() - msgAgeSec * 1000).toISOString() },
|
|
59
|
+
] } }));
|
|
60
|
+
await ctx.route('**/api/hub/tasks*', (route) => route.fulfill({ json: { tasks: [] } }));
|
|
61
|
+
|
|
62
|
+
const page = await ctx.newPage();
|
|
63
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
|
|
64
|
+
await page.waitForFunction(() => document.querySelectorAll('g[data-node]').length === 2, { timeout: 30000 });
|
|
65
|
+
await page.waitForSelector('[data-active-links-freshness-dot]', { timeout: 10000 });
|
|
66
|
+
await page.waitForTimeout(400);
|
|
67
|
+
const out = await page.evaluate(() => {
|
|
68
|
+
const el = document.querySelector('[data-active-links-freshness-dot]');
|
|
69
|
+
if (!el) return null;
|
|
70
|
+
const styleColor = el.style.color || getComputedStyle(el).color;
|
|
71
|
+
return {
|
|
72
|
+
alpha: parseFloat(el.getAttribute('data-active-links-freshness-alpha') || ''),
|
|
73
|
+
color: styleColor,
|
|
74
|
+
fontWeight: el.style.fontWeight || getComputedStyle(el).fontWeight,
|
|
75
|
+
text: el.textContent,
|
|
76
|
+
};
|
|
77
|
+
});
|
|
78
|
+
await page.close();
|
|
79
|
+
return out;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const A = await probe(5); // fresh
|
|
83
|
+
const B = await probe(90); // mid
|
|
84
|
+
const C = await probe(360); // stale
|
|
85
|
+
|
|
86
|
+
await browser.close();
|
|
87
|
+
|
|
88
|
+
const cyanRgb = (str) => {
|
|
89
|
+
// Inline `style="color: rgba(34, 211, 238, ...)"` — alpha is part of color.
|
|
90
|
+
const m = /rgba?\((\d+),\s*(\d+),\s*(\d+)/.exec(str);
|
|
91
|
+
if (!m) return null;
|
|
92
|
+
return [Number(m[1]), Number(m[2]), Number(m[3])];
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
const results = {
|
|
96
|
+
fresh_dot_found: A !== null,
|
|
97
|
+
mid_dot_found: B !== null,
|
|
98
|
+
stale_dot_found: C !== null,
|
|
99
|
+
fresh_alpha_1: A && Math.abs(A.alpha - 1.0) < 0.05,
|
|
100
|
+
mid_alpha_window: B && B.alpha > 0.7 && B.alpha < 0.95,
|
|
101
|
+
stale_alpha_floor: C && Math.abs(C.alpha - 0.25) < 0.05,
|
|
102
|
+
fresh_color_cyan: A && JSON.stringify(cyanRgb(A.color)) === '[34,211,238]',
|
|
103
|
+
fresh_weight_bold: A && (A.fontWeight === '700' || A.fontWeight === 'bold'),
|
|
104
|
+
stale_weight_norm: C && (C.fontWeight === '400' || C.fontWeight === 'normal' || C.fontWeight === ''),
|
|
105
|
+
ladder_descends: A && B && C && A.alpha > B.alpha && B.alpha > C.alpha,
|
|
106
|
+
text_is_separator: A && A.text && A.text.trim() === '·',
|
|
107
|
+
};
|
|
108
|
+
const ok = Object.values(results).every(Boolean);
|
|
109
|
+
console.log(`${ok ? '✅' : '❌'} active-links freshness:`, JSON.stringify(results),
|
|
110
|
+
`\n fresh =`, A,
|
|
111
|
+
`\n mid =`, B,
|
|
112
|
+
`\n stale =`, C);
|
|
113
|
+
process.exit(ok ? 0 : 1);
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/* Round 114 verification: active-links chip tooltip lists the actual
|
|
2
|
+
* flow pairs. Closes the info-density sweep on the last chip-row
|
|
3
|
+
* hover surface (R97-R113 covered everything else). Format:
|
|
4
|
+
* "alpha→beta (3), gamma→delta (1) — hover brightens all"
|
|
5
|
+
*
|
|
6
|
+
* Drive 3 flow pairs of different counts. Verify each pair appears
|
|
7
|
+
* in the title with its count; the trailing action hint says
|
|
8
|
+
* "hover brightens all". Empty-flow fleet → no title.
|
|
9
|
+
*/
|
|
10
|
+
import { chromium } from 'playwright';
|
|
11
|
+
import { readFileSync } from 'node:fs';
|
|
12
|
+
|
|
13
|
+
const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
|
|
14
|
+
const browser = await chromium.launch({ headless: true });
|
|
15
|
+
const fresh = new Date(Date.now() - 30 * 1000).toISOString();
|
|
16
|
+
|
|
17
|
+
const probe = async (withFlow) => {
|
|
18
|
+
const ctx = await browser.newContext({ viewport: { width: 1400, height: 1500 } });
|
|
19
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
20
|
+
await ctx.addInitScript(() => {
|
|
21
|
+
try { localStorage.setItem('anet-theme', 'cyber'); sessionStorage.setItem('anet_v3_auth', '1'); } catch {}
|
|
22
|
+
});
|
|
23
|
+
await ctx.route('**/api/hub/status*', async (route) => {
|
|
24
|
+
const r = await route.fetch();
|
|
25
|
+
const b = await r.json();
|
|
26
|
+
const nid = (b.sessions || [])[0]?.network_id || 'default';
|
|
27
|
+
const mk = (alias) => ({
|
|
28
|
+
alias, status: 'idle', model: 'claude-opus-4', runtime: 'cli-claude-code',
|
|
29
|
+
network_id: nid, project_dir: null,
|
|
30
|
+
created_at: fresh, updated_at: fresh, last_seen_at: fresh,
|
|
31
|
+
});
|
|
32
|
+
await route.fulfill({ response: r, json: { ...b, sessions: [mk('alpha'), mk('beta'), mk('gamma'), mk('delta')] } });
|
|
33
|
+
});
|
|
34
|
+
const now = Date.now();
|
|
35
|
+
const mkMsg = (id, from_alias, to_alias, ageMs) => ({
|
|
36
|
+
id, from_alias, to_alias, content: 'hi', network_id: 'default',
|
|
37
|
+
created_at: new Date(now - ageMs).toISOString(),
|
|
38
|
+
});
|
|
39
|
+
await ctx.route('**/api/hub/messages*', (route) => route.fulfill({ json: { messages: withFlow ? [
|
|
40
|
+
mkMsg('m1', 'alpha', 'beta', 30 * 1000),
|
|
41
|
+
mkMsg('m2', 'alpha', 'beta', 40 * 1000),
|
|
42
|
+
mkMsg('m3', 'alpha', 'beta', 50 * 1000),
|
|
43
|
+
mkMsg('m4', 'gamma', 'delta', 60 * 1000),
|
|
44
|
+
] : [] } }));
|
|
45
|
+
await ctx.route('**/api/hub/tasks*', (route) => route.fulfill({ json: { tasks: [] } }));
|
|
46
|
+
const page = await ctx.newPage();
|
|
47
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
|
|
48
|
+
await page.waitForFunction(() => document.querySelectorAll('g[data-node]').length === 4, { timeout: 30000 });
|
|
49
|
+
await page.waitForTimeout(600);
|
|
50
|
+
const data = await page.evaluate(() => {
|
|
51
|
+
const el = document.querySelector('[data-active-links-chip]');
|
|
52
|
+
return {
|
|
53
|
+
title: el?.getAttribute('title'),
|
|
54
|
+
flowCount: el?.getAttribute('data-active-links-flow-count') || '',
|
|
55
|
+
text: el?.textContent?.trim() || '',
|
|
56
|
+
};
|
|
57
|
+
});
|
|
58
|
+
await ctx.close();
|
|
59
|
+
return data;
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
const empty = await probe(false);
|
|
63
|
+
const full = await probe(true);
|
|
64
|
+
await browser.close();
|
|
65
|
+
|
|
66
|
+
const results = {
|
|
67
|
+
empty_noTitle: empty.title === null,
|
|
68
|
+
empty_zeroCount: empty.flowCount === '0',
|
|
69
|
+
full_titleHasAlphaBeta: /alpha→beta \(3\)/.test(full.title || ''),
|
|
70
|
+
full_titleHasGammaDelta: /gamma→delta \(1\)/.test(full.title || ''),
|
|
71
|
+
full_titleActionHint: /hover brightens all/.test(full.title || ''),
|
|
72
|
+
full_flowCount2: full.flowCount === '2',
|
|
73
|
+
full_chipShowsCount: /2 active link/.test(full.text),
|
|
74
|
+
};
|
|
75
|
+
const ok = Object.values(results).every(Boolean);
|
|
76
|
+
console.log(`${ok ? '✅' : '❌'} active-links tooltip:`, JSON.stringify(results),
|
|
77
|
+
`\n empty=`, empty,
|
|
78
|
+
`\n full=`, full);
|
|
79
|
+
process.exit(ok ? 0 : 1);
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/* Round 75 verification: each fresh flow edge gets an "arrival ping"
|
|
2
|
+
* circle at the destination, synchronised to the particle period via
|
|
3
|
+
* `begin = -0.92 * dur`. Stale edges (fresh ≤ 0.5) skip the ping;
|
|
4
|
+
* reduced-motion users see none at all.
|
|
5
|
+
*
|
|
6
|
+
* - Fresh edge alpha→beta (created now) + stale edge gamma→delta (5 min
|
|
7
|
+
* old) → ping[alpha->beta] present, ping[gamma->delta] absent.
|
|
8
|
+
* - Reduced-motion context: no ping anywhere.
|
|
9
|
+
*/
|
|
10
|
+
import { chromium } from 'playwright';
|
|
11
|
+
import { readFileSync } from 'node:fs';
|
|
12
|
+
|
|
13
|
+
const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
|
|
14
|
+
const browser = await chromium.launch({ headless: true });
|
|
15
|
+
|
|
16
|
+
async function probe(reducedMotion) {
|
|
17
|
+
const ctx = await browser.newContext({
|
|
18
|
+
viewport: { width: 1280, height: 1500 },
|
|
19
|
+
reducedMotion: reducedMotion ? 'reduce' : 'no-preference',
|
|
20
|
+
});
|
|
21
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
22
|
+
await ctx.addInitScript(() => {
|
|
23
|
+
try {
|
|
24
|
+
localStorage.setItem('anet-theme', 'cyber');
|
|
25
|
+
localStorage.setItem('anet-topo-layout', 'ring');
|
|
26
|
+
sessionStorage.setItem('anet_v3_auth', '1');
|
|
27
|
+
sessionStorage.removeItem('anet-topo-pinned-status');
|
|
28
|
+
sessionStorage.removeItem('anet-topo-pinned-group');
|
|
29
|
+
} catch {}
|
|
30
|
+
});
|
|
31
|
+
const fresh = new Date(Date.now() - 60 * 1000).toISOString();
|
|
32
|
+
await ctx.route('**/api/hub/status*', async (route) => {
|
|
33
|
+
const r = await route.fetch();
|
|
34
|
+
const b = await r.json();
|
|
35
|
+
const nid = (b.sessions || [])[0]?.network_id || 'default';
|
|
36
|
+
const sessions = ['alpha', 'beta', 'gamma', 'delta'].map(a => ({
|
|
37
|
+
alias: a, status: 'idle', network_id: nid, project_dir: null,
|
|
38
|
+
created_at: fresh, updated_at: fresh, last_seen_at: fresh,
|
|
39
|
+
}));
|
|
40
|
+
await route.fulfill({ response: r, json: { ...b, sessions } });
|
|
41
|
+
});
|
|
42
|
+
// alpha→beta fresh (0s ago); gamma→delta stale (6 min ago) so fresh
|
|
43
|
+
// value drops below 0.5 (the 5-min half-life is roughly 0.4 at 6min).
|
|
44
|
+
const now = new Date().toISOString();
|
|
45
|
+
const old = new Date(Date.now() - 6 * 60 * 1000).toISOString();
|
|
46
|
+
await ctx.route('**/api/hub/messages*', (route) => route.fulfill({ json: { messages: [
|
|
47
|
+
{ from_alias: 'alpha', to_alias: 'beta', content: 'm', created_at: now },
|
|
48
|
+
{ from_alias: 'gamma', to_alias: 'delta', content: 'm', created_at: old },
|
|
49
|
+
] } }));
|
|
50
|
+
await ctx.route('**/api/hub/tasks*', (route) => route.fulfill({ json: { tasks: [] } }));
|
|
51
|
+
const page = await ctx.newPage();
|
|
52
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
|
|
53
|
+
await page.waitForFunction(() => document.querySelectorAll('g[data-node]').length === 4, { timeout: 30000 });
|
|
54
|
+
await page.waitForTimeout(600);
|
|
55
|
+
const pings = await page.evaluate(() => {
|
|
56
|
+
const out = [];
|
|
57
|
+
for (const el of document.querySelectorAll('[data-arrival-ping]')) {
|
|
58
|
+
out.push({
|
|
59
|
+
key: el.getAttribute('data-arrival-ping'),
|
|
60
|
+
cx: el.getAttribute('cx'),
|
|
61
|
+
cy: el.getAttribute('cy'),
|
|
62
|
+
stroke: el.getAttribute('stroke'),
|
|
63
|
+
animateCount: el.querySelectorAll('animate').length,
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
return out;
|
|
67
|
+
});
|
|
68
|
+
await ctx.close();
|
|
69
|
+
return pings;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const normal = await probe(false);
|
|
73
|
+
const reduced = await probe(true);
|
|
74
|
+
await browser.close();
|
|
75
|
+
|
|
76
|
+
const has = (rows, key) => rows.some(p => p.key === key);
|
|
77
|
+
const results = {
|
|
78
|
+
normal_freshPingPresent: has(normal, 'alpha->beta'),
|
|
79
|
+
normal_stalePingAbsent: !has(normal, 'gamma->delta'),
|
|
80
|
+
normal_twoAnimateChildren: normal.find(p => p.key === 'alpha->beta')?.animateCount === 2,
|
|
81
|
+
reduced_noPings: reduced.length === 0,
|
|
82
|
+
};
|
|
83
|
+
const ok = Object.values(results).every(Boolean);
|
|
84
|
+
console.log(`${ok ? '✅' : '❌'} arrival ping:`, JSON.stringify(results),
|
|
85
|
+
`\n normal=`, normal,
|
|
86
|
+
`\n reduced=`, reduced);
|
|
87
|
+
process.exit(ok ? 0 : 1);
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/* Round 16 verification: three flow-link arrow markers exist with the
|
|
2
|
+
* right sizes, all using userSpaceOnUse so they're decoupled from stroke. */
|
|
3
|
+
import { chromium } from 'playwright';
|
|
4
|
+
import { readFileSync } from 'node:fs';
|
|
5
|
+
|
|
6
|
+
const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
|
|
7
|
+
const browser = await chromium.launch({ headless: true });
|
|
8
|
+
|
|
9
|
+
const ctx = await browser.newContext({ viewport: { width: 1280, height: 900 } });
|
|
10
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
11
|
+
await ctx.addInitScript(() => {
|
|
12
|
+
try {
|
|
13
|
+
localStorage.setItem('anet-theme', 'cyber');
|
|
14
|
+
localStorage.removeItem('anet-brand');
|
|
15
|
+
localStorage.removeItem('anet-topo-view');
|
|
16
|
+
localStorage.setItem('anet-topo-layout', 'grid');
|
|
17
|
+
sessionStorage.setItem('anet_v3_auth', '1');
|
|
18
|
+
} catch {}
|
|
19
|
+
});
|
|
20
|
+
await ctx.route('**/api/hub/status*', async (route) => {
|
|
21
|
+
const r = await route.fetch();
|
|
22
|
+
const b = await r.json();
|
|
23
|
+
const nid = (b.sessions || [])[0]?.network_id || 'default';
|
|
24
|
+
const sessions = ['a', 'b', 'c'].map(a => ({
|
|
25
|
+
alias: a, status: 'idle', network_id: nid, project_dir: null,
|
|
26
|
+
created_at: '2026-05-15T00:00:00Z', updated_at: '2026-05-15T00:00:00Z',
|
|
27
|
+
last_seen_at: new Date().toISOString(),
|
|
28
|
+
}));
|
|
29
|
+
await route.fulfill({ response: r, json: { ...b, sessions } });
|
|
30
|
+
});
|
|
31
|
+
await ctx.route('**/api/hub/tasks*', (route) => route.fulfill({ json: { tasks: [] } }));
|
|
32
|
+
const page = await ctx.newPage();
|
|
33
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
|
|
34
|
+
await page.waitForFunction(() => {
|
|
35
|
+
const svg = document.querySelector('svg[viewBox="0 0 1000 680"]');
|
|
36
|
+
return !!svg && svg.querySelectorAll('g[data-node]').length === 3;
|
|
37
|
+
}, { timeout: 30000 }).catch(() => {});
|
|
38
|
+
await page.waitForTimeout(400);
|
|
39
|
+
|
|
40
|
+
const m = await page.evaluate(() => {
|
|
41
|
+
const reads = (id) => {
|
|
42
|
+
const el = document.querySelector(`marker#${id}`);
|
|
43
|
+
if (!el) return null;
|
|
44
|
+
return {
|
|
45
|
+
width: +el.getAttribute('markerWidth'),
|
|
46
|
+
units: el.getAttribute('markerUnits'),
|
|
47
|
+
};
|
|
48
|
+
};
|
|
49
|
+
return { s: reads('topo-arrow-s'), m: reads('topo-arrow'), l: reads('topo-arrow-l') };
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
await browser.close();
|
|
53
|
+
const results = {
|
|
54
|
+
smallExists: m.s?.width === 12 && m.s?.units === 'userSpaceOnUse',
|
|
55
|
+
mediumExists: m.m?.width === 16 && m.m?.units === 'userSpaceOnUse',
|
|
56
|
+
largeExists: m.l?.width === 22 && m.l?.units === 'userSpaceOnUse',
|
|
57
|
+
legendCompatible: m.m !== null, // legend uses url(#topo-arrow); medium tier must exist by that id
|
|
58
|
+
};
|
|
59
|
+
const ok = Object.values(results).every(Boolean);
|
|
60
|
+
console.log(`${ok ? '✅' : '❌'} arrow tiers:`, JSON.stringify(results), 'sizes:', m);
|
|
61
|
+
process.exit(ok ? 0 : 1);
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/* Round 28 verification: first-paint auto-fit zoom when grid content
|
|
2
|
+
* would overflow viewBox; respects persisted view; doesn't fire on
|
|
3
|
+
* small fleets (no overflow). */
|
|
4
|
+
import { chromium } from 'playwright';
|
|
5
|
+
import { readFileSync } from 'node:fs';
|
|
6
|
+
|
|
7
|
+
const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
|
|
8
|
+
const browser = await chromium.launch({ headless: true });
|
|
9
|
+
|
|
10
|
+
async function probe({ fleetSize, persisted }) {
|
|
11
|
+
const ctx = await browser.newContext({ viewport: { width: 1280, height: 1600 } });
|
|
12
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
13
|
+
await ctx.addInitScript(([pers]) => {
|
|
14
|
+
try {
|
|
15
|
+
localStorage.setItem('anet-theme', 'cyber');
|
|
16
|
+
localStorage.setItem('anet-topo-layout', 'grid');
|
|
17
|
+
if (pers) localStorage.setItem('anet-topo-view', JSON.stringify(pers));
|
|
18
|
+
else localStorage.removeItem('anet-topo-view');
|
|
19
|
+
sessionStorage.setItem('anet_v3_auth', '1');
|
|
20
|
+
} catch {}
|
|
21
|
+
}, [persisted]);
|
|
22
|
+
const fresh = new Date(Date.now() - 60 * 1000).toISOString();
|
|
23
|
+
await ctx.route('**/api/hub/status*', async (route) => {
|
|
24
|
+
const r = await route.fetch();
|
|
25
|
+
const b = await r.json();
|
|
26
|
+
const nid = (b.sessions || [])[0]?.network_id || 'default';
|
|
27
|
+
// Use prefix groups with 5 members each — 7 bands stack vertically
|
|
28
|
+
// and overflow the 680-px viewBox at cellH ≥ 81 (Round 27 floor).
|
|
29
|
+
const aliases = Array.from({ length: fleetSize }, (_, i) => {
|
|
30
|
+
const groups = ['A站', 'B站', 'C站', 'D站', 'E站', 'F站', 'G站', 'H站', 'I站', 'J站'];
|
|
31
|
+
const group = groups[Math.floor(i / 5) % groups.length];
|
|
32
|
+
return `${group}n${i + 1}`;
|
|
33
|
+
});
|
|
34
|
+
const sessions = aliases.map(a => ({
|
|
35
|
+
alias: a, status: 'idle', network_id: nid, project_dir: null,
|
|
36
|
+
created_at: fresh, updated_at: fresh, last_seen_at: fresh,
|
|
37
|
+
}));
|
|
38
|
+
await route.fulfill({ response: r, json: { ...b, sessions } });
|
|
39
|
+
});
|
|
40
|
+
await ctx.route('**/api/hub/tasks*', (route) => route.fulfill({ json: { tasks: [] } }));
|
|
41
|
+
const page = await ctx.newPage();
|
|
42
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
|
|
43
|
+
await page.waitForFunction((n) => {
|
|
44
|
+
const svg = document.querySelector('svg[viewBox="0 0 1000 680"]');
|
|
45
|
+
return !!svg && svg.querySelectorAll('g[data-node]').length === n;
|
|
46
|
+
}, fleetSize, { timeout: 30000 }).catch(() => {});
|
|
47
|
+
await page.waitForTimeout(600);
|
|
48
|
+
const zoom = await page.evaluate(() => {
|
|
49
|
+
const span = document.querySelector('button[aria-label="Zoom in"]').parentElement.querySelector('span[title*="zoom level"]');
|
|
50
|
+
return +span.textContent.replace('%', '');
|
|
51
|
+
});
|
|
52
|
+
await ctx.close();
|
|
53
|
+
return zoom;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// 1. Big fleet (35 nodes / 7 bands → overflows ~680-px viewBox at cellH≥81)
|
|
57
|
+
// with no persisted view → auto-fit triggers (zoom < 100%)
|
|
58
|
+
const bigFresh = await probe({ fleetSize: 35 });
|
|
59
|
+
// 2. Big fleet, user has persisted view (zoom=1) → respect it, no auto-fit
|
|
60
|
+
const bigPersisted = await probe({ fleetSize: 35, persisted: { zoom: 1, x: 0, y: 0 } });
|
|
61
|
+
// 3. Small fleet, no persisted view → no overflow, zoom stays 100%
|
|
62
|
+
const smallFresh = await probe({ fleetSize: 6 });
|
|
63
|
+
|
|
64
|
+
await browser.close();
|
|
65
|
+
const results = {
|
|
66
|
+
bigFleetAutoFits: bigFresh < 100 && bigFresh >= 50,
|
|
67
|
+
persistedRespected: bigPersisted === 100,
|
|
68
|
+
smallFleetStays100: smallFresh === 100,
|
|
69
|
+
};
|
|
70
|
+
const ok = Object.values(results).every(Boolean);
|
|
71
|
+
console.log(`${ok ? '✅' : '❌'} auto-fit:`, JSON.stringify(results),
|
|
72
|
+
`bigFresh=${bigFresh}% bigPersisted=${bigPersisted}% smallFresh=${smallFresh}%`);
|
|
73
|
+
process.exit(ok ? 0 : 1);
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/* Round 158 verification: main canvas SVG gains aria-label +
|
|
2
|
+
* aria-roledescription.
|
|
3
|
+
*
|
|
4
|
+
* R151-R157 closed a11y across every interactive surface INSIDE
|
|
5
|
+
* the canvas (nodes / group labels / edge badges / recent rows /
|
|
6
|
+
* legend rows / chrome buttons / minimap). The canvas <svg> root
|
|
7
|
+
* itself was a nameless 1000×680 box — a screen-reader user who
|
|
8
|
+
* landed on it before tab-diving into children heard nothing
|
|
9
|
+
* identifying the surface.
|
|
10
|
+
*
|
|
11
|
+
* R158 closes that gap:
|
|
12
|
+
* aria-roledescription="agent network topology"
|
|
13
|
+
* aria-label live-updates with snapshot:
|
|
14
|
+
* "Agent network topology — 5 agents online · 3 working ·
|
|
15
|
+
* 1 offline · 2 active links. Tab to navigate nodes,
|
|
16
|
+
* double-click canvas to reset view."
|
|
17
|
+
*
|
|
18
|
+
* No role override — default SVG role (graphics-document) keeps
|
|
19
|
+
* children navigable; role="img" would flatten the SVG to a
|
|
20
|
+
* single opaque image and hide all the R151-R157 work.
|
|
21
|
+
*
|
|
22
|
+
* Test:
|
|
23
|
+
* 1. Mock 3 working + 2 idle online + 1 offline + 2 active links
|
|
24
|
+
* 2. Assert canvas SVG has both ARIA attrs
|
|
25
|
+
* 3. Assert aria-label contains all four count fragments + gesture hints
|
|
26
|
+
* 4. Assert no role="img" (would defeat children a11y)
|
|
27
|
+
*/
|
|
28
|
+
import { chromium } from 'playwright';
|
|
29
|
+
import { readFileSync } from 'node:fs';
|
|
30
|
+
|
|
31
|
+
const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
|
|
32
|
+
const browser = await chromium.launch({ headless: true });
|
|
33
|
+
|
|
34
|
+
const ctx = await browser.newContext({ viewport: { width: 1400, height: 1500 } });
|
|
35
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
36
|
+
await ctx.addInitScript(() => {
|
|
37
|
+
try { localStorage.setItem('anet-theme', 'cyber'); sessionStorage.setItem('anet_v3_auth', '1'); } catch {}
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
const fresh = new Date(Date.now() - 60 * 1000).toISOString();
|
|
41
|
+
const stale = new Date(Date.now() - 10 * 60 * 1000).toISOString();
|
|
42
|
+
await ctx.route('**/api/hub/status*', async (route) => {
|
|
43
|
+
const r = await route.fetch();
|
|
44
|
+
const b = await r.json();
|
|
45
|
+
const nid = (b.sessions || [])[0]?.network_id || 'default';
|
|
46
|
+
const mk = (alias, status, last) => ({
|
|
47
|
+
alias, status, model: 'claude-opus-4', runtime: 'cli-claude-code',
|
|
48
|
+
network_id: nid, project_dir: null,
|
|
49
|
+
created_at: last, updated_at: last, last_seen_at: last,
|
|
50
|
+
});
|
|
51
|
+
await route.fulfill({ response: r, json: { ...b, sessions: [
|
|
52
|
+
mk('agents-a1', 'working', fresh),
|
|
53
|
+
mk('agents-a2', 'working', fresh),
|
|
54
|
+
mk('agents-a3', 'working', fresh),
|
|
55
|
+
mk('infra-b1', 'idle', fresh),
|
|
56
|
+
mk('infra-b2', 'idle', fresh),
|
|
57
|
+
mk('legacy-c1', 'offline', stale),
|
|
58
|
+
] } });
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
const now = Date.now();
|
|
62
|
+
// 4 a1↔a2 msgs (R100 threshold for edge badge) + 1 a2↔a3 = 2 flowLinks
|
|
63
|
+
const msgs = [];
|
|
64
|
+
for (let i = 0; i < 4; i++) {
|
|
65
|
+
msgs.push({ id: `m${i}`, from_alias: 'agents-a1', to_alias: 'agents-a2', content: 'hi',
|
|
66
|
+
network_id: 'default', created_at: new Date(now - (10000 + i * 500)).toISOString() });
|
|
67
|
+
}
|
|
68
|
+
msgs.push({ id: 'mx', from_alias: 'agents-a2', to_alias: 'agents-a3', content: 'hi',
|
|
69
|
+
network_id: 'default', created_at: new Date(now - 14000).toISOString() });
|
|
70
|
+
await ctx.route('**/api/hub/messages*', (route) => route.fulfill({ json: { messages: msgs } }));
|
|
71
|
+
await ctx.route('**/api/hub/tasks*', (route) => route.fulfill({ json: { tasks: [] } }));
|
|
72
|
+
|
|
73
|
+
const page = await ctx.newPage();
|
|
74
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
|
|
75
|
+
// 5 online + 1 offline = 6 g[data-node]
|
|
76
|
+
await page.waitForFunction(() => document.querySelectorAll('g[data-node]').length === 6, { timeout: 30000 });
|
|
77
|
+
await page.waitForTimeout(400);
|
|
78
|
+
|
|
79
|
+
const probe = await page.evaluate(() => {
|
|
80
|
+
const el = document.querySelector('[data-topo-canvas-aria]');
|
|
81
|
+
if (!el) return null;
|
|
82
|
+
return {
|
|
83
|
+
tagName: el.tagName.toLowerCase(),
|
|
84
|
+
role: el.getAttribute('role'),
|
|
85
|
+
roledesc: el.getAttribute('aria-roledescription'),
|
|
86
|
+
label: el.getAttribute('aria-label'),
|
|
87
|
+
};
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
await browser.close();
|
|
91
|
+
|
|
92
|
+
const label = probe?.label || '';
|
|
93
|
+
const results = {
|
|
94
|
+
canvas_found: probe !== null,
|
|
95
|
+
is_svg: probe?.tagName === 'svg',
|
|
96
|
+
no_role_img: probe?.role !== 'img',
|
|
97
|
+
has_roledescription: probe?.roledesc === 'agent network topology',
|
|
98
|
+
label_mentions_online: /5 agents online/.test(label),
|
|
99
|
+
label_mentions_working: /3 working/.test(label),
|
|
100
|
+
label_mentions_offline: /1 offline/.test(label),
|
|
101
|
+
label_mentions_links: /2 active links/.test(label),
|
|
102
|
+
label_mentions_tab: /Tab to navigate/.test(label),
|
|
103
|
+
label_mentions_doubleclick: /double-click/.test(label),
|
|
104
|
+
};
|
|
105
|
+
const ok = Object.values(results).every(Boolean);
|
|
106
|
+
console.log(`${ok ? '✅' : '❌'} canvas SVG aria:`, JSON.stringify(results),
|
|
107
|
+
`\n probe=`, probe);
|
|
108
|
+
process.exit(ok ? 0 : 1);
|