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

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 (157) 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 +4 -4
  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 +2 -2
  16. package/.next/server/app/_not-found.segments/_full.segment.rsc +2 -2
  17. package/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  18. package/.next/server/app/_not-found.segments/_index.segment.rsc +2 -2
  19. package/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  20. package/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  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 +2 -2
  25. package/.next/server/app/admin.segments/_full.segment.rsc +2 -2
  26. package/.next/server/app/admin.segments/_head.segment.rsc +1 -1
  27. package/.next/server/app/admin.segments/_index.segment.rsc +2 -2
  28. package/.next/server/app/admin.segments/_tree.segment.rsc +2 -2
  29. package/.next/server/app/admin.segments/admin/__PAGE__.segment.rsc +1 -1
  30. package/.next/server/app/admin.segments/admin.segment.rsc +1 -1
  31. package/.next/server/app/index.html +2 -2
  32. package/.next/server/app/index.rsc +3 -3
  33. package/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  34. package/.next/server/app/index.segments/_full.segment.rsc +3 -3
  35. package/.next/server/app/index.segments/_head.segment.rsc +1 -1
  36. package/.next/server/app/index.segments/_index.segment.rsc +2 -2
  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 +3 -3
  41. package/.next/server/app/login.segments/_full.segment.rsc +3 -3
  42. package/.next/server/app/login.segments/_head.segment.rsc +1 -1
  43. package/.next/server/app/login.segments/_index.segment.rsc +2 -2
  44. package/.next/server/app/login.segments/_tree.segment.rsc +2 -2
  45. package/.next/server/app/login.segments/login/__PAGE__.segment.rsc +2 -2
  46. package/.next/server/app/login.segments/login.segment.rsc +1 -1
  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 +2 -2
  50. package/.next/server/app/logs.segments/_full.segment.rsc +2 -2
  51. package/.next/server/app/logs.segments/_head.segment.rsc +1 -1
  52. package/.next/server/app/logs.segments/_index.segment.rsc +2 -2
  53. package/.next/server/app/logs.segments/_tree.segment.rsc +2 -2
  54. package/.next/server/app/logs.segments/logs/__PAGE__.segment.rsc +1 -1
  55. package/.next/server/app/logs.segments/logs.segment.rsc +1 -1
  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 +2 -2
  59. package/.next/server/app/messages.segments/_full.segment.rsc +2 -2
  60. package/.next/server/app/messages.segments/_head.segment.rsc +1 -1
  61. package/.next/server/app/messages.segments/_index.segment.rsc +2 -2
  62. package/.next/server/app/messages.segments/_tree.segment.rsc +2 -2
  63. package/.next/server/app/messages.segments/messages/__PAGE__.segment.rsc +1 -1
  64. package/.next/server/app/messages.segments/messages.segment.rsc +1 -1
  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 +2 -2
  68. package/.next/server/app/node.segments/_full.segment.rsc +2 -2
  69. package/.next/server/app/node.segments/_head.segment.rsc +1 -1
  70. package/.next/server/app/node.segments/_index.segment.rsc +2 -2
  71. package/.next/server/app/node.segments/_tree.segment.rsc +2 -2
  72. package/.next/server/app/node.segments/node/__PAGE__.segment.rsc +1 -1
  73. package/.next/server/app/node.segments/node.segment.rsc +1 -1
  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 +2 -2
  77. package/.next/server/app/nodes.segments/_full.segment.rsc +2 -2
  78. package/.next/server/app/nodes.segments/_head.segment.rsc +1 -1
  79. package/.next/server/app/nodes.segments/_index.segment.rsc +2 -2
  80. package/.next/server/app/nodes.segments/_tree.segment.rsc +2 -2
  81. package/.next/server/app/nodes.segments/nodes/__PAGE__.segment.rsc +1 -1
  82. package/.next/server/app/nodes.segments/nodes.segment.rsc +1 -1
  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 +2 -2
  87. package/.next/server/app/server-logs.segments/_full.segment.rsc +2 -2
  88. package/.next/server/app/server-logs.segments/_head.segment.rsc +1 -1
  89. package/.next/server/app/server-logs.segments/_index.segment.rsc +2 -2
  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 +1 -1
  92. package/.next/server/app/server-logs.segments/server-logs.segment.rsc +1 -1
  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 +2 -2
  96. package/.next/server/app/settings/networks.segments/_full.segment.rsc +2 -2
  97. package/.next/server/app/settings/networks.segments/_head.segment.rsc +1 -1
  98. package/.next/server/app/settings/networks.segments/_index.segment.rsc +2 -2
  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 +1 -1
  101. package/.next/server/app/settings/networks.segments/settings/networks.segment.rsc +1 -1
  102. package/.next/server/app/settings/networks.segments/settings.segment.rsc +1 -1
  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 +2 -2
  107. package/.next/server/app/settings/tokens.segments/_full.segment.rsc +2 -2
  108. package/.next/server/app/settings/tokens.segments/_head.segment.rsc +1 -1
  109. package/.next/server/app/settings/tokens.segments/_index.segment.rsc +2 -2
  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 +1 -1
  112. package/.next/server/app/settings/tokens.segments/settings/tokens.segment.rsc +1 -1
  113. package/.next/server/app/settings/tokens.segments/settings.segment.rsc +1 -1
  114. package/.next/server/app/settings.html +2 -2
  115. package/.next/server/app/settings.rsc +3 -3
  116. package/.next/server/app/settings.segments/_full.segment.rsc +3 -3
  117. package/.next/server/app/settings.segments/_head.segment.rsc +1 -1
  118. package/.next/server/app/settings.segments/_index.segment.rsc +2 -2
  119. package/.next/server/app/settings.segments/_tree.segment.rsc +2 -2
  120. package/.next/server/app/settings.segments/settings/__PAGE__.segment.rsc +2 -2
  121. package/.next/server/app/settings.segments/settings.segment.rsc +1 -1
  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 +2 -2
  126. package/.next/server/app/tasks.segments/_full.segment.rsc +2 -2
  127. package/.next/server/app/tasks.segments/_head.segment.rsc +1 -1
  128. package/.next/server/app/tasks.segments/_index.segment.rsc +2 -2
  129. package/.next/server/app/tasks.segments/_tree.segment.rsc +2 -2
  130. package/.next/server/app/tasks.segments/tasks/__PAGE__.segment.rsc +1 -1
  131. package/.next/server/app/tasks.segments/tasks.segment.rsc +1 -1
  132. package/.next/server/chunks/ssr/agent-network-dashboard_09kk21a._.js +1 -1
  133. package/.next/server/chunks/ssr/agent-network-dashboard_09kk21a._.js.map +1 -1
  134. package/.next/server/chunks/ssr/agent-network-dashboard_app_01jhlxz._.js +1 -1
  135. package/.next/server/chunks/ssr/agent-network-dashboard_app_01jhlxz._.js.map +1 -1
  136. package/.next/server/chunks/ssr/agent-network-dashboard_app_09d29my._.js +1 -1
  137. package/.next/server/chunks/ssr/agent-network-dashboard_app_09d29my._.js.map +1 -1
  138. package/.next/server/middleware-build-manifest.js +3 -3
  139. package/.next/server/pages/404.html +2 -2
  140. package/.next/server/pages/500.html +1 -1
  141. package/.next/server/server-reference-manifest.js +1 -1
  142. package/.next/server/server-reference-manifest.json +1 -1
  143. package/.next/static/chunks/{0y8v4grez.a76.js → 01nhr7-qa0bpn.js} +1 -1
  144. package/.next/static/chunks/{0sjqjenh7~k-j.js → 0f2hte6kip4g2.js} +1 -1
  145. package/.next/static/chunks/0o_7k8ylvvs__.js +1 -0
  146. package/.next/static/chunks/{09nd.t_hd.y6t.css → 13.zti9ix.1eh.css} +1 -1
  147. package/.next/trace +2 -2
  148. package/.next/trace-build +1 -1
  149. package/app/components/TopoGraph.tsx +84 -9
  150. package/package.json +1 -1
  151. package/scripts/topo-auto-fit-test.mjs +73 -0
  152. package/scripts/topo-label-lift-test.mjs +115 -0
  153. package/scripts/topo-overlap-test.mjs +32 -5
  154. package/.next/static/chunks/0_8snedeata9k.js +0 -1
  155. /package/.next/static/{Q3_3F7glo-M3CFrXA8POE → 2mfVL5BX6WSYKSYcpYe9i}/_buildManifest.js +0 -0
  156. /package/.next/static/{Q3_3F7glo-M3CFrXA8POE → 2mfVL5BX6WSYKSYcpYe9i}/_clientMiddlewareManifest.js +0 -0
  157. /package/.next/static/{Q3_3F7glo-M3CFrXA8POE → 2mfVL5BX6WSYKSYcpYe9i}/_ssgManifest.js +0 -0
