@sleep2agi/agent-network-dashboard 0.4.5-preview.9 → 0.4.5-preview.91

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 (319) hide show
  1. package/.mcp.json +11 -0
  2. package/.next/BUILD_ID +1 -1
  3. package/.next/build-manifest.json +3 -3
  4. package/.next/diagnostics/route-bundle-stats.json +48 -48
  5. package/.next/fallback-build-manifest.json +3 -3
  6. package/.next/prerender-manifest.json +3 -3
  7. package/.next/server/app/_global-error.html +1 -1
  8. package/.next/server/app/_global-error.rsc +1 -1
  9. package/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  10. package/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  11. package/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  12. package/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  13. package/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  14. package/.next/server/app/_not-found/page/next-font-manifest.json +1 -1
  15. package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  16. package/.next/server/app/_not-found.html +4 -4
  17. package/.next/server/app/_not-found.rsc +12 -12
  18. package/.next/server/app/_not-found.segments/_full.segment.rsc +12 -12
  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/next-font-manifest.json +1 -1
  25. package/.next/server/app/admin/page.js.nft.json +1 -1
  26. package/.next/server/app/admin/page_client-reference-manifest.js +1 -1
  27. package/.next/server/app/admin.html +4 -4
  28. package/.next/server/app/admin.rsc +15 -15
  29. package/.next/server/app/admin.segments/_full.segment.rsc +15 -15
  30. package/.next/server/app/admin.segments/_head.segment.rsc +4 -4
  31. package/.next/server/app/admin.segments/_index.segment.rsc +7 -7
  32. package/.next/server/app/admin.segments/_tree.segment.rsc +3 -3
  33. package/.next/server/app/admin.segments/admin/__PAGE__.segment.rsc +4 -4
  34. package/.next/server/app/admin.segments/admin.segment.rsc +3 -3
  35. package/.next/server/app/index.html +4 -4
  36. package/.next/server/app/index.rsc +15 -15
  37. package/.next/server/app/index.segments/__PAGE__.segment.rsc +4 -4
  38. package/.next/server/app/index.segments/_full.segment.rsc +15 -15
  39. package/.next/server/app/index.segments/_head.segment.rsc +4 -4
  40. package/.next/server/app/index.segments/_index.segment.rsc +7 -7
  41. package/.next/server/app/index.segments/_tree.segment.rsc +3 -3
  42. package/.next/server/app/login/page/next-font-manifest.json +1 -1
  43. package/.next/server/app/login/page.js.nft.json +1 -1
  44. package/.next/server/app/login/page_client-reference-manifest.js +1 -1
  45. package/.next/server/app/login.html +2 -2
  46. package/.next/server/app/login.rsc +15 -15
  47. package/.next/server/app/login.segments/_full.segment.rsc +15 -15
  48. package/.next/server/app/login.segments/_head.segment.rsc +4 -4
  49. package/.next/server/app/login.segments/_index.segment.rsc +7 -7
  50. package/.next/server/app/login.segments/_tree.segment.rsc +3 -3
  51. package/.next/server/app/login.segments/login/__PAGE__.segment.rsc +4 -4
  52. package/.next/server/app/login.segments/login.segment.rsc +3 -3
  53. package/.next/server/app/logs/page/next-font-manifest.json +1 -1
  54. package/.next/server/app/logs/page.js.nft.json +1 -1
  55. package/.next/server/app/logs/page_client-reference-manifest.js +1 -1
  56. package/.next/server/app/logs.html +4 -4
  57. package/.next/server/app/logs.rsc +15 -15
  58. package/.next/server/app/logs.segments/_full.segment.rsc +15 -15
  59. package/.next/server/app/logs.segments/_head.segment.rsc +4 -4
  60. package/.next/server/app/logs.segments/_index.segment.rsc +7 -7
  61. package/.next/server/app/logs.segments/_tree.segment.rsc +3 -3
  62. package/.next/server/app/logs.segments/logs/__PAGE__.segment.rsc +4 -4
  63. package/.next/server/app/logs.segments/logs.segment.rsc +3 -3
  64. package/.next/server/app/messages/page/next-font-manifest.json +1 -1
  65. package/.next/server/app/messages/page.js.nft.json +1 -1
  66. package/.next/server/app/messages/page_client-reference-manifest.js +1 -1
  67. package/.next/server/app/messages.html +4 -4
  68. package/.next/server/app/messages.rsc +15 -15
  69. package/.next/server/app/messages.segments/_full.segment.rsc +15 -15
  70. package/.next/server/app/messages.segments/_head.segment.rsc +4 -4
  71. package/.next/server/app/messages.segments/_index.segment.rsc +7 -7
  72. package/.next/server/app/messages.segments/_tree.segment.rsc +3 -3
  73. package/.next/server/app/messages.segments/messages/__PAGE__.segment.rsc +4 -4
  74. package/.next/server/app/messages.segments/messages.segment.rsc +3 -3
  75. package/.next/server/app/node/page/next-font-manifest.json +1 -1
  76. package/.next/server/app/node/page.js.nft.json +1 -1
  77. package/.next/server/app/node/page_client-reference-manifest.js +1 -1
  78. package/.next/server/app/node.html +4 -4
  79. package/.next/server/app/node.rsc +15 -15
  80. package/.next/server/app/node.segments/_full.segment.rsc +15 -15
  81. package/.next/server/app/node.segments/_head.segment.rsc +4 -4
  82. package/.next/server/app/node.segments/_index.segment.rsc +7 -7
  83. package/.next/server/app/node.segments/_tree.segment.rsc +3 -3
  84. package/.next/server/app/node.segments/node/__PAGE__.segment.rsc +4 -4
  85. package/.next/server/app/node.segments/node.segment.rsc +3 -3
  86. package/.next/server/app/nodes/page/next-font-manifest.json +1 -1
  87. package/.next/server/app/nodes/page.js.nft.json +1 -1
  88. package/.next/server/app/nodes/page_client-reference-manifest.js +1 -1
  89. package/.next/server/app/nodes.html +4 -4
  90. package/.next/server/app/nodes.rsc +15 -15
  91. package/.next/server/app/nodes.segments/_full.segment.rsc +15 -15
  92. package/.next/server/app/nodes.segments/_head.segment.rsc +4 -4
  93. package/.next/server/app/nodes.segments/_index.segment.rsc +7 -7
  94. package/.next/server/app/nodes.segments/_tree.segment.rsc +3 -3
  95. package/.next/server/app/nodes.segments/nodes/__PAGE__.segment.rsc +4 -4
  96. package/.next/server/app/nodes.segments/nodes.segment.rsc +3 -3
  97. package/.next/server/app/page/next-font-manifest.json +1 -1
  98. package/.next/server/app/page.js.nft.json +1 -1
  99. package/.next/server/app/page_client-reference-manifest.js +1 -1
  100. package/.next/server/app/server-logs/page/next-font-manifest.json +1 -1
  101. package/.next/server/app/server-logs/page_client-reference-manifest.js +1 -1
  102. package/.next/server/app/server-logs.html +4 -4
  103. package/.next/server/app/server-logs.rsc +15 -15
  104. package/.next/server/app/server-logs.segments/_full.segment.rsc +15 -15
  105. package/.next/server/app/server-logs.segments/_head.segment.rsc +4 -4
  106. package/.next/server/app/server-logs.segments/_index.segment.rsc +7 -7
  107. package/.next/server/app/server-logs.segments/_tree.segment.rsc +3 -3
  108. package/.next/server/app/server-logs.segments/server-logs/__PAGE__.segment.rsc +4 -4
  109. package/.next/server/app/server-logs.segments/server-logs.segment.rsc +3 -3
  110. package/.next/server/app/settings/networks/page/next-font-manifest.json +1 -1
  111. package/.next/server/app/settings/networks/page.js.nft.json +1 -1
  112. package/.next/server/app/settings/networks/page_client-reference-manifest.js +1 -1
  113. package/.next/server/app/settings/networks.html +4 -4
  114. package/.next/server/app/settings/networks.rsc +15 -15
  115. package/.next/server/app/settings/networks.segments/_full.segment.rsc +15 -15
  116. package/.next/server/app/settings/networks.segments/_head.segment.rsc +4 -4
  117. package/.next/server/app/settings/networks.segments/_index.segment.rsc +7 -7
  118. package/.next/server/app/settings/networks.segments/_tree.segment.rsc +3 -3
  119. package/.next/server/app/settings/networks.segments/settings/networks/__PAGE__.segment.rsc +4 -4
  120. package/.next/server/app/settings/networks.segments/settings/networks.segment.rsc +3 -3
  121. package/.next/server/app/settings/networks.segments/settings.segment.rsc +3 -3
  122. package/.next/server/app/settings/page/next-font-manifest.json +1 -1
  123. package/.next/server/app/settings/page.js.nft.json +1 -1
  124. package/.next/server/app/settings/page_client-reference-manifest.js +1 -1
  125. package/.next/server/app/settings/tokens/page/next-font-manifest.json +1 -1
  126. package/.next/server/app/settings/tokens/page_client-reference-manifest.js +1 -1
  127. package/.next/server/app/settings/tokens.html +4 -4
  128. package/.next/server/app/settings/tokens.rsc +15 -15
  129. package/.next/server/app/settings/tokens.segments/_full.segment.rsc +15 -15
  130. package/.next/server/app/settings/tokens.segments/_head.segment.rsc +4 -4
  131. package/.next/server/app/settings/tokens.segments/_index.segment.rsc +7 -7
  132. package/.next/server/app/settings/tokens.segments/_tree.segment.rsc +3 -3
  133. package/.next/server/app/settings/tokens.segments/settings/tokens/__PAGE__.segment.rsc +4 -4
  134. package/.next/server/app/settings/tokens.segments/settings/tokens.segment.rsc +3 -3
  135. package/.next/server/app/settings/tokens.segments/settings.segment.rsc +3 -3
  136. package/.next/server/app/settings.html +4 -4
  137. package/.next/server/app/settings.rsc +15 -15
  138. package/.next/server/app/settings.segments/_full.segment.rsc +15 -15
  139. package/.next/server/app/settings.segments/_head.segment.rsc +4 -4
  140. package/.next/server/app/settings.segments/_index.segment.rsc +7 -7
  141. package/.next/server/app/settings.segments/_tree.segment.rsc +3 -3
  142. package/.next/server/app/settings.segments/settings/__PAGE__.segment.rsc +4 -4
  143. package/.next/server/app/settings.segments/settings.segment.rsc +3 -3
  144. package/.next/server/app/tasks/[id]/page/next-font-manifest.json +1 -1
  145. package/.next/server/app/tasks/[id]/page.js.nft.json +1 -1
  146. package/.next/server/app/tasks/[id]/page_client-reference-manifest.js +1 -1
  147. package/.next/server/app/tasks/page/next-font-manifest.json +1 -1
  148. package/.next/server/app/tasks/page.js.nft.json +1 -1
  149. package/.next/server/app/tasks/page_client-reference-manifest.js +1 -1
  150. package/.next/server/app/tasks.html +4 -4
  151. package/.next/server/app/tasks.rsc +15 -15
  152. package/.next/server/app/tasks.segments/_full.segment.rsc +15 -15
  153. package/.next/server/app/tasks.segments/_head.segment.rsc +4 -4
  154. package/.next/server/app/tasks.segments/_index.segment.rsc +7 -7
  155. package/.next/server/app/tasks.segments/_tree.segment.rsc +3 -3
  156. package/.next/server/app/tasks.segments/tasks/__PAGE__.segment.rsc +4 -4
  157. package/.next/server/app/tasks.segments/tasks.segment.rsc +3 -3
  158. package/.next/server/chunks/ssr/[root-of-the-server]__0jl4ukn._.js +3 -0
  159. package/.next/server/chunks/ssr/[root-of-the-server]__0jl4ukn._.js.map +1 -0
  160. package/.next/server/chunks/ssr/[root-of-the-server]__0n46s~k._.js +3 -0
  161. package/.next/server/chunks/ssr/[root-of-the-server]__0n46s~k._.js.map +1 -0
  162. package/.next/server/chunks/ssr/[root-of-the-server]__0w2ay2h._.js +3 -0
  163. package/.next/server/chunks/ssr/[root-of-the-server]__0w2ay2h._.js.map +1 -0
  164. package/.next/server/chunks/ssr/[root-of-the-server]__0xm3h9x._.js +1 -1
  165. package/.next/server/chunks/ssr/[root-of-the-server]__0xm3h9x._.js.map +1 -1
  166. package/.next/server/chunks/ssr/_0nne7mz._.js +3 -0
  167. package/.next/server/chunks/ssr/_0nne7mz._.js.map +1 -0
  168. package/.next/server/chunks/ssr/app_0.zbtn5._.js +9 -0
  169. package/.next/server/chunks/ssr/app_0.zbtn5._.js.map +1 -0
  170. package/.next/server/chunks/ssr/app_01y-~mp._.js +3 -0
  171. package/.next/server/chunks/ssr/app_01y-~mp._.js.map +1 -0
  172. package/.next/server/chunks/ssr/app_04n78pr._.js +3 -0
  173. package/.next/server/chunks/ssr/app_04n78pr._.js.map +1 -0
  174. package/.next/server/chunks/ssr/app_0_agk0r._.js +3 -0
  175. package/.next/server/chunks/ssr/app_0_agk0r._.js.map +1 -0
  176. package/.next/server/chunks/ssr/app_0aenxef._.js +3 -0
  177. package/.next/server/chunks/ssr/app_0aenxef._.js.map +1 -0
  178. package/.next/server/chunks/ssr/app_0aum_g5._.js +3 -0
  179. package/.next/server/chunks/ssr/app_0aum_g5._.js.map +1 -0
  180. package/.next/server/chunks/ssr/app_0emvkn2._.js +3 -0
  181. package/.next/server/chunks/ssr/app_0emvkn2._.js.map +1 -0
  182. package/.next/server/chunks/ssr/app_0esuljp._.js +3 -0
  183. package/.next/server/chunks/ssr/app_0esuljp._.js.map +1 -0
  184. package/.next/server/chunks/ssr/app_0izi28j._.js +1 -1
  185. package/.next/server/chunks/ssr/app_0izi28j._.js.map +1 -1
  186. package/.next/server/chunks/ssr/app_components_08ys5y3._.js +5 -5
  187. package/.next/server/chunks/ssr/app_components_08ys5y3._.js.map +1 -1
  188. package/.next/server/chunks/ssr/app_server-logs_page_tsx_0_kpp1p._.js +1 -1
  189. package/.next/server/chunks/ssr/app_server-logs_page_tsx_0_kpp1p._.js.map +1 -1
  190. package/.next/server/chunks/ssr/app_tasks_page_tsx_0z-d6mp._.js +1 -1
  191. package/.next/server/chunks/ssr/app_tasks_page_tsx_0z-d6mp._.js.map +1 -1
  192. package/.next/server/middleware-build-manifest.js +3 -3
  193. package/.next/server/next-font-manifest.js +1 -1
  194. package/.next/server/next-font-manifest.json +14 -14
  195. package/.next/server/pages/404.html +4 -4
  196. package/.next/server/pages/500.html +1 -1
  197. package/.next/server/server-reference-manifest.js +1 -1
  198. package/.next/server/server-reference-manifest.json +1 -1
  199. package/.next/static/chunks/0-hlcuoemhe7w.js +7 -0
  200. package/.next/static/chunks/02_zpo7taex9o.js +7 -0
  201. package/.next/static/chunks/03b6jkic-1r9u.css +2 -0
  202. package/.next/static/chunks/06fliypy0.f0r.js +1 -0
  203. package/.next/static/chunks/06n3d~fbbtagk.js +1 -0
  204. package/.next/static/chunks/07eba1lz2u3p4.js +1 -0
  205. package/.next/static/chunks/0av2~0.96~d~g.js +1 -0
  206. package/.next/static/chunks/{07okhs5561y5y.js → 0c1bp~g7.8ru..js} +1 -1
  207. package/.next/static/chunks/0g9aof0ob_fcj.js +1 -0
  208. package/.next/static/chunks/0gtbwcilfu6b7.js +1 -0
  209. package/.next/static/chunks/0s8jo6jypzkx5.js +1 -0
  210. package/.next/static/chunks/0ubqqhhpsaez4.js +1 -0
  211. package/.next/static/chunks/0vmfu_gz9tp4f.js +1 -0
  212. package/.next/static/chunks/0~qw9kxksr1v2.js +1 -0
  213. package/.next/static/chunks/12gprw3l0kvvf.js +1 -0
  214. package/.next/static/chunks/12mjtyh-j74~k.js +1 -0
  215. package/.next/static/chunks/12yuo353giomx.js +1 -0
  216. package/.next/static/media/4fa387ec64143e14-s.0.qu-9752pffj.woff2 +0 -0
  217. package/.next/static/media/5ce348bf30bf5439-s.0ee55_hj9qcer.woff2 +0 -0
  218. package/.next/static/media/6306c77e7c8268e4-s.0mao5jbfbduzp.woff2 +0 -0
  219. package/.next/static/media/797e433ab948586e-s.p.09zddjkbdep5a.woff2 +0 -0
  220. package/.next/static/media/7d817b4c03b0c5f1-s.0uzt.a6d44yda.woff2 +0 -0
  221. package/.next/static/media/bbc41e54d2fcbd21-s.0mvwgmnhv29no.woff2 +0 -0
  222. package/.next/trace +2 -2
  223. package/.next/trace-build +1 -1
  224. package/app/admin/page.tsx +97 -27
  225. package/app/components/AgentCard.tsx +19 -5
  226. package/app/components/BroadcastBar.tsx +22 -4
  227. package/app/components/DispatchPanel.tsx +9 -5
  228. package/app/components/EmptyState.tsx +127 -12
  229. package/app/components/HealthBanner.tsx +11 -2
  230. package/app/components/HelpOverlay.tsx +50 -10
  231. package/app/components/InboxPanel.tsx +7 -4
  232. package/app/components/Sidebar.tsx +81 -44
  233. package/app/components/StatsBar.tsx +59 -36
  234. package/app/components/TaskChatPanel.tsx +8 -10
  235. package/app/components/TaskDrawer.tsx +72 -28
  236. package/app/components/TopoGraph.tsx +527 -41
  237. package/app/components/utils.ts +13 -0
  238. package/app/globals.css +90 -0
  239. package/app/lib/status.ts +85 -0
  240. package/app/lib/version.ts +7 -0
  241. package/app/login/page.tsx +40 -7
  242. package/app/logs/page.tsx +70 -21
  243. package/app/messages/page.tsx +34 -9
  244. package/app/node/page.tsx +52 -27
  245. package/app/nodes/page.tsx +45 -21
  246. package/app/page.tsx +103 -32
  247. package/app/server-logs/page.tsx +104 -28
  248. package/app/settings/networks/page.tsx +40 -16
  249. package/app/settings/page.tsx +39 -11
  250. package/app/tasks/[id]/page.tsx +2 -13
  251. package/app/tasks/page.tsx +66 -73
  252. package/package.json +1 -1
  253. package/public/intern_avatar.png +0 -0
  254. package/scripts/empty-state-test.mjs +41 -0
  255. package/scripts/fold-only.mjs +47 -0
  256. package/scripts/intern-alias-test.mjs +46 -0
  257. package/scripts/loop-review.mjs +270 -0
  258. package/scripts/network-derive-shot.mjs +16 -0
  259. package/scripts/network-derive-test.mjs +28 -0
  260. package/scripts/topo-brand-shot.mjs +61 -0
  261. package/scripts/topo-cluster-test.mjs +41 -0
  262. package/scripts/topo-controls-shot.mjs +24 -0
  263. package/scripts/topo-group-test.mjs +37 -0
  264. package/scripts/topo-inspect.mjs +56 -0
  265. package/scripts/topo-interaction-test.mjs +80 -0
  266. package/scripts/topo-mock-large.mjs +58 -0
  267. package/scripts/topo-r104-test.mjs +54 -0
  268. package/scripts/topo-shot.mjs +31 -0
  269. package/.next/server/chunks/ssr/[root-of-the-server]__06w_u7t._.js +0 -3
  270. package/.next/server/chunks/ssr/[root-of-the-server]__06w_u7t._.js.map +0 -1
  271. package/.next/server/chunks/ssr/[root-of-the-server]__0ehu0jb._.js +0 -3
  272. package/.next/server/chunks/ssr/[root-of-the-server]__0ehu0jb._.js.map +0 -1
  273. package/.next/server/chunks/ssr/[root-of-the-server]__0nrckjd._.js +0 -3
  274. package/.next/server/chunks/ssr/[root-of-the-server]__0nrckjd._.js.map +0 -1
  275. package/.next/server/chunks/ssr/_13_v7-3._.js +0 -3
  276. package/.next/server/chunks/ssr/_13_v7-3._.js.map +0 -1
  277. package/.next/server/chunks/ssr/app_0.0wpa~._.js +0 -3
  278. package/.next/server/chunks/ssr/app_0.0wpa~._.js.map +0 -1
  279. package/.next/server/chunks/ssr/app_0ap_oiq._.js +0 -3
  280. package/.next/server/chunks/ssr/app_0ap_oiq._.js.map +0 -1
  281. package/.next/server/chunks/ssr/app_0dk5wao._.js +0 -3
  282. package/.next/server/chunks/ssr/app_0dk5wao._.js.map +0 -1
  283. package/.next/server/chunks/ssr/app_0et5yua._.js +0 -3
  284. package/.next/server/chunks/ssr/app_0et5yua._.js.map +0 -1
  285. package/.next/server/chunks/ssr/app_10b5blc._.js +0 -9
  286. package/.next/server/chunks/ssr/app_10b5blc._.js.map +0 -1
  287. package/.next/server/chunks/ssr/app_11vl967._.js +0 -3
  288. package/.next/server/chunks/ssr/app_11vl967._.js.map +0 -1
  289. package/.next/server/chunks/ssr/app_login_page_tsx_0z71ad3._.js +0 -3
  290. package/.next/server/chunks/ssr/app_login_page_tsx_0z71ad3._.js.map +0 -1
  291. package/.next/server/chunks/ssr/app_page_tsx_0es_sk2._.js +0 -3
  292. package/.next/server/chunks/ssr/app_page_tsx_0es_sk2._.js.map +0 -1
  293. package/.next/static/chunks/0-.hjh--kcdiy.js +0 -1
  294. package/.next/static/chunks/02afyxgpty3uf.js +0 -1
  295. package/.next/static/chunks/02flrewxlf_m_.js +0 -1
  296. package/.next/static/chunks/051gslfjka1kj.js +0 -1
  297. package/.next/static/chunks/07oobuohrpigy.js +0 -1
  298. package/.next/static/chunks/09al3qm76q7nd.js +0 -1
  299. package/.next/static/chunks/0e7c40p~wq665.js +0 -1
  300. package/.next/static/chunks/0g7m7zk.v7g6h.js +0 -1
  301. package/.next/static/chunks/0h.ajsk_uxigl.js +0 -1
  302. package/.next/static/chunks/0msa~bub38ytf.css +0 -2
  303. package/.next/static/chunks/0ogeals5ufhho.js +0 -1
  304. package/.next/static/chunks/10ir.g.n~hre0.js +0 -7
  305. package/.next/static/chunks/10njj7kn9ylkf.js +0 -1
  306. package/.next/static/chunks/12dcb86elsl-e.js +0 -7
  307. package/.next/static/chunks/13.dst7liziwo.js +0 -1
  308. package/.next/static/chunks/132e__998_q9r.js +0 -1
  309. package/.next/static/media/4fa387ec64143e14-s.0q3udbd2bu5yp.woff2 +0 -0
  310. package/.next/static/media/797e433ab948586e-s.p.0.q-h669a_dqa.woff2 +0 -0
  311. package/.next/static/media/bbc41e54d2fcbd21-s.0gw~uztddq1df.woff2 +0 -0
  312. package/public/file.svg +0 -1
  313. package/public/globe.svg +0 -1
  314. package/public/next.svg +0 -1
  315. package/public/vercel.svg +0 -1
  316. package/public/window.svg +0 -1
  317. /package/.next/static/{stSZtBF9uGYc3L399m0h1 → u-HIIfy-O0UVQ02APphkX}/_buildManifest.js +0 -0
  318. /package/.next/static/{stSZtBF9uGYc3L399m0h1 → u-HIIfy-O0UVQ02APphkX}/_clientMiddlewareManifest.js +0 -0
  319. /package/.next/static/{stSZtBF9uGYc3L399m0h1 → u-HIIfy-O0UVQ02APphkX}/_ssgManifest.js +0 -0
