@sleep2agi/agent-network-dashboard 0.4.6-preview.28 → 0.4.6-preview.281

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 (460) 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/08kf-.bgs10ze.js +1 -0
  171. package/.next/static/chunks/0c_eg6lxw~36i.js +4 -0
  172. package/.next/static/chunks/0ggj5ummw2a84.js +7 -0
  173. package/.next/static/chunks/0glmrdj9112tc.js +7 -0
  174. package/.next/static/chunks/0qnfuwkukbu01.js +1 -0
  175. package/.next/static/chunks/0rxrez_cjn.eh.js +1 -0
  176. package/.next/static/chunks/0x8x.29hkju5a.js +1 -0
  177. package/.next/static/chunks/0y.7kwty.hl7h.css +2 -0
  178. package/.next/static/chunks/11ilooy_9niy-.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 +5595 -246
  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/package.json +2 -2
  190. package/scripts/help-overlay-topo-test.mjs +44 -0
  191. package/scripts/topo-active-filter-pill-test.mjs +101 -0
  192. package/scripts/topo-active-links-chip-hover-test.mjs +103 -0
  193. package/scripts/topo-active-links-chip-nav-test.mjs +117 -0
  194. package/scripts/topo-active-links-chip-self-hover-test.mjs +171 -0
  195. package/scripts/topo-active-links-chip-test.mjs +73 -0
  196. package/scripts/topo-active-links-empty-recede-test.mjs +125 -0
  197. package/scripts/topo-active-links-freshness-test.mjs +113 -0
  198. package/scripts/topo-active-links-tooltip-test.mjs +79 -0
  199. package/scripts/topo-active-pulse-ease-test.mjs +120 -0
  200. package/scripts/topo-arrival-ping-test.mjs +87 -0
  201. package/scripts/topo-auto-fit-test.mjs +73 -0
  202. package/scripts/topo-canvas-aria-test.mjs +108 -0
  203. package/scripts/topo-chat-target-breath-test.mjs +84 -0
  204. package/scripts/topo-chat-target-ring-ease-test.mjs +82 -0
  205. package/scripts/topo-chat-target-ring-fade-test.mjs +124 -0
  206. package/scripts/topo-chip-empty-recede-test.mjs +116 -0
  207. package/scripts/topo-chip-focus-test.mjs +95 -0
  208. package/scripts/topo-chip-pin-mirror-test.mjs +113 -0
  209. package/scripts/topo-chip-row-semantic-gap-test.mjs +97 -0
  210. package/scripts/topo-chip-row-tabular-test.mjs +111 -0
  211. package/scripts/topo-chrome-a11y-test.mjs +107 -0
  212. package/scripts/topo-chrome-pop-extension-test.mjs +98 -0
  213. package/scripts/topo-chrome-pop-nodesize-test.mjs +88 -0
  214. package/scripts/topo-chrome-press-state-test.mjs +135 -0
  215. package/scripts/topo-chrome-strip-semantic-gap-test.mjs +99 -0
  216. package/scripts/topo-chrome-strip-theme-ease-test.mjs +99 -0
  217. package/scripts/topo-chrome-zoom-level-pop-test.mjs +122 -0
  218. package/scripts/topo-chrome-zoom-pop-test.mjs +130 -0
  219. package/scripts/topo-click-ripple-ease-test.mjs +94 -0
  220. package/scripts/topo-cmdk-edge-clear-test.mjs +109 -0
  221. package/scripts/topo-cmdk-layout-view-test.mjs +108 -0
  222. package/scripts/topo-cmdk-pin-test.mjs +123 -0
  223. package/scripts/topo-cmdk-vendor-clear-test.mjs +133 -0
  224. package/scripts/topo-cmdk-vendor-pin-test.mjs +103 -0
  225. package/scripts/topo-corner-radius-unify-test.mjs +103 -0
  226. package/scripts/topo-cwd-tooltip-test.mjs +64 -0
  227. package/scripts/topo-dblclick-reset-test.mjs +74 -0
  228. package/scripts/topo-dense-alias-fill-transition-test.mjs +133 -0
  229. package/scripts/topo-discrete-zoom-smooth-test.mjs +125 -0
  230. package/scripts/topo-dispatch-pulse-test.mjs +83 -0
  231. package/scripts/topo-edge-badge-click-pin-test.mjs +94 -0
  232. package/scripts/topo-edge-badge-crossfade-test.mjs +138 -0
  233. package/scripts/topo-edge-badge-hot-test.mjs +115 -0
  234. package/scripts/topo-edge-badge-hover-test.mjs +85 -0
  235. package/scripts/topo-edge-badge-lift-test.mjs +150 -0
  236. package/scripts/topo-edge-badge-ripple-test.mjs +111 -0
  237. package/scripts/topo-edge-badge-stroke-transition-test.mjs +118 -0
  238. package/scripts/topo-edge-badge-text-pin-test.mjs +121 -0
  239. package/scripts/topo-edge-badge-theme-ease-test.mjs +89 -0
  240. package/scripts/topo-edge-count-badge-test.mjs +86 -0
  241. package/scripts/topo-edge-endpoint-highlight-test.mjs +111 -0
  242. package/scripts/topo-edge-fadein-test.mjs +106 -0
  243. package/scripts/topo-edge-focus-test.mjs +113 -0
  244. package/scripts/topo-edge-hover-test.mjs +93 -0
  245. package/scripts/topo-edge-pill-hot-test.mjs +129 -0
  246. package/scripts/topo-edge-pill-test.mjs +105 -0
  247. package/scripts/topo-edge-smil-sync-test.mjs +148 -0
  248. package/scripts/topo-edge-smil-theme-ease-test.mjs +97 -0
  249. package/scripts/topo-edge-stroke-ease-test.mjs +100 -0
  250. package/scripts/topo-edge-stroke-transition-test.mjs +132 -0
  251. package/scripts/topo-edge-tooltip-test.mjs +70 -0
  252. package/scripts/topo-empty-state-breath-test.mjs +150 -0
  253. package/scripts/topo-empty-state-crossfade-test.mjs +130 -0
  254. package/scripts/topo-empty-state-recenter-test.mjs +107 -0
  255. package/scripts/topo-endpoint-ring-fade-test.mjs +132 -0
  256. package/scripts/topo-endpoint-ring-test.mjs +93 -0
  257. package/scripts/topo-endpoint-ring-thicken-test.mjs +112 -0
  258. package/scripts/topo-esc-clears-pin-test.mjs +98 -0
  259. package/scripts/topo-filter-pill-aliases-test.mjs +121 -0
  260. package/scripts/topo-filter-pill-body-click-test.mjs +112 -0
  261. package/scripts/topo-filter-pill-count-test.mjs +110 -0
  262. package/scripts/topo-filter-pill-mobile-test.mjs +90 -0
  263. package/scripts/topo-fit-key-test.mjs +106 -0
  264. package/scripts/topo-freshness-chip-test.mjs +74 -0
  265. package/scripts/topo-freshness-chip-transition-test.mjs +80 -0
  266. package/scripts/topo-freshness-text-color-coherence-test.mjs +97 -0
  267. package/scripts/topo-fullscreen-active-test.mjs +115 -0
  268. package/scripts/topo-group-box-pinned-state-test.mjs +95 -0
  269. package/scripts/topo-group-count-test.mjs +6 -1
  270. package/scripts/topo-group-label-a11y-test.mjs +113 -0
  271. package/scripts/topo-group-label-count-inherit-test.mjs +99 -0
  272. package/scripts/topo-group-label-hover-test.mjs +119 -0
  273. package/scripts/topo-group-label-pin-spacing-test.mjs +136 -0
  274. package/scripts/topo-group-label-tint-test.mjs +99 -0
  275. package/scripts/topo-group-label-title-test.mjs +83 -0
  276. package/scripts/topo-group-pin-test.mjs +119 -0
  277. package/scripts/topo-group-pip-fadein-test.mjs +100 -0
  278. package/scripts/topo-group-pip-tabular-test.mjs +95 -0
  279. package/scripts/topo-group-status-pips-test.mjs +103 -0
  280. package/scripts/topo-groupbox-fadein-test.mjs +95 -0
  281. package/scripts/topo-groupbox-hover-lift-test.mjs +127 -0
  282. package/scripts/topo-groupbox-hubcore-ease-test.mjs +106 -0
  283. package/scripts/topo-groupbox-live-test.mjs +100 -0
  284. package/scripts/topo-groupbox-march-busyness-test.mjs +155 -0
  285. package/scripts/topo-groupbox-test.mjs +4 -2
  286. package/scripts/topo-halo-breath-ease-test.mjs +92 -0
  287. package/scripts/topo-halo-breath-stagger-test.mjs +89 -0
  288. package/scripts/topo-help-overlay-r109-test.mjs +67 -0
  289. package/scripts/topo-help-overlay-r118-test.mjs +69 -0
  290. package/scripts/topo-help-overlay-r123-test.mjs +69 -0
  291. package/scripts/topo-help-overlay-r134-test.mjs +74 -0
  292. package/scripts/topo-help-overlay-r137-test.mjs +81 -0
  293. package/scripts/topo-help-overlay-r141-test.mjs +86 -0
  294. package/scripts/topo-help-overlay-r153-test.mjs +85 -0
  295. package/scripts/topo-help-overlay-r59-test.mjs +67 -0
  296. package/scripts/topo-help-overlay-r65-test.mjs +64 -0
  297. package/scripts/topo-help-overlay-r70-test.mjs +63 -0
  298. package/scripts/topo-help-overlay-r78-test.mjs +59 -0
  299. package/scripts/topo-help-overlay-r81-test.mjs +58 -0
  300. package/scripts/topo-help-overlay-r87-test.mjs +64 -0
  301. package/scripts/topo-help-overlay-r91-test.mjs +65 -0
  302. package/scripts/topo-hot-tail-crossfade-test.mjs +117 -0
  303. package/scripts/topo-html-overlay-padding-unify-test.mjs +120 -0
  304. package/scripts/topo-hub-a11y-test.mjs +112 -0
  305. package/scripts/topo-hub-busyness-test.mjs +100 -0
  306. package/scripts/topo-hub-center-crossfade-test.mjs +124 -0
  307. package/scripts/topo-hub-click-fit-test.mjs +137 -0
  308. package/scripts/topo-hub-digit-scale-test.mjs +129 -0
  309. package/scripts/topo-hub-fadein-test.mjs +88 -0
  310. package/scripts/topo-hub-hover-lift-test.mjs +101 -0
  311. package/scripts/topo-hub-hover-ring-test.mjs +82 -0
  312. package/scripts/topo-hub-pip-theme-ease-test.mjs +116 -0
  313. package/scripts/topo-hub-spoke-ease-test.mjs +120 -0
  314. package/scripts/topo-hub-title-test.mjs +93 -0
  315. package/scripts/topo-hub-working-count-test.mjs +99 -0
  316. package/scripts/topo-ingroup-edge-test.mjs +103 -0
  317. package/scripts/topo-label-card-theme-ease-test.mjs +85 -0
  318. package/scripts/topo-label-lift-test.mjs +119 -0
  319. package/scripts/topo-lastseen-tooltip-test.mjs +59 -0
  320. package/scripts/topo-layout-hover-text-preview-test.mjs +101 -0
  321. package/scripts/topo-layout-key-test.mjs +91 -0
  322. package/scripts/topo-layout-switch-crossfade-test.mjs +126 -0
  323. package/scripts/topo-layout-toggle-border-unify-test.mjs +104 -0
  324. package/scripts/topo-layout-toggle-test.mjs +131 -0
  325. package/scripts/topo-legend-count-empty-test.mjs +126 -0
  326. package/scripts/topo-legend-count-tabular-test.mjs +87 -0
  327. package/scripts/topo-legend-count-test.mjs +88 -0
  328. package/scripts/topo-legend-count-tier-fill-test.mjs +121 -0
  329. package/scripts/topo-legend-header-symmetric-inset-test.mjs +112 -0
  330. package/scripts/topo-legend-hitbox-swatch-center-test.mjs +93 -0
  331. package/scripts/topo-legend-hover-test.mjs +113 -0
  332. package/scripts/topo-legend-offline-delimiter-test.mjs +84 -0
  333. package/scripts/topo-legend-panel-header-test.mjs +83 -0
  334. package/scripts/topo-legend-pin-ring-fade-test.mjs +112 -0
  335. package/scripts/topo-legend-pin-test.mjs +128 -0
  336. package/scripts/topo-legend-row-hover-lift-test.mjs +109 -0
  337. package/scripts/topo-legend-row-pin-spacing-test.mjs +124 -0
  338. package/scripts/topo-legend-row-tint-test.mjs +95 -0
  339. package/scripts/topo-legend-row-title-test.mjs +102 -0
  340. package/scripts/topo-legend-swatch-grow-test.mjs +116 -0
  341. package/scripts/topo-minimap-a11y-test.mjs +101 -0
  342. package/scripts/topo-minimap-dot-transition-test.mjs +113 -0
  343. package/scripts/topo-minimap-test.mjs +68 -0
  344. package/scripts/topo-minimap-viewport-smooth-test.mjs +124 -0
  345. package/scripts/topo-mobile-chips-test.mjs +103 -0
  346. package/scripts/topo-node-a11y-test.mjs +107 -0
  347. package/scripts/topo-node-hover-lift-test.mjs +85 -0
  348. package/scripts/topo-node-label-card-elevation-test.mjs +157 -0
  349. package/scripts/topo-node-label-card-stroke-test.mjs +135 -0
  350. package/scripts/topo-node-stroke-transition-test.mjs +103 -0
  351. package/scripts/topo-node-text-fill-transition-test.mjs +119 -0
  352. package/scripts/topo-node-title-peers-test.mjs +107 -0
  353. package/scripts/topo-node-title-test.mjs +101 -0
  354. package/scripts/topo-nodesize-active-hover-test.mjs +109 -0
  355. package/scripts/topo-nodesize-crossfade-test.mjs +141 -0
  356. package/scripts/topo-online-chip-nav-test.mjs +143 -0
  357. package/scripts/topo-orbit-busyness-test.mjs +96 -0
  358. package/scripts/topo-orbit-opacity-bucket-test.mjs +124 -0
  359. package/scripts/topo-overlap-test.mjs +32 -5
  360. package/scripts/topo-pan-cursor-test.mjs +62 -0
  361. package/scripts/topo-panel-elevation-test.mjs +76 -0
  362. package/scripts/topo-panel-fadein-test.mjs +102 -0
  363. package/scripts/topo-panel-hot-tail-fade-test.mjs +132 -0
  364. package/scripts/topo-panel-hover-elevation-test.mjs +118 -0
  365. package/scripts/topo-panel-theme-ease-test.mjs +85 -0
  366. package/scripts/topo-panel-title-fill-ease-test.mjs +91 -0
  367. package/scripts/topo-particle-stagger-test.mjs +82 -0
  368. package/scripts/topo-pin-intersection-color-ease-test.mjs +111 -0
  369. package/scripts/topo-pin-intersection-empty-test.mjs +129 -0
  370. package/scripts/topo-pin-intersection-tabular-test.mjs +96 -0
  371. package/scripts/topo-pin-intersection-test.mjs +121 -0
  372. package/scripts/topo-pin-intersection-warning-crossfade-test.mjs +107 -0
  373. package/scripts/topo-pin-mirror-transition-test.mjs +101 -0
  374. package/scripts/topo-pin-persistence-test.mjs +105 -0
  375. package/scripts/topo-ping-pulse-ease-test.mjs +96 -0
  376. package/scripts/topo-popover-meta-test.mjs +78 -0
  377. package/scripts/topo-prepublish-guard-test.mjs +95 -0
  378. package/scripts/topo-pressure-bar-test.mjs +69 -0
  379. package/scripts/topo-pressure-hover-test.mjs +123 -0
  380. package/scripts/topo-pressure-pin-test.mjs +119 -0
  381. package/scripts/topo-pressure-seg-self-hover-test.mjs +126 -0
  382. package/scripts/topo-pressure-seg-tooltip-test.mjs +98 -0
  383. package/scripts/topo-pressure-seg-transition-test.mjs +107 -0
  384. package/scripts/topo-pulse-dot-crossfade-test.mjs +122 -0
  385. package/scripts/topo-pulse-rate-test.mjs +71 -0
  386. package/scripts/topo-recent-panel-count-freshness-test.mjs +109 -0
  387. package/scripts/topo-recent-panel-count-test.mjs +72 -0
  388. package/scripts/topo-recent-panel-footer-breath-test.mjs +142 -0
  389. package/scripts/topo-recent-panel-hot-header-test.mjs +132 -0
  390. package/scripts/topo-recent-panel-more-crossfade-test.mjs +124 -0
  391. package/scripts/topo-recent-panel-more-cyan-hover-test.mjs +151 -0
  392. package/scripts/topo-recent-panel-more-nav-test.mjs +127 -0
  393. package/scripts/topo-recent-panel-more-test.mjs +106 -0
  394. package/scripts/topo-recent-panel-readability-bump-test.mjs +151 -0
  395. package/scripts/topo-recent-row-count-fill-test.mjs +129 -0
  396. package/scripts/topo-recent-row-fadein-test.mjs +107 -0
  397. package/scripts/topo-recent-row-freshness-test.mjs +102 -0
  398. package/scripts/topo-recent-row-hot-test.mjs +110 -0
  399. package/scripts/topo-recent-row-hover-lift-test.mjs +128 -0
  400. package/scripts/topo-recent-row-hover-test.mjs +122 -0
  401. package/scripts/topo-recent-row-pin-spacing-test.mjs +137 -0
  402. package/scripts/topo-recent-row-pin-test.mjs +126 -0
  403. package/scripts/topo-recent-row-tint-test.mjs +91 -0
  404. package/scripts/topo-recent-row-title-test.mjs +112 -0
  405. package/scripts/topo-recent-row-ts-alpha-test.mjs +100 -0
  406. package/scripts/topo-recent-row-ts-test.mjs +95 -0
  407. package/scripts/topo-recent-row-typography-test.mjs +119 -0
  408. package/scripts/topo-recent-signal-empty-hint-test.mjs +73 -0
  409. package/scripts/topo-recent-signal-empty-test.mjs +63 -0
  410. package/scripts/topo-reduced-motion-test.mjs +77 -0
  411. package/scripts/topo-reset-spin-test.mjs +120 -0
  412. package/scripts/topo-runtime-badge-grow-test.mjs +114 -0
  413. package/scripts/topo-spoke-busyness-test.mjs +110 -0
  414. package/scripts/topo-spoke-tint-test.mjs +96 -0
  415. package/scripts/topo-status-chip-hover-test.mjs +101 -0
  416. package/scripts/topo-status-chip-tooltip-test.mjs +95 -0
  417. package/scripts/topo-statusbar-chips-self-hover-test.mjs +177 -0
  418. package/scripts/topo-svg-focus-test.mjs +112 -0
  419. package/scripts/topo-sweep-busyness-test.mjs +94 -0
  420. package/scripts/topo-tabular-nums-sweep-test.mjs +93 -0
  421. package/scripts/topo-tier-ring-fadein-test.mjs +107 -0
  422. package/scripts/topo-tier-ring-occupancy-test.mjs +87 -0
  423. package/scripts/topo-tier-ring-test.mjs +69 -0
  424. package/scripts/topo-tier-ring-tint-test.mjs +110 -0
  425. package/scripts/topo-tier-stagger-test.mjs +89 -0
  426. package/scripts/topo-title-block-tight-leading-test.mjs +95 -0
  427. package/scripts/topo-toggle-inactive-cyan-hover-test.mjs +110 -0
  428. package/scripts/topo-top-rail-theme-ease-test.mjs +89 -0
  429. package/scripts/topo-tz-ghost-test.mjs +69 -0
  430. package/scripts/topo-vendor-chip-hover-test.mjs +111 -0
  431. package/scripts/topo-vendor-chip-self-hover-test.mjs +130 -0
  432. package/scripts/topo-vendor-chip-tabular-test.mjs +89 -0
  433. package/scripts/topo-vendor-letter-tooltip-test.mjs +92 -0
  434. package/scripts/topo-vendor-pill-test.mjs +125 -0
  435. package/scripts/topo-vendor-pin-test.mjs +125 -0
  436. package/scripts/topo-view-smooth-test.mjs +131 -0
  437. package/scripts/topo-wheel-zoom-test.mjs +79 -0
  438. package/scripts/topo-working-chip-pin-test.mjs +154 -0
  439. package/scripts/topo-working-halo-breath-test.mjs +86 -0
  440. package/scripts/topo-wrapper-flow-arrow-theme-test.mjs +97 -0
  441. package/scripts/topo-wrapper-shadow-theme-ease-test.mjs +89 -0
  442. package/scripts/topo-zoom-keys-test.mjs +89 -0
  443. package/.next/static/chunks/0-7iowzu4.798.js +0 -1
  444. package/.next/static/chunks/02t5jr4shh.hy.js +0 -1
  445. package/.next/static/chunks/09nd.t_hd.y6t.css +0 -2
  446. package/.next/static/chunks/0_qfg5s5uzs7..js +0 -7
  447. package/.next/static/chunks/0a6k5x_~ch.y7.js +0 -1
  448. package/.next/static/chunks/0elalb9n_.~di.js +0 -1
  449. package/.next/static/chunks/0ipujag5x55bt.js +0 -1
  450. package/.next/static/chunks/0j_q__o8p6g83.js +0 -1
  451. package/.next/static/chunks/0jl6_w50zh4l5.js +0 -1
  452. package/.next/static/chunks/0pl7l_.2im.j0.js +0 -7
  453. package/.next/static/chunks/0r4q73.-1bkyl.js +0 -1
  454. package/.next/static/chunks/0r_c8eccg3z2o.js +0 -1
  455. package/.next/static/chunks/0zs511wcsq~0j.js +0 -1
  456. package/.next/static/chunks/10oi7l-tycgl9.js +0 -1
  457. package/.next/static/chunks/11uk1izuv3~0t.js +0 -1
  458. /package/.next/static/{DCVxQ0usFqDQ5PHW3d_Zx → gjUOBeB2JqesZ_cSX14ph}/_buildManifest.js +0 -0
  459. /package/.next/static/{DCVxQ0usFqDQ5PHW3d_Zx → gjUOBeB2JqesZ_cSX14ph}/_clientMiddlewareManifest.js +0 -0
  460. /package/.next/static/{DCVxQ0usFqDQ5PHW3d_Zx → gjUOBeB2JqesZ_cSX14ph}/_ssgManifest.js +0 -0
