@sleep2agi/agent-network-dashboard 0.5.1-preview.4 → 0.5.1-preview.40
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/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/static/chunks/05.asnoxq2t39.js +1 -0
- package/.next/static/chunks/06_k1dgr3isa2.js +1 -0
- package/.next/static/chunks/0fxhdt5-198se.js +4 -0
- package/.next/static/chunks/0hwb_h953qm4d.css +2 -0
- package/.next/trace +2 -2
- package/.next/trace-build +1 -1
- package/app/components/TopoGraph.tsx +760 -58
- package/package.json +1 -1
- package/scripts/topo-chip-digit-fontweight-test.mjs +105 -0
- package/scripts/topo-chrome-segmented-radius-test.mjs +100 -0
- package/scripts/topo-edge-badge-fontsize-test.mjs +90 -0
- package/scripts/topo-edge-badge-opacity-test.mjs +80 -0
- package/scripts/topo-edge-badge-stroke-test.mjs +92 -0
- package/scripts/topo-filter-pill-hover-opacity-test.mjs +110 -0
- package/scripts/topo-filter-pill-x-hover-scale-test.mjs +99 -0
- package/scripts/topo-flow-rail-linecap-test.mjs +79 -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-label-count-fontweight-test.mjs +108 -0
- package/scripts/topo-hub-digit-fontsize-test.mjs +86 -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-layout-toggle-hover-tracking-test.mjs +109 -0
- package/scripts/topo-layout-toggle-radius-test.mjs +87 -0
- package/scripts/topo-legend-label-fontweight-test.mjs +94 -0
- package/scripts/topo-minimap-offline-opacity-test.mjs +90 -0
- package/scripts/topo-minimap-viewport-hover-test.mjs +109 -0
- package/scripts/topo-minimap-viewport-linejoin-test.mjs +75 -0
- package/scripts/topo-more-flows-fontweight-test.mjs +103 -0
- package/scripts/topo-more-flows-hover-letterspacing-test.mjs +98 -0
- package/scripts/topo-panel-count-letterspacing-test.mjs +89 -0
- package/scripts/topo-panel-rect-opacity-hover-test.mjs +109 -0
- package/scripts/topo-panel-title-hover-letterspacing-test.mjs +97 -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-test.mjs +76 -0
- package/scripts/topo-recent-row-text-fontweight-test.mjs +90 -0
- package/scripts/topo-reset-hover-rotate-test.mjs +102 -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-zoom-icon-hover-scale-test.mjs +114 -0
- package/scripts/topo-zoom-level-hover-letterspacing-test.mjs +91 -0
- package/.next/static/chunks/04sya_8oheege.js +0 -4
- package/.next/static/chunks/08c-dt44c.swe.js +0 -1
- package/.next/static/chunks/0aauz~36q5n2a.css +0 -2
- package/.next/static/chunks/12e0z26h2p0xl.js +0 -1
- /package/.next/static/{CkuUcpLXVJ-OsmjZqi3xX → PtUnxSzwOvGhpWPUawz9k}/_buildManifest.js +0 -0
- /package/.next/static/{CkuUcpLXVJ-OsmjZqi3xX → PtUnxSzwOvGhpWPUawz9k}/_clientMiddlewareManifest.js +0 -0
- /package/.next/static/{CkuUcpLXVJ-OsmjZqi3xX → PtUnxSzwOvGhpWPUawz9k}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/* Round 360 verification: hub working-count digit fontSize 11 → 12.
|
|
2
|
+
* The hub is the canvas's focal point — its digit is the most-read
|
|
3
|
+
* scalar on the whole topology. R130 sized it at 11 inside the
|
|
4
|
+
* r=10 / 20-px core; R360 nudges to 12 (~13 px wide × 12 px tall,
|
|
5
|
+
* still well inside) for ~9 % more presence. Sibling visual-weight
|
|
6
|
+
* bump family with R287/R295/R359.
|
|
7
|
+
*
|
|
8
|
+
* Contract:
|
|
9
|
+
* - Hub digit font-size attr === '12'.
|
|
10
|
+
* - data-topo-hub-working-count-font-size === '12'.
|
|
11
|
+
* - data-topo-hub-working-count surfaces the count (>0 with mocked
|
|
12
|
+
* working sessions).
|
|
13
|
+
* - Pre-R360 invariants: R225 tabular-nums + R209 scale-on-hover
|
|
14
|
+
* transform-box still set, fontWeight=700, dy="0.36em" preserved.
|
|
15
|
+
* - Overlap-test stays green (digit is inside hub <g>, not a node
|
|
16
|
+
* the overlap probe scans).
|
|
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 browser = await chromium.launch({ headless: true });
|
|
23
|
+
const ctx = await browser.newContext({ viewport: { width: 1500, height: 1500 } });
|
|
24
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
25
|
+
await ctx.addInitScript(() => {
|
|
26
|
+
try { localStorage.setItem('anet-theme', 'cyber'); sessionStorage.setItem('anet_v3_auth', '1'); } catch {}
|
|
27
|
+
});
|
|
28
|
+
const fresh = new Date(Date.now() - 60 * 1000).toISOString();
|
|
29
|
+
await ctx.route('**/api/hub/status*', async (route) => {
|
|
30
|
+
const r = await route.fetch();
|
|
31
|
+
const b = await r.json();
|
|
32
|
+
const nid = (b.sessions || [])[0]?.network_id || 'default';
|
|
33
|
+
const mk = (alias) => ({
|
|
34
|
+
alias, status: 'working', model: 'claude-opus-4', runtime: 'claude-code-cli',
|
|
35
|
+
network_id: nid, project_dir: null,
|
|
36
|
+
created_at: fresh, updated_at: fresh, last_seen_at: fresh,
|
|
37
|
+
});
|
|
38
|
+
// 3 working sessions → workingCount=3 → digit visible.
|
|
39
|
+
await route.fulfill({ response: r, json: { ...b, sessions: [ mk('a'), mk('b'), mk('c') ] } });
|
|
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('[data-topo-hub-working-count]', { timeout: 15000 });
|
|
47
|
+
await page.waitForTimeout(300);
|
|
48
|
+
|
|
49
|
+
const probe = await page.evaluate(() => {
|
|
50
|
+
const t = document.querySelector('[data-topo-hub-working-count]');
|
|
51
|
+
const cs = t ? getComputedStyle(t) : null;
|
|
52
|
+
return {
|
|
53
|
+
fontSizeAttr: t?.getAttribute('font-size') ?? null,
|
|
54
|
+
fontSizeData: t?.getAttribute('data-topo-hub-working-count-font-size') ?? null,
|
|
55
|
+
countValue: t?.getAttribute('data-topo-hub-working-count') ?? null,
|
|
56
|
+
fontWeight: t?.getAttribute('font-weight') ?? null,
|
|
57
|
+
dy: t?.getAttribute('dy') ?? null,
|
|
58
|
+
fontVariant: cs?.fontVariantNumeric ?? null,
|
|
59
|
+
transformBox: cs?.transformBox ?? null,
|
|
60
|
+
transformOrigin: cs?.transformOrigin ?? null,
|
|
61
|
+
transition: cs?.transition ?? null,
|
|
62
|
+
opacity: t?.getAttribute('opacity') ?? null,
|
|
63
|
+
};
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
await browser.close();
|
|
67
|
+
|
|
68
|
+
const hasTrans = (s, prop) =>
|
|
69
|
+
new RegExp(`${prop}\\s+\\d*\\.?\\d*s|${prop}\\s+\\d+ms`, 'i').test(s || '');
|
|
70
|
+
|
|
71
|
+
const results = {
|
|
72
|
+
font_size_attr_12: probe.fontSizeAttr === '12',
|
|
73
|
+
data_font_size_12: probe.fontSizeData === '12',
|
|
74
|
+
count_value_3: probe.countValue === '3', // 3 mocked working sessions
|
|
75
|
+
font_weight_700: probe.fontWeight === '700',
|
|
76
|
+
dy_0_36em: probe.dy === '0.36em',
|
|
77
|
+
tabular_nums: /tabular-nums/.test(probe.fontVariant || ''), // R225
|
|
78
|
+
transform_box_fill: probe.transformBox === 'fill-box', // R209
|
|
79
|
+
trans_has_transform: hasTrans(probe.transition, 'transform'), // R209
|
|
80
|
+
trans_has_fill: hasTrans(probe.transition, 'fill'), // R253
|
|
81
|
+
opacity_visible: probe.opacity === '1',
|
|
82
|
+
};
|
|
83
|
+
const ok = Object.values(results).every(Boolean);
|
|
84
|
+
console.log(`${ok ? '✅' : '❌'} hub digit fontSize 11 → 12:`, JSON.stringify(results),
|
|
85
|
+
'\n probe:', probe);
|
|
86
|
+
process.exit(ok ? 0 : 1);
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/* Round 365 verification: hub-center 'lit-lamp' decorative highlight
|
|
2
|
+
* circle radius 5 → 5.5. Visible when workingCount === 0 (idle fleet
|
|
3
|
+
* decor per R130). Sibling visual-weight bump family — extends to
|
|
4
|
+
* 6 canvas anchors:
|
|
5
|
+
* R287 minimap viewport stroke 1 → 1.5
|
|
6
|
+
* R295 legend swatch base radius 5.5 → 6
|
|
7
|
+
* R359 recent-row pip base radius 1.6 → 1.8
|
|
8
|
+
* R360 hub digit fontSize 11 → 12
|
|
9
|
+
* R361 edge-badge digit fontSize 10 → 11
|
|
10
|
+
* R365 hub-highlight base radius 5 → 5.5 (this round)
|
|
11
|
+
*
|
|
12
|
+
* 21 % area bump (π·5.5² / π·5² = 1.21). Still well inside r=10 core.
|
|
13
|
+
*
|
|
14
|
+
* Test approach: feed an IDLE fleet (no working sessions) so the
|
|
15
|
+
* highlight is fully opaque.
|
|
16
|
+
*
|
|
17
|
+
* Contract:
|
|
18
|
+
* - data-topo-hub-highlight element r attr === '5.5'.
|
|
19
|
+
* - data-topo-hub-highlight-radius === '5.5'.
|
|
20
|
+
* - data-topo-hub-highlight-visible === 'true' (idle fleet).
|
|
21
|
+
* - opacity attr === '0.9' (workingCount === 0 branch).
|
|
22
|
+
* - Pre-R365 invariants:
|
|
23
|
+
* * cx + cy unchanged (visual center stable)
|
|
24
|
+
* * fill='#d1fae5' (R130 lamp color)
|
|
25
|
+
* * style.transition contains opacity (R213 always-mount gate)
|
|
26
|
+
* * pointerEvents: 'none' (R130)
|
|
27
|
+
*/
|
|
28
|
+
import { chromium } from 'playwright';
|
|
29
|
+
import { readFileSync } from 'node:fs';
|
|
30
|
+
|
|
31
|
+
const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
|
|
32
|
+
const browser = await chromium.launch({ headless: true });
|
|
33
|
+
const ctx = await browser.newContext({ viewport: { width: 1500, height: 1500 } });
|
|
34
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
35
|
+
await ctx.addInitScript(() => {
|
|
36
|
+
try { localStorage.setItem('anet-theme', 'cyber'); sessionStorage.setItem('anet_v3_auth', '1'); } catch {}
|
|
37
|
+
});
|
|
38
|
+
const fresh = new Date(Date.now() - 60 * 1000).toISOString();
|
|
39
|
+
await ctx.route('**/api/hub/status*', async (route) => {
|
|
40
|
+
const r = await route.fetch();
|
|
41
|
+
const b = await r.json();
|
|
42
|
+
const nid = (b.sessions || [])[0]?.network_id || 'default';
|
|
43
|
+
// IDLE: status !== 'working' so workingCount=0 and the highlight is opaque.
|
|
44
|
+
const mk = (alias) => ({
|
|
45
|
+
alias, status: 'idle', model: 'claude-opus-4', runtime: 'claude-code-cli',
|
|
46
|
+
network_id: nid, project_dir: null,
|
|
47
|
+
created_at: fresh, updated_at: fresh, last_seen_at: fresh,
|
|
48
|
+
});
|
|
49
|
+
await route.fulfill({ response: r, json: { ...b, sessions: [ mk('a'), mk('b'), mk('c') ] } });
|
|
50
|
+
});
|
|
51
|
+
await ctx.route('**/api/hub/messages*', (r) => r.fulfill({ json: { messages: [] } }));
|
|
52
|
+
await ctx.route('**/api/hub/tasks*', (r) => r.fulfill({ json: { tasks: [] } }));
|
|
53
|
+
|
|
54
|
+
const page = await ctx.newPage();
|
|
55
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
|
|
56
|
+
await page.waitForSelector('[data-topo-hub-highlight]', { timeout: 15000 });
|
|
57
|
+
await page.waitForTimeout(300);
|
|
58
|
+
|
|
59
|
+
const probe = await page.evaluate(() => {
|
|
60
|
+
const h = document.querySelector('[data-topo-hub-highlight]');
|
|
61
|
+
const cs = h ? getComputedStyle(h) : null;
|
|
62
|
+
return {
|
|
63
|
+
rAttr: h?.getAttribute('r') ?? null,
|
|
64
|
+
rData: h?.getAttribute('data-topo-hub-highlight-radius') ?? null,
|
|
65
|
+
visibleAttr: h?.getAttribute('data-topo-hub-highlight-visible') ?? null,
|
|
66
|
+
opacityAttr: h?.getAttribute('opacity') ?? null,
|
|
67
|
+
fill: h?.getAttribute('fill') ?? null,
|
|
68
|
+
transition: cs?.transition ?? null,
|
|
69
|
+
pointerEv: cs?.pointerEvents ?? null,
|
|
70
|
+
};
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
await browser.close();
|
|
74
|
+
|
|
75
|
+
const hasTrans = (s, prop) =>
|
|
76
|
+
new RegExp(`${prop}\\s+\\d*\\.?\\d*s|${prop}\\s+\\d+ms`, 'i').test(s || '');
|
|
77
|
+
|
|
78
|
+
const results = {
|
|
79
|
+
r_attr_5_5: probe.rAttr === '5.5',
|
|
80
|
+
r_data_5_5: probe.rData === '5.5',
|
|
81
|
+
visible_true: probe.visibleAttr === 'true',
|
|
82
|
+
opacity_0_9: probe.opacityAttr === '0.9',
|
|
83
|
+
fill_d1fae5: probe.fill === '#d1fae5',
|
|
84
|
+
trans_has_opacity: hasTrans(probe.transition, 'opacity'),
|
|
85
|
+
pointer_events_none: probe.pointerEv === 'none',
|
|
86
|
+
};
|
|
87
|
+
const ok = Object.values(results).every(Boolean);
|
|
88
|
+
console.log(`${ok ? '✅' : '❌'} hub-highlight radius 5 → 5.5:`, JSON.stringify(results),
|
|
89
|
+
'\n probe:', probe);
|
|
90
|
+
process.exit(ok ? 0 : 1);
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/* Round 370 verification: hub hover-ring cyber opacity 0.7 → 0.8.
|
|
2
|
+
* R177 designed the hub hover-ring at opacity-0 → 0.85 (light) / 0 →
|
|
3
|
+
* 0.7 (cyber). The 15 % gap between themes meant cyber-theme users
|
|
4
|
+
* got a noticeably softer hover cue than light-theme users against
|
|
5
|
+
* backgrounds that should equalise (dark bg needs more luminance to
|
|
6
|
+
* read as 'on'). R370 bumps cyber 0.7 → 0.8, narrowing the theme
|
|
7
|
+
* gap to 5 % (light stays at 0.85).
|
|
8
|
+
*
|
|
9
|
+
* Contract (cyber theme):
|
|
10
|
+
* - Rest (hub NOT hovered): hub-hover-ring opacity attr === '0'.
|
|
11
|
+
* - Hover hub: opacity attr === '0.8'.
|
|
12
|
+
* - data-topo-hub-hover-ring-opacity === '0.8' on hover.
|
|
13
|
+
* - Pre-R370 invariants:
|
|
14
|
+
* * r=17 on hover (R177)
|
|
15
|
+
* * stroke=#10b981 (cyber, R253)
|
|
16
|
+
* * strokeWidth=1.5
|
|
17
|
+
* * pointerEvents:none
|
|
18
|
+
* * R177 r + opacity transitions preserved
|
|
19
|
+
*/
|
|
20
|
+
import { chromium } from 'playwright';
|
|
21
|
+
import { readFileSync } from 'node:fs';
|
|
22
|
+
|
|
23
|
+
const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
|
|
24
|
+
const 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
|
+
const fresh = new Date(Date.now() - 60 * 1000).toISOString();
|
|
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) => ({
|
|
36
|
+
alias, status: 'working', model: 'claude-opus-4', runtime: 'claude-code-cli',
|
|
37
|
+
network_id: nid, project_dir: null,
|
|
38
|
+
created_at: fresh, updated_at: fresh, last_seen_at: fresh,
|
|
39
|
+
});
|
|
40
|
+
await route.fulfill({ response: r, json: { ...b, sessions: [ mk('a'), mk('b'), mk('c') ] } });
|
|
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-topo-hub-hover-ring]', { timeout: 15000 });
|
|
48
|
+
await page.waitForTimeout(300);
|
|
49
|
+
|
|
50
|
+
const restProbe = await page.evaluate(() => {
|
|
51
|
+
const r = document.querySelector('[data-topo-hub-hover-ring]');
|
|
52
|
+
const cs = r ? getComputedStyle(r) : null;
|
|
53
|
+
return {
|
|
54
|
+
opacityAttr: r?.getAttribute('opacity') ?? null,
|
|
55
|
+
opacityData: r?.getAttribute('data-topo-hub-hover-ring-opacity') ?? null,
|
|
56
|
+
rAttr: r?.getAttribute('r') ?? null,
|
|
57
|
+
radiusData: r?.getAttribute('data-topo-hub-hover-ring-radius') ?? null,
|
|
58
|
+
strokeAttr: r?.getAttribute('stroke') ?? null,
|
|
59
|
+
strokeWidthAttr: r?.getAttribute('stroke-width') ?? null,
|
|
60
|
+
pointerEv: cs?.pointerEvents ?? null,
|
|
61
|
+
};
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
// Hover the hub group.
|
|
65
|
+
await page.hover('[data-topo-hub]');
|
|
66
|
+
await page.waitForTimeout(300);
|
|
67
|
+
const hoverProbe = await page.evaluate(() => {
|
|
68
|
+
const r = document.querySelector('[data-topo-hub-hover-ring]');
|
|
69
|
+
return {
|
|
70
|
+
opacityAttr: r?.getAttribute('opacity') ?? null,
|
|
71
|
+
opacityData: r?.getAttribute('data-topo-hub-hover-ring-opacity') ?? null,
|
|
72
|
+
rAttr: r?.getAttribute('r') ?? null,
|
|
73
|
+
radiusData: r?.getAttribute('data-topo-hub-hover-ring-radius') ?? null,
|
|
74
|
+
};
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
await browser.close();
|
|
78
|
+
|
|
79
|
+
const results = {
|
|
80
|
+
rest_opacity_0: restProbe.opacityAttr === '0',
|
|
81
|
+
rest_opacity_data_0: restProbe.opacityData === '0',
|
|
82
|
+
rest_r_14: restProbe.rAttr === '14', // R177 rest
|
|
83
|
+
rest_radius_data_14: restProbe.radiusData === '14',
|
|
84
|
+
rest_stroke_cyber: restProbe.strokeAttr === '#10b981', // R253 cyber
|
|
85
|
+
rest_stroke_width_1_5: restProbe.strokeWidthAttr === '1.5', // R51 sentinel reserved but R177
|
|
86
|
+
pointer_events_none: restProbe.pointerEv === 'none',
|
|
87
|
+
hover_opacity_0_8: hoverProbe.opacityAttr === '0.8', // R370 cyber bump
|
|
88
|
+
hover_opacity_data_0_8: hoverProbe.opacityData === '0.8',
|
|
89
|
+
hover_r_17: hoverProbe.rAttr === '17', // R177 hover lift
|
|
90
|
+
hover_radius_data_17: hoverProbe.radiusData === '17',
|
|
91
|
+
};
|
|
92
|
+
const ok = Object.values(results).every(Boolean);
|
|
93
|
+
console.log(`${ok ? '✅' : '❌'} hub hover-ring opacity 0.7 → 0.8 (cyber):`, JSON.stringify(results),
|
|
94
|
+
'\n rest: ', restProbe,
|
|
95
|
+
'\n hover:', hoverProbe);
|
|
96
|
+
process.exit(ok ? 0 : 1);
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/* Round 351 verification: Layout-toggle Ring|Grid buttons gain
|
|
2
|
+
* hover-state letter-spacing (Tailwind hover:tracking-wide =
|
|
3
|
+
* 0.025em). Extends the R344 (footer) / R345 (panel titles) /
|
|
4
|
+
* R347 (zoom-level readout) hover-letter-spacing family to a
|
|
5
|
+
* 4th surface — the chrome-strip Ring/Grid layout-toggle pair.
|
|
6
|
+
*
|
|
7
|
+
* Pure-CSS approach: no new React state. transition-colors
|
|
8
|
+
* className dropped in favour of an inline transition spec
|
|
9
|
+
* that bundles bg/color (150ms ease) + letter-spacing (200ms
|
|
10
|
+
* ease-out) so the tracking-wide hover doesn't snap. Grid
|
|
11
|
+
* button additionally keeps border-color in the transition
|
|
12
|
+
* list (R268 theme-ease).
|
|
13
|
+
*
|
|
14
|
+
* Contract (cyber):
|
|
15
|
+
* - Rest: both buttons computed letter-spacing === 'normal' (0).
|
|
16
|
+
* - Hover Ring: computed letter-spacing === '0.4px' (0.025em ×
|
|
17
|
+
* ~14-16 base font; we'll accept any value > 0.1px).
|
|
18
|
+
* - Hover Grid: same.
|
|
19
|
+
* - Inline transition on both contains 'letter-spacing'.
|
|
20
|
+
* - Pre-R351 invariants: data-topo-chrome-layout attrs intact,
|
|
21
|
+
* R268 border-color transition still present on Grid.
|
|
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 browser = await chromium.launch({ headless: true });
|
|
28
|
+
const ctx = await browser.newContext({ viewport: { width: 1500, height: 1500 } });
|
|
29
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
30
|
+
await ctx.addInitScript(() => {
|
|
31
|
+
try { localStorage.setItem('anet-theme', 'cyber'); sessionStorage.setItem('anet_v3_auth', '1'); } catch {}
|
|
32
|
+
});
|
|
33
|
+
const fresh = new Date(Date.now() - 60 * 1000).toISOString();
|
|
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: 'working', 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('a'), mk('b'), mk('c') ] } });
|
|
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-chrome-layout="ring"]', { timeout: 15000 });
|
|
51
|
+
await page.waitForSelector('[data-topo-chrome-layout="grid"]', { timeout: 5000 });
|
|
52
|
+
await page.waitForTimeout(300);
|
|
53
|
+
|
|
54
|
+
const restProbe = await page.evaluate(() => {
|
|
55
|
+
const r = document.querySelector('[data-topo-chrome-layout="ring"]');
|
|
56
|
+
const g = document.querySelector('[data-topo-chrome-layout="grid"]');
|
|
57
|
+
const rcs = r ? getComputedStyle(r) : null;
|
|
58
|
+
const gcs = g ? getComputedStyle(g) : null;
|
|
59
|
+
return {
|
|
60
|
+
ringLs: rcs?.letterSpacing ?? null,
|
|
61
|
+
ringTrans: rcs?.transition ?? null,
|
|
62
|
+
gridLs: gcs?.letterSpacing ?? null,
|
|
63
|
+
gridTrans: gcs?.transition ?? null,
|
|
64
|
+
};
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
// Hover Ring button.
|
|
68
|
+
await page.hover('[data-topo-chrome-layout="ring"]');
|
|
69
|
+
await page.waitForTimeout(300);
|
|
70
|
+
const ringHover = await page.evaluate(() => {
|
|
71
|
+
const r = document.querySelector('[data-topo-chrome-layout="ring"]');
|
|
72
|
+
return { ls: r ? getComputedStyle(r).letterSpacing : null };
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
// Move to Grid button.
|
|
76
|
+
await page.hover('[data-topo-chrome-layout="grid"]');
|
|
77
|
+
await page.waitForTimeout(300);
|
|
78
|
+
const gridHover = await page.evaluate(() => {
|
|
79
|
+
const g = document.querySelector('[data-topo-chrome-layout="grid"]');
|
|
80
|
+
return { ls: g ? getComputedStyle(g).letterSpacing : null };
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
await browser.close();
|
|
84
|
+
|
|
85
|
+
const isRestLs = (v) => v === 'normal' || v === '0px' || v === '0' || v === null;
|
|
86
|
+
const isHoverLs = (v) => {
|
|
87
|
+
// tracking-wide = 0.025em. At base 14-16px font, that's ~0.35-0.4px.
|
|
88
|
+
if (!v || v === 'normal') return false;
|
|
89
|
+
const n = parseFloat(v);
|
|
90
|
+
return Number.isFinite(n) && n > 0.2 && n < 1.0;
|
|
91
|
+
};
|
|
92
|
+
const hasTrans = (s, prop) =>
|
|
93
|
+
new RegExp(`${prop}\\s+\\d*\\.?\\d*s|${prop}\\s+\\d+ms`, 'i').test(s || '');
|
|
94
|
+
|
|
95
|
+
const results = {
|
|
96
|
+
rest_ring_ls_zero: isRestLs(restProbe.ringLs),
|
|
97
|
+
rest_grid_ls_zero: isRestLs(restProbe.gridLs),
|
|
98
|
+
ring_trans_has_ls: hasTrans(restProbe.ringTrans, 'letter-spacing'),
|
|
99
|
+
grid_trans_has_ls: hasTrans(restProbe.gridTrans, 'letter-spacing'),
|
|
100
|
+
grid_trans_has_bcol: hasTrans(restProbe.gridTrans, 'border-color'), // R268
|
|
101
|
+
hover_ring_tracked: isHoverLs(ringHover.ls),
|
|
102
|
+
hover_grid_tracked: isHoverLs(gridHover.ls),
|
|
103
|
+
};
|
|
104
|
+
const ok = Object.values(results).every(Boolean);
|
|
105
|
+
console.log(`${ok ? '✅' : '❌'} layout-toggle hover tracking-wide:`, JSON.stringify(results),
|
|
106
|
+
'\n rest: ', restProbe,
|
|
107
|
+
'\n hover ring: ', ringHover,
|
|
108
|
+
'\n hover grid: ', gridHover);
|
|
109
|
+
process.exit(ok ? 0 : 1);
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/* Round 375 verification: Layout-toggle wrapper rounded-md → rounded-
|
|
2
|
+
* lg (6 → 8 px). Extends the R330/R331/R332 corner-radius cascade to
|
|
3
|
+
* the chrome-strip layout-toggle wrapper. Pre-R375 the wrapper at
|
|
4
|
+
* rounded-md (6 px) was the only chrome-strip container still using
|
|
5
|
+
* the smaller corner radius — both R330 outer wrapper and R332
|
|
6
|
+
* minimap sit at ≥ 8 px; R375 brings the toggle into the rounded-lg
|
|
7
|
+
* tier where minimap already lives.
|
|
8
|
+
*
|
|
9
|
+
* Contract:
|
|
10
|
+
* - data-topo-chrome-layout-trailer element computed border-radius
|
|
11
|
+
* === '8px' (rounded-lg).
|
|
12
|
+
* - data-topo-chrome-layout-radius === 'rounded-lg'.
|
|
13
|
+
* - Pre-R375 invariants:
|
|
14
|
+
* * border still present (1 px default Tailwind)
|
|
15
|
+
* * R268 inline borderColor + 200ms border-color transition
|
|
16
|
+
* * R329 mr-0.5 spacing preserved
|
|
17
|
+
* * inline-flex + overflow-hidden preserved
|
|
18
|
+
* * Inner buttons (Ring + Grid) still mounted as flex children
|
|
19
|
+
*/
|
|
20
|
+
import { chromium } from 'playwright';
|
|
21
|
+
import { readFileSync } from 'node:fs';
|
|
22
|
+
|
|
23
|
+
const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
|
|
24
|
+
const 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
|
+
const fresh = new Date(Date.now() - 60 * 1000).toISOString();
|
|
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) => ({
|
|
36
|
+
alias, status: 'working', model: 'claude-opus-4', runtime: 'claude-code-cli',
|
|
37
|
+
network_id: nid, project_dir: null,
|
|
38
|
+
created_at: fresh, updated_at: fresh, last_seen_at: fresh,
|
|
39
|
+
});
|
|
40
|
+
await route.fulfill({ response: r, json: { ...b, sessions: [ mk('a'), mk('b'), mk('c') ] } });
|
|
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-topo-chrome-layout-trailer]', { timeout: 15000 });
|
|
48
|
+
await page.waitForTimeout(300);
|
|
49
|
+
|
|
50
|
+
const probe = await page.evaluate(() => {
|
|
51
|
+
const w = document.querySelector('[data-topo-chrome-layout-trailer]');
|
|
52
|
+
const cs = w ? getComputedStyle(w) : null;
|
|
53
|
+
const ring = w?.querySelector('[data-topo-chrome-layout="ring"]');
|
|
54
|
+
const grid = w?.querySelector('[data-topo-chrome-layout="grid"]');
|
|
55
|
+
return {
|
|
56
|
+
borderRadius: cs?.borderRadius ?? null,
|
|
57
|
+
radiusData: w?.getAttribute('data-topo-chrome-layout-radius') ?? null,
|
|
58
|
+
borderWidth: cs?.borderWidth ?? null,
|
|
59
|
+
display: cs?.display ?? null,
|
|
60
|
+
overflow: cs?.overflow ?? null,
|
|
61
|
+
transition: cs?.transition ?? null,
|
|
62
|
+
cls: w?.getAttribute('class') ?? null,
|
|
63
|
+
ringPresent: !!ring,
|
|
64
|
+
gridPresent: !!grid,
|
|
65
|
+
};
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
await browser.close();
|
|
69
|
+
|
|
70
|
+
const hasTrans = (s, prop) =>
|
|
71
|
+
new RegExp(`${prop}\\s+\\d*\\.?\\d*s|${prop}\\s+\\d+ms`, 'i').test(s || '');
|
|
72
|
+
|
|
73
|
+
const results = {
|
|
74
|
+
border_radius_8px: probe.borderRadius === '8px', // rounded-lg
|
|
75
|
+
data_radius_lg: probe.radiusData === 'rounded-lg',
|
|
76
|
+
border_width_1px: probe.borderWidth === '1px',
|
|
77
|
+
display_inline_flex: probe.display === 'inline-flex' || probe.display === 'flex',
|
|
78
|
+
overflow_hidden: probe.overflow === 'hidden',
|
|
79
|
+
trans_has_border_color: hasTrans(probe.transition, 'border-color'), // R268
|
|
80
|
+
cls_has_mr_0_5: /mr-0\.5/.test(probe.cls || ''), // R329
|
|
81
|
+
ring_button_present: probe.ringPresent,
|
|
82
|
+
grid_button_present: probe.gridPresent,
|
|
83
|
+
};
|
|
84
|
+
const ok = Object.values(results).every(Boolean);
|
|
85
|
+
console.log(`${ok ? '✅' : '❌'} Layout-toggle wrapper rounded-md → rounded-lg:`, JSON.stringify(results),
|
|
86
|
+
'\n probe:', probe);
|
|
87
|
+
process.exit(ok ? 0 : 1);
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/* Round 364 verification: legend-row label fontWeight 400 → 500.
|
|
2
|
+
* Sibling typography lift to R363 recent-row text fw 400 → 500.
|
|
3
|
+
* Both surfaces render small monospace text against panel chrome
|
|
4
|
+
* at fontSize 9-11 where SVG-default fw 400 sits at the legibility
|
|
5
|
+
* floor.
|
|
6
|
+
*
|
|
7
|
+
* Family snapshot post-R364:
|
|
8
|
+
* legend label fw 500 (R364, this round)
|
|
9
|
+
* legend count fw 600 (R309)
|
|
10
|
+
* recent alias fw 500 (R363)
|
|
11
|
+
* recent count fw 600/700 (R320)
|
|
12
|
+
*
|
|
13
|
+
* Contract (cyber, fixture with active rows):
|
|
14
|
+
* - Each rendered [data-legend-row-label] has font-weight === '500'.
|
|
15
|
+
* - Each has data-legend-row-label-font-weight === '500'.
|
|
16
|
+
* - Pre-R364 invariants:
|
|
17
|
+
* * fontSize=11 + fontFamily=monospace
|
|
18
|
+
* * R219 letter-spacing 0 → 0.5px on pin (style.transition still
|
|
19
|
+
* lists letter-spacing)
|
|
20
|
+
* * R55 fill transition retained
|
|
21
|
+
* * data-legend-row-label key surfaces (working / idle / offline)
|
|
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 browser = await chromium.launch({ headless: true });
|
|
28
|
+
const ctx = await browser.newContext({ viewport: { width: 1500, height: 1500 } });
|
|
29
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
30
|
+
await ctx.addInitScript(() => {
|
|
31
|
+
try { localStorage.setItem('anet-theme', 'cyber'); sessionStorage.setItem('anet_v3_auth', '1'); } catch {}
|
|
32
|
+
});
|
|
33
|
+
const fresh = new Date(Date.now() - 60 * 1000).toISOString();
|
|
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: 'working', 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('a'), mk('b'), mk('c') ] } });
|
|
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-legend-row-label]', { timeout: 15000 });
|
|
51
|
+
await page.waitForTimeout(300);
|
|
52
|
+
|
|
53
|
+
const probe = await page.evaluate(() => {
|
|
54
|
+
const labels = Array.from(document.querySelectorAll('[data-legend-row-label]'));
|
|
55
|
+
return labels.map(el => {
|
|
56
|
+
const cs = getComputedStyle(el);
|
|
57
|
+
return {
|
|
58
|
+
key: el.getAttribute('data-legend-row-label'),
|
|
59
|
+
fontWeightAttr: el.getAttribute('font-weight'),
|
|
60
|
+
fontWeightData: el.getAttribute('data-legend-row-label-font-weight'),
|
|
61
|
+
fontSizeAttr: el.getAttribute('font-size'),
|
|
62
|
+
fontFamily: el.getAttribute('font-family'),
|
|
63
|
+
transition: cs.transition,
|
|
64
|
+
};
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
await browser.close();
|
|
69
|
+
|
|
70
|
+
const hasTrans = (s, prop) =>
|
|
71
|
+
new RegExp(`${prop}\\s+\\d*\\.?\\d*s|${prop}\\s+\\d+ms`, 'i').test(s || '');
|
|
72
|
+
|
|
73
|
+
const allRowsOk = probe.length > 0 && probe.every(r =>
|
|
74
|
+
r.fontWeightAttr === '500'
|
|
75
|
+
&& r.fontWeightData === '500'
|
|
76
|
+
&& r.fontSizeAttr === '11'
|
|
77
|
+
&& /monospace/i.test(r.fontFamily || '')
|
|
78
|
+
&& hasTrans(r.transition, 'letter-spacing')
|
|
79
|
+
&& hasTrans(r.transition, 'fill')
|
|
80
|
+
);
|
|
81
|
+
|
|
82
|
+
const results = {
|
|
83
|
+
rows_rendered: probe.length >= 1,
|
|
84
|
+
all_rows_fw_500: probe.every(r => r.fontWeightAttr === '500'),
|
|
85
|
+
all_rows_data_500: probe.every(r => r.fontWeightData === '500'),
|
|
86
|
+
all_rows_fontsize_11: probe.every(r => r.fontSizeAttr === '11'),
|
|
87
|
+
all_rows_monospace: probe.every(r => /monospace/i.test(r.fontFamily || '')),
|
|
88
|
+
all_rows_have_ls_trans: probe.every(r => hasTrans(r.transition, 'letter-spacing')),
|
|
89
|
+
all_rows_have_fill_trans: probe.every(r => hasTrans(r.transition, 'fill')),
|
|
90
|
+
};
|
|
91
|
+
const ok = allRowsOk && Object.values(results).every(Boolean);
|
|
92
|
+
console.log(`${ok ? '✅' : '❌'} legend-row label fw 400 → 500:`, JSON.stringify(results),
|
|
93
|
+
'\n rows: ', probe.map(r => ({ key: r.key, fw: r.fontWeightAttr })));
|
|
94
|
+
process.exit(ok ? 0 : 1);
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/* Round 372 verification: minimap offline-dot opacity 0.5 → 0.6.
|
|
2
|
+
* Sibling stale-state legibility lift to R358 (freshness ramp floor
|
|
3
|
+
* 0.25 → 0.30). Pre-R372 R198 drew offline dots at α=0.5; R372 lifts
|
|
4
|
+
* to 0.6 (+20 % relative) for better readability while keeping a
|
|
5
|
+
* clear two-tier distinction vs online α=0.9.
|
|
6
|
+
*
|
|
7
|
+
* The minimap only renders when view is non-default (zoom !== 1 ||
|
|
8
|
+
* pan). Test triggers zoom-in to mount it, then probes the offline
|
|
9
|
+
* dot's opacity attr.
|
|
10
|
+
*
|
|
11
|
+
* Contract:
|
|
12
|
+
* - data-topo-minimap-dot-online="false" element opacity === '0.6'.
|
|
13
|
+
* - data-topo-minimap-dot-opacity === '0.6' for offline dot.
|
|
14
|
+
* - Online dot still at opacity '0.9' (R198 invariant).
|
|
15
|
+
* - Pre-R372 invariants:
|
|
16
|
+
* * R198 offline r=1.2, online r=1.7 preserved
|
|
17
|
+
* * R198 transition list (opacity + fill + r) preserved
|
|
18
|
+
*/
|
|
19
|
+
import { chromium } from 'playwright';
|
|
20
|
+
import { readFileSync } from 'node:fs';
|
|
21
|
+
|
|
22
|
+
const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
|
|
23
|
+
const browser = await chromium.launch({ headless: true });
|
|
24
|
+
const ctx = await browser.newContext({ viewport: { width: 1500, height: 1500 } });
|
|
25
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
26
|
+
await ctx.addInitScript(() => {
|
|
27
|
+
try { localStorage.setItem('anet-theme', 'cyber'); sessionStorage.setItem('anet_v3_auth', '1'); } catch {}
|
|
28
|
+
});
|
|
29
|
+
const fresh = new Date(Date.now() - 60 * 1000).toISOString();
|
|
30
|
+
const stale = new Date(Date.now() - 600 * 1000).toISOString();
|
|
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
|
+
// Mix of online (working) + offline sessions.
|
|
36
|
+
await route.fulfill({ response: r, json: { ...b, sessions: [
|
|
37
|
+
{ alias: 'on-a', status: 'working', model: 'claude-opus-4', runtime: 'claude-code-cli',
|
|
38
|
+
network_id: nid, project_dir: null, created_at: fresh, updated_at: fresh, last_seen_at: fresh },
|
|
39
|
+
{ alias: 'on-b', status: 'working', model: 'claude-opus-4', runtime: 'claude-code-cli',
|
|
40
|
+
network_id: nid, project_dir: null, created_at: fresh, updated_at: fresh, last_seen_at: fresh },
|
|
41
|
+
{ alias: 'off-c', status: 'offline', model: 'claude-opus-4', runtime: 'claude-code-cli',
|
|
42
|
+
network_id: nid, project_dir: null, created_at: stale, updated_at: stale, last_seen_at: stale },
|
|
43
|
+
] } });
|
|
44
|
+
});
|
|
45
|
+
await ctx.route('**/api/hub/messages*', (r) => r.fulfill({ json: { messages: [] } }));
|
|
46
|
+
await ctx.route('**/api/hub/tasks*', (r) => r.fulfill({ json: { tasks: [] } }));
|
|
47
|
+
|
|
48
|
+
const page = await ctx.newPage();
|
|
49
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
|
|
50
|
+
// Minimap only mounts when view is non-default — zoom in twice.
|
|
51
|
+
await page.waitForSelector('[data-topo-chrome-zoom-in]', { timeout: 15000 });
|
|
52
|
+
await page.click('[data-topo-chrome-zoom-in]');
|
|
53
|
+
await page.waitForTimeout(200);
|
|
54
|
+
await page.click('[data-topo-chrome-zoom-in]');
|
|
55
|
+
await page.waitForSelector('[data-topo-minimap-dot]', { timeout: 5000 });
|
|
56
|
+
await page.waitForTimeout(400);
|
|
57
|
+
|
|
58
|
+
const probe = await page.evaluate(() => {
|
|
59
|
+
const offline = document.querySelector('[data-topo-minimap-dot-online="false"]');
|
|
60
|
+
const online = document.querySelector('[data-topo-minimap-dot-online="true"]');
|
|
61
|
+
const cs = offline ? getComputedStyle(offline) : null;
|
|
62
|
+
return {
|
|
63
|
+
offlineOpacity: offline?.getAttribute('opacity') ?? null,
|
|
64
|
+
offlineData: offline?.getAttribute('data-topo-minimap-dot-opacity') ?? null,
|
|
65
|
+
offlineR: offline?.getAttribute('r') ?? null,
|
|
66
|
+
offlineTrans: cs?.transition ?? null,
|
|
67
|
+
onlineOpacity: online?.getAttribute('opacity') ?? null,
|
|
68
|
+
onlineR: online?.getAttribute('r') ?? null,
|
|
69
|
+
};
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
await browser.close();
|
|
73
|
+
|
|
74
|
+
const hasTrans = (s, prop) =>
|
|
75
|
+
new RegExp(`${prop}\\s+\\d*\\.?\\d*s|${prop}\\s+\\d+ms`, 'i').test(s || '');
|
|
76
|
+
|
|
77
|
+
const results = {
|
|
78
|
+
offline_opacity_0_6: probe.offlineOpacity === '0.6',
|
|
79
|
+
offline_data_0_6: probe.offlineData === '0.6',
|
|
80
|
+
offline_r_1_2: probe.offlineR === '1.2', // R198 invariant
|
|
81
|
+
online_opacity_0_9: probe.onlineOpacity === '0.9', // R198 invariant
|
|
82
|
+
online_r_1_7: probe.onlineR === '1.7', // R198 invariant
|
|
83
|
+
trans_has_opacity: hasTrans(probe.offlineTrans, 'opacity'), // R198
|
|
84
|
+
trans_has_fill: hasTrans(probe.offlineTrans, 'fill'), // R198
|
|
85
|
+
trans_has_r: hasTrans(probe.offlineTrans, 'r'), // R198
|
|
86
|
+
};
|
|
87
|
+
const ok = Object.values(results).every(Boolean);
|
|
88
|
+
console.log(`${ok ? '✅' : '❌'} minimap offline opacity 0.5 → 0.6:`, JSON.stringify(results),
|
|
89
|
+
'\n probe:', probe);
|
|
90
|
+
process.exit(ok ? 0 : 1);
|