@sleep2agi/agent-network-dashboard 0.5.1-preview.12 → 0.5.1-preview.126
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 +6 -6
- 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 +2 -2
- package/.next/server/app/_not-found.segments/_full.segment.rsc +2 -2
- package/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/.next/server/app/_not-found.segments/_index.segment.rsc +2 -2
- package/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- 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 +2 -2
- package/.next/server/app/admin.segments/_full.segment.rsc +2 -2
- package/.next/server/app/admin.segments/_head.segment.rsc +1 -1
- package/.next/server/app/admin.segments/_index.segment.rsc +2 -2
- package/.next/server/app/admin.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/admin.segments/admin/__PAGE__.segment.rsc +1 -1
- package/.next/server/app/admin.segments/admin.segment.rsc +1 -1
- package/.next/server/app/index.html +2 -2
- package/.next/server/app/index.rsc +3 -3
- package/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
- package/.next/server/app/index.segments/_full.segment.rsc +3 -3
- package/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/.next/server/app/index.segments/_index.segment.rsc +2 -2
- 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 +3 -3
- package/.next/server/app/login.segments/_full.segment.rsc +3 -3
- package/.next/server/app/login.segments/_head.segment.rsc +1 -1
- package/.next/server/app/login.segments/_index.segment.rsc +2 -2
- package/.next/server/app/login.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/login.segments/login/__PAGE__.segment.rsc +2 -2
- package/.next/server/app/login.segments/login.segment.rsc +1 -1
- 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 +2 -2
- package/.next/server/app/logs.segments/_full.segment.rsc +2 -2
- package/.next/server/app/logs.segments/_head.segment.rsc +1 -1
- package/.next/server/app/logs.segments/_index.segment.rsc +2 -2
- package/.next/server/app/logs.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/logs.segments/logs/__PAGE__.segment.rsc +1 -1
- package/.next/server/app/logs.segments/logs.segment.rsc +1 -1
- 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 +2 -2
- package/.next/server/app/messages.segments/_full.segment.rsc +2 -2
- package/.next/server/app/messages.segments/_head.segment.rsc +1 -1
- package/.next/server/app/messages.segments/_index.segment.rsc +2 -2
- package/.next/server/app/messages.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/messages.segments/messages/__PAGE__.segment.rsc +1 -1
- package/.next/server/app/messages.segments/messages.segment.rsc +1 -1
- 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 +2 -2
- package/.next/server/app/node.segments/_full.segment.rsc +2 -2
- package/.next/server/app/node.segments/_head.segment.rsc +1 -1
- package/.next/server/app/node.segments/_index.segment.rsc +2 -2
- package/.next/server/app/node.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/node.segments/node/__PAGE__.segment.rsc +1 -1
- package/.next/server/app/node.segments/node.segment.rsc +1 -1
- 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 +2 -2
- package/.next/server/app/nodes.segments/_full.segment.rsc +2 -2
- package/.next/server/app/nodes.segments/_head.segment.rsc +1 -1
- package/.next/server/app/nodes.segments/_index.segment.rsc +2 -2
- package/.next/server/app/nodes.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/nodes.segments/nodes/__PAGE__.segment.rsc +1 -1
- package/.next/server/app/nodes.segments/nodes.segment.rsc +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 +2 -2
- package/.next/server/app/server-logs.segments/_full.segment.rsc +2 -2
- package/.next/server/app/server-logs.segments/_head.segment.rsc +1 -1
- package/.next/server/app/server-logs.segments/_index.segment.rsc +2 -2
- package/.next/server/app/server-logs.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/server-logs.segments/server-logs/__PAGE__.segment.rsc +1 -1
- package/.next/server/app/server-logs.segments/server-logs.segment.rsc +1 -1
- 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 +2 -2
- package/.next/server/app/settings/networks.segments/_full.segment.rsc +2 -2
- package/.next/server/app/settings/networks.segments/_head.segment.rsc +1 -1
- package/.next/server/app/settings/networks.segments/_index.segment.rsc +2 -2
- package/.next/server/app/settings/networks.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/settings/networks.segments/settings/networks/__PAGE__.segment.rsc +1 -1
- package/.next/server/app/settings/networks.segments/settings/networks.segment.rsc +1 -1
- package/.next/server/app/settings/networks.segments/settings.segment.rsc +1 -1
- 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 +2 -2
- package/.next/server/app/settings/tokens.segments/_full.segment.rsc +2 -2
- package/.next/server/app/settings/tokens.segments/_head.segment.rsc +1 -1
- package/.next/server/app/settings/tokens.segments/_index.segment.rsc +2 -2
- package/.next/server/app/settings/tokens.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/settings/tokens.segments/settings/tokens/__PAGE__.segment.rsc +1 -1
- package/.next/server/app/settings/tokens.segments/settings/tokens.segment.rsc +1 -1
- package/.next/server/app/settings/tokens.segments/settings.segment.rsc +1 -1
- package/.next/server/app/settings.html +2 -2
- package/.next/server/app/settings.rsc +3 -3
- package/.next/server/app/settings.segments/_full.segment.rsc +3 -3
- package/.next/server/app/settings.segments/_head.segment.rsc +1 -1
- package/.next/server/app/settings.segments/_index.segment.rsc +2 -2
- package/.next/server/app/settings.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/settings.segments/settings/__PAGE__.segment.rsc +2 -2
- package/.next/server/app/settings.segments/settings.segment.rsc +1 -1
- 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 +2 -2
- package/.next/server/app/tasks.segments/_full.segment.rsc +2 -2
- package/.next/server/app/tasks.segments/_head.segment.rsc +1 -1
- package/.next/server/app/tasks.segments/_index.segment.rsc +2 -2
- package/.next/server/app/tasks.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/tasks.segments/tasks/__PAGE__.segment.rsc +1 -1
- package/.next/server/app/tasks.segments/tasks.segment.rsc +1 -1
- 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/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/08wd64qaxk2x..js +4 -0
- package/.next/static/chunks/0_8eoaavz7.7w.js +1 -0
- package/.next/static/chunks/0a4hmfvj-81x5.css +2 -0
- package/.next/static/chunks/0c~70gswmge-5.js +1 -0
- package/.next/trace +2 -2
- package/.next/trace-build +1 -1
- package/app/components/TopoGraph.tsx +2469 -185
- package/package.json +1 -1
- package/screenshots/v0.11.0-147/after.png +0 -0
- package/scripts/p0-147-screenshot.mjs +53 -0
- package/scripts/topo-active-links-chip-hover-lift-test.mjs +93 -0
- package/scripts/topo-chip-digit-fontweight-test.mjs +105 -0
- package/scripts/topo-chip-digit-hover-bold-test.mjs +94 -0
- package/scripts/topo-chip-row-group-hover-brighten-test.mjs +107 -0
- package/scripts/topo-chip-row-hover-lift-test.mjs +95 -0
- package/scripts/topo-chrome-button-hover-lift-test.mjs +94 -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-segmented-radius-test.mjs +100 -0
- package/scripts/topo-chrome-zoom-icon-sw-test.mjs +90 -0
- package/scripts/topo-click-ripple-opacity-test.mjs +99 -0
- package/scripts/topo-dense-alias-opacity-test.mjs +68 -0
- package/scripts/topo-edge-badge-digit-fw-test.mjs +103 -0
- package/scripts/topo-edge-badge-fontsize-test.mjs +90 -0
- package/scripts/topo-edge-badge-hover-opacity-test.mjs +94 -0
- package/scripts/topo-edge-badge-hover-stroke-test.mjs +92 -0
- package/scripts/topo-edge-badge-letter-spacing-test.mjs +86 -0
- package/scripts/topo-edge-badge-opacity-test.mjs +80 -0
- package/scripts/topo-edge-badge-pin-opacity-test.mjs +86 -0
- package/scripts/topo-edge-badge-stroke-test.mjs +92 -0
- package/scripts/topo-edge-endpoint-hover-sw-test.mjs +127 -0
- package/scripts/topo-edge-freshness-floor-test.mjs +99 -0
- package/scripts/topo-edge-particle-hover-r-test.mjs +113 -0
- package/scripts/topo-edge-particle-radius-test.mjs +76 -0
- package/scripts/topo-edge-visible-linecap-test.mjs +89 -0
- package/scripts/topo-endpoint-ring-r-hover-test.mjs +89 -0
- package/scripts/topo-filter-pill-hover-lift-test.mjs +101 -0
- package/scripts/topo-filter-pill-hover-opacity-test.mjs +110 -0
- package/scripts/topo-filter-pill-value-fw-test.mjs +88 -0
- package/scripts/topo-filter-pill-x-hover-scale-test.mjs +99 -0
- package/scripts/topo-flow-rail-hover-sw-test.mjs +113 -0
- package/scripts/topo-flow-rail-linecap-test.mjs +79 -0
- package/scripts/topo-freshness-chip-hierarchy-test.mjs +93 -0
- package/scripts/topo-freshness-chip-tabular-test.mjs +41 -0
- package/scripts/topo-freshness-floor-lift-test.mjs +92 -0
- package/scripts/topo-freshness-suffix-tabular-test.mjs +88 -0
- package/scripts/topo-fullscreen-icon-hover-scale-test.mjs +91 -0
- package/scripts/topo-group-box-stroke-test.mjs +105 -0
- package/scripts/topo-group-label-count-fontweight-test.mjs +108 -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-letter-spacing-test.mjs +113 -0
- package/scripts/topo-group-pip-fontsize-test.mjs +106 -0
- package/scripts/topo-hover-detail-body-fw-test.mjs +101 -0
- package/scripts/topo-hover-detail-model-fw-test.mjs +98 -0
- package/scripts/topo-hover-detail-opacity-test.mjs +98 -0
- package/scripts/topo-hover-detail-rx-test.mjs +81 -0
- package/scripts/topo-hub-core-fill-hover-test.mjs +85 -0
- package/scripts/topo-hub-digit-fontsize-test.mjs +86 -0
- package/scripts/topo-hub-digit-fw-hover-test.mjs +102 -0
- package/scripts/topo-hub-halo-light-trough-test.mjs +88 -0
- package/scripts/topo-hub-halo-r-hover-test.mjs +82 -0
- package/scripts/topo-hub-halo-radius-test.mjs +86 -0
- package/scripts/topo-hub-halo-trough-test.mjs +83 -0
- package/scripts/topo-hub-highlight-opacity-test.mjs +88 -0
- package/scripts/topo-hub-highlight-radius-test.mjs +90 -0
- package/scripts/topo-hub-hover-ring-opacity-test.mjs +96 -0
- package/scripts/topo-hub-hover-ring-stroke-test.mjs +86 -0
- package/scripts/topo-hub-spoke-hover-opacity-test.mjs +119 -0
- package/scripts/topo-hub-spoke-hover-sw-test.mjs +121 -0
- package/scripts/topo-hub-spoke-linecap-test.mjs +80 -0
- package/scripts/topo-label-card-opacity-hover-test.mjs +99 -0
- package/scripts/topo-layout-toggle-radius-test.mjs +87 -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-legend-label-fontweight-test.mjs +94 -0
- package/scripts/topo-legend-pin-ring-stroke-test.mjs +101 -0
- package/scripts/topo-legend-row-letter-spacing-test.mjs +101 -0
- package/scripts/topo-minimap-offline-opacity-test.mjs +90 -0
- package/scripts/topo-minimap-online-hover-opacity-test.mjs +92 -0
- package/scripts/topo-minimap-online-opacity-test.mjs +93 -0
- package/scripts/topo-minimap-online-radius-test.mjs +85 -0
- package/scripts/topo-minimap-viewport-linejoin-test.mjs +75 -0
- package/scripts/topo-minimap-viewport-opacity-test.mjs +96 -0
- package/scripts/topo-minimap-viewport-rx-test.mjs +85 -0
- package/scripts/topo-more-flows-fontweight-test.mjs +103 -0
- package/scripts/topo-node-alias-letter-spacing-test.mjs +112 -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-halo-offline-opacity-test.mjs +87 -0
- package/scripts/topo-node-label-card-rx-test.mjs +85 -0
- package/scripts/topo-node-pulse-peak-test.mjs +89 -0
- package/scripts/topo-node-pulse-trough-test.mjs +91 -0
- package/scripts/topo-node-sub-text-fw-test.mjs +75 -0
- package/scripts/topo-node-sub-text-letter-spacing-test.mjs +115 -0
- package/scripts/topo-panel-count-fw-hover-test.mjs +105 -0
- package/scripts/topo-panel-stroke-hover-test.mjs +110 -0
- package/scripts/topo-pressure-bar-height-test.mjs +92 -0
- package/scripts/topo-pressure-kicker-fontweight-test.mjs +76 -0
- package/scripts/topo-recent-pip-radius-2-test.mjs +72 -0
- package/scripts/topo-recent-pip-radius-test.mjs +76 -0
- package/scripts/topo-recent-row-content-opacity-test.mjs +81 -0
- package/scripts/topo-recent-row-count-pin-fw-test.mjs +106 -0
- package/scripts/topo-recent-row-letter-spacing-test.mjs +109 -0
- package/scripts/topo-recent-row-pip-hover-r-test.mjs +104 -0
- package/scripts/topo-recent-row-text-fontweight-test.mjs +90 -0
- package/scripts/topo-runtime-icon-hover-test.mjs +96 -0
- package/scripts/topo-spoke-active-opacity-test.mjs +104 -0
- package/scripts/topo-spoke-active-stroke-test.mjs +95 -0
- package/scripts/topo-spoke-idle-opacity-test.mjs +91 -0
- package/scripts/topo-status-ring-hover-sw-test.mjs +105 -0
- package/scripts/topo-vendor-chip-hover-lift-test.mjs +87 -0
- package/scripts/topo-vendor-glyph-fontweight-test.mjs +102 -0
- package/scripts/topo-vendor-letter-hover-scale-test.mjs +129 -0
- package/scripts/topo-vendor-suffix-hover-brighten-test.mjs +87 -0
- package/scripts/topo-zoom-icon-hover-scale-test.mjs +114 -0
- package/scripts/topo-zoom-level-hover-fw-test.mjs +95 -0
- package/.next/static/chunks/0rwo2q9_by3o-.css +0 -2
- package/.next/static/chunks/122abdjq6gm8i.js +0 -4
- package/.next/static/chunks/156q5y0rq19h5.js +0 -1
- package/.next/static/chunks/163kbbv9y-8_7.js +0 -1
- /package/.next/static/{xhrrmtOS6EmcuOXkSdTGX → nZZeDhR9rXaGlwl6okEGV}/_buildManifest.js +0 -0
- /package/.next/static/{xhrrmtOS6EmcuOXkSdTGX → nZZeDhR9rXaGlwl6okEGV}/_clientMiddlewareManifest.js +0 -0
- /package/.next/static/{xhrrmtOS6EmcuOXkSdTGX → nZZeDhR9rXaGlwl6okEGV}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/* Round 444 verification: group label count tspan fontWeight lift —
|
|
2
|
+
* 500 → 600 on isPinned. Mirror of R416/R424/R425/R426 "data tightens
|
|
3
|
+
* under attention" pattern at group-label-count scope.
|
|
4
|
+
*
|
|
5
|
+
* Contract:
|
|
6
|
+
* - rest: every group-label-count reports font-weight '500' +
|
|
7
|
+
* pinned='false'
|
|
8
|
+
* - click a group-label-hit: that group's count flips to '600' +
|
|
9
|
+
* pinned='true'
|
|
10
|
+
* - siblings stay rest
|
|
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 {
|
|
23
|
+
localStorage.setItem('anet-theme', 'cyber');
|
|
24
|
+
localStorage.setItem('anet-topo-layout', 'grid');
|
|
25
|
+
sessionStorage.setItem('anet_v3_auth', '1');
|
|
26
|
+
} catch {}
|
|
27
|
+
});
|
|
28
|
+
await ctx.route('**/api/hub/status*', async (route) => {
|
|
29
|
+
const r = await route.fetch();
|
|
30
|
+
const b = await r.json();
|
|
31
|
+
const nid = (b.sessions || [])[0]?.network_id || 'default';
|
|
32
|
+
const mk = (alias, status) => ({
|
|
33
|
+
alias, status, model: 'claude-opus-4', runtime: 'claude-code-cli',
|
|
34
|
+
network_id: nid, project_dir: null,
|
|
35
|
+
created_at: fresh, updated_at: fresh, last_seen_at: fresh,
|
|
36
|
+
});
|
|
37
|
+
await route.fulfill({ response: r, json: { ...b, sessions: [
|
|
38
|
+
mk('alpha·1', 'working'),
|
|
39
|
+
mk('alpha·2', 'idle'),
|
|
40
|
+
mk('beta·1', 'working'),
|
|
41
|
+
mk('beta·2', 'idle'),
|
|
42
|
+
] } });
|
|
43
|
+
});
|
|
44
|
+
await ctx.route('**/api/hub/messages*', (r) => r.fulfill({ json: { messages: [] } }));
|
|
45
|
+
await ctx.route('**/api/hub/tasks*', (r) => r.fulfill({ json: { tasks: [] } }));
|
|
46
|
+
|
|
47
|
+
const page = await ctx.newPage();
|
|
48
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
|
|
49
|
+
await page.waitForSelector('[data-group-label-count]', { timeout: 15000 });
|
|
50
|
+
await page.waitForTimeout(400);
|
|
51
|
+
|
|
52
|
+
const readAll = () => page.evaluate(() => {
|
|
53
|
+
const ts = [...document.querySelectorAll('[data-group-label-count]')];
|
|
54
|
+
return ts.map(t => ({
|
|
55
|
+
key: t.getAttribute('data-group-label-count'),
|
|
56
|
+
fw: t.getAttribute('font-weight'),
|
|
57
|
+
pinned: t.getAttribute('data-group-label-count-pinned'),
|
|
58
|
+
}));
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
const rest = await readAll();
|
|
62
|
+
const firstKey = rest[0]?.key;
|
|
63
|
+
|
|
64
|
+
// Pin the first group by clicking its label-hit wrapper
|
|
65
|
+
let pinned = null;
|
|
66
|
+
if (firstKey) {
|
|
67
|
+
const hit = await page.$(`[data-group-label-hit="${firstKey}"]`);
|
|
68
|
+
if (hit) {
|
|
69
|
+
await hit.click();
|
|
70
|
+
await page.waitForTimeout(250);
|
|
71
|
+
pinned = await readAll();
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const fileText = readFileSync('/home/vansin/agent-network-dashboard/app/components/TopoGraph.tsx', 'utf8');
|
|
76
|
+
const sourceWired = /fontWeight=\{isPinned \? '600' : '500'\}/.test(fileText);
|
|
77
|
+
|
|
78
|
+
await browser.close();
|
|
79
|
+
|
|
80
|
+
const restAll500 = rest.every(r => r.fw === '500');
|
|
81
|
+
const restNoPin = rest.every(r => r.pinned === 'false');
|
|
82
|
+
const pinnedEntry = pinned?.find(r => r.key === firstKey);
|
|
83
|
+
const pinnedFw_600 = pinnedEntry?.fw === '600';
|
|
84
|
+
const pinnedFlag = pinnedEntry?.pinned === 'true';
|
|
85
|
+
const othersRest = pinned ? pinned.filter(r => r.key !== firstKey).every(r => r.fw === '500' && r.pinned === 'false') : false;
|
|
86
|
+
|
|
87
|
+
const results = {
|
|
88
|
+
rest_count_ge_2: rest.length >= 2,
|
|
89
|
+
rest_all_fw_500: restAll500,
|
|
90
|
+
rest_no_pin: restNoPin,
|
|
91
|
+
pinned_target_fw_600: pinnedFw_600,
|
|
92
|
+
pinned_target_flag: pinnedFlag,
|
|
93
|
+
pinned_others_stay: othersRest,
|
|
94
|
+
source_wired: sourceWired,
|
|
95
|
+
};
|
|
96
|
+
const ok = Object.values(results).every(Boolean);
|
|
97
|
+
console.log(`${ok ? '✅' : '❌'} group label count fw pin:`, JSON.stringify(results),
|
|
98
|
+
'\n rest:', JSON.stringify(rest),
|
|
99
|
+
'\n pinned target:', JSON.stringify(pinnedEntry));
|
|
100
|
+
process.exit(ok ? 0 : 1);
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/* Round 457 verification: group label parent text fontWeight 700 → 800
|
|
2
|
+
* on isPinned. Adds typographic weight axis at parent-text scope.
|
|
3
|
+
*
|
|
4
|
+
* Contract:
|
|
5
|
+
* - rest: every group-label parent <text> reports font-weight '700' +
|
|
6
|
+
* pinned='false'
|
|
7
|
+
* - click a group-label-hit: that group's <text> flips to '800' +
|
|
8
|
+
* pinned='true'; siblings stay rest
|
|
9
|
+
*/
|
|
10
|
+
import { chromium } from 'playwright';
|
|
11
|
+
import { readFileSync } from 'node:fs';
|
|
12
|
+
|
|
13
|
+
const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
|
|
14
|
+
const fresh = new Date(Date.now() - 60 * 1000).toISOString();
|
|
15
|
+
|
|
16
|
+
const browser = await chromium.launch({ headless: true });
|
|
17
|
+
const ctx = await browser.newContext({ viewport: { width: 1500, height: 1500 } });
|
|
18
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
19
|
+
await ctx.addInitScript(() => {
|
|
20
|
+
try {
|
|
21
|
+
localStorage.setItem('anet-theme', 'cyber');
|
|
22
|
+
localStorage.setItem('anet-topo-layout', 'grid');
|
|
23
|
+
sessionStorage.setItem('anet_v3_auth', '1');
|
|
24
|
+
} catch {}
|
|
25
|
+
});
|
|
26
|
+
await ctx.route('**/api/hub/status*', async (route) => {
|
|
27
|
+
const r = await route.fetch();
|
|
28
|
+
const b = await r.json();
|
|
29
|
+
const nid = (b.sessions || [])[0]?.network_id || 'default';
|
|
30
|
+
const mk = (alias, status) => ({
|
|
31
|
+
alias, status, model: 'claude-opus-4', runtime: 'claude-code-cli',
|
|
32
|
+
network_id: nid, project_dir: null,
|
|
33
|
+
created_at: fresh, updated_at: fresh, last_seen_at: fresh,
|
|
34
|
+
});
|
|
35
|
+
await route.fulfill({ response: r, json: { ...b, sessions: [
|
|
36
|
+
mk('alpha·1', 'working'),
|
|
37
|
+
mk('alpha·2', 'idle'),
|
|
38
|
+
mk('beta·1', 'working'),
|
|
39
|
+
mk('beta·2', 'idle'),
|
|
40
|
+
] } });
|
|
41
|
+
});
|
|
42
|
+
await ctx.route('**/api/hub/messages*', (r) => r.fulfill({ json: { messages: [] } }));
|
|
43
|
+
await ctx.route('**/api/hub/tasks*', (r) => r.fulfill({ json: { tasks: [] } }));
|
|
44
|
+
|
|
45
|
+
const page = await ctx.newPage();
|
|
46
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
|
|
47
|
+
await page.waitForSelector('[data-group-label]', { timeout: 15000 });
|
|
48
|
+
await page.waitForTimeout(400);
|
|
49
|
+
|
|
50
|
+
const readAll = () => page.evaluate(() => {
|
|
51
|
+
const ts = [...document.querySelectorAll('[data-group-label]')];
|
|
52
|
+
return ts.map(t => ({
|
|
53
|
+
key: t.getAttribute('data-group-label'),
|
|
54
|
+
fw: t.getAttribute('font-weight'),
|
|
55
|
+
fw_d: t.getAttribute('data-group-label-font-weight'),
|
|
56
|
+
pinned: t.getAttribute('data-group-label-pinned'),
|
|
57
|
+
}));
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
const rest = await readAll();
|
|
61
|
+
const firstKey = rest[0]?.key;
|
|
62
|
+
|
|
63
|
+
// Pin first group by clicking its hit-area
|
|
64
|
+
let pinned = null;
|
|
65
|
+
if (firstKey) {
|
|
66
|
+
const hit = await page.$(`[data-group-label-hit="${firstKey}"]`);
|
|
67
|
+
if (hit) {
|
|
68
|
+
await hit.click();
|
|
69
|
+
await page.waitForTimeout(250);
|
|
70
|
+
pinned = await readAll();
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const fileText = readFileSync('/home/vansin/agent-network-dashboard/app/components/TopoGraph.tsx', 'utf8');
|
|
75
|
+
const sourceWired = /fontWeight=\{isPinned \? '800' : '700'\}/.test(fileText);
|
|
76
|
+
|
|
77
|
+
await browser.close();
|
|
78
|
+
|
|
79
|
+
const restAll700 = rest.every(r => r.fw === '700');
|
|
80
|
+
const restNoPin = rest.every(r => r.pinned === 'false');
|
|
81
|
+
const pinnedEntry = pinned?.find(r => r.key === firstKey);
|
|
82
|
+
const pinFw800 = pinnedEntry?.fw === '800';
|
|
83
|
+
const pinFlag = pinnedEntry?.pinned === 'true';
|
|
84
|
+
const othersRest = pinned ? pinned.filter(r => r.key !== firstKey).every(r => r.fw === '700' && r.pinned === 'false') : false;
|
|
85
|
+
|
|
86
|
+
const results = {
|
|
87
|
+
rest_count_ge_2: rest.length >= 2,
|
|
88
|
+
rest_all_fw_700: restAll700,
|
|
89
|
+
rest_no_pin: restNoPin,
|
|
90
|
+
pinned_target_fw_800: pinFw800,
|
|
91
|
+
pinned_target_flag: pinFlag,
|
|
92
|
+
pinned_others_stay: othersRest,
|
|
93
|
+
source_wired: sourceWired,
|
|
94
|
+
};
|
|
95
|
+
const ok = Object.values(results).every(Boolean);
|
|
96
|
+
console.log(`${ok ? '✅' : '❌'} group label fw pin:`, JSON.stringify(results),
|
|
97
|
+
'\n rest:', JSON.stringify(rest),
|
|
98
|
+
'\n pinned target:', JSON.stringify(pinnedEntry));
|
|
99
|
+
process.exit(ok ? 0 : 1);
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/* Round 432 verification: group label text 3-tier letter-spacing —
|
|
2
|
+
* rest 0 / hover 0.25 / pinned 0.5. Extends R427 alias 3-tier and
|
|
3
|
+
* R431 edge-badge 3-tier to group-label scope. Hover-letter-spacing
|
|
4
|
+
* family now 8 anchors.
|
|
5
|
+
*
|
|
6
|
+
* Contract:
|
|
7
|
+
* - need >1 alias prefix group to mount group boxes (grid layout)
|
|
8
|
+
* - rest: every group-label reports letter-spacing '0px' (or
|
|
9
|
+
* 'normal' computed), pinned=false, hovered=false
|
|
10
|
+
* - hover one label-hit: that group-label reports letter-spacing
|
|
11
|
+
* '0.25px' + hovered=true (R432 mid tier)
|
|
12
|
+
* - source-file probe confirms 3-tier conditional
|
|
13
|
+
*/
|
|
14
|
+
import { chromium } from 'playwright';
|
|
15
|
+
import { readFileSync } from 'node:fs';
|
|
16
|
+
|
|
17
|
+
const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
|
|
18
|
+
const fresh = new Date(Date.now() - 60 * 1000).toISOString();
|
|
19
|
+
|
|
20
|
+
const browser = await chromium.launch({ headless: true });
|
|
21
|
+
const ctx = await browser.newContext({ viewport: { width: 1500, height: 1500 } });
|
|
22
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
23
|
+
await ctx.addInitScript(() => {
|
|
24
|
+
// Force grid layout (the layout toggle persists in localStorage)
|
|
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
|
+
// Sessions with alias prefix groups: alpha·X / beta·X / gamma·X
|
|
41
|
+
await route.fulfill({ response: r, json: { ...b, sessions: [
|
|
42
|
+
mk('alpha·1', 'working'),
|
|
43
|
+
mk('alpha·2', 'idle'),
|
|
44
|
+
mk('beta·1', 'working'),
|
|
45
|
+
mk('beta·2', 'idle'),
|
|
46
|
+
mk('gamma·1', 'working'),
|
|
47
|
+
mk('gamma·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 readAll = () => page.evaluate(() => {
|
|
59
|
+
const ts = [...document.querySelectorAll('[data-group-label]')];
|
|
60
|
+
return ts.map(t => ({
|
|
61
|
+
key: t.getAttribute('data-group-label'),
|
|
62
|
+
ls: t.style.letterSpacing,
|
|
63
|
+
pinned: t.getAttribute('data-group-label-pinned'),
|
|
64
|
+
hovered: t.getAttribute('data-group-label-hovered'),
|
|
65
|
+
}));
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
const rest = await readAll();
|
|
69
|
+
const firstKey = rest[0]?.key;
|
|
70
|
+
let hover = null;
|
|
71
|
+
if (firstKey) {
|
|
72
|
+
const box = await page.evaluate((key) => {
|
|
73
|
+
// Hover the label-hit <g> wrapper which dispatches onPointerEnter →
|
|
74
|
+
// setHoveredGroupLabel(key). The associated <text> shares the same
|
|
75
|
+
// box.key as data-group-label.
|
|
76
|
+
const hit = document.querySelector(`[data-group-label-hit="${key}"]`);
|
|
77
|
+
if (!hit) return null;
|
|
78
|
+
const b = hit.getBoundingClientRect();
|
|
79
|
+
return { x: b.x + b.width / 2, y: b.y + b.height / 2 };
|
|
80
|
+
}, firstKey);
|
|
81
|
+
if (box) {
|
|
82
|
+
await page.mouse.move(box.x, box.y);
|
|
83
|
+
await page.waitForTimeout(300);
|
|
84
|
+
hover = await readAll();
|
|
85
|
+
await page.mouse.move(0, 0);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const fileText = readFileSync('/home/vansin/agent-network-dashboard/app/components/TopoGraph.tsx', 'utf8');
|
|
90
|
+
const sourceWired = /letterSpacing:\s*isPinned\s*\?\s*'0\.5px'\s*:\s*\n?\s*isHovered\s*\?\s*'0\.25px'\s*:\s*'0px'/.test(fileText);
|
|
91
|
+
|
|
92
|
+
await browser.close();
|
|
93
|
+
|
|
94
|
+
const isRest = (ls) => ls === '0px' || ls === '' || ls === 'normal';
|
|
95
|
+
|
|
96
|
+
const hoveredEntry = hover?.find(r => r.key === firstKey);
|
|
97
|
+
const othersRest = hover ? hover.filter(r => r.key !== firstKey).every(r => isRest(r.ls)) : false;
|
|
98
|
+
|
|
99
|
+
const results = {
|
|
100
|
+
rest_count_gte_2: rest.length >= 2,
|
|
101
|
+
rest_all_zero: rest.every(r => isRest(r.ls)),
|
|
102
|
+
rest_all_pinned_false: rest.every(r => r.pinned === 'false'),
|
|
103
|
+
rest_all_hovered_false: rest.every(r => r.hovered === 'false'),
|
|
104
|
+
hover_target_ls_0_25: hoveredEntry?.ls === '0.25px',
|
|
105
|
+
hover_target_hovered_attr: hoveredEntry?.hovered === 'true',
|
|
106
|
+
hover_others_stay_rest: othersRest,
|
|
107
|
+
source_three_tier_wired: sourceWired,
|
|
108
|
+
};
|
|
109
|
+
const ok = Object.values(results).every(Boolean);
|
|
110
|
+
console.log(`${ok ? '✅' : '❌'} group label 3-tier letter-spacing:`, JSON.stringify(results),
|
|
111
|
+
'\n rest count:', rest.length,
|
|
112
|
+
'\n hover target:', JSON.stringify(hoveredEntry));
|
|
113
|
+
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,101 @@
|
|
|
1
|
+
/* Round 388 verification: hover-detail panel body lines fw 400 → 500.
|
|
2
|
+
* Small-text fw lift family (6th anchor) after R363 recent-row
|
|
3
|
+
* alias, R364 legend-row label, R366 group-label count tspan, R368
|
|
4
|
+
* +N footer, R373 pressure-bar kicker. Lifts the three fontSize=9
|
|
5
|
+
* body lines (runtime, host, task) in the on-hover product card to
|
|
6
|
+
* font-weight=500 so they read consistently bolder against the
|
|
7
|
+
* cyber-theme backdrop.
|
|
8
|
+
*
|
|
9
|
+
* Contract:
|
|
10
|
+
* - On hover, the hover-detail card mounts and:
|
|
11
|
+
* * Each fontSize=9 body line has font-weight attr === '500'
|
|
12
|
+
* * Each carries data-topo-hover-detail-body-fw === '500'
|
|
13
|
+
* * Tier structure preserved:
|
|
14
|
+
* - y=16 vendor headline at fw=700 unchanged
|
|
15
|
+
* - y=32 model subhead has no fw attr (preserved)
|
|
16
|
+
* - Task line keeps opacity 0.7 (R388 doesn't touch it)
|
|
17
|
+
* - The 3 body lines render at fontSize=9 (R388 doesn't touch size)
|
|
18
|
+
*
|
|
19
|
+
* Fixture: 2 idle sessions so hover-detail mounts cleanly without
|
|
20
|
+
* the dense-layout >16-node gate. Computed font-weight is asserted
|
|
21
|
+
* to be '500' as the browser-canonical resolution of the SVG attr.
|
|
22
|
+
*/
|
|
23
|
+
import { chromium } from 'playwright';
|
|
24
|
+
import { readFileSync } from 'node:fs';
|
|
25
|
+
|
|
26
|
+
const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
|
|
27
|
+
const fresh = new Date(Date.now() - 60 * 1000).toISOString();
|
|
28
|
+
|
|
29
|
+
const browser = await chromium.launch({ headless: true });
|
|
30
|
+
const ctx = await browser.newContext({ viewport: { width: 1500, height: 1500 } });
|
|
31
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
32
|
+
await ctx.addInitScript(() => {
|
|
33
|
+
try { localStorage.setItem('anet-theme', 'cyber'); sessionStorage.setItem('anet_v3_auth', '1'); } catch {}
|
|
34
|
+
});
|
|
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) => ({
|
|
40
|
+
alias, status: 'idle', 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: [ mk('alpha'), mk('beta') ] } });
|
|
45
|
+
});
|
|
46
|
+
await ctx.route('**/api/hub/messages*', (r) => r.fulfill({ json: { messages: [] } }));
|
|
47
|
+
await ctx.route('**/api/hub/tasks*', (r) => r.fulfill({ json: { tasks: [] } }));
|
|
48
|
+
|
|
49
|
+
const page = await ctx.newPage();
|
|
50
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
|
|
51
|
+
await page.waitForSelector('g[data-node]', { timeout: 15000 });
|
|
52
|
+
await page.waitForTimeout(300);
|
|
53
|
+
await page.hover('g[data-node]');
|
|
54
|
+
await page.waitForSelector('[data-topo-hover-detail]', { timeout: 5000 });
|
|
55
|
+
await page.waitForTimeout(300);
|
|
56
|
+
|
|
57
|
+
const probe = await page.evaluate(() => {
|
|
58
|
+
const card = document.querySelector('[data-topo-hover-detail]');
|
|
59
|
+
if (!card) return null;
|
|
60
|
+
const texts = Array.from(card.querySelectorAll('text'));
|
|
61
|
+
const lines = texts.map((t) => ({
|
|
62
|
+
y: t.getAttribute('y'),
|
|
63
|
+
fontSize: t.getAttribute('font-size'),
|
|
64
|
+
fwAttr: t.getAttribute('font-weight'),
|
|
65
|
+
fwData: t.getAttribute('data-topo-hover-detail-body-fw'),
|
|
66
|
+
fwComputed: getComputedStyle(t).fontWeight,
|
|
67
|
+
opacityAttr: t.getAttribute('opacity'),
|
|
68
|
+
}));
|
|
69
|
+
return { lines };
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
await browser.close();
|
|
73
|
+
|
|
74
|
+
const byY = Object.fromEntries((probe?.lines || []).map((l) => [l.y, l]));
|
|
75
|
+
|
|
76
|
+
const results = {
|
|
77
|
+
// y=16 vendor headline unchanged at fw=700
|
|
78
|
+
vendor_y16_fw700: byY['16']?.fwAttr === '700',
|
|
79
|
+
// y=32 model subhead — no R388 attrs (size 10 differentiation)
|
|
80
|
+
model_y32_size_10: byY['32']?.fontSize === '10',
|
|
81
|
+
model_y32_no_body_fw_attr: byY['32']?.fwData === null || byY['32']?.fwData === undefined,
|
|
82
|
+
// y=48 runtime body — R388 lifts to fw=500
|
|
83
|
+
runtime_y48_size_9: byY['48']?.fontSize === '9',
|
|
84
|
+
runtime_y48_fw500: byY['48']?.fwAttr === '500',
|
|
85
|
+
runtime_y48_data_500: byY['48']?.fwData === '500',
|
|
86
|
+
runtime_y48_computed_500: byY['48']?.fwComputed === '500',
|
|
87
|
+
// y=64 host body — R388 lifts to fw=500
|
|
88
|
+
host_y64_size_9: byY['64']?.fontSize === '9',
|
|
89
|
+
host_y64_fw500: byY['64']?.fwAttr === '500',
|
|
90
|
+
host_y64_data_500: byY['64']?.fwData === '500',
|
|
91
|
+
host_y64_computed_500: byY['64']?.fwComputed === '500',
|
|
92
|
+
// y=80 task body — R388 lifts to fw=500, opacity 0.7 preserved
|
|
93
|
+
task_y80_size_9: byY['80']?.fontSize === '9',
|
|
94
|
+
task_y80_fw500: byY['80']?.fwAttr === '500',
|
|
95
|
+
task_y80_data_500: byY['80']?.fwData === '500',
|
|
96
|
+
task_y80_opacity_07: byY['80']?.opacityAttr === '0.7',
|
|
97
|
+
};
|
|
98
|
+
const ok = Object.values(results).every(Boolean);
|
|
99
|
+
console.log(`${ok ? '✅' : '❌'} hover-detail body lines fw 400 → 500:`, JSON.stringify(results),
|
|
100
|
+
'\n lines:', JSON.stringify(probe?.lines, null, 2));
|
|
101
|
+
process.exit(ok ? 0 : 1);
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/* Round 389 verification: hover-detail model line (y=32) fw 400 → 600.
|
|
2
|
+
* Closes the hover-detail typography 3-tier ladder by giving the
|
|
3
|
+
* subhead its own weight tier between R0 vendor label badge (fw=700)
|
|
4
|
+
* and R388 body lines (fw=500). Sibling to the chip-internal-
|
|
5
|
+
* hierarchy arc (R333-R341/R362/R369) which uses fw=600 for value
|
|
6
|
+
* lines.
|
|
7
|
+
*
|
|
8
|
+
* Contract:
|
|
9
|
+
* - On hover, the hover-detail card mounts and:
|
|
10
|
+
* * y=32 <text> font-weight attr === '600'
|
|
11
|
+
* * y=32 data-topo-hover-detail-model-fw === '600'
|
|
12
|
+
* * y=32 computed font-weight === '600'
|
|
13
|
+
* * y=32 fontSize === '10' (R389 doesn't change size)
|
|
14
|
+
* - Tier ladder preserved:
|
|
15
|
+
* * y=16 vendor fw=700 (R0 invariant)
|
|
16
|
+
* * y=48/64/80 body fw=500 (R388 invariant)
|
|
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: 1500 } });
|
|
26
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
27
|
+
await ctx.addInitScript(() => {
|
|
28
|
+
try { localStorage.setItem('anet-theme', 'cyber'); sessionStorage.setItem('anet_v3_auth', '1'); } catch {}
|
|
29
|
+
});
|
|
30
|
+
await ctx.route('**/api/hub/status*', async (route) => {
|
|
31
|
+
const r = await route.fetch();
|
|
32
|
+
const b = await r.json();
|
|
33
|
+
const nid = (b.sessions || [])[0]?.network_id || 'default';
|
|
34
|
+
const mk = (alias) => ({
|
|
35
|
+
alias, status: 'idle', model: 'claude-opus-4', runtime: 'claude-code-cli',
|
|
36
|
+
network_id: nid, project_dir: null,
|
|
37
|
+
created_at: fresh, updated_at: fresh, last_seen_at: fresh,
|
|
38
|
+
});
|
|
39
|
+
await route.fulfill({ response: r, json: { ...b, sessions: [ mk('alpha'), mk('beta') ] } });
|
|
40
|
+
});
|
|
41
|
+
await ctx.route('**/api/hub/messages*', (r) => r.fulfill({ json: { messages: [] } }));
|
|
42
|
+
await ctx.route('**/api/hub/tasks*', (r) => r.fulfill({ json: { tasks: [] } }));
|
|
43
|
+
|
|
44
|
+
const page = await ctx.newPage();
|
|
45
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
|
|
46
|
+
await page.waitForSelector('g[data-node]', { timeout: 15000 });
|
|
47
|
+
await page.waitForTimeout(300);
|
|
48
|
+
await page.hover('g[data-node]');
|
|
49
|
+
await page.waitForSelector('[data-topo-hover-detail]', { timeout: 5000 });
|
|
50
|
+
await page.waitForTimeout(300);
|
|
51
|
+
|
|
52
|
+
const probe = await page.evaluate(() => {
|
|
53
|
+
const card = document.querySelector('[data-topo-hover-detail]');
|
|
54
|
+
if (!card) return null;
|
|
55
|
+
const texts = Array.from(card.querySelectorAll('text'));
|
|
56
|
+
const get = (y) => {
|
|
57
|
+
const t = texts.find((el) => el.getAttribute('y') === y);
|
|
58
|
+
return t ? {
|
|
59
|
+
fontSize: t.getAttribute('font-size'),
|
|
60
|
+
fwAttr: t.getAttribute('font-weight'),
|
|
61
|
+
fwComputed: getComputedStyle(t).fontWeight,
|
|
62
|
+
modelFwData: t.getAttribute('data-topo-hover-detail-model-fw'),
|
|
63
|
+
bodyFwData: t.getAttribute('data-topo-hover-detail-body-fw'),
|
|
64
|
+
} : null;
|
|
65
|
+
};
|
|
66
|
+
return {
|
|
67
|
+
vendor: get('16'),
|
|
68
|
+
model: get('32'),
|
|
69
|
+
runtime: get('48'),
|
|
70
|
+
host: get('64'),
|
|
71
|
+
task: get('80'),
|
|
72
|
+
};
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
await browser.close();
|
|
76
|
+
|
|
77
|
+
const results = {
|
|
78
|
+
// R389 changes: y=32 model lifted to fw=600
|
|
79
|
+
model_y32_size_10: probe?.model?.fontSize === '10',
|
|
80
|
+
model_y32_fw_attr_600: probe?.model?.fwAttr === '600',
|
|
81
|
+
model_y32_data_600: probe?.model?.modelFwData === '600',
|
|
82
|
+
model_y32_computed_600: probe?.model?.fwComputed === '600',
|
|
83
|
+
// R0 invariant: y=16 vendor fw=700 unchanged
|
|
84
|
+
vendor_y16_fw_700: probe?.vendor?.fwAttr === '700',
|
|
85
|
+
// R388 invariants: body lines y=48/64/80 fw=500 unchanged
|
|
86
|
+
runtime_y48_fw_500: probe?.runtime?.fwAttr === '500',
|
|
87
|
+
host_y64_fw_500: probe?.host?.fwAttr === '500',
|
|
88
|
+
task_y80_fw_500: probe?.task?.fwAttr === '500',
|
|
89
|
+
// Tier-isolation invariant: only y=32 carries the model-fw data attr
|
|
90
|
+
vendor_y16_no_model_attr: probe?.vendor?.modelFwData === null || probe?.vendor?.modelFwData === undefined,
|
|
91
|
+
runtime_y48_no_model_attr: probe?.runtime?.modelFwData === null || probe?.runtime?.modelFwData === undefined,
|
|
92
|
+
host_y64_no_model_attr: probe?.host?.modelFwData === null || probe?.host?.modelFwData === undefined,
|
|
93
|
+
task_y80_no_model_attr: probe?.task?.modelFwData === null || probe?.task?.modelFwData === undefined,
|
|
94
|
+
};
|
|
95
|
+
const ok = Object.values(results).every(Boolean);
|
|
96
|
+
console.log(`${ok ? '✅' : '❌'} hover-detail model line fw 400 → 600:`, JSON.stringify(results),
|
|
97
|
+
'\n probe:', JSON.stringify(probe, null, 2));
|
|
98
|
+
process.exit(ok ? 0 : 1);
|