@sleep2agi/agent-network-dashboard 0.4.5-preview.0 → 0.4.5-preview.10

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 (237) hide show
  1. package/.next/BUILD_ID +1 -1
  2. package/.next/build-manifest.json +3 -3
  3. package/.next/diagnostics/route-bundle-stats.json +37 -37
  4. package/.next/fallback-build-manifest.json +3 -3
  5. package/.next/prerender-manifest.json +3 -3
  6. package/.next/server/app/_global-error.html +1 -1
  7. package/.next/server/app/_global-error.rsc +1 -1
  8. package/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  9. package/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  10. package/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  11. package/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  12. package/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  13. package/.next/server/app/_not-found/page.js.nft.json +1 -1
  14. package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  15. package/.next/server/app/_not-found.html +2 -2
  16. package/.next/server/app/_not-found.rsc +12 -12
  17. package/.next/server/app/_not-found.segments/_full.segment.rsc +12 -12
  18. package/.next/server/app/_not-found.segments/_head.segment.rsc +4 -4
  19. package/.next/server/app/_not-found.segments/_index.segment.rsc +7 -7
  20. package/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +2 -2
  21. package/.next/server/app/_not-found.segments/_not-found.segment.rsc +3 -3
  22. package/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  23. package/.next/server/app/admin/page.js.nft.json +1 -1
  24. package/.next/server/app/admin/page_client-reference-manifest.js +1 -1
  25. package/.next/server/app/admin.html +2 -2
  26. package/.next/server/app/admin.rsc +14 -14
  27. package/.next/server/app/admin.segments/_full.segment.rsc +14 -14
  28. package/.next/server/app/admin.segments/_head.segment.rsc +4 -4
  29. package/.next/server/app/admin.segments/_index.segment.rsc +7 -7
  30. package/.next/server/app/admin.segments/_tree.segment.rsc +2 -2
  31. package/.next/server/app/admin.segments/admin/__PAGE__.segment.rsc +4 -4
  32. package/.next/server/app/admin.segments/admin.segment.rsc +3 -3
  33. package/.next/server/app/index.html +2 -2
  34. package/.next/server/app/index.rsc +14 -14
  35. package/.next/server/app/index.segments/__PAGE__.segment.rsc +4 -4
  36. package/.next/server/app/index.segments/_full.segment.rsc +14 -14
  37. package/.next/server/app/index.segments/_head.segment.rsc +4 -4
  38. package/.next/server/app/index.segments/_index.segment.rsc +7 -7
  39. package/.next/server/app/index.segments/_tree.segment.rsc +2 -2
  40. package/.next/server/app/login/page.js.nft.json +1 -1
  41. package/.next/server/app/login/page_client-reference-manifest.js +1 -1
  42. package/.next/server/app/login.html +2 -2
  43. package/.next/server/app/login.rsc +14 -14
  44. package/.next/server/app/login.segments/_full.segment.rsc +14 -14
  45. package/.next/server/app/login.segments/_head.segment.rsc +4 -4
  46. package/.next/server/app/login.segments/_index.segment.rsc +7 -7
  47. package/.next/server/app/login.segments/_tree.segment.rsc +2 -2
  48. package/.next/server/app/login.segments/login/__PAGE__.segment.rsc +4 -4
  49. package/.next/server/app/login.segments/login.segment.rsc +3 -3
  50. package/.next/server/app/logs/page.js.nft.json +1 -1
  51. package/.next/server/app/logs/page_client-reference-manifest.js +1 -1
  52. package/.next/server/app/logs.html +2 -2
  53. package/.next/server/app/logs.rsc +14 -14
  54. package/.next/server/app/logs.segments/_full.segment.rsc +14 -14
  55. package/.next/server/app/logs.segments/_head.segment.rsc +4 -4
  56. package/.next/server/app/logs.segments/_index.segment.rsc +7 -7
  57. package/.next/server/app/logs.segments/_tree.segment.rsc +2 -2
  58. package/.next/server/app/logs.segments/logs/__PAGE__.segment.rsc +4 -4
  59. package/.next/server/app/logs.segments/logs.segment.rsc +3 -3
  60. package/.next/server/app/messages/page.js.nft.json +1 -1
  61. package/.next/server/app/messages/page_client-reference-manifest.js +1 -1
  62. package/.next/server/app/messages.html +2 -2
  63. package/.next/server/app/messages.rsc +14 -14
  64. package/.next/server/app/messages.segments/_full.segment.rsc +14 -14
  65. package/.next/server/app/messages.segments/_head.segment.rsc +4 -4
  66. package/.next/server/app/messages.segments/_index.segment.rsc +7 -7
  67. package/.next/server/app/messages.segments/_tree.segment.rsc +2 -2
  68. package/.next/server/app/messages.segments/messages/__PAGE__.segment.rsc +4 -4
  69. package/.next/server/app/messages.segments/messages.segment.rsc +3 -3
  70. package/.next/server/app/node/page.js.nft.json +1 -1
  71. package/.next/server/app/node/page_client-reference-manifest.js +1 -1
  72. package/.next/server/app/node.html +2 -2
  73. package/.next/server/app/node.rsc +14 -14
  74. package/.next/server/app/node.segments/_full.segment.rsc +14 -14
  75. package/.next/server/app/node.segments/_head.segment.rsc +4 -4
  76. package/.next/server/app/node.segments/_index.segment.rsc +7 -7
  77. package/.next/server/app/node.segments/_tree.segment.rsc +2 -2
  78. package/.next/server/app/node.segments/node/__PAGE__.segment.rsc +4 -4
  79. package/.next/server/app/node.segments/node.segment.rsc +3 -3
  80. package/.next/server/app/nodes/page.js.nft.json +1 -1
  81. package/.next/server/app/nodes/page_client-reference-manifest.js +1 -1
  82. package/.next/server/app/nodes.html +2 -2
  83. package/.next/server/app/nodes.rsc +14 -14
  84. package/.next/server/app/nodes.segments/_full.segment.rsc +14 -14
  85. package/.next/server/app/nodes.segments/_head.segment.rsc +4 -4
  86. package/.next/server/app/nodes.segments/_index.segment.rsc +7 -7
  87. package/.next/server/app/nodes.segments/_tree.segment.rsc +2 -2
  88. package/.next/server/app/nodes.segments/nodes/__PAGE__.segment.rsc +4 -4
  89. package/.next/server/app/nodes.segments/nodes.segment.rsc +3 -3
  90. package/.next/server/app/page.js.nft.json +1 -1
  91. package/.next/server/app/page_client-reference-manifest.js +1 -1
  92. package/.next/server/app/server-logs/page.js.nft.json +1 -1
  93. package/.next/server/app/server-logs/page_client-reference-manifest.js +1 -1
  94. package/.next/server/app/server-logs.html +2 -2
  95. package/.next/server/app/server-logs.rsc +14 -14
  96. package/.next/server/app/server-logs.segments/_full.segment.rsc +14 -14
  97. package/.next/server/app/server-logs.segments/_head.segment.rsc +4 -4
  98. package/.next/server/app/server-logs.segments/_index.segment.rsc +7 -7
  99. package/.next/server/app/server-logs.segments/_tree.segment.rsc +2 -2
  100. package/.next/server/app/server-logs.segments/server-logs/__PAGE__.segment.rsc +4 -4
  101. package/.next/server/app/server-logs.segments/server-logs.segment.rsc +3 -3
  102. package/.next/server/app/settings/networks/page.js.nft.json +1 -1
  103. package/.next/server/app/settings/networks/page_client-reference-manifest.js +1 -1
  104. package/.next/server/app/settings/networks.html +2 -2
  105. package/.next/server/app/settings/networks.rsc +14 -14
  106. package/.next/server/app/settings/networks.segments/_full.segment.rsc +14 -14
  107. package/.next/server/app/settings/networks.segments/_head.segment.rsc +4 -4
  108. package/.next/server/app/settings/networks.segments/_index.segment.rsc +7 -7
  109. package/.next/server/app/settings/networks.segments/_tree.segment.rsc +2 -2
  110. package/.next/server/app/settings/networks.segments/settings/networks/__PAGE__.segment.rsc +4 -4
  111. package/.next/server/app/settings/networks.segments/settings/networks.segment.rsc +3 -3
  112. package/.next/server/app/settings/networks.segments/settings.segment.rsc +3 -3
  113. package/.next/server/app/settings/page.js.nft.json +1 -1
  114. package/.next/server/app/settings/page_client-reference-manifest.js +1 -1
  115. package/.next/server/app/settings/tokens/page.js.nft.json +1 -1
  116. package/.next/server/app/settings/tokens/page_client-reference-manifest.js +1 -1
  117. package/.next/server/app/settings/tokens.html +2 -2
  118. package/.next/server/app/settings/tokens.rsc +14 -14
  119. package/.next/server/app/settings/tokens.segments/_full.segment.rsc +14 -14
  120. package/.next/server/app/settings/tokens.segments/_head.segment.rsc +4 -4
  121. package/.next/server/app/settings/tokens.segments/_index.segment.rsc +7 -7
  122. package/.next/server/app/settings/tokens.segments/_tree.segment.rsc +2 -2
  123. package/.next/server/app/settings/tokens.segments/settings/tokens/__PAGE__.segment.rsc +4 -4
  124. package/.next/server/app/settings/tokens.segments/settings/tokens.segment.rsc +3 -3
  125. package/.next/server/app/settings/tokens.segments/settings.segment.rsc +3 -3
  126. package/.next/server/app/settings.html +2 -2
  127. package/.next/server/app/settings.rsc +14 -14
  128. package/.next/server/app/settings.segments/_full.segment.rsc +14 -14
  129. package/.next/server/app/settings.segments/_head.segment.rsc +4 -4
  130. package/.next/server/app/settings.segments/_index.segment.rsc +7 -7
  131. package/.next/server/app/settings.segments/_tree.segment.rsc +2 -2
  132. package/.next/server/app/settings.segments/settings/__PAGE__.segment.rsc +4 -4
  133. package/.next/server/app/settings.segments/settings.segment.rsc +3 -3
  134. package/.next/server/app/tasks/[id]/page.js.nft.json +1 -1
  135. package/.next/server/app/tasks/[id]/page_client-reference-manifest.js +1 -1
  136. package/.next/server/app/tasks/page.js.nft.json +1 -1
  137. package/.next/server/app/tasks/page_client-reference-manifest.js +1 -1
  138. package/.next/server/app/tasks.html +2 -2
  139. package/.next/server/app/tasks.rsc +14 -14
  140. package/.next/server/app/tasks.segments/_full.segment.rsc +14 -14
  141. package/.next/server/app/tasks.segments/_head.segment.rsc +4 -4
  142. package/.next/server/app/tasks.segments/_index.segment.rsc +7 -7
  143. package/.next/server/app/tasks.segments/_tree.segment.rsc +2 -2
  144. package/.next/server/app/tasks.segments/tasks/__PAGE__.segment.rsc +4 -4
  145. package/.next/server/app/tasks.segments/tasks.segment.rsc +3 -3
  146. package/.next/server/chunks/ssr/[root-of-the-server]__0a0ffmv._.js +3 -0
  147. package/.next/server/chunks/ssr/[root-of-the-server]__0a0ffmv._.js.map +1 -0
  148. package/.next/server/chunks/ssr/[root-of-the-server]__0epcm6p._.js +3 -0
  149. package/.next/server/chunks/ssr/[root-of-the-server]__0epcm6p._.js.map +1 -0
  150. package/.next/server/chunks/ssr/[root-of-the-server]__0to~xqw._.js +3 -0
  151. package/.next/server/chunks/ssr/[root-of-the-server]__0to~xqw._.js.map +1 -0
  152. package/.next/server/chunks/ssr/[root-of-the-server]__0xm3h9x._.js +1 -1
  153. package/.next/server/chunks/ssr/[root-of-the-server]__0xm3h9x._.js.map +1 -1
  154. package/.next/server/chunks/ssr/[root-of-the-server]__0xo8x6b._.js +3 -0
  155. package/.next/server/chunks/ssr/[root-of-the-server]__0xo8x6b._.js.map +1 -0
  156. package/.next/server/chunks/ssr/_13_v7-3._.js +3 -0
  157. package/.next/server/chunks/ssr/_13_v7-3._.js.map +1 -0
  158. package/.next/server/chunks/ssr/app_10b5blc._.js +9 -0
  159. package/.next/server/chunks/ssr/app_10b5blc._.js.map +1 -0
  160. package/.next/server/chunks/ssr/app_components_08ys5y3._.js +9 -0
  161. package/.next/server/chunks/ssr/app_components_08ys5y3._.js.map +1 -0
  162. package/.next/server/chunks/ssr/app_page_tsx_0es_sk2._.js +1 -1
  163. package/.next/server/chunks/ssr/app_page_tsx_0es_sk2._.js.map +1 -1
  164. package/.next/server/chunks/ssr/app_tasks_page_tsx_0z-d6mp._.js +1 -1
  165. package/.next/server/chunks/ssr/app_tasks_page_tsx_0z-d6mp._.js.map +1 -1
  166. package/.next/server/middleware-build-manifest.js +3 -3
  167. package/.next/server/pages/404.html +2 -2
  168. package/.next/server/pages/500.html +1 -1
  169. package/.next/server/server-reference-manifest.js +1 -1
  170. package/.next/server/server-reference-manifest.json +1 -1
  171. package/.next/static/chunks/03wwuo3wor.05.js +1 -0
  172. package/.next/static/chunks/04nx85kn48m6a.css +2 -0
  173. package/.next/static/chunks/09xm65~ucg19e.js +1 -0
  174. package/.next/static/chunks/0bbx5m_hcs39u.js +1 -0
  175. package/.next/static/chunks/0f0tgtns1m6zh.js +1 -0
  176. package/.next/static/chunks/10ir.g.n~hre0.js +7 -0
  177. package/.next/static/chunks/12dcb86elsl-e.js +7 -0
  178. package/.next/static/chunks/12xk2ohuxsyo5.js +1 -0
  179. package/.next/static/chunks/132e__998_q9r.js +1 -0
  180. package/.next/trace +2 -2
  181. package/.next/trace-build +1 -1
  182. package/app/components/AgentCard.tsx +6 -2
  183. package/app/components/AliasAvatar.tsx +51 -0
  184. package/app/components/AppShell.tsx +9 -1
  185. package/app/components/CommandPalette.tsx +391 -0
  186. package/app/components/HealthBanner.tsx +132 -0
  187. package/app/components/HelpOverlay.tsx +121 -0
  188. package/app/components/LoadingSkeleton.tsx +81 -25
  189. package/app/components/Sidebar.tsx +18 -0
  190. package/app/components/TaskChatPanel.tsx +7 -5
  191. package/app/components/TopoGraph.tsx +16 -3
  192. package/app/components/UserBar.tsx +16 -2
  193. package/app/globals.css +244 -0
  194. package/app/messages/page.tsx +79 -48
  195. package/app/nodes/page.tsx +21 -23
  196. package/app/page.tsx +96 -20
  197. package/app/tasks/page.tsx +130 -40
  198. package/docs/loop-design-rounds.md +298 -3
  199. package/docs/screenshots/0.4.5-preview.1/cyber-admin.png +0 -0
  200. package/docs/screenshots/0.4.5-preview.1/cyber-cmdk-search.png +0 -0
  201. package/docs/screenshots/0.4.5-preview.1/cyber-cmdk.png +0 -0
  202. package/docs/screenshots/0.4.5-preview.1/cyber-login.png +0 -0
  203. package/docs/screenshots/0.4.5-preview.1/cyber-overview.png +0 -0
  204. package/docs/screenshots/0.4.5-preview.1/cyber-settings.png +0 -0
  205. package/docs/screenshots/0.4.5-preview.1/cyber-tasks.png +0 -0
  206. package/docs/screenshots/0.4.5-preview.1/light-admin.png +0 -0
  207. package/docs/screenshots/0.4.5-preview.1/light-cmdk-search.png +0 -0
  208. package/docs/screenshots/0.4.5-preview.1/light-cmdk.png +0 -0
  209. package/docs/screenshots/0.4.5-preview.1/light-login.png +0 -0
  210. package/docs/screenshots/0.4.5-preview.1/light-overview.png +0 -0
  211. package/docs/screenshots/0.4.5-preview.1/light-settings.png +0 -0
  212. package/docs/screenshots/0.4.5-preview.1/light-tasks.png +0 -0
  213. package/package.json +1 -1
  214. package/.next/server/chunks/ssr/[root-of-the-server]__013i9e9._.js +0 -9
  215. package/.next/server/chunks/ssr/[root-of-the-server]__013i9e9._.js.map +0 -1
  216. package/.next/server/chunks/ssr/[root-of-the-server]__0_jnflc._.js +0 -3
  217. package/.next/server/chunks/ssr/[root-of-the-server]__0_jnflc._.js.map +0 -1
  218. package/.next/server/chunks/ssr/[root-of-the-server]__0nrckjd._.js +0 -3
  219. package/.next/server/chunks/ssr/[root-of-the-server]__0nrckjd._.js.map +0 -1
  220. package/.next/server/chunks/ssr/[root-of-the-server]__12mpoig._.js +0 -3
  221. package/.next/server/chunks/ssr/[root-of-the-server]__12mpoig._.js.map +0 -1
  222. package/.next/server/chunks/ssr/_0d-fuox._.js +0 -3
  223. package/.next/server/chunks/ssr/_0d-fuox._.js.map +0 -1
  224. package/.next/server/chunks/ssr/app_0ff~kjj._.js +0 -9
  225. package/.next/server/chunks/ssr/app_0ff~kjj._.js.map +0 -1
  226. package/.next/static/chunks/06t_vzei8s9_h.js +0 -1
  227. package/.next/static/chunks/07okhs5561y5y.js +0 -1
  228. package/.next/static/chunks/0hyhubmh-__wg.js +0 -1
  229. package/.next/static/chunks/0khpyxpdrp~ty.js +0 -1
  230. package/.next/static/chunks/0lo_g.q1fm-hr.js +0 -7
  231. package/.next/static/chunks/0ogeals5ufhho.js +0 -1
  232. package/.next/static/chunks/0snd~q2ucn.h1.css +0 -2
  233. package/.next/static/chunks/0xn9.0ejo1s_a.js +0 -7
  234. package/.next/static/chunks/0y0lo-~k2c~00.js +0 -1
  235. /package/.next/static/{2m1yIfZCIYDWMYrrJEKSC → kfcVh72WCbkWVFpnWl0vE}/_buildManifest.js +0 -0
  236. /package/.next/static/{2m1yIfZCIYDWMYrrJEKSC → kfcVh72WCbkWVFpnWl0vE}/_clientMiddlewareManifest.js +0 -0
  237. /package/.next/static/{2m1yIfZCIYDWMYrrJEKSC → kfcVh72WCbkWVFpnWl0vE}/_ssgManifest.js +0 -0
