@sleep2agi/agent-network-dashboard 0.5.3-preview.77 → 0.5.3-preview.79

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.
Files changed (157) hide show
  1. package/.next/BUILD_ID +1 -1
  2. package/.next/build-manifest.json +3 -3
  3. package/.next/diagnostics/route-bundle-stats.json +5 -5
  4. package/.next/fallback-build-manifest.json +3 -3
  5. package/.next/server/app/_global-error.html +1 -1
  6. package/.next/server/app/_global-error.rsc +1 -1
  7. package/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  8. package/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  9. package/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  10. package/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  11. package/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  12. package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  13. package/.next/server/app/_not-found.html +2 -2
  14. package/.next/server/app/_not-found.rsc +2 -2
  15. package/.next/server/app/_not-found.segments/_full.segment.rsc +2 -2
  16. package/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  17. package/.next/server/app/_not-found.segments/_index.segment.rsc +2 -2
  18. package/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  19. package/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  20. package/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  21. package/.next/server/app/admin/page_client-reference-manifest.js +1 -1
  22. package/.next/server/app/admin.html +2 -2
  23. package/.next/server/app/admin.rsc +2 -2
  24. package/.next/server/app/admin.segments/_full.segment.rsc +2 -2
  25. package/.next/server/app/admin.segments/_head.segment.rsc +1 -1
  26. package/.next/server/app/admin.segments/_index.segment.rsc +2 -2
  27. package/.next/server/app/admin.segments/_tree.segment.rsc +2 -2
  28. package/.next/server/app/admin.segments/admin/__PAGE__.segment.rsc +1 -1
  29. package/.next/server/app/admin.segments/admin.segment.rsc +1 -1
  30. package/.next/server/app/index.html +2 -2
  31. package/.next/server/app/index.rsc +3 -3
  32. package/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  33. package/.next/server/app/index.segments/_full.segment.rsc +3 -3
  34. package/.next/server/app/index.segments/_head.segment.rsc +1 -1
  35. package/.next/server/app/index.segments/_index.segment.rsc +2 -2
  36. package/.next/server/app/index.segments/_tree.segment.rsc +2 -2
  37. package/.next/server/app/login/page_client-reference-manifest.js +1 -1
  38. package/.next/server/app/login.html +2 -2
  39. package/.next/server/app/login.rsc +3 -3
  40. package/.next/server/app/login.segments/_full.segment.rsc +3 -3
  41. package/.next/server/app/login.segments/_head.segment.rsc +1 -1
  42. package/.next/server/app/login.segments/_index.segment.rsc +2 -2
  43. package/.next/server/app/login.segments/_tree.segment.rsc +2 -2
  44. package/.next/server/app/login.segments/login/__PAGE__.segment.rsc +2 -2
  45. package/.next/server/app/login.segments/login.segment.rsc +1 -1
  46. package/.next/server/app/logs/page_client-reference-manifest.js +1 -1
  47. package/.next/server/app/logs.html +2 -2
  48. package/.next/server/app/logs.rsc +2 -2
  49. package/.next/server/app/logs.segments/_full.segment.rsc +2 -2
  50. package/.next/server/app/logs.segments/_head.segment.rsc +1 -1
  51. package/.next/server/app/logs.segments/_index.segment.rsc +2 -2
  52. package/.next/server/app/logs.segments/_tree.segment.rsc +2 -2
  53. package/.next/server/app/logs.segments/logs/__PAGE__.segment.rsc +1 -1
  54. package/.next/server/app/logs.segments/logs.segment.rsc +1 -1
  55. package/.next/server/app/messages/page_client-reference-manifest.js +1 -1
  56. package/.next/server/app/messages.html +2 -2
  57. package/.next/server/app/messages.rsc +2 -2
  58. package/.next/server/app/messages.segments/_full.segment.rsc +2 -2
  59. package/.next/server/app/messages.segments/_head.segment.rsc +1 -1
  60. package/.next/server/app/messages.segments/_index.segment.rsc +2 -2
  61. package/.next/server/app/messages.segments/_tree.segment.rsc +2 -2
  62. package/.next/server/app/messages.segments/messages/__PAGE__.segment.rsc +1 -1
  63. package/.next/server/app/messages.segments/messages.segment.rsc +1 -1
  64. package/.next/server/app/node/page_client-reference-manifest.js +1 -1
  65. package/.next/server/app/node.html +2 -2
  66. package/.next/server/app/node.rsc +2 -2
  67. package/.next/server/app/node.segments/_full.segment.rsc +2 -2
  68. package/.next/server/app/node.segments/_head.segment.rsc +1 -1
  69. package/.next/server/app/node.segments/_index.segment.rsc +2 -2
  70. package/.next/server/app/node.segments/_tree.segment.rsc +2 -2
  71. package/.next/server/app/node.segments/node/__PAGE__.segment.rsc +1 -1
  72. package/.next/server/app/node.segments/node.segment.rsc +1 -1
  73. package/.next/server/app/nodes/page_client-reference-manifest.js +1 -1
  74. package/.next/server/app/nodes.html +2 -2
  75. package/.next/server/app/nodes.rsc +2 -2
  76. package/.next/server/app/nodes.segments/_full.segment.rsc +2 -2
  77. package/.next/server/app/nodes.segments/_head.segment.rsc +1 -1
  78. package/.next/server/app/nodes.segments/_index.segment.rsc +2 -2
  79. package/.next/server/app/nodes.segments/_tree.segment.rsc +2 -2
  80. package/.next/server/app/nodes.segments/nodes/__PAGE__.segment.rsc +1 -1
  81. package/.next/server/app/nodes.segments/nodes.segment.rsc +1 -1
  82. package/.next/server/app/page_client-reference-manifest.js +1 -1
  83. package/.next/server/app/server-logs/page_client-reference-manifest.js +1 -1
  84. package/.next/server/app/server-logs.html +2 -2
  85. package/.next/server/app/server-logs.rsc +2 -2
  86. package/.next/server/app/server-logs.segments/_full.segment.rsc +2 -2
  87. package/.next/server/app/server-logs.segments/_head.segment.rsc +1 -1
  88. package/.next/server/app/server-logs.segments/_index.segment.rsc +2 -2
  89. package/.next/server/app/server-logs.segments/_tree.segment.rsc +2 -2
  90. package/.next/server/app/server-logs.segments/server-logs/__PAGE__.segment.rsc +1 -1
  91. package/.next/server/app/server-logs.segments/server-logs.segment.rsc +1 -1
  92. package/.next/server/app/settings/networks/page_client-reference-manifest.js +1 -1
  93. package/.next/server/app/settings/networks.html +2 -2
  94. package/.next/server/app/settings/networks.rsc +2 -2
  95. package/.next/server/app/settings/networks.segments/_full.segment.rsc +2 -2
  96. package/.next/server/app/settings/networks.segments/_head.segment.rsc +1 -1
  97. package/.next/server/app/settings/networks.segments/_index.segment.rsc +2 -2
  98. package/.next/server/app/settings/networks.segments/_tree.segment.rsc +2 -2
  99. package/.next/server/app/settings/networks.segments/settings/networks/__PAGE__.segment.rsc +1 -1
  100. package/.next/server/app/settings/networks.segments/settings/networks.segment.rsc +1 -1
  101. package/.next/server/app/settings/networks.segments/settings.segment.rsc +1 -1
  102. package/.next/server/app/settings/page_client-reference-manifest.js +1 -1
  103. package/.next/server/app/settings/tokens/page_client-reference-manifest.js +1 -1
  104. package/.next/server/app/settings/tokens.html +2 -2
  105. package/.next/server/app/settings/tokens.rsc +2 -2
  106. package/.next/server/app/settings/tokens.segments/_full.segment.rsc +2 -2
  107. package/.next/server/app/settings/tokens.segments/_head.segment.rsc +1 -1
  108. package/.next/server/app/settings/tokens.segments/_index.segment.rsc +2 -2
  109. package/.next/server/app/settings/tokens.segments/_tree.segment.rsc +2 -2
  110. package/.next/server/app/settings/tokens.segments/settings/tokens/__PAGE__.segment.rsc +1 -1
  111. package/.next/server/app/settings/tokens.segments/settings/tokens.segment.rsc +1 -1
  112. package/.next/server/app/settings/tokens.segments/settings.segment.rsc +1 -1
  113. package/.next/server/app/settings.html +2 -2
  114. package/.next/server/app/settings.rsc +3 -3
  115. package/.next/server/app/settings.segments/_full.segment.rsc +3 -3
  116. package/.next/server/app/settings.segments/_head.segment.rsc +1 -1
  117. package/.next/server/app/settings.segments/_index.segment.rsc +2 -2
  118. package/.next/server/app/settings.segments/_tree.segment.rsc +2 -2
  119. package/.next/server/app/settings.segments/settings/__PAGE__.segment.rsc +2 -2
  120. package/.next/server/app/settings.segments/settings.segment.rsc +1 -1
  121. package/.next/server/app/tasks/[id]/page_client-reference-manifest.js +1 -1
  122. package/.next/server/app/tasks/page_client-reference-manifest.js +1 -1
  123. package/.next/server/app/tasks.html +2 -2
  124. package/.next/server/app/tasks.rsc +2 -2
  125. package/.next/server/app/tasks.segments/_full.segment.rsc +2 -2
  126. package/.next/server/app/tasks.segments/_head.segment.rsc +1 -1
  127. package/.next/server/app/tasks.segments/_index.segment.rsc +2 -2
  128. package/.next/server/app/tasks.segments/_tree.segment.rsc +2 -2
  129. package/.next/server/app/tasks.segments/tasks/__PAGE__.segment.rsc +1 -1
  130. package/.next/server/app/tasks.segments/tasks.segment.rsc +1 -1
  131. package/.next/server/chunks/ssr/[root-of-the-server]__0sv~g.o._.js +1 -1
  132. package/.next/server/chunks/ssr/[root-of-the-server]__0sv~g.o._.js.map +1 -1
  133. package/.next/server/chunks/ssr/agent-network-dashboard_09kk21a._.js +3 -3
  134. package/.next/server/chunks/ssr/agent-network-dashboard_09kk21a._.js.map +1 -1
  135. package/.next/server/chunks/ssr/agent-network-dashboard_app_01jhlxz._.js +1 -1
  136. package/.next/server/chunks/ssr/agent-network-dashboard_app_01jhlxz._.js.map +1 -1
  137. package/.next/server/chunks/ssr/agent-network-dashboard_app_09d29my._.js +1 -1
  138. package/.next/server/chunks/ssr/agent-network-dashboard_app_09d29my._.js.map +1 -1
  139. package/.next/server/middleware-build-manifest.js +3 -3
  140. package/.next/server/pages/404.html +2 -2
  141. package/.next/server/pages/500.html +1 -1
  142. package/.next/static/chunks/{0y6dbmw-7m5ge.js → 0--8mvvvzr97z.js} +1 -1
  143. package/.next/static/chunks/{152t93ijmu05q.js → 03xk38u576z.4.js} +1 -1
  144. package/.next/static/chunks/0am7wwpjzr9cc.js +4 -0
  145. package/.next/static/chunks/0vl-xelss~c7q.css +2 -0
  146. package/.next/static/chunks/{0j27z9tlhz_9m.js → 0yj9lhlde8etv.js} +1 -1
  147. package/.next/trace +2 -2
  148. package/.next/trace-build +1 -1
  149. package/app/components/TopoGraph.tsx +76 -3
  150. package/package.json +1 -1
  151. package/scripts/topo-chip-row-member-alias-lit-test.mjs +154 -0
  152. package/scripts/topo-node-alias-brightness-test.mjs +84 -0
  153. package/.next/static/chunks/0fy4m4-njsp87.js +0 -4
  154. package/.next/static/chunks/0l0qml9uwy7fm.css +0 -2
  155. /package/.next/static/{jAndvCzJpRMDJpnlA3DCR → iiLvRnGGaWIOP-xRwJkb3}/_buildManifest.js +0 -0
  156. /package/.next/static/{jAndvCzJpRMDJpnlA3DCR → iiLvRnGGaWIOP-xRwJkb3}/_clientMiddlewareManifest.js +0 -0
  157. /package/.next/static/{jAndvCzJpRMDJpnlA3DCR → iiLvRnGGaWIOP-xRwJkb3}/_ssgManifest.js +0 -0
