@sleep2agi/agent-network-dashboard 0.4.6 → 0.5.1-preview.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 (493) 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/03v-0n3d~t1sm.js +4 -0
  173. package/.next/static/chunks/0aauz~36q5n2a.css +2 -0
  174. package/.next/static/chunks/0l_~q07bhpkcx.js +7 -0
  175. package/.next/static/chunks/{0hyl7mdapsz38.js → 0vt5wron8jig5.js} +1 -1
  176. package/.next/static/chunks/{16yfxp9ak2gdm.js → 180biiw78-hb_.js} +1 -1
  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 +107 -0
  185. package/app/components/HelpOverlay.tsx +109 -1
  186. package/app/components/ServersDrawer.tsx +181 -5
  187. package/app/components/TopoGraph.tsx +6420 -286
  188. package/app/globals.css +110 -5
  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-filter-pill-test.mjs +101 -0
  209. package/scripts/topo-active-links-chip-hover-test.mjs +103 -0
  210. package/scripts/topo-active-links-chip-nav-test.mjs +117 -0
  211. package/scripts/topo-active-links-chip-self-hover-test.mjs +171 -0
  212. package/scripts/topo-active-links-empty-recede-test.mjs +125 -0
  213. package/scripts/topo-active-links-freshness-test.mjs +113 -0
  214. package/scripts/topo-active-links-tooltip-test.mjs +79 -0
  215. package/scripts/topo-active-links-unit-test.mjs +79 -0
  216. package/scripts/topo-active-pulse-ease-test.mjs +120 -0
  217. package/scripts/topo-brand-logo-transition-test.mjs +94 -0
  218. package/scripts/topo-brand-watermark-test.mjs +97 -0
  219. package/scripts/topo-canvas-aria-test.mjs +108 -0
  220. package/scripts/topo-canvas-brand-fade-test.mjs +87 -0
  221. package/scripts/topo-chat-target-breath-test.mjs +84 -0
  222. package/scripts/topo-chat-target-ring-ease-test.mjs +82 -0
  223. package/scripts/topo-chat-target-ring-fade-test.mjs +124 -0
  224. package/scripts/topo-chip-empty-recede-test.mjs +116 -0
  225. package/scripts/topo-chip-focus-test.mjs +95 -0
  226. package/scripts/topo-chip-pin-mirror-test.mjs +113 -0
  227. package/scripts/topo-chip-row-gap-test.mjs +90 -0
  228. package/scripts/topo-chip-row-semantic-gap-test.mjs +97 -0
  229. package/scripts/topo-chip-row-tabular-test.mjs +111 -0
  230. package/scripts/topo-chip-unit-demotion-test.mjs +93 -0
  231. package/scripts/topo-chiprow-data-weight-test.mjs +94 -0
  232. package/scripts/topo-chrome-a11y-test.mjs +107 -0
  233. package/scripts/topo-chrome-active-weight-test.mjs +104 -0
  234. package/scripts/topo-chrome-focus-ring-unify-test.mjs +100 -0
  235. package/scripts/topo-chrome-gap-test.mjs +73 -0
  236. package/scripts/topo-chrome-icon-stroke-test.mjs +95 -0
  237. package/scripts/topo-chrome-inactive-color-test.mjs +90 -0
  238. package/scripts/topo-chrome-pop-extension-test.mjs +98 -0
  239. package/scripts/topo-chrome-pop-nodesize-test.mjs +88 -0
  240. package/scripts/topo-chrome-press-state-test.mjs +135 -0
  241. package/scripts/topo-chrome-strip-semantic-gap-test.mjs +99 -0
  242. package/scripts/topo-chrome-strip-theme-ease-test.mjs +99 -0
  243. package/scripts/topo-chrome-zoom-level-pop-test.mjs +122 -0
  244. package/scripts/topo-chrome-zoom-pop-test.mjs +130 -0
  245. package/scripts/topo-chrome-zoom-readout-weight-test.mjs +81 -0
  246. package/scripts/topo-click-ripple-ease-test.mjs +94 -0
  247. package/scripts/topo-cmdk-edge-clear-test.mjs +109 -0
  248. package/scripts/topo-cmdk-layout-view-test.mjs +108 -0
  249. package/scripts/topo-cmdk-pin-test.mjs +123 -0
  250. package/scripts/topo-cmdk-vendor-clear-test.mjs +133 -0
  251. package/scripts/topo-cmdk-vendor-pin-test.mjs +103 -0
  252. package/scripts/topo-corner-radius-unify-test.mjs +103 -0
  253. package/scripts/topo-dense-alias-fill-transition-test.mjs +133 -0
  254. package/scripts/topo-discrete-zoom-smooth-test.mjs +125 -0
  255. package/scripts/topo-edge-badge-click-pin-test.mjs +94 -0
  256. package/scripts/topo-edge-badge-crossfade-test.mjs +138 -0
  257. package/scripts/topo-edge-badge-hot-test.mjs +115 -0
  258. package/scripts/topo-edge-badge-hover-test.mjs +85 -0
  259. package/scripts/topo-edge-badge-lift-test.mjs +150 -0
  260. package/scripts/topo-edge-badge-ripple-test.mjs +111 -0
  261. package/scripts/topo-edge-badge-stroke-transition-test.mjs +118 -0
  262. package/scripts/topo-edge-badge-text-pin-test.mjs +121 -0
  263. package/scripts/topo-edge-badge-theme-ease-test.mjs +89 -0
  264. package/scripts/topo-edge-count-badge-test.mjs +86 -0
  265. package/scripts/topo-edge-endpoint-highlight-test.mjs +111 -0
  266. package/scripts/topo-edge-fadein-test.mjs +106 -0
  267. package/scripts/topo-edge-focus-test.mjs +113 -0
  268. package/scripts/topo-edge-hover-test.mjs +13 -5
  269. package/scripts/topo-edge-pill-hot-test.mjs +129 -0
  270. package/scripts/topo-edge-pill-test.mjs +105 -0
  271. package/scripts/topo-edge-ping-pulse-retired-test.mjs +119 -0
  272. package/scripts/topo-edge-stroke-ease-test.mjs +100 -0
  273. package/scripts/topo-edge-stroke-transition-test.mjs +132 -0
  274. package/scripts/topo-empty-hint-tracking-test.mjs +84 -0
  275. package/scripts/topo-empty-state-breath-test.mjs +150 -0
  276. package/scripts/topo-empty-state-crossfade-test.mjs +130 -0
  277. package/scripts/topo-empty-state-recenter-test.mjs +107 -0
  278. package/scripts/topo-empty-sub-hint-italic-test.mjs +83 -0
  279. package/scripts/topo-empty-subhint-tracking-test.mjs +87 -0
  280. package/scripts/topo-endpoint-ring-fade-test.mjs +132 -0
  281. package/scripts/topo-endpoint-ring-test.mjs +93 -0
  282. package/scripts/topo-endpoint-ring-thicken-test.mjs +112 -0
  283. package/scripts/topo-esc-clears-pin-test.mjs +98 -0
  284. package/scripts/topo-filter-pill-aliases-test.mjs +121 -0
  285. package/scripts/topo-filter-pill-body-click-test.mjs +112 -0
  286. package/scripts/topo-filter-pill-count-tabular-test.mjs +135 -0
  287. package/scripts/topo-filter-pill-count-test.mjs +110 -0
  288. package/scripts/topo-filter-pill-mobile-test.mjs +90 -0
  289. package/scripts/topo-freshness-chip-transition-test.mjs +80 -0
  290. package/scripts/topo-freshness-chip-weight-test.mjs +90 -0
  291. package/scripts/topo-freshness-conditional-render-test.mjs +92 -0
  292. package/scripts/topo-fullscreen-active-test.mjs +115 -0
  293. package/scripts/topo-group-box-pinned-state-test.mjs +95 -0
  294. package/scripts/topo-group-count-test.mjs +6 -1
  295. package/scripts/topo-group-label-a11y-test.mjs +113 -0
  296. package/scripts/topo-group-label-count-inherit-test.mjs +99 -0
  297. package/scripts/topo-group-label-hover-test.mjs +119 -0
  298. package/scripts/topo-group-label-pin-spacing-test.mjs +136 -0
  299. package/scripts/topo-group-label-tint-test.mjs +99 -0
  300. package/scripts/topo-group-label-title-test.mjs +83 -0
  301. package/scripts/topo-group-pin-test.mjs +119 -0
  302. package/scripts/topo-group-pip-fadein-test.mjs +104 -0
  303. package/scripts/topo-group-pip-singletier-drop-test.mjs +131 -0
  304. package/scripts/topo-group-pip-tabular-test.mjs +95 -0
  305. package/scripts/topo-group-status-pips-test.mjs +103 -0
  306. package/scripts/topo-groupbox-fadein-test.mjs +95 -0
  307. package/scripts/topo-groupbox-hover-lift-test.mjs +127 -0
  308. package/scripts/topo-groupbox-hubcore-ease-test.mjs +106 -0
  309. package/scripts/topo-groupbox-live-test.mjs +100 -0
  310. package/scripts/topo-groupbox-march-busyness-test.mjs +155 -0
  311. package/scripts/topo-groupbox-test.mjs +4 -2
  312. package/scripts/topo-header-gap-test.mjs +94 -0
  313. package/scripts/topo-help-overlay-r109-test.mjs +67 -0
  314. package/scripts/topo-help-overlay-r118-test.mjs +69 -0
  315. package/scripts/topo-help-overlay-r123-test.mjs +69 -0
  316. package/scripts/topo-help-overlay-r134-test.mjs +74 -0
  317. package/scripts/topo-help-overlay-r137-test.mjs +81 -0
  318. package/scripts/topo-help-overlay-r141-test.mjs +86 -0
  319. package/scripts/topo-help-overlay-r153-test.mjs +85 -0
  320. package/scripts/topo-help-overlay-r59-test.mjs +67 -0
  321. package/scripts/topo-help-overlay-r65-test.mjs +64 -0
  322. package/scripts/topo-help-overlay-r70-test.mjs +63 -0
  323. package/scripts/topo-help-overlay-r78-test.mjs +59 -0
  324. package/scripts/topo-help-overlay-r81-test.mjs +58 -0
  325. package/scripts/topo-help-overlay-r87-test.mjs +64 -0
  326. package/scripts/topo-help-overlay-r91-test.mjs +65 -0
  327. package/scripts/topo-hot-tail-crossfade-test.mjs +117 -0
  328. package/scripts/topo-html-overlay-padding-unify-test.mjs +120 -0
  329. package/scripts/topo-hub-a11y-test.mjs +112 -0
  330. package/scripts/topo-hub-busyness-test.mjs +100 -0
  331. package/scripts/topo-hub-center-crossfade-test.mjs +124 -0
  332. package/scripts/topo-hub-click-fit-test.mjs +137 -0
  333. package/scripts/topo-hub-digit-scale-test.mjs +129 -0
  334. package/scripts/topo-hub-fadein-test.mjs +88 -0
  335. package/scripts/topo-hub-hover-lift-test.mjs +101 -0
  336. package/scripts/topo-hub-hover-ring-test.mjs +82 -0
  337. package/scripts/topo-hub-pip-theme-ease-test.mjs +116 -0
  338. package/scripts/topo-hub-spoke-ease-test.mjs +120 -0
  339. package/scripts/topo-hub-title-test.mjs +7 -2
  340. package/scripts/topo-hub-working-count-test.mjs +99 -0
  341. package/scripts/topo-ingroup-edge-test.mjs +103 -0
  342. package/scripts/topo-inner-radar-ring-retired-test.mjs +89 -0
  343. package/scripts/topo-kicker-color-test.mjs +93 -0
  344. package/scripts/topo-kicker-tracking-test.mjs +101 -0
  345. package/scripts/topo-kicker-weight-test.mjs +98 -0
  346. package/scripts/topo-label-card-theme-ease-test.mjs +85 -0
  347. package/scripts/topo-label-lift-test.mjs +5 -1
  348. package/scripts/topo-layout-hover-text-preview-test.mjs +101 -0
  349. package/scripts/topo-layout-switch-crossfade-test.mjs +126 -0
  350. package/scripts/topo-layout-toggle-border-unify-test.mjs +104 -0
  351. package/scripts/topo-layout-toggle-test.mjs +131 -0
  352. package/scripts/topo-layout-trailer-mr-test.mjs +82 -0
  353. package/scripts/topo-legend-compress-test.mjs +107 -0
  354. package/scripts/topo-legend-count-empty-test.mjs +126 -0
  355. package/scripts/topo-legend-count-tabular-parity-test.mjs +90 -0
  356. package/scripts/topo-legend-count-tabular-test.mjs +87 -0
  357. package/scripts/topo-legend-count-test.mjs +88 -0
  358. package/scripts/topo-legend-count-tier-fill-test.mjs +121 -0
  359. package/scripts/topo-legend-count-weight-test.mjs +86 -0
  360. package/scripts/topo-legend-header-symmetric-inset-test.mjs +112 -0
  361. package/scripts/topo-legend-hitbox-swatch-center-test.mjs +93 -0
  362. package/scripts/topo-legend-hover-test.mjs +113 -0
  363. package/scripts/topo-legend-offline-delimiter-test.mjs +84 -0
  364. package/scripts/topo-legend-offline-label-simplify-test.mjs +86 -0
  365. package/scripts/topo-legend-panel-count-weight-test.mjs +89 -0
  366. package/scripts/topo-legend-panel-header-test.mjs +83 -0
  367. package/scripts/topo-legend-pin-ring-fade-test.mjs +112 -0
  368. package/scripts/topo-legend-pin-test.mjs +128 -0
  369. package/scripts/topo-legend-row-hover-lift-test.mjs +109 -0
  370. package/scripts/topo-legend-row-labels-simplify-test.mjs +80 -0
  371. package/scripts/topo-legend-row-pin-spacing-test.mjs +124 -0
  372. package/scripts/topo-legend-row-tint-test.mjs +95 -0
  373. package/scripts/topo-legend-row-title-test.mjs +102 -0
  374. package/scripts/topo-legend-swatch-grow-test.mjs +116 -0
  375. package/scripts/topo-legend-swatch-radius-test.mjs +78 -0
  376. package/scripts/topo-minimap-a11y-test.mjs +101 -0
  377. package/scripts/topo-minimap-dot-transition-test.mjs +113 -0
  378. package/scripts/topo-minimap-radius-test.mjs +88 -0
  379. package/scripts/topo-minimap-rect-stroke-test.mjs +94 -0
  380. package/scripts/topo-minimap-viewport-smooth-test.mjs +124 -0
  381. package/scripts/topo-monogram-font-test.mjs +112 -0
  382. package/scripts/topo-monogram-stroke-test.mjs +101 -0
  383. package/scripts/topo-more-flows-letterspacing-test.mjs +111 -0
  384. package/scripts/topo-node-a11y-test.mjs +107 -0
  385. package/scripts/topo-node-alias-chat-pin-test.mjs +95 -0
  386. package/scripts/topo-node-hover-lift-test.mjs +85 -0
  387. package/scripts/topo-node-label-card-elevation-test.mjs +157 -0
  388. package/scripts/topo-node-label-card-stroke-test.mjs +135 -0
  389. package/scripts/topo-node-stroke-transition-test.mjs +103 -0
  390. package/scripts/topo-node-text-fill-transition-test.mjs +119 -0
  391. package/scripts/topo-node-title-peers-test.mjs +107 -0
  392. package/scripts/topo-node-title-test.mjs +101 -0
  393. package/scripts/topo-nodesize-active-hover-test.mjs +109 -0
  394. package/scripts/topo-nodesize-crossfade-test.mjs +141 -0
  395. package/scripts/topo-online-chip-nav-test.mjs +143 -0
  396. package/scripts/topo-orbit-particles-retired-test.mjs +91 -0
  397. package/scripts/topo-panel-count-unit-test.mjs +112 -0
  398. package/scripts/topo-panel-elevation-test.mjs +76 -0
  399. package/scripts/topo-panel-fadein-test.mjs +102 -0
  400. package/scripts/topo-panel-hot-tail-fade-test.mjs +132 -0
  401. package/scripts/topo-panel-hover-elevation-test.mjs +118 -0
  402. package/scripts/topo-panel-rx-test.mjs +90 -0
  403. package/scripts/topo-panel-theme-ease-test.mjs +85 -0
  404. package/scripts/topo-panel-title-fill-ease-test.mjs +91 -0
  405. package/scripts/topo-panel-title-tracking-test.mjs +78 -0
  406. package/scripts/topo-particle-stagger-test.mjs +82 -0
  407. package/scripts/topo-pin-intersection-color-ease-test.mjs +111 -0
  408. package/scripts/topo-pin-intersection-empty-test.mjs +129 -0
  409. package/scripts/topo-pin-intersection-tabular-test.mjs +96 -0
  410. package/scripts/topo-pin-intersection-test.mjs +121 -0
  411. package/scripts/topo-pin-intersection-warning-crossfade-test.mjs +107 -0
  412. package/scripts/topo-pin-mirror-transition-test.mjs +101 -0
  413. package/scripts/topo-pin-persistence-test.mjs +105 -0
  414. package/scripts/topo-prefix-opacity-test.mjs +107 -0
  415. package/scripts/topo-prepublish-guard-test.mjs +95 -0
  416. package/scripts/topo-pressure-hover-test.mjs +123 -0
  417. package/scripts/topo-pressure-pin-test.mjs +119 -0
  418. package/scripts/topo-pressure-seg-self-hover-test.mjs +126 -0
  419. package/scripts/topo-pressure-seg-tooltip-test.mjs +98 -0
  420. package/scripts/topo-pressure-seg-transition-test.mjs +107 -0
  421. package/scripts/topo-pulse-dot-crossfade-test.mjs +122 -0
  422. package/scripts/topo-pulse-dot-retired-test.mjs +86 -0
  423. package/scripts/topo-recent-panel-count-freshness-test.mjs +109 -0
  424. package/scripts/topo-recent-panel-count-test.mjs +72 -0
  425. package/scripts/topo-recent-panel-count-weight-test.mjs +91 -0
  426. package/scripts/topo-recent-panel-footer-breath-test.mjs +142 -0
  427. package/scripts/topo-recent-panel-hot-header-test.mjs +132 -0
  428. package/scripts/topo-recent-panel-hot-tabular-test.mjs +113 -0
  429. package/scripts/topo-recent-panel-more-crossfade-test.mjs +124 -0
  430. package/scripts/topo-recent-panel-more-cyan-hover-test.mjs +151 -0
  431. package/scripts/topo-recent-panel-more-nav-test.mjs +127 -0
  432. package/scripts/topo-recent-panel-more-test.mjs +106 -0
  433. package/scripts/topo-recent-panel-readability-bump-test.mjs +151 -0
  434. package/scripts/topo-recent-row-count-fill-test.mjs +129 -0
  435. package/scripts/topo-recent-row-count-weight-test.mjs +112 -0
  436. package/scripts/topo-recent-row-fadein-test.mjs +107 -0
  437. package/scripts/topo-recent-row-freshness-test.mjs +102 -0
  438. package/scripts/topo-recent-row-hot-test.mjs +110 -0
  439. package/scripts/topo-recent-row-hover-lift-test.mjs +128 -0
  440. package/scripts/topo-recent-row-hover-test.mjs +122 -0
  441. package/scripts/topo-recent-row-pin-spacing-test.mjs +137 -0
  442. package/scripts/topo-recent-row-pin-test.mjs +126 -0
  443. package/scripts/topo-recent-row-tint-test.mjs +91 -0
  444. package/scripts/topo-recent-row-title-test.mjs +112 -0
  445. package/scripts/topo-recent-row-ts-alpha-test.mjs +100 -0
  446. package/scripts/topo-recent-row-ts-tabular-test.mjs +108 -0
  447. package/scripts/topo-recent-row-ts-test.mjs +95 -0
  448. package/scripts/topo-recent-row-typography-test.mjs +119 -0
  449. package/scripts/topo-recent-signal-empty-hint-test.mjs +73 -0
  450. package/scripts/topo-reset-spin-test.mjs +120 -0
  451. package/scripts/topo-runtime-badge-grow-test.mjs +114 -0
  452. package/scripts/topo-spokes-retired-test.mjs +93 -0
  453. package/scripts/topo-starfield-density-test.mjs +89 -0
  454. package/scripts/topo-status-chip-hover-test.mjs +101 -0
  455. package/scripts/topo-status-chip-tooltip-test.mjs +95 -0
  456. package/scripts/topo-statusbar-chips-self-hover-test.mjs +177 -0
  457. package/scripts/topo-svg-focus-test.mjs +112 -0
  458. package/scripts/topo-sweep-busyness-test.mjs +94 -0
  459. package/scripts/topo-tabular-nums-sweep-test.mjs +93 -0
  460. package/scripts/topo-tier-guide-dashes-test.mjs +86 -0
  461. package/scripts/topo-tier-ring-fadein-test.mjs +107 -0
  462. package/scripts/topo-tier-ring-occupancy-test.mjs +87 -0
  463. package/scripts/topo-tier-ring-test.mjs +69 -0
  464. package/scripts/topo-tier-ring-tint-test.mjs +110 -0
  465. package/scripts/topo-tier-stagger-test.mjs +89 -0
  466. package/scripts/topo-title-block-tight-leading-test.mjs +95 -0
  467. package/scripts/topo-title-tracking-test.mjs +98 -0
  468. package/scripts/topo-titleblock-gap-test.mjs +86 -0
  469. package/scripts/topo-titleblock-margin-test.mjs +83 -0
  470. package/scripts/topo-toggle-inactive-cyan-hover-test.mjs +110 -0
  471. package/scripts/topo-top-rail-theme-ease-test.mjs +89 -0
  472. package/scripts/topo-vendor-chip-hover-test.mjs +111 -0
  473. package/scripts/topo-vendor-chip-self-hover-test.mjs +131 -0
  474. package/scripts/topo-vendor-chip-tabular-test.mjs +92 -0
  475. package/scripts/topo-vendor-chip-threshold-test.mjs +78 -0
  476. package/scripts/topo-vendor-chip-weight-test.mjs +87 -0
  477. package/scripts/topo-vendor-count-suffix-test.mjs +95 -0
  478. package/scripts/topo-vendor-letter-tooltip-test.mjs +92 -0
  479. package/scripts/topo-vendor-pill-test.mjs +125 -0
  480. package/scripts/topo-vendor-pin-test.mjs +125 -0
  481. package/scripts/topo-view-smooth-test.mjs +131 -0
  482. package/scripts/topo-watermark-tracking-test.mjs +99 -0
  483. package/scripts/topo-working-chip-pin-test.mjs +154 -0
  484. package/scripts/topo-working-halo-breath-retired-test.mjs +99 -0
  485. package/scripts/topo-wrapper-flow-arrow-theme-test.mjs +97 -0
  486. package/scripts/topo-wrapper-radius-test.mjs +73 -0
  487. package/scripts/topo-wrapper-shadow-theme-ease-test.mjs +89 -0
  488. package/.next/static/chunks/088ouqy7tekty.js +0 -2
  489. package/.next/static/chunks/0mqwn-l7wtcdo.js +0 -7
  490. package/.next/static/chunks/127kw7~wsnyu7.css +0 -2
  491. /package/.next/static/{23MxP0RBVA4BaOJ_HMYmM → ypixDJRds4g4TLoUdmrwN}/_buildManifest.js +0 -0
  492. /package/.next/static/{23MxP0RBVA4BaOJ_HMYmM → ypixDJRds4g4TLoUdmrwN}/_clientMiddlewareManifest.js +0 -0
  493. /package/.next/static/{23MxP0RBVA4BaOJ_HMYmM → ypixDJRds4g4TLoUdmrwN}/_ssgManifest.js +0 -0
