@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,133 @@
|
|
|
1
|
+
/* Round 563 verification: pressure-bar segment lights up (R210
|
|
2
|
+
* brightness + R542 drop-shadow) when operator hovers a node alias
|
|
3
|
+
* whose status matches the segment's tier. 6th anchor in
|
|
4
|
+
* inspection-overrides-encoding family.
|
|
5
|
+
*
|
|
6
|
+
* Mock: alpha·1 (working) + alpha·2 (idle) + alpha·3 (offline).
|
|
7
|
+
* Hover alpha·1 → 'working' segment lights up; idle + offline rest.
|
|
8
|
+
*
|
|
9
|
+
* Test phases:
|
|
10
|
+
* 1. rest: all 3 segments filter='none', lit='false'
|
|
11
|
+
* 2. hover alpha·1 (working) → working seg filter contains
|
|
12
|
+
* brightness(1.2) and drop-shadow with green hex; idle +
|
|
13
|
+
* offline stay at rest
|
|
14
|
+
* 3. hover alpha·2 (idle) → idle seg lit
|
|
15
|
+
* 4. hover alpha·3 (offline) → offline seg lit
|
|
16
|
+
* 5. source-side regex confirms wiring
|
|
17
|
+
*/
|
|
18
|
+
import { chromium } from 'playwright';
|
|
19
|
+
import { readFileSync } from 'node:fs';
|
|
20
|
+
|
|
21
|
+
const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
|
|
22
|
+
const fresh = new Date(Date.now() - 60 * 1000).toISOString();
|
|
23
|
+
|
|
24
|
+
const browser = await chromium.launch({ headless: true });
|
|
25
|
+
const ctx = await browser.newContext({ viewport: { width: 1500, height: 1200 } });
|
|
26
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
27
|
+
await ctx.addInitScript(() => {
|
|
28
|
+
try {
|
|
29
|
+
localStorage.setItem('anet-theme', 'cyber');
|
|
30
|
+
localStorage.setItem('anet-topo-layout', 'ring');
|
|
31
|
+
sessionStorage.setItem('anet_v3_auth', '1');
|
|
32
|
+
} catch {}
|
|
33
|
+
});
|
|
34
|
+
await ctx.route('**/api/hub/status*', async (route) => {
|
|
35
|
+
const r = await route.fetch();
|
|
36
|
+
const b = await r.json();
|
|
37
|
+
const nid = (b.sessions || [])[0]?.network_id || 'default';
|
|
38
|
+
const mk = (alias, status) => ({
|
|
39
|
+
alias, status, model: 'claude-opus-4', runtime: 'claude-code-cli',
|
|
40
|
+
network_id: nid, project_dir: null,
|
|
41
|
+
created_at: fresh, updated_at: fresh, last_seen_at: fresh,
|
|
42
|
+
});
|
|
43
|
+
await route.fulfill({ response: r, json: { ...b, sessions: [
|
|
44
|
+
mk('alpha·1', 'working'),
|
|
45
|
+
mk('alpha·2', 'idle'),
|
|
46
|
+
mk('alpha·3', 'offline'),
|
|
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-pressure-seg="working"]', { timeout: 15000 });
|
|
54
|
+
await page.waitForTimeout(500);
|
|
55
|
+
|
|
56
|
+
const probeSeg = (key) => page.evaluate((k) => {
|
|
57
|
+
const el = document.querySelector(`[data-pressure-seg="${k}"]`);
|
|
58
|
+
if (!el) return null;
|
|
59
|
+
const cs = getComputedStyle(el);
|
|
60
|
+
return {
|
|
61
|
+
filter: cs.filter,
|
|
62
|
+
matching: el.getAttribute('data-pressure-seg-member-alias-matching') === 'true',
|
|
63
|
+
lit: el.getAttribute('data-pressure-seg-lit') === 'true',
|
|
64
|
+
hovered: el.getAttribute('data-pressure-seg-hovered') === 'true',
|
|
65
|
+
};
|
|
66
|
+
}, key);
|
|
67
|
+
|
|
68
|
+
const restWorking = await probeSeg('working');
|
|
69
|
+
const restIdle = await probeSeg('idle');
|
|
70
|
+
const restOffline = await probeSeg('offline');
|
|
71
|
+
|
|
72
|
+
// Hover working node
|
|
73
|
+
await page.hover('g[data-node="alpha·1"]');
|
|
74
|
+
await page.waitForTimeout(400);
|
|
75
|
+
const hoverWorkingW = await probeSeg('working');
|
|
76
|
+
const hoverWorkingI = await probeSeg('idle');
|
|
77
|
+
const hoverWorkingO = await probeSeg('offline');
|
|
78
|
+
|
|
79
|
+
await page.mouse.move(0, 0);
|
|
80
|
+
await page.waitForTimeout(300);
|
|
81
|
+
await page.hover('g[data-node="alpha·2"]');
|
|
82
|
+
await page.waitForTimeout(400);
|
|
83
|
+
const hoverIdleI = await probeSeg('idle');
|
|
84
|
+
|
|
85
|
+
await page.mouse.move(0, 0);
|
|
86
|
+
await page.waitForTimeout(300);
|
|
87
|
+
await page.hover('g[data-node="alpha·3"]');
|
|
88
|
+
await page.waitForTimeout(400);
|
|
89
|
+
const hoverOfflineO = await probeSeg('offline');
|
|
90
|
+
|
|
91
|
+
await browser.close();
|
|
92
|
+
|
|
93
|
+
const src = readFileSync('/home/vansin/agent-network-dashboard/app/components/TopoGraph.tsx', 'utf8');
|
|
94
|
+
const sourceTierKey = /const hoveredAliasTierKey: 'working' \| 'idle' \| 'offline' \| null/.test(src);
|
|
95
|
+
const sourceMatching = /const isMemberAliasMatching = hoveredAliasTierKey === key;/.test(src);
|
|
96
|
+
const sourceLit = /const isSegLit = hoveredStatus === key \|\| isMemberAliasMatching;/.test(src);
|
|
97
|
+
const sourceFilter = /filter: isSegLit \? `brightness\(1\.2\) drop-shadow\(0 0 2px \$\{color\}99\)` : undefined/.test(src);
|
|
98
|
+
const sourceAttr = /data-pressure-seg-member-alias-matching=/.test(src);
|
|
99
|
+
|
|
100
|
+
const results = {
|
|
101
|
+
rest_working_filter_none: restWorking?.filter === 'none',
|
|
102
|
+
rest_working_lit_false: restWorking?.lit === false,
|
|
103
|
+
rest_idle_filter_none: restIdle?.filter === 'none',
|
|
104
|
+
rest_offline_filter_none: restOffline?.filter === 'none',
|
|
105
|
+
// Hover working node → working seg lit
|
|
106
|
+
hover_working_w_lit: hoverWorkingW?.lit === true,
|
|
107
|
+
hover_working_w_matching: hoverWorkingW?.matching === true,
|
|
108
|
+
hover_working_w_brightness: /brightness\(1\.2\)/.test(hoverWorkingW?.filter || ''),
|
|
109
|
+
hover_working_w_dropshadow: /drop-shadow\(/.test(hoverWorkingW?.filter || ''),
|
|
110
|
+
// idle + offline segments stay at rest
|
|
111
|
+
hover_working_i_lit_false: hoverWorkingI?.lit === false,
|
|
112
|
+
hover_working_o_lit_false: hoverWorkingO?.lit === false,
|
|
113
|
+
// Hover idle node → idle seg lit
|
|
114
|
+
hover_idle_i_lit: hoverIdleI?.lit === true,
|
|
115
|
+
hover_idle_i_matching: hoverIdleI?.matching === true,
|
|
116
|
+
// Hover offline node → offline seg lit
|
|
117
|
+
hover_offline_o_lit: hoverOfflineO?.lit === true,
|
|
118
|
+
hover_offline_o_matching: hoverOfflineO?.matching === true,
|
|
119
|
+
// Source
|
|
120
|
+
source_tier_key: sourceTierKey,
|
|
121
|
+
source_matching: sourceMatching,
|
|
122
|
+
source_lit: sourceLit,
|
|
123
|
+
source_filter: sourceFilter,
|
|
124
|
+
source_attr: sourceAttr,
|
|
125
|
+
};
|
|
126
|
+
const ok = Object.values(results).every(Boolean);
|
|
127
|
+
console.log(`${ok ? '✅' : '❌'} R563 pressure-seg inspection-overrides-encoding (6th anchor):`,
|
|
128
|
+
JSON.stringify(results, null, 2),
|
|
129
|
+
'\n rest working:', JSON.stringify(restWorking),
|
|
130
|
+
'\n hover alpha·1 (working) → working:', JSON.stringify(hoverWorkingW),
|
|
131
|
+
'\n hover alpha·2 (idle) → idle:', JSON.stringify(hoverIdleI),
|
|
132
|
+
'\n hover alpha·3 (offline) → offline:', JSON.stringify(hoverOfflineO));
|
|
133
|
+
process.exit(ok ? 0 : 1);
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/* Round 524 verification: pressure-bar segment width + filter motion
|
|
2
|
+
* restored — extends .anet-topo-chip-focus transition-property list
|
|
3
|
+
* to include `width` and `filter`, fixing the R165/R210 motion
|
|
4
|
+
* polishes silently broken by R490.
|
|
5
|
+
*
|
|
6
|
+
* Test phases:
|
|
7
|
+
* 1. computed transition on pressure-seg includes:
|
|
8
|
+
* - background-color (R510 family, R83 box-shadow already works)
|
|
9
|
+
* - width (R165 restoration ← R524)
|
|
10
|
+
* - filter (R210 brightness restoration ← R524)
|
|
11
|
+
* all at 200ms ease-out
|
|
12
|
+
* 2. globals.css source confirms width + filter in property list
|
|
13
|
+
* 3. hover the segment → filter brightness applied + transitioning
|
|
14
|
+
*/
|
|
15
|
+
import { chromium } from 'playwright';
|
|
16
|
+
import { readFileSync } from 'node:fs';
|
|
17
|
+
|
|
18
|
+
const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
|
|
19
|
+
const fresh = new Date(Date.now() - 60 * 1000).toISOString();
|
|
20
|
+
|
|
21
|
+
const browser = await chromium.launch({ headless: true });
|
|
22
|
+
const ctx = await browser.newContext({ viewport: { width: 1500, height: 1200 } });
|
|
23
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
24
|
+
await ctx.addInitScript(() => {
|
|
25
|
+
try {
|
|
26
|
+
localStorage.setItem('anet-theme', 'cyber');
|
|
27
|
+
localStorage.setItem('anet-topo-layout', 'ring');
|
|
28
|
+
sessionStorage.setItem('anet_v3_auth', '1');
|
|
29
|
+
} catch {}
|
|
30
|
+
});
|
|
31
|
+
await ctx.route('**/api/hub/status*', async (route) => {
|
|
32
|
+
const r = await route.fetch();
|
|
33
|
+
const b = await r.json();
|
|
34
|
+
const nid = (b.sessions || [])[0]?.network_id || 'default';
|
|
35
|
+
const mk = (alias, status) => ({
|
|
36
|
+
alias, status, model: 'claude-opus-4', runtime: 'claude-code-cli',
|
|
37
|
+
network_id: nid, project_dir: null,
|
|
38
|
+
created_at: fresh, updated_at: fresh, last_seen_at: fresh,
|
|
39
|
+
});
|
|
40
|
+
await route.fulfill({ response: r, json: { ...b, sessions: [
|
|
41
|
+
mk('a·1', 'working'),
|
|
42
|
+
mk('a·2', 'idle'),
|
|
43
|
+
mk('a·3', 'offline'),
|
|
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-pressure-seg="working"]', { timeout: 15000 });
|
|
51
|
+
await page.waitForTimeout(800);
|
|
52
|
+
|
|
53
|
+
const rest = await page.evaluate(() => {
|
|
54
|
+
const el = document.querySelector('[data-pressure-seg="working"]');
|
|
55
|
+
if (!el) return null;
|
|
56
|
+
const cs = getComputedStyle(el);
|
|
57
|
+
return {
|
|
58
|
+
transition: cs.transition,
|
|
59
|
+
transitionProp: cs.transitionProperty,
|
|
60
|
+
transitionDur: cs.transitionDuration,
|
|
61
|
+
filter: cs.filter,
|
|
62
|
+
};
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
// Hover the segment → filter should apply
|
|
66
|
+
await page.hover('[data-pressure-seg="working"]');
|
|
67
|
+
await page.waitForTimeout(350);
|
|
68
|
+
const hover = await page.evaluate(() => {
|
|
69
|
+
const el = document.querySelector('[data-pressure-seg="working"]');
|
|
70
|
+
if (!el) return null;
|
|
71
|
+
const cs = getComputedStyle(el);
|
|
72
|
+
return {
|
|
73
|
+
filter: cs.filter,
|
|
74
|
+
};
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
await browser.close();
|
|
78
|
+
|
|
79
|
+
const css = readFileSync('/home/vansin/agent-network-dashboard/app/globals.css', 'utf8');
|
|
80
|
+
const cssHasWidth =
|
|
81
|
+
/\.anet-topo-chip-focus[\s\S]*?transition-property:[\s\S]*?width[\s\S]*?!important/.test(css);
|
|
82
|
+
const cssHasFilter =
|
|
83
|
+
/\.anet-topo-chip-focus[\s\S]*?transition-property:[\s\S]*?filter[\s\S]*?!important/.test(css);
|
|
84
|
+
|
|
85
|
+
const results = {
|
|
86
|
+
has_width_in_prop: /(^|,\s*)width(,|$)/.test(rest?.transitionProp || '') ||
|
|
87
|
+
/\bwidth\b/.test(rest?.transitionProp || ''),
|
|
88
|
+
has_filter_in_prop: /\bfilter\b/.test(rest?.transitionProp || ''),
|
|
89
|
+
has_bg_color_in_prop: /background-color/.test(rest?.transitionProp || ''), // sanity
|
|
90
|
+
duration_200ms: /(200ms|0\.2s)/.test(rest?.transitionDur || ''),
|
|
91
|
+
rest_no_filter: rest?.filter === 'none' || rest?.filter === '',
|
|
92
|
+
hover_filter_brightness: /brightness\(1\.2\)/.test(hover?.filter || ''),
|
|
93
|
+
css_width_in_list: cssHasWidth,
|
|
94
|
+
css_filter_in_list: cssHasFilter,
|
|
95
|
+
};
|
|
96
|
+
const ok = Object.values(results).every(Boolean);
|
|
97
|
+
console.log(`${ok ? '✅' : '❌'} R524 pressure-seg motion restored:`,
|
|
98
|
+
JSON.stringify(results, null, 2),
|
|
99
|
+
'\n rest:', JSON.stringify(rest),
|
|
100
|
+
'\n hover.filter:', hover?.filter);
|
|
101
|
+
process.exit(ok ? 0 : 1);
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/* Round 498 verification: recent-signal row hot-count tspan gains a
|
|
2
|
+
* 3s opacity pulse (0.85↔1.0) when count >= 10 (isHot && !reducedMotion).
|
|
3
|
+
* Adds the 呼吸感 theme's second anchor after R497 hub idle-breath —
|
|
4
|
+
* gentle motion attracts glance to high-traffic lanes.
|
|
5
|
+
*
|
|
6
|
+
* Test scenarios — needs >= 10 messages between two aliases to trigger
|
|
7
|
+
* the hot threshold AND the recent-signal panel to render. Uses a
|
|
8
|
+
* messages fixture with 10 messages from alpha·a1 → alpha·a2.
|
|
9
|
+
*/
|
|
10
|
+
import { chromium } from 'playwright';
|
|
11
|
+
import { readFileSync } from 'node:fs';
|
|
12
|
+
|
|
13
|
+
const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
|
|
14
|
+
const fresh = new Date(Date.now() - 60 * 1000).toISOString();
|
|
15
|
+
|
|
16
|
+
async function probe({ reducedMotion }) {
|
|
17
|
+
const browser = await chromium.launch({ headless: true });
|
|
18
|
+
const ctx = await browser.newContext({
|
|
19
|
+
viewport: { width: 1500, height: 1200 },
|
|
20
|
+
reducedMotion: reducedMotion ? 'reduce' : 'no-preference',
|
|
21
|
+
});
|
|
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', 'ring');
|
|
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·a1', 'working'),
|
|
41
|
+
mk('alpha·a2', 'idle'),
|
|
42
|
+
] } });
|
|
43
|
+
});
|
|
44
|
+
// 12 messages → count >= 10 → isHot true
|
|
45
|
+
const msgs = Array.from({ length: 12 }, (_, i) => ({
|
|
46
|
+
id: `m${i}`, from_alias: 'alpha·a1', to_alias: 'alpha·a2',
|
|
47
|
+
content: 'test', created_at: fresh,
|
|
48
|
+
}));
|
|
49
|
+
await ctx.route('**/api/hub/messages*', (r) => r.fulfill({ json: { messages: msgs } }));
|
|
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.waitForTimeout(2000);
|
|
54
|
+
|
|
55
|
+
const result = await page.evaluate(() => {
|
|
56
|
+
const tspans = Array.from(document.querySelectorAll('[data-recent-row-count]'));
|
|
57
|
+
const hotTspan = tspans.find((t) => t.getAttribute('data-recent-row-count-hot') === 'true');
|
|
58
|
+
if (!hotTspan) return { found: false, totalTspans: tspans.length };
|
|
59
|
+
const cs = window.getComputedStyle(hotTspan);
|
|
60
|
+
return {
|
|
61
|
+
found: true,
|
|
62
|
+
class_has_pulse: /anet-recent-hot-pulse/.test(hotTspan.getAttribute('class') || ''),
|
|
63
|
+
pulse_attr: hotTspan.getAttribute('data-recent-row-count-hot-pulse'),
|
|
64
|
+
animation_name: cs.animationName,
|
|
65
|
+
animation_duration: cs.animationDuration,
|
|
66
|
+
};
|
|
67
|
+
});
|
|
68
|
+
await browser.close();
|
|
69
|
+
return result;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const motion = await probe({ reducedMotion: false });
|
|
73
|
+
const a11y = await probe({ reducedMotion: true });
|
|
74
|
+
|
|
75
|
+
const src = readFileSync('/home/vansin/agent-network-dashboard/app/components/TopoGraph.tsx', 'utf8');
|
|
76
|
+
const css = readFileSync('/home/vansin/agent-network-dashboard/app/globals.css', 'utf8');
|
|
77
|
+
const sourceClassWired = /className=\{isHot && !reducedMotion \? 'anet-recent-hot-pulse' : undefined\}/.test(src);
|
|
78
|
+
const sourceAttrWired = /data-recent-row-count-hot-pulse=\{isHot && !reducedMotion \? 'true' : 'false'\}/.test(src);
|
|
79
|
+
const cssKeyframeWired = /@keyframes anet-recent-hot-pulse-kf\s*\{[\s\S]*?opacity:\s*0\.85[\s\S]*?opacity:\s*1[\s\S]*?\}/.test(css);
|
|
80
|
+
const cssClassWired = /\.anet-recent-hot-pulse\s*\{\s*animation:\s*anet-recent-hot-pulse-kf 3s ease-in-out infinite/.test(css);
|
|
81
|
+
|
|
82
|
+
const results = {
|
|
83
|
+
// Motion fixture: tspan found + class applied + attr='true' + animation runs
|
|
84
|
+
motion_hot_found: motion.found,
|
|
85
|
+
motion_class_pulse: motion.found && motion.class_has_pulse,
|
|
86
|
+
motion_attr_true: motion.found && motion.pulse_attr === 'true',
|
|
87
|
+
motion_anim_name: motion.found && motion.animation_name === 'anet-recent-hot-pulse-kf',
|
|
88
|
+
// a11y fixture: class still absent (component-side gate) — attr='false'
|
|
89
|
+
a11y_hot_found: a11y.found,
|
|
90
|
+
a11y_no_class: a11y.found && !a11y.class_has_pulse,
|
|
91
|
+
a11y_attr_false: a11y.found && a11y.pulse_attr === 'false',
|
|
92
|
+
// Source/CSS
|
|
93
|
+
source_class_wired: sourceClassWired,
|
|
94
|
+
source_attr_wired: sourceAttrWired,
|
|
95
|
+
css_keyframe_wired: cssKeyframeWired,
|
|
96
|
+
css_class_wired: cssClassWired,
|
|
97
|
+
};
|
|
98
|
+
const ok = Object.values(results).every(Boolean);
|
|
99
|
+
console.log(`${ok ? '✅' : '❌'} R498 recent-row hot pulse:`, JSON.stringify(results),
|
|
100
|
+
'\n motion:', JSON.stringify(motion),
|
|
101
|
+
'\n a11y: ', JSON.stringify(a11y));
|
|
102
|
+
process.exit(ok ? 0 : 1);
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/* Round 520 verification: `+N more flows` footer gains 5-axis hover
|
|
2
|
+
* signature by adding fontWeight 500 → 600 on hover. Closes R475
|
|
3
|
+
* panel-text cadence at this last 150ms holdout.
|
|
4
|
+
*
|
|
5
|
+
* Test phases:
|
|
6
|
+
* 1. rest: fw=500, attr='500', opacity=0.55, ls=0.2px, no underline
|
|
7
|
+
* + transition list includes opacity at 200ms (not 150ms)
|
|
8
|
+
* 2. hover: fw=600, attr='600', opacity=0.85, ls=0.3px, underline
|
|
9
|
+
* 3. source-side regex confirms fw ternary + cadence
|
|
10
|
+
*
|
|
11
|
+
* Needs flowLinks > 3 to render the footer — uses 5 working sessions
|
|
12
|
+
* with at least 1 inbound flow each via mock messages.
|
|
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', 'ring');
|
|
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) => ({
|
|
35
|
+
alias, status: 'working', 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('a·1'), mk('a·2'), mk('a·3'), mk('a·4'), mk('a·5'), mk('a·6'),
|
|
41
|
+
] } });
|
|
42
|
+
});
|
|
43
|
+
// Mock 6 recent messages → 6 flowLinks → "+ 3 more flows" footer (top-3 visible)
|
|
44
|
+
await ctx.route('**/api/hub/messages*', (r) => r.fulfill({ json: {
|
|
45
|
+
messages: [
|
|
46
|
+
{ id: 'm1', from_alias: 'a·1', to_alias: 'a·2', content: 't', created_at: fresh },
|
|
47
|
+
{ id: 'm2', from_alias: 'a·2', to_alias: 'a·3', content: 't', created_at: fresh },
|
|
48
|
+
{ id: 'm3', from_alias: 'a·3', to_alias: 'a·4', content: 't', created_at: fresh },
|
|
49
|
+
{ id: 'm4', from_alias: 'a·4', to_alias: 'a·5', content: 't', created_at: fresh },
|
|
50
|
+
{ id: 'm5', from_alias: 'a·5', to_alias: 'a·6', content: 't', created_at: fresh },
|
|
51
|
+
{ id: 'm6', from_alias: 'a·6', to_alias: 'a·1', content: 't', created_at: fresh },
|
|
52
|
+
]
|
|
53
|
+
} }));
|
|
54
|
+
await ctx.route('**/api/hub/tasks*', (r) => r.fulfill({ json: { tasks: [] } }));
|
|
55
|
+
const page = await ctx.newPage();
|
|
56
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'networkidle' });
|
|
57
|
+
await page.waitForSelector('[data-recent-panel-more]', { timeout: 15000 });
|
|
58
|
+
await page.waitForTimeout(1000);
|
|
59
|
+
|
|
60
|
+
const sel = '[data-recent-panel-more]';
|
|
61
|
+
|
|
62
|
+
// Phase 1: rest
|
|
63
|
+
const rest = await page.evaluate((sel) => {
|
|
64
|
+
const el = document.querySelector(sel);
|
|
65
|
+
if (!el) return null;
|
|
66
|
+
const cs = getComputedStyle(el);
|
|
67
|
+
return {
|
|
68
|
+
attrFw: el.getAttribute('data-recent-panel-more-font-weight'),
|
|
69
|
+
attrHovered: el.getAttribute('data-recent-panel-more-hovered'),
|
|
70
|
+
attrTrans: el.getAttribute('data-recent-panel-more-transition'),
|
|
71
|
+
fontWeight: cs.fontWeight,
|
|
72
|
+
opacity: cs.opacity,
|
|
73
|
+
letterSpacing: cs.letterSpacing,
|
|
74
|
+
textDecoration:cs.textDecorationLine,
|
|
75
|
+
transition: cs.transition,
|
|
76
|
+
};
|
|
77
|
+
}, sel);
|
|
78
|
+
|
|
79
|
+
// Phase 2: hover the parent <g> (text is wrapped in a click-target <g>)
|
|
80
|
+
await page.hover('[data-recent-panel-more-nav]');
|
|
81
|
+
await page.waitForTimeout(350);
|
|
82
|
+
const hover = await page.evaluate((sel) => {
|
|
83
|
+
const el = document.querySelector(sel);
|
|
84
|
+
if (!el) return null;
|
|
85
|
+
const cs = getComputedStyle(el);
|
|
86
|
+
return {
|
|
87
|
+
attrFw: el.getAttribute('data-recent-panel-more-font-weight'),
|
|
88
|
+
attrHovered: el.getAttribute('data-recent-panel-more-hovered'),
|
|
89
|
+
fontWeight: cs.fontWeight,
|
|
90
|
+
opacity: cs.opacity,
|
|
91
|
+
letterSpacing: cs.letterSpacing,
|
|
92
|
+
textDecoration:cs.textDecorationLine,
|
|
93
|
+
};
|
|
94
|
+
}, sel);
|
|
95
|
+
|
|
96
|
+
await browser.close();
|
|
97
|
+
|
|
98
|
+
// Phase 3: source regex
|
|
99
|
+
const src = readFileSync('/home/vansin/agent-network-dashboard/app/components/TopoGraph.tsx', 'utf8');
|
|
100
|
+
const sourceWiredFw =
|
|
101
|
+
/fontWeight=\{hoveredRecentMore \? '600' : '500'\}/.test(src) &&
|
|
102
|
+
/data-recent-panel-more-font-weight=\{hoveredRecentMore \? '600' : '500'\}/.test(src);
|
|
103
|
+
const sourceWiredCadence =
|
|
104
|
+
/transition: 'opacity 200ms ease-out, fill 200ms ease-out, letter-spacing 200ms ease-out, font-weight 200ms ease-out'/.test(src);
|
|
105
|
+
|
|
106
|
+
const results = {
|
|
107
|
+
rest_attr_fw_500: rest?.attrFw === '500',
|
|
108
|
+
rest_attr_hovered_false: rest?.attrHovered === 'false',
|
|
109
|
+
rest_attr_trans_200: rest?.attrTrans === '200ms',
|
|
110
|
+
rest_fw_500: rest?.fontWeight === '500',
|
|
111
|
+
rest_underline_none: rest?.textDecoration === 'none' || rest?.textDecoration === '',
|
|
112
|
+
rest_transition_200: /(200ms|0\.2s).+font-weight|font-weight.+(200ms|0\.2s)/.test(rest?.transition || '') ||
|
|
113
|
+
/(200ms|0\.2s)/.test(rest?.transition || ''),
|
|
114
|
+
hover_attr_fw_600: hover?.attrFw === '600',
|
|
115
|
+
hover_attr_hovered_true: hover?.attrHovered === 'true',
|
|
116
|
+
hover_fw_600: hover?.fontWeight === '600',
|
|
117
|
+
hover_letter_spacing_3: hover?.letterSpacing === '0.3px',
|
|
118
|
+
hover_underline: /underline/.test(hover?.textDecoration || ''),
|
|
119
|
+
source_fw_ternary: sourceWiredFw,
|
|
120
|
+
source_cadence_4axis: sourceWiredCadence,
|
|
121
|
+
};
|
|
122
|
+
const ok = Object.values(results).every(Boolean);
|
|
123
|
+
console.log(`${ok ? '✅' : '❌'} R520 recent-panel-more 5-axis hover + 200ms cadence:`,
|
|
124
|
+
JSON.stringify(results, null, 2),
|
|
125
|
+
'\n rest:', JSON.stringify(rest), '\n hover:', JSON.stringify(hover));
|
|
126
|
+
process.exit(ok ? 0 : 1);
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/* Round 530 verification: recent-row alias text gains fontWeight 500
|
|
2
|
+
* → 600 on hover OR pin. Hover-fw family 7th anchor.
|
|
3
|
+
*
|
|
4
|
+
* Test phases (needs ≥1 flowLink for recent-row to render):
|
|
5
|
+
* 1. rest: fw=500, attr='500', hovered/pinned='false'
|
|
6
|
+
* 2. hover row (via hover the row's text element):
|
|
7
|
+
* fw=600, attr='600', hovered='true'
|
|
8
|
+
* 3. mouseleave: fw returns to 500
|
|
9
|
+
* 4. count tspan unaffected (R320 inline fw=600 preserved)
|
|
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) => ({
|
|
33
|
+
alias, status: 'working', 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: [
|
|
38
|
+
mk('a·1'), mk('a·2'),
|
|
39
|
+
] } });
|
|
40
|
+
});
|
|
41
|
+
// 1 flow → 1 recent-row visible
|
|
42
|
+
await ctx.route('**/api/hub/messages*', (r) => r.fulfill({ json: {
|
|
43
|
+
messages: [{ id: 'm1', from_alias: 'a·1', to_alias: 'a·2', content: 'test', created_at: fresh }]
|
|
44
|
+
} }));
|
|
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-recent-row-text]', { timeout: 15000 });
|
|
49
|
+
await page.waitForTimeout(800);
|
|
50
|
+
|
|
51
|
+
const sel = '[data-recent-row-text]';
|
|
52
|
+
|
|
53
|
+
const restRead = async () => page.evaluate((sel) => {
|
|
54
|
+
const el = document.querySelector(sel);
|
|
55
|
+
if (!el) return null;
|
|
56
|
+
const cs = getComputedStyle(el);
|
|
57
|
+
return {
|
|
58
|
+
attrFw: el.getAttribute('data-recent-row-text-font-weight'),
|
|
59
|
+
attrPinned: el.getAttribute('data-recent-row-text-pinned'),
|
|
60
|
+
attrHovered: el.getAttribute('data-recent-row-text-hovered'),
|
|
61
|
+
fontWeight: cs.fontWeight,
|
|
62
|
+
transition: cs.transition,
|
|
63
|
+
};
|
|
64
|
+
}, sel);
|
|
65
|
+
|
|
66
|
+
// Phase 1: rest
|
|
67
|
+
const rest = await restRead();
|
|
68
|
+
|
|
69
|
+
// Phase 2: hover the row's hitbox (rect parent) — the row text
|
|
70
|
+
// has pointer-events behavior driven by row-level hover handlers.
|
|
71
|
+
// Look for the row group's tint rect or rect hitbox.
|
|
72
|
+
const bbox = await page.locator(sel).first().boundingBox();
|
|
73
|
+
if (bbox) {
|
|
74
|
+
await page.mouse.move(bbox.x + bbox.width / 2, bbox.y + bbox.height / 2);
|
|
75
|
+
}
|
|
76
|
+
await page.waitForTimeout(400);
|
|
77
|
+
const hover = await restRead();
|
|
78
|
+
|
|
79
|
+
// Phase 3: mouseleave
|
|
80
|
+
await page.mouse.move(50, 50);
|
|
81
|
+
await page.waitForTimeout(400);
|
|
82
|
+
const leave = await restRead();
|
|
83
|
+
|
|
84
|
+
await browser.close();
|
|
85
|
+
|
|
86
|
+
// Source regex
|
|
87
|
+
const src = readFileSync('/home/vansin/agent-network-dashboard/app/components/TopoGraph.tsx', 'utf8');
|
|
88
|
+
const sourceFwTernary =
|
|
89
|
+
/fontWeight=\{\(isRowHovered \|\| isRowPinned\) \? '600' : '500'\}/.test(src);
|
|
90
|
+
const sourceAttrWired =
|
|
91
|
+
/data-recent-row-text-font-weight=\{\(isRowHovered \|\| isRowPinned\) \? '600' : '500'\}/.test(src);
|
|
92
|
+
const sourceTransitionExt =
|
|
93
|
+
/transition: 'fill 200ms ease-out, letter-spacing 200ms ease-out, font-weight 200ms ease-out'/.test(src);
|
|
94
|
+
|
|
95
|
+
const results = {
|
|
96
|
+
rest_attr_500: rest?.attrFw === '500',
|
|
97
|
+
rest_fw_500: rest?.fontWeight === '500',
|
|
98
|
+
rest_hovered_false: rest?.attrHovered === 'false',
|
|
99
|
+
rest_pinned_false: rest?.attrPinned === 'false',
|
|
100
|
+
hover_attr_600: hover?.attrFw === '600',
|
|
101
|
+
hover_fw_600: hover?.fontWeight === '600',
|
|
102
|
+
hover_hovered_true: hover?.attrHovered === 'true',
|
|
103
|
+
leave_attr_500: leave?.attrFw === '500',
|
|
104
|
+
leave_fw_500: leave?.fontWeight === '500',
|
|
105
|
+
source_fw_ternary: sourceFwTernary,
|
|
106
|
+
source_attr_wired: sourceAttrWired,
|
|
107
|
+
source_transition_ext: sourceTransitionExt,
|
|
108
|
+
};
|
|
109
|
+
const ok = Object.values(results).every(Boolean);
|
|
110
|
+
console.log(`${ok ? '✅' : '❌'} R530 recent-row hover-fw:`,
|
|
111
|
+
JSON.stringify(results, null, 2),
|
|
112
|
+
'\n rest:', JSON.stringify(rest),
|
|
113
|
+
'\n hover:', JSON.stringify(hover),
|
|
114
|
+
'\n leave:', JSON.stringify(leave));
|
|
115
|
+
process.exit(ok ? 0 : 1);
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/* Round 513 verification: root svg surfaces `data-topo-prefers-reduced-
|
|
2
|
+
* motion` (15th attr in canvas state surface set). Reflects the
|
|
3
|
+
* client's prefers-reduced-motion media-query state.
|
|
4
|
+
*
|
|
5
|
+
* Tests:
|
|
6
|
+
* 1. no-preference: attr='false'
|
|
7
|
+
* 2. reduce: attr='true'
|
|
8
|
+
* 3. source-side regex confirms wiring
|
|
9
|
+
*/
|
|
10
|
+
import { chromium } from 'playwright';
|
|
11
|
+
import { readFileSync } from 'node:fs';
|
|
12
|
+
|
|
13
|
+
const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
|
|
14
|
+
const fresh = new Date(Date.now() - 60 * 1000).toISOString();
|
|
15
|
+
|
|
16
|
+
async function probe(reducedMotion) {
|
|
17
|
+
const browser = await chromium.launch({ headless: true });
|
|
18
|
+
const ctx = await browser.newContext({
|
|
19
|
+
viewport: { width: 1500, height: 1200 },
|
|
20
|
+
reducedMotion: reducedMotion ? 'reduce' : 'no-preference',
|
|
21
|
+
});
|
|
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', 'ring');
|
|
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: [mk('a·1', 'idle')] } });
|
|
40
|
+
});
|
|
41
|
+
await ctx.route('**/api/hub/messages*', (r) => r.fulfill({ json: { messages: [] } }));
|
|
42
|
+
await ctx.route('**/api/hub/tasks*', (r) => r.fulfill({ json: { tasks: [] } }));
|
|
43
|
+
const page = await ctx.newPage();
|
|
44
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'networkidle' });
|
|
45
|
+
await page.waitForSelector('svg[data-topo-prefers-reduced-motion]', { timeout: 15000 });
|
|
46
|
+
// Wait for the useEffect that updates reducedMotion via matchMedia listener
|
|
47
|
+
await page.waitForTimeout(800);
|
|
48
|
+
const attr = await page.evaluate(() =>
|
|
49
|
+
document.querySelector('svg[viewBox="0 0 1000 680"]')?.getAttribute('data-topo-prefers-reduced-motion')
|
|
50
|
+
);
|
|
51
|
+
await browser.close();
|
|
52
|
+
return attr;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const noPref = await probe(false);
|
|
56
|
+
const reduce = await probe(true);
|
|
57
|
+
|
|
58
|
+
const src = readFileSync('/home/vansin/agent-network-dashboard/app/components/TopoGraph.tsx', 'utf8');
|
|
59
|
+
const sourceWired = /data-topo-prefers-reduced-motion=\{reducedMotion \? 'true' : 'false'\}/.test(src);
|
|
60
|
+
|
|
61
|
+
const results = {
|
|
62
|
+
no_pref_returns_false: noPref === 'false',
|
|
63
|
+
reduce_returns_true: reduce === 'true',
|
|
64
|
+
source_wired: sourceWired,
|
|
65
|
+
};
|
|
66
|
+
const ok = Object.values(results).every(Boolean);
|
|
67
|
+
console.log(`${ok ? '✅' : '❌'} R513 prefers-reduced-motion attr:`, JSON.stringify(results),
|
|
68
|
+
'\n no-pref:', noPref, '/ reduce:', reduce);
|
|
69
|
+
process.exit(ok ? 0 : 1);
|