@sleep2agi/agent-network-dashboard 0.6.3-preview.48 → 0.6.3-preview.49

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 (179) 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 +7 -7
  5. package/.next/fallback-build-manifest.json +3 -3
  6. package/.next/prerender-manifest.json +3 -3
  7. package/.next/server/app/_global-error.html +1 -1
  8. package/.next/server/app/_global-error.rsc +1 -1
  9. package/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  10. package/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  11. package/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  12. package/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  13. package/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  14. package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  15. package/.next/server/app/_not-found.html +2 -2
  16. package/.next/server/app/_not-found.rsc +2 -2
  17. package/.next/server/app/_not-found.segments/_full.segment.rsc +2 -2
  18. package/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  19. package/.next/server/app/_not-found.segments/_index.segment.rsc +2 -2
  20. package/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  21. package/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  22. package/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  23. package/.next/server/app/admin/page_client-reference-manifest.js +1 -1
  24. package/.next/server/app/admin.html +2 -2
  25. package/.next/server/app/admin.rsc +2 -2
  26. package/.next/server/app/admin.segments/_full.segment.rsc +2 -2
  27. package/.next/server/app/admin.segments/_head.segment.rsc +1 -1
  28. package/.next/server/app/admin.segments/_index.segment.rsc +2 -2
  29. package/.next/server/app/admin.segments/_tree.segment.rsc +2 -2
  30. package/.next/server/app/admin.segments/admin/__PAGE__.segment.rsc +1 -1
  31. package/.next/server/app/admin.segments/admin.segment.rsc +1 -1
  32. package/.next/server/app/index.html +2 -2
  33. package/.next/server/app/index.rsc +3 -3
  34. package/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  35. package/.next/server/app/index.segments/_full.segment.rsc +3 -3
  36. package/.next/server/app/index.segments/_head.segment.rsc +1 -1
  37. package/.next/server/app/index.segments/_index.segment.rsc +2 -2
  38. package/.next/server/app/index.segments/_tree.segment.rsc +2 -2
  39. package/.next/server/app/login/page_client-reference-manifest.js +1 -1
  40. package/.next/server/app/login.html +2 -2
  41. package/.next/server/app/login.rsc +3 -3
  42. package/.next/server/app/login.segments/_full.segment.rsc +3 -3
  43. package/.next/server/app/login.segments/_head.segment.rsc +1 -1
  44. package/.next/server/app/login.segments/_index.segment.rsc +2 -2
  45. package/.next/server/app/login.segments/_tree.segment.rsc +2 -2
  46. package/.next/server/app/login.segments/login/__PAGE__.segment.rsc +2 -2
  47. package/.next/server/app/login.segments/login.segment.rsc +1 -1
  48. package/.next/server/app/logs/page_client-reference-manifest.js +1 -1
  49. package/.next/server/app/logs.html +2 -2
  50. package/.next/server/app/logs.rsc +2 -2
  51. package/.next/server/app/logs.segments/_full.segment.rsc +2 -2
  52. package/.next/server/app/logs.segments/_head.segment.rsc +1 -1
  53. package/.next/server/app/logs.segments/_index.segment.rsc +2 -2
  54. package/.next/server/app/logs.segments/_tree.segment.rsc +2 -2
  55. package/.next/server/app/logs.segments/logs/__PAGE__.segment.rsc +1 -1
  56. package/.next/server/app/logs.segments/logs.segment.rsc +1 -1
  57. package/.next/server/app/messages/page_client-reference-manifest.js +1 -1
  58. package/.next/server/app/messages.html +2 -2
  59. package/.next/server/app/messages.rsc +2 -2
  60. package/.next/server/app/messages.segments/_full.segment.rsc +2 -2
  61. package/.next/server/app/messages.segments/_head.segment.rsc +1 -1
  62. package/.next/server/app/messages.segments/_index.segment.rsc +2 -2
  63. package/.next/server/app/messages.segments/_tree.segment.rsc +2 -2
  64. package/.next/server/app/messages.segments/messages/__PAGE__.segment.rsc +1 -1
  65. package/.next/server/app/messages.segments/messages.segment.rsc +1 -1
  66. package/.next/server/app/node/page_client-reference-manifest.js +1 -1
  67. package/.next/server/app/node.html +2 -2
  68. package/.next/server/app/node.rsc +2 -2
  69. package/.next/server/app/node.segments/_full.segment.rsc +2 -2
  70. package/.next/server/app/node.segments/_head.segment.rsc +1 -1
  71. package/.next/server/app/node.segments/_index.segment.rsc +2 -2
  72. package/.next/server/app/node.segments/_tree.segment.rsc +2 -2
  73. package/.next/server/app/node.segments/node/__PAGE__.segment.rsc +1 -1
  74. package/.next/server/app/node.segments/node.segment.rsc +1 -1
  75. package/.next/server/app/nodes/[alias]/page_client-reference-manifest.js +1 -1
  76. package/.next/server/app/nodes/page_client-reference-manifest.js +1 -1
  77. package/.next/server/app/nodes.html +2 -2
  78. package/.next/server/app/nodes.rsc +3 -3
  79. package/.next/server/app/nodes.segments/_full.segment.rsc +3 -3
  80. package/.next/server/app/nodes.segments/_head.segment.rsc +1 -1
  81. package/.next/server/app/nodes.segments/_index.segment.rsc +2 -2
  82. package/.next/server/app/nodes.segments/_tree.segment.rsc +2 -2
  83. package/.next/server/app/nodes.segments/nodes/__PAGE__.segment.rsc +2 -2
  84. package/.next/server/app/nodes.segments/nodes.segment.rsc +1 -1
  85. package/.next/server/app/page_client-reference-manifest.js +1 -1
  86. package/.next/server/app/providers/page_client-reference-manifest.js +1 -1
  87. package/.next/server/app/providers.html +2 -2
  88. package/.next/server/app/providers.rsc +2 -2
  89. package/.next/server/app/providers.segments/_full.segment.rsc +2 -2
  90. package/.next/server/app/providers.segments/_head.segment.rsc +1 -1
  91. package/.next/server/app/providers.segments/_index.segment.rsc +2 -2
  92. package/.next/server/app/providers.segments/_tree.segment.rsc +2 -2
  93. package/.next/server/app/providers.segments/providers/__PAGE__.segment.rsc +1 -1
  94. package/.next/server/app/providers.segments/providers.segment.rsc +1 -1
  95. package/.next/server/app/server-logs/page_client-reference-manifest.js +1 -1
  96. package/.next/server/app/server-logs.html +2 -2
  97. package/.next/server/app/server-logs.rsc +2 -2
  98. package/.next/server/app/server-logs.segments/_full.segment.rsc +2 -2
  99. package/.next/server/app/server-logs.segments/_head.segment.rsc +1 -1
  100. package/.next/server/app/server-logs.segments/_index.segment.rsc +2 -2
  101. package/.next/server/app/server-logs.segments/_tree.segment.rsc +2 -2
  102. package/.next/server/app/server-logs.segments/server-logs/__PAGE__.segment.rsc +1 -1
  103. package/.next/server/app/server-logs.segments/server-logs.segment.rsc +1 -1
  104. package/.next/server/app/servers/page_client-reference-manifest.js +1 -1
  105. package/.next/server/app/servers.html +2 -2
  106. package/.next/server/app/servers.rsc +2 -2
  107. package/.next/server/app/servers.segments/_full.segment.rsc +2 -2
  108. package/.next/server/app/servers.segments/_head.segment.rsc +1 -1
  109. package/.next/server/app/servers.segments/_index.segment.rsc +2 -2
  110. package/.next/server/app/servers.segments/_tree.segment.rsc +2 -2
  111. package/.next/server/app/servers.segments/servers/__PAGE__.segment.rsc +1 -1
  112. package/.next/server/app/servers.segments/servers.segment.rsc +1 -1
  113. package/.next/server/app/settings/networks/page_client-reference-manifest.js +1 -1
  114. package/.next/server/app/settings/networks.html +2 -2
  115. package/.next/server/app/settings/networks.rsc +2 -2
  116. package/.next/server/app/settings/networks.segments/_full.segment.rsc +2 -2
  117. package/.next/server/app/settings/networks.segments/_head.segment.rsc +1 -1
  118. package/.next/server/app/settings/networks.segments/_index.segment.rsc +2 -2
  119. package/.next/server/app/settings/networks.segments/_tree.segment.rsc +2 -2
  120. package/.next/server/app/settings/networks.segments/settings/networks/__PAGE__.segment.rsc +1 -1
  121. package/.next/server/app/settings/networks.segments/settings/networks.segment.rsc +1 -1
  122. package/.next/server/app/settings/networks.segments/settings.segment.rsc +1 -1
  123. package/.next/server/app/settings/page_client-reference-manifest.js +1 -1
  124. package/.next/server/app/settings/tokens/page_client-reference-manifest.js +1 -1
  125. package/.next/server/app/settings/tokens.html +2 -2
  126. package/.next/server/app/settings/tokens.rsc +2 -2
  127. package/.next/server/app/settings/tokens.segments/_full.segment.rsc +2 -2
  128. package/.next/server/app/settings/tokens.segments/_head.segment.rsc +1 -1
  129. package/.next/server/app/settings/tokens.segments/_index.segment.rsc +2 -2
  130. package/.next/server/app/settings/tokens.segments/_tree.segment.rsc +2 -2
  131. package/.next/server/app/settings/tokens.segments/settings/tokens/__PAGE__.segment.rsc +1 -1
  132. package/.next/server/app/settings/tokens.segments/settings/tokens.segment.rsc +1 -1
  133. package/.next/server/app/settings/tokens.segments/settings.segment.rsc +1 -1
  134. package/.next/server/app/settings.html +2 -2
  135. package/.next/server/app/settings.rsc +3 -3
  136. package/.next/server/app/settings.segments/_full.segment.rsc +3 -3
  137. package/.next/server/app/settings.segments/_head.segment.rsc +1 -1
  138. package/.next/server/app/settings.segments/_index.segment.rsc +2 -2
  139. package/.next/server/app/settings.segments/_tree.segment.rsc +2 -2
  140. package/.next/server/app/settings.segments/settings/__PAGE__.segment.rsc +2 -2
  141. package/.next/server/app/settings.segments/settings.segment.rsc +1 -1
  142. package/.next/server/app/tasks/[id]/page_client-reference-manifest.js +1 -1
  143. package/.next/server/app/tasks/page_client-reference-manifest.js +1 -1
  144. package/.next/server/app/tasks.html +2 -2
  145. package/.next/server/app/tasks.rsc +2 -2
  146. package/.next/server/app/tasks.segments/_full.segment.rsc +2 -2
  147. package/.next/server/app/tasks.segments/_head.segment.rsc +1 -1
  148. package/.next/server/app/tasks.segments/_index.segment.rsc +2 -2
  149. package/.next/server/app/tasks.segments/_tree.segment.rsc +2 -2
  150. package/.next/server/app/tasks.segments/tasks/__PAGE__.segment.rsc +1 -1
  151. package/.next/server/app/tasks.segments/tasks.segment.rsc +1 -1
  152. package/.next/server/chunks/ssr/[root-of-the-server]__0~hwpo-._.js +1 -1
  153. package/.next/server/chunks/ssr/[root-of-the-server]__0~hwpo-._.js.map +1 -1
  154. package/.next/server/chunks/ssr/dash-stageb-wt_app_0qn7hvc._.js +1 -1
  155. package/.next/server/chunks/ssr/dash-stageb-wt_app_0qn7hvc._.js.map +1 -1
  156. package/.next/server/chunks/ssr/dash-stageb-wt_app_0ss0pj-._.js +1 -1
  157. package/.next/server/chunks/ssr/dash-stageb-wt_app_0ss0pj-._.js.map +1 -1
  158. package/.next/server/chunks/ssr/dash-stageb-wt_app_nodes_NodesView_tsx_0patjj7._.js +1 -1
  159. package/.next/server/chunks/ssr/dash-stageb-wt_app_nodes_NodesView_tsx_0patjj7._.js.map +1 -1
  160. package/.next/server/middleware-build-manifest.js +3 -3
  161. package/.next/server/pages/404.html +2 -2
  162. package/.next/server/pages/500.html +1 -1
  163. package/.next/server/server-reference-manifest.js +1 -1
  164. package/.next/server/server-reference-manifest.json +1 -1
  165. package/.next/static/chunks/{0f4ka5~cerf-7.js → 0_xyyy_x0k42j.js} +1 -1
  166. package/.next/static/chunks/0ev252k-tf_aa.css +1 -0
  167. package/.next/static/chunks/{0b.l705p4.7r..js → 0i8qbq4v47v3r.js} +1 -1
  168. package/.next/static/chunks/{0aai8zcjyszd3.js → 0ko39v-gezo7d.js} +1 -1
  169. package/.next/static/chunks/{0myw8w8x~cg35.js → 0xcazs6t8~l4q.js} +1 -1
  170. package/.next/trace +2 -2
  171. package/.next/trace-build +1 -1
  172. package/app/components/ChatPane.tsx +5 -1
  173. package/app/nodes/NodesView.tsx +29 -2
  174. package/package.json +1 -1
  175. package/tests/e2e-stage-b-chat-pane.spec.ts +33 -6
  176. package/.next/static/chunks/0zgw-p4j0r3q0.css +0 -1
  177. /package/.next/static/{9glwGqiQS_tqV79QBeB0R → HIKVEkFShWE481BxQDjwH}/_buildManifest.js +0 -0
  178. /package/.next/static/{9glwGqiQS_tqV79QBeB0R → HIKVEkFShWE481BxQDjwH}/_clientMiddlewareManifest.js +0 -0
  179. /package/.next/static/{9glwGqiQS_tqV79QBeB0R → HIKVEkFShWE481BxQDjwH}/_ssgManifest.js +0 -0
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../dash-stageb-wt/app/nodes/NodesView.tsx","../../../../../dash-stageb-wt/app/components/CreateNodeWizard.tsx","../../../../../dash-stageb-wt/app/components/HostSupervisorPicker.tsx","../../../../../dash-stageb-wt/app/components/NodeList.tsx","../../../../../dash-stageb-wt/app/components/ChatPane.tsx"],"sourcesContent":["'use client';\n\nimport { useState, useRef, useEffect, useSyncExternalStore } from 'react';\nimport { timeAgo } from '../components/utils';\nimport { useSessions, useHealth, useNodeLifecycle } from '../lib/hooks';\nimport { useSWRConfig } from 'swr';\nimport { TaskChatPanel } from '../components/TaskChatPanel';\nimport { CreateNodeWizard } from '../components/CreateNodeWizard';\nimport { NodeLifecycleMenu } from '../components/NodeLifecycleMenu';\nimport { EmptyState, NodesEmptyState } from '../components/EmptyState';\nimport { AliasAvatar } from '../components/AliasAvatar';\nimport { useHasDraft } from '../lib/chat-drafts';\nimport { isMuted, useMuteVersion } from '../lib/chat-mute';\nimport { isPinned, usePinVersion } from '../lib/chat-pin';\nimport { pinyinMatch, usePinyinReady } from '../lib/pinyin-match';\nimport { useCollapsibleSearch } from '../components/CollapsibleSearch';\nimport { NodeList } from '../components/NodeList';\nimport { ChatPane } from '../components/ChatPane';\nimport type { Session } from '../components/types';\nimport { SESSION_STATUS_CHIP_CLASS as STATUS_COLORS } from '../lib/status';\nimport { useChatUnread } from '../lib/chat-unread';\nimport { t } from '../lib/ui-lang';\n\n/** Round 81: shorten long server hostnames (Alibaba `iZ…oyZ` style)\n * for table display. Returns the original string unchanged when ≤12\n * chars. Full value should stay in `title=` for hover + screen-readers. */\nfunction shortServer(server: string | null | undefined): string {\n if (!server) return '—';\n return server.length > 12 ? `${server.slice(0, 8)}…` : server;\n}\n\ntype ViewMode = 'list' | 'grid';\ntype SessionRow = Session & { online: boolean };\n\n// #Stage B (dashboard 3-col): /nodes/[alias] URL routing. Next's app-router\n// param may arrive still percent-encoded (aliases are often Chinese); decode\n// exactly once, defensively — if the segment was already decoded and contains\n// a literal '%' that doesn't form a valid escape, decodeURIComponent throws\n// and we keep the raw value instead of double-decoding.\nexport function decodeAliasSegment(seg: string): string {\n try { return decodeURIComponent(seg); } catch { return seg; }\n}\n\n// #Stage B: < 768px (Tailwind md) falls back to the single-column layout —\n// chat opens as the existing full-screen overlay push instead of a third\n// column. useSyncExternalStore so SSR (no matchMedia) renders the desktop\n// shape and hydration corrects without a React mismatch.\nconst MD_QUERY = '(min-width: 768px)';\nfunction subscribeMd(cb: () => void) {\n const mql = window.matchMedia(MD_QUERY);\n mql.addEventListener('change', cb);\n return () => mql.removeEventListener('change', cb);\n}\nfunction useIsDesktop(): boolean {\n return useSyncExternalStore(subscribeMd, () => window.matchMedia(MD_QUERY).matches, () => true);\n}\n\n/** R13 (草稿闭环还债): same [草稿] mark as AgentCard/CommandCenter tabs. */\nfunction DraftMark({ alias }: { alias: string }) {\n const hasDraft = useHasDraft(alias);\n if (!hasDraft) return null;\n return <span className=\"shrink-0 text-[9px] text-red-400/90\" aria-label={t('有未发送草稿', 'Unsent draft')}>{t('[草稿]', '[draft]')}</span>;\n}\n\nexport function NodesView({ initialAlias = null }: { initialAlias?: string | null }) {\n const { sessions, isLoading: loading } = useSessions();\n const { health } = useHealth();\n const { lifecycleByAlias, nodeIdByAlias, attrsByAlias } = useNodeLifecycle();\n const { hasUnread, unreadCount, lastActivityAt } = useChatUnread();\n const { mutate } = useSWRConfig();\n // RFC-027 PR2 — after a stop/delete/restart dispatch lands, refresh\n // /api/hub/nodes (lifecycle_state) AND /api/hub/status (sessions).\n // Both feed the menu's state-aware items; otherwise menu stays\n // stale until next 5s SWR poll.\n const refreshNodes = () => {\n mutate((k: unknown) => typeof k === 'string' && (k.startsWith('/api/hub/nodes') || k.startsWith('/api/hub/status')));\n };\n const sseMap = health?.sse_sessions || {};\n // SSE keys are `network_id:alias` since server v0.7+. Look up with the\n // composite key first, fall back to alias-only for legacy hubs.\n const sseFor = (s: { alias: string; network_id?: string }) =>\n (s.network_id ? sseMap[`${s.network_id}:${s.alias}`] : undefined) ?? sseMap[s.alias];\n const [filterStatus, setFilterStatus] = useState('');\n // #492 goal-3 step 2: filter by team (single-select, '' = no filter,\n // '__NO_TEAM__' = \"nodes without any team assignment\"). team match is\n // strict equality against attrsByAlias[alias].team ?? null — nodes\n // WITHOUT a team never leak into \"team X\" results (per PR review:\n // fixture must have mixed team values and assert exact aliases, not\n // just count).\n const [filterTeam, setFilterTeam] = useState('');\n // #492 goal-3 step 2: tag filter is multi-select with AND semantics —\n // \"show nodes that have ALL of these tags\". This is a product\n // decision (per PR review: OR would be the naive user default; AND\n // is intentional so operators can narrow down instead of widen out).\n // Rendered chip row shows explicit \"AND\" separators + empty-state\n // echoes the filter conditions so a zero-result AND intersection\n // never looks like a data-sync bug.\n const [filterTags, setFilterTags] = useState<string[]>([]);\n const [search, setSearch] = useState('');\n const toggleTag = (t: string) => setFilterTags(cur => cur.includes(t) ? cur.filter(x => x !== t) : [...cur, t]);\n // Distinct teams/tags across visible sessions — drives the select\n // options and chip row, and lets us distinguish \"cold-start no attrs\"\n // from \"no match\" in the empty state.\n const distinctTeams = Array.from(new Set(sessions.map(s => attrsByAlias[s.alias]?.team).filter((t): t is string => !!t && t.length > 0))).sort();\n const distinctTags = Array.from(new Set(sessions.flatMap(s => attrsByAlias[s.alias]?.tags ?? []).filter(t => t && t.length > 0))).sort();\n const anyAttrs = distinctTeams.length > 0 || distinctTags.length > 0;\n const pinyinReady = usePinyinReady();\n const muteVersion = useMuteVersion();\n void muteVersion; // re-render on mute toggles (isMuted used in map callbacks)\n const pinVersion = usePinVersion();\n void pinVersion;\n void pinyinReady; // R25: re-filter once the lazy pinyin dict lands\n const [viewMode, setViewMode] = useState<ViewMode>('list');\n // #Stage B: selection is seeded from the /nodes/[alias] URL (shareable\n // deep link); afterwards it's plain client state kept in sync with the\n // URL via history.pushState — shallow, no route remount, so switching\n // nodes is zero-operation and the conversation pane swaps in place.\n const [chatAlias, setChatAlias] = useState<string | null>(initialAlias);\n const isDesktop = useIsDesktop();\n const selectNode = (alias: string) => {\n setChatAlias(alias);\n try { window.history.pushState({}, '', `/nodes/${encodeURIComponent(alias)}`); } catch {}\n };\n const closeChat = () => {\n setChatAlias(null);\n try { window.history.pushState({}, '', '/nodes'); } catch {}\n };\n // Back/forward buttons walk the selection history the pushState calls\n // above created — mirror the URL back into state.\n useEffect(() => {\n const onPop = () => {\n const m = window.location.pathname.match(/^\\/nodes\\/([^/]+)\\/?$/);\n setChatAlias(m ? decodeAliasSegment(m[1]) : null);\n };\n window.addEventListener('popstate', onPop);\n return () => window.removeEventListener('popstate', onPop);\n }, []);\n const [showCreate, setShowCreate] = useState(false);\n // #Stage A (dashboard 3-col, 07-31): persistent narrow node list rail\n // to the left of the existing table. Default on; user can hide to\n // restore the pre-Stage-A dense-table-only layout (Vincent's \"看全局\"\n // pattern MUST stay reachable — 通信龙 07-31 explicit constraint).\n // Persisted in localStorage so a returning user gets the same layout\n // they left.\n const [showRail, setShowRail] = useState<boolean>(() => {\n if (typeof window === 'undefined') return true;\n const v = window.localStorage.getItem('anet-nodes-rail');\n return v === null ? true : v !== '0';\n });\n const toggleRail = () => {\n setShowRail(v => {\n const next = !v;\n try { window.localStorage.setItem('anet-nodes-rail', next ? '1' : '0'); } catch {}\n return next;\n });\n };\n // #209 R32→R34: the WeChat-style magnifier-toggle search was hand-rolled\n // inline in R32. R34 extracted it to a shared hook so /nodes, /messages,\n // and any future search surface stay visually + behaviourally identical.\n // The hook returns a Button (place in header) + Row (place after header).\n const searchCtl = useCollapsibleSearch({\n value: search,\n onChange: setSearch,\n placeholder: t('搜索节点(支持拼音/首字母)…', 'Search nodes (pinyin ok)…'),\n label: 'Search nodes',\n enabled: sessions.length > 0,\n });\n\n const lastOnlineRef = useRef<Map<string, number>>(new Map());\n // eslint-disable-next-line react-hooks/purity -- see Overview note (60s sort hysteresis clock)\n const nowMs = Date.now();\n const sortOnline = (alias: string, online: boolean) => {\n if (online) lastOnlineRef.current.set(alias, nowMs);\n return (nowMs - (lastOnlineRef.current.get(alias) || 0)) < 60_000 ? 1 : 0;\n };\n const filtered: SessionRow[] = sessions\n .map(s => ({ ...s, online: !!sseFor(s) }))\n .filter(s => {\n if (filterStatus === 'online') return s.online;\n if (filterStatus === 'offline') return !s.online;\n if (filterStatus && filterStatus !== s.status) return false;\n return true;\n })\n .filter(s => {\n // #492 team filter — strict match. '' = pass all; '__NO_TEAM__' =\n // only nodes with no team assigned; any other value = exact match.\n // Nodes without a team NEVER leak into a \"team X\" result.\n if (!filterTeam) return true;\n const team = attrsByAlias[s.alias]?.team ?? null;\n if (filterTeam === '__NO_TEAM__') return team === null || team === '';\n return team === filterTeam;\n })\n .filter(s => {\n // #492 tag filter — AND across all chip selections. Zero selected =\n // pass all. Product decision (AND not OR): operators narrow down.\n if (filterTags.length === 0) return true;\n const nodeTags = attrsByAlias[s.alias]?.tags ?? [];\n return filterTags.every(t => nodeTags.includes(t));\n })\n .filter(s => !search || pinyinMatch(s.alias, search) || pinyinMatch(s.agent || '', search))\n .sort((a, b) => ((isPinned(b.alias) ? 1 : 0) - (isPinned(a.alias) ? 1 : 0)) || (sortOnline(b.alias, b.online) - sortOnline(a.alias, a.online)) || lastActivityAt(b.alias) - lastActivityAt(a.alias)); // R41 pin > R29 online-hysteresis > recency\n\n const onlineCount = sessions.filter(s => sseFor(s)).length;\n\n // #Stage A: filtered rail sessions — same criteria as the table, so\n // the two views agree while chips are toggled. Passing the SAME\n // filtered array (not re-computing) is the invariant that keeps\n // \"rail count == table count\" true at all times.\n const railSessions = filtered;\n\n return (\n <div\n data-testid=\"nodes-layout\"\n data-rail-visible={showRail ? 'true' : 'false'}\n className=\"min-h-screen max-w-full overflow-x-hidden bg-[#0b0b0d] text-gray-100 flex\"\n >\n {/* #Stage A rail — only mounted when showRail is true AND we're\n past the mobile breakpoint (below sm, rail is hidden by CSS\n to give the table full width on small screens; the toggle\n button controls both). sessions.length===0 also hides the rail\n because there's nothing to list. */}\n {showRail && sessions.length > 0 && (\n <aside\n data-testid=\"node-list-rail\"\n className=\"hidden sm:flex sm:flex-col w-[280px] shrink-0 min-h-screen sticky top-0\"\n >\n <NodeList\n sessions={railSessions}\n selectedAlias={chatAlias}\n onSelect={selectNode}\n />\n </aside>\n )}\n <div className=\"flex-1 min-w-0 max-w-full overflow-x-hidden p-4 sm:p-6\">\n {/* #209 R31 (mobile vertical rhythm — goal \"大幅提升移动端体验\",\n extending R28's Overview pattern + R30's /tasks pattern):\n this header row + the status-bar wrapper + the filter row\n below all drop mb-6 → mb-4 sm:mb-6. Three spots × 8 px =\n ~24 px scroll reclaim on /nodes before the first card.\n #209 R32: search affordance moved to top-right magnifier\n button (Vincent WeChat ref msg 563). justify-between makes\n the title cluster hug left, button hugs right. */}\n <div className=\"flex items-center gap-4 mb-4 sm:mb-6\">\n <div className=\"flex items-center gap-3 min-w-0 flex-1\">\n <h1 className=\"text-2xl font-bold text-white lg:ml-0 ml-10\">Nodes</h1>\n <span className=\"text-xs bg-green-900/30 text-green-400 px-2 py-0.5 rounded-full border border-green-800/30 shrink-0\">\n {onlineCount} online\n </span>\n <span className=\"text-xs bg-gray-900/30 text-gray-400 px-2 py-0.5 rounded-full border border-gray-800/30 shrink-0\">\n {sessions.length} total\n </span>\n </div>\n <div className=\"flex items-center gap-2 shrink-0\">\n {/* #Stage A rail toggle — visible on sm+ (where rail also\n renders). Preserves Vincent's \"看全局\" dense-table view\n as one click away (通信龙 07-31 constraint). Icon-only\n on mobile / sm; icon + text on md+. */}\n <button\n type=\"button\"\n onClick={toggleRail}\n aria-pressed={showRail}\n data-testid=\"toggle-rail\"\n title={showRail ? t('隐藏节点列表', 'Hide node list') : t('显示节点列表', 'Show node list')}\n className=\"hidden sm:inline-flex items-center gap-1 rounded-lg border border-[#26262b] bg-[#161618] px-2.5 py-1.5 text-xs text-gray-400 hover:text-gray-200 hover:border-[#3a3a40] transition-colors\"\n >\n <span aria-hidden className=\"text-sm leading-none\">{showRail ? '☷' : '☰'}</span>\n <span className=\"hidden md:inline\">{showRail ? t('密视图', 'Dense') : t('分栏', 'Split')}</span>\n </button>\n {/* node-lifecycle M2: open the create-node wizard (RFC-026 §3.1 P1). */}\n <button\n type=\"button\"\n onClick={() => setShowCreate(true)}\n aria-label=\"新建节点\"\n className=\"inline-flex items-center gap-1 rounded-lg border border-cyan-700/50 bg-cyan-900/15 px-3 py-1.5 text-sm font-medium text-cyan-300 hover:bg-cyan-900/25 transition-colors\"\n >\n <span aria-hidden className=\"text-base leading-none\">+</span>\n <span className=\"hidden sm:inline\">新建节点</span>\n </button>\n <searchCtl.Button />\n </div>\n </div>\n\n {showCreate && <CreateNodeWizard onClose={() => setShowCreate(false)} />}\n\n {/* #209 R34: shared <CollapsibleSearch> component handles row reveal,\n autofocus, Escape, and Cancel. enabled=sessions.length>0 hides\n everything until there's content to search. */}\n <searchCtl.Row />\n\n {/* #217 D6 (less is more): the status distribution bar + its\n working/idle/offline legend duplicated the header chips\n (N online / N total) and the per-card status pills right\n below. One count display per screen — the bar is gone. */}\n\n {/* Round 74: hide the filter+view chrome when there are no nodes\n anywhere — these controls have nothing to act on, and they only\n push the onboarding CTA further down. When at least one session\n exists, the chrome is back even if the current filter happens\n to hide everything (so users can clear filters). */}\n {sessions.length > 0 && (\n <div className=\"flex flex-wrap gap-3 mb-4 sm:mb-6\">\n {/* R32: the inline search input was moved to the top-right\n magnifier toggle above. The status select + List/Grid\n toggle stay here. */}\n <select\n value={filterStatus}\n onChange={e => setFilterStatus(e.target.value)}\n className=\"bg-[#161618] border border-[#26262b] rounded-lg px-3 py-2 text-base sm:text-sm text-white focus:border-blue-500/50 focus:outline-none\"\n >\n <option value=\"\">All</option>\n <option value=\"online\">Online</option>\n <option value=\"offline\">Offline</option>\n <option value=\"working\">Working</option>\n <option value=\"idle\">Idle</option>\n <option value=\"blocked\">Blocked</option>\n <option value=\"error\">Error</option>\n </select>\n {/* #492 team select — only shown once at least one node has a\n team attribute. \"__NO_TEAM__\" surfaces nodes without team,\n so operators can find nodes that never got tagged. */}\n {distinctTeams.length > 0 && (\n <select\n value={filterTeam}\n onChange={e => setFilterTeam(e.target.value)}\n aria-label={t('按 Team 过滤', 'Filter by team')}\n data-testid=\"filter-team\"\n className=\"bg-[#161618] border border-[#26262b] rounded-lg px-3 py-2 text-base sm:text-sm text-white focus:border-blue-500/50 focus:outline-none\"\n >\n <option value=\"\">{t('全部 Team', 'All teams')}</option>\n <option value=\"__NO_TEAM__\">{t('未分组', '(no team)')}</option>\n {distinctTeams.map(team => (\n <option key={team} value={team}>{team}</option>\n ))}\n </select>\n )}\n {/* Round 80: List/Grid toggle hidden on mobile — Grid uses\n grid-cols-1 below `md` and List degrades to the same single\n column, so the toggle has no visual effect under sm and only\n steals a row of vertical space. */}\n <div className=\"hidden sm:flex ml-auto rounded-lg border border-[#26262b] bg-[#161618] p-1 text-sm\">\n {(['list', 'grid'] as const).map(mode => (\n <button\n key={mode}\n type=\"button\"\n onClick={() => setViewMode(mode)}\n className={`rounded-md px-3 py-1.5 transition-colors ${\n viewMode === mode\n ? 'bg-cyan-500/10 text-cyan-300'\n : 'text-gray-500 hover:text-gray-200'\n }`}\n >\n {mode === 'list' ? 'List' : 'Grid'}\n </button>\n ))}\n </div>\n </div>\n )}\n {/* #492 tag chip row — separate row so multi-select feels distinct\n from single-select controls above. Each chip toggles inclusion;\n selected chips get cyan bg. Explicit \"AND\" separators between\n selected chips make the join semantics visible in the UI (per\n PR review: silent AND under selected-multiple → 0 results\n reads as bug; the label makes it a deliberate narrow-down). */}\n {sessions.length > 0 && distinctTags.length > 0 && (\n <div className=\"mb-4 sm:mb-6 flex flex-wrap items-center gap-1.5\" data-testid=\"filter-tags-row\">\n <span className=\"text-[11px] text-gray-500 mr-1\">{t('Tags:', 'Tags:')}</span>\n {distinctTags.map((tag, idx) => {\n const selected = filterTags.includes(tag);\n const isNotFirstSelected = selected && filterTags.slice(0, filterTags.indexOf(tag)).length > 0;\n void idx; void isNotFirstSelected;\n return (\n <button\n key={tag}\n type=\"button\"\n onClick={() => toggleTag(tag)}\n aria-pressed={selected}\n data-tag={tag}\n data-selected={selected ? 'true' : 'false'}\n className={`text-xs rounded-full px-2.5 py-1 border transition-colors ${\n selected\n ? 'bg-cyan-500/15 text-cyan-200 border-cyan-500/40'\n : 'bg-[#161618] text-gray-400 border-[#26262b] hover:text-gray-200 hover:border-[#3a3a40]'\n }`}\n >\n {tag}\n </button>\n );\n })}\n {filterTags.length >= 2 && (\n <span\n className=\"text-[10px] text-cyan-300/80 ml-1 tabular-nums\"\n data-testid=\"filter-tags-and-hint\"\n >\n {t(`= 同时具有 ${filterTags.length} 个标签`, `= AND of ${filterTags.length} tags`)}\n </span>\n )}\n {(filterTags.length > 0 || filterTeam) && (\n <button\n type=\"button\"\n onClick={() => { setFilterTags([]); setFilterTeam(''); }}\n className=\"text-[11px] text-gray-500 hover:text-gray-200 underline-offset-2 hover:underline ml-2\"\n data-testid=\"clear-attr-filters\"\n >\n {t('清除', 'Clear')}\n </button>\n )}\n </div>\n )}\n\n {loading ? (\n <div className=\"animate-pulse space-y-2\">\n {[1,2,3,4].map(i => <div key={i} className=\"h-16 bg-gray-800/20 rounded-lg\" />)}\n </div>\n ) : filtered.length === 0 ? (\n sessions.length === 0 ? (\n /* Round 73: first-run case — no agents anywhere. Use the same\n onboarding empty state as the Overview (NodesEmptyState\n includes the `npx … init` quickstart command). Previously this\n was the \"No nodes match your filters\" copy, which was wrong\n for new users who have no filters applied. */\n <NodesEmptyState />\n ) : (filterTeam || filterTags.length > 0) ? (\n /* #492: attribute-filter no-match — echo the specific filter\n conditions so the user can tell \"no nodes exist with this\n combo\" from \"I mis-typed / data isn't synced\". Distinct\n from the generic status/search \"No match\" below. Under\n AND semantics for multi-tag, this is the copy 通信龙 asked\n for: \"没有节点同时具有 A 和 B\" instead of \"no match\". */\n <EmptyState\n variant=\"nodes\"\n title={t('没有节点符合当前属性筛选', 'No nodes match the current attribute filters')}\n sub={(() => {\n const parts: string[] = [];\n if (filterTeam === '__NO_TEAM__') parts.push(t('未分组', 'no-team'));\n else if (filterTeam) parts.push(t(`Team = ${filterTeam}`, `Team = ${filterTeam}`));\n if (filterTags.length === 1) parts.push(t(`标签 ${filterTags[0]}`, `tag ${filterTags[0]}`));\n else if (filterTags.length >= 2) parts.push(t(`同时具有标签 ${filterTags.join(' 和 ')}`, `all of tags: ${filterTags.join(' AND ')}`));\n return t(`没有节点满足:${parts.join(' + ')}。清除筛选或减少标签。`, `No node satisfies: ${parts.join(' + ')}. Clear filters or drop a tag.`);\n })()}\n />\n ) : !anyAttrs && (filterStatus || search) ? (\n <EmptyState\n variant=\"nodes\"\n title={t('还没有节点被打过标签', 'No nodes have been tagged yet')}\n sub={t('先在节点详情里给几个节点分配 team / tag,然后就可以按属性筛选。', 'Assign team / tag to a few nodes first, then attribute filters will show up.')}\n />\n ) : (\n <EmptyState\n variant=\"nodes\"\n title=\"No nodes match your filters\"\n sub=\"Try clearing search or status filters, or wait for an agent to register.\"\n />\n )\n ) : viewMode === 'grid' ? (\n <div className=\"grid min-w-0 grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-4\">\n {filtered.map(s => {\n const statusKey = s.online ? s.status : 'offline';\n const progress = typeof s.progress === 'number' ? s.progress : 0;\n const unread = hasUnread(s.alias);\n\n return (\n <div\n key={s.alias}\n role=\"button\"\n tabIndex={0}\n data-node-card\n data-node-alias={s.alias}\n onClick={() => selectNode(s.alias)}\n onKeyDown={e => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); selectNode(s.alias); } }}\n className={`relative min-w-0 max-w-full overflow-hidden rounded-xl border border-[#26262b] bg-[#161618] p-4 transition-colors hover:border-cyan-500/40 cursor-pointer ${!s.online ? 'opacity-60' : ''}`}\n >\n {!s.online && (\n <div className=\"pointer-events-none absolute inset-0 flex items-center justify-center\">\n <span className=\"rotate-[-20deg] rounded-xl border border-white/10 bg-black/20 px-5 py-2 text-xl font-bold uppercase tracking-[0.35em] text-white/10\">\n Offline\n </span>\n </div>\n )}\n <div className=\"flex items-start gap-3\">\n <div className=\"relative shrink-0\">\n <span className=\"relative inline-flex shrink-0\">\n <AliasAvatar alias={s.alias} size={36} />\n {unreadCount(s.alias) > 0 && isMuted(s.alias) && (\n <span aria-label={t('有未读(已静音)', 'Unread (muted)')} className=\"absolute -top-0.5 -right-1 h-2.5 w-2.5 rounded-full bg-red-500/80 ring-2 ring-[#161618]\" />\n )}\n {unreadCount(s.alias) > 0 && !isMuted(s.alias) && (\n <span aria-label={t(`${unreadCount(s.alias)} 条未读`, `${unreadCount(s.alias)} unread`)} className=\"absolute -top-1 -right-1.5 min-w-[16px] h-4 px-1 rounded-full bg-red-500 text-white text-[9px] font-semibold leading-4 text-center ring-2 ring-[#161618]\">\n {unreadCount(s.alias) > 99 ? '99+' : unreadCount(s.alias)}\n </span>\n )}\n </span>\n {unread && <span className=\"absolute -right-1 -top-1 h-3 w-3 rounded-full border-2 border-[#161618] bg-red-500\" />}\n </div>\n <div className=\"min-w-0 flex-1\">\n <div className=\"flex items-center gap-2\">\n <span className=\"truncate text-base font-semibold text-white\">{s.alias}</span>\n <DraftMark alias={s.alias} />\n {unread && <span className=\"shrink-0 rounded-full bg-red-500/15 px-2 py-0.5 text-[10px] font-semibold uppercase tracking-wide text-red-300\">New</span>}\n <span className={`shrink-0 rounded-md border px-2 py-0.5 text-[10px] uppercase tracking-wide ${STATUS_COLORS[statusKey] || STATUS_COLORS.offline}`}>\n {statusKey}\n </span>\n </div>\n <div className=\"mt-0.5 truncate text-xs text-gray-500\">\n {(s.agent || '—')}<span className=\"text-gray-700 mx-1.5\">·</span><span title={s.server || ''}>{shortServer(s.server)}</span>\n </div>\n </div>\n <span className=\"hidden shrink-0 rounded-lg border border-cyan-500/15 bg-cyan-500/5 px-2 py-1 text-[10px] text-cyan-300/70 sm:inline\">Tap to chat</span>\n {/* RFC-027 PR2 — per-node ⋮ lifecycle menu. The button stopsPropagation\n internally so it doesn't open chat. lifecycleByAlias absent → 'active'\n default, menu renders normal stop/delete options. */}\n <NodeLifecycleMenu\n nodeId={nodeIdByAlias[s.alias] || s.node_id || s.alias}\n alias={s.alias}\n lifecycleState={lifecycleByAlias[s.alias]}\n networkId={s.network_id || null}\n onCompleted={refreshNodes}\n attrsSnapshot={attrsByAlias[s.alias]}\n />\n </div>\n\n <div className=\"mt-3 rounded-lg border border-[#1c1c1f] bg-[#0e0e10] px-3 py-2 text-xs\">\n <div className=\"flex items-center justify-between gap-3\">\n <span className=\"text-[10px] uppercase tracking-wide text-gray-600\">Current task</span>\n <span className=\"text-[10px] text-gray-600\">{timeAgo(s.last_seen_at || s.updated_at)}</span>\n </div>\n <div className={`mt-1 line-clamp-2 ${s.task ? 'text-gray-300' : 'text-gray-600 italic'}`}>\n {s.task || 'No current task'}\n </div>\n </div>\n\n {progress > 0 && progress < 100 && (\n <div className=\"mt-3 h-1.5 overflow-hidden rounded-full bg-gray-800\">\n <div className=\"h-1.5 rounded-full bg-cyan-400 transition-all\" style={{ width: `${progress}%` }} />\n </div>\n )}\n\n </div>\n );\n })}\n </div>\n ) : (\n <div className=\"space-y-1 sm:space-y-2\">\n {/* Round 94: AGENT + SERVER merged into one `agent · server`\n cell. Round mobile-command: node row itself opens chat, so\n the old Chat / Send Task action column is gone. */}\n <div className=\"hidden sm:grid sm:grid-cols-10 gap-2 px-4 py-2 text-xs text-gray-600 uppercase\">\n <div className=\"col-span-1\">Status</div>\n <div className=\"col-span-2\">Alias</div>\n <div className=\"col-span-2\">Agent · Server</div>\n <div className=\"col-span-4\">Current Task</div>\n <div className=\"col-span-1\">Updated</div>\n </div>\n {filtered.map(s => {\n const statusKey = s.online ? s.status : 'offline';\n const unread = hasUnread(s.alias);\n\n return (\n <div\n key={s.alias}\n role=\"button\"\n tabIndex={0}\n data-node-card\n data-node-alias={s.alias}\n onClick={() => selectNode(s.alias)}\n onKeyDown={e => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); selectNode(s.alias); } }}\n className={`rounded-lg border border-[#26262b] bg-[#161618] px-3 py-2 sm:px-4 sm:py-3 transition-colors hover:border-cyan-500/40 cursor-pointer ${!s.online ? 'opacity-50' : ''}`}\n >\n <div className=\"hidden sm:grid sm:grid-cols-10 gap-2 items-center\">\n <div className=\"col-span-1\">\n <span className={`text-xs px-2 py-0.5 rounded-md border ${STATUS_COLORS[statusKey] || STATUS_COLORS.offline}`}>\n {statusKey}\n </span>\n </div>\n <div className=\"col-span-2 min-w-0\">\n <div className=\"flex items-center gap-2 min-w-0\">\n <div className=\"relative shrink-0\">\n <span className=\"relative inline-flex shrink-0\">\n <AliasAvatar alias={s.alias} size={20} />\n {unreadCount(s.alias) > 0 && isMuted(s.alias) && (\n <span aria-label={t('有未读(已静音)', 'Unread (muted)')} className=\"absolute -top-1 -right-1 h-2 w-2 rounded-full bg-red-500/80\" />\n )}\n {unreadCount(s.alias) > 0 && !isMuted(s.alias) && (\n <span aria-label={t(`${unreadCount(s.alias)} 条未读`, `${unreadCount(s.alias)} unread`)} className=\"absolute -top-1.5 -right-2 min-w-[15px] h-[15px] px-1 rounded-full bg-red-500 text-white text-[9px] font-semibold leading-[15px] text-center\">\n {unreadCount(s.alias) > 99 ? '99+' : unreadCount(s.alias)}\n </span>\n )}\n </span>\n {unread && <span className=\"absolute -right-1 -top-1 h-2.5 w-2.5 rounded-full border border-[#161618] bg-red-500\" />}\n </div>\n <span className=\"truncate text-sm font-medium text-white\">{s.alias}</span>\n <DraftMark alias={s.alias} />\n {unread && <span className=\"shrink-0 rounded-full bg-red-500/15 px-1.5 py-0.5 text-[9px] font-semibold uppercase tracking-wide text-red-300\">New</span>}\n </div>\n </div>\n <div className=\"col-span-2 truncate text-xs text-gray-400\" title={s.server || ''}>\n <span className=\"truncate\">{s.agent || '--'}<span className=\"text-gray-700 mx-1.5\">·</span>{shortServer(s.server)}</span>\n </div>\n <div className=\"col-span-4 truncate text-xs text-gray-500\" title={s.task || ''}>{s.task || '--'}</div>\n <div className=\"col-span-1 flex items-center justify-between gap-2 text-xs text-gray-500\">\n <span className=\"truncate\">{timeAgo(s.last_seen_at || s.updated_at)}</span>\n {/* RFC-027 PR2 ⋮ lifecycle menu — desktop list. Defaults\n to 'active' when lifecycleByAlias absent. */}\n <NodeLifecycleMenu\n nodeId={nodeIdByAlias[s.alias] || s.node_id || s.alias}\n alias={s.alias}\n lifecycleState={lifecycleByAlias[s.alias]}\n networkId={s.network_id || null}\n onCompleted={refreshNodes}\n attrsSnapshot={attrsByAlias[s.alias]}\n />\n </div>\n </div>\n {/* R7 of #190: mobile node row was ~340px tall × ~150\n rows = the 51k page. Wins this round, in priority\n order: (1) drop the per-row \"Tap anywhere to chat\"\n hint — useful once, redundant 149 times; the cyan\n border on hover/focus still teaches it. (2) tighten\n space-y-2 → space-y-1 so the avatar/task gap is\n 4px tighter on every row. */}\n <div className=\"sm:hidden space-y-1\">\n <div className=\"flex items-center gap-2.5\">\n <div className=\"relative shrink-0\">\n <AliasAvatar alias={s.alias} size={28} />\n {unread && <span className=\"absolute -right-1 -top-1 h-3 w-3 rounded-full border-2 border-[#161618] bg-red-500\" />}\n </div>\n <div className=\"min-w-0 flex-1\">\n <div className=\"flex items-center gap-2 min-w-0\">\n <div className=\"truncate text-sm font-medium text-white\">{s.alias}</div>\n {unread && <span className=\"shrink-0 rounded-full bg-red-500/15 px-1.5 py-0.5 text-[9px] font-semibold uppercase tracking-wide text-red-300\">New</span>}\n </div>\n <div className=\"truncate text-[10px] text-gray-500\">{s.agent || '—'} · {timeAgo(s.last_seen_at || s.updated_at)}</div>\n </div>\n <span className={`shrink-0 text-xs px-2 py-0.5 rounded-md border ${STATUS_COLORS[statusKey] || STATUS_COLORS.offline}`}>\n {statusKey}\n </span>\n {/* RFC-027 PR2 ⋮ lifecycle menu — mobile list. */}\n <NodeLifecycleMenu\n nodeId={nodeIdByAlias[s.alias] || s.node_id || s.alias}\n alias={s.alias}\n lifecycleState={lifecycleByAlias[s.alias]}\n networkId={s.network_id || null}\n onCompleted={refreshNodes}\n attrsSnapshot={attrsByAlias[s.alias]}\n />\n </div>\n {s.task && <div className=\"truncate text-xs text-gray-500\">{s.task}</div>}\n </div>\n </div>\n );\n })}\n </div>\n )}\n\n {/* #Stage B: below md the chat keeps the pre-B behavior — a\n full-screen overlay push (TaskChatPanel's own fixed shell).\n On md+ the persistent right pane below renders instead; the\n two are mutually exclusive via isDesktop so only ONE\n TaskChatPanel is ever mounted (no double SSE / mark-read). */}\n {chatAlias && !isDesktop && <TaskChatPanel alias={chatAlias} onClose={closeChat} />}\n </div>\n {/* #Stage B: persistent right chat column (md+) — see ChatPane.tsx\n (ChatPopover minus the floating shell; TaskChatPanel inline body).\n Switching nodes swaps `alias` in place (no remount). */}\n {chatAlias && isDesktop && <ChatPane alias={chatAlias} onClose={closeChat} />}\n </div>\n );\n}\n","'use client';\n\nimport { useEffect, useState } from 'react';\nimport { useNetworkId } from '../lib/network-context';\nimport { DaemonOption, HostSupervisorPicker } from './HostSupervisorPicker';\n\n/**\n * Create-node wizard (node-lifecycle UI M2/PR4 — RFC-026 §3.1).\n * 6 steps now: ⓪ host (PR4 #338) ① name ② runtime ③ model ④ flags ⑤ confirm\n * → POST /api/anet/node-create with `daemon_node_id` set to the chosen host.\n *\n * PR4 (#338 main lane PR4) folds RFC-026 §9.4 host_supervisor picker in front\n * of the existing 5 steps. Three states the picker resolves internally:\n * - count=0 → onboarding (no daemon, show install command + block forward)\n * - count=1 → auto-pick + forward immediately\n * - count≥2 → user picks, then forward\n * The wizard now ALWAYS passes daemon_node_id to /api/anet/node-create (the\n * route's `resolveLocalDaemonNodeId` fallback only fires if daemon_node_id is\n * absent — kept for back-compat with non-wizard callers but no longer used\n * from this flow). Per [[feedback_doc_capability_claim_verify_code_path]] —\n * the API contract is exercised locally before any prod hub touches the path.\n */\n\n// IDs MUST match the hub validator enums (server/src/create-node-validate.ts).\n// Caught via local /mcp probe during mobile wizard build (#338 plan B):\n// pre-fix RUNTIMES had 'codex' + 'grok' but hub accepts 'codex-sdk' +\n// 'grok-build-acp'; pre-fix PERMISSION_MODES had 'auto' but hub rejects it\n// (flag_value_invalid). The wizard has been silently shipping invalid combos\n// for any non-claude-agent-sdk pick since M2 — only worked end-to-end with\n// the default claude path.\n//\n// `defaultModel` — hub's `create_node.node_spec.model` schema is\n// `z.string().min(1).max(100)`; the wizard's \"默认\" option leaves the state\n// empty, so pre-fix the POST body dropped `model` entirely and hub rejected\n// with `Invalid input: expected string, received undefined`. `defaultModel`\n// gets substituted before submit (and shown in the dropdown label so the\n// operator knows what \"默认\" will actually become).\nconst RUNTIMES: { id: string; label: string; models: string[]; defaultModel: string }[] = [\n { id: 'claude-agent-sdk', label: 'Claude Agent SDK', models: ['deepseek-v4-pro', 'MiniMax-M3', 'claude-sonnet-4-6', 'claude-opus-4-x'], defaultModel: 'claude-sonnet-4-6' },\n { id: 'codex-sdk', label: 'Codex SDK', models: ['gpt-5.5'], defaultModel: 'gpt-5.5' },\n { id: 'grok-build-acp', label: 'Grok (build-acp)', models: ['grok-build'], defaultModel: 'grok-build' },\n];\nconst PERMISSION_MODES = ['default', 'acceptEdits', 'plan', 'bypassPermissions'];\nconst STEPS = ['服务器', '名字', 'Runtime', '模型', '参数', '确认'];\n\ntype Phase = 'form' | 'creating' | 'done' | 'unconfirmed' | 'error';\n\nexport function CreateNodeWizard({\n networkId,\n onClose,\n onCreated,\n}: {\n networkId?: string;\n onClose: () => void;\n onCreated?: (result: unknown) => void;\n}) {\n const [step, setStep] = useState(0);\n const [daemonNodeId, setDaemonNodeId] = useState<string | null>(null);\n // (#338 wizard-runtime-filter) keep the full daemon row so the Runtime\n // step can disable runtimes the chosen daemon doesn't declare support\n // for. Hub-side enforcement still wins; this is UX surfacing.\n const [daemon, setDaemon] = useState<DaemonOption | null>(null);\n const [name, setName] = useState('');\n const [runtimeId, setRuntimeId] = useState(RUNTIMES[0].id);\n const [model, setModel] = useState('');\n const [permissionMode, setPermissionMode] = useState('default');\n const [maxTurns, setMaxTurns] = useState('');\n const [budget, setBudget] = useState('');\n const [timeout, setTimeout] = useState('');\n const [phase, setPhase] = useState<Phase>('form');\n const [msg, setMsg] = useState('');\n const [childUp, setChildUp] = useState(false);\n const { networkId: ctxNetworkId } = useNetworkId();\n const netId = networkId || ctxNetworkId;\n\n // Escape closes the wizard (unless a create is mid-flight, so a stray key\n // can't drop the dialog while the request is settling).\n useEffect(() => {\n const onKey = (e: KeyboardEvent) => { if (e.key === 'Escape' && phase !== 'creating') onClose(); };\n window.addEventListener('keydown', onKey);\n return () => window.removeEventListener('keydown', onKey);\n }, [onClose, phase]);\n\n // After dispatch, confirm the child actually came up by watching the node\n // list for it to register (RFC-026 progress signal — get_create_request is\n // daemon-only, so the dashboard confirms via /api/hub/status). Polls ~24s.\n useEffect(() => {\n if (phase !== 'done' || childUp) return;\n let alive = true;\n let tries = 0;\n const want = name.trim();\n const tick = async () => {\n tries += 1;\n try {\n const url = netId ? `/api/hub/status?network_id=${encodeURIComponent(netId)}` : '/api/hub/status';\n const r = await fetch(url, { cache: 'no-store' });\n const d = await r.json().catch(() => ({}));\n const list = Array.isArray(d?.sessions) ? d.sessions : Array.isArray(d) ? d : [];\n if (alive && list.some((s: { alias?: string }) => s?.alias === want)) { setChildUp(true); return; }\n } catch { /* transient — keep polling */ }\n if (alive && tries < 16) window.setTimeout(tick, 1500);\n };\n const t = window.setTimeout(tick, 1200);\n return () => { alive = false; window.clearTimeout(t); };\n }, [phase, childUp, netId, name]);\n\n const runtime = RUNTIMES.find(r => r.id === runtimeId) || RUNTIMES[0];\n const nameValid = name.trim().length > 0;\n const canNext =\n (step === 0 && Boolean(daemonNodeId)) || // step 0: must have chosen a daemon\n (step === 1 && nameValid) || // step 1: name non-empty\n (step >= 2 && step < STEPS.length); // later steps: nothing required to advance\n const busy = phase === 'creating';\n\n async function handleCreate() {\n setPhase('creating');\n setMsg('');\n const numOrUndef = (v: string) => (v.trim() === '' ? undefined : Number(v));\n // Hub's create_node.node_spec.model schema is z.string().min(1); the\n // wizard's \"默认\" option leaves state empty, so pick the runtime's\n // documented default here. This mirrors what agent-node itself defaults\n // to at boot (see agent-node cli.ts model resolution), so the \"默认\"\n // dropdown label + this fallback both point at the same model.\n const effectiveModel = model || runtime.defaultModel;\n const node_spec = {\n name: name.trim(),\n runtime: runtimeId,\n model: effectiveModel,\n flags: {\n permissionMode,\n maxTurns: numOrUndef(maxTurns),\n budget: numOrUndef(budget),\n timeout: numOrUndef(timeout),\n },\n };\n try {\n const r = await fetch('/api/anet/node-create', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n node_spec,\n ...(daemonNodeId ? { daemon_node_id: daemonNodeId } : {}),\n ...(networkId ? { network_id: networkId } : {}),\n }),\n });\n const data = await r.json().catch(() => ({}));\n if (r.ok && data?.ok) {\n setPhase('done');\n setMsg('创建请求已下发,节点正在拉起…');\n onCreated?.(data.result);\n } else if (data?.unconfirmed) {\n setPhase('unconfirmed');\n setMsg(`后端 create_node 未就绪:${data?.error || '不可用'}(测试 hub 可能未含 #299)`);\n } else {\n setPhase('error');\n setMsg(data?.error ? `创建失败:${data.error}` : '创建失败');\n }\n } catch (e) {\n setPhase('error');\n setMsg(`创建失败:${e instanceof Error ? e.message : '网络错误'}`);\n }\n }\n\n const inputCls =\n 'w-full rounded-md border border-[#26262b] bg-[#0e0e10] px-3 py-2 text-sm text-gray-200 focus:border-cyan-600 focus:outline-none';\n\n return (\n <>\n <div className=\"fixed inset-0 bg-black/50 z-40\" onClick={onClose} aria-hidden />\n <div\n role=\"dialog\"\n aria-label=\"新建节点\"\n // RFC-026 §9.4 responsive: mobile single-screen (full width minus\n // gutter, taller); desktop ~3-col-friendly width when picker is shown.\n className=\"fixed left-1/2 top-1/2 z-50 w-[min(94vw,440px)] md:w-[min(92vw,720px)] -translate-x-1/2 -translate-y-1/2 rounded-xl border border-[#26262b] bg-[#161618] shadow-2xl\"\n >\n {/* Header */}\n <div className=\"flex items-center justify-between border-b border-[#26262b] px-4 py-3\">\n <div className=\"text-sm font-semibold text-white\">新建节点</div>\n <button onClick={onClose} aria-label=\"关闭\" className=\"inline-flex h-8 w-8 items-center justify-center rounded-md text-gray-500 hover:bg-white/5 hover:text-white\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" aria-hidden>\n <path d=\"M18 6 6 18M6 6l12 12\" />\n </svg>\n </button>\n </div>\n\n {/* Step indicator */}\n <div className=\"flex items-center gap-1.5 px-4 pt-3\">\n {STEPS.map((label, i) => (\n <div key={label} className=\"flex flex-1 flex-col items-center gap-1\">\n <div className={`h-1 w-full rounded-full ${i <= step ? 'bg-cyan-500' : 'bg-[#26262b]'}`} />\n <span className={`text-[10px] ${i === step ? 'text-cyan-300' : 'text-gray-600'}`}>{label}</span>\n </div>\n ))}\n </div>\n\n {/* Body */}\n <div className=\"min-h-[180px] px-4 py-4\">\n {phase !== 'form' ? (\n <div className=\"flex h-[180px] flex-col items-center justify-center gap-3 text-center\">\n {busy && (\n <svg className=\"h-7 w-7 animate-spin text-cyan-400\" viewBox=\"0 0 24 24\" fill=\"none\" aria-hidden>\n <circle className=\"opacity-25\" cx=\"12\" cy=\"12\" r=\"10\" stroke=\"currentColor\" strokeWidth=\"4\" />\n <path className=\"opacity-90\" fill=\"currentColor\" d=\"M4 12a8 8 0 018-8v4a4 4 0 00-4 4H4z\" />\n </svg>\n )}\n <div className={`text-sm ${phase === 'done' ? 'text-green-300' : phase === 'error' ? 'text-red-300' : phase === 'unconfirmed' ? 'text-amber-300' : 'text-gray-300'}`}>\n {busy ? '正在创建…' : phase === 'done' && childUp ? `✓ ${name.trim()} 已上线` : msg}\n </div>\n {/* Real progress: poll the node list for the child to register\n (派单→fork→注册→✓). */}\n {phase === 'done' && (childUp ? (\n <p className=\"text-[11px] text-green-500/80\">节点已注册,已出现在节点列表。</p>\n ) : (\n <p className=\"inline-flex items-center gap-1.5 text-[11px] text-gray-500\">\n <svg className=\"h-3 w-3 animate-spin\" viewBox=\"0 0 24 24\" fill=\"none\" aria-hidden>\n <circle className=\"opacity-25\" cx=\"12\" cy=\"12\" r=\"10\" stroke=\"currentColor\" strokeWidth=\"4\" />\n <path className=\"opacity-90\" fill=\"currentColor\" d=\"M4 12a8 8 0 018-8v4a4 4 0 00-4 4H4z\" />\n </svg>\n 正在监测 {name.trim()} 注册…(最长 ~24s)\n </p>\n ))}\n </div>\n ) : (\n <>\n {step === 0 && (\n <div className=\"space-y-2\">\n <span className=\"text-xs text-gray-400\">在哪台机器上创建</span>\n <HostSupervisorPicker\n networkId={netId || undefined}\n value={daemonNodeId}\n onChange={(id, d) => {\n setDaemonNodeId(id);\n setDaemon(d);\n // (#338 wizard-runtime-filter) If the current runtime\n // pick isn't supported by the new daemon, reset so\n // the user is forced to re-pick on step 2. Otherwise\n // they could land on step 5 (确认) with an\n // already-invalid combo that only hub rejection\n // surfaces.\n const supported = d?.runtimes_supported;\n if (supported && supported.length > 0 && !supported.includes(runtimeId)) {\n setRuntimeId(supported[0]);\n setModel('');\n }\n }}\n />\n {!daemonNodeId && (\n <p className=\"text-[11px] text-gray-600\">\n 没选服务器之前无法继续;如果列表是空的,按提示在目标机器上跑 <code className=\"rounded bg-black/40 px-1 py-0.5\">anet daemon up &lt;name&gt;</code>。\n </p>\n )}\n </div>\n )}\n {step === 1 && (\n <label className=\"block space-y-1.5\">\n <span className=\"text-xs text-gray-400\">节点名字</span>\n <input autoFocus value={name} onChange={e => setName(e.target.value)} placeholder=\"例如 my-agent-1\" className={inputCls} />\n {!nameValid && <span className=\"text-[11px] text-gray-600\">名字不能为空</span>}\n </label>\n )}\n {step === 2 && (\n <div className=\"space-y-2\">\n <span className=\"text-xs text-gray-400\">\n Runtime{daemon ? `(${daemon.alias} 支持)` : ''}\n </span>\n {RUNTIMES.map(r => {\n // (#338 wizard-runtime-filter) Permissive when the\n // daemon didn't publish runtimes_supported at all\n // (pre-PR3 daemons OR daemons not yet upgraded) — hub\n // still validates. Restrictive only when the daemon\n // explicitly told us its supported set.\n const supported = daemon?.runtimes_supported;\n const disabled = Array.isArray(supported) && supported.length > 0 && !supported.includes(r.id);\n const selected = runtimeId === r.id;\n return (\n <button\n key={r.id}\n type=\"button\"\n disabled={disabled}\n onClick={() => { if (!disabled) { setRuntimeId(r.id); setModel(''); } }}\n title={disabled ? `${daemon?.alias || '该 daemon'} 未声明支持此 runtime` : undefined}\n className={`flex w-full items-center justify-between rounded-md border px-3 py-2 text-sm transition-colors ${\n disabled\n ? 'border-[#1c1c1f] bg-[#0a0a0c] text-gray-600 cursor-not-allowed'\n : selected\n ? 'border-cyan-600 bg-cyan-900/15 text-cyan-200'\n : 'border-[#26262b] bg-[#0e0e10] text-gray-300 hover:border-[#3a3a41]'\n }`}\n >\n <span>\n {r.label}\n {disabled && <span className=\"ml-2 text-[10px] text-gray-700\">该 daemon 不支持</span>}\n </span>\n {selected && !disabled && (\n <svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden>\n <path d=\"M20 6 9 17l-5-5\" />\n </svg>\n )}\n </button>\n );\n })}\n </div>\n )}\n {step === 3 && (\n <label className=\"block space-y-1.5\">\n <span className=\"text-xs text-gray-400\">模型({runtime.label})</span>\n <select value={model} onChange={e => setModel(e.target.value)} className={inputCls}>\n <option value=\"\">默认({runtime.defaultModel})</option>\n {runtime.models.map(m => <option key={m} value={m}>{m}</option>)}\n </select>\n </label>\n )}\n {step === 4 && (\n <div className=\"space-y-3\">\n <label className=\"block space-y-1.5\">\n <span className=\"text-xs text-gray-400\">permissionMode</span>\n <select value={permissionMode} onChange={e => setPermissionMode(e.target.value)} className={inputCls}>\n {PERMISSION_MODES.map(m => <option key={m} value={m}>{m}</option>)}\n </select>\n </label>\n <div className=\"grid grid-cols-3 gap-2\">\n <label className=\"space-y-1\"><span className=\"text-[11px] text-gray-500\">maxTurns</span><input inputMode=\"numeric\" value={maxTurns} onChange={e => setMaxTurns(e.target.value)} className={inputCls} /></label>\n <label className=\"space-y-1\"><span className=\"text-[11px] text-gray-500\">budget</span><input inputMode=\"numeric\" value={budget} onChange={e => setBudget(e.target.value)} className={inputCls} /></label>\n <label className=\"space-y-1\"><span className=\"text-[11px] text-gray-500\">timeout</span><input inputMode=\"numeric\" value={timeout} onChange={e => setTimeout(e.target.value)} className={inputCls} /></label>\n </div>\n </div>\n )}\n {step === 5 && (\n <div className=\"space-y-2 text-sm\">\n <div className=\"rounded-md border border-[#26262b] bg-[#0e0e10] divide-y divide-[#1c1c1f]\">\n {[\n ['服务器', daemonNodeId ? `${daemonNodeId.slice(0, 24)}…` : '—'],\n ['名字', name.trim() || '—'],\n ['Runtime', runtime.label],\n ['模型', model || `默认(${runtime.defaultModel})`],\n ['permissionMode', permissionMode],\n ['maxTurns / budget / timeout', `${maxTurns || '—'} / ${budget || '—'} / ${timeout || '—'}`],\n ].map(([k, v]) => (\n <div key={k} className=\"flex items-start justify-between gap-3 px-3 py-2\">\n <span className=\"shrink-0 text-gray-500 text-xs\">{k}</span>\n <span className=\"text-right text-gray-200 text-xs break-all\">{v}</span>\n </div>\n ))}\n </div>\n </div>\n )}\n </>\n )}\n </div>\n\n {/* Footer nav */}\n {phase === 'form' ? (\n <div className=\"flex items-center justify-between border-t border-[#26262b] px-4 py-3\">\n <button type=\"button\" onClick={() => (step === 0 ? onClose() : setStep(step - 1))} className=\"rounded-md px-3 py-1.5 text-sm text-gray-400 hover:text-gray-200\">\n {step === 0 ? '取消' : '上一步'}\n </button>\n {step < STEPS.length - 1 ? (\n <button type=\"button\" disabled={!canNext} onClick={() => setStep(step + 1)} className={`rounded-md px-4 py-1.5 text-sm font-medium ${canNext ? 'bg-cyan-600 text-white hover:bg-cyan-500' : 'bg-[#1c1c1f] text-gray-600 cursor-not-allowed'}`}>\n 下一步\n </button>\n ) : (\n <button type=\"button\" onClick={handleCreate} className=\"rounded-md bg-green-600 px-4 py-1.5 text-sm font-medium text-white hover:bg-green-500\">\n 创建节点\n </button>\n )}\n </div>\n ) : (\n <div className=\"flex items-center justify-end border-t border-[#26262b] px-4 py-3\">\n <button type=\"button\" onClick={onClose} className=\"rounded-md bg-[#1c1c1f] px-4 py-1.5 text-sm text-gray-200 hover:bg-[#26262b]\">\n {phase === 'done' ? '完成' : '关闭'}\n </button>\n {(phase === 'error' || phase === 'unconfirmed') && (\n <button type=\"button\" onClick={() => setPhase('form')} className=\"ml-2 rounded-md bg-cyan-600 px-4 py-1.5 text-sm text-white hover:bg-cyan-500\">返回修改</button>\n )}\n </div>\n )}\n </div>\n </>\n );\n}\n","'use client';\n\nimport { useEffect, useState } from 'react';\n\n/**\n * PR4 #338 — host_supervisor daemon picker (RFC-026 §9.4 locked mockup).\n *\n * Three states (the only branching the wizard ever sees):\n *\n * count=0 → onboarding: explain what a daemon is + give the install command.\n * No daemon = nothing to dispatch to; create flow is blocked here\n * until the user runs `anet daemon init <name>` somewhere.\n *\n * count=1 → auto-pick: just show \"using <alias>\" + a quiet `换一个 →` link\n * (which switches to the picker view if the user really wants).\n *\n * count≥2 → picker grid: cards for each daemon w/ runtimes + alert chip,\n * click selects. Desktop = up to 3 columns; mobile = single column.\n *\n * Data shape mirrors `/api/anet/host-supervisors`, which in turn mirrors the\n * hub's GET /api/host-supervisors (#338 PR2 — needs commhub-server@0.9.0-preview.8+).\n * On `unconfirmed` (older hub), we degrade honestly to an upgrade hint — never\n * show a fake empty list. Per [[feedback_doc_capability_claim_verify_code_path]].\n */\n\nexport interface DaemonOption {\n // Hub canonical key is `daemon_node_id` (PR2 v2 §9.2 contract). We keep the\n // same name end-to-end so the value the wizard passes back to create_node\n // as `daemon_node_id` doesn't need a rename layer.\n daemon_node_id: string;\n alias: string;\n hostname?: string | null;\n online?: boolean;\n last_seen_at?: string | null;\n runtimes_supported?: string[];\n host_telemetry?: {\n alert_level?: 'green' | 'yellow' | 'red' | 'gray';\n cpu_cores?: number | null;\n mem_gb?: number | null;\n ip_internal?: string | null;\n };\n}\n\ninterface PickResponse {\n ok: boolean;\n unconfirmed?: boolean;\n error?: string;\n count: number;\n daemons: DaemonOption[];\n selected?: string | null;\n}\n\ntype LoadState = 'loading' | 'ready' | 'error' | 'unconfirmed';\n\nexport function HostSupervisorPicker({\n networkId,\n value,\n onChange,\n}: {\n networkId?: string | null;\n value: string | null;\n // (#338 wizard-runtime-filter) passes the full daemon row alongside the\n // id so the wizard can filter the Runtime step by daemon.runtimes_supported\n // — disabling combos the hub would reject anyway and surfacing why upfront.\n onChange: (nodeId: string | null, daemon: DaemonOption | null) => void;\n}) {\n const [state, setState] = useState<LoadState>('loading');\n const [daemons, setDaemons] = useState<DaemonOption[]>([]);\n const [errMsg, setErrMsg] = useState('');\n const [forcePicker, setForcePicker] = useState(false);\n\n useEffect(() => {\n let alive = true;\n setState('loading');\n setErrMsg('');\n const url = networkId\n ? `/api/anet/host-supervisors?network_id=${encodeURIComponent(networkId)}`\n : '/api/anet/host-supervisors';\n fetch(url, { cache: 'no-store' })\n .then(r => r.json().then(d => ({ status: r.status, body: d as PickResponse })))\n .then(({ status, body }) => {\n if (!alive) return;\n if (status === 501 || body?.unconfirmed) {\n setState('unconfirmed');\n setErrMsg(body?.error || 'hub /api/host-supervisors unavailable — upgrade to >=0.9.0-preview.8');\n setDaemons([]);\n return;\n }\n if (!body?.ok) {\n setState('error');\n setErrMsg(body?.error || `hub ${status}`);\n setDaemons([]);\n return;\n }\n const list = Array.isArray(body.daemons) ? body.daemons : [];\n setDaemons(list);\n setState('ready');\n // count=1 auto-pick: preselect the only daemon. count≥2 leaves the\n // selection to the user (parent value stays null until click).\n if (list.length === 1 && !value) onChange(list[0].daemon_node_id, list[0]);\n })\n .catch(e => {\n if (!alive) return;\n setState('error');\n setErrMsg(e instanceof Error ? e.message : String(e));\n setDaemons([]);\n });\n return () => { alive = false; };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [networkId]);\n\n // ───── render branches ──────────────────────────────────────────────\n\n if (state === 'loading') {\n return (\n <div className=\"flex items-center gap-2 rounded-md border border-[#26262b] bg-[#0e0e10] px-3 py-3 text-xs text-gray-500\">\n <svg className=\"h-3.5 w-3.5 animate-spin\" viewBox=\"0 0 24 24\" fill=\"none\" aria-hidden>\n <circle className=\"opacity-25\" cx=\"12\" cy=\"12\" r=\"10\" stroke=\"currentColor\" strokeWidth=\"4\" />\n <path className=\"opacity-90\" fill=\"currentColor\" d=\"M4 12a8 8 0 018-8v4a4 4 0 00-4 4H4z\" />\n </svg>\n 正在查询可用的 host_supervisor 节点…\n </div>\n );\n }\n\n if (state === 'unconfirmed') {\n return (\n <div className=\"rounded-md border border-amber-700/40 bg-amber-900/10 px-3 py-3 text-xs text-amber-200\">\n <div className=\"font-semibold mb-1\">hub 暂未升级</div>\n <div className=\"text-amber-200/80\">{errMsg}</div>\n <div className=\"mt-1 text-[11px] text-amber-200/60\">\n 升级到 <code className=\"rounded bg-black/40 px-1 py-0.5\">@sleep2agi/commhub-server@0.9.0-preview.8</code> 后选服务器功能才会出现。\n </div>\n </div>\n );\n }\n\n if (state === 'error') {\n return (\n <div className=\"rounded-md border border-red-700/40 bg-red-900/10 px-3 py-3 text-xs text-red-200\">\n 查询 host_supervisor 节点失败:{errMsg}\n </div>\n );\n }\n\n // count=0 — onboarding\n if (daemons.length === 0) {\n return (\n <div className=\"rounded-md border border-[#26262b] bg-[#0e0e10] px-3 py-4 text-xs text-gray-300\">\n <div className=\"text-sm font-semibold text-gray-200\">还没有可用的 host_supervisor 节点</div>\n <p className=\"mt-1 text-gray-500\">\n 要在某台机器上创建节点,先在那台机器上跑一次 daemon 初始化命令:\n </p>\n <pre className=\"mt-2 overflow-x-auto rounded bg-black/40 p-2 text-[11px] text-cyan-300\">{`# 任选一台目标机器(你的笔记本 / 一台服务器都行)\nanet daemon up my-daemon`}</pre>\n <p className=\"mt-2 text-gray-500\">\n 注册成功后这里会自动出现,无需刷新。\n </p>\n </div>\n );\n }\n\n // count=1 — auto-pick (collapsed). User can opt into picker via \"换一个 →\".\n if (daemons.length === 1 && !forcePicker) {\n const d = daemons[0];\n return (\n <div className=\"rounded-md border border-cyan-700/40 bg-cyan-900/10 px-3 py-3 text-xs text-cyan-100\">\n <div className=\"flex items-center justify-between gap-2\">\n <div>\n <span className=\"text-cyan-400/80\">将在</span>{' '}\n <span className=\"font-semibold\">{d.alias}</span>\n <span className=\"text-cyan-300/60\"> ({d.hostname || '—'}) </span>\n <span className=\"text-cyan-400/80\">上创建</span>\n </div>\n {/* Single-daemon networks can still let the user enter picker view; */}\n {/* useful if they want to see telemetry before committing. */}\n <button\n type=\"button\"\n onClick={() => setForcePicker(true)}\n className=\"text-[11px] text-cyan-400 hover:text-cyan-200 underline-offset-2 hover:underline\"\n >\n 详情 →\n </button>\n </div>\n <RuntimeList runtimes={d.runtimes_supported} className=\"mt-1\" />\n </div>\n );\n }\n\n // count≥2 (or forcePicker=true) — grid picker. Desktop up to 3 columns,\n // mobile = single column. Locked per RFC-026 §9.4 mockup.\n return (\n <div className=\"space-y-2\">\n <div className=\"flex items-center justify-between text-xs text-gray-400\">\n <span>选择一台 host_supervisor 节点({daemons.length} 台在线)</span>\n {forcePicker && daemons.length === 1 && (\n <button\n type=\"button\"\n onClick={() => setForcePicker(false)}\n className=\"text-[11px] text-gray-500 hover:text-gray-300\"\n >\n ← 折叠\n </button>\n )}\n </div>\n <div className=\"grid grid-cols-1 gap-2 md:grid-cols-2 lg:grid-cols-3\">\n {daemons.map(d => (\n <DaemonCard\n key={d.daemon_node_id}\n daemon={d}\n selected={d.daemon_node_id === value}\n onClick={() => onChange(d.daemon_node_id, d)}\n />\n ))}\n </div>\n </div>\n );\n}\n\n// ───── subcomponents ──────────────────────────────────────────────────\n\nfunction DaemonCard({\n daemon,\n selected,\n onClick,\n}: {\n daemon: DaemonOption;\n selected: boolean;\n onClick: () => void;\n}) {\n const alert = daemon.host_telemetry?.alert_level || 'gray';\n return (\n <button\n type=\"button\"\n onClick={onClick}\n aria-pressed={selected}\n className={`flex w-full flex-col gap-1.5 rounded-md border px-3 py-2.5 text-left text-xs transition-colors ${\n selected\n ? 'border-cyan-600 bg-cyan-900/15 text-cyan-100'\n : 'border-[#26262b] bg-[#0e0e10] text-gray-300 hover:border-[#3a3a41]'\n }`}\n >\n <div className=\"flex items-center justify-between gap-2\">\n <span className=\"truncate font-semibold\">{daemon.alias}</span>\n <AlertChip level={alert} />\n </div>\n <div className=\"truncate text-[11px] text-gray-500\">{daemon.hostname || '—'}</div>\n <RuntimeList runtimes={daemon.runtimes_supported} />\n {(daemon.host_telemetry?.cpu_cores != null || daemon.host_telemetry?.mem_gb != null) && (\n <div className=\"flex gap-3 text-[10px] text-gray-500\">\n {daemon.host_telemetry?.cpu_cores != null && <span>{daemon.host_telemetry.cpu_cores} 核</span>}\n {daemon.host_telemetry?.mem_gb != null && <span>{daemon.host_telemetry.mem_gb} GB</span>}\n </div>\n )}\n </button>\n );\n}\n\nfunction RuntimeList({ runtimes, className = '' }: { runtimes?: string[]; className?: string }) {\n if (!runtimes || runtimes.length === 0) {\n return <div className={`text-[10px] text-gray-600 ${className}`}>runtimes_supported: —</div>;\n }\n return (\n <div className={`flex flex-wrap gap-1 ${className}`}>\n {runtimes.map(r => (\n <span key={r} className=\"rounded bg-[#1c1c1f] px-1.5 py-0.5 text-[10px] text-gray-400\">{r}</span>\n ))}\n </div>\n );\n}\n\nfunction AlertChip({ level }: { level: 'green' | 'yellow' | 'red' | 'gray' }) {\n const cls = {\n green: 'bg-green-600/20 text-green-300 border-green-700/40',\n yellow: 'bg-amber-600/20 text-amber-300 border-amber-700/40',\n red: 'bg-red-600/20 text-red-300 border-red-700/40',\n gray: 'bg-gray-600/20 text-gray-400 border-gray-700/40',\n }[level];\n const label = { green: '正常', yellow: '注意', red: '警报', gray: '离线' }[level];\n return (\n <span className={`rounded border px-1.5 py-0.5 text-[10px] ${cls}`}>{label}</span>\n );\n}\n","'use client';\n\nimport { AliasAvatar } from './AliasAvatar';\nimport { useChatUnread } from '../lib/chat-unread';\nimport { useHasDraft } from '../lib/chat-drafts';\nimport type { Session } from './types';\nimport { t } from '../lib/ui-lang';\n\n// #Stage A (dashboard 3-col): persistent narrow node list rail —\n// WeChat-style entries (avatar + alias + activity preview + unread badge)\n// that stay visible while user reads/interacts with the table on the\n// right OR opens a chat popover. The point is not \"look like Feishu\";\n// the point is \"node list and chat panel are visible at the same time,\n// switching between nodes takes zero operations\" (通信龙, 07-31).\n//\n// Test-hook contract:\n// - Rail entries carry `data-node-list-item` + `data-node-list-alias`.\n// Deliberately distinct from the table's `data-node-card` /\n// `data-node-alias` so #492's exact-count assertions on the table\n// view stay valid (rail and table would otherwise both match and\n// `toHaveCount(1)` would break).\n// - Selected entry gets `data-selected=\"true\"` for keyboard/screen-\n// reader affordance and future tests.\n\ntype SessionRow = Session & { online: boolean };\n\nexport interface NodeListProps {\n /** The already-filtered list from NodesPage — rail mirrors what the\n * table shows, not a second filter chain. Sharing keeps the two\n * views from disagreeing while filter chips are being toggled. */\n sessions: SessionRow[];\n /** Currently-selected alias (drives visual highlight). Passing null\n * means nothing selected — the rail still lists everything. */\n selectedAlias: string | null;\n /** Called when the user clicks an entry. Parent decides what to do\n * with it (open ChatPopover, navigate, etc). Stage A keeps the\n * existing ChatPopover behavior; Stage B may swap this for URL\n * navigation. */\n onSelect: (alias: string) => void;\n}\n\nfunction LastLine({ alias, session }: { alias: string; session: SessionRow }) {\n const draft = useHasDraft(alias);\n if (draft) {\n return (\n <span className=\"text-[11px] text-red-400/90 truncate\" aria-label={t('有未发送草稿', 'Unsent draft')}>\n {t('[草稿]', '[draft]')} {session.task ? session.task.slice(0, 40) : ''}\n </span>\n );\n }\n if (session.task) {\n return <span className=\"text-[11px] text-gray-500 truncate\">{session.task}</span>;\n }\n if (!session.online) {\n return <span className=\"text-[11px] text-gray-600 italic\">{t('离线', 'offline')}</span>;\n }\n return <span className=\"text-[11px] text-gray-600\">{t('空闲', 'idle')}</span>;\n}\n\nexport function NodeList({ sessions, selectedAlias, onSelect }: NodeListProps) {\n const { unreadCount } = useChatUnread();\n\n return (\n <div\n data-node-list-rail\n data-node-list-count={sessions.length}\n className=\"flex flex-col w-full overflow-hidden bg-[#111113] border-r border-[#26262b]\"\n aria-label={t('节点列表', 'Node list')}\n >\n <div className=\"px-3 py-2 text-[11px] text-gray-500 tracking-wide uppercase border-b border-[#1e1e22] shrink-0\">\n {t(`节点 ${sessions.length}`, `Nodes · ${sessions.length}`)}\n </div>\n <div className=\"flex-1 min-h-0 overflow-y-auto\">\n {sessions.length === 0 ? (\n <div className=\"p-4 text-[11px] text-gray-600\">\n {t('列表为空 —— 右侧的筛选控件或空态说明会告诉你原因。', 'Rail is empty — the filter controls or empty state on the right explain why.')}\n </div>\n ) : (\n sessions.map(s => {\n const selected = s.alias === selectedAlias;\n const unread = unreadCount(s.alias);\n return (\n <button\n key={s.alias}\n type=\"button\"\n data-node-list-item\n data-node-list-alias={s.alias}\n data-selected={selected ? 'true' : 'false'}\n onClick={() => onSelect(s.alias)}\n className={`w-full flex items-center gap-2.5 px-3 py-2.5 text-left transition-colors border-b border-[#1a1a1d] ${\n selected ? 'bg-cyan-500/8' : 'hover:bg-[#161618]'\n }`}\n >\n <div className=\"relative shrink-0\">\n <AliasAvatar alias={s.alias} size={32} />\n {s.online && (\n <span\n aria-hidden\n className=\"absolute -bottom-0.5 -right-0.5 w-2.5 h-2.5 rounded-full bg-green-400 ring-2 ring-[#111113]\"\n />\n )}\n </div>\n <div className=\"flex-1 min-w-0\">\n <div className=\"flex items-center justify-between gap-2\">\n <span className={`text-[13px] truncate ${selected ? 'text-cyan-200 font-medium' : 'text-gray-200'}`}>\n {s.alias}\n </span>\n {unread > 0 && (\n <span\n aria-label={t(`${unread} 条未读`, `${unread} unread`)}\n className=\"shrink-0 min-w-[16px] h-4 px-1 rounded-full bg-red-500 text-white text-[9px] font-semibold leading-4 text-center\"\n >\n {unread > 99 ? '99+' : unread}\n </span>\n )}\n </div>\n <div className=\"mt-0.5 flex items-center gap-1.5\">\n <LastLine alias={s.alias} session={s} />\n </div>\n </div>\n </button>\n );\n })\n )}\n </div>\n </div>\n );\n}\n","'use client';\n\nimport { AliasAvatar } from './AliasAvatar';\nimport { TaskChatPanel } from './TaskChatPanel';\nimport { t } from '../lib/ui-lang';\n\n// #Stage B (dashboard 3-col): the persistent right chat column on /nodes.\n// This is ChatPopover with the floating shell stripped: no drag, no resize,\n// no viewport-clamped positioning — just a column header + TaskChatPanel's\n// `inline` body (the same body ChatPopover embeds), so send / SSE / history\n// / drafts behave identically in popover, overlay, and pane.\n//\n// Test-hook contract: `data-testid=\"chat-pane\"` + `data-chat-alias` are the\n// Stage B assertions' anchors. Deliberately does NOT render any\n// [data-node-card] / [data-node-alias] — those belong exclusively to the\n// table in NodesView (#492 exact-count contract).\nexport interface ChatPaneProps {\n /** Node alias to chat with. Changing it swaps the conversation in place. */\n alias: string;\n /** Close the pane (unselect + URL back to /nodes — parent owns both). */\n onClose: () => void;\n}\n\nexport function ChatPane({ alias, onClose }: ChatPaneProps) {\n return (\n <aside\n data-testid=\"chat-pane\"\n data-chat-alias={alias}\n className=\"hidden md:flex md:flex-col w-[400px] xl:w-[480px] shrink-0 h-screen sticky top-0 border-l border-[#26262b] bg-[var(--bg)]\"\n >\n <div className=\"flex items-center justify-between gap-2 px-3 py-2.5 border-b border-[#26262b] bg-[#111113] shrink-0\">\n <div className=\"flex items-center gap-2 min-w-0\">\n <AliasAvatar alias={alias} size={26} />\n <span className=\"truncate text-sm font-semibold text-white\">{alias}</span>\n </div>\n <button\n type=\"button\"\n onClick={onClose}\n aria-label={t('关闭会话', 'Close chat')}\n data-testid=\"chat-pane-close\"\n className=\"inline-flex h-8 w-8 items-center justify-center rounded-lg text-gray-500 hover:text-gray-200 hover:bg-[#1c1c1f] transition-colors\"\n >\n <svg className=\"w-4 h-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={2}>\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n </button>\n </div>\n <div className=\"flex-1 min-h-0\">\n <TaskChatPanel alias={alias} onClose={onClose} inline />\n </div>\n </aside>\n );\n}\n"],"names":["HostSupervisorPicker","networkId","value","onChange","state","setState","daemons","setDaemons","errMsg","setErrMsg","forcePicker","setForcePicker","alive","url","encodeURIComponent","fetch","cache","then","r","json","d","status","body","unconfirmed","error","ok","list","Array","isArray","length","daemon_node_id","catch","e","Error","message","String","className","viewBox","fill","cx","cy","stroke","strokeWidth","alias","hostname","type","onClick","RuntimeList","runtimes","runtimes_supported","map","DaemonCard","daemon","selected","alert","host_telemetry","alert_level","AlertChip","level","cpu_cores","mem_gb","cls","green","yellow","red","gray","label"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../../dash-stageb-wt/app/nodes/NodesView.tsx","../../../../../dash-stageb-wt/app/components/CreateNodeWizard.tsx","../../../../../dash-stageb-wt/app/components/HostSupervisorPicker.tsx","../../../../../dash-stageb-wt/app/components/NodeList.tsx","../../../../../dash-stageb-wt/app/components/ChatPane.tsx"],"sourcesContent":["'use client';\n\nimport { useState, useRef, useEffect, useSyncExternalStore } from 'react';\nimport { timeAgo } from '../components/utils';\nimport { useSessions, useHealth, useNodeLifecycle } from '../lib/hooks';\nimport { useSWRConfig } from 'swr';\nimport { TaskChatPanel } from '../components/TaskChatPanel';\nimport { CreateNodeWizard } from '../components/CreateNodeWizard';\nimport { NodeLifecycleMenu } from '../components/NodeLifecycleMenu';\nimport { EmptyState, NodesEmptyState } from '../components/EmptyState';\nimport { AliasAvatar } from '../components/AliasAvatar';\nimport { useHasDraft } from '../lib/chat-drafts';\nimport { isMuted, useMuteVersion } from '../lib/chat-mute';\nimport { isPinned, usePinVersion } from '../lib/chat-pin';\nimport { pinyinMatch, usePinyinReady } from '../lib/pinyin-match';\nimport { useCollapsibleSearch } from '../components/CollapsibleSearch';\nimport { NodeList } from '../components/NodeList';\nimport { ChatPane } from '../components/ChatPane';\nimport type { Session } from '../components/types';\nimport { SESSION_STATUS_CHIP_CLASS as STATUS_COLORS } from '../lib/status';\nimport { useChatUnread } from '../lib/chat-unread';\nimport { t } from '../lib/ui-lang';\n\n/** Round 81: shorten long server hostnames (Alibaba `iZ…oyZ` style)\n * for table display. Returns the original string unchanged when ≤12\n * chars. Full value should stay in `title=` for hover + screen-readers. */\nfunction shortServer(server: string | null | undefined): string {\n if (!server) return '—';\n return server.length > 12 ? `${server.slice(0, 8)}…` : server;\n}\n\ntype ViewMode = 'list' | 'grid';\ntype SessionRow = Session & { online: boolean };\n\n// #Stage B (dashboard 3-col): /nodes/[alias] URL routing. Next's app-router\n// param may arrive still percent-encoded (aliases are often Chinese); decode\n// exactly once, defensively — if the segment was already decoded and contains\n// a literal '%' that doesn't form a valid escape, decodeURIComponent throws\n// and we keep the raw value instead of double-decoding.\nexport function decodeAliasSegment(seg: string): string {\n try { return decodeURIComponent(seg); } catch { return seg; }\n}\n\n// #Stage B: < 768px (Tailwind md) falls back to the single-column layout —\n// chat opens as the existing full-screen overlay push instead of a third\n// column. useSyncExternalStore so SSR (no matchMedia) renders the desktop\n// shape and hydration corrects without a React mismatch.\nconst MD_QUERY = '(min-width: 768px)';\nfunction subscribeMd(cb: () => void) {\n const mql = window.matchMedia(MD_QUERY);\n mql.addEventListener('change', cb);\n return () => mql.removeEventListener('change', cb);\n}\nfunction useIsDesktop(): boolean {\n return useSyncExternalStore(subscribeMd, () => window.matchMedia(MD_QUERY).matches, () => true);\n}\n\n/** R13 (草稿闭环还债): same [草稿] mark as AgentCard/CommandCenter tabs. */\nfunction DraftMark({ alias }: { alias: string }) {\n const hasDraft = useHasDraft(alias);\n if (!hasDraft) return null;\n return <span className=\"shrink-0 text-[9px] text-red-400/90\" aria-label={t('有未发送草稿', 'Unsent draft')}>{t('[草稿]', '[draft]')}</span>;\n}\n\nexport function NodesView({ initialAlias = null }: { initialAlias?: string | null }) {\n const { sessions, isLoading: loading } = useSessions();\n const { health } = useHealth();\n const { lifecycleByAlias, nodeIdByAlias, attrsByAlias } = useNodeLifecycle();\n const { hasUnread, unreadCount, lastActivityAt } = useChatUnread();\n const { mutate } = useSWRConfig();\n // RFC-027 PR2 — after a stop/delete/restart dispatch lands, refresh\n // /api/hub/nodes (lifecycle_state) AND /api/hub/status (sessions).\n // Both feed the menu's state-aware items; otherwise menu stays\n // stale until next 5s SWR poll.\n const refreshNodes = () => {\n mutate((k: unknown) => typeof k === 'string' && (k.startsWith('/api/hub/nodes') || k.startsWith('/api/hub/status')));\n };\n const sseMap = health?.sse_sessions || {};\n // SSE keys are `network_id:alias` since server v0.7+. Look up with the\n // composite key first, fall back to alias-only for legacy hubs.\n const sseFor = (s: { alias: string; network_id?: string }) =>\n (s.network_id ? sseMap[`${s.network_id}:${s.alias}`] : undefined) ?? sseMap[s.alias];\n const [filterStatus, setFilterStatus] = useState('');\n // #492 goal-3 step 2: filter by team (single-select, '' = no filter,\n // '__NO_TEAM__' = \"nodes without any team assignment\"). team match is\n // strict equality against attrsByAlias[alias].team ?? null — nodes\n // WITHOUT a team never leak into \"team X\" results (per PR review:\n // fixture must have mixed team values and assert exact aliases, not\n // just count).\n const [filterTeam, setFilterTeam] = useState('');\n // #492 goal-3 step 2: tag filter is multi-select with AND semantics —\n // \"show nodes that have ALL of these tags\". This is a product\n // decision (per PR review: OR would be the naive user default; AND\n // is intentional so operators can narrow down instead of widen out).\n // Rendered chip row shows explicit \"AND\" separators + empty-state\n // echoes the filter conditions so a zero-result AND intersection\n // never looks like a data-sync bug.\n const [filterTags, setFilterTags] = useState<string[]>([]);\n const [search, setSearch] = useState('');\n const toggleTag = (t: string) => setFilterTags(cur => cur.includes(t) ? cur.filter(x => x !== t) : [...cur, t]);\n // Distinct teams/tags across visible sessions — drives the select\n // options and chip row, and lets us distinguish \"cold-start no attrs\"\n // from \"no match\" in the empty state.\n const distinctTeams = Array.from(new Set(sessions.map(s => attrsByAlias[s.alias]?.team).filter((t): t is string => !!t && t.length > 0))).sort();\n const distinctTags = Array.from(new Set(sessions.flatMap(s => attrsByAlias[s.alias]?.tags ?? []).filter(t => t && t.length > 0))).sort();\n const anyAttrs = distinctTeams.length > 0 || distinctTags.length > 0;\n const pinyinReady = usePinyinReady();\n const muteVersion = useMuteVersion();\n void muteVersion; // re-render on mute toggles (isMuted used in map callbacks)\n const pinVersion = usePinVersion();\n void pinVersion;\n void pinyinReady; // R25: re-filter once the lazy pinyin dict lands\n const [viewMode, setViewMode] = useState<ViewMode>('list');\n // #Stage B: selection is seeded from the /nodes/[alias] URL (shareable\n // deep link); afterwards it's plain client state kept in sync with the\n // URL via history.pushState — shallow, no route remount, so switching\n // nodes is zero-operation and the conversation pane swaps in place.\n const [chatAlias, setChatAlias] = useState<string | null>(initialAlias);\n const isDesktop = useIsDesktop();\n const selectNode = (alias: string) => {\n setChatAlias(alias);\n try { window.history.pushState({}, '', `/nodes/${encodeURIComponent(alias)}`); } catch {}\n };\n const closeChat = () => {\n setChatAlias(null);\n try { window.history.pushState({}, '', '/nodes'); } catch {}\n };\n // Back/forward buttons walk the selection history the pushState calls\n // above created — mirror the URL back into state.\n useEffect(() => {\n const onPop = () => {\n const m = window.location.pathname.match(/^\\/nodes\\/([^/]+)\\/?$/);\n setChatAlias(m ? decodeAliasSegment(m[1]) : null);\n };\n window.addEventListener('popstate', onPop);\n return () => window.removeEventListener('popstate', onPop);\n }, []);\n const [showCreate, setShowCreate] = useState(false);\n // #Stage A (dashboard 3-col, 07-31): persistent narrow node list rail\n // to the left of the existing table. Default on; user can hide to\n // restore the pre-Stage-A dense-table-only layout (Vincent's \"看全局\"\n // pattern MUST stay reachable — 通信龙 07-31 explicit constraint).\n // Persisted in localStorage so a returning user gets the same layout\n // they left.\n const [showRail, setShowRail] = useState<boolean>(() => {\n if (typeof window === 'undefined') return true;\n const v = window.localStorage.getItem('anet-nodes-rail');\n return v === null ? true : v !== '0';\n });\n const toggleRail = () => {\n setShowRail(v => {\n const next = !v;\n try { window.localStorage.setItem('anet-nodes-rail', next ? '1' : '0'); } catch {}\n return next;\n });\n };\n // #209 R32→R34: the WeChat-style magnifier-toggle search was hand-rolled\n // inline in R32. R34 extracted it to a shared hook so /nodes, /messages,\n // and any future search surface stay visually + behaviourally identical.\n // The hook returns a Button (place in header) + Row (place after header).\n const searchCtl = useCollapsibleSearch({\n value: search,\n onChange: setSearch,\n placeholder: t('搜索节点(支持拼音/首字母)…', 'Search nodes (pinyin ok)…'),\n label: 'Search nodes',\n enabled: sessions.length > 0,\n });\n\n const lastOnlineRef = useRef<Map<string, number>>(new Map());\n // eslint-disable-next-line react-hooks/purity -- see Overview note (60s sort hysteresis clock)\n const nowMs = Date.now();\n const sortOnline = (alias: string, online: boolean) => {\n if (online) lastOnlineRef.current.set(alias, nowMs);\n return (nowMs - (lastOnlineRef.current.get(alias) || 0)) < 60_000 ? 1 : 0;\n };\n const filtered: SessionRow[] = sessions\n .map(s => ({ ...s, online: !!sseFor(s) }))\n .filter(s => {\n if (filterStatus === 'online') return s.online;\n if (filterStatus === 'offline') return !s.online;\n if (filterStatus && filterStatus !== s.status) return false;\n return true;\n })\n .filter(s => {\n // #492 team filter — strict match. '' = pass all; '__NO_TEAM__' =\n // only nodes with no team assigned; any other value = exact match.\n // Nodes without a team NEVER leak into a \"team X\" result.\n if (!filterTeam) return true;\n const team = attrsByAlias[s.alias]?.team ?? null;\n if (filterTeam === '__NO_TEAM__') return team === null || team === '';\n return team === filterTeam;\n })\n .filter(s => {\n // #492 tag filter — AND across all chip selections. Zero selected =\n // pass all. Product decision (AND not OR): operators narrow down.\n if (filterTags.length === 0) return true;\n const nodeTags = attrsByAlias[s.alias]?.tags ?? [];\n return filterTags.every(t => nodeTags.includes(t));\n })\n .filter(s => !search || pinyinMatch(s.alias, search) || pinyinMatch(s.agent || '', search))\n .sort((a, b) => ((isPinned(b.alias) ? 1 : 0) - (isPinned(a.alias) ? 1 : 0)) || (sortOnline(b.alias, b.online) - sortOnline(a.alias, a.online)) || lastActivityAt(b.alias) - lastActivityAt(a.alias)); // R41 pin > R29 online-hysteresis > recency\n\n const onlineCount = sessions.filter(s => sseFor(s)).length;\n\n // #Stage A: filtered rail sessions — same criteria as the table, so\n // the two views agree while chips are toggled. Passing the SAME\n // filtered array (not re-computing) is the invariant that keeps\n // \"rail count == table count\" true at all times.\n const railSessions = filtered;\n\n // #Stage C: with a node selected on desktop, the page is LIST + CHAT —\n // the middle table does not render (通信龙 production screenshot catch:\n // rail and table were painting the same 199 nodes twice, squeezing the\n // chat into a sliver; Feishu/WeChat is icon | list | chat, 3 columns not\n // 4). The table is NOT deleted — it's the \"manage all nodes\" view and\n // stays on /nodes with nothing selected.\n //\n // The sessions.length guard does TWO jobs (通信龙 Stage C review — do\n // not remove it thinking the rail makes it redundant):\n // 1. empty states: with no sessions there's no rail either, so the\n // middle column must stay to show onboarding/empty UI;\n // 2. SSR blank-screen guard: useIsDesktop's server snapshot is `true`,\n // so on a narrow-screen deep link the server would otherwise render\n // \"middle hidden + ChatPane hidden by `hidden md:` + rail hidden by\n // `hidden sm:`\" = a fully blank page until hydration. During SSR,\n // SWR has no data yet → sessions=[] → this guard keeps the middle\n // column rendered.\n const chatOpenDesktop = !!chatAlias && isDesktop && sessions.length > 0;\n\n return (\n <div\n data-testid=\"nodes-layout\"\n data-rail-visible={showRail ? 'true' : 'false'}\n className=\"min-h-screen max-w-full overflow-x-hidden bg-[#0b0b0d] text-gray-100 flex\"\n >\n {/* #Stage A rail — only mounted when showRail is true AND we're\n past the mobile breakpoint (below sm, rail is hidden by CSS\n to give the table full width on small screens; the toggle\n button controls both). sessions.length===0 also hides the rail\n because there's nothing to list.\n #Stage C: a selected node FORCES the rail on (even for dense-view\n users with showRail=false) — in the list+chat layout the rail is\n the only way to switch nodes, so it must be there. */}\n {(showRail || chatOpenDesktop) && sessions.length > 0 && (\n <aside\n data-testid=\"node-list-rail\"\n className=\"hidden sm:flex sm:flex-col w-[280px] shrink-0 min-h-screen sticky top-0\"\n >\n <NodeList\n sessions={railSessions}\n selectedAlias={chatAlias}\n onSelect={selectNode}\n />\n </aside>\n )}\n {/* #Stage C: middle column (header + filters + table/grid) renders\n only when NO node is selected on desktop — see chatOpenDesktop\n note above. Mobile keeps it always (chat is an overlay there). */}\n {!chatOpenDesktop && (\n <div className=\"flex-1 min-w-0 max-w-full overflow-x-hidden p-4 sm:p-6\">\n {/* #209 R31 (mobile vertical rhythm — goal \"大幅提升移动端体验\",\n extending R28's Overview pattern + R30's /tasks pattern):\n this header row + the status-bar wrapper + the filter row\n below all drop mb-6 → mb-4 sm:mb-6. Three spots × 8 px =\n ~24 px scroll reclaim on /nodes before the first card.\n #209 R32: search affordance moved to top-right magnifier\n button (Vincent WeChat ref msg 563). justify-between makes\n the title cluster hug left, button hugs right. */}\n <div className=\"flex items-center gap-4 mb-4 sm:mb-6\">\n <div className=\"flex items-center gap-3 min-w-0 flex-1\">\n <h1 className=\"text-2xl font-bold text-white lg:ml-0 ml-10\">Nodes</h1>\n <span className=\"text-xs bg-green-900/30 text-green-400 px-2 py-0.5 rounded-full border border-green-800/30 shrink-0\">\n {onlineCount} online\n </span>\n <span className=\"text-xs bg-gray-900/30 text-gray-400 px-2 py-0.5 rounded-full border border-gray-800/30 shrink-0\">\n {sessions.length} total\n </span>\n </div>\n <div className=\"flex items-center gap-2 shrink-0\">\n {/* #Stage A rail toggle — visible on sm+ (where rail also\n renders). Preserves Vincent's \"看全局\" dense-table view\n as one click away (通信龙 07-31 constraint). Icon-only\n on mobile / sm; icon + text on md+. */}\n <button\n type=\"button\"\n onClick={toggleRail}\n aria-pressed={showRail}\n data-testid=\"toggle-rail\"\n title={showRail ? t('隐藏节点列表', 'Hide node list') : t('显示节点列表', 'Show node list')}\n className=\"hidden sm:inline-flex items-center gap-1 rounded-lg border border-[#26262b] bg-[#161618] px-2.5 py-1.5 text-xs text-gray-400 hover:text-gray-200 hover:border-[#3a3a40] transition-colors\"\n >\n <span aria-hidden className=\"text-sm leading-none\">{showRail ? '☷' : '☰'}</span>\n <span className=\"hidden md:inline\">{showRail ? t('密视图', 'Dense') : t('分栏', 'Split')}</span>\n </button>\n {/* node-lifecycle M2: open the create-node wizard (RFC-026 §3.1 P1). */}\n <button\n type=\"button\"\n onClick={() => setShowCreate(true)}\n aria-label=\"新建节点\"\n className=\"inline-flex items-center gap-1 rounded-lg border border-cyan-700/50 bg-cyan-900/15 px-3 py-1.5 text-sm font-medium text-cyan-300 hover:bg-cyan-900/25 transition-colors\"\n >\n <span aria-hidden className=\"text-base leading-none\">+</span>\n <span className=\"hidden sm:inline\">新建节点</span>\n </button>\n <searchCtl.Button />\n </div>\n </div>\n\n {showCreate && <CreateNodeWizard onClose={() => setShowCreate(false)} />}\n\n {/* #209 R34: shared <CollapsibleSearch> component handles row reveal,\n autofocus, Escape, and Cancel. enabled=sessions.length>0 hides\n everything until there's content to search. */}\n <searchCtl.Row />\n\n {/* #217 D6 (less is more): the status distribution bar + its\n working/idle/offline legend duplicated the header chips\n (N online / N total) and the per-card status pills right\n below. One count display per screen — the bar is gone. */}\n\n {/* Round 74: hide the filter+view chrome when there are no nodes\n anywhere — these controls have nothing to act on, and they only\n push the onboarding CTA further down. When at least one session\n exists, the chrome is back even if the current filter happens\n to hide everything (so users can clear filters). */}\n {sessions.length > 0 && (\n <div className=\"flex flex-wrap gap-3 mb-4 sm:mb-6\">\n {/* R32: the inline search input was moved to the top-right\n magnifier toggle above. The status select + List/Grid\n toggle stay here. */}\n <select\n value={filterStatus}\n onChange={e => setFilterStatus(e.target.value)}\n className=\"bg-[#161618] border border-[#26262b] rounded-lg px-3 py-2 text-base sm:text-sm text-white focus:border-blue-500/50 focus:outline-none\"\n >\n <option value=\"\">All</option>\n <option value=\"online\">Online</option>\n <option value=\"offline\">Offline</option>\n <option value=\"working\">Working</option>\n <option value=\"idle\">Idle</option>\n <option value=\"blocked\">Blocked</option>\n <option value=\"error\">Error</option>\n </select>\n {/* #492 team select — only shown once at least one node has a\n team attribute. \"__NO_TEAM__\" surfaces nodes without team,\n so operators can find nodes that never got tagged. */}\n {distinctTeams.length > 0 && (\n <select\n value={filterTeam}\n onChange={e => setFilterTeam(e.target.value)}\n aria-label={t('按 Team 过滤', 'Filter by team')}\n data-testid=\"filter-team\"\n className=\"bg-[#161618] border border-[#26262b] rounded-lg px-3 py-2 text-base sm:text-sm text-white focus:border-blue-500/50 focus:outline-none\"\n >\n <option value=\"\">{t('全部 Team', 'All teams')}</option>\n <option value=\"__NO_TEAM__\">{t('未分组', '(no team)')}</option>\n {distinctTeams.map(team => (\n <option key={team} value={team}>{team}</option>\n ))}\n </select>\n )}\n {/* Round 80: List/Grid toggle hidden on mobile — Grid uses\n grid-cols-1 below `md` and List degrades to the same single\n column, so the toggle has no visual effect under sm and only\n steals a row of vertical space. */}\n <div className=\"hidden sm:flex ml-auto rounded-lg border border-[#26262b] bg-[#161618] p-1 text-sm\">\n {(['list', 'grid'] as const).map(mode => (\n <button\n key={mode}\n type=\"button\"\n onClick={() => setViewMode(mode)}\n className={`rounded-md px-3 py-1.5 transition-colors ${\n viewMode === mode\n ? 'bg-cyan-500/10 text-cyan-300'\n : 'text-gray-500 hover:text-gray-200'\n }`}\n >\n {mode === 'list' ? 'List' : 'Grid'}\n </button>\n ))}\n </div>\n </div>\n )}\n {/* #492 tag chip row — separate row so multi-select feels distinct\n from single-select controls above. Each chip toggles inclusion;\n selected chips get cyan bg. Explicit \"AND\" separators between\n selected chips make the join semantics visible in the UI (per\n PR review: silent AND under selected-multiple → 0 results\n reads as bug; the label makes it a deliberate narrow-down). */}\n {sessions.length > 0 && distinctTags.length > 0 && (\n <div className=\"mb-4 sm:mb-6 flex flex-wrap items-center gap-1.5\" data-testid=\"filter-tags-row\">\n <span className=\"text-[11px] text-gray-500 mr-1\">{t('Tags:', 'Tags:')}</span>\n {distinctTags.map((tag, idx) => {\n const selected = filterTags.includes(tag);\n const isNotFirstSelected = selected && filterTags.slice(0, filterTags.indexOf(tag)).length > 0;\n void idx; void isNotFirstSelected;\n return (\n <button\n key={tag}\n type=\"button\"\n onClick={() => toggleTag(tag)}\n aria-pressed={selected}\n data-tag={tag}\n data-selected={selected ? 'true' : 'false'}\n className={`text-xs rounded-full px-2.5 py-1 border transition-colors ${\n selected\n ? 'bg-cyan-500/15 text-cyan-200 border-cyan-500/40'\n : 'bg-[#161618] text-gray-400 border-[#26262b] hover:text-gray-200 hover:border-[#3a3a40]'\n }`}\n >\n {tag}\n </button>\n );\n })}\n {filterTags.length >= 2 && (\n <span\n className=\"text-[10px] text-cyan-300/80 ml-1 tabular-nums\"\n data-testid=\"filter-tags-and-hint\"\n >\n {t(`= 同时具有 ${filterTags.length} 个标签`, `= AND of ${filterTags.length} tags`)}\n </span>\n )}\n {(filterTags.length > 0 || filterTeam) && (\n <button\n type=\"button\"\n onClick={() => { setFilterTags([]); setFilterTeam(''); }}\n className=\"text-[11px] text-gray-500 hover:text-gray-200 underline-offset-2 hover:underline ml-2\"\n data-testid=\"clear-attr-filters\"\n >\n {t('清除', 'Clear')}\n </button>\n )}\n </div>\n )}\n\n {loading ? (\n <div className=\"animate-pulse space-y-2\">\n {[1,2,3,4].map(i => <div key={i} className=\"h-16 bg-gray-800/20 rounded-lg\" />)}\n </div>\n ) : filtered.length === 0 ? (\n sessions.length === 0 ? (\n /* Round 73: first-run case — no agents anywhere. Use the same\n onboarding empty state as the Overview (NodesEmptyState\n includes the `npx … init` quickstart command). Previously this\n was the \"No nodes match your filters\" copy, which was wrong\n for new users who have no filters applied. */\n <NodesEmptyState />\n ) : (filterTeam || filterTags.length > 0) ? (\n /* #492: attribute-filter no-match — echo the specific filter\n conditions so the user can tell \"no nodes exist with this\n combo\" from \"I mis-typed / data isn't synced\". Distinct\n from the generic status/search \"No match\" below. Under\n AND semantics for multi-tag, this is the copy 通信龙 asked\n for: \"没有节点同时具有 A 和 B\" instead of \"no match\". */\n <EmptyState\n variant=\"nodes\"\n title={t('没有节点符合当前属性筛选', 'No nodes match the current attribute filters')}\n sub={(() => {\n const parts: string[] = [];\n if (filterTeam === '__NO_TEAM__') parts.push(t('未分组', 'no-team'));\n else if (filterTeam) parts.push(t(`Team = ${filterTeam}`, `Team = ${filterTeam}`));\n if (filterTags.length === 1) parts.push(t(`标签 ${filterTags[0]}`, `tag ${filterTags[0]}`));\n else if (filterTags.length >= 2) parts.push(t(`同时具有标签 ${filterTags.join(' 和 ')}`, `all of tags: ${filterTags.join(' AND ')}`));\n return t(`没有节点满足:${parts.join(' + ')}。清除筛选或减少标签。`, `No node satisfies: ${parts.join(' + ')}. Clear filters or drop a tag.`);\n })()}\n />\n ) : !anyAttrs && (filterStatus || search) ? (\n <EmptyState\n variant=\"nodes\"\n title={t('还没有节点被打过标签', 'No nodes have been tagged yet')}\n sub={t('先在节点详情里给几个节点分配 team / tag,然后就可以按属性筛选。', 'Assign team / tag to a few nodes first, then attribute filters will show up.')}\n />\n ) : (\n <EmptyState\n variant=\"nodes\"\n title=\"No nodes match your filters\"\n sub=\"Try clearing search or status filters, or wait for an agent to register.\"\n />\n )\n ) : viewMode === 'grid' ? (\n <div className=\"grid min-w-0 grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-4\">\n {filtered.map(s => {\n const statusKey = s.online ? s.status : 'offline';\n const progress = typeof s.progress === 'number' ? s.progress : 0;\n const unread = hasUnread(s.alias);\n\n return (\n <div\n key={s.alias}\n role=\"button\"\n tabIndex={0}\n data-node-card\n data-node-alias={s.alias}\n onClick={() => selectNode(s.alias)}\n onKeyDown={e => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); selectNode(s.alias); } }}\n className={`relative min-w-0 max-w-full overflow-hidden rounded-xl border border-[#26262b] bg-[#161618] p-4 transition-colors hover:border-cyan-500/40 cursor-pointer ${!s.online ? 'opacity-60' : ''}`}\n >\n {!s.online && (\n <div className=\"pointer-events-none absolute inset-0 flex items-center justify-center\">\n <span className=\"rotate-[-20deg] rounded-xl border border-white/10 bg-black/20 px-5 py-2 text-xl font-bold uppercase tracking-[0.35em] text-white/10\">\n Offline\n </span>\n </div>\n )}\n <div className=\"flex items-start gap-3\">\n <div className=\"relative shrink-0\">\n <span className=\"relative inline-flex shrink-0\">\n <AliasAvatar alias={s.alias} size={36} />\n {unreadCount(s.alias) > 0 && isMuted(s.alias) && (\n <span aria-label={t('有未读(已静音)', 'Unread (muted)')} className=\"absolute -top-0.5 -right-1 h-2.5 w-2.5 rounded-full bg-red-500/80 ring-2 ring-[#161618]\" />\n )}\n {unreadCount(s.alias) > 0 && !isMuted(s.alias) && (\n <span aria-label={t(`${unreadCount(s.alias)} 条未读`, `${unreadCount(s.alias)} unread`)} className=\"absolute -top-1 -right-1.5 min-w-[16px] h-4 px-1 rounded-full bg-red-500 text-white text-[9px] font-semibold leading-4 text-center ring-2 ring-[#161618]\">\n {unreadCount(s.alias) > 99 ? '99+' : unreadCount(s.alias)}\n </span>\n )}\n </span>\n {unread && <span className=\"absolute -right-1 -top-1 h-3 w-3 rounded-full border-2 border-[#161618] bg-red-500\" />}\n </div>\n <div className=\"min-w-0 flex-1\">\n <div className=\"flex items-center gap-2\">\n <span className=\"truncate text-base font-semibold text-white\">{s.alias}</span>\n <DraftMark alias={s.alias} />\n {unread && <span className=\"shrink-0 rounded-full bg-red-500/15 px-2 py-0.5 text-[10px] font-semibold uppercase tracking-wide text-red-300\">New</span>}\n <span className={`shrink-0 rounded-md border px-2 py-0.5 text-[10px] uppercase tracking-wide ${STATUS_COLORS[statusKey] || STATUS_COLORS.offline}`}>\n {statusKey}\n </span>\n </div>\n <div className=\"mt-0.5 truncate text-xs text-gray-500\">\n {(s.agent || '—')}<span className=\"text-gray-700 mx-1.5\">·</span><span title={s.server || ''}>{shortServer(s.server)}</span>\n </div>\n </div>\n <span className=\"hidden shrink-0 rounded-lg border border-cyan-500/15 bg-cyan-500/5 px-2 py-1 text-[10px] text-cyan-300/70 sm:inline\">Tap to chat</span>\n {/* RFC-027 PR2 — per-node ⋮ lifecycle menu. The button stopsPropagation\n internally so it doesn't open chat. lifecycleByAlias absent → 'active'\n default, menu renders normal stop/delete options. */}\n <NodeLifecycleMenu\n nodeId={nodeIdByAlias[s.alias] || s.node_id || s.alias}\n alias={s.alias}\n lifecycleState={lifecycleByAlias[s.alias]}\n networkId={s.network_id || null}\n onCompleted={refreshNodes}\n attrsSnapshot={attrsByAlias[s.alias]}\n />\n </div>\n\n <div className=\"mt-3 rounded-lg border border-[#1c1c1f] bg-[#0e0e10] px-3 py-2 text-xs\">\n <div className=\"flex items-center justify-between gap-3\">\n <span className=\"text-[10px] uppercase tracking-wide text-gray-600\">Current task</span>\n <span className=\"text-[10px] text-gray-600\">{timeAgo(s.last_seen_at || s.updated_at)}</span>\n </div>\n <div className={`mt-1 line-clamp-2 ${s.task ? 'text-gray-300' : 'text-gray-600 italic'}`}>\n {s.task || 'No current task'}\n </div>\n </div>\n\n {progress > 0 && progress < 100 && (\n <div className=\"mt-3 h-1.5 overflow-hidden rounded-full bg-gray-800\">\n <div className=\"h-1.5 rounded-full bg-cyan-400 transition-all\" style={{ width: `${progress}%` }} />\n </div>\n )}\n\n </div>\n );\n })}\n </div>\n ) : (\n <div className=\"space-y-1 sm:space-y-2\">\n {/* Round 94: AGENT + SERVER merged into one `agent · server`\n cell. Round mobile-command: node row itself opens chat, so\n the old Chat / Send Task action column is gone. */}\n <div className=\"hidden sm:grid sm:grid-cols-10 gap-2 px-4 py-2 text-xs text-gray-600 uppercase\">\n <div className=\"col-span-1\">Status</div>\n <div className=\"col-span-2\">Alias</div>\n <div className=\"col-span-2\">Agent · Server</div>\n <div className=\"col-span-4\">Current Task</div>\n <div className=\"col-span-1\">Updated</div>\n </div>\n {filtered.map(s => {\n const statusKey = s.online ? s.status : 'offline';\n const unread = hasUnread(s.alias);\n\n return (\n <div\n key={s.alias}\n role=\"button\"\n tabIndex={0}\n data-node-card\n data-node-alias={s.alias}\n onClick={() => selectNode(s.alias)}\n onKeyDown={e => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); selectNode(s.alias); } }}\n className={`rounded-lg border border-[#26262b] bg-[#161618] px-3 py-2 sm:px-4 sm:py-3 transition-colors hover:border-cyan-500/40 cursor-pointer ${!s.online ? 'opacity-50' : ''}`}\n >\n <div className=\"hidden sm:grid sm:grid-cols-10 gap-2 items-center\">\n <div className=\"col-span-1\">\n <span className={`text-xs px-2 py-0.5 rounded-md border ${STATUS_COLORS[statusKey] || STATUS_COLORS.offline}`}>\n {statusKey}\n </span>\n </div>\n <div className=\"col-span-2 min-w-0\">\n <div className=\"flex items-center gap-2 min-w-0\">\n <div className=\"relative shrink-0\">\n <span className=\"relative inline-flex shrink-0\">\n <AliasAvatar alias={s.alias} size={20} />\n {unreadCount(s.alias) > 0 && isMuted(s.alias) && (\n <span aria-label={t('有未读(已静音)', 'Unread (muted)')} className=\"absolute -top-1 -right-1 h-2 w-2 rounded-full bg-red-500/80\" />\n )}\n {unreadCount(s.alias) > 0 && !isMuted(s.alias) && (\n <span aria-label={t(`${unreadCount(s.alias)} 条未读`, `${unreadCount(s.alias)} unread`)} className=\"absolute -top-1.5 -right-2 min-w-[15px] h-[15px] px-1 rounded-full bg-red-500 text-white text-[9px] font-semibold leading-[15px] text-center\">\n {unreadCount(s.alias) > 99 ? '99+' : unreadCount(s.alias)}\n </span>\n )}\n </span>\n {unread && <span className=\"absolute -right-1 -top-1 h-2.5 w-2.5 rounded-full border border-[#161618] bg-red-500\" />}\n </div>\n <span className=\"truncate text-sm font-medium text-white\">{s.alias}</span>\n <DraftMark alias={s.alias} />\n {unread && <span className=\"shrink-0 rounded-full bg-red-500/15 px-1.5 py-0.5 text-[9px] font-semibold uppercase tracking-wide text-red-300\">New</span>}\n </div>\n </div>\n <div className=\"col-span-2 truncate text-xs text-gray-400\" title={s.server || ''}>\n <span className=\"truncate\">{s.agent || '--'}<span className=\"text-gray-700 mx-1.5\">·</span>{shortServer(s.server)}</span>\n </div>\n <div className=\"col-span-4 truncate text-xs text-gray-500\" title={s.task || ''}>{s.task || '--'}</div>\n <div className=\"col-span-1 flex items-center justify-between gap-2 text-xs text-gray-500\">\n <span className=\"truncate\">{timeAgo(s.last_seen_at || s.updated_at)}</span>\n {/* RFC-027 PR2 ⋮ lifecycle menu — desktop list. Defaults\n to 'active' when lifecycleByAlias absent. */}\n <NodeLifecycleMenu\n nodeId={nodeIdByAlias[s.alias] || s.node_id || s.alias}\n alias={s.alias}\n lifecycleState={lifecycleByAlias[s.alias]}\n networkId={s.network_id || null}\n onCompleted={refreshNodes}\n attrsSnapshot={attrsByAlias[s.alias]}\n />\n </div>\n </div>\n {/* R7 of #190: mobile node row was ~340px tall × ~150\n rows = the 51k page. Wins this round, in priority\n order: (1) drop the per-row \"Tap anywhere to chat\"\n hint — useful once, redundant 149 times; the cyan\n border on hover/focus still teaches it. (2) tighten\n space-y-2 → space-y-1 so the avatar/task gap is\n 4px tighter on every row. */}\n <div className=\"sm:hidden space-y-1\">\n <div className=\"flex items-center gap-2.5\">\n <div className=\"relative shrink-0\">\n <AliasAvatar alias={s.alias} size={28} />\n {unread && <span className=\"absolute -right-1 -top-1 h-3 w-3 rounded-full border-2 border-[#161618] bg-red-500\" />}\n </div>\n <div className=\"min-w-0 flex-1\">\n <div className=\"flex items-center gap-2 min-w-0\">\n <div className=\"truncate text-sm font-medium text-white\">{s.alias}</div>\n {unread && <span className=\"shrink-0 rounded-full bg-red-500/15 px-1.5 py-0.5 text-[9px] font-semibold uppercase tracking-wide text-red-300\">New</span>}\n </div>\n <div className=\"truncate text-[10px] text-gray-500\">{s.agent || '—'} · {timeAgo(s.last_seen_at || s.updated_at)}</div>\n </div>\n <span className={`shrink-0 text-xs px-2 py-0.5 rounded-md border ${STATUS_COLORS[statusKey] || STATUS_COLORS.offline}`}>\n {statusKey}\n </span>\n {/* RFC-027 PR2 ⋮ lifecycle menu — mobile list. */}\n <NodeLifecycleMenu\n nodeId={nodeIdByAlias[s.alias] || s.node_id || s.alias}\n alias={s.alias}\n lifecycleState={lifecycleByAlias[s.alias]}\n networkId={s.network_id || null}\n onCompleted={refreshNodes}\n attrsSnapshot={attrsByAlias[s.alias]}\n />\n </div>\n {s.task && <div className=\"truncate text-xs text-gray-500\">{s.task}</div>}\n </div>\n </div>\n );\n })}\n </div>\n )}\n\n {/* #Stage B: below md the chat keeps the pre-B behavior — a\n full-screen overlay push (TaskChatPanel's own fixed shell).\n On md+ the persistent right pane below renders instead; the\n two are mutually exclusive via isDesktop so only ONE\n TaskChatPanel is ever mounted (no double SSE / mark-read). */}\n {chatAlias && !isDesktop && <TaskChatPanel alias={chatAlias} onClose={closeChat} />}\n </div>\n )}\n {/* #Stage B: persistent right chat column (md+) — see ChatPane.tsx\n (ChatPopover minus the floating shell; TaskChatPanel inline body).\n Switching nodes swaps `alias` in place (no remount). */}\n {chatAlias && isDesktop && <ChatPane alias={chatAlias} onClose={closeChat} />}\n </div>\n );\n}\n","'use client';\n\nimport { useEffect, useState } from 'react';\nimport { useNetworkId } from '../lib/network-context';\nimport { DaemonOption, HostSupervisorPicker } from './HostSupervisorPicker';\n\n/**\n * Create-node wizard (node-lifecycle UI M2/PR4 — RFC-026 §3.1).\n * 6 steps now: ⓪ host (PR4 #338) ① name ② runtime ③ model ④ flags ⑤ confirm\n * → POST /api/anet/node-create with `daemon_node_id` set to the chosen host.\n *\n * PR4 (#338 main lane PR4) folds RFC-026 §9.4 host_supervisor picker in front\n * of the existing 5 steps. Three states the picker resolves internally:\n * - count=0 → onboarding (no daemon, show install command + block forward)\n * - count=1 → auto-pick + forward immediately\n * - count≥2 → user picks, then forward\n * The wizard now ALWAYS passes daemon_node_id to /api/anet/node-create (the\n * route's `resolveLocalDaemonNodeId` fallback only fires if daemon_node_id is\n * absent — kept for back-compat with non-wizard callers but no longer used\n * from this flow). Per [[feedback_doc_capability_claim_verify_code_path]] —\n * the API contract is exercised locally before any prod hub touches the path.\n */\n\n// IDs MUST match the hub validator enums (server/src/create-node-validate.ts).\n// Caught via local /mcp probe during mobile wizard build (#338 plan B):\n// pre-fix RUNTIMES had 'codex' + 'grok' but hub accepts 'codex-sdk' +\n// 'grok-build-acp'; pre-fix PERMISSION_MODES had 'auto' but hub rejects it\n// (flag_value_invalid). The wizard has been silently shipping invalid combos\n// for any non-claude-agent-sdk pick since M2 — only worked end-to-end with\n// the default claude path.\n//\n// `defaultModel` — hub's `create_node.node_spec.model` schema is\n// `z.string().min(1).max(100)`; the wizard's \"默认\" option leaves the state\n// empty, so pre-fix the POST body dropped `model` entirely and hub rejected\n// with `Invalid input: expected string, received undefined`. `defaultModel`\n// gets substituted before submit (and shown in the dropdown label so the\n// operator knows what \"默认\" will actually become).\nconst RUNTIMES: { id: string; label: string; models: string[]; defaultModel: string }[] = [\n { id: 'claude-agent-sdk', label: 'Claude Agent SDK', models: ['deepseek-v4-pro', 'MiniMax-M3', 'claude-sonnet-4-6', 'claude-opus-4-x'], defaultModel: 'claude-sonnet-4-6' },\n { id: 'codex-sdk', label: 'Codex SDK', models: ['gpt-5.5'], defaultModel: 'gpt-5.5' },\n { id: 'grok-build-acp', label: 'Grok (build-acp)', models: ['grok-build'], defaultModel: 'grok-build' },\n];\nconst PERMISSION_MODES = ['default', 'acceptEdits', 'plan', 'bypassPermissions'];\nconst STEPS = ['服务器', '名字', 'Runtime', '模型', '参数', '确认'];\n\ntype Phase = 'form' | 'creating' | 'done' | 'unconfirmed' | 'error';\n\nexport function CreateNodeWizard({\n networkId,\n onClose,\n onCreated,\n}: {\n networkId?: string;\n onClose: () => void;\n onCreated?: (result: unknown) => void;\n}) {\n const [step, setStep] = useState(0);\n const [daemonNodeId, setDaemonNodeId] = useState<string | null>(null);\n // (#338 wizard-runtime-filter) keep the full daemon row so the Runtime\n // step can disable runtimes the chosen daemon doesn't declare support\n // for. Hub-side enforcement still wins; this is UX surfacing.\n const [daemon, setDaemon] = useState<DaemonOption | null>(null);\n const [name, setName] = useState('');\n const [runtimeId, setRuntimeId] = useState(RUNTIMES[0].id);\n const [model, setModel] = useState('');\n const [permissionMode, setPermissionMode] = useState('default');\n const [maxTurns, setMaxTurns] = useState('');\n const [budget, setBudget] = useState('');\n const [timeout, setTimeout] = useState('');\n const [phase, setPhase] = useState<Phase>('form');\n const [msg, setMsg] = useState('');\n const [childUp, setChildUp] = useState(false);\n const { networkId: ctxNetworkId } = useNetworkId();\n const netId = networkId || ctxNetworkId;\n\n // Escape closes the wizard (unless a create is mid-flight, so a stray key\n // can't drop the dialog while the request is settling).\n useEffect(() => {\n const onKey = (e: KeyboardEvent) => { if (e.key === 'Escape' && phase !== 'creating') onClose(); };\n window.addEventListener('keydown', onKey);\n return () => window.removeEventListener('keydown', onKey);\n }, [onClose, phase]);\n\n // After dispatch, confirm the child actually came up by watching the node\n // list for it to register (RFC-026 progress signal — get_create_request is\n // daemon-only, so the dashboard confirms via /api/hub/status). Polls ~24s.\n useEffect(() => {\n if (phase !== 'done' || childUp) return;\n let alive = true;\n let tries = 0;\n const want = name.trim();\n const tick = async () => {\n tries += 1;\n try {\n const url = netId ? `/api/hub/status?network_id=${encodeURIComponent(netId)}` : '/api/hub/status';\n const r = await fetch(url, { cache: 'no-store' });\n const d = await r.json().catch(() => ({}));\n const list = Array.isArray(d?.sessions) ? d.sessions : Array.isArray(d) ? d : [];\n if (alive && list.some((s: { alias?: string }) => s?.alias === want)) { setChildUp(true); return; }\n } catch { /* transient — keep polling */ }\n if (alive && tries < 16) window.setTimeout(tick, 1500);\n };\n const t = window.setTimeout(tick, 1200);\n return () => { alive = false; window.clearTimeout(t); };\n }, [phase, childUp, netId, name]);\n\n const runtime = RUNTIMES.find(r => r.id === runtimeId) || RUNTIMES[0];\n const nameValid = name.trim().length > 0;\n const canNext =\n (step === 0 && Boolean(daemonNodeId)) || // step 0: must have chosen a daemon\n (step === 1 && nameValid) || // step 1: name non-empty\n (step >= 2 && step < STEPS.length); // later steps: nothing required to advance\n const busy = phase === 'creating';\n\n async function handleCreate() {\n setPhase('creating');\n setMsg('');\n const numOrUndef = (v: string) => (v.trim() === '' ? undefined : Number(v));\n // Hub's create_node.node_spec.model schema is z.string().min(1); the\n // wizard's \"默认\" option leaves state empty, so pick the runtime's\n // documented default here. This mirrors what agent-node itself defaults\n // to at boot (see agent-node cli.ts model resolution), so the \"默认\"\n // dropdown label + this fallback both point at the same model.\n const effectiveModel = model || runtime.defaultModel;\n const node_spec = {\n name: name.trim(),\n runtime: runtimeId,\n model: effectiveModel,\n flags: {\n permissionMode,\n maxTurns: numOrUndef(maxTurns),\n budget: numOrUndef(budget),\n timeout: numOrUndef(timeout),\n },\n };\n try {\n const r = await fetch('/api/anet/node-create', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n node_spec,\n ...(daemonNodeId ? { daemon_node_id: daemonNodeId } : {}),\n ...(networkId ? { network_id: networkId } : {}),\n }),\n });\n const data = await r.json().catch(() => ({}));\n if (r.ok && data?.ok) {\n setPhase('done');\n setMsg('创建请求已下发,节点正在拉起…');\n onCreated?.(data.result);\n } else if (data?.unconfirmed) {\n setPhase('unconfirmed');\n setMsg(`后端 create_node 未就绪:${data?.error || '不可用'}(测试 hub 可能未含 #299)`);\n } else {\n setPhase('error');\n setMsg(data?.error ? `创建失败:${data.error}` : '创建失败');\n }\n } catch (e) {\n setPhase('error');\n setMsg(`创建失败:${e instanceof Error ? e.message : '网络错误'}`);\n }\n }\n\n const inputCls =\n 'w-full rounded-md border border-[#26262b] bg-[#0e0e10] px-3 py-2 text-sm text-gray-200 focus:border-cyan-600 focus:outline-none';\n\n return (\n <>\n <div className=\"fixed inset-0 bg-black/50 z-40\" onClick={onClose} aria-hidden />\n <div\n role=\"dialog\"\n aria-label=\"新建节点\"\n // RFC-026 §9.4 responsive: mobile single-screen (full width minus\n // gutter, taller); desktop ~3-col-friendly width when picker is shown.\n className=\"fixed left-1/2 top-1/2 z-50 w-[min(94vw,440px)] md:w-[min(92vw,720px)] -translate-x-1/2 -translate-y-1/2 rounded-xl border border-[#26262b] bg-[#161618] shadow-2xl\"\n >\n {/* Header */}\n <div className=\"flex items-center justify-between border-b border-[#26262b] px-4 py-3\">\n <div className=\"text-sm font-semibold text-white\">新建节点</div>\n <button onClick={onClose} aria-label=\"关闭\" className=\"inline-flex h-8 w-8 items-center justify-center rounded-md text-gray-500 hover:bg-white/5 hover:text-white\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" aria-hidden>\n <path d=\"M18 6 6 18M6 6l12 12\" />\n </svg>\n </button>\n </div>\n\n {/* Step indicator */}\n <div className=\"flex items-center gap-1.5 px-4 pt-3\">\n {STEPS.map((label, i) => (\n <div key={label} className=\"flex flex-1 flex-col items-center gap-1\">\n <div className={`h-1 w-full rounded-full ${i <= step ? 'bg-cyan-500' : 'bg-[#26262b]'}`} />\n <span className={`text-[10px] ${i === step ? 'text-cyan-300' : 'text-gray-600'}`}>{label}</span>\n </div>\n ))}\n </div>\n\n {/* Body */}\n <div className=\"min-h-[180px] px-4 py-4\">\n {phase !== 'form' ? (\n <div className=\"flex h-[180px] flex-col items-center justify-center gap-3 text-center\">\n {busy && (\n <svg className=\"h-7 w-7 animate-spin text-cyan-400\" viewBox=\"0 0 24 24\" fill=\"none\" aria-hidden>\n <circle className=\"opacity-25\" cx=\"12\" cy=\"12\" r=\"10\" stroke=\"currentColor\" strokeWidth=\"4\" />\n <path className=\"opacity-90\" fill=\"currentColor\" d=\"M4 12a8 8 0 018-8v4a4 4 0 00-4 4H4z\" />\n </svg>\n )}\n <div className={`text-sm ${phase === 'done' ? 'text-green-300' : phase === 'error' ? 'text-red-300' : phase === 'unconfirmed' ? 'text-amber-300' : 'text-gray-300'}`}>\n {busy ? '正在创建…' : phase === 'done' && childUp ? `✓ ${name.trim()} 已上线` : msg}\n </div>\n {/* Real progress: poll the node list for the child to register\n (派单→fork→注册→✓). */}\n {phase === 'done' && (childUp ? (\n <p className=\"text-[11px] text-green-500/80\">节点已注册,已出现在节点列表。</p>\n ) : (\n <p className=\"inline-flex items-center gap-1.5 text-[11px] text-gray-500\">\n <svg className=\"h-3 w-3 animate-spin\" viewBox=\"0 0 24 24\" fill=\"none\" aria-hidden>\n <circle className=\"opacity-25\" cx=\"12\" cy=\"12\" r=\"10\" stroke=\"currentColor\" strokeWidth=\"4\" />\n <path className=\"opacity-90\" fill=\"currentColor\" d=\"M4 12a8 8 0 018-8v4a4 4 0 00-4 4H4z\" />\n </svg>\n 正在监测 {name.trim()} 注册…(最长 ~24s)\n </p>\n ))}\n </div>\n ) : (\n <>\n {step === 0 && (\n <div className=\"space-y-2\">\n <span className=\"text-xs text-gray-400\">在哪台机器上创建</span>\n <HostSupervisorPicker\n networkId={netId || undefined}\n value={daemonNodeId}\n onChange={(id, d) => {\n setDaemonNodeId(id);\n setDaemon(d);\n // (#338 wizard-runtime-filter) If the current runtime\n // pick isn't supported by the new daemon, reset so\n // the user is forced to re-pick on step 2. Otherwise\n // they could land on step 5 (确认) with an\n // already-invalid combo that only hub rejection\n // surfaces.\n const supported = d?.runtimes_supported;\n if (supported && supported.length > 0 && !supported.includes(runtimeId)) {\n setRuntimeId(supported[0]);\n setModel('');\n }\n }}\n />\n {!daemonNodeId && (\n <p className=\"text-[11px] text-gray-600\">\n 没选服务器之前无法继续;如果列表是空的,按提示在目标机器上跑 <code className=\"rounded bg-black/40 px-1 py-0.5\">anet daemon up &lt;name&gt;</code>。\n </p>\n )}\n </div>\n )}\n {step === 1 && (\n <label className=\"block space-y-1.5\">\n <span className=\"text-xs text-gray-400\">节点名字</span>\n <input autoFocus value={name} onChange={e => setName(e.target.value)} placeholder=\"例如 my-agent-1\" className={inputCls} />\n {!nameValid && <span className=\"text-[11px] text-gray-600\">名字不能为空</span>}\n </label>\n )}\n {step === 2 && (\n <div className=\"space-y-2\">\n <span className=\"text-xs text-gray-400\">\n Runtime{daemon ? `(${daemon.alias} 支持)` : ''}\n </span>\n {RUNTIMES.map(r => {\n // (#338 wizard-runtime-filter) Permissive when the\n // daemon didn't publish runtimes_supported at all\n // (pre-PR3 daemons OR daemons not yet upgraded) — hub\n // still validates. Restrictive only when the daemon\n // explicitly told us its supported set.\n const supported = daemon?.runtimes_supported;\n const disabled = Array.isArray(supported) && supported.length > 0 && !supported.includes(r.id);\n const selected = runtimeId === r.id;\n return (\n <button\n key={r.id}\n type=\"button\"\n disabled={disabled}\n onClick={() => { if (!disabled) { setRuntimeId(r.id); setModel(''); } }}\n title={disabled ? `${daemon?.alias || '该 daemon'} 未声明支持此 runtime` : undefined}\n className={`flex w-full items-center justify-between rounded-md border px-3 py-2 text-sm transition-colors ${\n disabled\n ? 'border-[#1c1c1f] bg-[#0a0a0c] text-gray-600 cursor-not-allowed'\n : selected\n ? 'border-cyan-600 bg-cyan-900/15 text-cyan-200'\n : 'border-[#26262b] bg-[#0e0e10] text-gray-300 hover:border-[#3a3a41]'\n }`}\n >\n <span>\n {r.label}\n {disabled && <span className=\"ml-2 text-[10px] text-gray-700\">该 daemon 不支持</span>}\n </span>\n {selected && !disabled && (\n <svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden>\n <path d=\"M20 6 9 17l-5-5\" />\n </svg>\n )}\n </button>\n );\n })}\n </div>\n )}\n {step === 3 && (\n <label className=\"block space-y-1.5\">\n <span className=\"text-xs text-gray-400\">模型({runtime.label})</span>\n <select value={model} onChange={e => setModel(e.target.value)} className={inputCls}>\n <option value=\"\">默认({runtime.defaultModel})</option>\n {runtime.models.map(m => <option key={m} value={m}>{m}</option>)}\n </select>\n </label>\n )}\n {step === 4 && (\n <div className=\"space-y-3\">\n <label className=\"block space-y-1.5\">\n <span className=\"text-xs text-gray-400\">permissionMode</span>\n <select value={permissionMode} onChange={e => setPermissionMode(e.target.value)} className={inputCls}>\n {PERMISSION_MODES.map(m => <option key={m} value={m}>{m}</option>)}\n </select>\n </label>\n <div className=\"grid grid-cols-3 gap-2\">\n <label className=\"space-y-1\"><span className=\"text-[11px] text-gray-500\">maxTurns</span><input inputMode=\"numeric\" value={maxTurns} onChange={e => setMaxTurns(e.target.value)} className={inputCls} /></label>\n <label className=\"space-y-1\"><span className=\"text-[11px] text-gray-500\">budget</span><input inputMode=\"numeric\" value={budget} onChange={e => setBudget(e.target.value)} className={inputCls} /></label>\n <label className=\"space-y-1\"><span className=\"text-[11px] text-gray-500\">timeout</span><input inputMode=\"numeric\" value={timeout} onChange={e => setTimeout(e.target.value)} className={inputCls} /></label>\n </div>\n </div>\n )}\n {step === 5 && (\n <div className=\"space-y-2 text-sm\">\n <div className=\"rounded-md border border-[#26262b] bg-[#0e0e10] divide-y divide-[#1c1c1f]\">\n {[\n ['服务器', daemonNodeId ? `${daemonNodeId.slice(0, 24)}…` : '—'],\n ['名字', name.trim() || '—'],\n ['Runtime', runtime.label],\n ['模型', model || `默认(${runtime.defaultModel})`],\n ['permissionMode', permissionMode],\n ['maxTurns / budget / timeout', `${maxTurns || '—'} / ${budget || '—'} / ${timeout || '—'}`],\n ].map(([k, v]) => (\n <div key={k} className=\"flex items-start justify-between gap-3 px-3 py-2\">\n <span className=\"shrink-0 text-gray-500 text-xs\">{k}</span>\n <span className=\"text-right text-gray-200 text-xs break-all\">{v}</span>\n </div>\n ))}\n </div>\n </div>\n )}\n </>\n )}\n </div>\n\n {/* Footer nav */}\n {phase === 'form' ? (\n <div className=\"flex items-center justify-between border-t border-[#26262b] px-4 py-3\">\n <button type=\"button\" onClick={() => (step === 0 ? onClose() : setStep(step - 1))} className=\"rounded-md px-3 py-1.5 text-sm text-gray-400 hover:text-gray-200\">\n {step === 0 ? '取消' : '上一步'}\n </button>\n {step < STEPS.length - 1 ? (\n <button type=\"button\" disabled={!canNext} onClick={() => setStep(step + 1)} className={`rounded-md px-4 py-1.5 text-sm font-medium ${canNext ? 'bg-cyan-600 text-white hover:bg-cyan-500' : 'bg-[#1c1c1f] text-gray-600 cursor-not-allowed'}`}>\n 下一步\n </button>\n ) : (\n <button type=\"button\" onClick={handleCreate} className=\"rounded-md bg-green-600 px-4 py-1.5 text-sm font-medium text-white hover:bg-green-500\">\n 创建节点\n </button>\n )}\n </div>\n ) : (\n <div className=\"flex items-center justify-end border-t border-[#26262b] px-4 py-3\">\n <button type=\"button\" onClick={onClose} className=\"rounded-md bg-[#1c1c1f] px-4 py-1.5 text-sm text-gray-200 hover:bg-[#26262b]\">\n {phase === 'done' ? '完成' : '关闭'}\n </button>\n {(phase === 'error' || phase === 'unconfirmed') && (\n <button type=\"button\" onClick={() => setPhase('form')} className=\"ml-2 rounded-md bg-cyan-600 px-4 py-1.5 text-sm text-white hover:bg-cyan-500\">返回修改</button>\n )}\n </div>\n )}\n </div>\n </>\n );\n}\n","'use client';\n\nimport { useEffect, useState } from 'react';\n\n/**\n * PR4 #338 — host_supervisor daemon picker (RFC-026 §9.4 locked mockup).\n *\n * Three states (the only branching the wizard ever sees):\n *\n * count=0 → onboarding: explain what a daemon is + give the install command.\n * No daemon = nothing to dispatch to; create flow is blocked here\n * until the user runs `anet daemon init <name>` somewhere.\n *\n * count=1 → auto-pick: just show \"using <alias>\" + a quiet `换一个 →` link\n * (which switches to the picker view if the user really wants).\n *\n * count≥2 → picker grid: cards for each daemon w/ runtimes + alert chip,\n * click selects. Desktop = up to 3 columns; mobile = single column.\n *\n * Data shape mirrors `/api/anet/host-supervisors`, which in turn mirrors the\n * hub's GET /api/host-supervisors (#338 PR2 — needs commhub-server@0.9.0-preview.8+).\n * On `unconfirmed` (older hub), we degrade honestly to an upgrade hint — never\n * show a fake empty list. Per [[feedback_doc_capability_claim_verify_code_path]].\n */\n\nexport interface DaemonOption {\n // Hub canonical key is `daemon_node_id` (PR2 v2 §9.2 contract). We keep the\n // same name end-to-end so the value the wizard passes back to create_node\n // as `daemon_node_id` doesn't need a rename layer.\n daemon_node_id: string;\n alias: string;\n hostname?: string | null;\n online?: boolean;\n last_seen_at?: string | null;\n runtimes_supported?: string[];\n host_telemetry?: {\n alert_level?: 'green' | 'yellow' | 'red' | 'gray';\n cpu_cores?: number | null;\n mem_gb?: number | null;\n ip_internal?: string | null;\n };\n}\n\ninterface PickResponse {\n ok: boolean;\n unconfirmed?: boolean;\n error?: string;\n count: number;\n daemons: DaemonOption[];\n selected?: string | null;\n}\n\ntype LoadState = 'loading' | 'ready' | 'error' | 'unconfirmed';\n\nexport function HostSupervisorPicker({\n networkId,\n value,\n onChange,\n}: {\n networkId?: string | null;\n value: string | null;\n // (#338 wizard-runtime-filter) passes the full daemon row alongside the\n // id so the wizard can filter the Runtime step by daemon.runtimes_supported\n // — disabling combos the hub would reject anyway and surfacing why upfront.\n onChange: (nodeId: string | null, daemon: DaemonOption | null) => void;\n}) {\n const [state, setState] = useState<LoadState>('loading');\n const [daemons, setDaemons] = useState<DaemonOption[]>([]);\n const [errMsg, setErrMsg] = useState('');\n const [forcePicker, setForcePicker] = useState(false);\n\n useEffect(() => {\n let alive = true;\n setState('loading');\n setErrMsg('');\n const url = networkId\n ? `/api/anet/host-supervisors?network_id=${encodeURIComponent(networkId)}`\n : '/api/anet/host-supervisors';\n fetch(url, { cache: 'no-store' })\n .then(r => r.json().then(d => ({ status: r.status, body: d as PickResponse })))\n .then(({ status, body }) => {\n if (!alive) return;\n if (status === 501 || body?.unconfirmed) {\n setState('unconfirmed');\n setErrMsg(body?.error || 'hub /api/host-supervisors unavailable — upgrade to >=0.9.0-preview.8');\n setDaemons([]);\n return;\n }\n if (!body?.ok) {\n setState('error');\n setErrMsg(body?.error || `hub ${status}`);\n setDaemons([]);\n return;\n }\n const list = Array.isArray(body.daemons) ? body.daemons : [];\n setDaemons(list);\n setState('ready');\n // count=1 auto-pick: preselect the only daemon. count≥2 leaves the\n // selection to the user (parent value stays null until click).\n if (list.length === 1 && !value) onChange(list[0].daemon_node_id, list[0]);\n })\n .catch(e => {\n if (!alive) return;\n setState('error');\n setErrMsg(e instanceof Error ? e.message : String(e));\n setDaemons([]);\n });\n return () => { alive = false; };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [networkId]);\n\n // ───── render branches ──────────────────────────────────────────────\n\n if (state === 'loading') {\n return (\n <div className=\"flex items-center gap-2 rounded-md border border-[#26262b] bg-[#0e0e10] px-3 py-3 text-xs text-gray-500\">\n <svg className=\"h-3.5 w-3.5 animate-spin\" viewBox=\"0 0 24 24\" fill=\"none\" aria-hidden>\n <circle className=\"opacity-25\" cx=\"12\" cy=\"12\" r=\"10\" stroke=\"currentColor\" strokeWidth=\"4\" />\n <path className=\"opacity-90\" fill=\"currentColor\" d=\"M4 12a8 8 0 018-8v4a4 4 0 00-4 4H4z\" />\n </svg>\n 正在查询可用的 host_supervisor 节点…\n </div>\n );\n }\n\n if (state === 'unconfirmed') {\n return (\n <div className=\"rounded-md border border-amber-700/40 bg-amber-900/10 px-3 py-3 text-xs text-amber-200\">\n <div className=\"font-semibold mb-1\">hub 暂未升级</div>\n <div className=\"text-amber-200/80\">{errMsg}</div>\n <div className=\"mt-1 text-[11px] text-amber-200/60\">\n 升级到 <code className=\"rounded bg-black/40 px-1 py-0.5\">@sleep2agi/commhub-server@0.9.0-preview.8</code> 后选服务器功能才会出现。\n </div>\n </div>\n );\n }\n\n if (state === 'error') {\n return (\n <div className=\"rounded-md border border-red-700/40 bg-red-900/10 px-3 py-3 text-xs text-red-200\">\n 查询 host_supervisor 节点失败:{errMsg}\n </div>\n );\n }\n\n // count=0 — onboarding\n if (daemons.length === 0) {\n return (\n <div className=\"rounded-md border border-[#26262b] bg-[#0e0e10] px-3 py-4 text-xs text-gray-300\">\n <div className=\"text-sm font-semibold text-gray-200\">还没有可用的 host_supervisor 节点</div>\n <p className=\"mt-1 text-gray-500\">\n 要在某台机器上创建节点,先在那台机器上跑一次 daemon 初始化命令:\n </p>\n <pre className=\"mt-2 overflow-x-auto rounded bg-black/40 p-2 text-[11px] text-cyan-300\">{`# 任选一台目标机器(你的笔记本 / 一台服务器都行)\nanet daemon up my-daemon`}</pre>\n <p className=\"mt-2 text-gray-500\">\n 注册成功后这里会自动出现,无需刷新。\n </p>\n </div>\n );\n }\n\n // count=1 — auto-pick (collapsed). User can opt into picker via \"换一个 →\".\n if (daemons.length === 1 && !forcePicker) {\n const d = daemons[0];\n return (\n <div className=\"rounded-md border border-cyan-700/40 bg-cyan-900/10 px-3 py-3 text-xs text-cyan-100\">\n <div className=\"flex items-center justify-between gap-2\">\n <div>\n <span className=\"text-cyan-400/80\">将在</span>{' '}\n <span className=\"font-semibold\">{d.alias}</span>\n <span className=\"text-cyan-300/60\"> ({d.hostname || '—'}) </span>\n <span className=\"text-cyan-400/80\">上创建</span>\n </div>\n {/* Single-daemon networks can still let the user enter picker view; */}\n {/* useful if they want to see telemetry before committing. */}\n <button\n type=\"button\"\n onClick={() => setForcePicker(true)}\n className=\"text-[11px] text-cyan-400 hover:text-cyan-200 underline-offset-2 hover:underline\"\n >\n 详情 →\n </button>\n </div>\n <RuntimeList runtimes={d.runtimes_supported} className=\"mt-1\" />\n </div>\n );\n }\n\n // count≥2 (or forcePicker=true) — grid picker. Desktop up to 3 columns,\n // mobile = single column. Locked per RFC-026 §9.4 mockup.\n return (\n <div className=\"space-y-2\">\n <div className=\"flex items-center justify-between text-xs text-gray-400\">\n <span>选择一台 host_supervisor 节点({daemons.length} 台在线)</span>\n {forcePicker && daemons.length === 1 && (\n <button\n type=\"button\"\n onClick={() => setForcePicker(false)}\n className=\"text-[11px] text-gray-500 hover:text-gray-300\"\n >\n ← 折叠\n </button>\n )}\n </div>\n <div className=\"grid grid-cols-1 gap-2 md:grid-cols-2 lg:grid-cols-3\">\n {daemons.map(d => (\n <DaemonCard\n key={d.daemon_node_id}\n daemon={d}\n selected={d.daemon_node_id === value}\n onClick={() => onChange(d.daemon_node_id, d)}\n />\n ))}\n </div>\n </div>\n );\n}\n\n// ───── subcomponents ──────────────────────────────────────────────────\n\nfunction DaemonCard({\n daemon,\n selected,\n onClick,\n}: {\n daemon: DaemonOption;\n selected: boolean;\n onClick: () => void;\n}) {\n const alert = daemon.host_telemetry?.alert_level || 'gray';\n return (\n <button\n type=\"button\"\n onClick={onClick}\n aria-pressed={selected}\n className={`flex w-full flex-col gap-1.5 rounded-md border px-3 py-2.5 text-left text-xs transition-colors ${\n selected\n ? 'border-cyan-600 bg-cyan-900/15 text-cyan-100'\n : 'border-[#26262b] bg-[#0e0e10] text-gray-300 hover:border-[#3a3a41]'\n }`}\n >\n <div className=\"flex items-center justify-between gap-2\">\n <span className=\"truncate font-semibold\">{daemon.alias}</span>\n <AlertChip level={alert} />\n </div>\n <div className=\"truncate text-[11px] text-gray-500\">{daemon.hostname || '—'}</div>\n <RuntimeList runtimes={daemon.runtimes_supported} />\n {(daemon.host_telemetry?.cpu_cores != null || daemon.host_telemetry?.mem_gb != null) && (\n <div className=\"flex gap-3 text-[10px] text-gray-500\">\n {daemon.host_telemetry?.cpu_cores != null && <span>{daemon.host_telemetry.cpu_cores} 核</span>}\n {daemon.host_telemetry?.mem_gb != null && <span>{daemon.host_telemetry.mem_gb} GB</span>}\n </div>\n )}\n </button>\n );\n}\n\nfunction RuntimeList({ runtimes, className = '' }: { runtimes?: string[]; className?: string }) {\n if (!runtimes || runtimes.length === 0) {\n return <div className={`text-[10px] text-gray-600 ${className}`}>runtimes_supported: —</div>;\n }\n return (\n <div className={`flex flex-wrap gap-1 ${className}`}>\n {runtimes.map(r => (\n <span key={r} className=\"rounded bg-[#1c1c1f] px-1.5 py-0.5 text-[10px] text-gray-400\">{r}</span>\n ))}\n </div>\n );\n}\n\nfunction AlertChip({ level }: { level: 'green' | 'yellow' | 'red' | 'gray' }) {\n const cls = {\n green: 'bg-green-600/20 text-green-300 border-green-700/40',\n yellow: 'bg-amber-600/20 text-amber-300 border-amber-700/40',\n red: 'bg-red-600/20 text-red-300 border-red-700/40',\n gray: 'bg-gray-600/20 text-gray-400 border-gray-700/40',\n }[level];\n const label = { green: '正常', yellow: '注意', red: '警报', gray: '离线' }[level];\n return (\n <span className={`rounded border px-1.5 py-0.5 text-[10px] ${cls}`}>{label}</span>\n );\n}\n","'use client';\n\nimport { AliasAvatar } from './AliasAvatar';\nimport { useChatUnread } from '../lib/chat-unread';\nimport { useHasDraft } from '../lib/chat-drafts';\nimport type { Session } from './types';\nimport { t } from '../lib/ui-lang';\n\n// #Stage A (dashboard 3-col): persistent narrow node list rail —\n// WeChat-style entries (avatar + alias + activity preview + unread badge)\n// that stay visible while user reads/interacts with the table on the\n// right OR opens a chat popover. The point is not \"look like Feishu\";\n// the point is \"node list and chat panel are visible at the same time,\n// switching between nodes takes zero operations\" (通信龙, 07-31).\n//\n// Test-hook contract:\n// - Rail entries carry `data-node-list-item` + `data-node-list-alias`.\n// Deliberately distinct from the table's `data-node-card` /\n// `data-node-alias` so #492's exact-count assertions on the table\n// view stay valid (rail and table would otherwise both match and\n// `toHaveCount(1)` would break).\n// - Selected entry gets `data-selected=\"true\"` for keyboard/screen-\n// reader affordance and future tests.\n\ntype SessionRow = Session & { online: boolean };\n\nexport interface NodeListProps {\n /** The already-filtered list from NodesPage — rail mirrors what the\n * table shows, not a second filter chain. Sharing keeps the two\n * views from disagreeing while filter chips are being toggled. */\n sessions: SessionRow[];\n /** Currently-selected alias (drives visual highlight). Passing null\n * means nothing selected — the rail still lists everything. */\n selectedAlias: string | null;\n /** Called when the user clicks an entry. Parent decides what to do\n * with it (open ChatPopover, navigate, etc). Stage A keeps the\n * existing ChatPopover behavior; Stage B may swap this for URL\n * navigation. */\n onSelect: (alias: string) => void;\n}\n\nfunction LastLine({ alias, session }: { alias: string; session: SessionRow }) {\n const draft = useHasDraft(alias);\n if (draft) {\n return (\n <span className=\"text-[11px] text-red-400/90 truncate\" aria-label={t('有未发送草稿', 'Unsent draft')}>\n {t('[草稿]', '[draft]')} {session.task ? session.task.slice(0, 40) : ''}\n </span>\n );\n }\n if (session.task) {\n return <span className=\"text-[11px] text-gray-500 truncate\">{session.task}</span>;\n }\n if (!session.online) {\n return <span className=\"text-[11px] text-gray-600 italic\">{t('离线', 'offline')}</span>;\n }\n return <span className=\"text-[11px] text-gray-600\">{t('空闲', 'idle')}</span>;\n}\n\nexport function NodeList({ sessions, selectedAlias, onSelect }: NodeListProps) {\n const { unreadCount } = useChatUnread();\n\n return (\n <div\n data-node-list-rail\n data-node-list-count={sessions.length}\n className=\"flex flex-col w-full overflow-hidden bg-[#111113] border-r border-[#26262b]\"\n aria-label={t('节点列表', 'Node list')}\n >\n <div className=\"px-3 py-2 text-[11px] text-gray-500 tracking-wide uppercase border-b border-[#1e1e22] shrink-0\">\n {t(`节点 ${sessions.length}`, `Nodes · ${sessions.length}`)}\n </div>\n <div className=\"flex-1 min-h-0 overflow-y-auto\">\n {sessions.length === 0 ? (\n <div className=\"p-4 text-[11px] text-gray-600\">\n {t('列表为空 —— 右侧的筛选控件或空态说明会告诉你原因。', 'Rail is empty — the filter controls or empty state on the right explain why.')}\n </div>\n ) : (\n sessions.map(s => {\n const selected = s.alias === selectedAlias;\n const unread = unreadCount(s.alias);\n return (\n <button\n key={s.alias}\n type=\"button\"\n data-node-list-item\n data-node-list-alias={s.alias}\n data-selected={selected ? 'true' : 'false'}\n onClick={() => onSelect(s.alias)}\n className={`w-full flex items-center gap-2.5 px-3 py-2.5 text-left transition-colors border-b border-[#1a1a1d] ${\n selected ? 'bg-cyan-500/8' : 'hover:bg-[#161618]'\n }`}\n >\n <div className=\"relative shrink-0\">\n <AliasAvatar alias={s.alias} size={32} />\n {s.online && (\n <span\n aria-hidden\n className=\"absolute -bottom-0.5 -right-0.5 w-2.5 h-2.5 rounded-full bg-green-400 ring-2 ring-[#111113]\"\n />\n )}\n </div>\n <div className=\"flex-1 min-w-0\">\n <div className=\"flex items-center justify-between gap-2\">\n <span className={`text-[13px] truncate ${selected ? 'text-cyan-200 font-medium' : 'text-gray-200'}`}>\n {s.alias}\n </span>\n {unread > 0 && (\n <span\n aria-label={t(`${unread} 条未读`, `${unread} unread`)}\n className=\"shrink-0 min-w-[16px] h-4 px-1 rounded-full bg-red-500 text-white text-[9px] font-semibold leading-4 text-center\"\n >\n {unread > 99 ? '99+' : unread}\n </span>\n )}\n </div>\n <div className=\"mt-0.5 flex items-center gap-1.5\">\n <LastLine alias={s.alias} session={s} />\n </div>\n </div>\n </button>\n );\n })\n )}\n </div>\n </div>\n );\n}\n","'use client';\n\nimport { AliasAvatar } from './AliasAvatar';\nimport { TaskChatPanel } from './TaskChatPanel';\nimport { t } from '../lib/ui-lang';\n\n// #Stage B (dashboard 3-col): the persistent right chat column on /nodes.\n// This is ChatPopover with the floating shell stripped: no drag, no resize,\n// no viewport-clamped positioning — just a column header + TaskChatPanel's\n// `inline` body (the same body ChatPopover embeds), so send / SSE / history\n// / drafts behave identically in popover, overlay, and pane.\n//\n// #Stage C: flex-1 — when a node is selected the middle table no longer\n// renders (NodesView.chatOpenDesktop), so the pane takes all width right\n// of the rail instead of being squeezed to a fixed sliver by the table.\n//\n// Test-hook contract: `data-testid=\"chat-pane\"` + `data-chat-alias` are the\n// Stage B assertions' anchors. Deliberately does NOT render any\n// [data-node-card] / [data-node-alias] — those belong exclusively to the\n// table in NodesView (#492 exact-count contract).\nexport interface ChatPaneProps {\n /** Node alias to chat with. Changing it swaps the conversation in place. */\n alias: string;\n /** Close the pane (unselect + URL back to /nodes — parent owns both). */\n onClose: () => void;\n}\n\nexport function ChatPane({ alias, onClose }: ChatPaneProps) {\n return (\n <aside\n data-testid=\"chat-pane\"\n data-chat-alias={alias}\n className=\"hidden md:flex md:flex-col flex-1 min-w-0 h-screen sticky top-0 border-l border-[#26262b] bg-[var(--bg)]\"\n >\n <div className=\"flex items-center justify-between gap-2 px-3 py-2.5 border-b border-[#26262b] bg-[#111113] shrink-0\">\n <div className=\"flex items-center gap-2 min-w-0\">\n <AliasAvatar alias={alias} size={26} />\n <span className=\"truncate text-sm font-semibold text-white\">{alias}</span>\n </div>\n <button\n type=\"button\"\n onClick={onClose}\n aria-label={t('关闭会话', 'Close chat')}\n data-testid=\"chat-pane-close\"\n className=\"inline-flex h-8 w-8 items-center justify-center rounded-lg text-gray-500 hover:text-gray-200 hover:bg-[#1c1c1f] transition-colors\"\n >\n <svg className=\"w-4 h-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={2}>\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n </button>\n </div>\n <div className=\"flex-1 min-h-0\">\n <TaskChatPanel alias={alias} onClose={onClose} inline />\n </div>\n </aside>\n );\n}\n"],"names":["HostSupervisorPicker","networkId","value","onChange","state","setState","daemons","setDaemons","errMsg","setErrMsg","forcePicker","setForcePicker","alive","url","encodeURIComponent","fetch","cache","then","r","json","d","status","body","unconfirmed","error","ok","list","Array","isArray","length","daemon_node_id","catch","e","Error","message","String","className","viewBox","fill","cx","cy","stroke","strokeWidth","alias","hostname","type","onClick","RuntimeList","runtimes","runtimes_supported","map","DaemonCard","daemon","selected","alert","host_telemetry","alert_level","AlertChip","level","cpu_cores","mem_gb","cls","green","yellow","red","gray","label"],"mappings":"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"}