@sleep2agi/agent-network-dashboard 0.4.6-preview.99 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (448) hide show
  1. package/.next/BUILD_ID +1 -1
  2. package/.next/app-path-routes-manifest.json +2 -0
  3. package/.next/build-manifest.json +3 -3
  4. package/.next/diagnostics/route-bundle-stats.json +31 -31
  5. package/.next/fallback-build-manifest.json +3 -3
  6. package/.next/prerender-manifest.json +3 -3
  7. package/.next/routes-manifest.json +16 -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/server/[hostname]/agents/route/app-paths-manifest.json +3 -0
  34. package/.next/server/app/api/hub/server/[hostname]/agents/route/build-manifest.json +9 -0
  35. package/.next/server/app/api/hub/server/[hostname]/agents/route/server-reference-manifest.json +4 -0
  36. package/.next/server/app/api/hub/server/[hostname]/agents/route.js +7 -0
  37. package/.next/server/app/api/hub/server/[hostname]/agents/route.js.map +5 -0
  38. package/.next/server/app/api/hub/server/[hostname]/agents/route.js.nft.json +1 -0
  39. package/.next/server/app/api/hub/server/[hostname]/agents/route_client-reference-manifest.js +3 -0
  40. package/.next/server/app/api/hub/server/[hostname]/health/route/app-paths-manifest.json +3 -0
  41. package/.next/server/app/api/hub/server/[hostname]/health/route/build-manifest.json +9 -0
  42. package/.next/server/app/api/hub/server/[hostname]/health/route/server-reference-manifest.json +4 -0
  43. package/.next/server/app/api/hub/server/[hostname]/health/route.js +7 -0
  44. package/.next/server/app/api/hub/server/[hostname]/health/route.js.map +5 -0
  45. package/.next/server/app/api/hub/server/[hostname]/health/route.js.nft.json +1 -0
  46. package/.next/server/app/api/hub/server/[hostname]/health/route_client-reference-manifest.js +3 -0
  47. package/.next/server/app/index.html +2 -2
  48. package/.next/server/app/index.rsc +14 -14
  49. package/.next/server/app/index.segments/__PAGE__.segment.rsc +4 -4
  50. package/.next/server/app/index.segments/_full.segment.rsc +14 -14
  51. package/.next/server/app/index.segments/_head.segment.rsc +4 -4
  52. package/.next/server/app/index.segments/_index.segment.rsc +7 -7
  53. package/.next/server/app/index.segments/_tree.segment.rsc +2 -2
  54. package/.next/server/app/login/page_client-reference-manifest.js +1 -1
  55. package/.next/server/app/login.html +2 -2
  56. package/.next/server/app/login.rsc +14 -14
  57. package/.next/server/app/login.segments/_full.segment.rsc +14 -14
  58. package/.next/server/app/login.segments/_head.segment.rsc +4 -4
  59. package/.next/server/app/login.segments/_index.segment.rsc +7 -7
  60. package/.next/server/app/login.segments/_tree.segment.rsc +2 -2
  61. package/.next/server/app/login.segments/login/__PAGE__.segment.rsc +4 -4
  62. package/.next/server/app/login.segments/login.segment.rsc +3 -3
  63. package/.next/server/app/logs/page_client-reference-manifest.js +1 -1
  64. package/.next/server/app/logs.html +2 -2
  65. package/.next/server/app/logs.rsc +14 -14
  66. package/.next/server/app/logs.segments/_full.segment.rsc +14 -14
  67. package/.next/server/app/logs.segments/_head.segment.rsc +4 -4
  68. package/.next/server/app/logs.segments/_index.segment.rsc +7 -7
  69. package/.next/server/app/logs.segments/_tree.segment.rsc +2 -2
  70. package/.next/server/app/logs.segments/logs/__PAGE__.segment.rsc +4 -4
  71. package/.next/server/app/logs.segments/logs.segment.rsc +3 -3
  72. package/.next/server/app/messages/page_client-reference-manifest.js +1 -1
  73. package/.next/server/app/messages.html +2 -2
  74. package/.next/server/app/messages.rsc +14 -14
  75. package/.next/server/app/messages.segments/_full.segment.rsc +14 -14
  76. package/.next/server/app/messages.segments/_head.segment.rsc +4 -4
  77. package/.next/server/app/messages.segments/_index.segment.rsc +7 -7
  78. package/.next/server/app/messages.segments/_tree.segment.rsc +2 -2
  79. package/.next/server/app/messages.segments/messages/__PAGE__.segment.rsc +4 -4
  80. package/.next/server/app/messages.segments/messages.segment.rsc +3 -3
  81. package/.next/server/app/node/page_client-reference-manifest.js +1 -1
  82. package/.next/server/app/node.html +2 -2
  83. package/.next/server/app/node.rsc +14 -14
  84. package/.next/server/app/node.segments/_full.segment.rsc +14 -14
  85. package/.next/server/app/node.segments/_head.segment.rsc +4 -4
  86. package/.next/server/app/node.segments/_index.segment.rsc +7 -7
  87. package/.next/server/app/node.segments/_tree.segment.rsc +2 -2
  88. package/.next/server/app/node.segments/node/__PAGE__.segment.rsc +4 -4
  89. package/.next/server/app/node.segments/node.segment.rsc +3 -3
  90. package/.next/server/app/nodes/page_client-reference-manifest.js +1 -1
  91. package/.next/server/app/nodes.html +2 -2
  92. package/.next/server/app/nodes.rsc +14 -14
  93. package/.next/server/app/nodes.segments/_full.segment.rsc +14 -14
  94. package/.next/server/app/nodes.segments/_head.segment.rsc +4 -4
  95. package/.next/server/app/nodes.segments/_index.segment.rsc +7 -7
  96. package/.next/server/app/nodes.segments/_tree.segment.rsc +2 -2
  97. package/.next/server/app/nodes.segments/nodes/__PAGE__.segment.rsc +4 -4
  98. package/.next/server/app/nodes.segments/nodes.segment.rsc +3 -3
  99. package/.next/server/app/page_client-reference-manifest.js +1 -1
  100. package/.next/server/app/server-logs/page_client-reference-manifest.js +1 -1
  101. package/.next/server/app/server-logs.html +2 -2
  102. package/.next/server/app/server-logs.rsc +14 -14
  103. package/.next/server/app/server-logs.segments/_full.segment.rsc +14 -14
  104. package/.next/server/app/server-logs.segments/_head.segment.rsc +4 -4
  105. package/.next/server/app/server-logs.segments/_index.segment.rsc +7 -7
  106. package/.next/server/app/server-logs.segments/_tree.segment.rsc +2 -2
  107. package/.next/server/app/server-logs.segments/server-logs/__PAGE__.segment.rsc +4 -4
  108. package/.next/server/app/server-logs.segments/server-logs.segment.rsc +3 -3
  109. package/.next/server/app/settings/networks/page_client-reference-manifest.js +1 -1
  110. package/.next/server/app/settings/networks.html +2 -2
  111. package/.next/server/app/settings/networks.rsc +14 -14
  112. package/.next/server/app/settings/networks.segments/_full.segment.rsc +14 -14
  113. package/.next/server/app/settings/networks.segments/_head.segment.rsc +4 -4
  114. package/.next/server/app/settings/networks.segments/_index.segment.rsc +7 -7
  115. package/.next/server/app/settings/networks.segments/_tree.segment.rsc +2 -2
  116. package/.next/server/app/settings/networks.segments/settings/networks/__PAGE__.segment.rsc +4 -4
  117. package/.next/server/app/settings/networks.segments/settings/networks.segment.rsc +3 -3
  118. package/.next/server/app/settings/networks.segments/settings.segment.rsc +3 -3
  119. package/.next/server/app/settings/page_client-reference-manifest.js +1 -1
  120. package/.next/server/app/settings/tokens/page_client-reference-manifest.js +1 -1
  121. package/.next/server/app/settings/tokens.html +2 -2
  122. package/.next/server/app/settings/tokens.rsc +14 -14
  123. package/.next/server/app/settings/tokens.segments/_full.segment.rsc +14 -14
  124. package/.next/server/app/settings/tokens.segments/_head.segment.rsc +4 -4
  125. package/.next/server/app/settings/tokens.segments/_index.segment.rsc +7 -7
  126. package/.next/server/app/settings/tokens.segments/_tree.segment.rsc +2 -2
  127. package/.next/server/app/settings/tokens.segments/settings/tokens/__PAGE__.segment.rsc +4 -4
  128. package/.next/server/app/settings/tokens.segments/settings/tokens.segment.rsc +3 -3
  129. package/.next/server/app/settings/tokens.segments/settings.segment.rsc +3 -3
  130. package/.next/server/app/settings.html +2 -2
  131. package/.next/server/app/settings.rsc +14 -14
  132. package/.next/server/app/settings.segments/_full.segment.rsc +14 -14
  133. package/.next/server/app/settings.segments/_head.segment.rsc +4 -4
  134. package/.next/server/app/settings.segments/_index.segment.rsc +7 -7
  135. package/.next/server/app/settings.segments/_tree.segment.rsc +2 -2
  136. package/.next/server/app/settings.segments/settings/__PAGE__.segment.rsc +4 -4
  137. package/.next/server/app/settings.segments/settings.segment.rsc +3 -3
  138. package/.next/server/app/tasks/[id]/page_client-reference-manifest.js +1 -1
  139. package/.next/server/app/tasks/page_client-reference-manifest.js +1 -1
  140. package/.next/server/app/tasks.html +2 -2
  141. package/.next/server/app/tasks.rsc +14 -14
  142. package/.next/server/app/tasks.segments/_full.segment.rsc +14 -14
  143. package/.next/server/app/tasks.segments/_head.segment.rsc +4 -4
  144. package/.next/server/app/tasks.segments/_index.segment.rsc +7 -7
  145. package/.next/server/app/tasks.segments/_tree.segment.rsc +2 -2
  146. package/.next/server/app/tasks.segments/tasks/__PAGE__.segment.rsc +4 -4
  147. package/.next/server/app/tasks.segments/tasks.segment.rsc +3 -3
  148. package/.next/server/app-paths-manifest.json +2 -0
  149. package/.next/server/chunks/0dk5_next-internal_server_app_api_hub_server_[hostname]_agents_route_actions_0vr92s4.js +3 -0
  150. package/.next/server/chunks/0dk5_next-internal_server_app_api_hub_server_[hostname]_agents_route_actions_0vr92s4.js.map +1 -0
  151. package/.next/server/chunks/0dk5_next-internal_server_app_api_hub_server_[hostname]_health_route_actions_0vr-bv5.js +3 -0
  152. package/.next/server/chunks/0dk5_next-internal_server_app_api_hub_server_[hostname]_health_route_actions_0vr-bv5.js.map +1 -0
  153. package/.next/server/chunks/[root-of-the-server]__05nyivw._.js +3 -0
  154. package/.next/server/chunks/[root-of-the-server]__05nyivw._.js.map +1 -0
  155. package/.next/server/chunks/[root-of-the-server]__0floe3h._.js +3 -0
  156. package/.next/server/chunks/[root-of-the-server]__0floe3h._.js.map +1 -0
  157. package/.next/server/chunks/[root-of-the-server]__0tx8s8i._.js +1 -1
  158. package/.next/server/chunks/[root-of-the-server]__0tx8s8i._.js.map +1 -1
  159. package/.next/server/chunks/ssr/agent-network-dashboard_09kk21a._.js +4 -2
  160. package/.next/server/chunks/ssr/agent-network-dashboard_09kk21a._.js.map +1 -1
  161. package/.next/server/chunks/ssr/agent-network-dashboard_app_01jhlxz._.js +1 -1
  162. package/.next/server/chunks/ssr/agent-network-dashboard_app_01jhlxz._.js.map +1 -1
  163. package/.next/server/chunks/ssr/agent-network-dashboard_app_09d29my._.js +1 -1
  164. package/.next/server/chunks/ssr/agent-network-dashboard_app_09d29my._.js.map +1 -1
  165. package/.next/server/chunks/ssr/agent-network-dashboard_app_components_0mvyi-4._.js +1 -1
  166. package/.next/server/chunks/ssr/agent-network-dashboard_app_components_0mvyi-4._.js.map +1 -1
  167. package/.next/server/middleware-build-manifest.js +3 -3
  168. package/.next/server/pages/404.html +2 -2
  169. package/.next/server/pages/500.html +1 -1
  170. package/.next/server/server-reference-manifest.js +1 -1
  171. package/.next/server/server-reference-manifest.json +1 -1
  172. package/.next/static/chunks/0aauz~36q5n2a.css +2 -0
  173. package/.next/static/chunks/0f~0kgy2pycyc.js +1 -0
  174. package/.next/static/chunks/0l_~q07bhpkcx.js +7 -0
  175. package/.next/static/chunks/1175-dp18a1e_.js +1 -0
  176. package/.next/static/chunks/1552j0415oeal.js +4 -0
  177. package/.next/trace +2 -2
  178. package/.next/trace-build +1 -1
  179. package/.next/types/routes.d.ts +3 -1
  180. package/.next/types/validator.ts +18 -0
  181. package/app/api/hub/server/[hostname]/agents/route.ts +62 -0
  182. package/app/api/hub/server/[hostname]/health/route.ts +58 -0
  183. package/app/api/hub/servers/route.ts +88 -1
  184. package/app/components/CommandPalette.tsx +41 -1
  185. package/app/components/HelpOverlay.tsx +55 -0
  186. package/app/components/ServersDrawer.tsx +181 -5
  187. package/app/components/TopoGraph.tsx +5514 -336
  188. package/app/globals.css +93 -6
  189. package/app/lib/vendorIdentity.ts +14 -3
  190. package/docs/rfc/v0.10.0-hero3-dashboard-upgrade.md +230 -0
  191. package/package.json +2 -2
  192. package/public/sleep2agi-logo.svg +11 -0
  193. package/public/vendors/claude.svg +11 -0
  194. package/public/vendors/minimax.svg +11 -0
  195. package/public/vendors/openai.svg +12 -0
  196. package/screenshots/r293-p0/after-full.png +0 -0
  197. package/screenshots/r293-p0/after-topo.png +0 -0
  198. package/screenshots/r293-p0/baseline-full.png +0 -0
  199. package/screenshots/r293-p0/baseline-topo.png +0 -0
  200. package/screenshots/r293-p0/logo-integrated-full.png +0 -0
  201. package/screenshots/r293-p0/logo-integrated-topo.png +0 -0
  202. package/screenshots/r293-p0/servers-drawer-v0.10.0-full.png +0 -0
  203. package/screenshots/r293-p0/servers-drawer-v0.10.0.png +0 -0
  204. package/screenshots/r293-p0/wave1-after-full.png +0 -0
  205. package/screenshots/r293-p0/wave1-after-topo.png +0 -0
  206. package/scripts/p0-servers-drawer-screenshot.mjs +99 -0
  207. package/scripts/p0-topo-screenshot.mjs +82 -0
  208. package/scripts/topo-active-links-chip-nav-test.mjs +117 -0
  209. package/scripts/topo-active-links-chip-self-hover-test.mjs +171 -0
  210. package/scripts/topo-active-links-empty-recede-test.mjs +125 -0
  211. package/scripts/topo-active-links-freshness-test.mjs +113 -0
  212. package/scripts/topo-active-links-tooltip-test.mjs +79 -0
  213. package/scripts/topo-active-pulse-ease-test.mjs +120 -0
  214. package/scripts/topo-brand-logo-transition-test.mjs +94 -0
  215. package/scripts/topo-brand-watermark-test.mjs +97 -0
  216. package/scripts/topo-canvas-aria-test.mjs +108 -0
  217. package/scripts/topo-canvas-brand-fade-test.mjs +87 -0
  218. package/scripts/topo-chat-target-breath-test.mjs +84 -0
  219. package/scripts/topo-chat-target-ring-ease-test.mjs +82 -0
  220. package/scripts/topo-chat-target-ring-fade-test.mjs +124 -0
  221. package/scripts/topo-chip-empty-recede-test.mjs +116 -0
  222. package/scripts/topo-chip-focus-test.mjs +95 -0
  223. package/scripts/topo-chip-row-gap-test.mjs +90 -0
  224. package/scripts/topo-chip-row-semantic-gap-test.mjs +97 -0
  225. package/scripts/topo-chip-row-tabular-test.mjs +111 -0
  226. package/scripts/topo-chip-unit-demotion-test.mjs +93 -0
  227. package/scripts/topo-chiprow-data-weight-test.mjs +94 -0
  228. package/scripts/topo-chrome-a11y-test.mjs +107 -0
  229. package/scripts/topo-chrome-active-weight-test.mjs +104 -0
  230. package/scripts/topo-chrome-focus-ring-unify-test.mjs +100 -0
  231. package/scripts/topo-chrome-gap-test.mjs +73 -0
  232. package/scripts/topo-chrome-icon-stroke-test.mjs +95 -0
  233. package/scripts/topo-chrome-inactive-color-test.mjs +90 -0
  234. package/scripts/topo-chrome-pop-extension-test.mjs +98 -0
  235. package/scripts/topo-chrome-pop-nodesize-test.mjs +88 -0
  236. package/scripts/topo-chrome-press-state-test.mjs +135 -0
  237. package/scripts/topo-chrome-strip-semantic-gap-test.mjs +99 -0
  238. package/scripts/topo-chrome-strip-theme-ease-test.mjs +99 -0
  239. package/scripts/topo-chrome-zoom-level-pop-test.mjs +122 -0
  240. package/scripts/topo-chrome-zoom-pop-test.mjs +130 -0
  241. package/scripts/topo-chrome-zoom-readout-weight-test.mjs +81 -0
  242. package/scripts/topo-click-ripple-ease-test.mjs +94 -0
  243. package/scripts/topo-cmdk-edge-clear-test.mjs +109 -0
  244. package/scripts/topo-cmdk-vendor-pin-test.mjs +103 -0
  245. package/scripts/topo-corner-radius-unify-test.mjs +103 -0
  246. package/scripts/topo-dense-alias-fill-transition-test.mjs +133 -0
  247. package/scripts/topo-discrete-zoom-smooth-test.mjs +125 -0
  248. package/scripts/topo-edge-badge-click-pin-test.mjs +94 -0
  249. package/scripts/topo-edge-badge-crossfade-test.mjs +138 -0
  250. package/scripts/topo-edge-badge-hot-test.mjs +115 -0
  251. package/scripts/topo-edge-badge-hover-test.mjs +85 -0
  252. package/scripts/topo-edge-badge-lift-test.mjs +150 -0
  253. package/scripts/topo-edge-badge-ripple-test.mjs +111 -0
  254. package/scripts/topo-edge-badge-stroke-transition-test.mjs +118 -0
  255. package/scripts/topo-edge-badge-text-pin-test.mjs +121 -0
  256. package/scripts/topo-edge-badge-theme-ease-test.mjs +89 -0
  257. package/scripts/topo-edge-count-badge-test.mjs +86 -0
  258. package/scripts/topo-edge-fadein-test.mjs +106 -0
  259. package/scripts/topo-edge-pill-hot-test.mjs +129 -0
  260. package/scripts/topo-edge-pill-test.mjs +105 -0
  261. package/scripts/topo-edge-ping-pulse-retired-test.mjs +119 -0
  262. package/scripts/topo-edge-stroke-ease-test.mjs +100 -0
  263. package/scripts/topo-edge-stroke-transition-test.mjs +132 -0
  264. package/scripts/topo-empty-hint-tracking-test.mjs +84 -0
  265. package/scripts/topo-empty-state-breath-test.mjs +150 -0
  266. package/scripts/topo-empty-state-crossfade-test.mjs +130 -0
  267. package/scripts/topo-empty-state-recenter-test.mjs +107 -0
  268. package/scripts/topo-empty-subhint-tracking-test.mjs +87 -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-filter-pill-aliases-test.mjs +121 -0
  273. package/scripts/topo-filter-pill-count-tabular-test.mjs +135 -0
  274. package/scripts/topo-freshness-chip-transition-test.mjs +80 -0
  275. package/scripts/topo-freshness-chip-weight-test.mjs +90 -0
  276. package/scripts/topo-freshness-conditional-render-test.mjs +92 -0
  277. package/scripts/topo-fullscreen-active-test.mjs +115 -0
  278. package/scripts/topo-group-label-a11y-test.mjs +113 -0
  279. package/scripts/topo-group-label-count-inherit-test.mjs +99 -0
  280. package/scripts/topo-group-label-pin-spacing-test.mjs +136 -0
  281. package/scripts/topo-group-label-tint-test.mjs +99 -0
  282. package/scripts/topo-group-label-title-test.mjs +83 -0
  283. package/scripts/topo-group-pip-fadein-test.mjs +104 -0
  284. package/scripts/topo-group-pip-singletier-drop-test.mjs +131 -0
  285. package/scripts/topo-group-pip-tabular-test.mjs +95 -0
  286. package/scripts/topo-groupbox-fadein-test.mjs +95 -0
  287. package/scripts/topo-groupbox-hover-lift-test.mjs +127 -0
  288. package/scripts/topo-groupbox-hubcore-ease-test.mjs +106 -0
  289. package/scripts/topo-groupbox-march-busyness-test.mjs +155 -0
  290. package/scripts/topo-header-gap-test.mjs +94 -0
  291. package/scripts/topo-help-overlay-r109-test.mjs +67 -0
  292. package/scripts/topo-help-overlay-r118-test.mjs +69 -0
  293. package/scripts/topo-help-overlay-r123-test.mjs +69 -0
  294. package/scripts/topo-help-overlay-r134-test.mjs +74 -0
  295. package/scripts/topo-help-overlay-r137-test.mjs +81 -0
  296. package/scripts/topo-help-overlay-r141-test.mjs +86 -0
  297. package/scripts/topo-help-overlay-r153-test.mjs +85 -0
  298. package/scripts/topo-hot-tail-crossfade-test.mjs +117 -0
  299. package/scripts/topo-html-overlay-padding-unify-test.mjs +120 -0
  300. package/scripts/topo-hub-a11y-test.mjs +112 -0
  301. package/scripts/topo-hub-center-crossfade-test.mjs +124 -0
  302. package/scripts/topo-hub-digit-scale-test.mjs +129 -0
  303. package/scripts/topo-hub-fadein-test.mjs +88 -0
  304. package/scripts/topo-hub-hover-lift-test.mjs +101 -0
  305. package/scripts/topo-hub-hover-ring-test.mjs +82 -0
  306. package/scripts/topo-hub-pip-theme-ease-test.mjs +116 -0
  307. package/scripts/topo-hub-spoke-ease-test.mjs +120 -0
  308. package/scripts/topo-hub-working-count-test.mjs +99 -0
  309. package/scripts/topo-inner-radar-ring-retired-test.mjs +89 -0
  310. package/scripts/topo-kicker-color-test.mjs +93 -0
  311. package/scripts/topo-kicker-tracking-test.mjs +101 -0
  312. package/scripts/topo-kicker-weight-test.mjs +98 -0
  313. package/scripts/topo-label-card-theme-ease-test.mjs +85 -0
  314. package/scripts/topo-layout-hover-text-preview-test.mjs +101 -0
  315. package/scripts/topo-layout-switch-crossfade-test.mjs +126 -0
  316. package/scripts/topo-layout-toggle-border-unify-test.mjs +104 -0
  317. package/scripts/topo-layout-toggle-test.mjs +131 -0
  318. package/scripts/topo-layout-trailer-mr-test.mjs +82 -0
  319. package/scripts/topo-legend-compress-test.mjs +107 -0
  320. package/scripts/topo-legend-count-empty-test.mjs +126 -0
  321. package/scripts/topo-legend-count-tabular-parity-test.mjs +90 -0
  322. package/scripts/topo-legend-count-tabular-test.mjs +87 -0
  323. package/scripts/topo-legend-count-test.mjs +88 -0
  324. package/scripts/topo-legend-count-tier-fill-test.mjs +121 -0
  325. package/scripts/topo-legend-count-weight-test.mjs +86 -0
  326. package/scripts/topo-legend-header-symmetric-inset-test.mjs +112 -0
  327. package/scripts/topo-legend-hitbox-swatch-center-test.mjs +93 -0
  328. package/scripts/topo-legend-offline-delimiter-test.mjs +84 -0
  329. package/scripts/topo-legend-offline-label-simplify-test.mjs +86 -0
  330. package/scripts/topo-legend-panel-count-weight-test.mjs +89 -0
  331. package/scripts/topo-legend-panel-header-test.mjs +83 -0
  332. package/scripts/topo-legend-pin-ring-fade-test.mjs +112 -0
  333. package/scripts/topo-legend-row-hover-lift-test.mjs +109 -0
  334. package/scripts/topo-legend-row-labels-simplify-test.mjs +80 -0
  335. package/scripts/topo-legend-row-pin-spacing-test.mjs +124 -0
  336. package/scripts/topo-legend-row-tint-test.mjs +95 -0
  337. package/scripts/topo-legend-row-title-test.mjs +102 -0
  338. package/scripts/topo-legend-swatch-grow-test.mjs +116 -0
  339. package/scripts/topo-legend-swatch-radius-test.mjs +78 -0
  340. package/scripts/topo-minimap-a11y-test.mjs +101 -0
  341. package/scripts/topo-minimap-dot-transition-test.mjs +113 -0
  342. package/scripts/topo-minimap-radius-test.mjs +88 -0
  343. package/scripts/topo-minimap-rect-stroke-test.mjs +94 -0
  344. package/scripts/topo-minimap-viewport-smooth-test.mjs +124 -0
  345. package/scripts/topo-monogram-font-test.mjs +112 -0
  346. package/scripts/topo-monogram-stroke-test.mjs +101 -0
  347. package/scripts/topo-more-flows-letterspacing-test.mjs +111 -0
  348. package/scripts/topo-node-a11y-test.mjs +107 -0
  349. package/scripts/topo-node-alias-chat-pin-test.mjs +95 -0
  350. package/scripts/topo-node-label-card-elevation-test.mjs +157 -0
  351. package/scripts/topo-node-label-card-stroke-test.mjs +135 -0
  352. package/scripts/topo-node-stroke-transition-test.mjs +103 -0
  353. package/scripts/topo-node-text-fill-transition-test.mjs +119 -0
  354. package/scripts/topo-node-title-peers-test.mjs +107 -0
  355. package/scripts/topo-node-title-test.mjs +101 -0
  356. package/scripts/topo-nodesize-active-hover-test.mjs +109 -0
  357. package/scripts/topo-nodesize-crossfade-test.mjs +141 -0
  358. package/scripts/topo-online-chip-nav-test.mjs +143 -0
  359. package/scripts/topo-orbit-particles-retired-test.mjs +91 -0
  360. package/scripts/topo-panel-count-unit-test.mjs +112 -0
  361. package/scripts/topo-panel-fadein-test.mjs +102 -0
  362. package/scripts/topo-panel-hot-tail-fade-test.mjs +132 -0
  363. package/scripts/topo-panel-hover-elevation-test.mjs +118 -0
  364. package/scripts/topo-panel-rx-test.mjs +90 -0
  365. package/scripts/topo-panel-theme-ease-test.mjs +85 -0
  366. package/scripts/topo-panel-title-fill-ease-test.mjs +91 -0
  367. package/scripts/topo-panel-title-tracking-test.mjs +78 -0
  368. package/scripts/topo-particle-stagger-test.mjs +82 -0
  369. package/scripts/topo-pin-intersection-color-ease-test.mjs +111 -0
  370. package/scripts/topo-pin-intersection-empty-test.mjs +129 -0
  371. package/scripts/topo-pin-intersection-tabular-test.mjs +96 -0
  372. package/scripts/topo-pin-intersection-test.mjs +121 -0
  373. package/scripts/topo-pin-intersection-warning-crossfade-test.mjs +107 -0
  374. package/scripts/topo-pin-mirror-transition-test.mjs +101 -0
  375. package/scripts/topo-prefix-opacity-test.mjs +107 -0
  376. package/scripts/topo-prepublish-guard-test.mjs +95 -0
  377. package/scripts/topo-pressure-seg-self-hover-test.mjs +126 -0
  378. package/scripts/topo-pressure-seg-tooltip-test.mjs +98 -0
  379. package/scripts/topo-pressure-seg-transition-test.mjs +107 -0
  380. package/scripts/topo-pulse-dot-crossfade-test.mjs +122 -0
  381. package/scripts/topo-pulse-dot-retired-test.mjs +86 -0
  382. package/scripts/topo-recent-panel-count-freshness-test.mjs +109 -0
  383. package/scripts/topo-recent-panel-count-test.mjs +72 -0
  384. package/scripts/topo-recent-panel-count-weight-test.mjs +91 -0
  385. package/scripts/topo-recent-panel-footer-breath-test.mjs +142 -0
  386. package/scripts/topo-recent-panel-hot-header-test.mjs +132 -0
  387. package/scripts/topo-recent-panel-hot-tabular-test.mjs +113 -0
  388. package/scripts/topo-recent-panel-more-crossfade-test.mjs +124 -0
  389. package/scripts/topo-recent-panel-more-cyan-hover-test.mjs +151 -0
  390. package/scripts/topo-recent-panel-more-nav-test.mjs +127 -0
  391. package/scripts/topo-recent-panel-more-test.mjs +106 -0
  392. package/scripts/topo-recent-panel-readability-bump-test.mjs +151 -0
  393. package/scripts/topo-recent-row-count-fill-test.mjs +129 -0
  394. package/scripts/topo-recent-row-count-weight-test.mjs +112 -0
  395. package/scripts/topo-recent-row-fadein-test.mjs +107 -0
  396. package/scripts/topo-recent-row-freshness-test.mjs +102 -0
  397. package/scripts/topo-recent-row-hot-test.mjs +110 -0
  398. package/scripts/topo-recent-row-hover-lift-test.mjs +128 -0
  399. package/scripts/topo-recent-row-pin-spacing-test.mjs +137 -0
  400. package/scripts/topo-recent-row-pin-test.mjs +126 -0
  401. package/scripts/topo-recent-row-tint-test.mjs +91 -0
  402. package/scripts/topo-recent-row-title-test.mjs +112 -0
  403. package/scripts/topo-recent-row-ts-alpha-test.mjs +100 -0
  404. package/scripts/topo-recent-row-ts-tabular-test.mjs +108 -0
  405. package/scripts/topo-recent-row-ts-test.mjs +95 -0
  406. package/scripts/topo-recent-row-typography-test.mjs +119 -0
  407. package/scripts/topo-recent-signal-empty-hint-test.mjs +73 -0
  408. package/scripts/topo-reset-spin-test.mjs +120 -0
  409. package/scripts/topo-runtime-badge-grow-test.mjs +114 -0
  410. package/scripts/topo-spokes-retired-test.mjs +93 -0
  411. package/scripts/topo-starfield-density-test.mjs +89 -0
  412. package/scripts/topo-status-chip-tooltip-test.mjs +95 -0
  413. package/scripts/topo-statusbar-chips-self-hover-test.mjs +177 -0
  414. package/scripts/topo-svg-focus-test.mjs +112 -0
  415. package/scripts/topo-sweep-busyness-test.mjs +94 -0
  416. package/scripts/topo-tabular-nums-sweep-test.mjs +93 -0
  417. package/scripts/topo-tier-guide-dashes-test.mjs +86 -0
  418. package/scripts/topo-tier-ring-fadein-test.mjs +107 -0
  419. package/scripts/topo-tier-ring-tint-test.mjs +110 -0
  420. package/scripts/topo-title-block-tight-leading-test.mjs +95 -0
  421. package/scripts/topo-title-tracking-test.mjs +98 -0
  422. package/scripts/topo-titleblock-gap-test.mjs +86 -0
  423. package/scripts/topo-titleblock-margin-test.mjs +83 -0
  424. package/scripts/topo-toggle-inactive-cyan-hover-test.mjs +110 -0
  425. package/scripts/topo-top-rail-theme-ease-test.mjs +89 -0
  426. package/scripts/topo-vendor-chip-self-hover-test.mjs +131 -0
  427. package/scripts/topo-vendor-chip-tabular-test.mjs +92 -0
  428. package/scripts/topo-vendor-chip-threshold-test.mjs +78 -0
  429. package/scripts/topo-vendor-chip-weight-test.mjs +87 -0
  430. package/scripts/topo-vendor-count-suffix-test.mjs +95 -0
  431. package/scripts/topo-vendor-letter-tooltip-test.mjs +92 -0
  432. package/scripts/topo-view-smooth-test.mjs +131 -0
  433. package/scripts/topo-watermark-tracking-test.mjs +99 -0
  434. package/scripts/topo-working-chip-pin-test.mjs +154 -0
  435. package/scripts/topo-working-halo-breath-retired-test.mjs +99 -0
  436. package/scripts/topo-wrapper-flow-arrow-theme-test.mjs +97 -0
  437. package/scripts/topo-wrapper-radius-test.mjs +73 -0
  438. package/scripts/topo-wrapper-shadow-theme-ease-test.mjs +89 -0
  439. package/.next/static/chunks/03w4rgx_vt8ec.js +0 -1
  440. package/.next/static/chunks/072so8rfx2tt-.css +0 -2
  441. package/.next/static/chunks/0o.k-.0kl4bz5.js +0 -2
  442. package/.next/static/chunks/121d8yvfl8l_..js +0 -7
  443. package/.next/static/chunks/148o1e4ijgwp1.js +0 -1
  444. package/scripts/topo-arrival-ping-test.mjs +0 -87
  445. package/scripts/topo-dispatch-pulse-test.mjs +0 -83
  446. /package/.next/static/{Dhky2WTh8mvJhw56taHVs → 424zX3i80AJ_wHF_otKuP}/_buildManifest.js +0 -0
  447. /package/.next/static/{Dhky2WTh8mvJhw56taHVs → 424zX3i80AJ_wHF_otKuP}/_clientMiddlewareManifest.js +0 -0
  448. /package/.next/static/{Dhky2WTh8mvJhw56taHVs → 424zX3i80AJ_wHF_otKuP}/_ssgManifest.js +0 -0
