@sleep2agi/agent-network-dashboard 0.4.6-preview.33 → 0.4.6-preview.331

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 (496) 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/0ggj5ummw2a84.js +7 -0
  173. package/.next/static/chunks/0glmrdj9112tc.js +7 -0
  174. package/.next/static/chunks/0mpa-fgyi2k78.js +1 -0
  175. package/.next/static/chunks/0nlhul7k4hwil.js +1 -0
  176. package/.next/static/chunks/0rxrez_cjn.eh.js +1 -0
  177. package/.next/static/chunks/0x8x.29hkju5a.js +1 -0
  178. package/.next/static/chunks/174re5ar~kxne.js +1 -0
  179. package/.next/static/chunks/1851sbdemt00t.js +4 -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 +111 -1
  185. package/app/components/TopoGraph.tsx +6197 -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/screenshots/r293-p0/v0.10.0-hero3-rfc.md +230 -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 +94 -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-chiprow-data-weight-test.mjs +94 -0
  225. package/scripts/topo-chrome-a11y-test.mjs +107 -0
  226. package/scripts/topo-chrome-focus-ring-unify-test.mjs +100 -0
  227. package/scripts/topo-chrome-icon-stroke-test.mjs +95 -0
  228. package/scripts/topo-chrome-inactive-color-test.mjs +90 -0
  229. package/scripts/topo-chrome-pop-extension-test.mjs +98 -0
  230. package/scripts/topo-chrome-pop-nodesize-test.mjs +88 -0
  231. package/scripts/topo-chrome-press-state-test.mjs +135 -0
  232. package/scripts/topo-chrome-strip-semantic-gap-test.mjs +99 -0
  233. package/scripts/topo-chrome-strip-theme-ease-test.mjs +99 -0
  234. package/scripts/topo-chrome-zoom-level-pop-test.mjs +122 -0
  235. package/scripts/topo-chrome-zoom-pop-test.mjs +130 -0
  236. package/scripts/topo-chrome-zoom-readout-weight-test.mjs +81 -0
  237. package/scripts/topo-click-ripple-ease-test.mjs +94 -0
  238. package/scripts/topo-cmdk-edge-clear-test.mjs +109 -0
  239. package/scripts/topo-cmdk-layout-view-test.mjs +108 -0
  240. package/scripts/topo-cmdk-pin-test.mjs +123 -0
  241. package/scripts/topo-cmdk-vendor-clear-test.mjs +133 -0
  242. package/scripts/topo-cmdk-vendor-pin-test.mjs +103 -0
  243. package/scripts/topo-corner-radius-unify-test.mjs +103 -0
  244. package/scripts/topo-cwd-tooltip-test.mjs +64 -0
  245. package/scripts/topo-dblclick-reset-test.mjs +74 -0
  246. package/scripts/topo-dense-alias-fill-transition-test.mjs +133 -0
  247. package/scripts/topo-discrete-zoom-smooth-test.mjs +125 -0
  248. package/scripts/topo-edge-badge-click-pin-test.mjs +94 -0
  249. package/scripts/topo-edge-badge-crossfade-test.mjs +138 -0
  250. package/scripts/topo-edge-badge-hot-test.mjs +115 -0
  251. package/scripts/topo-edge-badge-hover-test.mjs +85 -0
  252. package/scripts/topo-edge-badge-lift-test.mjs +150 -0
  253. package/scripts/topo-edge-badge-ripple-test.mjs +111 -0
  254. package/scripts/topo-edge-badge-stroke-transition-test.mjs +118 -0
  255. package/scripts/topo-edge-badge-text-pin-test.mjs +121 -0
  256. package/scripts/topo-edge-badge-theme-ease-test.mjs +89 -0
  257. package/scripts/topo-edge-count-badge-test.mjs +86 -0
  258. package/scripts/topo-edge-endpoint-highlight-test.mjs +111 -0
  259. package/scripts/topo-edge-fadein-test.mjs +106 -0
  260. package/scripts/topo-edge-focus-test.mjs +113 -0
  261. package/scripts/topo-edge-hover-test.mjs +93 -0
  262. package/scripts/topo-edge-pill-hot-test.mjs +129 -0
  263. package/scripts/topo-edge-pill-test.mjs +105 -0
  264. package/scripts/topo-edge-ping-pulse-retired-test.mjs +119 -0
  265. package/scripts/topo-edge-stroke-ease-test.mjs +100 -0
  266. package/scripts/topo-edge-stroke-transition-test.mjs +132 -0
  267. package/scripts/topo-edge-tooltip-test.mjs +70 -0
  268. package/scripts/topo-empty-hint-tracking-test.mjs +84 -0
  269. package/scripts/topo-empty-state-breath-test.mjs +150 -0
  270. package/scripts/topo-empty-state-crossfade-test.mjs +130 -0
  271. package/scripts/topo-empty-state-recenter-test.mjs +107 -0
  272. package/scripts/topo-empty-subhint-tracking-test.mjs +87 -0
  273. package/scripts/topo-endpoint-ring-fade-test.mjs +132 -0
  274. package/scripts/topo-endpoint-ring-test.mjs +93 -0
  275. package/scripts/topo-endpoint-ring-thicken-test.mjs +112 -0
  276. package/scripts/topo-esc-clears-pin-test.mjs +98 -0
  277. package/scripts/topo-filter-pill-aliases-test.mjs +121 -0
  278. package/scripts/topo-filter-pill-body-click-test.mjs +112 -0
  279. package/scripts/topo-filter-pill-count-test.mjs +110 -0
  280. package/scripts/topo-filter-pill-mobile-test.mjs +90 -0
  281. package/scripts/topo-fit-key-test.mjs +106 -0
  282. package/scripts/topo-freshness-chip-test.mjs +74 -0
  283. package/scripts/topo-freshness-chip-transition-test.mjs +80 -0
  284. package/scripts/topo-freshness-chip-weight-test.mjs +90 -0
  285. package/scripts/topo-freshness-conditional-render-test.mjs +92 -0
  286. package/scripts/topo-fullscreen-active-test.mjs +115 -0
  287. package/scripts/topo-group-box-pinned-state-test.mjs +95 -0
  288. package/scripts/topo-group-count-test.mjs +6 -1
  289. package/scripts/topo-group-label-a11y-test.mjs +113 -0
  290. package/scripts/topo-group-label-count-inherit-test.mjs +99 -0
  291. package/scripts/topo-group-label-hover-test.mjs +119 -0
  292. package/scripts/topo-group-label-pin-spacing-test.mjs +136 -0
  293. package/scripts/topo-group-label-tint-test.mjs +99 -0
  294. package/scripts/topo-group-label-title-test.mjs +83 -0
  295. package/scripts/topo-group-pin-test.mjs +119 -0
  296. package/scripts/topo-group-pip-fadein-test.mjs +100 -0
  297. package/scripts/topo-group-pip-tabular-test.mjs +95 -0
  298. package/scripts/topo-group-status-pips-test.mjs +103 -0
  299. package/scripts/topo-groupbox-fadein-test.mjs +95 -0
  300. package/scripts/topo-groupbox-hover-lift-test.mjs +127 -0
  301. package/scripts/topo-groupbox-hubcore-ease-test.mjs +106 -0
  302. package/scripts/topo-groupbox-live-test.mjs +100 -0
  303. package/scripts/topo-groupbox-march-busyness-test.mjs +155 -0
  304. package/scripts/topo-groupbox-test.mjs +4 -2
  305. package/scripts/topo-help-overlay-r109-test.mjs +67 -0
  306. package/scripts/topo-help-overlay-r118-test.mjs +69 -0
  307. package/scripts/topo-help-overlay-r123-test.mjs +69 -0
  308. package/scripts/topo-help-overlay-r134-test.mjs +74 -0
  309. package/scripts/topo-help-overlay-r137-test.mjs +81 -0
  310. package/scripts/topo-help-overlay-r141-test.mjs +86 -0
  311. package/scripts/topo-help-overlay-r153-test.mjs +85 -0
  312. package/scripts/topo-help-overlay-r59-test.mjs +67 -0
  313. package/scripts/topo-help-overlay-r65-test.mjs +64 -0
  314. package/scripts/topo-help-overlay-r70-test.mjs +63 -0
  315. package/scripts/topo-help-overlay-r78-test.mjs +59 -0
  316. package/scripts/topo-help-overlay-r81-test.mjs +58 -0
  317. package/scripts/topo-help-overlay-r87-test.mjs +64 -0
  318. package/scripts/topo-help-overlay-r91-test.mjs +65 -0
  319. package/scripts/topo-hot-tail-crossfade-test.mjs +117 -0
  320. package/scripts/topo-html-overlay-padding-unify-test.mjs +120 -0
  321. package/scripts/topo-hub-a11y-test.mjs +112 -0
  322. package/scripts/topo-hub-busyness-test.mjs +100 -0
  323. package/scripts/topo-hub-center-crossfade-test.mjs +124 -0
  324. package/scripts/topo-hub-click-fit-test.mjs +137 -0
  325. package/scripts/topo-hub-digit-scale-test.mjs +129 -0
  326. package/scripts/topo-hub-fadein-test.mjs +88 -0
  327. package/scripts/topo-hub-hover-lift-test.mjs +101 -0
  328. package/scripts/topo-hub-hover-ring-test.mjs +82 -0
  329. package/scripts/topo-hub-pip-theme-ease-test.mjs +116 -0
  330. package/scripts/topo-hub-spoke-ease-test.mjs +120 -0
  331. package/scripts/topo-hub-title-test.mjs +93 -0
  332. package/scripts/topo-hub-working-count-test.mjs +99 -0
  333. package/scripts/topo-ingroup-edge-test.mjs +103 -0
  334. package/scripts/topo-inner-radar-ring-retired-test.mjs +89 -0
  335. package/scripts/topo-kicker-color-test.mjs +93 -0
  336. package/scripts/topo-kicker-tracking-test.mjs +101 -0
  337. package/scripts/topo-kicker-weight-test.mjs +98 -0
  338. package/scripts/topo-label-card-theme-ease-test.mjs +85 -0
  339. package/scripts/topo-label-lift-test.mjs +119 -0
  340. package/scripts/topo-lastseen-tooltip-test.mjs +59 -0
  341. package/scripts/topo-layout-hover-text-preview-test.mjs +101 -0
  342. package/scripts/topo-layout-key-test.mjs +91 -0
  343. package/scripts/topo-layout-switch-crossfade-test.mjs +126 -0
  344. package/scripts/topo-layout-toggle-border-unify-test.mjs +104 -0
  345. package/scripts/topo-layout-toggle-test.mjs +131 -0
  346. package/scripts/topo-legend-compress-test.mjs +107 -0
  347. package/scripts/topo-legend-count-empty-test.mjs +126 -0
  348. package/scripts/topo-legend-count-tabular-parity-test.mjs +90 -0
  349. package/scripts/topo-legend-count-tabular-test.mjs +87 -0
  350. package/scripts/topo-legend-count-test.mjs +88 -0
  351. package/scripts/topo-legend-count-tier-fill-test.mjs +121 -0
  352. package/scripts/topo-legend-count-weight-test.mjs +86 -0
  353. package/scripts/topo-legend-header-symmetric-inset-test.mjs +112 -0
  354. package/scripts/topo-legend-hitbox-swatch-center-test.mjs +93 -0
  355. package/scripts/topo-legend-hover-test.mjs +113 -0
  356. package/scripts/topo-legend-offline-delimiter-test.mjs +84 -0
  357. package/scripts/topo-legend-offline-label-simplify-test.mjs +86 -0
  358. package/scripts/topo-legend-panel-count-weight-test.mjs +89 -0
  359. package/scripts/topo-legend-panel-header-test.mjs +83 -0
  360. package/scripts/topo-legend-pin-ring-fade-test.mjs +112 -0
  361. package/scripts/topo-legend-pin-test.mjs +128 -0
  362. package/scripts/topo-legend-row-hover-lift-test.mjs +109 -0
  363. package/scripts/topo-legend-row-labels-simplify-test.mjs +80 -0
  364. package/scripts/topo-legend-row-pin-spacing-test.mjs +124 -0
  365. package/scripts/topo-legend-row-tint-test.mjs +95 -0
  366. package/scripts/topo-legend-row-title-test.mjs +102 -0
  367. package/scripts/topo-legend-swatch-grow-test.mjs +116 -0
  368. package/scripts/topo-legend-swatch-radius-test.mjs +78 -0
  369. package/scripts/topo-minimap-a11y-test.mjs +101 -0
  370. package/scripts/topo-minimap-dot-transition-test.mjs +113 -0
  371. package/scripts/topo-minimap-rect-stroke-test.mjs +94 -0
  372. package/scripts/topo-minimap-test.mjs +68 -0
  373. package/scripts/topo-minimap-viewport-smooth-test.mjs +124 -0
  374. package/scripts/topo-mobile-chips-test.mjs +103 -0
  375. package/scripts/topo-monogram-font-test.mjs +112 -0
  376. package/scripts/topo-monogram-stroke-test.mjs +101 -0
  377. package/scripts/topo-node-a11y-test.mjs +107 -0
  378. package/scripts/topo-node-alias-chat-pin-test.mjs +95 -0
  379. package/scripts/topo-node-hover-lift-test.mjs +85 -0
  380. package/scripts/topo-node-label-card-elevation-test.mjs +157 -0
  381. package/scripts/topo-node-label-card-stroke-test.mjs +135 -0
  382. package/scripts/topo-node-stroke-transition-test.mjs +103 -0
  383. package/scripts/topo-node-text-fill-transition-test.mjs +119 -0
  384. package/scripts/topo-node-title-peers-test.mjs +107 -0
  385. package/scripts/topo-node-title-test.mjs +101 -0
  386. package/scripts/topo-nodesize-active-hover-test.mjs +109 -0
  387. package/scripts/topo-nodesize-crossfade-test.mjs +141 -0
  388. package/scripts/topo-online-chip-nav-test.mjs +143 -0
  389. package/scripts/topo-orbit-particles-retired-test.mjs +91 -0
  390. package/scripts/topo-overlap-test.mjs +32 -5
  391. package/scripts/topo-panel-elevation-test.mjs +76 -0
  392. package/scripts/topo-panel-fadein-test.mjs +102 -0
  393. package/scripts/topo-panel-hot-tail-fade-test.mjs +132 -0
  394. package/scripts/topo-panel-hover-elevation-test.mjs +118 -0
  395. package/scripts/topo-panel-theme-ease-test.mjs +85 -0
  396. package/scripts/topo-panel-title-fill-ease-test.mjs +91 -0
  397. package/scripts/topo-panel-title-tracking-test.mjs +78 -0
  398. package/scripts/topo-particle-stagger-test.mjs +82 -0
  399. package/scripts/topo-pin-intersection-color-ease-test.mjs +111 -0
  400. package/scripts/topo-pin-intersection-empty-test.mjs +129 -0
  401. package/scripts/topo-pin-intersection-tabular-test.mjs +96 -0
  402. package/scripts/topo-pin-intersection-test.mjs +121 -0
  403. package/scripts/topo-pin-intersection-warning-crossfade-test.mjs +107 -0
  404. package/scripts/topo-pin-mirror-transition-test.mjs +101 -0
  405. package/scripts/topo-pin-persistence-test.mjs +105 -0
  406. package/scripts/topo-popover-meta-test.mjs +78 -0
  407. package/scripts/topo-prepublish-guard-test.mjs +95 -0
  408. package/scripts/topo-pressure-bar-test.mjs +69 -0
  409. package/scripts/topo-pressure-hover-test.mjs +123 -0
  410. package/scripts/topo-pressure-pin-test.mjs +119 -0
  411. package/scripts/topo-pressure-seg-self-hover-test.mjs +126 -0
  412. package/scripts/topo-pressure-seg-tooltip-test.mjs +98 -0
  413. package/scripts/topo-pressure-seg-transition-test.mjs +107 -0
  414. package/scripts/topo-pulse-dot-crossfade-test.mjs +122 -0
  415. package/scripts/topo-pulse-dot-retired-test.mjs +86 -0
  416. package/scripts/topo-recent-panel-count-freshness-test.mjs +109 -0
  417. package/scripts/topo-recent-panel-count-test.mjs +72 -0
  418. package/scripts/topo-recent-panel-count-weight-test.mjs +91 -0
  419. package/scripts/topo-recent-panel-footer-breath-test.mjs +142 -0
  420. package/scripts/topo-recent-panel-hot-header-test.mjs +132 -0
  421. package/scripts/topo-recent-panel-more-crossfade-test.mjs +124 -0
  422. package/scripts/topo-recent-panel-more-cyan-hover-test.mjs +151 -0
  423. package/scripts/topo-recent-panel-more-nav-test.mjs +127 -0
  424. package/scripts/topo-recent-panel-more-test.mjs +106 -0
  425. package/scripts/topo-recent-panel-readability-bump-test.mjs +151 -0
  426. package/scripts/topo-recent-row-count-fill-test.mjs +129 -0
  427. package/scripts/topo-recent-row-fadein-test.mjs +107 -0
  428. package/scripts/topo-recent-row-freshness-test.mjs +102 -0
  429. package/scripts/topo-recent-row-hot-test.mjs +110 -0
  430. package/scripts/topo-recent-row-hover-lift-test.mjs +128 -0
  431. package/scripts/topo-recent-row-hover-test.mjs +122 -0
  432. package/scripts/topo-recent-row-pin-spacing-test.mjs +137 -0
  433. package/scripts/topo-recent-row-pin-test.mjs +126 -0
  434. package/scripts/topo-recent-row-tint-test.mjs +91 -0
  435. package/scripts/topo-recent-row-title-test.mjs +112 -0
  436. package/scripts/topo-recent-row-ts-alpha-test.mjs +100 -0
  437. package/scripts/topo-recent-row-ts-test.mjs +95 -0
  438. package/scripts/topo-recent-row-typography-test.mjs +119 -0
  439. package/scripts/topo-recent-signal-empty-hint-test.mjs +73 -0
  440. package/scripts/topo-recent-signal-empty-test.mjs +63 -0
  441. package/scripts/topo-reduced-motion-test.mjs +77 -0
  442. package/scripts/topo-reset-spin-test.mjs +120 -0
  443. package/scripts/topo-runtime-badge-grow-test.mjs +114 -0
  444. package/scripts/topo-spokes-retired-test.mjs +93 -0
  445. package/scripts/topo-starfield-density-test.mjs +89 -0
  446. package/scripts/topo-status-chip-hover-test.mjs +101 -0
  447. package/scripts/topo-status-chip-tooltip-test.mjs +95 -0
  448. package/scripts/topo-statusbar-chips-self-hover-test.mjs +177 -0
  449. package/scripts/topo-svg-focus-test.mjs +112 -0
  450. package/scripts/topo-sweep-busyness-test.mjs +94 -0
  451. package/scripts/topo-tabular-nums-sweep-test.mjs +93 -0
  452. package/scripts/topo-tier-guide-dashes-test.mjs +86 -0
  453. package/scripts/topo-tier-ring-fadein-test.mjs +107 -0
  454. package/scripts/topo-tier-ring-occupancy-test.mjs +87 -0
  455. package/scripts/topo-tier-ring-test.mjs +69 -0
  456. package/scripts/topo-tier-ring-tint-test.mjs +110 -0
  457. package/scripts/topo-tier-stagger-test.mjs +89 -0
  458. package/scripts/topo-title-block-tight-leading-test.mjs +95 -0
  459. package/scripts/topo-title-tracking-test.mjs +98 -0
  460. package/scripts/topo-titleblock-gap-test.mjs +86 -0
  461. package/scripts/topo-titleblock-margin-test.mjs +83 -0
  462. package/scripts/topo-toggle-inactive-cyan-hover-test.mjs +110 -0
  463. package/scripts/topo-top-rail-theme-ease-test.mjs +89 -0
  464. package/scripts/topo-tz-ghost-test.mjs +69 -0
  465. package/scripts/topo-vendor-chip-hover-test.mjs +111 -0
  466. package/scripts/topo-vendor-chip-self-hover-test.mjs +131 -0
  467. package/scripts/topo-vendor-chip-tabular-test.mjs +92 -0
  468. package/scripts/topo-vendor-chip-threshold-test.mjs +78 -0
  469. package/scripts/topo-vendor-chip-weight-test.mjs +87 -0
  470. package/scripts/topo-vendor-letter-tooltip-test.mjs +92 -0
  471. package/scripts/topo-vendor-pill-test.mjs +125 -0
  472. package/scripts/topo-vendor-pin-test.mjs +125 -0
  473. package/scripts/topo-view-smooth-test.mjs +131 -0
  474. package/scripts/topo-watermark-tracking-test.mjs +99 -0
  475. package/scripts/topo-working-chip-pin-test.mjs +154 -0
  476. package/scripts/topo-working-halo-breath-retired-test.mjs +99 -0
  477. package/scripts/topo-wrapper-flow-arrow-theme-test.mjs +97 -0
  478. package/scripts/topo-wrapper-shadow-theme-ease-test.mjs +89 -0
  479. package/.next/static/chunks/0-7iowzu4.798.js +0 -1
  480. package/.next/static/chunks/02t5jr4shh.hy.js +0 -1
  481. package/.next/static/chunks/09nd.t_hd.y6t.css +0 -2
  482. package/.next/static/chunks/0_8snedeata9k.js +0 -1
  483. package/.next/static/chunks/0_qfg5s5uzs7..js +0 -7
  484. package/.next/static/chunks/0elalb9n_.~di.js +0 -1
  485. package/.next/static/chunks/0j_q__o8p6g83.js +0 -1
  486. package/.next/static/chunks/0jl6_w50zh4l5.js +0 -1
  487. package/.next/static/chunks/0kwf..oq7.27x.js +0 -7
  488. package/.next/static/chunks/0r4q73.-1bkyl.js +0 -1
  489. package/.next/static/chunks/0r_c8eccg3z2o.js +0 -1
  490. package/.next/static/chunks/0sjqjenh7~k-j.js +0 -1
  491. package/.next/static/chunks/0y8v4grez.a76.js +0 -1
  492. package/.next/static/chunks/10oi7l-tycgl9.js +0 -1
  493. package/.next/static/chunks/11uk1izuv3~0t.js +0 -1
  494. /package/.next/static/{Q3_3F7glo-M3CFrXA8POE → 3PMYuA9TBRow9F7QeNZc7}/_buildManifest.js +0 -0
  495. /package/.next/static/{Q3_3F7glo-M3CFrXA8POE → 3PMYuA9TBRow9F7QeNZc7}/_clientMiddlewareManifest.js +0 -0
  496. /package/.next/static/{Q3_3F7glo-M3CFrXA8POE → 3PMYuA9TBRow9F7QeNZc7}/_ssgManifest.js +0 -0
