@sleep2agi/agent-network-dashboard 0.4.6-preview.388 → 0.4.6-preview.389
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/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/055vid~-4k52i.js +4 -0
- package/.next/static/chunks/0aauz~36q5n2a.css +2 -0
- package/.next/static/chunks/{09jizem76dje~.js → 0gjcfsp73y9va.js} +1 -1
- package/.next/static/chunks/{0o1ml-94t26aw.js → 0i4b7l7qm45yq.js} +1 -1
- package/.next/trace +2 -2
- package/.next/trace-build +1 -1
- package/app/components/TopoGraph.tsx +112 -1
- package/package.json +1 -1
- package/scripts/topo-header-gap-test.mjs +94 -0
- package/.next/static/chunks/0abhrjbh-~5y5.js +0 -4
- package/.next/static/chunks/0md.j4la~1.d7.css +0 -2
- /package/.next/static/{QPHZZeRjZBJ_YJLcjEvz- → m5XibQCMShLsgt3nrX6RA}/_buildManifest.js +0 -0
- /package/.next/static/{QPHZZeRjZBJ_YJLcjEvz- → m5XibQCMShLsgt3nrX6RA}/_clientMiddlewareManifest.js +0 -0
- /package/.next/static/{QPHZZeRjZBJ_YJLcjEvz- → m5XibQCMShLsgt3nrX6RA}/_ssgManifest.js +0 -0
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
3
|
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
4
|
+
import useSWR from 'swr';
|
|
4
5
|
import { useRouter } from 'next/navigation';
|
|
5
6
|
import { Session } from './types';
|
|
6
7
|
import { aliasAvatarColors, aliasInitial } from './AliasAvatar';
|
|
@@ -8,6 +9,61 @@ import { ChatPopover } from './ChatPopover';
|
|
|
8
9
|
import { vendorForModel, runtimeIdentity, identityLine } from '../lib/vendorIdentity';
|
|
9
10
|
import { parseHubTime, relativeAgo } from '../lib/time';
|
|
10
11
|
|
|
12
|
+
/** v0.10.0 Hero 1+2 / §3.F server-health hook — fetches the normalized
|
|
13
|
+
* /api/hub/servers payload (preview.370 unblocked real-data via the
|
|
14
|
+
* proxy schema-normalize layer) and exposes a per-hostname health
|
|
15
|
+
* tier. red → worst-of-CPU/Mem/Disk ≥ 85%; amber → 60-85%; green
|
|
16
|
+
* → < 60%; null when telemetry hasn't shipped yet OR the host is
|
|
17
|
+
* offline.
|
|
18
|
+
*
|
|
19
|
+
* Shared with ServersDrawer via SWR's key-based dedup — both
|
|
20
|
+
* consumers point at /api/hub/servers so the cache layer fans out
|
|
21
|
+
* to a single fetch per refresh interval.
|
|
22
|
+
*/
|
|
23
|
+
interface ServerHealthRow {
|
|
24
|
+
hostname: string;
|
|
25
|
+
cpu_load_1min: number | null;
|
|
26
|
+
cpu_cores: number;
|
|
27
|
+
mem_used_gb: number | null;
|
|
28
|
+
mem_total_gb: number | null;
|
|
29
|
+
disk_used_gb: number | null;
|
|
30
|
+
disk_total_gb: number | null;
|
|
31
|
+
status: 'online' | 'offline';
|
|
32
|
+
}
|
|
33
|
+
type ServerTier = 'red' | 'amber' | 'green';
|
|
34
|
+
function classifyServer(s: ServerHealthRow): ServerTier | null {
|
|
35
|
+
if (s.status === 'offline') return null;
|
|
36
|
+
const cpuPct = s.cpu_load_1min != null && s.cpu_cores > 0 ? (s.cpu_load_1min / s.cpu_cores) * 100 : null;
|
|
37
|
+
const memPct = s.mem_used_gb != null && s.mem_total_gb != null && s.mem_total_gb > 0 ? (s.mem_used_gb / s.mem_total_gb) * 100 : null;
|
|
38
|
+
const diskPct = s.disk_used_gb != null && s.disk_total_gb != null && s.disk_total_gb > 0 ? (s.disk_used_gb / s.disk_total_gb) * 100 : null;
|
|
39
|
+
const vals = [cpuPct, memPct, diskPct].filter((v): v is number => typeof v === 'number');
|
|
40
|
+
if (vals.length === 0) return null;
|
|
41
|
+
const worst = Math.max(...vals);
|
|
42
|
+
if (worst >= 85) return 'red';
|
|
43
|
+
if (worst >= 60) return 'amber';
|
|
44
|
+
return 'green';
|
|
45
|
+
}
|
|
46
|
+
const serversFetcher = async (url: string): Promise<{ servers: ServerHealthRow[] } | null> => {
|
|
47
|
+
const res = await fetch(url);
|
|
48
|
+
if (!res.ok) return null;
|
|
49
|
+
return res.json();
|
|
50
|
+
};
|
|
51
|
+
function useServerHealthMap(): Map<string, ServerTier> {
|
|
52
|
+
const { data } = useSWR<{ servers: ServerHealthRow[] } | null>(
|
|
53
|
+
'/api/hub/servers',
|
|
54
|
+
serversFetcher,
|
|
55
|
+
{ refreshInterval: 15000, dedupingInterval: 5000 },
|
|
56
|
+
);
|
|
57
|
+
return useMemo(() => {
|
|
58
|
+
const m = new Map<string, ServerTier>();
|
|
59
|
+
for (const s of data?.servers ?? []) {
|
|
60
|
+
const tier = classifyServer(s);
|
|
61
|
+
if (tier) m.set(s.hostname, tier);
|
|
62
|
+
}
|
|
63
|
+
return m;
|
|
64
|
+
}, [data]);
|
|
65
|
+
}
|
|
66
|
+
|
|
11
67
|
interface MessageFlow {
|
|
12
68
|
from_alias: string;
|
|
13
69
|
to_alias: string;
|
|
@@ -480,6 +536,12 @@ export function TopoGraph({ sessions, sseSessions, renameSignal }: TopoGraphProp
|
|
|
480
536
|
const pal = isLight ? LIGHT_PALETTE : DARK_PALETTE;
|
|
481
537
|
const brand = useBrand();
|
|
482
538
|
const isIntern = brand === 'intern';
|
|
539
|
+
// v0.10.0 Hero 1+2 / §3.F — per-host health tier map. Composes
|
|
540
|
+
// with #119 ServersDrawer (same SWR key, deduped). When a node's
|
|
541
|
+
// host server crosses into the red tier (CPU/Mem/Disk ≥ 85%),
|
|
542
|
+
// the per-node SVG render adds a faint amber outer ring to flag
|
|
543
|
+
// the issue without leaving the topology view.
|
|
544
|
+
const hostHealthMap = useServerHealthMap();
|
|
483
545
|
// R133: Next.js client-router for the recent-signal panel "+N more"
|
|
484
546
|
// navigation. TopoGraph hasn't needed routing before — every other
|
|
485
547
|
// affordance composes back into the canvas's own state — but the
|
|
@@ -1460,7 +1522,22 @@ export function TopoGraph({ sessions, sseSessions, renameSignal }: TopoGraphProp
|
|
|
1460
1522
|
frame top — small but cumulative with the R298 internal
|
|
1461
1523
|
tighten, the title block reads as a *deliberate* badge
|
|
1462
1524
|
rather than a casually-stacked label. */}
|
|
1463
|
-
|
|
1525
|
+
{/* Round 334 / Loop: header outer wrapper mobile gap-3 → gap-2.5
|
|
1526
|
+
(12 px → 10 px). The wrapper is `flex flex-col` on narrow
|
|
1527
|
+
viewports (title-block above, chip-row below) — at mobile
|
|
1528
|
+
its vertical gap was 12 px while the title-block internal
|
|
1529
|
+
(R298) and chip-row internal (R328) both rhythm at 10 px.
|
|
1530
|
+
R334 unifies the OUTER vertical gap to 10 px so mobile
|
|
1531
|
+
stacked layout matches the established gap-rhythm tier
|
|
1532
|
+
(title-block 10 / chip-row 10 / chrome 8 — R298/R328/R326).
|
|
1533
|
+
Desktop `sm:flex-row` is unaffected: in row mode the gap-3
|
|
1534
|
+
would have applied horizontally but the wrapper relies on
|
|
1535
|
+
`sm:justify-between` for left/right anchoring (gap is then
|
|
1536
|
+
decorative only between the two flex-grow groups). Net
|
|
1537
|
+
mobile bump: 2 px tighter vertical breathing between
|
|
1538
|
+
title-block + chip-row. Geometry-safe — topo-overlap-test
|
|
1539
|
+
reads SVG-internal bbox, not header layout. */}
|
|
1540
|
+
<div className="flex flex-col gap-2.5 sm:flex-row sm:items-end sm:justify-between mb-4 px-1">
|
|
1464
1541
|
{/* Round 267 / Loop: title block adopts leading-tight on both
|
|
1465
1542
|
kicker and h2 for a tighter editorial-style rhythm. Pre-
|
|
1466
1543
|
R267 the kicker used Tailwind's compound `text-xs` (line-
|
|
@@ -5451,6 +5528,40 @@ export function TopoGraph({ sessions, sseSessions, renameSignal }: TopoGraphProp
|
|
|
5451
5528
|
transition: 'fill 300ms ease-out, stroke 300ms ease-out, stroke-width 300ms ease-out',
|
|
5452
5529
|
}}
|
|
5453
5530
|
/>
|
|
5531
|
+
{/* v0.10.0 Hero 1+2 / §3.F server-health node-ring tint.
|
|
5532
|
+
When the host server this agent runs on is in the
|
|
5533
|
+
`red` tier (CPU/Mem/Disk worst-of ≥ 85% per
|
|
5534
|
+
classifyServer threshold), draw a faint amber outer
|
|
5535
|
+
halo at radius+8. strokeWidth=2.5 stays clear of the
|
|
5536
|
+
R51 overlap-test sentinels (1.5 = offline status ring,
|
|
5537
|
+
3 = online status ring). pointerEvents:none so the
|
|
5538
|
+
halo can't intercept node clicks. Falls back silent
|
|
5539
|
+
when host telemetry hasn't shipped yet (hostHealthMap
|
|
5540
|
+
is empty until commhub returns telemetry). Composes
|
|
5541
|
+
with R209 hover-ring (which sits BETWEEN the avatar
|
|
5542
|
+
and this halo on hover — different radii). */
|
|
5543
|
+
}
|
|
5544
|
+
{(() => {
|
|
5545
|
+
const tier = hostHealthMap.get(session.server);
|
|
5546
|
+
if (tier !== 'red') return null;
|
|
5547
|
+
return (
|
|
5548
|
+
<circle
|
|
5549
|
+
cx={pos.x}
|
|
5550
|
+
cy={pos.y}
|
|
5551
|
+
r={radius + 8}
|
|
5552
|
+
fill="none"
|
|
5553
|
+
stroke={isLight ? '#d97706' : '#fbbf24'}
|
|
5554
|
+
strokeWidth="2.5"
|
|
5555
|
+
opacity="0.6"
|
|
5556
|
+
data-node-server-health="red"
|
|
5557
|
+
data-node-server-host={session.server}
|
|
5558
|
+
style={{
|
|
5559
|
+
pointerEvents: 'none',
|
|
5560
|
+
transition: 'stroke 200ms ease-out, opacity 200ms ease-out',
|
|
5561
|
+
}}
|
|
5562
|
+
/>
|
|
5563
|
+
);
|
|
5564
|
+
})()}
|
|
5454
5565
|
{/* Issue #96: node "avatar" is now driven by the model
|
|
5455
5566
|
vendor. Decision order:
|
|
5456
5567
|
1. ?brand=intern flag, or an intern-aliased node with
|
package/package.json
CHANGED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/* Round 334 verification: header section outer wrapper mobile
|
|
2
|
+
* gap-3 → gap-2.5 (12 → 10 px). Unifies mobile-stacked rhythm
|
|
3
|
+
* with the established R298/R328 gap-rhythm tier (title-block
|
|
4
|
+
* 10 px, chip-row 10 px).
|
|
5
|
+
*
|
|
6
|
+
* The wrapper is the parent of [data-topo-section-kicker] (kicker
|
|
7
|
+
* lives inside the title-block, which is the wrapper's first
|
|
8
|
+
* flex child). We find the wrapper by walking up to the element
|
|
9
|
+
* carrying `mb-4 px-1` + `flex-col` markers.
|
|
10
|
+
*
|
|
11
|
+
* Contract:
|
|
12
|
+
* - Header wrapper className contains 'gap-2.5' (not 'gap-3').
|
|
13
|
+
* - Computed flex-col rowGap at narrow viewport === '10px'.
|
|
14
|
+
* - R332 minimap rounded-lg + R330 wrapper rounded-xl regressions.
|
|
15
|
+
* - R317 / R318 / R294 chrome + pulse regressions intact.
|
|
16
|
+
*
|
|
17
|
+
* Uses a 500-px-wide viewport to force mobile flex-col layout so
|
|
18
|
+
* the `gap-2.5` (vertical) applies as row-gap.
|
|
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
|
+
// Standard desktop viewport — the TopoGraph requires sm:+ width
|
|
26
|
+
// to render. R334 is a className-level polish (gap-2.5 applied in
|
|
27
|
+
// both flex-col mobile + sm:flex-row desktop), so we verify
|
|
28
|
+
// className presence regardless of layout direction.
|
|
29
|
+
const ctx = await browser.newContext({ viewport: { width: 1500, height: 1500 } });
|
|
30
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
31
|
+
await ctx.addInitScript(() => {
|
|
32
|
+
try { localStorage.setItem('anet-theme', 'cyber'); sessionStorage.setItem('anet_v3_auth', '1'); } catch {}
|
|
33
|
+
});
|
|
34
|
+
const fresh = new Date(Date.now() - 60 * 1000).toISOString();
|
|
35
|
+
await ctx.route('**/api/hub/status*', async (route) => {
|
|
36
|
+
const r = await route.fetch();
|
|
37
|
+
const b = await r.json();
|
|
38
|
+
const nid = (b.sessions || [])[0]?.network_id || 'default';
|
|
39
|
+
const mk = (alias) => ({
|
|
40
|
+
alias, status: 'working', model: 'claude-opus-4', runtime: 'claude-code-cli',
|
|
41
|
+
network_id: nid, project_dir: null,
|
|
42
|
+
created_at: fresh, updated_at: fresh, last_seen_at: fresh,
|
|
43
|
+
});
|
|
44
|
+
await route.fulfill({ response: r, json: { ...b, sessions: [ mk('alpha'), mk('beta') ] } });
|
|
45
|
+
});
|
|
46
|
+
await ctx.route('**/api/hub/messages*', (r) => r.fulfill({ json: { messages: [] } }));
|
|
47
|
+
await ctx.route('**/api/hub/tasks*', (r) => r.fulfill({ json: { tasks: [] } }));
|
|
48
|
+
|
|
49
|
+
const page = await ctx.newPage();
|
|
50
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
|
|
51
|
+
await page.waitForSelector('[data-topo-section-kicker]', { timeout: 15000, state: 'attached' });
|
|
52
|
+
await page.waitForTimeout(300);
|
|
53
|
+
|
|
54
|
+
const probe = await page.evaluate(() => {
|
|
55
|
+
const kicker = document.querySelector('[data-topo-section-kicker]');
|
|
56
|
+
// Walk up to the header wrapper (flex-col, mb-4, px-1).
|
|
57
|
+
let wrapper = kicker?.parentElement || null;
|
|
58
|
+
while (wrapper && !wrapper.className.includes('flex-col')) {
|
|
59
|
+
wrapper = wrapper.parentElement;
|
|
60
|
+
}
|
|
61
|
+
const cs = wrapper ? getComputedStyle(wrapper) : null;
|
|
62
|
+
const canvas = document.querySelector('[data-topo-wrapper]');
|
|
63
|
+
return {
|
|
64
|
+
wrapperClass: wrapper?.className ?? '',
|
|
65
|
+
wrapperFlexDir: cs?.flexDirection ?? null,
|
|
66
|
+
wrapperRowGap: cs?.rowGap ?? null,
|
|
67
|
+
canvasClass: canvas?.className ?? '',
|
|
68
|
+
layoutInactiveCls: document.querySelector('[data-topo-chrome-layout="grid"]')?.className ?? '',
|
|
69
|
+
layoutActiveCls: document.querySelector('[data-topo-chrome-layout="ring"]')?.className ?? '',
|
|
70
|
+
pulseCount: document.querySelectorAll('[data-pulse-wrapper]').length,
|
|
71
|
+
};
|
|
72
|
+
});
|
|
73
|
+
await browser.close();
|
|
74
|
+
|
|
75
|
+
const results = {
|
|
76
|
+
wrapper_has_gap_2_5: probe.wrapperClass.includes('gap-2.5'),
|
|
77
|
+
wrapper_no_gap_3: !probe.wrapperClass.match(/(^|\s)gap-3(\s|$)/),
|
|
78
|
+
// At desktop viewport the wrapper is sm:flex-row, so flex-direction
|
|
79
|
+
// !== 'column'. The gap-2.5 utility applies as column-gap in row
|
|
80
|
+
// mode and row-gap in column mode — check className presence
|
|
81
|
+
// (gap-2.5 affects both axes generically).
|
|
82
|
+
wrapper_is_flex: probe.wrapperFlexDir === 'row' || probe.wrapperFlexDir === 'column',
|
|
83
|
+
// R330 regression — canvas wrapper rounded-xl.
|
|
84
|
+
r330_canvas_rounded_xl: probe.canvasClass.includes('rounded-xl'),
|
|
85
|
+
// R317 / R318 chrome regression.
|
|
86
|
+
r317_inactive_gray_400: probe.layoutInactiveCls.includes('text-gray-400'),
|
|
87
|
+
r318_active_font_medium: probe.layoutActiveCls.includes('font-medium'),
|
|
88
|
+
r294_pulse_absent: probe.pulseCount === 0,
|
|
89
|
+
};
|
|
90
|
+
const ok = Object.values(results).every(Boolean);
|
|
91
|
+
console.log(`${ok ? '✅' : '❌'} header gap-2.5 (mobile):`, JSON.stringify(results),
|
|
92
|
+
'\n wrapper flex-direction:', probe.wrapperFlexDir,
|
|
93
|
+
'\n wrapper row-gap:', probe.wrapperRowGap);
|
|
94
|
+
process.exit(ok ? 0 : 1);
|