agent-relay-server 0.35.4 → 0.36.0

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 (125) hide show
  1. package/docs/openapi.json +68 -1
  2. package/package.json +2 -2
  3. package/public/assets/{activity-CPuZGkeP.js → activity-DVdEofAq.js} +2 -2
  4. package/public/assets/{activity-CPuZGkeP.js.map → activity-DVdEofAq.js.map} +1 -1
  5. package/public/assets/{agent-profiles-Bs8MAW6j.js → agent-profiles-BiQ-5F3l.js} +2 -2
  6. package/public/assets/{agent-profiles-Bs8MAW6j.js.map → agent-profiles-BiQ-5F3l.js.map} +1 -1
  7. package/public/assets/agents-Dt4FBBnk.js +2 -0
  8. package/public/assets/agents-Dt4FBBnk.js.map +1 -0
  9. package/public/assets/{analytics-inmkBD_j.js → analytics-BeUxZhkP.js} +3 -3
  10. package/public/assets/{analytics-inmkBD_j.js.map → analytics-BeUxZhkP.js.map} +1 -1
  11. package/public/assets/{automation-DRN2lcqQ.js → automation--G9ZMkL6.js} +2 -2
  12. package/public/assets/{automation-DRN2lcqQ.js.map → automation--G9ZMkL6.js.map} +1 -1
  13. package/public/assets/{badge-t8zAwHW9.js → badge-JVybSpzR.js} +2 -2
  14. package/public/assets/{badge-t8zAwHW9.js.map → badge-JVybSpzR.js.map} +1 -1
  15. package/public/assets/{branch-state-badge-EliCEAQI.js → branch-state-badge-BTqHF74k.js} +2 -2
  16. package/public/assets/{branch-state-badge-EliCEAQI.js.map → branch-state-badge-BTqHF74k.js.map} +1 -1
  17. package/public/assets/{button-DDA5P2YQ.js → button-BsMqBNJb.js} +2 -2
  18. package/public/assets/{button-DDA5P2YQ.js.map → button-BsMqBNJb.js.map} +1 -1
  19. package/public/assets/card-I8w4U656.js +2 -0
  20. package/public/assets/{card-CggxP1h9.js.map → card-I8w4U656.js.map} +1 -1
  21. package/public/assets/{channels-BzSpsE5h.js → channels-nqTHGf6J.js} +2 -2
  22. package/public/assets/{channels-BzSpsE5h.js.map → channels-nqTHGf6J.js.map} +1 -1
  23. package/public/assets/chat-DALcMlDH.js +2 -0
  24. package/public/assets/chat-DALcMlDH.js.map +1 -0
  25. package/public/assets/{connectors-DoUgct8f.js → connectors-ChkEg-0q.js} +2 -2
  26. package/public/assets/{connectors-DoUgct8f.js.map → connectors-ChkEg-0q.js.map} +1 -1
  27. package/public/assets/copy-button-B-XlL8nF.js +2 -0
  28. package/public/assets/{copy-button-CE8e2c-F.js.map → copy-button-B-XlL8nF.js.map} +1 -1
  29. package/public/assets/display-ConJ9cJB.js +3 -0
  30. package/public/assets/{display-Bebqs1qu.js.map → display-ConJ9cJB.js.map} +1 -1
  31. package/public/assets/{dist-CiWi_f7V.js → dist-BQ52MnS1.js} +2 -2
  32. package/public/assets/{dist-CiWi_f7V.js.map → dist-BQ52MnS1.js.map} +1 -1
  33. package/public/assets/{dist-CHi40_tZ.js → dist-BgfF2Rlm.js} +2 -2
  34. package/public/assets/{dist-CHi40_tZ.js.map → dist-BgfF2Rlm.js.map} +1 -1
  35. package/public/assets/dist-CnJzBTp1.js +2 -0
  36. package/public/assets/{dist-DTLaCErY.js.map → dist-CnJzBTp1.js.map} +1 -1
  37. package/public/assets/{dist-xorgjFcF.js → dist-CrBurS6i.js} +2 -2
  38. package/public/assets/{dist-xorgjFcF.js.map → dist-CrBurS6i.js.map} +1 -1
  39. package/public/assets/dist-D6iXJzms.js +2 -0
  40. package/public/assets/{dist-BmYJ5xuf.js.map → dist-D6iXJzms.js.map} +1 -1
  41. package/public/assets/{dist-CkiXMjV0.js → dist-DRlgXPi_.js} +2 -2
  42. package/public/assets/{dist-CkiXMjV0.js.map → dist-DRlgXPi_.js.map} +1 -1
  43. package/public/assets/{dist-B3igiXqp.js → dist-DSNhRDNh.js} +2 -2
  44. package/public/assets/{dist-B3igiXqp.js.map → dist-DSNhRDNh.js.map} +1 -1
  45. package/public/assets/{dist-C3Yx04R4.js → dist-SqFV12iO.js} +2 -2
  46. package/public/assets/{dist-C3Yx04R4.js.map → dist-SqFV12iO.js.map} +1 -1
  47. package/public/assets/{es2015-BDK_SBFZ.js → es2015-iucXYTIE.js} +2 -2
  48. package/public/assets/{es2015-BDK_SBFZ.js.map → es2015-iucXYTIE.js.map} +1 -1
  49. package/public/assets/{formatted-body-impl-DP9iZsd4.js → formatted-body-impl-D1K3GML5.js} +2 -2
  50. package/public/assets/{formatted-body-impl-DP9iZsd4.js.map → formatted-body-impl-D1K3GML5.js.map} +1 -1
  51. package/public/assets/index-DUxpx-Zp.css +2 -0
  52. package/public/assets/index-DdB6SVZY.js +21 -0
  53. package/public/assets/index-DdB6SVZY.js.map +1 -0
  54. package/public/assets/{input-BW9UD3FM.js → input-dPzf0luy.js} +2 -2
  55. package/public/assets/{input-BW9UD3FM.js.map → input-dPzf0luy.js.map} +1 -1
  56. package/public/assets/{insights-yJFgCa3o.js → insights-5CDeJfoX.js} +2 -2
  57. package/public/assets/{insights-yJFgCa3o.js.map → insights-5CDeJfoX.js.map} +1 -1
  58. package/public/assets/{integrations-CUv4i_4i.js → integrations-C8839Qa0.js} +2 -2
  59. package/public/assets/{integrations-CUv4i_4i.js.map → integrations-C8839Qa0.js.map} +1 -1
  60. package/public/assets/{lib-ZEIADKGq.js → lib-BAE--T4O.js} +3 -3
  61. package/public/assets/{lib-ZEIADKGq.js.map → lib-BAE--T4O.js.map} +1 -1
  62. package/public/assets/lucide-react-DLQFnqNm.js +9 -0
  63. package/public/assets/{lucide-react-CD8Xl2U3.js.map → lucide-react-DLQFnqNm.js.map} +1 -1
  64. package/public/assets/{maintenance-DtfpsMZa.js → maintenance-Ddl4zgKZ.js} +2 -2
  65. package/public/assets/{maintenance-DtfpsMZa.js.map → maintenance-Ddl4zgKZ.js.map} +1 -1
  66. package/public/assets/{managed-agents-C5pzetBh.js → managed-agents-D-K6vUKj.js} +2 -2
  67. package/public/assets/{managed-agents-C5pzetBh.js.map → managed-agents-D-K6vUKj.js.map} +1 -1
  68. package/public/assets/{markdown-preview-impl-4s9YDGM7.js → markdown-preview-impl-BjS4cnc3.js} +2 -2
  69. package/public/assets/{markdown-preview-impl-4s9YDGM7.js.map → markdown-preview-impl-BjS4cnc3.js.map} +1 -1
  70. package/public/assets/memory-BTV0z4uL.js +2 -0
  71. package/public/assets/{memory-BWfDbph3.js.map → memory-BTV0z4uL.js.map} +1 -1
  72. package/public/assets/{messages-C8cP25kp.js → messages-CzHsL-om.js} +2 -2
  73. package/public/assets/{messages-C8cP25kp.js.map → messages-CzHsL-om.js.map} +1 -1
  74. package/public/assets/{orchestrators-Clu8MNKo.js → orchestrators-PMUp2sUP.js} +2 -2
  75. package/public/assets/{orchestrators-Clu8MNKo.js.map → orchestrators-PMUp2sUP.js.map} +1 -1
  76. package/public/assets/{overview-CXcGh2D6.js → overview-B_od6jh0.js} +2 -2
  77. package/public/assets/{overview-CXcGh2D6.js.map → overview-B_od6jh0.js.map} +1 -1
  78. package/public/assets/pairs-CaxiFyfY.js +2 -0
  79. package/public/assets/{pairs-eOZl_lQn.js.map → pairs-CaxiFyfY.js.map} +1 -1
  80. package/public/assets/{react-dom-CX8inunm.js → react-dom-CzfKBOnw.js} +2 -2
  81. package/public/assets/{react-dom-CX8inunm.js.map → react-dom-CzfKBOnw.js.map} +1 -1
  82. package/public/assets/{security-CA03sHyP.js → security-BZYHZ4CE.js} +2 -2
  83. package/public/assets/{security-CA03sHyP.js.map → security-BZYHZ4CE.js.map} +1 -1
  84. package/public/assets/{settings-KTOwGJiW.js → settings-RLyewdfK.js} +7 -7
  85. package/public/assets/{settings-KTOwGJiW.js.map → settings-RLyewdfK.js.map} +1 -1
  86. package/public/assets/store-CMUFZKxf.js +9 -0
  87. package/public/assets/store-CMUFZKxf.js.map +1 -0
  88. package/public/assets/{switch-22dlDUXs.js → switch-W2_mhdrR.js} +2 -2
  89. package/public/assets/{switch-22dlDUXs.js.map → switch-W2_mhdrR.js.map} +1 -1
  90. package/public/assets/tasks-BYTcfYDQ.js +2 -0
  91. package/public/assets/{tasks-D6jbr2y6.js.map → tasks-BYTcfYDQ.js.map} +1 -1
  92. package/public/assets/{terminal-viewer-impl-DFODXxpG.js → terminal-viewer-impl-B5rPCNkZ.js} +3 -3
  93. package/public/assets/{terminal-viewer-impl-DFODXxpG.js.map → terminal-viewer-impl-B5rPCNkZ.js.map} +1 -1
  94. package/public/assets/{use-keyboard-viewport-DxY_xJV5.js → use-keyboard-viewport-bZ1J-ZnH.js} +2 -2
  95. package/public/assets/{use-keyboard-viewport-DxY_xJV5.js.map → use-keyboard-viewport-bZ1J-ZnH.js.map} +1 -1
  96. package/public/assets/work-queue-DYgqkTQD.js +2 -0
  97. package/public/assets/{work-queue-BWWckTVy.js.map → work-queue-DYgqkTQD.js.map} +1 -1
  98. package/public/assets/{workspaces-D7lsWShY.js → workspaces-Dkq9DxCL.js} +3 -3
  99. package/public/assets/{workspaces-D7lsWShY.js.map → workspaces-Dkq9DxCL.js.map} +1 -1
  100. package/public/index.html +20 -20
  101. package/src/db/message-reads.ts +54 -1
  102. package/src/db/migrations.ts +1 -0
  103. package/src/routes/_shared.ts +2 -1
  104. package/src/routes/agents.ts +21 -2
  105. package/src/routes/index.ts +2 -1
  106. package/src/sse.ts +7 -2
  107. package/public/assets/agents-Bz4eJ4zH.js +0 -2
  108. package/public/assets/agents-Bz4eJ4zH.js.map +0 -1
  109. package/public/assets/card-CggxP1h9.js +0 -2
  110. package/public/assets/chat-Dn3TEhl0.js +0 -2
  111. package/public/assets/chat-Dn3TEhl0.js.map +0 -1
  112. package/public/assets/copy-button-CE8e2c-F.js +0 -2
  113. package/public/assets/display-Bebqs1qu.js +0 -3
  114. package/public/assets/dist-BmYJ5xuf.js +0 -2
  115. package/public/assets/dist-DTLaCErY.js +0 -2
  116. package/public/assets/index-BL8r94_U.js +0 -21
  117. package/public/assets/index-BL8r94_U.js.map +0 -1
  118. package/public/assets/index-DeSwlD3c.css +0 -2
  119. package/public/assets/lucide-react-CD8Xl2U3.js +0 -9
  120. package/public/assets/memory-BWfDbph3.js +0 -2
  121. package/public/assets/pairs-eOZl_lQn.js +0 -2
  122. package/public/assets/store-CICRhg1m.js +0 -9
  123. package/public/assets/store-CICRhg1m.js.map +0 -1
  124. package/public/assets/tasks-D6jbr2y6.js +0 -2
  125. package/public/assets/work-queue-BWWckTVy.js +0 -2