package/.next/trace CHANGED
@@ -1,2 +1,2 @@
1
- [{"name":"generate-buildid","duration":273,"timestamp":13628053560,"id":4,"parentId":1,"tags":{},"startTime":1778821600300,"traceId":"a309209d9e3cd974"},{"name":"load-custom-routes","duration":465,"timestamp":13628053972,"id":5,"parentId":1,"tags":{},"startTime":1778821600300,"traceId":"a309209d9e3cd974"},{"name":"create-dist-dir","duration":646,"timestamp":13628054481,"id":6,"parentId":1,"tags":{},"startTime":1778821600301,"traceId":"a309209d9e3cd974"},{"name":"clean","duration":533,"timestamp":13628055711,"id":7,"parentId":1,"tags":{},"startTime":1778821600302,"traceId":"a309209d9e3cd974"},{"name":"discover-routes","duration":8766,"timestamp":13628137671,"id":8,"parentId":1,"tags":{},"startTime":1778821600384,"traceId":"a309209d9e3cd974"},{"name":"create-root-mapping","duration":106,"timestamp":13628146497,"id":9,"parentId":1,"tags":{},"startTime":1778821600393,"traceId":"a309209d9e3cd974"},{"name":"generate-route-types","duration":31514,"timestamp":13628148835,"id":10,"parentId":1,"tags":{},"startTime":1778821600395,"traceId":"a309209d9e3cd974"},{"name":"public-dir-conflict-check","duration":102,"timestamp":13628180499,"id":11,"parentId":1,"tags":{},"startTime":1778821600427,"traceId":"a309209d9e3cd974"},{"name":"generate-routes-manifest","duration":4198,"timestamp":13628180713,"id":12,"parentId":1,"tags":{},"startTime":1778821600427,"traceId":"a309209d9e3cd974"},{"name":"run-turbopack","duration":5479065,"timestamp":13628190383,"id":14,"parentId":1,"tags":{},"startTime":1778821600437,"traceId":"a309209d9e3cd974"},{"name":"turbopack-build-events","duration":101,"timestamp":13628544506,"id":15,"parentId":1,"tags":{},"startTime":1778821600791,"traceId":"a309209d9e3cd974"},{"name":"run-typescript","duration":8228736,"timestamp":13633684536,"id":16,"parentId":1,"tags":{},"startTime":1778821605931,"traceId":"a309209d9e3cd974"},{"name":"generate-required-server-files","duration":2417,"timestamp":13641914349,"id":18,"parentId":1,"tags":{},"startTime":1778821614161,"traceId":"a309209d9e3cd974"},{"name":"check-static-error-page","duration":11730,"timestamp":13642088721,"id":20,"parentId":19,"tags":{},"startTime":1778821614335,"traceId":"a309209d9e3cd974"},{"name":"is-page-static","duration":405245,"timestamp":13642102986,"id":63,"parentId":22,"tags":{},"startTime":1778821614349,"traceId":"a309209d9e3cd974"},{"name":"check-page","duration":417268,"timestamp":13642091130,"id":22,"parentId":19,"tags":{"page":"/_global-error"},"startTime":1778821614337,"traceId":"a309209d9e3cd974"},{"name":"is-page-static","duration":506064,"timestamp":13642107236,"id":69,"parentId":30,"tags":{},"startTime":1778821614354,"traceId":"a309209d9e3cd974"},{"name":"check-page","duration":519279,"timestamp":13642094120,"id":30,"parentId":19,"tags":{"page":"/api/hub/broadcast"},"startTime":1778821614340,"traceId":"a309209d9e3cd974"},{"name":"is-page-static","duration":517889,"timestamp":13642107436,"id":70,"parentId":32,"tags":{},"startTime":1778821614354,"traceId":"a309209d9e3cd974"},{"name":"check-page","duration":530977,"timestamp":13642094433,"id":32,"parentId":19,"tags":{"page":"/api/hub/health"},"startTime":1778821614341,"traceId":"a309209d9e3cd974"},{"name":"is-page-static","duration":535613,"timestamp":13642105500,"id":66,"parentId":27,"tags":{},"startTime":1778821614352,"traceId":"a309209d9e3cd974"},{"name":"check-page","duration":547398,"timestamp":13642093800,"id":27,"parentId":19,"tags":{"page":"/api/auth/v3"},"startTime":1778821614340,"traceId":"a309209d9e3cd974"},{"name":"is-page-static","duration":538782,"timestamp":13642107499,"id":71,"parentId":33,"tags":{},"startTime":1778821614354,"traceId":"a309209d9e3cd974"},{"name":"check-page","duration":551832,"timestamp":13642094526,"id":33,"parentId":19,"tags":{"page":"/api/hub/inbox"},"startTime":1778821614341,"traceId":"a309209d9e3cd974"},{"name":"is-page-static","duration":539150,"timestamp":13642107580,"id":72,"parentId":34,"tags":{},"startTime":1778821614354,"traceId":"a309209d9e3cd974"},{"name":"check-page","duration":552180,"timestamp":13642094606,"id":34,"parentId":19,"tags":{"page":"/api/hub/license"},"startTime":1778821614341,"traceId":"a309209d9e3cd974"},{"name":"is-page-static","duration":548639,"timestamp":13642107611,"id":73,"parentId":35,"tags":{},"startTime":1778821614354,"traceId":"a309209d9e3cd974"},{"name":"check-page","duration":561610,"timestamp":13642094709,"id":35,"parentId":19,"tags":{"page":"/api/hub/messages"},"startTime":1778821614341,"traceId":"a309209d9e3cd974"},{"name":"is-page-static","duration":549405,"timestamp":13642107760,"id":75,"parentId":37,"tags":{},"startTime":1778821614354,"traceId":"a309209d9e3cd974"},{"name":"check-page","duration":561979,"timestamp":13642095236,"id":37,"parentId":19,"tags":{"page":"/api/hub/nodes"},"startTime":1778821614342,"traceId":"a309209d9e3cd974"},{"name":"is-page-static","duration":555010,"timestamp":13642105957,"id":68,"parentId":29,"tags":{},"startTime":1778821614352,"traceId":"a309209d9e3cd974"},{"name":"check-page","duration":567066,"timestamp":13642093968,"id":29,"parentId":19,"tags":{"page":"/api/hub/auth"},"startTime":1778821614340,"traceId":"a309209d9e3cd974"},{"name":"is-page-static","duration":553977,"timestamp":13642107779,"id":76,"parentId":38,"tags":{},"startTime":1778821614354,"traceId":"a309209d9e3cd974"},{"name":"check-page","duration":566466,"timestamp":13642095330,"id":38,"parentId":19,"tags":{"page":"/api/hub/register"},"startTime":1778821614342,"traceId":"a309209d9e3cd974"},{"name":"is-page-static","duration":558833,"timestamp":13642103143,"id":64,"parentId":25,"tags":{},"startTime":1778821614349,"traceId":"a309209d9e3cd974"},{"name":"check-page","duration":568470,"timestamp":13642093557,"id":25,"parentId":19,"tags":{"page":"/api/auth/login"},"startTime":1778821614340,"traceId":"a309209d9e3cd974"},{"name":"is-page-static","duration":559815,"timestamp":13642105788,"id":67,"parentId":28,"tags":{},"startTime":1778821614352,"traceId":"a309209d9e3cd974"},{"name":"check-page","duration":571762,"timestamp":13642093886,"id":28,"parentId":19,"tags":{"page":"/api/hub/audit-log"},"startTime":1778821614340,"traceId":"a309209d9e3cd974"},{"name":"is-page-static","duration":558287,"timestamp":13642107802,"id":78,"parentId":40,"tags":{},"startTime":1778821614354,"traceId":"a309209d9e3cd974"},{"name":"check-page","duration":570671,"timestamp":13642095466,"id":40,"parentId":19,"tags":{"page":"/api/hub/server-logs"},"startTime":1778821614342,"traceId":"a309209d9e3cd974"},{"name":"is-page-static","duration":558527,"timestamp":13642107793,"id":77,"parentId":39,"tags":{},"startTime":1778821614354,"traceId":"a309209d9e3cd974"},{"name":"check-page","duration":571123,"timestamp":13642095400,"id":39,"parentId":19,"tags":{"page":"/api/hub/send"},"startTime":1778821614342,"traceId":"a309209d9e3cd974"},{"name":"is-page-static","duration":562642,"timestamp":13642107832,"id":80,"parentId":42,"tags":{},"startTime":1778821614354,"traceId":"a309209d9e3cd974"},{"name":"check-page","duration":574913,"timestamp":13642095608,"id":42,"parentId":19,"tags":{"page":"/api/hub/session"},"startTime":1778821614342,"traceId":"a309209d9e3cd974"},{"name":"is-page-static","duration":563474,"timestamp":13642107841,"id":81,"parentId":43,"tags":{},"startTime":1778821614354,"traceId":"a309209d9e3cd974"},{"name":"check-page","duration":575674,"timestamp":13642095691,"id":43,"parentId":19,"tags":{"page":"/api/hub/stats"},"startTime":1778821614342,"traceId":"a309209d9e3cd974"},{"name":"is-page-static","duration":568089,"timestamp":13642107879,"id":84,"parentId":46,"tags":{},"startTime":1778821614354,"traceId":"a309209d9e3cd974"},{"name":"check-page","duration":580010,"timestamp":13642096053,"id":46,"parentId":19,"tags":{"page":"/api/hub/tasks"},"startTime":1778821614342,"traceId":"a309209d9e3cd974"},{"name":"is-page-static","duration":572215,"timestamp":13642107816,"id":79,"parentId":41,"tags":{},"startTime":1778821614354,"traceId":"a309209d9e3cd974"},{"name":"check-page","duration":584540,"timestamp":13642095535,"id":41,"parentId":19,"tags":{"page":"/api/hub/servers"},"startTime":1778821614342,"traceId":"a309209d9e3cd974"},{"name":"is-page-static","duration":572758,"timestamp":13642107891,"id":85,"parentId":47,"tags":{},"startTime":1778821614354,"traceId":"a309209d9e3cd974"},{"name":"check-page","duration":584513,"timestamp":13642096190,"id":47,"parentId":19,"tags":{"page":"/api/hub/tmux"},"startTime":1778821614342,"traceId":"a309209d9e3cd974"},{"name":"is-page-static","duration":580470,"timestamp":13642107727,"id":74,"parentId":36,"tags":{},"startTime":1778821614354,"traceId":"a309209d9e3cd974"},{"name":"check-page","duration":593148,"timestamp":13642095092,"id":36,"parentId":19,"tags":{"page":"/api/hub/networks"},"startTime":1778821614341,"traceId":"a309209d9e3cd974"},{"name":"is-page-static","duration":583030,"timestamp":13642107903,"id":86,"parentId":48,"tags":{},"startTime":1778821614354,"traceId":"a309209d9e3cd974"},{"name":"check-page","duration":593164,"timestamp":13642097814,"id":48,"parentId":19,"tags":{"page":"/api/hub/tokens"},"startTime":1778821614344,"traceId":"a309209d9e3cd974"},{"name":"is-page-static","duration":588559,"timestamp":13642107916,"id":87,"parentId":49,"tags":{},"startTime":1778821614354,"traceId":"a309209d9e3cd974"},{"name":"check-page","duration":598612,"timestamp":13642097906,"id":49,"parentId":19,"tags":{"page":"/favicon.ico"},"startTime":1778821614344,"traceId":"a309209d9e3cd974"},{"name":"is-page-static","duration":585423,"timestamp":13642111832,"id":88,"parentId":24,"tags":{},"startTime":1778821614358,"traceId":"a309209d9e3cd974"},{"name":"check-page","duration":605770,"timestamp":13642091527,"id":24,"parentId":19,"tags":{"page":"/api/anet/config"},"startTime":1778821614338,"traceId":"a309209d9e3cd974"},{"name":"is-page-static","duration":584452,"timestamp":13642112999,"id":89,"parentId":31,"tags":{},"startTime":1778821614359,"traceId":"a309209d9e3cd974"},{"name":"check-page","duration":603257,"timestamp":13642094222,"id":31,"parentId":19,"tags":{"page":"/api/hub/events"},"startTime":1778821614340,"traceId":"a309209d9e3cd974"},{"name":"is-page-static","duration":597664,"timestamp":13642102652,"id":62,"parentId":21,"tags":{},"startTime":1778821614349,"traceId":"a309209d9e3cd974"},{"name":"check-page","duration":610413,"timestamp":13642089945,"id":21,"parentId":19,"tags":{"page":"/_not-found"},"startTime":1778821614336,"traceId":"a309209d9e3cd974"},{"name":"is-page-static","duration":592632,"timestamp":13642107867,"id":83,"parentId":45,"tags":{},"startTime":1778821614354,"traceId":"a309209d9e3cd974"},{"name":"check-page","duration":604594,"timestamp":13642095935,"id":45,"parentId":19,"tags":{"page":"/api/hub/task-events"},"startTime":1778821614342,"traceId":"a309209d9e3cd974"},{"name":"is-page-static","duration":606733,"timestamp":13642107854,"id":82,"parentId":44,"tags":{},"startTime":1778821614354,"traceId":"a309209d9e3cd974"},{"name":"check-page","duration":618881,"timestamp":13642095793,"id":44,"parentId":19,"tags":{"page":"/api/hub/status"},"startTime":1778821614342,"traceId":"a309209d9e3cd974"},{"name":"is-page-static","duration":615025,"timestamp":13642104378,"id":65,"parentId":26,"tags":{},"startTime":1778821614351,"traceId":"a309209d9e3cd974"},{"name":"check-page","duration":625749,"timestamp":13642093715,"id":26,"parentId":19,"tags":{"page":"/api/auth/logout"},"startTime":1778821614340,"traceId":"a309209d9e3cd974"},{"name":"is-page-static","duration":632201,"timestamp":13642115391,"id":93,"parentId":52,"tags":{},"startTime":1778821614362,"traceId":"a309209d9e3cd974"},{"name":"check-page","duration":649168,"timestamp":13642098522,"id":52,"parentId":19,"tags":{"page":"/messages"},"startTime":1778821614345,"traceId":"a309209d9e3cd974"},{"name":"is-page-static","duration":639920,"timestamp":13642115433,"id":97,"parentId":57,"tags":{},"startTime":1778821614362,"traceId":"a309209d9e3cd974"},{"name":"check-page","duration":655865,"timestamp":13642099588,"id":57,"parentId":19,"tags":{"page":"/settings/networks"},"startTime":1778821614346,"traceId":"a309209d9e3cd974"},{"name":"is-page-static","duration":643281,"timestamp":13642115335,"id":90,"parentId":23,"tags":{},"startTime":1778821614362,"traceId":"a309209d9e3cd974"},{"name":"check-page","duration":667337,"timestamp":13642091351,"id":23,"parentId":19,"tags":{"page":"/admin"},"startTime":1778821614338,"traceId":"a309209d9e3cd974"},{"name":"is-page-static","duration":648270,"timestamp":13642115445,"id":98,"parentId":59,"tags":{},"startTime":1778821614362,"traceId":"a309209d9e3cd974"},{"name":"check-page","duration":663750,"timestamp":13642100023,"id":59,"parentId":19,"tags":{"page":"/settings/tokens"},"startTime":1778821614346,"traceId":"a309209d9e3cd974"},{"name":"is-page-static","duration":659607,"timestamp":13642115475,"id":100,"parentId":61,"tags":{},"startTime":1778821614362,"traceId":"a309209d9e3cd974"},{"name":"check-page","duration":674905,"timestamp":13642100274,"id":61,"parentId":19,"tags":{"page":"/tasks"},"startTime":1778821614347,"traceId":"a309209d9e3cd974"},{"name":"is-page-static","duration":659952,"timestamp":13642115461,"id":99,"parentId":60,"tags":{},"startTime":1778821614362,"traceId":"a309209d9e3cd974"},{"name":"check-page","duration":675310,"timestamp":13642100165,"id":60,"parentId":19,"tags":{"page":"/tasks/[id]"},"startTime":1778821614346,"traceId":"a309209d9e3cd974"},{"name":"is-page-static","duration":658661,"timestamp":13642121278,"id":101,"parentId":58,"tags":{},"startTime":1778821614368,"traceId":"a309209d9e3cd974"},{"name":"check-page","duration":680260,"timestamp":13642099723,"id":58,"parentId":19,"tags":{"page":"/settings"},"startTime":1778821614346,"traceId":"a309209d9e3cd974"},{"name":"is-page-static","duration":666964,"timestamp":13642115402,"id":94,"parentId":53,"tags":{},"startTime":1778821614362,"traceId":"a309209d9e3cd974"},{"name":"check-page","duration":683719,"timestamp":13642098693,"id":53,"parentId":19,"tags":{"page":"/node"},"startTime":1778821614345,"traceId":"a309209d9e3cd974"},{"name":"is-page-static","duration":646426,"timestamp":13642137498,"id":102,"parentId":55,"tags":{},"startTime":1778821614384,"traceId":"a309209d9e3cd974"},{"name":"check-page","duration":684923,"timestamp":13642099038,"id":55,"parentId":19,"tags":{"page":"/"},"startTime":1778821614345,"traceId":"a309209d9e3cd974"},{"name":"is-page-static","duration":671621,"timestamp":13642115414,"id":95,"parentId":54,"tags":{},"startTime":1778821614362,"traceId":"a309209d9e3cd974"},{"name":"check-page","duration":688236,"timestamp":13642098841,"id":54,"parentId":19,"tags":{"page":"/nodes"},"startTime":1778821614345,"traceId":"a309209d9e3cd974"},{"name":"is-page-static","duration":678792,"timestamp":13642115365,"id":91,"parentId":50,"tags":{},"startTime":1778821614362,"traceId":"a309209d9e3cd974"},{"name":"check-page","duration":695940,"timestamp":13642098252,"id":50,"parentId":19,"tags":{"page":"/login"},"startTime":1778821614345,"traceId":"a309209d9e3cd974"},{"name":"is-page-static","duration":679762,"timestamp":13642115381,"id":92,"parentId":51,"tags":{},"startTime":1778821614362,"traceId":"a309209d9e3cd974"},{"name":"check-page","duration":696793,"timestamp":13642098370,"id":51,"parentId":19,"tags":{"page":"/logs"},"startTime":1778821614345,"traceId":"a309209d9e3cd974"},{"name":"is-page-static","duration":685770,"timestamp":13642115421,"id":96,"parentId":56,"tags":{},"startTime":1778821614362,"traceId":"a309209d9e3cd974"},{"name":"check-page","duration":701782,"timestamp":13642099439,"id":56,"parentId":19,"tags":{"page":"/server-logs"},"startTime":1778821614346,"traceId":"a309209d9e3cd974"},{"name":"static-check","duration":713353,"timestamp":13642087907,"id":19,"parentId":1,"tags":{},"startTime":1778821614334,"traceId":"a309209d9e3cd974"},{"name":"write-routes-manifest","duration":584,"timestamp":13642807582,"id":104,"parentId":1,"tags":{},"startTime":1778821615054,"traceId":"a309209d9e3cd974"},{"name":"load-dotenv","duration":53,"timestamp":13642820613,"id":107,"parentId":106,"tags":{},"startTime":1778821615067,"traceId":"a309209d9e3cd974"},{"name":"run-export-path-map","duration":590,"timestamp":13642824408,"id":108,"parentId":106,"tags":{},"startTime":1778821615071,"traceId":"a309209d9e3cd974"},{"name":"next-export","duration":630839,"timestamp":13642819435,"id":106,"parentId":1,"tags":{},"startTime":1778821615066,"traceId":"a309209d9e3cd974"}]
2
- [{"name":"move-exported-app-not-found-","duration":2466,"timestamp":13643453674,"id":109,"parentId":105,"tags":{},"startTime":1778821615700,"traceId":"a309209d9e3cd974"},{"name":"move-exported-app-global-error-","duration":655,"timestamp":13643456260,"id":110,"parentId":105,"tags":{},"startTime":1778821615703,"traceId":"a309209d9e3cd974"},{"name":"static-generation","duration":644399,"timestamp":13642814237,"id":105,"parentId":1,"tags":{},"startTime":1778821615061,"traceId":"a309209d9e3cd974"},{"name":"write-routes-manifest","duration":382,"timestamp":13643458802,"id":111,"parentId":1,"tags":{},"startTime":1778821615705,"traceId":"a309209d9e3cd974"},{"name":"print-tree-view","duration":4889,"timestamp":13643476023,"id":112,"parentId":1,"tags":{},"startTime":1778821615722,"traceId":"a309209d9e3cd974"},{"name":"write-route-bundle-stats","duration":12383,"timestamp":13643480941,"id":113,"parentId":1,"tags":{},"startTime":1778821615727,"traceId":"a309209d9e3cd974"},{"name":"telemetry-flush","duration":22192,"timestamp":13643493351,"id":114,"parentId":1,"tags":{},"startTime":1778821615740,"traceId":"a309209d9e3cd974"},{"name":"next-build","duration":15511487,"timestamp":13628004086,"id":1,"tags":{"buildMode":"default","version":"16.2.3","bundler":"turbopack","has-custom-webpack-config":"false","use-build-worker":"true"},"startTime":1778821600250,"traceId":"a309209d9e3cd974"}]
1
+ [{"name":"generate-buildid","duration":386,"timestamp":15191724542,"id":4,"parentId":1,"tags":{},"startTime":1778823163971,"traceId":"b3d43d52a98272bb"},{"name":"load-custom-routes","duration":665,"timestamp":15191725190,"id":5,"parentId":1,"tags":{},"startTime":1778823163971,"traceId":"b3d43d52a98272bb"},{"name":"create-dist-dir","duration":866,"timestamp":15191725911,"id":6,"parentId":1,"tags":{},"startTime":1778823163972,"traceId":"b3d43d52a98272bb"},{"name":"clean","duration":437,"timestamp":15191727472,"id":7,"parentId":1,"tags":{},"startTime":1778823163974,"traceId":"b3d43d52a98272bb"},{"name":"discover-routes","duration":11292,"timestamp":15191810563,"id":8,"parentId":1,"tags":{},"startTime":1778823164057,"traceId":"b3d43d52a98272bb"},{"name":"create-root-mapping","duration":244,"timestamp":15191821956,"id":9,"parentId":1,"tags":{},"startTime":1778823164068,"traceId":"b3d43d52a98272bb"},{"name":"generate-route-types","duration":32915,"timestamp":15191824910,"id":10,"parentId":1,"tags":{},"startTime":1778823164071,"traceId":"b3d43d52a98272bb"},{"name":"public-dir-conflict-check","duration":135,"timestamp":15191857977,"id":11,"parentId":1,"tags":{},"startTime":1778823164104,"traceId":"b3d43d52a98272bb"},{"name":"generate-routes-manifest","duration":4491,"timestamp":15191858234,"id":12,"parentId":1,"tags":{},"startTime":1778823164105,"traceId":"b3d43d52a98272bb"},{"name":"run-turbopack","duration":5382748,"timestamp":15191867363,"id":14,"parentId":1,"tags":{},"startTime":1778823164114,"traceId":"b3d43d52a98272bb"},{"name":"turbopack-build-events","duration":109,"timestamp":15192151702,"id":15,"parentId":1,"tags":{},"startTime":1778823164398,"traceId":"b3d43d52a98272bb"},{"name":"run-typescript","duration":8087949,"timestamp":15197258858,"id":16,"parentId":1,"tags":{},"startTime":1778823169505,"traceId":"b3d43d52a98272bb"},{"name":"generate-required-server-files","duration":2298,"timestamp":15205347970,"id":18,"parentId":1,"tags":{},"startTime":1778823177594,"traceId":"b3d43d52a98272bb"},{"name":"check-static-error-page","duration":13427,"timestamp":15205574262,"id":20,"parentId":19,"tags":{},"startTime":1778823177821,"traceId":"b3d43d52a98272bb"},{"name":"is-page-static","duration":425672,"timestamp":15205590189,"id":63,"parentId":22,"tags":{},"startTime":1778823177836,"traceId":"b3d43d52a98272bb"},{"name":"check-page","duration":438348,"timestamp":15205577693,"id":22,"parentId":19,"tags":{"page":"/_global-error"},"startTime":1778823177824,"traceId":"b3d43d52a98272bb"},{"name":"is-page-static","duration":575883,"timestamp":15205591164,"id":69,"parentId":30,"tags":{},"startTime":1778823177837,"traceId":"b3d43d52a98272bb"},{"name":"check-page","duration":585067,"timestamp":15205582076,"id":30,"parentId":19,"tags":{"page":"/api/hub/broadcast"},"startTime":1778823177828,"traceId":"b3d43d52a98272bb"},{"name":"is-page-static","duration":589003,"timestamp":15205590425,"id":65,"parentId":26,"tags":{},"startTime":1778823177837,"traceId":"b3d43d52a98272bb"},{"name":"check-page","duration":597995,"timestamp":15205581513,"id":26,"parentId":19,"tags":{"page":"/api/auth/logout"},"startTime":1778823177828,"traceId":"b3d43d52a98272bb"},{"name":"is-page-static","duration":588728,"timestamp":15205590988,"id":68,"parentId":29,"tags":{},"startTime":1778823177837,"traceId":"b3d43d52a98272bb"},{"name":"check-page","duration":597877,"timestamp":15205581907,"id":29,"parentId":19,"tags":{"page":"/api/hub/auth"},"startTime":1778823177828,"traceId":"b3d43d52a98272bb"},{"name":"is-page-static","duration":589468,"timestamp":15205591386,"id":70,"parentId":32,"tags":{},"startTime":1778823177838,"traceId":"b3d43d52a98272bb"},{"name":"check-page","duration":598375,"timestamp":15205582533,"id":32,"parentId":19,"tags":{"page":"/api/hub/health"},"startTime":1778823177829,"traceId":"b3d43d52a98272bb"},{"name":"is-page-static","duration":591710,"timestamp":15205589828,"id":62,"parentId":21,"tags":{},"startTime":1778823177836,"traceId":"b3d43d52a98272bb"},{"name":"check-page","duration":605655,"timestamp":15205576032,"id":21,"parentId":19,"tags":{"page":"/_not-found"},"startTime":1778823177822,"traceId":"b3d43d52a98272bb"},{"name":"is-page-static","duration":595334,"timestamp":15205590829,"id":67,"parentId":28,"tags":{},"startTime":1778823177837,"traceId":"b3d43d52a98272bb"},{"name":"check-page","duration":604443,"timestamp":15205581772,"id":28,"parentId":19,"tags":{"page":"/api/hub/audit-log"},"startTime":1778823177828,"traceId":"b3d43d52a98272bb"},{"name":"is-page-static","duration":597036,"timestamp":15205591463,"id":71,"parentId":33,"tags":{},"startTime":1778823177838,"traceId":"b3d43d52a98272bb"},{"name":"check-page","duration":605846,"timestamp":15205582700,"id":33,"parentId":19,"tags":{"page":"/api/hub/inbox"},"startTime":1778823177829,"traceId":"b3d43d52a98272bb"},{"name":"is-page-static","duration":603773,"timestamp":15205591579,"id":73,"parentId":35,"tags":{},"startTime":1778823177838,"traceId":"b3d43d52a98272bb"},{"name":"check-page","duration":612405,"timestamp":15205582989,"id":35,"parentId":19,"tags":{"page":"/api/hub/messages"},"startTime":1778823177829,"traceId":"b3d43d52a98272bb"},{"name":"is-page-static","duration":605118,"timestamp":15205590545,"id":66,"parentId":27,"tags":{},"startTime":1778823177837,"traceId":"b3d43d52a98272bb"},{"name":"check-page","duration":614054,"timestamp":15205581648,"id":27,"parentId":19,"tags":{"page":"/api/auth/v3"},"startTime":1778823177828,"traceId":"b3d43d52a98272bb"},{"name":"is-page-static","duration":604063,"timestamp":15205591752,"id":76,"parentId":38,"tags":{},"startTime":1778823177838,"traceId":"b3d43d52a98272bb"},{"name":"check-page","duration":611908,"timestamp":15205583933,"id":38,"parentId":19,"tags":{"page":"/api/hub/register"},"startTime":1778823177830,"traceId":"b3d43d52a98272bb"},{"name":"is-page-static","duration":609842,"timestamp":15205591796,"id":79,"parentId":41,"tags":{},"startTime":1778823177838,"traceId":"b3d43d52a98272bb"},{"name":"check-page","duration":617471,"timestamp":15205584217,"id":41,"parentId":19,"tags":{"page":"/api/hub/servers"},"startTime":1778823177830,"traceId":"b3d43d52a98272bb"},{"name":"is-page-static","duration":615679,"timestamp":15205591769,"id":77,"parentId":39,"tags":{},"startTime":1778823177838,"traceId":"b3d43d52a98272bb"},{"name":"check-page","duration":623428,"timestamp":15205584066,"id":39,"parentId":19,"tags":{"page":"/api/hub/send"},"startTime":1778823177830,"traceId":"b3d43d52a98272bb"},{"name":"is-page-static","duration":616317,"timestamp":15205591545,"id":72,"parentId":34,"tags":{},"startTime":1778823177838,"traceId":"b3d43d52a98272bb"},{"name":"check-page","duration":625056,"timestamp":15205582841,"id":34,"parentId":19,"tags":{"page":"/api/hub/license"},"startTime":1778823177829,"traceId":"b3d43d52a98272bb"},{"name":"is-page-static","duration":616812,"timestamp":15205591813,"id":80,"parentId":42,"tags":{},"startTime":1778823177838,"traceId":"b3d43d52a98272bb"},{"name":"check-page","duration":624361,"timestamp":15205584307,"id":42,"parentId":19,"tags":{"page":"/api/hub/session"},"startTime":1778823177831,"traceId":"b3d43d52a98272bb"},{"name":"is-page-static","duration":623131,"timestamp":15205591856,"id":83,"parentId":45,"tags":{},"startTime":1778823177838,"traceId":"b3d43d52a98272bb"},{"name":"check-page","duration":630531,"timestamp":15205584514,"id":45,"parentId":19,"tags":{"page":"/api/hub/task-events"},"startTime":1778823177831,"traceId":"b3d43d52a98272bb"},{"name":"is-page-static","duration":625290,"timestamp":15205591735,"id":75,"parentId":37,"tags":{},"startTime":1778823177838,"traceId":"b3d43d52a98272bb"},{"name":"check-page","duration":633307,"timestamp":15205583769,"id":37,"parentId":19,"tags":{"page":"/api/hub/nodes"},"startTime":1778823177830,"traceId":"b3d43d52a98272bb"},{"name":"is-page-static","duration":629464,"timestamp":15205591829,"id":81,"parentId":43,"tags":{},"startTime":1778823177838,"traceId":"b3d43d52a98272bb"},{"name":"check-page","duration":636952,"timestamp":15205584378,"id":43,"parentId":19,"tags":{"page":"/api/hub/stats"},"startTime":1778823177831,"traceId":"b3d43d52a98272bb"},{"name":"is-page-static","duration":630757,"timestamp":15205591871,"id":84,"parentId":46,"tags":{},"startTime":1778823177838,"traceId":"b3d43d52a98272bb"},{"name":"check-page","duration":638087,"timestamp":15205584581,"id":46,"parentId":19,"tags":{"page":"/api/hub/tasks"},"startTime":1778823177831,"traceId":"b3d43d52a98272bb"},{"name":"is-page-static","duration":634092,"timestamp":15205591784,"id":78,"parentId":40,"tags":{},"startTime":1778823177838,"traceId":"b3d43d52a98272bb"},{"name":"check-page","duration":641772,"timestamp":15205584148,"id":40,"parentId":19,"tags":{"page":"/api/hub/server-logs"},"startTime":1778823177830,"traceId":"b3d43d52a98272bb"},{"name":"is-page-static","duration":641810,"timestamp":15205591844,"id":82,"parentId":44,"tags":{},"startTime":1778823177838,"traceId":"b3d43d52a98272bb"},{"name":"check-page","duration":649254,"timestamp":15205584445,"id":44,"parentId":19,"tags":{"page":"/api/hub/status"},"startTime":1778823177831,"traceId":"b3d43d52a98272bb"},{"name":"is-page-static","duration":634377,"timestamp":15205599459,"id":88,"parentId":24,"tags":{},"startTime":1778823177846,"traceId":"b3d43d52a98272bb"},{"name":"check-page","duration":655533,"timestamp":15205578337,"id":24,"parentId":19,"tags":{"page":"/api/anet/config"},"startTime":1778823177825,"traceId":"b3d43d52a98272bb"},{"name":"is-page-static","duration":639086,"timestamp":15205600646,"id":89,"parentId":31,"tags":{},"startTime":1778823177847,"traceId":"b3d43d52a98272bb"},{"name":"check-page","duration":657565,"timestamp":15205582210,"id":31,"parentId":19,"tags":{"page":"/api/hub/events"},"startTime":1778823177828,"traceId":"b3d43d52a98272bb"},{"name":"is-page-static","duration":654886,"timestamp":15205591899,"id":86,"parentId":48,"tags":{},"startTime":1778823177838,"traceId":"b3d43d52a98272bb"},{"name":"check-page","duration":662093,"timestamp":15205584745,"id":48,"parentId":19,"tags":{"page":"/api/hub/tokens"},"startTime":1778823177831,"traceId":"b3d43d52a98272bb"},{"name":"is-page-static","duration":655121,"timestamp":15205591914,"id":87,"parentId":49,"tags":{},"startTime":1778823177838,"traceId":"b3d43d52a98272bb"},{"name":"check-page","duration":662269,"timestamp":15205584810,"id":49,"parentId":19,"tags":{"page":"/favicon.ico"},"startTime":1778823177831,"traceId":"b3d43d52a98272bb"},{"name":"is-page-static","duration":662723,"timestamp":15205591886,"id":85,"parentId":47,"tags":{},"startTime":1778823177838,"traceId":"b3d43d52a98272bb"},{"name":"check-page","duration":669984,"timestamp":15205584674,"id":47,"parentId":19,"tags":{"page":"/api/hub/tmux"},"startTime":1778823177831,"traceId":"b3d43d52a98272bb"},{"name":"is-page-static","duration":681664,"timestamp":15205590307,"id":64,"parentId":25,"tags":{},"startTime":1778823177837,"traceId":"b3d43d52a98272bb"},{"name":"check-page","duration":690749,"timestamp":15205581323,"id":25,"parentId":19,"tags":{"page":"/api/auth/login"},"startTime":1778823177828,"traceId":"b3d43d52a98272bb"},{"name":"is-page-static","duration":699852,"timestamp":15205591699,"id":74,"parentId":36,"tags":{},"startTime":1778823177838,"traceId":"b3d43d52a98272bb"},{"name":"check-page","duration":708070,"timestamp":15205583548,"id":36,"parentId":19,"tags":{"page":"/api/hub/networks"},"startTime":1778823177830,"traceId":"b3d43d52a98272bb"},{"name":"is-page-static","duration":703297,"timestamp":15205603300,"id":96,"parentId":56,"tags":{},"startTime":1778823177850,"traceId":"b3d43d52a98272bb"},{"name":"check-page","duration":720151,"timestamp":15205586517,"id":56,"parentId":19,"tags":{"page":"/server-logs"},"startTime":1778823177833,"traceId":"b3d43d52a98272bb"},{"name":"is-page-static","duration":704604,"timestamp":15205603205,"id":91,"parentId":50,"tags":{},"startTime":1778823177849,"traceId":"b3d43d52a98272bb"},{"name":"check-page","duration":722696,"timestamp":15205585166,"id":50,"parentId":19,"tags":{"page":"/login"},"startTime":1778823177831,"traceId":"b3d43d52a98272bb"},{"name":"is-page-static","duration":709688,"timestamp":15205603218,"id":92,"parentId":51,"tags":{},"startTime":1778823177849,"traceId":"b3d43d52a98272bb"},{"name":"check-page","duration":727654,"timestamp":15205585309,"id":51,"parentId":19,"tags":{"page":"/logs"},"startTime":1778823177832,"traceId":"b3d43d52a98272bb"},{"name":"is-page-static","duration":711734,"timestamp":15205603317,"id":97,"parentId":57,"tags":{},"startTime":1778823177850,"traceId":"b3d43d52a98272bb"},{"name":"check-page","duration":728400,"timestamp":15205586697,"id":57,"parentId":19,"tags":{"page":"/settings/networks"},"startTime":1778823177833,"traceId":"b3d43d52a98272bb"},{"name":"is-page-static","duration":712473,"timestamp":15205603334,"id":98,"parentId":59,"tags":{},"startTime":1778823177850,"traceId":"b3d43d52a98272bb"},{"name":"check-page","duration":728652,"timestamp":15205587212,"id":59,"parentId":19,"tags":{"page":"/settings/tokens"},"startTime":1778823177833,"traceId":"b3d43d52a98272bb"},{"name":"is-page-static","duration":719606,"timestamp":15205603372,"id":100,"parentId":61,"tags":{},"startTime":1778823177850,"traceId":"b3d43d52a98272bb"},{"name":"check-page","duration":735567,"timestamp":15205587470,"id":61,"parentId":19,"tags":{"page":"/tasks"},"startTime":1778823177834,"traceId":"b3d43d52a98272bb"},{"name":"is-page-static","duration":720362,"timestamp":15205603235,"id":93,"parentId":52,"tags":{},"startTime":1778823177850,"traceId":"b3d43d52a98272bb"},{"name":"check-page","duration":738184,"timestamp":15205585454,"id":52,"parentId":19,"tags":{"page":"/messages"},"startTime":1778823177832,"traceId":"b3d43d52a98272bb"},{"name":"is-page-static","duration":715098,"timestamp":15205608820,"id":101,"parentId":58,"tags":{},"startTime":1778823177855,"traceId":"b3d43d52a98272bb"},{"name":"check-page","duration":737134,"timestamp":15205586859,"id":58,"parentId":19,"tags":{"page":"/settings"},"startTime":1778823177833,"traceId":"b3d43d52a98272bb"},{"name":"is-page-static","duration":722731,"timestamp":15205603351,"id":99,"parentId":60,"tags":{},"startTime":1778823177850,"traceId":"b3d43d52a98272bb"},{"name":"check-page","duration":738776,"timestamp":15205587350,"id":60,"parentId":19,"tags":{"page":"/tasks/[id]"},"startTime":1778823177834,"traceId":"b3d43d52a98272bb"},{"name":"is-page-static","duration":714478,"timestamp":15205617130,"id":102,"parentId":55,"tags":{},"startTime":1778823177863,"traceId":"b3d43d52a98272bb"},{"name":"check-page","duration":745613,"timestamp":15205586038,"id":55,"parentId":19,"tags":{"page":"/"},"startTime":1778823177832,"traceId":"b3d43d52a98272bb"},{"name":"is-page-static","duration":728481,"timestamp":15205603256,"id":94,"parentId":53,"tags":{},"startTime":1778823177850,"traceId":"b3d43d52a98272bb"},{"name":"check-page","duration":746136,"timestamp":15205585629,"id":53,"parentId":19,"tags":{"page":"/node"},"startTime":1778823177832,"traceId":"b3d43d52a98272bb"},{"name":"is-page-static","duration":747921,"timestamp":15205603175,"id":90,"parentId":23,"tags":{},"startTime":1778823177849,"traceId":"b3d43d52a98272bb"},{"name":"check-page","duration":773103,"timestamp":15205578043,"id":23,"parentId":19,"tags":{"page":"/admin"},"startTime":1778823177824,"traceId":"b3d43d52a98272bb"},{"name":"is-page-static","duration":749644,"timestamp":15205603269,"id":95,"parentId":54,"tags":{},"startTime":1778823177850,"traceId":"b3d43d52a98272bb"},{"name":"check-page","duration":767152,"timestamp":15205585808,"id":54,"parentId":19,"tags":{"page":"/nodes"},"startTime":1778823177832,"traceId":"b3d43d52a98272bb"},{"name":"static-check","duration":779867,"timestamp":15205573199,"id":19,"parentId":1,"tags":{},"startTime":1778823177819,"traceId":"b3d43d52a98272bb"},{"name":"write-routes-manifest","duration":458,"timestamp":15206360757,"id":104,"parentId":1,"tags":{},"startTime":1778823178607,"traceId":"b3d43d52a98272bb"},{"name":"load-dotenv","duration":51,"timestamp":15206373637,"id":107,"parentId":106,"tags":{},"startTime":1778823178620,"traceId":"b3d43d52a98272bb"},{"name":"run-export-path-map","duration":810,"timestamp":15206376537,"id":108,"parentId":106,"tags":{},"startTime":1778823178623,"traceId":"b3d43d52a98272bb"},{"name":"next-export","duration":621609,"timestamp":15206371893,"id":106,"parentId":1,"tags":{},"startTime":1778823178618,"traceId":"b3d43d52a98272bb"}]
2
+ [{"name":"move-exported-app-not-found-","duration":2792,"timestamp":15206997862,"id":109,"parentId":105,"tags":{},"startTime":1778823179244,"traceId":"b3d43d52a98272bb"},{"name":"move-exported-app-global-error-","duration":622,"timestamp":15207000757,"id":110,"parentId":105,"tags":{},"startTime":1778823179247,"traceId":"b3d43d52a98272bb"},{"name":"static-generation","duration":637092,"timestamp":15206366047,"id":105,"parentId":1,"tags":{},"startTime":1778823178612,"traceId":"b3d43d52a98272bb"},{"name":"write-routes-manifest","duration":367,"timestamp":15207003320,"id":111,"parentId":1,"tags":{},"startTime":1778823179250,"traceId":"b3d43d52a98272bb"},{"name":"print-tree-view","duration":4440,"timestamp":15207020507,"id":112,"parentId":1,"tags":{},"startTime":1778823179267,"traceId":"b3d43d52a98272bb"},{"name":"write-route-bundle-stats","duration":12305,"timestamp":15207024987,"id":113,"parentId":1,"tags":{},"startTime":1778823179271,"traceId":"b3d43d52a98272bb"},{"name":"telemetry-flush","duration":18593,"timestamp":15207037328,"id":114,"parentId":1,"tags":{},"startTime":1778823179284,"traceId":"b3d43d52a98272bb"},{"name":"next-build","duration":15383228,"timestamp":15191672721,"id":1,"tags":{"buildMode":"default","version":"16.2.3","bundler":"turbopack","has-custom-webpack-config":"false","use-build-worker":"true"},"startTime":1778823163919,"traceId":"b3d43d52a98272bb"}]
package/.next/trace-build CHANGED
@@ -1 +1 @@
1
- [{"name":"run-turbopack","duration":5479065,"timestamp":13628190383,"id":14,"parentId":1,"tags":{},"startTime":1778821600437,"traceId":"a309209d9e3cd974"},{"name":"turbopack-build-events","duration":101,"timestamp":13628544506,"id":15,"parentId":1,"tags":{},"startTime":1778821600791,"traceId":"a309209d9e3cd974"},{"name":"run-typescript","duration":8228736,"timestamp":13633684536,"id":16,"parentId":1,"tags":{},"startTime":1778821605931,"traceId":"a309209d9e3cd974"},{"name":"static-check","duration":713353,"timestamp":13642087907,"id":19,"parentId":1,"tags":{},"startTime":1778821614334,"traceId":"a309209d9e3cd974"},{"name":"static-generation","duration":644399,"timestamp":13642814237,"id":105,"parentId":1,"tags":{},"startTime":1778821615061,"traceId":"a309209d9e3cd974"},{"name":"telemetry-flush","duration":22192,"timestamp":13643493351,"id":114,"parentId":1,"tags":{},"startTime":1778821615740,"traceId":"a309209d9e3cd974"},{"name":"next-build","duration":15511487,"timestamp":13628004086,"id":1,"tags":{"buildMode":"default","version":"16.2.3","bundler":"turbopack","has-custom-webpack-config":"false","use-build-worker":"true"},"startTime":1778821600250,"traceId":"a309209d9e3cd974"}]
1
+ [{"name":"run-turbopack","duration":5382748,"timestamp":15191867363,"id":14,"parentId":1,"tags":{},"startTime":1778823164114,"traceId":"b3d43d52a98272bb"},{"name":"turbopack-build-events","duration":109,"timestamp":15192151702,"id":15,"parentId":1,"tags":{},"startTime":1778823164398,"traceId":"b3d43d52a98272bb"},{"name":"run-typescript","duration":8087949,"timestamp":15197258858,"id":16,"parentId":1,"tags":{},"startTime":1778823169505,"traceId":"b3d43d52a98272bb"},{"name":"static-check","duration":779867,"timestamp":15205573199,"id":19,"parentId":1,"tags":{},"startTime":1778823177819,"traceId":"b3d43d52a98272bb"},{"name":"static-generation","duration":637092,"timestamp":15206366047,"id":105,"parentId":1,"tags":{},"startTime":1778823178612,"traceId":"b3d43d52a98272bb"},{"name":"telemetry-flush","duration":18593,"timestamp":15207037328,"id":114,"parentId":1,"tags":{},"startTime":1778823179284,"traceId":"b3d43d52a98272bb"},{"name":"next-build","duration":15383228,"timestamp":15191672721,"id":1,"tags":{"buildMode":"default","version":"16.2.3","bundler":"turbopack","has-custom-webpack-config":"false","use-build-worker":"true"},"startTime":1778823163919,"traceId":"b3d43d52a98272bb"}]
@@ -415,6 +415,7 @@ export function TopoGraph({ sessions, sseSessions, renameSignal }: TopoGraphProp
415
415
  activeAliases,
416
416
  groupKeys,
417
417
  groupBoxes,
418
+ gridContentBottom,
418
419
  } = useMemo(() => {
419
420
  const sseCount = (s: { alias: string; network_id?: string }) =>
420
421
  (s.network_id ? sseSessions[`${s.network_id}:${s.alias}`] : undefined) ?? sseSessions[s.alias];
@@ -424,12 +425,17 @@ export function TopoGraph({ sessions, sseSessions, renameSignal }: TopoGraphProp
424
425
  // index, so contiguous-in-array becomes contiguous-in-ring, i.e.
425
426
  // each team visually clusters. localeCompare keeps CJK ordering sane.
426
427
  const byAlias = (a: Session, b: Session) => a.alias.localeCompare(b.alias);
427
- // #112 umbrella: ghost age-out — an offline node not seen for over a day
428
- // is almost certainly a deleted node the server `/api/status` still
428
+ // #112 umbrella: ghost age-out — an offline node not seen recently is
429
+ // almost certainly a deleted node the server `/api/status` still
429
430
  // returns (#74 root cause is server-side; this is the dashboard-side
430
431
  // fallback so stale ghosts stop cluttering the topology). A missing
431
432
  // last_seen_at is kept (conservative — could be a legitimately new node).
432
- const GHOST_MS = 24 * 60 * 60 * 1000;
433
+ // Round 27 / P0: the 24h threshold was too lenient — Vincent's preview.29
434
+ // screenshot showed B站马 nodes deleted ~4 h earlier still visible. A
435
+ // healthy agent heartbeats every few seconds; if it's been silent for
436
+ // an hour it's effectively gone. 1 h gives a fresh disconnect time to
437
+ // come back while removing dead nodes well within an operator session.
438
+ const GHOST_MS = 60 * 60 * 1000;
433
439
  const now = Date.now();
434
440
  const isGhost = (s: Session) => {
435
441
  if (s.status !== 'offline' || sseCount(s) || !s.last_seen_at) return false;
@@ -497,11 +503,25 @@ export function TopoGraph({ sessions, sseSessions, renameSignal }: TopoGraphProp
497
503
  // padding always fit and stacked group boxes never touch; past the
498
504
  // floor the grid overflows and zoom/pan handles it.
499
505
  const GROUP_TOP = nodeR + 20;
500
- // Row-height floor = the tightest of: a node + its label below it
501
- // (2·nodeR + ~22), and the label band + min box padding (GROUP_TOP + 12).
502
- // Below this, rows would overlap; past it the grid overflows and
503
- // zoom/pan covers the rest.
504
- const cellH = Math.max(2 * nodeR + 22, GROUP_TOP + 12, Math.min(100, (gy1 - gy0) / totalRows));
506
+ // Round 27 / P0 (Vincent screenshot preview.29): dense plain-text
507
+ // node labels (`pos.y + radius + denseDrop`, with a 3 px containerBg
508
+ // stroke halo for readability) at the BOTTOM row of band N would
509
+ // paint OVER the start of band N+1's group label, creating the
510
+ // "blueleap → eleap", "agent-network-dashboard → t-network / board"
511
+ // visual chopping. Geometry of the collision:
512
+ // dense label visual bottom = node_N.y + radius + denseDrop + halo
513
+ // group label glyph top = boxY + 4 (text y=boxY+14, ~10px ascent)
514
+ // = node_N+1.y - GROUP_TOP + 4
515
+ // node_N+1.y - node_N.y = cellH for consecutive rows, so no-collide:
516
+ // cellH ≥ radius + denseDrop + halo + GROUP_TOP - 4 + buffer
517
+ // With halo=3 buffer=4: cellH ≥ nodeR + denseDrop + GROUP_TOP + 3.
518
+ const denseDrop = nodeScale < 0.8 ? 12 : 14;
519
+ const cellH = Math.max(
520
+ 2 * nodeR + 22, // node + dense label within band
521
+ GROUP_TOP + 12, // group-label band + box padding
522
+ nodeR + denseDrop + GROUP_TOP + 3, // round-27 dense↔group label clearance
523
+ Math.min(100, (gy1 - gy0) / totalRows),
524
+ );
505
525
 
506
526
  // Pass 2 — place each band's members.
507
527
  for (const band of bands) {
@@ -541,6 +561,12 @@ export function TopoGraph({ sessions, sseSessions, renameSignal }: TopoGraphProp
541
561
  h: Math.max(...ys) - minY + GROUP_TOP + GROUP_PAD,
542
562
  };
543
563
  });
564
+ // Round 28 / Loop: surface the grid's natural content bottom so the
565
+ // mount effect can auto-fit zoom when the layout would overflow the
566
+ // viewBox. = bottom of the last node row + its label drop + a small
567
+ // breathing buffer. Round 27's cellH bump makes this overflow more
568
+ // common (30-node fleets reach ~774 px, viewBox is 680).
569
+ const gridContentBottom = gy0 + totalRows * cellH + 8;
544
570
  return {
545
571
  onlineNodes: online,
546
572
  offlineNodes: offline,
@@ -549,6 +575,7 @@ export function TopoGraph({ sessions, sseSessions, renameSignal }: TopoGraphProp
549
575
  activeAliases: active,
550
576
  groupKeys,
551
577
  groupBoxes,
578
+ gridContentBottom,
552
579
  };
553
580
  }
554
581
 
@@ -631,6 +658,8 @@ export function TopoGraph({ sessions, sseSessions, renameSignal }: TopoGraphProp
631
658
  // #111: group boxes are a grid-layout feature only — radially scattered
632
659
  // ring nodes can't be cleanly boxed. Ring keeps the #83 prefix hue.
633
660
  groupBoxes: [] as { key: string; count: number; x: number; y: number; w: number; h: number }[],
661
+ // ring fits within VIEWBOX_H by construction (offlineRadius=325 + centre at y=330)
662
+ gridContentBottom: 0,
634
663
  };
635
664
  }, [messages, sessions, sseSessions, layout, nodeScale]);
636
665
 
@@ -716,6 +745,42 @@ export function TopoGraph({ sessions, sseSessions, renameSignal }: TopoGraphProp
716
745
  } catch {}
717
746
  }, []);
