@sleep2agi/agent-network-dashboard 0.5.3-preview.9 → 0.5.3-preview.90
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/0ajvyui5ltdgw.js +1 -0
- package/.next/static/chunks/{00d~vl~k~7f75.js → 0u9my~t.g2_an.js} +1 -1
- package/.next/static/chunks/{03a4--7ncekmk.js → 0v4-5tng.uh.7.js} +2 -2
- package/.next/static/chunks/0y3zijtrr9r81.js +4 -0
- package/.next/static/chunks/13~aih56vx-cf.css +2 -0
- package/.next/static/chunks/1857rb9ikv20f.js +1 -0
- package/.next/trace +2 -2
- package/.next/trace-build +1 -1
- package/app/components/ServersDrawer.tsx +16 -3
- package/app/components/TopoGraph.tsx +2446 -121
- 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-badge-text-brightness-test.mjs +83 -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-fullscreen-icon-rotate-test.mjs +93 -0
- package/scripts/topo-grid-content-bottom-attr-test.mjs +72 -0
- package/scripts/topo-group-label-brightness-test.mjs +84 -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-brightness-test.mjs +79 -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-brightness-test.mjs +84 -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-row-label-glow-test.mjs +102 -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-node-sub-text-brightness-test.mjs +88 -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-row-brightness-test.mjs +116 -0
- package/scripts/topo-panel-title-brightness-test.mjs +98 -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-recent-row-text-glow-test.mjs +86 -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-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/0hndl9yzpqajt.css +0 -2
- package/.next/static/chunks/0jn4lbsj97vfl.js +0 -1
- package/.next/static/chunks/0rz3-6.xs78~d.js +0 -1
- package/.next/static/chunks/0~~xbw42y4m3v.js +0 -4
- /package/.next/static/{nbpD7Lhttq59fvvIw9gTX → IPCDbF7lRKC58UL3VvTa9}/_buildManifest.js +0 -0
- /package/.next/static/{nbpD7Lhttq59fvvIw9gTX → IPCDbF7lRKC58UL3VvTa9}/_clientMiddlewareManifest.js +0 -0
- /package/.next/static/{nbpD7Lhttq59fvvIw9gTX → IPCDbF7lRKC58UL3VvTa9}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/* Round 556 verification: title-block H2 "Command mesh" gains
|
|
2
|
+
* a 2nd editorial-emphasis axis — group-hover:font-bold paired
|
|
3
|
+
* with R554's group-hover:tracking-tighter.
|
|
4
|
+
*
|
|
5
|
+
* Test phases:
|
|
6
|
+
* 1. rest: fontWeight = 600 (semibold), letter-spacing ≈ -0.45px
|
|
7
|
+
* 2. hover brand logo (sibling, propagates via group-hover):
|
|
8
|
+
* H2 fontWeight = 700 (bold), letter-spacing ≈ -0.9px
|
|
9
|
+
* 3. transition-property contains BOTH letter-spacing AND font-weight
|
|
10
|
+
* 4. source-side regex confirms group-hover:font-bold wired
|
|
11
|
+
*/
|
|
12
|
+
import { chromium } from 'playwright';
|
|
13
|
+
import { readFileSync } from 'node:fs';
|
|
14
|
+
|
|
15
|
+
const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
|
|
16
|
+
const fresh = new Date(Date.now() - 60 * 1000).toISOString();
|
|
17
|
+
|
|
18
|
+
const browser = await chromium.launch({ headless: true });
|
|
19
|
+
const ctx = await browser.newContext({ viewport: { width: 1500, height: 1200 } });
|
|
20
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
21
|
+
await ctx.addInitScript(() => {
|
|
22
|
+
try {
|
|
23
|
+
localStorage.setItem('anet-theme', 'cyber');
|
|
24
|
+
localStorage.setItem('anet-topo-layout', 'ring');
|
|
25
|
+
sessionStorage.setItem('anet_v3_auth', '1');
|
|
26
|
+
} catch {}
|
|
27
|
+
});
|
|
28
|
+
await ctx.route('**/api/hub/status*', async (route) => {
|
|
29
|
+
const r = await route.fetch();
|
|
30
|
+
const b = await r.json();
|
|
31
|
+
const nid = (b.sessions || [])[0]?.network_id || 'default';
|
|
32
|
+
const mk = (alias) => ({
|
|
33
|
+
alias, status: 'idle', model: 'claude-opus-4', runtime: 'claude-code-cli',
|
|
34
|
+
network_id: nid, project_dir: null,
|
|
35
|
+
created_at: fresh, updated_at: fresh, last_seen_at: fresh,
|
|
36
|
+
});
|
|
37
|
+
await route.fulfill({ response: r, json: { ...b, sessions: [mk('a·1')] } });
|
|
38
|
+
});
|
|
39
|
+
await ctx.route('**/api/hub/messages*', (r) => r.fulfill({ json: { messages: [] } }));
|
|
40
|
+
await ctx.route('**/api/hub/tasks*', (r) => r.fulfill({ json: { tasks: [] } }));
|
|
41
|
+
const page = await ctx.newPage();
|
|
42
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'networkidle' });
|
|
43
|
+
await page.waitForSelector('[data-topo-section-title]', { timeout: 15000 });
|
|
44
|
+
await page.waitForTimeout(500);
|
|
45
|
+
|
|
46
|
+
const h2Sel = '[data-topo-section-title]';
|
|
47
|
+
const logoSel = '[data-topo-brand-logo]';
|
|
48
|
+
|
|
49
|
+
const parsePx = (s) => parseFloat((s || '').replace(/px$/, ''));
|
|
50
|
+
|
|
51
|
+
// Phase 1: rest
|
|
52
|
+
const rest = await page.evaluate((s) => {
|
|
53
|
+
const el = document.querySelector(s);
|
|
54
|
+
if (!el) return null;
|
|
55
|
+
const cs = getComputedStyle(el);
|
|
56
|
+
return {
|
|
57
|
+
fontWeight: cs.fontWeight,
|
|
58
|
+
letterSpacing: cs.letterSpacing,
|
|
59
|
+
transitionProperty: cs.transitionProperty,
|
|
60
|
+
transitionDuration: cs.transitionDuration,
|
|
61
|
+
hoverFwAttr: el.getAttribute('data-topo-section-title-hover-fw'),
|
|
62
|
+
hoverTrackingAttr: el.getAttribute('data-topo-section-title-hover-tracking'),
|
|
63
|
+
};
|
|
64
|
+
}, h2Sel);
|
|
65
|
+
|
|
66
|
+
// Phase 2: hover brand logo (sibling) → group-hover propagates
|
|
67
|
+
await page.hover(logoSel);
|
|
68
|
+
await page.waitForTimeout(400);
|
|
69
|
+
const hover = await page.evaluate((s) => {
|
|
70
|
+
const el = document.querySelector(s);
|
|
71
|
+
if (!el) return null;
|
|
72
|
+
const cs = getComputedStyle(el);
|
|
73
|
+
return { fontWeight: cs.fontWeight, letterSpacing: cs.letterSpacing };
|
|
74
|
+
}, h2Sel);
|
|
75
|
+
|
|
76
|
+
await browser.close();
|
|
77
|
+
|
|
78
|
+
const src = readFileSync('/home/vansin/agent-network-dashboard/app/components/TopoGraph.tsx', 'utf8');
|
|
79
|
+
const sourceFwWired = /group-hover:font-bold/.test(src);
|
|
80
|
+
const sourceTransition = /transition-\[letter-spacing,font-weight\] duration-200 ease-out/.test(src);
|
|
81
|
+
const sourceFwAttr = /data-topo-section-title-hover-fw="700"/.test(src);
|
|
82
|
+
|
|
83
|
+
const restPx = parsePx(rest?.letterSpacing);
|
|
84
|
+
const hoverPx = parsePx(hover?.letterSpacing);
|
|
85
|
+
|
|
86
|
+
const results = {
|
|
87
|
+
rest_fw_semibold: rest?.fontWeight === '600',
|
|
88
|
+
rest_tracking_tight: Math.abs(restPx - (-0.45)) < 0.05,
|
|
89
|
+
hover_fw_bold: hover?.fontWeight === '700',
|
|
90
|
+
hover_tracking_tighter: Math.abs(hoverPx - (-0.9)) < 0.05,
|
|
91
|
+
// Both axes intensify together — confirm by directionality
|
|
92
|
+
fw_intensifies: parseInt(hover?.fontWeight || '0') > parseInt(rest?.fontWeight || '0'),
|
|
93
|
+
tracking_intensifies: hoverPx < restPx - 0.3, // more negative = tighter
|
|
94
|
+
transition_has_ls: /letter-spacing/.test(rest?.transitionProperty || ''),
|
|
95
|
+
transition_has_fw: /font-weight/.test(rest?.transitionProperty || ''),
|
|
96
|
+
transition_duration: rest?.transitionDuration === '0.2s',
|
|
97
|
+
rest_hover_fw_attr: rest?.hoverFwAttr === '700',
|
|
98
|
+
rest_hover_tracking_attr: rest?.hoverTrackingAttr === 'tracking-tighter',
|
|
99
|
+
source_fw_wired: sourceFwWired,
|
|
100
|
+
source_transition: sourceTransition,
|
|
101
|
+
source_fw_attr: sourceFwAttr,
|
|
102
|
+
};
|
|
103
|
+
const ok = Object.values(results).every(Boolean);
|
|
104
|
+
console.log(`${ok ? '✅' : '❌'} R556 title-block H2 group-hover:font-bold (2-axis editorial emphasis):`,
|
|
105
|
+
JSON.stringify(results, null, 2),
|
|
106
|
+
`\n rest: fw=${rest?.fontWeight}, ls=${rest?.letterSpacing}`,
|
|
107
|
+
`\n hover: fw=${hover?.fontWeight}, ls=${hover?.letterSpacing}`,
|
|
108
|
+
`\n transition: ${rest?.transitionProperty}`);
|
|
109
|
+
process.exit(ok ? 0 : 1);
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/* Round 554 verification: title-block H2 "Command mesh" gains
|
|
2
|
+
* group-hover:tracking-tighter via the wrapper's `group` flag.
|
|
3
|
+
* Hovering the brand logo OR the title text should tighten the
|
|
4
|
+
* H2's kerning from -0.025em → -0.05em.
|
|
5
|
+
*
|
|
6
|
+
* Tailwind tracking utilities map to letter-spacing CSS:
|
|
7
|
+
* tracking-tight -0.025em
|
|
8
|
+
* tracking-tighter -0.05em
|
|
9
|
+
*
|
|
10
|
+
* At text-lg (18px font-size):
|
|
11
|
+
* tracking-tight = -0.45px
|
|
12
|
+
* tracking-tighter = -0.9px
|
|
13
|
+
*
|
|
14
|
+
* Test phases:
|
|
15
|
+
* 1. rest: H2 letter-spacing ≈ -0.45px (tracking-tight)
|
|
16
|
+
* 2. hover brand logo: H2 letter-spacing ≈ -0.9px (tracking-tighter)
|
|
17
|
+
* Verifies group-hover propagation from sibling element.
|
|
18
|
+
* 3. hover H2 itself: letter-spacing ≈ -0.9px (same)
|
|
19
|
+
* 4. source: wrapper has `group`, H2 has group-hover:tracking-tighter
|
|
20
|
+
*/
|
|
21
|
+
import { chromium } from 'playwright';
|
|
22
|
+
import { readFileSync } from 'node:fs';
|
|
23
|
+
|
|
24
|
+
const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
|
|
25
|
+
const fresh = new Date(Date.now() - 60 * 1000).toISOString();
|
|
26
|
+
|
|
27
|
+
const browser = await chromium.launch({ headless: true });
|
|
28
|
+
const ctx = await browser.newContext({ viewport: { width: 1500, height: 1200 } });
|
|
29
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
30
|
+
await ctx.addInitScript(() => {
|
|
31
|
+
try {
|
|
32
|
+
localStorage.setItem('anet-theme', 'cyber');
|
|
33
|
+
localStorage.setItem('anet-topo-layout', 'ring');
|
|
34
|
+
sessionStorage.setItem('anet_v3_auth', '1');
|
|
35
|
+
} catch {}
|
|
36
|
+
});
|
|
37
|
+
await ctx.route('**/api/hub/status*', async (route) => {
|
|
38
|
+
const r = await route.fetch();
|
|
39
|
+
const b = await r.json();
|
|
40
|
+
const nid = (b.sessions || [])[0]?.network_id || 'default';
|
|
41
|
+
const mk = (alias) => ({
|
|
42
|
+
alias, status: 'idle', model: 'claude-opus-4', runtime: 'claude-code-cli',
|
|
43
|
+
network_id: nid, project_dir: null,
|
|
44
|
+
created_at: fresh, updated_at: fresh, last_seen_at: fresh,
|
|
45
|
+
});
|
|
46
|
+
await route.fulfill({ response: r, json: { ...b, sessions: [mk('a·1')] } });
|
|
47
|
+
});
|
|
48
|
+
await ctx.route('**/api/hub/messages*', (r) => r.fulfill({ json: { messages: [] } }));
|
|
49
|
+
await ctx.route('**/api/hub/tasks*', (r) => r.fulfill({ json: { tasks: [] } }));
|
|
50
|
+
const page = await ctx.newPage();
|
|
51
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'networkidle' });
|
|
52
|
+
await page.waitForSelector('[data-topo-section-title]', { timeout: 15000 });
|
|
53
|
+
await page.waitForTimeout(500);
|
|
54
|
+
|
|
55
|
+
const h2Sel = '[data-topo-section-title]';
|
|
56
|
+
const logoSel = '[data-topo-brand-logo]';
|
|
57
|
+
|
|
58
|
+
const parsePx = (s) => parseFloat((s || '').replace(/px$/, ''));
|
|
59
|
+
|
|
60
|
+
// Phase 1: rest
|
|
61
|
+
const rest = await page.evaluate((s) => {
|
|
62
|
+
const el = document.querySelector(s);
|
|
63
|
+
if (!el) return null;
|
|
64
|
+
const cs = getComputedStyle(el);
|
|
65
|
+
return {
|
|
66
|
+
letterSpacing: cs.letterSpacing,
|
|
67
|
+
transitionProperty: cs.transitionProperty,
|
|
68
|
+
transitionDuration: cs.transitionDuration,
|
|
69
|
+
fontSize: cs.fontSize,
|
|
70
|
+
hoverAttr: el.getAttribute('data-topo-section-title-hover-tracking'),
|
|
71
|
+
};
|
|
72
|
+
}, h2Sel);
|
|
73
|
+
|
|
74
|
+
// Phase 2: hover brand logo (different element, but same group → H2 should tighten)
|
|
75
|
+
await page.hover(logoSel);
|
|
76
|
+
await page.waitForTimeout(400);
|
|
77
|
+
const hoverLogo = await page.evaluate((s) => {
|
|
78
|
+
const el = document.querySelector(s);
|
|
79
|
+
if (!el) return null;
|
|
80
|
+
const cs = getComputedStyle(el);
|
|
81
|
+
return { letterSpacing: cs.letterSpacing };
|
|
82
|
+
}, h2Sel);
|
|
83
|
+
|
|
84
|
+
// Phase 3: hover H2 itself (cross-confirm)
|
|
85
|
+
await page.mouse.move(0, 0);
|
|
86
|
+
await page.waitForTimeout(300);
|
|
87
|
+
await page.hover(h2Sel);
|
|
88
|
+
await page.waitForTimeout(400);
|
|
89
|
+
const hoverH2 = await page.evaluate((s) => {
|
|
90
|
+
const el = document.querySelector(s);
|
|
91
|
+
if (!el) return null;
|
|
92
|
+
const cs = getComputedStyle(el);
|
|
93
|
+
return { letterSpacing: cs.letterSpacing };
|
|
94
|
+
}, h2Sel);
|
|
95
|
+
|
|
96
|
+
await browser.close();
|
|
97
|
+
|
|
98
|
+
const src = readFileSync('/home/vansin/agent-network-dashboard/app/components/TopoGraph.tsx', 'utf8');
|
|
99
|
+
const sourceGroupWrapper = /<div className="group flex items-center gap-2\.5" data-topo-section-titleblock-group>/.test(src);
|
|
100
|
+
const sourceH2HoverTracking = /group-hover:tracking-tighter/.test(src);
|
|
101
|
+
const sourceH2HoverAttr = /data-topo-section-title-hover-tracking="tracking-tighter"/.test(src);
|
|
102
|
+
|
|
103
|
+
// Rest ≈ -0.45px (-0.025em × 18px), hover ≈ -0.9px (-0.05em × 18px)
|
|
104
|
+
const restPx = parsePx(rest?.letterSpacing);
|
|
105
|
+
const hoverLogoPx = parsePx(hoverLogo?.letterSpacing);
|
|
106
|
+
const hoverH2Px = parsePx(hoverH2?.letterSpacing);
|
|
107
|
+
|
|
108
|
+
const results = {
|
|
109
|
+
rest_attr_present: rest?.hoverAttr === 'tracking-tighter',
|
|
110
|
+
rest_tracking_tight: Math.abs(restPx - (-0.45)) < 0.05,
|
|
111
|
+
hover_via_logo_tightens: Math.abs(hoverLogoPx - (-0.9)) < 0.05,
|
|
112
|
+
hover_via_h2_tightens: Math.abs(hoverH2Px - (-0.9)) < 0.05,
|
|
113
|
+
hover_tighter_than_rest: hoverLogoPx < restPx - 0.3,
|
|
114
|
+
transition_has_letter_spacing: /letter-spacing/.test(rest?.transitionProperty || ''),
|
|
115
|
+
transition_duration_200ms: rest?.transitionDuration === '0.2s',
|
|
116
|
+
source_group_wrapper: sourceGroupWrapper,
|
|
117
|
+
source_h2_group_hover: sourceH2HoverTracking,
|
|
118
|
+
source_h2_attr: sourceH2HoverAttr,
|
|
119
|
+
};
|
|
120
|
+
const ok = Object.values(results).every(Boolean);
|
|
121
|
+
console.log(`${ok ? '✅' : '❌'} R554 title-block H2 group-hover:tracking-tighter:`,
|
|
122
|
+
JSON.stringify(results, null, 2),
|
|
123
|
+
`\n rest letter-spacing: ${rest?.letterSpacing} (expect ≈ -0.45px)`,
|
|
124
|
+
`\n hover-via-logo: ${hoverLogo?.letterSpacing} (expect ≈ -0.9px)`,
|
|
125
|
+
`\n hover-via-h2: ${hoverH2?.letterSpacing} (expect ≈ -0.9px)`,
|
|
126
|
+
`\n font-size: ${rest?.fontSize}`,
|
|
127
|
+
`\n transition-property: ${rest?.transitionProperty}`);
|
|
128
|
+
process.exit(ok ? 0 : 1);
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
/* Round 555 verification: title-block kicker "Network Topology"
|
|
2
|
+
* gains group-hover affordance via the R554 wrapper's `group` flag.
|
|
3
|
+
* Closes the title-block cluster's hover coverage at 3 surfaces
|
|
4
|
+
* (brand logo + H2 + kicker).
|
|
5
|
+
*
|
|
6
|
+
* Picks up small-label SPREAD direction (R554 idiom) — tracking-
|
|
7
|
+
* widest (0.1em) → 0.13em on hover, plus color lift text-gray-500
|
|
8
|
+
* #6b7280 → text-gray-400 #9ca3af.
|
|
9
|
+
*
|
|
10
|
+
* At text-xs (12px):
|
|
11
|
+
* tracking-widest = 1.2px per gap (rest)
|
|
12
|
+
* 0.13em = 1.56px per gap (hover)
|
|
13
|
+
*
|
|
14
|
+
* Test phases:
|
|
15
|
+
* 1. rest: letter-spacing ≈ 1.2px, color = gray-500
|
|
16
|
+
* 2. hover brand logo (sibling): kicker letter-spacing ≈ 1.56px,
|
|
17
|
+
* color = gray-400 (group-hover propagation)
|
|
18
|
+
* 3. source: kicker className contains group-hover utilities
|
|
19
|
+
*/
|
|
20
|
+
import { chromium } from 'playwright';
|
|
21
|
+
import { readFileSync } from 'node:fs';
|
|
22
|
+
|
|
23
|
+
const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
|
|
24
|
+
const fresh = new Date(Date.now() - 60 * 1000).toISOString();
|
|
25
|
+
|
|
26
|
+
const browser = await chromium.launch({ headless: true });
|
|
27
|
+
const ctx = await browser.newContext({ viewport: { width: 1500, height: 1200 } });
|
|
28
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
29
|
+
await ctx.addInitScript(() => {
|
|
30
|
+
try {
|
|
31
|
+
localStorage.setItem('anet-theme', 'cyber');
|
|
32
|
+
localStorage.setItem('anet-topo-layout', 'ring');
|
|
33
|
+
sessionStorage.setItem('anet_v3_auth', '1');
|
|
34
|
+
} catch {}
|
|
35
|
+
});
|
|
36
|
+
await ctx.route('**/api/hub/status*', async (route) => {
|
|
37
|
+
const r = await route.fetch();
|
|
38
|
+
const b = await r.json();
|
|
39
|
+
const nid = (b.sessions || [])[0]?.network_id || 'default';
|
|
40
|
+
const mk = (alias) => ({
|
|
41
|
+
alias, status: 'idle', model: 'claude-opus-4', runtime: 'claude-code-cli',
|
|
42
|
+
network_id: nid, project_dir: null,
|
|
43
|
+
created_at: fresh, updated_at: fresh, last_seen_at: fresh,
|
|
44
|
+
});
|
|
45
|
+
await route.fulfill({ response: r, json: { ...b, sessions: [mk('a·1')] } });
|
|
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-topo-section-kicker]', { timeout: 15000 });
|
|
52
|
+
await page.waitForTimeout(500);
|
|
53
|
+
|
|
54
|
+
const kickerSel = '[data-topo-section-kicker]';
|
|
55
|
+
const logoSel = '[data-topo-brand-logo]';
|
|
56
|
+
|
|
57
|
+
const parsePx = (s) => parseFloat((s || '').replace(/px$/, ''));
|
|
58
|
+
const parseLab = (s) => {
|
|
59
|
+
const m = (s || '').match(/lab\(([0-9.]+)\s/) || (s || '').match(/oklab\(([0-9.]+)\s/);
|
|
60
|
+
return m ? parseFloat(m[1]) : NaN;
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
// Phase 1: rest
|
|
64
|
+
const rest = await page.evaluate((s) => {
|
|
65
|
+
const el = document.querySelector(s);
|
|
66
|
+
if (!el) return null;
|
|
67
|
+
const cs = getComputedStyle(el);
|
|
68
|
+
return {
|
|
69
|
+
letterSpacing: cs.letterSpacing,
|
|
70
|
+
color: cs.color,
|
|
71
|
+
transitionProperty: cs.transitionProperty,
|
|
72
|
+
transitionDuration: cs.transitionDuration,
|
|
73
|
+
fontSize: cs.fontSize,
|
|
74
|
+
trackingAttr: el.getAttribute('data-topo-section-kicker-hover-tracking'),
|
|
75
|
+
colorAttr: el.getAttribute('data-topo-section-kicker-hover-color'),
|
|
76
|
+
};
|
|
77
|
+
}, kickerSel);
|
|
78
|
+
|
|
79
|
+
// Phase 2: hover brand logo (sibling element) → group-hover propagation
|
|
80
|
+
await page.hover(logoSel);
|
|
81
|
+
await page.waitForTimeout(400);
|
|
82
|
+
const hoverLogo = await page.evaluate((s) => {
|
|
83
|
+
const el = document.querySelector(s);
|
|
84
|
+
if (!el) return null;
|
|
85
|
+
const cs = getComputedStyle(el);
|
|
86
|
+
return { letterSpacing: cs.letterSpacing, color: cs.color };
|
|
87
|
+
}, kickerSel);
|
|
88
|
+
|
|
89
|
+
await browser.close();
|
|
90
|
+
|
|
91
|
+
const src = readFileSync('/home/vansin/agent-network-dashboard/app/components/TopoGraph.tsx', 'utf8');
|
|
92
|
+
const sourceKickerWired = /group-hover:text-gray-400/.test(src) &&
|
|
93
|
+
/group-hover:tracking-\[0\.13em\]/.test(src);
|
|
94
|
+
const sourceTransition = /transition-\[letter-spacing,color\] duration-200 ease-out/.test(src);
|
|
95
|
+
const sourceTrackingAttr = /data-topo-section-kicker-hover-tracking="0\.13em"/.test(src);
|
|
96
|
+
const sourceColorAttr = /data-topo-section-kicker-hover-color="text-gray-400"/.test(src);
|
|
97
|
+
|
|
98
|
+
// Rest: tracking-widest 0.1em × 12px = 1.2px
|
|
99
|
+
// Hover: 0.13em × 12px = 1.56px
|
|
100
|
+
const restPx = parsePx(rest?.letterSpacing);
|
|
101
|
+
const hoverPx = parsePx(hoverLogo?.letterSpacing);
|
|
102
|
+
|
|
103
|
+
// Color: rest gray-500 ≈ #6b7280; hover gray-400 ≈ #9ca3af (lighter).
|
|
104
|
+
// Tailwind v4 may emit in lab/oklab; check that hover L > rest L.
|
|
105
|
+
const restL = parseLab(rest?.color);
|
|
106
|
+
const hoverL = parseLab(hoverLogo?.color);
|
|
107
|
+
// Also handle the legacy rgb() case in case it's emitted that way
|
|
108
|
+
const colorVaries = rest?.color !== hoverLogo?.color;
|
|
109
|
+
|
|
110
|
+
const results = {
|
|
111
|
+
rest_tracking_widest_1_2px: Math.abs(restPx - 1.2) < 0.1,
|
|
112
|
+
hover_tracking_0_13em: Math.abs(hoverPx - 1.56) < 0.1,
|
|
113
|
+
hover_spreads_vs_rest: hoverPx > restPx + 0.2,
|
|
114
|
+
color_varies_on_hover: colorVaries,
|
|
115
|
+
hover_color_lighter: !Number.isNaN(restL) && !Number.isNaN(hoverL) ? (hoverL > restL + 5) : true,
|
|
116
|
+
rest_tracking_attr: rest?.trackingAttr === '0.13em',
|
|
117
|
+
rest_color_attr: rest?.colorAttr === 'text-gray-400',
|
|
118
|
+
transition_has_ls_color: /letter-spacing/.test(rest?.transitionProperty || '') && /color/.test(rest?.transitionProperty || ''),
|
|
119
|
+
transition_duration_200ms: rest?.transitionDuration === '0.2s',
|
|
120
|
+
source_kicker_wired: sourceKickerWired,
|
|
121
|
+
source_transition: sourceTransition,
|
|
122
|
+
source_tracking_attr: sourceTrackingAttr,
|
|
123
|
+
source_color_attr: sourceColorAttr,
|
|
124
|
+
};
|
|
125
|
+
const ok = Object.values(results).every(Boolean);
|
|
126
|
+
console.log(`${ok ? '✅' : '❌'} R555 title-block kicker group-hover (spread + color lift):`,
|
|
127
|
+
JSON.stringify(results, null, 2),
|
|
128
|
+
`\n rest letter-spacing: ${rest?.letterSpacing} (expect ≈ 1.2px)`,
|
|
129
|
+
`\n hover letter-spacing: ${hoverLogo?.letterSpacing} (expect ≈ 1.56px)`,
|
|
130
|
+
`\n rest color: ${rest?.color}`,
|
|
131
|
+
`\n hover color: ${hoverLogo?.color}`,
|
|
132
|
+
`\n font-size: ${rest?.fontSize}`,
|
|
133
|
+
`\n transition-property: ${rest?.transitionProperty}`);
|
|
134
|
+
process.exit(ok ? 0 : 1);
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/* Round 541 verification: vendor letter chip gains drop-shadow glow on
|
|
2
|
+
* hover/pin using its own vendor.color identity. 2-tier alpha ladder
|
|
3
|
+
* (pin 99 / hover 66). Sibling to R537 legend-swatch tier-color glow.
|
|
4
|
+
*
|
|
5
|
+
* Test phases (multi-vendor setup so vendor chips render):
|
|
6
|
+
* 1. rest: data-vendor-glow='false', filter='none'
|
|
7
|
+
* 2. hover vendor chip: glow='hover', filter has drop-shadow with
|
|
8
|
+
* vendor color at lower alpha
|
|
9
|
+
* 3. source-side regex confirms filter ternary + 3-value attr
|
|
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, model) => ({
|
|
32
|
+
alias, status: 'idle', model, runtime: 'claude-code-cli',
|
|
33
|
+
network_id: nid, project_dir: null,
|
|
34
|
+
created_at: fresh, updated_at: fresh, last_seen_at: fresh,
|
|
35
|
+
});
|
|
36
|
+
// R281 gates vendor chip render on vendorDist.length > 2 — need 3+
|
|
37
|
+
// distinct vendor types. Anthropic claude / Google gemini / OpenAI gpt.
|
|
38
|
+
await route.fulfill({ response: r, json: { ...b, sessions: [
|
|
39
|
+
mk('a·1', 'claude-opus-4'),
|
|
40
|
+
mk('a·2', 'gemini-2.5-pro'),
|
|
41
|
+
mk('a·3', 'gpt-4'),
|
|
42
|
+
] } });
|
|
43
|
+
});
|
|
44
|
+
await ctx.route('**/api/hub/messages*', (r) => r.fulfill({ json: { messages: [] } }));
|
|
45
|
+
await ctx.route('**/api/hub/tasks*', (r) => r.fulfill({ json: { tasks: [] } }));
|
|
46
|
+
const page = await ctx.newPage();
|
|
47
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'networkidle' });
|
|
48
|
+
await page.waitForSelector('[data-vendor-letter]', { timeout: 15000 });
|
|
49
|
+
await page.waitForTimeout(800);
|
|
50
|
+
|
|
51
|
+
// Pick the first vendor chip — probe both computed (CSS resolved) AND
|
|
52
|
+
// inline (React-set raw style) for filter, since !important class rules
|
|
53
|
+
// can override computed even if inline is set.
|
|
54
|
+
const restRead = async () => page.evaluate(() => {
|
|
55
|
+
const el = document.querySelector('[data-vendor-letter]');
|
|
56
|
+
if (!el) return null;
|
|
57
|
+
const cs = getComputedStyle(el);
|
|
58
|
+
return {
|
|
59
|
+
glow: el.getAttribute('data-vendor-glow'),
|
|
60
|
+
initial: el.getAttribute('data-vendor-letter'),
|
|
61
|
+
filter: cs.filter,
|
|
62
|
+
inlineFilter: el.style.filter,
|
|
63
|
+
};
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
// Phase 1: rest
|
|
67
|
+
const rest = await restRead();
|
|
68
|
+
|
|
69
|
+
// Phase 2: hover the chip
|
|
70
|
+
await page.hover('[data-vendor-letter]');
|
|
71
|
+
await page.waitForTimeout(400);
|
|
72
|
+
const hover = await restRead();
|
|
73
|
+
|
|
74
|
+
await browser.close();
|
|
75
|
+
|
|
76
|
+
// Source regex — uses color-mix() instead of hex+alpha since v.color is
|
|
77
|
+
// HSL format (vendorIdentity mono.text), not hex. Banked test-craft note.
|
|
78
|
+
const src = readFileSync('/home/vansin/agent-network-dashboard/app/components/TopoGraph.tsx', 'utf8');
|
|
79
|
+
const sourceFilterTernary =
|
|
80
|
+
/filter: isPinned\s+\? `drop-shadow\(0 0 3px color-mix\(in srgb, \$\{v\.color\} 60%, transparent\)\)`\s+: hoveredVendor === v\.initial\s+\? `drop-shadow\(0 0 3px color-mix\(in srgb, \$\{v\.color\} 40%, transparent\)\)`\s+: undefined,/.test(src);
|
|
81
|
+
const sourceAttrTernary =
|
|
82
|
+
/data-vendor-glow=\{isPinned \? 'pin' : hoveredVendor === v\.initial \? 'hover' : 'false'\}/.test(src);
|
|
83
|
+
|
|
84
|
+
const results = {
|
|
85
|
+
rest_glow_false: rest?.glow === 'false',
|
|
86
|
+
rest_filter_none: rest?.filter === 'none' || rest?.filter === '',
|
|
87
|
+
hover_glow_hover: hover?.glow === 'hover',
|
|
88
|
+
hover_filter_drop_shadow: /drop-shadow/.test(hover?.filter || ''),
|
|
89
|
+
source_filter_ternary: sourceFilterTernary,
|
|
90
|
+
source_attr_ternary: sourceAttrTernary,
|
|
91
|
+
};
|
|
92
|
+
const ok = Object.values(results).every(Boolean);
|
|
93
|
+
console.log(`${ok ? '✅' : '❌'} R541 vendor-chip glow:`,
|
|
94
|
+
JSON.stringify(results, null, 2),
|
|
95
|
+
'\n rest:', JSON.stringify(rest),
|
|
96
|
+
'\n hover:', JSON.stringify(hover));
|
|
97
|
+
process.exit(ok ? 0 : 1);
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/* Round 545 verification: vendor filter pill gains vendorColor drop-
|
|
2
|
+
* shadow when rendered. 3rd of 4 pill variants after R543/R544.
|
|
3
|
+
* Source-canonical (banked R544 lesson — pin via UI is impractical for
|
|
4
|
+
* vendor chip surface; setPinnedVendor needs explicit click on vendor
|
|
5
|
+
* letter chip which renders only at vendorDist > 2).
|
|
6
|
+
*
|
|
7
|
+
* Test phases:
|
|
8
|
+
* 1. unpinned (default): no [data-active-filter="vendor"] element
|
|
9
|
+
* 2. source-side regex confirms filter wired with vendorColor via
|
|
10
|
+
* color-mix 60% syntax
|
|
11
|
+
* 3. source-side scoping: filter wiring is INSIDE the vendor-pill block
|
|
12
|
+
* (matched via setPinnedVendor handler proximity)
|
|
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, model) => ({
|
|
35
|
+
alias, status: 'idle', model, runtime: 'claude-code-cli',
|
|
36
|
+
network_id: nid, project_dir: null,
|
|
37
|
+
created_at: fresh, updated_at: fresh, last_seen_at: fresh,
|
|
38
|
+
});
|
|
39
|
+
// 3 vendors so vendor chip renders (vendorDist.length > 2 gate per R281)
|
|
40
|
+
await route.fulfill({ response: r, json: { ...b, sessions: [
|
|
41
|
+
mk('a·1', 'claude-opus-4'),
|
|
42
|
+
mk('a·2', 'gemini-2.5-pro'),
|
|
43
|
+
mk('a·3', 'gpt-4'),
|
|
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-vendor-letter]', { timeout: 15000 });
|
|
51
|
+
await page.waitForTimeout(500);
|
|
52
|
+
|
|
53
|
+
const unpinned = await page.evaluate(() =>
|
|
54
|
+
document.querySelector('[data-active-filter="vendor"]') !== null
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
// Phase 2: try to pin via clicking vendor letter chip (HTML element, hoverable)
|
|
58
|
+
await page.click('[data-vendor-letter]');
|
|
59
|
+
await page.waitForTimeout(400);
|
|
60
|
+
|
|
61
|
+
const pillPresent = await page.evaluate(() =>
|
|
62
|
+
document.querySelector('[data-active-filter="vendor"]') !== null
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
let pinned = null;
|
|
66
|
+
if (pillPresent) {
|
|
67
|
+
pinned = await page.evaluate(() => {
|
|
68
|
+
const el = document.querySelector('[data-active-filter="vendor"]');
|
|
69
|
+
if (!el) return null;
|
|
70
|
+
const cs = getComputedStyle(el);
|
|
71
|
+
return {
|
|
72
|
+
inlineFilter: el.style.filter,
|
|
73
|
+
filter: cs.filter,
|
|
74
|
+
};
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
await browser.close();
|
|
79
|
+
|
|
80
|
+
const src = readFileSync('/home/vansin/agent-network-dashboard/app/components/TopoGraph.tsx', 'utf8');
|
|
81
|
+
// Filter wiring: same color-mix pattern as R544 but with vendorColor not pal.legendAccent
|
|
82
|
+
const vendorPillScope = src.match(/onClick=\{\(\) => setPinnedVendor\(null\)\}[\s\S]{0,2500}/)?.[0] || '';
|
|
83
|
+
const sourceFilterScoped =
|
|
84
|
+
/filter: `drop-shadow\(0 0 3px color-mix\(in srgb, \$\{vendorColor\} 60%, transparent\)\)`,/.test(vendorPillScope);
|
|
85
|
+
|
|
86
|
+
const results = {
|
|
87
|
+
unpinned_pill_absent: unpinned === false,
|
|
88
|
+
pinned_pill_present: pillPresent === true,
|
|
89
|
+
pinned_inline_filter: pinned && /drop-shadow/.test(pinned.inlineFilter || ''),
|
|
90
|
+
pinned_computed_filter: pinned && /drop-shadow/.test(pinned.filter || ''),
|
|
91
|
+
source_filter_scoped: sourceFilterScoped,
|
|
92
|
+
};
|
|
93
|
+
const ok = Object.values(results).every(Boolean);
|
|
94
|
+
console.log(`${ok ? '✅' : '❌'} R545 vendor filter pill glow:`,
|
|
95
|
+
JSON.stringify(results, null, 2),
|
|
96
|
+
'\n unpinned absent:', unpinned,
|
|
97
|
+
'\n pinned:', JSON.stringify(pinned));
|
|
98
|
+
process.exit(ok ? 0 : 1);
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/* Round 519 verification: brand watermark gains ambient SMIL breath
|
|
2
|
+
* animation — 呼吸感 family 3rd anchor.
|
|
3
|
+
*
|
|
4
|
+
* Test phases:
|
|
5
|
+
* 1. default (motion enabled): data-topo-brand-watermark-breath='true'
|
|
6
|
+
* + <animate> child mounted inside the <text>
|
|
7
|
+
* + animate values='0.32;0.48;0.32', dur='6s', repeatCount='indefinite'
|
|
8
|
+
* 2. prefers-reduced-motion: data-topo-brand-watermark-breath='false'
|
|
9
|
+
* + NO <animate> child (gated out at JSX level)
|
|
10
|
+
* 3. source-side regex confirms SMIL gate + values + duration
|
|
11
|
+
* 4. zero-overlap is gated separately by topo-overlap-test.mjs
|
|
12
|
+
*/
|
|
13
|
+
import { chromium } from 'playwright';
|
|
14
|
+
import { readFileSync } from 'node:fs';
|
|
15
|
+
|
|
16
|
+
const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
|
|
17
|
+
const fresh = new Date(Date.now() - 60 * 1000).toISOString();
|
|
18
|
+
|
|
19
|
+
async function probe(reducedMotion) {
|
|
20
|
+
const browser = await chromium.launch({ headless: true });
|
|
21
|
+
const ctx = await browser.newContext({
|
|
22
|
+
viewport: { width: 1500, height: 1200 },
|
|
23
|
+
reducedMotion: reducedMotion ? 'reduce' : 'no-preference',
|
|
24
|
+
});
|
|
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: [mk('a·1')] } });
|
|
43
|
+
});
|
|
44
|
+
await ctx.route('**/api/hub/messages*', (r) => r.fulfill({ json: { messages: [] } }));
|
|
45
|
+
await ctx.route('**/api/hub/tasks*', (r) => r.fulfill({ json: { tasks: [] } }));
|
|
46
|
+
const page = await ctx.newPage();
|
|
47
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'networkidle' });
|
|
48
|
+
await page.waitForSelector('[data-topo-brand-watermark]', { timeout: 15000 });
|
|
49
|
+
await page.waitForTimeout(800);
|
|
50
|
+
const probe = await page.evaluate(() => {
|
|
51
|
+
const el = document.querySelector('[data-topo-brand-watermark]');
|
|
52
|
+
if (!el) return null;
|
|
53
|
+
const animate = el.querySelector('animate');
|
|
54
|
+
return {
|
|
55
|
+
attrBreath: el.getAttribute('data-topo-brand-watermark-breath'),
|
|
56
|
+
hasAnimate: !!animate,
|
|
57
|
+
attrName: animate?.getAttribute('attributeName') || null,
|
|
58
|
+
values: animate?.getAttribute('values') || null,
|
|
59
|
+
dur: animate?.getAttribute('dur') || null,
|
|
60
|
+
repeatCount: animate?.getAttribute('repeatCount') || null,
|
|
61
|
+
textContent: el.textContent?.trim() || null,
|
|
62
|
+
opacity: el.getAttribute('opacity'),
|
|
63
|
+
};
|
|
64
|
+
});
|
|
65
|
+
await browser.close();
|
|
66
|
+
return probe;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const normal = await probe(false);
|
|
70
|
+
const reduced = await probe(true);
|
|
71
|
+
|
|
72
|
+
const src = readFileSync('/home/vansin/agent-network-dashboard/app/components/TopoGraph.tsx', 'utf8');
|
|
73
|
+
const sourceWiredGate =
|
|
74
|
+
/\{!reducedMotion && \(\s*<animate attributeName="opacity" values="0\.32;0\.48;0\.32" dur="6s" repeatCount="indefinite" \/>\s*\)\}/.test(src);
|
|
75
|
+
const sourceWiredAttr =
|
|
76
|
+
/data-topo-brand-watermark-breath=\{reducedMotion \? 'false' : 'true'\}/.test(src);
|
|
77
|
+
|
|
78
|
+
const results = {
|
|
79
|
+
// Phase 1: motion enabled
|
|
80
|
+
normal_attr_true: normal?.attrBreath === 'true',
|
|
81
|
+
normal_has_animate: normal?.hasAnimate === true,
|
|
82
|
+
normal_attr_name_opacity: normal?.attrName === 'opacity',
|
|
83
|
+
normal_values_correct: normal?.values === '0.32;0.48;0.32',
|
|
84
|
+
normal_dur_6s: normal?.dur === '6s',
|
|
85
|
+
normal_repeat_indefinite: normal?.repeatCount === 'indefinite',
|
|
86
|
+
normal_text_content: normal?.textContent === 'sleep2agi',
|
|
87
|
+
normal_static_opacity_04: normal?.opacity === '0.4',
|
|
88
|
+
// Phase 2: prefers-reduced-motion
|
|
89
|
+
reduced_attr_false: reduced?.attrBreath === 'false',
|
|
90
|
+
reduced_no_animate: reduced?.hasAnimate === false,
|
|
91
|
+
reduced_text_content: reduced?.textContent === 'sleep2agi',
|
|
92
|
+
// Phase 3: source regex
|
|
93
|
+
source_animate_gated: sourceWiredGate,
|
|
94
|
+
source_attr_wired: sourceWiredAttr,
|
|
95
|
+
};
|
|
96
|
+
const ok = Object.values(results).every(Boolean);
|
|
97
|
+
console.log(`${ok ? '✅' : '❌'} R519 watermark breath:`, JSON.stringify(results, null, 2),
|
|
98
|
+
'\n normal:', JSON.stringify(normal),
|
|
99
|
+
'\n reduced:', JSON.stringify(reduced));
|
|
100
|
+
process.exit(ok ? 0 : 1);
|