@sleep2agi/agent-network-dashboard 0.5.1-preview.98 → 0.5.1
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/05admfiu6qfp2.js +1 -0
- package/.next/static/chunks/0a4hmfvj-81x5.css +2 -0
- package/.next/static/chunks/0d9mlqf.rjey5.js +1 -0
- package/.next/static/chunks/11puuje6at2jt.js +4 -0
- package/.next/static/chunks/{03~~oirxz7~vc.js → 15ub0_3b099x1.js} +1 -1
- package/.next/trace +2 -2
- package/.next/trace-build +1 -1
- package/app/components/ServersDrawer.tsx +17 -0
- package/app/components/TopoGraph.tsx +778 -90
- 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-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-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/scripts/topo-status-ring-hover-sw-test.mjs +105 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__03b.f76._.js.map +0 -1
- package/.next/static/chunks/017hq2-5l~_98.css +0 -2
- package/.next/static/chunks/0kmjjpdppowr2.js +0 -1
- package/.next/static/chunks/11-cqnshuwwij.js +0 -4
- package/.next/static/chunks/14myvippibo7y.js +0 -1
- /package/.next/static/{4VuFWzQ7d8yfyNm5pNIB0 → gowHgWkn_kpMCSBn8RFaa}/_buildManifest.js +0 -0
- /package/.next/static/{4VuFWzQ7d8yfyNm5pNIB0 → gowHgWkn_kpMCSBn8RFaa}/_clientMiddlewareManifest.js +0 -0
- /package/.next/static/{4VuFWzQ7d8yfyNm5pNIB0 → gowHgWkn_kpMCSBn8RFaa}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/* Round 460 verification: group-label tint rect transition list
|
|
2
|
+
* extends to include `x 200ms, width 200ms`. Pre-R460 the hitbox
|
|
3
|
+
* snap-jumped when a cluster grew/shrunk (member joins or leaves
|
|
4
|
+
* re-priced box.x / box.w); R460 tweens both geometry axes so
|
|
5
|
+
* the rect slides into the new bounds matching codex preview.125
|
|
6
|
+
* + R459 200ms motion vocabulary.
|
|
7
|
+
*
|
|
8
|
+
* Contract:
|
|
9
|
+
* - every <rect data-group-label-tint-geom-transition="x,width">
|
|
10
|
+
* renders inside the group cluster boundary
|
|
11
|
+
* - inline style includes 'x 200ms ease-out' AND 'width 200ms
|
|
12
|
+
* ease-out' alongside the R459 fill+opacity transitions
|
|
13
|
+
* - source-file conditional wired
|
|
14
|
+
*/
|
|
15
|
+
import { chromium } from 'playwright';
|
|
16
|
+
import { readFileSync } from 'node:fs';
|
|
17
|
+
|
|
18
|
+
const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
|
|
19
|
+
const fresh = new Date(Date.now() - 60 * 1000).toISOString();
|
|
20
|
+
|
|
21
|
+
const browser = await chromium.launch({ headless: true });
|
|
22
|
+
const ctx = await browser.newContext({ viewport: { width: 1500, height: 1200 } });
|
|
23
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
24
|
+
await ctx.addInitScript(() => {
|
|
25
|
+
try {
|
|
26
|
+
localStorage.setItem('anet-theme', 'cyber');
|
|
27
|
+
localStorage.setItem('anet-topo-layout', 'grid');
|
|
28
|
+
sessionStorage.setItem('anet_v3_auth', '1');
|
|
29
|
+
} catch {}
|
|
30
|
+
});
|
|
31
|
+
await ctx.route('**/api/hub/status*', async (route) => {
|
|
32
|
+
const r = await route.fetch();
|
|
33
|
+
const b = await r.json();
|
|
34
|
+
const nid = (b.sessions || [])[0]?.network_id || 'default';
|
|
35
|
+
const mk = (alias, status) => ({
|
|
36
|
+
alias, status, model: 'claude-opus-4', runtime: 'claude-code-cli',
|
|
37
|
+
network_id: nid, project_dir: null,
|
|
38
|
+
created_at: fresh, updated_at: fresh, last_seen_at: fresh,
|
|
39
|
+
});
|
|
40
|
+
await route.fulfill({ response: r, json: { ...b, sessions: [
|
|
41
|
+
mk('alpha·1', 'working'),
|
|
42
|
+
mk('alpha·2', 'idle'),
|
|
43
|
+
mk('beta·1', 'working'),
|
|
44
|
+
mk('beta·2', 'idle'),
|
|
45
|
+
] } });
|
|
46
|
+
});
|
|
47
|
+
await ctx.route('**/api/hub/messages*', (r) => r.fulfill({ json: { messages: [] } }));
|
|
48
|
+
await ctx.route('**/api/hub/tasks*', (r) => r.fulfill({ json: { tasks: [] } }));
|
|
49
|
+
|
|
50
|
+
const page = await ctx.newPage();
|
|
51
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
|
|
52
|
+
await page.waitForSelector('[data-group-label]', { timeout: 15000 });
|
|
53
|
+
await page.waitForTimeout(400);
|
|
54
|
+
|
|
55
|
+
const probe = await page.evaluate(() => {
|
|
56
|
+
const tints = [...document.querySelectorAll('[data-group-label-tint-geom-transition]')];
|
|
57
|
+
return {
|
|
58
|
+
count: tints.length,
|
|
59
|
+
nodes: tints.map(t => ({
|
|
60
|
+
geom: t.getAttribute('data-group-label-tint-geom-transition'),
|
|
61
|
+
style: t.getAttribute('style') || '',
|
|
62
|
+
})),
|
|
63
|
+
};
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
const src = readFileSync('/home/vansin/agent-network-dashboard/app/components/TopoGraph.tsx', 'utf8');
|
|
67
|
+
const sourceHasGeom = /data-group-label-tint-geom-transition="x,width"/.test(src);
|
|
68
|
+
const sourceHasXTween = /x 200ms ease-out/.test(src);
|
|
69
|
+
const sourceHasWidthTween = /width 200ms ease-out/.test(src);
|
|
70
|
+
|
|
71
|
+
await browser.close();
|
|
72
|
+
|
|
73
|
+
const countGe2 = probe.count >= 2;
|
|
74
|
+
const allDataAttrXW = probe.nodes.every(n => n.geom === 'x,width');
|
|
75
|
+
const allStyleHasX = probe.nodes.every(n => /x 200ms ease-out/.test(n.style));
|
|
76
|
+
const allStyleHasW = probe.nodes.every(n => /width 200ms ease-out/.test(n.style));
|
|
77
|
+
const allStylePreservesFillOpacity = probe.nodes.every(n =>
|
|
78
|
+
/fill 200ms ease-out/.test(n.style) && /opacity 200ms ease-out/.test(n.style));
|
|
79
|
+
|
|
80
|
+
const results = {
|
|
81
|
+
tint_count_ge_2: countGe2,
|
|
82
|
+
all_data_attr_xw: allDataAttrXW,
|
|
83
|
+
all_style_has_x: allStyleHasX,
|
|
84
|
+
all_style_has_width: allStyleHasW,
|
|
85
|
+
all_style_preserves_fill_opacity: allStylePreservesFillOpacity,
|
|
86
|
+
source_geom_attr_wired: sourceHasGeom,
|
|
87
|
+
source_x_tween_wired: sourceHasXTween,
|
|
88
|
+
source_w_tween_wired: sourceHasWidthTween,
|
|
89
|
+
};
|
|
90
|
+
const ok = Object.values(results).every(Boolean);
|
|
91
|
+
console.log(`${ok ? '✅' : '❌'} group label tint geom transition x+width:`, JSON.stringify(results),
|
|
92
|
+
'\n count:', probe.count,
|
|
93
|
+
'\n first style:', probe.nodes[0]?.style);
|
|
94
|
+
process.exit(ok ? 0 : 1);
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/* Round 459 verification: group-label tint hitbox rect transition
|
|
2
|
+
* cadence sync 150ms → 200ms to match codex preview.125 parent
|
|
3
|
+
* <text> transition list. The R107 hitbox rect carried legacy 150ms
|
|
4
|
+
* cadence; codex's #147 P1 lifted the parent label to 200ms across
|
|
5
|
+
* every axis. R459 closes the 50ms desync so tint + label flip as
|
|
6
|
+
* one motion-coherent unit on hover / pin / unpin.
|
|
7
|
+
*
|
|
8
|
+
* Contract:
|
|
9
|
+
* - every <rect data-group-label-tint-transition="200ms">
|
|
10
|
+
* renders inside the group cluster boundary (i.e. there's at
|
|
11
|
+
* least one when fixtures have prefix-group clusters)
|
|
12
|
+
* - source-file style string is 'fill 200ms ease-out, opacity
|
|
13
|
+
* 200ms ease-out' on the rect just below #147 Hero D pivot
|
|
14
|
+
* comment, NOT 'fill 150ms, opacity 150ms'
|
|
15
|
+
* - source-file the data attr `data-group-label-tint-transition`
|
|
16
|
+
* is wired
|
|
17
|
+
*/
|
|
18
|
+
import { chromium } from 'playwright';
|
|
19
|
+
import { readFileSync } from 'node:fs';
|
|
20
|
+
|
|
21
|
+
const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
|
|
22
|
+
const fresh = new Date(Date.now() - 60 * 1000).toISOString();
|
|
23
|
+
|
|
24
|
+
const browser = await chromium.launch({ headless: true });
|
|
25
|
+
const ctx = await browser.newContext({ viewport: { width: 1500, height: 1200 } });
|
|
26
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
27
|
+
await ctx.addInitScript(() => {
|
|
28
|
+
try {
|
|
29
|
+
localStorage.setItem('anet-theme', 'cyber');
|
|
30
|
+
localStorage.setItem('anet-topo-layout', 'grid');
|
|
31
|
+
sessionStorage.setItem('anet_v3_auth', '1');
|
|
32
|
+
} catch {}
|
|
33
|
+
});
|
|
34
|
+
await ctx.route('**/api/hub/status*', async (route) => {
|
|
35
|
+
const r = await route.fetch();
|
|
36
|
+
const b = await r.json();
|
|
37
|
+
const nid = (b.sessions || [])[0]?.network_id || 'default';
|
|
38
|
+
const mk = (alias, status) => ({
|
|
39
|
+
alias, status, model: 'claude-opus-4', runtime: 'claude-code-cli',
|
|
40
|
+
network_id: nid, project_dir: null,
|
|
41
|
+
created_at: fresh, updated_at: fresh, last_seen_at: fresh,
|
|
42
|
+
});
|
|
43
|
+
await route.fulfill({ response: r, json: { ...b, sessions: [
|
|
44
|
+
mk('alpha·1', 'working'),
|
|
45
|
+
mk('alpha·2', 'idle'),
|
|
46
|
+
mk('beta·1', 'working'),
|
|
47
|
+
mk('beta·2', 'idle'),
|
|
48
|
+
] } });
|
|
49
|
+
});
|
|
50
|
+
await ctx.route('**/api/hub/messages*', (r) => r.fulfill({ json: { messages: [] } }));
|
|
51
|
+
await ctx.route('**/api/hub/tasks*', (r) => r.fulfill({ json: { tasks: [] } }));
|
|
52
|
+
|
|
53
|
+
const page = await ctx.newPage();
|
|
54
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
|
|
55
|
+
await page.waitForSelector('[data-group-label]', { timeout: 15000 });
|
|
56
|
+
await page.waitForTimeout(400);
|
|
57
|
+
|
|
58
|
+
const probe = await page.evaluate(() => {
|
|
59
|
+
const tints = [...document.querySelectorAll('[data-group-label-tint-transition]')];
|
|
60
|
+
return {
|
|
61
|
+
count: tints.length,
|
|
62
|
+
transitions: tints.map(t => ({
|
|
63
|
+
value: t.getAttribute('data-group-label-tint-transition'),
|
|
64
|
+
style: t.getAttribute('style') || '',
|
|
65
|
+
computedTransition: getComputedStyle(t).transition,
|
|
66
|
+
})),
|
|
67
|
+
};
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
const src = readFileSync('/home/vansin/agent-network-dashboard/app/components/TopoGraph.tsx', 'utf8');
|
|
71
|
+
const sourceWired200 = /data-group-label-tint-transition="200ms"[\s\S]{0,300}?fill 200ms ease-out, opacity 200ms ease-out/.test(src);
|
|
72
|
+
// negative: there must NOT be a legacy 150ms transition WITHIN the
|
|
73
|
+
// same JSX element as data-group-label-tinted (the hitbox rect).
|
|
74
|
+
// other elements may still legitimately use 150ms (e.g. recent-row,
|
|
75
|
+
// legend-row at lines 8597 / 9458 — those are NOT the hitbox).
|
|
76
|
+
const tintRectBlockMatch = src.match(/data-group-label-tinted=[\s\S]{0,2000}?\/>/);
|
|
77
|
+
const tintRectBlock = tintRectBlockMatch ? tintRectBlockMatch[0] : '';
|
|
78
|
+
const sourceNoLegacy150 = !!tintRectBlock && !tintRectBlock.includes('fill 150ms');
|
|
79
|
+
|
|
80
|
+
await browser.close();
|
|
81
|
+
|
|
82
|
+
const tintCountGe2 = probe.count >= 2;
|
|
83
|
+
const allDataAttr200 = probe.transitions.every(t => t.value === '200ms');
|
|
84
|
+
const allStyle200 = probe.transitions.every(t => /fill 200ms ease-out, opacity 200ms ease-out/.test(t.style));
|
|
85
|
+
|
|
86
|
+
const results = {
|
|
87
|
+
tint_rect_count_ge_2: tintCountGe2,
|
|
88
|
+
all_data_attr_200: allDataAttr200,
|
|
89
|
+
all_style_200ms: allStyle200,
|
|
90
|
+
source_wired_200: sourceWired200,
|
|
91
|
+
source_no_legacy_150: sourceNoLegacy150,
|
|
92
|
+
};
|
|
93
|
+
const ok = Object.values(results).every(Boolean);
|
|
94
|
+
console.log(`${ok ? '✅' : '❌'} group label tint transition 150→200:`, JSON.stringify(results),
|
|
95
|
+
'\n count:', probe.count,
|
|
96
|
+
'\n first tint style:', probe.transitions[0]?.style);
|
|
97
|
+
process.exit(ok ? 0 : 1);
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/* Round 458 verification: status pip strip fontSize 11 → 8 + dx
|
|
2
|
+
* 8/4/4 → 6/3/3, to scale-match the new 9px label that N站牛/codex
|
|
3
|
+
* preview.125 shipped (Hero D #147 Option C: label fontSize 13→9,
|
|
4
|
+
* opacity 0.55 rest / 1 hover+pin, count tspan 11→8). R458 closes
|
|
5
|
+
* the pip-strip leg of the same family.
|
|
6
|
+
*
|
|
7
|
+
* Contract:
|
|
8
|
+
* - every <tspan data-group-pip="working|idle|offline">
|
|
9
|
+
* reports font-size '8' (down from '11')
|
|
10
|
+
* - source-file dx values for the 3 pips are '6'/'3'/'3'
|
|
11
|
+
* (down from '8'/'4'/'4')
|
|
12
|
+
* - parent <text data-group-label> font-size stays '9' (codex
|
|
13
|
+
* preview.125 baseline preserved — R458 is a follow-on, not a
|
|
14
|
+
* replacement)
|
|
15
|
+
* - count tspan font-size stays '8' (codex preview.125 baseline)
|
|
16
|
+
*/
|
|
17
|
+
import { chromium } from 'playwright';
|
|
18
|
+
import { readFileSync } from 'node:fs';
|
|
19
|
+
|
|
20
|
+
const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
|
|
21
|
+
const fresh = new Date(Date.now() - 60 * 1000).toISOString();
|
|
22
|
+
|
|
23
|
+
const browser = await chromium.launch({ headless: true });
|
|
24
|
+
const ctx = await browser.newContext({ viewport: { width: 1500, height: 1200 } });
|
|
25
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
26
|
+
await ctx.addInitScript(() => {
|
|
27
|
+
try {
|
|
28
|
+
localStorage.setItem('anet-theme', 'cyber');
|
|
29
|
+
localStorage.setItem('anet-topo-layout', 'grid');
|
|
30
|
+
sessionStorage.setItem('anet_v3_auth', '1');
|
|
31
|
+
} catch {}
|
|
32
|
+
});
|
|
33
|
+
// Fixture: 2 prefix groups, each MIXED (so at least one pip
|
|
34
|
+
// renders — R319 drops pips when count===box.count).
|
|
35
|
+
await ctx.route('**/api/hub/status*', async (route) => {
|
|
36
|
+
const r = await route.fetch();
|
|
37
|
+
const b = await r.json();
|
|
38
|
+
const nid = (b.sessions || [])[0]?.network_id || 'default';
|
|
39
|
+
const mk = (alias, status) => ({
|
|
40
|
+
alias, status, model: 'claude-opus-4', runtime: 'claude-code-cli',
|
|
41
|
+
network_id: nid, project_dir: null,
|
|
42
|
+
created_at: fresh, updated_at: fresh, last_seen_at: fresh,
|
|
43
|
+
});
|
|
44
|
+
await route.fulfill({ response: r, json: { ...b, sessions: [
|
|
45
|
+
mk('alpha·1', 'working'),
|
|
46
|
+
mk('alpha·2', 'idle'),
|
|
47
|
+
mk('alpha·3', 'offline'),
|
|
48
|
+
mk('beta·1', 'working'),
|
|
49
|
+
mk('beta·2', 'idle'),
|
|
50
|
+
] } });
|
|
51
|
+
});
|
|
52
|
+
await ctx.route('**/api/hub/messages*', (r) => r.fulfill({ json: { messages: [] } }));
|
|
53
|
+
await ctx.route('**/api/hub/tasks*', (r) => r.fulfill({ json: { tasks: [] } }));
|
|
54
|
+
|
|
55
|
+
const page = await ctx.newPage();
|
|
56
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
|
|
57
|
+
await page.waitForSelector('[data-group-label]', { timeout: 15000 });
|
|
58
|
+
await page.waitForTimeout(500);
|
|
59
|
+
|
|
60
|
+
const probe = await page.evaluate(() => {
|
|
61
|
+
const pips = [...document.querySelectorAll('[data-group-pip]')].map(t => ({
|
|
62
|
+
tier: t.getAttribute('data-group-pip'),
|
|
63
|
+
fontSize: t.getAttribute('font-size'),
|
|
64
|
+
text: t.textContent,
|
|
65
|
+
}));
|
|
66
|
+
const labels = [...document.querySelectorAll('[data-group-label]')].map(t => ({
|
|
67
|
+
key: t.getAttribute('data-group-label'),
|
|
68
|
+
fontSize: t.getAttribute('font-size'),
|
|
69
|
+
}));
|
|
70
|
+
const counts = [...document.querySelectorAll('[data-group-label-count]')].map(t => ({
|
|
71
|
+
key: t.getAttribute('data-group-label-count'),
|
|
72
|
+
fontSize: t.getAttribute('font-size'),
|
|
73
|
+
}));
|
|
74
|
+
return { pips, labels, counts };
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
const src = readFileSync('/home/vansin/agent-network-dashboard/app/components/TopoGraph.tsx', 'utf8');
|
|
78
|
+
// dx values for the 3 pips — the source file uses dx="6" then dx="3" twice
|
|
79
|
+
const dxWorking = /data-group-pip="working"[\s\S]{0,400}?dx="6"/.test(src) ||
|
|
80
|
+
/dx="6"[\s\S]{0,400}?data-group-pip="working"/.test(src);
|
|
81
|
+
const dxIdle = /data-group-pip="idle"[\s\S]{0,400}?dx="3"/.test(src) ||
|
|
82
|
+
/dx="3"[\s\S]{0,400}?data-group-pip="idle"/.test(src);
|
|
83
|
+
const dxOffline = /data-group-pip="offline"[\s\S]{0,400}?dx="3"/.test(src) ||
|
|
84
|
+
/dx="3"[\s\S]{0,400}?data-group-pip="offline"/.test(src);
|
|
85
|
+
|
|
86
|
+
await browser.close();
|
|
87
|
+
|
|
88
|
+
const allPipsAre8 = probe.pips.length >= 2 && probe.pips.every(p => p.fontSize === '8');
|
|
89
|
+
const labelStays9 = probe.labels.length >= 2 && probe.labels.every(l => l.fontSize === '9');
|
|
90
|
+
const countStays8 = probe.counts.length >= 2 && probe.counts.every(c => c.fontSize === '8');
|
|
91
|
+
|
|
92
|
+
const results = {
|
|
93
|
+
pips_count_ge_2: probe.pips.length >= 2,
|
|
94
|
+
pips_all_fontsize_8: allPipsAre8,
|
|
95
|
+
labels_stay_9: labelStays9,
|
|
96
|
+
counts_stay_8: countStays8,
|
|
97
|
+
dx_working_is_6: dxWorking,
|
|
98
|
+
dx_idle_is_3: dxIdle,
|
|
99
|
+
dx_offline_is_3: dxOffline,
|
|
100
|
+
};
|
|
101
|
+
const ok = Object.values(results).every(Boolean);
|
|
102
|
+
console.log(`${ok ? '✅' : '❌'} group pip fontSize scale-match:`, JSON.stringify(results),
|
|
103
|
+
'\n pips:', JSON.stringify(probe.pips),
|
|
104
|
+
'\n labels:', JSON.stringify(probe.labels),
|
|
105
|
+
'\n counts:', JSON.stringify(probe.counts));
|
|
106
|
+
process.exit(ok ? 0 : 1);
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/* Round 465 verification: hitbox tint rect rx 4 → 5 on
|
|
2
|
+
* pinnedGroup match — mirror R464 (parent group-box rx 14 → 16
|
|
3
|
+
* on isPinned) at the hitbox tier. Pre-R465 the inner hitbox
|
|
4
|
+
* stayed at fixed rx=4 (codex p.125) while the outer container
|
|
5
|
+
* gained pin-tier rx softening; R465 echoes the locked posture
|
|
6
|
+
* at the smaller rect scale.
|
|
7
|
+
*
|
|
8
|
+
* Contract:
|
|
9
|
+
* - every <rect data-group-label-tint-rx> reports rx='4' at rest
|
|
10
|
+
* - clicking the hitbox flips that group's rx to '5'
|
|
11
|
+
* - sibling stays '4'
|
|
12
|
+
* - transition list (R460) extends to include rx 200ms
|
|
13
|
+
* - data-group-label-tint-geom-transition='x,width,rx'
|
|
14
|
+
*/
|
|
15
|
+
import { chromium } from 'playwright';
|
|
16
|
+
import { readFileSync } from 'node:fs';
|
|
17
|
+
|
|
18
|
+
const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
|
|
19
|
+
const fresh = new Date(Date.now() - 60 * 1000).toISOString();
|
|
20
|
+
|
|
21
|
+
const browser = await chromium.launch({ headless: true });
|
|
22
|
+
const ctx = await browser.newContext({ viewport: { width: 1500, height: 1200 } });
|
|
23
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
24
|
+
await ctx.addInitScript(() => {
|
|
25
|
+
try {
|
|
26
|
+
localStorage.setItem('anet-theme', 'cyber');
|
|
27
|
+
localStorage.setItem('anet-topo-layout', 'grid');
|
|
28
|
+
sessionStorage.setItem('anet_v3_auth', '1');
|
|
29
|
+
} catch {}
|
|
30
|
+
});
|
|
31
|
+
await ctx.route('**/api/hub/status*', async (route) => {
|
|
32
|
+
const r = await route.fetch();
|
|
33
|
+
const b = await r.json();
|
|
34
|
+
const nid = (b.sessions || [])[0]?.network_id || 'default';
|
|
35
|
+
const mk = (alias, status) => ({
|
|
36
|
+
alias, status, model: 'claude-opus-4', runtime: 'claude-code-cli',
|
|
37
|
+
network_id: nid, project_dir: null,
|
|
38
|
+
created_at: fresh, updated_at: fresh, last_seen_at: fresh,
|
|
39
|
+
});
|
|
40
|
+
await route.fulfill({ response: r, json: { ...b, sessions: [
|
|
41
|
+
mk('alpha·1', 'working'),
|
|
42
|
+
mk('alpha·2', 'idle'),
|
|
43
|
+
mk('beta·1', 'working'),
|
|
44
|
+
mk('beta·2', 'idle'),
|
|
45
|
+
] } });
|
|
46
|
+
});
|
|
47
|
+
await ctx.route('**/api/hub/messages*', (r) => r.fulfill({ json: { messages: [] } }));
|
|
48
|
+
await ctx.route('**/api/hub/tasks*', (r) => r.fulfill({ json: { tasks: [] } }));
|
|
49
|
+
|
|
50
|
+
const page = await ctx.newPage();
|
|
51
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
|
|
52
|
+
await page.waitForSelector('[data-group-label-tint-rx]', { timeout: 15000 });
|
|
53
|
+
await page.waitForTimeout(400);
|
|
54
|
+
|
|
55
|
+
const readAll = () => page.evaluate(() => {
|
|
56
|
+
const tints = [...document.querySelectorAll('[data-group-label-tint-rx]')];
|
|
57
|
+
return tints.map(t => {
|
|
58
|
+
const parentG = t.closest('g[data-group]');
|
|
59
|
+
return {
|
|
60
|
+
key: parentG ? parentG.getAttribute('data-group') : null,
|
|
61
|
+
rx_attr: t.getAttribute('data-group-label-tint-rx'),
|
|
62
|
+
rx_live: t.getAttribute('rx'),
|
|
63
|
+
geom: t.getAttribute('data-group-label-tint-geom-transition'),
|
|
64
|
+
};
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
const rest = await readAll();
|
|
69
|
+
const firstKey = rest[0]?.key;
|
|
70
|
+
|
|
71
|
+
let pinned = null;
|
|
72
|
+
if (firstKey) {
|
|
73
|
+
const hit = await page.$(`[data-group-label-hit="${firstKey}"]`);
|
|
74
|
+
if (hit) {
|
|
75
|
+
await hit.click();
|
|
76
|
+
await page.waitForTimeout(300);
|
|
77
|
+
pinned = await readAll();
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const src = readFileSync('/home/vansin/agent-network-dashboard/app/components/TopoGraph.tsx', 'utf8');
|
|
82
|
+
const sourceRxConditional = /rx=\{pinnedGroup === box\.key \? '5' : '4'\}/.test(src);
|
|
83
|
+
const sourceGeomXWidthRx = /data-group-label-tint-geom-transition="x,width,rx"/.test(src);
|
|
84
|
+
|
|
85
|
+
await browser.close();
|
|
86
|
+
|
|
87
|
+
const restCountGe2 = rest.length >= 2;
|
|
88
|
+
const restAllRx4 = rest.every(r => r.rx_attr === '4' && r.rx_live === '4');
|
|
89
|
+
const restGeomXWR = rest.every(r => r.geom === 'x,width,rx');
|
|
90
|
+
const pinnedTarget = pinned?.find(r => r.key === firstKey);
|
|
91
|
+
const pinTargetRx5 = pinnedTarget?.rx_attr === '5' && pinnedTarget?.rx_live === '5';
|
|
92
|
+
const pinSiblings = pinned ? pinned.filter(r => r.key !== firstKey).every(r => r.rx_attr === '4') : false;
|
|
93
|
+
|
|
94
|
+
const results = {
|
|
95
|
+
rest_count_ge_2: restCountGe2,
|
|
96
|
+
rest_all_rx_4: restAllRx4,
|
|
97
|
+
rest_geom_attr_xwrx: restGeomXWR,
|
|
98
|
+
pinned_target_rx_5: pinTargetRx5,
|
|
99
|
+
pinned_siblings_rest: pinSiblings,
|
|
100
|
+
source_rx_conditional: sourceRxConditional,
|
|
101
|
+
source_geom_attr_xwrx: sourceGeomXWidthRx,
|
|
102
|
+
};
|
|
103
|
+
const ok = Object.values(results).every(Boolean);
|
|
104
|
+
console.log(`${ok ? '✅' : '❌'} hitbox tint rx pin 4→5:`, JSON.stringify(results),
|
|
105
|
+
'\n rest:', JSON.stringify(rest),
|
|
106
|
+
'\n pinned target:', JSON.stringify(pinnedTarget));
|
|
107
|
+
process.exit(ok ? 0 : 1);
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/* Round 441 verification: hub center core fill brighten on hoveredHub.
|
|
2
|
+
* Cyber emerald-500 #10b981 → emerald-400 #34d399.
|
|
3
|
+
*
|
|
4
|
+
* Contract:
|
|
5
|
+
* - rest: core fill = '#10b981' + hovered='false'
|
|
6
|
+
* - hover the hub <g>: core fill = '#34d399' + hovered='true'
|
|
7
|
+
*/
|
|
8
|
+
import { chromium } from 'playwright';
|
|
9
|
+
import { readFileSync } from 'node:fs';
|
|
10
|
+
|
|
11
|
+
const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
|
|
12
|
+
const fresh = new Date(Date.now() - 60 * 1000).toISOString();
|
|
13
|
+
|
|
14
|
+
const browser = await chromium.launch({ headless: true });
|
|
15
|
+
const ctx = await browser.newContext({ viewport: { width: 1500, height: 1500 } });
|
|
16
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
17
|
+
await ctx.addInitScript(() => {
|
|
18
|
+
try { localStorage.setItem('anet-theme', 'cyber'); sessionStorage.setItem('anet_v3_auth', '1'); } catch {}
|
|
19
|
+
});
|
|
20
|
+
await ctx.route('**/api/hub/status*', async (route) => {
|
|
21
|
+
const r = await route.fetch();
|
|
22
|
+
const b = await r.json();
|
|
23
|
+
const nid = (b.sessions || [])[0]?.network_id || 'default';
|
|
24
|
+
const mk = (alias, status) => ({
|
|
25
|
+
alias, status, model: 'claude-opus-4', runtime: 'claude-code-cli',
|
|
26
|
+
network_id: nid, project_dir: null,
|
|
27
|
+
created_at: fresh, updated_at: fresh, last_seen_at: fresh,
|
|
28
|
+
});
|
|
29
|
+
await route.fulfill({ response: r, json: { ...b, sessions: [
|
|
30
|
+
mk('alpha', 'working'),
|
|
31
|
+
mk('beta', 'idle'),
|
|
32
|
+
] } });
|
|
33
|
+
});
|
|
34
|
+
await ctx.route('**/api/hub/messages*', (r) => r.fulfill({ json: { messages: [] } }));
|
|
35
|
+
await ctx.route('**/api/hub/tasks*', (r) => r.fulfill({ json: { tasks: [] } }));
|
|
36
|
+
|
|
37
|
+
const page = await ctx.newPage();
|
|
38
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
|
|
39
|
+
await page.waitForSelector('[data-topo-hub-core]', { timeout: 15000 });
|
|
40
|
+
await page.waitForTimeout(400);
|
|
41
|
+
|
|
42
|
+
const readCore = () => page.evaluate(() => {
|
|
43
|
+
const c = document.querySelector('[data-topo-hub-core]');
|
|
44
|
+
return c ? {
|
|
45
|
+
fill_attr: c.getAttribute('fill'),
|
|
46
|
+
fill_data: c.getAttribute('data-topo-hub-core-fill'),
|
|
47
|
+
hovered: c.getAttribute('data-topo-hub-core-hovered'),
|
|
48
|
+
r: c.getAttribute('r'),
|
|
49
|
+
} : null;
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
const rest = await readCore();
|
|
53
|
+
|
|
54
|
+
const hubBox = await page.evaluate(() => {
|
|
55
|
+
const hub = document.querySelector('[data-topo-hub]');
|
|
56
|
+
if (!hub) return null;
|
|
57
|
+
const b = hub.getBoundingClientRect();
|
|
58
|
+
return { x: b.x + b.width / 2, y: b.y + b.height / 2 };
|
|
59
|
+
});
|
|
60
|
+
let hover = null;
|
|
61
|
+
if (hubBox) {
|
|
62
|
+
await page.mouse.move(hubBox.x, hubBox.y);
|
|
63
|
+
await page.waitForTimeout(300);
|
|
64
|
+
hover = await readCore();
|
|
65
|
+
await page.mouse.move(0, 0);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const fileText = readFileSync('/home/vansin/agent-network-dashboard/app/components/TopoGraph.tsx', 'utf8');
|
|
69
|
+
const sourceWired = /const coreFill = isLight\s*\n\s*\?\s*\(isCoreHovered \? '#10b981' : '#059669'\)\s*\n\s*:\s*\(isCoreHovered \? '#34d399' : '#10b981'\)/.test(fileText);
|
|
70
|
+
|
|
71
|
+
await browser.close();
|
|
72
|
+
|
|
73
|
+
const results = {
|
|
74
|
+
rest_mounted: !!rest,
|
|
75
|
+
rest_fill_emerald_500: rest?.fill_data === '#10b981',
|
|
76
|
+
rest_hovered_false: rest?.hovered === 'false',
|
|
77
|
+
rest_r_10: rest?.r === '10',
|
|
78
|
+
hover_fill_emerald_400: hover?.fill_data === '#34d399',
|
|
79
|
+
hover_hovered_true: hover?.hovered === 'true',
|
|
80
|
+
source_wired: sourceWired,
|
|
81
|
+
};
|
|
82
|
+
const ok = Object.values(results).every(Boolean);
|
|
83
|
+
console.log(`${ok ? '✅' : '❌'} hub core fill hover:`, JSON.stringify(results),
|
|
84
|
+
'\n rest:', rest, '\n hover:', hover);
|
|
85
|
+
process.exit(ok ? 0 : 1);
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/* Round 451 verification: hub center halo radius hover lift —
|
|
2
|
+
* r 20 → 22 on hoveredHub.
|
|
3
|
+
*
|
|
4
|
+
* Contract:
|
|
5
|
+
* - rest: hub halo reports data-topo-hub-halo-radius '20' + hovered='false'
|
|
6
|
+
* - hover the hub <g>: halo lifts to r '22' + hovered='true'
|
|
7
|
+
*/
|
|
8
|
+
import { chromium } from 'playwright';
|
|
9
|
+
import { readFileSync } from 'node:fs';
|
|
10
|
+
|
|
11
|
+
const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
|
|
12
|
+
const fresh = new Date(Date.now() - 60 * 1000).toISOString();
|
|
13
|
+
|
|
14
|
+
const browser = await chromium.launch({ headless: true });
|
|
15
|
+
const ctx = await browser.newContext({ viewport: { width: 1500, height: 1500 } });
|
|
16
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
17
|
+
await ctx.addInitScript(() => {
|
|
18
|
+
try { localStorage.setItem('anet-theme', 'cyber'); sessionStorage.setItem('anet_v3_auth', '1'); } catch {}
|
|
19
|
+
});
|
|
20
|
+
await ctx.route('**/api/hub/status*', async (route) => {
|
|
21
|
+
const r = await route.fetch();
|
|
22
|
+
const b = await r.json();
|
|
23
|
+
const nid = (b.sessions || [])[0]?.network_id || 'default';
|
|
24
|
+
const mk = (alias, status) => ({
|
|
25
|
+
alias, status, model: 'claude-opus-4', runtime: 'claude-code-cli',
|
|
26
|
+
network_id: nid, project_dir: null,
|
|
27
|
+
created_at: fresh, updated_at: fresh, last_seen_at: fresh,
|
|
28
|
+
});
|
|
29
|
+
await route.fulfill({ response: r, json: { ...b, sessions: [
|
|
30
|
+
mk('alpha', 'working'),
|
|
31
|
+
mk('beta', 'idle'),
|
|
32
|
+
] } });
|
|
33
|
+
});
|
|
34
|
+
await ctx.route('**/api/hub/messages*', (r) => r.fulfill({ json: { messages: [] } }));
|
|
35
|
+
await ctx.route('**/api/hub/tasks*', (r) => r.fulfill({ json: { tasks: [] } }));
|
|
36
|
+
|
|
37
|
+
const page = await ctx.newPage();
|
|
38
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
|
|
39
|
+
await page.waitForSelector('[data-topo-hub-halo-radius]', { timeout: 15000 });
|
|
40
|
+
await page.waitForTimeout(400);
|
|
41
|
+
|
|
42
|
+
const readHalo = () => page.evaluate(() => {
|
|
43
|
+
const c = document.querySelector('[data-topo-hub-halo-radius]');
|
|
44
|
+
return c ? {
|
|
45
|
+
r_data: parseFloat(c.getAttribute('data-topo-hub-halo-radius') || '0'),
|
|
46
|
+
hovered: c.getAttribute('data-topo-hub-halo-hovered'),
|
|
47
|
+
} : null;
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
const rest = await readHalo();
|
|
51
|
+
|
|
52
|
+
let hover = null;
|
|
53
|
+
const hubBox = await page.evaluate(() => {
|
|
54
|
+
const hub = document.querySelector('[data-topo-hub]');
|
|
55
|
+
if (!hub) return null;
|
|
56
|
+
const b = hub.getBoundingClientRect();
|
|
57
|
+
return { x: b.x + b.width / 2, y: b.y + b.height / 2 };
|
|
58
|
+
});
|
|
59
|
+
if (hubBox) {
|
|
60
|
+
await page.mouse.move(hubBox.x, hubBox.y);
|
|
61
|
+
await page.waitForTimeout(300);
|
|
62
|
+
hover = await readHalo();
|
|
63
|
+
await page.mouse.move(0, 0);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const fileText = readFileSync('/home/vansin/agent-network-dashboard/app/components/TopoGraph.tsx', 'utf8');
|
|
67
|
+
const sourceWired = /const haloR = isHaloHovered \? 22 : 20/.test(fileText);
|
|
68
|
+
|
|
69
|
+
await browser.close();
|
|
70
|
+
|
|
71
|
+
const results = {
|
|
72
|
+
rest_mounted: !!rest,
|
|
73
|
+
rest_r_20: rest?.r_data === 20,
|
|
74
|
+
rest_hovered_false: rest?.hovered === 'false',
|
|
75
|
+
hover_r_22: hover?.r_data === 22,
|
|
76
|
+
hover_hovered_true: hover?.hovered === 'true',
|
|
77
|
+
source_wired: sourceWired,
|
|
78
|
+
};
|
|
79
|
+
const ok = Object.values(results).every(Boolean);
|
|
80
|
+
console.log(`${ok ? '✅' : '❌'} hub halo hover r:`, JSON.stringify(results),
|
|
81
|
+
'\n rest:', rest, '\n hover:', hover);
|
|
82
|
+
process.exit(ok ? 0 : 1);
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/* Round 449 verification: legend-row count active-state opacity
|
|
2
|
+
* 0.95 → 1.0 on (hoveredStatus===row.key || isPinned). Closes the 5%
|
|
3
|
+
* alpha gap on populated active rows.
|
|
4
|
+
*
|
|
5
|
+
* Contract:
|
|
6
|
+
* - rest: every populated legend-count reports opacity '0.65' (R204)
|
|
7
|
+
* - click 'working' status: that count opacity '1'
|
|
8
|
+
* - empty (0-count) rows stay at R204 dim (0.28/0.30) unaffected
|
|
9
|
+
* - siblings stay at rest 0.65
|
|
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: 1500 } });
|
|
19
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
20
|
+
await ctx.addInitScript(() => {
|
|
21
|
+
try { localStorage.setItem('anet-theme', 'cyber'); sessionStorage.setItem('anet_v3_auth', '1'); } catch {}
|
|
22
|
+
});
|
|
23
|
+
await ctx.route('**/api/hub/status*', async (route) => {
|
|
24
|
+
const r = await route.fetch();
|
|
25
|
+
const b = await r.json();
|
|
26
|
+
const nid = (b.sessions || [])[0]?.network_id || 'default';
|
|
27
|
+
const mk = (alias, status) => ({
|
|
28
|
+
alias, status, model: 'claude-opus-4', runtime: 'claude-code-cli',
|
|
29
|
+
network_id: nid, project_dir: null,
|
|
30
|
+
created_at: fresh, updated_at: fresh, last_seen_at: fresh,
|
|
31
|
+
});
|
|
32
|
+
await route.fulfill({ response: r, json: { ...b, sessions: [
|
|
33
|
+
mk('alpha', 'working'),
|
|
34
|
+
mk('beta', 'working'),
|
|
35
|
+
mk('gamma', '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-legend-count]', { timeout: 15000 });
|
|
44
|
+
await page.waitForTimeout(400);
|
|
45
|
+
|
|
46
|
+
const readAll = () => page.evaluate(() => {
|
|
47
|
+
const ts = [...document.querySelectorAll('[data-legend-count]')];
|
|
48
|
+
return ts.map(t => ({
|
|
49
|
+
key: t.getAttribute('data-legend-count'),
|
|
50
|
+
opacity: t.getAttribute('opacity'),
|
|
51
|
+
empty: t.getAttribute('data-legend-count-empty'),
|
|
52
|
+
}));
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
const rest = await readAll();
|
|
56
|
+
|
|
57
|
+
// Click 'working' status row to pin
|
|
58
|
+
let pinned = null;
|
|
59
|
+
const workingGroup = await page.$(`[data-legend-status="working"]`);
|
|
60
|
+
if (workingGroup) {
|
|
61
|
+
await workingGroup.click();
|
|
62
|
+
await page.waitForTimeout(250);
|
|
63
|
+
pinned = await readAll();
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const fileText = readFileSync('/home/vansin/agent-network-dashboard/app/components/TopoGraph.tsx', 'utf8');
|
|
67
|
+
const sourceWired = /:\s*\(hoveredStatus === row\.key \|\| isPinned \? 1 : 0\.65\)/.test(fileText);
|
|
68
|
+
|
|
69
|
+
await browser.close();
|
|
70
|
+
|
|
71
|
+
// rest: populated rows (working=2, idle=1) should be 0.65; offline (count=0) should be 0.28/0.30
|
|
72
|
+
const workingRest = rest.find(r => r.key === 'working');
|
|
73
|
+
const idleRest = rest.find(r => r.key === 'idle');
|
|
74
|
+
const offlineRest = rest.find(r => r.key === 'offline');
|
|
75
|
+
|
|
76
|
+
const restWorking_065 = workingRest?.opacity === '0.65';
|
|
77
|
+
const restIdle_065 = idleRest?.opacity === '0.65';
|
|
78
|
+
const restOfflineEmpty = offlineRest?.empty === 'true' && (offlineRest?.opacity === '0.3' || offlineRest?.opacity === '0.28');
|
|
79
|
+
|
|
80
|
+
// pinned: working should be 1
|
|
81
|
+
const pinnedWorking = pinned?.find(r => r.key === 'working');
|
|
82
|
+
const pinnedIdle = pinned?.find(r => r.key === 'idle');
|
|
83
|
+
const pinnedOffline = pinned?.find(r => r.key === 'offline');
|
|
84
|
+
|
|
85
|
+
const pinWorking_1 = pinnedWorking?.opacity === '1';
|
|
86
|
+
const pinIdleRest = pinnedIdle?.opacity === '0.65';
|
|
87
|
+
const pinOfflineEmpty = pinnedOffline?.empty === 'true';
|
|
88
|
+
|
|
89
|
+
const results = {
|
|
90
|
+
rest_working_065: restWorking_065,
|
|
91
|
+
rest_idle_065: restIdle_065,
|
|
92
|
+
rest_offline_empty_dim: restOfflineEmpty,
|
|
93
|
+
pin_working_opacity_1: pinWorking_1,
|
|
94
|
+
pin_idle_stays_rest_065: pinIdleRest,
|
|
95
|
+
pin_offline_stays_empty: pinOfflineEmpty,
|
|
96
|
+
source_wired: sourceWired,
|
|
97
|
+
};
|
|
98
|
+
const ok = Object.values(results).every(Boolean);
|
|
99
|
+
console.log(`${ok ? '✅' : '❌'} legend count active opacity:`, JSON.stringify(results),
|
|
100
|
+
'\n rest:', JSON.stringify(rest),
|
|
101
|
+
'\n pinned:', JSON.stringify(pinned));
|
|
102
|
+
process.exit(ok ? 0 : 1);
|