@@ -1,42 +1,86 @@
1
1
  'use client';
2
2
 
3
+ /**
4
+ * Loading skeleton — mirrors the actual Overview layout structure so the
5
+ * page doesn't appear to "shift" once data arrives. Uses the same
6
+ * `anet-skeleton-pulse` rhythm as the brand pulse (1.6s opacity drift,
7
+ * no scale, no blur, no glow) so the loading animation feels native to
8
+ * the rest of the dashboard rather than a generic spinner.
9
+ *
10
+ * Bars are theme-aware: anet-skeleton-bar (existing CSS shim resolves this to
11
+ * var(--bg-elevated) on light/mint), so light theme shows soft grey blocks
12
+ * on white cards and dark theme shows lighter blocks on navy cards.
13
+ */
3
14
  export function LoadingSkeleton() {
4
15
  return (
5
- <div className="min-h-screen bg-[#0a0a1a] text-gray-100 p-6 font-mono animate-pulse">
6
- {/* Header skeleton */}
7
- <div className="flex items-center justify-between mb-8">
8
- <div>
9
- <div className="h-7 w-48 bg-gray-800 rounded mb-2" />
10
- <div className="h-4 w-64 bg-gray-800/60 rounded" />
11
- </div>
12
- <div className="flex gap-3">
13
- {[1, 2, 3].map(i => (
14
- <div key={i} className="w-[72px] h-[60px] bg-gray-800/40 rounded-lg border border-gray-800" />
15
- ))}
16
+ <div className="min-h-screen bg-[#0a0a1a] text-gray-100 p-4 sm:p-6 font-mono">
17
+ {/* KPI top strip — 4 cards matching StatsBar */}
18
+ <div className="grid grid-cols-2 sm:grid-cols-4 gap-3 mb-8 anet-skeleton-pulse">
19
+ {[1, 2, 3, 4].map(i => (
20
+ <div key={i} className="rounded-xl border border-[#2a2a4a] bg-[#111128] px-4 py-3">
21
+ <Bar w="2.5rem" h="1.75rem" />
22
+ <Bar w="3.5rem" h="0.75rem" className="mt-2" />
23
+ <Bar w="5rem" h="0.625rem" className="mt-1" />
24
+ </div>
25
+ ))}
26
+ </div>
27
+
28
+ {/* Dispatch + UserBar row */}
29
+ <div className="flex items-center gap-3 mb-3 anet-skeleton-pulse">
30
+ <Bar w="6rem" h="2.5rem" rounded="0.75rem" />
31
+ <div className="flex-1 rounded-lg border border-[#2a2a4a] bg-[#111128] px-4 py-2.5 flex items-center gap-3">
32
+ <div className="w-8 h-8 rounded-full anet-skeleton-bar" />
33
+ <div className="flex-1">
34
+ <Bar w="6rem" h="0.875rem" />
35
+ <Bar w="10rem" h="0.625rem" className="mt-1" />
36
+ </div>
16
37
  </div>
17
38
  </div>
18
39
 
19
- {/* Broadcast bar skeleton */}
20
- <div className="mb-6 flex gap-2">
21
- <div className="flex-1 h-10 bg-gray-800/40 rounded-lg" />
22
- <div className="w-28 h-10 bg-gray-800/40 rounded-lg" />
40
+ {/* Config bar */}
41
+ <div className="mb-6 rounded-lg border border-[#2a2a4a] bg-[#111128] px-4 py-3 anet-skeleton-pulse">
42
+ <Bar w="14rem" h="0.875rem" />
43
+ </div>
44
+
45
+ {/* Stat strip 3 cards */}
46
+ <div className="grid grid-cols-3 gap-2 sm:gap-3 mb-3 anet-skeleton-pulse">
47
+ {[1, 2, 3].map(i => (
48
+ <div key={i} className="rounded-xl border border-[#2a2a4a] bg-[#111128] px-3 py-3">
49
+ <Bar w="2rem" h="1.25rem" />
50
+ <Bar w="2.5rem" h="0.75rem" className="mt-1" />
51
+ <Bar w="3.5rem" h="0.625rem" className="mt-px" />
52
+ </div>
53
+ ))}
54
+ </div>
55
+
56
+ {/* Nav rail 3 cards */}
57
+ <div className="grid grid-cols-3 gap-2 sm:gap-3 mb-6 anet-skeleton-pulse">
58
+ {[1, 2, 3].map(i => (
59
+ <div key={i} className="rounded-xl border border-[#2a2a4a] bg-[#111128] px-3 py-2.5 flex items-center justify-center gap-2">
60
+ <div className="w-4 h-4 rounded anet-skeleton-bar" />
61
+ <Bar w="4rem" h="0.75rem" />
62
+ </div>
63
+ ))}
23
64
  </div>
24
65
 
25
- {/* Topology skeleton */}
26
- <div className="w-full max-w-4xl mx-auto mb-8 h-64 bg-gray-800/20 rounded-xl" />
66
+ {/* Broadcast bar */}
67
+ <div className="mb-6 flex gap-2 anet-skeleton-pulse">
68
+ <div className="flex-1 h-10 rounded-lg border border-[#2a2a4a] bg-[#111128]" />
69
+ <div className="w-28 h-10 rounded-lg anet-skeleton-bar" />
70
+ </div>
27
71
 
28
- {/* Card grid skeleton */}
29
- <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4">
72
+ {/* Agent card grid */}
73
+ <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-2 xl:grid-cols-3 2xl:grid-cols-4 gap-3 sm:gap-4 anet-skeleton-pulse">
30
74
  {[1, 2, 3, 4].map(i => (
31
- <div key={i} className="rounded-xl border border-gray-800/40 p-4 bg-gray-800/20">
75
+ <div key={i} className="rounded-xl border border-[#2a2a4a] bg-[#111128] p-4">
32
76
  <div className="flex items-center gap-2 mb-3">
33
- <div className="w-2.5 h-2.5 rounded-full bg-gray-700" />
34
- <div className="h-4 w-24 bg-gray-700 rounded" />
77
+ <div className="w-2 h-2 rounded-full anet-skeleton-bar" />
78
+ <Bar w="6rem" h="0.875rem" />
35
79
  </div>
36
80
  <div className="space-y-2">
37
- <div className="h-3 w-full bg-gray-800/60 rounded" />
38
- <div className="h-3 w-3/4 bg-gray-800/60 rounded" />
39
- <div className="h-3 w-1/2 bg-gray-800/60 rounded" />
81
+ <Bar w="100%" h="0.625rem" />
82
+ <Bar w="75%" h="0.625rem" />
83
+ <Bar w="55%" h="0.625rem" />
40
84
  </div>
41
85
  </div>
42
86
  ))}
@@ -45,6 +89,18 @@ export function LoadingSkeleton() {
45
89
  );
46
90
  }
47
91
 
92
+ /** Single shimmer bar — uses `anet-skeleton-bar` so theme-specific bar
93
+ * color (dark navy on dark themes, mid-grey on light) overrides the
94
+ * default. */
95
+ function Bar({ w, h, rounded, className }: { w: string; h: string; rounded?: string; className?: string }) {
96
+ return (
97
+ <div
98
+ className={`anet-skeleton-bar ${className || ''}`}
99
+ style={{ width: w, height: h, borderRadius: rounded || '0.375rem' }}
100
+ />
101
+ );
102
+ }
103
+
48
104
  // EmptyState export removed in 0.4.5 — replaced by EmptyState.tsx with
49
105
  // per-variant glyphs and a NodesEmptyState wrapper for the Overview
50
106
  // hint-aware behavior. See app/components/EmptyState.tsx.
@@ -151,6 +151,24 @@ export function Sidebar() {
151
151
  Sign out
152
152
  </button>
153
153
  )}
