@sleep2agi/agent-network-dashboard 0.4.6-preview.32 → 0.4.6-preview.321

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 (487) hide show
  1. package/.next/BUILD_ID +1 -1
  2. package/.next/build-manifest.json +3 -3
  3. package/.next/diagnostics/route-bundle-stats.json +41 -41
  4. package/.next/fallback-build-manifest.json +3 -3
  5. package/.next/prerender-manifest.json +3 -3
  6. package/.next/server/app/_global-error.html +1 -1
  7. package/.next/server/app/_global-error.rsc +1 -1
  8. package/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  9. package/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  10. package/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  11. package/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  12. package/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  13. package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  14. package/.next/server/app/_not-found.html +2 -2
  15. package/.next/server/app/_not-found.rsc +12 -12
  16. package/.next/server/app/_not-found.segments/_full.segment.rsc +12 -12
  17. package/.next/server/app/_not-found.segments/_head.segment.rsc +4 -4
  18. package/.next/server/app/_not-found.segments/_index.segment.rsc +7 -7
  19. package/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +2 -2
  20. package/.next/server/app/_not-found.segments/_not-found.segment.rsc +3 -3
  21. package/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  22. package/.next/server/app/admin/page_client-reference-manifest.js +1 -1
  23. package/.next/server/app/admin.html +2 -2
  24. package/.next/server/app/admin.rsc +14 -14
  25. package/.next/server/app/admin.segments/_full.segment.rsc +14 -14
  26. package/.next/server/app/admin.segments/_head.segment.rsc +4 -4
  27. package/.next/server/app/admin.segments/_index.segment.rsc +7 -7
  28. package/.next/server/app/admin.segments/_tree.segment.rsc +2 -2
  29. package/.next/server/app/admin.segments/admin/__PAGE__.segment.rsc +4 -4
  30. package/.next/server/app/admin.segments/admin.segment.rsc +3 -3
  31. package/.next/server/app/index.html +2 -2
  32. package/.next/server/app/index.rsc +14 -14
  33. package/.next/server/app/index.segments/__PAGE__.segment.rsc +4 -4
  34. package/.next/server/app/index.segments/_full.segment.rsc +14 -14
  35. package/.next/server/app/index.segments/_head.segment.rsc +4 -4
  36. package/.next/server/app/index.segments/_index.segment.rsc +7 -7
  37. package/.next/server/app/index.segments/_tree.segment.rsc +2 -2
  38. package/.next/server/app/login/page_client-reference-manifest.js +1 -1
  39. package/.next/server/app/login.html +2 -2
  40. package/.next/server/app/login.rsc +14 -14
  41. package/.next/server/app/login.segments/_full.segment.rsc +14 -14
  42. package/.next/server/app/login.segments/_head.segment.rsc +4 -4
  43. package/.next/server/app/login.segments/_index.segment.rsc +7 -7
  44. package/.next/server/app/login.segments/_tree.segment.rsc +2 -2
  45. package/.next/server/app/login.segments/login/__PAGE__.segment.rsc +4 -4
  46. package/.next/server/app/login.segments/login.segment.rsc +3 -3
  47. package/.next/server/app/logs/page_client-reference-manifest.js +1 -1
  48. package/.next/server/app/logs.html +2 -2
  49. package/.next/server/app/logs.rsc +14 -14
  50. package/.next/server/app/logs.segments/_full.segment.rsc +14 -14
  51. package/.next/server/app/logs.segments/_head.segment.rsc +4 -4
  52. package/.next/server/app/logs.segments/_index.segment.rsc +7 -7
  53. package/.next/server/app/logs.segments/_tree.segment.rsc +2 -2
  54. package/.next/server/app/logs.segments/logs/__PAGE__.segment.rsc +4 -4
  55. package/.next/server/app/logs.segments/logs.segment.rsc +3 -3
  56. package/.next/server/app/messages/page_client-reference-manifest.js +1 -1
  57. package/.next/server/app/messages.html +2 -2
  58. package/.next/server/app/messages.rsc +14 -14
  59. package/.next/server/app/messages.segments/_full.segment.rsc +14 -14
  60. package/.next/server/app/messages.segments/_head.segment.rsc +4 -4
  61. package/.next/server/app/messages.segments/_index.segment.rsc +7 -7
  62. package/.next/server/app/messages.segments/_tree.segment.rsc +2 -2
  63. package/.next/server/app/messages.segments/messages/__PAGE__.segment.rsc +4 -4
  64. package/.next/server/app/messages.segments/messages.segment.rsc +3 -3
  65. package/.next/server/app/node/page_client-reference-manifest.js +1 -1
  66. package/.next/server/app/node.html +2 -2
  67. package/.next/server/app/node.rsc +14 -14
  68. package/.next/server/app/node.segments/_full.segment.rsc +14 -14
  69. package/.next/server/app/node.segments/_head.segment.rsc +4 -4
  70. package/.next/server/app/node.segments/_index.segment.rsc +7 -7
  71. package/.next/server/app/node.segments/_tree.segment.rsc +2 -2
  72. package/.next/server/app/node.segments/node/__PAGE__.segment.rsc +4 -4
  73. package/.next/server/app/node.segments/node.segment.rsc +3 -3
  74. package/.next/server/app/nodes/page_client-reference-manifest.js +1 -1
  75. package/.next/server/app/nodes.html +2 -2
  76. package/.next/server/app/nodes.rsc +14 -14
  77. package/.next/server/app/nodes.segments/_full.segment.rsc +14 -14
  78. package/.next/server/app/nodes.segments/_head.segment.rsc +4 -4
  79. package/.next/server/app/nodes.segments/_index.segment.rsc +7 -7
  80. package/.next/server/app/nodes.segments/_tree.segment.rsc +2 -2
  81. package/.next/server/app/nodes.segments/nodes/__PAGE__.segment.rsc +4 -4
  82. package/.next/server/app/nodes.segments/nodes.segment.rsc +3 -3
  83. package/.next/server/app/page_client-reference-manifest.js +1 -1
  84. package/.next/server/app/server-logs/page_client-reference-manifest.js +1 -1
  85. package/.next/server/app/server-logs.html +2 -2
  86. package/.next/server/app/server-logs.rsc +14 -14
  87. package/.next/server/app/server-logs.segments/_full.segment.rsc +14 -14
  88. package/.next/server/app/server-logs.segments/_head.segment.rsc +4 -4
  89. package/.next/server/app/server-logs.segments/_index.segment.rsc +7 -7
  90. package/.next/server/app/server-logs.segments/_tree.segment.rsc +2 -2
  91. package/.next/server/app/server-logs.segments/server-logs/__PAGE__.segment.rsc +4 -4
  92. package/.next/server/app/server-logs.segments/server-logs.segment.rsc +3 -3
  93. package/.next/server/app/settings/networks/page_client-reference-manifest.js +1 -1
  94. package/.next/server/app/settings/networks.html +2 -2
  95. package/.next/server/app/settings/networks.rsc +14 -14
  96. package/.next/server/app/settings/networks.segments/_full.segment.rsc +14 -14
  97. package/.next/server/app/settings/networks.segments/_head.segment.rsc +4 -4
  98. package/.next/server/app/settings/networks.segments/_index.segment.rsc +7 -7
  99. package/.next/server/app/settings/networks.segments/_tree.segment.rsc +2 -2
  100. package/.next/server/app/settings/networks.segments/settings/networks/__PAGE__.segment.rsc +4 -4
  101. package/.next/server/app/settings/networks.segments/settings/networks.segment.rsc +3 -3
  102. package/.next/server/app/settings/networks.segments/settings.segment.rsc +3 -3
  103. package/.next/server/app/settings/page_client-reference-manifest.js +1 -1
  104. package/.next/server/app/settings/tokens/page_client-reference-manifest.js +1 -1
  105. package/.next/server/app/settings/tokens.html +2 -2
  106. package/.next/server/app/settings/tokens.rsc +14 -14
  107. package/.next/server/app/settings/tokens.segments/_full.segment.rsc +14 -14
  108. package/.next/server/app/settings/tokens.segments/_head.segment.rsc +4 -4
  109. package/.next/server/app/settings/tokens.segments/_index.segment.rsc +7 -7
  110. package/.next/server/app/settings/tokens.segments/_tree.segment.rsc +2 -2
  111. package/.next/server/app/settings/tokens.segments/settings/tokens/__PAGE__.segment.rsc +4 -4
  112. package/.next/server/app/settings/tokens.segments/settings/tokens.segment.rsc +3 -3
  113. package/.next/server/app/settings/tokens.segments/settings.segment.rsc +3 -3
  114. package/.next/server/app/settings.html +2 -2
  115. package/.next/server/app/settings.rsc +14 -14
  116. package/.next/server/app/settings.segments/_full.segment.rsc +14 -14
  117. package/.next/server/app/settings.segments/_head.segment.rsc +4 -4
  118. package/.next/server/app/settings.segments/_index.segment.rsc +7 -7
  119. package/.next/server/app/settings.segments/_tree.segment.rsc +2 -2
  120. package/.next/server/app/settings.segments/settings/__PAGE__.segment.rsc +4 -4
  121. package/.next/server/app/settings.segments/settings.segment.rsc +3 -3
  122. package/.next/server/app/tasks/[id]/page_client-reference-manifest.js +1 -1
  123. package/.next/server/app/tasks/page_client-reference-manifest.js +1 -1
  124. package/.next/server/app/tasks.html +2 -2
  125. package/.next/server/app/tasks.rsc +14 -14
  126. package/.next/server/app/tasks.segments/_full.segment.rsc +14 -14
  127. package/.next/server/app/tasks.segments/_head.segment.rsc +4 -4
  128. package/.next/server/app/tasks.segments/_index.segment.rsc +7 -7
  129. package/.next/server/app/tasks.segments/_tree.segment.rsc +2 -2
  130. package/.next/server/app/tasks.segments/tasks/__PAGE__.segment.rsc +4 -4
  131. package/.next/server/app/tasks.segments/tasks.segment.rsc +3 -3
  132. package/.next/server/chunks/ssr/[root-of-the-server]__03b.f76._.js +1 -1
  133. package/.next/server/chunks/ssr/[root-of-the-server]__03b.f76._.js.map +1 -1
  134. package/.next/server/chunks/ssr/[root-of-the-server]__0fhoq8i._.js +1 -1
  135. package/.next/server/chunks/ssr/[root-of-the-server]__0fhoq8i._.js.map +1 -1
  136. package/.next/server/chunks/ssr/[root-of-the-server]__0nw~zhp._.js +1 -1
  137. package/.next/server/chunks/ssr/[root-of-the-server]__0nw~zhp._.js.map +1 -1
  138. package/.next/server/chunks/ssr/agent-network-dashboard_09kk21a._.js +4 -1
  139. package/.next/server/chunks/ssr/agent-network-dashboard_09kk21a._.js.map +1 -1
  140. package/.next/server/chunks/ssr/agent-network-dashboard_app_01jhlxz._.js +1 -1
  141. package/.next/server/chunks/ssr/agent-network-dashboard_app_01jhlxz._.js.map +1 -1
  142. package/.next/server/chunks/ssr/agent-network-dashboard_app_057q.ne._.js +1 -1
  143. package/.next/server/chunks/ssr/agent-network-dashboard_app_057q.ne._.js.map +1 -1
  144. package/.next/server/chunks/ssr/agent-network-dashboard_app_09d29my._.js +1 -1
  145. package/.next/server/chunks/ssr/agent-network-dashboard_app_09d29my._.js.map +1 -1
  146. package/.next/server/chunks/ssr/agent-network-dashboard_app_0_d45-d._.js +1 -1
  147. package/.next/server/chunks/ssr/agent-network-dashboard_app_0_d45-d._.js.map +1 -1
  148. package/.next/server/chunks/ssr/agent-network-dashboard_app_0i3759l._.js +1 -1
  149. package/.next/server/chunks/ssr/agent-network-dashboard_app_0i3759l._.js.map +1 -1
  150. package/.next/server/chunks/ssr/agent-network-dashboard_app_0xgney8._.js +1 -1
  151. package/.next/server/chunks/ssr/agent-network-dashboard_app_0xgney8._.js.map +1 -1
  152. package/.next/server/chunks/ssr/agent-network-dashboard_app_10hjgv4._.js +1 -1
  153. package/.next/server/chunks/ssr/agent-network-dashboard_app_10hjgv4._.js.map +1 -1
  154. package/.next/server/chunks/ssr/agent-network-dashboard_app_1153xeb._.js +1 -1
  155. package/.next/server/chunks/ssr/agent-network-dashboard_app_1153xeb._.js.map +1 -1
  156. package/.next/server/chunks/ssr/agent-network-dashboard_app_12l4oto._.js +1 -1
  157. package/.next/server/chunks/ssr/agent-network-dashboard_app_12l4oto._.js.map +1 -1
  158. package/.next/server/chunks/ssr/agent-network-dashboard_app_components_0mvyi-4._.js +1 -1
  159. package/.next/server/chunks/ssr/agent-network-dashboard_app_components_0mvyi-4._.js.map +1 -1
  160. package/.next/server/middleware-build-manifest.js +3 -3
  161. package/.next/server/pages/404.html +2 -2
  162. package/.next/server/pages/500.html +1 -1
  163. package/.next/server/server-reference-manifest.js +1 -1
  164. package/.next/server/server-reference-manifest.json +1 -1
  165. package/.next/static/chunks/0-mpa_947ipeq.js +1 -0
  166. package/.next/static/chunks/01lmbsd37fybu.js +1 -0
  167. package/.next/static/chunks/03o.h6kvmw4l_.js +1 -0
  168. package/.next/static/chunks/03~~oirxz7~vc.js +1 -0
  169. package/.next/static/chunks/05uk96gc~9mni.js +1 -0
  170. package/.next/static/chunks/07lsi~s-c0wvh.css +2 -0
  171. package/.next/static/chunks/08kf-.bgs10ze.js +1 -0
  172. package/.next/static/chunks/08s10wueoqydl.js +1 -0
  173. package/.next/static/chunks/0_l-j6k-ic81v.js +4 -0
  174. package/.next/static/chunks/0ggj5ummw2a84.js +7 -0
  175. package/.next/static/chunks/0glmrdj9112tc.js +7 -0
  176. package/.next/static/chunks/0rxrez_cjn.eh.js +1 -0
  177. package/.next/static/chunks/0wlu_nyra0im0.js +1 -0
  178. package/.next/static/chunks/0x8x.29hkju5a.js +1 -0
  179. package/.next/static/chunks/174re5ar~kxne.js +1 -0
  180. package/.next/trace +2 -2
  181. package/.next/trace-build +1 -1
  182. package/app/components/ChatPopover.tsx +38 -2
  183. package/app/components/CommandPalette.tsx +107 -0
  184. package/app/components/HelpOverlay.tsx +126 -0
  185. package/app/components/TopoGraph.tsx +6091 -262
  186. package/app/components/utils.ts +8 -7
  187. package/app/globals.css +110 -5
  188. package/app/lib/time.ts +36 -0
  189. package/app/lib/vendorIdentity.ts +14 -3
  190. package/package.json +2 -2
  191. package/public/sleep2agi-logo.svg +11 -0
  192. package/public/vendors/claude.svg +11 -0
  193. package/public/vendors/minimax.svg +11 -0
  194. package/public/vendors/openai.svg +12 -0
  195. package/screenshots/r293-p0/after-full.png +0 -0
  196. package/screenshots/r293-p0/after-topo.png +0 -0
  197. package/screenshots/r293-p0/baseline-full.png +0 -0
  198. package/screenshots/r293-p0/baseline-topo.png +0 -0
  199. package/screenshots/r293-p0/logo-integrated-full.png +0 -0
  200. package/screenshots/r293-p0/logo-integrated-topo.png +0 -0
  201. package/scripts/help-overlay-topo-test.mjs +44 -0
  202. package/scripts/p0-topo-screenshot.mjs +82 -0
  203. package/scripts/topo-active-filter-pill-test.mjs +101 -0
  204. package/scripts/topo-active-links-chip-hover-test.mjs +103 -0
  205. package/scripts/topo-active-links-chip-nav-test.mjs +117 -0
  206. package/scripts/topo-active-links-chip-self-hover-test.mjs +171 -0
  207. package/scripts/topo-active-links-chip-test.mjs +73 -0
  208. package/scripts/topo-active-links-empty-recede-test.mjs +125 -0
  209. package/scripts/topo-active-links-freshness-test.mjs +113 -0
  210. package/scripts/topo-active-links-tooltip-test.mjs +79 -0
  211. package/scripts/topo-active-pulse-ease-test.mjs +120 -0
  212. package/scripts/topo-auto-fit-test.mjs +73 -0
  213. package/scripts/topo-brand-logo-transition-test.mjs +93 -0
  214. package/scripts/topo-brand-watermark-test.mjs +97 -0
  215. package/scripts/topo-canvas-aria-test.mjs +108 -0
  216. package/scripts/topo-chat-target-breath-test.mjs +84 -0
  217. package/scripts/topo-chat-target-ring-ease-test.mjs +82 -0
  218. package/scripts/topo-chat-target-ring-fade-test.mjs +124 -0
  219. package/scripts/topo-chip-empty-recede-test.mjs +116 -0
  220. package/scripts/topo-chip-focus-test.mjs +95 -0
  221. package/scripts/topo-chip-pin-mirror-test.mjs +113 -0
  222. package/scripts/topo-chip-row-semantic-gap-test.mjs +97 -0
  223. package/scripts/topo-chip-row-tabular-test.mjs +111 -0
  224. package/scripts/topo-chrome-a11y-test.mjs +107 -0
  225. package/scripts/topo-chrome-focus-ring-unify-test.mjs +100 -0
  226. package/scripts/topo-chrome-icon-stroke-test.mjs +95 -0
  227. package/scripts/topo-chrome-pop-extension-test.mjs +98 -0
  228. package/scripts/topo-chrome-pop-nodesize-test.mjs +88 -0
  229. package/scripts/topo-chrome-press-state-test.mjs +135 -0
  230. package/scripts/topo-chrome-strip-semantic-gap-test.mjs +99 -0
  231. package/scripts/topo-chrome-strip-theme-ease-test.mjs +99 -0
  232. package/scripts/topo-chrome-zoom-level-pop-test.mjs +122 -0
  233. package/scripts/topo-chrome-zoom-pop-test.mjs +130 -0
  234. package/scripts/topo-click-ripple-ease-test.mjs +94 -0
  235. package/scripts/topo-cmdk-edge-clear-test.mjs +109 -0
  236. package/scripts/topo-cmdk-layout-view-test.mjs +108 -0
  237. package/scripts/topo-cmdk-pin-test.mjs +123 -0
  238. package/scripts/topo-cmdk-vendor-clear-test.mjs +133 -0
  239. package/scripts/topo-cmdk-vendor-pin-test.mjs +103 -0
  240. package/scripts/topo-corner-radius-unify-test.mjs +103 -0
  241. package/scripts/topo-cwd-tooltip-test.mjs +64 -0
  242. package/scripts/topo-dblclick-reset-test.mjs +74 -0
  243. package/scripts/topo-dense-alias-fill-transition-test.mjs +133 -0
  244. package/scripts/topo-discrete-zoom-smooth-test.mjs +125 -0
  245. package/scripts/topo-edge-badge-click-pin-test.mjs +94 -0
  246. package/scripts/topo-edge-badge-crossfade-test.mjs +138 -0
  247. package/scripts/topo-edge-badge-hot-test.mjs +115 -0
  248. package/scripts/topo-edge-badge-hover-test.mjs +85 -0
  249. package/scripts/topo-edge-badge-lift-test.mjs +150 -0
  250. package/scripts/topo-edge-badge-ripple-test.mjs +111 -0
  251. package/scripts/topo-edge-badge-stroke-transition-test.mjs +118 -0
  252. package/scripts/topo-edge-badge-text-pin-test.mjs +121 -0
  253. package/scripts/topo-edge-badge-theme-ease-test.mjs +89 -0
  254. package/scripts/topo-edge-count-badge-test.mjs +86 -0
  255. package/scripts/topo-edge-endpoint-highlight-test.mjs +111 -0
  256. package/scripts/topo-edge-fadein-test.mjs +106 -0
  257. package/scripts/topo-edge-focus-test.mjs +113 -0
  258. package/scripts/topo-edge-hover-test.mjs +93 -0
  259. package/scripts/topo-edge-pill-hot-test.mjs +129 -0
  260. package/scripts/topo-edge-pill-test.mjs +105 -0
  261. package/scripts/topo-edge-ping-pulse-retired-test.mjs +119 -0
  262. package/scripts/topo-edge-stroke-ease-test.mjs +100 -0
  263. package/scripts/topo-edge-stroke-transition-test.mjs +132 -0
  264. package/scripts/topo-edge-tooltip-test.mjs +70 -0
  265. package/scripts/topo-empty-hint-tracking-test.mjs +84 -0
  266. package/scripts/topo-empty-state-breath-test.mjs +150 -0
  267. package/scripts/topo-empty-state-crossfade-test.mjs +130 -0
  268. package/scripts/topo-empty-state-recenter-test.mjs +107 -0
  269. package/scripts/topo-empty-subhint-tracking-test.mjs +87 -0
  270. package/scripts/topo-endpoint-ring-fade-test.mjs +132 -0
  271. package/scripts/topo-endpoint-ring-test.mjs +93 -0
  272. package/scripts/topo-endpoint-ring-thicken-test.mjs +112 -0
  273. package/scripts/topo-esc-clears-pin-test.mjs +98 -0
  274. package/scripts/topo-filter-pill-aliases-test.mjs +121 -0
  275. package/scripts/topo-filter-pill-body-click-test.mjs +112 -0
  276. package/scripts/topo-filter-pill-count-test.mjs +110 -0
  277. package/scripts/topo-filter-pill-mobile-test.mjs +90 -0
  278. package/scripts/topo-fit-key-test.mjs +106 -0
  279. package/scripts/topo-freshness-chip-test.mjs +74 -0
  280. package/scripts/topo-freshness-chip-transition-test.mjs +80 -0
  281. package/scripts/topo-freshness-conditional-render-test.mjs +92 -0
  282. package/scripts/topo-fullscreen-active-test.mjs +115 -0
  283. package/scripts/topo-group-box-pinned-state-test.mjs +95 -0
  284. package/scripts/topo-group-count-test.mjs +6 -1
  285. package/scripts/topo-group-label-a11y-test.mjs +113 -0
  286. package/scripts/topo-group-label-count-inherit-test.mjs +99 -0
  287. package/scripts/topo-group-label-hover-test.mjs +119 -0
  288. package/scripts/topo-group-label-pin-spacing-test.mjs +136 -0
  289. package/scripts/topo-group-label-tint-test.mjs +99 -0
  290. package/scripts/topo-group-label-title-test.mjs +83 -0
  291. package/scripts/topo-group-pin-test.mjs +119 -0
  292. package/scripts/topo-group-pip-fadein-test.mjs +100 -0
  293. package/scripts/topo-group-pip-tabular-test.mjs +95 -0
  294. package/scripts/topo-group-status-pips-test.mjs +103 -0
  295. package/scripts/topo-groupbox-fadein-test.mjs +95 -0
  296. package/scripts/topo-groupbox-hover-lift-test.mjs +127 -0
  297. package/scripts/topo-groupbox-hubcore-ease-test.mjs +106 -0
  298. package/scripts/topo-groupbox-live-test.mjs +100 -0
  299. package/scripts/topo-groupbox-march-busyness-test.mjs +155 -0
  300. package/scripts/topo-groupbox-test.mjs +4 -2
  301. package/scripts/topo-help-overlay-r109-test.mjs +67 -0
  302. package/scripts/topo-help-overlay-r118-test.mjs +69 -0
  303. package/scripts/topo-help-overlay-r123-test.mjs +69 -0
  304. package/scripts/topo-help-overlay-r134-test.mjs +74 -0
  305. package/scripts/topo-help-overlay-r137-test.mjs +81 -0
  306. package/scripts/topo-help-overlay-r141-test.mjs +86 -0
  307. package/scripts/topo-help-overlay-r153-test.mjs +85 -0
  308. package/scripts/topo-help-overlay-r59-test.mjs +67 -0
  309. package/scripts/topo-help-overlay-r65-test.mjs +64 -0
  310. package/scripts/topo-help-overlay-r70-test.mjs +63 -0
  311. package/scripts/topo-help-overlay-r78-test.mjs +59 -0
  312. package/scripts/topo-help-overlay-r81-test.mjs +58 -0
  313. package/scripts/topo-help-overlay-r87-test.mjs +64 -0
  314. package/scripts/topo-help-overlay-r91-test.mjs +65 -0
  315. package/scripts/topo-hot-tail-crossfade-test.mjs +117 -0
  316. package/scripts/topo-html-overlay-padding-unify-test.mjs +120 -0
  317. package/scripts/topo-hub-a11y-test.mjs +112 -0
  318. package/scripts/topo-hub-busyness-test.mjs +100 -0
  319. package/scripts/topo-hub-center-crossfade-test.mjs +124 -0
  320. package/scripts/topo-hub-click-fit-test.mjs +137 -0
  321. package/scripts/topo-hub-digit-scale-test.mjs +129 -0
  322. package/scripts/topo-hub-fadein-test.mjs +88 -0
  323. package/scripts/topo-hub-hover-lift-test.mjs +101 -0
  324. package/scripts/topo-hub-hover-ring-test.mjs +82 -0
  325. package/scripts/topo-hub-pip-theme-ease-test.mjs +116 -0
  326. package/scripts/topo-hub-spoke-ease-test.mjs +120 -0
  327. package/scripts/topo-hub-title-test.mjs +93 -0
  328. package/scripts/topo-hub-working-count-test.mjs +99 -0
  329. package/scripts/topo-ingroup-edge-test.mjs +103 -0
  330. package/scripts/topo-inner-radar-ring-retired-test.mjs +89 -0
  331. package/scripts/topo-kicker-color-test.mjs +93 -0
  332. package/scripts/topo-kicker-tracking-test.mjs +101 -0
  333. package/scripts/topo-kicker-weight-test.mjs +98 -0
  334. package/scripts/topo-label-card-theme-ease-test.mjs +85 -0
  335. package/scripts/topo-label-lift-test.mjs +119 -0
  336. package/scripts/topo-lastseen-tooltip-test.mjs +59 -0
  337. package/scripts/topo-layout-hover-text-preview-test.mjs +101 -0
  338. package/scripts/topo-layout-key-test.mjs +91 -0
  339. package/scripts/topo-layout-switch-crossfade-test.mjs +126 -0
  340. package/scripts/topo-layout-toggle-border-unify-test.mjs +104 -0
  341. package/scripts/topo-layout-toggle-test.mjs +131 -0
  342. package/scripts/topo-legend-compress-test.mjs +107 -0
  343. package/scripts/topo-legend-count-empty-test.mjs +126 -0
  344. package/scripts/topo-legend-count-tabular-parity-test.mjs +90 -0
  345. package/scripts/topo-legend-count-tabular-test.mjs +87 -0
  346. package/scripts/topo-legend-count-test.mjs +88 -0
  347. package/scripts/topo-legend-count-tier-fill-test.mjs +121 -0
  348. package/scripts/topo-legend-header-symmetric-inset-test.mjs +112 -0
  349. package/scripts/topo-legend-hitbox-swatch-center-test.mjs +93 -0
  350. package/scripts/topo-legend-hover-test.mjs +113 -0
  351. package/scripts/topo-legend-offline-delimiter-test.mjs +84 -0
  352. package/scripts/topo-legend-offline-label-simplify-test.mjs +85 -0
  353. package/scripts/topo-legend-panel-header-test.mjs +83 -0
  354. package/scripts/topo-legend-pin-ring-fade-test.mjs +112 -0
  355. package/scripts/topo-legend-pin-test.mjs +128 -0
  356. package/scripts/topo-legend-row-hover-lift-test.mjs +109 -0
  357. package/scripts/topo-legend-row-pin-spacing-test.mjs +124 -0
  358. package/scripts/topo-legend-row-tint-test.mjs +95 -0
  359. package/scripts/topo-legend-row-title-test.mjs +102 -0
  360. package/scripts/topo-legend-swatch-grow-test.mjs +116 -0
  361. package/scripts/topo-legend-swatch-radius-test.mjs +78 -0
  362. package/scripts/topo-minimap-a11y-test.mjs +101 -0
  363. package/scripts/topo-minimap-dot-transition-test.mjs +113 -0
  364. package/scripts/topo-minimap-rect-stroke-test.mjs +94 -0
  365. package/scripts/topo-minimap-test.mjs +68 -0
  366. package/scripts/topo-minimap-viewport-smooth-test.mjs +124 -0
  367. package/scripts/topo-mobile-chips-test.mjs +103 -0
  368. package/scripts/topo-monogram-font-test.mjs +112 -0
  369. package/scripts/topo-monogram-stroke-test.mjs +101 -0
  370. package/scripts/topo-node-a11y-test.mjs +107 -0
  371. package/scripts/topo-node-alias-chat-pin-test.mjs +95 -0
  372. package/scripts/topo-node-hover-lift-test.mjs +85 -0
  373. package/scripts/topo-node-label-card-elevation-test.mjs +157 -0
  374. package/scripts/topo-node-label-card-stroke-test.mjs +135 -0
  375. package/scripts/topo-node-stroke-transition-test.mjs +103 -0
  376. package/scripts/topo-node-text-fill-transition-test.mjs +119 -0
  377. package/scripts/topo-node-title-peers-test.mjs +107 -0
  378. package/scripts/topo-node-title-test.mjs +101 -0
  379. package/scripts/topo-nodesize-active-hover-test.mjs +109 -0
  380. package/scripts/topo-nodesize-crossfade-test.mjs +141 -0
  381. package/scripts/topo-online-chip-nav-test.mjs +143 -0
  382. package/scripts/topo-orbit-particles-retired-test.mjs +91 -0
  383. package/scripts/topo-overlap-test.mjs +32 -5
  384. package/scripts/topo-panel-elevation-test.mjs +76 -0
  385. package/scripts/topo-panel-fadein-test.mjs +102 -0
  386. package/scripts/topo-panel-hot-tail-fade-test.mjs +132 -0
  387. package/scripts/topo-panel-hover-elevation-test.mjs +118 -0
  388. package/scripts/topo-panel-theme-ease-test.mjs +85 -0
  389. package/scripts/topo-panel-title-fill-ease-test.mjs +91 -0
  390. package/scripts/topo-panel-title-tracking-test.mjs +78 -0
  391. package/scripts/topo-particle-stagger-test.mjs +82 -0
  392. package/scripts/topo-pin-intersection-color-ease-test.mjs +111 -0
  393. package/scripts/topo-pin-intersection-empty-test.mjs +129 -0
  394. package/scripts/topo-pin-intersection-tabular-test.mjs +96 -0
  395. package/scripts/topo-pin-intersection-test.mjs +121 -0
  396. package/scripts/topo-pin-intersection-warning-crossfade-test.mjs +107 -0
  397. package/scripts/topo-pin-mirror-transition-test.mjs +101 -0
  398. package/scripts/topo-pin-persistence-test.mjs +105 -0
  399. package/scripts/topo-popover-meta-test.mjs +78 -0
  400. package/scripts/topo-prepublish-guard-test.mjs +95 -0
  401. package/scripts/topo-pressure-bar-test.mjs +69 -0
  402. package/scripts/topo-pressure-hover-test.mjs +123 -0
  403. package/scripts/topo-pressure-pin-test.mjs +119 -0
  404. package/scripts/topo-pressure-seg-self-hover-test.mjs +126 -0
  405. package/scripts/topo-pressure-seg-tooltip-test.mjs +98 -0
  406. package/scripts/topo-pressure-seg-transition-test.mjs +107 -0
  407. package/scripts/topo-pulse-dot-crossfade-test.mjs +122 -0
  408. package/scripts/topo-pulse-dot-retired-test.mjs +86 -0
  409. package/scripts/topo-recent-panel-count-freshness-test.mjs +109 -0
  410. package/scripts/topo-recent-panel-count-test.mjs +72 -0
  411. package/scripts/topo-recent-panel-footer-breath-test.mjs +142 -0
  412. package/scripts/topo-recent-panel-hot-header-test.mjs +132 -0
  413. package/scripts/topo-recent-panel-more-crossfade-test.mjs +124 -0
  414. package/scripts/topo-recent-panel-more-cyan-hover-test.mjs +151 -0
  415. package/scripts/topo-recent-panel-more-nav-test.mjs +127 -0
  416. package/scripts/topo-recent-panel-more-test.mjs +106 -0
  417. package/scripts/topo-recent-panel-readability-bump-test.mjs +151 -0
  418. package/scripts/topo-recent-row-count-fill-test.mjs +129 -0
  419. package/scripts/topo-recent-row-fadein-test.mjs +107 -0
  420. package/scripts/topo-recent-row-freshness-test.mjs +102 -0
  421. package/scripts/topo-recent-row-hot-test.mjs +110 -0
  422. package/scripts/topo-recent-row-hover-lift-test.mjs +128 -0
  423. package/scripts/topo-recent-row-hover-test.mjs +122 -0
  424. package/scripts/topo-recent-row-pin-spacing-test.mjs +137 -0
  425. package/scripts/topo-recent-row-pin-test.mjs +126 -0
  426. package/scripts/topo-recent-row-tint-test.mjs +91 -0
  427. package/scripts/topo-recent-row-title-test.mjs +112 -0
  428. package/scripts/topo-recent-row-ts-alpha-test.mjs +100 -0
  429. package/scripts/topo-recent-row-ts-test.mjs +95 -0
  430. package/scripts/topo-recent-row-typography-test.mjs +119 -0
  431. package/scripts/topo-recent-signal-empty-hint-test.mjs +73 -0
  432. package/scripts/topo-recent-signal-empty-test.mjs +63 -0
  433. package/scripts/topo-reduced-motion-test.mjs +77 -0
  434. package/scripts/topo-reset-spin-test.mjs +120 -0
  435. package/scripts/topo-runtime-badge-grow-test.mjs +114 -0
  436. package/scripts/topo-spokes-retired-test.mjs +93 -0
  437. package/scripts/topo-starfield-density-test.mjs +89 -0
  438. package/scripts/topo-status-chip-hover-test.mjs +101 -0
  439. package/scripts/topo-status-chip-tooltip-test.mjs +95 -0
  440. package/scripts/topo-statusbar-chips-self-hover-test.mjs +177 -0
  441. package/scripts/topo-svg-focus-test.mjs +112 -0
  442. package/scripts/topo-sweep-busyness-test.mjs +94 -0
  443. package/scripts/topo-tabular-nums-sweep-test.mjs +93 -0
  444. package/scripts/topo-tier-guide-dashes-test.mjs +86 -0
  445. package/scripts/topo-tier-ring-fadein-test.mjs +107 -0
  446. package/scripts/topo-tier-ring-occupancy-test.mjs +87 -0
  447. package/scripts/topo-tier-ring-test.mjs +69 -0
  448. package/scripts/topo-tier-ring-tint-test.mjs +110 -0
  449. package/scripts/topo-tier-stagger-test.mjs +89 -0
  450. package/scripts/topo-title-block-tight-leading-test.mjs +95 -0
  451. package/scripts/topo-title-tracking-test.mjs +98 -0
  452. package/scripts/topo-titleblock-gap-test.mjs +86 -0
  453. package/scripts/topo-titleblock-margin-test.mjs +83 -0
  454. package/scripts/topo-toggle-inactive-cyan-hover-test.mjs +110 -0
  455. package/scripts/topo-top-rail-theme-ease-test.mjs +89 -0
  456. package/scripts/topo-tz-ghost-test.mjs +69 -0
  457. package/scripts/topo-vendor-chip-hover-test.mjs +111 -0
  458. package/scripts/topo-vendor-chip-self-hover-test.mjs +131 -0
  459. package/scripts/topo-vendor-chip-tabular-test.mjs +92 -0
  460. package/scripts/topo-vendor-chip-threshold-test.mjs +78 -0
  461. package/scripts/topo-vendor-letter-tooltip-test.mjs +92 -0
  462. package/scripts/topo-vendor-pill-test.mjs +125 -0
  463. package/scripts/topo-vendor-pin-test.mjs +125 -0
  464. package/scripts/topo-view-smooth-test.mjs +131 -0
  465. package/scripts/topo-watermark-tracking-test.mjs +99 -0
  466. package/scripts/topo-working-chip-pin-test.mjs +154 -0
  467. package/scripts/topo-working-halo-breath-retired-test.mjs +99 -0
  468. package/scripts/topo-wrapper-flow-arrow-theme-test.mjs +97 -0
  469. package/scripts/topo-wrapper-shadow-theme-ease-test.mjs +89 -0
  470. package/.next/static/chunks/0-7iowzu4.798.js +0 -1
  471. package/.next/static/chunks/02t5jr4shh.hy.js +0 -1
  472. package/.next/static/chunks/08b1xx89c0ts9.js +0 -1
  473. package/.next/static/chunks/09nd.t_hd.y6t.css +0 -2
  474. package/.next/static/chunks/0_8snedeata9k.js +0 -1
  475. package/.next/static/chunks/0_qfg5s5uzs7..js +0 -7
  476. package/.next/static/chunks/0elalb9n_.~di.js +0 -1
  477. package/.next/static/chunks/0h_~v6f9o~_in.js +0 -1
  478. package/.next/static/chunks/0j_q__o8p6g83.js +0 -1
  479. package/.next/static/chunks/0jl6_w50zh4l5.js +0 -1
  480. package/.next/static/chunks/0pl7l_.2im.j0.js +0 -7
  481. package/.next/static/chunks/0r4q73.-1bkyl.js +0 -1
  482. package/.next/static/chunks/0r_c8eccg3z2o.js +0 -1
  483. package/.next/static/chunks/10oi7l-tycgl9.js +0 -1
  484. package/.next/static/chunks/11uk1izuv3~0t.js +0 -1
  485. /package/.next/static/{QkCLPQNNPLHlzKVvmAInn → 95X2ICTd2SB5ohx7R2QN2}/_buildManifest.js +0 -0
  486. /package/.next/static/{QkCLPQNNPLHlzKVvmAInn → 95X2ICTd2SB5ohx7R2QN2}/_clientMiddlewareManifest.js +0 -0
  487. /package/.next/static/{QkCLPQNNPLHlzKVvmAInn → 95X2ICTd2SB5ohx7R2QN2}/_ssgManifest.js +0 -0
