@sleep2agi/agent-network-dashboard 0.5.3 → 0.5.5-preview.0

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/app-path-routes-manifest.json +2 -0
  3. package/.next/build-manifest.json +3 -3
  4. package/.next/diagnostics/route-bundle-stats.json +37 -37
  5. package/.next/fallback-build-manifest.json +3 -3
  6. package/.next/prerender-manifest.json +29 -0
  7. package/.next/routes-manifest.json +12 -0
  8. package/.next/server/app/_global-error.html +1 -1
  9. package/.next/server/app/_global-error.rsc +2 -2
  10. package/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  11. package/.next/server/app/_global-error.segments/_full.segment.rsc +2 -2
  12. package/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  13. package/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  14. package/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  15. package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  16. package/.next/server/app/_not-found.html +3 -3
  17. package/.next/server/app/_not-found.rsc +14 -14
  18. package/.next/server/app/_not-found.segments/_full.segment.rsc +14 -14
  19. package/.next/server/app/_not-found.segments/_head.segment.rsc +4 -4
  20. package/.next/server/app/_not-found.segments/_index.segment.rsc +7 -7
  21. package/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +2 -2
  22. package/.next/server/app/_not-found.segments/_not-found.segment.rsc +3 -3
  23. package/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  24. package/.next/server/app/admin/page_client-reference-manifest.js +1 -1
  25. package/.next/server/app/admin.html +3 -3
  26. package/.next/server/app/admin.rsc +16 -16
  27. package/.next/server/app/admin.segments/_full.segment.rsc +16 -16
  28. package/.next/server/app/admin.segments/_head.segment.rsc +4 -4
  29. package/.next/server/app/admin.segments/_index.segment.rsc +7 -7
  30. package/.next/server/app/admin.segments/_tree.segment.rsc +2 -2
  31. package/.next/server/app/admin.segments/admin/__PAGE__.segment.rsc +4 -4
  32. package/.next/server/app/admin.segments/admin.segment.rsc +3 -3
  33. package/.next/server/app/api/hub/upload/route/app-paths-manifest.json +3 -0
  34. package/.next/server/app/api/hub/upload/route/build-manifest.json +9 -0
  35. package/.next/server/app/api/hub/upload/route/server-reference-manifest.json +4 -0
  36. package/.next/server/app/api/hub/upload/route.js +7 -0
  37. package/.next/server/app/api/hub/upload/route.js.map +5 -0
  38. package/.next/server/app/api/hub/upload/route.js.nft.json +1 -0
  39. package/.next/server/app/api/hub/upload/route_client-reference-manifest.js +3 -0
  40. package/.next/server/app/index.html +3 -3
  41. package/.next/server/app/index.rsc +16 -16
  42. package/.next/server/app/index.segments/__PAGE__.segment.rsc +4 -4
  43. package/.next/server/app/index.segments/_full.segment.rsc +16 -16
  44. package/.next/server/app/index.segments/_head.segment.rsc +4 -4
  45. package/.next/server/app/index.segments/_index.segment.rsc +7 -7
  46. package/.next/server/app/index.segments/_tree.segment.rsc +2 -2
  47. package/.next/server/app/login/page_client-reference-manifest.js +1 -1
  48. package/.next/server/app/login.html +2 -2
  49. package/.next/server/app/login.rsc +16 -16
  50. package/.next/server/app/login.segments/_full.segment.rsc +16 -16
  51. package/.next/server/app/login.segments/_head.segment.rsc +4 -4
  52. package/.next/server/app/login.segments/_index.segment.rsc +7 -7
  53. package/.next/server/app/login.segments/_tree.segment.rsc +2 -2
  54. package/.next/server/app/login.segments/login/__PAGE__.segment.rsc +4 -4
  55. package/.next/server/app/login.segments/login.segment.rsc +3 -3
  56. package/.next/server/app/logs/page_client-reference-manifest.js +1 -1
  57. package/.next/server/app/logs.html +3 -3
  58. package/.next/server/app/logs.rsc +16 -16
  59. package/.next/server/app/logs.segments/_full.segment.rsc +16 -16
  60. package/.next/server/app/logs.segments/_head.segment.rsc +4 -4
  61. package/.next/server/app/logs.segments/_index.segment.rsc +7 -7
  62. package/.next/server/app/logs.segments/_tree.segment.rsc +2 -2
  63. package/.next/server/app/logs.segments/logs/__PAGE__.segment.rsc +4 -4
  64. package/.next/server/app/logs.segments/logs.segment.rsc +3 -3
  65. package/.next/server/app/manifest.webmanifest/route/app-paths-manifest.json +3 -0
  66. package/.next/server/app/manifest.webmanifest/route/build-manifest.json +9 -0
  67. package/.next/server/app/manifest.webmanifest/route/server-reference-manifest.json +4 -0
  68. package/.next/server/app/manifest.webmanifest/route.js +8 -0
  69. package/.next/server/app/manifest.webmanifest/route.js.map +5 -0
  70. package/.next/server/app/manifest.webmanifest/route.js.nft.json +1 -0
  71. package/.next/server/app/manifest.webmanifest/route_client-reference-manifest.js +3 -0
  72. package/.next/server/app/manifest.webmanifest.body +1 -0
  73. package/.next/server/app/manifest.webmanifest.meta +1 -0
  74. package/.next/server/app/messages/page_client-reference-manifest.js +1 -1
  75. package/.next/server/app/messages.html +3 -3
  76. package/.next/server/app/messages.rsc +16 -16
  77. package/.next/server/app/messages.segments/_full.segment.rsc +16 -16
  78. package/.next/server/app/messages.segments/_head.segment.rsc +4 -4
  79. package/.next/server/app/messages.segments/_index.segment.rsc +7 -7
  80. package/.next/server/app/messages.segments/_tree.segment.rsc +2 -2
  81. package/.next/server/app/messages.segments/messages/__PAGE__.segment.rsc +4 -4
  82. package/.next/server/app/messages.segments/messages.segment.rsc +3 -3
  83. package/.next/server/app/node/page_client-reference-manifest.js +1 -1
  84. package/.next/server/app/node.html +3 -3
  85. package/.next/server/app/node.rsc +16 -16
  86. package/.next/server/app/node.segments/_full.segment.rsc +16 -16
  87. package/.next/server/app/node.segments/_head.segment.rsc +4 -4
  88. package/.next/server/app/node.segments/_index.segment.rsc +7 -7
  89. package/.next/server/app/node.segments/_tree.segment.rsc +2 -2
  90. package/.next/server/app/node.segments/node/__PAGE__.segment.rsc +4 -4
  91. package/.next/server/app/node.segments/node.segment.rsc +3 -3
  92. package/.next/server/app/nodes/page_client-reference-manifest.js +1 -1
  93. package/.next/server/app/nodes.html +3 -3
  94. package/.next/server/app/nodes.rsc +16 -16
  95. package/.next/server/app/nodes.segments/_full.segment.rsc +16 -16
  96. package/.next/server/app/nodes.segments/_head.segment.rsc +4 -4
  97. package/.next/server/app/nodes.segments/_index.segment.rsc +7 -7
  98. package/.next/server/app/nodes.segments/_tree.segment.rsc +2 -2
  99. package/.next/server/app/nodes.segments/nodes/__PAGE__.segment.rsc +4 -4
  100. package/.next/server/app/nodes.segments/nodes.segment.rsc +3 -3
  101. package/.next/server/app/page_client-reference-manifest.js +1 -1
  102. package/.next/server/app/server-logs/page_client-reference-manifest.js +1 -1
  103. package/.next/server/app/server-logs.html +3 -3
  104. package/.next/server/app/server-logs.rsc +16 -16
  105. package/.next/server/app/server-logs.segments/_full.segment.rsc +16 -16
  106. package/.next/server/app/server-logs.segments/_head.segment.rsc +4 -4
  107. package/.next/server/app/server-logs.segments/_index.segment.rsc +7 -7
  108. package/.next/server/app/server-logs.segments/_tree.segment.rsc +2 -2
  109. package/.next/server/app/server-logs.segments/server-logs/__PAGE__.segment.rsc +4 -4
  110. package/.next/server/app/server-logs.segments/server-logs.segment.rsc +3 -3
  111. package/.next/server/app/settings/networks/page_client-reference-manifest.js +1 -1
  112. package/.next/server/app/settings/networks.html +3 -3
  113. package/.next/server/app/settings/networks.rsc +16 -16
  114. package/.next/server/app/settings/networks.segments/_full.segment.rsc +16 -16
  115. package/.next/server/app/settings/networks.segments/_head.segment.rsc +4 -4
  116. package/.next/server/app/settings/networks.segments/_index.segment.rsc +7 -7
  117. package/.next/server/app/settings/networks.segments/_tree.segment.rsc +2 -2
  118. package/.next/server/app/settings/networks.segments/settings/networks/__PAGE__.segment.rsc +4 -4
  119. package/.next/server/app/settings/networks.segments/settings/networks.segment.rsc +3 -3
  120. package/.next/server/app/settings/networks.segments/settings.segment.rsc +3 -3
  121. package/.next/server/app/settings/page_client-reference-manifest.js +1 -1
  122. package/.next/server/app/settings/tokens/page_client-reference-manifest.js +1 -1
  123. package/.next/server/app/settings/tokens.html +3 -3
  124. package/.next/server/app/settings/tokens.rsc +16 -16
  125. package/.next/server/app/settings/tokens.segments/_full.segment.rsc +16 -16
  126. package/.next/server/app/settings/tokens.segments/_head.segment.rsc +4 -4
  127. package/.next/server/app/settings/tokens.segments/_index.segment.rsc +7 -7
  128. package/.next/server/app/settings/tokens.segments/_tree.segment.rsc +2 -2
  129. package/.next/server/app/settings/tokens.segments/settings/tokens/__PAGE__.segment.rsc +4 -4
  130. package/.next/server/app/settings/tokens.segments/settings/tokens.segment.rsc +3 -3
  131. package/.next/server/app/settings/tokens.segments/settings.segment.rsc +3 -3
  132. package/.next/server/app/settings.html +3 -3
  133. package/.next/server/app/settings.rsc +16 -16
  134. package/.next/server/app/settings.segments/_full.segment.rsc +16 -16
  135. package/.next/server/app/settings.segments/_head.segment.rsc +4 -4
  136. package/.next/server/app/settings.segments/_index.segment.rsc +7 -7
  137. package/.next/server/app/settings.segments/_tree.segment.rsc +2 -2
  138. package/.next/server/app/settings.segments/settings/__PAGE__.segment.rsc +4 -4
  139. package/.next/server/app/settings.segments/settings.segment.rsc +3 -3
  140. package/.next/server/app/tasks/[id]/page_client-reference-manifest.js +1 -1
  141. package/.next/server/app/tasks/page_client-reference-manifest.js +1 -1
  142. package/.next/server/app/tasks.html +3 -3
  143. package/.next/server/app/tasks.rsc +16 -16
  144. package/.next/server/app/tasks.segments/_full.segment.rsc +16 -16
  145. package/.next/server/app/tasks.segments/_head.segment.rsc +4 -4
  146. package/.next/server/app/tasks.segments/_index.segment.rsc +7 -7
  147. package/.next/server/app/tasks.segments/_tree.segment.rsc +2 -2
  148. package/.next/server/app/tasks.segments/tasks/__PAGE__.segment.rsc +4 -4
  149. package/.next/server/app/tasks.segments/tasks.segment.rsc +3 -3
  150. package/.next/server/app-paths-manifest.json +2 -0
  151. package/.next/server/chunks/00jm_next_dist_0ju_ux9._.js +18 -0
  152. package/.next/server/chunks/00jm_next_dist_0ju_ux9._.js.map +1 -0
  153. package/.next/server/chunks/0ykm__next-internal_server_app_api_hub_upload_route_actions_03_eqnf.js +3 -0
  154. package/.next/server/chunks/0ykm__next-internal_server_app_manifest_webmanifest_route_actions_0m16rb8.js +3 -0
  155. package/.next/server/chunks/0ykm__next-internal_server_app_manifest_webmanifest_route_actions_0m16rb8.js.map +1 -0
  156. package/.next/server/chunks/{[externals]__11vad82._.js → [externals]__036g1.i._.js} +2 -2
  157. package/.next/server/chunks/[externals]__036g1.i._.js.map +1 -0
  158. package/.next/server/chunks/[root-of-the-server]__0-8_f0o._.js +3 -0
  159. package/.next/server/chunks/[root-of-the-server]__0-8_f0o._.js.map +1 -0
  160. package/.next/server/chunks/{[root-of-the-server]__08uyvdq._.js → [root-of-the-server]__0jndzts._.js} +2 -2
  161. package/.next/server/chunks/{[root-of-the-server]__08uyvdq._.js.map → [root-of-the-server]__0jndzts._.js.map} +1 -1
  162. package/.next/server/chunks/[root-of-the-server]__0mxw4vb._.js +1 -1
  163. package/.next/server/chunks/[root-of-the-server]__0mxw4vb._.js.map +1 -1
  164. package/.next/server/chunks/[root-of-the-server]__0tx8s8i._.js +1 -1
  165. package/.next/server/chunks/[root-of-the-server]__0tx8s8i._.js.map +1 -1
  166. package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_0..ddwm.js +1 -1
  167. package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_0..ddwm.js.map +1 -1
  168. package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_02bxi6j.js +1 -1
  169. package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_02bxi6j.js.map +1 -1
  170. package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_05oassd.js +1 -1
  171. package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_05oassd.js.map +1 -1
  172. package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_05vxtby.js +1 -1
  173. package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_05vxtby.js.map +1 -1
  174. package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_05~eml4.js +1 -1
  175. package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_05~eml4.js.map +1 -1
  176. package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_0_-g_q2.js +1 -1
  177. package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_0_-g_q2.js.map +1 -1
  178. package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_0_ec0xu.js +1 -1
  179. package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_0_ec0xu.js.map +1 -1
  180. package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_0czb6wz.js +1 -1
  181. package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_0czb6wz.js.map +1 -1
  182. package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_0e-cn.p.js +1 -1
  183. package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_0e-cn.p.js.map +1 -1
  184. package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_0k8_sr8.js +1 -1
  185. package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_0k8_sr8.js.map +1 -1
  186. package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_0lt_3bw.js +1 -1
  187. package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_0lt_3bw.js.map +1 -1
  188. package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_0uyh3yt.js +1 -1
  189. package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_0uyh3yt.js.map +1 -1
  190. package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_0v-a2ps.js +1 -1
  191. package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_0v-a2ps.js.map +1 -1
  192. package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_12.4r9~.js +1 -1
  193. package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_12.4r9~.js.map +1 -1
  194. package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_13mqkay.js +1 -1
  195. package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_13mqkay.js.map +1 -1
  196. package/.next/server/chunks/ssr/[root-of-the-server]__030vg4n._.js +4 -1
  197. package/.next/server/chunks/ssr/[root-of-the-server]__030vg4n._.js.map +1 -1
  198. package/.next/server/chunks/ssr/[root-of-the-server]__0nw~zhp._.js +1 -1
  199. package/.next/server/chunks/ssr/[root-of-the-server]__0nw~zhp._.js.map +1 -1
  200. package/.next/server/chunks/ssr/[root-of-the-server]__0sv~g.o._.js +1 -1
  201. package/.next/server/chunks/ssr/[root-of-the-server]__0sv~g.o._.js.map +1 -1
  202. package/.next/server/chunks/ssr/[root-of-the-server]__0u5aqkk._.js +1 -1
  203. package/.next/server/chunks/ssr/[root-of-the-server]__0u5aqkk._.js.map +1 -1
  204. package/.next/server/chunks/ssr/agent-network-dashboard_09kk21a._.js +4 -4
  205. package/.next/server/chunks/ssr/agent-network-dashboard_09kk21a._.js.map +1 -1
  206. package/.next/server/chunks/ssr/agent-network-dashboard_app_01jhlxz._.js +1 -1
  207. package/.next/server/chunks/ssr/agent-network-dashboard_app_01jhlxz._.js.map +1 -1
  208. package/.next/server/chunks/ssr/agent-network-dashboard_app_09d29my._.js +1 -1
  209. package/.next/server/chunks/ssr/agent-network-dashboard_app_09d29my._.js.map +1 -1
  210. package/.next/server/chunks/ssr/agent-network-dashboard_app_components_0mvyi-4._.js +1 -1
  211. package/.next/server/chunks/ssr/agent-network-dashboard_app_components_0mvyi-4._.js.map +1 -1
  212. package/.next/server/chunks/ssr/agent-network-dashboard_app_tasks_page_tsx_0mwxy4z._.js +1 -1
  213. package/.next/server/chunks/ssr/agent-network-dashboard_app_tasks_page_tsx_0mwxy4z._.js.map +1 -1
  214. package/.next/server/middleware-build-manifest.js +3 -3
  215. package/.next/server/middleware.js +2 -2
  216. package/.next/server/middleware.js.nft.json +1 -1
  217. package/.next/server/pages/404.html +3 -3
  218. package/.next/server/pages/500.html +1 -1
  219. package/.next/static/chunks/{07~8sx3_5uiox.js → 0csnc6nlttr5s.js} +4 -1
  220. package/.next/static/chunks/0grmy4z.ylqtd.css +2 -0
  221. package/.next/static/chunks/0k68tvhf0o-sb.js +1 -0
  222. package/.next/static/chunks/{0v4-5tng.uh.7.js → 0lc4e9o91uv.n.js} +2 -2
  223. package/.next/static/chunks/0prdn66k~zu45.js +1 -0
  224. package/.next/static/chunks/{0ph1in3421~o-.js → 0qvb.hq86qp2g.js} +1 -1
  225. package/.next/static/chunks/0wyjrc0bekhiz.js +1 -0
  226. package/.next/static/chunks/0~ykmap37nw9d.js +1 -0
  227. package/.next/static/chunks/17r9h6cx1w6q-.js +4 -0
  228. package/.next/trace +2 -2
  229. package/.next/trace-build +1 -1
  230. package/.next/types/routes.d.ts +2 -1
  231. package/.next/types/validator.ts +9 -0
  232. package/app/api/hub/send/route.ts +11 -2
  233. package/app/api/hub/servers/route.ts +3 -29
  234. package/app/api/hub/upload/route.ts +83 -0
  235. package/app/components/AppShell.tsx +4 -2
  236. package/app/components/CommandCenter.tsx +1 -1
  237. package/app/components/DispatchPanel.tsx +1 -1
  238. package/app/components/MobileNav.tsx +58 -0
  239. package/app/components/TaskChatPanel.tsx +209 -30
  240. package/app/components/TaskDrawer.tsx +1 -1
  241. package/app/components/TopoGraph.tsx +6686 -248
  242. package/app/globals.css +897 -7
  243. package/app/layout.tsx +8 -2
  244. package/app/lib/serverDedupe.ts +122 -0
  245. package/app/lib/vendorIdentity.ts +74 -56
  246. package/app/manifest.ts +23 -0
  247. package/app/nodes/page.tsx +21 -151
  248. package/package.json +4 -4
  249. package/public/vendors/claude.svg +7 -8
  250. package/public/vendors/minimax.svg +8 -9
  251. package/public/vendors/openai.svg +8 -10
  252. package/scripts/p157-rc2-dedup-test.mjs +110 -0
  253. package/scripts/topo-a11y-titles-catalog-test.mjs +132 -0
  254. package/scripts/topo-active-chrome-hover-text-test.mjs +107 -0
  255. package/scripts/topo-active-links-chip-halo-layers-test.mjs +81 -0
  256. package/scripts/topo-alias-chat-brightness-test.mjs +79 -0
  257. package/scripts/topo-alias-text-halo-layers-test.mjs +98 -0
  258. package/scripts/topo-animation-temporal-modes-catalog-test.mjs +144 -0
  259. package/scripts/topo-avatar-chat-gate-test.mjs +77 -0
  260. package/scripts/topo-avatar-drop-shadow-test.mjs +86 -0
  261. package/scripts/topo-avatar-fallback-hover-test.mjs +104 -0
  262. package/scripts/topo-avatar-fallback-rotate-test.mjs +92 -0
  263. package/scripts/topo-avatar-rotate-test.mjs +85 -0
  264. package/scripts/topo-avatar-scale-test.mjs +89 -0
  265. package/scripts/topo-badge-chat-gate-test.mjs +74 -0
  266. package/scripts/topo-brand-drop-shadow-test.mjs +71 -0
  267. package/scripts/topo-brand-logo-breath-test.mjs +102 -0
  268. package/scripts/topo-brand-logo-halo-layers-test.mjs +85 -0
  269. package/scripts/topo-brand-logo-hover-brightness-test.mjs +105 -0
  270. package/scripts/topo-brand-logo-hover-rotate-test.mjs +93 -0
  271. package/scripts/topo-brand-logo-hover-test.mjs +85 -0
  272. package/scripts/topo-canvas-desc-a11y-test.mjs +87 -0
  273. package/scripts/topo-canvas-entrance-animation-test.mjs +117 -0
  274. package/scripts/topo-canvas-scan-beam-diagonal-test.mjs +148 -0
  275. package/scripts/topo-canvas-scan-beam-test.mjs +109 -0
  276. package/scripts/topo-canvas-scan-beam-vertical-test.mjs +123 -0
  277. package/scripts/topo-card-chat-brightness-test.mjs +86 -0
  278. package/scripts/topo-chat-ring-breath-curve-test.mjs +114 -0
  279. package/scripts/topo-chat-ring-brightness-test.mjs +80 -0
  280. package/scripts/topo-chat-ring-halo-layers-test.mjs +100 -0
  281. package/scripts/topo-chat-ring-r-breath-test.mjs +121 -0
  282. package/scripts/topo-chat-ring-status-halo-test.mjs +106 -0
  283. package/scripts/topo-chat-ring-sw-breath-test.mjs +123 -0
  284. package/scripts/topo-chip-pin-halo-test.mjs +85 -0
  285. package/scripts/topo-chip-row-digit-ls-test.mjs +135 -0
  286. package/scripts/topo-chip-row-member-alias-lit-test.mjs +154 -0
  287. package/scripts/topo-chip-row-tier-glow-brightness-test.mjs +99 -0
  288. package/scripts/topo-chip-row-unit-hover-tracking-test.mjs +124 -0
  289. package/scripts/topo-chrome-control-halo-layers-test.mjs +22 -0
  290. package/scripts/topo-chrome-fullscreen-breath-test.mjs +121 -0
  291. package/scripts/topo-chrome-layout-trailer-breath-test.mjs +86 -0
  292. package/scripts/topo-chrome-nodesize-trailer-breath-test.mjs +86 -0
  293. package/scripts/topo-chrome-reset-breath-test.mjs +115 -0
  294. package/scripts/topo-chrome-strip-entrance-animation-test.mjs +115 -0
  295. package/scripts/topo-chrome-wrapper-halo-test.mjs +83 -0
  296. package/scripts/topo-chrome-zoom-wrapper-breath-test.mjs +85 -0
  297. package/scripts/topo-click-ripple-glow-test.mjs +86 -0
  298. package/scripts/topo-click-ripple-halo-layers-test.mjs +79 -0
  299. package/scripts/topo-click-ripple-sw-test.mjs +110 -0
  300. package/scripts/topo-cluster-count-attr-test.mjs +80 -0
  301. package/scripts/topo-crescent-breath-test.mjs +104 -0
  302. package/scripts/topo-crescent-envelope-breath-test.mjs +103 -0
  303. package/scripts/topo-crescent-recede-test.mjs +111 -0
  304. package/scripts/topo-dense-alias-chat-halo-test.mjs +73 -0
  305. package/scripts/topo-dense-alias-halo-layers-test.mjs +80 -0
  306. package/scripts/topo-dual-axis-surfaces-catalog-test.mjs +94 -0
  307. package/scripts/topo-edge-badge-circle-brightness-test.mjs +82 -0
  308. package/scripts/topo-edge-badge-circle-hot-pulse-test.mjs +100 -0
  309. package/scripts/topo-edge-badge-digit-halo-layers-test.mjs +107 -0
  310. package/scripts/topo-edge-badge-endpoint-gate-test.mjs +94 -0
  311. package/scripts/topo-edge-badge-halo-layers-test.mjs +85 -0
  312. package/scripts/topo-edge-badge-hot-pulse-test.mjs +92 -0
  313. package/scripts/topo-edge-badge-hover-glow-test.mjs +90 -0
  314. package/scripts/topo-edge-badge-text-brightness-test.mjs +83 -0
  315. package/scripts/topo-edge-chat-gate-test.mjs +71 -0
  316. package/scripts/topo-edge-flow-rail-halo-layers-test.mjs +89 -0
  317. package/scripts/topo-edge-particle-brightness-test.mjs +82 -0
  318. package/scripts/topo-edge-particle-halo-layers-test.mjs +91 -0
  319. package/scripts/topo-edge-pill-glow-test.mjs +67 -0
  320. package/scripts/topo-edge-pin-halo-test.mjs +99 -0
  321. package/scripts/topo-edge-visible-brightness-test.mjs +84 -0
  322. package/scripts/topo-edge-visible-halo-layers-test.mjs +87 -0
  323. package/scripts/topo-endpoint-ring-brightness-test.mjs +83 -0
  324. package/scripts/topo-endpoint-ring-flow-halo-test.mjs +107 -0
  325. package/scripts/topo-endpoint-ring-halo-layers-test.mjs +100 -0
  326. package/scripts/topo-filter-pill-glow-test.mjs +90 -0
  327. package/scripts/topo-filter-pill-halo-layers-test.mjs +27 -0
  328. package/scripts/topo-flow-arrow-brightness-test.mjs +82 -0
  329. package/scripts/topo-flow-rail-brightness-test.mjs +80 -0
  330. package/scripts/topo-fullscreen-attr-test.mjs +73 -0
  331. package/scripts/topo-fullscreen-brightness-test.mjs +84 -0
  332. package/scripts/topo-fullscreen-icon-rotate-test.mjs +93 -0
  333. package/scripts/topo-grid-content-bottom-attr-test.mjs +72 -0
  334. package/scripts/topo-group-box-brightness-test.mjs +84 -0
  335. package/scripts/topo-group-box-halo-layers-test.mjs +91 -0
  336. package/scripts/topo-group-chat-gate-test.mjs +77 -0
  337. package/scripts/topo-group-label-brightness-test.mjs +84 -0
  338. package/scripts/topo-group-label-halo-layers-test.mjs +78 -0
  339. package/scripts/topo-group-label-hover-glow-test.mjs +86 -0
  340. package/scripts/topo-group-label-member-alias-hover-test.mjs +125 -0
  341. package/scripts/topo-group-pill-glow-test.mjs +76 -0
  342. package/scripts/topo-group-tint-brightness-test.mjs +82 -0
  343. package/scripts/topo-h2-dual-axis-breath-test.mjs +92 -0
  344. package/scripts/topo-h2-triple-axis-breath-test.mjs +142 -0
  345. package/scripts/topo-halo-chat-gate-test.mjs +72 -0
  346. package/scripts/topo-hover-detail-halo-test.mjs +76 -0
  347. package/scripts/topo-hub-a11y-title-test.mjs +95 -0
  348. package/scripts/topo-hub-core-brightness-test.mjs +82 -0
  349. package/scripts/topo-hub-core-halo-layers-test.mjs +81 -0
  350. package/scripts/topo-hub-digit-brightness-test.mjs +79 -0
  351. package/scripts/topo-hub-digit-halo-layers-test.mjs +76 -0
  352. package/scripts/topo-hub-digit-ls-test.mjs +119 -0
  353. package/scripts/topo-hub-halo-brightness-test.mjs +80 -0
  354. package/scripts/topo-hub-halo-glow-test.mjs +96 -0
  355. package/scripts/topo-hub-halo-halo-layers-test.mjs +76 -0
  356. package/scripts/topo-hub-highlight-brightness-test.mjs +84 -0
  357. package/scripts/topo-hub-highlight-glow-test.mjs +99 -0
  358. package/scripts/topo-hub-highlight-halo-layers-test.mjs +78 -0
  359. package/scripts/topo-hub-highlight-r-test.mjs +112 -0
  360. package/scripts/topo-hub-hover-ring-brightness-test.mjs +79 -0
  361. package/scripts/topo-hub-hover-ring-glow-test.mjs +97 -0
  362. package/scripts/topo-hub-hover-ring-halo-layers-test.mjs +71 -0
  363. package/scripts/topo-hub-spoke-brightness-test.mjs +77 -0
  364. package/scripts/topo-hub-spoke-glow-test.mjs +112 -0
  365. package/scripts/topo-hub-spoke-halo-layers-test.mjs +97 -0
  366. package/scripts/topo-hub-spoke-self-filter-test.mjs +119 -0
  367. package/scripts/topo-kicker-breath-test.mjs +100 -0
  368. package/scripts/topo-kicker-dual-axis-breath-test.mjs +81 -0
  369. package/scripts/topo-kicker-halo-layers-test.mjs +82 -0
  370. package/scripts/topo-kicker-triple-axis-breath-test.mjs +124 -0
  371. package/scripts/topo-label-card-brightness-test.mjs +81 -0
  372. package/scripts/topo-layout-hover-fw-test.mjs +98 -0
  373. package/scripts/topo-layout-toggle-brightness-test.mjs +94 -0
  374. package/scripts/topo-layout-toggle-halo-layers-test.mjs +95 -0
  375. package/scripts/topo-legend-count-brightness-test.mjs +80 -0
  376. package/scripts/topo-legend-count-halo-layers-test.mjs +79 -0
  377. package/scripts/topo-legend-count-letter-spacing-test.mjs +108 -0
  378. package/scripts/topo-legend-label-fw-test.mjs +107 -0
  379. package/scripts/topo-legend-panel-title-breath-test.mjs +86 -0
  380. package/scripts/topo-legend-pin-ring-brightness-test.mjs +82 -0
  381. package/scripts/topo-legend-pin-ring-halo-layers-test.mjs +71 -0
  382. package/scripts/topo-legend-row-count-brightness-test.mjs +85 -0
  383. package/scripts/topo-legend-row-label-glow-test.mjs +102 -0
  384. package/scripts/topo-legend-swatch-glow-test.mjs +109 -0
  385. package/scripts/topo-legend-swatch-member-alias-match-test.mjs +139 -0
  386. package/scripts/topo-legend-tint-brightness-test.mjs +83 -0
  387. package/scripts/topo-legend-trio-halo-layers-test.mjs +22 -0
  388. package/scripts/topo-live-lanes.mjs +48 -0
  389. package/scripts/topo-minimap-container-halo-test.mjs +82 -0
  390. package/scripts/topo-minimap-dot-chat-gate-test.mjs +81 -0
  391. package/scripts/topo-minimap-hover-glow-test.mjs +109 -0
  392. package/scripts/topo-minimap-viewport-brightness-test.mjs +84 -0
  393. package/scripts/topo-minimap-viewport-halo-layers-test.mjs +24 -0
  394. package/scripts/topo-more-footer-brightness-test.mjs +94 -0
  395. package/scripts/topo-node-alias-brightness-test.mjs +84 -0
  396. package/scripts/topo-node-avatar-halo-layers-test.mjs +25 -0
  397. package/scripts/topo-node-hover-ring-halo-layers-test.mjs +70 -0
  398. package/scripts/topo-node-label-card-halo-test.mjs +76 -0
  399. package/scripts/topo-node-sub-text-brightness-test.mjs +88 -0
  400. package/scripts/topo-nodesize-brightness-test.mjs +82 -0
  401. package/scripts/topo-nodesize-halo-layers-test.mjs +89 -0
  402. package/scripts/topo-nodesize-hover-fw-test.mjs +99 -0
  403. package/scripts/topo-orphan-label-opacity-test.mjs +98 -0
  404. package/scripts/topo-overlap-test.mjs +22 -8
  405. package/scripts/topo-panel-count-halo-layers-test.mjs +91 -0
  406. package/scripts/topo-panel-count-hover-ls-test.mjs +87 -0
  407. package/scripts/topo-panel-rect-halo-test.mjs +90 -0
  408. package/scripts/topo-panel-row-brightness-test.mjs +116 -0
  409. package/scripts/topo-panel-title-brightness-test.mjs +98 -0
  410. package/scripts/topo-panel-title-glow-test.mjs +111 -0
  411. package/scripts/topo-panel-titles-dual-axis-breath-test.mjs +94 -0
  412. package/scripts/topo-panel-titles-halo-layers-test.mjs +23 -0
  413. package/scripts/topo-panel-titles-triple-axis-breath-test.mjs +161 -0
  414. package/scripts/topo-pill-x-rotate-test.mjs +96 -0
  415. package/scripts/topo-pip-brightness-test.mjs +85 -0
  416. package/scripts/topo-pressure-bar-halo-layers-test.mjs +19 -0
  417. package/scripts/topo-pressure-seg-glow-test.mjs +92 -0
  418. package/scripts/topo-pressure-seg-member-alias-match-test.mjs +133 -0
  419. package/scripts/topo-pressure-seg-motion-test.mjs +101 -0
  420. package/scripts/topo-r717-scan-beam-pair-pattern-test.mjs +100 -0
  421. package/scripts/topo-r717-triple-axis-pair-pattern-test.mjs +113 -0
  422. package/scripts/topo-r717-triple-axis-tier-pattern-test.mjs +117 -0
  423. package/scripts/topo-recent-count-brightness-test.mjs +84 -0
  424. package/scripts/topo-recent-more-fw-test.mjs +126 -0
  425. package/scripts/topo-recent-more-halo-layers-test.mjs +90 -0
  426. package/scripts/topo-recent-panel-hot-pulse-test.mjs +105 -0
  427. package/scripts/topo-recent-panel-title-breath-test.mjs +91 -0
  428. package/scripts/topo-recent-pip-halo-layers-test.mjs +82 -0
  429. package/scripts/topo-recent-row-chat-gate-test.mjs +75 -0
  430. package/scripts/topo-recent-row-content-lift-test.mjs +140 -0
  431. package/scripts/topo-recent-row-fw-test.mjs +115 -0
  432. package/scripts/topo-recent-row-text-glow-test.mjs +86 -0
  433. package/scripts/topo-recent-row-text-halo-layers-test.mjs +67 -0
  434. package/scripts/topo-recent-tint-brightness-test.mjs +80 -0
  435. package/scripts/topo-recent-ts-brightness-test.mjs +86 -0
  436. package/scripts/topo-reduced-motion-attr-test.mjs +69 -0
  437. package/scripts/topo-reset-brightness-test.mjs +83 -0
  438. package/scripts/topo-reset-icon-hover-scale-test.mjs +102 -0
  439. package/scripts/topo-respiratory-axis-count-stats-test.mjs +154 -0
  440. package/scripts/topo-respiratory-patterns-catalog-test.mjs +112 -0
  441. package/scripts/topo-respiratory-rolodex-test.mjs +83 -0
  442. package/scripts/topo-respiratory-tiers-catalog-test.mjs +119 -0
  443. package/scripts/topo-respiratory-triple-axis-surfaces-catalog-test.mjs +127 -0
  444. package/scripts/topo-runtime-badge-brightness-test.mjs +78 -0
  445. package/scripts/topo-runtime-badge-glow-test.mjs +108 -0
  446. package/scripts/topo-runtime-badge-halo-layers-test.mjs +87 -0
  447. package/scripts/topo-runtime-badge-rotate-test.mjs +85 -0
  448. package/scripts/topo-section-title-breath-test.mjs +83 -0
  449. package/scripts/topo-section-title-halo-layers-test.mjs +88 -0
  450. package/scripts/topo-spoke-chat-gate-test.mjs +72 -0
  451. package/scripts/topo-starfield-hue-test.mjs +109 -0
  452. package/scripts/topo-status-pin-pill-halo-layers-test.mjs +17 -0
  453. package/scripts/topo-status-ring-brightness-test.mjs +84 -0
  454. package/scripts/topo-status-ring-chat-gate-test.mjs +72 -0
  455. package/scripts/topo-status-ring-halo-layers-test.mjs +105 -0
  456. package/scripts/topo-status-ring-status-halo-test.mjs +110 -0
  457. package/scripts/topo-sub-text-chat-brightness-test.mjs +81 -0
  458. package/scripts/topo-svg-title-a11y-r731-test.mjs +93 -0
  459. package/scripts/topo-svg-title-a11y-test.mjs +88 -0
  460. package/scripts/topo-title-block-entrance-animation-test.mjs +127 -0
  461. package/scripts/topo-title-block-envelope-breath-test.mjs +87 -0
  462. package/scripts/topo-titleblock-h2-hover-fw-test.mjs +109 -0
  463. package/scripts/topo-titleblock-h2-hover-tracking-test.mjs +128 -0
  464. package/scripts/topo-titleblock-kicker-hover-test.mjs +134 -0
  465. package/scripts/topo-tree-diag.mjs +95 -0
  466. package/scripts/topo-vendor-chip-glow-test.mjs +97 -0
  467. package/scripts/topo-vendor-chip-halo-layers-test.mjs +18 -0
  468. package/scripts/topo-vendor-chip-pin-halo-test.mjs +88 -0
  469. package/scripts/topo-vendor-count-suffix-halo-layers-test.mjs +79 -0
  470. package/scripts/topo-vendor-distribution-wrapper-halo-test.mjs +93 -0
  471. package/scripts/topo-vendor-letter-halo-layers-test.mjs +93 -0
  472. package/scripts/topo-vendor-pill-glow-test.mjs +98 -0
  473. package/scripts/topo-watermark-breath-test.mjs +100 -0
  474. package/scripts/topo-watermark-dual-axis-breath-test.mjs +88 -0
  475. package/scripts/topo-watermark-envelope-breath-test.mjs +88 -0
  476. package/scripts/topo-watermark-recede-test.mjs +114 -0
  477. package/scripts/topo-watermark-triple-axis-breath-test.mjs +129 -0
  478. package/scripts/topo-working-online-chip-halo-layers-test.mjs +94 -0
  479. package/scripts/topo-zoom-buttons-brightness-test.mjs +94 -0
  480. package/scripts/topo-zoom-in-out-halo-layers-test.mjs +97 -0
  481. package/scripts/topo-zoom-level-breath-test.mjs +87 -0
  482. package/scripts/topo-zoom-level-brightness-test.mjs +83 -0
  483. package/scripts/topo-zoom-level-color-test.mjs +105 -0
  484. package/scripts/topo-zoom-level-dual-axis-breath-test.mjs +83 -0
  485. package/scripts/topo-zoom-level-halo-layers-test.mjs +78 -0
  486. package/scripts/topo-zoom-level-triple-axis-breath-test.mjs +148 -0
  487. package/.next/static/chunks/01lmbsd37fybu.js +0 -1
  488. package/.next/static/chunks/03o.h6kvmw4l_.js +0 -1
  489. package/.next/static/chunks/0fuba20p57-zo.js +0 -1
  490. package/.next/static/chunks/0m.1mvl~t.avc.css +0 -2
  491. package/.next/static/chunks/10cj-86disers.js +0 -1
  492. package/.next/static/chunks/158h2g7f-nxbt.js +0 -4
  493. /package/.next/server/chunks/{[externals]__11vad82._.js.map → 0ykm__next-internal_server_app_api_hub_upload_route_actions_03_eqnf.js.map} +0 -0
  494. /package/.next/static/{tQ1EtcEiS7ikgAoAyZWm7 → 7CjN6e7QM2eogH8RhsM1k}/_buildManifest.js +0 -0
  495. /package/.next/static/{tQ1EtcEiS7ikgAoAyZWm7 → 7CjN6e7QM2eogH8RhsM1k}/_clientMiddlewareManifest.js +0 -0
  496. /package/.next/static/{tQ1EtcEiS7ikgAoAyZWm7 → 7CjN6e7QM2eogH8RhsM1k}/_ssgManifest.js +0 -0
