@sleep2agi/agent-network-dashboard 0.4.6-preview.33 → 0.4.6-preview.331
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.next/BUILD_ID +1 -1
- package/.next/build-manifest.json +3 -3
- package/.next/diagnostics/route-bundle-stats.json +41 -41
- package/.next/fallback-build-manifest.json +3 -3
- package/.next/prerender-manifest.json +3 -3
- package/.next/server/app/_global-error.html +1 -1
- package/.next/server/app/_global-error.rsc +1 -1
- package/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
- package/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/.next/server/app/_not-found.html +2 -2
- package/.next/server/app/_not-found.rsc +12 -12
- package/.next/server/app/_not-found.segments/_full.segment.rsc +12 -12
- package/.next/server/app/_not-found.segments/_head.segment.rsc +4 -4
- package/.next/server/app/_not-found.segments/_index.segment.rsc +7 -7
- package/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +2 -2
- package/.next/server/app/_not-found.segments/_not-found.segment.rsc +3 -3
- package/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/admin/page_client-reference-manifest.js +1 -1
- package/.next/server/app/admin.html +2 -2
- package/.next/server/app/admin.rsc +14 -14
- package/.next/server/app/admin.segments/_full.segment.rsc +14 -14
- package/.next/server/app/admin.segments/_head.segment.rsc +4 -4
- package/.next/server/app/admin.segments/_index.segment.rsc +7 -7
- package/.next/server/app/admin.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/admin.segments/admin/__PAGE__.segment.rsc +4 -4
- package/.next/server/app/admin.segments/admin.segment.rsc +3 -3
- package/.next/server/app/index.html +2 -2
- package/.next/server/app/index.rsc +14 -14
- package/.next/server/app/index.segments/__PAGE__.segment.rsc +4 -4
- package/.next/server/app/index.segments/_full.segment.rsc +14 -14
- package/.next/server/app/index.segments/_head.segment.rsc +4 -4
- package/.next/server/app/index.segments/_index.segment.rsc +7 -7
- package/.next/server/app/index.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/login/page_client-reference-manifest.js +1 -1
- package/.next/server/app/login.html +2 -2
- package/.next/server/app/login.rsc +14 -14
- package/.next/server/app/login.segments/_full.segment.rsc +14 -14
- package/.next/server/app/login.segments/_head.segment.rsc +4 -4
- package/.next/server/app/login.segments/_index.segment.rsc +7 -7
- package/.next/server/app/login.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/login.segments/login/__PAGE__.segment.rsc +4 -4
- package/.next/server/app/login.segments/login.segment.rsc +3 -3
- package/.next/server/app/logs/page_client-reference-manifest.js +1 -1
- package/.next/server/app/logs.html +2 -2
- package/.next/server/app/logs.rsc +14 -14
- package/.next/server/app/logs.segments/_full.segment.rsc +14 -14
- package/.next/server/app/logs.segments/_head.segment.rsc +4 -4
- package/.next/server/app/logs.segments/_index.segment.rsc +7 -7
- package/.next/server/app/logs.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/logs.segments/logs/__PAGE__.segment.rsc +4 -4
- package/.next/server/app/logs.segments/logs.segment.rsc +3 -3
- package/.next/server/app/messages/page_client-reference-manifest.js +1 -1
- package/.next/server/app/messages.html +2 -2
- package/.next/server/app/messages.rsc +14 -14
- package/.next/server/app/messages.segments/_full.segment.rsc +14 -14
- package/.next/server/app/messages.segments/_head.segment.rsc +4 -4
- package/.next/server/app/messages.segments/_index.segment.rsc +7 -7
- package/.next/server/app/messages.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/messages.segments/messages/__PAGE__.segment.rsc +4 -4
- package/.next/server/app/messages.segments/messages.segment.rsc +3 -3
- package/.next/server/app/node/page_client-reference-manifest.js +1 -1
- package/.next/server/app/node.html +2 -2
- package/.next/server/app/node.rsc +14 -14
- package/.next/server/app/node.segments/_full.segment.rsc +14 -14
- package/.next/server/app/node.segments/_head.segment.rsc +4 -4
- package/.next/server/app/node.segments/_index.segment.rsc +7 -7
- package/.next/server/app/node.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/node.segments/node/__PAGE__.segment.rsc +4 -4
- package/.next/server/app/node.segments/node.segment.rsc +3 -3
- package/.next/server/app/nodes/page_client-reference-manifest.js +1 -1
- package/.next/server/app/nodes.html +2 -2
- package/.next/server/app/nodes.rsc +14 -14
- package/.next/server/app/nodes.segments/_full.segment.rsc +14 -14
- package/.next/server/app/nodes.segments/_head.segment.rsc +4 -4
- package/.next/server/app/nodes.segments/_index.segment.rsc +7 -7
- package/.next/server/app/nodes.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/nodes.segments/nodes/__PAGE__.segment.rsc +4 -4
- package/.next/server/app/nodes.segments/nodes.segment.rsc +3 -3
- package/.next/server/app/page_client-reference-manifest.js +1 -1
- package/.next/server/app/server-logs/page_client-reference-manifest.js +1 -1
- package/.next/server/app/server-logs.html +2 -2
- package/.next/server/app/server-logs.rsc +14 -14
- package/.next/server/app/server-logs.segments/_full.segment.rsc +14 -14
- package/.next/server/app/server-logs.segments/_head.segment.rsc +4 -4
- package/.next/server/app/server-logs.segments/_index.segment.rsc +7 -7
- package/.next/server/app/server-logs.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/server-logs.segments/server-logs/__PAGE__.segment.rsc +4 -4
- package/.next/server/app/server-logs.segments/server-logs.segment.rsc +3 -3
- package/.next/server/app/settings/networks/page_client-reference-manifest.js +1 -1
- package/.next/server/app/settings/networks.html +2 -2
- package/.next/server/app/settings/networks.rsc +14 -14
- package/.next/server/app/settings/networks.segments/_full.segment.rsc +14 -14
- package/.next/server/app/settings/networks.segments/_head.segment.rsc +4 -4
- package/.next/server/app/settings/networks.segments/_index.segment.rsc +7 -7
- package/.next/server/app/settings/networks.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/settings/networks.segments/settings/networks/__PAGE__.segment.rsc +4 -4
- package/.next/server/app/settings/networks.segments/settings/networks.segment.rsc +3 -3
- package/.next/server/app/settings/networks.segments/settings.segment.rsc +3 -3
- package/.next/server/app/settings/page_client-reference-manifest.js +1 -1
- package/.next/server/app/settings/tokens/page_client-reference-manifest.js +1 -1
- package/.next/server/app/settings/tokens.html +2 -2
- package/.next/server/app/settings/tokens.rsc +14 -14
- package/.next/server/app/settings/tokens.segments/_full.segment.rsc +14 -14
- package/.next/server/app/settings/tokens.segments/_head.segment.rsc +4 -4
- package/.next/server/app/settings/tokens.segments/_index.segment.rsc +7 -7
- package/.next/server/app/settings/tokens.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/settings/tokens.segments/settings/tokens/__PAGE__.segment.rsc +4 -4
- package/.next/server/app/settings/tokens.segments/settings/tokens.segment.rsc +3 -3
- package/.next/server/app/settings/tokens.segments/settings.segment.rsc +3 -3
- package/.next/server/app/settings.html +2 -2
- package/.next/server/app/settings.rsc +14 -14
- package/.next/server/app/settings.segments/_full.segment.rsc +14 -14
- package/.next/server/app/settings.segments/_head.segment.rsc +4 -4
- package/.next/server/app/settings.segments/_index.segment.rsc +7 -7
- package/.next/server/app/settings.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/settings.segments/settings/__PAGE__.segment.rsc +4 -4
- package/.next/server/app/settings.segments/settings.segment.rsc +3 -3
- package/.next/server/app/tasks/[id]/page_client-reference-manifest.js +1 -1
- package/.next/server/app/tasks/page_client-reference-manifest.js +1 -1
- package/.next/server/app/tasks.html +2 -2
- package/.next/server/app/tasks.rsc +14 -14
- package/.next/server/app/tasks.segments/_full.segment.rsc +14 -14
- package/.next/server/app/tasks.segments/_head.segment.rsc +4 -4
- package/.next/server/app/tasks.segments/_index.segment.rsc +7 -7
- package/.next/server/app/tasks.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/tasks.segments/tasks/__PAGE__.segment.rsc +4 -4
- package/.next/server/app/tasks.segments/tasks.segment.rsc +3 -3
- package/.next/server/chunks/ssr/[root-of-the-server]__03b.f76._.js +1 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__03b.f76._.js.map +1 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__0fhoq8i._.js +1 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__0fhoq8i._.js.map +1 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__0nw~zhp._.js +1 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__0nw~zhp._.js.map +1 -1
- package/.next/server/chunks/ssr/agent-network-dashboard_09kk21a._.js +4 -1
- package/.next/server/chunks/ssr/agent-network-dashboard_09kk21a._.js.map +1 -1
- package/.next/server/chunks/ssr/agent-network-dashboard_app_01jhlxz._.js +1 -1
- package/.next/server/chunks/ssr/agent-network-dashboard_app_01jhlxz._.js.map +1 -1
- package/.next/server/chunks/ssr/agent-network-dashboard_app_057q.ne._.js +1 -1
- package/.next/server/chunks/ssr/agent-network-dashboard_app_057q.ne._.js.map +1 -1
- package/.next/server/chunks/ssr/agent-network-dashboard_app_09d29my._.js +1 -1
- package/.next/server/chunks/ssr/agent-network-dashboard_app_09d29my._.js.map +1 -1
- package/.next/server/chunks/ssr/agent-network-dashboard_app_0_d45-d._.js +1 -1
- package/.next/server/chunks/ssr/agent-network-dashboard_app_0_d45-d._.js.map +1 -1
- package/.next/server/chunks/ssr/agent-network-dashboard_app_0i3759l._.js +1 -1
- package/.next/server/chunks/ssr/agent-network-dashboard_app_0i3759l._.js.map +1 -1
- package/.next/server/chunks/ssr/agent-network-dashboard_app_0xgney8._.js +1 -1
- package/.next/server/chunks/ssr/agent-network-dashboard_app_0xgney8._.js.map +1 -1
- package/.next/server/chunks/ssr/agent-network-dashboard_app_10hjgv4._.js +1 -1
- package/.next/server/chunks/ssr/agent-network-dashboard_app_10hjgv4._.js.map +1 -1
- package/.next/server/chunks/ssr/agent-network-dashboard_app_1153xeb._.js +1 -1
- package/.next/server/chunks/ssr/agent-network-dashboard_app_1153xeb._.js.map +1 -1
- package/.next/server/chunks/ssr/agent-network-dashboard_app_12l4oto._.js +1 -1
- package/.next/server/chunks/ssr/agent-network-dashboard_app_12l4oto._.js.map +1 -1
- package/.next/server/chunks/ssr/agent-network-dashboard_app_components_0mvyi-4._.js +1 -1
- package/.next/server/chunks/ssr/agent-network-dashboard_app_components_0mvyi-4._.js.map +1 -1
- package/.next/server/middleware-build-manifest.js +3 -3
- package/.next/server/pages/404.html +2 -2
- package/.next/server/pages/500.html +1 -1
- package/.next/server/server-reference-manifest.js +1 -1
- package/.next/server/server-reference-manifest.json +1 -1
- package/.next/static/chunks/0-mpa_947ipeq.js +1 -0
- package/.next/static/chunks/01lmbsd37fybu.js +1 -0
- package/.next/static/chunks/03o.h6kvmw4l_.js +1 -0
- package/.next/static/chunks/03~~oirxz7~vc.js +1 -0
- package/.next/static/chunks/05uk96gc~9mni.js +1 -0
- package/.next/static/chunks/07lsi~s-c0wvh.css +2 -0
- package/.next/static/chunks/08kf-.bgs10ze.js +1 -0
- package/.next/static/chunks/0ggj5ummw2a84.js +7 -0
- package/.next/static/chunks/0glmrdj9112tc.js +7 -0
- package/.next/static/chunks/0mpa-fgyi2k78.js +1 -0
- package/.next/static/chunks/0nlhul7k4hwil.js +1 -0
- package/.next/static/chunks/0rxrez_cjn.eh.js +1 -0
- package/.next/static/chunks/0x8x.29hkju5a.js +1 -0
- package/.next/static/chunks/174re5ar~kxne.js +1 -0
- package/.next/static/chunks/1851sbdemt00t.js +4 -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 +111 -1
- package/app/components/TopoGraph.tsx +6197 -262
- package/app/components/utils.ts +8 -7
- package/app/globals.css +110 -5
- package/app/lib/time.ts +36 -0
- package/app/lib/vendorIdentity.ts +14 -3
- package/package.json +2 -2
- package/public/sleep2agi-logo.svg +11 -0
- package/public/vendors/claude.svg +11 -0
- package/public/vendors/minimax.svg +11 -0
- package/public/vendors/openai.svg +12 -0
- package/screenshots/r293-p0/after-full.png +0 -0
- package/screenshots/r293-p0/after-topo.png +0 -0
- package/screenshots/r293-p0/baseline-full.png +0 -0
- package/screenshots/r293-p0/baseline-topo.png +0 -0
- package/screenshots/r293-p0/logo-integrated-full.png +0 -0
- package/screenshots/r293-p0/logo-integrated-topo.png +0 -0
- package/screenshots/r293-p0/v0.10.0-hero3-rfc.md +230 -0
- package/scripts/p0-topo-screenshot.mjs +82 -0
- package/scripts/topo-active-filter-pill-test.mjs +101 -0
- package/scripts/topo-active-links-chip-hover-test.mjs +103 -0
- package/scripts/topo-active-links-chip-nav-test.mjs +117 -0
- package/scripts/topo-active-links-chip-self-hover-test.mjs +171 -0
- package/scripts/topo-active-links-chip-test.mjs +73 -0
- package/scripts/topo-active-links-empty-recede-test.mjs +125 -0
- package/scripts/topo-active-links-freshness-test.mjs +113 -0
- package/scripts/topo-active-links-tooltip-test.mjs +79 -0
- package/scripts/topo-active-pulse-ease-test.mjs +120 -0
- package/scripts/topo-auto-fit-test.mjs +73 -0
- package/scripts/topo-brand-logo-transition-test.mjs +94 -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-chiprow-data-weight-test.mjs +94 -0
- package/scripts/topo-chrome-a11y-test.mjs +107 -0
- package/scripts/topo-chrome-focus-ring-unify-test.mjs +100 -0
- package/scripts/topo-chrome-icon-stroke-test.mjs +95 -0
- package/scripts/topo-chrome-inactive-color-test.mjs +90 -0
- package/scripts/topo-chrome-pop-extension-test.mjs +98 -0
- package/scripts/topo-chrome-pop-nodesize-test.mjs +88 -0
- package/scripts/topo-chrome-press-state-test.mjs +135 -0
- package/scripts/topo-chrome-strip-semantic-gap-test.mjs +99 -0
- package/scripts/topo-chrome-strip-theme-ease-test.mjs +99 -0
- package/scripts/topo-chrome-zoom-level-pop-test.mjs +122 -0
- package/scripts/topo-chrome-zoom-pop-test.mjs +130 -0
- package/scripts/topo-chrome-zoom-readout-weight-test.mjs +81 -0
- package/scripts/topo-click-ripple-ease-test.mjs +94 -0
- package/scripts/topo-cmdk-edge-clear-test.mjs +109 -0
- package/scripts/topo-cmdk-layout-view-test.mjs +108 -0
- package/scripts/topo-cmdk-pin-test.mjs +123 -0
- package/scripts/topo-cmdk-vendor-clear-test.mjs +133 -0
- package/scripts/topo-cmdk-vendor-pin-test.mjs +103 -0
- package/scripts/topo-corner-radius-unify-test.mjs +103 -0
- package/scripts/topo-cwd-tooltip-test.mjs +64 -0
- package/scripts/topo-dblclick-reset-test.mjs +74 -0
- package/scripts/topo-dense-alias-fill-transition-test.mjs +133 -0
- package/scripts/topo-discrete-zoom-smooth-test.mjs +125 -0
- package/scripts/topo-edge-badge-click-pin-test.mjs +94 -0
- package/scripts/topo-edge-badge-crossfade-test.mjs +138 -0
- package/scripts/topo-edge-badge-hot-test.mjs +115 -0
- package/scripts/topo-edge-badge-hover-test.mjs +85 -0
- package/scripts/topo-edge-badge-lift-test.mjs +150 -0
- package/scripts/topo-edge-badge-ripple-test.mjs +111 -0
- package/scripts/topo-edge-badge-stroke-transition-test.mjs +118 -0
- package/scripts/topo-edge-badge-text-pin-test.mjs +121 -0
- package/scripts/topo-edge-badge-theme-ease-test.mjs +89 -0
- package/scripts/topo-edge-count-badge-test.mjs +86 -0
- package/scripts/topo-edge-endpoint-highlight-test.mjs +111 -0
- package/scripts/topo-edge-fadein-test.mjs +106 -0
- package/scripts/topo-edge-focus-test.mjs +113 -0
- package/scripts/topo-edge-hover-test.mjs +93 -0
- package/scripts/topo-edge-pill-hot-test.mjs +129 -0
- package/scripts/topo-edge-pill-test.mjs +105 -0
- package/scripts/topo-edge-ping-pulse-retired-test.mjs +119 -0
- package/scripts/topo-edge-stroke-ease-test.mjs +100 -0
- package/scripts/topo-edge-stroke-transition-test.mjs +132 -0
- package/scripts/topo-edge-tooltip-test.mjs +70 -0
- package/scripts/topo-empty-hint-tracking-test.mjs +84 -0
- package/scripts/topo-empty-state-breath-test.mjs +150 -0
- package/scripts/topo-empty-state-crossfade-test.mjs +130 -0
- package/scripts/topo-empty-state-recenter-test.mjs +107 -0
- package/scripts/topo-empty-subhint-tracking-test.mjs +87 -0
- package/scripts/topo-endpoint-ring-fade-test.mjs +132 -0
- package/scripts/topo-endpoint-ring-test.mjs +93 -0
- package/scripts/topo-endpoint-ring-thicken-test.mjs +112 -0
- package/scripts/topo-esc-clears-pin-test.mjs +98 -0
- package/scripts/topo-filter-pill-aliases-test.mjs +121 -0
- package/scripts/topo-filter-pill-body-click-test.mjs +112 -0
- package/scripts/topo-filter-pill-count-test.mjs +110 -0
- package/scripts/topo-filter-pill-mobile-test.mjs +90 -0
- package/scripts/topo-fit-key-test.mjs +106 -0
- package/scripts/topo-freshness-chip-test.mjs +74 -0
- package/scripts/topo-freshness-chip-transition-test.mjs +80 -0
- package/scripts/topo-freshness-chip-weight-test.mjs +90 -0
- package/scripts/topo-freshness-conditional-render-test.mjs +92 -0
- package/scripts/topo-fullscreen-active-test.mjs +115 -0
- package/scripts/topo-group-box-pinned-state-test.mjs +95 -0
- package/scripts/topo-group-count-test.mjs +6 -1
- package/scripts/topo-group-label-a11y-test.mjs +113 -0
- package/scripts/topo-group-label-count-inherit-test.mjs +99 -0
- package/scripts/topo-group-label-hover-test.mjs +119 -0
- package/scripts/topo-group-label-pin-spacing-test.mjs +136 -0
- package/scripts/topo-group-label-tint-test.mjs +99 -0
- package/scripts/topo-group-label-title-test.mjs +83 -0
- package/scripts/topo-group-pin-test.mjs +119 -0
- package/scripts/topo-group-pip-fadein-test.mjs +100 -0
- package/scripts/topo-group-pip-tabular-test.mjs +95 -0
- package/scripts/topo-group-status-pips-test.mjs +103 -0
- package/scripts/topo-groupbox-fadein-test.mjs +95 -0
- package/scripts/topo-groupbox-hover-lift-test.mjs +127 -0
- package/scripts/topo-groupbox-hubcore-ease-test.mjs +106 -0
- package/scripts/topo-groupbox-live-test.mjs +100 -0
- package/scripts/topo-groupbox-march-busyness-test.mjs +155 -0
- package/scripts/topo-groupbox-test.mjs +4 -2
- package/scripts/topo-help-overlay-r109-test.mjs +67 -0
- package/scripts/topo-help-overlay-r118-test.mjs +69 -0
- package/scripts/topo-help-overlay-r123-test.mjs +69 -0
- package/scripts/topo-help-overlay-r134-test.mjs +74 -0
- package/scripts/topo-help-overlay-r137-test.mjs +81 -0
- package/scripts/topo-help-overlay-r141-test.mjs +86 -0
- package/scripts/topo-help-overlay-r153-test.mjs +85 -0
- package/scripts/topo-help-overlay-r59-test.mjs +67 -0
- package/scripts/topo-help-overlay-r65-test.mjs +64 -0
- package/scripts/topo-help-overlay-r70-test.mjs +63 -0
- package/scripts/topo-help-overlay-r78-test.mjs +59 -0
- package/scripts/topo-help-overlay-r81-test.mjs +58 -0
- package/scripts/topo-help-overlay-r87-test.mjs +64 -0
- package/scripts/topo-help-overlay-r91-test.mjs +65 -0
- package/scripts/topo-hot-tail-crossfade-test.mjs +117 -0
- package/scripts/topo-html-overlay-padding-unify-test.mjs +120 -0
- package/scripts/topo-hub-a11y-test.mjs +112 -0
- package/scripts/topo-hub-busyness-test.mjs +100 -0
- package/scripts/topo-hub-center-crossfade-test.mjs +124 -0
- package/scripts/topo-hub-click-fit-test.mjs +137 -0
- package/scripts/topo-hub-digit-scale-test.mjs +129 -0
- package/scripts/topo-hub-fadein-test.mjs +88 -0
- package/scripts/topo-hub-hover-lift-test.mjs +101 -0
- package/scripts/topo-hub-hover-ring-test.mjs +82 -0
- package/scripts/topo-hub-pip-theme-ease-test.mjs +116 -0
- package/scripts/topo-hub-spoke-ease-test.mjs +120 -0
- package/scripts/topo-hub-title-test.mjs +93 -0
- package/scripts/topo-hub-working-count-test.mjs +99 -0
- package/scripts/topo-ingroup-edge-test.mjs +103 -0
- package/scripts/topo-inner-radar-ring-retired-test.mjs +89 -0
- package/scripts/topo-kicker-color-test.mjs +93 -0
- package/scripts/topo-kicker-tracking-test.mjs +101 -0
- package/scripts/topo-kicker-weight-test.mjs +98 -0
- package/scripts/topo-label-card-theme-ease-test.mjs +85 -0
- package/scripts/topo-label-lift-test.mjs +119 -0
- package/scripts/topo-lastseen-tooltip-test.mjs +59 -0
- package/scripts/topo-layout-hover-text-preview-test.mjs +101 -0
- package/scripts/topo-layout-key-test.mjs +91 -0
- package/scripts/topo-layout-switch-crossfade-test.mjs +126 -0
- package/scripts/topo-layout-toggle-border-unify-test.mjs +104 -0
- package/scripts/topo-layout-toggle-test.mjs +131 -0
- package/scripts/topo-legend-compress-test.mjs +107 -0
- package/scripts/topo-legend-count-empty-test.mjs +126 -0
- package/scripts/topo-legend-count-tabular-parity-test.mjs +90 -0
- package/scripts/topo-legend-count-tabular-test.mjs +87 -0
- package/scripts/topo-legend-count-test.mjs +88 -0
- package/scripts/topo-legend-count-tier-fill-test.mjs +121 -0
- package/scripts/topo-legend-count-weight-test.mjs +86 -0
- package/scripts/topo-legend-header-symmetric-inset-test.mjs +112 -0
- package/scripts/topo-legend-hitbox-swatch-center-test.mjs +93 -0
- package/scripts/topo-legend-hover-test.mjs +113 -0
- package/scripts/topo-legend-offline-delimiter-test.mjs +84 -0
- package/scripts/topo-legend-offline-label-simplify-test.mjs +86 -0
- package/scripts/topo-legend-panel-count-weight-test.mjs +89 -0
- package/scripts/topo-legend-panel-header-test.mjs +83 -0
- package/scripts/topo-legend-pin-ring-fade-test.mjs +112 -0
- package/scripts/topo-legend-pin-test.mjs +128 -0
- package/scripts/topo-legend-row-hover-lift-test.mjs +109 -0
- package/scripts/topo-legend-row-labels-simplify-test.mjs +80 -0
- package/scripts/topo-legend-row-pin-spacing-test.mjs +124 -0
- package/scripts/topo-legend-row-tint-test.mjs +95 -0
- package/scripts/topo-legend-row-title-test.mjs +102 -0
- package/scripts/topo-legend-swatch-grow-test.mjs +116 -0
- package/scripts/topo-legend-swatch-radius-test.mjs +78 -0
- package/scripts/topo-minimap-a11y-test.mjs +101 -0
- package/scripts/topo-minimap-dot-transition-test.mjs +113 -0
- package/scripts/topo-minimap-rect-stroke-test.mjs +94 -0
- package/scripts/topo-minimap-test.mjs +68 -0
- package/scripts/topo-minimap-viewport-smooth-test.mjs +124 -0
- package/scripts/topo-mobile-chips-test.mjs +103 -0
- package/scripts/topo-monogram-font-test.mjs +112 -0
- package/scripts/topo-monogram-stroke-test.mjs +101 -0
- package/scripts/topo-node-a11y-test.mjs +107 -0
- package/scripts/topo-node-alias-chat-pin-test.mjs +95 -0
- package/scripts/topo-node-hover-lift-test.mjs +85 -0
- package/scripts/topo-node-label-card-elevation-test.mjs +157 -0
- package/scripts/topo-node-label-card-stroke-test.mjs +135 -0
- package/scripts/topo-node-stroke-transition-test.mjs +103 -0
- package/scripts/topo-node-text-fill-transition-test.mjs +119 -0
- package/scripts/topo-node-title-peers-test.mjs +107 -0
- package/scripts/topo-node-title-test.mjs +101 -0
- package/scripts/topo-nodesize-active-hover-test.mjs +109 -0
- package/scripts/topo-nodesize-crossfade-test.mjs +141 -0
- package/scripts/topo-online-chip-nav-test.mjs +143 -0
- package/scripts/topo-orbit-particles-retired-test.mjs +91 -0
- package/scripts/topo-overlap-test.mjs +32 -5
- package/scripts/topo-panel-elevation-test.mjs +76 -0
- package/scripts/topo-panel-fadein-test.mjs +102 -0
- package/scripts/topo-panel-hot-tail-fade-test.mjs +132 -0
- package/scripts/topo-panel-hover-elevation-test.mjs +118 -0
- package/scripts/topo-panel-theme-ease-test.mjs +85 -0
- package/scripts/topo-panel-title-fill-ease-test.mjs +91 -0
- package/scripts/topo-panel-title-tracking-test.mjs +78 -0
- package/scripts/topo-particle-stagger-test.mjs +82 -0
- package/scripts/topo-pin-intersection-color-ease-test.mjs +111 -0
- package/scripts/topo-pin-intersection-empty-test.mjs +129 -0
- package/scripts/topo-pin-intersection-tabular-test.mjs +96 -0
- package/scripts/topo-pin-intersection-test.mjs +121 -0
- package/scripts/topo-pin-intersection-warning-crossfade-test.mjs +107 -0
- package/scripts/topo-pin-mirror-transition-test.mjs +101 -0
- package/scripts/topo-pin-persistence-test.mjs +105 -0
- package/scripts/topo-popover-meta-test.mjs +78 -0
- package/scripts/topo-prepublish-guard-test.mjs +95 -0
- package/scripts/topo-pressure-bar-test.mjs +69 -0
- package/scripts/topo-pressure-hover-test.mjs +123 -0
- package/scripts/topo-pressure-pin-test.mjs +119 -0
- package/scripts/topo-pressure-seg-self-hover-test.mjs +126 -0
- package/scripts/topo-pressure-seg-tooltip-test.mjs +98 -0
- package/scripts/topo-pressure-seg-transition-test.mjs +107 -0
- package/scripts/topo-pulse-dot-crossfade-test.mjs +122 -0
- package/scripts/topo-pulse-dot-retired-test.mjs +86 -0
- package/scripts/topo-recent-panel-count-freshness-test.mjs +109 -0
- package/scripts/topo-recent-panel-count-test.mjs +72 -0
- package/scripts/topo-recent-panel-count-weight-test.mjs +91 -0
- package/scripts/topo-recent-panel-footer-breath-test.mjs +142 -0
- package/scripts/topo-recent-panel-hot-header-test.mjs +132 -0
- package/scripts/topo-recent-panel-more-crossfade-test.mjs +124 -0
- package/scripts/topo-recent-panel-more-cyan-hover-test.mjs +151 -0
- package/scripts/topo-recent-panel-more-nav-test.mjs +127 -0
- package/scripts/topo-recent-panel-more-test.mjs +106 -0
- package/scripts/topo-recent-panel-readability-bump-test.mjs +151 -0
- package/scripts/topo-recent-row-count-fill-test.mjs +129 -0
- package/scripts/topo-recent-row-fadein-test.mjs +107 -0
- package/scripts/topo-recent-row-freshness-test.mjs +102 -0
- package/scripts/topo-recent-row-hot-test.mjs +110 -0
- package/scripts/topo-recent-row-hover-lift-test.mjs +128 -0
- package/scripts/topo-recent-row-hover-test.mjs +122 -0
- package/scripts/topo-recent-row-pin-spacing-test.mjs +137 -0
- package/scripts/topo-recent-row-pin-test.mjs +126 -0
- package/scripts/topo-recent-row-tint-test.mjs +91 -0
- package/scripts/topo-recent-row-title-test.mjs +112 -0
- package/scripts/topo-recent-row-ts-alpha-test.mjs +100 -0
- package/scripts/topo-recent-row-ts-test.mjs +95 -0
- package/scripts/topo-recent-row-typography-test.mjs +119 -0
- package/scripts/topo-recent-signal-empty-hint-test.mjs +73 -0
- package/scripts/topo-recent-signal-empty-test.mjs +63 -0
- package/scripts/topo-reduced-motion-test.mjs +77 -0
- package/scripts/topo-reset-spin-test.mjs +120 -0
- package/scripts/topo-runtime-badge-grow-test.mjs +114 -0
- package/scripts/topo-spokes-retired-test.mjs +93 -0
- package/scripts/topo-starfield-density-test.mjs +89 -0
- package/scripts/topo-status-chip-hover-test.mjs +101 -0
- package/scripts/topo-status-chip-tooltip-test.mjs +95 -0
- package/scripts/topo-statusbar-chips-self-hover-test.mjs +177 -0
- package/scripts/topo-svg-focus-test.mjs +112 -0
- package/scripts/topo-sweep-busyness-test.mjs +94 -0
- package/scripts/topo-tabular-nums-sweep-test.mjs +93 -0
- package/scripts/topo-tier-guide-dashes-test.mjs +86 -0
- package/scripts/topo-tier-ring-fadein-test.mjs +107 -0
- package/scripts/topo-tier-ring-occupancy-test.mjs +87 -0
- package/scripts/topo-tier-ring-test.mjs +69 -0
- package/scripts/topo-tier-ring-tint-test.mjs +110 -0
- package/scripts/topo-tier-stagger-test.mjs +89 -0
- package/scripts/topo-title-block-tight-leading-test.mjs +95 -0
- package/scripts/topo-title-tracking-test.mjs +98 -0
- package/scripts/topo-titleblock-gap-test.mjs +86 -0
- package/scripts/topo-titleblock-margin-test.mjs +83 -0
- package/scripts/topo-toggle-inactive-cyan-hover-test.mjs +110 -0
- package/scripts/topo-top-rail-theme-ease-test.mjs +89 -0
- package/scripts/topo-tz-ghost-test.mjs +69 -0
- package/scripts/topo-vendor-chip-hover-test.mjs +111 -0
- package/scripts/topo-vendor-chip-self-hover-test.mjs +131 -0
- package/scripts/topo-vendor-chip-tabular-test.mjs +92 -0
- package/scripts/topo-vendor-chip-threshold-test.mjs +78 -0
- package/scripts/topo-vendor-chip-weight-test.mjs +87 -0
- package/scripts/topo-vendor-letter-tooltip-test.mjs +92 -0
- package/scripts/topo-vendor-pill-test.mjs +125 -0
- package/scripts/topo-vendor-pin-test.mjs +125 -0
- package/scripts/topo-view-smooth-test.mjs +131 -0
- package/scripts/topo-watermark-tracking-test.mjs +99 -0
- package/scripts/topo-working-chip-pin-test.mjs +154 -0
- package/scripts/topo-working-halo-breath-retired-test.mjs +99 -0
- package/scripts/topo-wrapper-flow-arrow-theme-test.mjs +97 -0
- package/scripts/topo-wrapper-shadow-theme-ease-test.mjs +89 -0
- package/.next/static/chunks/0-7iowzu4.798.js +0 -1
- package/.next/static/chunks/02t5jr4shh.hy.js +0 -1
- package/.next/static/chunks/09nd.t_hd.y6t.css +0 -2
- package/.next/static/chunks/0_8snedeata9k.js +0 -1
- package/.next/static/chunks/0_qfg5s5uzs7..js +0 -7
- package/.next/static/chunks/0elalb9n_.~di.js +0 -1
- package/.next/static/chunks/0j_q__o8p6g83.js +0 -1
- package/.next/static/chunks/0jl6_w50zh4l5.js +0 -1
- package/.next/static/chunks/0kwf..oq7.27x.js +0 -7
- package/.next/static/chunks/0r4q73.-1bkyl.js +0 -1
- package/.next/static/chunks/0r_c8eccg3z2o.js +0 -1
- package/.next/static/chunks/0sjqjenh7~k-j.js +0 -1
- package/.next/static/chunks/0y8v4grez.a76.js +0 -1
- package/.next/static/chunks/10oi7l-tycgl9.js +0 -1
- package/.next/static/chunks/11uk1izuv3~0t.js +0 -1
- /package/.next/static/{Q3_3F7glo-M3CFrXA8POE → 3PMYuA9TBRow9F7QeNZc7}/_buildManifest.js +0 -0
- /package/.next/static/{Q3_3F7glo-M3CFrXA8POE → 3PMYuA9TBRow9F7QeNZc7}/_clientMiddlewareManifest.js +0 -0
- /package/.next/static/{Q3_3F7glo-M3CFrXA8POE → 3PMYuA9TBRow9F7QeNZc7}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
/* Round 259 verification: recent-signal panel's two italic instructional
|
|
2
|
+
* texts bump fontSize 8 → 9 for readability.
|
|
3
|
+
*
|
|
4
|
+
* Pre-R259 size hierarchy in the recent-signal panel:
|
|
5
|
+
* "no flow yet" main empty-state fontSize 10 italic (action prompt)
|
|
6
|
+
* row content "alpha→beta · 3" fontSize 9 regular (data)
|
|
7
|
+
* hint "send a message…" fontSize 8 italic (instruction)
|
|
8
|
+
* "+N more flows" footer link fontSize 8 italic (nav affordance)
|
|
9
|
+
* row timestamp "5s" fontSize 8 regular (recency tag)
|
|
10
|
+
*
|
|
11
|
+
* Pre-R259 the hint + footer rendered at the smallest readable size on
|
|
12
|
+
* canvas, italic + low opacity layering legibility cost on top of the
|
|
13
|
+
* small type. Both are READ-TO-ACT text (instructional / clickable).
|
|
14
|
+
*
|
|
15
|
+
* Post-R259:
|
|
16
|
+
* hint fontSize 8 → 9
|
|
17
|
+
* footer link fontSize 8 → 9
|
|
18
|
+
*
|
|
19
|
+
* The per-row timestamp STAYS at 8 — it's an at-a-glance recency tag
|
|
20
|
+
* tightly co-located with row text, not read-to-act instruction. Hint +
|
|
21
|
+
* footer at 9pt italic still subordinate to row content (9pt regular)
|
|
22
|
+
* via italic + lower opacity discrimination.
|
|
23
|
+
*
|
|
24
|
+
* Test scope:
|
|
25
|
+
* 1. Empty state hint fontSize === 9 (was 8). Tested in empty scenario.
|
|
26
|
+
* 2. "+N more flows" footer fontSize === 9. Tested in 5-msg scenario.
|
|
27
|
+
* 3. Per-row timestamp UNCHANGED at fontSize === 8 (sibling regression).
|
|
28
|
+
* 4. R256 footer-breath invariant preserved — hover footer client
|
|
29
|
+
* bottom inside panel client bottom (footer with fontSize 9 still
|
|
30
|
+
* tucks inside the panel).
|
|
31
|
+
*/
|
|
32
|
+
import { chromium } from 'playwright';
|
|
33
|
+
import { readFileSync } from 'node:fs';
|
|
34
|
+
|
|
35
|
+
const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
|
|
36
|
+
const browser = await chromium.launch({ headless: true });
|
|
37
|
+
|
|
38
|
+
async function probeEmpty() {
|
|
39
|
+
const ctx = await browser.newContext({ viewport: { width: 1500, height: 1500 } });
|
|
40
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
41
|
+
await ctx.addInitScript(() => {
|
|
42
|
+
try { localStorage.setItem('anet-theme', 'cyber'); sessionStorage.setItem('anet_v3_auth', '1'); } catch {}
|
|
43
|
+
});
|
|
44
|
+
const fresh = new Date(Date.now() - 60 * 1000).toISOString();
|
|
45
|
+
await ctx.route('**/api/hub/status*', async (route) => {
|
|
46
|
+
const r = await route.fetch();
|
|
47
|
+
const b = await r.json();
|
|
48
|
+
const nid = (b.sessions || [])[0]?.network_id || 'default';
|
|
49
|
+
const mk = (alias) => ({
|
|
50
|
+
alias, status: 'working', model: 'claude-opus-4', runtime: 'claude-code-cli',
|
|
51
|
+
network_id: nid, project_dir: null,
|
|
52
|
+
created_at: fresh, updated_at: fresh, last_seen_at: fresh,
|
|
53
|
+
});
|
|
54
|
+
await route.fulfill({ response: r, json: { ...b, sessions: [mk('alpha'), mk('beta')] } });
|
|
55
|
+
});
|
|
56
|
+
await ctx.route('**/api/hub/messages*', (r) => r.fulfill({ json: { messages: [] } }));
|
|
57
|
+
await ctx.route('**/api/hub/tasks*', (r) => r.fulfill({ json: { tasks: [] } }));
|
|
58
|
+
const page = await ctx.newPage();
|
|
59
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
|
|
60
|
+
await page.waitForFunction(() => document.querySelectorAll('g[data-node]').length === 2, { timeout: 30000 });
|
|
61
|
+
await page.waitForSelector('[data-recent-signal-empty-hint]', { timeout: 10000 });
|
|
62
|
+
await page.waitForTimeout(300);
|
|
63
|
+
const result = await page.evaluate(() => {
|
|
64
|
+
const hint = document.querySelector('[data-recent-signal-empty-hint]');
|
|
65
|
+
return { hintFontSize: hint?.getAttribute('font-size') };
|
|
66
|
+
});
|
|
67
|
+
await ctx.close();
|
|
68
|
+
return result;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
async function probePopulated() {
|
|
72
|
+
const ctx = await browser.newContext({ viewport: { width: 1500, height: 1500 } });
|
|
73
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
74
|
+
await ctx.addInitScript(() => {
|
|
75
|
+
try { localStorage.setItem('anet-theme', 'cyber'); sessionStorage.setItem('anet_v3_auth', '1'); } catch {}
|
|
76
|
+
});
|
|
77
|
+
const fresh = new Date(Date.now() - 60 * 1000).toISOString();
|
|
78
|
+
await ctx.route('**/api/hub/status*', async (route) => {
|
|
79
|
+
const r = await route.fetch();
|
|
80
|
+
const b = await r.json();
|
|
81
|
+
const nid = (b.sessions || [])[0]?.network_id || 'default';
|
|
82
|
+
const mk = (alias) => ({
|
|
83
|
+
alias, status: 'working', model: 'claude-opus-4', runtime: 'claude-code-cli',
|
|
84
|
+
network_id: nid, project_dir: null,
|
|
85
|
+
created_at: fresh, updated_at: fresh, last_seen_at: fresh,
|
|
86
|
+
});
|
|
87
|
+
await route.fulfill({ response: r, json: { ...b, sessions: [
|
|
88
|
+
mk('alpha'), mk('beta'), mk('gamma'), mk('delta'),
|
|
89
|
+
] } });
|
|
90
|
+
});
|
|
91
|
+
// 5 distinct flow pairs → flowLinks.length === 5 → footer visible
|
|
92
|
+
const now = Date.now();
|
|
93
|
+
const msgs = [
|
|
94
|
+
{ id: 'm0', from_alias: 'alpha', to_alias: 'beta', content: 'hi', network_id: 'default', created_at: new Date(now - 1000).toISOString() },
|
|
95
|
+
{ id: 'm1', from_alias: 'beta', to_alias: 'gamma', content: 'hi', network_id: 'default', created_at: new Date(now - 1500).toISOString() },
|
|
96
|
+
{ id: 'm2', from_alias: 'gamma', to_alias: 'delta', content: 'hi', network_id: 'default', created_at: new Date(now - 2000).toISOString() },
|
|
97
|
+
{ id: 'm3', from_alias: 'delta', to_alias: 'alpha', content: 'hi', network_id: 'default', created_at: new Date(now - 2500).toISOString() },
|
|
98
|
+
{ id: 'm4', from_alias: 'alpha', to_alias: 'gamma', content: 'hi', network_id: 'default', created_at: new Date(now - 3000).toISOString() },
|
|
99
|
+
];
|
|
100
|
+
await ctx.route('**/api/hub/messages*', (r) => r.fulfill({ json: { messages: msgs } }));
|
|
101
|
+
await ctx.route('**/api/hub/tasks*', (r) => r.fulfill({ json: { tasks: [] } }));
|
|
102
|
+
const page = await ctx.newPage();
|
|
103
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
|
|
104
|
+
await page.waitForFunction(() => document.querySelectorAll('g[data-node]').length === 4, { timeout: 30000 });
|
|
105
|
+
await page.waitForSelector('[data-recent-panel-more-nav]', { timeout: 10000 });
|
|
106
|
+
await page.waitForTimeout(500);
|
|
107
|
+
|
|
108
|
+
const rest = await page.evaluate(() => {
|
|
109
|
+
const footer = document.querySelector('[data-recent-panel-more]');
|
|
110
|
+
const ts = document.querySelector('[data-recent-row-ts]');
|
|
111
|
+
return {
|
|
112
|
+
footerFontSize: footer?.getAttribute('font-size'),
|
|
113
|
+
tsFontSize: ts?.getAttribute('font-size'),
|
|
114
|
+
};
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
// R256 invariant regression — hover the footer + check it tucks inside panel
|
|
118
|
+
await page.locator('[data-recent-panel-more-nav]').hover();
|
|
119
|
+
await page.waitForTimeout(250);
|
|
120
|
+
const hoverProbe = await page.evaluate(() => {
|
|
121
|
+
const panelG = document.querySelector('[data-topo-panel="recent"]');
|
|
122
|
+
const rect = panelG?.querySelector('rect');
|
|
123
|
+
const footer = document.querySelector('[data-recent-panel-more]');
|
|
124
|
+
return {
|
|
125
|
+
rectBottom: rect?.getBoundingClientRect().bottom ?? null,
|
|
126
|
+
footerBottom: footer?.getBoundingClientRect().bottom ?? null,
|
|
127
|
+
};
|
|
128
|
+
});
|
|
129
|
+
await ctx.close();
|
|
130
|
+
|
|
131
|
+
const hoverClearance = (hoverProbe.rectBottom != null && hoverProbe.footerBottom != null)
|
|
132
|
+
? (hoverProbe.rectBottom - hoverProbe.footerBottom) : null;
|
|
133
|
+
|
|
134
|
+
return { ...rest, hoverClearance };
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const empty = await probeEmpty();
|
|
138
|
+
const pop = await probePopulated();
|
|
139
|
+
await browser.close();
|
|
140
|
+
|
|
141
|
+
const results = {
|
|
142
|
+
hint_fontsize_bumped_to_9: empty.hintFontSize === '9',
|
|
143
|
+
footer_fontsize_bumped_to_9: pop.footerFontSize === '9',
|
|
144
|
+
per_row_timestamp_unchanged_at_8: pop.tsFontSize === '8',
|
|
145
|
+
r256_footer_inside_panel_on_hover: pop.hoverClearance != null && pop.hoverClearance >= -1,
|
|
146
|
+
};
|
|
147
|
+
const ok = Object.values(results).every(Boolean);
|
|
148
|
+
console.log(`${ok ? '✅' : '❌'} recent panel readability bump:`, JSON.stringify(results),
|
|
149
|
+
'\n empty:', empty,
|
|
150
|
+
'\n pop:', pop);
|
|
151
|
+
process.exit(ok ? 0 : 1);
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/* Round 189 verification: recent-signal row count tspan unified
|
|
2
|
+
* into one always-mounted element with fill/fontWeight gated by
|
|
3
|
+
* isHot. transition: fill 300ms ease-out makes the R127 hot
|
|
4
|
+
* threshold crossing (count >= 10) ease smoothly through the
|
|
5
|
+
* colour shift instead of snapping.
|
|
6
|
+
*
|
|
7
|
+
* Pre-R189 two tspans branched on isHot — different
|
|
8
|
+
* data-recent-row-count and data-recent-row-count-hot
|
|
9
|
+
* attributes; mount/unmount made fill+fontWeight snap.
|
|
10
|
+
*
|
|
11
|
+
* Test:
|
|
12
|
+
* Mock 3 flows side by side:
|
|
13
|
+
* alpha→beta: count=4 (cold) → fill unset, weight unset,
|
|
14
|
+
* no hot attr
|
|
15
|
+
* alpha→gamma: count=12 (hot) → fill=amber, weight=700,
|
|
16
|
+
* hot attr 'true'
|
|
17
|
+
* alpha→delta: count=20 (hot) → fill=amber, weight=700
|
|
18
|
+
* All three tspans:
|
|
19
|
+
* - have data-recent-row-count
|
|
20
|
+
* - have style.transition includes 'fill 300ms'
|
|
21
|
+
*/
|
|
22
|
+
import { chromium } from 'playwright';
|
|
23
|
+
import { readFileSync } from 'node:fs';
|
|
24
|
+
|
|
25
|
+
const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
|
|
26
|
+
const browser = await chromium.launch({ headless: true });
|
|
27
|
+
|
|
28
|
+
const ctx = await browser.newContext({ viewport: { width: 1500, height: 1500 } });
|
|
29
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
30
|
+
await ctx.addInitScript(() => {
|
|
31
|
+
try { localStorage.setItem('anet-theme', 'cyber'); sessionStorage.setItem('anet_v3_auth', '1'); } catch {}
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
const fresh = new Date(Date.now() - 60 * 1000).toISOString();
|
|
35
|
+
await ctx.route('**/api/hub/status*', async (route) => {
|
|
36
|
+
const r = await route.fetch();
|
|
37
|
+
const b = await r.json();
|
|
38
|
+
const nid = (b.sessions || [])[0]?.network_id || 'default';
|
|
39
|
+
const mk = (alias) => ({
|
|
40
|
+
alias, status: 'working', model: 'claude-opus-4', runtime: 'cli-claude-code',
|
|
41
|
+
network_id: nid, project_dir: null,
|
|
42
|
+
created_at: fresh, updated_at: fresh, last_seen_at: fresh,
|
|
43
|
+
});
|
|
44
|
+
await route.fulfill({ response: r, json: { ...b, sessions: [
|
|
45
|
+
mk('alpha'), mk('beta'), mk('gamma'), mk('delta'),
|
|
46
|
+
] } });
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
const now = Date.now();
|
|
50
|
+
const msgs = [];
|
|
51
|
+
// alpha→beta: 4 (cold)
|
|
52
|
+
for (let i = 0; i < 4; i++) {
|
|
53
|
+
msgs.push({ id: `cold${i}`, from_alias: 'alpha', to_alias: 'beta', content: 'hi',
|
|
54
|
+
network_id: 'default', created_at: new Date(now - (5000 + i * 50)).toISOString() });
|
|
55
|
+
}
|
|
56
|
+
// alpha→gamma: 12 (hot)
|
|
57
|
+
for (let i = 0; i < 12; i++) {
|
|
58
|
+
msgs.push({ id: `h1${i}`, from_alias: 'alpha', to_alias: 'gamma', content: 'hi',
|
|
59
|
+
network_id: 'default', created_at: new Date(now - (10000 + i * 50)).toISOString() });
|
|
60
|
+
}
|
|
61
|
+
// alpha→delta: 20 (hot)
|
|
62
|
+
for (let i = 0; i < 20; i++) {
|
|
63
|
+
msgs.push({ id: `h2${i}`, from_alias: 'alpha', to_alias: 'delta', content: 'hi',
|
|
64
|
+
network_id: 'default', created_at: new Date(now - (15000 + i * 50)).toISOString() });
|
|
65
|
+
}
|
|
66
|
+
await ctx.route('**/api/hub/messages*', (route) => route.fulfill({ json: { messages: msgs } }));
|
|
67
|
+
await ctx.route('**/api/hub/tasks*', (route) => route.fulfill({ json: { tasks: [] } }));
|
|
68
|
+
|
|
69
|
+
const page = await ctx.newPage();
|
|
70
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
|
|
71
|
+
await page.waitForFunction(() => document.querySelectorAll('g[data-node]').length === 4, { timeout: 30000 });
|
|
72
|
+
await page.waitForSelector('[data-recent-row-count]', { timeout: 10000 });
|
|
73
|
+
await page.waitForTimeout(400);
|
|
74
|
+
|
|
75
|
+
const probe = await page.evaluate(() => {
|
|
76
|
+
const tspans = [...document.querySelectorAll('[data-recent-row-count]')];
|
|
77
|
+
return tspans.map(t => {
|
|
78
|
+
const row = t.closest('[data-recent-row]');
|
|
79
|
+
return {
|
|
80
|
+
rowKey: row?.getAttribute('data-recent-row'),
|
|
81
|
+
text: t.textContent,
|
|
82
|
+
fill: t.getAttribute('fill'),
|
|
83
|
+
fontWeight: t.getAttribute('font-weight'),
|
|
84
|
+
hotAttr: t.getAttribute('data-recent-row-count-hot'),
|
|
85
|
+
transition: t.style.transition || getComputedStyle(t).transition,
|
|
86
|
+
};
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
await browser.close();
|
|
91
|
+
|
|
92
|
+
const findByKey = (key) => probe.find(p => p.rowKey === key);
|
|
93
|
+
const cold = findByKey('alpha->beta');
|
|
94
|
+
const hot1 = findByKey('alpha->gamma');
|
|
95
|
+
const hot2 = findByKey('alpha->delta');
|
|
96
|
+
|
|
97
|
+
const hasFillTransition = (s) =>
|
|
98
|
+
(s?.transition || '').includes('fill 300ms') ||
|
|
99
|
+
/fill\s+0\.3s|fill\s+300ms/.test(s?.transition || '');
|
|
100
|
+
|
|
101
|
+
const results = {
|
|
102
|
+
three_tspans_present: probe.length === 3,
|
|
103
|
+
cold_found: cold !== undefined,
|
|
104
|
+
hot1_found: hot1 !== undefined,
|
|
105
|
+
hot2_found: hot2 !== undefined,
|
|
106
|
+
|
|
107
|
+
cold_no_fill: cold?.fill === null || cold?.fill === undefined,
|
|
108
|
+
cold_no_fontWeight: cold?.fontWeight === null || cold?.fontWeight === undefined,
|
|
109
|
+
cold_no_hot_attr: cold?.hotAttr === null,
|
|
110
|
+
cold_text_4: cold?.text === '4',
|
|
111
|
+
|
|
112
|
+
hot1_fill_amber: hot1?.fill === '#fbbf24',
|
|
113
|
+
hot1_fontWeight_700: hot1?.fontWeight === '700',
|
|
114
|
+
hot1_hot_attr: hot1?.hotAttr === 'true',
|
|
115
|
+
hot1_text_12: hot1?.text === '12',
|
|
116
|
+
|
|
117
|
+
hot2_fill_amber: hot2?.fill === '#fbbf24',
|
|
118
|
+
hot2_fontWeight_700: hot2?.fontWeight === '700',
|
|
119
|
+
hot2_hot_attr: hot2?.hotAttr === 'true',
|
|
120
|
+
hot2_text_20: hot2?.text === '20',
|
|
121
|
+
|
|
122
|
+
all_have_fill_transition: probe.every(p => hasFillTransition(p)),
|
|
123
|
+
};
|
|
124
|
+
const ok = Object.values(results).every(Boolean);
|
|
125
|
+
console.log(`${ok ? '✅' : '❌'} recent-row count fill:`, JSON.stringify(results),
|
|
126
|
+
`\n cold:`, cold,
|
|
127
|
+
`\n hot1:`, hot1,
|
|
128
|
+
`\n hot2:`, hot2);
|
|
129
|
+
process.exit(ok ? 0 : 1);
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/* Round 203 verification: recent-signal panel rows fade in on mount,
|
|
2
|
+
* not just when the panel itself first appears (R175). Pre-R203 a new
|
|
3
|
+
* flow rising into the top-3 list snap-popped in; R203 attaches
|
|
4
|
+
* anet-fade-in per-row so the entrance eases.
|
|
5
|
+
*
|
|
6
|
+
* Key={link.key} preserves stable identity across re-renders — the
|
|
7
|
+
* animation plays once per mount, not on every count update.
|
|
8
|
+
*
|
|
9
|
+
* Test (cyber dark, 3 flows already present at load):
|
|
10
|
+
* 1. Three recent-signal rows render with data-recent-row.
|
|
11
|
+
* 2. Each row's className includes 'anet-fade-in' AND
|
|
12
|
+
* 'anet-topo-svg-focus' (existing focus class kept).
|
|
13
|
+
* 3. CSS animationName resolves to a non-empty value matching the
|
|
14
|
+
* anet-fade-in keyframe (we read it via getComputedStyle — the
|
|
15
|
+
* browser's compiled CSS-rule selector binds the class to the
|
|
16
|
+
* animation).
|
|
17
|
+
* 4. Existing R143 row-lift inline transition is intact
|
|
18
|
+
* (transform 150ms cubic-bezier).
|
|
19
|
+
* 5. Existing R160 pip and R191 ts elements still render inside
|
|
20
|
+
* each row — no markup regression from the className change.
|
|
21
|
+
*/
|
|
22
|
+
import { chromium } from 'playwright';
|
|
23
|
+
import { readFileSync } from 'node:fs';
|
|
24
|
+
|
|
25
|
+
const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
|
|
26
|
+
const browser = await chromium.launch({ headless: true });
|
|
27
|
+
|
|
28
|
+
const ctx = await browser.newContext({ viewport: { width: 1500, height: 1500 } });
|
|
29
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
30
|
+
await ctx.addInitScript(() => {
|
|
31
|
+
try { localStorage.setItem('anet-theme', 'cyber'); sessionStorage.setItem('anet_v3_auth', '1'); } catch {}
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
const fresh = new Date(Date.now() - 60 * 1000).toISOString();
|
|
35
|
+
await ctx.route('**/api/hub/status*', async (route) => {
|
|
36
|
+
const r = await route.fetch();
|
|
37
|
+
const b = await r.json();
|
|
38
|
+
const nid = (b.sessions || [])[0]?.network_id || 'default';
|
|
39
|
+
const mk = (alias) => ({
|
|
40
|
+
alias, status: 'working', model: 'claude-opus-4', runtime: 'cli-claude-code',
|
|
41
|
+
network_id: nid, project_dir: null,
|
|
42
|
+
created_at: fresh, updated_at: fresh, last_seen_at: fresh,
|
|
43
|
+
});
|
|
44
|
+
await route.fulfill({ response: r, json: { ...b, sessions: [
|
|
45
|
+
mk('alpha'), mk('beta'), mk('gamma'), mk('delta'),
|
|
46
|
+
] } });
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
const now = Date.now();
|
|
50
|
+
const msgs = [
|
|
51
|
+
{ id: 'a', from_alias: 'alpha', to_alias: 'beta', content: 'hi',
|
|
52
|
+
network_id: 'default', created_at: new Date(now - 3000).toISOString() },
|
|
53
|
+
{ id: 'b', from_alias: 'beta', to_alias: 'gamma', content: 'hi',
|
|
54
|
+
network_id: 'default', created_at: new Date(now - 6000).toISOString() },
|
|
55
|
+
{ id: 'c', from_alias: 'gamma', to_alias: 'delta', content: 'hi',
|
|
56
|
+
network_id: 'default', created_at: new Date(now - 9000).toISOString() },
|
|
57
|
+
];
|
|
58
|
+
await ctx.route('**/api/hub/messages*', (route) => route.fulfill({ json: { messages: msgs } }));
|
|
59
|
+
await ctx.route('**/api/hub/tasks*', (route) => route.fulfill({ json: { tasks: [] } }));
|
|
60
|
+
|
|
61
|
+
const page = await ctx.newPage();
|
|
62
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
|
|
63
|
+
await page.waitForFunction(() => document.querySelectorAll('g[data-node]').length === 4, { timeout: 30000 });
|
|
64
|
+
await page.waitForSelector('[data-recent-row]', { timeout: 10000 });
|
|
65
|
+
|
|
66
|
+
// Wait past panel R175 700ms delay + 150ms row animation so the rows
|
|
67
|
+
// have finished their entrance and computed style shows the resting
|
|
68
|
+
// state with the animation declared in CSS but completed.
|
|
69
|
+
await page.waitForTimeout(1100);
|
|
70
|
+
|
|
71
|
+
const rows = await page.evaluate(() => {
|
|
72
|
+
return [...document.querySelectorAll('[data-recent-row]')].map(el => {
|
|
73
|
+
const cs = getComputedStyle(el);
|
|
74
|
+
const pip = el.querySelector('[data-recent-row-freshness]');
|
|
75
|
+
const ts = el.querySelector('[data-recent-row-ts]');
|
|
76
|
+
return {
|
|
77
|
+
key: el.getAttribute('data-recent-row'),
|
|
78
|
+
className: el.getAttribute('class') || '',
|
|
79
|
+
animationName: cs.animationName,
|
|
80
|
+
animationDuration: cs.animationDuration,
|
|
81
|
+
inlineTransition: el.style.transition,
|
|
82
|
+
hasFreshnessPip: !!pip,
|
|
83
|
+
hasTimestamp: !!ts,
|
|
84
|
+
};
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
await browser.close();
|
|
89
|
+
|
|
90
|
+
const has = (s, c) => (s || '').split(/\s+/).includes(c);
|
|
91
|
+
|
|
92
|
+
const results = {
|
|
93
|
+
three_rows_present: rows.length === 3,
|
|
94
|
+
all_have_fadein_class: rows.every(r => has(r.className, 'anet-fade-in')),
|
|
95
|
+
all_keep_focus_class: rows.every(r => has(r.className, 'anet-topo-svg-focus')),
|
|
96
|
+
all_have_animation_bound: rows.every(r => /anet-fade-in|fadein/i.test(r.animationName)
|
|
97
|
+
|| r.animationName.includes('anet-fade-in')),
|
|
98
|
+
// R143 row-lift transition still in inline style
|
|
99
|
+
all_keep_transform_transition: rows.every(r => /transform\s+(?:150ms|0\.15s)/.test(r.inlineTransition || '')),
|
|
100
|
+
// R160 R191 markup contracts unbroken
|
|
101
|
+
all_have_pip: rows.every(r => r.hasFreshnessPip === true),
|
|
102
|
+
all_have_ts: rows.every(r => r.hasTimestamp === true),
|
|
103
|
+
};
|
|
104
|
+
const ok = Object.values(results).every(Boolean);
|
|
105
|
+
console.log(`${ok ? '✅' : '❌'} recent-row fade-in:`, JSON.stringify(results),
|
|
106
|
+
`\n rows:`, rows);
|
|
107
|
+
process.exit(ok ? 0 : 1);
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/* Round 160 verification: recency pip on recent-signal panel rows.
|
|
2
|
+
*
|
|
3
|
+
* Canvas flow edges fade by freshness (R10: full intensity ≤30s,
|
|
4
|
+
* decaying to ~35% over 5min). The recent-signal panel rows
|
|
5
|
+
* encoded last_at purely in text ("5s" at row right edge) — no
|
|
6
|
+
* at-a-glance visual cue for "which row is actively firing".
|
|
7
|
+
*
|
|
8
|
+
* R160 adds a 1.6-px cyan dot at x=10 (in the 7-px margin
|
|
9
|
+
* between rect-start x=6 and text-start x=13). Alpha ramp:
|
|
10
|
+
* ageSec ≤ 30 → 1.0 (fully fresh)
|
|
11
|
+
* 30 < ageSec ≤ 300 → smooth decay 1.0 → 0.25
|
|
12
|
+
* ageSec > 300 → 0.25 (stale floor)
|
|
13
|
+
*
|
|
14
|
+
* Three independent encodings on each row, none competing:
|
|
15
|
+
* rect fill = hover/pin state (R104/R116)
|
|
16
|
+
* count tspan = magnitude (R127 amber when ≥10)
|
|
17
|
+
* pip = recency (this round)
|
|
18
|
+
*
|
|
19
|
+
* Test:
|
|
20
|
+
* Mock 3 flows — 1 fresh (5s ago), 1 mid (90s ago), 1 stale
|
|
21
|
+
* (6 min ago). Each should produce one pip; alpha ladder:
|
|
22
|
+
* fresh > mid > stale.
|
|
23
|
+
*/
|
|
24
|
+
import { chromium } from 'playwright';
|
|
25
|
+
import { readFileSync } from 'node:fs';
|
|
26
|
+
|
|
27
|
+
const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
|
|
28
|
+
const browser = await chromium.launch({ headless: true });
|
|
29
|
+
|
|
30
|
+
const ctx = await browser.newContext({ viewport: { width: 1500, height: 1500 } });
|
|
31
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
32
|
+
await ctx.addInitScript(() => {
|
|
33
|
+
try { localStorage.setItem('anet-theme', 'cyber'); sessionStorage.setItem('anet_v3_auth', '1'); } catch {}
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
const fresh = new Date(Date.now() - 60 * 1000).toISOString();
|
|
37
|
+
await ctx.route('**/api/hub/status*', async (route) => {
|
|
38
|
+
const r = await route.fetch();
|
|
39
|
+
const b = await r.json();
|
|
40
|
+
const nid = (b.sessions || [])[0]?.network_id || 'default';
|
|
41
|
+
const mk = (alias) => ({
|
|
42
|
+
alias, status: 'working', model: 'claude-opus-4', runtime: '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('alpha'), mk('beta'), mk('gamma'), mk('delta'),
|
|
48
|
+
] } });
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
const now = Date.now();
|
|
52
|
+
// Three distinct flows with different recency:
|
|
53
|
+
// fresh: 5s ago → alpha ≈ 1.0
|
|
54
|
+
// mid: 90s ago → alpha ≈ 1 - (60/270)*0.75 ≈ 0.833
|
|
55
|
+
// stale: 360s ago → alpha ≈ 0.25 (floor)
|
|
56
|
+
const msgs = [
|
|
57
|
+
{ id: 'f1', from_alias: 'alpha', to_alias: 'beta', content: 'hi', network_id: 'default', created_at: new Date(now - 5000).toISOString() },
|
|
58
|
+
{ id: 'm1', from_alias: 'beta', to_alias: 'gamma', content: 'hi', network_id: 'default', created_at: new Date(now - 90000).toISOString() },
|
|
59
|
+
{ id: 's1', from_alias: 'gamma', to_alias: 'delta', content: 'hi', network_id: 'default', created_at: new Date(now - 360000).toISOString() },
|
|
60
|
+
];
|
|
61
|
+
await ctx.route('**/api/hub/messages*', (route) => route.fulfill({ json: { messages: msgs } }));
|
|
62
|
+
await ctx.route('**/api/hub/tasks*', (route) => route.fulfill({ json: { tasks: [] } }));
|
|
63
|
+
|
|
64
|
+
const page = await ctx.newPage();
|
|
65
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
|
|
66
|
+
await page.waitForFunction(() => document.querySelectorAll('g[data-node]').length === 4, { timeout: 30000 });
|
|
67
|
+
await page.waitForSelector('[data-recent-row-freshness]', { timeout: 10000 });
|
|
68
|
+
await page.waitForTimeout(400);
|
|
69
|
+
|
|
70
|
+
const probes = await page.evaluate(() => {
|
|
71
|
+
const pips = [...document.querySelectorAll('[data-recent-row-freshness]')];
|
|
72
|
+
return pips.map(el => ({
|
|
73
|
+
key: el.getAttribute('data-recent-row-freshness'),
|
|
74
|
+
alpha: parseFloat(el.getAttribute('data-recent-row-freshness-alpha') || ''),
|
|
75
|
+
cx: parseFloat(el.getAttribute('cx') || ''),
|
|
76
|
+
r: parseFloat(el.getAttribute('r') || ''),
|
|
77
|
+
tag: el.tagName.toLowerCase(),
|
|
78
|
+
}));
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
await browser.close();
|
|
82
|
+
|
|
83
|
+
if (probes.length !== 3) {
|
|
84
|
+
console.log(`❌ wrong pip count: expected 3, got ${probes.length}`, probes);
|
|
85
|
+
process.exit(1);
|
|
86
|
+
}
|
|
87
|
+
// Rows are sorted by recency (newest first), so probes[0] is freshest.
|
|
88
|
+
const [pFresh, pMid, pStale] = probes;
|
|
89
|
+
const results = {
|
|
90
|
+
three_pips: probes.length === 3,
|
|
91
|
+
all_circles: probes.every(p => p.tag === 'circle'),
|
|
92
|
+
all_at_x_10: probes.every(p => Math.abs(p.cx - 10) < 0.01),
|
|
93
|
+
all_radius_1p6: probes.every(p => Math.abs(p.r - 1.6) < 0.01),
|
|
94
|
+
fresh_alpha_1: Math.abs(pFresh.alpha - 1.0) < 0.05,
|
|
95
|
+
mid_alpha_0p7_to_0p9: pMid.alpha > 0.7 && pMid.alpha < 0.95,
|
|
96
|
+
stale_alpha_floor_0p25: Math.abs(pStale.alpha - 0.25) < 0.05,
|
|
97
|
+
ladder_descends: pFresh.alpha > pMid.alpha && pMid.alpha > pStale.alpha,
|
|
98
|
+
};
|
|
99
|
+
const ok = Object.values(results).every(Boolean);
|
|
100
|
+
console.log(`${ok ? '✅' : '❌'} recent-row freshness pip:`, JSON.stringify(results),
|
|
101
|
+
`\n probes=`, probes);
|
|
102
|
+
process.exit(ok ? 0 : 1);
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/* Round 127 verification: recent-signal panel row mirrors R126's
|
|
2
|
+
* canvas hot-badge convention. When link.count >= 10 the count
|
|
3
|
+
* digit inside the row text renders in amber (#d97706 light,
|
|
4
|
+
* #fbbf24 dark) + bold (font-weight 700). Surrounding alias text +
|
|
5
|
+
* separators stay in legendText/legendHeadline.
|
|
6
|
+
*
|
|
7
|
+
* Fleet:
|
|
8
|
+
* alpha → beta: 12 msgs → HOT row, count tspan amber+bold
|
|
9
|
+
* beta → gamma: 4 msgs → warm row, count tspan default
|
|
10
|
+
*
|
|
11
|
+
* Path:
|
|
12
|
+
* 1. recent panel has 2 rows; data-recent-row-hot reflects bucket
|
|
13
|
+
* 2. alpha→beta row: data-recent-row-count-hot tspan present, amber
|
|
14
|
+
* 3. beta→gamma row: data-recent-row-count (non-hot) tspan present
|
|
15
|
+
* 4. Symmetry with R126: the canvas badge for alpha→beta and the
|
|
16
|
+
* recent-row count for alpha→beta both render the same amber
|
|
17
|
+
* hex.
|
|
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: 1400, 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 { localStorage.setItem('anet-theme', 'cyber'); sessionStorage.setItem('anet_v3_auth', '1'); } catch {}
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
const fresh = new Date(Date.now() - 60 * 1000).toISOString();
|
|
32
|
+
await ctx.route('**/api/hub/status*', async (route) => {
|
|
33
|
+
const r = await route.fetch();
|
|
34
|
+
const b = await r.json();
|
|
35
|
+
const nid = (b.sessions || [])[0]?.network_id || 'default';
|
|
36
|
+
const mk = (alias, status) => ({
|
|
37
|
+
alias, status, model: 'claude-opus-4', runtime: 'cli-claude-code',
|
|
38
|
+
network_id: nid, project_dir: null,
|
|
39
|
+
created_at: fresh, updated_at: fresh, last_seen_at: fresh,
|
|
40
|
+
});
|
|
41
|
+
await route.fulfill({ response: r, json: { ...b, sessions: [
|
|
42
|
+
mk('alpha', 'working'), mk('beta', 'working'), mk('gamma', 'idle'),
|
|
43
|
+
] } });
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
const now = Date.now();
|
|
47
|
+
const mkMsg = (id, from_alias, to_alias, ageMs) => ({
|
|
48
|
+
id, from_alias, to_alias, content: 'hi', network_id: 'default',
|
|
49
|
+
created_at: new Date(now - ageMs).toISOString(),
|
|
50
|
+
});
|
|
51
|
+
const msgs = [];
|
|
52
|
+
for (let i = 0; i < 12; i++) msgs.push(mkMsg(`a${i}`, 'alpha', 'beta', 20000 + i * 500));
|
|
53
|
+
for (let i = 0; i < 4; i++) msgs.push(mkMsg(`b${i}`, 'beta', 'gamma', 30000 + i * 500));
|
|
54
|
+
await ctx.route('**/api/hub/messages*', (route) => route.fulfill({ json: { messages: msgs } }));
|
|
55
|
+
await ctx.route('**/api/hub/tasks*', (route) => route.fulfill({ json: { tasks: [] } }));
|
|
56
|
+
|
|
57
|
+
const page = await ctx.newPage();
|
|
58
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
|
|
59
|
+
await page.waitForFunction(() => document.querySelectorAll('g[data-node]').length === 3, { timeout: 30000 });
|
|
60
|
+
await page.waitForSelector('[data-recent-row="alpha->beta"]', { timeout: 10000 });
|
|
61
|
+
await page.waitForTimeout(400);
|
|
62
|
+
|
|
63
|
+
const inspect = (key) => page.evaluate((k) => {
|
|
64
|
+
const row = document.querySelector(`[data-recent-row="${k}"]`);
|
|
65
|
+
if (!row) return null;
|
|
66
|
+
const hotTspan = row.querySelector('[data-recent-row-count-hot]');
|
|
67
|
+
const warmTspan = row.querySelector('[data-recent-row-count]');
|
|
68
|
+
return {
|
|
69
|
+
hot: row.getAttribute('data-recent-row-hot'),
|
|
70
|
+
hotTspanText: hotTspan?.textContent,
|
|
71
|
+
hotTspanFill: hotTspan?.getAttribute('fill'),
|
|
72
|
+
hotTspanWeight: hotTspan?.getAttribute('font-weight'),
|
|
73
|
+
warmTspanText: warmTspan?.textContent,
|
|
74
|
+
};
|
|
75
|
+
}, key);
|
|
76
|
+
|
|
77
|
+
const a2b = await inspect('alpha->beta');
|
|
78
|
+
const b2g = await inspect('beta->gamma');
|
|
79
|
+
|
|
80
|
+
// Also assert the canvas badge for alpha→beta still flips to the
|
|
81
|
+
// same amber stroke — symmetry of canvas + panel hot signals.
|
|
82
|
+
const badgeStroke = await page.evaluate(() => {
|
|
83
|
+
const g = document.querySelector('[data-edge-count-badge="alpha->beta"]');
|
|
84
|
+
return g?.querySelector('circle')?.getAttribute('stroke');
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
await browser.close();
|
|
88
|
+
|
|
89
|
+
// Dark theme amber: #fbbf24
|
|
90
|
+
const amberHex = '#fbbf24';
|
|
91
|
+
|
|
92
|
+
const results = {
|
|
93
|
+
a2b_attrHot: a2b !== null && a2b.hot === 'true',
|
|
94
|
+
a2b_hotTspan: a2b !== null && a2b.hotTspanText === '12',
|
|
95
|
+
a2b_amberFill: a2b !== null && (a2b.hotTspanFill || '').toLowerCase() === amberHex,
|
|
96
|
+
a2b_boldWeight: a2b !== null && a2b.hotTspanWeight === '700',
|
|
97
|
+
a2b_noWarmTspan: a2b !== null && a2b.warmTspanText === undefined,
|
|
98
|
+
|
|
99
|
+
b2g_attrNotHot: b2g !== null && b2g.hot === 'false',
|
|
100
|
+
b2g_warmTspan: b2g !== null && b2g.warmTspanText === '4',
|
|
101
|
+
b2g_noHotTspan: b2g !== null && a2b !== null && b2g.hotTspanText === undefined,
|
|
102
|
+
|
|
103
|
+
symmetric_badgeAmber: (badgeStroke || '').toLowerCase() === amberHex,
|
|
104
|
+
};
|
|
105
|
+
const ok = Object.values(results).every(Boolean);
|
|
106
|
+
console.log(`${ok ? '✅' : '❌'} recent-row hot:`, JSON.stringify(results),
|
|
107
|
+
`\n a2b=`, a2b,
|
|
108
|
+
`\n b2g=`, b2g,
|
|
109
|
+
`\n canvas badge stroke for alpha→beta =`, badgeStroke);
|
|
110
|
+
process.exit(ok ? 0 : 1);
|