@sleep2agi/agent-network-dashboard 0.4.6-preview.15 → 0.4.6-preview.151

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 (355) 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/05b69-7w4fvbn.css +2 -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/0ax6wj36e_knr.js +7 -0
  187. package/.next/static/chunks/0d45f.svln5hm.js +1 -0
  188. package/.next/static/chunks/0f6m4wjhlakrw.js +1 -0
  189. package/.next/static/chunks/0g1ap~wkozy~6.js +4 -0
  190. package/.next/static/chunks/0glmrdj9112tc.js +7 -0
  191. package/.next/static/chunks/0rxrez_cjn.eh.js +1 -0
  192. package/.next/static/chunks/0x8x.29hkju5a.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 +115 -0
  202. package/app/components/ServersDrawer.tsx +64 -27
  203. package/app/components/TopoGraph.tsx +2866 -190
  204. package/app/components/utils.ts +8 -7
  205. package/app/globals.css +27 -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-nav-test.mjs +117 -0
  213. package/scripts/topo-active-links-chip-test.mjs +73 -0
  214. package/scripts/topo-active-links-tooltip-test.mjs +79 -0
  215. package/scripts/topo-arrival-ping-test.mjs +87 -0
  216. package/scripts/topo-arrow-tier-test.mjs +61 -0
  217. package/scripts/topo-auto-fit-test.mjs +73 -0
  218. package/scripts/topo-chat-focus-ring-test.mjs +77 -0
  219. package/scripts/topo-chat-target-breath-test.mjs +84 -0
  220. package/scripts/topo-chip-pin-mirror-test.mjs +113 -0
  221. package/scripts/topo-click-ripple-test.mjs +66 -0
  222. package/scripts/topo-cmdk-edge-clear-test.mjs +109 -0
  223. package/scripts/topo-cmdk-layout-view-test.mjs +108 -0
  224. package/scripts/topo-cmdk-pin-test.mjs +123 -0
  225. package/scripts/topo-cmdk-vendor-clear-test.mjs +133 -0
  226. package/scripts/topo-cmdk-vendor-pin-test.mjs +103 -0
  227. package/scripts/topo-cwd-tooltip-test.mjs +64 -0
  228. package/scripts/topo-dblclick-reset-test.mjs +74 -0
  229. package/scripts/topo-dispatch-pulse-test.mjs +83 -0
  230. package/scripts/topo-edge-badge-click-pin-test.mjs +94 -0
  231. package/scripts/topo-edge-badge-hot-test.mjs +115 -0
  232. package/scripts/topo-edge-badge-hover-test.mjs +85 -0
  233. package/scripts/topo-edge-count-badge-test.mjs +86 -0
  234. package/scripts/topo-edge-endpoint-highlight-test.mjs +111 -0
  235. package/scripts/topo-edge-focus-test.mjs +113 -0
  236. package/scripts/topo-edge-hover-test.mjs +93 -0
  237. package/scripts/topo-edge-pill-test.mjs +105 -0
  238. package/scripts/topo-edge-tooltip-test.mjs +70 -0
  239. package/scripts/topo-endpoint-ring-test.mjs +93 -0
  240. package/scripts/topo-esc-clears-pin-test.mjs +98 -0
  241. package/scripts/topo-filter-pill-aliases-test.mjs +121 -0
  242. package/scripts/topo-filter-pill-body-click-test.mjs +112 -0
  243. package/scripts/topo-filter-pill-count-test.mjs +110 -0
  244. package/scripts/topo-filter-pill-mobile-test.mjs +90 -0
  245. package/scripts/topo-fit-key-test.mjs +106 -0
  246. package/scripts/topo-freshness-chip-test.mjs +74 -0
  247. package/scripts/topo-group-box-pinned-state-test.mjs +95 -0
  248. package/scripts/topo-group-count-test.mjs +68 -0
  249. package/scripts/topo-group-hover-test.mjs +82 -0
  250. package/scripts/topo-group-label-hover-test.mjs +119 -0
  251. package/scripts/topo-group-label-tint-test.mjs +99 -0
  252. package/scripts/topo-group-label-title-test.mjs +83 -0
  253. package/scripts/topo-group-pin-test.mjs +119 -0
  254. package/scripts/topo-group-status-pips-test.mjs +103 -0
  255. package/scripts/topo-groupbox-hover-lift-test.mjs +127 -0
  256. package/scripts/topo-groupbox-live-test.mjs +100 -0
  257. package/scripts/topo-groupbox-march-busyness-test.mjs +155 -0
  258. package/scripts/topo-groupbox-test.mjs +4 -2
  259. package/scripts/topo-help-overlay-r109-test.mjs +67 -0
  260. package/scripts/topo-help-overlay-r118-test.mjs +69 -0
  261. package/scripts/topo-help-overlay-r123-test.mjs +69 -0
  262. package/scripts/topo-help-overlay-r134-test.mjs +74 -0
  263. package/scripts/topo-help-overlay-r137-test.mjs +81 -0
  264. package/scripts/topo-help-overlay-r141-test.mjs +86 -0
  265. package/scripts/topo-help-overlay-r59-test.mjs +67 -0
  266. package/scripts/topo-help-overlay-r65-test.mjs +64 -0
  267. package/scripts/topo-help-overlay-r70-test.mjs +63 -0
  268. package/scripts/topo-help-overlay-r78-test.mjs +59 -0
  269. package/scripts/topo-help-overlay-r81-test.mjs +58 -0
  270. package/scripts/topo-help-overlay-r87-test.mjs +64 -0
  271. package/scripts/topo-help-overlay-r91-test.mjs +65 -0
  272. package/scripts/topo-hub-busyness-test.mjs +100 -0
  273. package/scripts/topo-hub-click-fit-test.mjs +137 -0
  274. package/scripts/topo-hub-hover-ring-test.mjs +82 -0
  275. package/scripts/topo-hub-title-test.mjs +93 -0
  276. package/scripts/topo-hub-working-count-test.mjs +99 -0
  277. package/scripts/topo-ingroup-edge-test.mjs +103 -0
  278. package/scripts/topo-label-lift-test.mjs +119 -0
  279. package/scripts/topo-label-scale-test.mjs +78 -0
  280. package/scripts/topo-lastseen-tooltip-test.mjs +59 -0
  281. package/scripts/topo-layout-key-test.mjs +91 -0
  282. package/scripts/topo-legend-count-test.mjs +88 -0
  283. package/scripts/topo-legend-hover-test.mjs +113 -0
  284. package/scripts/topo-legend-panel-header-test.mjs +83 -0
  285. package/scripts/topo-legend-pin-test.mjs +128 -0
  286. package/scripts/topo-legend-row-hover-lift-test.mjs +109 -0
  287. package/scripts/topo-legend-row-tint-test.mjs +95 -0
  288. package/scripts/topo-minimap-test.mjs +68 -0
  289. package/scripts/topo-mobile-chips-test.mjs +103 -0
  290. package/scripts/topo-node-hover-lift-test.mjs +85 -0
  291. package/scripts/topo-node-title-test.mjs +101 -0
  292. package/scripts/topo-offline-dim-test.mjs +70 -0
  293. package/scripts/topo-online-chip-nav-test.mjs +143 -0
  294. package/scripts/topo-orbit-busyness-test.mjs +96 -0
  295. package/scripts/topo-overlap-test.mjs +32 -5
  296. package/scripts/topo-pan-cursor-test.mjs +62 -0
  297. package/scripts/topo-panel-elevation-test.mjs +76 -0
  298. package/scripts/topo-panel-hover-elevation-test.mjs +118 -0
  299. package/scripts/topo-particle-stagger-test.mjs +82 -0
  300. package/scripts/topo-pin-intersection-empty-test.mjs +129 -0
  301. package/scripts/topo-pin-intersection-test.mjs +121 -0
  302. package/scripts/topo-pin-persistence-test.mjs +105 -0
  303. package/scripts/topo-popover-meta-test.mjs +78 -0
  304. package/scripts/topo-pressure-bar-test.mjs +69 -0
  305. package/scripts/topo-pressure-hover-test.mjs +123 -0
  306. package/scripts/topo-pressure-pin-test.mjs +119 -0
  307. package/scripts/topo-pressure-seg-tooltip-test.mjs +98 -0
  308. package/scripts/topo-pulse-rate-test.mjs +71 -0
  309. package/scripts/topo-recent-panel-count-test.mjs +72 -0
  310. package/scripts/topo-recent-panel-hot-header-test.mjs +132 -0
  311. package/scripts/topo-recent-panel-more-nav-test.mjs +127 -0
  312. package/scripts/topo-recent-panel-more-test.mjs +106 -0
  313. package/scripts/topo-recent-row-hot-test.mjs +110 -0
  314. package/scripts/topo-recent-row-hover-lift-test.mjs +128 -0
  315. package/scripts/topo-recent-row-hover-test.mjs +122 -0
  316. package/scripts/topo-recent-row-pin-test.mjs +126 -0
  317. package/scripts/topo-recent-row-tint-test.mjs +91 -0
  318. package/scripts/topo-recent-row-ts-test.mjs +95 -0
  319. package/scripts/topo-recent-row-typography-test.mjs +119 -0
  320. package/scripts/topo-recent-signal-empty-hint-test.mjs +73 -0
  321. package/scripts/topo-recent-signal-empty-test.mjs +63 -0
  322. package/scripts/topo-reduced-motion-test.mjs +77 -0
  323. package/scripts/topo-status-chip-hover-test.mjs +101 -0
  324. package/scripts/topo-status-chip-tooltip-test.mjs +95 -0
  325. package/scripts/topo-tier-ring-occupancy-test.mjs +87 -0
  326. package/scripts/topo-tier-ring-test.mjs +69 -0
  327. package/scripts/topo-tier-ring-tint-test.mjs +110 -0
  328. package/scripts/topo-tier-stagger-test.mjs +89 -0
  329. package/scripts/topo-tz-ghost-test.mjs +69 -0
  330. package/scripts/topo-vendor-chip-hover-test.mjs +111 -0
  331. package/scripts/topo-vendor-letter-tooltip-test.mjs +92 -0
  332. package/scripts/topo-vendor-pill-test.mjs +125 -0
  333. package/scripts/topo-vendor-pin-test.mjs +125 -0
  334. package/scripts/topo-wheel-zoom-test.mjs +79 -0
  335. package/scripts/topo-working-chip-pin-test.mjs +148 -0
  336. package/scripts/topo-working-halo-breath-test.mjs +86 -0
  337. package/scripts/topo-zoom-keys-test.mjs +89 -0
  338. package/.next/static/chunks/0-7iowzu4.798.js +0 -1
  339. package/.next/static/chunks/02t5jr4shh.hy.js +0 -1
  340. package/.next/static/chunks/0_qfg5s5uzs7..js +0 -7
  341. package/.next/static/chunks/0e8tvxp4z.y4s.js +0 -1
  342. package/.next/static/chunks/0elalb9n_.~di.js +0 -1
  343. package/.next/static/chunks/0fqy_0wj_1xa7.js +0 -7
  344. package/.next/static/chunks/0j_q__o8p6g83.js +0 -1
  345. package/.next/static/chunks/0jl6_w50zh4l5.js +0 -1
  346. package/.next/static/chunks/0nia.a1mfg7q1.js +0 -1
  347. package/.next/static/chunks/0r4q73.-1bkyl.js +0 -1
  348. package/.next/static/chunks/0r_c8eccg3z2o.js +0 -1
  349. package/.next/static/chunks/10oi7l-tycgl9.js +0 -1
  350. package/.next/static/chunks/11uk1izuv3~0t.js +0 -1
  351. package/.next/static/chunks/13vw-ubg-9pjp.css +0 -2
  352. package/.next/static/chunks/14m.l5k.wx7cx.js +0 -1
  353. /package/.next/static/{-hO5QrBL0EPsoBbzcd662 → jNoJAOY9PpVhTslXxUvqQ}/_buildManifest.js +0 -0
  354. /package/.next/static/{-hO5QrBL0EPsoBbzcd662 → jNoJAOY9PpVhTslXxUvqQ}/_clientMiddlewareManifest.js +0 -0
  355. /package/.next/static/{-hO5QrBL0EPsoBbzcd662 → jNoJAOY9PpVhTslXxUvqQ}/_ssgManifest.js +0 -0