@@ -0,0 +1,81 @@
1
+ /* Round 137 verification: HelpOverlay catches up on R136 — the
2
+ * "N active links" chip in the chip row got a real onClick →
3
+ * /messages navigation (R136 fixed the cursor-pointer-lying bug:
4
+ * cursor:pointer existed since R77, but no click handler).
5
+ *
6
+ * Pairs with R134's footer-nav entry at a different surface:
7
+ * R133 footer-nav: canvas-side panel, only when flowLinks > 3
8
+ * R136 chip-nav: chip row, whenever flowLinks > 0 (broader)
9
+ *
10
+ * Stacks 13 docs generations now: R137 → R134 → R123 → R118 →
11
+ * R109 → R91 → R87 → R81 → R78 → R74 → R70 → R65 → R59. Any
12
+ * regression that drops an entry is caught by one of these.
13
+ */
14
+ import { chromium } from 'playwright';
15
+ import { readFileSync } from 'node:fs';
16
+
17
+ const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
18
+ const browser = await chromium.launch({ headless: true });
19
+
20
+ const ctx = await browser.newContext({ viewport: { width: 1280, height: 900 } });
21
+ await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
22
+ await ctx.addInitScript(() => {
23
+ try { localStorage.setItem('anet-theme', 'cyber'); sessionStorage.setItem('anet_v3_auth', '1'); } catch {}
24
+ });
25
+ await ctx.route('**/api/hub/messages*', (route) => route.fulfill({ json: { messages: [] } }));
26
+ await ctx.route('**/api/hub/tasks*', (route) => route.fulfill({ json: { tasks: [] } }));
27
+ const page = await ctx.newPage();
28
+ await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
29
+ await page.waitForTimeout(800);
30
+
31
+ await page.keyboard.press('?');
32
+ await page.waitForSelector('[role="dialog"][aria-label="Keyboard shortcuts"]', { timeout: 5000 });
33
+
34
+ const items = await page.evaluate(() => {
35
+ const dialog = document.querySelector('[role="dialog"][aria-label="Keyboard shortcuts"]');
36
+ const groups = [...(dialog?.querySelectorAll('div') || [])];
37
+ let active = null;
38
+ for (const g of groups) {
39
+ if (g.textContent && /^Topology canvas$/i.test(g.textContent.trim())) {
40
+ active = g.parentElement;
41
+ break;
42
+ }
43
+ }
44
+ return active ? [...active.querySelectorAll('li')].map(li => (li.textContent || '').trim()) : [];
45
+ });
46
+
47
+ await browser.close();
48
+
49
+ const has = (s) => items.some(t => t.includes(s));
50
+ const results = {
51
+ r137_clickChip: has('See all flows — click the "N active links" chip in the chip row (R136)'),
52
+ // R134 prior
53
+ r134_clickFooter: has('See all flows — click "+ N more flows" in the recent-signal panel (R133)'),
54
+ // R123 prior
55
+ r123_clickBadge: has('Pin a flow filter from the canvas — click an edge midpoint count badge (R121)'),
56
+ // R118 priors
57
+ r118_rowClickPin: has('Pin a flow filter — click a recent-signal row to lock the edge (R116)'),
58
+ r118_cmdkClearEdge: has('Clear edge pin only via palette → "Clear topology edge pin" (R117)'),
59
+ // R109 prior
60
+ r109_pinVendor: has('Pin vendor: Anthropic/OpenAI/书生 via palette → "Pin topology filter…" (R108)'),
61
+ // R91 prior
62
+ r91_clickVendor: has('Pin a vendor filter — click A/O/书/? in the chip row (R88)'),
63
+ // R87 prior
64
+ r87_segHover: has('Preview a status filter — hover a pressure-bar segment (R83)'),
65
+ // R81 prior
66
+ r81_vendorChip: has('Highlight one vendor — hover A/O/书/? in the chip row (R80)'),
67
+ // R78 prior
68
+ r78_pillBodyClick: has('Clear filter — click anywhere on the pill body (R73)'),
69
+ // R74 prior
70
+ r74_cmdkLayout: has('Toggle layout / Fit canvas via palette (R74)'),
71
+ // R70 prior
72
+ r70_cmdkPin: has('(R69)'),
73
+ // R65 prior
74
+ r65_groupClick: has('Pin a team focus (R63)'),
75
+ // R59 prior
76
+ r59_clickHub: has('Fit topology to canvas (R52)'),
77
+ };
78
+ const ok = Object.values(results).every(Boolean);
79
+ console.log(`${ok ? '✅' : '❌'} help overlay R137:`, JSON.stringify(results),
80
+ `\n items=`, items);
81
+ process.exit(ok ? 0 : 1);
@@ -0,0 +1,86 @@
1
+ /* Round 141 verification: HelpOverlay catches up on R139 + R140 —
2
+ * two new chip-row gestures landed since R137's last docs update.
3
+ *
4
+ * R139: click "N working" chip → pin pinnedStatus='working'
5
+ * (composes with R60 pressure-bar + R61 legend)
6
+ * R140: click "N online" chip → /nodes
7
+ * (pin 'idle' would misrepresent the chip semantically)
8
+ *
9
+ * Two entries added this round — usually one, but two gestures
10
+ * landed in consecutive rounds R139/R140.
11
+ *
12
+ * Stacks 14 docs generations now: R141 (×2) → R137 → R134 → R123
13
+ * → R118 → R109 → R91 → R87 → R81 → R78 → R74 → R70 → R65 → R59.
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: 1280, height: 900 } });
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
+ await ctx.route('**/api/hub/messages*', (route) => route.fulfill({ json: { messages: [] } }));
27
+ await ctx.route('**/api/hub/tasks*', (route) => route.fulfill({ json: { tasks: [] } }));
28
+ const page = await ctx.newPage();
29
+ await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
30
+ await page.waitForTimeout(800);
31
+
32
+ await page.keyboard.press('?');
33
+ await page.waitForSelector('[role="dialog"][aria-label="Keyboard shortcuts"]', { timeout: 5000 });
34
+
35
+ const items = await page.evaluate(() => {
36
+ const dialog = document.querySelector('[role="dialog"][aria-label="Keyboard shortcuts"]');
37
+ const groups = [...(dialog?.querySelectorAll('div') || [])];
38
+ let active = null;
39
+ for (const g of groups) {
40
+ if (g.textContent && /^Topology canvas$/i.test(g.textContent.trim())) {
41
+ active = g.parentElement;
42
+ break;
43
+ }
44
+ }
45
+ return active ? [...active.querySelectorAll('li')].map(li => (li.textContent || '').trim()) : [];
46
+ });
47
+
48
+ await browser.close();
49
+
50
+ const has = (s) => items.some(t => t.includes(s));
51
+ const results = {
52
+ // R141 NEW
53
+ r141_workingPin: has('Pin "working" status — click "N working" in the chip row (R139)'),
54
+ r141_onlineNav: has('Open the agent list — click "N online" in the chip row (R140)'),
55
+ // R137 prior
56
+ r137_clickChip: has('See all flows — click the "N active links" chip in the chip row (R136)'),
57
+ // R134 prior
58
+ r134_clickFooter: has('See all flows — click "+ N more flows" in the recent-signal panel (R133)'),
59
+ // R123 prior
60
+ r123_clickBadge: has('Pin a flow filter from the canvas — click an edge midpoint count badge (R121)'),
61
+ // R118 priors
62
+ r118_rowClickPin: has('Pin a flow filter — click a recent-signal row to lock the edge (R116)'),
63
+ r118_cmdkClearEdge: has('Clear edge pin only via palette → "Clear topology edge pin" (R117)'),
64
+ // R109 prior
65
+ r109_pinVendor: has('Pin vendor: Anthropic/OpenAI/书生 via palette → "Pin topology filter…" (R108)'),
66
+ // R91 prior
67
+ r91_clickVendor: has('Pin a vendor filter — click A/O/书/? in the chip row (R88)'),
68
+ // R87 prior
69
+ r87_segHover: has('Preview a status filter — hover a pressure-bar segment (R83)'),
70
+ // R81 prior
71
+ r81_vendorChip: has('Highlight one vendor — hover A/O/书/? in the chip row (R80)'),
72
+ // R78 prior
73
+ r78_pillBodyClick: has('Clear filter — click anywhere on the pill body (R73)'),
74
+ // R74 prior
75
+ r74_cmdkLayout: has('Toggle layout / Fit canvas via palette (R74)'),
76
+ // R70 prior
77
+ r70_cmdkPin: has('(R69)'),
78
+ // R65 prior
79
+ r65_groupClick: has('Pin a team focus (R63)'),
80
+ // R59 prior
81
+ r59_clickHub: has('Fit topology to canvas (R52)'),
82
+ };
83
+ const ok = Object.values(results).every(Boolean);
84
+ console.log(`${ok ? '✅' : '❌'} help overlay R141:`, JSON.stringify(results),
85
+ `\n items=`, items);
86
+ process.exit(ok ? 0 : 1);
@@ -0,0 +1,85 @@
1
+ /* Round 153 verification: HelpOverlay catches up on R151 — keyboard
2
+ * chat-open on a focused node. First true new gesture since R141's
3
+ * R139/R140 chip catch-up (R142 / R143 / R144 / R145 / R146 / R147 /
4
+ * R148 / R149 / R150 were visual / motion / hover-tooltip refinements
5
+ * with no new user gestures; R152 added an onKeyDown to the group
6
+ * label but that's just the keyboard parallel of the existing R63
7
+ * click-group entry, so it doesn't earn its own line).
8
+ *
9
+ * Stacks 15 docs generations now: R153 → R141 (×2) → R137 → R134 →
10
+ * R123 → R118 → R109 → R91 → R87 → R81 → R78 → R74 → R70 → R65 → R59.
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: 1280, height: 900 } });
19
+ await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
20
+ await ctx.addInitScript(() => {
21
+ try { localStorage.setItem('anet-theme', 'cyber'); sessionStorage.setItem('anet_v3_auth', '1'); } catch {}
22
+ });
23
+ await ctx.route('**/api/hub/messages*', (route) => route.fulfill({ json: { messages: [] } }));
24
+ await ctx.route('**/api/hub/tasks*', (route) => route.fulfill({ json: { tasks: [] } }));
25
+ const page = await ctx.newPage();
26
+ await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
27
+ await page.waitForTimeout(800);
28
+
29
+ await page.keyboard.press('?');
30
+ await page.waitForSelector('[role="dialog"][aria-label="Keyboard shortcuts"]', { timeout: 5000 });
31
+
32
+ const items = await page.evaluate(() => {
33
+ const dialog = document.querySelector('[role="dialog"][aria-label="Keyboard shortcuts"]');
34
+ const groups = [...(dialog?.querySelectorAll('div') || [])];
35
+ let active = null;
36
+ for (const g of groups) {
37
+ if (g.textContent && /^Topology canvas$/i.test(g.textContent.trim())) {
38
+ active = g.parentElement;
39
+ break;
40
+ }
41
+ }
42
+ return active ? [...active.querySelectorAll('li')].map(li => (li.textContent || '').trim()) : [];
43
+ });
44
+
45
+ await browser.close();
46
+
47
+ const has = (s) => items.some(t => t.includes(s));
48
+ const results = {
49
+ // R153 NEW — keyboard chat-open
50
+ r153_tabEnter: has('Open chat on a focused node (also Space) — keyboard parallel of click-to-chat (R151)'),
51
+ // R141 priors (2 entries)
52
+ r141_workingPin: has('Pin "working" status — click "N working" in the chip row (R139)'),
53
+ r141_onlineNav: has('Open the agent list — click "N online" in the chip row (R140)'),
54
+ // R137 prior
55
+ r137_clickChip: has('See all flows — click the "N active links" chip in the chip row (R136)'),
56
+ // R134 prior
57
+ r134_clickFooter: has('See all flows — click "+ N more flows" in the recent-signal panel (R133)'),
58
+ // R123 prior
59
+ r123_clickBadge: has('Pin a flow filter from the canvas — click an edge midpoint count badge (R121)'),
60
+ // R118 priors
61
+ r118_rowClickPin: has('Pin a flow filter — click a recent-signal row to lock the edge (R116)'),
62
+ r118_cmdkClearEdge: has('Clear edge pin only via palette → "Clear topology edge pin" (R117)'),
63
+ // R109 prior
64
+ r109_pinVendor: has('Pin vendor: Anthropic/OpenAI/书生 via palette → "Pin topology filter…" (R108)'),
65
+ // R91 prior
66
+ r91_clickVendor: has('Pin a vendor filter — click A/O/书/? in the chip row (R88)'),
67
+ // R87 prior
68
+ r87_segHover: has('Preview a status filter — hover a pressure-bar segment (R83)'),
69
+ // R81 prior
70
+ r81_vendorChip: has('Highlight one vendor — hover A/O/书/? in the chip row (R80)'),
71
+ // R78 prior
72
+ r78_pillBodyClick: has('Clear filter — click anywhere on the pill body (R73)'),
73
+ // R74 prior
74
+ r74_cmdkLayout: has('Toggle layout / Fit canvas via palette (R74)'),
75
+ // R70 prior
76
+ r70_cmdkPin: has('(R69)'),
77
+ // R65 prior
78
+ r65_groupClick: has('Pin a team focus (R63)'),
79
+ // R59 prior
80
+ r59_clickHub: has('Fit topology to canvas (R52)'),
81
+ };
82
+ const ok = Object.values(results).every(Boolean);
83
+ console.log(`${ok ? '✅' : '❌'} help overlay R153:`, JSON.stringify(results),
84
+ `\n items=`, items);
85
+ process.exit(ok ? 0 : 1);
@@ -0,0 +1,117 @@
1
+ /* Round 223 verification: recent-signal panel header hot-tail tspan
2
+ * ("· N hot") always-mounts; visibility crossfades via opacity gate
3
+ * instead of conditional mount/unmount on hotFlowCount > 0. R190's
4
+ * anet-fade-in entrance is preserved; R223 makes the EXIT also ease.
5
+ *
6
+ * Test scenarios:
7
+ * A. 0 hot flows (all counts < 10):
8
+ * · tspan IN DOM (always-mount proven)
9
+ * · data-recent-panel-hot-visible='false'
10
+ * · opacity attribute = 0
11
+ * · text content empty (no "· 0 hot" artifact)
12
+ * B. 1 hot flow (count=12):
13
+ * · visible='true', opacity=1
14
+ * · text content matches "· 1 hot"
15
+ * · anet-fade-in className retained for R190 compat
16
+ * Both: inline style.transition includes 'opacity 300ms'.
17
+ */
18
+ import { chromium } from 'playwright';
19
+ import { readFileSync } from 'node:fs';
20
+
21
+ const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
22
+ const browser = await chromium.launch({ headless: true });
23
+
24
+ async function setup(messages) {
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
+ const page = await ctx.newPage();
47
+ await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
48
+ await page.waitForFunction(() => document.querySelectorAll('g[data-node]').length === 4, { timeout: 30000 });
49
+ await page.waitForSelector('[data-recent-panel-hot-count]', { timeout: 10000, state: 'attached' });
50
+ await page.waitForTimeout(400);
51
+ return page;
52
+ }
53
+
54
+ const probe = async (page) => page.evaluate(() => {
55
+ const tail = document.querySelector('[data-recent-panel-hot-count]');
56
+ if (!tail) return null;
57
+ return {
58
+ present: true,
59
+ visible: tail.getAttribute('data-recent-panel-hot-visible'),
60
+ count: tail.getAttribute('data-recent-panel-hot-count'),
61
+ opacity: parseFloat(tail.getAttribute('opacity') || ''),
62
+ text: tail.textContent,
63
+ className: tail.getAttribute('class') || '',
64
+ transition: tail.style.transition,
65
+ };
66
+ });
67
+
68
+ const now = Date.now();
69
+
70
+ // Scenario A: 0 hot flows — 1 cold flow with 3 messages (still cold, < 10)
71
+ const coldMsgs = [];
72
+ for (let i = 0; i < 3; i++) {
73
+ coldMsgs.push({
74
+ id: `cold${i}`, from_alias: 'alpha', to_alias: 'beta', content: 'hi',
75
+ network_id: 'default', created_at: new Date(now - (1000 + i * 50)).toISOString(),
76
+ });
77
+ }
78
+ const pageA = await setup(coldMsgs);
79
+ const probeA = await probe(pageA);
80
+ await pageA.close();
81
+
82
+ // Scenario B: 1 hot flow — 12 messages from alpha to beta
83
+ const hotMsgs = [];
84
+ for (let i = 0; i < 12; i++) {
85
+ hotMsgs.push({
86
+ id: `hot${i}`, from_alias: 'alpha', to_alias: 'beta', content: 'hi',
87
+ network_id: 'default', created_at: new Date(now - (1000 + i * 50)).toISOString(),
88
+ });
89
+ }
90
+ const pageB = await setup(hotMsgs);
91
+ const probeB = await probe(pageB);
92
+ await pageB.close();
93
+ await browser.close();
94
+
95
+ const results = {
96
+ // A: 0 hot flows — tspan in DOM but hidden
97
+ A_present_in_dom: probeA?.present === true,
98
+ A_visible_false: probeA?.visible === 'false',
99
+ A_opacity_0: probeA?.opacity === 0,
100
+ A_text_empty: probeA?.text === '' || probeA?.text === null,
101
+ A_count_attr_0: probeA?.count === '0',
102
+ A_has_transition: /opacity\s+(?:300ms|0\.3s)/.test(probeA?.transition || ''),
103
+
104
+ // B: 1 hot flow — visible
105
+ B_present_in_dom: probeB?.present === true,
106
+ B_visible_true: probeB?.visible === 'true',
107
+ B_opacity_1: probeB?.opacity === 1,
108
+ B_text_one_hot: /·\s*1\s*hot/.test(probeB?.text || ''),
109
+ B_count_attr_1: probeB?.count === '1',
110
+ B_fade_class_present: (probeB?.className || '').split(/\s+/).includes('anet-fade-in'),
111
+ B_has_transition: /opacity\s+(?:300ms|0\.3s)/.test(probeB?.transition || ''),
112
+ };
113
+ const ok = Object.values(results).every(Boolean);
114
+ console.log(`${ok ? '✅' : '❌'} hot-tail crossfade:`, JSON.stringify(results),
115
+ `\n probeA (0 hot):`, probeA,
116
+ `\n probeB (1 hot):`, probeB);
117
+ process.exit(ok ? 0 : 1);
@@ -0,0 +1,120 @@
1
+ /* Round 261 verification: HTML overlay padding aligned with SVG corner
2
+ * panel padding — chrome strip + minimap both at 16 CSS px from canvas
3
+ * edges, matching the SVG corner panels at (16, 16) panel-translate.
4
+ *
5
+ * Pre-R261:
6
+ * SVG panels: 16 SVG units from edges (≈ 15 CSS px @ ~0.94× scale)
7
+ * chrome: 12 CSS px (bottom-3 right-3) — ~3px optical asymmetry
8
+ * minimap: 12 CSS px (right-3) — same asymmetry
9
+ *
10
+ * Post-R261:
11
+ * chrome: bottom-4 right-4 → 16 CSS px from container edges
12
+ * minimap: right-4 → 16 CSS px from container right edge
13
+ *
14
+ * 16 CSS px ≈ 17 SVG units, slightly tighter than the SVG 16-unit
15
+ * inset due to render-scale rounding, but visually matches the SVG
16
+ * panel padding so HTML overlays and SVG panels speak one inset
17
+ * vocabulary.
18
+ *
19
+ * Test scope:
20
+ * 1. Chrome strip's right edge sits at ~16 CSS px from container
21
+ * right edge (allow ±2 px sub-pixel slop).
22
+ * 2. Chrome strip's bottom edge sits at ~16 CSS px from container
23
+ * bottom edge (±2 slop).
24
+ * 3. Minimap (mounted after zoom-in × 3): right edge at ~16 CSS px.
25
+ * 4. R255 chrome-strip semantic gap intact: fleet→view gap still ≥ 11.
26
+ */
27
+ import { chromium } from 'playwright';
28
+ import { readFileSync } from 'node:fs';
29
+
30
+ const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
31
+ const browser = await chromium.launch({ headless: true });
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
+ const fresh = new Date(Date.now() - 60 * 1000).toISOString();
38
+ await ctx.route('**/api/hub/status*', async (route) => {
39
+ const r = await route.fetch();
40
+ const b = await r.json();
41
+ const nid = (b.sessions || [])[0]?.network_id || 'default';
42
+ const mk = (alias) => ({
43
+ alias, status: 'working', model: 'claude-opus-4', runtime: 'claude-code-cli',
44
+ network_id: nid, project_dir: null,
45
+ created_at: fresh, updated_at: fresh, last_seen_at: fresh,
46
+ });
47
+ await route.fulfill({ response: r, json: { ...b, sessions: [
48
+ mk('alpha'), mk('beta'), mk('gamma'), mk('delta'),
49
+ ] } });
50
+ });
51
+ await ctx.route('**/api/hub/messages*', (r) => r.fulfill({ json: { messages: [] } }));
52
+ await ctx.route('**/api/hub/tasks*', (r) => r.fulfill({ json: { tasks: [] } }));
53
+
54
+ const page = await ctx.newPage();
55
+ await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
56
+ await page.waitForFunction(() => document.querySelectorAll('g[data-node]').length === 4, { timeout: 30000 });
57
+ await page.waitForSelector('[data-topo-chrome]', { timeout: 10000 });
58
+ await page.waitForSelector('[data-topo-wrapper]', { timeout: 10000 });
59
+ await page.waitForTimeout(300);
60
+
61
+ const beforeMinimap = await page.evaluate(() => {
62
+ const wrapper = document.querySelector('[data-topo-wrapper]');
63
+ const chrome = document.querySelector('[data-topo-chrome]');
64
+ const fleet = document.querySelector('[data-topo-chrome-fleet-group-trailer]');
65
+ const view = document.querySelector('[data-topo-chrome-view-group-leader]');
66
+ const wrR = wrapper?.getBoundingClientRect() ?? null;
67
+ const chR = chrome?.getBoundingClientRect() ?? null;
68
+ return {
69
+ wrapperRight: wrR ? wrR.right : null,
70
+ wrapperBottom: wrR ? wrR.bottom : null,
71
+ chromeRight: chR ? chR.right : null,
72
+ chromeBottom: chR ? chR.bottom : null,
73
+ fleetRight: fleet ? fleet.getBoundingClientRect().right : null,
74
+ viewLeft: view ? view.getBoundingClientRect().left : null,
75
+ };
76
+ });
77
+
78
+ // Zoom in to force minimap mount
79
+ for (let i = 0; i < 3; i++) {
80
+ await page.locator('[data-topo-chrome-zoom-in]').click();
81
+ await page.waitForTimeout(120);
82
+ }
83
+ await page.waitForSelector('[data-topo-minimap]', { timeout: 5000 });
84
+ await page.waitForTimeout(300);
85
+
86
+ const minimapProbe = await page.evaluate(() => {
87
+ const wrapper = document.querySelector('[data-topo-wrapper]');
88
+ const mm = document.querySelector('[data-topo-minimap]');
89
+ const wrR = wrapper?.getBoundingClientRect() ?? null;
90
+ const mmR = mm?.getBoundingClientRect() ?? null;
91
+ return {
92
+ wrapperRight: wrR ? wrR.right : null,
93
+ minimapRight: mmR ? mmR.right : null,
94
+ };
95
+ });
96
+ await browser.close();
97
+
98
+ const chromeRightOffset = (beforeMinimap.wrapperRight != null && beforeMinimap.chromeRight != null)
99
+ ? (beforeMinimap.wrapperRight - beforeMinimap.chromeRight) : null;
100
+ const chromeBottomOffset = (beforeMinimap.wrapperBottom != null && beforeMinimap.chromeBottom != null)
101
+ ? (beforeMinimap.wrapperBottom - beforeMinimap.chromeBottom) : null;
102
+ const minimapRightOffset = (minimapProbe.wrapperRight != null && minimapProbe.minimapRight != null)
103
+ ? (minimapProbe.wrapperRight - minimapProbe.minimapRight) : null;
104
+ const fleetToViewGap = (beforeMinimap.fleetRight != null && beforeMinimap.viewLeft != null)
105
+ ? (beforeMinimap.viewLeft - beforeMinimap.fleetRight) : null;
106
+
107
+ const inWindow = (v, target, slop) => v != null && Math.abs(v - target) <= slop;
108
+
109
+ const results = {
110
+ chrome_right_at_16: inWindow(chromeRightOffset, 16, 2),
111
+ chrome_bottom_at_16: inWindow(chromeBottomOffset, 16, 2),
112
+ minimap_right_at_16: inWindow(minimapRightOffset, 16, 2),
113
+ r255_fleet_view_gap_intact: fleetToViewGap != null && fleetToViewGap >= 11,
114
+ };
115
+ const ok = Object.values(results).every(Boolean);
116
+ console.log(`${ok ? '✅' : '❌'} HTML overlay padding unify:`, JSON.stringify(results),
117
+ '\n chrome right offset:', chromeRightOffset, '/ bottom:', chromeBottomOffset,
118
+ '\n minimap right offset:', minimapRightOffset,
119
+ '\n R255 fleet→view gap:', fleetToViewGap);
120
+ process.exit(ok ? 0 : 1);
@@ -0,0 +1,112 @@
1
+ /* Round 159 verification: hub <g> gains keyboard a11y.
2
+ *
3
+ * R151-R157 a11y sweep covered nodes, group labels, edge badges,
4
+ * recent rows, legend rows, chrome buttons, minimap, chip-row.
5
+ * R158 named the canvas root. The hub <g> — the most visually
6
+ * prominent interactive element on the canvas (R39 enlarged,
7
+ * R43 tooltip, R52 click-to-fitView, R115 hover ring) — was the
8
+ * only major interactive R151-R157 skipped.
9
+ *
10
+ * R159 closes that gap with the same standard pattern:
11
+ * role="button"
12
+ * tabIndex={0}
13
+ * aria-label="Network hub · N online · K working · M links — Enter to fit view"
14
+ * className="anet-topo-svg-focus" (R156 cyan focus ring)
15
+ * onKeyDown(Enter/Space) → fitView() + ripple
16
+ *
17
+ * Test:
18
+ * 1. Mock 3 working + 2 idle sessions + zoom in (so fit-to-view
19
+ * has a visible effect — zoom level moves away from 100%)
20
+ * 2. Assert role / tabIndex / aria-label / className on hub
21
+ * 3. Focus hub + Enter → zoom resets to 100%
22
+ * 4. Confirm aria-label mentions counts + Enter
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: 1400, 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 {
34
+ localStorage.setItem('anet-theme', 'cyber');
35
+ sessionStorage.setItem('anet_v3_auth', '1');
36
+ // R159 hub is gated to layout === 'ring' (line 2946 — grid uses
37
+ // group boxes, no central hub). Force ring.
38
+ localStorage.setItem('anet-topo-layout', 'ring');
39
+ } catch {}
40
+ });
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 mk = (alias, status) => ({
48
+ alias, status, model: 'claude-opus-4', runtime: 'cli-claude-code',
49
+ network_id: nid, project_dir: null,
50
+ created_at: fresh, updated_at: fresh, last_seen_at: fresh,
51
+ });
52
+ await route.fulfill({ response: r, json: { ...b, sessions: [
53
+ mk('agents-a1', 'working'), mk('agents-a2', 'working'), mk('agents-a3', 'working'),
54
+ mk('infra-b1', 'idle'), mk('infra-b2', 'idle'),
55
+ ] } });
56
+ });
57
+ await ctx.route('**/api/hub/messages*', (route) => route.fulfill({ json: { messages: [] } }));
58
+ await ctx.route('**/api/hub/tasks*', (route) => route.fulfill({ json: { tasks: [] } }));
59
+
60
+ const page = await ctx.newPage();
61
+ await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
62
+ await page.waitForFunction(() => document.querySelectorAll('g[data-node]').length === 5, { timeout: 30000 });
63
+ await page.waitForSelector('[data-topo-hub]', { timeout: 10000 });
64
+ await page.waitForTimeout(400);
65
+
66
+ // Probe ARIA before any interaction
67
+ const probe = await page.evaluate(() => {
68
+ const el = document.querySelector('[data-topo-hub]');
69
+ if (!el) return null;
70
+ return {
71
+ tagName: el.tagName.toLowerCase(),
72
+ role: el.getAttribute('role'),
73
+ tabIndex: el.getAttribute('tabindex'),
74
+ ariaLabel: el.getAttribute('aria-label'),
75
+ className: el.getAttribute('class') || '',
76
+ };
77
+ });
78
+
79
+ // Zoom in twice so fitView has a visible effect
80
+ await page.keyboard.press('+');
81
+ await page.keyboard.press('+');
82
+ await page.waitForTimeout(250);
83
+ const zoomBefore = await page.evaluate(() =>
84
+ document.querySelector('[data-topo-chrome-zoom-level]')?.textContent?.trim());
85
+
86
+ // Focus hub + Enter → fitView resets zoom to 100%
87
+ await page.locator('[data-topo-hub]').focus();
88
+ await page.keyboard.press('Enter');
89
+ await page.waitForTimeout(350);
90
+ const zoomAfter = await page.evaluate(() =>
91
+ document.querySelector('[data-topo-chrome-zoom-level]')?.textContent?.trim());
92
+
93
+ await browser.close();
94
+
95
+ const label = probe?.ariaLabel || '';
96
+ const results = {
97
+ hub_found: probe !== null,
98
+ is_g: probe?.tagName === 'g',
99
+ role_button: probe?.role === 'button',
100
+ tabIndex_0: probe?.tabIndex === '0',
101
+ label_mentions_online: /5 online/.test(label),
102
+ label_mentions_working: /3 working/.test(label),
103
+ label_mentions_enter: /Enter to fit view/.test(label),
104
+ has_focus_class: (probe?.className || '').includes('anet-topo-svg-focus'),
105
+ zoomedBefore: zoomBefore !== '100%',
106
+ enter_resetsZoom: zoomAfter === '100%',
107
+ };
108
+ const ok = Object.values(results).every(Boolean);
109
+ console.log(`${ok ? '✅' : '❌'} hub a11y:`, JSON.stringify(results),
110
+ `\n probe=`, probe,
111
+ `\n zoomBefore=${zoomBefore} zoomAfter=${zoomAfter}`);
112
+ process.exit(ok ? 0 : 1);