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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (487) hide show
  1. package/.next/BUILD_ID +1 -1
  2. package/.next/build-manifest.json +3 -3
  3. package/.next/diagnostics/route-bundle-stats.json +41 -41
  4. package/.next/fallback-build-manifest.json +3 -3
  5. package/.next/prerender-manifest.json +3 -3
  6. package/.next/server/app/_global-error.html +1 -1
  7. package/.next/server/app/_global-error.rsc +1 -1
  8. package/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  9. package/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  10. package/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  11. package/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  12. package/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  13. package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  14. package/.next/server/app/_not-found.html +2 -2
  15. package/.next/server/app/_not-found.rsc +12 -12
  16. package/.next/server/app/_not-found.segments/_full.segment.rsc +12 -12
  17. package/.next/server/app/_not-found.segments/_head.segment.rsc +4 -4
  18. package/.next/server/app/_not-found.segments/_index.segment.rsc +7 -7
  19. package/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +2 -2
  20. package/.next/server/app/_not-found.segments/_not-found.segment.rsc +3 -3
  21. package/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  22. package/.next/server/app/admin/page_client-reference-manifest.js +1 -1
  23. package/.next/server/app/admin.html +2 -2
  24. package/.next/server/app/admin.rsc +14 -14
  25. package/.next/server/app/admin.segments/_full.segment.rsc +14 -14
  26. package/.next/server/app/admin.segments/_head.segment.rsc +4 -4
  27. package/.next/server/app/admin.segments/_index.segment.rsc +7 -7
  28. package/.next/server/app/admin.segments/_tree.segment.rsc +2 -2
  29. package/.next/server/app/admin.segments/admin/__PAGE__.segment.rsc +4 -4
  30. package/.next/server/app/admin.segments/admin.segment.rsc +3 -3
  31. package/.next/server/app/index.html +2 -2
  32. package/.next/server/app/index.rsc +14 -14
  33. package/.next/server/app/index.segments/__PAGE__.segment.rsc +4 -4
  34. package/.next/server/app/index.segments/_full.segment.rsc +14 -14
  35. package/.next/server/app/index.segments/_head.segment.rsc +4 -4
  36. package/.next/server/app/index.segments/_index.segment.rsc +7 -7
  37. package/.next/server/app/index.segments/_tree.segment.rsc +2 -2
  38. package/.next/server/app/login/page_client-reference-manifest.js +1 -1
  39. package/.next/server/app/login.html +2 -2
  40. package/.next/server/app/login.rsc +14 -14
  41. package/.next/server/app/login.segments/_full.segment.rsc +14 -14
  42. package/.next/server/app/login.segments/_head.segment.rsc +4 -4
  43. package/.next/server/app/login.segments/_index.segment.rsc +7 -7
  44. package/.next/server/app/login.segments/_tree.segment.rsc +2 -2
  45. package/.next/server/app/login.segments/login/__PAGE__.segment.rsc +4 -4
  46. package/.next/server/app/login.segments/login.segment.rsc +3 -3
  47. package/.next/server/app/logs/page_client-reference-manifest.js +1 -1
  48. package/.next/server/app/logs.html +2 -2
  49. package/.next/server/app/logs.rsc +14 -14
  50. package/.next/server/app/logs.segments/_full.segment.rsc +14 -14
  51. package/.next/server/app/logs.segments/_head.segment.rsc +4 -4
  52. package/.next/server/app/logs.segments/_index.segment.rsc +7 -7
  53. package/.next/server/app/logs.segments/_tree.segment.rsc +2 -2
  54. package/.next/server/app/logs.segments/logs/__PAGE__.segment.rsc +4 -4
  55. package/.next/server/app/logs.segments/logs.segment.rsc +3 -3
  56. package/.next/server/app/messages/page_client-reference-manifest.js +1 -1
  57. package/.next/server/app/messages.html +2 -2
  58. package/.next/server/app/messages.rsc +14 -14
  59. package/.next/server/app/messages.segments/_full.segment.rsc +14 -14
  60. package/.next/server/app/messages.segments/_head.segment.rsc +4 -4
  61. package/.next/server/app/messages.segments/_index.segment.rsc +7 -7
  62. package/.next/server/app/messages.segments/_tree.segment.rsc +2 -2
  63. package/.next/server/app/messages.segments/messages/__PAGE__.segment.rsc +4 -4
  64. package/.next/server/app/messages.segments/messages.segment.rsc +3 -3
  65. package/.next/server/app/node/page_client-reference-manifest.js +1 -1
  66. package/.next/server/app/node.html +2 -2
  67. package/.next/server/app/node.rsc +14 -14
  68. package/.next/server/app/node.segments/_full.segment.rsc +14 -14
  69. package/.next/server/app/node.segments/_head.segment.rsc +4 -4
  70. package/.next/server/app/node.segments/_index.segment.rsc +7 -7
  71. package/.next/server/app/node.segments/_tree.segment.rsc +2 -2
  72. package/.next/server/app/node.segments/node/__PAGE__.segment.rsc +4 -4
  73. package/.next/server/app/node.segments/node.segment.rsc +3 -3
  74. package/.next/server/app/nodes/page_client-reference-manifest.js +1 -1
  75. package/.next/server/app/nodes.html +2 -2
  76. package/.next/server/app/nodes.rsc +14 -14
  77. package/.next/server/app/nodes.segments/_full.segment.rsc +14 -14
  78. package/.next/server/app/nodes.segments/_head.segment.rsc +4 -4
  79. package/.next/server/app/nodes.segments/_index.segment.rsc +7 -7
  80. package/.next/server/app/nodes.segments/_tree.segment.rsc +2 -2
  81. package/.next/server/app/nodes.segments/nodes/__PAGE__.segment.rsc +4 -4
  82. package/.next/server/app/nodes.segments/nodes.segment.rsc +3 -3
  83. package/.next/server/app/page_client-reference-manifest.js +1 -1
  84. package/.next/server/app/server-logs/page_client-reference-manifest.js +1 -1
  85. package/.next/server/app/server-logs.html +2 -2
  86. package/.next/server/app/server-logs.rsc +14 -14
  87. package/.next/server/app/server-logs.segments/_full.segment.rsc +14 -14
  88. package/.next/server/app/server-logs.segments/_head.segment.rsc +4 -4
  89. package/.next/server/app/server-logs.segments/_index.segment.rsc +7 -7
  90. package/.next/server/app/server-logs.segments/_tree.segment.rsc +2 -2
  91. package/.next/server/app/server-logs.segments/server-logs/__PAGE__.segment.rsc +4 -4
  92. package/.next/server/app/server-logs.segments/server-logs.segment.rsc +3 -3
  93. package/.next/server/app/settings/networks/page_client-reference-manifest.js +1 -1
  94. package/.next/server/app/settings/networks.html +2 -2
  95. package/.next/server/app/settings/networks.rsc +14 -14
  96. package/.next/server/app/settings/networks.segments/_full.segment.rsc +14 -14
  97. package/.next/server/app/settings/networks.segments/_head.segment.rsc +4 -4
  98. package/.next/server/app/settings/networks.segments/_index.segment.rsc +7 -7
  99. package/.next/server/app/settings/networks.segments/_tree.segment.rsc +2 -2
  100. package/.next/server/app/settings/networks.segments/settings/networks/__PAGE__.segment.rsc +4 -4
  101. package/.next/server/app/settings/networks.segments/settings/networks.segment.rsc +3 -3
  102. package/.next/server/app/settings/networks.segments/settings.segment.rsc +3 -3
  103. package/.next/server/app/settings/page_client-reference-manifest.js +1 -1
  104. package/.next/server/app/settings/tokens/page_client-reference-manifest.js +1 -1
  105. package/.next/server/app/settings/tokens.html +2 -2
  106. package/.next/server/app/settings/tokens.rsc +14 -14
  107. package/.next/server/app/settings/tokens.segments/_full.segment.rsc +14 -14
  108. package/.next/server/app/settings/tokens.segments/_head.segment.rsc +4 -4
  109. package/.next/server/app/settings/tokens.segments/_index.segment.rsc +7 -7
  110. package/.next/server/app/settings/tokens.segments/_tree.segment.rsc +2 -2
  111. package/.next/server/app/settings/tokens.segments/settings/tokens/__PAGE__.segment.rsc +4 -4
  112. package/.next/server/app/settings/tokens.segments/settings/tokens.segment.rsc +3 -3
  113. package/.next/server/app/settings/tokens.segments/settings.segment.rsc +3 -3
  114. package/.next/server/app/settings.html +2 -2
  115. package/.next/server/app/settings.rsc +14 -14
  116. package/.next/server/app/settings.segments/_full.segment.rsc +14 -14
  117. package/.next/server/app/settings.segments/_head.segment.rsc +4 -4
  118. package/.next/server/app/settings.segments/_index.segment.rsc +7 -7
  119. package/.next/server/app/settings.segments/_tree.segment.rsc +2 -2
  120. package/.next/server/app/settings.segments/settings/__PAGE__.segment.rsc +4 -4
  121. package/.next/server/app/settings.segments/settings.segment.rsc +3 -3
  122. package/.next/server/app/tasks/[id]/page_client-reference-manifest.js +1 -1
  123. package/.next/server/app/tasks/page_client-reference-manifest.js +1 -1
  124. package/.next/server/app/tasks.html +2 -2
  125. package/.next/server/app/tasks.rsc +14 -14
  126. package/.next/server/app/tasks.segments/_full.segment.rsc +14 -14
  127. package/.next/server/app/tasks.segments/_head.segment.rsc +4 -4
  128. package/.next/server/app/tasks.segments/_index.segment.rsc +7 -7
  129. package/.next/server/app/tasks.segments/_tree.segment.rsc +2 -2
  130. package/.next/server/app/tasks.segments/tasks/__PAGE__.segment.rsc +4 -4
  131. package/.next/server/app/tasks.segments/tasks.segment.rsc +3 -3
  132. package/.next/server/chunks/ssr/[root-of-the-server]__03b.f76._.js +1 -1
  133. package/.next/server/chunks/ssr/[root-of-the-server]__03b.f76._.js.map +1 -1
  134. package/.next/server/chunks/ssr/[root-of-the-server]__0fhoq8i._.js +1 -1
  135. package/.next/server/chunks/ssr/[root-of-the-server]__0fhoq8i._.js.map +1 -1
  136. package/.next/server/chunks/ssr/[root-of-the-server]__0nw~zhp._.js +1 -1
  137. package/.next/server/chunks/ssr/[root-of-the-server]__0nw~zhp._.js.map +1 -1
  138. package/.next/server/chunks/ssr/agent-network-dashboard_09kk21a._.js +4 -1
  139. package/.next/server/chunks/ssr/agent-network-dashboard_09kk21a._.js.map +1 -1
  140. package/.next/server/chunks/ssr/agent-network-dashboard_app_01jhlxz._.js +1 -1
  141. package/.next/server/chunks/ssr/agent-network-dashboard_app_01jhlxz._.js.map +1 -1
  142. package/.next/server/chunks/ssr/agent-network-dashboard_app_057q.ne._.js +1 -1
  143. package/.next/server/chunks/ssr/agent-network-dashboard_app_057q.ne._.js.map +1 -1
  144. package/.next/server/chunks/ssr/agent-network-dashboard_app_09d29my._.js +1 -1
  145. package/.next/server/chunks/ssr/agent-network-dashboard_app_09d29my._.js.map +1 -1
  146. package/.next/server/chunks/ssr/agent-network-dashboard_app_0_d45-d._.js +1 -1
  147. package/.next/server/chunks/ssr/agent-network-dashboard_app_0_d45-d._.js.map +1 -1
  148. package/.next/server/chunks/ssr/agent-network-dashboard_app_0i3759l._.js +1 -1
  149. package/.next/server/chunks/ssr/agent-network-dashboard_app_0i3759l._.js.map +1 -1
  150. package/.next/server/chunks/ssr/agent-network-dashboard_app_0xgney8._.js +1 -1
  151. package/.next/server/chunks/ssr/agent-network-dashboard_app_0xgney8._.js.map +1 -1
  152. package/.next/server/chunks/ssr/agent-network-dashboard_app_10hjgv4._.js +1 -1
  153. package/.next/server/chunks/ssr/agent-network-dashboard_app_10hjgv4._.js.map +1 -1
  154. package/.next/server/chunks/ssr/agent-network-dashboard_app_1153xeb._.js +1 -1
  155. package/.next/server/chunks/ssr/agent-network-dashboard_app_1153xeb._.js.map +1 -1
  156. package/.next/server/chunks/ssr/agent-network-dashboard_app_12l4oto._.js +1 -1
  157. package/.next/server/chunks/ssr/agent-network-dashboard_app_12l4oto._.js.map +1 -1
  158. package/.next/server/chunks/ssr/agent-network-dashboard_app_components_0mvyi-4._.js +1 -1
  159. package/.next/server/chunks/ssr/agent-network-dashboard_app_components_0mvyi-4._.js.map +1 -1
  160. package/.next/server/middleware-build-manifest.js +3 -3
  161. package/.next/server/pages/404.html +2 -2
  162. package/.next/server/pages/500.html +1 -1
  163. package/.next/server/server-reference-manifest.js +1 -1
  164. package/.next/server/server-reference-manifest.json +1 -1
  165. package/.next/static/chunks/0-mpa_947ipeq.js +1 -0
  166. package/.next/static/chunks/01lmbsd37fybu.js +1 -0
  167. package/.next/static/chunks/03o.h6kvmw4l_.js +1 -0
  168. package/.next/static/chunks/03~~oirxz7~vc.js +1 -0
  169. package/.next/static/chunks/05uk96gc~9mni.js +1 -0
  170. package/.next/static/chunks/07lsi~s-c0wvh.css +2 -0
  171. package/.next/static/chunks/08kf-.bgs10ze.js +1 -0
  172. package/.next/static/chunks/08s10wueoqydl.js +1 -0
  173. package/.next/static/chunks/0_l-j6k-ic81v.js +4 -0
  174. package/.next/static/chunks/0ggj5ummw2a84.js +7 -0
  175. package/.next/static/chunks/0glmrdj9112tc.js +7 -0
  176. package/.next/static/chunks/0rxrez_cjn.eh.js +1 -0
  177. package/.next/static/chunks/0wlu_nyra0im0.js +1 -0
  178. package/.next/static/chunks/0x8x.29hkju5a.js +1 -0
  179. package/.next/static/chunks/174re5ar~kxne.js +1 -0
  180. package/.next/trace +2 -2
  181. package/.next/trace-build +1 -1
  182. package/app/components/ChatPopover.tsx +38 -2
  183. package/app/components/CommandPalette.tsx +107 -0
  184. package/app/components/HelpOverlay.tsx +126 -0
  185. package/app/components/TopoGraph.tsx +6091 -262
  186. package/app/components/utils.ts +8 -7
  187. package/app/globals.css +110 -5
  188. package/app/lib/time.ts +36 -0
  189. package/app/lib/vendorIdentity.ts +14 -3
  190. package/package.json +2 -2
  191. package/public/sleep2agi-logo.svg +11 -0
  192. package/public/vendors/claude.svg +11 -0
  193. package/public/vendors/minimax.svg +11 -0
  194. package/public/vendors/openai.svg +12 -0
  195. package/screenshots/r293-p0/after-full.png +0 -0
  196. package/screenshots/r293-p0/after-topo.png +0 -0
  197. package/screenshots/r293-p0/baseline-full.png +0 -0
  198. package/screenshots/r293-p0/baseline-topo.png +0 -0
  199. package/screenshots/r293-p0/logo-integrated-full.png +0 -0
  200. package/screenshots/r293-p0/logo-integrated-topo.png +0 -0
  201. package/scripts/help-overlay-topo-test.mjs +44 -0
  202. package/scripts/p0-topo-screenshot.mjs +82 -0
  203. package/scripts/topo-active-filter-pill-test.mjs +101 -0
  204. package/scripts/topo-active-links-chip-hover-test.mjs +103 -0
  205. package/scripts/topo-active-links-chip-nav-test.mjs +117 -0
  206. package/scripts/topo-active-links-chip-self-hover-test.mjs +171 -0
  207. package/scripts/topo-active-links-chip-test.mjs +73 -0
  208. package/scripts/topo-active-links-empty-recede-test.mjs +125 -0
  209. package/scripts/topo-active-links-freshness-test.mjs +113 -0
  210. package/scripts/topo-active-links-tooltip-test.mjs +79 -0
  211. package/scripts/topo-active-pulse-ease-test.mjs +120 -0
  212. package/scripts/topo-auto-fit-test.mjs +73 -0
  213. package/scripts/topo-brand-logo-transition-test.mjs +93 -0
  214. package/scripts/topo-brand-watermark-test.mjs +97 -0
  215. package/scripts/topo-canvas-aria-test.mjs +108 -0
  216. package/scripts/topo-chat-target-breath-test.mjs +84 -0
  217. package/scripts/topo-chat-target-ring-ease-test.mjs +82 -0
  218. package/scripts/topo-chat-target-ring-fade-test.mjs +124 -0
  219. package/scripts/topo-chip-empty-recede-test.mjs +116 -0
  220. package/scripts/topo-chip-focus-test.mjs +95 -0
  221. package/scripts/topo-chip-pin-mirror-test.mjs +113 -0
  222. package/scripts/topo-chip-row-semantic-gap-test.mjs +97 -0
  223. package/scripts/topo-chip-row-tabular-test.mjs +111 -0
  224. package/scripts/topo-chrome-a11y-test.mjs +107 -0
  225. package/scripts/topo-chrome-focus-ring-unify-test.mjs +100 -0
  226. package/scripts/topo-chrome-icon-stroke-test.mjs +95 -0
  227. package/scripts/topo-chrome-pop-extension-test.mjs +98 -0
  228. package/scripts/topo-chrome-pop-nodesize-test.mjs +88 -0
  229. package/scripts/topo-chrome-press-state-test.mjs +135 -0
  230. package/scripts/topo-chrome-strip-semantic-gap-test.mjs +99 -0
  231. package/scripts/topo-chrome-strip-theme-ease-test.mjs +99 -0
  232. package/scripts/topo-chrome-zoom-level-pop-test.mjs +122 -0
  233. package/scripts/topo-chrome-zoom-pop-test.mjs +130 -0
  234. package/scripts/topo-click-ripple-ease-test.mjs +94 -0
  235. package/scripts/topo-cmdk-edge-clear-test.mjs +109 -0
  236. package/scripts/topo-cmdk-layout-view-test.mjs +108 -0
  237. package/scripts/topo-cmdk-pin-test.mjs +123 -0
  238. package/scripts/topo-cmdk-vendor-clear-test.mjs +133 -0
  239. package/scripts/topo-cmdk-vendor-pin-test.mjs +103 -0
  240. package/scripts/topo-corner-radius-unify-test.mjs +103 -0
  241. package/scripts/topo-cwd-tooltip-test.mjs +64 -0
  242. package/scripts/topo-dblclick-reset-test.mjs +74 -0
  243. package/scripts/topo-dense-alias-fill-transition-test.mjs +133 -0
  244. package/scripts/topo-discrete-zoom-smooth-test.mjs +125 -0
  245. package/scripts/topo-edge-badge-click-pin-test.mjs +94 -0
  246. package/scripts/topo-edge-badge-crossfade-test.mjs +138 -0
  247. package/scripts/topo-edge-badge-hot-test.mjs +115 -0
  248. package/scripts/topo-edge-badge-hover-test.mjs +85 -0
  249. package/scripts/topo-edge-badge-lift-test.mjs +150 -0
  250. package/scripts/topo-edge-badge-ripple-test.mjs +111 -0
  251. package/scripts/topo-edge-badge-stroke-transition-test.mjs +118 -0
  252. package/scripts/topo-edge-badge-text-pin-test.mjs +121 -0
  253. package/scripts/topo-edge-badge-theme-ease-test.mjs +89 -0
  254. package/scripts/topo-edge-count-badge-test.mjs +86 -0
  255. package/scripts/topo-edge-endpoint-highlight-test.mjs +111 -0
  256. package/scripts/topo-edge-fadein-test.mjs +106 -0
  257. package/scripts/topo-edge-focus-test.mjs +113 -0
  258. package/scripts/topo-edge-hover-test.mjs +93 -0
  259. package/scripts/topo-edge-pill-hot-test.mjs +129 -0
  260. package/scripts/topo-edge-pill-test.mjs +105 -0
  261. package/scripts/topo-edge-ping-pulse-retired-test.mjs +119 -0
  262. package/scripts/topo-edge-stroke-ease-test.mjs +100 -0
  263. package/scripts/topo-edge-stroke-transition-test.mjs +132 -0
  264. package/scripts/topo-edge-tooltip-test.mjs +70 -0
  265. package/scripts/topo-empty-hint-tracking-test.mjs +84 -0
  266. package/scripts/topo-empty-state-breath-test.mjs +150 -0
  267. package/scripts/topo-empty-state-crossfade-test.mjs +130 -0
  268. package/scripts/topo-empty-state-recenter-test.mjs +107 -0
  269. package/scripts/topo-empty-subhint-tracking-test.mjs +87 -0
  270. package/scripts/topo-endpoint-ring-fade-test.mjs +132 -0
  271. package/scripts/topo-endpoint-ring-test.mjs +93 -0
  272. package/scripts/topo-endpoint-ring-thicken-test.mjs +112 -0
  273. package/scripts/topo-esc-clears-pin-test.mjs +98 -0
  274. package/scripts/topo-filter-pill-aliases-test.mjs +121 -0
  275. package/scripts/topo-filter-pill-body-click-test.mjs +112 -0
  276. package/scripts/topo-filter-pill-count-test.mjs +110 -0
  277. package/scripts/topo-filter-pill-mobile-test.mjs +90 -0
  278. package/scripts/topo-fit-key-test.mjs +106 -0
  279. package/scripts/topo-freshness-chip-test.mjs +74 -0
  280. package/scripts/topo-freshness-chip-transition-test.mjs +80 -0
  281. package/scripts/topo-freshness-conditional-render-test.mjs +92 -0
  282. package/scripts/topo-fullscreen-active-test.mjs +115 -0
  283. package/scripts/topo-group-box-pinned-state-test.mjs +95 -0
  284. package/scripts/topo-group-count-test.mjs +6 -1
  285. package/scripts/topo-group-label-a11y-test.mjs +113 -0
  286. package/scripts/topo-group-label-count-inherit-test.mjs +99 -0
  287. package/scripts/topo-group-label-hover-test.mjs +119 -0
  288. package/scripts/topo-group-label-pin-spacing-test.mjs +136 -0
  289. package/scripts/topo-group-label-tint-test.mjs +99 -0
  290. package/scripts/topo-group-label-title-test.mjs +83 -0
  291. package/scripts/topo-group-pin-test.mjs +119 -0
  292. package/scripts/topo-group-pip-fadein-test.mjs +100 -0
  293. package/scripts/topo-group-pip-tabular-test.mjs +95 -0
  294. package/scripts/topo-group-status-pips-test.mjs +103 -0
  295. package/scripts/topo-groupbox-fadein-test.mjs +95 -0
  296. package/scripts/topo-groupbox-hover-lift-test.mjs +127 -0
  297. package/scripts/topo-groupbox-hubcore-ease-test.mjs +106 -0
  298. package/scripts/topo-groupbox-live-test.mjs +100 -0
  299. package/scripts/topo-groupbox-march-busyness-test.mjs +155 -0
  300. package/scripts/topo-groupbox-test.mjs +4 -2
  301. package/scripts/topo-help-overlay-r109-test.mjs +67 -0
  302. package/scripts/topo-help-overlay-r118-test.mjs +69 -0
  303. package/scripts/topo-help-overlay-r123-test.mjs +69 -0
  304. package/scripts/topo-help-overlay-r134-test.mjs +74 -0
  305. package/scripts/topo-help-overlay-r137-test.mjs +81 -0
  306. package/scripts/topo-help-overlay-r141-test.mjs +86 -0
  307. package/scripts/topo-help-overlay-r153-test.mjs +85 -0
  308. package/scripts/topo-help-overlay-r59-test.mjs +67 -0
  309. package/scripts/topo-help-overlay-r65-test.mjs +64 -0
  310. package/scripts/topo-help-overlay-r70-test.mjs +63 -0
  311. package/scripts/topo-help-overlay-r78-test.mjs +59 -0
  312. package/scripts/topo-help-overlay-r81-test.mjs +58 -0
  313. package/scripts/topo-help-overlay-r87-test.mjs +64 -0
  314. package/scripts/topo-help-overlay-r91-test.mjs +65 -0
  315. package/scripts/topo-hot-tail-crossfade-test.mjs +117 -0
  316. package/scripts/topo-html-overlay-padding-unify-test.mjs +120 -0
  317. package/scripts/topo-hub-a11y-test.mjs +112 -0
  318. package/scripts/topo-hub-busyness-test.mjs +100 -0
  319. package/scripts/topo-hub-center-crossfade-test.mjs +124 -0
  320. package/scripts/topo-hub-click-fit-test.mjs +137 -0
  321. package/scripts/topo-hub-digit-scale-test.mjs +129 -0
  322. package/scripts/topo-hub-fadein-test.mjs +88 -0
  323. package/scripts/topo-hub-hover-lift-test.mjs +101 -0
  324. package/scripts/topo-hub-hover-ring-test.mjs +82 -0
  325. package/scripts/topo-hub-pip-theme-ease-test.mjs +116 -0
  326. package/scripts/topo-hub-spoke-ease-test.mjs +120 -0
  327. package/scripts/topo-hub-title-test.mjs +93 -0
  328. package/scripts/topo-hub-working-count-test.mjs +99 -0
  329. package/scripts/topo-ingroup-edge-test.mjs +103 -0
  330. package/scripts/topo-inner-radar-ring-retired-test.mjs +89 -0
  331. package/scripts/topo-kicker-color-test.mjs +93 -0
  332. package/scripts/topo-kicker-tracking-test.mjs +101 -0
  333. package/scripts/topo-kicker-weight-test.mjs +98 -0
  334. package/scripts/topo-label-card-theme-ease-test.mjs +85 -0
  335. package/scripts/topo-label-lift-test.mjs +119 -0
  336. package/scripts/topo-lastseen-tooltip-test.mjs +59 -0
  337. package/scripts/topo-layout-hover-text-preview-test.mjs +101 -0
  338. package/scripts/topo-layout-key-test.mjs +91 -0
  339. package/scripts/topo-layout-switch-crossfade-test.mjs +126 -0
  340. package/scripts/topo-layout-toggle-border-unify-test.mjs +104 -0
  341. package/scripts/topo-layout-toggle-test.mjs +131 -0
  342. package/scripts/topo-legend-compress-test.mjs +107 -0
  343. package/scripts/topo-legend-count-empty-test.mjs +126 -0
  344. package/scripts/topo-legend-count-tabular-parity-test.mjs +90 -0
  345. package/scripts/topo-legend-count-tabular-test.mjs +87 -0
  346. package/scripts/topo-legend-count-test.mjs +88 -0
  347. package/scripts/topo-legend-count-tier-fill-test.mjs +121 -0
  348. package/scripts/topo-legend-header-symmetric-inset-test.mjs +112 -0
  349. package/scripts/topo-legend-hitbox-swatch-center-test.mjs +93 -0
  350. package/scripts/topo-legend-hover-test.mjs +113 -0
  351. package/scripts/topo-legend-offline-delimiter-test.mjs +84 -0
  352. package/scripts/topo-legend-offline-label-simplify-test.mjs +85 -0
  353. package/scripts/topo-legend-panel-header-test.mjs +83 -0
  354. package/scripts/topo-legend-pin-ring-fade-test.mjs +112 -0
  355. package/scripts/topo-legend-pin-test.mjs +128 -0
  356. package/scripts/topo-legend-row-hover-lift-test.mjs +109 -0
  357. package/scripts/topo-legend-row-pin-spacing-test.mjs +124 -0
  358. package/scripts/topo-legend-row-tint-test.mjs +95 -0
  359. package/scripts/topo-legend-row-title-test.mjs +102 -0
  360. package/scripts/topo-legend-swatch-grow-test.mjs +116 -0
  361. package/scripts/topo-legend-swatch-radius-test.mjs +78 -0
  362. package/scripts/topo-minimap-a11y-test.mjs +101 -0
  363. package/scripts/topo-minimap-dot-transition-test.mjs +113 -0
  364. package/scripts/topo-minimap-rect-stroke-test.mjs +94 -0
  365. package/scripts/topo-minimap-test.mjs +68 -0
  366. package/scripts/topo-minimap-viewport-smooth-test.mjs +124 -0
  367. package/scripts/topo-mobile-chips-test.mjs +103 -0
  368. package/scripts/topo-monogram-font-test.mjs +112 -0
  369. package/scripts/topo-monogram-stroke-test.mjs +101 -0
  370. package/scripts/topo-node-a11y-test.mjs +107 -0
  371. package/scripts/topo-node-alias-chat-pin-test.mjs +95 -0
  372. package/scripts/topo-node-hover-lift-test.mjs +85 -0
  373. package/scripts/topo-node-label-card-elevation-test.mjs +157 -0
  374. package/scripts/topo-node-label-card-stroke-test.mjs +135 -0
  375. package/scripts/topo-node-stroke-transition-test.mjs +103 -0
  376. package/scripts/topo-node-text-fill-transition-test.mjs +119 -0
  377. package/scripts/topo-node-title-peers-test.mjs +107 -0
  378. package/scripts/topo-node-title-test.mjs +101 -0
  379. package/scripts/topo-nodesize-active-hover-test.mjs +109 -0
  380. package/scripts/topo-nodesize-crossfade-test.mjs +141 -0
  381. package/scripts/topo-online-chip-nav-test.mjs +143 -0
  382. package/scripts/topo-orbit-particles-retired-test.mjs +91 -0
  383. package/scripts/topo-overlap-test.mjs +32 -5
  384. package/scripts/topo-panel-elevation-test.mjs +76 -0
  385. package/scripts/topo-panel-fadein-test.mjs +102 -0
  386. package/scripts/topo-panel-hot-tail-fade-test.mjs +132 -0
  387. package/scripts/topo-panel-hover-elevation-test.mjs +118 -0
  388. package/scripts/topo-panel-theme-ease-test.mjs +85 -0
  389. package/scripts/topo-panel-title-fill-ease-test.mjs +91 -0
  390. package/scripts/topo-panel-title-tracking-test.mjs +78 -0
  391. package/scripts/topo-particle-stagger-test.mjs +82 -0
  392. package/scripts/topo-pin-intersection-color-ease-test.mjs +111 -0
  393. package/scripts/topo-pin-intersection-empty-test.mjs +129 -0
  394. package/scripts/topo-pin-intersection-tabular-test.mjs +96 -0
  395. package/scripts/topo-pin-intersection-test.mjs +121 -0
  396. package/scripts/topo-pin-intersection-warning-crossfade-test.mjs +107 -0
  397. package/scripts/topo-pin-mirror-transition-test.mjs +101 -0
  398. package/scripts/topo-pin-persistence-test.mjs +105 -0
  399. package/scripts/topo-popover-meta-test.mjs +78 -0
  400. package/scripts/topo-prepublish-guard-test.mjs +95 -0
  401. package/scripts/topo-pressure-bar-test.mjs +69 -0
  402. package/scripts/topo-pressure-hover-test.mjs +123 -0
  403. package/scripts/topo-pressure-pin-test.mjs +119 -0
  404. package/scripts/topo-pressure-seg-self-hover-test.mjs +126 -0
  405. package/scripts/topo-pressure-seg-tooltip-test.mjs +98 -0
  406. package/scripts/topo-pressure-seg-transition-test.mjs +107 -0
  407. package/scripts/topo-pulse-dot-crossfade-test.mjs +122 -0
  408. package/scripts/topo-pulse-dot-retired-test.mjs +86 -0
  409. package/scripts/topo-recent-panel-count-freshness-test.mjs +109 -0
  410. package/scripts/topo-recent-panel-count-test.mjs +72 -0
  411. package/scripts/topo-recent-panel-footer-breath-test.mjs +142 -0
  412. package/scripts/topo-recent-panel-hot-header-test.mjs +132 -0
  413. package/scripts/topo-recent-panel-more-crossfade-test.mjs +124 -0
  414. package/scripts/topo-recent-panel-more-cyan-hover-test.mjs +151 -0
  415. package/scripts/topo-recent-panel-more-nav-test.mjs +127 -0
  416. package/scripts/topo-recent-panel-more-test.mjs +106 -0
  417. package/scripts/topo-recent-panel-readability-bump-test.mjs +151 -0
  418. package/scripts/topo-recent-row-count-fill-test.mjs +129 -0
  419. package/scripts/topo-recent-row-fadein-test.mjs +107 -0
  420. package/scripts/topo-recent-row-freshness-test.mjs +102 -0
  421. package/scripts/topo-recent-row-hot-test.mjs +110 -0
  422. package/scripts/topo-recent-row-hover-lift-test.mjs +128 -0
  423. package/scripts/topo-recent-row-hover-test.mjs +122 -0
  424. package/scripts/topo-recent-row-pin-spacing-test.mjs +137 -0
  425. package/scripts/topo-recent-row-pin-test.mjs +126 -0
  426. package/scripts/topo-recent-row-tint-test.mjs +91 -0
  427. package/scripts/topo-recent-row-title-test.mjs +112 -0
  428. package/scripts/topo-recent-row-ts-alpha-test.mjs +100 -0
  429. package/scripts/topo-recent-row-ts-test.mjs +95 -0
  430. package/scripts/topo-recent-row-typography-test.mjs +119 -0
  431. package/scripts/topo-recent-signal-empty-hint-test.mjs +73 -0
  432. package/scripts/topo-recent-signal-empty-test.mjs +63 -0
  433. package/scripts/topo-reduced-motion-test.mjs +77 -0
  434. package/scripts/topo-reset-spin-test.mjs +120 -0
  435. package/scripts/topo-runtime-badge-grow-test.mjs +114 -0
  436. package/scripts/topo-spokes-retired-test.mjs +93 -0
  437. package/scripts/topo-starfield-density-test.mjs +89 -0
  438. package/scripts/topo-status-chip-hover-test.mjs +101 -0
  439. package/scripts/topo-status-chip-tooltip-test.mjs +95 -0
  440. package/scripts/topo-statusbar-chips-self-hover-test.mjs +177 -0
  441. package/scripts/topo-svg-focus-test.mjs +112 -0
  442. package/scripts/topo-sweep-busyness-test.mjs +94 -0
  443. package/scripts/topo-tabular-nums-sweep-test.mjs +93 -0
  444. package/scripts/topo-tier-guide-dashes-test.mjs +86 -0
  445. package/scripts/topo-tier-ring-fadein-test.mjs +107 -0
  446. package/scripts/topo-tier-ring-occupancy-test.mjs +87 -0
  447. package/scripts/topo-tier-ring-test.mjs +69 -0
  448. package/scripts/topo-tier-ring-tint-test.mjs +110 -0
  449. package/scripts/topo-tier-stagger-test.mjs +89 -0
  450. package/scripts/topo-title-block-tight-leading-test.mjs +95 -0
  451. package/scripts/topo-title-tracking-test.mjs +98 -0
  452. package/scripts/topo-titleblock-gap-test.mjs +86 -0
  453. package/scripts/topo-titleblock-margin-test.mjs +83 -0
  454. package/scripts/topo-toggle-inactive-cyan-hover-test.mjs +110 -0
  455. package/scripts/topo-top-rail-theme-ease-test.mjs +89 -0
  456. package/scripts/topo-tz-ghost-test.mjs +69 -0
  457. package/scripts/topo-vendor-chip-hover-test.mjs +111 -0
  458. package/scripts/topo-vendor-chip-self-hover-test.mjs +131 -0
  459. package/scripts/topo-vendor-chip-tabular-test.mjs +92 -0
  460. package/scripts/topo-vendor-chip-threshold-test.mjs +78 -0
  461. package/scripts/topo-vendor-letter-tooltip-test.mjs +92 -0
  462. package/scripts/topo-vendor-pill-test.mjs +125 -0
  463. package/scripts/topo-vendor-pin-test.mjs +125 -0
  464. package/scripts/topo-view-smooth-test.mjs +131 -0
  465. package/scripts/topo-watermark-tracking-test.mjs +99 -0
  466. package/scripts/topo-working-chip-pin-test.mjs +154 -0
  467. package/scripts/topo-working-halo-breath-retired-test.mjs +99 -0
  468. package/scripts/topo-wrapper-flow-arrow-theme-test.mjs +97 -0
  469. package/scripts/topo-wrapper-shadow-theme-ease-test.mjs +89 -0
  470. package/.next/static/chunks/0-7iowzu4.798.js +0 -1
  471. package/.next/static/chunks/02t5jr4shh.hy.js +0 -1
  472. package/.next/static/chunks/08b1xx89c0ts9.js +0 -1
  473. package/.next/static/chunks/09nd.t_hd.y6t.css +0 -2
  474. package/.next/static/chunks/0_8snedeata9k.js +0 -1
  475. package/.next/static/chunks/0_qfg5s5uzs7..js +0 -7
  476. package/.next/static/chunks/0elalb9n_.~di.js +0 -1
  477. package/.next/static/chunks/0h_~v6f9o~_in.js +0 -1
  478. package/.next/static/chunks/0j_q__o8p6g83.js +0 -1
  479. package/.next/static/chunks/0jl6_w50zh4l5.js +0 -1
  480. package/.next/static/chunks/0pl7l_.2im.j0.js +0 -7
  481. package/.next/static/chunks/0r4q73.-1bkyl.js +0 -1
  482. package/.next/static/chunks/0r_c8eccg3z2o.js +0 -1
  483. package/.next/static/chunks/10oi7l-tycgl9.js +0 -1
  484. package/.next/static/chunks/11uk1izuv3~0t.js +0 -1
  485. /package/.next/static/{QkCLPQNNPLHlzKVvmAInn → 95X2ICTd2SB5ohx7R2QN2}/_buildManifest.js +0 -0
  486. /package/.next/static/{QkCLPQNNPLHlzKVvmAInn → 95X2ICTd2SB5ohx7R2QN2}/_clientMiddlewareManifest.js +0 -0
  487. /package/.next/static/{QkCLPQNNPLHlzKVvmAInn → 95X2ICTd2SB5ohx7R2QN2}/_ssgManifest.js +0 -0
