@sleep2agi/agent-network-dashboard 0.4.6-preview.13 → 0.4.6-preview.131

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 (335) 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/09pxnkf-1.1fj.js +1 -0
  186. package/.next/static/chunks/0eo167c-wlmfz.js +4 -0
  187. package/.next/static/chunks/0glmrdj9112tc.js +7 -0
  188. package/.next/static/chunks/0rxrez_cjn.eh.js +1 -0
  189. package/.next/static/chunks/0x8x.29hkju5a.js +1 -0
  190. package/.next/static/chunks/0yv1jpx~5v038.js +7 -0
  191. package/.next/static/chunks/10tq~cwj-obp4.js +1 -0
  192. package/.next/static/chunks/1450fa_~v9qpc.css +2 -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 +87 -0
  202. package/app/components/ServersDrawer.tsx +64 -27
  203. package/app/components/TopoGraph.tsx +2419 -163
  204. package/app/components/utils.ts +8 -7
  205. package/app/globals.css +19 -1
  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-test.mjs +73 -0
  213. package/scripts/topo-active-links-tooltip-test.mjs +79 -0
  214. package/scripts/topo-arrival-ping-test.mjs +87 -0
  215. package/scripts/topo-arrow-tier-test.mjs +61 -0
  216. package/scripts/topo-auto-fit-test.mjs +73 -0
  217. package/scripts/topo-chat-focus-ring-test.mjs +77 -0
  218. package/scripts/topo-chat-target-breath-test.mjs +84 -0
  219. package/scripts/topo-chip-pin-mirror-test.mjs +113 -0
  220. package/scripts/topo-click-ripple-test.mjs +66 -0
  221. package/scripts/topo-cmdk-edge-clear-test.mjs +109 -0
  222. package/scripts/topo-cmdk-layout-view-test.mjs +108 -0
  223. package/scripts/topo-cmdk-pin-test.mjs +123 -0
  224. package/scripts/topo-cmdk-vendor-clear-test.mjs +133 -0
  225. package/scripts/topo-cmdk-vendor-pin-test.mjs +103 -0
  226. package/scripts/topo-cwd-tooltip-test.mjs +64 -0
  227. package/scripts/topo-dblclick-reset-test.mjs +74 -0
  228. package/scripts/topo-dispatch-pulse-test.mjs +83 -0
  229. package/scripts/topo-edge-badge-click-pin-test.mjs +94 -0
  230. package/scripts/topo-edge-badge-hover-test.mjs +85 -0
  231. package/scripts/topo-edge-count-badge-test.mjs +86 -0
  232. package/scripts/topo-edge-endpoint-highlight-test.mjs +111 -0
  233. package/scripts/topo-edge-focus-test.mjs +113 -0
  234. package/scripts/topo-edge-hover-test.mjs +93 -0
  235. package/scripts/topo-edge-pill-test.mjs +105 -0
  236. package/scripts/topo-edge-tooltip-test.mjs +70 -0
  237. package/scripts/topo-endpoint-ring-test.mjs +93 -0
  238. package/scripts/topo-esc-clears-pin-test.mjs +98 -0
  239. package/scripts/topo-filter-pill-aliases-test.mjs +121 -0
  240. package/scripts/topo-filter-pill-body-click-test.mjs +112 -0
  241. package/scripts/topo-filter-pill-count-test.mjs +110 -0
  242. package/scripts/topo-filter-pill-mobile-test.mjs +90 -0
  243. package/scripts/topo-fit-key-test.mjs +106 -0
  244. package/scripts/topo-freshness-chip-test.mjs +74 -0
  245. package/scripts/topo-group-box-pinned-state-test.mjs +95 -0
  246. package/scripts/topo-group-count-test.mjs +68 -0
  247. package/scripts/topo-group-hover-test.mjs +82 -0
  248. package/scripts/topo-group-label-hover-test.mjs +119 -0
  249. package/scripts/topo-group-label-tint-test.mjs +99 -0
  250. package/scripts/topo-group-label-title-test.mjs +83 -0
  251. package/scripts/topo-group-pin-test.mjs +119 -0
  252. package/scripts/topo-group-status-pips-test.mjs +103 -0
  253. package/scripts/topo-groupbox-live-test.mjs +100 -0
  254. package/scripts/topo-groupbox-test.mjs +4 -2
  255. package/scripts/topo-help-overlay-r109-test.mjs +67 -0
  256. package/scripts/topo-help-overlay-r118-test.mjs +69 -0
  257. package/scripts/topo-help-overlay-r123-test.mjs +69 -0
  258. package/scripts/topo-help-overlay-r59-test.mjs +67 -0
  259. package/scripts/topo-help-overlay-r65-test.mjs +64 -0
  260. package/scripts/topo-help-overlay-r70-test.mjs +63 -0
  261. package/scripts/topo-help-overlay-r78-test.mjs +59 -0
  262. package/scripts/topo-help-overlay-r81-test.mjs +58 -0
  263. package/scripts/topo-help-overlay-r87-test.mjs +64 -0
  264. package/scripts/topo-help-overlay-r91-test.mjs +65 -0
  265. package/scripts/topo-hub-busyness-test.mjs +100 -0
  266. package/scripts/topo-hub-click-fit-test.mjs +137 -0
  267. package/scripts/topo-hub-hover-ring-test.mjs +82 -0
  268. package/scripts/topo-hub-title-test.mjs +93 -0
  269. package/scripts/topo-ingroup-edge-test.mjs +103 -0
  270. package/scripts/topo-label-lift-test.mjs +119 -0
  271. package/scripts/topo-label-scale-test.mjs +78 -0
  272. package/scripts/topo-lastseen-tooltip-test.mjs +59 -0
  273. package/scripts/topo-layout-key-test.mjs +91 -0
  274. package/scripts/topo-legend-count-test.mjs +88 -0
  275. package/scripts/topo-legend-hover-test.mjs +113 -0
  276. package/scripts/topo-legend-panel-header-test.mjs +83 -0
  277. package/scripts/topo-legend-pin-test.mjs +128 -0
  278. package/scripts/topo-legend-row-tint-test.mjs +95 -0
  279. package/scripts/topo-minimap-test.mjs +68 -0
  280. package/scripts/topo-mobile-chips-test.mjs +103 -0
  281. package/scripts/topo-node-hover-lift-test.mjs +85 -0
  282. package/scripts/topo-node-title-test.mjs +101 -0
  283. package/scripts/topo-offline-dim-test.mjs +70 -0
  284. package/scripts/topo-overlap-test.mjs +32 -5
  285. package/scripts/topo-pan-cursor-test.mjs +62 -0
  286. package/scripts/topo-panel-elevation-test.mjs +76 -0
  287. package/scripts/topo-particle-stagger-test.mjs +82 -0
  288. package/scripts/topo-pin-intersection-test.mjs +121 -0
  289. package/scripts/topo-pin-persistence-test.mjs +105 -0
  290. package/scripts/topo-popover-meta-test.mjs +78 -0
  291. package/scripts/topo-pressure-bar-test.mjs +69 -0
  292. package/scripts/topo-pressure-hover-test.mjs +123 -0
  293. package/scripts/topo-pressure-pin-test.mjs +119 -0
  294. package/scripts/topo-pressure-seg-tooltip-test.mjs +98 -0
  295. package/scripts/topo-pulse-rate-test.mjs +71 -0
  296. package/scripts/topo-recent-panel-count-test.mjs +72 -0
  297. package/scripts/topo-recent-row-hover-test.mjs +122 -0
  298. package/scripts/topo-recent-row-pin-test.mjs +126 -0
  299. package/scripts/topo-recent-row-tint-test.mjs +91 -0
  300. package/scripts/topo-recent-row-ts-test.mjs +92 -0
  301. package/scripts/topo-recent-signal-empty-hint-test.mjs +73 -0
  302. package/scripts/topo-recent-signal-empty-test.mjs +63 -0
  303. package/scripts/topo-reduced-motion-test.mjs +77 -0
  304. package/scripts/topo-status-chip-hover-test.mjs +101 -0
  305. package/scripts/topo-status-chip-tooltip-test.mjs +95 -0
  306. package/scripts/topo-tier-ring-occupancy-test.mjs +87 -0
  307. package/scripts/topo-tier-ring-test.mjs +69 -0
  308. package/scripts/topo-tier-ring-tint-test.mjs +110 -0
  309. package/scripts/topo-tier-stagger-test.mjs +89 -0
  310. package/scripts/topo-tz-ghost-test.mjs +69 -0
  311. package/scripts/topo-vendor-chip-hover-test.mjs +111 -0
  312. package/scripts/topo-vendor-letter-tooltip-test.mjs +92 -0
  313. package/scripts/topo-vendor-pill-test.mjs +125 -0
  314. package/scripts/topo-vendor-pin-test.mjs +125 -0
  315. package/scripts/topo-wheel-zoom-test.mjs +79 -0
  316. package/scripts/topo-working-halo-breath-test.mjs +86 -0
  317. package/scripts/topo-zoom-keys-test.mjs +89 -0
  318. package/.next/static/chunks/0-7iowzu4.798.js +0 -1
  319. package/.next/static/chunks/02t5jr4shh.hy.js +0 -1
  320. package/.next/static/chunks/03u_oa2o2jrr~.js +0 -1
  321. package/.next/static/chunks/0_qfg5s5uzs7..js +0 -7
  322. package/.next/static/chunks/0dttftqqehpdj.js +0 -1
  323. package/.next/static/chunks/0elalb9n_.~di.js +0 -1
  324. package/.next/static/chunks/0fqy_0wj_1xa7.js +0 -7
  325. package/.next/static/chunks/0j_q__o8p6g83.js +0 -1
  326. package/.next/static/chunks/0jl6_w50zh4l5.js +0 -1
  327. package/.next/static/chunks/0q_z8ad2uojv5.js +0 -1
  328. package/.next/static/chunks/0r4q73.-1bkyl.js +0 -1
  329. package/.next/static/chunks/0r_c8eccg3z2o.js +0 -1
  330. package/.next/static/chunks/10oi7l-tycgl9.js +0 -1
  331. package/.next/static/chunks/11uk1izuv3~0t.js +0 -1
  332. package/.next/static/chunks/17h~0~zsxjx6x.css +0 -2
  333. /package/.next/static/{nhazRrlYzcsAAYMwx8NFz → A3ssjbOXf7a3BaCWBznPU}/_buildManifest.js +0 -0
  334. /package/.next/static/{nhazRrlYzcsAAYMwx8NFz → A3ssjbOXf7a3BaCWBznPU}/_clientMiddlewareManifest.js +0 -0
  335. /package/.next/static/{nhazRrlYzcsAAYMwx8NFz → A3ssjbOXf7a3BaCWBznPU}/_ssgManifest.js +0 -0
