@sleep2agi/agent-network-dashboard 0.4.6-preview.26 → 0.4.6-preview.261

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 (459) hide show
  1. package/.next/BUILD_ID +1 -1
  2. package/.next/app-path-routes-manifest.json +1 -0
  3. package/.next/build-manifest.json +3 -3
  4. package/.next/diagnostics/route-bundle-stats.json +41 -41
  5. package/.next/fallback-build-manifest.json +3 -3
  6. package/.next/prerender-manifest.json +3 -3
  7. package/.next/routes-manifest.json +6 -0
  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_client-reference-manifest.js +1 -1
  16. package/.next/server/app/_not-found.html +2 -2
  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_client-reference-manifest.js +1 -1
  25. package/.next/server/app/admin.html +2 -2
  26. package/.next/server/app/admin.rsc +14 -14
  27. package/.next/server/app/admin.segments/_full.segment.rsc +14 -14
  28. package/.next/server/app/admin.segments/_head.segment.rsc +4 -4
  29. package/.next/server/app/admin.segments/_index.segment.rsc +7 -7
  30. package/.next/server/app/admin.segments/_tree.segment.rsc +2 -2
  31. package/.next/server/app/admin.segments/admin/__PAGE__.segment.rsc +4 -4
  32. package/.next/server/app/admin.segments/admin.segment.rsc +3 -3
  33. package/.next/server/app/api/hub/servers/route/app-paths-manifest.json +3 -0
  34. package/.next/server/app/api/hub/servers/route/build-manifest.json +9 -0
  35. package/.next/server/app/api/hub/servers/route/server-reference-manifest.json +4 -0
  36. package/.next/server/app/api/hub/servers/route.js +7 -0
  37. package/.next/server/app/api/hub/servers/route.js.map +5 -0
  38. package/.next/server/app/api/hub/servers/route.js.nft.json +1 -0
  39. package/.next/server/app/api/hub/servers/route_client-reference-manifest.js +3 -0
  40. package/.next/server/app/index.html +2 -2
  41. package/.next/server/app/index.rsc +14 -14
  42. package/.next/server/app/index.segments/__PAGE__.segment.rsc +4 -4
  43. package/.next/server/app/index.segments/_full.segment.rsc +14 -14
  44. package/.next/server/app/index.segments/_head.segment.rsc +4 -4
  45. package/.next/server/app/index.segments/_index.segment.rsc +7 -7
  46. package/.next/server/app/index.segments/_tree.segment.rsc +2 -2
  47. package/.next/server/app/login/page_client-reference-manifest.js +1 -1
  48. package/.next/server/app/login.html +2 -2
  49. package/.next/server/app/login.rsc +14 -14
  50. package/.next/server/app/login.segments/_full.segment.rsc +14 -14
  51. package/.next/server/app/login.segments/_head.segment.rsc +4 -4
  52. package/.next/server/app/login.segments/_index.segment.rsc +7 -7
  53. package/.next/server/app/login.segments/_tree.segment.rsc +2 -2
  54. package/.next/server/app/login.segments/login/__PAGE__.segment.rsc +4 -4
  55. package/.next/server/app/login.segments/login.segment.rsc +3 -3
  56. package/.next/server/app/logs/page_client-reference-manifest.js +1 -1
  57. package/.next/server/app/logs.html +2 -2
  58. package/.next/server/app/logs.rsc +14 -14
  59. package/.next/server/app/logs.segments/_full.segment.rsc +14 -14
  60. package/.next/server/app/logs.segments/_head.segment.rsc +4 -4
  61. package/.next/server/app/logs.segments/_index.segment.rsc +7 -7
  62. package/.next/server/app/logs.segments/_tree.segment.rsc +2 -2
  63. package/.next/server/app/logs.segments/logs/__PAGE__.segment.rsc +4 -4
  64. package/.next/server/app/logs.segments/logs.segment.rsc +3 -3
  65. package/.next/server/app/messages/page_client-reference-manifest.js +1 -1
  66. package/.next/server/app/messages.html +2 -2
  67. package/.next/server/app/messages.rsc +14 -14
  68. package/.next/server/app/messages.segments/_full.segment.rsc +14 -14
  69. package/.next/server/app/messages.segments/_head.segment.rsc +4 -4
  70. package/.next/server/app/messages.segments/_index.segment.rsc +7 -7
  71. package/.next/server/app/messages.segments/_tree.segment.rsc +2 -2
  72. package/.next/server/app/messages.segments/messages/__PAGE__.segment.rsc +4 -4
  73. package/.next/server/app/messages.segments/messages.segment.rsc +3 -3
  74. package/.next/server/app/node/page_client-reference-manifest.js +1 -1
  75. package/.next/server/app/node.html +2 -2
  76. package/.next/server/app/node.rsc +14 -14
  77. package/.next/server/app/node.segments/_full.segment.rsc +14 -14
  78. package/.next/server/app/node.segments/_head.segment.rsc +4 -4
  79. package/.next/server/app/node.segments/_index.segment.rsc +7 -7
  80. package/.next/server/app/node.segments/_tree.segment.rsc +2 -2
  81. package/.next/server/app/node.segments/node/__PAGE__.segment.rsc +4 -4
  82. package/.next/server/app/node.segments/node.segment.rsc +3 -3
  83. package/.next/server/app/nodes/page_client-reference-manifest.js +1 -1
  84. package/.next/server/app/nodes.html +2 -2
  85. package/.next/server/app/nodes.rsc +14 -14
  86. package/.next/server/app/nodes.segments/_full.segment.rsc +14 -14
  87. package/.next/server/app/nodes.segments/_head.segment.rsc +4 -4
  88. package/.next/server/app/nodes.segments/_index.segment.rsc +7 -7
  89. package/.next/server/app/nodes.segments/_tree.segment.rsc +2 -2
  90. package/.next/server/app/nodes.segments/nodes/__PAGE__.segment.rsc +4 -4
  91. package/.next/server/app/nodes.segments/nodes.segment.rsc +3 -3
  92. package/.next/server/app/page_client-reference-manifest.js +1 -1
  93. package/.next/server/app/server-logs/page_client-reference-manifest.js +1 -1
  94. package/.next/server/app/server-logs.html +2 -2
  95. package/.next/server/app/server-logs.rsc +14 -14
  96. package/.next/server/app/server-logs.segments/_full.segment.rsc +14 -14
  97. package/.next/server/app/server-logs.segments/_head.segment.rsc +4 -4
  98. package/.next/server/app/server-logs.segments/_index.segment.rsc +7 -7
  99. package/.next/server/app/server-logs.segments/_tree.segment.rsc +2 -2
  100. package/.next/server/app/server-logs.segments/server-logs/__PAGE__.segment.rsc +4 -4
  101. package/.next/server/app/server-logs.segments/server-logs.segment.rsc +3 -3
  102. package/.next/server/app/settings/networks/page_client-reference-manifest.js +1 -1
  103. package/.next/server/app/settings/networks.html +2 -2
  104. package/.next/server/app/settings/networks.rsc +14 -14
  105. package/.next/server/app/settings/networks.segments/_full.segment.rsc +14 -14
  106. package/.next/server/app/settings/networks.segments/_head.segment.rsc +4 -4
  107. package/.next/server/app/settings/networks.segments/_index.segment.rsc +7 -7
  108. package/.next/server/app/settings/networks.segments/_tree.segment.rsc +2 -2
  109. package/.next/server/app/settings/networks.segments/settings/networks/__PAGE__.segment.rsc +4 -4
  110. package/.next/server/app/settings/networks.segments/settings/networks.segment.rsc +3 -3
  111. package/.next/server/app/settings/networks.segments/settings.segment.rsc +3 -3
  112. package/.next/server/app/settings/page_client-reference-manifest.js +1 -1
  113. package/.next/server/app/settings/tokens/page_client-reference-manifest.js +1 -1
  114. package/.next/server/app/settings/tokens.html +2 -2
  115. package/.next/server/app/settings/tokens.rsc +14 -14
  116. package/.next/server/app/settings/tokens.segments/_full.segment.rsc +14 -14
  117. package/.next/server/app/settings/tokens.segments/_head.segment.rsc +4 -4
  118. package/.next/server/app/settings/tokens.segments/_index.segment.rsc +7 -7
  119. package/.next/server/app/settings/tokens.segments/_tree.segment.rsc +2 -2
  120. package/.next/server/app/settings/tokens.segments/settings/tokens/__PAGE__.segment.rsc +4 -4
  121. package/.next/server/app/settings/tokens.segments/settings/tokens.segment.rsc +3 -3
  122. package/.next/server/app/settings/tokens.segments/settings.segment.rsc +3 -3
  123. package/.next/server/app/settings.html +2 -2
  124. package/.next/server/app/settings.rsc +14 -14
  125. package/.next/server/app/settings.segments/_full.segment.rsc +14 -14
  126. package/.next/server/app/settings.segments/_head.segment.rsc +4 -4
  127. package/.next/server/app/settings.segments/_index.segment.rsc +7 -7
  128. package/.next/server/app/settings.segments/_tree.segment.rsc +2 -2
  129. package/.next/server/app/settings.segments/settings/__PAGE__.segment.rsc +4 -4
  130. package/.next/server/app/settings.segments/settings.segment.rsc +3 -3
  131. package/.next/server/app/tasks/[id]/page_client-reference-manifest.js +1 -1
  132. package/.next/server/app/tasks/page_client-reference-manifest.js +1 -1
  133. package/.next/server/app/tasks.html +2 -2
  134. package/.next/server/app/tasks.rsc +14 -14
  135. package/.next/server/app/tasks.segments/_full.segment.rsc +14 -14
  136. package/.next/server/app/tasks.segments/_head.segment.rsc +4 -4
  137. package/.next/server/app/tasks.segments/_index.segment.rsc +7 -7
  138. package/.next/server/app/tasks.segments/_tree.segment.rsc +2 -2
  139. package/.next/server/app/tasks.segments/tasks/__PAGE__.segment.rsc +4 -4
  140. package/.next/server/app/tasks.segments/tasks.segment.rsc +3 -3
  141. package/.next/server/app-paths-manifest.json +1 -0
  142. package/.next/server/chunks/0ykm__next-internal_server_app_api_hub_servers_route_actions_08-m-cs.js +3 -0
  143. package/.next/server/chunks/0ykm__next-internal_server_app_api_hub_servers_route_actions_08-m-cs.js.map +1 -0
  144. package/.next/server/chunks/[root-of-the-server]__0tx8s8i._.js +3 -0
  145. package/.next/server/chunks/[root-of-the-server]__0tx8s8i._.js.map +1 -0
  146. package/.next/server/chunks/ssr/[root-of-the-server]__03b.f76._.js +1 -1
  147. package/.next/server/chunks/ssr/[root-of-the-server]__03b.f76._.js.map +1 -1
  148. package/.next/server/chunks/ssr/[root-of-the-server]__0fhoq8i._.js +1 -1
  149. package/.next/server/chunks/ssr/[root-of-the-server]__0fhoq8i._.js.map +1 -1
  150. package/.next/server/chunks/ssr/[root-of-the-server]__0nw~zhp._.js +1 -1
  151. package/.next/server/chunks/ssr/[root-of-the-server]__0nw~zhp._.js.map +1 -1
  152. package/.next/server/chunks/ssr/agent-network-dashboard_09kk21a._.js +4 -1
  153. package/.next/server/chunks/ssr/agent-network-dashboard_09kk21a._.js.map +1 -1
  154. package/.next/server/chunks/ssr/agent-network-dashboard_app_01jhlxz._.js +1 -1
  155. package/.next/server/chunks/ssr/agent-network-dashboard_app_01jhlxz._.js.map +1 -1
  156. package/.next/server/chunks/ssr/agent-network-dashboard_app_057q.ne._.js +1 -1
  157. package/.next/server/chunks/ssr/agent-network-dashboard_app_057q.ne._.js.map +1 -1
  158. package/.next/server/chunks/ssr/agent-network-dashboard_app_09d29my._.js +1 -1
  159. package/.next/server/chunks/ssr/agent-network-dashboard_app_09d29my._.js.map +1 -1
  160. package/.next/server/chunks/ssr/agent-network-dashboard_app_0_d45-d._.js +1 -1
  161. package/.next/server/chunks/ssr/agent-network-dashboard_app_0_d45-d._.js.map +1 -1
  162. package/.next/server/chunks/ssr/agent-network-dashboard_app_0i3759l._.js +1 -1
  163. package/.next/server/chunks/ssr/agent-network-dashboard_app_0i3759l._.js.map +1 -1
  164. package/.next/server/chunks/ssr/agent-network-dashboard_app_0xgney8._.js +1 -1
  165. package/.next/server/chunks/ssr/agent-network-dashboard_app_0xgney8._.js.map +1 -1
  166. package/.next/server/chunks/ssr/agent-network-dashboard_app_10hjgv4._.js +1 -1
  167. package/.next/server/chunks/ssr/agent-network-dashboard_app_10hjgv4._.js.map +1 -1
  168. package/.next/server/chunks/ssr/agent-network-dashboard_app_1153xeb._.js +1 -1
  169. package/.next/server/chunks/ssr/agent-network-dashboard_app_1153xeb._.js.map +1 -1
  170. package/.next/server/chunks/ssr/agent-network-dashboard_app_12l4oto._.js +1 -1
  171. package/.next/server/chunks/ssr/agent-network-dashboard_app_12l4oto._.js.map +1 -1
  172. package/.next/server/chunks/ssr/agent-network-dashboard_app_components_0mvyi-4._.js +1 -1
  173. package/.next/server/chunks/ssr/agent-network-dashboard_app_components_0mvyi-4._.js.map +1 -1
  174. package/.next/server/middleware-build-manifest.js +3 -3
  175. package/.next/server/pages/404.html +2 -2
  176. package/.next/server/pages/500.html +1 -1
  177. package/.next/server/server-reference-manifest.js +1 -1
  178. package/.next/server/server-reference-manifest.json +1 -1
  179. package/.next/static/chunks/0-mpa_947ipeq.js +1 -0
  180. package/.next/static/chunks/00.pi0.850kxg.js +1 -0
  181. package/.next/static/chunks/01lmbsd37fybu.js +1 -0
  182. package/.next/static/chunks/03o.h6kvmw4l_.js +1 -0
  183. package/.next/static/chunks/03~~oirxz7~vc.js +1 -0
  184. package/.next/static/chunks/05uk96gc~9mni.js +1 -0
  185. package/.next/static/chunks/08kf-.bgs10ze.js +1 -0
  186. package/.next/static/chunks/08y27uzl7w6bx.css +2 -0
  187. package/.next/static/chunks/0ggj5ummw2a84.js +7 -0
  188. package/.next/static/chunks/0glmrdj9112tc.js +7 -0
  189. package/.next/static/chunks/0rxrez_cjn.eh.js +1 -0
  190. package/.next/static/chunks/0s64vw8kd5rn7.js +1 -0
  191. package/.next/static/chunks/0x8x.29hkju5a.js +1 -0
  192. package/.next/static/chunks/11drzen-wfaop.js +4 -0
  193. package/.next/static/chunks/174re5ar~kxne.js +1 -0
  194. package/.next/trace +2 -2
  195. package/.next/trace-build +1 -1
  196. package/.next/types/routes.d.ts +2 -1
  197. package/.next/types/validator.ts +9 -0
  198. package/app/api/hub/servers/route.ts +39 -0
  199. package/app/components/ChatPopover.tsx +38 -2
  200. package/app/components/CommandPalette.tsx +107 -0
  201. package/app/components/HelpOverlay.tsx +126 -0
  202. package/app/components/ServersDrawer.tsx +64 -27
  203. package/app/components/TopoGraph.tsx +5291 -237
  204. package/app/components/utils.ts +8 -7
  205. package/app/globals.css +110 -5
  206. package/app/lib/time.ts +36 -0
  207. package/package.json +2 -2
  208. package/scripts/help-overlay-topo-test.mjs +44 -0
  209. package/scripts/servers-drawer-live-test.mjs +96 -0
  210. package/scripts/topo-active-filter-pill-test.mjs +101 -0
  211. package/scripts/topo-active-links-chip-hover-test.mjs +103 -0
  212. package/scripts/topo-active-links-chip-nav-test.mjs +117 -0
  213. package/scripts/topo-active-links-chip-self-hover-test.mjs +171 -0
  214. package/scripts/topo-active-links-chip-test.mjs +73 -0
  215. package/scripts/topo-active-links-empty-recede-test.mjs +125 -0
  216. package/scripts/topo-active-links-freshness-test.mjs +113 -0
  217. package/scripts/topo-active-links-tooltip-test.mjs +79 -0
  218. package/scripts/topo-active-pulse-ease-test.mjs +120 -0
  219. package/scripts/topo-arrival-ping-test.mjs +87 -0
  220. package/scripts/topo-auto-fit-test.mjs +73 -0
  221. package/scripts/topo-canvas-aria-test.mjs +108 -0
  222. package/scripts/topo-chat-target-breath-test.mjs +84 -0
  223. package/scripts/topo-chat-target-ring-ease-test.mjs +82 -0
  224. package/scripts/topo-chat-target-ring-fade-test.mjs +124 -0
  225. package/scripts/topo-chip-empty-recede-test.mjs +116 -0
  226. package/scripts/topo-chip-focus-test.mjs +95 -0
  227. package/scripts/topo-chip-pin-mirror-test.mjs +113 -0
  228. package/scripts/topo-chip-row-tabular-test.mjs +111 -0
  229. package/scripts/topo-chrome-a11y-test.mjs +107 -0
  230. package/scripts/topo-chrome-pop-extension-test.mjs +98 -0
  231. package/scripts/topo-chrome-pop-nodesize-test.mjs +88 -0
  232. package/scripts/topo-chrome-press-state-test.mjs +135 -0
  233. package/scripts/topo-chrome-zoom-level-pop-test.mjs +122 -0
  234. package/scripts/topo-chrome-zoom-pop-test.mjs +130 -0
  235. package/scripts/topo-click-ripple-ease-test.mjs +94 -0
  236. package/scripts/topo-cmdk-edge-clear-test.mjs +109 -0
  237. package/scripts/topo-cmdk-layout-view-test.mjs +108 -0
  238. package/scripts/topo-cmdk-pin-test.mjs +123 -0
  239. package/scripts/topo-cmdk-vendor-clear-test.mjs +133 -0
  240. package/scripts/topo-cmdk-vendor-pin-test.mjs +103 -0
  241. package/scripts/topo-cwd-tooltip-test.mjs +64 -0
  242. package/scripts/topo-dblclick-reset-test.mjs +74 -0
  243. package/scripts/topo-dense-alias-fill-transition-test.mjs +133 -0
  244. package/scripts/topo-discrete-zoom-smooth-test.mjs +125 -0
  245. package/scripts/topo-dispatch-pulse-test.mjs +83 -0
  246. package/scripts/topo-edge-badge-click-pin-test.mjs +94 -0
  247. package/scripts/topo-edge-badge-crossfade-test.mjs +138 -0
  248. package/scripts/topo-edge-badge-hot-test.mjs +115 -0
  249. package/scripts/topo-edge-badge-hover-test.mjs +85 -0
  250. package/scripts/topo-edge-badge-lift-test.mjs +150 -0
  251. package/scripts/topo-edge-badge-ripple-test.mjs +111 -0
  252. package/scripts/topo-edge-badge-stroke-transition-test.mjs +118 -0
  253. package/scripts/topo-edge-badge-text-pin-test.mjs +121 -0
  254. package/scripts/topo-edge-badge-theme-ease-test.mjs +89 -0
  255. package/scripts/topo-edge-count-badge-test.mjs +86 -0
  256. package/scripts/topo-edge-endpoint-highlight-test.mjs +111 -0
  257. package/scripts/topo-edge-fadein-test.mjs +106 -0
  258. package/scripts/topo-edge-focus-test.mjs +113 -0
  259. package/scripts/topo-edge-hover-test.mjs +93 -0
  260. package/scripts/topo-edge-pill-hot-test.mjs +129 -0
  261. package/scripts/topo-edge-pill-test.mjs +105 -0
  262. package/scripts/topo-edge-smil-sync-test.mjs +148 -0
  263. package/scripts/topo-edge-smil-theme-ease-test.mjs +97 -0
  264. package/scripts/topo-edge-stroke-ease-test.mjs +100 -0
  265. package/scripts/topo-edge-stroke-transition-test.mjs +132 -0
  266. package/scripts/topo-edge-tooltip-test.mjs +70 -0
  267. package/scripts/topo-empty-state-breath-test.mjs +150 -0
  268. package/scripts/topo-empty-state-crossfade-test.mjs +130 -0
  269. package/scripts/topo-endpoint-ring-fade-test.mjs +132 -0
  270. package/scripts/topo-endpoint-ring-test.mjs +93 -0
  271. package/scripts/topo-endpoint-ring-thicken-test.mjs +112 -0
  272. package/scripts/topo-esc-clears-pin-test.mjs +98 -0
  273. package/scripts/topo-filter-pill-aliases-test.mjs +121 -0
  274. package/scripts/topo-filter-pill-body-click-test.mjs +112 -0
  275. package/scripts/topo-filter-pill-count-test.mjs +110 -0
  276. package/scripts/topo-filter-pill-mobile-test.mjs +90 -0
  277. package/scripts/topo-fit-key-test.mjs +106 -0
  278. package/scripts/topo-freshness-chip-test.mjs +74 -0
  279. package/scripts/topo-freshness-chip-transition-test.mjs +80 -0
  280. package/scripts/topo-fullscreen-active-test.mjs +115 -0
  281. package/scripts/topo-group-box-pinned-state-test.mjs +95 -0
  282. package/scripts/topo-group-count-test.mjs +68 -0
  283. package/scripts/topo-group-label-a11y-test.mjs +113 -0
  284. package/scripts/topo-group-label-count-inherit-test.mjs +99 -0
  285. package/scripts/topo-group-label-hover-test.mjs +119 -0
  286. package/scripts/topo-group-label-pin-spacing-test.mjs +136 -0
  287. package/scripts/topo-group-label-tint-test.mjs +99 -0
  288. package/scripts/topo-group-label-title-test.mjs +83 -0
  289. package/scripts/topo-group-pin-test.mjs +119 -0
  290. package/scripts/topo-group-pip-fadein-test.mjs +100 -0
  291. package/scripts/topo-group-pip-tabular-test.mjs +95 -0
  292. package/scripts/topo-group-status-pips-test.mjs +103 -0
  293. package/scripts/topo-groupbox-fadein-test.mjs +95 -0
  294. package/scripts/topo-groupbox-hover-lift-test.mjs +127 -0
  295. package/scripts/topo-groupbox-hubcore-ease-test.mjs +106 -0
  296. package/scripts/topo-groupbox-live-test.mjs +100 -0
  297. package/scripts/topo-groupbox-march-busyness-test.mjs +155 -0
  298. package/scripts/topo-groupbox-test.mjs +4 -2
  299. package/scripts/topo-halo-breath-ease-test.mjs +92 -0
  300. package/scripts/topo-halo-breath-stagger-test.mjs +89 -0
  301. package/scripts/topo-help-overlay-r109-test.mjs +67 -0
  302. package/scripts/topo-help-overlay-r118-test.mjs +69 -0
  303. package/scripts/topo-help-overlay-r123-test.mjs +69 -0
  304. package/scripts/topo-help-overlay-r134-test.mjs +74 -0
  305. package/scripts/topo-help-overlay-r137-test.mjs +81 -0
  306. package/scripts/topo-help-overlay-r141-test.mjs +86 -0
  307. package/scripts/topo-help-overlay-r153-test.mjs +85 -0
  308. package/scripts/topo-help-overlay-r59-test.mjs +67 -0
  309. package/scripts/topo-help-overlay-r65-test.mjs +64 -0
  310. package/scripts/topo-help-overlay-r70-test.mjs +63 -0
  311. package/scripts/topo-help-overlay-r78-test.mjs +59 -0
  312. package/scripts/topo-help-overlay-r81-test.mjs +58 -0
  313. package/scripts/topo-help-overlay-r87-test.mjs +64 -0
  314. package/scripts/topo-help-overlay-r91-test.mjs +65 -0
  315. package/scripts/topo-hot-tail-crossfade-test.mjs +117 -0
  316. package/scripts/topo-hub-a11y-test.mjs +112 -0
  317. package/scripts/topo-hub-busyness-test.mjs +100 -0
  318. package/scripts/topo-hub-center-crossfade-test.mjs +124 -0
  319. package/scripts/topo-hub-click-fit-test.mjs +137 -0
  320. package/scripts/topo-hub-digit-scale-test.mjs +129 -0
  321. package/scripts/topo-hub-fadein-test.mjs +88 -0
  322. package/scripts/topo-hub-hover-lift-test.mjs +101 -0
  323. package/scripts/topo-hub-hover-ring-test.mjs +82 -0
  324. package/scripts/topo-hub-pip-theme-ease-test.mjs +116 -0
  325. package/scripts/topo-hub-spoke-ease-test.mjs +120 -0
  326. package/scripts/topo-hub-title-test.mjs +93 -0
  327. package/scripts/topo-hub-working-count-test.mjs +99 -0
  328. package/scripts/topo-ingroup-edge-test.mjs +103 -0
  329. package/scripts/topo-label-card-theme-ease-test.mjs +85 -0
  330. package/scripts/topo-label-lift-test.mjs +119 -0
  331. package/scripts/topo-lastseen-tooltip-test.mjs +59 -0
  332. package/scripts/topo-layout-key-test.mjs +91 -0
  333. package/scripts/topo-layout-switch-crossfade-test.mjs +126 -0
  334. package/scripts/topo-layout-toggle-test.mjs +131 -0
  335. package/scripts/topo-legend-count-empty-test.mjs +126 -0
  336. package/scripts/topo-legend-count-test.mjs +88 -0
  337. package/scripts/topo-legend-count-tier-fill-test.mjs +121 -0
  338. package/scripts/topo-legend-hover-test.mjs +113 -0
  339. package/scripts/topo-legend-panel-header-test.mjs +83 -0
  340. package/scripts/topo-legend-pin-ring-fade-test.mjs +112 -0
  341. package/scripts/topo-legend-pin-test.mjs +128 -0
  342. package/scripts/topo-legend-row-hover-lift-test.mjs +109 -0
  343. package/scripts/topo-legend-row-pin-spacing-test.mjs +124 -0
  344. package/scripts/topo-legend-row-tint-test.mjs +95 -0
  345. package/scripts/topo-legend-row-title-test.mjs +102 -0
  346. package/scripts/topo-legend-swatch-grow-test.mjs +116 -0
  347. package/scripts/topo-minimap-a11y-test.mjs +101 -0
  348. package/scripts/topo-minimap-dot-transition-test.mjs +113 -0
  349. package/scripts/topo-minimap-test.mjs +68 -0
  350. package/scripts/topo-minimap-viewport-smooth-test.mjs +124 -0
  351. package/scripts/topo-mobile-chips-test.mjs +103 -0
  352. package/scripts/topo-node-a11y-test.mjs +107 -0
  353. package/scripts/topo-node-hover-lift-test.mjs +85 -0
  354. package/scripts/topo-node-label-card-elevation-test.mjs +157 -0
  355. package/scripts/topo-node-label-card-stroke-test.mjs +135 -0
  356. package/scripts/topo-node-stroke-transition-test.mjs +103 -0
  357. package/scripts/topo-node-text-fill-transition-test.mjs +119 -0
  358. package/scripts/topo-node-title-peers-test.mjs +107 -0
  359. package/scripts/topo-node-title-test.mjs +101 -0
  360. package/scripts/topo-nodesize-active-hover-test.mjs +109 -0
  361. package/scripts/topo-nodesize-crossfade-test.mjs +141 -0
  362. package/scripts/topo-online-chip-nav-test.mjs +143 -0
  363. package/scripts/topo-orbit-busyness-test.mjs +96 -0
  364. package/scripts/topo-orbit-opacity-bucket-test.mjs +124 -0
  365. package/scripts/topo-overlap-test.mjs +32 -5
  366. package/scripts/topo-pan-cursor-test.mjs +62 -0
  367. package/scripts/topo-panel-elevation-test.mjs +76 -0
  368. package/scripts/topo-panel-fadein-test.mjs +102 -0
  369. package/scripts/topo-panel-hot-tail-fade-test.mjs +132 -0
  370. package/scripts/topo-panel-hover-elevation-test.mjs +118 -0
  371. package/scripts/topo-panel-theme-ease-test.mjs +85 -0
  372. package/scripts/topo-particle-stagger-test.mjs +82 -0
  373. package/scripts/topo-pin-intersection-color-ease-test.mjs +111 -0
  374. package/scripts/topo-pin-intersection-empty-test.mjs +129 -0
  375. package/scripts/topo-pin-intersection-tabular-test.mjs +96 -0
  376. package/scripts/topo-pin-intersection-test.mjs +121 -0
  377. package/scripts/topo-pin-intersection-warning-crossfade-test.mjs +107 -0
  378. package/scripts/topo-pin-mirror-transition-test.mjs +101 -0
  379. package/scripts/topo-pin-persistence-test.mjs +105 -0
  380. package/scripts/topo-ping-pulse-ease-test.mjs +96 -0
  381. package/scripts/topo-popover-meta-test.mjs +78 -0
  382. package/scripts/topo-prepublish-guard-test.mjs +95 -0
  383. package/scripts/topo-pressure-bar-test.mjs +69 -0
  384. package/scripts/topo-pressure-hover-test.mjs +123 -0
  385. package/scripts/topo-pressure-pin-test.mjs +119 -0
  386. package/scripts/topo-pressure-seg-self-hover-test.mjs +126 -0
  387. package/scripts/topo-pressure-seg-tooltip-test.mjs +98 -0
  388. package/scripts/topo-pressure-seg-transition-test.mjs +107 -0
  389. package/scripts/topo-pulse-dot-crossfade-test.mjs +122 -0
  390. package/scripts/topo-pulse-rate-test.mjs +71 -0
  391. package/scripts/topo-recent-panel-count-freshness-test.mjs +109 -0
  392. package/scripts/topo-recent-panel-count-test.mjs +72 -0
  393. package/scripts/topo-recent-panel-hot-header-test.mjs +132 -0
  394. package/scripts/topo-recent-panel-more-crossfade-test.mjs +124 -0
  395. package/scripts/topo-recent-panel-more-cyan-hover-test.mjs +151 -0
  396. package/scripts/topo-recent-panel-more-nav-test.mjs +127 -0
  397. package/scripts/topo-recent-panel-more-test.mjs +106 -0
  398. package/scripts/topo-recent-row-count-fill-test.mjs +129 -0
  399. package/scripts/topo-recent-row-fadein-test.mjs +107 -0
  400. package/scripts/topo-recent-row-freshness-test.mjs +102 -0
  401. package/scripts/topo-recent-row-hot-test.mjs +110 -0
  402. package/scripts/topo-recent-row-hover-lift-test.mjs +128 -0
  403. package/scripts/topo-recent-row-hover-test.mjs +122 -0
  404. package/scripts/topo-recent-row-pin-spacing-test.mjs +137 -0
  405. package/scripts/topo-recent-row-pin-test.mjs +126 -0
  406. package/scripts/topo-recent-row-tint-test.mjs +91 -0
  407. package/scripts/topo-recent-row-title-test.mjs +112 -0
  408. package/scripts/topo-recent-row-ts-alpha-test.mjs +100 -0
  409. package/scripts/topo-recent-row-ts-test.mjs +95 -0
  410. package/scripts/topo-recent-row-typography-test.mjs +119 -0
  411. package/scripts/topo-recent-signal-empty-hint-test.mjs +73 -0
  412. package/scripts/topo-recent-signal-empty-test.mjs +63 -0
  413. package/scripts/topo-reduced-motion-test.mjs +77 -0
  414. package/scripts/topo-reset-spin-test.mjs +120 -0
  415. package/scripts/topo-runtime-badge-grow-test.mjs +114 -0
  416. package/scripts/topo-spoke-busyness-test.mjs +110 -0
  417. package/scripts/topo-spoke-tint-test.mjs +96 -0
  418. package/scripts/topo-status-chip-hover-test.mjs +101 -0
  419. package/scripts/topo-status-chip-tooltip-test.mjs +95 -0
  420. package/scripts/topo-statusbar-chips-self-hover-test.mjs +177 -0
  421. package/scripts/topo-svg-focus-test.mjs +112 -0
  422. package/scripts/topo-sweep-busyness-test.mjs +94 -0
  423. package/scripts/topo-tabular-nums-sweep-test.mjs +93 -0
  424. package/scripts/topo-tier-ring-fadein-test.mjs +107 -0
  425. package/scripts/topo-tier-ring-occupancy-test.mjs +87 -0
  426. package/scripts/topo-tier-ring-test.mjs +69 -0
  427. package/scripts/topo-tier-ring-tint-test.mjs +110 -0
  428. package/scripts/topo-tier-stagger-test.mjs +89 -0
  429. package/scripts/topo-tz-ghost-test.mjs +69 -0
  430. package/scripts/topo-vendor-chip-hover-test.mjs +111 -0
  431. package/scripts/topo-vendor-chip-self-hover-test.mjs +130 -0
  432. package/scripts/topo-vendor-chip-tabular-test.mjs +89 -0
  433. package/scripts/topo-vendor-letter-tooltip-test.mjs +92 -0
  434. package/scripts/topo-vendor-pill-test.mjs +125 -0
  435. package/scripts/topo-vendor-pin-test.mjs +125 -0
  436. package/scripts/topo-view-smooth-test.mjs +131 -0
  437. package/scripts/topo-wheel-zoom-test.mjs +79 -0
  438. package/scripts/topo-working-chip-pin-test.mjs +154 -0
  439. package/scripts/topo-working-halo-breath-test.mjs +86 -0
  440. package/scripts/topo-wrapper-flow-arrow-theme-test.mjs +97 -0
  441. package/scripts/topo-zoom-keys-test.mjs +89 -0
  442. package/.next/static/chunks/0-7iowzu4.798.js +0 -1
  443. package/.next/static/chunks/02t5jr4shh.hy.js +0 -1
  444. package/.next/static/chunks/09nd.t_hd.y6t.css +0 -2
  445. package/.next/static/chunks/0_qfg5s5uzs7..js +0 -7
  446. package/.next/static/chunks/0elalb9n_.~di.js +0 -1
  447. package/.next/static/chunks/0fqy_0wj_1xa7.js +0 -7
  448. package/.next/static/chunks/0j_q__o8p6g83.js +0 -1
  449. package/.next/static/chunks/0jl6_w50zh4l5.js +0 -1
  450. package/.next/static/chunks/0jzqhqbydbrm~.js +0 -1
  451. package/.next/static/chunks/0lvk7f2_5y8b3.js +0 -1
  452. package/.next/static/chunks/0r4q73.-1bkyl.js +0 -1
  453. package/.next/static/chunks/0r_c8eccg3z2o.js +0 -1
  454. package/.next/static/chunks/10oi7l-tycgl9.js +0 -1
  455. package/.next/static/chunks/11uk1izuv3~0t.js +0 -1
  456. package/.next/static/chunks/12maqvd_4t3sh.js +0 -1
  457. /package/.next/static/{iC9JNLo0IdNSaeynEneGT → -JO9tjmCkno3inrj-XBxj}/_buildManifest.js +0 -0
  458. /package/.next/static/{iC9JNLo0IdNSaeynEneGT → -JO9tjmCkno3inrj-XBxj}/_clientMiddlewareManifest.js +0 -0
  459. /package/.next/static/{iC9JNLo0IdNSaeynEneGT → -JO9tjmCkno3inrj-XBxj}/_ssgManifest.js +0 -0
