@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,92 @@
|
|
|
1
|
+
/* Round 455 verification: chrome fullscreen icon (ENTER + EXIT
|
|
2
|
+
* variants) strokeWidth hover lift via Tailwind arbitrary class
|
|
3
|
+
* group-hover:[stroke-width:2.8]. Completes the chrome icon hover
|
|
4
|
+
* sw lift family (6 anchors).
|
|
5
|
+
*
|
|
6
|
+
* Contract:
|
|
7
|
+
* - rest: fullscreen-enter icon reports attr stroke-width '2.5' +
|
|
8
|
+
* computed '2.5px'
|
|
9
|
+
* - hover the fullscreen button: that icon computed '2.8px'
|
|
10
|
+
* - source-file probe confirms BOTH variants (enter + exit) carry
|
|
11
|
+
* the group-hover:[stroke-width:2.8] class
|
|
12
|
+
*/
|
|
13
|
+
import { chromium } from 'playwright';
|
|
14
|
+
import { readFileSync } from 'node:fs';
|
|
15
|
+
|
|
16
|
+
const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
|
|
17
|
+
const fresh = new Date(Date.now() - 60 * 1000).toISOString();
|
|
18
|
+
|
|
19
|
+
const browser = await chromium.launch({ headless: true });
|
|
20
|
+
const ctx = await browser.newContext({ viewport: { width: 1500, height: 1500 } });
|
|
21
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
22
|
+
await ctx.addInitScript(() => {
|
|
23
|
+
try { localStorage.setItem('anet-theme', 'cyber'); sessionStorage.setItem('anet_v3_auth', '1'); } catch {}
|
|
24
|
+
});
|
|
25
|
+
await ctx.route('**/api/hub/status*', async (route) => {
|
|
26
|
+
const r = await route.fetch();
|
|
27
|
+
const b = await r.json();
|
|
28
|
+
const nid = (b.sessions || [])[0]?.network_id || 'default';
|
|
29
|
+
const mk = (alias, status) => ({
|
|
30
|
+
alias, status, model: 'claude-opus-4', runtime: 'claude-code-cli',
|
|
31
|
+
network_id: nid, project_dir: null,
|
|
32
|
+
created_at: fresh, updated_at: fresh, last_seen_at: fresh,
|
|
33
|
+
});
|
|
34
|
+
await route.fulfill({ response: r, json: { ...b, sessions: [
|
|
35
|
+
mk('alpha', 'working'),
|
|
36
|
+
mk('beta', 'idle'),
|
|
37
|
+
] } });
|
|
38
|
+
});
|
|
39
|
+
await ctx.route('**/api/hub/messages*', (r) => r.fulfill({ json: { messages: [] } }));
|
|
40
|
+
await ctx.route('**/api/hub/tasks*', (r) => r.fulfill({ json: { tasks: [] } }));
|
|
41
|
+
|
|
42
|
+
const page = await ctx.newPage();
|
|
43
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
|
|
44
|
+
await page.waitForSelector('[data-topo-chrome-fullscreen-icon]', { timeout: 15000 });
|
|
45
|
+
await page.waitForTimeout(400);
|
|
46
|
+
|
|
47
|
+
const readIcon = () => page.evaluate(() => {
|
|
48
|
+
const i = document.querySelector('[data-topo-chrome-fullscreen-icon]');
|
|
49
|
+
return i ? {
|
|
50
|
+
variant: i.getAttribute('data-topo-chrome-fullscreen-icon'),
|
|
51
|
+
sw_attr: i.getAttribute('stroke-width'),
|
|
52
|
+
sw_computed: getComputedStyle(i).strokeWidth,
|
|
53
|
+
} : null;
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
const rest = await readIcon();
|
|
57
|
+
|
|
58
|
+
// Hover the fullscreen button parent — the button shares the group
|
|
59
|
+
// scope with the SVG icon child via Tailwind group/group-hover utility.
|
|
60
|
+
let hover = null;
|
|
61
|
+
const btn = await page.$('button[aria-label*="fullscreen" i], button[title*="ullscreen" i]');
|
|
62
|
+
if (btn) {
|
|
63
|
+
await btn.hover({ force: true });
|
|
64
|
+
await page.waitForTimeout(300);
|
|
65
|
+
hover = await readIcon();
|
|
66
|
+
await page.mouse.move(0, 0);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const fileText = readFileSync('/home/vansin/agent-network-dashboard/app/components/TopoGraph.tsx', 'utf8');
|
|
70
|
+
// className appears in TWO fullscreen-icon SVGs (enter + exit). Probe
|
|
71
|
+
// for both variants via separate searches:
|
|
72
|
+
const sourceFullscreenIconCount = (fileText.match(/data-topo-chrome-fullscreen-icon=/g) || []).length;
|
|
73
|
+
const sourceArbitrarySwCount = (fileText.match(/group-hover:\[stroke-width:2\.8\]/g) || []).length;
|
|
74
|
+
// We expect: zoom-in + zoom-out + fullscreen-enter + fullscreen-exit = 4 total
|
|
75
|
+
const sourceFourMatches = sourceArbitrarySwCount >= 4;
|
|
76
|
+
|
|
77
|
+
await browser.close();
|
|
78
|
+
|
|
79
|
+
const results = {
|
|
80
|
+
rest_mounted: !!rest,
|
|
81
|
+
rest_attr_2_5: rest?.sw_attr === '2.5',
|
|
82
|
+
rest_computed_2_5: rest?.sw_computed === '2.5px' || rest?.sw_computed === '2.5',
|
|
83
|
+
hover_computed_2_8: hover?.sw_computed === '2.8px' || hover?.sw_computed === '2.8',
|
|
84
|
+
source_fullscreen_variants: sourceFullscreenIconCount === 2,
|
|
85
|
+
source_arbitrary_4_matches: sourceFourMatches,
|
|
86
|
+
};
|
|
87
|
+
const ok = Object.values(results).every(Boolean);
|
|
88
|
+
console.log(`${ok ? '✅' : '❌'} chrome fullscreen icon sw hover:`, JSON.stringify(results),
|
|
89
|
+
'\n rest:', JSON.stringify(rest),
|
|
90
|
+
'\n hover:', JSON.stringify(hover),
|
|
91
|
+
'\n source matches: variants=' + sourceFullscreenIconCount + ' arbitrary-sw=' + sourceArbitrarySwCount);
|
|
92
|
+
process.exit(ok ? 0 : 1);
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/* Round 453 verification: chrome reset icon strokeWidth hover lift —
|
|
2
|
+
* 2.5 → 2.8 on hoveredReset && !resetSpinning. Sibling to R443
|
|
3
|
+
* runtime badge inner-icon sw lift.
|
|
4
|
+
*
|
|
5
|
+
* Contract:
|
|
6
|
+
* - rest: reset icon reports stroke-width '2.5' + hover='false'
|
|
7
|
+
* - hover the reset button: icon stroke-width '2.8' + hover='true'
|
|
8
|
+
*/
|
|
9
|
+
import { chromium } from 'playwright';
|
|
10
|
+
import { readFileSync } from 'node:fs';
|
|
11
|
+
|
|
12
|
+
const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
|
|
13
|
+
const fresh = new Date(Date.now() - 60 * 1000).toISOString();
|
|
14
|
+
|
|
15
|
+
const browser = await chromium.launch({ headless: true });
|
|
16
|
+
const ctx = await browser.newContext({ viewport: { width: 1500, height: 1500 } });
|
|
17
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
18
|
+
await ctx.addInitScript(() => {
|
|
19
|
+
try { localStorage.setItem('anet-theme', 'cyber'); sessionStorage.setItem('anet_v3_auth', '1'); } catch {}
|
|
20
|
+
});
|
|
21
|
+
await ctx.route('**/api/hub/status*', async (route) => {
|
|
22
|
+
const r = await route.fetch();
|
|
23
|
+
const b = await r.json();
|
|
24
|
+
const nid = (b.sessions || [])[0]?.network_id || 'default';
|
|
25
|
+
const mk = (alias, status) => ({
|
|
26
|
+
alias, status, model: 'claude-opus-4', runtime: 'claude-code-cli',
|
|
27
|
+
network_id: nid, project_dir: null,
|
|
28
|
+
created_at: fresh, updated_at: fresh, last_seen_at: fresh,
|
|
29
|
+
});
|
|
30
|
+
await route.fulfill({ response: r, json: { ...b, sessions: [
|
|
31
|
+
mk('alpha', 'working'),
|
|
32
|
+
mk('beta', 'idle'),
|
|
33
|
+
] } });
|
|
34
|
+
});
|
|
35
|
+
await ctx.route('**/api/hub/messages*', (r) => r.fulfill({ json: { messages: [] } }));
|
|
36
|
+
await ctx.route('**/api/hub/tasks*', (r) => r.fulfill({ json: { tasks: [] } }));
|
|
37
|
+
|
|
38
|
+
const page = await ctx.newPage();
|
|
39
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
|
|
40
|
+
await page.waitForSelector('[data-topo-chrome-reset-icon]', { timeout: 15000 });
|
|
41
|
+
await page.waitForTimeout(400);
|
|
42
|
+
|
|
43
|
+
const readIcon = () => page.evaluate(() => {
|
|
44
|
+
const i = document.querySelector('[data-topo-chrome-reset-icon]');
|
|
45
|
+
return i ? {
|
|
46
|
+
sw: i.getAttribute('stroke-width'),
|
|
47
|
+
sw_d: i.getAttribute('data-topo-chrome-reset-icon-stroke-width'),
|
|
48
|
+
hover: i.getAttribute('data-topo-chrome-reset-icon-hover'),
|
|
49
|
+
} : null;
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
const rest = await readIcon();
|
|
53
|
+
|
|
54
|
+
let hover = null;
|
|
55
|
+
const btn = await page.$('[data-topo-chrome-reset]');
|
|
56
|
+
if (btn) {
|
|
57
|
+
await btn.hover({ force: true });
|
|
58
|
+
await page.waitForTimeout(250);
|
|
59
|
+
hover = await readIcon();
|
|
60
|
+
await page.mouse.move(0, 0);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const fileText = readFileSync('/home/vansin/agent-network-dashboard/app/components/TopoGraph.tsx', 'utf8');
|
|
64
|
+
const sourceWired = /strokeWidth=\{hoveredReset && !resetSpinning \? '2\.8' : '2\.5'\}/.test(fileText);
|
|
65
|
+
|
|
66
|
+
await browser.close();
|
|
67
|
+
|
|
68
|
+
const results = {
|
|
69
|
+
rest_mounted: !!rest,
|
|
70
|
+
rest_sw_2_5: rest?.sw === '2.5',
|
|
71
|
+
rest_hover_false: rest?.hover === 'false',
|
|
72
|
+
hover_sw_2_8: hover?.sw === '2.8',
|
|
73
|
+
hover_sw_data_2_8: hover?.sw_d === '2.8',
|
|
74
|
+
hover_hover_true: hover?.hover === 'true',
|
|
75
|
+
source_wired: sourceWired,
|
|
76
|
+
};
|
|
77
|
+
const ok = Object.values(results).every(Boolean);
|
|
78
|
+
console.log(`${ok ? '✅' : '❌'} chrome reset icon sw hover:`, JSON.stringify(results),
|
|
79
|
+
'\n rest:', rest, '\n hover:', hover);
|
|
80
|
+
process.exit(ok ? 0 : 1);
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/* Round 376 verification: nodeSize + zoom segmented control wrappers
|
|
2
|
+
* rounded-md → rounded-lg (6 → 8 px). Sibling polish to R375 Layout-
|
|
3
|
+
* toggle wrapper — three chrome-strip segmented controls now all
|
|
4
|
+
* share rounded-lg at the wrapper tier:
|
|
5
|
+
* R375 Layout-toggle wrapper rounded-lg 8 px
|
|
6
|
+
* R376 nodeSize wrapper rounded-lg 8 px (this round)
|
|
7
|
+
* R376 zoom wrapper rounded-lg 8 px (this round)
|
|
8
|
+
*
|
|
9
|
+
* Individual atomic chrome buttons (reset, fullscreen) keep rounded-
|
|
10
|
+
* md (6 px) as their own atomic-button tier — chrome strip now
|
|
11
|
+
* expresses a two-tier hierarchy: 'segmented control container'
|
|
12
|
+
* (rounded-lg) vs 'standalone button' (rounded-md).
|
|
13
|
+
*
|
|
14
|
+
* Contract:
|
|
15
|
+
* - [data-topo-chrome-nodesize-radius] computed border-radius '8px'.
|
|
16
|
+
* - data-topo-chrome-nodesize-radius === 'rounded-lg'.
|
|
17
|
+
* - [data-topo-chrome-zoom-wrapper-radius] computed border-radius '8px'.
|
|
18
|
+
* - data-topo-chrome-zoom-wrapper-radius === 'rounded-lg'.
|
|
19
|
+
* - Pre-R376 invariants: border 1px + flex display + overflow:hidden
|
|
20
|
+
* + R263 background-color/border-color transition preserved on
|
|
21
|
+
* each wrapper.
|
|
22
|
+
* - Atomic reset + fullscreen buttons still have border-radius 6px
|
|
23
|
+
* (rounded-md, untouched).
|
|
24
|
+
*/
|
|
25
|
+
import { chromium } from 'playwright';
|
|
26
|
+
import { readFileSync } from 'node:fs';
|
|
27
|
+
|
|
28
|
+
const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
|
|
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
|
+
const fresh = new Date(Date.now() - 60 * 1000).toISOString();
|
|
36
|
+
await ctx.route('**/api/hub/status*', async (route) => {
|
|
37
|
+
const r = await route.fetch();
|
|
38
|
+
const b = await r.json();
|
|
39
|
+
const nid = (b.sessions || [])[0]?.network_id || 'default';
|
|
40
|
+
const mk = (alias) => ({
|
|
41
|
+
alias, status: 'working', model: 'claude-opus-4', runtime: 'claude-code-cli',
|
|
42
|
+
network_id: nid, project_dir: null,
|
|
43
|
+
created_at: fresh, updated_at: fresh, last_seen_at: fresh,
|
|
44
|
+
});
|
|
45
|
+
await route.fulfill({ response: r, json: { ...b, sessions: [ mk('a'), mk('b'), mk('c') ] } });
|
|
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-topo-chrome-nodesize-radius]', { timeout: 15000 });
|
|
53
|
+
await page.waitForSelector('[data-topo-chrome-zoom-wrapper-radius]', { timeout: 5000 });
|
|
54
|
+
await page.waitForTimeout(300);
|
|
55
|
+
|
|
56
|
+
const probe = await page.evaluate(() => {
|
|
57
|
+
const nodesize = document.querySelector('[data-topo-chrome-nodesize-radius]');
|
|
58
|
+
const zoom = document.querySelector('[data-topo-chrome-zoom-wrapper-radius]');
|
|
59
|
+
const reset = document.querySelector('[data-topo-chrome-reset]');
|
|
60
|
+
const fs = document.querySelector('[data-topo-chrome-fullscreen]');
|
|
61
|
+
const ncs = nodesize ? getComputedStyle(nodesize) : null;
|
|
62
|
+
const zcs = zoom ? getComputedStyle(zoom) : null;
|
|
63
|
+
const rcs = reset ? getComputedStyle(reset) : null;
|
|
64
|
+
const fcs = fs ? getComputedStyle(fs) : null;
|
|
65
|
+
return {
|
|
66
|
+
nodesizeRadius: ncs?.borderRadius ?? null,
|
|
67
|
+
nodesizeData: nodesize?.getAttribute('data-topo-chrome-nodesize-radius') ?? null,
|
|
68
|
+
nodesizeBorderW: ncs?.borderWidth ?? null,
|
|
69
|
+
nodesizeTrans: ncs?.transition ?? null,
|
|
70
|
+
zoomRadius: zcs?.borderRadius ?? null,
|
|
71
|
+
zoomData: zoom?.getAttribute('data-topo-chrome-zoom-wrapper-radius') ?? null,
|
|
72
|
+
zoomBorderW: zcs?.borderWidth ?? null,
|
|
73
|
+
zoomTrans: zcs?.transition ?? null,
|
|
74
|
+
resetRadius: rcs?.borderRadius ?? null,
|
|
75
|
+
fullscreenRadius: fcs?.borderRadius ?? null,
|
|
76
|
+
};
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
await browser.close();
|
|
80
|
+
|
|
81
|
+
const hasTrans = (s, prop) =>
|
|
82
|
+
new RegExp(`${prop}\\s+\\d*\\.?\\d*s|${prop}\\s+\\d+ms`, 'i').test(s || '');
|
|
83
|
+
|
|
84
|
+
const results = {
|
|
85
|
+
nodesize_radius_8px: probe.nodesizeRadius === '8px', // rounded-lg
|
|
86
|
+
nodesize_data_lg: probe.nodesizeData === 'rounded-lg',
|
|
87
|
+
nodesize_border_1px: probe.nodesizeBorderW === '1px',
|
|
88
|
+
nodesize_trans_border: hasTrans(probe.nodesizeTrans, 'border-color'), // R263 / R268
|
|
89
|
+
zoom_radius_8px: probe.zoomRadius === '8px',
|
|
90
|
+
zoom_data_lg: probe.zoomData === 'rounded-lg',
|
|
91
|
+
zoom_border_1px: probe.zoomBorderW === '1px',
|
|
92
|
+
zoom_trans_border: hasTrans(probe.zoomTrans, 'border-color'),
|
|
93
|
+
// Atomic chrome buttons stay rounded-md (6 px) — invariant.
|
|
94
|
+
reset_still_md: probe.resetRadius === '6px',
|
|
95
|
+
fullscreen_still_md: probe.fullscreenRadius === '6px',
|
|
96
|
+
};
|
|
97
|
+
const ok = Object.values(results).every(Boolean);
|
|
98
|
+
console.log(`${ok ? '✅' : '❌'} chrome segmented wrappers rounded-md → rounded-lg:`, JSON.stringify(results),
|
|
99
|
+
'\n probe:', probe);
|
|
100
|
+
process.exit(ok ? 0 : 1);
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/* Round 454 verification: chrome zoom +/- icons strokeWidth hover lift
|
|
2
|
+
* via Tailwind arbitrary class group-hover:[stroke-width:2.8].
|
|
3
|
+
* The attribute strokeWidth='2.5' stays at rest; CSS hover overrides
|
|
4
|
+
* with stroke-width: 2.8.
|
|
5
|
+
*
|
|
6
|
+
* Contract:
|
|
7
|
+
* - rest: zoom-in/zoom-out icons report computed stroke-width '2.5px'
|
|
8
|
+
* - hover the zoom-in button: that icon computed stroke-width '2.8px'
|
|
9
|
+
* - source-file probe confirms group-hover:[stroke-width:2.8] in
|
|
10
|
+
* both icon className strings
|
|
11
|
+
*/
|
|
12
|
+
import { chromium } from 'playwright';
|
|
13
|
+
import { readFileSync } from 'node:fs';
|
|
14
|
+
|
|
15
|
+
const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
|
|
16
|
+
const fresh = new Date(Date.now() - 60 * 1000).toISOString();
|
|
17
|
+
|
|
18
|
+
const browser = await chromium.launch({ headless: true });
|
|
19
|
+
const ctx = await browser.newContext({ viewport: { width: 1500, height: 1500 } });
|
|
20
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
21
|
+
await ctx.addInitScript(() => {
|
|
22
|
+
try { localStorage.setItem('anet-theme', 'cyber'); sessionStorage.setItem('anet_v3_auth', '1'); } catch {}
|
|
23
|
+
});
|
|
24
|
+
await ctx.route('**/api/hub/status*', async (route) => {
|
|
25
|
+
const r = await route.fetch();
|
|
26
|
+
const b = await r.json();
|
|
27
|
+
const nid = (b.sessions || [])[0]?.network_id || 'default';
|
|
28
|
+
const mk = (alias, status) => ({
|
|
29
|
+
alias, status, model: 'claude-opus-4', runtime: 'claude-code-cli',
|
|
30
|
+
network_id: nid, project_dir: null,
|
|
31
|
+
created_at: fresh, updated_at: fresh, last_seen_at: fresh,
|
|
32
|
+
});
|
|
33
|
+
await route.fulfill({ response: r, json: { ...b, sessions: [
|
|
34
|
+
mk('alpha', 'working'),
|
|
35
|
+
mk('beta', 'idle'),
|
|
36
|
+
] } });
|
|
37
|
+
});
|
|
38
|
+
await ctx.route('**/api/hub/messages*', (r) => r.fulfill({ json: { messages: [] } }));
|
|
39
|
+
await ctx.route('**/api/hub/tasks*', (r) => r.fulfill({ json: { tasks: [] } }));
|
|
40
|
+
|
|
41
|
+
const page = await ctx.newPage();
|
|
42
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
|
|
43
|
+
await page.waitForSelector('[data-topo-chrome-zoom-in-icon]', { timeout: 15000 });
|
|
44
|
+
await page.waitForTimeout(400);
|
|
45
|
+
|
|
46
|
+
const readIcons = () => page.evaluate(() => {
|
|
47
|
+
const zi = document.querySelector('[data-topo-chrome-zoom-in-icon]');
|
|
48
|
+
const zo = document.querySelector('[data-topo-chrome-zoom-out-icon]');
|
|
49
|
+
return {
|
|
50
|
+
zoom_in: zi ? { sw: zi.getAttribute('stroke-width'), sw_computed: getComputedStyle(zi).strokeWidth } : null,
|
|
51
|
+
zoom_out: zo ? { sw: zo.getAttribute('stroke-width'), sw_computed: getComputedStyle(zo).strokeWidth } : null,
|
|
52
|
+
};
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
const rest = await readIcons();
|
|
56
|
+
|
|
57
|
+
// Hover zoom-in button
|
|
58
|
+
let hover = null;
|
|
59
|
+
const btn = await page.$('[data-topo-chrome-zoom-in]');
|
|
60
|
+
if (btn) {
|
|
61
|
+
await btn.hover({ force: true });
|
|
62
|
+
await page.waitForTimeout(300);
|
|
63
|
+
hover = await readIcons();
|
|
64
|
+
await page.mouse.move(0, 0);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const fileText = readFileSync('/home/vansin/agent-network-dashboard/app/components/TopoGraph.tsx', 'utf8');
|
|
68
|
+
// className appears BEFORE data-attr on the icon SVG, so check both
|
|
69
|
+
// orderings + count >= 2 to confirm both zoom icons have the class.
|
|
70
|
+
const sourceMatch = fileText.match(/group-hover:\[stroke-width:2\.8\]/g);
|
|
71
|
+
const sourceTwoMatches = sourceMatch && sourceMatch.length >= 2;
|
|
72
|
+
const sourceZoomOut = /group-hover:\[stroke-width:2\.8\][\s\S]{0,400}data-topo-chrome-zoom-out-icon/.test(fileText);
|
|
73
|
+
const sourceZoomIn = /group-hover:\[stroke-width:2\.8\][\s\S]{0,400}data-topo-chrome-zoom-in-icon/.test(fileText);
|
|
74
|
+
|
|
75
|
+
await browser.close();
|
|
76
|
+
|
|
77
|
+
const results = {
|
|
78
|
+
rest_zi_attr_2_5: rest.zoom_in?.sw === '2.5',
|
|
79
|
+
rest_zo_attr_2_5: rest.zoom_out?.sw === '2.5',
|
|
80
|
+
rest_zi_computed_2_5: rest.zoom_in?.sw_computed === '2.5px' || rest.zoom_in?.sw_computed === '2.5',
|
|
81
|
+
hover_zi_computed_2_8: hover?.zoom_in?.sw_computed === '2.8px' || hover?.zoom_in?.sw_computed === '2.8',
|
|
82
|
+
source_zoom_out_wired: sourceZoomOut,
|
|
83
|
+
source_zoom_in_wired: sourceZoomIn,
|
|
84
|
+
source_two_matches: sourceTwoMatches,
|
|
85
|
+
};
|
|
86
|
+
const ok = Object.values(results).every(Boolean);
|
|
87
|
+
console.log(`${ok ? '✅' : '❌'} chrome zoom icon sw hover:`, JSON.stringify(results),
|
|
88
|
+
'\n rest:', JSON.stringify(rest),
|
|
89
|
+
'\n hover:', JSON.stringify(hover));
|
|
90
|
+
process.exit(ok ? 0 : 1);
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/* Round 403 verification: click-ripple SMIL initial opacity 0.7 →
|
|
2
|
+
* 0.8. Theme-consistency / canvas-presence polish family (8th
|
|
3
|
+
* anchor) — click-feedback now starts at the same 0.8 alpha as
|
|
4
|
+
* R370 hub hover-ring and R391 hub-spoke active. Three canvas
|
|
5
|
+
* state-feedback indicators share a uniform 0.8 start alpha.
|
|
6
|
+
*
|
|
7
|
+
* Contract:
|
|
8
|
+
* - Click the hub to fire the ripple (R52 fitView click path)
|
|
9
|
+
* - data-click-ripple-start-opacity === '0.8' on the opacity
|
|
10
|
+
* <animate> element
|
|
11
|
+
* - The opacity animation `values` starts with '0.8'
|
|
12
|
+
* - Pre-R403 invariants preserved:
|
|
13
|
+
* * dur='0.5s'
|
|
14
|
+
* * R227 calcMode='spline'
|
|
15
|
+
* * R227 keySplines='0.25 0.1 0.25 1'
|
|
16
|
+
* * fill='freeze'
|
|
17
|
+
*
|
|
18
|
+
* Source-file verification fallback: the SMIL element appears
|
|
19
|
+
* only during the 500ms ripple window, so the test reads source
|
|
20
|
+
* if the runtime probe doesn't catch the element in flight.
|
|
21
|
+
*/
|
|
22
|
+
import { chromium } from 'playwright';
|
|
23
|
+
import { readFileSync } from 'node:fs';
|
|
24
|
+
|
|
25
|
+
const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
|
|
26
|
+
const fresh = new Date(Date.now() - 60 * 1000).toISOString();
|
|
27
|
+
|
|
28
|
+
const browser = await chromium.launch({ headless: true });
|
|
29
|
+
const ctx = await browser.newContext({ viewport: { width: 1500, height: 1500 } });
|
|
30
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
31
|
+
await ctx.addInitScript(() => {
|
|
32
|
+
try { localStorage.setItem('anet-theme', 'cyber'); sessionStorage.setItem('anet_v3_auth', '1'); } 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) => ({
|
|
39
|
+
alias, status: 'idle', 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: [ mk('alpha'), mk('beta') ] } });
|
|
44
|
+
});
|
|
45
|
+
await ctx.route('**/api/hub/messages*', (r) => r.fulfill({ json: { messages: [] } }));
|
|
46
|
+
await ctx.route('**/api/hub/tasks*', (r) => r.fulfill({ json: { tasks: [] } }));
|
|
47
|
+
|
|
48
|
+
const page = await ctx.newPage();
|
|
49
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
|
|
50
|
+
await page.waitForSelector('[data-topo-hub]', { timeout: 15000 });
|
|
51
|
+
await page.waitForTimeout(400);
|
|
52
|
+
|
|
53
|
+
// Click hub to fire ripple
|
|
54
|
+
await page.click('[data-topo-hub]');
|
|
55
|
+
await page.waitForTimeout(100); // ripple lives 500ms, probe early
|
|
56
|
+
|
|
57
|
+
const probe = await page.evaluate(() => {
|
|
58
|
+
const ripple = document.querySelector('[data-click-ripple]');
|
|
59
|
+
if (!ripple) return null;
|
|
60
|
+
const opacityAnim = ripple.querySelector('[data-click-ripple-start-opacity]');
|
|
61
|
+
return {
|
|
62
|
+
rippleMounted: true,
|
|
63
|
+
strokeWidth: ripple.getAttribute('stroke-width'),
|
|
64
|
+
fillAttr: ripple.getAttribute('fill'),
|
|
65
|
+
startOpacity: opacityAnim?.getAttribute('data-click-ripple-start-opacity') ?? null,
|
|
66
|
+
valuesAttr: opacityAnim?.getAttribute('values') ?? null,
|
|
67
|
+
durAttr: opacityAnim?.getAttribute('dur') ?? null,
|
|
68
|
+
calcMode: opacityAnim?.getAttribute('calcMode') ?? null,
|
|
69
|
+
keySplines: opacityAnim?.getAttribute('keySplines') ?? null,
|
|
70
|
+
fillFreeze: opacityAnim?.getAttribute('fill') ?? null,
|
|
71
|
+
};
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
// Source-file fallback in case the SMIL element is not caught
|
|
75
|
+
const fileText = readFileSync('/home/vansin/agent-network-dashboard/app/components/TopoGraph.tsx', 'utf8');
|
|
76
|
+
const sourceHasStartOpacity = fileText.includes('data-click-ripple-start-opacity="0.8"');
|
|
77
|
+
const sourceHasValues08 = fileText.includes('values="0.8;0"');
|
|
78
|
+
|
|
79
|
+
await browser.close();
|
|
80
|
+
|
|
81
|
+
const results = {
|
|
82
|
+
// Source-file invariants (deterministic from disk)
|
|
83
|
+
source_start_opacity_attr: sourceHasStartOpacity,
|
|
84
|
+
source_values_0_8_to_0: sourceHasValues08,
|
|
85
|
+
// Runtime probe (best-effort during 500ms ripple window)
|
|
86
|
+
ripple_mounted: !!probe,
|
|
87
|
+
start_opacity_0_8: probe?.startOpacity === '0.8',
|
|
88
|
+
values_0_8_to_0: probe?.valuesAttr === '0.8;0',
|
|
89
|
+
dur_0_5s: probe?.durAttr === '0.5s',
|
|
90
|
+
calcMode_spline: probe?.calcMode === 'spline',
|
|
91
|
+
keySplines_easeout: probe?.keySplines === '0.25 0.1 0.25 1',
|
|
92
|
+
// Static ring invariants
|
|
93
|
+
strokeWidth_2: probe?.strokeWidth === '2',
|
|
94
|
+
fill_none: probe?.fillAttr === 'none',
|
|
95
|
+
};
|
|
96
|
+
const ok = Object.values(results).every(Boolean);
|
|
97
|
+
console.log(`${ok ? '✅' : '❌'} click-ripple SMIL opacity 0.7 → 0.8:`, JSON.stringify(results),
|
|
98
|
+
'\n probe:', JSON.stringify(probe, null, 2));
|
|
99
|
+
process.exit(ok ? 0 : 1);
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/* Round 452 verification: dense plain-text alias rest opacity 0.9 → 0.95.
|
|
2
|
+
* Sibling to R449/R450 canvas-presence alpha-gap closures.
|
|
3
|
+
*
|
|
4
|
+
* Contract:
|
|
5
|
+
* - need >16 sessions to enter dense layout
|
|
6
|
+
* - every dense alias-text reports opacity '0.95' + -opacity attr '0.95'
|
|
7
|
+
* - source-file probe confirms the value
|
|
8
|
+
*/
|
|
9
|
+
import { chromium } from 'playwright';
|
|
10
|
+
import { readFileSync } from 'node:fs';
|
|
11
|
+
|
|
12
|
+
const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
|
|
13
|
+
const fresh = new Date(Date.now() - 60 * 1000).toISOString();
|
|
14
|
+
|
|
15
|
+
const browser = await chromium.launch({ headless: true });
|
|
16
|
+
const ctx = await browser.newContext({ viewport: { width: 1500, height: 1500 } });
|
|
17
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
18
|
+
await ctx.addInitScript(() => {
|
|
19
|
+
try { localStorage.setItem('anet-theme', 'cyber'); sessionStorage.setItem('anet_v3_auth', '1'); } catch {}
|
|
20
|
+
});
|
|
21
|
+
await ctx.route('**/api/hub/status*', async (route) => {
|
|
22
|
+
const r = await route.fetch();
|
|
23
|
+
const b = await r.json();
|
|
24
|
+
const nid = (b.sessions || [])[0]?.network_id || 'default';
|
|
25
|
+
const mk = (alias, status) => ({
|
|
26
|
+
alias, status, model: 'claude-opus-4', runtime: 'claude-code-cli',
|
|
27
|
+
network_id: nid, project_dir: null,
|
|
28
|
+
created_at: fresh, updated_at: fresh, last_seen_at: fresh,
|
|
29
|
+
});
|
|
30
|
+
// 20 nodes — crosses the >16 dense threshold
|
|
31
|
+
const sessions = [];
|
|
32
|
+
for (let i = 0; i < 20; i++) {
|
|
33
|
+
sessions.push(mk(`n${String(i).padStart(2, '0')}`, i % 3 === 0 ? 'working' : 'idle'));
|
|
34
|
+
}
|
|
35
|
+
await route.fulfill({ response: r, json: { ...b, sessions } });
|
|
36
|
+
});
|
|
37
|
+
await ctx.route('**/api/hub/messages*', (r) => r.fulfill({ json: { messages: [] } }));
|
|
38
|
+
await ctx.route('**/api/hub/tasks*', (r) => r.fulfill({ json: { tasks: [] } }));
|
|
39
|
+
|
|
40
|
+
const page = await ctx.newPage();
|
|
41
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
|
|
42
|
+
await page.waitForSelector('[data-node-dense-alias-text]', { timeout: 15000 });
|
|
43
|
+
await page.waitForTimeout(400);
|
|
44
|
+
|
|
45
|
+
const aliases = await page.evaluate(() => {
|
|
46
|
+
const ts = [...document.querySelectorAll('[data-node-dense-alias-text]')];
|
|
47
|
+
return ts.map(t => ({
|
|
48
|
+
alias: t.getAttribute('data-node-dense-alias-text'),
|
|
49
|
+
opacity: t.getAttribute('opacity'),
|
|
50
|
+
data_op: t.getAttribute('data-node-dense-alias-text-opacity'),
|
|
51
|
+
}));
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
const fileText = readFileSync('/home/vansin/agent-network-dashboard/app/components/TopoGraph.tsx', 'utf8');
|
|
55
|
+
const sourceWired = /opacity=\{0\.95\}/.test(fileText) && /data-node-dense-alias-text-opacity="0\.95"/.test(fileText);
|
|
56
|
+
|
|
57
|
+
await browser.close();
|
|
58
|
+
|
|
59
|
+
const results = {
|
|
60
|
+
dense_layout_count_ge_17: aliases.length >= 17,
|
|
61
|
+
all_opacity_0_95: aliases.every(a => a.opacity === '0.95'),
|
|
62
|
+
all_data_op_0_95: aliases.every(a => a.data_op === '0.95'),
|
|
63
|
+
source_wired: sourceWired,
|
|
64
|
+
};
|
|
65
|
+
const ok = Object.values(results).every(Boolean);
|
|
66
|
+
console.log(`${ok ? '✅' : '❌'} dense alias opacity 0.95:`, JSON.stringify(results),
|
|
67
|
+
'\n count:', aliases.length, 'sample:', JSON.stringify(aliases[0]));
|
|
68
|
+
process.exit(ok ? 0 : 1);
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/* Round 426 verification: edge-badge digit fontWeight 700 → 800 on
|
|
2
|
+
* (isPinned || isHot). 4th anchor on the "data tightens under
|
|
3
|
+
* attention" typographic-weight pattern:
|
|
4
|
+
* R416 chip-digit (chip-row hover)
|
|
5
|
+
* R424 panel-digit (panel hover)
|
|
6
|
+
* R425 hub-digit (hub hover)
|
|
7
|
+
* R426 edge-badge (pin/hot) ← this round
|
|
8
|
+
*
|
|
9
|
+
* Contract:
|
|
10
|
+
* - rest state: edge-badge text font-weight === '700'
|
|
11
|
+
* - hot state (synthesize via dense recent traffic between two
|
|
12
|
+
* aliases): badge text font-weight === '800', data-edge-badge-
|
|
13
|
+
* text-pin === 'true', letter-spacing '0.4px' (R220 preserved)
|
|
14
|
+
* - source-file probe confirms wired conditional + transition list
|
|
15
|
+
*
|
|
16
|
+
* Test design: 'hot' is derived from flow link count threshold (R190
|
|
17
|
+
* hotFlowCount logic). We don't depend on knowing the exact threshold —
|
|
18
|
+
* we just generate many flow messages between alpha↔beta and assert
|
|
19
|
+
* at least one badge enters the pin state. The source-file probe is
|
|
20
|
+
* the canonical contract for the wire change; the DOM probe is best-
|
|
21
|
+
* effort confirmation that the conditional resolves to '800' for at
|
|
22
|
+
* least one badge in some fixture state.
|
|
23
|
+
*/
|
|
24
|
+
import { chromium } from 'playwright';
|
|
25
|
+
import { readFileSync } from 'node:fs';
|
|
26
|
+
|
|
27
|
+
const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
|
|
28
|
+
const fresh = new Date(Date.now() - 60 * 1000).toISOString();
|
|
29
|
+
|
|
30
|
+
const browser = await chromium.launch({ headless: true });
|
|
31
|
+
const ctx = await browser.newContext({ viewport: { width: 1500, height: 1500 } });
|
|
32
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
33
|
+
await ctx.addInitScript(() => {
|
|
34
|
+
try { localStorage.setItem('anet-theme', 'cyber'); sessionStorage.setItem('anet_v3_auth', '1'); } catch {}
|
|
35
|
+
});
|
|
36
|
+
await ctx.route('**/api/hub/status*', async (route) => {
|
|
37
|
+
const r = await route.fetch();
|
|
38
|
+
const b = await r.json();
|
|
39
|
+
const nid = (b.sessions || [])[0]?.network_id || 'default';
|
|
40
|
+
const mk = (alias, status) => ({
|
|
41
|
+
alias, status, model: 'claude-opus-4', runtime: 'claude-code-cli',
|
|
42
|
+
network_id: nid, project_dir: null,
|
|
43
|
+
created_at: fresh, updated_at: fresh, last_seen_at: fresh,
|
|
44
|
+
});
|
|
45
|
+
await route.fulfill({ response: r, json: { ...b, sessions: [
|
|
46
|
+
mk('alpha', 'working'),
|
|
47
|
+
mk('beta', 'idle'),
|
|
48
|
+
] } });
|
|
49
|
+
});
|
|
50
|
+
// Generate a thick flow: 8 messages alpha↔beta so the edge-badge
|
|
51
|
+
// renders with a high count + potentially trips hot threshold.
|
|
52
|
+
const flowMessages = Array.from({ length: 8 }, (_, i) => ({
|
|
53
|
+
id: `m${i}`, from_alias: 'alpha', to_alias: 'beta',
|
|
54
|
+
content: `ping ${i}`, created_at: fresh, network_id: 'default',
|
|
55
|
+
}));
|
|
56
|
+
await ctx.route('**/api/hub/messages*', (r) => r.fulfill({
|
|
57
|
+
json: { messages: flowMessages },
|
|
58
|
+
}));
|
|
59
|
+
await ctx.route('**/api/hub/tasks*', (r) => r.fulfill({ json: { tasks: [] } }));
|
|
60
|
+
|
|
61
|
+
const page = await ctx.newPage();
|
|
62
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
|
|
63
|
+
await page.waitForSelector('[data-edge-badge-text]', { timeout: 15000 });
|
|
64
|
+
await page.waitForTimeout(400);
|
|
65
|
+
|
|
66
|
+
const badges = await page.evaluate(() => {
|
|
67
|
+
const ts = [...document.querySelectorAll('[data-edge-badge-text]')];
|
|
68
|
+
return ts.map(t => ({
|
|
69
|
+
text: t.textContent,
|
|
70
|
+
fw: t.getAttribute('font-weight'),
|
|
71
|
+
pin: t.getAttribute('data-edge-badge-text-pin'),
|
|
72
|
+
fsize: t.getAttribute('font-size'),
|
|
73
|
+
}));
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
// Source-file verification
|
|
77
|
+
const fileText = readFileSync('/home/vansin/agent-network-dashboard/app/components/TopoGraph.tsx', 'utf8');
|
|
78
|
+
const sourceWired = /fontWeight=\{\(isPinned \|\| isHot\) \? '800' : '700'\}/.test(fileText);
|
|
79
|
+
const sourceTransition = /transition: 'letter-spacing 300ms ease-out, font-weight 300ms ease-out'/.test(fileText);
|
|
80
|
+
|
|
81
|
+
await browser.close();
|
|
82
|
+
|
|
83
|
+
// At least one badge present
|
|
84
|
+
const anyBadge = badges.length > 0;
|
|
85
|
+
// Rest invariants on at least one badge: fontSize=11
|
|
86
|
+
const anyFontSize11 = badges.some(b => b.fsize === '11');
|
|
87
|
+
// Conditional resolves: every badge attr is '700' or '800'
|
|
88
|
+
const fwValid = badges.every(b => b.fw === '700' || b.fw === '800');
|
|
89
|
+
// If any badge is pin/hot, its fw must be '800'; if not, '700'
|
|
90
|
+
const conditionalCoherent = badges.every(b => (b.pin === 'true' ? b.fw === '800' : b.fw === '700'));
|
|
91
|
+
|
|
92
|
+
const results = {
|
|
93
|
+
any_badge_mounted: anyBadge,
|
|
94
|
+
any_font_size_11: anyFontSize11,
|
|
95
|
+
fw_attr_valid: fwValid,
|
|
96
|
+
conditional_coherent: conditionalCoherent,
|
|
97
|
+
source_hover_wired: sourceWired,
|
|
98
|
+
source_transition_wired: sourceTransition,
|
|
99
|
+
};
|
|
100
|
+
const ok = Object.values(results).every(Boolean);
|
|
101
|
+
console.log(`${ok ? '✅' : '❌'} edge-badge digit fw pin/hot:`, JSON.stringify(results),
|
|
102
|
+
'\n badges:', JSON.stringify(badges));
|
|
103
|
+
process.exit(ok ? 0 : 1);
|