154
+ {!collapsed && (
155
+ <button
156
+ onClick={() => {
157
+ // Dispatch a synthetic keypress so the global Cmd+K listener fires
158
+ window.dispatchEvent(new KeyboardEvent('keydown', { key: 'k', metaKey: true, ctrlKey: true }));
159
+ }}
160
+ className="w-full flex items-center justify-between gap-2 px-5 py-2 text-[11px] text-gray-600 hover:text-gray-400 hover:bg-[#1a1a2a] transition-colors"
161
+ aria-label="Open command palette"
162
+ >
163
+ <span className="flex items-center gap-2">
164
+ <svg className="w-3.5 h-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={1.5}>
165
+ <path strokeLinecap="round" strokeLinejoin="round" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" />
166
+ </svg>
167
+ Quick search
168
+ </span>
169
+ <kbd className="text-[10px] border border-current rounded px-1 py-0.5 opacity-60 font-mono">⌘K</kbd>
170
+ </button>
171
+ )}
154
172
  <div className={`flex items-center gap-2 px-3 py-2 ${collapsed ? 'justify-center' : 'justify-between'}`}>
155
173
  <ThemeSwitcher compact={collapsed} />
156
174
  <button
@@ -2,6 +2,7 @@
2
2
 
3
3
  import { useState, useEffect, useRef, useCallback } from 'react';