@@ -0,0 +1,100 @@
1
+ /* Round 85 verification: group-box perimeter "marches" when the group
2
+ * has at least one working member, and neither hover nor pin is
3
+ * active. Pin/hover already carry their own emphasis via solid stroke
4
+ * — adding marching ants on top would feel busy. So the live
5
+ * treatment is exclusive to the resting state of a working group.
6
+ *
7
+ * Drive 4 groups via mocked /api/hub/status:
8
+ * alpha: 2 working → live
9
+ * beta: 2 idle → static
10
+ * gamma: 1 working + 1 idle → live
11
+ * delta: 2 offline → static
12
+ *
13
+ * Then verify pinning a live group drops it from the live class
14
+ * (mirrors R68 transient-priority ordering).
15
+ */
16
+ import { chromium } from 'playwright';
17
+ import { readFileSync } from 'node:fs';
18
+
19
+ const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
20
+ const browser = await chromium.launch({ headless: true });
21
+ const ctx = await browser.newContext({ viewport: { width: 1400, 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 {
25
+ localStorage.setItem('anet-theme', 'cyber');
26
+ localStorage.setItem('anet-topo-layout', 'grid');
27
+ sessionStorage.setItem('anet_v3_auth', '1');
28
+ sessionStorage.removeItem('anet-topo-pinned-status');
29
+ sessionStorage.removeItem('anet-topo-pinned-group');
30
+ } catch {}
31
+ });
32
+
33
+ const fresh = new Date(Date.now() - 60 * 1000).toISOString();
34
+ const stale10 = new Date(Date.now() - 10 * 60 * 1000).toISOString();
35
+ await ctx.route('**/api/hub/status*', async (route) => {
36
+ const r = await route.fetch();
37
+ const b = await r.json();
38
+ const nid = (b.sessions || [])[0]?.network_id || 'default';
39
+ const mk = (alias, status, ts) => ({
40
+ alias, status, model: 'claude-opus-4', runtime: 'cli-claude-code',
41
+ network_id: nid, project_dir: null,
42
+ created_at: ts, updated_at: ts, last_seen_at: ts,
43
+ });
44
+ const sessions = [
45
+ mk('alpha1', 'working', fresh),
46
+ mk('alpha2', 'working', fresh),
47
+ mk('beta1', 'idle', fresh),
48
+ mk('beta2', 'idle', fresh),
49
+ mk('gamma1', 'working', fresh),
50
+ mk('gamma2', 'idle', fresh),
51
+ mk('delta1', 'offline', stale10),
52
+ mk('delta2', 'offline', stale10),
53
+ ];
54
+ await route.fulfill({ response: r, json: { ...b, sessions } });
55
+ });
56
+ await ctx.route('**/api/hub/messages*', (route) => route.fulfill({ json: { messages: [] } }));
57
+ await ctx.route('**/api/hub/tasks*', (route) => route.fulfill({ json: { tasks: [] } }));
58
+ const page = await ctx.newPage();
59
+ await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
60
+ await page.waitForFunction(() => document.querySelectorAll('[data-group-box-live]').length >= 4, { timeout: 30000 });
61
+ await page.waitForTimeout(400);
62
+
63
+ const liveByGroup = () => page.evaluate(() => {
64
+ const out = {};
65
+ for (const g of document.querySelectorAll('g[data-group]')) {
66
+ const key = g.getAttribute('data-group');
67
+ const rect = g.querySelector('rect[data-group-box-live]');
68
+ out[key] = {
69
+ live: rect?.getAttribute('data-group-box-live'),
70
+ classy: !!rect?.classList.contains('anet-topo-groupbox-live'),
71
+ };
72
+ }
73
+ return out;
74
+ });
75
+
76
+ const before = await liveByGroup();
77
+
78
+ // Pin alpha (which is currently live). After pinning, alpha should
79
+ // drop the live class — R85 explicitly mutes the ambient marching
80
+ // when a stronger emphasis (pin) is active.
81
+ await page.locator('[data-group-label-hit="alpha"]').click();
82
+ await page.waitForTimeout(250);
83
+ const afterAlphaPin = await liveByGroup();
84
+
85
+ await browser.close();
86
+
87
+ const results = {
88
+ alpha_live: before.alpha?.live === 'true' && before.alpha?.classy,
89
+ gamma_live: before.gamma?.live === 'true' && before.gamma?.classy,
90
+ beta_static: before.beta?.live === 'false' && !before.beta?.classy,
91
+ delta_static: before.delta?.live === 'false' && !before.delta?.classy,
92
+ alphaPin_dropsLive: afterAlphaPin.alpha?.live === 'false' && !afterAlphaPin.alpha?.classy,
93
+ alphaPin_gammaUnchanged: afterAlphaPin.gamma?.live === 'true' && afterAlphaPin.gamma?.classy,
94
+ alphaPin_betaUnchanged: afterAlphaPin.beta?.live === 'false',
95
+ };
96
+ const ok = Object.values(results).every(Boolean);
97
+ console.log(`${ok ? '✅' : '❌'} groupbox-live:`, JSON.stringify(results),
98
+ `\n before=`, before,
99
+ `\n afterAlphaPin=`, afterAlphaPin);
100
+ process.exit(ok ? 0 : 1);
@@ -86,9 +86,11 @@ const results = {};
86
86
  return allGood;
87
87
  });
