@sleep2agi/agent-network-dashboard 0.5.1-preview.27 → 0.5.1-preview.29
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 +4 -4
- 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.html +1 -1
- package/.next/server/app/_not-found.rsc +1 -1
- package/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
- package/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
- 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 +1 -1
- package/.next/server/app/admin.html +1 -1
- package/.next/server/app/admin.rsc +1 -1
- package/.next/server/app/admin.segments/_full.segment.rsc +1 -1
- package/.next/server/app/admin.segments/_head.segment.rsc +1 -1
- package/.next/server/app/admin.segments/_index.segment.rsc +1 -1
- package/.next/server/app/admin.segments/_tree.segment.rsc +1 -1
- 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 +2 -2
- package/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
- package/.next/server/app/index.segments/_full.segment.rsc +2 -2
- package/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/.next/server/app/index.segments/_index.segment.rsc +1 -1
- package/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- 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 +2 -2
- package/.next/server/app/login.segments/_full.segment.rsc +2 -2
- package/.next/server/app/login.segments/_head.segment.rsc +1 -1
- package/.next/server/app/login.segments/_index.segment.rsc +1 -1
- package/.next/server/app/login.segments/_tree.segment.rsc +1 -1
- 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.html +1 -1
- package/.next/server/app/logs.rsc +1 -1
- package/.next/server/app/logs.segments/_full.segment.rsc +1 -1
- package/.next/server/app/logs.segments/_head.segment.rsc +1 -1
- package/.next/server/app/logs.segments/_index.segment.rsc +1 -1
- package/.next/server/app/logs.segments/_tree.segment.rsc +1 -1
- 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.html +1 -1
- package/.next/server/app/messages.rsc +1 -1
- package/.next/server/app/messages.segments/_full.segment.rsc +1 -1
- package/.next/server/app/messages.segments/_head.segment.rsc +1 -1
- package/.next/server/app/messages.segments/_index.segment.rsc +1 -1
- package/.next/server/app/messages.segments/_tree.segment.rsc +1 -1
- 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.html +1 -1
- package/.next/server/app/node.rsc +1 -1
- package/.next/server/app/node.segments/_full.segment.rsc +1 -1
- package/.next/server/app/node.segments/_head.segment.rsc +1 -1
- package/.next/server/app/node.segments/_index.segment.rsc +1 -1
- package/.next/server/app/node.segments/_tree.segment.rsc +1 -1
- 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.html +1 -1
- package/.next/server/app/nodes.rsc +1 -1
- package/.next/server/app/nodes.segments/_full.segment.rsc +1 -1
- package/.next/server/app/nodes.segments/_head.segment.rsc +1 -1
- package/.next/server/app/nodes.segments/_index.segment.rsc +1 -1
- package/.next/server/app/nodes.segments/_tree.segment.rsc +1 -1
- 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.html +1 -1
- package/.next/server/app/server-logs.rsc +1 -1
- package/.next/server/app/server-logs.segments/_full.segment.rsc +1 -1
- package/.next/server/app/server-logs.segments/_head.segment.rsc +1 -1
- package/.next/server/app/server-logs.segments/_index.segment.rsc +1 -1
- package/.next/server/app/server-logs.segments/_tree.segment.rsc +1 -1
- 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.html +1 -1
- package/.next/server/app/settings/networks.rsc +1 -1
- package/.next/server/app/settings/networks.segments/_full.segment.rsc +1 -1
- package/.next/server/app/settings/networks.segments/_head.segment.rsc +1 -1
- package/.next/server/app/settings/networks.segments/_index.segment.rsc +1 -1
- package/.next/server/app/settings/networks.segments/_tree.segment.rsc +1 -1
- 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.html +1 -1
- package/.next/server/app/settings/tokens.rsc +1 -1
- package/.next/server/app/settings/tokens.segments/_full.segment.rsc +1 -1
- package/.next/server/app/settings/tokens.segments/_head.segment.rsc +1 -1
- package/.next/server/app/settings/tokens.segments/_index.segment.rsc +1 -1
- package/.next/server/app/settings/tokens.segments/_tree.segment.rsc +1 -1
- 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 +2 -2
- package/.next/server/app/settings.segments/_full.segment.rsc +2 -2
- package/.next/server/app/settings.segments/_head.segment.rsc +1 -1
- package/.next/server/app/settings.segments/_index.segment.rsc +1 -1
- package/.next/server/app/settings.segments/_tree.segment.rsc +1 -1
- 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.html +1 -1
- package/.next/server/app/tasks.rsc +1 -1
- package/.next/server/app/tasks.segments/_full.segment.rsc +1 -1
- package/.next/server/app/tasks.segments/_head.segment.rsc +1 -1
- package/.next/server/app/tasks.segments/_index.segment.rsc +1 -1
- package/.next/server/app/tasks.segments/_tree.segment.rsc +1 -1
- 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 +1 -1
- 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 +1 -1
- package/.next/server/pages/500.html +1 -1
- package/.next/static/chunks/{0feqe3ryt~d-9.js → 00tcam64m5~rc.js} +1 -1
- package/.next/static/chunks/{11xaivtbslv7x.js → 0iwr.h1y0btzg.js} +1 -1
- package/.next/static/chunks/0u5t78m99~v0s.js +4 -0
- package/.next/trace +2 -2
- package/.next/trace-build +1 -1
- package/app/components/TopoGraph.tsx +43 -1
- package/package.json +1 -1
- package/scripts/topo-edge-badge-stroke-test.mjs +92 -0
- package/scripts/topo-more-flows-fontweight-test.mjs +103 -0
- package/.next/static/chunks/10p.1rpol0p3d.js +0 -4
- /package/.next/static/{GqeKDPqKv8MEUTK7SBLN3 → UoaOhm2QjMtDbdMc0tbP9}/_buildManifest.js +0 -0
- /package/.next/static/{GqeKDPqKv8MEUTK7SBLN3 → UoaOhm2QjMtDbdMc0tbP9}/_clientMiddlewareManifest.js +0 -0
- /package/.next/static/{GqeKDPqKv8MEUTK7SBLN3 → UoaOhm2QjMtDbdMc0tbP9}/_ssgManifest.js +0 -0
|
@@ -4776,14 +4776,37 @@ export function TopoGraph({ sessions, sseSessions, renameSignal }: TopoGraphProp
|
|
|
4776
4776
|
R251 closes the per-edge surface theme-toggle
|
|
4777
4777
|
smoothness — every theme-driven property on
|
|
4778
4778
|
every edge element now eases under cyber↔light. */}
|
|
4779
|
+
{/* Round 367 / Loop: edge midpoint badge rest
|
|
4780
|
+
stroke-width 1 → 1.25. Sibling visual-weight
|
|
4781
|
+
bump family (7th canvas anchor now):
|
|
4782
|
+
R287 minimap viewport stroke 1 → 1.5
|
|
4783
|
+
R295 legend swatch base radius 5.5 → 6
|
|
4784
|
+
R359 recent-row pip base radius 1.6 → 1.8
|
|
4785
|
+
R360 hub digit fontSize 11 → 12
|
|
4786
|
+
R361 edge-badge digit fontSize 10 → 11
|
|
4787
|
+
R365 hub-highlight base radius 5 → 5.5
|
|
4788
|
+
R367 edge-badge rest stroke 1 → 1.25 (this round)
|
|
4789
|
+
Cold edge badges gain ~25 % stroke presence
|
|
4790
|
+
(1.25/1.0 = 1.25). Stays clear of the R51
|
|
4791
|
+
overlap-test sentinel values (1.5 / 3 reserved
|
|
4792
|
+
for node strokes — the test selector is gated
|
|
4793
|
+
to g[data-node] ancestors so this edge-internal
|
|
4794
|
+
circle is invisible to that probe anyway, but
|
|
4795
|
+
1.25 is a safe non-sentinel value regardless).
|
|
4796
|
+
R188 transition list 'stroke-width 300ms ease-
|
|
4797
|
+
out' still smoothes the hot/pin flip — now
|
|
4798
|
+
1.25 → 2 instead of 1 → 2, same ease pace.
|
|
4799
|
+
data-edge-badge-stroke-width-rest exposes the
|
|
4800
|
+
new baseline for tests. */}
|
|
4779
4801
|
<circle
|
|
4780
4802
|
cx={badgeX} cy={badgeY}
|
|
4781
4803
|
r={isHoveredEdge || isPinned ? 10.5 : 9}
|
|
4782
4804
|
fill={pal.legendBox.fill}
|
|
4783
4805
|
stroke={isPinned ? pal.legendHeadline : isHot ? hotStroke : pal.flowEdge}
|
|
4784
|
-
strokeWidth={isPinned ? 2 : isHot ? 2 : 1}
|
|
4806
|
+
strokeWidth={isPinned ? 2 : isHot ? 2 : 1.25}
|
|
4785
4807
|
opacity={isLight ? 0.95 : 0.82}
|
|
4786
4808
|
data-edge-badge-lifted={(isHoveredEdge || isPinned) ? 'true' : 'false'}
|
|
4809
|
+
data-edge-badge-stroke-width-rest="1.25"
|
|
4787
4810
|
style={{ transition: 'r 180ms ease-out, stroke 300ms ease-out, stroke-width 300ms ease-out, fill 200ms ease-out, opacity 200ms ease-out' }}
|
|
4788
4811
|
/>
|
|
4789
4812
|
{/* Round 224 / Loop: edge badge text gains the 4th
|
|
@@ -7463,6 +7486,23 @@ export function TopoGraph({ sessions, sseSessions, renameSignal }: TopoGraphProp
|
|
|
7463
7486
|
surface. transition list extends letter-spacing
|
|
7464
7487
|
200ms ease-out alongside the existing opacity/
|
|
7465
7488
|
fill easings. */}
|
|
7489
|
+
{/* Round 368 / Loop: `+N more flows` footer text gains
|
|
7490
|
+
fontWeight=500 (font-medium tier). Sibling small-
|
|
7491
|
+
text fw lift family with R363 recent-row alias
|
|
7492
|
+
+ R364 legend-row label + R366 group-label count
|
|
7493
|
+
— all four lifts share the same theory: at small
|
|
7494
|
+
fontSize (9-11 px) against panel chrome, SVG-
|
|
7495
|
+
default fw 400 sits at the legibility floor;
|
|
7496
|
+
fw 500 brings the glyph into the deliberate-data
|
|
7497
|
+
band. fontStyle=italic + opacity 0.55 rest + R325
|
|
7498
|
+
letterSpacing 0.2 baseline + R344 hover-spread
|
|
7499
|
+
0.2 → 0.3 + R195 cyan fill on hover all preserved
|
|
7500
|
+
— the fw bump just thickens the italic stroke.
|
|
7501
|
+
Hover-state punch (R195 fill + R325 opacity 0.55
|
|
7502
|
+
→ 0.85 + R344 letter-spacing + R133 underline)
|
|
7503
|
+
stays as is, so the rest-vs-hover delta still
|
|
7504
|
+
reads clearly. data-recent-panel-more-font-weight
|
|
7505
|
+
attr exposes the value for tests. */}
|
|
7466
7506
|
<text
|
|
7467
7507
|
x="115" y="82"
|
|
7468
7508
|
textAnchor="middle"
|
|
@@ -7470,11 +7510,13 @@ export function TopoGraph({ sessions, sseSessions, renameSignal }: TopoGraphProp
|
|
|
7470
7510
|
fontSize="9"
|
|
7471
7511
|
fontFamily="monospace"
|
|
7472
7512
|
fontStyle="italic"
|
|
7513
|
+
fontWeight="500"
|
|
7473
7514
|
letterSpacing={hoveredRecentMore ? '0.3' : '0.2'}
|
|
7474
7515
|
opacity={hoveredRecentMore ? 0.85 : 0.55}
|
|
7475
7516
|
textDecoration={hoveredRecentMore ? 'underline' : 'none'}
|
|
7476
7517
|
data-recent-panel-more={moreCount}
|
|
7477
7518
|
data-recent-panel-more-hovered={hoveredRecentMore ? 'true' : 'false'}
|
|
7519
|
+
data-recent-panel-more-font-weight="500"
|
|
7478
7520
|
style={{ transition: 'opacity 150ms ease-out, fill 200ms ease-out, letter-spacing 200ms ease-out' }}
|
|
7479
7521
|
>
|
|
7480
7522
|
{`+ ${moreCount}`}
|
package/package.json
CHANGED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/* Round 367 verification: edge midpoint badge rest stroke-width
|
|
2
|
+
* 1 → 1.25. Sibling visual-weight bump (7th canvas anchor in the
|
|
3
|
+
* R287/R295/R359/R360/R361/R365/R367 family).
|
|
4
|
+
*
|
|
5
|
+
* Cold edge badges gain ~25 % stroke presence. Stays clear of the
|
|
6
|
+
* R51 overlap-test sentinel values (1.5 / 3 reserved for node
|
|
7
|
+
* strokes — the test selector is gated to g[data-node] ancestors
|
|
8
|
+
* so this edge-internal circle is invisible to that probe anyway).
|
|
9
|
+
* R188 transition list 'stroke-width 300ms ease-out' still smoothes
|
|
10
|
+
* the hot/pin flip — now 1.25 → 2 instead of 1 → 2.
|
|
11
|
+
*
|
|
12
|
+
* Contract (cyber, fixture with cold flow):
|
|
13
|
+
* - Edge badge circle stroke-width attr === '1.25'.
|
|
14
|
+
* - data-edge-badge-stroke-width-rest === '1.25'.
|
|
15
|
+
* - data-edge-badge-lifted === 'false' (rest, not hovered/pinned).
|
|
16
|
+
* - data-edge-badge-text-pin === 'false' (cold flow, link.count<10).
|
|
17
|
+
* - Inline transition contains 'stroke-width' (R188 preserved).
|
|
18
|
+
* - Pre-R367 invariants: r=9 (cold, R164), fill=pal.legendBox.fill,
|
|
19
|
+
* stroke=pal.flowEdge (cold), opacity 0.82 (cyber).
|
|
20
|
+
*/
|
|
21
|
+
import { chromium } from 'playwright';
|
|
22
|
+
import { readFileSync } from 'node:fs';
|
|
23
|
+
|
|
24
|
+
const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
|
|
25
|
+
const browser = await chromium.launch({ headless: true });
|
|
26
|
+
const ctx = await browser.newContext({ viewport: { width: 1500, height: 1500 } });
|
|
27
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
28
|
+
await ctx.addInitScript(() => {
|
|
29
|
+
try { localStorage.setItem('anet-theme', 'cyber'); sessionStorage.setItem('anet_v3_auth', '1'); } catch {}
|
|
30
|
+
});
|
|
31
|
+
const fresh = new Date(Date.now() - 60 * 1000).toISOString();
|
|
32
|
+
await ctx.route('**/api/hub/status*', async (route) => {
|
|
33
|
+
const r = await route.fetch();
|
|
34
|
+
const b = await r.json();
|
|
35
|
+
const nid = (b.sessions || [])[0]?.network_id || 'default';
|
|
36
|
+
const mk = (alias) => ({
|
|
37
|
+
alias, status: 'working', model: 'claude-opus-4', runtime: 'claude-code-cli',
|
|
38
|
+
network_id: nid, project_dir: null,
|
|
39
|
+
created_at: fresh, updated_at: fresh, last_seen_at: fresh,
|
|
40
|
+
});
|
|
41
|
+
await route.fulfill({ response: r, json: { ...b, sessions: [ mk('a'), mk('b') ] } });
|
|
42
|
+
});
|
|
43
|
+
// 1 message → 1 cold flow (count=1, well below R129 isHot=10).
|
|
44
|
+
const now = Date.now();
|
|
45
|
+
await ctx.route('**/api/hub/messages*', (r) => r.fulfill({ json: { messages: [
|
|
46
|
+
{ id: 'm1', from_alias: 'a', to_alias: 'b', content: 'ping',
|
|
47
|
+
network_id: 'default', created_at: new Date(now - 5000).toISOString() },
|
|
48
|
+
] } }));
|
|
49
|
+
await ctx.route('**/api/hub/tasks*', (r) => r.fulfill({ json: { tasks: [] } }));
|
|
50
|
+
|
|
51
|
+
const page = await ctx.newPage();
|
|
52
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
|
|
53
|
+
await page.waitForSelector('[data-edge-badge-stroke-width-rest]', { timeout: 15000 });
|
|
54
|
+
await page.waitForTimeout(300);
|
|
55
|
+
|
|
56
|
+
const probe = await page.evaluate(() => {
|
|
57
|
+
// Probe the cold/rest edge badge circle (the parent of data-edge-badge-text
|
|
58
|
+
// is the <g> wrapping circle + text; we want the circle sibling).
|
|
59
|
+
const circle = document.querySelector('[data-edge-badge-stroke-width-rest]');
|
|
60
|
+
const cs = circle ? getComputedStyle(circle) : null;
|
|
61
|
+
// Find the text in the same group to check pin state.
|
|
62
|
+
const grp = circle?.parentElement;
|
|
63
|
+
const text = grp?.querySelector('[data-edge-badge-text]');
|
|
64
|
+
return {
|
|
65
|
+
strokeWidthAttr: circle?.getAttribute('stroke-width') ?? null,
|
|
66
|
+
strokeWidthData: circle?.getAttribute('data-edge-badge-stroke-width-rest') ?? null,
|
|
67
|
+
liftedAttr: circle?.getAttribute('data-edge-badge-lifted') ?? null,
|
|
68
|
+
rAttr: circle?.getAttribute('r') ?? null,
|
|
69
|
+
opacityAttr: circle?.getAttribute('opacity') ?? null,
|
|
70
|
+
transition: cs?.transition ?? null,
|
|
71
|
+
pinAttr: text?.getAttribute('data-edge-badge-text-pin') ?? null,
|
|
72
|
+
};
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
await browser.close();
|
|
76
|
+
|
|
77
|
+
const hasTrans = (s, prop) =>
|
|
78
|
+
new RegExp(`${prop}\\s+\\d*\\.?\\d*s|${prop}\\s+\\d+ms`, 'i').test(s || '');
|
|
79
|
+
|
|
80
|
+
const results = {
|
|
81
|
+
stroke_width_1_25: probe.strokeWidthAttr === '1.25',
|
|
82
|
+
data_stroke_1_25: probe.strokeWidthData === '1.25',
|
|
83
|
+
lifted_false_rest: probe.liftedAttr === 'false',
|
|
84
|
+
r_9_cold: probe.rAttr === '9', // R164 cold
|
|
85
|
+
opacity_0_82_cyber: probe.opacityAttr === '0.82', // R251 cyber theme
|
|
86
|
+
trans_has_strokew: hasTrans(probe.transition, 'stroke-width'), // R188
|
|
87
|
+
cold_flow_not_hot: probe.pinAttr === 'false', // R220 isHot/isPinned both false
|
|
88
|
+
};
|
|
89
|
+
const ok = Object.values(results).every(Boolean);
|
|
90
|
+
console.log(`${ok ? '✅' : '❌'} edge badge stroke 1 → 1.25:`, JSON.stringify(results),
|
|
91
|
+
'\n probe:', probe);
|
|
92
|
+
process.exit(ok ? 0 : 1);
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/* Round 368 verification: recent-panel '+N more flows' footer text
|
|
2
|
+
* fontWeight 400 → 500. Sibling small-text fw lift family with R363
|
|
3
|
+
* recent-row alias + R364 legend-row label + R366 group-label count
|
|
4
|
+
* — all four lifts thicken small-fontSize text (9-11 px) against
|
|
5
|
+
* panel chrome from SVG-default 400 to the font-medium tier (500).
|
|
6
|
+
*
|
|
7
|
+
* The footer only renders when flowLinks.length > 3 (the panel shows
|
|
8
|
+
* the 3 most recent + a footer link to /messages for the overflow).
|
|
9
|
+
*
|
|
10
|
+
* Contract (cyber, 5+ flow links so the footer mounts):
|
|
11
|
+
* - data-recent-panel-more text element font-weight === '500'.
|
|
12
|
+
* - data-recent-panel-more-font-weight === '500'.
|
|
13
|
+
* - Pre-R368 invariants on the same element:
|
|
14
|
+
* * fontSize='9' + fontFamily='monospace' + fontStyle='italic'
|
|
15
|
+
* * letter-spacing='0.2' (R325 rest baseline)
|
|
16
|
+
* * opacity='0.55' (rest, R325 era)
|
|
17
|
+
* * inline transition lists opacity + letter-spacing + fill
|
|
18
|
+
* * data-recent-panel-more attr surfaces the count
|
|
19
|
+
* * data-recent-panel-more-unit tspan with opacity 0.7 (R340)
|
|
20
|
+
*/
|
|
21
|
+
import { chromium } from 'playwright';
|
|
22
|
+
import { readFileSync } from 'node:fs';
|
|
23
|
+
|
|
24
|
+
const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
|
|
25
|
+
const browser = await chromium.launch({ headless: true });
|
|
26
|
+
const ctx = await browser.newContext({ viewport: { width: 1500, height: 1500 } });
|
|
27
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
28
|
+
await ctx.addInitScript(() => {
|
|
29
|
+
try { localStorage.setItem('anet-theme', 'cyber'); sessionStorage.setItem('anet_v3_auth', '1'); } catch {}
|
|
30
|
+
});
|
|
31
|
+
const fresh = new Date(Date.now() - 60 * 1000).toISOString();
|
|
32
|
+
await ctx.route('**/api/hub/status*', async (route) => {
|
|
33
|
+
const r = await route.fetch();
|
|
34
|
+
const b = await r.json();
|
|
35
|
+
const nid = (b.sessions || [])[0]?.network_id || 'default';
|
|
36
|
+
const mk = (alias) => ({
|
|
37
|
+
alias, status: 'working', model: 'claude-opus-4', runtime: 'claude-code-cli',
|
|
38
|
+
network_id: nid, project_dir: null,
|
|
39
|
+
created_at: fresh, updated_at: fresh, last_seen_at: fresh,
|
|
40
|
+
});
|
|
41
|
+
await route.fulfill({ response: r, json: { ...b, sessions: [
|
|
42
|
+
mk('a'), mk('b'), mk('c'), mk('d'), mk('e'),
|
|
43
|
+
] } });
|
|
44
|
+
});
|
|
45
|
+
// 5 distinct flow links → panel shows 3 + footer "+ 2 more flows".
|
|
46
|
+
const now = Date.now();
|
|
47
|
+
const pairs = [['a','b'], ['c','d'], ['a','c'], ['b','d'], ['e','a']];
|
|
48
|
+
await ctx.route('**/api/hub/messages*', (r) => r.fulfill({ json: { messages:
|
|
49
|
+
pairs.map(([from, to], idx) => ({
|
|
50
|
+
id: `m${idx}`, from_alias: from, to_alias: to, content: `ping ${idx}`,
|
|
51
|
+
network_id: 'default',
|
|
52
|
+
created_at: new Date(now - (5000 + idx * 1000)).toISOString(),
|
|
53
|
+
}))
|
|
54
|
+
} }));
|
|
55
|
+
await ctx.route('**/api/hub/tasks*', (r) => r.fulfill({ json: { tasks: [] } }));
|
|
56
|
+
|
|
57
|
+
const page = await ctx.newPage();
|
|
58
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
|
|
59
|
+
await page.waitForSelector('[data-recent-panel-more]', { timeout: 15000 });
|
|
60
|
+
await page.waitForTimeout(300);
|
|
61
|
+
|
|
62
|
+
const probe = await page.evaluate(() => {
|
|
63
|
+
const t = document.querySelector('[data-recent-panel-more]');
|
|
64
|
+
const unit = document.querySelector('[data-recent-panel-more-unit]');
|
|
65
|
+
const cs = t ? getComputedStyle(t) : null;
|
|
66
|
+
return {
|
|
67
|
+
fontWeightAttr: t?.getAttribute('font-weight') ?? null,
|
|
68
|
+
fontWeightData: t?.getAttribute('data-recent-panel-more-font-weight') ?? null,
|
|
69
|
+
fontSizeAttr: t?.getAttribute('font-size') ?? null,
|
|
70
|
+
fontFamily: t?.getAttribute('font-family') ?? null,
|
|
71
|
+
fontStyle: t?.getAttribute('font-style') ?? null,
|
|
72
|
+
letterSpacing: t?.getAttribute('letter-spacing') ?? null,
|
|
73
|
+
opacityAttr: t?.getAttribute('opacity') ?? null,
|
|
74
|
+
moreCount: t?.getAttribute('data-recent-panel-more') ?? null,
|
|
75
|
+
hoveredAttr: t?.getAttribute('data-recent-panel-more-hovered') ?? null,
|
|
76
|
+
transition: cs?.transition ?? null,
|
|
77
|
+
unitOpacity: unit?.getAttribute('opacity') ?? null,
|
|
78
|
+
};
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
await browser.close();
|
|
82
|
+
|
|
83
|
+
const hasTrans = (s, prop) =>
|
|
84
|
+
new RegExp(`${prop}\\s+\\d*\\.?\\d*s|${prop}\\s+\\d+ms`, 'i').test(s || '');
|
|
85
|
+
|
|
86
|
+
const results = {
|
|
87
|
+
font_weight_500: probe.fontWeightAttr === '500',
|
|
88
|
+
data_fw_500: probe.fontWeightData === '500',
|
|
89
|
+
font_size_9: probe.fontSizeAttr === '9',
|
|
90
|
+
font_family_mono: /monospace/i.test(probe.fontFamily || ''),
|
|
91
|
+
font_style_italic: probe.fontStyle === 'italic', // pre-R368
|
|
92
|
+
letter_spacing_0_2: probe.letterSpacing === '0.2', // R325 rest
|
|
93
|
+
opacity_0_55_rest: probe.opacityAttr === '0.55', // R325 era rest
|
|
94
|
+
more_count_2: probe.moreCount === '2', // 5 links - 3 shown
|
|
95
|
+
hovered_false_rest: probe.hoveredAttr === 'false',
|
|
96
|
+
trans_has_letterspacing: hasTrans(probe.transition, 'letter-spacing'),
|
|
97
|
+
trans_has_fill: hasTrans(probe.transition, 'fill'),
|
|
98
|
+
unit_opacity_0_7: probe.unitOpacity === '0.7', // R340 unit split
|
|
99
|
+
};
|
|
100
|
+
const ok = Object.values(results).every(Boolean);
|
|
101
|
+
console.log(`${ok ? '✅' : '❌'} more-flows footer fw 400 → 500:`, JSON.stringify(results),
|
|
102
|
+
'\n probe:', probe);
|
|
103
|
+
process.exit(ok ? 0 : 1);
|