@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,101 @@
|
|
|
1
|
+
/* Round 180 verification: working / online / vendor-letter chips
|
|
2
|
+
* pick up box-shadow transition on pin/unpin.
|
|
3
|
+
*
|
|
4
|
+
* Pre-R180 the inset-ring pin-mirror style snapped instantly when
|
|
5
|
+
* the user pinned or unpinned a filter via these three chip
|
|
6
|
+
* surfaces. R165 had added the transition to pressure-bar
|
|
7
|
+
* segments only — R180 closes the smooth-pin-mirror family
|
|
8
|
+
* across all chip-row pinnable surfaces.
|
|
9
|
+
*
|
|
10
|
+
* Test:
|
|
11
|
+
* 1. Mock 3 working sessions across 2 vendors (claude + 书生)
|
|
12
|
+
* 2. Probe inline transition on working / online / vendor chips
|
|
13
|
+
* 3. All three should have 'box-shadow 150ms ease-out' in their
|
|
14
|
+
* inline transition style
|
|
15
|
+
*/
|
|
16
|
+
import { chromium } from 'playwright';
|
|
17
|
+
import { readFileSync } from 'node:fs';
|
|
18
|
+
|
|
19
|
+
const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
|
|
20
|
+
const browser = await chromium.launch({ headless: true });
|
|
21
|
+
|
|
22
|
+
const ctx = await browser.newContext({ viewport: { width: 1500, height: 1500 } });
|
|
23
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
24
|
+
await ctx.addInitScript(() => {
|
|
25
|
+
try { localStorage.setItem('anet-theme', 'cyber'); sessionStorage.setItem('anet_v3_auth', '1'); } catch {}
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
const fresh = new Date(Date.now() - 60 * 1000).toISOString();
|
|
29
|
+
await ctx.route('**/api/hub/status*', async (route) => {
|
|
30
|
+
const r = await route.fetch();
|
|
31
|
+
const b = await r.json();
|
|
32
|
+
const nid = (b.sessions || [])[0]?.network_id || 'default';
|
|
33
|
+
// Two distinct vendor families so vendor letter chip shows up
|
|
34
|
+
// (vendorDist.length > 1 requirement).
|
|
35
|
+
const mk = (alias, model) => ({
|
|
36
|
+
alias, status: 'working', model, runtime: 'cli-claude-code',
|
|
37
|
+
network_id: nid, project_dir: null,
|
|
38
|
+
created_at: fresh, updated_at: fresh, last_seen_at: fresh,
|
|
39
|
+
});
|
|
40
|
+
await route.fulfill({ response: r, json: { ...b, sessions: [
|
|
41
|
+
mk('alpha', 'claude-opus-4'),
|
|
42
|
+
mk('beta', 'claude-opus-4'),
|
|
43
|
+
mk('gamma', 'intern-s1-mini'),
|
|
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
|
+
|
|
49
|
+
const page = await ctx.newPage();
|
|
50
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
|
|
51
|
+
await page.waitForFunction(() => document.querySelectorAll('g[data-node]').length === 3, { timeout: 30000 });
|
|
52
|
+
await page.waitForSelector('[data-working-chip]', { timeout: 10000 });
|
|
53
|
+
await page.waitForSelector('[data-vendor-letter]', { timeout: 10000 });
|
|
54
|
+
await page.waitForTimeout(400);
|
|
55
|
+
|
|
56
|
+
const probe = async () => page.evaluate(() => {
|
|
57
|
+
const grab = (sel) => {
|
|
58
|
+
const el = document.querySelector(sel);
|
|
59
|
+
return el ? {
|
|
60
|
+
transition: el.style.transition || getComputedStyle(el).transition || '',
|
|
61
|
+
boxShadow: el.style.boxShadow || getComputedStyle(el).boxShadow || '',
|
|
62
|
+
} : null;
|
|
63
|
+
};
|
|
64
|
+
return {
|
|
65
|
+
working: grab('[data-working-chip]'),
|
|
66
|
+
online: grab('[data-online-chip-clickable]'),
|
|
67
|
+
vendor: grab('[data-vendor-letter]'),
|
|
68
|
+
};
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
const idle = await probe();
|
|
72
|
+
|
|
73
|
+
// Click the working chip to pin → boxShadow should appear
|
|
74
|
+
await page.locator('[data-working-chip]').click();
|
|
75
|
+
await page.waitForTimeout(250);
|
|
76
|
+
const pinnedWorking = await probe();
|
|
77
|
+
|
|
78
|
+
await browser.close();
|
|
79
|
+
|
|
80
|
+
const hasTransition = (s) =>
|
|
81
|
+
(s?.transition || '').includes('box-shadow 150ms') ||
|
|
82
|
+
/box-shadow\s+0\.15s|box-shadow\s+150ms/.test(s?.transition || '');
|
|
83
|
+
|
|
84
|
+
const results = {
|
|
85
|
+
working_found: idle.working !== null,
|
|
86
|
+
online_found: idle.online !== null,
|
|
87
|
+
vendor_found: idle.vendor !== null,
|
|
88
|
+
working_has_bs_transition: hasTransition(idle.working),
|
|
89
|
+
online_has_bs_transition: hasTransition(idle.online),
|
|
90
|
+
vendor_has_bs_transition: hasTransition(idle.vendor),
|
|
91
|
+
// Pre-pin: no inset rings on working chip
|
|
92
|
+
working_idle_no_inset: !(idle.working?.boxShadow || '').includes('inset'),
|
|
93
|
+
// After pin: inset rings appear, transition still set
|
|
94
|
+
working_pinned_has_inset: (pinnedWorking.working?.boxShadow || '').includes('inset'),
|
|
95
|
+
working_pinned_keeps_transition: hasTransition(pinnedWorking.working),
|
|
96
|
+
};
|
|
97
|
+
const ok = Object.values(results).every(Boolean);
|
|
98
|
+
console.log(`${ok ? '✅' : '❌'} pin-mirror transition:`, JSON.stringify(results),
|
|
99
|
+
`\n idle =`, idle,
|
|
100
|
+
`\n pinned =`, pinnedWorking);
|
|
101
|
+
process.exit(ok ? 0 : 1);
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/* Round 66 verification: pinnedStatus + pinnedGroup persist across page
|
|
2
|
+
* reloads via sessionStorage. Stale group pins (group no longer exists)
|
|
3
|
+
* are cleared on hydration so the chip row doesn't show a phantom team.
|
|
4
|
+
*
|
|
5
|
+
* - Pre-seed sessionStorage with anet-topo-pinned-status='working' →
|
|
6
|
+
* reload → assert filter pill renders + working stays bright + idles
|
|
7
|
+
* dim. (Status pin survives.)
|
|
8
|
+
* - Pre-seed anet-topo-pinned-group='alpha' WITH alpha sessions → reload
|
|
9
|
+
* → pill renders + alpha team stays bright.
|
|
10
|
+
* - Pre-seed anet-topo-pinned-group='ghost' WITHOUT any ghost session →
|
|
11
|
+
* reload → the stale pin is cleared on hydration; no pill renders.
|
|
12
|
+
*/
|
|
13
|
+
import { chromium } from 'playwright';
|
|
14
|
+
import { readFileSync } from 'node:fs';
|
|
15
|
+
|
|
16
|
+
const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
|
|
17
|
+
const browser = await chromium.launch({ headless: true });
|
|
18
|
+
|
|
19
|
+
async function probe({ status = null, group = null, sessions }) {
|
|
20
|
+
const ctx = await browser.newContext({ viewport: { width: 1400, height: 1500 } });
|
|
21
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
22
|
+
await ctx.addInitScript(({ status, group }) => {
|
|
23
|
+
try {
|
|
24
|
+
localStorage.setItem('anet-theme', 'cyber');
|
|
25
|
+
localStorage.setItem('anet-topo-layout', 'grid');
|
|
26
|
+
sessionStorage.setItem('anet_v3_auth', '1');
|
|
27
|
+
if (status) sessionStorage.setItem('anet-topo-pinned-status', status);
|
|
28
|
+
else sessionStorage.removeItem('anet-topo-pinned-status');
|
|
29
|
+
if (group) sessionStorage.setItem('anet-topo-pinned-group', group);
|
|
30
|
+
else sessionStorage.removeItem('anet-topo-pinned-group');
|
|
31
|
+
} catch {}
|
|
32
|
+
}, { status, group });
|
|
33
|
+
const fresh = new Date(Date.now() - 60 * 1000).toISOString();
|
|
34
|
+
await ctx.route('**/api/hub/status*', async (route) => {
|
|
35
|
+
const r = await route.fetch();
|
|
36
|
+
const b = await r.json();
|
|
37
|
+
const nid = (b.sessions || [])[0]?.network_id || 'default';
|
|
38
|
+
const seeded = sessions.map(s => ({
|
|
39
|
+
alias: s.alias, status: s.status, network_id: nid, project_dir: null,
|
|
40
|
+
created_at: fresh, updated_at: fresh, last_seen_at: fresh,
|
|
41
|
+
}));
|
|
42
|
+
await route.fulfill({ response: r, json: { ...b, sessions: seeded } });
|
|
43
|
+
});
|
|
44
|
+
await ctx.route('**/api/hub/messages*', (r) => r.fulfill({ json: { messages: [] } }));
|
|
45
|
+
await ctx.route('**/api/hub/tasks*', (r) => r.fulfill({ json: { tasks: [] } }));
|
|
46
|
+
const page = await ctx.newPage();
|
|
47
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
|
|
48
|
+
await page.waitForFunction(c => document.querySelectorAll('g[data-node]').length === c, sessions.length, { timeout: 30000 });
|
|
49
|
+
await page.waitForTimeout(700);
|
|
50
|
+
const result = await page.evaluate(() => {
|
|
51
|
+
const pills = [...document.querySelectorAll('[data-active-filter]')].map(el => ({
|
|
52
|
+
kind: el.getAttribute('data-active-filter'),
|
|
53
|
+
text: (el.textContent || '').trim(),
|
|
54
|
+
}));
|
|
55
|
+
const opacities = {};
|
|
56
|
+
for (const el of document.querySelectorAll('g[data-node]')) {
|
|
57
|
+
const a = el.getAttribute('data-node');
|
|
58
|
+
if (a) opacities[a] = +(el.style.opacity || '1');
|
|
59
|
+
}
|
|
60
|
+
const storage = {
|
|
61
|
+
status: sessionStorage.getItem('anet-topo-pinned-status'),
|
|
62
|
+
group: sessionStorage.getItem('anet-topo-pinned-group'),
|
|
63
|
+
};
|
|
64
|
+
return { pills, opacities, storage };
|
|
65
|
+
});
|
|
66
|
+
await ctx.close();
|
|
67
|
+
return result;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const sessions3 = [
|
|
71
|
+
{ alias: 'alpha1', status: 'working' },
|
|
72
|
+
{ alias: 'alpha2', status: 'idle' },
|
|
73
|
+
{ alias: 'beta', status: 'idle' },
|
|
74
|
+
];
|
|
75
|
+
const alphaPlus = [
|
|
76
|
+
{ alias: 'alpha1', status: 'idle' },
|
|
77
|
+
{ alias: 'alpha2', status: 'idle' },
|
|
78
|
+
{ alias: 'alpha3', status: 'idle' },
|
|
79
|
+
{ alias: 'beta', status: 'idle' },
|
|
80
|
+
];
|
|
81
|
+
|
|
82
|
+
const statusRestore = await probe({ status: 'working', sessions: sessions3 });
|
|
83
|
+
const groupRestore = await probe({ group: 'alpha', sessions: alphaPlus });
|
|
84
|
+
const stalePin = await probe({ group: 'ghost', sessions: sessions3 });
|
|
85
|
+
|
|
86
|
+
await browser.close();
|
|
87
|
+
|
|
88
|
+
const bright = (v) => v != null && v >= 0.55;
|
|
89
|
+
const dim = (v) => v != null && v < 0.4;
|
|
90
|
+
const results = {
|
|
91
|
+
statusPill_restored: statusRestore.pills.length === 1 && statusRestore.pills[0].kind === 'status'
|
|
92
|
+
&& /filter:\s*working/.test(statusRestore.pills[0].text),
|
|
93
|
+
statusPin_dimsIdle: bright(statusRestore.opacities.alpha1) && dim(statusRestore.opacities.alpha2),
|
|
94
|
+
groupPill_restored: groupRestore.pills.length === 1 && groupRestore.pills[0].kind === 'group'
|
|
95
|
+
&& /filter:\s*alpha/.test(groupRestore.pills[0].text),
|
|
96
|
+
groupPin_dimsOutsider: bright(groupRestore.opacities.alpha1) && dim(groupRestore.opacities.beta),
|
|
97
|
+
stale_pillCleared: stalePin.pills.length === 0,
|
|
98
|
+
stale_storageCleared: stalePin.storage.group === null,
|
|
99
|
+
};
|
|
100
|
+
const ok = Object.values(results).every(Boolean);
|
|
101
|
+
console.log(`${ok ? '✅' : '❌'} pin persistence:`, JSON.stringify(results),
|
|
102
|
+
`\n statusRestore=`, statusRestore,
|
|
103
|
+
`\n groupRestore=`, groupRestore,
|
|
104
|
+
`\n stalePin=`, stalePin);
|
|
105
|
+
process.exit(ok ? 0 : 1);
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/* Round 37 verification: ChatPopover header carries cwd / last-seen
|
|
2
|
+
* lines pulled from the SWR session cache. Three cases:
|
|
3
|
+
* - online node with cwd → cwd line, no last-seen
|
|
4
|
+
* - offline node with cwd → both lines
|
|
5
|
+
* - bare node (no cwd, no last_seen) → drag/Esc fallback hint */
|
|
6
|
+
import { chromium } from 'playwright';
|
|
7
|
+
import { readFileSync } from 'node:fs';
|
|
8
|
+
|
|
9
|
+
const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
|
|
10
|
+
const browser = await chromium.launch({ headless: true });
|
|
11
|
+
|
|
12
|
+
async function probe(targetAlias) {
|
|
13
|
+
const ctx = await browser.newContext({ viewport: { width: 1400, height: 1000 } });
|
|
14
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
15
|
+
await ctx.addInitScript(() => {
|
|
16
|
+
try {
|
|
17
|
+
localStorage.setItem('anet-theme', 'cyber');
|
|
18
|
+
localStorage.setItem('anet-topo-layout', 'grid');
|
|
19
|
+
localStorage.setItem('anet-topo-nodescale', '1');
|
|
20
|
+
sessionStorage.setItem('anet_v3_auth', '1');
|
|
21
|
+
} catch {}
|
|
22
|
+
});
|
|
23
|
+
const fresh = new Date(Date.now() - 60 * 1000).toISOString();
|
|
24
|
+
const offline = new Date(Date.now() - 8 * 60 * 1000).toISOString(); // 8 min ago
|
|
25
|
+
await ctx.route('**/api/hub/status*', async (route) => {
|
|
26
|
+
const r = await route.fetch();
|
|
27
|
+
const b = await r.json();
|
|
28
|
+
const nid = (b.sessions || [])[0]?.network_id || 'default';
|
|
29
|
+
const sessions = [
|
|
30
|
+
{ alias: 'liveCwd', status: 'idle', network_id: nid,
|
|
31
|
+
project_dir: '/home/vansin/agent-orchestra',
|
|
32
|
+
created_at: fresh, updated_at: fresh, last_seen_at: fresh },
|
|
33
|
+
{ alias: 'offCwd', status: 'offline', network_id: nid,
|
|
34
|
+
project_dir: '/home/vansin/some-project',
|
|
35
|
+
created_at: fresh, updated_at: fresh, last_seen_at: offline },
|
|
36
|
+
{ alias: 'bare', status: 'idle', network_id: nid, project_dir: null,
|
|
37
|
+
created_at: fresh, updated_at: fresh, last_seen_at: fresh },
|
|
38
|
+
];
|
|
39
|
+
await route.fulfill({ response: r, json: { ...b, sessions } });
|
|
40
|
+
});
|
|
41
|
+
await ctx.route('**/api/hub/tasks*', (route) => route.fulfill({ json: { tasks: [] } }));
|
|
42
|
+
const page = await ctx.newPage();
|
|
43
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
|
|
44
|
+
await page.waitForFunction(() => document.querySelectorAll('g[data-node]').length === 3, { timeout: 30000 });
|
|
45
|
+
await page.waitForTimeout(400);
|
|
46
|
+
await page.locator(`g[data-node="${targetAlias}"]`).click();
|
|
47
|
+
await page.waitForTimeout(300);
|
|
48
|
+
const meta = await page.evaluate(() => {
|
|
49
|
+
const cwd = document.querySelector('[data-popover-cwd]');
|
|
50
|
+
const ls = document.querySelector('[data-popover-lastseen]');
|
|
51
|
+
const popover = document.querySelector('[aria-label^="Chat with"]');
|
|
52
|
+
const dragHint = popover ? [...popover.querySelectorAll('div')].find(d => /Drag to move/.test(d.textContent || '')) : null;
|
|
53
|
+
return {
|
|
54
|
+
cwdText: cwd?.textContent || null,
|
|
55
|
+
lsText: ls?.textContent || null,
|
|
56
|
+
dragHintPresent: !!dragHint,
|
|
57
|
+
};
|
|
58
|
+
});
|
|
59
|
+
await ctx.close();
|
|
60
|
+
return meta;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const live = await probe('liveCwd');
|
|
64
|
+
const off = await probe('offCwd');
|
|
65
|
+
const bare = await probe('bare');
|
|
66
|
+
await browser.close();
|
|
67
|
+
|
|
68
|
+
const results = {
|
|
69
|
+
liveShowsCwd: live.cwdText === 'cwd: /home/vansin/agent-orchestra' && live.lsText === null && !live.dragHintPresent,
|
|
70
|
+
offlineShowsBoth: off.cwdText === 'cwd: /home/vansin/some-project'
|
|
71
|
+
&& /last seen: [78]m ago/.test(off.lsText || '')
|
|
72
|
+
&& !off.dragHintPresent,
|
|
73
|
+
bareFallsBackToDragHint: bare.cwdText === null && bare.lsText === null && bare.dragHintPresent,
|
|
74
|
+
};
|
|
75
|
+
const ok = Object.values(results).every(Boolean);
|
|
76
|
+
console.log(`${ok ? '✅' : '❌'} popover meta:`, JSON.stringify(results),
|
|
77
|
+
`\n live=`, live, `\n off=`, off, `\n bare=`, bare);
|
|
78
|
+
process.exit(ok ? 0 : 1);
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/* Round 238 verification: prepublishOnly is now a guard-only check
|
|
2
|
+
* instead of a destructive rebuild. This closes the chunk-500 root
|
|
3
|
+
* cause documented since R224.
|
|
4
|
+
*
|
|
5
|
+
* Pre-R238 prepublishOnly was 'rm -rf .next && npm run build', which:
|
|
6
|
+
* 1. Deleted .next/ on disk during npm publish.
|
|
7
|
+
* 2. Rebuilt with fresh content-hashed chunk filenames.
|
|
8
|
+
* 3. Left the already-running next-server process with a stale
|
|
9
|
+
* in-memory manifest pointing at chunks that no longer existed
|
|
10
|
+
* on disk → ENOENT → 500 on lazy chunk fetch.
|
|
11
|
+
* 4. Required a manual 'restart dash AFTER publish' step every
|
|
12
|
+
* round as a workaround.
|
|
13
|
+
*
|
|
14
|
+
* Post-R238 prepublishOnly is a guard:
|
|
15
|
+
* '[ -f .next/BUILD_ID ] || (echo ... && exit 1)'
|
|
16
|
+
*
|
|
17
|
+
* - If .next/BUILD_ID exists, succeed silently — publish proceeds
|
|
18
|
+
* with whatever .next/ is on disk (intentional: pipeline order
|
|
19
|
+
* is now bump → build → restart → test → publish, so the build
|
|
20
|
+
* already embeds the new version BEFORE publish).
|
|
21
|
+
* - If .next/BUILD_ID is missing, fail loudly with the R224
|
|
22
|
+
* reference so the developer knows what to do.
|
|
23
|
+
*
|
|
24
|
+
* No rm-rf-rebuild = running server's manifest stays consistent
|
|
25
|
+
* with disk chunks through the publish step. No post-publish
|
|
26
|
+
* restart needed.
|
|
27
|
+
*
|
|
28
|
+
* Test verifies:
|
|
29
|
+
* 1. package.json scripts.prepublishOnly contains no 'rm' command
|
|
30
|
+
* (destructive form removed)
|
|
31
|
+
* 2. package.json scripts.prepublishOnly contains no 'npm run
|
|
32
|
+
* build' (rebuild on publish removed)
|
|
33
|
+
* 3. The guard form is present (BUILD_ID check)
|
|
34
|
+
* 4. Running `npm run prepublishOnly` exits 0 when .next/BUILD_ID
|
|
35
|
+
* exists, leaving .next/ untouched (mtime + content hash stable)
|
|
36
|
+
*/
|
|
37
|
+
import { readFileSync, statSync } from 'node:fs';
|
|
38
|
+
import { execSync } from 'node:child_process';
|
|
39
|
+
import { createHash } from 'node:crypto';
|
|
40
|
+
|
|
41
|
+
const pkg = JSON.parse(readFileSync('/home/vansin/agent-network-dashboard/package.json', 'utf8'));
|
|
42
|
+
const hookSrc = pkg.scripts?.prepublishOnly || '';
|
|
43
|
+
|
|
44
|
+
// Hash + mtime of .next/BUILD_ID before running the hook
|
|
45
|
+
const buildIdPath = '/home/vansin/agent-network-dashboard/.next/BUILD_ID';
|
|
46
|
+
const before = (() => {
|
|
47
|
+
try {
|
|
48
|
+
return {
|
|
49
|
+
mtime: statSync(buildIdPath).mtimeMs,
|
|
50
|
+
hash: createHash('sha256').update(readFileSync(buildIdPath)).digest('hex'),
|
|
51
|
+
};
|
|
52
|
+
} catch {
|
|
53
|
+
return null;
|
|
54
|
+
}
|
|
55
|
+
})();
|
|
56
|
+
|
|
57
|
+
// Run the prepublishOnly hook explicitly via npm run
|
|
58
|
+
let exitCode = -1;
|
|
59
|
+
try {
|
|
60
|
+
execSync('npm run prepublishOnly', {
|
|
61
|
+
cwd: '/home/vansin/agent-network-dashboard',
|
|
62
|
+
stdio: 'pipe',
|
|
63
|
+
});
|
|
64
|
+
exitCode = 0;
|
|
65
|
+
} catch (e) {
|
|
66
|
+
exitCode = e.status ?? -1;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const after = (() => {
|
|
70
|
+
try {
|
|
71
|
+
return {
|
|
72
|
+
mtime: statSync(buildIdPath).mtimeMs,
|
|
73
|
+
hash: createHash('sha256').update(readFileSync(buildIdPath)).digest('hex'),
|
|
74
|
+
};
|
|
75
|
+
} catch {
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
})();
|
|
79
|
+
|
|
80
|
+
const results = {
|
|
81
|
+
hook_present: typeof hookSrc === 'string' && hookSrc.length > 0,
|
|
82
|
+
no_rm_command: !/\brm\b/.test(hookSrc),
|
|
83
|
+
has_build_id_check: /\.next\/BUILD_ID/.test(hookSrc),
|
|
84
|
+
has_exit_path: /exit\s+1/.test(hookSrc),
|
|
85
|
+
hook_exits_zero: exitCode === 0,
|
|
86
|
+
build_id_mtime_stable: before !== null && after !== null && before.mtime === after.mtime,
|
|
87
|
+
build_id_hash_stable: before !== null && after !== null && before.hash === after.hash,
|
|
88
|
+
};
|
|
89
|
+
const ok = Object.values(results).every(Boolean);
|
|
90
|
+
console.log(`${ok ? '✅' : '❌'} prepublishOnly guard:`, JSON.stringify(results),
|
|
91
|
+
'\n hookSrc:', hookSrc,
|
|
92
|
+
'\n exitCode:', exitCode,
|
|
93
|
+
'\n before:', before,
|
|
94
|
+
'\n after: ', after);
|
|
95
|
+
process.exit(ok ? 0 : 1);
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/* Round 31 verification: fleet-pressure chip with proportional segments.
|
|
2
|
+
* 4 working + 6 idle + 2 offline = 12 total → 33% / 50% / 17%. */
|
|
3
|
+
import { chromium } from 'playwright';
|
|
4
|
+
import { readFileSync } from 'node:fs';
|
|
5
|
+
|
|
6
|
+
const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
|
|
7
|
+
const browser = await chromium.launch({ headless: true });
|
|
8
|
+
const ctx = await browser.newContext({ viewport: { width: 1400, height: 1000 } });
|
|
9
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
10
|
+
await ctx.addInitScript(() => {
|
|
11
|
+
try {
|
|
12
|
+
localStorage.setItem('anet-theme', 'cyber');
|
|
13
|
+
localStorage.setItem('anet-topo-layout', 'grid');
|
|
14
|
+
sessionStorage.setItem('anet_v3_auth', '1');
|
|
15
|
+
} catch {}
|
|
16
|
+
});
|
|
17
|
+
const fresh = new Date(Date.now() - 60 * 1000).toISOString();
|
|
18
|
+
await ctx.route('**/api/hub/status*', async (route) => {
|
|
19
|
+
const r = await route.fetch();
|
|
20
|
+
const b = await r.json();
|
|
21
|
+
const nid = (b.sessions || [])[0]?.network_id || 'default';
|
|
22
|
+
const make = (alias, status) => ({
|
|
23
|
+
alias, status, network_id: nid, project_dir: null,
|
|
24
|
+
created_at: fresh, updated_at: fresh, last_seen_at: fresh,
|
|
25
|
+
});
|
|
26
|
+
const sessions = [
|
|
27
|
+
...Array.from({ length: 4 }, (_, i) => make(`w${i}`, 'working')),
|
|
28
|
+
...Array.from({ length: 6 }, (_, i) => make(`i${i}`, 'idle')),
|
|
29
|
+
...Array.from({ length: 2 }, (_, i) => make(`o${i}`, 'offline')),
|
|
30
|
+
];
|
|
31
|
+
await route.fulfill({ response: r, json: { ...b, sessions } });
|
|
32
|
+
});
|
|
33
|
+
await ctx.route('**/api/hub/tasks*', (route) => route.fulfill({ json: { tasks: [] } }));
|
|
34
|
+
const page = await ctx.newPage();
|
|
35
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
|
|
36
|
+
await page.waitForSelector('[data-fleet-pressure]', { timeout: 30000 });
|
|
37
|
+
await page.waitForTimeout(400);
|
|
38
|
+
|
|
39
|
+
const chip = '[data-fleet-pressure]';
|
|
40
|
+
const titleText = await page.locator(chip).getAttribute('title');
|
|
41
|
+
// The chip layout: <chip> > <label-span> + <bar-span> ; bar-span has the 3 segment spans.
|
|
42
|
+
const segments = await page.evaluate(() => {
|
|
43
|
+
const chip = document.querySelector('[data-fleet-pressure]');
|
|
44
|
+
if (!chip) return [];
|
|
45
|
+
// The bar container is the inline-flex w-16 span (second child).
|
|
46
|
+
const bar = [...chip.children].find(c => c.classList?.contains('w-16'));
|
|
47
|
+
if (!bar) return [];
|
|
48
|
+
return [...bar.children].map(el => ({ width: el.style.width, background: el.style.background }));
|
|
49
|
+
});
|
|
50
|
+
const segmentWidths = segments.map(s => s.width);
|
|
51
|
+
const segmentColors = segments.map(s => s.background);
|
|
52
|
+
|
|
53
|
+
// 4/12 = 33.33%, 6/12 = 50.00%, 2/12 = 16.67%
|
|
54
|
+
const close = (a, b) => Math.abs(parseFloat(a) - b) < 0.5;
|
|
55
|
+
|
|
56
|
+
await browser.close();
|
|
57
|
+
const results = {
|
|
58
|
+
titleHasCounts: titleText === '4 working · 6 idle · 2 offline',
|
|
59
|
+
threeSegments: segmentWidths.length === 3,
|
|
60
|
+
workingProportion: close(segmentWidths[0], 100 * 4 / 12),
|
|
61
|
+
idleProportion: close(segmentWidths[1], 100 * 6 / 12),
|
|
62
|
+
offlineProportion: close(segmentWidths[2], 100 * 2 / 12),
|
|
63
|
+
workingColor: /22c55e|rgb\(34, 197, 94\)/.test(segmentColors[0] || ''),
|
|
64
|
+
idleColor: /2dd4bf|rgb\(45, 212, 191\)/.test(segmentColors[1] || ''),
|
|
65
|
+
offlineColor: /6b7280|rgb\(107, 114, 128\)/.test(segmentColors[2] || ''),
|
|
66
|
+
};
|
|
67
|
+
const ok = Object.values(results).every(Boolean);
|
|
68
|
+
console.log(`${ok ? '✅' : '❌'} pressure bar:`, JSON.stringify(results), `widths=${segmentWidths.join(',')} colors=${segmentColors.join(' | ')}`);
|
|
69
|
+
process.exit(ok ? 0 : 1);
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/* Round 83 verification: pressure-bar segments expose a hover preview
|
|
2
|
+
* before the click pins. Matches the R55 legend + R79 status chip +
|
|
3
|
+
* R80 vendor letter hover pattern — same activeStatus mechanism, just
|
|
4
|
+
* the last surface that was click-only.
|
|
5
|
+
*
|
|
6
|
+
* Fleet: 1 working + 2 idle + 1 offline. Hover the working segment →
|
|
7
|
+
* working node stays bright, idle + offline dim. Mouseleave → restore.
|
|
8
|
+
* Then click the working segment → pin sticks via boxShadow. Hovering
|
|
9
|
+
* idle while working is pinned → live preview switches; mouseleave
|
|
10
|
+
* falls back to the working pin (activeStatus = hoveredStatus ??
|
|
11
|
+
* pinnedStatus).
|
|
12
|
+
*/
|
|
13
|
+
import { chromium } from 'playwright';
|
|
14
|
+
import { readFileSync } from 'node:fs';
|
|
15
|
+
|
|
16
|
+
const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
|
|
17
|
+
const browser = await chromium.launch({ headless: true });
|
|
18
|
+
|
|
19
|
+
const ctx = await browser.newContext({ viewport: { width: 1400, height: 1200 } });
|
|
20
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
21
|
+
await ctx.addInitScript(() => {
|
|
22
|
+
try {
|
|
23
|
+
localStorage.setItem('anet-theme', 'cyber');
|
|
24
|
+
sessionStorage.setItem('anet_v3_auth', '1');
|
|
25
|
+
sessionStorage.removeItem('anet-topo-pinned-status');
|
|
26
|
+
sessionStorage.removeItem('anet-topo-pinned-group');
|
|
27
|
+
} catch {}
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
const fresh = new Date(Date.now() - 60 * 1000).toISOString();
|
|
31
|
+
const stale10 = new Date(Date.now() - 10 * 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 sessions = [
|
|
37
|
+
{ alias: 'wkr', status: 'working', model: 'claude-opus-4', runtime: 'cli-claude-code',
|
|
38
|
+
network_id: nid, project_dir: null, created_at: fresh, updated_at: fresh, last_seen_at: fresh },
|
|
39
|
+
{ alias: 'idl1', status: 'idle', model: 'claude-opus-4', runtime: 'cli-claude-code',
|
|
40
|
+
network_id: nid, project_dir: null, created_at: fresh, updated_at: fresh, last_seen_at: fresh },
|
|
41
|
+
{ alias: 'idl2', status: 'idle', model: 'claude-opus-4', runtime: 'cli-claude-code',
|
|
42
|
+
network_id: nid, project_dir: null, created_at: fresh, updated_at: fresh, last_seen_at: fresh },
|
|
43
|
+
{ alias: 'off', status: 'offline', model: 'claude-opus-4', runtime: 'cli-claude-code',
|
|
44
|
+
network_id: nid, project_dir: null, created_at: stale10, updated_at: stale10, last_seen_at: stale10 },
|
|
45
|
+
];
|
|
46
|
+
await route.fulfill({ response: r, json: { ...b, sessions } });
|
|
47
|
+
});
|
|
48
|
+
await ctx.route('**/api/hub/messages*', (route) => route.fulfill({ json: { messages: [] } }));
|
|
49
|
+
await ctx.route('**/api/hub/tasks*', (route) => route.fulfill({ json: { tasks: [] } }));
|
|
50
|
+
const page = await ctx.newPage();
|
|
51
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
|
|
52
|
+
await page.waitForFunction(() => document.querySelectorAll('g[data-node]').length === 4, { timeout: 30000 });
|
|
53
|
+
await page.waitForTimeout(500);
|
|
54
|
+
|
|
55
|
+
const ops = () => page.evaluate(() => {
|
|
56
|
+
const o = {};
|
|
57
|
+
for (const a of ['wkr', 'idl1', 'idl2', 'off']) {
|
|
58
|
+
const g = document.querySelector(`g[data-node="${a}"]`);
|
|
59
|
+
o[a] = g ? +(g.style.opacity || '1') : null;
|
|
60
|
+
}
|
|
61
|
+
return o;
|
|
62
|
+
});
|
|
63
|
+
const segShadow = (k) => page.evaluate((key) => {
|
|
64
|
+
const s = document.querySelector(`[data-pressure-seg="${key}"]`);
|
|
65
|
+
return s ? (s.getAttribute('style') || '').includes('inset') : false;
|
|
66
|
+
}, k);
|
|
67
|
+
|
|
68
|
+
const before = await ops();
|
|
69
|
+
|
|
70
|
+
// Hover working segment → working stays bright, others dim.
|
|
71
|
+
await page.locator('[data-pressure-seg="working"]').hover();
|
|
72
|
+
await page.waitForTimeout(250);
|
|
73
|
+
const onHoverWorking = await ops();
|
|
74
|
+
const hoverPinShadowBefore = await segShadow('working');
|
|
75
|
+
|
|
76
|
+
// Mouseleave → baseline restores (no pin yet).
|
|
77
|
+
await page.mouse.move(10, 10);
|
|
78
|
+
await page.waitForTimeout(250);
|
|
79
|
+
const afterLeave = await ops();
|
|
80
|
+
|
|
81
|
+
// Click to pin working — segment gets inset shadow.
|
|
82
|
+
await page.locator('[data-pressure-seg="working"]').click();
|
|
83
|
+
await page.mouse.move(10, 10);
|
|
84
|
+
await page.waitForTimeout(250);
|
|
85
|
+
const afterPin = await ops();
|
|
86
|
+
const pinShadow = await segShadow('working');
|
|
87
|
+
|
|
88
|
+
// Hover idle while working is pinned — hoveredStatus overrides for the
|
|
89
|
+
// duration of the hover. idle stays bright, working dims (transient).
|
|
90
|
+
await page.locator('[data-pressure-seg="idle"]').hover();
|
|
91
|
+
await page.waitForTimeout(250);
|
|
92
|
+
const onHoverIdle = await ops();
|
|
93
|
+
|
|
94
|
+
// Mouseleave → falls back to working pin (NOT cleared).
|
|
95
|
+
await page.mouse.move(10, 10);
|
|
96
|
+
await page.waitForTimeout(250);
|
|
97
|
+
const afterLeaveIdle = await ops();
|
|
98
|
+
|
|
99
|
+
await browser.close();
|
|
100
|
+
|
|
101
|
+
const bright = (v) => v != null && v >= 0.55;
|
|
102
|
+
const dim = (v) => v != null && v < 0.4;
|
|
103
|
+
const results = {
|
|
104
|
+
before_baseline: bright(before.wkr) && bright(before.idl1) && bright(before.idl2) && before.off <= 0.6,
|
|
105
|
+
hoverWorking_workerStays: bright(onHoverWorking.wkr),
|
|
106
|
+
hoverWorking_idlesDim: dim(onHoverWorking.idl1) && dim(onHoverWorking.idl2),
|
|
107
|
+
hoverWorking_offDim: dim(onHoverWorking.off),
|
|
108
|
+
hoverWorking_noPinYet: !hoverPinShadowBefore,
|
|
109
|
+
leave_restoresBaseline: bright(afterLeave.wkr) && bright(afterLeave.idl1) && bright(afterLeave.idl2),
|
|
110
|
+
pin_workerStays: bright(afterPin.wkr),
|
|
111
|
+
pin_idlesDim: dim(afterPin.idl1) && dim(afterPin.idl2),
|
|
112
|
+
pin_shadowRendered: pinShadow,
|
|
113
|
+
hoverIdle_transient: bright(onHoverIdle.idl1) && bright(onHoverIdle.idl2) && dim(onHoverIdle.wkr),
|
|
114
|
+
leaveIdle_pinPersists: bright(afterLeaveIdle.wkr) && dim(afterLeaveIdle.idl1) && dim(afterLeaveIdle.idl2),
|
|
115
|
+
};
|
|
116
|
+
const ok = Object.values(results).every(Boolean);
|
|
117
|
+
console.log(`${ok ? '✅' : '❌'} pressure-hover:`, JSON.stringify(results),
|
|
118
|
+
`\n before=`, before,
|
|
119
|
+
`\n onHoverWorking=`, onHoverWorking,
|
|
120
|
+
`\n afterPin=`, afterPin,
|
|
121
|
+
`\n onHoverIdle=`, onHoverIdle,
|
|
122
|
+
`\n afterLeaveIdle=`, afterLeaveIdle);
|
|
123
|
+
process.exit(ok ? 0 : 1);
|