@sleep2agi/agent-network-dashboard 0.4.6-preview.18 → 0.4.6-preview.180
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/app-path-routes-manifest.json +1 -0
- 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/routes-manifest.json +6 -0
- 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/api/hub/servers/route/app-paths-manifest.json +3 -0
- package/.next/server/app/api/hub/servers/route/build-manifest.json +9 -0
- package/.next/server/app/api/hub/servers/route/server-reference-manifest.json +4 -0
- package/.next/server/app/api/hub/servers/route.js +7 -0
- package/.next/server/app/api/hub/servers/route.js.map +5 -0
- package/.next/server/app/api/hub/servers/route.js.nft.json +1 -0
- package/.next/server/app/api/hub/servers/route_client-reference-manifest.js +3 -0
- 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/app-paths-manifest.json +1 -0
- package/.next/server/chunks/0ykm__next-internal_server_app_api_hub_servers_route_actions_08-m-cs.js +3 -0
- package/.next/server/chunks/0ykm__next-internal_server_app_api_hub_servers_route_actions_08-m-cs.js.map +1 -0
- package/.next/server/chunks/[root-of-the-server]__0tx8s8i._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__0tx8s8i._.js.map +1 -0
- 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/0ia0~8uq23xxr.js +1 -0
- package/.next/static/chunks/0otgjhpse~amj.css +2 -0
- package/.next/static/chunks/0rxrez_cjn.eh.js +1 -0
- package/.next/static/chunks/0tfbneqpxn9gw.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/17limi7in00fo.js +4 -0
- package/.next/trace +2 -2
- package/.next/trace-build +1 -1
- package/.next/types/routes.d.ts +2 -1
- package/.next/types/validator.ts +9 -0
- package/app/api/hub/servers/route.ts +39 -0
- package/app/components/ChatPopover.tsx +38 -2
- package/app/components/CommandPalette.tsx +107 -0
- package/app/components/HelpOverlay.tsx +126 -0
- package/app/components/ServersDrawer.tsx +64 -27
- package/app/components/TopoGraph.tsx +3569 -255
- package/app/components/utils.ts +8 -7
- package/app/globals.css +75 -5
- package/app/lib/time.ts +36 -0
- package/package.json +1 -1
- package/scripts/help-overlay-topo-test.mjs +44 -0
- package/scripts/servers-drawer-live-test.mjs +96 -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-test.mjs +73 -0
- package/scripts/topo-active-links-freshness-test.mjs +113 -0
- package/scripts/topo-active-links-tooltip-test.mjs +79 -0
- package/scripts/topo-arrival-ping-test.mjs +87 -0
- package/scripts/topo-arrow-tier-test.mjs +61 -0
- package/scripts/topo-auto-fit-test.mjs +73 -0
- package/scripts/topo-canvas-aria-test.mjs +108 -0
- package/scripts/topo-chat-focus-ring-test.mjs +77 -0
- package/scripts/topo-chat-target-breath-test.mjs +84 -0
- package/scripts/topo-chip-focus-test.mjs +95 -0
- package/scripts/topo-chip-pin-mirror-test.mjs +113 -0
- package/scripts/topo-chrome-a11y-test.mjs +107 -0
- package/scripts/topo-click-ripple-test.mjs +66 -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-cwd-tooltip-test.mjs +64 -0
- package/scripts/topo-dblclick-reset-test.mjs +74 -0
- package/scripts/topo-discrete-zoom-smooth-test.mjs +125 -0
- package/scripts/topo-dispatch-pulse-test.mjs +83 -0
- package/scripts/topo-edge-badge-click-pin-test.mjs +94 -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-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-stroke-transition-test.mjs +132 -0
- package/scripts/topo-edge-tooltip-test.mjs +70 -0
- package/scripts/topo-endpoint-ring-test.mjs +93 -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-group-box-pinned-state-test.mjs +95 -0
- package/scripts/topo-group-count-test.mjs +68 -0
- package/scripts/topo-group-hover-test.mjs +82 -0
- package/scripts/topo-group-label-a11y-test.mjs +113 -0
- package/scripts/topo-group-label-hover-test.mjs +119 -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-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-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-hub-a11y-test.mjs +112 -0
- package/scripts/topo-hub-busyness-test.mjs +100 -0
- package/scripts/topo-hub-click-fit-test.mjs +137 -0
- package/scripts/topo-hub-hover-ring-test.mjs +82 -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-label-lift-test.mjs +119 -0
- package/scripts/topo-label-scale-test.mjs +78 -0
- package/scripts/topo-lastseen-tooltip-test.mjs +59 -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-test.mjs +131 -0
- package/scripts/topo-legend-count-test.mjs +88 -0
- package/scripts/topo-legend-hover-test.mjs +113 -0
- package/scripts/topo-legend-panel-header-test.mjs +83 -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-tint-test.mjs +95 -0
- package/scripts/topo-legend-row-title-test.mjs +102 -0
- package/scripts/topo-minimap-a11y-test.mjs +101 -0
- package/scripts/topo-minimap-test.mjs +68 -0
- package/scripts/topo-mobile-chips-test.mjs +103 -0
- package/scripts/topo-node-a11y-test.mjs +107 -0
- package/scripts/topo-node-hover-lift-test.mjs +85 -0
- package/scripts/topo-node-stroke-transition-test.mjs +103 -0
- package/scripts/topo-node-title-peers-test.mjs +107 -0
- package/scripts/topo-node-title-test.mjs +101 -0
- package/scripts/topo-nodesize-crossfade-test.mjs +141 -0
- package/scripts/topo-offline-dim-test.mjs +70 -0
- package/scripts/topo-online-chip-nav-test.mjs +143 -0
- package/scripts/topo-orbit-busyness-test.mjs +96 -0
- package/scripts/topo-overlap-test.mjs +32 -5
- package/scripts/topo-pan-cursor-test.mjs +62 -0
- package/scripts/topo-panel-elevation-test.mjs +76 -0
- package/scripts/topo-panel-hover-elevation-test.mjs +118 -0
- package/scripts/topo-particle-stagger-test.mjs +82 -0
- package/scripts/topo-pin-intersection-empty-test.mjs +129 -0
- package/scripts/topo-pin-intersection-test.mjs +121 -0
- package/scripts/topo-pin-persistence-test.mjs +105 -0
- package/scripts/topo-popover-meta-test.mjs +78 -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-tooltip-test.mjs +98 -0
- package/scripts/topo-pressure-seg-transition-test.mjs +107 -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-hot-header-test.mjs +132 -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-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-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-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-spoke-busyness-test.mjs +110 -0
- package/scripts/topo-status-chip-hover-test.mjs +101 -0
- package/scripts/topo-status-chip-tooltip-test.mjs +95 -0
- package/scripts/topo-svg-focus-test.mjs +112 -0
- package/scripts/topo-sweep-busyness-test.mjs +94 -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-tz-ghost-test.mjs +69 -0
- package/scripts/topo-vendor-chip-hover-test.mjs +111 -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-wheel-zoom-test.mjs +79 -0
- package/scripts/topo-working-chip-pin-test.mjs +148 -0
- package/scripts/topo-working-halo-breath-test.mjs +86 -0
- package/scripts/topo-zoom-keys-test.mjs +89 -0
- package/.next/static/chunks/0-7iowzu4.798.js +0 -1
- package/.next/static/chunks/0-elsllb_uimz.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/0ang8z1ph~8nf.js +0 -1
- package/.next/static/chunks/0elalb9n_.~di.js +0 -1
- package/.next/static/chunks/0fqy_0wj_1xa7.js +0 -7
- package/.next/static/chunks/0j_q__o8p6g83.js +0 -1
- package/.next/static/chunks/0jl6_w50zh4l5.js +0 -1
- package/.next/static/chunks/0n_cardir-ztl.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/{x222cMNV4lquOMK8fPD3G → Bfq_NKAKfgisiPZVimIBB}/_buildManifest.js +0 -0
- /package/.next/static/{x222cMNV4lquOMK8fPD3G → Bfq_NKAKfgisiPZVimIBB}/_clientMiddlewareManifest.js +0 -0
- /package/.next/static/{x222cMNV4lquOMK8fPD3G → Bfq_NKAKfgisiPZVimIBB}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/* Round 11 verification: clicking a node opens the ChatPopover AND draws a
|
|
2
|
+
* persistent chat-focus ring on that node (strokeWidth=2.5, status colour).
|
|
3
|
+
* Closing the popover removes the ring. The ring's strokeWidth stays clear
|
|
4
|
+
* of the overlap-test selectors (1.5 / 3). */
|
|
5
|
+
import { chromium } from 'playwright';
|
|
6
|
+
import { readFileSync } from 'node:fs';
|
|
7
|
+
|
|
8
|
+
const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
|
|
9
|
+
const browser = await chromium.launch({ headless: true });
|
|
10
|
+
|
|
11
|
+
const ctx = await browser.newContext({ viewport: { width: 1280, height: 900 } });
|
|
12
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
13
|
+
await ctx.addInitScript(() => {
|
|
14
|
+
try {
|
|
15
|
+
localStorage.setItem('anet-theme', 'cyber');
|
|
16
|
+
localStorage.removeItem('anet-brand');
|
|
17
|
+
localStorage.removeItem('anet-topo-view');
|
|
18
|
+
localStorage.setItem('anet-topo-layout', 'grid');
|
|
19
|
+
localStorage.setItem('anet-topo-nodescale', '1'); // L so radius=26
|
|
20
|
+
sessionStorage.setItem('anet_v3_auth', '1');
|
|
21
|
+
} catch {}
|
|
22
|
+
});
|
|
23
|
+
await ctx.route('**/api/hub/status*', async (route) => {
|
|
24
|
+
const r = await route.fetch();
|
|
25
|
+
const b = await r.json();
|
|
26
|
+
const nid = (b.sessions || [])[0]?.network_id || 'default';
|
|
27
|
+
const sessions = ['A站马', 'B站马', 'C站马'].map(a => ({
|
|
28
|
+
alias: a, status: 'idle', network_id: nid,
|
|
29
|
+
project_dir: null,
|
|
30
|
+
created_at: '2026-05-15T00:00:00Z', updated_at: '2026-05-15T00:00:00Z',
|
|
31
|
+
last_seen_at: new Date().toISOString(),
|
|
32
|
+
}));
|
|
33
|
+
await route.fulfill({ response: r, json: { ...b, sessions } });
|
|
34
|
+
});
|
|
35
|
+
await ctx.route('**/api/hub/tasks*', (route) => route.fulfill({ json: { tasks: [] } }));
|
|
36
|
+
const page = await ctx.newPage();
|
|
37
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
|
|
38
|
+
await page.waitForFunction(() => {
|
|
39
|
+
const svg = document.querySelector('svg[viewBox="0 0 1000 680"]');
|
|
40
|
+
return !!svg && svg.querySelectorAll('g[data-node]').length >= 3;
|
|
41
|
+
}, { timeout: 30000 }).catch(() => {});
|
|
42
|
+
await page.waitForTimeout(400);
|
|
43
|
+
|
|
44
|
+
// Pre-click: NO chat-focus ring on any node (strokeWidth=2.5, no group-hover class)
|
|
45
|
+
const ringsBefore = await page.$$eval('svg[viewBox="0 0 1000 680"] g[data-node] circle[stroke-width="2.5"]', els => els.length);
|
|
46
|
+
|
|
47
|
+
// Click A站马 → opens chat popover
|
|
48
|
+
await page.locator('g[data-node="A站马"]').click();
|
|
49
|
+
await page.waitForTimeout(300);
|
|
50
|
+
|
|
51
|
+
const ringsAfter = await page.$$eval('svg[viewBox="0 0 1000 680"] g[data-node] circle[stroke-width="2.5"]', els => els.length);
|
|
52
|
+
const ringOnTarget = await page.$eval(
|
|
53
|
+
'g[data-node="A站马"] circle[stroke-width="2.5"]',
|
|
54
|
+
el => ({ r: +el.getAttribute('r'), opacity: +el.getAttribute('opacity') })
|
|
55
|
+
).catch(() => null);
|
|
56
|
+
|
|
57
|
+
// Confirm popover is open
|
|
58
|
+
const popover = await page.locator('[role="dialog"], [data-chat-popover]').count();
|
|
59
|
+
|
|
60
|
+
// Ring should be ONLY on the clicked node, not on the others
|
|
61
|
+
const ringOnOther = await page.$$eval('g[data-node="B站马"] circle[stroke-width="2.5"], g[data-node="C站马"] circle[stroke-width="2.5"]', els => els.length);
|
|
62
|
+
|
|
63
|
+
const results = {
|
|
64
|
+
noRingBefore: ringsBefore === 0,
|
|
65
|
+
oneRingAfter: ringsAfter === 1,
|
|
66
|
+
ringOnTargetNode: !!ringOnTarget && ringOnTarget.r === 40, // radius=26 + 14
|
|
67
|
+
ringNotOnOthers: ringOnOther === 0,
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
// Re-run the overlap selector to confirm the chat-focus ring isn't mis-counted as a status ring
|
|
71
|
+
const statusRings = await page.$$eval('svg[viewBox="0 0 1000 680"] g[data-node] circle[stroke-width="3"], svg[viewBox="0 0 1000 680"] g[data-node] circle[stroke-width="1.5"]', els => els.length);
|
|
72
|
+
results.statusRingCountUnchanged = statusRings === 3; // exactly one per online node
|
|
73
|
+
|
|
74
|
+
await browser.close();
|
|
75
|
+
const ok = Object.values(results).every(Boolean);
|
|
76
|
+
console.log(`${ok ? '✅' : '❌'} chat-focus ring:`, JSON.stringify(results));
|
|
77
|
+
process.exit(ok ? 0 : 1);
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/* Round 120 verification: chat-target ring breathes when chat is
|
|
2
|
+
* open. R51 added the static ring at radius+14; R120 adds a SMIL
|
|
3
|
+
* opacity pulse (±0.1, 3s) so the active chat session reads as
|
|
4
|
+
* "live" without being intrusive. Gated by reducedMotion.
|
|
5
|
+
*
|
|
6
|
+
* Drive chatAlias by clicking a node to open the popover. Verify:
|
|
7
|
+
* - chat-target ring renders with data-chat-target-breath="on"
|
|
8
|
+
* - the ring has an <animate> child with dur="3s"
|
|
9
|
+
* - reducedMotion suppresses the breath
|
|
10
|
+
*/
|
|
11
|
+
import { chromium } from 'playwright';
|
|
12
|
+
import { readFileSync } from 'node:fs';
|
|
13
|
+
|
|
14
|
+
const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
|
|
15
|
+
const browser = await chromium.launch({ headless: true });
|
|
16
|
+
const fresh = new Date(Date.now() - 60 * 1000).toISOString();
|
|
17
|
+
|
|
18
|
+
const probe = async (reducedMotion) => {
|
|
19
|
+
const ctx = await browser.newContext({
|
|
20
|
+
viewport: { width: 1400, height: 1500 },
|
|
21
|
+
reducedMotion: reducedMotion ? 'reduce' : 'no-preference',
|
|
22
|
+
});
|
|
23
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
24
|
+
await ctx.addInitScript(() => {
|
|
25
|
+
try {
|
|
26
|
+
localStorage.setItem('anet-theme', 'cyber');
|
|
27
|
+
localStorage.setItem('anet-topo-layout', 'ring');
|
|
28
|
+
sessionStorage.setItem('anet_v3_auth', '1');
|
|
29
|
+
} catch {}
|
|
30
|
+
});
|
|
31
|
+
await ctx.route('**/api/hub/status*', async (route) => {
|
|
32
|
+
const r = await route.fetch();
|
|
33
|
+
const b = await r.json();
|
|
34
|
+
const nid = (b.sessions || [])[0]?.network_id || 'default';
|
|
35
|
+
const mk = (alias) => ({
|
|
36
|
+
alias, status: 'idle', model: 'claude-opus-4', 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: [mk('alpha'), mk('beta')] } });
|
|
41
|
+
});
|
|
42
|
+
await ctx.route('**/api/hub/messages*', (route) => route.fulfill({ json: { messages: [] } }));
|
|
43
|
+
await ctx.route('**/api/hub/tasks*', (route) => route.fulfill({ json: { tasks: [] } }));
|
|
44
|
+
const page = await ctx.newPage();
|
|
45
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
|
|
46
|
+
await page.waitForFunction(() => document.querySelectorAll('g[data-node]').length === 2, { timeout: 30000 });
|
|
47
|
+
await page.waitForTimeout(400);
|
|
48
|
+
|
|
49
|
+
// Open chat by clicking the alpha node.
|
|
50
|
+
await page.locator('g[data-node="alpha"]').click();
|
|
51
|
+
await page.waitForTimeout(500);
|
|
52
|
+
|
|
53
|
+
const data = await page.evaluate(() => {
|
|
54
|
+
const ring = document.querySelector('[data-chat-target-ring]');
|
|
55
|
+
const anim = ring?.querySelector('animate');
|
|
56
|
+
return {
|
|
57
|
+
ringPresent: !!ring,
|
|
58
|
+
breathAttr: ring?.getAttribute('data-chat-target-breath') || '',
|
|
59
|
+
hasAnimate: !!anim,
|
|
60
|
+
dur: anim?.getAttribute('dur') || null,
|
|
61
|
+
};
|
|
62
|
+
});
|
|
63
|
+
await ctx.close();
|
|
64
|
+
return data;
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
const normal = await probe(false);
|
|
68
|
+
const reduced = await probe(true);
|
|
69
|
+
await browser.close();
|
|
70
|
+
|
|
71
|
+
const results = {
|
|
72
|
+
normal_ringPresent: normal.ringPresent === true,
|
|
73
|
+
normal_breathOn: normal.breathAttr === 'on',
|
|
74
|
+
normal_hasAnimate: normal.hasAnimate === true,
|
|
75
|
+
normal_dur3s: normal.dur === '3s',
|
|
76
|
+
reduced_ringPresent: reduced.ringPresent === true,
|
|
77
|
+
reduced_breathOff: reduced.breathAttr === 'off',
|
|
78
|
+
reduced_noAnimate: reduced.hasAnimate === false,
|
|
79
|
+
};
|
|
80
|
+
const ok = Object.values(results).every(Boolean);
|
|
81
|
+
console.log(`${ok ? '✅' : '❌'} chat-target breath:`, JSON.stringify(results),
|
|
82
|
+
`\n normal=`, normal,
|
|
83
|
+
`\n reduced=`, reduced);
|
|
84
|
+
process.exit(ok ? 0 : 1);
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/* Round 155 verification: chip-row interactives gain
|
|
2
|
+
* `.anet-topo-chip-focus` for keyboard focus-visible outline,
|
|
3
|
+
* matching R154's chrome-button treatment.
|
|
4
|
+
*
|
|
5
|
+
* Why `outline` not `box-shadow`: the R88 vendor letter / R139
|
|
6
|
+
* working chip / R140 online chip already use inline boxShadow
|
|
7
|
+
* for the pin-mirror inset. Adding focus-visible:ring (which
|
|
8
|
+
* Tailwind paints via box-shadow) would conflict — inline style
|
|
9
|
+
* wins specificity. `outline: 2px solid currentColor` is on a
|
|
10
|
+
* separate CSS property, no conflict; `currentColor` inherits
|
|
11
|
+
* the chip's own accent (green / cyan / per-vendor / etc.).
|
|
12
|
+
*
|
|
13
|
+
* Test: every chip-row interactive surface carries the class.
|
|
14
|
+
*/
|
|
15
|
+
import { chromium } from 'playwright';
|
|
16
|
+
import { readFileSync } from 'node:fs';
|
|
17
|
+
|
|
18
|
+
const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
|
|
19
|
+
const browser = await chromium.launch({ headless: true });
|
|
20
|
+
|
|
21
|
+
const ctx = await browser.newContext({ viewport: { width: 1400, height: 1500 } });
|
|
22
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
23
|
+
await ctx.addInitScript(() => {
|
|
24
|
+
try { localStorage.setItem('anet-theme', 'cyber'); sessionStorage.setItem('anet_v3_auth', '1'); } catch {}
|
|
25
|
+
});
|
|
26
|
+
const fresh = new Date(Date.now() - 60 * 1000).toISOString();
|
|
27
|
+
await ctx.route('**/api/hub/status*', async (route) => {
|
|
28
|
+
const r = await route.fetch();
|
|
29
|
+
const b = await r.json();
|
|
30
|
+
const nid = (b.sessions || [])[0]?.network_id || 'default';
|
|
31
|
+
const mk = (alias, status, model) => ({
|
|
32
|
+
alias, status, model, runtime: 'cli-claude-code',
|
|
33
|
+
network_id: nid, project_dir: null,
|
|
34
|
+
created_at: fresh, updated_at: fresh, last_seen_at: fresh,
|
|
35
|
+
});
|
|
36
|
+
await route.fulfill({ response: r, json: { ...b, sessions: [
|
|
37
|
+
mk('alpha', 'working', 'claude-opus-4'),
|
|
38
|
+
mk('beta', 'idle', 'gpt-4o'),
|
|
39
|
+
] } });
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
const now = Date.now();
|
|
43
|
+
// 1 message to populate flowLinks → active-links chip is interactive
|
|
44
|
+
await ctx.route('**/api/hub/messages*', (route) => route.fulfill({ json: { messages: [
|
|
45
|
+
{ id: 'm0', from_alias: 'alpha', to_alias: 'beta', content: 'hi',
|
|
46
|
+
network_id: 'default', created_at: new Date(now - 10000).toISOString() },
|
|
47
|
+
] } }));
|
|
48
|
+
await ctx.route('**/api/hub/tasks*', (route) => route.fulfill({ json: { tasks: [] } }));
|
|
49
|
+
|
|
50
|
+
const page = await ctx.newPage();
|
|
51
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
|
|
52
|
+
await page.waitForFunction(() => document.querySelectorAll('g[data-node]').length === 2, { timeout: 30000 });
|
|
53
|
+
await page.waitForTimeout(400);
|
|
54
|
+
|
|
55
|
+
// Pin status + vendor to surface filter pills + intersection chip
|
|
56
|
+
await page.evaluate(() => {
|
|
57
|
+
window.dispatchEvent(new CustomEvent('anet:topo-pin', { detail: { kind: 'status', value: 'working' } }));
|
|
58
|
+
window.dispatchEvent(new CustomEvent('anet:topo-pin', { detail: { kind: 'vendor', value: 'A' } }));
|
|
59
|
+
});
|
|
60
|
+
await page.waitForTimeout(300);
|
|
61
|
+
|
|
62
|
+
const inspect = () => page.evaluate(() => {
|
|
63
|
+
const has = (sel) => {
|
|
64
|
+
const el = document.querySelector(sel);
|
|
65
|
+
return el && (el.className || '').includes('anet-topo-chip-focus');
|
|
66
|
+
};
|
|
67
|
+
return {
|
|
68
|
+
pressureSeg_working: has('[data-pressure-seg="working"]'),
|
|
69
|
+
workingChip: has('[data-working-chip]'),
|
|
70
|
+
onlineChip: has('[data-online-chip]'),
|
|
71
|
+
vendorLetter_A: has('[data-vendor-letter="A"]'),
|
|
72
|
+
activeLinks: has('[data-active-links-chip]'),
|
|
73
|
+
filterPill_status: has('[data-active-filter="status"]'),
|
|
74
|
+
filterPill_vendor: has('[data-active-filter="vendor"]'),
|
|
75
|
+
intersectionChip: has('[data-pin-intersection]'),
|
|
76
|
+
};
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
const result = await inspect();
|
|
80
|
+
await browser.close();
|
|
81
|
+
|
|
82
|
+
const results = {
|
|
83
|
+
pressureSeg_focusClass: result.pressureSeg_working === true,
|
|
84
|
+
workingChip_focusClass: result.workingChip === true,
|
|
85
|
+
onlineChip_focusClass: result.onlineChip === true,
|
|
86
|
+
vendorLetter_focusClass: result.vendorLetter_A === true,
|
|
87
|
+
activeLinks_focusClass: result.activeLinks === true,
|
|
88
|
+
filterPillStatus_focusClass: result.filterPill_status === true,
|
|
89
|
+
filterPillVendor_focusClass: result.filterPill_vendor === true,
|
|
90
|
+
intersectionChip_focusClass: result.intersectionChip === true,
|
|
91
|
+
};
|
|
92
|
+
const ok = Object.values(results).every(Boolean);
|
|
93
|
+
console.log(`${ok ? '✅' : '❌'} chip focus class:`, JSON.stringify(results),
|
|
94
|
+
`\n raw=`, result);
|
|
95
|
+
process.exit(ok ? 0 : 1);
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/* Round 82 verification: chip-row "N working" + "N online" chips mirror
|
|
2
|
+
* the pin state already shown by the R60 pressure-bar segments. When
|
|
3
|
+
* pinnedStatus === 'working', the working chip lights up via inset
|
|
4
|
+
* boxShadow + data-pin-mirror="true"; idle pin lights the online chip.
|
|
5
|
+
* Closes the visual inconsistency where pressure-bar + legend showed
|
|
6
|
+
* the pin but the sibling count chips stayed flat.
|
|
7
|
+
*
|
|
8
|
+
* Drive the pin via Cmd+K palette (R69 action) to verify the chip
|
|
9
|
+
* reflects a pin set from a non-chip surface — exercises the full
|
|
10
|
+
* coupling, not just a chip clicking itself.
|
|
11
|
+
*/
|
|
12
|
+
import { chromium } from 'playwright';
|
|
13
|
+
import { readFileSync } from 'node:fs';
|
|
14
|
+
|
|
15
|
+
const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
|
|
16
|
+
const browser = await chromium.launch({ headless: true });
|
|
17
|
+
|
|
18
|
+
const ctx = await browser.newContext({ viewport: { width: 1400, height: 1200 } });
|
|
19
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
20
|
+
await ctx.addInitScript(() => {
|
|
21
|
+
try {
|
|
22
|
+
localStorage.setItem('anet-theme', 'cyber');
|
|
23
|
+
sessionStorage.setItem('anet_v3_auth', '1');
|
|
24
|
+
sessionStorage.removeItem('anet-topo-pinned-status');
|
|
25
|
+
sessionStorage.removeItem('anet-topo-pinned-group');
|
|
26
|
+
} catch {}
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
const fresh = new Date(Date.now() - 60 * 1000).toISOString();
|
|
30
|
+
await ctx.route('**/api/hub/status*', async (route) => {
|
|
31
|
+
const r = await route.fetch();
|
|
32
|
+
const b = await r.json();
|
|
33
|
+
const nid = (b.sessions || [])[0]?.network_id || 'default';
|
|
34
|
+
const sessions = [
|
|
35
|
+
{ alias: 'alpha', status: 'working', model: 'claude-opus-4', runtime: 'cli-claude-code',
|
|
36
|
+
network_id: nid, project_dir: null, created_at: fresh, updated_at: fresh, last_seen_at: fresh },
|
|
37
|
+
{ alias: 'beta', status: 'idle', model: 'gpt-5', runtime: 'codex-cli',
|
|
38
|
+
network_id: nid, project_dir: null, created_at: fresh, updated_at: fresh, last_seen_at: fresh },
|
|
39
|
+
];
|
|
40
|
+
await route.fulfill({ response: r, json: { ...b, sessions } });
|
|
41
|
+
});
|
|
42
|
+
await ctx.route('**/api/hub/messages*', (route) => route.fulfill({ json: { messages: [] } }));
|
|
43
|
+
await ctx.route('**/api/hub/tasks*', (route) => route.fulfill({ json: { tasks: [] } }));
|
|
44
|
+
const page = await ctx.newPage();
|
|
45
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
|
|
46
|
+
await page.waitForFunction(() => document.querySelectorAll('g[data-node]').length === 2, { timeout: 30000 });
|
|
47
|
+
await page.waitForTimeout(400);
|
|
48
|
+
|
|
49
|
+
const snap = () => page.evaluate(() => {
|
|
50
|
+
const w = document.querySelector('[data-working-chip]');
|
|
51
|
+
const o = document.querySelector('[data-online-chip]');
|
|
52
|
+
return {
|
|
53
|
+
working: {
|
|
54
|
+
mirror: w?.getAttribute('data-pin-mirror'),
|
|
55
|
+
shadow: w ? (w.getAttribute('style') || '').includes('inset') : false,
|
|
56
|
+
title: w?.getAttribute('title') || '',
|
|
57
|
+
},
|
|
58
|
+
online: {
|
|
59
|
+
mirror: o?.getAttribute('data-pin-mirror'),
|
|
60
|
+
shadow: o ? (o.getAttribute('style') || '').includes('inset') : false,
|
|
61
|
+
title: o?.getAttribute('title') || '',
|
|
62
|
+
},
|
|
63
|
+
};
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
const before = await snap();
|
|
67
|
+
|
|
68
|
+
// Dispatch the R69 CustomEvent directly — same coupling the palette
|
|
69
|
+
// uses, deterministic without fuzzy-match ambiguity. The R69 listener
|
|
70
|
+
// in TopoGraph reads `detail.kind === 'status'` + `detail.value`.
|
|
71
|
+
const pin = async (value) => {
|
|
72
|
+
await page.evaluate((v) => {
|
|
73
|
+
try { sessionStorage.setItem('anet-topo-pinned-status', v); } catch {}
|
|
74
|
+
window.dispatchEvent(new CustomEvent('anet:topo-pin', { detail: { kind: 'status', value: v } }));
|
|
75
|
+
}, value);
|
|
76
|
+
await page.waitForTimeout(200);
|
|
77
|
+
};
|
|
78
|
+
const clear = async () => {
|
|
79
|
+
await page.keyboard.press('Escape');
|
|
80
|
+
await page.waitForTimeout(250);
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
await pin('working');
|
|
84
|
+
const onWorking = await snap();
|
|
85
|
+
await clear();
|
|
86
|
+
const afterWorking = await snap();
|
|
87
|
+
|
|
88
|
+
await pin('idle');
|
|
89
|
+
const onIdle = await snap();
|
|
90
|
+
await clear();
|
|
91
|
+
const afterIdle = await snap();
|
|
92
|
+
|
|
93
|
+
await browser.close();
|
|
94
|
+
|
|
95
|
+
const results = {
|
|
96
|
+
before_workingFlat: before.working.mirror === 'false' && !before.working.shadow,
|
|
97
|
+
before_onlineFlat: before.online.mirror === 'false' && !before.online.shadow,
|
|
98
|
+
workingPin_workingLit: onWorking.working.mirror === 'true' && onWorking.working.shadow,
|
|
99
|
+
workingPin_onlineFlat: onWorking.online.mirror === 'false' && !onWorking.online.shadow,
|
|
100
|
+
workingPin_titleHint: /Pinned/i.test(onWorking.working.title),
|
|
101
|
+
esc_workingFlat: afterWorking.working.mirror === 'false' && !afterWorking.working.shadow,
|
|
102
|
+
esc_onlineUntouched: afterWorking.online.mirror === 'false' && !afterWorking.online.shadow,
|
|
103
|
+
idlePin_onlineLit: onIdle.online.mirror === 'true' && onIdle.online.shadow,
|
|
104
|
+
idlePin_workingFlat: onIdle.working.mirror === 'false' && !onIdle.working.shadow,
|
|
105
|
+
idlePin_titleHint: /Pinned/i.test(onIdle.online.title),
|
|
106
|
+
esc_onlineFlat: afterIdle.online.mirror === 'false' && !afterIdle.online.shadow,
|
|
107
|
+
};
|
|
108
|
+
const ok = Object.values(results).every(Boolean);
|
|
109
|
+
console.log(`${ok ? '✅' : '❌'} chip pin-mirror:`, JSON.stringify(results),
|
|
110
|
+
`\n before=`, before,
|
|
111
|
+
`\n onWorking=`, onWorking,
|
|
112
|
+
`\n onIdle=`, onIdle);
|
|
113
|
+
process.exit(ok ? 0 : 1);
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/* Round 154 verification: TopoGraph chrome buttons gain stable
|
|
2
|
+
* data-* hooks for tests + focus-visible ring matching the
|
|
3
|
+
* dashboard's cyan accent (browser default focus outline often
|
|
4
|
+
* vanishes on the dark canvas).
|
|
5
|
+
*
|
|
6
|
+
* Chrome inventory (bottom-right of canvas):
|
|
7
|
+
* data-topo-chrome (wrapper div)
|
|
8
|
+
* data-topo-chrome-nodesize=S|M|L (segmented control, R113)
|
|
9
|
+
* data-topo-chrome-nodesize-active="true|false"
|
|
10
|
+
* data-topo-chrome-zoom-out (R104)
|
|
11
|
+
* data-topo-chrome-zoom-level (readout, also R104)
|
|
12
|
+
* data-topo-chrome-zoom-in
|
|
13
|
+
* data-topo-chrome-reset
|
|
14
|
+
* data-topo-chrome-fullscreen
|
|
15
|
+
* data-topo-chrome-fullscreen-active="true|false"
|
|
16
|
+
*
|
|
17
|
+
* Each button gains focus-visible:ring-1 ring-cyan-400/60. Tabs
|
|
18
|
+
* land somewhere visible.
|
|
19
|
+
*
|
|
20
|
+
* Test: every chrome button surfaces its data attribute, plus the
|
|
21
|
+
* three S/M/L buttons report active correctly when one is picked.
|
|
22
|
+
*/
|
|
23
|
+
import { chromium } from 'playwright';
|
|
24
|
+
import { readFileSync } from 'node:fs';
|
|
25
|
+
|
|
26
|
+
const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
|
|
27
|
+
const browser = await chromium.launch({ headless: true });
|
|
28
|
+
|
|
29
|
+
const ctx = await browser.newContext({ viewport: { width: 1400, height: 1500 } });
|
|
30
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
31
|
+
await ctx.addInitScript(() => {
|
|
32
|
+
try { localStorage.setItem('anet-theme', 'cyber'); sessionStorage.setItem('anet_v3_auth', '1'); } catch {}
|
|
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: [mk('alpha'), mk('beta')] } });
|
|
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 === 2, { timeout: 30000 });
|
|
52
|
+
await page.waitForSelector('[data-topo-chrome]', { timeout: 10000 });
|
|
53
|
+
await page.waitForTimeout(300);
|
|
54
|
+
|
|
55
|
+
const inspect = () => page.evaluate(() => {
|
|
56
|
+
const sel = (s) => document.querySelector(s);
|
|
57
|
+
const all = (s) => [...document.querySelectorAll(s)];
|
|
58
|
+
return {
|
|
59
|
+
wrapper: !!sel('[data-topo-chrome]'),
|
|
60
|
+
nodesizeS: sel('[data-topo-chrome-nodesize="S"]')?.getAttribute('data-topo-chrome-nodesize-active'),
|
|
61
|
+
nodesizeM: sel('[data-topo-chrome-nodesize="M"]')?.getAttribute('data-topo-chrome-nodesize-active'),
|
|
62
|
+
nodesizeL: sel('[data-topo-chrome-nodesize="L"]')?.getAttribute('data-topo-chrome-nodesize-active'),
|
|
63
|
+
zoomOut: !!sel('[data-topo-chrome-zoom-out]'),
|
|
64
|
+
zoomLevel: sel('[data-topo-chrome-zoom-level]')?.textContent?.trim(),
|
|
65
|
+
zoomIn: !!sel('[data-topo-chrome-zoom-in]'),
|
|
66
|
+
reset: !!sel('[data-topo-chrome-reset]'),
|
|
67
|
+
fullscreen: !!sel('[data-topo-chrome-fullscreen]'),
|
|
68
|
+
fullscreenActive: sel('[data-topo-chrome-fullscreen]')?.getAttribute('data-topo-chrome-fullscreen-active'),
|
|
69
|
+
// focus-visible ring is a CSS pseudo-class; just verify the
|
|
70
|
+
// className carries the focus-visible:ring tokens.
|
|
71
|
+
chromeButtonsHaveFocusRing: all('[data-topo-chrome] button').every(b =>
|
|
72
|
+
(b.className || '').includes('focus-visible:ring')),
|
|
73
|
+
};
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
const before = await inspect();
|
|
77
|
+
|
|
78
|
+
// Click L → it becomes active, M becomes inactive (default)
|
|
79
|
+
await page.locator('[data-topo-chrome-nodesize="L"]').click();
|
|
80
|
+
await page.waitForTimeout(150);
|
|
81
|
+
const afterL = await inspect();
|
|
82
|
+
|
|
83
|
+
await browser.close();
|
|
84
|
+
|
|
85
|
+
const results = {
|
|
86
|
+
wrapper_present: before.wrapper === true,
|
|
87
|
+
nodesizeS_present: before.nodesizeS === 'false',
|
|
88
|
+
nodesizeM_activeDefault: before.nodesizeM === 'true', // default scale 0.84 → M
|
|
89
|
+
nodesizeL_present: before.nodesizeL === 'false',
|
|
90
|
+
zoomOut_present: before.zoomOut === true,
|
|
91
|
+
zoomLevel_100pct: before.zoomLevel === '100%',
|
|
92
|
+
zoomIn_present: before.zoomIn === true,
|
|
93
|
+
reset_present: before.reset === true,
|
|
94
|
+
fullscreen_present: before.fullscreen === true,
|
|
95
|
+
fullscreenActive_false: before.fullscreenActive === 'false',
|
|
96
|
+
focusRing_onAllButtons: before.chromeButtonsHaveFocusRing === true,
|
|
97
|
+
|
|
98
|
+
// After clicking L: active flips to L
|
|
99
|
+
afterL_LActive: afterL.nodesizeL === 'true',
|
|
100
|
+
afterL_MInactive: afterL.nodesizeM === 'false',
|
|
101
|
+
afterL_SInactive: afterL.nodesizeS === 'false',
|
|
102
|
+
};
|
|
103
|
+
const ok = Object.values(results).every(Boolean);
|
|
104
|
+
console.log(`${ok ? '✅' : '❌'} chrome a11y:`, JSON.stringify(results),
|
|
105
|
+
`\n before=`, before,
|
|
106
|
+
`\n afterL=`, afterL);
|
|
107
|
+
process.exit(ok ? 0 : 1);
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/* Round 14 verification: clicking a node spawns a one-shot ripple circle
|
|
2
|
+
* (strokeWidth=2, status-coloured, ~500ms) that's gone by t=800ms. */
|
|
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
|
+
|
|
9
|
+
const ctx = await browser.newContext({ viewport: { width: 1280, height: 900 } });
|
|
10
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
11
|
+
await ctx.addInitScript(() => {
|
|
12
|
+
try {
|
|
13
|
+
localStorage.setItem('anet-theme', 'cyber');
|
|
14
|
+
localStorage.removeItem('anet-brand');
|
|
15
|
+
localStorage.removeItem('anet-topo-view');
|
|
16
|
+
localStorage.setItem('anet-topo-layout', 'grid');
|
|
17
|
+
localStorage.setItem('anet-topo-nodescale', '1');
|
|
18
|
+
sessionStorage.setItem('anet_v3_auth', '1');
|
|
19
|
+
} catch {}
|
|
20
|
+
});
|
|
21
|
+
await ctx.route('**/api/hub/status*', async (route) => {
|
|
22
|
+
const r = await route.fetch();
|
|
23
|
+
const b = await r.json();
|
|
24
|
+
const nid = (b.sessions || [])[0]?.network_id || 'default';
|
|
25
|
+
const sessions = ['ripA', 'ripB'].map(a => ({
|
|
26
|
+
alias: a, status: 'idle', network_id: nid, project_dir: null,
|
|
27
|
+
created_at: '2026-05-15T00:00:00Z', updated_at: '2026-05-15T00:00:00Z',
|
|
28
|
+
last_seen_at: new Date().toISOString(),
|
|
29
|
+
}));
|
|
30
|
+
await route.fulfill({ response: r, json: { ...b, sessions } });
|
|
31
|
+
});
|
|
32
|
+
await ctx.route('**/api/hub/tasks*', (route) => route.fulfill({ json: { tasks: [] } }));
|
|
33
|
+
const page = await ctx.newPage();
|
|
34
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
|
|
35
|
+
await page.waitForFunction(() => {
|
|
36
|
+
const svg = document.querySelector('svg[viewBox="0 0 1000 680"]');
|
|
37
|
+
return !!svg && svg.querySelectorAll('g[data-node]').length >= 2;
|
|
38
|
+
}, { timeout: 30000 }).catch(() => {});
|
|
39
|
+
await page.waitForTimeout(400);
|
|
40
|
+
|
|
41
|
+
// Ripple circle = direct child of the zoom/pan <g>, strokeWidth=2, with a
|
|
42
|
+
// <animate> child whose attributeName="r" (distinguishes it from the
|
|
43
|
+
// hover ring, which has strokeWidth=2 but no <animate> children).
|
|
44
|
+
const ripplePresent = async () => page.evaluate(() => {
|
|
45
|
+
const svg = document.querySelector('svg[viewBox="0 0 1000 680"]');
|
|
46
|
+
for (const c of svg.querySelectorAll('circle[stroke-width="2"]')) {
|
|
47
|
+
const anims = c.querySelectorAll('animate');
|
|
48
|
+
if (anims.length && [...anims].some(a => a.getAttribute('attributeName') === 'r')) return true;
|
|
49
|
+
}
|
|
50
|
+
return false;
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
const before = await ripplePresent();
|
|
54
|
+
await page.locator('g[data-node="ripA"]').click();
|
|
55
|
+
// Sample at ~150ms (mid-animation) — ripple should be present.
|
|
56
|
+
await page.waitForTimeout(150);
|
|
57
|
+
const during = await ripplePresent();
|
|
58
|
+
// After 800ms total — well past the 600ms clear timer.
|
|
59
|
+
await page.waitForTimeout(700);
|
|
60
|
+
const after = await ripplePresent();
|
|
61
|
+
|
|
62
|
+
await browser.close();
|
|
63
|
+
const results = { noRippleBefore: before === false, rippleDuring: during === true, rippleClearedAfter: after === false };
|
|
64
|
+
const ok = Object.values(results).every(Boolean);
|
|
65
|
+
console.log(`${ok ? '✅' : '❌'} click ripple:`, JSON.stringify(results));
|
|
66
|
+
process.exit(ok ? 0 : 1);
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/* Round 117 verification: Cmd+K "Clear topology filters" also
|
|
2
|
+
* releases pinnedEdgeKey (the 4th pin dim R116 added). Plus a new
|
|
3
|
+
* granular "Clear topology edge pin" command. Mirrors R90's
|
|
4
|
+
* vendor-clear treatment.
|
|
5
|
+
*
|
|
6
|
+
* Drive via direct CustomEvent dispatch (deterministic — same path
|
|
7
|
+
* R82/R90/R108 tests use). Verify:
|
|
8
|
+
* - Pin status + edge → click "clear" → both release
|
|
9
|
+
* - Pin status + edge → click "clear-edge" → only edge releases
|
|
10
|
+
*/
|
|
11
|
+
import { chromium } from 'playwright';
|
|
12
|
+
import { readFileSync } from 'node:fs';
|
|
13
|
+
|
|
14
|
+
const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
|
|
15
|
+
const browser = await chromium.launch({ headless: true });
|
|
16
|
+
|
|
17
|
+
const ctx = await browser.newContext({ viewport: { width: 1400, height: 1500 } });
|
|
18
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
19
|
+
await ctx.addInitScript(() => {
|
|
20
|
+
try {
|
|
21
|
+
localStorage.setItem('anet-theme', 'cyber');
|
|
22
|
+
sessionStorage.setItem('anet_v3_auth', '1');
|
|
23
|
+
sessionStorage.removeItem('anet-topo-pinned-status');
|
|
24
|
+
sessionStorage.removeItem('anet-topo-pinned-group');
|
|
25
|
+
sessionStorage.removeItem('anet-topo-pinned-vendor');
|
|
26
|
+
} catch {}
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
const fresh = new Date(Date.now() - 60 * 1000).toISOString();
|
|
30
|
+
await ctx.route('**/api/hub/status*', async (route) => {
|
|
31
|
+
const r = await route.fetch();
|
|
32
|
+
const b = await r.json();
|
|
33
|
+
const nid = (b.sessions || [])[0]?.network_id || 'default';
|
|
34
|
+
const mk = (alias, status) => ({
|
|
35
|
+
alias, status, model: 'claude-opus-4', runtime: 'cli-claude-code',
|
|
36
|
+
network_id: nid, project_dir: null,
|
|
37
|
+
created_at: fresh, updated_at: fresh, last_seen_at: fresh,
|
|
38
|
+
});
|
|
39
|
+
await route.fulfill({ response: r, json: { ...b, sessions: [
|
|
40
|
+
mk('alpha', 'working'),
|
|
41
|
+
mk('beta', 'idle'),
|
|
42
|
+
mk('gamma', 'idle'),
|
|
43
|
+
] } });
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
const now = Date.now();
|
|
47
|
+
await ctx.route('**/api/hub/messages*', (route) => route.fulfill({ json: { messages: [
|
|
48
|
+
{ id: 'm1', from_alias: 'alpha', to_alias: 'beta', content: 'hi',
|
|
49
|
+
network_id: 'default', created_at: new Date(now - 30000).toISOString() },
|
|
50
|
+
] } }));
|
|
51
|
+
await ctx.route('**/api/hub/tasks*', (route) => route.fulfill({ json: { tasks: [] } }));
|
|
52
|
+
const page = await ctx.newPage();
|
|
53
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
|
|
54
|
+
await page.waitForFunction(() => document.querySelectorAll('g[data-node]').length === 3, { timeout: 30000 });
|
|
55
|
+
await page.waitForSelector('[data-recent-row]', { timeout: 10000 });
|
|
56
|
+
await page.waitForTimeout(400);
|
|
57
|
+
|
|
58
|
+
// Helper: pin status via R69 CustomEvent + pin edge via row click.
|
|
59
|
+
const setupBothPins = async () => {
|
|
60
|
+
await page.evaluate(() => {
|
|
61
|
+
sessionStorage.setItem('anet-topo-pinned-status', 'working');
|
|
62
|
+
window.dispatchEvent(new CustomEvent('anet:topo-pin', { detail: { kind: 'status', value: 'working' } }));
|
|
63
|
+
});
|
|
64
|
+
await page.locator('[data-recent-row="alpha->beta"]').click();
|
|
65
|
+
await page.mouse.move(10, 10);
|
|
66
|
+
await page.waitForTimeout(300);
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
const probe = () => page.evaluate(() => ({
|
|
70
|
+
statusPill: document.querySelector('[data-active-filter="status"]') !== null,
|
|
71
|
+
edgePinned: document.querySelector('[data-recent-row-pinned="true"]') !== null,
|
|
72
|
+
}));
|
|
73
|
+
|
|
74
|
+
// === Test 1: clear-all clears both. ===
|
|
75
|
+
await setupBothPins();
|
|
76
|
+
const bothBefore = await probe();
|
|
77
|
+
await page.evaluate(() => {
|
|
78
|
+
sessionStorage.removeItem('anet-topo-pinned-status');
|
|
79
|
+
window.dispatchEvent(new CustomEvent('anet:topo-pin', { detail: { kind: 'clear' } }));
|
|
80
|
+
});
|
|
81
|
+
await page.waitForTimeout(300);
|
|
82
|
+
const afterClearAll = await probe();
|
|
83
|
+
|
|
84
|
+
// === Test 2: clear-edge clears only edge. ===
|
|
85
|
+
await setupBothPins();
|
|
86
|
+
const bothBefore2 = await probe();
|
|
87
|
+
await page.evaluate(() => {
|
|
88
|
+
window.dispatchEvent(new CustomEvent('anet:topo-pin', { detail: { kind: 'clear-edge' } }));
|
|
89
|
+
});
|
|
90
|
+
await page.waitForTimeout(300);
|
|
91
|
+
const afterClearEdge = await probe();
|
|
92
|
+
|
|
93
|
+
await browser.close();
|
|
94
|
+
|
|
95
|
+
const results = {
|
|
96
|
+
bothBefore_statusPinned: bothBefore.statusPill === true,
|
|
97
|
+
bothBefore_edgePinned: bothBefore.edgePinned === true,
|
|
98
|
+
clearAll_statusGone: afterClearAll.statusPill === false,
|
|
99
|
+
clearAll_edgeGone: afterClearAll.edgePinned === false,
|
|
100
|
+
bothBefore2_setup: bothBefore2.statusPill && bothBefore2.edgePinned,
|
|
101
|
+
clearEdge_statusKept: afterClearEdge.statusPill === true,
|
|
102
|
+
clearEdge_edgeGone: afterClearEdge.edgePinned === false,
|
|
103
|
+
};
|
|
104
|
+
const ok = Object.values(results).every(Boolean);
|
|
105
|
+
console.log(`${ok ? '✅' : '❌'} cmdk edge clear:`, JSON.stringify(results),
|
|
106
|
+
`\n bothBefore=`, bothBefore,
|
|
107
|
+
`\n afterClearAll=`, afterClearAll,
|
|
108
|
+
`\n afterClearEdge=`, afterClearEdge);
|
|
109
|
+
process.exit(ok ? 0 : 1);
|