@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
@@ -6,6 +6,7 @@ import Link from 'next/link';
6
6
  import { useNetworkId } from '../lib/network-context';
7
7
  import { TaskDrawer } from '../components/TaskDrawer';
8
8
  import { EmptyState } from '../components/EmptyState';
9
+ import { AliasAvatar } from '../components/AliasAvatar';
9
10
 
10
11
  interface Task {
11
12
  task_id: string;
@@ -48,6 +49,21 @@ const STATUS_COLORS: Record<string, string> = {
48
49
  expired: 'bg-orange-500/10 text-orange-300 border-orange-500/20',
49
50
  };
50
51
 
52
+ /** Small colored dot per status — visible on every tab (active + inactive)
53
+ * so users can scan the row at a glance. Hex inlined to avoid Tailwind
54
+ * purging dynamic `bg-${family}-400` class names. */
55
+ const STATUS_DOTS: Record<string, string> = {
56
+ created: '#9ca3af',
57
+ delivered: '#60a5fa',
58
+ acked: '#22d3ee',
59
+ running: '#4ade80',
60
+ replied: '#a78bfa',
61
+ closed: '#6b7280',
62
+ failed: '#f87171',
63
+ cancelled: '#facc15',
64
+ expired: '#fb923c',
65
+ };
66
+
51
67
  function statusBadge(status: string) {
52
68
  const color = STATUS_COLORS[status] || 'bg-gray-500/10 text-gray-400 border-gray-500/20';
53
69
  return `text-xs px-2 py-0.5 rounded-md border ${color}`;
@@ -134,36 +150,66 @@ function TasksContent() {
134
150
  </span>
135
151
  </div>
136
152
 
137
- {/* Status Tabs */}
138
- <div className="flex flex-wrap gap-1 mb-4 bg-[#111128] rounded-lg border border-[#2a2a4a] p-1">
153
+ {/* Status Tabs — color-coded dots per status family so users can
154
+ scan the row at a glance. Active tab gets full chip styling
155
+ (bg + border + text color), inactive tabs only carry the dot
156
+ + neutral label so the active state remains the strong cue.
157
+ On narrow viewports (<sm) the row scrolls horizontally with
158
+ subtle gradient fade-edges (via .anet-tabstrip-wrap pseudo
159
+ elements) hinting more content. */}
160
+ <div className="anet-tabstrip-wrap mb-4">
161
+ <div className="anet-tabstrip flex sm:flex-wrap gap-1 bg-[#111128] rounded-lg border border-[#2a2a4a] p-1 overflow-x-auto sm:overflow-x-visible scrollbar-thin">
139
162
  {['', ...STATUS_OPTIONS.filter(Boolean)].map(s => (
140
163
  <button key={s} onClick={() => setFilterStatus(s)}
141
- className={`px-3 py-1.5 rounded-md text-xs transition-colors ${
164
+ className={`px-3 py-1.5 rounded-md text-xs transition-colors flex items-center gap-1.5 shrink-0 whitespace-nowrap ${
142
165
  filterStatus === s
143
166
  ? `${STATUS_COLORS[s] || 'bg-cyan-500/10 text-cyan-300 border-cyan-500/20'} border`
144
- : 'text-gray-500 hover:text-gray-300'
167
+ : 'text-gray-500 hover:text-gray-300 hover:bg-[#1a1a2a]/40'
145
168
  }`}>
146
- {s || 'All'}
169
+ {s && (
170
+ <span
171
+ aria-hidden
172
+ className="inline-block w-1.5 h-1.5 rounded-full shrink-0"
173
+ style={{ backgroundColor: STATUS_DOTS[s] || '#6b7280' }}
174
+ />
175
+ )}
176
+ <span>{s || 'All'}</span>
147
177
  </button>
148
178
  ))}
149
179
  </div>
180
+ </div>
150
181
 
151
- {/* From/To Filters */}
152
- <div className="flex flex-wrap gap-3 mb-6">
153
- <input
154
- type="text"
155
- value={filterFrom}
156
- onChange={e => setFilterFrom(e.target.value)}
157
- placeholder="From node..."
158
- className="bg-[#111128] border border-[#2a2a4a] rounded-lg px-3 py-2 text-sm text-white placeholder-gray-600 focus:border-blue-500/50 focus:outline-none w-40"
159
- />
160
- <input
161
- type="text"
162
- value={filterTo}
163
- onChange={e => setFilterTo(e.target.value)}
164
- placeholder="To node..."
165
- className="bg-[#111128] border border-[#2a2a4a] rounded-lg px-3 py-2 text-sm text-white placeholder-gray-600 focus:border-blue-500/50 focus:outline-none w-40"
166
- />
182
+ {/* From/To Filters — same visual block as the status tabs above. */}
183
+ <div className="flex flex-wrap items-center gap-2 mb-6">
184
+ <div className="flex items-center gap-1.5 rounded-lg border border-[#2a2a4a] bg-[#111128] px-2.5 py-1.5 focus-within:border-blue-500/40">
185
+ <span className="text-[10px] uppercase tracking-wide text-gray-600">From</span>
186
+ <input
187
+ type="text"
188
+ value={filterFrom}
189
+ onChange={e => setFilterFrom(e.target.value)}
190
+ placeholder="any node"
191
+ className="w-28 bg-transparent text-sm text-white placeholder-gray-700 focus:outline-none"
192
+ />
193
+ </div>
194
+ <div className="flex items-center gap-1.5 rounded-lg border border-[#2a2a4a] bg-[#111128] px-2.5 py-1.5 focus-within:border-blue-500/40">
195
+ <span className="text-[10px] uppercase tracking-wide text-gray-600">To</span>
196
+ <input
197
+ type="text"
198
+ value={filterTo}
199
+ onChange={e => setFilterTo(e.target.value)}
200
+ placeholder="any node"
201
+ className="w-28 bg-transparent text-sm text-white placeholder-gray-700 focus:outline-none"
202
+ />
203
+ </div>
204
+ {(filterStatus || filterFrom || filterTo) && (
205
+ <button
206
+ type="button"
207
+ onClick={() => { setFilterStatus(''); setFilterFrom(''); setFilterTo(''); }}
208
+ className="rounded-lg border border-gray-700 px-2.5 py-1.5 text-[11px] text-gray-500 hover:text-gray-200 hover:border-gray-600"
209
+ >
210
+ Clear filters
211
+ </button>
212
+ )}
167
213
  </div>
168
214
 
169
215
  {/* Status distribution */}
@@ -220,22 +266,39 @@ function TasksContent() {
220
266
  <div className="col-span-2">Time</div>
221
267
  </div>
222
268
 
223
- {tasks.map(t => (
269
+ {tasks.map(t => {
270
+ const isOpen = expanded.has(t.task_id);
271
+ return (
224
272
  <div
225
273
  key={t.task_id}
226
- className="bg-[#111128] border border-[#2a2a4a] rounded-lg px-4 py-3 hover:border-[#3a3a5a] transition-colors cursor-pointer"
274
+ className={`anet-task-row group bg-[#111128] border rounded-lg px-4 py-3 transition-all duration-200 cursor-pointer ${
275
+ isOpen
276
+ ? 'border-[#3a3a5a] shadow-lg shadow-black/20'
277
+ : 'border-[#2a2a4a] hover:border-[#3a3a5a] hover:bg-[#15152e]'
278
+ }`}
227
279
  onClick={() => toggleExpand(t.task_id)}
280
+ role="button"
281
+ tabIndex={0}
282
+ aria-expanded={isOpen}
283
+ onKeyDown={(e) => {
284
+ if (e.key === 'Enter' || e.key === ' ') {
285
+ e.preventDefault();
286
+ toggleExpand(t.task_id);
287
+ }
288
+ }}
228
289
  >
229
290
  {/* Desktop row */}
230
291
  <div className="hidden sm:grid sm:grid-cols-12 gap-2 items-center">
231
292
  <div className="col-span-1">
232
293
  <span className={statusBadge(t.status)}>{t.status}</span>
233
294
  </div>
234
- <div className="col-span-2 text-sm text-blue-400 truncate" title={t.from_name}>
235
- {t.from_name || '--'}
295
+ <div className="col-span-2 flex items-center gap-1.5 min-w-0" title={t.from_name}>
296
+ {t.from_name && <AliasAvatar alias={t.from_name} size={18} />}
297
+ <span className="truncate text-sm text-gray-200">{t.from_name || '--'}</span>
236
298
  </div>
237
- <div className="col-span-2 text-sm text-cyan-400 truncate" title={t.to_name}>
238
- {t.to_name || '--'}
299
+ <div className="col-span-2 flex items-center gap-1.5 min-w-0" title={t.to_name}>
300
+ {t.to_name && <AliasAvatar alias={t.to_name} size={18} />}
301
+ <span className="truncate text-sm text-gray-200">{t.to_name || '--'}</span>
239
302
  </div>
240
303
  <div className="col-span-4 text-xs text-gray-400 truncate" title={t.content}>
241
304
  {t.content || '--'}
@@ -243,8 +306,15 @@ function TasksContent() {
243
306
  <div className="col-span-1">
244
307
  <span className={`text-xs ${priorityBadge(t.priority)}`}>{t.priority || 'normal'}</span>
245
308
  </div>
246
- <div className="col-span-2 text-xs text-gray-500" title={t.created_at}>
247
- {timeAgo(t.created_at)}
309
+ <div className="col-span-2 text-xs text-gray-500 flex items-center justify-between gap-2" title={t.created_at}>
310
+ <span className="truncate">{timeAgo(t.created_at)}</span>
311
+ <svg
312
+ aria-hidden
313
+ className={`shrink-0 text-gray-600 group-hover:text-gray-400 transition-transform duration-200 ${isOpen ? 'rotate-180' : ''}`}
314
+ width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"
315
+ >
316
+ <path strokeLinecap="round" strokeLinejoin="round" d="M6 9l6 6 6-6" />
317
+ </svg>
248
318
  </div>
249
319
  </div>
250
320
 
@@ -252,20 +322,38 @@ function TasksContent() {
252
322
  <div className="sm:hidden space-y-2">
253
323
  <div className="flex items-center justify-between">
254
324
  <span className={statusBadge(t.status)}>{t.status}</span>
255
- <span className={`text-xs ${priorityBadge(t.priority)}`}>{t.priority || 'normal'}</span>
325
+ <div className="flex items-center gap-2">
326
+ <span className={`text-xs ${priorityBadge(t.priority)}`}>{t.priority || 'normal'}</span>
327
+ <svg
328
+ aria-hidden
329
+ className={`text-gray-600 transition-transform duration-200 ${isOpen ? 'rotate-180' : ''}`}
330
+ width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"
331
+ >
332
+ <path strokeLinecap="round" strokeLinejoin="round" d="M6 9l6 6 6-6" />
333
+ </svg>
334
+ </div>
256
335
  </div>
257
- <div className="text-xs text-gray-500">
258
- <span className="text-blue-400">{t.from_name || '--'}</span>
259
- <span className="text-gray-600 mx-1">&rarr;</span>
260
- <span className="text-cyan-400">{t.to_name || '--'}</span>
336
+ <div className="flex items-center gap-1.5 text-xs text-gray-300 min-w-0">
337
+ {t.from_name && <AliasAvatar alias={t.from_name} size={16} />}
338
+ <span className="truncate max-w-[40%]">{t.from_name || '--'}</span>
339
+ <span className="text-gray-600">&rarr;</span>
340
+ {t.to_name && <AliasAvatar alias={t.to_name} size={16} />}
341
+ <span className="truncate max-w-[40%]">{t.to_name || '--'}</span>
261
342
  </div>
262
- <div className="text-xs text-gray-400 truncate">{t.content || '--'}</div>
343
+ <div className="text-xs text-gray-400 line-clamp-1">{t.content || '--'}</div>
263
344
  <div className="text-xs text-gray-600">{timeAgo(t.created_at)}</div>
264
345
  </div>
265
346
 
266
- {/* Expanded detail */}
267
- {expanded.has(t.task_id) && (
268
- <div className="mt-3 pt-3 border-t border-[#2a2a4a] space-y-3">
347
+ {/* Expanded detail — always mounted; grid-rows 0fr↔1fr trick gives
348
+ content-aware smooth max-height animation without measuring DOM. */}
349
+ <div
350
+ className={`grid transition-all duration-300 ease-out ${
351
+ isOpen ? 'grid-rows-[1fr] opacity-100 mt-3' : 'grid-rows-[0fr] opacity-0'
352
+ }`}
353
+ aria-hidden={!isOpen}
354
+ >
355
+ <div className="overflow-hidden">
356
+ <div className="pt-3 border-t border-[#2a2a4a] space-y-3">
269
357
  {t.content && (
270
358
  <div>
271
359
  <div className="text-xs text-gray-600 mb-1">Content</div>
@@ -327,9 +415,11 @@ function TasksContent() {
327
415
  </div>
328
416
  </div>
329
417
  </div>
330
- )}
418
+ </div>
419
+ </div>
331
420
  </div>
332
- ))}
421
+ );
422
+ })}
333
423
  </div>
334
424
  )}
335
425
 
@@ -497,6 +497,301 @@ Natural ship-point. Round 8 = the publish itself:
497
497
  4. Tell 通信龙 to bump CLI preview's PINNED_DASHBOARD_VERSION
498
498
  5. Telegram Vincent: `npm i -g @sleep2agi/agent-network@preview`
499
499
 
500
- After ship, rounds 9+ accumulate toward `0.4.6-preview.0`. Backlog
501
- ideas: layout collision avoidance in TopoGraph, hover affordances on
502
- KPI cards, Cmd+K command palette, header health banner, mobile audit.
500
+ After ship, rounds 9+ accumulate toward the **next** preview in the
501
+ SAME `0.4.5-preview.N` series (Vincent's policy: don't burn base version
502
+ numbers on preview-only work). Backlog ideas: layout collision
503
+ avoidance in TopoGraph, hover affordances on KPI cards, Cmd+K command
504
+ palette, header health banner, mobile audit.
505
+
506
+ > **Version policy (round 8 + Vincent telegram)**: stable stays at
507
+ > `0.4.2` until Vincent explicitly promotes a preview. All new previews
508
+ > bump only the `-preview.N` suffix on the same `0.4.5` base. The
509
+ > `latest` npm tag never moves without sign-off.
510
+
511
+ ---
512
+
513
+ ## Round 9 — Header health banner
514
+
515
+ ### What changed
516
+ - New `app/components/HealthBanner.tsx`: thin sticky strip mounted in
517
+ `AppShell` between sidebar and page content, visible on every
518
+ non-login page.
519
+ - Three states, priority-ranked:
520
+ - **red** — `CommHub unreachable — agents may be offline` + CTA
521
+ "Open Settings →"
522
+ - **amber** — `N task(s) failed recently` + CTA "Review failures →"
523
+ (links to `/tasks?status=failed`). Dot pulses with the same 1.6s
524
+ opacity drift as the sidebar online pulse.
525
+ - **green** — `All systems go`. Quiet. No CTA. Doesn't render until
526
+ at least one stats response confirms (avoids flashing green on
527
+ first paint before data arrives).
528
+ - Pulls from `/api/hub/stats` + `/api/hub/health` via SWR (15s refresh,
529
+ 5s dedupe). Both endpoints are already polled elsewhere — request
530
+ dedupes free, banner has zero net cost.
531
+ - Dismissible per-session via `sessionStorage.anet-hb-dismissed = '1'`.
532
+ Re-shows on next session.
533
+ - Light/mint themes get bumped color saturation via `.anet-health-banner`
534
+ override rules in globals.css so red/amber/green read crisply on
535
+ white surfaces.
536
+
537
+ ### Self-score: **8.7 / 10**
538
+
539
+ | Dimension | Score | Notes |
540
+ |--------------------------|------:|------------------------------------------------------------------------|
541
+ | Information value | 9 | Fleet health visible from every page without navigating to /nodes |
542
+ | Restraint | 9 | 32px-tall strip; opacity-only pulse; no glow; auto-dismissible |
543
+ | Affordance (CTAs) | 9 | Each non-green state has a clear "fix this" link |
544
+ | Theme parity | 9 | All 3 states verified in light + cyber |
545
+ | Failure-state robustness | 8 | "Red" fires only when both `/stats` AND `/health` fail; safer than either alone |
546
+ | Mobile | 7 | Strip wraps at 390px viewport; could collapse "Review failures →" copy further |
547
+
548
+ **Deductions**:
549
+ - −0.6: on very narrow mobile (<340px) the CTA + dismiss can wrap or
550
+ overlap. Could collapse CTA to icon-only at that breakpoint.
551
+ - −0.4: red state has a single message; doesn't distinguish "hub down"
552
+ vs "auth expired" vs "network error". Future round could add error
553
+ classification.
554
+ - −0.3: dismiss is session-scoped. Some users may want
555
+ "dismiss for this session only" vs "dismiss forever". Defer.
556
+
557
+ ### Round 10 plan: **KPI card rich hover preview**
558
+
559
+ Overview's stat strip (round 3) shows top-level numbers — `Nodes 4/5`,
560
+ `Tasks 0`, `Failed 0` — but a power user wants to see the breakdown
561
+ without clicking through. Add small CSS-only popovers that appear on
562
+ hover:
563
+ - Nodes hover → "3 working · 2 idle · 0 offline"
564
+ - Tasks hover → "by status: 4 running, 2 replied, 1 failed, 0 expired"
565
+ - Failed hover → "5 in last hour · last failure 12m ago"
566
+
567
+ Pure CSS popover (no JS state), 200ms delay-show, fades out on
568
+ unhover. Both themes. Doesn't affect mobile (touch shows full card
569
+ already).
570
+
571
+ Estimated work: 25 min. Fires next `*/5`.
572
+
573
+ ---
574
+
575
+ ## Round 10 — KPI card rich hover preview
576
+
577
+ ### What changed
578
+ - The 3-stat strip on Overview (Nodes / Tasks / Failed) now gets a
579
+ **hover popover** showing the breakdown that the headline number
580
+ abstracts away.
581
+ - **Nodes** hover → `● working {n}` / `● idle {n}` / `● offline {n}`
582
+ - **Tasks** hover → list of all populated statuses in priority
583
+ order (running → replied → failed → cancelled → expired → closed
584
+ → created → delivered → acked), each with its color dot + count
585
+ - **Failed** hover → `no failures yet` or `{n} in current view`
586
+ - **Pure CSS** popover: hidden by default, `opacity-0 translate-y-[-2px]`
587
+ transitions to `opacity-100 translate-y-0` on `group-hover`. 100ms
588
+ delay-show so a quick mouse-pass doesn't flicker. No React state.
589
+ - `pointer-events-none` on the popover so it never intercepts the
590
+ click through to the underlying Link target.
591
+ - **Mobile gate**: `hidden md:block` — touch devices don't get the
592
+ popover (no `:hover`). The card itself still navigates on tap, so no
593
+ functionality lost.
594
+ - Dot colors inlined as hex (`#4ade80` green, `#a78bfa` purple, etc.)
595
+ to dodge Tailwind's purge of dynamic `bg-${family}-400` class names.
596
+
597
+ ### Self-score: **8.5 / 10**
598
+
599
+ **Deductions**: no `:focus-within` trigger (keyboard users miss
600
+ popover); "Failed" copy doesn't show time bucket; dot hex inlined
601
+ rather than centralized in a constants palette.
602
+
603
+ ### Round 11 plan: **Mobile audit + polish pass**
604
+
605
+ Nine rounds in, the desktop story is solid. Mobile hasn't gotten a
606
+ dedicated round since the initial audit. Likely findings:
607
+
608
+ - Health banner at <340px: CTA + dismiss button + truncated message
609
+ competes for ~280px usable width. Collapse CTA to icon-only or
610
+ move it below the message.
611
+ - Stat strip 3-col at 360-390px: "View →" affordance shrinks below
612
+ legibility. Either drop "View →" on mobile or stack 1-col.
613
+ - Sidebar mobile drawer: not screenshot-audited against the latest
614
+ brand-mark + pulse changes.
615
+ - Footer text spacing on /login at 320px: wraps awkwardly.
616
+
617
+ Action: capture mobile screenshots across 5-6 key pages at 390×844
618
+ AND 360×740, identify worst offenders, fix the top 3.
619
+
620
+ Estimated work: 30 min. Fires next `*/5`.
621
+
622
+ ---
623
+
624
+ ## Round 11 — Mobile audit + polish pass
625
+
626
+ ### Findings (390×844 + 360×740)
627
+ Captured 12 screenshots (6 pages × 2 themes × 2 viewports). Three
628
+ clear regressions at narrow widths:
629
+
630
+ 1. **Health banner** ran into the fixed-position hamburger button at
631
+ top-left (top:4 left:3, ~44×44 hit area). Message text was
632
+ truncated to "...sks failed recently" because the leading 6
633
+ characters sat under the hamburger.
634
+ 2. **UserBar** "Edit" + "Sign out" text links cramped against the
635
+ user name + role on narrow screens, wrapping "Sign out" onto
636
+ two lines.
637
+ 3. **Stat strip** "View →" affordance in each card's top-right took
638
+ horizontal space the headline number needed, making the 3-col
639
+ grid feel cramped at 360px.
640
+
641
+ ### What changed
642
+ - **HealthBanner**: `pl-3` → `pl-14` on mobile (clears the hamburger
643
+ button), CTA text "Review failures" / "Open Settings" collapses to
644
+ a bare arrow on `<sm` with a proper `aria-label` so screen
645
+ readers still hear the destination.
646
+ - **UserBar Edit / Sign out**: text on `>=sm`, single inline-svg icon
647
+ on `<sm` (pencil for edit, doorway-arrow for sign out). Both stay
648
+ same hit area, just label-trimmed.
649
+ - **Stat strip "View →"**: `hidden sm:block` so the affordance only
650
+ appears on desktop. Mobile cards are fully tappable, so the
651
+ affordance is implicit.
652
+
653
+ ### Self-score: **9.0 / 10**
654
+
655
+ | Dimension | Score | Notes |
656
+ |------------------------|------:|------------------------------------------------------------------|
657
+ | Defect closure | 10 | All three observed mobile regressions resolved |
658
+ | Desktop non-regression | 9 | All changes wrapped in `sm:` breakpoint — pixel-identical >640px |
659
+ | Restraint | 9 | Icons are simple line SVGs matching the design system |
660
+ | Accessibility | 9 | `aria-label` on collapsed CTAs and icon-only buttons |
661
+ | Touch target | 8 | Icons are 16px visual; full `<button>` is still 44px hit area |
662
+
663
+ **Deductions**:
664
+ - −0.5: not tested below 360px (e.g. 320px iPhone SE first-gen).
665
+ Probably still fine but unverified.
666
+ - −0.3: sidebar drawer mobile state (when hamburger is tapped) not
667
+ re-screenshotted post round-4 brand changes.
668
+ - −0.2: existing chip filter rows on Tasks/Messages still wrap at
669
+ narrow widths. Not the most painful, deferred.
670
+
671
+ ### Round 12 plan: **Loading skeleton refresh**
672
+
673
+ The `LoadingSkeleton` component in `app/components/LoadingSkeleton.tsx`
674
+ still uses `bg-gray-800` / `bg-gray-800/40` patterns from the
675
+ pre-theme-token era. It works (CSS shim catches `bg-gray-800` in
676
+ light), but it's the only surface that didn't get a deliberate
677
+ restyle. Refresh to use:
678
+ - subtle bg + animated pulse using the same `anet-brand-pulse`
679
+ rhythm (1.6s opacity drift) for visual cohesion
680
+ - proper card structure matching round 3's stat-strip shape
681
+ - both themes, no AI-noise
682
+
683
+ Estimated work: 20 min. Fires next `*/5`.
684
+
685
+ ---
686
+
687
+ ## Round 14 — Cmd+K command palette (scaffold)
688
+
689
+ ### What changed
690
+ - New `app/components/CommandPalette.tsx` mounted in `AppShell` so it's
691
+ globally available on every non-login page.
692
+ - **Keyboard shortcuts** (global, not per-page):
693
+ - `⌘K` / `Ctrl+K` toggles open/closed
694
+ - `/` opens when no input is focused (Linear-style)
695
+ - `↑↓` navigates results, `Enter` activates, `Esc` closes
696
+ - **Layout**: centered modal at 10vh-15vh from top, max-w-xl, backdrop
697
+ blur over content. Search input + grouped results + footer hint bar.
698
+ - **Initial command set**: 10 navigation entries covering every
699
+ primary page (Overview / Tasks / Failed tasks / Nodes / Messages /
700
+ Networks / Audit Log / Server Logs / Admin / Settings). Each carries
701
+ a hint subtitle and a thin-stroke icon.
702
+ - **Filter behavior**: case-insensitive search over title + hint + id.
703
+ Active row gets emerald tint + `↵` glyph; mouse hover updates the
704
+ selected index so keyboard and pointer stay in sync.
705
+ - **Light/mint surface**: white modal with real soft shadow (vs the
706
+ default `bg-[#0d0d1a]` navy that CSS shim would translate). Override
707
+ ruled in globals.css.
708
+
709
+ ### Self-score: **8.7 / 10**
710
+
711
+ | Dimension | Score | Notes |
712
+ |------------------------|------:|------------------------------------------------------------------------|
713
+ | Adoption signal | 9 | Stripe/Linear/Vercel staple — sets reader expectation that we're modern |
714
+ | Keyboard-first | 9 | All keys wired; mouse + keyboard stay in sync |
715
+ | Restraint | 9 | Mono-stroke icons, single accent color, no AI shimmer |
716
+ | Theme parity | 9 | Light gets a proper white surface w/ shadow; cyber uses navy |
717
+ | Discoverability | 7 | No visible "press ⌘K" hint anywhere on the page yet |
718
+ | Mobile | 6 | Works on mobile (tap to open via UI) — but no on-screen launcher yet |
719
+
720
+ **Deductions**:
721
+ - −0.7: zero on-page hint that the palette exists. Most users will
722
+ never find `⌘K` without docs. Should add a tiny "⌘K" badge in
723
+ sidebar footer or in the UserBar.
724
+ - −0.4: no mobile launcher. Mobile has no obvious affordance.
725
+ - −0.2: command set is navigation-only. Round 15 will add actions
726
+ (theme toggle / sign out / Dispatch open) and recent-commands.
727
+
728
+ ### Round 15 plan: **Cmd+K actions + recent-commands**
729
+
730
+ Extend the scaffold with the "Actions" group:
731
+ - Toggle theme (cyber ↔ light)
732
+ - Open Dispatch dialog (current page's Dispatch button)
733
+ - Sign out
734
+ - Copy current URL
735
+
736
+ Plus add a `Recents` group at the top that surfaces the last 3-5
737
+ commands the user invoked (ring buffer in `sessionStorage`).
738
+
739
+ Plus a discoverability nudge — tiny `⌘K` chip in sidebar footer +
740
+ UserBar tooltip.
741
+
742
+ Estimated work: 25 min. Fires next `*/5`.
743
+
744
+ ---
745
+
746
+ ## Round 12 — Loading skeleton refresh
747
+
748
+ ### What changed
749
+ - `LoadingSkeleton` now **mirrors the actual Overview layout** so the
750
+ page doesn't shift on data arrival. Old version was generic header
751
+ + broadcast + topology + 4-card grid; new version shows: 4 KPI
752
+ cards, Dispatch+UserBar row, Config bar, 3-card stat strip, 3-tile
753
+ nav rail, Broadcast bar, 4-card agent grid.
754
+ - Switched from Tailwind's `animate-pulse` (1s opacity drift) to a
755
+ custom `anet-skeleton-pulse` (1.6s) to match the same rhythm as
756
+ `anet-brand-pulse` in the sidebar and the health banner amber dot.
757
+ Visual cohesion across the design system.
758
+ - Introduced `anet-skeleton-bar` class with explicit per-theme
759
+ background: `#1a1a2a` on dark (lighter navy on dark card),
760
+ `#d4d8df` on light/mint (mid-grey on white card). The previous
761
+ attempt to reuse the `bg-[#1a1a2a]` shim was too subtle (light
762
+ card #ffffff vs bar mapped to bg-elevated #eef0f4 = only ~7
763
+ brightness levels different = invisible bars).
764
+ - All bar dimensions use rem-based explicit values via inline style
765
+ so they don't depend on Tailwind purge correctness.
766
+ - `prefers-reduced-motion: reduce` kills the pulse on both classes.
767
+
768
+ ### Self-score: **9.0 / 10**
769
+
770
+ | Dimension | Score | Notes |
771
+ |------------------------|------:|------------------------------------------------------------------|
772
+ | No content shift | 9 | Skeleton matches Overview structure cell-for-cell |
773
+ | Theme parity | 10 | Both themes get visible bars (the original sin of round 11 plan) |
774
+ | Restraint | 9 | No shimmer-gradient, no animation noise, just 1.6s opacity drift |
775
+ | Design-system cohesion | 9 | Same pulse rhythm as brand pulse + health banner amber |
776
+ | Accessibility | 9 | prefers-reduced-motion respected on both classes |
777
+
778
+ **Deductions**:
779
+ - −0.5: skeleton shows the FULL Overview (8+ blocks). Most actual
780
+ page-loads complete in <300ms so user barely sees this. Slower
781
+ hubs may see the whole thing; some users might prefer a shorter
782
+ skeleton. Could trim agent grid to 2 cards if it feels long in
783
+ practice.
784
+ - −0.5: the agent-card skeleton is generic (status dot + alias bar
785
+ + 3 detail bars). Real cards carry status chip + agent type +
786
+ server hostname + uptime — could mirror more specifically.
787
+
788
+ ### Round 13 plan: **Tasks status tabs — color coding**
789
+
790
+ The Tasks page filter tab strip (`All / created / delivered / acked /
791
+ running / replied / closed / failed / cancelled / expired`) is all
792
+ neutral-styled — no visual scannability. Color-code each by its
793
+ status family using the same tokens as the chips system used
794
+ elsewhere (running=green, replied=purple, failed=red, etc.), so the
795
+ user can spot "failed" without reading every label.
796
+
797
+ Estimated work: 20 min. Fires next `*/5`.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sleep2agi/agent-network-dashboard",
3
- "version": "0.4.5-preview.0",
3
+ "version": "0.4.5-preview.10",
4
4
  "description": "Agent Network Dashboard — Web UI for managing AI Agent networks",
5
5
  "scripts": {
6
6
  "dev": "next dev",
@@ -1,9 +0,0 @@
1
- module.exports=[18622,(a,b,c)=>{b.exports=a.x("next/dist/compiled/next-server/app-page-turbo.runtime.prod.js",()=>require("next/dist/compiled/next-server/app-page-turbo.runtime.prod.js"))},56704,(a,b,c)=>{b.exports=a.x("next/dist/server/app-render/work-async-storage.external.js",()=>require("next/dist/server/app-render/work-async-storage.external.js"))},32319,(a,b,c)=>{b.exports=a.x("next/dist/server/app-render/work-unit-async-storage.external.js",()=>require("next/dist/server/app-render/work-unit-async-storage.external.js"))},24725,(a,b,c)=>{b.exports=a.x("next/dist/server/app-render/after-task-async-storage.external.js",()=>require("next/dist/server/app-render/after-task-async-storage.external.js"))},20635,(a,b,c)=>{b.exports=a.x("next/dist/server/app-render/action-async-storage.external.js",()=>require("next/dist/server/app-render/action-async-storage.external.js"))},43285,(a,b,c)=>{b.exports=a.x("next/dist/server/app-render/dynamic-access-async-storage.external.js",()=>require("next/dist/server/app-render/dynamic-access-async-storage.external.js"))},42602,(a,b,c)=>{"use strict";b.exports=a.r(18622)},87924,(a,b,c)=>{"use strict";b.exports=a.r(42602).vendored["react-ssr"].ReactJsxRuntime},72131,(a,b,c)=>{"use strict";b.exports=a.r(42602).vendored["react-ssr"].React},9270,(a,b,c)=>{"use strict";b.exports=a.r(42602).vendored.contexts.AppRouterContext},38783,(a,b,c)=>{"use strict";b.exports=a.r(42602).vendored["react-ssr"].ReactServerDOMTurbopackClient},36313,(a,b,c)=>{"use strict";b.exports=a.r(42602).vendored.contexts.HooksClientContext},18341,(a,b,c)=>{"use strict";b.exports=a.r(42602).vendored.contexts.ServerInsertedHtml},22397,a=>{"use strict";var b=a.i(87924),c=a.i(72131);let d=(0,c.createContext)({networkId:"",setNetworkId:()=>{}});a.s(["NetworkProvider",0,function({children:a}){let[e,f]=(0,c.useState)("");return(0,c.useEffect)(()=>{let a=sessionStorage.getItem("anet_network_id");a&&f(a)},[]),(0,b.jsx)(d.Provider,{value:{networkId:e,setNetworkId:a=>{f(a),sessionStorage.setItem("anet_network_id",a)}},children:a})},"useNetworkId",0,function(){return(0,c.useContext)(d)}])},76194,a=>{"use strict";var b=a.i(87924),c=a.i(72131);let d=[{id:"cyber",label:"Cyber",emoji:"🌃",desc:"默认深色"},{id:"light",label:"Light",emoji:"☀️",desc:"浅色简洁"},{id:"mint",label:"Mint",emoji:"🌿",desc:"薄荷绿"},{id:"sunset",label:"Sunset",emoji:"🌅",desc:"暖色橙紫"}],e="anet-theme";function f(a){"u">typeof document&&document.documentElement.setAttribute("data-theme",a)}a.s(["ThemeProvider",0,function({children:a}){return(0,c.useEffect)(()=>{f(localStorage.getItem(e)||"cyber")},[]),(0,b.jsx)(b.Fragment,{children:a})},"ThemeSwitcher",0,function({compact:a=!1}){let[g,h]=(0,c.useState)("cyber"),[i,j]=(0,c.useState)(!1);(0,c.useEffect)(()=>{let a=localStorage.getItem(e)||"cyber";h(a),f(a)},[]);let k=d.find(a=>a.id===g)||d[0];return(0,b.jsxs)("div",{className:"relative",children:[(0,b.jsxs)("button",{"aria-label":"切换主题",onClick:()=>j(!i),className:"px-2.5 py-1.5 rounded-md text-xs flex items-center gap-1.5 hover:opacity-80 transition-opacity",style:{background:"var(--bg-elevated)",color:"var(--fg)",border:"1px solid var(--border)"},children:[(0,b.jsx)("span",{"aria-hidden":!0,children:k.emoji}),!a&&(0,b.jsx)("span",{children:k.label})]}),i&&(0,b.jsxs)(b.Fragment,{children:[(0,b.jsx)("div",{className:"fixed inset-0 z-40",onClick:()=>j(!1)}),(0,b.jsx)("div",{className:"absolute right-0 top-full mt-1 z-50 rounded-md min-w-[160px] py-1 shadow-lg",style:{background:"var(--bg-secondary)",border:"1px solid var(--border)"},children:d.map(a=>(0,b.jsxs)("button",{onClick:()=>{var b;h(b=a.id),localStorage.setItem(e,b),f(b),j(!1)},className:"w-full px-3 py-2 text-left text-xs flex items-center gap-2 hover:opacity-80",style:{background:a.id===g?"var(--bg-elevated)":"transparent",color:"var(--fg)"},children:[(0,b.jsx)("span",{"aria-hidden":!0,children:a.emoji}),(0,b.jsx)("span",{className:"flex-1",children:a.label}),(0,b.jsx)("span",{style:{color:"var(--fg-dim)"},className:"text-[10px]",children:a.desc}),a.id===g&&(0,b.jsx)("span",{style:{color:"var(--accent)"},children:"•"})]},a.id))})]})]})}])},42588,a=>{"use strict";var b=a.i(87924),c=a.i(50944),d=a.i(38246),e=a.i(72131),f=a.i(72596),g=a.i(22397),h=a.i(76194);let i=a=>fetch(a).then(a=>a.ok?a.json():{networks:[]}),j=[{href:"/",label:"Overview",icon:"M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6"},{href:"/tasks",label:"Tasks",icon:"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"},{href:"/nodes",label:"Nodes",icon:"M5 12h14M5 12a2 2 0 01-2-2V6a2 2 0 012-2h14a2 2 0 012 2v4a2 2 0 01-2 2M5 12a2 2 0 00-2 2v4a2 2 0 002 2h14a2 2 0 002-2v-4a2 2 0 00-2-2m-2-4h.01M17 16h.01"},{href:"/messages",label:"Messages",icon:"M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z"},{href:"/settings/networks",label:"Networks",icon:"M21 12a9 9 0 01-9 9m9-9a9 9 0 00-9-9m9 9H3m9 9a9 9 0 01-9-9m9 9c1.657 0 3-4.03 3-9s-1.343-9-3-9m0 18c-1.657 0-3-4.03-3-9s1.343-9 3-9m-9 9a9 9 0 019-9"},{href:"/logs",label:"Audit Log",icon:"M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"},{href:"/server-logs",label:"Server Logs",icon:"M8 9l3 3-3 3m5 0h3M5 20h14a2 2 0 002-2V6a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z"},{href:"/admin",label:"Admin",icon:"M12 4.354a4 4 0 110 5.292M15 21H3v-1a6 6 0 0112 0v1zm0 0h6v-1a6 6 0 00-9-5.197M13 7a4 4 0 11-8 0 4 4 0 018 0z"},{href:"/settings",label:"Settings",icon:"M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.066 2.573c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.573 1.066c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.066-2.573c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z M15 12a3 3 0 11-6 0 3 3 0 016 0z"}],k={owner:"⭐",admin:"🔧",member:"👤",viewer:"👁"};function l(){let a=(0,c.usePathname)(),[l,m]=(0,e.useState)(!1),[o,p]=(0,e.useState)(!1),{networkId:q,setNetworkId:r}=(0,g.useNetworkId)(),{data:s}=(0,f.default)("/api/hub/networks",i,{refreshInterval:15e3,dedupingInterval:1e4}),t=s?.networks||[],u=(0,b.jsx)("nav",{className:"flex flex-col gap-1 px-2 py-4",children:j.map(c=>{var e;return(0,b.jsxs)(d.default,{href:c.href,prefetch:!1,onClick:()=>p(!1),className:`relative flex items-center gap-3 px-3 py-3 rounded-lg text-sm transition-colors active:bg-[#1a1a3a] ${("/"===(e=c.href)?"/"===a:"/settings"===e?"/settings"===a:a.startsWith(e))?"bg-cyan-500/10 text-cyan-300 border border-cyan-500/20 anet-nav-active":"text-gray-400 hover:text-gray-200 hover:bg-[#1a1a2a]"} ${l?"justify-center":""}`,children:[(0,b.jsx)("svg",{className:"w-5 h-5 shrink-0",fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",strokeWidth:1.5,children:(0,b.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",d:c.icon})}),!l&&(0,b.jsx)("span",{children:c.label})]},c.href)})});return(0,b.jsxs)(b.Fragment,{children:[(0,b.jsx)("button",{onClick:()=>p(!o),className:"fixed top-4 left-3 z-50 lg:hidden bg-[#111128] border border-[#2a2a4a] rounded-lg p-2.5 text-gray-400 hover:text-white active:bg-[#1a1a3a]","aria-label":"Toggle menu",children:(0,b.jsx)("svg",{className:"w-5 h-5",fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",strokeWidth:2,children:o?(0,b.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M6 18L18 6M6 6l12 12"}):(0,b.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M4 6h16M4 12h16M4 18h16"})})}),o&&(0,b.jsx)("div",{className:"fixed inset-0 bg-black/50 z-30 lg:hidden",onClick:()=>p(!1)}),(0,b.jsxs)("aside",{"data-anet-sidebar":"true",className:`
2
- fixed top-0 left-0 h-full z-40 bg-[#0d0d1a] border-r border-[#2a2a4a]
3
- transition-all duration-200
4
- ${l?"w-16":"w-52"}
5
- ${o?"translate-x-0":"-translate-x-full"}
6
- lg:translate-x-0 lg:static lg:shrink-0
7
- `,children:[(0,b.jsx)(n,{collapsed:l}),(0,b.jsx)("div",{className:"border-b border-[#2a2a4a]"}),!l&&t.length>0&&(0,b.jsxs)("div",{className:"px-2 py-3 border-b border-[#2a2a4a]",children:[(0,b.jsx)("div",{className:"px-3 text-[10px] text-gray-600 uppercase mb-2",children:"Networks"}),(0,b.jsx)("div",{className:"space-y-0.5 max-h-32 overflow-y-auto",children:t.map(a=>(0,b.jsxs)("button",{onClick:()=>{r(a.network_id),p(!1)},className:`w-full flex items-center gap-2 px-3 py-1.5 rounded-md text-xs transition-colors text-left ${q===a.network_id?"bg-cyan-500/10 text-cyan-300":"text-gray-500 hover:text-gray-300 hover:bg-[#1a1a2a]"}`,children:[(0,b.jsx)("span",{children:k[a.role||"member"]||"👤"}),(0,b.jsx)("span",{className:"truncate",children:a.network_name})]},a.network_id))})]}),(0,b.jsx)("div",{className:"pb-20",children:u}),(0,b.jsxs)("div",{className:"absolute bottom-0 left-0 right-0 border-t border-[#2a2a4a] bg-[#0d0d1a]",children:[!l&&(0,b.jsxs)("button",{onClick:async()=>{await fetch("/api/auth/logout",{method:"POST"}).catch(()=>{}),sessionStorage.removeItem("anet_v3_auth"),window.location.assign("/login")},className:"w-full flex items-center gap-3 px-5 py-3 text-xs text-gray-500 hover:text-red-400 hover:bg-red-500/5 transition-colors",children:[(0,b.jsx)("svg",{className:"w-4 h-4",fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",strokeWidth:1.5,children:(0,b.jsx)("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"})}),"Sign out"]}),(0,b.jsxs)("div",{className:`flex items-center gap-2 px-3 py-2 ${l?"justify-center":"justify-between"}`,children:[(0,b.jsx)(h.ThemeSwitcher,{compact:l}),(0,b.jsx)("button",{onClick:()=>m(!l),className:"hidden lg:flex p-1.5 rounded text-gray-600 hover:text-gray-400 transition-colors","aria-label":l?"Expand sidebar":"Collapse sidebar",children:(0,b.jsx)("svg",{className:`w-4 h-4 transition-transform ${l?"rotate-180":""}`,fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",strokeWidth:2,children:(0,b.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M15 19l-7-7 7-7"})})})]})]})]})]})}let m=a=>fetch(a).then(a=>a.ok?a.json():{sessions:[]});function n({collapsed:a}){let{data:c}=(0,f.default)("/api/hub/status",m,{refreshInterval:1e4,dedupingInterval:4e3}),e=c?.sessions||[],g=e.filter(a=>a.status&&"offline"!==a.status).length,h=e.length;return a?(0,b.jsx)(d.default,{href:"/",className:"block px-3 py-4 flex justify-center hover:opacity-80 transition-opacity","aria-label":"Agent Network — home",children:(0,b.jsx)(o,{size:32})}):(0,b.jsxs)(d.default,{href:"/",className:"block px-4 py-4 flex items-center gap-3 hover:bg-[#11112a]/40 transition-colors rounded-r-xl","aria-label":"Agent Network — home",children:[(0,b.jsx)(o,{size:32}),(0,b.jsxs)("div",{className:"min-w-0",children:[(0,b.jsx)("div",{className:"text-white text-[13px] font-semibold leading-tight",children:"Agent Network"}),(0,b.jsxs)("div",{className:"text-[10px] text-gray-500 flex items-center gap-1.5 mt-0.5",children:[(0,b.jsx)("span",{className:`inline-block w-1.5 h-1.5 rounded-full ${g>0?"bg-emerald-400 anet-brand-pulse":"bg-gray-600"}`,"aria-hidden":!0}),0===h?(0,b.jsx)("span",{children:"waiting for agents"}):(0,b.jsxs)("span",{children:[(0,b.jsx)("span",{className:"text-gray-300 font-medium tabular-nums",children:g}),(0,b.jsxs)("span",{className:"text-gray-600",children:["/",h]})," online"]})]})]})]})}function o({size:a}){return(0,b.jsxs)("svg",{width:a,height:a,viewBox:"0 0 32 32","aria-hidden":!0,className:"shrink-0",children:[(0,b.jsx)("circle",{cx:"16",cy:"16",r:"10",fill:"none",stroke:"currentColor",strokeWidth:"1.5",opacity:"0.2",className:"text-cyan-400"}),(0,b.jsx)("line",{x1:"16",y1:"10",x2:"10",y2:"20",stroke:"currentColor",strokeWidth:"1",opacity:"0.45",className:"text-cyan-400"}),(0,b.jsx)("line",{x1:"16",y1:"10",x2:"22",y2:"20",stroke:"currentColor",strokeWidth:"1",opacity:"0.45",className:"text-cyan-400"}),(0,b.jsx)("line",{x1:"10",y1:"20",x2:"22",y2:"20",stroke:"currentColor",strokeWidth:"1",opacity:"0.45",className:"text-cyan-400"}),(0,b.jsx)("circle",{cx:"16",cy:"10",r:"2.5",fill:"currentColor",className:"text-cyan-400"}),(0,b.jsx)("circle",{cx:"10",cy:"20",r:"2.5",fill:"currentColor",className:"text-green-400"}),(0,b.jsx)("circle",{cx:"22",cy:"20",r:"2.5",fill:"currentColor",className:"text-violet-400"})]})}let p=["/login"];a.s(["AppShell",0,function({children:a}){let d=(0,c.usePathname)();return p.includes(d)?(0,b.jsx)(b.Fragment,{children:a}):(0,b.jsxs)("div",{className:"flex min-h-screen",children:[(0,b.jsx)(l,{}),(0,b.jsx)("main",{className:"flex-1 min-w-0",children:a})]})}],42588)}];
8
-
9
- //# sourceMappingURL=%5Broot-of-the-server%5D__013i9e9._.js.map