@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,78 @@
1
+ /* Round 281 verification: vendor letters chip threshold tightened
2
+ * from `vendorDist.length > 1` to `vendorDist.length > 2`.
3
+ *
4
+ * Pre-R281: chip rendered whenever ≥2 vendor types existed in the
5
+ * fleet. For a typical Twitter demo (claude + gpt = 2 types), the
6
+ * chip rendered "A:N O:M" adding ~50-80px to the chip-row width.
7
+ *
8
+ * Post-R281: chip only renders when ≥3 vendor types. The typical
9
+ * 1-2 vendor case (most demos) hides the chip; only fleets with
10
+ * actual diverse multi-vendor composition (3+ vendor types) show it.
11
+ *
12
+ * Scenario A: 2 vendor types (claude + gpt) — chip should be ABSENT
13
+ * Scenario B: 3 vendor types (claude + gpt + InternLM) — chip PRESENT
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
+ async function probeForScenario(sessions) {
22
+ const ctx = await browser.newContext({ viewport: { width: 1500, height: 1500 } });
23
+ await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
24
+ await ctx.addInitScript(() => {
25
+ try { localStorage.setItem('anet-theme', 'cyber'); sessionStorage.setItem('anet_v3_auth', '1'); } catch {}
26
+ });
27
+ const fresh = new Date(Date.now() - 60 * 1000).toISOString();
28
+ await ctx.route('**/api/hub/status*', async (route) => {
29
+ const r = await route.fetch();
30
+ const b = await r.json();
31
+ const nid = (b.sessions || [])[0]?.network_id || 'default';
32
+ const mk = (alias, model) => ({
33
+ alias, status: 'working', model, runtime: 'claude-code-cli',
34
+ network_id: nid, project_dir: null,
35
+ created_at: fresh, updated_at: fresh, last_seen_at: fresh,
36
+ });
37
+ await route.fulfill({ response: r, json: { ...b, sessions: sessions.map(s => mk(s.alias, s.model)) } });
38
+ });
39
+ await ctx.route('**/api/hub/messages*', (r) => r.fulfill({ json: { messages: [] } }));
40
+ await ctx.route('**/api/hub/tasks*', (r) => r.fulfill({ json: { tasks: [] } }));
41
+
42
+ const page = await ctx.newPage();
43
+ await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
44
+ await page.waitForFunction((n) => document.querySelectorAll('g[data-node]').length === n, sessions.length, { timeout: 30000 });
45
+ await page.waitForTimeout(400);
46
+ const result = await page.evaluate(() => {
47
+ const chips = document.querySelectorAll('[data-vendor-letter]');
48
+ return { chipCount: chips.length };
49
+ });
50
+ await ctx.close();
51
+ return result;
52
+ }
53
+
54
+ const twoVendors = await probeForScenario([
55
+ { alias: 'alpha', model: 'claude-opus-4' },
56
+ { alias: 'beta', model: 'claude-sonnet-4' },
57
+ { alias: 'gamma', model: 'gpt-4o' },
58
+ { alias: 'delta', model: 'gpt-4' },
59
+ ]);
60
+
61
+ const threeVendors = await probeForScenario([
62
+ { alias: 'alpha', model: 'claude-opus-4' },
63
+ { alias: 'beta', model: 'gpt-4o' },
64
+ { alias: 'gamma', model: 'internlm/internlm2' },
65
+ { alias: 'delta', model: 'some-unknown' },
66
+ ]);
67
+
68
+ await browser.close();
69
+
70
+ const results = {
71
+ two_vendor_chip_absent: twoVendors.chipCount === 0,
72
+ three_vendor_chip_present: threeVendors.chipCount >= 3,
73
+ };
74
+ const ok = Object.values(results).every(Boolean);
75
+ console.log(`${ok ? '✅' : '❌'} vendor chip threshold:`, JSON.stringify(results),
76
+ '\n 2-vendor scenario chip count (expect 0):', twoVendors.chipCount,
77
+ '\n 3-vendor scenario chip count (expect >=3):', threeVendors.chipCount);
78
+ process.exit(ok ? 0 : 1);
@@ -0,0 +1,87 @@
1
+ /* Round 314 verification: vendor letter chips (e.g. 'A:N', 'O:N')
2
+ * pick up font-medium (500), completing the R312-R313 'HTML-context
3
+ * data chip = font-medium' family. R313 covered the 3 main chips
4
+ * (working/online/active-links); R314 closes the chip-row weight
5
+ * sweep at the vendor letters.
6
+ *
7
+ * Test fixture: 3 vendor types (claude + gpt + intern) to surface
8
+ * the chip row per R281 threshold (vendorDist.length > 2).
9
+ *
10
+ * Contract:
11
+ * - All [data-vendor-letter] chips have className containing
12
+ * 'font-medium' + 'tabular-nums'.
13
+ * - Computed font-weight === 500 for each.
14
+ * - R313 working/online/active chips still font-medium.
15
+ * - R312 chrome zoom still font-medium.
16
+ * - R311 recent count fw=600 + R309 row counts fw=600 + R294
17
+ * pulse absent all preserved.
18
+ */
19
+ import { chromium } from 'playwright';
20
+ import { readFileSync } from 'node:fs';
21
+
22
+ const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
23
+ const browser = await chromium.launch({ headless: true });
24
+ const ctx = await browser.newContext({ viewport: { width: 1500, height: 1500 } });
25
+ await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
26
+ await ctx.addInitScript(() => {
27
+ try { localStorage.setItem('anet-theme', 'cyber'); sessionStorage.setItem('anet_v3_auth', '1'); } catch {}
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 mk = (alias, model) => ({
35
+ alias, status: 'working', model, runtime: 'claude-code-cli',
36
+ network_id: nid, project_dir: null,
37
+ created_at: fresh, updated_at: fresh, last_seen_at: fresh,
38
+ });
39
+ // 3 vendor types → R281 vendorDist.length > 2 threshold → chips render.
40
+ await route.fulfill({ response: r, json: { ...b, sessions: [
41
+ mk('alpha', 'claude-opus-4'),
42
+ mk('beta', 'gpt-4o'),
43
+ mk('gamma', 'internlm/internlm2'),
44
+ ] } });
45
+ });
46
+ await ctx.route('**/api/hub/messages*', (r) => r.fulfill({ json: { messages: [] } }));
47
+ await ctx.route('**/api/hub/tasks*', (r) => r.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.waitForSelector('[data-vendor-letter]', { timeout: 15000 });
52
+ await page.waitForTimeout(300);
53
+
54
+ const probe = await page.evaluate(() => {
55
+ const sel = (s) => document.querySelector(s);
56
+ const chips = [...document.querySelectorAll('[data-vendor-letter]')];
57
+ const samples = chips.map(c => ({
58
+ initial: c.getAttribute('data-vendor-letter'),
59
+ className: c.className,
60
+ fontWeight: getComputedStyle(c).fontWeight,
61
+ }));
62
+ return {
63
+ samples,
64
+ workingChipCls: sel('[data-working-chip]')?.className ?? '',
65
+ chromeZoomCls: sel('[data-topo-chrome-zoom-level]')?.className ?? '',
66
+ recentCountFw: sel('[data-recent-panel-count]')?.getAttribute('font-weight') ?? null,
67
+ rowWorkingFw: sel('[data-legend-count="working"]')?.getAttribute('font-weight') ?? null,
68
+ pulseCount: document.querySelectorAll('[data-pulse-wrapper]').length,
69
+ };
70
+ });
71
+ await browser.close();
72
+
73
+ const results = {
74
+ vendor_chips_present: probe.samples.length >= 3,
75
+ all_have_font_medium_cls: probe.samples.every(s => s.className.includes('font-medium')),
76
+ all_have_tabular_nums_cls: probe.samples.every(s => s.className.includes('tabular-nums')),
77
+ all_computed_fw_500: probe.samples.every(s => String(s.fontWeight) === '500'),
78
+ r313_working_chip_fw_500: probe.workingChipCls.includes('font-medium'),
79
+ r312_chrome_zoom_fw_500: probe.chromeZoomCls.includes('font-medium'),
80
+ r311_recent_count_fw_600: probe.recentCountFw === '600',
81
+ r309_row_working_fw_600: probe.rowWorkingFw === '600',
82
+ r294_pulse_absent: probe.pulseCount === 0,
83
+ };
84
+ const ok = Object.values(results).every(Boolean);
85
+ console.log(`${ok ? '✅' : '❌'} vendor chip weight:`, JSON.stringify(results),
86
+ '\n vendor chips:', probe.samples.map(s => `${s.initial}=fw${s.fontWeight}`).join(', '));
87
+ process.exit(ok ? 0 : 1);
@@ -0,0 +1,95 @@
1
+ /* Round 333 verification: vendor letter chip count suffix `:{N}`
2
+ * picks up two polishes:
3
+ * 1. text-gray-500 → text-gray-400 (R317 subordinate-text-lift family)
4
+ * 2. tabular-nums (digit width-lock when count crosses 9→10 etc)
5
+ *
6
+ * Both surface a new test attr `data-vendor-letter-count` on the
7
+ * suffix span.
8
+ *
9
+ * Contract:
10
+ * - [data-vendor-letter-count-suffix] present (at least one vendor row).
11
+ * - Its className contains both 'text-gray-400' and 'tabular-nums'.
12
+ * - Computed fontVariantNumeric === 'tabular-nums'.
13
+ * - R332 minimap rounded-lg + R330 wrapper rounded-xl regressions.
14
+ * - R317 / R318 / R294 chrome + pulse regressions intact.
15
+ */
16
+ import { chromium } from 'playwright';
17
+ import { readFileSync } from 'node:fs';
18
+
19
+ const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
20
+ const browser = await chromium.launch({ headless: true });
21
+ const ctx = await browser.newContext({ viewport: { width: 1500, 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, model) => ({
32
+ alias, status: 'working', model, runtime: 'claude-code-cli',
33
+ network_id: nid, project_dir: null,
34
+ created_at: fresh, updated_at: fresh, last_seen_at: fresh,
35
+ });
36
+ // R281 vendorDist threshold is `vendorDist.length > 2` — need 3+
37
+ // distinct vendor types to surface the vendor letter chip row.
38
+ // Anthropic + OpenAI + internlm = 3 distinct vendors (matches the
39
+ // pre-existing topo-vendor-chip-weight-test fixture pattern).
40
+ await route.fulfill({ response: r, json: { ...b, sessions: [
41
+ mk('alpha', 'claude-opus-4'),
42
+ mk('beta', 'gpt-4o'),
43
+ mk('gamma', 'internlm/internlm2'),
44
+ ] } });
45
+ });
46
+ await ctx.route('**/api/hub/messages*', (r) => r.fulfill({ json: { messages: [] } }));
47
+ await ctx.route('**/api/hub/tasks*', (r) => r.fulfill({ json: { tasks: [] } }));
48
+
49
+ const page = await ctx.newPage();
50
+ await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
51
+ // Wait for at least one data-vendor-letter (the parent chip) — the
52
+ // child count suffix lands as a child whether or not the chip is in
53
+ // the visible viewport. Use `state: attached` so the test passes when
54
+ // the vendor chip exists in the DOM (chip-row rendered) even if any
55
+ // individual responsive class hides one specific vendor.
56
+ await page.waitForSelector('[data-vendor-letter]', { timeout: 15000, state: 'attached' });
57
+ await page.waitForSelector('[data-vendor-letter-count-suffix]', { timeout: 5000, state: 'attached' });
58
+ await page.waitForTimeout(300);
59
+
60
+ const probe = await page.evaluate(() => {
61
+ const suffixes = Array.from(document.querySelectorAll('[data-vendor-letter-count-suffix]'));
62
+ return {
63
+ suffixCount: suffixes.length,
64
+ suffixClasses: suffixes.map(s => s.className),
65
+ suffixTabulars: suffixes.map(s => getComputedStyle(s).fontVariantNumeric),
66
+ suffixTexts: suffixes.map(s => s.textContent),
67
+ layoutInactiveCls: document.querySelector('[data-topo-chrome-layout="grid"]')?.className ?? '',
68
+ layoutActiveCls: document.querySelector('[data-topo-chrome-layout="ring"]')?.className ?? '',
69
+ pulseCount: document.querySelectorAll('[data-pulse-wrapper]').length,
70
+ wrapperClass: document.querySelector('[data-topo-wrapper]')?.className ?? '',
71
+ };
72
+ });
73
+ await browser.close();
74
+
75
+ const hasTab = (s) => /tabular-nums/.test(s || '');
76
+ const hasGray400 = (cls) => /(^|\s)text-gray-400(\s|$)/.test(cls || '');
77
+ const hasTabClass = (cls) => /(^|\s)tabular-nums(\s|$)/.test(cls || '');
78
+
79
+ const results = {
80
+ suffix_at_least_one: probe.suffixCount >= 1,
81
+ all_have_gray_400: probe.suffixClasses.every(hasGray400),
82
+ all_have_tabular_class: probe.suffixClasses.every(hasTabClass),
83
+ all_have_computed_tabular: probe.suffixTabulars.every(hasTab),
84
+ // R330 wrapper regression.
85
+ r330_wrapper_rounded_xl: probe.wrapperClass.includes('rounded-xl'),
86
+ // R317 / R318 chrome regression.
87
+ r317_inactive_gray_400: probe.layoutInactiveCls.includes('text-gray-400'),
88
+ r318_active_font_medium: probe.layoutActiveCls.includes('font-medium'),
89
+ r294_pulse_absent: probe.pulseCount === 0,
90
+ };
91
+ const ok = Object.values(results).every(Boolean);
92
+ console.log(`${ok ? '✅' : '❌'} vendor count suffix gray-400+tabular:`, JSON.stringify(results),
93
+ '\n suffix texts:', probe.suffixTexts,
94
+ '\n suffix tabular:', probe.suffixTabulars);
95
+ process.exit(ok ? 0 : 1);
@@ -0,0 +1,92 @@
1
+ /* Round 101 verification: vendor-letter chip <span>s carry an alias-
2
+ * list tooltip. Completes the R97/R98/R99 info-density sweep — every
3
+ * surface that shows "X:N" should hover-explain which N.
4
+ *
5
+ * Fleet: 2 Claude (alpha, gamma), 2 GPT (beta, delta). Vendor chip
6
+ * shows "A:2 O:2". A letter's tooltip should list alpha, gamma;
7
+ * O letter's should list beta, delta. Pin state flips the trailing
8
+ * action hint ("click to pin" → "click again or Esc to clear").
9
+ */
10
+ import { chromium } from 'playwright';
11
+ import { readFileSync } from 'node:fs';
12
+
13
+ const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
14
+ const browser = await chromium.launch({ headless: true });
15
+
16
+ const ctx = await browser.newContext({ viewport: { width: 1400, height: 1500 } });
17
+ await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
18
+ await ctx.addInitScript(() => {
19
+ try {
20
+ localStorage.setItem('anet-theme', 'cyber');
21
+ sessionStorage.setItem('anet_v3_auth', '1');
22
+ sessionStorage.removeItem('anet-topo-pinned-vendor');
23
+ } catch {}
24
+ });
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, model) => ({
32
+ alias, status: 'idle', 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', 'claude-opus-4'),
38
+ mk('beta', 'gpt-5'),
39
+ mk('gamma', 'claude-opus-4'),
40
+ mk('delta', 'gpt-5'),
41
+ ] } });
42
+ });
43
+ await ctx.route('**/api/hub/messages*', (route) => route.fulfill({ json: { messages: [] } }));
44
+ await ctx.route('**/api/hub/tasks*', (route) => route.fulfill({ json: { tasks: [] } }));
45
+ const page = await ctx.newPage();
46
+ await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
47
+ await page.waitForFunction(() => document.querySelectorAll('g[data-node]').length === 4, { timeout: 30000 });
48
+ await page.waitForTimeout(400);
49
+
50
+ const read = (initial) => page.evaluate((i) => {
51
+ const el = document.querySelector(`[data-vendor-letter="${i}"]`);
52
+ if (!el) return null;
53
+ return {
54
+ title: el.getAttribute('title') || '',
55
+ aliases: el.getAttribute('data-vendor-aliases') || '',
56
+ pinned: el.getAttribute('data-vendor-pinned') || '',
57
+ };
58
+ }, initial);
59
+
60
+ const aSnap = await read('A');
61
+ const oSnap = await read('O');
62
+
63
+ // Pin A — title should flip.
64
+ await page.locator('[data-vendor-letter="A"]').click();
65
+ await page.mouse.move(10, 10);
66
+ await page.waitForTimeout(250);
67
+ const aPinned = await read('A');
68
+
69
+ await browser.close();
70
+
71
+ const sameSet = (csv, expected) => {
72
+ const got = new Set(csv.split(',').filter(Boolean));
73
+ const exp = new Set(expected);
74
+ return got.size === exp.size && [...exp].every(x => got.has(x));
75
+ };
76
+
77
+ const results = {
78
+ a_aliasesMatch: sameSet(aSnap?.aliases || '', ['alpha', 'gamma']),
79
+ a_titleListsThem: /alpha.*gamma|gamma.*alpha/.test(aSnap?.title || ''),
80
+ a_titleClickToPin: /click to pin/.test(aSnap?.title || ''),
81
+ o_aliasesMatch: sameSet(oSnap?.aliases || '', ['beta', 'delta']),
82
+ o_titleListsThem: /beta.*delta|delta.*beta/.test(oSnap?.title || ''),
83
+ pinnedA_aliasesUnchanged: sameSet(aPinned?.aliases || '', ['alpha', 'gamma']),
84
+ pinnedA_titleHintFlipped: /click again or Esc to clear/.test(aPinned?.title || ''),
85
+ pinnedA_pinnedAttrTrue: aPinned?.pinned === 'true',
86
+ };
87
+ const ok = Object.values(results).every(Boolean);
88
+ console.log(`${ok ? '✅' : '❌'} vendor-letter tooltip:`, JSON.stringify(results),
89
+ `\n A:`, aSnap,
90
+ `\n O:`, oSnap,
91
+ `\n A-pinned:`, aPinned);
92
+ process.exit(ok ? 0 : 1);
@@ -0,0 +1,131 @@
1
+ /* Round 168 verification: smooth viewport transition on reset/fit.
2
+ *
3
+ * Pre-R168 resetView/fitView snapped the <g transform> from
4
+ * current zoom/pan to {zoom:1, x:0, y:0} in one frame. Pressing
5
+ * `0` or clicking the hub jolted the eye.
6
+ *
7
+ * R168 arms a one-shot smoothView flag when resetView/fitView
8
+ * fires; the viewport <g> reads this flag and conditionally
9
+ * applies `transition: transform 300ms ease-out`. Auto-clears
10
+ * 350ms later. Pan (R103 drag) and wheel zoom never set the
11
+ * flag, so interactive view changes stay snappy.
12
+ *
13
+ * Test:
14
+ * 1. Load page → idle state, smoothView=false (no transition)
15
+ * 2. Zoom in twice via '+' to set non-default view
16
+ * 3. Press '0' (resetView) → smoothView=true, viewport <g>
17
+ * has style.transition = 'transform 300ms ease-out'
18
+ * 4. Wait 450ms → smoothView=false again, transition cleared
19
+ * 5. Repeat with 'f' (fitView)
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
+ const ctx = await browser.newContext({ viewport: { width: 1500, height: 1500 } });
28
+ await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
29
+ await ctx.addInitScript(() => {
30
+ try { localStorage.setItem('anet-theme', 'cyber'); sessionStorage.setItem('anet_v3_auth', '1'); } catch {}
31
+ });
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) => ({
39
+ alias, status: 'working', 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: [mk('alpha'), mk('beta'), mk('gamma')] } });
44
+ });
45
+ await ctx.route('**/api/hub/messages*', (route) => route.fulfill({ json: { messages: [] } }));
46
+ await ctx.route('**/api/hub/tasks*', (route) => route.fulfill({ json: { tasks: [] } }));
47
+
48
+ const page = await ctx.newPage();
49
+ await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
50
+ await page.waitForFunction(() => document.querySelectorAll('g[data-node]').length === 3, { timeout: 30000 });
51
+ await page.waitForSelector('[data-topo-viewport]', { timeout: 10000 });
52
+ await page.waitForTimeout(400);
53
+
54
+ // Idle: smoothView=false, no transition style.
55
+ const idle = await page.evaluate(() => {
56
+ const g = document.querySelector('[data-topo-viewport]');
57
+ return {
58
+ smooth: g?.getAttribute('data-topo-viewport-smooth'),
59
+ transition: g?.style?.transition || '',
60
+ };
61
+ });
62
+
63
+ // Zoom in twice → set non-default view
64
+ await page.keyboard.press('+');
65
+ await page.keyboard.press('+');
66
+ await page.waitForTimeout(150);
67
+ const zoomBefore = await page.evaluate(() =>
68
+ document.querySelector('[data-topo-chrome-zoom-level]')?.textContent?.trim());
69
+
70
+ // Press 0 (resetView) → smoothView=true. Probe within the
71
+ // 350ms window so the style is still set.
72
+ await page.keyboard.press('0');
73
+ // Small delay so React commits the state update.
74
+ await page.waitForTimeout(50);
75
+ const duringReset = await page.evaluate(() => {
76
+ const g = document.querySelector('[data-topo-viewport]');
77
+ return {
78
+ smooth: g?.getAttribute('data-topo-viewport-smooth'),
79
+ transition: g?.style?.transition || '',
80
+ };
81
+ });
82
+
83
+ // Wait past the 350ms window
84
+ await page.waitForTimeout(450);
85
+ const afterReset = await page.evaluate(() => {
86
+ const g = document.querySelector('[data-topo-viewport]');
87
+ return {
88
+ smooth: g?.getAttribute('data-topo-viewport-smooth'),
89
+ transition: g?.style?.transition || '',
90
+ };
91
+ });
92
+ const zoomAfter = await page.evaluate(() =>
93
+ document.querySelector('[data-topo-chrome-zoom-level]')?.textContent?.trim());
94
+
95
+ // Now zoom in again and press 'f' (fitView) — same arming path
96
+ await page.keyboard.press('+');
97
+ await page.keyboard.press('+');
98
+ await page.waitForTimeout(150);
99
+ await page.keyboard.press('f');
100
+ await page.waitForTimeout(50);
101
+ const duringFit = await page.evaluate(() => {
102
+ const g = document.querySelector('[data-topo-viewport]');
103
+ return {
104
+ smooth: g?.getAttribute('data-topo-viewport-smooth'),
105
+ transition: g?.style?.transition || '',
106
+ };
107
+ });
108
+
109
+ await browser.close();
110
+
111
+ const results = {
112
+ viewport_found: idle !== null,
113
+ idle_smooth_false: idle.smooth === 'false',
114
+ idle_no_transition: !idle.transition.includes('transform'),
115
+ zoomed_before_reset: zoomBefore !== '100%',
116
+ reset_armed_smooth: duringReset.smooth === 'true',
117
+ reset_transition_set: duringReset.transition.includes('transform 300ms'),
118
+ after_reset_smooth_false: afterReset.smooth === 'false',
119
+ after_reset_no_transition: !afterReset.transition.includes('transform'),
120
+ reset_landed_at_100: zoomAfter === '100%',
121
+ fit_armed_smooth: duringFit.smooth === 'true',
122
+ fit_transition_set: duringFit.transition.includes('transform 300ms'),
123
+ };
124
+ const ok = Object.values(results).every(Boolean);
125
+ console.log(`${ok ? '✅' : '❌'} view smooth transition:`, JSON.stringify(results),
126
+ `\n idle =`, idle,
127
+ `\n duringReset =`, duringReset,
128
+ `\n afterReset =`, afterReset,
129
+ `\n duringFit =`, duringFit,
130
+ `\n zoom before/after = ${zoomBefore} → ${zoomAfter}`);
131
+ process.exit(ok ? 0 : 1);
@@ -0,0 +1,99 @@
1
+ /* Round 289 verification: sleep2agi watermark wordmark gains
2
+ * letterSpacing="0.5". Same typographic-intent idiom R285 (kicker
3
+ * tracking-widest) and R286 (title tracking-tight) — letter-spacing
4
+ * as deliberate register signal.
5
+ *
6
+ * Contract:
7
+ * - [data-topo-brand-watermark] computed letter-spacing ≈ 0.5px.
8
+ * (SVG letter-spacing attr value is parsed as user-space units;
9
+ * at fontSize 11 monospace, 0.5px reads as a noticeable but
10
+ * non-loud track widening.)
11
+ * - Text content still 'sleep2agi'.
12
+ * - opacity still 0.4 (watermark register preserved).
13
+ * - fontWeight still 600.
14
+ * - R287 minimap rect + R286 title + R285 kicker + R283 monogram
15
+ * stroke all intact (regression).
16
+ */
17
+ import { chromium } from 'playwright';
18
+ import { readFileSync } from 'node:fs';
19
+
20
+ const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
21
+ const browser = await chromium.launch({ headless: true });
22
+ const ctx = await browser.newContext({ viewport: { width: 1500, height: 1500 } });
23
+ await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
24
+ await ctx.addInitScript(() => {
25
+ try { localStorage.setItem('anet-theme', 'cyber'); sessionStorage.setItem('anet_v3_auth', '1'); } catch {}
26
+ });
27
+ const fresh = new Date(Date.now() - 60 * 1000).toISOString();
28
+ await ctx.route('**/api/hub/status*', async (route) => {
29
+ const r = await route.fetch();
30
+ const b = await r.json();
31
+ const nid = (b.sessions || [])[0]?.network_id || 'default';
32
+ const mk = (alias, model) => ({
33
+ alias, status: 'working', model, runtime: 'claude-code-cli',
34
+ network_id: nid, project_dir: null,
35
+ created_at: fresh, updated_at: fresh, last_seen_at: fresh,
36
+ });
37
+ await route.fulfill({ response: r, json: { ...b, sessions: [
38
+ mk('alpha', 'claude-opus-4'),
39
+ mk('beta', 'gpt-4o'),
40
+ ] } });
41
+ });
42
+ await ctx.route('**/api/hub/messages*', (r) => r.fulfill({ json: { messages: [] } }));
43
+ await ctx.route('**/api/hub/tasks*', (r) => r.fulfill({ json: { tasks: [] } }));
44
+
45
+ const page = await ctx.newPage();
46
+ await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
47
+ await page.waitForSelector('[data-topo-brand-watermark]', { timeout: 15000 });
48
+ await page.waitForTimeout(300);
49
+
50
+ const probe = await page.evaluate(() => {
51
+ const mark = document.querySelector('[data-topo-brand-watermark]');
52
+ const ls = mark ? mark.getAttribute('letter-spacing') : null;
53
+ const computedLs = mark ? getComputedStyle(mark).letterSpacing : null;
54
+ const kicker = document.querySelector('[data-topo-section-kicker]');
55
+ const title = document.querySelector('[data-topo-section-title]');
56
+ const kCs = kicker ? getComputedStyle(kicker) : null;
57
+ const tCs = title ? getComputedStyle(title) : null;
58
+ const alphaNode = document.querySelector('g[data-node="alpha"]');
59
+ const alphaCircles = alphaNode ? [...alphaNode.querySelectorAll('circle')] : [];
60
+ const alphaAvatarCircle = alphaCircles
61
+ .map(c => ({ r: +c.getAttribute('r') || 0, sw: c.getAttribute('stroke-width'), isBadge: c.hasAttribute('data-runtime-badge') }))
62
+ .filter(c => c.r > 0 && c.r < 18 && !c.isBadge)
63
+ .sort((a, b) => b.r - a.r)[0];
64
+ return {
65
+ present: mark !== null,
66
+ text: mark?.textContent ?? null,
67
+ opacity: mark?.getAttribute('opacity') ?? null,
68
+ fontWeight: mark?.getAttribute('font-weight') ?? null,
69
+ letterSpacingAttr: ls,
70
+ computedLetterSpacing: computedLs,
71
+ kickerLs: kCs?.letterSpacing ?? null,
72
+ titleLs: tCs?.letterSpacing ?? null,
73
+ alphaAvatarStroke: alphaAvatarCircle?.sw ?? null,
74
+ };
75
+ });
76
+ await browser.close();
77
+
78
+ const computedLsVal = parseFloat(probe.computedLetterSpacing) || 0;
79
+ const kLs = parseFloat(probe.kickerLs) || 0;
80
+ const tLs = parseFloat(probe.titleLs) || 0;
81
+
82
+ const results = {
83
+ watermark_present: probe.present,
84
+ watermark_text_kept: probe.text === 'sleep2agi',
85
+ watermark_letter_spacing_attr_set: probe.letterSpacingAttr === '0.5',
86
+ watermark_computed_ls_about_half: computedLsVal >= 0.4 && computedLsVal <= 0.7,
87
+ watermark_opacity_kept: probe.opacity === '0.4',
88
+ watermark_font_weight_kept: probe.fontWeight === '600',
89
+ r285_kicker_widest_kept: kLs >= 1.0 && kLs <= 1.5,
90
+ r286_title_tight_kept: tLs < 0,
91
+ r283_monogram_stroke_kept: probe.alphaAvatarStroke === '1.5',
92
+ };
93
+ const ok = Object.values(results).every(Boolean);
94
+ console.log(`${ok ? '✅' : '❌'} watermark tracking:`, JSON.stringify(results),
95
+ '\n text:', JSON.stringify(probe.text),
96
+ '\n attr letter-spacing:', probe.letterSpacingAttr,
97
+ '\n computed letter-spacing:', probe.computedLetterSpacing,
98
+ '\n opacity:', probe.opacity);
99
+ process.exit(ok ? 0 : 1);