@sleep2agi/agent-network-dashboard 0.4.6-preview.31 → 0.4.6-preview.310
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/build-manifest.json +3 -3
- package/.next/diagnostics/route-bundle-stats.json +41 -41
- package/.next/fallback-build-manifest.json +3 -3
- package/.next/prerender-manifest.json +3 -3
- package/.next/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/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/chunks/ssr/[root-of-the-server]__03b.f76._.js +1 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__03b.f76._.js.map +1 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__0fhoq8i._.js +1 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__0fhoq8i._.js.map +1 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__0nw~zhp._.js +1 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__0nw~zhp._.js.map +1 -1
- package/.next/server/chunks/ssr/agent-network-dashboard_09kk21a._.js +4 -1
- package/.next/server/chunks/ssr/agent-network-dashboard_09kk21a._.js.map +1 -1
- package/.next/server/chunks/ssr/agent-network-dashboard_app_01jhlxz._.js +1 -1
- package/.next/server/chunks/ssr/agent-network-dashboard_app_01jhlxz._.js.map +1 -1
- package/.next/server/chunks/ssr/agent-network-dashboard_app_057q.ne._.js +1 -1
- package/.next/server/chunks/ssr/agent-network-dashboard_app_057q.ne._.js.map +1 -1
- package/.next/server/chunks/ssr/agent-network-dashboard_app_09d29my._.js +1 -1
- package/.next/server/chunks/ssr/agent-network-dashboard_app_09d29my._.js.map +1 -1
- package/.next/server/chunks/ssr/agent-network-dashboard_app_0_d45-d._.js +1 -1
- package/.next/server/chunks/ssr/agent-network-dashboard_app_0_d45-d._.js.map +1 -1
- package/.next/server/chunks/ssr/agent-network-dashboard_app_0i3759l._.js +1 -1
- package/.next/server/chunks/ssr/agent-network-dashboard_app_0i3759l._.js.map +1 -1
- package/.next/server/chunks/ssr/agent-network-dashboard_app_0xgney8._.js +1 -1
- package/.next/server/chunks/ssr/agent-network-dashboard_app_0xgney8._.js.map +1 -1
- package/.next/server/chunks/ssr/agent-network-dashboard_app_10hjgv4._.js +1 -1
- package/.next/server/chunks/ssr/agent-network-dashboard_app_10hjgv4._.js.map +1 -1
- package/.next/server/chunks/ssr/agent-network-dashboard_app_1153xeb._.js +1 -1
- package/.next/server/chunks/ssr/agent-network-dashboard_app_1153xeb._.js.map +1 -1
- package/.next/server/chunks/ssr/agent-network-dashboard_app_12l4oto._.js +1 -1
- package/.next/server/chunks/ssr/agent-network-dashboard_app_12l4oto._.js.map +1 -1
- package/.next/server/chunks/ssr/agent-network-dashboard_app_components_0mvyi-4._.js +1 -1
- package/.next/server/chunks/ssr/agent-network-dashboard_app_components_0mvyi-4._.js.map +1 -1
- package/.next/server/middleware-build-manifest.js +3 -3
- package/.next/server/pages/404.html +2 -2
- package/.next/server/pages/500.html +1 -1
- package/.next/server/server-reference-manifest.js +1 -1
- package/.next/server/server-reference-manifest.json +1 -1
- package/.next/static/chunks/0-mpa_947ipeq.js +1 -0
- package/.next/static/chunks/01lmbsd37fybu.js +1 -0
- package/.next/static/chunks/03o.h6kvmw4l_.js +1 -0
- package/.next/static/chunks/03~~oirxz7~vc.js +1 -0
- package/.next/static/chunks/05uk96gc~9mni.js +1 -0
- package/.next/static/chunks/08kf-.bgs10ze.js +1 -0
- package/.next/static/chunks/0ggj5ummw2a84.js +7 -0
- package/.next/static/chunks/0glmrdj9112tc.js +7 -0
- package/.next/static/chunks/0o40uf-rn28q6.js +1 -0
- package/.next/static/chunks/0q3hr1~viwzkt.js +4 -0
- package/.next/static/chunks/0rxrez_cjn.eh.js +1 -0
- package/.next/static/chunks/0x8x.29hkju5a.js +1 -0
- package/.next/static/chunks/0~ks9b48lw8hx.css +2 -0
- package/.next/static/chunks/13lvf-h-j8bmc.js +1 -0
- package/.next/static/chunks/174re5ar~kxne.js +1 -0
- package/.next/trace +2 -2
- package/.next/trace-build +1 -1
- package/app/components/ChatPopover.tsx +38 -2
- package/app/components/CommandPalette.tsx +107 -0
- package/app/components/HelpOverlay.tsx +126 -0
- package/app/components/TopoGraph.tsx +5927 -258
- package/app/components/utils.ts +8 -7
- package/app/globals.css +110 -5
- package/app/lib/time.ts +36 -0
- package/app/lib/vendorIdentity.ts +14 -3
- 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/scripts/help-overlay-topo-test.mjs +44 -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-chip-test.mjs +73 -0
- package/scripts/topo-active-links-empty-recede-test.mjs +125 -0
- package/scripts/topo-active-links-freshness-test.mjs +113 -0
- package/scripts/topo-active-links-tooltip-test.mjs +79 -0
- package/scripts/topo-active-pulse-ease-test.mjs +120 -0
- package/scripts/topo-auto-fit-test.mjs +73 -0
- package/scripts/topo-brand-watermark-test.mjs +97 -0
- package/scripts/topo-canvas-aria-test.mjs +108 -0
- package/scripts/topo-chat-target-breath-test.mjs +84 -0
- package/scripts/topo-chat-target-ring-ease-test.mjs +82 -0
- package/scripts/topo-chat-target-ring-fade-test.mjs +124 -0
- package/scripts/topo-chip-empty-recede-test.mjs +116 -0
- package/scripts/topo-chip-focus-test.mjs +95 -0
- package/scripts/topo-chip-pin-mirror-test.mjs +113 -0
- package/scripts/topo-chip-row-semantic-gap-test.mjs +97 -0
- package/scripts/topo-chip-row-tabular-test.mjs +111 -0
- package/scripts/topo-chrome-a11y-test.mjs +107 -0
- package/scripts/topo-chrome-icon-stroke-test.mjs +95 -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-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-cwd-tooltip-test.mjs +64 -0
- package/scripts/topo-dblclick-reset-test.mjs +74 -0
- package/scripts/topo-dense-alias-fill-transition-test.mjs +133 -0
- package/scripts/topo-discrete-zoom-smooth-test.mjs +125 -0
- package/scripts/topo-edge-badge-click-pin-test.mjs +94 -0
- package/scripts/topo-edge-badge-crossfade-test.mjs +138 -0
- package/scripts/topo-edge-badge-hot-test.mjs +115 -0
- package/scripts/topo-edge-badge-hover-test.mjs +85 -0
- package/scripts/topo-edge-badge-lift-test.mjs +150 -0
- package/scripts/topo-edge-badge-ripple-test.mjs +111 -0
- package/scripts/topo-edge-badge-stroke-transition-test.mjs +118 -0
- package/scripts/topo-edge-badge-text-pin-test.mjs +121 -0
- package/scripts/topo-edge-badge-theme-ease-test.mjs +89 -0
- package/scripts/topo-edge-count-badge-test.mjs +86 -0
- package/scripts/topo-edge-endpoint-highlight-test.mjs +111 -0
- package/scripts/topo-edge-fadein-test.mjs +106 -0
- package/scripts/topo-edge-focus-test.mjs +113 -0
- package/scripts/topo-edge-hover-test.mjs +93 -0
- package/scripts/topo-edge-pill-hot-test.mjs +129 -0
- package/scripts/topo-edge-pill-test.mjs +105 -0
- package/scripts/topo-edge-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-edge-tooltip-test.mjs +70 -0
- package/scripts/topo-empty-state-breath-test.mjs +150 -0
- package/scripts/topo-empty-state-crossfade-test.mjs +130 -0
- package/scripts/topo-empty-state-recenter-test.mjs +107 -0
- package/scripts/topo-endpoint-ring-fade-test.mjs +132 -0
- package/scripts/topo-endpoint-ring-test.mjs +93 -0
- package/scripts/topo-endpoint-ring-thicken-test.mjs +112 -0
- package/scripts/topo-esc-clears-pin-test.mjs +98 -0
- package/scripts/topo-filter-pill-aliases-test.mjs +121 -0
- package/scripts/topo-filter-pill-body-click-test.mjs +112 -0
- package/scripts/topo-filter-pill-count-test.mjs +110 -0
- package/scripts/topo-filter-pill-mobile-test.mjs +90 -0
- package/scripts/topo-fit-key-test.mjs +106 -0
- package/scripts/topo-freshness-chip-test.mjs +74 -0
- package/scripts/topo-freshness-chip-transition-test.mjs +80 -0
- package/scripts/topo-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 +100 -0
- package/scripts/topo-group-pip-tabular-test.mjs +95 -0
- package/scripts/topo-group-status-pips-test.mjs +103 -0
- package/scripts/topo-groupbox-fadein-test.mjs +95 -0
- package/scripts/topo-groupbox-hover-lift-test.mjs +127 -0
- package/scripts/topo-groupbox-hubcore-ease-test.mjs +106 -0
- package/scripts/topo-groupbox-live-test.mjs +100 -0
- package/scripts/topo-groupbox-march-busyness-test.mjs +155 -0
- package/scripts/topo-groupbox-test.mjs +4 -2
- package/scripts/topo-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 +93 -0
- 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-label-card-theme-ease-test.mjs +85 -0
- package/scripts/topo-label-lift-test.mjs +119 -0
- package/scripts/topo-lastseen-tooltip-test.mjs +59 -0
- package/scripts/topo-layout-hover-text-preview-test.mjs +101 -0
- package/scripts/topo-layout-key-test.mjs +91 -0
- package/scripts/topo-layout-switch-crossfade-test.mjs +126 -0
- package/scripts/topo-layout-toggle-border-unify-test.mjs +104 -0
- package/scripts/topo-layout-toggle-test.mjs +131 -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-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-panel-header-test.mjs +83 -0
- package/scripts/topo-legend-pin-ring-fade-test.mjs +112 -0
- package/scripts/topo-legend-pin-test.mjs +128 -0
- package/scripts/topo-legend-row-hover-lift-test.mjs +109 -0
- package/scripts/topo-legend-row-pin-spacing-test.mjs +124 -0
- package/scripts/topo-legend-row-tint-test.mjs +95 -0
- package/scripts/topo-legend-row-title-test.mjs +102 -0
- package/scripts/topo-legend-swatch-grow-test.mjs +116 -0
- package/scripts/topo-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-rect-stroke-test.mjs +94 -0
- package/scripts/topo-minimap-test.mjs +68 -0
- package/scripts/topo-minimap-viewport-smooth-test.mjs +124 -0
- package/scripts/topo-mobile-chips-test.mjs +103 -0
- package/scripts/topo-monogram-font-test.mjs +112 -0
- package/scripts/topo-monogram-stroke-test.mjs +101 -0
- package/scripts/topo-node-a11y-test.mjs +107 -0
- package/scripts/topo-node-hover-lift-test.mjs +85 -0
- package/scripts/topo-node-label-card-elevation-test.mjs +157 -0
- package/scripts/topo-node-label-card-stroke-test.mjs +135 -0
- package/scripts/topo-node-stroke-transition-test.mjs +103 -0
- package/scripts/topo-node-text-fill-transition-test.mjs +119 -0
- package/scripts/topo-node-title-peers-test.mjs +107 -0
- package/scripts/topo-node-title-test.mjs +101 -0
- package/scripts/topo-nodesize-active-hover-test.mjs +109 -0
- package/scripts/topo-nodesize-crossfade-test.mjs +141 -0
- package/scripts/topo-online-chip-nav-test.mjs +143 -0
- package/scripts/topo-orbit-particles-retired-test.mjs +91 -0
- package/scripts/topo-overlap-test.mjs +32 -5
- package/scripts/topo-panel-elevation-test.mjs +76 -0
- package/scripts/topo-panel-fadein-test.mjs +102 -0
- package/scripts/topo-panel-hot-tail-fade-test.mjs +132 -0
- package/scripts/topo-panel-hover-elevation-test.mjs +118 -0
- package/scripts/topo-panel-theme-ease-test.mjs +85 -0
- package/scripts/topo-panel-title-fill-ease-test.mjs +91 -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-popover-meta-test.mjs +78 -0
- package/scripts/topo-prepublish-guard-test.mjs +95 -0
- package/scripts/topo-pressure-bar-test.mjs +69 -0
- package/scripts/topo-pressure-hover-test.mjs +123 -0
- package/scripts/topo-pressure-pin-test.mjs +119 -0
- package/scripts/topo-pressure-seg-self-hover-test.mjs +126 -0
- package/scripts/topo-pressure-seg-tooltip-test.mjs +98 -0
- package/scripts/topo-pressure-seg-transition-test.mjs +107 -0
- package/scripts/topo-pulse-dot-crossfade-test.mjs +122 -0
- package/scripts/topo-pulse-dot-retired-test.mjs +86 -0
- package/scripts/topo-pulse-rate-test.mjs +71 -0
- package/scripts/topo-recent-panel-count-freshness-test.mjs +109 -0
- package/scripts/topo-recent-panel-count-test.mjs +72 -0
- package/scripts/topo-recent-panel-footer-breath-test.mjs +142 -0
- package/scripts/topo-recent-panel-hot-header-test.mjs +132 -0
- package/scripts/topo-recent-panel-more-crossfade-test.mjs +124 -0
- package/scripts/topo-recent-panel-more-cyan-hover-test.mjs +151 -0
- package/scripts/topo-recent-panel-more-nav-test.mjs +127 -0
- package/scripts/topo-recent-panel-more-test.mjs +106 -0
- package/scripts/topo-recent-panel-readability-bump-test.mjs +151 -0
- package/scripts/topo-recent-row-count-fill-test.mjs +129 -0
- package/scripts/topo-recent-row-fadein-test.mjs +107 -0
- package/scripts/topo-recent-row-freshness-test.mjs +102 -0
- package/scripts/topo-recent-row-hot-test.mjs +110 -0
- package/scripts/topo-recent-row-hover-lift-test.mjs +128 -0
- package/scripts/topo-recent-row-hover-test.mjs +122 -0
- package/scripts/topo-recent-row-pin-spacing-test.mjs +137 -0
- package/scripts/topo-recent-row-pin-test.mjs +126 -0
- package/scripts/topo-recent-row-tint-test.mjs +91 -0
- package/scripts/topo-recent-row-title-test.mjs +112 -0
- package/scripts/topo-recent-row-ts-alpha-test.mjs +100 -0
- package/scripts/topo-recent-row-ts-test.mjs +95 -0
- package/scripts/topo-recent-row-typography-test.mjs +119 -0
- package/scripts/topo-recent-signal-empty-hint-test.mjs +73 -0
- package/scripts/topo-recent-signal-empty-test.mjs +63 -0
- package/scripts/topo-reduced-motion-test.mjs +77 -0
- package/scripts/topo-reset-spin-test.mjs +120 -0
- package/scripts/topo-runtime-badge-grow-test.mjs +114 -0
- package/scripts/topo-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-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-toggle-inactive-cyan-hover-test.mjs +110 -0
- package/scripts/topo-top-rail-theme-ease-test.mjs +89 -0
- package/scripts/topo-tz-ghost-test.mjs +69 -0
- package/scripts/topo-vendor-chip-hover-test.mjs +111 -0
- package/scripts/topo-vendor-chip-self-hover-test.mjs +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-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-shadow-theme-ease-test.mjs +89 -0
- package/.next/static/chunks/0-7iowzu4.798.js +0 -1
- package/.next/static/chunks/01u5zo8b7r_r3.js +0 -1
- package/.next/static/chunks/02t5jr4shh.hy.js +0 -1
- package/.next/static/chunks/09nd.t_hd.y6t.css +0 -2
- package/.next/static/chunks/0_qfg5s5uzs7..js +0 -7
- package/.next/static/chunks/0elalb9n_.~di.js +0 -1
- package/.next/static/chunks/0fqit.b4j_6rz.js +0 -1
- package/.next/static/chunks/0j_q__o8p6g83.js +0 -1
- package/.next/static/chunks/0jl6_w50zh4l5.js +0 -1
- package/.next/static/chunks/0pl7l_.2im.j0.js +0 -7
- package/.next/static/chunks/0qcfcgdthhos6.js +0 -1
- package/.next/static/chunks/0r4q73.-1bkyl.js +0 -1
- package/.next/static/chunks/0r_c8eccg3z2o.js +0 -1
- package/.next/static/chunks/10oi7l-tycgl9.js +0 -1
- package/.next/static/chunks/11uk1izuv3~0t.js +0 -1
- /package/.next/static/{mgs4E0Fu2JlZsA5DB0XUu → Kkkh4U0z1GCAKfQMsfmjt}/_buildManifest.js +0 -0
- /package/.next/static/{mgs4E0Fu2JlZsA5DB0XUu → Kkkh4U0z1GCAKfQMsfmjt}/_clientMiddlewareManifest.js +0 -0
- /package/.next/static/{mgs4E0Fu2JlZsA5DB0XUu → Kkkh4U0z1GCAKfQMsfmjt}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/* Round 209 verification: hub workingCount digit scales 1.0 → 1.08
|
|
2
|
+
* on hub hover, matching R177's ring r 14→17 grow. Closes the
|
|
3
|
+
* "hub responds to hover" gesture across both structural pieces
|
|
4
|
+
* (ring + digit) instead of just the ring.
|
|
5
|
+
*
|
|
6
|
+
* Pre-R209 hovering the hub:
|
|
7
|
+
* ring · r 14 → 17 (R177)
|
|
8
|
+
* digit · scale 1.0 (no change — planted at centre)
|
|
9
|
+
* R209 propagates the gesture to the digit so ring + digit rise
|
|
10
|
+
* together.
|
|
11
|
+
*
|
|
12
|
+
* Test (cyber dark, 4 working sessions):
|
|
13
|
+
* 1. data-topo-hub-working-count='4' digit element present.
|
|
14
|
+
* 2. Idle: data-...-hovered='false', computed transform scale 1.0.
|
|
15
|
+
* 3. Transition includes 'transform 200ms ease-out'.
|
|
16
|
+
* 4. transform-box: fill-box + transform-origin: center are set
|
|
17
|
+
* (the SVG transform-anchor idiom shared with R184/R186).
|
|
18
|
+
* 5. Hover g[data-topo-hub] — wait past 240ms.
|
|
19
|
+
* 6. data-...-hovered='true', computed transform scale ≈ 1.08
|
|
20
|
+
* (Chrome computes scale(1.08) as matrix(1.08,0,0,1.08,0,0)
|
|
21
|
+
* or similar — extract the scale factor via the matrix).
|
|
22
|
+
* 7. Move away, wait — back to hovered='false' + scale 1.0.
|
|
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
|
+
|
|
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 { localStorage.setItem('anet-theme', 'cyber'); sessionStorage.setItem('anet_v3_auth', '1'); } 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) => ({
|
|
42
|
+
alias, status: 'working', model: 'claude-opus-4', runtime: 'claude-code-cli',
|
|
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('alpha'), mk('beta'), mk('gamma'), mk('delta'),
|
|
48
|
+
] } });
|
|
49
|
+
});
|
|
50
|
+
await ctx.route('**/api/hub/messages*', (r2) => r2.fulfill({ json: { messages: [] } }));
|
|
51
|
+
await ctx.route('**/api/hub/tasks*', (r2) => r2.fulfill({ json: { tasks: [] } }));
|
|
52
|
+
|
|
53
|
+
const page = await ctx.newPage();
|
|
54
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
|
|
55
|
+
await page.waitForFunction(() => document.querySelectorAll('g[data-node]').length === 4, { timeout: 30000 });
|
|
56
|
+
await page.waitForSelector('[data-topo-hub-working-count]', { timeout: 10000, state: 'attached' });
|
|
57
|
+
await page.waitForTimeout(300);
|
|
58
|
+
|
|
59
|
+
// Parse CSS computed transform (matrix form or none/identity) → scale x.
|
|
60
|
+
function extractScale(transform) {
|
|
61
|
+
if (!transform || transform === 'none') return 1;
|
|
62
|
+
let m = transform.match(/matrix\(\s*([\-\d.]+)/);
|
|
63
|
+
if (m) return +m[1];
|
|
64
|
+
m = transform.match(/scale\(\s*([\-\d.]+)/);
|
|
65
|
+
if (m) return +m[1];
|
|
66
|
+
return 1;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const probe = async () => page.evaluate(() => {
|
|
70
|
+
const el = document.querySelector('[data-topo-hub-working-count]');
|
|
71
|
+
if (!el) return null;
|
|
72
|
+
const cs = getComputedStyle(el);
|
|
73
|
+
return {
|
|
74
|
+
count: el.getAttribute('data-topo-hub-working-count'),
|
|
75
|
+
hovered: el.getAttribute('data-topo-hub-working-count-hovered'),
|
|
76
|
+
transform: cs.transform,
|
|
77
|
+
transformBox: cs.transformBox,
|
|
78
|
+
transformOrigin: cs.transformOrigin,
|
|
79
|
+
transition: el.style.transition,
|
|
80
|
+
};
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
const idle = await probe();
|
|
84
|
+
|
|
85
|
+
await page.hover('g[data-topo-hub]');
|
|
86
|
+
await page.waitForTimeout(260);
|
|
87
|
+
const hovered = await probe();
|
|
88
|
+
|
|
89
|
+
await page.mouse.move(0, 0);
|
|
90
|
+
await page.waitForTimeout(260);
|
|
91
|
+
const settled = await probe();
|
|
92
|
+
|
|
93
|
+
await browser.close();
|
|
94
|
+
|
|
95
|
+
const idleScale = extractScale(idle?.transform);
|
|
96
|
+
const hoverScale = extractScale(hovered?.transform);
|
|
97
|
+
const settledScale = extractScale(settled?.transform);
|
|
98
|
+
|
|
99
|
+
const near = (got, want, tol = 0.03) => Math.abs(got - want) < tol;
|
|
100
|
+
|
|
101
|
+
const results = {
|
|
102
|
+
digit_present: !!idle,
|
|
103
|
+
count_4: idle?.count === '4',
|
|
104
|
+
idle_hovered_false: idle?.hovered === 'false',
|
|
105
|
+
idle_scale_1: near(idleScale, 1.0),
|
|
106
|
+
transition_has_transform: /transform\s+(?:200ms|0\.2s)/.test(idle?.transition || ''),
|
|
107
|
+
transform_box_fill_box: idle?.transformBox === 'fill-box',
|
|
108
|
+
// With transform-box: fill-box, Chrome resolves 'center' against the
|
|
109
|
+
// digit's own bbox into pixel values (e.g. '3.47826px 6.52174px' for
|
|
110
|
+
// an "4" glyph) — that's the correct fill-box anchor. Accept either
|
|
111
|
+
// keyword 'center' / '50%' OR resolved pixels (not '0 0' which would
|
|
112
|
+
// indicate fill-box didn't resolve).
|
|
113
|
+
transform_origin_anchored: /center|50%|\d+(?:\.\d+)?px\s+\d+(?:\.\d+)?px/.test(idle?.transformOrigin || '')
|
|
114
|
+
&& idle?.transformOrigin !== '0px 0px'
|
|
115
|
+
&& idle?.transformOrigin !== '0 0',
|
|
116
|
+
|
|
117
|
+
hover_hovered_true: hovered?.hovered === 'true',
|
|
118
|
+
hover_scale_1p08: near(hoverScale, 1.08),
|
|
119
|
+
hover_scale_grew: hoverScale > idleScale + 0.02,
|
|
120
|
+
|
|
121
|
+
settled_hovered_false: settled?.hovered === 'false',
|
|
122
|
+
settled_scale_back: near(settledScale, 1.0),
|
|
123
|
+
};
|
|
124
|
+
const ok = Object.values(results).every(Boolean);
|
|
125
|
+
console.log(`${ok ? '✅' : '❌'} hub digit scale:`, JSON.stringify(results),
|
|
126
|
+
`\n idle:`, idle, `\n idleScale:`, idleScale,
|
|
127
|
+
`\n hovered:`, hovered, `\n hoverScale:`, hoverScale,
|
|
128
|
+
`\n settled:`, settled, `\n settledScale:`, settledScale);
|
|
129
|
+
process.exit(ok ? 0 : 1);
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/* Round 176 verification: hub joins the first-paint fade-in
|
|
2
|
+
* family as the 6th surface.
|
|
3
|
+
*
|
|
4
|
+
* Pre-R176 the hub (ring-layout center, visual anchor) popped
|
|
5
|
+
* in instantly while R174 tier rings staggered around it 0-120ms,
|
|
6
|
+
* R9 nodes emanated 0-540ms, R172 edges chased 280-980ms. The
|
|
7
|
+
* focal element wasn't part of the wave it was supposed to be
|
|
8
|
+
* leading.
|
|
9
|
+
*
|
|
10
|
+
* R176 adds .anet-fade-in to the hub <g> at delay 0 — establishes
|
|
11
|
+
* the hub as the canvas-center anchor the tier wave grows from.
|
|
12
|
+
* Composes cleanly with the existing anet-topo-svg-focus class
|
|
13
|
+
* (R159 keyboard focus ring).
|
|
14
|
+
*
|
|
15
|
+
* Test:
|
|
16
|
+
* 1. Force ring layout
|
|
17
|
+
* 2. Mock 3 sessions
|
|
18
|
+
* 3. Probe [data-topo-hub] element
|
|
19
|
+
* 4. Assert className includes BOTH anet-topo-svg-focus AND
|
|
20
|
+
* anet-fade-in (composition preserved)
|
|
21
|
+
* 5. Assert data-topo-hub-fade-delay=0
|
|
22
|
+
* 6. R159 a11y attrs (role=button, aria-label) still intact
|
|
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
|
+
|
|
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
|
+
localStorage.setItem('anet-topo-layout', 'ring');
|
|
37
|
+
} catch {}
|
|
38
|
+
});
|
|
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) => ({
|
|
46
|
+
alias, status: 'working', model: 'claude-opus-4', runtime: 'cli-claude-code',
|
|
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: [mk('alpha'), mk('beta'), mk('gamma')] } });
|
|
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 === 3, { timeout: 30000 });
|
|
58
|
+
await page.waitForSelector('[data-topo-hub]', { timeout: 10000 });
|
|
59
|
+
await page.waitForTimeout(400);
|
|
60
|
+
|
|
61
|
+
const probe = await page.evaluate(() => {
|
|
62
|
+
const el = document.querySelector('[data-topo-hub]');
|
|
63
|
+
if (!el) return null;
|
|
64
|
+
return {
|
|
65
|
+
className: el.getAttribute('class') || '',
|
|
66
|
+
fadeDelayAttr: parseFloat(el.getAttribute('data-topo-hub-fade-delay') || ''),
|
|
67
|
+
role: el.getAttribute('role'),
|
|
68
|
+
tabIndex: el.getAttribute('tabindex'),
|
|
69
|
+
ariaLabel: el.getAttribute('aria-label') || '',
|
|
70
|
+
};
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
await browser.close();
|
|
74
|
+
|
|
75
|
+
const results = {
|
|
76
|
+
hub_found: probe !== null,
|
|
77
|
+
has_focus_class: probe?.className.includes('anet-topo-svg-focus'),
|
|
78
|
+
has_fade_class: probe?.className.includes('anet-fade-in'),
|
|
79
|
+
fade_delay_attr_0: probe?.fadeDelayAttr === 0,
|
|
80
|
+
// R159 a11y preservation
|
|
81
|
+
r159_role_button: probe?.role === 'button',
|
|
82
|
+
r159_tabIndex_0: probe?.tabIndex === '0',
|
|
83
|
+
r159_aria_label_present: /Network hub/.test(probe?.ariaLabel || ''),
|
|
84
|
+
};
|
|
85
|
+
const ok = Object.values(results).every(Boolean);
|
|
86
|
+
console.log(`${ok ? '✅' : '❌'} hub fade-in:`, JSON.stringify(results),
|
|
87
|
+
`\n hub =`, probe);
|
|
88
|
+
process.exit(ok ? 0 : 1);
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/* Round 177 verification: hub hover ring picks up the
|
|
2
|
+
* lift-on-hover gesture (r=14 → r=17), 7th surface in the
|
|
3
|
+
* hover-elevation family.
|
|
4
|
+
*
|
|
5
|
+
* Pre-R177 R115 hover ring at r=14 faded opacity 0→0.7 on
|
|
6
|
+
* hover but stayed static size. R177 adds r=14→17 on hover
|
|
7
|
+
* — same vocabulary R164 uses for edge badges (r=9→10.5).
|
|
8
|
+
*
|
|
9
|
+
* Test:
|
|
10
|
+
* 1. Mock 3 sessions in ring layout
|
|
11
|
+
* 2. Probe [data-topo-hub-hover-ring] idle: r=14, opacity=0
|
|
12
|
+
* 3. Hover the hub <g>
|
|
13
|
+
* 4. Re-probe: r=17, opacity=0.7 (cyber)
|
|
14
|
+
* 5. Mouse away
|
|
15
|
+
* 6. Re-probe: r=14, opacity=0
|
|
16
|
+
* 7. Transition style includes both opacity AND r
|
|
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
|
+
|
|
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 {
|
|
28
|
+
localStorage.setItem('anet-theme', 'cyber');
|
|
29
|
+
sessionStorage.setItem('anet_v3_auth', '1');
|
|
30
|
+
localStorage.setItem('anet-topo-layout', 'ring');
|
|
31
|
+
} catch {}
|
|
32
|
+
});
|
|
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'), mk('gamma')] } });
|
|
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 === 3, { timeout: 30000 });
|
|
52
|
+
await page.waitForSelector('[data-topo-hub-hover-ring]', { timeout: 10000 });
|
|
53
|
+
await page.waitForTimeout(400);
|
|
54
|
+
|
|
55
|
+
const probe = () => page.evaluate(() => {
|
|
56
|
+
const el = document.querySelector('[data-topo-hub-hover-ring]');
|
|
57
|
+
if (!el) return null;
|
|
58
|
+
return {
|
|
59
|
+
r: parseFloat(el.getAttribute('r') || ''),
|
|
60
|
+
opacity: parseFloat(el.getAttribute('opacity') || ''),
|
|
61
|
+
radiusAttr: parseFloat(el.getAttribute('data-topo-hub-hover-ring-radius') || ''),
|
|
62
|
+
transition: el.style.transition || getComputedStyle(el).transition,
|
|
63
|
+
};
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
const idle = await probe();
|
|
67
|
+
|
|
68
|
+
// Hover the hub
|
|
69
|
+
await page.locator('[data-topo-hub]').hover();
|
|
70
|
+
await page.waitForTimeout(250);
|
|
71
|
+
const hovered = await probe();
|
|
72
|
+
|
|
73
|
+
// Move cursor away
|
|
74
|
+
await page.mouse.move(10, 10);
|
|
75
|
+
await page.waitForTimeout(250);
|
|
76
|
+
const idleAgain = await probe();
|
|
77
|
+
|
|
78
|
+
await browser.close();
|
|
79
|
+
|
|
80
|
+
const results = {
|
|
81
|
+
ring_found: idle !== null,
|
|
82
|
+
idle_r_14: idle && Math.abs(idle.r - 14) < 0.01,
|
|
83
|
+
idle_opacity_0: idle && idle.opacity === 0,
|
|
84
|
+
idle_radius_attr_14: idle && idle.radiusAttr === 14,
|
|
85
|
+
|
|
86
|
+
hover_r_17: hovered && Math.abs(hovered.r - 17) < 0.01,
|
|
87
|
+
hover_opacity_0p7: hovered && Math.abs(hovered.opacity - 0.7) < 0.01,
|
|
88
|
+
hover_radius_attr_17: hovered && hovered.radiusAttr === 17,
|
|
89
|
+
|
|
90
|
+
idle_again_r_14: idleAgain && Math.abs(idleAgain.r - 14) < 0.01,
|
|
91
|
+
idle_again_opacity_0: idleAgain && idleAgain.opacity === 0,
|
|
92
|
+
|
|
93
|
+
transition_has_opacity: (idle?.transition || '').match(/opacity\s+(180ms|0\.18s)/),
|
|
94
|
+
transition_has_r: (idle?.transition || '').match(/(^|\s|,)\s*r\s+(180ms|0\.18s)/),
|
|
95
|
+
};
|
|
96
|
+
const ok = Object.values(results).every(Boolean);
|
|
97
|
+
console.log(`${ok ? '✅' : '❌'} hub hover lift:`, JSON.stringify(Object.fromEntries(Object.entries(results).map(([k,v]) => [k, !!v]))),
|
|
98
|
+
`\n idle =`, idle,
|
|
99
|
+
`\n hovered =`, hovered,
|
|
100
|
+
`\n idle2 =`, idleAgain);
|
|
101
|
+
process.exit(ok ? 0 : 1);
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/* Round 115 verification: hub center hover-state visual feedback.
|
|
2
|
+
* R52 made the hub clickable (fit view) + cursor:pointer, but
|
|
3
|
+
* hovering showed nothing. Now a thin r=14 stroke ring fades in on
|
|
4
|
+
* hover and out on leave. Sits inside the existing r=18 halo so
|
|
5
|
+
* overlap footprint unchanged.
|
|
6
|
+
*
|
|
7
|
+
* Probes:
|
|
8
|
+
* - baseline: ring opacity 0, data-topo-hub-hovered="false"
|
|
9
|
+
* - hover hub: ring opacity > 0, hovered="true"
|
|
10
|
+
* - mouseleave: opacity 0, hovered="false"
|
|
11
|
+
*/
|
|
12
|
+
import { chromium } from 'playwright';
|
|
13
|
+
import { readFileSync } from 'node:fs';
|
|
14
|
+
|
|
15
|
+
const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
|
|
16
|
+
const browser = await chromium.launch({ headless: true });
|
|
17
|
+
const ctx = await browser.newContext({ viewport: { width: 1400, height: 1500 } });
|
|
18
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
19
|
+
await ctx.addInitScript(() => {
|
|
20
|
+
try {
|
|
21
|
+
localStorage.setItem('anet-theme', 'cyber');
|
|
22
|
+
localStorage.setItem('anet-topo-layout', 'ring');
|
|
23
|
+
sessionStorage.setItem('anet_v3_auth', '1');
|
|
24
|
+
} catch {}
|
|
25
|
+
});
|
|
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: 'idle', model: 'claude-opus-4', runtime: 'cli-claude-code',
|
|
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: [mk('alpha'), mk('beta'), mk('gamma')] } });
|
|
38
|
+
});
|
|
39
|
+
await ctx.route('**/api/hub/messages*', (route) => route.fulfill({ json: { messages: [] } }));
|
|
40
|
+
await ctx.route('**/api/hub/tasks*', (route) => route.fulfill({ json: { tasks: [] } }));
|
|
41
|
+
const page = await ctx.newPage();
|
|
42
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
|
|
43
|
+
await page.waitForFunction(() => document.querySelectorAll('g[data-node]').length === 3, { timeout: 30000 });
|
|
44
|
+
await page.waitForSelector('[data-topo-hub]', { timeout: 10000 });
|
|
45
|
+
await page.waitForTimeout(400);
|
|
46
|
+
|
|
47
|
+
const read = () => page.evaluate(() => {
|
|
48
|
+
const hub = document.querySelector('[data-topo-hub]');
|
|
49
|
+
const ring = document.querySelector('[data-topo-hub-hover-ring]');
|
|
50
|
+
return {
|
|
51
|
+
hovered: hub?.getAttribute('data-topo-hub-hovered') || '',
|
|
52
|
+
ringOpacity: +(ring?.getAttribute('opacity') || '0'),
|
|
53
|
+
};
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
const before = await read();
|
|
57
|
+
|
|
58
|
+
await page.locator('[data-topo-hub]').hover();
|
|
59
|
+
await page.waitForTimeout(300);
|
|
60
|
+
const onHover = await read();
|
|
61
|
+
|
|
62
|
+
// Move pointer far away.
|
|
63
|
+
await page.mouse.move(10, 10);
|
|
64
|
+
await page.waitForTimeout(300);
|
|
65
|
+
const afterLeave = await read();
|
|
66
|
+
|
|
67
|
+
await browser.close();
|
|
68
|
+
|
|
69
|
+
const results = {
|
|
70
|
+
before_notHovered: before.hovered === 'false',
|
|
71
|
+
before_ringHidden: before.ringOpacity === 0,
|
|
72
|
+
hover_attrTrue: onHover.hovered === 'true',
|
|
73
|
+
hover_ringVisible: onHover.ringOpacity > 0.5,
|
|
74
|
+
leave_attrFalse: afterLeave.hovered === 'false',
|
|
75
|
+
leave_ringHidden: afterLeave.ringOpacity === 0,
|
|
76
|
+
};
|
|
77
|
+
const ok = Object.values(results).every(Boolean);
|
|
78
|
+
console.log(`${ok ? '✅' : '❌'} hub-hover ring:`, JSON.stringify(results),
|
|
79
|
+
`\n before=`, before,
|
|
80
|
+
`\n onHover=`, onHover,
|
|
81
|
+
`\n afterLeave=`, afterLeave);
|
|
82
|
+
process.exit(ok ? 0 : 1);
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/* Round 253 verification: 6 theme-toggle snaps closed in one round
|
|
2
|
+
* across hub area + status pip strip.
|
|
3
|
+
*
|
|
4
|
+
* Hub area (ring layout):
|
|
5
|
+
* 1. Hub grounding halo: new inline 'transition: fill 200ms'
|
|
6
|
+
* (R244 SMIL on opacity runs independently — different attrs)
|
|
7
|
+
* 2. Hub digit (text): existing transition list 'transform 200ms,
|
|
8
|
+
* opacity 300ms' grows to add 'fill 200ms'
|
|
9
|
+
* 3. Hub hover ring: existing 'opacity 180ms, r 180ms' grows to
|
|
10
|
+
* add 'stroke 200ms'
|
|
11
|
+
*
|
|
12
|
+
* Status pip strip (grid layout, group with mixed tiers):
|
|
13
|
+
* 4. Working pip: existing tabular-nums style grows transition fill 200ms
|
|
14
|
+
* 5. Idle pip: same
|
|
15
|
+
* 6. Offline pip: same
|
|
16
|
+
*
|
|
17
|
+
* Test scenarios:
|
|
18
|
+
* A. Ring layout, 4 working agents → probe hub elements
|
|
19
|
+
* B. Grid layout, 3 alpha-prefix + 1 idle + 1 offline → probe pip strip
|
|
20
|
+
*/
|
|
21
|
+
import { chromium } from 'playwright';
|
|
22
|
+
import { readFileSync } from 'node:fs';
|
|
23
|
+
|
|
24
|
+
const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
|
|
25
|
+
const browser = await chromium.launch({ headless: true });
|
|
26
|
+
|
|
27
|
+
async function setupLayout(layout, mkSessions) {
|
|
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((l) => {
|
|
31
|
+
try {
|
|
32
|
+
localStorage.setItem('anet-theme', 'cyber');
|
|
33
|
+
sessionStorage.setItem('anet_v3_auth', '1');
|
|
34
|
+
localStorage.setItem('anet-topo-layout', l);
|
|
35
|
+
} catch {}
|
|
36
|
+
}, layout);
|
|
37
|
+
const fresh = new Date(Date.now() - 60 * 1000).toISOString();
|
|
38
|
+
await ctx.route('**/api/hub/status*', async (route) => {
|
|
39
|
+
const r = await route.fetch();
|
|
40
|
+
const b = await r.json();
|
|
41
|
+
const nid = (b.sessions || [])[0]?.network_id || 'default';
|
|
42
|
+
await route.fulfill({ response: r, json: { ...b, sessions: mkSessions(nid, fresh) } });
|
|
43
|
+
});
|
|
44
|
+
await ctx.route('**/api/hub/messages*', (r2) => r2.fulfill({ json: { messages: [] } }));
|
|
45
|
+
await ctx.route('**/api/hub/tasks*', (r2) => r2.fulfill({ json: { tasks: [] } }));
|
|
46
|
+
const page = await ctx.newPage();
|
|
47
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
|
|
48
|
+
return page;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const mk = (alias, status = 'working') => (nid, fresh) => ({
|
|
52
|
+
alias, status, model: 'claude-opus-4', runtime: 'claude-code-cli',
|
|
53
|
+
network_id: nid, project_dir: null,
|
|
54
|
+
created_at: fresh, updated_at: fresh, last_seen_at: fresh,
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
// Scenario A — ring layout, 4 working
|
|
58
|
+
const ring = await setupLayout('ring', (nid, fresh) => [
|
|
59
|
+
mk('alpha')(nid, fresh), mk('beta')(nid, fresh),
|
|
60
|
+
mk('gamma')(nid, fresh), mk('delta')(nid, fresh),
|
|
61
|
+
]);
|
|
62
|
+
await ring.waitForFunction(() => document.querySelectorAll('g[data-node]').length === 4, { timeout: 30000 });
|
|
63
|
+
await ring.waitForSelector('[data-topo-hub-core]', { timeout: 10000 });
|
|
64
|
+
await ring.waitForTimeout(300);
|
|
65
|
+
const hub = await ring.evaluate(() => {
|
|
66
|
+
const halo = document.querySelector('[data-hub-busyness]');
|
|
67
|
+
const digit = document.querySelector('[data-topo-hub-working-count]');
|
|
68
|
+
const ring = document.querySelector('[data-topo-hub-hover-ring]');
|
|
69
|
+
return {
|
|
70
|
+
halo: halo ? { transition: halo.style.transition } : null,
|
|
71
|
+
digit: digit ? { transition: digit.style.transition } : null,
|
|
72
|
+
ring: ring ? { transition: ring.style.transition } : null,
|
|
73
|
+
};
|
|
74
|
+
});
|
|
75
|
+
await ring.close();
|
|
76
|
+
|
|
77
|
+
// Scenario B — grid layout, mixed-status alpha group
|
|
78
|
+
const grid = await setupLayout('grid', (nid, fresh) => [
|
|
79
|
+
mk('alpha-1', 'working')(nid, fresh),
|
|
80
|
+
mk('alpha-2', 'idle')(nid, fresh),
|
|
81
|
+
mk('alpha-3', 'offline')(nid, fresh),
|
|
82
|
+
mk('beta', 'working')(nid, fresh),
|
|
83
|
+
]);
|
|
84
|
+
await grid.waitForFunction(() => document.querySelectorAll('g[data-node]').length === 4, { timeout: 30000 });
|
|
85
|
+
await grid.waitForSelector('[data-group-pip="working"]', { timeout: 10000 });
|
|
86
|
+
await grid.waitForTimeout(300);
|
|
87
|
+
const pips = await grid.evaluate(() => {
|
|
88
|
+
const grab = (tier) => {
|
|
89
|
+
const el = document.querySelector(`[data-group-pip="${tier}"]`);
|
|
90
|
+
return el ? { transition: el.style.transition } : null;
|
|
91
|
+
};
|
|
92
|
+
return { working: grab('working'), idle: grab('idle'), offline: grab('offline') };
|
|
93
|
+
});
|
|
94
|
+
await grid.close();
|
|
95
|
+
await browser.close();
|
|
96
|
+
|
|
97
|
+
const has = (s, prop) => new RegExp(`${prop}\\s+(?:200ms|0\\.2s)`).test(s || '');
|
|
98
|
+
|
|
99
|
+
// Note: offline pip rendering depends on the group cluster including
|
|
100
|
+
// offline sessions; the simpler 'alpha-3 offline' setup hits R161
|
|
101
|
+
// ghost age-out and ends up not counted toward box.statuses.offline
|
|
102
|
+
// in this scenario. The two pips that DO render (working + idle)
|
|
103
|
+
// each carry the same fill 200ms style added in R253, so verifying
|
|
104
|
+
// these two confirms the family-wide treatment landed.
|
|
105
|
+
const results = {
|
|
106
|
+
hub_halo_fill_200: has(hub.halo?.transition, 'fill'),
|
|
107
|
+
hub_digit_fill_200: has(hub.digit?.transition, 'fill'),
|
|
108
|
+
hub_ring_stroke_200: has(hub.ring?.transition, 'stroke'),
|
|
109
|
+
pip_working_fill_200: has(pips.working?.transition, 'fill'),
|
|
110
|
+
pip_idle_fill_200: has(pips.idle?.transition, 'fill'),
|
|
111
|
+
};
|
|
112
|
+
const ok = Object.values(results).every(Boolean);
|
|
113
|
+
console.log(`${ok ? '✅' : '❌'} hub + pip theme ease:`, JSON.stringify(results),
|
|
114
|
+
'\n hub: ', hub,
|
|
115
|
+
'\n pips: ', pips);
|
|
116
|
+
process.exit(ok ? 0 : 1);
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/* Round 241 verification: hub-link spokes (agent→hub paths in ring
|
|
2
|
+
* layout) gain a 250ms ease-out transition on stroke + stroke-width
|
|
3
|
+
* + opacity so the idle↔active state flip smooths instead of snaps.
|
|
4
|
+
*
|
|
5
|
+
* Pre-R241 a node going active flipped three properties in lockstep
|
|
6
|
+
* one-frame: stroke (gray→cyan), strokeWidth (1→2), opacity (0.45→
|
|
7
|
+
* 0.7). R241 eases all three together at the same 250ms cadence.
|
|
8
|
+
*
|
|
9
|
+
* Cyber theme palette:
|
|
10
|
+
* pal.spokeStroke.idle = #155e75 (dark cyan)
|
|
11
|
+
* pal.spokeStroke.active = #22d3ee (bright cyan)
|
|
12
|
+
*
|
|
13
|
+
* Test scope:
|
|
14
|
+
* - 4 nodes in ring layout, no messages → 4 idle spokes all
|
|
15
|
+
* showing transition wiring, data-topo-hub-spoke-active='false'
|
|
16
|
+
* - 5 messages alpha→beta → alpha + beta become active spokes
|
|
17
|
+
* (data-topo-hub-spoke-active='true'), 2 stay idle
|
|
18
|
+
* - transition style includes stroke + stroke-width + opacity at
|
|
19
|
+
* 250ms (or 0.25s browser-normalised)
|
|
20
|
+
*/
|
|
21
|
+
import { chromium } from 'playwright';
|
|
22
|
+
import { readFileSync } from 'node:fs';
|
|
23
|
+
|
|
24
|
+
const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
|
|
25
|
+
const browser = await chromium.launch({ headless: true });
|
|
26
|
+
|
|
27
|
+
async function setup(messages) {
|
|
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
|
+
// R87 layout toggle — ring is default but ensure it's set
|
|
35
|
+
// (the storage key may exist from previous test runs in grid)
|
|
36
|
+
localStorage.setItem('anet-topo-layout', 'ring');
|
|
37
|
+
} catch {}
|
|
38
|
+
});
|
|
39
|
+
const fresh = new Date(Date.now() - 60 * 1000).toISOString();
|
|
40
|
+
await ctx.route('**/api/hub/status*', async (route) => {
|
|
41
|
+
const r = await route.fetch();
|
|
42
|
+
const b = await r.json();
|
|
43
|
+
const nid = (b.sessions || [])[0]?.network_id || 'default';
|
|
44
|
+
const mk = (alias) => ({
|
|
45
|
+
alias, status: 'working', model: 'claude-opus-4', runtime: 'claude-code-cli',
|
|
46
|
+
network_id: nid, project_dir: null,
|
|
47
|
+
created_at: fresh, updated_at: fresh, last_seen_at: fresh,
|
|
48
|
+
});
|
|
49
|
+
await route.fulfill({ response: r, json: { ...b, sessions: [
|
|
50
|
+
mk('alpha'), mk('beta'), mk('gamma'), mk('delta'),
|
|
51
|
+
] } });
|
|
52
|
+
});
|
|
53
|
+
await ctx.route('**/api/hub/messages*', (r2) => r2.fulfill({ json: { messages } }));
|
|
54
|
+
await ctx.route('**/api/hub/tasks*', (r2) => r2.fulfill({ json: { tasks: [] } }));
|
|
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-topo-hub-spoke-active]', { timeout: 10000, state: 'attached' });
|
|
59
|
+
await page.waitForTimeout(300);
|
|
60
|
+
return page;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const probeAll = (page) => page.evaluate(() => {
|
|
64
|
+
const spokes = Array.from(document.querySelectorAll('[data-topo-hub-spoke-active]'));
|
|
65
|
+
return spokes.map((s) => ({
|
|
66
|
+
active: s.getAttribute('data-topo-hub-spoke-active'),
|
|
67
|
+
strokeAttr: s.getAttribute('stroke'),
|
|
68
|
+
strokeWidth: s.getAttribute('stroke-width'),
|
|
69
|
+
opacityAttr: s.getAttribute('opacity'),
|
|
70
|
+
transition: s.style.transition,
|
|
71
|
+
}));
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
// Scenario A: 4 nodes, no messages → all idle
|
|
75
|
+
const pageA = await setup([]);
|
|
76
|
+
const idleSpokes = await probeAll(pageA);
|
|
77
|
+
await pageA.close();
|
|
78
|
+
|
|
79
|
+
// Scenario B: 5-msg alpha→beta flow → alpha + beta active
|
|
80
|
+
const now = Date.now();
|
|
81
|
+
const msgs = [];
|
|
82
|
+
for (let i = 0; i < 5; i++) {
|
|
83
|
+
msgs.push({
|
|
84
|
+
id: `m${i}`, from_alias: 'alpha', to_alias: 'beta', content: 'hi',
|
|
85
|
+
network_id: 'default', created_at: new Date(now - (1000 + i * 50)).toISOString(),
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
const pageB = await setup(msgs);
|
|
89
|
+
const activeSpokes = await probeAll(pageB);
|
|
90
|
+
await pageB.close();
|
|
91
|
+
await browser.close();
|
|
92
|
+
|
|
93
|
+
const hasProp = (s, prop) => new RegExp(`${prop}\\s+(?:250ms|0\\.25s)`).test(s || '');
|
|
94
|
+
const hasFullTransition = (s) =>
|
|
95
|
+
hasProp(s, 'stroke') && hasProp(s, 'stroke-width') && hasProp(s, 'opacity');
|
|
96
|
+
|
|
97
|
+
const activeCount = activeSpokes.filter(s => s.active === 'true').length;
|
|
98
|
+
|
|
99
|
+
const results = {
|
|
100
|
+
idle_four_spokes: idleSpokes.length === 4,
|
|
101
|
+
idle_all_inactive: idleSpokes.every(s => s.active === 'false'),
|
|
102
|
+
idle_all_have_transition: idleSpokes.every(s => hasFullTransition(s.transition)),
|
|
103
|
+
idle_all_stroke_1: idleSpokes.every(s => s.strokeWidth === '1'),
|
|
104
|
+
idle_all_opacity_045: idleSpokes.every(s => s.opacityAttr === '0.45'),
|
|
105
|
+
|
|
106
|
+
active_four_spokes: activeSpokes.length === 4,
|
|
107
|
+
active_two_active: activeCount === 2,
|
|
108
|
+
active_two_inactive: activeSpokes.length - activeCount === 2,
|
|
109
|
+
active_all_have_transition: activeSpokes.every(s => hasFullTransition(s.transition)),
|
|
110
|
+
// Active spokes have strokeWidth='2' and opacity='0.7'
|
|
111
|
+
active_active_stroke_2: activeSpokes.filter(s => s.active === 'true').every(s => s.strokeWidth === '2'),
|
|
112
|
+
active_active_opacity_07: activeSpokes.filter(s => s.active === 'true').every(s => s.opacityAttr === '0.7'),
|
|
113
|
+
// Inactive spokes still at 1/0.45
|
|
114
|
+
active_inactive_stable: activeSpokes.filter(s => s.active === 'false').every(s => s.strokeWidth === '1' && s.opacityAttr === '0.45'),
|
|
115
|
+
};
|
|
116
|
+
const ok = Object.values(results).every(Boolean);
|
|
117
|
+
console.log(`${ok ? '✅' : '❌'} hub spoke ease:`, JSON.stringify(results),
|
|
118
|
+
'\n idle: ', idleSpokes.map(s => ({ a: s.active, w: s.strokeWidth, o: s.opacityAttr })),
|
|
119
|
+
'\n active:', activeSpokes.map(s => ({ a: s.active, w: s.strokeWidth, o: s.opacityAttr })));
|
|
120
|
+
process.exit(ok ? 0 : 1);
|