@sleep2agi/agent-network-dashboard 0.5.5-preview.0 → 0.5.5

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 (214) hide show
  1. package/.next/BUILD_ID +1 -1
  2. package/.next/app-path-routes-manifest.json +1 -0
  3. package/.next/build-manifest.json +3 -3
  4. package/.next/diagnostics/route-bundle-stats.json +60 -59
  5. package/.next/fallback-build-manifest.json +3 -3
  6. package/.next/prerender-manifest.json +24 -0
  7. package/.next/routes-manifest.json +6 -0
  8. package/.next/server/app/_global-error.html +1 -1
  9. package/.next/server/app/_global-error.rsc +1 -1
  10. package/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  11. package/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  12. package/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  13. package/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  14. package/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  15. package/.next/server/app/_not-found/page.js.nft.json +1 -1
  16. package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  17. package/.next/server/app/_not-found.html +2 -2
  18. package/.next/server/app/_not-found.rsc +12 -12
  19. package/.next/server/app/_not-found.segments/_full.segment.rsc +12 -12
  20. package/.next/server/app/_not-found.segments/_head.segment.rsc +4 -4
  21. package/.next/server/app/_not-found.segments/_index.segment.rsc +7 -7
  22. package/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +2 -2
  23. package/.next/server/app/_not-found.segments/_not-found.segment.rsc +3 -3
  24. package/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  25. package/.next/server/app/admin/page.js.nft.json +1 -1
  26. package/.next/server/app/admin/page_client-reference-manifest.js +1 -1
  27. package/.next/server/app/admin.html +2 -2
  28. package/.next/server/app/admin.rsc +14 -14
  29. package/.next/server/app/admin.segments/_full.segment.rsc +14 -14
  30. package/.next/server/app/admin.segments/_head.segment.rsc +4 -4
  31. package/.next/server/app/admin.segments/_index.segment.rsc +7 -7
  32. package/.next/server/app/admin.segments/_tree.segment.rsc +2 -2
  33. package/.next/server/app/admin.segments/admin/__PAGE__.segment.rsc +4 -4
  34. package/.next/server/app/admin.segments/admin.segment.rsc +3 -3
  35. package/.next/server/app/index.html +2 -2
  36. package/.next/server/app/index.rsc +14 -14
  37. package/.next/server/app/index.segments/__PAGE__.segment.rsc +4 -4
  38. package/.next/server/app/index.segments/_full.segment.rsc +14 -14
  39. package/.next/server/app/index.segments/_head.segment.rsc +4 -4
  40. package/.next/server/app/index.segments/_index.segment.rsc +7 -7
  41. package/.next/server/app/index.segments/_tree.segment.rsc +2 -2
  42. package/.next/server/app/login/page.js.nft.json +1 -1
  43. package/.next/server/app/login/page_client-reference-manifest.js +1 -1
  44. package/.next/server/app/login.html +2 -2
  45. package/.next/server/app/login.rsc +14 -14
  46. package/.next/server/app/login.segments/_full.segment.rsc +14 -14
  47. package/.next/server/app/login.segments/_head.segment.rsc +4 -4
  48. package/.next/server/app/login.segments/_index.segment.rsc +7 -7
  49. package/.next/server/app/login.segments/_tree.segment.rsc +2 -2
  50. package/.next/server/app/login.segments/login/__PAGE__.segment.rsc +4 -4
  51. package/.next/server/app/login.segments/login.segment.rsc +3 -3
  52. package/.next/server/app/logs/page.js.nft.json +1 -1
  53. package/.next/server/app/logs/page_client-reference-manifest.js +1 -1
  54. package/.next/server/app/logs.html +2 -2
  55. package/.next/server/app/logs.rsc +14 -14
  56. package/.next/server/app/logs.segments/_full.segment.rsc +14 -14
  57. package/.next/server/app/logs.segments/_head.segment.rsc +4 -4
  58. package/.next/server/app/logs.segments/_index.segment.rsc +7 -7
  59. package/.next/server/app/logs.segments/_tree.segment.rsc +2 -2
  60. package/.next/server/app/logs.segments/logs/__PAGE__.segment.rsc +4 -4
  61. package/.next/server/app/logs.segments/logs.segment.rsc +3 -3
  62. package/.next/server/app/messages/page.js.nft.json +1 -1
  63. package/.next/server/app/messages/page_client-reference-manifest.js +1 -1
  64. package/.next/server/app/messages.html +2 -2
  65. package/.next/server/app/messages.rsc +14 -14
  66. package/.next/server/app/messages.segments/_full.segment.rsc +14 -14
  67. package/.next/server/app/messages.segments/_head.segment.rsc +4 -4
  68. package/.next/server/app/messages.segments/_index.segment.rsc +7 -7
  69. package/.next/server/app/messages.segments/_tree.segment.rsc +2 -2
  70. package/.next/server/app/messages.segments/messages/__PAGE__.segment.rsc +4 -4
  71. package/.next/server/app/messages.segments/messages.segment.rsc +3 -3
  72. package/.next/server/app/node/page.js.nft.json +1 -1
  73. package/.next/server/app/node/page_client-reference-manifest.js +1 -1
  74. package/.next/server/app/node.html +2 -2
  75. package/.next/server/app/node.rsc +14 -14
  76. package/.next/server/app/node.segments/_full.segment.rsc +14 -14
  77. package/.next/server/app/node.segments/_head.segment.rsc +4 -4
  78. package/.next/server/app/node.segments/_index.segment.rsc +7 -7
  79. package/.next/server/app/node.segments/_tree.segment.rsc +2 -2
  80. package/.next/server/app/node.segments/node/__PAGE__.segment.rsc +4 -4
  81. package/.next/server/app/node.segments/node.segment.rsc +3 -3
  82. package/.next/server/app/nodes/page.js.nft.json +1 -1
  83. package/.next/server/app/nodes/page_client-reference-manifest.js +1 -1
  84. package/.next/server/app/nodes.html +2 -2
  85. package/.next/server/app/nodes.rsc +14 -14
  86. package/.next/server/app/nodes.segments/_full.segment.rsc +14 -14
  87. package/.next/server/app/nodes.segments/_head.segment.rsc +4 -4
  88. package/.next/server/app/nodes.segments/_index.segment.rsc +7 -7
  89. package/.next/server/app/nodes.segments/_tree.segment.rsc +2 -2
  90. package/.next/server/app/nodes.segments/nodes/__PAGE__.segment.rsc +4 -4
  91. package/.next/server/app/nodes.segments/nodes.segment.rsc +3 -3
  92. package/.next/server/app/page.js.nft.json +1 -1
  93. package/.next/server/app/page_client-reference-manifest.js +1 -1
  94. package/.next/server/app/server-logs/page.js.nft.json +1 -1
  95. package/.next/server/app/server-logs/page_client-reference-manifest.js +1 -1
  96. package/.next/server/app/server-logs.html +2 -2
  97. package/.next/server/app/server-logs.rsc +14 -14
  98. package/.next/server/app/server-logs.segments/_full.segment.rsc +14 -14
  99. package/.next/server/app/server-logs.segments/_head.segment.rsc +4 -4
  100. package/.next/server/app/server-logs.segments/_index.segment.rsc +7 -7
  101. package/.next/server/app/server-logs.segments/_tree.segment.rsc +2 -2
  102. package/.next/server/app/server-logs.segments/server-logs/__PAGE__.segment.rsc +4 -4
  103. package/.next/server/app/server-logs.segments/server-logs.segment.rsc +3 -3
  104. package/.next/server/app/servers/page/app-paths-manifest.json +3 -0
  105. package/.next/server/app/servers/page/build-manifest.json +17 -0
  106. package/.next/server/app/servers/page/next-font-manifest.json +10 -0
  107. package/.next/server/app/servers/page/react-loadable-manifest.json +1 -0
  108. package/.next/server/app/servers/page/server-reference-manifest.json +4 -0
  109. package/.next/server/app/servers/page.js +14 -0
  110. package/.next/server/app/servers/page.js.map +5 -0
  111. package/.next/server/app/servers/page.js.nft.json +1 -0
  112. package/.next/server/app/servers/page_client-reference-manifest.js +3 -0
  113. package/.next/server/app/servers.html +12 -0
  114. package/.next/server/app/servers.meta +15 -0
  115. package/.next/server/app/servers.rsc +24 -0
  116. package/.next/server/app/servers.segments/_full.segment.rsc +24 -0
  117. package/.next/server/app/servers.segments/_head.segment.rsc +6 -0
  118. package/.next/server/app/servers.segments/_index.segment.rsc +8 -0
  119. package/.next/server/app/servers.segments/_tree.segment.rsc +3 -0
  120. package/.next/server/app/servers.segments/servers/__PAGE__.segment.rsc +9 -0
  121. package/.next/server/app/servers.segments/servers.segment.rsc +5 -0
  122. package/.next/server/app/settings/networks/page.js.nft.json +1 -1
  123. package/.next/server/app/settings/networks/page_client-reference-manifest.js +1 -1
  124. package/.next/server/app/settings/networks.html +2 -2
  125. package/.next/server/app/settings/networks.rsc +14 -14
  126. package/.next/server/app/settings/networks.segments/_full.segment.rsc +14 -14
  127. package/.next/server/app/settings/networks.segments/_head.segment.rsc +4 -4
  128. package/.next/server/app/settings/networks.segments/_index.segment.rsc +7 -7
  129. package/.next/server/app/settings/networks.segments/_tree.segment.rsc +2 -2
  130. package/.next/server/app/settings/networks.segments/settings/networks/__PAGE__.segment.rsc +4 -4
  131. package/.next/server/app/settings/networks.segments/settings/networks.segment.rsc +3 -3
  132. package/.next/server/app/settings/networks.segments/settings.segment.rsc +3 -3
  133. package/.next/server/app/settings/page.js.nft.json +1 -1
  134. package/.next/server/app/settings/page_client-reference-manifest.js +1 -1
  135. package/.next/server/app/settings/tokens/page.js.nft.json +1 -1
  136. package/.next/server/app/settings/tokens/page_client-reference-manifest.js +1 -1
  137. package/.next/server/app/settings/tokens.html +2 -2
  138. package/.next/server/app/settings/tokens.rsc +14 -14
  139. package/.next/server/app/settings/tokens.segments/_full.segment.rsc +14 -14
  140. package/.next/server/app/settings/tokens.segments/_head.segment.rsc +4 -4
  141. package/.next/server/app/settings/tokens.segments/_index.segment.rsc +7 -7
  142. package/.next/server/app/settings/tokens.segments/_tree.segment.rsc +2 -2
  143. package/.next/server/app/settings/tokens.segments/settings/tokens/__PAGE__.segment.rsc +4 -4
  144. package/.next/server/app/settings/tokens.segments/settings/tokens.segment.rsc +3 -3
  145. package/.next/server/app/settings/tokens.segments/settings.segment.rsc +3 -3
  146. package/.next/server/app/settings.html +2 -2
  147. package/.next/server/app/settings.rsc +14 -14
  148. package/.next/server/app/settings.segments/_full.segment.rsc +14 -14
  149. package/.next/server/app/settings.segments/_head.segment.rsc +4 -4
  150. package/.next/server/app/settings.segments/_index.segment.rsc +7 -7
  151. package/.next/server/app/settings.segments/_tree.segment.rsc +2 -2
  152. package/.next/server/app/settings.segments/settings/__PAGE__.segment.rsc +4 -4
  153. package/.next/server/app/settings.segments/settings.segment.rsc +3 -3
  154. package/.next/server/app/tasks/[id]/page.js.nft.json +1 -1
  155. package/.next/server/app/tasks/[id]/page_client-reference-manifest.js +1 -1
  156. package/.next/server/app/tasks/page.js.nft.json +1 -1
  157. package/.next/server/app/tasks/page_client-reference-manifest.js +1 -1
  158. package/.next/server/app/tasks.html +2 -2
  159. package/.next/server/app/tasks.rsc +14 -14
  160. package/.next/server/app/tasks.segments/_full.segment.rsc +14 -14
  161. package/.next/server/app/tasks.segments/_head.segment.rsc +4 -4
  162. package/.next/server/app/tasks.segments/_index.segment.rsc +7 -7
  163. package/.next/server/app/tasks.segments/_tree.segment.rsc +2 -2
  164. package/.next/server/app/tasks.segments/tasks/__PAGE__.segment.rsc +4 -4
  165. package/.next/server/app/tasks.segments/tasks.segment.rsc +3 -3
  166. package/.next/server/app-paths-manifest.json +1 -0
  167. package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_10sgwq_.js +4 -0
  168. package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_10sgwq_.js.map +1 -0
  169. package/.next/server/chunks/ssr/[root-of-the-server]__0qylf1f._.js +3 -0
  170. package/.next/server/chunks/ssr/[root-of-the-server]__0qylf1f._.js.map +1 -0
  171. package/.next/server/chunks/ssr/[root-of-the-server]__0sv~g.o._.js +1 -1
  172. package/.next/server/chunks/ssr/[root-of-the-server]__0sv~g.o._.js.map +1 -1
  173. package/.next/server/chunks/ssr/[root-of-the-server]__11fu-5m._.js +3 -0
  174. package/.next/server/chunks/ssr/[root-of-the-server]__11fu-5m._.js.map +1 -0
  175. package/.next/server/chunks/ssr/agent-network-dashboard__next-internal_server_app_servers_page_actions_0mc5jn..js +3 -0
  176. package/.next/server/chunks/ssr/agent-network-dashboard__next-internal_server_app_servers_page_actions_0mc5jn..js.map +1 -0
  177. package/.next/server/chunks/ssr/agent-network-dashboard_app_01jhlxz._.js +1 -1
  178. package/.next/server/chunks/ssr/agent-network-dashboard_app_01jhlxz._.js.map +1 -1
  179. package/.next/server/chunks/ssr/agent-network-dashboard_app_09d29my._.js +1 -1
  180. package/.next/server/chunks/ssr/agent-network-dashboard_app_09d29my._.js.map +1 -1
  181. package/.next/server/chunks/ssr/agent-network-dashboard_app_components_0mvyi-4._.js +2 -2
  182. package/.next/server/chunks/ssr/agent-network-dashboard_app_components_0mvyi-4._.js.map +1 -1
  183. package/.next/server/chunks/ssr/agent-network-dashboard_app_servers_page_tsx_0jib5qm._.js +3 -0
  184. package/.next/server/chunks/ssr/agent-network-dashboard_app_servers_page_tsx_0jib5qm._.js.map +1 -0
  185. package/.next/server/middleware-build-manifest.js +3 -3
  186. package/.next/server/next-font-manifest.js +1 -1
  187. package/.next/server/next-font-manifest.json +3 -0
  188. package/.next/server/pages/404.html +2 -2
  189. package/.next/server/pages/500.html +1 -1
  190. package/.next/static/chunks/0ae8hatsa667~.js +1 -0
  191. package/.next/static/chunks/{0lc4e9o91uv.n.js → 0iwava1u7a3b4.js} +2 -2
  192. package/.next/static/chunks/0l4_5zb9iglew.css +2 -0
  193. package/.next/static/chunks/0nl95yu28e23u.js +1 -0
  194. package/.next/static/chunks/0qwqp6ulyj3o6.js +1 -0
  195. package/.next/static/chunks/{0qvb.hq86qp2g.js → 10w8tnv76~n~d.js} +1 -1
  196. package/.next/static/chunks/13yktdzuatx3d.js +1 -0
  197. package/.next/trace +2 -2
  198. package/.next/trace-build +1 -1
  199. package/.next/types/routes.d.ts +2 -1
  200. package/.next/types/validator.ts +9 -0
  201. package/app/components/ServersDrawer.tsx +170 -158
  202. package/app/components/Sidebar.tsx +1 -0
  203. package/app/servers/page.tsx +30 -0
  204. package/package.json +1 -1
  205. package/.next/server/chunks/ssr/[root-of-the-server]__0p-95r_._.js +0 -3
  206. package/.next/server/chunks/ssr/[root-of-the-server]__0p-95r_._.js.map +0 -1
  207. package/.next/static/chunks/0grmy4z.ylqtd.css +0 -2
  208. package/.next/static/chunks/0k68tvhf0o-sb.js +0 -1
  209. package/.next/static/chunks/0ku0fjqlm9mca.js +0 -1
  210. package/.next/static/chunks/0prdn66k~zu45.js +0 -1
  211. package/.next/static/chunks/0tvn2l1pc.h65.js +0 -1
  212. /package/.next/static/{7CjN6e7QM2eogH8RhsM1k → 98KrCVirJEwsHwoGr5TCX}/_buildManifest.js +0 -0
  213. /package/.next/static/{7CjN6e7QM2eogH8RhsM1k → 98KrCVirJEwsHwoGr5TCX}/_clientMiddlewareManifest.js +0 -0
  214. /package/.next/static/{7CjN6e7QM2eogH8RhsM1k → 98KrCVirJEwsHwoGr5TCX}/_ssgManifest.js +0 -0