@@ -2334,6 +2334,41 @@ export function TopoGraph({ sessions, sseSessions, renameSignal }: TopoGraphProp
2334
2334
  // lists once for both chips to share.
2335
2335
  const workingAliases = onlineNodes.filter(s => s.status === 'working').map(s => s.alias);
2336
2336
  const onlineAliases = onlineNodes.map(s => s.alias);
2337
+ /* Round 565 (50-round milestone) / Loop — extend the
2338
+ inspection-overrides-encoding family to a 7th anchor at
2339
+ the chip-row chip scope. Computes the hovered alias's
2340
+ status tier (same idiom as R562/R563) so each chip's
2341
+ className can include the "lit" bg/border treatment when
2342
+ operator hovers a node matching its tier.
2343
+ Family progression — 7 anchors complete:
2344
+ R484 recent-row timestamp alias hover
2345
+ R485 edge particle opacity alias hover
2346
+ R486 minimap dot opacity alias hover
2347
+ R561 group-label + ants-gate member-alias hover
2348
+ R562 legend-swatch r + glow member-alias status match
2349
+ R563 pressure-seg brightness member-alias status match
2350
+ R565 chip-row chip bg/border member-alias status match ← this round
2351
+ Status-tier-match feedback now SATURATES across panel
2352
+ chrome at 4 surfaces simultaneously:
2353
+ minimap dot (R486)
2354
+ legend swatch (R562)
2355
+ pressure-seg (R563)
2356
+ chip-row chip (R565) ← this round
2357
+ When operator hovers a 'working' node alias, ALL FOUR
2358
+ surfaces light up in green; 'idle' → all four in teal;
2359
+ 'offline' → all four in slate. The eye gets 4-way
2360
+ confirmation of "your inspected node is in this tier"
2361
+ across every persistent status-reference surface. */
2362
+ const hoveredAliasTierKey: 'working' | 'idle' | 'offline' | null = (() => {
2363
+ if (!hoveredAlias) return null;
2364
+ const s = onlineNodes.find(n => n.alias === hoveredAlias)
2365
+ ?? offlineNodes.find(n => n.alias === hoveredAlias);
2366
+ if (!s) return null;
2367
+ if (s.status === 'working') return 'working';
2368
+ return offlineNodes.includes(s) ? 'offline' : 'idle';
2369
+ })();
2370
+ const isWorkingChipLit = hoveredAliasTierKey === 'working';
2371
+ const isOnlineChipLit = hoveredAliasTierKey === 'idle';
2337
2372
  const truncate = (list: string[]) => {
2338
2373
  const head = list.slice(0, 8).join(', ');
2339
2374
  const tail = list.length > 8 ? ` + ${list.length - 8} more` : '';
@@ -2426,13 +2461,19 @@ export function TopoGraph({ sessions, sseSessions, renameSignal }: TopoGraphProp
2426
2461
  // R398 hover-lift conditional. Composes with hover:-
2427
2462
  // translate-y-px for the same lift-and-compress
2428
2463
  // tactile signature R493 brought to reset/fullscreen.
2464
+ /* R565: when isWorkingChipLit (operator hovers a working
2465
+ node), chip stays in its "lit" bg-green-500/15 +
2466
+ border-green-500/30 state at rest. Same visual as
2467
+ hover; member-alias-matching pins the lift without
2468
+ requiring cursor on the chip. */
2429
2469
  className={`group tabular-nums font-medium px-2.5 py-1 rounded-md border anet-topo-chip-focus transition-colors transition-transform duration-200 ease-out transform-gpu ${
2430
2470
  workingCount > 0
2431
- ? 'bg-green-500/10 text-green-300 border-green-500/20 hover:bg-green-500/15 hover:border-green-500/30 hover:-translate-y-px active:scale-95'
2471
+ ? `${isWorkingChipLit ? 'bg-green-500/15 border-green-500/30' : 'bg-green-500/10 border-green-500/20'} text-green-300 hover:bg-green-500/15 hover:border-green-500/30 hover:-translate-y-px active:scale-95`
2432
2472
  : 'bg-green-500/10 text-green-300 border-green-500/20'
2433
2473
  }`}
2434
2474
  data-chip-hover-lift={workingCount > 0 ? 'true' : 'false'}
2435
2475
  data-chip-group-hover-brighten="true"
2476
+ data-working-chip-member-alias-lit={isWorkingChipLit ? 'true' : 'false'}
2436
2477
  data-working-chip
2437
2478
  data-working-chip-aliases={workingAliases.join(',')}
2438
2479
  data-pin-mirror={pinnedStatus === 'working' ? 'true' : 'false'}
@@ -2550,13 +2591,18 @@ export function TopoGraph({ sessions, sseSessions, renameSignal }: TopoGraphProp
2550
2591
  // R494 sibling — online chip joins the active:scale-95 press
2551
2592
  // family (gated on onlineNodes.length > 0 clickable branch,
2552
2593
  // same conditional pattern as the working chip above).
2594
+ /* R565: same lit-on-member-alias-match pattern as
2595
+ working chip — online chip routes hover to 'idle'
2596
+ tier (see onMouseEnter below), so its member-alias
2597
+ gate is `hoveredAliasTierKey === 'idle'`. */
2553
2598
  className={`group tabular-nums font-medium px-2.5 py-1 rounded-md border anet-topo-chip-focus transition-colors transition-transform duration-200 ease-out transform-gpu ${
2554
2599
  onlineNodes.length > 0
2555
- ? 'bg-cyan-500/10 text-cyan-300 border-cyan-500/20 hover:bg-cyan-500/15 hover:border-cyan-500/30 hover:-translate-y-px active:scale-95'
2600
+ ? `${isOnlineChipLit ? 'bg-cyan-500/15 border-cyan-500/30' : 'bg-cyan-500/10 border-cyan-500/20'} text-cyan-300 hover:bg-cyan-500/15 hover:border-cyan-500/30 hover:-translate-y-px active:scale-95`
2556
2601
  : 'bg-cyan-500/10 text-cyan-300 border-cyan-500/20'
2557
2602
  }`}
2558
2603
  data-chip-hover-lift={onlineNodes.length > 0 ? 'true' : 'false'}
2559
2604
  data-chip-group-hover-brighten="true"
2605
+ data-online-chip-member-alias-lit={isOnlineChipLit ? 'true' : 'false'}
2560
2606
  data-online-chip
2561
2607
  data-online-chip-aliases={onlineAliases.join(',')}
2562
2608
  data-pin-mirror={pinnedStatus === 'idle' ? 'true' : 'false'}
@@ -9556,10 +9602,37 @@ export function TopoGraph({ sessions, sseSessions, renameSignal }: TopoGraphProp
9556
9602
  letterSpacing:
9557
9603
  chatAlias === session.alias ? '0.5px' :
9558
9604
  hoveredAlias === session.alias ? '0.3px' : '0px',
9605
+ /* Round 564 / Loop — alias text filter stacks
9606
+ brightness(1.15) on top of R500's drop-shadow
9607
+ on hover. Mirrors R542 pressure-seg pattern
9608
+ (brightness + drop-shadow in one stacked
9609
+ filter declaration). Pre-R564 hover added
9610
+ only a drop-shadow halo around the glyph;
9611
+ post-R564 the glyph ALSO brightens, so the
9612
+ identity text reads as both "glowing" AND
9613
+ "lit up" under attention — dual paint axes
9614
+ through one filter chain.
9615
+ CSS filter supports multiple functions
9616
+ applied left-to-right. brightness(1.15)
9617
+ lifts the per-status text color (status.text:
9618
+ green/teal/slate per tier) by 15%; the drop-
9619
+ shadow then paints the outer halo in the
9620
+ status-tier hue. Together: the alias glyph
9621
+ both intensifies its identity color AND
9622
+ radiates outward in that same color.
9623
+ Same +15% brightness as R501 vendor logo
9624
+ avatar (banked per-node hover-brightness
9625
+ pattern). Consistent +15% across all per-
9626
+ node identity surfaces (logo, monogram,
9627
+ fallback avatar from R558, AND now alias
9628
+ text). Cross-element brightness consistency.
9629
+ data-node-alias-brightness attr surfaces
9630
+ the lift for tests. */
9559
9631
  filter: !reducedMotion && hoveredAlias === session.alias
9560
- ? `drop-shadow(0 0 2px ${status.text}80)`
9632
+ ? `drop-shadow(0 0 2px ${status.text}80) brightness(1.15)`
9561
9633
  : undefined,
9562
9634
  }}
9635
+ data-node-alias-brightness={!reducedMotion && hoveredAlias === session.alias ? '1.15' : '1'}
9563
9636
  >
9564
9637
  {truncate(session.alias, fullMax)}
9565
9638
  </text>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sleep2agi/agent-network-dashboard",
3
- "version": "0.5.3-preview.77",
3
+ "version": "0.5.3-preview.79",
4
4
  "description": "Agent Network Dashboard \u2014 Web UI for managing AI Agent networks",
5
5
  "scripts": {
6
6
  "dev": "next dev",
@@ -0,0 +1,154 @@
1
+ /* Round 565 (50-round milestone) verification: chip-row chips
2
+ * gain "lit" bg/border treatment when operator hovers a node
3
+ * alias matching the chip's status tier. 7th anchor in the
4
+ * inspection-overrides-encoding family.
5
+ *
6
+ * Mock: alpha·1 (working) + alpha·2 (idle) + alpha·3 (offline).
7
+ * Hover alpha·1 → working chip lit (bg-green-500/15); hover
8
+ * alpha·2 → online chip lit (bg-cyan-500/15).
9
+ *
10
+ * Test phases:
11
+ * 1. rest: both chip bg's at /10 alpha (0.1); attrs 'false'
12
+ * 2. hover alpha·1 (working) → working chip bg at /15 (0.15);
13
+ * attr 'true'; online chip stays at /10
14
+ * 3. hover alpha·2 (idle) → online chip bg at /15; attr 'true';
15
+ * working stays at /10
16
+ * 4. hover alpha·3 (offline) → neither chip lit
17
+ * 5. source-side regex confirms wiring
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 fresh = new Date(Date.now() - 60 * 1000).toISOString();
24
+
25
+ const browser = await chromium.launch({ headless: true });
26
+ const ctx = await browser.newContext({ viewport: { width: 1500, height: 1200 } });
27
+ await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
28
+ await ctx.addInitScript(() => {
29
+ try {
30
+ localStorage.setItem('anet-theme', 'cyber');
31
+ localStorage.setItem('anet-topo-layout', 'ring');
32
+ sessionStorage.setItem('anet_v3_auth', '1');
33
+ } catch {}
34
+ });
35
+ await ctx.route('**/api/hub/status*', async (route) => {
36
+ const r = await route.fetch();
37
+ const b = await r.json();
38
+ const nid = (b.sessions || [])[0]?.network_id || 'default';
39
+ const mk = (alias, status) => ({
40
+ alias, status, model: 'claude-opus-4', runtime: 'claude-code-cli',
41
+ network_id: nid, project_dir: null,
42
+ created_at: fresh, updated_at: fresh, last_seen_at: fresh,
43
+ });
44
+ await route.fulfill({ response: r, json: { ...b, sessions: [
45
+ mk('alpha·1', 'working'),
46
+ mk('alpha·2', 'idle'),
47
+ mk('alpha·3', 'offline'),
48
+ ] } });
49
+ });
50
+ await ctx.route('**/api/hub/messages*', (r) => r.fulfill({ json: { messages: [] } }));
51
+ await ctx.route('**/api/hub/tasks*', (r) => r.fulfill({ json: { tasks: [] } }));
52
+ const page = await ctx.newPage();
53
+ await page.goto('http://127.0.0.1:3000/', { waitUntil: 'networkidle' });
54
+ await page.waitForSelector('[data-working-chip]', { timeout: 15000 });
55
+ await page.waitForTimeout(500);
56
+
57
+ const probeChips = async () => {
58
+ return page.evaluate(() => {
59
+ const probe = (sel) => {
60
+ const el = document.querySelector(sel);
61
+ if (!el) return null;
62
+ const cs = getComputedStyle(el);
63
+ // Tailwind v4 emits bg in oklab format: oklab(L A B / alpha)
64
+ // Parse the trailing alpha to detect /10 vs /15.
65
+ const m = (cs.backgroundColor || '').match(/\/\s*([0-9.]+)\s*\)/);
66
+ return {
67
+ bg: cs.backgroundColor,
68
+ bgAlpha: m ? parseFloat(m[1]) : null,
69
+ };
70
+ };
71
+ return {
72
+ working: {
73
+ ...probe('[data-working-chip]'),
74
+ lit: document.querySelector('[data-working-chip-member-alias-lit]')
75
+ ?.getAttribute('data-working-chip-member-alias-lit') === 'true',
76
+ },
77
+ online: {
78
+ ...probe('[data-online-chip]'),
79
+ lit: document.querySelector('[data-online-chip-member-alias-lit]')
80
+ ?.getAttribute('data-online-chip-member-alias-lit') === 'true',
81
+ },
82
+ };
83
+ });
84
+ };
85
+
86
+ const rest = await probeChips();
87
+
88
+ // Hover working node
89
+ await page.hover('g[data-node="alpha·1"]');
90
+ await page.waitForTimeout(400);
91
+ const hoverWorking = await probeChips();
92
+
93
+ // Move and hover idle node
94
+ await page.mouse.move(0, 0);
95
+ await page.waitForTimeout(300);
96
+ await page.hover('g[data-node="alpha·2"]');
97
+ await page.waitForTimeout(400);
98
+ const hoverIdle = await probeChips();
99
+
100
+ // Move and hover offline node
101
+ await page.mouse.move(0, 0);
102
+ await page.waitForTimeout(300);
103
+ await page.hover('g[data-node="alpha·3"]');
104
+ await page.waitForTimeout(400);
105
+ const hoverOffline = await probeChips();
106
+
107
+ await browser.close();
108
+
109
+ const src = readFileSync('/home/vansin/agent-network-dashboard/app/components/TopoGraph.tsx', 'utf8');
110
+ const sourceTierKey = /const hoveredAliasTierKey: 'working' \| 'idle' \| 'offline' \| null/.test(src);
111
+ const sourceWorkingLit = /const isWorkingChipLit = hoveredAliasTierKey === 'working';/.test(src);
112
+ const sourceOnlineLit = /const isOnlineChipLit\s+= hoveredAliasTierKey === 'idle';/.test(src);
113
+ const sourceWorkingClass = /isWorkingChipLit \? 'bg-green-500\/15 border-green-500\/30' : 'bg-green-500\/10 border-green-500\/20'/.test(src);
114
+ const sourceOnlineClass = /isOnlineChipLit \? 'bg-cyan-500\/15 border-cyan-500\/30' : 'bg-cyan-500\/10 border-cyan-500\/20'/.test(src);
115
+ const sourceWorkingAttr = /data-working-chip-member-alias-lit=/.test(src);
116
+ const sourceOnlineAttr = /data-online-chip-member-alias-lit=/.test(src);
117
+
118
+ const closeAlpha = (a, target) => a !== null && Math.abs(a - target) < 0.005;
119
+
120
+ const results = {
121
+ rest_working_alpha_10: closeAlpha(rest.working.bgAlpha, 0.1),
122
+ rest_online_alpha_10: closeAlpha(rest.online.bgAlpha, 0.1),
123
+ rest_working_lit_false: rest.working.lit === false,
124
+ rest_online_lit_false: rest.online.lit === false,
125
+ // hover working → working chip alpha lifts to 0.15
126
+ hover_working_w_alpha_15: closeAlpha(hoverWorking.working.bgAlpha, 0.15),
127
+ hover_working_w_lit_true: hoverWorking.working.lit === true,
128
+ hover_working_o_alpha_10: closeAlpha(hoverWorking.online.bgAlpha, 0.1),
129
+ hover_working_o_lit_false: hoverWorking.online.lit === false,
130
+ // hover idle → online chip alpha lifts; working stays
131
+ hover_idle_o_alpha_15: closeAlpha(hoverIdle.online.bgAlpha, 0.15),
132
+ hover_idle_o_lit_true: hoverIdle.online.lit === true,
133
+ hover_idle_w_alpha_10: closeAlpha(hoverIdle.working.bgAlpha, 0.1),
134
+ hover_idle_w_lit_false: hoverIdle.working.lit === false,
135
+ // hover offline → neither chip lit
136
+ hover_offline_w_lit_false: hoverOffline.working.lit === false,
137
+ hover_offline_o_lit_false: hoverOffline.online.lit === false,
138
+ // Source
139
+ source_tier_key: sourceTierKey,
140
+ source_working_lit: sourceWorkingLit,
141
+ source_online_lit: sourceOnlineLit,
142
+ source_working_class: sourceWorkingClass,
143
+ source_online_class: sourceOnlineClass,
144
+ source_working_attr: sourceWorkingAttr,
145
+ source_online_attr: sourceOnlineAttr,
146
+ };
147
+ const ok = Object.values(results).every(Boolean);
148
+ console.log(`${ok ? '✅' : '❌'} R565 chip-row chip member-alias-lit (7th anchor, 50-round milestone):`,
149
+ JSON.stringify(results, null, 2),
150
+ '\n rest:', JSON.stringify(rest),
151
+ '\n hover working node:', JSON.stringify(hoverWorking),
152
+ '\n hover idle node:', JSON.stringify(hoverIdle),
153
+ '\n hover offline node:', JSON.stringify(hoverOffline));
154
+ process.exit(ok ? 0 : 1);
@@ -0,0 +1,84 @@
1
+ /* Round 564 verification: per-node alias text gains stacked filter
2
+ * brightness(1.15) on top of R500 drop-shadow on hover. Mirrors
3
+ * R542 pressure-seg pattern.
4
+ *
5
+ * Test phases:
6
+ * 1. rest: filter = 'none', brightness-attr = '1'
7
+ * 2. hover: filter contains BOTH drop-shadow AND brightness(1.15);
8
+ * brightness-attr = '1.15'
9
+ * 3. source-side regex confirms stacked filter expression
10
+ */
11
+ import { chromium } from 'playwright';
12
+ import { readFileSync } from 'node:fs';
13
+
14
+ const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
15
+ const fresh = new Date(Date.now() - 60 * 1000).toISOString();
16
+
17
+ const browser = await chromium.launch({ headless: true });
18
+ const ctx = await browser.newContext({ viewport: { width: 1500, height: 1200 } });
19
+ await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
20
+ await ctx.addInitScript(() => {
21
+ try {
22
+ localStorage.setItem('anet-theme', 'cyber');
23
+ localStorage.setItem('anet-topo-layout', 'ring');
24
+ sessionStorage.setItem('anet_v3_auth', '1');
25
+ } catch {}
26
+ });
27
+ await ctx.route('**/api/hub/status*', async (route) => {
28
+ const r = await route.fetch();
29
+ const b = await r.json();
30
+ const nid = (b.sessions || [])[0]?.network_id || 'default';
31
+ const mk = (alias) => ({
32
+ alias, status: 'working', model: 'claude-opus-4', runtime: 'claude-code-cli',
33
+ network_id: nid, project_dir: null,
34
+ created_at: fresh, updated_at: fresh, last_seen_at: fresh,
35
+ });
36
+ await route.fulfill({ response: r, json: { ...b, sessions: [mk('a·1'), mk('a·2')] } });
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
+ const page = await ctx.newPage();
41
+ await page.goto('http://127.0.0.1:3000/', { waitUntil: 'networkidle' });
42
+ await page.waitForSelector('[data-node-alias-text="a·1"]', { timeout: 15000 });
43
+ await page.waitForTimeout(500);
44
+
45
+ const aliasSel = '[data-node-alias-text="a·1"]';
46
+ const probe = () => page.evaluate((s) => {
47
+ const el = document.querySelector(s);
48
+ if (!el) return null;
49
+ const cs = getComputedStyle(el);
50
+ return {
51
+ filter: cs.filter,
52
+ glowAttr: el.getAttribute('data-node-alias-glow'),
53
+ brightnessAttr: el.getAttribute('data-node-alias-brightness'),
54
+ };
55
+ }, aliasSel);
56
+
57
+ const rest = await probe();
58
+ await page.hover('g[data-node="a·1"]');
59
+ await page.waitForTimeout(400);
60
+ const hover = await probe();
61
+
62
+ await browser.close();
63
+
64
+ const src = readFileSync('/home/vansin/agent-network-dashboard/app/components/TopoGraph.tsx', 'utf8');
65
+ const sourceFilter = /filter: !reducedMotion && hoveredAlias === session\.alias\s*\?\s*`drop-shadow\(0 0 2px \$\{status\.text\}80\) brightness\(1\.15\)`/.test(src);
66
+ const sourceAttr = /data-node-alias-brightness=\{!reducedMotion && hoveredAlias === session\.alias \? '1\.15' : '1'\}/.test(src);
67
+
68
+ const results = {
69
+ rest_filter_none: rest?.filter === 'none',
70
+ rest_glow_false: rest?.glowAttr === 'false',
71
+ rest_brightness_1: rest?.brightnessAttr === '1',
72
+ hover_filter_has_dropshadow: /drop-shadow\(/.test(hover?.filter || ''),
73
+ hover_filter_has_brightness: /brightness\(1\.15\)/.test(hover?.filter || ''),
74
+ hover_glow_true: hover?.glowAttr === 'true',
75
+ hover_brightness_1_15: hover?.brightnessAttr === '1.15',
76
+ source_filter: sourceFilter,
77
+ source_attr: sourceAttr,
78
+ };
79
+ const ok = Object.values(results).every(Boolean);
80
+ console.log(`${ok ? '✅' : '❌'} R564 per-node alias text brightness(1.15) stacked on R500 drop-shadow:`,
81
+ JSON.stringify(results, null, 2),
82
+ `\n rest: ${JSON.stringify(rest)}`,
83
+ `\n hover: ${JSON.stringify(hover)}`);
84
+ process.exit(ok ? 0 : 1);