718
747
 
748
+ // Round 28 / Loop: first-paint auto-fit. Round 27's cellH bump means
749
+ // dense grids (≥6-7 rows) overflow the 680-px viewBox at the natural
750
+ // 100% zoom — a new user sees the topology with its bottom rows
751
+ // clipped and no hint that there's more below. Auto-fit on first
752
+ // paint (and only if the user has no persisted view) sets the
753
+ // initial zoom so all content fits. Subsequent zoom changes persist
754
+ // and override the auto-fit on reload; explicit reset (0 key) still
755
+ // goes back to 100% so the gesture's "reset to natural size" semantic
756
+ // is preserved.
757
+ //
758
+ // Capture pre-mount persistence in a useState initializer — the
759
+ // existing `persist` effect (declared below) runs on first render
760
+ // with the default {1,0,0} view and writes it to localStorage before
761
+ // the auto-fit effect (deps on async-arriving sessions) gets a turn.
762
+ // Reading localStorage from the effect would see that write and
763
+ // skip the fit. The useState snapshot fires once, before any effects.
764
+ const [hadPersistedViewOnMount] = useState<boolean>(
765
+ () => typeof window !== 'undefined' && !!localStorage.getItem('anet-topo-view'),
766
+ );
767
+ const autoFitDoneRef = useRef(false);
768
+ useEffect(() => {
769
+ if (autoFitDoneRef.current) return;
770
+ if (hadPersistedViewOnMount) {
771
+ autoFitDoneRef.current = true;
772
+ return;
773
+ }
774
+ if (layout !== 'grid' || sessions.length === 0 || !gridContentBottom) return;
775
+ if (gridContentBottom <= VIEWBOX_H) {
776
+ autoFitDoneRef.current = true; // no overflow → no fit needed
777
+ return;
778
+ }
779
+ const fitZoom = Math.max(ZOOM_MIN, Math.min(1, VIEWBOX_H / gridContentBottom));
780
+ setView({ zoom: fitZoom, x: 0, y: 0 });
781
+ autoFitDoneRef.current = true;
782
+ }, [layout, sessions.length, gridContentBottom, hadPersistedViewOnMount]);
783
+
719
784
  // persist view