@@ -195,27 +195,27 @@ function AgentList({ agents }: { agents?: ServerAgent[] }) {
195
195
  );
196
196
  }
197
197
 
198
- export function ServersDrawer() {
199
- const [open, setOpen] = useState(false);
200
- /** v0.10.0 Hero 1+2 — per-server expanded state for detail card
201
- * (sparklines + disk bar + agent rollup). Stored as a Set of
202
- * hostnames; persists in localStorage so the user's last selection
203
- * survives reload. Independent of the drawer's open/close state. */
198
+ function useServers(enabled = true) {
199
+ const { data, error } = useSWR<ServersResponse>(
200
+ enabled ? '/api/hub/servers' : null,
201
+ fetcher,
202
+ { refreshInterval: 5000, dedupingInterval: 3000 },
203
+ );
204
+ const servers = data?.servers ?? [];
205
+ const unavailable = data?.unavailable === true;
206
+ const onlineCount = servers.filter(s => s.status === 'online').length;
207
+ const loading = enabled && !data && !error;
208
+ return { data, error, servers, unavailable, onlineCount, loading };
209
+ }
210
+
211
+ export function ServersPanel({ enabled = true, className = '' }: { enabled?: boolean; className?: string }) {
204
212
  const [expanded, setExpanded] = useState<Set<string>>(new Set());
205
- // Drawer state is per-user-machine — persist like the other dashboard
206
- // sticky toggles (`anet-topo-layout`, `anet-topo-view`, etc.).
207
213
  useEffect(() => {
208
- try { if (localStorage.getItem('anet-servers-drawer') === '1') setOpen(true); } catch {}
209
214
  try {
210
215
  const raw = localStorage.getItem('anet-servers-drawer-expanded');
211
216
  if (raw) setExpanded(new Set(JSON.parse(raw)));
212
217
  } catch {}
213
218
  }, []);
214
- const toggle = () => setOpen(prev => {
215
- const next = !prev;
216
- try { localStorage.setItem('anet-servers-drawer', next ? '1' : '0'); } catch {}
217
- return next;
218
- });
219
219
  const toggleExpanded = (hostname: string) => setExpanded(prev => {
220
220
  const next = new Set(prev);
221
221
  if (next.has(hostname)) next.delete(hostname); else next.add(hostname);
@@ -223,19 +223,165 @@ export function ServersDrawer() {
223
223
  return next;
224
224
  });
225
225
 
226
+ const { data, error, servers, unavailable, loading } = useServers(enabled);
227
+
228
+ return (
229
+ <div className={`min-h-0 overflow-y-auto px-2 py-2 space-y-2 ${className}`} data-servers-body>
230
+ {loading && (
231
+ <div className="text-[10px] text-[var(--fg-muted)] font-mono text-center py-4">
232
+ loading servers…
233
+ </div>
234
+ )}
235
+ {error && !data && (
236
+ <div className="rounded-md border px-2.5 py-2 text-[10px] font-mono"
237
+ style={{ background: 'rgb(239 68 68 / 0.06)', borderColor: 'rgb(239 68 68 / 0.25)', color: '#ef4444' }}>
238
+ hub unreachable · retrying every 5s
239
+ </div>
240
+ )}
241
+ {unavailable && (
242
+ <div className="text-[10px] text-[var(--fg-muted)] font-mono text-center py-3 leading-relaxed">
243
+ host telemetry not available<br/>
244
+ <span className="text-[var(--fg-dim)]">upgrade commhub-server ≥ 0.8.1-preview.2</span>
245
+ </div>
246
+ )}
247
+ {!loading && !error && !unavailable && servers.length === 0 && (
248
+ <div className="text-[10px] text-[var(--fg-muted)] font-mono text-center py-4">
249
+ no servers reporting yet
250
+ </div>
251
+ )}
252
+ {servers.map(s => {
253
+ const offline = s.status === 'offline';
254
+ const cpuPct = s.cpu_load_1min != null && s.cpu_cores > 0 ? (s.cpu_load_1min / s.cpu_cores) * 100 : null;
255
+ 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;
256
+ 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;
257
+ const isExpanded = expanded.has(s.hostname);
258
+ return (
259
+ <div
260
+ key={s.hostname}
261
+ className="rounded-lg border px-2.5 py-2 space-y-1.5"
262
+ style={{
263
+ background: 'var(--bg)',
264
+ borderColor: 'var(--border)',
265
+ opacity: offline ? 0.55 : 1,
266
+ }}
267
+ data-server-card={s.hostname}
268
+ data-server-expanded={isExpanded ? 'true' : 'false'}
269
+ title={s.ip ? `${s.hostname} · ${s.ip}` : s.hostname}
270
+ >
271
+ {/* v0.10.0 Hero 1+2: header row — click toggles expanded
272
+ detail view (sparklines + disk + agent rollup). */}
273
+ <button
274
+ type="button"
275
+ onClick={() => toggleExpanded(s.hostname)}
276
+ aria-expanded={isExpanded}
277
+ className="w-full flex items-center justify-between gap-2 text-left"
278
+ data-server-card-toggle={s.hostname}
279
+ >
280
+ <div className="min-w-0 flex items-center gap-1.5">
281
+ {/* Hero 1 health badge — worst-of CPU/Mem/Disk */}
282
+ {!offline && <HealthBadge cpu={cpuPct} mem={memPct} disk={diskPct} />}
283
+ <span className="font-mono text-[12px] font-semibold truncate" style={{ color: 'var(--fg)' }}>{s.hostname}</span>
284
+ {s.note && <span className="text-[9px] text-[var(--fg-dim)]">({s.note})</span>}
285
+ </div>
286
+ <span className="flex items-center gap-1 shrink-0">
287
+ <span className="text-[10px] text-[var(--fg-muted)] font-mono tabular-nums">
288
+ {s.agent_count}&nbsp;agent{s.agent_count === 1 ? '' : 's'}
289
+ </span>
290
+ {/* Chevron — rotates 90° on expanded */}
291
+ <svg
292
+ width="10" height="10" viewBox="0 0 10 10"
293
+ style={{ transform: isExpanded ? 'rotate(90deg)' : 'rotate(0deg)', transition: 'transform 150ms ease-out' }}
294
+ aria-hidden
295
+ >
296
+ <path d="M3 1.5L7 5L3 8.5" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
297
+ </svg>
298
+ </span>
299
+ </button>
300
+ {!offline && cpuPct != null && (
301
+ <Bar pct={cpuPct} label={`CPU ${s.cpu_load_1min!.toFixed(2)}/${s.cpu_cores}`} />
302
+ )}
303
+ {!offline && memPct != null && (
304
+ <Bar pct={memPct} label={`RAM ${s.mem_used_gb!.toFixed(1)}/${s.mem_total_gb!.toFixed(1)}G`} />
305
+ )}
306
+ {offline && (
307
+ <div className="text-[10px] text-[var(--fg-dim)] font-mono italic">CPU n/a · RAM n/a · offline</div>
308
+ )}
309
+ {/* v0.10.0 Hero 1+2: expanded detail — disk bar +
310
+ 5-min sparklines + agent rollup. Visible only when
311
+ the user clicks the card. Renders gracefully when
312
+ upstream hub hasn't shipped optional fields. */}
313
+ {isExpanded && !offline && (
314
+ <div className="pt-1 mt-1 border-t space-y-1.5" style={{ borderColor: 'var(--border)' }}>
315
+ {diskPct != null ? (
316
+ <Bar pct={diskPct} label={`DISK ${s.disk_used_gb!.toFixed(1)}/${s.disk_total_gb!.toFixed(1)}G`} />
317
+ ) : (
318
+ /* #157 sibling fix — same misleading version-pin copy
319
+ dropped at the disk-metric placeholder. Same
320
+ rationale as the agent-rollup copy above. */
321
+ <div className="text-[9px] text-[var(--fg-dim)] font-mono italic" data-server-disk-missing="true">disk metric not reported by hub</div>
322
+ )}
323
+ {s.cpu_history && s.cpu_history.length >= 2 && (
324
+ <div className="space-y-0.5">
325
+ <div className="text-[9px] text-[var(--fg-muted)] font-mono">CPU · 5-min</div>
326
+ <Sparkline values={s.cpu_history} tint="#10b981" label="CPU" />
327
+ </div>
328
+ )}
329
+ {s.mem_history && s.mem_history.length >= 2 && (
330
+ <div className="space-y-0.5">
331
+ <div className="text-[9px] text-[var(--fg-muted)] font-mono">RAM · 5-min</div>
332
+ <Sparkline values={s.mem_history} tint="#06b6d4" label="MEM" />
333
+ </div>
334
+ )}
335
+ {/* v0.10.2 RFC-014 §7 close gate #3 — disk usage
336
+ 5-min curve. Amber tint matches the disk bar
337
+ tier convention (DISK > CPU/Mem in alert-
338
+ priority hierarchy since disk-full is a hard
339
+ failure mode). Render only when agent-node
340
+ 2.4.1-preview.0+ has shipped disk_history;
341
+ backward-compat handles older agents silently
342
+ (no sparkline, no broken state). */}
343
+ {s.disk_history && s.disk_history.length >= 2 && (
344
+ <div className="space-y-0.5">
345
+ <div className="text-[9px] text-[var(--fg-muted)] font-mono">DISK · 5-min</div>
346
+ <Sparkline values={s.disk_history} tint="#f59e0b" label="DISK" />
347
+ </div>
348
+ )}
349
+ <div className="pt-1">
350
+ <div className="text-[9px] text-[var(--fg-muted)] font-mono mb-0.5">agents</div>
351
+ <AgentList agents={s.agents} />
352
+ </div>
353
+ </div>
354
+ )}
355
+ </div>
356
+ );
357
+ })}
358
+ {servers.length > 0 && (
359
+ <div className="pt-1 text-[9px] text-[var(--fg-dim)] font-mono text-center">
360
+ live · refreshing every 5s
361
+ </div>
362
+ )}
363
+ </div>
364
+ );
365
+ }
366
+
367
+ export function ServersDrawer() {
368
+ const [open, setOpen] = useState(false);
369
+ // Drawer state is per-user-machine — persist like the other dashboard
370
+ // sticky toggles (`anet-topo-layout`, `anet-topo-view`, etc.).
371
+ useEffect(() => {
372
+ try { if (localStorage.getItem('anet-servers-drawer') === '1') setOpen(true); } catch {}
373
+ }, []);
374
+ const toggle = () => setOpen(prev => {
375
+ const next = !prev;
376
+ try { localStorage.setItem('anet-servers-drawer', next ? '1' : '0'); } catch {}
377
+ return next;
378
+ });
379
+
226
380
  // Round 20 / #119 step 3 final delivery — real SWR fetch. 5s refresh
227
381
  // matches the other live drawers (HealthBanner, Sidebar) so an operator
228
382
  // sees host telemetry update in roughly the same beat as session state.
229
383
  // Only poll while expanded — collapsed icon strip doesn't need fresh data.
230
- const { data, error } = useSWR<ServersResponse>(
231
- open ? '/api/hub/servers' : null,
232
- fetcher,
233
- { refreshInterval: 5000, dedupingInterval: 3000 },
234
- );
235
- const servers = data?.servers ?? [];
236
- const unavailable = data?.unavailable === true;
237
- const onlineCount = servers.filter(s => s.status === 'online').length;
238
- const loading = open && !data && !error;
384
+ const { servers, onlineCount } = useServers(open);
239
385
 
240
386
  return (
241
387
  <aside
@@ -271,141 +417,7 @@ export function ServersDrawer() {
271
417
  </button>
272
418
 
273
419
  {open && (
274
- <div className="flex-1 min-h-0 overflow-y-auto px-2 py-2 space-y-2" data-servers-body>
275
- {loading && (
276
- <div className="text-[10px] text-[var(--fg-muted)] font-mono text-center py-4">
277
- loading servers…
278
- </div>
279
- )}
280
- {error && !data && (
281
- <div className="rounded-md border px-2.5 py-2 text-[10px] font-mono"
282
- style={{ background: 'rgb(239 68 68 / 0.06)', borderColor: 'rgb(239 68 68 / 0.25)', color: '#ef4444' }}>
283
- hub unreachable · retrying every 5s
284
- </div>
285
- )}
286
- {unavailable && (
287
- <div className="text-[10px] text-[var(--fg-muted)] font-mono text-center py-3 leading-relaxed">
288
- host telemetry not available<br/>
289
- <span className="text-[var(--fg-dim)]">upgrade commhub-server ≥ 0.8.1-preview.2</span>
290
- </div>
291
- )}
292
- {!loading && !error && !unavailable && servers.length === 0 && (
293
- <div className="text-[10px] text-[var(--fg-muted)] font-mono text-center py-4">
294
- no servers reporting yet
295
- </div>
296
- )}
297
- {servers.map(s => {
298
- const offline = s.status === 'offline';
299
- const cpuPct = s.cpu_load_1min != null && s.cpu_cores > 0 ? (s.cpu_load_1min / s.cpu_cores) * 100 : null;
300
- 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;
301
- 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;
302
- const isExpanded = expanded.has(s.hostname);
303
- return (
304
- <div
305
- key={s.hostname}
306
- className="rounded-lg border px-2.5 py-2 space-y-1.5"
307
- style={{
308
- background: 'var(--bg)',
309
- borderColor: 'var(--border)',
310
- opacity: offline ? 0.55 : 1,
311
- }}
312
- data-server-card={s.hostname}
313
- data-server-expanded={isExpanded ? 'true' : 'false'}
314
- title={s.ip ? `${s.hostname} · ${s.ip}` : s.hostname}
315
- >
316
- {/* v0.10.0 Hero 1+2: header row — click toggles expanded
317
- detail view (sparklines + disk + agent rollup). */}
318
- <button
319
- type="button"
320
- onClick={() => toggleExpanded(s.hostname)}
321
- aria-expanded={isExpanded}
322
- className="w-full flex items-center justify-between gap-2 text-left"
323
- data-server-card-toggle={s.hostname}
324
- >
325
- <div className="min-w-0 flex items-center gap-1.5">
326
- {/* Hero 1 health badge — worst-of CPU/Mem/Disk */}
327
- {!offline && <HealthBadge cpu={cpuPct} mem={memPct} disk={diskPct} />}
328
- <span className="font-mono text-[12px] font-semibold truncate" style={{ color: 'var(--fg)' }}>{s.hostname}</span>
329
- {s.note && <span className="text-[9px] text-[var(--fg-dim)]">({s.note})</span>}
330
- </div>
331
- <span className="flex items-center gap-1 shrink-0">
332
- <span className="text-[10px] text-[var(--fg-muted)] font-mono tabular-nums">
333
- {s.agent_count}&nbsp;agent{s.agent_count === 1 ? '' : 's'}
334
- </span>
335
- {/* Chevron — rotates 90° on expanded */}
336
- <svg
337
- width="10" height="10" viewBox="0 0 10 10"
338
- style={{ transform: isExpanded ? 'rotate(90deg)' : 'rotate(0deg)', transition: 'transform 150ms ease-out' }}
339
- aria-hidden
340
- >
341
- <path d="M3 1.5L7 5L3 8.5" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
342
- </svg>
343
- </span>
344
- </button>
345
- {!offline && cpuPct != null && (
346
- <Bar pct={cpuPct} label={`CPU ${s.cpu_load_1min!.toFixed(2)}/${s.cpu_cores}`} />
347
- )}
348
- {!offline && memPct != null && (
349
- <Bar pct={memPct} label={`RAM ${s.mem_used_gb!.toFixed(1)}/${s.mem_total_gb!.toFixed(1)}G`} />
350
- )}
351
- {offline && (
352
- <div className="text-[10px] text-[var(--fg-dim)] font-mono italic">CPU n/a · RAM n/a · offline</div>
353
- )}
354
- {/* v0.10.0 Hero 1+2: expanded detail — disk bar +
355
- 5-min sparklines + agent rollup. Visible only when
356
- the user clicks the card. Renders gracefully when
357
- upstream hub hasn't shipped optional fields. */}
358
- {isExpanded && !offline && (
359
- <div className="pt-1 mt-1 border-t space-y-1.5" style={{ borderColor: 'var(--border)' }}>
360
- {diskPct != null ? (
361
- <Bar pct={diskPct} label={`DISK ${s.disk_used_gb!.toFixed(1)}/${s.disk_total_gb!.toFixed(1)}G`} />
362
- ) : (
363
- /* #157 sibling fix — same misleading version-pin copy
364
- dropped at the disk-metric placeholder. Same
365
- rationale as the agent-rollup copy above. */
366
- <div className="text-[9px] text-[var(--fg-dim)] font-mono italic" data-server-disk-missing="true">disk metric not reported by hub</div>
367
- )}
368
- {s.cpu_history && s.cpu_history.length >= 2 && (
369
- <div className="space-y-0.5">
370
- <div className="text-[9px] text-[var(--fg-muted)] font-mono">CPU · 5-min</div>
371
- <Sparkline values={s.cpu_history} tint="#10b981" label="CPU" />
372
- </div>
373
- )}
374
- {s.mem_history && s.mem_history.length >= 2 && (
375
- <div className="space-y-0.5">
376
- <div className="text-[9px] text-[var(--fg-muted)] font-mono">RAM · 5-min</div>
377
- <Sparkline values={s.mem_history} tint="#06b6d4" label="MEM" />
378
- </div>
379
- )}
380
- {/* v0.10.2 RFC-014 §7 close gate #3 — disk usage
381
- 5-min curve. Amber tint matches the disk bar
382
- tier convention (DISK > CPU/Mem in alert-
383
- priority hierarchy since disk-full is a hard
384
- failure mode). Render only when agent-node
385
- 2.4.1-preview.0+ has shipped disk_history;
386
- backward-compat handles older agents silently
387
- (no sparkline, no broken state). */}
388
- {s.disk_history && s.disk_history.length >= 2 && (
389
- <div className="space-y-0.5">
390
- <div className="text-[9px] text-[var(--fg-muted)] font-mono">DISK · 5-min</div>
391
- <Sparkline values={s.disk_history} tint="#f59e0b" label="DISK" />
392
- </div>
393
- )}
394
- <div className="pt-1">
395
- <div className="text-[9px] text-[var(--fg-muted)] font-mono mb-0.5">agents</div>
396
- <AgentList agents={s.agents} />
397
- </div>
398
- </div>
399
- )}
400
- </div>
401
- );
402
- })}
403
- {servers.length > 0 && (
404
- <div className="pt-1 text-[9px] text-[var(--fg-dim)] font-mono text-center">
405
- live · refreshing every 5s
406
- </div>
407
- )}
408
- </div>
420
+ <ServersPanel enabled={open} className="flex-1" />
409
421
  )}
410
422
  </aside>
411
423
  );
@@ -13,6 +13,7 @@ const NAV_ITEMS = [
13
13
  { href: '/', label: 'Overview', icon: 'M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6' },
14
14
  { href: '/tasks', label: 'Tasks', icon: 'M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4' },
15
15
  { href: '/nodes', label: 'Nodes', icon: 'M5 12h14M5 12a2 2 0 01-2-2V6a2 2 0 012-2h14a2 2 0 012 2v4a2 2 0 01-2 2M5 12a2 2 0 00-2 2v4a2 2 0 002 2h14a2 2 0 002-2v-4a2 2 0 00-2-2m-2-4h.01M17 16h.01' },
16
+ { href: '/servers', label: 'Servers', icon: 'M4 6.5A2.5 2.5 0 016.5 4h11A2.5 2.5 0 0120 6.5v1A2.5 2.5 0 0117.5 10h-11A2.5 2.5 0 014 7.5v-1zM4 16.5A2.5 2.5 0 016.5 14h11a2.5 2.5 0 012.5 2.5v1a2.5 2.5 0 01-2.5 2.5h-11A2.5 2.5 0 014 17.5v-1zM7 7h.01M7 17h.01' },
16
17
  { href: '/messages', label: 'Messages', icon: 'M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z' },
17
18
  { href: '/settings/networks', label: 'Networks', icon: 'M21 12a9 9 0 01-9 9m9-9a9 9 0 00-9-9m9 9H3m9 9a9 9 0 01-9-9m9 9c1.657 0 3-4.03 3-9s-1.343-9-3-9m0 18c-1.657 0-3-4.03-3-9s1.343-9 3-9m-9 9a9 9 0 019-9' },
18
19
  { href: '/logs', label: 'Audit Log', icon: 'M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z' },
@@ -0,0 +1,30 @@
1
+ 'use client';
2
+
3
+ import { ServersPanel } from '../components/ServersDrawer';
4
+
5
+ export default function ServersPage() {
6
+ return (
7
+ <main className="min-h-screen bg-[#0a0a1a] px-4 py-5 text-gray-100 sm:px-6 lg:px-8">
8
+ <div className="mx-auto max-w-5xl space-y-5">
9
+ <header className="rounded-2xl border border-[#2a2a4a] bg-[#111128] p-5 shadow-lg shadow-black/20">
10
+ <div className="flex flex-col gap-3 sm:flex-row sm:items-end sm:justify-between">
11
+ <div>
12
+ <p className="text-[11px] uppercase tracking-[0.18em] text-cyan-300/70">Infrastructure</p>
13
+ <h1 className="mt-2 text-2xl font-semibold text-white">Servers</h1>
14
+ <p className="mt-2 max-w-2xl text-sm leading-6 text-gray-400">
15
+ Host-level health, disk, memory, CPU history, and agent rollups from CommHub telemetry.
16
+ </p>
17
+ </div>
18
+ <div className="rounded-xl border border-cyan-500/20 bg-cyan-500/10 px-3 py-2 text-xs font-mono text-cyan-200">
19
+ live · refreshes every 5s
20
+ </div>
21
+ </div>
22
+ </header>
23
+
24
+ <section className="rounded-2xl border border-[#2a2a4a] bg-[#111128] p-3 shadow-lg shadow-black/20">
25
+ <ServersPanel className="max-h-none overflow-visible" />
26
+ </section>
27
+ </div>
28
+ </main>
29
+ );
30
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sleep2agi/agent-network-dashboard",
3
- "version": "0.5.5-preview.0",
3
+ "version": "0.5.5",
4
4
  "description": "Agent Network Dashboard — Web UI for managing AI Agent networks",
5
5
  "scripts": {
6
6
  "dev": "next dev",
@@ -1,3 +0,0 @@
1
- module.exports=[18622,(a,b,c)=>{b.exports=a.x("next/dist/compiled/next-server/app-page-turbo.runtime.prod.js",()=>require("next/dist/compiled/next-server/app-page-turbo.runtime.prod.js"))},56704,(a,b,c)=>{b.exports=a.x("next/dist/server/app-render/work-async-storage.external.js",()=>require("next/dist/server/app-render/work-async-storage.external.js"))},32319,(a,b,c)=>{b.exports=a.x("next/dist/server/app-render/work-unit-async-storage.external.js",()=>require("next/dist/server/app-render/work-unit-async-storage.external.js"))},24725,(a,b,c)=>{b.exports=a.x("next/dist/server/app-render/after-task-async-storage.external.js",()=>require("next/dist/server/app-render/after-task-async-storage.external.js"))},20635,(a,b,c)=>{b.exports=a.x("next/dist/server/app-render/action-async-storage.external.js",()=>require("next/dist/server/app-render/action-async-storage.external.js"))},43285,(a,b,c)=>{b.exports=a.x("next/dist/server/app-render/dynamic-access-async-storage.external.js",()=>require("next/dist/server/app-render/dynamic-access-async-storage.external.js"))},63535,(a,b,c)=>{"use strict";b.exports=a.r(18622)},64247,(a,b,c)=>{"use strict";b.exports=a.r(63535).vendored["react-ssr"].ReactJsxRuntime},54413,(a,b,c)=>{"use strict";b.exports=a.r(63535).vendored["react-ssr"].React},19080,(a,b,c)=>{"use strict";b.exports=a.r(63535).vendored.contexts.AppRouterContext},91078,(a,b,c)=>{"use strict";b.exports=a.r(63535).vendored["react-ssr"].ReactServerDOMTurbopackClient},63502,(a,b,c)=>{"use strict";b.exports=a.r(63535).vendored.contexts.HooksClientContext},21672,(a,b,c)=>{"use strict";b.exports=a.r(63535).vendored.contexts.ServerInsertedHtml},59202,a=>{"use strict";var b=a.i(64247),c=a.i(54413);let d=(0,c.createContext)({networkId:"",setNetworkId:()=>{}});a.s(["NetworkProvider",0,function({children:a}){let[e,f]=(0,c.useState)("");return(0,c.useEffect)(()=>{let a=sessionStorage.getItem("anet_network_id");a&&f(a)},[]),(0,b.jsx)(d.Provider,{value:{networkId:e,setNetworkId:a=>{f(a),sessionStorage.setItem("anet_network_id",a)}},children:a})},"useNetworkId",0,function(){return(0,c.useContext)(d)}])}];
2
-
3
- //# sourceMappingURL=%5Broot-of-the-server%5D__0p-95r_._.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../../../../agent-network-dashboard/node_modules/next/src/server/route-modules/app-page/module.compiled.js","../../../../../agent-network-dashboard/node_modules/next/src/server/route-modules/app-page/vendored/ssr/react-jsx-runtime.ts","../../../../../agent-network-dashboard/node_modules/next/src/server/route-modules/app-page/vendored/ssr/react.ts","../../../../../agent-network-dashboard/node_modules/next/src/server/route-modules/app-page/vendored/contexts/app-router-context.ts","../../../../../agent-network-dashboard/node_modules/next/src/server/route-modules/app-page/vendored/ssr/react-server-dom-turbopack-client.ts","../../../../../agent-network-dashboard/node_modules/next/src/server/route-modules/app-page/vendored/contexts/hooks-client-context.ts","../../../../../agent-network-dashboard/node_modules/next/src/server/route-modules/app-page/vendored/contexts/server-inserted-html.ts","../../../../../agent-network-dashboard/app/lib/network-context.tsx"],"sourcesContent":["if (process.env.NEXT_RUNTIME === 'edge') {\n module.exports = require('next/dist/server/route-modules/app-page/module.js')\n} else {\n if (process.env.__NEXT_EXPERIMENTAL_REACT) {\n if (process.env.NODE_ENV === 'development') {\n if (process.env.TURBOPACK) {\n module.exports = require('next/dist/compiled/next-server/app-page-turbo-experimental.runtime.dev.js')\n } else {\n module.exports = require('next/dist/compiled/next-server/app-page-experimental.runtime.dev.js')\n }\n } else {\n if (process.env.TURBOPACK) {\n module.exports = require('next/dist/compiled/next-server/app-page-turbo-experimental.runtime.prod.js')\n } else {\n module.exports = require('next/dist/compiled/next-server/app-page-experimental.runtime.prod.js')\n }\n }\n } else {\n if (process.env.NODE_ENV === 'development') {\n if (process.env.TURBOPACK) {\n module.exports = require('next/dist/compiled/next-server/app-page-turbo.runtime.dev.js')\n } else {\n module.exports = require('next/dist/compiled/next-server/app-page.runtime.dev.js')\n }\n } else {\n if (process.env.TURBOPACK) {\n module.exports = require('next/dist/compiled/next-server/app-page-turbo.runtime.prod.js')\n } else {\n module.exports = require('next/dist/compiled/next-server/app-page.runtime.prod.js')\n }\n }\n }\n}\n","module.exports = (\n require('../../module.compiled') as typeof import('../../module.compiled')\n).vendored['react-ssr']!.ReactJsxRuntime\n","module.exports = (\n require('../../module.compiled') as typeof import('../../module.compiled')\n).vendored['react-ssr']!.React\n","module.exports = (\n require('../../module.compiled') as typeof import('../../module.compiled')\n).vendored['contexts'].AppRouterContext\n","module.exports = (\n require('../../module.compiled') as typeof import('../../module.compiled')\n).vendored['react-ssr']!.ReactServerDOMTurbopackClient\n","module.exports = (\n require('../../module.compiled') as typeof import('../../module.compiled')\n).vendored['contexts'].HooksClientContext\n","module.exports = (\n require('../../module.compiled') as typeof import('../../module.compiled')\n).vendored['contexts'].ServerInsertedHtml\n","'use client';\n\nimport { createContext, useContext, useState, useEffect, ReactNode } from 'react';\n\ninterface NetworkContextType {\n networkId: string;\n setNetworkId: (id: string) => void;\n}\n\nconst NetworkContext = createContext<NetworkContextType>({ networkId: '', setNetworkId: () => {} });\n\nexport function NetworkProvider({ children }: { children: ReactNode }) {\n const [networkId, setNetworkId] = useState('');\n\n useEffect(() => {\n const saved = sessionStorage.getItem('anet_network_id');\n if (saved) setNetworkId(saved);\n }, []);\n\n const setAndPersist = (id: string) => {\n setNetworkId(id);\n sessionStorage.setItem('anet_network_id', id);\n };\n\n return (\n <NetworkContext.Provider value={{ networkId, setNetworkId: setAndPersist }}>\n {children}\n </NetworkContext.Provider>\n );\n}\n\nexport function useNetworkId() {\n return useContext(NetworkContext);\n}\n"],"names":["process","env","NEXT_RUNTIME","module","exports","require","__NEXT_EXPERIMENTAL_REACT","NODE_ENV","TURBOPACK","vendored","ReactJsxRuntime","React","AppRouterContext","ReactServerDOMTurbopackClient","HooksClientContext","ServerInsertedHtml","NetworkContext","networkId","setNetworkId","NetworkProvider","children","saved","sessionStorage","getItem","setAndPersist","id","setItem","Provider","value","useNetworkId"],"mappings":"2kCA0BQG,EAAOC,OAAO,CAAGC,EAAQ,CAAA,CAAA,IAAA,iCC1BjCF,EAAOC,OAAO,CACZC,EAAQ,CAAA,CAAA,IAAA,GACRI,QAAQ,CAAC,YAAY,CAAEC,eAAe,+BCFxCP,EAAOC,OAAO,CACZC,EAAQ,CAAA,CAAA,IAAA,GACRI,QAAQ,CAAC,YAAY,CAAEE,KAAK,+BCF9BR,EAAOC,OAAO,CACZC,EAAQ,CAAA,CAAA,IAAA,GACRI,QAAQ,CAAC,QAAW,CAACG,gBAAgB,+BCFvCT,EAAOC,OAAO,CACZC,EAAQ,CAAA,CAAA,IAAA,GACRI,QAAQ,CAAC,YAAY,CAAEI,6BAA6B,+BCFtDV,EAAOC,OAAO,CACZC,EAAQ,CAAA,CAAA,IAAA,GACRI,QAAQ,CAAC,QAAW,CAACK,kBAAkB,+BCFzCX,EAAOC,OAAO,CACZC,EAAQ,CAAA,CAAA,IAAA,GACRI,QAAQ,CAAC,QAAW,CAACM,kBAAkB,0CCAzC,EAAA,EAAA,CAAA,CAAA,OAOA,IAAMC,EAAiB,CAAA,EAAA,EAAA,aAAA,AAAa,EAAqB,CAAEC,UAAW,GAAIC,aAAc,KAAO,CAAE,4BAE1F,SAASC,AAAgB,UAAEC,CAAQ,CAA2B,EACnE,GAAM,CAACH,EAAWC,EAAa,CAAG,CAAA,EAAA,EAAA,QAAA,AAAQ,EAAC,UAE3C,CAAA,EAAA,EAAA,SAAS,AAAT,EAAU,KACR,IAAMG,EAAQC,eAAeC,OAAO,CAAC,mBACjCF,GAAOH,EAAaG,EAC1B,EAAG,EAAE,EAQH,CAAA,EAAA,EAAA,GAAA,EAACL,EAAeW,QAAQ,CAAA,CAACC,MAAO,WAAEX,EAAWC,aANxBO,AAAD,CAMuCD,GAL3DN,EAAaO,GACbH,eAAeI,OAAO,CAAC,kBAAmBD,EAC5C,CAG2E,WACtEL,GAGP,mBAEO,SAASS,EACd,MAAO,CAAA,EAAA,EAAA,UAAA,AAAU,EAACb,EACpB","ignoreList":[0,1,2,3,4,5,6]}