@sleep2agi/agent-network-dashboard 0.5.3-preview.260 → 0.5.3-preview.262
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/{0u8v68gl7g6j1.js → 01~4zvq_o_k32.js} +1 -1
- package/.next/static/chunks/{0p142v5va508~.js → 070._s.6bq1dx.js} +1 -1
- package/.next/static/chunks/0vuc69a~-fb7u.js +4 -0
- package/.next/static/chunks/{11sahbo6ikg8g.js → 0~~5hvnaek6hz.js} +1 -1
- package/.next/trace +2 -2
- package/.next/trace-build +1 -1
- package/app/components/TopoGraph.tsx +396 -22
- package/app/lib/vendorIdentity.ts +74 -56
- package/package.json +1 -1
- package/public/vendors/claude.svg +7 -8
- package/public/vendors/minimax.svg +8 -9
- package/public/vendors/openai.svg +8 -10
- package/scripts/topo-overlap-test.mjs +22 -8
- package/scripts/topo-tree-diag.mjs +95 -0
- package/.next/static/chunks/083elibefsefi.js +0 -4
- /package/.next/static/{wz1T-LhLDalz691PpN3E7 → uxzbzXUe6BEA30oLCqiD_}/_buildManifest.js +0 -0
- /package/.next/static/{wz1T-LhLDalz691PpN3E7 → uxzbzXUe6BEA30oLCqiD_}/_clientMiddlewareManifest.js +0 -0
- /package/.next/static/{wz1T-LhLDalz691PpN3E7 → uxzbzXUe6BEA30oLCqiD_}/_ssgManifest.js +0 -0
|
@@ -33,70 +33,88 @@ const UNKNOWN_VENDOR: VendorIdentity = {
|
|
|
33
33
|
logo: null,
|
|
34
34
|
};
|
|
35
35
|
|
|
36
|
+
// Vendor identities, named so both the model-prefix rules and the
|
|
37
|
+
// runtime fallback map below can reference the same object.
|
|
38
|
+
const INTERN_VENDOR: VendorIdentity = {
|
|
39
|
+
id: 'intern',
|
|
40
|
+
label: '书生 · 上海 AI 实验室',
|
|
41
|
+
mono: { bg: 'hsl(28 38% 24%)', ring: 'hsl(32 45% 52%)', text: 'hsl(34 60% 82%)' },
|
|
42
|
+
initial: '书',
|
|
43
|
+
// #79 shipped this asset — reuse it as the 书生 vendor logo.
|
|
44
|
+
logo: '/intern_avatar.png',
|
|
45
|
+
};
|
|
46
|
+
const MINIMAX_VENDOR: VendorIdentity = {
|
|
47
|
+
id: 'minimax',
|
|
48
|
+
label: 'MiniMax',
|
|
49
|
+
mono: { bg: 'hsl(18 50% 26%)', ring: 'hsl(18 65% 52%)', text: 'hsl(20 80% 82%)' },
|
|
50
|
+
initial: 'M',
|
|
51
|
+
// Official MiniMax mark (simple-icons set, CC0) on a warm-red tinted
|
|
52
|
+
// badge. Vincent-authorized 2026-05-21 to use real vendor marks.
|
|
53
|
+
logo: '/vendors/minimax.svg',
|
|
54
|
+
};
|
|
55
|
+
const ANTHROPIC_VENDOR: VendorIdentity = {
|
|
56
|
+
id: 'anthropic',
|
|
57
|
+
label: 'Anthropic',
|
|
58
|
+
mono: { bg: 'hsl(16 32% 26%)', ring: 'hsl(16 48% 54%)', text: 'hsl(18 60% 84%)' },
|
|
59
|
+
initial: 'A',
|
|
60
|
+
// Official Anthropic mark (simple-icons set, CC0) on a warm-orange
|
|
61
|
+
// tinted badge. Vincent-authorized 2026-05-21 to use real vendor marks.
|
|
62
|
+
logo: '/vendors/claude.svg',
|
|
63
|
+
};
|
|
64
|
+
const OPENAI_VENDOR: VendorIdentity = {
|
|
65
|
+
id: 'openai',
|
|
66
|
+
label: 'OpenAI',
|
|
67
|
+
mono: { bg: 'hsl(165 26% 22%)', ring: 'hsl(165 40% 44%)', text: 'hsl(165 45% 80%)' },
|
|
68
|
+
initial: 'O',
|
|
69
|
+
// Official OpenAI mark (simple-icons set, CC0) on a teal tinted
|
|
70
|
+
// badge. Vincent-authorized 2026-05-21 to use real vendor marks.
|
|
71
|
+
logo: '/vendors/openai.svg',
|
|
72
|
+
};
|
|
73
|
+
|
|
36
74
|
// Ordered prefix rules — first match wins. `test` runs against a lowercased
|
|
37
75
|
// model id. Keep the most specific prefixes first.
|
|
38
76
|
const VENDOR_RULES: Array<{ test: (m: string) => boolean; vendor: VendorIdentity }> = [
|
|
39
|
-
{
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
id: 'intern',
|
|
43
|
-
label: '书生 · 上海 AI 实验室',
|
|
44
|
-
mono: { bg: 'hsl(28 38% 24%)', ring: 'hsl(32 45% 52%)', text: 'hsl(34 60% 82%)' },
|
|
45
|
-
initial: '书',
|
|
46
|
-
// #79 shipped this asset — reuse it as the 书生 vendor logo.
|
|
47
|
-
logo: '/intern_avatar.png',
|
|
48
|
-
},
|
|
49
|
-
},
|
|
50
|
-
{
|
|
51
|
-
test: (m) => m.startsWith('minimax'),
|
|
52
|
-
vendor: {
|
|
53
|
-
id: 'minimax',
|
|
54
|
-
label: 'MiniMax',
|
|
55
|
-
mono: { bg: 'hsl(18 50% 26%)', ring: 'hsl(18 65% 52%)', text: 'hsl(20 80% 82%)' },
|
|
56
|
-
initial: 'M',
|
|
57
|
-
// P0 (Vincent 5222) custom-designed vendor badge — NOT a copy of
|
|
58
|
-
// the MiniMax trademark; geometric min/max zigzag in their warm-
|
|
59
|
-
// red palette. Replaces plain-letter "M" fallback.
|
|
60
|
-
logo: '/vendors/minimax.svg',
|
|
61
|
-
},
|
|
62
|
-
},
|
|
63
|
-
{
|
|
64
|
-
test: (m) => m.startsWith('claude'),
|
|
65
|
-
vendor: {
|
|
66
|
-
id: 'anthropic',
|
|
67
|
-
label: 'Anthropic',
|
|
68
|
-
mono: { bg: 'hsl(16 32% 26%)', ring: 'hsl(16 48% 54%)', text: 'hsl(18 60% 84%)' },
|
|
69
|
-
initial: 'A',
|
|
70
|
-
// P0 (Vincent 5222) custom-designed vendor badge — NOT a copy of
|
|
71
|
-
// the Anthropic trademark; 4-pointed sparkle in their warm-orange
|
|
72
|
-
// palette evokes AI/Claude without imitating the official mark.
|
|
73
|
-
// Real Anthropic logo still pending Vincent-direct asset OK.
|
|
74
|
-
logo: '/vendors/claude.svg',
|
|
75
|
-
},
|
|
76
|
-
},
|
|
77
|
+
{ test: (m) => m.startsWith('intern'), vendor: INTERN_VENDOR },
|
|
78
|
+
{ test: (m) => m.startsWith('minimax'), vendor: MINIMAX_VENDOR },
|
|
79
|
+
{ test: (m) => m.startsWith('claude'), vendor: ANTHROPIC_VENDOR },
|
|
77
80
|
{
|
|
78
81
|
test: (m) => m.startsWith('gpt') || m.startsWith('codex') || m.startsWith('o1') || m.startsWith('o3') || m.startsWith('o4'),
|
|
79
|
-
vendor:
|
|
80
|
-
id: 'openai',
|
|
81
|
-
label: 'OpenAI',
|
|
82
|
-
mono: { bg: 'hsl(165 26% 22%)', ring: 'hsl(165 40% 44%)', text: 'hsl(165 45% 80%)' },
|
|
83
|
-
initial: 'O',
|
|
84
|
-
// P0 (Vincent 5222) custom-designed vendor badge — NOT a copy of
|
|
85
|
-
// the OpenAI trademark; hexagonal frame + center dot in their
|
|
86
|
-
// teal palette evokes geometric AI lattice without imitating the
|
|
87
|
-
// knot. Real OpenAI logo still pending Vincent-direct asset OK.
|
|
88
|
-
logo: '/vendors/openai.svg',
|
|
89
|
-
},
|
|
82
|
+
vendor: OPENAI_VENDOR,
|
|
90
83
|
},
|
|
91
84
|
];
|
|
92
85
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
86
|
+
/* Runtime → vendor fallback. Used only when the `model` field can't
|
|
87
|
+
* resolve a vendor (null or unmatched).
|
|
88
|
+
*
|
|
89
|
+
* Why this exists: live hub /api/status probe (2026-05-21) showed 62%
|
|
90
|
+
* of sessions report `model: null` — including ALL claude-code-cli
|
|
91
|
+
* nodes — so the avatar fell back to the dark "unknown vendor"
|
|
92
|
+
* monogram for most of the fleet. The `runtime` field, by contrast,
|
|
93
|
+
* is reliably populated. A claude-code-cli / claude-agent-sdk node is
|
|
94
|
+
* an Anthropic shell; codex-sdk is OpenAI's. Deriving the vendor from
|
|
95
|
+
* runtime when the model is silent lights up the vendor logo for the
|
|
96
|
+
* whole fleet instead of leaving it grey. The model still wins when
|
|
97
|
+
* present — runtime is strictly the fallback. */
|
|
98
|
+
const RUNTIME_VENDOR: Record<string, VendorIdentity> = {
|
|
99
|
+
'claude-code-cli': ANTHROPIC_VENDOR,
|
|
100
|
+
'claude-agent-sdk': ANTHROPIC_VENDOR,
|
|
101
|
+
'codex-sdk': OPENAI_VENDOR,
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
/** Resolve a node's vendor identity. Model id wins; when the model is
|
|
105
|
+
* null or unmatched, fall back to the execution runtime. Both silent
|
|
106
|
+
* → UNKNOWN. */
|
|
107
|
+
export function vendorForModel(
|
|
108
|
+
model: string | null | undefined,
|
|
109
|
+
runtime?: string | null | undefined,
|
|
110
|
+
): VendorIdentity {
|
|
111
|
+
if (model) {
|
|
112
|
+
const m = model.toLowerCase();
|
|
113
|
+
for (const rule of VENDOR_RULES) {
|
|
114
|
+
if (rule.test(m)) return rule.vendor;
|
|
115
|
+
}
|
|
99
116
|
}
|
|
117
|
+
if (runtime && RUNTIME_VENDOR[runtime]) return RUNTIME_VENDOR[runtime];
|
|
100
118
|
return UNKNOWN_VENDOR;
|
|
101
119
|
}
|
|
102
120
|
|
|
@@ -146,7 +164,7 @@ export function runtimeIdentity(runtime: string | null | undefined): RuntimeIden
|
|
|
146
164
|
/** Compact one-line identity for hover / detail surfaces:
|
|
147
165
|
* "Anthropic · claude-opus-4 · Claude Code CLI". Pieces with no data drop. */
|
|
148
166
|
export function identityLine(model: string | null | undefined, runtime: string | null | undefined): string {
|
|
149
|
-
const v = vendorForModel(model);
|
|
167
|
+
const v = vendorForModel(model, runtime);
|
|
150
168
|
const r = runtimeIdentity(runtime);
|
|
151
169
|
const parts: string[] = [];
|
|
152
170
|
if (v.id !== 'unknown') parts.push(v.label);
|
package/package.json
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64">
|
|
2
|
-
<!-- Anthropic
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
<circle cx="32" cy="32" r="
|
|
7
|
-
<
|
|
8
|
-
|
|
9
|
-
<path d="M 0 -18 L 4 -4 L 18 0 L 4 4 L 0 18 L -4 4 L -18 0 L -4 -4 Z" />
|
|
2
|
+
<!-- Anthropic vendor mark — official Anthropic logo (simple-icons set, CC0).
|
|
3
|
+
Vincent-authorized 2026-05-21 to use real vendor marks. Tinted circular
|
|
4
|
+
badge frames the official mark for the dashboard node-avatar context. -->
|
|
5
|
+
<circle cx="32" cy="32" r="32" fill="hsl(16 32% 22%)"/>
|
|
6
|
+
<circle cx="32" cy="32" r="30" fill="none" stroke="hsl(16 48% 54%)" stroke-width="2"/>
|
|
7
|
+
<g transform="translate(16 16) scale(1.333)" fill="hsl(20 80% 82%)">
|
|
8
|
+
<path d="M17.3041 3.541h-3.6718l6.696 16.918H24Zm-10.6082 0L0 20.459h3.7442l1.3693-3.5527h7.0052l1.3693 3.5528h3.7442L10.5363 3.5409Zm-.3712 10.2232 2.2914-5.9456 2.2914 5.9456Z"/>
|
|
10
9
|
</g>
|
|
11
10
|
</svg>
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64">
|
|
2
|
-
<!-- MiniMax vendor mark
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
<circle cx="32" cy="32" r="
|
|
7
|
-
<
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
stroke-linecap="round" stroke-linejoin="round" />
|
|
2
|
+
<!-- MiniMax vendor mark — official MiniMax logo (simple-icons set, CC0).
|
|
3
|
+
Vincent-authorized 2026-05-21 to use real vendor marks. Tinted circular
|
|
4
|
+
badge frames the official mark for the dashboard node-avatar context. -->
|
|
5
|
+
<circle cx="32" cy="32" r="32" fill="hsl(18 50% 22%)"/>
|
|
6
|
+
<circle cx="32" cy="32" r="30" fill="none" stroke="hsl(18 65% 52%)" stroke-width="2"/>
|
|
7
|
+
<g transform="translate(16 16) scale(1.333)" fill="hsl(20 80% 84%)">
|
|
8
|
+
<path d="M11.43 3.92a.86.86 0 1 0-1.718 0v14.236a1.999 1.999 0 0 1-3.997 0V9.022a.86.86 0 1 0-1.718 0v3.87a1.999 1.999 0 0 1-3.997 0V11.49a.57.57 0 0 1 1.139 0v1.404a.86.86 0 0 0 1.719 0V9.022a1.999 1.999 0 0 1 3.997 0v9.134a.86.86 0 0 0 1.719 0V3.92a1.998 1.998 0 1 1 3.996 0v11.788a.57.57 0 1 1-1.139 0zm10.572 3.105a2 2 0 0 0-1.999 1.997v7.63a.86.86 0 0 1-1.718 0V3.923a1.999 1.999 0 0 0-3.997 0v16.16a.86.86 0 0 1-1.719 0V18.08a.57.57 0 1 0-1.138 0v2a1.998 1.998 0 0 0 3.996 0V3.92a.86.86 0 0 1 1.719 0v12.73a1.999 1.999 0 0 0 3.996 0V9.023a.86.86 0 1 1 1.72 0v6.686a.57.57 0 0 0 1.138 0V9.022a2 2 0 0 0-1.998-1.997"/>
|
|
9
|
+
</g>
|
|
11
10
|
</svg>
|
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64">
|
|
2
|
-
<!-- OpenAI
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
<
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
fill="none" stroke="hsl(165 50% 78%)" stroke-width="3" stroke-linejoin="round" />
|
|
11
|
-
<circle cx="32" cy="32" r="4" fill="hsl(165 50% 78%)" />
|
|
2
|
+
<!-- OpenAI vendor mark — official OpenAI logo (simple-icons set, CC0).
|
|
3
|
+
Vincent-authorized 2026-05-21 to use real vendor marks. Tinted circular
|
|
4
|
+
badge frames the official mark for the dashboard node-avatar context. -->
|
|
5
|
+
<circle cx="32" cy="32" r="32" fill="hsl(165 26% 20%)"/>
|
|
6
|
+
<circle cx="32" cy="32" r="30" fill="none" stroke="hsl(165 40% 44%)" stroke-width="2"/>
|
|
7
|
+
<g transform="translate(16 16) scale(1.333)" fill="hsl(165 50% 82%)">
|
|
8
|
+
<path d="M22.2819 9.8211a5.9847 5.9847 0 0 0-.5157-4.9108 6.0462 6.0462 0 0 0-6.5098-2.9A6.0651 6.0651 0 0 0 4.9807 4.1818a5.9847 5.9847 0 0 0-3.9977 2.9 6.0462 6.0462 0 0 0 .7427 7.0966 5.98 5.98 0 0 0 .511 4.9107 6.051 6.051 0 0 0 6.5146 2.9001A5.9847 5.9847 0 0 0 13.2599 24a6.0557 6.0557 0 0 0 5.7718-4.2058 5.9894 5.9894 0 0 0 3.9977-2.9001 6.0557 6.0557 0 0 0-.7475-7.0729zm-9.022 12.6081a4.4755 4.4755 0 0 1-2.8764-1.0408l.1419-.0804 4.7783-2.7582a.7948.7948 0 0 0 .3927-.6813v-6.7369l2.02 1.1686a.071.071 0 0 1 .038.052v5.5826a4.504 4.504 0 0 1-4.4945 4.4944zm-9.6607-4.1254a4.4708 4.4708 0 0 1-.5346-3.0137l.142.0852 4.783 2.7582a.7712.7712 0 0 0 .7806 0l5.8428-3.3685v2.3324a.0804.0804 0 0 1-.0332.0615L9.74 19.9502a4.4992 4.4992 0 0 1-6.1408-1.6464zM2.3408 7.8956a4.485 4.485 0 0 1 2.3655-1.9728V11.6a.7664.7664 0 0 0 .3879.6765l5.8144 3.3543-2.0201 1.1685a.0757.0757 0 0 1-.071 0l-4.8303-2.7865A4.504 4.504 0 0 1 2.3408 7.872zm16.5963 3.8558L13.1038 8.364 15.1192 7.2a.0757.0757 0 0 1 .071 0l4.8303 2.7913a4.4944 4.4944 0 0 1-.6765 8.1042v-5.6772a.79.79 0 0 0-.407-.667zm2.0107-3.0231l-.142-.0852-4.7735-2.7818a.7759.7759 0 0 0-.7854 0L9.409 9.2297V6.8974a.0662.0662 0 0 1 .0284-.0615l4.8303-2.7866a4.4992 4.4992 0 0 1 6.6802 4.66zM8.3065 12.863l-2.02-1.1638a.0804.0804 0 0 1-.038-.0567V6.0742a4.4992 4.4992 0 0 1 7.3757-3.4537l-.142.0805L8.704 5.459a.7948.7948 0 0 0-.3927.6813zm1.0976-2.3654l2.602-1.4998 2.6069 1.4998v2.9994l-2.5974 1.4997-2.6067-1.4997Z"/>
|
|
9
|
+
</g>
|
|
12
10
|
</svg>
|
|
@@ -14,15 +14,26 @@ const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8'))
|
|
|
14
14
|
mkdirSync('/tmp/anet-issue-112', { recursive: true });
|
|
15
15
|
const browser = await chromium.launch({ headless: true });
|
|
16
16
|
|
|
17
|
-
// ~30 nodes: 4 prefix groups + a workdir group + singletons
|
|
17
|
+
// ~30 nodes: 4 prefix groups + a workdir group + singletons.
|
|
18
|
+
// #170 tree-view MVP — the fleet now also carries `runtime` so the org-
|
|
19
|
+
// chart layout can derive team leads (claude-code-cli) and deputies
|
|
20
|
+
// (codex-sdk). The first node in each prefix group is the cli lead, the
|
|
21
|
+
// second is the codex deputy; the rest are plain members. ring/grid
|
|
22
|
+
// ignore `runtime` so their overlap geometry is unchanged.
|
|
23
|
+
const lead = (a) => ({ alias: a, runtime: 'claude-code-cli' });
|
|
24
|
+
const dep = (a) => ({ alias: a, runtime: 'codex-sdk' });
|
|
25
|
+
const mem = (a) => ({ alias: a, runtime: 'claude-agent-sdk' });
|
|
18
26
|
const FLEET = [
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
]
|
|
27
|
+
// commander roots — exercise the layer-0 / layer-1 derivation
|
|
28
|
+
lead('总指挥'), lead('副指挥A'), lead('副指挥B'),
|
|
29
|
+
[lead, dep, mem, mem, mem, mem].map((f, i) => f(['A站内容', 'A站评测', 'A站数据', 'A站设计', 'A站运营', 'A站工程'][i])),
|
|
30
|
+
[lead, dep, mem, mem, mem].map((f, i) => f(['B站产品', 'B站工程', 'B站测试', 'B站运维', 'B站运营'][i])),
|
|
31
|
+
[lead, dep, mem, mem].map((f, i) => f(['P站产品', 'P站工程', 'P站测试', 'P站运维'][i])),
|
|
32
|
+
[lead, dep, mem, mem].map((f, i) => f(['通信龙', '通信牛', '通信马', '通信SDK马'][i])),
|
|
33
|
+
['srv-a', 'srv-b', 'srv-c'].map(a => ({ alias: a, runtime: 'http-api', project_dir: '/home/v/agent-orchestra' })),
|
|
34
|
+
// orphan singletons — collected into the 未分组 bucket in tree mode
|
|
35
|
+
['群星马', '书生1号', '微信马', '飞书马', '独立节点', '研究员1号', '研究员2号', '游侠马'].map(a => mem(a)),
|
|
36
|
+
].flat();
|
|
26
37
|
|
|
27
38
|
const overlaps1D = (a0, a1, b0, b1, tol) => a0 < b1 - tol && b0 < a1 - tol;
|
|
28
39
|
|
|
@@ -46,6 +57,7 @@ async function check(layout) {
|
|
|
46
57
|
const sessions = FLEET.map((f, i) => ({
|
|
47
58
|
alias: f.alias, status: i % 5 === 0 ? 'working' : 'idle', network_id: nid,
|
|
48
59
|
project_dir: f.project_dir ?? null,
|
|
60
|
+
runtime: f.runtime ?? null,
|
|
49
61
|
created_at: '2026-05-15T00:00:00Z', updated_at: '2026-05-15T00:00:00Z', last_seen_at: new Date().toISOString(),
|
|
50
62
|
}));
|
|
51
63
|
await route.fulfill({ response: r, json: { ...b, sessions } });
|
|
@@ -189,6 +201,8 @@ async function check(layout) {
|
|
|
189
201
|
const all = [];
|
|
190
202
|
all.push(await check('grid'));
|
|
191
203
|
all.push(await check('ring'));
|
|
204
|
+
// #170 tree-view MVP — the org-chart layout must be zero-overlap too.
|
|
205
|
+
all.push(await check('tree'));
|
|
192
206
|
await browser.close();
|
|
193
207
|
// R463: any non-boolean return is a sentinel (e.g. { stale: true }
|
|
194
208
|
// from the zombie-build guard). Treat as a hard fail — collision
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/* Diagnostic: compare grid vs tree node frontend presentation.
|
|
2
|
+
* Vincent UX complaint — tree view "没有像 grid 视图那样的前端展示".
|
|
3
|
+
* Screenshots both layouts + dumps per-node visual element counts. */
|
|
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-tree-diag', { recursive: true });
|
|
9
|
+
|
|
10
|
+
const lead = (a) => ({ alias: a, runtime: 'claude-code-cli' });
|
|
11
|
+
const dep = (a) => ({ alias: a, runtime: 'codex-sdk' });
|
|
12
|
+
const mem = (a) => ({ alias: a, runtime: 'claude-agent-sdk' });
|
|
13
|
+
const FLEET = [
|
|
14
|
+
lead('总指挥'), lead('副指挥A'), lead('副指挥B'),
|
|
15
|
+
[lead, dep, mem, mem, mem, mem].map((f, i) => f(['A站内容', 'A站评测', 'A站数据', 'A站设计', 'A站运营', 'A站工程'][i])),
|
|
16
|
+
[lead, dep, mem, mem, mem].map((f, i) => f(['B站产品', 'B站工程', 'B站测试', 'B站运维', 'B站运营'][i])),
|
|
17
|
+
[lead, dep, mem, mem].map((f, i) => f(['P站产品', 'P站工程', 'P站测试', 'P站运维'][i])),
|
|
18
|
+
[lead, dep, mem, mem].map((f, i) => f(['通信龙', '通信牛', '通信马', '通信SDK马'][i])),
|
|
19
|
+
['srv-a', 'srv-b', 'srv-c'].map(a => ({ alias: a, runtime: 'http-api', project_dir: '/home/v/agent-orchestra' })),
|
|
20
|
+
['群星马', '书生1号', '微信马', '飞书马', '独立节点', '研究员1号', '研究员2号', '游侠马'].map(a => mem(a)),
|
|
21
|
+
].flat();
|
|
22
|
+
|
|
23
|
+
const browser = await chromium.launch({ headless: true });
|
|
24
|
+
|
|
25
|
+
async function shot(layout) {
|
|
26
|
+
const ctx = await browser.newContext({ viewport: { width: 1280, height: 920 } });
|
|
27
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
28
|
+
await ctx.addInitScript((lay) => {
|
|
29
|
+
try {
|
|
30
|
+
localStorage.setItem('anet-theme', 'cyber');
|
|
31
|
+
localStorage.removeItem('anet-brand');
|
|
32
|
+
localStorage.removeItem('anet-topo-view');
|
|
33
|
+
localStorage.removeItem('anet-topo-nodescale');
|
|
34
|
+
localStorage.setItem('anet-topo-layout', lay);
|
|
35
|
+
sessionStorage.setItem('anet_v3_auth', '1');
|
|
36
|
+
} catch {}
|
|
37
|
+
}, layout);
|
|
38
|
+
await ctx.route('**/api/hub/status*', async (route) => {
|
|
39
|
+
const r = await route.fetch();
|
|
40
|
+
const b = await r.json();
|
|
41
|
+
const nid = (b.sessions || [])[0]?.network_id || 'default';
|
|
42
|
+
const sessions = FLEET.map((f, i) => ({
|
|
43
|
+
alias: f.alias, status: i % 5 === 0 ? 'working' : 'idle', network_id: nid,
|
|
44
|
+
project_dir: f.project_dir ?? null, runtime: f.runtime ?? null,
|
|
45
|
+
created_at: '2026-05-15T00:00:00Z', updated_at: '2026-05-15T00:00:00Z',
|
|
46
|
+
last_seen_at: new Date().toISOString(),
|
|
47
|
+
}));
|
|
48
|
+
await route.fulfill({ response: r, json: { ...b, sessions } });
|
|
49
|
+
});
|
|
50
|
+
await ctx.route('**/api/hub/tasks*', (route) => route.fulfill({ json: { tasks: [] } }));
|
|
51
|
+
const page = await ctx.newPage();
|
|
52
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
|
|
53
|
+
await page.waitForFunction(() => {
|
|
54
|
+
const svg = document.querySelector('svg[viewBox="0 0 1000 680"]');
|
|
55
|
+
return !!svg && svg.querySelectorAll('g[data-node]').length > 20;
|
|
56
|
+
}, { timeout: 30000 }).catch(() => {});
|
|
57
|
+
await page.waitForTimeout(1200);
|
|
58
|
+
await page.evaluate(() => {
|
|
59
|
+
const svg = document.querySelector('svg[viewBox="0 0 1000 680"]');
|
|
60
|
+
svg?.scrollIntoView({ behavior: 'instant', block: 'center' });
|
|
61
|
+
});
|
|
62
|
+
await page.waitForTimeout(500);
|
|
63
|
+
|
|
64
|
+
const facts = await page.evaluate(() => {
|
|
65
|
+
const svg = document.querySelector('svg[viewBox="0 0 1000 680"]');
|
|
66
|
+
const nodes = [...svg.querySelectorAll('g[data-node]')];
|
|
67
|
+
const sample = nodes.slice(0, 3).map(g => ({
|
|
68
|
+
alias: g.getAttribute('data-node'),
|
|
69
|
+
circles: g.querySelectorAll('circle').length,
|
|
70
|
+
images: g.querySelectorAll('image').length,
|
|
71
|
+
texts: g.querySelectorAll('text').length,
|
|
72
|
+
paths: g.querySelectorAll('path').length,
|
|
73
|
+
}));
|
|
74
|
+
const viewG = svg.querySelector('g[data-topo-viewport], g[transform*="scale"]');
|
|
75
|
+
const groups = svg.querySelectorAll('g[data-group]').length;
|
|
76
|
+
return {
|
|
77
|
+
nodeCount: nodes.length,
|
|
78
|
+
groupBoxes: groups,
|
|
79
|
+
viewportTransform: viewG ? viewG.getAttribute('transform') : null,
|
|
80
|
+
sample,
|
|
81
|
+
};
|
|
82
|
+
});
|
|
83
|
+
const svgEl = await page.$('svg[viewBox="0 0 1000 680"]');
|
|
84
|
+
await svgEl.screenshot({ path: `/tmp/anet-tree-diag/${layout}.png`, animations: 'disabled' });
|
|
85
|
+
await ctx.close();
|
|
86
|
+
return facts;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
for (const lay of ['grid', 'tree']) {
|
|
90
|
+
const f = await shot(lay);
|
|
91
|
+
console.log(`\n=== ${lay} ===`);
|
|
92
|
+
console.log(JSON.stringify(f, null, 2));
|
|
93
|
+
}
|
|
94
|
+
await browser.close();
|
|
95
|
+
console.log('\nscreenshots: /tmp/anet-tree-diag/{grid,tree}.png');
|