@@ -1 +1 @@
1
- {"version":3,"file":"messages-C8cP25kp.js","names":[],"sources":["../../dashboard/src/components/views/messages.tsx"],"sourcesContent":["import { useMemo, useState } from 'react'\nimport { useRelayStore, useNow } from '@/store'\nimport { useComposeAgents, useUniqueTags } from '@/hooks/use-selectors'\nimport { Card, CardContent } from '@/components/ui/card'\nimport { Badge } from '@/components/ui/badge'\nimport { Button } from '@/components/ui/button'\nimport { Input } from '@/components/ui/input'\nimport { FormattedBody } from '@/components/shared/formatted-body'\nimport {\n Mail, Pencil, MessageSquareReply, CheckCircle2, Trash2, X, Hash, AlertTriangle, RotateCcw, Ban,\n} from 'lucide-react'\nimport { displayName, displayTarget, messageBody, timeAgo, fmtTime } from '@/lib/display'\nimport type { Message } from '@/types'\n\nfunction resolveRelativePath(cwd: string, path: string): string {\n if (path.startsWith('/')) return path\n const parts = `${cwd.replace(/\\/+$/, '')}/${path}`.split('/')\n const stack: string[] = []\n for (const part of parts) {\n if (!part || part === '.') continue\n if (part === '..') stack.pop()\n else stack.push(part)\n }\n return '/' + stack.join('/')\n}\n\nfunction parentPath(path: string): string {\n const trimmed = path.replace(/\\/+$/, '')\n const index = trimmed.lastIndexOf('/')\n return index > 0 ? trimmed.slice(0, index) : '/'\n}\n\nexport function MessagesView() {\n const now = useNow()\n const messages = useRelayStore((s) => s.messages)\n const agentsById = useRelayStore((s) => s.agentsById)\n const selectedAgent = useRelayStore((s) => s.selectedAgent)\n const channelFilter = useRelayStore((s) => s.channelFilter)\n const tagFilter = useRelayStore((s) => s.tagFilter)\n const replyTo = useRelayStore((s) => s.replyTo)\n const set = useRelayStore((s) => s.set)\n const openCompose = useRelayStore((s) => s.openCompose)\n const startReply = useRelayStore((s) => s.startReply)\n const doClaim = useRelayStore((s) => s.doClaim)\n const doDeliveryAction = useRelayStore((s) => s.doDeliveryAction)\n const doDeleteMessage = useRelayStore((s) => s.doDeleteMessage)\n const openThread = useRelayStore((s) => s.openThread)\n const cancelReply = useRelayStore((s) => s.cancelReply)\n\n const composeAgents = useComposeAgents()\n const uniqueTags = useUniqueTags()\n\n const filtered = useMemo(() => {\n let list = [...messages].sort((a, b) => b.id - a.id)\n if (selectedAgent) list = list.filter((m) => m.from === selectedAgent || m.to === selectedAgent)\n if (channelFilter) list = list.filter((m) => m.channel === channelFilter)\n if (tagFilter) list = list.filter((m) => {\n const agent = agentsById[m.from] || agentsById[m.to]\n return (agent?.tags || []).includes(tagFilter)\n })\n return list\n }, [messages, selectedAgent, channelFilter, tagFilter, agentsById])\n\n // Group by threadId — show root messages, collapse replies\n const grouped = useMemo(() => {\n const roots: Message[] = []\n const threads = new Map<number, Message[]>()\n for (const msg of filtered) {\n const tid = msg.threadId ?? msg.id\n if (!threads.has(tid)) threads.set(tid, [])\n threads.get(tid)!.push(msg)\n if (msg.id === tid) roots.push(msg)\n }\n // messages without a known root\n const seenRoots = new Set(roots.map((r) => r.id))\n for (const msg of filtered) {\n if (!seenRoots.has(msg.threadId ?? msg.id) && !roots.find((r) => r.id === msg.id)) {\n roots.push(msg)\n }\n }\n roots.sort((a, b) => b.id - a.id)\n return roots.map((r) => ({ root: r, replies: (threads.get(r.id) || []).filter((m) => m.id !== r.id).sort((a, b) => a.id - b.id) }))\n }, [filtered])\n\n function agentLabel(id: string) {\n return agentsById[id] ? displayName(agentsById[id]) : id.slice(-10)\n }\n\n const uniqueChannels = useMemo(() => {\n return [...new Set(messages.map((m) => m.channel).filter(Boolean) as string[])]\n }, [messages])\n\n return (\n <div className=\"space-y-4\">\n <div className=\"flex items-center justify-between flex-wrap gap-2\">\n <div className=\"flex items-center gap-2\">\n <Mail className=\"w-5 h-5 text-muted-foreground\" />\n <h2 className=\"text-lg font-semibold\">Messages</h2>\n <Badge variant=\"secondary\">{filtered.length}</Badge>\n </div>\n <Button size=\"sm\" onClick={openCompose}>\n <Pencil className=\"w-4 h-4 mr-1\" /> Compose\n </Button>\n </div>\n\n <div className=\"flex flex-wrap gap-2\">\n <select\n className=\"rounded-md border border-input bg-background px-3 py-1.5 text-sm\"\n value={selectedAgent}\n onChange={(e) => set({ selectedAgent: e.target.value })}\n >\n <option value=\"\">All agents</option>\n {composeAgents.map((a) => <option key={a.id} value={a.id}>{displayName(a)}</option>)}\n </select>\n <select\n className=\"rounded-md border border-input bg-background px-3 py-1.5 text-sm\"\n value={tagFilter}\n onChange={(e) => set({ tagFilter: e.target.value })}\n >\n <option value=\"\">All tags</option>\n {uniqueTags.map((t) => <option key={t} value={t}>#{t}</option>)}\n </select>\n <select\n className=\"rounded-md border border-input bg-background px-3 py-1.5 text-sm\"\n value={channelFilter}\n onChange={(e) => set({ channelFilter: e.target.value })}\n >\n <option value=\"\">All channels</option>\n {uniqueChannels.map((c) => <option key={c} value={c}>{c}</option>)}\n </select>\n </div>\n\n {replyTo && (\n <div className=\"flex items-center gap-2 rounded-md bg-blue-500/10 border border-blue-500/20 px-3 py-2 text-sm text-blue-300\">\n <MessageSquareReply className=\"w-4 h-4 shrink-0\" />\n <span>Replying to message #{replyTo.id} from <strong>{agentLabel(replyTo.from)}</strong></span>\n <Button variant=\"ghost\" size=\"sm\" className=\"ml-auto h-6 px-1.5\" onClick={cancelReply}>\n <X className=\"w-3.5 h-3.5\" />\n </Button>\n </div>\n )}\n\n <div className=\"h-[calc(100dvh-15rem)] overflow-y-auto\">\n <div className=\"space-y-2 pr-2\">\n {grouped.length === 0 && (\n <div className=\"text-center text-muted-foreground py-16 text-sm\">No messages</div>\n )}\n {grouped.map(({ root, replies }) => (\n <div key={root.id} className=\"space-y-1\">\n <MessageRow\n msg={root}\n now={now}\n agentLabel={agentLabel}\n agentsById={agentsById}\n onReply={() => startReply(root)}\n onClaim={() => doClaim(root.id)}\n onRetry={() => doDeliveryAction(root.id, 'retry-now')}\n onMarkDead={() => doDeliveryAction(root.id, 'mark-dead', 'Marked dead from dashboard')}\n onClear={() => doDeliveryAction(root.id, 'clear', 'Cleared after manual handling')}\n onDelete={() => doDeleteMessage(root.id)}\n onThread={root.threadId ? () => openThread(root.threadId!) : undefined}\n replyCount={replies.length}\n />\n {replies.map((r) => (\n <div key={r.id} className=\"ml-6\">\n <MessageRow\n msg={r}\n now={now}\n agentLabel={agentLabel}\n agentsById={agentsById}\n onReply={() => startReply(r)}\n onClaim={() => doClaim(r.id)}\n onRetry={() => doDeliveryAction(r.id, 'retry-now')}\n onMarkDead={() => doDeliveryAction(r.id, 'mark-dead', 'Marked dead from dashboard')}\n onClear={() => doDeliveryAction(r.id, 'clear', 'Cleared after manual handling')}\n onDelete={() => doDeleteMessage(r.id)}\n />\n </div>\n ))}\n </div>\n ))}\n </div>\n </div>\n </div>\n )\n}\n\nfunction MessageRow({\n msg, now, agentLabel, agentsById, onReply, onClaim, onRetry, onMarkDead, onClear, onDelete, onThread, replyCount,\n}: {\n msg: Message\n now: number\n agentLabel: (id: string) => string\n agentsById: Record<string, import('@/types').Agent>\n onReply: () => void\n onClaim: () => void\n onRetry: () => void\n onMarkDead: () => void\n onClear: () => void\n onDelete: () => void\n onThread?: () => void\n replyCount?: number\n}) {\n const [expanded, setExpanded] = useState(false)\n const body = messageBody(msg)\n const openFilesAt = useRelayStore((s) => s.openFilesAt)\n const deliveryProblem = msg.deliveryStatus === 'queued' || msg.deliveryStatus === 'failed' || msg.deliveryStatus === 'dead' || Boolean(msg.deliveryLastError || msg.deliveryPoisonReason)\n const peer = msg.from === 'user' ? msg.to : msg.from\n const peerAgent = agentsById[peer]\n\n function resolvedReferencedPath(path: string): string {\n const cwd = typeof peerAgent?.meta?.cwd === 'string' ? peerAgent.meta.cwd : ''\n return resolveRelativePath(cwd || '/', path)\n }\n\n function openReferencedPath(path: string, line?: number) {\n const absolute = resolvedReferencedPath(path)\n void openFilesAt({ path: parentPath(absolute), selectedPath: absolute, line, overlay: true })\n }\n\n return (\n <Card className=\"group relative\">\n <CardContent className=\"p-3\">\n <div className=\"min-w-0\">\n <div className=\"flex items-center gap-2 flex-wrap text-xs text-muted-foreground mb-1\">\n <span className=\"font-medium text-foreground\">{agentLabel(msg.from)}</span>\n <span>→</span>\n <span>{displayTarget(msg.to, agentsById)}</span>\n {msg.channel && (\n <Badge variant=\"outline\" className=\"text-xs px-1.5 py-0 gap-0.5\">\n <Hash className=\"w-2.5 h-2.5\" />{msg.channel}\n </Badge>\n )}\n {msg.claimedBy && (\n <Badge variant=\"outline\" className=\"text-xs px-1.5 py-0 text-emerald-400 border-emerald-500/30\">\n <CheckCircle2 className=\"w-2.5 h-2.5 mr-0.5\" />claimed\n </Badge>\n )}\n {deliveryProblem && <DeliveryBadge msg={msg} now={now} />}\n {msg.subject && <span className=\"font-medium text-foreground\">{msg.subject}</span>}\n <span className=\"ml-auto shrink-0\" title={fmtTime(msg.createdAt)}><span className=\"opacity-40 mr-1\">#{msg.id}</span>{timeAgo(now, msg.createdAt)}</span>\n </div>\n {body && (\n <div className=\"cursor-pointer\" onClick={() => setExpanded((v) => !v)}>\n <FormattedBody text={body} rawBody={msg.body} className={`text-sm text-muted-foreground ${expanded ? '' : 'max-h-[3.75rem] overflow-hidden'}`} onOpenPath={openReferencedPath} resolvePathTitle={(path, line) => `${resolvedReferencedPath(path)}${line ? `:${line}` : ''}`} />\n </div>\n )}\n </div>\n <div className=\"absolute top-2 right-2 flex items-center gap-1 opacity-0 group-hover:opacity-100 transition-opacity bg-card rounded-md shadow-sm border border-border px-1 py-0.5\">\n <Button variant=\"ghost\" size=\"sm\" className=\"h-7 px-2 text-xs\" onClick={onReply} title=\"Reply\">\n <MessageSquareReply className=\"w-3.5 h-3.5\" />\n </Button>\n {msg.claimable && !msg.claimedBy && (\n <Button variant=\"ghost\" size=\"sm\" className=\"h-7 px-2 text-xs text-orange-400 hover:text-orange-300\" onClick={onClaim} title=\"Claim\">\n <CheckCircle2 className=\"w-3.5 h-3.5\" />\n </Button>\n )}\n {deliveryProblem && (\n <Button variant=\"ghost\" size=\"sm\" className=\"h-7 px-2 text-xs text-blue-400 hover:text-blue-300\" onClick={onRetry} title=\"Retry delivery now\">\n <RotateCcw className=\"w-3.5 h-3.5\" />\n </Button>\n )}\n {msg.deliveryStatus !== 'dead' && deliveryProblem && (\n <Button variant=\"ghost\" size=\"sm\" className=\"h-7 px-2 text-xs text-red-400 hover:text-red-300\" onClick={onMarkDead} title=\"Mark dead\">\n <Ban className=\"w-3.5 h-3.5\" />\n </Button>\n )}\n {(msg.deliveryStatus === 'failed' || msg.deliveryStatus === 'dead') && (\n <Button variant=\"ghost\" size=\"sm\" className=\"h-7 px-2 text-xs text-emerald-400 hover:text-emerald-300\" onClick={onClear} title=\"Clear after manual handling\">\n <CheckCircle2 className=\"w-3.5 h-3.5\" />\n </Button>\n )}\n {onThread && (replyCount ?? 0) > 0 && (\n <Button variant=\"ghost\" size=\"sm\" className=\"h-7 px-2 text-xs\" onClick={onThread} title=\"Thread\">\n +{replyCount}\n </Button>\n )}\n <Button variant=\"ghost\" size=\"sm\" className=\"h-7 px-2 text-xs text-red-400 hover:text-red-300\" onClick={onDelete} title=\"Delete\">\n <Trash2 className=\"w-3.5 h-3.5\" />\n </Button>\n </div>\n </CardContent>\n </Card>\n )\n}\n\nfunction DeliveryBadge({ msg, now }: { msg: Message; now: number }) {\n const status = msg.deliveryStatus || 'pending'\n const detail = msg.deliveryPoisonReason || msg.deliveryLastError || (msg.deliveryNextRetryAt ? `retry ${timeAgo(now, msg.deliveryNextRetryAt)}` : undefined)\n const className = status === 'dead'\n ? 'text-red-300 border-red-500/30 bg-red-500/10'\n : status === 'failed'\n ? 'text-amber-300 border-amber-500/30 bg-amber-500/10'\n : 'text-blue-300 border-blue-500/30 bg-blue-500/10'\n return (\n <Badge variant=\"outline\" className={`text-xs px-1.5 py-0 ${className}`} title={detail || status}>\n <AlertTriangle className=\"w-2.5 h-2.5 mr-0.5\" />\n {status}{msg.deliveryAttempts ? ` ${msg.deliveryAttempts}x` : ''}\n </Badge>\n )\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"messages-CzHsL-om.js","names":[],"sources":["../../dashboard/src/components/views/messages.tsx"],"sourcesContent":["import { useMemo, useState } from 'react'\nimport { useRelayStore, useNow } from '@/store'\nimport { useComposeAgents, useUniqueTags } from '@/hooks/use-selectors'\nimport { Card, CardContent } from '@/components/ui/card'\nimport { Badge } from '@/components/ui/badge'\nimport { Button } from '@/components/ui/button'\nimport { Input } from '@/components/ui/input'\nimport { FormattedBody } from '@/components/shared/formatted-body'\nimport {\n Mail, Pencil, MessageSquareReply, CheckCircle2, Trash2, X, Hash, AlertTriangle, RotateCcw, Ban,\n} from 'lucide-react'\nimport { displayName, displayTarget, messageBody, timeAgo, fmtTime } from '@/lib/display'\nimport type { Message } from '@/types'\n\nfunction resolveRelativePath(cwd: string, path: string): string {\n if (path.startsWith('/')) return path\n const parts = `${cwd.replace(/\\/+$/, '')}/${path}`.split('/')\n const stack: string[] = []\n for (const part of parts) {\n if (!part || part === '.') continue\n if (part === '..') stack.pop()\n else stack.push(part)\n }\n return '/' + stack.join('/')\n}\n\nfunction parentPath(path: string): string {\n const trimmed = path.replace(/\\/+$/, '')\n const index = trimmed.lastIndexOf('/')\n return index > 0 ? trimmed.slice(0, index) : '/'\n}\n\nexport function MessagesView() {\n const now = useNow()\n const messages = useRelayStore((s) => s.messages)\n const agentsById = useRelayStore((s) => s.agentsById)\n const selectedAgent = useRelayStore((s) => s.selectedAgent)\n const channelFilter = useRelayStore((s) => s.channelFilter)\n const tagFilter = useRelayStore((s) => s.tagFilter)\n const replyTo = useRelayStore((s) => s.replyTo)\n const set = useRelayStore((s) => s.set)\n const openCompose = useRelayStore((s) => s.openCompose)\n const startReply = useRelayStore((s) => s.startReply)\n const doClaim = useRelayStore((s) => s.doClaim)\n const doDeliveryAction = useRelayStore((s) => s.doDeliveryAction)\n const doDeleteMessage = useRelayStore((s) => s.doDeleteMessage)\n const openThread = useRelayStore((s) => s.openThread)\n const cancelReply = useRelayStore((s) => s.cancelReply)\n\n const composeAgents = useComposeAgents()\n const uniqueTags = useUniqueTags()\n\n const filtered = useMemo(() => {\n let list = [...messages].sort((a, b) => b.id - a.id)\n if (selectedAgent) list = list.filter((m) => m.from === selectedAgent || m.to === selectedAgent)\n if (channelFilter) list = list.filter((m) => m.channel === channelFilter)\n if (tagFilter) list = list.filter((m) => {\n const agent = agentsById[m.from] || agentsById[m.to]\n return (agent?.tags || []).includes(tagFilter)\n })\n return list\n }, [messages, selectedAgent, channelFilter, tagFilter, agentsById])\n\n // Group by threadId — show root messages, collapse replies\n const grouped = useMemo(() => {\n const roots: Message[] = []\n const threads = new Map<number, Message[]>()\n for (const msg of filtered) {\n const tid = msg.threadId ?? msg.id\n if (!threads.has(tid)) threads.set(tid, [])\n threads.get(tid)!.push(msg)\n if (msg.id === tid) roots.push(msg)\n }\n // messages without a known root\n const seenRoots = new Set(roots.map((r) => r.id))\n for (const msg of filtered) {\n if (!seenRoots.has(msg.threadId ?? msg.id) && !roots.find((r) => r.id === msg.id)) {\n roots.push(msg)\n }\n }\n roots.sort((a, b) => b.id - a.id)\n return roots.map((r) => ({ root: r, replies: (threads.get(r.id) || []).filter((m) => m.id !== r.id).sort((a, b) => a.id - b.id) }))\n }, [filtered])\n\n function agentLabel(id: string) {\n return agentsById[id] ? displayName(agentsById[id]) : id.slice(-10)\n }\n\n const uniqueChannels = useMemo(() => {\n return [...new Set(messages.map((m) => m.channel).filter(Boolean) as string[])]\n }, [messages])\n\n return (\n <div className=\"space-y-4\">\n <div className=\"flex items-center justify-between flex-wrap gap-2\">\n <div className=\"flex items-center gap-2\">\n <Mail className=\"w-5 h-5 text-muted-foreground\" />\n <h2 className=\"text-lg font-semibold\">Messages</h2>\n <Badge variant=\"secondary\">{filtered.length}</Badge>\n </div>\n <Button size=\"sm\" onClick={openCompose}>\n <Pencil className=\"w-4 h-4 mr-1\" /> Compose\n </Button>\n </div>\n\n <div className=\"flex flex-wrap gap-2\">\n <select\n className=\"rounded-md border border-input bg-background px-3 py-1.5 text-sm\"\n value={selectedAgent}\n onChange={(e) => set({ selectedAgent: e.target.value })}\n >\n <option value=\"\">All agents</option>\n {composeAgents.map((a) => <option key={a.id} value={a.id}>{displayName(a)}</option>)}\n </select>\n <select\n className=\"rounded-md border border-input bg-background px-3 py-1.5 text-sm\"\n value={tagFilter}\n onChange={(e) => set({ tagFilter: e.target.value })}\n >\n <option value=\"\">All tags</option>\n {uniqueTags.map((t) => <option key={t} value={t}>#{t}</option>)}\n </select>\n <select\n className=\"rounded-md border border-input bg-background px-3 py-1.5 text-sm\"\n value={channelFilter}\n onChange={(e) => set({ channelFilter: e.target.value })}\n >\n <option value=\"\">All channels</option>\n {uniqueChannels.map((c) => <option key={c} value={c}>{c}</option>)}\n </select>\n </div>\n\n {replyTo && (\n <div className=\"flex items-center gap-2 rounded-md bg-blue-500/10 border border-blue-500/20 px-3 py-2 text-sm text-blue-300\">\n <MessageSquareReply className=\"w-4 h-4 shrink-0\" />\n <span>Replying to message #{replyTo.id} from <strong>{agentLabel(replyTo.from)}</strong></span>\n <Button variant=\"ghost\" size=\"sm\" className=\"ml-auto h-6 px-1.5\" onClick={cancelReply}>\n <X className=\"w-3.5 h-3.5\" />\n </Button>\n </div>\n )}\n\n <div className=\"h-[calc(100dvh-15rem)] overflow-y-auto\">\n <div className=\"space-y-2 pr-2\">\n {grouped.length === 0 && (\n <div className=\"text-center text-muted-foreground py-16 text-sm\">No messages</div>\n )}\n {grouped.map(({ root, replies }) => (\n <div key={root.id} className=\"space-y-1\">\n <MessageRow\n msg={root}\n now={now}\n agentLabel={agentLabel}\n agentsById={agentsById}\n onReply={() => startReply(root)}\n onClaim={() => doClaim(root.id)}\n onRetry={() => doDeliveryAction(root.id, 'retry-now')}\n onMarkDead={() => doDeliveryAction(root.id, 'mark-dead', 'Marked dead from dashboard')}\n onClear={() => doDeliveryAction(root.id, 'clear', 'Cleared after manual handling')}\n onDelete={() => doDeleteMessage(root.id)}\n onThread={root.threadId ? () => openThread(root.threadId!) : undefined}\n replyCount={replies.length}\n />\n {replies.map((r) => (\n <div key={r.id} className=\"ml-6\">\n <MessageRow\n msg={r}\n now={now}\n agentLabel={agentLabel}\n agentsById={agentsById}\n onReply={() => startReply(r)}\n onClaim={() => doClaim(r.id)}\n onRetry={() => doDeliveryAction(r.id, 'retry-now')}\n onMarkDead={() => doDeliveryAction(r.id, 'mark-dead', 'Marked dead from dashboard')}\n onClear={() => doDeliveryAction(r.id, 'clear', 'Cleared after manual handling')}\n onDelete={() => doDeleteMessage(r.id)}\n />\n </div>\n ))}\n </div>\n ))}\n </div>\n </div>\n </div>\n )\n}\n\nfunction MessageRow({\n msg, now, agentLabel, agentsById, onReply, onClaim, onRetry, onMarkDead, onClear, onDelete, onThread, replyCount,\n}: {\n msg: Message\n now: number\n agentLabel: (id: string) => string\n agentsById: Record<string, import('@/types').Agent>\n onReply: () => void\n onClaim: () => void\n onRetry: () => void\n onMarkDead: () => void\n onClear: () => void\n onDelete: () => void\n onThread?: () => void\n replyCount?: number\n}) {\n const [expanded, setExpanded] = useState(false)\n const body = messageBody(msg)\n const openFilesAt = useRelayStore((s) => s.openFilesAt)\n const deliveryProblem = msg.deliveryStatus === 'queued' || msg.deliveryStatus === 'failed' || msg.deliveryStatus === 'dead' || Boolean(msg.deliveryLastError || msg.deliveryPoisonReason)\n const peer = msg.from === 'user' ? msg.to : msg.from\n const peerAgent = agentsById[peer]\n\n function resolvedReferencedPath(path: string): string {\n const cwd = typeof peerAgent?.meta?.cwd === 'string' ? peerAgent.meta.cwd : ''\n return resolveRelativePath(cwd || '/', path)\n }\n\n function openReferencedPath(path: string, line?: number) {\n const absolute = resolvedReferencedPath(path)\n void openFilesAt({ path: parentPath(absolute), selectedPath: absolute, line, overlay: true })\n }\n\n return (\n <Card className=\"group relative\">\n <CardContent className=\"p-3\">\n <div className=\"min-w-0\">\n <div className=\"flex items-center gap-2 flex-wrap text-xs text-muted-foreground mb-1\">\n <span className=\"font-medium text-foreground\">{agentLabel(msg.from)}</span>\n <span>→</span>\n <span>{displayTarget(msg.to, agentsById)}</span>\n {msg.channel && (\n <Badge variant=\"outline\" className=\"text-xs px-1.5 py-0 gap-0.5\">\n <Hash className=\"w-2.5 h-2.5\" />{msg.channel}\n </Badge>\n )}\n {msg.claimedBy && (\n <Badge variant=\"outline\" className=\"text-xs px-1.5 py-0 text-emerald-400 border-emerald-500/30\">\n <CheckCircle2 className=\"w-2.5 h-2.5 mr-0.5\" />claimed\n </Badge>\n )}\n {deliveryProblem && <DeliveryBadge msg={msg} now={now} />}\n {msg.subject && <span className=\"font-medium text-foreground\">{msg.subject}</span>}\n <span className=\"ml-auto shrink-0\" title={fmtTime(msg.createdAt)}><span className=\"opacity-40 mr-1\">#{msg.id}</span>{timeAgo(now, msg.createdAt)}</span>\n </div>\n {body && (\n <div className=\"cursor-pointer\" onClick={() => setExpanded((v) => !v)}>\n <FormattedBody text={body} rawBody={msg.body} className={`text-sm text-muted-foreground ${expanded ? '' : 'max-h-[3.75rem] overflow-hidden'}`} onOpenPath={openReferencedPath} resolvePathTitle={(path, line) => `${resolvedReferencedPath(path)}${line ? `:${line}` : ''}`} />\n </div>\n )}\n </div>\n <div className=\"absolute top-2 right-2 flex items-center gap-1 opacity-0 group-hover:opacity-100 transition-opacity bg-card rounded-md shadow-sm border border-border px-1 py-0.5\">\n <Button variant=\"ghost\" size=\"sm\" className=\"h-7 px-2 text-xs\" onClick={onReply} title=\"Reply\">\n <MessageSquareReply className=\"w-3.5 h-3.5\" />\n </Button>\n {msg.claimable && !msg.claimedBy && (\n <Button variant=\"ghost\" size=\"sm\" className=\"h-7 px-2 text-xs text-orange-400 hover:text-orange-300\" onClick={onClaim} title=\"Claim\">\n <CheckCircle2 className=\"w-3.5 h-3.5\" />\n </Button>\n )}\n {deliveryProblem && (\n <Button variant=\"ghost\" size=\"sm\" className=\"h-7 px-2 text-xs text-blue-400 hover:text-blue-300\" onClick={onRetry} title=\"Retry delivery now\">\n <RotateCcw className=\"w-3.5 h-3.5\" />\n </Button>\n )}\n {msg.deliveryStatus !== 'dead' && deliveryProblem && (\n <Button variant=\"ghost\" size=\"sm\" className=\"h-7 px-2 text-xs text-red-400 hover:text-red-300\" onClick={onMarkDead} title=\"Mark dead\">\n <Ban className=\"w-3.5 h-3.5\" />\n </Button>\n )}\n {(msg.deliveryStatus === 'failed' || msg.deliveryStatus === 'dead') && (\n <Button variant=\"ghost\" size=\"sm\" className=\"h-7 px-2 text-xs text-emerald-400 hover:text-emerald-300\" onClick={onClear} title=\"Clear after manual handling\">\n <CheckCircle2 className=\"w-3.5 h-3.5\" />\n </Button>\n )}\n {onThread && (replyCount ?? 0) > 0 && (\n <Button variant=\"ghost\" size=\"sm\" className=\"h-7 px-2 text-xs\" onClick={onThread} title=\"Thread\">\n +{replyCount}\n </Button>\n )}\n <Button variant=\"ghost\" size=\"sm\" className=\"h-7 px-2 text-xs text-red-400 hover:text-red-300\" onClick={onDelete} title=\"Delete\">\n <Trash2 className=\"w-3.5 h-3.5\" />\n </Button>\n </div>\n </CardContent>\n </Card>\n )\n}\n\nfunction DeliveryBadge({ msg, now }: { msg: Message; now: number }) {\n const status = msg.deliveryStatus || 'pending'\n const detail = msg.deliveryPoisonReason || msg.deliveryLastError || (msg.deliveryNextRetryAt ? `retry ${timeAgo(now, msg.deliveryNextRetryAt)}` : undefined)\n const className = status === 'dead'\n ? 'text-red-300 border-red-500/30 bg-red-500/10'\n : status === 'failed'\n ? 'text-amber-300 border-amber-500/30 bg-amber-500/10'\n : 'text-blue-300 border-blue-500/30 bg-blue-500/10'\n return (\n <Badge variant=\"outline\" className={`text-xs px-1.5 py-0 ${className}`} title={detail || status}>\n <AlertTriangle className=\"w-2.5 h-2.5 mr-0.5\" />\n {status}{msg.deliveryAttempts ? ` ${msg.deliveryAttempts}x` : ''}\n </Badge>\n )\n}\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- import{I as e,P as t,Qt as n,T as r,k as i,kn as a,p as o,zt as s}from"./lucide-react-CD8Xl2U3.js";import{i as c,t as l}from"./store-CICRhg1m.js";import{A as u,k as d,z as f}from"./display-Bebqs1qu.js";import{t as p}from"./badge-t8zAwHW9.js";import{t as m}from"./button-DDA5P2YQ.js";import{D as h}from"./index-BL8r94_U.js";import{i as g,n as _,r as v,t as y}from"./card-CggxP1h9.js";var b=a();function x({agent:e,orch:n}){let r=l(e=>e.orchestratorAction),a=l(e=>e.openFilesAt);return(0,b.jsxs)(`div`,{className:`flex items-center gap-2 py-1.5`,children:[(0,b.jsx)(s,{className:`w-3.5 h-3.5 text-muted-foreground shrink-0`}),(0,b.jsxs)(`div`,{className:`flex-1 min-w-0`,children:[(0,b.jsx)(`div`,{className:`text-xs font-medium truncate`,children:e.label||e.agentId.slice(-12)}),(0,b.jsxs)(`button`,{type:`button`,className:`max-w-full truncate text-left text-[10px] text-muted-foreground hover:text-foreground`,title:`Open ${e.cwd||n.baseDir} in Files`,onClick:t=>{t.stopPropagation(),a({orchestratorId:n.id,path:e.cwd||n.baseDir})},children:[e.provider,` · `,e.cwd||`~`]})]}),(0,b.jsxs)(`div`,{className:`flex gap-1`,children:[(0,b.jsx)(m,{size:`icon`,variant:`ghost`,className:`h-6 w-6`,title:`Restart agent`,onClick:t=>{t.stopPropagation(),r(n.id,`restart`,e.agentId,`orchestrators`)},children:(0,b.jsx)(i,{className:`w-3 h-3`})}),(0,b.jsx)(m,{size:`icon`,variant:`ghost`,className:`h-6 w-6 text-red-400 hover:text-red-300`,title:`Shutdown agent`,onClick:t=>{t.stopPropagation(),r(n.id,`shutdown`,e.agentId,`orchestrators`)},children:(0,b.jsx)(t,{className:`w-3 h-3`})})]})]})}function S({orch:a}){let s=c(),S=l(e=>e.orchestratorAction),C=l(e=>e.upgradeOrchestrator),w=l(e=>e.stats.version),T=l(e=>e.openOrchestratorSpawnFor),E=l(e=>e.openFilesAt),D=l(e=>e.deleteOrchestrator),O=l(e=>e.refreshOrchestratorProviders),k=u(a),A=d(a),j=a.status===`online`,M=a.package?.version||a.version,N=a.upgrade,P=N?.status===`pending`,F=j&&!!a.version&&!!w&&a.version!==w,I=j&&!P&&(F||N?.status===`failed`),L=Object.entries(a.contracts||{}).filter(([,e])=>typeof e==`number`),R=a.providerStatus||a.providers.map(e=>({name:e,available:!0,checkedAt:Number(a.lastSeen)||Date.now()})),z=a.managedAgents.map(e=>e.workspace?{agent:e,workspace:e.workspace}:null).filter(e=>!!(e?.workspace?.id||e?.workspace?.worktreePath));return(0,b.jsxs)(y,{className:`${j?``:`opacity-60`}`,children:[(0,b.jsx)(v,{className:`pb-2 pt-4 px-4`,children:(0,b.jsxs)(`div`,{className:`flex items-start gap-2`,children:[(0,b.jsx)(`div`,{className:`p-1.5 rounded-md ${j?`bg-emerald-500/10`:`bg-zinc-800`}`,children:(0,b.jsx)(r,{className:`w-4 h-4 ${j?`text-emerald-400`:`text-zinc-500`}`})}),(0,b.jsxs)(`div`,{className:`flex-1 min-w-0`,children:[(0,b.jsx)(g,{className:`text-sm font-medium truncate`,children:a.hostname}),(0,b.jsxs)(`div`,{className:`text-xs text-muted-foreground mt-0.5`,children:[a.id.slice(0,16),`…`]})]}),(0,b.jsx)(p,{className:`text-[10px] shrink-0 ${A}`,children:k})]})}),(0,b.jsxs)(_,{className:`px-4 pb-4 space-y-3`,children:[(0,b.jsxs)(`div`,{className:`flex flex-wrap gap-x-4 gap-y-1 text-xs text-muted-foreground`,children:[(0,b.jsx)(`span`,{className:j?`text-emerald-400`:`text-zinc-500`,children:a.status}),M&&(0,b.jsxs)(`span`,{children:[a.package?.name||`orchestrator`,` v`,M]}),P&&(0,b.jsxs)(p,{className:`text-[10px] bg-amber-500/10 text-amber-400 border-amber-500/20 gap-1`,children:[(0,b.jsx)(n,{className:`w-3 h-3 animate-pulse`}),`upgrading → v`,N.desiredVersion]}),!P&&N?.status===`failed`&&(0,b.jsxs)(p,{className:`text-[10px] bg-red-500/10 text-red-400 border-red-500/20 gap-1`,title:N.error,children:[(0,b.jsx)(o,{className:`w-3 h-3`}),`upgrade failed`]}),!P&&F&&(0,b.jsxs)(p,{className:`text-[10px] bg-blue-500/10 text-blue-400 border-blue-500/20`,children:[`→ v`,w,` available`]}),(0,b.jsx)(`span`,{className:`ml-auto`,children:f(s,a.lastSeen)})]}),R.length>0&&(0,b.jsx)(`div`,{className:`flex flex-wrap gap-1`,children:R.map(e=>(0,b.jsx)(p,{variant:`secondary`,title:e.available?`version`in e&&e.version?e.version:e.name:`reason`in e&&e.reason?e.reason:`${e.name} unavailable`,className:`text-[10px] ${e.available?`bg-emerald-500/10 text-emerald-400 border-emerald-500/20`:`bg-red-500/10 text-red-400 border-red-500/20`}`,children:e.name},e.name))}),L.length>0&&(0,b.jsx)(`div`,{className:`flex flex-wrap gap-1`,children:L.map(([e,t])=>(0,b.jsxs)(p,{variant:`secondary`,className:`text-[10px]`,children:[e,`=`,t]},e))}),a.managedAgents.length>0&&(0,b.jsxs)(b.Fragment,{children:[(0,b.jsx)(h,{}),(0,b.jsxs)(`div`,{children:[(0,b.jsxs)(`div`,{className:`text-xs font-medium text-muted-foreground mb-1.5`,children:[`Managed agents (`,a.managedAgents.length,`)`]}),(0,b.jsx)(`div`,{className:`space-y-0`,children:a.managedAgents.map(e=>(0,b.jsx)(x,{agent:e,orch:a},e.agentId))})]})]}),z.length>0&&(0,b.jsxs)(b.Fragment,{children:[(0,b.jsx)(h,{}),(0,b.jsxs)(`div`,{children:[(0,b.jsxs)(`div`,{className:`text-xs font-medium text-muted-foreground mb-1.5`,children:[`Workspaces (`,z.length,`)`]}),(0,b.jsx)(`div`,{className:`space-y-1`,children:z.map(({agent:e,workspace:t})=>(0,b.jsxs)(`button`,{type:`button`,className:`block w-full min-w-0 rounded border border-border/60 px-2 py-1.5 text-left hover:bg-accent/40`,onClick:()=>t.worktreePath&&void E({orchestratorId:a.id,path:t.worktreePath}),children:[(0,b.jsxs)(`div`,{className:`flex items-center gap-2 text-xs`,children:[(0,b.jsx)(`span`,{className:`truncate font-medium`,children:t.branch||e.label||e.agentId.slice(-12)}),t.status&&(0,b.jsx)(p,{variant:`outline`,className:`h-4 shrink-0 text-[10px]`,children:t.status})]}),(0,b.jsx)(`div`,{className:`truncate text-[10px] text-muted-foreground`,children:t.worktreePath||t.repoRoot})]},t.id||t.worktreePath))})]})]}),(0,b.jsx)(h,{}),(0,b.jsxs)(`div`,{className:`flex flex-wrap gap-1.5`,children:[j&&(0,b.jsxs)(m,{size:`sm`,variant:`outline`,className:`h-7 text-xs gap-1`,onClick:()=>T(a.id),children:[(0,b.jsx)(e,{className:`w-3 h-3`}),`Spawn agent`]}),j&&(0,b.jsxs)(m,{size:`sm`,variant:`outline`,className:`h-7 text-xs gap-1`,onClick:()=>O(a.id),children:[(0,b.jsx)(i,{className:`w-3 h-3`}),`Refresh providers`]}),(I||P)&&(0,b.jsxs)(m,{size:`sm`,variant:`outline`,disabled:P,className:`h-7 text-xs gap-1 text-blue-400 hover:text-blue-300 border-blue-500/30 disabled:opacity-60`,title:P?`Upgrading to v${N.desiredVersion}…`:`Upgrade to v${w}`,onClick:()=>C(a.id),children:[(0,b.jsx)(n,{className:`w-3 h-3 ${P?`animate-pulse`:``}`}),P?`Upgrading…`:`Upgrade`]}),j&&(0,b.jsxs)(m,{size:`sm`,variant:`outline`,className:`h-7 text-xs gap-1`,onClick:()=>S(a.id,`restart`,void 0,`orchestrators`),children:[(0,b.jsx)(i,{className:`w-3 h-3`}),`Restart all`]}),j&&(0,b.jsxs)(m,{size:`sm`,variant:`outline`,className:`h-7 text-xs gap-1 text-red-400 hover:text-red-300 border-red-500/30`,onClick:()=>S(a.id,`shutdown`,void 0,`orchestrators`),children:[(0,b.jsx)(t,{className:`w-3 h-3`}),`Shutdown all`]}),(0,b.jsx)(m,{size:`sm`,variant:`ghost`,className:`h-7 text-xs text-muted-foreground hover:text-red-400`,onClick:()=>D(a.id),children:`Remove`})]})]})]})}function C(){let t=l(e=>e.orchestrators),n=l(e=>e.openOrchestratorSpawn),i=l(e=>e.openOrchestratorInstall),a=t.filter(e=>e.status===`online`).length;return(0,b.jsxs)(`div`,{className:`space-y-4`,children:[(0,b.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,b.jsxs)(`div`,{children:[(0,b.jsx)(`h2`,{className:`text-base font-semibold`,children:`Orchestrators`}),(0,b.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:`Multi-host agent lifecycle managers`})]}),(0,b.jsxs)(`div`,{className:`flex items-center gap-2 ml-auto`,children:[(0,b.jsxs)(p,{variant:`outline`,className:`text-xs`,children:[a,` online`]}),(0,b.jsxs)(m,{size:`sm`,variant:`outline`,className:`gap-1`,onClick:i,children:[(0,b.jsx)(r,{className:`w-3.5 h-3.5`}),`Add`]}),(0,b.jsxs)(m,{size:`sm`,className:`gap-1`,onClick:n,children:[(0,b.jsx)(e,{className:`w-3.5 h-3.5`}),`Spawn`]})]})]}),t.length===0?(0,b.jsx)(`div`,{className:`text-center py-16 text-muted-foreground text-sm`,children:`No orchestrators registered.`}):(0,b.jsx)(`div`,{className:`grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-4`,children:t.map(e=>(0,b.jsx)(S,{orch:e},e.id))})]})}export{C as OrchestratorsView};
2
- //# sourceMappingURL=orchestrators-Clu8MNKo.js.map
1
+ import{An as e,I as t,P as n,Qt as r,T as i,k as a,p as o,zt as s}from"./lucide-react-DLQFnqNm.js";import{i as c,t as l}from"./store-CMUFZKxf.js";import{H as u,M as d,N as f}from"./display-ConJ9cJB.js";import{t as p}from"./badge-JVybSpzR.js";import{t as m}from"./button-BsMqBNJb.js";import{D as h}from"./index-DdB6SVZY.js";import{i as g,n as _,r as v,t as y}from"./card-I8w4U656.js";var b=e();function x({agent:e,orch:t}){let r=l(e=>e.orchestratorAction),i=l(e=>e.openFilesAt);return(0,b.jsxs)(`div`,{className:`flex items-center gap-2 py-1.5`,children:[(0,b.jsx)(s,{className:`w-3.5 h-3.5 text-muted-foreground shrink-0`}),(0,b.jsxs)(`div`,{className:`flex-1 min-w-0`,children:[(0,b.jsx)(`div`,{className:`text-xs font-medium truncate`,children:e.label||e.agentId.slice(-12)}),(0,b.jsxs)(`button`,{type:`button`,className:`max-w-full truncate text-left text-[10px] text-muted-foreground hover:text-foreground`,title:`Open ${e.cwd||t.baseDir} in Files`,onClick:n=>{n.stopPropagation(),i({orchestratorId:t.id,path:e.cwd||t.baseDir})},children:[e.provider,` · `,e.cwd||`~`]})]}),(0,b.jsxs)(`div`,{className:`flex gap-1`,children:[(0,b.jsx)(m,{size:`icon`,variant:`ghost`,className:`h-6 w-6`,title:`Restart agent`,onClick:n=>{n.stopPropagation(),r(t.id,`restart`,e.agentId,`orchestrators`)},children:(0,b.jsx)(a,{className:`w-3 h-3`})}),(0,b.jsx)(m,{size:`icon`,variant:`ghost`,className:`h-6 w-6 text-red-400 hover:text-red-300`,title:`Shutdown agent`,onClick:n=>{n.stopPropagation(),r(t.id,`shutdown`,e.agentId,`orchestrators`)},children:(0,b.jsx)(n,{className:`w-3 h-3`})})]})]})}function S({orch:e}){let s=c(),S=l(e=>e.orchestratorAction),C=l(e=>e.upgradeOrchestrator),w=l(e=>e.stats.version),T=l(e=>e.openOrchestratorSpawnFor),E=l(e=>e.openFilesAt),D=l(e=>e.deleteOrchestrator),O=l(e=>e.refreshOrchestratorProviders),k=f(e),A=d(e),j=e.status===`online`,M=e.package?.version||e.version,N=e.upgrade,P=N?.status===`pending`,F=j&&!!e.version&&!!w&&e.version!==w,I=j&&!P&&(F||N?.status===`failed`),L=Object.entries(e.contracts||{}).filter(([,e])=>typeof e==`number`),R=e.providerStatus||e.providers.map(t=>({name:t,available:!0,checkedAt:Number(e.lastSeen)||Date.now()})),z=e.managedAgents.map(e=>e.workspace?{agent:e,workspace:e.workspace}:null).filter(e=>!!(e?.workspace?.id||e?.workspace?.worktreePath));return(0,b.jsxs)(y,{className:`${j?``:`opacity-60`}`,children:[(0,b.jsx)(v,{className:`pb-2 pt-4 px-4`,children:(0,b.jsxs)(`div`,{className:`flex items-start gap-2`,children:[(0,b.jsx)(`div`,{className:`p-1.5 rounded-md ${j?`bg-emerald-500/10`:`bg-zinc-800`}`,children:(0,b.jsx)(i,{className:`w-4 h-4 ${j?`text-emerald-400`:`text-zinc-500`}`})}),(0,b.jsxs)(`div`,{className:`flex-1 min-w-0`,children:[(0,b.jsx)(g,{className:`text-sm font-medium truncate`,children:e.hostname}),(0,b.jsxs)(`div`,{className:`text-xs text-muted-foreground mt-0.5`,children:[e.id.slice(0,16),`…`]})]}),(0,b.jsx)(p,{className:`text-[10px] shrink-0 ${A}`,children:k})]})}),(0,b.jsxs)(_,{className:`px-4 pb-4 space-y-3`,children:[(0,b.jsxs)(`div`,{className:`flex flex-wrap gap-x-4 gap-y-1 text-xs text-muted-foreground`,children:[(0,b.jsx)(`span`,{className:j?`text-emerald-400`:`text-zinc-500`,children:e.status}),M&&(0,b.jsxs)(`span`,{children:[e.package?.name||`orchestrator`,` v`,M]}),P&&(0,b.jsxs)(p,{className:`text-[10px] bg-amber-500/10 text-amber-400 border-amber-500/20 gap-1`,children:[(0,b.jsx)(r,{className:`w-3 h-3 animate-pulse`}),`upgrading → v`,N.desiredVersion]}),!P&&N?.status===`failed`&&(0,b.jsxs)(p,{className:`text-[10px] bg-red-500/10 text-red-400 border-red-500/20 gap-1`,title:N.error,children:[(0,b.jsx)(o,{className:`w-3 h-3`}),`upgrade failed`]}),!P&&F&&(0,b.jsxs)(p,{className:`text-[10px] bg-blue-500/10 text-blue-400 border-blue-500/20`,children:[`→ v`,w,` available`]}),(0,b.jsx)(`span`,{className:`ml-auto`,children:u(s,e.lastSeen)})]}),R.length>0&&(0,b.jsx)(`div`,{className:`flex flex-wrap gap-1`,children:R.map(e=>(0,b.jsx)(p,{variant:`secondary`,title:e.available?`version`in e&&e.version?e.version:e.name:`reason`in e&&e.reason?e.reason:`${e.name} unavailable`,className:`text-[10px] ${e.available?`bg-emerald-500/10 text-emerald-400 border-emerald-500/20`:`bg-red-500/10 text-red-400 border-red-500/20`}`,children:e.name},e.name))}),L.length>0&&(0,b.jsx)(`div`,{className:`flex flex-wrap gap-1`,children:L.map(([e,t])=>(0,b.jsxs)(p,{variant:`secondary`,className:`text-[10px]`,children:[e,`=`,t]},e))}),e.managedAgents.length>0&&(0,b.jsxs)(b.Fragment,{children:[(0,b.jsx)(h,{}),(0,b.jsxs)(`div`,{children:[(0,b.jsxs)(`div`,{className:`text-xs font-medium text-muted-foreground mb-1.5`,children:[`Managed agents (`,e.managedAgents.length,`)`]}),(0,b.jsx)(`div`,{className:`space-y-0`,children:e.managedAgents.map(t=>(0,b.jsx)(x,{agent:t,orch:e},t.agentId))})]})]}),z.length>0&&(0,b.jsxs)(b.Fragment,{children:[(0,b.jsx)(h,{}),(0,b.jsxs)(`div`,{children:[(0,b.jsxs)(`div`,{className:`text-xs font-medium text-muted-foreground mb-1.5`,children:[`Workspaces (`,z.length,`)`]}),(0,b.jsx)(`div`,{className:`space-y-1`,children:z.map(({agent:t,workspace:n})=>(0,b.jsxs)(`button`,{type:`button`,className:`block w-full min-w-0 rounded border border-border/60 px-2 py-1.5 text-left hover:bg-accent/40`,onClick:()=>n.worktreePath&&void E({orchestratorId:e.id,path:n.worktreePath}),children:[(0,b.jsxs)(`div`,{className:`flex items-center gap-2 text-xs`,children:[(0,b.jsx)(`span`,{className:`truncate font-medium`,children:n.branch||t.label||t.agentId.slice(-12)}),n.status&&(0,b.jsx)(p,{variant:`outline`,className:`h-4 shrink-0 text-[10px]`,children:n.status})]}),(0,b.jsx)(`div`,{className:`truncate text-[10px] text-muted-foreground`,children:n.worktreePath||n.repoRoot})]},n.id||n.worktreePath))})]})]}),(0,b.jsx)(h,{}),(0,b.jsxs)(`div`,{className:`flex flex-wrap gap-1.5`,children:[j&&(0,b.jsxs)(m,{size:`sm`,variant:`outline`,className:`h-7 text-xs gap-1`,onClick:()=>T(e.id),children:[(0,b.jsx)(t,{className:`w-3 h-3`}),`Spawn agent`]}),j&&(0,b.jsxs)(m,{size:`sm`,variant:`outline`,className:`h-7 text-xs gap-1`,onClick:()=>O(e.id),children:[(0,b.jsx)(a,{className:`w-3 h-3`}),`Refresh providers`]}),(I||P)&&(0,b.jsxs)(m,{size:`sm`,variant:`outline`,disabled:P,className:`h-7 text-xs gap-1 text-blue-400 hover:text-blue-300 border-blue-500/30 disabled:opacity-60`,title:P?`Upgrading to v${N.desiredVersion}…`:`Upgrade to v${w}`,onClick:()=>C(e.id),children:[(0,b.jsx)(r,{className:`w-3 h-3 ${P?`animate-pulse`:``}`}),P?`Upgrading…`:`Upgrade`]}),j&&(0,b.jsxs)(m,{size:`sm`,variant:`outline`,className:`h-7 text-xs gap-1`,onClick:()=>S(e.id,`restart`,void 0,`orchestrators`),children:[(0,b.jsx)(a,{className:`w-3 h-3`}),`Restart all`]}),j&&(0,b.jsxs)(m,{size:`sm`,variant:`outline`,className:`h-7 text-xs gap-1 text-red-400 hover:text-red-300 border-red-500/30`,onClick:()=>S(e.id,`shutdown`,void 0,`orchestrators`),children:[(0,b.jsx)(n,{className:`w-3 h-3`}),`Shutdown all`]}),(0,b.jsx)(m,{size:`sm`,variant:`ghost`,className:`h-7 text-xs text-muted-foreground hover:text-red-400`,onClick:()=>D(e.id),children:`Remove`})]})]})]})}function C(){let e=l(e=>e.orchestrators),n=l(e=>e.openOrchestratorSpawn),r=l(e=>e.openOrchestratorInstall),a=e.filter(e=>e.status===`online`).length;return(0,b.jsxs)(`div`,{className:`space-y-4`,children:[(0,b.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,b.jsxs)(`div`,{children:[(0,b.jsx)(`h2`,{className:`text-base font-semibold`,children:`Orchestrators`}),(0,b.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:`Multi-host agent lifecycle managers`})]}),(0,b.jsxs)(`div`,{className:`flex items-center gap-2 ml-auto`,children:[(0,b.jsxs)(p,{variant:`outline`,className:`text-xs`,children:[a,` online`]}),(0,b.jsxs)(m,{size:`sm`,variant:`outline`,className:`gap-1`,onClick:r,children:[(0,b.jsx)(i,{className:`w-3.5 h-3.5`}),`Add`]}),(0,b.jsxs)(m,{size:`sm`,className:`gap-1`,onClick:n,children:[(0,b.jsx)(t,{className:`w-3.5 h-3.5`}),`Spawn`]})]})]}),e.length===0?(0,b.jsx)(`div`,{className:`text-center py-16 text-muted-foreground text-sm`,children:`No orchestrators registered.`}):(0,b.jsx)(`div`,{className:`grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-4`,children:e.map(e=>(0,b.jsx)(S,{orch:e},e.id))})]})}export{C as OrchestratorsView};
2
+ //# sourceMappingURL=orchestrators-PMUp2sUP.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"orchestrators-Clu8MNKo.js","names":[],"sources":["../../dashboard/src/components/views/orchestrators.tsx"],"sourcesContent":["import { useRelayStore, useNow } from '@/store'\nimport { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'\nimport { Badge } from '@/components/ui/badge'\nimport { Button } from '@/components/ui/button'\nimport { Separator } from '@/components/ui/separator'\nimport { displayName, orchestratorHealthLabel, orchestratorHealthClass, timeAgo } from '@/lib/display'\nimport { Server, Plus, RotateCw, Power, Cpu, ArrowUpCircle, AlertTriangle } from 'lucide-react'\nimport type { Orchestrator, ManagedAgent } from '@/types'\n\nfunction ManagedAgentRow({ agent, orch }: { agent: ManagedAgent; orch: Orchestrator }) {\n const orchestratorAction = useRelayStore((s) => s.orchestratorAction)\n const openFilesAt = useRelayStore((s) => s.openFilesAt)\n\n return (\n <div className=\"flex items-center gap-2 py-1.5\">\n <Cpu className=\"w-3.5 h-3.5 text-muted-foreground shrink-0\" />\n <div className=\"flex-1 min-w-0\">\n <div className=\"text-xs font-medium truncate\">\n {agent.label || agent.agentId.slice(-12)}\n </div>\n <button\n type=\"button\"\n className=\"max-w-full truncate text-left text-[10px] text-muted-foreground hover:text-foreground\"\n title={`Open ${agent.cwd || orch.baseDir} in Files`}\n onClick={(e) => { e.stopPropagation(); void openFilesAt({ orchestratorId: orch.id, path: agent.cwd || orch.baseDir }) }}\n >\n {agent.provider} · {agent.cwd || '~'}\n </button>\n </div>\n <div className=\"flex gap-1\">\n <Button\n size=\"icon\"\n variant=\"ghost\"\n className=\"h-6 w-6\"\n title=\"Restart agent\"\n onClick={(e) => { e.stopPropagation(); orchestratorAction(orch.id, 'restart', agent.agentId, 'orchestrators') }}\n >\n <RotateCw className=\"w-3 h-3\" />\n </Button>\n <Button\n size=\"icon\"\n variant=\"ghost\"\n className=\"h-6 w-6 text-red-400 hover:text-red-300\"\n title=\"Shutdown agent\"\n onClick={(e) => { e.stopPropagation(); orchestratorAction(orch.id, 'shutdown', agent.agentId, 'orchestrators') }}\n >\n <Power className=\"w-3 h-3\" />\n </Button>\n </div>\n </div>\n )\n}\n\nfunction OrchestratorCard({ orch }: { orch: Orchestrator }) {\n const now = useNow()\n const orchestratorAction = useRelayStore((s) => s.orchestratorAction)\n const upgradeOrchestrator = useRelayStore((s) => s.upgradeOrchestrator)\n const fleetTarget = useRelayStore((s) => s.stats.version)\n const openOrchestratorSpawnFor = useRelayStore((s) => s.openOrchestratorSpawnFor)\n const openFilesAt = useRelayStore((s) => s.openFilesAt)\n const deleteOrchestrator = useRelayStore((s) => s.deleteOrchestrator)\n const refreshOrchestratorProviders = useRelayStore((s) => s.refreshOrchestratorProviders)\n\n const healthLabel = orchestratorHealthLabel(orch)\n const healthClass = orchestratorHealthClass(orch)\n const online = orch.status === 'online'\n const packageVersion = orch.package?.version || orch.version\n const upgrade = orch.upgrade\n const upgrading = upgrade?.status === 'pending'\n // Drift = reported version differs from the relay's own version (fleet target).\n const driftAvailable = online && !!orch.version && !!fleetTarget && orch.version !== fleetTarget\n const canUpgrade = online && !upgrading && (driftAvailable || upgrade?.status === 'failed')\n const contractEntries = Object.entries(orch.contracts || {}).filter(([, value]) => typeof value === 'number')\n const providerStatus = orch.providerStatus || orch.providers.map((provider) => ({ name: provider, available: true, checkedAt: Number(orch.lastSeen) || Date.now() }))\n const workspaces = orch.managedAgents\n .map((agent) => agent.workspace ? { agent, workspace: agent.workspace } : null)\n .filter((item): item is { agent: ManagedAgent; workspace: NonNullable<ManagedAgent['workspace']> } => Boolean(item?.workspace?.id || item?.workspace?.worktreePath))\n\n return (\n <Card className={`${!online ? 'opacity-60' : ''}`}>\n <CardHeader className=\"pb-2 pt-4 px-4\">\n <div className=\"flex items-start gap-2\">\n <div className={`p-1.5 rounded-md ${online ? 'bg-emerald-500/10' : 'bg-zinc-800'}`}>\n <Server className={`w-4 h-4 ${online ? 'text-emerald-400' : 'text-zinc-500'}`} />\n </div>\n <div className=\"flex-1 min-w-0\">\n <CardTitle className=\"text-sm font-medium truncate\">{orch.hostname}</CardTitle>\n <div className=\"text-xs text-muted-foreground mt-0.5\">{orch.id.slice(0, 16)}…</div>\n </div>\n <Badge className={`text-[10px] shrink-0 ${healthClass}`}>{healthLabel}</Badge>\n </div>\n </CardHeader>\n\n <CardContent className=\"px-4 pb-4 space-y-3\">\n {/* Meta row */}\n <div className=\"flex flex-wrap gap-x-4 gap-y-1 text-xs text-muted-foreground\">\n <span className={online ? 'text-emerald-400' : 'text-zinc-500'}>{orch.status}</span>\n {packageVersion && <span>{orch.package?.name || 'orchestrator'} v{packageVersion}</span>}\n {upgrading && (\n <Badge className=\"text-[10px] bg-amber-500/10 text-amber-400 border-amber-500/20 gap-1\">\n <ArrowUpCircle className=\"w-3 h-3 animate-pulse\" />upgrading → v{upgrade!.desiredVersion}\n </Badge>\n )}\n {!upgrading && upgrade?.status === 'failed' && (\n <Badge className=\"text-[10px] bg-red-500/10 text-red-400 border-red-500/20 gap-1\" title={upgrade.error}>\n <AlertTriangle className=\"w-3 h-3\" />upgrade failed\n </Badge>\n )}\n {!upgrading && driftAvailable && (\n <Badge className=\"text-[10px] bg-blue-500/10 text-blue-400 border-blue-500/20\">→ v{fleetTarget} available</Badge>\n )}\n <span className=\"ml-auto\">{timeAgo(now, orch.lastSeen)}</span>\n </div>\n\n {providerStatus.length > 0 && (\n <div className=\"flex flex-wrap gap-1\">\n {providerStatus.map((status) => (\n <Badge\n key={status.name}\n variant=\"secondary\"\n title={status.available ? ('version' in status && status.version ? status.version : status.name) : ('reason' in status && status.reason ? status.reason : `${status.name} unavailable`)}\n className={`text-[10px] ${status.available ? 'bg-emerald-500/10 text-emerald-400 border-emerald-500/20' : 'bg-red-500/10 text-red-400 border-red-500/20'}`}\n >\n {status.name}\n </Badge>\n ))}\n </div>\n )}\n\n {contractEntries.length > 0 && (\n <div className=\"flex flex-wrap gap-1\">\n {contractEntries.map(([name, version]) => (\n <Badge key={name} variant=\"secondary\" className=\"text-[10px]\">{name}={version}</Badge>\n ))}\n </div>\n )}\n\n {/* Managed agents */}\n {orch.managedAgents.length > 0 && (\n <>\n <Separator />\n <div>\n <div className=\"text-xs font-medium text-muted-foreground mb-1.5\">\n Managed agents ({orch.managedAgents.length})\n </div>\n <div className=\"space-y-0\">\n {orch.managedAgents.map((a) => (\n <ManagedAgentRow key={a.agentId} agent={a} orch={orch} />\n ))}\n </div>\n </div>\n </>\n )}\n\n {workspaces.length > 0 && (\n <>\n <Separator />\n <div>\n <div className=\"text-xs font-medium text-muted-foreground mb-1.5\">\n Workspaces ({workspaces.length})\n </div>\n <div className=\"space-y-1\">\n {workspaces.map(({ agent, workspace }) => (\n <button\n key={workspace.id || workspace.worktreePath}\n type=\"button\"\n className=\"block w-full min-w-0 rounded border border-border/60 px-2 py-1.5 text-left hover:bg-accent/40\"\n onClick={() => workspace.worktreePath && void openFilesAt({ orchestratorId: orch.id, path: workspace.worktreePath })}\n >\n <div className=\"flex items-center gap-2 text-xs\">\n <span className=\"truncate font-medium\">{workspace.branch || agent.label || agent.agentId.slice(-12)}</span>\n {workspace.status && <Badge variant=\"outline\" className=\"h-4 shrink-0 text-[10px]\">{workspace.status}</Badge>}\n </div>\n <div className=\"truncate text-[10px] text-muted-foreground\">{workspace.worktreePath || workspace.repoRoot}</div>\n </button>\n ))}\n </div>\n </div>\n </>\n )}\n\n {/* Actions */}\n <Separator />\n <div className=\"flex flex-wrap gap-1.5\">\n {online && (\n <Button size=\"sm\" variant=\"outline\" className=\"h-7 text-xs gap-1\" onClick={() => openOrchestratorSpawnFor(orch.id)}>\n <Plus className=\"w-3 h-3\" />\n Spawn agent\n </Button>\n )}\n {online && (\n <Button\n size=\"sm\"\n variant=\"outline\"\n className=\"h-7 text-xs gap-1\"\n onClick={() => refreshOrchestratorProviders(orch.id)}\n >\n <RotateCw className=\"w-3 h-3\" />\n Refresh providers\n </Button>\n )}\n {(canUpgrade || upgrading) && (\n <Button\n size=\"sm\"\n variant=\"outline\"\n disabled={upgrading}\n className=\"h-7 text-xs gap-1 text-blue-400 hover:text-blue-300 border-blue-500/30 disabled:opacity-60\"\n title={upgrading ? `Upgrading to v${upgrade!.desiredVersion}…` : `Upgrade to v${fleetTarget}`}\n onClick={() => upgradeOrchestrator(orch.id)}\n >\n <ArrowUpCircle className={`w-3 h-3 ${upgrading ? 'animate-pulse' : ''}`} />\n {upgrading ? 'Upgrading…' : 'Upgrade'}\n </Button>\n )}\n {online && (\n <Button\n size=\"sm\"\n variant=\"outline\"\n className=\"h-7 text-xs gap-1\"\n onClick={() => orchestratorAction(orch.id, 'restart', undefined, 'orchestrators')}\n >\n <RotateCw className=\"w-3 h-3\" />\n Restart all\n </Button>\n )}\n {online && (\n <Button\n size=\"sm\"\n variant=\"outline\"\n className=\"h-7 text-xs gap-1 text-red-400 hover:text-red-300 border-red-500/30\"\n onClick={() => orchestratorAction(orch.id, 'shutdown', undefined, 'orchestrators')}\n >\n <Power className=\"w-3 h-3\" />\n Shutdown all\n </Button>\n )}\n <Button\n size=\"sm\"\n variant=\"ghost\"\n className=\"h-7 text-xs text-muted-foreground hover:text-red-400\"\n onClick={() => deleteOrchestrator(orch.id)}\n >\n Remove\n </Button>\n </div>\n </CardContent>\n </Card>\n )\n}\n\nexport function OrchestratorsView() {\n const orchestrators = useRelayStore((s) => s.orchestrators)\n const openOrchestratorSpawn = useRelayStore((s) => s.openOrchestratorSpawn)\n const openOrchestratorInstall = useRelayStore((s) => s.openOrchestratorInstall)\n\n const onlineCount = orchestrators.filter((o) => o.status === 'online').length\n\n return (\n <div className=\"space-y-4\">\n {/* Header */}\n <div className=\"flex items-center gap-3\">\n <div>\n <h2 className=\"text-base font-semibold\">Orchestrators</h2>\n <p className=\"text-xs text-muted-foreground\">Multi-host agent lifecycle managers</p>\n </div>\n <div className=\"flex items-center gap-2 ml-auto\">\n <Badge variant=\"outline\" className=\"text-xs\">\n {onlineCount} online\n </Badge>\n <Button size=\"sm\" variant=\"outline\" className=\"gap-1\" onClick={openOrchestratorInstall}>\n <Server className=\"w-3.5 h-3.5\" />\n Add\n </Button>\n <Button size=\"sm\" className=\"gap-1\" onClick={openOrchestratorSpawn}>\n <Plus className=\"w-3.5 h-3.5\" />\n Spawn\n </Button>\n </div>\n </div>\n\n {/* Cards */}\n {orchestrators.length === 0 ? (\n <div className=\"text-center py-16 text-muted-foreground text-sm\">\n No orchestrators registered.\n </div>\n ) : (\n <div className=\"grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-4\">\n {orchestrators.map((orch) => (\n <OrchestratorCard key={orch.id} orch={orch} />\n ))}\n </div>\n )}\n </div>\n )\n}\n"],"mappings":"yYASA,SAAS,EAAgB,CAAE,QAAO,QAAqD,CACrF,IAAM,EAAqB,EAAe,GAAM,EAAE,mBAAmB,CAC/D,EAAc,EAAe,GAAM,EAAE,YAAY,CAEvD,OACE,EAAA,EAAA,MAAC,MAAD,CAAK,UAAU,0CAAf,EACE,EAAA,EAAA,KAAC,EAAD,CAAK,UAAU,6CAA+C,CAAA,EAC9D,EAAA,EAAA,MAAC,MAAD,CAAK,UAAU,0BAAf,EACE,EAAA,EAAA,KAAC,MAAD,CAAK,UAAU,wCACZ,EAAM,OAAS,EAAM,QAAQ,MAAM,IAAI,CACpC,CAAA,EACN,EAAA,EAAA,MAAC,SAAD,CACE,KAAK,SACL,UAAU,wFACV,MAAO,QAAQ,EAAM,KAAO,EAAK,QAAQ,WACzC,QAAU,GAAM,CAAE,EAAE,iBAAiB,CAAE,EAAiB,CAAE,eAAgB,EAAK,GAAI,KAAM,EAAM,KAAO,EAAK,QAAS,CAAC,WAJvH,CAMG,EAAM,SAAS,MAAI,EAAM,KAAO,IAC1B,GACL,IACN,EAAA,EAAA,MAAC,MAAD,CAAK,UAAU,sBAAf,EACE,EAAA,EAAA,KAAC,EAAD,CACE,KAAK,OACL,QAAQ,QACR,UAAU,UACV,MAAM,gBACN,QAAU,GAAM,CAAE,EAAE,iBAAiB,CAAE,EAAmB,EAAK,GAAI,UAAW,EAAM,QAAS,gBAAgB,YAE7G,EAAA,EAAA,KAAC,EAAD,CAAU,UAAU,UAAY,CAAA,CACzB,CAAA,EACT,EAAA,EAAA,KAAC,EAAD,CACE,KAAK,OACL,QAAQ,QACR,UAAU,0CACV,MAAM,iBACN,QAAU,GAAM,CAAE,EAAE,iBAAiB,CAAE,EAAmB,EAAK,GAAI,WAAY,EAAM,QAAS,gBAAgB,YAE9G,EAAA,EAAA,KAAC,EAAD,CAAO,UAAU,UAAY,CAAA,CACtB,CAAA,CACL,GACF,GAIV,SAAS,EAAiB,CAAE,QAAgC,CAC1D,IAAM,EAAM,GAAQ,CACd,EAAqB,EAAe,GAAM,EAAE,mBAAmB,CAC/D,EAAsB,EAAe,GAAM,EAAE,oBAAoB,CACjE,EAAc,EAAe,GAAM,EAAE,MAAM,QAAQ,CACnD,EAA2B,EAAe,GAAM,EAAE,yBAAyB,CAC3E,EAAc,EAAe,GAAM,EAAE,YAAY,CACjD,EAAqB,EAAe,GAAM,EAAE,mBAAmB,CAC/D,EAA+B,EAAe,GAAM,EAAE,6BAA6B,CAEnF,EAAc,EAAwB,EAAK,CAC3C,EAAc,EAAwB,EAAK,CAC3C,EAAS,EAAK,SAAW,SACzB,EAAiB,EAAK,SAAS,SAAW,EAAK,QAC/C,EAAU,EAAK,QACf,EAAY,GAAS,SAAW,UAEhC,EAAiB,GAAU,CAAC,CAAC,EAAK,SAAW,CAAC,CAAC,GAAe,EAAK,UAAY,EAC/E,EAAa,GAAU,CAAC,IAAc,GAAkB,GAAS,SAAW,UAC5E,EAAkB,OAAO,QAAQ,EAAK,WAAa,EAAE,CAAC,CAAC,QAAQ,EAAG,KAAW,OAAO,GAAU,SAAS,CACvG,EAAiB,EAAK,gBAAkB,EAAK,UAAU,IAAK,IAAc,CAAE,KAAM,EAAU,UAAW,GAAM,UAAW,OAAO,EAAK,SAAS,EAAI,KAAK,KAAK,CAAE,EAAE,CAC/J,EAAa,EAAK,cACrB,IAAK,GAAU,EAAM,UAAY,CAAE,QAAO,UAAW,EAAM,UAAW,CAAG,KAAK,CAC9E,OAAQ,GAA6F,GAAQ,GAAM,WAAW,IAAM,GAAM,WAAW,cAAc,CAEtK,OACE,EAAA,EAAA,MAAC,EAAD,CAAM,UAAW,GAAI,EAAwB,GAAf,wBAA9B,EACE,EAAA,EAAA,KAAC,EAAD,CAAY,UAAU,2BACpB,EAAA,EAAA,MAAC,MAAD,CAAK,UAAU,kCAAf,EACE,EAAA,EAAA,KAAC,MAAD,CAAK,UAAW,oBAAoB,EAAS,oBAAsB,0BACjE,EAAA,EAAA,KAAC,EAAD,CAAQ,UAAW,WAAW,EAAS,mBAAqB,kBAAqB,CAAA,CAC7E,CAAA,EACN,EAAA,EAAA,MAAC,MAAD,CAAK,UAAU,0BAAf,EACE,EAAA,EAAA,KAAC,EAAD,CAAW,UAAU,wCAAgC,EAAK,SAAqB,CAAA,EAC/E,EAAA,EAAA,MAAC,MAAD,CAAK,UAAU,gDAAf,CAAuD,EAAK,GAAG,MAAM,EAAG,GAAG,CAAC,IAAO,GAC/E,IACN,EAAA,EAAA,KAAC,EAAD,CAAO,UAAW,wBAAwB,aAAgB,EAAoB,CAAA,CAC1E,GACK,CAAA,EAEb,EAAA,EAAA,MAAC,EAAD,CAAa,UAAU,+BAAvB,EAEE,EAAA,EAAA,MAAC,MAAD,CAAK,UAAU,wEAAf,EACE,EAAA,EAAA,KAAC,OAAD,CAAM,UAAW,EAAS,mBAAqB,yBAAkB,EAAK,OAAc,CAAA,CACnF,IAAkB,EAAA,EAAA,MAAC,OAAD,CAAA,SAAA,CAAO,EAAK,SAAS,MAAQ,eAAe,KAAG,EAAsB,CAAA,CAAA,CACvF,IACC,EAAA,EAAA,MAAC,EAAD,CAAO,UAAU,gFAAjB,EACE,EAAA,EAAA,KAAC,EAAD,CAAe,UAAU,wBAA0B,CAAA,iBAAc,EAAS,eACpE,GAET,CAAC,GAAa,GAAS,SAAW,WACjC,EAAA,EAAA,MAAC,EAAD,CAAO,UAAU,iEAAiE,MAAO,EAAQ,eAAjG,EACE,EAAA,EAAA,KAAC,EAAD,CAAe,UAAU,UAAY,CAAA,CAAA,iBAC/B,GAET,CAAC,GAAa,IACb,EAAA,EAAA,MAAC,EAAD,CAAO,UAAU,uEAAjB,CAA+E,MAAI,EAAY,aAAkB,IAEnH,EAAA,EAAA,KAAC,OAAD,CAAM,UAAU,mBAAW,EAAQ,EAAK,EAAK,SAAS,CAAQ,CAAA,CAC1D,GAEL,EAAe,OAAS,IACvB,EAAA,EAAA,KAAC,MAAD,CAAK,UAAU,gCACZ,EAAe,IAAK,IACnB,EAAA,EAAA,KAAC,EAAD,CAEE,QAAQ,YACR,MAAO,EAAO,UAAa,YAAa,GAAU,EAAO,QAAU,EAAO,QAAU,EAAO,KAAS,WAAY,GAAU,EAAO,OAAS,EAAO,OAAS,GAAG,EAAO,KAAK,cACzK,UAAW,eAAe,EAAO,UAAY,2DAA6D,0DAEzG,EAAO,KACF,CAND,EAAO,KAMN,CACR,CACE,CAAA,CAGP,EAAgB,OAAS,IACxB,EAAA,EAAA,KAAC,MAAD,CAAK,UAAU,gCACZ,EAAgB,KAAK,CAAC,EAAM,MAC3B,EAAA,EAAA,MAAC,EAAD,CAAkB,QAAQ,YAAY,UAAU,uBAAhD,CAA+D,EAAK,IAAE,EAAgB,EAA1E,EAA0E,CACtF,CACE,CAAA,CAIP,EAAK,cAAc,OAAS,IAC3B,EAAA,EAAA,MAAA,EAAA,SAAA,CAAA,SAAA,EACE,EAAA,EAAA,KAAC,EAAD,EAAa,CAAA,EACb,EAAA,EAAA,MAAC,MAAD,CAAA,SAAA,EACE,EAAA,EAAA,MAAC,MAAD,CAAK,UAAU,4DAAf,CAAkE,mBAC/C,EAAK,cAAc,OAAO,IACvC,IACN,EAAA,EAAA,KAAC,MAAD,CAAK,UAAU,qBACZ,EAAK,cAAc,IAAK,IACvB,EAAA,EAAA,KAAC,EAAD,CAAiC,MAAO,EAAS,OAAQ,CAAnC,EAAE,QAAiC,CACzD,CACE,CAAA,CACF,CAAA,CAAA,CACL,CAAA,CAAA,CAGJ,EAAW,OAAS,IACnB,EAAA,EAAA,MAAA,EAAA,SAAA,CAAA,SAAA,EACE,EAAA,EAAA,KAAC,EAAD,EAAa,CAAA,EACb,EAAA,EAAA,MAAC,MAAD,CAAA,SAAA,EACE,EAAA,EAAA,MAAC,MAAD,CAAK,UAAU,4DAAf,CAAkE,eACnD,EAAW,OAAO,IAC3B,IACN,EAAA,EAAA,KAAC,MAAD,CAAK,UAAU,qBACZ,EAAW,KAAK,CAAE,QAAO,gBACxB,EAAA,EAAA,MAAC,SAAD,CAEE,KAAK,SACL,UAAU,gGACV,YAAe,EAAU,cAAgB,KAAK,EAAY,CAAE,eAAgB,EAAK,GAAI,KAAM,EAAU,aAAc,CAAC,UAJtH,EAME,EAAA,EAAA,MAAC,MAAD,CAAK,UAAU,2CAAf,EACE,EAAA,EAAA,KAAC,OAAD,CAAM,UAAU,gCAAwB,EAAU,QAAU,EAAM,OAAS,EAAM,QAAQ,MAAM,IAAI,CAAQ,CAAA,CAC1G,EAAU,SAAU,EAAA,EAAA,KAAC,EAAD,CAAO,QAAQ,UAAU,UAAU,oCAA4B,EAAU,OAAe,CAAA,CACzG,IACN,EAAA,EAAA,KAAC,MAAD,CAAK,UAAU,sDAA8C,EAAU,cAAgB,EAAU,SAAe,CAAA,CACzG,EAVF,EAAU,IAAM,EAAU,aAUxB,CACT,CACE,CAAA,CACF,CAAA,CAAA,CACL,CAAA,CAAA,EAIL,EAAA,EAAA,KAAC,EAAD,EAAa,CAAA,EACb,EAAA,EAAA,MAAC,MAAD,CAAK,UAAU,kCAAf,CACG,IACC,EAAA,EAAA,MAAC,EAAD,CAAQ,KAAK,KAAK,QAAQ,UAAU,UAAU,oBAAoB,YAAe,EAAyB,EAAK,GAAG,UAAlH,EACE,EAAA,EAAA,KAAC,EAAD,CAAM,UAAU,UAAY,CAAA,CAAA,cAErB,GAEV,IACC,EAAA,EAAA,MAAC,EAAD,CACE,KAAK,KACL,QAAQ,UACR,UAAU,oBACV,YAAe,EAA6B,EAAK,GAAG,UAJtD,EAME,EAAA,EAAA,KAAC,EAAD,CAAU,UAAU,UAAY,CAAA,CAAA,oBAEzB,IAET,GAAc,KACd,EAAA,EAAA,MAAC,EAAD,CACE,KAAK,KACL,QAAQ,UACR,SAAU,EACV,UAAU,6FACV,MAAO,EAAY,iBAAiB,EAAS,eAAe,GAAK,eAAe,IAChF,YAAe,EAAoB,EAAK,GAAG,UAN7C,EAQE,EAAA,EAAA,KAAC,EAAD,CAAe,UAAW,WAAW,EAAY,gBAAkB,KAAQ,CAAA,CAC1E,EAAY,aAAe,UACrB,GAEV,IACC,EAAA,EAAA,MAAC,EAAD,CACE,KAAK,KACL,QAAQ,UACR,UAAU,oBACV,YAAe,EAAmB,EAAK,GAAI,UAAW,IAAA,GAAW,gBAAgB,UAJnF,EAME,EAAA,EAAA,KAAC,EAAD,CAAU,UAAU,UAAY,CAAA,CAAA,cAEzB,GAEV,IACC,EAAA,EAAA,MAAC,EAAD,CACE,KAAK,KACL,QAAQ,UACR,UAAU,sEACV,YAAe,EAAmB,EAAK,GAAI,WAAY,IAAA,GAAW,gBAAgB,UAJpF,EAME,EAAA,EAAA,KAAC,EAAD,CAAO,UAAU,UAAY,CAAA,CAAA,eAEtB,IAEX,EAAA,EAAA,KAAC,EAAD,CACE,KAAK,KACL,QAAQ,QACR,UAAU,uDACV,YAAe,EAAmB,EAAK,GAAG,UAC3C,SAEQ,CAAA,CACL,GACM,GACT,GAIX,SAAgB,GAAoB,CAClC,IAAM,EAAgB,EAAe,GAAM,EAAE,cAAc,CACrD,EAAwB,EAAe,GAAM,EAAE,sBAAsB,CACrE,EAA0B,EAAe,GAAM,EAAE,wBAAwB,CAEzE,EAAc,EAAc,OAAQ,GAAM,EAAE,SAAW,SAAS,CAAC,OAEvE,OACE,EAAA,EAAA,MAAC,MAAD,CAAK,UAAU,qBAAf,EAEE,EAAA,EAAA,MAAC,MAAD,CAAK,UAAU,mCAAf,EACE,EAAA,EAAA,MAAC,MAAD,CAAA,SAAA,EACE,EAAA,EAAA,KAAC,KAAD,CAAI,UAAU,mCAA0B,gBAAkB,CAAA,EAC1D,EAAA,EAAA,KAAC,IAAD,CAAG,UAAU,yCAAgC,sCAAuC,CAAA,CAChF,CAAA,CAAA,EACN,EAAA,EAAA,MAAC,MAAD,CAAK,UAAU,2CAAf,EACE,EAAA,EAAA,MAAC,EAAD,CAAO,QAAQ,UAAU,UAAU,mBAAnC,CACG,EAAY,UACP,IACR,EAAA,EAAA,MAAC,EAAD,CAAQ,KAAK,KAAK,QAAQ,UAAU,UAAU,QAAQ,QAAS,WAA/D,EACE,EAAA,EAAA,KAAC,EAAD,CAAQ,UAAU,cAAgB,CAAA,CAAA,MAE3B,IACT,EAAA,EAAA,MAAC,EAAD,CAAQ,KAAK,KAAK,UAAU,QAAQ,QAAS,WAA7C,EACE,EAAA,EAAA,KAAC,EAAD,CAAM,UAAU,cAAgB,CAAA,CAAA,QAEzB,GACL,GACF,GAGL,EAAc,SAAW,GACxB,EAAA,EAAA,KAAC,MAAD,CAAK,UAAU,2DAAkD,+BAE3D,CAAA,EAEN,EAAA,EAAA,KAAC,MAAD,CAAK,UAAU,gEACZ,EAAc,IAAK,IAClB,EAAA,EAAA,KAAC,EAAD,CAAsC,OAAQ,CAAvB,EAAK,GAAkB,CAC9C,CACE,CAAA,CAEJ"}
1
+ {"version":3,"file":"orchestrators-PMUp2sUP.js","names":[],"sources":["../../dashboard/src/components/views/orchestrators.tsx"],"sourcesContent":["import { useRelayStore, useNow } from '@/store'\nimport { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'\nimport { Badge } from '@/components/ui/badge'\nimport { Button } from '@/components/ui/button'\nimport { Separator } from '@/components/ui/separator'\nimport { displayName, orchestratorHealthLabel, orchestratorHealthClass, timeAgo } from '@/lib/display'\nimport { Server, Plus, RotateCw, Power, Cpu, ArrowUpCircle, AlertTriangle } from 'lucide-react'\nimport type { Orchestrator, ManagedAgent } from '@/types'\n\nfunction ManagedAgentRow({ agent, orch }: { agent: ManagedAgent; orch: Orchestrator }) {\n const orchestratorAction = useRelayStore((s) => s.orchestratorAction)\n const openFilesAt = useRelayStore((s) => s.openFilesAt)\n\n return (\n <div className=\"flex items-center gap-2 py-1.5\">\n <Cpu className=\"w-3.5 h-3.5 text-muted-foreground shrink-0\" />\n <div className=\"flex-1 min-w-0\">\n <div className=\"text-xs font-medium truncate\">\n {agent.label || agent.agentId.slice(-12)}\n </div>\n <button\n type=\"button\"\n className=\"max-w-full truncate text-left text-[10px] text-muted-foreground hover:text-foreground\"\n title={`Open ${agent.cwd || orch.baseDir} in Files`}\n onClick={(e) => { e.stopPropagation(); void openFilesAt({ orchestratorId: orch.id, path: agent.cwd || orch.baseDir }) }}\n >\n {agent.provider} · {agent.cwd || '~'}\n </button>\n </div>\n <div className=\"flex gap-1\">\n <Button\n size=\"icon\"\n variant=\"ghost\"\n className=\"h-6 w-6\"\n title=\"Restart agent\"\n onClick={(e) => { e.stopPropagation(); orchestratorAction(orch.id, 'restart', agent.agentId, 'orchestrators') }}\n >\n <RotateCw className=\"w-3 h-3\" />\n </Button>\n <Button\n size=\"icon\"\n variant=\"ghost\"\n className=\"h-6 w-6 text-red-400 hover:text-red-300\"\n title=\"Shutdown agent\"\n onClick={(e) => { e.stopPropagation(); orchestratorAction(orch.id, 'shutdown', agent.agentId, 'orchestrators') }}\n >\n <Power className=\"w-3 h-3\" />\n </Button>\n </div>\n </div>\n )\n}\n\nfunction OrchestratorCard({ orch }: { orch: Orchestrator }) {\n const now = useNow()\n const orchestratorAction = useRelayStore((s) => s.orchestratorAction)\n const upgradeOrchestrator = useRelayStore((s) => s.upgradeOrchestrator)\n const fleetTarget = useRelayStore((s) => s.stats.version)\n const openOrchestratorSpawnFor = useRelayStore((s) => s.openOrchestratorSpawnFor)\n const openFilesAt = useRelayStore((s) => s.openFilesAt)\n const deleteOrchestrator = useRelayStore((s) => s.deleteOrchestrator)\n const refreshOrchestratorProviders = useRelayStore((s) => s.refreshOrchestratorProviders)\n\n const healthLabel = orchestratorHealthLabel(orch)\n const healthClass = orchestratorHealthClass(orch)\n const online = orch.status === 'online'\n const packageVersion = orch.package?.version || orch.version\n const upgrade = orch.upgrade\n const upgrading = upgrade?.status === 'pending'\n // Drift = reported version differs from the relay's own version (fleet target).\n const driftAvailable = online && !!orch.version && !!fleetTarget && orch.version !== fleetTarget\n const canUpgrade = online && !upgrading && (driftAvailable || upgrade?.status === 'failed')\n const contractEntries = Object.entries(orch.contracts || {}).filter(([, value]) => typeof value === 'number')\n const providerStatus = orch.providerStatus || orch.providers.map((provider) => ({ name: provider, available: true, checkedAt: Number(orch.lastSeen) || Date.now() }))\n const workspaces = orch.managedAgents\n .map((agent) => agent.workspace ? { agent, workspace: agent.workspace } : null)\n .filter((item): item is { agent: ManagedAgent; workspace: NonNullable<ManagedAgent['workspace']> } => Boolean(item?.workspace?.id || item?.workspace?.worktreePath))\n\n return (\n <Card className={`${!online ? 'opacity-60' : ''}`}>\n <CardHeader className=\"pb-2 pt-4 px-4\">\n <div className=\"flex items-start gap-2\">\n <div className={`p-1.5 rounded-md ${online ? 'bg-emerald-500/10' : 'bg-zinc-800'}`}>\n <Server className={`w-4 h-4 ${online ? 'text-emerald-400' : 'text-zinc-500'}`} />\n </div>\n <div className=\"flex-1 min-w-0\">\n <CardTitle className=\"text-sm font-medium truncate\">{orch.hostname}</CardTitle>\n <div className=\"text-xs text-muted-foreground mt-0.5\">{orch.id.slice(0, 16)}…</div>\n </div>\n <Badge className={`text-[10px] shrink-0 ${healthClass}`}>{healthLabel}</Badge>\n </div>\n </CardHeader>\n\n <CardContent className=\"px-4 pb-4 space-y-3\">\n {/* Meta row */}\n <div className=\"flex flex-wrap gap-x-4 gap-y-1 text-xs text-muted-foreground\">\n <span className={online ? 'text-emerald-400' : 'text-zinc-500'}>{orch.status}</span>\n {packageVersion && <span>{orch.package?.name || 'orchestrator'} v{packageVersion}</span>}\n {upgrading && (\n <Badge className=\"text-[10px] bg-amber-500/10 text-amber-400 border-amber-500/20 gap-1\">\n <ArrowUpCircle className=\"w-3 h-3 animate-pulse\" />upgrading → v{upgrade!.desiredVersion}\n </Badge>\n )}\n {!upgrading && upgrade?.status === 'failed' && (\n <Badge className=\"text-[10px] bg-red-500/10 text-red-400 border-red-500/20 gap-1\" title={upgrade.error}>\n <AlertTriangle className=\"w-3 h-3\" />upgrade failed\n </Badge>\n )}\n {!upgrading && driftAvailable && (\n <Badge className=\"text-[10px] bg-blue-500/10 text-blue-400 border-blue-500/20\">→ v{fleetTarget} available</Badge>\n )}\n <span className=\"ml-auto\">{timeAgo(now, orch.lastSeen)}</span>\n </div>\n\n {providerStatus.length > 0 && (\n <div className=\"flex flex-wrap gap-1\">\n {providerStatus.map((status) => (\n <Badge\n key={status.name}\n variant=\"secondary\"\n title={status.available ? ('version' in status && status.version ? status.version : status.name) : ('reason' in status && status.reason ? status.reason : `${status.name} unavailable`)}\n className={`text-[10px] ${status.available ? 'bg-emerald-500/10 text-emerald-400 border-emerald-500/20' : 'bg-red-500/10 text-red-400 border-red-500/20'}`}\n >\n {status.name}\n </Badge>\n ))}\n </div>\n )}\n\n {contractEntries.length > 0 && (\n <div className=\"flex flex-wrap gap-1\">\n {contractEntries.map(([name, version]) => (\n <Badge key={name} variant=\"secondary\" className=\"text-[10px]\">{name}={version}</Badge>\n ))}\n </div>\n )}\n\n {/* Managed agents */}\n {orch.managedAgents.length > 0 && (\n <>\n <Separator />\n <div>\n <div className=\"text-xs font-medium text-muted-foreground mb-1.5\">\n Managed agents ({orch.managedAgents.length})\n </div>\n <div className=\"space-y-0\">\n {orch.managedAgents.map((a) => (\n <ManagedAgentRow key={a.agentId} agent={a} orch={orch} />\n ))}\n </div>\n </div>\n </>\n )}\n\n {workspaces.length > 0 && (\n <>\n <Separator />\n <div>\n <div className=\"text-xs font-medium text-muted-foreground mb-1.5\">\n Workspaces ({workspaces.length})\n </div>\n <div className=\"space-y-1\">\n {workspaces.map(({ agent, workspace }) => (\n <button\n key={workspace.id || workspace.worktreePath}\n type=\"button\"\n className=\"block w-full min-w-0 rounded border border-border/60 px-2 py-1.5 text-left hover:bg-accent/40\"\n onClick={() => workspace.worktreePath && void openFilesAt({ orchestratorId: orch.id, path: workspace.worktreePath })}\n >\n <div className=\"flex items-center gap-2 text-xs\">\n <span className=\"truncate font-medium\">{workspace.branch || agent.label || agent.agentId.slice(-12)}</span>\n {workspace.status && <Badge variant=\"outline\" className=\"h-4 shrink-0 text-[10px]\">{workspace.status}</Badge>}\n </div>\n <div className=\"truncate text-[10px] text-muted-foreground\">{workspace.worktreePath || workspace.repoRoot}</div>\n </button>\n ))}\n </div>\n </div>\n </>\n )}\n\n {/* Actions */}\n <Separator />\n <div className=\"flex flex-wrap gap-1.5\">\n {online && (\n <Button size=\"sm\" variant=\"outline\" className=\"h-7 text-xs gap-1\" onClick={() => openOrchestratorSpawnFor(orch.id)}>\n <Plus className=\"w-3 h-3\" />\n Spawn agent\n </Button>\n )}\n {online && (\n <Button\n size=\"sm\"\n variant=\"outline\"\n className=\"h-7 text-xs gap-1\"\n onClick={() => refreshOrchestratorProviders(orch.id)}\n >\n <RotateCw className=\"w-3 h-3\" />\n Refresh providers\n </Button>\n )}\n {(canUpgrade || upgrading) && (\n <Button\n size=\"sm\"\n variant=\"outline\"\n disabled={upgrading}\n className=\"h-7 text-xs gap-1 text-blue-400 hover:text-blue-300 border-blue-500/30 disabled:opacity-60\"\n title={upgrading ? `Upgrading to v${upgrade!.desiredVersion}…` : `Upgrade to v${fleetTarget}`}\n onClick={() => upgradeOrchestrator(orch.id)}\n >\n <ArrowUpCircle className={`w-3 h-3 ${upgrading ? 'animate-pulse' : ''}`} />\n {upgrading ? 'Upgrading…' : 'Upgrade'}\n </Button>\n )}\n {online && (\n <Button\n size=\"sm\"\n variant=\"outline\"\n className=\"h-7 text-xs gap-1\"\n onClick={() => orchestratorAction(orch.id, 'restart', undefined, 'orchestrators')}\n >\n <RotateCw className=\"w-3 h-3\" />\n Restart all\n </Button>\n )}\n {online && (\n <Button\n size=\"sm\"\n variant=\"outline\"\n className=\"h-7 text-xs gap-1 text-red-400 hover:text-red-300 border-red-500/30\"\n onClick={() => orchestratorAction(orch.id, 'shutdown', undefined, 'orchestrators')}\n >\n <Power className=\"w-3 h-3\" />\n Shutdown all\n </Button>\n )}\n <Button\n size=\"sm\"\n variant=\"ghost\"\n className=\"h-7 text-xs text-muted-foreground hover:text-red-400\"\n onClick={() => deleteOrchestrator(orch.id)}\n >\n Remove\n </Button>\n </div>\n </CardContent>\n </Card>\n )\n}\n\nexport function OrchestratorsView() {\n const orchestrators = useRelayStore((s) => s.orchestrators)\n const openOrchestratorSpawn = useRelayStore((s) => s.openOrchestratorSpawn)\n const openOrchestratorInstall = useRelayStore((s) => s.openOrchestratorInstall)\n\n const onlineCount = orchestrators.filter((o) => o.status === 'online').length\n\n return (\n <div className=\"space-y-4\">\n {/* Header */}\n <div className=\"flex items-center gap-3\">\n <div>\n <h2 className=\"text-base font-semibold\">Orchestrators</h2>\n <p className=\"text-xs text-muted-foreground\">Multi-host agent lifecycle managers</p>\n </div>\n <div className=\"flex items-center gap-2 ml-auto\">\n <Badge variant=\"outline\" className=\"text-xs\">\n {onlineCount} online\n </Badge>\n <Button size=\"sm\" variant=\"outline\" className=\"gap-1\" onClick={openOrchestratorInstall}>\n <Server className=\"w-3.5 h-3.5\" />\n Add\n </Button>\n <Button size=\"sm\" className=\"gap-1\" onClick={openOrchestratorSpawn}>\n <Plus className=\"w-3.5 h-3.5\" />\n Spawn\n </Button>\n </div>\n </div>\n\n {/* Cards */}\n {orchestrators.length === 0 ? (\n <div className=\"text-center py-16 text-muted-foreground text-sm\">\n No orchestrators registered.\n </div>\n ) : (\n <div className=\"grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-4\">\n {orchestrators.map((orch) => (\n <OrchestratorCard key={orch.id} orch={orch} />\n ))}\n </div>\n )}\n </div>\n )\n}\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- import{r as e}from"./chunk-CilyBKbf.js";import{$ as t,En as n,J as r,Vn as i,at as a,kn as o,l as s,mn as c,mt as l,ot as u,p as d}from"./lucide-react-CD8Xl2U3.js";import{i as f,t as p}from"./store-CICRhg1m.js";import{B as m,E as h,U as g,d as _,h as v,ot as y,u as b,z as x}from"./display-Bebqs1qu.js";import{t as S}from"./badge-t8zAwHW9.js";import{A as C,D as w,N as T,_ as E,g as D,j as O,s as k}from"./index-BL8r94_U.js";import{i as A,n as j,r as M,t as N}from"./card-CggxP1h9.js";var P=e(i(),1),F=o();function I(){let e=p(e=>e.stats),i=p(e=>e.agents),o=p(e=>e.messages),I=p(e=>e.health),L=f(),R=p(e=>e.agentsById),z=p(e=>e.switchView),B=p(e=>e.runHealthAction),V=p(e=>e.managedPolicies),H=p(e=>e.showOffline),U=T(),W=O(),G=C(),K=(0,P.useMemo)(()=>{let e=g(i,!1,V);return H||(e=e.filter(e=>e.status!==`offline`)),[...e].sort((e,t)=>(y[e.status]??9)-(y[t.status]??9)||m(t.lastSeen)-m(e.lastSeen))},[i,H,V]),q=K.slice(0,20),J=[...o].sort((e,t)=>t.id-e.id).slice(0,15),Y=I&&I.status!==`ok`?v(I.checks||[]):[];function X(e){z(e)}return(0,F.jsxs)(`div`,{className:`space-y-6`,children:[(0,F.jsxs)(`div`,{className:`grid grid-cols-2 md:grid-cols-4 gap-4`,children:[(0,F.jsxs)(N,{className:`cursor-pointer hover:border-zinc-600 transition-colors`,onClick:()=>X(`agents`),children:[(0,F.jsx)(M,{className:`pb-1 pt-4 px-4`,children:(0,F.jsxs)(A,{className:`text-xs font-medium text-muted-foreground flex items-center gap-1.5`,children:[(0,F.jsx)(s,{className:`w-3.5 h-3.5`}),`Agents`]})}),(0,F.jsxs)(j,{className:`px-4 pb-4`,children:[(0,F.jsx)(`div`,{className:`text-2xl font-bold`,children:K.length}),(0,F.jsxs)(`div`,{className:`text-xs text-muted-foreground mt-0.5`,children:[U,` online`]})]})]}),(0,F.jsxs)(N,{className:`cursor-pointer hover:border-zinc-600 transition-colors`,onClick:()=>X(`agents`),children:[(0,F.jsx)(M,{className:`pb-1 pt-4 px-4`,children:(0,F.jsxs)(A,{className:`text-xs font-medium text-muted-foreground flex items-center gap-1.5`,children:[(0,F.jsx)(n,{className:`w-3.5 h-3.5`}),`Busy`]})}),(0,F.jsxs)(j,{className:`px-4 pb-4`,children:[(0,F.jsx)(`div`,{className:`text-2xl font-bold`,children:W}),(0,F.jsx)(`div`,{className:`text-xs text-muted-foreground mt-0.5`,children:`in a turn now`})]})]}),(0,F.jsxs)(N,{className:`cursor-pointer hover:border-zinc-600 transition-colors`,onClick:()=>X(`messages`),children:[(0,F.jsx)(M,{className:`pb-1 pt-4 px-4`,children:(0,F.jsxs)(A,{className:`text-xs font-medium text-muted-foreground flex items-center gap-1.5`,children:[(0,F.jsx)(r,{className:`w-3.5 h-3.5`}),`Messages 24h`]})}),(0,F.jsxs)(j,{className:`px-4 pb-4`,children:[(0,F.jsx)(`div`,{className:`text-2xl font-bold`,children:e.messagesLast24h??`—`}),(0,F.jsx)(`div`,{className:`text-xs text-muted-foreground mt-0.5`,children:`last 24 hours`})]})]}),(0,F.jsxs)(N,{className:`cursor-pointer hover:border-zinc-600 transition-colors`,onClick:()=>X(`messages`),children:[(0,F.jsx)(M,{className:`pb-1 pt-4 px-4`,children:(0,F.jsxs)(A,{className:`text-xs font-medium text-muted-foreground flex items-center gap-1.5`,children:[(0,F.jsx)(t,{className:`w-3.5 h-3.5`}),`Total Messages`]})}),(0,F.jsxs)(j,{className:`px-4 pb-4`,children:[(0,F.jsx)(`div`,{className:`text-2xl font-bold`,children:e.messages??`—`}),(0,F.jsx)(`div`,{className:`text-xs text-muted-foreground mt-0.5`,children:`all time`})]})]})]}),Y.length>0&&(0,F.jsxs)(N,{className:`border-yellow-500/40 bg-yellow-500/5`,children:[(0,F.jsx)(M,{className:`pb-2 pt-4 px-4`,children:(0,F.jsxs)(A,{className:`text-sm font-medium text-yellow-400 flex items-center gap-2`,children:[(0,F.jsx)(d,{className:`w-4 h-4`}),`Health Alerts (`,Y.length,`)`]})}),(0,F.jsx)(j,{className:`px-4 pb-4 space-y-2`,children:Y.map(e=>(0,F.jsxs)(`div`,{className:`text-sm space-y-1`,children:[(0,F.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,F.jsx)(S,{variant:`outline`,className:e.status===`error`?`border-red-500/40 text-red-400`:`border-yellow-500/40 text-yellow-400`,children:e.status}),(0,F.jsx)(`span`,{className:`font-medium`,children:e.name})]}),(0,F.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:e.detail}),e.subjects.length>0&&(0,F.jsx)(`div`,{className:`flex flex-wrap gap-1.5`,children:e.subjects.map(e=>(0,F.jsxs)(S,{variant:`secondary`,className:`max-w-full truncate text-[11px]`,title:[e.id,e.status,e.detail].filter(Boolean).join(` · `),children:[e.label||e.id,e.status?` · ${e.status}`:``,e.detail?` · ${e.detail}`:``]},e.id))}),e.actions.length>0&&(0,F.jsx)(`div`,{className:`flex flex-wrap gap-1.5 pt-0.5`,children:e.actions.slice(0,3).map(e=>(0,F.jsx)(`button`,{onClick:()=>B(e),className:`text-xs text-blue-400 hover:text-blue-300 underline underline-offset-2`,children:e.label},e.label))})]},e.name))})]}),(0,F.jsxs)(`div`,{className:`grid grid-cols-1 sm:grid-cols-3 gap-4`,children:[(0,F.jsx)(N,{className:`cursor-pointer hover:border-zinc-600 transition-colors ${G.unreadInbox>0?`border-red-500/40`:``}`,onClick:()=>X(`chat`),children:(0,F.jsxs)(j,{className:`p-4 flex items-center gap-3`,children:[(0,F.jsx)(`div`,{className:`p-2 rounded-lg ${G.unreadInbox>0?`bg-red-500/15`:`bg-zinc-800`}`,children:(0,F.jsx)(l,{className:`w-4 h-4 ${G.unreadInbox>0?`text-red-400`:`text-zinc-400`}`})}),(0,F.jsxs)(`div`,{children:[(0,F.jsx)(`div`,{className:`text-lg font-bold`,children:G.unreadInbox}),(0,F.jsx)(`div`,{className:`text-xs text-muted-foreground`,children:`Unread`})]})]})}),(0,F.jsx)(N,{className:`cursor-pointer hover:border-zinc-600 transition-colors ${G.pendingPairInvites>0?`border-yellow-500/40`:``}`,onClick:()=>X(`pairs`),children:(0,F.jsxs)(j,{className:`p-4 flex items-center gap-3`,children:[(0,F.jsx)(`div`,{className:`p-2 rounded-lg ${G.pendingPairInvites>0?`bg-yellow-500/15`:`bg-zinc-800`}`,children:(0,F.jsx)(u,{className:`w-4 h-4 ${G.pendingPairInvites>0?`text-yellow-400`:`text-zinc-400`}`})}),(0,F.jsxs)(`div`,{children:[(0,F.jsx)(`div`,{className:`text-lg font-bold`,children:G.pendingPairInvites}),(0,F.jsx)(`div`,{className:`text-xs text-muted-foreground`,children:`Pair invites`})]})]})}),(0,F.jsx)(N,{className:`cursor-pointer hover:border-zinc-600 transition-colors ${G.claimableTasks>0?`border-orange-500/40`:``}`,onClick:()=>X(`work`),children:(0,F.jsxs)(j,{className:`p-4 flex items-center gap-3`,children:[(0,F.jsx)(`div`,{className:`p-2 rounded-lg ${G.claimableTasks>0?`bg-orange-500/15`:`bg-zinc-800`}`,children:(0,F.jsx)(a,{className:`w-4 h-4 ${G.claimableTasks>0?`text-orange-400`:`text-zinc-400`}`})}),(0,F.jsxs)(`div`,{children:[(0,F.jsx)(`div`,{className:`text-lg font-bold`,children:G.claimableTasks}),(0,F.jsx)(`div`,{className:`text-xs text-muted-foreground`,children:`Claimable waiting`})]})]})})]}),(0,F.jsxs)(`div`,{className:`grid grid-cols-1 md:grid-cols-2 gap-6`,children:[(0,F.jsxs)(N,{children:[(0,F.jsx)(M,{className:`pb-2 pt-4 px-4`,children:(0,F.jsxs)(A,{className:`text-sm font-medium flex items-center gap-2`,children:[(0,F.jsx)(c,{className:`w-4 h-4 text-muted-foreground`}),`Agents`,(0,F.jsx)(`span`,{className:`ml-auto text-xs text-muted-foreground font-normal`,children:q.length})]})}),(0,F.jsx)(j,{className:`px-0 pb-0`,children:(0,F.jsx)(k,{className:`h-[340px]`,children:q.length===0?(0,F.jsx)(`div`,{className:`px-4 pb-4 text-sm text-muted-foreground`,children:`No agents registered.`}):(0,F.jsx)(`div`,{className:`space-y-0`,children:q.map((e,t)=>(0,F.jsxs)(`div`,{children:[t>0&&(0,F.jsx)(w,{}),(0,F.jsxs)(`div`,{className:`flex items-center gap-2.5 px-4 py-2.5 hover:bg-zinc-800/50 transition-colors cursor-pointer`,onClick:()=>p.getState().openAgentDetail(e),children:[(0,F.jsx)(E,{agent:e,now:L}),(0,F.jsx)(D,{agent:e}),(0,F.jsxs)(`div`,{className:`flex-1 min-w-0`,children:[(0,F.jsx)(`div`,{className:`text-sm font-medium truncate`,children:b(e)}),e.tags.length>0&&(0,F.jsx)(`div`,{className:`flex gap-1 mt-0.5 flex-wrap`,children:e.tags.slice(0,2).map(e=>(0,F.jsx)(S,{variant:`outline`,className:`text-[9px] px-1 py-0 h-4`,children:e},e))})]}),(0,F.jsx)(`span`,{className:`text-xs text-muted-foreground shrink-0`,children:x(L,e.lastSeen)})]})]},e.id))})})})]}),(0,F.jsxs)(N,{children:[(0,F.jsx)(M,{className:`pb-2 pt-4 px-4`,children:(0,F.jsxs)(A,{className:`text-sm font-medium flex items-center gap-2`,children:[(0,F.jsx)(n,{className:`w-4 h-4 text-muted-foreground`}),`Recent Activity`,(0,F.jsx)(`span`,{className:`ml-auto text-xs text-muted-foreground font-normal`,children:J.length})]})}),(0,F.jsx)(j,{className:`px-0 pb-0`,children:(0,F.jsx)(k,{className:`h-[340px]`,children:J.length===0?(0,F.jsx)(`div`,{className:`px-4 pb-4 text-sm text-muted-foreground`,children:`No recent messages.`}):(0,F.jsx)(`div`,{className:`space-y-0`,children:J.map((e,t)=>(0,F.jsxs)(`div`,{children:[t>0&&(0,F.jsx)(w,{}),(0,F.jsxs)(`div`,{className:`px-4 py-2.5 hover:bg-zinc-800/50 transition-colors`,children:[(0,F.jsxs)(`div`,{className:`flex items-center gap-1 text-xs text-muted-foreground mb-0.5`,children:[(0,F.jsx)(`span`,{className:`text-foreground font-medium truncate max-w-[100px]`,children:_(e.from,R)}),(0,F.jsx)(`span`,{children:`→`}),(0,F.jsx)(`span`,{className:`truncate max-w-[100px]`,children:_(e.to,R)}),(0,F.jsxs)(`span`,{className:`ml-auto shrink-0 tabular-nums`,children:[(0,F.jsxs)(`span`,{className:`opacity-40 mr-1`,children:[`#`,e.id]}),x(L,e.createdAt)]})]}),(0,F.jsx)(`div`,{className:`text-xs text-foreground line-clamp-2 leading-snug`,children:h(e)})]})]},e.id))})})})]})]})]})}export{I as OverviewView};
2
- //# sourceMappingURL=overview-CXcGh2D6.js.map
1
+ import{r as e}from"./chunk-CilyBKbf.js";import{$ as t,An as n,Dn as r,Hn as i,J as a,at as o,l as s,mn as c,mt as l,ot as u,p as d}from"./lucide-react-DLQFnqNm.js";import{i as f,t as p}from"./store-CMUFZKxf.js";import{H as m,K as h,U as g,d as _,f as v,g as y,k as b,lt as x}from"./display-ConJ9cJB.js";import{t as S}from"./badge-JVybSpzR.js";import{A as C,D as w,N as T,_ as E,g as D,j as O,s as k}from"./index-DdB6SVZY.js";import{i as A,n as j,r as M,t as N}from"./card-I8w4U656.js";var P=e(i(),1),F=n();function I(){let e=p(e=>e.stats),n=p(e=>e.agents),i=p(e=>e.messages),I=p(e=>e.health),L=f(),R=p(e=>e.agentsById),z=p(e=>e.switchView),B=p(e=>e.runHealthAction),V=p(e=>e.managedPolicies),H=p(e=>e.showOffline),U=T(),W=O(),G=C(),K=(0,P.useMemo)(()=>{let e=h(n,!1,V);return H||(e=e.filter(e=>e.status!==`offline`)),[...e].sort((e,t)=>(x[e.status]??9)-(x[t.status]??9)||g(t.lastSeen)-g(e.lastSeen))},[n,H,V]),q=K.slice(0,20),J=[...i].sort((e,t)=>t.id-e.id).slice(0,15),Y=I&&I.status!==`ok`?y(I.checks||[]):[];function X(e){z(e)}return(0,F.jsxs)(`div`,{className:`space-y-6`,children:[(0,F.jsxs)(`div`,{className:`grid grid-cols-2 md:grid-cols-4 gap-4`,children:[(0,F.jsxs)(N,{className:`cursor-pointer hover:border-zinc-600 transition-colors`,onClick:()=>X(`agents`),children:[(0,F.jsx)(M,{className:`pb-1 pt-4 px-4`,children:(0,F.jsxs)(A,{className:`text-xs font-medium text-muted-foreground flex items-center gap-1.5`,children:[(0,F.jsx)(s,{className:`w-3.5 h-3.5`}),`Agents`]})}),(0,F.jsxs)(j,{className:`px-4 pb-4`,children:[(0,F.jsx)(`div`,{className:`text-2xl font-bold`,children:K.length}),(0,F.jsxs)(`div`,{className:`text-xs text-muted-foreground mt-0.5`,children:[U,` online`]})]})]}),(0,F.jsxs)(N,{className:`cursor-pointer hover:border-zinc-600 transition-colors`,onClick:()=>X(`agents`),children:[(0,F.jsx)(M,{className:`pb-1 pt-4 px-4`,children:(0,F.jsxs)(A,{className:`text-xs font-medium text-muted-foreground flex items-center gap-1.5`,children:[(0,F.jsx)(r,{className:`w-3.5 h-3.5`}),`Busy`]})}),(0,F.jsxs)(j,{className:`px-4 pb-4`,children:[(0,F.jsx)(`div`,{className:`text-2xl font-bold`,children:W}),(0,F.jsx)(`div`,{className:`text-xs text-muted-foreground mt-0.5`,children:`in a turn now`})]})]}),(0,F.jsxs)(N,{className:`cursor-pointer hover:border-zinc-600 transition-colors`,onClick:()=>X(`messages`),children:[(0,F.jsx)(M,{className:`pb-1 pt-4 px-4`,children:(0,F.jsxs)(A,{className:`text-xs font-medium text-muted-foreground flex items-center gap-1.5`,children:[(0,F.jsx)(a,{className:`w-3.5 h-3.5`}),`Messages 24h`]})}),(0,F.jsxs)(j,{className:`px-4 pb-4`,children:[(0,F.jsx)(`div`,{className:`text-2xl font-bold`,children:e.messagesLast24h??`—`}),(0,F.jsx)(`div`,{className:`text-xs text-muted-foreground mt-0.5`,children:`last 24 hours`})]})]}),(0,F.jsxs)(N,{className:`cursor-pointer hover:border-zinc-600 transition-colors`,onClick:()=>X(`messages`),children:[(0,F.jsx)(M,{className:`pb-1 pt-4 px-4`,children:(0,F.jsxs)(A,{className:`text-xs font-medium text-muted-foreground flex items-center gap-1.5`,children:[(0,F.jsx)(t,{className:`w-3.5 h-3.5`}),`Total Messages`]})}),(0,F.jsxs)(j,{className:`px-4 pb-4`,children:[(0,F.jsx)(`div`,{className:`text-2xl font-bold`,children:e.messages??`—`}),(0,F.jsx)(`div`,{className:`text-xs text-muted-foreground mt-0.5`,children:`all time`})]})]})]}),Y.length>0&&(0,F.jsxs)(N,{className:`border-yellow-500/40 bg-yellow-500/5`,children:[(0,F.jsx)(M,{className:`pb-2 pt-4 px-4`,children:(0,F.jsxs)(A,{className:`text-sm font-medium text-yellow-400 flex items-center gap-2`,children:[(0,F.jsx)(d,{className:`w-4 h-4`}),`Health Alerts (`,Y.length,`)`]})}),(0,F.jsx)(j,{className:`px-4 pb-4 space-y-2`,children:Y.map(e=>(0,F.jsxs)(`div`,{className:`text-sm space-y-1`,children:[(0,F.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,F.jsx)(S,{variant:`outline`,className:e.status===`error`?`border-red-500/40 text-red-400`:`border-yellow-500/40 text-yellow-400`,children:e.status}),(0,F.jsx)(`span`,{className:`font-medium`,children:e.name})]}),(0,F.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:e.detail}),e.subjects.length>0&&(0,F.jsx)(`div`,{className:`flex flex-wrap gap-1.5`,children:e.subjects.map(e=>(0,F.jsxs)(S,{variant:`secondary`,className:`max-w-full truncate text-[11px]`,title:[e.id,e.status,e.detail].filter(Boolean).join(` · `),children:[e.label||e.id,e.status?` · ${e.status}`:``,e.detail?` · ${e.detail}`:``]},e.id))}),e.actions.length>0&&(0,F.jsx)(`div`,{className:`flex flex-wrap gap-1.5 pt-0.5`,children:e.actions.slice(0,3).map(e=>(0,F.jsx)(`button`,{onClick:()=>B(e),className:`text-xs text-blue-400 hover:text-blue-300 underline underline-offset-2`,children:e.label},e.label))})]},e.name))})]}),(0,F.jsxs)(`div`,{className:`grid grid-cols-1 sm:grid-cols-3 gap-4`,children:[(0,F.jsx)(N,{className:`cursor-pointer hover:border-zinc-600 transition-colors ${G.unreadInbox>0?`border-red-500/40`:``}`,onClick:()=>X(`chat`),children:(0,F.jsxs)(j,{className:`p-4 flex items-center gap-3`,children:[(0,F.jsx)(`div`,{className:`p-2 rounded-lg ${G.unreadInbox>0?`bg-red-500/15`:`bg-zinc-800`}`,children:(0,F.jsx)(l,{className:`w-4 h-4 ${G.unreadInbox>0?`text-red-400`:`text-zinc-400`}`})}),(0,F.jsxs)(`div`,{children:[(0,F.jsx)(`div`,{className:`text-lg font-bold`,children:G.unreadInbox}),(0,F.jsx)(`div`,{className:`text-xs text-muted-foreground`,children:`Unread`})]})]})}),(0,F.jsx)(N,{className:`cursor-pointer hover:border-zinc-600 transition-colors ${G.pendingPairInvites>0?`border-yellow-500/40`:``}`,onClick:()=>X(`pairs`),children:(0,F.jsxs)(j,{className:`p-4 flex items-center gap-3`,children:[(0,F.jsx)(`div`,{className:`p-2 rounded-lg ${G.pendingPairInvites>0?`bg-yellow-500/15`:`bg-zinc-800`}`,children:(0,F.jsx)(u,{className:`w-4 h-4 ${G.pendingPairInvites>0?`text-yellow-400`:`text-zinc-400`}`})}),(0,F.jsxs)(`div`,{children:[(0,F.jsx)(`div`,{className:`text-lg font-bold`,children:G.pendingPairInvites}),(0,F.jsx)(`div`,{className:`text-xs text-muted-foreground`,children:`Pair invites`})]})]})}),(0,F.jsx)(N,{className:`cursor-pointer hover:border-zinc-600 transition-colors ${G.claimableTasks>0?`border-orange-500/40`:``}`,onClick:()=>X(`work`),children:(0,F.jsxs)(j,{className:`p-4 flex items-center gap-3`,children:[(0,F.jsx)(`div`,{className:`p-2 rounded-lg ${G.claimableTasks>0?`bg-orange-500/15`:`bg-zinc-800`}`,children:(0,F.jsx)(o,{className:`w-4 h-4 ${G.claimableTasks>0?`text-orange-400`:`text-zinc-400`}`})}),(0,F.jsxs)(`div`,{children:[(0,F.jsx)(`div`,{className:`text-lg font-bold`,children:G.claimableTasks}),(0,F.jsx)(`div`,{className:`text-xs text-muted-foreground`,children:`Claimable waiting`})]})]})})]}),(0,F.jsxs)(`div`,{className:`grid grid-cols-1 md:grid-cols-2 gap-6`,children:[(0,F.jsxs)(N,{children:[(0,F.jsx)(M,{className:`pb-2 pt-4 px-4`,children:(0,F.jsxs)(A,{className:`text-sm font-medium flex items-center gap-2`,children:[(0,F.jsx)(c,{className:`w-4 h-4 text-muted-foreground`}),`Agents`,(0,F.jsx)(`span`,{className:`ml-auto text-xs text-muted-foreground font-normal`,children:q.length})]})}),(0,F.jsx)(j,{className:`px-0 pb-0`,children:(0,F.jsx)(k,{className:`h-[340px]`,children:q.length===0?(0,F.jsx)(`div`,{className:`px-4 pb-4 text-sm text-muted-foreground`,children:`No agents registered.`}):(0,F.jsx)(`div`,{className:`space-y-0`,children:q.map((e,t)=>(0,F.jsxs)(`div`,{children:[t>0&&(0,F.jsx)(w,{}),(0,F.jsxs)(`div`,{className:`flex items-center gap-2.5 px-4 py-2.5 hover:bg-zinc-800/50 transition-colors cursor-pointer`,onClick:()=>p.getState().openAgentDetail(e),children:[(0,F.jsx)(E,{agent:e,now:L}),(0,F.jsx)(D,{agent:e}),(0,F.jsxs)(`div`,{className:`flex-1 min-w-0`,children:[(0,F.jsx)(`div`,{className:`text-sm font-medium truncate`,children:_(e)}),e.tags.length>0&&(0,F.jsx)(`div`,{className:`flex gap-1 mt-0.5 flex-wrap`,children:e.tags.slice(0,2).map(e=>(0,F.jsx)(S,{variant:`outline`,className:`text-[9px] px-1 py-0 h-4`,children:e},e))})]}),(0,F.jsx)(`span`,{className:`text-xs text-muted-foreground shrink-0`,children:m(L,e.lastSeen)})]})]},e.id))})})})]}),(0,F.jsxs)(N,{children:[(0,F.jsx)(M,{className:`pb-2 pt-4 px-4`,children:(0,F.jsxs)(A,{className:`text-sm font-medium flex items-center gap-2`,children:[(0,F.jsx)(r,{className:`w-4 h-4 text-muted-foreground`}),`Recent Activity`,(0,F.jsx)(`span`,{className:`ml-auto text-xs text-muted-foreground font-normal`,children:J.length})]})}),(0,F.jsx)(j,{className:`px-0 pb-0`,children:(0,F.jsx)(k,{className:`h-[340px]`,children:J.length===0?(0,F.jsx)(`div`,{className:`px-4 pb-4 text-sm text-muted-foreground`,children:`No recent messages.`}):(0,F.jsx)(`div`,{className:`space-y-0`,children:J.map((e,t)=>(0,F.jsxs)(`div`,{children:[t>0&&(0,F.jsx)(w,{}),(0,F.jsxs)(`div`,{className:`px-4 py-2.5 hover:bg-zinc-800/50 transition-colors`,children:[(0,F.jsxs)(`div`,{className:`flex items-center gap-1 text-xs text-muted-foreground mb-0.5`,children:[(0,F.jsx)(`span`,{className:`text-foreground font-medium truncate max-w-[100px]`,children:v(e.from,R)}),(0,F.jsx)(`span`,{children:`→`}),(0,F.jsx)(`span`,{className:`truncate max-w-[100px]`,children:v(e.to,R)}),(0,F.jsxs)(`span`,{className:`ml-auto shrink-0 tabular-nums`,children:[(0,F.jsxs)(`span`,{className:`opacity-40 mr-1`,children:[`#`,e.id]}),m(L,e.createdAt)]})]}),(0,F.jsx)(`div`,{className:`text-xs text-foreground line-clamp-2 leading-snug`,children:b(e)})]})]},e.id))})})})]})]})]})}export{I as OverviewView};
2
+ //# sourceMappingURL=overview-B_od6jh0.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"overview-CXcGh2D6.js","names":[],"sources":["../../dashboard/src/components/views/overview.tsx"],"sourcesContent":["import { useMemo } from 'react'\nimport { useRelayStore, useNow } from '@/store'\nimport { useAttentionSummary, useOnlineCount, useBusyCount } from '@/hooks/use-selectors'\nimport { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'\nimport { Badge } from '@/components/ui/badge'\nimport { ScrollArea } from '@/components/ui/scroll-area'\nimport { Separator } from '@/components/ui/separator'\nimport { StatusDot } from '@/components/shared/status-dot'\nimport { AgentTypeIcon } from '@/components/shared/agent-type-icon'\nimport {\n displayName, displayTarget, timeAgo, messagePreview, healthDiagnostics,\n toneToColor, visibleAgents, toTimestamp,\n} from '@/lib/display'\nimport { STATUS_SORT_ORDER } from '@/lib/constants'\nimport {\n Bot, Mail, Link, Inbox, AlertTriangle, Activity,\n Users, MessageSquare, ListChecks,\n} from 'lucide-react'\nimport type { ViewName } from '@/types'\n\nexport function OverviewView() {\n const stats = useRelayStore((s) => s.stats)\n const agents = useRelayStore((s) => s.agents)\n const messages = useRelayStore((s) => s.messages)\n const health = useRelayStore((s) => s.health)\n const now = useNow()\n const agentsById = useRelayStore((s) => s.agentsById)\n const switchView = useRelayStore((s) => s.switchView)\n const runHealthAction = useRelayStore((s) => s.runHealthAction)\n const managedPolicies = useRelayStore((s) => s.managedPolicies)\n\n const showOffline = useRelayStore((s) => s.showOffline)\n\n const onlineCount = useOnlineCount()\n const busyCount = useBusyCount()\n const attention = useAttentionSummary()\n\n const filteredAgents = useMemo(() => {\n let list = visibleAgents(agents, false, managedPolicies)\n if (!showOffline) list = list.filter((a) => a.status !== 'offline')\n return [...list].sort((a, b) => {\n const s = (STATUS_SORT_ORDER[a.status] ?? 9) - (STATUS_SORT_ORDER[b.status] ?? 9)\n return s || toTimestamp(b.lastSeen) - toTimestamp(a.lastSeen)\n })\n }, [agents, showOffline, managedPolicies])\n const recentAgents = filteredAgents.slice(0, 20)\n const recentMessages = [...messages].sort((a, b) => b.id - a.id).slice(0, 15)\n\n const healthIssues =\n health && health.status !== 'ok'\n ? healthDiagnostics(health.checks || [])\n : []\n\n function nav(view: ViewName) {\n switchView(view)\n }\n\n return (\n <div className=\"space-y-6\">\n {/* Stat cards */}\n <div className=\"grid grid-cols-2 md:grid-cols-4 gap-4\">\n <Card className=\"cursor-pointer hover:border-zinc-600 transition-colors\" onClick={() => nav('agents')}>\n <CardHeader className=\"pb-1 pt-4 px-4\">\n <CardTitle className=\"text-xs font-medium text-muted-foreground flex items-center gap-1.5\">\n <Users className=\"w-3.5 h-3.5\" />\n Agents\n </CardTitle>\n </CardHeader>\n <CardContent className=\"px-4 pb-4\">\n <div className=\"text-2xl font-bold\">{filteredAgents.length}</div>\n <div className=\"text-xs text-muted-foreground mt-0.5\">{onlineCount} online</div>\n </CardContent>\n </Card>\n\n <Card className=\"cursor-pointer hover:border-zinc-600 transition-colors\" onClick={() => nav('agents')}>\n <CardHeader className=\"pb-1 pt-4 px-4\">\n <CardTitle className=\"text-xs font-medium text-muted-foreground flex items-center gap-1.5\">\n <Activity className=\"w-3.5 h-3.5\" />\n Busy\n </CardTitle>\n </CardHeader>\n <CardContent className=\"px-4 pb-4\">\n <div className=\"text-2xl font-bold\">{busyCount}</div>\n <div className=\"text-xs text-muted-foreground mt-0.5\">in a turn now</div>\n </CardContent>\n </Card>\n\n <Card className=\"cursor-pointer hover:border-zinc-600 transition-colors\" onClick={() => nav('messages')}>\n <CardHeader className=\"pb-1 pt-4 px-4\">\n <CardTitle className=\"text-xs font-medium text-muted-foreground flex items-center gap-1.5\">\n <MessageSquare className=\"w-3.5 h-3.5\" />\n Messages 24h\n </CardTitle>\n </CardHeader>\n <CardContent className=\"px-4 pb-4\">\n <div className=\"text-2xl font-bold\">{stats.messagesLast24h ?? '—'}</div>\n <div className=\"text-xs text-muted-foreground mt-0.5\">last 24 hours</div>\n </CardContent>\n </Card>\n\n <Card className=\"cursor-pointer hover:border-zinc-600 transition-colors\" onClick={() => nav('messages')}>\n <CardHeader className=\"pb-1 pt-4 px-4\">\n <CardTitle className=\"text-xs font-medium text-muted-foreground flex items-center gap-1.5\">\n <Mail className=\"w-3.5 h-3.5\" />\n Total Messages\n </CardTitle>\n </CardHeader>\n <CardContent className=\"px-4 pb-4\">\n <div className=\"text-2xl font-bold\">{stats.messages ?? '—'}</div>\n <div className=\"text-xs text-muted-foreground mt-0.5\">all time</div>\n </CardContent>\n </Card>\n </div>\n\n {/* Health alert banner */}\n {healthIssues.length > 0 && (\n <Card className=\"border-yellow-500/40 bg-yellow-500/5\">\n <CardHeader className=\"pb-2 pt-4 px-4\">\n <CardTitle className=\"text-sm font-medium text-yellow-400 flex items-center gap-2\">\n <AlertTriangle className=\"w-4 h-4\" />\n Health Alerts ({healthIssues.length})\n </CardTitle>\n </CardHeader>\n <CardContent className=\"px-4 pb-4 space-y-2\">\n {healthIssues.map((issue) => (\n <div key={issue.name} className=\"text-sm space-y-1\">\n <div className=\"flex items-center gap-2\">\n <Badge\n variant=\"outline\"\n className={issue.status === 'error' ? 'border-red-500/40 text-red-400' : 'border-yellow-500/40 text-yellow-400'}\n >\n {issue.status}\n </Badge>\n <span className=\"font-medium\">{issue.name}</span>\n </div>\n <p className=\"text-xs text-muted-foreground\">{issue.detail}</p>\n {issue.subjects.length > 0 && (\n <div className=\"flex flex-wrap gap-1.5\">\n {issue.subjects.map((subject) => (\n <Badge key={subject.id} variant=\"secondary\" className=\"max-w-full truncate text-[11px]\" title={[subject.id, subject.status, subject.detail].filter(Boolean).join(' · ')}>\n {subject.label || subject.id}\n {subject.status ? ` · ${subject.status}` : ''}\n {subject.detail ? ` · ${subject.detail}` : ''}\n </Badge>\n ))}\n </div>\n )}\n {issue.actions.length > 0 && (\n <div className=\"flex flex-wrap gap-1.5 pt-0.5\">\n {issue.actions.slice(0, 3).map((action) => (\n <button\n key={action.label}\n onClick={() => runHealthAction(action)}\n className=\"text-xs text-blue-400 hover:text-blue-300 underline underline-offset-2\"\n >\n {action.label}\n </button>\n ))}\n </div>\n )}\n </div>\n ))}\n </CardContent>\n </Card>\n )}\n\n {/* Attention shortcuts */}\n <div className=\"grid grid-cols-1 sm:grid-cols-3 gap-4\">\n <Card\n className={`cursor-pointer hover:border-zinc-600 transition-colors ${attention.unreadInbox > 0 ? 'border-red-500/40' : ''}`}\n onClick={() => nav('chat')}\n >\n <CardContent className=\"p-4 flex items-center gap-3\">\n <div className={`p-2 rounded-lg ${attention.unreadInbox > 0 ? 'bg-red-500/15' : 'bg-zinc-800'}`}>\n <Inbox className={`w-4 h-4 ${attention.unreadInbox > 0 ? 'text-red-400' : 'text-zinc-400'}`} />\n </div>\n <div>\n <div className=\"text-lg font-bold\">{attention.unreadInbox}</div>\n <div className=\"text-xs text-muted-foreground\">Unread</div>\n </div>\n </CardContent>\n </Card>\n\n <Card\n className={`cursor-pointer hover:border-zinc-600 transition-colors ${attention.pendingPairInvites > 0 ? 'border-yellow-500/40' : ''}`}\n onClick={() => nav('pairs')}\n >\n <CardContent className=\"p-4 flex items-center gap-3\">\n <div className={`p-2 rounded-lg ${attention.pendingPairInvites > 0 ? 'bg-yellow-500/15' : 'bg-zinc-800'}`}>\n <Link className={`w-4 h-4 ${attention.pendingPairInvites > 0 ? 'text-yellow-400' : 'text-zinc-400'}`} />\n </div>\n <div>\n <div className=\"text-lg font-bold\">{attention.pendingPairInvites}</div>\n <div className=\"text-xs text-muted-foreground\">Pair invites</div>\n </div>\n </CardContent>\n </Card>\n\n <Card\n className={`cursor-pointer hover:border-zinc-600 transition-colors ${attention.claimableTasks > 0 ? 'border-orange-500/40' : ''}`}\n onClick={() => nav('work')}\n >\n <CardContent className=\"p-4 flex items-center gap-3\">\n <div className={`p-2 rounded-lg ${attention.claimableTasks > 0 ? 'bg-orange-500/15' : 'bg-zinc-800'}`}>\n <ListChecks className={`w-4 h-4 ${attention.claimableTasks > 0 ? 'text-orange-400' : 'text-zinc-400'}`} />\n </div>\n <div>\n <div className=\"text-lg font-bold\">{attention.claimableTasks}</div>\n <div className=\"text-xs text-muted-foreground\">Claimable waiting</div>\n </div>\n </CardContent>\n </Card>\n </div>\n\n {/* Two-column: agents + recent activity */}\n <div className=\"grid grid-cols-1 md:grid-cols-2 gap-6\">\n {/* Top agents */}\n <Card>\n <CardHeader className=\"pb-2 pt-4 px-4\">\n <CardTitle className=\"text-sm font-medium flex items-center gap-2\">\n <Bot className=\"w-4 h-4 text-muted-foreground\" />\n Agents\n <span className=\"ml-auto text-xs text-muted-foreground font-normal\">{recentAgents.length}</span>\n </CardTitle>\n </CardHeader>\n <CardContent className=\"px-0 pb-0\">\n <ScrollArea className=\"h-[340px]\">\n {recentAgents.length === 0 ? (\n <div className=\"px-4 pb-4 text-sm text-muted-foreground\">No agents registered.</div>\n ) : (\n <div className=\"space-y-0\">\n {recentAgents.map((agent, i) => (\n <div key={agent.id}>\n {i > 0 && <Separator />}\n <div className=\"flex items-center gap-2.5 px-4 py-2.5 hover:bg-zinc-800/50 transition-colors cursor-pointer\" onClick={() => useRelayStore.getState().openAgentDetail(agent)}>\n <StatusDot agent={agent} now={now} />\n <AgentTypeIcon agent={agent} />\n <div className=\"flex-1 min-w-0\">\n <div className=\"text-sm font-medium truncate\">{displayName(agent)}</div>\n {agent.tags.length > 0 && (\n <div className=\"flex gap-1 mt-0.5 flex-wrap\">\n {agent.tags.slice(0, 2).map((t) => (\n <Badge key={t} variant=\"outline\" className=\"text-[9px] px-1 py-0 h-4\">{t}</Badge>\n ))}\n </div>\n )}\n </div>\n <span className=\"text-xs text-muted-foreground shrink-0\">{timeAgo(now, agent.lastSeen)}</span>\n </div>\n </div>\n ))}\n </div>\n )}\n </ScrollArea>\n </CardContent>\n </Card>\n\n {/* Recent activity */}\n <Card>\n <CardHeader className=\"pb-2 pt-4 px-4\">\n <CardTitle className=\"text-sm font-medium flex items-center gap-2\">\n <Activity className=\"w-4 h-4 text-muted-foreground\" />\n Recent Activity\n <span className=\"ml-auto text-xs text-muted-foreground font-normal\">{recentMessages.length}</span>\n </CardTitle>\n </CardHeader>\n <CardContent className=\"px-0 pb-0\">\n <ScrollArea className=\"h-[340px]\">\n {recentMessages.length === 0 ? (\n <div className=\"px-4 pb-4 text-sm text-muted-foreground\">No recent messages.</div>\n ) : (\n <div className=\"space-y-0\">\n {recentMessages.map((msg, i) => (\n <div key={msg.id}>\n {i > 0 && <Separator />}\n <div className=\"px-4 py-2.5 hover:bg-zinc-800/50 transition-colors\">\n <div className=\"flex items-center gap-1 text-xs text-muted-foreground mb-0.5\">\n <span className=\"text-foreground font-medium truncate max-w-[100px]\">{displayTarget(msg.from, agentsById)}</span>\n <span>→</span>\n <span className=\"truncate max-w-[100px]\">{displayTarget(msg.to, agentsById)}</span>\n <span className=\"ml-auto shrink-0 tabular-nums\"><span className=\"opacity-40 mr-1\">#{msg.id}</span>{timeAgo(now, msg.createdAt)}</span>\n </div>\n <div className=\"text-xs text-foreground line-clamp-2 leading-snug\">{messagePreview(msg)}</div>\n </div>\n </div>\n ))}\n </div>\n )}\n </ScrollArea>\n </CardContent>\n </Card>\n </div>\n </div>\n )\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"overview-B_od6jh0.js","names":[],"sources":["../../dashboard/src/components/views/overview.tsx"],"sourcesContent":["import { useMemo } from 'react'\nimport { useRelayStore, useNow } from '@/store'\nimport { useAttentionSummary, useOnlineCount, useBusyCount } from '@/hooks/use-selectors'\nimport { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'\nimport { Badge } from '@/components/ui/badge'\nimport { ScrollArea } from '@/components/ui/scroll-area'\nimport { Separator } from '@/components/ui/separator'\nimport { StatusDot } from '@/components/shared/status-dot'\nimport { AgentTypeIcon } from '@/components/shared/agent-type-icon'\nimport {\n displayName, displayTarget, timeAgo, messagePreview, healthDiagnostics,\n toneToColor, visibleAgents, toTimestamp,\n} from '@/lib/display'\nimport { STATUS_SORT_ORDER } from '@/lib/constants'\nimport {\n Bot, Mail, Link, Inbox, AlertTriangle, Activity,\n Users, MessageSquare, ListChecks,\n} from 'lucide-react'\nimport type { ViewName } from '@/types'\n\nexport function OverviewView() {\n const stats = useRelayStore((s) => s.stats)\n const agents = useRelayStore((s) => s.agents)\n const messages = useRelayStore((s) => s.messages)\n const health = useRelayStore((s) => s.health)\n const now = useNow()\n const agentsById = useRelayStore((s) => s.agentsById)\n const switchView = useRelayStore((s) => s.switchView)\n const runHealthAction = useRelayStore((s) => s.runHealthAction)\n const managedPolicies = useRelayStore((s) => s.managedPolicies)\n\n const showOffline = useRelayStore((s) => s.showOffline)\n\n const onlineCount = useOnlineCount()\n const busyCount = useBusyCount()\n const attention = useAttentionSummary()\n\n const filteredAgents = useMemo(() => {\n let list = visibleAgents(agents, false, managedPolicies)\n if (!showOffline) list = list.filter((a) => a.status !== 'offline')\n return [...list].sort((a, b) => {\n const s = (STATUS_SORT_ORDER[a.status] ?? 9) - (STATUS_SORT_ORDER[b.status] ?? 9)\n return s || toTimestamp(b.lastSeen) - toTimestamp(a.lastSeen)\n })\n }, [agents, showOffline, managedPolicies])\n const recentAgents = filteredAgents.slice(0, 20)\n const recentMessages = [...messages].sort((a, b) => b.id - a.id).slice(0, 15)\n\n const healthIssues =\n health && health.status !== 'ok'\n ? healthDiagnostics(health.checks || [])\n : []\n\n function nav(view: ViewName) {\n switchView(view)\n }\n\n return (\n <div className=\"space-y-6\">\n {/* Stat cards */}\n <div className=\"grid grid-cols-2 md:grid-cols-4 gap-4\">\n <Card className=\"cursor-pointer hover:border-zinc-600 transition-colors\" onClick={() => nav('agents')}>\n <CardHeader className=\"pb-1 pt-4 px-4\">\n <CardTitle className=\"text-xs font-medium text-muted-foreground flex items-center gap-1.5\">\n <Users className=\"w-3.5 h-3.5\" />\n Agents\n </CardTitle>\n </CardHeader>\n <CardContent className=\"px-4 pb-4\">\n <div className=\"text-2xl font-bold\">{filteredAgents.length}</div>\n <div className=\"text-xs text-muted-foreground mt-0.5\">{onlineCount} online</div>\n </CardContent>\n </Card>\n\n <Card className=\"cursor-pointer hover:border-zinc-600 transition-colors\" onClick={() => nav('agents')}>\n <CardHeader className=\"pb-1 pt-4 px-4\">\n <CardTitle className=\"text-xs font-medium text-muted-foreground flex items-center gap-1.5\">\n <Activity className=\"w-3.5 h-3.5\" />\n Busy\n </CardTitle>\n </CardHeader>\n <CardContent className=\"px-4 pb-4\">\n <div className=\"text-2xl font-bold\">{busyCount}</div>\n <div className=\"text-xs text-muted-foreground mt-0.5\">in a turn now</div>\n </CardContent>\n </Card>\n\n <Card className=\"cursor-pointer hover:border-zinc-600 transition-colors\" onClick={() => nav('messages')}>\n <CardHeader className=\"pb-1 pt-4 px-4\">\n <CardTitle className=\"text-xs font-medium text-muted-foreground flex items-center gap-1.5\">\n <MessageSquare className=\"w-3.5 h-3.5\" />\n Messages 24h\n </CardTitle>\n </CardHeader>\n <CardContent className=\"px-4 pb-4\">\n <div className=\"text-2xl font-bold\">{stats.messagesLast24h ?? '—'}</div>\n <div className=\"text-xs text-muted-foreground mt-0.5\">last 24 hours</div>\n </CardContent>\n </Card>\n\n <Card className=\"cursor-pointer hover:border-zinc-600 transition-colors\" onClick={() => nav('messages')}>\n <CardHeader className=\"pb-1 pt-4 px-4\">\n <CardTitle className=\"text-xs font-medium text-muted-foreground flex items-center gap-1.5\">\n <Mail className=\"w-3.5 h-3.5\" />\n Total Messages\n </CardTitle>\n </CardHeader>\n <CardContent className=\"px-4 pb-4\">\n <div className=\"text-2xl font-bold\">{stats.messages ?? '—'}</div>\n <div className=\"text-xs text-muted-foreground mt-0.5\">all time</div>\n </CardContent>\n </Card>\n </div>\n\n {/* Health alert banner */}\n {healthIssues.length > 0 && (\n <Card className=\"border-yellow-500/40 bg-yellow-500/5\">\n <CardHeader className=\"pb-2 pt-4 px-4\">\n <CardTitle className=\"text-sm font-medium text-yellow-400 flex items-center gap-2\">\n <AlertTriangle className=\"w-4 h-4\" />\n Health Alerts ({healthIssues.length})\n </CardTitle>\n </CardHeader>\n <CardContent className=\"px-4 pb-4 space-y-2\">\n {healthIssues.map((issue) => (\n <div key={issue.name} className=\"text-sm space-y-1\">\n <div className=\"flex items-center gap-2\">\n <Badge\n variant=\"outline\"\n className={issue.status === 'error' ? 'border-red-500/40 text-red-400' : 'border-yellow-500/40 text-yellow-400'}\n >\n {issue.status}\n </Badge>\n <span className=\"font-medium\">{issue.name}</span>\n </div>\n <p className=\"text-xs text-muted-foreground\">{issue.detail}</p>\n {issue.subjects.length > 0 && (\n <div className=\"flex flex-wrap gap-1.5\">\n {issue.subjects.map((subject) => (\n <Badge key={subject.id} variant=\"secondary\" className=\"max-w-full truncate text-[11px]\" title={[subject.id, subject.status, subject.detail].filter(Boolean).join(' · ')}>\n {subject.label || subject.id}\n {subject.status ? ` · ${subject.status}` : ''}\n {subject.detail ? ` · ${subject.detail}` : ''}\n </Badge>\n ))}\n </div>\n )}\n {issue.actions.length > 0 && (\n <div className=\"flex flex-wrap gap-1.5 pt-0.5\">\n {issue.actions.slice(0, 3).map((action) => (\n <button\n key={action.label}\n onClick={() => runHealthAction(action)}\n className=\"text-xs text-blue-400 hover:text-blue-300 underline underline-offset-2\"\n >\n {action.label}\n </button>\n ))}\n </div>\n )}\n </div>\n ))}\n </CardContent>\n </Card>\n )}\n\n {/* Attention shortcuts */}\n <div className=\"grid grid-cols-1 sm:grid-cols-3 gap-4\">\n <Card\n className={`cursor-pointer hover:border-zinc-600 transition-colors ${attention.unreadInbox > 0 ? 'border-red-500/40' : ''}`}\n onClick={() => nav('chat')}\n >\n <CardContent className=\"p-4 flex items-center gap-3\">\n <div className={`p-2 rounded-lg ${attention.unreadInbox > 0 ? 'bg-red-500/15' : 'bg-zinc-800'}`}>\n <Inbox className={`w-4 h-4 ${attention.unreadInbox > 0 ? 'text-red-400' : 'text-zinc-400'}`} />\n </div>\n <div>\n <div className=\"text-lg font-bold\">{attention.unreadInbox}</div>\n <div className=\"text-xs text-muted-foreground\">Unread</div>\n </div>\n </CardContent>\n </Card>\n\n <Card\n className={`cursor-pointer hover:border-zinc-600 transition-colors ${attention.pendingPairInvites > 0 ? 'border-yellow-500/40' : ''}`}\n onClick={() => nav('pairs')}\n >\n <CardContent className=\"p-4 flex items-center gap-3\">\n <div className={`p-2 rounded-lg ${attention.pendingPairInvites > 0 ? 'bg-yellow-500/15' : 'bg-zinc-800'}`}>\n <Link className={`w-4 h-4 ${attention.pendingPairInvites > 0 ? 'text-yellow-400' : 'text-zinc-400'}`} />\n </div>\n <div>\n <div className=\"text-lg font-bold\">{attention.pendingPairInvites}</div>\n <div className=\"text-xs text-muted-foreground\">Pair invites</div>\n </div>\n </CardContent>\n </Card>\n\n <Card\n className={`cursor-pointer hover:border-zinc-600 transition-colors ${attention.claimableTasks > 0 ? 'border-orange-500/40' : ''}`}\n onClick={() => nav('work')}\n >\n <CardContent className=\"p-4 flex items-center gap-3\">\n <div className={`p-2 rounded-lg ${attention.claimableTasks > 0 ? 'bg-orange-500/15' : 'bg-zinc-800'}`}>\n <ListChecks className={`w-4 h-4 ${attention.claimableTasks > 0 ? 'text-orange-400' : 'text-zinc-400'}`} />\n </div>\n <div>\n <div className=\"text-lg font-bold\">{attention.claimableTasks}</div>\n <div className=\"text-xs text-muted-foreground\">Claimable waiting</div>\n </div>\n </CardContent>\n </Card>\n </div>\n\n {/* Two-column: agents + recent activity */}\n <div className=\"grid grid-cols-1 md:grid-cols-2 gap-6\">\n {/* Top agents */}\n <Card>\n <CardHeader className=\"pb-2 pt-4 px-4\">\n <CardTitle className=\"text-sm font-medium flex items-center gap-2\">\n <Bot className=\"w-4 h-4 text-muted-foreground\" />\n Agents\n <span className=\"ml-auto text-xs text-muted-foreground font-normal\">{recentAgents.length}</span>\n </CardTitle>\n </CardHeader>\n <CardContent className=\"px-0 pb-0\">\n <ScrollArea className=\"h-[340px]\">\n {recentAgents.length === 0 ? (\n <div className=\"px-4 pb-4 text-sm text-muted-foreground\">No agents registered.</div>\n ) : (\n <div className=\"space-y-0\">\n {recentAgents.map((agent, i) => (\n <div key={agent.id}>\n {i > 0 && <Separator />}\n <div className=\"flex items-center gap-2.5 px-4 py-2.5 hover:bg-zinc-800/50 transition-colors cursor-pointer\" onClick={() => useRelayStore.getState().openAgentDetail(agent)}>\n <StatusDot agent={agent} now={now} />\n <AgentTypeIcon agent={agent} />\n <div className=\"flex-1 min-w-0\">\n <div className=\"text-sm font-medium truncate\">{displayName(agent)}</div>\n {agent.tags.length > 0 && (\n <div className=\"flex gap-1 mt-0.5 flex-wrap\">\n {agent.tags.slice(0, 2).map((t) => (\n <Badge key={t} variant=\"outline\" className=\"text-[9px] px-1 py-0 h-4\">{t}</Badge>\n ))}\n </div>\n )}\n </div>\n <span className=\"text-xs text-muted-foreground shrink-0\">{timeAgo(now, agent.lastSeen)}</span>\n </div>\n </div>\n ))}\n </div>\n )}\n </ScrollArea>\n </CardContent>\n </Card>\n\n {/* Recent activity */}\n <Card>\n <CardHeader className=\"pb-2 pt-4 px-4\">\n <CardTitle className=\"text-sm font-medium flex items-center gap-2\">\n <Activity className=\"w-4 h-4 text-muted-foreground\" />\n Recent Activity\n <span className=\"ml-auto text-xs text-muted-foreground font-normal\">{recentMessages.length}</span>\n </CardTitle>\n </CardHeader>\n <CardContent className=\"px-0 pb-0\">\n <ScrollArea className=\"h-[340px]\">\n {recentMessages.length === 0 ? (\n <div className=\"px-4 pb-4 text-sm text-muted-foreground\">No recent messages.</div>\n ) : (\n <div className=\"space-y-0\">\n {recentMessages.map((msg, i) => (\n <div key={msg.id}>\n {i > 0 && <Separator />}\n <div className=\"px-4 py-2.5 hover:bg-zinc-800/50 transition-colors\">\n <div className=\"flex items-center gap-1 text-xs text-muted-foreground mb-0.5\">\n <span className=\"text-foreground font-medium truncate max-w-[100px]\">{displayTarget(msg.from, agentsById)}</span>\n <span>→</span>\n <span className=\"truncate max-w-[100px]\">{displayTarget(msg.to, agentsById)}</span>\n <span className=\"ml-auto shrink-0 tabular-nums\"><span className=\"opacity-40 mr-1\">#{msg.id}</span>{timeAgo(now, msg.createdAt)}</span>\n </div>\n <div className=\"text-xs text-foreground line-clamp-2 leading-snug\">{messagePreview(msg)}</div>\n </div>\n </div>\n ))}\n </div>\n )}\n </ScrollArea>\n </CardContent>\n </Card>\n </div>\n </div>\n )\n}\n"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import{$ as e,An as t,bn as n,ct as r,d as i,ot as a}from"./lucide-react-DLQFnqNm.js";import{i as o,t as s}from"./store-CMUFZKxf.js";import{H as c,d as l,h as u,st as d}from"./display-ConJ9cJB.js";import{t as f}from"./badge-JVybSpzR.js";import{t as p}from"./button-BsMqBNJb.js";import{s as m}from"./index-DdB6SVZY.js";import{n as h,r as g,t as _}from"./card-I8w4U656.js";var v=t(),y=[{value:`open`,label:`Active & Pending`},{value:`active`,label:`Active`},{value:`pending`,label:`Pending`},{value:`ended`,label:`Ended`},{value:`rejected`,label:`Rejected`},{value:`expired`,label:`Expired`},{value:``,label:`All`}];function b(){let e=o(),t=s(e=>e.pairs),n=s(e=>e.agentsById),r=s(e=>e.pairStatusFilter),c=s(e=>e.set),u=s(e=>e.fetchPairs),d=s(e=>e.openPairInvite),h=s(e=>e.openPairMessage),g=s(e=>e.doAcceptPair),_=s(e=>e.doRejectPair),b=s(e=>e.doHangupPair),S=t.filter(e=>e.status===`pending`).length;function C(e){c({pairStatusFilter:e}),setTimeout(()=>u(),0)}function w(e){return n[e]?l(n[e]):e.slice(-10)}return(0,v.jsxs)(`div`,{className:`space-y-4`,children:[(0,v.jsxs)(`div`,{className:`flex items-center justify-between flex-wrap gap-2`,children:[(0,v.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,v.jsx)(a,{className:`w-5 h-5 text-muted-foreground`}),(0,v.jsx)(`h2`,{className:`text-lg font-semibold`,children:`Pair Sessions`}),S>0&&(0,v.jsxs)(f,{className:`bg-yellow-500/20 text-yellow-400 border-yellow-500/30 border`,children:[S,` pending`]})]}),(0,v.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,v.jsx)(`select`,{className:`rounded-md border border-input bg-background px-3 py-1.5 text-sm`,value:r,onChange:e=>C(e.target.value),children:y.map(e=>(0,v.jsx)(`option`,{value:e.value,children:e.label},e.value))}),(0,v.jsxs)(p,{size:`sm`,onClick:()=>d(),children:[(0,v.jsx)(i,{className:`w-4 h-4 mr-1`}),` Pair agents`]})]})]}),(0,v.jsx)(m,{className:`h-[calc(100dvh-11rem)]`,children:(0,v.jsxs)(`div`,{className:`space-y-3 pr-2`,children:[t.length===0&&(0,v.jsx)(`div`,{className:`text-center text-muted-foreground py-16 text-sm`,children:`No pair sessions`}),t.map(t=>(0,v.jsx)(x,{pair:t,now:e,agentName:w,onAccept:()=>g(t),onReject:()=>_(t),onMessage:()=>h(t),onHangup:()=>b(t)},t.id))]})})]})}function x({pair:t,now:i,agentName:a,onAccept:o,onReject:s,onMessage:l,onHangup:m}){let y=d[t.status]||`bg-zinc-500/20 text-zinc-400`,b=t.status===`pending`,x=t.status===`active`;return(0,v.jsxs)(_,{children:[(0,v.jsx)(g,{className:`py-3 px-4 pb-0`,children:(0,v.jsxs)(`div`,{className:`flex items-start justify-between gap-2`,children:[(0,v.jsxs)(`div`,{className:`flex items-center gap-2 flex-wrap flex-1 min-w-0`,children:[(0,v.jsx)(f,{className:`${y} border text-xs`,children:t.status}),(0,v.jsxs)(`div`,{className:`flex items-center gap-1.5 text-sm min-w-0`,children:[(0,v.jsx)(`span`,{className:`font-medium truncate max-w-[120px]`,title:t.requesterId,children:a(t.requesterId)}),(0,v.jsx)(n,{className:`w-3.5 h-3.5 text-muted-foreground shrink-0`}),(0,v.jsx)(`span`,{className:`font-medium truncate max-w-[120px]`,title:t.targetId,children:a(t.targetId)})]})]}),(0,v.jsxs)(`div`,{className:`text-right shrink-0`,children:[(0,v.jsx)(`div`,{className:`text-xs font-mono text-muted-foreground/60 truncate max-w-[100px]`,children:t.id.slice(-10)}),(0,v.jsx)(`div`,{className:`text-xs text-muted-foreground`,title:u(t.updatedAt),children:c(i,t.updatedAt)})]})]})}),(0,v.jsxs)(h,{className:`px-4 py-3`,children:[t.objective&&(0,v.jsx)(`p`,{className:`text-xs text-muted-foreground mb-3 line-clamp-2`,children:t.objective}),(0,v.jsxs)(`div`,{className:`flex items-center gap-2 flex-wrap`,children:[b&&(0,v.jsxs)(v.Fragment,{children:[(0,v.jsx)(p,{size:`sm`,className:`bg-emerald-600 hover:bg-emerald-700 text-white h-7 text-xs`,onClick:o,children:`Accept`}),(0,v.jsx)(p,{size:`sm`,variant:`outline`,className:`h-7 text-xs text-red-400 hover:text-red-300`,onClick:s,children:`Reject`})]}),x&&(0,v.jsxs)(v.Fragment,{children:[(0,v.jsxs)(p,{size:`sm`,variant:`outline`,className:`h-7 text-xs`,onClick:l,children:[(0,v.jsx)(e,{className:`w-3.5 h-3.5 mr-1`}),` Message`]}),(0,v.jsxs)(p,{size:`sm`,variant:`outline`,className:`h-7 text-xs text-red-400 hover:text-red-300`,onClick:m,children:[(0,v.jsx)(r,{className:`w-3.5 h-3.5 mr-1`}),` Hang up`]})]})]})]})]})}export{b as PairsView};
2
+ //# sourceMappingURL=pairs-CaxiFyfY.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"pairs-eOZl_lQn.js","names":[],"sources":["../../dashboard/src/components/views/pairs.tsx"],"sourcesContent":["import { useRelayStore, useNow } from '@/store'\nimport { Card, CardContent, CardHeader } from '@/components/ui/card'\nimport { Badge } from '@/components/ui/badge'\nimport { Button } from '@/components/ui/button'\nimport { ScrollArea } from '@/components/ui/scroll-area'\nimport { Link, Link2Off, Mail, UserPlus, ArrowRight } from 'lucide-react'\nimport { displayName, timeAgo, fmtTime } from '@/lib/display'\nimport { PAIR_STATUS_COLORS } from '@/lib/constants'\nimport type { PairSession } from '@/types'\n\nconst STATUS_OPTIONS = [\n { value: 'open', label: 'Active & Pending' },\n { value: 'active', label: 'Active' },\n { value: 'pending', label: 'Pending' },\n { value: 'ended', label: 'Ended' },\n { value: 'rejected', label: 'Rejected' },\n { value: 'expired', label: 'Expired' },\n { value: '', label: 'All' },\n]\n\nexport function PairsView() {\n const now = useNow()\n const pairs = useRelayStore((s) => s.pairs)\n const agentsById = useRelayStore((s) => s.agentsById)\n const pairStatusFilter = useRelayStore((s) => s.pairStatusFilter)\n const set = useRelayStore((s) => s.set)\n const fetchPairs = useRelayStore((s) => s.fetchPairs)\n const openPairInvite = useRelayStore((s) => s.openPairInvite)\n const openPairMessage = useRelayStore((s) => s.openPairMessage)\n const doAcceptPair = useRelayStore((s) => s.doAcceptPair)\n const doRejectPair = useRelayStore((s) => s.doRejectPair)\n const doHangupPair = useRelayStore((s) => s.doHangupPair)\n\n const pendingCount = pairs.filter((p) => p.status === 'pending').length\n\n function handleStatusChange(value: string) {\n set({ pairStatusFilter: value })\n setTimeout(() => fetchPairs(), 0)\n }\n\n function agentName(id: string) {\n return agentsById[id] ? displayName(agentsById[id]) : id.slice(-10)\n }\n\n return (\n <div className=\"space-y-4\">\n <div className=\"flex items-center justify-between flex-wrap gap-2\">\n <div className=\"flex items-center gap-2\">\n <Link className=\"w-5 h-5 text-muted-foreground\" />\n <h2 className=\"text-lg font-semibold\">Pair Sessions</h2>\n {pendingCount > 0 && (\n <Badge className=\"bg-yellow-500/20 text-yellow-400 border-yellow-500/30 border\">\n {pendingCount} pending\n </Badge>\n )}\n </div>\n <div className=\"flex items-center gap-2\">\n <select\n className=\"rounded-md border border-input bg-background px-3 py-1.5 text-sm\"\n value={pairStatusFilter}\n onChange={(e) => handleStatusChange(e.target.value)}\n >\n {STATUS_OPTIONS.map((o) => <option key={o.value} value={o.value}>{o.label}</option>)}\n </select>\n <Button size=\"sm\" onClick={() => openPairInvite()}>\n <UserPlus className=\"w-4 h-4 mr-1\" /> Pair agents\n </Button>\n </div>\n </div>\n\n <ScrollArea className=\"h-[calc(100dvh-11rem)]\">\n <div className=\"space-y-3 pr-2\">\n {pairs.length === 0 && (\n <div className=\"text-center text-muted-foreground py-16 text-sm\">No pair sessions</div>\n )}\n {pairs.map((pair) => (\n <PairCard\n key={pair.id}\n pair={pair}\n now={now}\n agentName={agentName}\n onAccept={() => doAcceptPair(pair)}\n onReject={() => doRejectPair(pair)}\n onMessage={() => openPairMessage(pair)}\n onHangup={() => doHangupPair(pair)}\n />\n ))}\n </div>\n </ScrollArea>\n </div>\n )\n}\n\nfunction PairCard({\n pair, now, agentName, onAccept, onReject, onMessage, onHangup,\n}: {\n pair: PairSession\n now: number\n agentName: (id: string) => string\n onAccept: () => void\n onReject: () => void\n onMessage: () => void\n onHangup: () => void\n}) {\n const colorClass = PAIR_STATUS_COLORS[pair.status] || 'bg-zinc-500/20 text-zinc-400'\n const isPending = pair.status === 'pending'\n const isActive = pair.status === 'active'\n\n return (\n <Card>\n <CardHeader className=\"py-3 px-4 pb-0\">\n <div className=\"flex items-start justify-between gap-2\">\n <div className=\"flex items-center gap-2 flex-wrap flex-1 min-w-0\">\n <Badge className={`${colorClass} border text-xs`}>{pair.status}</Badge>\n <div className=\"flex items-center gap-1.5 text-sm min-w-0\">\n <span className=\"font-medium truncate max-w-[120px]\" title={pair.requesterId}>{agentName(pair.requesterId)}</span>\n <ArrowRight className=\"w-3.5 h-3.5 text-muted-foreground shrink-0\" />\n <span className=\"font-medium truncate max-w-[120px]\" title={pair.targetId}>{agentName(pair.targetId)}</span>\n </div>\n </div>\n <div className=\"text-right shrink-0\">\n <div className=\"text-xs font-mono text-muted-foreground/60 truncate max-w-[100px]\">{pair.id.slice(-10)}</div>\n <div className=\"text-xs text-muted-foreground\" title={fmtTime(pair.updatedAt)}>\n {timeAgo(now, pair.updatedAt)}\n </div>\n </div>\n </div>\n </CardHeader>\n <CardContent className=\"px-4 py-3\">\n {pair.objective && (\n <p className=\"text-xs text-muted-foreground mb-3 line-clamp-2\">{pair.objective}</p>\n )}\n <div className=\"flex items-center gap-2 flex-wrap\">\n {isPending && (\n <>\n <Button size=\"sm\" className=\"bg-emerald-600 hover:bg-emerald-700 text-white h-7 text-xs\" onClick={onAccept}>\n Accept\n </Button>\n <Button size=\"sm\" variant=\"outline\" className=\"h-7 text-xs text-red-400 hover:text-red-300\" onClick={onReject}>\n Reject\n </Button>\n </>\n )}\n {isActive && (\n <>\n <Button size=\"sm\" variant=\"outline\" className=\"h-7 text-xs\" onClick={onMessage}>\n <Mail className=\"w-3.5 h-3.5 mr-1\" /> Message\n </Button>\n <Button size=\"sm\" variant=\"outline\" className=\"h-7 text-xs text-red-400 hover:text-red-300\" onClick={onHangup}>\n <Link2Off className=\"w-3.5 h-3.5 mr-1\" /> Hang up\n </Button>\n </>\n )}\n </div>\n </CardContent>\n </Card>\n )\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"pairs-CaxiFyfY.js","names":[],"sources":["../../dashboard/src/components/views/pairs.tsx"],"sourcesContent":["import { useRelayStore, useNow } from '@/store'\nimport { Card, CardContent, CardHeader } from '@/components/ui/card'\nimport { Badge } from '@/components/ui/badge'\nimport { Button } from '@/components/ui/button'\nimport { ScrollArea } from '@/components/ui/scroll-area'\nimport { Link, Link2Off, Mail, UserPlus, ArrowRight } from 'lucide-react'\nimport { displayName, timeAgo, fmtTime } from '@/lib/display'\nimport { PAIR_STATUS_COLORS } from '@/lib/constants'\nimport type { PairSession } from '@/types'\n\nconst STATUS_OPTIONS = [\n { value: 'open', label: 'Active & Pending' },\n { value: 'active', label: 'Active' },\n { value: 'pending', label: 'Pending' },\n { value: 'ended', label: 'Ended' },\n { value: 'rejected', label: 'Rejected' },\n { value: 'expired', label: 'Expired' },\n { value: '', label: 'All' },\n]\n\nexport function PairsView() {\n const now = useNow()\n const pairs = useRelayStore((s) => s.pairs)\n const agentsById = useRelayStore((s) => s.agentsById)\n const pairStatusFilter = useRelayStore((s) => s.pairStatusFilter)\n const set = useRelayStore((s) => s.set)\n const fetchPairs = useRelayStore((s) => s.fetchPairs)\n const openPairInvite = useRelayStore((s) => s.openPairInvite)\n const openPairMessage = useRelayStore((s) => s.openPairMessage)\n const doAcceptPair = useRelayStore((s) => s.doAcceptPair)\n const doRejectPair = useRelayStore((s) => s.doRejectPair)\n const doHangupPair = useRelayStore((s) => s.doHangupPair)\n\n const pendingCount = pairs.filter((p) => p.status === 'pending').length\n\n function handleStatusChange(value: string) {\n set({ pairStatusFilter: value })\n setTimeout(() => fetchPairs(), 0)\n }\n\n function agentName(id: string) {\n return agentsById[id] ? displayName(agentsById[id]) : id.slice(-10)\n }\n\n return (\n <div className=\"space-y-4\">\n <div className=\"flex items-center justify-between flex-wrap gap-2\">\n <div className=\"flex items-center gap-2\">\n <Link className=\"w-5 h-5 text-muted-foreground\" />\n <h2 className=\"text-lg font-semibold\">Pair Sessions</h2>\n {pendingCount > 0 && (\n <Badge className=\"bg-yellow-500/20 text-yellow-400 border-yellow-500/30 border\">\n {pendingCount} pending\n </Badge>\n )}\n </div>\n <div className=\"flex items-center gap-2\">\n <select\n className=\"rounded-md border border-input bg-background px-3 py-1.5 text-sm\"\n value={pairStatusFilter}\n onChange={(e) => handleStatusChange(e.target.value)}\n >\n {STATUS_OPTIONS.map((o) => <option key={o.value} value={o.value}>{o.label}</option>)}\n </select>\n <Button size=\"sm\" onClick={() => openPairInvite()}>\n <UserPlus className=\"w-4 h-4 mr-1\" /> Pair agents\n </Button>\n </div>\n </div>\n\n <ScrollArea className=\"h-[calc(100dvh-11rem)]\">\n <div className=\"space-y-3 pr-2\">\n {pairs.length === 0 && (\n <div className=\"text-center text-muted-foreground py-16 text-sm\">No pair sessions</div>\n )}\n {pairs.map((pair) => (\n <PairCard\n key={pair.id}\n pair={pair}\n now={now}\n agentName={agentName}\n onAccept={() => doAcceptPair(pair)}\n onReject={() => doRejectPair(pair)}\n onMessage={() => openPairMessage(pair)}\n onHangup={() => doHangupPair(pair)}\n />\n ))}\n </div>\n </ScrollArea>\n </div>\n )\n}\n\nfunction PairCard({\n pair, now, agentName, onAccept, onReject, onMessage, onHangup,\n}: {\n pair: PairSession\n now: number\n agentName: (id: string) => string\n onAccept: () => void\n onReject: () => void\n onMessage: () => void\n onHangup: () => void\n}) {\n const colorClass = PAIR_STATUS_COLORS[pair.status] || 'bg-zinc-500/20 text-zinc-400'\n const isPending = pair.status === 'pending'\n const isActive = pair.status === 'active'\n\n return (\n <Card>\n <CardHeader className=\"py-3 px-4 pb-0\">\n <div className=\"flex items-start justify-between gap-2\">\n <div className=\"flex items-center gap-2 flex-wrap flex-1 min-w-0\">\n <Badge className={`${colorClass} border text-xs`}>{pair.status}</Badge>\n <div className=\"flex items-center gap-1.5 text-sm min-w-0\">\n <span className=\"font-medium truncate max-w-[120px]\" title={pair.requesterId}>{agentName(pair.requesterId)}</span>\n <ArrowRight className=\"w-3.5 h-3.5 text-muted-foreground shrink-0\" />\n <span className=\"font-medium truncate max-w-[120px]\" title={pair.targetId}>{agentName(pair.targetId)}</span>\n </div>\n </div>\n <div className=\"text-right shrink-0\">\n <div className=\"text-xs font-mono text-muted-foreground/60 truncate max-w-[100px]\">{pair.id.slice(-10)}</div>\n <div className=\"text-xs text-muted-foreground\" title={fmtTime(pair.updatedAt)}>\n {timeAgo(now, pair.updatedAt)}\n </div>\n </div>\n </div>\n </CardHeader>\n <CardContent className=\"px-4 py-3\">\n {pair.objective && (\n <p className=\"text-xs text-muted-foreground mb-3 line-clamp-2\">{pair.objective}</p>\n )}\n <div className=\"flex items-center gap-2 flex-wrap\">\n {isPending && (\n <>\n <Button size=\"sm\" className=\"bg-emerald-600 hover:bg-emerald-700 text-white h-7 text-xs\" onClick={onAccept}>\n Accept\n </Button>\n <Button size=\"sm\" variant=\"outline\" className=\"h-7 text-xs text-red-400 hover:text-red-300\" onClick={onReject}>\n Reject\n </Button>\n </>\n )}\n {isActive && (\n <>\n <Button size=\"sm\" variant=\"outline\" className=\"h-7 text-xs\" onClick={onMessage}>\n <Mail className=\"w-3.5 h-3.5 mr-1\" /> Message\n </Button>\n <Button size=\"sm\" variant=\"outline\" className=\"h-7 text-xs text-red-400 hover:text-red-300\" onClick={onHangup}>\n <Link2Off className=\"w-3.5 h-3.5 mr-1\" /> Hang up\n </Button>\n </>\n )}\n </div>\n </CardContent>\n </Card>\n )\n}\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- import{t as e}from"./chunk-CilyBKbf.js";import{Vn as t}from"./lucide-react-CD8Xl2U3.js";var n=e((e=>{var n=t();function r(e){var t=`https://react.dev/errors/`+e;if(1<arguments.length){t+=`?args[]=`+encodeURIComponent(arguments[1]);for(var n=2;n<arguments.length;n++)t+=`&args[]=`+encodeURIComponent(arguments[n])}return`Minified React error #`+e+`; visit `+t+` for the full message or use the non-minified dev environment for full errors and additional helpful warnings.`}function i(){}var a={d:{f:i,r:function(){throw Error(r(522))},D:i,C:i,L:i,m:i,X:i,S:i,M:i},p:0,findDOMNode:null},o=Symbol.for(`react.portal`);function s(e,t,n){var r=3<arguments.length&&arguments[3]!==void 0?arguments[3]:null;return{$$typeof:o,key:r==null?null:``+r,children:e,containerInfo:t,implementation:n}}var c=n.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE;function l(e,t){if(e===`font`)return``;if(typeof t==`string`)return t===`use-credentials`?t:``}e.__DOM_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE=a,e.createPortal=function(e,t){var n=2<arguments.length&&arguments[2]!==void 0?arguments[2]:null;if(!t||t.nodeType!==1&&t.nodeType!==9&&t.nodeType!==11)throw Error(r(299));return s(e,t,null,n)},e.flushSync=function(e){var t=c.T,n=a.p;try{if(c.T=null,a.p=2,e)return e()}finally{c.T=t,a.p=n,a.d.f()}},e.preconnect=function(e,t){typeof e==`string`&&(t?(t=t.crossOrigin,t=typeof t==`string`?t===`use-credentials`?t:``:void 0):t=null,a.d.C(e,t))},e.prefetchDNS=function(e){typeof e==`string`&&a.d.D(e)},e.preinit=function(e,t){if(typeof e==`string`&&t&&typeof t.as==`string`){var n=t.as,r=l(n,t.crossOrigin),i=typeof t.integrity==`string`?t.integrity:void 0,o=typeof t.fetchPriority==`string`?t.fetchPriority:void 0;n===`style`?a.d.S(e,typeof t.precedence==`string`?t.precedence:void 0,{crossOrigin:r,integrity:i,fetchPriority:o}):n===`script`&&a.d.X(e,{crossOrigin:r,integrity:i,fetchPriority:o,nonce:typeof t.nonce==`string`?t.nonce:void 0})}},e.preinitModule=function(e,t){if(typeof e==`string`)if(typeof t==`object`&&t){if(t.as==null||t.as===`script`){var n=l(t.as,t.crossOrigin);a.d.M(e,{crossOrigin:n,integrity:typeof t.integrity==`string`?t.integrity:void 0,nonce:typeof t.nonce==`string`?t.nonce:void 0})}}else t??a.d.M(e)},e.preload=function(e,t){if(typeof e==`string`&&typeof t==`object`&&t&&typeof t.as==`string`){var n=t.as,r=l(n,t.crossOrigin);a.d.L(e,n,{crossOrigin:r,integrity:typeof t.integrity==`string`?t.integrity:void 0,nonce:typeof t.nonce==`string`?t.nonce:void 0,type:typeof t.type==`string`?t.type:void 0,fetchPriority:typeof t.fetchPriority==`string`?t.fetchPriority:void 0,referrerPolicy:typeof t.referrerPolicy==`string`?t.referrerPolicy:void 0,imageSrcSet:typeof t.imageSrcSet==`string`?t.imageSrcSet:void 0,imageSizes:typeof t.imageSizes==`string`?t.imageSizes:void 0,media:typeof t.media==`string`?t.media:void 0})}},e.preloadModule=function(e,t){if(typeof e==`string`)if(t){var n=l(t.as,t.crossOrigin);a.d.m(e,{as:typeof t.as==`string`&&t.as!==`script`?t.as:void 0,crossOrigin:n,integrity:typeof t.integrity==`string`?t.integrity:void 0})}else a.d.m(e)},e.requestFormReset=function(e){a.d.r(e)},e.unstable_batchedUpdates=function(e,t){return e(t)},e.useFormState=function(e,t,n){return c.H.useFormState(e,t,n)},e.useFormStatus=function(){return c.H.useHostTransitionStatus()},e.version=`19.2.6`})),r=e(((e,t)=>{function r(){if(!(typeof __REACT_DEVTOOLS_GLOBAL_HOOK__>`u`||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!=`function`))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(r)}catch(e){console.error(e)}}r(),t.exports=n()}));export{r as t};
2
- //# sourceMappingURL=react-dom-CX8inunm.js.map
1
+ import{t as e}from"./chunk-CilyBKbf.js";import{Hn as t}from"./lucide-react-DLQFnqNm.js";var n=e((e=>{var n=t();function r(e){var t=`https://react.dev/errors/`+e;if(1<arguments.length){t+=`?args[]=`+encodeURIComponent(arguments[1]);for(var n=2;n<arguments.length;n++)t+=`&args[]=`+encodeURIComponent(arguments[n])}return`Minified React error #`+e+`; visit `+t+` for the full message or use the non-minified dev environment for full errors and additional helpful warnings.`}function i(){}var a={d:{f:i,r:function(){throw Error(r(522))},D:i,C:i,L:i,m:i,X:i,S:i,M:i},p:0,findDOMNode:null},o=Symbol.for(`react.portal`);function s(e,t,n){var r=3<arguments.length&&arguments[3]!==void 0?arguments[3]:null;return{$$typeof:o,key:r==null?null:``+r,children:e,containerInfo:t,implementation:n}}var c=n.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE;function l(e,t){if(e===`font`)return``;if(typeof t==`string`)return t===`use-credentials`?t:``}e.__DOM_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE=a,e.createPortal=function(e,t){var n=2<arguments.length&&arguments[2]!==void 0?arguments[2]:null;if(!t||t.nodeType!==1&&t.nodeType!==9&&t.nodeType!==11)throw Error(r(299));return s(e,t,null,n)},e.flushSync=function(e){var t=c.T,n=a.p;try{if(c.T=null,a.p=2,e)return e()}finally{c.T=t,a.p=n,a.d.f()}},e.preconnect=function(e,t){typeof e==`string`&&(t?(t=t.crossOrigin,t=typeof t==`string`?t===`use-credentials`?t:``:void 0):t=null,a.d.C(e,t))},e.prefetchDNS=function(e){typeof e==`string`&&a.d.D(e)},e.preinit=function(e,t){if(typeof e==`string`&&t&&typeof t.as==`string`){var n=t.as,r=l(n,t.crossOrigin),i=typeof t.integrity==`string`?t.integrity:void 0,o=typeof t.fetchPriority==`string`?t.fetchPriority:void 0;n===`style`?a.d.S(e,typeof t.precedence==`string`?t.precedence:void 0,{crossOrigin:r,integrity:i,fetchPriority:o}):n===`script`&&a.d.X(e,{crossOrigin:r,integrity:i,fetchPriority:o,nonce:typeof t.nonce==`string`?t.nonce:void 0})}},e.preinitModule=function(e,t){if(typeof e==`string`)if(typeof t==`object`&&t){if(t.as==null||t.as===`script`){var n=l(t.as,t.crossOrigin);a.d.M(e,{crossOrigin:n,integrity:typeof t.integrity==`string`?t.integrity:void 0,nonce:typeof t.nonce==`string`?t.nonce:void 0})}}else t??a.d.M(e)},e.preload=function(e,t){if(typeof e==`string`&&typeof t==`object`&&t&&typeof t.as==`string`){var n=t.as,r=l(n,t.crossOrigin);a.d.L(e,n,{crossOrigin:r,integrity:typeof t.integrity==`string`?t.integrity:void 0,nonce:typeof t.nonce==`string`?t.nonce:void 0,type:typeof t.type==`string`?t.type:void 0,fetchPriority:typeof t.fetchPriority==`string`?t.fetchPriority:void 0,referrerPolicy:typeof t.referrerPolicy==`string`?t.referrerPolicy:void 0,imageSrcSet:typeof t.imageSrcSet==`string`?t.imageSrcSet:void 0,imageSizes:typeof t.imageSizes==`string`?t.imageSizes:void 0,media:typeof t.media==`string`?t.media:void 0})}},e.preloadModule=function(e,t){if(typeof e==`string`)if(t){var n=l(t.as,t.crossOrigin);a.d.m(e,{as:typeof t.as==`string`&&t.as!==`script`?t.as:void 0,crossOrigin:n,integrity:typeof t.integrity==`string`?t.integrity:void 0})}else a.d.m(e)},e.requestFormReset=function(e){a.d.r(e)},e.unstable_batchedUpdates=function(e,t){return e(t)},e.useFormState=function(e,t,n){return c.H.useFormState(e,t,n)},e.useFormStatus=function(){return c.H.useHostTransitionStatus()},e.version=`19.2.6`})),r=e(((e,t)=>{function r(){if(!(typeof __REACT_DEVTOOLS_GLOBAL_HOOK__>`u`||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!=`function`))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(r)}catch(e){console.error(e)}}r(),t.exports=n()}));export{r as t};
2
+ //# sourceMappingURL=react-dom-CzfKBOnw.js.map