@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,93 @@
1
+ /* Round 225 verification: info-density tabular-nums sweep across
2
+ * the three remaining digit-bearing texts in the TopoGraph after
3
+ * R224's edge badge:
4
+ * 1) Hub center digit (data-topo-hub-working-count)
5
+ * 2) Recent panel header (data-recent-panel-count tspan)
6
+ * 3) Recent row count (data-recent-row-count tspan)
7
+ *
8
+ * Pre-R225 each suffered the same monospace-digit jitter at the
9
+ * 9 → 10 boundary (the digit-vs-control glyph width variance is
10
+ * non-zero even in mono fonts; textAnchor='middle' or trailing
11
+ * text columns visibly shift on the boundary).
12
+ *
13
+ * Verification: getComputedStyle().fontVariantNumeric contains
14
+ * 'tabular-nums' on each of the three. Single populated scenario
15
+ * (4 working agents + 12-msg hot flow) drives all three at once.
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) => ({
33
+ alias, status: 'working', model: 'claude-opus-4', 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'), mk('beta'), mk('gamma'), mk('delta'),
39
+ ] } });
40
+ });
41
+ const now = Date.now();
42
+ const msgs = [];
43
+ for (let i = 0; i < 12; i++) {
44
+ msgs.push({
45
+ id: `m${i}`, from_alias: 'alpha', to_alias: 'beta', content: 'hi',
46
+ network_id: 'default', created_at: new Date(now - (1000 + i * 50)).toISOString(),
47
+ });
48
+ }
49
+ await ctx.route('**/api/hub/messages*', (r2) => r2.fulfill({ json: { messages: msgs } }));
50
+ await ctx.route('**/api/hub/tasks*', (r2) => r2.fulfill({ json: { tasks: [] } }));
51
+
52
+ const page = await ctx.newPage();
53
+ await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
54
+ await page.waitForFunction(() => document.querySelectorAll('g[data-node]').length === 4, { timeout: 30000 });
55
+ await page.waitForSelector('[data-recent-row-count]', { timeout: 10000, state: 'attached' });
56
+ await page.waitForTimeout(400);
57
+
58
+ const out = await page.evaluate(() => {
59
+ const fvn = (el) => el ? getComputedStyle(el).fontVariantNumeric : null;
60
+ const text = (el) => el?.textContent?.trim() || null;
61
+ const hubDigit = document.querySelector('[data-topo-hub-working-count]');
62
+ const panelCnt = document.querySelector('[data-recent-panel-count]');
63
+ const rowCnt = document.querySelector('[data-recent-row-count]');
64
+ return {
65
+ hub: { found: !!hubDigit, fvn: fvn(hubDigit), text: text(hubDigit),
66
+ working: hubDigit?.getAttribute('data-topo-hub-working-count') },
67
+ panel: { found: !!panelCnt, fvn: fvn(panelCnt), text: text(panelCnt) },
68
+ row: { found: !!rowCnt, fvn: fvn(rowCnt), text: text(rowCnt) },
69
+ };
70
+ });
71
+ await browser.close();
72
+
73
+ const hasTab = (s) => /tabular-nums/.test(s || '');
74
+ const results = {
75
+ hub_found: out.hub.found,
76
+ hub_tabular: hasTab(out.hub.fvn),
77
+ hub_text_present: /^\d+$/.test(out.hub.text || ''),
78
+ hub_text_equals_4: out.hub.text === '4',
79
+
80
+ panel_found: out.panel.found,
81
+ panel_tabular: hasTab(out.panel.fvn),
82
+ panel_text_flows: /^\d+\s+flows?$/.test(out.panel.text || ''),
83
+
84
+ row_found: out.row.found,
85
+ row_tabular: hasTab(out.row.fvn),
86
+ row_text_equals_12: out.row.text === '12',
87
+ };
88
+ const ok = Object.values(results).every(Boolean);
89
+ console.log(`${ok ? '✅' : '❌'} tabular-nums sweep:`, JSON.stringify(results),
90
+ '\n hub: ', out.hub,
91
+ '\n panel:', out.panel,
92
+ '\n row: ', out.row);
93
+ process.exit(ok ? 0 : 1);
@@ -0,0 +1,86 @@
1
+ /* Round 303 verification: tier guide ring strokeDasharray tightens
2
+ * from "2 8" → "2 6". Same 2px dash; 8px gap → 6px gap so dashes
3
+ * read closer together, giving tier-guide rings clearer continuous-
4
+ * ring presence after R290/R291 cleared surrounding backdrop noise.
5
+ *
6
+ * Contract:
7
+ * - All [data-tier-ring] elements have stroke-dasharray '2 6'.
8
+ * - strokeWidth still 0.7 (regression).
9
+ * - At least one tier ring rendered with the test fixture (4-node
10
+ * working fleet → single-tier layout 220 fits).
11
+ * - R302 empty-hint ls=0.2 + R301 panel titles ls=0.3 + R300 kicker
12
+ * fw=500 + R294 pulse absent intact.
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
+ const ctx = await browser.newContext({ viewport: { width: 1500, height: 1500 } });
20
+ await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
21
+ await ctx.addInitScript(() => {
22
+ try { localStorage.setItem('anet-theme', 'cyber'); sessionStorage.setItem('anet_v3_auth', '1'); } catch {}
23
+ });
24
+ const fresh = new Date(Date.now() - 60 * 1000).toISOString();
25
+ await ctx.route('**/api/hub/status*', async (route) => {
26
+ const r = await route.fetch();
27
+ const b = await r.json();
28
+ const nid = (b.sessions || [])[0]?.network_id || 'default';
29
+ const mk = (alias, model) => ({
30
+ alias, status: 'working', model, runtime: 'claude-code-cli',
31
+ network_id: nid, project_dir: null,
32
+ created_at: fresh, updated_at: fresh, last_seen_at: fresh,
33
+ });
34
+ // 4 working nodes → single-tier ring layout.
35
+ await route.fulfill({ response: r, json: { ...b, sessions: [
36
+ mk('alpha', 'claude-opus-4'),
37
+ mk('beta', 'gpt-4o'),
38
+ mk('gamma', 'claude-sonnet-4'),
39
+ mk('delta', 'gpt-4'),
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.waitForFunction(() => document.querySelectorAll('g[data-node]').length === 4, { timeout: 30000 });
48
+ await page.waitForTimeout(400);
49
+
50
+ const probe = await page.evaluate(() => {
51
+ const tierRings = [...document.querySelectorAll('[data-tier-ring]')];
52
+ const samples = tierRings.map(t => ({
53
+ r: t.getAttribute('data-tier-ring'),
54
+ dasharray: t.getAttribute('stroke-dasharray'),
55
+ strokeWidth: t.getAttribute('stroke-width'),
56
+ occupancy: t.getAttribute('data-tier-occupancy'),
57
+ }));
58
+ const empty = document.querySelector('[data-recent-signal-empty]');
59
+ const recentTitle = document.querySelector('[data-recent-panel-title]');
60
+ const legendTitle = document.querySelector('[data-legend-panel-title]');
61
+ const kicker = document.querySelector('[data-topo-section-kicker]');
62
+ return {
63
+ samples,
64
+ emptyLs: empty?.getAttribute('letter-spacing') ?? null,
65
+ recentTitleLs: recentTitle?.getAttribute('letter-spacing') ?? null,
66
+ legendTitleLs: legendTitle?.getAttribute('letter-spacing') ?? null,
67
+ kickerFw: kicker ? getComputedStyle(kicker).fontWeight : null,
68
+ pulseCount: document.querySelectorAll('[data-pulse-wrapper]').length,
69
+ };
70
+ });
71
+ await browser.close();
72
+
73
+ const results = {
74
+ tier_rings_rendered: probe.samples.length >= 1,
75
+ all_dasharray_2_6: probe.samples.every(s => s.dasharray === '2 6'),
76
+ all_stroke_width_0_7: probe.samples.every(s => s.strokeWidth === '0.7'),
77
+ r302_empty_hint_ls_0_2: probe.emptyLs === '0.2',
78
+ r301_recent_title_ls: probe.recentTitleLs === '0.3',
79
+ r301_legend_title_ls: probe.legendTitleLs === '0.3',
80
+ r300_kicker_fw_500: String(probe.kickerFw) === '500',
81
+ r294_pulse_absent: probe.pulseCount === 0,
82
+ };
83
+ const ok = Object.values(results).every(Boolean);
84
+ console.log(`${ok ? '✅' : '❌'} tier guide dashes:`, JSON.stringify(results),
85
+ '\n tier rings sampled:', probe.samples);
86
+ process.exit(ok ? 0 : 1);
@@ -0,0 +1,107 @@
1
+ /* Round 174 verification: tier guide rings (ring layout) fade-in
2
+ * alongside R9/R172/R173 first-paint wave.
3
+ *
4
+ * Pre-R174 the structural scaffolding for ring layout — R54
5
+ * dashed concentric guide rings — appeared instantly while
6
+ * nodes inside eased in via R9/R72. Closes the symmetry with
7
+ * R173 group boxes (grid layout's structural frame).
8
+ *
9
+ * R174 wraps each tier ring <circle> in:
10
+ * className="anet-fade-in"
11
+ * style.animationDelay: tierIdx × 60ms (cap 8)
12
+ * transition list grows opacity 250ms ease-out
13
+ * data-tier-fade-delay={...}
14
+ *
15
+ * Test:
16
+ * 1. Force ring layout
17
+ * 2. Mock 16 sessions → triggers triple-tier render (>14)
18
+ * 3. Probe all [data-tier-ring] circles
19
+ * 4. Each has .anet-fade-in className + correct fade-delay
20
+ * 5. Delays strictly increase by 60ms
21
+ */
22
+ import { chromium } from 'playwright';
23
+ import { readFileSync } from 'node:fs';
24
+
25
+ const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
26
+ const browser = await chromium.launch({ headless: true });
27
+
28
+ const ctx = await browser.newContext({ viewport: { width: 1500, height: 1500 } });
29
+ await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
30
+ await ctx.addInitScript(() => {
31
+ try {
32
+ localStorage.setItem('anet-theme', 'cyber');
33
+ sessionStorage.setItem('anet_v3_auth', '1');
34
+ localStorage.setItem('anet-topo-layout', 'ring');
35
+ } catch {}
36
+ });
37
+
38
+ const fresh = new Date(Date.now() - 60 * 1000).toISOString();
39
+ await ctx.route('**/api/hub/status*', async (route) => {
40
+ const r = await route.fetch();
41
+ const b = await r.json();
42
+ const nid = (b.sessions || [])[0]?.network_id || 'default';
43
+ // 16 sessions → R98 triple-tier (threshold > 14)
44
+ const sessions = [];
45
+ for (let i = 0; i < 16; i++) {
46
+ sessions.push({
47
+ alias: `n${i}`,
48
+ status: 'working',
49
+ model: 'claude-opus-4',
50
+ runtime: 'cli-claude-code',
51
+ network_id: nid,
52
+ project_dir: null,
53
+ created_at: fresh, updated_at: fresh, last_seen_at: fresh,
54
+ });
55
+ }
56
+ await route.fulfill({ response: r, json: { ...b, sessions } });
57
+ });
58
+ await ctx.route('**/api/hub/messages*', (route) => route.fulfill({ json: { messages: [] } }));
59
+ await ctx.route('**/api/hub/tasks*', (route) => route.fulfill({ json: { tasks: [] } }));
60
+
61
+ const page = await ctx.newPage();
62
+ await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
63
+ await page.waitForFunction(() => document.querySelectorAll('g[data-node]').length === 16, { timeout: 30000 });
64
+ await page.waitForSelector('[data-tier-ring]', { timeout: 10000 });
65
+ await page.waitForTimeout(400);
66
+
67
+ const probe = await page.evaluate(() => {
68
+ const rings = [...document.querySelectorAll('[data-tier-ring]')];
69
+ return rings.map(r => ({
70
+ radius: parseFloat(r.getAttribute('data-tier-ring') || ''),
71
+ occupancy: parseFloat(r.getAttribute('data-tier-occupancy') || ''),
72
+ hasFadeClass: (r.getAttribute('class') || '').includes('anet-fade-in'),
73
+ fadeDelayAttr: parseFloat(r.getAttribute('data-tier-fade-delay') || ''),
74
+ animationDelay: r.style.animationDelay || getComputedStyle(r).animationDelay,
75
+ transition: r.style.transition || getComputedStyle(r).transition,
76
+ }));
77
+ });
78
+
79
+ await browser.close();
80
+
81
+ const parseDelay = (s) => {
82
+ if (!s) return null;
83
+ if (s.endsWith('ms')) return parseFloat(s);
84
+ if (s.endsWith('s')) return parseFloat(s) * 1000;
85
+ return parseFloat(s);
86
+ };
87
+ const delays = probe.map(p => parseDelay(p.animationDelay));
88
+
89
+ const expectedDelays = probe.map((_, i) => Math.min(i, 8) * 60);
90
+
91
+ const results = {
92
+ three_tiers_found: probe.length === 3,
93
+ all_have_fade_class: probe.every(p => p.hasFadeClass),
94
+ all_have_opacity_in_transition: probe.every(p =>
95
+ (p.transition || '').includes('opacity')),
96
+ delay_attrs_match: probe.every((p, i) => p.fadeDelayAttr === expectedDelays[i]),
97
+ delays_match: delays.every((d, i) => Math.abs(d - expectedDelays[i]) < 0.5),
98
+ delays_strictly_increase: delays[0] < delays[1] && delays[1] < delays[2],
99
+ first_delay_0ms: delays[0] === 0,
100
+ third_delay_120ms: delays[2] === 120,
101
+ };
102
+ const ok = Object.values(results).every(Boolean);
103
+ console.log(`${ok ? '✅' : '❌'} tier-ring fade-in:`, JSON.stringify(results),
104
+ `\n rings =`, probe,
105
+ `\n delays (ms) =`, delays,
106
+ `\n expected =`, expectedDelays);
107
+ process.exit(ok ? 0 : 1);
@@ -0,0 +1,110 @@
1
+ /* Round 93 verification: tier rings tint to pal.legendAccent when
2
+ * any of pinnedStatus / pinnedGroup / pinnedVendor is active, and
3
+ * revert to the neutral pal.ringStroke when all three release.
4
+ *
5
+ * Drive pin state via the R69 CustomEvent for status (deterministic;
6
+ * same approach the R82 chip-pin-mirror test uses) and the vendor
7
+ * letter click for vendor. Verify data-tier-tinted toggles + stroke
8
+ * attribute differs from the neutral baseline.
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
+ localStorage.setItem('anet-topo-layout', 'ring');
22
+ sessionStorage.setItem('anet_v3_auth', '1');
23
+ sessionStorage.removeItem('anet-topo-pinned-status');
24
+ sessionStorage.removeItem('anet-topo-pinned-group');
25
+ sessionStorage.removeItem('anet-topo-pinned-vendor');
26
+ } catch {}
27
+ });
28
+
29
+ const fresh = new Date(Date.now() - 60 * 1000).toISOString();
30
+ await ctx.route('**/api/hub/status*', async (route) => {
31
+ const r = await route.fetch();
32
+ const b = await r.json();
33
+ const nid = (b.sessions || [])[0]?.network_id || 'default';
34
+ // 4 nodes → single tier (≤8 threshold). Enough to have 1 ring to inspect.
35
+ const mk = (alias, model) => ({
36
+ alias, status: 'idle', model, runtime: 'cli-claude-code',
37
+ network_id: nid, project_dir: null,
38
+ created_at: fresh, updated_at: fresh, last_seen_at: fresh,
39
+ });
40
+ const sessions = [
41
+ mk('alpha', 'claude-opus-4'),
42
+ mk('beta', 'gpt-5'),
43
+ mk('gamma', 'claude-opus-4'),
44
+ mk('delta', 'gpt-5'),
45
+ ];
46
+ await route.fulfill({ response: r, json: { ...b, sessions } });
47
+ });
48
+ await ctx.route('**/api/hub/messages*', (route) => route.fulfill({ json: { messages: [] } }));
49
+ await ctx.route('**/api/hub/tasks*', (route) => route.fulfill({ json: { tasks: [] } }));
50
+ const page = await ctx.newPage();
51
+ await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
52
+ await page.waitForFunction(() => document.querySelectorAll('g[data-node]').length === 4, { timeout: 30000 });
53
+ await page.waitForTimeout(400);
54
+
55
+ const ring = () => page.evaluate(() => {
56
+ const r = document.querySelector('[data-tier-ring]');
57
+ if (!r) return null;
58
+ return {
59
+ tinted: r.getAttribute('data-tier-tinted'),
60
+ stroke: r.getAttribute('stroke'),
61
+ };
62
+ });
63
+
64
+ const before = await ring();
65
+
66
+ // Pin a status — tier ring should tint.
67
+ await page.evaluate(() => {
68
+ sessionStorage.setItem('anet-topo-pinned-status', 'idle');
69
+ window.dispatchEvent(new CustomEvent('anet:topo-pin', { detail: { kind: 'status', value: 'idle' } }));
70
+ });
71
+ await page.waitForTimeout(300);
72
+ const afterStatusPin = await ring();
73
+
74
+ // Clear via Esc — ring should revert.
75
+ await page.keyboard.press('Escape');
76
+ await page.waitForTimeout(250);
77
+ const afterEscStatus = await ring();
78
+
79
+ // Pin vendor — tier ring should tint again.
80
+ await page.locator('[data-vendor-letter="A"]').click();
81
+ await page.mouse.move(10, 10);
82
+ await page.waitForTimeout(250);
83
+ const afterVendorPin = await ring();
84
+
85
+ // Clear via Esc — back to neutral.
86
+ await page.keyboard.press('Escape');
87
+ await page.waitForTimeout(250);
88
+ const afterEscVendor = await ring();
89
+
90
+ await browser.close();
91
+
92
+ const results = {
93
+ before_neutral: before?.tinted === 'false',
94
+ before_strokeSet: typeof before?.stroke === 'string' && before.stroke.length > 0,
95
+ statusPin_tinted: afterStatusPin?.tinted === 'true',
96
+ statusPin_strokeDiffers: afterStatusPin?.stroke !== before?.stroke,
97
+ escStatus_revertsTinted: afterEscStatus?.tinted === 'false',
98
+ escStatus_strokeMatchesBaseline: afterEscStatus?.stroke === before?.stroke,
99
+ vendorPin_tinted: afterVendorPin?.tinted === 'true',
100
+ vendorPin_strokeDiffers: afterVendorPin?.stroke !== before?.stroke,
101
+ escVendor_revertsTinted: afterEscVendor?.tinted === 'false',
102
+ };
103
+ const ok = Object.values(results).every(Boolean);
104
+ console.log(`${ok ? '✅' : '❌'} tier-ring tint:`, JSON.stringify(results),
105
+ `\n before=`, before,
106
+ `\n afterStatusPin=`, afterStatusPin,
107
+ `\n afterEscStatus=`, afterEscStatus,
108
+ `\n afterVendorPin=`, afterVendorPin,
109
+ `\n afterEscVendor=`, afterEscVendor);
110
+ process.exit(ok ? 0 : 1);
@@ -0,0 +1,95 @@
1
+ /* Round 267 verification: title block adopts leading-tight on both
2
+ * kicker and h2 for tighter editorial-style rhythm.
3
+ *
4
+ * Pre-R267 the title block used Tailwind compound defaults:
5
+ * kicker (text-xs): font 12px / line 16px (ratio ~1.33)
6
+ * h2 (text-lg): font 18px / line 28px (ratio ~1.56)
7
+ * Total title block height: ~44 px
8
+ *
9
+ * R267 adds leading-tight (1.25) to both:
10
+ * kicker: 12px font in 15px line
11
+ * h2: 18px font in 22.5px line
12
+ * Total: ~37.5 px (~15% more compact)
13
+ *
14
+ * Test scope:
15
+ * 1. Kicker present with data-topo-section-kicker attr.
16
+ * 2. h2 present with data-topo-section-title attr.
17
+ * 3. Kicker computed line-height < 16px (was 16px; should be 15px).
18
+ * 4. h2 computed line-height < 28px (was 28px; should be 22.5px).
19
+ * 5. Total title block bounding height ≤ 45 px (was ~44; should be ~37).
20
+ * Allow generous slop since browser font metrics + sub-pixel
21
+ * rounding vary.
22
+ */
23
+ import { chromium } from 'playwright';
24
+ import { readFileSync } from 'node:fs';
25
+
26
+ const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
27
+ const browser = await chromium.launch({ headless: true });
28
+ const ctx = await browser.newContext({ viewport: { width: 1500, height: 1500 } });
29
+ await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
30
+ await ctx.addInitScript(() => {
31
+ try { localStorage.setItem('anet-theme', 'cyber'); sessionStorage.setItem('anet_v3_auth', '1'); } catch {}
32
+ });
33
+ const fresh = new Date(Date.now() - 60 * 1000).toISOString();
34
+ await ctx.route('**/api/hub/status*', async (route) => {
35
+ const r = await route.fetch();
36
+ const b = await r.json();
37
+ const nid = (b.sessions || [])[0]?.network_id || 'default';
38
+ const mk = (alias) => ({
39
+ alias, status: 'working', model: 'claude-opus-4', runtime: 'claude-code-cli',
40
+ network_id: nid, project_dir: null,
41
+ created_at: fresh, updated_at: fresh, last_seen_at: fresh,
42
+ });
43
+ await route.fulfill({ response: r, json: { ...b, sessions: [
44
+ mk('alpha'), mk('beta'), mk('gamma'), mk('delta'),
45
+ ] } });
46
+ });
47
+ await ctx.route('**/api/hub/messages*', (r) => r.fulfill({ json: { messages: [] } }));
48
+ await ctx.route('**/api/hub/tasks*', (r) => r.fulfill({ json: { tasks: [] } }));
49
+
50
+ const page = await ctx.newPage();
51
+ await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
52
+ await page.waitForFunction(() => document.querySelectorAll('g[data-node]').length === 4, { timeout: 30000 });
53
+ await page.waitForSelector('[data-topo-section-kicker]', { timeout: 10000 });
54
+ await page.waitForSelector('[data-topo-section-title]', { timeout: 10000 });
55
+ await page.waitForTimeout(300);
56
+
57
+ const probe = await page.evaluate(() => {
58
+ const kicker = document.querySelector('[data-topo-section-kicker]');
59
+ const title = document.querySelector('[data-topo-section-title]');
60
+ // The two stack inside a parent <div>; measure parent's bounding box
61
+ // for "title block height".
62
+ const parent = kicker?.parentElement ?? null;
63
+ const parseLH = (el) => {
64
+ const lh = window.getComputedStyle(el).lineHeight;
65
+ // Chrome returns either '15px' or 'normal' or a multiplier like '1.25'.
66
+ // For px values, parseFloat works; for 'normal', return font-size.
67
+ if (lh === 'normal') {
68
+ return parseFloat(window.getComputedStyle(el).fontSize);
69
+ }
70
+ return parseFloat(lh);
71
+ };
72
+ return {
73
+ kickerHasClass: kicker?.classList.contains('leading-tight') ?? false,
74
+ titleHasClass: title?.classList.contains('leading-tight') ?? false,
75
+ kickerLH: kicker ? parseLH(kicker) : null,
76
+ titleLH: title ? parseLH(title) : null,
77
+ parentHeight: parent ? parent.getBoundingClientRect().height : null,
78
+ };
79
+ });
80
+ await browser.close();
81
+
82
+ const results = {
83
+ kicker_has_leading_tight_class: probe.kickerHasClass,
84
+ title_has_leading_tight_class: probe.titleHasClass,
85
+ kicker_line_height_under_16: probe.kickerLH != null && probe.kickerLH < 16,
86
+ title_line_height_under_28: probe.titleLH != null && probe.titleLH < 28,
87
+ // Pre-R267 title block was ~44px tall. Post-R267 target ~37.5px.
88
+ // Allow slop for browser metrics: <= 45 confirms compression happened.
89
+ title_block_height_under_45: probe.parentHeight != null && probe.parentHeight <= 45,
90
+ };
91
+ const ok = Object.values(results).every(Boolean);
92
+ console.log(`${ok ? '✅' : '❌'} title block tight leading:`, JSON.stringify(results),
93
+ '\n kicker line-height:', probe.kickerLH, '/ title line-height:', probe.titleLH,
94
+ '\n title block height:', probe.parentHeight);
95
+ process.exit(ok ? 0 : 1);
@@ -0,0 +1,98 @@
1
+ /* Round 286 verification: h2 title 'Command mesh' adopts tracking-
2
+ * tight (-0.025em) to pair with R285 kicker tracking-widest (0.1em).
3
+ * Wide eyebrow + tight headline is the editorial-pairing convention.
4
+ *
5
+ * At text-lg = 18px, tracking-tight resolves to:
6
+ * 18 * -0.025 = -0.45px letter-spacing
7
+ *
8
+ * Contract:
9
+ * - [data-topo-section-title] computed letter-spacing is negative
10
+ * and ~ -0.025em (= ~ -0.45px at 18px).
11
+ * - Text content still 'Command mesh'.
12
+ * - font-weight still 600 (font-semibold).
13
+ * - Kicker still tracking-widest (R285 regression).
14
+ * - R283 monogram stroke / R282 watermark 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
+ await route.fulfill({ response: r, json: { ...b, sessions: [
37
+ mk('alpha', 'claude-opus-4'),
38
+ mk('beta', 'gpt-4o'),
39
+ ] } });
40
+ });
41
+ await ctx.route('**/api/hub/messages*', (r) => r.fulfill({ json: { messages: [] } }));
42
+ await ctx.route('**/api/hub/tasks*', (r) => r.fulfill({ json: { tasks: [] } }));
43
+
44
+ const page = await ctx.newPage();
45
+ await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
46
+ await page.waitForSelector('[data-topo-section-title]', { timeout: 15000 });
47
+ await page.waitForSelector('[data-topo-brand-watermark]', { timeout: 10000 });
48
+ await page.waitForTimeout(300);
49
+
50
+ const probe = await page.evaluate(() => {
51
+ const title = document.querySelector('[data-topo-section-title]');
52
+ const kicker = document.querySelector('[data-topo-section-kicker]');
53
+ const tCs = title ? getComputedStyle(title) : null;
54
+ const kCs = kicker ? getComputedStyle(kicker) : null;
55
+ const alphaNode = document.querySelector('g[data-node="alpha"]');
56
+ const alphaCircles = alphaNode ? [...alphaNode.querySelectorAll('circle')] : [];
57
+ const alphaAvatarCircle = alphaCircles
58
+ .map(c => ({ r: +c.getAttribute('r') || 0, sw: c.getAttribute('stroke-width'), isBadge: c.hasAttribute('data-runtime-badge') }))
59
+ .filter(c => c.r > 0 && c.r < 18 && !c.isBadge)
60
+ .sort((a, b) => b.r - a.r)[0];
61
+ const watermark = document.querySelector('[data-topo-brand-watermark]');
62
+ return {
63
+ titleLetterSpacing: tCs?.letterSpacing ?? null,
64
+ titleFontSize: tCs?.fontSize ?? null,
65
+ titleFontWeight: tCs?.fontWeight ?? null,
66
+ titleText: title?.textContent ?? null,
67
+ kickerLetterSpacing: kCs?.letterSpacing ?? null,
68
+ kickerFontSize: kCs?.fontSize ?? null,
69
+ alphaAvatarStroke: alphaAvatarCircle?.sw ?? null,
70
+ watermarkPresent: watermark !== null,
71
+ };
72
+ });
73
+ await browser.close();
74
+
75
+ const tLs = parseFloat(probe.titleLetterSpacing) || 0;
76
+ const tFs = parseFloat(probe.titleFontSize) || 18;
77
+ const tLsPerEm = tFs ? tLs / tFs : 0;
78
+
79
+ const kLs = parseFloat(probe.kickerLetterSpacing) || 0;
80
+ const kFs = parseFloat(probe.kickerFontSize) || 12;
81
+ const kLsPerEm = kFs ? kLs / kFs : 0;
82
+
83
+ const results = {
84
+ title_present: probe.titleText === 'Command mesh',
85
+ title_tight_negative_ls: tLs < 0,
86
+ title_tight_about_n025em: tLsPerEm <= -0.02 && tLsPerEm >= -0.03,
87
+ title_font_weight_600: String(probe.titleFontWeight) === '600',
88
+ kicker_still_widest_r285: kLsPerEm >= 0.08 && kLsPerEm <= 0.12,
89
+ r283_monogram_stroke_kept: probe.alphaAvatarStroke === '1.5',
90
+ r282_watermark_present: probe.watermarkPresent,
91
+ };
92
+ const ok = Object.values(results).every(Boolean);
93
+ console.log(`${ok ? '✅' : '❌'} title tracking:`, JSON.stringify(results),
94
+ '\n title text:', JSON.stringify(probe.titleText),
95
+ '\n title letter-spacing:', probe.titleLetterSpacing, `(=${tLsPerEm.toFixed(4)}em)`,
96
+ '\n title font-size:', probe.titleFontSize, ' weight:', probe.titleFontWeight,
97
+ '\n kicker letter-spacing (R285):', probe.kickerLetterSpacing, `(=${kLsPerEm.toFixed(3)}em)`);
98
+ process.exit(ok ? 0 : 1);