@@ -0,0 +1,107 @@
1
+ /* Round 147 verification: node tooltip extends R98's flow summary
2
+ * with the actual sender / receiver alias breakdown. The R97 idiom
3
+ * — anywhere the UI shows "N" should hover-explain WHICH N — was
4
+ * applied to filter pills, group labels, vendor letters, pressure
5
+ * segments, recent-row, active-links chip. The node title was the
6
+ * last surface showing only aggregate counts ("12 in / 5 out");
7
+ * R147 adds peer lines.
8
+ *
9
+ * Fleet:
10
+ * alpha — sends 3 msgs to beta, 5 to gamma, 2 to delta
11
+ * beta — sends 4 msgs to alpha, 1 to gamma
12
+ * gamma — quiet (receiver only)
13
+ * delta — quiet (receiver only)
14
+ *
15
+ * For alpha:
16
+ * flowOut = 3 + 5 + 2 = 10
17
+ * flowIn = 4 (from beta)
18
+ * senders ← beta (4)
19
+ * receivers → beta (3), gamma (5), delta (2) — sorted by count desc:
20
+ * gamma (5), beta (3), delta (2)
21
+ *
22
+ * Title should contain:
23
+ * "flows: 4 in / 10 out"
24
+ * "← from: beta (4)"
25
+ * "→ to: gamma (5), beta (3), delta (2)" (sorted desc by count)
26
+ *
27
+ * Also verify a node with no flows (gamma will have 5 inbound from alpha
28
+ * and 1 from beta; let's pick delta which only has 2 inbound from alpha).
29
+ */
30
+ import { chromium } from 'playwright';
31
+ import { readFileSync } from 'node:fs';
32
+
33
+ const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
34
+ const browser = await chromium.launch({ headless: true });
35
+
36
+ const ctx = await browser.newContext({ viewport: { width: 1400, height: 1500 } });
37
+ await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
38
+ await ctx.addInitScript(() => {
39
+ try { localStorage.setItem('anet-theme', 'cyber'); sessionStorage.setItem('anet_v3_auth', '1'); } 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('alpha', 'working'), mk('beta', 'working'),
54
+ mk('gamma', 'idle'), mk('delta', 'idle'),
55
+ ] } });
56
+ });
57
+
58
+ const now = Date.now();
59
+ const mkMsg = (id, from, to, ageMs) => ({
60
+ id, from_alias: from, to_alias: to, content: 'hi',
61
+ network_id: 'default', created_at: new Date(now - ageMs).toISOString(),
62
+ });
63
+ const msgs = [];
64
+ let id = 0;
65
+ // alpha → beta (3), gamma (5), delta (2)
66
+ for (let i = 0; i < 3; i++) msgs.push(mkMsg(`m${id++}`, 'alpha', 'beta', 10000 + id * 100));
67
+ for (let i = 0; i < 5; i++) msgs.push(mkMsg(`m${id++}`, 'alpha', 'gamma', 10000 + id * 100));
68
+ for (let i = 0; i < 2; i++) msgs.push(mkMsg(`m${id++}`, 'alpha', 'delta', 10000 + id * 100));
69
+ // beta → alpha (4), gamma (1)
70
+ for (let i = 0; i < 4; i++) msgs.push(mkMsg(`m${id++}`, 'beta', 'alpha', 10000 + id * 100));
71
+ for (let i = 0; i < 1; i++) msgs.push(mkMsg(`m${id++}`, 'beta', 'gamma', 10000 + id * 100));
72
+ await ctx.route('**/api/hub/messages*', (route) => route.fulfill({ json: { messages: msgs } }));
73
+ await ctx.route('**/api/hub/tasks*', (route) => route.fulfill({ json: { tasks: [] } }));
74
+
75
+ const page = await ctx.newPage();
76
+ await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
77
+ await page.waitForFunction(() => document.querySelectorAll('g[data-node]').length === 4, { timeout: 30000 });
78
+ await page.waitForTimeout(400);
79
+
80
+ const readTitle = (alias) => page.evaluate((a) => {
81
+ const node = document.querySelector(`g[data-node="${a}"]`);
82
+ return node?.querySelector('title')?.textContent || '';
83
+ }, alias);
84
+
85
+ const alphaTitle = await readTitle('alpha');
86
+ const deltaTitle = await readTitle('delta');
87
+
88
+ await browser.close();
89
+
90
+ const results = {
91
+ // alpha: flows aggregate
92
+ alpha_flowSummary: alphaTitle.includes('flows: 4 in / 10 out'),
93
+ // alpha: senders line
94
+ alpha_sendersLine: alphaTitle.includes('← from: beta (4)'),
95
+ // alpha: receivers line — must be sorted desc by count (gamma 5, beta 3, delta 2)
96
+ alpha_receiversOrder: alphaTitle.includes('→ to: gamma (5), beta (3), delta (2)'),
97
+
98
+ // delta: receiver only, only inbound from alpha (2 msgs)
99
+ delta_flowSummary: deltaTitle.includes('flows: 2 in / 0 out'),
100
+ delta_sendersLine: deltaTitle.includes('← from: alpha (2)'),
101
+ delta_noReceivers: !deltaTitle.includes('→ to:'),
102
+ };
103
+ const ok = Object.values(results).every(Boolean);
104
+ console.log(`${ok ? '✅' : '❌'} node title peers:`, JSON.stringify(results),
105
+ `\n alpha title:\n${alphaTitle}`,
106
+ `\n delta title:\n${deltaTitle}`);
107
+ process.exit(ok ? 0 : 1);
@@ -0,0 +1,101 @@
1
+ /* Round 98 verification: node <title> tooltips now include status,
2
+ * group membership (when applicable), and per-node flow counts
3
+ * (inbound/outbound) alongside the existing identity/cwd/last-seen
4
+ * lines. Same info-density spirit as R97 pill tooltips — hover any
5
+ * node and the answer is right there.
6
+ *
7
+ * Fleet:
8
+ * - alpha1 (working, claude) + alpha2 (idle, claude) → alpha group of 2
9
+ * - solo (working, gpt-5) — no group (singleton)
10
+ * - off1 (offline, claude) — has last_seen_at older
11
+ *
12
+ * Flows:
13
+ * alpha1 → solo × 3
14
+ * solo → alpha1 × 1
15
+ * ⇒ alpha1: 1 in / 3 out; solo: 3 in / 1 out; alpha2/off1: no flows
16
+ */
17
+ import { chromium } from 'playwright';
18
+ import { readFileSync } from 'node:fs';
19
+
20
+ const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
21
+ const browser = await chromium.launch({ headless: true });
22
+
23
+ const ctx = await browser.newContext({ viewport: { width: 1400, height: 1500 } });
24
+ await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
25
+ await ctx.addInitScript(() => {
26
+ try { localStorage.setItem('anet-theme', 'cyber'); sessionStorage.setItem('anet_v3_auth', '1'); } catch {}
27
+ });
28
+
29
+ const fresh = new Date(Date.now() - 60 * 1000).toISOString();
30
+ const stale = new Date(Date.now() - 20 * 60 * 1000).toISOString();
31
+ await ctx.route('**/api/hub/status*', async (route) => {
32
+ const r = await route.fetch();
33
+ const b = await r.json();
34
+ const nid = (b.sessions || [])[0]?.network_id || 'default';
35
+ const mk = (alias, status, model, ts) => ({
36
+ alias, status, model, runtime: 'cli-claude-code',
37
+ network_id: nid, project_dir: null,
38
+ created_at: ts, updated_at: ts, last_seen_at: ts,
39
+ });
40
+ const sessions = [
41
+ mk('alpha1', 'working', 'claude-opus-4', fresh),
42
+ mk('alpha2', 'idle', 'claude-opus-4', fresh),
43
+ mk('solo', 'working', 'gpt-5', fresh),
44
+ mk('off1', 'offline', 'claude-opus-4', stale),
45
+ ];
46
+ await route.fulfill({ response: r, json: { ...b, sessions } });
47
+ });
48
+
49
+ const now = Date.now();
50
+ const mkMsg = (id, from_alias, to_alias, ageMs) => ({
51
+ id, from_alias, to_alias, content: 'hi', network_id: 'default',
52
+ created_at: new Date(now - ageMs).toISOString(),
53
+ });
54
+ await ctx.route('**/api/hub/messages*', (route) => route.fulfill({ json: { messages: [
55
+ mkMsg('m1', 'alpha1', 'solo', 30 * 1000),
56
+ mkMsg('m2', 'alpha1', 'solo', 60 * 1000),
57
+ mkMsg('m3', 'alpha1', 'solo', 90 * 1000),
58
+ mkMsg('m4', 'solo', 'alpha1', 45 * 1000),
59
+ ] } }));
60
+ await ctx.route('**/api/hub/tasks*', (route) => route.fulfill({ json: { tasks: [] } }));
61
+ const page = await ctx.newPage();
62
+ await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
63
+ await page.waitForFunction(() => document.querySelectorAll('g[data-node]').length === 4, { timeout: 30000 });
64
+ await page.waitForTimeout(400);
65
+
66
+ const titles = await page.evaluate(() => {
67
+ const out = {};
68
+ for (const alias of ['alpha1', 'alpha2', 'solo', 'off1']) {
69
+ const g = document.querySelector(`g[data-node="${alias}"]`);
70
+ out[alias] = g?.querySelector('title')?.textContent || '';
71
+ }
72
+ return out;
73
+ });
74
+
75
+ await browser.close();
76
+
77
+ const results = {
78
+ // Status line is the heading.
79
+ alpha1_statusHeading: /^alpha1 · working/m.test(titles.alpha1),
80
+ alpha2_statusHeading: /^alpha2 · idle/m.test(titles.alpha2),
81
+ solo_statusHeading: /^solo · working/m.test(titles.solo),
82
+ off1_statusHeading: /^off1 · offline/m.test(titles.off1),
83
+ // Group line only on multi-member band.
84
+ alpha1_groupShown: /group: alpha · 2/.test(titles.alpha1),
85
+ alpha2_groupShown: /group: alpha · 2/.test(titles.alpha2),
86
+ solo_groupSkipped: !/group:/.test(titles.solo),
87
+ // Flow counts on participating nodes only.
88
+ alpha1_flowsCorrect: /flows: 1 in \/ 3 out/.test(titles.alpha1),
89
+ solo_flowsCorrect: /flows: 3 in \/ 1 out/.test(titles.solo),
90
+ alpha2_noFlows: !/flows:/.test(titles.alpha2),
91
+ off1_lastSeen: /last seen:/.test(titles.off1),
92
+ // Identity line still present.
93
+ alpha1_hasIdentity: /claude/i.test(titles.alpha1),
94
+ };
95
+ const ok = Object.values(results).every(Boolean);
96
+ console.log(`${ok ? '✅' : '❌'} node titles:`, JSON.stringify(results),
97
+ `\n alpha1:\n${titles.alpha1}`,
98
+ `\n alpha2:\n${titles.alpha2}`,
99
+ `\n solo:\n${titles.solo}`,
100
+ `\n off1:\n${titles.off1}`);
101
+ process.exit(ok ? 0 : 1);
@@ -0,0 +1,109 @@
1
+ /* Round 179 verification: nodeSize S/M/L active button picks up
2
+ * hover:bg-cyan-500/20, closing the inconsistency with R163
3
+ * layout-toggle and R178 fullscreen which already ship the
4
+ * cyan-500/20 hover step on the active variant.
5
+ *
6
+ * Three active-cyan chrome surfaces now share the same gesture:
7
+ * R163 Ring/Grid layout toggle (chip-row)
8
+ * R178 Fullscreen button (chrome BR)
9
+ * R179 nodeSize S/M/L (chrome BR) ← this round
10
+ *
11
+ * Test:
12
+ * 1. Default state: M is active (default nodeScale=0.84)
13
+ * 2. Active 'M' button:
14
+ * className includes 'bg-cyan-500/15 text-cyan-300 hover:bg-cyan-500/20'
15
+ * 3. Inactive 'S' button:
16
+ * className includes 'hover:bg-white/5'
17
+ * className does NOT include 'bg-cyan-500/15'
18
+ * 4. Click 'S' → S becomes active
19
+ * 5. S's className now has cyan + cyan-500/20 hover, M doesn'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
+ const browser = await chromium.launch({ headless: true });
26
+
27
+ const ctx = await browser.newContext({ viewport: { width: 1500, 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 {
31
+ localStorage.setItem('anet-theme', 'cyber');
32
+ sessionStorage.setItem('anet_v3_auth', '1');
33
+ localStorage.removeItem('anet-topo-nodescale');
34
+ } catch {}
35
+ });
36
+
37
+ const fresh = new Date(Date.now() - 60 * 1000).toISOString();
38
+ await ctx.route('**/api/hub/status*', async (route) => {
39
+ const r = await route.fetch();
40
+ const b = await r.json();
41
+ const nid = (b.sessions || [])[0]?.network_id || 'default';
42
+ const mk = (alias) => ({
43
+ alias, status: 'working', model: 'claude-opus-4', runtime: 'cli-claude-code',
44
+ network_id: nid, project_dir: null,
45
+ created_at: fresh, updated_at: fresh, last_seen_at: fresh,
46
+ });
47
+ await route.fulfill({ response: r, json: { ...b, sessions: [mk('alpha'), mk('beta'), mk('gamma')] } });
48
+ });
49
+ await ctx.route('**/api/hub/messages*', (route) => route.fulfill({ json: { messages: [] } }));
50
+ await ctx.route('**/api/hub/tasks*', (route) => route.fulfill({ json: { tasks: [] } }));
51
+
52
+ const page = await ctx.newPage();
53
+ await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
54
+ await page.waitForFunction(() => document.querySelectorAll('g[data-node]').length === 3, { timeout: 30000 });
55
+ await page.waitForSelector('[data-topo-chrome-nodesize="M"]', { timeout: 10000 });
56
+ await page.waitForTimeout(400);
57
+
58
+ const probe = () => page.evaluate(() => {
59
+ const grab = (sel) => {
60
+ const el = document.querySelector(sel);
61
+ return el ? {
62
+ className: el.getAttribute('class') || '',
63
+ active: el.getAttribute('data-topo-chrome-nodesize-active'),
64
+ } : null;
65
+ };
66
+ return {
67
+ S: grab('[data-topo-chrome-nodesize="S"]'),
68
+ M: grab('[data-topo-chrome-nodesize="M"]'),
69
+ L: grab('[data-topo-chrome-nodesize="L"]'),
70
+ };
71
+ });
72
+
73
+ const initial = await probe();
74
+
75
+ // Click S → S becomes active
76
+ await page.locator('[data-topo-chrome-nodesize="S"]').click();
77
+ await page.waitForTimeout(450); // past R171 crossfade window
78
+ const afterS = await probe();
79
+
80
+ await browser.close();
81
+
82
+ const results = {
83
+ // Initial: M default-active
84
+ M_initial_active: initial.M?.active === 'true',
85
+ M_initial_has_cyan_bg: initial.M?.className.includes('bg-cyan-500/15'),
86
+ M_initial_has_cyan_text: initial.M?.className.includes('text-cyan-300'),
87
+ M_initial_has_cyan_hover: initial.M?.className.includes('hover:bg-cyan-500/20'),
88
+
89
+ S_initial_inactive: initial.S?.active === 'false',
90
+ S_initial_no_cyan_bg: !initial.S?.className.includes('bg-cyan-500/15'),
91
+ S_initial_has_white_hover: initial.S?.className.includes('hover:bg-white/5'),
92
+ S_initial_no_cyan_hover: !initial.S?.className.includes('hover:bg-cyan-500/20'),
93
+
94
+ // After click S: S active, M inactive
95
+ S_after_click_active: afterS.S?.active === 'true',
96
+ S_after_has_cyan_bg: afterS.S?.className.includes('bg-cyan-500/15'),
97
+ S_after_has_cyan_hover: afterS.S?.className.includes('hover:bg-cyan-500/20'),
98
+ S_after_no_white_hover: !afterS.S?.className.includes('hover:bg-white/5'),
99
+
100
+ M_after_inactive: afterS.M?.active === 'false',
101
+ M_after_no_cyan_bg: !afterS.M?.className.includes('bg-cyan-500/15'),
102
+ M_after_no_cyan_hover: !afterS.M?.className.includes('hover:bg-cyan-500/20'),
103
+ M_after_has_white_hover: afterS.M?.className.includes('hover:bg-white/5'),
104
+ };
105
+ const ok = Object.values(results).every(Boolean);
106
+ console.log(`${ok ? '✅' : '❌'} nodesize active hover:`, JSON.stringify(results),
107
+ `\n initial =`, initial,
108
+ `\n afterS =`, afterS);
109
+ process.exit(ok ? 0 : 1);
@@ -0,0 +1,141 @@
1
+ /* Round 171 verification: nodeSize change (S/M/L) picks up the
2
+ * R170 crossfade pattern.
3
+ *
4
+ * Pre-R171 clicking S → L (or any non-active button) in the
5
+ * chrome node-size segment re-derived every node's radius +
6
+ * label sizing + (in grid) cell spacing in one paint frame.
7
+ * Wholesale visual shift, no easing.
8
+ *
9
+ * R171 introduces nodeSizeSwitching one-shot flag (parallel
10
+ * to R170 layoutSwitching). pickNodeScale arms it for 400ms
11
+ * UNLESS the picked scale matches the current one (clicking
12
+ * the already-active button bails early). The viewport <g>
13
+ * opacity dims to 0.45 via the same `(layoutSwitching ||
14
+ * nodeSizeSwitching)` OR expression.
15
+ *
16
+ * Test:
17
+ * 1. Idle: nodeSize-switching='false', opacity=1, M active
18
+ * 2. Click 'S' → flag='true', opacity='0.45', S now active
19
+ * 3. Wait 450ms → flag='false', opacity='1', S still active
20
+ * 4. Click 'S' again (same as current) → no flag arm (bail)
21
+ * 5. Click 'L' → flag='true' again
22
+ */
23
+ import { chromium } from 'playwright';
24
+ import { readFileSync } from 'node:fs';
25
+
26
+ const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
27
+ const browser = await chromium.launch({ headless: true });
28
+
29
+ const ctx = await browser.newContext({ viewport: { width: 1500, height: 1500 } });
30
+ await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
31
+ await ctx.addInitScript(() => {
32
+ try {
33
+ localStorage.setItem('anet-theme', 'cyber');
34
+ sessionStorage.setItem('anet_v3_auth', '1');
35
+ // Default M (0.84) per the React useState — explicitly clear any
36
+ // saved value so the test starts at a known state.
37
+ localStorage.removeItem('anet-topo-nodescale');
38
+ } catch {}
39
+ });
40
+
41
+ const fresh = new Date(Date.now() - 60 * 1000).toISOString();
42
+ await ctx.route('**/api/hub/status*', async (route) => {
43
+ const r = await route.fetch();
44
+ const b = await r.json();
45
+ const nid = (b.sessions || [])[0]?.network_id || 'default';
46
+ const mk = (alias) => ({
47
+ alias, status: 'working', model: 'claude-opus-4', runtime: 'cli-claude-code',
48
+ network_id: nid, project_dir: null,
49
+ created_at: fresh, updated_at: fresh, last_seen_at: fresh,
50
+ });
51
+ await route.fulfill({ response: r, json: { ...b, sessions: [mk('alpha'), mk('beta'), mk('gamma')] } });
52
+ });
53
+ await ctx.route('**/api/hub/messages*', (route) => route.fulfill({ json: { messages: [] } }));
54
+ await ctx.route('**/api/hub/tasks*', (route) => route.fulfill({ json: { tasks: [] } }));
55
+
56
+ const page = await ctx.newPage();
57
+ await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
58
+ await page.waitForFunction(() => document.querySelectorAll('g[data-node]').length === 3, { timeout: 30000 });
59
+ await page.waitForSelector('[data-topo-viewport]', { timeout: 10000 });
60
+ await page.waitForSelector('[data-topo-chrome-nodesize="S"]', { timeout: 10000 });
61
+ await page.waitForTimeout(400);
62
+
63
+ const probe = () => page.evaluate(() => {
64
+ const g = document.querySelector('[data-topo-viewport]');
65
+ const sBtn = document.querySelector('[data-topo-chrome-nodesize="S"]');
66
+ const mBtn = document.querySelector('[data-topo-chrome-nodesize="M"]');
67
+ const lBtn = document.querySelector('[data-topo-chrome-nodesize="L"]');
68
+ return {
69
+ nodeSizeSwitching: g?.getAttribute('data-topo-viewport-nodesize-switching'),
70
+ opacity: g?.style?.opacity || '',
71
+ transition: g?.style?.transition || '',
72
+ s_active: sBtn?.getAttribute('data-topo-chrome-nodesize-active'),
73
+ m_active: mBtn?.getAttribute('data-topo-chrome-nodesize-active'),
74
+ l_active: lBtn?.getAttribute('data-topo-chrome-nodesize-active'),
75
+ };
76
+ });
77
+
78
+ const idle = await probe();
79
+
80
+ // Click S → flag arms, opacity drops
81
+ await page.locator('[data-topo-chrome-nodesize="S"]').click();
82
+ await page.waitForTimeout(50);
83
+ const duringS = await probe();
84
+
85
+ // Wait past 400ms window
86
+ await page.waitForTimeout(450);
87
+ const afterS = await probe();
88
+
89
+ // Click S again (same as current) → no fire, no fade
90
+ await page.locator('[data-topo-chrome-nodesize="S"]').click();
91
+ await page.waitForTimeout(50);
92
+ const sameS = await probe();
93
+
94
+ // Click L (different from S) → flag arms again
95
+ await page.locator('[data-topo-chrome-nodesize="L"]').click();
96
+ await page.waitForTimeout(50);
97
+ const duringL = await probe();
98
+
99
+ await page.waitForTimeout(450);
100
+ const afterL = await probe();
101
+
102
+ await browser.close();
103
+
104
+ const results = {
105
+ viewport_found: idle !== null,
106
+ idle_flag_false: idle.nodeSizeSwitching === 'false',
107
+ idle_opacity_1: idle.opacity === '1' || idle.opacity === '',
108
+ idle_has_opacity_transition: idle.transition.includes('opacity 250ms'),
109
+ idle_M_active: idle.m_active === 'true',
110
+ idle_S_inactive: idle.s_active === 'false',
111
+ idle_L_inactive: idle.l_active === 'false',
112
+
113
+ S_armed_flag: duringS.nodeSizeSwitching === 'true',
114
+ S_armed_opacity_0p45: duringS.opacity === '0.45',
115
+ S_active_after_click: duringS.s_active === 'true',
116
+ S_M_deactivated: duringS.m_active === 'false',
117
+
118
+ after_S_flag_false: afterS.nodeSizeSwitching === 'false',
119
+ after_S_opacity_1: afterS.opacity === '1',
120
+ after_S_still_S_active: afterS.s_active === 'true',
121
+
122
+ sameS_no_arm: sameS.nodeSizeSwitching === 'false',
123
+ sameS_opacity_stable: sameS.opacity === '1',
124
+
125
+ L_armed_flag: duringL.nodeSizeSwitching === 'true',
126
+ L_armed_opacity_0p45: duringL.opacity === '0.45',
127
+ L_active_after_click: duringL.l_active === 'true',
128
+ L_S_deactivated: duringL.s_active === 'false',
129
+
130
+ after_L_flag_false: afterL.nodeSizeSwitching === 'false',
131
+ after_L_opacity_1: afterL.opacity === '1',
132
+ };
133
+ const ok = Object.values(results).every(Boolean);
134
+ console.log(`${ok ? '✅' : '❌'} nodesize crossfade:`, JSON.stringify(results),
135
+ `\n idle =`, idle,
136
+ `\n during S =`, duringS,
137
+ `\n after S =`, afterS,
138
+ `\n same S =`, sameS,
139
+ `\n during L =`, duringL,
140
+ `\n after L =`, afterL);
141
+ process.exit(ok ? 0 : 1);
@@ -0,0 +1,143 @@
1
+ /* Round 140 verification: the "N online" chip in the chip row
2
+ * gets an onClick that navigates to /nodes when interactive.
3
+ * Mirrors R136 active-links→/messages idiom; complements R139
4
+ * working→pin idiom. The online chip is the third chip-row chip
5
+ * that had cursor:pointer without a click action since R79.
6
+ *
7
+ * Why nav not pin: "online" = working + idle in semantics; there's
8
+ * no single pinnedStatus value that captures both. /nodes is the
9
+ * natural full-list destination.
10
+ *
11
+ * Three states tested:
12
+ * - Empty fleet (onlineCount=0): chip not interactive
13
+ * - 1 online: clickable, role=link, click → /nodes
14
+ * - 5 online (mix of working+idle): same shape, click → /nodes
15
+ *
16
+ * Hover preview still works (R79 highlight all online) — that's
17
+ * a separate gesture verified in topo-active-links-chip-hover-test
18
+ * for the chip-row's hover ladder.
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
+
25
+ // status: 'working' | 'idle' | 'offline' — distribute by counts
26
+ async function probe({ working, idle, offline }) {
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
+ const fresh = new Date(Date.now() - 60 * 1000).toISOString();
34
+ await ctx.route('**/api/hub/status*', async (route) => {
35
+ const r = await route.fetch();
36
+ const b = await r.json();
37
+ const nid = (b.sessions || [])[0]?.network_id || 'default';
38
+ const sessions = [];
39
+ let i = 0;
40
+ for (let n = 0; n < working; n++, i++) sessions.push(mk(i, 'working', fresh, nid));
41
+ for (let n = 0; n < idle; n++, i++) sessions.push(mk(i, 'idle', fresh, nid));
42
+ for (let n = 0; n < offline; n++, i++) sessions.push(mk(i, 'offline', fresh, nid));
43
+ await route.fulfill({ response: r, json: { ...b, sessions } });
44
+ });
45
+ await ctx.route('**/api/hub/messages*', (route) => route.fulfill({ json: { messages: [] } }));
46
+ await ctx.route('**/api/hub/tasks*', (route) => route.fulfill({ json: { tasks: [] } }));
47
+
48
+ const page = await ctx.newPage();
49
+ await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
50
+ // offline-only fleet won't render g[data-node] (only online ones do),
51
+ // but the chip row still renders because sessions.length > 0.
52
+ await page.waitForSelector('[data-online-chip]', { timeout: 10000 });
53
+ await page.waitForTimeout(400);
54
+
55
+ return { browser, page };
56
+ }
57
+
58
+ function mk(i, status, fresh, nid) {
59
+ return {
60
+ alias: `node${i}`,
61
+ status,
62
+ model: 'claude-opus-4', runtime: 'cli-claude-code',
63
+ network_id: nid, project_dir: null,
64
+ created_at: fresh, updated_at: fresh, last_seen_at: fresh,
65
+ };
66
+ }
67
+
68
+ // State A: 5 online (3 working / 2 idle)
69
+ const { browser: b1, page: p1 } = await probe({ working: 3, idle: 2, offline: 0 });
70
+ const fiveProbe = await p1.evaluate(() => {
71
+ const chip = document.querySelector('[data-online-chip]');
72
+ return {
73
+ text: chip?.textContent,
74
+ clickable: chip?.getAttribute('data-online-chip-clickable'),
75
+ role: chip?.getAttribute('role'),
76
+ tabindex: chip?.getAttribute('tabindex'),
77
+ cursor: chip?.getAttribute('style')?.includes('cursor: pointer'),
78
+ title: chip?.getAttribute('title'),
79
+ };
80
+ });
81
+ await p1.locator('[data-online-chip]').click();
82
+ await p1.waitForURL('**/nodes', { timeout: 10000 });
83
+ const fiveUrl = p1.url();
84
+ await b1.close();
85
+
86
+ // State B: 1 online (1 idle, 0 working)
87
+ const { browser: b2, page: p2 } = await probe({ working: 0, idle: 1, offline: 0 });
88
+ const oneProbe = await p2.evaluate(() => {
89
+ const chip = document.querySelector('[data-online-chip]');
90
+ return {
91
+ text: chip?.textContent,
92
+ clickable: chip?.getAttribute('data-online-chip-clickable'),
93
+ role: chip?.getAttribute('role'),
94
+ };
95
+ });
96
+ await p2.locator('[data-online-chip]').click();
97
+ await p2.waitForURL('**/nodes', { timeout: 10000 });
98
+ const oneUrl = p2.url();
99
+ await b2.close();
100
+
101
+ // State C: offline-only fleet (2 sessions, all offline → onlineNodes=0)
102
+ // 0-session fleet hits Overview's R52/R70 first-run CTA path, not
103
+ // TopoGraph; offline-only keeps the chip row alive so the non-
104
+ // interactive contract on "0 online" can be verified.
105
+ const { browser: b3, page: p3 } = await probe({ working: 0, idle: 0, offline: 2 });
106
+ const emptyProbe = await p3.evaluate(() => {
107
+ const chip = document.querySelector('[data-online-chip]');
108
+ return {
109
+ text: chip?.textContent,
110
+ clickable: chip?.getAttribute('data-online-chip-clickable'),
111
+ role: chip?.getAttribute('role'),
112
+ tabindex: chip?.getAttribute('tabindex'),
113
+ cursor: chip?.getAttribute('style')?.includes('cursor: pointer'),
114
+ };
115
+ });
116
+ await b3.close();
117
+
118
+ const results = {
119
+ five_text5Online: fiveProbe.text === '5 online',
120
+ five_clickableTrue: fiveProbe.clickable === 'true',
121
+ five_roleLink: fiveProbe.role === 'link',
122
+ five_tabIndex0: fiveProbe.tabindex === '0',
123
+ five_cursorPointer: fiveProbe.cursor === true,
124
+ five_titleMentionsNodes: (fiveProbe.title || '').includes('/nodes'),
125
+ five_navToNodes: /\/nodes$/.test(fiveUrl),
126
+
127
+ one_text1Online: oneProbe.text === '1 online',
128
+ one_clickableTrue: oneProbe.clickable === 'true',
129
+ one_roleLink: oneProbe.role === 'link',
130
+ one_navToNodes: /\/nodes$/.test(oneUrl),
131
+
132
+ empty_text0Online: emptyProbe.text === '0 online',
133
+ empty_clickableFalse: emptyProbe.clickable === 'false',
134
+ empty_noRole: emptyProbe.role === null || emptyProbe.role === undefined,
135
+ empty_noTabIndex: emptyProbe.tabindex === null || emptyProbe.tabindex === undefined,
136
+ empty_noCursor: !emptyProbe.cursor,
137
+ };
138
+ const ok = Object.values(results).every(Boolean);
139
+ console.log(`${ok ? '✅' : '❌'} online chip nav:`, JSON.stringify(results),
140
+ `\n fiveProbe=`, fiveProbe, ` fiveUrl=`, fiveUrl,
141
+ `\n oneProbe=`, oneProbe, ` oneUrl=`, oneUrl,
142
+ `\n emptyProbe=`, emptyProbe);
143
+ process.exit(ok ? 0 : 1);