@sleep2agi/agent-network-dashboard 0.5.7-preview.7 → 0.5.7-preview.73

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 (376) hide show
  1. package/.next/BUILD_ID +1 -1
  2. package/.next/app-path-routes-manifest.json +0 -1
  3. package/.next/build-manifest.json +3 -3
  4. package/.next/diagnostics/route-bundle-stats.json +65 -65
  5. package/.next/fallback-build-manifest.json +3 -3
  6. package/.next/prerender-manifest.json +3 -3
  7. package/.next/routes-manifest.json +0 -6
  8. package/.next/server/app/_global-error.html +1 -1
  9. package/.next/server/app/_global-error.rsc +1 -1
  10. package/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  11. package/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  12. package/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  13. package/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  14. package/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  15. package/.next/server/app/_not-found/page/next-font-manifest.json +2 -1
  16. package/.next/server/app/_not-found/page.js +1 -1
  17. package/.next/server/app/_not-found/page.js.nft.json +1 -1
  18. package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  19. package/.next/server/app/_not-found.html +4 -4
  20. package/.next/server/app/_not-found.rsc +16 -16
  21. package/.next/server/app/_not-found.segments/_full.segment.rsc +16 -16
  22. package/.next/server/app/_not-found.segments/_head.segment.rsc +4 -4
  23. package/.next/server/app/_not-found.segments/_index.segment.rsc +9 -9
  24. package/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +2 -2
  25. package/.next/server/app/_not-found.segments/_not-found.segment.rsc +3 -3
  26. package/.next/server/app/_not-found.segments/_tree.segment.rsc +3 -3
  27. package/.next/server/app/admin/page/next-font-manifest.json +2 -1
  28. package/.next/server/app/admin/page.js +1 -1
  29. package/.next/server/app/admin/page.js.nft.json +1 -1
  30. package/.next/server/app/admin/page_client-reference-manifest.js +1 -1
  31. package/.next/server/app/admin.html +4 -4
  32. package/.next/server/app/admin.rsc +20 -19
  33. package/.next/server/app/admin.segments/_full.segment.rsc +20 -19
  34. package/.next/server/app/admin.segments/_head.segment.rsc +4 -4
  35. package/.next/server/app/admin.segments/_index.segment.rsc +9 -9
  36. package/.next/server/app/admin.segments/_tree.segment.rsc +5 -4
  37. package/.next/server/app/admin.segments/admin/__PAGE__.segment.rsc +4 -4
  38. package/.next/server/app/admin.segments/admin.segment.rsc +3 -3
  39. package/.next/server/app/index.html +4 -4
  40. package/.next/server/app/index.rsc +20 -19
  41. package/.next/server/app/index.segments/__PAGE__.segment.rsc +4 -4
  42. package/.next/server/app/index.segments/_full.segment.rsc +20 -19
  43. package/.next/server/app/index.segments/_head.segment.rsc +4 -4
  44. package/.next/server/app/index.segments/_index.segment.rsc +9 -9
  45. package/.next/server/app/index.segments/_tree.segment.rsc +5 -4
  46. package/.next/server/app/login/page/next-font-manifest.json +2 -1
  47. package/.next/server/app/login/page.js +1 -1
  48. package/.next/server/app/login/page.js.nft.json +1 -1
  49. package/.next/server/app/login/page_client-reference-manifest.js +1 -1
  50. package/.next/server/app/login.html +2 -2
  51. package/.next/server/app/login.rsc +20 -19
  52. package/.next/server/app/login.segments/_full.segment.rsc +20 -19
  53. package/.next/server/app/login.segments/_head.segment.rsc +4 -4
  54. package/.next/server/app/login.segments/_index.segment.rsc +9 -9
  55. package/.next/server/app/login.segments/_tree.segment.rsc +5 -4
  56. package/.next/server/app/login.segments/login/__PAGE__.segment.rsc +4 -4
  57. package/.next/server/app/login.segments/login.segment.rsc +3 -3
  58. package/.next/server/app/logs/page/next-font-manifest.json +2 -1
  59. package/.next/server/app/logs/page.js +1 -1
  60. package/.next/server/app/logs/page.js.nft.json +1 -1
  61. package/.next/server/app/logs/page_client-reference-manifest.js +1 -1
  62. package/.next/server/app/logs.html +4 -4
  63. package/.next/server/app/logs.rsc +20 -19
  64. package/.next/server/app/logs.segments/_full.segment.rsc +20 -19
  65. package/.next/server/app/logs.segments/_head.segment.rsc +4 -4
  66. package/.next/server/app/logs.segments/_index.segment.rsc +9 -9
  67. package/.next/server/app/logs.segments/_tree.segment.rsc +5 -4
  68. package/.next/server/app/logs.segments/logs/__PAGE__.segment.rsc +4 -4
  69. package/.next/server/app/logs.segments/logs.segment.rsc +3 -3
  70. package/.next/server/app/manifest.webmanifest.body +1 -1
  71. package/.next/server/app/messages/page/next-font-manifest.json +2 -1
  72. package/.next/server/app/messages/page.js +1 -1
  73. package/.next/server/app/messages/page.js.nft.json +1 -1
  74. package/.next/server/app/messages/page_client-reference-manifest.js +1 -1
  75. package/.next/server/app/messages.html +4 -4
  76. package/.next/server/app/messages.rsc +20 -19
  77. package/.next/server/app/messages.segments/_full.segment.rsc +20 -19
  78. package/.next/server/app/messages.segments/_head.segment.rsc +4 -4
  79. package/.next/server/app/messages.segments/_index.segment.rsc +9 -9
  80. package/.next/server/app/messages.segments/_tree.segment.rsc +5 -4
  81. package/.next/server/app/messages.segments/messages/__PAGE__.segment.rsc +4 -4
  82. package/.next/server/app/messages.segments/messages.segment.rsc +3 -3
  83. package/.next/server/app/node/page/next-font-manifest.json +2 -1
  84. package/.next/server/app/node/page.js +1 -1
  85. package/.next/server/app/node/page.js.nft.json +1 -1
  86. package/.next/server/app/node/page_client-reference-manifest.js +1 -1
  87. package/.next/server/app/node.html +4 -4
  88. package/.next/server/app/node.rsc +20 -19
  89. package/.next/server/app/node.segments/_full.segment.rsc +20 -19
  90. package/.next/server/app/node.segments/_head.segment.rsc +4 -4
  91. package/.next/server/app/node.segments/_index.segment.rsc +9 -9
  92. package/.next/server/app/node.segments/_tree.segment.rsc +5 -4
  93. package/.next/server/app/node.segments/node/__PAGE__.segment.rsc +4 -4
  94. package/.next/server/app/node.segments/node.segment.rsc +3 -3
  95. package/.next/server/app/nodes/page/next-font-manifest.json +2 -1
  96. package/.next/server/app/nodes/page.js +1 -1
  97. package/.next/server/app/nodes/page.js.nft.json +1 -1
  98. package/.next/server/app/nodes/page_client-reference-manifest.js +1 -1
  99. package/.next/server/app/nodes.html +4 -4
  100. package/.next/server/app/nodes.rsc +20 -19
  101. package/.next/server/app/nodes.segments/_full.segment.rsc +20 -19
  102. package/.next/server/app/nodes.segments/_head.segment.rsc +4 -4
  103. package/.next/server/app/nodes.segments/_index.segment.rsc +9 -9
  104. package/.next/server/app/nodes.segments/_tree.segment.rsc +5 -4
  105. package/.next/server/app/nodes.segments/nodes/__PAGE__.segment.rsc +4 -4
  106. package/.next/server/app/nodes.segments/nodes.segment.rsc +3 -3
  107. package/.next/server/app/page/next-font-manifest.json +2 -1
  108. package/.next/server/app/page.js +1 -1
  109. package/.next/server/app/page.js.nft.json +1 -1
  110. package/.next/server/app/page_client-reference-manifest.js +1 -1
  111. package/.next/server/app/server-logs/page/next-font-manifest.json +2 -1
  112. package/.next/server/app/server-logs/page.js +1 -1
  113. package/.next/server/app/server-logs/page.js.nft.json +1 -1
  114. package/.next/server/app/server-logs/page_client-reference-manifest.js +1 -1
  115. package/.next/server/app/server-logs.html +4 -4
  116. package/.next/server/app/server-logs.rsc +20 -19
  117. package/.next/server/app/server-logs.segments/_full.segment.rsc +20 -19
  118. package/.next/server/app/server-logs.segments/_head.segment.rsc +4 -4
  119. package/.next/server/app/server-logs.segments/_index.segment.rsc +9 -9
  120. package/.next/server/app/server-logs.segments/_tree.segment.rsc +5 -4
  121. package/.next/server/app/server-logs.segments/server-logs/__PAGE__.segment.rsc +4 -4
  122. package/.next/server/app/server-logs.segments/server-logs.segment.rsc +3 -3
  123. package/.next/server/app/servers/page/next-font-manifest.json +2 -1
  124. package/.next/server/app/servers/page.js +1 -1
  125. package/.next/server/app/servers/page.js.nft.json +1 -1
  126. package/.next/server/app/servers/page_client-reference-manifest.js +1 -1
  127. package/.next/server/app/servers.html +4 -4
  128. package/.next/server/app/servers.rsc +20 -19
  129. package/.next/server/app/servers.segments/_full.segment.rsc +20 -19
  130. package/.next/server/app/servers.segments/_head.segment.rsc +4 -4
  131. package/.next/server/app/servers.segments/_index.segment.rsc +9 -9
  132. package/.next/server/app/servers.segments/_tree.segment.rsc +5 -4
  133. package/.next/server/app/servers.segments/servers/__PAGE__.segment.rsc +4 -4
  134. package/.next/server/app/servers.segments/servers.segment.rsc +3 -3
  135. package/.next/server/app/settings/networks/page/next-font-manifest.json +2 -1
  136. package/.next/server/app/settings/networks/page.js +1 -1
  137. package/.next/server/app/settings/networks/page.js.nft.json +1 -1
  138. package/.next/server/app/settings/networks/page_client-reference-manifest.js +1 -1
  139. package/.next/server/app/settings/networks.html +4 -4
  140. package/.next/server/app/settings/networks.rsc +20 -19
  141. package/.next/server/app/settings/networks.segments/_full.segment.rsc +20 -19
  142. package/.next/server/app/settings/networks.segments/_head.segment.rsc +4 -4
  143. package/.next/server/app/settings/networks.segments/_index.segment.rsc +9 -9
  144. package/.next/server/app/settings/networks.segments/_tree.segment.rsc +5 -4
  145. package/.next/server/app/settings/networks.segments/settings/networks/__PAGE__.segment.rsc +4 -4
  146. package/.next/server/app/settings/networks.segments/settings/networks.segment.rsc +3 -3
  147. package/.next/server/app/settings/networks.segments/settings.segment.rsc +3 -3
  148. package/.next/server/app/settings/page/next-font-manifest.json +2 -1
  149. package/.next/server/app/settings/page.js +1 -1
  150. package/.next/server/app/settings/page.js.nft.json +1 -1
  151. package/.next/server/app/settings/page_client-reference-manifest.js +1 -1
  152. package/.next/server/app/settings/tokens/page/next-font-manifest.json +2 -1
  153. package/.next/server/app/settings/tokens/page.js +1 -1
  154. package/.next/server/app/settings/tokens/page.js.nft.json +1 -1
  155. package/.next/server/app/settings/tokens/page_client-reference-manifest.js +1 -1
  156. package/.next/server/app/settings/tokens.html +4 -4
  157. package/.next/server/app/settings/tokens.rsc +20 -19
  158. package/.next/server/app/settings/tokens.segments/_full.segment.rsc +20 -19
  159. package/.next/server/app/settings/tokens.segments/_head.segment.rsc +4 -4
  160. package/.next/server/app/settings/tokens.segments/_index.segment.rsc +9 -9
  161. package/.next/server/app/settings/tokens.segments/_tree.segment.rsc +5 -4
  162. package/.next/server/app/settings/tokens.segments/settings/tokens/__PAGE__.segment.rsc +4 -4
  163. package/.next/server/app/settings/tokens.segments/settings/tokens.segment.rsc +3 -3
  164. package/.next/server/app/settings/tokens.segments/settings.segment.rsc +3 -3
  165. package/.next/server/app/settings.html +4 -4
  166. package/.next/server/app/settings.rsc +20 -19
  167. package/.next/server/app/settings.segments/_full.segment.rsc +20 -19
  168. package/.next/server/app/settings.segments/_head.segment.rsc +4 -4
  169. package/.next/server/app/settings.segments/_index.segment.rsc +9 -9
  170. package/.next/server/app/settings.segments/_tree.segment.rsc +5 -4
  171. package/.next/server/app/settings.segments/settings/__PAGE__.segment.rsc +4 -4
  172. package/.next/server/app/settings.segments/settings.segment.rsc +3 -3
  173. package/.next/server/app/tasks/[id]/page/next-font-manifest.json +2 -1
  174. package/.next/server/app/tasks/[id]/page.js +1 -1
  175. package/.next/server/app/tasks/[id]/page.js.nft.json +1 -1
  176. package/.next/server/app/tasks/[id]/page_client-reference-manifest.js +1 -1
  177. package/.next/server/app/tasks/page/next-font-manifest.json +2 -1
  178. package/.next/server/app/tasks/page.js +1 -1
  179. package/.next/server/app/tasks/page.js.nft.json +1 -1
  180. package/.next/server/app/tasks/page_client-reference-manifest.js +1 -1
  181. package/.next/server/app/tasks.html +4 -4
  182. package/.next/server/app/tasks.rsc +20 -19
  183. package/.next/server/app/tasks.segments/_full.segment.rsc +20 -19
  184. package/.next/server/app/tasks.segments/_head.segment.rsc +4 -4
  185. package/.next/server/app/tasks.segments/_index.segment.rsc +9 -9
  186. package/.next/server/app/tasks.segments/_tree.segment.rsc +5 -4
  187. package/.next/server/app/tasks.segments/tasks/__PAGE__.segment.rsc +4 -4
  188. package/.next/server/app/tasks.segments/tasks.segment.rsc +3 -3
  189. package/.next/server/app-paths-manifest.json +0 -1
  190. package/.next/server/chunks/00jm_next_dist_0ju_ux9._.js +1 -1
  191. package/.next/server/chunks/00jm_next_dist_0ju_ux9._.js.map +1 -1
  192. package/.next/server/chunks/ssr/[root-of-the-server]__030vg4n._.js +1 -1
  193. package/.next/server/chunks/ssr/[root-of-the-server]__030vg4n._.js.map +1 -1
  194. package/.next/server/chunks/ssr/[root-of-the-server]__04gz75y._.js +3 -0
  195. package/.next/server/chunks/ssr/[root-of-the-server]__04gz75y._.js.map +1 -0
  196. package/.next/server/chunks/ssr/[root-of-the-server]__05kf31s._.js +3 -0
  197. package/.next/server/chunks/ssr/[root-of-the-server]__05kf31s._.js.map +1 -0
  198. package/.next/server/chunks/ssr/[root-of-the-server]__096ytyk._.js +3 -0
  199. package/.next/server/chunks/ssr/[root-of-the-server]__096ytyk._.js.map +1 -0
  200. package/.next/server/chunks/ssr/[root-of-the-server]__0fhoq8i._.js +1 -1
  201. package/.next/server/chunks/ssr/[root-of-the-server]__0fhoq8i._.js.map +1 -1
  202. package/.next/server/chunks/ssr/[root-of-the-server]__0u4-66w._.js +8 -0
  203. package/.next/server/chunks/ssr/[root-of-the-server]__0u4-66w._.js.map +1 -0
  204. package/.next/server/chunks/ssr/agent-network-dashboard_09kk21a._.js +3 -3
  205. package/.next/server/chunks/ssr/agent-network-dashboard_09kk21a._.js.map +1 -1
  206. package/.next/server/chunks/ssr/agent-network-dashboard_app_01jhlxz._.js +1 -1
  207. package/.next/server/chunks/ssr/agent-network-dashboard_app_01jhlxz._.js.map +1 -1
  208. package/.next/server/chunks/ssr/agent-network-dashboard_app_09d29my._.js +1 -1
  209. package/.next/server/chunks/ssr/agent-network-dashboard_app_09d29my._.js.map +1 -1
  210. package/.next/server/chunks/ssr/agent-network-dashboard_app_0_870i8._.js +3 -0
  211. package/.next/server/chunks/ssr/agent-network-dashboard_app_0_870i8._.js.map +1 -0
  212. package/.next/server/chunks/ssr/agent-network-dashboard_app_0_d45-d._.js +1 -1
  213. package/.next/server/chunks/ssr/agent-network-dashboard_app_0_d45-d._.js.map +1 -1
  214. package/.next/server/chunks/ssr/agent-network-dashboard_app_0fjlnh~._.js +3 -0
  215. package/.next/server/chunks/ssr/agent-network-dashboard_app_0fjlnh~._.js.map +1 -0
  216. package/.next/server/chunks/ssr/agent-network-dashboard_app_0gd.4pc._.js +9 -0
  217. package/.next/server/chunks/ssr/agent-network-dashboard_app_0gd.4pc._.js.map +1 -0
  218. package/.next/server/chunks/ssr/agent-network-dashboard_app_0wn4jc5._.js +3 -0
  219. package/.next/server/chunks/ssr/agent-network-dashboard_app_0wn4jc5._.js.map +1 -0
  220. package/.next/server/chunks/ssr/agent-network-dashboard_app_0xgney8._.js +1 -1
  221. package/.next/server/chunks/ssr/agent-network-dashboard_app_0xgney8._.js.map +1 -1
  222. package/.next/server/chunks/ssr/agent-network-dashboard_app_10hjgv4._.js +1 -1
  223. package/.next/server/chunks/ssr/agent-network-dashboard_app_10hjgv4._.js.map +1 -1
  224. package/.next/server/chunks/ssr/agent-network-dashboard_app_12l4oto._.js +1 -1
  225. package/.next/server/chunks/ssr/agent-network-dashboard_app_12l4oto._.js.map +1 -1
  226. package/.next/server/chunks/ssr/agent-network-dashboard_app_components_0r7kb.o._.js +9 -0
  227. package/.next/server/chunks/ssr/agent-network-dashboard_app_components_0r7kb.o._.js.map +1 -0
  228. package/.next/server/chunks/ssr/agent-network-dashboard_app_servers_page_tsx_0jib5qm._.js +1 -1
  229. package/.next/server/chunks/ssr/agent-network-dashboard_app_servers_page_tsx_0jib5qm._.js.map +1 -1
  230. package/.next/server/chunks/ssr/agent-network-dashboard_app_tasks_page_tsx_0mwxy4z._.js +1 -1
  231. package/.next/server/chunks/ssr/agent-network-dashboard_app_tasks_page_tsx_0mwxy4z._.js.map +1 -1
  232. package/.next/server/middleware-build-manifest.js +3 -3
  233. package/.next/server/next-font-manifest.js +1 -1
  234. package/.next/server/next-font-manifest.json +30 -15
  235. package/.next/server/pages/404.html +4 -4
  236. package/.next/server/pages/500.html +1 -1
  237. package/.next/server/server-reference-manifest.js +1 -1
  238. package/.next/server/server-reference-manifest.json +1 -1
  239. package/.next/static/chunks/0..h8s._z~uek.js +1 -0
  240. package/.next/static/chunks/0.mh8n0itrii5.js +1 -0
  241. package/.next/static/chunks/{0jp~cs9-zkmqa.js → 00b4y77vxfabl.js} +1 -1
  242. package/.next/static/chunks/049vx3qljs1tt.js +1 -0
  243. package/.next/static/chunks/066jf0nk75nic.css +2 -0
  244. package/.next/static/chunks/06vp7429lrzl7.js +1 -0
  245. package/.next/static/chunks/06xxn73qy0qiz.js +7 -0
  246. package/.next/static/chunks/0_bn~gcrgo.4n.js +1 -0
  247. package/.next/static/chunks/0_tvbie.c68h5.js +1 -0
  248. package/.next/static/chunks/0cp0cz3mxejl~.js +4 -0
  249. package/.next/static/chunks/0g4d-_fi-d9hg.js +1 -0
  250. package/.next/static/chunks/0scww97p6z5z..css +1 -0
  251. package/.next/static/chunks/0shtnff1p8hzw.js +1 -0
  252. package/.next/static/chunks/0wz0122ym_gr3.js +1 -0
  253. package/.next/static/chunks/0y5gol09tlu63.js +1 -0
  254. package/.next/static/chunks/13l-ngu707546.js +1 -0
  255. package/.next/static/chunks/14141xj5.1t3t.js +1 -0
  256. package/.next/static/chunks/149a4l50_3vw-.js +7 -0
  257. package/.next/static/chunks/152_p6jt7txp6.js +1 -0
  258. package/.next/static/chunks/15hos-r_t7doi.js +1 -0
  259. package/.next/static/media/4fa387ec64143e14-s.0wkzw~je483f-.woff2 +0 -0
  260. package/.next/static/media/53b9e256198e5412-s.0-wfv7uh4i7h9.woff2 +0 -0
  261. package/.next/static/media/5ce348bf30bf5439-s.0zgw-jeven.3w.woff2 +0 -0
  262. package/.next/static/media/6306c77e7c8268e4-s.0rhz0arwfsn~5.woff2 +0 -0
  263. package/.next/static/media/7178b3e590c64307-s.0nx0ww8fni_q3.woff2 +0 -0
  264. package/.next/static/media/797e433ab948586e-s.p.08e28id.o-okb.woff2 +0 -0
  265. package/.next/static/media/7d817b4c03b0c5f1-s.0l76wvqk9d84w.woff2 +0 -0
  266. package/.next/static/media/8a480f0b521d4e75-s.0jzbimsg8vl84.woff2 +0 -0
  267. package/.next/static/media/bbc41e54d2fcbd21-s.0k4k9394f2q-k.woff2 +0 -0
  268. package/.next/static/media/caa3a2e1cccd8315-s.p.09~u27dqhyhd6.woff2 +0 -0
  269. package/.next/static/media/fef07dbb0973bf53-s.12tyk43_3sh9u.woff2 +0 -0
  270. package/.next/trace +2 -2
  271. package/.next/trace-build +1 -1
  272. package/.next/types/routes.d.ts +1 -2
  273. package/.next/types/validator.ts +0 -9
  274. package/app/admin/page.tsx +53 -38
  275. package/app/components/AgentCard.tsx +36 -20
  276. package/app/components/AppShell.tsx +7 -1
  277. package/app/components/ChatPopover.tsx +1 -1
  278. package/app/components/CollapsibleSearch.tsx +127 -0
  279. package/app/components/CommandCenter.tsx +14 -4
  280. package/app/components/CommandPalette.tsx +6 -6
  281. package/app/components/DispatchPanel.tsx +13 -10
  282. package/app/components/EmptyState.tsx +19 -4
  283. package/app/components/HealthBanner.tsx +28 -4
  284. package/app/components/HelpOverlay.tsx +4 -7
  285. package/app/components/LoadingSkeleton.tsx +31 -21
  286. package/app/components/MobileNav.tsx +28 -21
  287. package/app/components/Sidebar.tsx +30 -23
  288. package/app/components/StatsBar.tsx +69 -42
  289. package/app/components/TaskChatPanel.tsx +19 -5
  290. package/app/components/TaskDrawer.tsx +9 -7
  291. package/app/components/ThemeSwitcher.tsx +15 -79
  292. package/app/components/TopoGraph.tsx +31 -21
  293. package/app/components/UserBar.tsx +5 -5
  294. package/app/globals.css +1757 -1776
  295. package/app/layout.tsx +37 -4
  296. package/app/lib/hooks.ts +0 -5
  297. package/app/lib/status.ts +24 -17
  298. package/app/login/page.tsx +7 -7
  299. package/app/logs/page.tsx +12 -6
  300. package/app/manifest.ts +2 -2
  301. package/app/messages/page.tsx +67 -47
  302. package/app/node/page.tsx +27 -17
  303. package/app/nodes/page.tsx +62 -49
  304. package/app/page.tsx +60 -282
  305. package/app/server-logs/page.tsx +40 -14
  306. package/app/servers/page.tsx +33 -12
  307. package/app/settings/networks/page.tsx +17 -15
  308. package/app/settings/page.tsx +102 -96
  309. package/app/settings/tokens/page.tsx +5 -5
  310. package/app/tasks/[id]/page.tsx +10 -10
  311. package/app/tasks/page.tsx +58 -34
  312. package/bin/start.js +0 -0
  313. package/package.json +1 -1
  314. package/public/favicon.svg +1 -1
  315. package/public/manifest.webmanifest +24 -0
  316. package/public/robots.txt +7 -0
  317. package/.next/server/app/api/hub/license/route/app-paths-manifest.json +0 -3
  318. package/.next/server/app/api/hub/license/route/build-manifest.json +0 -9
  319. package/.next/server/app/api/hub/license/route/server-reference-manifest.json +0 -4
  320. package/.next/server/app/api/hub/license/route.js +0 -7
  321. package/.next/server/app/api/hub/license/route.js.map +0 -5
  322. package/.next/server/app/api/hub/license/route.js.nft.json +0 -1
  323. package/.next/server/app/api/hub/license/route_client-reference-manifest.js +0 -3
  324. package/.next/server/chunks/0ykm__next-internal_server_app_api_hub_license_route_actions_0a4.fuh.js +0 -3
  325. package/.next/server/chunks/0ykm__next-internal_server_app_api_hub_license_route_actions_0a4.fuh.js.map +0 -1
  326. package/.next/server/chunks/[root-of-the-server]__0rovr5-._.js +0 -3
  327. package/.next/server/chunks/[root-of-the-server]__0rovr5-._.js.map +0 -1
  328. package/.next/server/chunks/ssr/[root-of-the-server]__0lu1wok._.js +0 -8
  329. package/.next/server/chunks/ssr/[root-of-the-server]__0lu1wok._.js.map +0 -1
  330. package/.next/server/chunks/ssr/[root-of-the-server]__0nw~zhp._.js +0 -3
  331. package/.next/server/chunks/ssr/[root-of-the-server]__0nw~zhp._.js.map +0 -1
  332. package/.next/server/chunks/ssr/[root-of-the-server]__0sv~g.o._.js +0 -3
  333. package/.next/server/chunks/ssr/[root-of-the-server]__0sv~g.o._.js.map +0 -1
  334. package/.next/server/chunks/ssr/[root-of-the-server]__11fu-5m._.js +0 -3
  335. package/.next/server/chunks/ssr/[root-of-the-server]__11fu-5m._.js.map +0 -1
  336. package/.next/server/chunks/ssr/agent-network-dashboard_app_057q.ne._.js +0 -3
  337. package/.next/server/chunks/ssr/agent-network-dashboard_app_057q.ne._.js.map +0 -1
  338. package/.next/server/chunks/ssr/agent-network-dashboard_app_0i3759l._.js +0 -3
  339. package/.next/server/chunks/ssr/agent-network-dashboard_app_0i3759l._.js.map +0 -1
  340. package/.next/server/chunks/ssr/agent-network-dashboard_app_1153xeb._.js +0 -9
  341. package/.next/server/chunks/ssr/agent-network-dashboard_app_1153xeb._.js.map +0 -1
  342. package/.next/server/chunks/ssr/agent-network-dashboard_app_components_0s5uqlp._.js +0 -9
  343. package/.next/server/chunks/ssr/agent-network-dashboard_app_components_0s5uqlp._.js.map +0 -1
  344. package/.next/server/chunks/ssr/agent-network-dashboard_app_server-logs_page_tsx_0dg.l_8._.js +0 -3
  345. package/.next/server/chunks/ssr/agent-network-dashboard_app_server-logs_page_tsx_0dg.l_8._.js.map +0 -1
  346. package/.next/static/chunks/0-mpa_947ipeq.js +0 -1
  347. package/.next/static/chunks/02to42x11p557.js +0 -7
  348. package/.next/static/chunks/03~5pxwbxxw-b.js +0 -1
  349. package/.next/static/chunks/04~fkia6-79k3.js +0 -1
  350. package/.next/static/chunks/0561vp5-q5.zp.js +0 -1
  351. package/.next/static/chunks/05uk96gc~9mni.js +0 -1
  352. package/.next/static/chunks/085rejlait1fs.js +0 -1
  353. package/.next/static/chunks/0a.9~-nf0gpec.js +0 -1
  354. package/.next/static/chunks/0im751o4n61c7.js +0 -1
  355. package/.next/static/chunks/0inql3s9ldyx5.js +0 -1
  356. package/.next/static/chunks/0ku0fjqlm9mca.js +0 -1
  357. package/.next/static/chunks/0mcamnu4w_x1r.js +0 -4
  358. package/.next/static/chunks/0ss8u23bnbyry.js +0 -1
  359. package/.next/static/chunks/0~rv5y.y5my9s.css +0 -1
  360. package/.next/static/chunks/13yktdzuatx3d.js +0 -1
  361. package/.next/static/chunks/15-ltfhot3b4n.js +0 -7
  362. package/.next/static/chunks/16ls93seuyj8a.js +0 -1
  363. package/.next/static/chunks/17sxlwlx5fhrp.css +0 -1
  364. package/.next/static/chunks/181u38qblp8lz.js +0 -1
  365. package/.next/static/media/4fa387ec64143e14-s.0.qu-9752pffj.woff2 +0 -0
  366. package/.next/static/media/5ce348bf30bf5439-s.0ee55_hj9qcer.woff2 +0 -0
  367. package/.next/static/media/6306c77e7c8268e4-s.0mao5jbfbduzp.woff2 +0 -0
  368. package/.next/static/media/797e433ab948586e-s.p.09zddjkbdep5a.woff2 +0 -0
  369. package/.next/static/media/7d817b4c03b0c5f1-s.0uzt.a6d44yda.woff2 +0 -0
  370. package/.next/static/media/bbc41e54d2fcbd21-s.0mvwgmnhv29no.woff2 +0 -0
  371. package/app/api/hub/license/route.ts +0 -33
  372. package/app/components/BroadcastBar.tsx +0 -84
  373. package/app/components/InboxPanel.tsx +0 -36
  374. /package/.next/static/{vv4Gz5yVhOzydMI2UlT1l → TDZA1Sx9EZPbGBOvEQtJ7}/_buildManifest.js +0 -0
  375. /package/.next/static/{vv4Gz5yVhOzydMI2UlT1l → TDZA1Sx9EZPbGBOvEQtJ7}/_clientMiddlewareManifest.js +0 -0
  376. /package/.next/static/{vv4Gz5yVhOzydMI2UlT1l → TDZA1Sx9EZPbGBOvEQtJ7}/_ssgManifest.js +0 -0
