@sleep2agi/agent-network-dashboard 0.4.6-preview.20 → 0.4.6-preview.201

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 (404) 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/01b6zl3rabau1.js +1 -0
  181. package/.next/static/chunks/01lmbsd37fybu.js +1 -0
  182. package/.next/static/chunks/03o.h6kvmw4l_.js +1 -0
  183. package/.next/static/chunks/03~~oirxz7~vc.js +1 -0
  184. package/.next/static/chunks/05uk96gc~9mni.js +1 -0
  185. package/.next/static/chunks/08kf-.bgs10ze.js +1 -0
  186. package/.next/static/chunks/0fzk-axksemic.css +2 -0
  187. package/.next/static/chunks/0ggj5ummw2a84.js +7 -0
  188. package/.next/static/chunks/0glmrdj9112tc.js +7 -0
  189. package/.next/static/chunks/0n7ow3nu-_bsk.js +4 -0
  190. package/.next/static/chunks/0rxrez_cjn.eh.js +1 -0
  191. package/.next/static/chunks/0x8x.29hkju5a.js +1 -0
  192. package/.next/static/chunks/0zx.24yobat5o.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 +3984 -264
  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-freshness-test.mjs +113 -0
  216. package/scripts/topo-active-links-tooltip-test.mjs +79 -0
  217. package/scripts/topo-arrival-ping-test.mjs +87 -0
  218. package/scripts/topo-arrow-tier-test.mjs +61 -0
  219. package/scripts/topo-auto-fit-test.mjs +73 -0
  220. package/scripts/topo-canvas-aria-test.mjs +108 -0
  221. package/scripts/topo-chat-target-breath-test.mjs +84 -0
  222. package/scripts/topo-chat-target-ring-fade-test.mjs +124 -0
  223. package/scripts/topo-chip-focus-test.mjs +95 -0
  224. package/scripts/topo-chip-pin-mirror-test.mjs +113 -0
  225. package/scripts/topo-chrome-a11y-test.mjs +107 -0
  226. package/scripts/topo-chrome-zoom-level-pop-test.mjs +122 -0
  227. package/scripts/topo-chrome-zoom-pop-test.mjs +130 -0
  228. package/scripts/topo-click-ripple-test.mjs +66 -0
  229. package/scripts/topo-cmdk-edge-clear-test.mjs +109 -0
  230. package/scripts/topo-cmdk-layout-view-test.mjs +108 -0
  231. package/scripts/topo-cmdk-pin-test.mjs +123 -0
  232. package/scripts/topo-cmdk-vendor-clear-test.mjs +133 -0
  233. package/scripts/topo-cmdk-vendor-pin-test.mjs +103 -0
  234. package/scripts/topo-cwd-tooltip-test.mjs +64 -0
  235. package/scripts/topo-dblclick-reset-test.mjs +74 -0
  236. package/scripts/topo-discrete-zoom-smooth-test.mjs +125 -0
  237. package/scripts/topo-dispatch-pulse-test.mjs +83 -0
  238. package/scripts/topo-edge-badge-click-pin-test.mjs +94 -0
  239. package/scripts/topo-edge-badge-hot-test.mjs +115 -0
  240. package/scripts/topo-edge-badge-hover-test.mjs +85 -0
  241. package/scripts/topo-edge-badge-lift-test.mjs +150 -0
  242. package/scripts/topo-edge-badge-ripple-test.mjs +111 -0
  243. package/scripts/topo-edge-badge-stroke-transition-test.mjs +118 -0
  244. package/scripts/topo-edge-count-badge-test.mjs +86 -0
  245. package/scripts/topo-edge-endpoint-highlight-test.mjs +111 -0
  246. package/scripts/topo-edge-fadein-test.mjs +106 -0
  247. package/scripts/topo-edge-focus-test.mjs +113 -0
  248. package/scripts/topo-edge-hover-test.mjs +93 -0
  249. package/scripts/topo-edge-pill-hot-test.mjs +129 -0
  250. package/scripts/topo-edge-pill-test.mjs +105 -0
  251. package/scripts/topo-edge-stroke-transition-test.mjs +132 -0
  252. package/scripts/topo-edge-tooltip-test.mjs +70 -0
  253. package/scripts/topo-endpoint-ring-fade-test.mjs +132 -0
  254. package/scripts/topo-endpoint-ring-test.mjs +93 -0
  255. package/scripts/topo-esc-clears-pin-test.mjs +98 -0
  256. package/scripts/topo-filter-pill-aliases-test.mjs +121 -0
  257. package/scripts/topo-filter-pill-body-click-test.mjs +112 -0
  258. package/scripts/topo-filter-pill-count-test.mjs +110 -0
  259. package/scripts/topo-filter-pill-mobile-test.mjs +90 -0
  260. package/scripts/topo-fit-key-test.mjs +106 -0
  261. package/scripts/topo-freshness-chip-test.mjs +74 -0
  262. package/scripts/topo-freshness-chip-transition-test.mjs +80 -0
  263. package/scripts/topo-fullscreen-active-test.mjs +115 -0
  264. package/scripts/topo-group-box-pinned-state-test.mjs +95 -0
  265. package/scripts/topo-group-count-test.mjs +68 -0
  266. package/scripts/topo-group-hover-test.mjs +82 -0
  267. package/scripts/topo-group-label-a11y-test.mjs +113 -0
  268. package/scripts/topo-group-label-hover-test.mjs +119 -0
  269. package/scripts/topo-group-label-tint-test.mjs +99 -0
  270. package/scripts/topo-group-label-title-test.mjs +83 -0
  271. package/scripts/topo-group-pin-test.mjs +119 -0
  272. package/scripts/topo-group-status-pips-test.mjs +103 -0
  273. package/scripts/topo-groupbox-fadein-test.mjs +95 -0
  274. package/scripts/topo-groupbox-hover-lift-test.mjs +127 -0
  275. package/scripts/topo-groupbox-live-test.mjs +100 -0
  276. package/scripts/topo-groupbox-march-busyness-test.mjs +155 -0
  277. package/scripts/topo-groupbox-test.mjs +4 -2
  278. package/scripts/topo-help-overlay-r109-test.mjs +67 -0
  279. package/scripts/topo-help-overlay-r118-test.mjs +69 -0
  280. package/scripts/topo-help-overlay-r123-test.mjs +69 -0
  281. package/scripts/topo-help-overlay-r134-test.mjs +74 -0
  282. package/scripts/topo-help-overlay-r137-test.mjs +81 -0
  283. package/scripts/topo-help-overlay-r141-test.mjs +86 -0
  284. package/scripts/topo-help-overlay-r153-test.mjs +85 -0
  285. package/scripts/topo-help-overlay-r59-test.mjs +67 -0
  286. package/scripts/topo-help-overlay-r65-test.mjs +64 -0
  287. package/scripts/topo-help-overlay-r70-test.mjs +63 -0
  288. package/scripts/topo-help-overlay-r78-test.mjs +59 -0
  289. package/scripts/topo-help-overlay-r81-test.mjs +58 -0
  290. package/scripts/topo-help-overlay-r87-test.mjs +64 -0
  291. package/scripts/topo-help-overlay-r91-test.mjs +65 -0
  292. package/scripts/topo-hub-a11y-test.mjs +112 -0
  293. package/scripts/topo-hub-busyness-test.mjs +100 -0
  294. package/scripts/topo-hub-click-fit-test.mjs +137 -0
  295. package/scripts/topo-hub-fadein-test.mjs +88 -0
  296. package/scripts/topo-hub-hover-lift-test.mjs +101 -0
  297. package/scripts/topo-hub-hover-ring-test.mjs +82 -0
  298. package/scripts/topo-hub-title-test.mjs +93 -0
  299. package/scripts/topo-hub-working-count-test.mjs +99 -0
  300. package/scripts/topo-ingroup-edge-test.mjs +103 -0
  301. package/scripts/topo-label-lift-test.mjs +119 -0
  302. package/scripts/topo-label-scale-test.mjs +78 -0
  303. package/scripts/topo-lastseen-tooltip-test.mjs +59 -0
  304. package/scripts/topo-layout-key-test.mjs +91 -0
  305. package/scripts/topo-layout-switch-crossfade-test.mjs +126 -0
  306. package/scripts/topo-layout-toggle-test.mjs +131 -0
  307. package/scripts/topo-legend-count-test.mjs +88 -0
  308. package/scripts/topo-legend-hover-test.mjs +113 -0
  309. package/scripts/topo-legend-panel-header-test.mjs +83 -0
  310. package/scripts/topo-legend-pin-ring-fade-test.mjs +112 -0
  311. package/scripts/topo-legend-pin-test.mjs +128 -0
  312. package/scripts/topo-legend-row-hover-lift-test.mjs +109 -0
  313. package/scripts/topo-legend-row-tint-test.mjs +95 -0
  314. package/scripts/topo-legend-row-title-test.mjs +102 -0
  315. package/scripts/topo-minimap-a11y-test.mjs +101 -0
  316. package/scripts/topo-minimap-test.mjs +68 -0
  317. package/scripts/topo-mobile-chips-test.mjs +103 -0
  318. package/scripts/topo-node-a11y-test.mjs +107 -0
  319. package/scripts/topo-node-hover-lift-test.mjs +85 -0
  320. package/scripts/topo-node-label-card-elevation-test.mjs +157 -0
  321. package/scripts/topo-node-stroke-transition-test.mjs +103 -0
  322. package/scripts/topo-node-title-peers-test.mjs +107 -0
  323. package/scripts/topo-node-title-test.mjs +101 -0
  324. package/scripts/topo-nodesize-active-hover-test.mjs +109 -0
  325. package/scripts/topo-nodesize-crossfade-test.mjs +141 -0
  326. package/scripts/topo-offline-dim-test.mjs +70 -0
  327. package/scripts/topo-online-chip-nav-test.mjs +143 -0
  328. package/scripts/topo-orbit-busyness-test.mjs +96 -0
  329. package/scripts/topo-overlap-test.mjs +32 -5
  330. package/scripts/topo-pan-cursor-test.mjs +62 -0
  331. package/scripts/topo-panel-elevation-test.mjs +76 -0
  332. package/scripts/topo-panel-fadein-test.mjs +102 -0
  333. package/scripts/topo-panel-hot-tail-fade-test.mjs +124 -0
  334. package/scripts/topo-panel-hover-elevation-test.mjs +118 -0
  335. package/scripts/topo-particle-stagger-test.mjs +82 -0
  336. package/scripts/topo-pin-intersection-empty-test.mjs +129 -0
  337. package/scripts/topo-pin-intersection-test.mjs +121 -0
  338. package/scripts/topo-pin-mirror-transition-test.mjs +101 -0
  339. package/scripts/topo-pin-persistence-test.mjs +105 -0
  340. package/scripts/topo-popover-meta-test.mjs +78 -0
  341. package/scripts/topo-pressure-bar-test.mjs +69 -0
  342. package/scripts/topo-pressure-hover-test.mjs +123 -0
  343. package/scripts/topo-pressure-pin-test.mjs +119 -0
  344. package/scripts/topo-pressure-seg-tooltip-test.mjs +98 -0
  345. package/scripts/topo-pressure-seg-transition-test.mjs +107 -0
  346. package/scripts/topo-pulse-rate-test.mjs +71 -0
  347. package/scripts/topo-recent-panel-count-freshness-test.mjs +109 -0
  348. package/scripts/topo-recent-panel-count-test.mjs +72 -0
  349. package/scripts/topo-recent-panel-hot-header-test.mjs +132 -0
  350. package/scripts/topo-recent-panel-more-nav-test.mjs +127 -0
  351. package/scripts/topo-recent-panel-more-test.mjs +106 -0
  352. package/scripts/topo-recent-row-count-fill-test.mjs +129 -0
  353. package/scripts/topo-recent-row-freshness-test.mjs +102 -0
  354. package/scripts/topo-recent-row-hot-test.mjs +110 -0
  355. package/scripts/topo-recent-row-hover-lift-test.mjs +128 -0
  356. package/scripts/topo-recent-row-hover-test.mjs +122 -0
  357. package/scripts/topo-recent-row-pin-test.mjs +126 -0
  358. package/scripts/topo-recent-row-tint-test.mjs +91 -0
  359. package/scripts/topo-recent-row-title-test.mjs +112 -0
  360. package/scripts/topo-recent-row-ts-alpha-test.mjs +100 -0
  361. package/scripts/topo-recent-row-ts-test.mjs +95 -0
  362. package/scripts/topo-recent-row-typography-test.mjs +119 -0
  363. package/scripts/topo-recent-signal-empty-hint-test.mjs +73 -0
  364. package/scripts/topo-recent-signal-empty-test.mjs +63 -0
  365. package/scripts/topo-reduced-motion-test.mjs +77 -0
  366. package/scripts/topo-reset-spin-test.mjs +120 -0
  367. package/scripts/topo-spoke-busyness-test.mjs +110 -0
  368. package/scripts/topo-status-chip-hover-test.mjs +101 -0
  369. package/scripts/topo-status-chip-tooltip-test.mjs +95 -0
  370. package/scripts/topo-svg-focus-test.mjs +112 -0
  371. package/scripts/topo-sweep-busyness-test.mjs +94 -0
  372. package/scripts/topo-tier-ring-fadein-test.mjs +107 -0
  373. package/scripts/topo-tier-ring-occupancy-test.mjs +87 -0
  374. package/scripts/topo-tier-ring-test.mjs +69 -0
  375. package/scripts/topo-tier-ring-tint-test.mjs +110 -0
  376. package/scripts/topo-tier-stagger-test.mjs +89 -0
  377. package/scripts/topo-tz-ghost-test.mjs +69 -0
  378. package/scripts/topo-vendor-chip-hover-test.mjs +111 -0
  379. package/scripts/topo-vendor-letter-tooltip-test.mjs +92 -0
  380. package/scripts/topo-vendor-pill-test.mjs +125 -0
  381. package/scripts/topo-vendor-pin-test.mjs +125 -0
  382. package/scripts/topo-view-smooth-test.mjs +131 -0
  383. package/scripts/topo-wheel-zoom-test.mjs +79 -0
  384. package/scripts/topo-working-chip-pin-test.mjs +154 -0
  385. package/scripts/topo-working-halo-breath-test.mjs +86 -0
  386. package/scripts/topo-zoom-keys-test.mjs +89 -0
  387. package/.next/static/chunks/0-7iowzu4.798.js +0 -1
  388. package/.next/static/chunks/02t5jr4shh.hy.js +0 -1
  389. package/.next/static/chunks/076u9wjiilxzg.js +0 -1
  390. package/.next/static/chunks/07hlou5cndq1b.js +0 -1
  391. package/.next/static/chunks/09nd.t_hd.y6t.css +0 -2
  392. package/.next/static/chunks/0_qfg5s5uzs7..js +0 -7
  393. package/.next/static/chunks/0elalb9n_.~di.js +0 -1
  394. package/.next/static/chunks/0fqy_0wj_1xa7.js +0 -7
  395. package/.next/static/chunks/0j_q__o8p6g83.js +0 -1
  396. package/.next/static/chunks/0jl6_w50zh4l5.js +0 -1
  397. package/.next/static/chunks/0lw~4lr23sl-r.js +0 -1
  398. package/.next/static/chunks/0r4q73.-1bkyl.js +0 -1
  399. package/.next/static/chunks/0r_c8eccg3z2o.js +0 -1
  400. package/.next/static/chunks/10oi7l-tycgl9.js +0 -1
  401. package/.next/static/chunks/11uk1izuv3~0t.js +0 -1
  402. /package/.next/static/{kZOwEPGbIfBUUE4MFGvHz → IZ83xXmRRznWkvPwyxx-z}/_buildManifest.js +0 -0
  403. /package/.next/static/{kZOwEPGbIfBUUE4MFGvHz → IZ83xXmRRznWkvPwyxx-z}/_clientMiddlewareManifest.js +0 -0
  404. /package/.next/static/{kZOwEPGbIfBUUE4MFGvHz → IZ83xXmRRznWkvPwyxx-z}/_ssgManifest.js +0 -0
