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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (272) hide show
  1. package/.next/BUILD_ID +1 -1
  2. package/.next/build-manifest.json +6 -6
  3. package/.next/diagnostics/route-bundle-stats.json +106 -92
  4. package/.next/fallback-build-manifest.json +3 -3
  5. package/.next/prerender-manifest.json +3 -3
  6. package/.next/server/app/_global-error/page/build-manifest.json +3 -3
  7. package/.next/server/app/_global-error.html +1 -1
  8. package/.next/server/app/_global-error.rsc +1 -1
  9. package/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  10. package/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  11. package/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  12. package/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  13. package/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  14. package/.next/server/app/_not-found/page/build-manifest.json +3 -3
  15. package/.next/server/app/_not-found/page.js.nft.json +1 -1
  16. package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  17. package/.next/server/app/_not-found.html +2 -2
  18. package/.next/server/app/_not-found.rsc +12 -12
  19. package/.next/server/app/_not-found.segments/_full.segment.rsc +12 -12
  20. package/.next/server/app/_not-found.segments/_head.segment.rsc +4 -4
  21. package/.next/server/app/_not-found.segments/_index.segment.rsc +7 -7
  22. package/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +2 -2
  23. package/.next/server/app/_not-found.segments/_not-found.segment.rsc +3 -3
  24. package/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  25. package/.next/server/app/admin/page/build-manifest.json +3 -3
  26. package/.next/server/app/admin/page.js.nft.json +1 -1
  27. package/.next/server/app/admin/page_client-reference-manifest.js +1 -1
  28. package/.next/server/app/admin.html +2 -2
  29. package/.next/server/app/admin.rsc +14 -14
  30. package/.next/server/app/admin.segments/_full.segment.rsc +14 -14
  31. package/.next/server/app/admin.segments/_head.segment.rsc +4 -4
  32. package/.next/server/app/admin.segments/_index.segment.rsc +7 -7
  33. package/.next/server/app/admin.segments/_tree.segment.rsc +2 -2
  34. package/.next/server/app/admin.segments/admin/__PAGE__.segment.rsc +4 -4
  35. package/.next/server/app/admin.segments/admin.segment.rsc +3 -3
  36. package/.next/server/app/index.html +2 -2
  37. package/.next/server/app/index.rsc +14 -14
  38. package/.next/server/app/index.segments/__PAGE__.segment.rsc +4 -4
  39. package/.next/server/app/index.segments/_full.segment.rsc +14 -14
  40. package/.next/server/app/index.segments/_head.segment.rsc +4 -4
  41. package/.next/server/app/index.segments/_index.segment.rsc +7 -7
  42. package/.next/server/app/index.segments/_tree.segment.rsc +2 -2
  43. package/.next/server/app/login/page/build-manifest.json +3 -3
  44. package/.next/server/app/login/page.js.nft.json +1 -1
  45. package/.next/server/app/login/page_client-reference-manifest.js +1 -1
  46. package/.next/server/app/login.html +2 -2
  47. package/.next/server/app/login.rsc +14 -14
  48. package/.next/server/app/login.segments/_full.segment.rsc +14 -14
  49. package/.next/server/app/login.segments/_head.segment.rsc +4 -4
  50. package/.next/server/app/login.segments/_index.segment.rsc +7 -7
  51. package/.next/server/app/login.segments/_tree.segment.rsc +2 -2
  52. package/.next/server/app/login.segments/login/__PAGE__.segment.rsc +4 -4
  53. package/.next/server/app/login.segments/login.segment.rsc +3 -3
  54. package/.next/server/app/logs/page/build-manifest.json +3 -3
  55. package/.next/server/app/logs/page.js.nft.json +1 -1
  56. package/.next/server/app/logs/page_client-reference-manifest.js +1 -1
  57. package/.next/server/app/logs.html +2 -2
  58. package/.next/server/app/logs.rsc +14 -14
  59. package/.next/server/app/logs.segments/_full.segment.rsc +14 -14
  60. package/.next/server/app/logs.segments/_head.segment.rsc +4 -4
  61. package/.next/server/app/logs.segments/_index.segment.rsc +7 -7
  62. package/.next/server/app/logs.segments/_tree.segment.rsc +2 -2
  63. package/.next/server/app/logs.segments/logs/__PAGE__.segment.rsc +4 -4
  64. package/.next/server/app/logs.segments/logs.segment.rsc +3 -3
  65. package/.next/server/app/messages/page/build-manifest.json +3 -3
  66. package/.next/server/app/messages/page.js.nft.json +1 -1
  67. package/.next/server/app/messages/page_client-reference-manifest.js +1 -1
  68. package/.next/server/app/messages.html +2 -2
  69. package/.next/server/app/messages.rsc +14 -14
  70. package/.next/server/app/messages.segments/_full.segment.rsc +14 -14
  71. package/.next/server/app/messages.segments/_head.segment.rsc +4 -4
  72. package/.next/server/app/messages.segments/_index.segment.rsc +7 -7
  73. package/.next/server/app/messages.segments/_tree.segment.rsc +2 -2
  74. package/.next/server/app/messages.segments/messages/__PAGE__.segment.rsc +4 -4
  75. package/.next/server/app/messages.segments/messages.segment.rsc +3 -3
  76. package/.next/server/app/node/page/build-manifest.json +3 -3
  77. package/.next/server/app/node/page.js.nft.json +1 -1
  78. package/.next/server/app/node/page_client-reference-manifest.js +1 -1
  79. package/.next/server/app/node.html +2 -2
  80. package/.next/server/app/node.rsc +14 -14
  81. package/.next/server/app/node.segments/_full.segment.rsc +14 -14
  82. package/.next/server/app/node.segments/_head.segment.rsc +4 -4
  83. package/.next/server/app/node.segments/_index.segment.rsc +7 -7
  84. package/.next/server/app/node.segments/_tree.segment.rsc +2 -2
  85. package/.next/server/app/node.segments/node/__PAGE__.segment.rsc +4 -4
  86. package/.next/server/app/node.segments/node.segment.rsc +3 -3
  87. package/.next/server/app/nodes/page/build-manifest.json +3 -3
  88. package/.next/server/app/nodes/page.js.nft.json +1 -1
  89. package/.next/server/app/nodes/page_client-reference-manifest.js +1 -1
  90. package/.next/server/app/nodes.html +2 -2
  91. package/.next/server/app/nodes.rsc +14 -14
  92. package/.next/server/app/nodes.segments/_full.segment.rsc +14 -14
  93. package/.next/server/app/nodes.segments/_head.segment.rsc +4 -4
  94. package/.next/server/app/nodes.segments/_index.segment.rsc +7 -7
  95. package/.next/server/app/nodes.segments/_tree.segment.rsc +2 -2
  96. package/.next/server/app/nodes.segments/nodes/__PAGE__.segment.rsc +4 -4
  97. package/.next/server/app/nodes.segments/nodes.segment.rsc +3 -3
  98. package/.next/server/app/page/build-manifest.json +3 -3
  99. package/.next/server/app/page.js.nft.json +1 -1
  100. package/.next/server/app/page_client-reference-manifest.js +1 -1
  101. package/.next/server/app/server-logs/page/build-manifest.json +3 -3
  102. package/.next/server/app/server-logs/page.js.nft.json +1 -1
  103. package/.next/server/app/server-logs/page_client-reference-manifest.js +1 -1
  104. package/.next/server/app/server-logs.html +2 -2
  105. package/.next/server/app/server-logs.rsc +14 -14
  106. package/.next/server/app/server-logs.segments/_full.segment.rsc +14 -14
  107. package/.next/server/app/server-logs.segments/_head.segment.rsc +4 -4
  108. package/.next/server/app/server-logs.segments/_index.segment.rsc +7 -7
  109. package/.next/server/app/server-logs.segments/_tree.segment.rsc +2 -2
  110. package/.next/server/app/server-logs.segments/server-logs/__PAGE__.segment.rsc +4 -4
  111. package/.next/server/app/server-logs.segments/server-logs.segment.rsc +3 -3
  112. package/.next/server/app/settings/networks/page/build-manifest.json +3 -3
  113. package/.next/server/app/settings/networks/page.js.nft.json +1 -1
  114. package/.next/server/app/settings/networks/page_client-reference-manifest.js +1 -1
  115. package/.next/server/app/settings/networks.html +2 -2
  116. package/.next/server/app/settings/networks.rsc +14 -14
  117. package/.next/server/app/settings/networks.segments/_full.segment.rsc +14 -14
  118. package/.next/server/app/settings/networks.segments/_head.segment.rsc +4 -4
  119. package/.next/server/app/settings/networks.segments/_index.segment.rsc +7 -7
  120. package/.next/server/app/settings/networks.segments/_tree.segment.rsc +2 -2
  121. package/.next/server/app/settings/networks.segments/settings/networks/__PAGE__.segment.rsc +4 -4
  122. package/.next/server/app/settings/networks.segments/settings/networks.segment.rsc +3 -3
  123. package/.next/server/app/settings/networks.segments/settings.segment.rsc +3 -3
  124. package/.next/server/app/settings/page/build-manifest.json +3 -3
  125. package/.next/server/app/settings/page.js.nft.json +1 -1
  126. package/.next/server/app/settings/page_client-reference-manifest.js +1 -1
  127. package/.next/server/app/settings/tokens/page/build-manifest.json +3 -3
  128. package/.next/server/app/settings/tokens/page.js.nft.json +1 -1
  129. package/.next/server/app/settings/tokens/page_client-reference-manifest.js +1 -1
  130. package/.next/server/app/settings/tokens.html +2 -2
  131. package/.next/server/app/settings/tokens.rsc +14 -14
  132. package/.next/server/app/settings/tokens.segments/_full.segment.rsc +14 -14
  133. package/.next/server/app/settings/tokens.segments/_head.segment.rsc +4 -4
  134. package/.next/server/app/settings/tokens.segments/_index.segment.rsc +7 -7
  135. package/.next/server/app/settings/tokens.segments/_tree.segment.rsc +2 -2
  136. package/.next/server/app/settings/tokens.segments/settings/tokens/__PAGE__.segment.rsc +4 -4
  137. package/.next/server/app/settings/tokens.segments/settings/tokens.segment.rsc +3 -3
  138. package/.next/server/app/settings/tokens.segments/settings.segment.rsc +3 -3
  139. package/.next/server/app/settings.html +2 -2
  140. package/.next/server/app/settings.rsc +14 -14
  141. package/.next/server/app/settings.segments/_full.segment.rsc +14 -14
  142. package/.next/server/app/settings.segments/_head.segment.rsc +4 -4
  143. package/.next/server/app/settings.segments/_index.segment.rsc +7 -7
  144. package/.next/server/app/settings.segments/_tree.segment.rsc +2 -2
  145. package/.next/server/app/settings.segments/settings/__PAGE__.segment.rsc +4 -4
  146. package/.next/server/app/settings.segments/settings.segment.rsc +3 -3
  147. package/.next/server/app/tasks/[id]/page/build-manifest.json +3 -3
  148. package/.next/server/app/tasks/[id]/page.js.nft.json +1 -1
  149. package/.next/server/app/tasks/[id]/page_client-reference-manifest.js +1 -1
  150. package/.next/server/app/tasks/page/build-manifest.json +3 -3
  151. package/.next/server/app/tasks/page.js.nft.json +1 -1
  152. package/.next/server/app/tasks/page_client-reference-manifest.js +1 -1
  153. package/.next/server/app/tasks.html +2 -2
  154. package/.next/server/app/tasks.rsc +14 -14
  155. package/.next/server/app/tasks.segments/_full.segment.rsc +14 -14
  156. package/.next/server/app/tasks.segments/_head.segment.rsc +4 -4
  157. package/.next/server/app/tasks.segments/_index.segment.rsc +7 -7
  158. package/.next/server/app/tasks.segments/_tree.segment.rsc +2 -2
  159. package/.next/server/app/tasks.segments/tasks/__PAGE__.segment.rsc +4 -4
  160. package/.next/server/app/tasks.segments/tasks.segment.rsc +3 -3
  161. package/.next/server/chunks/ssr/[root-of-the-server]__013i9e9._.js +9 -0
  162. package/.next/server/chunks/ssr/[root-of-the-server]__013i9e9._.js.map +1 -0
  163. package/.next/server/chunks/ssr/[root-of-the-server]__0_jnflc._.js +3 -0
  164. package/.next/server/chunks/ssr/[root-of-the-server]__0_jnflc._.js.map +1 -0
  165. package/.next/server/chunks/ssr/[root-of-the-server]__12mpoig._.js +3 -0
  166. package/.next/server/chunks/ssr/[root-of-the-server]__12mpoig._.js.map +1 -0
  167. package/.next/server/chunks/ssr/_0d-fuox._.js +3 -0
  168. package/.next/server/chunks/ssr/_0d-fuox._.js.map +1 -0
  169. package/.next/server/chunks/ssr/app_0.0wpa~._.js +3 -0
  170. package/.next/server/chunks/ssr/app_0.0wpa~._.js.map +1 -0
  171. package/.next/server/chunks/ssr/app_0dk5wao._.js +1 -1
  172. package/.next/server/chunks/ssr/app_0dk5wao._.js.map +1 -1
  173. package/.next/server/chunks/ssr/app_0et5yua._.js +3 -0
  174. package/.next/server/chunks/ssr/app_0et5yua._.js.map +1 -0
  175. package/.next/server/chunks/ssr/app_0ff~kjj._.js +9 -0
  176. package/.next/server/chunks/ssr/app_0ff~kjj._.js.map +1 -0
  177. package/.next/server/chunks/ssr/app_0izi28j._.js +3 -0
  178. package/.next/server/chunks/ssr/app_0izi28j._.js.map +1 -0
  179. package/.next/server/chunks/ssr/app_login_page_tsx_0z71ad3._.js +1 -1
  180. package/.next/server/chunks/ssr/app_login_page_tsx_0z71ad3._.js.map +1 -1
  181. package/.next/server/chunks/ssr/app_page_tsx_0es_sk2._.js +1 -1
  182. package/.next/server/chunks/ssr/app_page_tsx_0es_sk2._.js.map +1 -1
  183. package/.next/server/chunks/ssr/app_server-logs_page_tsx_0_kpp1p._.js +1 -1
  184. package/.next/server/chunks/ssr/app_server-logs_page_tsx_0_kpp1p._.js.map +1 -1
  185. package/.next/server/chunks/ssr/app_tasks_page_tsx_0z-d6mp._.js +1 -1
  186. package/.next/server/chunks/ssr/app_tasks_page_tsx_0z-d6mp._.js.map +1 -1
  187. package/.next/server/chunks/ssr/node_modules_0ck2~9g._.js +3 -0
  188. package/.next/server/chunks/ssr/node_modules_0ck2~9g._.js.map +1 -0
  189. package/.next/server/middleware-build-manifest.js +6 -6
  190. package/.next/server/pages/404.html +2 -2
  191. package/.next/server/pages/500.html +1 -1
  192. package/.next/server/server-reference-manifest.js +1 -1
  193. package/.next/server/server-reference-manifest.json +1 -1
  194. package/.next/static/chunks/0257pdz1-imal.js +2 -0
  195. package/.next/static/chunks/02flrewxlf_m_.js +1 -0
  196. package/.next/static/chunks/051gslfjka1kj.js +1 -0
  197. package/.next/static/chunks/06t_vzei8s9_h.js +1 -0
  198. package/.next/static/chunks/0e-.zgw81gela.js +31 -0
  199. package/.next/static/chunks/0e7c40p~wq665.js +1 -0
  200. package/.next/static/chunks/0g7m7zk.v7g6h.js +1 -0
  201. package/.next/static/chunks/0hyhubmh-__wg.js +1 -0
  202. package/.next/static/chunks/0khpyxpdrp~ty.js +1 -0
  203. package/.next/static/chunks/0lo_g.q1fm-hr.js +7 -0
  204. package/.next/static/chunks/0snd~q2ucn.h1.css +2 -0
  205. package/.next/static/chunks/0w1zwt8kq_7nb.js +1 -0
  206. package/.next/static/chunks/0xn9.0ejo1s_a.js +7 -0
  207. package/.next/static/chunks/0y0lo-~k2c~00.js +1 -0
  208. package/.next/static/chunks/10njj7kn9ylkf.js +1 -0
  209. package/.next/static/chunks/13.dst7liziwo.js +1 -0
  210. package/.next/static/chunks/{turbopack-0vsvjs02l449s.js → turbopack-01f1xs~cq_~si.js} +1 -1
  211. package/.next/trace +2 -2
  212. package/.next/trace-build +1 -1
  213. package/app/components/EmptyState.tsx +189 -0
  214. package/app/components/LoadingSkeleton.tsx +3 -18
  215. package/app/components/Sidebar.tsx +72 -11
  216. package/app/components/StatsBar.tsx +7 -1
  217. package/app/components/TopoGraph.tsx +151 -62
  218. package/app/globals.css +108 -8
  219. package/app/login/page.tsx +26 -13
  220. package/app/logs/page.tsx +24 -11
  221. package/app/messages/page.tsx +2 -5
  222. package/app/nodes/page.tsx +6 -1
  223. package/app/page.tsx +36 -12
  224. package/app/server-logs/page.tsx +22 -11
  225. package/app/settings/networks/page.tsx +6 -1
  226. package/app/settings/page.tsx +56 -29
  227. package/app/settings/tokens/page.tsx +6 -1
  228. package/app/tasks/page.tsx +7 -9
  229. package/docs/loop-design-rounds.md +502 -0
  230. package/docs/oss-readiness-report.md +189 -0
  231. package/package.json +1 -1
  232. package/.mcp.json +0 -11
  233. package/.next/server/chunks/ssr/[root-of-the-server]__093ymui._.js +0 -3
  234. package/.next/server/chunks/ssr/[root-of-the-server]__093ymui._.js.map +0 -1
  235. package/.next/server/chunks/ssr/[root-of-the-server]__0i1gizm._.js +0 -9
  236. package/.next/server/chunks/ssr/[root-of-the-server]__0i1gizm._.js.map +0 -1
  237. package/.next/server/chunks/ssr/[root-of-the-server]__0~yad5w._.js +0 -3
  238. package/.next/server/chunks/ssr/[root-of-the-server]__0~yad5w._.js.map +0 -1
  239. package/.next/server/chunks/ssr/_06_xh1~._.js +0 -3
  240. package/.next/server/chunks/ssr/_06_xh1~._.js.map +0 -1
  241. package/.next/server/chunks/ssr/app_01vhyfx._.js +0 -9
  242. package/.next/server/chunks/ssr/app_01vhyfx._.js.map +0 -1
  243. package/.next/server/chunks/ssr/app_023a94i._.js +0 -3
  244. package/.next/server/chunks/ssr/app_023a94i._.js.map +0 -1
  245. package/.next/server/chunks/ssr/app_0basiqb._.js +0 -3
  246. package/.next/server/chunks/ssr/app_0basiqb._.js.map +0 -1
  247. package/.next/server/chunks/ssr/app_0pljk5o._.js +0 -3
  248. package/.next/server/chunks/ssr/app_0pljk5o._.js.map +0 -1
  249. package/.next/server/chunks/ssr/node_modules_next_dist_0t-hj0x._.js +0 -3
  250. package/.next/server/chunks/ssr/node_modules_next_dist_0t-hj0x._.js.map +0 -1
  251. package/.next/static/chunks/0.z~9klrgd.t-.js +0 -1
  252. package/.next/static/chunks/08aj9~75raaah.js +0 -7
  253. package/.next/static/chunks/08iom_z8w-wmz.js +0 -7
  254. package/.next/static/chunks/08v0-ki6vwpxf.js +0 -1
  255. package/.next/static/chunks/0agna31q2fjq1.css +0 -2
  256. package/.next/static/chunks/0dkkv90do9a4r.js +0 -1
  257. package/.next/static/chunks/0e-wrhqh4h3r5.js +0 -2
  258. package/.next/static/chunks/0ejz4zwhu3a3y.js +0 -1
  259. package/.next/static/chunks/0o5zj~5vjeks3.js +0 -1
  260. package/.next/static/chunks/0ttvcv6~g0f6i.js +0 -1
  261. package/.next/static/chunks/0uqfv6rc-xdru.js +0 -1
  262. package/.next/static/chunks/0xrnwfefpke-g.js +0 -31
  263. package/.next/static/chunks/0y_po~f~fk~ap.js +0 -1
  264. package/.next/static/chunks/0~93h~zb55yh9.js +0 -1
  265. package/.next/static/chunks/140l7~i5q9wrv.js +0 -1
  266. package/AGENTS.md +0 -5
  267. package/DASHBOARD_OPTIMIZATION_PLAN.md +0 -414
  268. package/docs/iteration-plan.md +0 -62
  269. package/docs/v4-plan.md +0 -38
  270. /package/.next/static/{7dwKlhAm5uyghPmkAubQK → 2m1yIfZCIYDWMYrrJEKSC}/_buildManifest.js +0 -0
  271. /package/.next/static/{7dwKlhAm5uyghPmkAubQK → 2m1yIfZCIYDWMYrrJEKSC}/_clientMiddlewareManifest.js +0 -0
  272. /package/.next/static/{7dwKlhAm5uyghPmkAubQK → 2m1yIfZCIYDWMYrrJEKSC}/_ssgManifest.js +0 -0