720
785
  useEffect(() => {
721
786
  try { localStorage.setItem('anet-topo-view', JSON.stringify(view)); } catch {}
@@ -1529,8 +1594,17 @@ export function TopoGraph({ sessions, sseSessions, renameSignal }: TopoGraphProp
1529
1594
  const fullMax = isSmall ? 11 : 12;
1530
1595
  const denseFs = isSmall ? 9 : 10;
1531
1596
  const denseDrop = isSmall ? 12 : 14;
1597
+ // Round 26 / Loop: micro-lift the label group on hover —
1598
+ // 1.5 px upward, 200 ms ease. Pairs with the Round 18
1599
+ // group-box hover-accent treatment to give the same
1600
+ // "this is the focused element" feedback at the per-
1601
+ // node level. CSS transform stacks onto the SVG
1602
+ // positioning transform attribute (SVG 2 cascade);
1603
+ // bbox is unchanged at rest, so the overlap-test gate
1604
+ // continues to see the geometric layout it expects.
1532
1605
  return showFullLabel ? (
1533
- <g transform={`translate(${pos.x}, ${pos.y + radius + dropY})`} style={{ pointerEvents: 'none' }}>
1606
+ <g transform={`translate(${pos.x}, ${pos.y + radius + dropY})`} style={{ pointerEvents: 'none' }}
1607
+ className="transition-transform duration-200 group-hover:-translate-y-[1.5px]">
1534
1608
  <rect x={-cardW / 2} y={cardTopY} width={cardW} height={cardH} rx="6" fill={pal.labelBox.fill} stroke={pal.labelBox.stroke} opacity={isLight ? 1 : 0.94} />
1535
1609
  <text x="0" y="1" textAnchor="middle" fill={status.text} fontSize={aliasFs} fontFamily="monospace" fontWeight="700">
1536
1610
  {truncate(session.alias, fullMax)}
@@ -1549,6 +1623,7 @@ export function TopoGraph({ sessions, sseSessions, renameSignal }: TopoGraphProp
1549
1623
  fontFamily="monospace"
1550
1624
  fontWeight="700"
1551
1625
  opacity={0.9}
1626
+ className="transition-transform duration-200 group-hover:-translate-y-[1.5px]"
1552
1627
  style={{ pointerEvents: 'none', paintOrder: 'stroke' }}
1553
1628
  stroke={pal.containerBg}
1554
1629
  strokeWidth="3"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sleep2agi/agent-network-dashboard",
3
- "version": "0.4.6-preview.33",
3
+ "version": "0.4.6-preview.35",
4
4
  "description": "Agent Network Dashboard — Web UI for managing AI Agent networks",
5
5
  "scripts": {
6
6
  "dev": "next dev",
@@ -0,0 +1,73 @@
1
+ /* Round 28 verification: first-paint auto-fit zoom when grid content
2
+ * would overflow viewBox; respects persisted view; doesn't fire on
3
+ * small fleets (no overflow). */
4
+ import { chromium } from 'playwright';
5
+ import { readFileSync } from 'node:fs';
6
+
7
+ const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
8
+ const browser = await chromium.launch({ headless: true });
9
+
10
+ async function probe({ fleetSize, persisted }) {
11
+ const ctx = await browser.newContext({ viewport: { width: 1280, height: 1600 } });
12
+ await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
13
+ await ctx.addInitScript(([pers]) => {
14
+ try {
15
+ localStorage.setItem('anet-theme', 'cyber');
16
+ localStorage.setItem('anet-topo-layout', 'grid');
17
+ if (pers) localStorage.setItem('anet-topo-view', JSON.stringify(pers));
18
+ else localStorage.removeItem('anet-topo-view');
19
+ sessionStorage.setItem('anet_v3_auth', '1');
20
+ } catch {}
21
+ }, [persisted]);
22
+ const fresh = new Date(Date.now() - 60 * 1000).toISOString();
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
+ // Use prefix groups with 5 members each — 7 bands stack vertically
28
+ // and overflow the 680-px viewBox at cellH ≥ 81 (Round 27 floor).
29
+ const aliases = Array.from({ length: fleetSize }, (_, i) => {
30
+ const groups = ['A站', 'B站', 'C站', 'D站', 'E站', 'F站', 'G站', 'H站', 'I站', 'J站'];
31
+ const group = groups[Math.floor(i / 5) % groups.length];
32
+ return `${group}n${i + 1}`;
33
+ });
34
+ const sessions = aliases.map(a => ({
35
+ alias: a, status: 'idle', 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 } });
39
+ });
40
+ await ctx.route('**/api/hub/tasks*', (route) => route.fulfill({ json: { tasks: [] } }));
41
+ const page = await ctx.newPage();
42
+ await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
43
+ await page.waitForFunction((n) => {
44
+ const svg = document.querySelector('svg[viewBox="0 0 1000 680"]');
45
+ return !!svg && svg.querySelectorAll('g[data-node]').length === n;
46
+ }, fleetSize, { timeout: 30000 }).catch(() => {});
47
+ await page.waitForTimeout(600);
48
+ const zoom = await page.evaluate(() => {
49
+ const span = document.querySelector('button[aria-label="Zoom in"]').parentElement.querySelector('span[title*="zoom level"]');
50
+ return +span.textContent.replace('%', '');
51
+ });
52
+ await ctx.close();
53
+ return zoom;
54
+ }
55
+
56
+ // 1. Big fleet (35 nodes / 7 bands → overflows ~680-px viewBox at cellH≥81)
57
+ // with no persisted view → auto-fit triggers (zoom < 100%)
58
+ const bigFresh = await probe({ fleetSize: 35 });
59
+ // 2. Big fleet, user has persisted view (zoom=1) → respect it, no auto-fit
60
+ const bigPersisted = await probe({ fleetSize: 35, persisted: { zoom: 1, x: 0, y: 0 } });
61
+ // 3. Small fleet, no persisted view → no overflow, zoom stays 100%
62
+ const smallFresh = await probe({ fleetSize: 6 });
63
+
64
+ await browser.close();
65
+ const results = {
66
+ bigFleetAutoFits: bigFresh < 100 && bigFresh >= 50,
67
+ persistedRespected: bigPersisted === 100,
68
+ smallFleetStays100: smallFresh === 100,
69
+ };
70
+ const ok = Object.values(results).every(Boolean);
71
+ console.log(`${ok ? '✅' : '❌'} auto-fit:`, JSON.stringify(results),
72
+ `bigFresh=${bigFresh}% bigPersisted=${bigPersisted}% smallFresh=${smallFresh}%`);
73
+ process.exit(ok ? 0 : 1);
@@ -0,0 +1,115 @@
1
+ /* Round 26 verification: hovering a node lifts its label group up by
2
+ * 1.5 px (CSS transform stacked on the SVG positioning translate). Both
3
+ * the full-card path (sparse fleet) and the dense plain-text path
4
+ * (large fleet) should respond. */
5
+ import { chromium } from 'playwright';
6
+ import { readFileSync } from 'node:fs';
7
+
8
+ const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
9
+ const browser = await chromium.launch({ headless: true });
10
+
11
+ async function probe(fleetSize) {
12
+ const ctx = await browser.newContext({ viewport: { width: 1280, height: 1600 } });
13
+ await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
14
+ await ctx.addInitScript(() => {
15
+ try {
16
+ localStorage.setItem('anet-theme', 'cyber');
17
+ localStorage.setItem('anet-topo-layout', 'grid');
18
+ localStorage.setItem('anet-topo-nodescale', '1');
19
+ sessionStorage.setItem('anet_v3_auth', '1');
20
+ } catch {}
21
+ });
22
+ const fresh = new Date(Date.now() - 60 * 1000).toISOString();
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 sessions = Array.from({ length: fleetSize }, (_, i) => ({
28
+ alias: `lab${i + 1}`, status: 'idle', network_id: nid, project_dir: null,
29
+ created_at: fresh, updated_at: fresh, last_seen_at: fresh,
30
+ }));
31
+ await route.fulfill({ response: r, json: { ...b, sessions } });
32
+ });
33
+ await ctx.route('**/api/hub/tasks*', (route) => route.fulfill({ json: { tasks: [] } }));
34
+ const page = await ctx.newPage();
35
+ await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
36
+ await page.waitForFunction((n) => {
37
+ const svg = document.querySelector('svg[viewBox="0 0 1000 680"]');
38
+ return !!svg && svg.querySelectorAll('g[data-node]').length === n;
39
+ }, fleetSize, { timeout: 30000 }).catch(() => {});
40
+ await page.waitForTimeout(500);
41
+
42
+ // Re-query the label element fresh each sample — React re-renders on
43
+ // hover (hoveredAlias state change) so any element handle captured
44
+ // before the hover would be detached/stale by the time we read its
45
+ // post-hover position.
46
+ const readLabelTop = () => page.evaluate(() => {
47
+ const node = document.querySelector('g[data-node="lab1"]');
48
+ if (!node) return null;
49
+ const full = [...node.querySelectorAll('g')].find(g => /group-hover:-translate-y/.test(g.getAttribute('class') || ''));
50
+ const el = full || [...node.querySelectorAll('text')].find(t => /group-hover:-translate-y/.test(t.getAttribute('class') || ''));
51
+ return el ? el.getBoundingClientRect().top : null;
52
+ });
53
+
54
+ const beforeY = await readLabelTop();
55
+ await page.locator('g[data-node="lab1"]').hover();
56
+ await page.waitForTimeout(300);
57
+ const afterY = await readLabelTop();
58
+
59
+ await ctx.close();
60
+ return { beforeY, afterY };
61
+ }
62
+
63
+ const sparse = await probe(4);
64
+ // Note: in dense mode the same alias's hover triggers `showFullLabel`,
65
+ // which swaps the plain-text element for the full-card <g>. That path
66
+ // switch makes a same-element before/after comparison meaningless.
67
+ // The plain-text element still carries the same hover-lift class, so
68
+ // the lift wiring is verified at the DOM level via the second probe.
69
+ const denseClassPresent = await (async () => {
70
+ const ctx = await browser.newContext({ viewport: { width: 1280, height: 1600 } });
71
+ const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
72
+ await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
73
+ await ctx.addInitScript(() => {
74
+ localStorage.setItem('anet-topo-layout', 'grid');
75
+ localStorage.setItem('anet-topo-nodescale', '1');
76
+ sessionStorage.setItem('anet_v3_auth', '1');
77
+ });
78
+ const fresh = new Date(Date.now() - 60 * 1000).toISOString();
79
+ await ctx.route('**/api/hub/status*', async (route) => {
80
+ const r = await route.fetch();
81
+ const b = await r.json();
82
+ const nid = (b.sessions || [])[0]?.network_id || 'default';
83
+ const sessions = Array.from({ length: 28 }, (_, i) => ({
84
+ alias: `lab${i + 1}`, status: 'idle', network_id: nid, project_dir: null,
85
+ created_at: fresh, updated_at: fresh, last_seen_at: fresh,
86
+ }));
87
+ await route.fulfill({ response: r, json: { ...b, sessions } });
88
+ });
89
+ await ctx.route('**/api/hub/tasks*', (route) => route.fulfill({ json: { tasks: [] } }));
90
+ const page = await ctx.newPage();
91
+ await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
92
+ await page.waitForFunction(() => document.querySelectorAll('g[data-node]').length === 28, { timeout: 30000 }).catch(() => {});
93
+ await page.waitForTimeout(500);
94
+ const has = await page.evaluate(() => {
95
+ const node = document.querySelector('g[data-node="lab2"]'); // not the one we'd hover
96
+ if (!node) return false;
97
+ const t = [...node.querySelectorAll('text')].find(x => /group-hover:-translate-y/.test(x.getAttribute('class') || ''));
98
+ return !!t;
99
+ });
100
+ await ctx.close();
101
+ return has;
102
+ })();
103
+
104
+ await browser.close();
105
+
106
+ const lifted = (m) => m.beforeY != null && m.afterY != null && m.beforeY - m.afterY >= 1 && m.beforeY - m.afterY <= 2.5;
107
+
108
+ const results = {
109
+ sparseLabelLifts: lifted(sparse),
110
+ densePlainTextHasLiftClass: denseClassPresent,
111
+ };
112
+ const ok = Object.values(results).every(Boolean);
113
+ console.log(`${ok ? '✅' : '❌'} label hover lift:`, JSON.stringify(results),
114
+ `sparse=Δ${(sparse.beforeY - sparse.afterY)?.toFixed(2)}px`);
115
+ process.exit(ok ? 0 : 1);
@@ -3,7 +3,10 @@
3
3
  * - node ↔ node — status rings don't intersect
4
4
  * - node ↔ panel — no node circle intersects an overlay panel rect
5
5
  * - node ↔ group-label — no group-box label text covers a node
6
- * - group-box ↔ box — no two group boxes overlap */
6
+ * - group-box ↔ box — no two group boxes overlap
7
+ * - label ↔ label — no two text labels overlap (Round 27 — caught
8
+ * the dense-node-label vs group-label collision
9
+ * Vincent reported in preview.29) */
7
10
  import { chromium } from 'playwright';
8
11
  import { readFileSync, mkdirSync } from 'node:fs';
9
12
 
@@ -80,11 +83,24 @@ async function check(layout) {
80
83
  label: { x: bb.x, y: bb.y, w: bb.width, h: bb.height },
81
84
  };
82
85
  });
