@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,98 @@
|
|
|
1
|
+
/* Round 286 verification: h2 title 'Command mesh' adopts tracking-
|
|
2
|
+
* tight (-0.025em) to pair with R285 kicker tracking-widest (0.1em).
|
|
3
|
+
* Wide eyebrow + tight headline is the editorial-pairing convention.
|
|
4
|
+
*
|
|
5
|
+
* At text-lg = 18px, tracking-tight resolves to:
|
|
6
|
+
* 18 * -0.025 = -0.45px letter-spacing
|
|
7
|
+
*
|
|
8
|
+
* Contract:
|
|
9
|
+
* - [data-topo-section-title] computed letter-spacing is negative
|
|
10
|
+
* and ~ -0.025em (= ~ -0.45px at 18px).
|
|
11
|
+
* - Text content still 'Command mesh'.
|
|
12
|
+
* - font-weight still 600 (font-semibold).
|
|
13
|
+
* - Kicker still tracking-widest (R285 regression).
|
|
14
|
+
* - R283 monogram stroke / R282 watermark intact.
|
|
15
|
+
*/
|
|
16
|
+
import { chromium } from 'playwright';
|
|
17
|
+
import { readFileSync } from 'node:fs';
|
|
18
|
+
|
|
19
|
+
const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
|
|
20
|
+
const browser = await chromium.launch({ headless: true });
|
|
21
|
+
const ctx = await browser.newContext({ viewport: { width: 1500, height: 1500 } });
|
|
22
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
23
|
+
await ctx.addInitScript(() => {
|
|
24
|
+
try { localStorage.setItem('anet-theme', 'cyber'); sessionStorage.setItem('anet_v3_auth', '1'); } catch {}
|
|
25
|
+
});
|
|
26
|
+
const fresh = new Date(Date.now() - 60 * 1000).toISOString();
|
|
27
|
+
await ctx.route('**/api/hub/status*', async (route) => {
|
|
28
|
+
const r = await route.fetch();
|
|
29
|
+
const b = await r.json();
|
|
30
|
+
const nid = (b.sessions || [])[0]?.network_id || 'default';
|
|
31
|
+
const mk = (alias, model) => ({
|
|
32
|
+
alias, status: 'working', model, runtime: 'claude-code-cli',
|
|
33
|
+
network_id: nid, project_dir: null,
|
|
34
|
+
created_at: fresh, updated_at: fresh, last_seen_at: fresh,
|
|
35
|
+
});
|
|
36
|
+
await route.fulfill({ response: r, json: { ...b, sessions: [
|
|
37
|
+
mk('alpha', 'claude-opus-4'),
|
|
38
|
+
mk('beta', 'gpt-4o'),
|
|
39
|
+
] } });
|
|
40
|
+
});
|
|
41
|
+
await ctx.route('**/api/hub/messages*', (r) => r.fulfill({ json: { messages: [] } }));
|
|
42
|
+
await ctx.route('**/api/hub/tasks*', (r) => r.fulfill({ json: { tasks: [] } }));
|
|
43
|
+
|
|
44
|
+
const page = await ctx.newPage();
|
|
45
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
|
|
46
|
+
await page.waitForSelector('[data-topo-section-title]', { timeout: 15000 });
|
|
47
|
+
await page.waitForSelector('[data-topo-brand-watermark]', { timeout: 10000 });
|
|
48
|
+
await page.waitForTimeout(300);
|
|
49
|
+
|
|
50
|
+
const probe = await page.evaluate(() => {
|
|
51
|
+
const title = document.querySelector('[data-topo-section-title]');
|
|
52
|
+
const kicker = document.querySelector('[data-topo-section-kicker]');
|
|
53
|
+
const tCs = title ? getComputedStyle(title) : null;
|
|
54
|
+
const kCs = kicker ? getComputedStyle(kicker) : null;
|
|
55
|
+
const alphaNode = document.querySelector('g[data-node="alpha"]');
|
|
56
|
+
const alphaCircles = alphaNode ? [...alphaNode.querySelectorAll('circle')] : [];
|
|
57
|
+
const alphaAvatarCircle = alphaCircles
|
|
58
|
+
.map(c => ({ r: +c.getAttribute('r') || 0, sw: c.getAttribute('stroke-width'), isBadge: c.hasAttribute('data-runtime-badge') }))
|
|
59
|
+
.filter(c => c.r > 0 && c.r < 18 && !c.isBadge)
|
|
60
|
+
.sort((a, b) => b.r - a.r)[0];
|
|
61
|
+
const watermark = document.querySelector('[data-topo-brand-watermark]');
|
|
62
|
+
return {
|
|
63
|
+
titleLetterSpacing: tCs?.letterSpacing ?? null,
|
|
64
|
+
titleFontSize: tCs?.fontSize ?? null,
|
|
65
|
+
titleFontWeight: tCs?.fontWeight ?? null,
|
|
66
|
+
titleText: title?.textContent ?? null,
|
|
67
|
+
kickerLetterSpacing: kCs?.letterSpacing ?? null,
|
|
68
|
+
kickerFontSize: kCs?.fontSize ?? null,
|
|
69
|
+
alphaAvatarStroke: alphaAvatarCircle?.sw ?? null,
|
|
70
|
+
watermarkPresent: watermark !== null,
|
|
71
|
+
};
|
|
72
|
+
});
|
|
73
|
+
await browser.close();
|
|
74
|
+
|
|
75
|
+
const tLs = parseFloat(probe.titleLetterSpacing) || 0;
|
|
76
|
+
const tFs = parseFloat(probe.titleFontSize) || 18;
|
|
77
|
+
const tLsPerEm = tFs ? tLs / tFs : 0;
|
|
78
|
+
|
|
79
|
+
const kLs = parseFloat(probe.kickerLetterSpacing) || 0;
|
|
80
|
+
const kFs = parseFloat(probe.kickerFontSize) || 12;
|
|
81
|
+
const kLsPerEm = kFs ? kLs / kFs : 0;
|
|
82
|
+
|
|
83
|
+
const results = {
|
|
84
|
+
title_present: probe.titleText === 'Command mesh',
|
|
85
|
+
title_tight_negative_ls: tLs < 0,
|
|
86
|
+
title_tight_about_n025em: tLsPerEm <= -0.02 && tLsPerEm >= -0.03,
|
|
87
|
+
title_font_weight_600: String(probe.titleFontWeight) === '600',
|
|
88
|
+
kicker_still_widest_r285: kLsPerEm >= 0.08 && kLsPerEm <= 0.12,
|
|
89
|
+
r283_monogram_stroke_kept: probe.alphaAvatarStroke === '1.5',
|
|
90
|
+
r282_watermark_present: probe.watermarkPresent,
|
|
91
|
+
};
|
|
92
|
+
const ok = Object.values(results).every(Boolean);
|
|
93
|
+
console.log(`${ok ? '✅' : '❌'} title tracking:`, JSON.stringify(results),
|
|
94
|
+
'\n title text:', JSON.stringify(probe.titleText),
|
|
95
|
+
'\n title letter-spacing:', probe.titleLetterSpacing, `(=${tLsPerEm.toFixed(4)}em)`,
|
|
96
|
+
'\n title font-size:', probe.titleFontSize, ' weight:', probe.titleFontWeight,
|
|
97
|
+
'\n kicker letter-spacing (R285):', probe.kickerLetterSpacing, `(=${kLsPerEm.toFixed(3)}em)`);
|
|
98
|
+
process.exit(ok ? 0 : 1);
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/* Round 270 verification: chrome strip TOGGLE buttons align inactive
|
|
2
|
+
* hover-bg to the Layout toggle's R163 cyan-preview pattern.
|
|
3
|
+
*
|
|
4
|
+
* Pre-R270:
|
|
5
|
+
* Layout Ring/Grid inactive: 'hover:bg-cyan-500/5 active:bg-cyan-500/15' ← R163 cyan preview
|
|
6
|
+
* nodeSize S/M/L inactive: 'hover:bg-white/5 active:bg-white/10' ← neutral white
|
|
7
|
+
* fullscreen inactive: 'hover:bg-white/5 active:bg-white/10' ← neutral white
|
|
8
|
+
* zoom -/+ + reset: 'hover:bg-white/5 active:bg-white/10' ← actions, no state
|
|
9
|
+
*
|
|
10
|
+
* The TOGGLES (Layout, nodeSize, fullscreen) split into two hover vocabularies:
|
|
11
|
+
* Layout uses cyan-preview, the others use neutral white. R270 unifies the
|
|
12
|
+
* other toggles to the cyan-preview pattern so all chrome TOGGLES preview
|
|
13
|
+
* their active state on hover. Pure ACTIONS (zoom, reset) stay white.
|
|
14
|
+
*
|
|
15
|
+
* Test scope:
|
|
16
|
+
* 1. nodeSize INACTIVE button(s) have 'hover:bg-cyan-500/5' class. With
|
|
17
|
+
* nodeScale=1 (L active), S and M are inactive — probe one of them.
|
|
18
|
+
* 2. nodeSize ACTIVE button still has 'hover:bg-cyan-500/20' (unchanged).
|
|
19
|
+
* 3. Fullscreen INACTIVE has 'hover:bg-cyan-500/5' (we're not in fullscreen).
|
|
20
|
+
* 4. Pure ACTIONS (zoom-out, reset) STILL use 'hover:bg-white/5' (regression).
|
|
21
|
+
* 5. R268 layout toggle border still uses pal.containerBorder (regression).
|
|
22
|
+
*/
|
|
23
|
+
import { chromium } from 'playwright';
|
|
24
|
+
import { readFileSync } from 'node:fs';
|
|
25
|
+
|
|
26
|
+
const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
|
|
27
|
+
const browser = await chromium.launch({ headless: true });
|
|
28
|
+
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
|
+
const fresh = new Date(Date.now() - 60 * 1000).toISOString();
|
|
34
|
+
await ctx.route('**/api/hub/status*', async (route) => {
|
|
35
|
+
const r = await route.fetch();
|
|
36
|
+
const b = await r.json();
|
|
37
|
+
const nid = (b.sessions || [])[0]?.network_id || 'default';
|
|
38
|
+
const mk = (alias) => ({
|
|
39
|
+
alias, status: 'working', model: 'claude-opus-4', runtime: 'claude-code-cli',
|
|
40
|
+
network_id: nid, project_dir: null,
|
|
41
|
+
created_at: fresh, updated_at: fresh, last_seen_at: fresh,
|
|
42
|
+
});
|
|
43
|
+
await route.fulfill({ response: r, json: { ...b, sessions: [
|
|
44
|
+
mk('alpha'), mk('beta'), mk('gamma'), mk('delta'),
|
|
45
|
+
] } });
|
|
46
|
+
});
|
|
47
|
+
await ctx.route('**/api/hub/messages*', (r) => r.fulfill({ json: { messages: [] } }));
|
|
48
|
+
await ctx.route('**/api/hub/tasks*', (r) => r.fulfill({ json: { tasks: [] } }));
|
|
49
|
+
|
|
50
|
+
const page = await ctx.newPage();
|
|
51
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
|
|
52
|
+
await page.waitForFunction(() => document.querySelectorAll('g[data-node]').length === 4, { timeout: 30000 });
|
|
53
|
+
await page.waitForSelector('[data-topo-chrome-nodesize="S"]', { timeout: 10000 });
|
|
54
|
+
await page.waitForSelector('[data-topo-chrome-nodesize="L"]', { timeout: 10000 });
|
|
55
|
+
await page.waitForSelector('[data-topo-chrome-fullscreen]', { timeout: 10000 });
|
|
56
|
+
await page.waitForSelector('[data-topo-chrome-zoom-out]', { timeout: 10000 });
|
|
57
|
+
await page.waitForSelector('[data-topo-chrome-reset]', { timeout: 10000 });
|
|
58
|
+
await page.waitForSelector('[data-topo-chrome-layout-trailer]',{ timeout: 10000 });
|
|
59
|
+
await page.waitForTimeout(300);
|
|
60
|
+
|
|
61
|
+
const probe = await page.evaluate(() => {
|
|
62
|
+
// With default state, nodeScale=1 → L active, S+M inactive.
|
|
63
|
+
const s = document.querySelector('[data-topo-chrome-nodesize="S"]');
|
|
64
|
+
const m = document.querySelector('[data-topo-chrome-nodesize="M"]');
|
|
65
|
+
const l = document.querySelector('[data-topo-chrome-nodesize="L"]');
|
|
66
|
+
const fullscreen = document.querySelector('[data-topo-chrome-fullscreen]');
|
|
67
|
+
const zoomOut = document.querySelector('[data-topo-chrome-zoom-out]');
|
|
68
|
+
const reset = document.querySelector('[data-topo-chrome-reset]');
|
|
69
|
+
const layoutWrap = document.querySelector('[data-topo-chrome-layout-trailer]');
|
|
70
|
+
return {
|
|
71
|
+
sClasses: s ? s.className.toString() : null,
|
|
72
|
+
mClasses: m ? m.className.toString() : null,
|
|
73
|
+
lClasses: l ? l.className.toString() : null,
|
|
74
|
+
fullscreenClasses: fullscreen ? fullscreen.className.toString() : null,
|
|
75
|
+
zoomOutClasses: zoomOut ? zoomOut.className.toString() : null,
|
|
76
|
+
resetClasses: reset ? reset.className.toString() : null,
|
|
77
|
+
layoutBorderColor: layoutWrap ? window.getComputedStyle(layoutWrap).borderTopColor : null,
|
|
78
|
+
};
|
|
79
|
+
});
|
|
80
|
+
await browser.close();
|
|
81
|
+
|
|
82
|
+
const has = (s, cls) => (s || '').includes(cls);
|
|
83
|
+
|
|
84
|
+
// nodeScale defaults to 0.84 (M is active). S and L are inactive.
|
|
85
|
+
const results = {
|
|
86
|
+
// Inactive nodeSize buttons (S + L when M is default-active) → cyan hover
|
|
87
|
+
s_inactive_has_cyan_hover: has(probe.sClasses, 'hover:bg-cyan-500/5'),
|
|
88
|
+
l_inactive_has_cyan_hover: has(probe.lClasses, 'hover:bg-cyan-500/5'),
|
|
89
|
+
// Active nodeSize (M @ 0.84 default) → unchanged cyan-500/20 hover (active variant)
|
|
90
|
+
m_active_has_cyan20_hover: has(probe.mClasses, 'hover:bg-cyan-500/20'),
|
|
91
|
+
// No more white/5 on inactive nodeSize
|
|
92
|
+
s_inactive_no_white_hover: !has(probe.sClasses, 'hover:bg-white/5'),
|
|
93
|
+
// Fullscreen INACTIVE (not in fullscreen) picks up cyan hover
|
|
94
|
+
fullscreen_inactive_has_cyan: has(probe.fullscreenClasses, 'hover:bg-cyan-500/5'),
|
|
95
|
+
fullscreen_no_white_hover: !has(probe.fullscreenClasses, 'hover:bg-white/5'),
|
|
96
|
+
// Pure ACTIONS stay white
|
|
97
|
+
zoom_out_keeps_white_hover: has(probe.zoomOutClasses, 'hover:bg-white/5'),
|
|
98
|
+
reset_keeps_white_hover: has(probe.resetClasses, 'hover:bg-white/5'),
|
|
99
|
+
// R268 regression: layout border still uses pal.containerBorder
|
|
100
|
+
r268_layout_border_unified: probe.layoutBorderColor === 'rgb(42, 42, 74)',
|
|
101
|
+
};
|
|
102
|
+
const ok = Object.values(results).every(Boolean);
|
|
103
|
+
console.log(`${ok ? '✅' : '❌'} toggle inactive cyan hover:`, JSON.stringify(results),
|
|
104
|
+
'\n S classes:', probe.sClasses,
|
|
105
|
+
'\n L (active):', probe.lClasses,
|
|
106
|
+
'\n fullscreen (inactive):', probe.fullscreenClasses,
|
|
107
|
+
'\n zoom-out:', probe.zoomOutClasses,
|
|
108
|
+
'\n reset:', probe.resetClasses,
|
|
109
|
+
'\n layout border:', probe.layoutBorderColor);
|
|
110
|
+
process.exit(ok ? 0 : 1);
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/* Round 265 verification: canvas top-rail gradient gains theme-toggle
|
|
2
|
+
* transition — closes the last canvas-envelope theme-snap.
|
|
3
|
+
*
|
|
4
|
+
* Pre-R265 the top-rail was:
|
|
5
|
+
* <div className={`absolute inset-x-0 top-0 h-px bg-gradient-to-r ${pal.topRailGradient}`} />
|
|
6
|
+
*
|
|
7
|
+
* pal.topRailGradient is theme-conditional:
|
|
8
|
+
* cyber: 'from-transparent via-cyan-400/70 to-transparent'
|
|
9
|
+
* light: 'from-transparent via-emerald-500/40 to-transparent'
|
|
10
|
+
*
|
|
11
|
+
* On theme toggle the className swap changes the gradient color but no
|
|
12
|
+
* inline transition existed — so the 1px-tall bright line at the
|
|
13
|
+
* canvas top edge SNAPPED while the wrapper bg (R254), border (R254),
|
|
14
|
+
* and shadow (R263) all eased. Small visible holdover.
|
|
15
|
+
*
|
|
16
|
+
* R265 adds `transition: background-image 200ms ease-out`. CSS
|
|
17
|
+
* gradient interpolation works on browsers ≥ Chrome 89 / Safari 14.1 /
|
|
18
|
+
* FF 96 when both gradients share matching stop structure — both
|
|
19
|
+
* gradients here are `from-transparent via-X to-transparent`
|
|
20
|
+
* (identical 3-stop layout).
|
|
21
|
+
*
|
|
22
|
+
* Test scope:
|
|
23
|
+
* 1. Top-rail element present at `[data-topo-top-rail]`.
|
|
24
|
+
* 2. Inline transition contains `background-image` at 200ms (or 0.2s).
|
|
25
|
+
* 3. Computed backgroundImage is a non-empty linear-gradient (not
|
|
26
|
+
* 'none' / empty — confirms the className gradient applied).
|
|
27
|
+
* 4. R263 wrapper box-shadow transition still in place (regression).
|
|
28
|
+
*/
|
|
29
|
+
import { chromium } from 'playwright';
|
|
30
|
+
import { readFileSync } from 'node:fs';
|
|
31
|
+
|
|
32
|
+
const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
|
|
33
|
+
const browser = await chromium.launch({ headless: true });
|
|
34
|
+
const ctx = await browser.newContext({ viewport: { width: 1500, height: 1500 } });
|
|
35
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
36
|
+
await ctx.addInitScript(() => {
|
|
37
|
+
try { localStorage.setItem('anet-theme', 'cyber'); sessionStorage.setItem('anet_v3_auth', '1'); } 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*', (r) => r.fulfill({ json: { messages: [] } }));
|
|
54
|
+
await ctx.route('**/api/hub/tasks*', (r) => r.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 === 4, { timeout: 30000 });
|
|
59
|
+
await page.waitForSelector('[data-topo-top-rail]', { timeout: 10000 });
|
|
60
|
+
await page.waitForSelector('[data-topo-wrapper]', { timeout: 10000 });
|
|
61
|
+
await page.waitForTimeout(300);
|
|
62
|
+
|
|
63
|
+
const probe = await page.evaluate(() => {
|
|
64
|
+
const rail = document.querySelector('[data-topo-top-rail]');
|
|
65
|
+
const wrapper = document.querySelector('[data-topo-wrapper]');
|
|
66
|
+
return {
|
|
67
|
+
railTransition: rail ? rail.style.transition : null,
|
|
68
|
+
railBackgroundImage: rail ? window.getComputedStyle(rail).backgroundImage : null,
|
|
69
|
+
wrapperTransition: wrapper ? wrapper.style.transition : null,
|
|
70
|
+
};
|
|
71
|
+
});
|
|
72
|
+
await browser.close();
|
|
73
|
+
|
|
74
|
+
const has = (s, prop) => new RegExp(`${prop}\\s+(?:200ms|0\\.2s)`).test(s || '');
|
|
75
|
+
|
|
76
|
+
const results = {
|
|
77
|
+
rail_present: probe.railTransition !== null,
|
|
78
|
+
rail_transition_has_bg_image_200: has(probe.railTransition, 'background-image'),
|
|
79
|
+
rail_has_non_empty_gradient: probe.railBackgroundImage != null
|
|
80
|
+
&& probe.railBackgroundImage !== 'none'
|
|
81
|
+
&& probe.railBackgroundImage.includes('linear-gradient'),
|
|
82
|
+
r263_wrapper_has_box_shadow_200: has(probe.wrapperTransition, 'box-shadow'),
|
|
83
|
+
};
|
|
84
|
+
const ok = Object.values(results).every(Boolean);
|
|
85
|
+
console.log(`${ok ? '✅' : '❌'} top-rail theme ease:`, JSON.stringify(results),
|
|
86
|
+
'\n rail transition: ', probe.railTransition,
|
|
87
|
+
'\n rail backgroundImage: ', probe.railBackgroundImage,
|
|
88
|
+
'\n wrapper transition: ', probe.wrapperTransition);
|
|
89
|
+
process.exit(ok ? 0 : 1);
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/* Round 35 verification: SQL-style timestamps (CommHub format) parse as
|
|
2
|
+
* UTC regardless of the browser's local timezone. Reproduces the latent
|
|
3
|
+
* bug from Round 34 — a 30-min-old offline node would have been ghosted
|
|
4
|
+
* on a UTC+8 browser without parseHubTime. */
|
|
5
|
+
import { chromium } from 'playwright';
|
|
6
|
+
import { readFileSync } from 'node:fs';
|
|
7
|
+
|
|
8
|
+
const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
|
|
9
|
+
const browser = await chromium.launch({ headless: true });
|
|
10
|
+
|
|
11
|
+
// SQL-style timestamp = ISO with the T replaced by space and Z stripped.
|
|
12
|
+
// This is exactly what the CommHub returns (see /api/status probe).
|
|
13
|
+
const sqlMin = (m) => {
|
|
14
|
+
const d = new Date(Date.now() - m * 60 * 1000);
|
|
15
|
+
return d.toISOString().replace('T', ' ').replace(/\.\d+Z$/, '');
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
async function probe(timezoneId) {
|
|
19
|
+
const ctx = await browser.newContext({ viewport: { width: 1280, height: 900 }, timezoneId });
|
|
20
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
21
|
+
await ctx.addInitScript(() => {
|
|
22
|
+
try {
|
|
23
|
+
localStorage.setItem('anet-theme', 'cyber');
|
|
24
|
+
localStorage.setItem('anet-topo-layout', 'grid');
|
|
25
|
+
sessionStorage.setItem('anet_v3_auth', '1');
|
|
26
|
+
} catch {}
|
|
27
|
+
});
|
|
28
|
+
const fresh = sqlMin(0.1);
|
|
29
|
+
await ctx.route('**/api/hub/status*', async (route) => {
|
|
30
|
+
const r = await route.fetch();
|
|
31
|
+
const b = await r.json();
|
|
32
|
+
const nid = (b.sessions || [])[0]?.network_id || 'default';
|
|
33
|
+
const sessions = [
|
|
34
|
+
{ alias: 'live', status: 'idle', network_id: nid, project_dir: null,
|
|
35
|
+
created_at: fresh, updated_at: fresh, last_seen_at: fresh },
|
|
36
|
+
{ alias: 'off30', status: 'offline', network_id: nid, project_dir: null,
|
|
37
|
+
created_at: fresh, updated_at: fresh, last_seen_at: sqlMin(30) }, // 30 min ago, SQL format
|
|
38
|
+
{ alias: 'ghost', status: 'offline', network_id: nid, project_dir: null,
|
|
39
|
+
created_at: fresh, updated_at: fresh, last_seen_at: sqlMin(75) }, // 75 min ago — should ghost
|
|
40
|
+
];
|
|
41
|
+
await route.fulfill({ response: r, json: { ...b, sessions } });
|
|
42
|
+
});
|
|
43
|
+
await ctx.route('**/api/hub/tasks*', (route) => route.fulfill({ json: { tasks: [] } }));
|
|
44
|
+
const page = await ctx.newPage();
|
|
45
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
|
|
46
|
+
await page.waitForSelector('svg[viewBox="0 0 1000 680"]', { timeout: 30000 });
|
|
47
|
+
await page.waitForTimeout(600);
|
|
48
|
+
const rendered = await page.$$eval('g[data-node]', els => els.map(e => e.getAttribute('data-node')));
|
|
49
|
+
await ctx.close();
|
|
50
|
+
return rendered;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const utc = await probe('UTC');
|
|
54
|
+
const shanghai = await probe('Asia/Shanghai'); // UTC+8 — the failing case before Round 35
|
|
55
|
+
const losAngeles = await probe('America/Los_Angeles'); // UTC-7/8 — the opposite skew
|
|
56
|
+
await browser.close();
|
|
57
|
+
|
|
58
|
+
const expectsLiveAndOff30 = list =>
|
|
59
|
+
list.includes('live') && list.includes('off30') && !list.includes('ghost');
|
|
60
|
+
|
|
61
|
+
const results = {
|
|
62
|
+
utcRendersLiveAndOff30: expectsLiveAndOff30(utc),
|
|
63
|
+
shanghaiRendersLiveAndOff30: expectsLiveAndOff30(shanghai),
|
|
64
|
+
losAngelesRendersLiveAndOff30: expectsLiveAndOff30(losAngeles),
|
|
65
|
+
};
|
|
66
|
+
const ok = Object.values(results).every(Boolean);
|
|
67
|
+
console.log(`${ok ? '✅' : '❌'} TZ-safe ghost:`, JSON.stringify(results),
|
|
68
|
+
`\n UTC=${JSON.stringify(utc)}\n Asia/Shanghai=${JSON.stringify(shanghai)}\n America/Los_Angeles=${JSON.stringify(losAngeles)}`);
|
|
69
|
+
process.exit(ok ? 0 : 1);
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/* Round 80 verification: hovering a vendor letter in the distribution
|
|
2
|
+
* chip dims nodes from other vendors. Composes with R55/R77/R79 dim
|
|
3
|
+
* mechanic — same 0.28 dim weight, distinct filter dimension.
|
|
4
|
+
*
|
|
5
|
+
* Fleet: 2 Claude nodes (alpha, gamma) + 1 GPT node (beta). The chip
|
|
6
|
+
* renders "C:2 G:1" (with the unknown bucket if any models don't
|
|
7
|
+
* resolve). Hover `C` → alpha + gamma stay bright, beta dims. Hover
|
|
8
|
+
* `G` → beta stays, alpha + gamma dim. Mouseleave restores.
|
|
9
|
+
*/
|
|
10
|
+
import { chromium } from 'playwright';
|
|
11
|
+
import { readFileSync } from 'node:fs';
|
|
12
|
+
|
|
13
|
+
const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
|
|
14
|
+
const browser = await chromium.launch({ headless: true });
|
|
15
|
+
|
|
16
|
+
const ctx = await browser.newContext({ viewport: { width: 1400, height: 1500 } });
|
|
17
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
18
|
+
await ctx.addInitScript(() => {
|
|
19
|
+
try {
|
|
20
|
+
localStorage.setItem('anet-theme', 'cyber');
|
|
21
|
+
localStorage.setItem('anet-topo-layout', 'ring');
|
|
22
|
+
sessionStorage.setItem('anet_v3_auth', '1');
|
|
23
|
+
sessionStorage.removeItem('anet-topo-pinned-status');
|
|
24
|
+
sessionStorage.removeItem('anet-topo-pinned-group');
|
|
25
|
+
} catch {}
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
const fresh = new Date(Date.now() - 60 * 1000).toISOString();
|
|
29
|
+
await ctx.route('**/api/hub/status*', async (route) => {
|
|
30
|
+
const r = await route.fetch();
|
|
31
|
+
const b = await r.json();
|
|
32
|
+
const nid = (b.sessions || [])[0]?.network_id || 'default';
|
|
33
|
+
const sessions = [
|
|
34
|
+
{ alias: 'alpha', status: 'idle', model: 'claude-opus-4', runtime: 'cli-claude-code',
|
|
35
|
+
network_id: nid, project_dir: null, created_at: fresh, updated_at: fresh, last_seen_at: fresh },
|
|
36
|
+
{ alias: 'beta', status: 'idle', model: 'gpt-5', runtime: 'codex-cli',
|
|
37
|
+
network_id: nid, project_dir: null, created_at: fresh, updated_at: fresh, last_seen_at: fresh },
|
|
38
|
+
{ alias: 'gamma', status: 'idle', model: 'claude-opus-4', runtime: 'cli-claude-code',
|
|
39
|
+
network_id: nid, project_dir: null, created_at: fresh, updated_at: fresh, last_seen_at: fresh },
|
|
40
|
+
];
|
|
41
|
+
await route.fulfill({ response: r, json: { ...b, sessions } });
|
|
42
|
+
});
|
|
43
|
+
await ctx.route('**/api/hub/messages*', (route) => route.fulfill({ json: { messages: [] } }));
|
|
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(500);
|
|
49
|
+
|
|
50
|
+
const opacities = () => page.evaluate(() => {
|
|
51
|
+
const o = {};
|
|
52
|
+
for (const a of ['alpha', 'beta', 'gamma']) {
|
|
53
|
+
const g = document.querySelector(`g[data-node="${a}"]`);
|
|
54
|
+
o[a] = g ? +(g.style.opacity || '1') : null;
|
|
55
|
+
}
|
|
56
|
+
return o;
|
|
57
|
+
});
|
|
58
|
+
const vendorLetters = await page.evaluate(() => {
|
|
59
|
+
return [...document.querySelectorAll('[data-vendor-letter]')].map(el => el.getAttribute('data-vendor-letter'));
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
const before = await opacities();
|
|
63
|
+
|
|
64
|
+
// vendorIdentity maps Anthropic→`A`, OpenAI→`O` (initials, not first
|
|
65
|
+
// letter of the model name). Find which sessions land in which bucket
|
|
66
|
+
// dynamically — `alpha` + `gamma` use claude-opus-4 (Anthropic = A),
|
|
67
|
+
// `beta` uses gpt-5 (OpenAI = O).
|
|
68
|
+
const aLetter = vendorLetters.find(l => l === 'A') || vendorLetters[0];
|
|
69
|
+
const oLetter = vendorLetters.find(l => l === 'O') || vendorLetters[1];
|
|
70
|
+
|
|
71
|
+
await page.locator(`[data-vendor-letter="${aLetter}"]`).hover();
|
|
72
|
+
await page.waitForTimeout(250);
|
|
73
|
+
const onClaude = await opacities();
|
|
74
|
+
|
|
75
|
+
await page.mouse.move(10, 10);
|
|
76
|
+
await page.waitForTimeout(250);
|
|
77
|
+
const afterClaude = await opacities();
|
|
78
|
+
|
|
79
|
+
if (oLetter) {
|
|
80
|
+
await page.locator(`[data-vendor-letter="${oLetter}"]`).hover();
|
|
81
|
+
await page.waitForTimeout(250);
|
|
82
|
+
}
|
|
83
|
+
const onGpt = await opacities();
|
|
84
|
+
|
|
85
|
+
await page.mouse.move(10, 10);
|
|
86
|
+
await page.waitForTimeout(250);
|
|
87
|
+
const afterGpt = await opacities();
|
|
88
|
+
|
|
89
|
+
await browser.close();
|
|
90
|
+
|
|
91
|
+
const bright = (v) => v != null && v >= 0.55;
|
|
92
|
+
const dim = (v) => v != null && v < 0.4;
|
|
93
|
+
const results = {
|
|
94
|
+
before_baseline: bright(before.alpha) && bright(before.beta) && bright(before.gamma),
|
|
95
|
+
vendorLetters_atLeast2: vendorLetters.length >= 2,
|
|
96
|
+
anthropicLetter_A: vendorLetters.includes('A'),
|
|
97
|
+
openaiLetter_O: vendorLetters.includes('O'),
|
|
98
|
+
hoverA_keepsClaudes: bright(onClaude.alpha) && bright(onClaude.gamma),
|
|
99
|
+
hoverA_dimsGPT: dim(onClaude.beta),
|
|
100
|
+
leaveA_restoresAll: bright(afterClaude.alpha) && bright(afterClaude.beta) && bright(afterClaude.gamma),
|
|
101
|
+
hoverO_keepsGPT: bright(onGpt.beta),
|
|
102
|
+
hoverO_dimsClaudes: dim(onGpt.alpha) && dim(onGpt.gamma),
|
|
103
|
+
leaveO_restoresAll: bright(afterGpt.alpha) && bright(afterGpt.beta) && bright(afterGpt.gamma),
|
|
104
|
+
};
|
|
105
|
+
const ok = Object.values(results).every(Boolean);
|
|
106
|
+
console.log(`${ok ? '✅' : '❌'} vendor-chip hover:`, JSON.stringify(results),
|
|
107
|
+
`\n vendorLetters=`, vendorLetters,
|
|
108
|
+
`\n before=`, before,
|
|
109
|
+
`\n onClaude=`, onClaude,
|
|
110
|
+
`\n onGpt=`, onGpt);
|
|
111
|
+
process.exit(ok ? 0 : 1);
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
/* Round 202 verification: vendor letter chips (A/O/书/M/?) deepen
|
|
2
|
+
* their OWN vendor colour on hover, completing the chip-row family
|
|
3
|
+
* R193/R195/R201 opened.
|
|
4
|
+
*
|
|
5
|
+
* Pre-R202 hover fired R88 canvas dim via setHoveredVendor but the
|
|
6
|
+
* chip itself stayed at bg=transparent. R202 tints the chip with
|
|
7
|
+
* color-mix(in srgb, <vendor-hue> 12%, transparent) only when hovered
|
|
8
|
+
* (and not pinned — pinned uses R180's stronger inset-ring treatment).
|
|
9
|
+
*
|
|
10
|
+
* Test (cyber dark, 2 claude + 2 gpt sessions → vendorDist={A:2, O:2}):
|
|
11
|
+
* 1. vendor letter chips A + O both render (vendorDist.length > 1).
|
|
12
|
+
* 2. Idle: data-vendor-hovered='false', backgroundColor='transparent'
|
|
13
|
+
* / 'rgba(0,0,0,0)'.
|
|
14
|
+
* 3. Inline transition includes 'box-shadow 150ms' (R180 still there)
|
|
15
|
+
* AND 'background-color 200ms' (R202 splice).
|
|
16
|
+
* 4. Hover 'A' chip — wait past 220ms.
|
|
17
|
+
* 5. 'A' data-vendor-hovered='true', backgroundColor is a non-empty
|
|
18
|
+
* tint string (color-mix or rendered fallback) different from
|
|
19
|
+
* idle. 'O' chip stays 'false' + transparent.
|
|
20
|
+
* 6. Move away — 'A' settles back to 'false' + transparent.
|
|
21
|
+
* 7. R88 canvas-effect verification — hover 'A' sets hoveredVendor
|
|
22
|
+
* which composes into the canvas dim logic; we probe via a
|
|
23
|
+
* surrogate signal that the chip's R55-like effect fires:
|
|
24
|
+
* hoveredVendor is exposed elsewhere via data attributes; the
|
|
25
|
+
* simplest gate is that the chip itself reflects the hover via
|
|
26
|
+
* its own data-vendor-hovered attribute already asserted above
|
|
27
|
+
* (event handler clearly ran).
|
|
28
|
+
*/
|
|
29
|
+
import { chromium } from 'playwright';
|
|
30
|
+
import { readFileSync } from 'node:fs';
|
|
31
|
+
|
|
32
|
+
const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
|
|
33
|
+
const browser = await chromium.launch({ headless: true });
|
|
34
|
+
|
|
35
|
+
const ctx = await browser.newContext({ viewport: { width: 1500, height: 1500 } });
|
|
36
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
37
|
+
await ctx.addInitScript(() => {
|
|
38
|
+
try { localStorage.setItem('anet-theme', 'cyber'); sessionStorage.setItem('anet_v3_auth', '1'); } catch {}
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
const fresh = new Date(Date.now() - 60 * 1000).toISOString();
|
|
42
|
+
await ctx.route('**/api/hub/status*', async (route) => {
|
|
43
|
+
const r = await route.fetch();
|
|
44
|
+
const b = await r.json();
|
|
45
|
+
const nid = (b.sessions || [])[0]?.network_id || 'default';
|
|
46
|
+
const mk = (alias, model) => ({
|
|
47
|
+
alias, status: 'working', model, runtime: 'cli-claude-code',
|
|
48
|
+
network_id: nid, project_dir: null,
|
|
49
|
+
created_at: fresh, updated_at: fresh, last_seen_at: fresh,
|
|
50
|
+
});
|
|
51
|
+
// 3+ vendor types (R281 threshold tightened to >2): one Anthropic +
|
|
52
|
+
// one OpenAI + one InternLM (书生) + one unknown → vendorDist 4 types.
|
|
53
|
+
await route.fulfill({ response: r, json: { ...b, sessions: [
|
|
54
|
+
mk('alpha', 'claude-opus-4'),
|
|
55
|
+
mk('beta', 'gpt-4o'),
|
|
56
|
+
mk('gamma', 'internlm/internlm2'),
|
|
57
|
+
mk('delta', 'some-unknown-model'),
|
|
58
|
+
] } });
|
|
59
|
+
});
|
|
60
|
+
await ctx.route('**/api/hub/messages*', (route) => route.fulfill({ json: { messages: [] } }));
|
|
61
|
+
await ctx.route('**/api/hub/tasks*', (route) => route.fulfill({ json: { tasks: [] } }));
|
|
62
|
+
|
|
63
|
+
const page = await ctx.newPage();
|
|
64
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
|
|
65
|
+
await page.waitForFunction(() => document.querySelectorAll('g[data-node]').length === 4, { timeout: 30000 });
|
|
66
|
+
await page.waitForSelector('[data-vendor-letter="A"]', { timeout: 10000 });
|
|
67
|
+
await page.waitForSelector('[data-vendor-letter="O"]', { timeout: 5000 });
|
|
68
|
+
await page.waitForTimeout(300);
|
|
69
|
+
|
|
70
|
+
const probe = async (initial) => page.evaluate((i) => {
|
|
71
|
+
const el = document.querySelector(`[data-vendor-letter="${i}"]`);
|
|
72
|
+
if (!el) return null;
|
|
73
|
+
const cs = getComputedStyle(el);
|
|
74
|
+
return {
|
|
75
|
+
initial: i,
|
|
76
|
+
hovered: el.getAttribute('data-vendor-hovered'),
|
|
77
|
+
pinned: el.getAttribute('data-vendor-pinned'),
|
|
78
|
+
bg: cs.backgroundColor,
|
|
79
|
+
inlineBg: el.style.backgroundColor,
|
|
80
|
+
transition: el.style.transition,
|
|
81
|
+
};
|
|
82
|
+
}, initial);
|
|
83
|
+
|
|
84
|
+
const idleA = await probe('A');
|
|
85
|
+
const idleO = await probe('O');
|
|
86
|
+
|
|
87
|
+
await page.hover('[data-vendor-letter="A"]');
|
|
88
|
+
await page.waitForTimeout(260);
|
|
89
|
+
const hoverA = await probe('A');
|
|
90
|
+
const otherO = await probe('O');
|
|
91
|
+
|
|
92
|
+
await page.mouse.move(0, 0);
|
|
93
|
+
await page.waitForTimeout(280);
|
|
94
|
+
const settledA = await probe('A');
|
|
95
|
+
|
|
96
|
+
await browser.close();
|
|
97
|
+
|
|
98
|
+
const isTransparent = (s) =>
|
|
99
|
+
!s || s === 'transparent' || s === 'rgba(0, 0, 0, 0)' || s === 'rgba(0,0,0,0)';
|
|
100
|
+
|
|
101
|
+
const hasColorMix = (s) => /color-mix\s*\(/i.test(s || '');
|
|
102
|
+
const isNonEmptyColor = (s) => !!s && !isTransparent(s);
|
|
103
|
+
|
|
104
|
+
const results = {
|
|
105
|
+
A_chip_present: !!idleA,
|
|
106
|
+
O_chip_present: !!idleO,
|
|
107
|
+
|
|
108
|
+
idle_A_not_hovered: idleA?.hovered === 'false',
|
|
109
|
+
idle_A_transparent_bg: isTransparent(idleA?.bg),
|
|
110
|
+
idle_A_transition_boxshadow: /box-shadow\s+(?:150ms|0\.15s)/.test(idleA?.transition || ''),
|
|
111
|
+
idle_A_transition_bgcolor: /background-color\s+(?:200ms|0\.2s)/.test(idleA?.transition || ''),
|
|
112
|
+
|
|
113
|
+
idle_O_not_hovered: idleO?.hovered === 'false',
|
|
114
|
+
|
|
115
|
+
hover_A_hovered_attr: hoverA?.hovered === 'true',
|
|
116
|
+
hover_A_inline_color_mix: hasColorMix(hoverA?.inlineBg),
|
|
117
|
+
hover_A_computed_non_transparent: isNonEmptyColor(hoverA?.bg) && !isTransparent(hoverA?.bg),
|
|
118
|
+
hover_A_bg_changed: idleA?.bg !== hoverA?.bg,
|
|
119
|
+
hover_O_stays_idle: otherO?.hovered === 'false' && isTransparent(otherO?.bg),
|
|
120
|
+
|
|
121
|
+
settled_A_not_hovered: settledA?.hovered === 'false',
|
|
122
|
+
settled_A_transparent_bg: isTransparent(settledA?.bg),
|
|
123
|
+
};
|
|
124
|
+
const ok = Object.values(results).every(Boolean);
|
|
125
|
+
console.log(`${ok ? '✅' : '❌'} vendor chip self-hover:`, JSON.stringify(results),
|
|
126
|
+
`\n idleA:`, idleA,
|
|
127
|
+
`\n idleO:`, idleO,
|
|
128
|
+
`\n hoverA:`, hoverA,
|
|
129
|
+
`\n otherO:`, otherO,
|
|
130
|
+
`\n settledA:`, settledA);
|
|
131
|
+
process.exit(ok ? 0 : 1);
|