@sleep2agi/agent-network-dashboard 0.4.6 → 0.5.0

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 (493) hide show
  1. package/.next/BUILD_ID +1 -1
  2. package/.next/app-path-routes-manifest.json +2 -0
  3. package/.next/build-manifest.json +3 -3
  4. package/.next/diagnostics/route-bundle-stats.json +31 -31
  5. package/.next/fallback-build-manifest.json +3 -3
  6. package/.next/prerender-manifest.json +3 -3
  7. package/.next/routes-manifest.json +16 -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_client-reference-manifest.js +1 -1
  16. package/.next/server/app/_not-found.html +2 -2
  17. package/.next/server/app/_not-found.rsc +12 -12
  18. package/.next/server/app/_not-found.segments/_full.segment.rsc +12 -12
  19. package/.next/server/app/_not-found.segments/_head.segment.rsc +4 -4
  20. package/.next/server/app/_not-found.segments/_index.segment.rsc +7 -7
  21. package/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +2 -2
  22. package/.next/server/app/_not-found.segments/_not-found.segment.rsc +3 -3
  23. package/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  24. package/.next/server/app/admin/page_client-reference-manifest.js +1 -1
  25. package/.next/server/app/admin.html +2 -2
  26. package/.next/server/app/admin.rsc +14 -14
  27. package/.next/server/app/admin.segments/_full.segment.rsc +14 -14
  28. package/.next/server/app/admin.segments/_head.segment.rsc +4 -4
  29. package/.next/server/app/admin.segments/_index.segment.rsc +7 -7
  30. package/.next/server/app/admin.segments/_tree.segment.rsc +2 -2
  31. package/.next/server/app/admin.segments/admin/__PAGE__.segment.rsc +4 -4
  32. package/.next/server/app/admin.segments/admin.segment.rsc +3 -3
  33. package/.next/server/app/api/hub/server/[hostname]/agents/route/app-paths-manifest.json +3 -0
  34. package/.next/server/app/api/hub/server/[hostname]/agents/route/build-manifest.json +9 -0
  35. package/.next/server/app/api/hub/server/[hostname]/agents/route/server-reference-manifest.json +4 -0
  36. package/.next/server/app/api/hub/server/[hostname]/agents/route.js +7 -0
  37. package/.next/server/app/api/hub/server/[hostname]/agents/route.js.map +5 -0
  38. package/.next/server/app/api/hub/server/[hostname]/agents/route.js.nft.json +1 -0
  39. package/.next/server/app/api/hub/server/[hostname]/agents/route_client-reference-manifest.js +3 -0
  40. package/.next/server/app/api/hub/server/[hostname]/health/route/app-paths-manifest.json +3 -0
  41. package/.next/server/app/api/hub/server/[hostname]/health/route/build-manifest.json +9 -0
  42. package/.next/server/app/api/hub/server/[hostname]/health/route/server-reference-manifest.json +4 -0
  43. package/.next/server/app/api/hub/server/[hostname]/health/route.js +7 -0
  44. package/.next/server/app/api/hub/server/[hostname]/health/route.js.map +5 -0
  45. package/.next/server/app/api/hub/server/[hostname]/health/route.js.nft.json +1 -0
  46. package/.next/server/app/api/hub/server/[hostname]/health/route_client-reference-manifest.js +3 -0
  47. package/.next/server/app/index.html +2 -2
  48. package/.next/server/app/index.rsc +14 -14
  49. package/.next/server/app/index.segments/__PAGE__.segment.rsc +4 -4
  50. package/.next/server/app/index.segments/_full.segment.rsc +14 -14
  51. package/.next/server/app/index.segments/_head.segment.rsc +4 -4
  52. package/.next/server/app/index.segments/_index.segment.rsc +7 -7
  53. package/.next/server/app/index.segments/_tree.segment.rsc +2 -2
  54. package/.next/server/app/login/page_client-reference-manifest.js +1 -1
  55. package/.next/server/app/login.html +2 -2
  56. package/.next/server/app/login.rsc +14 -14
  57. package/.next/server/app/login.segments/_full.segment.rsc +14 -14
  58. package/.next/server/app/login.segments/_head.segment.rsc +4 -4
  59. package/.next/server/app/login.segments/_index.segment.rsc +7 -7
  60. package/.next/server/app/login.segments/_tree.segment.rsc +2 -2
  61. package/.next/server/app/login.segments/login/__PAGE__.segment.rsc +4 -4
  62. package/.next/server/app/login.segments/login.segment.rsc +3 -3
  63. package/.next/server/app/logs/page_client-reference-manifest.js +1 -1
  64. package/.next/server/app/logs.html +2 -2
  65. package/.next/server/app/logs.rsc +14 -14
  66. package/.next/server/app/logs.segments/_full.segment.rsc +14 -14
  67. package/.next/server/app/logs.segments/_head.segment.rsc +4 -4
  68. package/.next/server/app/logs.segments/_index.segment.rsc +7 -7
  69. package/.next/server/app/logs.segments/_tree.segment.rsc +2 -2
  70. package/.next/server/app/logs.segments/logs/__PAGE__.segment.rsc +4 -4
  71. package/.next/server/app/logs.segments/logs.segment.rsc +3 -3
  72. package/.next/server/app/messages/page_client-reference-manifest.js +1 -1
  73. package/.next/server/app/messages.html +2 -2
  74. package/.next/server/app/messages.rsc +14 -14
  75. package/.next/server/app/messages.segments/_full.segment.rsc +14 -14
  76. package/.next/server/app/messages.segments/_head.segment.rsc +4 -4
  77. package/.next/server/app/messages.segments/_index.segment.rsc +7 -7
  78. package/.next/server/app/messages.segments/_tree.segment.rsc +2 -2
  79. package/.next/server/app/messages.segments/messages/__PAGE__.segment.rsc +4 -4
  80. package/.next/server/app/messages.segments/messages.segment.rsc +3 -3
  81. package/.next/server/app/node/page_client-reference-manifest.js +1 -1
  82. package/.next/server/app/node.html +2 -2
  83. package/.next/server/app/node.rsc +14 -14
  84. package/.next/server/app/node.segments/_full.segment.rsc +14 -14
  85. package/.next/server/app/node.segments/_head.segment.rsc +4 -4
  86. package/.next/server/app/node.segments/_index.segment.rsc +7 -7
  87. package/.next/server/app/node.segments/_tree.segment.rsc +2 -2
  88. package/.next/server/app/node.segments/node/__PAGE__.segment.rsc +4 -4
  89. package/.next/server/app/node.segments/node.segment.rsc +3 -3
  90. package/.next/server/app/nodes/page_client-reference-manifest.js +1 -1
  91. package/.next/server/app/nodes.html +2 -2
  92. package/.next/server/app/nodes.rsc +14 -14
  93. package/.next/server/app/nodes.segments/_full.segment.rsc +14 -14
  94. package/.next/server/app/nodes.segments/_head.segment.rsc +4 -4
  95. package/.next/server/app/nodes.segments/_index.segment.rsc +7 -7
  96. package/.next/server/app/nodes.segments/_tree.segment.rsc +2 -2
  97. package/.next/server/app/nodes.segments/nodes/__PAGE__.segment.rsc +4 -4
  98. package/.next/server/app/nodes.segments/nodes.segment.rsc +3 -3
  99. package/.next/server/app/page_client-reference-manifest.js +1 -1
  100. package/.next/server/app/server-logs/page_client-reference-manifest.js +1 -1
  101. package/.next/server/app/server-logs.html +2 -2
  102. package/.next/server/app/server-logs.rsc +14 -14
  103. package/.next/server/app/server-logs.segments/_full.segment.rsc +14 -14
  104. package/.next/server/app/server-logs.segments/_head.segment.rsc +4 -4
  105. package/.next/server/app/server-logs.segments/_index.segment.rsc +7 -7
  106. package/.next/server/app/server-logs.segments/_tree.segment.rsc +2 -2
  107. package/.next/server/app/server-logs.segments/server-logs/__PAGE__.segment.rsc +4 -4
  108. package/.next/server/app/server-logs.segments/server-logs.segment.rsc +3 -3
  109. package/.next/server/app/settings/networks/page_client-reference-manifest.js +1 -1
  110. package/.next/server/app/settings/networks.html +2 -2
  111. package/.next/server/app/settings/networks.rsc +14 -14
  112. package/.next/server/app/settings/networks.segments/_full.segment.rsc +14 -14
  113. package/.next/server/app/settings/networks.segments/_head.segment.rsc +4 -4
  114. package/.next/server/app/settings/networks.segments/_index.segment.rsc +7 -7
  115. package/.next/server/app/settings/networks.segments/_tree.segment.rsc +2 -2
  116. package/.next/server/app/settings/networks.segments/settings/networks/__PAGE__.segment.rsc +4 -4
  117. package/.next/server/app/settings/networks.segments/settings/networks.segment.rsc +3 -3
  118. package/.next/server/app/settings/networks.segments/settings.segment.rsc +3 -3
  119. package/.next/server/app/settings/page_client-reference-manifest.js +1 -1
  120. package/.next/server/app/settings/tokens/page_client-reference-manifest.js +1 -1
  121. package/.next/server/app/settings/tokens.html +2 -2
  122. package/.next/server/app/settings/tokens.rsc +14 -14
  123. package/.next/server/app/settings/tokens.segments/_full.segment.rsc +14 -14
  124. package/.next/server/app/settings/tokens.segments/_head.segment.rsc +4 -4
  125. package/.next/server/app/settings/tokens.segments/_index.segment.rsc +7 -7
  126. package/.next/server/app/settings/tokens.segments/_tree.segment.rsc +2 -2
  127. package/.next/server/app/settings/tokens.segments/settings/tokens/__PAGE__.segment.rsc +4 -4
  128. package/.next/server/app/settings/tokens.segments/settings/tokens.segment.rsc +3 -3
  129. package/.next/server/app/settings/tokens.segments/settings.segment.rsc +3 -3
  130. package/.next/server/app/settings.html +2 -2
  131. package/.next/server/app/settings.rsc +14 -14
  132. package/.next/server/app/settings.segments/_full.segment.rsc +14 -14
  133. package/.next/server/app/settings.segments/_head.segment.rsc +4 -4
  134. package/.next/server/app/settings.segments/_index.segment.rsc +7 -7
  135. package/.next/server/app/settings.segments/_tree.segment.rsc +2 -2
  136. package/.next/server/app/settings.segments/settings/__PAGE__.segment.rsc +4 -4
  137. package/.next/server/app/settings.segments/settings.segment.rsc +3 -3
  138. package/.next/server/app/tasks/[id]/page_client-reference-manifest.js +1 -1
  139. package/.next/server/app/tasks/page_client-reference-manifest.js +1 -1
  140. package/.next/server/app/tasks.html +2 -2
  141. package/.next/server/app/tasks.rsc +14 -14
  142. package/.next/server/app/tasks.segments/_full.segment.rsc +14 -14
  143. package/.next/server/app/tasks.segments/_head.segment.rsc +4 -4
  144. package/.next/server/app/tasks.segments/_index.segment.rsc +7 -7
  145. package/.next/server/app/tasks.segments/_tree.segment.rsc +2 -2
  146. package/.next/server/app/tasks.segments/tasks/__PAGE__.segment.rsc +4 -4
  147. package/.next/server/app/tasks.segments/tasks.segment.rsc +3 -3
  148. package/.next/server/app-paths-manifest.json +2 -0
  149. package/.next/server/chunks/0dk5_next-internal_server_app_api_hub_server_[hostname]_agents_route_actions_0vr92s4.js +3 -0
  150. package/.next/server/chunks/0dk5_next-internal_server_app_api_hub_server_[hostname]_agents_route_actions_0vr92s4.js.map +1 -0
  151. package/.next/server/chunks/0dk5_next-internal_server_app_api_hub_server_[hostname]_health_route_actions_0vr-bv5.js +3 -0
  152. package/.next/server/chunks/0dk5_next-internal_server_app_api_hub_server_[hostname]_health_route_actions_0vr-bv5.js.map +1 -0
  153. package/.next/server/chunks/[root-of-the-server]__05nyivw._.js +3 -0
  154. package/.next/server/chunks/[root-of-the-server]__05nyivw._.js.map +1 -0
  155. package/.next/server/chunks/[root-of-the-server]__0floe3h._.js +3 -0
  156. package/.next/server/chunks/[root-of-the-server]__0floe3h._.js.map +1 -0
  157. package/.next/server/chunks/[root-of-the-server]__0tx8s8i._.js +1 -1
  158. package/.next/server/chunks/[root-of-the-server]__0tx8s8i._.js.map +1 -1
  159. package/.next/server/chunks/ssr/agent-network-dashboard_09kk21a._.js +4 -2
  160. package/.next/server/chunks/ssr/agent-network-dashboard_09kk21a._.js.map +1 -1
  161. package/.next/server/chunks/ssr/agent-network-dashboard_app_01jhlxz._.js +1 -1
  162. package/.next/server/chunks/ssr/agent-network-dashboard_app_01jhlxz._.js.map +1 -1
  163. package/.next/server/chunks/ssr/agent-network-dashboard_app_09d29my._.js +1 -1
  164. package/.next/server/chunks/ssr/agent-network-dashboard_app_09d29my._.js.map +1 -1
  165. package/.next/server/chunks/ssr/agent-network-dashboard_app_components_0mvyi-4._.js +1 -1
  166. package/.next/server/chunks/ssr/agent-network-dashboard_app_components_0mvyi-4._.js.map +1 -1
  167. package/.next/server/middleware-build-manifest.js +3 -3
  168. package/.next/server/pages/404.html +2 -2
  169. package/.next/server/pages/500.html +1 -1
  170. package/.next/server/server-reference-manifest.js +1 -1
  171. package/.next/server/server-reference-manifest.json +1 -1
  172. package/.next/static/chunks/0aauz~36q5n2a.css +2 -0
  173. package/.next/static/chunks/0f~0kgy2pycyc.js +1 -0
  174. package/.next/static/chunks/0l_~q07bhpkcx.js +7 -0
  175. package/.next/static/chunks/1175-dp18a1e_.js +1 -0
  176. package/.next/static/chunks/1552j0415oeal.js +4 -0
  177. package/.next/trace +2 -2
  178. package/.next/trace-build +1 -1
  179. package/.next/types/routes.d.ts +3 -1
  180. package/.next/types/validator.ts +18 -0
  181. package/app/api/hub/server/[hostname]/agents/route.ts +62 -0
  182. package/app/api/hub/server/[hostname]/health/route.ts +58 -0
  183. package/app/api/hub/servers/route.ts +88 -1
  184. package/app/components/CommandPalette.tsx +107 -0
  185. package/app/components/HelpOverlay.tsx +109 -1
  186. package/app/components/ServersDrawer.tsx +181 -5
  187. package/app/components/TopoGraph.tsx +6409 -286
  188. package/app/globals.css +110 -5
  189. package/app/lib/vendorIdentity.ts +14 -3
  190. package/docs/rfc/v0.10.0-hero3-dashboard-upgrade.md +230 -0
  191. package/package.json +2 -2
  192. package/public/sleep2agi-logo.svg +11 -0
  193. package/public/vendors/claude.svg +11 -0
  194. package/public/vendors/minimax.svg +11 -0
  195. package/public/vendors/openai.svg +12 -0
  196. package/screenshots/r293-p0/after-full.png +0 -0
  197. package/screenshots/r293-p0/after-topo.png +0 -0
  198. package/screenshots/r293-p0/baseline-full.png +0 -0
  199. package/screenshots/r293-p0/baseline-topo.png +0 -0
  200. package/screenshots/r293-p0/logo-integrated-full.png +0 -0
  201. package/screenshots/r293-p0/logo-integrated-topo.png +0 -0
  202. package/screenshots/r293-p0/servers-drawer-v0.10.0-full.png +0 -0
  203. package/screenshots/r293-p0/servers-drawer-v0.10.0.png +0 -0
  204. package/screenshots/r293-p0/wave1-after-full.png +0 -0
  205. package/screenshots/r293-p0/wave1-after-topo.png +0 -0
  206. package/scripts/p0-servers-drawer-screenshot.mjs +99 -0
  207. package/scripts/p0-topo-screenshot.mjs +82 -0
  208. package/scripts/topo-active-filter-pill-test.mjs +101 -0
  209. package/scripts/topo-active-links-chip-hover-test.mjs +103 -0
  210. package/scripts/topo-active-links-chip-nav-test.mjs +117 -0
  211. package/scripts/topo-active-links-chip-self-hover-test.mjs +171 -0
  212. package/scripts/topo-active-links-empty-recede-test.mjs +125 -0
  213. package/scripts/topo-active-links-freshness-test.mjs +113 -0
  214. package/scripts/topo-active-links-tooltip-test.mjs +79 -0
  215. package/scripts/topo-active-pulse-ease-test.mjs +120 -0
  216. package/scripts/topo-brand-logo-transition-test.mjs +94 -0
  217. package/scripts/topo-brand-watermark-test.mjs +97 -0
  218. package/scripts/topo-canvas-aria-test.mjs +108 -0
  219. package/scripts/topo-canvas-brand-fade-test.mjs +87 -0
  220. package/scripts/topo-chat-target-breath-test.mjs +84 -0
  221. package/scripts/topo-chat-target-ring-ease-test.mjs +82 -0
  222. package/scripts/topo-chat-target-ring-fade-test.mjs +124 -0
  223. package/scripts/topo-chip-empty-recede-test.mjs +116 -0
  224. package/scripts/topo-chip-focus-test.mjs +95 -0
  225. package/scripts/topo-chip-pin-mirror-test.mjs +113 -0
  226. package/scripts/topo-chip-row-gap-test.mjs +90 -0
  227. package/scripts/topo-chip-row-semantic-gap-test.mjs +97 -0
  228. package/scripts/topo-chip-row-tabular-test.mjs +111 -0
  229. package/scripts/topo-chip-unit-demotion-test.mjs +93 -0
  230. package/scripts/topo-chiprow-data-weight-test.mjs +94 -0
  231. package/scripts/topo-chrome-a11y-test.mjs +107 -0
  232. package/scripts/topo-chrome-active-weight-test.mjs +104 -0
  233. package/scripts/topo-chrome-focus-ring-unify-test.mjs +100 -0
  234. package/scripts/topo-chrome-gap-test.mjs +73 -0
  235. package/scripts/topo-chrome-icon-stroke-test.mjs +95 -0
  236. package/scripts/topo-chrome-inactive-color-test.mjs +90 -0
  237. package/scripts/topo-chrome-pop-extension-test.mjs +98 -0
  238. package/scripts/topo-chrome-pop-nodesize-test.mjs +88 -0
  239. package/scripts/topo-chrome-press-state-test.mjs +135 -0
  240. package/scripts/topo-chrome-strip-semantic-gap-test.mjs +99 -0
  241. package/scripts/topo-chrome-strip-theme-ease-test.mjs +99 -0
  242. package/scripts/topo-chrome-zoom-level-pop-test.mjs +122 -0
  243. package/scripts/topo-chrome-zoom-pop-test.mjs +130 -0
  244. package/scripts/topo-chrome-zoom-readout-weight-test.mjs +81 -0
  245. package/scripts/topo-click-ripple-ease-test.mjs +94 -0
  246. package/scripts/topo-cmdk-edge-clear-test.mjs +109 -0
  247. package/scripts/topo-cmdk-layout-view-test.mjs +108 -0
  248. package/scripts/topo-cmdk-pin-test.mjs +123 -0
  249. package/scripts/topo-cmdk-vendor-clear-test.mjs +133 -0
  250. package/scripts/topo-cmdk-vendor-pin-test.mjs +103 -0
  251. package/scripts/topo-corner-radius-unify-test.mjs +103 -0
  252. package/scripts/topo-dense-alias-fill-transition-test.mjs +133 -0
  253. package/scripts/topo-discrete-zoom-smooth-test.mjs +125 -0
  254. package/scripts/topo-edge-badge-click-pin-test.mjs +94 -0
  255. package/scripts/topo-edge-badge-crossfade-test.mjs +138 -0
  256. package/scripts/topo-edge-badge-hot-test.mjs +115 -0
  257. package/scripts/topo-edge-badge-hover-test.mjs +85 -0
  258. package/scripts/topo-edge-badge-lift-test.mjs +150 -0
  259. package/scripts/topo-edge-badge-ripple-test.mjs +111 -0
  260. package/scripts/topo-edge-badge-stroke-transition-test.mjs +118 -0
  261. package/scripts/topo-edge-badge-text-pin-test.mjs +121 -0
  262. package/scripts/topo-edge-badge-theme-ease-test.mjs +89 -0
  263. package/scripts/topo-edge-count-badge-test.mjs +86 -0
  264. package/scripts/topo-edge-endpoint-highlight-test.mjs +111 -0
  265. package/scripts/topo-edge-fadein-test.mjs +106 -0
  266. package/scripts/topo-edge-focus-test.mjs +113 -0
  267. package/scripts/topo-edge-hover-test.mjs +13 -5
  268. package/scripts/topo-edge-pill-hot-test.mjs +129 -0
  269. package/scripts/topo-edge-pill-test.mjs +105 -0
  270. package/scripts/topo-edge-ping-pulse-retired-test.mjs +119 -0
  271. package/scripts/topo-edge-stroke-ease-test.mjs +100 -0
  272. package/scripts/topo-edge-stroke-transition-test.mjs +132 -0
  273. package/scripts/topo-empty-hint-tracking-test.mjs +84 -0
  274. package/scripts/topo-empty-state-breath-test.mjs +150 -0
  275. package/scripts/topo-empty-state-crossfade-test.mjs +130 -0
  276. package/scripts/topo-empty-state-recenter-test.mjs +107 -0
  277. package/scripts/topo-empty-subhint-tracking-test.mjs +87 -0
  278. package/scripts/topo-endpoint-ring-fade-test.mjs +132 -0
  279. package/scripts/topo-endpoint-ring-test.mjs +93 -0
  280. package/scripts/topo-endpoint-ring-thicken-test.mjs +112 -0
  281. package/scripts/topo-esc-clears-pin-test.mjs +98 -0
  282. package/scripts/topo-filter-pill-aliases-test.mjs +121 -0
  283. package/scripts/topo-filter-pill-body-click-test.mjs +112 -0
  284. package/scripts/topo-filter-pill-count-tabular-test.mjs +135 -0
  285. package/scripts/topo-filter-pill-count-test.mjs +110 -0
  286. package/scripts/topo-filter-pill-mobile-test.mjs +90 -0
  287. package/scripts/topo-freshness-chip-transition-test.mjs +80 -0
  288. package/scripts/topo-freshness-chip-weight-test.mjs +90 -0
  289. package/scripts/topo-freshness-conditional-render-test.mjs +92 -0
  290. package/scripts/topo-fullscreen-active-test.mjs +115 -0
  291. package/scripts/topo-group-box-pinned-state-test.mjs +95 -0
  292. package/scripts/topo-group-count-test.mjs +6 -1
  293. package/scripts/topo-group-label-a11y-test.mjs +113 -0
  294. package/scripts/topo-group-label-count-inherit-test.mjs +99 -0
  295. package/scripts/topo-group-label-hover-test.mjs +119 -0
  296. package/scripts/topo-group-label-pin-spacing-test.mjs +136 -0
  297. package/scripts/topo-group-label-tint-test.mjs +99 -0
  298. package/scripts/topo-group-label-title-test.mjs +83 -0
  299. package/scripts/topo-group-pin-test.mjs +119 -0
  300. package/scripts/topo-group-pip-fadein-test.mjs +104 -0
  301. package/scripts/topo-group-pip-singletier-drop-test.mjs +131 -0
  302. package/scripts/topo-group-pip-tabular-test.mjs +95 -0
  303. package/scripts/topo-group-status-pips-test.mjs +103 -0
  304. package/scripts/topo-groupbox-fadein-test.mjs +95 -0
  305. package/scripts/topo-groupbox-hover-lift-test.mjs +127 -0
  306. package/scripts/topo-groupbox-hubcore-ease-test.mjs +106 -0
  307. package/scripts/topo-groupbox-live-test.mjs +100 -0
  308. package/scripts/topo-groupbox-march-busyness-test.mjs +155 -0
  309. package/scripts/topo-groupbox-test.mjs +4 -2
  310. package/scripts/topo-header-gap-test.mjs +94 -0
  311. package/scripts/topo-help-overlay-r109-test.mjs +67 -0
  312. package/scripts/topo-help-overlay-r118-test.mjs +69 -0
  313. package/scripts/topo-help-overlay-r123-test.mjs +69 -0
  314. package/scripts/topo-help-overlay-r134-test.mjs +74 -0
  315. package/scripts/topo-help-overlay-r137-test.mjs +81 -0
  316. package/scripts/topo-help-overlay-r141-test.mjs +86 -0
  317. package/scripts/topo-help-overlay-r153-test.mjs +85 -0
  318. package/scripts/topo-help-overlay-r59-test.mjs +67 -0
  319. package/scripts/topo-help-overlay-r65-test.mjs +64 -0
  320. package/scripts/topo-help-overlay-r70-test.mjs +63 -0
  321. package/scripts/topo-help-overlay-r78-test.mjs +59 -0
  322. package/scripts/topo-help-overlay-r81-test.mjs +58 -0
  323. package/scripts/topo-help-overlay-r87-test.mjs +64 -0
  324. package/scripts/topo-help-overlay-r91-test.mjs +65 -0
  325. package/scripts/topo-hot-tail-crossfade-test.mjs +117 -0
  326. package/scripts/topo-html-overlay-padding-unify-test.mjs +120 -0
  327. package/scripts/topo-hub-a11y-test.mjs +112 -0
  328. package/scripts/topo-hub-busyness-test.mjs +100 -0
  329. package/scripts/topo-hub-center-crossfade-test.mjs +124 -0
  330. package/scripts/topo-hub-click-fit-test.mjs +137 -0
  331. package/scripts/topo-hub-digit-scale-test.mjs +129 -0
  332. package/scripts/topo-hub-fadein-test.mjs +88 -0
  333. package/scripts/topo-hub-hover-lift-test.mjs +101 -0
  334. package/scripts/topo-hub-hover-ring-test.mjs +82 -0
  335. package/scripts/topo-hub-pip-theme-ease-test.mjs +116 -0
  336. package/scripts/topo-hub-spoke-ease-test.mjs +120 -0
  337. package/scripts/topo-hub-title-test.mjs +7 -2
  338. package/scripts/topo-hub-working-count-test.mjs +99 -0
  339. package/scripts/topo-ingroup-edge-test.mjs +103 -0
  340. package/scripts/topo-inner-radar-ring-retired-test.mjs +89 -0
  341. package/scripts/topo-kicker-color-test.mjs +93 -0
  342. package/scripts/topo-kicker-tracking-test.mjs +101 -0
  343. package/scripts/topo-kicker-weight-test.mjs +98 -0
  344. package/scripts/topo-label-card-theme-ease-test.mjs +85 -0
  345. package/scripts/topo-label-lift-test.mjs +5 -1
  346. package/scripts/topo-layout-hover-text-preview-test.mjs +101 -0
  347. package/scripts/topo-layout-switch-crossfade-test.mjs +126 -0
  348. package/scripts/topo-layout-toggle-border-unify-test.mjs +104 -0
  349. package/scripts/topo-layout-toggle-test.mjs +131 -0
  350. package/scripts/topo-layout-trailer-mr-test.mjs +82 -0
  351. package/scripts/topo-legend-compress-test.mjs +107 -0
  352. package/scripts/topo-legend-count-empty-test.mjs +126 -0
  353. package/scripts/topo-legend-count-tabular-parity-test.mjs +90 -0
  354. package/scripts/topo-legend-count-tabular-test.mjs +87 -0
  355. package/scripts/topo-legend-count-test.mjs +88 -0
  356. package/scripts/topo-legend-count-tier-fill-test.mjs +121 -0
  357. package/scripts/topo-legend-count-weight-test.mjs +86 -0
  358. package/scripts/topo-legend-header-symmetric-inset-test.mjs +112 -0
  359. package/scripts/topo-legend-hitbox-swatch-center-test.mjs +93 -0
  360. package/scripts/topo-legend-hover-test.mjs +113 -0
  361. package/scripts/topo-legend-offline-delimiter-test.mjs +84 -0
  362. package/scripts/topo-legend-offline-label-simplify-test.mjs +86 -0
  363. package/scripts/topo-legend-panel-count-weight-test.mjs +89 -0
  364. package/scripts/topo-legend-panel-header-test.mjs +83 -0
  365. package/scripts/topo-legend-pin-ring-fade-test.mjs +112 -0
  366. package/scripts/topo-legend-pin-test.mjs +128 -0
  367. package/scripts/topo-legend-row-hover-lift-test.mjs +109 -0
  368. package/scripts/topo-legend-row-labels-simplify-test.mjs +80 -0
  369. package/scripts/topo-legend-row-pin-spacing-test.mjs +124 -0
  370. package/scripts/topo-legend-row-tint-test.mjs +95 -0
  371. package/scripts/topo-legend-row-title-test.mjs +102 -0
  372. package/scripts/topo-legend-swatch-grow-test.mjs +116 -0
  373. package/scripts/topo-legend-swatch-radius-test.mjs +78 -0
  374. package/scripts/topo-minimap-a11y-test.mjs +101 -0
  375. package/scripts/topo-minimap-dot-transition-test.mjs +113 -0
  376. package/scripts/topo-minimap-radius-test.mjs +88 -0
  377. package/scripts/topo-minimap-rect-stroke-test.mjs +94 -0
  378. package/scripts/topo-minimap-viewport-smooth-test.mjs +124 -0
  379. package/scripts/topo-monogram-font-test.mjs +112 -0
  380. package/scripts/topo-monogram-stroke-test.mjs +101 -0
  381. package/scripts/topo-more-flows-letterspacing-test.mjs +111 -0
  382. package/scripts/topo-node-a11y-test.mjs +107 -0
  383. package/scripts/topo-node-alias-chat-pin-test.mjs +95 -0
  384. package/scripts/topo-node-hover-lift-test.mjs +85 -0
  385. package/scripts/topo-node-label-card-elevation-test.mjs +157 -0
  386. package/scripts/topo-node-label-card-stroke-test.mjs +135 -0
  387. package/scripts/topo-node-stroke-transition-test.mjs +103 -0
  388. package/scripts/topo-node-text-fill-transition-test.mjs +119 -0
  389. package/scripts/topo-node-title-peers-test.mjs +107 -0
  390. package/scripts/topo-node-title-test.mjs +101 -0
  391. package/scripts/topo-nodesize-active-hover-test.mjs +109 -0
  392. package/scripts/topo-nodesize-crossfade-test.mjs +141 -0
  393. package/scripts/topo-online-chip-nav-test.mjs +143 -0
  394. package/scripts/topo-orbit-particles-retired-test.mjs +91 -0
  395. package/scripts/topo-panel-count-unit-test.mjs +112 -0
  396. package/scripts/topo-panel-elevation-test.mjs +76 -0
  397. package/scripts/topo-panel-fadein-test.mjs +102 -0
  398. package/scripts/topo-panel-hot-tail-fade-test.mjs +132 -0
  399. package/scripts/topo-panel-hover-elevation-test.mjs +118 -0
  400. package/scripts/topo-panel-rx-test.mjs +90 -0
  401. package/scripts/topo-panel-theme-ease-test.mjs +85 -0
  402. package/scripts/topo-panel-title-fill-ease-test.mjs +91 -0
  403. package/scripts/topo-panel-title-tracking-test.mjs +78 -0
  404. package/scripts/topo-particle-stagger-test.mjs +82 -0
  405. package/scripts/topo-pin-intersection-color-ease-test.mjs +111 -0
  406. package/scripts/topo-pin-intersection-empty-test.mjs +129 -0
  407. package/scripts/topo-pin-intersection-tabular-test.mjs +96 -0
  408. package/scripts/topo-pin-intersection-test.mjs +121 -0
  409. package/scripts/topo-pin-intersection-warning-crossfade-test.mjs +107 -0
  410. package/scripts/topo-pin-mirror-transition-test.mjs +101 -0
  411. package/scripts/topo-pin-persistence-test.mjs +105 -0
  412. package/scripts/topo-prefix-opacity-test.mjs +107 -0
  413. package/scripts/topo-prepublish-guard-test.mjs +95 -0
  414. package/scripts/topo-pressure-hover-test.mjs +123 -0
  415. package/scripts/topo-pressure-pin-test.mjs +119 -0
  416. package/scripts/topo-pressure-seg-self-hover-test.mjs +126 -0
  417. package/scripts/topo-pressure-seg-tooltip-test.mjs +98 -0
  418. package/scripts/topo-pressure-seg-transition-test.mjs +107 -0
  419. package/scripts/topo-pulse-dot-crossfade-test.mjs +122 -0
  420. package/scripts/topo-pulse-dot-retired-test.mjs +86 -0
  421. package/scripts/topo-recent-panel-count-freshness-test.mjs +109 -0
  422. package/scripts/topo-recent-panel-count-test.mjs +72 -0
  423. package/scripts/topo-recent-panel-count-weight-test.mjs +91 -0
  424. package/scripts/topo-recent-panel-footer-breath-test.mjs +142 -0
  425. package/scripts/topo-recent-panel-hot-header-test.mjs +132 -0
  426. package/scripts/topo-recent-panel-hot-tabular-test.mjs +113 -0
  427. package/scripts/topo-recent-panel-more-crossfade-test.mjs +124 -0
  428. package/scripts/topo-recent-panel-more-cyan-hover-test.mjs +151 -0
  429. package/scripts/topo-recent-panel-more-nav-test.mjs +127 -0
  430. package/scripts/topo-recent-panel-more-test.mjs +106 -0
  431. package/scripts/topo-recent-panel-readability-bump-test.mjs +151 -0
  432. package/scripts/topo-recent-row-count-fill-test.mjs +129 -0
  433. package/scripts/topo-recent-row-count-weight-test.mjs +112 -0
  434. package/scripts/topo-recent-row-fadein-test.mjs +107 -0
  435. package/scripts/topo-recent-row-freshness-test.mjs +102 -0
  436. package/scripts/topo-recent-row-hot-test.mjs +110 -0
  437. package/scripts/topo-recent-row-hover-lift-test.mjs +128 -0
  438. package/scripts/topo-recent-row-hover-test.mjs +122 -0
  439. package/scripts/topo-recent-row-pin-spacing-test.mjs +137 -0
  440. package/scripts/topo-recent-row-pin-test.mjs +126 -0
  441. package/scripts/topo-recent-row-tint-test.mjs +91 -0
  442. package/scripts/topo-recent-row-title-test.mjs +112 -0
  443. package/scripts/topo-recent-row-ts-alpha-test.mjs +100 -0
  444. package/scripts/topo-recent-row-ts-tabular-test.mjs +108 -0
  445. package/scripts/topo-recent-row-ts-test.mjs +95 -0
  446. package/scripts/topo-recent-row-typography-test.mjs +119 -0
  447. package/scripts/topo-recent-signal-empty-hint-test.mjs +73 -0
  448. package/scripts/topo-reset-spin-test.mjs +120 -0
  449. package/scripts/topo-runtime-badge-grow-test.mjs +114 -0
  450. package/scripts/topo-spokes-retired-test.mjs +93 -0
  451. package/scripts/topo-starfield-density-test.mjs +89 -0
  452. package/scripts/topo-status-chip-hover-test.mjs +101 -0
  453. package/scripts/topo-status-chip-tooltip-test.mjs +95 -0
  454. package/scripts/topo-statusbar-chips-self-hover-test.mjs +177 -0
  455. package/scripts/topo-svg-focus-test.mjs +112 -0
  456. package/scripts/topo-sweep-busyness-test.mjs +94 -0
  457. package/scripts/topo-tabular-nums-sweep-test.mjs +93 -0
  458. package/scripts/topo-tier-guide-dashes-test.mjs +86 -0
  459. package/scripts/topo-tier-ring-fadein-test.mjs +107 -0
  460. package/scripts/topo-tier-ring-occupancy-test.mjs +87 -0
  461. package/scripts/topo-tier-ring-test.mjs +69 -0
  462. package/scripts/topo-tier-ring-tint-test.mjs +110 -0
  463. package/scripts/topo-tier-stagger-test.mjs +89 -0
  464. package/scripts/topo-title-block-tight-leading-test.mjs +95 -0
  465. package/scripts/topo-title-tracking-test.mjs +98 -0
  466. package/scripts/topo-titleblock-gap-test.mjs +86 -0
  467. package/scripts/topo-titleblock-margin-test.mjs +83 -0
  468. package/scripts/topo-toggle-inactive-cyan-hover-test.mjs +110 -0
  469. package/scripts/topo-top-rail-theme-ease-test.mjs +89 -0
  470. package/scripts/topo-vendor-chip-hover-test.mjs +111 -0
  471. package/scripts/topo-vendor-chip-self-hover-test.mjs +131 -0
  472. package/scripts/topo-vendor-chip-tabular-test.mjs +92 -0
  473. package/scripts/topo-vendor-chip-threshold-test.mjs +78 -0
  474. package/scripts/topo-vendor-chip-weight-test.mjs +87 -0
  475. package/scripts/topo-vendor-count-suffix-test.mjs +95 -0
  476. package/scripts/topo-vendor-letter-tooltip-test.mjs +92 -0
  477. package/scripts/topo-vendor-pill-test.mjs +125 -0
  478. package/scripts/topo-vendor-pin-test.mjs +125 -0
  479. package/scripts/topo-view-smooth-test.mjs +131 -0
  480. package/scripts/topo-watermark-tracking-test.mjs +99 -0
  481. package/scripts/topo-working-chip-pin-test.mjs +154 -0
  482. package/scripts/topo-working-halo-breath-retired-test.mjs +99 -0
  483. package/scripts/topo-wrapper-flow-arrow-theme-test.mjs +97 -0
  484. package/scripts/topo-wrapper-radius-test.mjs +73 -0
  485. package/scripts/topo-wrapper-shadow-theme-ease-test.mjs +89 -0
  486. package/.next/static/chunks/088ouqy7tekty.js +0 -2
  487. package/.next/static/chunks/0hyl7mdapsz38.js +0 -1
  488. package/.next/static/chunks/0mqwn-l7wtcdo.js +0 -7
  489. package/.next/static/chunks/127kw7~wsnyu7.css +0 -2
  490. package/.next/static/chunks/16yfxp9ak2gdm.js +0 -1
  491. /package/.next/static/{23MxP0RBVA4BaOJ_HMYmM → 424zX3i80AJ_wHF_otKuP}/_buildManifest.js +0 -0
  492. /package/.next/static/{23MxP0RBVA4BaOJ_HMYmM → 424zX3i80AJ_wHF_otKuP}/_clientMiddlewareManifest.js +0 -0
  493. /package/.next/static/{23MxP0RBVA4BaOJ_HMYmM → 424zX3i80AJ_wHF_otKuP}/_ssgManifest.js +0 -0
