@sleep2agi/agent-network-dashboard 0.5.3-preview.8 → 0.5.3-preview.80
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.next/BUILD_ID +1 -1
- package/.next/build-manifest.json +3 -3
- package/.next/diagnostics/route-bundle-stats.json +32 -32
- package/.next/fallback-build-manifest.json +3 -3
- package/.next/server/app/_global-error.html +1 -1
- package/.next/server/app/_global-error.rsc +1 -1
- package/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
- package/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/.next/server/app/_not-found.html +2 -2
- package/.next/server/app/_not-found.rsc +12 -12
- package/.next/server/app/_not-found.segments/_full.segment.rsc +12 -12
- package/.next/server/app/_not-found.segments/_head.segment.rsc +4 -4
- package/.next/server/app/_not-found.segments/_index.segment.rsc +7 -7
- package/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +2 -2
- package/.next/server/app/_not-found.segments/_not-found.segment.rsc +3 -3
- package/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/admin/page_client-reference-manifest.js +1 -1
- package/.next/server/app/admin.html +2 -2
- package/.next/server/app/admin.rsc +14 -14
- package/.next/server/app/admin.segments/_full.segment.rsc +14 -14
- package/.next/server/app/admin.segments/_head.segment.rsc +4 -4
- package/.next/server/app/admin.segments/_index.segment.rsc +7 -7
- package/.next/server/app/admin.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/admin.segments/admin/__PAGE__.segment.rsc +4 -4
- package/.next/server/app/admin.segments/admin.segment.rsc +3 -3
- package/.next/server/app/index.html +2 -2
- package/.next/server/app/index.rsc +14 -14
- package/.next/server/app/index.segments/__PAGE__.segment.rsc +4 -4
- package/.next/server/app/index.segments/_full.segment.rsc +14 -14
- package/.next/server/app/index.segments/_head.segment.rsc +4 -4
- package/.next/server/app/index.segments/_index.segment.rsc +7 -7
- package/.next/server/app/index.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/login/page_client-reference-manifest.js +1 -1
- package/.next/server/app/login.html +2 -2
- package/.next/server/app/login.rsc +14 -14
- package/.next/server/app/login.segments/_full.segment.rsc +14 -14
- package/.next/server/app/login.segments/_head.segment.rsc +4 -4
- package/.next/server/app/login.segments/_index.segment.rsc +7 -7
- package/.next/server/app/login.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/login.segments/login/__PAGE__.segment.rsc +4 -4
- package/.next/server/app/login.segments/login.segment.rsc +3 -3
- package/.next/server/app/logs/page_client-reference-manifest.js +1 -1
- package/.next/server/app/logs.html +2 -2
- package/.next/server/app/logs.rsc +14 -14
- package/.next/server/app/logs.segments/_full.segment.rsc +14 -14
- package/.next/server/app/logs.segments/_head.segment.rsc +4 -4
- package/.next/server/app/logs.segments/_index.segment.rsc +7 -7
- package/.next/server/app/logs.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/logs.segments/logs/__PAGE__.segment.rsc +4 -4
- package/.next/server/app/logs.segments/logs.segment.rsc +3 -3
- package/.next/server/app/messages/page_client-reference-manifest.js +1 -1
- package/.next/server/app/messages.html +2 -2
- package/.next/server/app/messages.rsc +14 -14
- package/.next/server/app/messages.segments/_full.segment.rsc +14 -14
- package/.next/server/app/messages.segments/_head.segment.rsc +4 -4
- package/.next/server/app/messages.segments/_index.segment.rsc +7 -7
- package/.next/server/app/messages.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/messages.segments/messages/__PAGE__.segment.rsc +4 -4
- package/.next/server/app/messages.segments/messages.segment.rsc +3 -3
- package/.next/server/app/node/page_client-reference-manifest.js +1 -1
- package/.next/server/app/node.html +2 -2
- package/.next/server/app/node.rsc +14 -14
- package/.next/server/app/node.segments/_full.segment.rsc +14 -14
- package/.next/server/app/node.segments/_head.segment.rsc +4 -4
- package/.next/server/app/node.segments/_index.segment.rsc +7 -7
- package/.next/server/app/node.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/node.segments/node/__PAGE__.segment.rsc +4 -4
- package/.next/server/app/node.segments/node.segment.rsc +3 -3
- package/.next/server/app/nodes/page_client-reference-manifest.js +1 -1
- package/.next/server/app/nodes.html +2 -2
- package/.next/server/app/nodes.rsc +14 -14
- package/.next/server/app/nodes.segments/_full.segment.rsc +14 -14
- package/.next/server/app/nodes.segments/_head.segment.rsc +4 -4
- package/.next/server/app/nodes.segments/_index.segment.rsc +7 -7
- package/.next/server/app/nodes.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/nodes.segments/nodes/__PAGE__.segment.rsc +4 -4
- package/.next/server/app/nodes.segments/nodes.segment.rsc +3 -3
- package/.next/server/app/page_client-reference-manifest.js +1 -1
- package/.next/server/app/server-logs/page_client-reference-manifest.js +1 -1
- package/.next/server/app/server-logs.html +2 -2
- package/.next/server/app/server-logs.rsc +14 -14
- package/.next/server/app/server-logs.segments/_full.segment.rsc +14 -14
- package/.next/server/app/server-logs.segments/_head.segment.rsc +4 -4
- package/.next/server/app/server-logs.segments/_index.segment.rsc +7 -7
- package/.next/server/app/server-logs.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/server-logs.segments/server-logs/__PAGE__.segment.rsc +4 -4
- package/.next/server/app/server-logs.segments/server-logs.segment.rsc +3 -3
- package/.next/server/app/settings/networks/page_client-reference-manifest.js +1 -1
- package/.next/server/app/settings/networks.html +2 -2
- package/.next/server/app/settings/networks.rsc +14 -14
- package/.next/server/app/settings/networks.segments/_full.segment.rsc +14 -14
- package/.next/server/app/settings/networks.segments/_head.segment.rsc +4 -4
- package/.next/server/app/settings/networks.segments/_index.segment.rsc +7 -7
- package/.next/server/app/settings/networks.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/settings/networks.segments/settings/networks/__PAGE__.segment.rsc +4 -4
- package/.next/server/app/settings/networks.segments/settings/networks.segment.rsc +3 -3
- package/.next/server/app/settings/networks.segments/settings.segment.rsc +3 -3
- package/.next/server/app/settings/page_client-reference-manifest.js +1 -1
- package/.next/server/app/settings/tokens/page_client-reference-manifest.js +1 -1
- package/.next/server/app/settings/tokens.html +2 -2
- package/.next/server/app/settings/tokens.rsc +14 -14
- package/.next/server/app/settings/tokens.segments/_full.segment.rsc +14 -14
- package/.next/server/app/settings/tokens.segments/_head.segment.rsc +4 -4
- package/.next/server/app/settings/tokens.segments/_index.segment.rsc +7 -7
- package/.next/server/app/settings/tokens.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/settings/tokens.segments/settings/tokens/__PAGE__.segment.rsc +4 -4
- package/.next/server/app/settings/tokens.segments/settings/tokens.segment.rsc +3 -3
- package/.next/server/app/settings/tokens.segments/settings.segment.rsc +3 -3
- package/.next/server/app/settings.html +2 -2
- package/.next/server/app/settings.rsc +14 -14
- package/.next/server/app/settings.segments/_full.segment.rsc +14 -14
- package/.next/server/app/settings.segments/_head.segment.rsc +4 -4
- package/.next/server/app/settings.segments/_index.segment.rsc +7 -7
- package/.next/server/app/settings.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/settings.segments/settings/__PAGE__.segment.rsc +4 -4
- package/.next/server/app/settings.segments/settings.segment.rsc +3 -3
- package/.next/server/app/tasks/[id]/page_client-reference-manifest.js +1 -1
- package/.next/server/app/tasks/page_client-reference-manifest.js +1 -1
- package/.next/server/app/tasks.html +2 -2
- package/.next/server/app/tasks.rsc +14 -14
- package/.next/server/app/tasks.segments/_full.segment.rsc +14 -14
- package/.next/server/app/tasks.segments/_head.segment.rsc +4 -4
- package/.next/server/app/tasks.segments/_index.segment.rsc +7 -7
- package/.next/server/app/tasks.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/tasks.segments/tasks/__PAGE__.segment.rsc +4 -4
- package/.next/server/app/tasks.segments/tasks.segment.rsc +3 -3
- package/.next/server/chunks/ssr/[root-of-the-server]__0sv~g.o._.js +1 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__0sv~g.o._.js.map +1 -1
- package/.next/server/chunks/ssr/agent-network-dashboard_09kk21a._.js +4 -4
- 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_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_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/static/chunks/09opq.s35allz.js +1 -0
- package/.next/static/chunks/0mnksqen3wvwj.js +4 -0
- package/.next/static/chunks/{03a4--7ncekmk.js → 0v4-5tng.uh.7.js} +2 -2
- package/.next/static/chunks/0vl-xelss~c7q.css +2 -0
- package/.next/static/chunks/0ye8xjzn045zw.js +1 -0
- package/.next/static/chunks/{0200cxbmk961-.js → 13x8dy_zr3iit.js} +1 -1
- package/.next/trace +2 -2
- package/.next/trace-build +1 -1
- package/app/components/ServersDrawer.tsx +16 -3
- package/app/components/TopoGraph.tsx +2242 -116
- package/app/globals.css +81 -7
- package/package.json +4 -4
- package/scripts/p157-servers-copy-test.mjs +95 -0
- package/scripts/topo-active-chrome-hover-text-test.mjs +107 -0
- package/scripts/topo-alias-glow-test.mjs +121 -0
- package/scripts/topo-avatar-brightness-test.mjs +116 -0
- package/scripts/topo-avatar-fallback-hover-test.mjs +104 -0
- package/scripts/topo-brand-logo-breath-test.mjs +102 -0
- package/scripts/topo-brand-logo-hover-brightness-test.mjs +105 -0
- package/scripts/topo-brand-logo-hover-rotate-test.mjs +93 -0
- package/scripts/topo-brand-logo-hover-test.mjs +85 -0
- package/scripts/topo-chip-row-digit-ls-test.mjs +135 -0
- package/scripts/topo-chip-row-member-alias-lit-test.mjs +154 -0
- package/scripts/topo-chip-row-unit-hover-tracking-test.mjs +124 -0
- package/scripts/topo-cluster-count-attr-test.mjs +80 -0
- package/scripts/topo-crescent-breath-test.mjs +104 -0
- package/scripts/topo-crescent-recede-test.mjs +111 -0
- package/scripts/topo-edge-badge-hover-glow-test.mjs +90 -0
- package/scripts/topo-edge-pill-glow-test.mjs +67 -0
- package/scripts/topo-filter-pill-glow-test.mjs +90 -0
- package/scripts/topo-fleet-density-tier-test.mjs +84 -0
- package/scripts/topo-freshness-chip-fade-test.mjs +105 -0
- package/scripts/topo-fullscreen-attr-test.mjs +73 -0
- package/scripts/topo-grid-content-bottom-attr-test.mjs +72 -0
- package/scripts/topo-group-label-hover-glow-test.mjs +86 -0
- package/scripts/topo-group-label-member-alias-hover-test.mjs +125 -0
- package/scripts/topo-group-pill-glow-test.mjs +76 -0
- package/scripts/topo-hub-digit-ls-test.mjs +119 -0
- package/scripts/topo-hub-halo-glow-test.mjs +96 -0
- package/scripts/topo-hub-highlight-amplify-test.mjs +139 -0
- package/scripts/topo-hub-highlight-fill-transition-test.mjs +84 -0
- package/scripts/topo-hub-highlight-glow-test.mjs +99 -0
- package/scripts/topo-hub-highlight-r-test.mjs +112 -0
- package/scripts/topo-hub-highlight-recede-test.mjs +144 -0
- package/scripts/topo-hub-highlight-theme-fill-test.mjs +83 -0
- package/scripts/topo-hub-hover-ring-glow-test.mjs +97 -0
- package/scripts/topo-hub-idle-breath-test.mjs +109 -0
- package/scripts/topo-hub-recede-test.mjs +124 -0
- package/scripts/topo-hub-spoke-glow-test.mjs +112 -0
- package/scripts/topo-layout-hover-fw-test.mjs +98 -0
- package/scripts/topo-legend-count-letter-spacing-test.mjs +108 -0
- package/scripts/topo-legend-label-fw-test.mjs +107 -0
- package/scripts/topo-legend-swatch-glow-test.mjs +109 -0
- package/scripts/topo-legend-swatch-member-alias-match-test.mjs +139 -0
- package/scripts/topo-minimap-hover-glow-test.mjs +109 -0
- package/scripts/topo-node-alias-brightness-test.mjs +84 -0
- package/scripts/topo-nodesize-hover-fw-test.mjs +99 -0
- package/scripts/topo-orphan-box-dash-test.mjs +89 -0
- package/scripts/topo-orphan-fill-opacity-test.mjs +91 -0
- package/scripts/topo-orphan-label-italic-test.mjs +90 -0
- package/scripts/topo-orphan-label-opacity-test.mjs +98 -0
- package/scripts/topo-panel-count-hover-ls-test.mjs +87 -0
- package/scripts/topo-panel-title-glow-test.mjs +111 -0
- package/scripts/topo-pill-x-rotate-test.mjs +96 -0
- package/scripts/topo-pinned-aspect-test.mjs +89 -0
- package/scripts/topo-pressure-seg-glow-test.mjs +92 -0
- package/scripts/topo-pressure-seg-member-alias-match-test.mjs +133 -0
- package/scripts/topo-pressure-seg-motion-test.mjs +101 -0
- package/scripts/topo-recent-hot-pulse-test.mjs +102 -0
- package/scripts/topo-recent-more-fw-test.mjs +126 -0
- package/scripts/topo-recent-row-fw-test.mjs +115 -0
- package/scripts/topo-reduced-motion-attr-test.mjs +69 -0
- package/scripts/topo-reset-icon-hover-scale-test.mjs +102 -0
- package/scripts/topo-runtime-badge-glow-test.mjs +108 -0
- package/scripts/topo-starfield-hue-test.mjs +109 -0
- package/scripts/topo-titleblock-h2-hover-fw-test.mjs +109 -0
- package/scripts/topo-titleblock-h2-hover-tracking-test.mjs +128 -0
- package/scripts/topo-titleblock-kicker-hover-test.mjs +134 -0
- package/scripts/topo-vendor-activelinks-press-test.mjs +100 -0
- package/scripts/topo-vendor-chip-glow-test.mjs +97 -0
- package/scripts/topo-vendor-pill-glow-test.mjs +98 -0
- package/scripts/topo-watermark-breath-test.mjs +100 -0
- package/scripts/topo-watermark-recede-test.mjs +114 -0
- package/scripts/topo-zoom-level-color-test.mjs +105 -0
- package/.next/static/chunks/07fkn2-8-6ejj.js +0 -4
- package/.next/static/chunks/0hndl9yzpqajt.css +0 -2
- package/.next/static/chunks/0nvcaq5be21x_.js +0 -1
- package/.next/static/chunks/0~r4zc7qlx96l.js +0 -1
- /package/.next/static/{iEkfox1TCVhnJmt_k5SoD → mwWrJ4INww4i53E7v_xMz}/_buildManifest.js +0 -0
- /package/.next/static/{iEkfox1TCVhnJmt_k5SoD → mwWrJ4INww4i53E7v_xMz}/_clientMiddlewareManifest.js +0 -0
- /package/.next/static/{iEkfox1TCVhnJmt_k5SoD → mwWrJ4INww4i53E7v_xMz}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/* Round 561 verification: group-label opacity lifts to 1.0 when
|
|
2
|
+
* operator hovers a NODE ALIAS that's a member of this group.
|
|
3
|
+
* 4th anchor in the inspection-overrides-encoding family.
|
|
4
|
+
*
|
|
5
|
+
* Mock: 3 'alpha-' prefix sessions (1 group) + 3 standalone
|
|
6
|
+
* (orphan band). Hover the alpha-1 node → group 'alpha·' label
|
|
7
|
+
* should lift opacity 0.55 → 1.0.
|
|
8
|
+
*
|
|
9
|
+
* Test phases:
|
|
10
|
+
* 1. confirm grid layout active
|
|
11
|
+
* 2. rest: group 'alpha·' opacity = 0.55
|
|
12
|
+
* 3. hover a node from alpha group → 'alpha·' opacity = 1.0,
|
|
13
|
+
* member-alias-hovered attr = 'true'
|
|
14
|
+
* 4. orphan group should NOT lift (its members aren't hovered)
|
|
15
|
+
* 5. source-side regex confirms wiring
|
|
16
|
+
*/
|
|
17
|
+
import { chromium } from 'playwright';
|
|
18
|
+
import { readFileSync } from 'node:fs';
|
|
19
|
+
|
|
20
|
+
const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
|
|
21
|
+
const fresh = new Date(Date.now() - 60 * 1000).toISOString();
|
|
22
|
+
|
|
23
|
+
const browser = await chromium.launch({ headless: true });
|
|
24
|
+
const ctx = await browser.newContext({ viewport: { width: 1500, height: 1200 } });
|
|
25
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
26
|
+
await ctx.addInitScript(() => {
|
|
27
|
+
try {
|
|
28
|
+
localStorage.setItem('anet-theme', 'cyber');
|
|
29
|
+
localStorage.setItem('anet-topo-layout', 'grid');
|
|
30
|
+
sessionStorage.setItem('anet_v3_auth', '1');
|
|
31
|
+
} catch {}
|
|
32
|
+
});
|
|
33
|
+
await ctx.route('**/api/hub/status*', async (route) => {
|
|
34
|
+
const r = await route.fetch();
|
|
35
|
+
const b = await r.json();
|
|
36
|
+
const nid = (b.sessions || [])[0]?.network_id || 'default';
|
|
37
|
+
const mk = (alias, status = 'idle') => ({
|
|
38
|
+
alias, status, model: 'claude-opus-4', runtime: 'claude-code-cli',
|
|
39
|
+
network_id: nid, project_dir: null,
|
|
40
|
+
created_at: fresh, updated_at: fresh, last_seen_at: fresh,
|
|
41
|
+
});
|
|
42
|
+
// alpha-group has WORKING members → ants run at rest. Hovering a
|
|
43
|
+
// member alias should keep ants running (R561 refined gate).
|
|
44
|
+
await route.fulfill({ response: r, json: { ...b, sessions: [
|
|
45
|
+
mk('alpha·1', 'working'), mk('alpha·2', 'working'), mk('alpha·3'),
|
|
46
|
+
mk('foo'), mk('bar'), mk('baz'),
|
|
47
|
+
] } });
|
|
48
|
+
});
|
|
49
|
+
await ctx.route('**/api/hub/messages*', (r) => r.fulfill({ json: { messages: [] } }));
|
|
50
|
+
await ctx.route('**/api/hub/tasks*', (r) => r.fulfill({ json: { tasks: [] } }));
|
|
51
|
+
const page = await ctx.newPage();
|
|
52
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'networkidle' });
|
|
53
|
+
await page.waitForSelector('[data-group-label]', { timeout: 15000 });
|
|
54
|
+
await page.waitForTimeout(500);
|
|
55
|
+
|
|
56
|
+
const probeGroups = async () => {
|
|
57
|
+
return page.evaluate(() => {
|
|
58
|
+
const els = Array.from(document.querySelectorAll('[data-group-label]'));
|
|
59
|
+
return els.map(el => {
|
|
60
|
+
// Find the matching outer <g> with data-group-box-live to read the
|
|
61
|
+
// ants-gate refinement. The box rect sits within the same parent
|
|
62
|
+
// group as the label — both nest under the per-band <g> in the
|
|
63
|
+
// groupBoxes.map() loop.
|
|
64
|
+
const parent = el.closest('g')?.parentElement || null;
|
|
65
|
+
const boxRect = parent?.querySelector('[data-group-box-live]') || null;
|
|
66
|
+
return {
|
|
67
|
+
key: el.getAttribute('data-group-label'),
|
|
68
|
+
orphan: el.getAttribute('data-group-label-orphan') === 'true',
|
|
69
|
+
opacityAttr: el.getAttribute('data-group-label-opacity'),
|
|
70
|
+
computedOpacity: getComputedStyle(el).opacity,
|
|
71
|
+
memberAliasHovered: el.getAttribute('data-group-label-member-alias-hovered') === 'true',
|
|
72
|
+
boxLive: boxRect?.getAttribute('data-group-box-live'),
|
|
73
|
+
};
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
const restGroups = await probeGroups();
|
|
79
|
+
|
|
80
|
+
// Hover a node from the alpha group.
|
|
81
|
+
await page.hover('g[data-node="alpha·1"]');
|
|
82
|
+
await page.waitForTimeout(400);
|
|
83
|
+
const hoverGroups = await probeGroups();
|
|
84
|
+
|
|
85
|
+
await browser.close();
|
|
86
|
+
|
|
87
|
+
const restAlpha = restGroups.find(g => g.key === 'alpha·');
|
|
88
|
+
const restOrphan = restGroups.find(g => g.orphan);
|
|
89
|
+
const hoverAlpha = hoverGroups.find(g => g.key === 'alpha·');
|
|
90
|
+
const hoverOrphan = hoverGroups.find(g => g.orphan);
|
|
91
|
+
|
|
92
|
+
const src = readFileSync('/home/vansin/agent-network-dashboard/app/components/TopoGraph.tsx', 'utf8');
|
|
93
|
+
const sourceFlag = /const isMemberAliasHovered = !!hoveredAlias && groupKeys\[hoveredAlias\] === box\.key;/.test(src);
|
|
94
|
+
const sourceOpacity = /opacity=\{isPinned \|\| isHovered \|\| isMemberAliasHovered \? 1 : box\.isOrphan \? 0\.4 : 0\.55\}/.test(src);
|
|
95
|
+
const sourceAttr = /data-group-label-member-alias-hovered=/.test(src);
|
|
96
|
+
|
|
97
|
+
const results = {
|
|
98
|
+
alpha_present: !!restAlpha,
|
|
99
|
+
orphan_present: !!restOrphan,
|
|
100
|
+
rest_alpha_opacity_0_55: restAlpha?.computedOpacity === '0.55',
|
|
101
|
+
rest_alpha_attr_not_hovered: restAlpha?.memberAliasHovered === false,
|
|
102
|
+
rest_orphan_opacity_0_4: restOrphan?.computedOpacity === '0.4',
|
|
103
|
+
hover_alpha_opacity_1: hoverAlpha?.computedOpacity === '1',
|
|
104
|
+
hover_alpha_attr_hovered: hoverAlpha?.memberAliasHovered === true,
|
|
105
|
+
hover_orphan_opacity_unchanged: hoverOrphan?.computedOpacity === '0.4',
|
|
106
|
+
hover_orphan_attr_not_hovered: hoverOrphan?.memberAliasHovered === false,
|
|
107
|
+
// R561 ants-gate refinement: alpha group has working members.
|
|
108
|
+
// Rest: ants run ('true'). Pre-R561 hovering a member alias
|
|
109
|
+
// halted ants ('false'); R561 keeps them running on member-alias
|
|
110
|
+
// hover ('true'). Direct label hover would still halt — not
|
|
111
|
+
// exercised here.
|
|
112
|
+
rest_alpha_ants_running: restAlpha?.boxLive === 'true',
|
|
113
|
+
hover_alpha_ants_keep_running: hoverAlpha?.boxLive === 'true',
|
|
114
|
+
source_flag: sourceFlag,
|
|
115
|
+
source_opacity: sourceOpacity,
|
|
116
|
+
source_attr: sourceAttr,
|
|
117
|
+
};
|
|
118
|
+
const ok = Object.values(results).every(Boolean);
|
|
119
|
+
console.log(`${ok ? '✅' : '❌'} R561 group-label member-alias-hover opacity lift (4th anchor in inspection-overrides-encoding):`,
|
|
120
|
+
JSON.stringify(results, null, 2),
|
|
121
|
+
'\n rest alpha:', JSON.stringify(restAlpha),
|
|
122
|
+
'\n rest orphan:', JSON.stringify(restOrphan),
|
|
123
|
+
'\n hover alpha:', JSON.stringify(hoverAlpha),
|
|
124
|
+
'\n hover orphan:', JSON.stringify(hoverOrphan));
|
|
125
|
+
process.exit(ok ? 0 : 1);
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/* Round 544 verification: group filter pill gains cyan-accent drop-
|
|
2
|
+
* shadow when rendered (pin-active visual). Sibling to R543 status pill.
|
|
3
|
+
*
|
|
4
|
+
* Test strategy: source-canonical because group-label click via Playwright
|
|
5
|
+
* is impractical (banked R538/R544 lesson — SVG hit-test intercept).
|
|
6
|
+
* Source regex confirms the wiring; rest-state DOM probe confirms pill
|
|
7
|
+
* is absent when unpinned (baseline behavior unchanged).
|
|
8
|
+
*
|
|
9
|
+
* Test phases:
|
|
10
|
+
* 1. unpinned (default): no [data-active-filter="group"] element
|
|
11
|
+
* 2. source-side regex confirms filter wired with pal.legendAccent
|
|
12
|
+
* via color-mix 60% syntax
|
|
13
|
+
*/
|
|
14
|
+
import { chromium } from 'playwright';
|
|
15
|
+
import { readFileSync } from 'node:fs';
|
|
16
|
+
|
|
17
|
+
const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
|
|
18
|
+
const fresh = new Date(Date.now() - 60 * 1000).toISOString();
|
|
19
|
+
|
|
20
|
+
const browser = await chromium.launch({ headless: true });
|
|
21
|
+
const ctx = await browser.newContext({ viewport: { width: 1500, height: 1200 } });
|
|
22
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
23
|
+
await ctx.addInitScript(() => {
|
|
24
|
+
try {
|
|
25
|
+
localStorage.setItem('anet-theme', 'cyber');
|
|
26
|
+
localStorage.setItem('anet-topo-layout', 'grid');
|
|
27
|
+
sessionStorage.setItem('anet_v3_auth', '1');
|
|
28
|
+
} catch {}
|
|
29
|
+
});
|
|
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: 'claude-code-cli',
|
|
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·1', 'working'), mk('alpha·2', 'working'),
|
|
41
|
+
mk('beta·1', 'idle'), mk('beta·2', 'idle'),
|
|
42
|
+
] } });
|
|
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: 'networkidle' });
|
|
48
|
+
await page.waitForSelector('[data-group-label]', { timeout: 15000 });
|
|
49
|
+
await page.waitForTimeout(500);
|
|
50
|
+
|
|
51
|
+
const unpinned = await page.evaluate(() =>
|
|
52
|
+
document.querySelector('[data-active-filter="group"]') !== null
|
|
53
|
+
);
|
|
54
|
+
|
|
55
|
+
await browser.close();
|
|
56
|
+
|
|
57
|
+
const src = readFileSync('/home/vansin/agent-network-dashboard/app/components/TopoGraph.tsx', 'utf8');
|
|
58
|
+
const sourceFilterWired =
|
|
59
|
+
/filter: `drop-shadow\(0 0 3px color-mix\(in srgb, \$\{pal\.legendAccent\} 60%, transparent\)\)`,/.test(src);
|
|
60
|
+
|
|
61
|
+
// Confirm we edited the GROUP pill specifically (data-active-filter="group")
|
|
62
|
+
// — look for the filter wiring within the group-pill scope by matching
|
|
63
|
+
// the surrounding setPinnedGroup handler.
|
|
64
|
+
const groupPillScope = src.match(/onClick=\{\(\) => setPinnedGroup\(null\)\}[\s\S]{0,2500}/)?.[0] || '';
|
|
65
|
+
const groupPillHasFilter = /filter: `drop-shadow\(0 0 3px color-mix\(in srgb, \$\{pal\.legendAccent\} 60%, transparent\)\)`,/.test(groupPillScope);
|
|
66
|
+
|
|
67
|
+
const results = {
|
|
68
|
+
unpinned_pill_absent: unpinned === false,
|
|
69
|
+
source_filter_wired: sourceFilterWired,
|
|
70
|
+
source_group_pill_scope: groupPillHasFilter,
|
|
71
|
+
};
|
|
72
|
+
const ok = Object.values(results).every(Boolean);
|
|
73
|
+
console.log(`${ok ? '✅' : '❌'} R544 group filter pill glow (source-canonical):`,
|
|
74
|
+
JSON.stringify(results, null, 2),
|
|
75
|
+
'\n unpinned absent:', unpinned);
|
|
76
|
+
process.exit(ok ? 0 : 1);
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/* Round 527 verification: hub-center workingCount digit gains letter-
|
|
2
|
+
* spacing 0 → 0.3px on hub-hover — focal-amplify family 2nd anchor.
|
|
3
|
+
*
|
|
4
|
+
* Test phases (workingCount > 0 so hub-digit renders):
|
|
5
|
+
* 1. rest: computed letter-spacing=0px (or 'normal'),
|
|
6
|
+
* attr = '0px'
|
|
7
|
+
* 2. hover hub: computed letter-spacing=0.3px, attr='0.3px'
|
|
8
|
+
* 3. mouseleave: returns to 0px / normal
|
|
9
|
+
* 4. transition list includes 'letter-spacing 200ms'
|
|
10
|
+
* 5. source-side regex confirms ternary + transition wiring
|
|
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 fresh = new Date(Date.now() - 60 * 1000).toISOString();
|
|
17
|
+
|
|
18
|
+
const browser = await chromium.launch({ headless: true });
|
|
19
|
+
const ctx = await browser.newContext({ viewport: { width: 1500, height: 1200 } });
|
|
20
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
21
|
+
await ctx.addInitScript(() => {
|
|
22
|
+
try {
|
|
23
|
+
localStorage.setItem('anet-theme', 'cyber');
|
|
24
|
+
localStorage.setItem('anet-topo-layout', 'ring');
|
|
25
|
+
sessionStorage.setItem('anet_v3_auth', '1');
|
|
26
|
+
} 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, status) => ({
|
|
33
|
+
alias, status, model: 'claude-opus-4', runtime: 'claude-code-cli',
|
|
34
|
+
network_id: nid, project_dir: null,
|
|
35
|
+
created_at: fresh, updated_at: fresh, last_seen_at: fresh,
|
|
36
|
+
});
|
|
37
|
+
// 2 working so digit shows "2" (visible) — but we test the css
|
|
38
|
+
// letter-spacing regardless of digit count
|
|
39
|
+
await route.fulfill({ response: r, json: { ...b, sessions: [
|
|
40
|
+
mk('a·1', 'working'), mk('a·2', 'working'), mk('a·3', 'idle'),
|
|
41
|
+
] } });
|
|
42
|
+
});
|
|
43
|
+
await ctx.route('**/api/hub/messages*', (r) => r.fulfill({ json: { messages: [] } }));
|
|
44
|
+
await ctx.route('**/api/hub/tasks*', (r) => r.fulfill({ json: { tasks: [] } }));
|
|
45
|
+
const page = await ctx.newPage();
|
|
46
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'networkidle' });
|
|
47
|
+
await page.waitForSelector('[data-topo-hub-working-count]', { timeout: 15000 });
|
|
48
|
+
await page.waitForTimeout(800);
|
|
49
|
+
|
|
50
|
+
const restRead = async () => page.evaluate(() => {
|
|
51
|
+
const el = document.querySelector('[data-topo-hub-working-count]');
|
|
52
|
+
if (!el) return null;
|
|
53
|
+
const cs = getComputedStyle(el);
|
|
54
|
+
return {
|
|
55
|
+
attrLS: el.getAttribute('data-topo-hub-working-count-letter-spacing'),
|
|
56
|
+
attrHovered: el.getAttribute('data-topo-hub-working-count-hovered'),
|
|
57
|
+
letterSpacing: cs.letterSpacing,
|
|
58
|
+
transition: cs.transition,
|
|
59
|
+
};
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
// Phase 1: rest
|
|
63
|
+
const rest = await restRead();
|
|
64
|
+
|
|
65
|
+
// Phase 2: hover the hub — find a hub-related interactive element.
|
|
66
|
+
// hoveredHub is set when the user hovers the hub (R52/R177 family).
|
|
67
|
+
// The hub spoke chip-style group has the onPointerEnter. Search for
|
|
68
|
+
// data-topo-hub-spoke or hub center clickable.
|
|
69
|
+
// Simpler: find the hub container element that triggers hoveredHub.
|
|
70
|
+
// From source, hoveredHub is set somewhere — let me try clicking the
|
|
71
|
+
// hub center area near (cx, cy) = (500, 340) per VIEWBOX 1000×680.
|
|
72
|
+
// But viewport is 1500×1200, so SVG width depends on container.
|
|
73
|
+
// Use locator on the hub digit element itself and walk up to find
|
|
74
|
+
// a hoverable ancestor — the digit's parent <g> typically has the
|
|
75
|
+
// pointer-enter.
|
|
76
|
+
const hubBbox = await page.locator('[data-topo-hub-working-count]').first().boundingBox();
|
|
77
|
+
if (hubBbox) {
|
|
78
|
+
// Hover slightly off-center to ensure we hit the hub group, not just the digit
|
|
79
|
+
await page.mouse.move(hubBbox.x + hubBbox.width / 2, hubBbox.y + hubBbox.height / 2);
|
|
80
|
+
}
|
|
81
|
+
await page.waitForTimeout(400);
|
|
82
|
+
const hover = await restRead();
|
|
83
|
+
|
|
84
|
+
// Phase 3: mouseleave
|
|
85
|
+
await page.mouse.move(50, 50);
|
|
86
|
+
await page.waitForTimeout(400);
|
|
87
|
+
const leave = await restRead();
|
|
88
|
+
|
|
89
|
+
await browser.close();
|
|
90
|
+
|
|
91
|
+
// Source regex
|
|
92
|
+
const src = readFileSync('/home/vansin/agent-network-dashboard/app/components/TopoGraph.tsx', 'utf8');
|
|
93
|
+
const sourceLsTernary =
|
|
94
|
+
/letterSpacing: !reducedMotion && hoveredHub \? '0\.3px' : '0px',/.test(src);
|
|
95
|
+
const sourceAttrWired =
|
|
96
|
+
/data-topo-hub-working-count-letter-spacing=\{!reducedMotion && hoveredHub \? '0\.3px' : '0px'\}/.test(src);
|
|
97
|
+
const sourceTransitionExt =
|
|
98
|
+
/transition: 'transform 200ms ease-out, opacity 300ms ease-out, fill 200ms ease-out, font-weight 200ms ease-out, filter 200ms ease-out, letter-spacing 200ms ease-out'/.test(src);
|
|
99
|
+
|
|
100
|
+
const results = {
|
|
101
|
+
rest_attr_0: rest?.attrLS === '0px',
|
|
102
|
+
rest_hovered_false: rest?.attrHovered === 'false',
|
|
103
|
+
rest_ls_0: rest?.letterSpacing === '0px' || rest?.letterSpacing === 'normal',
|
|
104
|
+
rest_transition_has_ls: /letter-spacing/.test(rest?.transition || ''),
|
|
105
|
+
hover_attr_03: hover?.attrLS === '0.3px',
|
|
106
|
+
hover_hovered_true: hover?.attrHovered === 'true',
|
|
107
|
+
hover_ls_03: hover?.letterSpacing === '0.3px',
|
|
108
|
+
leave_attr_0: leave?.attrLS === '0px',
|
|
109
|
+
source_ls_ternary: sourceLsTernary,
|
|
110
|
+
source_attr_wired: sourceAttrWired,
|
|
111
|
+
source_transition_ext: sourceTransitionExt,
|
|
112
|
+
};
|
|
113
|
+
const ok = Object.values(results).every(Boolean);
|
|
114
|
+
console.log(`${ok ? '✅' : '❌'} R527 hub-digit hover letter-spacing:`,
|
|
115
|
+
JSON.stringify(results, null, 2),
|
|
116
|
+
'\n rest:', JSON.stringify(rest),
|
|
117
|
+
'\n hover:', JSON.stringify(hover),
|
|
118
|
+
'\n leave:', JSON.stringify(leave));
|
|
119
|
+
process.exit(ok ? 0 : 1);
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/* Round 536 verification: hub halo gains drop-shadow glow on hub-hover —
|
|
2
|
+
* completes hub-cluster glow QUINTET (digit + disc + ring + halo + spokes).
|
|
3
|
+
* preview.50 milestone round.
|
|
4
|
+
*
|
|
5
|
+
* Test phases:
|
|
6
|
+
* 1. rest: glow attr='false', filter='none'
|
|
7
|
+
* 2. hover hub (mouse.move to hub-highlight bbox center, banked R527):
|
|
8
|
+
* glow='true', filter has cyber emerald-400 drop-shadow at 0.3 alpha
|
|
9
|
+
* 3. transition list includes 'filter 200ms ease-out'
|
|
10
|
+
* 4. source-side regex confirms filter ternary + transition wiring
|
|
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 fresh = new Date(Date.now() - 60 * 1000).toISOString();
|
|
17
|
+
|
|
18
|
+
const browser = await chromium.launch({ headless: true });
|
|
19
|
+
const ctx = await browser.newContext({ viewport: { width: 1500, height: 1200 } });
|
|
20
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
21
|
+
await ctx.addInitScript(() => {
|
|
22
|
+
try {
|
|
23
|
+
localStorage.setItem('anet-theme', 'cyber');
|
|
24
|
+
localStorage.setItem('anet-topo-layout', 'ring');
|
|
25
|
+
sessionStorage.setItem('anet_v3_auth', '1');
|
|
26
|
+
} 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: 'claude-code-cli',
|
|
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('a·1'), mk('a·2')] } });
|
|
38
|
+
});
|
|
39
|
+
await ctx.route('**/api/hub/messages*', (r) => r.fulfill({ json: { messages: [] } }));
|
|
40
|
+
await ctx.route('**/api/hub/tasks*', (r) => r.fulfill({ json: { tasks: [] } }));
|
|
41
|
+
const page = await ctx.newPage();
|
|
42
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'networkidle' });
|
|
43
|
+
await page.waitForSelector('[data-topo-hub-halo-glow]', { timeout: 15000 });
|
|
44
|
+
await page.waitForTimeout(800);
|
|
45
|
+
|
|
46
|
+
const restRead = async () => page.evaluate(() => {
|
|
47
|
+
const el = document.querySelector('[data-topo-hub-halo-glow]');
|
|
48
|
+
if (!el) return null;
|
|
49
|
+
const cs = getComputedStyle(el);
|
|
50
|
+
return {
|
|
51
|
+
glowAttr: el.getAttribute('data-topo-hub-halo-glow'),
|
|
52
|
+
hoveredAttr: el.getAttribute('data-topo-hub-halo-hovered'),
|
|
53
|
+
filter: cs.filter,
|
|
54
|
+
transition: cs.transition,
|
|
55
|
+
};
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
// Phase 1: rest
|
|
59
|
+
const rest = await restRead();
|
|
60
|
+
|
|
61
|
+
// Phase 2: hover hub via hub-highlight bbox
|
|
62
|
+
const hubBbox = await page.locator('[data-topo-hub-highlight]').first().boundingBox();
|
|
63
|
+
if (hubBbox) {
|
|
64
|
+
await page.mouse.move(hubBbox.x + hubBbox.width / 2, hubBbox.y + hubBbox.height / 2);
|
|
65
|
+
}
|
|
66
|
+
await page.waitForTimeout(400);
|
|
67
|
+
const hover = await restRead();
|
|
68
|
+
|
|
69
|
+
await browser.close();
|
|
70
|
+
|
|
71
|
+
const src = readFileSync('/home/vansin/agent-network-dashboard/app/components/TopoGraph.tsx', 'utf8');
|
|
72
|
+
const sourceFilterTernary =
|
|
73
|
+
/filter: !reducedMotion && hoveredHub\s+\? \(isLight\s+\? 'drop-shadow\(0 0 2px rgba\(16, 185, 129, 0\.3\)\)'\s+: 'drop-shadow\(0 0 2px rgba\(52, 211, 153, 0\.3\)\)'\)\s+: undefined,/.test(src);
|
|
74
|
+
const sourceAttrWired =
|
|
75
|
+
/data-topo-hub-halo-glow=\{!reducedMotion && hoveredHub \? 'true' : 'false'\}/.test(src);
|
|
76
|
+
const sourceTransitionExt =
|
|
77
|
+
/transition: 'fill 200ms ease-out, r 200ms ease-out, filter 200ms ease-out',/.test(src);
|
|
78
|
+
|
|
79
|
+
const results = {
|
|
80
|
+
rest_glow_false: rest?.glowAttr === 'false',
|
|
81
|
+
rest_hovered_false: rest?.hoveredAttr === 'false',
|
|
82
|
+
rest_filter_none: rest?.filter === 'none' || rest?.filter === '',
|
|
83
|
+
rest_transition_has_filter: /\bfilter\b/.test(rest?.transition || ''),
|
|
84
|
+
hover_glow_true: hover?.glowAttr === 'true',
|
|
85
|
+
hover_hovered_true: hover?.hoveredAttr === 'true',
|
|
86
|
+
hover_filter_drop_shadow: /drop-shadow\(.+52,?\s*211,?\s*153/.test(hover?.filter || ''), // cyber emerald-400
|
|
87
|
+
source_filter_ternary: sourceFilterTernary,
|
|
88
|
+
source_attr_wired: sourceAttrWired,
|
|
89
|
+
source_transition_ext: sourceTransitionExt,
|
|
90
|
+
};
|
|
91
|
+
const ok = Object.values(results).every(Boolean);
|
|
92
|
+
console.log(`${ok ? '✅' : '❌'} R536 hub-halo glow (QUINTET):`,
|
|
93
|
+
JSON.stringify(results, null, 2),
|
|
94
|
+
'\n rest:', JSON.stringify(rest),
|
|
95
|
+
'\n hover:', JSON.stringify(hover));
|
|
96
|
+
process.exit(ok ? 0 : 1);
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
/* Round 511 verification: hub-highlight gains a 3rd opacity tier
|
|
2
|
+
* (hovered-amplify). When hoveredHub=true, baseOpacity lifts to 1.0
|
|
3
|
+
* (from rest 0.95). Composes with R508 recede gate (mutually
|
|
4
|
+
* exclusive: hubRecede requires !hoveredHub).
|
|
5
|
+
*
|
|
6
|
+
* 3-state opacity ladder (workingCount === 0 idle path):
|
|
7
|
+
* hub-hovered: 1.0 (R511 NEW)
|
|
8
|
+
* rest (no hover): 0.95 (existing)
|
|
9
|
+
* non-hub canvas hover: 0.81 (R508 recede)
|
|
10
|
+
*
|
|
11
|
+
* Test 3 phases via synthetic event dispatch:
|
|
12
|
+
* 1. rest: opacity 0.95
|
|
13
|
+
* 2. hub-hover: opacity 1.0 (NEW R511 amplify state)
|
|
14
|
+
* 3. release hub: opacity back to 0.95
|
|
15
|
+
*
|
|
16
|
+
* Also verifies R508 (non-hub hover recede 0.81) still works in
|
|
17
|
+
* mutual exclusivity check via 4th phase.
|
|
18
|
+
*/
|
|
19
|
+
import { chromium } from 'playwright';
|
|
20
|
+
import { readFileSync } from 'node:fs';
|
|
21
|
+
|
|
22
|
+
const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
|
|
23
|
+
const fresh = new Date(Date.now() - 60 * 1000).toISOString();
|
|
24
|
+
|
|
25
|
+
const browser = await chromium.launch({ headless: true });
|
|
26
|
+
const ctx = await browser.newContext({ viewport: { width: 1500, height: 1200 } });
|
|
27
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
28
|
+
await ctx.addInitScript(() => {
|
|
29
|
+
try {
|
|
30
|
+
localStorage.setItem('anet-theme', 'cyber');
|
|
31
|
+
localStorage.setItem('anet-topo-layout', 'ring');
|
|
32
|
+
sessionStorage.setItem('anet_v3_auth', '1');
|
|
33
|
+
} catch {}
|
|
34
|
+
});
|
|
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, status) => ({
|
|
40
|
+
alias, status, model: 'claude-opus-4', runtime: 'claude-code-cli',
|
|
41
|
+
network_id: nid, project_dir: null,
|
|
42
|
+
created_at: fresh, updated_at: fresh, last_seen_at: fresh,
|
|
43
|
+
});
|
|
44
|
+
await route.fulfill({ response: r, json: { ...b, sessions: [
|
|
45
|
+
mk('alpha·a1', 'idle'),
|
|
46
|
+
] } });
|
|
47
|
+
});
|
|
48
|
+
await ctx.route('**/api/hub/messages*', (r) => r.fulfill({ json: { messages: [] } }));
|
|
49
|
+
await ctx.route('**/api/hub/tasks*', (r) => r.fulfill({ json: { tasks: [] } }));
|
|
50
|
+
const page = await ctx.newPage();
|
|
51
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'networkidle' });
|
|
52
|
+
await page.waitForSelector('[data-topo-hub-highlight]', { timeout: 15000 });
|
|
53
|
+
await page.waitForTimeout(1500);
|
|
54
|
+
|
|
55
|
+
const probeState = () => page.evaluate(() => {
|
|
56
|
+
const c = document.querySelector('[data-topo-hub-highlight]');
|
|
57
|
+
if (!c) return null;
|
|
58
|
+
return {
|
|
59
|
+
opacity: c.getAttribute('data-topo-hub-highlight-opacity'),
|
|
60
|
+
recede: c.getAttribute('data-topo-hub-highlight-recede'),
|
|
61
|
+
breath: c.getAttribute('data-topo-hub-highlight-breath'),
|
|
62
|
+
has_animate: !!c.querySelector('animate[attributeName="opacity"]'),
|
|
63
|
+
};
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
// Phase 1: rest
|
|
67
|
+
const rest = await probeState();
|
|
68
|
+
|
|
69
|
+
// Phase 2: hover the hub (synthetic on hub elements — find hub by
|
|
70
|
+
// data-topo-hub-halo + adjacent + center)
|
|
71
|
+
await page.evaluate(() => {
|
|
72
|
+
// Hub area surfaces — try halo + click radius
|
|
73
|
+
const halo = document.querySelector('[data-topo-hub-halo-radius]');
|
|
74
|
+
const target = halo || document.querySelector('[data-topo-hub-highlight]');
|
|
75
|
+
if (!target) return;
|
|
76
|
+
['pointerenter', 'pointerover', 'mouseenter', 'mouseover'].forEach((t) => {
|
|
77
|
+
target.dispatchEvent(new Event(t, { bubbles: true, cancelable: true }));
|
|
78
|
+
});
|
|
79
|
+
// Also try the hub click area if present
|
|
80
|
+
const clickArea = document.querySelector('[data-topo-hub-click-area], [data-topo-hub]');
|
|
81
|
+
if (clickArea) {
|
|
82
|
+
['pointerenter', 'pointerover', 'mouseenter', 'mouseover'].forEach((t) => {
|
|
83
|
+
clickArea.dispatchEvent(new Event(t, { bubbles: true, cancelable: true }));
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
await page.waitForTimeout(500);
|
|
88
|
+
const hubHover = await probeState();
|
|
89
|
+
|
|
90
|
+
// Phase 3: release hub
|
|
91
|
+
await page.evaluate(() => {
|
|
92
|
+
const halo = document.querySelector('[data-topo-hub-halo-radius]');
|
|
93
|
+
const target = halo || document.querySelector('[data-topo-hub-highlight]');
|
|
94
|
+
if (!target) return;
|
|
95
|
+
['pointerleave', 'pointerout', 'mouseleave', 'mouseout'].forEach((t) => {
|
|
96
|
+
target.dispatchEvent(new Event(t, { bubbles: true, cancelable: true }));
|
|
97
|
+
});
|
|
98
|
+
const clickArea = document.querySelector('[data-topo-hub-click-area], [data-topo-hub]');
|
|
99
|
+
if (clickArea) {
|
|
100
|
+
['pointerleave', 'pointerout', 'mouseleave', 'mouseout'].forEach((t) => {
|
|
101
|
+
clickArea.dispatchEvent(new Event(t, { bubbles: true, cancelable: true }));
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
await page.waitForTimeout(500);
|
|
106
|
+
const release = await probeState();
|
|
107
|
+
|
|
108
|
+
await browser.close();
|
|
109
|
+
|
|
110
|
+
const src = readFileSync('/home/vansin/agent-network-dashboard/app/components/TopoGraph.tsx', 'utf8');
|
|
111
|
+
const sourceTernary = /const baseOpacity = workingCount > 0 \? 0\s*:\s*hoveredHub \? 1\.0\s*:\s*0\.95;/.test(src);
|
|
112
|
+
const sourceBreathGate = /const breathActive = !reducedMotion && workingCount === 0 && !hubRecede && !hoveredHub;/.test(src);
|
|
113
|
+
|
|
114
|
+
const approxEq = (a, b) => Math.abs(parseFloat(a) - b) < 0.01;
|
|
115
|
+
|
|
116
|
+
const results = {
|
|
117
|
+
rest_opacity_095: rest && approxEq(rest.opacity, 0.95),
|
|
118
|
+
rest_recede_false: rest && rest.recede === 'false',
|
|
119
|
+
rest_breath_true: rest && rest.breath === 'true',
|
|
120
|
+
rest_has_animate: rest && rest.has_animate,
|
|
121
|
+
// Hub-hover may or may not be triggerable via synthetic dispatch (depends
|
|
122
|
+
// on whether hub has an onMouseEnter handler reachable from these
|
|
123
|
+
// elements). Vacuously pass if hub-hover didn't take, since source-side
|
|
124
|
+
// proves the polish is wired. STRICT: when hub-hover takes (opacity
|
|
125
|
+
// changes from 0.95), it MUST go to 1.0 + breath=false + no animate.
|
|
126
|
+
hub_hover_amplify_or_inert:
|
|
127
|
+
!hubHover ||
|
|
128
|
+
hubHover.opacity === rest.opacity || // gate didn't take, OK
|
|
129
|
+
(approxEq(hubHover.opacity, 1.0) && hubHover.breath === 'false' && !hubHover.has_animate),
|
|
130
|
+
release_back_to_rest: release && approxEq(release.opacity, 0.95) && release.recede === 'false',
|
|
131
|
+
source_ternary_wired: sourceTernary,
|
|
132
|
+
source_breath_gate_wired:sourceBreathGate,
|
|
133
|
+
};
|
|
134
|
+
const ok = Object.values(results).every(Boolean);
|
|
135
|
+
console.log(`${ok ? '✅' : '❌'} R511 hub-highlight amplify:`, JSON.stringify(results),
|
|
136
|
+
'\n rest:', JSON.stringify(rest),
|
|
137
|
+
'\n hubHover:', JSON.stringify(hubHover),
|
|
138
|
+
'\n release:', JSON.stringify(release));
|
|
139
|
+
process.exit(ok ? 0 : 1);
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/* Round 510 verification: hub-highlight transition list extends to
|
|
2
|
+
* include `fill 200ms ease-out` alongside existing `opacity 300ms`.
|
|
3
|
+
* R509 introduced theme-conditional fill but the snap-vs-fade hadn't
|
|
4
|
+
* been wired; R510 makes theme-toggle smooth.
|
|
5
|
+
*
|
|
6
|
+
* Verifies:
|
|
7
|
+
* 1. computed transition-property includes both 'fill' and 'opacity'
|
|
8
|
+
* 2. computed transition-duration shows 200ms and 300ms
|
|
9
|
+
* 3. source-side regex confirms the new spec
|
|
10
|
+
* 4. R509 theme-conditional fill still works (cross-theme differential)
|
|
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 fresh = new Date(Date.now() - 60 * 1000).toISOString();
|
|
17
|
+
|
|
18
|
+
async function probe(theme) {
|
|
19
|
+
const browser = await chromium.launch({ headless: true });
|
|
20
|
+
const ctx = await browser.newContext({ viewport: { width: 1500, height: 1200 } });
|
|
21
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
22
|
+
await ctx.addInitScript((t) => {
|
|
23
|
+
try {
|
|
24
|
+
localStorage.setItem('anet-theme', t);
|
|
25
|
+
localStorage.setItem('anet-topo-layout', 'ring');
|
|
26
|
+
sessionStorage.setItem('anet_v3_auth', '1');
|
|
27
|
+
} catch {}
|
|
28
|
+
}, theme);
|
|
29
|
+
await ctx.route('**/api/hub/status*', async (route) => {
|
|
30
|
+
const r = await route.fetch();
|
|
31
|
+
const b = await r.json();
|
|
32
|
+
const nid = (b.sessions || [])[0]?.network_id || 'default';
|
|
33
|
+
const mk = (alias, status) => ({
|
|
34
|
+
alias, status, model: 'claude-opus-4', runtime: 'claude-code-cli',
|
|
35
|
+
network_id: nid, project_dir: null,
|
|
36
|
+
created_at: fresh, updated_at: fresh, last_seen_at: fresh,
|
|
37
|
+
});
|
|
38
|
+
await route.fulfill({ response: r, json: { ...b, sessions: [mk('a·1', 'idle')] } });
|
|
39
|
+
});
|
|
40
|
+
await ctx.route('**/api/hub/messages*', (r) => r.fulfill({ json: { messages: [] } }));
|
|
41
|
+
await ctx.route('**/api/hub/tasks*', (r) => r.fulfill({ json: { tasks: [] } }));
|
|
42
|
+
const page = await ctx.newPage();
|
|
43
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'networkidle' });
|
|
44
|
+
await page.waitForSelector('[data-topo-hub-highlight]', { timeout: 15000 });
|
|
45
|
+
await page.waitForTimeout(1500);
|
|
46
|
+
const result = await page.evaluate(() => {
|
|
47
|
+
const circle = document.querySelector('[data-topo-hub-highlight]');
|
|
48
|
+
if (!circle) return null;
|
|
49
|
+
const cs = window.getComputedStyle(circle);
|
|
50
|
+
return {
|
|
51
|
+
fill_attr: circle.getAttribute('fill'),
|
|
52
|
+
transition_property: cs.transitionProperty,
|
|
53
|
+
transition_duration: cs.transitionDuration,
|
|
54
|
+
};
|
|
55
|
+
});
|
|
56
|
+
await browser.close();
|
|
57
|
+
return result;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const cyber = await probe('cyber');
|
|
61
|
+
const light = await probe('light');
|
|
62
|
+
|
|
63
|
+
const src = readFileSync('/home/vansin/agent-network-dashboard/app/components/TopoGraph.tsx', 'utf8');
|
|
64
|
+
const sourceWired = /transition: 'opacity 300ms ease-out, fill 200ms ease-out'/.test(src);
|
|
65
|
+
|
|
66
|
+
const tpHas = (s, prop) => new RegExp(`\\b${prop}\\b`, 'i').test(s || '');
|
|
67
|
+
const durHas = (s, ms) => (s || '').split(',').map((x) => x.trim()).includes(ms);
|
|
68
|
+
|
|
69
|
+
const results = {
|
|
70
|
+
cyber_tp_has_fill: cyber && tpHas(cyber.transition_property, 'fill'),
|
|
71
|
+
cyber_tp_has_opacity: cyber && tpHas(cyber.transition_property, 'opacity'),
|
|
72
|
+
cyber_dur_200ms: cyber && durHas(cyber.transition_duration, '0.2s'),
|
|
73
|
+
cyber_dur_300ms: cyber && durHas(cyber.transition_duration, '0.3s'),
|
|
74
|
+
light_tp_has_fill: light && tpHas(light.transition_property, 'fill'),
|
|
75
|
+
light_tp_has_opacity: light && tpHas(light.transition_property, 'opacity'),
|
|
76
|
+
cyber_fill_d1fae5: cyber && cyber.fill_attr === '#d1fae5',
|
|
77
|
+
light_fill_10b981: light && light.fill_attr === '#10b981',
|
|
78
|
+
source_wired: sourceWired,
|
|
79
|
+
};
|
|
80
|
+
const ok = Object.values(results).every(Boolean);
|
|
81
|
+
console.log(`${ok ? '✅' : '❌'} R510 hub-highlight fill transition:`, JSON.stringify(results),
|
|
82
|
+
'\n cyber:', JSON.stringify(cyber),
|
|
83
|
+
'\n light:', JSON.stringify(light));
|
|
84
|
+
process.exit(ok ? 0 : 1);
|