package/app/page.tsx CHANGED
@@ -1,46 +1,33 @@
1
1
  'use client';
2
2
 
3
- import { useEffect, useState } from 'react';
3
+ import { useState } from 'react';
4
4
  import Link from 'next/link';
5
- import { formatUptime, previewContent } from './components/utils';
6
5
  import { StatsBar } from './components/StatsBar';
7
- import { BroadcastBar } from './components/BroadcastBar';
8
6
  import { TopoGraph } from './components/TopoGraph';
9
7
  import { AgentCard } from './components/AgentCard';
10
- import { InboxPanel } from './components/InboxPanel';
11
8
  import { LoadingSkeleton } from './components/LoadingSkeleton';
12
9
  import { NodesEmptyState as EmptyState } from './components/EmptyState';
13
- import { AliasAvatar } from './components/AliasAvatar';
14
- import { STATUS_DOT_HEX, STATUS_CHIP_CLASS } from './lib/status';
15
- import { UserBar } from './components/UserBar';
16
10
  import { CommandCenter, useCommandCenter } from './components/CommandCenter';
17
- import { DispatchPanel } from './components/DispatchPanel';
18
- import { useSessions, useHealth, useAnetConfig, useTasks, useStats } from './lib/hooks';
11
+ import { useSessions, useHealth, useTasks, useStats } from './lib/hooks';
19
12
  import { useSSE } from './lib/useSSE';