88
88
 
89
- // label text present for each group
89
+ // label text present for each group. R19 appended " · N" and R58 appended
90
+ // status-mix pips ("2w 1i") to the same <text> element, so the textContent
91
+ // is now "A站· 4 2w 1i" rather than bare "A站". Match by prefix.
90
92
  const labels = await page.$$eval(`${svg} g[data-group] text`, els => els.map(e => (e.textContent || '').trim()));
91
- results.gridLabels = ['A站', '书生', '通信'].every(g => labels.includes(g));
93
+ results.gridLabels = ['A站', '书生', '通信'].every(g => labels.some(l => l.startsWith(g)));
92
94
 
93
95
  await page.screenshot({ path: '/tmp/anet-issue-111/groupbox-grid-cyber.png' });
94
96
  await ctx.close();
@@ -0,0 +1,67 @@
1
+ /* Round 109 verification: HelpOverlay catches up on R108 — palette
2
+ * gained pin-vendor commands (Anthropic/OpenAI/书生). Continues the
3
+ * R59/R62/R65/R70/R78/R81/R87/R91 docs-catch-up cadence.
4
+ *
5
+ * Stacks eight generations of help-overlay assertions — any future
6
+ * regression that drops an entry will be caught by one of:
7
+ * R109 (this) → R91 → R87 → R81 → R78 → R74 → R70 → R65 → R59
8
+ */
9
+ import { chromium } from 'playwright';
10
+ import { readFileSync } from 'node:fs';
11
+
12
+ const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
13
+ const browser = await chromium.launch({ headless: true });
14
+
15
+ const ctx = await browser.newContext({ viewport: { width: 1280, height: 900 } });
16
+ await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
17
+ await ctx.addInitScript(() => {
18
+ try { localStorage.setItem('anet-theme', 'cyber'); sessionStorage.setItem('anet_v3_auth', '1'); } catch {}
19
+ });
20
+ await ctx.route('**/api/hub/messages*', (route) => route.fulfill({ json: { messages: [] } }));
21
+ await ctx.route('**/api/hub/tasks*', (route) => route.fulfill({ json: { tasks: [] } }));
22
+ const page = await ctx.newPage();
23
+ await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
24
+ await page.waitForTimeout(800);
25
+
26
+ await page.keyboard.press('?');
27
+ await page.waitForSelector('[role="dialog"][aria-label="Keyboard shortcuts"]', { timeout: 5000 });
28
+
29
+ const items = await page.evaluate(() => {
30
+ const dialog = document.querySelector('[role="dialog"][aria-label="Keyboard shortcuts"]');
31
+ const groups = [...(dialog?.querySelectorAll('div') || [])];
32
+ let active = null;
33
+ for (const g of groups) {
34
+ if (g.textContent && /^Topology canvas$/i.test(g.textContent.trim())) {
35
+ active = g.parentElement;
36
+ break;
37
+ }
38
+ }
39
+ return active ? [...active.querySelectorAll('li')].map(li => (li.textContent || '').trim()) : [];
40
+ });
41
+
42
+ await browser.close();
43
+
44
+ const has = (s) => items.some(t => t.includes(s));
45
+ const results = {
46
+ r109_pinVendor: has('Pin vendor: Anthropic/OpenAI/书生 via palette → "Pin topology filter…" (R108)'),
47
+ // R91 priors
48
+ r91_clickVendor: has('Pin a vendor filter — click A/O/书/? in the chip row (R88)'),
49
+ r91_clearVendor: has('Clear vendor pin only via palette → "Clear topology vendor filter" (R90)'),
50
+ // R87 priors
51
+ r87_segHover: has('Preview a status filter — hover a pressure-bar segment (R83)'),
52
+ r87_groupLabelHover: has('Preview a team focus — hover a group label (R86)'),
53
+ // R81 priors
54
+ r81_workingChip: has('Highlight working nodes — chip-row sibling of legend (R79)'),
55
+ r81_vendorChip: has('Highlight one vendor — hover A/O/书/? in the chip row (R80)'),
56
+ // R78 / R74 / R70 / R65 / R59 priors — 8 generations now
57
+ r78_pillBodyClick: has('Clear filter — click anywhere on the pill body (R73)'),
58
+ r74_cmdkLayout: has('Toggle layout / Fit canvas via palette (R74)'),
59
+ r70_cmdkPin: has('(R69)'),
60
+ r65_groupClick: has('Pin a team focus (R63)'),
61
+ r62_pinChip: has('Pin a status filter (R60/R61)'),
62
+ r59_clickHub: has('Fit topology to canvas (R52)'),
63
+ };
64
+ const ok = Object.values(results).every(Boolean);
65
+ console.log(`${ok ? '✅' : '❌'} help overlay R109:`, JSON.stringify(results),
66
+ `\n items=`, items);
67
+ process.exit(ok ? 0 : 1);
@@ -0,0 +1,69 @@
1
+ /* Round 118 verification: HelpOverlay catches up on R116 (recent-
2
+ * signal row click pins the edge) + R117 (Cmd+K clear-edge command).
3
+ * Continues the R59/R62/R65/R70/R78/R81/R87/R91/R109 cadence (~5-8
4
+ * rounds between syncs).
5
+ *
6
+ * Nine generations of help-overlay assertions stacked here — any
7
+ * future regression that drops an entry is caught by one of:
8
+ * R118 → R109 → R91 → R87 → R81 → R78 → R74 → R70 → R65 → R59
9
+ */
10
+ import { chromium } from 'playwright';
11
+ import { readFileSync } from 'node:fs';
12
+
13
+ const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
14
+ const browser = await chromium.launch({ headless: true });
15
+
16
+ const ctx = await browser.newContext({ viewport: { width: 1280, height: 900 } });
17
+ await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
18
+ await ctx.addInitScript(() => {
19
+ try { localStorage.setItem('anet-theme', 'cyber'); sessionStorage.setItem('anet_v3_auth', '1'); } catch {}
20
+ });
21
+ await ctx.route('**/api/hub/messages*', (route) => route.fulfill({ json: { messages: [] } }));
22
+ await ctx.route('**/api/hub/tasks*', (route) => route.fulfill({ json: { tasks: [] } }));
23
+ const page = await ctx.newPage();
24
+ await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
25
+ await page.waitForTimeout(800);
26
+
27
+ await page.keyboard.press('?');
28
+ await page.waitForSelector('[role="dialog"][aria-label="Keyboard shortcuts"]', { timeout: 5000 });
29
+
30
+ const items = await page.evaluate(() => {
31
+ const dialog = document.querySelector('[role="dialog"][aria-label="Keyboard shortcuts"]');
32
+ const groups = [...(dialog?.querySelectorAll('div') || [])];
33
+ let active = null;
34
+ for (const g of groups) {
35
+ if (g.textContent && /^Topology canvas$/i.test(g.textContent.trim())) {
36
+ active = g.parentElement;
37
+ break;
38
+ }
39
+ }
40
+ return active ? [...active.querySelectorAll('li')].map(li => (li.textContent || '').trim()) : [];
41
+ });
42
+
43
+ await browser.close();
44
+
45
+ const has = (s) => items.some(t => t.includes(s));
46
+ const results = {
47
+ r118_rowClickPin: has('Pin a flow filter — click a recent-signal row to lock the edge (R116)'),
48
+ r118_cmdkClearEdge: has('Clear edge pin only via palette → "Clear topology edge pin" (R117)'),
49
+ // R109 priors
50
+ r109_pinVendor: has('Pin vendor: Anthropic/OpenAI/书生 via palette → "Pin topology filter…" (R108)'),
51
+ // R91 priors
52
+ r91_clickVendor: has('Pin a vendor filter — click A/O/书/? in the chip row (R88)'),
53
+ r91_clearVendor: has('Clear vendor pin only via palette → "Clear topology vendor filter" (R90)'),
54
+ // R87 priors
55
+ r87_segHover: has('Preview a status filter — hover a pressure-bar segment (R83)'),
56
+ // R81 priors
57
+ r81_vendorChip: has('Highlight one vendor — hover A/O/书/? in the chip row (R80)'),
58
+ // R78 / R74 / R70 / R65 / R59 priors — 10 generations
59
+ r78_pillBodyClick: has('Clear filter — click anywhere on the pill body (R73)'),
60
+ r74_cmdkLayout: has('Toggle layout / Fit canvas via palette (R74)'),
61
+ r70_cmdkPin: has('(R69)'),
62
+ r65_groupClick: has('Pin a team focus (R63)'),
63
+ r62_pinChip: has('Pin a status filter (R60/R61)'),
64
+ r59_clickHub: has('Fit topology to canvas (R52)'),
65
+ };
66
+ const ok = Object.values(results).every(Boolean);
67
+ console.log(`${ok ? '✅' : '❌'} help overlay R118:`, JSON.stringify(results),
68
+ `\n items=`, items);
69
+ process.exit(ok ? 0 : 1);
@@ -0,0 +1,69 @@
1
+ /* Round 123 verification: HelpOverlay catches up on R121 — edge
2
+ * midpoint count badge became click-to-pin. R122's badge hover
3
+ * is the natural partner of R121 click; doesn't need its own
4
+ * entry. Continues the R59/R62/R65/R70/R78/R81/R87/R91/R109/R118
5
+ * cadence.
6
+ *
7
+ * Ten generations of help-overlay assertions stacked here — any
8
+ * future regression that drops an entry is caught by one of:
9
+ * R123 → R118 → R109 → R91 → R87 → R81 → R78 → R74 → R70 → R65 → R59
10
+ */
11
+ import { chromium } from 'playwright';
12
+ import { readFileSync } from 'node:fs';
13
+
14
+ const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
15
+ const browser = await chromium.launch({ headless: true });
16
+
17
+ const ctx = await browser.newContext({ viewport: { width: 1280, height: 900 } });
18
+ await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
19
+ await ctx.addInitScript(() => {
20
+ try { localStorage.setItem('anet-theme', 'cyber'); sessionStorage.setItem('anet_v3_auth', '1'); } catch {}
21
+ });
22
+ await ctx.route('**/api/hub/messages*', (route) => route.fulfill({ json: { messages: [] } }));
23
+ await ctx.route('**/api/hub/tasks*', (route) => route.fulfill({ json: { tasks: [] } }));
24
+ const page = await ctx.newPage();
25
+ await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
26
+ await page.waitForTimeout(800);
27
+
28
+ await page.keyboard.press('?');
29
+ await page.waitForSelector('[role="dialog"][aria-label="Keyboard shortcuts"]', { timeout: 5000 });
30
+
31
+ const items = await page.evaluate(() => {
32
+ const dialog = document.querySelector('[role="dialog"][aria-label="Keyboard shortcuts"]');
33
+ const groups = [...(dialog?.querySelectorAll('div') || [])];
34
+ let active = null;
35
+ for (const g of groups) {
36
+ if (g.textContent && /^Topology canvas$/i.test(g.textContent.trim())) {
37
+ active = g.parentElement;
38
+ break;
39
+ }
40
+ }
41
+ return active ? [...active.querySelectorAll('li')].map(li => (li.textContent || '').trim()) : [];
42
+ });
43
+
44
+ await browser.close();
45
+
46
+ const has = (s) => items.some(t => t.includes(s));
47
+ const results = {
48
+ r123_clickBadge: has('Pin a flow filter from the canvas — click an edge midpoint count badge (R121)'),
49
+ // R118 priors
50
+ r118_rowClickPin: has('Pin a flow filter — click a recent-signal row to lock the edge (R116)'),
51
+ r118_cmdkClearEdge: has('Clear edge pin only via palette → "Clear topology edge pin" (R117)'),
52
+ // R109 priors
53
+ r109_pinVendor: has('Pin vendor: Anthropic/OpenAI/书生 via palette → "Pin topology filter…" (R108)'),
54
+ // R91 priors
55
+ r91_clickVendor: has('Pin a vendor filter — click A/O/书/? in the chip row (R88)'),
56
+ // R87 / R81 / R78 / R74 / R70 / R65 / R59 priors — 11 generations
57
+ r87_segHover: has('Preview a status filter — hover a pressure-bar segment (R83)'),
58
+ r81_vendorChip: has('Highlight one vendor — hover A/O/书/? in the chip row (R80)'),
59
+ r78_pillBodyClick: has('Clear filter — click anywhere on the pill body (R73)'),
60
+ r74_cmdkLayout: has('Toggle layout / Fit canvas via palette (R74)'),
61
+ r70_cmdkPin: has('(R69)'),
62
+ r65_groupClick: has('Pin a team focus (R63)'),
63
+ r62_pinChip: has('Pin a status filter (R60/R61)'),
64
+ r59_clickHub: has('Fit topology to canvas (R52)'),
65
+ };
66
+ const ok = Object.values(results).every(Boolean);
67
+ console.log(`${ok ? '✅' : '❌'} help overlay R123:`, JSON.stringify(results),
68
+ `\n items=`, items);
69
+ process.exit(ok ? 0 : 1);
@@ -0,0 +1,67 @@
1
+ /* Round 59 verification: HelpOverlay topology section documents the new
2
+ * R52 (hub click → fit) / R55 (legend hover) / R56 (recent-signal hover)
3
+ * interactions. R41 dbl-click clarification is also expected.
4
+ *
5
+ * Press "?" on the overview page → assert each of the three new entries
6
+ * shows up under the "Topology canvas" group heading.
7
+ */
8
+ import { chromium } from 'playwright';
9
+ import { readFileSync } from 'node:fs';
10
+
11
+ const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
12
+ const browser = await chromium.launch({ headless: true });
13
+
14
+ const ctx = await browser.newContext({ viewport: { width: 1280, height: 900 } });
15
+ await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
16
+ await ctx.addInitScript(() => {
17
+ try {
18
+ localStorage.setItem('anet-theme', 'cyber');
19
+ sessionStorage.setItem('anet_v3_auth', '1');
20
+ } catch {}
21
+ });
22
+ await ctx.route('**/api/hub/status*', async (route) => {
23
+ const r = await route.fetch();
24
+ const b = await r.json();
25
+ await route.fulfill({ response: r, json: b });
26
+ });
27
+ await ctx.route('**/api/hub/messages*', (route) => route.fulfill({ json: { messages: [] } }));
28
+ await ctx.route('**/api/hub/tasks*', (route) => route.fulfill({ json: { tasks: [] } }));
29
+ const page = await ctx.newPage();
30
+ await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
31
+ await page.waitForTimeout(800);
32
+
33
+ // Open help overlay via `?` (Shift + /).
34
+ await page.keyboard.press('?');
35
+ await page.waitForSelector('[role="dialog"][aria-label="Keyboard shortcuts"]', { timeout: 5000 });
36
+
37
+ const topology = await page.evaluate(() => {
38
+ const dialog = document.querySelector('[role="dialog"][aria-label="Keyboard shortcuts"]');
39
+ if (!dialog) return null;
40
+ // Walk the group divs — each starts with the group title text. Pick the
41
+ // one that says "Topology canvas" and capture its `<li>` items.
42
+ const groups = [...dialog.querySelectorAll('div')];
43
+ let active = null;
44
+ for (const g of groups) {
45
+ if (g.textContent && /^Topology canvas$/i.test(g.textContent.trim())) {
46
+ active = g.parentElement;
47
+ break;
48
+ }
49
+ }
50
+ if (!active) return null;
51
+ return [...active.querySelectorAll('li')].map(li => (li.textContent || '').trim());
52
+ });
53
+
54
+ await browser.close();
55
+ if (!topology) { console.log('❌ topology group not found in help overlay'); process.exit(1); }
56
+
57
+ const has = (s) => topology.some(t => t.includes(s));
58
+ const results = {
59
+ hasHubClickEntry: has('Fit topology to canvas (R52)'),
60
+ hasLegendHoverEntry: has('Highlight nodes of a status (R55)'),
61
+ hasSignalHoverEntry: has('Highlight one flow edge (R56)'),
62
+ hasDblClickClarified: has('(empty canvas only)'),
63
+ };
64
+ const ok = Object.values(results).every(Boolean);
65
+ console.log(`${ok ? '✅' : '❌'} help overlay R59:`, JSON.stringify(results),
66
+ `\n topology items=`, topology);
67
+ process.exit(ok ? 0 : 1);
@@ -0,0 +1,64 @@
1
+ /* Round 65 verification: HelpOverlay topology section catches up on
2
+ * R63 (group label pin) + R64 (active-filter pill ×).
3
+ *
4
+ * Press "?" → assert both new entries render under "Topology canvas".
5
+ * Also verify the R59/R62 prior entries still exist (no regression
6
+ * in the section).
7
+ */
8
+ import { chromium } from 'playwright';
9
+ import { readFileSync } from 'node:fs';
10
+
11
+ const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
12
+ const browser = await chromium.launch({ headless: true });
13
+
14
+ const ctx = await browser.newContext({ viewport: { width: 1280, height: 900 } });
15
+ await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
16
+ await ctx.addInitScript(() => {
17
+ try {
18
+ localStorage.setItem('anet-theme', 'cyber');
19
+ sessionStorage.setItem('anet_v3_auth', '1');
20
+ } catch {}
21
+ });
22
+ await ctx.route('**/api/hub/messages*', (route) => route.fulfill({ json: { messages: [] } }));
23
+ await ctx.route('**/api/hub/tasks*', (route) => route.fulfill({ json: { tasks: [] } }));
24
+ const page = await ctx.newPage();
25
+ await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
26
+ await page.waitForTimeout(800);
27
+
28
+ // Open help overlay via `?`.
29
+ await page.keyboard.press('?');
30
+ await page.waitForSelector('[role="dialog"][aria-label="Keyboard shortcuts"]', { timeout: 5000 });
31
+
32
+ const items = await page.evaluate(() => {
33
+ const dialog = document.querySelector('[role="dialog"][aria-label="Keyboard shortcuts"]');
34
+ if (!dialog) return [];
35
+ const groups = [...dialog.querySelectorAll('div')];
36
+ let active = null;
37
+ for (const g of groups) {
38
+ if (g.textContent && /^Topology canvas$/i.test(g.textContent.trim())) {
39
+ active = g.parentElement;
40
+ break;
41
+ }
42
+ }
43
+ if (!active) return [];
44
+ return [...active.querySelectorAll('li')].map(li => (li.textContent || '').trim());
45
+ });
46
+
47
+ await browser.close();
48
+ if (items.length === 0) { console.log('❌ topology section not found'); process.exit(1); }
49
+
50
+ const has = (s) => items.some(t => t.includes(s));
51
+ const results = {
52
+ r63_groupPin: has('Pin a team focus (R63)'),
53
+ r64_clearOne: has('Clear one filter (R64) — Esc clears all'),
54
+ // R59 priors still present (no regression in section)
55
+ r52_clickHub: has('Fit topology to canvas (R52)'),
56
+ r55_legendHover: has('Highlight nodes of a status (R55)'),
57
+ r56_signalHover: has('Highlight one flow edge (R56)'),
58
+ r60_pinChip: has('Pin a status filter (R60/R61)'),
59
+ r62_esc: has('Clear pinned filter (R62)'),
60
+ };
61
+ const ok = Object.values(results).every(Boolean);
62
+ console.log(`${ok ? '✅' : '❌'} help overlay R65:`, JSON.stringify(results),
63
+ `\n items=`, items);
64
+ process.exit(ok ? 0 : 1);
@@ -0,0 +1,63 @@
1
+ /* Round 70 verification: HelpOverlay topology section surfaces the R69
2
+ * Cmd+K palette pin actions. The 1 new entry sits alongside R65's R63
3
+ * + R64 entries; this test re-verifies the full chain so a future edit
4
+ * accidentally dropping any rung gets caught here.
5
+ */
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
+ sessionStorage.setItem('anet_v3_auth', '1');
18
+ } catch {}
19
+ });
20
+ await ctx.route('**/api/hub/messages*', (route) => route.fulfill({ json: { messages: [] } }));
21
+ await ctx.route('**/api/hub/tasks*', (route) => route.fulfill({ json: { tasks: [] } }));
22
+ const page = await ctx.newPage();
23
+ await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
24
+ await page.waitForTimeout(800);
25
+
26
+ await page.keyboard.press('?');
27
+ await page.waitForSelector('[role="dialog"][aria-label="Keyboard shortcuts"]', { timeout: 5000 });
28
+
29
+ const items = await page.evaluate(() => {
30
+ const dialog = document.querySelector('[role="dialog"][aria-label="Keyboard shortcuts"]');
31
+ if (!dialog) return [];
32
+ const groups = [...dialog.querySelectorAll('div')];
33
+ let active = null;
34
+ for (const g of groups) {
35
+ if (g.textContent && /^Topology canvas$/i.test(g.textContent.trim())) {
36
+ active = g.parentElement;
37
+ break;
38
+ }
39
+ }
40
+ return active ? [...active.querySelectorAll('li')].map(li => (li.textContent || '').trim()) : [];
41
+ });
42
+
43
+ await browser.close();
44
+ if (items.length === 0) { console.log('❌ topology section not found'); process.exit(1); }
45
+
46
+ const has = (s) => items.some(t => t.includes(s));
47
+ const results = {
48
+ r70_cmdkPin: has('Pin / clear filters via palette') && has('(R69)'),
49
+ // R65 priors
50
+ r63_groupPin: has('Pin a team focus (R63)'),
51
+ r64_clearOne: has('Clear one filter (R64)'),
52
+ // R62 priors
53
+ r60_pinChip: has('Pin a status filter (R60/R61)'),
54
+ r62_esc: has('Clear pinned filter (R62)'),
55
+ // R59 priors
56
+ r52_clickHub: has('Fit topology to canvas (R52)'),
57
+ r55_legendHover: has('Highlight nodes of a status (R55)'),
58
+ r56_signalHover: has('Highlight one flow edge (R56)'),
59
+ };
60
+ const ok = Object.values(results).every(Boolean);
61
+ console.log(`${ok ? '✅' : '❌'} help overlay R70:`, JSON.stringify(results),
62
+ `\n items=`, items);
63
+ process.exit(ok ? 0 : 1);
@@ -0,0 +1,59 @@
1
+ /* Round 78 verification: HelpOverlay surfaces the R73 (click pill body
2
+ * to clear) + R77 (hover N active links to brighten all flows) gestures.
3
+ * Both shipped as real user gestures but weren't in the discoverability
4
+ * surface.
5
+ */
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 { localStorage.setItem('anet-theme', 'cyber'); sessionStorage.setItem('anet_v3_auth', '1'); } catch {}
16
+ });
17
+ await ctx.route('**/api/hub/messages*', (route) => route.fulfill({ json: { messages: [] } }));
18
+ await ctx.route('**/api/hub/tasks*', (route) => route.fulfill({ json: { tasks: [] } }));
19
+ const page = await ctx.newPage();
20
+ await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
21
+ await page.waitForTimeout(800);
22
+
23
+ await page.keyboard.press('?');
24
+ await page.waitForSelector('[role="dialog"][aria-label="Keyboard shortcuts"]', { timeout: 5000 });
25
+
26
+ const items = await page.evaluate(() => {
27
+ const dialog = document.querySelector('[role="dialog"][aria-label="Keyboard shortcuts"]');
28
+ const groups = [...(dialog?.querySelectorAll('div') || [])];
29
+ let active = null;
30
+ for (const g of groups) {
31
+ if (g.textContent && /^Topology canvas$/i.test(g.textContent.trim())) {
32
+ active = g.parentElement;
33
+ break;
34
+ }
35
+ }
36
+ return active ? [...active.querySelectorAll('li')].map(li => (li.textContent || '').trim()) : [];
37
+ });
38
+
39
+ await browser.close();
40
+
41
+ const has = (s) => items.some(t => t.includes(s));
42
+ const results = {
43
+ r78_pillBodyClick: has('Clear filter — click anywhere on the pill body (R73)'),
44
+ r78_chipHover: has('Brighten all active flows — hover'),
45
+ // R74 and R70 priors should still appear (no regression)
46
+ r74_cmdkLayout: has('Toggle layout / Fit canvas via palette (R74)'),
47
+ r70_cmdkPin: has('(R69)'),
48
+ // R65 priors
49
+ r63_groupPin: has('Pin a team focus (R63)'),
50
+ r64_clearOne: has('Clear one filter (R64)'),
51
+ // R59 priors
52
+ r52_clickHub: has('Fit topology to canvas (R52)'),
53
+ r55_legendHover: has('Highlight nodes of a status (R55)'),
54
+ r56_signalHover: has('Highlight one flow edge (R56)'),
55
+ };
56
+ const ok = Object.values(results).every(Boolean);
57
+ console.log(`${ok ? '✅' : '❌'} help overlay R78:`, JSON.stringify(results),
58
+ `\n items=`, items);
59
+ process.exit(ok ? 0 : 1);
@@ -0,0 +1,58 @@
1
+ /* Round 81 verification: HelpOverlay surfaces R79 (status chip hover) +
2
+ * R80 (vendor chip letter hover). Both gestures landed without entries
3
+ * in the discoverability surface. Continues the R59/R62/R65/R70/R78
4
+ * docs-catch-up cadence.
5
+ */
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 { localStorage.setItem('anet-theme', 'cyber'); sessionStorage.setItem('anet_v3_auth', '1'); } catch {}
16
+ });
17
+ await ctx.route('**/api/hub/messages*', (route) => route.fulfill({ json: { messages: [] } }));
18
+ await ctx.route('**/api/hub/tasks*', (route) => route.fulfill({ json: { tasks: [] } }));
19
+ const page = await ctx.newPage();
20
+ await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
21
+ await page.waitForTimeout(800);
22
+
23
+ await page.keyboard.press('?');
24
+ await page.waitForSelector('[role="dialog"][aria-label="Keyboard shortcuts"]', { timeout: 5000 });
25
+
26
+ const items = await page.evaluate(() => {
27
+ const dialog = document.querySelector('[role="dialog"][aria-label="Keyboard shortcuts"]');
28
+ const groups = [...(dialog?.querySelectorAll('div') || [])];
29
+ let active = null;
30
+ for (const g of groups) {
31
+ if (g.textContent && /^Topology canvas$/i.test(g.textContent.trim())) {
32
+ active = g.parentElement;
33
+ break;
34
+ }
35
+ }
36
+ return active ? [...active.querySelectorAll('li')].map(li => (li.textContent || '').trim()) : [];
37
+ });
38
+
39
+ await browser.close();
40
+
41
+ const has = (s) => items.some(t => t.includes(s));
42
+ const results = {
43
+ r81_workingChip: has('Highlight working nodes — chip-row sibling of legend (R79)'),
44
+ r81_vendorChip: has('Highlight one vendor — hover A/O/书/? in the chip row (R80)'),
45
+ // R78 priors
46
+ r73_pillBodyClick: has('Clear filter — click anywhere on the pill body (R73)'),
47
+ r77_activeLinks: has('Brighten all active flows — hover'),
48
+ // R74 / R70 / R65 / R59 priors
49
+ r74_cmdkLayout: has('Toggle layout / Fit canvas via palette (R74)'),
50
+ r70_cmdkPin: has('(R69)'),
51
+ r63_groupPin: has('Pin a team focus (R63)'),
52
+ r60_pinChip: has('Pin a status filter (R60/R61)'),
53
+ r52_clickHub: has('Fit topology to canvas (R52)'),
54
+ };
55
+ const ok = Object.values(results).every(Boolean);
56
+ console.log(`${ok ? '✅' : '❌'} help overlay R81:`, JSON.stringify(results),
57
+ `\n items=`, items);
58
+ process.exit(ok ? 0 : 1);