@sleep2agi/agent-network-dashboard 0.4.6-preview.32 → 0.4.6-preview.321
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/07lsi~s-c0wvh.css +2 -0
- package/.next/static/chunks/08kf-.bgs10ze.js +1 -0
- package/.next/static/chunks/08s10wueoqydl.js +1 -0
- package/.next/static/chunks/0_l-j6k-ic81v.js +4 -0
- package/.next/static/chunks/0ggj5ummw2a84.js +7 -0
- package/.next/static/chunks/0glmrdj9112tc.js +7 -0
- package/.next/static/chunks/0rxrez_cjn.eh.js +1 -0
- package/.next/static/chunks/0wlu_nyra0im0.js +1 -0
- package/.next/static/chunks/0x8x.29hkju5a.js +1 -0
- package/.next/static/chunks/174re5ar~kxne.js +1 -0
- package/.next/trace +2 -2
- package/.next/trace-build +1 -1
- package/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 +6091 -262
- 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-logo-transition-test.mjs +93 -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-focus-ring-unify-test.mjs +100 -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-hint-tracking-test.mjs +84 -0
- package/scripts/topo-empty-state-breath-test.mjs +150 -0
- package/scripts/topo-empty-state-crossfade-test.mjs +130 -0
- package/scripts/topo-empty-state-recenter-test.mjs +107 -0
- package/scripts/topo-empty-subhint-tracking-test.mjs +87 -0
- package/scripts/topo-endpoint-ring-fade-test.mjs +132 -0
- package/scripts/topo-endpoint-ring-test.mjs +93 -0
- package/scripts/topo-endpoint-ring-thicken-test.mjs +112 -0
- package/scripts/topo-esc-clears-pin-test.mjs +98 -0
- package/scripts/topo-filter-pill-aliases-test.mjs +121 -0
- package/scripts/topo-filter-pill-body-click-test.mjs +112 -0
- package/scripts/topo-filter-pill-count-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-kicker-weight-test.mjs +98 -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-offline-label-simplify-test.mjs +85 -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-alias-chat-pin-test.mjs +95 -0
- package/scripts/topo-node-hover-lift-test.mjs +85 -0
- package/scripts/topo-node-label-card-elevation-test.mjs +157 -0
- package/scripts/topo-node-label-card-stroke-test.mjs +135 -0
- package/scripts/topo-node-stroke-transition-test.mjs +103 -0
- package/scripts/topo-node-text-fill-transition-test.mjs +119 -0
- package/scripts/topo-node-title-peers-test.mjs +107 -0
- package/scripts/topo-node-title-test.mjs +101 -0
- package/scripts/topo-nodesize-active-hover-test.mjs +109 -0
- package/scripts/topo-nodesize-crossfade-test.mjs +141 -0
- package/scripts/topo-online-chip-nav-test.mjs +143 -0
- package/scripts/topo-orbit-particles-retired-test.mjs +91 -0
- package/scripts/topo-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-panel-title-tracking-test.mjs +78 -0
- package/scripts/topo-particle-stagger-test.mjs +82 -0
- package/scripts/topo-pin-intersection-color-ease-test.mjs +111 -0
- package/scripts/topo-pin-intersection-empty-test.mjs +129 -0
- package/scripts/topo-pin-intersection-tabular-test.mjs +96 -0
- package/scripts/topo-pin-intersection-test.mjs +121 -0
- package/scripts/topo-pin-intersection-warning-crossfade-test.mjs +107 -0
- package/scripts/topo-pin-mirror-transition-test.mjs +101 -0
- package/scripts/topo-pin-persistence-test.mjs +105 -0
- package/scripts/topo-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-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-guide-dashes-test.mjs +86 -0
- package/scripts/topo-tier-ring-fadein-test.mjs +107 -0
- package/scripts/topo-tier-ring-occupancy-test.mjs +87 -0
- package/scripts/topo-tier-ring-test.mjs +69 -0
- package/scripts/topo-tier-ring-tint-test.mjs +110 -0
- package/scripts/topo-tier-stagger-test.mjs +89 -0
- package/scripts/topo-title-block-tight-leading-test.mjs +95 -0
- package/scripts/topo-title-tracking-test.mjs +98 -0
- package/scripts/topo-titleblock-gap-test.mjs +86 -0
- package/scripts/topo-titleblock-margin-test.mjs +83 -0
- package/scripts/topo-toggle-inactive-cyan-hover-test.mjs +110 -0
- package/scripts/topo-top-rail-theme-ease-test.mjs +89 -0
- package/scripts/topo-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/02t5jr4shh.hy.js +0 -1
- package/.next/static/chunks/08b1xx89c0ts9.js +0 -1
- package/.next/static/chunks/09nd.t_hd.y6t.css +0 -2
- package/.next/static/chunks/0_8snedeata9k.js +0 -1
- package/.next/static/chunks/0_qfg5s5uzs7..js +0 -7
- package/.next/static/chunks/0elalb9n_.~di.js +0 -1
- package/.next/static/chunks/0h_~v6f9o~_in.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/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/{QkCLPQNNPLHlzKVvmAInn → 95X2ICTd2SB5ohx7R2QN2}/_buildManifest.js +0 -0
- /package/.next/static/{QkCLPQNNPLHlzKVvmAInn → 95X2ICTd2SB5ohx7R2QN2}/_clientMiddlewareManifest.js +0 -0
- /package/.next/static/{QkCLPQNNPLHlzKVvmAInn → 95X2ICTd2SB5ohx7R2QN2}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/* Round 90 verification: Cmd+K palette "Clear topology filters" also
|
|
2
|
+
* releases the R88 pinnedVendor (the R69 implementation only knew
|
|
3
|
+
* about status + group). Plus the new granular "Clear topology vendor
|
|
4
|
+
* filter" command releases just vendor without disturbing status or
|
|
5
|
+
* group pins.
|
|
6
|
+
*
|
|
7
|
+
* Drive via direct CustomEvent dispatch (avoids fuzzy-match flake —
|
|
8
|
+
* same approach as the R82 chip-pin-mirror test). Verifies both the
|
|
9
|
+
* TopoGraph listener branch (state mutation) and the in-memory
|
|
10
|
+
* sessionStorage cleanup.
|
|
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: 1200 } });
|
|
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
|
+
sessionStorage.removeItem('anet-topo-pinned-status');
|
|
25
|
+
sessionStorage.removeItem('anet-topo-pinned-group');
|
|
26
|
+
sessionStorage.removeItem('anet-topo-pinned-vendor');
|
|
27
|
+
} catch {}
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
const fresh = new Date(Date.now() - 60 * 1000).toISOString();
|
|
31
|
+
await ctx.route('**/api/hub/status*', async (route) => {
|
|
32
|
+
const r = await route.fetch();
|
|
33
|
+
const b = await r.json();
|
|
34
|
+
const nid = (b.sessions || [])[0]?.network_id || 'default';
|
|
35
|
+
const mk = (alias, status, model) => ({
|
|
36
|
+
alias, status, model, runtime: 'cli-claude-code',
|
|
37
|
+
network_id: nid, project_dir: null,
|
|
38
|
+
created_at: fresh, updated_at: fresh, last_seen_at: fresh,
|
|
39
|
+
});
|
|
40
|
+
const sessions = [
|
|
41
|
+
mk('alpha', 'working', 'claude-opus-4'),
|
|
42
|
+
mk('beta', 'idle', 'gpt-5'),
|
|
43
|
+
mk('gamma', 'idle', 'claude-opus-4'),
|
|
44
|
+
];
|
|
45
|
+
await route.fulfill({ response: r, json: { ...b, sessions } });
|
|
46
|
+
});
|
|
47
|
+
await ctx.route('**/api/hub/messages*', (route) => route.fulfill({ json: { messages: [] } }));
|
|
48
|
+
await ctx.route('**/api/hub/tasks*', (route) => route.fulfill({ json: { tasks: [] } }));
|
|
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.waitForTimeout(400);
|
|
53
|
+
|
|
54
|
+
const pills = () => page.evaluate(() => {
|
|
55
|
+
const all = document.querySelectorAll('[data-active-filter]');
|
|
56
|
+
return [...all].map(p => p.getAttribute('data-active-filter'));
|
|
57
|
+
});
|
|
58
|
+
const storage = () => page.evaluate(() => ({
|
|
59
|
+
status: sessionStorage.getItem('anet-topo-pinned-status'),
|
|
60
|
+
group: sessionStorage.getItem('anet-topo-pinned-group'),
|
|
61
|
+
vendor: sessionStorage.getItem('anet-topo-pinned-vendor'),
|
|
62
|
+
}));
|
|
63
|
+
|
|
64
|
+
// Helper: dispatch a topo-pin event from the page side.
|
|
65
|
+
const pin = async (kind, value) => {
|
|
66
|
+
await page.evaluate(({ kind, value }) => {
|
|
67
|
+
if (kind === 'status') sessionStorage.setItem('anet-topo-pinned-status', value);
|
|
68
|
+
if (kind === 'group') sessionStorage.setItem('anet-topo-pinned-group', value);
|
|
69
|
+
window.dispatchEvent(new CustomEvent('anet:topo-pin', { detail: { kind, value } }));
|
|
70
|
+
}, { kind, value });
|
|
71
|
+
await page.waitForTimeout(200);
|
|
72
|
+
};
|
|
73
|
+
// Pin vendor via the actual UI letter click (no CustomEvent for that
|
|
74
|
+
// flow yet — palette doesn't surface per-vendor pin actions).
|
|
75
|
+
const pinVendor = async (initial) => {
|
|
76
|
+
await page.locator(`[data-vendor-letter="${initial}"]`).click();
|
|
77
|
+
await page.mouse.move(10, 10);
|
|
78
|
+
await page.waitForTimeout(200);
|
|
79
|
+
};
|
|
80
|
+
const clearAll = async () => {
|
|
81
|
+
await page.evaluate(() => {
|
|
82
|
+
sessionStorage.removeItem('anet-topo-pinned-status');
|
|
83
|
+
sessionStorage.removeItem('anet-topo-pinned-group');
|
|
84
|
+
sessionStorage.removeItem('anet-topo-pinned-vendor');
|
|
85
|
+
window.dispatchEvent(new CustomEvent('anet:topo-pin', { detail: { kind: 'clear' } }));
|
|
86
|
+
});
|
|
87
|
+
await page.waitForTimeout(250);
|
|
88
|
+
};
|
|
89
|
+
const clearVendor = async () => {
|
|
90
|
+
await page.evaluate(() => {
|
|
91
|
+
sessionStorage.removeItem('anet-topo-pinned-vendor');
|
|
92
|
+
window.dispatchEvent(new CustomEvent('anet:topo-pin', { detail: { kind: 'clear-vendor' } }));
|
|
93
|
+
});
|
|
94
|
+
await page.waitForTimeout(250);
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
// === Test 1: clear-all now also clears vendor (the R90 bug fix). ===
|
|
98
|
+
await pin('status', 'working');
|
|
99
|
+
await pinVendor('A');
|
|
100
|
+
const afterPinBoth = { pills: await pills(), storage: await storage() };
|
|
101
|
+
|
|
102
|
+
await clearAll();
|
|
103
|
+
const afterClearAll = { pills: await pills(), storage: await storage() };
|
|
104
|
+
|
|
105
|
+
// === Test 2: granular clear-vendor leaves status + group untouched. ===
|
|
106
|
+
await pin('status', 'working');
|
|
107
|
+
await pinVendor('A');
|
|
108
|
+
const beforeGranular = { pills: await pills(), storage: await storage() };
|
|
109
|
+
|
|
110
|
+
await clearVendor();
|
|
111
|
+
const afterClearVendor = { pills: await pills(), storage: await storage() };
|
|
112
|
+
|
|
113
|
+
await browser.close();
|
|
114
|
+
|
|
115
|
+
const sameSet = (a, b) => a.length === b.length && a.every(x => b.includes(x));
|
|
116
|
+
const results = {
|
|
117
|
+
pinBoth_threePills: sameSet(afterPinBoth.pills, ['status', 'vendor']),
|
|
118
|
+
pinBoth_storageBoth: afterPinBoth.storage.status === 'working' && afterPinBoth.storage.vendor === 'A',
|
|
119
|
+
clearAll_noPills: afterClearAll.pills.length === 0,
|
|
120
|
+
clearAll_storageAllNull: afterClearAll.storage.status === null && afterClearAll.storage.group === null && afterClearAll.storage.vendor === null,
|
|
121
|
+
granular_threePills: sameSet(beforeGranular.pills, ['status', 'vendor']),
|
|
122
|
+
clearVendor_keepsStatus: afterClearVendor.pills.includes('status'),
|
|
123
|
+
clearVendor_dropsVendor: !afterClearVendor.pills.includes('vendor'),
|
|
124
|
+
clearVendor_storageStatusKept: afterClearVendor.storage.status === 'working',
|
|
125
|
+
clearVendor_storageVendorCleared: afterClearVendor.storage.vendor === null,
|
|
126
|
+
};
|
|
127
|
+
const ok = Object.values(results).every(Boolean);
|
|
128
|
+
console.log(`${ok ? '✅' : '❌'} cmdk vendor clear:`, JSON.stringify(results),
|
|
129
|
+
`\n afterPinBoth=`, afterPinBoth,
|
|
130
|
+
`\n afterClearAll=`, afterClearAll,
|
|
131
|
+
`\n beforeGranular=`, beforeGranular,
|
|
132
|
+
`\n afterClearVendor=`, afterClearVendor);
|
|
133
|
+
process.exit(ok ? 0 : 1);
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/* Round 108 verification: Cmd+K palette can pin a vendor filter via
|
|
2
|
+
* three new static actions ("Pin topology filter: Anthropic" /
|
|
3
|
+
* OpenAI / 书生). TopoGraph's R69 listener handles kind='vendor' to
|
|
4
|
+
* setPinnedVendor. The R88 stale-purge cleans up if the vendor isn't
|
|
5
|
+
* in the fleet.
|
|
6
|
+
*
|
|
7
|
+
* Drives via direct CustomEvent dispatch (same deterministic path
|
|
8
|
+
* R82/R90 tests use — fuzzy-match-free). Verifies pin sticks, vendor
|
|
9
|
+
* pill renders, storage persists, and Esc / clear-all release.
|
|
10
|
+
*/
|
|
11
|
+
import { chromium } from 'playwright';
|
|
12
|
+
import { readFileSync } from 'node:fs';
|
|
13
|
+
|
|
14
|
+
const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
|
|
15
|
+
const browser = await chromium.launch({ headless: true });
|
|
16
|
+
const ctx = await browser.newContext({ viewport: { width: 1400, height: 1200 } });
|
|
17
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
18
|
+
await ctx.addInitScript(() => {
|
|
19
|
+
try {
|
|
20
|
+
localStorage.setItem('anet-theme', 'cyber');
|
|
21
|
+
localStorage.setItem('anet-topo-layout', 'ring');
|
|
22
|
+
sessionStorage.setItem('anet_v3_auth', '1');
|
|
23
|
+
sessionStorage.removeItem('anet-topo-pinned-status');
|
|
24
|
+
sessionStorage.removeItem('anet-topo-pinned-group');
|
|
25
|
+
sessionStorage.removeItem('anet-topo-pinned-vendor');
|
|
26
|
+
} catch {}
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
const fresh = new Date(Date.now() - 60 * 1000).toISOString();
|
|
30
|
+
await ctx.route('**/api/hub/status*', async (route) => {
|
|
31
|
+
const r = await route.fetch();
|
|
32
|
+
const b = await r.json();
|
|
33
|
+
const nid = (b.sessions || [])[0]?.network_id || 'default';
|
|
34
|
+
const mk = (alias, model) => ({
|
|
35
|
+
alias, status: 'idle', model, runtime: 'cli-claude-code',
|
|
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', 'claude-opus-4'), // A (Anthropic)
|
|
41
|
+
mk('beta', 'gpt-5'), // O (OpenAI)
|
|
42
|
+
mk('gamma', 'claude-opus-4'), // A
|
|
43
|
+
] } });
|
|
44
|
+
});
|
|
45
|
+
await ctx.route('**/api/hub/messages*', (route) => route.fulfill({ json: { messages: [] } }));
|
|
46
|
+
await ctx.route('**/api/hub/tasks*', (route) => route.fulfill({ json: { tasks: [] } }));
|
|
47
|
+
const page = await ctx.newPage();
|
|
48
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
|
|
49
|
+
await page.waitForFunction(() => document.querySelectorAll('g[data-node]').length === 3, { timeout: 30000 });
|
|
50
|
+
await page.waitForTimeout(400);
|
|
51
|
+
|
|
52
|
+
const pillCount = () => page.locator('[data-active-filter="vendor"]').count();
|
|
53
|
+
const storage = () => page.evaluate(() => sessionStorage.getItem('anet-topo-pinned-vendor'));
|
|
54
|
+
const opacities = () => page.evaluate(() => {
|
|
55
|
+
const o = {};
|
|
56
|
+
for (const a of ['alpha', 'beta', 'gamma']) {
|
|
57
|
+
const g = document.querySelector(`g[data-node="${a}"]`);
|
|
58
|
+
o[a] = g ? +(g.style.opacity || '1') : null;
|
|
59
|
+
}
|
|
60
|
+
return o;
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
// Initial state — no pin.
|
|
64
|
+
const beforePill = await pillCount();
|
|
65
|
+
const beforeStorage = await storage();
|
|
66
|
+
|
|
67
|
+
// Pin A via R108 palette action's CustomEvent.
|
|
68
|
+
await page.evaluate(() => {
|
|
69
|
+
sessionStorage.setItem('anet-topo-pinned-vendor', 'A');
|
|
70
|
+
window.dispatchEvent(new CustomEvent('anet:topo-pin', { detail: { kind: 'vendor', value: 'A' } }));
|
|
71
|
+
});
|
|
72
|
+
await page.waitForTimeout(300);
|
|
73
|
+
const afterPinA_ops = await opacities();
|
|
74
|
+
const afterPinA_pill = await pillCount();
|
|
75
|
+
const afterPinA_storage = await storage();
|
|
76
|
+
|
|
77
|
+
// Esc → clear pin.
|
|
78
|
+
await page.keyboard.press('Escape');
|
|
79
|
+
await page.waitForTimeout(300);
|
|
80
|
+
const afterEsc_pill = await pillCount();
|
|
81
|
+
const afterEsc_storage = await storage();
|
|
82
|
+
|
|
83
|
+
await browser.close();
|
|
84
|
+
|
|
85
|
+
const bright = (v) => v != null && v >= 0.55;
|
|
86
|
+
const dim = (v) => v != null && v < 0.4;
|
|
87
|
+
const results = {
|
|
88
|
+
before_noPill: beforePill === 0,
|
|
89
|
+
before_noStorage: beforeStorage === null,
|
|
90
|
+
pinA_pillShown: afterPinA_pill === 1,
|
|
91
|
+
pinA_storageWritten: afterPinA_storage === 'A',
|
|
92
|
+
pinA_keepsClaudes: bright(afterPinA_ops.alpha) && bright(afterPinA_ops.gamma),
|
|
93
|
+
pinA_dimsGPT: dim(afterPinA_ops.beta),
|
|
94
|
+
esc_clearsPill: afterEsc_pill === 0,
|
|
95
|
+
esc_clearsStorage: afterEsc_storage === null,
|
|
96
|
+
};
|
|
97
|
+
const ok = Object.values(results).every(Boolean);
|
|
98
|
+
console.log(`${ok ? '✅' : '❌'} cmdk vendor pin:`, JSON.stringify(results),
|
|
99
|
+
`\n afterPinA_ops=`, afterPinA_ops,
|
|
100
|
+
`\n afterPinA_pill=`, afterPinA_pill,
|
|
101
|
+
`\n afterPinA_storage=`, afterPinA_storage,
|
|
102
|
+
`\n afterEsc_pill=`, afterEsc_pill);
|
|
103
|
+
process.exit(ok ? 0 : 1);
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/* Round 262 verification: corner-radius vocabulary unified across the
|
|
2
|
+
* canvas chrome — panels drop rx="10" → rx="8" to match the wrapper's
|
|
3
|
+
* rounded-lg (8px).
|
|
4
|
+
*
|
|
5
|
+
* Pre-R262 corner-radius hierarchy:
|
|
6
|
+
* Group label rect: rx="4" ← tiny chip
|
|
7
|
+
* Node label card: rx="6" ← small card
|
|
8
|
+
* Recent-signal panel: rx="10" ← panel chrome ← MISMATCHED
|
|
9
|
+
* Legend panel: rx="10" ← panel chrome ← MISMATCHED
|
|
10
|
+
* Canvas wrapper: rounded-lg (8 px CSS)
|
|
11
|
+
* ⇒ Panels at 10 px more rounded than the wrapper at 8 px.
|
|
12
|
+
*
|
|
13
|
+
* Post-R262:
|
|
14
|
+
* Group label: rx=4
|
|
15
|
+
* Node label card:rx=6
|
|
16
|
+
* Panels: rx=8 ← matches wrapper
|
|
17
|
+
* Canvas wrapper: rounded-lg (8 px)
|
|
18
|
+
* ⇒ Clean 4→6→8 progression. Panel corners now flush with wrapper
|
|
19
|
+
* corners, not exceeding them.
|
|
20
|
+
*
|
|
21
|
+
* Test scope:
|
|
22
|
+
* 1. Recent-signal panel rect rx === "8".
|
|
23
|
+
* 2. Legend panel rect rx === "8".
|
|
24
|
+
* 3. Node label card rect rx === "6" (unchanged regression).
|
|
25
|
+
* 4. Group label rect rx === "4" (unchanged regression).
|
|
26
|
+
* 5. Canvas wrapper computed border-top-left-radius === 8 px.
|
|
27
|
+
*/
|
|
28
|
+
import { chromium } from 'playwright';
|
|
29
|
+
import { readFileSync } from 'node:fs';
|
|
30
|
+
|
|
31
|
+
const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
|
|
32
|
+
const browser = await chromium.launch({ headless: true });
|
|
33
|
+
const ctx = await browser.newContext({ viewport: { width: 1500, height: 1500 } });
|
|
34
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
35
|
+
await ctx.addInitScript(() => {
|
|
36
|
+
try {
|
|
37
|
+
localStorage.setItem('anet-theme', 'cyber');
|
|
38
|
+
sessionStorage.setItem('anet_v3_auth', '1');
|
|
39
|
+
// Grid layout exposes the group label rect (rx=4)
|
|
40
|
+
localStorage.setItem('anet-topo-layout', 'grid');
|
|
41
|
+
} catch {}
|
|
42
|
+
});
|
|
43
|
+
const fresh = new Date(Date.now() - 60 * 1000).toISOString();
|
|
44
|
+
await ctx.route('**/api/hub/status*', async (route) => {
|
|
45
|
+
const r = await route.fetch();
|
|
46
|
+
const b = await r.json();
|
|
47
|
+
const nid = (b.sessions || [])[0]?.network_id || 'default';
|
|
48
|
+
const mk = (alias) => ({
|
|
49
|
+
alias, status: 'working', model: 'claude-opus-4', runtime: 'claude-code-cli',
|
|
50
|
+
network_id: nid, project_dir: null,
|
|
51
|
+
created_at: fresh, updated_at: fresh, last_seen_at: fresh,
|
|
52
|
+
});
|
|
53
|
+
// Use a group prefix so the prefix-group boundary box renders + its
|
|
54
|
+
// group label rect with rx=4 is in the DOM for regression check.
|
|
55
|
+
await route.fulfill({ response: r, json: { ...b, sessions: [
|
|
56
|
+
mk('alpha-1'), mk('alpha-2'), mk('alpha-3'), mk('alpha-4'),
|
|
57
|
+
] } });
|
|
58
|
+
});
|
|
59
|
+
await ctx.route('**/api/hub/messages*', (r) => r.fulfill({ json: { messages: [] } }));
|
|
60
|
+
await ctx.route('**/api/hub/tasks*', (r) => r.fulfill({ json: { tasks: [] } }));
|
|
61
|
+
|
|
62
|
+
const page = await ctx.newPage();
|
|
63
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
|
|
64
|
+
await page.waitForFunction(() => document.querySelectorAll('g[data-node]').length === 4, { timeout: 30000 });
|
|
65
|
+
await page.waitForSelector('[data-topo-panel="recent"]', { timeout: 10000 });
|
|
66
|
+
await page.waitForSelector('[data-topo-panel="legend"]', { timeout: 10000 });
|
|
67
|
+
await page.waitForSelector('[data-node-label-card]', { timeout: 10000 });
|
|
68
|
+
await page.waitForSelector('[data-group-label-tinted]', { timeout: 10000 });
|
|
69
|
+
await page.waitForSelector('[data-topo-wrapper]', { timeout: 10000 });
|
|
70
|
+
await page.waitForTimeout(300);
|
|
71
|
+
|
|
72
|
+
const probe = await page.evaluate(() => {
|
|
73
|
+
const recentG = document.querySelector('[data-topo-panel="recent"]');
|
|
74
|
+
const legendG = document.querySelector('[data-topo-panel="legend"]');
|
|
75
|
+
const recentRx = recentG?.querySelector('rect')?.getAttribute('rx');
|
|
76
|
+
const legendRx = legendG?.querySelector('rect')?.getAttribute('rx');
|
|
77
|
+
// Node label card rect — query any one of them
|
|
78
|
+
const cardRect = document.querySelector('[data-node-label-card]');
|
|
79
|
+
const cardRx = cardRect?.getAttribute('rx');
|
|
80
|
+
// Group label rect — the bg tint rect inside the group-label-hit group
|
|
81
|
+
const groupTintRect = document.querySelector('[data-group-label-tinted]');
|
|
82
|
+
const groupTintRx = groupTintRect?.getAttribute('rx');
|
|
83
|
+
// Wrapper CSS corner radius
|
|
84
|
+
const wrapper = document.querySelector('[data-topo-wrapper]');
|
|
85
|
+
const wrapperBorderRadius = wrapper ? window.getComputedStyle(wrapper).borderTopLeftRadius : null;
|
|
86
|
+
return {
|
|
87
|
+
recentRx, legendRx, cardRx, groupTintRx, wrapperBorderRadius,
|
|
88
|
+
};
|
|
89
|
+
});
|
|
90
|
+
await browser.close();
|
|
91
|
+
|
|
92
|
+
const results = {
|
|
93
|
+
recent_panel_rx_8: probe.recentRx === '8',
|
|
94
|
+
legend_panel_rx_8: probe.legendRx === '8',
|
|
95
|
+
node_label_card_rx_6: probe.cardRx === '6',
|
|
96
|
+
group_label_tint_rx_4: probe.groupTintRx === '4',
|
|
97
|
+
wrapper_border_radius_8px: probe.wrapperBorderRadius === '8px',
|
|
98
|
+
};
|
|
99
|
+
const ok = Object.values(results).every(Boolean);
|
|
100
|
+
console.log(`${ok ? '✅' : '❌'} corner-radius unify:`, JSON.stringify(results),
|
|
101
|
+
'\n rxs: recent', probe.recentRx, '· legend', probe.legendRx, '· card', probe.cardRx, '· group-tint', probe.groupTintRx,
|
|
102
|
+
'\n wrapper border-radius:', probe.wrapperBorderRadius);
|
|
103
|
+
process.exit(ok ? 0 : 1);
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/* Round 33 verification: hover tooltip carries `cwd: <project_dir>` on a
|
|
2
|
+
* second line when reported; falls back to the identity-only line
|
|
3
|
+
* otherwise; no `cwd:` line for nodes without project_dir. */
|
|
4
|
+
import { chromium } from 'playwright';
|
|
5
|
+
import { readFileSync } from 'node:fs';
|
|
6
|
+
|
|
7
|
+
const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
|
|
8
|
+
const browser = await chromium.launch({ headless: true });
|
|
9
|
+
const ctx = await browser.newContext({ viewport: { width: 1280, height: 900 } });
|
|
10
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
11
|
+
await ctx.addInitScript(() => {
|
|
12
|
+
try {
|
|
13
|
+
localStorage.setItem('anet-theme', 'cyber');
|
|
14
|
+
localStorage.setItem('anet-topo-layout', 'grid');
|
|
15
|
+
sessionStorage.setItem('anet_v3_auth', '1');
|
|
16
|
+
} catch {}
|
|
17
|
+
});
|
|
18
|
+
const fresh = new Date(Date.now() - 60 * 1000).toISOString();
|
|
19
|
+
await ctx.route('**/api/hub/status*', async (route) => {
|
|
20
|
+
const r = await route.fetch();
|
|
21
|
+
const b = await r.json();
|
|
22
|
+
const nid = (b.sessions || [])[0]?.network_id || 'default';
|
|
23
|
+
const sessions = [
|
|
24
|
+
{
|
|
25
|
+
alias: 'full', status: 'idle', network_id: nid,
|
|
26
|
+
project_dir: '/home/vansin/agent-orchestra',
|
|
27
|
+
model: 'claude-opus-4-7', runtime: 'cli-claude-code',
|
|
28
|
+
created_at: fresh, updated_at: fresh, last_seen_at: fresh,
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
alias: 'cwdOnly', status: 'idle', network_id: nid,
|
|
32
|
+
project_dir: '/home/vansin/some-project',
|
|
33
|
+
model: null, runtime: null,
|
|
34
|
+
created_at: fresh, updated_at: fresh, last_seen_at: fresh,
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
alias: 'bare', status: 'idle', network_id: nid,
|
|
38
|
+
project_dir: null, model: null, runtime: null,
|
|
39
|
+
created_at: fresh, updated_at: fresh, last_seen_at: fresh,
|
|
40
|
+
},
|
|
41
|
+
];
|
|
42
|
+
await route.fulfill({ response: r, json: { ...b, sessions } });
|
|
43
|
+
});
|
|
44
|
+
await ctx.route('**/api/hub/tasks*', (route) => route.fulfill({ json: { tasks: [] } }));
|
|
45
|
+
const page = await ctx.newPage();
|
|
46
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
|
|
47
|
+
await page.waitForFunction(() => document.querySelectorAll('g[data-node]').length === 3, { timeout: 30000 });
|
|
48
|
+
await page.waitForTimeout(400);
|
|
49
|
+
|
|
50
|
+
const titleOf = alias => page.$eval(`g[data-node="${alias}"] title`, el => el.textContent);
|
|
51
|
+
const full = await titleOf('full');
|
|
52
|
+
const cwdOnly = await titleOf('cwdOnly');
|
|
53
|
+
const bare = await titleOf('bare');
|
|
54
|
+
|
|
55
|
+
await browser.close();
|
|
56
|
+
const results = {
|
|
57
|
+
fullHasIdentityAndCwd: /claude-opus-4-7/.test(full) && /cwd: \/home\/vansin\/agent-orchestra/.test(full) && full.includes('\n'),
|
|
58
|
+
cwdOnlyShowsAliasAndCwd: cwdOnly.startsWith('cwdOnly') && /cwd: \/home\/vansin\/some-project/.test(cwdOnly),
|
|
59
|
+
bareShowsAliasOnly: bare === 'bare',
|
|
60
|
+
};
|
|
61
|
+
const ok = Object.values(results).every(Boolean);
|
|
62
|
+
console.log(`${ok ? '✅' : '❌'} cwd tooltip:`, JSON.stringify(results),
|
|
63
|
+
`\n full=${JSON.stringify(full)}\n cwdOnly=${JSON.stringify(cwdOnly)}\n bare=${JSON.stringify(bare)}`);
|
|
64
|
+
process.exit(ok ? 0 : 1);
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/* Round 41 verification: double-clicking empty canvas resets view to
|
|
2
|
+
* {zoom:1, x:0, y:0}. Double-clicking a node does NOT reset (the
|
|
3
|
+
* node's own onClick wins, and resetView should not fire). */
|
|
4
|
+
import { chromium } from 'playwright';
|
|
5
|
+
import { readFileSync } from 'node:fs';
|
|
6
|
+
|
|
7
|
+
const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
|
|
8
|
+
const browser = await chromium.launch({ headless: true });
|
|
9
|
+
const ctx = await browser.newContext({ viewport: { width: 1280, height: 1600 } });
|
|
10
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
11
|
+
await ctx.addInitScript(() => {
|
|
12
|
+
try {
|
|
13
|
+
localStorage.setItem('anet-theme', 'cyber');
|
|
14
|
+
localStorage.setItem('anet-topo-layout', 'grid');
|
|
15
|
+
localStorage.setItem('anet-topo-view', JSON.stringify({ zoom: 1, x: 0, y: 0 }));
|
|
16
|
+
sessionStorage.setItem('anet_v3_auth', '1');
|
|
17
|
+
} catch {}
|
|
18
|
+
});
|
|
19
|
+
const fresh = new Date(Date.now() - 60 * 1000).toISOString();
|
|
20
|
+
await ctx.route('**/api/hub/status*', async (route) => {
|
|
21
|
+
const r = await route.fetch();
|
|
22
|
+
const b = await r.json();
|
|
23
|
+
const nid = (b.sessions || [])[0]?.network_id || 'default';
|
|
24
|
+
const sessions = ['a', 'b'].map(a => ({
|
|
25
|
+
alias: a, status: 'idle', network_id: nid, project_dir: null,
|
|
26
|
+
created_at: fresh, updated_at: fresh, last_seen_at: fresh,
|
|
27
|
+
}));
|
|
28
|
+
await route.fulfill({ response: r, json: { ...b, sessions } });
|
|
29
|
+
});
|
|
30
|
+
await ctx.route('**/api/hub/tasks*', (route) => route.fulfill({ json: { tasks: [] } }));
|
|
31
|
+
const page = await ctx.newPage();
|
|
32
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
|
|
33
|
+
await page.waitForSelector('svg[viewBox="0 0 1000 680"]', { timeout: 30000 });
|
|
34
|
+
await page.waitForTimeout(500);
|
|
35
|
+
|
|
36
|
+
const readZoom = () => page.evaluate(() => {
|
|
37
|
+
const span = document.querySelector('button[aria-label="Zoom in"]').parentElement.querySelector('span[title*="zoom level"]');
|
|
38
|
+
return +span.textContent.replace('%', '');
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
// Zoom in a couple times via keyboard, then dbl-click empty canvas → expect reset to 100%.
|
|
42
|
+
await page.keyboard.press('=');
|
|
43
|
+
await page.keyboard.press('=');
|
|
44
|
+
await page.waitForTimeout(120);
|
|
45
|
+
const zoomedIn = await readZoom();
|
|
46
|
+
|
|
47
|
+
// Find empty-canvas coords: top-left area of the SVG, well outside node positions.
|
|
48
|
+
const box = await page.$eval('svg[viewBox="0 0 1000 680"]', el => el.getBoundingClientRect());
|
|
49
|
+
// y=0.35 is below the top-overlay panels (which sit at y<100 inside the SVG)
|
|
50
|
+
const emptyX = box.x + box.width * 0.20;
|
|
51
|
+
const emptyY = box.y + box.height * 0.40;
|
|
52
|
+
await page.mouse.dblclick(emptyX, emptyY);
|
|
53
|
+
await page.waitForTimeout(200);
|
|
54
|
+
const afterEmptyDbl = await readZoom();
|
|
55
|
+
|
|
56
|
+
// Now zoom in again and dbl-click a node — view should NOT reset.
|
|
57
|
+
await page.keyboard.press('=');
|
|
58
|
+
await page.keyboard.press('=');
|
|
59
|
+
await page.waitForTimeout(120);
|
|
60
|
+
const zoomedIn2 = await readZoom();
|
|
61
|
+
await page.locator('g[data-node="a"]').dblclick().catch(() => {});
|
|
62
|
+
await page.waitForTimeout(200);
|
|
63
|
+
const afterNodeDbl = await readZoom();
|
|
64
|
+
|
|
65
|
+
await browser.close();
|
|
66
|
+
const results = {
|
|
67
|
+
zoomedInBeforeDbl: zoomedIn > 100,
|
|
68
|
+
emptyCanvasResets: afterEmptyDbl === 100,
|
|
69
|
+
nodeDoesNotReset: zoomedIn2 > 100 && afterNodeDbl === zoomedIn2,
|
|
70
|
+
};
|
|
71
|
+
const ok = Object.values(results).every(Boolean);
|
|
72
|
+
console.log(`${ok ? '✅' : '❌'} dblclick reset:`, JSON.stringify(results),
|
|
73
|
+
`\n zoomedIn=${zoomedIn} afterEmptyDbl=${afterEmptyDbl} zoomedIn2=${zoomedIn2} afterNodeDbl=${afterNodeDbl}`);
|
|
74
|
+
process.exit(ok ? 0 : 1);
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/* Round 212 verification: dense plain-text alias (used when
|
|
2
|
+
* denseLayout > 16 nodes) gains fill transition on status flip,
|
|
3
|
+
* extending R211's card-mode coverage to the dense fallback path
|
|
4
|
+
* users see most on busy fleets.
|
|
5
|
+
*
|
|
6
|
+
* Pre-R212 the dense alias snap-cut its fill on tier change while
|
|
7
|
+
* the status ring smoothly transitioned (R167). R212 inline
|
|
8
|
+
* transition combines R26 transform 200ms (hover lift) with R212
|
|
9
|
+
* fill 300ms (status flip ease).
|
|
10
|
+
*
|
|
11
|
+
* Test (cyber dark, 17 sessions in mixed status → denseLayout=true):
|
|
12
|
+
* 1. 17+ [data-node-dense-alias-text] elements present (one per
|
|
13
|
+
* session — confirms denseLayout path fired, not card mode).
|
|
14
|
+
* 2. Inline transition includes BOTH 'transform 200ms' AND
|
|
15
|
+
* 'fill 300ms' (composite spliced, group-hover lift unbroken).
|
|
16
|
+
* 3. group-hover:-translate-y-[1.5px] className preserved (lift
|
|
17
|
+
* still wires via CSS pseudo-class).
|
|
18
|
+
* 4. Mixed-status fleet renders different fills per tier (working
|
|
19
|
+
* green ≠ idle teal ≠ offline gray family).
|
|
20
|
+
* 5. paintOrder: stroke + stroke attribute preserved (R110 halo).
|
|
21
|
+
*/
|
|
22
|
+
import { chromium } from 'playwright';
|
|
23
|
+
import { readFileSync } from 'node:fs';
|
|
24
|
+
|
|
25
|
+
const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
|
|
26
|
+
const browser = await chromium.launch({ headless: true });
|
|
27
|
+
|
|
28
|
+
const ctx = await browser.newContext({ viewport: { width: 1500, height: 1500 } });
|
|
29
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
30
|
+
await ctx.addInitScript(() => {
|
|
31
|
+
try { localStorage.setItem('anet-theme', 'cyber'); sessionStorage.setItem('anet_v3_auth', '1'); } catch {}
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
const fresh = new Date(Date.now() - 60 * 1000).toISOString();
|
|
35
|
+
// Build 17 sessions: mostly working, a couple idle + offline so fill
|
|
36
|
+
// colors visibly differ.
|
|
37
|
+
const statuses = [
|
|
38
|
+
...Array(13).fill('working'),
|
|
39
|
+
'working', 'idle', 'idle', 'offline',
|
|
40
|
+
];
|
|
41
|
+
const aliases = statuses.map((_, i) => `node-${(i + 1).toString().padStart(2, '0')}`);
|
|
42
|
+
|
|
43
|
+
await ctx.route('**/api/hub/status*', async (route) => {
|
|
44
|
+
const r = await route.fetch();
|
|
45
|
+
const b = await r.json();
|
|
46
|
+
const nid = (b.sessions || [])[0]?.network_id || 'default';
|
|
47
|
+
await route.fulfill({ response: r, json: { ...b, sessions: aliases.map((alias, i) => ({
|
|
48
|
+
alias, status: statuses[i], model: 'claude-opus-4', runtime: 'claude-code-cli',
|
|
49
|
+
network_id: nid, project_dir: null,
|
|
50
|
+
created_at: fresh, updated_at: fresh, last_seen_at: fresh,
|
|
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
|
+
|
|
56
|
+
const page = await ctx.newPage();
|
|
57
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
|
|
58
|
+
await page.waitForFunction(() => document.querySelectorAll('g[data-node]').length === 17, { timeout: 30000 });
|
|
59
|
+
await page.waitForSelector('[data-node-dense-alias-text]', { timeout: 10000, state: 'attached' });
|
|
60
|
+
await page.waitForTimeout(300);
|
|
61
|
+
|
|
62
|
+
const probe = await page.evaluate(() => {
|
|
63
|
+
return [...document.querySelectorAll('[data-node-dense-alias-text]')].map(el => ({
|
|
64
|
+
alias: el.getAttribute('data-node-dense-alias-text'),
|
|
65
|
+
text: el.textContent,
|
|
66
|
+
fill: el.getAttribute('fill'),
|
|
67
|
+
className: el.getAttribute('class') || '',
|
|
68
|
+
transition: el.style.transition,
|
|
69
|
+
paintOrder: el.style.paintOrder,
|
|
70
|
+
stroke: el.getAttribute('stroke'),
|
|
71
|
+
}));
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
await browser.close();
|
|
75
|
+
|
|
76
|
+
const hasTransformT = (s) => /transform\s+(?:200ms|0\.2s)/.test(s || '');
|
|
77
|
+
const hasFillT = (s) => /fill\s+(?:300ms|0\.3s)/.test(s || '');
|
|
78
|
+
|
|
79
|
+
const workingAlias = probe.find(p => p.alias === 'node-01'); // first working
|
|
80
|
+
const idleAlias = probe.find(p => p.alias === 'node-15'); // first idle
|
|
81
|
+
const offlineAlias = probe.find(p => p.alias === 'node-17'); // offline
|
|
82
|
+
|
|
83
|
+
const results = {
|
|
84
|
+
dense_mode_fired: probe.length >= 17,
|
|
85
|
+
// R211 [data-node-alias-text] should NOT be present (card path skipped)
|
|
86
|
+
card_path_skipped: true, // implicit — if dense path fired, card path didn't render its texts
|
|
87
|
+
all_have_transition_fill: probe.every(p => hasFillT(p.transition)),
|
|
88
|
+
all_have_transition_trans: probe.every(p => hasTransformT(p.transition)),
|
|
89
|
+
all_keep_group_hover: probe.every(p => /group-hover:-translate-y/.test(p.className)),
|
|
90
|
+
all_have_paint_order: probe.every(p => p.paintOrder === 'stroke'),
|
|
91
|
+
all_have_halo_stroke: probe.every(p => !!p.stroke && p.stroke !== 'none'),
|
|
92
|
+
working_idle_fill_differs: workingAlias?.fill && idleAlias?.fill
|
|
93
|
+
&& workingAlias.fill !== idleAlias.fill,
|
|
94
|
+
working_offline_fill_differs: workingAlias?.fill && offlineAlias?.fill
|
|
95
|
+
&& workingAlias.fill !== offlineAlias.fill,
|
|
96
|
+
alias_text_rendered: workingAlias?.text === 'node-01',
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
// Verify card path skipped — no R211 card-mode texts at >16 nodes
|
|
100
|
+
const cardAliasCount = await chromium.launch({ headless: true }).then(async (b2) => {
|
|
101
|
+
const ctx2 = await b2.newContext();
|
|
102
|
+
await ctx2.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
103
|
+
await ctx2.addInitScript(() => {
|
|
104
|
+
try { localStorage.setItem('anet-theme', 'cyber'); sessionStorage.setItem('anet_v3_auth', '1'); } catch {}
|
|
105
|
+
});
|
|
106
|
+
await ctx2.route('**/api/hub/status*', async (route) => {
|
|
107
|
+
const r = await route.fetch();
|
|
108
|
+
const bj = await r.json();
|
|
109
|
+
const nid = (bj.sessions || [])[0]?.network_id || 'default';
|
|
110
|
+
await route.fulfill({ response: r, json: { ...bj, sessions: aliases.map((alias, i) => ({
|
|
111
|
+
alias, status: statuses[i], model: 'claude-opus-4', runtime: 'claude-code-cli',
|
|
112
|
+
network_id: nid, project_dir: null,
|
|
113
|
+
created_at: fresh, updated_at: fresh, last_seen_at: fresh,
|
|
114
|
+
})) } });
|
|
115
|
+
});
|
|
116
|
+
await ctx2.route('**/api/hub/messages*', (rr) => rr.fulfill({ json: { messages: [] } }));
|
|
117
|
+
await ctx2.route('**/api/hub/tasks*', (rr) => rr.fulfill({ json: { tasks: [] } }));
|
|
118
|
+
const p2 = await ctx2.newPage();
|
|
119
|
+
await p2.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
|
|
120
|
+
await p2.waitForFunction(() => document.querySelectorAll('g[data-node]').length === 17, { timeout: 30000 });
|
|
121
|
+
await p2.waitForTimeout(300);
|
|
122
|
+
const c = await p2.evaluate(() =>
|
|
123
|
+
document.querySelectorAll('[data-node-alias-text]').length);
|
|
124
|
+
await b2.close();
|
|
125
|
+
return c;
|
|
126
|
+
});
|
|
127
|
+
results.card_path_skipped = cardAliasCount === 0;
|
|
128
|
+
|
|
129
|
+
const ok = Object.values(results).every(Boolean);
|
|
130
|
+
console.log(`${ok ? '✅' : '❌'} dense alias fill transition:`, JSON.stringify(results),
|
|
131
|
+
`\n sample (first 3):`, probe.slice(0, 3),
|
|
132
|
+
`\n cardAliasCount:`, cardAliasCount);
|
|
133
|
+
process.exit(ok ? 0 : 1);
|