83
- return { nodes, panels, groups };
86
+ // Round 27 / P0: every visible label bbox (node alias text + group
87
+ // headings) so we can assert label↔label clearance. Skip elements
88
+ // with empty bboxes (e.g., text inside an unrendered <g>).
89
+ const allLabels = [];
90
+ for (const t of svg.querySelectorAll('g[data-node] text, g[data-group] text')) {
91
+ const bb = t.getBBox();
92
+ if (bb.width === 0 || bb.height === 0) continue;
93
+ allLabels.push({
94
+ kind: t.closest('g[data-group]') ? 'group' : 'node',
95
+ owner: (t.closest('g[data-group]')?.getAttribute('data-group')) || (t.closest('g[data-node]')?.getAttribute('data-node')) || '?',
96
+ x: bb.x, y: bb.y, w: bb.width, h: bb.height,
97
+ });
98
+ }
99
+ return { nodes, panels, groups, allLabels };
84
100
  });
85
101
 
86
102
  const TOL = 2; // px slack — touching edges is fine, real overlap is not
87
- let nodeNode = 0, nodePanel = 0, nodeLabel = 0, boxBox = 0;
103
+ let nodeNode = 0, nodePanel = 0, nodeLabel = 0, boxBox = 0, labelLabel = 0;
88
104
 
