@sleep2agi/agent-network-dashboard 0.4.6-preview.13 → 0.4.6-preview.131
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/09pxnkf-1.1fj.js +1 -0
- package/.next/static/chunks/0eo167c-wlmfz.js +4 -0
- package/.next/static/chunks/0glmrdj9112tc.js +7 -0
- package/.next/static/chunks/0rxrez_cjn.eh.js +1 -0
- package/.next/static/chunks/0x8x.29hkju5a.js +1 -0
- package/.next/static/chunks/0yv1jpx~5v038.js +7 -0
- package/.next/static/chunks/10tq~cwj-obp4.js +1 -0
- package/.next/static/chunks/1450fa_~v9qpc.css +2 -0
- package/.next/static/chunks/174re5ar~kxne.js +1 -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 +87 -0
- package/app/components/ServersDrawer.tsx +64 -27
- package/app/components/TopoGraph.tsx +2419 -163
- package/app/components/utils.ts +8 -7
- package/app/globals.css +19 -1
- 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-test.mjs +73 -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-chat-focus-ring-test.mjs +77 -0
- package/scripts/topo-chat-target-breath-test.mjs +84 -0
- package/scripts/topo-chip-pin-mirror-test.mjs +113 -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-dispatch-pulse-test.mjs +83 -0
- package/scripts/topo-edge-badge-click-pin-test.mjs +94 -0
- package/scripts/topo-edge-badge-hover-test.mjs +85 -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-focus-test.mjs +113 -0
- package/scripts/topo-edge-hover-test.mjs +93 -0
- package/scripts/topo-edge-pill-test.mjs +105 -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-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-live-test.mjs +100 -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-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-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-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-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-tint-test.mjs +95 -0
- package/scripts/topo-minimap-test.mjs +68 -0
- package/scripts/topo-mobile-chips-test.mjs +103 -0
- package/scripts/topo-node-hover-lift-test.mjs +85 -0
- package/scripts/topo-node-title-test.mjs +101 -0
- package/scripts/topo-offline-dim-test.mjs +70 -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-particle-stagger-test.mjs +82 -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-pulse-rate-test.mjs +71 -0
- package/scripts/topo-recent-panel-count-test.mjs +72 -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-ts-test.mjs +92 -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-status-chip-hover-test.mjs +101 -0
- package/scripts/topo-status-chip-tooltip-test.mjs +95 -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-wheel-zoom-test.mjs +79 -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/02t5jr4shh.hy.js +0 -1
- package/.next/static/chunks/03u_oa2o2jrr~.js +0 -1
- package/.next/static/chunks/0_qfg5s5uzs7..js +0 -7
- package/.next/static/chunks/0dttftqqehpdj.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/0q_z8ad2uojv5.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/chunks/17h~0~zsxjx6x.css +0 -2
- /package/.next/static/{nhazRrlYzcsAAYMwx8NFz → A3ssjbOXf7a3BaCWBznPU}/_buildManifest.js +0 -0
- /package/.next/static/{nhazRrlYzcsAAYMwx8NFz → A3ssjbOXf7a3BaCWBznPU}/_clientMiddlewareManifest.js +0 -0
- /package/.next/static/{nhazRrlYzcsAAYMwx8NFz → A3ssjbOXf7a3BaCWBznPU}/_ssgManifest.js +0 -0
|
@@ -3,7 +3,10 @@
|
|
|
3
3
|
* - node ↔ node — status rings don't intersect
|
|
4
4
|
* - node ↔ panel — no node circle intersects an overlay panel rect
|
|
5
5
|
* - node ↔ group-label — no group-box label text covers a node
|
|
6
|
-
* - group-box ↔ box — no two group boxes overlap
|
|
6
|
+
* - group-box ↔ box — no two group boxes overlap
|
|
7
|
+
* - label ↔ label — no two text labels overlap (Round 27 — caught
|
|
8
|
+
* the dense-node-label vs group-label collision
|
|
9
|
+
* Vincent reported in preview.29) */
|
|
7
10
|
import { chromium } from 'playwright';
|
|
8
11
|
import { readFileSync, mkdirSync } from 'node:fs';
|
|
9
12
|
|
|
@@ -80,11 +83,24 @@ async function check(layout) {
|
|
|
80
83
|
label: { x: bb.x, y: bb.y, w: bb.width, h: bb.height },
|
|
81
84
|
};
|
|
82
85
|
});
|
|
83
|
-
|
|
86
|
+
// Round 27 / P0: every visible label bbox (node alias text + group
|
|
87
|
+
// headings) so we can assert label↔label clearance. Skip elements
|
|
88
|
+
// with empty bboxes (e.g., text inside an unrendered <g>).
|
|
89
|
+
const allLabels = [];
|
|
90
|
+
for (const t of svg.querySelectorAll('g[data-node] text, g[data-group] text')) {
|
|
91
|
+
const bb = t.getBBox();
|
|
92
|
+
if (bb.width === 0 || bb.height === 0) continue;
|
|
93
|
+
allLabels.push({
|
|
94
|
+
kind: t.closest('g[data-group]') ? 'group' : 'node',
|
|
95
|
+
owner: (t.closest('g[data-group]')?.getAttribute('data-group')) || (t.closest('g[data-node]')?.getAttribute('data-node')) || '?',
|
|
96
|
+
x: bb.x, y: bb.y, w: bb.width, h: bb.height,
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
return { nodes, panels, groups, allLabels };
|
|
84
100
|
});
|
|
85
101
|
|
|
86
102
|
const TOL = 2; // px slack — touching edges is fine, real overlap is not
|
|
87
|
-
let nodeNode = 0, nodePanel = 0, nodeLabel = 0, boxBox = 0;
|
|
103
|
+
let nodeNode = 0, nodePanel = 0, nodeLabel = 0, boxBox = 0, labelLabel = 0;
|
|
88
104
|
|
|
89
105
|
// node ↔ node
|
|
90
106
|
for (let i = 0; i < data.nodes.length; i++) {
|
|
@@ -119,12 +135,23 @@ async function check(layout) {
|
|
|
119
135
|
overlaps1D(a.y, a.y + a.h, b.y, b.y + b.h, TOL)) boxBox++;
|
|
120
136
|
}
|
|
121
137
|
}
|
|
138
|
+
// label ↔ label (Round 27)
|
|
139
|
+
// Same-node node-labels (e.g. alias + sub-status in the full card) are
|
|
140
|
+
// intentionally close and adjacent — skip pairs that share an owner.
|
|
141
|
+
for (let i = 0; i < data.allLabels.length; i++) {
|
|
142
|
+
for (let j = i + 1; j < data.allLabels.length; j++) {
|
|
143
|
+
const a = data.allLabels[i], b = data.allLabels[j];
|
|
144
|
+
if (a.owner === b.owner) continue;
|
|
145
|
+
if (overlaps1D(a.x, a.x + a.w, b.x, b.x + b.w, TOL) &&
|
|
146
|
+
overlaps1D(a.y, a.y + a.h, b.y, b.y + b.h, TOL)) labelLabel++;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
122
149
|
|
|
123
150
|
await page.screenshot({ path: `/tmp/anet-issue-112/overlap-${layout}.png` });
|
|
124
151
|
await ctx.close();
|
|
125
|
-
const ok = nodeNode === 0 && nodePanel === 0 && nodeLabel === 0 && boxBox === 0;
|
|
152
|
+
const ok = nodeNode === 0 && nodePanel === 0 && nodeLabel === 0 && boxBox === 0 && labelLabel === 0;
|
|
126
153
|
console.log(`${ok ? '✅' : '❌'} [${layout}] nodes=${data.nodes.length} groups=${data.groups.length} — ` +
|
|
127
|
-
`node↔node:${nodeNode} node↔panel:${nodePanel} node↔label:${nodeLabel} box↔box:${boxBox}`);
|
|
154
|
+
`node↔node:${nodeNode} node↔panel:${nodePanel} node↔label:${nodeLabel} box↔box:${boxBox} label↔label:${labelLabel}`);
|
|
128
155
|
return ok;
|
|
129
156
|
}
|
|
130
157
|
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/* Round 21 verification: SVG cursor flips from grab → grabbing during
|
|
2
|
+
* a pan drag and back to grab on release. */
|
|
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
|
+
// Need a tall enough viewport to keep the SVG ABOVE the fold so real
|
|
9
|
+
// pointer events land — at 1280×900 the canvas starts at ~y=815 (the
|
|
10
|
+
// /admin hero + StatsBar above push it below the viewport bottom).
|
|
11
|
+
const ctx = await browser.newContext({ viewport: { width: 1280, height: 1600 } });
|
|
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.setItem('anet-topo-layout', 'grid');
|
|
17
|
+
sessionStorage.setItem('anet_v3_auth', '1');
|
|
18
|
+
} catch {}
|
|
19
|
+
});
|
|
20
|
+
const fresh = new Date(Date.now() - 60 * 1000).toISOString();
|
|
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 = ['a', 'b'].map(a => ({
|
|
26
|
+
alias: a, status: 'idle', network_id: nid, project_dir: null,
|
|
27
|
+
created_at: fresh, updated_at: fresh, last_seen_at: fresh,
|
|
28
|
+
}));
|
|
29
|
+
await route.fulfill({ response: r, json: { ...b, sessions } });
|
|
30
|
+
});
|
|
31
|
+
await ctx.route('**/api/hub/tasks*', (route) => route.fulfill({ json: { tasks: [] } }));
|
|
32
|
+
const page = await ctx.newPage();
|
|
33
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
|
|
34
|
+
await page.waitForSelector('svg[viewBox="0 0 1000 680"]', { timeout: 30000 });
|
|
35
|
+
await page.waitForTimeout(400);
|
|
36
|
+
|
|
37
|
+
const cursorAt = () => page.$eval('svg[viewBox="0 0 1000 680"]', el => el.style.cursor);
|
|
38
|
+
const rest = await cursorAt();
|
|
39
|
+
|
|
40
|
+
// pick a pan-safe target far from any node — top-left empty canvas region
|
|
41
|
+
const box = await page.$eval('svg[viewBox="0 0 1000 680"]', el => el.getBoundingClientRect());
|
|
42
|
+
const sx = box.x + box.width * 0.08;
|
|
43
|
+
const sy = box.y + box.height * 0.40;
|
|
44
|
+
|
|
45
|
+
await page.mouse.move(sx, sy);
|
|
46
|
+
await page.mouse.down();
|
|
47
|
+
await page.mouse.move(sx + 40, sy + 30);
|
|
48
|
+
await page.waitForTimeout(50);
|
|
49
|
+
const during = await cursorAt();
|
|
50
|
+
await page.mouse.up();
|
|
51
|
+
await page.waitForTimeout(50);
|
|
52
|
+
const after = await cursorAt();
|
|
53
|
+
|
|
54
|
+
await browser.close();
|
|
55
|
+
const results = {
|
|
56
|
+
restIsGrab: rest === 'grab',
|
|
57
|
+
duringIsGrabbing: during === 'grabbing',
|
|
58
|
+
afterIsGrab: after === 'grab',
|
|
59
|
+
};
|
|
60
|
+
const ok = Object.values(results).every(Boolean);
|
|
61
|
+
console.log(`${ok ? '✅' : '❌'} pan cursor:`, JSON.stringify(results), `rest=${rest} during=${during} after=${after}`);
|
|
62
|
+
process.exit(ok ? 0 : 1);
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/* Round 57 verification: recent-signal + legend panels carry a drop-
|
|
2
|
+
* shadow filter so they read as floating cards instead of pasted-on
|
|
3
|
+
* graphics — especially important on light theme where panel fill is
|
|
4
|
+
* near-white on a near-white canvas.
|
|
5
|
+
*
|
|
6
|
+
* - Both panels render a <rect> with `data-topo-panel-elevation`.
|
|
7
|
+
* - The rect's `style.filter` contains "drop-shadow(".
|
|
8
|
+
* - Light vs cyber themes use different shadow alpha (light tuned for
|
|
9
|
+
* contrast against white canvas; cyber for subtle depth on dark).
|
|
10
|
+
* Verify the strings differ so the theme switch isn't a no-op.
|
|
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
|
+
async function probe(theme) {
|
|
19
|
+
const ctx = await browser.newContext({ viewport: { width: 1280, height: 1500 } });
|
|
20
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
21
|
+
await ctx.addInitScript((t) => {
|
|
22
|
+
try {
|
|
23
|
+
localStorage.setItem('anet-theme', t);
|
|
24
|
+
localStorage.setItem('anet-topo-layout', 'ring');
|
|
25
|
+
sessionStorage.setItem('anet_v3_auth', '1');
|
|
26
|
+
} catch {}
|
|
27
|
+
}, theme);
|
|
28
|
+
const fresh = new Date(Date.now() - 60 * 1000).toISOString();
|
|
29
|
+
await ctx.route('**/api/hub/status*', async (route) => {
|
|
30
|
+
const r = await route.fetch();
|
|
31
|
+
const b = await r.json();
|
|
32
|
+
const nid = (b.sessions || [])[0]?.network_id || 'default';
|
|
33
|
+
const sessions = ['alpha', 'beta'].map(a => ({
|
|
34
|
+
alias: a, status: 'idle', network_id: nid, project_dir: null,
|
|
35
|
+
created_at: fresh, updated_at: fresh, last_seen_at: fresh,
|
|
36
|
+
}));
|
|
37
|
+
await route.fulfill({ response: r, json: { ...b, sessions } });
|
|
38
|
+
});
|
|
39
|
+
await ctx.route('**/api/hub/messages*', (route) => route.fulfill({ json: { messages: [] } }));
|
|
40
|
+
await ctx.route('**/api/hub/tasks*', (route) => route.fulfill({ json: { tasks: [] } }));
|
|
41
|
+
const page = await ctx.newPage();
|
|
42
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
|
|
43
|
+
await page.waitForSelector('rect[data-topo-panel-elevation="recent"]', { timeout: 30000 });
|
|
44
|
+
await page.waitForTimeout(400);
|
|
45
|
+
const filters = await page.evaluate(() => {
|
|
46
|
+
const recent = document.querySelector('rect[data-topo-panel-elevation="recent"]');
|
|
47
|
+
const legend = document.querySelector('rect[data-topo-panel-elevation="legend"]');
|
|
48
|
+
return {
|
|
49
|
+
recent: recent?.getAttribute('style') || '',
|
|
50
|
+
legend: legend?.getAttribute('style') || '',
|
|
51
|
+
recentComputed: recent ? getComputedStyle(recent).filter : null,
|
|
52
|
+
legendComputed: legend ? getComputedStyle(legend).filter : null,
|
|
53
|
+
};
|
|
54
|
+
});
|
|
55
|
+
await ctx.close();
|
|
56
|
+
return filters;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const light = await probe('light');
|
|
60
|
+
const cyber = await probe('cyber');
|
|
61
|
+
await browser.close();
|
|
62
|
+
|
|
63
|
+
const hasShadow = (s) => /drop-shadow\(/.test(s || '');
|
|
64
|
+
const results = {
|
|
65
|
+
light_recent_hasShadow: hasShadow(light.recent),
|
|
66
|
+
light_legend_hasShadow: hasShadow(light.legend),
|
|
67
|
+
cyber_recent_hasShadow: hasShadow(cyber.recent),
|
|
68
|
+
cyber_legend_hasShadow: hasShadow(cyber.legend),
|
|
69
|
+
themes_differ: light.recent !== cyber.recent,
|
|
70
|
+
computed_resolves: hasShadow(light.recentComputed) && hasShadow(cyber.recentComputed),
|
|
71
|
+
};
|
|
72
|
+
const ok = Object.values(results).every(Boolean);
|
|
73
|
+
console.log(`${ok ? '✅' : '❌'} panel elevation:`, JSON.stringify(results),
|
|
74
|
+
`\n light.recent=${JSON.stringify(light.recent)}`,
|
|
75
|
+
`\n cyber.recent=${JSON.stringify(cyber.recent)}`);
|
|
76
|
+
process.exit(ok ? 0 : 1);
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/* Round 103 verification: flow-particle `<animateMotion begin>` is
|
|
2
|
+
* unique per edge, staggered by `-(index × 0.37) % duration s`. Pre-
|
|
3
|
+
* R103 all edges' particles fired at t=0 in lockstep; the stagger
|
|
4
|
+
* gives the canvas an organic "many independent rivers" feel.
|
|
5
|
+
*
|
|
6
|
+
* Verifies:
|
|
7
|
+
* - every edge has a `begin` attribute on its <animateMotion>
|
|
8
|
+
* - all begin values are distinct (no two edges share a phase)
|
|
9
|
+
* - the format is "-Ns" (negative offset for retroactive cycle start)
|
|
10
|
+
* - reducedMotion still suppresses the particle entirely
|
|
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
|
+
const fresh = new Date(Date.now() - 30 * 1000).toISOString();
|
|
18
|
+
|
|
19
|
+
const probe = async (reducedMotion) => {
|
|
20
|
+
const ctx = await browser.newContext({
|
|
21
|
+
viewport: { width: 1400, height: 1500 },
|
|
22
|
+
reducedMotion: reducedMotion ? 'reduce' : 'no-preference',
|
|
23
|
+
});
|
|
24
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
25
|
+
await ctx.addInitScript(() => {
|
|
26
|
+
try { localStorage.setItem('anet-theme', 'cyber'); sessionStorage.setItem('anet_v3_auth', '1'); } catch {}
|
|
27
|
+
});
|
|
28
|
+
await ctx.route('**/api/hub/status*', async (route) => {
|
|
29
|
+
const r = await route.fetch();
|
|
30
|
+
const b = await r.json();
|
|
31
|
+
const nid = (b.sessions || [])[0]?.network_id || 'default';
|
|
32
|
+
const mk = (alias) => ({
|
|
33
|
+
alias, status: 'idle', model: 'claude-opus-4', runtime: 'cli-claude-code',
|
|
34
|
+
network_id: nid, project_dir: null,
|
|
35
|
+
created_at: fresh, updated_at: fresh, last_seen_at: fresh,
|
|
36
|
+
});
|
|
37
|
+
await route.fulfill({ response: r, json: { ...b, sessions: [mk('alpha'), mk('beta'), mk('gamma'), mk('delta'), mk('epsilon')] } });
|
|
38
|
+
});
|
|
39
|
+
const now = Date.now();
|
|
40
|
+
const mkMsg = (id, from_alias, to_alias, ageMs) => ({
|
|
41
|
+
id, from_alias, to_alias, content: 'hi', network_id: 'default',
|
|
42
|
+
created_at: new Date(now - ageMs).toISOString(),
|
|
43
|
+
});
|
|
44
|
+
// Five distinct edges → five animations.
|
|
45
|
+
await ctx.route('**/api/hub/messages*', (route) => route.fulfill({ json: { messages: [
|
|
46
|
+
mkMsg('m1', 'alpha', 'beta', 30 * 1000),
|
|
47
|
+
mkMsg('m2', 'gamma', 'delta', 35 * 1000),
|
|
48
|
+
mkMsg('m3', 'beta', 'gamma', 40 * 1000),
|
|
49
|
+
mkMsg('m4', 'delta', 'epsilon', 45 * 1000),
|
|
50
|
+
mkMsg('m5', 'epsilon', 'alpha', 50 * 1000),
|
|
51
|
+
] } }));
|
|
52
|
+
await ctx.route('**/api/hub/tasks*', (route) => route.fulfill({ json: { tasks: [] } }));
|
|
53
|
+
const page = await ctx.newPage();
|
|
54
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
|
|
55
|
+
await page.waitForFunction(() => document.querySelectorAll('g[data-node]').length === 5, { timeout: 30000 });
|
|
56
|
+
await page.waitForTimeout(400);
|
|
57
|
+
|
|
58
|
+
const beginValues = await page.evaluate(() => {
|
|
59
|
+
return [...document.querySelectorAll('animateMotion')]
|
|
60
|
+
.map(a => a.getAttribute('begin'));
|
|
61
|
+
});
|
|
62
|
+
await ctx.close();
|
|
63
|
+
return beginValues;
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
const normal = await probe(false);
|
|
67
|
+
const reduced = await probe(true);
|
|
68
|
+
await browser.close();
|
|
69
|
+
|
|
70
|
+
const results = {
|
|
71
|
+
normal_hasAtLeast5: normal.length >= 5,
|
|
72
|
+
normal_allHaveBegin: normal.every(b => typeof b === 'string' && b.length > 0),
|
|
73
|
+
normal_allNegativeOffset: normal.every(b => /^-\d/.test(b || '')),
|
|
74
|
+
normal_allDistinct: new Set(normal).size === normal.length,
|
|
75
|
+
normal_firstIsZero: normal[0] === '-0.000s',
|
|
76
|
+
reduced_noParticles: reduced.length === 0,
|
|
77
|
+
};
|
|
78
|
+
const ok = Object.values(results).every(Boolean);
|
|
79
|
+
console.log(`${ok ? '✅' : '❌'} particle stagger:`, JSON.stringify(results),
|
|
80
|
+
`\n normal=`, normal,
|
|
81
|
+
`\n reduced=`, reduced);
|
|
82
|
+
process.exit(ok ? 0 : 1);
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/* Round 124 verification: pin-intersection summary chip.
|
|
2
|
+
*
|
|
3
|
+
* The four filter pills (R64 status / R63 group / R89 vendor /
|
|
4
|
+
* R119 edge) each show their own dim's match count in isolation.
|
|
5
|
+
* But the node-opacity chain (lines 2723-2741 of TopoGraph.tsx)
|
|
6
|
+
* AND-composes all four pin dimensions — every miss dims the node.
|
|
7
|
+
* So two active pins produce an intersection ≤ either individual
|
|
8
|
+
* count, and the existing pills don't surface that.
|
|
9
|
+
*
|
|
10
|
+
* R124 adds a small "match: N pins · K" chip after the last pill
|
|
11
|
+
* when ≥ 2 pin dims are active. K = nodes that satisfy ALL active
|
|
12
|
+
* pins. Single pin keeps its old pill story (chip hidden).
|
|
13
|
+
*
|
|
14
|
+
* Fleet:
|
|
15
|
+
* alpha (working, vendor=A, group=agents)
|
|
16
|
+
* beta (working, vendor=O, group=agents)
|
|
17
|
+
* gamma (idle, vendor=A, group=agents)
|
|
18
|
+
* delta (working, vendor=A, group=infra)
|
|
19
|
+
*
|
|
20
|
+
* Test path:
|
|
21
|
+
* 1. No pin → chip hidden
|
|
22
|
+
* 2. Pin status=working → chip hidden (1 pin)
|
|
23
|
+
* 3. + Pin vendor=A → chip "2 pins · 2"
|
|
24
|
+
* (working AND vendor=A: alpha, delta)
|
|
25
|
+
* 4. + Pin group=agents → chip "3 pins · 1"
|
|
26
|
+
* (working AND A AND agents: alpha only)
|
|
27
|
+
* 5. Esc → chip hidden
|
|
28
|
+
*/
|
|
29
|
+
import { chromium } from 'playwright';
|
|
30
|
+
import { readFileSync } from 'node:fs';
|
|
31
|
+
|
|
32
|
+
const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
|
|
33
|
+
const browser = await chromium.launch({ headless: true });
|
|
34
|
+
|
|
35
|
+
const ctx = await browser.newContext({ viewport: { width: 1400, height: 1100 } });
|
|
36
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
37
|
+
await ctx.addInitScript(() => {
|
|
38
|
+
try { localStorage.setItem('anet-theme', 'cyber'); sessionStorage.setItem('anet_v3_auth', '1'); } catch {}
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
const fresh = new Date(Date.now() - 60 * 1000).toISOString();
|
|
42
|
+
await ctx.route('**/api/hub/status*', async (route) => {
|
|
43
|
+
const r = await route.fetch();
|
|
44
|
+
const b = await r.json();
|
|
45
|
+
const nid = (b.sessions || [])[0]?.network_id || 'default';
|
|
46
|
+
const mk = (alias, status, model) => ({
|
|
47
|
+
alias, status, model, runtime: 'cli-claude-code',
|
|
48
|
+
network_id: nid, project_dir: alias.startsWith('infra-') ? '/srv/infra' : '/srv/agents',
|
|
49
|
+
created_at: fresh, updated_at: fresh, last_seen_at: fresh,
|
|
50
|
+
});
|
|
51
|
+
await route.fulfill({ response: r, json: { ...b, sessions: [
|
|
52
|
+
mk('agents-alpha', 'working', 'claude-opus-4'),
|
|
53
|
+
mk('agents-beta', 'working', 'gpt-4o'),
|
|
54
|
+
mk('agents-gamma', 'idle', 'claude-sonnet-4'),
|
|
55
|
+
mk('infra-delta', 'working', 'claude-haiku-4'),
|
|
56
|
+
] } });
|
|
57
|
+
});
|
|
58
|
+
await ctx.route('**/api/hub/messages*', (route) => route.fulfill({ json: { messages: [] } }));
|
|
59
|
+
await ctx.route('**/api/hub/tasks*', (route) => route.fulfill({ json: { tasks: [] } }));
|
|
60
|
+
|
|
61
|
+
const page = await ctx.newPage();
|
|
62
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
|
|
63
|
+
await page.waitForFunction(() => document.querySelectorAll('g[data-node]').length === 4, { timeout: 30000 });
|
|
64
|
+
await page.waitForTimeout(400);
|
|
65
|
+
|
|
66
|
+
const readChip = () => page.evaluate(() => {
|
|
67
|
+
const el = document.querySelector('[data-pin-intersection]');
|
|
68
|
+
if (!el) return null;
|
|
69
|
+
return {
|
|
70
|
+
dimCount: parseInt(el.getAttribute('data-pin-dim-count') || '0', 10),
|
|
71
|
+
matchCount: parseInt(el.getAttribute('data-pin-intersection-count') || '0', 10),
|
|
72
|
+
aliases: (el.getAttribute('data-pin-intersection-aliases') || '').split(',').filter(Boolean),
|
|
73
|
+
text: el.textContent?.trim(),
|
|
74
|
+
};
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
// State 1 — no pins
|
|
78
|
+
const s1 = await readChip();
|
|
79
|
+
|
|
80
|
+
// State 2 — pin status=working via pressure-bar segment
|
|
81
|
+
await page.locator('[data-pressure-seg="working"]').click();
|
|
82
|
+
await page.waitForTimeout(200);
|
|
83
|
+
const s2 = await readChip();
|
|
84
|
+
|
|
85
|
+
// State 3 — + pin vendor=A
|
|
86
|
+
await page.locator('[data-vendor-letter="A"]').click();
|
|
87
|
+
await page.waitForTimeout(200);
|
|
88
|
+
const s3 = await readChip();
|
|
89
|
+
|
|
90
|
+
// State 4 — + pin group=agents via the R69 CustomEvent contract.
|
|
91
|
+
// Direct dispatch is mode-independent (group-label hit-rects only
|
|
92
|
+
// render in grid layout; default is ring). The handler at line 945
|
|
93
|
+
// of TopoGraph.tsx accepts { kind: 'group', value: <key> }.
|
|
94
|
+
await page.evaluate(() => {
|
|
95
|
+
window.dispatchEvent(new CustomEvent('anet:topo-pin', { detail: { kind: 'group', value: 'agents' } }));
|
|
96
|
+
});
|
|
97
|
+
await page.waitForTimeout(200);
|
|
98
|
+
const s4 = await readChip();
|
|
99
|
+
|
|
100
|
+
// State 5 — Esc clears all pins
|
|
101
|
+
await page.keyboard.press('Escape');
|
|
102
|
+
await page.waitForTimeout(200);
|
|
103
|
+
const s5 = await readChip();
|
|
104
|
+
|
|
105
|
+
await browser.close();
|
|
106
|
+
|
|
107
|
+
const results = {
|
|
108
|
+
s1_noPins_chipHidden: s1 === null,
|
|
109
|
+
s2_onePin_chipHidden: s2 === null,
|
|
110
|
+
s3_twoPins_chipShown: !!s3 && s3.dimCount === 2,
|
|
111
|
+
s3_intersection_2: !!s3 && s3.matchCount === 2,
|
|
112
|
+
s3_aliases_alphaDelta: !!s3 && s3.aliases.includes('agents-alpha') && s3.aliases.includes('infra-delta'),
|
|
113
|
+
s4_threePins_chipShown: !!s4 && s4.dimCount === 3,
|
|
114
|
+
s4_intersection_1: !!s4 && s4.matchCount === 1,
|
|
115
|
+
s4_aliases_alphaOnly: !!s4 && s4.aliases.length === 1 && s4.aliases[0] === 'agents-alpha',
|
|
116
|
+
s5_escClears_chipHidden: s5 === null,
|
|
117
|
+
};
|
|
118
|
+
const ok = Object.values(results).every(Boolean);
|
|
119
|
+
console.log(`${ok ? '✅' : '❌'} pin-intersection chip:`, JSON.stringify(results),
|
|
120
|
+
`\n s1=`, s1, `\n s2=`, s2, `\n s3=`, s3, `\n s4=`, s4, `\n s5=`, s5);
|
|
121
|
+
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,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);
|