@sleep2agi/agent-network-dashboard 0.4.6-preview.28 → 0.4.6-preview.281

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 (460) hide show
  1. package/.next/BUILD_ID +1 -1
  2. package/.next/build-manifest.json +3 -3
  3. package/.next/diagnostics/route-bundle-stats.json +41 -41
  4. package/.next/fallback-build-manifest.json +3 -3
  5. package/.next/prerender-manifest.json +3 -3
  6. package/.next/server/app/_global-error.html +1 -1
  7. package/.next/server/app/_global-error.rsc +1 -1
  8. package/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  9. package/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  10. package/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  11. package/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  12. package/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  13. package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  14. package/.next/server/app/_not-found.html +2 -2
  15. package/.next/server/app/_not-found.rsc +12 -12
  16. package/.next/server/app/_not-found.segments/_full.segment.rsc +12 -12
  17. package/.next/server/app/_not-found.segments/_head.segment.rsc +4 -4
  18. package/.next/server/app/_not-found.segments/_index.segment.rsc +7 -7
  19. package/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +2 -2
  20. package/.next/server/app/_not-found.segments/_not-found.segment.rsc +3 -3
  21. package/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  22. package/.next/server/app/admin/page_client-reference-manifest.js +1 -1
  23. package/.next/server/app/admin.html +2 -2
  24. package/.next/server/app/admin.rsc +14 -14
  25. package/.next/server/app/admin.segments/_full.segment.rsc +14 -14
  26. package/.next/server/app/admin.segments/_head.segment.rsc +4 -4
  27. package/.next/server/app/admin.segments/_index.segment.rsc +7 -7
  28. package/.next/server/app/admin.segments/_tree.segment.rsc +2 -2
  29. package/.next/server/app/admin.segments/admin/__PAGE__.segment.rsc +4 -4
  30. package/.next/server/app/admin.segments/admin.segment.rsc +3 -3
  31. package/.next/server/app/index.html +2 -2
  32. package/.next/server/app/index.rsc +14 -14
  33. package/.next/server/app/index.segments/__PAGE__.segment.rsc +4 -4
  34. package/.next/server/app/index.segments/_full.segment.rsc +14 -14
  35. package/.next/server/app/index.segments/_head.segment.rsc +4 -4
  36. package/.next/server/app/index.segments/_index.segment.rsc +7 -7
  37. package/.next/server/app/index.segments/_tree.segment.rsc +2 -2
  38. package/.next/server/app/login/page_client-reference-manifest.js +1 -1
  39. package/.next/server/app/login.html +2 -2
  40. package/.next/server/app/login.rsc +14 -14
  41. package/.next/server/app/login.segments/_full.segment.rsc +14 -14
  42. package/.next/server/app/login.segments/_head.segment.rsc +4 -4
  43. package/.next/server/app/login.segments/_index.segment.rsc +7 -7
  44. package/.next/server/app/login.segments/_tree.segment.rsc +2 -2
  45. package/.next/server/app/login.segments/login/__PAGE__.segment.rsc +4 -4
  46. package/.next/server/app/login.segments/login.segment.rsc +3 -3
  47. package/.next/server/app/logs/page_client-reference-manifest.js +1 -1
  48. package/.next/server/app/logs.html +2 -2
  49. package/.next/server/app/logs.rsc +14 -14
  50. package/.next/server/app/logs.segments/_full.segment.rsc +14 -14
  51. package/.next/server/app/logs.segments/_head.segment.rsc +4 -4
  52. package/.next/server/app/logs.segments/_index.segment.rsc +7 -7
  53. package/.next/server/app/logs.segments/_tree.segment.rsc +2 -2
  54. package/.next/server/app/logs.segments/logs/__PAGE__.segment.rsc +4 -4
  55. package/.next/server/app/logs.segments/logs.segment.rsc +3 -3
  56. package/.next/server/app/messages/page_client-reference-manifest.js +1 -1
  57. package/.next/server/app/messages.html +2 -2
  58. package/.next/server/app/messages.rsc +14 -14
  59. package/.next/server/app/messages.segments/_full.segment.rsc +14 -14
  60. package/.next/server/app/messages.segments/_head.segment.rsc +4 -4
  61. package/.next/server/app/messages.segments/_index.segment.rsc +7 -7
  62. package/.next/server/app/messages.segments/_tree.segment.rsc +2 -2
  63. package/.next/server/app/messages.segments/messages/__PAGE__.segment.rsc +4 -4
  64. package/.next/server/app/messages.segments/messages.segment.rsc +3 -3
  65. package/.next/server/app/node/page_client-reference-manifest.js +1 -1
  66. package/.next/server/app/node.html +2 -2
  67. package/.next/server/app/node.rsc +14 -14
  68. package/.next/server/app/node.segments/_full.segment.rsc +14 -14
  69. package/.next/server/app/node.segments/_head.segment.rsc +4 -4
  70. package/.next/server/app/node.segments/_index.segment.rsc +7 -7
  71. package/.next/server/app/node.segments/_tree.segment.rsc +2 -2
  72. package/.next/server/app/node.segments/node/__PAGE__.segment.rsc +4 -4
  73. package/.next/server/app/node.segments/node.segment.rsc +3 -3
  74. package/.next/server/app/nodes/page_client-reference-manifest.js +1 -1
  75. package/.next/server/app/nodes.html +2 -2
  76. package/.next/server/app/nodes.rsc +14 -14
  77. package/.next/server/app/nodes.segments/_full.segment.rsc +14 -14
  78. package/.next/server/app/nodes.segments/_head.segment.rsc +4 -4
  79. package/.next/server/app/nodes.segments/_index.segment.rsc +7 -7
  80. package/.next/server/app/nodes.segments/_tree.segment.rsc +2 -2
  81. package/.next/server/app/nodes.segments/nodes/__PAGE__.segment.rsc +4 -4
  82. package/.next/server/app/nodes.segments/nodes.segment.rsc +3 -3
  83. package/.next/server/app/page_client-reference-manifest.js +1 -1
  84. package/.next/server/app/server-logs/page_client-reference-manifest.js +1 -1
  85. package/.next/server/app/server-logs.html +2 -2
  86. package/.next/server/app/server-logs.rsc +14 -14
  87. package/.next/server/app/server-logs.segments/_full.segment.rsc +14 -14
  88. package/.next/server/app/server-logs.segments/_head.segment.rsc +4 -4
  89. package/.next/server/app/server-logs.segments/_index.segment.rsc +7 -7
  90. package/.next/server/app/server-logs.segments/_tree.segment.rsc +2 -2
  91. package/.next/server/app/server-logs.segments/server-logs/__PAGE__.segment.rsc +4 -4
  92. package/.next/server/app/server-logs.segments/server-logs.segment.rsc +3 -3
  93. package/.next/server/app/settings/networks/page_client-reference-manifest.js +1 -1
  94. package/.next/server/app/settings/networks.html +2 -2
  95. package/.next/server/app/settings/networks.rsc +14 -14
  96. package/.next/server/app/settings/networks.segments/_full.segment.rsc +14 -14
  97. package/.next/server/app/settings/networks.segments/_head.segment.rsc +4 -4
  98. package/.next/server/app/settings/networks.segments/_index.segment.rsc +7 -7
  99. package/.next/server/app/settings/networks.segments/_tree.segment.rsc +2 -2
  100. package/.next/server/app/settings/networks.segments/settings/networks/__PAGE__.segment.rsc +4 -4
  101. package/.next/server/app/settings/networks.segments/settings/networks.segment.rsc +3 -3
  102. package/.next/server/app/settings/networks.segments/settings.segment.rsc +3 -3
  103. package/.next/server/app/settings/page_client-reference-manifest.js +1 -1
  104. package/.next/server/app/settings/tokens/page_client-reference-manifest.js +1 -1
  105. package/.next/server/app/settings/tokens.html +2 -2
  106. package/.next/server/app/settings/tokens.rsc +14 -14
  107. package/.next/server/app/settings/tokens.segments/_full.segment.rsc +14 -14
  108. package/.next/server/app/settings/tokens.segments/_head.segment.rsc +4 -4
  109. package/.next/server/app/settings/tokens.segments/_index.segment.rsc +7 -7
  110. package/.next/server/app/settings/tokens.segments/_tree.segment.rsc +2 -2
  111. package/.next/server/app/settings/tokens.segments/settings/tokens/__PAGE__.segment.rsc +4 -4
  112. package/.next/server/app/settings/tokens.segments/settings/tokens.segment.rsc +3 -3
  113. package/.next/server/app/settings/tokens.segments/settings.segment.rsc +3 -3
  114. package/.next/server/app/settings.html +2 -2
  115. package/.next/server/app/settings.rsc +14 -14
  116. package/.next/server/app/settings.segments/_full.segment.rsc +14 -14
  117. package/.next/server/app/settings.segments/_head.segment.rsc +4 -4
  118. package/.next/server/app/settings.segments/_index.segment.rsc +7 -7
  119. package/.next/server/app/settings.segments/_tree.segment.rsc +2 -2
  120. package/.next/server/app/settings.segments/settings/__PAGE__.segment.rsc +4 -4
  121. package/.next/server/app/settings.segments/settings.segment.rsc +3 -3
  122. package/.next/server/app/tasks/[id]/page_client-reference-manifest.js +1 -1
  123. package/.next/server/app/tasks/page_client-reference-manifest.js +1 -1
  124. package/.next/server/app/tasks.html +2 -2
  125. package/.next/server/app/tasks.rsc +14 -14
  126. package/.next/server/app/tasks.segments/_full.segment.rsc +14 -14
  127. package/.next/server/app/tasks.segments/_head.segment.rsc +4 -4
  128. package/.next/server/app/tasks.segments/_index.segment.rsc +7 -7
  129. package/.next/server/app/tasks.segments/_tree.segment.rsc +2 -2
  130. package/.next/server/app/tasks.segments/tasks/__PAGE__.segment.rsc +4 -4
  131. package/.next/server/app/tasks.segments/tasks.segment.rsc +3 -3
  132. package/.next/server/chunks/ssr/[root-of-the-server]__03b.f76._.js +1 -1
  133. package/.next/server/chunks/ssr/[root-of-the-server]__03b.f76._.js.map +1 -1
  134. package/.next/server/chunks/ssr/[root-of-the-server]__0fhoq8i._.js +1 -1
  135. package/.next/server/chunks/ssr/[root-of-the-server]__0fhoq8i._.js.map +1 -1
  136. package/.next/server/chunks/ssr/[root-of-the-server]__0nw~zhp._.js +1 -1
  137. package/.next/server/chunks/ssr/[root-of-the-server]__0nw~zhp._.js.map +1 -1
  138. package/.next/server/chunks/ssr/agent-network-dashboard_09kk21a._.js +4 -1
  139. package/.next/server/chunks/ssr/agent-network-dashboard_09kk21a._.js.map +1 -1
  140. package/.next/server/chunks/ssr/agent-network-dashboard_app_01jhlxz._.js +1 -1
  141. package/.next/server/chunks/ssr/agent-network-dashboard_app_01jhlxz._.js.map +1 -1
  142. package/.next/server/chunks/ssr/agent-network-dashboard_app_057q.ne._.js +1 -1
  143. package/.next/server/chunks/ssr/agent-network-dashboard_app_057q.ne._.js.map +1 -1
  144. package/.next/server/chunks/ssr/agent-network-dashboard_app_09d29my._.js +1 -1
  145. package/.next/server/chunks/ssr/agent-network-dashboard_app_09d29my._.js.map +1 -1
  146. package/.next/server/chunks/ssr/agent-network-dashboard_app_0_d45-d._.js +1 -1
  147. package/.next/server/chunks/ssr/agent-network-dashboard_app_0_d45-d._.js.map +1 -1
  148. package/.next/server/chunks/ssr/agent-network-dashboard_app_0i3759l._.js +1 -1
  149. package/.next/server/chunks/ssr/agent-network-dashboard_app_0i3759l._.js.map +1 -1
  150. package/.next/server/chunks/ssr/agent-network-dashboard_app_0xgney8._.js +1 -1
  151. package/.next/server/chunks/ssr/agent-network-dashboard_app_0xgney8._.js.map +1 -1
  152. package/.next/server/chunks/ssr/agent-network-dashboard_app_10hjgv4._.js +1 -1
  153. package/.next/server/chunks/ssr/agent-network-dashboard_app_10hjgv4._.js.map +1 -1
  154. package/.next/server/chunks/ssr/agent-network-dashboard_app_1153xeb._.js +1 -1
  155. package/.next/server/chunks/ssr/agent-network-dashboard_app_1153xeb._.js.map +1 -1
  156. package/.next/server/chunks/ssr/agent-network-dashboard_app_12l4oto._.js +1 -1
  157. package/.next/server/chunks/ssr/agent-network-dashboard_app_12l4oto._.js.map +1 -1
  158. package/.next/server/chunks/ssr/agent-network-dashboard_app_components_0mvyi-4._.js +1 -1
  159. package/.next/server/chunks/ssr/agent-network-dashboard_app_components_0mvyi-4._.js.map +1 -1
  160. package/.next/server/middleware-build-manifest.js +3 -3
  161. package/.next/server/pages/404.html +2 -2
  162. package/.next/server/pages/500.html +1 -1
  163. package/.next/server/server-reference-manifest.js +1 -1
  164. package/.next/server/server-reference-manifest.json +1 -1
  165. package/.next/static/chunks/0-mpa_947ipeq.js +1 -0
  166. package/.next/static/chunks/01lmbsd37fybu.js +1 -0
  167. package/.next/static/chunks/03o.h6kvmw4l_.js +1 -0
  168. package/.next/static/chunks/03~~oirxz7~vc.js +1 -0
  169. package/.next/static/chunks/05uk96gc~9mni.js +1 -0
  170. package/.next/static/chunks/08kf-.bgs10ze.js +1 -0
  171. package/.next/static/chunks/0c_eg6lxw~36i.js +4 -0
  172. package/.next/static/chunks/0ggj5ummw2a84.js +7 -0
  173. package/.next/static/chunks/0glmrdj9112tc.js +7 -0
  174. package/.next/static/chunks/0qnfuwkukbu01.js +1 -0
  175. package/.next/static/chunks/0rxrez_cjn.eh.js +1 -0
  176. package/.next/static/chunks/0x8x.29hkju5a.js +1 -0
  177. package/.next/static/chunks/0y.7kwty.hl7h.css +2 -0
  178. package/.next/static/chunks/11ilooy_9niy-.js +1 -0
  179. package/.next/static/chunks/174re5ar~kxne.js +1 -0
  180. package/.next/trace +2 -2
  181. package/.next/trace-build +1 -1
  182. package/app/components/ChatPopover.tsx +38 -2
  183. package/app/components/CommandPalette.tsx +107 -0
  184. package/app/components/HelpOverlay.tsx +126 -0
  185. package/app/components/TopoGraph.tsx +5595 -246
  186. package/app/components/utils.ts +8 -7
  187. package/app/globals.css +110 -5
  188. package/app/lib/time.ts +36 -0
  189. package/package.json +2 -2
  190. package/scripts/help-overlay-topo-test.mjs +44 -0
  191. package/scripts/topo-active-filter-pill-test.mjs +101 -0
  192. package/scripts/topo-active-links-chip-hover-test.mjs +103 -0
  193. package/scripts/topo-active-links-chip-nav-test.mjs +117 -0
  194. package/scripts/topo-active-links-chip-self-hover-test.mjs +171 -0
  195. package/scripts/topo-active-links-chip-test.mjs +73 -0
  196. package/scripts/topo-active-links-empty-recede-test.mjs +125 -0
  197. package/scripts/topo-active-links-freshness-test.mjs +113 -0
  198. package/scripts/topo-active-links-tooltip-test.mjs +79 -0
  199. package/scripts/topo-active-pulse-ease-test.mjs +120 -0
  200. package/scripts/topo-arrival-ping-test.mjs +87 -0
  201. package/scripts/topo-auto-fit-test.mjs +73 -0
  202. package/scripts/topo-canvas-aria-test.mjs +108 -0
  203. package/scripts/topo-chat-target-breath-test.mjs +84 -0
  204. package/scripts/topo-chat-target-ring-ease-test.mjs +82 -0
  205. package/scripts/topo-chat-target-ring-fade-test.mjs +124 -0
  206. package/scripts/topo-chip-empty-recede-test.mjs +116 -0
  207. package/scripts/topo-chip-focus-test.mjs +95 -0
  208. package/scripts/topo-chip-pin-mirror-test.mjs +113 -0
  209. package/scripts/topo-chip-row-semantic-gap-test.mjs +97 -0
  210. package/scripts/topo-chip-row-tabular-test.mjs +111 -0
  211. package/scripts/topo-chrome-a11y-test.mjs +107 -0
  212. package/scripts/topo-chrome-pop-extension-test.mjs +98 -0
  213. package/scripts/topo-chrome-pop-nodesize-test.mjs +88 -0
  214. package/scripts/topo-chrome-press-state-test.mjs +135 -0
  215. package/scripts/topo-chrome-strip-semantic-gap-test.mjs +99 -0
  216. package/scripts/topo-chrome-strip-theme-ease-test.mjs +99 -0
  217. package/scripts/topo-chrome-zoom-level-pop-test.mjs +122 -0
  218. package/scripts/topo-chrome-zoom-pop-test.mjs +130 -0
  219. package/scripts/topo-click-ripple-ease-test.mjs +94 -0
  220. package/scripts/topo-cmdk-edge-clear-test.mjs +109 -0
  221. package/scripts/topo-cmdk-layout-view-test.mjs +108 -0
  222. package/scripts/topo-cmdk-pin-test.mjs +123 -0
  223. package/scripts/topo-cmdk-vendor-clear-test.mjs +133 -0
  224. package/scripts/topo-cmdk-vendor-pin-test.mjs +103 -0
  225. package/scripts/topo-corner-radius-unify-test.mjs +103 -0
  226. package/scripts/topo-cwd-tooltip-test.mjs +64 -0
  227. package/scripts/topo-dblclick-reset-test.mjs +74 -0
  228. package/scripts/topo-dense-alias-fill-transition-test.mjs +133 -0
  229. package/scripts/topo-discrete-zoom-smooth-test.mjs +125 -0
  230. package/scripts/topo-dispatch-pulse-test.mjs +83 -0
  231. package/scripts/topo-edge-badge-click-pin-test.mjs +94 -0
  232. package/scripts/topo-edge-badge-crossfade-test.mjs +138 -0
  233. package/scripts/topo-edge-badge-hot-test.mjs +115 -0
  234. package/scripts/topo-edge-badge-hover-test.mjs +85 -0
  235. package/scripts/topo-edge-badge-lift-test.mjs +150 -0
  236. package/scripts/topo-edge-badge-ripple-test.mjs +111 -0
  237. package/scripts/topo-edge-badge-stroke-transition-test.mjs +118 -0
  238. package/scripts/topo-edge-badge-text-pin-test.mjs +121 -0
  239. package/scripts/topo-edge-badge-theme-ease-test.mjs +89 -0
  240. package/scripts/topo-edge-count-badge-test.mjs +86 -0
  241. package/scripts/topo-edge-endpoint-highlight-test.mjs +111 -0
  242. package/scripts/topo-edge-fadein-test.mjs +106 -0
  243. package/scripts/topo-edge-focus-test.mjs +113 -0
  244. package/scripts/topo-edge-hover-test.mjs +93 -0
  245. package/scripts/topo-edge-pill-hot-test.mjs +129 -0
  246. package/scripts/topo-edge-pill-test.mjs +105 -0
  247. package/scripts/topo-edge-smil-sync-test.mjs +148 -0
  248. package/scripts/topo-edge-smil-theme-ease-test.mjs +97 -0
  249. package/scripts/topo-edge-stroke-ease-test.mjs +100 -0
  250. package/scripts/topo-edge-stroke-transition-test.mjs +132 -0
  251. package/scripts/topo-edge-tooltip-test.mjs +70 -0
  252. package/scripts/topo-empty-state-breath-test.mjs +150 -0
  253. package/scripts/topo-empty-state-crossfade-test.mjs +130 -0
  254. package/scripts/topo-empty-state-recenter-test.mjs +107 -0
  255. package/scripts/topo-endpoint-ring-fade-test.mjs +132 -0
  256. package/scripts/topo-endpoint-ring-test.mjs +93 -0
  257. package/scripts/topo-endpoint-ring-thicken-test.mjs +112 -0
  258. package/scripts/topo-esc-clears-pin-test.mjs +98 -0
  259. package/scripts/topo-filter-pill-aliases-test.mjs +121 -0
  260. package/scripts/topo-filter-pill-body-click-test.mjs +112 -0
  261. package/scripts/topo-filter-pill-count-test.mjs +110 -0
  262. package/scripts/topo-filter-pill-mobile-test.mjs +90 -0
  263. package/scripts/topo-fit-key-test.mjs +106 -0
  264. package/scripts/topo-freshness-chip-test.mjs +74 -0
  265. package/scripts/topo-freshness-chip-transition-test.mjs +80 -0
  266. package/scripts/topo-freshness-text-color-coherence-test.mjs +97 -0
  267. package/scripts/topo-fullscreen-active-test.mjs +115 -0
  268. package/scripts/topo-group-box-pinned-state-test.mjs +95 -0
  269. package/scripts/topo-group-count-test.mjs +6 -1
  270. package/scripts/topo-group-label-a11y-test.mjs +113 -0
  271. package/scripts/topo-group-label-count-inherit-test.mjs +99 -0
  272. package/scripts/topo-group-label-hover-test.mjs +119 -0
  273. package/scripts/topo-group-label-pin-spacing-test.mjs +136 -0
  274. package/scripts/topo-group-label-tint-test.mjs +99 -0
  275. package/scripts/topo-group-label-title-test.mjs +83 -0
  276. package/scripts/topo-group-pin-test.mjs +119 -0
  277. package/scripts/topo-group-pip-fadein-test.mjs +100 -0
  278. package/scripts/topo-group-pip-tabular-test.mjs +95 -0
  279. package/scripts/topo-group-status-pips-test.mjs +103 -0
  280. package/scripts/topo-groupbox-fadein-test.mjs +95 -0
  281. package/scripts/topo-groupbox-hover-lift-test.mjs +127 -0
  282. package/scripts/topo-groupbox-hubcore-ease-test.mjs +106 -0
  283. package/scripts/topo-groupbox-live-test.mjs +100 -0
  284. package/scripts/topo-groupbox-march-busyness-test.mjs +155 -0
  285. package/scripts/topo-groupbox-test.mjs +4 -2
  286. package/scripts/topo-halo-breath-ease-test.mjs +92 -0
  287. package/scripts/topo-halo-breath-stagger-test.mjs +89 -0
  288. package/scripts/topo-help-overlay-r109-test.mjs +67 -0
  289. package/scripts/topo-help-overlay-r118-test.mjs +69 -0
  290. package/scripts/topo-help-overlay-r123-test.mjs +69 -0
  291. package/scripts/topo-help-overlay-r134-test.mjs +74 -0
  292. package/scripts/topo-help-overlay-r137-test.mjs +81 -0
  293. package/scripts/topo-help-overlay-r141-test.mjs +86 -0
  294. package/scripts/topo-help-overlay-r153-test.mjs +85 -0
  295. package/scripts/topo-help-overlay-r59-test.mjs +67 -0
  296. package/scripts/topo-help-overlay-r65-test.mjs +64 -0
  297. package/scripts/topo-help-overlay-r70-test.mjs +63 -0
  298. package/scripts/topo-help-overlay-r78-test.mjs +59 -0
  299. package/scripts/topo-help-overlay-r81-test.mjs +58 -0
  300. package/scripts/topo-help-overlay-r87-test.mjs +64 -0
  301. package/scripts/topo-help-overlay-r91-test.mjs +65 -0
  302. package/scripts/topo-hot-tail-crossfade-test.mjs +117 -0
  303. package/scripts/topo-html-overlay-padding-unify-test.mjs +120 -0
  304. package/scripts/topo-hub-a11y-test.mjs +112 -0
  305. package/scripts/topo-hub-busyness-test.mjs +100 -0
  306. package/scripts/topo-hub-center-crossfade-test.mjs +124 -0
  307. package/scripts/topo-hub-click-fit-test.mjs +137 -0
  308. package/scripts/topo-hub-digit-scale-test.mjs +129 -0
  309. package/scripts/topo-hub-fadein-test.mjs +88 -0
  310. package/scripts/topo-hub-hover-lift-test.mjs +101 -0
  311. package/scripts/topo-hub-hover-ring-test.mjs +82 -0
  312. package/scripts/topo-hub-pip-theme-ease-test.mjs +116 -0
  313. package/scripts/topo-hub-spoke-ease-test.mjs +120 -0
  314. package/scripts/topo-hub-title-test.mjs +93 -0
  315. package/scripts/topo-hub-working-count-test.mjs +99 -0
  316. package/scripts/topo-ingroup-edge-test.mjs +103 -0
  317. package/scripts/topo-label-card-theme-ease-test.mjs +85 -0
  318. package/scripts/topo-label-lift-test.mjs +119 -0
  319. package/scripts/topo-lastseen-tooltip-test.mjs +59 -0
  320. package/scripts/topo-layout-hover-text-preview-test.mjs +101 -0
  321. package/scripts/topo-layout-key-test.mjs +91 -0
  322. package/scripts/topo-layout-switch-crossfade-test.mjs +126 -0
  323. package/scripts/topo-layout-toggle-border-unify-test.mjs +104 -0
  324. package/scripts/topo-layout-toggle-test.mjs +131 -0
  325. package/scripts/topo-legend-count-empty-test.mjs +126 -0
  326. package/scripts/topo-legend-count-tabular-test.mjs +87 -0
  327. package/scripts/topo-legend-count-test.mjs +88 -0
  328. package/scripts/topo-legend-count-tier-fill-test.mjs +121 -0
  329. package/scripts/topo-legend-header-symmetric-inset-test.mjs +112 -0
  330. package/scripts/topo-legend-hitbox-swatch-center-test.mjs +93 -0
  331. package/scripts/topo-legend-hover-test.mjs +113 -0
  332. package/scripts/topo-legend-offline-delimiter-test.mjs +84 -0
  333. package/scripts/topo-legend-panel-header-test.mjs +83 -0
  334. package/scripts/topo-legend-pin-ring-fade-test.mjs +112 -0
  335. package/scripts/topo-legend-pin-test.mjs +128 -0
  336. package/scripts/topo-legend-row-hover-lift-test.mjs +109 -0
  337. package/scripts/topo-legend-row-pin-spacing-test.mjs +124 -0
  338. package/scripts/topo-legend-row-tint-test.mjs +95 -0
  339. package/scripts/topo-legend-row-title-test.mjs +102 -0
  340. package/scripts/topo-legend-swatch-grow-test.mjs +116 -0
  341. package/scripts/topo-minimap-a11y-test.mjs +101 -0
  342. package/scripts/topo-minimap-dot-transition-test.mjs +113 -0
  343. package/scripts/topo-minimap-test.mjs +68 -0
  344. package/scripts/topo-minimap-viewport-smooth-test.mjs +124 -0
  345. package/scripts/topo-mobile-chips-test.mjs +103 -0
  346. package/scripts/topo-node-a11y-test.mjs +107 -0
  347. package/scripts/topo-node-hover-lift-test.mjs +85 -0
  348. package/scripts/topo-node-label-card-elevation-test.mjs +157 -0
  349. package/scripts/topo-node-label-card-stroke-test.mjs +135 -0
  350. package/scripts/topo-node-stroke-transition-test.mjs +103 -0
  351. package/scripts/topo-node-text-fill-transition-test.mjs +119 -0
  352. package/scripts/topo-node-title-peers-test.mjs +107 -0
  353. package/scripts/topo-node-title-test.mjs +101 -0
  354. package/scripts/topo-nodesize-active-hover-test.mjs +109 -0
  355. package/scripts/topo-nodesize-crossfade-test.mjs +141 -0
  356. package/scripts/topo-online-chip-nav-test.mjs +143 -0
  357. package/scripts/topo-orbit-busyness-test.mjs +96 -0
  358. package/scripts/topo-orbit-opacity-bucket-test.mjs +124 -0
  359. package/scripts/topo-overlap-test.mjs +32 -5
  360. package/scripts/topo-pan-cursor-test.mjs +62 -0
  361. package/scripts/topo-panel-elevation-test.mjs +76 -0
  362. package/scripts/topo-panel-fadein-test.mjs +102 -0
  363. package/scripts/topo-panel-hot-tail-fade-test.mjs +132 -0
  364. package/scripts/topo-panel-hover-elevation-test.mjs +118 -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-particle-stagger-test.mjs +82 -0
  368. package/scripts/topo-pin-intersection-color-ease-test.mjs +111 -0
  369. package/scripts/topo-pin-intersection-empty-test.mjs +129 -0
  370. package/scripts/topo-pin-intersection-tabular-test.mjs +96 -0
  371. package/scripts/topo-pin-intersection-test.mjs +121 -0
  372. package/scripts/topo-pin-intersection-warning-crossfade-test.mjs +107 -0
  373. package/scripts/topo-pin-mirror-transition-test.mjs +101 -0
  374. package/scripts/topo-pin-persistence-test.mjs +105 -0
  375. package/scripts/topo-ping-pulse-ease-test.mjs +96 -0
  376. package/scripts/topo-popover-meta-test.mjs +78 -0
  377. package/scripts/topo-prepublish-guard-test.mjs +95 -0
  378. package/scripts/topo-pressure-bar-test.mjs +69 -0
  379. package/scripts/topo-pressure-hover-test.mjs +123 -0
  380. package/scripts/topo-pressure-pin-test.mjs +119 -0
  381. package/scripts/topo-pressure-seg-self-hover-test.mjs +126 -0
  382. package/scripts/topo-pressure-seg-tooltip-test.mjs +98 -0
  383. package/scripts/topo-pressure-seg-transition-test.mjs +107 -0
  384. package/scripts/topo-pulse-dot-crossfade-test.mjs +122 -0
  385. package/scripts/topo-pulse-rate-test.mjs +71 -0
  386. package/scripts/topo-recent-panel-count-freshness-test.mjs +109 -0
  387. package/scripts/topo-recent-panel-count-test.mjs +72 -0
  388. package/scripts/topo-recent-panel-footer-breath-test.mjs +142 -0
  389. package/scripts/topo-recent-panel-hot-header-test.mjs +132 -0
  390. package/scripts/topo-recent-panel-more-crossfade-test.mjs +124 -0
  391. package/scripts/topo-recent-panel-more-cyan-hover-test.mjs +151 -0
  392. package/scripts/topo-recent-panel-more-nav-test.mjs +127 -0
  393. package/scripts/topo-recent-panel-more-test.mjs +106 -0
  394. package/scripts/topo-recent-panel-readability-bump-test.mjs +151 -0
  395. package/scripts/topo-recent-row-count-fill-test.mjs +129 -0
  396. package/scripts/topo-recent-row-fadein-test.mjs +107 -0
  397. package/scripts/topo-recent-row-freshness-test.mjs +102 -0
  398. package/scripts/topo-recent-row-hot-test.mjs +110 -0
  399. package/scripts/topo-recent-row-hover-lift-test.mjs +128 -0
  400. package/scripts/topo-recent-row-hover-test.mjs +122 -0
  401. package/scripts/topo-recent-row-pin-spacing-test.mjs +137 -0
  402. package/scripts/topo-recent-row-pin-test.mjs +126 -0
  403. package/scripts/topo-recent-row-tint-test.mjs +91 -0
  404. package/scripts/topo-recent-row-title-test.mjs +112 -0
  405. package/scripts/topo-recent-row-ts-alpha-test.mjs +100 -0
  406. package/scripts/topo-recent-row-ts-test.mjs +95 -0
  407. package/scripts/topo-recent-row-typography-test.mjs +119 -0
  408. package/scripts/topo-recent-signal-empty-hint-test.mjs +73 -0
  409. package/scripts/topo-recent-signal-empty-test.mjs +63 -0
  410. package/scripts/topo-reduced-motion-test.mjs +77 -0
  411. package/scripts/topo-reset-spin-test.mjs +120 -0
  412. package/scripts/topo-runtime-badge-grow-test.mjs +114 -0
  413. package/scripts/topo-spoke-busyness-test.mjs +110 -0
  414. package/scripts/topo-spoke-tint-test.mjs +96 -0
  415. package/scripts/topo-status-chip-hover-test.mjs +101 -0
  416. package/scripts/topo-status-chip-tooltip-test.mjs +95 -0
  417. package/scripts/topo-statusbar-chips-self-hover-test.mjs +177 -0
  418. package/scripts/topo-svg-focus-test.mjs +112 -0
  419. package/scripts/topo-sweep-busyness-test.mjs +94 -0
  420. package/scripts/topo-tabular-nums-sweep-test.mjs +93 -0
  421. package/scripts/topo-tier-ring-fadein-test.mjs +107 -0
  422. package/scripts/topo-tier-ring-occupancy-test.mjs +87 -0
  423. package/scripts/topo-tier-ring-test.mjs +69 -0
  424. package/scripts/topo-tier-ring-tint-test.mjs +110 -0
  425. package/scripts/topo-tier-stagger-test.mjs +89 -0
  426. package/scripts/topo-title-block-tight-leading-test.mjs +95 -0
  427. package/scripts/topo-toggle-inactive-cyan-hover-test.mjs +110 -0
  428. package/scripts/topo-top-rail-theme-ease-test.mjs +89 -0
  429. package/scripts/topo-tz-ghost-test.mjs +69 -0
  430. package/scripts/topo-vendor-chip-hover-test.mjs +111 -0
  431. package/scripts/topo-vendor-chip-self-hover-test.mjs +130 -0
  432. package/scripts/topo-vendor-chip-tabular-test.mjs +89 -0
  433. package/scripts/topo-vendor-letter-tooltip-test.mjs +92 -0
  434. package/scripts/topo-vendor-pill-test.mjs +125 -0
  435. package/scripts/topo-vendor-pin-test.mjs +125 -0
  436. package/scripts/topo-view-smooth-test.mjs +131 -0
  437. package/scripts/topo-wheel-zoom-test.mjs +79 -0
  438. package/scripts/topo-working-chip-pin-test.mjs +154 -0
  439. package/scripts/topo-working-halo-breath-test.mjs +86 -0
  440. package/scripts/topo-wrapper-flow-arrow-theme-test.mjs +97 -0
  441. package/scripts/topo-wrapper-shadow-theme-ease-test.mjs +89 -0
  442. package/scripts/topo-zoom-keys-test.mjs +89 -0
  443. package/.next/static/chunks/0-7iowzu4.798.js +0 -1
  444. package/.next/static/chunks/02t5jr4shh.hy.js +0 -1
  445. package/.next/static/chunks/09nd.t_hd.y6t.css +0 -2
  446. package/.next/static/chunks/0_qfg5s5uzs7..js +0 -7
  447. package/.next/static/chunks/0a6k5x_~ch.y7.js +0 -1
  448. package/.next/static/chunks/0elalb9n_.~di.js +0 -1
  449. package/.next/static/chunks/0ipujag5x55bt.js +0 -1
  450. package/.next/static/chunks/0j_q__o8p6g83.js +0 -1
  451. package/.next/static/chunks/0jl6_w50zh4l5.js +0 -1
  452. package/.next/static/chunks/0pl7l_.2im.j0.js +0 -7
  453. package/.next/static/chunks/0r4q73.-1bkyl.js +0 -1
  454. package/.next/static/chunks/0r_c8eccg3z2o.js +0 -1
  455. package/.next/static/chunks/0zs511wcsq~0j.js +0 -1
  456. package/.next/static/chunks/10oi7l-tycgl9.js +0 -1
  457. package/.next/static/chunks/11uk1izuv3~0t.js +0 -1
  458. /package/.next/static/{DCVxQ0usFqDQ5PHW3d_Zx → gjUOBeB2JqesZ_cSX14ph}/_buildManifest.js +0 -0
  459. /package/.next/static/{DCVxQ0usFqDQ5PHW3d_Zx → gjUOBeB2JqesZ_cSX14ph}/_clientMiddlewareManifest.js +0 -0
  460. /package/.next/static/{DCVxQ0usFqDQ5PHW3d_Zx → gjUOBeB2JqesZ_cSX14ph}/_ssgManifest.js +0 -0
