@sleep2agi/agent-network-dashboard 0.4.6 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.next/BUILD_ID +1 -1
- package/.next/app-path-routes-manifest.json +2 -0
- package/.next/build-manifest.json +3 -3
- package/.next/diagnostics/route-bundle-stats.json +31 -31
- package/.next/fallback-build-manifest.json +3 -3
- package/.next/prerender-manifest.json +3 -3
- package/.next/routes-manifest.json +16 -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/server/[hostname]/agents/route/app-paths-manifest.json +3 -0
- package/.next/server/app/api/hub/server/[hostname]/agents/route/build-manifest.json +9 -0
- package/.next/server/app/api/hub/server/[hostname]/agents/route/server-reference-manifest.json +4 -0
- package/.next/server/app/api/hub/server/[hostname]/agents/route.js +7 -0
- package/.next/server/app/api/hub/server/[hostname]/agents/route.js.map +5 -0
- package/.next/server/app/api/hub/server/[hostname]/agents/route.js.nft.json +1 -0
- package/.next/server/app/api/hub/server/[hostname]/agents/route_client-reference-manifest.js +3 -0
- package/.next/server/app/api/hub/server/[hostname]/health/route/app-paths-manifest.json +3 -0
- package/.next/server/app/api/hub/server/[hostname]/health/route/build-manifest.json +9 -0
- package/.next/server/app/api/hub/server/[hostname]/health/route/server-reference-manifest.json +4 -0
- package/.next/server/app/api/hub/server/[hostname]/health/route.js +7 -0
- package/.next/server/app/api/hub/server/[hostname]/health/route.js.map +5 -0
- package/.next/server/app/api/hub/server/[hostname]/health/route.js.nft.json +1 -0
- package/.next/server/app/api/hub/server/[hostname]/health/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 +2 -0
- package/.next/server/chunks/0dk5_next-internal_server_app_api_hub_server_[hostname]_agents_route_actions_0vr92s4.js +3 -0
- package/.next/server/chunks/0dk5_next-internal_server_app_api_hub_server_[hostname]_agents_route_actions_0vr92s4.js.map +1 -0
- package/.next/server/chunks/0dk5_next-internal_server_app_api_hub_server_[hostname]_health_route_actions_0vr-bv5.js +3 -0
- package/.next/server/chunks/0dk5_next-internal_server_app_api_hub_server_[hostname]_health_route_actions_0vr-bv5.js.map +1 -0
- package/.next/server/chunks/[root-of-the-server]__05nyivw._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__05nyivw._.js.map +1 -0
- package/.next/server/chunks/[root-of-the-server]__0floe3h._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__0floe3h._.js.map +1 -0
- package/.next/server/chunks/[root-of-the-server]__0tx8s8i._.js +1 -1
- package/.next/server/chunks/[root-of-the-server]__0tx8s8i._.js.map +1 -1
- package/.next/server/chunks/ssr/agent-network-dashboard_09kk21a._.js +4 -2
- 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_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_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/0aauz~36q5n2a.css +2 -0
- package/.next/static/chunks/0f~0kgy2pycyc.js +1 -0
- package/.next/static/chunks/0l_~q07bhpkcx.js +7 -0
- package/.next/static/chunks/1175-dp18a1e_.js +1 -0
- package/.next/static/chunks/1552j0415oeal.js +4 -0
- package/.next/trace +2 -2
- package/.next/trace-build +1 -1
- package/.next/types/routes.d.ts +3 -1
- package/.next/types/validator.ts +18 -0
- package/app/api/hub/server/[hostname]/agents/route.ts +62 -0
- package/app/api/hub/server/[hostname]/health/route.ts +58 -0
- package/app/api/hub/servers/route.ts +88 -1
- package/app/components/CommandPalette.tsx +107 -0
- package/app/components/HelpOverlay.tsx +109 -1
- package/app/components/ServersDrawer.tsx +181 -5
- package/app/components/TopoGraph.tsx +6409 -286
- package/app/globals.css +110 -5
- package/app/lib/vendorIdentity.ts +14 -3
- package/docs/rfc/v0.10.0-hero3-dashboard-upgrade.md +230 -0
- package/package.json +2 -2
- package/public/sleep2agi-logo.svg +11 -0
- package/public/vendors/claude.svg +11 -0
- package/public/vendors/minimax.svg +11 -0
- package/public/vendors/openai.svg +12 -0
- package/screenshots/r293-p0/after-full.png +0 -0
- package/screenshots/r293-p0/after-topo.png +0 -0
- package/screenshots/r293-p0/baseline-full.png +0 -0
- package/screenshots/r293-p0/baseline-topo.png +0 -0
- package/screenshots/r293-p0/logo-integrated-full.png +0 -0
- package/screenshots/r293-p0/logo-integrated-topo.png +0 -0
- package/screenshots/r293-p0/servers-drawer-v0.10.0-full.png +0 -0
- package/screenshots/r293-p0/servers-drawer-v0.10.0.png +0 -0
- package/screenshots/r293-p0/wave1-after-full.png +0 -0
- package/screenshots/r293-p0/wave1-after-topo.png +0 -0
- package/scripts/p0-servers-drawer-screenshot.mjs +99 -0
- package/scripts/p0-topo-screenshot.mjs +82 -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-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-brand-logo-transition-test.mjs +94 -0
- package/scripts/topo-brand-watermark-test.mjs +97 -0
- package/scripts/topo-canvas-aria-test.mjs +108 -0
- package/scripts/topo-canvas-brand-fade-test.mjs +87 -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-gap-test.mjs +90 -0
- package/scripts/topo-chip-row-semantic-gap-test.mjs +97 -0
- package/scripts/topo-chip-row-tabular-test.mjs +111 -0
- package/scripts/topo-chip-unit-demotion-test.mjs +93 -0
- package/scripts/topo-chiprow-data-weight-test.mjs +94 -0
- package/scripts/topo-chrome-a11y-test.mjs +107 -0
- package/scripts/topo-chrome-active-weight-test.mjs +104 -0
- package/scripts/topo-chrome-focus-ring-unify-test.mjs +100 -0
- package/scripts/topo-chrome-gap-test.mjs +73 -0
- package/scripts/topo-chrome-icon-stroke-test.mjs +95 -0
- package/scripts/topo-chrome-inactive-color-test.mjs +90 -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-strip-semantic-gap-test.mjs +99 -0
- package/scripts/topo-chrome-strip-theme-ease-test.mjs +99 -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-chrome-zoom-readout-weight-test.mjs +81 -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-corner-radius-unify-test.mjs +103 -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-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 +13 -5
- package/scripts/topo-edge-pill-hot-test.mjs +129 -0
- package/scripts/topo-edge-pill-test.mjs +105 -0
- package/scripts/topo-edge-ping-pulse-retired-test.mjs +119 -0
- package/scripts/topo-edge-stroke-ease-test.mjs +100 -0
- package/scripts/topo-edge-stroke-transition-test.mjs +132 -0
- package/scripts/topo-empty-hint-tracking-test.mjs +84 -0
- package/scripts/topo-empty-state-breath-test.mjs +150 -0
- package/scripts/topo-empty-state-crossfade-test.mjs +130 -0
- package/scripts/topo-empty-state-recenter-test.mjs +107 -0
- package/scripts/topo-empty-subhint-tracking-test.mjs +87 -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-tabular-test.mjs +135 -0
- package/scripts/topo-filter-pill-count-test.mjs +110 -0
- package/scripts/topo-filter-pill-mobile-test.mjs +90 -0
- package/scripts/topo-freshness-chip-transition-test.mjs +80 -0
- package/scripts/topo-freshness-chip-weight-test.mjs +90 -0
- package/scripts/topo-freshness-conditional-render-test.mjs +92 -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 +6 -1
- 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 +104 -0
- package/scripts/topo-group-pip-singletier-drop-test.mjs +131 -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-header-gap-test.mjs +94 -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-html-overlay-padding-unify-test.mjs +120 -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 +7 -2
- package/scripts/topo-hub-working-count-test.mjs +99 -0
- package/scripts/topo-ingroup-edge-test.mjs +103 -0
- package/scripts/topo-inner-radar-ring-retired-test.mjs +89 -0
- package/scripts/topo-kicker-color-test.mjs +93 -0
- package/scripts/topo-kicker-tracking-test.mjs +101 -0
- package/scripts/topo-kicker-weight-test.mjs +98 -0
- package/scripts/topo-label-card-theme-ease-test.mjs +85 -0
- package/scripts/topo-label-lift-test.mjs +5 -1
- package/scripts/topo-layout-hover-text-preview-test.mjs +101 -0
- package/scripts/topo-layout-switch-crossfade-test.mjs +126 -0
- package/scripts/topo-layout-toggle-border-unify-test.mjs +104 -0
- package/scripts/topo-layout-toggle-test.mjs +131 -0
- package/scripts/topo-layout-trailer-mr-test.mjs +82 -0
- package/scripts/topo-legend-compress-test.mjs +107 -0
- package/scripts/topo-legend-count-empty-test.mjs +126 -0
- package/scripts/topo-legend-count-tabular-parity-test.mjs +90 -0
- package/scripts/topo-legend-count-tabular-test.mjs +87 -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-count-weight-test.mjs +86 -0
- package/scripts/topo-legend-header-symmetric-inset-test.mjs +112 -0
- package/scripts/topo-legend-hitbox-swatch-center-test.mjs +93 -0
- package/scripts/topo-legend-hover-test.mjs +113 -0
- package/scripts/topo-legend-offline-delimiter-test.mjs +84 -0
- package/scripts/topo-legend-offline-label-simplify-test.mjs +86 -0
- package/scripts/topo-legend-panel-count-weight-test.mjs +89 -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-labels-simplify-test.mjs +80 -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-legend-swatch-radius-test.mjs +78 -0
- package/scripts/topo-minimap-a11y-test.mjs +101 -0
- package/scripts/topo-minimap-dot-transition-test.mjs +113 -0
- package/scripts/topo-minimap-radius-test.mjs +88 -0
- package/scripts/topo-minimap-rect-stroke-test.mjs +94 -0
- package/scripts/topo-minimap-viewport-smooth-test.mjs +124 -0
- package/scripts/topo-monogram-font-test.mjs +112 -0
- package/scripts/topo-monogram-stroke-test.mjs +101 -0
- package/scripts/topo-more-flows-letterspacing-test.mjs +111 -0
- package/scripts/topo-node-a11y-test.mjs +107 -0
- package/scripts/topo-node-alias-chat-pin-test.mjs +95 -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-particles-retired-test.mjs +91 -0
- package/scripts/topo-panel-count-unit-test.mjs +112 -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-rx-test.mjs +90 -0
- package/scripts/topo-panel-theme-ease-test.mjs +85 -0
- package/scripts/topo-panel-title-fill-ease-test.mjs +91 -0
- package/scripts/topo-panel-title-tracking-test.mjs +78 -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-prefix-opacity-test.mjs +107 -0
- package/scripts/topo-prepublish-guard-test.mjs +95 -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-dot-retired-test.mjs +86 -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-count-weight-test.mjs +91 -0
- package/scripts/topo-recent-panel-footer-breath-test.mjs +142 -0
- package/scripts/topo-recent-panel-hot-header-test.mjs +132 -0
- package/scripts/topo-recent-panel-hot-tabular-test.mjs +113 -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-panel-readability-bump-test.mjs +151 -0
- package/scripts/topo-recent-row-count-fill-test.mjs +129 -0
- package/scripts/topo-recent-row-count-weight-test.mjs +112 -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-tabular-test.mjs +108 -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-reset-spin-test.mjs +120 -0
- package/scripts/topo-runtime-badge-grow-test.mjs +114 -0
- package/scripts/topo-spokes-retired-test.mjs +93 -0
- package/scripts/topo-starfield-density-test.mjs +89 -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-guide-dashes-test.mjs +86 -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-title-block-tight-leading-test.mjs +95 -0
- package/scripts/topo-title-tracking-test.mjs +98 -0
- package/scripts/topo-titleblock-gap-test.mjs +86 -0
- package/scripts/topo-titleblock-margin-test.mjs +83 -0
- package/scripts/topo-toggle-inactive-cyan-hover-test.mjs +110 -0
- package/scripts/topo-top-rail-theme-ease-test.mjs +89 -0
- package/scripts/topo-vendor-chip-hover-test.mjs +111 -0
- package/scripts/topo-vendor-chip-self-hover-test.mjs +131 -0
- package/scripts/topo-vendor-chip-tabular-test.mjs +92 -0
- package/scripts/topo-vendor-chip-threshold-test.mjs +78 -0
- package/scripts/topo-vendor-chip-weight-test.mjs +87 -0
- package/scripts/topo-vendor-count-suffix-test.mjs +95 -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-watermark-tracking-test.mjs +99 -0
- package/scripts/topo-working-chip-pin-test.mjs +154 -0
- package/scripts/topo-working-halo-breath-retired-test.mjs +99 -0
- package/scripts/topo-wrapper-flow-arrow-theme-test.mjs +97 -0
- package/scripts/topo-wrapper-radius-test.mjs +73 -0
- package/scripts/topo-wrapper-shadow-theme-ease-test.mjs +89 -0
- package/.next/static/chunks/088ouqy7tekty.js +0 -2
- package/.next/static/chunks/0hyl7mdapsz38.js +0 -1
- package/.next/static/chunks/0mqwn-l7wtcdo.js +0 -7
- package/.next/static/chunks/127kw7~wsnyu7.css +0 -2
- package/.next/static/chunks/16yfxp9ak2gdm.js +0 -1
- /package/.next/static/{23MxP0RBVA4BaOJ_HMYmM → 424zX3i80AJ_wHF_otKuP}/_buildManifest.js +0 -0
- /package/.next/static/{23MxP0RBVA4BaOJ_HMYmM → 424zX3i80AJ_wHF_otKuP}/_clientMiddlewareManifest.js +0 -0
- /package/.next/static/{23MxP0RBVA4BaOJ_HMYmM → 424zX3i80AJ_wHF_otKuP}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
/* Round 201 verification: the chip-row "N working" / "N online" chips
|
|
2
|
+
* adopt deeper versions of their own identity colour on hover,
|
|
3
|
+
* mirroring R193 active-links chip pattern.
|
|
4
|
+
*
|
|
5
|
+
* Pre-R201 hover working chip → R55 canvas dim + chip-row highlight,
|
|
6
|
+
* but chip itself stayed at bg-{color}-500/10 — cause silent, effect
|
|
7
|
+
* loud. R201 deepens 10→15 bg and 20→30 border on hover (only when
|
|
8
|
+
* the chip has a target count > 0). The inline transition list is
|
|
9
|
+
* extended to cover background-color + border-color so the swap
|
|
10
|
+
* eases instead of snapping (Tailwind transition-colors on the
|
|
11
|
+
* className alone would be overridden by the existing R180 inline
|
|
12
|
+
* box-shadow transition).
|
|
13
|
+
*
|
|
14
|
+
* Test (cyber dark, 4 working sessions):
|
|
15
|
+
* 1. Working chip: clickable='true', className has hover:bg-green-500/15
|
|
16
|
+
* + hover:border-green-500/30, transition includes 'background-color'
|
|
17
|
+
* + 'border-color' (both 200ms), inline still has 'box-shadow 150ms'.
|
|
18
|
+
* 2. Online chip: same shape with cyan hue.
|
|
19
|
+
* 3. Hover the working chip — wait past 220ms → computed bg
|
|
20
|
+
* shifts to a more-saturated/darker green (RGB-or-OKLab signal).
|
|
21
|
+
* 4. Move away — bg returns to idle (with margin past 220ms).
|
|
22
|
+
* 5. The chip's R55 canvas-effect setHoveredStatus still fires —
|
|
23
|
+
* verified via hoveredStatus change reflected on the working
|
|
24
|
+
* legend row's data-legend-row-lifted attribute.
|
|
25
|
+
*/
|
|
26
|
+
import { chromium } from 'playwright';
|
|
27
|
+
import { readFileSync } from 'node:fs';
|
|
28
|
+
|
|
29
|
+
const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
|
|
30
|
+
const browser = await chromium.launch({ headless: true });
|
|
31
|
+
|
|
32
|
+
const ctx = await browser.newContext({ viewport: { width: 1500, height: 1500 } });
|
|
33
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
34
|
+
await ctx.addInitScript(() => {
|
|
35
|
+
try { localStorage.setItem('anet-theme', 'cyber'); sessionStorage.setItem('anet_v3_auth', '1'); } 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
|
+
const mk = (alias) => ({
|
|
44
|
+
alias, status: 'working', model: 'claude-opus-4', runtime: 'cli-claude-code',
|
|
45
|
+
network_id: nid, project_dir: null,
|
|
46
|
+
created_at: fresh, updated_at: fresh, last_seen_at: fresh,
|
|
47
|
+
});
|
|
48
|
+
await route.fulfill({ response: r, json: { ...b, sessions: [
|
|
49
|
+
mk('alpha'), mk('beta'), mk('gamma'), mk('delta'),
|
|
50
|
+
] } });
|
|
51
|
+
});
|
|
52
|
+
await ctx.route('**/api/hub/messages*', (route) => route.fulfill({ json: { messages: [] } }));
|
|
53
|
+
await ctx.route('**/api/hub/tasks*', (route) => route.fulfill({ json: { tasks: [] } }));
|
|
54
|
+
|
|
55
|
+
const page = await ctx.newPage();
|
|
56
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
|
|
57
|
+
await page.waitForFunction(() => document.querySelectorAll('g[data-node]').length === 4, { timeout: 30000 });
|
|
58
|
+
await page.waitForSelector('[data-working-chip]', { timeout: 10000 });
|
|
59
|
+
await page.waitForTimeout(300);
|
|
60
|
+
|
|
61
|
+
const probeChip = async (selector) => page.evaluate((sel) => {
|
|
62
|
+
const el = document.querySelector(sel);
|
|
63
|
+
if (!el) return null;
|
|
64
|
+
const cs = getComputedStyle(el);
|
|
65
|
+
return {
|
|
66
|
+
className: el.getAttribute('class') || '',
|
|
67
|
+
clickable: el.getAttribute('data-working-chip-clickable') ||
|
|
68
|
+
el.getAttribute('data-online-chip-clickable'),
|
|
69
|
+
bg: cs.backgroundColor,
|
|
70
|
+
borderColor: cs.borderTopColor,
|
|
71
|
+
transition: el.style.transition,
|
|
72
|
+
};
|
|
73
|
+
}, selector);
|
|
74
|
+
|
|
75
|
+
const idleWorking = await probeChip('[data-working-chip]');
|
|
76
|
+
const idleOnline = await probeChip('[data-online-chip]');
|
|
77
|
+
|
|
78
|
+
await page.hover('[data-working-chip]');
|
|
79
|
+
await page.waitForTimeout(250);
|
|
80
|
+
const hoverWorking = await probeChip('[data-working-chip]');
|
|
81
|
+
|
|
82
|
+
// Confirm R55 canvas effect still fires — hoveredStatus='working'
|
|
83
|
+
// lifts the legend working row.
|
|
84
|
+
const workingRowLifted = await page.evaluate(() =>
|
|
85
|
+
document.querySelector('[data-legend-status="working"]')
|
|
86
|
+
?.getAttribute('data-legend-row-lifted'));
|
|
87
|
+
|
|
88
|
+
await page.mouse.move(0, 0);
|
|
89
|
+
await page.waitForTimeout(280);
|
|
90
|
+
const settledWorking = await probeChip('[data-working-chip]');
|
|
91
|
+
|
|
92
|
+
await page.hover('[data-online-chip]');
|
|
93
|
+
await page.waitForTimeout(250);
|
|
94
|
+
const hoverOnline = await probeChip('[data-online-chip]');
|
|
95
|
+
|
|
96
|
+
await page.mouse.move(0, 0);
|
|
97
|
+
await page.waitForTimeout(280);
|
|
98
|
+
const settledOnline = await probeChip('[data-online-chip]');
|
|
99
|
+
|
|
100
|
+
await browser.close();
|
|
101
|
+
|
|
102
|
+
// Tailwind 4 emits oklab/oklch / color-mix forms. Just check the bg
|
|
103
|
+
// string actually differs idle vs hover, and a brief parser confirms
|
|
104
|
+
// the channel that should grow (green for working, blue/green for cyan).
|
|
105
|
+
// Parse colors including alpha. R201's Tailwind /10 → /15 emits same
|
|
106
|
+
// OKLab L/a/b with stepped-up alpha (0.1 → 0.15); R193's gray→cyan
|
|
107
|
+
// pattern emits a different hue at any alpha. Both are "more saturated
|
|
108
|
+
// against the canvas" from the user's POV. Capture alpha and treat
|
|
109
|
+
// alpha-increase as a valid saturation signal alongside chroma growth.
|
|
110
|
+
function parseColor(s) {
|
|
111
|
+
if (!s) return null;
|
|
112
|
+
let m = s.match(/rgba?\(\s*(\d+)\s*,?\s*(\d+)\s*,?\s*(\d+)(?:\s*[,/]\s*([\d.]+))?/);
|
|
113
|
+
if (m) return { kind: 'rgb', r: +m[1], g: +m[2], b: +m[3], a: m[4] != null ? +m[4] : 1 };
|
|
114
|
+
m = s.match(/oklab\(\s*([\-\d.]+)\s+([\-\d.]+)\s+([\-\d.]+)(?:\s*\/\s*([\d.]+))?/);
|
|
115
|
+
if (m) return { kind: 'oklab', L: +m[1], a: +m[2], b: +m[3], alpha: m[4] != null ? +m[4] : 1 };
|
|
116
|
+
m = s.match(/oklch\(\s*([\-\d.]+)\s+([\-\d.]+)\s+([\-\d.]+)(?:\s*\/\s*([\d.]+))?/);
|
|
117
|
+
if (m) return { kind: 'oklch', L: +m[1], C: +m[2], h: +m[3], alpha: m[4] != null ? +m[4] : 1 };
|
|
118
|
+
return null;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// "More saturated against the canvas" = either chroma/hue distance
|
|
122
|
+
// from gray grew OR alpha grew (Tailwind /10 → /15 deepens by alpha).
|
|
123
|
+
const moreSaturated = (idle, hov) => {
|
|
124
|
+
if (!idle || !hov) return false;
|
|
125
|
+
if (idle.kind === 'rgb' && hov.kind === 'rgb') {
|
|
126
|
+
const chromaIdle = Math.max(idle.r, idle.g, idle.b) - Math.min(idle.r, idle.g, idle.b);
|
|
127
|
+
const chromaHov = Math.max(hov.r, hov.g, hov.b) - Math.min(hov.r, hov.g, hov.b);
|
|
128
|
+
return chromaHov > chromaIdle || hov.a > idle.a + 0.01;
|
|
129
|
+
}
|
|
130
|
+
if (idle.kind === 'oklab' && hov.kind === 'oklab') {
|
|
131
|
+
const dIdle = Math.hypot(idle.a, idle.b);
|
|
132
|
+
const dHov = Math.hypot(hov.a, hov.b);
|
|
133
|
+
return dHov > dIdle + 0.005 || hov.alpha > idle.alpha + 0.01;
|
|
134
|
+
}
|
|
135
|
+
if (idle.kind === 'oklch' && hov.kind === 'oklch') {
|
|
136
|
+
return hov.C > idle.C + 0.005 || hov.alpha > idle.alpha + 0.01;
|
|
137
|
+
}
|
|
138
|
+
return false;
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
const idleWorkingC = parseColor(idleWorking?.bg);
|
|
142
|
+
const hoverWorkingC = parseColor(hoverWorking?.bg);
|
|
143
|
+
const idleOnlineC = parseColor(idleOnline?.bg);
|
|
144
|
+
const hoverOnlineC = parseColor(hoverOnline?.bg);
|
|
145
|
+
|
|
146
|
+
const results = {
|
|
147
|
+
working_clickable: idleWorking?.clickable === 'true',
|
|
148
|
+
working_className_has_hover: idleWorking?.className.includes('hover:bg-green-500/15')
|
|
149
|
+
&& idleWorking?.className.includes('hover:border-green-500/30'),
|
|
150
|
+
working_transition_includes_bg: /background-color\s+(?:200ms|0\.2s)/.test(idleWorking?.transition || ''),
|
|
151
|
+
working_transition_includes_border: /border-color\s+(?:200ms|0\.2s)/.test(idleWorking?.transition || ''),
|
|
152
|
+
working_transition_keeps_boxshadow: /box-shadow\s+(?:150ms|0\.15s)/.test(idleWorking?.transition || ''),
|
|
153
|
+
working_hover_bg_changed: idleWorking?.bg !== hoverWorking?.bg,
|
|
154
|
+
working_hover_more_saturated: moreSaturated(idleWorkingC, hoverWorkingC),
|
|
155
|
+
working_settles_back: settledWorking?.bg === idleWorking?.bg,
|
|
156
|
+
// R55 canvas-effect still fires from the chip — hovering the
|
|
157
|
+
// working chip lifts the legend working row.
|
|
158
|
+
working_canvas_effect_fires: workingRowLifted === 'true',
|
|
159
|
+
|
|
160
|
+
online_clickable: idleOnline?.clickable === 'true',
|
|
161
|
+
online_className_has_hover: idleOnline?.className.includes('hover:bg-cyan-500/15')
|
|
162
|
+
&& idleOnline?.className.includes('hover:border-cyan-500/30'),
|
|
163
|
+
online_transition_includes_bg: /background-color\s+(?:200ms|0\.2s)/.test(idleOnline?.transition || ''),
|
|
164
|
+
online_transition_includes_border: /border-color\s+(?:200ms|0\.2s)/.test(idleOnline?.transition || ''),
|
|
165
|
+
online_hover_bg_changed: idleOnline?.bg !== hoverOnline?.bg,
|
|
166
|
+
online_hover_more_saturated: moreSaturated(idleOnlineC, hoverOnlineC),
|
|
167
|
+
online_settles_back: settledOnline?.bg === idleOnline?.bg,
|
|
168
|
+
};
|
|
169
|
+
const ok = Object.values(results).every(Boolean);
|
|
170
|
+
console.log(`${ok ? '✅' : '❌'} status-bar chips self-hover:`, JSON.stringify(results),
|
|
171
|
+
`\n idleWorking:`, idleWorking,
|
|
172
|
+
`\n hoverWorking:`, hoverWorking,
|
|
173
|
+
`\n settledWorking:`, settledWorking,
|
|
174
|
+
`\n idleOnline:`, idleOnline,
|
|
175
|
+
`\n hoverOnline:`, hoverOnline,
|
|
176
|
+
`\n settledOnline:`, settledOnline);
|
|
177
|
+
process.exit(ok ? 0 : 1);
|
|
@@ -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,86 @@
|
|
|
1
|
+
/* Round 303 verification: tier guide ring strokeDasharray tightens
|
|
2
|
+
* from "2 8" → "2 6". Same 2px dash; 8px gap → 6px gap so dashes
|
|
3
|
+
* read closer together, giving tier-guide rings clearer continuous-
|
|
4
|
+
* ring presence after R290/R291 cleared surrounding backdrop noise.
|
|
5
|
+
*
|
|
6
|
+
* Contract:
|
|
7
|
+
* - All [data-tier-ring] elements have stroke-dasharray '2 6'.
|
|
8
|
+
* - strokeWidth still 0.7 (regression).
|
|
9
|
+
* - At least one tier ring rendered with the test fixture (4-node
|
|
10
|
+
* working fleet → single-tier layout 220 fits).
|
|
11
|
+
* - R302 empty-hint ls=0.2 + R301 panel titles ls=0.3 + R300 kicker
|
|
12
|
+
* fw=500 + R294 pulse absent intact.
|
|
13
|
+
*/
|
|
14
|
+
import { chromium } from 'playwright';
|
|
15
|
+
import { readFileSync } from 'node:fs';
|
|
16
|
+
|
|
17
|
+
const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
|
|
18
|
+
const browser = await chromium.launch({ headless: true });
|
|
19
|
+
const ctx = await browser.newContext({ viewport: { width: 1500, 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 { localStorage.setItem('anet-theme', 'cyber'); sessionStorage.setItem('anet_v3_auth', '1'); } catch {}
|
|
23
|
+
});
|
|
24
|
+
const fresh = new Date(Date.now() - 60 * 1000).toISOString();
|
|
25
|
+
await ctx.route('**/api/hub/status*', async (route) => {
|
|
26
|
+
const r = await route.fetch();
|
|
27
|
+
const b = await r.json();
|
|
28
|
+
const nid = (b.sessions || [])[0]?.network_id || 'default';
|
|
29
|
+
const mk = (alias, model) => ({
|
|
30
|
+
alias, status: 'working', model, runtime: 'claude-code-cli',
|
|
31
|
+
network_id: nid, project_dir: null,
|
|
32
|
+
created_at: fresh, updated_at: fresh, last_seen_at: fresh,
|
|
33
|
+
});
|
|
34
|
+
// 4 working nodes → single-tier ring layout.
|
|
35
|
+
await route.fulfill({ response: r, json: { ...b, sessions: [
|
|
36
|
+
mk('alpha', 'claude-opus-4'),
|
|
37
|
+
mk('beta', 'gpt-4o'),
|
|
38
|
+
mk('gamma', 'claude-sonnet-4'),
|
|
39
|
+
mk('delta', 'gpt-4'),
|
|
40
|
+
] } });
|
|
41
|
+
});
|
|
42
|
+
await ctx.route('**/api/hub/messages*', (r) => r.fulfill({ json: { messages: [] } }));
|
|
43
|
+
await ctx.route('**/api/hub/tasks*', (r) => r.fulfill({ json: { tasks: [] } }));
|
|
44
|
+
|
|
45
|
+
const page = await ctx.newPage();
|
|
46
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
|
|
47
|
+
await page.waitForFunction(() => document.querySelectorAll('g[data-node]').length === 4, { timeout: 30000 });
|
|
48
|
+
await page.waitForTimeout(400);
|
|
49
|
+
|
|
50
|
+
const probe = await page.evaluate(() => {
|
|
51
|
+
const tierRings = [...document.querySelectorAll('[data-tier-ring]')];
|
|
52
|
+
const samples = tierRings.map(t => ({
|
|
53
|
+
r: t.getAttribute('data-tier-ring'),
|
|
54
|
+
dasharray: t.getAttribute('stroke-dasharray'),
|
|
55
|
+
strokeWidth: t.getAttribute('stroke-width'),
|
|
56
|
+
occupancy: t.getAttribute('data-tier-occupancy'),
|
|
57
|
+
}));
|
|
58
|
+
const empty = document.querySelector('[data-recent-signal-empty]');
|
|
59
|
+
const recentTitle = document.querySelector('[data-recent-panel-title]');
|
|
60
|
+
const legendTitle = document.querySelector('[data-legend-panel-title]');
|
|
61
|
+
const kicker = document.querySelector('[data-topo-section-kicker]');
|
|
62
|
+
return {
|
|
63
|
+
samples,
|
|
64
|
+
emptyLs: empty?.getAttribute('letter-spacing') ?? null,
|
|
65
|
+
recentTitleLs: recentTitle?.getAttribute('letter-spacing') ?? null,
|
|
66
|
+
legendTitleLs: legendTitle?.getAttribute('letter-spacing') ?? null,
|
|
67
|
+
kickerFw: kicker ? getComputedStyle(kicker).fontWeight : null,
|
|
68
|
+
pulseCount: document.querySelectorAll('[data-pulse-wrapper]').length,
|
|
69
|
+
};
|
|
70
|
+
});
|
|
71
|
+
await browser.close();
|
|
72
|
+
|
|
73
|
+
const results = {
|
|
74
|
+
tier_rings_rendered: probe.samples.length >= 1,
|
|
75
|
+
all_dasharray_2_6: probe.samples.every(s => s.dasharray === '2 6'),
|
|
76
|
+
all_stroke_width_0_7: probe.samples.every(s => s.strokeWidth === '0.7'),
|
|
77
|
+
r302_empty_hint_ls_0_2: probe.emptyLs === '0.2',
|
|
78
|
+
r301_recent_title_ls: probe.recentTitleLs === '0.3',
|
|
79
|
+
r301_legend_title_ls: probe.legendTitleLs === '0.3',
|
|
80
|
+
r300_kicker_fw_500: String(probe.kickerFw) === '500',
|
|
81
|
+
r294_pulse_absent: probe.pulseCount === 0,
|
|
82
|
+
};
|
|
83
|
+
const ok = Object.values(results).every(Boolean);
|
|
84
|
+
console.log(`${ok ? '✅' : '❌'} tier guide dashes:`, JSON.stringify(results),
|
|
85
|
+
'\n tier rings sampled:', probe.samples);
|
|
86
|
+
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);
|