20
- import { InboxMessage } from './components/types';
21
13
  import { useSWRConfig } from 'swr';
22
14
 
23
15
  export default function Dashboard() {
24
- // Auto-upgrade: if no V3 auth in session, force re-login to get user token
25
- useEffect(() => {
26
- const hasV3 = sessionStorage.getItem('anet_v3_auth');
27
- if (!hasV3) {
28
- // Try silent re-auth: logout old cookie + redirect to login
29
- fetch('/api/auth/logout', { method: 'POST' }).catch(() => {});
30
- window.location.assign('/login');
31
- }
32
- }, []);
16
+ // #214 F1: the old "V3 auto-upgrade" guard here checked per-tab
17
+ // sessionStorage and, when empty (every new tab / browser restart /
18
+ // bookmark visit), logged out the *valid* cookie session and bounced
19
+ // to /login. Unauthenticated access is already handled server-side
20
+ // by proxy.ts (no cookie /login); the sessionStorage blob is just
21
+ // a client cache that pages re-hydrate on demand. A genuinely stale
22
+ // pre-V3 cookie now surfaces as API 401s with the error banner
23
+ // instead of silent session destruction.
33
24
 
34
25
  const { sessions, hint: sessHint, error: sessError, isLoading } = useSessions();
35
26
  const { health } = useHealth();
36
- const { config: anetConfig } = useAnetConfig();
37
27
  const { tasks } = useTasks({ limit: '500' });
38
28
  const { stats } = useStats();
39
29
  const [showTopo, setShowTopo] = useState(typeof window !== 'undefined' && window.innerWidth >= 1024);
40
- const [showConfig, setShowConfig] = useState(false);
41
30
  const cmd = useCommandCenter();
42
- const [showDispatch, setShowDispatch] = useState(false);
43
- const [inbox, setInbox] = useState<InboxMessage[]>([]);
44
31
  const [agentFilter, setAgentFilter] = useState<'all' | 'working' | 'idle' | 'offline'>('all');
45
32
  // #84: last node.renamed event — passed to TopoGraph so an open chat
46
33
  // popover follows the rename instead of pointing at a dead alias. `ts`
@@ -75,22 +62,6 @@ export default function Dashboard() {
75
62
  },
76
63
  });
