@sleep2agi/agent-network-dashboard 0.6.3-preview.1 → 0.6.3-preview.10

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 (348) hide show
  1. package/.next/BUILD_COMMIT +1 -1
  2. package/.next/BUILD_ID +1 -1
  3. package/.next/app-path-routes-manifest.json +5 -0
  4. package/.next/build-manifest.json +3 -3
  5. package/.next/cache/.previewinfo +1 -0
  6. package/.next/cache/.rscinfo +1 -0
  7. package/.next/diagnostics/route-bundle-stats.json +56 -39
  8. package/.next/fallback-build-manifest.json +3 -3
  9. package/.next/prerender-manifest.json +27 -3
  10. package/.next/routes-manifest.json +30 -0
  11. package/.next/server/app/_global-error.html +1 -1
  12. package/.next/server/app/_global-error.rsc +1 -1
  13. package/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  14. package/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  15. package/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  16. package/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  17. package/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  18. package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  19. package/.next/server/app/_not-found.html +2 -2
  20. package/.next/server/app/_not-found.rsc +13 -13
  21. package/.next/server/app/_not-found.segments/_full.segment.rsc +13 -13
  22. package/.next/server/app/_not-found.segments/_head.segment.rsc +4 -4
  23. package/.next/server/app/_not-found.segments/_index.segment.rsc +8 -8
  24. package/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +2 -2
  25. package/.next/server/app/_not-found.segments/_not-found.segment.rsc +3 -3
  26. package/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  27. package/.next/server/app/admin/page_client-reference-manifest.js +1 -1
  28. package/.next/server/app/admin.html +2 -2
  29. package/.next/server/app/admin.rsc +15 -15
  30. package/.next/server/app/admin.segments/_full.segment.rsc +15 -15
  31. package/.next/server/app/admin.segments/_head.segment.rsc +4 -4
  32. package/.next/server/app/admin.segments/_index.segment.rsc +8 -8
  33. package/.next/server/app/admin.segments/_tree.segment.rsc +2 -2
  34. package/.next/server/app/admin.segments/admin/__PAGE__.segment.rsc +4 -4
  35. package/.next/server/app/admin.segments/admin.segment.rsc +3 -3
  36. package/.next/server/app/api/anet/host-supervisors/route/app-paths-manifest.json +3 -0
  37. package/.next/server/app/api/anet/host-supervisors/route/build-manifest.json +9 -0
  38. package/.next/server/app/api/anet/host-supervisors/route/server-reference-manifest.json +4 -0
  39. package/.next/server/app/api/anet/host-supervisors/route.js +7 -0
  40. package/.next/server/app/api/anet/host-supervisors/route.js.map +5 -0
  41. package/.next/server/app/api/anet/host-supervisors/route.js.nft.json +1 -0
  42. package/.next/server/app/api/anet/host-supervisors/route_client-reference-manifest.js +3 -0
  43. package/.next/server/app/api/anet/providers/probe/route/app-paths-manifest.json +3 -0
  44. package/.next/server/app/api/anet/providers/probe/route/build-manifest.json +9 -0
  45. package/.next/server/app/api/anet/providers/probe/route/server-reference-manifest.json +4 -0
  46. package/.next/server/app/api/anet/providers/probe/route.js +7 -0
  47. package/.next/server/app/api/anet/providers/probe/route.js.map +5 -0
  48. package/.next/server/app/api/anet/providers/probe/route.js.nft.json +1 -0
  49. package/.next/server/app/api/anet/providers/probe/route_client-reference-manifest.js +3 -0
  50. package/.next/server/app/api/anet/providers/probe-results/route/app-paths-manifest.json +3 -0
  51. package/.next/server/app/api/anet/providers/probe-results/route/build-manifest.json +9 -0
  52. package/.next/server/app/api/anet/providers/probe-results/route/server-reference-manifest.json +4 -0
  53. package/.next/server/app/api/anet/providers/probe-results/route.js +7 -0
  54. package/.next/server/app/api/anet/providers/probe-results/route.js.map +5 -0
  55. package/.next/server/app/api/anet/providers/probe-results/route.js.nft.json +1 -0
  56. package/.next/server/app/api/anet/providers/probe-results/route_client-reference-manifest.js +3 -0
  57. package/.next/server/app/api/anet/providers/route/app-paths-manifest.json +3 -0
  58. package/.next/server/app/api/anet/providers/route/build-manifest.json +9 -0
  59. package/.next/server/app/api/anet/providers/route/server-reference-manifest.json +4 -0
  60. package/.next/server/app/api/anet/providers/route.js +8 -0
  61. package/.next/server/app/api/anet/providers/route.js.map +5 -0
  62. package/.next/server/app/api/anet/providers/route.js.nft.json +1 -0
  63. package/.next/server/app/api/anet/providers/route_client-reference-manifest.js +3 -0
  64. package/.next/server/app/index.html +2 -2
  65. package/.next/server/app/index.rsc +15 -15
  66. package/.next/server/app/index.segments/__PAGE__.segment.rsc +4 -4
  67. package/.next/server/app/index.segments/_full.segment.rsc +15 -15
  68. package/.next/server/app/index.segments/_head.segment.rsc +4 -4
  69. package/.next/server/app/index.segments/_index.segment.rsc +8 -8
  70. package/.next/server/app/index.segments/_tree.segment.rsc +2 -2
  71. package/.next/server/app/login/page_client-reference-manifest.js +1 -1
  72. package/.next/server/app/login.html +2 -2
  73. package/.next/server/app/login.rsc +15 -15
  74. package/.next/server/app/login.segments/_full.segment.rsc +15 -15
  75. package/.next/server/app/login.segments/_head.segment.rsc +4 -4
  76. package/.next/server/app/login.segments/_index.segment.rsc +8 -8
  77. package/.next/server/app/login.segments/_tree.segment.rsc +2 -2
  78. package/.next/server/app/login.segments/login/__PAGE__.segment.rsc +4 -4
  79. package/.next/server/app/login.segments/login.segment.rsc +3 -3
  80. package/.next/server/app/logs/page_client-reference-manifest.js +1 -1
  81. package/.next/server/app/logs.html +2 -2
  82. package/.next/server/app/logs.rsc +15 -15
  83. package/.next/server/app/logs.segments/_full.segment.rsc +15 -15
  84. package/.next/server/app/logs.segments/_head.segment.rsc +4 -4
  85. package/.next/server/app/logs.segments/_index.segment.rsc +8 -8
  86. package/.next/server/app/logs.segments/_tree.segment.rsc +2 -2
  87. package/.next/server/app/logs.segments/logs/__PAGE__.segment.rsc +4 -4
  88. package/.next/server/app/logs.segments/logs.segment.rsc +3 -3
  89. package/.next/server/app/messages/page_client-reference-manifest.js +1 -1
  90. package/.next/server/app/messages.html +2 -2
  91. package/.next/server/app/messages.rsc +15 -15
  92. package/.next/server/app/messages.segments/_full.segment.rsc +15 -15
  93. package/.next/server/app/messages.segments/_head.segment.rsc +4 -4
  94. package/.next/server/app/messages.segments/_index.segment.rsc +8 -8
  95. package/.next/server/app/messages.segments/_tree.segment.rsc +2 -2
  96. package/.next/server/app/messages.segments/messages/__PAGE__.segment.rsc +4 -4
  97. package/.next/server/app/messages.segments/messages.segment.rsc +3 -3
  98. package/.next/server/app/node/page_client-reference-manifest.js +1 -1
  99. package/.next/server/app/node.html +2 -2
  100. package/.next/server/app/node.rsc +15 -15
  101. package/.next/server/app/node.segments/_full.segment.rsc +15 -15
  102. package/.next/server/app/node.segments/_head.segment.rsc +4 -4
  103. package/.next/server/app/node.segments/_index.segment.rsc +8 -8
  104. package/.next/server/app/node.segments/_tree.segment.rsc +2 -2
  105. package/.next/server/app/node.segments/node/__PAGE__.segment.rsc +4 -4
  106. package/.next/server/app/node.segments/node.segment.rsc +3 -3
  107. package/.next/server/app/nodes/page_client-reference-manifest.js +1 -1
  108. package/.next/server/app/nodes.html +2 -2
  109. package/.next/server/app/nodes.rsc +15 -15
  110. package/.next/server/app/nodes.segments/_full.segment.rsc +15 -15
  111. package/.next/server/app/nodes.segments/_head.segment.rsc +4 -4
  112. package/.next/server/app/nodes.segments/_index.segment.rsc +8 -8
  113. package/.next/server/app/nodes.segments/_tree.segment.rsc +2 -2
  114. package/.next/server/app/nodes.segments/nodes/__PAGE__.segment.rsc +4 -4
  115. package/.next/server/app/nodes.segments/nodes.segment.rsc +3 -3
  116. package/.next/server/app/page_client-reference-manifest.js +1 -1
  117. package/.next/server/app/providers/page/app-paths-manifest.json +3 -0
  118. package/.next/server/app/providers/page/build-manifest.json +17 -0
  119. package/.next/server/app/providers/page/next-font-manifest.json +11 -0
  120. package/.next/server/app/providers/page/react-loadable-manifest.json +1 -0
  121. package/.next/server/app/providers/page/server-reference-manifest.json +4 -0
  122. package/.next/server/app/providers/page.js +14 -0
  123. package/.next/server/app/providers/page.js.map +5 -0
  124. package/.next/server/app/providers/page.js.nft.json +1 -0
  125. package/.next/server/app/providers/page_client-reference-manifest.js +3 -0
  126. package/.next/server/app/providers.html +12 -0
  127. package/.next/server/app/providers.meta +15 -0
  128. package/.next/server/app/providers.rsc +27 -0
  129. package/.next/server/app/providers.segments/_full.segment.rsc +27 -0
  130. package/.next/server/app/providers.segments/_head.segment.rsc +6 -0
  131. package/.next/server/app/providers.segments/_index.segment.rsc +10 -0
  132. package/.next/server/app/providers.segments/_tree.segment.rsc +5 -0
  133. package/.next/server/app/providers.segments/providers/__PAGE__.segment.rsc +9 -0
  134. package/.next/server/app/providers.segments/providers.segment.rsc +5 -0
  135. package/.next/server/app/server-logs/page_client-reference-manifest.js +1 -1
  136. package/.next/server/app/server-logs.html +2 -2
  137. package/.next/server/app/server-logs.rsc +15 -15
  138. package/.next/server/app/server-logs.segments/_full.segment.rsc +15 -15
  139. package/.next/server/app/server-logs.segments/_head.segment.rsc +4 -4
  140. package/.next/server/app/server-logs.segments/_index.segment.rsc +8 -8
  141. package/.next/server/app/server-logs.segments/_tree.segment.rsc +2 -2
  142. package/.next/server/app/server-logs.segments/server-logs/__PAGE__.segment.rsc +4 -4
  143. package/.next/server/app/server-logs.segments/server-logs.segment.rsc +3 -3
  144. package/.next/server/app/servers/page_client-reference-manifest.js +1 -1
  145. package/.next/server/app/servers.html +2 -2
  146. package/.next/server/app/servers.rsc +15 -15
  147. package/.next/server/app/servers.segments/_full.segment.rsc +15 -15
  148. package/.next/server/app/servers.segments/_head.segment.rsc +4 -4
  149. package/.next/server/app/servers.segments/_index.segment.rsc +8 -8
  150. package/.next/server/app/servers.segments/_tree.segment.rsc +2 -2
  151. package/.next/server/app/servers.segments/servers/__PAGE__.segment.rsc +4 -4
  152. package/.next/server/app/servers.segments/servers.segment.rsc +3 -3
  153. package/.next/server/app/settings/networks/page_client-reference-manifest.js +1 -1
  154. package/.next/server/app/settings/networks.html +2 -2
  155. package/.next/server/app/settings/networks.rsc +15 -15
  156. package/.next/server/app/settings/networks.segments/_full.segment.rsc +15 -15
  157. package/.next/server/app/settings/networks.segments/_head.segment.rsc +4 -4
  158. package/.next/server/app/settings/networks.segments/_index.segment.rsc +8 -8
  159. package/.next/server/app/settings/networks.segments/_tree.segment.rsc +2 -2
  160. package/.next/server/app/settings/networks.segments/settings/networks/__PAGE__.segment.rsc +4 -4
  161. package/.next/server/app/settings/networks.segments/settings/networks.segment.rsc +3 -3
  162. package/.next/server/app/settings/networks.segments/settings.segment.rsc +3 -3
  163. package/.next/server/app/settings/page_client-reference-manifest.js +1 -1
  164. package/.next/server/app/settings/tokens/page_client-reference-manifest.js +1 -1
  165. package/.next/server/app/settings/tokens.html +2 -2
  166. package/.next/server/app/settings/tokens.rsc +15 -15
  167. package/.next/server/app/settings/tokens.segments/_full.segment.rsc +15 -15
  168. package/.next/server/app/settings/tokens.segments/_head.segment.rsc +4 -4
  169. package/.next/server/app/settings/tokens.segments/_index.segment.rsc +8 -8
  170. package/.next/server/app/settings/tokens.segments/_tree.segment.rsc +2 -2
  171. package/.next/server/app/settings/tokens.segments/settings/tokens/__PAGE__.segment.rsc +4 -4
  172. package/.next/server/app/settings/tokens.segments/settings/tokens.segment.rsc +3 -3
  173. package/.next/server/app/settings/tokens.segments/settings.segment.rsc +3 -3
  174. package/.next/server/app/settings.html +2 -2
  175. package/.next/server/app/settings.rsc +15 -15
  176. package/.next/server/app/settings.segments/_full.segment.rsc +15 -15
  177. package/.next/server/app/settings.segments/_head.segment.rsc +4 -4
  178. package/.next/server/app/settings.segments/_index.segment.rsc +8 -8
  179. package/.next/server/app/settings.segments/_tree.segment.rsc +2 -2
  180. package/.next/server/app/settings.segments/settings/__PAGE__.segment.rsc +4 -4
  181. package/.next/server/app/settings.segments/settings.segment.rsc +3 -3
  182. package/.next/server/app/tasks/[id]/page_client-reference-manifest.js +1 -1
  183. package/.next/server/app/tasks/page_client-reference-manifest.js +1 -1
  184. package/.next/server/app/tasks.html +2 -2
  185. package/.next/server/app/tasks.rsc +15 -15
  186. package/.next/server/app/tasks.segments/_full.segment.rsc +15 -15
  187. package/.next/server/app/tasks.segments/_head.segment.rsc +4 -4
  188. package/.next/server/app/tasks.segments/_index.segment.rsc +8 -8
  189. package/.next/server/app/tasks.segments/_tree.segment.rsc +2 -2
  190. package/.next/server/app/tasks.segments/tasks/__PAGE__.segment.rsc +4 -4
  191. package/.next/server/app/tasks.segments/tasks.segment.rsc +3 -3
  192. package/.next/server/app-paths-manifest.json +5 -0
  193. package/.next/server/chunks/00jm_next_dist_esm_build_templates_app-route_0bobkt3.js +3 -0
  194. package/.next/server/chunks/00jm_next_dist_esm_build_templates_app-route_0bobkt3.js.map +1 -0
  195. package/.next/server/chunks/0dk5_next-internal_server_app_api_anet_providers_probe-results_route_actions_07.d.5a.js +3 -0
  196. package/.next/server/chunks/0dk5_next-internal_server_app_api_anet_providers_probe-results_route_actions_07.d.5a.js.map +1 -0
  197. package/.next/server/chunks/0ykm__next-internal_server_app_api_anet_host-supervisors_route_actions_0g3hek2.js +3 -0
  198. package/.next/server/chunks/0ykm__next-internal_server_app_api_anet_host-supervisors_route_actions_0g3hek2.js.map +1 -0
  199. package/.next/server/chunks/0ykm__next-internal_server_app_api_anet_providers_probe_route_actions_05f000..js +3 -0
  200. package/.next/server/chunks/0ykm__next-internal_server_app_api_anet_providers_probe_route_actions_05f000..js.map +1 -0
  201. package/.next/server/chunks/0ykm__next-internal_server_app_api_anet_providers_route_actions_10htbhd.js +3 -0
  202. package/.next/server/chunks/0ykm__next-internal_server_app_api_anet_providers_route_actions_10htbhd.js.map +1 -0
  203. package/.next/server/chunks/[root-of-the-server]__0-29ynz._.js.map +1 -1
  204. package/.next/server/chunks/[root-of-the-server]__0-2le8-._.js.map +1 -1
  205. package/.next/server/chunks/[root-of-the-server]__0-8_f0o._.js.map +1 -1
  206. package/.next/server/chunks/[root-of-the-server]__02p2n3n._.js.map +1 -1
  207. package/.next/server/chunks/[root-of-the-server]__03nze3z._.js +3 -0
  208. package/.next/server/chunks/[root-of-the-server]__03nze3z._.js.map +1 -0
  209. package/.next/server/chunks/[root-of-the-server]__043tnx2._.js.map +1 -1
  210. package/.next/server/chunks/[root-of-the-server]__04z62zk._.js.map +1 -1
  211. package/.next/server/chunks/[root-of-the-server]__07ztet2._.js.map +1 -1
  212. package/.next/server/chunks/[root-of-the-server]__0aqb4n5._.js +1 -1
  213. package/.next/server/chunks/[root-of-the-server]__0aqb4n5._.js.map +1 -1
  214. package/.next/server/chunks/[root-of-the-server]__0cphmer._.js +3 -0
  215. package/.next/server/chunks/[root-of-the-server]__0cphmer._.js.map +1 -0
  216. package/.next/server/chunks/[root-of-the-server]__0e3ucl1._.js.map +1 -1
  217. package/.next/server/chunks/[root-of-the-server]__0e6yail._.js.map +1 -1
  218. package/.next/server/chunks/[root-of-the-server]__0gx2_6a._.js.map +1 -1
  219. package/.next/server/chunks/[root-of-the-server]__0hg3_8r._.js.map +1 -1
  220. package/.next/server/chunks/[root-of-the-server]__0lhq4ha._.js.map +1 -1
  221. package/.next/server/chunks/[root-of-the-server]__0mkwzz7._.js +1 -1
  222. package/.next/server/chunks/[root-of-the-server]__0mkwzz7._.js.map +1 -1
  223. package/.next/server/chunks/[root-of-the-server]__0mxw4vb._.js.map +1 -1
  224. package/.next/server/chunks/[root-of-the-server]__0mzopco._.js.map +1 -1
  225. package/.next/server/chunks/[root-of-the-server]__0o45a4q._.js.map +1 -1
  226. package/.next/server/chunks/[root-of-the-server]__0w1w_w0._.js +3 -0
  227. package/.next/server/chunks/[root-of-the-server]__0w1w_w0._.js.map +1 -0
  228. package/.next/server/chunks/[root-of-the-server]__0xtp-et._.js.map +1 -1
  229. package/.next/server/chunks/[root-of-the-server]__0yyo7k5._.js +1 -1
  230. package/.next/server/chunks/[root-of-the-server]__0yyo7k5._.js.map +1 -1
  231. package/.next/server/chunks/[root-of-the-server]__0~rwgo1._.js +3 -0
  232. package/.next/server/chunks/[root-of-the-server]__0~rwgo1._.js.map +1 -0
  233. package/.next/server/chunks/[root-of-the-server]__10pvabe._.js.map +1 -1
  234. package/.next/server/chunks/[root-of-the-server]__10t11zq._.js.map +1 -1
  235. package/.next/server/chunks/[root-of-the-server]__12r~omy._.js.map +1 -1
  236. package/.next/server/chunks/[root-of-the-server]__1389~cs._.js.map +1 -1
  237. package/.next/server/chunks/[root-of-the-server]__13n8t..._.js.map +1 -1
  238. package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_02lorbl.js +4 -0
  239. package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_02lorbl.js.map +1 -0
  240. package/.next/server/chunks/ssr/[root-of-the-server]__030vg4n._.js.map +1 -1
  241. package/.next/server/chunks/ssr/[root-of-the-server]__04mx~5g._.js +3 -0
  242. package/.next/server/chunks/ssr/[root-of-the-server]__04mx~5g._.js.map +1 -0
  243. package/.next/server/chunks/ssr/[root-of-the-server]__05kf31s._.js +1 -1
  244. package/.next/server/chunks/ssr/[root-of-the-server]__05kf31s._.js.map +1 -1
  245. package/.next/server/chunks/ssr/[root-of-the-server]__096ytyk._.js.map +1 -1
  246. package/.next/server/chunks/ssr/[root-of-the-server]__0fhoq8i._.js +1 -1
  247. package/.next/server/chunks/ssr/[root-of-the-server]__0fhoq8i._.js.map +1 -1
  248. package/.next/server/chunks/ssr/[root-of-the-server]__0h5dae6._.js +1 -1
  249. package/.next/server/chunks/ssr/[root-of-the-server]__0h5dae6._.js.map +1 -1
  250. package/.next/server/chunks/ssr/agent-network-dashboard_09kk21a._.js +3 -3
  251. package/.next/server/chunks/ssr/agent-network-dashboard_09kk21a._.js.map +1 -1
  252. package/.next/server/chunks/ssr/agent-network-dashboard__next-internal_server_app_providers_page_actions_0ou6p43.js +3 -0
  253. package/.next/server/chunks/ssr/agent-network-dashboard__next-internal_server_app_providers_page_actions_0ou6p43.js.map +1 -0
  254. package/.next/server/chunks/ssr/agent-network-dashboard_app_012oyw5._.js +1 -1
  255. package/.next/server/chunks/ssr/agent-network-dashboard_app_012oyw5._.js.map +1 -1
  256. package/.next/server/chunks/ssr/agent-network-dashboard_app_01jhlxz._.js +1 -1
  257. package/.next/server/chunks/ssr/agent-network-dashboard_app_01jhlxz._.js.map +1 -1
  258. package/.next/server/chunks/ssr/agent-network-dashboard_app_09d29my._.js +1 -1
  259. package/.next/server/chunks/ssr/agent-network-dashboard_app_09d29my._.js.map +1 -1
  260. package/.next/server/chunks/ssr/agent-network-dashboard_app_0_d45-d._.js +1 -1
  261. package/.next/server/chunks/ssr/agent-network-dashboard_app_0_d45-d._.js.map +1 -1
  262. package/.next/server/chunks/ssr/agent-network-dashboard_app_0gd.4pc._.js +1 -1
  263. package/.next/server/chunks/ssr/agent-network-dashboard_app_0gd.4pc._.js.map +1 -1
  264. package/.next/server/chunks/ssr/agent-network-dashboard_app_12l4oto._.js.map +1 -1
  265. package/.next/server/chunks/ssr/agent-network-dashboard_app_components_0r7kb.o._.js +1 -1
  266. package/.next/server/chunks/ssr/agent-network-dashboard_app_components_0r7kb.o._.js.map +1 -1
  267. package/.next/server/chunks/ssr/agent-network-dashboard_app_components_EmptyState_tsx_0aol-el._.js +3 -0
  268. package/.next/server/chunks/ssr/agent-network-dashboard_app_components_EmptyState_tsx_0aol-el._.js.map +1 -0
  269. package/.next/server/chunks/ssr/agent-network-dashboard_app_nodes_page_tsx_11haf_p._.js +2 -1
  270. package/.next/server/chunks/ssr/agent-network-dashboard_app_nodes_page_tsx_11haf_p._.js.map +1 -1
  271. package/.next/server/chunks/ssr/agent-network-dashboard_app_providers_page_tsx_0hw2n0v._.js +3 -0
  272. package/.next/server/chunks/ssr/agent-network-dashboard_app_providers_page_tsx_0hw2n0v._.js.map +1 -0
  273. package/.next/server/chunks/ssr/agent-network-dashboard_app_tasks_page_tsx_0mwxy4z._.js.map +1 -1
  274. package/.next/server/middleware-build-manifest.js +3 -3
  275. package/.next/server/next-font-manifest.js +1 -1
  276. package/.next/server/next-font-manifest.json +4 -0
  277. package/.next/server/pages/404.html +2 -2
  278. package/.next/server/pages/500.html +1 -1
  279. package/.next/server/server-reference-manifest.js +1 -1
  280. package/.next/server/server-reference-manifest.json +1 -1
  281. package/.next/static/chunks/{10kkhdde5ve~c.js → 0-z_kfck7-6_1.js} +3 -3
  282. package/.next/static/chunks/049vx3qljs1tt.js +1 -0
  283. package/.next/static/chunks/06.5euf239uvr.css +1 -0
  284. package/.next/static/chunks/{0vun~4ljcrj3p.js → 091hae.lhv9t1.js} +2 -2
  285. package/.next/static/chunks/0chpv7zsh-qrg.js +1 -0
  286. package/.next/static/chunks/0i-l67o_ae5hk.js +2 -0
  287. package/.next/static/chunks/{0vus9xpsz0s~i.js → 0l.gu-iqnmeja.js} +1 -1
  288. package/.next/static/chunks/{149a4l50_3vw-.js → 0mnmn-~ava1vy.js} +1 -1
  289. package/.next/static/chunks/0o-b62_a66.jr.js +1 -0
  290. package/.next/static/chunks/0pk6amtz5icbx.js +1 -0
  291. package/.next/static/chunks/0r4u1.sl.8p15.js +1 -0
  292. package/.next/static/chunks/0wz0122ym_gr3.js +1 -0
  293. package/.next/static/chunks/15aqdc5txzq9r.js +1 -0
  294. package/.next/trace +2 -2
  295. package/.next/trace-build +1 -1
  296. package/.next/types/routes.d.ts +7 -2
  297. package/.next/types/validator.ts +45 -0
  298. package/app/admin/page.tsx +3 -1
  299. package/app/api/anet/host-supervisors/route.ts +102 -0
  300. package/app/api/anet/node-config/route.ts +26 -2
  301. package/app/api/anet/node-create/route.ts +14 -5
  302. package/app/api/anet/node-lifecycle/route.ts +54 -5
  303. package/app/api/anet/providers/probe/route.ts +79 -0
  304. package/app/api/anet/providers/probe-results/route.ts +60 -0
  305. package/app/api/anet/providers/route.ts +191 -0
  306. package/app/api/hub/auth/route.ts +0 -12
  307. package/app/api/hub/networks/route.ts +1 -1
  308. package/app/api/hub/nodes/route.ts +0 -14
  309. package/app/api/hub/upload/route.ts +0 -9
  310. package/app/components/CommandCenter.tsx +3 -6
  311. package/app/components/CommandPalette.tsx +0 -5
  312. package/app/components/CreateNodeWizard.tsx +140 -47
  313. package/app/components/HostSupervisorPicker.tsx +283 -0
  314. package/app/components/NodeLifecycleMenu.tsx +436 -0
  315. package/app/components/NodeSettingsPanel.tsx +80 -39
  316. package/app/components/ProviderFormModal.tsx +303 -0
  317. package/app/components/ReachabilityMatrix.tsx +196 -0
  318. package/app/components/Sidebar.tsx +1 -0
  319. package/app/components/TaskDrawer.tsx +1 -0
  320. package/app/components/TopoGraph.tsx +4 -8
  321. package/app/components/UserBar.tsx +37 -0
  322. package/app/components/types.ts +11 -0
  323. package/app/lib/chat-unread.ts +0 -6
  324. package/app/lib/dashboard-auth.ts +0 -12
  325. package/app/lib/hooks.ts +22 -4
  326. package/app/lib/hub.ts +4 -0
  327. package/app/lib/network-context.tsx +0 -6
  328. package/app/lib/rate-limit.ts +2 -16
  329. package/app/node/page.tsx +12 -1
  330. package/app/nodes/page.tsx +42 -2
  331. package/app/page.tsx +1 -0
  332. package/app/providers/page.tsx +182 -0
  333. package/app/settings/networks/page.tsx +1 -1
  334. package/app/settings/page.tsx +5 -0
  335. package/app/tasks/[id]/page.tsx +1 -0
  336. package/app/tasks/page.tsx +1 -0
  337. package/package.json +1 -1
  338. package/.next/static/chunks/0-t2rbg9~-oh5.js +0 -1
  339. package/.next/static/chunks/0iv.0p9_5b36e.js +0 -1
  340. package/.next/static/chunks/0l_hz3xrjwumg.js +0 -1
  341. package/.next/static/chunks/0lmdw~i5qjqsg.js +0 -1
  342. package/.next/static/chunks/0vruzstkdr99w.js +0 -1
  343. package/.next/static/chunks/0xssg9sin~2xw.js +0 -1
  344. package/.next/static/chunks/124dtwo1k24ao.css +0 -1
  345. package/bun.lock +0 -1663
  346. /package/.next/static/{ZxdmFd_iOEELuA2Km4Q5t → tRPXkJdGLR6a0skqvMgQa}/_buildManifest.js +0 -0
  347. /package/.next/static/{ZxdmFd_iOEELuA2Km4Q5t → tRPXkJdGLR6a0skqvMgQa}/_clientMiddlewareManifest.js +0 -0
  348. /package/.next/static/{ZxdmFd_iOEELuA2Km4Q5t → tRPXkJdGLR6a0skqvMgQa}/_ssgManifest.js +0 -0
