@sleep2agi/agent-network-dashboard 0.4.6-preview.23 → 0.4.6-preview.231

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 (432) 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/01lmbsd37fybu.js +1 -0
  181. package/.next/static/chunks/03o.h6kvmw4l_.js +1 -0
  182. package/.next/static/chunks/03~~oirxz7~vc.js +1 -0
  183. package/.next/static/chunks/05uk96gc~9mni.js +1 -0
  184. package/.next/static/chunks/08kf-.bgs10ze.js +1 -0
  185. package/.next/static/chunks/0dpr42ixguifs.js +1 -0
  186. package/.next/static/chunks/0ggj5ummw2a84.js +7 -0
  187. package/.next/static/chunks/0glmrdj9112tc.js +7 -0
  188. package/.next/static/chunks/0rntk9_zs6l38.js +4 -0
  189. package/.next/static/chunks/0rxrez_cjn.eh.js +1 -0
  190. package/.next/static/chunks/0x8x.29hkju5a.js +1 -0
  191. package/.next/static/chunks/0~k1yvhakbob6.css +2 -0
  192. package/.next/static/chunks/11c3ptzm7ghp7.js +1 -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 +4568 -233
  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 +1 -1
  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-arrival-ping-test.mjs +87 -0
  219. package/scripts/topo-arrow-tier-test.mjs +61 -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-fade-test.mjs +124 -0
  224. package/scripts/topo-chip-empty-recede-test.mjs +116 -0
  225. package/scripts/topo-chip-focus-test.mjs +95 -0
  226. package/scripts/topo-chip-pin-mirror-test.mjs +113 -0
  227. package/scripts/topo-chrome-a11y-test.mjs +107 -0
  228. package/scripts/topo-chrome-press-state-test.mjs +135 -0
  229. package/scripts/topo-chrome-zoom-level-pop-test.mjs +122 -0
  230. package/scripts/topo-chrome-zoom-pop-test.mjs +130 -0
  231. package/scripts/topo-cmdk-edge-clear-test.mjs +109 -0
  232. package/scripts/topo-cmdk-layout-view-test.mjs +108 -0
  233. package/scripts/topo-cmdk-pin-test.mjs +123 -0
  234. package/scripts/topo-cmdk-vendor-clear-test.mjs +133 -0
  235. package/scripts/topo-cmdk-vendor-pin-test.mjs +103 -0
  236. package/scripts/topo-cwd-tooltip-test.mjs +64 -0
  237. package/scripts/topo-dblclick-reset-test.mjs +74 -0
  238. package/scripts/topo-dense-alias-fill-transition-test.mjs +133 -0
  239. package/scripts/topo-discrete-zoom-smooth-test.mjs +125 -0
  240. package/scripts/topo-dispatch-pulse-test.mjs +83 -0
  241. package/scripts/topo-edge-badge-click-pin-test.mjs +94 -0
  242. package/scripts/topo-edge-badge-crossfade-test.mjs +138 -0
  243. package/scripts/topo-edge-badge-hot-test.mjs +115 -0
  244. package/scripts/topo-edge-badge-hover-test.mjs +85 -0
  245. package/scripts/topo-edge-badge-lift-test.mjs +150 -0
  246. package/scripts/topo-edge-badge-ripple-test.mjs +111 -0
  247. package/scripts/topo-edge-badge-stroke-transition-test.mjs +118 -0
  248. package/scripts/topo-edge-badge-text-pin-test.mjs +121 -0
  249. package/scripts/topo-edge-count-badge-test.mjs +86 -0
  250. package/scripts/topo-edge-endpoint-highlight-test.mjs +111 -0
  251. package/scripts/topo-edge-fadein-test.mjs +106 -0
  252. package/scripts/topo-edge-focus-test.mjs +113 -0
  253. package/scripts/topo-edge-hover-test.mjs +93 -0
  254. package/scripts/topo-edge-pill-hot-test.mjs +129 -0
  255. package/scripts/topo-edge-pill-test.mjs +105 -0
  256. package/scripts/topo-edge-stroke-transition-test.mjs +132 -0
  257. package/scripts/topo-edge-tooltip-test.mjs +70 -0
  258. package/scripts/topo-empty-state-breath-test.mjs +150 -0
  259. package/scripts/topo-empty-state-crossfade-test.mjs +130 -0
  260. package/scripts/topo-endpoint-ring-fade-test.mjs +132 -0
  261. package/scripts/topo-endpoint-ring-test.mjs +93 -0
  262. package/scripts/topo-esc-clears-pin-test.mjs +98 -0
  263. package/scripts/topo-filter-pill-aliases-test.mjs +121 -0
  264. package/scripts/topo-filter-pill-body-click-test.mjs +112 -0
  265. package/scripts/topo-filter-pill-count-test.mjs +110 -0
  266. package/scripts/topo-filter-pill-mobile-test.mjs +90 -0
  267. package/scripts/topo-fit-key-test.mjs +106 -0
  268. package/scripts/topo-freshness-chip-test.mjs +74 -0
  269. package/scripts/topo-freshness-chip-transition-test.mjs +80 -0
  270. package/scripts/topo-fullscreen-active-test.mjs +115 -0
  271. package/scripts/topo-group-box-pinned-state-test.mjs +95 -0
  272. package/scripts/topo-group-count-test.mjs +68 -0
  273. package/scripts/topo-group-hover-test.mjs +82 -0
  274. package/scripts/topo-group-label-a11y-test.mjs +113 -0
  275. package/scripts/topo-group-label-hover-test.mjs +119 -0
  276. package/scripts/topo-group-label-pin-spacing-test.mjs +136 -0
  277. package/scripts/topo-group-label-tint-test.mjs +99 -0
  278. package/scripts/topo-group-label-title-test.mjs +83 -0
  279. package/scripts/topo-group-pin-test.mjs +119 -0
  280. package/scripts/topo-group-pip-fadein-test.mjs +100 -0
  281. package/scripts/topo-group-status-pips-test.mjs +103 -0
  282. package/scripts/topo-groupbox-fadein-test.mjs +95 -0
  283. package/scripts/topo-groupbox-hover-lift-test.mjs +127 -0
  284. package/scripts/topo-groupbox-live-test.mjs +100 -0
  285. package/scripts/topo-groupbox-march-busyness-test.mjs +155 -0
  286. package/scripts/topo-groupbox-test.mjs +4 -2
  287. package/scripts/topo-help-overlay-r109-test.mjs +67 -0
  288. package/scripts/topo-help-overlay-r118-test.mjs +69 -0
  289. package/scripts/topo-help-overlay-r123-test.mjs +69 -0
  290. package/scripts/topo-help-overlay-r134-test.mjs +74 -0
  291. package/scripts/topo-help-overlay-r137-test.mjs +81 -0
  292. package/scripts/topo-help-overlay-r141-test.mjs +86 -0
  293. package/scripts/topo-help-overlay-r153-test.mjs +85 -0
  294. package/scripts/topo-help-overlay-r59-test.mjs +67 -0
  295. package/scripts/topo-help-overlay-r65-test.mjs +64 -0
  296. package/scripts/topo-help-overlay-r70-test.mjs +63 -0
  297. package/scripts/topo-help-overlay-r78-test.mjs +59 -0
  298. package/scripts/topo-help-overlay-r81-test.mjs +58 -0
  299. package/scripts/topo-help-overlay-r87-test.mjs +64 -0
  300. package/scripts/topo-help-overlay-r91-test.mjs +65 -0
  301. package/scripts/topo-hot-tail-crossfade-test.mjs +117 -0
  302. package/scripts/topo-hub-a11y-test.mjs +112 -0
  303. package/scripts/topo-hub-busyness-test.mjs +100 -0
  304. package/scripts/topo-hub-center-crossfade-test.mjs +124 -0
  305. package/scripts/topo-hub-click-fit-test.mjs +137 -0
  306. package/scripts/topo-hub-digit-scale-test.mjs +129 -0
  307. package/scripts/topo-hub-fadein-test.mjs +88 -0
  308. package/scripts/topo-hub-hover-lift-test.mjs +101 -0
  309. package/scripts/topo-hub-hover-ring-test.mjs +82 -0
  310. package/scripts/topo-hub-title-test.mjs +93 -0
  311. package/scripts/topo-hub-working-count-test.mjs +99 -0
  312. package/scripts/topo-ingroup-edge-test.mjs +103 -0
  313. package/scripts/topo-label-lift-test.mjs +119 -0
  314. package/scripts/topo-lastseen-tooltip-test.mjs +59 -0
  315. package/scripts/topo-layout-key-test.mjs +91 -0
  316. package/scripts/topo-layout-switch-crossfade-test.mjs +126 -0
  317. package/scripts/topo-layout-toggle-test.mjs +131 -0
  318. package/scripts/topo-legend-count-empty-test.mjs +126 -0
  319. package/scripts/topo-legend-count-test.mjs +88 -0
  320. package/scripts/topo-legend-hover-test.mjs +113 -0
  321. package/scripts/topo-legend-panel-header-test.mjs +83 -0
  322. package/scripts/topo-legend-pin-ring-fade-test.mjs +112 -0
  323. package/scripts/topo-legend-pin-test.mjs +128 -0
  324. package/scripts/topo-legend-row-hover-lift-test.mjs +109 -0
  325. package/scripts/topo-legend-row-pin-spacing-test.mjs +124 -0
  326. package/scripts/topo-legend-row-tint-test.mjs +95 -0
  327. package/scripts/topo-legend-row-title-test.mjs +102 -0
  328. package/scripts/topo-legend-swatch-grow-test.mjs +116 -0
  329. package/scripts/topo-minimap-a11y-test.mjs +101 -0
  330. package/scripts/topo-minimap-dot-transition-test.mjs +113 -0
  331. package/scripts/topo-minimap-test.mjs +68 -0
  332. package/scripts/topo-minimap-viewport-smooth-test.mjs +124 -0
  333. package/scripts/topo-mobile-chips-test.mjs +103 -0
  334. package/scripts/topo-node-a11y-test.mjs +107 -0
  335. package/scripts/topo-node-hover-lift-test.mjs +85 -0
  336. package/scripts/topo-node-label-card-elevation-test.mjs +157 -0
  337. package/scripts/topo-node-label-card-stroke-test.mjs +135 -0
  338. package/scripts/topo-node-stroke-transition-test.mjs +103 -0
  339. package/scripts/topo-node-text-fill-transition-test.mjs +119 -0
  340. package/scripts/topo-node-title-peers-test.mjs +107 -0
  341. package/scripts/topo-node-title-test.mjs +101 -0
  342. package/scripts/topo-nodesize-active-hover-test.mjs +109 -0
  343. package/scripts/topo-nodesize-crossfade-test.mjs +141 -0
  344. package/scripts/topo-offline-dim-test.mjs +70 -0
  345. package/scripts/topo-online-chip-nav-test.mjs +143 -0
  346. package/scripts/topo-orbit-busyness-test.mjs +96 -0
  347. package/scripts/topo-orbit-opacity-bucket-test.mjs +124 -0
  348. package/scripts/topo-overlap-test.mjs +32 -5
  349. package/scripts/topo-pan-cursor-test.mjs +62 -0
  350. package/scripts/topo-panel-elevation-test.mjs +76 -0
  351. package/scripts/topo-panel-fadein-test.mjs +102 -0
  352. package/scripts/topo-panel-hot-tail-fade-test.mjs +132 -0
  353. package/scripts/topo-panel-hover-elevation-test.mjs +118 -0
  354. package/scripts/topo-particle-stagger-test.mjs +82 -0
  355. package/scripts/topo-pin-intersection-empty-test.mjs +129 -0
  356. package/scripts/topo-pin-intersection-test.mjs +121 -0
  357. package/scripts/topo-pin-mirror-transition-test.mjs +101 -0
  358. package/scripts/topo-pin-persistence-test.mjs +105 -0
  359. package/scripts/topo-popover-meta-test.mjs +78 -0
  360. package/scripts/topo-pressure-bar-test.mjs +69 -0
  361. package/scripts/topo-pressure-hover-test.mjs +123 -0
  362. package/scripts/topo-pressure-pin-test.mjs +119 -0
  363. package/scripts/topo-pressure-seg-self-hover-test.mjs +126 -0
  364. package/scripts/topo-pressure-seg-tooltip-test.mjs +98 -0
  365. package/scripts/topo-pressure-seg-transition-test.mjs +107 -0
  366. package/scripts/topo-pulse-dot-crossfade-test.mjs +122 -0
  367. package/scripts/topo-pulse-rate-test.mjs +71 -0
  368. package/scripts/topo-recent-panel-count-freshness-test.mjs +109 -0
  369. package/scripts/topo-recent-panel-count-test.mjs +72 -0
  370. package/scripts/topo-recent-panel-hot-header-test.mjs +132 -0
  371. package/scripts/topo-recent-panel-more-crossfade-test.mjs +124 -0
  372. package/scripts/topo-recent-panel-more-cyan-hover-test.mjs +151 -0
  373. package/scripts/topo-recent-panel-more-nav-test.mjs +127 -0
  374. package/scripts/topo-recent-panel-more-test.mjs +106 -0
  375. package/scripts/topo-recent-row-count-fill-test.mjs +129 -0
  376. package/scripts/topo-recent-row-fadein-test.mjs +107 -0
  377. package/scripts/topo-recent-row-freshness-test.mjs +102 -0
  378. package/scripts/topo-recent-row-hot-test.mjs +110 -0
  379. package/scripts/topo-recent-row-hover-lift-test.mjs +128 -0
  380. package/scripts/topo-recent-row-hover-test.mjs +122 -0
  381. package/scripts/topo-recent-row-pin-spacing-test.mjs +137 -0
  382. package/scripts/topo-recent-row-pin-test.mjs +126 -0
  383. package/scripts/topo-recent-row-tint-test.mjs +91 -0
  384. package/scripts/topo-recent-row-title-test.mjs +112 -0
  385. package/scripts/topo-recent-row-ts-alpha-test.mjs +100 -0
  386. package/scripts/topo-recent-row-ts-test.mjs +95 -0
  387. package/scripts/topo-recent-row-typography-test.mjs +119 -0
  388. package/scripts/topo-recent-signal-empty-hint-test.mjs +73 -0
  389. package/scripts/topo-recent-signal-empty-test.mjs +63 -0
  390. package/scripts/topo-reduced-motion-test.mjs +77 -0
  391. package/scripts/topo-reset-spin-test.mjs +120 -0
  392. package/scripts/topo-runtime-badge-grow-test.mjs +114 -0
  393. package/scripts/topo-spoke-busyness-test.mjs +110 -0
  394. package/scripts/topo-status-chip-hover-test.mjs +101 -0
  395. package/scripts/topo-status-chip-tooltip-test.mjs +95 -0
  396. package/scripts/topo-statusbar-chips-self-hover-test.mjs +177 -0
  397. package/scripts/topo-svg-focus-test.mjs +112 -0
  398. package/scripts/topo-sweep-busyness-test.mjs +94 -0
  399. package/scripts/topo-tier-ring-fadein-test.mjs +107 -0
  400. package/scripts/topo-tier-ring-occupancy-test.mjs +87 -0
  401. package/scripts/topo-tier-ring-test.mjs +69 -0
  402. package/scripts/topo-tier-ring-tint-test.mjs +110 -0
  403. package/scripts/topo-tier-stagger-test.mjs +89 -0
  404. package/scripts/topo-tz-ghost-test.mjs +69 -0
  405. package/scripts/topo-vendor-chip-hover-test.mjs +111 -0
  406. package/scripts/topo-vendor-chip-self-hover-test.mjs +130 -0
  407. package/scripts/topo-vendor-letter-tooltip-test.mjs +92 -0
  408. package/scripts/topo-vendor-pill-test.mjs +125 -0
  409. package/scripts/topo-vendor-pin-test.mjs +125 -0
  410. package/scripts/topo-view-smooth-test.mjs +131 -0
  411. package/scripts/topo-wheel-zoom-test.mjs +79 -0
  412. package/scripts/topo-working-chip-pin-test.mjs +154 -0
  413. package/scripts/topo-working-halo-breath-test.mjs +86 -0
  414. package/scripts/topo-zoom-keys-test.mjs +89 -0
  415. package/.next/static/chunks/0-7iowzu4.798.js +0 -1
  416. package/.next/static/chunks/01h.pqggl08cf.js +0 -1
  417. package/.next/static/chunks/02t5jr4shh.hy.js +0 -1
  418. package/.next/static/chunks/09nd.t_hd.y6t.css +0 -2
  419. package/.next/static/chunks/0_qfg5s5uzs7..js +0 -7
  420. package/.next/static/chunks/0elalb9n_.~di.js +0 -1
  421. package/.next/static/chunks/0fqy_0wj_1xa7.js +0 -7
  422. package/.next/static/chunks/0j_q__o8p6g83.js +0 -1
  423. package/.next/static/chunks/0jl6_w50zh4l5.js +0 -1
  424. package/.next/static/chunks/0r4q73.-1bkyl.js +0 -1
  425. package/.next/static/chunks/0r_c8eccg3z2o.js +0 -1
  426. package/.next/static/chunks/0vize6s4a808r.js +0 -1
  427. package/.next/static/chunks/10oi7l-tycgl9.js +0 -1
  428. package/.next/static/chunks/11uk1izuv3~0t.js +0 -1
  429. package/.next/static/chunks/18dhhyoi_h..v.js +0 -1
  430. /package/.next/static/{ZgfN4dmEdRkfxqN6GWJeP → XCMqFGXs65DvNw_TGcR9u}/_buildManifest.js +0 -0
  431. /package/.next/static/{ZgfN4dmEdRkfxqN6GWJeP → XCMqFGXs65DvNw_TGcR9u}/_clientMiddlewareManifest.js +0 -0
  432. /package/.next/static/{ZgfN4dmEdRkfxqN6GWJeP → XCMqFGXs65DvNw_TGcR9u}/_ssgManifest.js +0 -0
