@sleep2agi/agent-network-dashboard 0.5.3-preview.263 → 0.5.3-preview.266
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 +5 -5
- 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/[root-of-the-server]__0sv~g.o._.js +1 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__0sv~g.o._.js.map +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 +1 -1
- package/.next/server/pages/500.html +1 -1
- package/.next/static/chunks/{02t4qx0vnsbnj.js → 089t1exs6apb8.js} +3 -3
- package/.next/static/chunks/{11gdlkf54jqv9.js → 0cjutq9mapkb7.js} +1 -1
- package/.next/static/chunks/{0hf7fag69h3.7.js → 0nkzy-apq7r0c.js} +1 -1
- package/.next/static/chunks/{0_jsqyukmaf5a.js → 13lpe1ad6sd-p.js} +1 -1
- package/.next/trace +2 -2
- package/.next/trace-build +1 -1
- package/app/components/TopoGraph.tsx +117 -48
- package/package.json +2 -2
- package/scripts/topo-live-lanes.mjs +48 -0
- /package/.next/static/{IoxDnk-zAN2bqUJxKcKN- → f2Eapuqm0T-focdAHRC28}/_buildManifest.js +0 -0
- /package/.next/static/{IoxDnk-zAN2bqUJxKcKN- → f2Eapuqm0T-focdAHRC28}/_clientMiddlewareManifest.js +0 -0
- /package/.next/static/{IoxDnk-zAN2bqUJxKcKN- → f2Eapuqm0T-focdAHRC28}/_ssgManifest.js +0 -0
|
@@ -72,6 +72,19 @@ interface MessageFlow {
|
|
|
72
72
|
created_at: string;
|
|
73
73
|
}
|
|
74
74
|
|
|
75
|
+
interface TaskFlow {
|
|
76
|
+
from_name?: string | null;
|
|
77
|
+
from_alias?: string | null;
|
|
78
|
+
to_name?: string | null;
|
|
79
|
+
to_alias?: string | null;
|
|
80
|
+
content?: string | null;
|
|
81
|
+
status?: string | null;
|
|
82
|
+
created_at?: string | null;
|
|
83
|
+
delivered_at?: string | null;
|
|
84
|
+
started_at?: string | null;
|
|
85
|
+
completed_at?: string | null;
|
|
86
|
+
}
|
|
87
|
+
|
|
75
88
|
interface TopoGraphProps {
|
|
76
89
|
sessions: Session[];
|
|
77
90
|
sseSessions: Record<string, number>;
|
|
@@ -508,11 +521,21 @@ function commonPrefix(a: string, b: string): string {
|
|
|
508
521
|
return a.slice(0, i);
|
|
509
522
|
}
|
|
510
523
|
|
|
511
|
-
/** #83 + #111: group nodes
|
|
512
|
-
*
|
|
513
|
-
*
|
|
514
|
-
*
|
|
515
|
-
|
|
524
|
+
/** #83 + #111: group nodes by shared ≥2-char alias prefix. Union-find over
|
|
525
|
+
* the sessions; the component label is the common alias prefix. Returns
|
|
526
|
+
* alias → groupKey.
|
|
527
|
+
*
|
|
528
|
+
* #172/#174 short-term fix: grouping is alias-prefix ONLY. The earlier
|
|
529
|
+
* project_dir co-union (Vincent 4724) was dropped — live /api/status
|
|
530
|
+
* data showed it actively wrong: 视频测试马 reported project_dir
|
|
531
|
+
* `/Users/vansin/intern-aip`, the same dir as the unrelated standalone
|
|
532
|
+
* nodes 知识马 / 群星马, so union-find transitively bridged 知识马 /
|
|
533
|
+
* 群星马 into the 视频 team. project_dir data quality is also poor
|
|
534
|
+
* (corrupted nested paths like `VideoNode/~/code/VideoNode/~/…`).
|
|
535
|
+
* alias prefix is the reliable signal; prefix-less nodes correctly
|
|
536
|
+
* fall out as singletons → the 未分组 bucket. The real fix is a
|
|
537
|
+
* first-class node.team field — tracked as #175. */
|
|
538
|
+
function computeGroups(sessions: { alias: string }[]): Record<string, string> {
|
|
516
539
|
const n = sessions.length;
|
|
517
540
|
const parent = sessions.map((_, i) => i);
|
|
518
541
|
const find = (i: number): number => {
|
|
@@ -524,16 +547,6 @@ function computeGroups(sessions: { alias: string; project_dir?: string | null }[
|
|
|
524
547
|
if (ra !== rb) parent[ra] = rb;
|
|
525
548
|
};
|
|
526
549
|
|
|
527
|
-
// union by shared project_dir
|
|
528
|
-
const byDir: Record<string, number[]> = {};
|
|
529
|
-
sessions.forEach((s, i) => {
|
|
530
|
-
const d = s.project_dir?.trim();
|
|
531
|
-
if (d) (byDir[d] ||= []).push(i);
|
|
532
|
-
});
|
|
533
|
-
for (const idxs of Object.values(byDir)) {
|
|
534
|
-
for (let k = 1; k < idxs.length; k++) union(idxs[0], idxs[k]);
|
|
535
|
-
}
|
|
536
|
-
|
|
537
550
|
// union by shared ≥2-char alias prefix — sort, link adjacent pairs
|
|
538
551
|
const order = sessions.map((_, i) => i).sort((a, b) => sessions[a].alias.localeCompare(sessions[b].alias));
|
|
539
552
|
for (let k = 0; k + 1 < order.length; k++) {
|
|
@@ -542,7 +555,7 @@ function computeGroups(sessions: { alias: string; project_dir?: string | null }[
|
|
|
542
555
|
}
|
|
543
556
|
}
|
|
544
557
|
|
|
545
|
-
// label each connected component
|
|
558
|
+
// label each connected component with the common alias prefix
|
|
546
559
|
const comps: Record<number, number[]> = {};
|
|
547
560
|
for (let i = 0; i < n; i++) (comps[find(i)] ||= []).push(i);
|
|
548
561
|
const keys: Record<string, string> = {};
|
|
@@ -551,53 +564,71 @@ function computeGroups(sessions: { alias: string; project_dir?: string | null }[
|
|
|
551
564
|
if (members.length === 1) {
|
|
552
565
|
label = sessions[members[0]].alias;
|
|
553
566
|
} else {
|
|
554
|
-
|
|
555
|
-
if (
|
|
556
|
-
const d = [...dirs][0];
|
|
557
|
-
label = d.split('/').filter(Boolean).pop() || d;
|
|
558
|
-
} else {
|
|
559
|
-
label = members.map(i => sessions[i].alias).reduce((a, b) => commonPrefix(a, b));
|
|
560
|
-
if (label.length < 2) label = sessions[members[0]].alias;
|
|
561
|
-
}
|
|
567
|
+
label = members.map(i => sessions[i].alias).reduce((a, b) => commonPrefix(a, b));
|
|
568
|
+
if (label.length < 2) label = sessions[members[0]].alias;
|
|
562
569
|
}
|
|
563
570
|
for (const i of members) keys[sessions[i].alias] = label;
|
|
564
571
|
}
|
|
565
572
|
return keys;
|
|
566
573
|
}
|
|
567
574
|
|
|
568
|
-
function buildFlowLinks(messages: MessageFlow[], positions: Record<string, Point>) {
|
|
575
|
+
function buildFlowLinks(messages: MessageFlow[], tasks: TaskFlow[], positions: Record<string, Point>) {
|
|
569
576
|
const links = new Map<string, FlowLink>();
|
|
570
577
|
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
)
|
|
578
|
+
const commandAlias = Object.keys(positions).find(a => a.includes('副指挥'))
|
|
579
|
+
?? Object.keys(positions).find(a => a.includes('总指挥'))
|
|
580
|
+
?? null;
|
|
581
|
+
|
|
582
|
+
const resolveAlias = (alias: string | null | undefined) => {
|
|
583
|
+
const clean = (alias || '').trim();
|
|
584
|
+
if (!clean) return null;
|
|
585
|
+
if (positions[clean]) return clean;
|
|
586
|
+
if ((clean === 'api' || clean === 'admin') && commandAlias) return commandAlias;
|
|
587
|
+
return clean;
|
|
588
|
+
};
|
|
589
|
+
|
|
590
|
+
const addLink = (fromRaw: string | null | undefined, toRaw: string | null | undefined, content: string, createdAt: string) => {
|
|
591
|
+
const from = resolveAlias(fromRaw);
|
|
592
|
+
const to = resolveAlias(toRaw);
|
|
593
|
+
if (!from || !to || !positions[from] || !positions[to] || from === to) {
|
|
577
594
|
return;
|
|
578
595
|
}
|
|
579
596
|
|
|
580
|
-
const key = `${
|
|
597
|
+
const key = `${from}->${to}`;
|
|
581
598
|
const current = links.get(key);
|
|
582
599
|
|
|
583
600
|
// Keep the most-recent timestamp per pair so the render can fade
|
|
584
601
|
// dormant edges (Round 10 freshness fade).
|
|
585
|
-
const incoming =
|
|
602
|
+
const incoming = createdAt || '';
|
|
586
603
|
const last_at = !current
|
|
587
604
|
? incoming
|
|
588
605
|
: (incoming > current.last_at ? incoming : current.last_at);
|
|
589
606
|
|
|
590
607
|
links.set(key, {
|
|
591
608
|
key,
|
|
592
|
-
from
|
|
593
|
-
to
|
|
609
|
+
from,
|
|
610
|
+
to,
|
|
594
611
|
count: (current?.count || 0) + 1,
|
|
595
|
-
content: current?.content ||
|
|
612
|
+
content: current?.content || content,
|
|
596
613
|
last_at,
|
|
597
614
|
});
|
|
615
|
+
};
|
|
616
|
+
|
|
617
|
+
messages.forEach(message => {
|
|
618
|
+
addLink(message.from_alias, message.to_alias, message.content, message.created_at);
|
|
598
619
|
});
|
|
599
620
|
|
|
600
|
-
|
|
621
|
+
tasks.forEach(task => {
|
|
622
|
+
const from = task.from_alias ?? task.from_name;
|
|
623
|
+
const to = task.to_alias ?? task.to_name;
|
|
624
|
+
const when = task.completed_at || task.started_at || task.delivered_at || task.created_at || '';
|
|
625
|
+
const label = task.content || (task.status ? `task:${task.status}` : 'task');
|
|
626
|
+
addLink(from, to, label, when);
|
|
627
|
+
});
|
|
628
|
+
|
|
629
|
+
return [...links.values()]
|
|
630
|
+
.sort((a, b) => (b.last_at || '').localeCompare(a.last_at || ''))
|
|
631
|
+
.slice(0, 18);
|
|
601
632
|
}
|
|
602
633
|
|
|
603
634
|
export function TopoGraph({ sessions, sseSessions, renameSignal }: TopoGraphProps) {
|
|
@@ -620,6 +651,7 @@ export function TopoGraph({ sessions, sseSessions, renameSignal }: TopoGraphProp
|
|
|
620
651
|
// wants to leave: "show me the rest of the flows" → /messages.
|
|
621
652
|
const router = useRouter();
|
|
622
653
|
const [messages, setMessages] = useState<MessageFlow[]>([]);
|
|
654
|
+
const [tasks, setTasks] = useState<TaskFlow[]>([]);
|
|
623
655
|
// Issue #87: ring | grid layout toggle. Ring is the tiered-radial default;
|
|
624
656
|
// grid arranges nodes in an N×M grid (better for 30+ nodes). Persisted to
|
|
625
657
|
// localStorage like the zoom/pan view state. Declared above nodePositions
|
|
@@ -724,20 +756,24 @@ export function TopoGraph({ sessions, sseSessions, renameSignal }: TopoGraphProp
|
|
|
724
756
|
};
|
|
725
757
|
|
|
726
758
|
useEffect(() => {
|
|
727
|
-
const
|
|
759
|
+
const fetchFlows = async () => {
|
|
728
760
|
try {
|
|
729
|
-
const
|
|
730
|
-
|
|
761
|
+
const [messageRes, taskRes] = await Promise.all([
|
|
762
|
+
fetch('/api/hub/messages?limit=50'),
|
|
763
|
+
fetch('/api/hub/tasks?limit=100'),
|
|
764
|
+
]);
|
|
765
|
+
if (messageRes.status === 401 || taskRes.status === 401) {
|
|
731
766
|
window.location.assign('/login');
|
|
732
767
|
return;
|
|
733
768
|
}
|
|
734
769
|
|
|
735
|
-
const
|
|
736
|
-
setMessages(
|
|
770
|
+
const [messageData, taskData] = await Promise.all([messageRes.json(), taskRes.json()]);
|
|
771
|
+
setMessages(messageData.messages || []);
|
|
772
|
+
setTasks(taskData.tasks || []);
|
|
737
773
|
} catch {}
|
|
738
774
|
};
|
|
739
|
-
|
|
740
|
-
const interval = setInterval(
|
|
775
|
+
fetchFlows();
|
|
776
|
+
const interval = setInterval(fetchFlows, 5000);
|
|
741
777
|
return () => clearInterval(interval);
|
|
742
778
|
}, []);
|
|
743
779
|
|
|
@@ -886,7 +922,7 @@ export function TopoGraph({ sessions, sseSessions, renameSignal }: TopoGraphProp
|
|
|
886
922
|
});
|
|
887
923
|
}
|
|
888
924
|
|
|
889
|
-
const links = buildFlowLinks(messages, positions);
|
|
925
|
+
const links = buildFlowLinks(messages, tasks, positions);
|
|
890
926
|
const active = new Set<string>();
|
|
891
927
|
links.forEach(link => { active.add(link.from); active.add(link.to); });
|
|
892
928
|
// #111: one bounding box per multi-member group (Vincent 4722). Each
|
|
@@ -1063,6 +1099,39 @@ export function TopoGraph({ sessions, sseSessions, renameSignal }: TopoGraphProp
|
|
|
1063
1099
|
// secondary sort by key keeps equal-length lanes from jittering
|
|
1064
1100
|
// between renders.
|
|
1065
1101
|
lanes.sort((a, b) => b.members.length - a.members.length || a.key.localeCompare(b.key));
|
|
1102
|
+
// Vincent 5923 (#181): keep related team lanes adjacent. Two teams
|
|
1103
|
+
// are "related" when one's key is a substring of the other's
|
|
1104
|
+
// (设计 ⊂ 海报设计师). Union-find over lane keys → substring-relation
|
|
1105
|
+
// components; each component is emitted contiguously, anchored at its
|
|
1106
|
+
// largest lane's size-sorted slot (lanes within a component stay
|
|
1107
|
+
// size-desc). Unrelated teams keep their size order — this only stops
|
|
1108
|
+
// a related pair from being split apart by an unrelated team.
|
|
1109
|
+
{
|
|
1110
|
+
const lp = lanes.map((_, i) => i);
|
|
1111
|
+
const lfind = (i: number): number => {
|
|
1112
|
+
while (lp[i] !== i) { lp[i] = lp[lp[i]]; i = lp[i]; }
|
|
1113
|
+
return i;
|
|
1114
|
+
};
|
|
1115
|
+
for (let i = 0; i < lanes.length; i++) {
|
|
1116
|
+
for (let j = i + 1; j < lanes.length; j++) {
|
|
1117
|
+
const a = lanes[i].key, b = lanes[j].key;
|
|
1118
|
+
if (a.length >= 2 && b.length >= 2 && (a.includes(b) || b.includes(a))) {
|
|
1119
|
+
lp[lfind(i)] = lfind(j);
|
|
1120
|
+
}
|
|
1121
|
+
}
|
|
1122
|
+
}
|
|
1123
|
+
const seenRoot = new Set<number>();
|
|
1124
|
+
const clustered: Lane[] = [];
|
|
1125
|
+
for (let i = 0; i < lanes.length; i++) {
|
|
1126
|
+
const root = lfind(i);
|
|
1127
|
+
if (seenRoot.has(root)) continue;
|
|
1128
|
+
seenRoot.add(root);
|
|
1129
|
+
for (let j = i; j < lanes.length; j++) {
|
|
1130
|
+
if (lfind(j) === root) clustered.push(lanes[j]);
|
|
1131
|
+
}
|
|
1132
|
+
}
|
|
1133
|
+
lanes.splice(0, lanes.length, ...clustered);
|
|
1134
|
+
}
|
|
1066
1135
|
|
|
1067
1136
|
// each lane = a wide box; its members in a single row inside it.
|
|
1068
1137
|
const laneStep = LANE_H + LANE_GAP;
|
|
@@ -1167,7 +1236,7 @@ export function TopoGraph({ sessions, sseSessions, renameSignal }: TopoGraphProp
|
|
|
1167
1236
|
// tree/swimlane. iter4 (a6689b6) suppressed them as "杂线"; Vincent
|
|
1168
1237
|
// now explicitly wants them back — same buildFlowLinks the ring/grid
|
|
1169
1238
|
// layouts use, drawn against the swimlane node positions.
|
|
1170
|
-
const links = buildFlowLinks(messages, positions);
|
|
1239
|
+
const links = buildFlowLinks(messages, tasks, positions);
|
|
1171
1240
|
const active = new Set<string>();
|
|
1172
1241
|
links.forEach(link => { active.add(link.from); active.add(link.to); });
|
|
1173
1242
|
|
|
@@ -1244,7 +1313,7 @@ export function TopoGraph({ sessions, sseSessions, renameSignal }: TopoGraphProp
|
|
|
1244
1313
|
positions[s.alias] = polarPoint(index, Math.max(offline.length, 1), offlineR, offlineRotation);
|
|
1245
1314
|
});
|
|
1246
1315
|
|
|
1247
|
-
const links = buildFlowLinks(messages, positions);
|
|
1316
|
+
const links = buildFlowLinks(messages, tasks, positions);
|
|
1248
1317
|
const active = new Set<string>();
|
|
1249
1318
|
links.forEach(link => {
|
|
1250
1319
|
active.add(link.from);
|
|
@@ -1269,7 +1338,7 @@ export function TopoGraph({ sessions, sseSessions, renameSignal }: TopoGraphProp
|
|
|
1269
1338
|
treeConnectors: { lines: [], synthLabels: [], synthRoot: false } as TreeLayout,
|
|
1270
1339
|
treeContentBox: null as { x: number; y: number; w: number; h: number } | null,
|
|
1271
1340
|
};
|
|
1272
|
-
}, [messages, sessions, sseSessions, layout, nodeScale]);
|
|
1341
|
+
}, [messages, tasks, sessions, sseSessions, layout, nodeScale]);
|
|
1273
1342
|
|
|
1274
1343
|
const workingCount = onlineNodes.filter(s => s.status === 'working').length;
|
|
1275
1344
|
// Round 744 / Loop: legend header node-count. The legend panel's header
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sleep2agi/agent-network-dashboard",
|
|
3
|
-
"version": "0.5.3-preview.
|
|
3
|
+
"version": "0.5.3-preview.266",
|
|
4
4
|
"description": "Agent Network Dashboard \u2014 Web UI for managing AI Agent networks",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"dev": "next dev",
|
|
@@ -44,4 +44,4 @@
|
|
|
44
44
|
"tailwindcss": "^4",
|
|
45
45
|
"typescript": "^5"
|
|
46
46
|
}
|
|
47
|
-
}
|
|
47
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/* #181 verify: load the LIVE dashboard (real ~99 sessions), tree/swimlane
|
|
2
|
+
* layout, dump team-lane order top→bottom + screenshot. Confirms 设计 lane
|
|
3
|
+
* sits adjacent to 海报设计师 (substring-related cluster). */
|
|
4
|
+
import { chromium } from 'playwright';
|
|
5
|
+
import { readFileSync, mkdirSync } from 'node:fs';
|
|
6
|
+
|
|
7
|
+
const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
|
|
8
|
+
mkdirSync('/tmp/anet-181', { recursive: true });
|
|
9
|
+
const browser = await chromium.launch({ headless: true });
|
|
10
|
+
const ctx = await browser.newContext({ viewport: { width: 1280, height: 920 } });
|
|
11
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
12
|
+
await ctx.addInitScript(() => {
|
|
13
|
+
try {
|
|
14
|
+
localStorage.setItem('anet-theme', 'cyber');
|
|
15
|
+
localStorage.removeItem('anet-brand');
|
|
16
|
+
localStorage.removeItem('anet-topo-view');
|
|
17
|
+
localStorage.setItem('anet-topo-layout', 'tree');
|
|
18
|
+
sessionStorage.setItem('anet_v3_auth', '1');
|
|
19
|
+
} catch {}
|
|
20
|
+
});
|
|
21
|
+
const page = await ctx.newPage();
|
|
22
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
|
|
23
|
+
await page.waitForFunction(() => {
|
|
24
|
+
const svg = document.querySelector('svg[viewBox="0 0 1000 680"]');
|
|
25
|
+
return !!svg && svg.querySelectorAll('g[data-group]').length > 3;
|
|
26
|
+
}, { timeout: 30000 }).catch(() => {});
|
|
27
|
+
await page.waitForTimeout(1200);
|
|
28
|
+
await page.evaluate(() => document.querySelector('svg[viewBox="0 0 1000 680"]')
|
|
29
|
+
?.scrollIntoView({ behavior: 'instant', block: 'center' }));
|
|
30
|
+
await page.waitForTimeout(400);
|
|
31
|
+
|
|
32
|
+
const lanes = await page.evaluate(() => {
|
|
33
|
+
const svg = document.querySelector('svg[viewBox="0 0 1000 680"]');
|
|
34
|
+
return [...svg.querySelectorAll('g[data-group]')]
|
|
35
|
+
.map(g => {
|
|
36
|
+
const r = g.querySelector('rect');
|
|
37
|
+
return { key: g.getAttribute('data-group'), y: +r.getAttribute('y'), x: +r.getAttribute('x') };
|
|
38
|
+
})
|
|
39
|
+
.sort((a, b) => a.y - b.y);
|
|
40
|
+
});
|
|
41
|
+
console.log('lane order (top → bottom):');
|
|
42
|
+
lanes.forEach((l, i) => console.log(` ${String(i + 1).padStart(2)}. ${l.key} (y=${l.y.toFixed(0)}, x=${l.x.toFixed(0)})`));
|
|
43
|
+
|
|
44
|
+
const svgEl = await page.$('svg[viewBox="0 0 1000 680"]');
|
|
45
|
+
await svgEl.screenshot({ path: '/tmp/anet-181/swimlane-live.png', animations: 'disabled' });
|
|
46
|
+
await ctx.close();
|
|
47
|
+
await browser.close();
|
|
48
|
+
console.log('screenshot: /tmp/anet-181/swimlane-live.png');
|
|
File without changes
|
/package/.next/static/{IoxDnk-zAN2bqUJxKcKN- → f2Eapuqm0T-focdAHRC28}/_clientMiddlewareManifest.js
RENAMED
|
File without changes
|
|
File without changes
|