@sleep2agi/agent-network-dashboard 0.4.6-preview.26 → 0.4.6-preview.261
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/00.pi0.850kxg.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/05uk96gc~9mni.js +1 -0
- package/.next/static/chunks/08kf-.bgs10ze.js +1 -0
- package/.next/static/chunks/08y27uzl7w6bx.css +2 -0
- package/.next/static/chunks/0ggj5ummw2a84.js +7 -0
- package/.next/static/chunks/0glmrdj9112tc.js +7 -0
- package/.next/static/chunks/0rxrez_cjn.eh.js +1 -0
- package/.next/static/chunks/0s64vw8kd5rn7.js +1 -0
- package/.next/static/chunks/0x8x.29hkju5a.js +1 -0
- package/.next/static/chunks/11drzen-wfaop.js +4 -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 +5291 -237
- package/app/components/utils.ts +8 -7
- package/app/globals.css +110 -5
- package/app/lib/time.ts +36 -0
- package/package.json +2 -2
- 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-self-hover-test.mjs +171 -0
- package/scripts/topo-active-links-chip-test.mjs +73 -0
- package/scripts/topo-active-links-empty-recede-test.mjs +125 -0
- package/scripts/topo-active-links-freshness-test.mjs +113 -0
- package/scripts/topo-active-links-tooltip-test.mjs +79 -0
- package/scripts/topo-active-pulse-ease-test.mjs +120 -0
- package/scripts/topo-arrival-ping-test.mjs +87 -0
- package/scripts/topo-auto-fit-test.mjs +73 -0
- package/scripts/topo-canvas-aria-test.mjs +108 -0
- package/scripts/topo-chat-target-breath-test.mjs +84 -0
- package/scripts/topo-chat-target-ring-ease-test.mjs +82 -0
- package/scripts/topo-chat-target-ring-fade-test.mjs +124 -0
- package/scripts/topo-chip-empty-recede-test.mjs +116 -0
- package/scripts/topo-chip-focus-test.mjs +95 -0
- package/scripts/topo-chip-pin-mirror-test.mjs +113 -0
- package/scripts/topo-chip-row-tabular-test.mjs +111 -0
- package/scripts/topo-chrome-a11y-test.mjs +107 -0
- package/scripts/topo-chrome-pop-extension-test.mjs +98 -0
- package/scripts/topo-chrome-pop-nodesize-test.mjs +88 -0
- package/scripts/topo-chrome-press-state-test.mjs +135 -0
- package/scripts/topo-chrome-zoom-level-pop-test.mjs +122 -0
- package/scripts/topo-chrome-zoom-pop-test.mjs +130 -0
- package/scripts/topo-click-ripple-ease-test.mjs +94 -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-dense-alias-fill-transition-test.mjs +133 -0
- package/scripts/topo-discrete-zoom-smooth-test.mjs +125 -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-crossfade-test.mjs +138 -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-badge-lift-test.mjs +150 -0
- package/scripts/topo-edge-badge-ripple-test.mjs +111 -0
- package/scripts/topo-edge-badge-stroke-transition-test.mjs +118 -0
- package/scripts/topo-edge-badge-text-pin-test.mjs +121 -0
- package/scripts/topo-edge-badge-theme-ease-test.mjs +89 -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-fadein-test.mjs +106 -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-smil-sync-test.mjs +148 -0
- package/scripts/topo-edge-smil-theme-ease-test.mjs +97 -0
- package/scripts/topo-edge-stroke-ease-test.mjs +100 -0
- package/scripts/topo-edge-stroke-transition-test.mjs +132 -0
- package/scripts/topo-edge-tooltip-test.mjs +70 -0
- package/scripts/topo-empty-state-breath-test.mjs +150 -0
- package/scripts/topo-empty-state-crossfade-test.mjs +130 -0
- package/scripts/topo-endpoint-ring-fade-test.mjs +132 -0
- package/scripts/topo-endpoint-ring-test.mjs +93 -0
- package/scripts/topo-endpoint-ring-thicken-test.mjs +112 -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-freshness-chip-transition-test.mjs +80 -0
- package/scripts/topo-fullscreen-active-test.mjs +115 -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-label-a11y-test.mjs +113 -0
- package/scripts/topo-group-label-count-inherit-test.mjs +99 -0
- package/scripts/topo-group-label-hover-test.mjs +119 -0
- package/scripts/topo-group-label-pin-spacing-test.mjs +136 -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-pip-fadein-test.mjs +100 -0
- package/scripts/topo-group-pip-tabular-test.mjs +95 -0
- package/scripts/topo-group-status-pips-test.mjs +103 -0
- package/scripts/topo-groupbox-fadein-test.mjs +95 -0
- package/scripts/topo-groupbox-hover-lift-test.mjs +127 -0
- package/scripts/topo-groupbox-hubcore-ease-test.mjs +106 -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-halo-breath-ease-test.mjs +92 -0
- package/scripts/topo-halo-breath-stagger-test.mjs +89 -0
- 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-hot-tail-crossfade-test.mjs +117 -0
- package/scripts/topo-hub-a11y-test.mjs +112 -0
- package/scripts/topo-hub-busyness-test.mjs +100 -0
- package/scripts/topo-hub-center-crossfade-test.mjs +124 -0
- package/scripts/topo-hub-click-fit-test.mjs +137 -0
- package/scripts/topo-hub-digit-scale-test.mjs +129 -0
- package/scripts/topo-hub-fadein-test.mjs +88 -0
- package/scripts/topo-hub-hover-lift-test.mjs +101 -0
- package/scripts/topo-hub-hover-ring-test.mjs +82 -0
- package/scripts/topo-hub-pip-theme-ease-test.mjs +116 -0
- package/scripts/topo-hub-spoke-ease-test.mjs +120 -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-card-theme-ease-test.mjs +85 -0
- package/scripts/topo-label-lift-test.mjs +119 -0
- package/scripts/topo-lastseen-tooltip-test.mjs +59 -0
- package/scripts/topo-layout-key-test.mjs +91 -0
- package/scripts/topo-layout-switch-crossfade-test.mjs +126 -0
- package/scripts/topo-layout-toggle-test.mjs +131 -0
- package/scripts/topo-legend-count-empty-test.mjs +126 -0
- package/scripts/topo-legend-count-test.mjs +88 -0
- package/scripts/topo-legend-count-tier-fill-test.mjs +121 -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-ring-fade-test.mjs +112 -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-pin-spacing-test.mjs +124 -0
- package/scripts/topo-legend-row-tint-test.mjs +95 -0
- package/scripts/topo-legend-row-title-test.mjs +102 -0
- package/scripts/topo-legend-swatch-grow-test.mjs +116 -0
- package/scripts/topo-minimap-a11y-test.mjs +101 -0
- package/scripts/topo-minimap-dot-transition-test.mjs +113 -0
- package/scripts/topo-minimap-test.mjs +68 -0
- package/scripts/topo-minimap-viewport-smooth-test.mjs +124 -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-label-card-elevation-test.mjs +157 -0
- package/scripts/topo-node-label-card-stroke-test.mjs +135 -0
- package/scripts/topo-node-stroke-transition-test.mjs +103 -0
- package/scripts/topo-node-text-fill-transition-test.mjs +119 -0
- package/scripts/topo-node-title-peers-test.mjs +107 -0
- package/scripts/topo-node-title-test.mjs +101 -0
- package/scripts/topo-nodesize-active-hover-test.mjs +109 -0
- package/scripts/topo-nodesize-crossfade-test.mjs +141 -0
- package/scripts/topo-online-chip-nav-test.mjs +143 -0
- package/scripts/topo-orbit-busyness-test.mjs +96 -0
- package/scripts/topo-orbit-opacity-bucket-test.mjs +124 -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-fadein-test.mjs +102 -0
- package/scripts/topo-panel-hot-tail-fade-test.mjs +132 -0
- package/scripts/topo-panel-hover-elevation-test.mjs +118 -0
- package/scripts/topo-panel-theme-ease-test.mjs +85 -0
- package/scripts/topo-particle-stagger-test.mjs +82 -0
- package/scripts/topo-pin-intersection-color-ease-test.mjs +111 -0
- package/scripts/topo-pin-intersection-empty-test.mjs +129 -0
- package/scripts/topo-pin-intersection-tabular-test.mjs +96 -0
- package/scripts/topo-pin-intersection-test.mjs +121 -0
- package/scripts/topo-pin-intersection-warning-crossfade-test.mjs +107 -0
- package/scripts/topo-pin-mirror-transition-test.mjs +101 -0
- package/scripts/topo-pin-persistence-test.mjs +105 -0
- package/scripts/topo-ping-pulse-ease-test.mjs +96 -0
- package/scripts/topo-popover-meta-test.mjs +78 -0
- package/scripts/topo-prepublish-guard-test.mjs +95 -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-self-hover-test.mjs +126 -0
- package/scripts/topo-pressure-seg-tooltip-test.mjs +98 -0
- package/scripts/topo-pressure-seg-transition-test.mjs +107 -0
- package/scripts/topo-pulse-dot-crossfade-test.mjs +122 -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-crossfade-test.mjs +124 -0
- package/scripts/topo-recent-panel-more-cyan-hover-test.mjs +151 -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-count-fill-test.mjs +129 -0
- package/scripts/topo-recent-row-fadein-test.mjs +107 -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-spacing-test.mjs +137 -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-alpha-test.mjs +100 -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-reset-spin-test.mjs +120 -0
- package/scripts/topo-runtime-badge-grow-test.mjs +114 -0
- package/scripts/topo-spoke-busyness-test.mjs +110 -0
- package/scripts/topo-spoke-tint-test.mjs +96 -0
- package/scripts/topo-status-chip-hover-test.mjs +101 -0
- package/scripts/topo-status-chip-tooltip-test.mjs +95 -0
- package/scripts/topo-statusbar-chips-self-hover-test.mjs +177 -0
- package/scripts/topo-svg-focus-test.mjs +112 -0
- package/scripts/topo-sweep-busyness-test.mjs +94 -0
- package/scripts/topo-tabular-nums-sweep-test.mjs +93 -0
- package/scripts/topo-tier-ring-fadein-test.mjs +107 -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-chip-self-hover-test.mjs +130 -0
- package/scripts/topo-vendor-chip-tabular-test.mjs +89 -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-view-smooth-test.mjs +131 -0
- package/scripts/topo-wheel-zoom-test.mjs +79 -0
- package/scripts/topo-working-chip-pin-test.mjs +154 -0
- package/scripts/topo-working-halo-breath-test.mjs +86 -0
- package/scripts/topo-wrapper-flow-arrow-theme-test.mjs +97 -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/09nd.t_hd.y6t.css +0 -2
- package/.next/static/chunks/0_qfg5s5uzs7..js +0 -7
- package/.next/static/chunks/0elalb9n_.~di.js +0 -1
- package/.next/static/chunks/0fqy_0wj_1xa7.js +0 -7
- package/.next/static/chunks/0j_q__o8p6g83.js +0 -1
- package/.next/static/chunks/0jl6_w50zh4l5.js +0 -1
- package/.next/static/chunks/0jzqhqbydbrm~.js +0 -1
- package/.next/static/chunks/0lvk7f2_5y8b3.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/12maqvd_4t3sh.js +0 -1
- /package/.next/static/{iC9JNLo0IdNSaeynEneGT → -JO9tjmCkno3inrj-XBxj}/_buildManifest.js +0 -0
- /package/.next/static/{iC9JNLo0IdNSaeynEneGT → -JO9tjmCkno3inrj-XBxj}/_clientMiddlewareManifest.js +0 -0
- /package/.next/static/{iC9JNLo0IdNSaeynEneGT → -JO9tjmCkno3inrj-XBxj}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/* Round 156 verification: SVG <g> interactives gain
|
|
2
|
+
* `.anet-topo-svg-focus` for keyboard focus outline.
|
|
3
|
+
*
|
|
4
|
+
* Mirrors R155's chip-row treatment at the SVG scope. 6 surfaces:
|
|
5
|
+
* data-node (R151 node body)
|
|
6
|
+
* data-group-label-hit (R63 group label)
|
|
7
|
+
* data-edge-count-badge (R121 edge badge)
|
|
8
|
+
* data-recent-row (R116 recent-signal row)
|
|
9
|
+
* data-recent-panel-more-nav (R133 "+N more" footer)
|
|
10
|
+
* data-legend-status (R61 legend row)
|
|
11
|
+
*
|
|
12
|
+
* Class `.anet-topo-svg-focus:focus-visible` paints outline 2px
|
|
13
|
+
* cyan-300 (#67e8f9) with 2px outline-offset. Browser default
|
|
14
|
+
* focus ring on SVG is hard to spot against the dashboard
|
|
15
|
+
* canvas; explicit cyan matches the legendAccent palette.
|
|
16
|
+
*
|
|
17
|
+
* Test: every SVG interactive surface carries the class.
|
|
18
|
+
*/
|
|
19
|
+
import { chromium } from 'playwright';
|
|
20
|
+
import { readFileSync } from 'node:fs';
|
|
21
|
+
|
|
22
|
+
const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
|
|
23
|
+
const browser = await chromium.launch({ headless: true });
|
|
24
|
+
|
|
25
|
+
const ctx = await browser.newContext({ viewport: { width: 1600, height: 1500 } });
|
|
26
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
27
|
+
await ctx.addInitScript(() => {
|
|
28
|
+
try {
|
|
29
|
+
localStorage.setItem('anet-theme', 'cyber');
|
|
30
|
+
sessionStorage.setItem('anet_v3_auth', '1');
|
|
31
|
+
// grid layout to surface group labels
|
|
32
|
+
localStorage.setItem('anet-topo-layout', 'grid');
|
|
33
|
+
} catch {}
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
const fresh = new Date(Date.now() - 60 * 1000).toISOString();
|
|
37
|
+
await ctx.route('**/api/hub/status*', async (route) => {
|
|
38
|
+
const r = await route.fetch();
|
|
39
|
+
const b = await r.json();
|
|
40
|
+
const nid = (b.sessions || [])[0]?.network_id || 'default';
|
|
41
|
+
const mk = (alias, status) => ({
|
|
42
|
+
alias, status, model: 'claude-opus-4', runtime: 'cli-claude-code',
|
|
43
|
+
network_id: nid, project_dir: null,
|
|
44
|
+
created_at: fresh, updated_at: fresh, last_seen_at: fresh,
|
|
45
|
+
});
|
|
46
|
+
await route.fulfill({ response: r, json: { ...b, sessions: [
|
|
47
|
+
mk('agents-a1', 'working'), mk('agents-a2', 'working'),
|
|
48
|
+
mk('infra-b1', 'working'),
|
|
49
|
+
] } });
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
const now = Date.now();
|
|
53
|
+
// Edge midpoint count badge (R100) only renders when link.count >= 3.
|
|
54
|
+
// Pair agents-a1 → agents-a2 gets 4 msgs to clear the threshold; add 4
|
|
55
|
+
// other singletons so flowLinks.length = 5 → R128 "+ 2 more flows"
|
|
56
|
+
// footer also renders.
|
|
57
|
+
const msgs = [];
|
|
58
|
+
for (let i = 0; i < 4; i++) {
|
|
59
|
+
msgs.push({
|
|
60
|
+
id: `a2a${i}`, from_alias: 'agents-a1', to_alias: 'agents-a2', content: 'hi',
|
|
61
|
+
network_id: 'default', created_at: new Date(now - (10000 + i * 500)).toISOString(),
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
msgs.push({ id: 'm1', from_alias: 'agents-a2', to_alias: 'infra-b1', content: 'hi',
|
|
65
|
+
network_id: 'default', created_at: new Date(now - 11000).toISOString() });
|
|
66
|
+
msgs.push({ id: 'm2', from_alias: 'infra-b1', to_alias: 'agents-a1', content: 'hi',
|
|
67
|
+
network_id: 'default', created_at: new Date(now - 12000).toISOString() });
|
|
68
|
+
msgs.push({ id: 'm3', from_alias: 'agents-a1', to_alias: 'infra-b1', content: 'hi',
|
|
69
|
+
network_id: 'default', created_at: new Date(now - 13000).toISOString() });
|
|
70
|
+
msgs.push({ id: 'm4', from_alias: 'agents-a2', to_alias: 'agents-a1', content: 'hi',
|
|
71
|
+
network_id: 'default', created_at: new Date(now - 14000).toISOString() });
|
|
72
|
+
await ctx.route('**/api/hub/messages*', (route) => route.fulfill({ json: { messages: msgs } }));
|
|
73
|
+
await ctx.route('**/api/hub/tasks*', (route) => route.fulfill({ json: { tasks: [] } }));
|
|
74
|
+
|
|
75
|
+
const page = await ctx.newPage();
|
|
76
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
|
|
77
|
+
await page.waitForFunction(() => document.querySelectorAll('g[data-node]').length === 3, { timeout: 30000 });
|
|
78
|
+
await page.waitForSelector('[data-recent-row]', { timeout: 10000 });
|
|
79
|
+
await page.waitForSelector('[data-recent-panel-more-nav]', { timeout: 10000 });
|
|
80
|
+
await page.waitForSelector('[data-edge-count-badge]', { timeout: 10000 });
|
|
81
|
+
await page.waitForSelector('[data-group-label-hit]', { timeout: 10000 });
|
|
82
|
+
await page.waitForTimeout(400);
|
|
83
|
+
|
|
84
|
+
const out = await page.evaluate(() => {
|
|
85
|
+
const has = (sel) => {
|
|
86
|
+
const el = document.querySelector(sel);
|
|
87
|
+
return el && (el.getAttribute('class') || '').includes('anet-topo-svg-focus');
|
|
88
|
+
};
|
|
89
|
+
return {
|
|
90
|
+
nodeBody: has('g[data-node]'),
|
|
91
|
+
groupLabel: has('[data-group-label-hit]'),
|
|
92
|
+
edgeCountBadge: has('[data-edge-count-badge]'),
|
|
93
|
+
recentRow: has('[data-recent-row]'),
|
|
94
|
+
recentPanelMoreNav: has('[data-recent-panel-more-nav]'),
|
|
95
|
+
legendStatusRow: has('[data-legend-status="working"]'),
|
|
96
|
+
};
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
await browser.close();
|
|
100
|
+
|
|
101
|
+
const results = {
|
|
102
|
+
nodeBody_focus: out.nodeBody === true,
|
|
103
|
+
groupLabel_focus: out.groupLabel === true,
|
|
104
|
+
edgeCountBadge_focus: out.edgeCountBadge === true,
|
|
105
|
+
recentRow_focus: out.recentRow === true,
|
|
106
|
+
recentPanelMoreNav_focus: out.recentPanelMoreNav === true,
|
|
107
|
+
legendStatusRow_focus: out.legendStatusRow === true,
|
|
108
|
+
};
|
|
109
|
+
const ok = Object.values(results).every(Boolean);
|
|
110
|
+
console.log(`${ok ? '✅' : '❌'} SVG focus class:`, JSON.stringify(results),
|
|
111
|
+
`\n raw=`, out);
|
|
112
|
+
process.exit(ok ? 0 : 1);
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/* Round 146 verification: R45 radar sweep rotation rate buckets on
|
|
2
|
+
* workingCount, completing the 5-layer busyness-driven motion family:
|
|
3
|
+
*
|
|
4
|
+
* R84 hub grounding-halo breath — 4 / 3.2 / 2.7 / 2.4 s
|
|
5
|
+
* R131 outer-ring orbit period — 16 / 14 / 12 / 10 s
|
|
6
|
+
* R132 groupbox marching ants — 14 / 12 / 10 / 8 s (grid only)
|
|
7
|
+
* R145 idle-spoke flow rate — 2.8 / 2.4 / 2.0 / 1.6 s (ring only)
|
|
8
|
+
* R146 radar sweep rotation — 8 / 6 / 4 / 3 s (both layouts)
|
|
9
|
+
*
|
|
10
|
+
* Shared R84 thresholds (0 / 1-2 / 3-5 / 6+) drive every layer. The
|
|
11
|
+
* sweep is the only layer visible in BOTH layouts and ties the family
|
|
12
|
+
* together at the canvas-wide scope.
|
|
13
|
+
*
|
|
14
|
+
* R45 baseline 6s sits at bucket 1 — preserved when workingCount in
|
|
15
|
+
* [1, 2] so existing demos and screenshots stay identical.
|
|
16
|
+
*/
|
|
17
|
+
import { chromium } from 'playwright';
|
|
18
|
+
import { readFileSync } from 'node:fs';
|
|
19
|
+
|
|
20
|
+
const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
|
|
21
|
+
|
|
22
|
+
async function probe(workingCount, totalCount) {
|
|
23
|
+
const browser = await chromium.launch({ headless: true });
|
|
24
|
+
const ctx = await browser.newContext({ viewport: { width: 1400, height: 1500 } });
|
|
25
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
26
|
+
await ctx.addInitScript(() => {
|
|
27
|
+
try { localStorage.setItem('anet-theme', 'cyber'); sessionStorage.setItem('anet_v3_auth', '1'); } catch {}
|
|
28
|
+
});
|
|
29
|
+
const fresh = new Date(Date.now() - 60 * 1000).toISOString();
|
|
30
|
+
await ctx.route('**/api/hub/status*', async (route) => {
|
|
31
|
+
const r = await route.fetch();
|
|
32
|
+
const b = await r.json();
|
|
33
|
+
const nid = (b.sessions || [])[0]?.network_id || 'default';
|
|
34
|
+
const sessions = [];
|
|
35
|
+
for (let i = 0; i < totalCount; i++) {
|
|
36
|
+
sessions.push({
|
|
37
|
+
alias: `node${i}`,
|
|
38
|
+
status: i < workingCount ? 'working' : 'idle',
|
|
39
|
+
model: 'claude-opus-4', runtime: 'cli-claude-code',
|
|
40
|
+
network_id: nid, project_dir: null,
|
|
41
|
+
created_at: fresh, updated_at: fresh, last_seen_at: fresh,
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
await route.fulfill({ response: r, json: { ...b, sessions } });
|
|
45
|
+
});
|
|
46
|
+
await ctx.route('**/api/hub/messages*', (route) => route.fulfill({ json: { messages: [] } }));
|
|
47
|
+
await ctx.route('**/api/hub/tasks*', (route) => route.fulfill({ json: { tasks: [] } }));
|
|
48
|
+
|
|
49
|
+
const page = await ctx.newPage();
|
|
50
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
|
|
51
|
+
await page.waitForFunction((n) => document.querySelectorAll('g[data-node]').length === n, totalCount, { timeout: 30000 });
|
|
52
|
+
await page.waitForSelector('.anet-topo-sweep', { timeout: 10000 });
|
|
53
|
+
await page.waitForTimeout(400);
|
|
54
|
+
|
|
55
|
+
const out = await page.evaluate(() => {
|
|
56
|
+
const g = document.querySelector('.anet-topo-sweep');
|
|
57
|
+
return {
|
|
58
|
+
bucket: g?.getAttribute('data-topo-sweep-bucket'),
|
|
59
|
+
dur: g?.getAttribute('data-topo-sweep-dur'),
|
|
60
|
+
cssDur: g ? getComputedStyle(g).getPropertyValue('animation-duration').trim() : null,
|
|
61
|
+
};
|
|
62
|
+
});
|
|
63
|
+
await browser.close();
|
|
64
|
+
return out;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const b0 = await probe(0, 4); // 0 working → bucket 0 (8s)
|
|
68
|
+
const b1 = await probe(2, 4); // 2 working → bucket 1 (6s, R45 baseline)
|
|
69
|
+
const b2 = await probe(4, 5); // 4 working → bucket 2 (4s)
|
|
70
|
+
const b3 = await probe(7, 8); // 7 working → bucket 3 (3s)
|
|
71
|
+
|
|
72
|
+
const consistent = (probe, bucket, dur) =>
|
|
73
|
+
probe.bucket === String(bucket) && probe.dur === String(dur) && probe.cssDur === `${dur}s`;
|
|
74
|
+
|
|
75
|
+
const results = {
|
|
76
|
+
b0_bucket0_8s: consistent(b0, 0, 8),
|
|
77
|
+
b1_bucket1_6s: consistent(b1, 1, 6),
|
|
78
|
+
b2_bucket2_4s: consistent(b2, 2, 4),
|
|
79
|
+
b3_bucket3_3s: consistent(b3, 3, 3),
|
|
80
|
+
// dur strictly decreases as busy climbs
|
|
81
|
+
dur_monotonic:
|
|
82
|
+
Number(b0.dur) > Number(b1.dur) &&
|
|
83
|
+
Number(b1.dur) > Number(b2.dur) &&
|
|
84
|
+
Number(b2.dur) > Number(b3.dur),
|
|
85
|
+
// R45 baseline preservation: bucket 1 still 6s
|
|
86
|
+
baseline_preserved: b1.dur === '6',
|
|
87
|
+
};
|
|
88
|
+
const ok = Object.values(results).every(Boolean);
|
|
89
|
+
console.log(`${ok ? '✅' : '❌'} sweep busyness:`, JSON.stringify(results),
|
|
90
|
+
`\n b0(0w/4)=`, b0,
|
|
91
|
+
`\n b1(2w/4)=`, b1,
|
|
92
|
+
`\n b2(4w/5)=`, b2,
|
|
93
|
+
`\n b3(7w/8)=`, b3);
|
|
94
|
+
process.exit(ok ? 0 : 1);
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/* Round 225 verification: info-density tabular-nums sweep across
|
|
2
|
+
* the three remaining digit-bearing texts in the TopoGraph after
|
|
3
|
+
* R224's edge badge:
|
|
4
|
+
* 1) Hub center digit (data-topo-hub-working-count)
|
|
5
|
+
* 2) Recent panel header (data-recent-panel-count tspan)
|
|
6
|
+
* 3) Recent row count (data-recent-row-count tspan)
|
|
7
|
+
*
|
|
8
|
+
* Pre-R225 each suffered the same monospace-digit jitter at the
|
|
9
|
+
* 9 → 10 boundary (the digit-vs-control glyph width variance is
|
|
10
|
+
* non-zero even in mono fonts; textAnchor='middle' or trailing
|
|
11
|
+
* text columns visibly shift on the boundary).
|
|
12
|
+
*
|
|
13
|
+
* Verification: getComputedStyle().fontVariantNumeric contains
|
|
14
|
+
* 'tabular-nums' on each of the three. Single populated scenario
|
|
15
|
+
* (4 working agents + 12-msg hot flow) drives all three at once.
|
|
16
|
+
*/
|
|
17
|
+
import { chromium } from 'playwright';
|
|
18
|
+
import { readFileSync } from 'node:fs';
|
|
19
|
+
|
|
20
|
+
const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
|
|
21
|
+
const browser = await chromium.launch({ headless: true });
|
|
22
|
+
const ctx = await browser.newContext({ viewport: { width: 1500, height: 1500 } });
|
|
23
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
24
|
+
await ctx.addInitScript(() => {
|
|
25
|
+
try { localStorage.setItem('anet-theme', 'cyber'); sessionStorage.setItem('anet_v3_auth', '1'); } catch {}
|
|
26
|
+
});
|
|
27
|
+
const fresh = new Date(Date.now() - 60 * 1000).toISOString();
|
|
28
|
+
await ctx.route('**/api/hub/status*', async (route) => {
|
|
29
|
+
const r = await route.fetch();
|
|
30
|
+
const b = await r.json();
|
|
31
|
+
const nid = (b.sessions || [])[0]?.network_id || 'default';
|
|
32
|
+
const mk = (alias) => ({
|
|
33
|
+
alias, status: 'working', model: 'claude-opus-4', runtime: 'claude-code-cli',
|
|
34
|
+
network_id: nid, project_dir: null,
|
|
35
|
+
created_at: fresh, updated_at: fresh, last_seen_at: fresh,
|
|
36
|
+
});
|
|
37
|
+
await route.fulfill({ response: r, json: { ...b, sessions: [
|
|
38
|
+
mk('alpha'), mk('beta'), mk('gamma'), mk('delta'),
|
|
39
|
+
] } });
|
|
40
|
+
});
|
|
41
|
+
const now = Date.now();
|
|
42
|
+
const msgs = [];
|
|
43
|
+
for (let i = 0; i < 12; i++) {
|
|
44
|
+
msgs.push({
|
|
45
|
+
id: `m${i}`, from_alias: 'alpha', to_alias: 'beta', content: 'hi',
|
|
46
|
+
network_id: 'default', created_at: new Date(now - (1000 + i * 50)).toISOString(),
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
await ctx.route('**/api/hub/messages*', (r2) => r2.fulfill({ json: { messages: msgs } }));
|
|
50
|
+
await ctx.route('**/api/hub/tasks*', (r2) => r2.fulfill({ json: { tasks: [] } }));
|
|
51
|
+
|
|
52
|
+
const page = await ctx.newPage();
|
|
53
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
|
|
54
|
+
await page.waitForFunction(() => document.querySelectorAll('g[data-node]').length === 4, { timeout: 30000 });
|
|
55
|
+
await page.waitForSelector('[data-recent-row-count]', { timeout: 10000, state: 'attached' });
|
|
56
|
+
await page.waitForTimeout(400);
|
|
57
|
+
|
|
58
|
+
const out = await page.evaluate(() => {
|
|
59
|
+
const fvn = (el) => el ? getComputedStyle(el).fontVariantNumeric : null;
|
|
60
|
+
const text = (el) => el?.textContent?.trim() || null;
|
|
61
|
+
const hubDigit = document.querySelector('[data-topo-hub-working-count]');
|
|
62
|
+
const panelCnt = document.querySelector('[data-recent-panel-count]');
|
|
63
|
+
const rowCnt = document.querySelector('[data-recent-row-count]');
|
|
64
|
+
return {
|
|
65
|
+
hub: { found: !!hubDigit, fvn: fvn(hubDigit), text: text(hubDigit),
|
|
66
|
+
working: hubDigit?.getAttribute('data-topo-hub-working-count') },
|
|
67
|
+
panel: { found: !!panelCnt, fvn: fvn(panelCnt), text: text(panelCnt) },
|
|
68
|
+
row: { found: !!rowCnt, fvn: fvn(rowCnt), text: text(rowCnt) },
|
|
69
|
+
};
|
|
70
|
+
});
|
|
71
|
+
await browser.close();
|
|
72
|
+
|
|
73
|
+
const hasTab = (s) => /tabular-nums/.test(s || '');
|
|
74
|
+
const results = {
|
|
75
|
+
hub_found: out.hub.found,
|
|
76
|
+
hub_tabular: hasTab(out.hub.fvn),
|
|
77
|
+
hub_text_present: /^\d+$/.test(out.hub.text || ''),
|
|
78
|
+
hub_text_equals_4: out.hub.text === '4',
|
|
79
|
+
|
|
80
|
+
panel_found: out.panel.found,
|
|
81
|
+
panel_tabular: hasTab(out.panel.fvn),
|
|
82
|
+
panel_text_flows: /^\d+\s+flows?$/.test(out.panel.text || ''),
|
|
83
|
+
|
|
84
|
+
row_found: out.row.found,
|
|
85
|
+
row_tabular: hasTab(out.row.fvn),
|
|
86
|
+
row_text_equals_12: out.row.text === '12',
|
|
87
|
+
};
|
|
88
|
+
const ok = Object.values(results).every(Boolean);
|
|
89
|
+
console.log(`${ok ? '✅' : '❌'} tabular-nums sweep:`, JSON.stringify(results),
|
|
90
|
+
'\n hub: ', out.hub,
|
|
91
|
+
'\n panel:', out.panel,
|
|
92
|
+
'\n row: ', out.row);
|
|
93
|
+
process.exit(ok ? 0 : 1);
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/* Round 174 verification: tier guide rings (ring layout) fade-in
|
|
2
|
+
* alongside R9/R172/R173 first-paint wave.
|
|
3
|
+
*
|
|
4
|
+
* Pre-R174 the structural scaffolding for ring layout — R54
|
|
5
|
+
* dashed concentric guide rings — appeared instantly while
|
|
6
|
+
* nodes inside eased in via R9/R72. Closes the symmetry with
|
|
7
|
+
* R173 group boxes (grid layout's structural frame).
|
|
8
|
+
*
|
|
9
|
+
* R174 wraps each tier ring <circle> in:
|
|
10
|
+
* className="anet-fade-in"
|
|
11
|
+
* style.animationDelay: tierIdx × 60ms (cap 8)
|
|
12
|
+
* transition list grows opacity 250ms ease-out
|
|
13
|
+
* data-tier-fade-delay={...}
|
|
14
|
+
*
|
|
15
|
+
* Test:
|
|
16
|
+
* 1. Force ring layout
|
|
17
|
+
* 2. Mock 16 sessions → triggers triple-tier render (>14)
|
|
18
|
+
* 3. Probe all [data-tier-ring] circles
|
|
19
|
+
* 4. Each has .anet-fade-in className + correct fade-delay
|
|
20
|
+
* 5. Delays strictly increase by 60ms
|
|
21
|
+
*/
|
|
22
|
+
import { chromium } from 'playwright';
|
|
23
|
+
import { readFileSync } from 'node:fs';
|
|
24
|
+
|
|
25
|
+
const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
|
|
26
|
+
const browser = await chromium.launch({ headless: true });
|
|
27
|
+
|
|
28
|
+
const ctx = await browser.newContext({ viewport: { width: 1500, height: 1500 } });
|
|
29
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
30
|
+
await ctx.addInitScript(() => {
|
|
31
|
+
try {
|
|
32
|
+
localStorage.setItem('anet-theme', 'cyber');
|
|
33
|
+
sessionStorage.setItem('anet_v3_auth', '1');
|
|
34
|
+
localStorage.setItem('anet-topo-layout', 'ring');
|
|
35
|
+
} catch {}
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
const fresh = new Date(Date.now() - 60 * 1000).toISOString();
|
|
39
|
+
await ctx.route('**/api/hub/status*', async (route) => {
|
|
40
|
+
const r = await route.fetch();
|
|
41
|
+
const b = await r.json();
|
|
42
|
+
const nid = (b.sessions || [])[0]?.network_id || 'default';
|
|
43
|
+
// 16 sessions → R98 triple-tier (threshold > 14)
|
|
44
|
+
const sessions = [];
|
|
45
|
+
for (let i = 0; i < 16; i++) {
|
|
46
|
+
sessions.push({
|
|
47
|
+
alias: `n${i}`,
|
|
48
|
+
status: 'working',
|
|
49
|
+
model: 'claude-opus-4',
|
|
50
|
+
runtime: 'cli-claude-code',
|
|
51
|
+
network_id: nid,
|
|
52
|
+
project_dir: null,
|
|
53
|
+
created_at: fresh, updated_at: fresh, last_seen_at: fresh,
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
await route.fulfill({ response: r, json: { ...b, sessions } });
|
|
57
|
+
});
|
|
58
|
+
await ctx.route('**/api/hub/messages*', (route) => route.fulfill({ json: { messages: [] } }));
|
|
59
|
+
await ctx.route('**/api/hub/tasks*', (route) => route.fulfill({ json: { tasks: [] } }));
|
|
60
|
+
|
|
61
|
+
const page = await ctx.newPage();
|
|
62
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
|
|
63
|
+
await page.waitForFunction(() => document.querySelectorAll('g[data-node]').length === 16, { timeout: 30000 });
|
|
64
|
+
await page.waitForSelector('[data-tier-ring]', { timeout: 10000 });
|
|
65
|
+
await page.waitForTimeout(400);
|
|
66
|
+
|
|
67
|
+
const probe = await page.evaluate(() => {
|
|
68
|
+
const rings = [...document.querySelectorAll('[data-tier-ring]')];
|
|
69
|
+
return rings.map(r => ({
|
|
70
|
+
radius: parseFloat(r.getAttribute('data-tier-ring') || ''),
|
|
71
|
+
occupancy: parseFloat(r.getAttribute('data-tier-occupancy') || ''),
|
|
72
|
+
hasFadeClass: (r.getAttribute('class') || '').includes('anet-fade-in'),
|
|
73
|
+
fadeDelayAttr: parseFloat(r.getAttribute('data-tier-fade-delay') || ''),
|
|
74
|
+
animationDelay: r.style.animationDelay || getComputedStyle(r).animationDelay,
|
|
75
|
+
transition: r.style.transition || getComputedStyle(r).transition,
|
|
76
|
+
}));
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
await browser.close();
|
|
80
|
+
|
|
81
|
+
const parseDelay = (s) => {
|
|
82
|
+
if (!s) return null;
|
|
83
|
+
if (s.endsWith('ms')) return parseFloat(s);
|
|
84
|
+
if (s.endsWith('s')) return parseFloat(s) * 1000;
|
|
85
|
+
return parseFloat(s);
|
|
86
|
+
};
|
|
87
|
+
const delays = probe.map(p => parseDelay(p.animationDelay));
|
|
88
|
+
|
|
89
|
+
const expectedDelays = probe.map((_, i) => Math.min(i, 8) * 60);
|
|
90
|
+
|
|
91
|
+
const results = {
|
|
92
|
+
three_tiers_found: probe.length === 3,
|
|
93
|
+
all_have_fade_class: probe.every(p => p.hasFadeClass),
|
|
94
|
+
all_have_opacity_in_transition: probe.every(p =>
|
|
95
|
+
(p.transition || '').includes('opacity')),
|
|
96
|
+
delay_attrs_match: probe.every((p, i) => p.fadeDelayAttr === expectedDelays[i]),
|
|
97
|
+
delays_match: delays.every((d, i) => Math.abs(d - expectedDelays[i]) < 0.5),
|
|
98
|
+
delays_strictly_increase: delays[0] < delays[1] && delays[1] < delays[2],
|
|
99
|
+
first_delay_0ms: delays[0] === 0,
|
|
100
|
+
third_delay_120ms: delays[2] === 120,
|
|
101
|
+
};
|
|
102
|
+
const ok = Object.values(results).every(Boolean);
|
|
103
|
+
console.log(`${ok ? '✅' : '❌'} tier-ring fade-in:`, JSON.stringify(results),
|
|
104
|
+
`\n rings =`, probe,
|
|
105
|
+
`\n delays (ms) =`, delays,
|
|
106
|
+
`\n expected =`, expectedDelays);
|
|
107
|
+
process.exit(ok ? 0 : 1);
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/* Round 92 verification: tier-ring opacity reflects occupancy. R54
|
|
2
|
+
* drew the guide rings at a fixed opacity regardless of how many
|
|
3
|
+
* nodes lived on each tier. R92 buckets the count and scales
|
|
4
|
+
* opacity, so a crowded tier shouts and an empty tier disappears.
|
|
5
|
+
*
|
|
6
|
+
* Probe three fleet sizes: small (4 → 1 ring), medium (12 → 2 rings),
|
|
7
|
+
* large (18 → 3 rings). Assert bucket monotonicity (higher count =
|
|
8
|
+
* higher bucket = higher opacity) and that each rendered ring carries
|
|
9
|
+
* its occupancy + bucket data attributes.
|
|
10
|
+
*/
|
|
11
|
+
import { chromium } from 'playwright';
|
|
12
|
+
import { readFileSync } from 'node:fs';
|
|
13
|
+
|
|
14
|
+
const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
|
|
15
|
+
const browser = await chromium.launch({ headless: true });
|
|
16
|
+
const fresh = new Date(Date.now() - 60 * 1000).toISOString();
|
|
17
|
+
|
|
18
|
+
const probe = async (count) => {
|
|
19
|
+
const ctx = await browser.newContext({ viewport: { width: 1400, height: 1500 } });
|
|
20
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
21
|
+
await ctx.addInitScript(() => {
|
|
22
|
+
try {
|
|
23
|
+
localStorage.setItem('anet-theme', 'cyber');
|
|
24
|
+
localStorage.setItem('anet-topo-layout', 'ring');
|
|
25
|
+
sessionStorage.setItem('anet_v3_auth', '1');
|
|
26
|
+
} catch {}
|
|
27
|
+
});
|
|
28
|
+
await ctx.route('**/api/hub/status*', async (route) => {
|
|
29
|
+
const r = await route.fetch();
|
|
30
|
+
const b = await r.json();
|
|
31
|
+
const nid = (b.sessions || [])[0]?.network_id || 'default';
|
|
32
|
+
const sessions = [];
|
|
33
|
+
for (let i = 0; i < count; i++) {
|
|
34
|
+
sessions.push({ alias: `n${i}`, status: 'idle', model: 'claude-opus-4', runtime: 'cli-claude-code',
|
|
35
|
+
network_id: nid, project_dir: null, created_at: fresh, updated_at: fresh, last_seen_at: fresh });
|
|
36
|
+
}
|
|
37
|
+
await route.fulfill({ response: r, json: { ...b, sessions } });
|
|
38
|
+
});
|
|
39
|
+
await ctx.route('**/api/hub/messages*', (route) => route.fulfill({ json: { messages: [] } }));
|
|
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) => document.querySelectorAll('g[data-node]').length === n,
|
|
44
|
+
count, { timeout: 30000 });
|
|
45
|
+
await page.waitForTimeout(500);
|
|
46
|
+
|
|
47
|
+
const rings = await page.evaluate(() => {
|
|
48
|
+
return [...document.querySelectorAll('[data-tier-ring]')].map(r => ({
|
|
49
|
+
radius: r.getAttribute('data-tier-ring'),
|
|
50
|
+
occupancy: r.getAttribute('data-tier-occupancy'),
|
|
51
|
+
bucket: r.getAttribute('data-tier-bucket'),
|
|
52
|
+
opacity: +(r.getAttribute('opacity') || '0'),
|
|
53
|
+
})).sort((a, b) => +a.radius - +b.radius);
|
|
54
|
+
});
|
|
55
|
+
await ctx.close();
|
|
56
|
+
return rings;
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
const small = await probe(4); // 4 nodes → 1 ring, occupancy 4, bucket 1 (3-6)
|
|
60
|
+
const medium = await probe(12); // 12 nodes → 2 rings
|
|
61
|
+
const large = await probe(18); // 18 nodes → 3 rings
|
|
62
|
+
await browser.close();
|
|
63
|
+
|
|
64
|
+
const occupancySum = (rings) => rings.reduce((acc, r) => acc + +r.occupancy, 0);
|
|
65
|
+
|
|
66
|
+
const results = {
|
|
67
|
+
small_oneRing: small.length === 1,
|
|
68
|
+
small_occupancy4: small[0]?.occupancy === '4',
|
|
69
|
+
small_bucket1: small[0]?.bucket === '1',
|
|
70
|
+
medium_twoRings: medium.length === 2,
|
|
71
|
+
medium_occupancyMatchesFleet: occupancySum(medium) === 12,
|
|
72
|
+
large_threeRings: large.length === 3,
|
|
73
|
+
large_occupancyMatchesFleet: occupancySum(large) === 18,
|
|
74
|
+
// Higher bucket → higher opacity (monotonic ladder).
|
|
75
|
+
bucketLadder_monotonic: large.every(r => {
|
|
76
|
+
const b = +r.bucket;
|
|
77
|
+
// dark theme: bucket 0 → 0.32, 1 → 0.46, 2 → 0.62
|
|
78
|
+
const expected = [0.32, 0.46, 0.62][b];
|
|
79
|
+
return Math.abs(r.opacity - expected) < 0.01;
|
|
80
|
+
}),
|
|
81
|
+
};
|
|
82
|
+
const ok = Object.values(results).every(Boolean);
|
|
83
|
+
console.log(`${ok ? '✅' : '❌'} tier-ring occupancy:`, JSON.stringify(results),
|
|
84
|
+
`\n small (4)=`, small,
|
|
85
|
+
`\n medium (12)=`, medium,
|
|
86
|
+
`\n large (18)=`, large);
|
|
87
|
+
process.exit(ok ? 0 : 1);
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/* Round 54 verification: tier-radius guide rings render at the active
|
|
2
|
+
* tier radii only, picked from the online node count.
|
|
3
|
+
* - N ≤ 8 → 1 ring at r=220
|
|
4
|
+
* - 9-14 → 2 rings at r=175 and r=260
|
|
5
|
+
* - N > 14 → 3 rings at r=145, 215, 285
|
|
6
|
+
* - Grid layout has NO tier rings (they're ring-only).
|
|
7
|
+
* Identified via the `data-tier-ring` attribute the implementation
|
|
8
|
+
* stamps on each guide circle. */
|
|
9
|
+
import { chromium } from 'playwright';
|
|
10
|
+
import { readFileSync } from 'node:fs';
|
|
11
|
+
|
|
12
|
+
const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
|
|
13
|
+
const browser = await chromium.launch({ headless: true });
|
|
14
|
+
|
|
15
|
+
async function probe(layout, count) {
|
|
16
|
+
const ctx = await browser.newContext({ viewport: { width: 1280, height: 1500 } });
|
|
17
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
18
|
+
await ctx.addInitScript((layout) => {
|
|
19
|
+
try {
|
|
20
|
+
localStorage.setItem('anet-theme', 'cyber');
|
|
21
|
+
localStorage.setItem('anet-topo-layout', layout);
|
|
22
|
+
sessionStorage.setItem('anet_v3_auth', '1');
|
|
23
|
+
} catch {}
|
|
24
|
+
}, layout);
|
|
25
|
+
const fresh = new Date(Date.now() - 60 * 1000).toISOString();
|
|
26
|
+
await ctx.route('**/api/hub/status*', async (route) => {
|
|
27
|
+
const r = await route.fetch();
|
|
28
|
+
const b = await r.json();
|
|
29
|
+
const nid = (b.sessions || [])[0]?.network_id || 'default';
|
|
30
|
+
const sessions = Array.from({ length: count }).map((_, i) => ({
|
|
31
|
+
alias: `n${i.toString().padStart(2, '0')}`,
|
|
32
|
+
status: 'idle', network_id: nid, project_dir: null,
|
|
33
|
+
created_at: fresh, updated_at: fresh, last_seen_at: fresh,
|
|
34
|
+
}));
|
|
35
|
+
await route.fulfill({ response: r, json: { ...b, sessions } });
|
|
36
|
+
});
|
|
37
|
+
await ctx.route('**/api/hub/messages*', (route) => route.fulfill({ json: { messages: [] } }));
|
|
38
|
+
await ctx.route('**/api/hub/tasks*', (route) => route.fulfill({ json: { tasks: [] } }));
|
|
39
|
+
const page = await ctx.newPage();
|
|
40
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
|
|
41
|
+
await page.waitForFunction(c => document.querySelectorAll('g[data-node]').length === c, count, { timeout: 30000 });
|
|
42
|
+
await page.waitForTimeout(400);
|
|
43
|
+
const radii = await page.evaluate(() => {
|
|
44
|
+
const svg = document.querySelector('svg[viewBox="0 0 1000 680"]');
|
|
45
|
+
return [...svg.querySelectorAll('circle[data-tier-ring]')]
|
|
46
|
+
.map(c => +c.getAttribute('data-tier-ring'))
|
|
47
|
+
.sort((a, b) => a - b);
|
|
48
|
+
});
|
|
49
|
+
await ctx.close();
|
|
50
|
+
return radii;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const single = await probe('ring', 6);
|
|
54
|
+
const dual = await probe('ring', 12);
|
|
55
|
+
const triple = await probe('ring', 22);
|
|
56
|
+
const grid = await probe('grid', 6);
|
|
57
|
+
|
|
58
|
+
await browser.close();
|
|
59
|
+
const eq = (a, b) => a.length === b.length && a.every((v, i) => v === b[i]);
|
|
60
|
+
const results = {
|
|
61
|
+
singleHas220: eq(single, [220]),
|
|
62
|
+
dualHas175And260: eq(dual, [175, 260]),
|
|
63
|
+
tripleHas145_215_285: eq(triple, [145, 215, 285]),
|
|
64
|
+
gridHasNoTierRings: eq(grid, []),
|
|
65
|
+
};
|
|
66
|
+
const ok = Object.values(results).every(Boolean);
|
|
67
|
+
console.log(`${ok ? '✅' : '❌'} tier rings:`, JSON.stringify(results),
|
|
68
|
+
`\n single=${JSON.stringify(single)} dual=${JSON.stringify(dual)} triple=${JSON.stringify(triple)} grid=${JSON.stringify(grid)}`);
|
|
69
|
+
process.exit(ok ? 0 : 1);
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/* Round 93 verification: tier rings tint to pal.legendAccent when
|
|
2
|
+
* any of pinnedStatus / pinnedGroup / pinnedVendor is active, and
|
|
3
|
+
* revert to the neutral pal.ringStroke when all three release.
|
|
4
|
+
*
|
|
5
|
+
* Drive pin state via the R69 CustomEvent for status (deterministic;
|
|
6
|
+
* same approach the R82 chip-pin-mirror test uses) and the vendor
|
|
7
|
+
* letter click for vendor. Verify data-tier-tinted toggles + stroke
|
|
8
|
+
* attribute differs from the neutral baseline.
|
|
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
|
+
const ctx = await browser.newContext({ viewport: { width: 1400, height: 1500 } });
|
|
17
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
18
|
+
await ctx.addInitScript(() => {
|
|
19
|
+
try {
|
|
20
|
+
localStorage.setItem('anet-theme', 'cyber');
|
|
21
|
+
localStorage.setItem('anet-topo-layout', 'ring');
|
|
22
|
+
sessionStorage.setItem('anet_v3_auth', '1');
|
|
23
|
+
sessionStorage.removeItem('anet-topo-pinned-status');
|
|
24
|
+
sessionStorage.removeItem('anet-topo-pinned-group');
|
|
25
|
+
sessionStorage.removeItem('anet-topo-pinned-vendor');
|
|
26
|
+
} catch {}
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
const fresh = new Date(Date.now() - 60 * 1000).toISOString();
|
|
30
|
+
await ctx.route('**/api/hub/status*', async (route) => {
|
|
31
|
+
const r = await route.fetch();
|
|
32
|
+
const b = await r.json();
|
|
33
|
+
const nid = (b.sessions || [])[0]?.network_id || 'default';
|
|
34
|
+
// 4 nodes → single tier (≤8 threshold). Enough to have 1 ring to inspect.
|
|
35
|
+
const mk = (alias, model) => ({
|
|
36
|
+
alias, status: 'idle', model, runtime: 'cli-claude-code',
|
|
37
|
+
network_id: nid, project_dir: null,
|
|
38
|
+
created_at: fresh, updated_at: fresh, last_seen_at: fresh,
|
|
39
|
+
});
|
|
40
|
+
const sessions = [
|
|
41
|
+
mk('alpha', 'claude-opus-4'),
|
|
42
|
+
mk('beta', 'gpt-5'),
|
|
43
|
+
mk('gamma', 'claude-opus-4'),
|
|
44
|
+
mk('delta', 'gpt-5'),
|
|
45
|
+
];
|
|
46
|
+
await route.fulfill({ response: r, json: { ...b, sessions } });
|
|
47
|
+
});
|
|
48
|
+
await ctx.route('**/api/hub/messages*', (route) => route.fulfill({ json: { messages: [] } }));
|
|
49
|
+
await ctx.route('**/api/hub/tasks*', (route) => route.fulfill({ json: { tasks: [] } }));
|
|
50
|
+
const page = await ctx.newPage();
|
|
51
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
|
|
52
|
+
await page.waitForFunction(() => document.querySelectorAll('g[data-node]').length === 4, { timeout: 30000 });
|
|
53
|
+
await page.waitForTimeout(400);
|
|
54
|
+
|
|
55
|
+
const ring = () => page.evaluate(() => {
|
|
56
|
+
const r = document.querySelector('[data-tier-ring]');
|
|
57
|
+
if (!r) return null;
|
|
58
|
+
return {
|
|
59
|
+
tinted: r.getAttribute('data-tier-tinted'),
|
|
60
|
+
stroke: r.getAttribute('stroke'),
|
|
61
|
+
};
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
const before = await ring();
|
|
65
|
+
|
|
66
|
+
// Pin a status — tier ring should tint.
|
|
67
|
+
await page.evaluate(() => {
|
|
68
|
+
sessionStorage.setItem('anet-topo-pinned-status', 'idle');
|
|
69
|
+
window.dispatchEvent(new CustomEvent('anet:topo-pin', { detail: { kind: 'status', value: 'idle' } }));
|
|
70
|
+
});
|
|
71
|
+
await page.waitForTimeout(300);
|
|
72
|
+
const afterStatusPin = await ring();
|
|
73
|
+
|
|
74
|
+
// Clear via Esc — ring should revert.
|
|
75
|
+
await page.keyboard.press('Escape');
|
|
76
|
+
await page.waitForTimeout(250);
|
|
77
|
+
const afterEscStatus = await ring();
|
|
78
|
+
|
|
79
|
+
// Pin vendor — tier ring should tint again.
|
|
80
|
+
await page.locator('[data-vendor-letter="A"]').click();
|
|
81
|
+
await page.mouse.move(10, 10);
|
|
82
|
+
await page.waitForTimeout(250);
|
|
83
|
+
const afterVendorPin = await ring();
|
|
84
|
+
|
|
85
|
+
// Clear via Esc — back to neutral.
|
|
86
|
+
await page.keyboard.press('Escape');
|
|
87
|
+
await page.waitForTimeout(250);
|
|
88
|
+
const afterEscVendor = await ring();
|
|
89
|
+
|
|
90
|
+
await browser.close();
|
|
91
|
+
|
|
92
|
+
const results = {
|
|
93
|
+
before_neutral: before?.tinted === 'false',
|
|
94
|
+
before_strokeSet: typeof before?.stroke === 'string' && before.stroke.length > 0,
|
|
95
|
+
statusPin_tinted: afterStatusPin?.tinted === 'true',
|
|
96
|
+
statusPin_strokeDiffers: afterStatusPin?.stroke !== before?.stroke,
|
|
97
|
+
escStatus_revertsTinted: afterEscStatus?.tinted === 'false',
|
|
98
|
+
escStatus_strokeMatchesBaseline: afterEscStatus?.stroke === before?.stroke,
|
|
99
|
+
vendorPin_tinted: afterVendorPin?.tinted === 'true',
|
|
100
|
+
vendorPin_strokeDiffers: afterVendorPin?.stroke !== before?.stroke,
|
|
101
|
+
escVendor_revertsTinted: afterEscVendor?.tinted === 'false',
|
|
102
|
+
};
|
|
103
|
+
const ok = Object.values(results).every(Boolean);
|
|
104
|
+
console.log(`${ok ? '✅' : '❌'} tier-ring tint:`, JSON.stringify(results),
|
|
105
|
+
`\n before=`, before,
|
|
106
|
+
`\n afterStatusPin=`, afterStatusPin,
|
|
107
|
+
`\n afterEscStatus=`, afterEscStatus,
|
|
108
|
+
`\n afterVendorPin=`, afterVendorPin,
|
|
109
|
+
`\n afterEscVendor=`, afterEscVendor);
|
|
110
|
+
process.exit(ok ? 0 : 1);
|