@@ -0,0 +1,132 @@
1
+ /* Round 129 verification: recent-signal panel header gains a
2
+ * " · N hot" amber tail when ≥ 1 flowLink has count ≥ 10.
3
+ *
4
+ * The hot-lane convention's surfaces:
5
+ * R126: canvas midpoint count badge → amber stroke
6
+ * R127: recent-signal row count digit → amber + bold
7
+ * R129: recent-signal panel HEADER → " · N hot" amber suffix
8
+ *
9
+ * Vertical scan path now reads: header → rows → canvas. Each layer
10
+ * answers a different scope: header = "how many hot?", rows =
11
+ * "which ones?", canvas = "where on the topology?".
12
+ *
13
+ * Three states:
14
+ * A. 3 pairs, all count < 10 → header "3 flows", no hot tail
15
+ * B. 5 pairs, 2 of them count ≥ 10 → header "5 flows · 2 hot", amber tail
16
+ * C. 5 pairs, 5 of them count ≥ 10 → header "5 flows · 5 hot"
17
+ */
18
+ import { chromium } from 'playwright';
19
+ import { readFileSync } from 'node:fs';
20
+
21
+ const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
22
+
23
+ async function probe(seedPairs) {
24
+ // seedPairs is an array of [from, to, count] tuples — each pair gets
25
+ // `count` msgs to make link.count == count after dedup.
26
+ const browser = await chromium.launch({ headless: true });
27
+ const ctx = await browser.newContext({ viewport: { width: 1400, height: 1500 } });
28
+ await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
29
+ await ctx.addInitScript(() => {
30
+ try { localStorage.setItem('anet-theme', 'cyber'); sessionStorage.setItem('anet_v3_auth', '1'); } catch {}
31
+ });
32
+
33
+ const fresh = new Date(Date.now() - 60 * 1000).toISOString();
34
+ const aliasSet = new Set();
35
+ for (const [a, b] of seedPairs) { aliasSet.add(a); aliasSet.add(b); }
36
+ const aliases = [...aliasSet];
37
+ await ctx.route('**/api/hub/status*', async (route) => {
38
+ const r = await route.fetch();
39
+ const b = await r.json();
40
+ const nid = (b.sessions || [])[0]?.network_id || 'default';
41
+ const mk = (alias) => ({
42
+ alias, status: 'working', model: 'claude-opus-4', runtime: 'cli-claude-code',
43
+ network_id: nid, project_dir: null,
44
+ created_at: fresh, updated_at: fresh, last_seen_at: fresh,
45
+ });
46
+ await route.fulfill({ response: r, json: { ...b, sessions: aliases.map(mk) } });
47
+ });
48
+
49
+ const now = Date.now();
50
+ const msgs = [];
51
+ let id = 0;
52
+ for (const [from, to, count] of seedPairs) {
53
+ for (let i = 0; i < count; i++) {
54
+ msgs.push({
55
+ id: `m${id++}`,
56
+ from_alias: from,
57
+ to_alias: to,
58
+ content: 'hi',
59
+ network_id: 'default',
60
+ created_at: new Date(now - (20000 + i * 500 + id * 13)).toISOString(),
61
+ });
62
+ }
63
+ }
64
+ await ctx.route('**/api/hub/messages*', (route) => route.fulfill({ json: { messages: msgs } }));
65
+ await ctx.route('**/api/hub/tasks*', (route) => route.fulfill({ json: { tasks: [] } }));
66
+
67
+ const page = await ctx.newPage();
68
+ await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
69
+ await page.waitForFunction((n) => document.querySelectorAll('g[data-node]').length === n, aliases.length, { timeout: 30000 });
70
+ await page.waitForTimeout(500);
71
+
72
+ const out = await page.evaluate(() => {
73
+ const count = document.querySelector('[data-recent-panel-count]');
74
+ const hot = document.querySelector('[data-recent-panel-hot-count]');
75
+ return {
76
+ countText: count?.textContent,
77
+ hotText: hot?.textContent,
78
+ hotAttr: hot?.getAttribute('data-recent-panel-hot-count'),
79
+ hotFill: hot?.getAttribute('fill'),
80
+ hotWeight: hot?.getAttribute('font-weight'),
81
+ };
82
+ });
83
+
84
+ await browser.close();
85
+ return out;
86
+ }
87
+
88
+ // State A: all warm
89
+ const a = await probe([
90
+ ['alpha', 'beta', 4],
91
+ ['gamma', 'delta', 5],
92
+ ['epsilon', 'zeta', 3],
93
+ ]);
94
+
95
+ // State B: 5 pairs, 2 hot (≥ 10)
96
+ const b = await probe([
97
+ ['alpha', 'beta', 12], // hot
98
+ ['gamma', 'delta', 15], // hot
99
+ ['epsilon', 'zeta', 4],
100
+ ['eta', 'theta', 6],
101
+ ['iota', 'kappa', 8],
102
+ ]);
103
+
104
+ // State C: 5 pairs, all 5 hot
105
+ const c = await probe([
106
+ ['alpha', 'beta', 12],
107
+ ['gamma', 'delta', 11],
108
+ ['epsilon', 'zeta', 14],
109
+ ['eta', 'theta', 13],
110
+ ['iota', 'kappa', 25],
111
+ ]);
112
+
113
+ const amber = '#fbbf24';
114
+
115
+ const results = {
116
+ a_count_3flows: a.countText === '3 flows',
117
+ a_noHotTspan: a.hotText === undefined,
118
+
119
+ b_count_5flows: b.countText === '5 flows',
120
+ b_hot_text: b.hotText === ' · 2 hot',
121
+ b_hot_attr: b.hotAttr === '2',
122
+ b_hot_amberFill: (b.hotFill || '').toLowerCase() === amber,
123
+ b_hot_boldWeight: b.hotWeight === '700',
124
+
125
+ c_count_5flows: c.countText === '5 flows',
126
+ c_hot_text: c.hotText === ' · 5 hot',
127
+ c_hot_attr: c.hotAttr === '5',
128
+ };
129
+ const ok = Object.values(results).every(Boolean);
130
+ console.log(`${ok ? '✅' : '❌'} recent-panel hot header:`, JSON.stringify(results),
131
+ `\n A=`, a, `\n B=`, b, `\n C=`, c);
132
+ process.exit(ok ? 0 : 1);
@@ -0,0 +1,127 @@
1
+ /* Round 133 verification: R128's "+N more flows" footer becomes a
2
+ * clickable nav to /messages. R128 introduced the truncation hint
3
+ * as pure metadata; R133 lets the user act on it.
4
+ *
5
+ * Three states tested:
6
+ * A. Click footer → navigation lands on /messages
7
+ * B. Hover footer → opacity rises 0.55 → 0.85, underline appears
8
+ * C. Leave hover → opacity drops back, underline gone
9
+ *
10
+ * Plus: footer carries role="link" + cursor:pointer + a tooltip
11
+ * referencing /messages, all for discoverability and a11y.
12
+ */
13
+ import { chromium } from 'playwright';
14
+ import { readFileSync } from 'node:fs';
15
+
16
+ const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
17
+ const browser = await chromium.launch({ headless: true });
18
+
19
+ const ctx = await browser.newContext({ viewport: { width: 1400, height: 1500 } });
20
+ await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
21
+ await ctx.addInitScript(() => {
22
+ try { localStorage.setItem('anet-theme', 'cyber'); sessionStorage.setItem('anet_v3_auth', '1'); } catch {}
23
+ });
24
+
25
+ const fresh = new Date(Date.now() - 60 * 1000).toISOString();
26
+ const aliases = ['alpha', 'beta', 'gamma', 'delta', 'epsilon', 'zeta'];
27
+ await ctx.route('**/api/hub/status*', async (route) => {
28
+ const r = await route.fetch();
29
+ const b = await r.json();
30
+ const nid = (b.sessions || [])[0]?.network_id || 'default';
31
+ const mk = (alias) => ({
32
+ alias, status: 'working', model: 'claude-opus-4', runtime: 'cli-claude-code',
33
+ network_id: nid, project_dir: null,
34
+ created_at: fresh, updated_at: fresh, last_seen_at: fresh,
35
+ });
36
+ await route.fulfill({ response: r, json: { ...b, sessions: aliases.map(mk) } });
37
+ });
38
+
39
+ const now = Date.now();
40
+ const msgs = [];
41
+ // 5 distinct pairs → forces R128 footer with "+ 2 more flows"
42
+ for (let i = 0; i < 5; i++) {
43
+ msgs.push({
44
+ id: `m${i}`,
45
+ from_alias: aliases[i],
46
+ to_alias: aliases[(i + 1) % aliases.length],
47
+ content: 'hi',
48
+ network_id: 'default',
49
+ created_at: new Date(now - (20000 + i * 1000)).toISOString(),
50
+ });
51
+ }
52
+ await ctx.route('**/api/hub/messages*', (route) => route.fulfill({ json: { messages: msgs } }));
53
+ await ctx.route('**/api/hub/tasks*', (route) => route.fulfill({ json: { tasks: [] } }));
54
+
55
+ const page = await ctx.newPage();
56
+ await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
57
+ await page.waitForFunction(() => document.querySelectorAll('g[data-node]').length === 6, { timeout: 30000 });
58
+ await page.waitForSelector('[data-recent-panel-more-nav]', { timeout: 10000 });
59
+ await page.waitForTimeout(400);
60
+
61
+ const beforeHover = await page.evaluate(() => {
62
+ const wrap = document.querySelector('[data-recent-panel-more-nav]');
63
+ const text = wrap?.querySelector('text[data-recent-panel-more]');
64
+ return {
65
+ role: wrap?.getAttribute('role'),
66
+ tabindex: wrap?.getAttribute('tabindex'),
67
+ cursor: (wrap?.getAttribute('style') || '').includes('pointer'),
68
+ title: wrap?.querySelector('title')?.textContent,
69
+ opacity: text?.getAttribute('opacity'),
70
+ underline: text?.getAttribute('text-decoration'),
71
+ moreCount: text?.getAttribute('data-recent-panel-more'),
72
+ };
73
+ });
74
+
75
+ // Hover the footer
76
+ await page.locator('[data-recent-panel-more-nav]').hover();
77
+ await page.waitForTimeout(250);
78
+ const onHover = await page.evaluate(() => {
79
+ const text = document.querySelector('[data-recent-panel-more-nav] text');
80
+ return {
81
+ opacity: text?.getAttribute('opacity'),
82
+ underline: text?.getAttribute('text-decoration'),
83
+ };
84
+ });
85
+
86
+ // Move away → restore
87
+ await page.mouse.move(10, 10);
88
+ await page.waitForTimeout(250);
89
+ const afterLeave = await page.evaluate(() => {
90
+ const text = document.querySelector('[data-recent-panel-more-nav] text');
91
+ return {
92
+ opacity: text?.getAttribute('opacity'),
93
+ underline: text?.getAttribute('text-decoration'),
94
+ };
95
+ });
96
+
97
+ // Click → expect /messages navigation
98
+ await page.locator('[data-recent-panel-more-nav]').click();
99
+ await page.waitForURL('**/messages', { timeout: 10000 });
100
+ const finalUrl = page.url();
101
+
102
+ await browser.close();
103
+
104
+ const results = {
105
+ before_roleLink: beforeHover.role === 'link',
106
+ before_tabIndex0: beforeHover.tabindex === '0',
107
+ before_cursorPointer: beforeHover.cursor,
108
+ before_titleMentionsMessages: (beforeHover.title || '').includes('/messages'),
109
+ before_moreCount2: beforeHover.moreCount === '2',
110
+ before_opacity55: beforeHover.opacity === '0.55',
111
+ before_noUnderline: beforeHover.underline === 'none' || !beforeHover.underline,
112
+
113
+ hover_opacity85: onHover.opacity === '0.85',
114
+ hover_underline: onHover.underline === 'underline',
115
+
116
+ leave_opacityRestored: afterLeave.opacity === '0.55',
117
+ leave_underlineGone: afterLeave.underline === 'none' || !afterLeave.underline,
118
+
119
+ click_navigatedToMessages: /\/messages$/.test(finalUrl),
120
+ };
121
+ const ok = Object.values(results).every(Boolean);
122
+ console.log(`${ok ? '✅' : '❌'} recent-panel more nav:`, JSON.stringify(results),
123
+ `\n before=`, beforeHover,
124
+ `\n onHover=`, onHover,
125
+ `\n afterLeave=`, afterLeave,
126
+ `\n finalUrl=`, finalUrl);
127
+ process.exit(ok ? 0 : 1);
@@ -0,0 +1,106 @@
1
+ /* Round 128 verification: "+N more flows" overflow hint in the
2
+ * recent-signal panel.
3
+ *
4
+ * The panel renders top 3 flowLinks via .slice(0, 3). When the
5
+ * fleet has > 3 active flows, the rest silently disappear — the
6
+ * R96 "X flows" header reports the total but doesn't make
7
+ * truncation explicit. R128 adds a muted italic footer
8
+ * "+ N more flow(s)"
9
+ * inside the existing panel (y=82, between row-3 baseline and the
10
+ * panel bottom at y=84), only when flowLinks.length > 3.
11
+ *
12
+ * Three states tested:
13
+ * - 5 distinct flow pairs → footer shows "+ 2 more flows"
14
+ * - exactly 3 flow pairs → footer absent
15
+ * - 0 flows (empty panel) → footer absent (R45 placeholder wins)
16
+ *
17
+ * Note: the test seeds (count) messages per pair so each unique
18
+ * (from→to) pair becomes ONE flowLink (deduped). Pairs > 3 force
19
+ * the hint; pairs ≤ 3 don't.
20
+ */
21
+ import { chromium } from 'playwright';
22
+ import { readFileSync } from 'node:fs';
23
+
24
+ const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
25
+
26
+ async function probe(pairCount) {
27
+ const browser = await chromium.launch({ headless: true });
28
+ const ctx = await browser.newContext({ viewport: { width: 1400, height: 1500 } });
29
+ await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
30
+ await ctx.addInitScript(() => {
31
+ try { localStorage.setItem('anet-theme', 'cyber'); sessionStorage.setItem('anet_v3_auth', '1'); } catch {}
32
+ });
33
+
34
+ const fresh = new Date(Date.now() - 60 * 1000).toISOString();
35
+ const aliases = ['alpha', 'beta', 'gamma', 'delta', 'epsilon', 'zeta'];
36
+ await ctx.route('**/api/hub/status*', async (route) => {
37
+ const r = await route.fetch();
38
+ const b = await r.json();
39
+ const nid = (b.sessions || [])[0]?.network_id || 'default';
40
+ const mk = (alias) => ({
41
+ alias, status: 'working', model: 'claude-opus-4', runtime: 'cli-claude-code',
42
+ network_id: nid, project_dir: null,
43
+ created_at: fresh, updated_at: fresh, last_seen_at: fresh,
44
+ });
45
+ await route.fulfill({ response: r, json: { ...b, sessions: aliases.map(mk) } });
46
+ });
47
+
48
+ const now = Date.now();
49
+ const msgs = [];
50
+ // Make pairCount distinct (from→to) pairs, 1 msg each, ascending age
51
+ for (let i = 0; i < pairCount; i++) {
52
+ msgs.push({
53
+ id: `m${i}`,
54
+ from_alias: aliases[i],
55
+ to_alias: aliases[(i + 1) % aliases.length],
56
+ content: 'hi',
57
+ network_id: 'default',
58
+ created_at: new Date(now - (20000 + i * 1000)).toISOString(),
59
+ });
60
+ }
61
+ await ctx.route('**/api/hub/messages*', (route) => route.fulfill({ json: { messages: msgs } }));
62
+ await ctx.route('**/api/hub/tasks*', (route) => route.fulfill({ json: { tasks: [] } }));
63
+
64
+ const page = await ctx.newPage();
65
+ await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
66
+ await page.waitForFunction(() => document.querySelectorAll('g[data-node]').length === 6, { timeout: 30000 });
67
+ await page.waitForTimeout(500);
68
+
69
+ const out = await page.evaluate(() => {
70
+ const el = document.querySelector('[data-recent-panel-more]');
71
+ const rows = document.querySelectorAll('[data-recent-row]').length;
72
+ const headerCount = document.querySelector('[data-recent-panel-count]')?.textContent;
73
+ return {
74
+ footerPresent: !!el,
75
+ footerText: el?.textContent?.trim(),
76
+ footerAttr: el?.getAttribute('data-recent-panel-more'),
77
+ rows,
78
+ headerCount,
79
+ };
80
+ });
81
+
82
+ await browser.close();
83
+ return out;
84
+ }
85
+
86
+ const five = await probe(5);
87
+ const three = await probe(3);
88
+ const zero = await probe(0);
89
+
90
+ const results = {
91
+ five_footerPresent: five.footerPresent,
92
+ five_footerText: five.footerText === '+ 2 more flows',
93
+ five_footerAttr: five.footerAttr === '2',
94
+ five_rowsCapped3: five.rows === 3,
95
+ five_headerSaysFive: five.headerCount?.startsWith('5'),
96
+
97
+ three_footerAbsent: !three.footerPresent,
98
+ three_rowsExactly3: three.rows === 3,
99
+
100
+ zero_footerAbsent: !zero.footerPresent,
101
+ zero_rowsZero: zero.rows === 0,
102
+ };
103
+ const ok = Object.values(results).every(Boolean);
104
+ console.log(`${ok ? '✅' : '❌'} recent-panel more:`, JSON.stringify(results),
105
+ `\n five=`, five, `\n three=`, three, `\n zero=`, zero);
106
+ process.exit(ok ? 0 : 1);
@@ -0,0 +1,110 @@
1
+ /* Round 127 verification: recent-signal panel row mirrors R126's
2
+ * canvas hot-badge convention. When link.count >= 10 the count
3
+ * digit inside the row text renders in amber (#d97706 light,
4
+ * #fbbf24 dark) + bold (font-weight 700). Surrounding alias text +
5
+ * separators stay in legendText/legendHeadline.
6
+ *
7
+ * Fleet:
8
+ * alpha → beta: 12 msgs → HOT row, count tspan amber+bold
9
+ * beta → gamma: 4 msgs → warm row, count tspan default
10
+ *
11
+ * Path:
12
+ * 1. recent panel has 2 rows; data-recent-row-hot reflects bucket
13
+ * 2. alpha→beta row: data-recent-row-count-hot tspan present, amber
14
+ * 3. beta→gamma row: data-recent-row-count (non-hot) tspan present
15
+ * 4. Symmetry with R126: the canvas badge for alpha→beta and the
16
+ * recent-row count for alpha→beta both render the same amber
17
+ * hex.
18
+ */
19
+ import { chromium } from 'playwright';
20
+ import { readFileSync } from 'node:fs';
21
+
22
+ const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
23
+ const browser = await chromium.launch({ headless: true });
24
+
25
+ const ctx = await browser.newContext({ viewport: { width: 1400, height: 1500 } });
26
+ await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
27
+ await ctx.addInitScript(() => {
28
+ try { localStorage.setItem('anet-theme', 'cyber'); sessionStorage.setItem('anet_v3_auth', '1'); } catch {}
29
+ });
30
+
31
+ const fresh = new Date(Date.now() - 60 * 1000).toISOString();
32
+ await ctx.route('**/api/hub/status*', async (route) => {
33
+ const r = await route.fetch();
34
+ const b = await r.json();
35
+ const nid = (b.sessions || [])[0]?.network_id || 'default';
36
+ const mk = (alias, status) => ({
37
+ alias, status, model: 'claude-opus-4', runtime: 'cli-claude-code',
38
+ network_id: nid, project_dir: null,
39
+ created_at: fresh, updated_at: fresh, last_seen_at: fresh,
40
+ });
41
+ await route.fulfill({ response: r, json: { ...b, sessions: [
42
+ mk('alpha', 'working'), mk('beta', 'working'), mk('gamma', 'idle'),
43
+ ] } });
44
+ });
45
+
46
+ const now = Date.now();
47
+ const mkMsg = (id, from_alias, to_alias, ageMs) => ({
48
+ id, from_alias, to_alias, content: 'hi', network_id: 'default',
49
+ created_at: new Date(now - ageMs).toISOString(),
50
+ });
51
+ const msgs = [];
52
+ for (let i = 0; i < 12; i++) msgs.push(mkMsg(`a${i}`, 'alpha', 'beta', 20000 + i * 500));
53
+ for (let i = 0; i < 4; i++) msgs.push(mkMsg(`b${i}`, 'beta', 'gamma', 30000 + i * 500));
54
+ await ctx.route('**/api/hub/messages*', (route) => route.fulfill({ json: { messages: msgs } }));
55
+ await ctx.route('**/api/hub/tasks*', (route) => route.fulfill({ json: { tasks: [] } }));
56
+
57
+ const page = await ctx.newPage();
58
+ await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
59
+ await page.waitForFunction(() => document.querySelectorAll('g[data-node]').length === 3, { timeout: 30000 });
60
+ await page.waitForSelector('[data-recent-row="alpha->beta"]', { timeout: 10000 });
61
+ await page.waitForTimeout(400);
62
+
63
+ const inspect = (key) => page.evaluate((k) => {
64
+ const row = document.querySelector(`[data-recent-row="${k}"]`);
65
+ if (!row) return null;
66
+ const hotTspan = row.querySelector('[data-recent-row-count-hot]');
67
+ const warmTspan = row.querySelector('[data-recent-row-count]');
68
+ return {
69
+ hot: row.getAttribute('data-recent-row-hot'),
70
+ hotTspanText: hotTspan?.textContent,
71
+ hotTspanFill: hotTspan?.getAttribute('fill'),
72
+ hotTspanWeight: hotTspan?.getAttribute('font-weight'),
73
+ warmTspanText: warmTspan?.textContent,
74
+ };
75
+ }, key);
76
+
77
+ const a2b = await inspect('alpha->beta');
78
+ const b2g = await inspect('beta->gamma');
79
+
80
+ // Also assert the canvas badge for alpha→beta still flips to the
81
+ // same amber stroke — symmetry of canvas + panel hot signals.
82
+ const badgeStroke = await page.evaluate(() => {
83
+ const g = document.querySelector('[data-edge-count-badge="alpha->beta"]');
84
+ return g?.querySelector('circle')?.getAttribute('stroke');
85
+ });
86
+
87
+ await browser.close();
88
+
89
+ // Dark theme amber: #fbbf24
90
+ const amberHex = '#fbbf24';
91
+
92
+ const results = {
93
+ a2b_attrHot: a2b !== null && a2b.hot === 'true',
94
+ a2b_hotTspan: a2b !== null && a2b.hotTspanText === '12',
95
+ a2b_amberFill: a2b !== null && (a2b.hotTspanFill || '').toLowerCase() === amberHex,
96
+ a2b_boldWeight: a2b !== null && a2b.hotTspanWeight === '700',
97
+ a2b_noWarmTspan: a2b !== null && a2b.warmTspanText === undefined,
98
+
99
+ b2g_attrNotHot: b2g !== null && b2g.hot === 'false',
100
+ b2g_warmTspan: b2g !== null && b2g.warmTspanText === '4',
101
+ b2g_noHotTspan: b2g !== null && a2b !== null && b2g.hotTspanText === undefined,
102
+
103
+ symmetric_badgeAmber: (badgeStroke || '').toLowerCase() === amberHex,
104
+ };
105
+ const ok = Object.values(results).every(Boolean);
106
+ console.log(`${ok ? '✅' : '❌'} recent-row hot:`, JSON.stringify(results),
107
+ `\n a2b=`, a2b,
108
+ `\n b2g=`, b2g,
109
+ `\n canvas badge stroke for alpha→beta =`, badgeStroke);
110
+ process.exit(ok ? 0 : 1);
@@ -0,0 +1,128 @@
1
+ /* Round 143 verification: recent-signal panel rows lift 1px on
2
+ * hover or pin. Closes the "interactive surface elevates" idiom
3
+ * across four nested canvas-region scopes:
4
+ * R51 node hover-lift (canvas element) → translateY(-2px)
5
+ * R135 overlay panels (canvas chrome) → drop-shadow boost
6
+ * R142 group boxes (canvas-side per-team) → drop-shadow filter
7
+ * R143 recent-signal rows (panel content) → translateY(-1px)
8
+ *
9
+ * Smaller layer = smaller lift (1px row, 2px node, drop-shadow
10
+ * panel/box). Each layer signals interactivity in its own
11
+ * vocabulary.
12
+ *
13
+ * States:
14
+ * 1. Idle row: data-recent-row-lifted="false", no transform
15
+ * 2. Hover row → lifted=true, transform contains translateY(-1px)
16
+ * 3. Leave hover → restored to flat
17
+ * 4. Click to pin → lifted=true (pin keeps the lift)
18
+ * 5. Esc → cleared back to flat
19
+ */
20
+ import { chromium } from 'playwright';
21
+ import { readFileSync } from 'node:fs';
22
+
23
+ const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
24
+ const browser = await chromium.launch({ headless: true });
25
+
26
+ const ctx = await browser.newContext({ viewport: { width: 1400, height: 1500 } });
27
+ await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
28
+ await ctx.addInitScript(() => {
29
+ try { localStorage.setItem('anet-theme', 'cyber'); sessionStorage.setItem('anet_v3_auth', '1'); } 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 mk = (alias, status) => ({
38
+ alias, status, model: 'claude-opus-4', runtime: 'cli-claude-code',
39
+ network_id: nid, project_dir: null,
40
+ created_at: fresh, updated_at: fresh, last_seen_at: fresh,
41
+ });
42
+ await route.fulfill({ response: r, json: { ...b, sessions: [
43
+ mk('alpha', 'working'), mk('beta', 'working'), mk('gamma', 'idle'),
44
+ ] } });
45
+ });
46
+
47
+ const now = Date.now();
48
+ const msgs = [];
49
+ // 3 distinct pairs → 3 recent-signal rows
50
+ const pairs = [['alpha', 'beta'], ['beta', 'gamma'], ['gamma', 'alpha']];
51
+ pairs.forEach(([from, to], i) => {
52
+ msgs.push({
53
+ id: `m${i}`,
54
+ from_alias: from,
55
+ to_alias: to,
56
+ content: 'hi',
57
+ network_id: 'default',
58
+ created_at: new Date(now - (20000 + i * 1000)).toISOString(),
59
+ });
60
+ });
61
+ await ctx.route('**/api/hub/messages*', (route) => route.fulfill({ json: { messages: msgs } }));
62
+ await ctx.route('**/api/hub/tasks*', (route) => route.fulfill({ json: { tasks: [] } }));
63
+
64
+ const page = await ctx.newPage();
65
+ await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
66
+ await page.waitForFunction(() => document.querySelectorAll('g[data-node]').length === 3, { timeout: 30000 });
67
+ await page.waitForSelector('[data-recent-row="alpha->beta"]', { timeout: 10000 });
68
+ await page.waitForTimeout(400);
69
+
70
+ const inspect = (key) => page.evaluate((k) => {
71
+ const row = document.querySelector(`[data-recent-row="${k}"]`);
72
+ return {
73
+ lifted: row?.getAttribute('data-recent-row-lifted'),
74
+ hovered: row?.getAttribute('data-recent-row-hovered'),
75
+ pinned: row?.getAttribute('data-recent-row-pinned'),
76
+ transform: row?.getAttribute('style')?.match(/translateY\([^)]+\)/)?.[0],
77
+ };
78
+ }, key);
79
+
80
+ // State 1: idle baseline (no hover, no pin)
81
+ const s1 = await inspect('alpha->beta');
82
+
83
+ // State 2: hover alpha->beta row
84
+ await page.locator('[data-recent-row="alpha->beta"]').hover();
85
+ await page.waitForTimeout(250);
86
+ const s2_hovered = await inspect('alpha->beta');
87
+ const s2_other = await inspect('beta->gamma');
88
+
89
+ // State 3: leave hover (mouse far away to clear all panel hovers)
90
+ await page.mouse.move(700, 350);
91
+ await page.waitForTimeout(250);
92
+ const s3 = await inspect('alpha->beta');
93
+
94
+ // State 4: click row to pin
95
+ await page.locator('[data-recent-row="alpha->beta"]').click();
96
+ await page.waitForTimeout(250);
97
+ // Move mouse away so only pin lifts the row (not hover)
98
+ await page.mouse.move(700, 350);
99
+ await page.waitForTimeout(250);
100
+ const s4 = await inspect('alpha->beta');
101
+
102
+ // State 5: Esc clears pin
103
+ await page.keyboard.press('Escape');
104
+ await page.waitForTimeout(250);
105
+ const s5 = await inspect('alpha->beta');
106
+
107
+ await browser.close();
108
+
109
+ const liftStr = 'translateY(-1px)';
110
+ const results = {
111
+ s1_idleFlat: s1.lifted === 'false' && !s1.transform,
112
+
113
+ s2_hoveredLifted: s2_hovered.hovered === 'true' && s2_hovered.lifted === 'true',
114
+ s2_hoveredTransform: s2_hovered.transform === liftStr,
115
+ s2_otherStillFlat: s2_other.lifted === 'false' && !s2_other.transform,
116
+
117
+ s3_restored: s3.lifted === 'false' && !s3.transform,
118
+
119
+ s4_pinnedLifted: s4.pinned === 'true' && s4.lifted === 'true',
120
+ s4_pinnedTransform: s4.transform === liftStr,
121
+
122
+ s5_clearedAfterEsc: s5.lifted === 'false' && !s5.transform,
123
+ };
124
+ const ok = Object.values(results).every(Boolean);
125
+ console.log(`${ok ? '✅' : '❌'} recent-row hover lift:`, JSON.stringify(results),
126
+ `\n s1=`, s1, `\n s2_hovered=`, s2_hovered, ` s2_other=`, s2_other,
127
+ `\n s3=`, s3, `\n s4=`, s4, `\n s5=`, s5);
128
+ process.exit(ok ? 0 : 1);