@@ -2,29 +2,46 @@
2
2
 
3
3
  import { useEffect, useState } from 'react';
4
4
  import { useNetworkId } from '../lib/network-context';
5
+ import { DaemonOption, HostSupervisorPicker } from './HostSupervisorPicker';
5
6
 
6
7
  /**
7
- * Create-node wizard (node-lifecycle UI M2 — RFC-026 §3.1 P1, 本机创建).
8
- * 5 steps: ① name ② runtime ③ model ④ flags ⑤ confirm → POST /api/anet/node-create.
8
+ * Create-node wizard (node-lifecycle UI M2/PR4 — RFC-026 §3.1).
9
+ * 6 steps now: ⓪ host (PR4 #338) ① name ② runtime ③ model ④ flags ⑤ confirm
10
+ * → POST /api/anet/node-create with `daemon_node_id` set to the chosen host.
9
11
  *
10
- * ⚠️ Two contract gaps the submit path depends on (asked 通信龙/工程马):
11
- * - node_spec.runtime enum: these ids (claude-agent-sdk / codex / grok) follow
12
- * 通信龙's spec, but the panel's RUNTIME_MODELS keys differ; confirm the exact
13
- * values the backend expects, then adjust RUNTIMES below.
14
- * - daemon_node_id: P1 is "本机". Until there's a way to resolve the local
15
- * daemon's node_id, we omit it (the route omits when absent) and surface
16
- * whatever the hub returns never a fake success.
17
- * The route already returns a flagged `unconfirmed` when create_node isn't
18
- * available (e.g. test hub not on #299), so this UI degrades honestly.
12
+ * PR4 (#338 main lane PR4) folds RFC-026 §9.4 host_supervisor picker in front
13
+ * of the existing 5 steps. Three states the picker resolves internally:
14
+ * - count=0 onboarding (no daemon, show install command + block forward)
15
+ * - count=1 auto-pick + forward immediately
16
+ * - count≥2 user picks, then forward
17
+ * The wizard now ALWAYS passes daemon_node_id to /api/anet/node-create (the
18
+ * route's `resolveLocalDaemonNodeId` fallback only fires if daemon_node_id is
19
+ * absent kept for back-compat with non-wizard callers but no longer used
20
+ * from this flow). Per [[feedback_doc_capability_claim_verify_code_path]]
21
+ * the API contract is exercised locally before any prod hub touches the path.
19
22
  */
