@sleep2agi/agent-network-dashboard 0.4.6-preview.2 → 0.4.6-preview.21

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 (797) hide show
  1. package/.next/BUILD_ID +1 -1
  2. package/.next/build/chunks/{node_modules_13sb.px._.js → 00jm_02mlcew._.js} +167 -167
  3. package/.next/build/chunks/00jm_02mlcew._.js.map +47 -0
  4. package/.next/build/chunks/{[root-of-the-server]__0ubbtyl._.js → [root-of-the-server]__0tgc-8p._.js} +3 -3
  5. package/.next/build/chunks/{[root-of-the-server]__0d-m0h0._.js → [root-of-the-server]__13z64y.._.js} +7 -7
  6. package/.next/build/chunks/{[root-of-the-server]__0d-m0h0._.js.map → [root-of-the-server]__13z64y.._.js.map} +2 -2
  7. package/.next/build/chunks/[turbopack-node]_transforms_postcss_ts_0r4x5ys._.js +13 -0
  8. package/.next/build/chunks/[turbopack]_runtime.js +1 -1
  9. package/.next/build/postcss.js +4 -4
  10. package/.next/build-manifest.json +8 -8
  11. package/.next/diagnostics/route-bundle-stats.json +157 -143
  12. package/.next/fallback-build-manifest.json +3 -3
  13. package/.next/next-minimal-server.js.nft.json +1 -1
  14. package/.next/next-server.js.nft.json +1 -1
  15. package/.next/prerender-manifest.json +3 -3
  16. package/.next/required-server-files.js +4 -4
  17. package/.next/required-server-files.json +4 -4
  18. package/.next/server/app/_global-error/page/build-manifest.json +5 -5
  19. package/.next/server/app/_global-error/page.js +9 -9
  20. package/.next/server/app/_global-error/page.js.nft.json +1 -1
  21. package/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  22. package/.next/server/app/_global-error.html +1 -1
  23. package/.next/server/app/_global-error.rsc +8 -8
  24. package/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +2 -2
  25. package/.next/server/app/_global-error.segments/_full.segment.rsc +8 -8
  26. package/.next/server/app/_global-error.segments/_head.segment.rsc +4 -4
  27. package/.next/server/app/_global-error.segments/_index.segment.rsc +3 -3
  28. package/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  29. package/.next/server/app/_not-found/page/build-manifest.json +5 -5
  30. package/.next/server/app/_not-found/page/next-font-manifest.json +1 -1
  31. package/.next/server/app/_not-found/page.js +12 -12
  32. package/.next/server/app/_not-found/page.js.nft.json +1 -1
  33. package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  34. package/.next/server/app/_not-found.html +2 -2
  35. package/.next/server/app/_not-found.rsc +12 -12
  36. package/.next/server/app/_not-found.segments/_full.segment.rsc +12 -12
  37. package/.next/server/app/_not-found.segments/_head.segment.rsc +4 -4
  38. package/.next/server/app/_not-found.segments/_index.segment.rsc +7 -7
  39. package/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +2 -2
  40. package/.next/server/app/_not-found.segments/_not-found.segment.rsc +3 -3
  41. package/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  42. package/.next/server/app/admin/page/build-manifest.json +5 -5
  43. package/.next/server/app/admin/page/next-font-manifest.json +1 -1
  44. package/.next/server/app/admin/page.js +13 -13
  45. package/.next/server/app/admin/page.js.nft.json +1 -1
  46. package/.next/server/app/admin/page_client-reference-manifest.js +1 -1
  47. package/.next/server/app/admin.html +2 -2
  48. package/.next/server/app/admin.rsc +14 -14
  49. package/.next/server/app/admin.segments/_full.segment.rsc +14 -14
  50. package/.next/server/app/admin.segments/_head.segment.rsc +4 -4
  51. package/.next/server/app/admin.segments/_index.segment.rsc +7 -7
  52. package/.next/server/app/admin.segments/_tree.segment.rsc +2 -2
  53. package/.next/server/app/admin.segments/admin/__PAGE__.segment.rsc +4 -4
  54. package/.next/server/app/admin.segments/admin.segment.rsc +3 -3
  55. package/.next/server/app/api/anet/config/route.js +6 -6
  56. package/.next/server/app/api/anet/config/route.js.nft.json +1 -1
  57. package/.next/server/app/api/auth/login/route.js +7 -7
  58. package/.next/server/app/api/auth/login/route.js.nft.json +1 -1
  59. package/.next/server/app/api/auth/logout/route.js +7 -7
  60. package/.next/server/app/api/auth/logout/route.js.nft.json +1 -1
  61. package/.next/server/app/api/auth/v3/route.js +7 -7
  62. package/.next/server/app/api/auth/v3/route.js.nft.json +1 -1
  63. package/.next/server/app/api/hub/audit-log/route.js +6 -6
  64. package/.next/server/app/api/hub/audit-log/route.js.nft.json +1 -1
  65. package/.next/server/app/api/hub/auth/route.js +7 -7
  66. package/.next/server/app/api/hub/auth/route.js.nft.json +1 -1
  67. package/.next/server/app/api/hub/broadcast/route.js +6 -6
  68. package/.next/server/app/api/hub/broadcast/route.js.nft.json +1 -1
  69. package/.next/server/app/api/hub/events/route.js +6 -6
  70. package/.next/server/app/api/hub/events/route.js.nft.json +1 -1
  71. package/.next/server/app/api/hub/health/route.js +6 -6
  72. package/.next/server/app/api/hub/health/route.js.nft.json +1 -1
  73. package/.next/server/app/api/hub/inbox/route.js +6 -6
  74. package/.next/server/app/api/hub/inbox/route.js.nft.json +1 -1
  75. package/.next/server/app/api/hub/license/route.js +6 -6
  76. package/.next/server/app/api/hub/license/route.js.nft.json +1 -1
  77. package/.next/server/app/api/hub/messages/route.js +6 -6
  78. package/.next/server/app/api/hub/messages/route.js.nft.json +1 -1
  79. package/.next/server/app/api/hub/networks/route.js +6 -6
  80. package/.next/server/app/api/hub/networks/route.js.nft.json +1 -1
  81. package/.next/server/app/api/hub/nodes/route.js +6 -6
  82. package/.next/server/app/api/hub/nodes/route.js.nft.json +1 -1
  83. package/.next/server/app/api/hub/register/route.js +6 -6
  84. package/.next/server/app/api/hub/register/route.js.nft.json +1 -1
  85. package/.next/server/app/api/hub/send/route.js +6 -6
  86. package/.next/server/app/api/hub/send/route.js.nft.json +1 -1
  87. package/.next/server/app/api/hub/server-logs/route.js +6 -6
  88. package/.next/server/app/api/hub/server-logs/route.js.nft.json +1 -1
  89. package/.next/server/app/api/hub/session/route.js +6 -6
  90. package/.next/server/app/api/hub/session/route.js.nft.json +1 -1
  91. package/.next/server/app/api/hub/stats/route.js +6 -6
  92. package/.next/server/app/api/hub/stats/route.js.nft.json +1 -1
  93. package/.next/server/app/api/hub/status/route.js +6 -6
  94. package/.next/server/app/api/hub/status/route.js.nft.json +1 -1
  95. package/.next/server/app/api/hub/task-events/route.js +6 -6
  96. package/.next/server/app/api/hub/task-events/route.js.nft.json +1 -1
  97. package/.next/server/app/api/hub/tasks/route.js +6 -6
  98. package/.next/server/app/api/hub/tasks/route.js.nft.json +1 -1
  99. package/.next/server/app/api/hub/tmux/route.js +6 -6
  100. package/.next/server/app/api/hub/tmux/route.js.nft.json +1 -1
  101. package/.next/server/app/api/hub/tokens/route.js +6 -6
  102. package/.next/server/app/api/hub/tokens/route.js.nft.json +1 -1
  103. package/.next/server/app/favicon.ico/route.js +6 -6
  104. package/.next/server/app/favicon.ico/route.js.nft.json +1 -1
  105. package/.next/server/app/index.html +2 -2
  106. package/.next/server/app/index.rsc +14 -14
  107. package/.next/server/app/index.segments/__PAGE__.segment.rsc +4 -4
  108. package/.next/server/app/index.segments/_full.segment.rsc +14 -14
  109. package/.next/server/app/index.segments/_head.segment.rsc +4 -4
  110. package/.next/server/app/index.segments/_index.segment.rsc +7 -7
  111. package/.next/server/app/index.segments/_tree.segment.rsc +2 -2
  112. package/.next/server/app/login/page/build-manifest.json +5 -5
  113. package/.next/server/app/login/page/next-font-manifest.json +1 -1
  114. package/.next/server/app/login/page.js +13 -13
  115. package/.next/server/app/login/page.js.nft.json +1 -1
  116. package/.next/server/app/login/page_client-reference-manifest.js +1 -1
  117. package/.next/server/app/login.html +2 -2
  118. package/.next/server/app/login.rsc +14 -14
  119. package/.next/server/app/login.segments/_full.segment.rsc +14 -14
  120. package/.next/server/app/login.segments/_head.segment.rsc +4 -4
  121. package/.next/server/app/login.segments/_index.segment.rsc +7 -7
  122. package/.next/server/app/login.segments/_tree.segment.rsc +2 -2
  123. package/.next/server/app/login.segments/login/__PAGE__.segment.rsc +4 -4
  124. package/.next/server/app/login.segments/login.segment.rsc +3 -3
  125. package/.next/server/app/logs/page/build-manifest.json +5 -5
  126. package/.next/server/app/logs/page/next-font-manifest.json +1 -1
  127. package/.next/server/app/logs/page.js +13 -13
  128. package/.next/server/app/logs/page.js.nft.json +1 -1
  129. package/.next/server/app/logs/page_client-reference-manifest.js +1 -1
  130. package/.next/server/app/logs.html +2 -2
  131. package/.next/server/app/logs.rsc +14 -14
  132. package/.next/server/app/logs.segments/_full.segment.rsc +14 -14
  133. package/.next/server/app/logs.segments/_head.segment.rsc +4 -4
  134. package/.next/server/app/logs.segments/_index.segment.rsc +7 -7
  135. package/.next/server/app/logs.segments/_tree.segment.rsc +2 -2
  136. package/.next/server/app/logs.segments/logs/__PAGE__.segment.rsc +4 -4
  137. package/.next/server/app/logs.segments/logs.segment.rsc +3 -3
  138. package/.next/server/app/messages/page/build-manifest.json +5 -5
  139. package/.next/server/app/messages/page/next-font-manifest.json +1 -1
  140. package/.next/server/app/messages/page.js +13 -13
  141. package/.next/server/app/messages/page.js.nft.json +1 -1
  142. package/.next/server/app/messages/page_client-reference-manifest.js +1 -1
  143. package/.next/server/app/messages.html +2 -2
  144. package/.next/server/app/messages.rsc +14 -14
  145. package/.next/server/app/messages.segments/_full.segment.rsc +14 -14
  146. package/.next/server/app/messages.segments/_head.segment.rsc +4 -4
  147. package/.next/server/app/messages.segments/_index.segment.rsc +7 -7
  148. package/.next/server/app/messages.segments/_tree.segment.rsc +2 -2
  149. package/.next/server/app/messages.segments/messages/__PAGE__.segment.rsc +4 -4
  150. package/.next/server/app/messages.segments/messages.segment.rsc +3 -3
  151. package/.next/server/app/node/page/build-manifest.json +5 -5
  152. package/.next/server/app/node/page/next-font-manifest.json +1 -1
  153. package/.next/server/app/node/page.js +13 -13
  154. package/.next/server/app/node/page.js.nft.json +1 -1
  155. package/.next/server/app/node/page_client-reference-manifest.js +1 -1
  156. package/.next/server/app/node.html +2 -2
  157. package/.next/server/app/node.rsc +14 -14
  158. package/.next/server/app/node.segments/_full.segment.rsc +14 -14
  159. package/.next/server/app/node.segments/_head.segment.rsc +4 -4
  160. package/.next/server/app/node.segments/_index.segment.rsc +7 -7
  161. package/.next/server/app/node.segments/_tree.segment.rsc +2 -2
  162. package/.next/server/app/node.segments/node/__PAGE__.segment.rsc +4 -4
  163. package/.next/server/app/node.segments/node.segment.rsc +3 -3
  164. package/.next/server/app/nodes/page/build-manifest.json +5 -5
  165. package/.next/server/app/nodes/page/next-font-manifest.json +1 -1
  166. package/.next/server/app/nodes/page.js +13 -13
  167. package/.next/server/app/nodes/page.js.nft.json +1 -1
  168. package/.next/server/app/nodes/page_client-reference-manifest.js +1 -1
  169. package/.next/server/app/nodes.html +2 -2
  170. package/.next/server/app/nodes.rsc +14 -14
  171. package/.next/server/app/nodes.segments/_full.segment.rsc +14 -14
  172. package/.next/server/app/nodes.segments/_head.segment.rsc +4 -4
  173. package/.next/server/app/nodes.segments/_index.segment.rsc +7 -7
  174. package/.next/server/app/nodes.segments/_tree.segment.rsc +2 -2
  175. package/.next/server/app/nodes.segments/nodes/__PAGE__.segment.rsc +4 -4
  176. package/.next/server/app/nodes.segments/nodes.segment.rsc +3 -3
  177. package/.next/server/app/page/build-manifest.json +5 -5
  178. package/.next/server/app/page/next-font-manifest.json +1 -1
  179. package/.next/server/app/page.js +13 -13
  180. package/.next/server/app/page.js.nft.json +1 -1
  181. package/.next/server/app/page_client-reference-manifest.js +1 -1
  182. package/.next/server/app/server-logs/page/build-manifest.json +5 -5
  183. package/.next/server/app/server-logs/page/next-font-manifest.json +1 -1
  184. package/.next/server/app/server-logs/page.js +13 -13
  185. package/.next/server/app/server-logs/page.js.nft.json +1 -1
  186. package/.next/server/app/server-logs/page_client-reference-manifest.js +1 -1
  187. package/.next/server/app/server-logs.html +2 -2
  188. package/.next/server/app/server-logs.rsc +14 -14
  189. package/.next/server/app/server-logs.segments/_full.segment.rsc +14 -14
  190. package/.next/server/app/server-logs.segments/_head.segment.rsc +4 -4
  191. package/.next/server/app/server-logs.segments/_index.segment.rsc +7 -7
  192. package/.next/server/app/server-logs.segments/_tree.segment.rsc +2 -2
  193. package/.next/server/app/server-logs.segments/server-logs/__PAGE__.segment.rsc +4 -4
  194. package/.next/server/app/server-logs.segments/server-logs.segment.rsc +3 -3
  195. package/.next/server/app/settings/networks/page/build-manifest.json +5 -5
  196. package/.next/server/app/settings/networks/page/next-font-manifest.json +1 -1
  197. package/.next/server/app/settings/networks/page.js +13 -13
  198. package/.next/server/app/settings/networks/page.js.nft.json +1 -1
  199. package/.next/server/app/settings/networks/page_client-reference-manifest.js +1 -1
  200. package/.next/server/app/settings/networks.html +2 -2
  201. package/.next/server/app/settings/networks.rsc +14 -14
  202. package/.next/server/app/settings/networks.segments/_full.segment.rsc +14 -14
  203. package/.next/server/app/settings/networks.segments/_head.segment.rsc +4 -4
  204. package/.next/server/app/settings/networks.segments/_index.segment.rsc +7 -7
  205. package/.next/server/app/settings/networks.segments/_tree.segment.rsc +2 -2
  206. package/.next/server/app/settings/networks.segments/settings/networks/__PAGE__.segment.rsc +4 -4
  207. package/.next/server/app/settings/networks.segments/settings/networks.segment.rsc +3 -3
  208. package/.next/server/app/settings/networks.segments/settings.segment.rsc +3 -3
  209. package/.next/server/app/settings/page/build-manifest.json +5 -5
  210. package/.next/server/app/settings/page/next-font-manifest.json +1 -1
  211. package/.next/server/app/settings/page.js +13 -13
  212. package/.next/server/app/settings/page.js.nft.json +1 -1
  213. package/.next/server/app/settings/page_client-reference-manifest.js +1 -1
  214. package/.next/server/app/settings/tokens/page/build-manifest.json +5 -5
  215. package/.next/server/app/settings/tokens/page/next-font-manifest.json +1 -1
  216. package/.next/server/app/settings/tokens/page.js +13 -13
  217. package/.next/server/app/settings/tokens/page.js.nft.json +1 -1
  218. package/.next/server/app/settings/tokens/page_client-reference-manifest.js +1 -1
  219. package/.next/server/app/settings/tokens.html +2 -2
  220. package/.next/server/app/settings/tokens.rsc +14 -14
  221. package/.next/server/app/settings/tokens.segments/_full.segment.rsc +14 -14
  222. package/.next/server/app/settings/tokens.segments/_head.segment.rsc +4 -4
  223. package/.next/server/app/settings/tokens.segments/_index.segment.rsc +7 -7
  224. package/.next/server/app/settings/tokens.segments/_tree.segment.rsc +2 -2
  225. package/.next/server/app/settings/tokens.segments/settings/tokens/__PAGE__.segment.rsc +4 -4
  226. package/.next/server/app/settings/tokens.segments/settings/tokens.segment.rsc +3 -3
  227. package/.next/server/app/settings/tokens.segments/settings.segment.rsc +3 -3
  228. package/.next/server/app/settings.html +2 -2
  229. package/.next/server/app/settings.rsc +14 -14
  230. package/.next/server/app/settings.segments/_full.segment.rsc +14 -14
  231. package/.next/server/app/settings.segments/_head.segment.rsc +4 -4
  232. package/.next/server/app/settings.segments/_index.segment.rsc +7 -7
  233. package/.next/server/app/settings.segments/_tree.segment.rsc +2 -2
  234. package/.next/server/app/settings.segments/settings/__PAGE__.segment.rsc +4 -4
  235. package/.next/server/app/settings.segments/settings.segment.rsc +3 -3
  236. package/.next/server/app/tasks/[id]/page/build-manifest.json +5 -5
  237. package/.next/server/app/tasks/[id]/page/next-font-manifest.json +1 -1
  238. package/.next/server/app/tasks/[id]/page.js +13 -13
  239. package/.next/server/app/tasks/[id]/page.js.nft.json +1 -1
  240. package/.next/server/app/tasks/[id]/page_client-reference-manifest.js +1 -1
  241. package/.next/server/app/tasks/page/build-manifest.json +5 -5
  242. package/.next/server/app/tasks/page/next-font-manifest.json +1 -1
  243. package/.next/server/app/tasks/page.js +13 -13
  244. package/.next/server/app/tasks/page.js.nft.json +1 -1
  245. package/.next/server/app/tasks/page_client-reference-manifest.js +1 -1
  246. package/.next/server/app/tasks.html +2 -2
  247. package/.next/server/app/tasks.rsc +14 -14
  248. package/.next/server/app/tasks.segments/_full.segment.rsc +14 -14
  249. package/.next/server/app/tasks.segments/_head.segment.rsc +4 -4
  250. package/.next/server/app/tasks.segments/_index.segment.rsc +7 -7
  251. package/.next/server/app/tasks.segments/_tree.segment.rsc +2 -2
  252. package/.next/server/app/tasks.segments/tasks/__PAGE__.segment.rsc +4 -4
  253. package/.next/server/app/tasks.segments/tasks.segment.rsc +3 -3
  254. package/.next/server/chunks/00jm_next_04f3gac._.js +10 -0
  255. package/.next/server/chunks/00jm_next_04f3gac._.js.map +1 -0
  256. package/.next/server/chunks/00jm_next_dist_esm_build_templates_app-route_02f430o.js +3 -0
  257. package/.next/server/chunks/00jm_next_dist_esm_build_templates_app-route_02f430o.js.map +1 -0
  258. package/.next/server/chunks/0ci9_nt-network-dashboard__next-internal_server_app_api_auth_v3_route_actions_0f5nbzr.js +3 -0
  259. package/.next/server/chunks/0ci9_nt-network-dashboard__next-internal_server_app_favicon_ico_route_actions_0t0eu9r.js +3 -0
  260. package/.next/server/chunks/0ykm__next-internal_server_app_api_anet_config_route_actions_0a~v55_.js +3 -0
  261. package/.next/server/chunks/0ykm__next-internal_server_app_api_auth_login_route_actions_0xnxfs4.js +3 -0
  262. package/.next/server/chunks/0ykm__next-internal_server_app_api_auth_logout_route_actions_0p8p0rn.js +3 -0
  263. package/.next/server/chunks/0ykm__next-internal_server_app_api_hub_audit-log_route_actions_06uquwi.js +3 -0
  264. package/.next/server/chunks/0ykm__next-internal_server_app_api_hub_auth_route_actions_0f_y1ey.js +3 -0
  265. package/.next/server/chunks/0ykm__next-internal_server_app_api_hub_broadcast_route_actions_0ao3j43.js +3 -0
  266. package/.next/server/chunks/0ykm__next-internal_server_app_api_hub_events_route_actions_0_5ndld.js +3 -0
  267. package/.next/server/chunks/0ykm__next-internal_server_app_api_hub_health_route_actions_0mpzl74.js +3 -0
  268. package/.next/server/chunks/0ykm__next-internal_server_app_api_hub_inbox_route_actions_0stoyto.js +3 -0
  269. package/.next/server/chunks/0ykm__next-internal_server_app_api_hub_license_route_actions_0a4.fuh.js +3 -0
  270. package/.next/server/chunks/0ykm__next-internal_server_app_api_hub_messages_route_actions_059rw1o.js +3 -0
  271. package/.next/server/chunks/0ykm__next-internal_server_app_api_hub_networks_route_actions_03sehpn.js +3 -0
  272. package/.next/server/chunks/0ykm__next-internal_server_app_api_hub_nodes_route_actions_11fbp28.js +3 -0
  273. package/.next/server/chunks/0ykm__next-internal_server_app_api_hub_register_route_actions_0l.d7~n.js +3 -0
  274. package/.next/server/chunks/0ykm__next-internal_server_app_api_hub_send_route_actions_0.p82vy.js +3 -0
  275. package/.next/server/chunks/0ykm__next-internal_server_app_api_hub_server-logs_route_actions_05~c5lb.js +3 -0
  276. package/.next/server/chunks/0ykm__next-internal_server_app_api_hub_session_route_actions_0b9ef2i.js +3 -0
  277. package/.next/server/chunks/0ykm__next-internal_server_app_api_hub_stats_route_actions_03u65u0.js +3 -0
  278. package/.next/server/chunks/0ykm__next-internal_server_app_api_hub_status_route_actions_0_71ear.js +3 -0
  279. package/.next/server/chunks/0ykm__next-internal_server_app_api_hub_task-events_route_actions_07md_ee.js +3 -0
  280. package/.next/server/chunks/0ykm__next-internal_server_app_api_hub_tasks_route_actions_0er3uvk.js +3 -0
  281. package/.next/server/chunks/0ykm__next-internal_server_app_api_hub_tmux_route_actions_0o_1-8u.js +3 -0
  282. package/.next/server/chunks/0ykm__next-internal_server_app_api_hub_tokens_route_actions_09doluz.js +3 -0
  283. package/.next/server/chunks/[root-of-the-server]__0-2le8-._.js +3 -0
  284. package/.next/server/chunks/[root-of-the-server]__0-2le8-._.js.map +1 -0
  285. package/.next/server/chunks/[root-of-the-server]__0-g~15e._.js +3 -0
  286. package/.next/server/chunks/[root-of-the-server]__0-g~15e._.js.map +1 -0
  287. package/.next/server/chunks/[root-of-the-server]__00194.t._.js +3 -0
  288. package/.next/server/chunks/{[root-of-the-server]__03ueci3._.js.map → [root-of-the-server]__00194.t._.js.map} +1 -1
  289. package/.next/server/chunks/[root-of-the-server]__02p2n3n._.js +3 -0
  290. package/.next/server/chunks/[root-of-the-server]__02p2n3n._.js.map +1 -0
  291. package/.next/server/chunks/[root-of-the-server]__02y-i-p._.js +6 -0
  292. package/.next/server/chunks/[root-of-the-server]__02y-i-p._.js.map +1 -0
  293. package/.next/server/chunks/[root-of-the-server]__043tnx2._.js +3 -0
  294. package/.next/server/chunks/{[root-of-the-server]__0o4qfn9._.js.map → [root-of-the-server]__043tnx2._.js.map} +1 -1
  295. package/.next/server/chunks/[root-of-the-server]__04z62zk._.js +3 -0
  296. package/.next/server/chunks/[root-of-the-server]__04z62zk._.js.map +1 -0
  297. package/.next/server/chunks/[root-of-the-server]__06p6kkp._.js +3 -0
  298. package/.next/server/chunks/[root-of-the-server]__06p6kkp._.js.map +1 -0
  299. package/.next/server/chunks/[root-of-the-server]__07ztet2._.js +3 -0
  300. package/.next/server/chunks/[root-of-the-server]__07ztet2._.js.map +1 -0
  301. package/.next/server/chunks/[root-of-the-server]__08uyvdq._.js +20 -0
  302. package/.next/server/chunks/[root-of-the-server]__08uyvdq._.js.map +1 -0
  303. package/.next/server/chunks/[root-of-the-server]__0b7v51y._.js +3 -0
  304. package/.next/server/chunks/[root-of-the-server]__0b7v51y._.js.map +1 -0
  305. package/.next/server/chunks/[root-of-the-server]__0e3ucl1._.js +3 -0
  306. package/.next/server/chunks/{[root-of-the-server]__0rg9ifx._.js.map → [root-of-the-server]__0e3ucl1._.js.map} +1 -1
  307. package/.next/server/chunks/[root-of-the-server]__0e6yail._.js +3 -0
  308. package/.next/server/chunks/[root-of-the-server]__0e6yail._.js.map +1 -0
  309. package/.next/server/chunks/[root-of-the-server]__0gx2_6a._.js +3 -0
  310. package/.next/server/chunks/[root-of-the-server]__0gx2_6a._.js.map +1 -0
  311. package/.next/server/chunks/[root-of-the-server]__0hcnyp.._.js +3 -0
  312. package/.next/server/chunks/{[root-of-the-server]__0o29v8c._.js.map → [root-of-the-server]__0hcnyp.._.js.map} +1 -1
  313. package/.next/server/chunks/[root-of-the-server]__0hg3_8r._.js +3 -0
  314. package/.next/server/chunks/[root-of-the-server]__0hg3_8r._.js.map +1 -0
  315. package/.next/server/chunks/[root-of-the-server]__0mxw4vb._.js +3 -0
  316. package/.next/server/chunks/[root-of-the-server]__0mxw4vb._.js.map +1 -0
  317. package/.next/server/chunks/[root-of-the-server]__0mzopco._.js +3 -0
  318. package/.next/server/chunks/[root-of-the-server]__0mzopco._.js.map +1 -0
  319. package/.next/server/chunks/[root-of-the-server]__0o45a4q._.js +3 -0
  320. package/.next/server/chunks/{[root-of-the-server]__0p6tutt._.js.map → [root-of-the-server]__0o45a4q._.js.map} +1 -1
  321. package/.next/server/chunks/[root-of-the-server]__0q-teo6._.js +3 -0
  322. package/.next/server/chunks/[root-of-the-server]__0q-teo6._.js.map +1 -0
  323. package/.next/server/chunks/[root-of-the-server]__0qcxxzf._.js +3 -0
  324. package/.next/server/chunks/[root-of-the-server]__0qcxxzf._.js.map +1 -0
  325. package/.next/server/chunks/[root-of-the-server]__0rovr5-._.js +3 -0
  326. package/.next/server/chunks/[root-of-the-server]__0rovr5-._.js.map +1 -0
  327. package/.next/server/chunks/[root-of-the-server]__0xtp-et._.js +3 -0
  328. package/.next/server/chunks/[root-of-the-server]__0xtp-et._.js.map +1 -0
  329. package/.next/server/chunks/[root-of-the-server]__10pvabe._.js +3 -0
  330. package/.next/server/chunks/[root-of-the-server]__10pvabe._.js.map +1 -0
  331. package/.next/server/chunks/[root-of-the-server]__10t11zq._.js +3 -0
  332. package/.next/server/chunks/[root-of-the-server]__10t11zq._.js.map +1 -0
  333. package/.next/server/chunks/[root-of-the-server]__12r~omy._.js +3 -0
  334. package/.next/server/chunks/[root-of-the-server]__12r~omy._.js.map +1 -0
  335. package/.next/server/chunks/[root-of-the-server]__1389~cs._.js +3 -0
  336. package/.next/server/chunks/[root-of-the-server]__1389~cs._.js.map +1 -0
  337. package/.next/server/chunks/[root-of-the-server]__13n8t..._.js +3 -0
  338. package/.next/server/chunks/[root-of-the-server]__13n8t..._.js.map +1 -0
  339. package/.next/server/chunks/[turbopack]_runtime.js +1 -1
  340. package/.next/server/chunks/ssr/{node_modules_0r_.s40._.js → 00jm_03rn9vn._.js} +2 -2
  341. package/.next/server/chunks/ssr/00jm_03rn9vn._.js.map +1 -0
  342. package/.next/server/chunks/ssr/{node_modules_09w7yel._.js → 00jm_059ns68._.js} +3 -3
  343. package/.next/server/chunks/ssr/00jm_059ns68._.js.map +1 -0
  344. package/.next/server/chunks/ssr/00jm_09ae-q0._.js +3 -0
  345. package/.next/server/chunks/ssr/00jm_09ae-q0._.js.map +1 -0
  346. package/.next/server/chunks/ssr/00jm_0j7__z.._.js +3 -0
  347. package/.next/server/chunks/ssr/00jm_0j7__z.._.js.map +1 -0
  348. package/.next/server/chunks/ssr/00jm_next_01-0urn._.js +6 -0
  349. package/.next/server/chunks/ssr/00jm_next_01-0urn._.js.map +1 -0
  350. package/.next/server/chunks/ssr/00jm_next_dist_05rlh5d._.js +6 -0
  351. package/.next/server/chunks/ssr/00jm_next_dist_05rlh5d._.js.map +1 -0
  352. package/.next/server/chunks/ssr/00jm_next_dist_client_components_0gkudcq._.js +3 -0
  353. package/.next/server/chunks/ssr/00jm_next_dist_client_components_0gkudcq._.js.map +1 -0
  354. package/.next/server/chunks/ssr/00jm_next_dist_client_components_builtin_forbidden_0ecus3e.js +3 -0
  355. package/.next/server/chunks/ssr/00jm_next_dist_client_components_builtin_forbidden_0ecus3e.js.map +1 -0
  356. package/.next/server/chunks/ssr/00jm_next_dist_client_components_builtin_global-error_07n8pg2.js +3 -0
  357. package/.next/server/chunks/ssr/00jm_next_dist_client_components_builtin_global-error_07n8pg2.js.map +1 -0
  358. package/.next/server/chunks/ssr/00jm_next_dist_client_components_builtin_unauthorized_0r0uq4j.js +3 -0
  359. package/.next/server/chunks/ssr/00jm_next_dist_client_components_builtin_unauthorized_0r0uq4j.js.map +1 -0
  360. package/.next/server/chunks/ssr/{node_modules_next_dist_esm_build_templates_app-page_002l7yi.js → 00jm_next_dist_esm_build_templates_app-page_0..ddwm.js} +3 -3
  361. package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_0..ddwm.js.map +1 -0
  362. package/.next/server/chunks/ssr/{node_modules_next_dist_esm_build_templates_app-page_0qm1-a1.js → 00jm_next_dist_esm_build_templates_app-page_02bxi6j.js} +3 -3
  363. package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_02bxi6j.js.map +1 -0
  364. package/.next/server/chunks/ssr/{node_modules_next_dist_esm_build_templates_app-page_02suzhc.js → 00jm_next_dist_esm_build_templates_app-page_05oassd.js} +3 -3
  365. package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_05oassd.js.map +1 -0
  366. package/.next/server/chunks/ssr/{node_modules_next_dist_esm_build_templates_app-page_0dm~kj8.js → 00jm_next_dist_esm_build_templates_app-page_05vxtby.js} +3 -3
  367. package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_05vxtby.js.map +1 -0
  368. package/.next/server/chunks/ssr/{node_modules_next_dist_esm_build_templates_app-page_0uccf9z.js → 00jm_next_dist_esm_build_templates_app-page_05~eml4.js} +3 -3
  369. package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_05~eml4.js.map +1 -0
  370. package/.next/server/chunks/ssr/{node_modules_next_dist_esm_build_templates_app-page_0l-fh0i.js → 00jm_next_dist_esm_build_templates_app-page_0_-g_q2.js} +3 -3
  371. package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_0_-g_q2.js.map +1 -0
  372. package/.next/server/chunks/ssr/{node_modules_next_dist_esm_build_templates_app-page_0uv6jyc.js → 00jm_next_dist_esm_build_templates_app-page_0_ec0xu.js} +3 -3
  373. package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_0_ec0xu.js.map +1 -0
  374. package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_0czb6wz.js +4 -0
  375. package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_0czb6wz.js.map +1 -0
  376. package/.next/server/chunks/ssr/{node_modules_next_dist_esm_build_templates_app-page_13s07li.js → 00jm_next_dist_esm_build_templates_app-page_0e-cn.p.js} +3 -3
  377. package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_0e-cn.p.js.map +1 -0
  378. package/.next/server/chunks/ssr/{node_modules_next_dist_esm_build_templates_app-page_0o9vt1n.js → 00jm_next_dist_esm_build_templates_app-page_0k8_sr8.js} +3 -3
  379. package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_0k8_sr8.js.map +1 -0
  380. package/.next/server/chunks/ssr/{node_modules_next_dist_esm_build_templates_app-page_0nsg22r.js → 00jm_next_dist_esm_build_templates_app-page_0lt_3bw.js} +3 -3
  381. package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_0lt_3bw.js.map +1 -0
  382. package/.next/server/chunks/ssr/{node_modules_next_dist_esm_build_templates_app-page_0d2yq5t.js → 00jm_next_dist_esm_build_templates_app-page_0uyh3yt.js} +3 -3
  383. package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_0uyh3yt.js.map +1 -0
  384. package/.next/server/chunks/ssr/{node_modules_next_dist_esm_build_templates_app-page_0foejvu.js → 00jm_next_dist_esm_build_templates_app-page_0v-a2ps.js} +3 -3
  385. package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_0v-a2ps.js.map +1 -0
  386. package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_12.4r9~.js +4 -0
  387. package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_12.4r9~.js.map +1 -0
  388. package/.next/server/chunks/ssr/{node_modules_next_dist_esm_build_templates_app-page_07uu-xq.js → 00jm_next_dist_esm_build_templates_app-page_13mqkay.js} +3 -3
  389. package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_13mqkay.js.map +1 -0
  390. package/.next/server/chunks/ssr/0dwh_ent-network-dashboard__next-internal_server_app_server-logs_page_actions_0hkk815.js +3 -0
  391. package/.next/server/chunks/ssr/0yas_gent-network-dashboard__next-internal_server_app__not-found_page_actions_0u.f-rz.js +3 -0
  392. package/.next/server/chunks/ssr/0yas_gent-network-dashboard__next-internal_server_app_tasks_[id]_page_actions_0r3~lho.js +3 -0
  393. package/.next/server/chunks/ssr/0ykm__next-internal_server_app__global-error_page_actions_100fxls.js +3 -0
  394. package/.next/server/chunks/ssr/0ykm__next-internal_server_app_settings_networks_page_actions_0jgy57m.js +3 -0
  395. package/.next/server/chunks/ssr/0ykm__next-internal_server_app_settings_tokens_page_actions_0l5h.k~.js +3 -0
  396. package/.next/server/chunks/ssr/[root-of-the-server]__030vg4n._.js +3 -0
  397. package/.next/server/chunks/ssr/[root-of-the-server]__030vg4n._.js.map +1 -0
  398. package/.next/server/chunks/ssr/[root-of-the-server]__03b.f76._.js +3 -0
  399. package/.next/server/chunks/ssr/[root-of-the-server]__03b.f76._.js.map +1 -0
  400. package/.next/server/chunks/ssr/[root-of-the-server]__063~dul._.js +3 -0
  401. package/.next/server/chunks/ssr/[root-of-the-server]__063~dul._.js.map +1 -0
  402. package/.next/server/chunks/ssr/[root-of-the-server]__07io.d8._.js +3 -0
  403. package/.next/server/chunks/ssr/[root-of-the-server]__07io.d8._.js.map +1 -0
  404. package/.next/server/chunks/ssr/[root-of-the-server]__08d6lp4._.js +3 -0
  405. package/.next/server/chunks/ssr/[root-of-the-server]__08d6lp4._.js.map +1 -0
  406. package/.next/server/chunks/ssr/[root-of-the-server]__09f1wn6._.js +3 -0
  407. package/.next/server/chunks/ssr/[root-of-the-server]__09f1wn6._.js.map +1 -0
  408. package/.next/server/chunks/ssr/[root-of-the-server]__0c4xtkg._.js +3 -0
  409. package/.next/server/chunks/ssr/[root-of-the-server]__0c4xtkg._.js.map +1 -0
  410. package/.next/server/chunks/ssr/[root-of-the-server]__0erfzjn._.js +3 -0
  411. package/.next/server/chunks/ssr/[root-of-the-server]__0erfzjn._.js.map +1 -0
  412. package/.next/server/chunks/ssr/[root-of-the-server]__0ezjwje._.js +3 -0
  413. package/.next/server/chunks/ssr/[root-of-the-server]__0ezjwje._.js.map +1 -0
  414. package/.next/server/chunks/ssr/[root-of-the-server]__0fhoq8i._.js +3 -0
  415. package/.next/server/chunks/ssr/[root-of-the-server]__0fhoq8i._.js.map +1 -0
  416. package/.next/server/chunks/ssr/{[root-of-the-server]__08qr2ji._.js → [root-of-the-server]__0gc.4uk._.js} +3 -3
  417. package/.next/server/chunks/ssr/[root-of-the-server]__0gc.4uk._.js.map +1 -0
  418. package/.next/server/chunks/ssr/[root-of-the-server]__0h_p~-4._.js +19 -0
  419. package/.next/server/chunks/ssr/[root-of-the-server]__0h_p~-4._.js.map +1 -0
  420. package/.next/server/chunks/ssr/[root-of-the-server]__0jdr1e5._.js +3 -0
  421. package/.next/server/chunks/ssr/[root-of-the-server]__0jdr1e5._.js.map +1 -0
  422. package/.next/server/chunks/ssr/[root-of-the-server]__0lw16mu._.js +3 -0
  423. package/.next/server/chunks/ssr/[root-of-the-server]__0lw16mu._.js.map +1 -0
  424. package/.next/server/chunks/ssr/[root-of-the-server]__0mjly~-._.js +33 -0
  425. package/.next/server/chunks/ssr/[root-of-the-server]__0mjly~-._.js.map +1 -0
  426. package/.next/server/chunks/ssr/[root-of-the-server]__0nw~zhp._.js +3 -0
  427. package/.next/server/chunks/ssr/[root-of-the-server]__0nw~zhp._.js.map +1 -0
  428. package/.next/server/chunks/ssr/[root-of-the-server]__0p-95r_._.js +3 -0
  429. package/.next/server/chunks/ssr/[root-of-the-server]__0p-95r_._.js.map +1 -0
  430. package/.next/server/chunks/ssr/[root-of-the-server]__0u5aqkk._.js +8 -0
  431. package/.next/server/chunks/ssr/[root-of-the-server]__0u5aqkk._.js.map +1 -0
  432. package/.next/server/chunks/ssr/[root-of-the-server]__0ue5.fy._.js +3 -0
  433. package/.next/server/chunks/ssr/[root-of-the-server]__0ue5.fy._.js.map +1 -0
  434. package/.next/server/chunks/ssr/[root-of-the-server]__0uggxvx._.js +3 -0
  435. package/.next/server/chunks/ssr/[root-of-the-server]__0uggxvx._.js.map +1 -0
  436. package/.next/server/chunks/ssr/[root-of-the-server]__0zjk5ro._.js +3 -0
  437. package/.next/server/chunks/ssr/[root-of-the-server]__0zjk5ro._.js.map +1 -0
  438. package/.next/server/chunks/ssr/[root-of-the-server]__0zz3v7a._.js +3 -0
  439. package/.next/server/chunks/ssr/[root-of-the-server]__0zz3v7a._.js.map +1 -0
  440. package/.next/server/chunks/ssr/[root-of-the-server]__0~y12ef._.js +3 -0
  441. package/.next/server/chunks/ssr/[root-of-the-server]__0~y12ef._.js.map +1 -0
  442. package/.next/server/chunks/ssr/[root-of-the-server]__129sc_9._.js +3 -0
  443. package/.next/server/chunks/ssr/[root-of-the-server]__129sc_9._.js.map +1 -0
  444. package/.next/server/chunks/ssr/[turbopack]_runtime.js +1 -1
  445. package/.next/server/chunks/ssr/agent-network-dashboard_09kk21a._.js +3 -0
  446. package/.next/server/chunks/ssr/agent-network-dashboard_09kk21a._.js.map +1 -0
  447. package/.next/server/chunks/ssr/agent-network-dashboard__next-internal_server_app_admin_page_actions_0i~.x~j.js +3 -0
  448. package/.next/server/chunks/ssr/agent-network-dashboard__next-internal_server_app_login_page_actions_0frwl15.js +3 -0
  449. package/.next/server/chunks/ssr/agent-network-dashboard__next-internal_server_app_logs_page_actions_0xa2ox_.js +3 -0
  450. package/.next/server/chunks/ssr/agent-network-dashboard__next-internal_server_app_messages_page_actions_10j3tg4.js +3 -0
  451. package/.next/server/chunks/ssr/agent-network-dashboard__next-internal_server_app_node_page_actions_0sl4ntd.js +3 -0
  452. package/.next/server/chunks/ssr/agent-network-dashboard__next-internal_server_app_nodes_page_actions_0cpgkfs.js +3 -0
  453. package/.next/server/chunks/ssr/agent-network-dashboard__next-internal_server_app_page_actions_08nuo36.js +3 -0
  454. package/.next/server/chunks/ssr/agent-network-dashboard__next-internal_server_app_settings_page_actions_0iv.lmk.js +3 -0
  455. package/.next/server/chunks/ssr/agent-network-dashboard__next-internal_server_app_tasks_page_actions_08c7qlx.js +3 -0
  456. package/.next/server/chunks/ssr/agent-network-dashboard_app_01jhlxz._.js +3 -0
  457. package/.next/server/chunks/ssr/agent-network-dashboard_app_01jhlxz._.js.map +1 -0
  458. package/.next/server/chunks/ssr/agent-network-dashboard_app_057q.ne._.js +3 -0
  459. package/.next/server/chunks/ssr/agent-network-dashboard_app_057q.ne._.js.map +1 -0
  460. package/.next/server/chunks/ssr/agent-network-dashboard_app_09d29my._.js +3 -0
  461. package/.next/server/chunks/ssr/agent-network-dashboard_app_09d29my._.js.map +1 -0
  462. package/.next/server/chunks/ssr/agent-network-dashboard_app_0_d45-d._.js +3 -0
  463. package/.next/server/chunks/ssr/agent-network-dashboard_app_0_d45-d._.js.map +1 -0
  464. package/.next/server/chunks/ssr/agent-network-dashboard_app_0i3759l._.js +3 -0
  465. package/.next/server/chunks/ssr/agent-network-dashboard_app_0i3759l._.js.map +1 -0
  466. package/.next/server/chunks/ssr/{app_0izi28j._.js → agent-network-dashboard_app_0xgney8._.js} +2 -2
  467. package/.next/server/chunks/ssr/agent-network-dashboard_app_0xgney8._.js.map +1 -0
  468. package/.next/server/chunks/ssr/{app_0_agk0r._.js → agent-network-dashboard_app_10hjgv4._.js} +2 -2
  469. package/.next/server/chunks/ssr/agent-network-dashboard_app_10hjgv4._.js.map +1 -0
  470. package/.next/server/chunks/ssr/{app_0.zbtn5._.js → agent-network-dashboard_app_1153xeb._.js} +2 -2
  471. package/.next/server/chunks/ssr/agent-network-dashboard_app_1153xeb._.js.map +1 -0
  472. package/.next/server/chunks/ssr/{app_04n78pr._.js → agent-network-dashboard_app_12l4oto._.js} +2 -2
  473. package/.next/server/chunks/ssr/agent-network-dashboard_app_12l4oto._.js.map +1 -0
  474. package/.next/server/chunks/ssr/{app_components_08ys5y3._.js → agent-network-dashboard_app_components_0mvyi-4._.js} +3 -3
  475. package/.next/server/chunks/ssr/agent-network-dashboard_app_components_0mvyi-4._.js.map +1 -0
  476. package/.next/server/chunks/ssr/{app_server-logs_page_tsx_0_kpp1p._.js → agent-network-dashboard_app_server-logs_page_tsx_0dg.l_8._.js} +2 -2
  477. package/.next/server/chunks/ssr/agent-network-dashboard_app_server-logs_page_tsx_0dg.l_8._.js.map +1 -0
  478. package/.next/server/chunks/ssr/agent-network-dashboard_app_tasks_page_tsx_0mwxy4z._.js +3 -0
  479. package/.next/server/chunks/ssr/agent-network-dashboard_app_tasks_page_tsx_0mwxy4z._.js.map +1 -0
  480. package/.next/server/middleware-build-manifest.js +8 -8
  481. package/.next/server/middleware.js +3 -3
  482. package/.next/server/middleware.js.nft.json +1 -1
  483. package/.next/server/next-font-manifest.js +1 -1
  484. package/.next/server/next-font-manifest.json +14 -14
  485. package/.next/server/pages/404.html +2 -2
  486. package/.next/server/pages/500.html +1 -1
  487. package/.next/server/server-reference-manifest.js +1 -1
  488. package/.next/server/server-reference-manifest.json +1 -1
  489. package/.next/static/chunks/0-7iowzu4.798.js +1 -0
  490. package/.next/static/chunks/{0gtbwcilfu6b7.js → 0.66f3.rtcybb.js} +1 -1
  491. package/.next/static/chunks/01j59m93~ijpq.js +1 -0
  492. package/.next/static/chunks/02t5jr4shh.hy.js +1 -0
  493. package/.next/static/chunks/039-b.v_9-_rm.js +1 -0
  494. package/.next/static/chunks/05oi25hh7b81r.js +31 -0
  495. package/.next/static/chunks/07~8sx3_5uiox.js +1 -0
  496. package/.next/static/chunks/09nd.t_hd.y6t.css +2 -0
  497. package/.next/static/chunks/{0pqt~8bl3ukh4.js → 0_pxg.4pebw__.js} +2 -2
  498. package/.next/static/chunks/0_qfg5s5uzs7..js +7 -0
  499. package/.next/static/chunks/0b8wnt4put-5n.js +2 -0
  500. package/.next/static/chunks/0elalb9n_.~di.js +1 -0
  501. package/.next/static/chunks/{01xlw8hd842-c.js → 0eov~nkwaf-qa.js} +1 -1
  502. package/.next/static/chunks/{0-hlcuoemhe7w.js → 0fqy_0wj_1xa7.js} +3 -3
  503. package/.next/static/chunks/0j_q__o8p6g83.js +1 -0
  504. package/.next/static/chunks/0jl6_w50zh4l5.js +1 -0
  505. package/.next/static/chunks/{0w1zwt8kq_7nb.js → 0ku0fjqlm9mca.js} +1 -1
  506. package/.next/static/chunks/0ms~5~zq93-vs.js +1 -0
  507. package/.next/static/chunks/0nh4tljy5z5ns.js +1 -0
  508. package/.next/static/chunks/0r4q73.-1bkyl.js +1 -0
  509. package/.next/static/chunks/0r_c8eccg3z2o.js +1 -0
  510. package/.next/static/chunks/0tvn2l1pc.h65.js +1 -0
  511. package/.next/static/chunks/0u3b93reo9xci.js +1 -0
  512. package/.next/static/chunks/10oi7l-tycgl9.js +1 -0
  513. package/.next/static/chunks/11uk1izuv3~0t.js +1 -0
  514. package/.next/static/chunks/{turbopack-01f1xs~cq_~si.js → turbopack-0.7dvsf9rllt0.js} +1 -1
  515. package/.next/trace +2 -2
  516. package/.next/trace-build +1 -1
  517. package/app/components/AppShell.tsx +2 -0
  518. package/app/components/ChatPopover.tsx +6 -6
  519. package/app/components/ServersDrawer.tsx +169 -0
  520. package/app/components/TaskChatPanel.tsx +39 -39
  521. package/app/components/TopoGraph.tsx +589 -111
  522. package/app/components/types.ts +7 -0
  523. package/app/lib/vendorIdentity.ts +145 -0
  524. package/app/page.tsx +18 -1
  525. package/package.json +1 -1
  526. package/scripts/chat-popover-test.mjs +2 -0
  527. package/scripts/chat-theme-test.mjs +98 -0
  528. package/scripts/topo-chat-focus-ring-test.mjs +77 -0
  529. package/scripts/topo-groupbox-test.mjs +118 -0
  530. package/scripts/topo-layout-test.mjs +113 -0
  531. package/scripts/topo-overlap-test.mjs +137 -0
  532. package/scripts/topo-p0round-test.mjs +166 -0
  533. package/scripts/topo-rename-test.mjs +107 -0
  534. package/scripts/topo-vendor-test.mjs +97 -0
  535. package/.next/build/chunks/[turbopack-node]_transforms_postcss_ts_06e.r3r._.js +0 -13
  536. package/.next/build/chunks/node_modules_13sb.px._.js.map +0 -47
  537. package/.next/server/chunks/[root-of-the-server]__0-mykaf._.js +0 -3
  538. package/.next/server/chunks/[root-of-the-server]__0-mykaf._.js.map +0 -1
  539. package/.next/server/chunks/[root-of-the-server]__0.d_kqy._.js +0 -3
  540. package/.next/server/chunks/[root-of-the-server]__0.d_kqy._.js.map +0 -1
  541. package/.next/server/chunks/[root-of-the-server]__02pocyg._.js +0 -3
  542. package/.next/server/chunks/[root-of-the-server]__02pocyg._.js.map +0 -1
  543. package/.next/server/chunks/[root-of-the-server]__03ueci3._.js +0 -3
  544. package/.next/server/chunks/[root-of-the-server]__04aud7x._.js +0 -3
  545. package/.next/server/chunks/[root-of-the-server]__04aud7x._.js.map +0 -1
  546. package/.next/server/chunks/[root-of-the-server]__05fnt3n._.js +0 -3
  547. package/.next/server/chunks/[root-of-the-server]__05fnt3n._.js.map +0 -1
  548. package/.next/server/chunks/[root-of-the-server]__077tsd.._.js +0 -20
  549. package/.next/server/chunks/[root-of-the-server]__077tsd.._.js.map +0 -1
  550. package/.next/server/chunks/[root-of-the-server]__08wy1jr._.js +0 -3
  551. package/.next/server/chunks/[root-of-the-server]__08wy1jr._.js.map +0 -1
  552. package/.next/server/chunks/[root-of-the-server]__0adhu1m._.js +0 -3
  553. package/.next/server/chunks/[root-of-the-server]__0adhu1m._.js.map +0 -1
  554. package/.next/server/chunks/[root-of-the-server]__0aqv02v._.js +0 -3
  555. package/.next/server/chunks/[root-of-the-server]__0aqv02v._.js.map +0 -1
  556. package/.next/server/chunks/[root-of-the-server]__0cawhfq._.js +0 -3
  557. package/.next/server/chunks/[root-of-the-server]__0cawhfq._.js.map +0 -1
  558. package/.next/server/chunks/[root-of-the-server]__0d_-_k.._.js +0 -3
  559. package/.next/server/chunks/[root-of-the-server]__0d_-_k.._.js.map +0 -1
  560. package/.next/server/chunks/[root-of-the-server]__0f6bxfl._.js +0 -3
  561. package/.next/server/chunks/[root-of-the-server]__0f6bxfl._.js.map +0 -1
  562. package/.next/server/chunks/[root-of-the-server]__0h15edq._.js +0 -3
  563. package/.next/server/chunks/[root-of-the-server]__0h15edq._.js.map +0 -1
  564. package/.next/server/chunks/[root-of-the-server]__0k.vegl._.js +0 -3
  565. package/.next/server/chunks/[root-of-the-server]__0k.vegl._.js.map +0 -1
  566. package/.next/server/chunks/[root-of-the-server]__0kltbce._.js +0 -3
  567. package/.next/server/chunks/[root-of-the-server]__0kltbce._.js.map +0 -1
  568. package/.next/server/chunks/[root-of-the-server]__0mn04fw._.js +0 -3
  569. package/.next/server/chunks/[root-of-the-server]__0mn04fw._.js.map +0 -1
  570. package/.next/server/chunks/[root-of-the-server]__0o29v8c._.js +0 -3
  571. package/.next/server/chunks/[root-of-the-server]__0o4qfn9._.js +0 -3
  572. package/.next/server/chunks/[root-of-the-server]__0o7ya7r._.js +0 -3
  573. package/.next/server/chunks/[root-of-the-server]__0o7ya7r._.js.map +0 -1
  574. package/.next/server/chunks/[root-of-the-server]__0p3fo6l._.js +0 -6
  575. package/.next/server/chunks/[root-of-the-server]__0p3fo6l._.js.map +0 -1
  576. package/.next/server/chunks/[root-of-the-server]__0p6tutt._.js +0 -3
  577. package/.next/server/chunks/[root-of-the-server]__0pn3wsx._.js +0 -3
  578. package/.next/server/chunks/[root-of-the-server]__0pn3wsx._.js.map +0 -1
  579. package/.next/server/chunks/[root-of-the-server]__0rg9ifx._.js +0 -3
  580. package/.next/server/chunks/[root-of-the-server]__0x.-194._.js +0 -3
  581. package/.next/server/chunks/[root-of-the-server]__0x.-194._.js.map +0 -1
  582. package/.next/server/chunks/[root-of-the-server]__0x.a_yh._.js +0 -3
  583. package/.next/server/chunks/[root-of-the-server]__0x.a_yh._.js.map +0 -1
  584. package/.next/server/chunks/[root-of-the-server]__0~h2uqi._.js +0 -3
  585. package/.next/server/chunks/[root-of-the-server]__0~h2uqi._.js.map +0 -1
  586. package/.next/server/chunks/[root-of-the-server]__139~d6a._.js +0 -3
  587. package/.next/server/chunks/[root-of-the-server]__139~d6a._.js.map +0 -1
  588. package/.next/server/chunks/_next-internal_server_app_api_anet_config_route_actions_0xzy73j.js +0 -3
  589. package/.next/server/chunks/_next-internal_server_app_api_auth_login_route_actions_0zukc38.js +0 -3
  590. package/.next/server/chunks/_next-internal_server_app_api_auth_logout_route_actions_0fm~3ij.js +0 -3
  591. package/.next/server/chunks/_next-internal_server_app_api_auth_v3_route_actions_0ndzs5l.js +0 -3
  592. package/.next/server/chunks/_next-internal_server_app_api_hub_audit-log_route_actions_11k8fqt.js +0 -3
  593. package/.next/server/chunks/_next-internal_server_app_api_hub_auth_route_actions_0gs7ttk.js +0 -3
  594. package/.next/server/chunks/_next-internal_server_app_api_hub_broadcast_route_actions_0ads-kd.js +0 -3
  595. package/.next/server/chunks/_next-internal_server_app_api_hub_events_route_actions_0opktby.js +0 -3
  596. package/.next/server/chunks/_next-internal_server_app_api_hub_health_route_actions_0tzzt~x.js +0 -3
  597. package/.next/server/chunks/_next-internal_server_app_api_hub_inbox_route_actions_0xvslrg.js +0 -3
  598. package/.next/server/chunks/_next-internal_server_app_api_hub_license_route_actions_0i3tlr3.js +0 -3
  599. package/.next/server/chunks/_next-internal_server_app_api_hub_messages_route_actions_08-gi-s.js +0 -3
  600. package/.next/server/chunks/_next-internal_server_app_api_hub_networks_route_actions_02vejq2.js +0 -3
  601. package/.next/server/chunks/_next-internal_server_app_api_hub_nodes_route_actions_0nx8ryn.js +0 -3
  602. package/.next/server/chunks/_next-internal_server_app_api_hub_register_route_actions_086wi_3.js +0 -3
  603. package/.next/server/chunks/_next-internal_server_app_api_hub_send_route_actions_0-ga_ug.js +0 -3
  604. package/.next/server/chunks/_next-internal_server_app_api_hub_server-logs_route_actions_00euexv.js +0 -3
  605. package/.next/server/chunks/_next-internal_server_app_api_hub_session_route_actions_041wa62.js +0 -3
  606. package/.next/server/chunks/_next-internal_server_app_api_hub_stats_route_actions_1242~od.js +0 -3
  607. package/.next/server/chunks/_next-internal_server_app_api_hub_status_route_actions_0aml09a.js +0 -3
  608. package/.next/server/chunks/_next-internal_server_app_api_hub_task-events_route_actions_02v1tmm.js +0 -3
  609. package/.next/server/chunks/_next-internal_server_app_api_hub_tasks_route_actions_0nl77v4.js +0 -3
  610. package/.next/server/chunks/_next-internal_server_app_api_hub_tmux_route_actions_0u~aaza.js +0 -3
  611. package/.next/server/chunks/_next-internal_server_app_api_hub_tokens_route_actions_09hzf_1.js +0 -3
  612. package/.next/server/chunks/_next-internal_server_app_favicon_ico_route_actions_095lj93.js +0 -3
  613. package/.next/server/chunks/node_modules_next_11synfn._.js +0 -10
  614. package/.next/server/chunks/node_modules_next_11synfn._.js.map +0 -1
  615. package/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_0yubv2d.js +0 -3
  616. package/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_0yubv2d.js.map +0 -1
  617. package/.next/server/chunks/ssr/[root-of-the-server]__014uja_._.js +0 -3
  618. package/.next/server/chunks/ssr/[root-of-the-server]__014uja_._.js.map +0 -1
  619. package/.next/server/chunks/ssr/[root-of-the-server]__02hi65f._.js +0 -3
  620. package/.next/server/chunks/ssr/[root-of-the-server]__02hi65f._.js.map +0 -1
  621. package/.next/server/chunks/ssr/[root-of-the-server]__02xqa5z._.js +0 -3
  622. package/.next/server/chunks/ssr/[root-of-the-server]__02xqa5z._.js.map +0 -1
  623. package/.next/server/chunks/ssr/[root-of-the-server]__04ph1de._.js +0 -3
  624. package/.next/server/chunks/ssr/[root-of-the-server]__04ph1de._.js.map +0 -1
  625. package/.next/server/chunks/ssr/[root-of-the-server]__05wc5-z._.js +0 -3
  626. package/.next/server/chunks/ssr/[root-of-the-server]__05wc5-z._.js.map +0 -1
  627. package/.next/server/chunks/ssr/[root-of-the-server]__06-2p1a._.js +0 -33
  628. package/.next/server/chunks/ssr/[root-of-the-server]__06-2p1a._.js.map +0 -1
  629. package/.next/server/chunks/ssr/[root-of-the-server]__08qr2ji._.js.map +0 -1
  630. package/.next/server/chunks/ssr/[root-of-the-server]__09l8xaa._.js +0 -3
  631. package/.next/server/chunks/ssr/[root-of-the-server]__09l8xaa._.js.map +0 -1
  632. package/.next/server/chunks/ssr/[root-of-the-server]__09z7o2x._.js +0 -19
  633. package/.next/server/chunks/ssr/[root-of-the-server]__09z7o2x._.js.map +0 -1
  634. package/.next/server/chunks/ssr/[root-of-the-server]__0a0ffmv._.js +0 -3
  635. package/.next/server/chunks/ssr/[root-of-the-server]__0a0ffmv._.js.map +0 -1
  636. package/.next/server/chunks/ssr/[root-of-the-server]__0b7uu-_._.js +0 -3
  637. package/.next/server/chunks/ssr/[root-of-the-server]__0b7uu-_._.js.map +0 -1
  638. package/.next/server/chunks/ssr/[root-of-the-server]__0bl_wqk._.js +0 -3
  639. package/.next/server/chunks/ssr/[root-of-the-server]__0bl_wqk._.js.map +0 -1
  640. package/.next/server/chunks/ssr/[root-of-the-server]__0ft0rpu._.js +0 -3
  641. package/.next/server/chunks/ssr/[root-of-the-server]__0ft0rpu._.js.map +0 -1
  642. package/.next/server/chunks/ssr/[root-of-the-server]__0i~g-2t._.js +0 -3
  643. package/.next/server/chunks/ssr/[root-of-the-server]__0i~g-2t._.js.map +0 -1
  644. package/.next/server/chunks/ssr/[root-of-the-server]__0jl4ukn._.js +0 -3
  645. package/.next/server/chunks/ssr/[root-of-the-server]__0jl4ukn._.js.map +0 -1
  646. package/.next/server/chunks/ssr/[root-of-the-server]__0mook08._.js +0 -3
  647. package/.next/server/chunks/ssr/[root-of-the-server]__0mook08._.js.map +0 -1
  648. package/.next/server/chunks/ssr/[root-of-the-server]__0n46s~k._.js +0 -3
  649. package/.next/server/chunks/ssr/[root-of-the-server]__0n46s~k._.js.map +0 -1
  650. package/.next/server/chunks/ssr/[root-of-the-server]__0qchqb~._.js +0 -3
  651. package/.next/server/chunks/ssr/[root-of-the-server]__0qchqb~._.js.map +0 -1
  652. package/.next/server/chunks/ssr/[root-of-the-server]__0rrm~-q._.js +0 -3
  653. package/.next/server/chunks/ssr/[root-of-the-server]__0rrm~-q._.js.map +0 -1
  654. package/.next/server/chunks/ssr/[root-of-the-server]__0w2ay2h._.js +0 -3
  655. package/.next/server/chunks/ssr/[root-of-the-server]__0w2ay2h._.js.map +0 -1
  656. package/.next/server/chunks/ssr/[root-of-the-server]__0xjish~._.js +0 -3
  657. package/.next/server/chunks/ssr/[root-of-the-server]__0xjish~._.js.map +0 -1
  658. package/.next/server/chunks/ssr/[root-of-the-server]__0xm3h9x._.js +0 -3
  659. package/.next/server/chunks/ssr/[root-of-the-server]__0xm3h9x._.js.map +0 -1
  660. package/.next/server/chunks/ssr/[root-of-the-server]__0ywihy_._.js +0 -8
  661. package/.next/server/chunks/ssr/[root-of-the-server]__0ywihy_._.js.map +0 -1
  662. package/.next/server/chunks/ssr/[root-of-the-server]__12ad1n.._.js +0 -3
  663. package/.next/server/chunks/ssr/[root-of-the-server]__12ad1n.._.js.map +0 -1
  664. package/.next/server/chunks/ssr/_0nne7mz._.js +0 -3
  665. package/.next/server/chunks/ssr/_0nne7mz._.js.map +0 -1
  666. package/.next/server/chunks/ssr/_next-internal_server_app__global-error_page_actions_0k77kol.js +0 -3
  667. package/.next/server/chunks/ssr/_next-internal_server_app__not-found_page_actions_0eq97pa.js +0 -3
  668. package/.next/server/chunks/ssr/_next-internal_server_app_admin_page_actions_0ycnu8f.js +0 -3
  669. package/.next/server/chunks/ssr/_next-internal_server_app_login_page_actions_02kefem.js +0 -3
  670. package/.next/server/chunks/ssr/_next-internal_server_app_logs_page_actions_0rvsl~d.js +0 -3
  671. package/.next/server/chunks/ssr/_next-internal_server_app_messages_page_actions_0gsqep_.js +0 -3
  672. package/.next/server/chunks/ssr/_next-internal_server_app_node_page_actions_0wd8cgl.js +0 -3
  673. package/.next/server/chunks/ssr/_next-internal_server_app_nodes_page_actions_0-.rv67.js +0 -3
  674. package/.next/server/chunks/ssr/_next-internal_server_app_page_actions_09-gtaw.js +0 -3
  675. package/.next/server/chunks/ssr/_next-internal_server_app_server-logs_page_actions_0g1gb5c.js +0 -3
  676. package/.next/server/chunks/ssr/_next-internal_server_app_settings_networks_page_actions_09uw.sw.js +0 -3
  677. package/.next/server/chunks/ssr/_next-internal_server_app_settings_page_actions_0mr68ai.js +0 -3
  678. package/.next/server/chunks/ssr/_next-internal_server_app_settings_tokens_page_actions_0yi54x8.js +0 -3
  679. package/.next/server/chunks/ssr/_next-internal_server_app_tasks_[id]_page_actions_0k_hm9g.js +0 -3
  680. package/.next/server/chunks/ssr/_next-internal_server_app_tasks_page_actions_0_2o_cr.js +0 -3
  681. package/.next/server/chunks/ssr/app_0.zbtn5._.js.map +0 -1
  682. package/.next/server/chunks/ssr/app_01y-~mp._.js +0 -3
  683. package/.next/server/chunks/ssr/app_01y-~mp._.js.map +0 -1
  684. package/.next/server/chunks/ssr/app_04n78pr._.js.map +0 -1
  685. package/.next/server/chunks/ssr/app_0_agk0r._.js.map +0 -1
  686. package/.next/server/chunks/ssr/app_0aenxef._.js +0 -3
  687. package/.next/server/chunks/ssr/app_0aenxef._.js.map +0 -1
  688. package/.next/server/chunks/ssr/app_0aum_g5._.js +0 -3
  689. package/.next/server/chunks/ssr/app_0aum_g5._.js.map +0 -1
  690. package/.next/server/chunks/ssr/app_0emvkn2._.js +0 -3
  691. package/.next/server/chunks/ssr/app_0emvkn2._.js.map +0 -1
  692. package/.next/server/chunks/ssr/app_0esuljp._.js +0 -3
  693. package/.next/server/chunks/ssr/app_0esuljp._.js.map +0 -1
  694. package/.next/server/chunks/ssr/app_0izi28j._.js.map +0 -1
  695. package/.next/server/chunks/ssr/app_components_08ys5y3._.js.map +0 -1
  696. package/.next/server/chunks/ssr/app_server-logs_page_tsx_0_kpp1p._.js.map +0 -1
  697. package/.next/server/chunks/ssr/app_tasks_page_tsx_0z-d6mp._.js +0 -3
  698. package/.next/server/chunks/ssr/app_tasks_page_tsx_0z-d6mp._.js.map +0 -1
  699. package/.next/server/chunks/ssr/node_modules_09w7yel._.js.map +0 -1
  700. package/.next/server/chunks/ssr/node_modules_0ck2~9g._.js +0 -3
  701. package/.next/server/chunks/ssr/node_modules_0ck2~9g._.js.map +0 -1
  702. package/.next/server/chunks/ssr/node_modules_0r_.s40._.js.map +0 -1
  703. package/.next/server/chunks/ssr/node_modules_0vtdjw7._.js +0 -3
  704. package/.next/server/chunks/ssr/node_modules_0vtdjw7._.js.map +0 -1
  705. package/.next/server/chunks/ssr/node_modules_next_0w2y7fz._.js +0 -6
  706. package/.next/server/chunks/ssr/node_modules_next_0w2y7fz._.js.map +0 -1
  707. package/.next/server/chunks/ssr/node_modules_next_dist_0e1izl_._.js +0 -6
  708. package/.next/server/chunks/ssr/node_modules_next_dist_0e1izl_._.js.map +0 -1
  709. package/.next/server/chunks/ssr/node_modules_next_dist_client_components_0inhx6q._.js +0 -3
  710. package/.next/server/chunks/ssr/node_modules_next_dist_client_components_0inhx6q._.js.map +0 -1
  711. package/.next/server/chunks/ssr/node_modules_next_dist_client_components_builtin_forbidden_0ghu-f7.js +0 -3
  712. package/.next/server/chunks/ssr/node_modules_next_dist_client_components_builtin_forbidden_0ghu-f7.js.map +0 -1
  713. package/.next/server/chunks/ssr/node_modules_next_dist_client_components_builtin_global-error_0lgvd_..js +0 -3
  714. package/.next/server/chunks/ssr/node_modules_next_dist_client_components_builtin_global-error_0lgvd_..js.map +0 -1
  715. package/.next/server/chunks/ssr/node_modules_next_dist_client_components_builtin_unauthorized_0cjv-23.js +0 -3
  716. package/.next/server/chunks/ssr/node_modules_next_dist_client_components_builtin_unauthorized_0cjv-23.js.map +0 -1
  717. package/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_002l7yi.js.map +0 -1
  718. package/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_02suzhc.js.map +0 -1
  719. package/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_07uu-xq.js.map +0 -1
  720. package/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0d2yq5t.js.map +0 -1
  721. package/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0dm~kj8.js.map +0 -1
  722. package/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0foejvu.js.map +0 -1
  723. package/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0l-fh0i.js.map +0 -1
  724. package/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0nsg22r.js.map +0 -1
  725. package/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0o9vt1n.js.map +0 -1
  726. package/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0qm1-a1.js.map +0 -1
  727. package/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0uccf9z.js.map +0 -1
  728. package/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0uv6jyc.js.map +0 -1
  729. package/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_10~~o-h.js +0 -4
  730. package/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_10~~o-h.js.map +0 -1
  731. package/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_13leyhk.js +0 -4
  732. package/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_13leyhk.js.map +0 -1
  733. package/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_13s07li.js.map +0 -1
  734. package/.next/static/chunks/0257pdz1-imal.js +0 -2
  735. package/.next/static/chunks/02_zpo7taex9o.js +0 -7
  736. package/.next/static/chunks/03tdotf7ifdxm.js +0 -1
  737. package/.next/static/chunks/06n3d~fbbtagk.js +0 -1
  738. package/.next/static/chunks/07eba1lz2u3p4.js +0 -1
  739. package/.next/static/chunks/0av2~0.96~d~g.js +0 -1
  740. package/.next/static/chunks/0bd~fi9sar8di.js +0 -1
  741. package/.next/static/chunks/0c1bp~g7.8ru..js +0 -1
  742. package/.next/static/chunks/0e-.zgw81gela.js +0 -31
  743. package/.next/static/chunks/0g9aof0ob_fcj.js +0 -1
  744. package/.next/static/chunks/0od70ylwpxjld.js +0 -1
  745. package/.next/static/chunks/0s8jo6jypzkx5.js +0 -1
  746. package/.next/static/chunks/0u359llqm1_01.js +0 -1
  747. package/.next/static/chunks/0ubqqhhpsaez4.js +0 -1
  748. package/.next/static/chunks/0ux36eo4a-0ry.css +0 -2
  749. package/.next/static/chunks/0~qw9kxksr1v2.js +0 -1
  750. package/.next/static/chunks/12gprw3l0kvvf.js +0 -1
  751. package/.next/static/chunks/12yuo353giomx.js +0 -1
  752. package/.next/static/chunks/14bsg3_-taiw4.js +0 -1
  753. /package/.next/build/chunks/{[root-of-the-server]__0ubbtyl._.js.map → [root-of-the-server]__0tgc-8p._.js.map} +0 -0
  754. /package/.next/build/chunks/{[turbopack-node]_transforms_postcss_ts_06e.r3r._.js.map → [turbopack-node]_transforms_postcss_ts_0r4x5ys._.js.map} +0 -0
  755. /package/.next/server/chunks/{_next-internal_server_app_api_anet_config_route_actions_0xzy73j.js.map → 0ci9_nt-network-dashboard__next-internal_server_app_api_auth_v3_route_actions_0f5nbzr.js.map} +0 -0
  756. /package/.next/server/chunks/{_next-internal_server_app_api_auth_login_route_actions_0zukc38.js.map → 0ci9_nt-network-dashboard__next-internal_server_app_favicon_ico_route_actions_0t0eu9r.js.map} +0 -0
  757. /package/.next/server/chunks/{_next-internal_server_app_api_auth_logout_route_actions_0fm~3ij.js.map → 0ykm__next-internal_server_app_api_anet_config_route_actions_0a~v55_.js.map} +0 -0
  758. /package/.next/server/chunks/{_next-internal_server_app_api_auth_v3_route_actions_0ndzs5l.js.map → 0ykm__next-internal_server_app_api_auth_login_route_actions_0xnxfs4.js.map} +0 -0
  759. /package/.next/server/chunks/{_next-internal_server_app_api_hub_audit-log_route_actions_11k8fqt.js.map → 0ykm__next-internal_server_app_api_auth_logout_route_actions_0p8p0rn.js.map} +0 -0
  760. /package/.next/server/chunks/{_next-internal_server_app_api_hub_auth_route_actions_0gs7ttk.js.map → 0ykm__next-internal_server_app_api_hub_audit-log_route_actions_06uquwi.js.map} +0 -0
  761. /package/.next/server/chunks/{_next-internal_server_app_api_hub_broadcast_route_actions_0ads-kd.js.map → 0ykm__next-internal_server_app_api_hub_auth_route_actions_0f_y1ey.js.map} +0 -0
  762. /package/.next/server/chunks/{_next-internal_server_app_api_hub_events_route_actions_0opktby.js.map → 0ykm__next-internal_server_app_api_hub_broadcast_route_actions_0ao3j43.js.map} +0 -0
  763. /package/.next/server/chunks/{_next-internal_server_app_api_hub_health_route_actions_0tzzt~x.js.map → 0ykm__next-internal_server_app_api_hub_events_route_actions_0_5ndld.js.map} +0 -0
  764. /package/.next/server/chunks/{_next-internal_server_app_api_hub_inbox_route_actions_0xvslrg.js.map → 0ykm__next-internal_server_app_api_hub_health_route_actions_0mpzl74.js.map} +0 -0
  765. /package/.next/server/chunks/{_next-internal_server_app_api_hub_license_route_actions_0i3tlr3.js.map → 0ykm__next-internal_server_app_api_hub_inbox_route_actions_0stoyto.js.map} +0 -0
  766. /package/.next/server/chunks/{_next-internal_server_app_api_hub_messages_route_actions_08-gi-s.js.map → 0ykm__next-internal_server_app_api_hub_license_route_actions_0a4.fuh.js.map} +0 -0
  767. /package/.next/server/chunks/{_next-internal_server_app_api_hub_networks_route_actions_02vejq2.js.map → 0ykm__next-internal_server_app_api_hub_messages_route_actions_059rw1o.js.map} +0 -0
  768. /package/.next/server/chunks/{_next-internal_server_app_api_hub_nodes_route_actions_0nx8ryn.js.map → 0ykm__next-internal_server_app_api_hub_networks_route_actions_03sehpn.js.map} +0 -0
  769. /package/.next/server/chunks/{_next-internal_server_app_api_hub_register_route_actions_086wi_3.js.map → 0ykm__next-internal_server_app_api_hub_nodes_route_actions_11fbp28.js.map} +0 -0
  770. /package/.next/server/chunks/{_next-internal_server_app_api_hub_send_route_actions_0-ga_ug.js.map → 0ykm__next-internal_server_app_api_hub_register_route_actions_0l.d7~n.js.map} +0 -0
  771. /package/.next/server/chunks/{_next-internal_server_app_api_hub_server-logs_route_actions_00euexv.js.map → 0ykm__next-internal_server_app_api_hub_send_route_actions_0.p82vy.js.map} +0 -0
  772. /package/.next/server/chunks/{_next-internal_server_app_api_hub_session_route_actions_041wa62.js.map → 0ykm__next-internal_server_app_api_hub_server-logs_route_actions_05~c5lb.js.map} +0 -0
  773. /package/.next/server/chunks/{_next-internal_server_app_api_hub_stats_route_actions_1242~od.js.map → 0ykm__next-internal_server_app_api_hub_session_route_actions_0b9ef2i.js.map} +0 -0
  774. /package/.next/server/chunks/{_next-internal_server_app_api_hub_status_route_actions_0aml09a.js.map → 0ykm__next-internal_server_app_api_hub_stats_route_actions_03u65u0.js.map} +0 -0
  775. /package/.next/server/chunks/{_next-internal_server_app_api_hub_task-events_route_actions_02v1tmm.js.map → 0ykm__next-internal_server_app_api_hub_status_route_actions_0_71ear.js.map} +0 -0
  776. /package/.next/server/chunks/{_next-internal_server_app_api_hub_tasks_route_actions_0nl77v4.js.map → 0ykm__next-internal_server_app_api_hub_task-events_route_actions_07md_ee.js.map} +0 -0
  777. /package/.next/server/chunks/{_next-internal_server_app_api_hub_tmux_route_actions_0u~aaza.js.map → 0ykm__next-internal_server_app_api_hub_tasks_route_actions_0er3uvk.js.map} +0 -0
  778. /package/.next/server/chunks/{_next-internal_server_app_api_hub_tokens_route_actions_09hzf_1.js.map → 0ykm__next-internal_server_app_api_hub_tmux_route_actions_0o_1-8u.js.map} +0 -0
  779. /package/.next/server/chunks/{_next-internal_server_app_favicon_ico_route_actions_095lj93.js.map → 0ykm__next-internal_server_app_api_hub_tokens_route_actions_09doluz.js.map} +0 -0
  780. /package/.next/server/chunks/ssr/{_next-internal_server_app__global-error_page_actions_0k77kol.js.map → 0dwh_ent-network-dashboard__next-internal_server_app_server-logs_page_actions_0hkk815.js.map} +0 -0
  781. /package/.next/server/chunks/ssr/{_next-internal_server_app__not-found_page_actions_0eq97pa.js.map → 0yas_gent-network-dashboard__next-internal_server_app__not-found_page_actions_0u.f-rz.js.map} +0 -0
  782. /package/.next/server/chunks/ssr/{_next-internal_server_app_admin_page_actions_0ycnu8f.js.map → 0yas_gent-network-dashboard__next-internal_server_app_tasks_[id]_page_actions_0r3~lho.js.map} +0 -0
  783. /package/.next/server/chunks/ssr/{_next-internal_server_app_login_page_actions_02kefem.js.map → 0ykm__next-internal_server_app__global-error_page_actions_100fxls.js.map} +0 -0
  784. /package/.next/server/chunks/ssr/{_next-internal_server_app_logs_page_actions_0rvsl~d.js.map → 0ykm__next-internal_server_app_settings_networks_page_actions_0jgy57m.js.map} +0 -0
  785. /package/.next/server/chunks/ssr/{_next-internal_server_app_messages_page_actions_0gsqep_.js.map → 0ykm__next-internal_server_app_settings_tokens_page_actions_0l5h.k~.js.map} +0 -0
  786. /package/.next/server/chunks/ssr/{_next-internal_server_app_node_page_actions_0wd8cgl.js.map → agent-network-dashboard__next-internal_server_app_admin_page_actions_0i~.x~j.js.map} +0 -0
  787. /package/.next/server/chunks/ssr/{_next-internal_server_app_nodes_page_actions_0-.rv67.js.map → agent-network-dashboard__next-internal_server_app_login_page_actions_0frwl15.js.map} +0 -0
  788. /package/.next/server/chunks/ssr/{_next-internal_server_app_page_actions_09-gtaw.js.map → agent-network-dashboard__next-internal_server_app_logs_page_actions_0xa2ox_.js.map} +0 -0
  789. /package/.next/server/chunks/ssr/{_next-internal_server_app_server-logs_page_actions_0g1gb5c.js.map → agent-network-dashboard__next-internal_server_app_messages_page_actions_10j3tg4.js.map} +0 -0
  790. /package/.next/server/chunks/ssr/{_next-internal_server_app_settings_networks_page_actions_09uw.sw.js.map → agent-network-dashboard__next-internal_server_app_node_page_actions_0sl4ntd.js.map} +0 -0
  791. /package/.next/server/chunks/ssr/{_next-internal_server_app_settings_page_actions_0mr68ai.js.map → agent-network-dashboard__next-internal_server_app_nodes_page_actions_0cpgkfs.js.map} +0 -0
  792. /package/.next/server/chunks/ssr/{_next-internal_server_app_settings_tokens_page_actions_0yi54x8.js.map → agent-network-dashboard__next-internal_server_app_page_actions_08nuo36.js.map} +0 -0
  793. /package/.next/server/chunks/ssr/{_next-internal_server_app_tasks_[id]_page_actions_0k_hm9g.js.map → agent-network-dashboard__next-internal_server_app_settings_page_actions_0iv.lmk.js.map} +0 -0
  794. /package/.next/server/chunks/ssr/{_next-internal_server_app_tasks_page_actions_0_2o_cr.js.map → agent-network-dashboard__next-internal_server_app_tasks_page_actions_08c7qlx.js.map} +0 -0
  795. /package/.next/static/{cnPvCZlSAHV4OCtuXKMlY → XiA2VWgHsZvuY-5yWxSPj}/_buildManifest.js +0 -0
  796. /package/.next/static/{cnPvCZlSAHV4OCtuXKMlY → XiA2VWgHsZvuY-5yWxSPj}/_clientMiddlewareManifest.js +0 -0
  797. /package/.next/static/{cnPvCZlSAHV4OCtuXKMlY → XiA2VWgHsZvuY-5yWxSPj}/_ssgManifest.js +0 -0