4
4
  import { timeAgo } from './utils';
5
+ import { AliasAvatar } from './AliasAvatar';
5
6
 
6
7
  interface ChatTask {
7
8
  task_id: string;
@@ -386,7 +387,10 @@ export function TaskChatPanel({ alias, onClose, inline, availableNodes }: TaskCh
386
387
  {m.result && (
387
388
  <div className="flex justify-start">
388
389
  <div className="max-w-[85%] bg-green-500/8 border border-green-500/15 rounded-2xl rounded-bl-md px-4 py-2.5 shadow-sm">
389
- <div className="text-[10px] text-green-400 font-medium mb-1.5">{m.to_name}</div>
390
+ <div className="flex items-center gap-1.5 mb-1.5">
391
+ {m.to_name && <AliasAvatar alias={m.to_name} size={14} />}
392
+ <span className="text-[10px] text-gray-200 font-medium">{m.to_name}</span>
393
+ </div>
390
394
  <div className="text-[13px] text-gray-200">
391
395
  <MarkdownContent text={m.result} />
392
396
  </div>
@@ -422,7 +426,7 @@ export function TaskChatPanel({ alias, onClose, inline, availableNodes }: TaskCh
422
426
  {filteredMentions.map(node => (
423
427
  <button key={node} onClick={() => insertMention(node)}
424
428
  className="w-full flex items-center gap-2 px-3 py-2 text-xs text-left hover:bg-cyan-500/10 transition-colors">
425
- <span className="w-2 h-2 rounded-full bg-cyan-400 shrink-0" />
429
+ <AliasAvatar alias={node} size={16} />
426
430
  <span className="text-gray-300">{node}</span>
427
431
  </button>
428
432
  ))}
@@ -476,9 +480,7 @@ export function TaskChatPanel({ alias, onClose, inline, availableNodes }: TaskCh
476
480
  {/* Header */}
477
481
  <div className="flex items-center justify-between px-4 py-3 border-b border-[#2a2a4a] bg-[#0d0d1a]">
478
482
  <div className="flex items-center gap-3">
479
- <div className="w-8 h-8 rounded-full bg-gradient-to-br from-cyan-500/30 to-blue-500/30 flex items-center justify-center text-xs font-bold text-cyan-300">
480
- {alias.slice(0, 2)}
481
- </div>
483
+ <AliasAvatar alias={alias} size={32} />
482
484
  <div>
483
485
  <div className="text-sm font-semibold text-white">{alias}</div>
484
486
  <div className="text-[10px] text-gray-500">{pollingIds.size > 0 ? 'Processing...' : 'Ready'}</div>
@@ -33,10 +33,14 @@ const cy = 330;
33
33
  const onlineRadius = 220;
34
34
  const offlineRadius = 315;
35
35
 
36
- function polarPoint(index: number, total: number, radius: number) {
36
+ /** Polar coordinate for a node on a ring. `rotateBy` lets the caller offset
37
+ * the whole ring so two stacked rings don't align radially (round 25: the
38
+ * offline ring gets a half-step rotation so its nodes sit in the gaps
39
+ * between online ones). */
40
+ function polarPoint(index: number, total: number, radius: number, rotateBy = 0) {
37
41
  const spread = total <= 2 ? Math.PI : Math.PI * 1.78;
38
42
  const start = -Math.PI / 2 - spread / 2;
39
- const angle = total <= 1 ? -Math.PI / 2 : start + (spread * index) / (total - 1);
43
+ const angle = total <= 1 ? -Math.PI / 2 : start + (spread * index) / (total - 1) + rotateBy;
40
44
  return {
41
45
  x: cx + radius * Math.cos(angle),
42
46
  y: cy + radius * Math.sin(angle),
@@ -248,8 +252,17 @@ export function TopoGraph({ sessions, sseSessions }: TopoGraphProps) {
248
252
  positions[s.alias] = polarPoint(index, Math.max(online.length, 1), onlineRadius);
249
253
  });
250
254
 
255
+ // Offset the offline ring radially by half the online step so offline
256
+ // bubbles sit in the angular gaps between online bubbles instead of
257
+ // stacking directly behind them. Also push the outer ring further when
258
+ // there are many offline nodes so labels don't crowd the legend.
259
+ const spread = online.length <= 2 ? Math.PI : Math.PI * 1.78;
260
+ const onlineStep = online.length > 1 ? spread / (online.length - 1) : 0;
261
+ const offlineRotation = online.length > 0 ? onlineStep / 2 : 0;
262
+ const offlineR = offlineRadius + Math.max(0, offline.length - 4) * 6;
263
+
251
264
  offline.forEach((s, index) => {
252
- positions[s.alias] = polarPoint(index, Math.max(offline.length, 1), offlineRadius);
265
+ positions[s.alias] = polarPoint(index, Math.max(offline.length, 1), offlineR, offlineRotation);
253
266
  });
254
267
 
255
268
  const links = buildFlowLinks(messages, positions);
@@ -140,8 +140,22 @@ export function UserBar() {
140
140
  ))}
141
141
  </select>
142
142
  )}
143
- <button onClick={() => { setEditName(auth.user?.display_name || ''); setEditEmail(''); setEditing(!editing); }} className="text-xs text-gray-500 hover:text-gray-300">Edit</button>
144
- <button onClick={logout} className="text-xs text-gray-500 hover:text-gray-300">Sign out</button>
143
+ <button onClick={() => { setEditName(auth.user?.display_name || ''); setEditEmail(''); setEditing(!editing); }}
144
+ className="text-xs text-gray-500 hover:text-gray-300 whitespace-nowrap"
145
+ aria-label="Edit profile">
146
+ <span className="hidden sm:inline">Edit</span>
147
+ <svg className="sm:hidden w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth="1.5">
148
+ <path strokeLinecap="round" strokeLinejoin="round" d="M16.862 4.487l1.687-1.688a1.875 1.875 0 112.652 2.652L10.582 16.07a4.5 4.5 0 01-1.897 1.13l-2.685.8.8-2.685a4.5 4.5 0 011.13-1.897L16.862 4.487z" />
149
+ </svg>
150
+ </button>
151
+ <button onClick={logout}
152
+ className="text-xs text-gray-500 hover:text-gray-300 whitespace-nowrap"
153
+ aria-label="Sign out">
154
+ <span className="hidden sm:inline">Sign out</span>
155
+ <svg className="sm:hidden w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth="1.5">
156
+ <path strokeLinecap="round" strokeLinejoin="round" d="M15.75 9V5.25A2.25 2.25 0 0013.5 3h-6a2.25 2.25 0 00-2.25 2.25v13.5A2.25 2.25 0 007.5 21h6a2.25 2.25 0 002.25-2.25V15m3 0l3-3m0 0l-3-3m3 3H9" />
157
+ </svg>
158
+ </button>
145
159
  </div>
146
160
  {editing && (
147
161
  <div className="flex flex-wrap items-center gap-2 mt-2 pt-2 border-t border-[#2a2a4a]">
package/app/globals.css CHANGED
@@ -309,6 +309,66 @@ body {
309
309
  [data-theme="light"] .text-indigo-400 {
310
310
  color: var(--accent) !important;
311
311
  }
312
+
313
+ /* Light theme: every "-300/400" accent text color needs a darker mid-tone
314
+ variant. The default Tailwind `-300/-400` shades are designed for dark
315
+ backgrounds — putting them on white gives "barely visible" text (the
316
+ problem Vincent flagged: "浅色下很多字体看不见"). Map each family to its
317
+ `-700` equivalent so contrast against white card is ≥ AA. */
318
+ [data-theme="light"] .text-green-400,
319
+ [data-theme="light"] .text-green-300,
320
+ [data-theme="mint"] .text-green-400,
321
+ [data-theme="mint"] .text-green-300 { color: #047857 !important; }
322
+
323
+ [data-theme="light"] .text-yellow-400,
324
+ [data-theme="light"] .text-yellow-300,
325
+ [data-theme="mint"] .text-yellow-400,
326
+ [data-theme="mint"] .text-yellow-300 { color: #92400e !important; }
327
+
328
+ [data-theme="light"] .text-amber-400,
329
+ [data-theme="light"] .text-amber-300,
330
+ [data-theme="mint"] .text-amber-400,
331
+ [data-theme="mint"] .text-amber-300 { color: #92400e !important; }
332
+
333
+ [data-theme="light"] .text-red-400,
334
+ [data-theme="light"] .text-red-300,
335
+ [data-theme="mint"] .text-red-400,
336
+ [data-theme="mint"] .text-red-300 { color: #b91c1c !important; }
337
+
338
+ [data-theme="light"] .text-purple-400,
339
+ [data-theme="light"] .text-purple-300,
340
+ [data-theme="mint"] .text-purple-400,
341
+ [data-theme="mint"] .text-purple-300 { color: #6d28d9 !important; }
342
+
343
+ [data-theme="light"] .text-orange-400,
344
+ [data-theme="light"] .text-orange-300,
345
+ [data-theme="mint"] .text-orange-400,
346
+ [data-theme="mint"] .text-orange-300 { color: #c2410c !important; }
347
+
348
+ [data-theme="light"] .text-blue-400,
349
+ [data-theme="light"] .text-blue-300,
350
+ [data-theme="mint"] .text-blue-400,
351
+ [data-theme="mint"] .text-blue-300 { color: #1d4ed8 !important; }
352
+
353
+ [data-theme="light"] .text-pink-400,
354
+ [data-theme="light"] .text-pink-300,
355
+ [data-theme="mint"] .text-pink-400,
356
+ [data-theme="mint"] .text-pink-300 { color: #be185d !important; }
357
+
358
+ [data-theme="light"] .text-violet-400,
359
+ [data-theme="light"] .text-violet-300,
360
+ [data-theme="mint"] .text-violet-400,
361
+ [data-theme="mint"] .text-violet-300 { color: #6d28d9 !important; }
362
+
363
+ [data-theme="light"] .text-teal-400,
364
+ [data-theme="light"] .text-teal-300,
365
+ [data-theme="mint"] .text-teal-400,
366
+ [data-theme="mint"] .text-teal-300 { color: #0f766e !important; }
367
+
368
+ /* Light theme: text-gray-700 (used in footers / muted body) is too pale
369
+ when sitting on slightly-grey page bg. Bump to fg-muted. */
370
+ [data-theme="light"] .text-gray-700,
371
+ [data-theme="mint"] .text-gray-700 { color: var(--fg-muted) !important; }
312
372
  [data-theme="light"] .bg-emerald-500\/10,
313
373
  [data-theme="light"] .bg-emerald-500\/20,
314
374
  [data-theme="light"] .bg-cyan-500\/10,
@@ -517,6 +577,30 @@ body {
517
577
  box-shadow: 0 6px 18px -10px rgba(15, 23, 42, 0.12);
518
578
  }
519
579
 
580
+ /* Task row hover bg (round 19) — dark hex would land on a white card and
581
+ look like a stripe. Re-map to a faint accent tint per theme. */
582
+ [data-theme="light"] .anet-task-row:hover {
583
+ background-color: #f5f7fb !important;
584
+ }
585
+ [data-theme="mint"] .anet-task-row:hover {
586
+ background-color: #ecf6f1 !important;
587
+ }
588
+ [data-theme="sunset"] .anet-task-row:hover {
589
+ background-color: #fff4ec !important;
590
+ }
591
+ /* Open state — slightly stronger fill so users can see "this one is the
592
+ open row" while scrolling. */
593
+ [data-theme="light"] .anet-task-row[aria-expanded="true"] {
594
+ background-color: #fafbfd !important;
595
+ box-shadow: 0 4px 14px -10px rgba(15, 23, 42, 0.14) !important;
596
+ }
597
+ [data-theme="mint"] .anet-task-row[aria-expanded="true"] {
598
+ background-color: #f3faf6 !important;
599
+ }
600
+ [data-theme="sunset"] .anet-task-row[aria-expanded="true"] {
601
+ background-color: #fff8f1 !important;
602
+ }
603
+
520
604
  /* ─────────────────────────────────────────────────────────────────────
521
605
  Login surface (round 1 polish)
522
606
  Restrained, minimal — first impression for new Agent Network users.
@@ -539,6 +623,29 @@ body {
539
623
  box-shadow: 0 1px 2px rgba(15, 23, 42, 0.06), 0 0 0 1px var(--border);
540
624
  }
541
625
 
626
+ /* Health banner — sticky thin strip above content, with theme-aware
627
+ green/amber/red tints. Dark themes use the lower-opacity bg+border
628
+ that come from the component classes directly. Light/mint need
629
+ slightly more saturation so the tint reads on a white surface. */
630
+ [data-theme="light"] .anet-health-banner.bg-emerald-500\/6,
631
+ [data-theme="mint"] .anet-health-banner.bg-emerald-500\/6 {
632
+ background-color: rgba(16, 185, 129, 0.08) !important;
633
+ color: #047857 !important;
634
+ border-color: rgba(16, 185, 129, 0.25) !important;
635
+ }
636
+ [data-theme="light"] .anet-health-banner.bg-amber-500\/8,
637
+ [data-theme="mint"] .anet-health-banner.bg-amber-500\/8 {
638
+ background-color: rgba(245, 158, 11, 0.12) !important;
639
+ color: #92400e !important;
640
+ border-color: rgba(245, 158, 11, 0.30) !important;
641
+ }
642
+ [data-theme="light"] .anet-health-banner.bg-red-500\/8,
643
+ [data-theme="mint"] .anet-health-banner.bg-red-500\/8 {
644
+ background-color: rgba(220, 38, 38, 0.10) !important;
645
+ color: #b91c1c !important;
646
+ border-color: rgba(220, 38, 38, 0.30) !important;
647
+ }
648
+
542
649
  /* Sidebar brand "online" pulse — slow, restrained, NO glow.
543
650
  1.6s opacity drift between 1.0 and 0.5; nothing scales, nothing blurs. */
544
651
  @keyframes anet-brand-pulse-kf {
@@ -552,6 +659,143 @@ body {
552
659
  .anet-brand-pulse { animation: none; }
553
660
  }
554
661
 
662
+ /* Skeleton pulse — same 1.6s rhythm as the brand pulse but applied to a
663
+ container so all bars inside breathe together. Drifts between full
664
+ token value and 60% so light themes show a calm grey-to-bg-elevated
665
+ fade and dark themes show a calm navy-to-elevated fade. */
666
+ @keyframes anet-skeleton-kf {
667
+ 0%, 100% { opacity: 1; }
668
+ 50% { opacity: 0.55; }
669
+ }
670
+ .anet-skeleton-pulse {
671
+ animation: anet-skeleton-kf 1.6s ease-in-out infinite;
672
+ }
673
+ @media (prefers-reduced-motion: reduce) {
674
+ .anet-skeleton-pulse { animation: none; }
675
+ }
676
+
677
+ /* Skeleton bar fill — different per theme so it's visible against the
678
+ card bg without being loud. Dark: lighter navy block on dark card.
679
+ Light: mid-grey on white card (not too light or it disappears). */
680
+ .anet-skeleton-bar {
681
+ background-color: #1a1a2a;
682
+ }
683
+ [data-theme="light"] .anet-skeleton-bar,
684
+ [data-theme="mint"] .anet-skeleton-bar {
685
+ background-color: #d4d8df;
686
+ }
687
+
688
+ /* Command palette modal surface — bumped depth so it sits clearly above
689
+ the page content in both themes. Light/mint: white shell with a real
690
+ shadow (not the dark navy that the CSS shim would normally translate
691
+ `bg-[#0d0d1a]` into). */
692
+ .anet-cmdk kbd {
693
+ font-size: 9px;
694
+ line-height: 1;
695
+ padding: 1px 4px;
696
+ border: 1px solid currentColor;
697
+ border-radius: 3px;
698
+ opacity: 0.6;
699
+ }
700
+ [data-theme="light"] .anet-cmdk > div:not([aria-hidden]),
701
+ [data-theme="mint"] .anet-cmdk > div:not([aria-hidden]) {
702
+ background-color: var(--bg-secondary) !important;
703
+ box-shadow: 0 10px 30px -8px rgba(15, 23, 42, 0.18),
704
+ 0 2px 6px -2px rgba(15, 23, 42, 0.10);
705
+ }
706
+ [data-theme="light"] .anet-cmdk-row.bg-cyan-500\/10,
707
+ [data-theme="mint"] .anet-cmdk-row.bg-cyan-500\/10 {
708
+ background-color: rgba(0, 158, 126, 0.08) !important;
709
+ }
710
+
711
+ /* Round 20 — matched-char highlight inside cmdk titles/hints. Inherits
712
+ line color (`color`) instead of forcing one — keeps text readable on
713
+ both inactive (gray) and active (cyan-300) rows. <mark> default is a
714
+ garish yellow block, which we override. */
715
+ .anet-cmdk-mark {
716
+ background: transparent;
717
+ color: inherit;
718
+ font-weight: 600;
719
+ /* Subtle underline so the mark stays visible even on the active row
720
+ where the background tint matches the accent color. */
721
+ text-decoration: underline;
722
+ text-decoration-color: currentColor;
723
+ text-decoration-thickness: 1px;
724
+ text-underline-offset: 2px;
725
+ text-decoration-skip-ink: none;
726
+ }
727
+ /* Cyber: accent the matched glyph color so it pops on the dark bg. */
728
+ [data-theme="cyber"] .anet-cmdk-mark,
729
+ :root:not([data-theme]) .anet-cmdk-mark {
730
+ color: #22d3ee;
731
+ }
732
+ /* Light/mint: use the brand teal — undertone matches the active row. */
733
+ [data-theme="light"] .anet-cmdk-mark,
734
+ [data-theme="mint"] .anet-cmdk-mark {
735
+ color: #0d9488;
736
+ }
737
+ [data-theme="sunset"] .anet-cmdk-mark {
738
+ color: #ea580c;
739
+ }
740
+ /* On the active (cyan-tinted) row, the title is already cyan-300 — use
741
+ white-with-underline so the highlight reads as emphasis, not redundancy. */
742
+ .anet-cmdk-row.bg-cyan-500\/10 .anet-cmdk-mark {
743
+ color: #f0fdff;
744
+ }
745
+ [data-theme="light"] .anet-cmdk-row.bg-cyan-500\/10 .anet-cmdk-mark,
746
+ [data-theme="mint"] .anet-cmdk-row.bg-cyan-500\/10 .anet-cmdk-mark {
747
+ color: #064e3b;
748
+ }
749
+
750
+ /* Help overlay — same white-card-with-shadow treatment as cmdk on light */
751
+ [data-theme="light"] .anet-help > div:not([aria-hidden]),
752
+ [data-theme="mint"] .anet-help > div:not([aria-hidden]) {
753
+ background-color: var(--bg-secondary) !important;
754
+ box-shadow: 0 10px 30px -8px rgba(15, 23, 42, 0.18),
755
+ 0 2px 6px -2px rgba(15, 23, 42, 0.10);
756
+ }
757
+
758
+ /* Tasks tab strip horizontal scroll fade — gradient overlays at left/right
759
+ edges hint that there's more content when the row overflows. Only
760
+ applied on <sm (where the strip actually scrolls). The wrapper is
761
+ `position: relative` and the fades are absolute siblings. */
762
+ .anet-tabstrip-wrap {
763
+ position: relative;
764
+ }
765
+ .anet-tabstrip-wrap::before,
766
+ .anet-tabstrip-wrap::after {
767
+ content: '';
768
+ position: absolute;
769
+ top: 4px;
770
+ bottom: 4px;
771
+ width: 20px;
772
+ pointer-events: none;
773
+ z-index: 1;
774
+ }
775
+ .anet-tabstrip-wrap::before {
776
+ left: 0;
777
+ background: linear-gradient(to right, #111128, transparent);
778
+ border-radius: 8px 0 0 8px;
779
+ }
780
+ .anet-tabstrip-wrap::after {
781
+ right: 0;
782
+ background: linear-gradient(to left, #111128, transparent);
783
+ border-radius: 0 8px 8px 0;
784
+ }
785
+ @media (min-width: 640px) {
786
+ /* sm: stops scrolling, hide the fades */
787
+ .anet-tabstrip-wrap::before,
788
+ .anet-tabstrip-wrap::after { display: none; }
789
+ }
790
+ [data-theme="light"] .anet-tabstrip-wrap::before,
791
+ [data-theme="mint"] .anet-tabstrip-wrap::before {
792
+ background: linear-gradient(to right, var(--bg-secondary), transparent);
793
+ }
794
+ [data-theme="light"] .anet-tabstrip-wrap::after,
795
+ [data-theme="mint"] .anet-tabstrip-wrap::after {
796
+ background: linear-gradient(to left, var(--bg-secondary), transparent);
797
+ }
798
+
555
799
  /* P0-3 baseline: error / warning chip colors for light themes.
556
800
  The component-level copy (replacing raw JSON with human text) is fixed
557
801
  in the Logs / Server-Logs page components separately. */