@@ -0,0 +1,105 @@
1
+ /* Round 119 verification: when a recent-signal row is pinned (R116),
2
+ * the chip row renders a 4th "filter: from→to · N" pill matching
3
+ * the R64 / R89 pattern for status / group / vendor pins. Closes the
4
+ * pill-pattern gap left after R116.
5
+ *
6
+ * Verifies:
7
+ * - Before pin: no edge pill
8
+ * - Click row → pill shows correct from→to and count
9
+ * - Click pill body → clears
10
+ * - × button also clears
11
+ * - data-filter-match-aliases lists the two endpoints
12
+ */
13
+ import { chromium } from 'playwright';
14
+ import { readFileSync } from 'node:fs';
15
+
16
+ const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
17
+ const browser = await chromium.launch({ headless: true });
18
+
19
+ const ctx = await browser.newContext({ viewport: { width: 1400, 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
+
25
+ const fresh = new Date(Date.now() - 60 * 1000).toISOString();
26
+ await ctx.route('**/api/hub/status*', async (route) => {
27
+ const r = await route.fetch();
28
+ const b = await r.json();
29
+ const nid = (b.sessions || [])[0]?.network_id || 'default';
30
+ const mk = (alias) => ({
31
+ alias, status: 'idle', model: 'claude-opus-4', runtime: 'cli-claude-code',
32
+ network_id: nid, project_dir: null,
33
+ created_at: fresh, updated_at: fresh, last_seen_at: fresh,
34
+ });
35
+ await route.fulfill({ response: r, json: { ...b, sessions: [mk('alpha'), mk('beta'), mk('gamma')] } });
36
+ });
37
+
38
+ const now = Date.now();
39
+ const mkMsg = (id, from_alias, to_alias, ageMs) => ({
40
+ id, from_alias, to_alias, content: 'hi', network_id: 'default',
41
+ created_at: new Date(now - ageMs).toISOString(),
42
+ });
43
+ await ctx.route('**/api/hub/messages*', (route) => route.fulfill({ json: { messages: [
44
+ mkMsg('m1', 'alpha', 'beta', 30 * 1000),
45
+ mkMsg('m2', 'alpha', 'beta', 40 * 1000),
46
+ mkMsg('m3', 'alpha', 'beta', 50 * 1000),
47
+ ] } }));
48
+ await ctx.route('**/api/hub/tasks*', (route) => route.fulfill({ json: { tasks: [] } }));
49
+ const page = await ctx.newPage();
50
+ await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
51
+ await page.waitForFunction(() => document.querySelectorAll('g[data-node]').length === 3, { timeout: 30000 });
52
+ await page.waitForSelector('[data-recent-row]', { timeout: 10000 });
53
+ await page.waitForTimeout(400);
54
+
55
+ const readPill = () => page.evaluate(() => {
56
+ const p = document.querySelector('[data-active-filter="edge"]');
57
+ if (!p) return null;
58
+ return {
59
+ text: (p.textContent || '').trim(),
60
+ count: p.getAttribute('data-filter-match-count'),
61
+ aliases: p.getAttribute('data-filter-match-aliases') || '',
62
+ title: p.getAttribute('title') || '',
63
+ };
64
+ });
65
+
66
+ const before = await readPill();
67
+
68
+ // Click row to pin.
69
+ await page.locator('[data-recent-row="alpha->beta"]').click();
70
+ await page.mouse.move(10, 10);
71
+ await page.waitForTimeout(300);
72
+ const afterPin = await readPill();
73
+
74
+ // Click pill body to clear.
75
+ await page.locator('[data-active-filter="edge"]').click();
76
+ await page.mouse.move(10, 10);
77
+ await page.waitForTimeout(300);
78
+ const afterBodyClear = await readPill();
79
+
80
+ // Pin again, then click × button.
81
+ await page.locator('[data-recent-row="alpha->beta"]').click();
82
+ await page.mouse.move(10, 10);
83
+ await page.waitForTimeout(300);
84
+ await page.locator('[data-active-filter="edge"] button').click();
85
+ await page.waitForTimeout(300);
86
+ const afterXClear = await readPill();
87
+
88
+ await browser.close();
89
+
90
+ const results = {
91
+ before_noPill: before === null,
92
+ pin_pillRendered: afterPin !== null,
93
+ pin_textContainsArrow: /alpha→beta/.test(afterPin?.text || ''),
94
+ pin_count3: afterPin?.count === '3',
95
+ pin_aliasesMatch: afterPin?.aliases === 'alpha,beta',
96
+ pin_titleHasFromTo: /alpha → beta \(3 msgs\)/.test(afterPin?.title || ''),
97
+ bodyClear_pillGone: afterBodyClear === null,
98
+ xClear_pillGone: afterXClear === null,
99
+ };
100
+ const ok = Object.values(results).every(Boolean);
101
+ console.log(`${ok ? '✅' : '❌'} edge pill:`, JSON.stringify(results),
102
+ `\n afterPin=`, afterPin,
103
+ `\n afterBodyClear=`, afterBodyClear,
104
+ `\n afterXClear=`, afterXClear);
105
+ process.exit(ok ? 0 : 1);
@@ -0,0 +1,119 @@
1
+ /* Round 279 verification: arrival ping + dispatch pulse SMIL retired
2
+ * (R75 + R76 + R228 + R231 + R252 family) — 减法 cut #5.
3
+ *
4
+ * Per active flow edge the pre-R279 SMIL family was:
5
+ * particle (R50 animateMotion along curve path) ← KEPT
6
+ * arrival ping (R75 circle + r/opacity animate) ← RETIRED
7
+ * dispatch pulse (R76 circle + r/opacity animate) ← RETIRED
8
+ *
9
+ * For a 5-edge fleet that's 5×3 = 15 simultaneous SMIL on edges
10
+ * alone, pre-R279. The particle (a moving dot along the path) is the
11
+ * primary "data flowing from A → B" visual signal; the ping + pulse
12
+ * are secondary "arrival/dispatch confirmation" that the moving
13
+ * particle already conveys. R279 culls ping + pulse, keeps particle.
14
+ *
15
+ * Net: -10 SMIL animations for a 5-edge fleet. Combined with R276
16
+ * (-4 orbit) and R278 (-4 working halo), the canvas motion budget
17
+ * is now: 1 hub breath + N particles per active edge, that's it.
18
+ *
19
+ * Test scope:
20
+ * 1. No element matches `[data-arrival-ping]` (R75 retired).
21
+ * 2. No element matches `[data-dispatch-pulse]` (R76 retired).
22
+ * 3. Particles still present (`[data-edge-particle]` or equivalent).
23
+ * 4. R275 freshness chip absent (regression).
24
+ * 5. R276 orbit absent (regression).
25
+ * 6. R277 legend height 88 (regression).
26
+ * 7. R278 working halo <animate> count 0 (regression).
27
+ */
28
+ import { chromium } from 'playwright';
29
+ import { readFileSync } from 'node:fs';
30
+
31
+ const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
32
+ const browser = await chromium.launch({ headless: true });
33
+ const ctx = await browser.newContext({ viewport: { width: 1500, height: 1500 } });
34
+ await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
35
+ await ctx.addInitScript(() => {
36
+ try { localStorage.setItem('anet-theme', 'cyber'); sessionStorage.setItem('anet_v3_auth', '1'); } catch {}
37
+ });
38
+ const fresh = new Date(Date.now() - 60 * 1000).toISOString();
39
+ await ctx.route('**/api/hub/status*', async (route) => {
40
+ const r = await route.fetch();
41
+ const b = await r.json();
42
+ const nid = (b.sessions || [])[0]?.network_id || 'default';
43
+ const mk = (alias) => ({
44
+ alias, status: 'working', model: 'claude-opus-4', runtime: 'claude-code-cli',
45
+ network_id: nid, project_dir: null,
46
+ created_at: fresh, updated_at: fresh, last_seen_at: fresh,
47
+ });
48
+ await route.fulfill({ response: r, json: { ...b, sessions: [
49
+ mk('alpha'), mk('beta'), mk('gamma'), mk('delta'),
50
+ ] } });
51
+ });
52
+ // 5 distinct flow pairs so particles + (formerly) ping/pulse mount
53
+ // on multiple edges with link.count >= 3 (the dispatch-pulse gate
54
+ // pre-R279).
55
+ const now = Date.now();
56
+ const msgs = [];
57
+ for (let pair = 0; pair < 5; pair++) {
58
+ for (let i = 0; i < 5; i++) {
59
+ const from = ['alpha','beta','gamma','delta'][pair % 4];
60
+ const to = ['beta','gamma','delta','alpha'][pair % 4];
61
+ msgs.push({
62
+ id: `m${pair}-${i}`, from_alias: from, to_alias: to, content: 'hi',
63
+ network_id: 'default',
64
+ created_at: new Date(now - (1000 + pair * 200 + i * 50)).toISOString(),
65
+ });
66
+ }
67
+ }
68
+ await ctx.route('**/api/hub/messages*', (r) => r.fulfill({ json: { messages: msgs } }));
69
+ await ctx.route('**/api/hub/tasks*', (r) => r.fulfill({ json: { tasks: [] } }));
70
+
71
+ const page = await ctx.newPage();
72
+ await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
73
+ await page.waitForFunction(() => document.querySelectorAll('g[data-node]').length === 4, { timeout: 30000 });
74
+ await page.waitForSelector('[data-topo-panel="legend"]', { timeout: 10000 });
75
+ await page.waitForSelector('[data-edge-particle]', { timeout: 10000, state: 'attached' });
76
+ await page.waitForTimeout(300);
77
+
78
+ const probe = await page.evaluate(() => {
79
+ const ping = document.querySelectorAll('[data-arrival-ping]');
80
+ const pulse = document.querySelectorAll('[data-dispatch-pulse]');
81
+ const particle = document.querySelectorAll('[data-edge-particle]');
82
+ const freshnessChip = document.querySelector('[data-freshness-chip]');
83
+ const orbits = document.querySelectorAll('[data-topo-orbit-bucket]');
84
+ const legendG = document.querySelector('[data-topo-panel="legend"]');
85
+ const legendH = legendG?.querySelector('rect')?.getAttribute('height') ?? null;
86
+ const halos = document.querySelectorAll('[data-node-halo-breath="on"]');
87
+ let haloAnimateCount = 0;
88
+ halos.forEach((h) => { haloAnimateCount += h.querySelectorAll('animate').length; });
89
+ return {
90
+ pingCount: ping.length,
91
+ pulseCount: pulse.length,
92
+ particleCount: particle.length,
93
+ freshnessPresent: freshnessChip !== null,
94
+ orbitCount: orbits.length,
95
+ legendHeight: legendH,
96
+ haloAnimateCount,
97
+ };
98
+ });
99
+ await browser.close();
100
+
101
+ const results = {
102
+ arrival_ping_absent: probe.pingCount === 0,
103
+ dispatch_pulse_absent: probe.pulseCount === 0,
104
+ particles_still_present: probe.particleCount > 0,
105
+ r275_freshness_absent: probe.freshnessPresent === false,
106
+ r276_orbit_absent: probe.orbitCount === 0,
107
+ r277_legend_height_88: probe.legendHeight === '88',
108
+ r278_halo_animate_count_zero: probe.haloAnimateCount === 0,
109
+ };
110
+ const ok = Object.values(results).every(Boolean);
111
+ console.log(`${ok ? '✅' : '❌'} edge ping/pulse retired:`, JSON.stringify(results),
112
+ '\n arrival ping count (expect 0):', probe.pingCount,
113
+ '\n dispatch pulse count (expect 0):', probe.pulseCount,
114
+ '\n particle count (expect > 0):', probe.particleCount,
115
+ '\n freshness absent:', !probe.freshnessPresent,
116
+ '\n orbit count (expect 0):', probe.orbitCount,
117
+ '\n legend height:', probe.legendHeight,
118
+ '\n halo animate count (expect 0):', probe.haloAnimateCount);
119
+ process.exit(ok ? 0 : 1);
@@ -0,0 +1,100 @@
1
+ /* Round 245 verification: edge surface (visible flow path + flow
2
+ * rail dashed underline) picks up stroke-color transitions so
3
+ * theme toggle eases instead of snapping.
4
+ *
5
+ * Pre-R245:
6
+ * - [data-edge-visible]: transition = 'opacity 300ms ease-out,
7
+ * stroke-width 300ms ease-out' (R166)
8
+ * - [data-edge-flow-rail]: Tailwind className 'transition-opacity
9
+ * duration-300' (opacity only, no stroke)
10
+ *
11
+ * Post-R245:
12
+ * - [data-edge-visible]: transition list adds 'stroke 300ms ease-
13
+ * out' alongside the existing two
14
+ * - [data-edge-flow-rail]: inline style with both 'opacity' and
15
+ * 'stroke' at 300ms ease-out; Tailwind className dropped
16
+ *
17
+ * Scenario: 4 working agents + 5-msg alpha→beta flow → at least
18
+ * one visible flow + flow-rail pair.
19
+ */
20
+ import { chromium } from 'playwright';
21
+ import { readFileSync } from 'node:fs';
22
+
23
+ const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
24
+ const browser = await chromium.launch({ headless: true });
25
+ const ctx = await browser.newContext({ viewport: { width: 1500, height: 1500 } });
26
+ await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
27
+ await ctx.addInitScript(() => {
28
+ try { localStorage.setItem('anet-theme', 'cyber'); sessionStorage.setItem('anet_v3_auth', '1'); } catch {}
29
+ });
30
+ const fresh = new Date(Date.now() - 60 * 1000).toISOString();
31
+ await ctx.route('**/api/hub/status*', async (route) => {
32
+ const r = await route.fetch();
33
+ const b = await r.json();
34
+ const nid = (b.sessions || [])[0]?.network_id || 'default';
35
+ const mk = (alias) => ({
36
+ alias, status: 'working', model: 'claude-opus-4', runtime: 'claude-code-cli',
37
+ network_id: nid, project_dir: null,
38
+ created_at: fresh, updated_at: fresh, last_seen_at: fresh,
39
+ });
40
+ await route.fulfill({ response: r, json: { ...b, sessions: [
41
+ mk('alpha'), mk('beta'), mk('gamma'), mk('delta'),
42
+ ] } });
43
+ });
44
+ const now = Date.now();
45
+ const msgs = [];
46
+ for (let i = 0; i < 5; i++) {
47
+ msgs.push({
48
+ id: `m${i}`, from_alias: 'alpha', to_alias: 'beta', content: 'hi',
49
+ network_id: 'default', created_at: new Date(now - (1000 + i * 50)).toISOString(),
50
+ });
51
+ }
52
+ await ctx.route('**/api/hub/messages*', (r2) => r2.fulfill({ json: { messages: msgs } }));
53
+ await ctx.route('**/api/hub/tasks*', (r2) => r2.fulfill({ json: { tasks: [] } }));
54
+
55
+ const page = await ctx.newPage();
56
+ await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
57
+ await page.waitForFunction(() => document.querySelectorAll('g[data-node]').length === 4, { timeout: 30000 });
58
+ await page.waitForSelector('[data-edge-visible]', { timeout: 10000, state: 'attached' });
59
+ await page.waitForSelector('[data-edge-flow-rail]', { timeout: 10000, state: 'attached' });
60
+ await page.waitForTimeout(300);
61
+
62
+ const out = await page.evaluate(() => {
63
+ const probe = (sel) => {
64
+ const el = document.querySelector(sel);
65
+ if (!el) return null;
66
+ return {
67
+ transition: getComputedStyle(el).transition,
68
+ className: el.getAttribute('class') || '',
69
+ stroke: el.getAttribute('stroke'),
70
+ };
71
+ };
72
+ return {
73
+ visible: probe('[data-edge-visible]'),
74
+ rail: probe('[data-edge-flow-rail]'),
75
+ };
76
+ });
77
+ await browser.close();
78
+
79
+ const hasProp = (s, prop) => new RegExp(`${prop}\\s+(?:300ms|0\\.3s)`).test(s || '');
80
+
81
+ const results = {
82
+ visible_present: out.visible !== null,
83
+ visible_has_opacity_300ms: hasProp(out.visible?.transition, 'opacity'),
84
+ visible_has_stroke_width_300ms: hasProp(out.visible?.transition, 'stroke-width'),
85
+ visible_has_stroke_300ms: hasProp(out.visible?.transition, 'stroke'),
86
+
87
+ rail_present: out.rail !== null,
88
+ rail_has_opacity_300ms: hasProp(out.rail?.transition, 'opacity'),
89
+ rail_has_stroke_300ms: hasProp(out.rail?.transition, 'stroke'),
90
+ // Tailwind 'transition-opacity duration-300' className dropped
91
+ // (the inline transition list replaces it; Tailwind would
92
+ // otherwise OVERRIDE the inline stroke transition with its
93
+ // opacity-only declaration)
94
+ rail_no_tailwind_class: !/transition-opacity/.test(out.rail?.className || ''),
95
+ };
96
+ const ok = Object.values(results).every(Boolean);
97
+ console.log(`${ok ? '✅' : '❌'} edge stroke ease:`, JSON.stringify(results),
98
+ '\n visible:', out.visible,
99
+ '\n rail: ', out.rail);
100
+ process.exit(ok ? 0 : 1);
@@ -0,0 +1,132 @@
1
+ /* Round 166 verification: visible flow edge path picks up
2
+ * stroke-width transition.
3
+ *
4
+ * R50 thickens hovered edges to 1.4× (renderWidth = width * 1.4)
5
+ * but pre-R166 only opacity transitioned — width snapped. R166
6
+ * adds stroke-width to the transition list so the edge thickens
7
+ * smoothly on hover, pairing with R164 edge-badge r-lift for
8
+ * coordinated 300ms ease-out across the edge surface.
9
+ *
10
+ * Test:
11
+ * 1. Mock 4 sessions + 1 flow alpha→beta
12
+ * 2. Probe visible path before hover → strokeWidth=base
13
+ * 3. Probe transition string includes both opacity and
14
+ * stroke-width
15
+ * 4. Hover edge hitbox → wait 350ms (past transition)
16
+ * 5. Probe strokeWidth → should be ≈ base * 1.4
17
+ * 6. mouse away → strokeWidth back to base
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
+
25
+ const ctx = await browser.newContext({ viewport: { width: 1500, height: 1500 } });
26
+ await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
27
+ await ctx.addInitScript(() => {
28
+ try { localStorage.setItem('anet-theme', 'cyber'); sessionStorage.setItem('anet_v3_auth', '1'); } catch {}
29
+ });
30
+
31
+ const fresh = new Date(Date.now() - 60 * 1000).toISOString();
32
+ await ctx.route('**/api/hub/status*', async (route) => {
33
+ const r = await route.fetch();
34
+ const b = await r.json();
35
+ const nid = (b.sessions || [])[0]?.network_id || 'default';
36
+ const mk = (alias) => ({
37
+ alias, status: 'working', model: 'claude-opus-4', runtime: 'cli-claude-code',
38
+ network_id: nid, project_dir: null,
39
+ created_at: fresh, updated_at: fresh, last_seen_at: fresh,
40
+ });
41
+ // 4 sessions so alpha + beta are 90° apart (not 180° — that
42
+ // would put their edge midpoint on the hub, where the hub
43
+ // <g> intercepts pointer events). gamma + delta are filler.
44
+ await route.fulfill({ response: r, json: { ...b, sessions: [
45
+ mk('alpha'), mk('beta'), mk('gamma'), mk('delta'),
46
+ ] } });
47
+ });
48
+
49
+ const now = Date.now();
50
+ // 4 msgs so:
51
+ // - width = Math.min(2+4, 7) = 6
52
+ // - hover renderWidth = Math.min(6*1.4, 10) = 8.4
53
+ // AND the edge midpoint count badge renders (R100 threshold
54
+ // count >= 3) so we can use it as the hover surface. The
55
+ // visible path has pointerEvents:none; the R48 hitbox is a
56
+ // thin stroke that Playwright's .hover() can't reliably land
57
+ // on. The badge is a r=9 circle with pointerEvents:all and
58
+ // propagates hover to hoveredEdgeKey (R122) — most reliable
59
+ // target for triggering the visible-path transition.
60
+ const msgs = [];
61
+ for (let i = 0; i < 4; i++) {
62
+ msgs.push({ id: `m${i}`, from_alias: 'alpha', to_alias: 'beta', content: 'hi',
63
+ network_id: 'default', created_at: new Date(now - (10000 + i * 500)).toISOString() });
64
+ }
65
+ await ctx.route('**/api/hub/messages*', (route) => route.fulfill({ json: { messages: msgs } }));
66
+ await ctx.route('**/api/hub/tasks*', (route) => route.fulfill({ json: { tasks: [] } }));
67
+
68
+ const page = await ctx.newPage();
69
+ await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
70
+ await page.waitForFunction(() => document.querySelectorAll('g[data-node]').length === 4, { timeout: 30000 });
71
+ await page.waitForSelector('[data-edge-visible]', { timeout: 10000 });
72
+ await page.waitForTimeout(400);
73
+
74
+ const idle = await page.evaluate(() => {
75
+ const el = document.querySelector('[data-edge-visible]');
76
+ if (!el) return null;
77
+ return {
78
+ strokeWidth: parseFloat(el.getAttribute('stroke-width')),
79
+ inlineTransition: el.style.transition || '',
80
+ computedTransition: getComputedStyle(el).transition || '',
81
+ };
82
+ });
83
+
84
+ // Hover the edge midpoint badge (R164 r=9 circle, pointerEvents:all,
85
+ // propagates to hoveredEdgeKey via R122). The visible path has
86
+ // pointerEvents:none; the R48 hitbox is a thin stroke that
87
+ // Playwright .hover() can't reliably land on.
88
+ await page.locator('[data-edge-count-badge]').hover();
89
+ // Wait for transition to settle.
90
+ await page.waitForTimeout(400);
91
+ const hovered = await page.evaluate(() => {
92
+ const el = document.querySelector('[data-edge-visible]');
93
+ if (!el) return null;
94
+ return {
95
+ strokeWidth: parseFloat(el.getAttribute('stroke-width')),
96
+ };
97
+ });
98
+
99
+ // Move cursor away
100
+ await page.mouse.move(10, 10);
101
+ await page.waitForTimeout(400);
102
+ const idleAgain = await page.evaluate(() => {
103
+ const el = document.querySelector('[data-edge-visible]');
104
+ if (!el) return null;
105
+ return {
106
+ strokeWidth: parseFloat(el.getAttribute('stroke-width')),
107
+ };
108
+ });
109
+
110
+ await browser.close();
111
+
112
+ const hasOpacity = (idle?.inlineTransition || '').includes('opacity 300ms') ||
113
+ /opacity\s+0\.3s|opacity\s+300ms/.test(idle?.computedTransition || '');
114
+ const hasStrokeWidth = (idle?.inlineTransition || '').includes('stroke-width 300ms') ||
115
+ /stroke-width\s+0\.3s|stroke-width\s+300ms/.test(idle?.computedTransition || '');
116
+
117
+ // Expected: width=Math.min(2+4, 7)=6. Hover renderWidth=Math.min(6*1.4, 10)=8.4.
118
+ const results = {
119
+ edge_found: idle !== null,
120
+ has_opacity_transition: hasOpacity,
121
+ has_stroke_width_transition: hasStrokeWidth,
122
+ idle_width_6: idle && Math.abs(idle.strokeWidth - 6) < 0.05,
123
+ hover_width_8p4: hovered && Math.abs(hovered.strokeWidth - 8.4) < 0.1,
124
+ hover_width_thicker: hovered && idle && hovered.strokeWidth > idle.strokeWidth,
125
+ idle_again_width_6: idleAgain && Math.abs(idleAgain.strokeWidth - 6) < 0.05,
126
+ };
127
+ const ok = Object.values(results).every(Boolean);
128
+ console.log(`${ok ? '✅' : '❌'} edge stroke transition:`, JSON.stringify(results),
129
+ `\n idle =`, idle,
130
+ `\n hovered =`, hovered,
131
+ `\n idleAgain =`, idleAgain);
132
+ process.exit(ok ? 0 : 1);
@@ -0,0 +1,84 @@
1
+ /* Round 302 verification: recent-signal panel empty-state hint
2
+ * ('no flow yet') gains letterSpacing="0.2" for editorial parity
3
+ * with R301 panel titles (0.3) + R285 kicker tracking-widest +
4
+ * R289 watermark letterSpacing.
5
+ *
6
+ * Contract:
7
+ * - [data-recent-signal-empty] attr letter-spacing === '0.2'.
8
+ * - Text content still 'no flow yet'.
9
+ * - opacity 0.65 + fontStyle italic preserved.
10
+ * - R301 panel-title letter-spacings (0.3) still in place.
11
+ * - R300 kicker font-medium + R295 swatch r=6 + R294 pulse absent
12
+ * 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
+ await route.fulfill({ response: r, json: { ...b, sessions: [
35
+ mk('alpha', 'claude-opus-4'),
36
+ mk('beta', 'gpt-4o'),
37
+ ] } });
38
+ });
39
+ // Empty messages → "no flow yet" hint visible.
40
+ await ctx.route('**/api/hub/messages*', (r) => r.fulfill({ json: { messages: [] } }));
41
+ await ctx.route('**/api/hub/tasks*', (r) => r.fulfill({ json: { tasks: [] } }));
42
+
43
+ const page = await ctx.newPage();
44
+ await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
45
+ await page.waitForSelector('[data-recent-signal-empty]', { timeout: 15000 });
46
+ await page.waitForTimeout(300);
47
+
48
+ const probe = await page.evaluate(() => {
49
+ const empty = document.querySelector('[data-recent-signal-empty]');
50
+ const recentTitle = document.querySelector('[data-recent-panel-title]');
51
+ const legendTitle = document.querySelector('[data-legend-panel-title]');
52
+ const kicker = document.querySelector('[data-topo-section-kicker]');
53
+ const swatch = document.querySelector('[data-legend-swatch="working"]');
54
+ return {
55
+ emptyLs: empty?.getAttribute('letter-spacing') ?? null,
56
+ emptyText: empty?.textContent?.trim() ?? null,
57
+ emptyOpacity: empty?.getAttribute('opacity') ?? null,
58
+ emptyStyle: empty?.getAttribute('font-style') ?? null,
59
+ recentTitleLs: recentTitle?.getAttribute('letter-spacing') ?? null,
60
+ legendTitleLs: legendTitle?.getAttribute('letter-spacing') ?? null,
61
+ kickerFw: kicker ? getComputedStyle(kicker).fontWeight : null,
62
+ swatchR: swatch?.getAttribute('r') ?? null,
63
+ pulseCount: document.querySelectorAll('[data-pulse-wrapper]').length,
64
+ };
65
+ });
66
+ await browser.close();
67
+
68
+ const results = {
69
+ empty_hint_ls_0_2: probe.emptyLs === '0.2',
70
+ empty_hint_text_kept: (probe.emptyText || '').startsWith('no flow yet'),
71
+ empty_opacity_0_65: String(probe.emptyOpacity) === '0.65',
72
+ empty_italic_kept: probe.emptyStyle === 'italic',
73
+ r301_recent_title_ls: probe.recentTitleLs === '0.3',
74
+ r301_legend_title_ls: probe.legendTitleLs === '0.3',
75
+ r300_kicker_fw_500: String(probe.kickerFw) === '500',
76
+ r295_swatch_r_6: probe.swatchR === '6',
77
+ r294_pulse_absent: probe.pulseCount === 0,
78
+ };
79
+ const ok = Object.values(results).every(Boolean);
80
+ console.log(`${ok ? '✅' : '❌'} empty-hint tracking:`, JSON.stringify(results),
81
+ '\n empty hint letter-spacing:', probe.emptyLs,
82
+ '\n empty hint text:', JSON.stringify(probe.emptyText),
83
+ '\n R301 panel titles ls:', probe.recentTitleLs, '/', probe.legendTitleLs);
84
+ process.exit(ok ? 0 : 1);