@sleep2agi/agent-network-dashboard 0.5.1-preview.99 → 0.5.2-preview.0
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/prerender-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.js.nft.json +1 -1
- 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]__03b.f76._.js → [root-of-the-server]__0sv~g.o._.js} +2 -2
- package/.next/server/chunks/ssr/[root-of-the-server]__0sv~g.o._.js.map +1 -0
- package/.next/server/chunks/ssr/agent-network-dashboard_09kk21a._.js +3 -3
- 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/server/server-reference-manifest.js +1 -1
- package/.next/server/server-reference-manifest.json +1 -1
- package/.next/static/chunks/{0l_~q07bhpkcx.js → 03a4--7ncekmk.js} +1 -1
- package/.next/static/chunks/0a4hmfvj-81x5.css +2 -0
- package/.next/static/chunks/0caxil0dw-oe9.js +4 -0
- package/.next/static/chunks/{03~~oirxz7~vc.js → 0p8xwrfjtykvn.js} +1 -1
- package/.next/static/chunks/0x.m3vy8e5iit.js +1 -0
- package/.next/static/chunks/12gq1w9k_7v06.js +1 -0
- package/.next/trace +2 -2
- package/.next/trace-build +1 -1
- package/app/components/ServersDrawer.tsx +17 -0
- package/app/components/TopoGraph.tsx +770 -76
- package/package.json +1 -1
- package/screenshots/v0.10.2-disk-verify/disk-render-full.png +0 -0
- package/screenshots/v0.10.2-disk-verify/disk-render.png +0 -0
- package/screenshots/v0.11.0-147/after.png +0 -0
- package/scripts/p0-147-screenshot.mjs +53 -0
- package/scripts/p0-servers-drawer-screenshot.mjs +2 -0
- package/scripts/topo-any-hover-attr-test.mjs +83 -0
- package/scripts/topo-any-pinned-attr-test.mjs +86 -0
- package/scripts/topo-chrome-fullscreen-icon-sw-test.mjs +92 -0
- package/scripts/topo-chrome-reset-icon-sw-test.mjs +80 -0
- package/scripts/topo-chrome-zoom-icon-sw-test.mjs +90 -0
- package/scripts/topo-dashboard-version-attr-test.mjs +69 -0
- package/scripts/topo-dense-alias-opacity-test.mjs +68 -0
- package/scripts/topo-edge-particle-hover-r-test.mjs +113 -0
- package/scripts/topo-endpoint-ring-r-hover-test.mjs +89 -0
- package/scripts/topo-fleet-count-attrs-test.mjs +87 -0
- package/scripts/topo-group-box-geom-transition-test.mjs +110 -0
- package/scripts/topo-group-box-rx-pin-test.mjs +103 -0
- package/scripts/topo-group-label-count-fw-test.mjs +100 -0
- package/scripts/topo-group-label-fw-pin-test.mjs +99 -0
- package/scripts/topo-group-label-tint-geom-test.mjs +94 -0
- package/scripts/topo-group-label-tint-transition-test.mjs +97 -0
- package/scripts/topo-group-pip-fontsize-test.mjs +106 -0
- package/scripts/topo-group-tier-attr-test.mjs +84 -0
- package/scripts/topo-group-tint-rx-pin-test.mjs +107 -0
- package/scripts/topo-hub-core-fill-hover-test.mjs +85 -0
- package/scripts/topo-hub-halo-r-hover-test.mjs +82 -0
- package/scripts/topo-legend-count-active-opacity-test.mjs +102 -0
- package/scripts/topo-legend-count-pin-fw-test.mjs +90 -0
- package/scripts/topo-minimap-viewport-opacity-test.mjs +96 -0
- package/scripts/topo-node-halo-hover-opacity-test.mjs +104 -0
- package/scripts/topo-node-halo-light-offline-test.mjs +80 -0
- package/scripts/topo-node-sub-text-fw-test.mjs +75 -0
- package/scripts/topo-overlap-stale-build-guard-test.mjs +66 -0
- package/scripts/topo-overlap-test.mjs +42 -1
- package/scripts/topo-recent-row-count-pin-fw-test.mjs +106 -0
- package/scripts/topo-recent-row-pip-hover-r-test.mjs +104 -0
- package/scripts/topo-runtime-icon-hover-test.mjs +96 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__03b.f76._.js.map +0 -1
- package/.next/static/chunks/0.sf46gnv4wwm.js +0 -1
- package/.next/static/chunks/017hq2-5l~_98.css +0 -2
- package/.next/static/chunks/0_igeywsok2_-.js +0 -1
- package/.next/static/chunks/0igz0bww16uvc.js +0 -4
- /package/.next/static/{4rHxTzLwe2XC9M1rN-MpJ → 5IMzNtH5S5Oqe-FCw1CX4}/_buildManifest.js +0 -0
- /package/.next/static/{4rHxTzLwe2XC9M1rN-MpJ → 5IMzNtH5S5Oqe-FCw1CX4}/_clientMiddlewareManifest.js +0 -0
- /package/.next/static/{4rHxTzLwe2XC9M1rN-MpJ → 5IMzNtH5S5Oqe-FCw1CX4}/_ssgManifest.js +0 -0
package/package.json
CHANGED
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { chromium } from 'playwright';
|
|
2
|
+
import { readFileSync } from 'node:fs';
|
|
3
|
+
const out = process.argv[2] || 'screenshots/v0.11.0-147/after';
|
|
4
|
+
const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
|
|
5
|
+
const browser = await chromium.launch({ headless: true });
|
|
6
|
+
const ctx = await browser.newContext({ viewport: { width: 1600, height: 1400 }, deviceScaleFactor: 2 });
|
|
7
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
8
|
+
await ctx.addInitScript(() => { try { localStorage.setItem('anet-theme', 'cyber'); sessionStorage.setItem('anet_v3_auth', '1'); localStorage.setItem('anet-topo-layout', 'grid'); } catch {} });
|
|
9
|
+
const fresh = new Date(Date.now() - 60_000).toISOString();
|
|
10
|
+
// Build a multi-prefix-group fleet (4 prefixes × 5 nodes = 20 nodes — triggers grid + multiple cluster boxes)
|
|
11
|
+
const sessions = [];
|
|
12
|
+
const prefixes = ['ai-insight', 'agent-network-dashboard', 'p-station', 'pay-blueleap'];
|
|
13
|
+
const models = ['claude-opus-4', 'gpt-4o', 'internlm/internlm2', 'minimax/abab6'];
|
|
14
|
+
prefixes.forEach((prefix, gIdx) => {
|
|
15
|
+
for (let i = 1; i <= 5; i++) {
|
|
16
|
+
sessions.push({
|
|
17
|
+
alias: `${prefix}-node-${i}`,
|
|
18
|
+
status: i === 1 ? 'working' : 'idle',
|
|
19
|
+
model: models[gIdx],
|
|
20
|
+
runtime: 'claude-code-cli',
|
|
21
|
+
network_id: 'default', project_dir: null,
|
|
22
|
+
created_at: fresh, updated_at: fresh, last_seen_at: fresh,
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
await ctx.route('**/api/hub/status*', async (route) => {
|
|
27
|
+
const r = await route.fetch();
|
|
28
|
+
const b = await r.json();
|
|
29
|
+
await route.fulfill({ response: r, json: { ...b, sessions } });
|
|
30
|
+
});
|
|
31
|
+
await ctx.route('**/api/hub/messages*', (r) => r.fulfill({ json: { messages: [] } }));
|
|
32
|
+
await ctx.route('**/api/hub/tasks*', (r) => r.fulfill({ json: { tasks: [] } }));
|
|
33
|
+
const page = await ctx.newPage();
|
|
34
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
|
|
35
|
+
await page.waitForFunction(() => document.querySelectorAll('g[data-node]').length >= 20, { timeout: 30000 });
|
|
36
|
+
await page.waitForTimeout(800);
|
|
37
|
+
const box = await page.evaluate(() => {
|
|
38
|
+
const chrome = document.querySelector('[data-topo-chrome]');
|
|
39
|
+
let card = chrome?.parentElement;
|
|
40
|
+
while (card && !card.querySelector(':scope > svg')) card = card?.parentElement;
|
|
41
|
+
if (!card) return null;
|
|
42
|
+
card.scrollIntoView({ block: 'start' });
|
|
43
|
+
return new Promise(resolve => requestAnimationFrame(() => {
|
|
44
|
+
const r = card.getBoundingClientRect();
|
|
45
|
+
resolve({ x: Math.max(0, r.x), y: Math.max(0, r.y), width: r.width, height: r.height });
|
|
46
|
+
}));
|
|
47
|
+
});
|
|
48
|
+
await page.waitForTimeout(400);
|
|
49
|
+
if (box && box.width > 100) {
|
|
50
|
+
await page.screenshot({ path: `${out}.png`, clip: { x: box.x, y: box.y, width: box.width, height: Math.min(box.height, 980) } });
|
|
51
|
+
}
|
|
52
|
+
console.log(`✅ wrote ${out}.png`);
|
|
53
|
+
await browser.close();
|
|
@@ -35,6 +35,7 @@ await ctx.route('**/api/hub/servers*', (route) => {
|
|
|
35
35
|
disk_total_gb: 500,
|
|
36
36
|
cpu_history: [25, 28, 32, 30, 35, 38, 40, 36, 33, 30],
|
|
37
37
|
mem_history: [50, 52, 55, 56, 58, 57, 59, 60, 58, 57],
|
|
38
|
+
disk_history: [40, 42, 43, 43, 44, 44, 44, 44, 44, 44],
|
|
38
39
|
agents: [
|
|
39
40
|
{ alias: 'claude-1', runtime: 'claude-code-cli', status: 'working', progress: 0.42 },
|
|
40
41
|
{ alias: 'codex-1', runtime: 'codex-sdk', status: 'working', progress: 0.18 },
|
|
@@ -54,6 +55,7 @@ await ctx.route('**/api/hub/servers*', (route) => {
|
|
|
54
55
|
disk_total_gb: 500,
|
|
55
56
|
cpu_history: [80, 88, 92, 95, 96, 94, 93, 91, 90, 89],
|
|
56
57
|
mem_history: [85, 87, 89, 91, 90, 92, 93, 91, 90, 91],
|
|
58
|
+
disk_history: [86, 88, 89, 90, 90, 91, 92, 92, 92, 92],
|
|
57
59
|
agents: [
|
|
58
60
|
{ alias: 'minimax-busy', runtime: 'claude-code-cli', status: 'working', progress: 0.78 },
|
|
59
61
|
],
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/* Round 466 verification: root svg gains `data-topo-any-hover`
|
|
2
|
+
* aggregate hover attr. Composed from 6 per-surface hover vars
|
|
3
|
+
* (hoveredAlias, hoveredHub, hoveredEdgeKey, hoveredGroupLabel,
|
|
4
|
+
* hoveredStatus, hoveredVendor). Read-only computed signal —
|
|
5
|
+
* useful for tests + external CSS hooks.
|
|
6
|
+
*
|
|
7
|
+
* Contract:
|
|
8
|
+
* - at rest (no hover): data-topo-any-hover === 'false'
|
|
9
|
+
* - hover a node: 'true'
|
|
10
|
+
* - leave the node: back to 'false'
|
|
11
|
+
* - source-file conditional wired
|
|
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
|
+
const browser = await chromium.launch({ headless: true });
|
|
20
|
+
const ctx = await browser.newContext({ viewport: { width: 1500, height: 1200 } });
|
|
21
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
22
|
+
await ctx.addInitScript(() => {
|
|
23
|
+
try {
|
|
24
|
+
localStorage.setItem('anet-theme', 'cyber');
|
|
25
|
+
localStorage.setItem('anet-topo-layout', 'grid');
|
|
26
|
+
sessionStorage.setItem('anet_v3_auth', '1');
|
|
27
|
+
} catch {}
|
|
28
|
+
});
|
|
29
|
+
await ctx.route('**/api/hub/status*', async (route) => {
|
|
30
|
+
const r = await route.fetch();
|
|
31
|
+
const b = await r.json();
|
|
32
|
+
const nid = (b.sessions || [])[0]?.network_id || 'default';
|
|
33
|
+
const mk = (alias, status) => ({
|
|
34
|
+
alias, status, model: 'claude-opus-4', runtime: 'claude-code-cli',
|
|
35
|
+
network_id: nid, project_dir: null,
|
|
36
|
+
created_at: fresh, updated_at: fresh, last_seen_at: fresh,
|
|
37
|
+
});
|
|
38
|
+
await route.fulfill({ response: r, json: { ...b, sessions: [
|
|
39
|
+
mk('alpha·1', 'working'),
|
|
40
|
+
mk('alpha·2', 'idle'),
|
|
41
|
+
] } });
|
|
42
|
+
});
|
|
43
|
+
await ctx.route('**/api/hub/messages*', (r) => r.fulfill({ json: { messages: [] } }));
|
|
44
|
+
await ctx.route('**/api/hub/tasks*', (r) => r.fulfill({ json: { tasks: [] } }));
|
|
45
|
+
|
|
46
|
+
const page = await ctx.newPage();
|
|
47
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
|
|
48
|
+
await page.waitForSelector('svg[data-topo-any-hover]', { timeout: 15000 });
|
|
49
|
+
await page.waitForTimeout(400);
|
|
50
|
+
|
|
51
|
+
const readAttr = () => page.evaluate(() =>
|
|
52
|
+
document.querySelector('svg[viewBox="0 0 1000 680"]')?.getAttribute('data-topo-any-hover')
|
|
53
|
+
);
|
|
54
|
+
|
|
55
|
+
const restValue = await readAttr();
|
|
56
|
+
|
|
57
|
+
// Hover a group label to flip hoveredGroupLabel
|
|
58
|
+
await page.hover('[data-group-label-hit]');
|
|
59
|
+
await page.waitForTimeout(200);
|
|
60
|
+
const hoverValue = await readAttr();
|
|
61
|
+
|
|
62
|
+
// Move pointer far away to clear hover
|
|
63
|
+
await page.mouse.move(2, 2);
|
|
64
|
+
await page.waitForTimeout(300);
|
|
65
|
+
const restAgainValue = await readAttr();
|
|
66
|
+
|
|
67
|
+
const src = readFileSync('/home/vansin/agent-network-dashboard/app/components/TopoGraph.tsx', 'utf8');
|
|
68
|
+
const sourceHasAttr = /data-topo-any-hover=\{/.test(src);
|
|
69
|
+
const sourceCombines6Vars = /hoveredAlias \|\| hoveredHub \|\| hoveredEdgeKey \|\| hoveredGroupLabel \|\|/.test(src);
|
|
70
|
+
|
|
71
|
+
await browser.close();
|
|
72
|
+
|
|
73
|
+
const results = {
|
|
74
|
+
rest_is_false: restValue === 'false',
|
|
75
|
+
hover_flips_true: hoverValue === 'true',
|
|
76
|
+
rest_again_is_false: restAgainValue === 'false',
|
|
77
|
+
source_attr_wired: sourceHasAttr,
|
|
78
|
+
source_6_vars: sourceCombines6Vars,
|
|
79
|
+
};
|
|
80
|
+
const ok = Object.values(results).every(Boolean);
|
|
81
|
+
console.log(`${ok ? '✅' : '❌'} data-topo-any-hover aggregate:`, JSON.stringify(results),
|
|
82
|
+
'\n rest:', restValue, '/ hover:', hoverValue, '/ rest again:', restAgainValue);
|
|
83
|
+
process.exit(ok ? 0 : 1);
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/* Round 467 verification: root svg gains `data-topo-any-pinned`
|
|
2
|
+
* aggregate pin attr — sibling to R466 data-topo-any-hover.
|
|
3
|
+
* Composed from 4 pin state vars (pinnedStatus, pinnedGroup,
|
|
4
|
+
* pinnedVendor, pinnedEdgeKey). Together they form a 2-bit
|
|
5
|
+
* inspection-mode signal on the canvas root.
|
|
6
|
+
*
|
|
7
|
+
* Contract:
|
|
8
|
+
* - at rest: data-topo-any-pinned === 'false'
|
|
9
|
+
* - click a group-label hitbox: attr flips to 'true'
|
|
10
|
+
* - press Escape (R62/R63/R88/R116 universal-cancel): back to 'false'
|
|
11
|
+
* - source-file conditional wired
|
|
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
|
+
const browser = await chromium.launch({ headless: true });
|
|
20
|
+
const ctx = await browser.newContext({ viewport: { width: 1500, height: 1200 } });
|
|
21
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
22
|
+
await ctx.addInitScript(() => {
|
|
23
|
+
try {
|
|
24
|
+
localStorage.setItem('anet-theme', 'cyber');
|
|
25
|
+
localStorage.setItem('anet-topo-layout', 'grid');
|
|
26
|
+
sessionStorage.setItem('anet_v3_auth', '1');
|
|
27
|
+
} catch {}
|
|
28
|
+
});
|
|
29
|
+
await ctx.route('**/api/hub/status*', async (route) => {
|
|
30
|
+
const r = await route.fetch();
|
|
31
|
+
const b = await r.json();
|
|
32
|
+
const nid = (b.sessions || [])[0]?.network_id || 'default';
|
|
33
|
+
const mk = (alias, status) => ({
|
|
34
|
+
alias, status, model: 'claude-opus-4', runtime: 'claude-code-cli',
|
|
35
|
+
network_id: nid, project_dir: null,
|
|
36
|
+
created_at: fresh, updated_at: fresh, last_seen_at: fresh,
|
|
37
|
+
});
|
|
38
|
+
await route.fulfill({ response: r, json: { ...b, sessions: [
|
|
39
|
+
mk('alpha·1', 'working'),
|
|
40
|
+
mk('alpha·2', 'idle'),
|
|
41
|
+
mk('beta·1', 'working'),
|
|
42
|
+
mk('beta·2', 'idle'),
|
|
43
|
+
] } });
|
|
44
|
+
});
|
|
45
|
+
await ctx.route('**/api/hub/messages*', (r) => r.fulfill({ json: { messages: [] } }));
|
|
46
|
+
await ctx.route('**/api/hub/tasks*', (r) => r.fulfill({ json: { tasks: [] } }));
|
|
47
|
+
|
|
48
|
+
const page = await ctx.newPage();
|
|
49
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
|
|
50
|
+
await page.waitForSelector('svg[data-topo-any-pinned]', { timeout: 15000 });
|
|
51
|
+
await page.waitForTimeout(400);
|
|
52
|
+
|
|
53
|
+
const readAttr = () => page.evaluate(() =>
|
|
54
|
+
document.querySelector('svg[viewBox="0 0 1000 680"]')?.getAttribute('data-topo-any-pinned')
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
const restValue = await readAttr();
|
|
58
|
+
|
|
59
|
+
// Click group-label hitbox → pinnedGroup flips
|
|
60
|
+
await page.click('[data-group-label-hit]');
|
|
61
|
+
await page.waitForTimeout(300);
|
|
62
|
+
const pinnedValue = await readAttr();
|
|
63
|
+
|
|
64
|
+
// Esc → universal cancel
|
|
65
|
+
await page.mouse.move(500, 400); // move off the hitbox so Esc isn't swallowed
|
|
66
|
+
await page.keyboard.press('Escape');
|
|
67
|
+
await page.waitForTimeout(300);
|
|
68
|
+
const restAgainValue = await readAttr();
|
|
69
|
+
|
|
70
|
+
const src = readFileSync('/home/vansin/agent-network-dashboard/app/components/TopoGraph.tsx', 'utf8');
|
|
71
|
+
const sourceHasAttr = /data-topo-any-pinned=\{/.test(src);
|
|
72
|
+
const sourceCombines4Vars = /pinnedStatus \|\| pinnedGroup \|\| pinnedVendor \|\| pinnedEdgeKey/.test(src);
|
|
73
|
+
|
|
74
|
+
await browser.close();
|
|
75
|
+
|
|
76
|
+
const results = {
|
|
77
|
+
rest_is_false: restValue === 'false',
|
|
78
|
+
click_flips_true: pinnedValue === 'true',
|
|
79
|
+
esc_resets_false: restAgainValue === 'false',
|
|
80
|
+
source_attr_wired: sourceHasAttr,
|
|
81
|
+
source_4_vars: sourceCombines4Vars,
|
|
82
|
+
};
|
|
83
|
+
const ok = Object.values(results).every(Boolean);
|
|
84
|
+
console.log(`${ok ? '✅' : '❌'} data-topo-any-pinned aggregate:`, JSON.stringify(results),
|
|
85
|
+
'\n rest:', restValue, '/ pinned:', pinnedValue, '/ esc:', restAgainValue);
|
|
86
|
+
process.exit(ok ? 0 : 1);
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/* Round 455 verification: chrome fullscreen icon (ENTER + EXIT
|
|
2
|
+
* variants) strokeWidth hover lift via Tailwind arbitrary class
|
|
3
|
+
* group-hover:[stroke-width:2.8]. Completes the chrome icon hover
|
|
4
|
+
* sw lift family (6 anchors).
|
|
5
|
+
*
|
|
6
|
+
* Contract:
|
|
7
|
+
* - rest: fullscreen-enter icon reports attr stroke-width '2.5' +
|
|
8
|
+
* computed '2.5px'
|
|
9
|
+
* - hover the fullscreen button: that icon computed '2.8px'
|
|
10
|
+
* - source-file probe confirms BOTH variants (enter + exit) carry
|
|
11
|
+
* the group-hover:[stroke-width:2.8] class
|
|
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
|
+
const browser = await chromium.launch({ headless: true });
|
|
20
|
+
const ctx = await browser.newContext({ viewport: { width: 1500, height: 1500 } });
|
|
21
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
22
|
+
await ctx.addInitScript(() => {
|
|
23
|
+
try { localStorage.setItem('anet-theme', 'cyber'); sessionStorage.setItem('anet_v3_auth', '1'); } catch {}
|
|
24
|
+
});
|
|
25
|
+
await ctx.route('**/api/hub/status*', async (route) => {
|
|
26
|
+
const r = await route.fetch();
|
|
27
|
+
const b = await r.json();
|
|
28
|
+
const nid = (b.sessions || [])[0]?.network_id || 'default';
|
|
29
|
+
const mk = (alias, status) => ({
|
|
30
|
+
alias, status, model: 'claude-opus-4', runtime: 'claude-code-cli',
|
|
31
|
+
network_id: nid, project_dir: null,
|
|
32
|
+
created_at: fresh, updated_at: fresh, last_seen_at: fresh,
|
|
33
|
+
});
|
|
34
|
+
await route.fulfill({ response: r, json: { ...b, sessions: [
|
|
35
|
+
mk('alpha', 'working'),
|
|
36
|
+
mk('beta', 'idle'),
|
|
37
|
+
] } });
|
|
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
|
+
|
|
42
|
+
const page = await ctx.newPage();
|
|
43
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
|
|
44
|
+
await page.waitForSelector('[data-topo-chrome-fullscreen-icon]', { timeout: 15000 });
|
|
45
|
+
await page.waitForTimeout(400);
|
|
46
|
+
|
|
47
|
+
const readIcon = () => page.evaluate(() => {
|
|
48
|
+
const i = document.querySelector('[data-topo-chrome-fullscreen-icon]');
|
|
49
|
+
return i ? {
|
|
50
|
+
variant: i.getAttribute('data-topo-chrome-fullscreen-icon'),
|
|
51
|
+
sw_attr: i.getAttribute('stroke-width'),
|
|
52
|
+
sw_computed: getComputedStyle(i).strokeWidth,
|
|
53
|
+
} : null;
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
const rest = await readIcon();
|
|
57
|
+
|
|
58
|
+
// Hover the fullscreen button parent — the button shares the group
|
|
59
|
+
// scope with the SVG icon child via Tailwind group/group-hover utility.
|
|
60
|
+
let hover = null;
|
|
61
|
+
const btn = await page.$('button[aria-label*="fullscreen" i], button[title*="ullscreen" i]');
|
|
62
|
+
if (btn) {
|
|
63
|
+
await btn.hover({ force: true });
|
|
64
|
+
await page.waitForTimeout(300);
|
|
65
|
+
hover = await readIcon();
|
|
66
|
+
await page.mouse.move(0, 0);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const fileText = readFileSync('/home/vansin/agent-network-dashboard/app/components/TopoGraph.tsx', 'utf8');
|
|
70
|
+
// className appears in TWO fullscreen-icon SVGs (enter + exit). Probe
|
|
71
|
+
// for both variants via separate searches:
|
|
72
|
+
const sourceFullscreenIconCount = (fileText.match(/data-topo-chrome-fullscreen-icon=/g) || []).length;
|
|
73
|
+
const sourceArbitrarySwCount = (fileText.match(/group-hover:\[stroke-width:2\.8\]/g) || []).length;
|
|
74
|
+
// We expect: zoom-in + zoom-out + fullscreen-enter + fullscreen-exit = 4 total
|
|
75
|
+
const sourceFourMatches = sourceArbitrarySwCount >= 4;
|
|
76
|
+
|
|
77
|
+
await browser.close();
|
|
78
|
+
|
|
79
|
+
const results = {
|
|
80
|
+
rest_mounted: !!rest,
|
|
81
|
+
rest_attr_2_5: rest?.sw_attr === '2.5',
|
|
82
|
+
rest_computed_2_5: rest?.sw_computed === '2.5px' || rest?.sw_computed === '2.5',
|
|
83
|
+
hover_computed_2_8: hover?.sw_computed === '2.8px' || hover?.sw_computed === '2.8',
|
|
84
|
+
source_fullscreen_variants: sourceFullscreenIconCount === 2,
|
|
85
|
+
source_arbitrary_4_matches: sourceFourMatches,
|
|
86
|
+
};
|
|
87
|
+
const ok = Object.values(results).every(Boolean);
|
|
88
|
+
console.log(`${ok ? '✅' : '❌'} chrome fullscreen icon sw hover:`, JSON.stringify(results),
|
|
89
|
+
'\n rest:', JSON.stringify(rest),
|
|
90
|
+
'\n hover:', JSON.stringify(hover),
|
|
91
|
+
'\n source matches: variants=' + sourceFullscreenIconCount + ' arbitrary-sw=' + sourceArbitrarySwCount);
|
|
92
|
+
process.exit(ok ? 0 : 1);
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/* Round 453 verification: chrome reset icon strokeWidth hover lift —
|
|
2
|
+
* 2.5 → 2.8 on hoveredReset && !resetSpinning. Sibling to R443
|
|
3
|
+
* runtime badge inner-icon sw lift.
|
|
4
|
+
*
|
|
5
|
+
* Contract:
|
|
6
|
+
* - rest: reset icon reports stroke-width '2.5' + hover='false'
|
|
7
|
+
* - hover the reset button: icon stroke-width '2.8' + hover='true'
|
|
8
|
+
*/
|
|
9
|
+
import { chromium } from 'playwright';
|
|
10
|
+
import { readFileSync } from 'node:fs';
|
|
11
|
+
|
|
12
|
+
const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
|
|
13
|
+
const fresh = new Date(Date.now() - 60 * 1000).toISOString();
|
|
14
|
+
|
|
15
|
+
const browser = await chromium.launch({ headless: true });
|
|
16
|
+
const ctx = await browser.newContext({ viewport: { width: 1500, height: 1500 } });
|
|
17
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
18
|
+
await ctx.addInitScript(() => {
|
|
19
|
+
try { localStorage.setItem('anet-theme', 'cyber'); sessionStorage.setItem('anet_v3_auth', '1'); } catch {}
|
|
20
|
+
});
|
|
21
|
+
await ctx.route('**/api/hub/status*', async (route) => {
|
|
22
|
+
const r = await route.fetch();
|
|
23
|
+
const b = await r.json();
|
|
24
|
+
const nid = (b.sessions || [])[0]?.network_id || 'default';
|
|
25
|
+
const mk = (alias, status) => ({
|
|
26
|
+
alias, status, model: 'claude-opus-4', runtime: 'claude-code-cli',
|
|
27
|
+
network_id: nid, project_dir: null,
|
|
28
|
+
created_at: fresh, updated_at: fresh, last_seen_at: fresh,
|
|
29
|
+
});
|
|
30
|
+
await route.fulfill({ response: r, json: { ...b, sessions: [
|
|
31
|
+
mk('alpha', 'working'),
|
|
32
|
+
mk('beta', 'idle'),
|
|
33
|
+
] } });
|
|
34
|
+
});
|
|
35
|
+
await ctx.route('**/api/hub/messages*', (r) => r.fulfill({ json: { messages: [] } }));
|
|
36
|
+
await ctx.route('**/api/hub/tasks*', (r) => r.fulfill({ json: { tasks: [] } }));
|
|
37
|
+
|
|
38
|
+
const page = await ctx.newPage();
|
|
39
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
|
|
40
|
+
await page.waitForSelector('[data-topo-chrome-reset-icon]', { timeout: 15000 });
|
|
41
|
+
await page.waitForTimeout(400);
|
|
42
|
+
|
|
43
|
+
const readIcon = () => page.evaluate(() => {
|
|
44
|
+
const i = document.querySelector('[data-topo-chrome-reset-icon]');
|
|
45
|
+
return i ? {
|
|
46
|
+
sw: i.getAttribute('stroke-width'),
|
|
47
|
+
sw_d: i.getAttribute('data-topo-chrome-reset-icon-stroke-width'),
|
|
48
|
+
hover: i.getAttribute('data-topo-chrome-reset-icon-hover'),
|
|
49
|
+
} : null;
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
const rest = await readIcon();
|
|
53
|
+
|
|
54
|
+
let hover = null;
|
|
55
|
+
const btn = await page.$('[data-topo-chrome-reset]');
|
|
56
|
+
if (btn) {
|
|
57
|
+
await btn.hover({ force: true });
|
|
58
|
+
await page.waitForTimeout(250);
|
|
59
|
+
hover = await readIcon();
|
|
60
|
+
await page.mouse.move(0, 0);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const fileText = readFileSync('/home/vansin/agent-network-dashboard/app/components/TopoGraph.tsx', 'utf8');
|
|
64
|
+
const sourceWired = /strokeWidth=\{hoveredReset && !resetSpinning \? '2\.8' : '2\.5'\}/.test(fileText);
|
|
65
|
+
|
|
66
|
+
await browser.close();
|
|
67
|
+
|
|
68
|
+
const results = {
|
|
69
|
+
rest_mounted: !!rest,
|
|
70
|
+
rest_sw_2_5: rest?.sw === '2.5',
|
|
71
|
+
rest_hover_false: rest?.hover === 'false',
|
|
72
|
+
hover_sw_2_8: hover?.sw === '2.8',
|
|
73
|
+
hover_sw_data_2_8: hover?.sw_d === '2.8',
|
|
74
|
+
hover_hover_true: hover?.hover === 'true',
|
|
75
|
+
source_wired: sourceWired,
|
|
76
|
+
};
|
|
77
|
+
const ok = Object.values(results).every(Boolean);
|
|
78
|
+
console.log(`${ok ? '✅' : '❌'} chrome reset icon sw hover:`, JSON.stringify(results),
|
|
79
|
+
'\n rest:', rest, '\n hover:', hover);
|
|
80
|
+
process.exit(ok ? 0 : 1);
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/* Round 454 verification: chrome zoom +/- icons strokeWidth hover lift
|
|
2
|
+
* via Tailwind arbitrary class group-hover:[stroke-width:2.8].
|
|
3
|
+
* The attribute strokeWidth='2.5' stays at rest; CSS hover overrides
|
|
4
|
+
* with stroke-width: 2.8.
|
|
5
|
+
*
|
|
6
|
+
* Contract:
|
|
7
|
+
* - rest: zoom-in/zoom-out icons report computed stroke-width '2.5px'
|
|
8
|
+
* - hover the zoom-in button: that icon computed stroke-width '2.8px'
|
|
9
|
+
* - source-file probe confirms group-hover:[stroke-width:2.8] in
|
|
10
|
+
* both icon className strings
|
|
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: 1500 } });
|
|
20
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
21
|
+
await ctx.addInitScript(() => {
|
|
22
|
+
try { localStorage.setItem('anet-theme', 'cyber'); sessionStorage.setItem('anet_v3_auth', '1'); } catch {}
|
|
23
|
+
});
|
|
24
|
+
await ctx.route('**/api/hub/status*', async (route) => {
|
|
25
|
+
const r = await route.fetch();
|
|
26
|
+
const b = await r.json();
|
|
27
|
+
const nid = (b.sessions || [])[0]?.network_id || 'default';
|
|
28
|
+
const mk = (alias, status) => ({
|
|
29
|
+
alias, status, model: 'claude-opus-4', runtime: 'claude-code-cli',
|
|
30
|
+
network_id: nid, project_dir: null,
|
|
31
|
+
created_at: fresh, updated_at: fresh, last_seen_at: fresh,
|
|
32
|
+
});
|
|
33
|
+
await route.fulfill({ response: r, json: { ...b, sessions: [
|
|
34
|
+
mk('alpha', 'working'),
|
|
35
|
+
mk('beta', 'idle'),
|
|
36
|
+
] } });
|
|
37
|
+
});
|
|
38
|
+
await ctx.route('**/api/hub/messages*', (r) => r.fulfill({ json: { messages: [] } }));
|
|
39
|
+
await ctx.route('**/api/hub/tasks*', (r) => r.fulfill({ json: { tasks: [] } }));
|
|
40
|
+
|
|
41
|
+
const page = await ctx.newPage();
|
|
42
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
|
|
43
|
+
await page.waitForSelector('[data-topo-chrome-zoom-in-icon]', { timeout: 15000 });
|
|
44
|
+
await page.waitForTimeout(400);
|
|
45
|
+
|
|
46
|
+
const readIcons = () => page.evaluate(() => {
|
|
47
|
+
const zi = document.querySelector('[data-topo-chrome-zoom-in-icon]');
|
|
48
|
+
const zo = document.querySelector('[data-topo-chrome-zoom-out-icon]');
|
|
49
|
+
return {
|
|
50
|
+
zoom_in: zi ? { sw: zi.getAttribute('stroke-width'), sw_computed: getComputedStyle(zi).strokeWidth } : null,
|
|
51
|
+
zoom_out: zo ? { sw: zo.getAttribute('stroke-width'), sw_computed: getComputedStyle(zo).strokeWidth } : null,
|
|
52
|
+
};
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
const rest = await readIcons();
|
|
56
|
+
|
|
57
|
+
// Hover zoom-in button
|
|
58
|
+
let hover = null;
|
|
59
|
+
const btn = await page.$('[data-topo-chrome-zoom-in]');
|
|
60
|
+
if (btn) {
|
|
61
|
+
await btn.hover({ force: true });
|
|
62
|
+
await page.waitForTimeout(300);
|
|
63
|
+
hover = await readIcons();
|
|
64
|
+
await page.mouse.move(0, 0);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const fileText = readFileSync('/home/vansin/agent-network-dashboard/app/components/TopoGraph.tsx', 'utf8');
|
|
68
|
+
// className appears BEFORE data-attr on the icon SVG, so check both
|
|
69
|
+
// orderings + count >= 2 to confirm both zoom icons have the class.
|
|
70
|
+
const sourceMatch = fileText.match(/group-hover:\[stroke-width:2\.8\]/g);
|
|
71
|
+
const sourceTwoMatches = sourceMatch && sourceMatch.length >= 2;
|
|
72
|
+
const sourceZoomOut = /group-hover:\[stroke-width:2\.8\][\s\S]{0,400}data-topo-chrome-zoom-out-icon/.test(fileText);
|
|
73
|
+
const sourceZoomIn = /group-hover:\[stroke-width:2\.8\][\s\S]{0,400}data-topo-chrome-zoom-in-icon/.test(fileText);
|
|
74
|
+
|
|
75
|
+
await browser.close();
|
|
76
|
+
|
|
77
|
+
const results = {
|
|
78
|
+
rest_zi_attr_2_5: rest.zoom_in?.sw === '2.5',
|
|
79
|
+
rest_zo_attr_2_5: rest.zoom_out?.sw === '2.5',
|
|
80
|
+
rest_zi_computed_2_5: rest.zoom_in?.sw_computed === '2.5px' || rest.zoom_in?.sw_computed === '2.5',
|
|
81
|
+
hover_zi_computed_2_8: hover?.zoom_in?.sw_computed === '2.8px' || hover?.zoom_in?.sw_computed === '2.8',
|
|
82
|
+
source_zoom_out_wired: sourceZoomOut,
|
|
83
|
+
source_zoom_in_wired: sourceZoomIn,
|
|
84
|
+
source_two_matches: sourceTwoMatches,
|
|
85
|
+
};
|
|
86
|
+
const ok = Object.values(results).every(Boolean);
|
|
87
|
+
console.log(`${ok ? '✅' : '❌'} chrome zoom icon sw hover:`, JSON.stringify(results),
|
|
88
|
+
'\n rest:', JSON.stringify(rest),
|
|
89
|
+
'\n hover:', JSON.stringify(hover));
|
|
90
|
+
process.exit(ok ? 0 : 1);
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/* Round 462 verification: TopoGraph root <svg> exposes the
|
|
2
|
+
* shipped DASHBOARD_VERSION via data-dashboard-version attr.
|
|
3
|
+
* Closes the feedback_dash_zombie_port_3000.md memory rule:
|
|
4
|
+
* "verify ships via SVG DOM, not tmux 'Ready'" — pre-R462 there
|
|
5
|
+
* was no in-DOM signal of which build the dash was serving.
|
|
6
|
+
*
|
|
7
|
+
* Contract:
|
|
8
|
+
* - svg[viewBox="0 0 1000 680"] reports data-dashboard-version
|
|
9
|
+
* matching package.json#version (a non-empty string that
|
|
10
|
+
* starts with a digit)
|
|
11
|
+
* - the dash is serving the EXPECTED preview (rejects zombie
|
|
12
|
+
* server scenarios where DOM and package.json disagree)
|
|
13
|
+
* - source-file conditional wired (import + attr presence)
|
|
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 expected = JSON.parse(readFileSync('/home/vansin/agent-network-dashboard/package.json', 'utf8')).version;
|
|
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', 'grid');
|
|
28
|
+
sessionStorage.setItem('anet_v3_auth', '1');
|
|
29
|
+
} catch {}
|
|
30
|
+
});
|
|
31
|
+
await ctx.route('**/api/hub/messages*', (r) => r.fulfill({ json: { messages: [] } }));
|
|
32
|
+
await ctx.route('**/api/hub/tasks*', (r) => r.fulfill({ json: { tasks: [] } }));
|
|
33
|
+
|
|
34
|
+
const page = await ctx.newPage();
|
|
35
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
|
|
36
|
+
await page.waitForSelector('svg[viewBox="0 0 1000 680"]', { timeout: 15000 });
|
|
37
|
+
await page.waitForTimeout(400);
|
|
38
|
+
|
|
39
|
+
const probe = await page.evaluate(() => {
|
|
40
|
+
const svg = document.querySelector('svg[viewBox="0 0 1000 680"]');
|
|
41
|
+
return {
|
|
42
|
+
attr: svg ? svg.getAttribute('data-dashboard-version') : null,
|
|
43
|
+
hasSvg: !!svg,
|
|
44
|
+
};
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
const src = readFileSync('/home/vansin/agent-network-dashboard/app/components/TopoGraph.tsx', 'utf8');
|
|
48
|
+
const sourceHasImport = /import \{ DASHBOARD_VERSION \} from '\.\.\/lib\/version'/.test(src);
|
|
49
|
+
const sourceHasAttr = /data-dashboard-version=\{DASHBOARD_VERSION\}/.test(src);
|
|
50
|
+
|
|
51
|
+
await browser.close();
|
|
52
|
+
|
|
53
|
+
const attrPresent = typeof probe.attr === 'string' && probe.attr.length > 0;
|
|
54
|
+
const attrIsVersionish = attrPresent && /^\d/.test(probe.attr);
|
|
55
|
+
const attrMatchesPkg = probe.attr === expected;
|
|
56
|
+
|
|
57
|
+
const results = {
|
|
58
|
+
svg_present: probe.hasSvg,
|
|
59
|
+
attr_present: attrPresent,
|
|
60
|
+
attr_is_version_shape: attrIsVersionish,
|
|
61
|
+
attr_matches_package: attrMatchesPkg,
|
|
62
|
+
source_import_wired: sourceHasImport,
|
|
63
|
+
source_attr_wired: sourceHasAttr,
|
|
64
|
+
};
|
|
65
|
+
const ok = Object.values(results).every(Boolean);
|
|
66
|
+
console.log(`${ok ? '✅' : '❌'} svg data-dashboard-version:`, JSON.stringify(results),
|
|
67
|
+
'\n expected:', expected,
|
|
68
|
+
'\n found:', probe.attr);
|
|
69
|
+
process.exit(ok ? 0 : 1);
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/* Round 452 verification: dense plain-text alias rest opacity 0.9 → 0.95.
|
|
2
|
+
* Sibling to R449/R450 canvas-presence alpha-gap closures.
|
|
3
|
+
*
|
|
4
|
+
* Contract:
|
|
5
|
+
* - need >16 sessions to enter dense layout
|
|
6
|
+
* - every dense alias-text reports opacity '0.95' + -opacity attr '0.95'
|
|
7
|
+
* - source-file probe confirms the value
|
|
8
|
+
*/
|
|
9
|
+
import { chromium } from 'playwright';
|
|
10
|
+
import { readFileSync } from 'node:fs';
|
|
11
|
+
|
|
12
|
+
const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
|
|
13
|
+
const fresh = new Date(Date.now() - 60 * 1000).toISOString();
|
|
14
|
+
|
|
15
|
+
const browser = await chromium.launch({ headless: true });
|
|
16
|
+
const ctx = await browser.newContext({ viewport: { width: 1500, height: 1500 } });
|
|
17
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
18
|
+
await ctx.addInitScript(() => {
|
|
19
|
+
try { localStorage.setItem('anet-theme', 'cyber'); sessionStorage.setItem('anet_v3_auth', '1'); } catch {}
|
|
20
|
+
});
|
|
21
|
+
await ctx.route('**/api/hub/status*', async (route) => {
|
|
22
|
+
const r = await route.fetch();
|
|
23
|
+
const b = await r.json();
|
|
24
|
+
const nid = (b.sessions || [])[0]?.network_id || 'default';
|
|
25
|
+
const mk = (alias, status) => ({
|
|
26
|
+
alias, status, model: 'claude-opus-4', runtime: 'claude-code-cli',
|
|
27
|
+
network_id: nid, project_dir: null,
|
|
28
|
+
created_at: fresh, updated_at: fresh, last_seen_at: fresh,
|
|
29
|
+
});
|
|
30
|
+
// 20 nodes — crosses the >16 dense threshold
|
|
31
|
+
const sessions = [];
|
|
32
|
+
for (let i = 0; i < 20; i++) {
|
|
33
|
+
sessions.push(mk(`n${String(i).padStart(2, '0')}`, i % 3 === 0 ? 'working' : 'idle'));
|
|
34
|
+
}
|
|
35
|
+
await route.fulfill({ response: r, json: { ...b, sessions } });
|
|
36
|
+
});
|
|
37
|
+
await ctx.route('**/api/hub/messages*', (r) => r.fulfill({ json: { messages: [] } }));
|
|
38
|
+
await ctx.route('**/api/hub/tasks*', (r) => r.fulfill({ json: { tasks: [] } }));
|
|
39
|
+
|
|
40
|
+
const page = await ctx.newPage();
|
|
41
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
|
|
42
|
+
await page.waitForSelector('[data-node-dense-alias-text]', { timeout: 15000 });
|
|
43
|
+
await page.waitForTimeout(400);
|
|
44
|
+
|
|
45
|
+
const aliases = await page.evaluate(() => {
|
|
46
|
+
const ts = [...document.querySelectorAll('[data-node-dense-alias-text]')];
|
|
47
|
+
return ts.map(t => ({
|
|
48
|
+
alias: t.getAttribute('data-node-dense-alias-text'),
|
|
49
|
+
opacity: t.getAttribute('opacity'),
|
|
50
|
+
data_op: t.getAttribute('data-node-dense-alias-text-opacity'),
|
|
51
|
+
}));
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
const fileText = readFileSync('/home/vansin/agent-network-dashboard/app/components/TopoGraph.tsx', 'utf8');
|
|
55
|
+
const sourceWired = /opacity=\{0\.95\}/.test(fileText) && /data-node-dense-alias-text-opacity="0\.95"/.test(fileText);
|
|
56
|
+
|
|
57
|
+
await browser.close();
|
|
58
|
+
|
|
59
|
+
const results = {
|
|
60
|
+
dense_layout_count_ge_17: aliases.length >= 17,
|
|
61
|
+
all_opacity_0_95: aliases.every(a => a.opacity === '0.95'),
|
|
62
|
+
all_data_op_0_95: aliases.every(a => a.data_op === '0.95'),
|
|
63
|
+
source_wired: sourceWired,
|
|
64
|
+
};
|
|
65
|
+
const ok = Object.values(results).every(Boolean);
|
|
66
|
+
console.log(`${ok ? '✅' : '❌'} dense alias opacity 0.95:`, JSON.stringify(results),
|
|
67
|
+
'\n count:', aliases.length, 'sample:', JSON.stringify(aliases[0]));
|
|
68
|
+
process.exit(ok ? 0 : 1);
|