@sleep2agi/agent-network-dashboard 0.5.7-preview.5 → 0.5.7-preview.66

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 (376) hide show
  1. package/.next/BUILD_ID +1 -1
  2. package/.next/app-path-routes-manifest.json +0 -1
  3. package/.next/build-manifest.json +3 -3
  4. package/.next/diagnostics/route-bundle-stats.json +65 -65
  5. package/.next/fallback-build-manifest.json +3 -3
  6. package/.next/prerender-manifest.json +3 -3
  7. package/.next/routes-manifest.json +0 -6
  8. package/.next/server/app/_global-error.html +1 -1
  9. package/.next/server/app/_global-error.rsc +1 -1
  10. package/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  11. package/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  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/next-font-manifest.json +2 -1
  16. package/.next/server/app/_not-found/page.js +1 -1
  17. package/.next/server/app/_not-found/page.js.nft.json +1 -1
  18. package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  19. package/.next/server/app/_not-found.html +4 -4
  20. package/.next/server/app/_not-found.rsc +16 -16
  21. package/.next/server/app/_not-found.segments/_full.segment.rsc +16 -16
  22. package/.next/server/app/_not-found.segments/_head.segment.rsc +4 -4
  23. package/.next/server/app/_not-found.segments/_index.segment.rsc +9 -9
  24. package/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +2 -2
  25. package/.next/server/app/_not-found.segments/_not-found.segment.rsc +3 -3
  26. package/.next/server/app/_not-found.segments/_tree.segment.rsc +3 -3
  27. package/.next/server/app/admin/page/next-font-manifest.json +2 -1
  28. package/.next/server/app/admin/page.js +1 -1
  29. package/.next/server/app/admin/page.js.nft.json +1 -1
  30. package/.next/server/app/admin/page_client-reference-manifest.js +1 -1
  31. package/.next/server/app/admin.html +4 -4
  32. package/.next/server/app/admin.rsc +20 -19
  33. package/.next/server/app/admin.segments/_full.segment.rsc +20 -19
  34. package/.next/server/app/admin.segments/_head.segment.rsc +4 -4
  35. package/.next/server/app/admin.segments/_index.segment.rsc +9 -9
  36. package/.next/server/app/admin.segments/_tree.segment.rsc +5 -4
  37. package/.next/server/app/admin.segments/admin/__PAGE__.segment.rsc +4 -4
  38. package/.next/server/app/admin.segments/admin.segment.rsc +3 -3
  39. package/.next/server/app/index.html +4 -4
  40. package/.next/server/app/index.rsc +20 -19
  41. package/.next/server/app/index.segments/__PAGE__.segment.rsc +4 -4
  42. package/.next/server/app/index.segments/_full.segment.rsc +20 -19
  43. package/.next/server/app/index.segments/_head.segment.rsc +4 -4
  44. package/.next/server/app/index.segments/_index.segment.rsc +9 -9
  45. package/.next/server/app/index.segments/_tree.segment.rsc +5 -4
  46. package/.next/server/app/login/page/next-font-manifest.json +2 -1
  47. package/.next/server/app/login/page.js +1 -1
  48. package/.next/server/app/login/page.js.nft.json +1 -1
  49. package/.next/server/app/login/page_client-reference-manifest.js +1 -1
  50. package/.next/server/app/login.html +2 -2
  51. package/.next/server/app/login.rsc +20 -19
  52. package/.next/server/app/login.segments/_full.segment.rsc +20 -19
  53. package/.next/server/app/login.segments/_head.segment.rsc +4 -4
  54. package/.next/server/app/login.segments/_index.segment.rsc +9 -9
  55. package/.next/server/app/login.segments/_tree.segment.rsc +5 -4
  56. package/.next/server/app/login.segments/login/__PAGE__.segment.rsc +4 -4
  57. package/.next/server/app/login.segments/login.segment.rsc +3 -3
  58. package/.next/server/app/logs/page/next-font-manifest.json +2 -1
  59. package/.next/server/app/logs/page.js +1 -1
  60. package/.next/server/app/logs/page.js.nft.json +1 -1
  61. package/.next/server/app/logs/page_client-reference-manifest.js +1 -1
  62. package/.next/server/app/logs.html +4 -4
  63. package/.next/server/app/logs.rsc +20 -19
  64. package/.next/server/app/logs.segments/_full.segment.rsc +20 -19
  65. package/.next/server/app/logs.segments/_head.segment.rsc +4 -4
  66. package/.next/server/app/logs.segments/_index.segment.rsc +9 -9
  67. package/.next/server/app/logs.segments/_tree.segment.rsc +5 -4
  68. package/.next/server/app/logs.segments/logs/__PAGE__.segment.rsc +4 -4
  69. package/.next/server/app/logs.segments/logs.segment.rsc +3 -3
  70. package/.next/server/app/manifest.webmanifest.body +1 -1
  71. package/.next/server/app/messages/page/next-font-manifest.json +2 -1
  72. package/.next/server/app/messages/page.js +1 -1
  73. package/.next/server/app/messages/page.js.nft.json +1 -1
  74. package/.next/server/app/messages/page_client-reference-manifest.js +1 -1
  75. package/.next/server/app/messages.html +4 -4
  76. package/.next/server/app/messages.rsc +20 -19
  77. package/.next/server/app/messages.segments/_full.segment.rsc +20 -19
  78. package/.next/server/app/messages.segments/_head.segment.rsc +4 -4
  79. package/.next/server/app/messages.segments/_index.segment.rsc +9 -9
  80. package/.next/server/app/messages.segments/_tree.segment.rsc +5 -4
  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/next-font-manifest.json +2 -1
  84. package/.next/server/app/node/page.js +1 -1
  85. package/.next/server/app/node/page.js.nft.json +1 -1
  86. package/.next/server/app/node/page_client-reference-manifest.js +1 -1
  87. package/.next/server/app/node.html +4 -4
  88. package/.next/server/app/node.rsc +20 -19
  89. package/.next/server/app/node.segments/_full.segment.rsc +20 -19
  90. package/.next/server/app/node.segments/_head.segment.rsc +4 -4
  91. package/.next/server/app/node.segments/_index.segment.rsc +9 -9
  92. package/.next/server/app/node.segments/_tree.segment.rsc +5 -4
  93. package/.next/server/app/node.segments/node/__PAGE__.segment.rsc +4 -4
  94. package/.next/server/app/node.segments/node.segment.rsc +3 -3
  95. package/.next/server/app/nodes/page/next-font-manifest.json +2 -1
  96. package/.next/server/app/nodes/page.js +1 -1
  97. package/.next/server/app/nodes/page.js.nft.json +1 -1
  98. package/.next/server/app/nodes/page_client-reference-manifest.js +1 -1
  99. package/.next/server/app/nodes.html +4 -4
  100. package/.next/server/app/nodes.rsc +20 -19
  101. package/.next/server/app/nodes.segments/_full.segment.rsc +20 -19
  102. package/.next/server/app/nodes.segments/_head.segment.rsc +4 -4
  103. package/.next/server/app/nodes.segments/_index.segment.rsc +9 -9
  104. package/.next/server/app/nodes.segments/_tree.segment.rsc +5 -4
  105. package/.next/server/app/nodes.segments/nodes/__PAGE__.segment.rsc +4 -4
  106. package/.next/server/app/nodes.segments/nodes.segment.rsc +3 -3
  107. package/.next/server/app/page/next-font-manifest.json +2 -1
  108. package/.next/server/app/page.js +1 -1
  109. package/.next/server/app/page.js.nft.json +1 -1
  110. package/.next/server/app/page_client-reference-manifest.js +1 -1
  111. package/.next/server/app/server-logs/page/next-font-manifest.json +2 -1
  112. package/.next/server/app/server-logs/page.js +1 -1
  113. package/.next/server/app/server-logs/page.js.nft.json +1 -1
  114. package/.next/server/app/server-logs/page_client-reference-manifest.js +1 -1
  115. package/.next/server/app/server-logs.html +4 -4
  116. package/.next/server/app/server-logs.rsc +20 -19
  117. package/.next/server/app/server-logs.segments/_full.segment.rsc +20 -19
  118. package/.next/server/app/server-logs.segments/_head.segment.rsc +4 -4
  119. package/.next/server/app/server-logs.segments/_index.segment.rsc +9 -9
  120. package/.next/server/app/server-logs.segments/_tree.segment.rsc +5 -4
  121. package/.next/server/app/server-logs.segments/server-logs/__PAGE__.segment.rsc +4 -4
  122. package/.next/server/app/server-logs.segments/server-logs.segment.rsc +3 -3
  123. package/.next/server/app/servers/page/next-font-manifest.json +2 -1
  124. package/.next/server/app/servers/page.js +1 -1
  125. package/.next/server/app/servers/page.js.nft.json +1 -1
  126. package/.next/server/app/servers/page_client-reference-manifest.js +1 -1
  127. package/.next/server/app/servers.html +4 -4
  128. package/.next/server/app/servers.rsc +20 -19
  129. package/.next/server/app/servers.segments/_full.segment.rsc +20 -19
  130. package/.next/server/app/servers.segments/_head.segment.rsc +4 -4
  131. package/.next/server/app/servers.segments/_index.segment.rsc +9 -9
  132. package/.next/server/app/servers.segments/_tree.segment.rsc +5 -4
  133. package/.next/server/app/servers.segments/servers/__PAGE__.segment.rsc +4 -4
  134. package/.next/server/app/servers.segments/servers.segment.rsc +3 -3
  135. package/.next/server/app/settings/networks/page/next-font-manifest.json +2 -1
  136. package/.next/server/app/settings/networks/page.js +1 -1
  137. package/.next/server/app/settings/networks/page.js.nft.json +1 -1
  138. package/.next/server/app/settings/networks/page_client-reference-manifest.js +1 -1
  139. package/.next/server/app/settings/networks.html +4 -4
  140. package/.next/server/app/settings/networks.rsc +20 -19
  141. package/.next/server/app/settings/networks.segments/_full.segment.rsc +20 -19
  142. package/.next/server/app/settings/networks.segments/_head.segment.rsc +4 -4
  143. package/.next/server/app/settings/networks.segments/_index.segment.rsc +9 -9
  144. package/.next/server/app/settings/networks.segments/_tree.segment.rsc +5 -4
  145. package/.next/server/app/settings/networks.segments/settings/networks/__PAGE__.segment.rsc +4 -4
  146. package/.next/server/app/settings/networks.segments/settings/networks.segment.rsc +3 -3
  147. package/.next/server/app/settings/networks.segments/settings.segment.rsc +3 -3
  148. package/.next/server/app/settings/page/next-font-manifest.json +2 -1
  149. package/.next/server/app/settings/page.js +1 -1
  150. package/.next/server/app/settings/page.js.nft.json +1 -1
  151. package/.next/server/app/settings/page_client-reference-manifest.js +1 -1
  152. package/.next/server/app/settings/tokens/page/next-font-manifest.json +2 -1
  153. package/.next/server/app/settings/tokens/page.js +1 -1
  154. package/.next/server/app/settings/tokens/page.js.nft.json +1 -1
  155. package/.next/server/app/settings/tokens/page_client-reference-manifest.js +1 -1
  156. package/.next/server/app/settings/tokens.html +4 -4
  157. package/.next/server/app/settings/tokens.rsc +20 -19
  158. package/.next/server/app/settings/tokens.segments/_full.segment.rsc +20 -19
  159. package/.next/server/app/settings/tokens.segments/_head.segment.rsc +4 -4
  160. package/.next/server/app/settings/tokens.segments/_index.segment.rsc +9 -9
  161. package/.next/server/app/settings/tokens.segments/_tree.segment.rsc +5 -4
  162. package/.next/server/app/settings/tokens.segments/settings/tokens/__PAGE__.segment.rsc +4 -4
  163. package/.next/server/app/settings/tokens.segments/settings/tokens.segment.rsc +3 -3
  164. package/.next/server/app/settings/tokens.segments/settings.segment.rsc +3 -3
  165. package/.next/server/app/settings.html +4 -4
  166. package/.next/server/app/settings.rsc +20 -19
  167. package/.next/server/app/settings.segments/_full.segment.rsc +20 -19
  168. package/.next/server/app/settings.segments/_head.segment.rsc +4 -4
  169. package/.next/server/app/settings.segments/_index.segment.rsc +9 -9
  170. package/.next/server/app/settings.segments/_tree.segment.rsc +5 -4
  171. package/.next/server/app/settings.segments/settings/__PAGE__.segment.rsc +4 -4
  172. package/.next/server/app/settings.segments/settings.segment.rsc +3 -3
  173. package/.next/server/app/tasks/[id]/page/next-font-manifest.json +2 -1
  174. package/.next/server/app/tasks/[id]/page.js +1 -1
  175. package/.next/server/app/tasks/[id]/page.js.nft.json +1 -1
  176. package/.next/server/app/tasks/[id]/page_client-reference-manifest.js +1 -1
  177. package/.next/server/app/tasks/page/next-font-manifest.json +2 -1
  178. package/.next/server/app/tasks/page.js +1 -1
  179. package/.next/server/app/tasks/page.js.nft.json +1 -1
  180. package/.next/server/app/tasks/page_client-reference-manifest.js +1 -1
  181. package/.next/server/app/tasks.html +4 -4
  182. package/.next/server/app/tasks.rsc +20 -19
  183. package/.next/server/app/tasks.segments/_full.segment.rsc +20 -19
  184. package/.next/server/app/tasks.segments/_head.segment.rsc +4 -4
  185. package/.next/server/app/tasks.segments/_index.segment.rsc +9 -9
  186. package/.next/server/app/tasks.segments/_tree.segment.rsc +5 -4
  187. package/.next/server/app/tasks.segments/tasks/__PAGE__.segment.rsc +4 -4
  188. package/.next/server/app/tasks.segments/tasks.segment.rsc +3 -3
  189. package/.next/server/app-paths-manifest.json +0 -1
  190. package/.next/server/chunks/00jm_next_dist_0ju_ux9._.js +1 -1
  191. package/.next/server/chunks/00jm_next_dist_0ju_ux9._.js.map +1 -1
  192. package/.next/server/chunks/ssr/[root-of-the-server]__030vg4n._.js +1 -1
  193. package/.next/server/chunks/ssr/[root-of-the-server]__030vg4n._.js.map +1 -1
  194. package/.next/server/chunks/ssr/[root-of-the-server]__04gz75y._.js +3 -0
  195. package/.next/server/chunks/ssr/[root-of-the-server]__04gz75y._.js.map +1 -0
  196. package/.next/server/chunks/ssr/[root-of-the-server]__05kf31s._.js +3 -0
  197. package/.next/server/chunks/ssr/[root-of-the-server]__05kf31s._.js.map +1 -0
  198. package/.next/server/chunks/ssr/[root-of-the-server]__096ytyk._.js +3 -0
  199. package/.next/server/chunks/ssr/[root-of-the-server]__096ytyk._.js.map +1 -0
  200. package/.next/server/chunks/ssr/[root-of-the-server]__0fhoq8i._.js +1 -1
  201. package/.next/server/chunks/ssr/[root-of-the-server]__0fhoq8i._.js.map +1 -1
  202. package/.next/server/chunks/ssr/[root-of-the-server]__0u4-66w._.js +8 -0
  203. package/.next/server/chunks/ssr/[root-of-the-server]__0u4-66w._.js.map +1 -0
  204. package/.next/server/chunks/ssr/agent-network-dashboard_09kk21a._.js +3 -3
  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_0_870i8._.js +3 -0
  211. package/.next/server/chunks/ssr/agent-network-dashboard_app_0_870i8._.js.map +1 -0
  212. package/.next/server/chunks/ssr/agent-network-dashboard_app_0_d45-d._.js +1 -1
  213. package/.next/server/chunks/ssr/agent-network-dashboard_app_0_d45-d._.js.map +1 -1
  214. package/.next/server/chunks/ssr/agent-network-dashboard_app_0fjlnh~._.js +3 -0
  215. package/.next/server/chunks/ssr/agent-network-dashboard_app_0fjlnh~._.js.map +1 -0
  216. package/.next/server/chunks/ssr/agent-network-dashboard_app_0gd.4pc._.js +9 -0
  217. package/.next/server/chunks/ssr/agent-network-dashboard_app_0gd.4pc._.js.map +1 -0
  218. package/.next/server/chunks/ssr/agent-network-dashboard_app_0wn4jc5._.js +3 -0
  219. package/.next/server/chunks/ssr/agent-network-dashboard_app_0wn4jc5._.js.map +1 -0
  220. package/.next/server/chunks/ssr/agent-network-dashboard_app_0xgney8._.js +1 -1
  221. package/.next/server/chunks/ssr/agent-network-dashboard_app_0xgney8._.js.map +1 -1
  222. package/.next/server/chunks/ssr/agent-network-dashboard_app_10hjgv4._.js +1 -1
  223. package/.next/server/chunks/ssr/agent-network-dashboard_app_10hjgv4._.js.map +1 -1
  224. package/.next/server/chunks/ssr/agent-network-dashboard_app_12l4oto._.js +1 -1
  225. package/.next/server/chunks/ssr/agent-network-dashboard_app_12l4oto._.js.map +1 -1
  226. package/.next/server/chunks/ssr/agent-network-dashboard_app_components_0r7kb.o._.js +9 -0
  227. package/.next/server/chunks/ssr/agent-network-dashboard_app_components_0r7kb.o._.js.map +1 -0
  228. package/.next/server/chunks/ssr/agent-network-dashboard_app_servers_page_tsx_0jib5qm._.js +1 -1
  229. package/.next/server/chunks/ssr/agent-network-dashboard_app_servers_page_tsx_0jib5qm._.js.map +1 -1
  230. package/.next/server/chunks/ssr/agent-network-dashboard_app_tasks_page_tsx_0mwxy4z._.js +1 -1
  231. package/.next/server/chunks/ssr/agent-network-dashboard_app_tasks_page_tsx_0mwxy4z._.js.map +1 -1
  232. package/.next/server/middleware-build-manifest.js +3 -3
  233. package/.next/server/next-font-manifest.js +1 -1
  234. package/.next/server/next-font-manifest.json +30 -15
  235. package/.next/server/pages/404.html +4 -4
  236. package/.next/server/pages/500.html +1 -1
  237. package/.next/server/server-reference-manifest.js +1 -1
  238. package/.next/server/server-reference-manifest.json +1 -1
  239. package/.next/static/chunks/{0jp~cs9-zkmqa.js → 00b4y77vxfabl.js} +1 -1
  240. package/.next/static/chunks/00y0qgigxb62-.js +1 -0
  241. package/.next/static/chunks/049vx3qljs1tt.js +1 -0
  242. package/.next/static/chunks/04cf.98_cyxen.js +1 -0
  243. package/.next/static/chunks/066jf0nk75nic.css +2 -0
  244. package/.next/static/chunks/07sj5zwg46-5~.css +1 -0
  245. package/.next/static/chunks/0_bn~gcrgo.4n.js +1 -0
  246. package/.next/static/chunks/0g4d-_fi-d9hg.js +1 -0
  247. package/.next/static/chunks/0t4lpxu4ny9-3.js +1 -0
  248. package/.next/static/chunks/0vgrwqsgja19l.js +1 -0
  249. package/.next/static/chunks/0wz0122ym_gr3.js +1 -0
  250. package/.next/static/chunks/0xxx7yeapw~2a.js +1 -0
  251. package/.next/static/chunks/0y5gol09tlu63.js +1 -0
  252. package/.next/static/chunks/143g3n8za083f.js +7 -0
  253. package/.next/static/chunks/149a4l50_3vw-.js +7 -0
  254. package/.next/static/chunks/14lac~_cpjlh..js +1 -0
  255. package/.next/static/chunks/152_p6jt7txp6.js +1 -0
  256. package/.next/static/chunks/165v74i3j-wk0.js +1 -0
  257. package/.next/static/chunks/16glr1c4nc85n.js +4 -0
  258. package/.next/static/chunks/17-7ama~oijou.js +1 -0
  259. package/.next/static/media/4fa387ec64143e14-s.0wkzw~je483f-.woff2 +0 -0
  260. package/.next/static/media/53b9e256198e5412-s.0-wfv7uh4i7h9.woff2 +0 -0
  261. package/.next/static/media/5ce348bf30bf5439-s.0zgw-jeven.3w.woff2 +0 -0
  262. package/.next/static/media/6306c77e7c8268e4-s.0rhz0arwfsn~5.woff2 +0 -0
  263. package/.next/static/media/7178b3e590c64307-s.0nx0ww8fni_q3.woff2 +0 -0
  264. package/.next/static/media/797e433ab948586e-s.p.08e28id.o-okb.woff2 +0 -0
  265. package/.next/static/media/7d817b4c03b0c5f1-s.0l76wvqk9d84w.woff2 +0 -0
  266. package/.next/static/media/8a480f0b521d4e75-s.0jzbimsg8vl84.woff2 +0 -0
  267. package/.next/static/media/bbc41e54d2fcbd21-s.0k4k9394f2q-k.woff2 +0 -0
  268. package/.next/static/media/caa3a2e1cccd8315-s.p.09~u27dqhyhd6.woff2 +0 -0
  269. package/.next/static/media/fef07dbb0973bf53-s.12tyk43_3sh9u.woff2 +0 -0
  270. package/.next/trace +2 -2
  271. package/.next/trace-build +1 -1
  272. package/.next/types/routes.d.ts +1 -2
  273. package/.next/types/validator.ts +0 -9
  274. package/app/admin/page.tsx +53 -38
  275. package/app/components/AgentCard.tsx +38 -17
  276. package/app/components/AppShell.tsx +7 -1
  277. package/app/components/ChatPopover.tsx +1 -1
  278. package/app/components/CollapsibleSearch.tsx +127 -0
  279. package/app/components/CommandCenter.tsx +14 -4
  280. package/app/components/CommandPalette.tsx +6 -6
  281. package/app/components/DispatchPanel.tsx +13 -10
  282. package/app/components/EmptyState.tsx +11 -4
  283. package/app/components/HealthBanner.tsx +28 -4
  284. package/app/components/HelpOverlay.tsx +4 -7
  285. package/app/components/LoadingSkeleton.tsx +31 -21
  286. package/app/components/MobileNav.tsx +28 -21
  287. package/app/components/Sidebar.tsx +30 -23
  288. package/app/components/StatsBar.tsx +40 -42
  289. package/app/components/TaskChatPanel.tsx +19 -5
  290. package/app/components/TaskDrawer.tsx +9 -7
  291. package/app/components/ThemeSwitcher.tsx +15 -79
  292. package/app/components/TopoGraph.tsx +31 -21
  293. package/app/components/UserBar.tsx +5 -5
  294. package/app/globals.css +1757 -1776
  295. package/app/layout.tsx +37 -4
  296. package/app/lib/hooks.ts +0 -5
  297. package/app/lib/status.ts +24 -17
  298. package/app/login/page.tsx +7 -7
  299. package/app/logs/page.tsx +12 -6
  300. package/app/manifest.ts +2 -2
  301. package/app/messages/page.tsx +84 -57
  302. package/app/node/page.tsx +27 -17
  303. package/app/nodes/page.tsx +62 -49
  304. package/app/page.tsx +40 -269
  305. package/app/server-logs/page.tsx +40 -14
  306. package/app/servers/page.tsx +33 -12
  307. package/app/settings/networks/page.tsx +17 -15
  308. package/app/settings/page.tsx +90 -95
  309. package/app/settings/tokens/page.tsx +5 -5
  310. package/app/tasks/[id]/page.tsx +10 -10
  311. package/app/tasks/page.tsx +58 -34
  312. package/bin/start.js +0 -0
  313. package/package.json +1 -1
  314. package/public/favicon.svg +1 -1
  315. package/public/manifest.webmanifest +24 -0
  316. package/public/robots.txt +7 -0
  317. package/.next/server/app/api/hub/license/route/app-paths-manifest.json +0 -3
  318. package/.next/server/app/api/hub/license/route/build-manifest.json +0 -9
  319. package/.next/server/app/api/hub/license/route/server-reference-manifest.json +0 -4
  320. package/.next/server/app/api/hub/license/route.js +0 -7
  321. package/.next/server/app/api/hub/license/route.js.map +0 -5
  322. package/.next/server/app/api/hub/license/route.js.nft.json +0 -1
  323. package/.next/server/app/api/hub/license/route_client-reference-manifest.js +0 -3
  324. package/.next/server/chunks/0ykm__next-internal_server_app_api_hub_license_route_actions_0a4.fuh.js +0 -3
  325. package/.next/server/chunks/0ykm__next-internal_server_app_api_hub_license_route_actions_0a4.fuh.js.map +0 -1
  326. package/.next/server/chunks/[root-of-the-server]__0rovr5-._.js +0 -3
  327. package/.next/server/chunks/[root-of-the-server]__0rovr5-._.js.map +0 -1
  328. package/.next/server/chunks/ssr/[root-of-the-server]__0lu1wok._.js +0 -8
  329. package/.next/server/chunks/ssr/[root-of-the-server]__0lu1wok._.js.map +0 -1
  330. package/.next/server/chunks/ssr/[root-of-the-server]__0nw~zhp._.js +0 -3
  331. package/.next/server/chunks/ssr/[root-of-the-server]__0nw~zhp._.js.map +0 -1
  332. package/.next/server/chunks/ssr/[root-of-the-server]__0sv~g.o._.js +0 -3
  333. package/.next/server/chunks/ssr/[root-of-the-server]__0sv~g.o._.js.map +0 -1
  334. package/.next/server/chunks/ssr/[root-of-the-server]__11fu-5m._.js +0 -3
  335. package/.next/server/chunks/ssr/[root-of-the-server]__11fu-5m._.js.map +0 -1
  336. package/.next/server/chunks/ssr/agent-network-dashboard_app_057q.ne._.js +0 -3
  337. package/.next/server/chunks/ssr/agent-network-dashboard_app_057q.ne._.js.map +0 -1
  338. package/.next/server/chunks/ssr/agent-network-dashboard_app_0i3759l._.js +0 -3
  339. package/.next/server/chunks/ssr/agent-network-dashboard_app_0i3759l._.js.map +0 -1
  340. package/.next/server/chunks/ssr/agent-network-dashboard_app_1153xeb._.js +0 -9
  341. package/.next/server/chunks/ssr/agent-network-dashboard_app_1153xeb._.js.map +0 -1
  342. package/.next/server/chunks/ssr/agent-network-dashboard_app_components_0s5uqlp._.js +0 -9
  343. package/.next/server/chunks/ssr/agent-network-dashboard_app_components_0s5uqlp._.js.map +0 -1
  344. package/.next/server/chunks/ssr/agent-network-dashboard_app_server-logs_page_tsx_0dg.l_8._.js +0 -3
  345. package/.next/server/chunks/ssr/agent-network-dashboard_app_server-logs_page_tsx_0dg.l_8._.js.map +0 -1
  346. package/.next/static/chunks/0-mpa_947ipeq.js +0 -1
  347. package/.next/static/chunks/0.t1evm65itbw.js +0 -1
  348. package/.next/static/chunks/03~5pxwbxxw-b.js +0 -1
  349. package/.next/static/chunks/04~fkia6-79k3.js +0 -1
  350. package/.next/static/chunks/0561vp5-q5.zp.js +0 -1
  351. package/.next/static/chunks/05uk96gc~9mni.js +0 -1
  352. package/.next/static/chunks/0a.9~-nf0gpec.js +0 -1
  353. package/.next/static/chunks/0az0wa3gxme68.js +0 -1
  354. package/.next/static/chunks/0dq6wv-e0vk_o.css +0 -1
  355. package/.next/static/chunks/0gi_03g-uxj0r.js +0 -1
  356. package/.next/static/chunks/0im751o4n61c7.js +0 -1
  357. package/.next/static/chunks/0inql3s9ldyx5.js +0 -1
  358. package/.next/static/chunks/0ku0fjqlm9mca.js +0 -1
  359. package/.next/static/chunks/0nqm.7w9_inwd.js +0 -7
  360. package/.next/static/chunks/13yktdzuatx3d.js +0 -1
  361. package/.next/static/chunks/15-ltfhot3b4n.js +0 -7
  362. package/.next/static/chunks/15qxef.ilfysw.js +0 -4
  363. package/.next/static/chunks/17sxlwlx5fhrp.css +0 -1
  364. package/.next/static/chunks/181u38qblp8lz.js +0 -1
  365. package/.next/static/media/4fa387ec64143e14-s.0.qu-9752pffj.woff2 +0 -0
  366. package/.next/static/media/5ce348bf30bf5439-s.0ee55_hj9qcer.woff2 +0 -0
  367. package/.next/static/media/6306c77e7c8268e4-s.0mao5jbfbduzp.woff2 +0 -0
  368. package/.next/static/media/797e433ab948586e-s.p.09zddjkbdep5a.woff2 +0 -0
  369. package/.next/static/media/7d817b4c03b0c5f1-s.0uzt.a6d44yda.woff2 +0 -0
  370. package/.next/static/media/bbc41e54d2fcbd21-s.0mvwgmnhv29no.woff2 +0 -0
  371. package/app/api/hub/license/route.ts +0 -33
  372. package/app/components/BroadcastBar.tsx +0 -84
  373. package/app/components/InboxPanel.tsx +0 -36
  374. /package/.next/static/{e-lUTefNl8edrYCV4yWtG → 2dHfsg3G4Q4tXXzlz3hFv}/_buildManifest.js +0 -0
  375. /package/.next/static/{e-lUTefNl8edrYCV4yWtG → 2dHfsg3G4Q4tXXzlz3hFv}/_clientMiddlewareManifest.js +0 -0
  376. /package/.next/static/{e-lUTefNl8edrYCV4yWtG → 2dHfsg3G4Q4tXXzlz3hFv}/_ssgManifest.js +0 -0