@@ -0,0 +1,171 @@
1
+ /* Round 193 verification: the active-links chip itself responds to
2
+ * hover by adopting a cyan tint, mirroring the canvas-edge highlight
3
+ * it already fires (which R77's topo-active-links-chip-hover-test
4
+ * verifies). Two different surfaces:
5
+ * R77 test → canvas edges (effect element)
6
+ * R193 test → chip itself (cause element)
7
+ *
8
+ * Pre-R193 the chip stayed gray when hovered while the canvas edges
9
+ * brightened to cyan — cause-element silent, effect-element loud.
10
+ * R193 attaches a Tailwind :hover variant (cyan-500/10 bg, cyan-200
11
+ * text, cyan-500/30 border) when the chip is interactive, plus a
12
+ * transition-colors duration-200 for smooth blend. Non-interactive
13
+ * chips (0 active links) keep the gray-only variant.
14
+ *
15
+ * Test scenarios:
16
+ * A. Interactive (3 flows):
17
+ * 1. Idle: bg near gray-500/10 (R,G,B close to each other)
18
+ * 2. className includes 'hover:bg-cyan-500/10'
19
+ * 3. Hover: bg, text, border all shift cyan (B > R)
20
+ * 4. transition-colors duration-200 present
21
+ * 5. bg actually changed from idle to hover
22
+ * B. Non-interactive (0 flows):
23
+ * 6. className does NOT include 'hover:bg-cyan-500/10'
24
+ * 7. data-active-links-clickable='false'
25
+ */
26
+ import { chromium } from 'playwright';
27
+ import { readFileSync } from 'node:fs';
28
+
29
+ const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
30
+ const browser = await chromium.launch({ headless: true });
31
+
32
+ const ctx = await browser.newContext({ viewport: { width: 1500, height: 1500 } });
33
+ await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
34
+ await ctx.addInitScript(() => {
35
+ try { localStorage.setItem('anet-theme', 'cyber'); sessionStorage.setItem('anet_v3_auth', '1'); } catch {}
36
+ });
37
+
38
+ async function load(flowsScenario) {
39
+ const fresh = new Date(Date.now() - 60 * 1000).toISOString();
40
+ await ctx.unroute('**/api/hub/status*').catch(() => {});
41
+ await ctx.unroute('**/api/hub/messages*').catch(() => {});
42
+ await ctx.unroute('**/api/hub/tasks*').catch(() => {});
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) => ({
48
+ alias, status: 'working', 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'), mk('beta'), mk('gamma'), mk('delta'),
54
+ ] } });
55
+ });
56
+ const now = Date.now();
57
+ const msgs = flowsScenario(now);
58
+ await ctx.route('**/api/hub/messages*', (route) => route.fulfill({ json: { messages: msgs } }));
59
+ await ctx.route('**/api/hub/tasks*', (route) => route.fulfill({ json: { tasks: [] } }));
60
+
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.waitForSelector('[data-active-links-chip]', { timeout: 10000 });
65
+ await page.waitForTimeout(400);
66
+ return page;
67
+ }
68
+
69
+ // Scenario A: 3 flows (interactive)
70
+ const pageA = await load((now) => [
71
+ { id: '1', from_alias: 'alpha', to_alias: 'beta', content: 'hi',
72
+ network_id: 'default', created_at: new Date(now - 5000).toISOString() },
73
+ { id: '2', from_alias: 'beta', to_alias: 'gamma', content: 'hi',
74
+ network_id: 'default', created_at: new Date(now - 8000).toISOString() },
75
+ { id: '3', from_alias: 'gamma', to_alias: 'delta', content: 'hi',
76
+ network_id: 'default', created_at: new Date(now - 11000).toISOString() },
77
+ ]);
78
+
79
+ const idleA = await pageA.evaluate(() => {
80
+ const el = document.querySelector('[data-active-links-chip]');
81
+ const cs = getComputedStyle(el);
82
+ return {
83
+ className: el.getAttribute('class') || '',
84
+ clickable: el.getAttribute('data-active-links-clickable'),
85
+ flowCount: el.getAttribute('data-active-links-flow-count'),
86
+ bg: cs.backgroundColor,
87
+ color: cs.color,
88
+ borderColor:cs.borderTopColor,
89
+ transition: cs.transitionProperty + ' / ' + cs.transitionDuration,
90
+ };
91
+ });
92
+
93
+ await pageA.hover('[data-active-links-chip]');
94
+ await pageA.waitForTimeout(280); // longer than 200ms transition
95
+
96
+ const hoverA = await pageA.evaluate(() => {
97
+ const el = document.querySelector('[data-active-links-chip]');
98
+ const cs = getComputedStyle(el);
99
+ return {
100
+ bg: cs.backgroundColor,
101
+ color: cs.color,
102
+ borderColor:cs.borderTopColor,
103
+ };
104
+ });
105
+
106
+ await pageA.mouse.move(0, 0);
107
+ await pageA.waitForTimeout(50);
108
+ await pageA.close();
109
+
110
+ // Scenario B: 0 flows (non-interactive)
111
+ const pageB = await load(() => []);
112
+ const idleB = await pageB.evaluate(() => {
113
+ const el = document.querySelector('[data-active-links-chip]');
114
+ return {
115
+ className: el.getAttribute('class') || '',
116
+ clickable: el.getAttribute('data-active-links-clickable'),
117
+ flowCount: el.getAttribute('data-active-links-flow-count'),
118
+ };
119
+ });
120
+ await pageB.close();
121
+ await browser.close();
122
+
123
+ // Tailwind 4 emits modern color spaces (oklab / lab). Cyan in OKLab
124
+ // is characterised by a<0 (green-leaning) AND b<0 (blue-leaning).
125
+ // Gray has a ≈ 0, b ≈ 0. Lab uses similar axes at different scales.
126
+ function parseLab(s) {
127
+ const m = (s || '').match(/(?:oklab|lab)\(\s*([\-\d.]+)\s+([\-\d.]+)\s+([\-\d.]+)/);
128
+ return m ? { L: +m[1], a: +m[2], b: +m[3] } : null;
129
+ }
130
+ const idleBgLab = parseLab(idleA.bg);
131
+ const hoverBgLab = parseLab(hoverA.bg);
132
+ const hoverFgLab = parseLab(hoverA.color);
133
+ const hoverBdLab = parseLab(hoverA.borderColor);
134
+ const idleFgLab = parseLab(idleA.color);
135
+
136
+ // Cyan-leaning thresholds: a more negative by at least 0.05 (OKLab)
137
+ // or 5 (Lab), b similarly. Robust to either color space.
138
+ const isMoreCyan = (idle, hov) =>
139
+ hov && idle && (hov.a < idle.a - 0.04 || hov.b < idle.b - 0.04 || hov.a < -0.05 || hov.b < -0.05);
140
+
141
+ const results = {
142
+ // A1: idle is roughly gray-ish — small a,b deviation from 0
143
+ idleA_gray_bg: idleBgLab && Math.abs(idleBgLab.a) < 0.05 && Math.abs(idleBgLab.b) < 0.05,
144
+
145
+ // A2: className has hover variant
146
+ idleA_has_hover: idleA.className.includes('hover:bg-cyan-500/10'),
147
+
148
+ // A3: hovered surfaces lean cyan vs idle
149
+ hover_bg_cyan: isMoreCyan(idleBgLab, hoverBgLab),
150
+ hover_text_cyan: isMoreCyan(idleFgLab, hoverFgLab),
151
+ hover_border_cyan: isMoreCyan(idleBgLab, hoverBdLab),
152
+
153
+ // bg actually changed
154
+ bg_changed: idleA.bg !== hoverA.bg,
155
+
156
+ // A4: transition-colors duration-200 present
157
+ idleA_has_transition: idleA.transition.includes('color') && idleA.transition.includes('0.2s'),
158
+ idleA_clickable_true: idleA.clickable === 'true',
159
+ idleA_flow_count_3: idleA.flowCount === '3',
160
+
161
+ // B6: non-interactive chip has NO hover variant
162
+ idleB_no_hover: !idleB.className.includes('hover:bg-cyan-500/10'),
163
+ idleB_clickable_false:idleB.clickable === 'false',
164
+ idleB_flow_count_0: idleB.flowCount === '0',
165
+ };
166
+ const ok = Object.values(results).every(Boolean);
167
+ console.log(`${ok ? '✅' : '❌'} active-links chip self-hover:`, JSON.stringify(results),
168
+ `\n idleA:`, idleA,
169
+ `\n hoverA:`, hoverA,
170
+ `\n idleB:`, idleB);
171
+ process.exit(ok ? 0 : 1);
@@ -0,0 +1,73 @@
1
+ /* Round 42 verification: "X active links" chip in the header includes
2
+ * "· last <relative>" when flow links exist, drops the `· last …` tail
3
+ * when no flow links are present, and renders singular/plural correctly. */
4
+ import { chromium } from 'playwright';
5
+ import { readFileSync } from 'node:fs';
6
+
7
+ const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
8
+ const browser = await chromium.launch({ headless: true });
9
+
10
+ async function probe({ msgs }) {
11
+ const ctx = await browser.newContext({ viewport: { width: 1400, height: 1000 } });
12
+ await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
13
+ await ctx.addInitScript(() => {
14
+ try {
15
+ localStorage.setItem('anet-theme', 'cyber');
16
+ localStorage.setItem('anet-topo-layout', 'grid');
17
+ sessionStorage.setItem('anet_v3_auth', '1');
18
+ } catch {}
19
+ });
20
+ const fresh = new Date(Date.now() - 60 * 1000).toISOString();
21
+ await ctx.route('**/api/hub/status*', async (route) => {
22
+ const r = await route.fetch();
23
+ const b = await r.json();
24
+ const nid = (b.sessions || [])[0]?.network_id || 'default';
25
+ const sessions = ['alpha', 'beta', 'gamma'].map(a => ({
26
+ alias: a, status: 'idle', network_id: nid, project_dir: null,
27
+ created_at: fresh, updated_at: fresh, last_seen_at: fresh,
28
+ }));
29
+ await route.fulfill({ response: r, json: { ...b, sessions } });
30
+ });
31
+ await ctx.route('**/api/hub/messages*', (route) => route.fulfill({ json: { messages: msgs } }));
32
+ await ctx.route('**/api/hub/tasks*', (route) => route.fulfill({ json: { tasks: [] } }));
33
+ const page = await ctx.newPage();
34
+ await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
35
+ await page.waitForSelector('svg[viewBox="0 0 1000 680"]', { timeout: 30000 });
36
+ await page.waitForTimeout(500);
37
+ const text = await page.evaluate(() => {
38
+ // The active-links chip is the LAST chip in the topo header row (after
39
+ // pressure-bar + vendor + working/online). Match by `active link`.
40
+ const spans = [...document.querySelectorAll('span')];
41
+ return spans.find(s => /active link/.test(s.textContent || ''))?.textContent?.replace(/\s+/g, ' ').trim() || null;
42
+ });
43
+ await ctx.close();
44
+ return text;
45
+ }
46
+
47
+ // 1. No messages → 0 active links, no "· last X" tail
48
+ const empty = await probe({ msgs: [] });
49
+ // 2. One message just now → 1 active link · last Ns ago
50
+ const recent = await probe({ msgs: [
51
+ { from_alias: 'alpha', to_alias: 'beta', content: 'hi', created_at: new Date(Date.now() - 30 * 1000).toISOString() },
52
+ ] });
53
+ // 3. Five messages, latest 4 min ago → 5 active links · last 4m ago (singular link uses "link", plural "links")
54
+ const fourMinAgo = new Date(Date.now() - 4 * 60 * 1000).toISOString();
55
+ const eightMinAgo = new Date(Date.now() - 8 * 60 * 1000).toISOString();
56
+ const five = await probe({ msgs: [
57
+ { from_alias: 'alpha', to_alias: 'beta', content: '1', created_at: eightMinAgo },
58
+ { from_alias: 'alpha', to_alias: 'gamma', content: '2', created_at: eightMinAgo },
59
+ { from_alias: 'alpha', to_alias: 'gamma', content: '3', created_at: eightMinAgo },
60
+ { from_alias: 'beta', to_alias: 'gamma', content: '4', created_at: eightMinAgo },
61
+ { from_alias: 'beta', to_alias: 'gamma', content: '5', created_at: fourMinAgo }, // latest
62
+ ] });
63
+
64
+ await browser.close();
65
+ const results = {
66
+ emptyChipHasNoTail: empty === '0 active links',
67
+ recentSingularChip: recent !== null && /^1 active link · last \d+s ago$/.test(recent),
68
+ pluralChipShowsLatest: five !== null && /active links · last [34]m ago/.test(five),
69
+ };
70
+ const ok = Object.values(results).every(Boolean);
71
+ console.log(`${ok ? '✅' : '❌'} active-links chip:`, JSON.stringify(results),
72
+ `\n empty=${JSON.stringify(empty)}\n recent=${JSON.stringify(recent)}\n five=${JSON.stringify(five)}`);
73
+ process.exit(ok ? 0 : 1);
@@ -0,0 +1,125 @@
1
+ /* Round 206 verification: active-links chip recedes to opacity 0.5
2
+ * when flowLinks.length === 0, mirroring R204 legend count recede and
3
+ * R205 working/online chip recede patterns at a third scope.
4
+ *
5
+ * Pre-R206 "0 active links" rendered at the same bg-gray-500/10 +
6
+ * opacity 1 as "12 active links" — only the absent cursor + missing
7
+ * tooltip signalled empty. R206 adds the visual recede so all three
8
+ * signals (visual / interactive / affordance) align.
9
+ *
10
+ * Test scenarios:
11
+ * A. 0 messages → flowLinks.length === 0:
12
+ * data-active-links-empty='true', clickable='false',
13
+ * opacity ≈ 0.5
14
+ * B. 3 messages → flowLinks.length === 3:
15
+ * data-active-links-empty='false', clickable='true',
16
+ * opacity = 1.0
17
+ * Both: inline transition includes color/background-color/
18
+ * border-color/opacity 200ms (4-property splice).
19
+ * R193 hover-cyan markup preserved in scenario B className.
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
+ async function setup(messages) {
28
+ const ctx = await browser.newContext({ viewport: { width: 1500, 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 mk = (alias) => ({
39
+ alias, status: 'working', model: 'claude-opus-4', runtime: 'cli-claude-code',
40
+ network_id: nid, project_dir: null,
41
+ created_at: fresh, updated_at: fresh, last_seen_at: fresh,
42
+ });
43
+ await route.fulfill({ response: r, json: { ...b, sessions: [
44
+ mk('alpha'), mk('beta'), mk('gamma'), mk('delta'),
45
+ ] } });
46
+ });
47
+ await ctx.route('**/api/hub/messages*', (r2) => r2.fulfill({ json: { messages } }));
48
+ await ctx.route('**/api/hub/tasks*', (r2) => r2.fulfill({ json: { tasks: [] } }));
49
+ const page = await ctx.newPage();
50
+ await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
51
+ await page.waitForFunction(() => document.querySelectorAll('g[data-node]').length === 4, { timeout: 30000 });
52
+ await page.waitForSelector('[data-active-links-chip]', { timeout: 10000 });
53
+ await page.waitForTimeout(300);
54
+ return page;
55
+ }
56
+
57
+ const probe = async (page) => page.evaluate(() => {
58
+ const el = document.querySelector('[data-active-links-chip]');
59
+ if (!el) return null;
60
+ const cs = getComputedStyle(el);
61
+ return {
62
+ className: el.getAttribute('class') || '',
63
+ empty: el.getAttribute('data-active-links-empty'),
64
+ clickable: el.getAttribute('data-active-links-clickable'),
65
+ flowCount: el.getAttribute('data-active-links-flow-count'),
66
+ opacity: parseFloat(cs.opacity),
67
+ transition: el.style.transition,
68
+ bg: cs.backgroundColor,
69
+ };
70
+ });
71
+
72
+ // Scenario A: empty
73
+ const pageA = await setup([]);
74
+ const probeA = await probe(pageA);
75
+ await pageA.close();
76
+
77
+ // Scenario B: populated
78
+ const now = Date.now();
79
+ const pageB = await setup([
80
+ { id: '1', from_alias: 'alpha', to_alias: 'beta', content: 'hi',
81
+ network_id: 'default', created_at: new Date(now - 1000).toISOString() },
82
+ { id: '2', from_alias: 'beta', to_alias: 'gamma', content: 'hi',
83
+ network_id: 'default', created_at: new Date(now - 2000).toISOString() },
84
+ { id: '3', from_alias: 'gamma', to_alias: 'delta', content: 'hi',
85
+ network_id: 'default', created_at: new Date(now - 3000).toISOString() },
86
+ ]);
87
+ const probeB = await probe(pageB);
88
+ await pageB.close();
89
+ await browser.close();
90
+
91
+ const near = (got, want, tol = 0.05) => Math.abs(got - want) < tol;
92
+ const has = (s, re) => re.test(s || '');
93
+
94
+ const results = {
95
+ // Scenario A: 0 flows
96
+ A_chip_present: !!probeA,
97
+ A_flow_count_0: probeA?.flowCount === '0',
98
+ A_empty_true: probeA?.empty === 'true',
99
+ A_clickable_false: probeA?.clickable === 'false',
100
+ A_opacity_half: near(probeA?.opacity ?? 0, 0.5),
101
+ // hover variant NOT present on empty (only base bg-gray)
102
+ A_no_hover_variant: !(probeA?.className || '').includes('hover:bg-cyan-500/10'),
103
+
104
+ // Scenario B: 3 flows
105
+ B_chip_present: !!probeB,
106
+ B_flow_count_3: probeB?.flowCount === '3',
107
+ B_empty_false: probeB?.empty === 'false',
108
+ B_clickable_true: probeB?.clickable === 'true',
109
+ B_opacity_full: near(probeB?.opacity ?? 0, 1.0),
110
+ // R193 hover-cyan markup preserved
111
+ B_has_hover_variant: (probeB?.className || '').includes('hover:bg-cyan-500/10'),
112
+
113
+ // Transition integrity — 4-property splice on both scenarios
114
+ A_transition_opacity: has(probeA?.transition, /opacity\s+(?:200ms|0\.2s)/),
115
+ A_transition_bg: has(probeA?.transition, /background-color\s+(?:200ms|0\.2s)/),
116
+ A_transition_color: has(probeA?.transition, /\bcolor\s+(?:200ms|0\.2s)/),
117
+ A_transition_border: has(probeA?.transition, /border-color\s+(?:200ms|0\.2s)/),
118
+ B_transition_opacity: has(probeB?.transition, /opacity\s+(?:200ms|0\.2s)/),
119
+ B_transition_bg: has(probeB?.transition, /background-color\s+(?:200ms|0\.2s)/),
120
+ };
121
+ const ok = Object.values(results).every(Boolean);
122
+ console.log(`${ok ? '✅' : '❌'} active-links empty recede:`, JSON.stringify(results),
123
+ `\n probeA (0 flows):`, probeA,
124
+ `\n probeB (3 flows):`, probeB);
125
+ process.exit(ok ? 0 : 1);
@@ -0,0 +1,113 @@
1
+ /* Round 161 verification: active-links chip bullet picks up
2
+ * the R160 freshness vocabulary.
3
+ *
4
+ * R10 fades canvas flow edges by freshness. R160 brought that
5
+ * vocabulary to the recent-signal panel rows via a 1.6-px cyan
6
+ * pip at row left edge. R161 extends it one more scope — up to
7
+ * the fleet-aggregate active-links chip in the chip-row.
8
+ *
9
+ * The chip text was already "3 active links · last 5s ago" but
10
+ * the " · " separator was dead gray. R161 colors that bullet
11
+ * by freshness using the same alpha ramp:
12
+ * ageSec ≤ 30 → 1.0 (fully fresh)
13
+ * 30-300s → 1.0 → 0.25 smooth decay
14
+ * > 300s → 0.25 stale floor
15
+ *
16
+ * Three nested scopes now share one freshness ladder:
17
+ * canvas edge fade (R10) — per-edge visual
18
+ * row pip (R160) — per-flow row in recent-signal
19
+ * chip bullet (R161) — fleet aggregate in chip-row
20
+ *
21
+ * Test scenarios (one page load each):
22
+ * A. fresh most-recent flow (5s ago) → alpha ≈ 1.0, fontWeight 700
23
+ * B. mid recency (90s ago) → alpha ≈ 0.83
24
+ * C. stale (360s ago) → alpha ≈ 0.25 (floor)
25
+ *
26
+ * Color parses out of `rgba(34, 211, 238, 1)` cyber theme.
27
+ */
28
+ import { chromium } from 'playwright';
29
+ import { readFileSync } from 'node:fs';
30
+
31
+ const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
32
+ const browser = await chromium.launch({ headless: true });
33
+
34
+ const ctx = await browser.newContext({ viewport: { width: 1500, height: 1500 } });
35
+ await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
36
+ await ctx.addInitScript(() => {
37
+ try { localStorage.setItem('anet-theme', 'cyber'); sessionStorage.setItem('anet_v3_auth', '1'); } catch {}
38
+ });
39
+
40
+ async function probe(msgAgeSec) {
41
+ const fresh = new Date(Date.now() - 60 * 1000).toISOString();
42
+ await ctx.unroute('**/api/hub/status*').catch(() => {});
43
+ await ctx.unroute('**/api/hub/messages*').catch(() => {});
44
+ await ctx.unroute('**/api/hub/tasks*').catch(() => {});
45
+ await ctx.route('**/api/hub/status*', async (route) => {
46
+ const r = await route.fetch();
47
+ const b = await r.json();
48
+ const nid = (b.sessions || [])[0]?.network_id || 'default';
49
+ const mk = (alias) => ({
50
+ alias, status: 'working', model: 'claude-opus-4', runtime: 'cli-claude-code',
51
+ network_id: nid, project_dir: null,
52
+ created_at: fresh, updated_at: fresh, last_seen_at: fresh,
53
+ });
54
+ await route.fulfill({ response: r, json: { ...b, sessions: [mk('alpha'), mk('beta')] } });
55
+ });
56
+ await ctx.route('**/api/hub/messages*', (route) => route.fulfill({ json: { messages: [
57
+ { id: 'x', from_alias: 'alpha', to_alias: 'beta', content: 'hi',
58
+ network_id: 'default', created_at: new Date(Date.now() - msgAgeSec * 1000).toISOString() },
59
+ ] } }));
60
+ await ctx.route('**/api/hub/tasks*', (route) => route.fulfill({ json: { tasks: [] } }));
61
+
62
+ const page = await ctx.newPage();
63
+ await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
64
+ await page.waitForFunction(() => document.querySelectorAll('g[data-node]').length === 2, { timeout: 30000 });
65
+ await page.waitForSelector('[data-active-links-freshness-dot]', { timeout: 10000 });
66
+ await page.waitForTimeout(400);
67
+ const out = await page.evaluate(() => {
68
+ const el = document.querySelector('[data-active-links-freshness-dot]');
69
+ if (!el) return null;
70
+ const styleColor = el.style.color || getComputedStyle(el).color;
71
+ return {
72
+ alpha: parseFloat(el.getAttribute('data-active-links-freshness-alpha') || ''),
73
+ color: styleColor,
74
+ fontWeight: el.style.fontWeight || getComputedStyle(el).fontWeight,
75
+ text: el.textContent,
76
+ };
77
+ });
78
+ await page.close();
79
+ return out;
80
+ }
81
+
82
+ const A = await probe(5); // fresh
83
+ const B = await probe(90); // mid
84
+ const C = await probe(360); // stale
85
+
86
+ await browser.close();
87
+
88
+ const cyanRgb = (str) => {
89
+ // Inline `style="color: rgba(34, 211, 238, ...)"` — alpha is part of color.
90
+ const m = /rgba?\((\d+),\s*(\d+),\s*(\d+)/.exec(str);
91
+ if (!m) return null;
92
+ return [Number(m[1]), Number(m[2]), Number(m[3])];
93
+ };
94
+
95
+ const results = {
96
+ fresh_dot_found: A !== null,
97
+ mid_dot_found: B !== null,
98
+ stale_dot_found: C !== null,
99
+ fresh_alpha_1: A && Math.abs(A.alpha - 1.0) < 0.05,
100
+ mid_alpha_window: B && B.alpha > 0.7 && B.alpha < 0.95,
101
+ stale_alpha_floor: C && Math.abs(C.alpha - 0.25) < 0.05,
102
+ fresh_color_cyan: A && JSON.stringify(cyanRgb(A.color)) === '[34,211,238]',
103
+ fresh_weight_bold: A && (A.fontWeight === '700' || A.fontWeight === 'bold'),
104
+ stale_weight_norm: C && (C.fontWeight === '400' || C.fontWeight === 'normal' || C.fontWeight === ''),
105
+ ladder_descends: A && B && C && A.alpha > B.alpha && B.alpha > C.alpha,
106
+ text_is_separator: A && A.text && A.text.trim() === '·',
107
+ };
108
+ const ok = Object.values(results).every(Boolean);
109
+ console.log(`${ok ? '✅' : '❌'} active-links freshness:`, JSON.stringify(results),
110
+ `\n fresh =`, A,
111
+ `\n mid =`, B,
112
+ `\n stale =`, C);
113
+ process.exit(ok ? 0 : 1);
@@ -0,0 +1,79 @@
1
+ /* Round 114 verification: active-links chip tooltip lists the actual
2
+ * flow pairs. Closes the info-density sweep on the last chip-row
3
+ * hover surface (R97-R113 covered everything else). Format:
4
+ * "alpha→beta (3), gamma→delta (1) — hover brightens all"
5
+ *
6
+ * Drive 3 flow pairs of different counts. Verify each pair appears
7
+ * in the title with its count; the trailing action hint says
8
+ * "hover brightens all". Empty-flow fleet → no title.
9
+ */
10
+ import { chromium } from 'playwright';
11
+ import { readFileSync } from 'node:fs';
12
+
13
+ const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
14
+ const browser = await chromium.launch({ headless: true });
15
+ const fresh = new Date(Date.now() - 30 * 1000).toISOString();
16
+
17
+ const probe = async (withFlow) => {
18
+ const ctx = await browser.newContext({ viewport: { width: 1400, height: 1500 } });
19
+ await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
20
+ await ctx.addInitScript(() => {
21
+ try { localStorage.setItem('anet-theme', 'cyber'); sessionStorage.setItem('anet_v3_auth', '1'); } catch {}
22
+ });
23
+ await ctx.route('**/api/hub/status*', async (route) => {
24
+ const r = await route.fetch();
25
+ const b = await r.json();
26
+ const nid = (b.sessions || [])[0]?.network_id || 'default';
27
+ const mk = (alias) => ({
28
+ alias, status: 'idle', model: 'claude-opus-4', runtime: 'cli-claude-code',
29
+ network_id: nid, project_dir: null,
30
+ created_at: fresh, updated_at: fresh, last_seen_at: fresh,
31
+ });
32
+ await route.fulfill({ response: r, json: { ...b, sessions: [mk('alpha'), mk('beta'), mk('gamma'), mk('delta')] } });
33
+ });
34
+ const now = Date.now();
35
+ const mkMsg = (id, from_alias, to_alias, ageMs) => ({
36
+ id, from_alias, to_alias, content: 'hi', network_id: 'default',
37
+ created_at: new Date(now - ageMs).toISOString(),
38
+ });
39
+ await ctx.route('**/api/hub/messages*', (route) => route.fulfill({ json: { messages: withFlow ? [
40
+ mkMsg('m1', 'alpha', 'beta', 30 * 1000),
41
+ mkMsg('m2', 'alpha', 'beta', 40 * 1000),
42
+ mkMsg('m3', 'alpha', 'beta', 50 * 1000),
43
+ mkMsg('m4', 'gamma', 'delta', 60 * 1000),
44
+ ] : [] } }));
45
+ await ctx.route('**/api/hub/tasks*', (route) => route.fulfill({ json: { tasks: [] } }));
46
+ const page = await ctx.newPage();
47
+ await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
48
+ await page.waitForFunction(() => document.querySelectorAll('g[data-node]').length === 4, { timeout: 30000 });
49
+ await page.waitForTimeout(600);
50
+ const data = await page.evaluate(() => {
51
+ const el = document.querySelector('[data-active-links-chip]');
52
+ return {
53
+ title: el?.getAttribute('title'),
54
+ flowCount: el?.getAttribute('data-active-links-flow-count') || '',
55
+ text: el?.textContent?.trim() || '',
56
+ };
57
+ });
58
+ await ctx.close();
59
+ return data;
60
+ };
61
+
62
+ const empty = await probe(false);
63
+ const full = await probe(true);
64
+ await browser.close();
65
+
66
+ const results = {
67
+ empty_noTitle: empty.title === null,
68
+ empty_zeroCount: empty.flowCount === '0',
69
+ full_titleHasAlphaBeta: /alpha→beta \(3\)/.test(full.title || ''),
70
+ full_titleHasGammaDelta: /gamma→delta \(1\)/.test(full.title || ''),
71
+ full_titleActionHint: /hover brightens all/.test(full.title || ''),
72
+ full_flowCount2: full.flowCount === '2',
73
+ full_chipShowsCount: /2 active link/.test(full.text),
74
+ };
75
+ const ok = Object.values(results).every(Boolean);
76
+ console.log(`${ok ? '✅' : '❌'} active-links tooltip:`, JSON.stringify(results),
77
+ `\n empty=`, empty,
78
+ `\n full=`, full);
79
+ process.exit(ok ? 0 : 1);