@sleep2agi/agent-network-dashboard 0.4.6-preview.22 → 0.4.6-preview.220

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 (422) hide show
  1. package/.next/BUILD_ID +1 -1
  2. package/.next/app-path-routes-manifest.json +1 -0
  3. package/.next/build-manifest.json +3 -3
  4. package/.next/diagnostics/route-bundle-stats.json +41 -41
  5. package/.next/fallback-build-manifest.json +3 -3
  6. package/.next/prerender-manifest.json +3 -3
  7. package/.next/routes-manifest.json +6 -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/servers/route/app-paths-manifest.json +3 -0
  34. package/.next/server/app/api/hub/servers/route/build-manifest.json +9 -0
  35. package/.next/server/app/api/hub/servers/route/server-reference-manifest.json +4 -0
  36. package/.next/server/app/api/hub/servers/route.js +7 -0
  37. package/.next/server/app/api/hub/servers/route.js.map +5 -0
  38. package/.next/server/app/api/hub/servers/route.js.nft.json +1 -0
  39. package/.next/server/app/api/hub/servers/route_client-reference-manifest.js +3 -0
  40. package/.next/server/app/index.html +2 -2
  41. package/.next/server/app/index.rsc +14 -14
  42. package/.next/server/app/index.segments/__PAGE__.segment.rsc +4 -4
  43. package/.next/server/app/index.segments/_full.segment.rsc +14 -14
  44. package/.next/server/app/index.segments/_head.segment.rsc +4 -4
  45. package/.next/server/app/index.segments/_index.segment.rsc +7 -7
  46. package/.next/server/app/index.segments/_tree.segment.rsc +2 -2
  47. package/.next/server/app/login/page_client-reference-manifest.js +1 -1
  48. package/.next/server/app/login.html +2 -2
  49. package/.next/server/app/login.rsc +14 -14
  50. package/.next/server/app/login.segments/_full.segment.rsc +14 -14
  51. package/.next/server/app/login.segments/_head.segment.rsc +4 -4
  52. package/.next/server/app/login.segments/_index.segment.rsc +7 -7
  53. package/.next/server/app/login.segments/_tree.segment.rsc +2 -2
  54. package/.next/server/app/login.segments/login/__PAGE__.segment.rsc +4 -4
  55. package/.next/server/app/login.segments/login.segment.rsc +3 -3
  56. package/.next/server/app/logs/page_client-reference-manifest.js +1 -1
  57. package/.next/server/app/logs.html +2 -2
  58. package/.next/server/app/logs.rsc +14 -14
  59. package/.next/server/app/logs.segments/_full.segment.rsc +14 -14
  60. package/.next/server/app/logs.segments/_head.segment.rsc +4 -4
  61. package/.next/server/app/logs.segments/_index.segment.rsc +7 -7
  62. package/.next/server/app/logs.segments/_tree.segment.rsc +2 -2
  63. package/.next/server/app/logs.segments/logs/__PAGE__.segment.rsc +4 -4
  64. package/.next/server/app/logs.segments/logs.segment.rsc +3 -3
  65. package/.next/server/app/messages/page_client-reference-manifest.js +1 -1
  66. package/.next/server/app/messages.html +2 -2
  67. package/.next/server/app/messages.rsc +14 -14
  68. package/.next/server/app/messages.segments/_full.segment.rsc +14 -14
  69. package/.next/server/app/messages.segments/_head.segment.rsc +4 -4
  70. package/.next/server/app/messages.segments/_index.segment.rsc +7 -7
  71. package/.next/server/app/messages.segments/_tree.segment.rsc +2 -2
  72. package/.next/server/app/messages.segments/messages/__PAGE__.segment.rsc +4 -4
  73. package/.next/server/app/messages.segments/messages.segment.rsc +3 -3
  74. package/.next/server/app/node/page_client-reference-manifest.js +1 -1
  75. package/.next/server/app/node.html +2 -2
  76. package/.next/server/app/node.rsc +14 -14
  77. package/.next/server/app/node.segments/_full.segment.rsc +14 -14
  78. package/.next/server/app/node.segments/_head.segment.rsc +4 -4
  79. package/.next/server/app/node.segments/_index.segment.rsc +7 -7
  80. package/.next/server/app/node.segments/_tree.segment.rsc +2 -2
  81. package/.next/server/app/node.segments/node/__PAGE__.segment.rsc +4 -4
  82. package/.next/server/app/node.segments/node.segment.rsc +3 -3
  83. package/.next/server/app/nodes/page_client-reference-manifest.js +1 -1
  84. package/.next/server/app/nodes.html +2 -2
  85. package/.next/server/app/nodes.rsc +14 -14
  86. package/.next/server/app/nodes.segments/_full.segment.rsc +14 -14
  87. package/.next/server/app/nodes.segments/_head.segment.rsc +4 -4
  88. package/.next/server/app/nodes.segments/_index.segment.rsc +7 -7
  89. package/.next/server/app/nodes.segments/_tree.segment.rsc +2 -2
  90. package/.next/server/app/nodes.segments/nodes/__PAGE__.segment.rsc +4 -4
  91. package/.next/server/app/nodes.segments/nodes.segment.rsc +3 -3
  92. package/.next/server/app/page_client-reference-manifest.js +1 -1
  93. package/.next/server/app/server-logs/page_client-reference-manifest.js +1 -1
  94. package/.next/server/app/server-logs.html +2 -2
  95. package/.next/server/app/server-logs.rsc +14 -14
  96. package/.next/server/app/server-logs.segments/_full.segment.rsc +14 -14
  97. package/.next/server/app/server-logs.segments/_head.segment.rsc +4 -4
  98. package/.next/server/app/server-logs.segments/_index.segment.rsc +7 -7
  99. package/.next/server/app/server-logs.segments/_tree.segment.rsc +2 -2
  100. package/.next/server/app/server-logs.segments/server-logs/__PAGE__.segment.rsc +4 -4
  101. package/.next/server/app/server-logs.segments/server-logs.segment.rsc +3 -3
  102. package/.next/server/app/settings/networks/page_client-reference-manifest.js +1 -1
  103. package/.next/server/app/settings/networks.html +2 -2
  104. package/.next/server/app/settings/networks.rsc +14 -14
  105. package/.next/server/app/settings/networks.segments/_full.segment.rsc +14 -14
  106. package/.next/server/app/settings/networks.segments/_head.segment.rsc +4 -4
  107. package/.next/server/app/settings/networks.segments/_index.segment.rsc +7 -7
  108. package/.next/server/app/settings/networks.segments/_tree.segment.rsc +2 -2
  109. package/.next/server/app/settings/networks.segments/settings/networks/__PAGE__.segment.rsc +4 -4
  110. package/.next/server/app/settings/networks.segments/settings/networks.segment.rsc +3 -3
  111. package/.next/server/app/settings/networks.segments/settings.segment.rsc +3 -3
  112. package/.next/server/app/settings/page_client-reference-manifest.js +1 -1
  113. package/.next/server/app/settings/tokens/page_client-reference-manifest.js +1 -1
  114. package/.next/server/app/settings/tokens.html +2 -2
  115. package/.next/server/app/settings/tokens.rsc +14 -14
  116. package/.next/server/app/settings/tokens.segments/_full.segment.rsc +14 -14
  117. package/.next/server/app/settings/tokens.segments/_head.segment.rsc +4 -4
  118. package/.next/server/app/settings/tokens.segments/_index.segment.rsc +7 -7
  119. package/.next/server/app/settings/tokens.segments/_tree.segment.rsc +2 -2
  120. package/.next/server/app/settings/tokens.segments/settings/tokens/__PAGE__.segment.rsc +4 -4
  121. package/.next/server/app/settings/tokens.segments/settings/tokens.segment.rsc +3 -3
  122. package/.next/server/app/settings/tokens.segments/settings.segment.rsc +3 -3
  123. package/.next/server/app/settings.html +2 -2
  124. package/.next/server/app/settings.rsc +14 -14
  125. package/.next/server/app/settings.segments/_full.segment.rsc +14 -14
  126. package/.next/server/app/settings.segments/_head.segment.rsc +4 -4
  127. package/.next/server/app/settings.segments/_index.segment.rsc +7 -7
  128. package/.next/server/app/settings.segments/_tree.segment.rsc +2 -2
  129. package/.next/server/app/settings.segments/settings/__PAGE__.segment.rsc +4 -4
  130. package/.next/server/app/settings.segments/settings.segment.rsc +3 -3
  131. package/.next/server/app/tasks/[id]/page_client-reference-manifest.js +1 -1
  132. package/.next/server/app/tasks/page_client-reference-manifest.js +1 -1
  133. package/.next/server/app/tasks.html +2 -2
  134. package/.next/server/app/tasks.rsc +14 -14
  135. package/.next/server/app/tasks.segments/_full.segment.rsc +14 -14
  136. package/.next/server/app/tasks.segments/_head.segment.rsc +4 -4
  137. package/.next/server/app/tasks.segments/_index.segment.rsc +7 -7
  138. package/.next/server/app/tasks.segments/_tree.segment.rsc +2 -2
  139. package/.next/server/app/tasks.segments/tasks/__PAGE__.segment.rsc +4 -4
  140. package/.next/server/app/tasks.segments/tasks.segment.rsc +3 -3
  141. package/.next/server/app-paths-manifest.json +1 -0
  142. package/.next/server/chunks/0ykm__next-internal_server_app_api_hub_servers_route_actions_08-m-cs.js +3 -0
  143. package/.next/server/chunks/0ykm__next-internal_server_app_api_hub_servers_route_actions_08-m-cs.js.map +1 -0
  144. package/.next/server/chunks/[root-of-the-server]__0tx8s8i._.js +3 -0
  145. package/.next/server/chunks/[root-of-the-server]__0tx8s8i._.js.map +1 -0
  146. package/.next/server/chunks/ssr/[root-of-the-server]__03b.f76._.js +1 -1
  147. package/.next/server/chunks/ssr/[root-of-the-server]__03b.f76._.js.map +1 -1
  148. package/.next/server/chunks/ssr/[root-of-the-server]__0fhoq8i._.js +1 -1
  149. package/.next/server/chunks/ssr/[root-of-the-server]__0fhoq8i._.js.map +1 -1
  150. package/.next/server/chunks/ssr/[root-of-the-server]__0nw~zhp._.js +1 -1
  151. package/.next/server/chunks/ssr/[root-of-the-server]__0nw~zhp._.js.map +1 -1
  152. package/.next/server/chunks/ssr/agent-network-dashboard_09kk21a._.js +4 -1
  153. package/.next/server/chunks/ssr/agent-network-dashboard_09kk21a._.js.map +1 -1
  154. package/.next/server/chunks/ssr/agent-network-dashboard_app_01jhlxz._.js +1 -1
  155. package/.next/server/chunks/ssr/agent-network-dashboard_app_01jhlxz._.js.map +1 -1
  156. package/.next/server/chunks/ssr/agent-network-dashboard_app_057q.ne._.js +1 -1
  157. package/.next/server/chunks/ssr/agent-network-dashboard_app_057q.ne._.js.map +1 -1
  158. package/.next/server/chunks/ssr/agent-network-dashboard_app_09d29my._.js +1 -1
  159. package/.next/server/chunks/ssr/agent-network-dashboard_app_09d29my._.js.map +1 -1
  160. package/.next/server/chunks/ssr/agent-network-dashboard_app_0_d45-d._.js +1 -1
  161. package/.next/server/chunks/ssr/agent-network-dashboard_app_0_d45-d._.js.map +1 -1
  162. package/.next/server/chunks/ssr/agent-network-dashboard_app_0i3759l._.js +1 -1
  163. package/.next/server/chunks/ssr/agent-network-dashboard_app_0i3759l._.js.map +1 -1
  164. package/.next/server/chunks/ssr/agent-network-dashboard_app_0xgney8._.js +1 -1
  165. package/.next/server/chunks/ssr/agent-network-dashboard_app_0xgney8._.js.map +1 -1
  166. package/.next/server/chunks/ssr/agent-network-dashboard_app_10hjgv4._.js +1 -1
  167. package/.next/server/chunks/ssr/agent-network-dashboard_app_10hjgv4._.js.map +1 -1
  168. package/.next/server/chunks/ssr/agent-network-dashboard_app_1153xeb._.js +1 -1
  169. package/.next/server/chunks/ssr/agent-network-dashboard_app_1153xeb._.js.map +1 -1
  170. package/.next/server/chunks/ssr/agent-network-dashboard_app_12l4oto._.js +1 -1
  171. package/.next/server/chunks/ssr/agent-network-dashboard_app_12l4oto._.js.map +1 -1
  172. package/.next/server/chunks/ssr/agent-network-dashboard_app_components_0mvyi-4._.js +1 -1
  173. package/.next/server/chunks/ssr/agent-network-dashboard_app_components_0mvyi-4._.js.map +1 -1
  174. package/.next/server/middleware-build-manifest.js +3 -3
  175. package/.next/server/pages/404.html +2 -2
  176. package/.next/server/pages/500.html +1 -1
  177. package/.next/server/server-reference-manifest.js +1 -1
  178. package/.next/server/server-reference-manifest.json +1 -1
  179. package/.next/static/chunks/0-mpa_947ipeq.js +1 -0
  180. package/.next/static/chunks/01lmbsd37fybu.js +1 -0
  181. package/.next/static/chunks/03o.h6kvmw4l_.js +1 -0
  182. package/.next/static/chunks/03~~oirxz7~vc.js +1 -0
  183. package/.next/static/chunks/05uk96gc~9mni.js +1 -0
  184. package/.next/static/chunks/08kf-.bgs10ze.js +1 -0
  185. package/.next/static/chunks/0da64ezyfmcem.js +1 -0
  186. package/.next/static/chunks/0ggj5ummw2a84.js +7 -0
  187. package/.next/static/chunks/0glmrdj9112tc.js +7 -0
  188. package/.next/static/chunks/0h5i3vkb6nloa.js +4 -0
  189. package/.next/static/chunks/0rxrez_cjn.eh.js +1 -0
  190. package/.next/static/chunks/0x8x.29hkju5a.js +1 -0
  191. package/.next/static/chunks/0~k1yvhakbob6.css +2 -0
  192. package/.next/static/chunks/16o3.7zw1l.-g.js +1 -0
  193. package/.next/static/chunks/174re5ar~kxne.js +1 -0
  194. package/.next/trace +2 -2
  195. package/.next/trace-build +1 -1
  196. package/.next/types/routes.d.ts +2 -1
  197. package/.next/types/validator.ts +9 -0
  198. package/app/api/hub/servers/route.ts +39 -0
  199. package/app/components/ChatPopover.tsx +38 -2
  200. package/app/components/CommandPalette.tsx +107 -0
  201. package/app/components/HelpOverlay.tsx +126 -0
  202. package/app/components/ServersDrawer.tsx +64 -27
  203. package/app/components/TopoGraph.tsx +4371 -256
  204. package/app/components/utils.ts +8 -7
  205. package/app/globals.css +110 -5
  206. package/app/lib/time.ts +36 -0
  207. package/package.json +1 -1
  208. package/scripts/help-overlay-topo-test.mjs +44 -0
  209. package/scripts/servers-drawer-live-test.mjs +96 -0
  210. package/scripts/topo-active-filter-pill-test.mjs +101 -0
  211. package/scripts/topo-active-links-chip-hover-test.mjs +103 -0
  212. package/scripts/topo-active-links-chip-nav-test.mjs +117 -0
  213. package/scripts/topo-active-links-chip-self-hover-test.mjs +171 -0
  214. package/scripts/topo-active-links-chip-test.mjs +73 -0
  215. package/scripts/topo-active-links-empty-recede-test.mjs +125 -0
  216. package/scripts/topo-active-links-freshness-test.mjs +113 -0
  217. package/scripts/topo-active-links-tooltip-test.mjs +79 -0
  218. package/scripts/topo-arrival-ping-test.mjs +87 -0
  219. package/scripts/topo-arrow-tier-test.mjs +61 -0
  220. package/scripts/topo-auto-fit-test.mjs +73 -0
  221. package/scripts/topo-canvas-aria-test.mjs +108 -0
  222. package/scripts/topo-chat-target-breath-test.mjs +84 -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-chrome-a11y-test.mjs +107 -0
  228. package/scripts/topo-chrome-press-state-test.mjs +135 -0
  229. package/scripts/topo-chrome-zoom-level-pop-test.mjs +122 -0
  230. package/scripts/topo-chrome-zoom-pop-test.mjs +130 -0
  231. package/scripts/topo-cmdk-edge-clear-test.mjs +109 -0
  232. package/scripts/topo-cmdk-layout-view-test.mjs +108 -0
  233. package/scripts/topo-cmdk-pin-test.mjs +123 -0
  234. package/scripts/topo-cmdk-vendor-clear-test.mjs +133 -0
  235. package/scripts/topo-cmdk-vendor-pin-test.mjs +103 -0
  236. package/scripts/topo-cwd-tooltip-test.mjs +64 -0
  237. package/scripts/topo-dblclick-reset-test.mjs +74 -0
  238. package/scripts/topo-dense-alias-fill-transition-test.mjs +133 -0
  239. package/scripts/topo-discrete-zoom-smooth-test.mjs +125 -0
  240. package/scripts/topo-dispatch-pulse-test.mjs +83 -0
  241. package/scripts/topo-edge-badge-click-pin-test.mjs +94 -0
  242. package/scripts/topo-edge-badge-hot-test.mjs +115 -0
  243. package/scripts/topo-edge-badge-hover-test.mjs +85 -0
  244. package/scripts/topo-edge-badge-lift-test.mjs +150 -0
  245. package/scripts/topo-edge-badge-ripple-test.mjs +111 -0
  246. package/scripts/topo-edge-badge-stroke-transition-test.mjs +118 -0
  247. package/scripts/topo-edge-count-badge-test.mjs +86 -0
  248. package/scripts/topo-edge-endpoint-highlight-test.mjs +111 -0
  249. package/scripts/topo-edge-fadein-test.mjs +106 -0
  250. package/scripts/topo-edge-focus-test.mjs +113 -0
  251. package/scripts/topo-edge-hover-test.mjs +93 -0
  252. package/scripts/topo-edge-pill-hot-test.mjs +129 -0
  253. package/scripts/topo-edge-pill-test.mjs +105 -0
  254. package/scripts/topo-edge-stroke-transition-test.mjs +132 -0
  255. package/scripts/topo-edge-tooltip-test.mjs +70 -0
  256. package/scripts/topo-empty-state-breath-test.mjs +150 -0
  257. package/scripts/topo-endpoint-ring-fade-test.mjs +132 -0
  258. package/scripts/topo-endpoint-ring-test.mjs +93 -0
  259. package/scripts/topo-esc-clears-pin-test.mjs +98 -0
  260. package/scripts/topo-filter-pill-aliases-test.mjs +121 -0
  261. package/scripts/topo-filter-pill-body-click-test.mjs +112 -0
  262. package/scripts/topo-filter-pill-count-test.mjs +110 -0
  263. package/scripts/topo-filter-pill-mobile-test.mjs +90 -0
  264. package/scripts/topo-fit-key-test.mjs +106 -0
  265. package/scripts/topo-freshness-chip-test.mjs +74 -0
  266. package/scripts/topo-freshness-chip-transition-test.mjs +80 -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 +68 -0
  270. package/scripts/topo-group-hover-test.mjs +82 -0
  271. package/scripts/topo-group-label-a11y-test.mjs +113 -0
  272. package/scripts/topo-group-label-hover-test.mjs +119 -0
  273. package/scripts/topo-group-label-tint-test.mjs +99 -0
  274. package/scripts/topo-group-label-title-test.mjs +83 -0
  275. package/scripts/topo-group-pin-test.mjs +119 -0
  276. package/scripts/topo-group-pip-fadein-test.mjs +100 -0
  277. package/scripts/topo-group-status-pips-test.mjs +103 -0
  278. package/scripts/topo-groupbox-fadein-test.mjs +95 -0
  279. package/scripts/topo-groupbox-hover-lift-test.mjs +127 -0
  280. package/scripts/topo-groupbox-live-test.mjs +100 -0
  281. package/scripts/topo-groupbox-march-busyness-test.mjs +155 -0
  282. package/scripts/topo-groupbox-test.mjs +4 -2
  283. package/scripts/topo-help-overlay-r109-test.mjs +67 -0
  284. package/scripts/topo-help-overlay-r118-test.mjs +69 -0
  285. package/scripts/topo-help-overlay-r123-test.mjs +69 -0
  286. package/scripts/topo-help-overlay-r134-test.mjs +74 -0
  287. package/scripts/topo-help-overlay-r137-test.mjs +81 -0
  288. package/scripts/topo-help-overlay-r141-test.mjs +86 -0
  289. package/scripts/topo-help-overlay-r153-test.mjs +85 -0
  290. package/scripts/topo-help-overlay-r59-test.mjs +67 -0
  291. package/scripts/topo-help-overlay-r65-test.mjs +64 -0
  292. package/scripts/topo-help-overlay-r70-test.mjs +63 -0
  293. package/scripts/topo-help-overlay-r78-test.mjs +59 -0
  294. package/scripts/topo-help-overlay-r81-test.mjs +58 -0
  295. package/scripts/topo-help-overlay-r87-test.mjs +64 -0
  296. package/scripts/topo-help-overlay-r91-test.mjs +65 -0
  297. package/scripts/topo-hub-a11y-test.mjs +112 -0
  298. package/scripts/topo-hub-busyness-test.mjs +100 -0
  299. package/scripts/topo-hub-center-crossfade-test.mjs +124 -0
  300. package/scripts/topo-hub-click-fit-test.mjs +137 -0
  301. package/scripts/topo-hub-digit-scale-test.mjs +129 -0
  302. package/scripts/topo-hub-fadein-test.mjs +88 -0
  303. package/scripts/topo-hub-hover-lift-test.mjs +101 -0
  304. package/scripts/topo-hub-hover-ring-test.mjs +82 -0
  305. package/scripts/topo-hub-title-test.mjs +93 -0
  306. package/scripts/topo-hub-working-count-test.mjs +99 -0
  307. package/scripts/topo-ingroup-edge-test.mjs +103 -0
  308. package/scripts/topo-label-lift-test.mjs +119 -0
  309. package/scripts/topo-label-scale-test.mjs +78 -0
  310. package/scripts/topo-lastseen-tooltip-test.mjs +59 -0
  311. package/scripts/topo-layout-key-test.mjs +91 -0
  312. package/scripts/topo-layout-switch-crossfade-test.mjs +126 -0
  313. package/scripts/topo-layout-toggle-test.mjs +131 -0
  314. package/scripts/topo-legend-count-empty-test.mjs +126 -0
  315. package/scripts/topo-legend-count-test.mjs +88 -0
  316. package/scripts/topo-legend-hover-test.mjs +113 -0
  317. package/scripts/topo-legend-panel-header-test.mjs +83 -0
  318. package/scripts/topo-legend-pin-ring-fade-test.mjs +112 -0
  319. package/scripts/topo-legend-pin-test.mjs +128 -0
  320. package/scripts/topo-legend-row-hover-lift-test.mjs +109 -0
  321. package/scripts/topo-legend-row-tint-test.mjs +95 -0
  322. package/scripts/topo-legend-row-title-test.mjs +102 -0
  323. package/scripts/topo-legend-swatch-grow-test.mjs +116 -0
  324. package/scripts/topo-minimap-a11y-test.mjs +101 -0
  325. package/scripts/topo-minimap-dot-transition-test.mjs +113 -0
  326. package/scripts/topo-minimap-test.mjs +68 -0
  327. package/scripts/topo-minimap-viewport-smooth-test.mjs +124 -0
  328. package/scripts/topo-mobile-chips-test.mjs +103 -0
  329. package/scripts/topo-node-a11y-test.mjs +107 -0
  330. package/scripts/topo-node-hover-lift-test.mjs +85 -0
  331. package/scripts/topo-node-label-card-elevation-test.mjs +157 -0
  332. package/scripts/topo-node-stroke-transition-test.mjs +103 -0
  333. package/scripts/topo-node-text-fill-transition-test.mjs +119 -0
  334. package/scripts/topo-node-title-peers-test.mjs +107 -0
  335. package/scripts/topo-node-title-test.mjs +101 -0
  336. package/scripts/topo-nodesize-active-hover-test.mjs +109 -0
  337. package/scripts/topo-nodesize-crossfade-test.mjs +141 -0
  338. package/scripts/topo-offline-dim-test.mjs +70 -0
  339. package/scripts/topo-online-chip-nav-test.mjs +143 -0
  340. package/scripts/topo-orbit-busyness-test.mjs +96 -0
  341. package/scripts/topo-overlap-test.mjs +32 -5
  342. package/scripts/topo-pan-cursor-test.mjs +62 -0
  343. package/scripts/topo-panel-elevation-test.mjs +76 -0
  344. package/scripts/topo-panel-fadein-test.mjs +102 -0
  345. package/scripts/topo-panel-hot-tail-fade-test.mjs +124 -0
  346. package/scripts/topo-panel-hover-elevation-test.mjs +118 -0
  347. package/scripts/topo-particle-stagger-test.mjs +82 -0
  348. package/scripts/topo-pin-intersection-empty-test.mjs +129 -0
  349. package/scripts/topo-pin-intersection-test.mjs +121 -0
  350. package/scripts/topo-pin-mirror-transition-test.mjs +101 -0
  351. package/scripts/topo-pin-persistence-test.mjs +105 -0
  352. package/scripts/topo-popover-meta-test.mjs +78 -0
  353. package/scripts/topo-pressure-bar-test.mjs +69 -0
  354. package/scripts/topo-pressure-hover-test.mjs +123 -0
  355. package/scripts/topo-pressure-pin-test.mjs +119 -0
  356. package/scripts/topo-pressure-seg-self-hover-test.mjs +126 -0
  357. package/scripts/topo-pressure-seg-tooltip-test.mjs +98 -0
  358. package/scripts/topo-pressure-seg-transition-test.mjs +107 -0
  359. package/scripts/topo-pulse-rate-test.mjs +71 -0
  360. package/scripts/topo-recent-panel-count-freshness-test.mjs +109 -0
  361. package/scripts/topo-recent-panel-count-test.mjs +72 -0
  362. package/scripts/topo-recent-panel-hot-header-test.mjs +132 -0
  363. package/scripts/topo-recent-panel-more-cyan-hover-test.mjs +151 -0
  364. package/scripts/topo-recent-panel-more-nav-test.mjs +127 -0
  365. package/scripts/topo-recent-panel-more-test.mjs +106 -0
  366. package/scripts/topo-recent-row-count-fill-test.mjs +129 -0
  367. package/scripts/topo-recent-row-fadein-test.mjs +107 -0
  368. package/scripts/topo-recent-row-freshness-test.mjs +102 -0
  369. package/scripts/topo-recent-row-hot-test.mjs +110 -0
  370. package/scripts/topo-recent-row-hover-lift-test.mjs +128 -0
  371. package/scripts/topo-recent-row-hover-test.mjs +122 -0
  372. package/scripts/topo-recent-row-pin-test.mjs +126 -0
  373. package/scripts/topo-recent-row-tint-test.mjs +91 -0
  374. package/scripts/topo-recent-row-title-test.mjs +112 -0
  375. package/scripts/topo-recent-row-ts-alpha-test.mjs +100 -0
  376. package/scripts/topo-recent-row-ts-test.mjs +95 -0
  377. package/scripts/topo-recent-row-typography-test.mjs +119 -0
  378. package/scripts/topo-recent-signal-empty-hint-test.mjs +73 -0
  379. package/scripts/topo-recent-signal-empty-test.mjs +63 -0
  380. package/scripts/topo-reduced-motion-test.mjs +77 -0
  381. package/scripts/topo-reset-spin-test.mjs +120 -0
  382. package/scripts/topo-runtime-badge-grow-test.mjs +114 -0
  383. package/scripts/topo-spoke-busyness-test.mjs +110 -0
  384. package/scripts/topo-status-chip-hover-test.mjs +101 -0
  385. package/scripts/topo-status-chip-tooltip-test.mjs +95 -0
  386. package/scripts/topo-statusbar-chips-self-hover-test.mjs +177 -0
  387. package/scripts/topo-svg-focus-test.mjs +112 -0
  388. package/scripts/topo-sweep-busyness-test.mjs +94 -0
  389. package/scripts/topo-tier-ring-fadein-test.mjs +107 -0
  390. package/scripts/topo-tier-ring-occupancy-test.mjs +87 -0
  391. package/scripts/topo-tier-ring-test.mjs +69 -0
  392. package/scripts/topo-tier-ring-tint-test.mjs +110 -0
  393. package/scripts/topo-tier-stagger-test.mjs +89 -0
  394. package/scripts/topo-tz-ghost-test.mjs +69 -0
  395. package/scripts/topo-vendor-chip-hover-test.mjs +111 -0
  396. package/scripts/topo-vendor-chip-self-hover-test.mjs +130 -0
  397. package/scripts/topo-vendor-letter-tooltip-test.mjs +92 -0
  398. package/scripts/topo-vendor-pill-test.mjs +125 -0
  399. package/scripts/topo-vendor-pin-test.mjs +125 -0
  400. package/scripts/topo-view-smooth-test.mjs +131 -0
  401. package/scripts/topo-wheel-zoom-test.mjs +79 -0
  402. package/scripts/topo-working-chip-pin-test.mjs +154 -0
  403. package/scripts/topo-working-halo-breath-test.mjs +86 -0
  404. package/scripts/topo-zoom-keys-test.mjs +89 -0
  405. package/.next/static/chunks/0-7iowzu4.798.js +0 -1
  406. package/.next/static/chunks/02t5jr4shh.hy.js +0 -1
  407. package/.next/static/chunks/09nd.t_hd.y6t.css +0 -2
  408. package/.next/static/chunks/0_qfg5s5uzs7..js +0 -7
  409. package/.next/static/chunks/0elalb9n_.~di.js +0 -1
  410. package/.next/static/chunks/0fqy_0wj_1xa7.js +0 -7
  411. package/.next/static/chunks/0j_q__o8p6g83.js +0 -1
  412. package/.next/static/chunks/0jl6_w50zh4l5.js +0 -1
  413. package/.next/static/chunks/0n0t~-gcuxjal.js +0 -1
  414. package/.next/static/chunks/0r4q73.-1bkyl.js +0 -1
  415. package/.next/static/chunks/0r_c8eccg3z2o.js +0 -1
  416. package/.next/static/chunks/0ztnqa~vzxbbs.js +0 -1
  417. package/.next/static/chunks/10oi7l-tycgl9.js +0 -1
  418. package/.next/static/chunks/11uk1izuv3~0t.js +0 -1
  419. package/.next/static/chunks/17jybqi.k7lrd.js +0 -1
  420. /package/.next/static/{Fb5M4fLP--Xb56NsSE-Bw → WwoMVd5LJf4yU99_Ggd23}/_buildManifest.js +0 -0
  421. /package/.next/static/{Fb5M4fLP--Xb56NsSE-Bw → WwoMVd5LJf4yU99_Ggd23}/_clientMiddlewareManifest.js +0 -0
  422. /package/.next/static/{Fb5M4fLP--Xb56NsSE-Bw → WwoMVd5LJf4yU99_Ggd23}/_ssgManifest.js +0 -0