package/app/layout.tsx CHANGED
@@ -1,11 +1,18 @@
1
1
  import type { Metadata, Viewport } from "next";
2
- import { Geist_Mono } from "next/font/google";
2
+ import { Geist, Geist_Mono } from "next/font/google";
3
3
  import "./globals.css";
4
4
  import { AppShell } from "./components/AppShell";
5
5
  import { NetworkProvider } from "./lib/network-context";
6
6
  import { ThemeProvider } from "./components/ThemeSwitcher";
7
7
  import { PwaInstaller } from "./components/PwaInstaller";
8
8
 
9
+ // #217 D1 (Vincent: OpenWebUI-style serious-product feel): UI text is
10
+ // sans; mono stays for code blocks, IDs and logs via .font-mono.
11
+ const geistSans = Geist({
12
+ variable: "--font-geist-sans",
13
+ subsets: ["latin"],
14
+ });
15
+
9
16
  const geistMono = Geist_Mono({
10
17
  variable: "--font-geist-mono",
11
18
  subsets: ["latin"],
@@ -20,7 +27,26 @@ export const metadata: Metadata = {
20
27
  statusBarStyle: "black-translucent",
21
28
  title: "Agent Network",
22
29
  },
23
- icons: { icon: '/favicon.svg' },
30
+ // R26 of #190: Next.js 16 renders `mobile-web-app-capable` (the modern
31
+ // standardized meta) but NOT the legacy `apple-mobile-web-app-capable`.
32
+ // iOS Safari < 16.4 only checks the apple-prefixed name; without it,
33
+ // the dashboard won't install as a web app on those iOS versions and
34
+ // the statusBarStyle + apple-touch-icon (R24) are silently ignored.
35
+ // Emit the legacy alias via metadata.other for back-compat.
36
+ other: {
37
+ 'apple-mobile-web-app-capable': 'yes',
38
+ },
39
+ // R24 of #190: appleWebApp.capable above declares this is an iOS web
40
+ // app, but only `icon` was specified, leaving iOS Safari to fall back
41
+ // to a generic icon on Add-to-Home-Screen. iOS 15+ accepts SVG via
42
+ // `rel="apple-touch-icon" type="image/svg+xml"`; older iOS will fall
43
+ // back to the manifest icons (added R23) and then the generic. Reuse
44
+ // the existing sleep2agi-logo.svg — no new asset shipped.
45
+ icons: {
46
+ icon: [{ url: '/favicon.svg', type: 'image/svg+xml' }],
47
+ apple: [{ url: '/sleep2agi-logo.svg', type: 'image/svg+xml' }],
48
+ shortcut: '/favicon.svg',
49
+ },
24
50
  openGraph: {
25
51
  title: "Agent Network Dashboard",
26
52
  description: "Real-time monitoring dashboard for Agent Network nodes",
@@ -33,7 +59,14 @@ export const viewport: Viewport = {
33
59
  initialScale: 1,
34
60
  maximumScale: 5,
35
61
  userScalable: true,
36
- themeColor: "#0a0a1a",
62
+ themeColor: "#0b0b0d",
63
+ // R25 of #190: metadata.appleWebApp.statusBarStyle above is
64
+ // "black-translucent", which renders the iOS status bar as a
65
+ // transparent overlay above the page (rather than reserving its own
66
+ // strip). Without viewportFit: "cover" the resulting safe-area-inset
67
+ // env() values resolve to 0, so the HealthBanner gets occluded by
68
+ // the clock/battery row when the user opens the installed PWA.
69
+ viewportFit: "cover",
37
70
  };
38
71
 
39
72
  // Inline pre-paint script to apply persisted theme before React hydrates,
@@ -51,7 +84,7 @@ export default function RootLayout({
51
84
  children: React.ReactNode;
52
85
  }>) {
53
86
  return (
54
- <html lang="en" data-theme="cyber" className={`${geistMono.variable} h-full antialiased`}>
87
+ <html lang="en" data-theme="cyber" className={`${geistSans.variable} ${geistMono.variable} h-full antialiased`}>
55
88
  <head>
56
89
  <script dangerouslySetInnerHTML={{ __html: themeBootScript }} />
57
90
  </head>
package/app/lib/hooks.ts CHANGED
@@ -63,11 +63,6 @@ export function useStats() {
63
63
  return { stats: data?.ok ? data : null, error };
64
64
  }
65
65
 
66
- export function useLicense() {
67
- const { data, error } = useSWR('/api/hub/license', fetcher, { refreshInterval: 60000 });
68
- return { license: data?.ok ? data : null, error };
69
- }
70
-
71
66
  export function useMessages(limit = 100) {
72
67
  const { networkId } = useNetworkId();
73
68
  const { data, error, isLoading } = useSWR(
package/app/lib/status.ts CHANGED
@@ -23,39 +23,46 @@ export type TaskStatus = typeof TASK_STATUSES[number];
23
23
 
24
24
  /** Pill / chip background+text+border. Tailwind classes, not inlined hex,
25
25
  * because chips are static class names safe from purge. */
26
+ /** #217 D3 (OpenWebUI-style color restraint): the 9-hue rainbow is
27
+ * collapsed to a semantic triad — green = actively running, red =
28
+ * failed, gray = everything else (in-flight states in lighter gray,
29
+ * terminal states dimmer). Color now means something instead of
30
+ * decorating every enum value. */
26
31
  export const STATUS_CHIP_CLASS: Record<string, string> = {
27
32
  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',
33
+ delivered: 'bg-gray-500/10 text-gray-300 border-gray-500/20',
34
+ acked: 'bg-gray-500/10 text-gray-300 border-gray-500/20',
30
35
  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',
36
+ replied: 'bg-gray-500/10 text-gray-300 border-gray-500/20',
32
37
  closed: 'bg-gray-500/10 text-gray-500 border-gray-500/20',
33
38
  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',
39
+ cancelled: 'bg-gray-500/10 text-gray-500 border-gray-500/20',
40
+ expired: 'bg-gray-500/10 text-gray-500 border-gray-500/20',
36
41
  };
37
42
 
38
43
  /** Inline hex dots — used wherever Tailwind would purge dynamic class
39
44
  * names (`bg-${family}-400`). Style attribute carries the color. */
40
45
  export const STATUS_DOT_HEX: Record<string, string> = {
41
46
  created: '#9ca3af',
42
- delivered: '#60a5fa',
43
- acked: '#22d3ee',
47
+ delivered: '#9ca3af',
48
+ acked: '#9ca3af',
44
49
  running: '#4ade80',
45
- replied: '#a78bfa',
50
+ replied: '#9ca3af',
46
51
  closed: '#6b7280',
47
52
  failed: '#f87171',
48
- cancelled: '#facc15',
49
- expired: '#fb923c',
53
+ cancelled: '#6b7280',
54
+ expired: '#6b7280',
50
55
  };
51
56
 
52
57
  /** Session lifecycle (distinct from task lifecycle above). Shared by
53
58
  * /nodes status pills and /admin Online Sessions row chips so an
54
59
  * agent in `blocked` state reads the same color everywhere.
55
60
  * Round 91 — extracted from app/nodes/page.tsx. */
61
+ /** D3: idle drops from blue to gray — only working (green), blocked
62
+ * (amber, actionable) and error (red) earn color. */
56
63
  export const SESSION_STATUS_CHIP_CLASS: Record<string, string> = {
57
64
  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',
65
+ idle: 'bg-gray-500/10 text-gray-300 border-gray-500/20',
59
66
  blocked: 'bg-yellow-500/10 text-yellow-300 border-yellow-500/20',
60
67
  error: 'bg-red-500/10 text-red-300 border-red-500/20',
61
68
  offline: 'bg-gray-500/10 text-gray-500 border-gray-500/20',
@@ -65,7 +72,7 @@ export const SESSION_STATUS_CHIP_CLASS: Record<string, string> = {
65
72
  * would be too heavy — e.g. /node detail header status label. */
66
73
  export const SESSION_STATUS_TEXT_CLASS: Record<string, string> = {
67
74
  working: 'text-green-400',
68
- idle: 'text-blue-400',
75
+ idle: 'text-gray-400',
69
76
  blocked: 'text-yellow-400',
70
77
  error: 'text-red-400',
71
78
  offline: 'text-gray-500',
@@ -74,12 +81,12 @@ export const SESSION_STATUS_TEXT_CLASS: Record<string, string> = {
74
81
  /** Solid bar segment background for the Tasks distribution bar. */
75
82
  export const STATUS_BAR_CLASS: Record<string, string> = {
76
83
  created: 'bg-gray-500',
77
- delivered: 'bg-blue-500',
78
- acked: 'bg-cyan-500',
84
+ delivered: 'bg-gray-400',
85
+ acked: 'bg-gray-300',
79
86
  running: 'bg-green-500',
80
- replied: 'bg-purple-500',
87
+ replied: 'bg-gray-400',
81
88
  closed: 'bg-gray-600',
82
89
  failed: 'bg-red-500',
83
- cancelled: 'bg-yellow-500',
84
- expired: 'bg-orange-500',
90
+ cancelled: 'bg-gray-600',
91
+ expired: 'bg-gray-600',
85
92
  };
@@ -46,7 +46,7 @@ export default function LoginPage() {
46
46
  };
47
47
 
48
48
  return (
49
- <main className="min-h-screen bg-[#0a0a1a] text-gray-100 font-mono flex items-center justify-center relative overflow-hidden px-4 py-10 sm:py-16">
49
+ <main className="min-h-screen bg-[#0b0b0d] text-gray-100 flex items-center justify-center relative overflow-hidden px-4 py-10 sm:py-16">
50
50
  {/* Subtle off-grid background — restraint over AI-glow.
51
51
  Dark themes get a faint radial wash; light themes show a low-contrast
52
52
  dotted grid for surface texture without noise. */}
@@ -57,7 +57,7 @@ export default function LoginPage() {
57
57
  {/* Brand mark — uses the favicon 3-node mesh SVG which IS the
58
58
  agent-network concept (nodes + edges). Replaces the previous
59
59
  flat emerald square placeholder. */}
60
- <div className="inline-flex items-center justify-center w-16 h-16 mb-4 rounded-2xl bg-[#111128] border border-[#2a2a4a] anet-login-mark">
60
+ <div className="inline-flex items-center justify-center w-16 h-16 mb-4 rounded-2xl bg-[#161618] border border-[#26262b] anet-login-mark">
61
61
  <svg className="w-9 h-9" viewBox="0 0 32 32" aria-hidden>
62
62
  <circle cx="16" cy="16" r="10" fill="none" stroke="currentColor" strokeWidth="1.5" opacity="0.25" className="text-cyan-400 anet-login-mark-ring" />
63
63
  <line x1="16" y1="10" x2="10" y2="20" stroke="currentColor" strokeWidth="1" opacity="0.5" className="text-cyan-400 anet-login-mark-edge" />
@@ -77,7 +77,7 @@ export default function LoginPage() {
77
77
  </div>
78
78
 
79
79
  {/* Mode toggle */}
80
- <div className="flex rounded-lg border border-[#2a2a4a] bg-[#111128] p-1 mb-4">
80
+ <div className="flex rounded-lg border border-[#26262b] bg-[#161618] p-1 mb-4">
81
81
  {(['login', 'register'] as const).map(m => (
82
82
  <button key={m} type="button" onClick={() => { setMode(m); setError(''); }}
83
83
  className={`flex-1 rounded-md px-3 py-2 text-sm transition-colors ${mode === m ? 'bg-cyan-500/10 text-cyan-300' : 'text-gray-500 hover:text-gray-200'}`}>
@@ -86,13 +86,13 @@ export default function LoginPage() {
86
86
  ))}
87
87
  </div>
88
88
 
89
- <form onSubmit={submit} className="border border-[#2a2a4a] bg-[#111128]/80 backdrop-blur-sm rounded-xl p-6 shadow-2xl shadow-black/30">
89
+ <form onSubmit={submit} className="border border-[#26262b] bg-[#161618]/80 backdrop-blur-sm rounded-xl p-6 shadow-2xl shadow-black/30">
90
90
  <label htmlFor="username" className="block text-xs text-gray-500 mb-2 uppercase tracking-wider">
91
91
  Username
92
92
  </label>
93
93
  <input id="username" type="text" value={username} onChange={e => setUsername(e.target.value)} autoFocus
94
94
  placeholder="Enter username"
95
- 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 mb-4" />
95
+ className="w-full bg-[#0e0e10] border border-[#26262b] rounded-lg px-4 py-3 text-base sm: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 mb-4" />
96
96
 
97
97
  <label htmlFor="password" className="block text-xs text-gray-500 mb-2 uppercase tracking-wider">
98
98
  Password
@@ -100,13 +100,13 @@ export default function LoginPage() {
100
100
  <div className="relative">
101
101
  <input id="password" type={showPassword ? 'text' : 'password'} value={password} onChange={e => setPassword(e.target.value)}
102
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" />
103
+ className="w-full bg-[#0e0e10] border border-[#26262b] rounded-lg px-4 pr-11 py-3 text-base sm: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
104
  <button
105
105
  type="button"
106
106
  onClick={() => setShowPassword(s => !s)}
107
107
  tabIndex={-1}
108
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"
109
+ className="absolute inset-y-0 right-0 flex items-center justify-center min-w-[44px] px-3 text-gray-600 hover:text-gray-300 transition-colors"
110
110
  >
111
111
  {showPassword ? (
112
112
  <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round">
package/app/logs/page.tsx CHANGED
@@ -75,8 +75,10 @@ export default function LogsPage() {
75
75
  }, [fetchLogs]);
76
76
 
77
77
  return (
78
- <div className="min-h-screen bg-[#0a0a1a] text-gray-100 p-4 sm:p-6 font-mono">
79
- <div className="flex items-center gap-4 mb-6">
78
+ <div className="min-h-screen bg-[#0b0b0d] text-gray-100 p-4 sm:p-6">
79
+ {/* #209 R36: mobile vertical rhythm — same R28/R30/R31 pattern,
80
+ mb-6 → mb-4 sm:mb-6 here and on the action-filter strip below. */}
81
+ <div className="flex items-center gap-4 mb-4 sm:mb-6">
80
82
  <h1 className="text-2xl font-bold text-white lg:ml-0 ml-10">Audit Log</h1>
81
83
  {/* Round 87: dropped {logs.length} header chip — r43 added
82
84
  `All <count>` to the action-filter strip below, which
@@ -87,7 +89,7 @@ export default function LogsPage() {
87
89
  status tabs / Overview agent filter. Each chip carries its
88
90
  ACTION_STRIPE dot so the visual key matches the per-row left
89
91
  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">
92
+ <div className="mb-4 sm:mb-6 flex flex-wrap items-center gap-1 anet-tabstrip-wrap overflow-x-auto sm:overflow-x-visible">
91
93
  {(() => {
92
94
  const counts: Record<string, number> = {};
93
95
  logs.forEach(l => { counts[l.action] = (counts[l.action] || 0) + 1; });
@@ -111,7 +113,7 @@ export default function LogsPage() {
111
113
  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
114
  isActive
113
115
  ? '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'
116
+ : 'text-gray-500 hover:text-gray-200 hover:bg-[#1c1c1f] border border-transparent'
115
117
  }`}
116
118
  >
117
119
  {c.dot && <span aria-hidden className="inline-block w-1.5 h-1.5 rounded-full" style={{ backgroundColor: c.dot }} />}
@@ -162,11 +164,15 @@ export default function LogsPage() {
162
164
  ) : logs.length === 0 ? (
163
165
  <EmptyState variant="logs" />
164
166
  ) : (
165
- <div className="space-y-2">
167
+ /* R18 of #190 mobile polish: /logs was 28,791 px on 390 px
168
+ mobile; same dense-card pattern that R7/R8 hit on /nodes
169
+ and /tasks. Tighten card padding and inter-card gap on
170
+ mobile, sm:-gated so desktop stays comfortable. */
171
+ <div className="space-y-1 sm:space-y-2">
166
172
  {logs.map(log => {
167
173
  const userName = log.username || log.user_id;
168
174
  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">
175
+ <div key={log.id} className="relative bg-[#161618] border border-[#26262b] rounded-lg pl-3 pr-3 py-2 sm:pl-4 sm:pr-4 sm:py-3 hover:border-[#3a3a41] transition-colors overflow-hidden">
170
176
  {/* 2px left rail per action (round 33) — failed logins, token
171
177
  rotations spike out of a wall of register/login rows. */}
172
178
  <span
package/app/manifest.ts CHANGED
@@ -8,8 +8,8 @@ export default function manifest(): MetadataRoute.Manifest {
8
8
  start_url: '/',
9
9
  scope: '/',
10
10
  display: 'standalone',
11
- background_color: '#0a0a1a',
12
- theme_color: '#0a0a1a',
11
+ background_color: '#0b0b0d',
12
+ theme_color: '#0b0b0d',
13
13
  orientation: 'portrait',
14
14
  icons: [
15
15
  {
@@ -5,6 +5,7 @@ import { useMessages } from '../lib/hooks';
5
5
  import { timeAgo, previewContent } from '../components/utils';
6
6
  import { EmptyState } from '../components/EmptyState';
7
7
  import { AliasAvatar } from '../components/AliasAvatar';
8
+ import { useCollapsibleSearch } from '../components/CollapsibleSearch';
8
9
 
9
10
  interface MessageItem {
10
11
  id: string;
@@ -58,6 +59,14 @@ export default function MessagesPage() {
58
59
  const [search, setSearch] = useState('');
59
60
  const [debug, setDebug] = useState(false);
60
61
  const [viewMode, setViewMode] = useState<'timeline' | 'grouped'>('timeline');
62
+ // #209 R33→R34: WeChat-style magnifier-toggle search hook (shared with /nodes).
63
+ const searchCtl = useCollapsibleSearch({
64
+ value: search,
65
+ onChange: setSearch,
66
+ placeholder: 'Search from/to/content or use from:alias…',
67
+ label: 'Search messages',
68
+ enabled: messages.length > 0,
69
+ });
61
70
 
62
71
  const quickFromChips = useMemo(() => {
63
72
  const aliases = new Set<string>();
@@ -104,56 +113,64 @@ export default function MessagesPage() {
104
113
  }, [filtered]);
105
114
 
106
115
  return (
107
- <div className="min-h-screen bg-[#0a0a1a] text-gray-100 p-4 sm:p-6 font-mono">
108
- <div className="flex items-center gap-4 mb-6">
109
- <h1 className="text-2xl font-bold text-white lg:ml-0 ml-10">Messages</h1>
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}
120
- </span>
121
- {filtered.length > 0 && (
122
- <button
123
- onClick={() => {
124
- const md = filtered.map((m: MessageItem) =>
125
- `**${m.from_alias || '?'}** → ${m.to_alias || '?'} (${m.type || '?'}) — ${m.created_at || ''}\n\n${m.content || '--'}\n\n---`
126
- ).join('\n\n');
127
- const blob = new Blob([`# Messages Export\n\n${md}`], { type: 'text/markdown' });
128
- const url = URL.createObjectURL(blob);
129
- const a = document.createElement('a');
130
- a.href = url; a.download = `messages-${new Date().toISOString().slice(0,10)}.md`;
131
- a.click(); URL.revokeObjectURL(url);
132
- }}
133
- className="text-xs text-gray-500 hover:text-gray-300 border border-gray-700/50 px-2.5 py-1 rounded-lg transition-colors"
116
+ <div className="min-h-screen bg-[#0b0b0d] text-gray-100 p-4 sm:p-6">
117
+ {/* #209 R31 (mobile vertical rhythm — same pattern as R28/R30):
118
+ header row + quick-from chips row both mb-6 → mb-4 sm:mb-6.
119
+ #209 R33: header restructured to mirror /nodes R32 title
120
+ cluster left (Messages + count chip + Export MD), magnifier
121
+ circle right. Inline ~290 px search input was moved into the
122
+ collapsible row below. */}
123
+ <div className="flex items-center gap-4 mb-4 sm:mb-6">
124
+ <div className="flex items-center gap-3 min-w-0 flex-1">
125
+ <h1 className="text-2xl font-bold text-white lg:ml-0 ml-10">Messages</h1>
126
+ {/* Round 89: filter-aware chip. When search/type filter is active
127
+ the visible rows are filtered.length; the total loaded is
128
+ messages.length (capped at 200 by useMessages). Show
129
+ `filtered / total` so users notice how much the filter is
130
+ hiding. Same pattern as r88 /tasks chip. */}
131
+ <span
132
+ className="text-xs bg-blue-900/30 text-blue-400 px-2 py-0.5 rounded-full border border-blue-800/30 tabular-nums shrink-0"
133
+ title={filtered.length < messages.length ? `Showing ${filtered.length} of ${messages.length} messages` : undefined}
134
134
  >
135
- Export MD
136
- </button>
137
- )}
135
+ {filtered.length < messages.length ? `${filtered.length} / ${messages.length}` : messages.length}
136
+ </span>
137
+ {filtered.length > 0 && (
138
+ <button
139
+ onClick={() => {
140
+ const md = filtered.map((m: MessageItem) =>
141
+ `**${m.from_alias || '?'}** → ${m.to_alias || '?'} (${m.type || '?'}) — ${m.created_at || ''}\n\n${m.content || '--'}\n\n---`
142
+ ).join('\n\n');
143
+ const blob = new Blob([`# Messages Export\n\n${md}`], { type: 'text/markdown' });
144
+ const url = URL.createObjectURL(blob);
145
+ const a = document.createElement('a');
146
+ a.href = url; a.download = `messages-${new Date().toISOString().slice(0,10)}.md`;
147
+ a.click(); URL.revokeObjectURL(url);
148
+ }}
149
+ className="text-xs text-gray-500 hover:text-gray-300 border border-gray-700/50 px-2.5 py-1 rounded-lg transition-colors shrink-0"
150
+ >
151
+ Export MD
152
+ </button>
153
+ )}
154
+ </div>
155
+ <searchCtl.Button />
138
156
  </div>
139
157
 
158
+ {/* #209 R34: shared <CollapsibleSearch> component. enabled gate
159
+ handles the no-content case (button + row both hide). */}
160
+ <searchCtl.Row />
161
+
140
162
  {/* Round 76: hide search + type filter + view toggle + Debug button
141
163
  when there are no messages at all. Same r70-class fix carried
142
164
  across /nodes (r74) and /tasks (r75). When at least one message
143
165
  exists, the chrome reappears so users can still clear filters. */}
144
166
  {messages.length > 0 && (
145
167
  <div className="flex flex-wrap gap-3 mb-3">
146
- <input
147
- type="text"
148
- value={search}
149
- onChange={e => setSearch(e.target.value)}
150
- placeholder="Search from/to/content or use from:alias"
151
- className="bg-[#111128] border border-[#2a2a4a] rounded-lg px-3 py-2 text-sm text-white placeholder-gray-600 focus:border-blue-500/50 focus:outline-none w-full sm:w-72"
152
- />
168
+ {/* R33: inline search input moved to the top-right magnifier
169
+ toggle above. Type select + view-mode toggle + Debug stay. */}
153
170
  <select
154
171
  value={filterType}
155
172
  onChange={e => setFilterType(e.target.value)}
156
- className="bg-[#111128] border border-[#2a2a4a] rounded-lg px-3 py-2 text-sm text-white focus:border-blue-500/50 focus:outline-none"
173
+ className="bg-[#161618] border border-[#26262b] rounded-lg px-3 py-2 text-base sm:text-sm text-white focus:border-blue-500/50 focus:outline-none"
157
174
  >
158
175
  <option value="">All types</option>
159
176
  <option value="task">task</option>
@@ -161,7 +178,7 @@ export default function MessagesPage() {
161
178
  <option value="broadcast">broadcast</option>
162
179
  <option value="reply">reply</option>
163
180
  </select>
164
- <div className="flex rounded-lg border border-[#2a2a4a] bg-[#111128] p-0.5">
181
+ <div className="flex rounded-lg border border-[#26262b] bg-[#161618] p-0.5">
165
182
  {(['timeline', 'grouped'] as const).map(mode => (
166
183
  <button key={mode} type="button" onClick={() => setViewMode(mode)}
167
184
  className={`rounded-md px-2.5 py-1.5 text-xs transition-colors ${viewMode === mode ? 'bg-cyan-500/10 text-cyan-300' : 'text-gray-500 hover:text-gray-200'}`}>
@@ -180,17 +197,20 @@ export default function MessagesPage() {
180
197
  </div>
181
198
  )}
182
199
 
200
+ {/* #217 S8 (less is more): on phones the sender chips wrapped into
201
+ ~5 rows and pushed the first message below the fold. One
202
+ scrollable row on mobile; wrap returns from sm: up. */}
183
203
  {quickFromChips.length > 0 && (
184
- <div className="mb-6 flex flex-wrap gap-2">
204
+ <div className="mb-4 sm:mb-6 flex gap-2 overflow-x-auto whitespace-nowrap pb-1 scrollbar-thin sm:flex-wrap sm:overflow-visible sm:whitespace-normal sm:pb-0">
185
205
  {quickFromChips.map(alias => (
186
206
  <button
187
207
  key={alias}
188
208
  type="button"
189
209
  onClick={() => setSearch(`from:${alias}`)}
190
- className={`rounded-full border px-3 py-1 text-xs transition-colors ${
210
+ className={`shrink-0 rounded-full border px-3 py-1 text-xs transition-colors ${
191
211
  search === `from:${alias}`
192
212
  ? 'border-cyan-500/30 bg-cyan-500/10 text-cyan-300'
193
- : 'border-[#2a2a4a] bg-[#111128] text-gray-400 hover:text-gray-200'
213
+ : 'border-[#26262b] bg-[#161618] text-gray-400 hover:text-gray-200'
194
214
  }`}
195
215
  >
196
216
  from:{alias}
@@ -200,7 +220,7 @@ export default function MessagesPage() {
200
220
  <button
201
221
  type="button"
202
222
  onClick={() => setSearch('')}
203
- className="rounded-full border border-gray-700 px-3 py-1 text-xs text-gray-500 hover:text-gray-200"
223
+ className="shrink-0 rounded-full border border-gray-700 px-3 py-1 text-xs text-gray-500 hover:text-gray-200"
204
224
  >
205
225
  Clear
206
226
  </button>
@@ -217,8 +237,8 @@ export default function MessagesPage() {
217
237
  ) : viewMode === 'grouped' ? (
218
238
  <div className="space-y-4">
219
239
  {conversations.map((conv, ci) => (
220
- <div key={ci} className="bg-[#111128] border border-[#2a2a4a] rounded-xl overflow-hidden">
221
- <div className="px-4 py-2.5 border-b border-[#2a2a4a] flex items-center justify-between">
240
+ <div key={ci} className="bg-[#161618] border border-[#26262b] rounded-xl overflow-hidden">
241
+ <div className="px-4 py-2.5 border-b border-[#26262b] flex items-center justify-between">
222
242
  <div className="flex items-center gap-2">
223
243
  <AliasAvatar alias={conv.participants[0]} size={16} />
224
244
  <span className="text-sm text-gray-200 font-medium">{conv.participants[0]}</span>
@@ -260,19 +280,26 @@ export default function MessagesPage() {
260
280
 
261
281
  return (
262
282
  <div key={message.id}>
283
+ {/* R6 of #190 mobile polish: gap divider was my-4 (=16px
284
+ each side), and with multi-hour message lulls it
285
+ fired several times per session, eating ~32px each.
286
+ Halve it on mobile. */}
263
287
  {gapExceeded && (
264
- <div className="my-4 flex items-center gap-3">
265
- <div className="h-px flex-1 bg-[#2a2a4a]" />
288
+ <div className="my-2 sm:my-4 flex items-center gap-3">
289
+ <div className="h-px flex-1 bg-[#26262b]" />
266
290
  <div className="text-[11px] text-gray-600">{formatDividerLabel(message.created_at)}</div>
267
- <div className="h-px flex-1 bg-[#2a2a4a]" />
291
+ <div className="h-px flex-1 bg-[#26262b]" />
268
292
  </div>
269
293
  )}
270
294
 
271
- {/* Broadcasts span full width — no avatar gutter. */}
295
+ {/* Broadcasts span full width — no avatar gutter. R6 mobile:
296
+ tighter padding + tighter header margin + snug leading
297
+ on the content so each bubble is ~25-30% shorter at
298
+ 390px. Desktop unchanged from sm: up. */}
272
299
  {variant === 'broadcast' ? (
273
- <div className={samePrev ? 'mt-1' : 'mt-3'}>
274
- <div className="rounded-2xl border border-purple-500/20 bg-purple-500/10 px-4 py-3 shadow-sm w-full">
275
- <div className="mb-2 flex flex-wrap items-center gap-2">
300
+ <div className={samePrev ? 'mt-0.5 sm:mt-1' : 'mt-2 sm:mt-3'}>
301
+ <div className="rounded-2xl border border-purple-500/20 bg-purple-500/10 px-3 py-2 sm:px-4 sm:py-3 shadow-sm w-full">
302
+ <div className="mb-1 sm:mb-2 flex flex-wrap items-center gap-2">
276
303
  <span className={`text-xs px-2 py-0.5 rounded-md border ${TYPE_COLORS[message.type || ''] || 'bg-gray-500/10 text-gray-400 border-gray-500/20'}`}>
277
304
  {message.type || 'unknown'}
278
305
  </span>
@@ -285,24 +312,24 @@ export default function MessagesPage() {
285
312
  long unbroken runs (URLs, ASCII rules like
286
313
  `═══════════════`) wrap instead of pushing the
287
314
  chat bubble past the mobile viewport. */}
288
- <div className="whitespace-pre-wrap break-words [overflow-wrap:anywhere] text-sm leading-relaxed text-gray-200">
315
+ <div className="whitespace-pre-wrap break-words [overflow-wrap:anywhere] text-sm leading-snug sm:leading-relaxed text-gray-200">
289
316
  {renderHighlighted(message.content, search)}
290
317
  </div>
291
318
  </div>
292
319
  </div>
293
320
  ) : (
294
- <div className={`${samePrev ? 'mt-1' : 'mt-3'} flex gap-2 ${variant === 'outgoing' ? 'flex-row-reverse' : 'flex-row'}`}>
321
+ <div className={`${samePrev ? 'mt-0.5 sm:mt-1' : 'mt-2 sm:mt-3'} flex gap-2 ${variant === 'outgoing' ? 'flex-row-reverse' : 'flex-row'}`}>
295
322
  {/* Avatar gutter — fixed width keeps bubble columns aligned even on streaks */}
296
323
  <div className="w-8 shrink-0 pt-1">
297
324
  {!samePrev && <AliasAvatar alias={fromAlias} size={32} />}
298
325
  </div>
299
- <div className={`min-w-0 max-w-3xl rounded-2xl border px-4 py-3 shadow-sm ${
326
+ <div className={`min-w-0 max-w-3xl rounded-2xl border px-3 py-2 sm:px-4 sm:py-3 shadow-sm ${
300
327
  variant === 'outgoing'
301
328
  ? 'border-green-500/20 bg-green-500/10'
302
329
  : 'border-blue-500/20 bg-blue-500/10'
303
330
  }`}>
304
331
  {!samePrev && (
305
- <div className="mb-2 flex flex-wrap items-center gap-2">
332
+ <div className="mb-1 sm:mb-2 flex flex-wrap items-center gap-2">
306
333
  <span className={`text-xs px-2 py-0.5 rounded-md border ${TYPE_COLORS[message.type || ''] || 'bg-gray-500/10 text-gray-400 border-gray-500/20'}`}>
307
334
  {message.type || 'unknown'}
308
335
  </span>
@@ -320,7 +347,7 @@ export default function MessagesPage() {
320
347
  long unbroken runs (URLs, ASCII rules like
321
348
  `═══════════════`) wrap instead of pushing the
322
349
  chat bubble past the mobile viewport. */}
323
- <div className="whitespace-pre-wrap break-words [overflow-wrap:anywhere] text-sm leading-relaxed text-gray-200">
350
+ <div className="whitespace-pre-wrap break-words [overflow-wrap:anywhere] text-sm leading-snug sm:leading-relaxed text-gray-200">
324
351
  {renderHighlighted(message.content, search)}
325
352
  </div>
326
353