@@ -0,0 +1,189 @@
1
+ 'use client';
2
+
3
+ import Link from 'next/link';
4
+
5
+ export type EmptyVariant = 'nodes' | 'tasks' | 'messages' | 'logs' | 'tokens' | 'networks' | 'generic';
6
+
7
+ interface EmptyStateProps {
8
+ /** Picks the icon glyph and default copy if title/sub omitted. */
9
+ variant?: EmptyVariant;
10
+ /** Optional override headline. */
11
+ title?: string;
12
+ /** Optional override sub-copy. */
13
+ sub?: string;
14
+ /** Optional CTA: text + href (internal) or onClick. */
15
+ cta?: { label: string; href?: string; onClick?: () => void };
16
+ /** Compact mode for in-card empty states (smaller padding). */
17
+ compact?: boolean;
18
+ }
19
+
20
+ const DEFAULTS: Record<EmptyVariant, { title: string; sub: string }> = {
21
+ nodes: { title: 'No agents in this network', sub: 'Agent sessions will appear here once they connect to the CommHub.' },
22
+ tasks: { title: 'No tasks yet', sub: 'Tasks will appear here when agents send them via CommHub.' },
23
+ messages: { title: 'No messages', sub: 'Messages between agents will appear here.' },
24
+ logs: { title: 'No audit logs', sub: 'Events will appear here when users register, login, or perform actions.' },
25
+ tokens: { title: 'No API tokens', sub: 'Create one to authenticate CLI tools and external integrations.' },
26
+ networks: { title: 'No networks found', sub: 'Create one or sign in with V3 auth to see your networks.' },
27
+ generic: { title: 'Nothing here yet', sub: 'Data will appear here once available.' },
28
+ };
29
+
30
+ /**
31
+ * Minimal monochrome SVG glyphs per variant. No filled shapes, no gradients,
32
+ * no AI-decoration — just thin-stroke line art that fades into the page.
33
+ * 64×64 viewBox; rendered at 56×56 (compact 40×40).
34
+ */
35
+ function Glyph({ variant, size }: { variant: EmptyVariant; size: number }) {
36
+ const s = { width: size, height: size };
37
+ const baseProps = {
38
+ fill: 'none',
39
+ stroke: 'currentColor',
40
+ strokeWidth: 1.25,
41
+ strokeLinecap: 'round' as const,
42
+ strokeLinejoin: 'round' as const,
43
+ };
44
+
45
+ switch (variant) {
46
+ case 'nodes':
47
+ // Mesh with dashed edges = "nodes will land here"
48
+ return (
49
+ <svg viewBox="0 0 64 64" {...s}>
50
+ <g {...baseProps}>
51
+ <circle cx="32" cy="14" r="4" />
52
+ <circle cx="14" cy="44" r="4" />
53
+ <circle cx="50" cy="44" r="4" />
54
+ <line x1="32" y1="18" x2="14" y2="40" strokeDasharray="3 3" opacity="0.6" />
55
+ <line x1="32" y1="18" x2="50" y2="40" strokeDasharray="3 3" opacity="0.6" />
56
+ <line x1="18" y1="44" x2="46" y2="44" strokeDasharray="3 3" opacity="0.6" />
57
+ </g>
58
+ </svg>
59
+ );
60
+ case 'tasks':
61
+ // Empty checkbox list
62
+ return (
63
+ <svg viewBox="0 0 64 64" {...s}>
64
+ <g {...baseProps}>
65
+ <rect x="14" y="14" width="36" height="6" rx="1.5" />
66
+ <rect x="14" y="26" width="36" height="6" rx="1.5" opacity="0.6" />
67
+ <rect x="14" y="38" width="36" height="6" rx="1.5" opacity="0.35" />
68
+ </g>
69
+ </svg>
70
+ );
71
+ case 'messages':
72
+ // Speech bubble outline
73
+ return (
74
+ <svg viewBox="0 0 64 64" {...s}>
75
+ <g {...baseProps}>
76
+ <path d="M14 18 h36 a3 3 0 0 1 3 3 v18 a3 3 0 0 1 -3 3 h-18 l-8 6 v-6 h-10 a3 3 0 0 1 -3 -3 v-18 a3 3 0 0 1 3 -3 z" />
77
+ <line x1="22" y1="28" x2="42" y2="28" opacity="0.5" />
78
+ <line x1="22" y1="34" x2="36" y2="34" opacity="0.5" />
79
+ </g>
80
+ </svg>
81
+ );
82
+ case 'logs':
83
+ // Document with lines
84
+ return (
85
+ <svg viewBox="0 0 64 64" {...s}>
86
+ <g {...baseProps}>
87
+ <path d="M18 12 h22 l8 8 v32 a2 2 0 0 1 -2 2 h-28 a2 2 0 0 1 -2 -2 v-38 a2 2 0 0 1 2 -2 z" />
88
+ <path d="M40 12 v8 h8" opacity="0.6" />
89
+ <line x1="24" y1="32" x2="40" y2="32" opacity="0.55" />
90
+ <line x1="24" y1="38" x2="40" y2="38" opacity="0.4" />
91
+ <line x1="24" y1="44" x2="34" y2="44" opacity="0.25" />
92
+ </g>
93
+ </svg>
94
+ );
95
+ case 'tokens':
96
+ // Key outline
97
+ return (
98
+ <svg viewBox="0 0 64 64" {...s}>
99
+ <g {...baseProps}>
100
+ <circle cx="22" cy="32" r="8" />
101
+ <line x1="30" y1="32" x2="54" y2="32" />
102
+ <line x1="44" y1="32" x2="44" y2="38" />
103
+ <line x1="50" y1="32" x2="50" y2="40" />
104
+ </g>
105
+ </svg>
106
+ );
107
+ case 'networks':
108
+ // Globe-ish concentric ovals
109
+ return (
110
+ <svg viewBox="0 0 64 64" {...s}>
111
+ <g {...baseProps}>
112
+ <circle cx="32" cy="32" r="18" />
113
+ <ellipse cx="32" cy="32" rx="18" ry="9" opacity="0.55" />
114
+ <line x1="14" y1="32" x2="50" y2="32" opacity="0.55" />
115
+ <line x1="32" y1="14" x2="32" y2="50" opacity="0.55" />
116
+ </g>
117
+ </svg>
118
+ );
119
+ case 'generic':
120
+ default:
121
+ // Soft sparkle outline
122
+ return (
123
+ <svg viewBox="0 0 64 64" {...s}>
124
+ <g {...baseProps}>
125
+ <circle cx="32" cy="32" r="14" strokeDasharray="3 3" opacity="0.6" />
126
+ <circle cx="32" cy="32" r="3" />
127
+ </g>
128
+ </svg>
129
+ );
130
+ }
131
+ }
132
+
133
+ export function EmptyState({ variant = 'generic', title, sub, cta, compact = false }: EmptyStateProps) {
134
+ const d = DEFAULTS[variant];
135
+ const headline = title ?? d.title;
136
+ const subcopy = sub ?? d.sub;
137
+ const iconSize = compact ? 40 : 56;
138
+
139
+ return (
140
+ <div className={`text-center ${compact ? 'py-8' : 'py-16'} px-4`} role="status">
141
+ <div className="anet-empty-glyph inline-flex items-center justify-center mb-4 text-gray-500" aria-hidden>
142
+ <Glyph variant={variant} size={iconSize} />
143
+ </div>
144
+ <h3 className={`font-medium text-gray-300 ${compact ? 'text-sm' : 'text-base'}`}>{headline}</h3>
145
+ {subcopy && (
146
+ <p className={`text-gray-500 ${compact ? 'text-xs mt-1.5' : 'text-sm mt-2'} max-w-md mx-auto leading-relaxed`}>
147
+ {subcopy}
148
+ </p>
149
+ )}
150
+ {cta && (
151
+ <div className="mt-4">
152
+ {cta.href ? (
153
+ <Link href={cta.href} className="inline-flex items-center gap-1.5 text-sm font-medium text-cyan-400 hover:text-cyan-300">
154
+ {cta.label}
155
+ <span aria-hidden>→</span>
156
+ </Link>
157
+ ) : (
158
+ <button onClick={cta.onClick} className="inline-flex items-center gap-1.5 text-sm font-medium text-cyan-400 hover:text-cyan-300">
159
+ {cta.label}
160
+ <span aria-hidden>→</span>
161
+ </button>
162
+ )}
163
+ </div>
164
+ )}
165
+ </div>
166
+ );
167
+ }
168
+
169
+ /**
170
+ * Overview-specific variant with a hint about cross-network global count.
171
+ * Kept here so /app/page.tsx can drop in without ceremony.
172
+ */
173
+ export function NodesEmptyState({ hint }: { hint?: { global_count?: number; filtered_network?: string } }) {
174
+ if (hint?.global_count) {
175
+ return (
176
+ <EmptyState
177
+ variant="nodes"
178
+ title="No agents in this network"
179
+ sub={`Server has ${hint.global_count} nodes globally, but none are registered to the current network. Switch network or contact admin.`}
180
+ />
181
+ );
182
+ }
183
+ return (
184
+ <EmptyState
185
+ variant="nodes"
186
+ cta={{ label: 'Run anet quickstart', href: 'https://anet.sh' }}
187
+ />
188
+ );
189
+ }
@@ -45,21 +45,6 @@ export function LoadingSkeleton() {
45
45
  );