@@ -0,0 +1,97 @@
1
+ /* Round 654 — hub-spoke drop-shadow gains a SECOND outer layer at
2
+ * 3px + 0.2 alpha. CLOSES hub-cluster glow QUINTET at 5/5 multi-
3
+ * layer (R533 was the last single-layer hub element after R650-R653).
4
+ *
5
+ * Test phases:
6
+ * 1. mock 2 nodes → hub-spokes render (one per non-hub node)
7
+ * 2. rest: all spokes halo-layers='0', no drop-shadow filter
8
+ * 3. open chat with a·1 → R636 isHoveredSpoke fires → that spoke
9
+ * gets halo-layers='2', computed filter has 2 drop-shadow
10
+ * substrings with teal/cyan tint (rgba(34,211,238,...) on cyber)
11
+ * 4. source: both light + cyber branches stack 2 drop-shadows
12
+ */
13
+ import { chromium } from 'playwright';
14
+ import { readFileSync } from 'node:fs';
15
+
16
+ const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
17
+ const fresh = new Date(Date.now() - 60 * 1000).toISOString();
18
+
19
+ const browser = await chromium.launch({ headless: true });
20
+ const ctx = await browser.newContext({ viewport: { width: 1500, height: 1200 } });
21
+ await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
22
+ await ctx.addInitScript(() => {
23
+ try {
24
+ localStorage.setItem('anet-theme', 'cyber');
25
+ localStorage.setItem('anet-topo-layout', 'ring');
26
+ sessionStorage.setItem('anet_v3_auth', '1');
27
+ } catch {}
28
+ });
29
+ await ctx.route('**/api/hub/status*', async (route) => {
30
+ const r = await route.fetch();
31
+ const b = await r.json();
32
+ const nid = (b.sessions || [])[0]?.network_id || 'default';
33
+ const mk = (alias) => ({
34
+ alias, status: 'idle', model: 'claude-opus-4', runtime: 'claude-code-cli',
35
+ network_id: nid, project_dir: null,
36
+ created_at: fresh, updated_at: fresh, last_seen_at: fresh,
37
+ });
38
+ await route.fulfill({ response: r, json: { ...b, sessions: [mk('a·1'), mk('a·2')] } });
39
+ });
40
+ await ctx.route('**/api/hub/messages*', (r) => r.fulfill({ json: { messages: [] } }));
41
+ await ctx.route('**/api/hub/tasks*', (r) => r.fulfill({ json: { tasks: [] } }));
42
+ const page = await ctx.newPage();
43
+ await page.goto('http://127.0.0.1:3000/', { waitUntil: 'networkidle' });
44
+ await page.waitForSelector('[data-topo-hub-spoke-halo-layers]', { timeout: 15000, state: 'attached' });
45
+ await page.waitForTimeout(500);
46
+
47
+ const restSpokes = await page.evaluate(() => {
48
+ return Array.from(document.querySelectorAll('[data-topo-hub-spoke-halo-layers]')).map(el => ({
49
+ layers: el.getAttribute('data-topo-hub-spoke-halo-layers'),
50
+ glow: el.getAttribute('data-topo-hub-spoke-glow'),
51
+ }));
52
+ });
53
+
54
+ // Open chat to fire isHoveredSpoke on a·1's spoke
55
+ await page.click('[data-node="a·1"]', { force: true });
56
+ await page.waitForTimeout(400);
57
+
58
+ const activeState = await page.evaluate(() => {
59
+ return Array.from(document.querySelectorAll('[data-topo-hub-spoke-halo-layers]')).map(el => {
60
+ const cs = getComputedStyle(el);
61
+ return {
62
+ layers: el.getAttribute('data-topo-hub-spoke-halo-layers'),
63
+ glow: el.getAttribute('data-topo-hub-spoke-glow'),
64
+ self: el.getAttribute('data-topo-hub-spoke-brightness-self'),
65
+ filter: cs.filter,
66
+ };
67
+ });
68
+ });
69
+
70
+ await browser.close();
71
+
72
+ const src = readFileSync('/home/vansin/agent-network-dashboard/app/components/TopoGraph.tsx', 'utf8');
73
+ const sourceLight = /'drop-shadow\(0 0 1\.5px rgba\(13, 148, 136, 0\.4\)\) drop-shadow\(0 0 3px rgba\(13, 148, 136, 0\.2\)\) brightness\(1\.15\)'/.test(src);
74
+ const sourceCyber = /'drop-shadow\(0 0 1\.5px rgba\(34, 211, 238, 0\.4\)\) drop-shadow\(0 0 3px rgba\(34, 211, 238, 0\.2\)\) brightness\(1\.15\)'/.test(src);
75
+ const sourceLayersAttr = /data-topo-hub-spoke-halo-layers=\{!reducedMotion && \(hoveredHub \|\| isHoveredSpoke\) \? '2' : '0'\}/.test(src);
76
+
77
+ const restAllZero = restSpokes.every(s => s.layers === '0' && s.glow === 'false');
78
+ const activeSpokes = activeState.filter(s => s.self === 'true');
79
+ const activeAllTwoLayers = activeSpokes.length >= 1
80
+ && activeSpokes.every(s => s.layers === '2'
81
+ && (s.filter?.match(/drop-shadow/g) || []).length === 2);
82
+
83
+ const results = {
84
+ spokes_present: restSpokes.length >= 2,
85
+ rest_all_zero: restAllZero,
86
+ active_exactly_one: activeSpokes.length === 1,
87
+ active_all_two_layers:activeAllTwoLayers,
88
+ source_light: sourceLight,
89
+ source_cyber: sourceCyber,
90
+ source_layers_attr: sourceLayersAttr,
91
+ };
92
+ const ok = Object.values(results).every(Boolean);
93
+ console.log(`${ok ? '✅' : '❌'} R654 hub-spoke multi-layer halo (CLOSES hub-cluster glow QUINTET at 5/5):`,
94
+ JSON.stringify(results, null, 2),
95
+ `\n rest: ${JSON.stringify(restSpokes)}`,
96
+ `\n active: ${JSON.stringify(activeState)}`);
97
+ process.exit(ok ? 0 : 1);
@@ -0,0 +1,119 @@
1
+ /* Round 636 — extend hub-spoke filter gate from hub-wide
2
+ * (hoveredHub) to per-spoke (isHoveredSpoke). Closes the 4-axis
3
+ * chat-target focus signature on the hub-spoke surface:
4
+ * R622 opacity 0.50 → 0.70 / 0.80 → 0.95 (per-spoke)
5
+ * R622 stroke-wd 1.00 → 1.25 / 2.25 → 2.50 (per-spoke)
6
+ * R580 drop-shadow halo (hub-wide only — pre-R636)
7
+ * R580 brightness 1.0 → 1.15 (hub-wide only — pre-R636)
8
+ * R636 drop-shadow + brightness ALSO on isHoveredSpoke (per-spoke)
9
+ *
10
+ * Test phases:
11
+ * 1. mock 2 nodes → spokes present, no hover/chat
12
+ * 2. rest: per-spoke brightness-self='false', brightness='1',
13
+ * glow='false'
14
+ * 3. open chat with one node (click) → that node's spoke
15
+ * brightness-self='true', brightness='1.15', glow='true';
16
+ * OTHER spoke stays brightness-self='false', brightness='1'
17
+ * 4. source: filter expression + attrs include
18
+ * (hoveredHub || isHoveredSpoke) OR-chain
19
+ */
20
+ import { chromium } from 'playwright';
21
+ import { readFileSync } from 'node:fs';
22
+
23
+ const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
24
+ const fresh = new Date(Date.now() - 60 * 1000).toISOString();
25
+
26
+ const browser = await chromium.launch({ headless: true });
27
+ const ctx = await browser.newContext({ viewport: { width: 1500, height: 1200 } });
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
+ localStorage.setItem('anet-topo-layout', 'ring');
33
+ sessionStorage.setItem('anet_v3_auth', '1');
34
+ } catch {}
35
+ });
36
+ await ctx.route('**/api/hub/status*', async (route) => {
37
+ const r = await route.fetch();
38
+ const b = await r.json();
39
+ const nid = (b.sessions || [])[0]?.network_id || 'default';
40
+ const mk = (alias) => ({
41
+ alias, status: 'idle', model: 'claude-opus-4', runtime: 'claude-code-cli',
42
+ network_id: nid, project_dir: null,
43
+ created_at: fresh, updated_at: fresh, last_seen_at: fresh,
44
+ });
45
+ await route.fulfill({ response: r, json: { ...b, sessions: [mk('a·1'), mk('a·2')] } });
46
+ });
47
+ await ctx.route('**/api/hub/messages*', (r) => r.fulfill({ json: { messages: [] } }));
48
+ await ctx.route('**/api/hub/tasks*', (r) => r.fulfill({ json: { tasks: [] } }));
49
+ const page = await ctx.newPage();
50
+ await page.goto('http://127.0.0.1:3000/', { waitUntil: 'networkidle' });
51
+ await page.waitForSelector('[data-topo-hub-spoke-brightness-self]', { timeout: 15000, state: 'attached' });
52
+ await page.waitForTimeout(500);
53
+
54
+ const restPerSpoke = await page.evaluate(() => {
55
+ const spokes = Array.from(document.querySelectorAll('[data-topo-hub-spoke-brightness-self]'));
56
+ return spokes.map(el => ({
57
+ self: el.getAttribute('data-topo-hub-spoke-brightness-self'),
58
+ brightness: el.getAttribute('data-topo-hub-spoke-brightness'),
59
+ glow: el.getAttribute('data-topo-hub-spoke-glow'),
60
+ }));
61
+ });
62
+
63
+ // Open chat with a·1
64
+ await page.click('[data-node="a·1"]', { force: true });
65
+ await page.waitForTimeout(400);
66
+
67
+ const chatPerSpoke = await page.evaluate(() => {
68
+ // Each spoke is paired with its node alias via path key (`hub-${alias}`)
69
+ // — but key isn't queryable. We look at all spokes and find the one
70
+ // whose brightness-self attr is now 'true'.
71
+ const spokes = Array.from(document.querySelectorAll('[data-topo-hub-spoke-brightness-self]'));
72
+ return spokes.map(el => ({
73
+ self: el.getAttribute('data-topo-hub-spoke-brightness-self'),
74
+ brightness: el.getAttribute('data-topo-hub-spoke-brightness'),
75
+ glow: el.getAttribute('data-topo-hub-spoke-glow'),
76
+ }));
77
+ });
78
+
79
+ await browser.close();
80
+
81
+ const src = readFileSync('/home/vansin/agent-network-dashboard/app/components/TopoGraph.tsx', 'utf8');
82
+ const sourceFilterGate = /filter: !reducedMotion && \(hoveredHub \|\| isHoveredSpoke\)\s*\n\s*\?\s*\(isLight/.test(src);
83
+ const sourceBrightnessAttr = /data-topo-hub-spoke-brightness=\{!reducedMotion && \(hoveredHub \|\| isHoveredSpoke\) \? '1\.15' : '1'\}/.test(src);
84
+ const sourceSelfAttr = /data-topo-hub-spoke-brightness-self=\{!reducedMotion && isHoveredSpoke \? 'true' : 'false'\}/.test(src);
85
+ const sourceGlowGate = /data-topo-hub-spoke-glow=\{!reducedMotion && \(hoveredHub \|\| isHoveredSpoke\) \? 'true' : 'false'\}/.test(src);
86
+
87
+ const restAllSelfFalse = restPerSpoke.every(s => s.self === 'false');
88
+ const restAllBrightness1 = restPerSpoke.every(s => s.brightness === '1');
89
+ const restAllGlowFalse = restPerSpoke.every(s => s.glow === 'false');
90
+
91
+ const chatActiveSpokes = chatPerSpoke.filter(s => s.self === 'true');
92
+ const chatIdleSpokes = chatPerSpoke.filter(s => s.self === 'false');
93
+ const chatExactlyOneActive = chatActiveSpokes.length === 1;
94
+ const chatActiveBrightness115 = chatActiveSpokes.every(s => s.brightness === '1.15');
95
+ const chatActiveGlowTrue = chatActiveSpokes.every(s => s.glow === 'true');
96
+ const chatIdleBrightness1 = chatIdleSpokes.every(s => s.brightness === '1');
97
+ const chatIdleGlowFalse = chatIdleSpokes.every(s => s.glow === 'false');
98
+
99
+ const results = {
100
+ spokes_present: restPerSpoke.length >= 2,
101
+ rest_all_self_false: restAllSelfFalse,
102
+ rest_all_brightness_1: restAllBrightness1,
103
+ rest_all_glow_false: restAllGlowFalse,
104
+ chat_exactly_one_active: chatExactlyOneActive,
105
+ chat_active_brightness: chatActiveBrightness115,
106
+ chat_active_glow: chatActiveGlowTrue,
107
+ chat_idle_brightness: chatIdleBrightness1,
108
+ chat_idle_glow_false: chatIdleGlowFalse,
109
+ source_filter_gate: sourceFilterGate,
110
+ source_brightness_attr: sourceBrightnessAttr,
111
+ source_self_attr: sourceSelfAttr,
112
+ source_glow_gate: sourceGlowGate,
113
+ };
114
+ const ok = Object.values(results).every(Boolean);
115
+ console.log(`${ok ? '✅' : '❌'} R636 hub-spoke per-spoke filter (chat-target / hover-self gate):`,
116
+ JSON.stringify(results, null, 2),
117
+ `\n rest: ${JSON.stringify(restPerSpoke)}`,
118
+ `\n chat: ${JSON.stringify(chatPerSpoke)}`);
119
+ process.exit(ok ? 0 : 1);
@@ -0,0 +1,100 @@
1
+ /* Round 699 — kicker "Network Topology" gains at-rest breathing fade.
2
+ * Pre-R699 the kicker eyebrow sat at fixed alpha (text-gray-500 token)
3
+ * — static, no sign of life. R699 adds a 6s opacity 0.78↔1 cycle via
4
+ * `.anet-topo-kicker-breath` (globals.css). Pure opacity → geometry
5
+ * stable → topo-overlap-test unaffected.
6
+ *
7
+ * Source assertions:
8
+ * - globals.css @keyframes anet-topo-kicker-breath-kf with 0/100% 1, 50% 0.78
9
+ * - globals.css .anet-topo-kicker-breath rule with 6s ease-in-out infinite
10
+ * - globals.css prefers-reduced-motion guard: animation: none
11
+ * - TopoGraph.tsx kicker element has class anet-topo-kicker-breath
12
+ * - TopoGraph.tsx kicker element has data-topo-section-kicker-breath="6s"
13
+ *
14
+ * Runtime assertions:
15
+ * - kicker element present
16
+ * - kicker has anet-topo-kicker-breath class
17
+ * - computed animation-name reflects the keyframe (or 'none' under reduced-motion)
18
+ * - computed animation-duration is 6s
19
+ */
20
+ import { chromium } from 'playwright';
21
+ import { readFileSync } from 'node:fs';
22
+
23
+ const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
24
+ const fresh = new Date(Date.now() - 60 * 1000).toISOString();
25
+
26
+ const browser = await chromium.launch({ headless: true });
27
+ const ctx = await browser.newContext({ viewport: { width: 1500, height: 1200 } });
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
+ localStorage.setItem('anet-topo-layout', 'ring');
33
+ sessionStorage.setItem('anet_v3_auth', '1');
34
+ } catch {}
35
+ });
36
+ await ctx.route('**/api/hub/status*', async (route) => {
37
+ const r = await route.fetch();
38
+ const b = await r.json();
39
+ const nid = (b.sessions || [])[0]?.network_id || 'default';
40
+ const mk = (alias) => ({
41
+ alias, status: 'idle', model: 'claude-opus-4', runtime: 'claude-code-cli',
42
+ network_id: nid, project_dir: null,
43
+ created_at: fresh, updated_at: fresh, last_seen_at: fresh,
44
+ });
45
+ await route.fulfill({ response: r, json: { ...b, sessions: [mk('a·1'), mk('a·2')] } });
46
+ });
47
+ await ctx.route('**/api/hub/messages*', (r) => r.fulfill({ json: { messages: [] } }));
48
+ await ctx.route('**/api/hub/tasks*', (r) => r.fulfill({ json: { tasks: [] } }));
49
+ const page = await ctx.newPage();
50
+ await page.goto('http://127.0.0.1:3000/', { waitUntil: 'networkidle' });
51
+ await page.waitForSelector('[data-topo-section-kicker]', { timeout: 15000, state: 'attached' });
52
+ await page.waitForTimeout(300);
53
+
54
+ const runtimeState = await page.evaluate(() => {
55
+ const k = document.querySelector('[data-topo-section-kicker]');
56
+ if (!k) return null;
57
+ const cs = getComputedStyle(k);
58
+ return {
59
+ has_class: k.classList.contains('anet-topo-kicker-breath'),
60
+ breath_attr: k.getAttribute('data-topo-section-kicker-breath'),
61
+ anim_name: cs.animationName,
62
+ anim_duration: cs.animationDuration,
63
+ anim_iter: cs.animationIterationCount,
64
+ };
65
+ });
66
+
67
+ await browser.close();
68
+
69
+ const cssSrc = readFileSync('/home/vansin/agent-network-dashboard/app/globals.css', 'utf8');
70
+ const tsxSrc = readFileSync('/home/vansin/agent-network-dashboard/app/components/TopoGraph.tsx', 'utf8');
71
+
72
+ const cssKeyframes = /@keyframes anet-topo-kicker-breath-kf\s*\{[\s\S]*?0%, 100%\s*\{\s*opacity:\s*1;\s*\}[\s\S]*?50%\s*\{\s*opacity:\s*0\.78;/.test(cssSrc);
73
+ const cssRule = /\.anet-topo-kicker-breath\s*\{[\s\S]*?animation:\s*anet-topo-kicker-breath-kf\s+6s\s+ease-in-out\s+infinite/.test(cssSrc);
74
+ const cssReducedMotion = /prefers-reduced-motion:\s*reduce\s*\)\s*\{\s*\.anet-topo-kicker-breath\s*\{\s*animation:\s*none/.test(cssSrc);
75
+ const tsxClass = /anet-topo-kicker-breath text-xs uppercase/.test(tsxSrc);
76
+ const tsxAttr = /data-topo-section-kicker-breath="6s"/.test(tsxSrc);
77
+
78
+ // Runtime animation may be 'none' under prefers-reduced-motion. In default
79
+ // headless playwright, motion is allowed by default, so the keyframe should
80
+ // be active (anim_name === 'anet-topo-kicker-breath-kf').
81
+ const runtimeAnim = runtimeState?.anim_name === 'anet-topo-kicker-breath-kf' || runtimeState?.anim_name === 'none';
82
+ const runtimeDuration = runtimeState?.anim_duration === '6s' || runtimeState?.anim_name === 'none';
83
+
84
+ const results = {
85
+ kicker_present: !!runtimeState,
86
+ has_breath_class: runtimeState?.has_class === true,
87
+ breath_attr_6s: runtimeState?.breath_attr === '6s',
88
+ runtime_anim_ok: runtimeAnim,
89
+ runtime_duration_ok: runtimeDuration,
90
+ css_keyframes: cssKeyframes,
91
+ css_rule: cssRule,
92
+ css_reduced_motion: cssReducedMotion,
93
+ tsx_class: tsxClass,
94
+ tsx_breath_attr: tsxAttr,
95
+ };
96
+ const ok = Object.values(results).every(Boolean);
97
+ console.log(`${ok ? '✅' : '❌'} R699 kicker at-rest breathing fade (3rd respiratory rhythm — 6s eyebrow):`,
98
+ JSON.stringify(results, null, 2),
99
+ `\n runtime: ${JSON.stringify(runtimeState)}`);
100
+ process.exit(ok ? 0 : 1);
@@ -0,0 +1,81 @@
1
+ /* Round 714 — kicker dual-axis breath. R699 introduced 6s opacity
2
+ * breath; R714 adds CSS transform scale 0.995↔1 axis in the same
3
+ * @keyframes block, in phase. Mirror to R711 H2 dual-axis at the
4
+ * title-block eyebrow tier. Closes title-block dual-axis symmetry
5
+ * across kicker (R699+R714) and H2 (R702+R711).
6
+ */
7
+ import { chromium } from 'playwright';
8
+ import { readFileSync } from 'node:fs';
9
+
10
+ const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
11
+ const fresh = new Date(Date.now() - 60 * 1000).toISOString();
12
+
13
+ const browser = await chromium.launch({ headless: true });
14
+ const ctx = await browser.newContext({ viewport: { width: 1500, height: 1200 } });
15
+ await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
16
+ await ctx.addInitScript(() => {
17
+ try {
18
+ localStorage.setItem('anet-theme', 'cyber');
19
+ localStorage.setItem('anet-topo-layout', 'ring');
20
+ sessionStorage.setItem('anet_v3_auth', '1');
21
+ } 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: 'claude-code-cli',
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('a·1'), mk('a·2')] } });
33
+ });
34
+ await ctx.route('**/api/hub/messages*', (r) => r.fulfill({ json: { messages: [] } }));
35
+ await ctx.route('**/api/hub/tasks*', (r) => r.fulfill({ json: { tasks: [] } }));
36
+ const page = await ctx.newPage();
37
+ await page.goto('http://127.0.0.1:3000/', { waitUntil: 'networkidle' });
38
+ await page.waitForSelector('[data-topo-section-kicker]', { timeout: 15000, state: 'attached' });
39
+ await page.waitForTimeout(300);
40
+
41
+ const runtimeState = await page.evaluate(() => {
42
+ const k = document.querySelector('[data-topo-section-kicker]');
43
+ if (!k) return null;
44
+ const cs = getComputedStyle(k);
45
+ return {
46
+ has_class: k.classList.contains('anet-topo-kicker-breath'),
47
+ breath_attr: k.getAttribute('data-topo-section-kicker-breath'),
48
+ anim_name: cs.animationName,
49
+ anim_duration: cs.animationDuration,
50
+ };
51
+ });
52
+
53
+ await browser.close();
54
+
55
+ const cssSrc = readFileSync('/home/vansin/agent-network-dashboard/app/globals.css', 'utf8');
56
+
57
+ // R699 opacity axis preserved
58
+ const cssR699Opacity = /@keyframes anet-topo-kicker-breath-kf\s*\{[\s\S]*?0%, 100%\s*\{[\s\S]*?opacity:\s*1[\s\S]*?\}[\s\S]*?50%\s*\{[\s\S]*?opacity:\s*0\.78/.test(cssSrc);
59
+ const cssR699Class = /\.anet-topo-kicker-breath\s*\{[\s\S]*?animation:\s*anet-topo-kicker-breath-kf\s+6s\s+ease-in-out\s+infinite/.test(cssSrc);
60
+
61
+ // R714 scale axis added
62
+ const cssR714ScaleNorm = /@keyframes anet-topo-kicker-breath-kf\s*\{[\s\S]*?0%, 100%\s*\{[\s\S]*?transform:\s*scale\(1\)/.test(cssSrc);
63
+ const cssR714ScaleMid = /50%\s*\{[\s\S]*?transform:\s*scale\(0\.995\)/.test(cssSrc);
64
+
65
+ const runtimeAnim = runtimeState?.anim_name === 'anet-topo-kicker-breath-kf' || runtimeState?.anim_name === 'none';
66
+
67
+ const results = {
68
+ kicker_present: !!runtimeState,
69
+ has_breath_class: runtimeState?.has_class === true,
70
+ breath_attr_6s_preserved: runtimeState?.breath_attr === '6s',
71
+ runtime_anim_ok: runtimeAnim,
72
+ css_r699_opacity_kept: cssR699Opacity,
73
+ css_r699_class_kept: cssR699Class,
74
+ css_r714_scale_norm: cssR714ScaleNorm,
75
+ css_r714_scale_mid: cssR714ScaleMid,
76
+ };
77
+ const ok = Object.values(results).every(Boolean);
78
+ console.log(`${ok ? '✅' : '❌'} R714 kicker dual-axis breath (opacity + transform scale on shared 6s @keyframes — title-block dual-axis symmetry closed):`,
79
+ JSON.stringify(results, null, 2),
80
+ `\n runtime: ${JSON.stringify(runtimeState)}`);
81
+ process.exit(ok ? 0 : 1);
@@ -0,0 +1,82 @@
1
+ /* Round 685 — kicker "Network Topology" extends from 2 hover axes
2
+ * (R555 tracking-spread + color lift) to also include multi-layer
3
+ * halo paint axis. Closes title-block trio 3/3 (logo R683 + H2 R684
4
+ * + kicker R685). CSS descendant rule targets the kicker via data
5
+ * attr; 2+4px stride at currentColor (kicker scale = text-xs 12px).
6
+ *
7
+ * Source assertions:
8
+ * - globals.css has cluster-hover descendant rule for kicker with
9
+ * 2 drop-shadow layers (2+4px)
10
+ * - globals.css has transition rule on kicker including 'filter 200ms'
11
+ * - TopoGraph.tsx kicker has data-topo-section-kicker-halo-layers="2"
12
+ *
13
+ * Runtime assertions:
14
+ * - kicker element present
15
+ * - halo-layers attr = "2"
16
+ * - kicker text = "Network Topology"
17
+ */
18
+ import { chromium } from 'playwright';
19
+ import { readFileSync } from 'node:fs';
20
+
21
+ const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
22
+ const fresh = new Date(Date.now() - 60 * 1000).toISOString();
23
+
24
+ const browser = await chromium.launch({ headless: true });
25
+ const ctx = await browser.newContext({ viewport: { width: 1500, height: 1200 } });
26
+ await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
27
+ await ctx.addInitScript(() => {
28
+ try {
29
+ localStorage.setItem('anet-theme', 'cyber');
30
+ localStorage.setItem('anet-topo-layout', 'ring');
31
+ sessionStorage.setItem('anet_v3_auth', '1');
32
+ } catch {}
33
+ });
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: 'idle', model: 'claude-opus-4', runtime: 'claude-code-cli',
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: [mk('a·1'), mk('a·2')] } });
44
+ });
45
+ await ctx.route('**/api/hub/messages*', (r) => r.fulfill({ json: { messages: [] } }));
46
+ await ctx.route('**/api/hub/tasks*', (r) => r.fulfill({ json: { tasks: [] } }));
47
+ const page = await ctx.newPage();
48
+ await page.goto('http://127.0.0.1:3000/', { waitUntil: 'networkidle' });
49
+ await page.waitForSelector('[data-topo-section-kicker]', { timeout: 15000, state: 'attached' });
50
+ await page.waitForTimeout(300);
51
+
52
+ const runtimeState = await page.evaluate(() => {
53
+ const kicker = document.querySelector('[data-topo-section-kicker]');
54
+ return {
55
+ present: !!kicker,
56
+ halo_layers: kicker?.getAttribute('data-topo-section-kicker-halo-layers'),
57
+ text: kicker?.textContent,
58
+ };
59
+ });
60
+
61
+ await browser.close();
62
+
63
+ const tsxSrc = readFileSync('/home/vansin/agent-network-dashboard/app/components/TopoGraph.tsx', 'utf8');
64
+ const cssSrc = readFileSync('/home/vansin/agent-network-dashboard/app/globals.css', 'utf8');
65
+
66
+ const cssHoverRule = /\[data-topo-section-titleblock-group\]:hover \[data-topo-section-kicker\]\s*\{[\s\S]*?drop-shadow\(0 0 2px currentColor\)[\s\S]*?drop-shadow\(0 0 4px currentColor\)/.test(cssSrc);
67
+ const cssTransition = /\[data-topo-section-kicker\]\s*\{[\s\S]*?transition:[\s\S]*?filter 200ms/.test(cssSrc);
68
+ const tsxHaloAttr = /data-topo-section-kicker-halo-layers="2"/.test(tsxSrc);
69
+
70
+ const results = {
71
+ kicker_present: runtimeState.present,
72
+ runtime_halo_layers: runtimeState.halo_layers === '2',
73
+ runtime_text: runtimeState.text === 'Network Topology',
74
+ css_hover_rule: cssHoverRule,
75
+ css_transition: cssTransition,
76
+ tsx_halo_attr: tsxHaloAttr,
77
+ };
78
+ const ok = Object.values(results).every(Boolean);
79
+ console.log(`${ok ? '✅' : '❌'} R685 kicker multi-layer halo (closes title-block trio 3/3):`,
80
+ JSON.stringify(results, null, 2),
81
+ `\n runtime: ${JSON.stringify(runtimeState)}`);
82
+ process.exit(ok ? 0 : 1);
@@ -0,0 +1,124 @@
1
+ /* Round 721 — kicker promoted from dual-axis to TRIPLE-axis breath.
2
+ * R699 opacity (6 s) + R714 transform-scale (6 s) joined by R721
3
+ * text-shadow (6 s) — all 3 axes share the 6 s cadence in phase.
4
+ * First triple-axis surface in the family.
5
+ *
6
+ * Glow specification: at mid-breath (50%) the kicker emits
7
+ * text-shadow: 0 0 6px rgba(34, 211, 238, 0.30). Reads as an "inhale
8
+ * glow" — a subtle cyan aura appears as the text dims and shrinks.
9
+ *
10
+ * Assertions:
11
+ * - CSS keyframes 0%/100% has text-shadow: none
12
+ * - CSS keyframes 50% has text-shadow: 0 0 6px rgba(34, 211, 238, 0.30)
13
+ * - existing opacity (1 ↔ 0.78) + transform-scale (1 ↔ 0.995) axes
14
+ * preserved in same @keyframes block (R699 + R714 still composing)
15
+ * - .anet-topo-kicker-breath rule still binds 6 s cadence
16
+ * - prefers-reduced-motion guard still present
17
+ * - runtime kicker has the breath class + 6s data attr (preserved)
18
+ * - R716 catalog kicker entry axes = ["opacity", "transform-scale", "text-shadow"]
19
+ * - kicker is the ONLY entry with 3 axes (first triple-axis surface)
20
+ * - text-shadow appears nowhere else in the catalog (kicker exclusive)
21
+ */
22
+ import { chromium } from 'playwright';
23
+ import { readFileSync } from 'node:fs';
24
+
25
+ const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
26
+ const fresh = new Date(Date.now() - 60 * 1000).toISOString();
27
+
28
+ const browser = await chromium.launch({ headless: true });
29
+ const ctx = await browser.newContext({ viewport: { width: 1500, height: 1200 } });
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
+ localStorage.setItem('anet-topo-layout', 'ring');
35
+ sessionStorage.setItem('anet_v3_auth', '1');
36
+ } catch {}
37
+ });
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: 'idle', model: 'claude-opus-4', runtime: 'claude-code-cli',
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('a·1'), mk('a·2')] } });
48
+ });
49
+ await ctx.route('**/api/hub/messages*', (r) => r.fulfill({ json: { messages: [] } }));
50
+ await ctx.route('**/api/hub/tasks*', (r) => r.fulfill({ json: { tasks: [] } }));
51
+ const page = await ctx.newPage();
52
+ await page.goto('http://127.0.0.1:3000/', { waitUntil: 'networkidle' });
53
+ await page.waitForSelector('.anet-topo-kicker-breath', { timeout: 15000, state: 'attached' });
54
+ await page.waitForTimeout(300);
55
+
56
+ const runtimeState = await page.evaluate(() => {
57
+ const kicker = document.querySelector('.anet-topo-kicker-breath');
58
+ if (!kicker) return null;
59
+ const cs = getComputedStyle(kicker);
60
+ const svg = document.querySelector('[data-topo-canvas-aria]');
61
+ return {
62
+ has_class: kicker.classList.contains('anet-topo-kicker-breath'),
63
+ breath_attr: kicker.getAttribute('data-topo-section-kicker-breath'),
64
+ anim_name: cs.animationName,
65
+ anim_duration: cs.animationDuration,
66
+ catalog: svg?.getAttribute('data-topo-respiratory-dual-axis-surfaces') ?? null,
67
+ };
68
+ });
69
+
70
+ await browser.close();
71
+
72
+ const cssSrc = readFileSync('/home/vansin/agent-network-dashboard/app/globals.css', 'utf8');
73
+ // 0%/100% keyframe must include text-shadow: none + opacity:1 + transform: scale(1)
74
+ const cssKf0_Triple = /@keyframes anet-topo-kicker-breath-kf\s*\{[\s\S]*?0%,\s*100%\s*\{[\s\S]*?opacity:\s*1[\s\S]*?transform:\s*scale\(1\)[\s\S]*?text-shadow:\s*none[\s\S]*?\}/.test(cssSrc);
75
+ // 50% keyframe must include text-shadow: 0 0 6px rgba(34, 211, 238, 0.30) + dim opacity + retract scale
76
+ const cssKf50_Triple = /@keyframes anet-topo-kicker-breath-kf\s*\{[\s\S]*?50%\s*\{[\s\S]*?opacity:\s*0\.78[\s\S]*?transform:\s*scale\(0\.995\)[\s\S]*?text-shadow:\s*0\s+0\s+6px\s+rgba\(34,\s*211,\s*238,\s*0\.30\)/.test(cssSrc);
77
+ const cssClassBound6s = /\.anet-topo-kicker-breath\s*\{[\s\S]*?animation:\s*anet-topo-kicker-breath-kf\s+6s\s+ease-in-out\s+infinite/.test(cssSrc);
78
+ const cssReducedMotion = /@media\s*\(prefers-reduced-motion:\s*reduce\)\s*\{[\s\S]*?\.anet-topo-kicker-breath\s*\{\s*animation:\s*none/.test(cssSrc);
79
+
80
+ const runtimeAnim = runtimeState?.anim_name === 'anet-topo-kicker-breath-kf' || runtimeState?.anim_name === 'none';
81
+
82
+ let catalog = null;
83
+ try { catalog = JSON.parse(runtimeState?.catalog ?? ''); } catch {}
84
+ const kickerEntry = Array.isArray(catalog) ? catalog.find(e => e.anchor === 'kicker') : null;
85
+ const kickerTripleAxes = !!kickerEntry
86
+ && Array.isArray(kickerEntry.axes)
87
+ && kickerEntry.axes.length === 3
88
+ && JSON.stringify(kickerEntry.axes) === JSON.stringify(['opacity', 'transform-scale', 'text-shadow']);
89
+
90
+ /* R722 added watermark as the 2nd triple-axis surface, so the
91
+ * "exclusive to kicker" invariants from R721's first-mover round
92
+ * no longer hold. R723 widens these to "kicker is a member of the
93
+ * triple-axis set" — the property R721 actually established (kicker
94
+ * IS triple-axis with text-shadow), without the exclusivity claim
95
+ * that R722 retired. */
96
+ const tripleAxisSurfaces = Array.isArray(catalog)
97
+ ? catalog.filter(e => Array.isArray(e.axes) && e.axes.length === 3)
98
+ : [];
99
+ const kickerIsTripleAxisMember = tripleAxisSurfaces.some(e => e.anchor === 'kicker');
100
+
101
+ const textShadowSurfaces = Array.isArray(catalog)
102
+ ? catalog.filter(e => Array.isArray(e.axes) && e.axes.includes('text-shadow'))
103
+ : [];
104
+ const kickerHasTextShadow = textShadowSurfaces.some(e => e.anchor === 'kicker');
105
+
106
+ const results = {
107
+ kicker_present: !!runtimeState,
108
+ has_breath_class: runtimeState?.has_class === true,
109
+ breath_cadence_attr_6s: runtimeState?.breath_attr === '6s',
110
+ runtime_anim_kicker_kf: runtimeAnim,
111
+ css_0_100_triple_axis: cssKf0_Triple,
112
+ css_50_triple_axis_with_glow: cssKf50_Triple,
113
+ css_class_binds_6s: cssClassBound6s,
114
+ css_reduced_motion_guard: cssReducedMotion,
115
+ catalog_kicker_three_axes: kickerTripleAxes,
116
+ kicker_is_triple_axis_member: kickerIsTripleAxisMember,
117
+ kicker_has_text_shadow_axis: kickerHasTextShadow,
118
+ };
119
+ const ok = Object.values(results).every(Boolean);
120
+ console.log(`${ok ? '✅' : '❌'} R721 kicker triple-axis breath (first 3-axis surface: opacity + transform-scale + text-shadow @ 6s):`,
121
+ JSON.stringify(results, null, 2),
122
+ `\n kicker entry: ${JSON.stringify(kickerEntry)}`,
123
+ `\n runtime: ${JSON.stringify({ anim_name: runtimeState?.anim_name, anim_duration: runtimeState?.anim_duration })}`);
124
+ process.exit(ok ? 0 : 1);