package/app/globals.css CHANGED
@@ -828,6 +828,41 @@ body {
828
828
  }
829
829
  .anet-fade-in { animation: anet-fade-in 0.15s ease-out; }
830
830
 
831
+ /* Round 184 — chrome reset button click-spin. The reset button's
832
+ onClick triggers R168 smoothView crossfade on the canvas, but the
833
+ BUTTON itself had no visual feedback that the click registered. A
834
+ single 360° rotation on the refresh-arrow icon (450ms ease-out) is
835
+ a quick "yes, I heard you" confirmation. Counter-clockwise (-360°)
836
+ reads as "rewind" / "undo" — natural for a reset gesture. Mirror
837
+ to R52's hub click ripple at the chrome scope. */
838
+ @keyframes anet-reset-spin {
839
+ from { transform: rotate(0deg); }
840
+ to { transform: rotate(-360deg); }
841
+ }
842
+ .anet-reset-spin {
843
+ animation: anet-reset-spin 0.45s cubic-bezier(0.4, 0, 0.2, 1);
844
+ transform-origin: center;
845
+ transform-box: fill-box;
846
+ }
847
+
848
+ /* Round 186 — chrome zoom-in / zoom-out buttons get a brief icon pop
849
+ on click. Same click-feel idiom R184 added for the reset button —
850
+ the canvas already smoothes via R168/R169 smoothView, but the
851
+ chrome BUTTON itself needs its own confirmation. A quick scale
852
+ up-then-back (1 → 1.18 → 1 over 220ms) reads as "tapped". Same
853
+ transform-box: fill-box anchoring as R184 keeps the icon
854
+ centered in place. */
855
+ @keyframes anet-chrome-pop {
856
+ 0% { transform: scale(1); }
857
+ 50% { transform: scale(1.18); }
858
+ 100% { transform: scale(1); }
859
+ }
860
+ .anet-chrome-pop {
861
+ animation: anet-chrome-pop 0.22s ease-out;
862
+ transform-origin: center;
863
+ transform-box: fill-box;
864
+ }
865
+
831
866
  /* Round 36 — current-step ring pulse on TaskDrawer timeline. Halo gently
832
867
  breathes around the active step's dot so users can spot "task is here". */