46
46
  }
47
47
 
48
- export function EmptyState({ hint }: { hint?: { global_count?: number; filtered_network?: string } }) {
49
- return (
50
- <div className="text-center py-16">
51
- <div className="text-gray-600 text-4xl mb-4">--</div>
52
- <h3 className="text-gray-400 text-lg font-medium mb-2">No agents in this network</h3>
53
- {hint?.global_count ? (
54
- <p className="text-gray-500 text-sm max-w-md mx-auto">
55
- Server has <span className="text-cyan-400 font-medium">{hint.global_count}</span> nodes globally,
56
- but none are registered to the current network. Switch network or contact admin.
57
- </p>
58
- ) : (
59
- <p className="text-gray-600 text-sm max-w-md mx-auto">
60
- Agent sessions will appear here once they connect to the CommHub.
61
- </p>
62
- )}
63
- </div>
64
- );
65
- }
48
+ // EmptyState export removed in 0.4.5 replaced by EmptyState.tsx with
49
+ // per-variant glyphs and a NodesEmptyState wrapper for the Overview
50
+ // hint-aware behavior. See app/components/EmptyState.tsx.
@@ -101,17 +101,11 @@ export function Sidebar() {
101
101
  ${mobileOpen ? 'translate-x-0' : '-translate-x-full'}
102
102
  lg:translate-x-0 lg:static lg:shrink-0
103
103
  `}>
104
- {/* Logo */}
105
- <div className={`px-4 py-5 border-b border-[#2a2a4a] ${collapsed ? 'text-center' : ''}`}>
106
- {collapsed ? (
107
- <span className="text-cyan-400 font-bold text-lg">A</span>
108
- ) : (
109
- <div>
110
- <div className="text-white font-bold text-sm">Agent Network</div>
111
- <div className="text-gray-600 text-xs">Dashboard</div>
112
- </div>
113
- )}
114
- </div>
104
+ {/* Brand header — round 4: 3-node mesh mark matches /login,
105
+ with an inline live "online" pulse so every page surfaces
106
+ fleet health without leaving for /nodes. */}
107
+ <SidebarBrand collapsed={collapsed} />
108
+ <div className={`border-b border-[#2a2a4a]`} />
115
109
 
116
110
  {/* Network list */}
117
111
  {!collapsed && networks.length > 0 && (
@@ -174,3 +168,70 @@ export function Sidebar() {
174
168
  </>
175
169
  );
176
170
  }
171
+
172
+ interface StatusData {
173
+ sessions?: Array<{ status?: string; alias?: string }>;
174
+ }
175
+
176
+ const statusFetcher = (url: string) =>
177
+ fetch(url).then(r => r.ok ? r.json() as Promise<StatusData> : { sessions: [] });
178
+
179
+ function SidebarBrand({ collapsed }: { collapsed: boolean }) {
180
+ // Live online count — re-uses the same /api/hub/status endpoint the
181
+ // Overview already polls, so SWR dedupes the request. Pulse is muted —
182
+ // emerald dot at 4px with a 1.6s slow opacity pulse, no glow, no halo.
183
+ const { data } = useSWR<StatusData>('/api/hub/status', statusFetcher, {
184
+ refreshInterval: 10000,
185
+ dedupingInterval: 4000,
186
+ });
187
+ const sessions = data?.sessions || [];
188
+ const online = sessions.filter(s => s.status && s.status !== 'offline').length;
189
+ const total = sessions.length;
190
+
191
+ if (collapsed) {
192
+ return (
193
+ <Link href="/" className="block px-3 py-4 flex justify-center hover:opacity-80 transition-opacity" aria-label="Agent Network — home">
194
+ <BrandMark size={32} />
195
+ </Link>
196
+ );
197
+ }
198
+
199
+ return (
200
+ <Link
201
+ href="/"
202
+ className="block px-4 py-4 flex items-center gap-3 hover:bg-[#11112a]/40 transition-colors rounded-r-xl"
203
+ aria-label="Agent Network — home"
204
+ >
205
+ <BrandMark size={32} />
206
+ <div className="min-w-0">
207
+ <div className="text-white text-[13px] font-semibold leading-tight">Agent Network</div>
208
+ <div className="text-[10px] text-gray-500 flex items-center gap-1.5 mt-0.5">
209
+ <span
210
+ className={`inline-block w-1.5 h-1.5 rounded-full ${online > 0 ? 'bg-emerald-400 anet-brand-pulse' : 'bg-gray-600'}`}
211
+ aria-hidden
212
+ />
213
+ {total === 0 ? (
214
+ <span>waiting for agents</span>
215
+ ) : (
216
+ <span><span className="text-gray-300 font-medium tabular-nums">{online}</span><span className="text-gray-600">/{total}</span> online</span>
217
+ )}
218
+ </div>
219
+ </div>
220
+ </Link>
221
+ );
222
+ }
223
+
224
+ /** 3-node mesh mark — same SVG as /login, reusable. */
225
+ function BrandMark({ size }: { size: number }) {
226
+ return (
227
+ <svg width={size} height={size} viewBox="0 0 32 32" aria-hidden className="shrink-0">
228
+ <circle cx="16" cy="16" r="10" fill="none" stroke="currentColor" strokeWidth="1.5" opacity="0.2" className="text-cyan-400" />
229
+ <line x1="16" y1="10" x2="10" y2="20" stroke="currentColor" strokeWidth="1" opacity="0.45" className="text-cyan-400" />
230
+ <line x1="16" y1="10" x2="22" y2="20" stroke="currentColor" strokeWidth="1" opacity="0.45" className="text-cyan-400" />
231
+ <line x1="10" y1="20" x2="22" y2="20" stroke="currentColor" strokeWidth="1" opacity="0.45" className="text-cyan-400" />
232
+ <circle cx="16" cy="10" r="2.5" fill="currentColor" className="text-cyan-400" />
233
+ <circle cx="10" cy="20" r="2.5" fill="currentColor" className="text-green-400" />
234
+ <circle cx="22" cy="20" r="2.5" fill="currentColor" className="text-violet-400" />
235
+ </svg>
236
+ );
237
+ }
@@ -63,8 +63,14 @@ export function StatsBar({ online, working, total, version, uptime }: StatsBarPr
63
63
  function StatCard({ value, label, sub, color, accent, border }: {
64
64
  value: number; label: string; sub: string; color: string; accent: string; border: string;
65
65
  }) {
66
+ // Extract the color family (green/cyan/gray/blue/white) from `color` prop
67
+ // so the light-theme top-strip CSS can pick the right accent.
68
+ const accentKey = color.replace('text-', '').split('-')[0];
66
69
  return (
67
- <div className={`relative overflow-hidden rounded-xl border ${border} bg-[#111128] px-4 py-3`}>
70
+ <div
71
+ data-anet-stat-card={accentKey}
72
+ className={`anet-stat-card relative overflow-hidden rounded-xl border ${border} bg-[#111128] px-4 py-3 transition-all`}
73
+ >
68
74
  <div className={`absolute inset-0 bg-gradient-to-br ${accent} pointer-events-none`} />
69
75
  <div className="relative">
70
76
  <div className={`text-3xl font-bold ${color} tabular-nums leading-tight`}>{value}</div>