@sleep2agi/agent-network-dashboard 0.5.3 → 0.5.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 (496) hide show
  1. package/.next/BUILD_ID +1 -1
  2. package/.next/app-path-routes-manifest.json +2 -0
  3. package/.next/build-manifest.json +3 -3
  4. package/.next/diagnostics/route-bundle-stats.json +37 -37
  5. package/.next/fallback-build-manifest.json +3 -3
  6. package/.next/prerender-manifest.json +29 -0
  7. package/.next/routes-manifest.json +12 -0
  8. package/.next/server/app/_global-error.html +1 -1
  9. package/.next/server/app/_global-error.rsc +2 -2
  10. package/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  11. package/.next/server/app/_global-error.segments/_full.segment.rsc +2 -2
  12. package/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  13. package/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  14. package/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  15. package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  16. package/.next/server/app/_not-found.html +3 -3
  17. package/.next/server/app/_not-found.rsc +14 -14
  18. package/.next/server/app/_not-found.segments/_full.segment.rsc +14 -14
  19. package/.next/server/app/_not-found.segments/_head.segment.rsc +4 -4
  20. package/.next/server/app/_not-found.segments/_index.segment.rsc +7 -7
  21. package/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +2 -2
  22. package/.next/server/app/_not-found.segments/_not-found.segment.rsc +3 -3
  23. package/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  24. package/.next/server/app/admin/page_client-reference-manifest.js +1 -1
  25. package/.next/server/app/admin.html +3 -3
  26. package/.next/server/app/admin.rsc +16 -16
  27. package/.next/server/app/admin.segments/_full.segment.rsc +16 -16
  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/api/hub/upload/route/app-paths-manifest.json +3 -0
  34. package/.next/server/app/api/hub/upload/route/build-manifest.json +9 -0
  35. package/.next/server/app/api/hub/upload/route/server-reference-manifest.json +4 -0
  36. package/.next/server/app/api/hub/upload/route.js +7 -0
  37. package/.next/server/app/api/hub/upload/route.js.map +5 -0
  38. package/.next/server/app/api/hub/upload/route.js.nft.json +1 -0
  39. package/.next/server/app/api/hub/upload/route_client-reference-manifest.js +3 -0
  40. package/.next/server/app/index.html +3 -3
  41. package/.next/server/app/index.rsc +16 -16
  42. package/.next/server/app/index.segments/__PAGE__.segment.rsc +4 -4
  43. package/.next/server/app/index.segments/_full.segment.rsc +16 -16
  44. package/.next/server/app/index.segments/_head.segment.rsc +4 -4
  45. package/.next/server/app/index.segments/_index.segment.rsc +7 -7
  46. package/.next/server/app/index.segments/_tree.segment.rsc +2 -2
  47. package/.next/server/app/login/page_client-reference-manifest.js +1 -1
  48. package/.next/server/app/login.html +2 -2
  49. package/.next/server/app/login.rsc +16 -16
  50. package/.next/server/app/login.segments/_full.segment.rsc +16 -16
  51. package/.next/server/app/login.segments/_head.segment.rsc +4 -4
  52. package/.next/server/app/login.segments/_index.segment.rsc +7 -7
  53. package/.next/server/app/login.segments/_tree.segment.rsc +2 -2
  54. package/.next/server/app/login.segments/login/__PAGE__.segment.rsc +4 -4
  55. package/.next/server/app/login.segments/login.segment.rsc +3 -3
  56. package/.next/server/app/logs/page_client-reference-manifest.js +1 -1
  57. package/.next/server/app/logs.html +3 -3
  58. package/.next/server/app/logs.rsc +16 -16
  59. package/.next/server/app/logs.segments/_full.segment.rsc +16 -16
  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/manifest.webmanifest/route/app-paths-manifest.json +3 -0
  66. package/.next/server/app/manifest.webmanifest/route/build-manifest.json +9 -0
  67. package/.next/server/app/manifest.webmanifest/route/server-reference-manifest.json +4 -0
  68. package/.next/server/app/manifest.webmanifest/route.js +8 -0
  69. package/.next/server/app/manifest.webmanifest/route.js.map +5 -0
  70. package/.next/server/app/manifest.webmanifest/route.js.nft.json +1 -0
  71. package/.next/server/app/manifest.webmanifest/route_client-reference-manifest.js +3 -0
  72. package/.next/server/app/manifest.webmanifest.body +1 -0
  73. package/.next/server/app/manifest.webmanifest.meta +1 -0
  74. package/.next/server/app/messages/page_client-reference-manifest.js +1 -1
  75. package/.next/server/app/messages.html +3 -3
  76. package/.next/server/app/messages.rsc +16 -16
  77. package/.next/server/app/messages.segments/_full.segment.rsc +16 -16
  78. package/.next/server/app/messages.segments/_head.segment.rsc +4 -4
  79. package/.next/server/app/messages.segments/_index.segment.rsc +7 -7
  80. package/.next/server/app/messages.segments/_tree.segment.rsc +2 -2
  81. package/.next/server/app/messages.segments/messages/__PAGE__.segment.rsc +4 -4
  82. package/.next/server/app/messages.segments/messages.segment.rsc +3 -3
  83. package/.next/server/app/node/page_client-reference-manifest.js +1 -1
  84. package/.next/server/app/node.html +3 -3
  85. package/.next/server/app/node.rsc +16 -16
  86. package/.next/server/app/node.segments/_full.segment.rsc +16 -16
  87. package/.next/server/app/node.segments/_head.segment.rsc +4 -4
  88. package/.next/server/app/node.segments/_index.segment.rsc +7 -7
  89. package/.next/server/app/node.segments/_tree.segment.rsc +2 -2
  90. package/.next/server/app/node.segments/node/__PAGE__.segment.rsc +4 -4
  91. package/.next/server/app/node.segments/node.segment.rsc +3 -3
  92. package/.next/server/app/nodes/page_client-reference-manifest.js +1 -1
  93. package/.next/server/app/nodes.html +3 -3
  94. package/.next/server/app/nodes.rsc +16 -16
  95. package/.next/server/app/nodes.segments/_full.segment.rsc +16 -16
  96. package/.next/server/app/nodes.segments/_head.segment.rsc +4 -4
  97. package/.next/server/app/nodes.segments/_index.segment.rsc +7 -7
  98. package/.next/server/app/nodes.segments/_tree.segment.rsc +2 -2
  99. package/.next/server/app/nodes.segments/nodes/__PAGE__.segment.rsc +4 -4
  100. package/.next/server/app/nodes.segments/nodes.segment.rsc +3 -3
  101. package/.next/server/app/page_client-reference-manifest.js +1 -1
  102. package/.next/server/app/server-logs/page_client-reference-manifest.js +1 -1
  103. package/.next/server/app/server-logs.html +3 -3
  104. package/.next/server/app/server-logs.rsc +16 -16
  105. package/.next/server/app/server-logs.segments/_full.segment.rsc +16 -16
  106. package/.next/server/app/server-logs.segments/_head.segment.rsc +4 -4
  107. package/.next/server/app/server-logs.segments/_index.segment.rsc +7 -7
  108. package/.next/server/app/server-logs.segments/_tree.segment.rsc +2 -2
  109. package/.next/server/app/server-logs.segments/server-logs/__PAGE__.segment.rsc +4 -4
  110. package/.next/server/app/server-logs.segments/server-logs.segment.rsc +3 -3
  111. package/.next/server/app/settings/networks/page_client-reference-manifest.js +1 -1
  112. package/.next/server/app/settings/networks.html +3 -3
  113. package/.next/server/app/settings/networks.rsc +16 -16
  114. package/.next/server/app/settings/networks.segments/_full.segment.rsc +16 -16
  115. package/.next/server/app/settings/networks.segments/_head.segment.rsc +4 -4
  116. package/.next/server/app/settings/networks.segments/_index.segment.rsc +7 -7
  117. package/.next/server/app/settings/networks.segments/_tree.segment.rsc +2 -2
  118. package/.next/server/app/settings/networks.segments/settings/networks/__PAGE__.segment.rsc +4 -4
  119. package/.next/server/app/settings/networks.segments/settings/networks.segment.rsc +3 -3
  120. package/.next/server/app/settings/networks.segments/settings.segment.rsc +3 -3
  121. package/.next/server/app/settings/page_client-reference-manifest.js +1 -1
  122. package/.next/server/app/settings/tokens/page_client-reference-manifest.js +1 -1
  123. package/.next/server/app/settings/tokens.html +3 -3
  124. package/.next/server/app/settings/tokens.rsc +16 -16
  125. package/.next/server/app/settings/tokens.segments/_full.segment.rsc +16 -16
  126. package/.next/server/app/settings/tokens.segments/_head.segment.rsc +4 -4
  127. package/.next/server/app/settings/tokens.segments/_index.segment.rsc +7 -7
  128. package/.next/server/app/settings/tokens.segments/_tree.segment.rsc +2 -2
  129. package/.next/server/app/settings/tokens.segments/settings/tokens/__PAGE__.segment.rsc +4 -4
  130. package/.next/server/app/settings/tokens.segments/settings/tokens.segment.rsc +3 -3
  131. package/.next/server/app/settings/tokens.segments/settings.segment.rsc +3 -3
  132. package/.next/server/app/settings.html +3 -3
  133. package/.next/server/app/settings.rsc +16 -16
  134. package/.next/server/app/settings.segments/_full.segment.rsc +16 -16
  135. package/.next/server/app/settings.segments/_head.segment.rsc +4 -4
  136. package/.next/server/app/settings.segments/_index.segment.rsc +7 -7
  137. package/.next/server/app/settings.segments/_tree.segment.rsc +2 -2
  138. package/.next/server/app/settings.segments/settings/__PAGE__.segment.rsc +4 -4
  139. package/.next/server/app/settings.segments/settings.segment.rsc +3 -3
  140. package/.next/server/app/tasks/[id]/page_client-reference-manifest.js +1 -1
  141. package/.next/server/app/tasks/page_client-reference-manifest.js +1 -1
  142. package/.next/server/app/tasks.html +3 -3
  143. package/.next/server/app/tasks.rsc +16 -16
  144. package/.next/server/app/tasks.segments/_full.segment.rsc +16 -16
  145. package/.next/server/app/tasks.segments/_head.segment.rsc +4 -4
  146. package/.next/server/app/tasks.segments/_index.segment.rsc +7 -7
  147. package/.next/server/app/tasks.segments/_tree.segment.rsc +2 -2
  148. package/.next/server/app/tasks.segments/tasks/__PAGE__.segment.rsc +4 -4
  149. package/.next/server/app/tasks.segments/tasks.segment.rsc +3 -3
  150. package/.next/server/app-paths-manifest.json +2 -0
  151. package/.next/server/chunks/00jm_next_dist_0ju_ux9._.js +18 -0
  152. package/.next/server/chunks/00jm_next_dist_0ju_ux9._.js.map +1 -0
  153. package/.next/server/chunks/0ykm__next-internal_server_app_api_hub_upload_route_actions_03_eqnf.js +3 -0
  154. package/.next/server/chunks/0ykm__next-internal_server_app_manifest_webmanifest_route_actions_0m16rb8.js +3 -0
  155. package/.next/server/chunks/0ykm__next-internal_server_app_manifest_webmanifest_route_actions_0m16rb8.js.map +1 -0
  156. package/.next/server/chunks/{[externals]__11vad82._.js → [externals]__036g1.i._.js} +2 -2
  157. package/.next/server/chunks/[externals]__036g1.i._.js.map +1 -0
  158. package/.next/server/chunks/[root-of-the-server]__0-8_f0o._.js +3 -0
  159. package/.next/server/chunks/[root-of-the-server]__0-8_f0o._.js.map +1 -0
  160. package/.next/server/chunks/{[root-of-the-server]__08uyvdq._.js → [root-of-the-server]__0jndzts._.js} +2 -2
  161. package/.next/server/chunks/{[root-of-the-server]__08uyvdq._.js.map → [root-of-the-server]__0jndzts._.js.map} +1 -1
  162. package/.next/server/chunks/[root-of-the-server]__0mxw4vb._.js +1 -1
  163. package/.next/server/chunks/[root-of-the-server]__0mxw4vb._.js.map +1 -1
  164. package/.next/server/chunks/[root-of-the-server]__0tx8s8i._.js +1 -1
  165. package/.next/server/chunks/[root-of-the-server]__0tx8s8i._.js.map +1 -1
  166. package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_0..ddwm.js +1 -1
  167. package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_0..ddwm.js.map +1 -1
  168. package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_02bxi6j.js +1 -1
  169. package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_02bxi6j.js.map +1 -1
  170. package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_05oassd.js +1 -1
  171. package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_05oassd.js.map +1 -1
  172. package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_05vxtby.js +1 -1
  173. package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_05vxtby.js.map +1 -1
  174. package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_05~eml4.js +1 -1
  175. package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_05~eml4.js.map +1 -1
  176. package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_0_-g_q2.js +1 -1
  177. package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_0_-g_q2.js.map +1 -1
  178. package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_0_ec0xu.js +1 -1
  179. package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_0_ec0xu.js.map +1 -1
  180. package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_0czb6wz.js +1 -1
  181. package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_0czb6wz.js.map +1 -1
  182. package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_0e-cn.p.js +1 -1
  183. package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_0e-cn.p.js.map +1 -1
  184. package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_0k8_sr8.js +1 -1
  185. package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_0k8_sr8.js.map +1 -1
  186. package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_0lt_3bw.js +1 -1
  187. package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_0lt_3bw.js.map +1 -1
  188. package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_0uyh3yt.js +1 -1
  189. package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_0uyh3yt.js.map +1 -1
  190. package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_0v-a2ps.js +1 -1
  191. package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_0v-a2ps.js.map +1 -1
  192. package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_12.4r9~.js +1 -1
  193. package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_12.4r9~.js.map +1 -1
  194. package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_13mqkay.js +1 -1
  195. package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_13mqkay.js.map +1 -1
  196. package/.next/server/chunks/ssr/[root-of-the-server]__030vg4n._.js +4 -1
  197. package/.next/server/chunks/ssr/[root-of-the-server]__030vg4n._.js.map +1 -1
  198. package/.next/server/chunks/ssr/[root-of-the-server]__0nw~zhp._.js +1 -1
  199. package/.next/server/chunks/ssr/[root-of-the-server]__0nw~zhp._.js.map +1 -1
  200. package/.next/server/chunks/ssr/[root-of-the-server]__0sv~g.o._.js +1 -1
  201. package/.next/server/chunks/ssr/[root-of-the-server]__0sv~g.o._.js.map +1 -1
  202. package/.next/server/chunks/ssr/[root-of-the-server]__0u5aqkk._.js +1 -1
  203. package/.next/server/chunks/ssr/[root-of-the-server]__0u5aqkk._.js.map +1 -1
  204. package/.next/server/chunks/ssr/agent-network-dashboard_09kk21a._.js +4 -4
  205. package/.next/server/chunks/ssr/agent-network-dashboard_09kk21a._.js.map +1 -1
  206. package/.next/server/chunks/ssr/agent-network-dashboard_app_01jhlxz._.js +1 -1
  207. package/.next/server/chunks/ssr/agent-network-dashboard_app_01jhlxz._.js.map +1 -1
  208. package/.next/server/chunks/ssr/agent-network-dashboard_app_09d29my._.js +1 -1
  209. package/.next/server/chunks/ssr/agent-network-dashboard_app_09d29my._.js.map +1 -1
  210. package/.next/server/chunks/ssr/agent-network-dashboard_app_components_0mvyi-4._.js +1 -1
  211. package/.next/server/chunks/ssr/agent-network-dashboard_app_components_0mvyi-4._.js.map +1 -1
  212. package/.next/server/chunks/ssr/agent-network-dashboard_app_tasks_page_tsx_0mwxy4z._.js +1 -1
  213. package/.next/server/chunks/ssr/agent-network-dashboard_app_tasks_page_tsx_0mwxy4z._.js.map +1 -1
  214. package/.next/server/middleware-build-manifest.js +3 -3
  215. package/.next/server/middleware.js +2 -2
  216. package/.next/server/middleware.js.nft.json +1 -1
  217. package/.next/server/pages/404.html +3 -3
  218. package/.next/server/pages/500.html +1 -1
  219. package/.next/static/chunks/{07~8sx3_5uiox.js → 0csnc6nlttr5s.js} +4 -1
  220. package/.next/static/chunks/0grmy4z.ylqtd.css +2 -0
  221. package/.next/static/chunks/0k68tvhf0o-sb.js +1 -0
  222. package/.next/static/chunks/{0v4-5tng.uh.7.js → 0lc4e9o91uv.n.js} +2 -2
  223. package/.next/static/chunks/0prdn66k~zu45.js +1 -0
  224. package/.next/static/chunks/{0ph1in3421~o-.js → 0qvb.hq86qp2g.js} +1 -1
  225. package/.next/static/chunks/0wyjrc0bekhiz.js +1 -0
  226. package/.next/static/chunks/0~ykmap37nw9d.js +1 -0
  227. package/.next/static/chunks/17r9h6cx1w6q-.js +4 -0
  228. package/.next/trace +2 -2
  229. package/.next/trace-build +1 -1
  230. package/.next/types/routes.d.ts +2 -1
  231. package/.next/types/validator.ts +9 -0
  232. package/app/api/hub/send/route.ts +11 -2
  233. package/app/api/hub/servers/route.ts +3 -29
  234. package/app/api/hub/upload/route.ts +83 -0
  235. package/app/components/AppShell.tsx +4 -2
  236. package/app/components/CommandCenter.tsx +1 -1
  237. package/app/components/DispatchPanel.tsx +1 -1
  238. package/app/components/MobileNav.tsx +58 -0
  239. package/app/components/TaskChatPanel.tsx +209 -30
  240. package/app/components/TaskDrawer.tsx +1 -1
  241. package/app/components/TopoGraph.tsx +6686 -248
  242. package/app/globals.css +897 -7
  243. package/app/layout.tsx +8 -2
  244. package/app/lib/serverDedupe.ts +122 -0
  245. package/app/lib/vendorIdentity.ts +74 -56
  246. package/app/manifest.ts +23 -0
  247. package/app/nodes/page.tsx +21 -151
  248. package/package.json +4 -4
  249. package/public/vendors/claude.svg +7 -8
  250. package/public/vendors/minimax.svg +8 -9
  251. package/public/vendors/openai.svg +8 -10
  252. package/scripts/p157-rc2-dedup-test.mjs +110 -0
  253. package/scripts/topo-a11y-titles-catalog-test.mjs +132 -0
  254. package/scripts/topo-active-chrome-hover-text-test.mjs +107 -0
  255. package/scripts/topo-active-links-chip-halo-layers-test.mjs +81 -0
  256. package/scripts/topo-alias-chat-brightness-test.mjs +79 -0
  257. package/scripts/topo-alias-text-halo-layers-test.mjs +98 -0
  258. package/scripts/topo-animation-temporal-modes-catalog-test.mjs +144 -0
  259. package/scripts/topo-avatar-chat-gate-test.mjs +77 -0
  260. package/scripts/topo-avatar-drop-shadow-test.mjs +86 -0
  261. package/scripts/topo-avatar-fallback-hover-test.mjs +104 -0
  262. package/scripts/topo-avatar-fallback-rotate-test.mjs +92 -0
  263. package/scripts/topo-avatar-rotate-test.mjs +85 -0
  264. package/scripts/topo-avatar-scale-test.mjs +89 -0
  265. package/scripts/topo-badge-chat-gate-test.mjs +74 -0
  266. package/scripts/topo-brand-drop-shadow-test.mjs +71 -0
  267. package/scripts/topo-brand-logo-breath-test.mjs +102 -0
  268. package/scripts/topo-brand-logo-halo-layers-test.mjs +85 -0
  269. package/scripts/topo-brand-logo-hover-brightness-test.mjs +105 -0
  270. package/scripts/topo-brand-logo-hover-rotate-test.mjs +93 -0
  271. package/scripts/topo-brand-logo-hover-test.mjs +85 -0
  272. package/scripts/topo-canvas-desc-a11y-test.mjs +87 -0
  273. package/scripts/topo-canvas-entrance-animation-test.mjs +117 -0
  274. package/scripts/topo-canvas-scan-beam-diagonal-test.mjs +148 -0
  275. package/scripts/topo-canvas-scan-beam-test.mjs +109 -0
  276. package/scripts/topo-canvas-scan-beam-vertical-test.mjs +123 -0
  277. package/scripts/topo-card-chat-brightness-test.mjs +86 -0
  278. package/scripts/topo-chat-ring-breath-curve-test.mjs +114 -0
  279. package/scripts/topo-chat-ring-brightness-test.mjs +80 -0
  280. package/scripts/topo-chat-ring-halo-layers-test.mjs +100 -0
  281. package/scripts/topo-chat-ring-r-breath-test.mjs +121 -0
  282. package/scripts/topo-chat-ring-status-halo-test.mjs +106 -0
  283. package/scripts/topo-chat-ring-sw-breath-test.mjs +123 -0
  284. package/scripts/topo-chip-pin-halo-test.mjs +85 -0
  285. package/scripts/topo-chip-row-digit-ls-test.mjs +135 -0
  286. package/scripts/topo-chip-row-member-alias-lit-test.mjs +154 -0
  287. package/scripts/topo-chip-row-tier-glow-brightness-test.mjs +99 -0
  288. package/scripts/topo-chip-row-unit-hover-tracking-test.mjs +124 -0
  289. package/scripts/topo-chrome-control-halo-layers-test.mjs +22 -0
  290. package/scripts/topo-chrome-fullscreen-breath-test.mjs +121 -0
  291. package/scripts/topo-chrome-layout-trailer-breath-test.mjs +86 -0
  292. package/scripts/topo-chrome-nodesize-trailer-breath-test.mjs +86 -0
  293. package/scripts/topo-chrome-reset-breath-test.mjs +115 -0
  294. package/scripts/topo-chrome-strip-entrance-animation-test.mjs +115 -0
  295. package/scripts/topo-chrome-wrapper-halo-test.mjs +83 -0
  296. package/scripts/topo-chrome-zoom-wrapper-breath-test.mjs +85 -0
  297. package/scripts/topo-click-ripple-glow-test.mjs +86 -0
  298. package/scripts/topo-click-ripple-halo-layers-test.mjs +79 -0
  299. package/scripts/topo-click-ripple-sw-test.mjs +110 -0
  300. package/scripts/topo-cluster-count-attr-test.mjs +80 -0
  301. package/scripts/topo-crescent-breath-test.mjs +104 -0
  302. package/scripts/topo-crescent-envelope-breath-test.mjs +103 -0
  303. package/scripts/topo-crescent-recede-test.mjs +111 -0
  304. package/scripts/topo-dense-alias-chat-halo-test.mjs +73 -0
  305. package/scripts/topo-dense-alias-halo-layers-test.mjs +80 -0
  306. package/scripts/topo-dual-axis-surfaces-catalog-test.mjs +94 -0
  307. package/scripts/topo-edge-badge-circle-brightness-test.mjs +82 -0
  308. package/scripts/topo-edge-badge-circle-hot-pulse-test.mjs +100 -0
  309. package/scripts/topo-edge-badge-digit-halo-layers-test.mjs +107 -0
  310. package/scripts/topo-edge-badge-endpoint-gate-test.mjs +94 -0
  311. package/scripts/topo-edge-badge-halo-layers-test.mjs +85 -0
  312. package/scripts/topo-edge-badge-hot-pulse-test.mjs +92 -0
  313. package/scripts/topo-edge-badge-hover-glow-test.mjs +90 -0
  314. package/scripts/topo-edge-badge-text-brightness-test.mjs +83 -0
  315. package/scripts/topo-edge-chat-gate-test.mjs +71 -0
  316. package/scripts/topo-edge-flow-rail-halo-layers-test.mjs +89 -0
  317. package/scripts/topo-edge-particle-brightness-test.mjs +82 -0
  318. package/scripts/topo-edge-particle-halo-layers-test.mjs +91 -0
  319. package/scripts/topo-edge-pill-glow-test.mjs +67 -0
  320. package/scripts/topo-edge-pin-halo-test.mjs +99 -0
  321. package/scripts/topo-edge-visible-brightness-test.mjs +84 -0
  322. package/scripts/topo-edge-visible-halo-layers-test.mjs +87 -0
  323. package/scripts/topo-endpoint-ring-brightness-test.mjs +83 -0
  324. package/scripts/topo-endpoint-ring-flow-halo-test.mjs +107 -0
  325. package/scripts/topo-endpoint-ring-halo-layers-test.mjs +100 -0
  326. package/scripts/topo-filter-pill-glow-test.mjs +90 -0
  327. package/scripts/topo-filter-pill-halo-layers-test.mjs +27 -0
  328. package/scripts/topo-flow-arrow-brightness-test.mjs +82 -0
  329. package/scripts/topo-flow-rail-brightness-test.mjs +80 -0
  330. package/scripts/topo-fullscreen-attr-test.mjs +73 -0
  331. package/scripts/topo-fullscreen-brightness-test.mjs +84 -0
  332. package/scripts/topo-fullscreen-icon-rotate-test.mjs +93 -0
  333. package/scripts/topo-grid-content-bottom-attr-test.mjs +72 -0
  334. package/scripts/topo-group-box-brightness-test.mjs +84 -0
  335. package/scripts/topo-group-box-halo-layers-test.mjs +91 -0
  336. package/scripts/topo-group-chat-gate-test.mjs +77 -0
  337. package/scripts/topo-group-label-brightness-test.mjs +84 -0
  338. package/scripts/topo-group-label-halo-layers-test.mjs +78 -0
  339. package/scripts/topo-group-label-hover-glow-test.mjs +86 -0
  340. package/scripts/topo-group-label-member-alias-hover-test.mjs +125 -0
  341. package/scripts/topo-group-pill-glow-test.mjs +76 -0
  342. package/scripts/topo-group-tint-brightness-test.mjs +82 -0
  343. package/scripts/topo-h2-dual-axis-breath-test.mjs +92 -0
  344. package/scripts/topo-h2-triple-axis-breath-test.mjs +142 -0
  345. package/scripts/topo-halo-chat-gate-test.mjs +72 -0
  346. package/scripts/topo-hover-detail-halo-test.mjs +76 -0
  347. package/scripts/topo-hub-a11y-title-test.mjs +95 -0
  348. package/scripts/topo-hub-core-brightness-test.mjs +82 -0
  349. package/scripts/topo-hub-core-halo-layers-test.mjs +81 -0
  350. package/scripts/topo-hub-digit-brightness-test.mjs +79 -0
  351. package/scripts/topo-hub-digit-halo-layers-test.mjs +76 -0
  352. package/scripts/topo-hub-digit-ls-test.mjs +119 -0
  353. package/scripts/topo-hub-halo-brightness-test.mjs +80 -0
  354. package/scripts/topo-hub-halo-glow-test.mjs +96 -0
  355. package/scripts/topo-hub-halo-halo-layers-test.mjs +76 -0
  356. package/scripts/topo-hub-highlight-brightness-test.mjs +84 -0
  357. package/scripts/topo-hub-highlight-glow-test.mjs +99 -0
  358. package/scripts/topo-hub-highlight-halo-layers-test.mjs +78 -0
  359. package/scripts/topo-hub-highlight-r-test.mjs +112 -0
  360. package/scripts/topo-hub-hover-ring-brightness-test.mjs +79 -0
  361. package/scripts/topo-hub-hover-ring-glow-test.mjs +97 -0
  362. package/scripts/topo-hub-hover-ring-halo-layers-test.mjs +71 -0
  363. package/scripts/topo-hub-spoke-brightness-test.mjs +77 -0
  364. package/scripts/topo-hub-spoke-glow-test.mjs +112 -0
  365. package/scripts/topo-hub-spoke-halo-layers-test.mjs +97 -0
  366. package/scripts/topo-hub-spoke-self-filter-test.mjs +119 -0
  367. package/scripts/topo-kicker-breath-test.mjs +100 -0
  368. package/scripts/topo-kicker-dual-axis-breath-test.mjs +81 -0
  369. package/scripts/topo-kicker-halo-layers-test.mjs +82 -0
  370. package/scripts/topo-kicker-triple-axis-breath-test.mjs +124 -0
  371. package/scripts/topo-label-card-brightness-test.mjs +81 -0
  372. package/scripts/topo-layout-hover-fw-test.mjs +98 -0
  373. package/scripts/topo-layout-toggle-brightness-test.mjs +94 -0
  374. package/scripts/topo-layout-toggle-halo-layers-test.mjs +95 -0
  375. package/scripts/topo-legend-count-brightness-test.mjs +80 -0
  376. package/scripts/topo-legend-count-halo-layers-test.mjs +79 -0
  377. package/scripts/topo-legend-count-letter-spacing-test.mjs +108 -0
  378. package/scripts/topo-legend-label-fw-test.mjs +107 -0
  379. package/scripts/topo-legend-panel-title-breath-test.mjs +86 -0
  380. package/scripts/topo-legend-pin-ring-brightness-test.mjs +82 -0
  381. package/scripts/topo-legend-pin-ring-halo-layers-test.mjs +71 -0
  382. package/scripts/topo-legend-row-count-brightness-test.mjs +85 -0
  383. package/scripts/topo-legend-row-label-glow-test.mjs +102 -0
  384. package/scripts/topo-legend-swatch-glow-test.mjs +109 -0
  385. package/scripts/topo-legend-swatch-member-alias-match-test.mjs +139 -0
  386. package/scripts/topo-legend-tint-brightness-test.mjs +83 -0
  387. package/scripts/topo-legend-trio-halo-layers-test.mjs +22 -0
  388. package/scripts/topo-live-lanes.mjs +48 -0
  389. package/scripts/topo-minimap-container-halo-test.mjs +82 -0
  390. package/scripts/topo-minimap-dot-chat-gate-test.mjs +81 -0
  391. package/scripts/topo-minimap-hover-glow-test.mjs +109 -0
  392. package/scripts/topo-minimap-viewport-brightness-test.mjs +84 -0
  393. package/scripts/topo-minimap-viewport-halo-layers-test.mjs +24 -0
  394. package/scripts/topo-more-footer-brightness-test.mjs +94 -0
  395. package/scripts/topo-node-alias-brightness-test.mjs +84 -0
  396. package/scripts/topo-node-avatar-halo-layers-test.mjs +25 -0
  397. package/scripts/topo-node-hover-ring-halo-layers-test.mjs +70 -0
  398. package/scripts/topo-node-label-card-halo-test.mjs +76 -0
  399. package/scripts/topo-node-sub-text-brightness-test.mjs +88 -0
  400. package/scripts/topo-nodesize-brightness-test.mjs +82 -0
  401. package/scripts/topo-nodesize-halo-layers-test.mjs +89 -0
  402. package/scripts/topo-nodesize-hover-fw-test.mjs +99 -0
  403. package/scripts/topo-orphan-label-opacity-test.mjs +98 -0
  404. package/scripts/topo-overlap-test.mjs +22 -8
  405. package/scripts/topo-panel-count-halo-layers-test.mjs +91 -0
  406. package/scripts/topo-panel-count-hover-ls-test.mjs +87 -0
  407. package/scripts/topo-panel-rect-halo-test.mjs +90 -0
  408. package/scripts/topo-panel-row-brightness-test.mjs +116 -0
  409. package/scripts/topo-panel-title-brightness-test.mjs +98 -0
  410. package/scripts/topo-panel-title-glow-test.mjs +111 -0
  411. package/scripts/topo-panel-titles-dual-axis-breath-test.mjs +94 -0
  412. package/scripts/topo-panel-titles-halo-layers-test.mjs +23 -0
  413. package/scripts/topo-panel-titles-triple-axis-breath-test.mjs +161 -0
  414. package/scripts/topo-pill-x-rotate-test.mjs +96 -0
  415. package/scripts/topo-pip-brightness-test.mjs +85 -0
  416. package/scripts/topo-pressure-bar-halo-layers-test.mjs +19 -0
  417. package/scripts/topo-pressure-seg-glow-test.mjs +92 -0
  418. package/scripts/topo-pressure-seg-member-alias-match-test.mjs +133 -0
  419. package/scripts/topo-pressure-seg-motion-test.mjs +101 -0
  420. package/scripts/topo-r717-scan-beam-pair-pattern-test.mjs +100 -0
  421. package/scripts/topo-r717-triple-axis-pair-pattern-test.mjs +113 -0
  422. package/scripts/topo-r717-triple-axis-tier-pattern-test.mjs +117 -0
  423. package/scripts/topo-recent-count-brightness-test.mjs +84 -0
  424. package/scripts/topo-recent-more-fw-test.mjs +126 -0
  425. package/scripts/topo-recent-more-halo-layers-test.mjs +90 -0
  426. package/scripts/topo-recent-panel-hot-pulse-test.mjs +105 -0
  427. package/scripts/topo-recent-panel-title-breath-test.mjs +91 -0
  428. package/scripts/topo-recent-pip-halo-layers-test.mjs +82 -0
  429. package/scripts/topo-recent-row-chat-gate-test.mjs +75 -0
  430. package/scripts/topo-recent-row-content-lift-test.mjs +140 -0
  431. package/scripts/topo-recent-row-fw-test.mjs +115 -0
  432. package/scripts/topo-recent-row-text-glow-test.mjs +86 -0
  433. package/scripts/topo-recent-row-text-halo-layers-test.mjs +67 -0
  434. package/scripts/topo-recent-tint-brightness-test.mjs +80 -0
  435. package/scripts/topo-recent-ts-brightness-test.mjs +86 -0
  436. package/scripts/topo-reduced-motion-attr-test.mjs +69 -0
  437. package/scripts/topo-reset-brightness-test.mjs +83 -0
  438. package/scripts/topo-reset-icon-hover-scale-test.mjs +102 -0
  439. package/scripts/topo-respiratory-axis-count-stats-test.mjs +154 -0
  440. package/scripts/topo-respiratory-patterns-catalog-test.mjs +112 -0
  441. package/scripts/topo-respiratory-rolodex-test.mjs +83 -0
  442. package/scripts/topo-respiratory-tiers-catalog-test.mjs +119 -0
  443. package/scripts/topo-respiratory-triple-axis-surfaces-catalog-test.mjs +127 -0
  444. package/scripts/topo-runtime-badge-brightness-test.mjs +78 -0
  445. package/scripts/topo-runtime-badge-glow-test.mjs +108 -0
  446. package/scripts/topo-runtime-badge-halo-layers-test.mjs +87 -0
  447. package/scripts/topo-runtime-badge-rotate-test.mjs +85 -0
  448. package/scripts/topo-section-title-breath-test.mjs +83 -0
  449. package/scripts/topo-section-title-halo-layers-test.mjs +88 -0
  450. package/scripts/topo-spoke-chat-gate-test.mjs +72 -0
  451. package/scripts/topo-starfield-hue-test.mjs +109 -0
  452. package/scripts/topo-status-pin-pill-halo-layers-test.mjs +17 -0
  453. package/scripts/topo-status-ring-brightness-test.mjs +84 -0
  454. package/scripts/topo-status-ring-chat-gate-test.mjs +72 -0
  455. package/scripts/topo-status-ring-halo-layers-test.mjs +105 -0
  456. package/scripts/topo-status-ring-status-halo-test.mjs +110 -0
  457. package/scripts/topo-sub-text-chat-brightness-test.mjs +81 -0
  458. package/scripts/topo-svg-title-a11y-r731-test.mjs +93 -0
  459. package/scripts/topo-svg-title-a11y-test.mjs +88 -0
  460. package/scripts/topo-title-block-entrance-animation-test.mjs +127 -0
  461. package/scripts/topo-title-block-envelope-breath-test.mjs +87 -0
  462. package/scripts/topo-titleblock-h2-hover-fw-test.mjs +109 -0
  463. package/scripts/topo-titleblock-h2-hover-tracking-test.mjs +128 -0
  464. package/scripts/topo-titleblock-kicker-hover-test.mjs +134 -0
  465. package/scripts/topo-tree-diag.mjs +95 -0
  466. package/scripts/topo-vendor-chip-glow-test.mjs +97 -0
  467. package/scripts/topo-vendor-chip-halo-layers-test.mjs +18 -0
  468. package/scripts/topo-vendor-chip-pin-halo-test.mjs +88 -0
  469. package/scripts/topo-vendor-count-suffix-halo-layers-test.mjs +79 -0
  470. package/scripts/topo-vendor-distribution-wrapper-halo-test.mjs +93 -0
  471. package/scripts/topo-vendor-letter-halo-layers-test.mjs +93 -0
  472. package/scripts/topo-vendor-pill-glow-test.mjs +98 -0
  473. package/scripts/topo-watermark-breath-test.mjs +100 -0
  474. package/scripts/topo-watermark-dual-axis-breath-test.mjs +88 -0
  475. package/scripts/topo-watermark-envelope-breath-test.mjs +88 -0
  476. package/scripts/topo-watermark-recede-test.mjs +114 -0
  477. package/scripts/topo-watermark-triple-axis-breath-test.mjs +129 -0
  478. package/scripts/topo-working-online-chip-halo-layers-test.mjs +94 -0
  479. package/scripts/topo-zoom-buttons-brightness-test.mjs +94 -0
  480. package/scripts/topo-zoom-in-out-halo-layers-test.mjs +97 -0
  481. package/scripts/topo-zoom-level-breath-test.mjs +87 -0
  482. package/scripts/topo-zoom-level-brightness-test.mjs +83 -0
  483. package/scripts/topo-zoom-level-color-test.mjs +105 -0
  484. package/scripts/topo-zoom-level-dual-axis-breath-test.mjs +83 -0
  485. package/scripts/topo-zoom-level-halo-layers-test.mjs +78 -0
  486. package/scripts/topo-zoom-level-triple-axis-breath-test.mjs +148 -0
  487. package/.next/static/chunks/01lmbsd37fybu.js +0 -1
  488. package/.next/static/chunks/03o.h6kvmw4l_.js +0 -1
  489. package/.next/static/chunks/0fuba20p57-zo.js +0 -1
  490. package/.next/static/chunks/0m.1mvl~t.avc.css +0 -2
  491. package/.next/static/chunks/10cj-86disers.js +0 -1
  492. package/.next/static/chunks/158h2g7f-nxbt.js +0 -4
  493. /package/.next/server/chunks/{[externals]__11vad82._.js.map → 0ykm__next-internal_server_app_api_hub_upload_route_actions_03_eqnf.js.map} +0 -0
  494. /package/.next/static/{tQ1EtcEiS7ikgAoAyZWm7 → 7CjN6e7QM2eogH8RhsM1k}/_buildManifest.js +0 -0
  495. /package/.next/static/{tQ1EtcEiS7ikgAoAyZWm7 → 7CjN6e7QM2eogH8RhsM1k}/_clientMiddlewareManifest.js +0 -0
  496. /package/.next/static/{tQ1EtcEiS7ikgAoAyZWm7 → 7CjN6e7QM2eogH8RhsM1k}/_ssgManifest.js +0 -0