@@ -0,0 +1,102 @@
1
+ /* Round 160 verification: recency pip on recent-signal panel rows.
2
+ *
3
+ * Canvas flow edges fade by freshness (R10: full intensity ≤30s,
4
+ * decaying to ~35% over 5min). The recent-signal panel rows
5
+ * encoded last_at purely in text ("5s" at row right edge) — no
6
+ * at-a-glance visual cue for "which row is actively firing".
7
+ *
8
+ * R160 adds a 1.6-px cyan dot at x=10 (in the 7-px margin
9
+ * between rect-start x=6 and text-start x=13). Alpha ramp:
10
+ * ageSec ≤ 30 → 1.0 (fully fresh)
11
+ * 30 < ageSec ≤ 300 → smooth decay 1.0 → 0.25
12
+ * ageSec > 300 → 0.25 (stale floor)
13
+ *
14
+ * Three independent encodings on each row, none competing:
15
+ * rect fill = hover/pin state (R104/R116)
16
+ * count tspan = magnitude (R127 amber when ≥10)
17
+ * pip = recency (this round)
18
+ *
19
+ * Test:
20
+ * Mock 3 flows — 1 fresh (5s ago), 1 mid (90s ago), 1 stale
21
+ * (6 min ago). Each should produce one pip; alpha ladder:
22
+ * fresh > mid > stale.
23
+ */
24
+ import { chromium } from 'playwright';
25
+ import { readFileSync } from 'node:fs';
26
+
27
+ const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
28
+ const browser = await chromium.launch({ headless: true });
29
+
30
+ const ctx = await browser.newContext({ viewport: { width: 1500, height: 1500 } });
31
+ await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
32
+ await ctx.addInitScript(() => {
33
+ try { localStorage.setItem('anet-theme', 'cyber'); sessionStorage.setItem('anet_v3_auth', '1'); } catch {}
34
+ });
35
+
36
+ const fresh = new Date(Date.now() - 60 * 1000).toISOString();
37
+ await ctx.route('**/api/hub/status*', async (route) => {
38
+ const r = await route.fetch();
39
+ const b = await r.json();
40
+ const nid = (b.sessions || [])[0]?.network_id || 'default';
41
+ const mk = (alias) => ({
42
+ alias, status: 'working', model: 'claude-opus-4', runtime: 'cli-claude-code',
43
+ network_id: nid, project_dir: null,
44
+ created_at: fresh, updated_at: fresh, last_seen_at: fresh,
45
+ });
46
+ await route.fulfill({ response: r, json: { ...b, sessions: [
47
+ mk('alpha'), mk('beta'), mk('gamma'), mk('delta'),
48
+ ] } });
49
+ });
50
+
51
+ const now = Date.now();
52
+ // Three distinct flows with different recency:
53
+ // fresh: 5s ago → alpha ≈ 1.0
54
+ // mid: 90s ago → alpha ≈ 1 - (60/270)*0.75 ≈ 0.833
55
+ // stale: 360s ago → alpha ≈ 0.25 (floor)
56
+ const msgs = [
57
+ { id: 'f1', from_alias: 'alpha', to_alias: 'beta', content: 'hi', network_id: 'default', created_at: new Date(now - 5000).toISOString() },
58
+ { id: 'm1', from_alias: 'beta', to_alias: 'gamma', content: 'hi', network_id: 'default', created_at: new Date(now - 90000).toISOString() },
59
+ { id: 's1', from_alias: 'gamma', to_alias: 'delta', content: 'hi', network_id: 'default', created_at: new Date(now - 360000).toISOString() },
60
+ ];
61
+ await ctx.route('**/api/hub/messages*', (route) => route.fulfill({ json: { messages: msgs } }));
62
+ await ctx.route('**/api/hub/tasks*', (route) => route.fulfill({ json: { tasks: [] } }));
63
+
64
+ const page = await ctx.newPage();
65
+ await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
66
+ await page.waitForFunction(() => document.querySelectorAll('g[data-node]').length === 4, { timeout: 30000 });
67
+ await page.waitForSelector('[data-recent-row-freshness]', { timeout: 10000 });
68
+ await page.waitForTimeout(400);
69
+
70
+ const probes = await page.evaluate(() => {
71
+ const pips = [...document.querySelectorAll('[data-recent-row-freshness]')];
72
+ return pips.map(el => ({
73
+ key: el.getAttribute('data-recent-row-freshness'),
74
+ alpha: parseFloat(el.getAttribute('data-recent-row-freshness-alpha') || ''),
75
+ cx: parseFloat(el.getAttribute('cx') || ''),
76
+ r: parseFloat(el.getAttribute('r') || ''),
77
+ tag: el.tagName.toLowerCase(),
78
+ }));
79
+ });
80
+
81
+ await browser.close();
82
+
83
+ if (probes.length !== 3) {
84
+ console.log(`❌ wrong pip count: expected 3, got ${probes.length}`, probes);
85
+ process.exit(1);
86
+ }
87
+ // Rows are sorted by recency (newest first), so probes[0] is freshest.
88
+ const [pFresh, pMid, pStale] = probes;
89
+ const results = {
90
+ three_pips: probes.length === 3,
91
+ all_circles: probes.every(p => p.tag === 'circle'),
92
+ all_at_x_10: probes.every(p => Math.abs(p.cx - 10) < 0.01),
93
+ all_radius_1p6: probes.every(p => Math.abs(p.r - 1.6) < 0.01),
94
+ fresh_alpha_1: Math.abs(pFresh.alpha - 1.0) < 0.05,
95
+ mid_alpha_0p7_to_0p9: pMid.alpha > 0.7 && pMid.alpha < 0.95,
96
+ stale_alpha_floor_0p25: Math.abs(pStale.alpha - 0.25) < 0.05,
97
+ ladder_descends: pFresh.alpha > pMid.alpha && pMid.alpha > pStale.alpha,
98
+ };
99
+ const ok = Object.values(results).every(Boolean);
100
+ console.log(`${ok ? '✅' : '❌'} recent-row freshness pip:`, JSON.stringify(results),
101
+ `\n probes=`, probes);
102
+ process.exit(ok ? 0 : 1);
@@ -0,0 +1,110 @@
1
+ /* Round 127 verification: recent-signal panel row mirrors R126's
2
+ * canvas hot-badge convention. When link.count >= 10 the count
3
+ * digit inside the row text renders in amber (#d97706 light,
4
+ * #fbbf24 dark) + bold (font-weight 700). Surrounding alias text +
5
+ * separators stay in legendText/legendHeadline.
6
+ *
7
+ * Fleet:
8
+ * alpha → beta: 12 msgs → HOT row, count tspan amber+bold
9
+ * beta → gamma: 4 msgs → warm row, count tspan default
10
+ *
11
+ * Path:
12
+ * 1. recent panel has 2 rows; data-recent-row-hot reflects bucket
13
+ * 2. alpha→beta row: data-recent-row-count-hot tspan present, amber
14
+ * 3. beta→gamma row: data-recent-row-count (non-hot) tspan present
15
+ * 4. Symmetry with R126: the canvas badge for alpha→beta and the
16
+ * recent-row count for alpha→beta both render the same amber
17
+ * hex.
18
+ */
19
+ import { chromium } from 'playwright';
20
+ import { readFileSync } from 'node:fs';
21
+
22
+ const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
23
+ const browser = await chromium.launch({ headless: true });
24
+
25
+ const ctx = await browser.newContext({ viewport: { width: 1400, height: 1500 } });
26
+ await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
27
+ await ctx.addInitScript(() => {
28
+ try { localStorage.setItem('anet-theme', 'cyber'); sessionStorage.setItem('anet_v3_auth', '1'); } catch {}
29
+ });
30
+
31
+ const fresh = new Date(Date.now() - 60 * 1000).toISOString();
32
+ await ctx.route('**/api/hub/status*', async (route) => {
33
+ const r = await route.fetch();
34
+ const b = await r.json();
35
+ const nid = (b.sessions || [])[0]?.network_id || 'default';
36
+ const mk = (alias, status) => ({
37
+ alias, status, model: 'claude-opus-4', runtime: 'cli-claude-code',
38
+ network_id: nid, project_dir: null,
39
+ created_at: fresh, updated_at: fresh, last_seen_at: fresh,
40
+ });
41
+ await route.fulfill({ response: r, json: { ...b, sessions: [
42
+ mk('alpha', 'working'), mk('beta', 'working'), mk('gamma', 'idle'),
43
+ ] } });
44
+ });
45
+
46
+ const now = Date.now();
47
+ const mkMsg = (id, from_alias, to_alias, ageMs) => ({
48
+ id, from_alias, to_alias, content: 'hi', network_id: 'default',
49
+ created_at: new Date(now - ageMs).toISOString(),
50
+ });
51
+ const msgs = [];
52
+ for (let i = 0; i < 12; i++) msgs.push(mkMsg(`a${i}`, 'alpha', 'beta', 20000 + i * 500));
53
+ for (let i = 0; i < 4; i++) msgs.push(mkMsg(`b${i}`, 'beta', 'gamma', 30000 + i * 500));
54
+ await ctx.route('**/api/hub/messages*', (route) => route.fulfill({ json: { messages: msgs } }));
55
+ await ctx.route('**/api/hub/tasks*', (route) => route.fulfill({ json: { tasks: [] } }));
56
+
57
+ const page = await ctx.newPage();
58
+ await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
59
+ await page.waitForFunction(() => document.querySelectorAll('g[data-node]').length === 3, { timeout: 30000 });
60
+ await page.waitForSelector('[data-recent-row="alpha->beta"]', { timeout: 10000 });
61
+ await page.waitForTimeout(400);
62
+
63
+ const inspect = (key) => page.evaluate((k) => {
64
+ const row = document.querySelector(`[data-recent-row="${k}"]`);
65
+ if (!row) return null;
66
+ const hotTspan = row.querySelector('[data-recent-row-count-hot]');
67
+ const warmTspan = row.querySelector('[data-recent-row-count]');
68
+ return {
69
+ hot: row.getAttribute('data-recent-row-hot'),
70
+ hotTspanText: hotTspan?.textContent,
71
+ hotTspanFill: hotTspan?.getAttribute('fill'),
72
+ hotTspanWeight: hotTspan?.getAttribute('font-weight'),
73
+ warmTspanText: warmTspan?.textContent,
74
+ };
75
+ }, key);
76
+
77
+ const a2b = await inspect('alpha->beta');
78
+ const b2g = await inspect('beta->gamma');
79
+
80
+ // Also assert the canvas badge for alpha→beta still flips to the
81
+ // same amber stroke — symmetry of canvas + panel hot signals.
82
+ const badgeStroke = await page.evaluate(() => {
83
+ const g = document.querySelector('[data-edge-count-badge="alpha->beta"]');
84
+ return g?.querySelector('circle')?.getAttribute('stroke');
85
+ });
86
+
87
+ await browser.close();
88
+
89
+ // Dark theme amber: #fbbf24
90
+ const amberHex = '#fbbf24';
91
+
92
+ const results = {
93
+ a2b_attrHot: a2b !== null && a2b.hot === 'true',
94
+ a2b_hotTspan: a2b !== null && a2b.hotTspanText === '12',
95
+ a2b_amberFill: a2b !== null && (a2b.hotTspanFill || '').toLowerCase() === amberHex,
96
+ a2b_boldWeight: a2b !== null && a2b.hotTspanWeight === '700',
97
+ a2b_noWarmTspan: a2b !== null && a2b.warmTspanText === undefined,
98
+
99
+ b2g_attrNotHot: b2g !== null && b2g.hot === 'false',
100
+ b2g_warmTspan: b2g !== null && b2g.warmTspanText === '4',
101
+ b2g_noHotTspan: b2g !== null && a2b !== null && b2g.hotTspanText === undefined,
102
+
103
+ symmetric_badgeAmber: (badgeStroke || '').toLowerCase() === amberHex,
104
+ };
105
+ const ok = Object.values(results).every(Boolean);
106
+ console.log(`${ok ? '✅' : '❌'} recent-row hot:`, JSON.stringify(results),
107
+ `\n a2b=`, a2b,
108
+ `\n b2g=`, b2g,
109
+ `\n canvas badge stroke for alpha→beta =`, badgeStroke);
110
+ process.exit(ok ? 0 : 1);
@@ -0,0 +1,128 @@
1
+ /* Round 143 verification: recent-signal panel rows lift 1px on
2
+ * hover or pin. Closes the "interactive surface elevates" idiom
3
+ * across four nested canvas-region scopes:
4
+ * R51 node hover-lift (canvas element) → translateY(-2px)
5
+ * R135 overlay panels (canvas chrome) → drop-shadow boost
6
+ * R142 group boxes (canvas-side per-team) → drop-shadow filter
7
+ * R143 recent-signal rows (panel content) → translateY(-1px)
8
+ *
9
+ * Smaller layer = smaller lift (1px row, 2px node, drop-shadow
10
+ * panel/box). Each layer signals interactivity in its own
11
+ * vocabulary.
12
+ *
13
+ * States:
14
+ * 1. Idle row: data-recent-row-lifted="false", no transform
15
+ * 2. Hover row → lifted=true, transform contains translateY(-1px)
16
+ * 3. Leave hover → restored to flat
17
+ * 4. Click to pin → lifted=true (pin keeps the lift)
18
+ * 5. Esc → cleared back to flat
19
+ */
20
+ import { chromium } from 'playwright';
21
+ import { readFileSync } from 'node:fs';
22
+
23
+ const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
24
+ const browser = await chromium.launch({ headless: true });
25
+
26
+ const ctx = await browser.newContext({ viewport: { width: 1400, height: 1500 } });
27
+ await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
28
+ await ctx.addInitScript(() => {
29
+ try { localStorage.setItem('anet-theme', 'cyber'); sessionStorage.setItem('anet_v3_auth', '1'); } catch {}
30
+ });
31
+
32
+ const fresh = new Date(Date.now() - 60 * 1000).toISOString();
33
+ await ctx.route('**/api/hub/status*', async (route) => {
34
+ const r = await route.fetch();
35
+ const b = await r.json();
36
+ const nid = (b.sessions || [])[0]?.network_id || 'default';
37
+ const mk = (alias, status) => ({
38
+ alias, status, model: 'claude-opus-4', runtime: 'cli-claude-code',
39
+ network_id: nid, project_dir: null,
40
+ created_at: fresh, updated_at: fresh, last_seen_at: fresh,
41
+ });
42
+ await route.fulfill({ response: r, json: { ...b, sessions: [
43
+ mk('alpha', 'working'), mk('beta', 'working'), mk('gamma', 'idle'),
44
+ ] } });
45
+ });
46
+
47
+ const now = Date.now();
48
+ const msgs = [];
49
+ // 3 distinct pairs → 3 recent-signal rows
50
+ const pairs = [['alpha', 'beta'], ['beta', 'gamma'], ['gamma', 'alpha']];
51
+ pairs.forEach(([from, to], i) => {
52
+ msgs.push({
53
+ id: `m${i}`,
54
+ from_alias: from,
55
+ to_alias: to,
56
+ content: 'hi',
57
+ network_id: 'default',
58
+ created_at: new Date(now - (20000 + i * 1000)).toISOString(),
59
+ });
60
+ });
61
+ await ctx.route('**/api/hub/messages*', (route) => route.fulfill({ json: { messages: msgs } }));
62
+ await ctx.route('**/api/hub/tasks*', (route) => route.fulfill({ json: { tasks: [] } }));
63
+
64
+ const page = await ctx.newPage();
65
+ await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
66
+ await page.waitForFunction(() => document.querySelectorAll('g[data-node]').length === 3, { timeout: 30000 });
67
+ await page.waitForSelector('[data-recent-row="alpha->beta"]', { timeout: 10000 });
68
+ await page.waitForTimeout(400);
69
+
70
+ const inspect = (key) => page.evaluate((k) => {
71
+ const row = document.querySelector(`[data-recent-row="${k}"]`);
72
+ return {
73
+ lifted: row?.getAttribute('data-recent-row-lifted'),
74
+ hovered: row?.getAttribute('data-recent-row-hovered'),
75
+ pinned: row?.getAttribute('data-recent-row-pinned'),
76
+ transform: row?.getAttribute('style')?.match(/translateY\([^)]+\)/)?.[0],
77
+ };
78
+ }, key);
79
+
80
+ // State 1: idle baseline (no hover, no pin)
81
+ const s1 = await inspect('alpha->beta');
82
+
83
+ // State 2: hover alpha->beta row
84
+ await page.locator('[data-recent-row="alpha->beta"]').hover();
85
+ await page.waitForTimeout(250);
86
+ const s2_hovered = await inspect('alpha->beta');
87
+ const s2_other = await inspect('beta->gamma');
88
+
89
+ // State 3: leave hover (mouse far away to clear all panel hovers)
90
+ await page.mouse.move(700, 350);
91
+ await page.waitForTimeout(250);
92
+ const s3 = await inspect('alpha->beta');
93
+
94
+ // State 4: click row to pin
95
+ await page.locator('[data-recent-row="alpha->beta"]').click();
96
+ await page.waitForTimeout(250);
97
+ // Move mouse away so only pin lifts the row (not hover)
98
+ await page.mouse.move(700, 350);
99
+ await page.waitForTimeout(250);
100
+ const s4 = await inspect('alpha->beta');
101
+
102
+ // State 5: Esc clears pin
103
+ await page.keyboard.press('Escape');
104
+ await page.waitForTimeout(250);
105
+ const s5 = await inspect('alpha->beta');
106
+
107
+ await browser.close();
108
+
109
+ const liftStr = 'translateY(-1px)';
110
+ const results = {
111
+ s1_idleFlat: s1.lifted === 'false' && !s1.transform,
112
+
113
+ s2_hoveredLifted: s2_hovered.hovered === 'true' && s2_hovered.lifted === 'true',
114
+ s2_hoveredTransform: s2_hovered.transform === liftStr,
115
+ s2_otherStillFlat: s2_other.lifted === 'false' && !s2_other.transform,
116
+
117
+ s3_restored: s3.lifted === 'false' && !s3.transform,
118
+
119
+ s4_pinnedLifted: s4.pinned === 'true' && s4.lifted === 'true',
120
+ s4_pinnedTransform: s4.transform === liftStr,
121
+
122
+ s5_clearedAfterEsc: s5.lifted === 'false' && !s5.transform,
123
+ };
124
+ const ok = Object.values(results).every(Boolean);
125
+ console.log(`${ok ? '✅' : '❌'} recent-row hover lift:`, JSON.stringify(results),
126
+ `\n s1=`, s1, `\n s2_hovered=`, s2_hovered, ` s2_other=`, s2_other,
127
+ `\n s3=`, s3, `\n s4=`, s4, `\n s5=`, s5);
128
+ process.exit(ok ? 0 : 1);
@@ -0,0 +1,122 @@
1
+ /* Round 56 verification: hovering a recent-signal panel row sets
2
+ * hoveredEdgeKey to that link, which fires the R50 edge-focus +
3
+ * R49 endpoint-highlight ladders against the canvas.
4
+ *
5
+ * Sessions: alpha, beta, gamma, delta, epsilon, zeta (all idle).
6
+ * Messages create three deduped flow links in this order:
7
+ * alpha → beta
8
+ * gamma → delta
9
+ * epsilon → zeta
10
+ * Hover the FIRST recent-signal row (alpha→beta):
11
+ * - alpha→beta visible edge: opacity boosts ≥1.5× baseline (R50)
12
+ * - other edges (γ→δ, ε→ζ): opacity dims < 0.6× baseline
13
+ * - alpha + beta nodes: stay bright (≥0.55) — endpoint highlight (R49)
14
+ * - gamma/delta/epsilon/zeta nodes: dim (<0.4)
15
+ * Release → all restore.
16
+ */
17
+ import { chromium } from 'playwright';
18
+ import { readFileSync } from 'node:fs';
19
+
20
+ const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
21
+ const browser = await chromium.launch({ headless: true });
22
+
23
+ const ctx = await browser.newContext({ viewport: { width: 1400, height: 1500 } });
24
+ await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
25
+ await ctx.addInitScript(() => {
26
+ try {
27
+ localStorage.setItem('anet-theme', 'cyber');
28
+ localStorage.setItem('anet-topo-layout', 'ring');
29
+ sessionStorage.setItem('anet_v3_auth', '1');
30
+ } catch {}
31
+ });
32
+
33
+ const fresh = new Date(Date.now() - 60 * 1000).toISOString();
34
+ await ctx.route('**/api/hub/status*', async (route) => {
35
+ const r = await route.fetch();
36
+ const b = await r.json();
37
+ const nid = (b.sessions || [])[0]?.network_id || 'default';
38
+ const sessions = ['alpha', 'beta', 'gamma', 'delta', 'epsilon', 'zeta'].map(a => ({
39
+ alias: a, status: 'idle', network_id: nid, project_dir: null,
40
+ created_at: fresh, updated_at: fresh, last_seen_at: fresh,
41
+ }));
42
+ await route.fulfill({ response: r, json: { ...b, sessions } });
43
+ });
44
+ const now = new Date().toISOString();
45
+ await ctx.route('**/api/hub/messages*', (route) => route.fulfill({ json: { messages: [
46
+ { from_alias: 'alpha', to_alias: 'beta', content: 'm', created_at: now },
47
+ { from_alias: 'gamma', to_alias: 'delta', content: 'm', created_at: now },
48
+ { from_alias: 'epsilon', to_alias: 'zeta', content: 'm', created_at: now },
49
+ ] } }));
50
+ await ctx.route('**/api/hub/tasks*', (route) => route.fulfill({ json: { tasks: [] } }));
51
+ const page = await ctx.newPage();
52
+ await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
53
+ await page.waitForFunction(() => document.querySelectorAll('g[data-node]').length === 6, { timeout: 30000 });
54
+ await page.waitForTimeout(600);
55
+
56
+ const readState = () => page.evaluate(() => {
57
+ const svg = document.querySelector('svg[viewBox="0 0 1000 680"]');
58
+ const edges = {};
59
+ for (const g of svg.querySelectorAll(':scope > g > g')) {
60
+ const t = g.querySelector('path[data-edge-hitbox] title');
61
+ if (!t) continue;
62
+ const route = (t.textContent || '').split('\n')[0];
63
+ const base = [...g.querySelectorAll(':scope > path')].find(
64
+ p => !p.hasAttribute('data-edge-hitbox') && p.hasAttribute('marker-end')
65
+ );
66
+ if (base) edges[route] = +base.getAttribute('opacity');
67
+ }
68
+ const nodes = {};
69
+ for (const a of ['alpha', 'beta', 'gamma', 'delta', 'epsilon', 'zeta']) {
70
+ const n = document.querySelector(`g[data-node="${a}"]`);
71
+ nodes[a] = n ? +(n.style.opacity || '1') : null;
72
+ }
73
+ return { edges, nodes };
74
+ });
75
+
76
+ const before = await readState();
77
+
78
+ // Hover the first recent-signal row — its key is "alpha->beta".
79
+ const rowRect = await page.evaluate(() => {
80
+ const g = document.querySelector('g[data-recent-row="alpha->beta"]');
81
+ if (!g) return null;
82
+ const r = g.getBoundingClientRect();
83
+ return { x: r.x + r.width / 2, y: r.y + r.height / 2 };
84
+ });
85
+ if (!rowRect) { console.log('❌ recent-signal row alpha->beta not found'); process.exit(1); }
86
+ await page.mouse.move(10, 10);
87
+ await page.mouse.move(rowRect.x, rowRect.y);
88
+ await page.waitForTimeout(350);
89
+ const during = await readState();
90
+
91
+ await page.mouse.move(10, 10);
92
+ await page.waitForTimeout(350);
93
+ const after = await readState();
94
+
95
+ await browser.close();
96
+
97
+ const baseEdgeOp = before.edges['alpha → beta'];
98
+ const eAB = during.edges['alpha → beta'];
99
+ const eGD = during.edges['gamma → delta'];
100
+ const eEZ = during.edges['epsilon → zeta'];
101
+
102
+ const bright = (v) => v != null && v >= 0.55;
103
+ const dim = (v) => v != null && v < 0.4;
104
+ const results = {
105
+ baselineEqual: Math.abs(before.edges['alpha → beta'] - before.edges['gamma → delta']) < 0.001
106
+ && Math.abs(before.edges['alpha → beta'] - before.edges['epsilon → zeta']) < 0.001,
107
+ hoverBrightensTargetEdge: eAB > baseEdgeOp * 1.5,
108
+ hoverDimsOtherEdges: eGD < baseEdgeOp * 0.6 && eEZ < baseEdgeOp * 0.6,
109
+ endpointsStayBright: bright(during.nodes.alpha) && bright(during.nodes.beta),
110
+ nonEndpointsDim: dim(during.nodes.gamma) && dim(during.nodes.delta)
111
+ && dim(during.nodes.epsilon) && dim(during.nodes.zeta),
112
+ releaseRestoresEdges: Math.abs(after.edges['alpha → beta'] - baseEdgeOp) < 0.05
113
+ && Math.abs(after.edges['gamma → delta'] - baseEdgeOp) < 0.05,
114
+ releaseRestoresNodes: bright(after.nodes.alpha) && bright(after.nodes.gamma) && bright(after.nodes.epsilon),
115
+ };
116
+ const ok = Object.values(results).every(Boolean);
117
+ console.log(`${ok ? '✅' : '❌'} recent-row hover:`, JSON.stringify(results),
118
+ `\n baseline α→β=${baseEdgeOp}`,
119
+ `\n during α→β=${eAB} γ→δ=${eGD} ε→ζ=${eEZ}`,
120
+ `\n during nodes=`, during.nodes,
121
+ `\n after edges=`, after.edges);
122
+ process.exit(ok ? 0 : 1);
@@ -0,0 +1,137 @@
1
+ /* Round 220 verification (milestone): recent-signal row text completes
2
+ * the pin-signature typography triple (R218 group labels / R219
3
+ * legend rows / R220 recent-signal rows). All three label-based
4
+ * interactive surfaces now read "locked in" at type level on pin.
5
+ *
6
+ * Test (cyber dark, 4 working sessions + 3 mock flows so recent-
7
+ * signal panel renders 3 rows):
8
+ * 1. 3 [data-recent-row-text] rows render.
9
+ * 2. Idle: all pinned='false', spacing 'normal' or 0px.
10
+ * 3. Inline transition includes 'letter-spacing 150ms'.
11
+ * 4. Click first row to pin it.
12
+ * 5. First row: pinned='true', spacing ≈ 0.5px.
13
+ * 6. Other rows stay unpinned + 0 spacing.
14
+ * 7. Click pinned row again → unpin → back to 0.
15
+ * 8. Hover (not pin) does NOT trigger letter-spacing spread —
16
+ * pin-exclusive signature (proven by hover-without-click test).
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 browser = await chromium.launch({ headless: true });
23
+
24
+ const ctx = await browser.newContext({ viewport: { width: 1500, height: 1500 } });
25
+ await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
26
+ await ctx.addInitScript(() => {
27
+ try { localStorage.setItem('anet-theme', 'cyber'); sessionStorage.setItem('anet_v3_auth', '1'); } catch {}
28
+ });
29
+
30
+ const fresh = new Date(Date.now() - 60 * 1000).toISOString();
31
+ await ctx.route('**/api/hub/status*', async (route) => {
32
+ const r = await route.fetch();
33
+ const b = await r.json();
34
+ const nid = (b.sessions || [])[0]?.network_id || 'default';
35
+ const mk = (alias) => ({
36
+ alias, status: 'working', model: 'claude-opus-4', runtime: 'claude-code-cli',
37
+ network_id: nid, project_dir: null,
38
+ created_at: fresh, updated_at: fresh, last_seen_at: fresh,
39
+ });
40
+ await route.fulfill({ response: r, json: { ...b, sessions: [
41
+ mk('alpha'), mk('beta'), mk('gamma'), mk('delta'),
42
+ ] } });
43
+ });
44
+
45
+ const now = Date.now();
46
+ const msgs = [
47
+ { id: '1', from_alias: 'alpha', to_alias: 'beta', content: 'hi',
48
+ network_id: 'default', created_at: new Date(now - 2000).toISOString() },
49
+ { id: '2', from_alias: 'beta', to_alias: 'gamma', content: 'hi',
50
+ network_id: 'default', created_at: new Date(now - 5000).toISOString() },
51
+ { id: '3', from_alias: 'gamma', to_alias: 'delta', content: 'hi',
52
+ network_id: 'default', created_at: new Date(now - 8000).toISOString() },
53
+ ];
54
+ await ctx.route('**/api/hub/messages*', (r2) => r2.fulfill({ json: { messages: msgs } }));
55
+ await ctx.route('**/api/hub/tasks*', (r2) => r2.fulfill({ json: { tasks: [] } }));
56
+
57
+ const page = await ctx.newPage();
58
+ await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
59
+ await page.waitForFunction(() => document.querySelectorAll('g[data-node]').length === 4, { timeout: 30000 });
60
+ await page.waitForSelector('[data-recent-row-text]', { timeout: 10000, state: 'attached' });
61
+ await page.waitForTimeout(300);
62
+
63
+ const probe = async () => page.evaluate(() => {
64
+ return [...document.querySelectorAll('[data-recent-row-text]')].map(el => {
65
+ const cs = getComputedStyle(el);
66
+ return {
67
+ key: el.getAttribute('data-recent-row-text'),
68
+ pinned: el.getAttribute('data-recent-row-text-pinned'),
69
+ spacing: cs.letterSpacing,
70
+ transition: el.style.transition,
71
+ };
72
+ });
73
+ });
74
+
75
+ const idle = await probe();
76
+ const firstKey = idle[0]?.key;
77
+
78
+ // Hover-without-pin probe: hover the first row, verify spacing
79
+ // stays at 0 (pin-exclusive signature, not triggered by hover)
80
+ await page.hover(`[data-recent-row="${firstKey}"]`);
81
+ await page.waitForTimeout(200);
82
+ const hovered = await probe();
83
+ await page.mouse.move(0, 0);
84
+ await page.waitForTimeout(180);
85
+
86
+ // Click to pin
87
+ await page.click(`[data-recent-row="${firstKey}"]`);
88
+ await page.waitForTimeout(200);
89
+ const pinned = await probe();
90
+
91
+ // Click again to unpin
92
+ await page.click(`[data-recent-row="${firstKey}"]`);
93
+ await page.waitForTimeout(200);
94
+ const unpinned = await probe();
95
+
96
+ await browser.close();
97
+
98
+ const near = (s, want, tol = 0.15) => {
99
+ if (want === 0 && (s === 'normal' || s === '0px' || s === '0' || !s)) return true;
100
+ const got = parseFloat(s || '0');
101
+ return Math.abs(got - want) < tol;
102
+ };
103
+ const hasLetterSpacingT = (s) => /letter-spacing\s+(?:150ms|0\.15s)/.test(s || '');
104
+
105
+ const firstIdle = idle.find(p => p.key === firstKey);
106
+ const firstHovered = hovered.find(p => p.key === firstKey);
107
+ const firstPinned = pinned.find(p => p.key === firstKey);
108
+ const otherPinned = pinned.find(p => p.key !== firstKey);
109
+ const firstUnpin = unpinned.find(p => p.key === firstKey);
110
+
111
+ const results = {
112
+ three_rows_present: idle.length === 3,
113
+ all_idle_unpinned: idle.every(p => p.pinned === 'false'),
114
+ all_idle_spacing_zero: idle.every(p => near(p.spacing, 0)),
115
+ all_have_transition: idle.every(p => hasLetterSpacingT(p.transition)),
116
+
117
+ // Pin-exclusive: hover does NOT trigger letter-spacing spread
118
+ hovered_pinned_false: firstHovered?.pinned === 'false',
119
+ hovered_spacing_zero: near(firstHovered?.spacing, 0),
120
+
121
+ // Pin click triggers spread
122
+ first_pinned_attr: firstPinned?.pinned === 'true',
123
+ first_pinned_spacing: near(firstPinned?.spacing, 0.5),
124
+ other_stays_unpinned: otherPinned?.pinned === 'false',
125
+ other_spacing_unchanged: near(otherPinned?.spacing, 0),
126
+
127
+ // Unpin returns to 0
128
+ unpin_attr_false: firstUnpin?.pinned === 'false',
129
+ unpin_spacing_zero: near(firstUnpin?.spacing, 0),
130
+ };
131
+ const ok = Object.values(results).every(Boolean);
132
+ console.log(`${ok ? '✅' : '❌'} recent-row pin spacing:`, JSON.stringify(results),
133
+ `\n idle:`, idle,
134
+ `\n hovered:`, hovered,
135
+ `\n pinned:`, pinned,
136
+ `\n unpinned:`,unpinned);
137
+ process.exit(ok ? 0 : 1);