@@ -0,0 +1,123 @@
1
+ /* Round 69 verification: Cmd+K palette can pin topology filters from
2
+ * anywhere. The palette dispatches a CustomEvent('anet:topo-pin') that
3
+ * TopoGraph listens for and translates into pinnedStatus / pinnedGroup
4
+ * state. sessionStorage is written in lockstep so a reload preserves it
5
+ * (R66 carries it through).
6
+ *
7
+ * - Dispatch {kind:'status', value:'working'} → pill appears + idle/
8
+ * offline nodes dim. sessionStorage holds 'working'.
9
+ * - Dispatch {kind:'clear'} → pill disappears + opacities restore.
10
+ * sessionStorage entries cleared.
11
+ * - Dispatch {kind:'group', value:'alpha'} → group pill + opacities
12
+ * composed; storage holds 'alpha'.
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: 1500 } });
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', 'grid');
26
+ sessionStorage.setItem('anet_v3_auth', '1');
27
+ sessionStorage.removeItem('anet-topo-pinned-status');
28
+ sessionStorage.removeItem('anet-topo-pinned-group');
29
+ } catch {}
30
+ });
31
+
32
+ const fresh = new Date(Date.now() - 60 * 1000).toISOString();
33
+ await ctx.route('**/api/hub/status*', async (route) => {
34
+ const r = await route.fetch();
35
+ const b = await r.json();
36
+ const nid = (b.sessions || [])[0]?.network_id || 'default';
37
+ const sessions = [
38
+ { alias: 'alpha1', status: 'working', network_id: nid, project_dir: null, created_at: fresh, updated_at: fresh, last_seen_at: fresh },
39
+ { alias: 'alpha2', status: 'idle', network_id: nid, project_dir: null, created_at: fresh, updated_at: fresh, last_seen_at: fresh },
40
+ { alias: 'alpha3', status: 'idle', network_id: nid, project_dir: null, created_at: fresh, updated_at: fresh, last_seen_at: fresh },
41
+ { alias: 'beta', status: 'idle', network_id: nid, project_dir: null, created_at: fresh, updated_at: fresh, last_seen_at: fresh },
42
+ ];
43
+ await route.fulfill({ response: r, json: { ...b, sessions } });
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
+ 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.waitForTimeout(500);
51
+
52
+ const snapshot = () => page.evaluate(() => {
53
+ const pills = [...document.querySelectorAll('[data-active-filter]')].map(el => ({
54
+ kind: el.getAttribute('data-active-filter'),
55
+ text: (el.innerText || el.textContent || '').trim(),
56
+ }));
57
+ const opacities = {};
58
+ for (const a of ['alpha1', 'alpha2', 'beta']) {
59
+ const g = document.querySelector(`g[data-node="${a}"]`);
60
+ opacities[a] = g ? +(g.style.opacity || '1') : null;
61
+ }
62
+ return {
63
+ pills,
64
+ opacities,
65
+ storageStatus: sessionStorage.getItem('anet-topo-pinned-status'),
66
+ storageGroup: sessionStorage.getItem('anet-topo-pinned-group'),
67
+ };
68
+ });
69
+
70
+ const before = await snapshot();
71
+
72
+ // Dispatch palette pin: status=working
73
+ await page.evaluate(() => {
74
+ // The Cmd+K commands write to storage AND dispatch the event in
75
+ // lockstep. We mirror both here so we exercise the same code path
76
+ // a palette `perform()` would take.
77
+ sessionStorage.setItem('anet-topo-pinned-status', 'working');
78
+ window.dispatchEvent(new CustomEvent('anet:topo-pin', { detail: { kind: 'status', value: 'working' } }));
79
+ });
80
+ await page.waitForTimeout(250);
81
+ const afterStatus = await snapshot();
82
+
83
+ // Dispatch palette pin: group=alpha (additionally)
84
+ await page.evaluate(() => {
85
+ sessionStorage.setItem('anet-topo-pinned-group', 'alpha');
86
+ window.dispatchEvent(new CustomEvent('anet:topo-pin', { detail: { kind: 'group', value: 'alpha' } }));
87
+ });
88
+ await page.waitForTimeout(250);
89
+ const afterGroup = await snapshot();
90
+
91
+ // Dispatch palette clear
92
+ await page.evaluate(() => {
93
+ sessionStorage.removeItem('anet-topo-pinned-status');
94
+ sessionStorage.removeItem('anet-topo-pinned-group');
95
+ window.dispatchEvent(new CustomEvent('anet:topo-pin', { detail: { kind: 'clear' } }));
96
+ });
97
+ await page.waitForTimeout(250);
98
+ const afterClear = await snapshot();
99
+
100
+ await browser.close();
101
+
102
+ const bright = (v) => v != null && v >= 0.55;
103
+ const dim = (v) => v != null && v < 0.4;
104
+ const results = {
105
+ before_noPills: before.pills.length === 0,
106
+ before_baselineBright: bright(before.opacities.alpha1) && bright(before.opacities.alpha2),
107
+ status_pillRendered: afterStatus.pills.some(p => p.kind === 'status' && /working/.test(p.text)),
108
+ status_dimsIdle: dim(afterStatus.opacities.alpha2) && dim(afterStatus.opacities.beta),
109
+ status_keepsWorking: bright(afterStatus.opacities.alpha1),
110
+ status_storageWritten: afterStatus.storageStatus === 'working',
111
+ groupAdded_bothPills: afterGroup.pills.length === 2,
112
+ groupAdded_storageBoth: afterGroup.storageStatus === 'working' && afterGroup.storageGroup === 'alpha',
113
+ clear_noPills: afterClear.pills.length === 0,
114
+ clear_restoredOpacities: bright(afterClear.opacities.alpha1) && bright(afterClear.opacities.alpha2) && bright(afterClear.opacities.beta),
115
+ clear_storageCleared: afterClear.storageStatus === null && afterClear.storageGroup === null,
116
+ };
117
+ const ok = Object.values(results).every(Boolean);
118
+ console.log(`${ok ? '✅' : '❌'} cmdk-pin:`, JSON.stringify(results),
119
+ `\n before=`, before,
120
+ `\n afterStatus=`, afterStatus,
121
+ `\n afterGroup=`, afterGroup,
122
+ `\n afterClear=`, afterClear);
123
+ process.exit(ok ? 0 : 1);
@@ -0,0 +1,133 @@
1
+ /* Round 90 verification: Cmd+K palette "Clear topology filters" also
2
+ * releases the R88 pinnedVendor (the R69 implementation only knew
3
+ * about status + group). Plus the new granular "Clear topology vendor
4
+ * filter" command releases just vendor without disturbing status or
5
+ * group pins.
6
+ *
7
+ * Drive via direct CustomEvent dispatch (avoids fuzzy-match flake —
8
+ * same approach as the R82 chip-pin-mirror test). Verifies both the
9
+ * TopoGraph listener branch (state mutation) and the in-memory
10
+ * sessionStorage cleanup.
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
+ 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
+ await ctx.route('**/api/hub/status*', async (route) => {
32
+ const r = await route.fetch();
33
+ const b = await r.json();
34
+ const nid = (b.sessions || [])[0]?.network_id || 'default';
35
+ const mk = (alias, status, model) => ({
36
+ alias, status, model, runtime: 'cli-claude-code',
37
+ network_id: nid, project_dir: null,
38
+ created_at: fresh, updated_at: fresh, last_seen_at: fresh,
39
+ });
40
+ const sessions = [
41
+ mk('alpha', 'working', 'claude-opus-4'),
42
+ mk('beta', 'idle', 'gpt-5'),
43
+ mk('gamma', 'idle', 'claude-opus-4'),
44
+ ];
45
+ await route.fulfill({ response: r, json: { ...b, sessions } });
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 === 3, { timeout: 30000 });
52
+ await page.waitForTimeout(400);
53
+
54
+ const pills = () => page.evaluate(() => {
55
+ const all = document.querySelectorAll('[data-active-filter]');
56
+ return [...all].map(p => p.getAttribute('data-active-filter'));
57
+ });
58
+ const storage = () => page.evaluate(() => ({
59
+ status: sessionStorage.getItem('anet-topo-pinned-status'),
60
+ group: sessionStorage.getItem('anet-topo-pinned-group'),
61
+ vendor: sessionStorage.getItem('anet-topo-pinned-vendor'),
62
+ }));
63
+
64
+ // Helper: dispatch a topo-pin event from the page side.
65
+ const pin = async (kind, value) => {
66
+ await page.evaluate(({ kind, value }) => {
67
+ if (kind === 'status') sessionStorage.setItem('anet-topo-pinned-status', value);
68
+ if (kind === 'group') sessionStorage.setItem('anet-topo-pinned-group', value);
69
+ window.dispatchEvent(new CustomEvent('anet:topo-pin', { detail: { kind, value } }));
70
+ }, { kind, value });
71
+ await page.waitForTimeout(200);
72
+ };
73
+ // Pin vendor via the actual UI letter click (no CustomEvent for that
74
+ // flow yet — palette doesn't surface per-vendor pin actions).
75
+ const pinVendor = async (initial) => {
76
+ await page.locator(`[data-vendor-letter="${initial}"]`).click();
77
+ await page.mouse.move(10, 10);
78
+ await page.waitForTimeout(200);
79
+ };
80
+ const clearAll = async () => {
81
+ await page.evaluate(() => {
82
+ sessionStorage.removeItem('anet-topo-pinned-status');
83
+ sessionStorage.removeItem('anet-topo-pinned-group');
84
+ sessionStorage.removeItem('anet-topo-pinned-vendor');
85
+ window.dispatchEvent(new CustomEvent('anet:topo-pin', { detail: { kind: 'clear' } }));
86
+ });
87
+ await page.waitForTimeout(250);
88
+ };
89
+ const clearVendor = async () => {
90
+ await page.evaluate(() => {
91
+ sessionStorage.removeItem('anet-topo-pinned-vendor');
92
+ window.dispatchEvent(new CustomEvent('anet:topo-pin', { detail: { kind: 'clear-vendor' } }));
93
+ });
94
+ await page.waitForTimeout(250);
95
+ };
96
+
97
+ // === Test 1: clear-all now also clears vendor (the R90 bug fix). ===
98
+ await pin('status', 'working');
99
+ await pinVendor('A');
100
+ const afterPinBoth = { pills: await pills(), storage: await storage() };
101
+
102
+ await clearAll();
103
+ const afterClearAll = { pills: await pills(), storage: await storage() };
104
+
105
+ // === Test 2: granular clear-vendor leaves status + group untouched. ===
106
+ await pin('status', 'working');
107
+ await pinVendor('A');
108
+ const beforeGranular = { pills: await pills(), storage: await storage() };
109
+
110
+ await clearVendor();
111
+ const afterClearVendor = { pills: await pills(), storage: await storage() };
112
+
113
+ await browser.close();
114
+
115
+ const sameSet = (a, b) => a.length === b.length && a.every(x => b.includes(x));
116
+ const results = {
117
+ pinBoth_threePills: sameSet(afterPinBoth.pills, ['status', 'vendor']),
118
+ pinBoth_storageBoth: afterPinBoth.storage.status === 'working' && afterPinBoth.storage.vendor === 'A',
119
+ clearAll_noPills: afterClearAll.pills.length === 0,
120
+ clearAll_storageAllNull: afterClearAll.storage.status === null && afterClearAll.storage.group === null && afterClearAll.storage.vendor === null,
121
+ granular_threePills: sameSet(beforeGranular.pills, ['status', 'vendor']),
122
+ clearVendor_keepsStatus: afterClearVendor.pills.includes('status'),
123
+ clearVendor_dropsVendor: !afterClearVendor.pills.includes('vendor'),
124
+ clearVendor_storageStatusKept: afterClearVendor.storage.status === 'working',
125
+ clearVendor_storageVendorCleared: afterClearVendor.storage.vendor === null,
126
+ };
127
+ const ok = Object.values(results).every(Boolean);
128
+ console.log(`${ok ? '✅' : '❌'} cmdk vendor clear:`, JSON.stringify(results),
129
+ `\n afterPinBoth=`, afterPinBoth,
130
+ `\n afterClearAll=`, afterClearAll,
131
+ `\n beforeGranular=`, beforeGranular,
132
+ `\n afterClearVendor=`, afterClearVendor);
133
+ process.exit(ok ? 0 : 1);
@@ -0,0 +1,103 @@
1
+ /* Round 108 verification: Cmd+K palette can pin a vendor filter via
2
+ * three new static actions ("Pin topology filter: Anthropic" /
3
+ * OpenAI / 书生). TopoGraph's R69 listener handles kind='vendor' to
4
+ * setPinnedVendor. The R88 stale-purge cleans up if the vendor isn't
5
+ * in the fleet.
6
+ *
7
+ * Drives via direct CustomEvent dispatch (same deterministic path
8
+ * R82/R90 tests use — fuzzy-match-free). Verifies pin sticks, vendor
9
+ * pill renders, storage persists, and Esc / clear-all release.
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
+ const ctx = await browser.newContext({ viewport: { width: 1400, height: 1200 } });
17
+ await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
18
+ await ctx.addInitScript(() => {
19
+ try {
20
+ localStorage.setItem('anet-theme', 'cyber');
21
+ localStorage.setItem('anet-topo-layout', 'ring');
22
+ sessionStorage.setItem('anet_v3_auth', '1');
23
+ sessionStorage.removeItem('anet-topo-pinned-status');
24
+ sessionStorage.removeItem('anet-topo-pinned-group');
25
+ sessionStorage.removeItem('anet-topo-pinned-vendor');
26
+ } catch {}
27
+ });
28
+
29
+ const fresh = new Date(Date.now() - 60 * 1000).toISOString();
30
+ await ctx.route('**/api/hub/status*', async (route) => {
31
+ const r = await route.fetch();
32
+ const b = await r.json();
33
+ const nid = (b.sessions || [])[0]?.network_id || 'default';
34
+ const mk = (alias, model) => ({
35
+ alias, status: 'idle', model, runtime: 'cli-claude-code',
36
+ network_id: nid, project_dir: null,
37
+ created_at: fresh, updated_at: fresh, last_seen_at: fresh,
38
+ });
39
+ await route.fulfill({ response: r, json: { ...b, sessions: [
40
+ mk('alpha', 'claude-opus-4'), // A (Anthropic)
41
+ mk('beta', 'gpt-5'), // O (OpenAI)
42
+ mk('gamma', 'claude-opus-4'), // A
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
+ 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 === 3, { timeout: 30000 });
50
+ await page.waitForTimeout(400);
51
+
52
+ const pillCount = () => page.locator('[data-active-filter="vendor"]').count();
53
+ const storage = () => page.evaluate(() => sessionStorage.getItem('anet-topo-pinned-vendor'));
54
+ const opacities = () => page.evaluate(() => {
55
+ const o = {};
56
+ for (const a of ['alpha', 'beta', 'gamma']) {
57
+ const g = document.querySelector(`g[data-node="${a}"]`);
58
+ o[a] = g ? +(g.style.opacity || '1') : null;
59
+ }
60
+ return o;
61
+ });
62
+
63
+ // Initial state — no pin.
64
+ const beforePill = await pillCount();
65
+ const beforeStorage = await storage();
66
+
67
+ // Pin A via R108 palette action's CustomEvent.
68
+ await page.evaluate(() => {
69
+ sessionStorage.setItem('anet-topo-pinned-vendor', 'A');
70
+ window.dispatchEvent(new CustomEvent('anet:topo-pin', { detail: { kind: 'vendor', value: 'A' } }));
71
+ });
72
+ await page.waitForTimeout(300);
73
+ const afterPinA_ops = await opacities();
74
+ const afterPinA_pill = await pillCount();
75
+ const afterPinA_storage = await storage();
76
+
77
+ // Esc → clear pin.
78
+ await page.keyboard.press('Escape');
79
+ await page.waitForTimeout(300);
80
+ const afterEsc_pill = await pillCount();
81
+ const afterEsc_storage = await storage();
82
+
83
+ await browser.close();
84
+
85
+ const bright = (v) => v != null && v >= 0.55;
86
+ const dim = (v) => v != null && v < 0.4;
87
+ const results = {
88
+ before_noPill: beforePill === 0,
89
+ before_noStorage: beforeStorage === null,
90
+ pinA_pillShown: afterPinA_pill === 1,
91
+ pinA_storageWritten: afterPinA_storage === 'A',
92
+ pinA_keepsClaudes: bright(afterPinA_ops.alpha) && bright(afterPinA_ops.gamma),
93
+ pinA_dimsGPT: dim(afterPinA_ops.beta),
94
+ esc_clearsPill: afterEsc_pill === 0,
95
+ esc_clearsStorage: afterEsc_storage === null,
96
+ };
97
+ const ok = Object.values(results).every(Boolean);
98
+ console.log(`${ok ? '✅' : '❌'} cmdk vendor pin:`, JSON.stringify(results),
99
+ `\n afterPinA_ops=`, afterPinA_ops,
100
+ `\n afterPinA_pill=`, afterPinA_pill,
101
+ `\n afterPinA_storage=`, afterPinA_storage,
102
+ `\n afterEsc_pill=`, afterEsc_pill);
103
+ process.exit(ok ? 0 : 1);
@@ -0,0 +1,64 @@
1
+ /* Round 33 verification: hover tooltip carries `cwd: <project_dir>` on a
2
+ * second line when reported; falls back to the identity-only line
3
+ * otherwise; no `cwd:` line for nodes without project_dir. */
4
+ import { chromium } from 'playwright';
5
+ import { readFileSync } from 'node:fs';
6
+
7
+ const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
8
+ const browser = await chromium.launch({ headless: true });
9
+ const ctx = await browser.newContext({ viewport: { width: 1280, height: 900 } });
10
+ await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
11
+ await ctx.addInitScript(() => {
12
+ try {
13
+ localStorage.setItem('anet-theme', 'cyber');
14
+ localStorage.setItem('anet-topo-layout', 'grid');
15
+ sessionStorage.setItem('anet_v3_auth', '1');
16
+ } catch {}
17
+ });
18
+ const fresh = new Date(Date.now() - 60 * 1000).toISOString();
19
+ await ctx.route('**/api/hub/status*', async (route) => {
20
+ const r = await route.fetch();
21
+ const b = await r.json();
22
+ const nid = (b.sessions || [])[0]?.network_id || 'default';
23
+ const sessions = [
24
+ {
25
+ alias: 'full', status: 'idle', network_id: nid,
26
+ project_dir: '/home/vansin/agent-orchestra',
27
+ model: 'claude-opus-4-7', runtime: 'cli-claude-code',
28
+ created_at: fresh, updated_at: fresh, last_seen_at: fresh,
29
+ },
30
+ {
31
+ alias: 'cwdOnly', status: 'idle', network_id: nid,
32
+ project_dir: '/home/vansin/some-project',
33
+ model: null, runtime: null,
34
+ created_at: fresh, updated_at: fresh, last_seen_at: fresh,
35
+ },
36
+ {
37
+ alias: 'bare', status: 'idle', network_id: nid,
38
+ project_dir: null, model: null, runtime: null,
39
+ created_at: fresh, updated_at: fresh, last_seen_at: fresh,
40
+ },
41
+ ];
42
+ await route.fulfill({ response: r, json: { ...b, sessions } });
43
+ });
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 === 3, { timeout: 30000 });
48
+ await page.waitForTimeout(400);
49
+
50
+ const titleOf = alias => page.$eval(`g[data-node="${alias}"] title`, el => el.textContent);
51
+ const full = await titleOf('full');
52
+ const cwdOnly = await titleOf('cwdOnly');
53
+ const bare = await titleOf('bare');
54
+
55
+ await browser.close();
56
+ const results = {
57
+ fullHasIdentityAndCwd: /claude-opus-4-7/.test(full) && /cwd: \/home\/vansin\/agent-orchestra/.test(full) && full.includes('\n'),
58
+ cwdOnlyShowsAliasAndCwd: cwdOnly.startsWith('cwdOnly') && /cwd: \/home\/vansin\/some-project/.test(cwdOnly),
59
+ bareShowsAliasOnly: bare === 'bare',
60
+ };
61
+ const ok = Object.values(results).every(Boolean);
62
+ console.log(`${ok ? '✅' : '❌'} cwd tooltip:`, JSON.stringify(results),
63
+ `\n full=${JSON.stringify(full)}\n cwdOnly=${JSON.stringify(cwdOnly)}\n bare=${JSON.stringify(bare)}`);
64
+ process.exit(ok ? 0 : 1);
@@ -0,0 +1,74 @@
1
+ /* Round 41 verification: double-clicking empty canvas resets view to
2
+ * {zoom:1, x:0, y:0}. Double-clicking a node does NOT reset (the
3
+ * node's own onClick wins, and resetView should not fire). */
4
+ import { chromium } from 'playwright';
5
+ import { readFileSync } from 'node:fs';
6
+
7
+ const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
8
+ const browser = await chromium.launch({ headless: true });
9
+ const ctx = await browser.newContext({ viewport: { width: 1280, height: 1600 } });
10
+ await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
11
+ await ctx.addInitScript(() => {
12
+ try {
13
+ localStorage.setItem('anet-theme', 'cyber');
14
+ localStorage.setItem('anet-topo-layout', 'grid');
15
+ localStorage.setItem('anet-topo-view', JSON.stringify({ zoom: 1, x: 0, y: 0 }));
16
+ sessionStorage.setItem('anet_v3_auth', '1');
17
+ } catch {}
18
+ });
19
+ const fresh = new Date(Date.now() - 60 * 1000).toISOString();
20
+ await ctx.route('**/api/hub/status*', async (route) => {
21
+ const r = await route.fetch();
22
+ const b = await r.json();
23
+ const nid = (b.sessions || [])[0]?.network_id || 'default';
24
+ const sessions = ['a', 'b'].map(a => ({
25
+ alias: a, status: 'idle', network_id: nid, project_dir: null,
26
+ created_at: fresh, updated_at: fresh, last_seen_at: fresh,
27
+ }));
28
+ await route.fulfill({ response: r, json: { ...b, sessions } });
29
+ });
30
+ await ctx.route('**/api/hub/tasks*', (route) => route.fulfill({ json: { tasks: [] } }));
31
+ const page = await ctx.newPage();
32
+ await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
33
+ await page.waitForSelector('svg[viewBox="0 0 1000 680"]', { timeout: 30000 });
34
+ await page.waitForTimeout(500);
35
+
36
+ const readZoom = () => page.evaluate(() => {
37
+ const span = document.querySelector('button[aria-label="Zoom in"]').parentElement.querySelector('span[title*="zoom level"]');
38
+ return +span.textContent.replace('%', '');
39
+ });
40
+
41
+ // Zoom in a couple times via keyboard, then dbl-click empty canvas → expect reset to 100%.
42
+ await page.keyboard.press('=');
43
+ await page.keyboard.press('=');
44
+ await page.waitForTimeout(120);
45
+ const zoomedIn = await readZoom();
46
+
47
+ // Find empty-canvas coords: top-left area of the SVG, well outside node positions.
48
+ const box = await page.$eval('svg[viewBox="0 0 1000 680"]', el => el.getBoundingClientRect());
49
+ // y=0.35 is below the top-overlay panels (which sit at y<100 inside the SVG)
50
+ const emptyX = box.x + box.width * 0.20;
51
+ const emptyY = box.y + box.height * 0.40;
52
+ await page.mouse.dblclick(emptyX, emptyY);
53
+ await page.waitForTimeout(200);
54
+ const afterEmptyDbl = await readZoom();
55
+
56
+ // Now zoom in again and dbl-click a node — view should NOT reset.
57
+ await page.keyboard.press('=');
58
+ await page.keyboard.press('=');
59
+ await page.waitForTimeout(120);
60
+ const zoomedIn2 = await readZoom();
61
+ await page.locator('g[data-node="a"]').dblclick().catch(() => {});
62
+ await page.waitForTimeout(200);
63
+ const afterNodeDbl = await readZoom();
64
+
65
+ await browser.close();
66
+ const results = {
67
+ zoomedInBeforeDbl: zoomedIn > 100,
68
+ emptyCanvasResets: afterEmptyDbl === 100,
69
+ nodeDoesNotReset: zoomedIn2 > 100 && afterNodeDbl === zoomedIn2,
70
+ };
71
+ const ok = Object.values(results).every(Boolean);
72
+ console.log(`${ok ? '✅' : '❌'} dblclick reset:`, JSON.stringify(results),
73
+ `\n zoomedIn=${zoomedIn} afterEmptyDbl=${afterEmptyDbl} zoomedIn2=${zoomedIn2} afterNodeDbl=${afterNodeDbl}`);
74
+ process.exit(ok ? 0 : 1);
@@ -0,0 +1,125 @@
1
+ /* Round 169 verification: keyboard '+'/'−' and chrome zoom in/out
2
+ * buttons arm the R168 smoothView transition.
3
+ *
4
+ * R168 introduced one-shot smoothView arming on resetView/fitView.
5
+ * R169 extends the same arming to the three other DISCRETE zoom
6
+ * surfaces (one keypress / button-click = one 1.2× step):
7
+ * keyboard '+' / '=' / '−' / '_'
8
+ * chrome zoom-in / zoom-out buttons
9
+ *
10
+ * Wheel zoom stays direct (every tick = live, no transition lag).
11
+ * Wrapper:
12
+ * const zoomByDiscrete = (factor) => {
13
+ * setSmoothView(true);
14
+ * setTimeout(() => setSmoothView(false), 350);
15
+ * zoomBy(factor);
16
+ * };
17
+ *
18
+ * Test:
19
+ * 1. Idle: smooth=false, no transition
20
+ * 2. Press '+': smooth=true, transition 'transform 300ms ease-out'
21
+ * zoom 100% → 120%
22
+ * 3. Wait 450ms: smooth=false, transition cleared
23
+ * 4. Click chrome zoom-in button: smooth=true again (same path)
24
+ * 5. Press '−': smooth=true, zoom back toward 100%
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
+ const fresh = new Date(Date.now() - 60 * 1000).toISOString();
39
+ await ctx.route('**/api/hub/status*', async (route) => {
40
+ const r = await route.fetch();
41
+ const b = await r.json();
42
+ const nid = (b.sessions || [])[0]?.network_id || 'default';
43
+ const mk = (alias) => ({
44
+ alias, status: 'working', model: 'claude-opus-4', runtime: 'cli-claude-code',
45
+ network_id: nid, project_dir: null,
46
+ created_at: fresh, updated_at: fresh, last_seen_at: fresh,
47
+ });
48
+ await route.fulfill({ response: r, json: { ...b, sessions: [mk('alpha'), mk('beta'), mk('gamma')] } });
49
+ });
50
+ await ctx.route('**/api/hub/messages*', (route) => route.fulfill({ json: { messages: [] } }));
51
+ await ctx.route('**/api/hub/tasks*', (route) => route.fulfill({ json: { tasks: [] } }));
52
+
53
+ const page = await ctx.newPage();
54
+ await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
55
+ await page.waitForFunction(() => document.querySelectorAll('g[data-node]').length === 3, { timeout: 30000 });
56
+ await page.waitForSelector('[data-topo-viewport]', { timeout: 10000 });
57
+ await page.waitForTimeout(400);
58
+
59
+ const probeViewport = () => page.evaluate(() => {
60
+ const g = document.querySelector('[data-topo-viewport]');
61
+ return {
62
+ smooth: g?.getAttribute('data-topo-viewport-smooth'),
63
+ transition: g?.style?.transition || '',
64
+ };
65
+ });
66
+ const probeZoom = () => page.evaluate(() =>
67
+ document.querySelector('[data-topo-chrome-zoom-level]')?.textContent?.trim());
68
+
69
+ const idle = await probeViewport();
70
+ const zoomIdle = await probeZoom();
71
+
72
+ // Press '+' → keyboard zoom-in. Probe within the 350ms window.
73
+ await page.keyboard.press('+');
74
+ await page.waitForTimeout(50);
75
+ const duringKbZoomIn = await probeViewport();
76
+ const zoomAfterKb = await probeZoom();
77
+
78
+ // Wait past the 350ms window
79
+ await page.waitForTimeout(450);
80
+ const afterKbZoomIn = await probeViewport();
81
+
82
+ // Click chrome zoom-in button → same arming path
83
+ await page.locator('[data-topo-chrome-zoom-in]').click();
84
+ await page.waitForTimeout(50);
85
+ const duringChromeZoomIn = await probeViewport();
86
+ const zoomAfterChromeIn = await probeZoom();
87
+
88
+ // Wait past window then press '−' (keyboard zoom-out)
89
+ await page.waitForTimeout(450);
90
+ await page.keyboard.press('-');
91
+ await page.waitForTimeout(50);
92
+ const duringKbZoomOut = await probeViewport();
93
+ const zoomAfterKbOut = await probeZoom();
94
+
95
+ await browser.close();
96
+
97
+ const results = {
98
+ viewport_found: idle !== null,
99
+ idle_smooth_false: idle.smooth === 'false',
100
+ idle_no_transition: !idle.transition.includes('transform'),
101
+ idle_zoom_100: zoomIdle === '100%',
102
+
103
+ kb_plus_armed_smooth: duringKbZoomIn.smooth === 'true',
104
+ kb_plus_transition_set: duringKbZoomIn.transition.includes('transform 300ms'),
105
+ kb_plus_zoom_increased: zoomAfterKb !== '100%',
106
+
107
+ after_kb_smooth_cleared: afterKbZoomIn.smooth === 'false',
108
+ after_kb_no_transition: !afterKbZoomIn.transition.includes('transform'),
109
+
110
+ chrome_in_armed_smooth: duringChromeZoomIn.smooth === 'true',
111
+ chrome_in_transition_set: duringChromeZoomIn.transition.includes('transform 300ms'),
112
+ chrome_in_zoom_increased: zoomAfterChromeIn !== zoomAfterKb,
113
+
114
+ kb_minus_armed_smooth: duringKbZoomOut.smooth === 'true',
115
+ kb_minus_transition_set: duringKbZoomOut.transition.includes('transform 300ms'),
116
+ kb_minus_zoom_decreased: zoomAfterKbOut !== zoomAfterChromeIn,
117
+ };
118
+ const ok = Object.values(results).every(Boolean);
119
+ console.log(`${ok ? '✅' : '❌'} discrete zoom smooth:`, JSON.stringify(results),
120
+ `\n idle =`, idle, `zoom=${zoomIdle}`,
121
+ `\n '+' fired =`, duringKbZoomIn, `zoom=${zoomAfterKb}`,
122
+ `\n after '+' =`, afterKbZoomIn,
123
+ `\n chrome-in fired =`, duringChromeZoomIn, `zoom=${zoomAfterChromeIn}`,
124
+ `\n '-' fired =`, duringKbZoomOut, `zoom=${zoomAfterKbOut}`);
125
+ process.exit(ok ? 0 : 1);