89
105
  // node ↔ node
90
106
  for (let i = 0; i < data.nodes.length; i++) {
@@ -119,12 +135,23 @@ async function check(layout) {
119
135
  overlaps1D(a.y, a.y + a.h, b.y, b.y + b.h, TOL)) boxBox++;
120
136
  }
121
137
  }
138
+ // label ↔ label (Round 27)
139
+ // Same-node node-labels (e.g. alias + sub-status in the full card) are
140
+ // intentionally close and adjacent — skip pairs that share an owner.
141
+ for (let i = 0; i < data.allLabels.length; i++) {
142
+ for (let j = i + 1; j < data.allLabels.length; j++) {
143
+ const a = data.allLabels[i], b = data.allLabels[j];
144
+ if (a.owner === b.owner) continue;
145
+ if (overlaps1D(a.x, a.x + a.w, b.x, b.x + b.w, TOL) &&
146
+ overlaps1D(a.y, a.y + a.h, b.y, b.y + b.h, TOL)) labelLabel++;
147
+ }
148
+ }
122
149
 
123
150
  await page.screenshot({ path: `/tmp/anet-issue-112/overlap-${layout}.png` });
124
151
  await ctx.close();
125
- const ok = nodeNode === 0 && nodePanel === 0 && nodeLabel === 0 && boxBox === 0;
152
+ const ok = nodeNode === 0 && nodePanel === 0 && nodeLabel === 0 && boxBox === 0 && labelLabel === 0;
126
153
  console.log(`${ok ? '✅' : '❌'} [${layout}] nodes=${data.nodes.length} groups=${data.groups.length} — ` +
127
- `node↔node:${nodeNode} node↔panel:${nodePanel} node↔label:${nodeLabel} box↔box:${boxBox}`);
154
+ `node↔node:${nodeNode} node↔panel:${nodePanel} node↔label:${nodeLabel} box↔box:${boxBox} label↔label:${labelLabel}`);
128
155
  return ok;
129
156
  }
130
157