@@ -0,0 +1,116 @@
1
+ /* Round 205 verification: working / online chip-row chips visually
2
+ * recede to opacity 0.5 when their tier is empty, mirroring R204's
3
+ * legend count recede pattern at the chip-row scope.
4
+ *
5
+ * Pre-R205 "0 working" displayed at the same bg-green-500/10 +
6
+ * full opacity as "12 working" — the eye got zero signal that the
7
+ * tier was empty. R205 combines with R139's clickable=false +
8
+ * tooltip-undefined: visual + interactive + affordance all say
9
+ * "nothing to act on".
10
+ *
11
+ * Test scenarios:
12
+ * A. All offline (0 working, 0 online):
13
+ * working chip empty='true', opacity ≈ 0.5
14
+ * online chip empty='true', opacity ≈ 0.5
15
+ * B. All working (4 working, 4 online):
16
+ * working chip empty='false', opacity = 1
17
+ * online chip empty='false', opacity = 1
18
+ * Both: inline transition includes 'opacity 200ms' alongside the
19
+ * existing R180 box-shadow / R201 bg/border transitions.
20
+ */
21
+ import { chromium } from 'playwright';
22
+ import { readFileSync } from 'node:fs';
23
+
24
+ const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
25
+ const browser = await chromium.launch({ headless: true });
26
+
27
+ async function pageFor(allStatus) {
28
+ const ctx = await browser.newContext({ viewport: { width: 1500, height: 1500 } });
29
+ await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
30
+ await ctx.addInitScript(() => {
31
+ try { localStorage.setItem('anet-theme', 'cyber'); sessionStorage.setItem('anet_v3_auth', '1'); } catch {}
32
+ });
33
+ const fresh = new Date(Date.now() - 60 * 1000).toISOString();
34
+ await ctx.route('**/api/hub/status*', async (route) => {
35
+ const r = await route.fetch();
36
+ const b = await r.json();
37
+ const nid = (b.sessions || [])[0]?.network_id || 'default';
38
+ const mk = (alias, status) => ({
39
+ alias, status, model: 'claude-opus-4', runtime: 'cli-claude-code',
40
+ network_id: nid, project_dir: null,
41
+ created_at: fresh, updated_at: fresh, last_seen_at: fresh,
42
+ });
43
+ await route.fulfill({ response: r, json: { ...b, sessions: [
44
+ mk('alpha', allStatus), mk('beta', allStatus),
45
+ mk('gamma', allStatus), mk('delta', allStatus),
46
+ ] } });
47
+ });
48
+ await ctx.route('**/api/hub/messages*', (r2) => r2.fulfill({ json: { messages: [] } }));
49
+ await ctx.route('**/api/hub/tasks*', (r2) => r2.fulfill({ json: { tasks: [] } }));
50
+ const page = await ctx.newPage();
51
+ await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
52
+ await page.waitForFunction(() => document.querySelectorAll('g[data-node]').length === 4, { timeout: 30000 });
53
+ await page.waitForSelector('[data-working-chip]', { timeout: 10000 });
54
+ await page.waitForTimeout(300);
55
+ return page;
56
+ }
57
+
58
+ const probe = async (page) => page.evaluate(() => {
59
+ function pick(sel, emptyKey) {
60
+ const el = document.querySelector(sel);
61
+ if (!el) return null;
62
+ const cs = getComputedStyle(el);
63
+ return {
64
+ empty: el.getAttribute(emptyKey),
65
+ opacity: parseFloat(cs.opacity),
66
+ transition: el.style.transition,
67
+ };
68
+ }
69
+ return {
70
+ working: pick('[data-working-chip]', 'data-working-chip-empty'),
71
+ online: pick('[data-online-chip]', 'data-online-chip-empty'),
72
+ };
73
+ });
74
+
75
+ // Scenario A: all offline → both tiers empty
76
+ const pageA = await pageFor('offline');
77
+ const probeA = await probe(pageA);
78
+ await pageA.close();
79
+
80
+ // Scenario B: all working → both tiers populated
81
+ const pageB = await pageFor('working');
82
+ const probeB = await probe(pageB);
83
+ await pageB.close();
84
+ await browser.close();
85
+
86
+ const near = (got, want, tol = 0.05) => Math.abs(got - want) < tol;
87
+ const hasOpacityTransition = (s) => /opacity\s+(?:200ms|0\.2s)/.test(s || '');
88
+ const hasBgTransition = (s) => /background-color\s+(?:200ms|0\.2s)/.test(s || '');
89
+ const hasBoxShadowTransition = (s) => /box-shadow\s+(?:150ms|0\.15s)/.test(s || '');
90
+
91
+ const results = {
92
+ // Scenario A: all offline
93
+ A_working_empty_attr: probeA.working?.empty === 'true',
94
+ A_working_opacity_half: near(probeA.working?.opacity ?? 0, 0.5),
95
+ A_online_empty_attr: probeA.online?.empty === 'true',
96
+ A_online_opacity_half: near(probeA.online?.opacity ?? 0, 0.5),
97
+
98
+ // Scenario B: all working
99
+ B_working_empty_false: probeB.working?.empty === 'false',
100
+ B_working_opacity_full: near(probeB.working?.opacity ?? 0, 1.0),
101
+ B_online_empty_false: probeB.online?.empty === 'false',
102
+ B_online_opacity_full: near(probeB.online?.opacity ?? 0, 1.0),
103
+
104
+ // Transition list integrity — opacity ADDED, bg/border/box-shadow KEPT
105
+ A_working_transition_opacity: hasOpacityTransition(probeA.working?.transition),
106
+ A_online_transition_opacity: hasOpacityTransition(probeA.online?.transition),
107
+ B_working_transition_opacity: hasOpacityTransition(probeB.working?.transition),
108
+ B_online_transition_opacity: hasOpacityTransition(probeB.online?.transition),
109
+ A_working_keeps_bg_transition: hasBgTransition(probeA.working?.transition),
110
+ A_working_keeps_bs_transition: hasBoxShadowTransition(probeA.working?.transition),
111
+ };
112
+ const ok = Object.values(results).every(Boolean);
113
+ console.log(`${ok ? '✅' : '❌'} chip empty recede:`, JSON.stringify(results),
114
+ `\n probeA (offline):`, probeA,
115
+ `\n probeB (working):`, probeB);
116
+ process.exit(ok ? 0 : 1);
@@ -0,0 +1,95 @@
1
+ /* Round 155 verification: chip-row interactives gain
2
+ * `.anet-topo-chip-focus` for keyboard focus-visible outline,
3
+ * matching R154's chrome-button treatment.
4
+ *
5
+ * Why `outline` not `box-shadow`: the R88 vendor letter / R139
6
+ * working chip / R140 online chip already use inline boxShadow
7
+ * for the pin-mirror inset. Adding focus-visible:ring (which
8
+ * Tailwind paints via box-shadow) would conflict — inline style
9
+ * wins specificity. `outline: 2px solid currentColor` is on a
10
+ * separate CSS property, no conflict; `currentColor` inherits
11
+ * the chip's own accent (green / cyan / per-vendor / etc.).
12
+ *
13
+ * Test: every chip-row interactive surface carries the class.
14
+ */
15
+ import { chromium } from 'playwright';
16
+ import { readFileSync } from 'node:fs';
17
+
18
+ const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
19
+ const browser = await chromium.launch({ headless: true });
20
+
21
+ const ctx = await browser.newContext({ viewport: { width: 1400, height: 1500 } });
22
+ await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
23
+ await ctx.addInitScript(() => {
24
+ try { localStorage.setItem('anet-theme', 'cyber'); sessionStorage.setItem('anet_v3_auth', '1'); } catch {}
25
+ });
26
+ const fresh = new Date(Date.now() - 60 * 1000).toISOString();
27
+ await ctx.route('**/api/hub/status*', async (route) => {
28
+ const r = await route.fetch();
29
+ const b = await r.json();
30
+ const nid = (b.sessions || [])[0]?.network_id || 'default';
31
+ const mk = (alias, status, model) => ({
32
+ alias, status, model, runtime: 'cli-claude-code',
33
+ network_id: nid, project_dir: null,
34
+ created_at: fresh, updated_at: fresh, last_seen_at: fresh,
35
+ });
36
+ await route.fulfill({ response: r, json: { ...b, sessions: [
37
+ mk('alpha', 'working', 'claude-opus-4'),
38
+ mk('beta', 'idle', 'gpt-4o'),
39
+ ] } });
40
+ });
41
+
42
+ const now = Date.now();
43
+ // 1 message to populate flowLinks → active-links chip is interactive
44
+ await ctx.route('**/api/hub/messages*', (route) => route.fulfill({ json: { messages: [
45
+ { id: 'm0', from_alias: 'alpha', to_alias: 'beta', content: 'hi',
46
+ network_id: 'default', created_at: new Date(now - 10000).toISOString() },
47
+ ] } }));
48
+ await ctx.route('**/api/hub/tasks*', (route) => route.fulfill({ json: { tasks: [] } }));
49
+
50
+ const page = await ctx.newPage();
51
+ await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
52
+ await page.waitForFunction(() => document.querySelectorAll('g[data-node]').length === 2, { timeout: 30000 });
53
+ await page.waitForTimeout(400);
54
+
55
+ // Pin status + vendor to surface filter pills + intersection chip
56
+ await page.evaluate(() => {
57
+ window.dispatchEvent(new CustomEvent('anet:topo-pin', { detail: { kind: 'status', value: 'working' } }));
58
+ window.dispatchEvent(new CustomEvent('anet:topo-pin', { detail: { kind: 'vendor', value: 'A' } }));
59
+ });
60
+ await page.waitForTimeout(300);
61
+
62
+ const inspect = () => page.evaluate(() => {
63
+ const has = (sel) => {
64
+ const el = document.querySelector(sel);
65
+ return el && (el.className || '').includes('anet-topo-chip-focus');
66
+ };
67
+ return {
68
+ pressureSeg_working: has('[data-pressure-seg="working"]'),
69
+ workingChip: has('[data-working-chip]'),
70
+ onlineChip: has('[data-online-chip]'),
71
+ vendorLetter_A: has('[data-vendor-letter="A"]'),
72
+ activeLinks: has('[data-active-links-chip]'),
73
+ filterPill_status: has('[data-active-filter="status"]'),
74
+ filterPill_vendor: has('[data-active-filter="vendor"]'),
75
+ intersectionChip: has('[data-pin-intersection]'),
76
+ };
77
+ });
78
+
79
+ const result = await inspect();
80
+ await browser.close();
81
+
82
+ const results = {
83
+ pressureSeg_focusClass: result.pressureSeg_working === true,
84
+ workingChip_focusClass: result.workingChip === true,
85
+ onlineChip_focusClass: result.onlineChip === true,
86
+ vendorLetter_focusClass: result.vendorLetter_A === true,
87
+ activeLinks_focusClass: result.activeLinks === true,
88
+ filterPillStatus_focusClass: result.filterPill_status === true,
89
+ filterPillVendor_focusClass: result.filterPill_vendor === true,
90
+ intersectionChip_focusClass: result.intersectionChip === true,
91
+ };
92
+ const ok = Object.values(results).every(Boolean);
93
+ console.log(`${ok ? '✅' : '❌'} chip focus class:`, JSON.stringify(results),
94
+ `\n raw=`, result);
95
+ process.exit(ok ? 0 : 1);
@@ -0,0 +1,113 @@
1
+ /* Round 82 verification: chip-row "N working" + "N online" chips mirror
2
+ * the pin state already shown by the R60 pressure-bar segments. When
3
+ * pinnedStatus === 'working', the working chip lights up via inset
4
+ * boxShadow + data-pin-mirror="true"; idle pin lights the online chip.
5
+ * Closes the visual inconsistency where pressure-bar + legend showed
6
+ * the pin but the sibling count chips stayed flat.
7
+ *
8
+ * Drive the pin via Cmd+K palette (R69 action) to verify the chip
9
+ * reflects a pin set from a non-chip surface — exercises the full
10
+ * coupling, not just a chip clicking itself.
11
+ */
12
+ import { chromium } from 'playwright';
13
+ import { readFileSync } from 'node:fs';
14
+
15
+ const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
16
+ const browser = await chromium.launch({ headless: true });
17
+
18
+ const ctx = await browser.newContext({ viewport: { width: 1400, height: 1200 } });
19
+ await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
20
+ await ctx.addInitScript(() => {
21
+ try {
22
+ localStorage.setItem('anet-theme', 'cyber');
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
+ await ctx.route('**/api/hub/status*', async (route) => {
31
+ const r = await route.fetch();
32
+ const b = await r.json();
33
+ const nid = (b.sessions || [])[0]?.network_id || 'default';
34
+ const sessions = [
35
+ { alias: 'alpha', status: 'working', model: 'claude-opus-4', runtime: 'cli-claude-code',
36
+ network_id: nid, project_dir: null, created_at: fresh, updated_at: fresh, last_seen_at: fresh },
37
+ { alias: 'beta', status: 'idle', model: 'gpt-5', runtime: 'codex-cli',
38
+ network_id: nid, project_dir: null, created_at: fresh, updated_at: fresh, last_seen_at: fresh },
39
+ ];
40
+ await route.fulfill({ response: r, json: { ...b, sessions } });
41
+ });
42
+ await ctx.route('**/api/hub/messages*', (route) => route.fulfill({ json: { messages: [] } }));
43
+ await ctx.route('**/api/hub/tasks*', (route) => route.fulfill({ json: { tasks: [] } }));
44
+ const page = await ctx.newPage();
45
+ await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
46
+ await page.waitForFunction(() => document.querySelectorAll('g[data-node]').length === 2, { timeout: 30000 });
47
+ await page.waitForTimeout(400);
48
+
49
+ const snap = () => page.evaluate(() => {
50
+ const w = document.querySelector('[data-working-chip]');
51
+ const o = document.querySelector('[data-online-chip]');
52
+ return {
53
+ working: {
54
+ mirror: w?.getAttribute('data-pin-mirror'),
55
+ shadow: w ? (w.getAttribute('style') || '').includes('inset') : false,
56
+ title: w?.getAttribute('title') || '',
57
+ },
58
+ online: {
59
+ mirror: o?.getAttribute('data-pin-mirror'),
60
+ shadow: o ? (o.getAttribute('style') || '').includes('inset') : false,
61
+ title: o?.getAttribute('title') || '',
62
+ },
63
+ };
64
+ });
65
+
66
+ const before = await snap();
67
+
68
+ // Dispatch the R69 CustomEvent directly — same coupling the palette
69
+ // uses, deterministic without fuzzy-match ambiguity. The R69 listener
70
+ // in TopoGraph reads `detail.kind === 'status'` + `detail.value`.
71
+ const pin = async (value) => {
72
+ await page.evaluate((v) => {
73
+ try { sessionStorage.setItem('anet-topo-pinned-status', v); } catch {}
74
+ window.dispatchEvent(new CustomEvent('anet:topo-pin', { detail: { kind: 'status', value: v } }));
75
+ }, value);
76
+ await page.waitForTimeout(200);
77
+ };
78
+ const clear = async () => {
79
+ await page.keyboard.press('Escape');
80
+ await page.waitForTimeout(250);
81
+ };
82
+
83
+ await pin('working');
84
+ const onWorking = await snap();
85
+ await clear();
86
+ const afterWorking = await snap();
87
+
88
+ await pin('idle');
89
+ const onIdle = await snap();
90
+ await clear();
91
+ const afterIdle = await snap();
92
+
93
+ await browser.close();
94
+
95
+ const results = {
96
+ before_workingFlat: before.working.mirror === 'false' && !before.working.shadow,
97
+ before_onlineFlat: before.online.mirror === 'false' && !before.online.shadow,
98
+ workingPin_workingLit: onWorking.working.mirror === 'true' && onWorking.working.shadow,
99
+ workingPin_onlineFlat: onWorking.online.mirror === 'false' && !onWorking.online.shadow,
100
+ workingPin_titleHint: /Pinned/i.test(onWorking.working.title),
101
+ esc_workingFlat: afterWorking.working.mirror === 'false' && !afterWorking.working.shadow,
102
+ esc_onlineUntouched: afterWorking.online.mirror === 'false' && !afterWorking.online.shadow,
103
+ idlePin_onlineLit: onIdle.online.mirror === 'true' && onIdle.online.shadow,
104
+ idlePin_workingFlat: onIdle.working.mirror === 'false' && !onIdle.working.shadow,
105
+ idlePin_titleHint: /Pinned/i.test(onIdle.online.title),
106
+ esc_onlineFlat: afterIdle.online.mirror === 'false' && !afterIdle.online.shadow,
107
+ };
108
+ const ok = Object.values(results).every(Boolean);
109
+ console.log(`${ok ? '✅' : '❌'} chip pin-mirror:`, JSON.stringify(results),
110
+ `\n before=`, before,
111
+ `\n onWorking=`, onWorking,
112
+ `\n onIdle=`, onIdle);
113
+ process.exit(ok ? 0 : 1);
@@ -0,0 +1,107 @@
1
+ /* Round 154 verification: TopoGraph chrome buttons gain stable
2
+ * data-* hooks for tests + focus-visible ring matching the
3
+ * dashboard's cyan accent (browser default focus outline often
4
+ * vanishes on the dark canvas).
5
+ *
6
+ * Chrome inventory (bottom-right of canvas):
7
+ * data-topo-chrome (wrapper div)
8
+ * data-topo-chrome-nodesize=S|M|L (segmented control, R113)
9
+ * data-topo-chrome-nodesize-active="true|false"
10
+ * data-topo-chrome-zoom-out (R104)
11
+ * data-topo-chrome-zoom-level (readout, also R104)
12
+ * data-topo-chrome-zoom-in
13
+ * data-topo-chrome-reset
14
+ * data-topo-chrome-fullscreen
15
+ * data-topo-chrome-fullscreen-active="true|false"
16
+ *
17
+ * Each button gains focus-visible:ring-1 ring-cyan-400/60. Tabs
18
+ * land somewhere visible.
19
+ *
20
+ * Test: every chrome button surfaces its data attribute, plus the
21
+ * three S/M/L buttons report active correctly when one is picked.
22
+ */
23
+ import { chromium } from 'playwright';
24
+ import { readFileSync } from 'node:fs';
25
+
26
+ const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
27
+ const browser = await chromium.launch({ headless: true });
28
+
29
+ const ctx = await browser.newContext({ viewport: { width: 1400, height: 1500 } });
30
+ await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
31
+ await ctx.addInitScript(() => {
32
+ try { localStorage.setItem('anet-theme', 'cyber'); sessionStorage.setItem('anet_v3_auth', '1'); } catch {}
33
+ });
34
+ const fresh = new Date(Date.now() - 60 * 1000).toISOString();
35
+ await ctx.route('**/api/hub/status*', async (route) => {
36
+ const r = await route.fetch();
37
+ const b = await r.json();
38
+ const nid = (b.sessions || [])[0]?.network_id || 'default';
39
+ const mk = (alias) => ({
40
+ alias, status: 'working', model: 'claude-opus-4', runtime: 'cli-claude-code',
41
+ network_id: nid, project_dir: null,
42
+ created_at: fresh, updated_at: fresh, last_seen_at: fresh,
43
+ });
44
+ await route.fulfill({ response: r, json: { ...b, sessions: [mk('alpha'), mk('beta')] } });
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
+
49
+ const page = await ctx.newPage();
50
+ await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
51
+ await page.waitForFunction(() => document.querySelectorAll('g[data-node]').length === 2, { timeout: 30000 });
52
+ await page.waitForSelector('[data-topo-chrome]', { timeout: 10000 });
53
+ await page.waitForTimeout(300);
54
+
55
+ const inspect = () => page.evaluate(() => {
56
+ const sel = (s) => document.querySelector(s);
57
+ const all = (s) => [...document.querySelectorAll(s)];
58
+ return {
59
+ wrapper: !!sel('[data-topo-chrome]'),
60
+ nodesizeS: sel('[data-topo-chrome-nodesize="S"]')?.getAttribute('data-topo-chrome-nodesize-active'),
61
+ nodesizeM: sel('[data-topo-chrome-nodesize="M"]')?.getAttribute('data-topo-chrome-nodesize-active'),
62
+ nodesizeL: sel('[data-topo-chrome-nodesize="L"]')?.getAttribute('data-topo-chrome-nodesize-active'),
63
+ zoomOut: !!sel('[data-topo-chrome-zoom-out]'),
64
+ zoomLevel: sel('[data-topo-chrome-zoom-level]')?.textContent?.trim(),
65
+ zoomIn: !!sel('[data-topo-chrome-zoom-in]'),
66
+ reset: !!sel('[data-topo-chrome-reset]'),
67
+ fullscreen: !!sel('[data-topo-chrome-fullscreen]'),
68
+ fullscreenActive: sel('[data-topo-chrome-fullscreen]')?.getAttribute('data-topo-chrome-fullscreen-active'),
69
+ // focus-visible ring is a CSS pseudo-class; just verify the
70
+ // className carries the focus-visible:ring tokens.
71
+ chromeButtonsHaveFocusRing: all('[data-topo-chrome] button').every(b =>
72
+ (b.className || '').includes('focus-visible:ring')),
73
+ };
74
+ });
75
+
76
+ const before = await inspect();
77
+
78
+ // Click L → it becomes active, M becomes inactive (default)
79
+ await page.locator('[data-topo-chrome-nodesize="L"]').click();
80
+ await page.waitForTimeout(150);
81
+ const afterL = await inspect();
82
+
83
+ await browser.close();
84
+
85
+ const results = {
86
+ wrapper_present: before.wrapper === true,
87
+ nodesizeS_present: before.nodesizeS === 'false',
88
+ nodesizeM_activeDefault: before.nodesizeM === 'true', // default scale 0.84 → M
89
+ nodesizeL_present: before.nodesizeL === 'false',
90
+ zoomOut_present: before.zoomOut === true,
91
+ zoomLevel_100pct: before.zoomLevel === '100%',
92
+ zoomIn_present: before.zoomIn === true,
93
+ reset_present: before.reset === true,
94
+ fullscreen_present: before.fullscreen === true,
95
+ fullscreenActive_false: before.fullscreenActive === 'false',
96
+ focusRing_onAllButtons: before.chromeButtonsHaveFocusRing === true,
97
+
98
+ // After clicking L: active flips to L
99
+ afterL_LActive: afterL.nodesizeL === 'true',
100
+ afterL_MInactive: afterL.nodesizeM === 'false',
101
+ afterL_SInactive: afterL.nodesizeS === 'false',
102
+ };
103
+ const ok = Object.values(results).every(Boolean);
104
+ console.log(`${ok ? '✅' : '❌'} chrome a11y:`, JSON.stringify(results),
105
+ `\n before=`, before,
106
+ `\n afterL=`, afterL);
107
+ process.exit(ok ? 0 : 1);
@@ -0,0 +1,135 @@
1
+ /* Round 196 verification: every chrome button picks up an active:
2
+ * (pressed) state for tactile click feedback. Bridges the gap between
3
+ * mouse-down and the existing release-pop animations:
4
+ * R184 reset-spin (0.45s rotation on release)
5
+ * R186 +/− icon pop (0.22s scale on release)
6
+ * R192 readout pop (same 0.22s on release)
7
+ * Pre-R196 mouse-down → release was instant; nothing acknowledged the
8
+ * held-down phase. R196 lays a darker bg under the cursor while held.
9
+ *
10
+ * Buttons covered:
11
+ * layout Ring / Grid (active variant: cyan-500/25, base: cyan-500/15)
12
+ * nodeSize S / M / L (active: cyan-500/25, base: white/10)
13
+ * zoom-out / zoom-in (white/10)
14
+ * reset (white/10)
15
+ * fullscreen (active: cyan-500/25, base: white/10)
16
+ *
17
+ * Test:
18
+ * 1. Static markup check — each button's class string contains the
19
+ * 'active:bg-...' modifier(s).
20
+ * 2. Runtime check on zoom-out: mouse.down on the button, getComputed-
21
+ * Style snapshot — backgroundColor differs from the idle/hover bg.
22
+ * Mouse.up + move off — back to idle bg.
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
+ const browser = await chromium.launch({ headless: true });
29
+
30
+ const ctx = await browser.newContext({ viewport: { width: 1500, height: 1500 } });
31
+ await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
32
+ await ctx.addInitScript(() => {
33
+ try { localStorage.setItem('anet-theme', 'cyber'); sessionStorage.setItem('anet_v3_auth', '1'); } catch {}
34
+ });
35
+
36
+ const fresh = new Date(Date.now() - 60 * 1000).toISOString();
37
+ await ctx.route('**/api/hub/status*', async (route) => {
38
+ const r = await route.fetch();
39
+ const b = await r.json();
40
+ const nid = (b.sessions || [])[0]?.network_id || 'default';
41
+ const mk = (alias) => ({
42
+ alias, status: 'working', model: 'claude-opus-4', runtime: 'cli-claude-code',
43
+ network_id: nid, project_dir: null,
44
+ created_at: fresh, updated_at: fresh, last_seen_at: fresh,
45
+ });
46
+ await route.fulfill({ response: r, json: { ...b, sessions: [
47
+ mk('alpha'), mk('beta'), mk('gamma'), mk('delta'),
48
+ ] } });
49
+ });
50
+ await ctx.route('**/api/hub/messages*', (route) => route.fulfill({ json: { messages: [] } }));
51
+ await ctx.route('**/api/hub/tasks*', (route) => route.fulfill({ json: { tasks: [] } }));
52
+
53
+ const page = await ctx.newPage();
54
+ await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
55
+ await page.waitForFunction(() => document.querySelectorAll('g[data-node]').length === 4, { timeout: 30000 });
56
+ await page.waitForSelector('[data-topo-chrome-zoom-in]', { timeout: 10000 });
57
+ await page.waitForTimeout(300);
58
+
59
+ // Collect all chrome button className strings
60
+ const markup = await page.evaluate(() => ({
61
+ layoutRing: document.querySelector('[data-topo-chrome-layout="ring"]')?.getAttribute('class') || '',
62
+ layoutGrid: document.querySelector('[data-topo-chrome-layout="grid"]')?.getAttribute('class') || '',
63
+ nodeSizeS: document.querySelector('[data-topo-chrome-nodesize="S"]')?.getAttribute('class') || '',
64
+ nodeSizeM: document.querySelector('[data-topo-chrome-nodesize="M"]')?.getAttribute('class') || '',
65
+ nodeSizeL: document.querySelector('[data-topo-chrome-nodesize="L"]')?.getAttribute('class') || '',
66
+ zoomOut: document.querySelector('[data-topo-chrome-zoom-out]')?.getAttribute('class') || '',
67
+ zoomIn: document.querySelector('[data-topo-chrome-zoom-in]')?.getAttribute('class') || '',
68
+ reset: document.querySelector('[data-topo-chrome-reset]')?.getAttribute('class') || '',
69
+ fullscreen: document.querySelector('[data-topo-chrome-fullscreen]')?.getAttribute('class') || '',
70
+ }));
71
+
72
+ // Static markup assertions
73
+ const has = (s, modifier) => s.includes(modifier);
74
+ const staticChecks = {
75
+ layoutRing_press_active: has(markup.layoutRing, 'active:bg-cyan-500/15') || has(markup.layoutRing, 'active:bg-cyan-500/25'),
76
+ layoutGrid_press_active: has(markup.layoutGrid, 'active:bg-cyan-500/15') || has(markup.layoutGrid, 'active:bg-cyan-500/25'),
77
+ // nodeSize S/M/L: idle nodeScale=L default, so S/M are non-active
78
+ // variant (active:bg-white/10); L is the active cyan variant
79
+ // (active:bg-cyan-500/25). Check at least one of each pattern present.
80
+ nodeSizeS_press: has(markup.nodeSizeS, 'active:bg-white/10') || has(markup.nodeSizeS, 'active:bg-cyan-500/25'),
81
+ nodeSizeM_press: has(markup.nodeSizeM, 'active:bg-white/10') || has(markup.nodeSizeM, 'active:bg-cyan-500/25'),
82
+ nodeSizeL_press: has(markup.nodeSizeL, 'active:bg-white/10') || has(markup.nodeSizeL, 'active:bg-cyan-500/25'),
83
+ zoomOut_press_white: has(markup.zoomOut, 'active:bg-white/10'),
84
+ zoomIn_press_white: has(markup.zoomIn, 'active:bg-white/10'),
85
+ reset_press_white: has(markup.reset, 'active:bg-white/10'),
86
+ fullscreen_press: has(markup.fullscreen, 'active:bg-white/10') || has(markup.fullscreen, 'active:bg-cyan-500/25'),
87
+ };
88
+
89
+ // Stylesheet-presence check: walk document.styleSheets recursively
90
+ // and confirm Tailwind compiled the press-state rules into the page's
91
+ // CSS. Tailwind 4 nests utilities inside @layer utilities { ... } as
92
+ // a single grouping rule, so cssRules iteration must recurse.
93
+ // Synthetic Playwright pointer events don't reliably trigger
94
+ // :hover/:active in headless Chromium, so runtime computed-style
95
+ // snapshots are unreliable. Checking that the rule exists in the
96
+ // page's stylesheets is the closest static guarantee that a real
97
+ // user's click will deepen the bg.
98
+ const cssChecks = await page.evaluate(() => {
99
+ const activeRules = [];
100
+ function walk(list) {
101
+ for (const r of list || []) {
102
+ if (r.selectorText && r.selectorText.includes(':active')) {
103
+ activeRules.push({ selector: r.selectorText, text: r.cssText });
104
+ }
105
+ if (r.cssRules) walk(r.cssRules);
106
+ }
107
+ }
108
+ for (const sheet of document.styleSheets) {
109
+ let list;
110
+ try { list = sheet.cssRules; } catch { continue; }
111
+ walk(list);
112
+ }
113
+ // For each modifier the markup uses, verify at least one matching
114
+ // CSSStyleRule exists. Tailwind 4 emits each rule twice (an RGBA
115
+ // fallback and a color-mix() form), so .some() across either is fine.
116
+ const has = (selectorSubstr) =>
117
+ activeRules.some(r => r.selector.includes(selectorSubstr));
118
+ return {
119
+ css_active_white_10: has('active\\:bg-white\\/10'),
120
+ css_active_cyan_25: has('active\\:bg-cyan-500\\/25'),
121
+ css_active_cyan_15: has('active\\:bg-cyan-500\\/15'),
122
+ sample_active_rules: activeRules.length,
123
+ };
124
+ });
125
+
126
+ await browser.close();
127
+
128
+ const results = { ...staticChecks, ...cssChecks };
129
+ // Boolean fields must be true; numeric sample_active_rules just needs > 0.
130
+ const ok = Object.entries(results).every(([k, v]) =>
131
+ k.startsWith('sample_') ? (typeof v === 'number' && v > 0) : v === true);
132
+ console.log(`${ok ? '✅' : '❌'} chrome press-state:`, JSON.stringify(results),
133
+ `\n markup snippets:`,
134
+ Object.fromEntries(Object.entries(markup).map(([k, v]) => [k, v.match(/active:bg-[^\s]+/g)?.join(' ') || '(no active: classes)'])));
135
+ process.exit(ok ? 0 : 1);