@@ -1,3 +1,16 @@
1
+ /** Round 82: strip the most common markdown markup from agent-to-agent
2
+ * task / message bodies so single-line table previews read cleanly.
3
+ * Full original content stays in the expanded row / drawer / title=. */
4
+ export function previewContent(raw: string | null | undefined): string {
5
+ if (!raw) return '--';
6
+ return raw
7
+ .replace(/!\[([^\]]*)\]\([^)]*\)/g, '$1') // images: ![alt](src) → alt
8
+ .replace(/\[([^\]]+)\]\([^)]*\)/g, '$1') // links: [text](href) → text
9
+ .replace(/`([^`]+)`/g, '$1') // inline code: `x` → x
10
+ .replace(/\s+/g, ' ') // collapse whitespace
11
+ .trim() || '--';
12
+ }
13
+
1
14
  export function timeAgo(dateStr: string): string {
2
15
  if (!dateStr) return '--';
3
16
  const diff = Date.now() - new Date(dateStr.replace(' ', 'T') + 'Z').getTime();
package/app/globals.css CHANGED
@@ -811,3 +811,93 @@ body {
811
811
  color: #92400e !important;
812
812
  border-color: rgba(217, 119, 6, 0.28) !important;
813
813
  }
814
+
815
+ /* Round 30 — global drawer entrance keyframes so TaskDrawer, TaskChatPanel,
816
+ and any future right-side panel share one source. Previously the
817
+ keyframe lived inside TaskChatPanel's <style jsx global>; if that
818
+ component never mounted, the keyframe was missing for TaskDrawer. */
819
+ @keyframes anet-slide-in {
820
+ from { transform: translateX(100%); }
821
+ to { transform: translateX(0); }
822
+ }
823
+ .animate-slide-in { animation: anet-slide-in 0.2s ease-out; }
824
+
825
+ @keyframes anet-fade-in {
826
+ from { opacity: 0; }
827
+ to { opacity: 1; }
828
+ }
829
+ .anet-fade-in { animation: anet-fade-in 0.15s ease-out; }
830
+
831
+ /* Round 36 — current-step ring pulse on TaskDrawer timeline. Halo gently
832
+ breathes around the active step's dot so users can spot "task is here". */
833
+ @keyframes anet-current-step-pulse-kf {
834
+ 0%, 100% { transform: scale(1); opacity: 0.6; }
835
+ 50% { transform: scale(1.25); opacity: 0.0; }
836
+ }
837
+ .anet-current-step-pulse {
838
+ animation: anet-current-step-pulse-kf 1.6s ease-in-out infinite;
839
+ }
840
+
841
+ /* Round 45 — TopoGraph rotating radar sweep wedge. 6s slow rotation
842
+ gives the topology canvas a real "radar scan" feel without distracting
843
+ from the agent nodes. */
844
+ @keyframes anet-topo-sweep-kf {
845
+ 0% { transform: rotate(0deg); }
846
+ 100% { transform: rotate(360deg); }
847
+ }
848
+ .anet-topo-sweep {
849
+ animation: anet-topo-sweep-kf 6s linear infinite;
850
+ }
851
+
852
+ /* Round 46 — animated dashed spokes flowing from hub outward. Each spoke
853
+ gets a small animationDelay (set inline) so the dashes don't all flow
854
+ in sync — reads as "command relay" pulse rather than a metronome. */
855
+ @keyframes anet-topo-spoke-flow-kf {
856
+ from { stroke-dashoffset: 0; }
857
+ to { stroke-dashoffset: -40; }
858
+ }
859
+ .anet-topo-spoke-flow {
860
+ animation: anet-topo-spoke-flow-kf 2.4s linear infinite;
861
+ }
862
+
863
+ /* ─────────────────────────────────────────────────────────────────────
864
+ Round 29 — prefers-reduced-motion a11y sweep
865
+
866
+ Rounds 19~27 accumulated a lot of small animations: Tasks row 0fr↔1fr
867
+ expand, chevron rotate, hover bg shifts, Cmd+K popover, TaskChatPanel
868
+ slide-in, brand/skeleton pulses already had their own guards.
869
+
870
+ For users who set system "reduce motion": neutralise everything in one
871
+ pass. Don't kill state changes outright — only their durations and
872
+ keyframes. Hover and focus colours still apply, just instantly.
873
+ ───────────────────────────────────────────────────────────────────── */
874
+ @media (prefers-reduced-motion: reduce) {
875
+ *,
876
+ *::before,
877
+ *::after {
878
+ animation-duration: 0.001ms !important;
879
+ animation-iteration-count: 1 !important;
880
+ transition-duration: 0.001ms !important;
881
+ scroll-behavior: auto !important;
882
+ }
883
+ /* Skeleton pulse already has its own guard; harden in case the bar
884
+ class is reused without anet-skeleton-pulse. */
885
+ .anet-skeleton-bar {
886
+ animation: none !important;
887
+ }
888
+ /* Brand pulse hidden — green/red dot still indicates state via color. */
889
+ .anet-brand-pulse {
890
+ animation: none !important;
891
+ }
892
+ /* Drawer entrance kills — keyframes promoted to globals in r30. */
893
+ .animate-slide-in,
894
+ .anet-fade-in,
895
+ .anet-current-step-pulse,
896
+ .anet-topo-sweep,
897
+ .anet-topo-spoke-flow {
898
+ animation: none !important;
899
+ }
900
+ /* Tasks row grid 0fr↔1fr keep working (it's the toggle mechanism),
901
+ but the smooth transition just snaps. Already handled via the
902
+ blanket transition-duration override above. */
903
+ }
@@ -0,0 +1,85 @@
1
+ /** Single source of truth for task status colors. Both `/tasks` (chip
2
+ * strip, badge, distribution bar) and the Overview Recent Activity row
3
+ * used to ship their own incomplete maps; round 66 consolidates them
4
+ * here so adding a new status updates every consumer at once.
5
+ *
6
+ * Order in `TASK_STATUSES` is chronological-ish: lifecycle progress on
7
+ * the left, terminal-good (`closed`) in the middle, terminal-bad
8
+ * (`failed`/`cancelled`/`expired`) on the right. */
9
+
10
+ export const TASK_STATUSES = [
11
+ 'created',
12
+ 'delivered',
13
+ 'acked',
14
+ 'running',
15
+ 'replied',
16
+ 'closed',
17
+ 'failed',
18
+ 'cancelled',
19
+ 'expired',
20
+ ] as const;
21
+
22
+ export type TaskStatus = typeof TASK_STATUSES[number];
23
+
24
+ /** Pill / chip background+text+border. Tailwind classes, not inlined hex,
25
+ * because chips are static class names safe from purge. */
26
+ export const STATUS_CHIP_CLASS: Record<string, string> = {
27
+ created: 'bg-gray-500/10 text-gray-400 border-gray-500/20',
28
+ delivered: 'bg-blue-500/10 text-blue-300 border-blue-500/20',
29
+ acked: 'bg-cyan-500/10 text-cyan-300 border-cyan-500/20',
30
+ running: 'bg-green-500/10 text-green-300 border-green-500/20',
31
+ replied: 'bg-purple-500/10 text-purple-300 border-purple-500/20',
32
+ closed: 'bg-gray-500/10 text-gray-500 border-gray-500/20',
33
+ failed: 'bg-red-500/10 text-red-300 border-red-500/20',
34
+ cancelled: 'bg-yellow-500/10 text-yellow-300 border-yellow-500/20',
35
+ expired: 'bg-orange-500/10 text-orange-300 border-orange-500/20',
36
+ };
37
+
38
+ /** Inline hex dots — used wherever Tailwind would purge dynamic class
39
+ * names (`bg-${family}-400`). Style attribute carries the color. */
40
+ export const STATUS_DOT_HEX: Record<string, string> = {
41
+ created: '#9ca3af',
42
+ delivered: '#60a5fa',
43
+ acked: '#22d3ee',
44
+ running: '#4ade80',
45
+ replied: '#a78bfa',
46
+ closed: '#6b7280',
47
+ failed: '#f87171',
48
+ cancelled: '#facc15',
49
+ expired: '#fb923c',
50
+ };
51
+
52
+ /** Session lifecycle (distinct from task lifecycle above). Shared by
53
+ * /nodes status pills and /admin Online Sessions row chips so an
54
+ * agent in `blocked` state reads the same color everywhere.
55
+ * Round 91 — extracted from app/nodes/page.tsx. */
56
+ export const SESSION_STATUS_CHIP_CLASS: Record<string, string> = {
57
+ working: 'bg-green-500/10 text-green-300 border-green-500/20',
58
+ idle: 'bg-blue-500/10 text-blue-300 border-blue-500/20',
59
+ blocked: 'bg-yellow-500/10 text-yellow-300 border-yellow-500/20',
60
+ error: 'bg-red-500/10 text-red-300 border-red-500/20',
61
+ offline: 'bg-gray-500/10 text-gray-500 border-gray-500/20',
62
+ };
63
+
64
+ /** Text-only color for session status. Used where a chip background
65
+ * would be too heavy — e.g. /node detail header status label. */
66
+ export const SESSION_STATUS_TEXT_CLASS: Record<string, string> = {
67
+ working: 'text-green-400',
68
+ idle: 'text-blue-400',
69
+ blocked: 'text-yellow-400',
70
+ error: 'text-red-400',
71
+ offline: 'text-gray-500',
72
+ };
73
+
74
+ /** Solid bar segment background for the Tasks distribution bar. */
75
+ export const STATUS_BAR_CLASS: Record<string, string> = {
76
+ created: 'bg-gray-500',
77
+ delivered: 'bg-blue-500',
78
+ acked: 'bg-cyan-500',
79
+ running: 'bg-green-500',
80
+ replied: 'bg-purple-500',
81
+ closed: 'bg-gray-600',
82
+ failed: 'bg-red-500',
83
+ cancelled: 'bg-yellow-500',
84
+ expired: 'bg-orange-500',
85
+ };
@@ -0,0 +1,7 @@
1
+ /** Dashboard package version sourced from package.json at build time.
2
+ * Importing JSON requires `resolveJsonModule: true` in tsconfig, which
3
+ * Next sets by default. Bumping is automated by the publish flow, so this
4
+ * surfaces the real preview number in Settings → Dashboard. */
5
+ import pkg from '../../package.json' assert { type: 'json' };
6
+
7
+ export const DASHBOARD_VERSION: string = pkg.version;
@@ -1,11 +1,13 @@
1
1
  'use client';
2
2
 
3
3
  import { FormEvent, useState } from 'react';
4
+ import { DASHBOARD_VERSION } from '../lib/version';
4
5
 
5
6
  export default function LoginPage() {
6
7
  const [mode, setMode] = useState<'login' | 'register'>('login');
7
8
  const [username, setUsername] = useState('');
8
9
  const [password, setPassword] = useState('');
10
+ const [showPassword, setShowPassword] = useState(false);
9
11
  const [error, setError] = useState('');
10
12
  const [pending, setPending] = useState(false);
11
13
 
@@ -68,7 +70,9 @@ export default function LoginPage() {
68
70
  </div>
69
71
  <h1 className="text-[22px] sm:text-2xl font-semibold text-white tracking-tight">Agent Network</h1>
70
72
  <p className="text-[13px] text-gray-500 mt-1.5 leading-snug">
71
- One control plane for your AI agents · <span className="text-gray-600">Tasks · Mesh · Messages</span>
73
+ {mode === 'login'
74
+ ? <>Welcome back · <span className="text-gray-600">Tasks · Mesh · Messages</span></>
75
+ : <>Create your account · <span className="text-gray-600">Free preview · no credit card</span></>}
72
76
  </p>
73
77
  </div>
74
78
 
@@ -93,22 +97,51 @@ export default function LoginPage() {
93
97
  <label htmlFor="password" className="block text-xs text-gray-500 mb-2 uppercase tracking-wider">
94
98
  Password
95
99
  </label>
96
- <input id="password" type="password" value={password} onChange={e => setPassword(e.target.value)}
97
- placeholder="Enter password"
98
- className="w-full bg-[#0a0a15] border border-[#2a2a4a] rounded-lg px-4 py-3 text-sm text-white placeholder-gray-600 focus:border-cyan-500/50 focus:ring-1 focus:ring-cyan-500/20 focus:outline-none transition-all" />
100
+ <div className="relative">
101
+ <input id="password" type={showPassword ? 'text' : 'password'} value={password} onChange={e => setPassword(e.target.value)}
102
+ placeholder="Enter password"
103
+ className="w-full bg-[#0a0a15] border border-[#2a2a4a] rounded-lg px-4 pr-11 py-3 text-sm text-white placeholder-gray-600 focus:border-cyan-500/50 focus:ring-1 focus:ring-cyan-500/20 focus:outline-none transition-all" />
104
+ <button
105
+ type="button"
106
+ onClick={() => setShowPassword(s => !s)}
107
+ tabIndex={-1}
108
+ aria-label={showPassword ? 'Hide password' : 'Show password'}
109
+ className="absolute inset-y-0 right-0 flex items-center px-3 text-gray-600 hover:text-gray-300 transition-colors"
110
+ >
111
+ {showPassword ? (
112
+ <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round">
113
+ <path d="M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19m-6.72-1.07a3 3 0 1 1-4.24-4.24" />
114
+ <line x1="1" y1="1" x2="23" y2="23" />
115
+ </svg>
116
+ ) : (
117
+ <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round">
118
+ <path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z" />
119
+ <circle cx="12" cy="12" r="3" />
120
+ </svg>
121
+ )}
122
+ </button>
123
+ </div>
99
124
 
100
125
  {error && (
101
126
  <div className="mt-3 text-sm text-red-300 bg-red-500/5 border border-red-500/10 rounded-lg px-3 py-2">{error}</div>
102
127
  )}
103
128
 
104
- <button type="submit" disabled={pending || !password}
105
- className="mt-5 w-full px-4 py-3 bg-gradient-to-r from-cyan-600 to-blue-600 hover:from-cyan-500 hover:to-blue-500 disabled:from-gray-800 disabled:to-gray-800 disabled:text-gray-600 text-white text-sm font-medium rounded-lg transition-all shadow-lg shadow-cyan-500/10 hover:shadow-cyan-500/20 disabled:shadow-none">
106
- {pending ? (mode === 'login' ? 'Signing in...' : 'Registering...') : (mode === 'login' ? 'Sign in' : 'Create account')}
129
+ <button type="submit" disabled={pending || !password || !username.trim()}
130
+ className="mt-5 w-full flex items-center justify-center gap-2 px-4 py-3 bg-gradient-to-r from-cyan-600 to-blue-600 hover:from-cyan-500 hover:to-blue-500 disabled:from-gray-800 disabled:to-gray-800 disabled:text-gray-600 text-white text-sm font-medium rounded-lg transition-all shadow-lg shadow-cyan-500/10 hover:shadow-cyan-500/20 disabled:shadow-none">
131
+ {pending && (
132
+ <svg aria-hidden className="w-4 h-4 animate-spin" viewBox="0 0 24 24" fill="none">
133
+ <circle cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="3" opacity="0.25" />
134
+ <path d="M4 12a8 8 0 018-8" stroke="currentColor" strokeWidth="3" strokeLinecap="round" />
135
+ </svg>
136
+ )}
137
+ <span>{pending ? (mode === 'login' ? 'Signing in…' : 'Registering…') : (mode === 'login' ? 'Sign in' : 'Create account')}</span>
107
138
  </button>
108
139
  </form>
109
140
 
110
141
  <p className="text-center text-[11px] text-gray-700 mt-6">
111
142
  Sleep2AGI · Apache-2.0 · <a href="https://anet.sh" className="hover:text-gray-500 transition-colors">anet.sh</a>
143
+ <span className="mx-1 text-gray-800">·</span>
144
+ <span className="font-mono" title="@sleep2agi/agent-network-dashboard">v{DASHBOARD_VERSION}</span>
112
145
  </p>
113
146
  </div>
114
147
  </main>
package/app/logs/page.tsx CHANGED
@@ -5,6 +5,7 @@ import Link from 'next/link';
5
5
  import { timeAgo } from '../components/utils';
6
6
  import { useNetworkId } from '../lib/network-context';
7
7
  import { EmptyState } from '../components/EmptyState';
8
+ import { AliasAvatar } from '../components/AliasAvatar';
8
9
 
9
10
  interface AuditLog {
10
11
  id: string;
@@ -26,6 +27,18 @@ const ACTION_COLORS: Record<string, string> = {
26
27
  send_task: 'bg-cyan-500/10 text-cyan-300 border-cyan-500/20',
27
28
  };
28
29
 
30
+ /** 2px left-rail stripe color per audit action — reuses the r32 server-logs
31
+ * pattern so failed logins / token rotations spike out of a wall of
32
+ * registers and logins without users reading every chip. Inline hex
33
+ * prevents Tailwind v4 from purging dynamic class names. */
34
+ const ACTION_STRIPE: Record<string, string> = {
35
+ register: '#4ade80',
36
+ login: '#60a5fa',
37
+ login_failed: '#ef4444',
38
+ create_network: '#a78bfa',
39
+ send_task: '#22d3ee',
40
+ };
41
+
29
42
  export default function LogsPage() {
30
43
  const { networkId } = useNetworkId();
31
44
  const [logs, setLogs] = useState<AuditLog[]>([]);
@@ -64,25 +77,50 @@ export default function LogsPage() {
64
77
  return (
65
78
  <div className="min-h-screen bg-[#0a0a1a] text-gray-100 p-4 sm:p-6 font-mono">
66
79
  <div className="flex items-center gap-4 mb-6">
67
- <h1 className="text-2xl font-bold text-white lg:ml-0 ml-10">Logs</h1>
68
- <span className="text-xs bg-gray-900/30 text-gray-400 px-2 py-0.5 rounded-full border border-gray-800/30">
69
- Audit Log
70
- </span>
80
+ <h1 className="text-2xl font-bold text-white lg:ml-0 ml-10">Audit Log</h1>
81
+ {/* Round 87: dropped {logs.length} header chip — r43 added
82
+ `All <count>` to the action-filter strip below, which
83
+ duplicated this value 40px away. Matches r86 /server-logs. */}
71
84
  </div>
72
85
 
73
- <div className="flex flex-wrap gap-3 mb-6">
74
- <select
75
- value={filterAction}
76
- onChange={e => setFilterAction(e.target.value)}
77
- className="bg-[#111128] border border-[#2a2a4a] rounded-lg px-3 py-2 text-sm text-white focus:border-blue-500/50 focus:outline-none"
78
- >
79
- <option value="">All actions</option>
80
- <option value="register">register</option>
81
- <option value="login">login</option>
82
- <option value="login_failed">login_failed</option>
83
- <option value="create_network">create_network</option>
84
- <option value="send_task">send_task</option>
85
- </select>
86
+ {/* Action filter chips (round 43) — same chip pattern as Tasks
87
+ status tabs / Overview agent filter. Each chip carries its
88
+ ACTION_STRIPE dot so the visual key matches the per-row left
89
+ rail. Counts come from the currently loaded log set. */}
90
+ <div className="mb-6 flex flex-wrap items-center gap-1 anet-tabstrip-wrap overflow-x-auto sm:overflow-x-visible">
91
+ {(() => {
92
+ const counts: Record<string, number> = {};
93
+ logs.forEach(l => { counts[l.action] = (counts[l.action] || 0) + 1; });
94
+ const chips: { key: string; label: string; dot?: string }[] = [
95
+ { key: '', label: 'All' },
96
+ { key: 'login', label: 'login', dot: ACTION_STRIPE.login },
97
+ { key: 'login_failed', label: 'login_failed', dot: ACTION_STRIPE.login_failed },
98
+ { key: 'register', label: 'register', dot: ACTION_STRIPE.register },
99
+ { key: 'create_network', label: 'create_network', dot: ACTION_STRIPE.create_network },
100
+ { key: 'send_task', label: 'send_task', dot: ACTION_STRIPE.send_task },
101
+ ];
102
+ return chips.map(c => {
103
+ const count = c.key === '' ? logs.length : counts[c.key] || 0;
104
+ const isActive = filterAction === c.key;
105
+ return (
106
+ <button
107
+ key={c.key || 'all'}
108
+ type="button"
109
+ onClick={() => setFilterAction(c.key)}
110
+ disabled={count === 0 && c.key !== ''}
111
+ className={`flex items-center gap-1.5 rounded-md px-2.5 py-1 text-xs transition-colors disabled:opacity-30 disabled:cursor-not-allowed shrink-0 whitespace-nowrap ${
112
+ isActive
113
+ ? 'bg-cyan-500/10 text-cyan-300 border border-cyan-500/30'
114
+ : 'text-gray-500 hover:text-gray-200 hover:bg-[#1a1a2a] border border-transparent'
115
+ }`}
116
+ >
117
+ {c.dot && <span aria-hidden className="inline-block w-1.5 h-1.5 rounded-full" style={{ backgroundColor: c.dot }} />}
118
+ <span>{c.label}</span>
119
+ <span className={`text-[10px] tabular-nums ${isActive ? 'text-cyan-400' : 'text-gray-600'}`}>{count}</span>
120
+ </button>
121
+ );
122
+ });
123
+ })()}
86
124
  </div>
87
125
 
88
126
  {error && (() => {
@@ -125,13 +163,23 @@ export default function LogsPage() {
125
163
  <EmptyState variant="logs" />
126
164
  ) : (
127
165
  <div className="space-y-2">
128
- {logs.map(log => (
129
- <div key={log.id} className="bg-[#111128] border border-[#2a2a4a] rounded-lg px-4 py-3 hover:border-[#3a3a5a] transition-colors">
166
+ {logs.map(log => {
167
+ const userName = log.username || log.user_id;
168
+ return (
169
+ <div key={log.id} className="relative bg-[#111128] border border-[#2a2a4a] rounded-lg pl-4 pr-4 py-3 hover:border-[#3a3a5a] transition-colors overflow-hidden">
170
+ {/* 2px left rail per action (round 33) — failed logins, token
171
+ rotations spike out of a wall of register/login rows. */}
172
+ <span
173
+ aria-hidden
174
+ className="absolute left-0 top-0 bottom-0 w-0.5"
175
+ style={{ backgroundColor: ACTION_STRIPE[log.action] || 'transparent' }}
176
+ />
130
177
  <div className="flex flex-wrap items-center gap-2 mb-1">
131
178
  <span className={`text-xs px-2 py-0.5 rounded-md border ${ACTION_COLORS[log.action] || 'bg-gray-500/10 text-gray-400 border-gray-500/20'}`}>
132
179
  {log.action}
133
180
  </span>
134
- <span className="text-sm text-blue-400 font-medium">{log.username || log.user_id}</span>
181
+ {userName && <AliasAvatar alias={userName} size={16} />}
182
+ <span className="text-sm text-gray-200 font-medium">{userName}</span>
135
183
  {log.target_type && (
136
184
  <>
137
185
  <span className="text-xs text-gray-600">&rarr;</span>
@@ -143,7 +191,8 @@ export default function LogsPage() {
143
191
  {log.detail && <div className="text-xs text-gray-500">{log.detail}</div>}
144
192
  {log.ip && log.ip !== 'unknown' && <div className="text-[10px] text-gray-700">IP: {log.ip}</div>}
145
193
  </div>
146
- ))}
194
+ );
195
+ })}
147
196
  </div>
148
197
  )}
149
198
  </div>
@@ -2,7 +2,7 @@
2
2
 
3
3
  import { useMemo, useState } from 'react';
4
4
  import { useMessages } from '../lib/hooks';
5
- import { timeAgo } from '../components/utils';
5
+ import { timeAgo, previewContent } from '../components/utils';
6
6
  import { EmptyState } from '../components/EmptyState';
7
7
  import { AliasAvatar } from '../components/AliasAvatar';
8
8
 
@@ -107,8 +107,16 @@ export default function MessagesPage() {
107
107
  <div className="min-h-screen bg-[#0a0a1a] text-gray-100 p-4 sm:p-6 font-mono">
108
108
  <div className="flex items-center gap-4 mb-6">
109
109
  <h1 className="text-2xl font-bold text-white lg:ml-0 ml-10">Messages</h1>
110
- <span className="text-xs bg-blue-900/30 text-blue-400 px-2 py-0.5 rounded-full border border-blue-800/30">
111
- {messages.length}
110
+ {/* Round 89: filter-aware chip. When search/type filter is active
111
+ the visible rows are filtered.length; the total loaded is
112
+ messages.length (capped at 200 by useMessages). Show
113
+ `filtered / total` so users notice how much the filter is
114
+ hiding. Same pattern as r88 /tasks chip. */}
115
+ <span
116
+ className="text-xs bg-blue-900/30 text-blue-400 px-2 py-0.5 rounded-full border border-blue-800/30 tabular-nums"
117
+ title={filtered.length < messages.length ? `Showing ${filtered.length} of ${messages.length} messages` : undefined}
118
+ >
119
+ {filtered.length < messages.length ? `${filtered.length} / ${messages.length}` : messages.length}
112
120
  </span>
113
121
  {filtered.length > 0 && (
114
122
  <button
@@ -129,6 +137,11 @@ export default function MessagesPage() {
129
137
  )}
130
138
  </div>
131
139
 
140
+ {/* Round 76: hide search + type filter + view toggle + Debug button
141
+ when there are no messages at all. Same r70-class fix carried
142
+ across /nodes (r74) and /tasks (r75). When at least one message
143
+ exists, the chrome reappears so users can still clear filters. */}
144
+ {messages.length > 0 && (
132
145
  <div className="flex flex-wrap gap-3 mb-3">
133
146
  <input
134
147
  type="text"
@@ -165,6 +178,7 @@ export default function MessagesPage() {
165
178
  {debug ? 'Debug ON' : 'Debug'}
166
179
  </button>
167
180
  </div>
181
+ )}
168
182
 
169
183
  {quickFromChips.length > 0 && (
170
184
  <div className="mb-6 flex flex-wrap gap-2">
@@ -206,17 +220,20 @@ export default function MessagesPage() {
206
220
  <div key={ci} className="bg-[#111128] border border-[#2a2a4a] rounded-xl overflow-hidden">
207
221
  <div className="px-4 py-2.5 border-b border-[#2a2a4a] flex items-center justify-between">
208
222
  <div className="flex items-center gap-2">
209
- <span className="text-sm text-cyan-300 font-medium">{conv.participants[0]}</span>
223
+ <AliasAvatar alias={conv.participants[0]} size={16} />
224
+ <span className="text-sm text-gray-200 font-medium">{conv.participants[0]}</span>
210
225
  <span className="text-gray-600 text-xs">↔</span>
211
- <span className="text-sm text-green-300 font-medium">{conv.participants[1]}</span>
226
+ <AliasAvatar alias={conv.participants[1]} size={16} />
227
+ <span className="text-sm text-gray-200 font-medium">{conv.participants[1]}</span>
212
228
  </div>
213
229
  <span className="text-[10px] text-gray-600">{conv.messages.length} messages</span>
214
230
  </div>
215
231
  <div className="px-4 py-2 space-y-2 max-h-64 overflow-y-auto">
216
232
  {conv.messages.map(m => (
217
233
  <div key={m.id} className="flex items-start gap-2 text-xs py-1">
218
- <span className={`shrink-0 font-medium ${m.from_alias === conv.participants[0] ? 'text-cyan-400' : 'text-green-400'}`}>{m.from_alias}</span>
219
- <span className="text-gray-400 flex-1">{m.content?.slice(0, 120) || '--'}</span>
234
+ {m.from_alias && <AliasAvatar alias={m.from_alias} size={14} />}
235
+ <span className="shrink-0 font-medium text-gray-200">{m.from_alias}</span>
236
+ <span className="text-gray-400 flex-1 truncate" title={m.content || ''}>{previewContent(m.content).slice(0, 120)}</span>
220
237
  <span className="text-[9px] text-gray-600 shrink-0">{timeAgo(m.created_at || '')}</span>
221
238
  </div>
222
239
  ))}
@@ -264,7 +281,11 @@ export default function MessagesPage() {
264
281
  {message.priority === 'high' && <span className="text-xs text-red-400">HIGH</span>}
265
282
  <span className="ml-auto text-xs text-gray-500">{message.created_at ? timeAgo(message.created_at) : '--'}</span>
266
283
  </div>
267
- <div className="whitespace-pre-wrap text-sm leading-relaxed text-gray-200">
284
+ {/* Round 79: break-words + overflow-wrap:anywhere so
285
+ long unbroken runs (URLs, ASCII rules like
286
+ `═══════════════`) wrap instead of pushing the
287
+ chat bubble past the mobile viewport. */}
288
+ <div className="whitespace-pre-wrap break-words [overflow-wrap:anywhere] text-sm leading-relaxed text-gray-200">
268
289
  {renderHighlighted(message.content, search)}
269
290
  </div>
270
291
  </div>
@@ -295,7 +316,11 @@ export default function MessagesPage() {
295
316
  </div>
296
317
  )}
297
318
 
298
- <div className="whitespace-pre-wrap text-sm leading-relaxed text-gray-200">
319
+ {/* Round 79: break-words + overflow-wrap:anywhere so
320
+ long unbroken runs (URLs, ASCII rules like
321
+ `═══════════════`) wrap instead of pushing the
322
+ chat bubble past the mobile viewport. */}
323
+ <div className="whitespace-pre-wrap break-words [overflow-wrap:anywhere] text-sm leading-relaxed text-gray-200">
299
324
  {renderHighlighted(message.content, search)}
300
325
  </div>
301
326