@sleep2agi/agent-network-dashboard 0.6.3-preview.44 → 0.6.3-preview.45

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 (185) hide show
  1. package/.next/BUILD_COMMIT +1 -1
  2. package/.next/BUILD_ID +1 -1
  3. package/.next/build-manifest.json +3 -3
  4. package/.next/diagnostics/route-bundle-stats.json +52 -52
  5. package/.next/fallback-build-manifest.json +3 -3
  6. package/.next/server/app/_global-error.html +1 -1
  7. package/.next/server/app/_global-error.rsc +1 -1
  8. package/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  9. package/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  10. package/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  11. package/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  12. package/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  13. package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  14. package/.next/server/app/_not-found.html +2 -2
  15. package/.next/server/app/_not-found.rsc +12 -12
  16. package/.next/server/app/_not-found.segments/_full.segment.rsc +12 -12
  17. package/.next/server/app/_not-found.segments/_head.segment.rsc +4 -4
  18. package/.next/server/app/_not-found.segments/_index.segment.rsc +7 -7
  19. package/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +2 -2
  20. package/.next/server/app/_not-found.segments/_not-found.segment.rsc +3 -3
  21. package/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  22. package/.next/server/app/admin/page_client-reference-manifest.js +1 -1
  23. package/.next/server/app/admin.html +2 -2
  24. package/.next/server/app/admin.rsc +14 -14
  25. package/.next/server/app/admin.segments/_full.segment.rsc +14 -14
  26. package/.next/server/app/admin.segments/_head.segment.rsc +4 -4
  27. package/.next/server/app/admin.segments/_index.segment.rsc +7 -7
  28. package/.next/server/app/admin.segments/_tree.segment.rsc +1 -1
  29. package/.next/server/app/admin.segments/admin/__PAGE__.segment.rsc +4 -4
  30. package/.next/server/app/admin.segments/admin.segment.rsc +3 -3
  31. package/.next/server/app/index.html +2 -2
  32. package/.next/server/app/index.rsc +14 -14
  33. package/.next/server/app/index.segments/__PAGE__.segment.rsc +4 -4
  34. package/.next/server/app/index.segments/_full.segment.rsc +14 -14
  35. package/.next/server/app/index.segments/_head.segment.rsc +4 -4
  36. package/.next/server/app/index.segments/_index.segment.rsc +7 -7
  37. package/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  38. package/.next/server/app/login/page_client-reference-manifest.js +1 -1
  39. package/.next/server/app/login.html +2 -2
  40. package/.next/server/app/login.rsc +14 -14
  41. package/.next/server/app/login.segments/_full.segment.rsc +14 -14
  42. package/.next/server/app/login.segments/_head.segment.rsc +4 -4
  43. package/.next/server/app/login.segments/_index.segment.rsc +7 -7
  44. package/.next/server/app/login.segments/_tree.segment.rsc +1 -1
  45. package/.next/server/app/login.segments/login/__PAGE__.segment.rsc +4 -4
  46. package/.next/server/app/login.segments/login.segment.rsc +3 -3
  47. package/.next/server/app/logs/page_client-reference-manifest.js +1 -1
  48. package/.next/server/app/logs.html +2 -2
  49. package/.next/server/app/logs.rsc +14 -14
  50. package/.next/server/app/logs.segments/_full.segment.rsc +14 -14
  51. package/.next/server/app/logs.segments/_head.segment.rsc +4 -4
  52. package/.next/server/app/logs.segments/_index.segment.rsc +7 -7
  53. package/.next/server/app/logs.segments/_tree.segment.rsc +1 -1
  54. package/.next/server/app/logs.segments/logs/__PAGE__.segment.rsc +4 -4
  55. package/.next/server/app/logs.segments/logs.segment.rsc +3 -3
  56. package/.next/server/app/messages/page_client-reference-manifest.js +1 -1
  57. package/.next/server/app/messages.html +2 -2
  58. package/.next/server/app/messages.rsc +14 -14
  59. package/.next/server/app/messages.segments/_full.segment.rsc +14 -14
  60. package/.next/server/app/messages.segments/_head.segment.rsc +4 -4
  61. package/.next/server/app/messages.segments/_index.segment.rsc +7 -7
  62. package/.next/server/app/messages.segments/_tree.segment.rsc +1 -1
  63. package/.next/server/app/messages.segments/messages/__PAGE__.segment.rsc +4 -4
  64. package/.next/server/app/messages.segments/messages.segment.rsc +3 -3
  65. package/.next/server/app/node/page_client-reference-manifest.js +1 -1
  66. package/.next/server/app/node.html +2 -2
  67. package/.next/server/app/node.rsc +14 -14
  68. package/.next/server/app/node.segments/_full.segment.rsc +14 -14
  69. package/.next/server/app/node.segments/_head.segment.rsc +4 -4
  70. package/.next/server/app/node.segments/_index.segment.rsc +7 -7
  71. package/.next/server/app/node.segments/_tree.segment.rsc +1 -1
  72. package/.next/server/app/node.segments/node/__PAGE__.segment.rsc +4 -4
  73. package/.next/server/app/node.segments/node.segment.rsc +3 -3
  74. package/.next/server/app/nodes/page_client-reference-manifest.js +1 -1
  75. package/.next/server/app/nodes.html +2 -2
  76. package/.next/server/app/nodes.rsc +14 -14
  77. package/.next/server/app/nodes.segments/_full.segment.rsc +14 -14
  78. package/.next/server/app/nodes.segments/_head.segment.rsc +4 -4
  79. package/.next/server/app/nodes.segments/_index.segment.rsc +7 -7
  80. package/.next/server/app/nodes.segments/_tree.segment.rsc +1 -1
  81. package/.next/server/app/nodes.segments/nodes/__PAGE__.segment.rsc +4 -4
  82. package/.next/server/app/nodes.segments/nodes.segment.rsc +3 -3
  83. package/.next/server/app/page_client-reference-manifest.js +1 -1
  84. package/.next/server/app/providers/page_client-reference-manifest.js +1 -1
  85. package/.next/server/app/providers.html +2 -2
  86. package/.next/server/app/providers.rsc +14 -14
  87. package/.next/server/app/providers.segments/_full.segment.rsc +14 -14
  88. package/.next/server/app/providers.segments/_head.segment.rsc +4 -4
  89. package/.next/server/app/providers.segments/_index.segment.rsc +7 -7
  90. package/.next/server/app/providers.segments/_tree.segment.rsc +1 -1
  91. package/.next/server/app/providers.segments/providers/__PAGE__.segment.rsc +4 -4
  92. package/.next/server/app/providers.segments/providers.segment.rsc +3 -3
  93. package/.next/server/app/server-logs/page_client-reference-manifest.js +1 -1
  94. package/.next/server/app/server-logs.html +2 -2
  95. package/.next/server/app/server-logs.rsc +14 -14
  96. package/.next/server/app/server-logs.segments/_full.segment.rsc +14 -14
  97. package/.next/server/app/server-logs.segments/_head.segment.rsc +4 -4
  98. package/.next/server/app/server-logs.segments/_index.segment.rsc +7 -7
  99. package/.next/server/app/server-logs.segments/_tree.segment.rsc +1 -1
  100. package/.next/server/app/server-logs.segments/server-logs/__PAGE__.segment.rsc +4 -4
  101. package/.next/server/app/server-logs.segments/server-logs.segment.rsc +3 -3
  102. package/.next/server/app/servers/page_client-reference-manifest.js +1 -1
  103. package/.next/server/app/servers.html +2 -2
  104. package/.next/server/app/servers.rsc +14 -14
  105. package/.next/server/app/servers.segments/_full.segment.rsc +14 -14
  106. package/.next/server/app/servers.segments/_head.segment.rsc +4 -4
  107. package/.next/server/app/servers.segments/_index.segment.rsc +7 -7
  108. package/.next/server/app/servers.segments/_tree.segment.rsc +1 -1
  109. package/.next/server/app/servers.segments/servers/__PAGE__.segment.rsc +4 -4
  110. package/.next/server/app/servers.segments/servers.segment.rsc +3 -3
  111. package/.next/server/app/settings/networks/page_client-reference-manifest.js +1 -1
  112. package/.next/server/app/settings/networks.html +2 -2
  113. package/.next/server/app/settings/networks.rsc +14 -14
  114. package/.next/server/app/settings/networks.segments/_full.segment.rsc +14 -14
  115. package/.next/server/app/settings/networks.segments/_head.segment.rsc +4 -4
  116. package/.next/server/app/settings/networks.segments/_index.segment.rsc +7 -7
  117. package/.next/server/app/settings/networks.segments/_tree.segment.rsc +1 -1
  118. package/.next/server/app/settings/networks.segments/settings/networks/__PAGE__.segment.rsc +4 -4
  119. package/.next/server/app/settings/networks.segments/settings/networks.segment.rsc +3 -3
  120. package/.next/server/app/settings/networks.segments/settings.segment.rsc +3 -3
  121. package/.next/server/app/settings/page_client-reference-manifest.js +1 -1
  122. package/.next/server/app/settings/tokens/page_client-reference-manifest.js +1 -1
  123. package/.next/server/app/settings/tokens.html +2 -2
  124. package/.next/server/app/settings/tokens.rsc +14 -14
  125. package/.next/server/app/settings/tokens.segments/_full.segment.rsc +14 -14
  126. package/.next/server/app/settings/tokens.segments/_head.segment.rsc +4 -4
  127. package/.next/server/app/settings/tokens.segments/_index.segment.rsc +7 -7
  128. package/.next/server/app/settings/tokens.segments/_tree.segment.rsc +1 -1
  129. package/.next/server/app/settings/tokens.segments/settings/tokens/__PAGE__.segment.rsc +4 -4
  130. package/.next/server/app/settings/tokens.segments/settings/tokens.segment.rsc +3 -3
  131. package/.next/server/app/settings/tokens.segments/settings.segment.rsc +3 -3
  132. package/.next/server/app/settings.html +2 -2
  133. package/.next/server/app/settings.rsc +14 -14
  134. package/.next/server/app/settings.segments/_full.segment.rsc +14 -14
  135. package/.next/server/app/settings.segments/_head.segment.rsc +4 -4
  136. package/.next/server/app/settings.segments/_index.segment.rsc +7 -7
  137. package/.next/server/app/settings.segments/_tree.segment.rsc +1 -1
  138. package/.next/server/app/settings.segments/settings/__PAGE__.segment.rsc +4 -4
  139. package/.next/server/app/settings.segments/settings.segment.rsc +3 -3
  140. package/.next/server/app/tasks/[id]/page_client-reference-manifest.js +1 -1
  141. package/.next/server/app/tasks/page_client-reference-manifest.js +1 -1
  142. package/.next/server/app/tasks.html +2 -2
  143. package/.next/server/app/tasks.rsc +14 -14
  144. package/.next/server/app/tasks.segments/_full.segment.rsc +14 -14
  145. package/.next/server/app/tasks.segments/_head.segment.rsc +4 -4
  146. package/.next/server/app/tasks.segments/_index.segment.rsc +7 -7
  147. package/.next/server/app/tasks.segments/_tree.segment.rsc +1 -1
  148. package/.next/server/app/tasks.segments/tasks/__PAGE__.segment.rsc +4 -4
  149. package/.next/server/app/tasks.segments/tasks.segment.rsc +3 -3
  150. package/.next/server/chunks/ssr/[root-of-the-server]__0z0lvdf._.js +1 -1
  151. package/.next/server/chunks/ssr/[root-of-the-server]__0z0lvdf._.js.map +1 -1
  152. package/.next/server/chunks/ssr/[root-of-the-server]__13svd64._.js +1 -1
  153. package/.next/server/chunks/ssr/[root-of-the-server]__13svd64._.js.map +1 -1
  154. package/.next/server/chunks/ssr/dash-492_agent-network-dashboard_0f4savf._.js +2 -2
  155. package/.next/server/chunks/ssr/dash-492_agent-network-dashboard_0f4savf._.js.map +1 -1
  156. package/.next/server/chunks/ssr/dash-492_agent-network-dashboard_app_0fv9~x1._.js +1 -1
  157. package/.next/server/chunks/ssr/dash-492_agent-network-dashboard_app_0fv9~x1._.js.map +1 -1
  158. package/.next/server/chunks/ssr/dash-492_agent-network-dashboard_app_10nv4wt._.js +1 -1
  159. package/.next/server/chunks/ssr/dash-492_agent-network-dashboard_app_10nv4wt._.js.map +1 -1
  160. package/.next/server/chunks/ssr/dash-492_agent-network-dashboard_app_components_07gcm8v._.js +1 -1
  161. package/.next/server/chunks/ssr/dash-492_agent-network-dashboard_app_components_07gcm8v._.js.map +1 -1
  162. package/.next/server/middleware-build-manifest.js +3 -3
  163. package/.next/server/pages/404.html +2 -2
  164. package/.next/server/pages/500.html +1 -1
  165. package/.next/static/chunks/{0b3jrmai2phnc.js → 00.lep~gx75xc.js} +1 -1
  166. package/.next/static/chunks/{03kazq4f2o8kc.js → 0gv~xarphwy7~.js} +1 -1
  167. package/.next/static/chunks/{0mqxob_pphde0.js → 0k_3kdj.1c2m5.js} +1 -1
  168. package/.next/static/chunks/0~rml5aiu3yw7.js +7 -0
  169. package/.next/static/chunks/{17bch5v2vnph5.js → 0~v0m8f1.aob5.js} +2 -2
  170. package/.next/static/chunks/16kecv_vyjyyv.js +1 -0
  171. package/.next/trace +2 -2
  172. package/.next/trace-build +1 -1
  173. package/app/components/HealthBanner.tsx +21 -2
  174. package/app/components/Sidebar.tsx +8 -2
  175. package/app/components/StatsBar.tsx +32 -14
  176. package/app/lib/presence.ts +56 -1
  177. package/app/page.tsx +17 -4
  178. package/package.json +1 -1
  179. package/tests/e2e-53-blind-vs-empty.spec.ts +262 -0
  180. package/tests/e2e-53-presence-status.spec.ts +52 -0
  181. package/.next/static/chunks/0adq.v18n1i97.js +0 -7
  182. package/.next/static/chunks/0ws5f9sp.pgiv.js +0 -1
  183. /package/.next/static/{VeCvA8ZJHnHbQwP2X4xfs → EEoQxe-lggOsAx0h8hIFx}/_buildManifest.js +0 -0
  184. /package/.next/static/{VeCvA8ZJHnHbQwP2X4xfs → EEoQxe-lggOsAx0h8hIFx}/_clientMiddlewareManifest.js +0 -0
  185. /package/.next/static/{VeCvA8ZJHnHbQwP2X4xfs → EEoQxe-lggOsAx0h8hIFx}/_ssgManifest.js +0 -0
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../dash-492/agent-network-dashboard/node_modules/next/src/server/route-modules/app-page/module.compiled.js","../../../../../../dash-492/agent-network-dashboard/node_modules/next/src/server/route-modules/app-page/vendored/ssr/react-jsx-runtime.ts","../../../../../../dash-492/agent-network-dashboard/node_modules/next/src/server/route-modules/app-page/vendored/ssr/react.ts","../../../../../../dash-492/agent-network-dashboard/node_modules/next/src/server/route-modules/app-page/vendored/contexts/app-router-context.ts","../../../../../../dash-492/agent-network-dashboard/node_modules/next/src/server/route-modules/app-page/vendored/ssr/react-server-dom-turbopack-client.ts","../../../../../../dash-492/agent-network-dashboard/node_modules/next/src/server/route-modules/app-page/vendored/contexts/hooks-client-context.ts","../../../../../../dash-492/agent-network-dashboard/node_modules/next/src/server/route-modules/app-page/vendored/contexts/server-inserted-html.ts","../../../../../../dash-492/agent-network-dashboard/app/lib/time.ts","../../../../../../dash-492/agent-network-dashboard/app/lib/network-context.tsx","../../../../../../dash-492/agent-network-dashboard/app/lib/hooks.ts","../../../../../../dash-492/agent-network-dashboard/app/lib/presence.ts","../../../../../../dash-492/agent-network-dashboard/app/lib/chat-unread.ts","../../../../../../dash-492/agent-network-dashboard/app/lib/chat-mute.ts","../../../../../../dash-492/agent-network-dashboard/app/components/ThemeSwitcher.tsx","../../../../../../dash-492/agent-network-dashboard/app/components/ServersDrawer.tsx"],"sourcesContent":["if (process.env.NEXT_RUNTIME === 'edge') {\n module.exports = require('next/dist/server/route-modules/app-page/module.js')\n} else {\n if (process.env.__NEXT_EXPERIMENTAL_REACT) {\n if (process.env.NODE_ENV === 'development') {\n if (process.env.TURBOPACK) {\n module.exports = require('next/dist/compiled/next-server/app-page-turbo-experimental.runtime.dev.js')\n } else {\n module.exports = require('next/dist/compiled/next-server/app-page-experimental.runtime.dev.js')\n }\n } else {\n if (process.env.TURBOPACK) {\n module.exports = require('next/dist/compiled/next-server/app-page-turbo-experimental.runtime.prod.js')\n } else {\n module.exports = require('next/dist/compiled/next-server/app-page-experimental.runtime.prod.js')\n }\n }\n } else {\n if (process.env.NODE_ENV === 'development') {\n if (process.env.TURBOPACK) {\n module.exports = require('next/dist/compiled/next-server/app-page-turbo.runtime.dev.js')\n } else {\n module.exports = require('next/dist/compiled/next-server/app-page.runtime.dev.js')\n }\n } else {\n if (process.env.TURBOPACK) {\n module.exports = require('next/dist/compiled/next-server/app-page-turbo.runtime.prod.js')\n } else {\n module.exports = require('next/dist/compiled/next-server/app-page.runtime.prod.js')\n }\n }\n }\n}\n","module.exports = (\n require('../../module.compiled') as typeof import('../../module.compiled')\n).vendored['react-ssr']!.ReactJsxRuntime\n","module.exports = (\n require('../../module.compiled') as typeof import('../../module.compiled')\n).vendored['react-ssr']!.React\n","module.exports = (\n require('../../module.compiled') as typeof import('../../module.compiled')\n).vendored['contexts'].AppRouterContext\n","module.exports = (\n require('../../module.compiled') as typeof import('../../module.compiled')\n).vendored['react-ssr']!.ReactServerDOMTurbopackClient\n","module.exports = (\n require('../../module.compiled') as typeof import('../../module.compiled')\n).vendored['contexts'].HooksClientContext\n","module.exports = (\n require('../../module.compiled') as typeof import('../../module.compiled')\n).vendored['contexts'].ServerInsertedHtml\n","/** Shared timestamp helpers for hub-sourced data.\n *\n * Background — the CommHub serialises timestamps SQL-style without a\n * zone (\"2026-05-15 06:00:28\"), but some test data uses full ISO\n * (\"…T06:00:28Z\"). `Date.parse` on bare SQL is **local-time** in every\n * browser the dashboard supports, so a UTC+8 operator silently sees\n * every timestamp 8 h older than reality (Round 35 dug this out via\n * the `isGhost` filter mis-fire).\n *\n * Round 38 / Loop consolidates parsing — TopoGraph (R35), ChatPopover\n * (R37) and utils.ts::timeAgo all mirrored the same SQL→UTC rewrite;\n * one source of truth here. */\n\n/** Parse a hub timestamp to ms-since-epoch, treating SQL-style strings\n * as UTC. ISO strings (with `T`) bypass the rewrite and are parsed as-is.\n * Returns null for empty / unparseable input. */\nexport function parseHubTime(dateStr: string | null | undefined): number | null {\n if (!dateStr) return null;\n const iso = dateStr.includes('T') ? dateStr : dateStr.replace(' ', 'T') + 'Z';\n const t = Date.parse(iso);\n return Number.isFinite(t) ? t : null;\n}\n\n/** Format `dateStr` as a short relative-time string (\"6m ago\" / \"2h ago\").\n * Future timestamps (clock skew) collapse to \"just now\". Returns null when\n * the input doesn't parse — callers can decide on a fallback. */\nexport function relativeAgo(dateStr: string | null | undefined): string | null {\n const t = parseHubTime(dateStr);\n if (t === null) return null;\n const s = Math.floor((Date.now() - t) / 1000);\n if (s < 0) return 'just now';\n if (s < 60) return `${s}s ago`;\n if (s < 3600) return `${Math.floor(s / 60)}m ago`;\n if (s < 86400) return `${Math.floor(s / 3600)}h ago`;\n return `${Math.floor(s / 86400)}d ago`;\n}\n\n/** Loop R7 (跨面一致性): WeChat-style contextual timestamp shared by the\n * chat panel (R3) and /messages dividers. zh locales keep the native\n * wording (昨天/星期X); others get Intl output (\"Yesterday\"/\"Tue\").\n * Today → \"14:32\" · yesterday → \"昨天 14:32\" · <7d → \"星期二 14:32\" ·\n * this year → \"7月16日 14:32\" · older adds the year. */\nexport function formatWeChatTime(value: string | null | undefined): string {\n const t = parseHubTime(value);\n if (t === null) return '';\n const d = new Date(t);\n const now = new Date();\n const zh = typeof navigator !== 'undefined' && (navigator.language || '').toLowerCase().startsWith('zh');\n const hm = `${String(d.getHours()).padStart(2, '0')}:${String(d.getMinutes()).padStart(2, '0')}`;\n const startOfDay = (x: Date) => new Date(x.getFullYear(), x.getMonth(), x.getDate()).getTime();\n const dayDiff = Math.round((startOfDay(now) - startOfDay(d)) / 86400000);\n if (dayDiff === 0) return hm;\n if (dayDiff === 1) return zh ? `昨天 ${hm}` : `Yesterday ${hm}`;\n if (dayDiff > 1 && dayDiff < 7) {\n const wd = new Intl.DateTimeFormat(zh ? 'zh-CN' : undefined, { weekday: zh ? 'long' : 'short' }).format(d);\n return `${wd} ${hm}`;\n }\n const md = new Intl.DateTimeFormat(zh ? 'zh-CN' : undefined, {\n month: zh ? 'long' : 'short', day: 'numeric',\n ...(d.getFullYear() !== now.getFullYear() ? { year: 'numeric' } : {}),\n }).format(d);\n return `${md} ${hm}`;\n}\n","'use client';\n\nimport { createContext, useContext, useState, useEffect, ReactNode } from 'react';\n\ninterface NetworkContextType {\n networkId: string;\n setNetworkId: (id: string) => void;\n}\n\nconst NetworkContext = createContext<NetworkContextType>({ networkId: '', setNetworkId: () => {} });\n\nexport function NetworkProvider({ children }: { children: ReactNode }) {\n const [networkId, setNetworkId] = useState('');\n\n useEffect(() => {\n const saved = sessionStorage.getItem('anet_network_id');\n // Hydration-safe restore (see UserBar note).\n // eslint-disable-next-line react-hooks/set-state-in-effect\n if (saved) setNetworkId(saved);\n }, []);\n\n const setAndPersist = (id: string) => {\n setNetworkId(id);\n sessionStorage.setItem('anet_network_id', id);\n };\n\n return (\n <NetworkContext.Provider value={{ networkId, setNetworkId: setAndPersist }}>\n {children}\n </NetworkContext.Provider>\n );\n}\n\nexport function useNetworkId() {\n return useContext(NetworkContext);\n}\n","import useSWR from 'swr';\nimport { Session, Health, AnetConfig } from '../components/types';\nimport { useNetworkId } from './network-context';\n\nconst fetcher = async (url: string) => {\n const res = await fetch(url);\n if (res.status === 401) {\n window.location.assign('/login');\n throw new Error('unauthorized');\n }\n return res.json();\n};\n\nconst SWR_OPTIONS = { refreshInterval: 5000, dedupingInterval: 3000 };\n\n/** Append network_id to URL if set */\nfunction withNetwork(url: string, networkId: string): string {\n if (!networkId) return url;\n const sep = url.includes('?') ? '&' : '?';\n return `${url}${sep}network_id=${encodeURIComponent(networkId)}`;\n}\n\nexport function useSessions() {\n const { networkId } = useNetworkId();\n const { data, error, isLoading } = useSWR<{ sessions: Session[]; _hint?: { global_count?: number; filtered_network?: string } }>(\n withNetwork('/api/hub/status', networkId),\n fetcher,\n SWR_OPTIONS,\n );\n return { sessions: data?.sessions || [], hint: data?._hint, error, isLoading };\n}\n\n// RFC-027 PR2 — alias → lifecycle_state map sourced from /api/nodes\n// (commhub-server preview.12+). /api/status reads from `sessions` which\n// doesn't carry lifecycle_state; /api/nodes does. Cheap secondary\n// fetch, same SWR cadence as useSessions; merged client-side by alias.\n// Absent alias → caller defaults to 'active'.\ninterface NodeAttrsSnapshot {\n display_name: string | null;\n team: string | null;\n tags: string[];\n attrs_revision: number;\n}\ninterface NodesResp { nodes?: Array<{\n alias?: string;\n node_id?: string;\n lifecycle_state?: string | null;\n // #492 goal-item-3: node display attributes (hub PR #497). Legacy\n // rows read as null/[]/0 respectively — no guard needed by callers.\n display_name?: string | null;\n team?: string | null;\n tags?: string[];\n attrs_revision?: number;\n}>; }\nexport function useNodeLifecycle() {\n const { networkId } = useNetworkId();\n const { data, error, mutate } = useSWR<NodesResp>(\n withNetwork('/api/hub/nodes', networkId),\n fetcher,\n SWR_OPTIONS,\n );\n const lifecycleByAlias: Record<string, string> = {};\n const nodeIdByAlias: Record<string, string> = {};\n const attrsByAlias: Record<string, NodeAttrsSnapshot> = {};\n for (const n of data?.nodes ?? []) {\n if (n.alias && typeof n.lifecycle_state === 'string') lifecycleByAlias[n.alias] = n.lifecycle_state;\n if (n.alias && typeof n.node_id === 'string') nodeIdByAlias[n.alias] = n.node_id;\n if (n.alias) {\n attrsByAlias[n.alias] = {\n display_name: typeof n.display_name === 'string' ? n.display_name : null,\n team: typeof n.team === 'string' ? n.team : null,\n tags: Array.isArray(n.tags) ? n.tags : [],\n attrs_revision: typeof n.attrs_revision === 'number' ? n.attrs_revision : 0,\n };\n }\n }\n return { lifecycleByAlias, nodeIdByAlias, attrsByAlias, error, refreshNodes: mutate };\n}\nexport type { NodeAttrsSnapshot };\n\nexport function useHealth() {\n const { data, error } = useSWR<Health>('/api/hub/health', fetcher, SWR_OPTIONS);\n return { health: data || null, error };\n}\n\nexport function useAnetConfig() {\n const { data } = useSWR<AnetConfig>('/api/anet/config', fetcher, { refreshInterval: 30000 });\n return { config: data || null };\n}\n\nexport function useTasks(params?: Record<string, string>) {\n const { networkId } = useNetworkId();\n const query = new URLSearchParams({ limit: '100', ...params }).toString();\n const { data, error, isLoading } = useSWR(\n withNetwork(`/api/hub/tasks?${query}`, networkId),\n fetcher,\n SWR_OPTIONS,\n );\n return {\n tasks: data?.tasks || [],\n count: data?.count ?? 0,\n source: data?.source,\n error,\n isLoading,\n };\n}\n\nexport function useStats() {\n const { networkId } = useNetworkId();\n const { data, error } = useSWR(withNetwork('/api/hub/stats', networkId), fetcher, SWR_OPTIONS);\n return { stats: data?.ok ? data : null, error };\n}\n\nexport function useMessages(limit = 100) {\n const { networkId } = useNetworkId();\n // keepPreviousData: /messages grows `limit` when the user asks for older\n // history (#217 M5) — without it the key change would blank the list and\n // flash the skeleton while the bigger page is in flight.\n const { data, error, isLoading } = useSWR(\n withNetwork(`/api/hub/messages?limit=${limit}`, networkId),\n fetcher,\n { ...SWR_OPTIONS, keepPreviousData: true },\n );\n return { messages: data?.messages || [], error, isLoading };\n}\n","// #515: single source of truth for \"is this node online?\" across\n// stats card / sidebar count / topology halos / chat popover / task\n// panel @-mention picker. If you add a new place that decides \"online\"\n// vs \"offline\", import isOnline() from here — don't roll your own.\n//\n// Definition: **SSE-reachable with at least one live connection**.\n// Adopted by #214 F2 (originally in app/page.tsx). Consolidated here so\n// consumers never disagree.\n//\n// Why `> 0` and not `!== undefined`:\n// - Hub `getSSEStats()` writes `sessions[name] = arr.length` and the\n// three removal paths (cancel, rekey, dead-pushEvent) each `delete`\n// the key when the array empties. So on the current hub the value\n// is never `0` — but this JSON comes from a hub whose version this\n// dashboard doesn't control (see the legacy alias-only fallback\n// below for the version we already know we support), so treating\n// the map defensively costs nothing and keeps the definition\n// pointing the same direction #214 F2 took: SSE-reachable = \"can I\n// talk to it right now\", and a zero-count row is not that.\n// - `!!sseLookup(s)` in the old page.tsx also treated 0 as false;\n// preserving that keeps this a pure refactor for page.tsx.\n//\n// SSE keys in health.sse_sessions are `network_id:alias` since v0.7+\n// (per-network scoping). Legacy fallback: bare alias.\n\nexport type SseSessionsMap = Record<string, unknown>;\n\nexport type PresenceSubject = {\n alias: string;\n network_id?: string;\n};\n\nexport function sseCountFor(session: PresenceSubject, sseSessions: SseSessionsMap | undefined): number | undefined {\n if (!sseSessions) return undefined;\n const scoped = session.network_id ? sseSessions[`${session.network_id}:${session.alias}`] : undefined;\n const value = (scoped ?? sseSessions[session.alias]) as number | undefined;\n return typeof value === 'number' ? value : undefined;\n}\n\nexport function isOnline(session: PresenceSubject, sseSessions: SseSessionsMap | undefined): boolean {\n const n = sseCountFor(session, sseSessions);\n return typeof n === 'number' && n > 0;\n}\n","'use client';\n\nimport { useCallback, useEffect, useMemo, useState } from 'react';\nimport useSWR from 'swr';\nimport { useNetworkId } from './network-context';\nimport { isMuted, useMuteVersion } from './chat-mute';\n\nconst STORAGE_PREFIX = 'anet_chat_read_v1:';\nconst UNREAD_EVENT = 'anet-chat-read-updated';\n\ninterface ChatMessage {\n from_alias?: string | null;\n to_alias?: string | null;\n created_at?: string | null;\n}\n\n/** Senders/recipients that mean \"the dashboard user\" in hub data. The chat\n * panel uses the same set to decide which bubbles are \"You\". */\nconst USERISH = new Set(['', 'dashboard', 'admin', 'api', 'hub']);\nconst isUserish = (v?: string | null) => USERISH.has((v || '').trim().toLowerCase());\n\ninterface ReadMap {\n [alias: string]: string;\n}\n\nfunction storageKey(networkId: string) {\n return `${STORAGE_PREFIX}${networkId || 'global'}`;\n}\n\nfunction parseHubTime(value?: string | null): number {\n if (!value) return 0;\n const normalized = value.includes('T') ? value : value.replace(' ', 'T');\n const withZone = /Z$|[+-]\\d{2}:\\d{2}$/.test(normalized) ? normalized : `${normalized}Z`;\n const ts = Date.parse(withZone);\n return Number.isFinite(ts) ? ts : 0;\n}\n\n// Loop R8 (Vincent: 未读数字角标): last-read moved sessionStorage →\n// localStorage so read state survives refresh/new tabs/restart (微信预期).\n// One-time migration pulls any old session value forward.\nconst BASELINE_KEY = '__baseline';\n\nfunction readStoredMap(networkId: string): ReadMap {\n if (typeof window === 'undefined') return {};\n try {\n let raw = window.localStorage.getItem(storageKey(networkId));\n if (!raw) {\n raw = window.sessionStorage.getItem(storageKey(networkId));\n if (raw) window.localStorage.setItem(storageKey(networkId), raw);\n }\n const parsed = raw ? JSON.parse(raw) : {};\n const map: ReadMap = parsed && typeof parsed === 'object' ? parsed : {};\n // R8 first-visit floor, written SYNCHRONOUSLY on first read: an async\n // (useEffect) baseline lost the race against the first SWR render and\n // let a badge storm flash — and stick, since nothing re-triggered the\n // count. Ensuring it here means no compute can ever see a missing\n // baseline. No event dispatch: every hook instance does the same\n // idempotent write.\n if (!map[BASELINE_KEY]) {\n map[BASELINE_KEY] = new Date().toISOString();\n window.localStorage.setItem(storageKey(networkId), JSON.stringify(map));\n }\n return map;\n } catch {\n return {};\n }\n}\n\nfunction writeStoredMap(networkId: string, next: ReadMap) {\n if (typeof window === 'undefined') return;\n try {\n window.localStorage.setItem(storageKey(networkId), JSON.stringify(next));\n window.dispatchEvent(new CustomEvent(UNREAD_EVENT, { detail: { networkId } }));\n } catch {}\n}\n\nconst fetcher = async (url: string) => {\n const res = await fetch(url);\n if (res.status === 401) {\n window.location.assign('/login');\n throw new Error('unauthorized');\n }\n return res.json();\n};\n\nfunction withNetwork(url: string, networkId: string): string {\n if (!networkId) return url;\n const sep = url.includes('?') ? '&' : '?';\n return `${url}${sep}network_id=${encodeURIComponent(networkId)}`;\n}\n\nexport function markChatRead(alias: string, networkId: string) {\n if (!alias) return;\n const current = readStoredMap(networkId);\n writeStoredMap(networkId, {\n ...current,\n [alias]: new Date().toISOString(),\n });\n}\n\nexport function useChatUnread() {\n const { networkId } = useNetworkId();\n // Messages are the ONLY count source: the hub mirrors every task reply as\n // a message to the originator (verified live: replied task + same-second\n // message, both present), so counting tasks too double-counted every\n // reply (E2E showed 4 where 2 was right).\n const { data: messagesData } = useSWR<{ messages?: ChatMessage[] }>(\n withNetwork('/api/hub/messages?limit=200', networkId),\n fetcher,\n { refreshInterval: 5000, dedupingInterval: 3000 },\n );\n const [readVersion, setReadVersion] = useState(0);\n\n useEffect(() => {\n const onStorage = (event: StorageEvent) => {\n if (event.key && event.key !== storageKey(networkId)) return;\n setReadVersion((v) => (typeof v === 'number' ? v + 1 : 1));\n };\n const onUnreadUpdate = (event: Event) => {\n const detail = (event as CustomEvent<{ networkId?: string }>).detail;\n if (detail?.networkId !== undefined && detail.networkId !== networkId) return;\n setReadVersion((v) => (typeof v === 'number' ? v + 1 : 1));\n };\n window.addEventListener('storage', onStorage);\n window.addEventListener(UNREAD_EVENT, onUnreadUpdate);\n return () => {\n window.removeEventListener('storage', onStorage);\n window.removeEventListener(UNREAD_EVENT, onUnreadUpdate);\n };\n }, [networkId, setReadVersion]);\n\n const readMap = useMemo(() => {\n void readVersion;\n return readStoredMap(networkId);\n }, [networkId, readVersion]);\n\n const unreadMap = useMemo(() => {\n // R8: count EVERY unread item per alias (Vincent: \"有几条消息显示数字\"),\n // not just a latest-activity boolean. A message from the alias counts;\n // a task's REPLY counts once when it lands after last-read. Self-sent\n // items never count (they're keyed by the counterpart alias).\n const counts = new Map<string, number>();\n // R28 (微信排序): recency tiebreak for Overview/Nodes — but ONLY for\n // conversations the user has actually OPENED (read-map entry). On this\n // fleet agents constantly report to 'admin'; counting those yanked\n // never-opened agents to the front on every report (measured: 2 cards\n // jumped 39→1 / 60→3 in one 6s window). WeChat's list holds YOUR\n // conversations — same rule here keeps the grid calm.\n const lastActivity = new Map<string, number>();\n const opened = new Set(Object.keys(readMap).filter((k) => k !== BASELINE_KEY));\n const baseline = parseHubTime(readMap[BASELINE_KEY]);\n const bump = (alias: string, at: number) => {\n if (opened.has(alias) && at > (lastActivity.get(alias) || 0)) lastActivity.set(alias, at);\n const readAt = Math.max(parseHubTime(readMap[alias]), baseline);\n if (at > readAt) counts.set(alias, (counts.get(alias) || 0) + 1);\n };\n // Scope: only the USER'S conversation — a badge on X means \"X has\n // something FOR YOU\". Fleet chatter (X's messages to other agents)\n // must NOT inflate it.\n for (const message of messagesData?.messages || []) {\n const alias = message.from_alias?.trim();\n if (!alias || isUserish(alias)) continue; // own sends never count\n if (!isUserish(message.to_alias)) continue; // must be addressed to the user\n const at = parseHubTime(message.created_at);\n if (at) bump(alias, at);\n }\n return { counts, lastActivity };\n }, [messagesData, readMap]);\n\n const hasUnread = useCallback((alias?: string | null) => {\n if (!alias) return false;\n return (unreadMap.counts.get(alias) || 0) > 0;\n }, [unreadMap]);\n\n const unreadCount = useCallback((alias?: string | null) => {\n if (!alias) return 0;\n return unreadMap.counts.get(alias) || 0;\n }, [unreadMap]);\n\n const lastActivityAt = useCallback((alias?: string | null) => {\n if (!alias) return 0;\n return unreadMap.lastActivity.get(alias) || 0;\n }, [unreadMap]);\n\n // R34: muted conversations are excluded from the global count (WeChat\n // semantics); hasMutedUnread lets entry badges fall back to a dot.\n const muteVersion = useMuteVersion();\n const { totalUnread, hasMutedUnread } = useMemo(() => {\n void muteVersion;\n let t = 0;\n let mutedAny = false;\n for (const [alias, n] of unreadMap.counts) {\n if (isMuted(alias)) { if (n > 0) mutedAny = true; continue; }\n t += n;\n }\n return { totalUnread: t, hasMutedUnread: mutedAny };\n }, [unreadMap, muteVersion]);\n\n const clearUnread = useCallback((alias: string) => {\n markChatRead(alias, networkId);\n }, [networkId]);\n\n return { unreadMap, hasUnread, unreadCount, lastActivityAt, totalUnread, hasMutedUnread, clearUnread };\n}\n\n/** WeChat badge label: 1-99 as-is, above → \"99+\"; 0/negative → '' (hide). */\nexport function badgeLabel(n: number): string {\n if (n <= 0) return '';\n return n > 99 ? '99+' : String(n);\n}\n","'use client';\n\nimport { useSyncExternalStore } from 'react';\n\n/* Loop R34 (微信消息免打扰, 克制版): per-conversation mute. Muted\n * conversations keep their red badge but show a DOT instead of the count,\n * and their unreads are excluded from the global total (WeChat semantics).\n * Same storage/reactivity pattern as chat-drafts. */\n\nconst STORE_KEY = 'anet_chat_mute_v1';\nconst MUTE_EVENT = 'anet-chat-mute-updated';\n\nfunction readSet(): Set<string> {\n if (typeof window === 'undefined') return new Set();\n try {\n const parsed = JSON.parse(window.localStorage.getItem(STORE_KEY) || '[]');\n return new Set(Array.isArray(parsed) ? parsed : []);\n } catch {\n return new Set();\n }\n}\n\nexport function isMuted(alias?: string | null): boolean {\n if (!alias) return false;\n return readSet().has(alias);\n}\n\nexport function toggleMute(alias: string) {\n if (typeof window === 'undefined' || !alias) return;\n try {\n const s = readSet();\n if (s.has(alias)) s.delete(alias);\n else s.add(alias);\n window.localStorage.setItem(STORE_KEY, JSON.stringify([...s]));\n window.dispatchEvent(new Event(MUTE_EVENT));\n } catch {}\n}\n\nlet version = 0;\nfunction subscribe(callback: () => void) {\n const bump = () => { version++; callback(); };\n window.addEventListener(MUTE_EVENT, bump);\n window.addEventListener('storage', bump);\n return () => {\n window.removeEventListener(MUTE_EVENT, bump);\n window.removeEventListener('storage', bump);\n };\n}\n\nexport function useMuted(alias?: string | null): boolean {\n return useSyncExternalStore(subscribe, () => (alias ? isMuted(alias) : false), () => false);\n}\n\n/** Monotonic version for callers that use plain isMuted() inside render\n * loops (map callbacks can't call hooks). */\nexport function useMuteVersion(): number {\n return useSyncExternalStore(subscribe, () => version, () => 0);\n}\n","'use client';\n\nimport { useEffect } from 'react';\n\n// #217 S6 — verified themes: cyber (dark), light (white), and slack\n// (Vincent 2026-07-16 via api channel: \"其他的就搞成那种 Slack 方式吧…快速搞一个\"\n// — Slack-style is now the DEFAULT look; the network/topology page keeps its\n// showcase visuals, see TopoGraph's data-skin exemption).\n//\n// Mechanism: `slack` is implemented as a SKIN on top of the light theme —\n// applyTheme sets `data-theme=\"light\"` (so every existing light compat-shim\n// in globals.css applies unchanged) plus `data-skin=\"slack\"` which the\n// slack-only overrides key on (aubergine rail, Slack-blue accent, de-noise).\n// This keeps the fast first version to globals.css + three tiny component\n// touches instead of a full hex→token sweep (that sweep stays scheduled as\n// redesign Phase 0 next version).\n\nexport const THEMES = new Set(['cyber', 'light', 'slack']);\n\n/** Apply a theme choice to <html>. Single owner of the data-theme/data-skin\n * contract — Settings and Cmd+K call this too, so the skin attribute can\n * never desync from the theme attribute. */\nexport function applyTheme(t: string) {\n if (typeof document === 'undefined') return;\n const el = document.documentElement;\n if (t === 'slack') {\n el.setAttribute('data-theme', 'light');\n el.setAttribute('data-skin', 'slack');\n } else {\n el.setAttribute('data-theme', t);\n el.removeAttribute('data-skin');\n }\n}\n\nexport function ThemeProvider({ children }: { children: React.ReactNode }) {\n useEffect(() => {\n if (typeof document === 'undefined') return;\n // ROLLBACK (Vincent 07-20): the classic dark theme is the default again\n // — he prefers the original look and doesn't want a Slack copy as the\n // face of the product. 'slack' stays available as an explicit Settings\n // choice until the original agent-network theme replaces it. Users who\n // explicitly picked a theme keep their pick; everyone else returns to\n // cyber automatically (the slack-default window never wrote storage).\n let t = 'cyber';\n try {\n const saved = localStorage.getItem('anet-theme');\n if (saved && THEMES.has(saved)) t = saved;\n } catch {}\n applyTheme(t);\n }, []);\n return <>{children}</>;\n}\n","'use client';\n\nimport { useEffect, useState } from 'react';\nimport useSWR from 'swr';\n\n/** Issue #119 — server-side panel listing the hub's hosts + CPU/RAM bars.\n *\n * Steps 1+2 (SDK马 host telemetry + CommHub aggregation) shipped with\n * commhub-server v0.8.1-preview.2. Step 3 (this file, Round 20 of the\n * dashboard /loop) swaps the original mock seed for a SWR fetch of\n * `/api/hub/servers` (which proxies to the hub's `/api/servers`).\n *\n * Collapsed by default to a thin vertical icon strip so it never competes\n * with the topology graph for horizontal real-estate. State persists to\n * localStorage just like the other dashboard drawers.\n *\n * Backward-compat: if the upstream hub predates v0.8.1-preview.2 the\n * proxy returns `{ servers: [], unavailable: true }`. The drawer\n * surfaces a friendly \"not yet available\" hint instead of an empty list,\n * so old hubs don't read as \"something broke\".\n */\n\ninterface ServerAgent {\n alias: string;\n runtime: string | null;\n status: 'working' | 'idle' | 'offline';\n last_seen_at?: string | null;\n progress?: number | null; // 0..1\n}\n\ninterface ServerCard {\n hostname: string;\n ip?: string | null;\n cpu_load_1min: number | null;\n cpu_cores: number;\n mem_used_gb: number | null;\n mem_total_gb: number | null;\n /** Hero 1 v0.10.0: disk usage. Optional — older hubs don't report. */\n disk_used_gb?: number | null;\n disk_total_gb?: number | null;\n /** Hero 1 v0.10.0: short history for sparklines (5-min sliding window).\n * Each is the rolling 1-min average sampled at ~30s cadence (so ~10\n * data points for 5-min). Optional — older hubs don't report. */\n cpu_history?: number[];\n mem_history?: number[];\n /** v0.10.2 RFC-014 — disk usage 5-min rolling history. Optional;\n * older agent-node (< 2.4.1-preview.0) doesn't ship it. */\n disk_history?: number[];\n /** Hero 2 v0.10.0: per-server agent rollup. Optional — older hubs\n * send only aggregate agent_count. */\n agents?: ServerAgent[];\n agent_count: number;\n status: 'online' | 'offline';\n note?: string;\n}\n\ninterface ServersResponse {\n servers: ServerCard[];\n unavailable?: boolean;\n}\n\nconst fetcher = async (url: string): Promise<ServersResponse> => {\n const res = await fetch(url);\n if (res.status === 401) {\n if (typeof window !== 'undefined') window.location.assign('/login');\n throw new Error('unauthorized');\n }\n if (!res.ok) throw new Error(`hub ${res.status}`);\n return res.json();\n};\n\n// Bar tint by usage — green ≤60%, amber 60–85%, red >85%. Keeps the eye\n// going to whichever box is actually about to tip over.\nfunction barTint(pct: number) {\n if (pct >= 85) return { fill: '#ef4444', track: 'rgb(239 68 68 / 0.16)' };\n if (pct >= 60) return { fill: '#f59e0b', track: 'rgb(245 158 11 / 0.16)' };\n return { fill: '#10b981', track: 'rgb(16 185 129 / 0.16)' };\n}\n\nfunction Bar({ pct, label }: { pct: number; label: string }) {\n const t = barTint(pct);\n const clamped = Math.max(0, Math.min(100, pct));\n return (\n <div className=\"space-y-0.5\">\n <div className=\"flex justify-between text-[10px] text-[var(--fg-muted)] font-mono\">\n <span>{label}</span>\n <span className=\"tabular-nums\">{Math.round(clamped)}%</span>\n </div>\n <div className=\"h-1.5 rounded-full overflow-hidden\" style={{ background: t.track }}>\n <div\n className=\"h-full transition-[width] duration-300 ease-out\"\n style={{ width: `${clamped}%`, background: t.fill }}\n />\n </div>\n </div>\n );\n}\n\n/** Hero 1 v0.10.0 — inline SVG sparkline for 5-min rolling history.\n * Zero-dep (no recharts). Renders a stroked polyline + filled area.\n * Values are percentages (0..100); clamps inside. */\nfunction Sparkline({ values, tint, label }: { values: number[]; tint: string; label: string }) {\n if (!values || values.length < 2) return null;\n const w = 100, h = 18;\n const max = 100;\n const stride = w / Math.max(1, values.length - 1);\n const pts = values.map((v, i) => {\n const x = i * stride;\n const y = h - (Math.max(0, Math.min(max, v)) / max) * h;\n return `${x.toFixed(1)},${y.toFixed(1)}`;\n });\n const polyline = pts.join(' ');\n const area = `M0,${h} L${pts.join(' L')} L${w},${h} Z`;\n return (\n <svg\n width=\"100%\" height={h} viewBox={`0 0 ${w} ${h}`}\n preserveAspectRatio=\"none\" aria-label={`${label} 5-min history`}\n data-server-sparkline={label}\n >\n <path d={area} fill={tint} opacity=\"0.18\" />\n <polyline points={polyline} fill=\"none\" stroke={tint} strokeWidth=\"1.2\" />\n </svg>\n );\n}\n\n/** Hero 1 v0.10.0 — single health badge derived from the worst of\n * CPU / Mem / Disk percentages. Green ≤60%, amber 60-85%, red >85%\n * (same thresholds as Bar). Returns null when no percentages available\n * (e.g. offline server) so the card layout reads \"n/a · offline\" instead. */\nfunction HealthBadge({ cpu, mem, disk }: { cpu: number | null; mem: number | null; disk: number | null }) {\n const vals = [cpu, mem, disk].filter((v): v is number => typeof v === 'number');\n if (vals.length === 0) return null;\n const worst = Math.max(...vals);\n const t = barTint(worst);\n const status = worst >= 85 ? 'red' : worst >= 60 ? 'amber' : 'green';\n return (\n <span\n className=\"inline-block w-2 h-2 rounded-full shrink-0\"\n style={{ background: t.fill, boxShadow: `0 0 0 2px ${t.track}` }}\n data-server-health-badge={status}\n title={`worst: ${Math.round(worst)}%`}\n />\n );\n}\n\n/** Hero 2 v0.10.0 — per-server expandable agent list. Renders compact\n * rows: alias · runtime · status chip · last_seen relative. progress\n * bar appears when an agent reports progress (0..1). When the upstream\n * hub doesn't report agents[], the row falls through to a small\n * \"agent list pending hub upgrade\" hint. */\nfunction AgentList({ agents }: { agents?: ServerAgent[] }) {\n if (!agents || agents.length === 0) {\n return (\n <div className=\"text-[9px] text-[var(--fg-dim)] font-mono italic px-1 py-1\" data-server-agents-missing=\"true\">\n {/* #157 fix — copy update. Pre-#157 the placeholder read\n \"agent rollup pending hub ≥ 0.8.2-preview\". commhub-server@\n 0.8.2 is LIVE in prod (Vincent screenshot 5560 verified) but\n still doesn't ship `agents[]`. Version-specific text was\n misleading — implied upgrade-needed when hub already\n crossed the threshold. New copy drops the version pinning\n and just states the data-shape: hub hasn't reported the\n agent rollup for this server (could be hub-side feature\n gap or session-source gap). data-server-agents-missing\n attr surfaces the gate for tests. */}\n agent rollup not reported by hub\n </div>\n );\n }\n return (\n <ul className=\"space-y-1\" data-server-agent-list>\n {agents.map(a => {\n const statusColor =\n a.status === 'working' ? '#10b981' :\n a.status === 'idle' ? '#06b6d4' : '#6b7280';\n return (\n <li\n key={a.alias}\n className=\"flex items-center gap-1.5 text-[10px] font-mono\"\n data-server-agent={a.alias}\n >\n <span className=\"w-1.5 h-1.5 rounded-full shrink-0\" style={{ background: statusColor }} />\n <span className=\"font-semibold truncate\" style={{ color: 'var(--fg)' }}>{a.alias}</span>\n {a.runtime && (\n <span className=\"text-[9px] text-[var(--fg-dim)] shrink-0\">· {a.runtime}</span>\n )}\n {typeof a.progress === 'number' && a.progress > 0 && (\n <span className=\"ml-auto text-[9px] tabular-nums text-[var(--fg-muted)]\">\n {Math.round(a.progress * 100)}%\n </span>\n )}\n </li>\n );\n })}\n </ul>\n );\n}\n\nfunction useServers(enabled = true) {\n const { data, error } = useSWR<ServersResponse>(\n enabled ? '/api/hub/servers' : null,\n fetcher,\n { refreshInterval: 5000, dedupingInterval: 3000 },\n );\n const servers = data?.servers ?? [];\n const unavailable = data?.unavailable === true;\n const onlineCount = servers.filter(s => s.status === 'online').length;\n const loading = enabled && !data && !error;\n return { data, error, servers, unavailable, onlineCount, loading };\n}\n\nexport function ServersPanel({ enabled = true, className = '' }: { enabled?: boolean; className?: string }) {\n const [expanded, setExpanded] = useState<Set<string>>(new Set());\n useEffect(() => {\n try {\n const raw = localStorage.getItem('anet-servers-drawer-expanded');\n // Expanded server rows are a client-only sticky preference; hydrate once\n // after mount so SSR stays deterministic.\n // eslint-disable-next-line react-hooks/set-state-in-effect\n if (raw) setExpanded(new Set(JSON.parse(raw)));\n } catch {}\n }, []);\n const toggleExpanded = (hostname: string) => setExpanded(prev => {\n const next = new Set(prev);\n if (next.has(hostname)) next.delete(hostname); else next.add(hostname);\n try { localStorage.setItem('anet-servers-drawer-expanded', JSON.stringify([...next])); } catch {}\n return next;\n });\n\n const { data, error, servers, unavailable, loading } = useServers(enabled);\n\n return (\n <div className={`min-h-0 overflow-y-auto px-2 py-2 space-y-2 ${className}`} data-servers-body>\n {loading && (\n <div className=\"text-[10px] text-[var(--fg-muted)] font-mono text-center py-4\">\n loading servers…\n </div>\n )}\n {error && !data && (\n <div className=\"rounded-md border px-2.5 py-2 text-[10px] font-mono\"\n style={{ background: 'rgb(239 68 68 / 0.06)', borderColor: 'rgb(239 68 68 / 0.25)', color: '#ef4444' }}>\n hub unreachable · retrying every 5s\n </div>\n )}\n {unavailable && (\n <div className=\"text-[10px] text-[var(--fg-muted)] font-mono text-center py-3 leading-relaxed\">\n host telemetry not available<br/>\n <span className=\"text-[var(--fg-dim)]\">upgrade commhub-server ≥ 0.8.1-preview.2</span>\n </div>\n )}\n {!loading && !error && !unavailable && servers.length === 0 && (\n <div className=\"text-[10px] text-[var(--fg-muted)] font-mono text-center py-4\">\n no servers reporting yet\n </div>\n )}\n {servers.map(s => {\n const offline = s.status === 'offline';\n const cpuPct = s.cpu_load_1min != null && s.cpu_cores > 0 ? (s.cpu_load_1min / s.cpu_cores) * 100 : null;\n const memPct = s.mem_used_gb != null && s.mem_total_gb != null && s.mem_total_gb > 0 ? (s.mem_used_gb / s.mem_total_gb) * 100 : null;\n const diskPct = s.disk_used_gb != null && s.disk_total_gb != null && s.disk_total_gb > 0 ? (s.disk_used_gb / s.disk_total_gb) * 100 : null;\n const isExpanded = expanded.has(s.hostname);\n return (\n <div\n key={s.hostname}\n className=\"rounded-lg border px-2.5 py-2 space-y-1.5\"\n style={{\n background: 'var(--bg)',\n borderColor: 'var(--border)',\n opacity: offline ? 0.55 : 1,\n }}\n data-server-card={s.hostname}\n data-server-expanded={isExpanded ? 'true' : 'false'}\n title={s.ip ? `${s.hostname} · ${s.ip}` : s.hostname}\n >\n {/* v0.10.0 Hero 1+2: header row — click toggles expanded\n detail view (sparklines + disk + agent rollup). */}\n <button\n type=\"button\"\n onClick={() => toggleExpanded(s.hostname)}\n aria-expanded={isExpanded}\n className=\"w-full flex items-center justify-between gap-2 text-left\"\n data-server-card-toggle={s.hostname}\n >\n <div className=\"min-w-0 flex items-center gap-1.5\">\n {/* Hero 1 health badge — worst-of CPU/Mem/Disk */}\n {!offline && <HealthBadge cpu={cpuPct} mem={memPct} disk={diskPct} />}\n <span className=\"font-mono text-[12px] font-semibold truncate\" style={{ color: 'var(--fg)' }}>{s.hostname}</span>\n {s.note && <span className=\"text-[9px] text-[var(--fg-dim)]\">({s.note})</span>}\n </div>\n <span className=\"flex items-center gap-1 shrink-0\">\n <span className=\"text-[10px] text-[var(--fg-muted)] font-mono tabular-nums\">\n {s.agent_count}&nbsp;agent{s.agent_count === 1 ? '' : 's'}\n </span>\n {/* Chevron — rotates 90° on expanded */}\n <svg\n width=\"10\" height=\"10\" viewBox=\"0 0 10 10\"\n style={{ transform: isExpanded ? 'rotate(90deg)' : 'rotate(0deg)', transition: 'transform 150ms ease-out' }}\n aria-hidden\n >\n <path d=\"M3 1.5L7 5L3 8.5\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n </svg>\n </span>\n </button>\n {!offline && cpuPct != null && (\n <Bar pct={cpuPct} label={`CPU ${s.cpu_load_1min!.toFixed(2)}/${s.cpu_cores}`} />\n )}\n {!offline && memPct != null && (\n <Bar pct={memPct} label={`RAM ${s.mem_used_gb!.toFixed(1)}/${s.mem_total_gb!.toFixed(1)}G`} />\n )}\n {offline && (\n <div className=\"text-[10px] text-[var(--fg-dim)] font-mono italic\">CPU n/a · RAM n/a · offline</div>\n )}\n {/* v0.10.0 Hero 1+2: expanded detail — disk bar +\n 5-min sparklines + agent rollup. Visible only when\n the user clicks the card. Renders gracefully when\n upstream hub hasn't shipped optional fields. */}\n {isExpanded && !offline && (\n <div className=\"pt-1 mt-1 border-t space-y-1.5\" style={{ borderColor: 'var(--border)' }}>\n {diskPct != null ? (\n <Bar pct={diskPct} label={`DISK ${s.disk_used_gb!.toFixed(1)}/${s.disk_total_gb!.toFixed(1)}G`} />\n ) : (\n /* #157 sibling fix — same misleading version-pin copy\n dropped at the disk-metric placeholder. Same\n rationale as the agent-rollup copy above. */\n <div className=\"text-[9px] text-[var(--fg-dim)] font-mono italic\" data-server-disk-missing=\"true\">disk metric not reported by hub</div>\n )}\n {s.cpu_history && s.cpu_history.length >= 2 && (\n <div className=\"space-y-0.5\">\n <div className=\"text-[9px] text-[var(--fg-muted)] font-mono\">CPU · 5-min</div>\n <Sparkline values={s.cpu_history} tint=\"#10b981\" label=\"CPU\" />\n </div>\n )}\n {s.mem_history && s.mem_history.length >= 2 && (\n <div className=\"space-y-0.5\">\n <div className=\"text-[9px] text-[var(--fg-muted)] font-mono\">RAM · 5-min</div>\n <Sparkline values={s.mem_history} tint=\"#06b6d4\" label=\"MEM\" />\n </div>\n )}\n {/* v0.10.2 RFC-014 §7 close gate #3 — disk usage\n 5-min curve. Amber tint matches the disk bar\n tier convention (DISK > CPU/Mem in alert-\n priority hierarchy since disk-full is a hard\n failure mode). Render only when agent-node\n 2.4.1-preview.0+ has shipped disk_history;\n backward-compat handles older agents silently\n (no sparkline, no broken state). */}\n {s.disk_history && s.disk_history.length >= 2 && (\n <div className=\"space-y-0.5\">\n <div className=\"text-[9px] text-[var(--fg-muted)] font-mono\">DISK · 5-min</div>\n <Sparkline values={s.disk_history} tint=\"#f59e0b\" label=\"DISK\" />\n </div>\n )}\n <div className=\"pt-1\">\n <div className=\"text-[9px] text-[var(--fg-muted)] font-mono mb-0.5\">agents</div>\n <AgentList agents={s.agents} />\n </div>\n </div>\n )}\n </div>\n );\n })}\n {servers.length > 0 && (\n <div className=\"pt-1 text-[9px] text-[var(--fg-dim)] font-mono text-center\">\n live · refreshing every 5s\n </div>\n )}\n </div>\n );\n}\n\nexport function ServersDrawer() {\n const [open, setOpen] = useState(false);\n // Drawer state is per-user-machine — persist like the other dashboard\n // sticky toggles (`anet-topo-layout`, `anet-topo-view`, etc.).\n useEffect(() => {\n // Drawer openness is persisted in localStorage and can only be restored on\n // the client after mount.\n // eslint-disable-next-line react-hooks/set-state-in-effect\n try { if (localStorage.getItem('anet-servers-drawer') === '1') setOpen(true); } catch {}\n }, []);\n const toggle = () => setOpen(prev => {\n const next = !prev;\n try { localStorage.setItem('anet-servers-drawer', next ? '1' : '0'); } catch {}\n return next;\n });\n\n // Round 20 / #119 step 3 final delivery — real SWR fetch. 5s refresh\n // matches the other live drawers (HealthBanner, Sidebar) so an operator\n // sees host telemetry update in roughly the same beat as session state.\n // Only poll while expanded — collapsed icon strip doesn't need fresh data.\n const { servers, onlineCount } = useServers(open);\n\n return (\n <aside\n className=\"fixed right-0 top-20 z-40 hidden lg:flex flex-col rounded-l-xl border border-r-0 shadow-xl shadow-black/30 anet-fade-in\"\n style={{\n background: 'var(--bg-secondary)',\n borderColor: 'var(--border)',\n width: open ? 296 : 40,\n maxHeight: 'calc(100vh - 6rem)',\n transition: 'width 200ms ease-out',\n }}\n aria-label=\"Servers panel\"\n >\n <button\n onClick={toggle}\n aria-expanded={open}\n aria-label={open ? 'Collapse servers panel' : 'Expand servers panel'}\n className=\"flex items-center gap-2 px-2.5 py-2 border-b text-[11px] font-semibold tracking-wide select-none\"\n style={{ color: 'var(--fg)', borderColor: 'var(--border)' }}\n >\n <svg className=\"w-4 h-4 shrink-0\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.8\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <rect x=\"3\" y=\"4\" width=\"18\" height=\"6\" rx=\"1.5\" />\n <rect x=\"3\" y=\"14\" width=\"18\" height=\"6\" rx=\"1.5\" />\n <circle cx=\"7\" cy=\"7\" r=\"0.7\" fill=\"currentColor\" />\n <circle cx=\"7\" cy=\"17\" r=\"0.7\" fill=\"currentColor\" />\n </svg>\n {open && (\n <>\n <span className=\"flex-1 text-left\">Servers</span>\n <span className=\"text-[10px] text-[var(--fg-muted)] font-mono\">{onlineCount}/{servers.length}</span>\n </>\n )}\n </button>\n\n {open && (\n <ServersPanel enabled={open} className=\"flex-1\" />\n )}\n </aside>\n );\n}\n"],"names":["process","env","NEXT_RUNTIME","module","exports","require","__NEXT_EXPERIMENTAL_REACT","NODE_ENV","TURBOPACK","vendored","ReactJsxRuntime","React","AppRouterContext","ReactServerDOMTurbopackClient","HooksClientContext","ServerInsertedHtml","parseHubTime","dateStr","iso","includes","replace","t","Date","parse","Number","isFinite","relativeAgo","s","Math","floor","now","formatWeChatTime","value","d","zh","navigator","language","toLowerCase","startsWith","hm","String","getHours","padStart","getMinutes","startOfDay","x","getFullYear","getMonth","getDate","getTime","dayDiff","round","wd","Intl","DateTimeFormat","undefined","weekday","format","md","month","day","year","NetworkContext","networkId","setNetworkId","NetworkProvider","children","saved","sessionStorage","getItem","setAndPersist","id","setItem","Provider","useNetworkId","fetcher","url","res","fetch","status","window","location","assign","Error","json","SWR_OPTIONS","refreshInterval","dedupingInterval","withNetwork","sep","encodeURIComponent","useSessions","data","error","isLoading","sessions","hint","_hint","useNodeLifecycle","mutate","lifecycleByAlias","nodeIdByAlias","attrsByAlias","n","nodes","alias","lifecycle_state","node_id","display_name","team","tags","Array","isArray","attrs_revision","refreshNodes","useHealth","health","useAnetConfig","config","useTasks","params","query","URLSearchParams","limit","toString","tasks","count","source","useStats","stats","ok","useMessages","keepPreviousData","messages","sseCountFor","session","sseSessions","scoped","network_id","isOnline","THEMES","Set","applyTheme","document","el","documentElement","setAttribute","removeAttribute","ThemeProvider","localStorage","has","barTint","pct","fill","track","Bar","label","clamped","max","min","className","style","background","width","Sparkline","values","tint","length","w","h","stride","pts","map","v","i","y","toFixed","polyline","join","area","height","viewBox","preserveAspectRatio","opacity","points","stroke","strokeWidth","HealthBadge","cpu","mem","disk","vals","filter","worst","boxShadow","title","AgentList","agents","a","statusColor","color","runtime","progress","useServers","enabled","servers","unavailable","onlineCount","loading","ServersPanel","expanded","setExpanded","raw","JSON","toggleExpanded","hostname","prev","next","delete","add","stringify","borderColor","offline","cpuPct","cpu_load_1min","cpu_cores","memPct","mem_used_gb","mem_total_gb","diskPct","disk_used_gb","disk_total_gb","isExpanded","ip","type","onClick","note","agent_count","transform","transition","strokeLinecap","strokeLinejoin","cpu_history","mem_history","disk_history","ServersDrawer","open","setOpen","toggle","maxHeight","rx","cx","cy","r"],"mappings":"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","ignoreList":[0,1,2,3,4,5,6]}
1
+ {"version":3,"sources":["../../../../../../dash-492/agent-network-dashboard/node_modules/next/src/server/route-modules/app-page/module.compiled.js","../../../../../../dash-492/agent-network-dashboard/node_modules/next/src/server/route-modules/app-page/vendored/ssr/react-jsx-runtime.ts","../../../../../../dash-492/agent-network-dashboard/node_modules/next/src/server/route-modules/app-page/vendored/ssr/react.ts","../../../../../../dash-492/agent-network-dashboard/node_modules/next/src/server/route-modules/app-page/vendored/contexts/app-router-context.ts","../../../../../../dash-492/agent-network-dashboard/node_modules/next/src/server/route-modules/app-page/vendored/ssr/react-server-dom-turbopack-client.ts","../../../../../../dash-492/agent-network-dashboard/node_modules/next/src/server/route-modules/app-page/vendored/contexts/hooks-client-context.ts","../../../../../../dash-492/agent-network-dashboard/node_modules/next/src/server/route-modules/app-page/vendored/contexts/server-inserted-html.ts","../../../../../../dash-492/agent-network-dashboard/app/lib/time.ts","../../../../../../dash-492/agent-network-dashboard/app/lib/network-context.tsx","../../../../../../dash-492/agent-network-dashboard/app/lib/hooks.ts","../../../../../../dash-492/agent-network-dashboard/app/lib/presence.ts","../../../../../../dash-492/agent-network-dashboard/app/lib/chat-unread.ts","../../../../../../dash-492/agent-network-dashboard/app/lib/chat-mute.ts","../../../../../../dash-492/agent-network-dashboard/app/components/ThemeSwitcher.tsx","../../../../../../dash-492/agent-network-dashboard/app/components/ServersDrawer.tsx"],"sourcesContent":["if (process.env.NEXT_RUNTIME === 'edge') {\n module.exports = require('next/dist/server/route-modules/app-page/module.js')\n} else {\n if (process.env.__NEXT_EXPERIMENTAL_REACT) {\n if (process.env.NODE_ENV === 'development') {\n if (process.env.TURBOPACK) {\n module.exports = require('next/dist/compiled/next-server/app-page-turbo-experimental.runtime.dev.js')\n } else {\n module.exports = require('next/dist/compiled/next-server/app-page-experimental.runtime.dev.js')\n }\n } else {\n if (process.env.TURBOPACK) {\n module.exports = require('next/dist/compiled/next-server/app-page-turbo-experimental.runtime.prod.js')\n } else {\n module.exports = require('next/dist/compiled/next-server/app-page-experimental.runtime.prod.js')\n }\n }\n } else {\n if (process.env.NODE_ENV === 'development') {\n if (process.env.TURBOPACK) {\n module.exports = require('next/dist/compiled/next-server/app-page-turbo.runtime.dev.js')\n } else {\n module.exports = require('next/dist/compiled/next-server/app-page.runtime.dev.js')\n }\n } else {\n if (process.env.TURBOPACK) {\n module.exports = require('next/dist/compiled/next-server/app-page-turbo.runtime.prod.js')\n } else {\n module.exports = require('next/dist/compiled/next-server/app-page.runtime.prod.js')\n }\n }\n }\n}\n","module.exports = (\n require('../../module.compiled') as typeof import('../../module.compiled')\n).vendored['react-ssr']!.ReactJsxRuntime\n","module.exports = (\n require('../../module.compiled') as typeof import('../../module.compiled')\n).vendored['react-ssr']!.React\n","module.exports = (\n require('../../module.compiled') as typeof import('../../module.compiled')\n).vendored['contexts'].AppRouterContext\n","module.exports = (\n require('../../module.compiled') as typeof import('../../module.compiled')\n).vendored['react-ssr']!.ReactServerDOMTurbopackClient\n","module.exports = (\n require('../../module.compiled') as typeof import('../../module.compiled')\n).vendored['contexts'].HooksClientContext\n","module.exports = (\n require('../../module.compiled') as typeof import('../../module.compiled')\n).vendored['contexts'].ServerInsertedHtml\n","/** Shared timestamp helpers for hub-sourced data.\n *\n * Background — the CommHub serialises timestamps SQL-style without a\n * zone (\"2026-05-15 06:00:28\"), but some test data uses full ISO\n * (\"…T06:00:28Z\"). `Date.parse` on bare SQL is **local-time** in every\n * browser the dashboard supports, so a UTC+8 operator silently sees\n * every timestamp 8 h older than reality (Round 35 dug this out via\n * the `isGhost` filter mis-fire).\n *\n * Round 38 / Loop consolidates parsing — TopoGraph (R35), ChatPopover\n * (R37) and utils.ts::timeAgo all mirrored the same SQL→UTC rewrite;\n * one source of truth here. */\n\n/** Parse a hub timestamp to ms-since-epoch, treating SQL-style strings\n * as UTC. ISO strings (with `T`) bypass the rewrite and are parsed as-is.\n * Returns null for empty / unparseable input. */\nexport function parseHubTime(dateStr: string | null | undefined): number | null {\n if (!dateStr) return null;\n const iso = dateStr.includes('T') ? dateStr : dateStr.replace(' ', 'T') + 'Z';\n const t = Date.parse(iso);\n return Number.isFinite(t) ? t : null;\n}\n\n/** Format `dateStr` as a short relative-time string (\"6m ago\" / \"2h ago\").\n * Future timestamps (clock skew) collapse to \"just now\". Returns null when\n * the input doesn't parse — callers can decide on a fallback. */\nexport function relativeAgo(dateStr: string | null | undefined): string | null {\n const t = parseHubTime(dateStr);\n if (t === null) return null;\n const s = Math.floor((Date.now() - t) / 1000);\n if (s < 0) return 'just now';\n if (s < 60) return `${s}s ago`;\n if (s < 3600) return `${Math.floor(s / 60)}m ago`;\n if (s < 86400) return `${Math.floor(s / 3600)}h ago`;\n return `${Math.floor(s / 86400)}d ago`;\n}\n\n/** Loop R7 (跨面一致性): WeChat-style contextual timestamp shared by the\n * chat panel (R3) and /messages dividers. zh locales keep the native\n * wording (昨天/星期X); others get Intl output (\"Yesterday\"/\"Tue\").\n * Today → \"14:32\" · yesterday → \"昨天 14:32\" · <7d → \"星期二 14:32\" ·\n * this year → \"7月16日 14:32\" · older adds the year. */\nexport function formatWeChatTime(value: string | null | undefined): string {\n const t = parseHubTime(value);\n if (t === null) return '';\n const d = new Date(t);\n const now = new Date();\n const zh = typeof navigator !== 'undefined' && (navigator.language || '').toLowerCase().startsWith('zh');\n const hm = `${String(d.getHours()).padStart(2, '0')}:${String(d.getMinutes()).padStart(2, '0')}`;\n const startOfDay = (x: Date) => new Date(x.getFullYear(), x.getMonth(), x.getDate()).getTime();\n const dayDiff = Math.round((startOfDay(now) - startOfDay(d)) / 86400000);\n if (dayDiff === 0) return hm;\n if (dayDiff === 1) return zh ? `昨天 ${hm}` : `Yesterday ${hm}`;\n if (dayDiff > 1 && dayDiff < 7) {\n const wd = new Intl.DateTimeFormat(zh ? 'zh-CN' : undefined, { weekday: zh ? 'long' : 'short' }).format(d);\n return `${wd} ${hm}`;\n }\n const md = new Intl.DateTimeFormat(zh ? 'zh-CN' : undefined, {\n month: zh ? 'long' : 'short', day: 'numeric',\n ...(d.getFullYear() !== now.getFullYear() ? { year: 'numeric' } : {}),\n }).format(d);\n return `${md} ${hm}`;\n}\n","'use client';\n\nimport { createContext, useContext, useState, useEffect, ReactNode } from 'react';\n\ninterface NetworkContextType {\n networkId: string;\n setNetworkId: (id: string) => void;\n}\n\nconst NetworkContext = createContext<NetworkContextType>({ networkId: '', setNetworkId: () => {} });\n\nexport function NetworkProvider({ children }: { children: ReactNode }) {\n const [networkId, setNetworkId] = useState('');\n\n useEffect(() => {\n const saved = sessionStorage.getItem('anet_network_id');\n // Hydration-safe restore (see UserBar note).\n // eslint-disable-next-line react-hooks/set-state-in-effect\n if (saved) setNetworkId(saved);\n }, []);\n\n const setAndPersist = (id: string) => {\n setNetworkId(id);\n sessionStorage.setItem('anet_network_id', id);\n };\n\n return (\n <NetworkContext.Provider value={{ networkId, setNetworkId: setAndPersist }}>\n {children}\n </NetworkContext.Provider>\n );\n}\n\nexport function useNetworkId() {\n return useContext(NetworkContext);\n}\n","import useSWR from 'swr';\nimport { Session, Health, AnetConfig } from '../components/types';\nimport { useNetworkId } from './network-context';\n\nconst fetcher = async (url: string) => {\n const res = await fetch(url);\n if (res.status === 401) {\n window.location.assign('/login');\n throw new Error('unauthorized');\n }\n return res.json();\n};\n\nconst SWR_OPTIONS = { refreshInterval: 5000, dedupingInterval: 3000 };\n\n/** Append network_id to URL if set */\nfunction withNetwork(url: string, networkId: string): string {\n if (!networkId) return url;\n const sep = url.includes('?') ? '&' : '?';\n return `${url}${sep}network_id=${encodeURIComponent(networkId)}`;\n}\n\nexport function useSessions() {\n const { networkId } = useNetworkId();\n const { data, error, isLoading } = useSWR<{ sessions: Session[]; _hint?: { global_count?: number; filtered_network?: string } }>(\n withNetwork('/api/hub/status', networkId),\n fetcher,\n SWR_OPTIONS,\n );\n return { sessions: data?.sessions || [], hint: data?._hint, error, isLoading };\n}\n\n// RFC-027 PR2 — alias → lifecycle_state map sourced from /api/nodes\n// (commhub-server preview.12+). /api/status reads from `sessions` which\n// doesn't carry lifecycle_state; /api/nodes does. Cheap secondary\n// fetch, same SWR cadence as useSessions; merged client-side by alias.\n// Absent alias → caller defaults to 'active'.\ninterface NodeAttrsSnapshot {\n display_name: string | null;\n team: string | null;\n tags: string[];\n attrs_revision: number;\n}\ninterface NodesResp { nodes?: Array<{\n alias?: string;\n node_id?: string;\n lifecycle_state?: string | null;\n // #492 goal-item-3: node display attributes (hub PR #497). Legacy\n // rows read as null/[]/0 respectively — no guard needed by callers.\n display_name?: string | null;\n team?: string | null;\n tags?: string[];\n attrs_revision?: number;\n}>; }\nexport function useNodeLifecycle() {\n const { networkId } = useNetworkId();\n const { data, error, mutate } = useSWR<NodesResp>(\n withNetwork('/api/hub/nodes', networkId),\n fetcher,\n SWR_OPTIONS,\n );\n const lifecycleByAlias: Record<string, string> = {};\n const nodeIdByAlias: Record<string, string> = {};\n const attrsByAlias: Record<string, NodeAttrsSnapshot> = {};\n for (const n of data?.nodes ?? []) {\n if (n.alias && typeof n.lifecycle_state === 'string') lifecycleByAlias[n.alias] = n.lifecycle_state;\n if (n.alias && typeof n.node_id === 'string') nodeIdByAlias[n.alias] = n.node_id;\n if (n.alias) {\n attrsByAlias[n.alias] = {\n display_name: typeof n.display_name === 'string' ? n.display_name : null,\n team: typeof n.team === 'string' ? n.team : null,\n tags: Array.isArray(n.tags) ? n.tags : [],\n attrs_revision: typeof n.attrs_revision === 'number' ? n.attrs_revision : 0,\n };\n }\n }\n return { lifecycleByAlias, nodeIdByAlias, attrsByAlias, error, refreshNodes: mutate };\n}\nexport type { NodeAttrsSnapshot };\n\nexport function useHealth() {\n const { data, error } = useSWR<Health>('/api/hub/health', fetcher, SWR_OPTIONS);\n return { health: data || null, error };\n}\n\nexport function useAnetConfig() {\n const { data } = useSWR<AnetConfig>('/api/anet/config', fetcher, { refreshInterval: 30000 });\n return { config: data || null };\n}\n\nexport function useTasks(params?: Record<string, string>) {\n const { networkId } = useNetworkId();\n const query = new URLSearchParams({ limit: '100', ...params }).toString();\n const { data, error, isLoading } = useSWR(\n withNetwork(`/api/hub/tasks?${query}`, networkId),\n fetcher,\n SWR_OPTIONS,\n );\n return {\n tasks: data?.tasks || [],\n count: data?.count ?? 0,\n source: data?.source,\n error,\n isLoading,\n };\n}\n\nexport function useStats() {\n const { networkId } = useNetworkId();\n const { data, error } = useSWR(withNetwork('/api/hub/stats', networkId), fetcher, SWR_OPTIONS);\n return { stats: data?.ok ? data : null, error };\n}\n\nexport function useMessages(limit = 100) {\n const { networkId } = useNetworkId();\n // keepPreviousData: /messages grows `limit` when the user asks for older\n // history (#217 M5) — without it the key change would blank the list and\n // flash the skeleton while the bigger page is in flight.\n const { data, error, isLoading } = useSWR(\n withNetwork(`/api/hub/messages?limit=${limit}`, networkId),\n fetcher,\n { ...SWR_OPTIONS, keepPreviousData: true },\n );\n return { messages: data?.messages || [], error, isLoading };\n}\n","// #515 / #53: single source of truth for \"is this node online?\" across\n// stats card / sidebar count / topology halos / chat popover / task\n// panel @-mention picker. If you add a new place that decides \"online\"\n// vs \"offline\", import isOnline() from here — don't roll your own.\n//\n// Definition: **SSE-reachable with at least one live connection**.\n// Adopted by #214 F2 (originally in app/page.tsx). Consolidated here so\n// consumers never disagree.\n//\n// Why `> 0` and not `!== undefined`:\n// - Hub `getSSEStats()` writes `sessions[name] = arr.length` and the\n// three removal paths (cancel, rekey, dead-pushEvent) each `delete`\n// the key when the array empties. So on the current hub the value\n// is never `0` — but this JSON comes from a hub whose version this\n// dashboard doesn't control (see the legacy alias-only fallback\n// below for the version we already know we support), so treating\n// the map defensively costs nothing and keeps the definition\n// pointing the same direction #214 F2 took: SSE-reachable = \"can I\n// talk to it right now\", and a zero-count row is not that.\n// - `!!sseLookup(s)` in the old page.tsx also treated 0 as false;\n// preserving that keeps this a pure refactor for page.tsx.\n//\n// SSE keys in health.sse_sessions are `network_id:alias` since v0.7+\n// (per-network scoping). Legacy fallback: bare alias.\n\nexport type SseSessionsMap = Record<string, unknown>;\n\nexport type PresenceSubject = {\n alias: string;\n network_id?: string;\n};\n\nexport function sseCountFor(session: PresenceSubject, sseSessions: SseSessionsMap | undefined): number | undefined {\n if (!sseSessions) return undefined;\n const scoped = session.network_id ? sseSessions[`${session.network_id}:${session.alias}`] : undefined;\n const value = (scoped ?? sseSessions[session.alias]) as number | undefined;\n return typeof value === 'number' ? value : undefined;\n}\n\nexport function isOnline(session: PresenceSubject, sseSessions: SseSessionsMap | undefined): boolean {\n const n = sseCountFor(session, sseSessions);\n return typeof n === 'number' && n > 0;\n}\n\n// -----------------------------------------------------------------------\n// #53: three-state ambient presence signal.\n//\n// `sse_sessions` on hub's /health is **auth-gated** (post `#495-followup`\n// / `f28a6c1b`): an anonymous or wrong-scope caller gets the field\n// **completely omitted** — indistinguishable at the JSON level from\n// \"no nodes connected\".\n//\n// If we hand that state to isOnline() and only render numbers, the UI\n// shows a confident, consistent, and *wrong* 0 online everywhere and\n// the \"three sites disagree\" signal #515 used to have — which was\n// itself the clue that something upstream was broken — is gone.\n//\n// So callers need to distinguish three cases:\n//\n// 'ready' — sseSessions is present (even if empty {}). Trust the\n// count. `filter(isOnline).length` is the answer.\n// 'blind' — sseSessions is absent but hub `sse_connections > 0`.\n// Two fields contradict → we are seeing an anonymized\n// view. Do NOT render \"0 online\"; render an alert.\n// 'loading' — sseSessions is absent and no positive contradiction\n// (either health hasn't loaded, or hub reports 0\n// connections and no map). Render a placeholder — don't\n// inflate the count, but don't cry wolf either.\n//\n// Callers that render user-visible counts MUST branch on this. Callers\n// that just need a per-node boolean (halos, chat-popover badges) can\n// stay on isOnline() — those degrade gracefully to \"everyone offline\"\n// which is the safer visual, while the ambient banner handles the\n// \"why\".\n// -----------------------------------------------------------------------\n\nexport type PresenceStatus = 'ready' | 'blind' | 'loading';\n\nexport type HealthShape = {\n sse_connections?: number;\n} | null | undefined;\n\nexport function presenceStatus(\n sseSessions: SseSessionsMap | undefined,\n health: HealthShape,\n): PresenceStatus {\n if (sseSessions !== undefined) return 'ready';\n // sseSessions is absent. Are we blind or truly empty/loading?\n const conns = health && typeof health.sse_connections === 'number' ? health.sse_connections : 0;\n // The contradiction case — hub says there are connections but the\n // map isn't in this response — is the strongest \"you're anonymous\"\n // signal we have.\n if (conns > 0) return 'blind';\n // No map AND hub reports 0 connections (or health hasn't loaded).\n // Both look identical to us, and both should render placeholders,\n // not \"0 online\" numbers. Conservative default = 'loading'.\n return 'loading';\n}\n","'use client';\n\nimport { useCallback, useEffect, useMemo, useState } from 'react';\nimport useSWR from 'swr';\nimport { useNetworkId } from './network-context';\nimport { isMuted, useMuteVersion } from './chat-mute';\n\nconst STORAGE_PREFIX = 'anet_chat_read_v1:';\nconst UNREAD_EVENT = 'anet-chat-read-updated';\n\ninterface ChatMessage {\n from_alias?: string | null;\n to_alias?: string | null;\n created_at?: string | null;\n}\n\n/** Senders/recipients that mean \"the dashboard user\" in hub data. The chat\n * panel uses the same set to decide which bubbles are \"You\". */\nconst USERISH = new Set(['', 'dashboard', 'admin', 'api', 'hub']);\nconst isUserish = (v?: string | null) => USERISH.has((v || '').trim().toLowerCase());\n\ninterface ReadMap {\n [alias: string]: string;\n}\n\nfunction storageKey(networkId: string) {\n return `${STORAGE_PREFIX}${networkId || 'global'}`;\n}\n\nfunction parseHubTime(value?: string | null): number {\n if (!value) return 0;\n const normalized = value.includes('T') ? value : value.replace(' ', 'T');\n const withZone = /Z$|[+-]\\d{2}:\\d{2}$/.test(normalized) ? normalized : `${normalized}Z`;\n const ts = Date.parse(withZone);\n return Number.isFinite(ts) ? ts : 0;\n}\n\n// Loop R8 (Vincent: 未读数字角标): last-read moved sessionStorage →\n// localStorage so read state survives refresh/new tabs/restart (微信预期).\n// One-time migration pulls any old session value forward.\nconst BASELINE_KEY = '__baseline';\n\nfunction readStoredMap(networkId: string): ReadMap {\n if (typeof window === 'undefined') return {};\n try {\n let raw = window.localStorage.getItem(storageKey(networkId));\n if (!raw) {\n raw = window.sessionStorage.getItem(storageKey(networkId));\n if (raw) window.localStorage.setItem(storageKey(networkId), raw);\n }\n const parsed = raw ? JSON.parse(raw) : {};\n const map: ReadMap = parsed && typeof parsed === 'object' ? parsed : {};\n // R8 first-visit floor, written SYNCHRONOUSLY on first read: an async\n // (useEffect) baseline lost the race against the first SWR render and\n // let a badge storm flash — and stick, since nothing re-triggered the\n // count. Ensuring it here means no compute can ever see a missing\n // baseline. No event dispatch: every hook instance does the same\n // idempotent write.\n if (!map[BASELINE_KEY]) {\n map[BASELINE_KEY] = new Date().toISOString();\n window.localStorage.setItem(storageKey(networkId), JSON.stringify(map));\n }\n return map;\n } catch {\n return {};\n }\n}\n\nfunction writeStoredMap(networkId: string, next: ReadMap) {\n if (typeof window === 'undefined') return;\n try {\n window.localStorage.setItem(storageKey(networkId), JSON.stringify(next));\n window.dispatchEvent(new CustomEvent(UNREAD_EVENT, { detail: { networkId } }));\n } catch {}\n}\n\nconst fetcher = async (url: string) => {\n const res = await fetch(url);\n if (res.status === 401) {\n window.location.assign('/login');\n throw new Error('unauthorized');\n }\n return res.json();\n};\n\nfunction withNetwork(url: string, networkId: string): string {\n if (!networkId) return url;\n const sep = url.includes('?') ? '&' : '?';\n return `${url}${sep}network_id=${encodeURIComponent(networkId)}`;\n}\n\nexport function markChatRead(alias: string, networkId: string) {\n if (!alias) return;\n const current = readStoredMap(networkId);\n writeStoredMap(networkId, {\n ...current,\n [alias]: new Date().toISOString(),\n });\n}\n\nexport function useChatUnread() {\n const { networkId } = useNetworkId();\n // Messages are the ONLY count source: the hub mirrors every task reply as\n // a message to the originator (verified live: replied task + same-second\n // message, both present), so counting tasks too double-counted every\n // reply (E2E showed 4 where 2 was right).\n const { data: messagesData } = useSWR<{ messages?: ChatMessage[] }>(\n withNetwork('/api/hub/messages?limit=200', networkId),\n fetcher,\n { refreshInterval: 5000, dedupingInterval: 3000 },\n );\n const [readVersion, setReadVersion] = useState(0);\n\n useEffect(() => {\n const onStorage = (event: StorageEvent) => {\n if (event.key && event.key !== storageKey(networkId)) return;\n setReadVersion((v) => (typeof v === 'number' ? v + 1 : 1));\n };\n const onUnreadUpdate = (event: Event) => {\n const detail = (event as CustomEvent<{ networkId?: string }>).detail;\n if (detail?.networkId !== undefined && detail.networkId !== networkId) return;\n setReadVersion((v) => (typeof v === 'number' ? v + 1 : 1));\n };\n window.addEventListener('storage', onStorage);\n window.addEventListener(UNREAD_EVENT, onUnreadUpdate);\n return () => {\n window.removeEventListener('storage', onStorage);\n window.removeEventListener(UNREAD_EVENT, onUnreadUpdate);\n };\n }, [networkId, setReadVersion]);\n\n const readMap = useMemo(() => {\n void readVersion;\n return readStoredMap(networkId);\n }, [networkId, readVersion]);\n\n const unreadMap = useMemo(() => {\n // R8: count EVERY unread item per alias (Vincent: \"有几条消息显示数字\"),\n // not just a latest-activity boolean. A message from the alias counts;\n // a task's REPLY counts once when it lands after last-read. Self-sent\n // items never count (they're keyed by the counterpart alias).\n const counts = new Map<string, number>();\n // R28 (微信排序): recency tiebreak for Overview/Nodes — but ONLY for\n // conversations the user has actually OPENED (read-map entry). On this\n // fleet agents constantly report to 'admin'; counting those yanked\n // never-opened agents to the front on every report (measured: 2 cards\n // jumped 39→1 / 60→3 in one 6s window). WeChat's list holds YOUR\n // conversations — same rule here keeps the grid calm.\n const lastActivity = new Map<string, number>();\n const opened = new Set(Object.keys(readMap).filter((k) => k !== BASELINE_KEY));\n const baseline = parseHubTime(readMap[BASELINE_KEY]);\n const bump = (alias: string, at: number) => {\n if (opened.has(alias) && at > (lastActivity.get(alias) || 0)) lastActivity.set(alias, at);\n const readAt = Math.max(parseHubTime(readMap[alias]), baseline);\n if (at > readAt) counts.set(alias, (counts.get(alias) || 0) + 1);\n };\n // Scope: only the USER'S conversation — a badge on X means \"X has\n // something FOR YOU\". Fleet chatter (X's messages to other agents)\n // must NOT inflate it.\n for (const message of messagesData?.messages || []) {\n const alias = message.from_alias?.trim();\n if (!alias || isUserish(alias)) continue; // own sends never count\n if (!isUserish(message.to_alias)) continue; // must be addressed to the user\n const at = parseHubTime(message.created_at);\n if (at) bump(alias, at);\n }\n return { counts, lastActivity };\n }, [messagesData, readMap]);\n\n const hasUnread = useCallback((alias?: string | null) => {\n if (!alias) return false;\n return (unreadMap.counts.get(alias) || 0) > 0;\n }, [unreadMap]);\n\n const unreadCount = useCallback((alias?: string | null) => {\n if (!alias) return 0;\n return unreadMap.counts.get(alias) || 0;\n }, [unreadMap]);\n\n const lastActivityAt = useCallback((alias?: string | null) => {\n if (!alias) return 0;\n return unreadMap.lastActivity.get(alias) || 0;\n }, [unreadMap]);\n\n // R34: muted conversations are excluded from the global count (WeChat\n // semantics); hasMutedUnread lets entry badges fall back to a dot.\n const muteVersion = useMuteVersion();\n const { totalUnread, hasMutedUnread } = useMemo(() => {\n void muteVersion;\n let t = 0;\n let mutedAny = false;\n for (const [alias, n] of unreadMap.counts) {\n if (isMuted(alias)) { if (n > 0) mutedAny = true; continue; }\n t += n;\n }\n return { totalUnread: t, hasMutedUnread: mutedAny };\n }, [unreadMap, muteVersion]);\n\n const clearUnread = useCallback((alias: string) => {\n markChatRead(alias, networkId);\n }, [networkId]);\n\n return { unreadMap, hasUnread, unreadCount, lastActivityAt, totalUnread, hasMutedUnread, clearUnread };\n}\n\n/** WeChat badge label: 1-99 as-is, above → \"99+\"; 0/negative → '' (hide). */\nexport function badgeLabel(n: number): string {\n if (n <= 0) return '';\n return n > 99 ? '99+' : String(n);\n}\n","'use client';\n\nimport { useSyncExternalStore } from 'react';\n\n/* Loop R34 (微信消息免打扰, 克制版): per-conversation mute. Muted\n * conversations keep their red badge but show a DOT instead of the count,\n * and their unreads are excluded from the global total (WeChat semantics).\n * Same storage/reactivity pattern as chat-drafts. */\n\nconst STORE_KEY = 'anet_chat_mute_v1';\nconst MUTE_EVENT = 'anet-chat-mute-updated';\n\nfunction readSet(): Set<string> {\n if (typeof window === 'undefined') return new Set();\n try {\n const parsed = JSON.parse(window.localStorage.getItem(STORE_KEY) || '[]');\n return new Set(Array.isArray(parsed) ? parsed : []);\n } catch {\n return new Set();\n }\n}\n\nexport function isMuted(alias?: string | null): boolean {\n if (!alias) return false;\n return readSet().has(alias);\n}\n\nexport function toggleMute(alias: string) {\n if (typeof window === 'undefined' || !alias) return;\n try {\n const s = readSet();\n if (s.has(alias)) s.delete(alias);\n else s.add(alias);\n window.localStorage.setItem(STORE_KEY, JSON.stringify([...s]));\n window.dispatchEvent(new Event(MUTE_EVENT));\n } catch {}\n}\n\nlet version = 0;\nfunction subscribe(callback: () => void) {\n const bump = () => { version++; callback(); };\n window.addEventListener(MUTE_EVENT, bump);\n window.addEventListener('storage', bump);\n return () => {\n window.removeEventListener(MUTE_EVENT, bump);\n window.removeEventListener('storage', bump);\n };\n}\n\nexport function useMuted(alias?: string | null): boolean {\n return useSyncExternalStore(subscribe, () => (alias ? isMuted(alias) : false), () => false);\n}\n\n/** Monotonic version for callers that use plain isMuted() inside render\n * loops (map callbacks can't call hooks). */\nexport function useMuteVersion(): number {\n return useSyncExternalStore(subscribe, () => version, () => 0);\n}\n","'use client';\n\nimport { useEffect } from 'react';\n\n// #217 S6 — verified themes: cyber (dark), light (white), and slack\n// (Vincent 2026-07-16 via api channel: \"其他的就搞成那种 Slack 方式吧…快速搞一个\"\n// — Slack-style is now the DEFAULT look; the network/topology page keeps its\n// showcase visuals, see TopoGraph's data-skin exemption).\n//\n// Mechanism: `slack` is implemented as a SKIN on top of the light theme —\n// applyTheme sets `data-theme=\"light\"` (so every existing light compat-shim\n// in globals.css applies unchanged) plus `data-skin=\"slack\"` which the\n// slack-only overrides key on (aubergine rail, Slack-blue accent, de-noise).\n// This keeps the fast first version to globals.css + three tiny component\n// touches instead of a full hex→token sweep (that sweep stays scheduled as\n// redesign Phase 0 next version).\n\nexport const THEMES = new Set(['cyber', 'light', 'slack']);\n\n/** Apply a theme choice to <html>. Single owner of the data-theme/data-skin\n * contract — Settings and Cmd+K call this too, so the skin attribute can\n * never desync from the theme attribute. */\nexport function applyTheme(t: string) {\n if (typeof document === 'undefined') return;\n const el = document.documentElement;\n if (t === 'slack') {\n el.setAttribute('data-theme', 'light');\n el.setAttribute('data-skin', 'slack');\n } else {\n el.setAttribute('data-theme', t);\n el.removeAttribute('data-skin');\n }\n}\n\nexport function ThemeProvider({ children }: { children: React.ReactNode }) {\n useEffect(() => {\n if (typeof document === 'undefined') return;\n // ROLLBACK (Vincent 07-20): the classic dark theme is the default again\n // — he prefers the original look and doesn't want a Slack copy as the\n // face of the product. 'slack' stays available as an explicit Settings\n // choice until the original agent-network theme replaces it. Users who\n // explicitly picked a theme keep their pick; everyone else returns to\n // cyber automatically (the slack-default window never wrote storage).\n let t = 'cyber';\n try {\n const saved = localStorage.getItem('anet-theme');\n if (saved && THEMES.has(saved)) t = saved;\n } catch {}\n applyTheme(t);\n }, []);\n return <>{children}</>;\n}\n","'use client';\n\nimport { useEffect, useState } from 'react';\nimport useSWR from 'swr';\n\n/** Issue #119 — server-side panel listing the hub's hosts + CPU/RAM bars.\n *\n * Steps 1+2 (SDK马 host telemetry + CommHub aggregation) shipped with\n * commhub-server v0.8.1-preview.2. Step 3 (this file, Round 20 of the\n * dashboard /loop) swaps the original mock seed for a SWR fetch of\n * `/api/hub/servers` (which proxies to the hub's `/api/servers`).\n *\n * Collapsed by default to a thin vertical icon strip so it never competes\n * with the topology graph for horizontal real-estate. State persists to\n * localStorage just like the other dashboard drawers.\n *\n * Backward-compat: if the upstream hub predates v0.8.1-preview.2 the\n * proxy returns `{ servers: [], unavailable: true }`. The drawer\n * surfaces a friendly \"not yet available\" hint instead of an empty list,\n * so old hubs don't read as \"something broke\".\n */\n\ninterface ServerAgent {\n alias: string;\n runtime: string | null;\n status: 'working' | 'idle' | 'offline';\n last_seen_at?: string | null;\n progress?: number | null; // 0..1\n}\n\ninterface ServerCard {\n hostname: string;\n ip?: string | null;\n cpu_load_1min: number | null;\n cpu_cores: number;\n mem_used_gb: number | null;\n mem_total_gb: number | null;\n /** Hero 1 v0.10.0: disk usage. Optional — older hubs don't report. */\n disk_used_gb?: number | null;\n disk_total_gb?: number | null;\n /** Hero 1 v0.10.0: short history for sparklines (5-min sliding window).\n * Each is the rolling 1-min average sampled at ~30s cadence (so ~10\n * data points for 5-min). Optional — older hubs don't report. */\n cpu_history?: number[];\n mem_history?: number[];\n /** v0.10.2 RFC-014 — disk usage 5-min rolling history. Optional;\n * older agent-node (< 2.4.1-preview.0) doesn't ship it. */\n disk_history?: number[];\n /** Hero 2 v0.10.0: per-server agent rollup. Optional — older hubs\n * send only aggregate agent_count. */\n agents?: ServerAgent[];\n agent_count: number;\n status: 'online' | 'offline';\n note?: string;\n}\n\ninterface ServersResponse {\n servers: ServerCard[];\n unavailable?: boolean;\n}\n\nconst fetcher = async (url: string): Promise<ServersResponse> => {\n const res = await fetch(url);\n if (res.status === 401) {\n if (typeof window !== 'undefined') window.location.assign('/login');\n throw new Error('unauthorized');\n }\n if (!res.ok) throw new Error(`hub ${res.status}`);\n return res.json();\n};\n\n// Bar tint by usage — green ≤60%, amber 60–85%, red >85%. Keeps the eye\n// going to whichever box is actually about to tip over.\nfunction barTint(pct: number) {\n if (pct >= 85) return { fill: '#ef4444', track: 'rgb(239 68 68 / 0.16)' };\n if (pct >= 60) return { fill: '#f59e0b', track: 'rgb(245 158 11 / 0.16)' };\n return { fill: '#10b981', track: 'rgb(16 185 129 / 0.16)' };\n}\n\nfunction Bar({ pct, label }: { pct: number; label: string }) {\n const t = barTint(pct);\n const clamped = Math.max(0, Math.min(100, pct));\n return (\n <div className=\"space-y-0.5\">\n <div className=\"flex justify-between text-[10px] text-[var(--fg-muted)] font-mono\">\n <span>{label}</span>\n <span className=\"tabular-nums\">{Math.round(clamped)}%</span>\n </div>\n <div className=\"h-1.5 rounded-full overflow-hidden\" style={{ background: t.track }}>\n <div\n className=\"h-full transition-[width] duration-300 ease-out\"\n style={{ width: `${clamped}%`, background: t.fill }}\n />\n </div>\n </div>\n );\n}\n\n/** Hero 1 v0.10.0 — inline SVG sparkline for 5-min rolling history.\n * Zero-dep (no recharts). Renders a stroked polyline + filled area.\n * Values are percentages (0..100); clamps inside. */\nfunction Sparkline({ values, tint, label }: { values: number[]; tint: string; label: string }) {\n if (!values || values.length < 2) return null;\n const w = 100, h = 18;\n const max = 100;\n const stride = w / Math.max(1, values.length - 1);\n const pts = values.map((v, i) => {\n const x = i * stride;\n const y = h - (Math.max(0, Math.min(max, v)) / max) * h;\n return `${x.toFixed(1)},${y.toFixed(1)}`;\n });\n const polyline = pts.join(' ');\n const area = `M0,${h} L${pts.join(' L')} L${w},${h} Z`;\n return (\n <svg\n width=\"100%\" height={h} viewBox={`0 0 ${w} ${h}`}\n preserveAspectRatio=\"none\" aria-label={`${label} 5-min history`}\n data-server-sparkline={label}\n >\n <path d={area} fill={tint} opacity=\"0.18\" />\n <polyline points={polyline} fill=\"none\" stroke={tint} strokeWidth=\"1.2\" />\n </svg>\n );\n}\n\n/** Hero 1 v0.10.0 — single health badge derived from the worst of\n * CPU / Mem / Disk percentages. Green ≤60%, amber 60-85%, red >85%\n * (same thresholds as Bar). Returns null when no percentages available\n * (e.g. offline server) so the card layout reads \"n/a · offline\" instead. */\nfunction HealthBadge({ cpu, mem, disk }: { cpu: number | null; mem: number | null; disk: number | null }) {\n const vals = [cpu, mem, disk].filter((v): v is number => typeof v === 'number');\n if (vals.length === 0) return null;\n const worst = Math.max(...vals);\n const t = barTint(worst);\n const status = worst >= 85 ? 'red' : worst >= 60 ? 'amber' : 'green';\n return (\n <span\n className=\"inline-block w-2 h-2 rounded-full shrink-0\"\n style={{ background: t.fill, boxShadow: `0 0 0 2px ${t.track}` }}\n data-server-health-badge={status}\n title={`worst: ${Math.round(worst)}%`}\n />\n );\n}\n\n/** Hero 2 v0.10.0 — per-server expandable agent list. Renders compact\n * rows: alias · runtime · status chip · last_seen relative. progress\n * bar appears when an agent reports progress (0..1). When the upstream\n * hub doesn't report agents[], the row falls through to a small\n * \"agent list pending hub upgrade\" hint. */\nfunction AgentList({ agents }: { agents?: ServerAgent[] }) {\n if (!agents || agents.length === 0) {\n return (\n <div className=\"text-[9px] text-[var(--fg-dim)] font-mono italic px-1 py-1\" data-server-agents-missing=\"true\">\n {/* #157 fix — copy update. Pre-#157 the placeholder read\n \"agent rollup pending hub ≥ 0.8.2-preview\". commhub-server@\n 0.8.2 is LIVE in prod (Vincent screenshot 5560 verified) but\n still doesn't ship `agents[]`. Version-specific text was\n misleading — implied upgrade-needed when hub already\n crossed the threshold. New copy drops the version pinning\n and just states the data-shape: hub hasn't reported the\n agent rollup for this server (could be hub-side feature\n gap or session-source gap). data-server-agents-missing\n attr surfaces the gate for tests. */}\n agent rollup not reported by hub\n </div>\n );\n }\n return (\n <ul className=\"space-y-1\" data-server-agent-list>\n {agents.map(a => {\n const statusColor =\n a.status === 'working' ? '#10b981' :\n a.status === 'idle' ? '#06b6d4' : '#6b7280';\n return (\n <li\n key={a.alias}\n className=\"flex items-center gap-1.5 text-[10px] font-mono\"\n data-server-agent={a.alias}\n >\n <span className=\"w-1.5 h-1.5 rounded-full shrink-0\" style={{ background: statusColor }} />\n <span className=\"font-semibold truncate\" style={{ color: 'var(--fg)' }}>{a.alias}</span>\n {a.runtime && (\n <span className=\"text-[9px] text-[var(--fg-dim)] shrink-0\">· {a.runtime}</span>\n )}\n {typeof a.progress === 'number' && a.progress > 0 && (\n <span className=\"ml-auto text-[9px] tabular-nums text-[var(--fg-muted)]\">\n {Math.round(a.progress * 100)}%\n </span>\n )}\n </li>\n );\n })}\n </ul>\n );\n}\n\nfunction useServers(enabled = true) {\n const { data, error } = useSWR<ServersResponse>(\n enabled ? '/api/hub/servers' : null,\n fetcher,\n { refreshInterval: 5000, dedupingInterval: 3000 },\n );\n const servers = data?.servers ?? [];\n const unavailable = data?.unavailable === true;\n const onlineCount = servers.filter(s => s.status === 'online').length;\n const loading = enabled && !data && !error;\n return { data, error, servers, unavailable, onlineCount, loading };\n}\n\nexport function ServersPanel({ enabled = true, className = '' }: { enabled?: boolean; className?: string }) {\n const [expanded, setExpanded] = useState<Set<string>>(new Set());\n useEffect(() => {\n try {\n const raw = localStorage.getItem('anet-servers-drawer-expanded');\n // Expanded server rows are a client-only sticky preference; hydrate once\n // after mount so SSR stays deterministic.\n // eslint-disable-next-line react-hooks/set-state-in-effect\n if (raw) setExpanded(new Set(JSON.parse(raw)));\n } catch {}\n }, []);\n const toggleExpanded = (hostname: string) => setExpanded(prev => {\n const next = new Set(prev);\n if (next.has(hostname)) next.delete(hostname); else next.add(hostname);\n try { localStorage.setItem('anet-servers-drawer-expanded', JSON.stringify([...next])); } catch {}\n return next;\n });\n\n const { data, error, servers, unavailable, loading } = useServers(enabled);\n\n return (\n <div className={`min-h-0 overflow-y-auto px-2 py-2 space-y-2 ${className}`} data-servers-body>\n {loading && (\n <div className=\"text-[10px] text-[var(--fg-muted)] font-mono text-center py-4\">\n loading servers…\n </div>\n )}\n {error && !data && (\n <div className=\"rounded-md border px-2.5 py-2 text-[10px] font-mono\"\n style={{ background: 'rgb(239 68 68 / 0.06)', borderColor: 'rgb(239 68 68 / 0.25)', color: '#ef4444' }}>\n hub unreachable · retrying every 5s\n </div>\n )}\n {unavailable && (\n <div className=\"text-[10px] text-[var(--fg-muted)] font-mono text-center py-3 leading-relaxed\">\n host telemetry not available<br/>\n <span className=\"text-[var(--fg-dim)]\">upgrade commhub-server ≥ 0.8.1-preview.2</span>\n </div>\n )}\n {!loading && !error && !unavailable && servers.length === 0 && (\n <div className=\"text-[10px] text-[var(--fg-muted)] font-mono text-center py-4\">\n no servers reporting yet\n </div>\n )}\n {servers.map(s => {\n const offline = s.status === 'offline';\n const cpuPct = s.cpu_load_1min != null && s.cpu_cores > 0 ? (s.cpu_load_1min / s.cpu_cores) * 100 : null;\n const memPct = s.mem_used_gb != null && s.mem_total_gb != null && s.mem_total_gb > 0 ? (s.mem_used_gb / s.mem_total_gb) * 100 : null;\n const diskPct = s.disk_used_gb != null && s.disk_total_gb != null && s.disk_total_gb > 0 ? (s.disk_used_gb / s.disk_total_gb) * 100 : null;\n const isExpanded = expanded.has(s.hostname);\n return (\n <div\n key={s.hostname}\n className=\"rounded-lg border px-2.5 py-2 space-y-1.5\"\n style={{\n background: 'var(--bg)',\n borderColor: 'var(--border)',\n opacity: offline ? 0.55 : 1,\n }}\n data-server-card={s.hostname}\n data-server-expanded={isExpanded ? 'true' : 'false'}\n title={s.ip ? `${s.hostname} · ${s.ip}` : s.hostname}\n >\n {/* v0.10.0 Hero 1+2: header row — click toggles expanded\n detail view (sparklines + disk + agent rollup). */}\n <button\n type=\"button\"\n onClick={() => toggleExpanded(s.hostname)}\n aria-expanded={isExpanded}\n className=\"w-full flex items-center justify-between gap-2 text-left\"\n data-server-card-toggle={s.hostname}\n >\n <div className=\"min-w-0 flex items-center gap-1.5\">\n {/* Hero 1 health badge — worst-of CPU/Mem/Disk */}\n {!offline && <HealthBadge cpu={cpuPct} mem={memPct} disk={diskPct} />}\n <span className=\"font-mono text-[12px] font-semibold truncate\" style={{ color: 'var(--fg)' }}>{s.hostname}</span>\n {s.note && <span className=\"text-[9px] text-[var(--fg-dim)]\">({s.note})</span>}\n </div>\n <span className=\"flex items-center gap-1 shrink-0\">\n <span className=\"text-[10px] text-[var(--fg-muted)] font-mono tabular-nums\">\n {s.agent_count}&nbsp;agent{s.agent_count === 1 ? '' : 's'}\n </span>\n {/* Chevron — rotates 90° on expanded */}\n <svg\n width=\"10\" height=\"10\" viewBox=\"0 0 10 10\"\n style={{ transform: isExpanded ? 'rotate(90deg)' : 'rotate(0deg)', transition: 'transform 150ms ease-out' }}\n aria-hidden\n >\n <path d=\"M3 1.5L7 5L3 8.5\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n </svg>\n </span>\n </button>\n {!offline && cpuPct != null && (\n <Bar pct={cpuPct} label={`CPU ${s.cpu_load_1min!.toFixed(2)}/${s.cpu_cores}`} />\n )}\n {!offline && memPct != null && (\n <Bar pct={memPct} label={`RAM ${s.mem_used_gb!.toFixed(1)}/${s.mem_total_gb!.toFixed(1)}G`} />\n )}\n {offline && (\n <div className=\"text-[10px] text-[var(--fg-dim)] font-mono italic\">CPU n/a · RAM n/a · offline</div>\n )}\n {/* v0.10.0 Hero 1+2: expanded detail — disk bar +\n 5-min sparklines + agent rollup. Visible only when\n the user clicks the card. Renders gracefully when\n upstream hub hasn't shipped optional fields. */}\n {isExpanded && !offline && (\n <div className=\"pt-1 mt-1 border-t space-y-1.5\" style={{ borderColor: 'var(--border)' }}>\n {diskPct != null ? (\n <Bar pct={diskPct} label={`DISK ${s.disk_used_gb!.toFixed(1)}/${s.disk_total_gb!.toFixed(1)}G`} />\n ) : (\n /* #157 sibling fix — same misleading version-pin copy\n dropped at the disk-metric placeholder. Same\n rationale as the agent-rollup copy above. */\n <div className=\"text-[9px] text-[var(--fg-dim)] font-mono italic\" data-server-disk-missing=\"true\">disk metric not reported by hub</div>\n )}\n {s.cpu_history && s.cpu_history.length >= 2 && (\n <div className=\"space-y-0.5\">\n <div className=\"text-[9px] text-[var(--fg-muted)] font-mono\">CPU · 5-min</div>\n <Sparkline values={s.cpu_history} tint=\"#10b981\" label=\"CPU\" />\n </div>\n )}\n {s.mem_history && s.mem_history.length >= 2 && (\n <div className=\"space-y-0.5\">\n <div className=\"text-[9px] text-[var(--fg-muted)] font-mono\">RAM · 5-min</div>\n <Sparkline values={s.mem_history} tint=\"#06b6d4\" label=\"MEM\" />\n </div>\n )}\n {/* v0.10.2 RFC-014 §7 close gate #3 — disk usage\n 5-min curve. Amber tint matches the disk bar\n tier convention (DISK > CPU/Mem in alert-\n priority hierarchy since disk-full is a hard\n failure mode). Render only when agent-node\n 2.4.1-preview.0+ has shipped disk_history;\n backward-compat handles older agents silently\n (no sparkline, no broken state). */}\n {s.disk_history && s.disk_history.length >= 2 && (\n <div className=\"space-y-0.5\">\n <div className=\"text-[9px] text-[var(--fg-muted)] font-mono\">DISK · 5-min</div>\n <Sparkline values={s.disk_history} tint=\"#f59e0b\" label=\"DISK\" />\n </div>\n )}\n <div className=\"pt-1\">\n <div className=\"text-[9px] text-[var(--fg-muted)] font-mono mb-0.5\">agents</div>\n <AgentList agents={s.agents} />\n </div>\n </div>\n )}\n </div>\n );\n })}\n {servers.length > 0 && (\n <div className=\"pt-1 text-[9px] text-[var(--fg-dim)] font-mono text-center\">\n live · refreshing every 5s\n </div>\n )}\n </div>\n );\n}\n\nexport function ServersDrawer() {\n const [open, setOpen] = useState(false);\n // Drawer state is per-user-machine — persist like the other dashboard\n // sticky toggles (`anet-topo-layout`, `anet-topo-view`, etc.).\n useEffect(() => {\n // Drawer openness is persisted in localStorage and can only be restored on\n // the client after mount.\n // eslint-disable-next-line react-hooks/set-state-in-effect\n try { if (localStorage.getItem('anet-servers-drawer') === '1') setOpen(true); } catch {}\n }, []);\n const toggle = () => setOpen(prev => {\n const next = !prev;\n try { localStorage.setItem('anet-servers-drawer', next ? '1' : '0'); } catch {}\n return next;\n });\n\n // Round 20 / #119 step 3 final delivery — real SWR fetch. 5s refresh\n // matches the other live drawers (HealthBanner, Sidebar) so an operator\n // sees host telemetry update in roughly the same beat as session state.\n // Only poll while expanded — collapsed icon strip doesn't need fresh data.\n const { servers, onlineCount } = useServers(open);\n\n return (\n <aside\n className=\"fixed right-0 top-20 z-40 hidden lg:flex flex-col rounded-l-xl border border-r-0 shadow-xl shadow-black/30 anet-fade-in\"\n style={{\n background: 'var(--bg-secondary)',\n borderColor: 'var(--border)',\n width: open ? 296 : 40,\n maxHeight: 'calc(100vh - 6rem)',\n transition: 'width 200ms ease-out',\n }}\n aria-label=\"Servers panel\"\n >\n <button\n onClick={toggle}\n aria-expanded={open}\n aria-label={open ? 'Collapse servers panel' : 'Expand servers panel'}\n className=\"flex items-center gap-2 px-2.5 py-2 border-b text-[11px] font-semibold tracking-wide select-none\"\n style={{ color: 'var(--fg)', borderColor: 'var(--border)' }}\n >\n <svg className=\"w-4 h-4 shrink-0\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.8\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <rect x=\"3\" y=\"4\" width=\"18\" height=\"6\" rx=\"1.5\" />\n <rect x=\"3\" y=\"14\" width=\"18\" height=\"6\" rx=\"1.5\" />\n <circle cx=\"7\" cy=\"7\" r=\"0.7\" fill=\"currentColor\" />\n <circle cx=\"7\" cy=\"17\" r=\"0.7\" fill=\"currentColor\" />\n </svg>\n {open && (\n <>\n <span className=\"flex-1 text-left\">Servers</span>\n <span className=\"text-[10px] text-[var(--fg-muted)] font-mono\">{onlineCount}/{servers.length}</span>\n </>\n )}\n </button>\n\n {open && (\n <ServersPanel enabled={open} className=\"flex-1\" />\n )}\n </aside>\n );\n}\n"],"names":["process","env","NEXT_RUNTIME","module","exports","require","__NEXT_EXPERIMENTAL_REACT","NODE_ENV","TURBOPACK","vendored","ReactJsxRuntime","React","AppRouterContext","ReactServerDOMTurbopackClient","HooksClientContext","ServerInsertedHtml","parseHubTime","dateStr","iso","includes","replace","t","Date","parse","Number","isFinite","relativeAgo","s","Math","floor","now","formatWeChatTime","value","d","zh","navigator","language","toLowerCase","startsWith","hm","String","getHours","padStart","getMinutes","startOfDay","x","getFullYear","getMonth","getDate","getTime","dayDiff","round","wd","Intl","DateTimeFormat","undefined","weekday","format","md","month","day","year","NetworkContext","networkId","setNetworkId","NetworkProvider","children","saved","sessionStorage","getItem","setAndPersist","id","setItem","Provider","useNetworkId","fetcher","url","res","fetch","status","window","location","assign","Error","json","SWR_OPTIONS","refreshInterval","dedupingInterval","withNetwork","sep","encodeURIComponent","useSessions","data","error","isLoading","sessions","hint","_hint","useNodeLifecycle","mutate","lifecycleByAlias","nodeIdByAlias","attrsByAlias","n","nodes","alias","lifecycle_state","node_id","display_name","team","tags","Array","isArray","attrs_revision","refreshNodes","useHealth","health","useAnetConfig","config","useTasks","params","query","URLSearchParams","limit","toString","tasks","count","source","useStats","stats","ok","useMessages","keepPreviousData","messages","sseCountFor","session","sseSessions","scoped","network_id","isOnline","presenceStatus","conns","sse_connections","THEMES","Set","applyTheme","document","el","documentElement","setAttribute","removeAttribute","ThemeProvider","localStorage","has","barTint","pct","fill","track","Bar","label","clamped","max","min","className","style","background","width","Sparkline","values","tint","length","w","h","stride","pts","map","v","i","y","toFixed","polyline","join","area","height","viewBox","preserveAspectRatio","opacity","points","stroke","strokeWidth","HealthBadge","cpu","mem","disk","vals","filter","worst","boxShadow","title","AgentList","agents","a","statusColor","color","runtime","progress","useServers","enabled","servers","unavailable","onlineCount","loading","ServersPanel","expanded","setExpanded","raw","JSON","toggleExpanded","hostname","prev","next","delete","add","stringify","borderColor","offline","cpuPct","cpu_load_1min","cpu_cores","memPct","mem_used_gb","mem_total_gb","diskPct","disk_used_gb","disk_total_gb","isExpanded","ip","type","onClick","note","agent_count","transform","transition","strokeLinecap","strokeLinejoin","cpu_history","mem_history","disk_history","ServersDrawer","open","setOpen","toggle","maxHeight","rx","cx","cy","r"],"mappings":"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","ignoreList":[0,1,2,3,4,5,6]}