@@ -0,0 +1,74 @@
1
+ /* Round 46 verification: live · Ns freshness chip.
2
+ * - renders in the topology header with initial "live · 0s" or "live · 1s"
3
+ * - ticks up over time (>= 2s after a 2.5s wait)
4
+ * - resets near 0 when SWR delivers a new sessions payload (we trigger
5
+ * this by mutating the mocked /api/hub/status response — SWR's 5s
6
+ * refresh re-fetches and the chip should re-zero)
7
+ * - turns amber when stale (>10s since last sync; verified by blocking
8
+ * the second poll and waiting >12s) */
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
+ const ctx = await browser.newContext({ viewport: { width: 1400, 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
+ localStorage.setItem('anet-topo-layout', 'grid');
20
+ sessionStorage.setItem('anet_v3_auth', '1');
21
+ } catch {}
22
+ });
23
+
24
+ let pollCount = 0;
25
+ const fresh = new Date(Date.now() - 60 * 1000).toISOString();
26
+ await ctx.route('**/api/hub/status*', async (route) => {
27
+ pollCount++;
28
+ const r = await route.fetch();
29
+ const b = await r.json();
30
+ const nid = (b.sessions || [])[0]?.network_id || 'default';
31
+ const sessions = [
32
+ { alias: `a${pollCount}`, status: 'idle', network_id: nid, project_dir: null,
33
+ created_at: fresh, updated_at: fresh, last_seen_at: fresh },
34
+ { alias: 'b', status: 'idle', network_id: nid, project_dir: null,
35
+ created_at: fresh, updated_at: fresh, last_seen_at: fresh },
36
+ ];
37
+ await route.fulfill({ response: r, json: { ...b, sessions } });
38
+ });
39
+ await ctx.route('**/api/hub/tasks*', (route) => route.fulfill({ json: { tasks: [] } }));
40
+ const page = await ctx.newPage();
41
+ await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
42
+ await page.waitForSelector('[data-freshness-chip]', { timeout: 30000 });
43
+
44
+ const readChip = () => page.evaluate(() => {
45
+ const el = document.querySelector('[data-freshness-chip]');
46
+ if (!el) return null;
47
+ return {
48
+ text: (el.textContent || '').trim(),
49
+ isAmber: /amber|warning/i.test(el.className) || el.className.includes('amber'),
50
+ };
51
+ });
52
+
53
+ const initial = await readChip();
54
+ await page.waitForTimeout(2500);
55
+ const afterTick = await readChip();
56
+
57
+ // SWR refreshes every 5s — wait past one cycle and confirm the chip re-zeros.
58
+ // Initial chip might be 1s, after 2.5s should be 3s. After a ~5s sync,
59
+ // should drop to 0-1s.
60
+ await page.waitForTimeout(3500);
61
+ const afterSync = await readChip();
62
+
63
+ await browser.close();
64
+ const seconds = (s) => +(s.text.match(/(\d+)s/)?.[1] ?? -1);
65
+ const results = {
66
+ initialNearZero: initial !== null && seconds(initial) <= 2,
67
+ tickedUpAfter25s: afterTick !== null && seconds(afterTick) >= 2 && seconds(afterTick) <= 4,
68
+ reZeroedAfterSync: afterSync !== null && seconds(afterSync) <= 2,
69
+ pollsHappened: pollCount >= 2,
70
+ };
71
+ const ok = Object.values(results).every(Boolean);
72
+ console.log(`${ok ? '✅' : '❌'} freshness chip:`, JSON.stringify(results),
73
+ `\n initial=${JSON.stringify(initial)}\n afterTick=${JSON.stringify(afterTick)}\n afterSync=${JSON.stringify(afterSync)} polls=${pollCount}`);
74
+ process.exit(ok ? 0 : 1);
@@ -0,0 +1,80 @@
1
+ /* Round 187 verification: FreshnessChip color transition.
2
+ *
3
+ * Pre-R187 the chip swapped between fresh (gray) and stale
4
+ * (amber) Tailwind classes — bg/text/border snapped every
5
+ * time the >10s boundary was crossed. R187 adds
6
+ * transition-colors duration-300 so the palette eases
7
+ * smoothly through the stale-onset and recovery.
8
+ *
9
+ * Test:
10
+ * 1. Mount: data-freshness-chip-stale='false' (just synced)
11
+ * 2. className includes transition-colors + duration-300
12
+ * 3. className includes gray fresh palette
13
+ * 4. computed transition string includes background-color,
14
+ * border-*, color properties
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
+
22
+ const ctx = await browser.newContext({ viewport: { width: 1500, height: 1500 } });
23
+ await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
24
+ await ctx.addInitScript(() => {
25
+ try { localStorage.setItem('anet-theme', 'cyber'); sessionStorage.setItem('anet_v3_auth', '1'); } catch {}
26
+ });
27
+
28
+ const fresh = new Date(Date.now() - 60 * 1000).toISOString();
29
+ await ctx.route('**/api/hub/status*', async (route) => {
30
+ const r = await route.fetch();
31
+ const b = await r.json();
32
+ const nid = (b.sessions || [])[0]?.network_id || 'default';
33
+ const mk = (alias) => ({
34
+ alias, status: 'working', model: 'claude-opus-4', runtime: 'cli-claude-code',
35
+ network_id: nid, project_dir: null,
36
+ created_at: fresh, updated_at: fresh, last_seen_at: fresh,
37
+ });
38
+ await route.fulfill({ response: r, json: { ...b, sessions: [mk('alpha'), mk('beta')] } });
39
+ });
40
+ await ctx.route('**/api/hub/messages*', (route) => route.fulfill({ json: { messages: [] } }));
41
+ await ctx.route('**/api/hub/tasks*', (route) => route.fulfill({ json: { tasks: [] } }));
42
+
43
+ const page = await ctx.newPage();
44
+ await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
45
+ await page.waitForFunction(() => document.querySelectorAll('g[data-node]').length === 2, { timeout: 30000 });
46
+ await page.waitForSelector('[data-freshness-chip]', { timeout: 10000 });
47
+ await page.waitForTimeout(400);
48
+
49
+ const probe = await page.evaluate(() => {
50
+ const chip = document.querySelector('[data-freshness-chip]');
51
+ if (!chip) return null;
52
+ const computed = getComputedStyle(chip);
53
+ return {
54
+ staleAttr: chip.getAttribute('data-freshness-chip-stale'),
55
+ className: chip.getAttribute('class') || '',
56
+ transition: computed.transitionProperty + ' / ' + computed.transitionDuration,
57
+ text: chip.textContent,
58
+ };
59
+ });
60
+
61
+ await browser.close();
62
+
63
+ const results = {
64
+ chip_found: probe !== null,
65
+ initial_stale_false: probe?.staleAttr === 'false',
66
+ has_transition_colors: probe?.className.includes('transition-colors'),
67
+ has_duration_300: probe?.className.includes('duration-300'),
68
+ has_fresh_palette_bg: probe?.className.includes('bg-gray-500/10'),
69
+ has_fresh_palette_text: probe?.className.includes('text-gray-400'),
70
+ has_fresh_palette_border: probe?.className.includes('border-gray-500/20'),
71
+ no_stale_palette: !probe?.className.includes('bg-amber-500/10'),
72
+ transition_covers_bg: (probe?.transition || '').includes('background-color'),
73
+ transition_covers_border: (probe?.transition || '').includes('border'),
74
+ transition_covers_color: (probe?.transition || '').match(/(^|[\s,/])color\b/),
75
+ text_shows_live: /^live ·/.test(probe?.text || ''),
76
+ };
77
+ const ok = Object.values(results).every(Boolean);
78
+ console.log(`${ok ? '✅' : '❌'} freshness chip transition:`, JSON.stringify(Object.fromEntries(Object.entries(results).map(([k,v]) => [k, !!v]))),
79
+ `\n probe:`, probe);
80
+ process.exit(ok ? 0 : 1);
@@ -0,0 +1,92 @@
1
+ /* Round 275 verification: FreshnessChip converts from always-render
2
+ * to conditional render (only when stale) — chip-row simplification
3
+ * per Vincent 5214/5215-5217 visual audit ask ("乱" cleanup for
4
+ * Twitter screenshot).
5
+ *
6
+ * Pre-R275 the chip ALWAYS rendered:
7
+ * fresh: gray + "live · {sec}s" (always-present "I'm fine" chip)
8
+ * stale: amber + "lag · {sec}s" (R272 prefix swap)
9
+ *
10
+ * Post-R275:
11
+ * fresh: chip absent (null)
12
+ * stale: amber + "lag · {sec}s" (warning indicator only)
13
+ *
14
+ * Net effect: chip-row at rest has 1 fewer chip — cleaner Twitter
15
+ * screenshot, less right-edge chrome. Stale state still alerts via
16
+ * conditional appearance (amber "lag" warning chip).
17
+ *
18
+ * R272 prefix-swap intent (live↔lag) still in code; only the lag side
19
+ * is rendered now. Fresh state implicitly relies on other liveness
20
+ * signals (recent-signal panel rows, edge animations, count updates).
21
+ *
22
+ * Test scope:
23
+ * 1. At fresh state (default page load, 0s elapsed), chip element
24
+ * is NOT present in DOM. R275 simplification verified.
25
+ * 2. R273 Layout toggle Grid inactive has hover:text-cyan-300
26
+ * (regression).
27
+ * 3. R274 legend per-row count has tabular-nums (regression).
28
+ * 4. Source code regression: FreshnessChip body still contains the
29
+ * "lag" / "live" ternary — verified by reading the bundled JS
30
+ * isn't worth the effort; trust the source diff + this fresh-
31
+ * absence test as proof R275 applied.
32
+ */
33
+ import { chromium } from 'playwright';
34
+ import { readFileSync } from 'node:fs';
35
+
36
+ const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
37
+ const browser = await chromium.launch({ headless: true });
38
+ const ctx = await browser.newContext({ viewport: { width: 1500, height: 1500 } });
39
+ await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
40
+ await ctx.addInitScript(() => {
41
+ try { localStorage.setItem('anet-theme', 'cyber'); sessionStorage.setItem('anet_v3_auth', '1'); } catch {}
42
+ });
43
+ const fresh = new Date(Date.now() - 60 * 1000).toISOString();
44
+ await ctx.route('**/api/hub/status*', async (route) => {
45
+ const r = await route.fetch();
46
+ const b = await r.json();
47
+ const nid = (b.sessions || [])[0]?.network_id || 'default';
48
+ const mk = (alias) => ({
49
+ alias, status: 'working', model: 'claude-opus-4', runtime: 'claude-code-cli',
50
+ network_id: nid, project_dir: null,
51
+ created_at: fresh, updated_at: fresh, last_seen_at: fresh,
52
+ });
53
+ await route.fulfill({ response: r, json: { ...b, sessions: [
54
+ mk('alpha'), mk('beta'), mk('gamma'), mk('delta'),
55
+ ] } });
56
+ });
57
+ await ctx.route('**/api/hub/messages*', (r) => r.fulfill({ json: { messages: [] } }));
58
+ await ctx.route('**/api/hub/tasks*', (r) => r.fulfill({ json: { tasks: [] } }));
59
+
60
+ const page = await ctx.newPage();
61
+ await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
62
+ await page.waitForFunction(() => document.querySelectorAll('g[data-node]').length === 4, { timeout: 30000 });
63
+ await page.waitForSelector('[data-topo-chrome-layout="grid"]', { timeout: 10000 });
64
+ await page.waitForSelector('[data-legend-count="working"]', { timeout: 10000 });
65
+ // Give the page time to settle so FreshnessChip mount cycle is stable.
66
+ // Note: we are NOT waiting for [data-freshness-chip] — that selector
67
+ // should NOT match in fresh state (chip absent). Use a short fixed
68
+ // wait instead.
69
+ await page.waitForTimeout(500);
70
+
71
+ const probe = await page.evaluate(() => {
72
+ const freshnessChip = document.querySelector('[data-freshness-chip]');
73
+ const grid = document.querySelector('[data-topo-chrome-layout="grid"]');
74
+ const legendCount = document.querySelector('[data-legend-count="working"]');
75
+ return {
76
+ chipPresentAtFresh: freshnessChip !== null,
77
+ gridClasses: grid ? grid.className.toString() : null,
78
+ legendCountFVN: legendCount ? window.getComputedStyle(legendCount).fontVariantNumeric : null,
79
+ };
80
+ });
81
+ await browser.close();
82
+
83
+ const results = {
84
+ chip_absent_at_fresh: probe.chipPresentAtFresh === false,
85
+ r273_grid_has_cyan_hover_text: (probe.gridClasses || '').includes('hover:text-cyan-300'),
86
+ r274_legend_count_tabular: probe.legendCountFVN != null && probe.legendCountFVN.includes('tabular-nums'),
87
+ };
88
+ const ok = Object.values(results).every(Boolean);
89
+ console.log(`${ok ? '✅' : '❌'} freshness conditional render:`, JSON.stringify(results),
90
+ '\n chip present at fresh:', probe.chipPresentAtFresh, '(expected: false)',
91
+ '\n legend count FVN:', probe.legendCountFVN);
92
+ process.exit(ok ? 0 : 1);
@@ -0,0 +1,115 @@
1
+ /* Round 178 verification: fullscreen chrome button picks up the
2
+ * active-state visual indicator R163 introduced for layout toggle.
3
+ *
4
+ * Pre-R178 the button changed icon when isFullscreen flipped but
5
+ * background + foreground stayed unchanged. R178 adds:
6
+ * active: bg-cyan-500/15 text-cyan-300 hover:bg-cyan-500/20
7
+ * inactive: hover:bg-white/5 + palette-driven inline bg/color
8
+ *
9
+ * Mirrors R163 Ring/Grid pattern.
10
+ *
11
+ * Test:
12
+ * 1. Probe inactive state (default — not in fullscreen):
13
+ * data-topo-chrome-fullscreen-active='false'
14
+ * className does NOT include 'bg-cyan-500/15'
15
+ * className includes 'hover:bg-white/5'
16
+ * inline style.background is set (from palette)
17
+ * 2. Fake fullscreen state via dispatching fullscreenchange
18
+ * with mocked document.fullscreenElement, then re-probe:
19
+ * data-topo-chrome-fullscreen-active='true'
20
+ * className includes 'bg-cyan-500/15' + 'text-cyan-300'
21
+ * className DOES NOT include 'hover:bg-white/5'
22
+ * inline style.background is unset (Tailwind wins)
23
+ */
24
+ import { chromium } from 'playwright';
25
+ import { readFileSync } from 'node:fs';
26
+
27
+ const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
28
+ const browser = await chromium.launch({ headless: true });
29
+
30
+ const ctx = await browser.newContext({ viewport: { width: 1500, height: 1500 } });
31
+ await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
32
+ await ctx.addInitScript(() => {
33
+ try { localStorage.setItem('anet-theme', 'cyber'); sessionStorage.setItem('anet_v3_auth', '1'); } catch {}
34
+ });
35
+
36
+ const fresh = new Date(Date.now() - 60 * 1000).toISOString();
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: [mk('alpha'), mk('beta'), mk('gamma')] } });
47
+ });
48
+ await ctx.route('**/api/hub/messages*', (route) => route.fulfill({ json: { messages: [] } }));
49
+ await ctx.route('**/api/hub/tasks*', (route) => route.fulfill({ json: { tasks: [] } }));
50
+
51
+ const page = await ctx.newPage();
52
+ await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
53
+ await page.waitForFunction(() => document.querySelectorAll('g[data-node]').length === 3, { timeout: 30000 });
54
+ await page.waitForSelector('[data-topo-chrome-fullscreen]', { timeout: 10000 });
55
+ await page.waitForTimeout(400);
56
+
57
+ const probe = () => page.evaluate(() => {
58
+ const btn = document.querySelector('[data-topo-chrome-fullscreen]');
59
+ if (!btn) return null;
60
+ return {
61
+ activeAttr: btn.getAttribute('data-topo-chrome-fullscreen-active'),
62
+ className: btn.getAttribute('class') || '',
63
+ inlineBg: btn.style.background || '',
64
+ inlineColor: btn.style.color || '',
65
+ ariaLabel: btn.getAttribute('aria-label'),
66
+ };
67
+ });
68
+
69
+ const inactive = await probe();
70
+
71
+ // Fake fullscreen state: define document.fullscreenElement to point at
72
+ // the container, then dispatch fullscreenchange. The listener at
73
+ // TopoGraph.tsx line ~1125 calls
74
+ // setIsFullscreen(document.fullscreenElement === containerRef.current)
75
+ // We can find the container via the chrome's parent (the chrome <div>
76
+ // sits inside the container <div ref={containerRef}>).
77
+ await page.evaluate(() => {
78
+ const chrome = document.querySelector('[data-topo-chrome]');
79
+ const container = chrome?.parentElement;
80
+ if (!container) throw new Error('container not found');
81
+ Object.defineProperty(document, 'fullscreenElement', {
82
+ configurable: true,
83
+ get: () => container,
84
+ });
85
+ document.dispatchEvent(new Event('fullscreenchange'));
86
+ });
87
+ await page.waitForTimeout(250);
88
+ const active = await probe();
89
+
90
+ await browser.close();
91
+
92
+ const results = {
93
+ // Inactive defaults
94
+ inactive_attr_false: inactive.activeAttr === 'false',
95
+ inactive_no_cyan_bg_class: !inactive.className.includes('bg-cyan-500/15'),
96
+ inactive_has_white_hover: inactive.className.includes('hover:bg-white/5'),
97
+ inactive_inline_bg_set: inactive.inlineBg !== '',
98
+ inactive_inline_color_set: inactive.inlineColor !== '',
99
+ inactive_aria_label_enter: /Enter fullscreen/.test(inactive.ariaLabel || ''),
100
+
101
+ // Active state (after faking fullscreenchange)
102
+ active_attr_true: active.activeAttr === 'true',
103
+ active_has_cyan_bg_class: active.className.includes('bg-cyan-500/15'),
104
+ active_has_cyan_text_class: active.className.includes('text-cyan-300'),
105
+ active_has_cyan_hover_class: active.className.includes('hover:bg-cyan-500/20'),
106
+ active_no_white_hover: !active.className.includes('hover:bg-white/5'),
107
+ active_inline_bg_empty: active.inlineBg === '',
108
+ active_inline_color_empty: active.inlineColor === '',
109
+ active_aria_label_exit: /Exit fullscreen/.test(active.ariaLabel || ''),
110
+ };
111
+ const ok = Object.values(results).every(Boolean);
112
+ console.log(`${ok ? '✅' : '❌'} fullscreen active state:`, JSON.stringify(results),
113
+ `\n inactive =`, inactive,
114
+ `\n active =`, active);
115
+ process.exit(ok ? 0 : 1);
@@ -0,0 +1,95 @@
1
+ /* Round 68 verification: group-box rect has a 3-tier visual ladder:
2
+ * idle → strokeWidth 1.5, dashed, ringStroke colour
3
+ * hovered → strokeWidth 2, solid, legendAccent colour
4
+ * pinned → strokeWidth 3, solid, legendAccent colour (stronger)
5
+ *
6
+ * Plus `data-group-box-pinned` reflects the pinned state so external
7
+ * tooling can spot a pinned box without inspecting computed CSS.
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: 1500 } });
16
+ await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
17
+ await ctx.addInitScript(() => {
18
+ try {
19
+ localStorage.setItem('anet-theme', 'cyber');
20
+ localStorage.setItem('anet-topo-layout', 'grid');
21
+ sessionStorage.setItem('anet_v3_auth', '1');
22
+ } catch {}
23
+ });
24
+
25
+ const fresh = new Date(Date.now() - 60 * 1000).toISOString();
26
+ await ctx.route('**/api/hub/status*', async (route) => {
27
+ const r = await route.fetch();
28
+ const b = await r.json();
29
+ const nid = (b.sessions || [])[0]?.network_id || 'default';
30
+ const sessions = [
31
+ { alias: 'alpha1', status: 'idle', network_id: nid, project_dir: null, created_at: fresh, updated_at: fresh, last_seen_at: fresh },
32
+ { alias: 'alpha2', status: 'idle', network_id: nid, project_dir: null, created_at: fresh, updated_at: fresh, last_seen_at: fresh },
33
+ { alias: 'alpha3', status: 'idle', network_id: nid, project_dir: null, created_at: fresh, updated_at: fresh, last_seen_at: fresh },
34
+ { alias: 'beta1', status: 'idle', network_id: nid, project_dir: null, created_at: fresh, updated_at: fresh, last_seen_at: fresh },
35
+ { alias: 'beta2', status: 'idle', network_id: nid, project_dir: null, created_at: fresh, updated_at: fresh, last_seen_at: fresh },
36
+ ];
37
+ await route.fulfill({ response: r, json: { ...b, sessions } });
38
+ });
39
+ await ctx.route('**/api/hub/messages*', (route) => route.fulfill({ json: { messages: [] } }));
40
+ await ctx.route('**/api/hub/tasks*', (route) => route.fulfill({ json: { tasks: [] } }));
41
+ const page = await ctx.newPage();
42
+ await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
43
+ await page.waitForFunction(() => document.querySelectorAll('g[data-node]').length === 5, { timeout: 30000 });
44
+ await page.waitForTimeout(600);
45
+
46
+ const readAlphaBox = () => page.evaluate(() => {
47
+ // Find the alpha group <g data-group="alpha"> and read its <rect>.
48
+ const g = document.querySelector('g[data-group="alpha"]');
49
+ if (!g) return null;
50
+ const rect = g.querySelector('rect');
51
+ if (!rect) return null;
52
+ return {
53
+ strokeWidth: rect.getAttribute('stroke-width'),
54
+ stroke: rect.getAttribute('stroke'),
55
+ dashArray: rect.getAttribute('stroke-dasharray'),
56
+ fillOpacity: rect.getAttribute('fill-opacity'),
57
+ pinnedAttr: rect.getAttribute('data-group-box-pinned'),
58
+ };
59
+ });
60
+
61
+ const idle = await readAlphaBox();
62
+
63
+ // Hover a member of alpha (alpha1) → group becomes hovered.
64
+ await page.locator('g[data-node="alpha1"]').hover();
65
+ await page.waitForTimeout(300);
66
+ const hovered = await readAlphaBox();
67
+ await page.mouse.move(10, 10);
68
+ await page.waitForTimeout(300);
69
+
70
+ // Pin alpha via group label click.
71
+ await page.locator('g[data-group-label-hit="alpha"]').first().click({ force: true });
72
+ await page.mouse.move(10, 10);
73
+ await page.waitForTimeout(300);
74
+ const pinned = await readAlphaBox();
75
+
76
+ await browser.close();
77
+
78
+ const results = {
79
+ idle_stroke15: idle && idle.strokeWidth === '1.5',
80
+ idle_dashed: idle && (idle.dashArray || '').startsWith('6'),
81
+ idle_pinnedFalse: idle && idle.pinnedAttr === 'false',
82
+ hovered_stroke2: hovered && hovered.strokeWidth === '2',
83
+ hovered_solid: hovered && (hovered.dashArray === 'none' || hovered.dashArray === null),
84
+ hovered_pinnedFalse: hovered && hovered.pinnedAttr === 'false',
85
+ pinned_stroke3: pinned && pinned.strokeWidth === '3',
86
+ pinned_solid: pinned && (pinned.dashArray === 'none' || pinned.dashArray === null),
87
+ pinned_pinnedTrue: pinned && pinned.pinnedAttr === 'true',
88
+ pinned_strongerFill: pinned && hovered && parseFloat(pinned.fillOpacity) > parseFloat(hovered.fillOpacity),
89
+ };
90
+ const ok = Object.values(results).every(Boolean);
91
+ console.log(`${ok ? '✅' : '❌'} group-box pinned state:`, JSON.stringify(results),
92
+ `\n idle=`, idle,
93
+ `\n hovered=`, hovered,
94
+ `\n pinned=`, pinned);
95
+ process.exit(ok ? 0 : 1);
@@ -53,8 +53,13 @@ const labels = await page.$$eval('svg[viewBox="0 0 1000 680"] g[data-group]', el
53
53
  await browser.close();
54
54
  const a = labels.find(l => l.key === 'A站');
55
55
  const b = labels.find(l => l.key === 'B站');
56
+ // R58 appended status-mix pips inside the same <text>, and SVG textContent
57
+ // concatenates tspans without preserving the visual `dx` gaps — so what
58
+ // renders as "A站 · 4 4w" surfaces as the string "A站· 44w". The R19
59
+ // count chip is still the second tspan; verify by matching "Group·" then
60
+ // the count, allowing any trailing pip text.
56
61
  const results = {
57
- bothGroupsHaveChip: a?.full === 'A站· 4' && b?.full === 'B站· 2',
62
+ bothGroupsHaveChip: /^A站·\s*4/.test(a?.full || '') && /^B站·\s*2/.test(b?.full || ''),
58
63
  chipSmallerFont: a?.chipFontSize === 11,
59
64
  chipLighterWeight: a?.chipFontWeight === '400',
60
65
  };
@@ -0,0 +1,113 @@
1
+ /* Round 152 verification: group-label hit gains onKeyDown.
2
+ *
3
+ * R63 added role="button" + tabIndex=0 + aria-pressed to the
4
+ * group label hit-area, but never wired keyboard activation —
5
+ * focused users could Tab to the label but Enter / Space did
6
+ * nothing. R152 wires onKeyDown to fire the same setPinnedGroup
7
+ * setter onClick uses.
8
+ *
9
+ * This is the last keyboard gap among the role="button" surfaces;
10
+ * pressure-bar segs (R60), legend rows (R61), recent rows (R116),
11
+ * edge count badges (R121), chip-row chips (R136 / R139 / R140),
12
+ * vendor letters (R88), and nodes (R151) all had it. Group labels
13
+ * were the last hold-out.
14
+ *
15
+ * Fleet: 3 working sessions in grid layout to force group boxes
16
+ * (R85). Two prefix groups: agents-* (2) and infra-* (1).
17
+ *
18
+ * Path:
19
+ * 1. Focus agents group label → aria-pressed=false initially
20
+ * 2. Press Enter → aria-pressed=true (pinned)
21
+ * 3. Press Enter again → aria-pressed=false (released)
22
+ * 4. Press Space → aria-pressed=true (pinned)
23
+ * 5. Esc clears → aria-pressed=false
24
+ */
25
+ import { chromium } from 'playwright';
26
+ import { readFileSync } from 'node:fs';
27
+
28
+ const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
29
+ const browser = await chromium.launch({ headless: true });
30
+
31
+ const ctx = await browser.newContext({ viewport: { width: 1600, height: 1500 } });
32
+ await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
33
+ await ctx.addInitScript(() => {
34
+ try {
35
+ localStorage.setItem('anet-theme', 'cyber');
36
+ sessionStorage.setItem('anet_v3_auth', '1');
37
+ // group boxes only render in grid layout
38
+ localStorage.setItem('anet-topo-layout', 'grid');
39
+ } catch {}
40
+ });
41
+
42
+ const fresh = new Date(Date.now() - 60 * 1000).toISOString();
43
+ await ctx.route('**/api/hub/status*', async (route) => {
44
+ const r = await route.fetch();
45
+ const b = await r.json();
46
+ const nid = (b.sessions || [])[0]?.network_id || 'default';
47
+ const mk = (alias, status) => ({
48
+ alias, status, model: 'claude-opus-4', runtime: 'cli-claude-code',
49
+ network_id: nid, project_dir: null,
50
+ created_at: fresh, updated_at: fresh, last_seen_at: fresh,
51
+ });
52
+ await route.fulfill({ response: r, json: { ...b, sessions: [
53
+ mk('agents-a1', 'working'), mk('agents-a2', 'working'),
54
+ mk('infra-b1', 'working'),
55
+ ] } });
56
+ });
57
+ await ctx.route('**/api/hub/messages*', (route) => route.fulfill({ json: { messages: [] } }));
58
+ await ctx.route('**/api/hub/tasks*', (route) => route.fulfill({ json: { tasks: [] } }));
59
+
60
+ const page = await ctx.newPage();
61
+ await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
62
+ await page.waitForFunction(() => document.querySelectorAll('g[data-node]').length === 3, { timeout: 30000 });
63
+ await page.waitForSelector('[data-group-label-hit]', { timeout: 10000 });
64
+ await page.waitForTimeout(400);
65
+
66
+ // Find the actual group keys (cluster prefix may differ)
67
+ const groupKeys = await page.evaluate(() =>
68
+ [...document.querySelectorAll('[data-group-label-hit]')].map(g => g.getAttribute('data-group-label-hit')));
69
+ const agentsKey = groupKeys.find(k => k.startsWith('agents')) || groupKeys[0];
70
+
71
+ const readAriaPressed = () => page.evaluate((k) => {
72
+ const g = document.querySelector(`[data-group-label-hit="${k}"]`);
73
+ return g?.getAttribute('aria-pressed');
74
+ }, agentsKey);
75
+
76
+ const before = await readAriaPressed();
77
+
78
+ // Focus the label and press Enter
79
+ await page.locator(`[data-group-label-hit="${agentsKey}"]`).focus();
80
+ await page.keyboard.press('Enter');
81
+ await page.waitForTimeout(200);
82
+ const afterEnter = await readAriaPressed();
83
+
84
+ // Press Enter again → toggle off
85
+ await page.keyboard.press('Enter');
86
+ await page.waitForTimeout(200);
87
+ const afterReEnter = await readAriaPressed();
88
+
89
+ // Press Space → pin again
90
+ await page.locator(`[data-group-label-hit="${agentsKey}"]`).focus();
91
+ await page.keyboard.press(' ');
92
+ await page.waitForTimeout(200);
93
+ const afterSpace = await readAriaPressed();
94
+
95
+ // Esc clears
96
+ await page.keyboard.press('Escape');
97
+ await page.waitForTimeout(200);
98
+ const afterEsc = await readAriaPressed();
99
+
100
+ await browser.close();
101
+
102
+ const results = {
103
+ before_notPinned: before === 'false',
104
+ enter_pins: afterEnter === 'true',
105
+ reEnter_releases: afterReEnter === 'false',
106
+ space_pins: afterSpace === 'true',
107
+ esc_clears: afterEsc === 'false',
108
+ };
109
+ const ok = Object.values(results).every(Boolean);
110
+ console.log(`${ok ? '✅' : '❌'} group label a11y:`, JSON.stringify(results),
111
+ `\n groupKey=${agentsKey}`,
112
+ `\n before=${before} enter=${afterEnter} reEnter=${afterReEnter} space=${afterSpace} esc=${afterEsc}`);
113
+ process.exit(ok ? 0 : 1);