@@ -4,6 +4,7 @@ import { useEffect, useMemo, useRef, useState } from 'react';
4
4
  import { Session } from './types';
5
5
  import { aliasAvatarColors, aliasInitial } from './AliasAvatar';
6
6
  import { ChatPopover } from './ChatPopover';
7
+ import { vendorForModel, runtimeIdentity, identityLine } from '../lib/vendorIdentity';
7
8
 
8
9
  interface MessageFlow {
9
10
  from_alias: string;
@@ -15,6 +16,9 @@ interface MessageFlow {
15
16
  interface TopoGraphProps {
16
17
  sessions: Session[];
17
18
  sseSessions: Record<string, number>;
19
+ // #84: a node.renamed event from the Overview's SSE listener. When the
20
+ // currently open chat popover targets `from`, it follows the rename to `to`.
21
+ renameSignal?: { from: string; to: string; ts: number } | null;
18
22
  }
19
23
 
20
24
  interface Point {
@@ -28,6 +32,9 @@ interface FlowLink {
28
32
  to: string;
29
33
  count: number;
30
34
  content: string;
35
+ /** ISO timestamp of the most recent message on this edge — drives
36
+ * the Round 10 freshness fade so dormant links recede visually. */
37
+ last_at: string;
31
38
  }
32
39
 
33
40
  const cx = 500;
@@ -81,36 +88,52 @@ function truncate(value: string, max: number) {
81
88
  return value.length > max ? `${value.slice(0, max - 1)}...` : value;
82
89
  }
83
90
 
91
+ /** Round 12 / Loop: status trio audit.
92
+ *
93
+ * Each (status × theme) cell returns a {primary, halo, text} trio. The trio
94
+ * invariant — keep it when adding states or tweaking shades:
95
+ *
96
+ * light: primary = <hue>-600 halo = <hue>-100 * text = <hue>-800/900
97
+ * dark: primary = <hue>-400/500 halo = <hue>-900 text = <hue>-100
98
+ *
99
+ * * offline.halo light deviates intentionally to slate-200 (#e2e8f0):
100
+ * slate-100 (#f1f5f9) is too close to the panel bg (#f8fafc) and the
101
+ * halo would vanish. The other three rows keep the 100-shade.
102
+ *
103
+ * Audit caught one cross-family drift before this round: online-other halo
104
+ * light was #dbeafe (blue-100) while its primary (#0284c7 sky-600) and text
105
+ * (#0c4a6e sky-900) were sky-family — now sky-100 (#e0f2fe). Tiny visual
106
+ * difference; large hygiene win — every trio is now mono-hue. */
84
107
  function nodeStatus(session: Session, isOnline: boolean, isLight: boolean) {
85
108
  if (!isOnline) {
86
109
  return {
87
110
  label: 'offline',
88
- primary: isLight ? '#94a3b8' : '#6b7280',
89
- halo: isLight ? '#e2e8f0' : '#111827',
90
- text: isLight ? '#475569' : '#9ca3af',
111
+ primary: isLight ? '#94a3b8' : '#6b7280', // slate-400 / gray-500
112
+ halo: isLight ? '#e2e8f0' : '#111827', // slate-200* / gray-900
113
+ text: isLight ? '#475569' : '#9ca3af', // slate-600 / gray-400
91
114
  };
92
115
  }
93
116
  if (session.status === 'working') {
94
117
  return {
95
118
  label: 'working',
96
- primary: isLight ? '#059669' : '#22c55e',
97
- halo: isLight ? '#d1fae5' : '#14532d',
98
- text: isLight ? '#065f46' : '#dcfce7',
119
+ primary: isLight ? '#059669' : '#22c55e', // emerald-600 / green-500
120
+ halo: isLight ? '#d1fae5' : '#14532d', // emerald-100 / green-900
121
+ text: isLight ? '#065f46' : '#dcfce7', // emerald-800 / green-100
99
122
  };
100
123
  }
101
124
  if (session.status === 'idle') {
102
125
  return {
103
126
  label: 'idle',
104
- primary: isLight ? '#0d9488' : '#2dd4bf',
105
- halo: isLight ? '#ccfbf1' : '#134e4a',
106
- text: isLight ? '#115e59' : '#ccfbf1',
127
+ primary: isLight ? '#0d9488' : '#2dd4bf', // teal-600 / teal-400
128
+ halo: isLight ? '#ccfbf1' : '#134e4a', // teal-100 / teal-900
129
+ text: isLight ? '#115e59' : '#ccfbf1', // teal-800 / teal-100
107
130
  };
108
131
  }
109
132
  return {
110
133
  label: session.status || 'online',
111
- primary: isLight ? '#0284c7' : '#38bdf8',
112
- halo: isLight ? '#dbeafe' : '#0c4a6e',
113
- text: isLight ? '#0c4a6e' : '#e0f2fe',
134
+ primary: isLight ? '#0284c7' : '#38bdf8', // sky-600 / sky-400
135
+ halo: isLight ? '#e0f2fe' : '#0c4a6e', // sky-100 / sky-900 (was blue-100 — drift fixed Round 12)
136
+ text: isLight ? '#0c4a6e' : '#e0f2fe', // sky-900 / sky-100
114
137
  };
115
138
  }
116
139
 
@@ -236,22 +259,59 @@ function commonPrefix(a: string, b: string): string {
236
259
  return a.slice(0, i);
237
260
  }
238
261
 
239
- function computeGroupKeys(aliases: string[]): Record<string, string> {
240
- const sorted = [...aliases].sort((a, b) => a.localeCompare(b));
262
+ /** #83 + #111: group nodes that share a ≥2-char alias prefix OR a project_dir
263
+ * ("either criterion same group", Vincent 4724). Union-find over the
264
+ * sessions; the component label prefers the shared project_dir's basename,
265
+ * else the common alias prefix. Returns alias → groupKey. */
266
+ function computeGroups(sessions: { alias: string; project_dir?: string | null }[]): Record<string, string> {
267
+ const n = sessions.length;
268
+ const parent = sessions.map((_, i) => i);
269
+ const find = (i: number): number => {
270
+ while (parent[i] !== i) { parent[i] = parent[parent[i]]; i = parent[i]; }
271
+ return i;
272
+ };
273
+ const union = (a: number, b: number) => {
274
+ const ra = find(a), rb = find(b);
275
+ if (ra !== rb) parent[ra] = rb;
276
+ };
277
+
278
+ // union by shared project_dir
279
+ const byDir: Record<string, number[]> = {};
280
+ sessions.forEach((s, i) => {
281
+ const d = s.project_dir?.trim();
282
+ if (d) (byDir[d] ||= []).push(i);
283
+ });
284
+ for (const idxs of Object.values(byDir)) {
285
+ for (let k = 1; k < idxs.length; k++) union(idxs[0], idxs[k]);
286
+ }
287
+
288
+ // union by shared ≥2-char alias prefix — sort, link adjacent pairs
289
+ const order = sessions.map((_, i) => i).sort((a, b) => sessions[a].alias.localeCompare(sessions[b].alias));
290
+ for (let k = 0; k + 1 < order.length; k++) {
291
+ if (commonPrefix(sessions[order[k]].alias, sessions[order[k + 1]].alias).length >= 2) {
292
+ union(order[k], order[k + 1]);
293
+ }
294
+ }
295
+
296
+ // label each connected component
297
+ const comps: Record<number, number[]> = {};
298
+ for (let i = 0; i < n; i++) (comps[find(i)] ||= []).push(i);
241
299
  const keys: Record<string, string> = {};
242
- let i = 0;
243
- while (i < sorted.length) {
244
- let j = i;
245
- let prefix = sorted[i];
246
- while (j + 1 < sorted.length) {
247
- const lcp = commonPrefix(prefix, sorted[j + 1]);
248
- if (lcp.length < 2) break;
249
- prefix = lcp;
250
- j++;
300
+ for (const members of Object.values(comps)) {
301
+ let label: string;
302
+ if (members.length === 1) {
303
+ label = sessions[members[0]].alias;
304
+ } else {
305
+ const dirs = new Set(members.map(i => sessions[i].project_dir?.trim()).filter(Boolean) as string[]);
306
+ if (dirs.size === 1) {
307
+ const d = [...dirs][0];
308
+ label = d.split('/').filter(Boolean).pop() || d;
309
+ } else {
310
+ label = members.map(i => sessions[i].alias).reduce((a, b) => commonPrefix(a, b));
311
+ if (label.length < 2) label = sessions[members[0]].alias;
312
+ }
251
313
  }
252
- const key = j > i ? prefix : sorted[i];
253
- for (let k = i; k <= j; k++) keys[sorted[k]] = key;
254
- i = j + 1;
314
+ for (const i of members) keys[sessions[i].alias] = label;
255
315
  }
256
316
  return keys;
257
317
  }
@@ -271,25 +331,63 @@ function buildFlowLinks(messages: MessageFlow[], positions: Record<string, Point
271
331
  const key = `${message.from_alias}->${message.to_alias}`;
272
332
  const current = links.get(key);
273
333
 
334
+ // Keep the most-recent timestamp per pair so the render can fade
335
+ // dormant edges (Round 10 freshness fade).
336
+ const incoming = message.created_at || '';
337
+ const last_at = !current
338
+ ? incoming
339
+ : (incoming > current.last_at ? incoming : current.last_at);
340
+
274
341
  links.set(key, {
275
342
  key,
276
343
  from: message.from_alias,
277
344
  to: message.to_alias,
278
345
  count: (current?.count || 0) + 1,
279
346
  content: current?.content || message.content,
347
+ last_at,
280
348
  });
281
349
  });
282
350
 
283
351
  return [...links.values()].slice(0, 18);
284
352
  }
285
353
 
286
- export function TopoGraph({ sessions, sseSessions }: TopoGraphProps) {
354
+ export function TopoGraph({ sessions, sseSessions, renameSignal }: TopoGraphProps) {
287
355
  const theme = useTheme();
288
356
  const isLight = theme === 'light';
289
357
  const pal = isLight ? LIGHT_PALETTE : DARK_PALETTE;
290
358
  const brand = useBrand();
291
359
  const isIntern = brand === 'intern';
292
360
  const [messages, setMessages] = useState<MessageFlow[]>([]);
361
+ // Issue #87: ring | grid layout toggle. Ring is the tiered-radial default;
362
+ // grid arranges nodes in an N×M grid (better for 30+ nodes). Persisted to
363
+ // localStorage like the zoom/pan view state. Declared above nodePositions
364
+ // since that useMemo branches on it.
365
+ const [layout, setLayout] = useState<'ring' | 'grid'>('ring');
366
+ useEffect(() => {
367
+ try {
368
+ const saved = localStorage.getItem('anet-topo-layout');
369
+ if (saved === 'grid' || saved === 'ring') setLayout(saved);
370
+ } catch {}
371
+ }, []);
372
+ const toggleLayout = () => setLayout(prev => {
373
+ const next = prev === 'ring' ? 'grid' : 'ring';
374
+ try { localStorage.setItem('anet-topo-layout', next); } catch {}
375
+ return next;
376
+ });
377
+ // Issue #113: node size scale (Vincent 4727 — nodes too big / crowded at
378
+ // ~22 nodes). S/M/L → 0.7/0.84/1.0; default M (one notch down from the old
379
+ // fixed size). Persisted like the layout toggle.
380
+ const [nodeScale, setNodeScale] = useState(0.84);
381
+ useEffect(() => {
382
+ try {
383
+ const saved = parseFloat(localStorage.getItem('anet-topo-nodescale') || '');
384
+ if (saved === 0.7 || saved === 0.84 || saved === 1) setNodeScale(saved);
385
+ } catch {}
386
+ }, []);
387
+ const pickNodeScale = (v: number) => {
388
+ setNodeScale(v);
389
+ try { localStorage.setItem('anet-topo-nodescale', String(v)); } catch {}
390
+ };
293
391
 
294
392
  useEffect(() => {
295
393
  const fetchMessages = async () => {
@@ -316,6 +414,7 @@ export function TopoGraph({ sessions, sseSessions }: TopoGraphProps) {
316
414
  flowLinks,
317
415
  activeAliases,
318
416
  groupKeys,
417
+ groupBoxes,
319
418
  } = useMemo(() => {
320
419
  const sseCount = (s: { alias: string; network_id?: string }) =>
321
420
  (s.network_id ? sseSessions[`${s.network_id}:${s.alias}`] : undefined) ?? sseSessions[s.alias];
@@ -325,10 +424,133 @@ export function TopoGraph({ sessions, sseSessions }: TopoGraphProps) {
325
424
  // index, so contiguous-in-array becomes contiguous-in-ring, i.e.
326
425
  // each team visually clusters. localeCompare keeps CJK ordering sane.
327
426
  const byAlias = (a: Session, b: Session) => a.alias.localeCompare(b.alias);
427
+ // #112 umbrella: ghost age-out — an offline node not seen for over a day
428
+ // is almost certainly a deleted node the server `/api/status` still
429
+ // returns (#74 root cause is server-side; this is the dashboard-side
430
+ // fallback so stale ghosts stop cluttering the topology). A missing
431
+ // last_seen_at is kept (conservative — could be a legitimately new node).
432
+ const GHOST_MS = 24 * 60 * 60 * 1000;
433
+ const now = Date.now();
434
+ const isGhost = (s: Session) => {
435
+ if (s.status !== 'offline' || sseCount(s) || !s.last_seen_at) return false;
436
+ const t = Date.parse(s.last_seen_at);
437
+ return !Number.isNaN(t) && now - t > GHOST_MS;
438
+ };
328
439
  const online = sessions.filter(s => s.status !== 'offline' || sseCount(s)).sort(byAlias);
329
- const offline = sessions.filter(s => s.status === 'offline' && !sseCount(s)).sort(byAlias);
440
+ const offline = sessions.filter(s => s.status === 'offline' && !sseCount(s) && !isGhost(s)).sort(byAlias);
330
441
  const positions: Record<string, Point> = {};
331
442
 
443
+ if (layout === 'grid') {
444
+ // Issue #87 + #111: group-banded grid. Nodes are sorted by alias so
445
+ // same-prefix aliases are adjacent; each multi-member prefix group then
446
+ // gets its OWN row(s) starting at column 0, while singletons pack into
447
+ // shared rows. Group-banded placement keeps every group's bounding box
448
+ // (#111) a clean rectangle — no box ever overlaps another group's.
449
+ const all = [...online, ...offline];
450
+ const groupKeys = computeGroups(all);
451
+ const cols = Math.max(1, Math.ceil(Math.sqrt(all.length)));
452
+ // #112: gy0 starts below the (now compact) recent-signal / legend
453
+ // overlay panels — their max bottom edge is y≈112 — so grid row 0 is
454
+ // never occluded; gy1 extends near the canvas bottom for breathing room.
455
+ const gx0 = 150, gx1 = 850, gy0 = 126, gy1 = 652;
456
+ const cellW = (gx1 - gx0) / cols;
457
+ // largest node radius at the current size scale — drives the group
458
+ // label band + the row-height floor so nothing ever overlaps.
459
+ const nodeR = Math.round(26 * nodeScale);
460
+
461
+ // ordered runs of consecutive same-group-key nodes (≥2 = real group)
462
+ const runs: { key: string; members: Session[] }[] = [];
463
+ for (const s of all) {
464
+ const gk = groupKeys[s.alias];
465
+ const last = runs[runs.length - 1];
466
+ if (last && last.key === gk) last.members.push(s);
467
+ else runs.push({ key: gk, members: [s] });
468
+ }
469
+
470
+ // Pass 1 — assign each run to a band: a multi-member group owns its
471
+ // rows (left-aligned, so its bounding box is a tidy rect); contiguous
472
+ // singletons pack into shared rows (centred). Collect total row count.
473
+ type Band = { members: Session[]; startRow: number; centred: boolean; isGroup: boolean };
474
+ const bands: Band[] = [];
475
+ let row = 0;
476
+ let i = 0;
477
+ while (i < runs.length) {
478
+ if (runs[i].members.length >= 2) {
479
+ bands.push({ members: runs[i].members, startRow: row, centred: false, isGroup: true });
480
+ row += Math.ceil(runs[i].members.length / cols);
481
+ i++;
482
+ } else {
483
+ const singles: Session[] = [];
484
+ while (i < runs.length && runs[i].members.length < 2) {
485
+ singles.push(runs[i].members[0]);
486
+ i++;
487
+ }
488
+ bands.push({ members: singles, startRow: row, centred: true, isGroup: false });
489
+ row += Math.ceil(singles.length / cols);
490
+ }
491
+ }
492
+ const totalRows = Math.max(1, row);
493
+ // #112: the group label sits in a band ABOVE the topmost node, so the
494
+ // band must clear the node radius — GROUP_TOP is node-relative, never
495
+ // cellH-derived (cellH-derived was the label↔node overlap bug Vincent
496
+ // hit). cellH then floors at GROUP_TOP + 30 so the label band + bottom
497
+ // padding always fit and stacked group boxes never touch; past the
498
+ // floor the grid overflows and zoom/pan handles it.
499
+ const GROUP_TOP = nodeR + 20;
500
+ // Row-height floor = the tightest of: a node + its label below it
501
+ // (2·nodeR + ~22), and the label band + min box padding (GROUP_TOP + 12).
502
+ // Below this, rows would overlap; past it the grid overflows and
503
+ // zoom/pan covers the rest.
504
+ const cellH = Math.max(2 * nodeR + 22, GROUP_TOP + 12, Math.min(100, (gy1 - gy0) / totalRows));
505
+
506
+ // Pass 2 — place each band's members.
507
+ for (const band of bands) {
508
+ band.members.forEach((s, idx) => {
509
+ const rowInBand = Math.floor(idx / cols);
510
+ const c = idx % cols;
511
+ const inRow = Math.min(cols, band.members.length - rowInBand * cols);
512
+ const inset = band.centred ? ((cols - inRow) * cellW) / 2 : 0;
513
+ positions[s.alias] = {
514
+ x: gx0 + inset + (c + 0.5) * cellW,
515
+ y: gy0 + (band.startRow + rowInBand + 0.5) * cellH,
516
+ };
517
+ });
518
+ }
519
+
520
+ const links = buildFlowLinks(messages, positions);
521
+ const active = new Set<string>();
522
+ links.forEach(link => { active.add(link.from); active.add(link.to); });
523
+ // #111: one bounding box per multi-member group (Vincent 4722). Each
524
+ // group owns its rows; GROUP_PAD fills the row space left below the
525
+ // nodes after the label band, so stacked group boxes always have a
526
+ // gap between them (GROUP_TOP is defined above, with cellH).
527
+ const GROUP_PAD = Math.max(8, Math.min(26, cellH - GROUP_TOP - 8)); // side/bottom
528
+ const groupBoxes = bands
529
+ .filter(b => b.isGroup)
530
+ .map(band => {
531
+ const pts = band.members.map(s => positions[s.alias]).filter(Boolean);
532
+ const xs = pts.map(p => p.x);
533
+ const ys = pts.map(p => p.y);
534
+ const minX = Math.min(...xs), minY = Math.min(...ys);
535
+ return {
536
+ key: band.members.length ? groupKeys[band.members[0].alias] : '',
537
+ x: minX - GROUP_PAD,
538
+ y: minY - GROUP_TOP,
539
+ w: Math.max(...xs) - minX + GROUP_PAD * 2,
540
+ h: Math.max(...ys) - minY + GROUP_TOP + GROUP_PAD,
541
+ };
542
+ });
543
+ return {
544
+ onlineNodes: online,
545
+ offlineNodes: offline,
546
+ nodePositions: positions,
547
+ flowLinks: links,
548
+ activeAliases: active,
549
+ groupKeys,
550
+ groupBoxes,
551
+ };
552
+ }
553
+
332
554
  // Round 97 (issue #50) + 98 (issue #61): three layout modes by N.
333
555
  // N ≤ 8 → single ring (r=220)
334
556
  // 8 < N ≤ 14 → two rings (inner r=175, outer r=260, half-step rot)
@@ -396,7 +618,7 @@ export function TopoGraph({ sessions, sseSessions }: TopoGraphProps) {
396
618
  });
397
619
 
398
620
  // Round 106 (issue #83): group key per alias → shared hue per team.
399
- const groupKeys = computeGroupKeys([...online, ...offline].map(s => s.alias));
621
+ const groupKeys = computeGroups([...online, ...offline]);
400
622
 
401
623
  return {
402
624
  onlineNodes: online,
@@ -405,15 +627,36 @@ export function TopoGraph({ sessions, sseSessions }: TopoGraphProps) {
405
627
  flowLinks: links,
406
628
  activeAliases: active,
407
629
  groupKeys,
630
+ // #111: group boxes are a grid-layout feature only — radially scattered
631
+ // ring nodes can't be cleanly boxed. Ring keeps the #83 prefix hue.
632
+ groupBoxes: [] as { key: string; x: number; y: number; w: number; h: number }[],
408
633
  };
409
- }, [messages, sessions, sseSessions]);
634
+ }, [messages, sessions, sseSessions, layout, nodeScale]);
410
635
 
411
636
  const workingCount = onlineNodes.filter(s => s.status === 'working').length;
637
+ // Round 6 / Loop: vendor distribution for the header chip — at a glance
638
+ // "what's in the fleet" (A:5 M:2 O:8 书:12 …) without opening a node.
639
+ // Sorted by count desc; "unknown" vendors collapse into a "?" bucket.
640
+ const vendorDist = useMemo(() => {
641
+ const tally = new Map<string, { initial: string; count: number; color: string }>();
642
+ for (const s of [...onlineNodes, ...offlineNodes]) {
643
+ const v = vendorForModel(s.model);
644
+ const key = v.id === 'unknown' ? '?' : v.initial;
645
+ const cur = tally.get(key);
646
+ if (cur) cur.count++;
647
+ else tally.set(key, { initial: key, count: 1, color: v.mono.text });
648
+ }
649
+ return [...tally.values()].sort((a, b) => b.count - a.count);
650
+ }, [onlineNodes, offlineNodes]);
412
651
  // Round 109 (Vincent 4582 P0): hover-gated labels above this node count
413
652
  // so dense fleets show clean avatars instead of a wall of overlapping
414
653
  // label cards. 16 ≈ where the triple-tier rings start to crowd.
415
654
  const denseLayout = onlineNodes.length + offlineNodes.length > 16;
416
655
  const [hoveredAlias, setHoveredAlias] = useState<string | null>(null);
656
+ // Round 8 / Loop: which group is currently focused. Nodes outside this
657
+ // group + other group boxes fade so the eye locks onto the team you're
658
+ // pointing at. Singletons use their own alias as the group key.
659
+ const hoveredGroup = hoveredAlias ? (groupKeys[hoveredAlias] ?? hoveredAlias) : null;
417
660
 
418
661
  // --- Round 103 (issue #81): fullscreen + zoom + pan interaction layer ---
419
662
  // DIY native (no d3 / svg-pan-zoom): wrap the topology content in a single
@@ -433,6 +676,16 @@ export function TopoGraph({ sessions, sseSessions }: TopoGraphProps) {
433
676
  // Issue #100: singleton chat popover. One alias at a time — clicking
434
677
  // another node swaps the target and the conversation switches in place.
435
678
  const [chatAlias, setChatAlias] = useState<string | null>(null);
679
+ // #84: when a node is renamed while its chat popover is open, follow the
680
+ // rename so the conversation keeps targeting a live alias.
681
+ useEffect(() => {
682
+ if (renameSignal && renameSignal.from === chatAlias) {
683
+ setChatAlias(renameSignal.to);
684
+ }
685
+ // chatAlias intentionally omitted — only react to a new rename signal,
686
+ // not to the user opening/closing the popover.
687
+ // eslint-disable-next-line react-hooks/exhaustive-deps
688
+ }, [renameSignal]);
436
689
 
437
690
  useEffect(() => { viewRef.current = view; }, [view]);
438
691
 
@@ -555,13 +808,44 @@ export function TopoGraph({ sessions, sseSessions }: TopoGraphProps) {
555
808
  <div className="text-xs uppercase text-gray-600 tracking-wider">Network Topology</div>
556
809
  <h2 className="text-lg text-white font-semibold">Command mesh</h2>
557
810
  </div>
558
- <div className="flex flex-wrap gap-2 text-xs">
811
+ <div className="flex flex-wrap items-center gap-2 text-xs">
812
+ {/* Issue #87: ring | grid layout toggle — segmented control,
813
+ persisted to localStorage anet-topo-layout. */}
814
+ <div className="inline-flex rounded-md border border-gray-500/25 overflow-hidden" role="group" aria-label="Topology layout">
815
+ <button
816
+ onClick={() => { if (layout !== 'ring') toggleLayout(); }}
817
+ aria-pressed={layout === 'ring'}
818
+ className={`px-2.5 py-1 transition-colors ${layout === 'ring' ? 'bg-cyan-500/15 text-cyan-300' : 'text-gray-500 hover:text-gray-400'}`}
819
+ >
820
+ Ring
821
+ </button>
822
+ <button
823
+ onClick={() => { if (layout !== 'grid') toggleLayout(); }}
824
+ aria-pressed={layout === 'grid'}
825
+ className={`px-2.5 py-1 border-l border-gray-500/25 transition-colors ${layout === 'grid' ? 'bg-cyan-500/15 text-cyan-300' : 'text-gray-500 hover:text-gray-400'}`}
826
+ >
827
+ Grid
828
+ </button>
829
+ </div>
559
830
  <span className="px-2.5 py-1 rounded-md bg-green-500/10 text-green-300 border border-green-500/20">
560
831
  {workingCount} working
561
832
  </span>
562
833
  <span className="px-2.5 py-1 rounded-md bg-cyan-500/10 text-cyan-300 border border-cyan-500/20">
563
834
  {onlineNodes.length} online
564
835
  </span>
836
+ {vendorDist.length > 1 && (
837
+ <span
838
+ className="inline-flex items-center gap-2 px-2.5 py-1 rounded-md bg-gray-500/10 text-gray-400 border border-gray-500/20 font-mono"
839
+ title="Fleet by model vendor"
840
+ >
841
+ {vendorDist.map(v => (
842
+ <span key={v.initial} className="inline-flex items-baseline gap-0.5">
843
+ <span style={{ color: v.color }}>{v.initial}</span>
844
+ <span className="text-gray-500">:{v.count}</span>
845
+ </span>
846
+ ))}
847
+ </span>
848
+ )}
565
849
  <span className="px-2.5 py-1 rounded-md bg-gray-500/10 text-gray-400 border border-gray-500/20">
566
850
  {flowLinks.length} active links
567
851
  </span>
@@ -624,6 +908,10 @@ export function TopoGraph({ sessions, sseSessions }: TopoGraphProps) {
624
908
  {/* Round 103 (issue #81): everything inside this <g> zooms + pans
625
909
  together. transform order = translate then scale. */}
626
910
  <g transform={`translate(${view.x} ${view.y}) scale(${view.zoom})`}>
911
+ {/* Issue #87: radar/ring ambiance renders only in ring layout —
912
+ grid mode drops it so the concentric rings don't sit behind a
913
+ rectangular grid. */}
914
+ {layout === 'ring' && (<>
627
915
  <circle cx={cx} cy={cy} r="330" fill="url(#topo-radar)" />
628
916
 
629
917
  {/* Round 45: subtle star field — 24 deterministic dots scattered
@@ -705,12 +993,13 @@ export function TopoGraph({ sessions, sseSessions }: TopoGraphProps) {
705
993
  opacity={isLight ? 0.35 : 0.18}
706
994
  />
707
995
  ))}
996
+ </>)}
708
997
 
709
998
  {/* hub links — round 46: idle spokes now have animated
710
999
  stroke-dashoffset so dashes flow outward from the hub
711
1000
  ("command relay" feel). Active spokes carrying live message
712
1001
  flow stay as solid bright strokes. */}
713
- {onlineNodes.map((session, idx) => {
1002
+ {layout === 'ring' && onlineNodes.map((session, idx) => {
714
1003
  const pos = nodePositions[session.alias];
715
1004
  if (!pos) return null;
716
1005
  const path = curvePath({ x: cx, y: cy }, pos, 0);
@@ -731,16 +1020,68 @@ export function TopoGraph({ sessions, sseSessions }: TopoGraphProps) {
731
1020
  );
732
1021
  })}
733
1022
 
1023
+ {/* #111: prefix-group boundary boxes (Vincent 4722). Grid layout
1024
+ only — groupBoxes is empty in ring mode. Rendered behind the
1025
+ flow links + nodes; pointer-events off so they never intercept
1026
+ a node click. Restrained dashed container + group-name label. */}
1027
+ {groupBoxes.map(box => (
1028
+ <g
1029
+ key={`grp-${box.key}`}
1030
+ data-group={box.key}
1031
+ className="transition-opacity"
1032
+ // Round 8: dim group boxes outside the hover focus so the eye
1033
+ // locks on the team being inspected.
1034
+ style={{ pointerEvents: 'none', opacity: !hoveredGroup || box.key === hoveredGroup ? 1 : 0.28 }}
1035
+ >
1036
+ <rect
1037
+ x={box.x}
1038
+ y={box.y}
1039
+ width={box.w}
1040
+ height={box.h}
1041
+ rx="14"
1042
+ fill={isLight ? '#0f172a' : '#a5b4fc'}
1043
+ fillOpacity={isLight ? 0.025 : 0.045}
1044
+ stroke={pal.ringStroke}
1045
+ strokeWidth="1.5"
1046
+ strokeDasharray="6 6"
1047
+ />
1048
+ <text
1049
+ x={box.x + 12}
1050
+ y={box.y + 14}
1051
+ fill={pal.legendText}
1052
+ fontSize="13"
1053
+ fontFamily="monospace"
1054
+ fontWeight="700"
1055
+ >
1056
+ {box.key}
1057
+ </text>
1058
+ </g>
1059
+ ))}
1060
+
734
1061
  {/* directed message flows */}
735
1062
  {flowLinks.map((link, index) => {
736
1063
  const from = nodePositions[link.from];
737
1064
  const to = nodePositions[link.to];
738
1065
  if (!from || !to) return null;
739
1066
 
740
- const lift = index % 2 === 0 ? 36 : -36;
1067
+ // Round 7 / Loop: lift now scales with distance so short links
1068
+ // aren't over-bent (long links keep the ~36px hump), and the
1069
+ // particle period shortens with link.count so busier edges
1070
+ // visibly pulse faster — instant info density on top of the
1071
+ // existing stroke-width-by-count chip.
1072
+ const dist = Math.hypot(to.x - from.x, to.y - from.y);
1073
+ const lift = (index % 2 === 0 ? 1 : -1) * Math.min(36, dist * 0.18);
741
1074
  const path = curvePath(from, to, lift);
742
1075
  const width = Math.min(2 + link.count, 7);
743
- const duration = 2.2 + (index % 5) * 0.32;
1076
+ const duration = Math.max(0.9, 2.6 / Math.sqrt(link.count));
1077
+ // Round 10 / Loop: freshness fade. An edge that fired ≤30s ago
1078
+ // stays at full intensity; over 5 minutes it decays to ~35%.
1079
+ // Surfaces "what's happening now" vs background chatter without
1080
+ // hiding old flow entirely (some context still useful). `now`
1081
+ // captured at useMemo-recompute time (every 5s message refresh)
1082
+ // — accuracy is within the poll interval, plenty.
1083
+ const ageMs = link.last_at ? Math.max(0, Date.now() - Date.parse(link.last_at)) : 0;
1084
+ const fresh = Math.max(0.35, 1 - ageMs / (5 * 60 * 1000));
744
1085
 
745
1086
  return (
746
1087
  <g key={link.key}>
@@ -749,9 +1090,10 @@ export function TopoGraph({ sessions, sseSessions }: TopoGraphProps) {
749
1090
  fill="none"
750
1091
  stroke={pal.flowEdge}
751
1092
  strokeWidth={width}
752
- opacity={isLight ? 0.22 : 0.28}
1093
+ opacity={(isLight ? 0.22 : 0.28) * fresh}
753
1094
  filter={isLight ? undefined : 'url(#topo-glow)'}
754
1095
  markerEnd="url(#topo-arrow)"
1096
+ className="transition-opacity duration-500"
755
1097
  />
756
1098
  <path
757
1099
  id={`flow-path-${index}`}
@@ -760,45 +1102,45 @@ export function TopoGraph({ sessions, sseSessions }: TopoGraphProps) {
760
1102
  stroke={pal.flowPath}
761
1103
  strokeWidth="1"
762
1104
  strokeDasharray="2 12"
763
- opacity={isLight ? 0.4 : 0.75}
1105
+ opacity={(isLight ? 0.4 : 0.75) * fresh}
1106
+ className="transition-opacity duration-500"
764
1107
  />
765
- <circle r="4" fill={pal.flowParticle} filter={isLight ? undefined : 'url(#topo-glow)'}>
1108
+ <circle r="4" fill={pal.flowParticle} filter={isLight ? undefined : 'url(#topo-glow)'} opacity={fresh}>
766
1109
  <animateMotion dur={`${duration}s`} repeatCount="indefinite" path={path} />
767
1110
  </circle>
768
1111
  </g>
769
1112
  );
770
1113
  })}
771
1114
 
772
- {/* center hub — round 39: enlarged from r=6 (12px) to r=10 (20px)
773
- core so the "control plane" reads as the network's anchor,
774
- not a stray particle. Static halo ring at r=18 grounds it
775
- visually; two outward pulses keep the "signal source" idea
776
- from r17. Light theme gets a paler core to avoid hot-spotting
777
- the bg. */}
778
- <g>
779
- {/* static grounding halo sits underneath, low opacity */}
1115
+ {/* center hub — round 39 sized + round 13 restraint.
1116
+ The hub is the control-plane anchor. r39 gave it two outward
1117
+ pulses (r 10→38, 2.4s, double-phase) which read as "loudest
1118
+ node in the room" wrong semantics: anchors don't emit,
1119
+ they hold. r13 swaps the kinetic pulse for a slow opacity
1120
+ breath on the static halo (4s, ±15% from base), so the hub
1121
+ stays alive without throwing kinetic energy outward. The
1122
+ dual-circle "lit lamp" core is unchanged. */}
1123
+ {layout === 'ring' && (<g>
1124
+ {/* grounding halo — now breathes in opacity, no expansion */}
780
1125
  <circle
781
1126
  cx={cx} cy={cy} r="18"
782
1127
  fill={isLight ? '#d1fae5' : '#10b981'}
783
- opacity={isLight ? 0.35 : 0.10}
784
- />
785
- {/* outer pulse 1 */}
786
- <circle cx={cx} cy={cy} r="10" fill="none" stroke="#10b981" strokeWidth="1.5">
787
- <animate attributeName="r" values="10;38;10" dur="2.4s" repeatCount="indefinite" />
788
- <animate attributeName="opacity" values="0.55;0;0.55" dur="2.4s" repeatCount="indefinite" />
789
- </circle>
790
- {/* outer pulse 2 (delayed 1.2s) */}
791
- <circle cx={cx} cy={cy} r="10" fill="none" stroke="#10b981" strokeWidth="1.5" opacity="0">
792
- <animate attributeName="r" values="10;38;10" dur="2.4s" begin="1.2s" repeatCount="indefinite" />
793
- <animate attributeName="opacity" values="0.45;0;0.45" dur="2.4s" begin="1.2s" repeatCount="indefinite" />
1128
+ opacity={isLight ? 0.42 : 0.12}
1129
+ >
1130
+ <animate
1131
+ attributeName="opacity"
1132
+ values={isLight ? '0.32;0.52;0.32' : '0.08;0.16;0.08'}
1133
+ dur="4s"
1134
+ repeatCount="indefinite"
1135
+ />
794
1136
  </circle>
795
1137
  {/* core — 20px diameter, larger inner highlight reads as a "lit lamp" */}
796
1138
  <circle cx={cx} cy={cy} r="10" fill={isLight ? '#059669' : '#10b981'} />
797
1139
  <circle cx={cx} cy={cy} r="5" fill="#d1fae5" opacity="0.9" />
798
- </g>
1140
+ </g>)}
799
1141
 
800
1142
  {/* agent nodes */}
801
- {[...onlineNodes, ...offlineNodes].map(session => {
1143
+ {[...onlineNodes, ...offlineNodes].map((session, nodeIdx) => {
802
1144
  const pos = nodePositions[session.alias];
803
1145
  if (!pos) return null;
804
1146
 
@@ -806,7 +1148,9 @@ export function TopoGraph({ sessions, sseSessions }: TopoGraphProps) {
806
1148
  const isOnline = session.status !== 'offline' || !!sseCountFor;
807
1149
  const status = nodeStatus(session, isOnline, isLight);
808
1150
  const isActive = activeAliases.has(session.alias);
809
- const radius = isOnline ? 26 : 18;
1151
+ // #113: node size scales with the S/M/L control; halos, labels,
1152
+ // badge and avatar all derive from `radius` so they follow.
1153
+ const radius = Math.round((isOnline ? 26 : 18) * nodeScale);
810
1154
  // Round 109/110 (Vincent 4582 + 4583 P0): at high node counts
811
1155
  // the 100px opaque label cards overlapped each other and
812
1156
  // covered neighbouring avatars. But hiding text entirely went
@@ -816,12 +1160,34 @@ export function TopoGraph({ sessions, sseSessions }: TopoGraphProps) {
816
1160
  // occlude an avatar), and the full card appears only for the
817
1161
  // hovered node or once zoomed in past 1.4×.
818
1162
  const showFullLabel = !denseLayout || hoveredAlias === session.alias || view.zoom >= 1.4;
1163
+ // Round 8: when a node in another group is hovered, fade this
1164
+ // one. Same-group nodes (incl. singletons matching the hovered
1165
+ // alias) stay full. Pure visual focus, geometry unchanged.
1166
+ const inFocus = !hoveredGroup || (groupKeys[session.alias] ?? session.alias) === hoveredGroup;
819
1167
 
820
1168
  return (
821
1169
  <g
822
1170
  key={session.alias}
823
- className="transition-opacity"
824
- style={{ cursor: 'pointer' }}
1171
+ data-node={session.alias}
1172
+ // Round 3 / Loop: `anet-fade-in` runs once when the <g>
1173
+ // mounts — a new session entering the fleet (or the topology
1174
+ // first rendering) eases in instead of popping. Re-renders of
1175
+ // an existing node don't re-trigger (React preserves the <g>
1176
+ // via the alias key), so status changes don't flicker. The
1177
+ // global prefers-reduced-motion sweep already neutralises it.
1178
+ className="group transition-opacity anet-fade-in"
1179
+ style={{
1180
+ cursor: 'pointer',
1181
+ opacity: inFocus ? 1 : 0.32,
1182
+ // Round 9 / Loop: stagger the anet-fade-in so the topology
1183
+ // reveals as a wave on first paint instead of one big pop.
1184
+ // Cap at 24 indices (≈600ms tail) so 50-node fleets still
1185
+ // finish revealing within a beat. CSS animation-delay only
1186
+ // applies during the keyframe — re-renders without a new
1187
+ // mount (same alias key) don't replay, so status changes
1188
+ // never trigger the stagger again.
1189
+ animationDelay: `${Math.min(nodeIdx, 24) * 25}ms`,
1190
+ }}
825
1191
  // Stop the pointerdown from reaching the SVG pan handler: the
826
1192
  // SVG calls setPointerCapture, and a captured pointer makes
827
1193
  // Chromium fire the follow-up `click` on the SVG instead of
@@ -829,17 +1195,74 @@ export function TopoGraph({ sessions, sseSessions }: TopoGraphProps) {
829
1195
  // Side effect (intended): you pan from empty canvas, not by
830
1196
  // grabbing a node.
831
1197
  onPointerDown={(e) => e.stopPropagation()}
832
- onPointerEnter={() => denseLayout && setHoveredAlias(session.alias)}
833
- onPointerLeave={() => denseLayout && setHoveredAlias(prev => (prev === session.alias ? null : prev))}
1198
+ // Track hover globally (not just under denseLayout) so the
1199
+ // Round 8 group-focus fade works at any fleet size.
1200
+ onPointerEnter={() => setHoveredAlias(session.alias)}
1201
+ onPointerLeave={() => setHoveredAlias(prev => (prev === session.alias ? null : prev))}
834
1202
  onClick={() => setChatAlias(session.alias)}
835
1203
  >
1204
+ {/* Issue #96: native hover tooltip — "Vendor · model · Runtime".
1205
+ Falls back to just the alias when the node reports no
1206
+ model/runtime. */}
1207
+ <title>{identityLine(session.model, session.runtime) || session.alias}</title>
1208
+ {/* Round 2 / Loop: hover ring — a thin outer stroke that fades
1209
+ in when the cursor enters the node, signalling clickability
1210
+ (real-user feedback for the chat-popover open). Pure CSS via
1211
+ Tailwind group-hover, so it costs nothing per frame and
1212
+ respects prefers-reduced-motion via the global media query. */}
1213
+ <circle
1214
+ cx={pos.x}
1215
+ cy={pos.y}
1216
+ r={radius + 12}
1217
+ fill="none"
1218
+ stroke={status.primary}
1219
+ // strokeWidth must NOT be 1.5 (offline status ring) or 3
1220
+ // (online status ring) — the overlap test selects by those
1221
+ // exact widths and would mis-count this invisible hover
1222
+ // ring as a node footprint.
1223
+ strokeWidth="2"
1224
+ className="opacity-0 group-hover:opacity-70 transition-opacity duration-150"
1225
+ style={{ pointerEvents: 'none' }}
1226
+ />
1227
+ {/* Round 11 / Loop: chat-focus ring — when the ChatPopover is
1228
+ open targeting this node, anchor a persistent ring around
1229
+ it so the floating popover visibly links back to its source
1230
+ node. Static (not pulsing) so it reads as "selected state"
1231
+ rather than "this node is active". strokeWidth=2.5 stays
1232
+ clear of the overlap-test selectors (1.5 / 3). Sits just
1233
+ outside the halo radius+8 so it never overlaps a neighbour
1234
+ (halos already pack flush in dense grids). */}
1235
+ {chatAlias === session.alias && (
1236
+ <circle
1237
+ cx={pos.x}
1238
+ cy={pos.y}
1239
+ r={radius + 14}
1240
+ fill="none"
1241
+ stroke={status.primary}
1242
+ strokeWidth="2.5"
1243
+ opacity={isLight ? 0.85 : 0.95}
1244
+ filter={!isLight ? 'url(#topo-glow)' : undefined}
1245
+ className="transition-opacity duration-200"
1246
+ style={{ pointerEvents: 'none' }}
1247
+ />
1248
+ )}
836
1249
  {isActive && (
837
1250
  <circle cx={pos.x} cy={pos.y} r={radius + 14} fill={status.primary} opacity={isLight ? 0.08 : 0.12}>
838
1251
  <animate attributeName="r" values={`${radius + 8};${radius + 22};${radius + 8}`} dur="2.4s" repeatCount="indefinite" />
839
1252
  <animate attributeName="opacity" values={isLight ? '0.12;0.02;0.12' : '0.18;0.04;0.18'} dur="2.4s" repeatCount="indefinite" />
840
1253
  </circle>
841
1254
  )}
842
- <circle cx={pos.x} cy={pos.y} r={radius + 8} fill={status.halo} opacity={isOnline ? (isLight ? 0.85 : 0.65) : (isLight ? 0.4 : 0.25)} />
1255
+ {/* Round 4 / Loop: transition-[fill,stroke,opacity] smooths
1256
+ status colour changes so idle↔working↔offline doesn't snap
1257
+ — task replies / node-rename / SSE updates ease in. */}
1258
+ <circle
1259
+ cx={pos.x}
1260
+ cy={pos.y}
1261
+ r={radius + 8}
1262
+ fill={status.halo}
1263
+ opacity={isOnline ? (isLight ? 0.85 : 0.65) : (isLight ? 0.4 : 0.25)}
1264
+ className="transition-[fill,opacity] duration-300 ease-out"
1265
+ />
843
1266
  <circle
844
1267
  cx={pos.x}
845
1268
  cy={pos.y}
@@ -849,34 +1272,28 @@ export function TopoGraph({ sessions, sseSessions }: TopoGraphProps) {
849
1272
  strokeWidth={isOnline ? 3 : 1.5}
850
1273
  strokeDasharray={isOnline ? 'none' : '5 5'}
851
1274
  filter={isOnline && !isLight ? 'url(#topo-glow)' : undefined}
1275
+ className="transition-[fill,stroke] duration-300 ease-out"
852
1276
  />
853
- {/* Round 99 (issue #79): node "avatar" hue-hashed
854
- initials circle inside the status ring. Round 100:
855
- when brand=intern, swap the initials for the 书小生
856
- mascot image (asset from 群星马 task 51dd0d1d). The
857
- image already has a transparent bg so it sits cleanly
858
- on the node's dark/light fill; the outer status ring
859
- still carries working/idle/etc. */}
1277
+ {/* Issue #96: node "avatar" is now driven by the model
1278
+ vendor. Decision order:
1279
+ 1. ?brand=intern flag, or an intern-aliased node with
1280
+ no model field 书生 coin (preserves #79).
1281
+ 2. vendor has a packaged logo asset that logo image
1282
+ (intern-s1-* models land here via vendorForModel).
1283
+ 3. known vendor, logo asset not shipped yet → a
1284
+ vendor-tinted monogram (spec-mandated fallback).
1285
+ 4. unknown vendor / null model → the prefix-group
1286
+ hue-hashed initial (#83/#99 behaviour, unchanged). */}
860
1287
  {(() => {
861
- const ar = isOnline ? 14 : 10;
862
- // Round 108 (issue #79 reopened): show the 书小生 avatar
863
- // coin for any agent whose alias marks it as an Intern /
864
- // 书生 runtime — not only under the global ?brand=intern
865
- // flag. Vincent 4565: a fleet of 书生N号 nodes should SHOW
866
- // 书生, not a generic "书" initial. ?brand=intern still
867
- // forces the coin on every node (full brand showcase).
868
- const isInternNode = isIntern || /书生|书小生|intern/i.test(session.alias);
869
- if (isInternNode) {
870
- // Round 102: self-contained "avatar coin" — 书小生 figure
871
- // keyed off its white background and composited onto a
872
- // cream circular backplate. The cream coin gives the
873
- // dark-haired figure consistent contrast on BOTH the
874
- // dark cyber theme and light theme. Render at the node
875
- // diameter so the coin fills inside the status ring.
876
- const size = radius * 2;
1288
+ const ar = Math.round((isOnline ? 14 : 10) * nodeScale);
1289
+ const size = radius * 2;
1290
+ const vendor = vendorForModel(session.model);
1291
+ const internByAlias = /书生|书小生|intern/i.test(session.alias);
1292
+
1293
+ if (isIntern || internByAlias || vendor.logo) {
877
1294
  return (
878
1295
  <image
879
- href="/intern_avatar.png"
1296
+ href={vendor.logo ?? '/intern_avatar.png'}
880
1297
  x={pos.x - size / 2}
881
1298
  y={pos.y - size / 2}
882
1299
  width={size}
@@ -885,12 +1302,25 @@ export function TopoGraph({ sessions, sseSessions }: TopoGraphProps) {
885
1302
  />
886
1303
  );
887
1304
  }
1305
+ if (vendor.id !== 'unknown') {
1306
+ // Known model house, logo asset not in public/vendors/
1307
+ // yet — vendor-tinted monogram stands in.
1308
+ return (
1309
+ <>
1310
+ <circle cx={pos.x} cy={pos.y} r={ar} fill={vendor.mono.bg} stroke={vendor.mono.ring} strokeWidth="1" />
1311
+ <text
1312
+ x={pos.x} y={pos.y} dy="0.34em" textAnchor="middle"
1313
+ fill={vendor.mono.text} fontSize={ar}
1314
+ fontFamily="monospace" fontWeight="700"
1315
+ >
1316
+ {vendor.initial}
1317
+ </text>
1318
+ </>
1319
+ );
1320
+ }
888
1321
  // Round 106 (issue #83): hue keyed to the prefix group,
889
- // not the full alias — every 通信* node shares one color,
890
- // every 研究员* another, so teams cluster visually even
891
- // when the tier layout spreads them across rings.
1322
+ // not the full alias — every 通信* node shares one color.
892
1323
  const c = aliasAvatarColors(groupKeys[session.alias] || session.alias);
893
- const fs = isOnline ? 14 : 10;
894
1324
  return (
895
1325
  <>
896
1326
  <circle cx={pos.x} cy={pos.y} r={ar} fill={c.bg} stroke={c.ring} strokeWidth="1" />
@@ -900,7 +1330,7 @@ export function TopoGraph({ sessions, sseSessions }: TopoGraphProps) {
900
1330
  dy="0.34em"
901
1331
  textAnchor="middle"
902
1332
  fill={c.text}
903
- fontSize={fs}
1333
+ fontSize={ar}
904
1334
  fontFamily="monospace"
905
1335
  fontWeight="700"
906
1336
  >
@@ -909,12 +1339,32 @@ export function TopoGraph({ sessions, sseSessions }: TopoGraphProps) {
909
1339
  </>
910
1340
  );
911
1341
  })()}
1342
+ {/* Issue #96: runtime badge — small corner glyph marking the
1343
+ execution shell (CLI / SDK / HTTP API). Sits bottom-right
1344
+ of the avatar; colours kept off the working/idle/offline
1345
+ status hues. Absent when the node reports no runtime. */}
1346
+ {(() => {
1347
+ const rt = runtimeIdentity(session.runtime);
1348
+ if (!rt) return null;
1349
+ const br = isOnline ? 7 : 5.5;
1350
+ const bx = pos.x + radius * 0.72;
1351
+ const by = pos.y + radius * 0.72;
1352
+ const icon = br * 2 * 0.62;
1353
+ return (
1354
+ <g style={{ pointerEvents: 'none' }}>
1355
+ <circle cx={bx} cy={by} r={br} fill={pal.containerBg} stroke={rt.color} strokeWidth="1.5" />
1356
+ <g transform={`translate(${bx - icon / 2} ${by - icon / 2}) scale(${icon / 24})`}>
1357
+ <path d={rt.iconPath} fill="none" stroke={rt.color} strokeWidth="2.4" strokeLinecap="round" strokeLinejoin="round" />
1358
+ </g>
1359
+ </g>
1360
+ );
1361
+ })()}
912
1362
  {session.status === 'working' && (
913
1363
  // working pulse — small dot just inside the status ring,
914
1364
  // above the avatar text. Was a 18px horizontal bar at
915
1365
  // y+11 which now collides with the avatar; the dot reads
916
1366
  // as the same "active" cue without occluding the initial.
917
- <circle cx={pos.x} cy={pos.y - (isOnline ? 18 : 13)} r="2.5" fill={pal.flowParticle}>
1367
+ <circle cx={pos.x} cy={pos.y - (radius - 6)} r="2.5" fill={pal.flowParticle}>
918
1368
  <animate attributeName="opacity" values="1;0.25;1" dur="1.1s" repeatCount="indefinite" />
919
1369
  </circle>
920
1370
  )}
@@ -955,29 +1405,37 @@ export function TopoGraph({ sessions, sseSessions }: TopoGraphProps) {
955
1405
  );
956
1406
  })}
957
1407
 
1408
+ </g>
1409
+
1410
+ {/* #112: overlay panels (recent-signal + legend) render OUTSIDE the
1411
+ zoom/pan <g> so they stay fixed while the topology pans/zooms.
1412
+ They're sized + tucked into the top corners so every corner of
1413
+ each panel is >325px from the canvas centre — i.e. fully outside
1414
+ the outermost (offline) ring. No node on any ring can reach the
1415
+ corner triangles, so the panels never overlap a node, in ring
1416
+ OR grid layout (Vincent 4727 zero-overlap criterion). */}
958
1417
  {/* latest flow labels */}
959
- <g transform="translate(28, 34)">
960
- <rect x="0" y="0" width="285" height={60 + Math.min(flowLinks.length, 4) * 20} rx="8" fill={pal.legendBox.fill} stroke={pal.legendBox.stroke} opacity={isLight ? 1 : 0.94} />
961
- <text x="16" y="26" fill={pal.legendHeadline} fontSize="13" fontFamily="monospace" fontWeight="700">recent signal</text>
962
- <text x="178" y="26" fill={pal.legendAccent} fontSize="11" fontFamily="monospace">{messages.length} messages</text>
963
- {flowLinks.slice(0, 4).map((link, index) => (
964
- <text key={link.key} x="16" y={54 + index * 20} fill={pal.legendText} fontSize="10" fontFamily="monospace">
965
- {truncate(link.from, 8)} {'->'} {truncate(link.to, 8)} / {link.count} / {truncate(link.content, 18)}
1418
+ <g transform="translate(16, 16)">
1419
+ <rect x="0" y="0" width="230" height="84" rx="10" fill={pal.legendBox.fill} stroke={pal.legendBox.stroke} opacity={isLight ? 0.97 : 0.92} />
1420
+ <text x="13" y="21" fill={pal.legendHeadline} fontSize="12" fontFamily="monospace" fontWeight="700">recent signal</text>
1421
+ <text x="150" y="21" fill={pal.legendAccent} fontSize="10" fontFamily="monospace">{messages.length} msgs</text>
1422
+ {flowLinks.slice(0, 3).map((link, index) => (
1423
+ <text key={link.key} x="13" y={38 + index * 16} fill={pal.legendText} fontSize="9" fontFamily="monospace">
1424
+ {truncate(link.from, 6)} {'->'} {truncate(link.to, 6)} / {link.count} / {truncate(link.content, 12)}
966
1425
  </text>
967
1426
  ))}
968
1427
  </g>
969
1428
 
970
1429
  {/* legend */}
971
- <g transform="translate(720, 34)">
972
- <rect x="0" y="0" width="250" height="112" rx="8" fill={pal.legendBox.fill} stroke={pal.legendBox.stroke} opacity={isLight ? 1 : 0.94} />
973
- <circle cx="18" cy="26" r="6" fill={isLight ? '#059669' : '#22c55e'} />
974
- <text x="34" y="30" fill={pal.legendText} fontSize="11" fontFamily="monospace">working node</text>
975
- <circle cx="18" cy="52" r="6" fill={isLight ? '#0d9488' : '#2dd4bf'} />
976
- <text x="34" y="56" fill={pal.legendText} fontSize="11" fontFamily="monospace">online idle</text>
977
- <circle cx="18" cy="78" r="6" fill={isLight ? '#94a3b8' : '#6b7280'} />
978
- <text x="34" y="82" fill={pal.legendText} fontSize="11" fontFamily="monospace">offline / no SSE</text>
979
- <path d="M150,78 Q176,52 210,78" fill="none" stroke={pal.flowEdge} strokeWidth="3" markerEnd="url(#topo-arrow)" />
980
- </g>
1430
+ <g transform="translate(760, 16)">
1431
+ <rect x="0" y="0" width="224" height="96" rx="10" fill={pal.legendBox.fill} stroke={pal.legendBox.stroke} opacity={isLight ? 0.97 : 0.92} />
1432
+ <circle cx="16" cy="24" r="5.5" fill={isLight ? '#059669' : '#22c55e'} />
1433
+ <text x="30" y="28" fill={pal.legendText} fontSize="11" fontFamily="monospace">working node</text>
1434
+ <circle cx="16" cy="48" r="5.5" fill={isLight ? '#0d9488' : '#2dd4bf'} />
1435
+ <text x="30" y="52" fill={pal.legendText} fontSize="11" fontFamily="monospace">online idle</text>
1436
+ <circle cx="16" cy="72" r="5.5" fill={isLight ? '#94a3b8' : '#6b7280'} />
1437
+ <text x="30" y="76" fill={pal.legendText} fontSize="11" fontFamily="monospace">offline / no SSE</text>
1438
+ <path d="M140,72 Q164,48 196,72" fill="none" stroke={pal.flowEdge} strokeWidth="3" markerEnd="url(#topo-arrow)" />
981
1439
  </g>
982
1440
  </svg>
983
1441
 
@@ -988,6 +1446,26 @@ export function TopoGraph({ sessions, sseSessions }: TopoGraphProps) {
988
1446
  Split into a plain % readout + an explicit reset button with
989
1447
  its own icon + tooltip. */}
990
1448
  <div className="absolute bottom-3 right-3 flex items-center gap-1.5 text-xs select-none">
1449
+ {/* #113: node size — S / M / L segmented control (Vincent 4727). */}
1450
+ <div
1451
+ className="flex items-center rounded-md border overflow-hidden"
1452
+ style={{ background: pal.legendBox.fill, borderColor: pal.containerBorder }}
1453
+ role="group"
1454
+ aria-label="Node size"
1455
+ >
1456
+ {([['S', 0.7], ['M', 0.84], ['L', 1]] as const).map(([lbl, v], idx) => (
1457
+ <button
1458
+ key={lbl}
1459
+ onClick={() => pickNodeScale(v)}
1460
+ aria-pressed={nodeScale === v}
1461
+ title={`Node size: ${lbl === 'S' ? 'small' : lbl === 'M' ? 'medium' : 'large'}`}
1462
+ className={`px-2 py-1 transition-colors ${idx > 0 ? 'border-l' : ''} ${nodeScale === v ? 'bg-cyan-500/15 text-cyan-300' : 'hover:bg-white/5'}`}
1463
+ style={{ color: nodeScale === v ? undefined : pal.legendText, borderColor: pal.containerBorder }}
1464
+ >
1465
+ {lbl}
1466
+ </button>
1467
+ ))}
1468
+ </div>
991
1469
  <div
992
1470
  className="flex items-center rounded-md border overflow-hidden"
993
1471
  style={{ background: pal.legendBox.fill, borderColor: pal.containerBorder }}