@sleep2agi/agent-network-dashboard 0.4.6-preview.99 → 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 +41 -1
- package/app/components/HelpOverlay.tsx +55 -0
- package/app/components/ServersDrawer.tsx +181 -5
- package/app/components/TopoGraph.tsx +5514 -336
- package/app/globals.css +93 -6
- 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-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-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-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-fadein-test.mjs +106 -0
- 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-filter-pill-aliases-test.mjs +121 -0
- package/scripts/topo-filter-pill-count-tabular-test.mjs +135 -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-label-a11y-test.mjs +113 -0
- package/scripts/topo-group-label-count-inherit-test.mjs +99 -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-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-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-march-busyness-test.mjs +155 -0
- 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-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-center-crossfade-test.mjs +124 -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-working-count-test.mjs +99 -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-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-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-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-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-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-prefix-opacity-test.mjs +107 -0
- package/scripts/topo-prepublish-guard-test.mjs +95 -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-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-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-tint-test.mjs +110 -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-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-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/03w4rgx_vt8ec.js +0 -1
- package/.next/static/chunks/072so8rfx2tt-.css +0 -2
- package/.next/static/chunks/0o.k-.0kl4bz5.js +0 -2
- package/.next/static/chunks/121d8yvfl8l_..js +0 -7
- package/.next/static/chunks/148o1e4ijgwp1.js +0 -1
- package/scripts/topo-arrival-ping-test.mjs +0 -87
- package/scripts/topo-dispatch-pulse-test.mjs +0 -83
- /package/.next/static/{Dhky2WTh8mvJhw56taHVs → 424zX3i80AJ_wHF_otKuP}/_buildManifest.js +0 -0
- /package/.next/static/{Dhky2WTh8mvJhw56taHVs → 424zX3i80AJ_wHF_otKuP}/_clientMiddlewareManifest.js +0 -0
- /package/.next/static/{Dhky2WTh8mvJhw56taHVs → 424zX3i80AJ_wHF_otKuP}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/* Round 232 verification: HTML chip row (working / online / active-
|
|
2
|
+
* links) gains the Tailwind `tabular-nums` utility class so the digit
|
|
3
|
+
* width stays stable across counter rollovers (9→10, 99→100).
|
|
4
|
+
*
|
|
5
|
+
* 7th surface in the info-density tabular-nums sweep — first on the
|
|
6
|
+
* HTML side (previous 6 were SVG <text>/<tspan>):
|
|
7
|
+
* R224 edge midpoint badge digit
|
|
8
|
+
* R225 hub center digit
|
|
9
|
+
* R225 recent panel header tspan
|
|
10
|
+
* R225 recent row count tspan
|
|
11
|
+
* R229 group-label · count chip
|
|
12
|
+
* R230 R58 status pip strip × 3 tiers
|
|
13
|
+
* R232 chip row × 3 chips (this round)
|
|
14
|
+
*
|
|
15
|
+
* Scenario: 4 working agents + 1 flow alpha→beta count=5. Drives
|
|
16
|
+
* workingCount=4, onlineNodes.length=4, flowLinks.length=1 → all
|
|
17
|
+
* three chips render with non-empty digits.
|
|
18
|
+
*
|
|
19
|
+
* Verifies for each chip:
|
|
20
|
+
* - element present at its data attr selector
|
|
21
|
+
* - getComputedStyle().fontVariantNumeric includes 'tabular-nums'
|
|
22
|
+
* - textContent starts with the expected digit (sanity)
|
|
23
|
+
*/
|
|
24
|
+
import { chromium } from 'playwright';
|
|
25
|
+
import { readFileSync } from 'node:fs';
|
|
26
|
+
|
|
27
|
+
const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
|
|
28
|
+
const browser = await chromium.launch({ headless: true });
|
|
29
|
+
const ctx = await browser.newContext({ viewport: { width: 1500, height: 1500 } });
|
|
30
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
31
|
+
await ctx.addInitScript(() => {
|
|
32
|
+
try { localStorage.setItem('anet-theme', 'cyber'); sessionStorage.setItem('anet_v3_auth', '1'); } catch {}
|
|
33
|
+
});
|
|
34
|
+
const fresh = new Date(Date.now() - 60 * 1000).toISOString();
|
|
35
|
+
await ctx.route('**/api/hub/status*', async (route) => {
|
|
36
|
+
const r = await route.fetch();
|
|
37
|
+
const b = await r.json();
|
|
38
|
+
const nid = (b.sessions || [])[0]?.network_id || 'default';
|
|
39
|
+
const mk = (alias) => ({
|
|
40
|
+
alias, status: 'working', model: 'claude-opus-4', runtime: 'claude-code-cli',
|
|
41
|
+
network_id: nid, project_dir: null,
|
|
42
|
+
created_at: fresh, updated_at: fresh, last_seen_at: fresh,
|
|
43
|
+
});
|
|
44
|
+
await route.fulfill({ response: r, json: { ...b, sessions: [
|
|
45
|
+
mk('alpha'), mk('beta'), mk('gamma'), mk('delta'),
|
|
46
|
+
] } });
|
|
47
|
+
});
|
|
48
|
+
const now = Date.now();
|
|
49
|
+
const msgs = [];
|
|
50
|
+
for (let i = 0; i < 5; i++) {
|
|
51
|
+
msgs.push({
|
|
52
|
+
id: `m${i}`, from_alias: 'alpha', to_alias: 'beta', content: 'hi',
|
|
53
|
+
network_id: 'default', created_at: new Date(now - (1000 + i * 50)).toISOString(),
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
await ctx.route('**/api/hub/messages*', (r2) => r2.fulfill({ json: { messages: msgs } }));
|
|
57
|
+
await ctx.route('**/api/hub/tasks*', (r2) => r2.fulfill({ json: { tasks: [] } }));
|
|
58
|
+
|
|
59
|
+
const page = await ctx.newPage();
|
|
60
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
|
|
61
|
+
await page.waitForFunction(() => document.querySelectorAll('g[data-node]').length === 4, { timeout: 30000 });
|
|
62
|
+
await page.waitForSelector('[data-working-chip]', { timeout: 10000, state: 'attached' });
|
|
63
|
+
await page.waitForSelector('[data-online-chip]', { timeout: 10000, state: 'attached' });
|
|
64
|
+
await page.waitForSelector('[data-active-links-chip]', { timeout: 10000, state: 'attached' });
|
|
65
|
+
await page.waitForTimeout(300);
|
|
66
|
+
|
|
67
|
+
const out = await page.evaluate(() => {
|
|
68
|
+
const grab = (sel, expectedPrefix) => {
|
|
69
|
+
const el = document.querySelector(sel);
|
|
70
|
+
if (!el) return null;
|
|
71
|
+
return {
|
|
72
|
+
present: true,
|
|
73
|
+
fontVarNumeric: getComputedStyle(el).fontVariantNumeric,
|
|
74
|
+
hasUtility: el.className.split(/\s+/).includes('tabular-nums'),
|
|
75
|
+
textStartsWith: (el.textContent || '').trim().startsWith(expectedPrefix),
|
|
76
|
+
text: (el.textContent || '').trim().slice(0, 30),
|
|
77
|
+
};
|
|
78
|
+
};
|
|
79
|
+
return {
|
|
80
|
+
working: grab('[data-working-chip]', '4 working'),
|
|
81
|
+
online: grab('[data-online-chip]', '4 online'),
|
|
82
|
+
activeLinks: grab('[data-active-links-chip]', '1 active'),
|
|
83
|
+
};
|
|
84
|
+
});
|
|
85
|
+
await browser.close();
|
|
86
|
+
|
|
87
|
+
const hasTab = (s) => /tabular-nums/.test(s || '');
|
|
88
|
+
const present = (o) => o && o.present;
|
|
89
|
+
|
|
90
|
+
const results = {
|
|
91
|
+
working_present: present(out.working),
|
|
92
|
+
working_class_utility: out.working?.hasUtility === true,
|
|
93
|
+
working_fvn_tabular: hasTab(out.working?.fontVarNumeric),
|
|
94
|
+
working_text_ok: out.working?.textStartsWith === true,
|
|
95
|
+
|
|
96
|
+
online_present: present(out.online),
|
|
97
|
+
online_class_utility: out.online?.hasUtility === true,
|
|
98
|
+
online_fvn_tabular: hasTab(out.online?.fontVarNumeric),
|
|
99
|
+
online_text_ok: out.online?.textStartsWith === true,
|
|
100
|
+
|
|
101
|
+
active_present: present(out.activeLinks),
|
|
102
|
+
active_class_utility: out.activeLinks?.hasUtility === true,
|
|
103
|
+
active_fvn_tabular: hasTab(out.activeLinks?.fontVarNumeric),
|
|
104
|
+
active_text_ok: out.activeLinks?.textStartsWith === true,
|
|
105
|
+
};
|
|
106
|
+
const ok = Object.values(results).every(Boolean);
|
|
107
|
+
console.log(`${ok ? '✅' : '❌'} chip row tabular-nums:`, JSON.stringify(results),
|
|
108
|
+
'\n working: ', out.working,
|
|
109
|
+
'\n online: ', out.online,
|
|
110
|
+
'\n activeLinks:', out.activeLinks);
|
|
111
|
+
process.exit(ok ? 0 : 1);
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/* Round 337 verification: working chip + online chip (HTML chip-row)
|
|
2
|
+
* split digit/unit with the unit at opacity-70.
|
|
3
|
+
*
|
|
4
|
+
* Extends the R333/R335/R336 chip-internal-hierarchy arc from SVG
|
|
5
|
+
* surfaces (panel headers + vendor count) and pin-chip prefix
|
|
6
|
+
* surfaces (filter pills) into the HTML chip-row chips themselves.
|
|
7
|
+
* Recurring pattern this loop arc: small label spans demote, value
|
|
8
|
+
* stays prominent.
|
|
9
|
+
*
|
|
10
|
+
* Contract:
|
|
11
|
+
* - [data-working-chip-unit] className contains 'opacity-70',
|
|
12
|
+
* textContent contains 'working', computed opacity 0.7.
|
|
13
|
+
* - [data-online-chip-unit] same for 'online'.
|
|
14
|
+
* - Parent chips' textContent retains the full "{N} working" /
|
|
15
|
+
* "{N} online" string so any legacy text-based tests pass.
|
|
16
|
+
* - R336 panel count units + R335 prefix opacity-70 regressions.
|
|
17
|
+
* - R317/R318/R294 chrome + pulse regressions intact.
|
|
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
|
+
const ctx = await browser.newContext({ viewport: { width: 1500, 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 mk = (alias) => ({
|
|
35
|
+
alias, status: 'working', model: 'claude-opus-4', runtime: 'claude-code-cli',
|
|
36
|
+
network_id: nid, project_dir: null,
|
|
37
|
+
created_at: fresh, updated_at: fresh, last_seen_at: fresh,
|
|
38
|
+
});
|
|
39
|
+
await route.fulfill({ response: r, json: { ...b, sessions: [
|
|
40
|
+
mk('alpha'), mk('beta'), mk('gamma'),
|
|
41
|
+
] } });
|
|
42
|
+
});
|
|
43
|
+
await ctx.route('**/api/hub/messages*', (r) => r.fulfill({ json: { messages: [] } }));
|
|
44
|
+
await ctx.route('**/api/hub/tasks*', (r) => r.fulfill({ json: { tasks: [] } }));
|
|
45
|
+
|
|
46
|
+
const page = await ctx.newPage();
|
|
47
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
|
|
48
|
+
await page.waitForSelector('[data-working-chip-unit]', { timeout: 15000 });
|
|
49
|
+
await page.waitForTimeout(300);
|
|
50
|
+
|
|
51
|
+
const probe = await page.evaluate(() => {
|
|
52
|
+
const workUnit = document.querySelector('[data-working-chip-unit]');
|
|
53
|
+
const onlineUnit = document.querySelector('[data-online-chip-unit]');
|
|
54
|
+
const workChip = document.querySelector('[data-working-chip]');
|
|
55
|
+
const onlineChip = document.querySelector('[data-online-chip]');
|
|
56
|
+
return {
|
|
57
|
+
workUnitClass: workUnit?.className ?? '',
|
|
58
|
+
workUnitText: workUnit?.textContent ?? null,
|
|
59
|
+
workUnitOpacity: workUnit ? getComputedStyle(workUnit).opacity : null,
|
|
60
|
+
onlineUnitClass: onlineUnit?.className ?? '',
|
|
61
|
+
onlineUnitText: onlineUnit?.textContent ?? null,
|
|
62
|
+
onlineUnitOpacity: onlineUnit ? getComputedStyle(onlineUnit).opacity : null,
|
|
63
|
+
workChipText: workChip?.textContent ?? null,
|
|
64
|
+
onlineChipText: onlineChip?.textContent ?? null,
|
|
65
|
+
layoutInactiveCls: document.querySelector('[data-topo-chrome-layout="grid"]')?.className ?? '',
|
|
66
|
+
layoutActiveCls: document.querySelector('[data-topo-chrome-layout="ring"]')?.className ?? '',
|
|
67
|
+
pulseCount: document.querySelectorAll('[data-pulse-wrapper]').length,
|
|
68
|
+
};
|
|
69
|
+
});
|
|
70
|
+
await browser.close();
|
|
71
|
+
|
|
72
|
+
const opacityClose = (val) => val !== null && Math.abs(parseFloat(val) - 0.7) < 0.01;
|
|
73
|
+
|
|
74
|
+
const results = {
|
|
75
|
+
work_unit_has_opacity70: /opacity-70/.test(probe.workUnitClass),
|
|
76
|
+
work_unit_text_working: (probe.workUnitText || '').includes('working'),
|
|
77
|
+
work_unit_computed_0_7: opacityClose(probe.workUnitOpacity),
|
|
78
|
+
online_unit_has_opacity70: /opacity-70/.test(probe.onlineUnitClass),
|
|
79
|
+
online_unit_text_online: (probe.onlineUnitText || '').includes('online'),
|
|
80
|
+
online_unit_computed_0_7: opacityClose(probe.onlineUnitOpacity),
|
|
81
|
+
// Parent textContent retention.
|
|
82
|
+
work_chip_contains_working: (probe.workChipText || '').includes('working'),
|
|
83
|
+
online_chip_contains_online: (probe.onlineChipText || '').includes('online'),
|
|
84
|
+
// R317 / R318 chrome regression.
|
|
85
|
+
r317_inactive_gray_400: probe.layoutInactiveCls.includes('text-gray-400'),
|
|
86
|
+
r318_active_font_medium: probe.layoutActiveCls.includes('font-medium'),
|
|
87
|
+
r294_pulse_absent: probe.pulseCount === 0,
|
|
88
|
+
};
|
|
89
|
+
const ok = Object.values(results).every(Boolean);
|
|
90
|
+
console.log(`${ok ? '✅' : '❌'} chip unit demotion:`, JSON.stringify(results),
|
|
91
|
+
'\n work unit:', JSON.stringify(probe.workUnitText), 'opacity:', probe.workUnitOpacity,
|
|
92
|
+
'\n online unit:', JSON.stringify(probe.onlineUnitText), 'opacity:', probe.onlineUnitOpacity);
|
|
93
|
+
process.exit(ok ? 0 : 1);
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/* Round 313 verification: chip-row data chips (working, online,
|
|
2
|
+
* active-links) pick up font-medium (500). Extends the R312
|
|
3
|
+
* 'HTML-context data = font-medium' rule from the chrome strip
|
|
4
|
+
* zoom readout to the chip-row chips at the title block.
|
|
5
|
+
*
|
|
6
|
+
* Contract:
|
|
7
|
+
* - [data-working-chip] className contains 'font-medium'.
|
|
8
|
+
* - [data-online-chip] className contains 'font-medium'.
|
|
9
|
+
* - [data-active-links-chip] className contains 'font-medium'.
|
|
10
|
+
* - Computed font-weight === 500 for each.
|
|
11
|
+
* - tabular-nums kept on all three (R232 regression).
|
|
12
|
+
* - R312 chrome zoom readout still font-medium (sibling).
|
|
13
|
+
* - R311/R310/R309/R294 regressions preserved.
|
|
14
|
+
*/
|
|
15
|
+
import { chromium } from 'playwright';
|
|
16
|
+
import { readFileSync } from 'node:fs';
|
|
17
|
+
|
|
18
|
+
const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
|
|
19
|
+
const browser = await chromium.launch({ headless: true });
|
|
20
|
+
const ctx = await browser.newContext({ viewport: { width: 1500, height: 1500 } });
|
|
21
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
22
|
+
await ctx.addInitScript(() => {
|
|
23
|
+
try { localStorage.setItem('anet-theme', 'cyber'); sessionStorage.setItem('anet_v3_auth', '1'); } catch {}
|
|
24
|
+
});
|
|
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 mk = (alias, model) => ({
|
|
31
|
+
alias, status: 'working', model, runtime: 'claude-code-cli',
|
|
32
|
+
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
|
+
mk('alpha', 'claude-opus-4'),
|
|
37
|
+
mk('beta', 'gpt-4o'),
|
|
38
|
+
] } });
|
|
39
|
+
});
|
|
40
|
+
await ctx.route('**/api/hub/messages*', (r) => r.fulfill({ json: { messages: [] } }));
|
|
41
|
+
await ctx.route('**/api/hub/tasks*', (r) => r.fulfill({ json: { tasks: [] } }));
|
|
42
|
+
|
|
43
|
+
const page = await ctx.newPage();
|
|
44
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
|
|
45
|
+
await page.waitForSelector('[data-working-chip]', { timeout: 15000 });
|
|
46
|
+
await page.waitForTimeout(300);
|
|
47
|
+
|
|
48
|
+
const probe = await page.evaluate(() => {
|
|
49
|
+
const sel = (s) => document.querySelector(s);
|
|
50
|
+
const working = sel('[data-working-chip]');
|
|
51
|
+
const online = sel('[data-online-chip]');
|
|
52
|
+
const active = sel('[data-active-links-chip]');
|
|
53
|
+
const fwOf = (el) => el ? getComputedStyle(el).fontWeight : null;
|
|
54
|
+
const clsHas = (el, needle) => (el?.className ?? '').includes(needle);
|
|
55
|
+
return {
|
|
56
|
+
workingCls: working?.className ?? '',
|
|
57
|
+
onlineCls: online?.className ?? '',
|
|
58
|
+
activeCls: active?.className ?? '',
|
|
59
|
+
workingFw: fwOf(working),
|
|
60
|
+
onlineFw: fwOf(online),
|
|
61
|
+
activeFw: fwOf(active),
|
|
62
|
+
workingHasTabular: clsHas(working, 'tabular-nums'),
|
|
63
|
+
onlineHasTabular: clsHas(online, 'tabular-nums'),
|
|
64
|
+
activeHasTabular: clsHas(active, 'tabular-nums'),
|
|
65
|
+
chromeZoomCls: sel('[data-topo-chrome-zoom-level]')?.className ?? '',
|
|
66
|
+
recentCountFw: sel('[data-recent-panel-count]')?.getAttribute('font-weight') ?? null,
|
|
67
|
+
rowWorkingFw: sel('[data-legend-count="working"]')?.getAttribute('font-weight') ?? null,
|
|
68
|
+
pulseCount: document.querySelectorAll('[data-pulse-wrapper]').length,
|
|
69
|
+
};
|
|
70
|
+
});
|
|
71
|
+
await browser.close();
|
|
72
|
+
|
|
73
|
+
const hasMedium = (s) => s.includes('font-medium');
|
|
74
|
+
|
|
75
|
+
const results = {
|
|
76
|
+
working_has_font_medium: hasMedium(probe.workingCls),
|
|
77
|
+
online_has_font_medium: hasMedium(probe.onlineCls),
|
|
78
|
+
active_has_font_medium: hasMedium(probe.activeCls),
|
|
79
|
+
working_fw_500: String(probe.workingFw) === '500',
|
|
80
|
+
online_fw_500: String(probe.onlineFw) === '500',
|
|
81
|
+
active_fw_500: String(probe.activeFw) === '500',
|
|
82
|
+
working_tabular_kept: probe.workingHasTabular,
|
|
83
|
+
online_tabular_kept: probe.onlineHasTabular,
|
|
84
|
+
active_tabular_kept: probe.activeHasTabular,
|
|
85
|
+
r312_chrome_zoom_kept: probe.chromeZoomCls.includes('font-medium'),
|
|
86
|
+
r311_recent_count_fw_600: probe.recentCountFw === '600',
|
|
87
|
+
r309_row_count_fw_600: probe.rowWorkingFw === '600',
|
|
88
|
+
r294_pulse_absent: probe.pulseCount === 0,
|
|
89
|
+
};
|
|
90
|
+
const ok = Object.values(results).every(Boolean);
|
|
91
|
+
console.log(`${ok ? '✅' : '❌'} chiprow data weight:`, JSON.stringify(results),
|
|
92
|
+
'\n fw: working=', probe.workingFw, ' online=', probe.onlineFw, ' active=', probe.activeFw,
|
|
93
|
+
'\n chrome zoom (R312):', probe.chromeZoomCls.includes('font-medium') ? 'has font-medium' : 'MISSING font-medium');
|
|
94
|
+
process.exit(ok ? 0 : 1);
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/* Round 154 verification: TopoGraph chrome buttons gain stable
|
|
2
|
+
* data-* hooks for tests + focus-visible ring matching the
|
|
3
|
+
* dashboard's cyan accent (browser default focus outline often
|
|
4
|
+
* vanishes on the dark canvas).
|
|
5
|
+
*
|
|
6
|
+
* Chrome inventory (bottom-right of canvas):
|
|
7
|
+
* data-topo-chrome (wrapper div)
|
|
8
|
+
* data-topo-chrome-nodesize=S|M|L (segmented control, R113)
|
|
9
|
+
* data-topo-chrome-nodesize-active="true|false"
|
|
10
|
+
* data-topo-chrome-zoom-out (R104)
|
|
11
|
+
* data-topo-chrome-zoom-level (readout, also R104)
|
|
12
|
+
* data-topo-chrome-zoom-in
|
|
13
|
+
* data-topo-chrome-reset
|
|
14
|
+
* data-topo-chrome-fullscreen
|
|
15
|
+
* data-topo-chrome-fullscreen-active="true|false"
|
|
16
|
+
*
|
|
17
|
+
* Each button gains focus-visible:ring-1 ring-cyan-400/60. Tabs
|
|
18
|
+
* land somewhere visible.
|
|
19
|
+
*
|
|
20
|
+
* Test: every chrome button surfaces its data attribute, plus the
|
|
21
|
+
* three S/M/L buttons report active correctly when one is picked.
|
|
22
|
+
*/
|
|
23
|
+
import { chromium } from 'playwright';
|
|
24
|
+
import { readFileSync } from 'node:fs';
|
|
25
|
+
|
|
26
|
+
const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
|
|
27
|
+
const browser = await chromium.launch({ headless: true });
|
|
28
|
+
|
|
29
|
+
const ctx = await browser.newContext({ viewport: { width: 1400, height: 1500 } });
|
|
30
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
31
|
+
await ctx.addInitScript(() => {
|
|
32
|
+
try { localStorage.setItem('anet-theme', 'cyber'); sessionStorage.setItem('anet_v3_auth', '1'); } catch {}
|
|
33
|
+
});
|
|
34
|
+
const fresh = new Date(Date.now() - 60 * 1000).toISOString();
|
|
35
|
+
await ctx.route('**/api/hub/status*', async (route) => {
|
|
36
|
+
const r = await route.fetch();
|
|
37
|
+
const b = await r.json();
|
|
38
|
+
const nid = (b.sessions || [])[0]?.network_id || 'default';
|
|
39
|
+
const mk = (alias) => ({
|
|
40
|
+
alias, status: 'working', model: 'claude-opus-4', runtime: 'cli-claude-code',
|
|
41
|
+
network_id: nid, project_dir: null,
|
|
42
|
+
created_at: fresh, updated_at: fresh, last_seen_at: fresh,
|
|
43
|
+
});
|
|
44
|
+
await route.fulfill({ response: r, json: { ...b, sessions: [mk('alpha'), mk('beta')] } });
|
|
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(() => document.querySelectorAll('g[data-node]').length === 2, { timeout: 30000 });
|
|
52
|
+
await page.waitForSelector('[data-topo-chrome]', { timeout: 10000 });
|
|
53
|
+
await page.waitForTimeout(300);
|
|
54
|
+
|
|
55
|
+
const inspect = () => page.evaluate(() => {
|
|
56
|
+
const sel = (s) => document.querySelector(s);
|
|
57
|
+
const all = (s) => [...document.querySelectorAll(s)];
|
|
58
|
+
return {
|
|
59
|
+
wrapper: !!sel('[data-topo-chrome]'),
|
|
60
|
+
nodesizeS: sel('[data-topo-chrome-nodesize="S"]')?.getAttribute('data-topo-chrome-nodesize-active'),
|
|
61
|
+
nodesizeM: sel('[data-topo-chrome-nodesize="M"]')?.getAttribute('data-topo-chrome-nodesize-active'),
|
|
62
|
+
nodesizeL: sel('[data-topo-chrome-nodesize="L"]')?.getAttribute('data-topo-chrome-nodesize-active'),
|
|
63
|
+
zoomOut: !!sel('[data-topo-chrome-zoom-out]'),
|
|
64
|
+
zoomLevel: sel('[data-topo-chrome-zoom-level]')?.textContent?.trim(),
|
|
65
|
+
zoomIn: !!sel('[data-topo-chrome-zoom-in]'),
|
|
66
|
+
reset: !!sel('[data-topo-chrome-reset]'),
|
|
67
|
+
fullscreen: !!sel('[data-topo-chrome-fullscreen]'),
|
|
68
|
+
fullscreenActive: sel('[data-topo-chrome-fullscreen]')?.getAttribute('data-topo-chrome-fullscreen-active'),
|
|
69
|
+
// focus-visible ring is a CSS pseudo-class; just verify the
|
|
70
|
+
// className carries the focus-visible:ring tokens.
|
|
71
|
+
chromeButtonsHaveFocusRing: all('[data-topo-chrome] button').every(b =>
|
|
72
|
+
(b.className || '').includes('focus-visible:ring')),
|
|
73
|
+
};
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
const before = await inspect();
|
|
77
|
+
|
|
78
|
+
// Click L → it becomes active, M becomes inactive (default)
|
|
79
|
+
await page.locator('[data-topo-chrome-nodesize="L"]').click();
|
|
80
|
+
await page.waitForTimeout(150);
|
|
81
|
+
const afterL = await inspect();
|
|
82
|
+
|
|
83
|
+
await browser.close();
|
|
84
|
+
|
|
85
|
+
const results = {
|
|
86
|
+
wrapper_present: before.wrapper === true,
|
|
87
|
+
nodesizeS_present: before.nodesizeS === 'false',
|
|
88
|
+
nodesizeM_activeDefault: before.nodesizeM === 'true', // default scale 0.84 → M
|
|
89
|
+
nodesizeL_present: before.nodesizeL === 'false',
|
|
90
|
+
zoomOut_present: before.zoomOut === true,
|
|
91
|
+
zoomLevel_100pct: before.zoomLevel === '100%',
|
|
92
|
+
zoomIn_present: before.zoomIn === true,
|
|
93
|
+
reset_present: before.reset === true,
|
|
94
|
+
fullscreen_present: before.fullscreen === true,
|
|
95
|
+
fullscreenActive_false: before.fullscreenActive === 'false',
|
|
96
|
+
focusRing_onAllButtons: before.chromeButtonsHaveFocusRing === true,
|
|
97
|
+
|
|
98
|
+
// After clicking L: active flips to L
|
|
99
|
+
afterL_LActive: afterL.nodesizeL === 'true',
|
|
100
|
+
afterL_MInactive: afterL.nodesizeM === 'false',
|
|
101
|
+
afterL_SInactive: afterL.nodesizeS === 'false',
|
|
102
|
+
};
|
|
103
|
+
const ok = Object.values(results).every(Boolean);
|
|
104
|
+
console.log(`${ok ? '✅' : '❌'} chrome a11y:`, JSON.stringify(results),
|
|
105
|
+
`\n before=`, before,
|
|
106
|
+
`\n afterL=`, afterL);
|
|
107
|
+
process.exit(ok ? 0 : 1);
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/* Round 318 verification: chrome segmented-control ACTIVE button
|
|
2
|
+
* gains font-medium (500) — visual weight emphasis layered on top
|
|
3
|
+
* of the existing cyan-300 color + cyan-500/15 background. The
|
|
4
|
+
* polish broadened across all four chrome control families that
|
|
5
|
+
* share the same active-state class string:
|
|
6
|
+
* - Layout toggle (Ring / Grid) — bottom-right
|
|
7
|
+
* - nodeSize segmented (S / M / L) — bottom-right
|
|
8
|
+
* - Fullscreen toggle — top-right (single button, isFullscreen
|
|
9
|
+
* branch is its "active" state)
|
|
10
|
+
*
|
|
11
|
+
* Direction: R313/R314/R315 established font-medium as the data-
|
|
12
|
+
* weight chip family. R318 extends the same weight tier to chrome
|
|
13
|
+
* control ACTIVE states so the currently-selected option carries
|
|
14
|
+
* stronger visual prominence than just color alone.
|
|
15
|
+
*
|
|
16
|
+
* Contract:
|
|
17
|
+
* - The active Layout toggle button has className containing
|
|
18
|
+
* 'font-medium'.
|
|
19
|
+
* - The inactive Layout toggle button does NOT have font-medium
|
|
20
|
+
* in its class string (still default 400).
|
|
21
|
+
* - Computed font-weight of active button === 500.
|
|
22
|
+
* - R317 inactive gray-400 + R316 brand-logo width=40 + R313
|
|
23
|
+
* chip-row weight + R294 pulse absent all preserved.
|
|
24
|
+
*/
|
|
25
|
+
import { chromium } from 'playwright';
|
|
26
|
+
import { readFileSync } from 'node:fs';
|
|
27
|
+
|
|
28
|
+
const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
|
|
29
|
+
const browser = await chromium.launch({ headless: true });
|
|
30
|
+
const ctx = await browser.newContext({ viewport: { width: 1500, height: 1500 } });
|
|
31
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
32
|
+
await ctx.addInitScript(() => {
|
|
33
|
+
try {
|
|
34
|
+
localStorage.setItem('anet-theme', 'cyber');
|
|
35
|
+
sessionStorage.setItem('anet_v3_auth', '1');
|
|
36
|
+
// Force ring layout so Ring is the active button.
|
|
37
|
+
localStorage.setItem('anet-topo-layout', 'ring');
|
|
38
|
+
} catch {}
|
|
39
|
+
});
|
|
40
|
+
const fresh = new Date(Date.now() - 60 * 1000).toISOString();
|
|
41
|
+
await ctx.route('**/api/hub/status*', async (route) => {
|
|
42
|
+
const r = await route.fetch();
|
|
43
|
+
const b = await r.json();
|
|
44
|
+
const nid = (b.sessions || [])[0]?.network_id || 'default';
|
|
45
|
+
const mk = (alias, model) => ({
|
|
46
|
+
alias, status: 'working', model, runtime: 'claude-code-cli',
|
|
47
|
+
network_id: nid, project_dir: null,
|
|
48
|
+
created_at: fresh, updated_at: fresh, last_seen_at: fresh,
|
|
49
|
+
});
|
|
50
|
+
await route.fulfill({ response: r, json: { ...b, sessions: [
|
|
51
|
+
mk('alpha', 'claude-opus-4'),
|
|
52
|
+
mk('beta', 'gpt-4o'),
|
|
53
|
+
] } });
|
|
54
|
+
});
|
|
55
|
+
await ctx.route('**/api/hub/messages*', (r) => r.fulfill({ json: { messages: [] } }));
|
|
56
|
+
await ctx.route('**/api/hub/tasks*', (r) => r.fulfill({ json: { tasks: [] } }));
|
|
57
|
+
|
|
58
|
+
const page = await ctx.newPage();
|
|
59
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
|
|
60
|
+
await page.waitForSelector('[data-topo-chrome-layout="ring"]', { timeout: 15000 });
|
|
61
|
+
await page.waitForTimeout(400);
|
|
62
|
+
|
|
63
|
+
const probe = await page.evaluate(() => {
|
|
64
|
+
const sel = (s) => document.querySelector(s);
|
|
65
|
+
const ringBtn = sel('[data-topo-chrome-layout="ring"]');
|
|
66
|
+
const gridBtn = sel('[data-topo-chrome-layout="grid"]');
|
|
67
|
+
const logo = sel('[data-topo-brand-logo]');
|
|
68
|
+
return {
|
|
69
|
+
ringActive: ringBtn?.getAttribute('data-topo-chrome-layout-active') === 'true',
|
|
70
|
+
gridActive: gridBtn?.getAttribute('data-topo-chrome-layout-active') === 'true',
|
|
71
|
+
ringCls: ringBtn?.className ?? '',
|
|
72
|
+
gridCls: gridBtn?.className ?? '',
|
|
73
|
+
ringFw: ringBtn ? getComputedStyle(ringBtn).fontWeight : null,
|
|
74
|
+
gridFw: gridBtn ? getComputedStyle(gridBtn).fontWeight : null,
|
|
75
|
+
brandLogoW: logo?.getAttribute('width') ?? null,
|
|
76
|
+
workingChipCls: sel('[data-working-chip]')?.className ?? '',
|
|
77
|
+
pulseCount: document.querySelectorAll('[data-pulse-wrapper]').length,
|
|
78
|
+
};
|
|
79
|
+
});
|
|
80
|
+
await browser.close();
|
|
81
|
+
|
|
82
|
+
const activeCls = probe.ringActive ? probe.ringCls : probe.gridCls;
|
|
83
|
+
const inactiveCls = probe.ringActive ? probe.gridCls : probe.ringCls;
|
|
84
|
+
const activeFw = probe.ringActive ? probe.ringFw : probe.gridFw;
|
|
85
|
+
|
|
86
|
+
const results = {
|
|
87
|
+
exactly_one_active: probe.ringActive !== probe.gridActive,
|
|
88
|
+
active_has_font_medium: activeCls.includes('font-medium'),
|
|
89
|
+
inactive_no_font_medium: !inactiveCls.includes('font-medium'),
|
|
90
|
+
active_fw_500: String(activeFw) === '500',
|
|
91
|
+
// R317 regression: inactive still gray-400.
|
|
92
|
+
r317_inactive_gray_400: inactiveCls.includes('text-gray-400'),
|
|
93
|
+
// R316 brand-logo width=40 regression.
|
|
94
|
+
r316_brand_logo_width_40: probe.brandLogoW === '40',
|
|
95
|
+
// R313 chip-row data weight regression.
|
|
96
|
+
r313_working_chip_kept: probe.workingChipCls.includes('font-medium'),
|
|
97
|
+
// R294 pulse absent regression.
|
|
98
|
+
r294_pulse_absent: probe.pulseCount === 0,
|
|
99
|
+
};
|
|
100
|
+
const ok = Object.values(results).every(Boolean);
|
|
101
|
+
console.log(`${ok ? '✅' : '❌'} chrome active weight:`, JSON.stringify(results),
|
|
102
|
+
'\n ring active:', probe.ringActive, ' grid active:', probe.gridActive,
|
|
103
|
+
'\n active fw:', activeFw, ' inactive fw:', probe.ringActive ? probe.gridFw : probe.ringFw);
|
|
104
|
+
process.exit(ok ? 0 : 1);
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/* Round 306 verification: Layout toggle (Ring/Grid) focus-visible:
|
|
2
|
+
* ring-2 → ring-1 unifies focus-ring width across all chrome
|
|
3
|
+
* buttons. Pre-R306 Layout toggle was the only chrome button at
|
|
4
|
+
* 2px; nodeSize, zoom, reset, fullscreen all at 1px.
|
|
5
|
+
*
|
|
6
|
+
* Test approach: tab/focus each chrome button via DOM-direct
|
|
7
|
+
* focus() + check the computed outline / box-shadow width. The
|
|
8
|
+
* focus-visible CSS only matches keyboard-style focus, so we
|
|
9
|
+
* dispatch keyboard focus to trigger the focus-visible state.
|
|
10
|
+
*
|
|
11
|
+
* Contract:
|
|
12
|
+
* - All chrome buttons (Layout Ring + Grid, nodeSize S+M+L,
|
|
13
|
+
* zoom-out + zoom-in, reset, fullscreen) share the same
|
|
14
|
+
* focus-visible ring style: 1px (or equivalent).
|
|
15
|
+
* - The R305 node-alias chat-pin signature is unchanged.
|
|
16
|
+
* - R304/R302/R301/R300/R294 regressions intact.
|
|
17
|
+
*/
|
|
18
|
+
import { chromium } from 'playwright';
|
|
19
|
+
import { readFileSync } from 'node:fs';
|
|
20
|
+
|
|
21
|
+
const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
|
|
22
|
+
const browser = await chromium.launch({ headless: true });
|
|
23
|
+
const ctx = await browser.newContext({ viewport: { width: 1500, height: 1500 } });
|
|
24
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
25
|
+
await ctx.addInitScript(() => {
|
|
26
|
+
try { localStorage.setItem('anet-theme', 'cyber'); sessionStorage.setItem('anet_v3_auth', '1'); } catch {}
|
|
27
|
+
});
|
|
28
|
+
const fresh = new Date(Date.now() - 60 * 1000).toISOString();
|
|
29
|
+
await ctx.route('**/api/hub/status*', async (route) => {
|
|
30
|
+
const r = await route.fetch();
|
|
31
|
+
const b = await r.json();
|
|
32
|
+
const nid = (b.sessions || [])[0]?.network_id || 'default';
|
|
33
|
+
const mk = (alias, model) => ({
|
|
34
|
+
alias, status: 'working', model, runtime: 'claude-code-cli',
|
|
35
|
+
network_id: nid, project_dir: null,
|
|
36
|
+
created_at: fresh, updated_at: fresh, last_seen_at: fresh,
|
|
37
|
+
});
|
|
38
|
+
await route.fulfill({ response: r, json: { ...b, sessions: [
|
|
39
|
+
mk('alpha', 'claude-opus-4'),
|
|
40
|
+
mk('beta', 'gpt-4o'),
|
|
41
|
+
] } });
|
|
42
|
+
});
|
|
43
|
+
await ctx.route('**/api/hub/messages*', (r) => r.fulfill({ json: { messages: [] } }));
|
|
44
|
+
await ctx.route('**/api/hub/tasks*', (r) => r.fulfill({ json: { tasks: [] } }));
|
|
45
|
+
|
|
46
|
+
const page = await ctx.newPage();
|
|
47
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
|
|
48
|
+
await page.waitForSelector('[data-topo-chrome-layout="ring"]', { timeout: 15000 });
|
|
49
|
+
await page.waitForSelector('[data-topo-chrome-fullscreen]', { timeout: 5000 });
|
|
50
|
+
await page.waitForTimeout(300);
|
|
51
|
+
|
|
52
|
+
// Probe the source-of-truth: Tailwind compiles `focus-visible:ring-N`
|
|
53
|
+
// into class names; we read className strings rather than triggering
|
|
54
|
+
// focus-visible state (which requires keyboard input simulation).
|
|
55
|
+
const probe = await page.evaluate(() => {
|
|
56
|
+
const sel = (s) => document.querySelector(s);
|
|
57
|
+
const cls = (el) => el?.className ?? '';
|
|
58
|
+
// Tailwind compiles `focus-visible:ring-N` literally in the className
|
|
59
|
+
// string; checking presence of `focus-visible:ring-1` vs `ring-2`.
|
|
60
|
+
const has = (s, needle) => cls(sel(s)).includes(needle);
|
|
61
|
+
return {
|
|
62
|
+
layoutRing_ring1: has('[data-topo-chrome-layout="ring"]', 'focus-visible:ring-1'),
|
|
63
|
+
layoutRing_no_ring2: !has('[data-topo-chrome-layout="ring"]', 'focus-visible:ring-2'),
|
|
64
|
+
layoutGrid_ring1: has('[data-topo-chrome-layout="grid"]', 'focus-visible:ring-1'),
|
|
65
|
+
layoutGrid_no_ring2: !has('[data-topo-chrome-layout="grid"]', 'focus-visible:ring-2'),
|
|
66
|
+
nodesizeS_ring1: has('[data-topo-chrome-nodesize="S"]', 'focus-visible:ring-1'),
|
|
67
|
+
fullscreen_ring1: has('[data-topo-chrome-fullscreen]', 'focus-visible:ring-1'),
|
|
68
|
+
zoomIn_ring1: has('[data-topo-chrome-zoom-in]', 'focus-visible:ring-1'),
|
|
69
|
+
aliasChatTargetAttrPresent: (() => {
|
|
70
|
+
const a = sel('[data-node-alias-text]');
|
|
71
|
+
return a?.hasAttribute('data-node-alias-chat-target') ?? false;
|
|
72
|
+
})(),
|
|
73
|
+
subhintLs: sel('[data-recent-signal-empty-hint]')?.getAttribute('letter-spacing') ?? null,
|
|
74
|
+
emptyLs: sel('[data-recent-signal-empty]')?.getAttribute('letter-spacing') ?? null,
|
|
75
|
+
kickerFw: (() => {
|
|
76
|
+
const k = sel('[data-topo-section-kicker]');
|
|
77
|
+
return k ? getComputedStyle(k).fontWeight : null;
|
|
78
|
+
})(),
|
|
79
|
+
pulseCount: document.querySelectorAll('[data-pulse-wrapper]').length,
|
|
80
|
+
};
|
|
81
|
+
});
|
|
82
|
+
await browser.close();
|
|
83
|
+
|
|
84
|
+
const results = {
|
|
85
|
+
layout_ring_ring_1: probe.layoutRing_ring1,
|
|
86
|
+
layout_ring_no_ring_2: probe.layoutRing_no_ring2,
|
|
87
|
+
layout_grid_ring_1: probe.layoutGrid_ring1,
|
|
88
|
+
layout_grid_no_ring_2: probe.layoutGrid_no_ring2,
|
|
89
|
+
nodesize_S_ring_1: probe.nodesizeS_ring1,
|
|
90
|
+
fullscreen_ring_1: probe.fullscreen_ring1,
|
|
91
|
+
zoom_in_ring_1: probe.zoomIn_ring1,
|
|
92
|
+
r305_alias_chat_target_attr: probe.aliasChatTargetAttrPresent,
|
|
93
|
+
r304_subhint_ls_0_15: probe.subhintLs === '0.15',
|
|
94
|
+
r302_empty_main_ls_0_2: probe.emptyLs === '0.2',
|
|
95
|
+
r300_kicker_fw_500: String(probe.kickerFw) === '500',
|
|
96
|
+
r294_pulse_absent: probe.pulseCount === 0,
|
|
97
|
+
};
|
|
98
|
+
const ok = Object.values(results).every(Boolean);
|
|
99
|
+
console.log(`${ok ? '✅' : '❌'} chrome focus ring unify:`, JSON.stringify(results));
|
|
100
|
+
process.exit(ok ? 0 : 1);
|