833
868
  @keyframes anet-current-step-pulse-kf {
@@ -840,24 +875,93 @@ body {
840
875
 
841
876
  /* Round 45 — TopoGraph rotating radar sweep wedge. 6s slow rotation
842
877
  gives the topology canvas a real "radar scan" feel without distracting
843
- from the agent nodes. */
878
+ from the agent nodes.
879
+ R146: split shorthand into longhand so per-render inline style can
880
+ override animation-duration via --sweep-dur, joining the R145
881
+ --spoke-dur / R132 --march-dur pattern. Default 6s preserves R45's
882
+ original cadence for any caller that forgets the var. */
844
883
  @keyframes anet-topo-sweep-kf {
845
884
  0% { transform: rotate(0deg); }
846
885
  100% { transform: rotate(360deg); }
847
886
  }
848
887
  .anet-topo-sweep {
849
- animation: anet-topo-sweep-kf 6s linear infinite;
888
+ animation-name: anet-topo-sweep-kf;
889
+ animation-duration: var(--sweep-dur, 6s);
890
+ animation-timing-function: linear;
891
+ animation-iteration-count: infinite;
892
+ }
893
+
894
+ /* R155 — focus-visible outline for TopoGraph chip-row interactives.
895
+ Cyber theme's dark canvas often swallows the browser default focus
896
+ ring; R154 fixed it for chrome buttons via Tailwind's focus-visible:
897
+ ring (box-shadow). Chip-row chips reuse `box-shadow` for the R88 /
898
+ R139 / R140 pin-mirror inset — so a focus box-shadow would conflict
899
+ with the pinned-state shadow. `outline` is a separate CSS property
900
+ and doesn't fight box-shadow, so we use it here. `currentColor`
901
+ inherits the chip's own accent (green for working, cyan for online,
902
+ per-vendor for letters, etc.). Only fires on :focus-visible
903
+ (keyboard) — mouse focus stays unstyled. */
904
+ .anet-topo-chip-focus:focus-visible {
905
+ outline: 2px solid currentColor;
906
+ outline-offset: 1px;
907
+ }
908
+
909
+ /* R156 — focus-visible outline for SVG-side TopoGraph interactives.
910
+ Same idiom as R155's chip-row class but for SVG <g> elements
911
+ (recent-signal rows, legend rows, group labels, edge badges,
912
+ node bodies, "+N more" footer). Each <g> already has role=
913
+ "button"/"link" + tabIndex=0 + onKeyDown (R116/R121/R133/R143/
914
+ R144/R151/R152). Browser default focus outline on SVG is hard
915
+ to spot against the canvas; explicit cyan-300 ring matches the
916
+ dashboard's legendAccent. 2-px outline-offset gives breathing
917
+ room around the painted bounding box. */
918
+ .anet-topo-svg-focus:focus-visible {
919
+ outline: 2px solid #67e8f9;
920
+ outline-offset: 2px;
850
921
  }
851
922
 
852
923
  /* Round 46 — animated dashed spokes flowing from hub outward. Each spoke
853
924
  gets a small animationDelay (set inline) so the dashes don't all flow
854
- in sync — reads as "command relay" pulse rather than a metronome. */
925
+ in sync — reads as "command relay" pulse rather than a metronome.
926
+ R145: split shorthand into longhand so per-render inline style can
927
+ override animation-duration via the --spoke-dur custom property —
928
+ same idiom R132 uses for --march-dur on group boxes. Default 2.4s
929
+ when --spoke-dur isn't set, so any future caller that forgets the
930
+ var keeps R46's original cadence. */
855
931
  @keyframes anet-topo-spoke-flow-kf {
856
932
  from { stroke-dashoffset: 0; }
857
933
  to { stroke-dashoffset: -40; }
858
934
  }
859
935
  .anet-topo-spoke-flow {
860
- animation: anet-topo-spoke-flow-kf 2.4s linear infinite;
936
+ animation-name: anet-topo-spoke-flow-kf;
937
+ animation-duration: var(--spoke-dur, 2.4s);
938
+ animation-timing-function: linear;
939
+ animation-iteration-count: infinite;
940
+ }
941
+
942
+ /* Round 85 — group-box "marching ants" perimeter drift.
943
+ Applied to a grid-layout group box whose `statuses.working > 0`
944
+ AND that is neither hovered nor pinned (those treatments already
945
+ carry their own visual emphasis via solid stroke). Slow 12s
946
+ linear cycle reads as ambient motion, not animation — the eye
947
+ parses "this group has live work" without registering the box
948
+ as moving. R86 stride matches the box's `strokeDasharray="6 6"`
949
+ so a single full cycle returns to a frame-identical state.
950
+ prefers-reduced-motion handled by the blanket override below.
951
+ R132: split shorthand into longhand so per-group inline style can
952
+ override animation-duration via the --march-dur custom property
953
+ without re-declaring keyframe + timing + iteration count. Default
954
+ stays at 12s when --march-dur isn't set, so existing single-group
955
+ call sites keep their cadence. */
956
+ @keyframes anet-topo-groupbox-march-kf {
957
+ from { stroke-dashoffset: 0; }
958
+ to { stroke-dashoffset: -12; }
959
+ }
960
+ .anet-topo-groupbox-live {
961
+ animation-name: anet-topo-groupbox-march-kf;
962
+ animation-duration: var(--march-dur, 12s);
963
+ animation-timing-function: linear;
964
+ animation-iteration-count: infinite;
861
965
  }
862
966
 
863
967
  /* ─────────────────────────────────────────────────────────────────────
@@ -894,7 +998,8 @@ body {
894
998
  .anet-fade-in,
895
999
  .anet-current-step-pulse,
896
1000
  .anet-topo-sweep,
897
- .anet-topo-spoke-flow {
1001
+ .anet-topo-spoke-flow,
1002
+ .anet-topo-groupbox-live {
898
1003
  animation: none !important;
899
1004
  }
900
1005
  /* Tasks row grid 0fr↔1fr keep working (it's the toggle mechanism),
@@ -54,7 +54,10 @@ const VENDOR_RULES: Array<{ test: (m: string) => boolean; vendor: VendorIdentity
54
54
  label: 'MiniMax',
55
55
  mono: { bg: 'hsl(18 50% 26%)', ring: 'hsl(18 65% 52%)', text: 'hsl(20 80% 82%)' },
56
56
  initial: 'M',
57
- logo: null, // public/vendors/minimax.* when assets land
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',
58
61
  },
59
62
  },
60
63
  {
@@ -64,7 +67,11 @@ const VENDOR_RULES: Array<{ test: (m: string) => boolean; vendor: VendorIdentity
64
67
  label: 'Anthropic',
65
68
  mono: { bg: 'hsl(16 32% 26%)', ring: 'hsl(16 48% 54%)', text: 'hsl(18 60% 84%)' },
66
69
  initial: 'A',
67
- logo: null,
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',
68
75
  },
69
76
  },
70
77
  {
@@ -74,7 +81,11 @@ const VENDOR_RULES: Array<{ test: (m: string) => boolean; vendor: VendorIdentity
74
81
  label: 'OpenAI',
75
82
  mono: { bg: 'hsl(165 26% 22%)', ring: 'hsl(165 40% 44%)', text: 'hsl(165 45% 80%)' },
76
83
  initial: 'O',
77
- logo: null,
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',
78
89
  },
79
90
  },
80
91
  ];
@@ -0,0 +1,230 @@
1
+ # RFC: v0.10.0 Hero 3 — Dashboard 网络节点前端展示升级
2
+
3
+ **Status**: DRAFT — review pending
4
+ **Author**: N站马 (`@sleep2agi/agent-network-dashboard` maintainer)
5
+ **Filed against**: [#140](https://github.com/sleep2agi/agent-network/issues/140) (v0.10.0 tracking)
6
+ **Related**: [#119](https://github.com/sleep2agi/agent-network/issues/119) (ServersDrawer), [#99](https://github.com/sleep2agi/agent-network/issues/99) (守护节点), [#114](https://github.com/sleep2agi/agent-network/issues/114) (Token stats), [#87](https://github.com/sleep2agi/agent-network/issues/87) (grid layout), [#81](https://github.com/sleep2agi/agent-network/issues/81) (fullscreen+zoom)
7
+ **Output target**: `@sleep2agi/agent-network-dashboard@0.4.7+`
8
+ **Generated**: 2026-05-16
9
+
10
+ ---
11
+
12
+ ## 0. Scope-status caveat (READ FIRST)
13
+
14
+ This RFC drafts the **Hero 3 (TopoGraph 升级)** scope. As of writing, [#140](https://github.com/sleep2agi/agent-network/issues/140) issue body **explicitly defers** "F Dashboard 0.5.x major" to **v0.11.0** in its `🚫 Defer 到 v0.11.0` section.
15
+
16
+ The RFC is written under the **counterfactual assumption** that Vincent decides to pull Hero 3 forward into v0.10.0. If Vincent keeps the defer, all RFC content moves to v0.11.0 planning. **Vincent's call.**
17
+
18
+ The author has not started implementation. No `preview.X+1` code ship has occurred for any Hero 3 item. Two related items (sweep arc retire + recent-signal hide-when-empty) were attempted earlier in the day under the Vincent 5222 Twitter-polish P0 and reverted by concurrent codex edits — those are documented in §3.B below and proposed for re-attempt only after Vincent ✅ on the v0.10.0 scope and codex coordination on the SVG edit region.
19
+
20
+ ---
21
+
22
+ ## 1. Goal & success criteria
23
+
24
+ The single sentence: **A first-time Twitter visitor sees the 16:9 screenshot and groks "多 agent 实时通信可视化 by sleep2agi"** — without "wow 太多花" reaction.
25
+
26
+ Success criteria (each measurable):
27
+
28
+ 1. **First-glance brand recognition** — `sleep2agi` mark visible without scrolling, top-half of card.
29
+ 2. **Multi-vendor multi-agent legibility** — every node's vendor identity is distinguishable at thumbnail size; no two vendors look identical at the 16:9 crop.
30
+ 3. **Visual quietness when idle** — empty/no-flow state has ≤ 1 SMIL animation visible; no animated chrome competing for attention.
31
+ 4. **Information density legible** — chip-row, panels, and overlays don't crowd the canvas; the eye lands on nodes + edges first.
32
+ 5. **Server-health integration** — hovering a node surfaces its host server's health badge (Hero 1+2 integration).
33
+ 6. **Zero regression** on the 6 existing interaction contracts (per `feedback_5291_amendment` regression list).
34
+
35
+ ---
36
+
37
+ ## 2. Current baseline (what shipped, what's held)
38
+
39
+ ### Already shipped this cycle (live in npm preview)
40
+
41
+ | Round / commit | Surface | What |
42
+ |---|---|---|
43
+ | R301 `bbde2b7` | Vendor avatars | claude.svg + openai.svg + minimax.svg custom-designed badges (NOT trademark copies); rendered via `<image href={vendor.logo}>` per existing vendorIdentity.ts logo path |
44
+ | R310 `b6da676` | Title block | Inline 36×36 crescent moon SVG left of the kicker+h2 pair (HTML side, theme-aware cyan/emerald color, racing-safe placement) |
45
+ | R275-R281 | Canvas 减法 | freshness-conditional, orbit retired, halo retired, ping retired, dispatch-pulse retired, spokes retired, vendor-chip threshold tightened |
46
+ | R282 `e1d324b` | Brand watermark | "sleep2agi" text at bottom-left (16, 672) |
47
+ | R283-R289 | Typography | monogram stroke 1→1.5, monogram font monospace→sans-serif, kicker tracking-widest, h2 tracking-tight, watermark letterSpacing 0.5 |
48
+ | R290-R291 | Canvas 减法 | Inner radar ring r=90 retired; starfield 28→14 dots |
49
+ | R294-R296 (codex) | Canvas + chrome | Per-node pulse-dot retired; legend swatch r 5.5→6; kicker color gray-600→500 |
50
+
51
+ ### Held by codex-race / pending Vincent ✅ on this RFC
52
+
53
+ | Item | Why held | Risk |
54
+ |---|---|---|
55
+ | sweep arc retire (rotating wedge) | Codex parallel SVG edits revert each attempt | Low — `false &&` gate idiom proven safe in R278/R279/R280; just needs no-race window |
56
+ | recent-signal panel hide-when-empty | Same codex race | Low — single `flowLinks.length > 0 &&` JSX guard |
57
+ | Canvas (16,16) watermark variant | recent-signal panel occupies that corner; current title-block placement is racing-safer alternative | Already mitigated by §2 title-block shipped |
58
+
59
+ ---
60
+
61
+ ## 3. Proposed changes — per surface
62
+
63
+ Each surface listed with: **A** = additive, **S** = subtractive, **U** = unification. Concrete edit, test impact, race risk.
64
+
65
+ ### 3.A — Hub center polish (A)
66
+
67
+ - Embed a faint crescent silhouette **behind** the working-count digit at the hub center (r=12 mask, opacity 0.18). Reads as "sleep2agi heartbeat" without competing with the digit (R213 hub center).
68
+ - Theme-aware via currentColor on the embedding `<g>`.
69
+ - Risk: minimal — same `<defs>` + mask construction already used in title-block.
70
+
71
+ ### 3.B — Sweep arc retire (S)
72
+
73
+ - Gate the existing radar sweep wedge with `{false && (() => {...})}` — same idiom as R278/R279/R280.
74
+ - Reason: rotating decoration competes with the working-halo pulse + edge flow animation. On a 16:9 Twitter screenshot it reads "wow lots of motion" not "agents communicating".
75
+ - Race-mitigation: ship this in a single small commit, paired with §3.C, immediately after Vincent ✅ on RFC; require codex to hold polish during that window (5min).
76
+
77
+ ### 3.C — Recent-signal panel hide-when-empty (S)
78
+
79
+ - Wrap the `<g data-topo-panel="recent">` block in `{flowLinks.length > 0 && (...)}`.
80
+ - First flow arrival triggers existing R175 fade-in. Empty corner stays clean for the Twitter-grok first impression.
81
+ - Race-mitigation: same window as §3.B.
82
+
83
+ ### 3.D — Grid layout default for ≥ 20 nodes (S of ring-default)
84
+
85
+ - Per [#87](https://github.com/sleep2agi/agent-network/issues/87) shipping ring/grid toggle, now switch the default **when** `sessions.length >= 20`. Below 20 nodes, ring stays prettier; above, grid scales cleaner.
86
+ - Persist user override in `anet-topo-layout` localStorage (existing).
87
+ - Risk: low — toggle UI unchanged; only the bootstrap default expression changes.
88
+
89
+ ### 3.E — Node detail card on hover (A)
90
+
91
+ - Hover a node ≥ 200ms → show a small detail card (220×140 px) anchored next to the node:
92
+ - alias (large)
93
+ - vendor.label · model id
94
+ - runtime label
95
+ - host server line: hostname + CPU% + RAM% (from Hero 1+2 endpoint)
96
+ - last_task / message preview (1 line)
97
+ - Reuses R57 panel chrome + R26 micro-lift idiom.
98
+ - Risk: zero-overlap — card is positioned via existing label-card geometry, just larger when sustained-hover; cancel on mouseleave.
99
+
100
+ ### 3.F — Server-health node-ring tint (A · Hero 1+2 integration)
101
+
102
+ - When a node's host server health is **red** (per Hero 1+2 endpoint), the node's status ring gains a faint amber outer ring (r+8, strokeWidth=2.5, opacity 0.6).
103
+ - Yellow/green pass through unchanged.
104
+ - Operator gets "this agent's machine is in trouble" signal without leaving the topology view.
105
+ - Risk: zero-overlap — outer ring sits OUTSIDE existing R209 hover-ring radius window; tested geometry.
106
+
107
+ ### 3.G — Fullscreen viewport polish (#81 close-out) (U)
108
+
109
+ - Existing fullscreen (R103) currently swaps to `width: 100vw; height: 100vh`. In fullscreen, the topology card chrome (kicker / h2 / chip-row) should hide — only canvas + brand logo visible.
110
+ - Add CSS `:fullscreen` selector or `data-topo-fullscreen=true` attr-driven hide of title-block + chip-row.
111
+ - Brand crescent moon moves into a small top-left overlay inside the SVG (16, 16) since the title-block disappears.
112
+ - Risk: needs careful keyboard-focus handling — ensure Esc still exits.
113
+
114
+ ### 3.H — Chip-row default collapse on idle (S/U)
115
+
116
+ - Chip row (`Ring | Grid | 3 working | 5 online | pressure …`) is fully visible by default. On a fleet with no traffic that's chrome bloat.
117
+ - Default: show only **2 chips** (Ring/Grid layout toggle + working count). The rest hide behind an "Expand" toggle / `…` chevron.
118
+ - Expand state persists in localStorage.
119
+ - Risk: medium — needs UX think. Maybe ship as opt-in via setting, not silent default change.
120
+
121
+ ### 3.I — Canvas (16,16) corner brand mark (A)
122
+
123
+ - In addition to the title-block crescent (R310), add a small (24×24) crescent at canvas viewBox (16, 16) **only when no recent-signal panel is showing** (composes with §3.C).
124
+ - Doubles the brand mark presence on Twitter screenshots — title-block + canvas corner = brand-first.
125
+ - Risk: zero-overlap — gated on the same `flowLinks.length === 0` predicate as §3.C; never co-exists with the panel.
126
+
127
+ ---
128
+
129
+ ## 4. Hero 1+2 integration touchpoints
130
+
131
+ This RFC is the dashboard "consumer" side. The actual data contracts (per [#119](https://github.com/sleep2agi/agent-network/issues/119) + [#99](https://github.com/sleep2agi/agent-network/issues/99)) are owned by:
132
+
133
+ - **agent-node telemetry** → SDK马 / 工程马 (CPU/mem/disk per-agent into `report_status`)
134
+ - **CommHub aggregation** → 通信牛 (`GET /api/servers`, `GET /api/server/:host/health`, `/agents`)
135
+ - **N站马 dashboard UI** consumes these and renders §3.E (hover detail), §3.F (red-server tint), and the standalone ServersDrawer page (Track 1, separate from Hero 3).
136
+
137
+ This RFC does **not** block on those endpoints — §3.E and §3.F render in degraded form (no host fields) when the endpoint is absent, and light up automatically when the endpoint ships.
138
+
139
+ For ServersDrawer (Track 1), I'll mock with a fixture against the §[3] schema in [#119](https://github.com/sleep2agi/agent-network/issues/119) and replace with the real endpoint once 通信牛 confirms the contract.
140
+
141
+ ---
142
+
143
+ ## 5. Risk & rollback
144
+
145
+ ### Concurrent-editor race (per `project_dashboard_concurrent_editors` memory)
146
+
147
+ - All §3 surface items live inside `app/components/TopoGraph.tsx` — high parallel-edit traffic with codex.
148
+ - **Mitigation**: bunch §3.B + §3.C + §3.I into one commit, immediately after Vincent ✅ on RFC; coordinate via commhub that codex holds polish edits for 10 min during the ship.
149
+ - **Rollback**: each subtractive item uses `false && (() => {...})` gating — single-character flip restores.
150
+
151
+ ### Regression coverage (per `feedback_5291_amendment`)
152
+
153
+ Each preview ship verifies:
154
+
155
+ - 9 components render: TopoGraph / ServersDrawer / NodeCard / ChatModal / EventStream / TopBar / VersionSwitcher / ServerCard / AgentTokenChip
156
+ - 6 interactions don't break: avatar click → ChatPopover (#100), drag-resize (#106), node delete cleanup (#74), vendor LOGO render (#96), grid toggle (#87), fullscreen zoom+pan (#81)
157
+ - 5 pages render: `/`, `/admin`, `/chat`, `/messages`, `/profile`
158
+ - `topo-overlap-test.mjs` green grid+ring (0:0:0:0:0)
159
+ - `curl http://dm.vansin.top:3000/` returns 307 (auth redirect; normal)
160
+ - `curl https://anet.sh` returns 200
161
+
162
+ ### Test regressions known from R301 + R310
163
+
164
+ - `topo-monogram-stroke-test` (R283) and `topo-monogram-font-test` (R284) FAIL for known vendors after R301 vendor-logo upgrade (avatar circle replaced with `<image>` for vendors with logos). **Expected** — those R283/R284 fine-grain monogram tests are obsolete for vendors with real logo assets. Unknown-vendor prefix-group fallback assertions still pass. Will retire those two test files in the next ship.
165
+ - `topo-kicker-tracking-test` and `topo-title-tracking-test`: occasional Playwright `waitForSelector` timeout after R310 flex-row title block. Element exists + renders correctly per diagnostic + screenshot. Hydration-timing flake. Will add `await page.waitForFunction(() => document.querySelectorAll('g[data-node]').length >= 2)` before the visibility check.
166
+
167
+ ---
168
+
169
+ ## 6. Phasing
170
+
171
+ Recommended chunking for `preview.X` slots, smallest-blast-radius first:
172
+
173
+ **Wave 1 — racing-safe quick wins (10 min ship + verify, single commit)**:
174
+ - §3.B sweep retire
175
+ - §3.C recent-signal hide-when-empty
176
+ - §3.I canvas (16,16) brand mark (gated on §3.C)
177
+ - → preview.X.0
178
+
179
+ **Wave 2 — incremental polish (no Hero 1+2 dependency)**:
180
+ - §3.A hub-center crescent silhouette
181
+ - §3.D grid default for ≥ 20 nodes
182
+ - §3.G fullscreen viewport polish (#81 close-out)
183
+ - → preview.X.1 / preview.X.2
184
+
185
+ **Wave 3 — Hero 1+2 integration (after 通信牛 endpoint ships)**:
186
+ - §3.E hover detail card
187
+ - §3.F server-health node-ring tint
188
+ - → preview.X.3 / preview.X.4
189
+
190
+ **Wave 4 — UX-think items (opt-in, not silent)**:
191
+ - §3.H chip-row default collapse — gated behind a setting toggle, not auto-applied
192
+ - → preview.X.5
193
+
194
+ ---
195
+
196
+ ## 7. Open questions for Vincent
197
+
198
+ 1. **Defer status**: #140 currently defers Hero 3 (Dashboard 0.5.x major) to v0.11.0. Is the channel-relay correct that you've pulled it forward to v0.10.0? Or does it stay deferred? **If deferred, this RFC moves to v0.11.0 planning.**
199
+
200
+ 2. **Scope inclusion**: of the 9 items (§3.A through §3.I), which are in v0.10.0 scope and which (if any) are dropped? My recommended cut, if any: §3.H (chip-row default collapse) — high UX risk, low first-glance impact.
201
+
202
+ 3. **Server-health hover**: do you want host CPU/RAM in the **hover** card (§3.E), or only on the dedicated ServersDrawer page (Track 1)? Both surfaces the data; hover is denser but adds load on every node lookup.
203
+
204
+ 4. **Brand-mark double-up**: title-block crescent (already shipped R310) + canvas corner crescent (proposed §3.I) — too much logo, or two complementary anchors?
205
+
206
+ 5. **Codex coordination**: §3.B/§3.C/§3.I need a no-race ship window. Acceptable to dispatch a 10-min "codex hold polish" via 通信龙 for the Wave 1 ship?
207
+
208
+ ---
209
+
210
+ ## 8. Non-goals (explicitly out of scope for this RFC)
211
+
212
+ - Hero 1+2 ServersDrawer **page-level** implementation — that's Track 1, a separate RFC slot if needed (current ServersDrawer per #119 v1 already exists).
213
+ - Token usage UI (#114) — Track 3 of v0.10.0, separate UI consumer.
214
+ - Backend changes (commhub endpoints, agent-node telemetry) — Hero 1+2 owned by 通信牛 + SDK马.
215
+ - Fine-grain typography / opacity / tabular-nums work — those are the post-5222 polish loop items that remain HOLD.
216
+
217
+ ---
218
+
219
+ ## 9. Approval gate
220
+
221
+ Implementation does **not** start on any §3 item until:
222
+
223
+ 1. Vincent acks the RFC scope (defer-or-include decision per Question 1) AND
224
+ 2. Vincent picks the §3 subset to actually ship (Question 2) AND
225
+ 3. For Wave 1 specifically, 通信龙 dispatches a 10-min codex polish-hold to avoid edit race AND
226
+ 4. The `topo-overlap-test` invariant is verified green pre-ship.
227
+
228
+ ---
229
+
230
+ *This RFC is markdown-only. No code in this PR / commit. Next step: post as a comment on [#140](https://github.com/sleep2agi/agent-network/issues/140), wait for Vincent review.*
package/package.json CHANGED
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "name": "@sleep2agi/agent-network-dashboard",
3
- "version": "0.4.6",
3
+ "version": "0.5.0",
4
4
  "description": "Agent Network Dashboard — Web UI for managing AI Agent networks",
5
5
  "scripts": {
6
6
  "dev": "next dev",
7
7
  "build": "next build",
8
8
  "start": "next start",
9
9
  "lint": "eslint",
10
- "prepublishOnly": "rm -rf .next && npm run build"
10
+ "prepublishOnly": "[ -f .next/BUILD_ID ] || (echo 'prepublishOnly: .next/BUILD_ID missing — run npm run build first (see commit 05c1ebf body for R224 chunk-500 root cause)' >&2 && exit 1)"
11
11
  },
12
12
  "bin": {
13
13
  "agent-network-dashboard": "./bin/start.js"
@@ -0,0 +1,11 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" fill="none">
2
+ <!-- sleep2agi brand mark: a crescent moon — the "sleep" metaphor in the
3
+ name. Two-shape construction: outer disc minus offset inner disc =
4
+ crescent. uses currentColor so the embedding context can theme it. -->
5
+ <mask id="s2a-moon-mask">
6
+ <rect width="32" height="32" fill="black" />
7
+ <circle cx="16" cy="16" r="13" fill="white" />
8
+ <circle cx="20.5" cy="14.5" r="11" fill="black" />
9
+ </mask>
10
+ <rect width="32" height="32" fill="currentColor" mask="url(#s2a-moon-mask)" />
11
+ </svg>
@@ -0,0 +1,11 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64">
2
+ <!-- Anthropic / Claude vendor mark.
3
+ NOT a copy of the Anthropic trademark — custom designed badge
4
+ in warm-orange palette. 4-rayed sparkle = "AI spark of insight".
5
+ Real Anthropic logo asset still gated on Vincent-direct. -->
6
+ <circle cx="32" cy="32" r="32" fill="hsl(16 32% 22%)" />
7
+ <circle cx="32" cy="32" r="30" fill="none" stroke="hsl(16 48% 54%)" stroke-width="2" />
8
+ <g fill="hsl(20 80% 78%)" transform="translate(32 32)">
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" />
10
+ </g>
11
+ </svg>
@@ -0,0 +1,11 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64">
2
+ <!-- MiniMax vendor mark. NOT a copy of the MiniMax trademark —
3
+ custom designed badge: angular min/max zigzag in warm-red
4
+ palette evokes the function-shape without imitating the official
5
+ mark. Real MiniMax logo asset still gated on Vincent-direct. -->
6
+ <circle cx="32" cy="32" r="32" fill="hsl(18 50% 22%)" />
7
+ <circle cx="32" cy="32" r="30" fill="none" stroke="hsl(18 65% 52%)" stroke-width="2" />
8
+ <polyline points="14,42 22,22 32,42 42,22 50,42"
9
+ fill="none" stroke="hsl(20 80% 80%)" stroke-width="4"
10
+ stroke-linecap="round" stroke-linejoin="round" />
11
+ </svg>
@@ -0,0 +1,12 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64">
2
+ <!-- OpenAI / GPT / Codex vendor mark. NOT a copy of the OpenAI
3
+ trademark — custom designed badge: hexagonal frame + center dot
4
+ in teal palette evokes "geometric AI lattice" without imitating
5
+ the OpenAI knot. Real OpenAI logo asset still gated on Vincent-
6
+ direct. -->
7
+ <circle cx="32" cy="32" r="32" fill="hsl(165 26% 20%)" />
8
+ <circle cx="32" cy="32" r="30" fill="none" stroke="hsl(165 40% 44%)" stroke-width="2" />
9
+ <polygon points="32,12 47,21 47,43 32,52 17,43 17,21"
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%)" />
12
+ </svg>
@@ -0,0 +1,99 @@
1
+ /* v0.10.0 Hero 1+2 — ServersDrawer extension screenshot evidence for #140.
2
+ * Mocks the /api/hub/servers response with disk + history + agents
3
+ * to surface the new expandable detail view. */
4
+ import { chromium } from 'playwright';
5
+ import { readFileSync } from 'node:fs';
6
+
7
+ const out = process.argv[2] || 'screenshots/r293-p0/servers-drawer-expanded';
8
+ const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
9
+ const browser = await chromium.launch({ headless: true });
10
+ const ctx = await browser.newContext({ viewport: { width: 1600, height: 1000 }, deviceScaleFactor: 2 });
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
+ sessionStorage.setItem('anet_v3_auth', '1');
16
+ // Force drawer open + expand the first card by hostname guess.
17
+ localStorage.setItem('anet-servers-drawer', '1');
18
+ localStorage.setItem('anet-servers-drawer-expanded', JSON.stringify(['mock-1', 'mock-2']));
19
+ } catch {}
20
+ });
21
+
22
+ // Mock servers payload with full v0.10.0 schema.
23
+ await ctx.route('**/api/hub/servers*', (route) => {
24
+ route.fulfill({
25
+ json: {
26
+ servers: [
27
+ {
28
+ hostname: 'mock-1',
29
+ ip: '10.0.0.10',
30
+ cpu_load_1min: 2.4,
31
+ cpu_cores: 8,
32
+ mem_used_gb: 18.2,
33
+ mem_total_gb: 32,
34
+ disk_used_gb: 220,
35
+ disk_total_gb: 500,
36
+ cpu_history: [25, 28, 32, 30, 35, 38, 40, 36, 33, 30],
37
+ mem_history: [50, 52, 55, 56, 58, 57, 59, 60, 58, 57],
38
+ agents: [
39
+ { alias: 'claude-1', runtime: 'claude-code-cli', status: 'working', progress: 0.42 },
40
+ { alias: 'codex-1', runtime: 'codex-sdk', status: 'working', progress: 0.18 },
41
+ { alias: 'intern-1', runtime: 'claude-agent-sdk', status: 'idle' },
42
+ ],
43
+ agent_count: 3,
44
+ status: 'online',
45
+ },
46
+ {
47
+ hostname: 'mock-2',
48
+ ip: '10.0.0.11',
49
+ cpu_load_1min: 7.1,
50
+ cpu_cores: 4,
51
+ mem_used_gb: 14.5,
52
+ mem_total_gb: 16,
53
+ disk_used_gb: 460,
54
+ disk_total_gb: 500,
55
+ cpu_history: [80, 88, 92, 95, 96, 94, 93, 91, 90, 89],
56
+ mem_history: [85, 87, 89, 91, 90, 92, 93, 91, 90, 91],
57
+ agents: [
58
+ { alias: 'minimax-busy', runtime: 'claude-code-cli', status: 'working', progress: 0.78 },
59
+ ],
60
+ agent_count: 1,
61
+ status: 'online',
62
+ },
63
+ {
64
+ hostname: 'mock-offline',
65
+ ip: '10.0.0.20',
66
+ cpu_load_1min: null,
67
+ cpu_cores: 0,
68
+ mem_used_gb: null,
69
+ mem_total_gb: null,
70
+ agent_count: 2,
71
+ status: 'offline',
72
+ note: 'last seen 12m ago',
73
+ },
74
+ ],
75
+ },
76
+ });
77
+ });
78
+ await ctx.route('**/api/hub/status*', (r) => r.fulfill({ json: { sessions: [], hub: { networks: [] } } }));
79
+ await ctx.route('**/api/hub/messages*', (r) => r.fulfill({ json: { messages: [] } }));
80
+ await ctx.route('**/api/hub/tasks*', (r) => r.fulfill({ json: { tasks: [] } }));
81
+
82
+ const page = await ctx.newPage();
83
+ await page.goto('http://127.0.0.1:3000/', { waitUntil: 'networkidle' });
84
+ await page.waitForSelector('[data-server-card]', { timeout: 15000 });
85
+ await page.waitForTimeout(800);
86
+
87
+ // Crop to the drawer region only.
88
+ const box = await page.evaluate(() => {
89
+ const aside = document.querySelector('[aria-label="Servers panel"]');
90
+ if (!aside) return null;
91
+ const r = aside.getBoundingClientRect();
92
+ return { x: r.x - 8, y: r.y - 8, width: r.width + 16, height: Math.min(r.height + 16, 980) };
93
+ });
94
+ if (box && box.width > 100) {
95
+ await page.screenshot({ path: `${out}.png`, clip: box });
96
+ }
97
+ await page.screenshot({ path: `${out}-full.png`, fullPage: false });
98
+ console.log(`✅ wrote ${out}.png + ${out}-full.png`);
99
+ await browser.close();