20
23
 
21
- const RUNTIMES: { id: string; label: string; models: string[] }[] = [
22
- { id: 'claude-agent-sdk', label: 'Claude Agent SDK', models: ['deepseek-v4-pro', 'MiniMax-M3', 'claude-sonnet-4-6', 'claude-opus-4-x'] },
23
- { id: 'codex', label: 'Codex', models: ['gpt-5.5'] },
24
- { id: 'grok', label: 'Grok', models: ['grok-build'] },
24
+ // IDs MUST match the hub validator enums (server/src/create-node-validate.ts).
25
+ // Caught via local /mcp probe during mobile wizard build (#338 plan B):
26
+ // pre-fix RUNTIMES had 'codex' + 'grok' but hub accepts 'codex-sdk' +
27
+ // 'grok-build-acp'; pre-fix PERMISSION_MODES had 'auto' but hub rejects it
28
+ // (flag_value_invalid). The wizard has been silently shipping invalid combos
29
+ // for any non-claude-agent-sdk pick since M2 — only worked end-to-end with
30
+ // the default claude path.
31
+ //
32
+ // `defaultModel` — hub's `create_node.node_spec.model` schema is
33
+ // `z.string().min(1).max(100)`; the wizard's "默认" option leaves the state
34
+ // empty, so pre-fix the POST body dropped `model` entirely and hub rejected
35
+ // with `Invalid input: expected string, received undefined`. `defaultModel`
36
+ // gets substituted before submit (and shown in the dropdown label so the
37
+ // operator knows what "默认" will actually become).
38
+ const RUNTIMES: { id: string; label: string; models: string[]; defaultModel: string }[] = [
39
+ { id: 'claude-agent-sdk', label: 'Claude Agent SDK', models: ['deepseek-v4-pro', 'MiniMax-M3', 'claude-sonnet-4-6', 'claude-opus-4-x'], defaultModel: 'claude-sonnet-4-6' },
40
+ { id: 'codex-sdk', label: 'Codex SDK', models: ['gpt-5.5'], defaultModel: 'gpt-5.5' },
41
+ { id: 'grok-build-acp', label: 'Grok (build-acp)', models: ['grok-build'], defaultModel: 'grok-build' },
25
42
  ];
26
- const PERMISSION_MODES = ['auto', 'default', 'bypassPermissions'];
27
- const STEPS = ['名字', 'Runtime', '模型', '参数', '确认'];
43
+ const PERMISSION_MODES = ['default', 'acceptEdits', 'plan', 'bypassPermissions'];
44
+ const STEPS = ['服务器', '名字', 'Runtime', '模型', '参数', '确认'];
28
45
 
29
46
  type Phase = 'form' | 'creating' | 'done' | 'unconfirmed' | 'error';
30
47
 
@@ -38,10 +55,15 @@ export function CreateNodeWizard({
38
55
  onCreated?: (result: unknown) => void;
39
56
  }) {
40
57
  const [step, setStep] = useState(0);
58
+ const [daemonNodeId, setDaemonNodeId] = useState<string | null>(null);
59
+ // (#338 wizard-runtime-filter) keep the full daemon row so the Runtime
60
+ // step can disable runtimes the chosen daemon doesn't declare support
61
+ // for. Hub-side enforcement still wins; this is UX surfacing.
62
+ const [daemon, setDaemon] = useState<DaemonOption | null>(null);
41
63
  const [name, setName] = useState('');
42
64
  const [runtimeId, setRuntimeId] = useState(RUNTIMES[0].id);
43
65
  const [model, setModel] = useState('');
44
- const [permissionMode, setPermissionMode] = useState('auto');
66
+ const [permissionMode, setPermissionMode] = useState('default');
45
67
  const [maxTurns, setMaxTurns] = useState('');
46
68
  const [budget, setBudget] = useState('');
47
69
  const [timeout, setTimeout] = useState('');
@@ -84,17 +106,26 @@ export function CreateNodeWizard({
84
106
 
85
107
  const runtime = RUNTIMES.find(r => r.id === runtimeId) || RUNTIMES[0];
86
108
  const nameValid = name.trim().length > 0;
87
- const canNext = step !== 0 || nameValid;
109
+ const canNext =
110
+ (step === 0 && Boolean(daemonNodeId)) || // step 0: must have chosen a daemon
111
+ (step === 1 && nameValid) || // step 1: name non-empty
112
+ (step >= 2 && step < STEPS.length); // later steps: nothing required to advance
88
113
  const busy = phase === 'creating';
89
114
 
90
115
  async function handleCreate() {
91
116
  setPhase('creating');
92
117
  setMsg('');
93
118
  const numOrUndef = (v: string) => (v.trim() === '' ? undefined : Number(v));
119
+ // Hub's create_node.node_spec.model schema is z.string().min(1); the
120
+ // wizard's "默认" option leaves state empty, so pick the runtime's
121
+ // documented default here. This mirrors what agent-node itself defaults
122
+ // to at boot (see agent-node cli.ts model resolution), so the "默认"
123
+ // dropdown label + this fallback both point at the same model.
124
+ const effectiveModel = model || runtime.defaultModel;
94
125
  const node_spec = {
95
126
  name: name.trim(),
96
127
  runtime: runtimeId,
97
- ...(model ? { model } : {}),
128
+ model: effectiveModel,
98
129
  flags: {
99
130
  permissionMode,
100
131
  maxTurns: numOrUndef(maxTurns),
@@ -106,7 +137,11 @@ export function CreateNodeWizard({
106
137
  const r = await fetch('/api/anet/node-create', {
107
138
  method: 'POST',
108
139
  headers: { 'Content-Type': 'application/json' },
109
- body: JSON.stringify({ node_spec, ...(networkId ? { network_id: networkId } : {}) }),
140
+ body: JSON.stringify({
141
+ node_spec,
142
+ ...(daemonNodeId ? { daemon_node_id: daemonNodeId } : {}),
143
+ ...(networkId ? { network_id: networkId } : {}),
144
+ }),
110
145
  });
111
146
  const data = await r.json().catch(() => ({}));
112
147
  if (r.ok && data?.ok) {
@@ -135,7 +170,9 @@ export function CreateNodeWizard({
135
170
  <div
136
171
  role="dialog"
137
172
  aria-label="新建节点"
138
- className="fixed left-1/2 top-1/2 z-50 w-[min(92vw,440px)] -translate-x-1/2 -translate-y-1/2 rounded-xl border border-[#26262b] bg-[#161618] shadow-2xl"
173
+ // RFC-026 §9.4 responsive: mobile single-screen (full width minus
174
+ // gutter, taller); desktop ~3-col-friendly width when picker is shown.
175
+ className="fixed left-1/2 top-1/2 z-50 w-[min(94vw,440px)] md:w-[min(92vw,720px)] -translate-x-1/2 -translate-y-1/2 rounded-xl border border-[#26262b] bg-[#161618] shadow-2xl"
139
176
  >
140
177
  {/* Header */}
141
178
  <div className="flex items-center justify-between border-b border-[#26262b] px-4 py-3">
@@ -187,44 +224,94 @@ export function CreateNodeWizard({
187
224
  ) : (
188
225
  <>
189
226
  {step === 0 && (
227
+ <div className="space-y-2">
228
+ <span className="text-xs text-gray-400">在哪台机器上创建</span>
229
+ <HostSupervisorPicker
230
+ networkId={netId || undefined}
231
+ value={daemonNodeId}
232
+ onChange={(id, d) => {
233
+ setDaemonNodeId(id);
234
+ setDaemon(d);
235
+ // (#338 wizard-runtime-filter) If the current runtime
236
+ // pick isn't supported by the new daemon, reset so
237
+ // the user is forced to re-pick on step 2. Otherwise
238
+ // they could land on step 5 (确认) with an
239
+ // already-invalid combo that only hub rejection
240
+ // surfaces.
241
+ const supported = d?.runtimes_supported;
242
+ if (supported && supported.length > 0 && !supported.includes(runtimeId)) {
243
+ setRuntimeId(supported[0]);
244
+ setModel('');
245
+ }
246
+ }}
247
+ />
248
+ {!daemonNodeId && (
249
+ <p className="text-[11px] text-gray-600">
250
+ 没选服务器之前无法继续;如果列表是空的,按提示在目标机器上跑 <code className="rounded bg-black/40 px-1 py-0.5">anet daemon up &lt;name&gt;</code>。
251
+ </p>
252
+ )}
253
+ </div>
254
+ )}
255
+ {step === 1 && (
190
256
  <label className="block space-y-1.5">
191
257
  <span className="text-xs text-gray-400">节点名字</span>
192
258
  <input autoFocus value={name} onChange={e => setName(e.target.value)} placeholder="例如 my-agent-1" className={inputCls} />
193
259
  {!nameValid && <span className="text-[11px] text-gray-600">名字不能为空</span>}
194
260
  </label>
195
261
  )}
196
- {step === 1 && (
262
+ {step === 2 && (
197
263
  <div className="space-y-2">
198
- <span className="text-xs text-gray-400">Runtime</span>
199
- {RUNTIMES.map(r => (
200
- <button
201
- key={r.id}
202
- type="button"
203
- onClick={() => { setRuntimeId(r.id); setModel(''); }}
204
- className={`flex w-full items-center justify-between rounded-md border px-3 py-2 text-sm transition-colors ${
205
- runtimeId === r.id ? 'border-cyan-600 bg-cyan-900/15 text-cyan-200' : 'border-[#26262b] bg-[#0e0e10] text-gray-300 hover:border-[#3a3a41]'
206
- }`}
207
- >
208
- {r.label}
209
- {runtimeId === r.id && (
210
- <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round" aria-hidden>
211
- <path d="M20 6 9 17l-5-5" />
212
- </svg>
213
- )}
214
- </button>
215
- ))}
264
+ <span className="text-xs text-gray-400">
265
+ Runtime{daemon ? `(${daemon.alias} 支持)` : ''}
266
+ </span>
267
+ {RUNTIMES.map(r => {
268
+ // (#338 wizard-runtime-filter) Permissive when the
269
+ // daemon didn't publish runtimes_supported at all
270
+ // (pre-PR3 daemons OR daemons not yet upgraded) hub
271
+ // still validates. Restrictive only when the daemon
272
+ // explicitly told us its supported set.
273
+ const supported = daemon?.runtimes_supported;
274
+ const disabled = Array.isArray(supported) && supported.length > 0 && !supported.includes(r.id);
275
+ const selected = runtimeId === r.id;
276
+ return (
277
+ <button
278
+ key={r.id}
279
+ type="button"
280
+ disabled={disabled}
281
+ onClick={() => { if (!disabled) { setRuntimeId(r.id); setModel(''); } }}
282
+ title={disabled ? `${daemon?.alias || '该 daemon'} 未声明支持此 runtime` : undefined}
283
+ className={`flex w-full items-center justify-between rounded-md border px-3 py-2 text-sm transition-colors ${
284
+ disabled
285
+ ? 'border-[#1c1c1f] bg-[#0a0a0c] text-gray-600 cursor-not-allowed'
286
+ : selected
287
+ ? 'border-cyan-600 bg-cyan-900/15 text-cyan-200'
288
+ : 'border-[#26262b] bg-[#0e0e10] text-gray-300 hover:border-[#3a3a41]'
289
+ }`}
290
+ >
291
+ <span>
292
+ {r.label}
293
+ {disabled && <span className="ml-2 text-[10px] text-gray-700">该 daemon 不支持</span>}
294
+ </span>
295
+ {selected && !disabled && (
296
+ <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round" aria-hidden>
297
+ <path d="M20 6 9 17l-5-5" />
298
+ </svg>
299
+ )}
300
+ </button>
301
+ );
302
+ })}
216
303
  </div>
217
304
  )}
218
- {step === 2 && (
305
+ {step === 3 && (
219
306
  <label className="block space-y-1.5">
220
307
  <span className="text-xs text-gray-400">模型({runtime.label})</span>
221
308
  <select value={model} onChange={e => setModel(e.target.value)} className={inputCls}>
222
- <option value="">默认</option>
309
+ <option value="">默认({runtime.defaultModel})</option>
223
310
  {runtime.models.map(m => <option key={m} value={m}>{m}</option>)}
224
311
  </select>
225
312
  </label>
226
313
  )}
227
- {step === 3 && (
314
+ {step === 4 && (
228
315
  <div className="space-y-3">
229
316
  <label className="block space-y-1.5">
230
317
  <span className="text-xs text-gray-400">permissionMode</span>
@@ -239,17 +326,23 @@ export function CreateNodeWizard({
239
326
  </div>
240
327
  </div>
241
328
  )}
242
- {step === 4 && (
329
+ {step === 5 && (
243
330
  <div className="space-y-2 text-sm">
244
331
  <div className="rounded-md border border-[#26262b] bg-[#0e0e10] divide-y divide-[#1c1c1f]">
245
- {[['名字', name.trim() || '—'], ['Runtime', runtime.label], ['模型', model || '默认'], ['permissionMode', permissionMode], ['maxTurns / budget / timeout', `${maxTurns || '—'} / ${budget || '—'} / ${timeout || '—'}`]].map(([k, v]) => (
332
+ {[
333
+ ['服务器', daemonNodeId ? `${daemonNodeId.slice(0, 24)}…` : '—'],
334
+ ['名字', name.trim() || '—'],
335
+ ['Runtime', runtime.label],
336
+ ['模型', model || `默认(${runtime.defaultModel})`],
337
+ ['permissionMode', permissionMode],
338
+ ['maxTurns / budget / timeout', `${maxTurns || '—'} / ${budget || '—'} / ${timeout || '—'}`],
339
+ ].map(([k, v]) => (
246
340
  <div key={k} className="flex items-start justify-between gap-3 px-3 py-2">
247
341
  <span className="shrink-0 text-gray-500 text-xs">{k}</span>
248
342
  <span className="text-right text-gray-200 text-xs break-all">{v}</span>
249
343
  </div>
250
344
  ))}
251
345
  </div>
252
- <p className="text-[11px] text-gray-600">P1:创建在本机 daemon(绕过选服务器)。</p>
253
346
  </div>
254
347
  )}
255
348
  </>
@@ -0,0 +1,283 @@
1
+ 'use client';
2
+
3
+ import { useEffect, useState } from 'react';
4
+
5
+ /**
6
+ * PR4 #338 — host_supervisor daemon picker (RFC-026 §9.4 locked mockup).
7
+ *
8
+ * Three states (the only branching the wizard ever sees):
9
+ *
10
+ * count=0 → onboarding: explain what a daemon is + give the install command.
11
+ * No daemon = nothing to dispatch to; create flow is blocked here
12
+ * until the user runs `anet daemon init <name>` somewhere.
13
+ *
14
+ * count=1 → auto-pick: just show "using <alias>" + a quiet `换一个 →` link
15
+ * (which switches to the picker view if the user really wants).
16
+ *
17
+ * count≥2 → picker grid: cards for each daemon w/ runtimes + alert chip,
18
+ * click selects. Desktop = up to 3 columns; mobile = single column.
19
+ *
20
+ * Data shape mirrors `/api/anet/host-supervisors`, which in turn mirrors the
21
+ * hub's GET /api/host-supervisors (#338 PR2 — needs commhub-server@0.9.0-preview.8+).
22
+ * On `unconfirmed` (older hub), we degrade honestly to an upgrade hint — never
23
+ * show a fake empty list. Per [[feedback_doc_capability_claim_verify_code_path]].
24
+ */
25
+
26
+ export interface DaemonOption {
27
+ // Hub canonical key is `daemon_node_id` (PR2 v2 §9.2 contract). We keep the
28
+ // same name end-to-end so the value the wizard passes back to create_node
29
+ // as `daemon_node_id` doesn't need a rename layer.
30
+ daemon_node_id: string;
31
+ alias: string;
32
+ hostname?: string | null;
33
+ online?: boolean;
34
+ last_seen_at?: string | null;
35
+ runtimes_supported?: string[];
36
+ host_telemetry?: {
37
+ alert_level?: 'green' | 'yellow' | 'red' | 'gray';
38
+ cpu_cores?: number | null;
39
+ mem_gb?: number | null;
40
+ ip_internal?: string | null;
41
+ };
42
+ }
43
+
44
+ interface PickResponse {
45
+ ok: boolean;
46
+ unconfirmed?: boolean;
47
+ error?: string;
48
+ count: number;
49
+ daemons: DaemonOption[];
50
+ selected?: string | null;
51
+ }
52
+
53
+ type LoadState = 'loading' | 'ready' | 'error' | 'unconfirmed';
54
+
55
+ export function HostSupervisorPicker({
56
+ networkId,
57
+ value,
58
+ onChange,
59
+ }: {
60
+ networkId?: string | null;
61
+ value: string | null;
62
+ // (#338 wizard-runtime-filter) passes the full daemon row alongside the
63
+ // id so the wizard can filter the Runtime step by daemon.runtimes_supported
64
+ // — disabling combos the hub would reject anyway and surfacing why upfront.
65
+ onChange: (nodeId: string | null, daemon: DaemonOption | null) => void;
66
+ }) {
67
+ const [state, setState] = useState<LoadState>('loading');
68
+ const [daemons, setDaemons] = useState<DaemonOption[]>([]);
69
+ const [errMsg, setErrMsg] = useState('');
70
+ const [forcePicker, setForcePicker] = useState(false);
71
+
72
+ useEffect(() => {
73
+ let alive = true;
74
+ setState('loading');
75
+ setErrMsg('');
76
+ const url = networkId
77
+ ? `/api/anet/host-supervisors?network_id=${encodeURIComponent(networkId)}`
78
+ : '/api/anet/host-supervisors';
79
+ fetch(url, { cache: 'no-store' })
80
+ .then(r => r.json().then(d => ({ status: r.status, body: d as PickResponse })))
81
+ .then(({ status, body }) => {
82
+ if (!alive) return;
83
+ if (status === 501 || body?.unconfirmed) {
84
+ setState('unconfirmed');
85
+ setErrMsg(body?.error || 'hub /api/host-supervisors unavailable — upgrade to >=0.9.0-preview.8');
86
+ setDaemons([]);
87
+ return;
88
+ }
89
+ if (!body?.ok) {
90
+ setState('error');
91
+ setErrMsg(body?.error || `hub ${status}`);
92
+ setDaemons([]);
93
+ return;
94
+ }
95
+ const list = Array.isArray(body.daemons) ? body.daemons : [];
96
+ setDaemons(list);
97
+ setState('ready');
98
+ // count=1 auto-pick: preselect the only daemon. count≥2 leaves the
99
+ // selection to the user (parent value stays null until click).
100
+ if (list.length === 1 && !value) onChange(list[0].daemon_node_id, list[0]);
101
+ })
102
+ .catch(e => {
103
+ if (!alive) return;
104
+ setState('error');
105
+ setErrMsg(e instanceof Error ? e.message : String(e));
106
+ setDaemons([]);
107
+ });
108
+ return () => { alive = false; };
109
+ // eslint-disable-next-line react-hooks/exhaustive-deps
110
+ }, [networkId]);
111
+
112
+ // ───── render branches ──────────────────────────────────────────────
113
+
114
+ if (state === 'loading') {
115
+ return (
116
+ <div className="flex items-center gap-2 rounded-md border border-[#26262b] bg-[#0e0e10] px-3 py-3 text-xs text-gray-500">
117
+ <svg className="h-3.5 w-3.5 animate-spin" viewBox="0 0 24 24" fill="none" aria-hidden>
118
+ <circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4" />
119
+ <path className="opacity-90" fill="currentColor" d="M4 12a8 8 0 018-8v4a4 4 0 00-4 4H4z" />
120
+ </svg>
121
+ 正在查询可用的 host_supervisor 节点…
122
+ </div>
123
+ );
124
+ }
125
+
126
+ if (state === 'unconfirmed') {
127
+ return (
128
+ <div className="rounded-md border border-amber-700/40 bg-amber-900/10 px-3 py-3 text-xs text-amber-200">
129
+ <div className="font-semibold mb-1">hub 暂未升级</div>
130
+ <div className="text-amber-200/80">{errMsg}</div>
131
+ <div className="mt-1 text-[11px] text-amber-200/60">
132
+ 升级到 <code className="rounded bg-black/40 px-1 py-0.5">@sleep2agi/commhub-server@0.9.0-preview.8</code> 后选服务器功能才会出现。
133
+ </div>
134
+ </div>
135
+ );
136
+ }
137
+
138
+ if (state === 'error') {
139
+ return (
140
+ <div className="rounded-md border border-red-700/40 bg-red-900/10 px-3 py-3 text-xs text-red-200">
141
+ 查询 host_supervisor 节点失败:{errMsg}
142
+ </div>
143
+ );
144
+ }
145
+
146
+ // count=0 — onboarding
147
+ if (daemons.length === 0) {
148
+ return (
149
+ <div className="rounded-md border border-[#26262b] bg-[#0e0e10] px-3 py-4 text-xs text-gray-300">
150
+ <div className="text-sm font-semibold text-gray-200">还没有可用的 host_supervisor 节点</div>
151
+ <p className="mt-1 text-gray-500">
152
+ 要在某台机器上创建节点,先在那台机器上跑一次 daemon 初始化命令:
153
+ </p>
154
+ <pre className="mt-2 overflow-x-auto rounded bg-black/40 p-2 text-[11px] text-cyan-300">{`# 任选一台目标机器(你的笔记本 / 一台服务器都行)
155
+ anet daemon up my-daemon`}</pre>
156
+ <p className="mt-2 text-gray-500">
157
+ 注册成功后这里会自动出现,无需刷新。
158
+ </p>
159
+ </div>
160
+ );
161
+ }
162
+
163
+ // count=1 — auto-pick (collapsed). User can opt into picker via "换一个 →".
164
+ if (daemons.length === 1 && !forcePicker) {
165
+ const d = daemons[0];
166
+ return (
167
+ <div className="rounded-md border border-cyan-700/40 bg-cyan-900/10 px-3 py-3 text-xs text-cyan-100">
168
+ <div className="flex items-center justify-between gap-2">
169
+ <div>
170
+ <span className="text-cyan-400/80">将在</span>{' '}
171
+ <span className="font-semibold">{d.alias}</span>
172
+ <span className="text-cyan-300/60"> ({d.hostname || '—'}) </span>
173
+ <span className="text-cyan-400/80">上创建</span>
174
+ </div>
175
+ {/* Single-daemon networks can still let the user enter picker view; */}
176
+ {/* useful if they want to see telemetry before committing. */}
177
+ <button
178
+ type="button"
179
+ onClick={() => setForcePicker(true)}
180
+ className="text-[11px] text-cyan-400 hover:text-cyan-200 underline-offset-2 hover:underline"
181
+ >
182
+ 详情 →
183
+ </button>
184
+ </div>
185
+ <RuntimeList runtimes={d.runtimes_supported} className="mt-1" />
186
+ </div>
187
+ );
188
+ }
189
+
190
+ // count≥2 (or forcePicker=true) — grid picker. Desktop up to 3 columns,
191
+ // mobile = single column. Locked per RFC-026 §9.4 mockup.
192
+ return (
193
+ <div className="space-y-2">
194
+ <div className="flex items-center justify-between text-xs text-gray-400">
195
+ <span>选择一台 host_supervisor 节点({daemons.length} 台在线)</span>
196
+ {forcePicker && daemons.length === 1 && (
197
+ <button
198
+ type="button"
199
+ onClick={() => setForcePicker(false)}
200
+ className="text-[11px] text-gray-500 hover:text-gray-300"
201
+ >
202
+ ← 折叠
203
+ </button>
204
+ )}
205
+ </div>
206
+ <div className="grid grid-cols-1 gap-2 md:grid-cols-2 lg:grid-cols-3">
207
+ {daemons.map(d => (
208
+ <DaemonCard
209
+ key={d.daemon_node_id}
210
+ daemon={d}
211
+ selected={d.daemon_node_id === value}
212
+ onClick={() => onChange(d.daemon_node_id, d)}
213
+ />
214
+ ))}
215
+ </div>
216
+ </div>
217
+ );
218
+ }
219
+
220
+ // ───── subcomponents ──────────────────────────────────────────────────
221
+
222
+ function DaemonCard({
223
+ daemon,
224
+ selected,
225
+ onClick,
226
+ }: {
227
+ daemon: DaemonOption;
228
+ selected: boolean;
229
+ onClick: () => void;
230
+ }) {
231
+ const alert = daemon.host_telemetry?.alert_level || 'gray';
232
+ return (
233
+ <button
234
+ type="button"
235
+ onClick={onClick}
236
+ aria-pressed={selected}
237
+ className={`flex w-full flex-col gap-1.5 rounded-md border px-3 py-2.5 text-left text-xs transition-colors ${
238
+ selected
239
+ ? 'border-cyan-600 bg-cyan-900/15 text-cyan-100'
240
+ : 'border-[#26262b] bg-[#0e0e10] text-gray-300 hover:border-[#3a3a41]'
241
+ }`}
242
+ >
243
+ <div className="flex items-center justify-between gap-2">
244
+ <span className="truncate font-semibold">{daemon.alias}</span>
245
+ <AlertChip level={alert} />
246
+ </div>
247
+ <div className="truncate text-[11px] text-gray-500">{daemon.hostname || '—'}</div>
248
+ <RuntimeList runtimes={daemon.runtimes_supported} />
249
+ {(daemon.host_telemetry?.cpu_cores != null || daemon.host_telemetry?.mem_gb != null) && (
250
+ <div className="flex gap-3 text-[10px] text-gray-500">
251
+ {daemon.host_telemetry?.cpu_cores != null && <span>{daemon.host_telemetry.cpu_cores} 核</span>}
252
+ {daemon.host_telemetry?.mem_gb != null && <span>{daemon.host_telemetry.mem_gb} GB</span>}
253
+ </div>
254
+ )}
255
+ </button>
256
+ );
257
+ }
258
+
259
+ function RuntimeList({ runtimes, className = '' }: { runtimes?: string[]; className?: string }) {
260
+ if (!runtimes || runtimes.length === 0) {
261
+ return <div className={`text-[10px] text-gray-600 ${className}`}>runtimes_supported: —</div>;
262
+ }
263
+ return (
264
+ <div className={`flex flex-wrap gap-1 ${className}`}>
265
+ {runtimes.map(r => (
266
+ <span key={r} className="rounded bg-[#1c1c1f] px-1.5 py-0.5 text-[10px] text-gray-400">{r}</span>
267
+ ))}
268
+ </div>
269
+ );
270
+ }
271
+
272
+ function AlertChip({ level }: { level: 'green' | 'yellow' | 'red' | 'gray' }) {
273
+ const cls = {
274
+ green: 'bg-green-600/20 text-green-300 border-green-700/40',
275
+ yellow: 'bg-amber-600/20 text-amber-300 border-amber-700/40',
276
+ red: 'bg-red-600/20 text-red-300 border-red-700/40',
277
+ gray: 'bg-gray-600/20 text-gray-400 border-gray-700/40',
278
+ }[level];
279
+ const label = { green: '正常', yellow: '注意', red: '警报', gray: '离线' }[level];
280
+ return (
281
+ <span className={`rounded border px-1.5 py-0.5 text-[10px] ${cls}`}>{label}</span>
282
+ );
283
+ }