@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,89 @@
|
|
|
1
|
+
/* Round 291 verification: starfield decorative dot count 28 → 14
|
|
2
|
+
* (50% reduction). Continuation of the 减法 register R290 pivoted
|
|
3
|
+
* back to. Atmospheric depth preserved; visual density cut in
|
|
4
|
+
* half so the eye has less ambient decoration to skip past.
|
|
5
|
+
*
|
|
6
|
+
* Contract:
|
|
7
|
+
* - [data-topo-starfield] container exists (cyber only).
|
|
8
|
+
* - 14 [data-topo-starfield-dot] children (was 28).
|
|
9
|
+
* - opacity 0.5 on the container unchanged (regression).
|
|
10
|
+
* - Light theme: starfield NOT rendered (regression — pre-R291
|
|
11
|
+
* behaviour, conditional on !isLight).
|
|
12
|
+
* - R290 radar ring set still ['170','250','330'] (regression).
|
|
13
|
+
* - R289 watermark letterSpacing + R283 monogram stroke intact.
|
|
14
|
+
*/
|
|
15
|
+
import { chromium } from 'playwright';
|
|
16
|
+
import { readFileSync } from 'node:fs';
|
|
17
|
+
|
|
18
|
+
const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
|
|
19
|
+
const browser = await chromium.launch({ headless: true });
|
|
20
|
+
const ctx = await browser.newContext({ viewport: { width: 1500, height: 1500 } });
|
|
21
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
22
|
+
await ctx.addInitScript(() => {
|
|
23
|
+
try { localStorage.setItem('anet-theme', 'cyber'); sessionStorage.setItem('anet_v3_auth', '1'); } catch {}
|
|
24
|
+
});
|
|
25
|
+
const fresh = new Date(Date.now() - 60 * 1000).toISOString();
|
|
26
|
+
await ctx.route('**/api/hub/status*', async (route) => {
|
|
27
|
+
const r = await route.fetch();
|
|
28
|
+
const b = await r.json();
|
|
29
|
+
const nid = (b.sessions || [])[0]?.network_id || 'default';
|
|
30
|
+
const mk = (alias, model) => ({
|
|
31
|
+
alias, status: 'working', model, runtime: 'claude-code-cli',
|
|
32
|
+
network_id: nid, project_dir: null,
|
|
33
|
+
created_at: fresh, updated_at: fresh, last_seen_at: fresh,
|
|
34
|
+
});
|
|
35
|
+
await route.fulfill({ response: r, json: { ...b, sessions: [
|
|
36
|
+
mk('alpha', 'claude-opus-4'),
|
|
37
|
+
mk('beta', 'gpt-4o'),
|
|
38
|
+
] } });
|
|
39
|
+
});
|
|
40
|
+
await ctx.route('**/api/hub/messages*', (r) => r.fulfill({ json: { messages: [] } }));
|
|
41
|
+
await ctx.route('**/api/hub/tasks*', (r) => r.fulfill({ json: { tasks: [] } }));
|
|
42
|
+
|
|
43
|
+
const page = await ctx.newPage();
|
|
44
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
|
|
45
|
+
await page.waitForSelector('[data-topo-starfield]', { timeout: 15000 });
|
|
46
|
+
await page.waitForSelector('[data-topo-brand-watermark]', { timeout: 10000 });
|
|
47
|
+
await page.waitForTimeout(300);
|
|
48
|
+
|
|
49
|
+
const probe = await page.evaluate(() => {
|
|
50
|
+
const sf = document.querySelector('[data-topo-starfield]');
|
|
51
|
+
const dots = document.querySelectorAll('[data-topo-starfield-dot]');
|
|
52
|
+
const opacity = sf?.getAttribute('opacity') ?? null;
|
|
53
|
+
const rings = [...document.querySelectorAll('[data-topo-radar-ring]')]
|
|
54
|
+
.map(r => r.getAttribute('data-topo-radar-ring')).sort((a, b) => +a - +b);
|
|
55
|
+
const wm = document.querySelector('[data-topo-brand-watermark]');
|
|
56
|
+
const wmLs = wm ? getComputedStyle(wm).letterSpacing : null;
|
|
57
|
+
const alphaNode = document.querySelector('g[data-node="alpha"]');
|
|
58
|
+
const alphaCircles = alphaNode ? [...alphaNode.querySelectorAll('circle')] : [];
|
|
59
|
+
const alphaAvatarCircle = alphaCircles
|
|
60
|
+
.map(c => ({ r: +c.getAttribute('r') || 0, sw: c.getAttribute('stroke-width'), isBadge: c.hasAttribute('data-runtime-badge') }))
|
|
61
|
+
.filter(c => c.r > 0 && c.r < 18 && !c.isBadge)
|
|
62
|
+
.sort((a, b) => b.r - a.r)[0];
|
|
63
|
+
return {
|
|
64
|
+
starfieldPresent: sf !== null,
|
|
65
|
+
dotCount: dots.length,
|
|
66
|
+
opacity,
|
|
67
|
+
radarRings: rings,
|
|
68
|
+
watermarkLs: wmLs,
|
|
69
|
+
alphaAvatarStroke: alphaAvatarCircle?.sw ?? null,
|
|
70
|
+
};
|
|
71
|
+
});
|
|
72
|
+
await browser.close();
|
|
73
|
+
|
|
74
|
+
const wmLsVal = parseFloat(probe.watermarkLs) || 0;
|
|
75
|
+
|
|
76
|
+
const results = {
|
|
77
|
+
starfield_container_present: probe.starfieldPresent,
|
|
78
|
+
fourteen_dots: probe.dotCount === 14,
|
|
79
|
+
opacity_0_5_kept: probe.opacity === '0.5',
|
|
80
|
+
r290_three_rings: JSON.stringify(probe.radarRings) === JSON.stringify(['170', '250', '330']),
|
|
81
|
+
r289_watermark_ls_kept: wmLsVal >= 0.4 && wmLsVal <= 0.7,
|
|
82
|
+
r283_monogram_stroke_kept: probe.alphaAvatarStroke === '1.5',
|
|
83
|
+
};
|
|
84
|
+
const ok = Object.values(results).every(Boolean);
|
|
85
|
+
console.log(`${ok ? '✅' : '❌'} starfield density:`, JSON.stringify(results),
|
|
86
|
+
'\n dot count (expect 14):', probe.dotCount,
|
|
87
|
+
'\n opacity:', probe.opacity,
|
|
88
|
+
'\n radar rings (R290):', probe.radarRings);
|
|
89
|
+
process.exit(ok ? 0 : 1);
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/* Round 79 verification: header working + online count chips become
|
|
2
|
+
* hover affordances (sister to R77 active-links chip).
|
|
3
|
+
* - Hover "N working" → setHoveredStatus('working') → idle + offline
|
|
4
|
+
* nodes dim, working stays bright. Same outcome as R55 legend row
|
|
5
|
+
* hover, just from the chip surface.
|
|
6
|
+
* - Hover "N online" with working present → same as above.
|
|
7
|
+
* - Mouseleave restores baseline.
|
|
8
|
+
*
|
|
9
|
+
* Fleet: 1 working (wkr), 2 idle (idl1, idl2), 1 offline (off).
|
|
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
|
+
|
|
17
|
+
const ctx = await browser.newContext({ viewport: { width: 1400, height: 1500 } });
|
|
18
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
19
|
+
await ctx.addInitScript(() => {
|
|
20
|
+
try {
|
|
21
|
+
localStorage.setItem('anet-theme', 'cyber');
|
|
22
|
+
localStorage.setItem('anet-topo-layout', 'ring');
|
|
23
|
+
sessionStorage.setItem('anet_v3_auth', '1');
|
|
24
|
+
sessionStorage.removeItem('anet-topo-pinned-status');
|
|
25
|
+
sessionStorage.removeItem('anet-topo-pinned-group');
|
|
26
|
+
} catch {}
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
const fresh = new Date(Date.now() - 60 * 1000).toISOString();
|
|
30
|
+
const stale = new Date(Date.now() - 30 * 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 sessions = [
|
|
36
|
+
{ alias: 'wkr', status: 'working', network_id: nid, project_dir: null, created_at: fresh, updated_at: fresh, last_seen_at: fresh },
|
|
37
|
+
{ alias: 'idl1', status: 'idle', network_id: nid, project_dir: null, created_at: fresh, updated_at: fresh, last_seen_at: fresh },
|
|
38
|
+
{ alias: 'idl2', status: 'idle', network_id: nid, project_dir: null, created_at: fresh, updated_at: fresh, last_seen_at: fresh },
|
|
39
|
+
{ alias: 'off', status: 'offline', network_id: nid, project_dir: null, created_at: stale, updated_at: stale, last_seen_at: stale },
|
|
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 === 4, { timeout: 30000 });
|
|
48
|
+
await page.waitForTimeout(500);
|
|
49
|
+
|
|
50
|
+
const opacities = () => page.evaluate(() => {
|
|
51
|
+
const o = {};
|
|
52
|
+
for (const a of ['wkr', 'idl1', 'idl2', 'off']) {
|
|
53
|
+
const g = document.querySelector(`g[data-node="${a}"]`);
|
|
54
|
+
o[a] = g ? +(g.style.opacity || '1') : null;
|
|
55
|
+
}
|
|
56
|
+
return o;
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
const before = await opacities();
|
|
60
|
+
|
|
61
|
+
// Hover working chip
|
|
62
|
+
await page.locator('[data-working-chip]').hover();
|
|
63
|
+
await page.waitForTimeout(250);
|
|
64
|
+
const onWorking = await opacities();
|
|
65
|
+
|
|
66
|
+
// Move away
|
|
67
|
+
await page.mouse.move(10, 10);
|
|
68
|
+
await page.waitForTimeout(250);
|
|
69
|
+
const afterWorking = await opacities();
|
|
70
|
+
|
|
71
|
+
// Hover online chip (working present → routes to 'working')
|
|
72
|
+
await page.locator('[data-online-chip]').hover();
|
|
73
|
+
await page.waitForTimeout(250);
|
|
74
|
+
const onOnline = await opacities();
|
|
75
|
+
|
|
76
|
+
await page.mouse.move(10, 10);
|
|
77
|
+
await page.waitForTimeout(250);
|
|
78
|
+
const afterOnline = await opacities();
|
|
79
|
+
|
|
80
|
+
await browser.close();
|
|
81
|
+
|
|
82
|
+
const bright = (v) => v != null && v >= 0.55;
|
|
83
|
+
const dim = (v) => v != null && v < 0.4;
|
|
84
|
+
const results = {
|
|
85
|
+
before_baseline: bright(before.wkr) && bright(before.idl1) && bright(before.idl2),
|
|
86
|
+
working_keepsWkrBright: bright(onWorking.wkr),
|
|
87
|
+
working_dimsIdle: dim(onWorking.idl1) && dim(onWorking.idl2),
|
|
88
|
+
working_dimsOffline: dim(onWorking.off),
|
|
89
|
+
workingLeave_restoresAll: bright(afterWorking.wkr) && bright(afterWorking.idl1),
|
|
90
|
+
online_keepsWkrBright: bright(onOnline.wkr), // routes to working filter
|
|
91
|
+
online_dimsIdle: dim(onOnline.idl1) && dim(onOnline.idl2),
|
|
92
|
+
onlineLeave_restoresAll: bright(afterOnline.wkr) && bright(afterOnline.idl1),
|
|
93
|
+
};
|
|
94
|
+
const ok = Object.values(results).every(Boolean);
|
|
95
|
+
console.log(`${ok ? '✅' : '❌'} status-chip hover:`, JSON.stringify(results),
|
|
96
|
+
`\n before=`, before,
|
|
97
|
+
`\n onWorking=`, onWorking,
|
|
98
|
+
`\n afterWorking=`, afterWorking,
|
|
99
|
+
`\n onOnline=`, onOnline,
|
|
100
|
+
`\n afterOnline=`, afterOnline);
|
|
101
|
+
process.exit(ok ? 0 : 1);
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/* Round 113 verification: chip-row "N working" + "N online" tooltips
|
|
2
|
+
* list matched aliases. Closes the last hover surfaces in the chip-
|
|
3
|
+
* row that had generic "Hover to highlight" titles. Same R97-R102 /
|
|
4
|
+
* R101 alias-list pattern.
|
|
5
|
+
*
|
|
6
|
+
* Fleet: 2 working (wkr1/2) + 2 idle (idl1/2) + 1 offline (off1).
|
|
7
|
+
* working chip title contains wkr1, wkr2; data-working-chip-aliases CSV matches
|
|
8
|
+
* online chip title contains all online aliases (4); data-online-chip-aliases matches
|
|
9
|
+
* pin state flips the action hint
|
|
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
|
+
|
|
17
|
+
const ctx = await browser.newContext({ viewport: { width: 1400, height: 1500 } });
|
|
18
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
19
|
+
await ctx.addInitScript(() => {
|
|
20
|
+
try {
|
|
21
|
+
localStorage.setItem('anet-theme', 'cyber');
|
|
22
|
+
sessionStorage.setItem('anet_v3_auth', '1');
|
|
23
|
+
sessionStorage.removeItem('anet-topo-pinned-status');
|
|
24
|
+
} catch {}
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
const fresh = new Date(Date.now() - 60 * 1000).toISOString();
|
|
28
|
+
const stale10 = new Date(Date.now() - 10 * 60 * 1000).toISOString();
|
|
29
|
+
await ctx.route('**/api/hub/status*', async (route) => {
|
|
30
|
+
const r = await route.fetch();
|
|
31
|
+
const b = await r.json();
|
|
32
|
+
const nid = (b.sessions || [])[0]?.network_id || 'default';
|
|
33
|
+
const mk = (alias, status, ts) => ({
|
|
34
|
+
alias, status, model: 'claude-opus-4', runtime: 'cli-claude-code',
|
|
35
|
+
network_id: nid, project_dir: null,
|
|
36
|
+
created_at: ts, updated_at: ts, last_seen_at: ts,
|
|
37
|
+
});
|
|
38
|
+
await route.fulfill({ response: r, json: { ...b, sessions: [
|
|
39
|
+
mk('wkr1', 'working', fresh),
|
|
40
|
+
mk('wkr2', 'working', fresh),
|
|
41
|
+
mk('idl1', 'idle', fresh),
|
|
42
|
+
mk('idl2', 'idle', fresh),
|
|
43
|
+
mk('off1', 'offline', stale10),
|
|
44
|
+
] } });
|
|
45
|
+
});
|
|
46
|
+
await ctx.route('**/api/hub/messages*', (route) => route.fulfill({ json: { messages: [] } }));
|
|
47
|
+
await ctx.route('**/api/hub/tasks*', (route) => route.fulfill({ json: { tasks: [] } }));
|
|
48
|
+
const page = await ctx.newPage();
|
|
49
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
|
|
50
|
+
await page.waitForFunction(() => document.querySelectorAll('g[data-node]').length === 5, { timeout: 30000 });
|
|
51
|
+
await page.waitForTimeout(400);
|
|
52
|
+
|
|
53
|
+
const read = (sel) => page.evaluate((s) => {
|
|
54
|
+
const el = document.querySelector(s);
|
|
55
|
+
if (!el) return null;
|
|
56
|
+
return {
|
|
57
|
+
title: el.getAttribute('title') || '',
|
|
58
|
+
aliases: el.getAttribute('data-working-chip-aliases') || el.getAttribute('data-online-chip-aliases') || '',
|
|
59
|
+
};
|
|
60
|
+
}, sel);
|
|
61
|
+
|
|
62
|
+
const workingBefore = await read('[data-working-chip]');
|
|
63
|
+
const onlineBefore = await read('[data-online-chip]');
|
|
64
|
+
|
|
65
|
+
// Pin working status — action hint should flip.
|
|
66
|
+
await page.evaluate(() => {
|
|
67
|
+
sessionStorage.setItem('anet-topo-pinned-status', 'working');
|
|
68
|
+
window.dispatchEvent(new CustomEvent('anet:topo-pin', { detail: { kind: 'status', value: 'working' } }));
|
|
69
|
+
});
|
|
70
|
+
await page.waitForTimeout(300);
|
|
71
|
+
const workingPinned = await read('[data-working-chip]');
|
|
72
|
+
|
|
73
|
+
await browser.close();
|
|
74
|
+
|
|
75
|
+
const sameSet = (csv, expected) => {
|
|
76
|
+
const got = new Set(csv.split(',').filter(Boolean));
|
|
77
|
+
const exp = new Set(expected);
|
|
78
|
+
return got.size === exp.size && [...exp].every(x => got.has(x));
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
const results = {
|
|
82
|
+
workingBefore_aliasesMatch: sameSet(workingBefore?.aliases || '', ['wkr1', 'wkr2']),
|
|
83
|
+
workingBefore_titleListsThem: /wkr1.*wkr2|wkr2.*wkr1/.test(workingBefore?.title || ''),
|
|
84
|
+
workingBefore_titleClickHint: /click to pin/.test(workingBefore?.title || ''),
|
|
85
|
+
onlineBefore_aliasesMatch: sameSet(onlineBefore?.aliases || '', ['wkr1', 'wkr2', 'idl1', 'idl2']),
|
|
86
|
+
onlineBefore_titleListsThem: /wkr1/.test(onlineBefore?.title || '') && /idl1/.test(onlineBefore?.title || ''),
|
|
87
|
+
pinnedWorking_aliasesStable: sameSet(workingPinned?.aliases || '', ['wkr1', 'wkr2']),
|
|
88
|
+
pinnedWorking_titleHintFlipped:/pinned, Esc to clear/.test(workingPinned?.title || ''),
|
|
89
|
+
};
|
|
90
|
+
const ok = Object.values(results).every(Boolean);
|
|
91
|
+
console.log(`${ok ? '✅' : '❌'} status-chip tooltip:`, JSON.stringify(results),
|
|
92
|
+
`\n workingBefore=`, workingBefore,
|
|
93
|
+
`\n onlineBefore=`, onlineBefore,
|
|
94
|
+
`\n workingPinned=`, workingPinned);
|
|
95
|
+
process.exit(ok ? 0 : 1);
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
/* Round 201 verification: the chip-row "N working" / "N online" chips
|
|
2
|
+
* adopt deeper versions of their own identity colour on hover,
|
|
3
|
+
* mirroring R193 active-links chip pattern.
|
|
4
|
+
*
|
|
5
|
+
* Pre-R201 hover working chip → R55 canvas dim + chip-row highlight,
|
|
6
|
+
* but chip itself stayed at bg-{color}-500/10 — cause silent, effect
|
|
7
|
+
* loud. R201 deepens 10→15 bg and 20→30 border on hover (only when
|
|
8
|
+
* the chip has a target count > 0). The inline transition list is
|
|
9
|
+
* extended to cover background-color + border-color so the swap
|
|
10
|
+
* eases instead of snapping (Tailwind transition-colors on the
|
|
11
|
+
* className alone would be overridden by the existing R180 inline
|
|
12
|
+
* box-shadow transition).
|
|
13
|
+
*
|
|
14
|
+
* Test (cyber dark, 4 working sessions):
|
|
15
|
+
* 1. Working chip: clickable='true', className has hover:bg-green-500/15
|
|
16
|
+
* + hover:border-green-500/30, transition includes 'background-color'
|
|
17
|
+
* + 'border-color' (both 200ms), inline still has 'box-shadow 150ms'.
|
|
18
|
+
* 2. Online chip: same shape with cyan hue.
|
|
19
|
+
* 3. Hover the working chip — wait past 220ms → computed bg
|
|
20
|
+
* shifts to a more-saturated/darker green (RGB-or-OKLab signal).
|
|
21
|
+
* 4. Move away — bg returns to idle (with margin past 220ms).
|
|
22
|
+
* 5. The chip's R55 canvas-effect setHoveredStatus still fires —
|
|
23
|
+
* verified via hoveredStatus change reflected on the working
|
|
24
|
+
* legend row's data-legend-row-lifted attribute.
|
|
25
|
+
*/
|
|
26
|
+
import { chromium } from 'playwright';
|
|
27
|
+
import { readFileSync } from 'node:fs';
|
|
28
|
+
|
|
29
|
+
const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
|
|
30
|
+
const browser = await chromium.launch({ headless: true });
|
|
31
|
+
|
|
32
|
+
const ctx = await browser.newContext({ viewport: { width: 1500, height: 1500 } });
|
|
33
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
34
|
+
await ctx.addInitScript(() => {
|
|
35
|
+
try { localStorage.setItem('anet-theme', 'cyber'); sessionStorage.setItem('anet_v3_auth', '1'); } catch {}
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
const fresh = new Date(Date.now() - 60 * 1000).toISOString();
|
|
39
|
+
await ctx.route('**/api/hub/status*', async (route) => {
|
|
40
|
+
const r = await route.fetch();
|
|
41
|
+
const b = await r.json();
|
|
42
|
+
const nid = (b.sessions || [])[0]?.network_id || 'default';
|
|
43
|
+
const mk = (alias) => ({
|
|
44
|
+
alias, status: 'working', model: 'claude-opus-4', runtime: 'cli-claude-code',
|
|
45
|
+
network_id: nid, project_dir: null,
|
|
46
|
+
created_at: fresh, updated_at: fresh, last_seen_at: fresh,
|
|
47
|
+
});
|
|
48
|
+
await route.fulfill({ response: r, json: { ...b, sessions: [
|
|
49
|
+
mk('alpha'), mk('beta'), mk('gamma'), mk('delta'),
|
|
50
|
+
] } });
|
|
51
|
+
});
|
|
52
|
+
await ctx.route('**/api/hub/messages*', (route) => route.fulfill({ json: { messages: [] } }));
|
|
53
|
+
await ctx.route('**/api/hub/tasks*', (route) => route.fulfill({ json: { tasks: [] } }));
|
|
54
|
+
|
|
55
|
+
const page = await ctx.newPage();
|
|
56
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
|
|
57
|
+
await page.waitForFunction(() => document.querySelectorAll('g[data-node]').length === 4, { timeout: 30000 });
|
|
58
|
+
await page.waitForSelector('[data-working-chip]', { timeout: 10000 });
|
|
59
|
+
await page.waitForTimeout(300);
|
|
60
|
+
|
|
61
|
+
const probeChip = async (selector) => page.evaluate((sel) => {
|
|
62
|
+
const el = document.querySelector(sel);
|
|
63
|
+
if (!el) return null;
|
|
64
|
+
const cs = getComputedStyle(el);
|
|
65
|
+
return {
|
|
66
|
+
className: el.getAttribute('class') || '',
|
|
67
|
+
clickable: el.getAttribute('data-working-chip-clickable') ||
|
|
68
|
+
el.getAttribute('data-online-chip-clickable'),
|
|
69
|
+
bg: cs.backgroundColor,
|
|
70
|
+
borderColor: cs.borderTopColor,
|
|
71
|
+
transition: el.style.transition,
|
|
72
|
+
};
|
|
73
|
+
}, selector);
|
|
74
|
+
|
|
75
|
+
const idleWorking = await probeChip('[data-working-chip]');
|
|
76
|
+
const idleOnline = await probeChip('[data-online-chip]');
|
|
77
|
+
|
|
78
|
+
await page.hover('[data-working-chip]');
|
|
79
|
+
await page.waitForTimeout(250);
|
|
80
|
+
const hoverWorking = await probeChip('[data-working-chip]');
|
|
81
|
+
|
|
82
|
+
// Confirm R55 canvas effect still fires — hoveredStatus='working'
|
|
83
|
+
// lifts the legend working row.
|
|
84
|
+
const workingRowLifted = await page.evaluate(() =>
|
|
85
|
+
document.querySelector('[data-legend-status="working"]')
|
|
86
|
+
?.getAttribute('data-legend-row-lifted'));
|
|
87
|
+
|
|
88
|
+
await page.mouse.move(0, 0);
|
|
89
|
+
await page.waitForTimeout(280);
|
|
90
|
+
const settledWorking = await probeChip('[data-working-chip]');
|
|
91
|
+
|
|
92
|
+
await page.hover('[data-online-chip]');
|
|
93
|
+
await page.waitForTimeout(250);
|
|
94
|
+
const hoverOnline = await probeChip('[data-online-chip]');
|
|
95
|
+
|
|
96
|
+
await page.mouse.move(0, 0);
|
|
97
|
+
await page.waitForTimeout(280);
|
|
98
|
+
const settledOnline = await probeChip('[data-online-chip]');
|
|
99
|
+
|
|
100
|
+
await browser.close();
|
|
101
|
+
|
|
102
|
+
// Tailwind 4 emits oklab/oklch / color-mix forms. Just check the bg
|
|
103
|
+
// string actually differs idle vs hover, and a brief parser confirms
|
|
104
|
+
// the channel that should grow (green for working, blue/green for cyan).
|
|
105
|
+
// Parse colors including alpha. R201's Tailwind /10 → /15 emits same
|
|
106
|
+
// OKLab L/a/b with stepped-up alpha (0.1 → 0.15); R193's gray→cyan
|
|
107
|
+
// pattern emits a different hue at any alpha. Both are "more saturated
|
|
108
|
+
// against the canvas" from the user's POV. Capture alpha and treat
|
|
109
|
+
// alpha-increase as a valid saturation signal alongside chroma growth.
|
|
110
|
+
function parseColor(s) {
|
|
111
|
+
if (!s) return null;
|
|
112
|
+
let m = s.match(/rgba?\(\s*(\d+)\s*,?\s*(\d+)\s*,?\s*(\d+)(?:\s*[,/]\s*([\d.]+))?/);
|
|
113
|
+
if (m) return { kind: 'rgb', r: +m[1], g: +m[2], b: +m[3], a: m[4] != null ? +m[4] : 1 };
|
|
114
|
+
m = s.match(/oklab\(\s*([\-\d.]+)\s+([\-\d.]+)\s+([\-\d.]+)(?:\s*\/\s*([\d.]+))?/);
|
|
115
|
+
if (m) return { kind: 'oklab', L: +m[1], a: +m[2], b: +m[3], alpha: m[4] != null ? +m[4] : 1 };
|
|
116
|
+
m = s.match(/oklch\(\s*([\-\d.]+)\s+([\-\d.]+)\s+([\-\d.]+)(?:\s*\/\s*([\d.]+))?/);
|
|
117
|
+
if (m) return { kind: 'oklch', L: +m[1], C: +m[2], h: +m[3], alpha: m[4] != null ? +m[4] : 1 };
|
|
118
|
+
return null;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// "More saturated against the canvas" = either chroma/hue distance
|
|
122
|
+
// from gray grew OR alpha grew (Tailwind /10 → /15 deepens by alpha).
|
|
123
|
+
const moreSaturated = (idle, hov) => {
|
|
124
|
+
if (!idle || !hov) return false;
|
|
125
|
+
if (idle.kind === 'rgb' && hov.kind === 'rgb') {
|
|
126
|
+
const chromaIdle = Math.max(idle.r, idle.g, idle.b) - Math.min(idle.r, idle.g, idle.b);
|
|
127
|
+
const chromaHov = Math.max(hov.r, hov.g, hov.b) - Math.min(hov.r, hov.g, hov.b);
|
|
128
|
+
return chromaHov > chromaIdle || hov.a > idle.a + 0.01;
|
|
129
|
+
}
|
|
130
|
+
if (idle.kind === 'oklab' && hov.kind === 'oklab') {
|
|
131
|
+
const dIdle = Math.hypot(idle.a, idle.b);
|
|
132
|
+
const dHov = Math.hypot(hov.a, hov.b);
|
|
133
|
+
return dHov > dIdle + 0.005 || hov.alpha > idle.alpha + 0.01;
|
|
134
|
+
}
|
|
135
|
+
if (idle.kind === 'oklch' && hov.kind === 'oklch') {
|
|
136
|
+
return hov.C > idle.C + 0.005 || hov.alpha > idle.alpha + 0.01;
|
|
137
|
+
}
|
|
138
|
+
return false;
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
const idleWorkingC = parseColor(idleWorking?.bg);
|
|
142
|
+
const hoverWorkingC = parseColor(hoverWorking?.bg);
|
|
143
|
+
const idleOnlineC = parseColor(idleOnline?.bg);
|
|
144
|
+
const hoverOnlineC = parseColor(hoverOnline?.bg);
|
|
145
|
+
|
|
146
|
+
const results = {
|
|
147
|
+
working_clickable: idleWorking?.clickable === 'true',
|
|
148
|
+
working_className_has_hover: idleWorking?.className.includes('hover:bg-green-500/15')
|
|
149
|
+
&& idleWorking?.className.includes('hover:border-green-500/30'),
|
|
150
|
+
working_transition_includes_bg: /background-color\s+(?:200ms|0\.2s)/.test(idleWorking?.transition || ''),
|
|
151
|
+
working_transition_includes_border: /border-color\s+(?:200ms|0\.2s)/.test(idleWorking?.transition || ''),
|
|
152
|
+
working_transition_keeps_boxshadow: /box-shadow\s+(?:150ms|0\.15s)/.test(idleWorking?.transition || ''),
|
|
153
|
+
working_hover_bg_changed: idleWorking?.bg !== hoverWorking?.bg,
|
|
154
|
+
working_hover_more_saturated: moreSaturated(idleWorkingC, hoverWorkingC),
|
|
155
|
+
working_settles_back: settledWorking?.bg === idleWorking?.bg,
|
|
156
|
+
// R55 canvas-effect still fires from the chip — hovering the
|
|
157
|
+
// working chip lifts the legend working row.
|
|
158
|
+
working_canvas_effect_fires: workingRowLifted === 'true',
|
|
159
|
+
|
|
160
|
+
online_clickable: idleOnline?.clickable === 'true',
|
|
161
|
+
online_className_has_hover: idleOnline?.className.includes('hover:bg-cyan-500/15')
|
|
162
|
+
&& idleOnline?.className.includes('hover:border-cyan-500/30'),
|
|
163
|
+
online_transition_includes_bg: /background-color\s+(?:200ms|0\.2s)/.test(idleOnline?.transition || ''),
|
|
164
|
+
online_transition_includes_border: /border-color\s+(?:200ms|0\.2s)/.test(idleOnline?.transition || ''),
|
|
165
|
+
online_hover_bg_changed: idleOnline?.bg !== hoverOnline?.bg,
|
|
166
|
+
online_hover_more_saturated: moreSaturated(idleOnlineC, hoverOnlineC),
|
|
167
|
+
online_settles_back: settledOnline?.bg === idleOnline?.bg,
|
|
168
|
+
};
|
|
169
|
+
const ok = Object.values(results).every(Boolean);
|
|
170
|
+
console.log(`${ok ? '✅' : '❌'} status-bar chips self-hover:`, JSON.stringify(results),
|
|
171
|
+
`\n idleWorking:`, idleWorking,
|
|
172
|
+
`\n hoverWorking:`, hoverWorking,
|
|
173
|
+
`\n settledWorking:`, settledWorking,
|
|
174
|
+
`\n idleOnline:`, idleOnline,
|
|
175
|
+
`\n hoverOnline:`, hoverOnline,
|
|
176
|
+
`\n settledOnline:`, settledOnline);
|
|
177
|
+
process.exit(ok ? 0 : 1);
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/* Round 156 verification: SVG <g> interactives gain
|
|
2
|
+
* `.anet-topo-svg-focus` for keyboard focus outline.
|
|
3
|
+
*
|
|
4
|
+
* Mirrors R155's chip-row treatment at the SVG scope. 6 surfaces:
|
|
5
|
+
* data-node (R151 node body)
|
|
6
|
+
* data-group-label-hit (R63 group label)
|
|
7
|
+
* data-edge-count-badge (R121 edge badge)
|
|
8
|
+
* data-recent-row (R116 recent-signal row)
|
|
9
|
+
* data-recent-panel-more-nav (R133 "+N more" footer)
|
|
10
|
+
* data-legend-status (R61 legend row)
|
|
11
|
+
*
|
|
12
|
+
* Class `.anet-topo-svg-focus:focus-visible` paints outline 2px
|
|
13
|
+
* cyan-300 (#67e8f9) with 2px outline-offset. Browser default
|
|
14
|
+
* focus ring on SVG is hard to spot against the dashboard
|
|
15
|
+
* canvas; explicit cyan matches the legendAccent palette.
|
|
16
|
+
*
|
|
17
|
+
* Test: every SVG interactive surface carries the class.
|
|
18
|
+
*/
|
|
19
|
+
import { chromium } from 'playwright';
|
|
20
|
+
import { readFileSync } from 'node:fs';
|
|
21
|
+
|
|
22
|
+
const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
|
|
23
|
+
const browser = await chromium.launch({ headless: true });
|
|
24
|
+
|
|
25
|
+
const ctx = await browser.newContext({ viewport: { width: 1600, height: 1500 } });
|
|
26
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
27
|
+
await ctx.addInitScript(() => {
|
|
28
|
+
try {
|
|
29
|
+
localStorage.setItem('anet-theme', 'cyber');
|
|
30
|
+
sessionStorage.setItem('anet_v3_auth', '1');
|
|
31
|
+
// grid layout to surface group labels
|
|
32
|
+
localStorage.setItem('anet-topo-layout', 'grid');
|
|
33
|
+
} catch {}
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
const fresh = new Date(Date.now() - 60 * 1000).toISOString();
|
|
37
|
+
await ctx.route('**/api/hub/status*', async (route) => {
|
|
38
|
+
const r = await route.fetch();
|
|
39
|
+
const b = await r.json();
|
|
40
|
+
const nid = (b.sessions || [])[0]?.network_id || 'default';
|
|
41
|
+
const mk = (alias, status) => ({
|
|
42
|
+
alias, status, model: 'claude-opus-4', runtime: 'cli-claude-code',
|
|
43
|
+
network_id: nid, project_dir: null,
|
|
44
|
+
created_at: fresh, updated_at: fresh, last_seen_at: fresh,
|
|
45
|
+
});
|
|
46
|
+
await route.fulfill({ response: r, json: { ...b, sessions: [
|
|
47
|
+
mk('agents-a1', 'working'), mk('agents-a2', 'working'),
|
|
48
|
+
mk('infra-b1', 'working'),
|
|
49
|
+
] } });
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
const now = Date.now();
|
|
53
|
+
// Edge midpoint count badge (R100) only renders when link.count >= 3.
|
|
54
|
+
// Pair agents-a1 → agents-a2 gets 4 msgs to clear the threshold; add 4
|
|
55
|
+
// other singletons so flowLinks.length = 5 → R128 "+ 2 more flows"
|
|
56
|
+
// footer also renders.
|
|
57
|
+
const msgs = [];
|
|
58
|
+
for (let i = 0; i < 4; i++) {
|
|
59
|
+
msgs.push({
|
|
60
|
+
id: `a2a${i}`, from_alias: 'agents-a1', to_alias: 'agents-a2', content: 'hi',
|
|
61
|
+
network_id: 'default', created_at: new Date(now - (10000 + i * 500)).toISOString(),
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
msgs.push({ id: 'm1', from_alias: 'agents-a2', to_alias: 'infra-b1', content: 'hi',
|
|
65
|
+
network_id: 'default', created_at: new Date(now - 11000).toISOString() });
|
|
66
|
+
msgs.push({ id: 'm2', from_alias: 'infra-b1', to_alias: 'agents-a1', content: 'hi',
|
|
67
|
+
network_id: 'default', created_at: new Date(now - 12000).toISOString() });
|
|
68
|
+
msgs.push({ id: 'm3', from_alias: 'agents-a1', to_alias: 'infra-b1', content: 'hi',
|
|
69
|
+
network_id: 'default', created_at: new Date(now - 13000).toISOString() });
|
|
70
|
+
msgs.push({ id: 'm4', from_alias: 'agents-a2', to_alias: 'agents-a1', content: 'hi',
|
|
71
|
+
network_id: 'default', created_at: new Date(now - 14000).toISOString() });
|
|
72
|
+
await ctx.route('**/api/hub/messages*', (route) => route.fulfill({ json: { messages: msgs } }));
|
|
73
|
+
await ctx.route('**/api/hub/tasks*', (route) => route.fulfill({ json: { tasks: [] } }));
|
|
74
|
+
|
|
75
|
+
const page = await ctx.newPage();
|
|
76
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
|
|
77
|
+
await page.waitForFunction(() => document.querySelectorAll('g[data-node]').length === 3, { timeout: 30000 });
|
|
78
|
+
await page.waitForSelector('[data-recent-row]', { timeout: 10000 });
|
|
79
|
+
await page.waitForSelector('[data-recent-panel-more-nav]', { timeout: 10000 });
|
|
80
|
+
await page.waitForSelector('[data-edge-count-badge]', { timeout: 10000 });
|
|
81
|
+
await page.waitForSelector('[data-group-label-hit]', { timeout: 10000 });
|
|
82
|
+
await page.waitForTimeout(400);
|
|
83
|
+
|
|
84
|
+
const out = await page.evaluate(() => {
|
|
85
|
+
const has = (sel) => {
|
|
86
|
+
const el = document.querySelector(sel);
|
|
87
|
+
return el && (el.getAttribute('class') || '').includes('anet-topo-svg-focus');
|
|
88
|
+
};
|
|
89
|
+
return {
|
|
90
|
+
nodeBody: has('g[data-node]'),
|
|
91
|
+
groupLabel: has('[data-group-label-hit]'),
|
|
92
|
+
edgeCountBadge: has('[data-edge-count-badge]'),
|
|
93
|
+
recentRow: has('[data-recent-row]'),
|
|
94
|
+
recentPanelMoreNav: has('[data-recent-panel-more-nav]'),
|
|
95
|
+
legendStatusRow: has('[data-legend-status="working"]'),
|
|
96
|
+
};
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
await browser.close();
|
|
100
|
+
|
|
101
|
+
const results = {
|
|
102
|
+
nodeBody_focus: out.nodeBody === true,
|
|
103
|
+
groupLabel_focus: out.groupLabel === true,
|
|
104
|
+
edgeCountBadge_focus: out.edgeCountBadge === true,
|
|
105
|
+
recentRow_focus: out.recentRow === true,
|
|
106
|
+
recentPanelMoreNav_focus: out.recentPanelMoreNav === true,
|
|
107
|
+
legendStatusRow_focus: out.legendStatusRow === true,
|
|
108
|
+
};
|
|
109
|
+
const ok = Object.values(results).every(Boolean);
|
|
110
|
+
console.log(`${ok ? '✅' : '❌'} SVG focus class:`, JSON.stringify(results),
|
|
111
|
+
`\n raw=`, out);
|
|
112
|
+
process.exit(ok ? 0 : 1);
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/* Round 146 verification: R45 radar sweep rotation rate buckets on
|
|
2
|
+
* workingCount, completing the 5-layer busyness-driven motion family:
|
|
3
|
+
*
|
|
4
|
+
* R84 hub grounding-halo breath — 4 / 3.2 / 2.7 / 2.4 s
|
|
5
|
+
* R131 outer-ring orbit period — 16 / 14 / 12 / 10 s
|
|
6
|
+
* R132 groupbox marching ants — 14 / 12 / 10 / 8 s (grid only)
|
|
7
|
+
* R145 idle-spoke flow rate — 2.8 / 2.4 / 2.0 / 1.6 s (ring only)
|
|
8
|
+
* R146 radar sweep rotation — 8 / 6 / 4 / 3 s (both layouts)
|
|
9
|
+
*
|
|
10
|
+
* Shared R84 thresholds (0 / 1-2 / 3-5 / 6+) drive every layer. The
|
|
11
|
+
* sweep is the only layer visible in BOTH layouts and ties the family
|
|
12
|
+
* together at the canvas-wide scope.
|
|
13
|
+
*
|
|
14
|
+
* R45 baseline 6s sits at bucket 1 — preserved when workingCount in
|
|
15
|
+
* [1, 2] so existing demos and screenshots stay identical.
|
|
16
|
+
*/
|
|
17
|
+
import { chromium } from 'playwright';
|
|
18
|
+
import { readFileSync } from 'node:fs';
|
|
19
|
+
|
|
20
|
+
const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
|
|
21
|
+
|
|
22
|
+
async function probe(workingCount, totalCount) {
|
|
23
|
+
const browser = await chromium.launch({ headless: true });
|
|
24
|
+
const ctx = await browser.newContext({ viewport: { width: 1400, height: 1500 } });
|
|
25
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
26
|
+
await ctx.addInitScript(() => {
|
|
27
|
+
try { localStorage.setItem('anet-theme', 'cyber'); sessionStorage.setItem('anet_v3_auth', '1'); } catch {}
|
|
28
|
+
});
|
|
29
|
+
const fresh = new Date(Date.now() - 60 * 1000).toISOString();
|
|
30
|
+
await ctx.route('**/api/hub/status*', async (route) => {
|
|
31
|
+
const r = await route.fetch();
|
|
32
|
+
const b = await r.json();
|
|
33
|
+
const nid = (b.sessions || [])[0]?.network_id || 'default';
|
|
34
|
+
const sessions = [];
|
|
35
|
+
for (let i = 0; i < totalCount; i++) {
|
|
36
|
+
sessions.push({
|
|
37
|
+
alias: `node${i}`,
|
|
38
|
+
status: i < workingCount ? 'working' : 'idle',
|
|
39
|
+
model: 'claude-opus-4', runtime: 'cli-claude-code',
|
|
40
|
+
network_id: nid, project_dir: null,
|
|
41
|
+
created_at: fresh, updated_at: fresh, last_seen_at: fresh,
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
await route.fulfill({ response: r, json: { ...b, sessions } });
|
|
45
|
+
});
|
|
46
|
+
await ctx.route('**/api/hub/messages*', (route) => route.fulfill({ json: { messages: [] } }));
|
|
47
|
+
await ctx.route('**/api/hub/tasks*', (route) => route.fulfill({ json: { tasks: [] } }));
|
|
48
|
+
|
|
49
|
+
const page = await ctx.newPage();
|
|
50
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
|
|
51
|
+
await page.waitForFunction((n) => document.querySelectorAll('g[data-node]').length === n, totalCount, { timeout: 30000 });
|
|
52
|
+
await page.waitForSelector('.anet-topo-sweep', { timeout: 10000 });
|
|
53
|
+
await page.waitForTimeout(400);
|
|
54
|
+
|
|
55
|
+
const out = await page.evaluate(() => {
|
|
56
|
+
const g = document.querySelector('.anet-topo-sweep');
|
|
57
|
+
return {
|
|
58
|
+
bucket: g?.getAttribute('data-topo-sweep-bucket'),
|
|
59
|
+
dur: g?.getAttribute('data-topo-sweep-dur'),
|
|
60
|
+
cssDur: g ? getComputedStyle(g).getPropertyValue('animation-duration').trim() : null,
|
|
61
|
+
};
|
|
62
|
+
});
|
|
63
|
+
await browser.close();
|
|
64
|
+
return out;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const b0 = await probe(0, 4); // 0 working → bucket 0 (8s)
|
|
68
|
+
const b1 = await probe(2, 4); // 2 working → bucket 1 (6s, R45 baseline)
|
|
69
|
+
const b2 = await probe(4, 5); // 4 working → bucket 2 (4s)
|
|
70
|
+
const b3 = await probe(7, 8); // 7 working → bucket 3 (3s)
|
|
71
|
+
|
|
72
|
+
const consistent = (probe, bucket, dur) =>
|
|
73
|
+
probe.bucket === String(bucket) && probe.dur === String(dur) && probe.cssDur === `${dur}s`;
|
|
74
|
+
|
|
75
|
+
const results = {
|
|
76
|
+
b0_bucket0_8s: consistent(b0, 0, 8),
|
|
77
|
+
b1_bucket1_6s: consistent(b1, 1, 6),
|
|
78
|
+
b2_bucket2_4s: consistent(b2, 2, 4),
|
|
79
|
+
b3_bucket3_3s: consistent(b3, 3, 3),
|
|
80
|
+
// dur strictly decreases as busy climbs
|
|
81
|
+
dur_monotonic:
|
|
82
|
+
Number(b0.dur) > Number(b1.dur) &&
|
|
83
|
+
Number(b1.dur) > Number(b2.dur) &&
|
|
84
|
+
Number(b2.dur) > Number(b3.dur),
|
|
85
|
+
// R45 baseline preservation: bucket 1 still 6s
|
|
86
|
+
baseline_preserved: b1.dur === '6',
|
|
87
|
+
};
|
|
88
|
+
const ok = Object.values(results).every(Boolean);
|
|
89
|
+
console.log(`${ok ? '✅' : '❌'} sweep busyness:`, JSON.stringify(results),
|
|
90
|
+
`\n b0(0w/4)=`, b0,
|
|
91
|
+
`\n b1(2w/4)=`, b1,
|
|
92
|
+
`\n b2(4w/5)=`, b2,
|
|
93
|
+
`\n b3(7w/8)=`, b3);
|
|
94
|
+
process.exit(ok ? 0 : 1);
|