@@ -0,0 +1,130 @@
1
+ /* Round 202 verification: vendor letter chips (A/O/书/M/?) deepen
2
+ * their OWN vendor colour on hover, completing the chip-row family
3
+ * R193/R195/R201 opened.
4
+ *
5
+ * Pre-R202 hover fired R88 canvas dim via setHoveredVendor but the
6
+ * chip itself stayed at bg=transparent. R202 tints the chip with
7
+ * color-mix(in srgb, <vendor-hue> 12%, transparent) only when hovered
8
+ * (and not pinned — pinned uses R180's stronger inset-ring treatment).
9
+ *
10
+ * Test (cyber dark, 2 claude + 2 gpt sessions → vendorDist={A:2, O:2}):
11
+ * 1. vendor letter chips A + O both render (vendorDist.length > 1).
12
+ * 2. Idle: data-vendor-hovered='false', backgroundColor='transparent'
13
+ * / 'rgba(0,0,0,0)'.
14
+ * 3. Inline transition includes 'box-shadow 150ms' (R180 still there)
15
+ * AND 'background-color 200ms' (R202 splice).
16
+ * 4. Hover 'A' chip — wait past 220ms.
17
+ * 5. 'A' data-vendor-hovered='true', backgroundColor is a non-empty
18
+ * tint string (color-mix or rendered fallback) different from
19
+ * idle. 'O' chip stays 'false' + transparent.
20
+ * 6. Move away — 'A' settles back to 'false' + transparent.
21
+ * 7. R88 canvas-effect verification — hover 'A' sets hoveredVendor
22
+ * which composes into the canvas dim logic; we probe via a
23
+ * surrogate signal that the chip's R55-like effect fires:
24
+ * hoveredVendor is exposed elsewhere via data attributes; the
25
+ * simplest gate is that the chip itself reflects the hover via
26
+ * its own data-vendor-hovered attribute already asserted above
27
+ * (event handler clearly ran).
28
+ */
29
+ import { chromium } from 'playwright';
30
+ import { readFileSync } from 'node:fs';
31
+
32
+ const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
33
+ const browser = await chromium.launch({ headless: true });
34
+
35
+ const ctx = await browser.newContext({ viewport: { width: 1500, height: 1500 } });
36
+ await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
37
+ await ctx.addInitScript(() => {
38
+ try { localStorage.setItem('anet-theme', 'cyber'); sessionStorage.setItem('anet_v3_auth', '1'); } catch {}
39
+ });
40
+
41
+ const fresh = new Date(Date.now() - 60 * 1000).toISOString();
42
+ await ctx.route('**/api/hub/status*', async (route) => {
43
+ const r = await route.fetch();
44
+ const b = await r.json();
45
+ const nid = (b.sessions || [])[0]?.network_id || 'default';
46
+ const mk = (alias, model) => ({
47
+ alias, status: 'working', model, runtime: 'cli-claude-code',
48
+ network_id: nid, project_dir: null,
49
+ created_at: fresh, updated_at: fresh, last_seen_at: fresh,
50
+ });
51
+ // Two Anthropic + two OpenAI → vendorDist={A:2, O:2}
52
+ await route.fulfill({ response: r, json: { ...b, sessions: [
53
+ mk('alpha', 'claude-opus-4'),
54
+ mk('beta', 'claude-sonnet-4'),
55
+ mk('gamma', 'gpt-4o'),
56
+ mk('delta', 'gpt-4'),
57
+ ] } });
58
+ });
59
+ await ctx.route('**/api/hub/messages*', (route) => route.fulfill({ json: { messages: [] } }));
60
+ await ctx.route('**/api/hub/tasks*', (route) => route.fulfill({ json: { tasks: [] } }));
61
+
62
+ const page = await ctx.newPage();
63
+ await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
64
+ await page.waitForFunction(() => document.querySelectorAll('g[data-node]').length === 4, { timeout: 30000 });
65
+ await page.waitForSelector('[data-vendor-letter="A"]', { timeout: 10000 });
66
+ await page.waitForSelector('[data-vendor-letter="O"]', { timeout: 5000 });
67
+ await page.waitForTimeout(300);
68
+
69
+ const probe = async (initial) => page.evaluate((i) => {
70
+ const el = document.querySelector(`[data-vendor-letter="${i}"]`);
71
+ if (!el) return null;
72
+ const cs = getComputedStyle(el);
73
+ return {
74
+ initial: i,
75
+ hovered: el.getAttribute('data-vendor-hovered'),
76
+ pinned: el.getAttribute('data-vendor-pinned'),
77
+ bg: cs.backgroundColor,
78
+ inlineBg: el.style.backgroundColor,
79
+ transition: el.style.transition,
80
+ };
81
+ }, initial);
82
+
83
+ const idleA = await probe('A');
84
+ const idleO = await probe('O');
85
+
86
+ await page.hover('[data-vendor-letter="A"]');
87
+ await page.waitForTimeout(260);
88
+ const hoverA = await probe('A');
89
+ const otherO = await probe('O');
90
+
91
+ await page.mouse.move(0, 0);
92
+ await page.waitForTimeout(280);
93
+ const settledA = await probe('A');
94
+
95
+ await browser.close();
96
+
97
+ const isTransparent = (s) =>
98
+ !s || s === 'transparent' || s === 'rgba(0, 0, 0, 0)' || s === 'rgba(0,0,0,0)';
99
+
100
+ const hasColorMix = (s) => /color-mix\s*\(/i.test(s || '');
101
+ const isNonEmptyColor = (s) => !!s && !isTransparent(s);
102
+
103
+ const results = {
104
+ A_chip_present: !!idleA,
105
+ O_chip_present: !!idleO,
106
+
107
+ idle_A_not_hovered: idleA?.hovered === 'false',
108
+ idle_A_transparent_bg: isTransparent(idleA?.bg),
109
+ idle_A_transition_boxshadow: /box-shadow\s+(?:150ms|0\.15s)/.test(idleA?.transition || ''),
110
+ idle_A_transition_bgcolor: /background-color\s+(?:200ms|0\.2s)/.test(idleA?.transition || ''),
111
+
112
+ idle_O_not_hovered: idleO?.hovered === 'false',
113
+
114
+ hover_A_hovered_attr: hoverA?.hovered === 'true',
115
+ hover_A_inline_color_mix: hasColorMix(hoverA?.inlineBg),
116
+ hover_A_computed_non_transparent: isNonEmptyColor(hoverA?.bg) && !isTransparent(hoverA?.bg),
117
+ hover_A_bg_changed: idleA?.bg !== hoverA?.bg,
118
+ hover_O_stays_idle: otherO?.hovered === 'false' && isTransparent(otherO?.bg),
119
+
120
+ settled_A_not_hovered: settledA?.hovered === 'false',
121
+ settled_A_transparent_bg: isTransparent(settledA?.bg),
122
+ };
123
+ const ok = Object.values(results).every(Boolean);
124
+ console.log(`${ok ? '✅' : '❌'} vendor chip self-hover:`, JSON.stringify(results),
125
+ `\n idleA:`, idleA,
126
+ `\n idleO:`, idleO,
127
+ `\n hoverA:`, hoverA,
128
+ `\n otherO:`, otherO,
129
+ `\n settledA:`, settledA);
130
+ process.exit(ok ? 0 : 1);
@@ -0,0 +1,89 @@
1
+ /* Round 234 verification: vendor letter chip (the inline chips
2
+ * showing 'A:3', 'C:2', etc. listing per-vendor session counts)
3
+ * picks up the Tailwind `tabular-nums` utility so its ':N' suffix
4
+ * digit doesn't reflow the chip row at the 9→10 boundary.
5
+ *
6
+ * 8th surface in the info-density tabular-nums sweep, completing
7
+ * the HTML chip-side after R232's working/online/active-links.
8
+ *
9
+ * Scenario: 4 working agents split across two vendors — 3 on
10
+ * claude-opus-4 (initial 'A') and 1 on gpt-4 (initial 'O') — so
11
+ * vendorDist.length === 2, which is the condition gating the
12
+ * chip strip render (line ~2116, `vendorDist.length > 1 && ...`).
13
+ * Expect two chips: A:3 and O:1.
14
+ */
15
+ import { chromium } from 'playwright';
16
+ import { readFileSync } from 'node:fs';
17
+
18
+ const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
19
+ const browser = await chromium.launch({ headless: true });
20
+ const ctx = await browser.newContext({ viewport: { width: 1500, height: 1500 } });
21
+ await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
22
+ await ctx.addInitScript(() => {
23
+ try { localStorage.setItem('anet-theme', 'cyber'); sessionStorage.setItem('anet_v3_auth', '1'); } catch {}
24
+ });
25
+ 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, model) => ({
31
+ alias, status: 'working', model, runtime: 'claude-code-cli',
32
+ network_id: nid, project_dir: null,
33
+ created_at: fresh, updated_at: fresh, last_seen_at: fresh,
34
+ });
35
+ // Mix 3 claude-opus-4 (vendor 'A') + 1 gpt-4 (vendor 'O') so
36
+ // vendorDist.length === 2 — chip strip render gate (line ~2116).
37
+ await route.fulfill({ response: r, json: { ...b, sessions: [
38
+ mk('alpha', 'claude-opus-4'),
39
+ mk('beta', 'claude-opus-4'),
40
+ mk('gamma', 'claude-opus-4'),
41
+ mk('delta', 'gpt-4'),
42
+ ] } });
43
+ });
44
+ await ctx.route('**/api/hub/messages*', (r2) => r2.fulfill({ json: { messages: [] } }));
45
+ await ctx.route('**/api/hub/tasks*', (r2) => r2.fulfill({ json: { tasks: [] } }));
46
+
47
+ const page = await ctx.newPage();
48
+ await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
49
+ await page.waitForFunction(() => document.querySelectorAll('g[data-node]').length === 4, { timeout: 30000 });
50
+ await page.waitForSelector('[data-vendor-letter]', { timeout: 10000, state: 'attached' });
51
+ await page.waitForTimeout(300);
52
+
53
+ const out = await page.evaluate(() => {
54
+ const chips = Array.from(document.querySelectorAll('[data-vendor-letter]'));
55
+ return chips.map((c) => ({
56
+ initial: c.getAttribute('data-vendor-letter'),
57
+ countAttr: c.getAttribute('data-vendor-letter-count'),
58
+ classListHas: c.className.split(/\s+/).includes('tabular-nums'),
59
+ fontVarNumeric: getComputedStyle(c).fontVariantNumeric,
60
+ text: (c.textContent || '').trim(),
61
+ // Inner ':N' suffix span — verify font-variant-numeric inherits
62
+ innerFvn: (() => {
63
+ const inner = c.querySelectorAll('span');
64
+ // last span is the gray ':N' suffix
65
+ const last = inner[inner.length - 1];
66
+ return last ? getComputedStyle(last).fontVariantNumeric : null;
67
+ })(),
68
+ }));
69
+ });
70
+ await browser.close();
71
+
72
+ const hasTab = (s) => /tabular-nums/.test(s || '');
73
+
74
+ // Build a map of initial → count from the chips we found.
75
+ const countByInitial = Object.fromEntries(out.map(o => [o.initial, o.countAttr]));
76
+ const results = {
77
+ two_chips: out.length === 2,
78
+ all_have_initial: out.every(o => typeof o.initial === 'string' && o.initial.length === 1),
79
+ anthropic_count_3: countByInitial['A'] === '3',
80
+ openai_count_1: countByInitial['O'] === '1',
81
+ all_class_utility: out.every(o => o.classListHas === true),
82
+ all_fvn_tabular: out.every(o => hasTab(o.fontVarNumeric)),
83
+ all_inner_fvn_inherits: out.every(o => hasTab(o.innerFvn)),
84
+ texts_match_counts: out.every(o => new RegExp(`:${o.countAttr}$`).test(o.text)),
85
+ };
86
+ const ok = Object.values(results).every(Boolean);
87
+ console.log(`${ok ? '✅' : '❌'} vendor chip tabular:`, JSON.stringify(results),
88
+ '\n chips:', out);
89
+ process.exit(ok ? 0 : 1);
@@ -0,0 +1,92 @@
1
+ /* Round 101 verification: vendor-letter chip <span>s carry an alias-
2
+ * list tooltip. Completes the R97/R98/R99 info-density sweep — every
3
+ * surface that shows "X:N" should hover-explain which N.
4
+ *
5
+ * Fleet: 2 Claude (alpha, gamma), 2 GPT (beta, delta). Vendor chip
6
+ * shows "A:2 O:2". A letter's tooltip should list alpha, gamma;
7
+ * O letter's should list beta, delta. Pin state flips the trailing
8
+ * action hint ("click to pin" → "click again or Esc to clear").
9
+ */
10
+ import { chromium } from 'playwright';
11
+ import { readFileSync } from 'node:fs';
12
+
13
+ const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
14
+ const browser = await chromium.launch({ headless: true });
15
+
16
+ const ctx = await browser.newContext({ viewport: { width: 1400, height: 1500 } });
17
+ await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
18
+ await ctx.addInitScript(() => {
19
+ try {
20
+ localStorage.setItem('anet-theme', 'cyber');
21
+ sessionStorage.setItem('anet_v3_auth', '1');
22
+ sessionStorage.removeItem('anet-topo-pinned-vendor');
23
+ } catch {}
24
+ });
25
+
26
+ const fresh = new Date(Date.now() - 60 * 1000).toISOString();
27
+ await ctx.route('**/api/hub/status*', async (route) => {
28
+ const r = await route.fetch();
29
+ const b = await r.json();
30
+ const nid = (b.sessions || [])[0]?.network_id || 'default';
31
+ const mk = (alias, model) => ({
32
+ alias, status: 'idle', model, runtime: 'cli-claude-code',
33
+ network_id: nid, project_dir: null,
34
+ created_at: fresh, updated_at: fresh, last_seen_at: fresh,
35
+ });
36
+ await route.fulfill({ response: r, json: { ...b, sessions: [
37
+ mk('alpha', 'claude-opus-4'),
38
+ mk('beta', 'gpt-5'),
39
+ mk('gamma', 'claude-opus-4'),
40
+ mk('delta', 'gpt-5'),
41
+ ] } });
42
+ });
43
+ await ctx.route('**/api/hub/messages*', (route) => route.fulfill({ json: { messages: [] } }));
44
+ await ctx.route('**/api/hub/tasks*', (route) => route.fulfill({ json: { tasks: [] } }));
45
+ const page = await ctx.newPage();
46
+ await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
47
+ await page.waitForFunction(() => document.querySelectorAll('g[data-node]').length === 4, { timeout: 30000 });
48
+ await page.waitForTimeout(400);
49
+
50
+ const read = (initial) => page.evaluate((i) => {
51
+ const el = document.querySelector(`[data-vendor-letter="${i}"]`);
52
+ if (!el) return null;
53
+ return {
54
+ title: el.getAttribute('title') || '',
55
+ aliases: el.getAttribute('data-vendor-aliases') || '',
56
+ pinned: el.getAttribute('data-vendor-pinned') || '',
57
+ };
58
+ }, initial);
59
+
60
+ const aSnap = await read('A');
61
+ const oSnap = await read('O');
62
+
63
+ // Pin A — title should flip.
64
+ await page.locator('[data-vendor-letter="A"]').click();
65
+ await page.mouse.move(10, 10);
66
+ await page.waitForTimeout(250);
67
+ const aPinned = await read('A');
68
+
69
+ await browser.close();
70
+
71
+ const sameSet = (csv, expected) => {
72
+ const got = new Set(csv.split(',').filter(Boolean));
73
+ const exp = new Set(expected);
74
+ return got.size === exp.size && [...exp].every(x => got.has(x));
75
+ };
76
+
77
+ const results = {
78
+ a_aliasesMatch: sameSet(aSnap?.aliases || '', ['alpha', 'gamma']),
79
+ a_titleListsThem: /alpha.*gamma|gamma.*alpha/.test(aSnap?.title || ''),
80
+ a_titleClickToPin: /click to pin/.test(aSnap?.title || ''),
81
+ o_aliasesMatch: sameSet(oSnap?.aliases || '', ['beta', 'delta']),
82
+ o_titleListsThem: /beta.*delta|delta.*beta/.test(oSnap?.title || ''),
83
+ pinnedA_aliasesUnchanged: sameSet(aPinned?.aliases || '', ['alpha', 'gamma']),
84
+ pinnedA_titleHintFlipped: /click again or Esc to clear/.test(aPinned?.title || ''),
85
+ pinnedA_pinnedAttrTrue: aPinned?.pinned === 'true',
86
+ };
87
+ const ok = Object.values(results).every(Boolean);
88
+ console.log(`${ok ? '✅' : '❌'} vendor-letter tooltip:`, JSON.stringify(results),
89
+ `\n A:`, aSnap,
90
+ `\n O:`, oSnap,
91
+ `\n A-pinned:`, aPinned);
92
+ process.exit(ok ? 0 : 1);
@@ -0,0 +1,125 @@
1
+ /* Round 89 verification: pinning a vendor renders a "filter: X · N ×"
2
+ * pill in the chip-row, mirroring R64 status + group pills. R88 added
3
+ * the pin but the affordance lived only on the letter — body-click /
4
+ * × button on a dedicated pill was missing. R89 closes that.
5
+ *
6
+ * Also verifies the stale-purge useEffect: if the fleet's vendor
7
+ * distribution loses the pinned vendor (last node disconnects), the
8
+ * pin clears automatically so the pill doesn't show "filter: A · 0"
9
+ * forever. Same defensive pattern pinnedGroup uses.
10
+ */
11
+ import { chromium } from 'playwright';
12
+ import { readFileSync } from 'node:fs';
13
+
14
+ const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
15
+ const browser = await chromium.launch({ headless: true });
16
+
17
+ const ctx = await browser.newContext({ viewport: { width: 1400, height: 1200 } });
18
+ await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
19
+ await ctx.addInitScript(() => {
20
+ try {
21
+ localStorage.setItem('anet-theme', 'cyber');
22
+ localStorage.setItem('anet-topo-layout', 'ring');
23
+ sessionStorage.setItem('anet_v3_auth', '1');
24
+ sessionStorage.removeItem('anet-topo-pinned-status');
25
+ sessionStorage.removeItem('anet-topo-pinned-group');
26
+ sessionStorage.removeItem('anet-topo-pinned-vendor');
27
+ } catch {}
28
+ });
29
+
30
+ const fresh = new Date(Date.now() - 60 * 1000).toISOString();
31
+ let dropGPT = false;
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, model) => ({
37
+ alias, status: 'idle', model, runtime: 'cli-claude-code',
38
+ network_id: nid, project_dir: null,
39
+ created_at: fresh, updated_at: fresh, last_seen_at: fresh,
40
+ });
41
+ const sessions = [
42
+ mk('alpha', 'claude-opus-4'),
43
+ mk('gamma', 'claude-opus-4'),
44
+ ];
45
+ if (!dropGPT) sessions.splice(1, 0, mk('beta', 'gpt-5'));
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 === 3, { timeout: 30000 });
53
+ await page.waitForTimeout(400);
54
+
55
+ const pill = () => page.evaluate(() => {
56
+ const p = document.querySelector('[data-active-filter="vendor"]');
57
+ if (!p) return null;
58
+ return {
59
+ text: (p.textContent || '').trim(),
60
+ count: p.getAttribute('data-filter-match-count'),
61
+ color: getComputedStyle(p).color,
62
+ };
63
+ });
64
+ const storage = () => page.evaluate(() => sessionStorage.getItem('anet-topo-pinned-vendor'));
65
+
66
+ // Pin O (gpt-5 → OpenAI) via click.
67
+ const before = await pill();
68
+ await page.locator('[data-vendor-letter="O"]').click();
69
+ await page.mouse.move(10, 10);
70
+ await page.waitForTimeout(250);
71
+ const afterPinO = await pill();
72
+ const afterPinOStorage = await storage();
73
+
74
+ // Clicking the pill body clears the pin.
75
+ await page.locator('[data-active-filter="vendor"]').click();
76
+ await page.waitForTimeout(250);
77
+ const afterBodyClick = await pill();
78
+
79
+ // Pin A (Anthropic) — verify the × button works.
80
+ await page.locator('[data-vendor-letter="A"]').click();
81
+ await page.mouse.move(10, 10);
82
+ await page.waitForTimeout(250);
83
+ const afterPinA = await pill();
84
+ await page.locator('[data-active-filter="vendor"] button').click();
85
+ await page.waitForTimeout(250);
86
+ const afterXButton = await pill();
87
+
88
+ // Pin O again, then mock the GPT node away → stale-purge fires.
89
+ await page.locator('[data-vendor-letter="O"]').click();
90
+ await page.waitForTimeout(250);
91
+ const beforePurge = await pill();
92
+ dropGPT = true;
93
+ // Force a refetch via swr revalidation — easiest is page.reload, but
94
+ // that wipes sessionStorage. Instead, just await the next swr cycle
95
+ // (5s by default). To speed things up, dispatch a focus event which
96
+ // triggers swr revalidateOnFocus. We expect the pin to clear once
97
+ // the vendor leaves the distribution.
98
+ await page.evaluate(() => window.dispatchEvent(new Event('focus')));
99
+ await page.waitForFunction(() => document.querySelectorAll('g[data-node]').length === 2, { timeout: 30000 });
100
+ await page.waitForTimeout(400);
101
+ const afterPurge = await pill();
102
+ const afterPurgeStorage = await storage();
103
+
104
+ await browser.close();
105
+
106
+ const results = {
107
+ before_noPill: before === null,
108
+ pinO_pillRendered: afterPinO !== null && /filter:?\s*O/.test(afterPinO.text),
109
+ pinO_countCorrect: afterPinO?.count === '1',
110
+ pinO_storage: afterPinOStorage === 'O',
111
+ bodyClick_clears: afterBodyClick === null,
112
+ pinA_pillRendered: afterPinA !== null && /filter:?\s*A/.test(afterPinA.text),
113
+ pinA_countCorrect: afterPinA?.count === '2',
114
+ xButton_clears: afterXButton === null,
115
+ beforePurge_present: beforePurge !== null && /filter:?\s*O/.test(beforePurge.text),
116
+ purge_pillGone: afterPurge === null,
117
+ purge_storageGone: afterPurgeStorage === null,
118
+ };
119
+ const ok = Object.values(results).every(Boolean);
120
+ console.log(`${ok ? '✅' : '❌'} vendor pill:`, JSON.stringify(results),
121
+ `\n afterPinO=`, afterPinO,
122
+ `\n afterPinA=`, afterPinA,
123
+ `\n beforePurge=`, beforePurge,
124
+ `\n afterPurge=`, afterPurge);
125
+ process.exit(ok ? 0 : 1);
@@ -0,0 +1,125 @@
1
+ /* Round 88 verification: clicking a vendor letter in the distribution
2
+ * chip toggles a sticky pin — closes the only filter dimension that
3
+ * still released on mouseleave (R60 status, R63 group, R69 Cmd+K all
4
+ * support pin). Composes via activeVendor = hoveredVendor ??
5
+ * pinnedVendor so hover still wins for spot comparison.
6
+ *
7
+ * Fleet: 2 Claude (alpha, gamma) + 1 GPT (beta). Click A → alpha + gamma
8
+ * stay bright across mouseleave; pinned-style boxShadow on the A
9
+ * letter; aria-pressed="true". Hover O while A pinned → transient O
10
+ * preview (alpha/gamma dim, beta lit); mouseleave → A pin restores.
11
+ * Esc clears the pin (R62/R63 universal-cancel extends to vendor).
12
+ * SessionStorage round-trips.
13
+ */
14
+ import { chromium } from 'playwright';
15
+ import { readFileSync } from 'node:fs';
16
+
17
+ const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
18
+ const browser = await chromium.launch({ headless: true });
19
+
20
+ const ctx = await browser.newContext({ viewport: { width: 1400, height: 1200 } });
21
+ await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
22
+ await ctx.addInitScript(() => {
23
+ try {
24
+ localStorage.setItem('anet-theme', 'cyber');
25
+ localStorage.setItem('anet-topo-layout', 'ring');
26
+ sessionStorage.setItem('anet_v3_auth', '1');
27
+ sessionStorage.removeItem('anet-topo-pinned-status');
28
+ sessionStorage.removeItem('anet-topo-pinned-group');
29
+ sessionStorage.removeItem('anet-topo-pinned-vendor');
30
+ } catch {}
31
+ });
32
+
33
+ const fresh = new Date(Date.now() - 60 * 1000).toISOString();
34
+ await ctx.route('**/api/hub/status*', async (route) => {
35
+ const r = await route.fetch();
36
+ const b = await r.json();
37
+ const nid = (b.sessions || [])[0]?.network_id || 'default';
38
+ const sessions = [
39
+ { alias: 'alpha', status: 'idle', model: 'claude-opus-4', runtime: 'cli-claude-code',
40
+ network_id: nid, project_dir: null, created_at: fresh, updated_at: fresh, last_seen_at: fresh },
41
+ { alias: 'beta', status: 'idle', model: 'gpt-5', runtime: 'codex-cli',
42
+ network_id: nid, project_dir: null, created_at: fresh, updated_at: fresh, last_seen_at: fresh },
43
+ { alias: 'gamma', status: 'idle', model: 'claude-opus-4', runtime: 'cli-claude-code',
44
+ network_id: nid, project_dir: null, created_at: fresh, updated_at: fresh, last_seen_at: fresh },
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 === 3, { timeout: 30000 });
53
+ await page.waitForTimeout(400);
54
+
55
+ const ops = () => page.evaluate(() => {
56
+ const o = {};
57
+ for (const a of ['alpha', 'beta', 'gamma']) {
58
+ const g = document.querySelector(`g[data-node="${a}"]`);
59
+ o[a] = g ? +(g.style.opacity || '1') : null;
60
+ }
61
+ return o;
62
+ });
63
+ const meta = () => page.evaluate(() => {
64
+ const a = document.querySelector('[data-vendor-letter="A"]');
65
+ const o = document.querySelector('[data-vendor-letter="O"]');
66
+ return {
67
+ A: { pinned: a?.getAttribute('data-vendor-pinned'), aria: a?.getAttribute('aria-pressed'), shadow: (a?.getAttribute('style') || '').includes('inset') },
68
+ O: { pinned: o?.getAttribute('data-vendor-pinned'), aria: o?.getAttribute('aria-pressed'), shadow: (o?.getAttribute('style') || '').includes('inset') },
69
+ };
70
+ });
71
+ const storage = () => page.evaluate(() => sessionStorage.getItem('anet-topo-pinned-vendor'));
72
+
73
+ const before = await ops();
74
+ const beforeMeta = await meta();
75
+
76
+ // Click A to pin. Mouse moves away — pin survives.
77
+ await page.locator('[data-vendor-letter="A"]').click();
78
+ await page.mouse.move(10, 10);
79
+ await page.waitForTimeout(300);
80
+ const afterClickA = await ops();
81
+ const afterClickAMeta = await meta();
82
+ const afterClickAStorage = await storage();
83
+
84
+ // Hover O while A pinned — transient O preview wins.
85
+ await page.locator('[data-vendor-letter="O"]').hover();
86
+ await page.waitForTimeout(250);
87
+ const hoverOWhilePinA = await ops();
88
+
89
+ // Leave — A pin restores.
90
+ await page.mouse.move(10, 10);
91
+ await page.waitForTimeout(250);
92
+ const leaveOWhilePinA = await ops();
93
+
94
+ // Esc clears the vendor pin.
95
+ await page.keyboard.press('Escape');
96
+ await page.waitForTimeout(250);
97
+ const afterEsc = await ops();
98
+ const afterEscMeta = await meta();
99
+ const afterEscStorage = await storage();
100
+
101
+ await browser.close();
102
+
103
+ const bright = (v) => v != null && v >= 0.55;
104
+ const dim = (v) => v != null && v < 0.4;
105
+ const results = {
106
+ before_baseline: bright(before.alpha) && bright(before.beta) && bright(before.gamma),
107
+ before_noPinMeta: beforeMeta.A.pinned === 'false' && beforeMeta.A.aria === 'false' && !beforeMeta.A.shadow,
108
+ pinA_keepsClaudes: bright(afterClickA.alpha) && bright(afterClickA.gamma),
109
+ pinA_dimsGPT: dim(afterClickA.beta),
110
+ pinA_metaSet: afterClickAMeta.A.pinned === 'true' && afterClickAMeta.A.aria === 'true' && afterClickAMeta.A.shadow,
111
+ pinA_storagePersisted: afterClickAStorage === 'A',
112
+ hoverOPinA_transientO: bright(hoverOWhilePinA.beta) && dim(hoverOWhilePinA.alpha) && dim(hoverOWhilePinA.gamma),
113
+ leaveOPinA_aRestored: bright(leaveOWhilePinA.alpha) && bright(leaveOWhilePinA.gamma) && dim(leaveOWhilePinA.beta),
114
+ esc_releasesPin: bright(afterEsc.alpha) && bright(afterEsc.beta) && bright(afterEsc.gamma),
115
+ esc_metaCleared: afterEscMeta.A.pinned === 'false' && afterEscMeta.A.aria === 'false' && !afterEscMeta.A.shadow,
116
+ esc_storageCleared: afterEscStorage === null,
117
+ };
118
+ const ok = Object.values(results).every(Boolean);
119
+ console.log(`${ok ? '✅' : '❌'} vendor pin:`, JSON.stringify(results),
120
+ `\n before=`, before,
121
+ `\n afterClickA=`, afterClickA,
122
+ `\n hoverOPinA=`, hoverOWhilePinA,
123
+ `\n leaveOPinA=`, leaveOWhilePinA,
124
+ `\n afterEsc=`, afterEsc);
125
+ process.exit(ok ? 0 : 1);