package/app/layout.tsx CHANGED
@@ -13,6 +13,12 @@ const geistMono = Geist_Mono({
13
13
  export const metadata: Metadata = {
14
14
  title: "Agent Network Dashboard",
15
15
  description: "Real-time monitoring dashboard for Agent Network nodes via CommHub",
16
+ manifest: "/manifest.webmanifest",
17
+ appleWebApp: {
18
+ capable: true,
19
+ statusBarStyle: "black-translucent",
20
+ title: "Agent Network",
21
+ },
16
22
  icons: { icon: '/favicon.svg' },
17
23
  openGraph: {
18
24
  title: "Agent Network Dashboard",
@@ -24,8 +30,8 @@ export const metadata: Metadata = {
24
30
  export const viewport: Viewport = {
25
31
  width: "device-width",
26
32
  initialScale: 1,
27
- maximumScale: 1,
28
- userScalable: false,
33
+ maximumScale: 5,
34
+ userScalable: true,
29
35
  themeColor: "#0a0a1a",
30
36
  };
31
37
 
@@ -0,0 +1,122 @@
1
+ /**
2
+ * #157 RC#2 — host telemetry row dedup for the Servers panel.
3
+ *
4
+ * The CommHub /api/servers endpoint keys host telemetry by (hostname,
5
+ * ip): a machine whose agents report over more than one interface
6
+ * yields one row per IP. Live data caught `iZrj93pr2rcf5r2y9uo1oyZ`
7
+ * twice — once at the Docker-bridge IP (carrying cpu/mem telemetry)
8
+ * and once at loopback (telemetry null) — so the panel showed the same
9
+ * physical host as two cards with split agent counts.
10
+ *
11
+ * Extracted from the /api/hub/servers route handler so the merge can
12
+ * be unit-tested against a mock fixture independently of the proxy.
13
+ */
14
+
15
+ export interface HubServerRow {
16
+ hostname: string;
17
+ ip?: string | null;
18
+ agent_count?: number;
19
+ cpu_load_1min?: number | null;
20
+ cpu_cores?: number | null;
21
+ mem_used_gb?: number | null;
22
+ mem_total_gb?: number | null;
23
+ mem_avail_gb?: number | null;
24
+ disk_used_gb?: number | null;
25
+ disk_total_gb?: number | null;
26
+ cpu_history?: number[];
27
+ mem_history?: number[];
28
+ agents?: unknown[];
29
+ last_seen?: string | null;
30
+ status?: 'online' | 'offline';
31
+ note?: string;
32
+ }
33
+
34
+ /**
35
+ * Parse a hub timestamp to epoch ms. CommHub reports last_seen as
36
+ * "YYYY-MM-DD HH:MM:SS" (space-separated, no timezone) — treat as UTC
37
+ * so all clients agree regardless of local zone. ISO 8601 with an
38
+ * explicit offset also parses cleanly (the +'Z' is only appended when
39
+ * no zone is present). Returns NaN for missing / unparseable input.
40
+ */
41
+ export function parseHubTime(ts: string | null | undefined): number {
42
+ if (!ts) return NaN;
43
+ const iso = ts.includes('T') ? ts : ts.replace(' ', 'T');
44
+ const withTz = /[zZ]|[+-]\d{2}:?\d{2}$/.test(iso) ? iso : iso + 'Z';
45
+ return Date.parse(withTz);
46
+ }
47
+
48
+ /**
49
+ * Collapse rows that share a hostname into one card.
50
+ *
51
+ * Dedup keys on hostname, not IP: a hostname is the machine identity,
52
+ * whereas an IP can be shared across hosts behind NAT (two distinct
53
+ * hostnames can surface as the same public IP) or differ per interface
54
+ * on one host. Merge rule for a multi-row hostname:
55
+ * - agent_count = sum across rows (one host's total fan-out)
56
+ * - telemetry = freshest-non-null per field — walk rows newest
57
+ * last_seen first, take the first row that actually
58
+ * reports each field, so a stale-but-telemetried row
59
+ * still contributes cpu/mem when the freshest row's
60
+ * values are null
61
+ * - last_seen = newest across rows
62
+ * - agents[] = union, dedup by alias
63
+ *
64
+ * Sentinel hostnames that are not real identities — empty or the
65
+ * literal "unknown" the hub emits when an agent never resolved its
66
+ * host — are passed through untouched: merging two distinct unknown
67
+ * machines into one card would be worse than showing both.
68
+ */
69
+ export function dedupeByHostname(rows: HubServerRow[]): HubServerRow[] {
70
+ const groups = new Map<string, HubServerRow[]>();
71
+ const passthrough: HubServerRow[] = [];
72
+ for (const row of rows) {
73
+ const h = row.hostname;
74
+ if (!h || h === 'unknown') { passthrough.push(row); continue; }
75
+ const bucket = groups.get(h) ?? [];
76
+ bucket.push(row);
77
+ groups.set(h, bucket);
78
+ }
79
+ const merged: HubServerRow[] = [];
80
+ for (const bucket of groups.values()) {
81
+ if (bucket.length === 1) { merged.push(bucket[0]); continue; }
82
+ // Freshest last_seen first. NaN (missing timestamp) sorts last.
83
+ const sorted = [...bucket].sort((a, b) => {
84
+ const ta = parseHubTime(a.last_seen), tb = parseHubTime(b.last_seen);
85
+ return (Number.isNaN(tb) ? -Infinity : tb) - (Number.isNaN(ta) ? -Infinity : ta);
86
+ });
87
+ const coalesce = <K extends keyof HubServerRow>(key: K): HubServerRow[K] | undefined => {
88
+ for (const r of sorted) {
89
+ const v = r[key];
90
+ if (v != null) return v;
91
+ }
92
+ return undefined;
93
+ };
94
+ const agentMap = new Map<string, unknown>();
95
+ for (const r of sorted) {
96
+ if (!Array.isArray(r.agents)) continue;
97
+ for (const a of r.agents) {
98
+ const key = (a as { alias?: string })?.alias ?? JSON.stringify(a);
99
+ if (!agentMap.has(key)) agentMap.set(key, a);
100
+ }
101
+ }
102
+ merged.push({
103
+ hostname: sorted[0].hostname,
104
+ ip: coalesce('ip') ?? null,
105
+ agent_count: bucket.reduce((sum, r) => sum + (r.agent_count ?? 0), 0),
106
+ cpu_load_1min: coalesce('cpu_load_1min') ?? null,
107
+ cpu_cores: coalesce('cpu_cores') ?? null,
108
+ mem_used_gb: coalesce('mem_used_gb') ?? null,
109
+ mem_total_gb: coalesce('mem_total_gb') ?? null,
110
+ mem_avail_gb: coalesce('mem_avail_gb') ?? null,
111
+ disk_used_gb: coalesce('disk_used_gb') ?? null,
112
+ disk_total_gb: coalesce('disk_total_gb') ?? null,
113
+ cpu_history: coalesce('cpu_history'),
114
+ mem_history: coalesce('mem_history'),
115
+ agents: agentMap.size > 0 ? [...agentMap.values()] : undefined,
116
+ last_seen: coalesce('last_seen') ?? null,
117
+ status: coalesce('status'),
118
+ note: coalesce('note'),
119
+ });
120
+ }
121
+ return [...merged, ...passthrough];
122
+ }
@@ -33,70 +33,88 @@ const UNKNOWN_VENDOR: VendorIdentity = {
33
33
  logo: null,
34
34
  };
35
35
 
36
+ // Vendor identities, named so both the model-prefix rules and the
37
+ // runtime fallback map below can reference the same object.
38
+ const INTERN_VENDOR: VendorIdentity = {
39
+ id: 'intern',
40
+ label: '书生 · 上海 AI 实验室',
41
+ mono: { bg: 'hsl(28 38% 24%)', ring: 'hsl(32 45% 52%)', text: 'hsl(34 60% 82%)' },
42
+ initial: '书',
43
+ // #79 shipped this asset — reuse it as the 书生 vendor logo.
44
+ logo: '/intern_avatar.png',
45
+ };
46
+ const MINIMAX_VENDOR: VendorIdentity = {
47
+ id: 'minimax',
48
+ label: 'MiniMax',
49
+ mono: { bg: 'hsl(18 50% 26%)', ring: 'hsl(18 65% 52%)', text: 'hsl(20 80% 82%)' },
50
+ initial: 'M',
51
+ // Official MiniMax mark (simple-icons set, CC0) on a warm-red tinted
52
+ // badge. Vincent-authorized 2026-05-21 to use real vendor marks.
53
+ logo: '/vendors/minimax.svg',
54
+ };
55
+ const ANTHROPIC_VENDOR: VendorIdentity = {
56
+ id: 'anthropic',
57
+ label: 'Anthropic',
58
+ mono: { bg: 'hsl(16 32% 26%)', ring: 'hsl(16 48% 54%)', text: 'hsl(18 60% 84%)' },
59
+ initial: 'A',
60
+ // Official Anthropic mark (simple-icons set, CC0) on a warm-orange
61
+ // tinted badge. Vincent-authorized 2026-05-21 to use real vendor marks.
62
+ logo: '/vendors/claude.svg',
63
+ };
64
+ const OPENAI_VENDOR: VendorIdentity = {
65
+ id: 'openai',
66
+ label: 'OpenAI',
67
+ mono: { bg: 'hsl(165 26% 22%)', ring: 'hsl(165 40% 44%)', text: 'hsl(165 45% 80%)' },
68
+ initial: 'O',
69
+ // Official OpenAI mark (simple-icons set, CC0) on a teal tinted
70
+ // badge. Vincent-authorized 2026-05-21 to use real vendor marks.
71
+ logo: '/vendors/openai.svg',
72
+ };
73
+
36
74
  // Ordered prefix rules — first match wins. `test` runs against a lowercased
37
75
  // model id. Keep the most specific prefixes first.
38
76
  const VENDOR_RULES: Array<{ test: (m: string) => boolean; vendor: VendorIdentity }> = [
39
- {
40
- test: (m) => m.startsWith('intern'),
41
- vendor: {
42
- id: 'intern',
43
- label: '书生 · 上海 AI 实验室',
44
- mono: { bg: 'hsl(28 38% 24%)', ring: 'hsl(32 45% 52%)', text: 'hsl(34 60% 82%)' },
45
- initial: '书',
46
- // #79 shipped this asset — reuse it as the 书生 vendor logo.
47
- logo: '/intern_avatar.png',
48
- },
49
- },
50
- {
51
- test: (m) => m.startsWith('minimax'),
52
- vendor: {
53
- id: 'minimax',
54
- label: 'MiniMax',
55
- mono: { bg: 'hsl(18 50% 26%)', ring: 'hsl(18 65% 52%)', text: 'hsl(20 80% 82%)' },
56
- initial: 'M',
57
- // P0 (Vincent 5222) custom-designed vendor badge — NOT a copy of
58
- // the MiniMax trademark; geometric min/max zigzag in their warm-
59
- // red palette. Replaces plain-letter "M" fallback.
60
- logo: '/vendors/minimax.svg',
61
- },
62
- },
63
- {
64
- test: (m) => m.startsWith('claude'),
65
- vendor: {
66
- id: 'anthropic',
67
- label: 'Anthropic',
68
- mono: { bg: 'hsl(16 32% 26%)', ring: 'hsl(16 48% 54%)', text: 'hsl(18 60% 84%)' },
69
- initial: 'A',
70
- // P0 (Vincent 5222) custom-designed vendor badge — NOT a copy of
71
- // the Anthropic trademark; 4-pointed sparkle in their warm-orange
72
- // palette evokes AI/Claude without imitating the official mark.
73
- // Real Anthropic logo still pending Vincent-direct asset OK.
74
- logo: '/vendors/claude.svg',
75
- },
76
- },
77
+ { test: (m) => m.startsWith('intern'), vendor: INTERN_VENDOR },
78
+ { test: (m) => m.startsWith('minimax'), vendor: MINIMAX_VENDOR },
79
+ { test: (m) => m.startsWith('claude'), vendor: ANTHROPIC_VENDOR },
77
80
  {
78
81
  test: (m) => m.startsWith('gpt') || m.startsWith('codex') || m.startsWith('o1') || m.startsWith('o3') || m.startsWith('o4'),
79
- vendor: {
80
- id: 'openai',
81
- label: 'OpenAI',
82
- mono: { bg: 'hsl(165 26% 22%)', ring: 'hsl(165 40% 44%)', text: 'hsl(165 45% 80%)' },
83
- initial: 'O',
84
- // P0 (Vincent 5222) custom-designed vendor badge — NOT a copy of
85
- // the OpenAI trademark; hexagonal frame + center dot in their
86
- // teal palette evokes geometric AI lattice without imitating the
87
- // knot. Real OpenAI logo still pending Vincent-direct asset OK.
88
- logo: '/vendors/openai.svg',
89
- },
82
+ vendor: OPENAI_VENDOR,
90
83
  },
91
84
  ];
92
85
 
93
- /** Resolve a model id to its vendor identity. `null` / unmatched → UNKNOWN. */
94
- export function vendorForModel(model: string | null | undefined): VendorIdentity {
95
- if (!model) return UNKNOWN_VENDOR;
96
- const m = model.toLowerCase();
97
- for (const rule of VENDOR_RULES) {
98
- if (rule.test(m)) return rule.vendor;
86
+ /* Runtime vendor fallback. Used only when the `model` field can't
87
+ * resolve a vendor (null or unmatched).
88
+ *
89
+ * Why this exists: live hub /api/status probe (2026-05-21) showed 62%
90
+ * of sessions report `model: null` — including ALL claude-code-cli
91
+ * nodes — so the avatar fell back to the dark "unknown vendor"
92
+ * monogram for most of the fleet. The `runtime` field, by contrast,
93
+ * is reliably populated. A claude-code-cli / claude-agent-sdk node is
94
+ * an Anthropic shell; codex-sdk is OpenAI's. Deriving the vendor from
95
+ * runtime when the model is silent lights up the vendor logo for the
96
+ * whole fleet instead of leaving it grey. The model still wins when
97
+ * present — runtime is strictly the fallback. */
98
+ const RUNTIME_VENDOR: Record<string, VendorIdentity> = {
99
+ 'claude-code-cli': ANTHROPIC_VENDOR,
100
+ 'claude-agent-sdk': ANTHROPIC_VENDOR,
101
+ 'codex-sdk': OPENAI_VENDOR,
102
+ };
103
+
104
+ /** Resolve a node's vendor identity. Model id wins; when the model is
105
+ * null or unmatched, fall back to the execution runtime. Both silent
106
+ * → UNKNOWN. */
107
+ export function vendorForModel(
108
+ model: string | null | undefined,
109
+ runtime?: string | null | undefined,
110
+ ): VendorIdentity {
111
+ if (model) {
112
+ const m = model.toLowerCase();
113
+ for (const rule of VENDOR_RULES) {
114
+ if (rule.test(m)) return rule.vendor;
115
+ }
99
116
  }
117
+ if (runtime && RUNTIME_VENDOR[runtime]) return RUNTIME_VENDOR[runtime];
100
118
  return UNKNOWN_VENDOR;
101
119
  }
102
120
 
@@ -146,7 +164,7 @@ export function runtimeIdentity(runtime: string | null | undefined): RuntimeIden
146
164
  /** Compact one-line identity for hover / detail surfaces:
147
165
  * "Anthropic · claude-opus-4 · Claude Code CLI". Pieces with no data drop. */
148
166
  export function identityLine(model: string | null | undefined, runtime: string | null | undefined): string {
149
- const v = vendorForModel(model);
167
+ const v = vendorForModel(model, runtime);
150
168
  const r = runtimeIdentity(runtime);
151
169
  const parts: string[] = [];
152
170
  if (v.id !== 'unknown') parts.push(v.label);
@@ -0,0 +1,23 @@
1
+ import type { MetadataRoute } from 'next';
2
+
3
+ export default function manifest(): MetadataRoute.Manifest {
4
+ return {
5
+ name: 'Agent Network Dashboard',
6
+ short_name: 'AgentNet',
7
+ description: 'Mobile command surface for Agent Network and CommHub',
8
+ start_url: '/',
9
+ scope: '/',
10
+ display: 'standalone',
11
+ background_color: '#0a0a1a',
12
+ theme_color: '#0a0a1a',
13
+ orientation: 'portrait',
14
+ icons: [
15
+ {
16
+ src: '/favicon.svg',
17
+ sizes: 'any',
18
+ type: 'image/svg+xml',
19
+ purpose: 'any',
20
+ },
21
+ ],
22
+ };
23
+ }
@@ -1,7 +1,6 @@
1
1
  'use client';
2
2
 
3
3
  import { useState } from 'react';
4
- import Link from 'next/link';
5
4
  import { timeAgo } from '../components/utils';
6
5
  import { useSessions, useHealth } from '../lib/hooks';
7
6
  import { TaskChatPanel } from '../components/TaskChatPanel';
@@ -32,9 +31,6 @@ export default function NodesPage() {
32
31
  const [filterStatus, setFilterStatus] = useState('');
33
32
  const [search, setSearch] = useState('');
34
33
  const [viewMode, setViewMode] = useState<ViewMode>('list');
35
- const [taskDrafts, setTaskDrafts] = useState<Record<string, string>>({});
36
- const [taskOpenFor, setTaskOpenFor] = useState<string | null>(null);
37
- const [sendState, setSendState] = useState<Record<string, { sending?: boolean; error?: string; success?: string }>>({});
38
34
  const [chatAlias, setChatAlias] = useState<string | null>(null);
39
35
 
40
36
  const filtered: SessionRow[] = sessions
@@ -50,44 +46,6 @@ export default function NodesPage() {
50
46
 
51
47
  const onlineCount = sessions.filter(s => sseFor(s)).length;
52
48
 
53
- const openSendTask = (alias: string) => {
54
- setTaskOpenFor(current => current === alias ? null : alias);
55
- setSendState(prev => ({ ...prev, [alias]: {} }));
56
- };
57
-
58
- const updateTaskDraft = (alias: string, value: string) => {
59
- setTaskDrafts(prev => ({ ...prev, [alias]: value }));
60
- };
61
-
62
- const sendTask = async (alias: string) => {
63
- const task = taskDrafts[alias]?.trim() || '';
64
- if (!task) return;
65
-
66
- setSendState(prev => ({ ...prev, [alias]: { sending: true } }));
67
-
68
- try {
69
- const res = await fetch('/api/hub/send', {
70
- method: 'POST',
71
- headers: { 'Content-Type': 'application/json' },
72
- body: JSON.stringify({ alias, task }),
73
- });
74
- const data = await res.json();
75
-
76
- if (!res.ok || data?.ok === false) {
77
- throw new Error(data?.error || 'Send failed');
78
- }
79
-
80
- setTaskDrafts(prev => ({ ...prev, [alias]: '' }));
81
- setSendState(prev => ({ ...prev, [alias]: { success: 'Task sent' } }));
82
- setTaskOpenFor(null);
83
- } catch (error: unknown) {
84
- setSendState(prev => ({
85
- ...prev,
86
- [alias]: { error: error instanceof Error ? error.message : 'Send failed' },
87
- }));
88
- }
89
- };
90
-
91
49
  return (
92
50
  <div className="min-h-screen bg-[#0a0a1a] text-gray-100 p-4 sm:p-6 font-mono">
93
51
  <div className="flex items-center gap-4 mb-6">
@@ -195,13 +153,16 @@ export default function NodesPage() {
195
153
  <div className="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-4">
196
154
  {filtered.map(s => {
197
155
  const statusKey = s.online ? s.status : 'offline';
198
- const state = sendState[s.alias] || {};
199
156
  const progress = typeof s.progress === 'number' ? s.progress : 0;
200
157
 
201
158
  return (
202
159
  <div
203
160
  key={s.alias}
204
- className={`relative overflow-hidden rounded-xl border border-[#2a2a4a] bg-[#111128] p-4 transition-colors ${!s.online ? 'opacity-60' : ''}`}
161
+ role="button"
162
+ tabIndex={0}
163
+ onClick={() => setChatAlias(s.alias)}
164
+ onKeyDown={e => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); setChatAlias(s.alias); } }}
165
+ className={`relative overflow-hidden rounded-xl border border-[#2a2a4a] bg-[#111128] p-4 transition-colors hover:border-cyan-500/40 cursor-pointer ${!s.online ? 'opacity-60' : ''}`}
205
166
  >
206
167
  {!s.online && (
207
168
  <div className="pointer-events-none absolute inset-0 flex items-center justify-center">
@@ -212,7 +173,7 @@ export default function NodesPage() {
212
173
  )}
213
174
  <div className="flex items-start gap-3">
214
175
  <AliasAvatar alias={s.alias} size={36} />
215
- <Link href={`/node?alias=${encodeURIComponent(s.alias)}`} className="min-w-0 flex-1 hover:text-cyan-300">
176
+ <div className="min-w-0 flex-1">
216
177
  <div className="flex items-center gap-2">
217
178
  <span className="truncate text-base font-semibold text-white">{s.alias}</span>
218
179
  <span className={`shrink-0 rounded-md border px-2 py-0.5 text-[10px] uppercase tracking-wide ${STATUS_COLORS[statusKey] || STATUS_COLORS.offline}`}>
@@ -222,17 +183,8 @@ export default function NodesPage() {
222
183
  <div className="mt-0.5 truncate text-xs text-gray-500">
223
184
  {(s.agent || '—')}<span className="text-gray-700 mx-1.5">·</span><span title={s.server || ''}>{shortServer(s.server)}</span>
224
185
  </div>
225
- </Link>
226
- <div className="flex gap-1.5 shrink-0">
227
- <button type="button" onClick={() => setChatAlias(s.alias)}
228
- className="rounded-lg border border-green-500/20 bg-green-500/10 px-3 py-1.5 text-xs text-green-300 transition-colors hover:bg-green-500/20">
229
- Chat
230
- </button>
231
- <button type="button" onClick={() => openSendTask(s.alias)}
232
- className="rounded-lg border border-cyan-500/20 bg-cyan-500/10 px-3 py-1.5 text-xs text-cyan-300 transition-colors hover:bg-cyan-500/20">
233
- Task
234
- </button>
235
186
  </div>
187
+ <span className="shrink-0 rounded-lg border border-cyan-500/15 bg-cyan-500/5 px-2 py-1 text-[10px] text-cyan-300/70">Tap to chat</span>
236
188
  </div>
237
189
 
238
190
  <div className="mt-3 rounded-lg border border-[#1a1a2a] bg-[#0a0a15] px-3 py-2 text-xs">
@@ -251,38 +203,6 @@ export default function NodesPage() {
251
203
  </div>
252
204
  )}
253
205
 
254
- {taskOpenFor === s.alias && (
255
- <div className="mt-4 space-y-2 rounded-lg border border-[#2a2a4a] bg-[#0a0a15] p-3">
256
- <input
257
- type="text"
258
- value={taskDrafts[s.alias] || ''}
259
- onChange={e => updateTaskDraft(s.alias, e.target.value)}
260
- onKeyDown={e => e.key === 'Enter' && sendTask(s.alias)}
261
- placeholder={`Send task to ${s.alias}...`}
262
- className="w-full rounded-lg border border-[#2a2a4a] bg-[#050510] px-3 py-2 text-xs text-white placeholder-gray-600 focus:border-cyan-500 focus:outline-none"
263
- />
264
- <div className="flex justify-end gap-2">
265
- <button
266
- type="button"
267
- onClick={() => setTaskOpenFor(null)}
268
- className="rounded-lg border border-gray-700 px-3 py-1.5 text-xs text-gray-400 hover:text-gray-200"
269
- >
270
- Cancel
271
- </button>
272
- <button
273
- type="button"
274
- onClick={() => sendTask(s.alias)}
275
- disabled={state.sending || !(taskDrafts[s.alias] || '').trim()}
276
- className="rounded-lg bg-cyan-600 px-3 py-1.5 text-xs text-white hover:bg-cyan-500 disabled:cursor-not-allowed disabled:bg-gray-700"
277
- >
278
- {state.sending ? 'Sending...' : 'Send'}
279
- </button>
280
- </div>
281
- </div>
282
- )}
283
-
284
- {state.error && <div className="mt-2 text-xs text-red-400">{state.error}</div>}
285
- {state.success && taskOpenFor !== s.alias && <div className="mt-2 text-xs text-green-400">{state.success}</div>}
286
206
  </div>
287
207
  );
288
208
  })}
@@ -290,109 +210,59 @@ export default function NodesPage() {
290
210
  ) : (
291
211
  <div className="space-y-2">
292
212
  {/* Round 94: AGENT + SERVER merged into one `agent · server`
293
- cell; the freed 2 columns expand CURRENT TASK so long task
294
- content lines wrap less. Total still 12: 1+2+2+4+1+2. */}
295
- <div className="hidden sm:grid sm:grid-cols-12 gap-2 px-4 py-2 text-xs text-gray-600 uppercase">
213
+ cell. Round mobile-command: node row itself opens chat, so
214
+ the old Chat / Send Task action column is gone. */}
215
+ <div className="hidden sm:grid sm:grid-cols-10 gap-2 px-4 py-2 text-xs text-gray-600 uppercase">
296
216
  <div className="col-span-1">Status</div>
297
217
  <div className="col-span-2">Alias</div>
298
218
  <div className="col-span-2">Agent · Server</div>
299
219
  <div className="col-span-4">Current Task</div>
300
220
  <div className="col-span-1">Updated</div>
301
- <div className="col-span-2 text-right">Actions</div>
302
221
  </div>
303
222
  {filtered.map(s => {
304
223
  const statusKey = s.online ? s.status : 'offline';
305
- const state = sendState[s.alias] || {};
306
224
 
307
225
  return (
308
226
  <div
309
227
  key={s.alias}
310
- className={`rounded-lg border border-[#2a2a4a] bg-[#111128] px-4 py-3 transition-colors hover:border-[#3a3a5a] ${!s.online ? 'opacity-50' : ''}`}
228
+ role="button"
229
+ tabIndex={0}
230
+ onClick={() => setChatAlias(s.alias)}
231
+ onKeyDown={e => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); setChatAlias(s.alias); } }}
232
+ className={`rounded-lg border border-[#2a2a4a] bg-[#111128] px-4 py-3 transition-colors hover:border-cyan-500/40 cursor-pointer ${!s.online ? 'opacity-50' : ''}`}
311
233
  >
312
- <div className="hidden sm:grid sm:grid-cols-12 gap-2 items-center">
234
+ <div className="hidden sm:grid sm:grid-cols-10 gap-2 items-center">
313
235
  <div className="col-span-1">
314
236
  <span className={`text-xs px-2 py-0.5 rounded-md border ${STATUS_COLORS[statusKey] || STATUS_COLORS.offline}`}>
315
237
  {statusKey}
316
238
  </span>
317
239
  </div>
318
240
  <div className="col-span-2 min-w-0">
319
- <Link href={`/node?alias=${encodeURIComponent(s.alias)}`} className="flex items-center gap-2 min-w-0 hover:text-cyan-300">
241
+ <div className="flex items-center gap-2 min-w-0">
320
242
  <AliasAvatar alias={s.alias} size={20} />
321
243
  <span className="truncate text-sm font-medium text-white">{s.alias}</span>
322
- </Link>
244
+ </div>
323
245
  </div>
324
246
  <div className="col-span-2 truncate text-xs text-gray-400" title={s.server || ''}>
325
247
  {s.agent || '--'}<span className="text-gray-700 mx-1.5">·</span>{shortServer(s.server)}
326
248
  </div>
327
249
  <div className="col-span-4 truncate text-xs text-gray-500" title={s.task || ''}>{s.task || '--'}</div>
328
250
  <div className="col-span-1 text-xs text-gray-500">{timeAgo(s.last_seen_at || s.updated_at)}</div>
329
- <div className="col-span-2 flex justify-end gap-1.5">
330
- <button type="button" onClick={() => setChatAlias(s.alias)}
331
- className="rounded-lg border border-green-500/20 bg-green-500/10 px-2 py-1 text-xs text-green-300 hover:bg-green-500/20">
332
- Chat
333
- </button>
334
- <button type="button" onClick={() => openSendTask(s.alias)}
335
- className="rounded-lg border border-cyan-500/20 bg-cyan-500/10 px-2 py-1 text-xs text-cyan-300 hover:bg-cyan-500/20">
336
- Task
337
- </button>
338
- </div>
339
251
  </div>
340
252
  <div className="sm:hidden space-y-2">
341
253
  <div className="flex items-center gap-2.5">
342
254
  <AliasAvatar alias={s.alias} size={28} />
343
- <Link href={`/node?alias=${encodeURIComponent(s.alias)}`} className="min-w-0 flex-1 hover:text-cyan-300">
255
+ <div className="min-w-0 flex-1">
344
256
  <div className="truncate text-sm font-medium text-white">{s.alias}</div>
345
257
  <div className="truncate text-[10px] text-gray-500">{s.agent || '—'} · {timeAgo(s.last_seen_at || s.updated_at)}</div>
346
- </Link>
258
+ </div>
347
259
  <span className={`shrink-0 text-xs px-2 py-0.5 rounded-md border ${STATUS_COLORS[statusKey] || STATUS_COLORS.offline}`}>
348
260
  {statusKey}
349
261
  </span>
350
262
  </div>
351
263
  {s.task && <div className="truncate text-xs text-gray-500">{s.task}</div>}
352
- <div className="flex gap-2">
353
- <button type="button" onClick={() => setChatAlias(s.alias)}
354
- className="flex-1 rounded-lg border border-green-500/20 bg-green-500/10 px-3 py-2 text-xs text-green-300 hover:bg-green-500/20">
355
- Chat
356
- </button>
357
- <button type="button" onClick={() => openSendTask(s.alias)}
358
- className="flex-1 rounded-lg border border-cyan-500/20 bg-cyan-500/10 px-3 py-2 text-xs text-cyan-300 hover:bg-cyan-500/20">
359
- Send Task
360
- </button>
361
- </div>
264
+ <div className="text-[10px] text-cyan-300/70">Tap anywhere to chat</div>
362
265
  </div>
363
-
364
- {taskOpenFor === s.alias && (
365
- <div className="mt-3 space-y-2 border-t border-[#2a2a4a] pt-3">
366
- <input
367
- type="text"
368
- value={taskDrafts[s.alias] || ''}
369
- onChange={e => updateTaskDraft(s.alias, e.target.value)}
370
- onKeyDown={e => e.key === 'Enter' && sendTask(s.alias)}
371
- placeholder={`Send task to ${s.alias}...`}
372
- className="w-full rounded-lg border border-[#2a2a4a] bg-[#0a0a15] px-3 py-2 text-xs text-white placeholder-gray-600 focus:border-cyan-500 focus:outline-none"
373
- />
374
- <div className="flex justify-end gap-2">
375
- <button
376
- type="button"
377
- onClick={() => setTaskOpenFor(null)}
378
- className="rounded-lg border border-gray-700 px-3 py-1.5 text-xs text-gray-400 hover:text-gray-200"
379
- >
380
- Cancel
381
- </button>
382
- <button
383
- type="button"
384
- onClick={() => sendTask(s.alias)}
385
- disabled={state.sending || !(taskDrafts[s.alias] || '').trim()}
386
- className="rounded-lg bg-cyan-600 px-3 py-1.5 text-xs text-white hover:bg-cyan-500 disabled:cursor-not-allowed disabled:bg-gray-700"
387
- >
388
- {state.sending ? 'Sending...' : 'Send'}
389
- </button>
390
- </div>
391
- </div>
392
- )}
393
-
394
- {state.error && <div className="mt-2 text-xs text-red-400">{state.error}</div>}
395
- {state.success && taskOpenFor !== s.alias && <div className="mt-2 text-xs text-green-400">{state.success}</div>}
396
266
  </div>
397
267
  );
398
268
  })}
package/package.json CHANGED
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "name": "@sleep2agi/agent-network-dashboard",
3
- "version": "0.5.3",
4
- "description": "Agent Network Dashboard \u2014 Web UI for managing AI Agent networks",
3
+ "version": "0.5.5-preview.0",
4
+ "description": "Agent Network Dashboard Web UI for managing AI Agent networks",
5
5
  "scripts": {
6
6
  "dev": "next dev",
7
7
  "build": "next build",
8
8
  "start": "next start",
9
9
  "lint": "eslint",
10
- "prepublishOnly": "[ -f .next/BUILD_ID ] || (echo 'prepublishOnly: .next/BUILD_ID missing \u2014 run npm run build first (see commit 05c1ebf body for R224 chunk-500 root cause)' >&2 && exit 1)"
10
+ "prepublishOnly": "[ -f .next/BUILD_ID ] || (echo 'prepublishOnly: .next/BUILD_ID missing run npm run build first (see commit 05c1ebf body for R224 chunk-500 root cause)' >&2 && exit 1)"
11
11
  },
12
12
  "bin": {
13
13
  "agent-network-dashboard": "./bin/start.js"
@@ -44,4 +44,4 @@
44
44
  "tailwindcss": "^4",
45
45
  "typescript": "^5"
46
46
  }
47
- }
47
+ }
@@ -1,11 +1,10 @@
1
1
  <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64">
2
- <!-- Anthropic / Claude vendor mark.
3
- NOT a copy of the Anthropic trademark custom designed badge
4
- in warm-orange palette. 4-rayed sparkle = "AI spark of insight".
5
- Real Anthropic logo asset still gated on Vincent-direct. -->
6
- <circle cx="32" cy="32" r="32" fill="hsl(16 32% 22%)" />
7
- <circle cx="32" cy="32" r="30" fill="none" stroke="hsl(16 48% 54%)" stroke-width="2" />
8
- <g fill="hsl(20 80% 78%)" transform="translate(32 32)">
9
- <path d="M 0 -18 L 4 -4 L 18 0 L 4 4 L 0 18 L -4 4 L -18 0 L -4 -4 Z" />
2
+ <!-- Anthropic vendor mark official Anthropic logo (simple-icons set, CC0).
3
+ Vincent-authorized 2026-05-21 to use real vendor marks. Tinted circular
4
+ badge frames the official mark for the dashboard node-avatar context. -->
5
+ <circle cx="32" cy="32" r="32" fill="hsl(16 32% 22%)"/>
6
+ <circle cx="32" cy="32" r="30" fill="none" stroke="hsl(16 48% 54%)" stroke-width="2"/>
7
+ <g transform="translate(16 16) scale(1.333)" fill="hsl(20 80% 82%)">
8
+ <path d="M17.3041 3.541h-3.6718l6.696 16.918H24Zm-10.6082 0L0 20.459h3.7442l1.3693-3.5527h7.0052l1.3693 3.5528h3.7442L10.5363 3.5409Zm-.3712 10.2232 2.2914-5.9456 2.2914 5.9456Z"/>
10
9
  </g>
11
10
  </svg>