@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,139 @@
|
|
|
1
|
+
/* Round 562 verification: legend-row swatch lifts r + drop-shadow
|
|
2
|
+
* when operator hovers a node alias whose status matches the row's
|
|
3
|
+
* tier. 5th anchor in inspection-overrides-encoding family.
|
|
4
|
+
*
|
|
5
|
+
* Mock: alpha·1 (working) + alpha·2 (idle) + alpha·3 (offline).
|
|
6
|
+
* Hover alpha·1 → 'working' legend swatch should lift; idle +
|
|
7
|
+
* offline swatches stay at rest.
|
|
8
|
+
*
|
|
9
|
+
* Test phases:
|
|
10
|
+
* 1. rest: all 3 swatches r=6, filter=none, attr='false'
|
|
11
|
+
* 2. hover alpha·1 (working) → working swatch r=7, filter contains
|
|
12
|
+
* drop-shadow with green hex; idle + offline unchanged
|
|
13
|
+
* 3. hover alpha·2 (idle) → idle swatch lifts, others rest
|
|
14
|
+
* 4. hover alpha·3 (offline) → offline swatch lifts, others rest
|
|
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', 'ring');
|
|
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) => ({
|
|
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
|
+
await route.fulfill({ response: r, json: { ...b, sessions: [
|
|
43
|
+
mk('alpha·1', 'working'),
|
|
44
|
+
mk('alpha·2', 'idle'),
|
|
45
|
+
mk('alpha·3', 'offline'),
|
|
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-legend-swatch="working"]', { timeout: 15000 });
|
|
53
|
+
await page.waitForTimeout(500);
|
|
54
|
+
|
|
55
|
+
const probeSwatch = (key) => page.evaluate((k) => {
|
|
56
|
+
const el = document.querySelector(`[data-legend-swatch="${k}"]`);
|
|
57
|
+
if (!el) return null;
|
|
58
|
+
const cs = getComputedStyle(el);
|
|
59
|
+
return {
|
|
60
|
+
r: cs.r,
|
|
61
|
+
filter: cs.filter,
|
|
62
|
+
state: el.getAttribute('data-legend-swatch-state'),
|
|
63
|
+
matching: el.getAttribute('data-legend-swatch-member-alias-matching') === 'true',
|
|
64
|
+
glow: el.getAttribute('data-legend-swatch-glow') === 'true',
|
|
65
|
+
};
|
|
66
|
+
}, key);
|
|
67
|
+
|
|
68
|
+
const restWorking = await probeSwatch('working');
|
|
69
|
+
const restIdle = await probeSwatch('idle');
|
|
70
|
+
const restOffline = await probeSwatch('offline');
|
|
71
|
+
|
|
72
|
+
// Hover working node
|
|
73
|
+
await page.hover('g[data-node="alpha·1"]');
|
|
74
|
+
await page.waitForTimeout(400);
|
|
75
|
+
const hoverWorkingWorking = await probeSwatch('working');
|
|
76
|
+
const hoverWorkingIdle = await probeSwatch('idle');
|
|
77
|
+
const hoverWorkingOffline = await probeSwatch('offline');
|
|
78
|
+
|
|
79
|
+
// Move away to reset
|
|
80
|
+
await page.mouse.move(0, 0);
|
|
81
|
+
await page.waitForTimeout(300);
|
|
82
|
+
|
|
83
|
+
// Hover idle node
|
|
84
|
+
await page.hover('g[data-node="alpha·2"]');
|
|
85
|
+
await page.waitForTimeout(400);
|
|
86
|
+
const hoverIdleIdle = await probeSwatch('idle');
|
|
87
|
+
|
|
88
|
+
// Move away and hover offline node
|
|
89
|
+
await page.mouse.move(0, 0);
|
|
90
|
+
await page.waitForTimeout(300);
|
|
91
|
+
await page.hover('g[data-node="alpha·3"]');
|
|
92
|
+
await page.waitForTimeout(400);
|
|
93
|
+
const hoverOfflineOffline = await probeSwatch('offline');
|
|
94
|
+
|
|
95
|
+
await browser.close();
|
|
96
|
+
|
|
97
|
+
const src = readFileSync('/home/vansin/agent-network-dashboard/app/components/TopoGraph.tsx', 'utf8');
|
|
98
|
+
const sourceFlag = /const isMemberAliasMatching = hoveredAliasRowKey === row\.key;/.test(src);
|
|
99
|
+
const sourceLifted = /const isSwatchLifted = isLifted \|\| isMemberAliasMatching;/.test(src);
|
|
100
|
+
const sourceR = /r: isSwatchLifted \? '7px' : '6px'/.test(src);
|
|
101
|
+
const sourceFilter = /filter: isSwatchLifted/.test(src);
|
|
102
|
+
const sourceAttr = /data-legend-swatch-member-alias-matching=/.test(src);
|
|
103
|
+
|
|
104
|
+
const results = {
|
|
105
|
+
// Rest state — all swatches r=6, no glow
|
|
106
|
+
rest_working_r_6: restWorking?.r === '6px',
|
|
107
|
+
rest_working_filter_none: restWorking?.filter === 'none',
|
|
108
|
+
rest_working_matching_false: restWorking?.matching === false,
|
|
109
|
+
rest_idle_r_6: restIdle?.r === '6px',
|
|
110
|
+
rest_offline_r_6: restOffline?.r === '6px',
|
|
111
|
+
// Hover working node → working swatch lifts; idle + offline stay
|
|
112
|
+
hover_working_w_r_7: hoverWorkingWorking?.r === '7px',
|
|
113
|
+
hover_working_w_matching: hoverWorkingWorking?.matching === true,
|
|
114
|
+
hover_working_w_glow: /drop-shadow\(/.test(hoverWorkingWorking?.filter || ''),
|
|
115
|
+
hover_working_i_r_6: hoverWorkingIdle?.r === '6px',
|
|
116
|
+
hover_working_o_r_6: hoverWorkingOffline?.r === '6px',
|
|
117
|
+
// Hover idle node → idle swatch lifts
|
|
118
|
+
hover_idle_i_r_7: hoverIdleIdle?.r === '7px',
|
|
119
|
+
hover_idle_i_matching: hoverIdleIdle?.matching === true,
|
|
120
|
+
// Hover offline node → offline swatch lifts
|
|
121
|
+
hover_offline_o_r_7: hoverOfflineOffline?.r === '7px',
|
|
122
|
+
hover_offline_o_matching: hoverOfflineOffline?.matching === true,
|
|
123
|
+
// Source
|
|
124
|
+
source_flag: sourceFlag,
|
|
125
|
+
source_lifted: sourceLifted,
|
|
126
|
+
source_r: sourceR,
|
|
127
|
+
source_filter: sourceFilter,
|
|
128
|
+
source_attr: sourceAttr,
|
|
129
|
+
};
|
|
130
|
+
const ok = Object.values(results).every(Boolean);
|
|
131
|
+
console.log(`${ok ? '✅' : '❌'} R562 legend-swatch inspection-overrides-encoding (5th anchor):`,
|
|
132
|
+
JSON.stringify(results, null, 2),
|
|
133
|
+
'\n rest working:', JSON.stringify(restWorking),
|
|
134
|
+
'\n rest idle:', JSON.stringify(restIdle),
|
|
135
|
+
'\n rest offline:', JSON.stringify(restOffline),
|
|
136
|
+
'\n hover alpha·1 (working) → working:', JSON.stringify(hoverWorkingWorking),
|
|
137
|
+
'\n hover alpha·2 (idle) → idle:', JSON.stringify(hoverIdleIdle),
|
|
138
|
+
'\n hover alpha·3 (offline) → offline:', JSON.stringify(hoverOfflineOffline));
|
|
139
|
+
process.exit(ok ? 0 : 1);
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/* Round 540 verification: minimap viewport gains drop-shadow glow on
|
|
2
|
+
* hover, with hover precedence over R481 zoom-state glow. 2-tier alpha
|
|
3
|
+
* ladder (hover 99 / zoom 80).
|
|
4
|
+
*
|
|
5
|
+
* Test strategy: minimap is only visible when canvas is zoomed or
|
|
6
|
+
* panned (default view returns null). Trigger zoom via the chrome
|
|
7
|
+
* zoom-in button, verify zoom-state glow renders, then hover the
|
|
8
|
+
* minimap container and verify hover precedence + alpha distinction
|
|
9
|
+
* via the data-attr. Source regex covers the ternary wiring.
|
|
10
|
+
*
|
|
11
|
+
* Test phases:
|
|
12
|
+
* 1. trigger zoom > 1.5 via chrome zoom-in clicks
|
|
13
|
+
* 2. minimap visible, viewport glow attr = 'zoom'
|
|
14
|
+
* 3. hover minimap container: viewport glow = 'hover'
|
|
15
|
+
* 4. source-side regex confirms 3-value attr + filter ternary
|
|
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', 'ring');
|
|
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) => ({
|
|
38
|
+
alias, status: 'idle', 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
|
+
await route.fulfill({ response: r, json: { ...b, sessions: [
|
|
43
|
+
mk('a·1'), mk('a·2'), mk('a·3'),
|
|
44
|
+
] } });
|
|
45
|
+
});
|
|
46
|
+
await ctx.route('**/api/hub/messages*', (r) => r.fulfill({ json: { messages: [] } }));
|
|
47
|
+
await ctx.route('**/api/hub/tasks*', (r) => r.fulfill({ json: { tasks: [] } }));
|
|
48
|
+
const page = await ctx.newPage();
|
|
49
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'networkidle' });
|
|
50
|
+
await page.waitForSelector('[data-topo-chrome-zoom-in]', { timeout: 15000 });
|
|
51
|
+
await page.waitForTimeout(500);
|
|
52
|
+
|
|
53
|
+
// Phase 1: click zoom-in until zoom > 1.5 (1.2^3 = 1.728)
|
|
54
|
+
for (let i = 0; i < 3; i++) {
|
|
55
|
+
await page.click('[data-topo-chrome-zoom-in]');
|
|
56
|
+
await page.waitForTimeout(150);
|
|
57
|
+
}
|
|
58
|
+
await page.waitForTimeout(500);
|
|
59
|
+
|
|
60
|
+
// Minimap should now be visible
|
|
61
|
+
await page.waitForSelector('[data-topo-minimap-viewport]', { timeout: 5000 });
|
|
62
|
+
|
|
63
|
+
// Phase 2: zoom-state read
|
|
64
|
+
const zoomState = await page.evaluate(() => {
|
|
65
|
+
const el = document.querySelector('[data-topo-minimap-viewport]');
|
|
66
|
+
if (!el) return null;
|
|
67
|
+
const cs = getComputedStyle(el);
|
|
68
|
+
return {
|
|
69
|
+
glow: el.getAttribute('data-topo-minimap-viewport-glow'),
|
|
70
|
+
filter: cs.filter,
|
|
71
|
+
};
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
// Phase 3: hover minimap container
|
|
75
|
+
await page.hover('[data-topo-minimap]');
|
|
76
|
+
await page.waitForTimeout(400);
|
|
77
|
+
const hoverState = await page.evaluate(() => {
|
|
78
|
+
const el = document.querySelector('[data-topo-minimap-viewport]');
|
|
79
|
+
if (!el) return null;
|
|
80
|
+
const cs = getComputedStyle(el);
|
|
81
|
+
return {
|
|
82
|
+
glow: el.getAttribute('data-topo-minimap-viewport-glow'),
|
|
83
|
+
filter: cs.filter,
|
|
84
|
+
};
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
await browser.close();
|
|
88
|
+
|
|
89
|
+
// Source regex
|
|
90
|
+
const src = readFileSync('/home/vansin/agent-network-dashboard/app/components/TopoGraph.tsx', 'utf8');
|
|
91
|
+
const sourceFilterTernary =
|
|
92
|
+
/filter: hoveredMinimap\s+\? `drop-shadow\(0 0 2px \$\{pal\.legendAccent\}99\)`\s+: view\.zoom > 1\.5\s+\? `drop-shadow\(0 0 2px \$\{pal\.legendAccent\}80\)`\s+: undefined,/.test(src);
|
|
93
|
+
const sourceAttrTernary =
|
|
94
|
+
/data-topo-minimap-viewport-glow=\{hoveredMinimap \? 'hover' : view\.zoom > 1\.5 \? 'zoom' : 'false'\}/.test(src);
|
|
95
|
+
|
|
96
|
+
const results = {
|
|
97
|
+
zoom_glow_zoom: zoomState?.glow === 'zoom',
|
|
98
|
+
zoom_filter_drop_shadow: /drop-shadow/.test(zoomState?.filter || ''),
|
|
99
|
+
hover_glow_hover: hoverState?.glow === 'hover',
|
|
100
|
+
hover_filter_drop_shadow: /drop-shadow/.test(hoverState?.filter || ''),
|
|
101
|
+
source_filter_ternary: sourceFilterTernary,
|
|
102
|
+
source_attr_ternary: sourceAttrTernary,
|
|
103
|
+
};
|
|
104
|
+
const ok = Object.values(results).every(Boolean);
|
|
105
|
+
console.log(`${ok ? '✅' : '❌'} R540 minimap viewport hover-glow:`,
|
|
106
|
+
JSON.stringify(results, null, 2),
|
|
107
|
+
'\n zoom:', JSON.stringify(zoomState),
|
|
108
|
+
'\n hover:', JSON.stringify(hoverState));
|
|
109
|
+
process.exit(ok ? 0 : 1);
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/* Round 564 verification: per-node alias text gains stacked filter
|
|
2
|
+
* brightness(1.15) on top of R500 drop-shadow on hover. Mirrors
|
|
3
|
+
* R542 pressure-seg pattern.
|
|
4
|
+
*
|
|
5
|
+
* Test phases:
|
|
6
|
+
* 1. rest: filter = 'none', brightness-attr = '1'
|
|
7
|
+
* 2. hover: filter contains BOTH drop-shadow AND brightness(1.15);
|
|
8
|
+
* brightness-attr = '1.15'
|
|
9
|
+
* 3. source-side regex confirms stacked filter expression
|
|
10
|
+
*/
|
|
11
|
+
import { chromium } from 'playwright';
|
|
12
|
+
import { readFileSync } from 'node:fs';
|
|
13
|
+
|
|
14
|
+
const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
|
|
15
|
+
const fresh = new Date(Date.now() - 60 * 1000).toISOString();
|
|
16
|
+
|
|
17
|
+
const browser = await chromium.launch({ headless: true });
|
|
18
|
+
const ctx = await browser.newContext({ viewport: { width: 1500, height: 1200 } });
|
|
19
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
20
|
+
await ctx.addInitScript(() => {
|
|
21
|
+
try {
|
|
22
|
+
localStorage.setItem('anet-theme', 'cyber');
|
|
23
|
+
localStorage.setItem('anet-topo-layout', 'ring');
|
|
24
|
+
sessionStorage.setItem('anet_v3_auth', '1');
|
|
25
|
+
} catch {}
|
|
26
|
+
});
|
|
27
|
+
await ctx.route('**/api/hub/status*', async (route) => {
|
|
28
|
+
const r = await route.fetch();
|
|
29
|
+
const b = await r.json();
|
|
30
|
+
const nid = (b.sessions || [])[0]?.network_id || 'default';
|
|
31
|
+
const mk = (alias) => ({
|
|
32
|
+
alias, status: 'working', model: 'claude-opus-4', runtime: 'claude-code-cli',
|
|
33
|
+
network_id: nid, project_dir: null,
|
|
34
|
+
created_at: fresh, updated_at: fresh, last_seen_at: fresh,
|
|
35
|
+
});
|
|
36
|
+
await route.fulfill({ response: r, json: { ...b, sessions: [mk('a·1'), mk('a·2')] } });
|
|
37
|
+
});
|
|
38
|
+
await ctx.route('**/api/hub/messages*', (r) => r.fulfill({ json: { messages: [] } }));
|
|
39
|
+
await ctx.route('**/api/hub/tasks*', (r) => r.fulfill({ json: { tasks: [] } }));
|
|
40
|
+
const page = await ctx.newPage();
|
|
41
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'networkidle' });
|
|
42
|
+
await page.waitForSelector('[data-node-alias-text="a·1"]', { timeout: 15000 });
|
|
43
|
+
await page.waitForTimeout(500);
|
|
44
|
+
|
|
45
|
+
const aliasSel = '[data-node-alias-text="a·1"]';
|
|
46
|
+
const probe = () => page.evaluate((s) => {
|
|
47
|
+
const el = document.querySelector(s);
|
|
48
|
+
if (!el) return null;
|
|
49
|
+
const cs = getComputedStyle(el);
|
|
50
|
+
return {
|
|
51
|
+
filter: cs.filter,
|
|
52
|
+
glowAttr: el.getAttribute('data-node-alias-glow'),
|
|
53
|
+
brightnessAttr: el.getAttribute('data-node-alias-brightness'),
|
|
54
|
+
};
|
|
55
|
+
}, aliasSel);
|
|
56
|
+
|
|
57
|
+
const rest = await probe();
|
|
58
|
+
await page.hover('g[data-node="a·1"]');
|
|
59
|
+
await page.waitForTimeout(400);
|
|
60
|
+
const hover = await probe();
|
|
61
|
+
|
|
62
|
+
await browser.close();
|
|
63
|
+
|
|
64
|
+
const src = readFileSync('/home/vansin/agent-network-dashboard/app/components/TopoGraph.tsx', 'utf8');
|
|
65
|
+
const sourceFilter = /filter: !reducedMotion && hoveredAlias === session\.alias\s*\?\s*`drop-shadow\(0 0 2px \$\{status\.text\}80\) brightness\(1\.15\)`/.test(src);
|
|
66
|
+
const sourceAttr = /data-node-alias-brightness=\{!reducedMotion && hoveredAlias === session\.alias \? '1\.15' : '1'\}/.test(src);
|
|
67
|
+
|
|
68
|
+
const results = {
|
|
69
|
+
rest_filter_none: rest?.filter === 'none',
|
|
70
|
+
rest_glow_false: rest?.glowAttr === 'false',
|
|
71
|
+
rest_brightness_1: rest?.brightnessAttr === '1',
|
|
72
|
+
hover_filter_has_dropshadow: /drop-shadow\(/.test(hover?.filter || ''),
|
|
73
|
+
hover_filter_has_brightness: /brightness\(1\.15\)/.test(hover?.filter || ''),
|
|
74
|
+
hover_glow_true: hover?.glowAttr === 'true',
|
|
75
|
+
hover_brightness_1_15: hover?.brightnessAttr === '1.15',
|
|
76
|
+
source_filter: sourceFilter,
|
|
77
|
+
source_attr: sourceAttr,
|
|
78
|
+
};
|
|
79
|
+
const ok = Object.values(results).every(Boolean);
|
|
80
|
+
console.log(`${ok ? '✅' : '❌'} R564 per-node alias text brightness(1.15) stacked on R500 drop-shadow:`,
|
|
81
|
+
JSON.stringify(results, null, 2),
|
|
82
|
+
`\n rest: ${JSON.stringify(rest)}`,
|
|
83
|
+
`\n hover: ${JSON.stringify(hover)}`);
|
|
84
|
+
process.exit(ok ? 0 : 1);
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/* Round 521 verification: chrome nodeSize S/M/L inactive variant gains
|
|
2
|
+
* hover-fw preview — fw 400 (default) → 500 (font-medium, matches active
|
|
3
|
+
* variant). Extends R270 hover-preview idiom to the typography axis.
|
|
4
|
+
*
|
|
5
|
+
* Test phases:
|
|
6
|
+
* 1. inactive rest: fontWeight = 400, data-attr = '500' (preview target)
|
|
7
|
+
* 2. inactive hover: fontWeight = 500 (preview lands at active fw)
|
|
8
|
+
* 3. active rest: fontWeight = 500 (existing font-medium class)
|
|
9
|
+
* 4. source-side regex confirms hover:font-medium class + attr wiring
|
|
10
|
+
*/
|
|
11
|
+
import { chromium } from 'playwright';
|
|
12
|
+
import { readFileSync } from 'node:fs';
|
|
13
|
+
|
|
14
|
+
const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
|
|
15
|
+
const fresh = new Date(Date.now() - 60 * 1000).toISOString();
|
|
16
|
+
|
|
17
|
+
const browser = await chromium.launch({ headless: true });
|
|
18
|
+
const ctx = await browser.newContext({ viewport: { width: 1500, height: 1200 } });
|
|
19
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
20
|
+
await ctx.addInitScript(() => {
|
|
21
|
+
try {
|
|
22
|
+
localStorage.setItem('anet-theme', 'cyber');
|
|
23
|
+
localStorage.setItem('anet-topo-layout', 'ring');
|
|
24
|
+
sessionStorage.setItem('anet_v3_auth', '1');
|
|
25
|
+
} catch {}
|
|
26
|
+
});
|
|
27
|
+
await ctx.route('**/api/hub/status*', async (route) => {
|
|
28
|
+
const r = await route.fetch();
|
|
29
|
+
const b = await r.json();
|
|
30
|
+
const nid = (b.sessions || [])[0]?.network_id || 'default';
|
|
31
|
+
const mk = (alias) => ({
|
|
32
|
+
alias, status: 'idle', model: 'claude-opus-4', runtime: 'claude-code-cli',
|
|
33
|
+
network_id: nid, project_dir: null,
|
|
34
|
+
created_at: fresh, updated_at: fresh, last_seen_at: fresh,
|
|
35
|
+
});
|
|
36
|
+
await route.fulfill({ response: r, json: { ...b, sessions: [mk('a·1')] } });
|
|
37
|
+
});
|
|
38
|
+
await ctx.route('**/api/hub/messages*', (r) => r.fulfill({ json: { messages: [] } }));
|
|
39
|
+
await ctx.route('**/api/hub/tasks*', (r) => r.fulfill({ json: { tasks: [] } }));
|
|
40
|
+
const page = await ctx.newPage();
|
|
41
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'networkidle' });
|
|
42
|
+
await page.waitForSelector('[data-topo-chrome-nodesize]', { timeout: 15000 });
|
|
43
|
+
await page.waitForTimeout(800);
|
|
44
|
+
|
|
45
|
+
// Find the inactive + active buttons via attrs
|
|
46
|
+
const buttons = await page.evaluate(() => {
|
|
47
|
+
const els = Array.from(document.querySelectorAll('[data-topo-chrome-nodesize]'));
|
|
48
|
+
return els.map((el) => ({
|
|
49
|
+
label: el.getAttribute('data-topo-chrome-nodesize'),
|
|
50
|
+
active: el.getAttribute('data-topo-chrome-nodesize-active'),
|
|
51
|
+
previewAttr: el.getAttribute('data-topo-chrome-nodesize-hover-preview-fw'),
|
|
52
|
+
fw: getComputedStyle(el).fontWeight,
|
|
53
|
+
}));
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
// Find an inactive one. Default nodeScale is M (1) so S + L should be inactive.
|
|
57
|
+
const inactiveLabel = buttons.find(b => b.active === 'false')?.label;
|
|
58
|
+
if (!inactiveLabel) {
|
|
59
|
+
console.log('❌ R521 — no inactive nodeSize button found');
|
|
60
|
+
process.exit(1);
|
|
61
|
+
}
|
|
62
|
+
const inactiveSel = `[data-topo-chrome-nodesize="${inactiveLabel}"]`;
|
|
63
|
+
|
|
64
|
+
// Phase 2: hover the inactive button
|
|
65
|
+
await page.hover(inactiveSel);
|
|
66
|
+
await page.waitForTimeout(350);
|
|
67
|
+
const hoverFw = await page.evaluate((sel) => getComputedStyle(document.querySelector(sel)).fontWeight, inactiveSel);
|
|
68
|
+
|
|
69
|
+
// Phase 3: find active button
|
|
70
|
+
const active = buttons.find(b => b.active === 'true');
|
|
71
|
+
|
|
72
|
+
await browser.close();
|
|
73
|
+
|
|
74
|
+
// Phase 4: source regex
|
|
75
|
+
const src = readFileSync('/home/vansin/agent-network-dashboard/app/components/TopoGraph.tsx', 'utf8');
|
|
76
|
+
const sourceWiredClass = /hover:bg-cyan-500\/5 active:bg-cyan-500\/15 hover:font-medium/.test(src);
|
|
77
|
+
const sourceWiredAttr =
|
|
78
|
+
/data-topo-chrome-nodesize-hover-preview-fw=\{nodeScale === v \? null : '500'\}/.test(src);
|
|
79
|
+
const sourceWiredTransition = /transition-\[font-weight\]/.test(src);
|
|
80
|
+
|
|
81
|
+
const inactiveRest = buttons.find(b => b.label === inactiveLabel);
|
|
82
|
+
|
|
83
|
+
const results = {
|
|
84
|
+
inactive_rest_fw_400: inactiveRest?.fw === '400',
|
|
85
|
+
inactive_rest_attr_500: inactiveRest?.previewAttr === '500',
|
|
86
|
+
inactive_active_attr_false: inactiveRest?.active === 'false',
|
|
87
|
+
inactive_hover_fw_500: hoverFw === '500',
|
|
88
|
+
active_rest_fw_500: active?.fw === '500',
|
|
89
|
+
active_no_preview_attr: active?.previewAttr === null || active?.previewAttr === undefined,
|
|
90
|
+
source_class_wired: sourceWiredClass,
|
|
91
|
+
source_attr_wired: sourceWiredAttr,
|
|
92
|
+
source_transition_wired: sourceWiredTransition,
|
|
93
|
+
};
|
|
94
|
+
const ok = Object.values(results).every(Boolean);
|
|
95
|
+
console.log(`${ok ? '✅' : '❌'} R521 nodeSize hover-fw preview:`,
|
|
96
|
+
JSON.stringify(results, null, 2),
|
|
97
|
+
'\n buttons:', JSON.stringify(buttons),
|
|
98
|
+
'\n inactive(', inactiveLabel, ')hover fw:', hoverFw);
|
|
99
|
+
process.exit(ok ? 0 : 1);
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/* Round 503 verification: orphan band rect (data-group-box-orphan="true")
|
|
2
|
+
* uses strokeDasharray='3 6' at rest, while prefix-group bands keep
|
|
3
|
+
* '6 6'. Pinned/hovered orphan still gets 'none' (solid stroke) — the
|
|
4
|
+
* differentiation lives ONLY in the rest state.
|
|
5
|
+
*
|
|
6
|
+
* Category-differentiation family 2nd anchor:
|
|
7
|
+
* R499 orphan label fontStyle: italic (1st anchor, R499)
|
|
8
|
+
* R503 orphan rect '3 6' dash pattern (2nd anchor, this round)
|
|
9
|
+
*
|
|
10
|
+
* Fixture: 2 prefix groups (alpha×3, beta×2) + 3 orphans (zeta/omega/lonely)
|
|
11
|
+
* — same shape as R499 test. Drives #150 orphan-band creation with
|
|
12
|
+
* prefix groups for differential assertion.
|
|
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', 'idle'), mk('alpha·3', 'idle'),
|
|
41
|
+
mk('beta·1', 'working'), mk('beta·2', 'idle'),
|
|
42
|
+
mk('zeta', 'idle'),
|
|
43
|
+
mk('omega', 'idle'),
|
|
44
|
+
mk('lonely', 'idle'),
|
|
45
|
+
] } });
|
|
46
|
+
});
|
|
47
|
+
await ctx.route('**/api/hub/messages*', (r) => r.fulfill({ json: { messages: [] } }));
|
|
48
|
+
await ctx.route('**/api/hub/tasks*', (r) => r.fulfill({ json: { tasks: [] } }));
|
|
49
|
+
const page = await ctx.newPage();
|
|
50
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'networkidle' });
|
|
51
|
+
await page.waitForSelector('[data-group-box-orphan]', { timeout: 15000 });
|
|
52
|
+
await page.waitForTimeout(1500);
|
|
53
|
+
|
|
54
|
+
const rects = await page.evaluate(() => {
|
|
55
|
+
const els = Array.from(document.querySelectorAll('[data-group-box-orphan]'));
|
|
56
|
+
return els.map((el) => {
|
|
57
|
+
const cs = window.getComputedStyle(el);
|
|
58
|
+
return {
|
|
59
|
+
orphan_attr: el.getAttribute('data-group-box-orphan'),
|
|
60
|
+
dasharray: el.getAttribute('stroke-dasharray') || cs.strokeDasharray || '',
|
|
61
|
+
};
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
await browser.close();
|
|
66
|
+
|
|
67
|
+
const src = readFileSync('/home/vansin/agent-network-dashboard/app/components/TopoGraph.tsx', 'utf8');
|
|
68
|
+
const sourceTernary = /\(isPinned \|\| isHovered\) \? 'none' :\s*box\.isOrphan \? '3 6' : '6 6'/.test(src);
|
|
69
|
+
const sourceAttr = /data-group-box-orphan=\{box\.isOrphan \? 'true' : 'false'\}/.test(src);
|
|
70
|
+
|
|
71
|
+
const orphanRect = rects.find((r) => r.orphan_attr === 'true');
|
|
72
|
+
const prefixRects = rects.filter((r) => r.orphan_attr === 'false');
|
|
73
|
+
|
|
74
|
+
// Computed strokeDasharray comes back as 'px-suffixed' or raw — normalize
|
|
75
|
+
const normalize = (s) => (s || '').replace(/px/g, '').replace(/,\s*/g, ' ').trim();
|
|
76
|
+
|
|
77
|
+
const results = {
|
|
78
|
+
rects_found: rects.length >= 2,
|
|
79
|
+
orphan_rect_present: !!orphanRect,
|
|
80
|
+
orphan_dash_3_6: orphanRect && (normalize(orphanRect.dasharray) === '3 6' || normalize(orphanRect.dasharray) === '3 6'),
|
|
81
|
+
prefix_rects_present: prefixRects.length >= 1,
|
|
82
|
+
prefix_dash_6_6: prefixRects.length > 0 && prefixRects.every((r) => normalize(r.dasharray) === '6 6'),
|
|
83
|
+
source_ternary_wired: sourceTernary,
|
|
84
|
+
source_attr_wired: sourceAttr,
|
|
85
|
+
};
|
|
86
|
+
const ok = Object.values(results).every(Boolean);
|
|
87
|
+
console.log(`${ok ? '✅' : '❌'} R503 orphan box dash:`, JSON.stringify(results),
|
|
88
|
+
'\n rects:', JSON.stringify(rects));
|
|
89
|
+
process.exit(ok ? 0 : 1);
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/* Round 506 verification: orphan band rect rest-state fillOpacity
|
|
2
|
+
* drops slightly below prefix-group rest (0.025/0.045 → 0.015/0.028).
|
|
3
|
+
* Category-differentiation family 3rd anchor.
|
|
4
|
+
*
|
|
5
|
+
* R499 orphan label fontStyle italic (1st anchor)
|
|
6
|
+
* R503 orphan rect '3 6' dasharray (2nd anchor)
|
|
7
|
+
* R506 orphan rect lower fillOpacity (3rd anchor)
|
|
8
|
+
*
|
|
9
|
+
* Pin and hover branches UNCHANGED (full inspection affordance).
|
|
10
|
+
* Differentiation lives ONLY in the rest state.
|
|
11
|
+
*
|
|
12
|
+
* Fixture: 2 prefix groups (alpha×3 + beta×2) + 3 orphans (zeta/omega/
|
|
13
|
+
* lonely) — same shape as R499/R503 tests for cross-round consistency.
|
|
14
|
+
* Cyber theme drives the 0.045 (prefix) vs 0.028 (orphan) comparison.
|
|
15
|
+
*/
|
|
16
|
+
import { chromium } from 'playwright';
|
|
17
|
+
import { readFileSync } from 'node:fs';
|
|
18
|
+
|
|
19
|
+
const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
|
|
20
|
+
const fresh = new Date(Date.now() - 60 * 1000).toISOString();
|
|
21
|
+
|
|
22
|
+
const browser = await chromium.launch({ headless: true });
|
|
23
|
+
const ctx = await browser.newContext({ viewport: { width: 1500, height: 1200 } });
|
|
24
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
25
|
+
await ctx.addInitScript(() => {
|
|
26
|
+
try {
|
|
27
|
+
localStorage.setItem('anet-theme', 'cyber');
|
|
28
|
+
localStorage.setItem('anet-topo-layout', 'grid');
|
|
29
|
+
sessionStorage.setItem('anet_v3_auth', '1');
|
|
30
|
+
} catch {}
|
|
31
|
+
});
|
|
32
|
+
await ctx.route('**/api/hub/status*', async (route) => {
|
|
33
|
+
const r = await route.fetch();
|
|
34
|
+
const b = await r.json();
|
|
35
|
+
const nid = (b.sessions || [])[0]?.network_id || 'default';
|
|
36
|
+
const mk = (alias, status) => ({
|
|
37
|
+
alias, status, model: 'claude-opus-4', runtime: 'claude-code-cli',
|
|
38
|
+
network_id: nid, project_dir: null,
|
|
39
|
+
created_at: fresh, updated_at: fresh, last_seen_at: fresh,
|
|
40
|
+
});
|
|
41
|
+
await route.fulfill({ response: r, json: { ...b, sessions: [
|
|
42
|
+
mk('alpha·1', 'working'), mk('alpha·2', 'idle'), mk('alpha·3', 'idle'),
|
|
43
|
+
mk('beta·1', 'working'), mk('beta·2', 'idle'),
|
|
44
|
+
mk('zeta', 'idle'),
|
|
45
|
+
mk('omega', 'idle'),
|
|
46
|
+
mk('lonely', 'idle'),
|
|
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-box-orphan]', { timeout: 15000 });
|
|
54
|
+
await page.waitForTimeout(1500);
|
|
55
|
+
|
|
56
|
+
const rects = await page.evaluate(() => {
|
|
57
|
+
const els = Array.from(document.querySelectorAll('[data-group-box-orphan]'));
|
|
58
|
+
return els.map((el) => ({
|
|
59
|
+
orphan_attr: el.getAttribute('data-group-box-orphan'),
|
|
60
|
+
fill_opacity_attr: el.getAttribute('data-group-box-fill-opacity'),
|
|
61
|
+
fill_opacity_dom: el.getAttribute('fill-opacity'),
|
|
62
|
+
}));
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
await browser.close();
|
|
66
|
+
|
|
67
|
+
const src = readFileSync('/home/vansin/agent-network-dashboard/app/components/TopoGraph.tsx', 'utf8');
|
|
68
|
+
const sourceTernary = /box\.isOrphan \? \(isLight \? 0\.015 : 0\.028\)\s*:\s*\(isLight \? 0\.025 : 0\.045\)/.test(src);
|
|
69
|
+
const sourceAttr = /data-group-box-fill-opacity=\{[\s\S]*?box\.isOrphan \? \(isLight \? 0\.015 : 0\.028\)/.test(src);
|
|
70
|
+
|
|
71
|
+
const orphanRect = rects.find((r) => r.orphan_attr === 'true');
|
|
72
|
+
const prefixRects = rects.filter((r) => r.orphan_attr === 'false');
|
|
73
|
+
|
|
74
|
+
// Cyber theme: prefix = 0.045, orphan = 0.028
|
|
75
|
+
const approxEq = (a, b) => Math.abs(parseFloat(a) - b) < 1e-9;
|
|
76
|
+
|
|
77
|
+
const results = {
|
|
78
|
+
rects_found: rects.length >= 2,
|
|
79
|
+
orphan_rect_present: !!orphanRect,
|
|
80
|
+
orphan_fill_028: orphanRect && approxEq(orphanRect.fill_opacity_attr, 0.028),
|
|
81
|
+
orphan_dom_fill_028: orphanRect && approxEq(orphanRect.fill_opacity_dom, 0.028),
|
|
82
|
+
prefix_rects_present: prefixRects.length >= 1,
|
|
83
|
+
prefix_fill_045: prefixRects.length > 0 && prefixRects.every((r) => approxEq(r.fill_opacity_attr, 0.045)),
|
|
84
|
+
prefix_dom_fill_045: prefixRects.length > 0 && prefixRects.every((r) => approxEq(r.fill_opacity_dom, 0.045)),
|
|
85
|
+
source_ternary_wired: sourceTernary,
|
|
86
|
+
source_attr_wired: sourceAttr,
|
|
87
|
+
};
|
|
88
|
+
const ok = Object.values(results).every(Boolean);
|
|
89
|
+
console.log(`${ok ? '✅' : '❌'} R506 orphan fill-opacity:`, JSON.stringify(results),
|
|
90
|
+
'\n rects:', JSON.stringify(rects));
|
|
91
|
+
process.exit(ok ? 0 : 1);
|