@@ -0,0 +1,110 @@
1
+ /* Round 145 verification: R46 idle-spoke flow rate buckets on
2
+ * workingCount, completing the 4-layer busyness-driven motion
3
+ * family:
4
+ * R84 hub breath (centre)
5
+ * R131 outer-ring orbit (periphery)
6
+ * R132 groupbox march (per-team, grid layout)
7
+ * R145 idle-spoke flow (ring layout, hub→nodes) — new
8
+ *
9
+ * Bucket ladder shared across the four layers (same R84
10
+ * thresholds):
11
+ * workingCount === 0 → bucket 0
12
+ * workingCount in [1, 2] → bucket 1
13
+ * workingCount in [3, 5] → bucket 2
14
+ * workingCount >= 6 → bucket 3
15
+ *
16
+ * Idle-spoke durations per bucket: 2.8 / 2.4 / 2.0 / 1.6 seconds
17
+ * (R46 baseline 2.4s is bucket 1).
18
+ *
19
+ * Spokes only render in ring layout. Active spokes (carrying flow
20
+ * traffic) don't get the animation — they're solid bright strokes.
21
+ * Only idle spokes carry the .anet-topo-spoke-flow class and the
22
+ * --spoke-dur var. The test seeds 0 messages so all spokes are idle.
23
+ */
24
+ import { chromium } from 'playwright';
25
+ import { readFileSync } from 'node:fs';
26
+
27
+ const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
28
+
29
+ async function probe(workingCount, totalCount) {
30
+ const browser = await chromium.launch({ headless: true });
31
+ const ctx = await browser.newContext({ viewport: { width: 1400, height: 1500 } });
32
+ await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
33
+ await ctx.addInitScript(() => {
34
+ try {
35
+ localStorage.setItem('anet-theme', 'cyber');
36
+ sessionStorage.setItem('anet_v3_auth', '1');
37
+ // ring layout is R145's target — it's also the default, but
38
+ // pinning explicitly defends against future default flips.
39
+ localStorage.setItem('anet-topo-layout', 'ring');
40
+ } catch {}
41
+ });
42
+ const fresh = new Date(Date.now() - 60 * 1000).toISOString();
43
+ await ctx.route('**/api/hub/status*', async (route) => {
44
+ const r = await route.fetch();
45
+ const b = await r.json();
46
+ const nid = (b.sessions || [])[0]?.network_id || 'default';
47
+ const sessions = [];
48
+ for (let i = 0; i < totalCount; i++) {
49
+ sessions.push({
50
+ alias: `node${i}`,
51
+ status: i < workingCount ? 'working' : 'idle',
52
+ model: 'claude-opus-4', runtime: 'cli-claude-code',
53
+ network_id: nid, project_dir: null,
54
+ created_at: fresh, updated_at: fresh, last_seen_at: fresh,
55
+ });
56
+ }
57
+ await route.fulfill({ response: r, json: { ...b, sessions } });
58
+ });
59
+ // 0 messages → no active spokes → every spoke is idle (.anet-topo-spoke-flow)
60
+ await ctx.route('**/api/hub/messages*', (route) => route.fulfill({ json: { messages: [] } }));
61
+ await ctx.route('**/api/hub/tasks*', (route) => route.fulfill({ json: { tasks: [] } }));
62
+
63
+ const page = await ctx.newPage();
64
+ await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
65
+ await page.waitForFunction((n) => document.querySelectorAll('g[data-node]').length === n, totalCount, { timeout: 30000 });
66
+ await page.waitForTimeout(400);
67
+
68
+ const out = await page.evaluate(() => {
69
+ const spokes = [...document.querySelectorAll('path.anet-topo-spoke-flow')];
70
+ return spokes.map(p => ({
71
+ bucket: p.getAttribute('data-topo-spoke-bucket'),
72
+ dur: p.getAttribute('data-topo-spoke-dur'),
73
+ // Resolved animation-duration from computed style — confirms
74
+ // the CSS var bridge through to the cascade.
75
+ cssDur: getComputedStyle(p).getPropertyValue('animation-duration').trim(),
76
+ }));
77
+ });
78
+ await browser.close();
79
+ return out;
80
+ }
81
+
82
+ // One probe per bucket
83
+ const b0 = await probe(0, 4); // 0 working / 4 idle → bucket 0 (2.8s)
84
+ const b1 = await probe(2, 4); // 2 working / 2 idle → bucket 1 (2.4s)
85
+ const b2 = await probe(4, 5); // 4 working / 1 idle → bucket 2 (2.0s)
86
+ const b3 = await probe(7, 8); // 7 working / 1 idle → bucket 3 (1.6s)
87
+
88
+ const consistent = (spokes, bucket, dur) =>
89
+ spokes.length > 0 &&
90
+ spokes.every(s => s.bucket === String(bucket) && s.dur === String(dur) && s.cssDur === `${dur}s`);
91
+
92
+ const results = {
93
+ b0_someSpokes: b0.length > 0,
94
+ b0_bucket0_2_8s: consistent(b0, 0, 2.8),
95
+ b1_bucket1_2_4s: consistent(b1, 1, 2.4),
96
+ b2_bucket2_2_0s: consistent(b2, 2, 2.0),
97
+ b3_bucket3_1_6s: consistent(b3, 3, 1.6),
98
+ // dur strictly decreases as busy climbs
99
+ dur_monotonic:
100
+ Number(b0[0]?.dur) > Number(b1[0]?.dur) &&
101
+ Number(b1[0]?.dur) > Number(b2[0]?.dur) &&
102
+ Number(b2[0]?.dur) > Number(b3[0]?.dur),
103
+ };
104
+ const ok = Object.values(results).every(Boolean);
105
+ console.log(`${ok ? '✅' : '❌'} spoke busyness:`, JSON.stringify(results),
106
+ `\n b0(0w/4)=`, b0.slice(0,1),
107
+ `\n b1(2w/4)=`, b1.slice(0,1),
108
+ `\n b2(4w/5)=`, b2.slice(0,1),
109
+ `\n b3(7w/8)=`, b3.slice(0,1));
110
+ process.exit(ok ? 0 : 1);
@@ -0,0 +1,96 @@
1
+ /* Round 240 verification: backdrop spokes (6 radar-style lines)
2
+ * tint to pal.legendAccent on any pinned filter, mirroring R93's
3
+ * tier-ring treatment. Background scaffolding now signals
4
+ * 'filtered mode' as a unified set instead of half-and-half.
5
+ *
6
+ * Cyber theme palette:
7
+ * pal.ringStroke = #164e63 = rgb(22, 78, 99)
8
+ * pal.legendAccent = #67e8f9 = rgb(103, 232, 249)
9
+ *
10
+ * Test scope:
11
+ * - rest state (no pin): all 6 spokes stroke = ringStroke
12
+ * - pinned state: all 6 spokes stroke = legendAccent
13
+ * - transition wiring: style.transition contains 'stroke 200ms'
14
+ * (browser may normalise to '0.2s' — accept either)
15
+ * - data-topo-spoke-tinted attr flips false ↔ true
16
+ *
17
+ * Scenario: 4 working agents (single tier, simple geometry).
18
+ * Click the working pressure-bar segment to pin status=working.
19
+ */
20
+ import { chromium } from 'playwright';
21
+ import { readFileSync } from 'node:fs';
22
+
23
+ const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
24
+ const browser = await chromium.launch({ headless: true });
25
+ const ctx = await browser.newContext({ viewport: { width: 1500, height: 1500 } });
26
+ await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
27
+ await ctx.addInitScript(() => {
28
+ try { localStorage.setItem('anet-theme', 'cyber'); sessionStorage.setItem('anet_v3_auth', '1'); } catch {}
29
+ });
30
+ const fresh = new Date(Date.now() - 60 * 1000).toISOString();
31
+ await ctx.route('**/api/hub/status*', async (route) => {
32
+ const r = await route.fetch();
33
+ const b = await r.json();
34
+ const nid = (b.sessions || [])[0]?.network_id || 'default';
35
+ const mk = (alias) => ({
36
+ alias, status: 'working', model: 'claude-opus-4', runtime: 'claude-code-cli',
37
+ network_id: nid, project_dir: null,
38
+ created_at: fresh, updated_at: fresh, last_seen_at: fresh,
39
+ });
40
+ await route.fulfill({ response: r, json: { ...b, sessions: [
41
+ mk('alpha'), mk('beta'), mk('gamma'), mk('delta'),
42
+ ] } });
43
+ });
44
+ await ctx.route('**/api/hub/messages*', (r2) => r2.fulfill({ json: { messages: [] } }));
45
+ await ctx.route('**/api/hub/tasks*', (r2) => r2.fulfill({ json: { tasks: [] } }));
46
+
47
+ const page = await ctx.newPage();
48
+ await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
49
+ await page.waitForFunction(() => document.querySelectorAll('g[data-node]').length === 4, { timeout: 30000 });
50
+ await page.waitForSelector('[data-topo-spoke-angle]', { timeout: 10000, state: 'attached' });
51
+ await page.waitForTimeout(400);
52
+
53
+ const probeSpokes = (page) => page.evaluate(() => {
54
+ const spokes = Array.from(document.querySelectorAll('[data-topo-spoke-angle]'));
55
+ return spokes.map((s) => ({
56
+ angle: s.getAttribute('data-topo-spoke-angle'),
57
+ tinted: s.getAttribute('data-topo-spoke-tinted'),
58
+ fill: getComputedStyle(s).stroke,
59
+ transition: getComputedStyle(s).transition,
60
+ }));
61
+ });
62
+
63
+ const rest = await probeSpokes(page);
64
+
65
+ // Pin working status via pressure-bar segment click
66
+ await page.locator('[data-pressure-seg="working"]').first().click();
67
+ await page.waitForTimeout(400);
68
+ const pinned = await probeSpokes(page);
69
+
70
+ await browser.close();
71
+
72
+ const RING_RGB = 'rgb(22, 78, 99)';
73
+ const ACCENT_RGB = 'rgb(103, 232, 249)';
74
+ // Browser normalises 200ms → 0.2s
75
+ const hasTransition = (s) => /stroke\s+(?:200ms|0\.2s)/.test(s || '');
76
+
77
+ const results = {
78
+ six_spokes: rest.length === 6,
79
+ rest_all_untinted: rest.every(s => s.tinted === 'false'),
80
+ rest_all_ring_stroke: rest.every(s => s.fill === RING_RGB),
81
+ rest_all_has_transition: rest.every(s => hasTransition(s.transition)),
82
+
83
+ pinned_six_spokes: pinned.length === 6,
84
+ pinned_all_tinted: pinned.every(s => s.tinted === 'true'),
85
+ pinned_all_accent: pinned.every(s => s.fill === ACCENT_RGB),
86
+ pinned_all_has_transition: pinned.every(s => hasTransition(s.transition)),
87
+
88
+ // Angles match the original 0/30/60/90/120/150 pattern (sanity)
89
+ angles_correct: JSON.stringify(rest.map(s => s.angle).sort())
90
+ === JSON.stringify(['0','120','150','30','60','90']),
91
+ };
92
+ const ok = Object.values(results).every(Boolean);
93
+ console.log(`${ok ? '✅' : '❌'} spoke tint:`, JSON.stringify(results),
94
+ '\n rest: ', rest.map(s => ({ a: s.angle, t: s.tinted, fill: s.fill })),
95
+ '\n pinned:', pinned.map(s => ({ a: s.angle, t: s.tinted, fill: s.fill })));
96
+ process.exit(ok ? 0 : 1);
@@ -0,0 +1,101 @@
1
+ /* Round 79 verification: header working + online count chips become
2
+ * hover affordances (sister to R77 active-links chip).
3
+ * - Hover "N working" → setHoveredStatus('working') → idle + offline
4
+ * nodes dim, working stays bright. Same outcome as R55 legend row
5
+ * hover, just from the chip surface.
6
+ * - Hover "N online" with working present → same as above.
7
+ * - Mouseleave restores baseline.
8
+ *
9
+ * Fleet: 1 working (wkr), 2 idle (idl1, idl2), 1 offline (off).
10
+ */
11
+ import { chromium } from 'playwright';
12
+ import { readFileSync } from 'node:fs';
13
+
14
+ const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
15
+ const browser = await chromium.launch({ headless: true });
16
+
17
+ const ctx = await browser.newContext({ viewport: { width: 1400, height: 1500 } });
18
+ await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
19
+ await ctx.addInitScript(() => {
20
+ try {
21
+ localStorage.setItem('anet-theme', 'cyber');
22
+ localStorage.setItem('anet-topo-layout', 'ring');
23
+ sessionStorage.setItem('anet_v3_auth', '1');
24
+ sessionStorage.removeItem('anet-topo-pinned-status');
25
+ sessionStorage.removeItem('anet-topo-pinned-group');
26
+ } catch {}
27
+ });
28
+
29
+ const fresh = new Date(Date.now() - 60 * 1000).toISOString();
30
+ const stale = new Date(Date.now() - 30 * 60 * 1000).toISOString();
31
+ await ctx.route('**/api/hub/status*', async (route) => {
32
+ const r = await route.fetch();
33
+ const b = await r.json();
34
+ const nid = (b.sessions || [])[0]?.network_id || 'default';
35
+ const sessions = [
36
+ { alias: 'wkr', status: 'working', network_id: nid, project_dir: null, created_at: fresh, updated_at: fresh, last_seen_at: fresh },
37
+ { alias: 'idl1', status: 'idle', network_id: nid, project_dir: null, created_at: fresh, updated_at: fresh, last_seen_at: fresh },
38
+ { alias: 'idl2', status: 'idle', network_id: nid, project_dir: null, created_at: fresh, updated_at: fresh, last_seen_at: fresh },
39
+ { alias: 'off', status: 'offline', network_id: nid, project_dir: null, created_at: stale, updated_at: stale, last_seen_at: stale },
40
+ ];
41
+ await route.fulfill({ response: r, json: { ...b, sessions } });
42
+ });
43
+ await ctx.route('**/api/hub/messages*', (route) => route.fulfill({ json: { messages: [] } }));
44
+ await ctx.route('**/api/hub/tasks*', (route) => route.fulfill({ json: { tasks: [] } }));
45
+ const page = await ctx.newPage();
46
+ await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
47
+ await page.waitForFunction(() => document.querySelectorAll('g[data-node]').length === 4, { timeout: 30000 });
48
+ await page.waitForTimeout(500);
49
+
50
+ const opacities = () => page.evaluate(() => {
51
+ const o = {};
52
+ for (const a of ['wkr', 'idl1', 'idl2', 'off']) {
53
+ const g = document.querySelector(`g[data-node="${a}"]`);
54
+ o[a] = g ? +(g.style.opacity || '1') : null;
55
+ }
56
+ return o;
57
+ });
58
+
59
+ const before = await opacities();
60
+
61
+ // Hover working chip
62
+ await page.locator('[data-working-chip]').hover();
63
+ await page.waitForTimeout(250);
64
+ const onWorking = await opacities();
65
+
66
+ // Move away
67
+ await page.mouse.move(10, 10);
68
+ await page.waitForTimeout(250);
69
+ const afterWorking = await opacities();
70
+
71
+ // Hover online chip (working present → routes to 'working')
72
+ await page.locator('[data-online-chip]').hover();
73
+ await page.waitForTimeout(250);
74
+ const onOnline = await opacities();
75
+
76
+ await page.mouse.move(10, 10);
77
+ await page.waitForTimeout(250);
78
+ const afterOnline = await opacities();
79
+
80
+ await browser.close();
81
+
82
+ const bright = (v) => v != null && v >= 0.55;
83
+ const dim = (v) => v != null && v < 0.4;
84
+ const results = {
85
+ before_baseline: bright(before.wkr) && bright(before.idl1) && bright(before.idl2),
86
+ working_keepsWkrBright: bright(onWorking.wkr),
87
+ working_dimsIdle: dim(onWorking.idl1) && dim(onWorking.idl2),
88
+ working_dimsOffline: dim(onWorking.off),
89
+ workingLeave_restoresAll: bright(afterWorking.wkr) && bright(afterWorking.idl1),
90
+ online_keepsWkrBright: bright(onOnline.wkr), // routes to working filter
91
+ online_dimsIdle: dim(onOnline.idl1) && dim(onOnline.idl2),
92
+ onlineLeave_restoresAll: bright(afterOnline.wkr) && bright(afterOnline.idl1),
93
+ };
94
+ const ok = Object.values(results).every(Boolean);
95
+ console.log(`${ok ? '✅' : '❌'} status-chip hover:`, JSON.stringify(results),
96
+ `\n before=`, before,
97
+ `\n onWorking=`, onWorking,
98
+ `\n afterWorking=`, afterWorking,
99
+ `\n onOnline=`, onOnline,
100
+ `\n afterOnline=`, afterOnline);
101
+ process.exit(ok ? 0 : 1);
@@ -0,0 +1,95 @@
1
+ /* Round 113 verification: chip-row "N working" + "N online" tooltips
2
+ * list matched aliases. Closes the last hover surfaces in the chip-
3
+ * row that had generic "Hover to highlight" titles. Same R97-R102 /
4
+ * R101 alias-list pattern.
5
+ *
6
+ * Fleet: 2 working (wkr1/2) + 2 idle (idl1/2) + 1 offline (off1).
7
+ * working chip title contains wkr1, wkr2; data-working-chip-aliases CSV matches
8
+ * online chip title contains all online aliases (4); data-online-chip-aliases matches
9
+ * pin state flips the action hint
10
+ */
11
+ import { chromium } from 'playwright';
12
+ import { readFileSync } from 'node:fs';
13
+
14
+ const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
15
+ const browser = await chromium.launch({ headless: true });
16
+
17
+ const ctx = await browser.newContext({ viewport: { width: 1400, height: 1500 } });
18
+ await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
19
+ await ctx.addInitScript(() => {
20
+ try {
21
+ localStorage.setItem('anet-theme', 'cyber');
22
+ sessionStorage.setItem('anet_v3_auth', '1');
23
+ sessionStorage.removeItem('anet-topo-pinned-status');
24
+ } catch {}
25
+ });
26
+
27
+ const fresh = new Date(Date.now() - 60 * 1000).toISOString();
28
+ const stale10 = new Date(Date.now() - 10 * 60 * 1000).toISOString();
29
+ await ctx.route('**/api/hub/status*', async (route) => {
30
+ const r = await route.fetch();
31
+ const b = await r.json();
32
+ const nid = (b.sessions || [])[0]?.network_id || 'default';
33
+ const mk = (alias, status, ts) => ({
34
+ alias, status, model: 'claude-opus-4', runtime: 'cli-claude-code',
35
+ network_id: nid, project_dir: null,
36
+ created_at: ts, updated_at: ts, last_seen_at: ts,
37
+ });
38
+ await route.fulfill({ response: r, json: { ...b, sessions: [
39
+ mk('wkr1', 'working', fresh),
40
+ mk('wkr2', 'working', fresh),
41
+ mk('idl1', 'idle', fresh),
42
+ mk('idl2', 'idle', fresh),
43
+ mk('off1', 'offline', stale10),
44
+ ] } });
45
+ });
46
+ await ctx.route('**/api/hub/messages*', (route) => route.fulfill({ json: { messages: [] } }));
47
+ await ctx.route('**/api/hub/tasks*', (route) => route.fulfill({ json: { tasks: [] } }));
48
+ const page = await ctx.newPage();
49
+ await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
50
+ await page.waitForFunction(() => document.querySelectorAll('g[data-node]').length === 5, { timeout: 30000 });
51
+ await page.waitForTimeout(400);
52
+
53
+ const read = (sel) => page.evaluate((s) => {
54
+ const el = document.querySelector(s);
55
+ if (!el) return null;
56
+ return {
57
+ title: el.getAttribute('title') || '',
58
+ aliases: el.getAttribute('data-working-chip-aliases') || el.getAttribute('data-online-chip-aliases') || '',
59
+ };
60
+ }, sel);
61
+
62
+ const workingBefore = await read('[data-working-chip]');
63
+ const onlineBefore = await read('[data-online-chip]');
64
+
65
+ // Pin working status — action hint should flip.
66
+ await page.evaluate(() => {
67
+ sessionStorage.setItem('anet-topo-pinned-status', 'working');
68
+ window.dispatchEvent(new CustomEvent('anet:topo-pin', { detail: { kind: 'status', value: 'working' } }));
69
+ });
70
+ await page.waitForTimeout(300);
71
+ const workingPinned = await read('[data-working-chip]');
72
+
73
+ await browser.close();
74
+
75
+ const sameSet = (csv, expected) => {
76
+ const got = new Set(csv.split(',').filter(Boolean));
77
+ const exp = new Set(expected);
78
+ return got.size === exp.size && [...exp].every(x => got.has(x));
79
+ };
80
+
81
+ const results = {
82
+ workingBefore_aliasesMatch: sameSet(workingBefore?.aliases || '', ['wkr1', 'wkr2']),
83
+ workingBefore_titleListsThem: /wkr1.*wkr2|wkr2.*wkr1/.test(workingBefore?.title || ''),
84
+ workingBefore_titleClickHint: /click to pin/.test(workingBefore?.title || ''),
85
+ onlineBefore_aliasesMatch: sameSet(onlineBefore?.aliases || '', ['wkr1', 'wkr2', 'idl1', 'idl2']),
86
+ onlineBefore_titleListsThem: /wkr1/.test(onlineBefore?.title || '') && /idl1/.test(onlineBefore?.title || ''),
87
+ pinnedWorking_aliasesStable: sameSet(workingPinned?.aliases || '', ['wkr1', 'wkr2']),
88
+ pinnedWorking_titleHintFlipped:/pinned, Esc to clear/.test(workingPinned?.title || ''),
89
+ };
90
+ const ok = Object.values(results).every(Boolean);
91
+ console.log(`${ok ? '✅' : '❌'} status-chip tooltip:`, JSON.stringify(results),
92
+ `\n workingBefore=`, workingBefore,
93
+ `\n onlineBefore=`, onlineBefore,
94
+ `\n workingPinned=`, workingPinned);
95
+ process.exit(ok ? 0 : 1);
@@ -0,0 +1,177 @@
1
+ /* Round 201 verification: the chip-row "N working" / "N online" chips
2
+ * adopt deeper versions of their own identity colour on hover,
3
+ * mirroring R193 active-links chip pattern.
4
+ *
5
+ * Pre-R201 hover working chip → R55 canvas dim + chip-row highlight,
6
+ * but chip itself stayed at bg-{color}-500/10 — cause silent, effect
7
+ * loud. R201 deepens 10→15 bg and 20→30 border on hover (only when
8
+ * the chip has a target count > 0). The inline transition list is
9
+ * extended to cover background-color + border-color so the swap
10
+ * eases instead of snapping (Tailwind transition-colors on the
11
+ * className alone would be overridden by the existing R180 inline
12
+ * box-shadow transition).
13
+ *
14
+ * Test (cyber dark, 4 working sessions):
15
+ * 1. Working chip: clickable='true', className has hover:bg-green-500/15
16
+ * + hover:border-green-500/30, transition includes 'background-color'
17
+ * + 'border-color' (both 200ms), inline still has 'box-shadow 150ms'.
18
+ * 2. Online chip: same shape with cyan hue.
19
+ * 3. Hover the working chip — wait past 220ms → computed bg
20
+ * shifts to a more-saturated/darker green (RGB-or-OKLab signal).
21
+ * 4. Move away — bg returns to idle (with margin past 220ms).
22
+ * 5. The chip's R55 canvas-effect setHoveredStatus still fires —
23
+ * verified via hoveredStatus change reflected on the working
24
+ * legend row's data-legend-row-lifted attribute.
25
+ */
26
+ import { chromium } from 'playwright';
27
+ import { readFileSync } from 'node:fs';
28
+
29
+ const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
30
+ const browser = await chromium.launch({ headless: true });
31
+
32
+ const ctx = await browser.newContext({ viewport: { width: 1500, height: 1500 } });
33
+ await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
34
+ await ctx.addInitScript(() => {
35
+ try { localStorage.setItem('anet-theme', 'cyber'); sessionStorage.setItem('anet_v3_auth', '1'); } catch {}
36
+ });
37
+
38
+ const fresh = new Date(Date.now() - 60 * 1000).toISOString();
39
+ await ctx.route('**/api/hub/status*', async (route) => {
40
+ const r = await route.fetch();
41
+ const b = await r.json();
42
+ const nid = (b.sessions || [])[0]?.network_id || 'default';
43
+ const mk = (alias) => ({
44
+ alias, status: 'working', model: 'claude-opus-4', runtime: 'cli-claude-code',
45
+ network_id: nid, project_dir: null,
46
+ created_at: fresh, updated_at: fresh, last_seen_at: fresh,
47
+ });
48
+ await route.fulfill({ response: r, json: { ...b, sessions: [
49
+ mk('alpha'), mk('beta'), mk('gamma'), mk('delta'),
50
+ ] } });
51
+ });
52
+ await ctx.route('**/api/hub/messages*', (route) => route.fulfill({ json: { messages: [] } }));
53
+ await ctx.route('**/api/hub/tasks*', (route) => route.fulfill({ json: { tasks: [] } }));
54
+
55
+ const page = await ctx.newPage();
56
+ await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
57
+ await page.waitForFunction(() => document.querySelectorAll('g[data-node]').length === 4, { timeout: 30000 });
58
+ await page.waitForSelector('[data-working-chip]', { timeout: 10000 });
59
+ await page.waitForTimeout(300);
60
+
61
+ const probeChip = async (selector) => page.evaluate((sel) => {
62
+ const el = document.querySelector(sel);
63
+ if (!el) return null;
64
+ const cs = getComputedStyle(el);
65
+ return {
66
+ className: el.getAttribute('class') || '',
67
+ clickable: el.getAttribute('data-working-chip-clickable') ||
68
+ el.getAttribute('data-online-chip-clickable'),
69
+ bg: cs.backgroundColor,
70
+ borderColor: cs.borderTopColor,
71
+ transition: el.style.transition,
72
+ };
73
+ }, selector);
74
+
75
+ const idleWorking = await probeChip('[data-working-chip]');
76
+ const idleOnline = await probeChip('[data-online-chip]');
77
+
78
+ await page.hover('[data-working-chip]');
79
+ await page.waitForTimeout(250);
80
+ const hoverWorking = await probeChip('[data-working-chip]');
81
+
82
+ // Confirm R55 canvas effect still fires — hoveredStatus='working'
83
+ // lifts the legend working row.
84
+ const workingRowLifted = await page.evaluate(() =>
85
+ document.querySelector('[data-legend-status="working"]')
86
+ ?.getAttribute('data-legend-row-lifted'));
87
+
88
+ await page.mouse.move(0, 0);
89
+ await page.waitForTimeout(280);
90
+ const settledWorking = await probeChip('[data-working-chip]');
91
+
92
+ await page.hover('[data-online-chip]');
93
+ await page.waitForTimeout(250);
94
+ const hoverOnline = await probeChip('[data-online-chip]');
95
+
96
+ await page.mouse.move(0, 0);
97
+ await page.waitForTimeout(280);
98
+ const settledOnline = await probeChip('[data-online-chip]');
99
+
100
+ await browser.close();
101
+
102
+ // Tailwind 4 emits oklab/oklch / color-mix forms. Just check the bg
103
+ // string actually differs idle vs hover, and a brief parser confirms
104
+ // the channel that should grow (green for working, blue/green for cyan).
105
+ // Parse colors including alpha. R201's Tailwind /10 → /15 emits same
106
+ // OKLab L/a/b with stepped-up alpha (0.1 → 0.15); R193's gray→cyan
107
+ // pattern emits a different hue at any alpha. Both are "more saturated
108
+ // against the canvas" from the user's POV. Capture alpha and treat
109
+ // alpha-increase as a valid saturation signal alongside chroma growth.
110
+ function parseColor(s) {
111
+ if (!s) return null;
112
+ let m = s.match(/rgba?\(\s*(\d+)\s*,?\s*(\d+)\s*,?\s*(\d+)(?:\s*[,/]\s*([\d.]+))?/);
113
+ if (m) return { kind: 'rgb', r: +m[1], g: +m[2], b: +m[3], a: m[4] != null ? +m[4] : 1 };
114
+ m = s.match(/oklab\(\s*([\-\d.]+)\s+([\-\d.]+)\s+([\-\d.]+)(?:\s*\/\s*([\d.]+))?/);
115
+ if (m) return { kind: 'oklab', L: +m[1], a: +m[2], b: +m[3], alpha: m[4] != null ? +m[4] : 1 };
116
+ m = s.match(/oklch\(\s*([\-\d.]+)\s+([\-\d.]+)\s+([\-\d.]+)(?:\s*\/\s*([\d.]+))?/);
117
+ if (m) return { kind: 'oklch', L: +m[1], C: +m[2], h: +m[3], alpha: m[4] != null ? +m[4] : 1 };
118
+ return null;
119
+ }
120
+
121
+ // "More saturated against the canvas" = either chroma/hue distance
122
+ // from gray grew OR alpha grew (Tailwind /10 → /15 deepens by alpha).
123
+ const moreSaturated = (idle, hov) => {
124
+ if (!idle || !hov) return false;
125
+ if (idle.kind === 'rgb' && hov.kind === 'rgb') {
126
+ const chromaIdle = Math.max(idle.r, idle.g, idle.b) - Math.min(idle.r, idle.g, idle.b);
127
+ const chromaHov = Math.max(hov.r, hov.g, hov.b) - Math.min(hov.r, hov.g, hov.b);
128
+ return chromaHov > chromaIdle || hov.a > idle.a + 0.01;
129
+ }
130
+ if (idle.kind === 'oklab' && hov.kind === 'oklab') {
131
+ const dIdle = Math.hypot(idle.a, idle.b);
132
+ const dHov = Math.hypot(hov.a, hov.b);
133
+ return dHov > dIdle + 0.005 || hov.alpha > idle.alpha + 0.01;
134
+ }
135
+ if (idle.kind === 'oklch' && hov.kind === 'oklch') {
136
+ return hov.C > idle.C + 0.005 || hov.alpha > idle.alpha + 0.01;
137
+ }
138
+ return false;
139
+ };
140
+
141
+ const idleWorkingC = parseColor(idleWorking?.bg);
142
+ const hoverWorkingC = parseColor(hoverWorking?.bg);
143
+ const idleOnlineC = parseColor(idleOnline?.bg);
144
+ const hoverOnlineC = parseColor(hoverOnline?.bg);
145
+
146
+ const results = {
147
+ working_clickable: idleWorking?.clickable === 'true',
148
+ working_className_has_hover: idleWorking?.className.includes('hover:bg-green-500/15')
149
+ && idleWorking?.className.includes('hover:border-green-500/30'),
150
+ working_transition_includes_bg: /background-color\s+(?:200ms|0\.2s)/.test(idleWorking?.transition || ''),
151
+ working_transition_includes_border: /border-color\s+(?:200ms|0\.2s)/.test(idleWorking?.transition || ''),
152
+ working_transition_keeps_boxshadow: /box-shadow\s+(?:150ms|0\.15s)/.test(idleWorking?.transition || ''),
153
+ working_hover_bg_changed: idleWorking?.bg !== hoverWorking?.bg,
154
+ working_hover_more_saturated: moreSaturated(idleWorkingC, hoverWorkingC),
155
+ working_settles_back: settledWorking?.bg === idleWorking?.bg,
156
+ // R55 canvas-effect still fires from the chip — hovering the
157
+ // working chip lifts the legend working row.
158
+ working_canvas_effect_fires: workingRowLifted === 'true',
159
+
160
+ online_clickable: idleOnline?.clickable === 'true',
161
+ online_className_has_hover: idleOnline?.className.includes('hover:bg-cyan-500/15')
162
+ && idleOnline?.className.includes('hover:border-cyan-500/30'),
163
+ online_transition_includes_bg: /background-color\s+(?:200ms|0\.2s)/.test(idleOnline?.transition || ''),
164
+ online_transition_includes_border: /border-color\s+(?:200ms|0\.2s)/.test(idleOnline?.transition || ''),
165
+ online_hover_bg_changed: idleOnline?.bg !== hoverOnline?.bg,
166
+ online_hover_more_saturated: moreSaturated(idleOnlineC, hoverOnlineC),
167
+ online_settles_back: settledOnline?.bg === idleOnline?.bg,
168
+ };
169
+ const ok = Object.values(results).every(Boolean);
170
+ console.log(`${ok ? '✅' : '❌'} status-bar chips self-hover:`, JSON.stringify(results),
171
+ `\n idleWorking:`, idleWorking,
172
+ `\n hoverWorking:`, hoverWorking,
173
+ `\n settledWorking:`, settledWorking,
174
+ `\n idleOnline:`, idleOnline,
175
+ `\n hoverOnline:`, hoverOnline,
176
+ `\n settledOnline:`, settledOnline);
177
+ process.exit(ok ? 0 : 1);