77
64
 
78
- // Fetch inbox (not in SWR since it accumulates)
79
- useEffect(() => {
80
- const fetchInbox = () => {
81
- fetch('/api/hub/inbox').then(r => r.json()).then(data => {
82
- if (data.messages?.length) setInbox(prev => {
83
- const ids = new Set(prev.map(m => m.id));
84
- const newMsgs = data.messages.filter((m: { id: string }) => !ids.has(m.id));
85
- return [...newMsgs, ...prev].slice(0, 100);
86
- });
87
- }).catch(() => {});
88
- };
89
- fetchInbox();
90
- const interval = setInterval(fetchInbox, 10000);
91
- return () => clearInterval(interval);
92
- }, []);
93
-
94
65
  if (isLoading) return <LoadingSkeleton />;
95
66
 
96
67
  const sseSessions = health?.sse_sessions || {};
@@ -98,19 +69,15 @@ export default function Dashboard() {
98
69
  // Fall back to alias-only for legacy hubs.
99
70
  const sseLookup = (s: { alias: string; network_id?: string }) =>
100
71
  (s.network_id ? sseSessions[`${s.network_id}:${s.alias}`] : undefined) ?? sseSessions[s.alias];
101
- // Online = status is not 'offline' (not just SSE-connected)
102
- const isOnline = (s: { alias: string; status: string; network_id?: string }) => s.status !== 'offline' || !!sseLookup(s);
72
+ // #214 F2: online = SSE-reachable ("can I talk to it right now").
73
+ // The old definition (status !== 'offline' OR sse) inflated the count
74
+ // with stale hub statuses and disagreed with /admin and /nodes, which
75
+ // both count pure SSE — and a "online" card you can't chat with
76
+ // contradicts the M2 tap-to-chat model. One definition everywhere.
77
+ const isOnline = (s: { alias: string; status: string; network_id?: string }) => !!sseLookup(s);
103
78
  const online = sessions.filter(isOnline).length;
104
79
  const total = sessions.length;
105
80
  const working = sessions.filter(s => s.status === 'working').length;
106
- const uptime = health ? formatUptime(health.uptime) : '--';
107
- const version = health?.version || '--';
108
- const configHealthy = Boolean(anetConfig?.hub && anetConfig.tokenConfigured);
109
- const configSourceLabel =
110
- anetConfig?.source === 'file' ? 'Local config'
111
- : anetConfig?.source === 'runtime-env' ? 'Runtime env'
112
- : 'Config missing';
113
-
114
81
  // Task stats: prefer /api/stats, fallback to manual
115
82
  const taskStats: Record<string, number> = {};
116
83
  if (stats?.tasks?.by_status?.length) {
@@ -132,233 +99,37 @@ export default function Dashboard() {
132
99
  return bWorking - aWorking;
133
100
  });
134
101
 
135
- /** Round 70: when the fleet is empty, the Overview reorders to lead with
136
- * the "Spin up your first agent" CTA and hides the Quick Navigation /
137
- * Nav rail / Broadcast bar that would otherwise occupy prime real estate
138
- * with zeros and dead-end links. Computed once, used as a gate below. */
139
- const fleetEmpty = sessions.length === 0 && !sessError;
140
-
141
102
  return (
142
- <div className="min-h-screen bg-[#0a0a1a] text-gray-100 p-4 sm:p-6 font-mono">
143
- <div className="lg:ml-0 ml-10">
144
- <StatsBar online={online} working={working} total={total} version={version} uptime={uptime} />
145
- </div>
103
+ <div className="min-h-screen bg-[#0b0b0d] text-gray-100 p-4 sm:p-6">
104
+ <StatsBar online={online} working={working} total={total} />
146
105
 
147
- {/* Dispatch + User Bar — Dispatch hidden when fleet empty (nothing to
148
- dispatch to); UserBar still useful (account/sign-out menu). */}
149
- <div className="flex items-center gap-3 mb-4">
150
- {!fleetEmpty && (
151
- <button onClick={() => setShowDispatch(true)}
152
- className="px-4 py-2 bg-gradient-to-r from-cyan-600 to-blue-600 hover:from-cyan-500 hover:to-blue-500 text-white text-sm font-medium rounded-xl shadow-lg shadow-cyan-500/10 transition-all active:scale-95 shrink-0">
153
- ⚡ Dispatch
154
- </button>
155
- )}
156
- <div className="flex-1"><UserBar /></div>
157
- </div>
106
+ {/* #217 S5 (Vincent: "极简极简,这些都可以放到设置里面去"): the
107
+ Dispatch button and UserBar row are gone from Overview.
108
+ Dispatch lives in /admin (Send Task panel); sign-out lives in
109
+ Settings and the sidebar; network switching lives in the
110
+ sidebar. */}
158
111
 
159
- {/* anet config (collapsed by default) */}
160
- <section className="mb-6 rounded-lg border border-[#2a2a4a] bg-[#111128] px-4 py-3 shadow-lg shadow-black/20">
161
- <button onClick={() => setShowConfig(!showConfig)} className="w-full flex items-center justify-between text-left">
162
- <div className="flex items-center gap-2 text-xs">
163
- <span className="uppercase text-gray-600">Config</span>
164
- <span className={`w-2 h-2 rounded-full ${configHealthy ? 'bg-green-400' : 'bg-red-400'}`} />
165
- <span className="text-gray-500">{configSourceLabel}</span>
166
- </div>
167
- <svg className={`w-4 h-4 text-gray-600 transition-transform ${showConfig ? 'rotate-180' : ''}`} fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
168
- <path strokeLinecap="round" strokeLinejoin="round" d="M19 9l-7 7-7-7" />
169
- </svg>
170
- </button>
171
- {showConfig && (
172
- <div className="mt-3 pt-3 border-t border-[#2a2a4a]">
173
- <div className="flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
174
- <div className="min-w-0">
175
- <div className="text-gray-100 truncate text-sm" title={anetConfig?.hub || undefined}>
176
- Hub: <span className={anetConfig?.hub ? 'text-cyan-300' : 'text-red-300'}>{anetConfig?.hub?.trim() || 'not configured'}</span>
177
- </div>
178
- </div>
179
- <div className="flex flex-wrap gap-2 text-xs">
180
- <span className={`px-2.5 py-1 rounded-md border ${anetConfig?.tokenConfigured ? 'bg-blue-500/5 text-blue-300 border-blue-500/20' : 'bg-gray-500/5 text-gray-400 border-gray-500/20'}`}>
181
- Token: {anetConfig?.tokenPreview || 'not configured'}
182
- </span>
183
- </div>
184
- </div>
185
- {anetConfig?.error && <div className="mt-2 text-xs text-gray-600">{anetConfig.error}</div>}
186
- </div>
187
- )}
188
- </section>
189
-
190
- {/* Task Status Stats */}
112
+ {/* Task summary. #217 S5 (Vincent: "乱七八糟的东西太多"): the
113
+ 9-status colored chip wall is now a single quiet line — the
114
+ only two numbers that drive action are running and failed;
115
+ everything else lives on /tasks. */}
191
116
  {Object.keys(taskStats).length > 0 && (
192
- <section className="mb-6 rounded-lg border border-[#2a2a4a] bg-[#111128] px-4 py-3 shadow-lg shadow-black/20">
193
- <div className="flex items-center justify-between mb-2">
194
- <div className="text-xs uppercase text-gray-600">Task Status</div>
195
- <Link href="/tasks" prefetch={false} className="text-xs text-cyan-400 hover:text-cyan-300">View all &rarr;</Link>
196
- </div>
197
- <div className="flex flex-wrap gap-2">
198
- {/* Round 69: order is "hot first" — active flow before terminal
199
- states — intentionally different from the lifecycle order on
200
- /tasks. Colors come from shared STATUS_CHIP_CLASS so a
201
- palette tweak in app/lib/status.ts updates here too.
202
- 'created' added in r69 (was missing — enum-coverage bug). */}
203
- {(['running', 'delivered', 'acked', 'replied', 'created', 'failed', 'cancelled', 'expired', 'closed'] as const)
204
- .filter((key) => taskStats[key])
205
- .map((key) => (
206
- <Link key={key} href={`/tasks?status=${key}`} prefetch={false} className={`px-2.5 py-1 rounded-md border text-xs ${STATUS_CHIP_CLASS[key]} hover:opacity-80 transition-opacity`}>
207
- {key}: {taskStats[key]}
208
- </Link>
209
- ))}
117
+ <section className="mb-4 sm:mb-6 flex items-center justify-between rounded-lg border border-[#26262b] bg-[#161618] px-4 py-2.5 text-xs">
118
+ <div className="text-gray-400 tabular-nums">
119
+ <span className={taskStats['running'] ? 'text-green-400' : 'text-gray-500'}>{taskStats['running'] || 0} running</span>
120
+ <span className="text-gray-600"> &middot; </span>
121
+ <span className={taskStats['failed'] ? 'text-red-400' : 'text-gray-500'}>{taskStats['failed'] || 0} failed</span>
210
122
  </div>
123
+ <Link href="/tasks" prefetch={false} className="text-cyan-400 hover:text-cyan-300">View all &rarr;</Link>
211
124
  </section>
212
125
  )}
213
126
 
214
- {/* Quick Actions split into two distinct intents:
215
- (1) Top: live stat cards (carry data, drill-in on click)
216
- (2) Bottom: pure nav rail (no number, icon + label)
217
- Round 24 wrap both in a labelled block so the rhythm reads as
218
- "here are the main jumps" instead of two disconnected strips.
219
- Round 70 entire Quick Nav + Nav rail + Broadcast + Recent
220
- Activity block is hidden when the fleet is empty so the
221
- onboarding CTA gets the page above the fold. */}
222
- {!fleetEmpty && <>
223
- <div className="text-[10px] uppercase tracking-[0.12em] text-gray-600 mb-2">Quick navigation</div>
224
- <section className="mb-3 grid grid-cols-3 gap-2 sm:gap-3">
225
- {(() => {
226
- // Build breakdown popover content per card. Pure data — pure CSS
227
- // popover (no JS state) wires the hover-show transition below.
228
- const idleCount = sessions.filter(s => isOnline(s) && s.status !== 'working').length;
229
- const offlineCount = total - online;
230
- const orderedStatuses = ['running', 'replied', 'failed', 'cancelled', 'expired', 'closed', 'created', 'delivered', 'acked'];
231
- const failedRecent = tasks.filter((t: { status: string }) => t.status === 'failed').length;
232
-
233
- const cards = [
234
- {
235
- href: '/nodes', label: 'Nodes',
236
- value: `${online}/${total}`,
237
- sub: `${total > 0 ? Math.round((online / total) * 100) : 0}% online`,
238
- color: 'text-green-400 border-green-500/20',
239
- popover: total === 0 ? null : [
240
- { k: 'working', v: working, dot: '', color: '#4ade80' },
241
- { k: 'idle', v: idleCount, dot: '', color: '#22d3ee' },
242
- { k: 'offline', v: offlineCount, dot: '', color: '#9ca3af' },
243
- ],
244
- },
245
- {
246
- href: '/tasks', label: 'Tasks',
247
- value: String(Object.values(taskStats).reduce((a, b) => a + b, 0) || 0),
248
- sub: 'all-time',
249
- color: 'text-cyan-400 border-cyan-500/20',
250
- popover: Object.keys(taskStats).length === 0 ? null
251
- : orderedStatuses
252
- .filter(s => taskStats[s])
253
- .map(s => {
254
- // Inline hex avoids Tailwind purging dynamic
255
- // `bg-${color}-400` class names.
256
- const hex = ({
257
- running: '#4ade80', replied: '#a78bfa', failed: '#f87171',
258
- cancelled: '#facc15', expired: '#fb923c', closed: '#9ca3af',
259
- created: '#9ca3af', delivered: '#60a5fa', acked: '#22d3ee',
260
- } as Record<string, string>)[s] || '#9ca3af';
261
- return { k: s, v: taskStats[s], dot: '', color: hex };
262
- }),
263
- },
264
- {
265
- href: '/tasks?status=failed', label: 'Failed',
266
- value: String(taskStats['failed'] || 0),
267
- sub: taskStats['failed'] ? 'needs review' : 'none',
268
- color: taskStats['failed'] ? 'text-red-400 border-red-500/25' : 'text-gray-500 border-gray-700/30',
269
- popover: !failedRecent ? [{ k: 'no failures yet', v: '', dot: '', color: '#4b5563' }]
270
- : [{ k: `${failedRecent} in current view`, v: '', dot: '', color: '#f87171' }],
271
- },
272
- ];
273
-
274
- return cards.map(a => (
275
- <Link
276
- key={a.href}
277
- href={a.href}
278
- prefetch={false}
279
- className={`anet-stat-link group relative rounded-xl border ${a.color} bg-[#111128] px-3 py-3 transition-all hover:-translate-y-px`}
280
- >
281
- <div className="flex items-baseline justify-between">
282
- <div className={`text-xl font-semibold tabular-nums ${a.color.split(' ')[0]}`}>{a.value}</div>
283
- <div className="hidden sm:block text-[10px] text-gray-600 group-hover:text-gray-400 transition-colors">View →</div>
284
- </div>
285
- <div className="text-[11px] text-gray-400 mt-0.5">{a.label}</div>
286
- <div className="text-[10px] text-gray-600 mt-px">{a.sub}</div>
287
-
288
- {/* Hover popover — CSS-only, restrained. Hidden on touch
289
- (no :hover) so mobile is unaffected. Positioned just
290
- below the card so it doesn't fight nav rail. */}
291
- {a.popover && a.popover.length > 0 && (
292
- <div className="anet-stat-popover hidden md:block pointer-events-none absolute left-2 right-2 top-full mt-1 z-20 rounded-lg border border-[#2a2a4a] bg-[#0d0d1a] shadow-lg shadow-black/30 px-3 py-2 opacity-0 translate-y-[-2px] group-hover:opacity-100 group-hover:translate-y-0 transition-all duration-150 delay-100">
293
- <div className="text-[10px] text-gray-600 uppercase tracking-wider mb-1.5">Breakdown</div>
294
- <ul className="space-y-1">
295
- {a.popover.map(row => (
296
- <li key={row.k} className="flex items-center gap-2 text-[11px]">
297
- <span
298
- className="inline-block w-1.5 h-1.5 rounded-full shrink-0"
299
- style={{ backgroundColor: row.color }}
300
- aria-hidden
301
- />
302
- <span className="text-gray-400 capitalize">{row.k}</span>
303
- {row.v !== '' && <span className="ml-auto text-gray-300 tabular-nums font-medium">{row.v}</span>}
304
- </li>
305
- ))}
306
- </ul>
307
- </div>
308
- )}
309
- </Link>
310
- ));
311
- })()}
312
- </section>
313
-
314
- {/* Nav rail — pure navigation, icon + label, no data */}
315
- <section className="mb-6 grid grid-cols-3 gap-2 sm:gap-3">
316
- {[
317
- { href: '/messages', label: 'Messages', icon: 'M21 11.5a8.38 8.38 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.38 8.38 0 0 1-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.38 8.38 0 0 1 3.8-.9h.5a8.48 8.48 0 0 1 8 8v.5z' },
318
- { href: '/logs', label: 'Audit log', icon: 'M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z M14 2v6h6 M16 13H8 M16 17H8 M10 9H8' },
319
- { href: '/admin', label: 'Admin', icon: 'M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4z M6 21v-2a4 4 0 0 1 4-4h4a4 4 0 0 1 4 4v2' },
320
- ].map(a => (
321
- <Link key={a.href} href={a.href} prefetch={false}
322
- className="anet-nav-tile flex items-center justify-center gap-2 rounded-xl border border-[#2a2a4a] bg-[#111128] px-3 py-2.5 text-[12px] text-gray-400 hover:text-gray-200 transition-colors">
323
- <svg className="w-4 h-4 shrink-0" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round">
324
- <path d={a.icon} />
325
- </svg>
326
- <span>{a.label}</span>
327
- </Link>
328
- ))}
329
- </section>
330
-
331
- <BroadcastBar />
332
-
333
- {/* Recent Activity */}
334
- {tasks.length > 0 && (
335
- <section className="mb-6 bg-[#111128] border border-[#2a2a4a] rounded-xl p-4">
336
- <div className="flex items-center justify-between mb-3">
337
- <h2 className="text-sm font-semibold text-gray-300">Recent Activity</h2>
338
- <Link href="/tasks" className="text-xs text-cyan-400 hover:text-cyan-300">All tasks &rarr;</Link>
339
- </div>
340
- <div className="space-y-2 max-h-40 overflow-y-auto">
341
- {tasks.slice(0, 5).map((t: { task_id: string; from_name: string; to_name: string; status: string; content: string; created_at: string }) => (
342
- <div key={t.task_id} className="flex items-center gap-2 text-xs">
343
- <span
344
- className="w-1.5 h-1.5 rounded-full shrink-0"
345
- style={{ backgroundColor: STATUS_DOT_HEX[t.status] || '#6b7280' }}
346
- />
347
- {t.from_name && <AliasAvatar alias={t.from_name} size={14} />}
348
- <span className="text-gray-300 shrink-0 max-w-[20%] truncate">{t.from_name || '?'}</span>
349
- <span className="text-gray-600">&rarr;</span>
350
- {t.to_name && <AliasAvatar alias={t.to_name} size={14} />}
351
- <span className="text-gray-300 shrink-0 max-w-[20%] truncate">{t.to_name || '?'}</span>
352
- <span className="text-gray-500 truncate flex-1" title={t.content || ''}>{previewContent(t.content).slice(0, 60)}</span>
353
- <span className={`shrink-0 px-1.5 py-0.5 rounded text-[10px] border ${
354
- STATUS_CHIP_CLASS[t.status] || 'text-gray-500 border-gray-700/30'
355
- }`}>{t.status}</span>
356
- </div>
357
- ))}
358
- </div>
359
- </section>
360
- )}
361
- </>}
127
+ {/* #217 S5 (less is more): Quick Navigation stat cards, the nav
128
+ rail, and Recent Activity are deleted. Every route they linked
129
+ to is one tap away in the bottom tab bar (mobile) or sidebar
130
+ (desktop), the headline numbers already live in the KPI cards
131
+ and the task summary line, and recent tasks live on /tasks.
132
+ Restore path: git revert this commit. */}
362
133
 
363
134
  {sessError && (
364
135
  <div className="bg-red-900/20 border border-red-800/40 text-red-300 px-4 py-3 rounded-lg mb-6 text-sm flex items-center justify-between" role="alert">
@@ -367,8 +138,12 @@ export default function Dashboard() {
367
138
  </div>
368
139
  )}
369
140
 
141
+ {/* #217 M1: topology toggle is lg-only — on a 390px phone the
142
+ graph needed a 70vh cap (R41) just to stay scrollable, i.e.
143
+ it never really worked there. Desktop keeps the full feature;
144
+ mobile Overview loses its last piece of chrome. */}
370
145
  {sessions.length > 0 && (
371
- <div className="flex justify-center mb-4">
146
+ <div className="hidden lg:flex justify-center mb-4">
372
147
  <button
373
148
  onClick={() => setShowTopo(!showTopo)}
374
149
  className="text-xs text-gray-500 hover:text-gray-300 border border-gray-700/50 px-4 py-1.5 rounded-lg transition-colors hover:border-gray-600 cursor-pointer"
@@ -378,15 +153,21 @@ export default function Dashboard() {
378
153
  </div>
379
154
  )}
380
155
 
381
- {/* Mobile hint when topo hidden */}
382
- {!showTopo && sessions.length > 0 && (
383
- <div className="lg:hidden text-center text-xs text-gray-600 mb-4">
384
- Topology hidden on mobile for better readability
156
+ {showTopo && sessions.length > 0 && (
157
+ // #209 R41: mobile-only soft cap on the rendered TopoGraph.
158
+ // Default behaviour on desktop is unchanged (lg: drops the cap
159
+ // entirely). On phones the SVG card was free to claim ~600+ px
160
+ // of vertical real-estate, which on a 667-844 px viewport meant
161
+ // tapping "Show Topology" pushed the agent grid completely off
162
+ // screen. Capping to 70 vh with overflow-y-auto keeps the graph
163
+ // interactive (the SVG already does its own pan + zoom inside
164
+ // the viewport) while letting the page below stay reachable
165
+ // with a single ordinary scroll past the cap.
166
+ <div className="lg:max-h-none lg:overflow-visible max-h-[70vh] overflow-y-auto rounded-xl border border-transparent lg:border-0">
167
+ <TopoGraph sessions={sessions} sseSessions={sseSessions} renameSignal={renameSignal} />
385
168
  </div>
386
169
  )}
387
170
 
388
- {showTopo && sessions.length > 0 && <TopoGraph sessions={sessions} sseSessions={sseSessions} renameSignal={renameSignal} />}
389
-
390
171
  {sessions.length === 0 && !sessError ? (
391
172
  <EmptyState
392
173
  hint={sessHint}
@@ -426,12 +207,14 @@ export default function Dashboard() {
426
207
  className={`flex items-center gap-1.5 rounded-md px-2.5 py-1 text-xs transition-colors disabled:opacity-30 disabled:cursor-not-allowed ${
427
208
  agentFilter === c.key
428
209
  ? 'bg-cyan-500/10 text-cyan-300 border border-cyan-500/30'
429
- : 'text-gray-500 hover:text-gray-200 hover:bg-[#1a1a2a] border border-transparent'
210
+ : 'text-gray-500 hover:text-gray-200 hover:bg-[#1c1c1f] border border-transparent'
430
211
  }`}
431
212
  >
432
213
  {c.dot && <span aria-hidden className="inline-block w-1.5 h-1.5 rounded-full" style={{ backgroundColor: c.dot }} />}
214
+ {/* #217 D5: counts dropped — the KPI cards directly above
215
+ already carry 53/100/153; repeating them here doubled
216
+ every number on the first screen. */}
433
217
  <span>{c.label}</span>
434
- <span className={`text-[10px] tabular-nums ${agentFilter === c.key ? 'text-cyan-400' : 'text-gray-600'}`}>{counts[c.key]}</span>
435
218
  </button>
436
219
  ))}
437
220
  </div>
@@ -454,8 +237,6 @@ export default function Dashboard() {
454
237
  );
455
238
  })()}
456
239
 
457
- <InboxPanel messages={inbox} />
458
-
459
240
  {/* Round 111 (issue #82): dropped the license badge — "trial (12d
460
241
  left)" read like a paywall countdown on an open-source dashboard
461
242
  and Vincent flagged it as misleading more than once. The SSE /
@@ -470,9 +251,6 @@ export default function Dashboard() {
470
251
  )}
471
252
  </div>
472
253
 
473
- {/* Dispatch Panel */}
474
- {showDispatch && <DispatchPanel sessions={sessions} onClose={() => setShowDispatch(false)} />}
475
-
476
254
  {/* Command Center (multi-tab chat) */}
477
255
  {cmd.tabs.length > 0 && (
478
256
  <CommandCenter
@@ -1,6 +1,7 @@
1
1
  'use client';
2
2
 
3
3
  import { useState, useEffect, useRef, useCallback } from 'react';
4
+ import { useCollapsibleSearch } from '@/app/components/CollapsibleSearch';
4
5
  import Link from 'next/link';
5
6
 
6
7
  interface LogLine {
@@ -63,6 +64,16 @@ export default function ServerLogsPage() {
63
64
  const [filterLevel, setFilterLevel] = useState<'all' | LogLine['level']>('all');
64
65
  const [search, setSearch] = useState('');
65
66
  const [autoRefresh, setAutoRefresh] = useState(true);
67
+ // #209 R35: adopt the shared CollapsibleSearch hook (R34) so the
68
+ // inline 全宽 search input collapses behind a magnifier circle in
69
+ // the toolbar — same WeChat-style affordance as /nodes /messages.
70
+ const searchCtl = useCollapsibleSearch({
71
+ value: search,
72
+ onChange: setSearch,
73
+ placeholder: '搜索关键字 (alias / task_id / error message)',
74
+ label: 'Search logs',
75
+ enabled: true,
76
+ });
66
77
  const lastTsRef = useRef<string>('');
67
78
 
68
79
  const fetchLogs = useCallback(async (initial = false) => {
@@ -116,10 +127,17 @@ export default function ServerLogsPage() {
116
127
  for (const l of logs) counts[l.level]++;
117
128
 
118
129
  return (
119
- <div className="p-6 max-w-[1600px] mx-auto">
130
+ // #209 R35: p-6 → p-4 sm:p-6 mobile-tighten (matches /tasks, /nodes,
131
+ // /messages, /overview convention). Saves 16 px of L/R padding on phones.
132
+ <div className="p-4 sm:p-6 max-w-[1600px] mx-auto">
120
133
  <div className="flex items-center justify-between mb-4 gap-3">
121
134
  <div className="flex items-center gap-3 min-w-0">
122
- <h1 className="text-2xl font-bold text-white">Server Logs</h1>
135
+ {/* #209 R35: lg:ml-0 ml-10 burger-clearance — without it the
136
+ fixed top-3 left-3 mobile hamburger sat right on top of the
137
+ "Se" of "Server Logs". Caught by playwright mobile shot. */}
138
+ {/* #217 D8: text-xl + nowrap on phones — at text-2xl the title
139
+ wrapped to two lines under the 4-control toolbar. */}
140
+ <h1 className="text-xl sm:text-2xl font-bold text-white lg:ml-0 ml-10 whitespace-nowrap">Server Logs</h1>
123
141
  {/* Round 86: dropped the {logs.length} header chip — r84 added
124
142
  `all <count>` to the filter strip just below, so this duplicated
125
143
  the value within 40px of itself. */}
@@ -158,9 +176,17 @@ export default function ServerLogsPage() {
158
176
  </svg>
159
177
  <span className="hidden sm:inline">Reload</span>
160
178
  </button>
179
+ {/* #209 R35: magnifier-toggle search (WeChat-style, via the
180
+ shared CollapsibleSearch hook). Lives at the tail of the
181
+ toolbar so it sits at the right edge of the header. */}
182
+ <searchCtl.Button />
161
183
  </div>
162
184
  </div>
163
185
 
186
+ {/* R35: collapsible search row — sits above the filter chip strip
187
+ so toggling it doesn't shift the chip layout. */}
188
+ <searchCtl.Row />
189
+
164
190
  {/* Round 95: flex-wrap + min-w-0 on the search wrapper so the
165
191
  search input drops below the chip strip on mobile instead of
166
192
  overflowing past the viewport. Desktop layout (single row)
@@ -183,7 +209,7 @@ export default function ServerLogsPage() {
183
209
  className={`px-2.5 py-1 rounded border flex items-center gap-1 disabled:opacity-30 disabled:cursor-not-allowed ${
184
210
  isActive
185
211
  ? 'bg-cyan-500/15 text-cyan-200 border-cyan-500/40'
186
- : 'bg-[#11111c] text-gray-400 border-[#2a2a4a] hover:bg-[#1a1a2a]'
212
+ : 'bg-[#161618] text-gray-400 border-[#26262b] hover:bg-[#1c1c1f]'
187
213
  }`}
188
214
  >
189
215
  <span>{lv}</span>
@@ -192,15 +218,15 @@ export default function ServerLogsPage() {
192
218
  );
193
219
  })}
194
220
  </div>
195
- <input
196
- value={search}
197
- onChange={e => setSearch(e.target.value)}
198
- placeholder="搜索关键字 (alias / task_id / error message)"
199
- className="flex-1 min-w-[140px] basis-full sm:basis-0 px-3 py-1.5 text-xs bg-[#11111c] border border-[#2a2a4a] rounded text-gray-200 focus:outline-none focus:border-cyan-500/40"
200
- />
201
- <span className="text-[10px] text-gray-600">
202
- {filtered.length} / {logs.length}
203
- </span>
221
+ {/* #217 D8 (same rule as the D6 /tasks chip): the counter only
222
+ renders when it carries unique info — a filter or search is
223
+ actually narrowing the list. "500 / 500" duplicated the
224
+ `all 500` chip 20px to its left. */}
225
+ {filtered.length < logs.length && (
226
+ <span className="text-[10px] text-gray-600 ml-auto tabular-nums">
227
+ {filtered.length} / {logs.length}
228
+ </span>
229
+ )}
204
230
  </div>
205
231
 
206
232
  {error && (() => {
@@ -235,7 +261,7 @@ export default function ServerLogsPage() {
235
261
  );
236
262
  })()}
237
263
 
238
- <div className="rounded border border-[#1a1a2a] bg-[#050510] font-mono text-[11px] leading-relaxed overflow-hidden">
264
+ <div className="rounded border border-[#1c1c1f] bg-[#060607] font-mono text-[11px] leading-relaxed overflow-hidden">
239
265
  {filtered.length === 0 ? (
240
266
  <div className="p-8 text-center text-gray-600">
241
267
  {error ? '加载失败' : logs.length === 0 ? '加载中...' : '没有匹配的日志'}
@@ -243,7 +269,7 @@ export default function ServerLogsPage() {
243
269
  ) : (
244
270
  <div className="divide-y divide-[#0d0d18] max-h-[calc(100vh-260px)] overflow-y-auto">
245
271
  {filtered.map((l, i) => (
246
- <div key={`${l.ts}-${i}`} className="relative pl-3 pr-3 py-1 hover:bg-[#0a0a14] flex gap-3">
272
+ <div key={`${l.ts}-${i}`} className="relative pl-3 pr-3 py-1 hover:bg-[#0e0e10] flex gap-3">
247
273
  {/* Round 32: 2px left rail keyed to level. Makes warn/error
248
274
  spike visible in a wall of `log` lines without users having
249
275
  to read the level chip on every row. */}
@@ -4,24 +4,45 @@ import { ServersPanel } from '../components/ServersDrawer';
4
4
 
5
5
  export default function ServersPage() {
6
6
  return (
7
- <main className="min-h-screen bg-[#0a0a1a] px-4 py-5 text-gray-100 sm:px-6 lg:px-8">
7
+ <main className="min-h-screen bg-[#0b0b0d] px-4 py-5 text-gray-100 sm:px-6 lg:px-8">
8
8
  <div className="mx-auto max-w-5xl space-y-5">
9
- <header className="rounded-2xl border border-[#2a2a4a] bg-[#111128] p-5 shadow-lg shadow-black/20">
10
- <div className="flex flex-col gap-3 sm:flex-row sm:items-end sm:justify-between">
11
- <div>
12
- <p className="text-[11px] uppercase tracking-[0.18em] text-cyan-300/70">Infrastructure</p>
13
- <h1 className="mt-2 text-2xl font-semibold text-white">Servers</h1>
14
- <p className="mt-2 max-w-2xl text-sm leading-6 text-gray-400">
15
- Host-level health, disk, memory, CPU history, and agent rollups from CommHub telemetry.
16
- </p>
9
+ {/* #209 R37: header card compressed for mobile. Original layout
10
+ stacked 4 things vertically on phones (INFRASTRUCTURE eyebrow,
11
+ big h1, 3-line description, full-width "live" chip) eating
12
+ ~50% of the iPhone viewport before any server card appeared.
13
+ New shape:
14
+ row 1: h1 "Servers" + tiny live chip (inline on every width)
15
+ row 2: optional desc line, single-truncate on mobile so it
16
+ fits without wrapping; full text via title= on hover.
17
+ eyebrow: kept but inlined with h1 as small uppercase prefix
18
+ (sm: up) — drops out on phones for density.
19
+ p-5 → p-4 sm:p-5 also tightens the inner padding.
20
+ Zero feature removed; the eyebrow + desc still render where
21
+ there is room. */}
22
+ <header className="rounded-2xl border border-[#26262b] bg-[#161618] p-4 sm:p-5 shadow-lg shadow-black/20">
23
+ <div className="flex items-center justify-between gap-3 lg:ml-0 ml-10">
24
+ <div className="flex items-baseline gap-2 min-w-0">
25
+ <span className="hidden sm:inline text-[11px] uppercase tracking-[0.18em] text-cyan-300/70 shrink-0">
26
+ Infrastructure
27
+ </span>
28
+ <span className="hidden sm:inline text-gray-700">·</span>
29
+ <h1 className="text-xl sm:text-2xl font-semibold text-white truncate">Servers</h1>
17
30
  </div>
18
- <div className="rounded-xl border border-cyan-500/20 bg-cyan-500/10 px-3 py-2 text-xs font-mono text-cyan-200">
19
- live · refreshes every 5s
31
+ <div className="shrink-0 rounded-full border border-cyan-500/20 bg-cyan-500/10 px-2.5 py-1 text-[11px] font-mono text-cyan-200 inline-flex items-center gap-1.5">
32
+ <span aria-hidden className="inline-block w-1.5 h-1.5 rounded-full bg-cyan-400 animate-pulse" />
33
+ <span className="hidden sm:inline">live · refreshes every 5s</span>
34
+ <span className="sm:hidden">live</span>
20
35
  </div>
21
36
  </div>
37
+ <p
38
+ className="mt-2 max-w-2xl text-xs sm:text-sm leading-snug sm:leading-6 text-gray-400 truncate sm:whitespace-normal lg:ml-0 ml-10"
39
+ title="Host-level health, disk, memory, CPU history, and agent rollups from CommHub telemetry."
40
+ >
41
+ Host-level health, disk, memory, CPU history, and agent rollups from CommHub telemetry.
42
+ </p>
22
43
  </header>
23
44
 
24
- <section className="rounded-2xl border border-[#2a2a4a] bg-[#111128] p-3 shadow-lg shadow-black/20">
45
+ <section className="rounded-2xl border border-[#26262b] bg-[#161618] p-3 shadow-lg shadow-black/20">
25
46
  <ServersPanel className="max-h-none overflow-visible" />
26
47
  </section>
27
48
  </div>