@@ -0,0 +1,126 @@
1
+ /* Round 210 verification: pressure-bar segments deepen their OWN
2
+ * colour on hover via filter: brightness(1.2). Closes the chip-row
3
+ * "hover deepens own identity" family at a 6th surface (the
4
+ * pressure-bar scope previously had R83 wire setHoveredStatus but
5
+ * the segment itself stayed flat).
6
+ *
7
+ * Pre-R210 hovering a segment fired R55 canvas dim via
8
+ * setHoveredStatus, but the segment's own background stayed at the
9
+ * unmodified tier color. R210 makes the cause element (segment)
10
+ * light up the same gesture it fires on the canvas (effect element).
11
+ *
12
+ * Test (cyber dark, 2 working + 1 idle + 1 offline → 3 segments):
13
+ * 1. 3 [data-pressure-seg] segments rendered.
14
+ * 2. Idle: every segment has hovered='false', filter='none' (or
15
+ * no filter style set).
16
+ * 3. Inline transition includes 'filter 150ms' alongside the
17
+ * existing R165 width 220ms + R60 box-shadow 150ms.
18
+ * 4. Hover working segment → working hovered='true', filter
19
+ * 'brightness(1.2)'.
20
+ * 5. Other (idle/offline) segments stay hovered='false', no filter.
21
+ * 6. Move away → working back to hovered='false', no filter.
22
+ */
23
+ import { chromium } from 'playwright';
24
+ import { readFileSync } from 'node:fs';
25
+
26
+ const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
27
+ const browser = await chromium.launch({ headless: true });
28
+
29
+ const ctx = await browser.newContext({ viewport: { width: 1500, height: 1500 } });
30
+ await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
31
+ await ctx.addInitScript(() => {
32
+ try { localStorage.setItem('anet-theme', 'cyber'); sessionStorage.setItem('anet_v3_auth', '1'); } catch {}
33
+ });
34
+
35
+ const fresh = new Date(Date.now() - 60 * 1000).toISOString();
36
+ await ctx.route('**/api/hub/status*', async (route) => {
37
+ const r = await route.fetch();
38
+ const b = await r.json();
39
+ const nid = (b.sessions || [])[0]?.network_id || 'default';
40
+ const mk = (alias, status) => ({
41
+ alias, status, model: 'claude-opus-4', runtime: 'claude-code-cli',
42
+ network_id: nid, project_dir: null,
43
+ created_at: fresh, updated_at: fresh, last_seen_at: fresh,
44
+ });
45
+ await route.fulfill({ response: r, json: { ...b, sessions: [
46
+ mk('alpha', 'working'),
47
+ mk('beta', 'working'),
48
+ mk('gamma', 'idle'),
49
+ mk('delta', 'offline'),
50
+ ] } });
51
+ });
52
+ await ctx.route('**/api/hub/messages*', (r2) => r2.fulfill({ json: { messages: [] } }));
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-pressure-seg="working"]', { timeout: 10000 });
59
+ await page.waitForTimeout(300);
60
+
61
+ const probe = async () => page.evaluate(() => {
62
+ return [...document.querySelectorAll('[data-pressure-seg]')].map(el => {
63
+ const cs = getComputedStyle(el);
64
+ return {
65
+ key: el.getAttribute('data-pressure-seg'),
66
+ hovered: el.getAttribute('data-pressure-seg-hovered'),
67
+ filter: cs.filter,
68
+ inlineFilter: el.style.filter,
69
+ transition: el.style.transition,
70
+ };
71
+ });
72
+ });
73
+
74
+ const idle = await probe();
75
+
76
+ await page.hover('[data-pressure-seg="working"]');
77
+ await page.waitForTimeout(180);
78
+ const hovered = await probe();
79
+
80
+ await page.mouse.move(0, 0);
81
+ await page.waitForTimeout(180);
82
+ const settled = await probe();
83
+
84
+ await browser.close();
85
+
86
+ const idleWorking = idle.find(s => s.key === 'working');
87
+ const idleIdle = idle.find(s => s.key === 'idle');
88
+ const idleOffline = idle.find(s => s.key === 'offline');
89
+ const hovWorking = hovered.find(s => s.key === 'working');
90
+ const hovIdle = hovered.find(s => s.key === 'idle');
91
+ const settledWorking = settled.find(s => s.key === 'working');
92
+
93
+ const isNoFilter = (s) => !s || s === 'none' || s === '';
94
+ const hasBrightness = (s) => /brightness\s*\(\s*1\.2/.test(s || '');
95
+
96
+ const results = {
97
+ three_segments_present: idle.length === 3,
98
+ working_found: !!idleWorking,
99
+ idle_found: !!idleIdle,
100
+ offline_found: !!idleOffline,
101
+
102
+ // Idle: no filter, hovered='false', transitions present
103
+ idle_all_not_hovered: idle.every(s => s.hovered === 'false'),
104
+ idle_all_no_filter: idle.every(s => isNoFilter(s.inlineFilter)),
105
+ transitions_have_filter: idle.every(s => /filter\s+(?:150ms|0\.15s)/.test(s.transition || '')),
106
+ transitions_keep_width: idle.every(s => /width\s+(?:220ms|0\.22s)/.test(s.transition || '')),
107
+ transitions_keep_bs: idle.every(s => /box-shadow\s+(?:150ms|0\.15s)/.test(s.transition || '')),
108
+
109
+ // Hover working: brightness applied
110
+ hov_working_hovered_true: hovWorking?.hovered === 'true',
111
+ hov_working_has_filter: hasBrightness(hovWorking?.inlineFilter)
112
+ || hasBrightness(hovWorking?.filter),
113
+ // Other segments stay idle
114
+ hov_idle_stays_false: hovIdle?.hovered === 'false',
115
+ hov_idle_no_filter: isNoFilter(hovIdle?.inlineFilter),
116
+
117
+ // Settled: back to idle
118
+ settled_hovered_false: settledWorking?.hovered === 'false',
119
+ settled_no_filter: isNoFilter(settledWorking?.inlineFilter),
120
+ };
121
+ const ok = Object.values(results).every(Boolean);
122
+ console.log(`${ok ? '✅' : '❌'} pressure-seg self-hover:`, JSON.stringify(results),
123
+ `\n idle:`, idle,
124
+ `\n hovered:`, hovered,
125
+ `\n settled:`, settled);
126
+ process.exit(ok ? 0 : 1);
@@ -0,0 +1,98 @@
1
+ /* Round 102 verification: pressure-bar segment tooltips list the
2
+ * aliases that fall into that status bucket. Closes the last "how
3
+ * many but not which" gap in the chip-row surfaces. Composes with
4
+ * the existing R83 hover preview (canvas dims still answer it
5
+ * visually too) — this adds a screen-reader-friendly textual
6
+ * channel for the same info.
7
+ *
8
+ * Fleet: 2 working + 2 idle + 1 offline. Verify each segment's
9
+ * title contains the matching aliases + action hint; data-pressure-
10
+ * seg-aliases attr carries the full CSV.
11
+ */
12
+ import { chromium } from 'playwright';
13
+ import { readFileSync } from 'node:fs';
14
+
15
+ const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
16
+ const browser = await chromium.launch({ headless: true });
17
+
18
+ const ctx = await browser.newContext({ viewport: { width: 1400, height: 1500 } });
19
+ await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
20
+ await ctx.addInitScript(() => {
21
+ try {
22
+ localStorage.setItem('anet-theme', 'cyber');
23
+ sessionStorage.setItem('anet_v3_auth', '1');
24
+ sessionStorage.removeItem('anet-topo-pinned-status');
25
+ } catch {}
26
+ });
27
+
28
+ const fresh = new Date(Date.now() - 60 * 1000).toISOString();
29
+ const stale10 = new Date(Date.now() - 10 * 60 * 1000).toISOString();
30
+ await ctx.route('**/api/hub/status*', async (route) => {
31
+ const r = await route.fetch();
32
+ const b = await r.json();
33
+ const nid = (b.sessions || [])[0]?.network_id || 'default';
34
+ const mk = (alias, status, ts) => ({
35
+ alias, status, model: 'claude-opus-4', runtime: 'cli-claude-code',
36
+ network_id: nid, project_dir: null,
37
+ created_at: ts, updated_at: ts, last_seen_at: ts,
38
+ });
39
+ await route.fulfill({ response: r, json: { ...b, sessions: [
40
+ mk('wkr1', 'working', fresh),
41
+ mk('wkr2', 'working', fresh),
42
+ mk('idl1', 'idle', fresh),
43
+ mk('idl2', 'idle', fresh),
44
+ mk('off1', 'offline', stale10),
45
+ ] } });
46
+ });
47
+ await ctx.route('**/api/hub/messages*', (route) => route.fulfill({ json: { messages: [] } }));
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 === 5, { timeout: 30000 });
52
+ await page.waitForTimeout(400);
53
+
54
+ const read = (key) => page.evaluate((k) => {
55
+ const el = document.querySelector(`[data-pressure-seg="${k}"]`);
56
+ if (!el) return null;
57
+ return {
58
+ title: el.getAttribute('title') || '',
59
+ aliases: el.getAttribute('data-pressure-seg-aliases') || '',
60
+ };
61
+ }, key);
62
+
63
+ const working = await read('working');
64
+ const idle = await read('idle');
65
+ const offline = await read('offline');
66
+
67
+ // Pin working — action hint should flip in the title.
68
+ await page.locator('[data-pressure-seg="working"]').click();
69
+ await page.waitForTimeout(250);
70
+ const workingPinned = await read('working');
71
+
72
+ await browser.close();
73
+
74
+ const sameSet = (csv, expected) => {
75
+ const got = new Set(csv.split(',').filter(Boolean));
76
+ const exp = new Set(expected);
77
+ return got.size === exp.size && [...exp].every(x => got.has(x));
78
+ };
79
+
80
+ const results = {
81
+ working_aliasesMatch: sameSet(working?.aliases || '', ['wkr1', 'wkr2']),
82
+ working_titleListsThem: /wkr1.*wkr2|wkr2.*wkr1/.test(working?.title || ''),
83
+ working_titleClickHint: /click to highlight/.test(working?.title || ''),
84
+ working_titleStatusN: /^2 working/m.test(working?.title || ''),
85
+ idle_aliasesMatch: sameSet(idle?.aliases || '', ['idl1', 'idl2']),
86
+ idle_titleListsThem: /idl1.*idl2|idl2.*idl1/.test(idle?.title || ''),
87
+ offline_aliasesMatch: sameSet(offline?.aliases || '', ['off1']),
88
+ offline_titleListsThem: /off1/.test(offline?.title || ''),
89
+ workingPin_aliasesStable: sameSet(workingPinned?.aliases || '', ['wkr1', 'wkr2']),
90
+ workingPin_hintFlipped: /click to release filter/.test(workingPinned?.title || ''),
91
+ };
92
+ const ok = Object.values(results).every(Boolean);
93
+ console.log(`${ok ? '✅' : '❌'} pressure-seg tooltip:`, JSON.stringify(results),
94
+ `\n working:`, working,
95
+ `\n idle:`, idle,
96
+ `\n offline:`, offline,
97
+ `\n workingPinned:`, workingPinned);
98
+ process.exit(ok ? 0 : 1);
@@ -0,0 +1,107 @@
1
+ /* Round 165 verification: pressure-bar segments smoothly
2
+ * transition their widths.
3
+ *
4
+ * Pre-R165 segment widths snapped instantly when fleet
5
+ * composition shifted (e.g., a node going idle → working).
6
+ * R165 adds `transition: width 220ms ease-out, box-shadow
7
+ * 150ms ease-out` on each <span data-pressure-seg> inline
8
+ * style — smooths the breath, doesn't change semantics.
9
+ *
10
+ * Tests:
11
+ * 1. All segments carry the inline transition declaration
12
+ * 2. Pin one segment → boxShadow string changes (R60 idiom)
13
+ * 3. Width attribute is a percentage of (n/total)*100
14
+ */
15
+ import { chromium } from 'playwright';
16
+ import { readFileSync } from 'node:fs';
17
+
18
+ const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
19
+ const browser = await chromium.launch({ headless: true });
20
+
21
+ const ctx = await browser.newContext({ viewport: { width: 1500, height: 1500 } });
22
+ await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
23
+ await ctx.addInitScript(() => {
24
+ try { localStorage.setItem('anet-theme', 'cyber'); sessionStorage.setItem('anet_v3_auth', '1'); } catch {}
25
+ });
26
+
27
+ const fresh = new Date(Date.now() - 60 * 1000).toISOString();
28
+ const stale = new Date(Date.now() - 10 * 60 * 1000).toISOString();
29
+ await ctx.route('**/api/hub/status*', async (route) => {
30
+ const r = await route.fetch();
31
+ const b = await r.json();
32
+ const nid = (b.sessions || [])[0]?.network_id || 'default';
33
+ const mk = (alias, status, last) => ({
34
+ alias, status, model: 'claude-opus-4', runtime: 'cli-claude-code',
35
+ network_id: nid, project_dir: null,
36
+ created_at: last, updated_at: last, last_seen_at: last,
37
+ });
38
+ // 3 working + 2 idle + 1 offline = 6 total
39
+ await route.fulfill({ response: r, json: { ...b, sessions: [
40
+ mk('a1', 'working', fresh), mk('a2', 'working', fresh), mk('a3', 'working', fresh),
41
+ mk('b1', 'idle', fresh), mk('b2', 'idle', fresh),
42
+ mk('c1', 'offline', stale),
43
+ ] } });
44
+ });
45
+ await ctx.route('**/api/hub/messages*', (route) => route.fulfill({ json: { messages: [] } }));
46
+ await ctx.route('**/api/hub/tasks*', (route) => route.fulfill({ json: { tasks: [] } }));
47
+
48
+ const page = await ctx.newPage();
49
+ await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
50
+ await page.waitForFunction(() => document.querySelectorAll('g[data-node]').length === 6, { timeout: 30000 });
51
+ await page.waitForSelector('[data-pressure-seg]', { timeout: 10000 });
52
+ await page.waitForTimeout(400);
53
+
54
+ const probe = await page.evaluate(() => {
55
+ const segs = ['working', 'idle', 'offline'].map(k => {
56
+ const el = document.querySelector(`[data-pressure-seg="${k}"]`);
57
+ if (!el) return null;
58
+ // Inline style is what we wrote; window.getComputedStyle reports the
59
+ // resolved value (which for `transition` is the long form).
60
+ const inlineTransition = el.style.transition || '';
61
+ const computedTransition = getComputedStyle(el).transition || '';
62
+ return {
63
+ key: k,
64
+ width: el.style.width,
65
+ inlineTransition,
66
+ // Match either width 220ms OR the resolved computed form.
67
+ hasTransitionWidth:
68
+ inlineTransition.includes('width 220ms') ||
69
+ /width\s+0\.22s|width\s+220ms/.test(computedTransition),
70
+ hasTransitionBoxShadow:
71
+ inlineTransition.includes('box-shadow 150ms') ||
72
+ /box-shadow\s+0\.15s|box-shadow\s+150ms/.test(computedTransition),
73
+ };
74
+ });
75
+ return segs;
76
+ });
77
+
78
+ // Pin the idle segment → boxShadow should appear (R60 inset rings)
79
+ const boxBeforePin = await page.evaluate(() => {
80
+ const el = document.querySelector('[data-pressure-seg="idle"]');
81
+ return el ? el.style.boxShadow : null;
82
+ });
83
+ await page.locator('[data-pressure-seg="idle"]').click({ force: true });
84
+ await page.waitForTimeout(300);
85
+ const boxAfterPin = await page.evaluate(() => {
86
+ const el = document.querySelector('[data-pressure-seg="idle"]');
87
+ return el ? el.style.boxShadow : null;
88
+ });
89
+
90
+ await browser.close();
91
+
92
+ const allOk = probe.every(p => p && p.hasTransitionWidth && p.hasTransitionBoxShadow);
93
+ const results = {
94
+ three_segs_present: probe.length === 3 && probe.every(p => p !== null),
95
+ all_have_transition_width: probe.every(p => p?.hasTransitionWidth),
96
+ all_have_transition_boxShadow: probe.every(p => p?.hasTransitionBoxShadow),
97
+ working_width_50: probe[0]?.width === '50%', // 3/6
98
+ idle_width_33: /33\.3|33%/.test(probe[1]?.width || ''), // 2/6
99
+ offline_width_16: /16\.6|16%/.test(probe[2]?.width || ''), // 1/6
100
+ pin_changes_boxShadow: boxBeforePin === '' && boxAfterPin !== '',
101
+ overall: allOk,
102
+ };
103
+ const ok = Object.values(results).every(Boolean);
104
+ console.log(`${ok ? '✅' : '❌'} pressure-seg transition:`, JSON.stringify(results),
105
+ `\n probes=`, probe,
106
+ `\n box before/after pin =`, JSON.stringify(boxBeforePin), '→', JSON.stringify(boxAfterPin));
107
+ process.exit(ok ? 0 : 1);
@@ -0,0 +1,71 @@
1
+ /* Round 24 verification: working-node pulse duration tiers by sse:N.
2
+ * sse 0-1 → 1.2s (calm)
3
+ * sse 2-3 → 0.9s (active)
4
+ * sse ≥ 4 → 0.7s (busy)
5
+ * Inject sse counts via mocked /api/hub/health → sse_sessions map. */
6
+ import { chromium } from 'playwright';
7
+ import { readFileSync } from 'node:fs';
8
+
9
+ const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
10
+ const browser = await chromium.launch({ headless: true });
11
+
12
+ const ctx = await browser.newContext({ viewport: { width: 1280, height: 900 } });
13
+ await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
14
+ await ctx.addInitScript(() => {
15
+ try {
16
+ localStorage.setItem('anet-theme', 'cyber');
17
+ localStorage.setItem('anet-topo-layout', 'grid');
18
+ sessionStorage.setItem('anet_v3_auth', '1');
19
+ } catch {}
20
+ });
21
+ const fresh = new Date(Date.now() - 60 * 1000).toISOString();
22
+ // Three working sessions with different sse counts. Use a known network_id
23
+ // so the `${nid}:${alias}` sse-map key works (the page's grouped lookup).
24
+ const NID = 'net_test';
25
+ await ctx.route('**/api/hub/status*', async (route) => {
26
+ await route.fulfill({ json: {
27
+ ok: true,
28
+ sessions: ['calm', 'active', 'busy'].map(alias => ({
29
+ alias, status: 'working', network_id: NID, project_dir: null,
30
+ created_at: fresh, updated_at: fresh, last_seen_at: fresh,
31
+ })),
32
+ } });
33
+ });
34
+ await ctx.route('**/api/hub/health*', async (route) => {
35
+ await route.fulfill({ json: {
36
+ ok: true,
37
+ version: '0.8.0-test',
38
+ sse_sessions: {
39
+ [`${NID}:calm`]: 1,
40
+ [`${NID}:active`]: 2,
41
+ [`${NID}:busy`]: 4,
42
+ },
43
+ } });
44
+ });
45
+ await ctx.route('**/api/hub/tasks*', (route) => route.fulfill({ json: { tasks: [] } }));
46
+ const page = await ctx.newPage();
47
+ await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
48
+ await page.waitForFunction(() => {
49
+ const svg = document.querySelector('svg[viewBox="0 0 1000 680"]');
50
+ return !!svg && svg.querySelectorAll('g[data-node]').length === 3;
51
+ }, { timeout: 30000 }).catch(() => {});
52
+ await page.waitForTimeout(600);
53
+
54
+ const durOf = alias => page.$eval(
55
+ `g[data-node="${alias}"] circle[data-pulse-dur]`,
56
+ el => el.getAttribute('data-pulse-dur'),
57
+ ).catch(() => null);
58
+
59
+ const calm = await durOf('calm');
60
+ const active = await durOf('active');
61
+ const busy = await durOf('busy');
62
+
63
+ await browser.close();
64
+ const results = {
65
+ calmIs1_2s: calm === '1.2s',
66
+ activeIs0_9s: active === '0.9s',
67
+ busyIs0_7s: busy === '0.7s',
68
+ };
69
+ const ok = Object.values(results).every(Boolean);
70
+ console.log(`${ok ? '✅' : '❌'} pulse rate:`, JSON.stringify(results), `calm=${calm} active=${active} busy=${busy}`);
71
+ process.exit(ok ? 0 : 1);
@@ -0,0 +1,109 @@
1
+ /* Round 162 verification: recent-signal panel header "N flows"
2
+ * tspan picks up the R160/R161 freshness vocabulary.
3
+ *
4
+ * R10 fades canvas edge by freshness (per-edge stroke opacity)
5
+ * R160 brought it to the recent-signal panel rows (per-flow pip)
6
+ * R161 brought it to the chip-row "active links" chip bullet
7
+ * (fleet aggregate in the chip-row above the SVG)
8
+ * R162 brings it to the recent-signal panel HEADER count
9
+ * (fleet aggregate inside the SVG corner)
10
+ *
11
+ * The chip-row "N active links · last 5s" and the panel-header
12
+ * "N flows" show the same metric at two scopes. R161 tinted the
13
+ * chip-row side; R162 tints the panel-side mirror so both
14
+ * scopes speak the same freshness vocabulary side-by-side.
15
+ *
16
+ * Same alpha ramp as R160/R161:
17
+ * ageSec ≤ 30 → 1.0 (fully fresh)
18
+ * 30-300s → smooth decay 1.0 → 0.25
19
+ * > 300s → 0.25 stale floor
20
+ *
21
+ * Hot tail (R129 amber " · N hot") is volume-tinted and stays
22
+ * unchanged — recency tints the head; volume colors the tail.
23
+ *
24
+ * Test: 3 page loads, 5s / 90s / 360s ago.
25
+ */
26
+ import { chromium } from 'playwright';
27
+ import { readFileSync } from 'node:fs';
28
+
29
+ const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
30
+ const browser = await chromium.launch({ headless: true });
31
+
32
+ const ctx = await browser.newContext({ viewport: { width: 1500, height: 1500 } });
33
+ await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
34
+ await ctx.addInitScript(() => {
35
+ try { localStorage.setItem('anet-theme', 'cyber'); sessionStorage.setItem('anet_v3_auth', '1'); } catch {}
36
+ });
37
+
38
+ async function probe(msgAgeSec) {
39
+ const fresh = new Date(Date.now() - 60 * 1000).toISOString();
40
+ await ctx.unroute('**/api/hub/status*').catch(() => {});
41
+ await ctx.unroute('**/api/hub/messages*').catch(() => {});
42
+ await ctx.unroute('**/api/hub/tasks*').catch(() => {});
43
+ await ctx.route('**/api/hub/status*', async (route) => {
44
+ const r = await route.fetch();
45
+ const b = await r.json();
46
+ const nid = (b.sessions || [])[0]?.network_id || 'default';
47
+ const mk = (alias) => ({
48
+ alias, status: 'working', model: 'claude-opus-4', runtime: 'cli-claude-code',
49
+ network_id: nid, project_dir: null,
50
+ created_at: fresh, updated_at: fresh, last_seen_at: fresh,
51
+ });
52
+ await route.fulfill({ response: r, json: { ...b, sessions: [mk('alpha'), mk('beta')] } });
53
+ });
54
+ await ctx.route('**/api/hub/messages*', (route) => route.fulfill({ json: { messages: [
55
+ { id: 'x', from_alias: 'alpha', to_alias: 'beta', content: 'hi',
56
+ network_id: 'default', created_at: new Date(Date.now() - msgAgeSec * 1000).toISOString() },
57
+ ] } }));
58
+ await ctx.route('**/api/hub/tasks*', (route) => route.fulfill({ json: { tasks: [] } }));
59
+
60
+ const page = await ctx.newPage();
61
+ await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
62
+ await page.waitForFunction(() => document.querySelectorAll('g[data-node]').length === 2, { timeout: 30000 });
63
+ await page.waitForSelector('[data-recent-panel-count]', { timeout: 10000 });
64
+ await page.waitForTimeout(400);
65
+ const out = await page.evaluate(() => {
66
+ const el = document.querySelector('[data-recent-panel-count]');
67
+ if (!el) return null;
68
+ // SVG tspan fill attribute is the source of truth — getComputedStyle on
69
+ // tspan returns nothing useful on some browsers.
70
+ return {
71
+ alpha: parseFloat(el.getAttribute('data-recent-panel-count-freshness-alpha') || ''),
72
+ fill: el.getAttribute('fill') || '',
73
+ text: el.textContent,
74
+ };
75
+ });
76
+ await page.close();
77
+ return out;
78
+ }
79
+
80
+ const A = await probe(5); // fresh
81
+ const B = await probe(90); // mid
82
+ const C = await probe(360); // stale
83
+
84
+ await browser.close();
85
+
86
+ const cyanRgb = (str) => {
87
+ const m = /rgba?\((\d+),\s*(\d+),\s*(\d+)/.exec(str);
88
+ if (!m) return null;
89
+ return [Number(m[1]), Number(m[2]), Number(m[3])];
90
+ };
91
+
92
+ const results = {
93
+ fresh_dot_found: A !== null,
94
+ mid_dot_found: B !== null,
95
+ stale_dot_found: C !== null,
96
+ fresh_alpha_1: A && Math.abs(A.alpha - 1.0) < 0.05,
97
+ mid_alpha_window: B && B.alpha > 0.7 && B.alpha < 0.95,
98
+ stale_alpha_floor: C && Math.abs(C.alpha - 0.25) < 0.05,
99
+ fresh_color_cyan: A && JSON.stringify(cyanRgb(A.fill)) === '[34,211,238]',
100
+ stale_alpha_in_fill: C && /0\.25/.test(C.fill),
101
+ ladder_descends: A && B && C && A.alpha > B.alpha && B.alpha > C.alpha,
102
+ text_says_1_flow: A && /1 flow/.test(A.text || ''),
103
+ };
104
+ const ok = Object.values(results).every(Boolean);
105
+ console.log(`${ok ? '✅' : '❌'} panel-header count freshness:`, JSON.stringify(results),
106
+ `\n fresh =`, A,
107
+ `\n mid =`, B,
108
+ `\n stale =`, C);
109
+ process.exit(ok ? 0 : 1);
@@ -0,0 +1,72 @@
1
+ /* Round 96 verification: the recent-signal panel header count now
2
+ * reads "X flows" off flowLinks.length (matching the deduped rows
3
+ * below), not "X msgs" off the raw messages.length. Pre-R96 a
4
+ * fleet with 10 messages aggregating to 3 unique pairs read
5
+ * "10 msgs" above only 3 rendered rows — read as broken.
6
+ *
7
+ * Mock 5 messages between 2 distinct pairs: alpha↔beta gets 4
8
+ * msgs (4 separate exchanges, dedupes to 1 flow), gamma→delta
9
+ * gets 1 msg (1 flow). Total = 5 msgs, 2 flows. Header should
10
+ * show "2 flows", panel renders 2 rows.
11
+ */
12
+ import { chromium } from 'playwright';
13
+ import { readFileSync } from 'node:fs';
14
+
15
+ const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
16
+ const browser = await chromium.launch({ headless: true });
17
+
18
+ const ctx = await browser.newContext({ viewport: { width: 1400, height: 1500 } });
19
+ await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
20
+ await ctx.addInitScript(() => {
21
+ try { localStorage.setItem('anet-theme', 'cyber'); sessionStorage.setItem('anet_v3_auth', '1'); } catch {}
22
+ });
23
+
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) => ({
30
+ alias, status: 'idle', model: 'claude-opus-4', runtime: 'cli-claude-code',
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: [mk('alpha'), mk('beta'), mk('gamma'), mk('delta')] } });
35
+ });
36
+
37
+ const now = Date.now();
38
+ const mkMsg = (id, from_alias, to_alias, content, ageMs) => ({
39
+ id, from_alias, to_alias, content, network_id: 'default',
40
+ created_at: new Date(now - ageMs).toISOString(),
41
+ });
42
+ // 5 messages → 2 flow pairs (alpha→beta × 4, gamma→delta × 1).
43
+ await ctx.route('**/api/hub/messages*', (route) => route.fulfill({ json: { messages: [
44
+ mkMsg('m1', 'alpha', 'beta', 'ping-1', 60 * 1000),
45
+ mkMsg('m2', 'alpha', 'beta', 'ping-2', 50 * 1000),
46
+ mkMsg('m3', 'alpha', 'beta', 'ping-3', 40 * 1000),
47
+ mkMsg('m4', 'alpha', 'beta', 'ping-4', 30 * 1000),
48
+ mkMsg('m5', 'gamma', 'delta', 'hello', 20 * 1000),
49
+ ] } }));
50
+ await ctx.route('**/api/hub/tasks*', (route) => route.fulfill({ json: { tasks: [] } }));
51
+ const page = await ctx.newPage();
52
+ await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
53
+ await page.waitForFunction(() => document.querySelectorAll('g[data-node]').length === 4, { timeout: 30000 });
54
+ await page.waitForSelector('[data-recent-panel-count]', { timeout: 10000 });
55
+ await page.waitForTimeout(400);
56
+
57
+ const headerCount = await page.locator('[data-recent-panel-count]').textContent();
58
+ const renderedRows = await page.locator('[data-recent-row]').count();
59
+
60
+ await browser.close();
61
+
62
+ const results = {
63
+ header_saysFlowsNotMsgs: /\bflows\b/.test(headerCount || ''),
64
+ header_count2: /^2 flows/.test(headerCount || ''),
65
+ rows_match_header: renderedRows === 2,
66
+ no_msgs_word: !/\bmsgs?\b/.test(headerCount || ''),
67
+ };
68
+ const ok = Object.values(results).every(Boolean);
69
+ console.log(`${ok ? '✅' : '❌'} recent-panel count:`, JSON.stringify(results),
70
+ `\n header=`, JSON.stringify(headerCount),
71
+ `\n rows=`, renderedRows);
72
+ process.exit(ok ? 0 : 1);