agent-relay-server 0.124.0 → 0.125.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.
- package/docs/openapi.json +1 -1
- package/package.json +2 -2
- package/public/assets/{MessageBubble-SQK8-Mzp.js → MessageBubble-BYeYFteG.js} +2 -2
- package/public/assets/{MessageBubble-SQK8-Mzp.js.map → MessageBubble-BYeYFteG.js.map} +1 -1
- package/public/assets/{PlanGraphPanel-CS-aow4S.js → PlanGraphPanel-iAXvkZKW.js} +2 -2
- package/public/assets/{PlanGraphPanel-CS-aow4S.js.map → PlanGraphPanel-iAXvkZKW.js.map} +1 -1
- package/public/assets/{activity-W31XvhC2.js → activity-Du9SRJt5.js} +2 -2
- package/public/assets/{activity-W31XvhC2.js.map → activity-Du9SRJt5.js.map} +1 -1
- package/public/assets/agent-profiles-DXDQnrlH.js +2 -0
- package/public/assets/{agent-profiles-DXysA9To.js.map → agent-profiles-DXDQnrlH.js.map} +1 -1
- package/public/assets/{agent-type-icon-BxUopALO.js → agent-type-icon-B3i0rndK.js} +2 -2
- package/public/assets/{agent-type-icon-BxUopALO.js.map → agent-type-icon-B3i0rndK.js.map} +1 -1
- package/public/assets/{agents-B5GRNRnN.js → agents-CWOdKrxP.js} +2 -2
- package/public/assets/{agents-B5GRNRnN.js.map → agents-CWOdKrxP.js.map} +1 -1
- package/public/assets/{analytics-DqAuUAwX.js → analytics-YcY59Hv9.js} +2 -2
- package/public/assets/{analytics-DqAuUAwX.js.map → analytics-YcY59Hv9.js.map} +1 -1
- package/public/assets/{automation-DYlgHYcb.js → automation-CItTse7F.js} +2 -2
- package/public/assets/{automation-DYlgHYcb.js.map → automation-CItTse7F.js.map} +1 -1
- package/public/assets/{branch-state-badge-Mf0Ow77K.js → branch-state-badge-QjTktTYj.js} +2 -2
- package/public/assets/{branch-state-badge-Mf0Ow77K.js.map → branch-state-badge-QjTktTYj.js.map} +1 -1
- package/public/assets/{channels-DVRkVeky.js → channels-BSFTsbhT.js} +2 -2
- package/public/assets/{channels-DVRkVeky.js.map → channels-BSFTsbhT.js.map} +1 -1
- package/public/assets/chat-CRzFSFWe.js +2 -0
- package/public/assets/chat-CRzFSFWe.js.map +1 -0
- package/public/assets/{connectors-Cqubkw9C.js → connectors-C7d5dlYz.js} +2 -2
- package/public/assets/{connectors-Cqubkw9C.js.map → connectors-C7d5dlYz.js.map} +1 -1
- package/public/assets/{display-GFbGUG0O.js → display-aTnwsqQh.js} +3 -3
- package/public/assets/{display-GFbGUG0O.js.map → display-aTnwsqQh.js.map} +1 -1
- package/public/assets/{formatted-body-BYQ-SPtj.js → formatted-body-BuLfVMeD.js} +3 -3
- package/public/assets/{formatted-body-BYQ-SPtj.js.map → formatted-body-BuLfVMeD.js.map} +1 -1
- package/public/assets/{formatted-body-impl-L1EMnNW6.js → formatted-body-impl-DO-8giS6.js} +2 -2
- package/public/assets/{formatted-body-impl-L1EMnNW6.js.map → formatted-body-impl-DO-8giS6.js.map} +1 -1
- package/public/assets/index-C9X_0QBt.css +2 -0
- package/public/assets/index-De1tR7J4.js +26 -0
- package/public/assets/index-De1tR7J4.js.map +1 -0
- package/public/assets/{insights-DwZxq1Dn.js → insights-Ci3VuA5Y.js} +2 -2
- package/public/assets/{insights-DwZxq1Dn.js.map → insights-Ci3VuA5Y.js.map} +1 -1
- package/public/assets/{integrations-9G5TJnnU.js → integrations-BboxWQQD.js} +2 -2
- package/public/assets/{integrations-9G5TJnnU.js.map → integrations-BboxWQQD.js.map} +1 -1
- package/public/assets/{maintenance-COcmUDnf.js → maintenance-CO1miJIJ.js} +2 -2
- package/public/assets/{maintenance-COcmUDnf.js.map → maintenance-CO1miJIJ.js.map} +1 -1
- package/public/assets/{managed-agents-D9-dgMeX.js → managed-agents-r4oYK3Fm.js} +2 -2
- package/public/assets/{managed-agents-D9-dgMeX.js.map → managed-agents-r4oYK3Fm.js.map} +1 -1
- package/public/assets/{markdown-preview-impl-DH372bL-.js → markdown-preview-impl-5CCM9iyL.js} +2 -2
- package/public/assets/{markdown-preview-impl-DH372bL-.js.map → markdown-preview-impl-5CCM9iyL.js.map} +1 -1
- package/public/assets/{memory-B9hRK8sk.js → memory-BJJS07W-.js} +2 -2
- package/public/assets/{memory-B9hRK8sk.js.map → memory-BJJS07W-.js.map} +1 -1
- package/public/assets/{messages-BHkHlXzF.js → messages-RT_dfEsL.js} +2 -2
- package/public/assets/{messages-BHkHlXzF.js.map → messages-RT_dfEsL.js.map} +1 -1
- package/public/assets/{orchestrators-CXy3SDSn.js → orchestrators-8hyl8hW1.js} +2 -2
- package/public/assets/{orchestrators-CXy3SDSn.js.map → orchestrators-8hyl8hW1.js.map} +1 -1
- package/public/assets/{overview-D2yRyCQq.js → overview-CUJ9QmW_.js} +2 -2
- package/public/assets/{overview-D2yRyCQq.js.map → overview-CUJ9QmW_.js.map} +1 -1
- package/public/assets/{pairs-5tXdHylI.js → pairs-CzkzMGZq.js} +2 -2
- package/public/assets/{pairs-5tXdHylI.js.map → pairs-CzkzMGZq.js.map} +1 -1
- package/public/assets/{projects-CquHTMo1.js → projects-CAuLWBU5.js} +2 -2
- package/public/assets/{projects-CquHTMo1.js.map → projects-CAuLWBU5.js.map} +1 -1
- package/public/assets/{prompt-settings-Bn5mmi9w.js → prompt-settings-BnB90R7F.js} +2 -2
- package/public/assets/{prompt-settings-Bn5mmi9w.js.map → prompt-settings-BnB90R7F.js.map} +1 -1
- package/public/assets/{registry-C3sB7qv5.js → registry-B8TInqru.js} +2 -2
- package/public/assets/{registry-C3sB7qv5.js.map → registry-B8TInqru.js.map} +1 -1
- package/public/assets/{security-CmD-YE-_.js → security-DG_VVZUW.js} +2 -2
- package/public/assets/{security-CmD-YE-_.js.map → security-DG_VVZUW.js.map} +1 -1
- package/public/assets/{select-C0UlhK2k.js → select-BJ8G38_V.js} +2 -2
- package/public/assets/{select-C0UlhK2k.js.map → select-BJ8G38_V.js.map} +1 -1
- package/public/assets/{settings-DrqMG5nG.js → settings-CK_T9z5w.js} +4 -4
- package/public/assets/{settings-DrqMG5nG.js.map → settings-CK_T9z5w.js.map} +1 -1
- package/public/assets/{store-zFLzd0Jd.js → store-Dl9Z8YUS.js} +4 -4
- package/public/assets/{store-zFLzd0Jd.js.map → store-Dl9Z8YUS.js.map} +1 -1
- package/public/assets/{tasks-ChQjtXHu.js → tasks-Briui9Mp.js} +2 -2
- package/public/assets/{tasks-ChQjtXHu.js.map → tasks-Briui9Mp.js.map} +1 -1
- package/public/assets/{teams-itjNlDLp.js → teams-Ck4EVV3R.js} +2 -2
- package/public/assets/{teams-itjNlDLp.js.map → teams-Ck4EVV3R.js.map} +1 -1
- package/public/assets/{terminal-viewer-impl-B9M6s2vB.js → terminal-viewer-impl-66ZjVN1v.js} +2 -2
- package/public/assets/{terminal-viewer-impl-B9M6s2vB.js.map → terminal-viewer-impl-66ZjVN1v.js.map} +1 -1
- package/public/assets/{types-CRptbSYh.js → types-BqeSkWrv.js} +2 -2
- package/public/assets/{types-CRptbSYh.js.map → types-BqeSkWrv.js.map} +1 -1
- package/public/assets/{user-avatar-kYPfLgXp.js → user-avatar-BOy9o2xK.js} +2 -2
- package/public/assets/{user-avatar-kYPfLgXp.js.map → user-avatar-BOy9o2xK.js.map} +1 -1
- package/public/assets/{work-queue-Kw0uMkEF.js → work-queue-CnghFRG2.js} +2 -2
- package/public/assets/{work-queue-Kw0uMkEF.js.map → work-queue-CnghFRG2.js.map} +1 -1
- package/public/assets/{workspaces-CR6f7G0R.js → workspaces-BzmQnzSm.js} +2 -2
- package/public/assets/{workspaces-CR6f7G0R.js.map → workspaces-BzmQnzSm.js.map} +1 -1
- package/public/index.html +7 -7
- package/runner/plugins/claude/.claude-plugin/plugin.json +1 -1
- package/runner/plugins/claude/hooks/relay-status.sh +11 -1
- package/runner/plugins/claude/hooks/stop.sh +6 -1
- package/runner/plugins/claude/hooks/user-prompt-submit.sh +6 -1
- package/runner/src/adapter.ts +5 -1
- package/runner/src/adapters/claude-transcript.ts +52 -58
- package/runner/src/adapters/codex-agent-message-capture.ts +8 -36
- package/runner/src/adapters/codex.ts +30 -12
- package/runner/src/control-server.ts +9 -4
- package/runner/src/response-capture-report.ts +4 -1
- package/runner/src/runner-core.ts +75 -33
- package/src/agent-lifecycle-events.ts +8 -0
- package/src/bus.ts +0 -24
- package/src/db/agents.ts +15 -1
- package/src/db/messages.ts +114 -43
- package/src/maintenance/jobs.ts +8 -2
- package/src/mcp/tools-workspace.ts +4 -0
- package/src/routes/agents.ts +0 -4
- package/src/services/send-message.ts +7 -18
- package/src/services/shutdown-agent.ts +6 -0
- package/src/services/task-entity.ts +4 -0
- package/src/services/transient-agent-reaper.ts +40 -1
- package/src/services/work-finality.ts +25 -0
- package/public/assets/agent-profiles-DXysA9To.js +0 -2
- package/public/assets/chat-Clz6qOtn.js +0 -2
- package/public/assets/chat-Clz6qOtn.js.map +0 -1
- package/public/assets/index-0uIGXT14.js +0 -25
- package/public/assets/index-0uIGXT14.js.map +0 -1
- package/public/assets/index-DOJ7KidA.css +0 -2
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{B as e,P as t,V as n,W as r,b as i,rr as a,y as o}from"./lucide-react-CoU_Xts2.js";import{t as s}from"./store-
|
|
2
|
-
//# sourceMappingURL=connectors-
|
|
1
|
+
import{B as e,P as t,V as n,W as r,b as i,rr as a,y as o}from"./lucide-react-CoU_Xts2.js";import{t as s}from"./store-Dl9Z8YUS.js";import{J as c,Y as l,l as u}from"./display-aTnwsqQh.js";import{t as d}from"./badge-XEru6wto.js";import{t as f}from"./button-C3CQSr4p.js";import{o as p,r as m,s as h,t as g}from"./card-C5XTIPvq.js";var _=a();function v({connector:a}){let v=s(e=>e.runConnectorAction),y=s(e=>e.openConfirm),b=s(e=>e.showNotification),x=u(a),S=a.runtime,C=a.manifest?.commands||{},w=S.installed,T=!!C.start&&w&&!S.running,E=!!C.stop&&S.running,D=!!C.restart&&w,O=!!C.doctor&&w,k=a.displayName||a.id,A=async e=>{try{await v(a.id,e),b(`${e.charAt(0).toUpperCase()+e.slice(1)} completed for ${k}`)}catch{}};return(0,_.jsxs)(g,{className:`hover:border-zinc-600 transition-colors`,children:[(0,_.jsx)(p,{className:`pb-2 pt-4 px-4`,children:(0,_.jsxs)(`div`,{className:`flex items-start gap-2`,children:[(0,_.jsx)(`div`,{className:`p-1.5 rounded-md ${S.running?`bg-emerald-500/10`:`bg-zinc-800`}`,children:(0,_.jsx)(n,{className:`w-4 h-4 ${S.running?`text-emerald-400`:`text-zinc-500`}`})}),(0,_.jsxs)(`div`,{className:`flex-1 min-w-0`,children:[(0,_.jsx)(h,{className:`text-sm font-medium truncate`,children:a.displayName||a.id}),(0,_.jsx)(`div`,{className:`text-xs text-muted-foreground mt-0.5`,children:a.kind})]}),(0,_.jsx)(d,{className:`text-[10px] shrink-0 ${c(x.tone)}`,children:x.label})]})}),(0,_.jsxs)(m,{className:`px-4 pb-4 space-y-2.5`,children:[a.description&&(0,_.jsx)(`p`,{className:`text-xs text-muted-foreground leading-relaxed line-clamp-2`,children:a.description}),S.detail&&(0,_.jsx)(`div`,{className:`text-xs px-2 py-1 rounded ${S.status===`error`?`bg-red-500/10 text-red-400`:S.status===`warn`?`bg-yellow-500/10 text-yellow-400`:`bg-zinc-800 text-muted-foreground`}`,children:S.detail}),l(a.capabilities).length>0&&(0,_.jsx)(`div`,{className:`flex flex-wrap gap-1`,children:l(a.capabilities).map(e=>(0,_.jsx)(d,{variant:`secondary`,className:`text-[9px] px-1 py-0 h-4`,children:e},e))}),a.version&&(0,_.jsxs)(`div`,{className:`text-xs text-muted-foreground`,children:[`v`,a.version]}),(0,_.jsxs)(`div`,{className:`flex flex-wrap gap-1.5 pt-0.5`,children:[T&&(0,_.jsxs)(f,{size:`sm`,variant:`outline`,className:`h-7 text-xs gap-1 text-emerald-400 border-emerald-500/30 hover:text-emerald-300`,onClick:()=>A(`start`),children:[(0,_.jsx)(r,{className:`w-3 h-3`}),`Start`]}),E&&(0,_.jsxs)(f,{size:`sm`,variant:`outline`,className:`h-7 text-xs gap-1 text-red-400 border-red-500/30 hover:text-red-300`,onClick:()=>y(`Stop Connector`,`Stop ${a.displayName||a.id}?`,()=>A(`stop`)),children:[(0,_.jsx)(i,{className:`w-3 h-3`}),`Stop`]}),D&&(0,_.jsxs)(f,{size:`sm`,variant:`outline`,className:`h-7 text-xs gap-1`,onClick:()=>y(`Restart Connector`,`Restart ${a.displayName||a.id}?`,()=>A(`restart`)),children:[(0,_.jsx)(t,{className:`w-3 h-3`}),`Restart`]}),O&&(0,_.jsxs)(f,{size:`sm`,variant:`ghost`,className:`h-7 text-xs gap-1 text-muted-foreground`,onClick:()=>A(`doctor`),children:[(0,_.jsx)(o,{className:`w-3 h-3`}),`Doctor`]}),!w&&C.install&&(0,_.jsxs)(f,{size:`sm`,variant:`outline`,className:`h-7 text-xs gap-1`,onClick:()=>A(`install`),children:[(0,_.jsx)(e,{className:`w-3 h-3`}),`Install`]}),w&&C.uninstall&&(0,_.jsx)(f,{size:`sm`,variant:`ghost`,className:`h-7 text-xs text-muted-foreground hover:text-red-400`,onClick:()=>y(`Uninstall Connector`,`Uninstall ${a.displayName||a.id}? This will remove the systemd service.`,()=>A(`uninstall`)),children:`Uninstall`})]})]})]})}function y(){let e=s(e=>e.connectors),t=e.filter(e=>e.runtime.running).length;return(0,_.jsxs)(`div`,{className:`space-y-4`,children:[(0,_.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,_.jsxs)(`div`,{children:[(0,_.jsx)(`h2`,{className:`text-base font-semibold`,children:`Connectors`}),(0,_.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:`Installed service connectors and integrations`})]}),(0,_.jsxs)(`div`,{className:`flex items-center gap-2 ml-auto`,children:[(0,_.jsxs)(d,{variant:`outline`,className:`text-xs`,children:[e.length,` total`]}),t>0&&(0,_.jsxs)(d,{className:`text-xs bg-emerald-500/15 text-emerald-400 border-emerald-500/30`,children:[t,` running`]})]})]}),e.length===0?(0,_.jsx)(`div`,{className:`text-center py-16 text-muted-foreground text-sm`,children:`No connectors registered.`}):(0,_.jsx)(`div`,{className:`grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-4`,children:e.map(e=>(0,_.jsx)(v,{connector:e},e.id))})]})}export{y as ConnectorsView};
|
|
2
|
+
//# sourceMappingURL=connectors-C7d5dlYz.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"connectors-Cqubkw9C.js","names":[],"sources":["../../dashboard/src/components/views/connectors.tsx"],"sourcesContent":["import { useRelayStore } from '@/store'\nimport { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'\nimport { Badge } from '@/components/ui/badge'\nimport { Button } from '@/components/ui/button'\nimport { connectorPresence, toneToColor, userFacingCapabilities } from '@/lib/display'\nimport { Plug, Play, Square, RotateCw, Stethoscope, Power } from 'lucide-react'\nimport type { ConnectorSummary } from '@/types'\n\nfunction ConnectorCard({ connector }: { connector: ConnectorSummary }) {\n const runConnectorAction = useRelayStore((s) => s.runConnectorAction)\n const openConfirm = useRelayStore((s) => s.openConfirm)\n const showNotification = useRelayStore((s) => s.showNotification)\n\n const presence = connectorPresence(connector)\n const runtime = connector.runtime\n const commands = connector.manifest?.commands || {}\n const installed = runtime.installed\n\n const canStart = Boolean(commands.start) && installed && !runtime.running\n const canStop = Boolean(commands.stop) && runtime.running\n const canRestart = Boolean(commands.restart) && installed\n const canDoctor = Boolean(commands.doctor) && installed\n\n const name = connector.displayName || connector.id\n const run = async (action: string) => {\n try {\n await runConnectorAction(connector.id, action)\n showNotification(`${action.charAt(0).toUpperCase() + action.slice(1)} completed for ${name}`)\n } catch { /* error modal already shown by store */ }\n }\n\n return (\n <Card className=\"hover:border-zinc-600 transition-colors\">\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 ${runtime.running ? 'bg-emerald-500/10' : 'bg-zinc-800'}`}>\n <Plug className={`w-4 h-4 ${runtime.running ? 'text-emerald-400' : 'text-zinc-500'}`} />\n </div>\n <div className=\"flex-1 min-w-0\">\n <CardTitle className=\"text-sm font-medium truncate\">{connector.displayName || connector.id}</CardTitle>\n <div className=\"text-xs text-muted-foreground mt-0.5\">{connector.kind}</div>\n </div>\n <Badge className={`text-[10px] shrink-0 ${toneToColor(presence.tone)}`}>\n {presence.label}\n </Badge>\n </div>\n </CardHeader>\n\n <CardContent className=\"px-4 pb-4 space-y-2.5\">\n {/* Description */}\n {connector.description && (\n <p className=\"text-xs text-muted-foreground leading-relaxed line-clamp-2\">{connector.description}</p>\n )}\n\n {/* Runtime status detail */}\n {runtime.detail && (\n <div className={`text-xs px-2 py-1 rounded ${runtime.status === 'error' ? 'bg-red-500/10 text-red-400' : runtime.status === 'warn' ? 'bg-yellow-500/10 text-yellow-400' : 'bg-zinc-800 text-muted-foreground'}`}>\n {runtime.detail}\n </div>\n )}\n\n {/* Capabilities */}\n {userFacingCapabilities(connector.capabilities).length > 0 && (\n <div className=\"flex flex-wrap gap-1\">\n {userFacingCapabilities(connector.capabilities).map((c) => (\n <Badge key={c} variant=\"secondary\" className=\"text-[9px] px-1 py-0 h-4\">{c}</Badge>\n ))}\n </div>\n )}\n\n {/* Version */}\n {connector.version && (\n <div className=\"text-xs text-muted-foreground\">v{connector.version}</div>\n )}\n\n {/* Action buttons */}\n <div className=\"flex flex-wrap gap-1.5 pt-0.5\">\n {canStart && (\n <Button\n size=\"sm\"\n variant=\"outline\"\n className=\"h-7 text-xs gap-1 text-emerald-400 border-emerald-500/30 hover:text-emerald-300\"\n onClick={() => run('start')}\n >\n <Play className=\"w-3 h-3\" />\n Start\n </Button>\n )}\n {canStop && (\n <Button\n size=\"sm\"\n variant=\"outline\"\n className=\"h-7 text-xs gap-1 text-red-400 border-red-500/30 hover:text-red-300\"\n onClick={() => openConfirm('Stop Connector', `Stop ${connector.displayName || connector.id}?`, () => run('stop'))}\n >\n <Square className=\"w-3 h-3\" />\n Stop\n </Button>\n )}\n {canRestart && (\n <Button\n size=\"sm\"\n variant=\"outline\"\n className=\"h-7 text-xs gap-1\"\n onClick={() => openConfirm('Restart Connector', `Restart ${connector.displayName || connector.id}?`, () => run('restart'))}\n >\n <RotateCw className=\"w-3 h-3\" />\n Restart\n </Button>\n )}\n {canDoctor && (\n <Button\n size=\"sm\"\n variant=\"ghost\"\n className=\"h-7 text-xs gap-1 text-muted-foreground\"\n onClick={() => run('doctor')}\n >\n <Stethoscope className=\"w-3 h-3\" />\n Doctor\n </Button>\n )}\n {!installed && commands.install && (\n <Button\n size=\"sm\"\n variant=\"outline\"\n className=\"h-7 text-xs gap-1\"\n onClick={() => run('install')}\n >\n <Power className=\"w-3 h-3\" />\n Install\n </Button>\n )}\n {installed && commands.uninstall && (\n <Button\n size=\"sm\"\n variant=\"ghost\"\n className=\"h-7 text-xs text-muted-foreground hover:text-red-400\"\n onClick={() => openConfirm('Uninstall Connector', `Uninstall ${connector.displayName || connector.id}? This will remove the systemd service.`, () => run('uninstall'))}\n >\n Uninstall\n </Button>\n )}\n </div>\n </CardContent>\n </Card>\n )\n}\n\nexport function ConnectorsView() {\n const connectors = useRelayStore((s) => s.connectors)\n\n const runningCount = connectors.filter((c) => c.runtime.running).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\">Connectors</h2>\n <p className=\"text-xs text-muted-foreground\">Installed service connectors and integrations</p>\n </div>\n <div className=\"flex items-center gap-2 ml-auto\">\n <Badge variant=\"outline\" className=\"text-xs\">\n {connectors.length} total\n </Badge>\n {runningCount > 0 && (\n <Badge className=\"text-xs bg-emerald-500/15 text-emerald-400 border-emerald-500/30\">\n {runningCount} running\n </Badge>\n )}\n </div>\n </div>\n\n {/* Cards */}\n {connectors.length === 0 ? (\n <div className=\"text-center py-16 text-muted-foreground text-sm\">\n No connectors registered.\n </div>\n ) : (\n <div className=\"grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-4\">\n {connectors.map((connector) => (\n <ConnectorCard key={connector.id} connector={connector} />\n ))}\n </div>\n )}\n </div>\n )\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"connectors-C7d5dlYz.js","names":[],"sources":["../../dashboard/src/components/views/connectors.tsx"],"sourcesContent":["import { useRelayStore } from '@/store'\nimport { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'\nimport { Badge } from '@/components/ui/badge'\nimport { Button } from '@/components/ui/button'\nimport { connectorPresence, toneToColor, userFacingCapabilities } from '@/lib/display'\nimport { Plug, Play, Square, RotateCw, Stethoscope, Power } from 'lucide-react'\nimport type { ConnectorSummary } from '@/types'\n\nfunction ConnectorCard({ connector }: { connector: ConnectorSummary }) {\n const runConnectorAction = useRelayStore((s) => s.runConnectorAction)\n const openConfirm = useRelayStore((s) => s.openConfirm)\n const showNotification = useRelayStore((s) => s.showNotification)\n\n const presence = connectorPresence(connector)\n const runtime = connector.runtime\n const commands = connector.manifest?.commands || {}\n const installed = runtime.installed\n\n const canStart = Boolean(commands.start) && installed && !runtime.running\n const canStop = Boolean(commands.stop) && runtime.running\n const canRestart = Boolean(commands.restart) && installed\n const canDoctor = Boolean(commands.doctor) && installed\n\n const name = connector.displayName || connector.id\n const run = async (action: string) => {\n try {\n await runConnectorAction(connector.id, action)\n showNotification(`${action.charAt(0).toUpperCase() + action.slice(1)} completed for ${name}`)\n } catch { /* error modal already shown by store */ }\n }\n\n return (\n <Card className=\"hover:border-zinc-600 transition-colors\">\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 ${runtime.running ? 'bg-emerald-500/10' : 'bg-zinc-800'}`}>\n <Plug className={`w-4 h-4 ${runtime.running ? 'text-emerald-400' : 'text-zinc-500'}`} />\n </div>\n <div className=\"flex-1 min-w-0\">\n <CardTitle className=\"text-sm font-medium truncate\">{connector.displayName || connector.id}</CardTitle>\n <div className=\"text-xs text-muted-foreground mt-0.5\">{connector.kind}</div>\n </div>\n <Badge className={`text-[10px] shrink-0 ${toneToColor(presence.tone)}`}>\n {presence.label}\n </Badge>\n </div>\n </CardHeader>\n\n <CardContent className=\"px-4 pb-4 space-y-2.5\">\n {/* Description */}\n {connector.description && (\n <p className=\"text-xs text-muted-foreground leading-relaxed line-clamp-2\">{connector.description}</p>\n )}\n\n {/* Runtime status detail */}\n {runtime.detail && (\n <div className={`text-xs px-2 py-1 rounded ${runtime.status === 'error' ? 'bg-red-500/10 text-red-400' : runtime.status === 'warn' ? 'bg-yellow-500/10 text-yellow-400' : 'bg-zinc-800 text-muted-foreground'}`}>\n {runtime.detail}\n </div>\n )}\n\n {/* Capabilities */}\n {userFacingCapabilities(connector.capabilities).length > 0 && (\n <div className=\"flex flex-wrap gap-1\">\n {userFacingCapabilities(connector.capabilities).map((c) => (\n <Badge key={c} variant=\"secondary\" className=\"text-[9px] px-1 py-0 h-4\">{c}</Badge>\n ))}\n </div>\n )}\n\n {/* Version */}\n {connector.version && (\n <div className=\"text-xs text-muted-foreground\">v{connector.version}</div>\n )}\n\n {/* Action buttons */}\n <div className=\"flex flex-wrap gap-1.5 pt-0.5\">\n {canStart && (\n <Button\n size=\"sm\"\n variant=\"outline\"\n className=\"h-7 text-xs gap-1 text-emerald-400 border-emerald-500/30 hover:text-emerald-300\"\n onClick={() => run('start')}\n >\n <Play className=\"w-3 h-3\" />\n Start\n </Button>\n )}\n {canStop && (\n <Button\n size=\"sm\"\n variant=\"outline\"\n className=\"h-7 text-xs gap-1 text-red-400 border-red-500/30 hover:text-red-300\"\n onClick={() => openConfirm('Stop Connector', `Stop ${connector.displayName || connector.id}?`, () => run('stop'))}\n >\n <Square className=\"w-3 h-3\" />\n Stop\n </Button>\n )}\n {canRestart && (\n <Button\n size=\"sm\"\n variant=\"outline\"\n className=\"h-7 text-xs gap-1\"\n onClick={() => openConfirm('Restart Connector', `Restart ${connector.displayName || connector.id}?`, () => run('restart'))}\n >\n <RotateCw className=\"w-3 h-3\" />\n Restart\n </Button>\n )}\n {canDoctor && (\n <Button\n size=\"sm\"\n variant=\"ghost\"\n className=\"h-7 text-xs gap-1 text-muted-foreground\"\n onClick={() => run('doctor')}\n >\n <Stethoscope className=\"w-3 h-3\" />\n Doctor\n </Button>\n )}\n {!installed && commands.install && (\n <Button\n size=\"sm\"\n variant=\"outline\"\n className=\"h-7 text-xs gap-1\"\n onClick={() => run('install')}\n >\n <Power className=\"w-3 h-3\" />\n Install\n </Button>\n )}\n {installed && commands.uninstall && (\n <Button\n size=\"sm\"\n variant=\"ghost\"\n className=\"h-7 text-xs text-muted-foreground hover:text-red-400\"\n onClick={() => openConfirm('Uninstall Connector', `Uninstall ${connector.displayName || connector.id}? This will remove the systemd service.`, () => run('uninstall'))}\n >\n Uninstall\n </Button>\n )}\n </div>\n </CardContent>\n </Card>\n )\n}\n\nexport function ConnectorsView() {\n const connectors = useRelayStore((s) => s.connectors)\n\n const runningCount = connectors.filter((c) => c.runtime.running).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\">Connectors</h2>\n <p className=\"text-xs text-muted-foreground\">Installed service connectors and integrations</p>\n </div>\n <div className=\"flex items-center gap-2 ml-auto\">\n <Badge variant=\"outline\" className=\"text-xs\">\n {connectors.length} total\n </Badge>\n {runningCount > 0 && (\n <Badge className=\"text-xs bg-emerald-500/15 text-emerald-400 border-emerald-500/30\">\n {runningCount} running\n </Badge>\n )}\n </div>\n </div>\n\n {/* Cards */}\n {connectors.length === 0 ? (\n <div className=\"text-center py-16 text-muted-foreground text-sm\">\n No connectors registered.\n </div>\n ) : (\n <div className=\"grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-4\">\n {connectors.map((connector) => (\n <ConnectorCard key={connector.id} connector={connector} />\n ))}\n </div>\n )}\n </div>\n )\n}\n"],"mappings":"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"}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import{_ as e,c as t,
|
|
2
|
-
`+t;if(e)return e;if(t)return t}let i=t.reaction;if(i&&typeof i==`object`){let e=typeof i.name==`string`?i.name:``,t=typeof i.emoji==`string`?i.emoji:``,n=typeof i.value==`string`?i.value:``;return[`Reaction`,b(t||e||n)].filter(Boolean).join(`: `)}let a=t.activity;return a&&typeof a==`object`?[typeof a.kind==`string`?a.kind:`activity`,typeof a.state==`string`?a.state:``].filter(Boolean).join(` `):typeof t.text==`string`&&t.text.trim()?t.text:typeof t.message==`string`&&t.message.trim()?t.message:W(e.body||``)??(e.body||``)}function H(e){if(!e?.payload)return!1;let t=e.payload.event;return e.payload.reactionNotification===!0||t?.type===`message.reaction`}function U(e){if(!e)return null;let t=e.trim();if(!t.startsWith(`{`))return null;try{let e=JSON.parse(t);if(typeof e!=`object`||!e||Array.isArray(e))return null;let n=typeof e.text==`string`?e.text:typeof e.message==`string`?e.message:null;if(!n?.trim())return null;let r=new Set([`text`,`message`]);return{text:n,meta:Object.entries(e).filter(([e,t])=>!r.has(e)&&(typeof t==`string`||typeof t==`number`||typeof t==`boolean`)).map(([e,t])=>[e,String(t)]),raw:e}}catch{return null}}function W(e){return U(e)?.text??null}function G(e){let t=e?.subject||V(e)||``;return t.length>90?t.slice(0,90)+`...`:t}function le(e){return o(e.from)&&e.to?e.to:o(e.to)&&e.from?e.from:``}function K(e){return o(e.to)&&!o(e.from)}function ue(e){if(e.kind!==`session`)return!1;let t=e.payload?.session?.type;return t===`reasoning`||t===`tool`}function q(e){return e.kind===`session`&&a(e.payload)}function de(e,t){let n=e.trim(),r=t.trim();return r?n===r?!0:n.startsWith(`${r}\n\n`)||n.endsWith(`\n\n${r}`)||n.includes(`\n\n${r}\n\n`):!1}function fe(e,t,n){if(!K(n)||!q(n)||(n.readBy||[]).includes(`user`))return!1;let r=Number(e[t]||0);return n.id>(Number.isFinite(r)?r:0)}function pe(e){return(e.kind??`claim`)===`claim`&&ee.has(e.status)&&!e.claimedBy}function me(e){return!!(e.claimable&&!e.claimedBy&&!(e.kind===`task`&&Number.isSafeInteger(e.payload?.taskId)))}function he(e,t){return!e||!t?!1:e===`broadcast`||e===t.id?!0:e.startsWith(`tag:`)?(t.tags||[]).includes(e.slice(4)):e.startsWith(`cap:`)?(t.capabilities||[]).includes(e.slice(4)):e.startsWith(`label:`)?t.label===e.slice(6):e.startsWith(`team:`)?t.teamId===e.slice(5):!1}function ge(e,t){return e?t.from===e||t.to===e||t.resolvedToAgent===e:!1}function _e(e,t){if(!e||!t)return!1;let n=[t.id,t.type,...t.topicChannels||[]].filter(Boolean);if(e.channel&&n.includes(e.channel))return!0;let r=e.payload?.channel;if(r&&typeof r==`object`){let e=[r.agentId,r.provider,r.accountId].filter(Boolean);if(e.includes(t.id)||e.includes(t.type)||t.accountId&&e.includes(t.accountId))return!0}return!!(t.agentId&&(e.from===t.agentId||e.to===t.agentId))}function J(e){let t=e?.meta?.providerState;return!n(t)||typeof t.state!=`string`?null:{state:t.state,reason:typeof t.reason==`string`?t.reason:void 0,label:typeof t.label==`string`&&t.label?t.label:t.state,recommendedAction:typeof t.recommendedAction==`string`?t.recommendedAction:void 0,source:typeof t.source==`string`?t.source:void 0,raw:t.raw,updatedAt:typeof t.updatedAt==`number`?t.updatedAt:void 0,pendingApproval:ve(t.pendingApproval)}}function ve(e){if(!n(e)||typeof e.id!=`string`)return;let t=Array.isArray(e.choices)?e.choices.filter(n).map(e=>({id:e.id,label:typeof e.label==`string`?e.label:String(e.id||``)})).filter(e=>(e.id===`approve`||e.id===`approve-session`||e.id===`deny`||e.id===`abort`)&&!!e.label):[],r=Array.isArray(e.questions)?e.questions.filter(n).map(e=>({question:typeof e.question==`string`?e.question:``,header:typeof e.header==`string`?e.header:void 0,multiSelect:e.multiSelect===!0,options:Array.isArray(e.options)?e.options.filter(n).map(e=>({label:typeof e.label==`string`?e.label:String(e.label??``),description:typeof e.description==`string`?e.description:void 0})).filter(e=>!!e.label):[]})).filter(e=>!!e.question&&e.options.length>0):void 0;return{id:e.id,provider:typeof e.provider==`string`?e.provider:void 0,kind:typeof e.kind==`string`?e.kind:void 0,title:typeof e.title==`string`&&e.title?e.title:`Permission request`,body:typeof e.body==`string`?e.body:``,choices:t,...r&&r.length?{questions:r}:{}}}function Y(e){let t=J(e);return t?.state===`blocked`?t:null}function ye(e){return!!e?.id}function be(e){return ye(Y(e)?.pendingApproval)}function X(e){let t=e?.meta?.activeSubagents;if(!Array.isArray(t)){let t=typeof e?.meta?.activeSubagentCount==`number`?e.meta.activeSubagentCount:0;return t>0?Array.from({length:t},(e,t)=>({id:`subagent-${t+1}`,label:`Subagent ${t+1}`})):[]}return t.filter(n).map((e,t)=>{let n=typeof e.id==`string`&&e.id?e.id:`subagent-${t+1}`,r=typeof e.role==`string`&&e.role?e.role:void 0;return{id:n,label:typeof e.label==`string`&&e.label?e.label:r||n,role:r,startedAt:typeof e.startedAt==`number`?e.startedAt:void 0}})}function Z(e){let t=e?.meta?.activeWork;if(!Array.isArray(t))return null;let r=t.find(e=>n(e)&&e.kind===`background-script`);return!r||!n(r)?null:typeof r.label==`string`&&r.label?r.label:`background script`}function xe(e,t,n,r){let i=typeof t?.meta?.lifecycleAction==`string`?t.meta.lifecycleAction:``,a=D(e,t),o=t?.status!==`offline`&&!t?.ready&&a,s=t?.status!==`offline`&&!t?.ready&&!a,c=n.unread>0&&t?.status!==`busy`,l=Y(t),u=Se(t,n,r);if(t?.status===`offline`)return{label:`offline`,tone:`secondary`,icon:`PlugZap`,stale:!1,reconnecting:!1,badges:u};if(i.startsWith(`finalizing-`))return{label:`wrapping up (${i.slice(11)})`,tone:`warning`,icon:`Hourglass`,stale:a,reconnecting:o,badges:u};if(i===`shutting-down`)return{label:`shutting down`,tone:`warning`,icon:`Power`,stale:a,reconnecting:o,badges:u};if(i===`killing`)return{label:`killing`,tone:`danger`,icon:`Power`,stale:a,reconnecting:o,badges:u};if(i===`restarting`)return{label:`restarting`,tone:`warning`,icon:`RefreshCw`,stale:a,reconnecting:o,badges:u};if(t?.status===`stale`)return{label:`stale`,tone:`danger`,icon:`RefreshCw`,stale:!0,reconnecting:!0,badges:u};if(o)return{label:`reconnecting`,tone:`danger`,icon:`RefreshCw`,stale:a,reconnecting:o,badges:u};if(s)return{label:`online, not ready`,tone:`warning`,icon:`Loader`,stale:a,reconnecting:o,badges:u};if(l)return{label:`blocked: ${l.label}`,tone:`danger`,icon:`AlertCircle`,stale:a,reconnecting:o,badges:u};if(t?.status===`busy`){let e=Array.isArray(t?.meta?.busyReasons)?t.meta.busyReasons:[];return Z(t)&&!e.includes(`provider-turn`)&&!e.includes(`subagent`)?{label:`running background work`,tone:`warning`,icon:`Play`,stale:a,reconnecting:o,badges:u}:{label:`busy in turn`,tone:`warning`,icon:`Play`,stale:a,reconnecting:o,badges:u}}return r?.status===`active`?{label:`paired`,tone:`success`,icon:`Link`,stale:a,reconnecting:o,badges:u}:c?{label:`idle, unread`,tone:`danger`,icon:`Bell`,stale:a,reconnecting:o,badges:u}:{label:t?.status===`idle`?`idle`:`ready`,tone:`success`,icon:`CircleCheck`,stale:a,reconnecting:o,badges:u}}function Se(e,t,n){let r=[],i=Y(e),a=X(e).length;i&&r.push({label:i.reason?`blocked: ${i.reason}`:`blocked`,className:`bg-red-500/20 text-red-400`}),a&&r.push({label:a===1?`1 subagent`:a+` subagents`,className:`bg-cyan-500/20 text-cyan-300`});let o=Z(e);return o&&r.push({label:o,className:`bg-indigo-500/20 text-indigo-300`}),n?.status===`active`&&r.push({label:`paired`,className:`bg-emerald-500/20 text-emerald-400`}),n?.status===`pending`&&r.push({label:`pair invite`,className:`bg-yellow-500/20 text-yellow-400`}),t.needsHumanResponse&&r.push({label:`needs response`,className:`bg-amber-500/20 text-amber-300`}),t.unread&&r.push({label:t.unread+` unread`,className:`bg-red-500/20 text-red-400`}),t.claimableTasks&&r.push({label:t.claimableTasks+` claimable`,className:`bg-orange-500/20 text-orange-400`}),r}function Ce(){return{unread:0,needsHumanResponse:!1,pendingPairInvite:!1,claimableTasks:0,total:0,score:0}}function Q(e){return!e||e.status===`offline`?!1:e.targetHealth?.status===`ok`?!0:e.targetHealth?.status===`error`||e.targetHealth?.status===`warning`?!1:e.ready}function we(e){return e?e.targetHealth?.status===`error`?{label:`target broken`,tone:`danger`,icon:`AlertTriangle`,badges:[]}:e.targetHealth?.status===`warning`?{label:`target warning`,tone:`warning`,icon:`AlertCircle`,badges:[]}:e.status===`offline`?{label:`offline`,tone:`secondary`,icon:`PlugZap`,badges:[]}:e.status===`busy`?{label:`busy`,tone:`warning`,icon:`Activity`,badges:[]}:Q(e)?{label:`ready`,tone:`success`,icon:`CircleCheck`,badges:[]}:{label:`not ready`,tone:`warning`,icon:`Loader`,badges:[]}:{label:`unknown`,tone:`secondary`,icon:`PlugZap`,badges:[]}}function Te(e){let t=e?.runtime||{};return t.status===`error`?{label:`error`,tone:`danger`,icon:`AlertTriangle`,badges:[]}:t.status===`warn`?{label:`warning`,tone:`warning`,icon:`AlertCircle`,badges:[]}:t.running?{label:`running`,tone:`success`,icon:`CircleCheck`,badges:[]}:t.enabled===!1?{label:`disabled`,tone:`secondary`,icon:`Pause`,badges:[]}:t.status===`ok`?{label:`ok`,tone:`success`,icon:`CircleCheck`,badges:[]}:{label:`unknown`,tone:`secondary`,icon:`HelpCircle`,badges:[]}}function Ee(e){let t=e?.taskStats||{};return(t.waitingTasks||0)>0?{label:`waiting`,tone:`warning`,icon:`AlertCircle`,badges:[]}:(t.openTasks||0)>0?{label:`active`,tone:`info`,icon:`Activity`,badges:[]}:e?.configured?e.observed?{label:`quiet`,tone:`success`,icon:`CircleCheck`,badges:[]}:{label:`configured`,tone:`primary`,icon:`PlugZap`,badges:[]}:{label:`observed only`,tone:`secondary`,icon:`Eye`,badges:[]}}function De(e){let t=e?.health;return!t||t.status===`ok`?e?.version||e?.package?.version?`compatible`:`unknown version`:t.status===`upgrade-required`?`upgrade required`:t.status===`restart-required`?`restart required`:t.status===`unknown`?`unknown contract`:(t.issues||[]).some(e=>e.code===`protocol-mismatch`)?`protocol mismatch`:(t.issues||[]).some(e=>e.code===`package-drift`)?`package drift`:t.restartRequired?`restart required`:t.status}function $(e){let t=e?.health?.status;return t===`upgrade-required`?`text-red-400 bg-red-500/10`:t===`warn`||t===`restart-required`?`text-yellow-400 bg-yellow-500/10`:t===`unknown`?`text-zinc-400 bg-zinc-500/10`:`text-emerald-400 bg-emerald-500/10`}function Oe(e,t){if(!t)return``;let n=new Date(t).getTime();if(!Number.isFinite(n))return``;let r=Math.max(0,(e-n)/1e3);return r<60?Math.floor(r)+`s ago`:r<3600?Math.floor(r/60)+`m ago`:r<86400?Math.floor(r/3600)+`h ago`:Math.floor(r/86400)+`d ago`}function ke(e){return e?new Date(e).toLocaleString():``}function Ae(e){return String(e||`export`).replace(/[^a-z0-9._-]+/gi,`-`).replace(/^-+|-+$/g,``).slice(0,80)||`export`}function je(e){return e.filter(e=>e.status!==`ok`).map(e=>{let t={name:e.name,status:e.status,detail:e.detail||e.name,impact:Me(e),subjects:e.subjects||[],actions:[{label:`Inspect logs`,icon:`FileSearch`,copy:`agent-relay daemon logs`},{label:`Restart daemon`,icon:`RefreshCw`,copy:`agent-relay daemon restart`},{label:`Copy env`,icon:`Copy`,copy:`agent-relay doctor`}]};return e.name===`stale-live-agents`?t.actions.unshift({label:`Run reaper`,icon:`Eraser`,api:`POST`,path:`/system/reap`},{label:`Show stale`,icon:`Filter`,view:`agents`,preset:`offline_stale`}):e.name===`channel-delivery-targets`?t.actions.unshift({label:`Open channels`,icon:`MessagesSquare`,view:`channels`},{label:`Run reaper`,icon:`Eraser`,api:`POST`,path:`/system/reap`}):[`expired-message-claims`,`expired-task-claims`,`offline-claimed-tasks`].includes(e.name)&&t.actions.unshift({label:`Run reaper`,icon:`Eraser`,api:`POST`,path:`/system/reap`},{label:`Open work`,icon:`ListChecks`,view:`work`}),t})}function Me(e){return{database:`Relay persistence is unavailable; messages, state, and audit writes may fail.`,"stale-live-agents":`Agents may look online even though their heartbeat has stopped.`,"expired-message-claims":`Claimable messages may be stuck until the reaper releases expired claims.`,"expired-task-claims":`Tasks can appear owned by agents that no longer hold a live lease.`,"offline-claimed-tasks":`Offline agents are still shown as owners for active work.`,"channel-delivery-targets":`Inbound channel messages may be accepted but routed to no live delivery agent.`}[e.name]||`Relay health is degraded for this check.`}function Ne(e){return{success:`text-emerald-400`,warning:`text-yellow-400`,danger:`text-red-400`,info:`text-blue-400`,primary:`text-blue-400`,secondary:`text-zinc-400`}[e]||`text-zinc-400`}function Pe(e,t){return!e||e.status===`offline`?`bg-zinc-500 opacity-50`:typeof e.meta?.lifecycleAction==`string`&&e.meta.lifecycleAction.startsWith(`finalizing-`)?`bg-amber-500 animate-pulse`:e.meta?.lifecycleAction===`shutting-down`||e.meta?.lifecycleAction===`restarting`?`bg-yellow-500 animate-pulse`:e.meta?.lifecycleAction===`killing`||Y(e)?`bg-red-500 animate-pulse`:e.status===`busy`?`bg-yellow-500`:t&&D(t,e)?`bg-red-500 animate-pulse`:e.ready?`bg-emerald-500 shadow-[0_0_6px_theme(colors.emerald.500)]`:`bg-emerald-500 animate-pulse`}function Fe(e,t,n){if(typeof document>`u`||typeof URL>`u`||typeof Blob>`u`)return;let r=URL.createObjectURL(new Blob([t],{type:n})),i=document.createElement(`a`);i.href=r,i.download=e,i.click(),URL.revokeObjectURL(r)}export{f as $,ge as A,J as B,me as C,ue as D,H as E,$ as F,Pe as G,de as H,De as I,Ne as J,Oe as K,U as L,G as M,x as N,fe as O,b as P,u as Q,ce as R,q as S,K as T,Ae as U,I as V,se as W,P as X,oe as Y,d as Z,z as _,O as a,l as at,Ee as b,we as c,y as ct,F as d,p as et,B as f,je as g,ke as h,xe as i,c as it,_e as j,V as k,Te as l,te as lt,Ce as m,M as n,m as nt,E as o,v as ot,Fe as p,re as q,be as r,s as rt,Q as s,ne as st,X as t,h as tt,he as u,L as v,pe as w,D as x,le as y,Y as z};
|
|
3
|
-
//# sourceMappingURL=display-
|
|
1
|
+
import{_ as e,c as t,h as n,l as r,p as i,s as a,v as o}from"./types-BqeSkWrv.js";var s=`user`,c=s,l=5e3,u=new Set([`done`,`failed`,`canceled`]),ee=new Set([`open`,`blocked`]),te={online:0,idle:0,busy:2,offline:3},d={idle:0,online:0,busy:2,offline:4},f={from:``,to:``,body:``,channel:``,subject:``,claimable:!1},p={toMode:`agent`,to:``,body:``,channel:``,subject:``,claimable:!1},m={pairId:``,from:``,body:``,subject:``},h={requesterId:``,targetId:``,objective:``},g={user:`User`,system:`Server`,channel:`MessagesSquare`,agent:`Bot`},_={user:`Human operator`,system:`System`,channel:`Channel`,agent:`Agent`};({...g,...Object.fromEntries(n().map(e=>[e,`Bot`]))}),{..._,...Object.fromEntries(n().map(t=>[t,`${e(t)} agent`]))};var v=[{key:`overview`,label:`Overview`,icon:`LayoutDashboard`},{key:`chat`,label:`Chat`,icon:`MessageCircle`},{key:`agents`,label:`Agents`,icon:`Bot`},{key:`managed`,label:`Managed Agents`,icon:`Workflow`},{key:`teams`,label:`Teams`,icon:`Users`},{key:`profiles`,label:`Agent Profiles`,icon:`UserCog`},{key:`orchestrators`,label:`Orchestrators`,icon:`Server`},{key:`workspaces`,label:`Workspaces`,icon:`GitBranch`},{key:`files`,label:`Files`,icon:`FolderTree`},{key:`channels`,label:`Channels`,icon:`MessagesSquare`},{key:`connectors`,label:`Connectors`,icon:`Plug`},{key:`integrations`,label:`Integrations`,icon:`PlugZap`},{key:`security`,label:`Security`,icon:`Shield`},{key:`memory`,label:`Memory`,icon:`BrainCircuit`},{key:`activity`,label:`Activity`,icon:`Activity`},{key:`pairs`,label:`Pairs`,icon:`Link`},{key:`messages`,label:`Messages`,icon:`Mail`},{key:`work`,label:`Work Queue`,icon:`ListChecks`},{key:`tasks`,label:`Tasks`,icon:`ClipboardList`},{key:`automation`,label:`Automation`,icon:`CalendarClock`},{key:`analytics`,label:`Analytics`,icon:`AreaChart`},{key:`insights`,label:`Insights`,icon:`Lightbulb`},{key:`projects`,label:`Projects`,icon:`Boxes`},{key:`prompts`,label:`Prompts`,icon:`FileText`},{key:`registry`,label:`Registry`,icon:`PackagePlus`},{key:`maintenance`,label:`Maintenance`,icon:`Wrench`},{key:`settings`,label:`Settings`,icon:`Settings`}],y={critical:`text-red-400 bg-red-500/10`,warning:`text-yellow-400 bg-yellow-500/10`,info:`text-blue-400 bg-blue-500/10`},ne={active:`bg-emerald-500/20 text-emerald-400`,pending:`bg-yellow-500/20 text-yellow-400`,ended:`bg-zinc-500/20 text-zinc-400`,rejected:`bg-red-500/20 text-red-400`,expired:`bg-red-500/20 text-red-400`};function re(e){let t=typeof e==`number`?e:new Date(e||0).getTime();return Number.isFinite(t)?t:0}var ie=[`lifecycle.`,`commands.`,`capabilities.`],ae={"+1":`👍`,":+1:":`👍`,thumbsup:`👍`,":thumbsup:":`👍`,"thumbs-up":`👍`,":thumbs-up:":`👍`,thumbs_up:`👍`,":thumbs_up:":`👍`,thumb_up:`👍`,":thumb_up:":`👍`,like:`👍`,":like:":`👍`,heart:`❤️`,":heart:":`❤️`,redheart:`❤️`,red_heart:`❤️`,":red_heart:":`❤️`,check:`✅`,":check:":`✅`,checkmark:`✅`,":checkmark:":`✅`,white_check_mark:`✅`,":white_check_mark:":`✅`,eyes:`👀`,":eyes:":`👀`};function b(e){let t=e.trim();return ae[t.toLowerCase()]??t}function oe(e){return e.filter(e=>!ie.some(t=>e.startsWith(t)))}function se(e,t=2){if(!e)return``;let n=e.replace(/\/+$/,``).split(`/`);return n.length<=t?e:n.slice(-t).join(`/`)}function x(e){return e.trim().replace(/\\/g,`/`).replace(/\/+$/,``)||`/`}function ce(e,t){if(!e?.trim()||!t?.trim())return!1;let n=x(e),r=x(t);return r===`/`?n.startsWith(`/`):n===`/`?!1:n===r||n.startsWith(r+`/`)}function S(e){return e?.meta?.builtin===!0||e?.id===`user`||e?.id===`system`}function C(e){let t=e?.tags||[],n=e?.capabilities||[],r=typeof e?.meta?.policyName==`string`?e.meta.policyName:``;return e?.kind===`channel`||e?.meta?.kind===`channel`||t.includes(`channel`)||t.some(e=>e.startsWith(`channel:`))||n.includes(`channel`)||n.some(e=>e.startsWith(`channel:`))||t.includes(`telegram`)||n.includes(`telegram`)||r===`telegram-main`}function w(e){return!!(typeof e?.meta?.automationId==`string`||typeof e?.meta?.automationRunId==`string`||e?.tags?.includes(`automation`))}function T(e){return S(e)||C(e)||w(e)}function E(e){if(e?.id===`user`)return`user`;if(e?.id===`system`)return`system`;if(C(e))return`channel`;let t=n(),r=typeof e?.meta?.provider==`string`?e.meta.provider.toLowerCase():void 0;if(r&&t.includes(r))return r;let i=[...e?.tags||[],e?.meta?.client,e?.meta?.runtime,e?.meta?.agentType].filter(e=>typeof e==`string`).map(e=>e.toLowerCase());for(let e of t)if(i.some(t=>t.includes(e)))return e;return`agent`}function D(e,t){if(!t?.lastSeen||t.status===`offline`||t.id===`user`||t.id===`system`)return!1;let n=t.meta?.transport;if(i(n)&&n.connected===!0)return!1;let r=new Date(t.lastSeen).getTime();return Number.isFinite(r)?e-r>6e4:!1}function O(e,t){if(!e||S(e)||C(e)||t===`resume`)return!1;if(t===`interrupt`)return e.providerCapabilities?.liveSession?.interrupt===!0&&e.status===`busy`;if(A(e)&&(t===`restart`||t===`shutdown`||t===`compact`||t===`clearContext`)&&!k(e))return!1;let n=e.providerCapabilities?.lifecycle;if(n){if(t===`restart`)return n.restartHard===!0;if(t===`shutdown`)return n.shutdownHard===!0;if(t===`reconnect`)return n.reconnect===!0}return t===`compact`?e.providerCapabilities?.context?.compact===!0:t===`clearContext`?e.providerCapabilities?.context?.clear===!0:e.meta?.runnerManaged===!0&&(t===`restart`||t===`shutdown`)}function k(e){return typeof e.meta?.tmuxSession==`string`&&e.meta.tmuxSession.trim().length>0}function A(e){return(typeof e?.meta?.provider==`string`?o(e.meta.provider):void 0)?.capabilityDefaults?.terminal?.mode===`live`}function j(e){return O(e,`restart`)||O(e,`shutdown`)||O(e,`reconnect`)||O(e,`compact`)||O(e,`clearContext`)}function M(e){return!!(e&&!S(e)&&!C(e)&&!j(e)&&(e.status===`offline`||e.status===`stale`))}function N(e,t){if(e.status!==`offline`)return!1;let n=typeof e.meta?.policyName==`string`?e.meta.policyName:``;if(!n)return!1;let r=t.find(e=>e.policy.name===n);return!!(r?.state.agentId&&r.state.agentId!==e.id)}function P(e,t,n=[]){let r=e.filter(e=>!N(e,n));return t?r:r.filter(e=>!T(e))}function F(e){return e?e.label||e.name||e.id.slice(-12):`?`}function I(e,t){let n=r(e);return n?t[n]:void 0}function L(e,t){let n=I(e,t);return n?.displayName?.trim()||n?.handle?.trim()||`User`}var R=[`text-sky-300`,`text-amber-300`,`text-emerald-300`,`text-violet-300`,`text-rose-300`,`text-cyan-300`];function z(e){let t=r(e)||``,n=0;for(let e=0;e<t.length;e++)n=n*31+t.charCodeAt(e)>>>0;return R[n%R.length]}function B(e,t){if(!e)return`?`;if(e===`broadcast`)return`broadcast`;if(e.startsWith(`tag:`))return`#`+e.slice(4);if(e.startsWith(`cap:`))return e.slice(4);if(e.startsWith(`label:`))return e.slice(6);if(e.startsWith(`team:`)){let n=e.slice(5),r=Object.values(t).find(e=>e.teamId===n);return r?`team:${F(r)}`:`team:${n.slice(-8)}`}let n=t[e];return n?F(n):e.slice(-8)}function V(e){if(!e)return``;let t=e.payload||{},n=t.message;if(n&&typeof n==`object`&&typeof n.text==`string`&&n.text.trim())return n.text;let r=t.interaction;if(r&&typeof r==`object`){let e=typeof r.title==`string`?r.title.trim():``,t=typeof r.description==`string`?r.description.trim():``;if(e&&t)return e+`
|
|
2
|
+
`+t;if(e)return e;if(t)return t}let i=t.reaction;if(i&&typeof i==`object`){let e=typeof i.name==`string`?i.name:``,t=typeof i.emoji==`string`?i.emoji:``,n=typeof i.value==`string`?i.value:``;return[`Reaction`,b(t||e||n)].filter(Boolean).join(`: `)}let a=t.activity;return a&&typeof a==`object`?[typeof a.kind==`string`?a.kind:`activity`,typeof a.state==`string`?a.state:``].filter(Boolean).join(` `):typeof t.text==`string`&&t.text.trim()?t.text:typeof t.message==`string`&&t.message.trim()?t.message:W(e.body||``)??(e.body||``)}function H(e){if(!e?.payload)return!1;let t=e.payload.event;return e.payload.reactionNotification===!0||t?.type===`message.reaction`}function U(e){if(!e)return null;let t=e.trim();if(!t.startsWith(`{`))return null;try{let e=JSON.parse(t);if(typeof e!=`object`||!e||Array.isArray(e))return null;let n=typeof e.text==`string`?e.text:typeof e.message==`string`?e.message:null;if(!n?.trim())return null;let r=new Set([`text`,`message`]);return{text:n,meta:Object.entries(e).filter(([e,t])=>!r.has(e)&&(typeof t==`string`||typeof t==`number`||typeof t==`boolean`)).map(([e,t])=>[e,String(t)]),raw:e}}catch{return null}}function W(e){return U(e)?.text??null}function G(e){let t=e?.subject||V(e)||``;return t.length>90?t.slice(0,90)+`...`:t}function le(e){return t(e.from)&&e.to?e.to:t(e.to)&&e.from?e.from:``}function K(e){return t(e.to)&&!t(e.from)}function ue(e){if(e.kind!==`session`)return!1;let t=e.payload?.session?.type;return t===`reasoning`||t===`tool`}function q(e){return e.kind===`session`&&a(e.payload)}function de(e,t){let n=e.trim(),r=t.trim();return r?n===r?!0:n.startsWith(`${r}\n\n`)||n.endsWith(`\n\n${r}`)||n.includes(`\n\n${r}\n\n`):!1}function fe(e,t,n){if(!K(n)||!q(n)||(n.readBy||[]).includes(`user`))return!1;let r=Number(e[t]||0);return n.id>(Number.isFinite(r)?r:0)}function pe(e){return(e.kind??`claim`)===`claim`&&ee.has(e.status)&&!e.claimedBy}function me(e){return!!(e.claimable&&!e.claimedBy&&!(e.kind===`task`&&Number.isSafeInteger(e.payload?.taskId)))}function he(e,t){return!e||!t?!1:e===`broadcast`||e===t.id?!0:e.startsWith(`tag:`)?(t.tags||[]).includes(e.slice(4)):e.startsWith(`cap:`)?(t.capabilities||[]).includes(e.slice(4)):e.startsWith(`label:`)?t.label===e.slice(6):e.startsWith(`team:`)?t.teamId===e.slice(5):!1}function ge(e,t){return e?t.from===e||t.to===e||t.resolvedToAgent===e:!1}function _e(e,t){if(!e||!t)return!1;let n=[t.id,t.type,...t.topicChannels||[]].filter(Boolean);if(e.channel&&n.includes(e.channel))return!0;let r=e.payload?.channel;if(r&&typeof r==`object`){let e=[r.agentId,r.provider,r.accountId].filter(Boolean);if(e.includes(t.id)||e.includes(t.type)||t.accountId&&e.includes(t.accountId))return!0}return!!(t.agentId&&(e.from===t.agentId||e.to===t.agentId))}function J(e){let t=e?.meta?.providerState;return!i(t)||typeof t.state!=`string`?null:{state:t.state,reason:typeof t.reason==`string`?t.reason:void 0,label:typeof t.label==`string`&&t.label?t.label:t.state,recommendedAction:typeof t.recommendedAction==`string`?t.recommendedAction:void 0,source:typeof t.source==`string`?t.source:void 0,raw:t.raw,updatedAt:typeof t.updatedAt==`number`?t.updatedAt:void 0,pendingApproval:ve(t.pendingApproval)}}function ve(e){if(!i(e)||typeof e.id!=`string`)return;let t=Array.isArray(e.choices)?e.choices.filter(i).map(e=>({id:e.id,label:typeof e.label==`string`?e.label:String(e.id||``)})).filter(e=>(e.id===`approve`||e.id===`approve-session`||e.id===`deny`||e.id===`abort`)&&!!e.label):[],n=Array.isArray(e.questions)?e.questions.filter(i).map(e=>({question:typeof e.question==`string`?e.question:``,header:typeof e.header==`string`?e.header:void 0,multiSelect:e.multiSelect===!0,options:Array.isArray(e.options)?e.options.filter(i).map(e=>({label:typeof e.label==`string`?e.label:String(e.label??``),description:typeof e.description==`string`?e.description:void 0})).filter(e=>!!e.label):[]})).filter(e=>!!e.question&&e.options.length>0):void 0;return{id:e.id,provider:typeof e.provider==`string`?e.provider:void 0,kind:typeof e.kind==`string`?e.kind:void 0,title:typeof e.title==`string`&&e.title?e.title:`Permission request`,body:typeof e.body==`string`?e.body:``,choices:t,...n&&n.length?{questions:n}:{}}}function Y(e){let t=J(e);return t?.state===`blocked`?t:null}function ye(e){return!!e?.id}function be(e){return ye(Y(e)?.pendingApproval)}function X(e){let t=e?.meta?.activeSubagents;if(!Array.isArray(t)){let t=typeof e?.meta?.activeSubagentCount==`number`?e.meta.activeSubagentCount:0;return t>0?Array.from({length:t},(e,t)=>({id:`subagent-${t+1}`,label:`Subagent ${t+1}`})):[]}return t.filter(i).map((e,t)=>{let n=typeof e.id==`string`&&e.id?e.id:`subagent-${t+1}`,r=typeof e.role==`string`&&e.role?e.role:void 0;return{id:n,label:typeof e.label==`string`&&e.label?e.label:r||n,role:r,startedAt:typeof e.startedAt==`number`?e.startedAt:void 0}})}function Z(e){let t=e?.meta?.activeWork;if(!Array.isArray(t))return null;let n=t.find(e=>i(e)&&e.kind===`background-script`);return!n||!i(n)?null:typeof n.label==`string`&&n.label?n.label:`background script`}function xe(e,t,n,r){let i=typeof t?.meta?.lifecycleAction==`string`?t.meta.lifecycleAction:``,a=D(e,t),o=t?.status!==`offline`&&!t?.ready&&a,s=t?.status!==`offline`&&!t?.ready&&!a,c=n.unread>0&&t?.status!==`busy`,l=Y(t),u=Se(t,n,r);if(t?.status===`offline`)return{label:`offline`,tone:`secondary`,icon:`PlugZap`,stale:!1,reconnecting:!1,badges:u};if(i.startsWith(`finalizing-`))return{label:`wrapping up (${i.slice(11)})`,tone:`warning`,icon:`Hourglass`,stale:a,reconnecting:o,badges:u};if(i===`shutting-down`)return{label:`shutting down`,tone:`warning`,icon:`Power`,stale:a,reconnecting:o,badges:u};if(i===`killing`)return{label:`killing`,tone:`danger`,icon:`Power`,stale:a,reconnecting:o,badges:u};if(i===`restarting`)return{label:`restarting`,tone:`warning`,icon:`RefreshCw`,stale:a,reconnecting:o,badges:u};if(t?.status===`stale`)return{label:`stale`,tone:`danger`,icon:`RefreshCw`,stale:!0,reconnecting:!0,badges:u};if(o)return{label:`reconnecting`,tone:`danger`,icon:`RefreshCw`,stale:a,reconnecting:o,badges:u};if(s)return{label:`online, not ready`,tone:`warning`,icon:`Loader`,stale:a,reconnecting:o,badges:u};if(l)return{label:`blocked: ${l.label}`,tone:`danger`,icon:`AlertCircle`,stale:a,reconnecting:o,badges:u};if(t?.status===`busy`){let e=Array.isArray(t?.meta?.busyReasons)?t.meta.busyReasons:[];return Z(t)&&!e.includes(`provider-turn`)&&!e.includes(`subagent`)?{label:`running background work`,tone:`warning`,icon:`Play`,stale:a,reconnecting:o,badges:u}:{label:`busy in turn`,tone:`warning`,icon:`Play`,stale:a,reconnecting:o,badges:u}}return r?.status===`active`?{label:`paired`,tone:`success`,icon:`Link`,stale:a,reconnecting:o,badges:u}:c?{label:`idle, unread`,tone:`danger`,icon:`Bell`,stale:a,reconnecting:o,badges:u}:{label:t?.status===`idle`?`idle`:`ready`,tone:`success`,icon:`CircleCheck`,stale:a,reconnecting:o,badges:u}}function Se(e,t,n){let r=[],i=Y(e),a=X(e).length;i&&r.push({label:i.reason?`blocked: ${i.reason}`:`blocked`,className:`bg-red-500/20 text-red-400`}),a&&r.push({label:a===1?`1 subagent`:a+` subagents`,className:`bg-cyan-500/20 text-cyan-300`});let o=Z(e);return o&&r.push({label:o,className:`bg-indigo-500/20 text-indigo-300`}),n?.status===`active`&&r.push({label:`paired`,className:`bg-emerald-500/20 text-emerald-400`}),n?.status===`pending`&&r.push({label:`pair invite`,className:`bg-yellow-500/20 text-yellow-400`}),t.needsHumanResponse&&r.push({label:`needs response`,className:`bg-amber-500/20 text-amber-300`}),t.unread&&r.push({label:t.unread+` unread`,className:`bg-red-500/20 text-red-400`}),t.claimableTasks&&r.push({label:t.claimableTasks+` claimable`,className:`bg-orange-500/20 text-orange-400`}),r}function Ce(){return{unread:0,needsHumanResponse:!1,pendingPairInvite:!1,claimableTasks:0,total:0,score:0}}function Q(e){return!e||e.status===`offline`?!1:e.targetHealth?.status===`ok`?!0:e.targetHealth?.status===`error`||e.targetHealth?.status===`warning`?!1:e.ready}function we(e){return e?e.targetHealth?.status===`error`?{label:`target broken`,tone:`danger`,icon:`AlertTriangle`,badges:[]}:e.targetHealth?.status===`warning`?{label:`target warning`,tone:`warning`,icon:`AlertCircle`,badges:[]}:e.status===`offline`?{label:`offline`,tone:`secondary`,icon:`PlugZap`,badges:[]}:e.status===`busy`?{label:`busy`,tone:`warning`,icon:`Activity`,badges:[]}:Q(e)?{label:`ready`,tone:`success`,icon:`CircleCheck`,badges:[]}:{label:`not ready`,tone:`warning`,icon:`Loader`,badges:[]}:{label:`unknown`,tone:`secondary`,icon:`PlugZap`,badges:[]}}function Te(e){let t=e?.runtime||{};return t.status===`error`?{label:`error`,tone:`danger`,icon:`AlertTriangle`,badges:[]}:t.status===`warn`?{label:`warning`,tone:`warning`,icon:`AlertCircle`,badges:[]}:t.running?{label:`running`,tone:`success`,icon:`CircleCheck`,badges:[]}:t.enabled===!1?{label:`disabled`,tone:`secondary`,icon:`Pause`,badges:[]}:t.status===`ok`?{label:`ok`,tone:`success`,icon:`CircleCheck`,badges:[]}:{label:`unknown`,tone:`secondary`,icon:`HelpCircle`,badges:[]}}function Ee(e){let t=e?.taskStats||{};return(t.waitingTasks||0)>0?{label:`waiting`,tone:`warning`,icon:`AlertCircle`,badges:[]}:(t.openTasks||0)>0?{label:`active`,tone:`info`,icon:`Activity`,badges:[]}:e?.configured?e.observed?{label:`quiet`,tone:`success`,icon:`CircleCheck`,badges:[]}:{label:`configured`,tone:`primary`,icon:`PlugZap`,badges:[]}:{label:`observed only`,tone:`secondary`,icon:`Eye`,badges:[]}}function De(e){let t=e?.health;return!t||t.status===`ok`?e?.version||e?.package?.version?`compatible`:`unknown version`:t.status===`upgrade-required`?`upgrade required`:t.status===`restart-required`?`restart required`:t.status===`unknown`?`unknown contract`:(t.issues||[]).some(e=>e.code===`protocol-mismatch`)?`protocol mismatch`:(t.issues||[]).some(e=>e.code===`package-drift`)?`package drift`:t.restartRequired?`restart required`:t.status}function $(e){let t=e?.health?.status;return t===`upgrade-required`?`text-red-400 bg-red-500/10`:t===`warn`||t===`restart-required`?`text-yellow-400 bg-yellow-500/10`:t===`unknown`?`text-zinc-400 bg-zinc-500/10`:`text-emerald-400 bg-emerald-500/10`}function Oe(e,t){if(!t)return``;let n=new Date(t).getTime();if(!Number.isFinite(n))return``;let r=Math.max(0,(e-n)/1e3);return r<60?Math.floor(r)+`s ago`:r<3600?Math.floor(r/60)+`m ago`:r<86400?Math.floor(r/3600)+`h ago`:Math.floor(r/86400)+`d ago`}function ke(e){return e?new Date(e).toLocaleString():``}function Ae(e){return String(e||`export`).replace(/[^a-z0-9._-]+/gi,`-`).replace(/^-+|-+$/g,``).slice(0,80)||`export`}function je(e){return e.filter(e=>e.status!==`ok`).map(e=>{let t={name:e.name,status:e.status,detail:e.detail||e.name,impact:Me(e),subjects:e.subjects||[],actions:[{label:`Inspect logs`,icon:`FileSearch`,copy:`agent-relay daemon logs`},{label:`Restart daemon`,icon:`RefreshCw`,copy:`agent-relay daemon restart`},{label:`Copy env`,icon:`Copy`,copy:`agent-relay doctor`}]};return e.name===`stale-live-agents`?t.actions.unshift({label:`Run reaper`,icon:`Eraser`,api:`POST`,path:`/system/reap`},{label:`Show stale`,icon:`Filter`,view:`agents`,preset:`offline_stale`}):e.name===`channel-delivery-targets`?t.actions.unshift({label:`Open channels`,icon:`MessagesSquare`,view:`channels`},{label:`Run reaper`,icon:`Eraser`,api:`POST`,path:`/system/reap`}):[`expired-message-claims`,`expired-task-claims`,`offline-claimed-tasks`].includes(e.name)&&t.actions.unshift({label:`Run reaper`,icon:`Eraser`,api:`POST`,path:`/system/reap`},{label:`Open work`,icon:`ListChecks`,view:`work`}),t})}function Me(e){return{database:`Relay persistence is unavailable; messages, state, and audit writes may fail.`,"stale-live-agents":`Agents may look online even though their heartbeat has stopped.`,"expired-message-claims":`Claimable messages may be stuck until the reaper releases expired claims.`,"expired-task-claims":`Tasks can appear owned by agents that no longer hold a live lease.`,"offline-claimed-tasks":`Offline agents are still shown as owners for active work.`,"channel-delivery-targets":`Inbound channel messages may be accepted but routed to no live delivery agent.`}[e.name]||`Relay health is degraded for this check.`}function Ne(e){return{success:`text-emerald-400`,warning:`text-yellow-400`,danger:`text-red-400`,info:`text-blue-400`,primary:`text-blue-400`,secondary:`text-zinc-400`}[e]||`text-zinc-400`}function Pe(e,t){return!e||e.status===`offline`?`bg-zinc-500 opacity-50`:typeof e.meta?.lifecycleAction==`string`&&e.meta.lifecycleAction.startsWith(`finalizing-`)?`bg-amber-500 animate-pulse`:e.meta?.lifecycleAction===`shutting-down`||e.meta?.lifecycleAction===`restarting`?`bg-yellow-500 animate-pulse`:e.meta?.lifecycleAction===`killing`||Y(e)?`bg-red-500 animate-pulse`:e.status===`busy`?`bg-yellow-500`:t&&D(t,e)?`bg-red-500 animate-pulse`:e.ready?`bg-emerald-500 shadow-[0_0_6px_theme(colors.emerald.500)]`:`bg-emerald-500 animate-pulse`}function Fe(e,t,n){if(typeof document>`u`||typeof URL>`u`||typeof Blob>`u`)return;let r=URL.createObjectURL(new Blob([t],{type:n})),i=document.createElement(`a`);i.href=r,i.download=e,i.click(),URL.revokeObjectURL(r)}export{f as $,ge as A,J as B,me as C,ue as D,H as E,$ as F,Pe as G,de as H,De as I,Ne as J,Oe as K,U as L,G as M,x as N,fe as O,b as P,u as Q,ce as R,q as S,K as T,Ae as U,I as V,se as W,P as X,oe as Y,d as Z,z as _,O as a,l as at,Ee as b,we as c,y as ct,F as d,p as et,B as f,je as g,ke as h,xe as i,c as it,_e as j,V as k,Te as l,te as lt,Ce as m,M as n,m as nt,E as o,v as ot,Fe as p,re as q,be as r,s as rt,Q as s,ne as st,X as t,h as tt,he as u,L as v,pe as w,D as x,le as y,Y as z};
|
|
3
|
+
//# sourceMappingURL=display-aTnwsqQh.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"display-GFbGUG0O.js","names":[],"sources":["../../dashboard/src/lib/constants.ts","../../dashboard/src/lib/display.ts"],"sourcesContent":["import type { ComposeState, InboxComposeState, PairMessageState, PairInviteState, ViewName } from '@/types'\n\nconst PREF_PREFIX = 'ar-'\nexport const HUMAN_AGENT_ID = 'user'\nexport const INBOX_OPERATOR_ID = HUMAN_AGENT_ID\nexport const LIVE_REFRESH_MS = 5_000\n// Max live messages retained in memory. Must be >= the largest fetch limit\n// (chat view fetches 300) so SSE appends never trim already-loaded history.\nexport const MESSAGE_BUFFER_CAP = 500\n\nexport const CLOSED_TASK_STATUSES = new Set(['done', 'failed', 'canceled'])\nexport const WAITING_TASK_STATUSES = new Set(['open', 'blocked'])\n\nexport const STATUS_SORT_ORDER: Record<string, number> = { online: 0, idle: 0, busy: 2, offline: 3 }\nexport const CHAT_STATUS_SORT_ORDER: Record<string, number> = { idle: 0, online: 0, busy: 2, offline: 4 }\n\nexport const DEFAULT_COMPOSE: ComposeState = { from: '', to: '', body: '', channel: '', subject: '', claimable: false }\nexport const DEFAULT_INBOX_COMPOSE: InboxComposeState = { toMode: 'agent', to: '', body: '', channel: '', subject: '', claimable: false }\nexport const DEFAULT_PAIR_MESSAGE: PairMessageState = { pairId: '', from: '', body: '', subject: '' }\nexport const DEFAULT_PAIR_INVITE: PairInviteState = { requesterId: '', targetId: '', objective: '' }\n\n\nimport { getKnownProviderIds, getProviderLabel } from './provider-display'\n\nconst SYSTEM_TYPE_ICONS: Record<string, string> = {\n user: 'User',\n system: 'Server',\n channel: 'MessagesSquare',\n agent: 'Bot',\n}\n\nconst SYSTEM_TYPE_TITLES: Record<string, string> = {\n user: 'Human operator',\n system: 'System',\n channel: 'Channel',\n agent: 'Agent',\n}\n\nexport const AGENT_TYPE_ICONS: Record<string, string> = {\n ...SYSTEM_TYPE_ICONS,\n ...Object.fromEntries(getKnownProviderIds().map((id) => [id, 'Bot'])),\n}\n\nexport const AGENT_TYPE_TITLES: Record<string, string> = {\n ...SYSTEM_TYPE_TITLES,\n ...Object.fromEntries(getKnownProviderIds().map((id) => [id, `${getProviderLabel(id)} agent`])),\n}\n\nexport const NAV_ITEMS: Array<{ key: ViewName; label: string; icon: string }> = [\n { key: 'overview', label: 'Overview', icon: 'LayoutDashboard' },\n { key: 'chat', label: 'Chat', icon: 'MessageCircle' },\n { key: 'agents', label: 'Agents', icon: 'Bot' },\n { key: 'managed', label: 'Managed Agents', icon: 'Workflow' },\n { key: 'teams', label: 'Teams', icon: 'Users' },\n { key: 'profiles', label: 'Agent Profiles', icon: 'UserCog' },\n { key: 'orchestrators', label: 'Orchestrators', icon: 'Server' },\n { key: 'workspaces', label: 'Workspaces', icon: 'GitBranch' },\n { key: 'files', label: 'Files', icon: 'FolderTree' },\n { key: 'channels', label: 'Channels', icon: 'MessagesSquare' },\n { key: 'connectors', label: 'Connectors', icon: 'Plug' },\n { key: 'integrations', label: 'Integrations', icon: 'PlugZap' },\n { key: 'security', label: 'Security', icon: 'Shield' },\n { key: 'memory', label: 'Memory', icon: 'BrainCircuit' },\n { key: 'activity', label: 'Activity', icon: 'Activity' },\n { key: 'pairs', label: 'Pairs', icon: 'Link' },\n { key: 'messages', label: 'Messages', icon: 'Mail' },\n { key: 'work', label: 'Work Queue', icon: 'ListChecks' },\n { key: 'tasks', label: 'Tasks', icon: 'ClipboardList' },\n { key: 'automation', label: 'Automation', icon: 'CalendarClock' },\n { key: 'analytics', label: 'Analytics', icon: 'AreaChart' },\n { key: 'insights', label: 'Insights', icon: 'Lightbulb' },\n { key: 'projects', label: 'Projects', icon: 'Boxes' },\n { key: 'prompts', label: 'Prompts', icon: 'FileText' },\n { key: 'registry', label: 'Registry', icon: 'PackagePlus' },\n { key: 'maintenance', label: 'Maintenance', icon: 'Wrench' },\n { key: 'settings', label: 'Settings', icon: 'Settings' },\n]\n\nexport const SEVERITY_COLORS: Record<string, string> = {\n critical: 'text-red-400 bg-red-500/10',\n warning: 'text-yellow-400 bg-yellow-500/10',\n info: 'text-blue-400 bg-blue-500/10',\n}\n\nexport const PAIR_STATUS_COLORS: Record<string, string> = {\n active: 'bg-emerald-500/20 text-emerald-400',\n pending: 'bg-yellow-500/20 text-yellow-400',\n ended: 'bg-zinc-500/20 text-zinc-400',\n rejected: 'bg-red-500/20 text-red-400',\n expired: 'bg-red-500/20 text-red-400',\n}\n","import type {\n Agent, Message, PairSession, Task, ChannelSummary, ConnectorSummary,\n IntegrationSummary, Orchestrator, AgentType, PresenceInfo, PresenceBadge,\n AttentionInfo, InboxThread, HealthCheck, HealthDiagnostic, ManagedPolicyHealth,\n} from '@/types'\nimport type { User } from '@/types'\nimport { HUMAN_AGENT_ID, AGENT_TYPE_ICONS, AGENT_TYPE_TITLES, WAITING_TASK_STATUSES } from './constants'\nimport { getKnownProviderIds, getProviderManifest } from './provider-display'\nimport { isRecord, isHumanAgentId, isWorkFinalMessagePayload, userIdFromAddress } from 'agent-relay-sdk/types'\n\nexport function toTimestamp(value: unknown): number {\n const ts = typeof value === 'number' ? value : new Date((value as string) || 0).getTime()\n return Number.isFinite(ts) ? ts : 0\n}\n\nconst INTERNAL_CAP_PREFIXES = ['lifecycle.', 'commands.', 'capabilities.']\n\nconst REACTION_EMOJI_ALIASES: Record<string, string> = {\n '+1': '👍',\n ':+1:': '👍',\n thumbsup: '👍',\n ':thumbsup:': '👍',\n 'thumbs-up': '👍',\n ':thumbs-up:': '👍',\n thumbs_up: '👍',\n ':thumbs_up:': '👍',\n thumb_up: '👍',\n ':thumb_up:': '👍',\n like: '👍',\n ':like:': '👍',\n heart: '❤️',\n ':heart:': '❤️',\n redheart: '❤️',\n red_heart: '❤️',\n ':red_heart:': '❤️',\n check: '✅',\n ':check:': '✅',\n checkmark: '✅',\n ':checkmark:': '✅',\n white_check_mark: '✅',\n ':white_check_mark:': '✅',\n eyes: '👀',\n ':eyes:': '👀',\n}\n\nexport function normalizeReactionEmoji(value: string): string {\n const trimmed = value.trim()\n return REACTION_EMOJI_ALIASES[trimmed.toLowerCase()] ?? trimmed\n}\n\nexport function userFacingCapabilities(caps: string[]): string[] {\n return caps.filter((c) => !INTERNAL_CAP_PREFIXES.some((p) => c.startsWith(p)))\n}\n\nexport function shortPath(cwd: string | undefined | null, segments = 2): string {\n if (!cwd) return ''\n const parts = cwd.replace(/\\/+$/, '').split('/')\n return parts.length <= segments ? cwd : parts.slice(-segments).join('/')\n}\n\nexport function normalizePathForCompare(path: string): string {\n return path.trim().replace(/\\\\/g, '/').replace(/\\/+$/, '') || '/'\n}\n\nexport function pathWithinBase(path: string | undefined | null, baseDir: string | undefined | null): boolean {\n if (!path?.trim() || !baseDir?.trim()) return false\n const normalizedPath = normalizePathForCompare(path)\n const normalizedBase = normalizePathForCompare(baseDir)\n if (normalizedBase === '/') return normalizedPath.startsWith('/')\n if (normalizedPath === '/') return false\n return normalizedPath === normalizedBase || normalizedPath.startsWith(normalizedBase + '/')\n}\n\nfunction isBuiltInAgent(agent: Agent | null | undefined): boolean {\n return agent?.meta?.builtin === true || agent?.id === HUMAN_AGENT_ID || agent?.id === 'system'\n}\n\nfunction isChannelAgent(agent: Agent | null | undefined): boolean {\n const tags = agent?.tags || []\n const caps = agent?.capabilities || []\n const policyName = typeof agent?.meta?.policyName === 'string' ? agent.meta.policyName : ''\n return agent?.kind === 'channel' ||\n agent?.meta?.kind === 'channel' ||\n tags.includes('channel') ||\n tags.some((tag) => tag.startsWith('channel:')) ||\n caps.includes('channel') ||\n caps.some((cap) => cap.startsWith('channel:')) ||\n tags.includes('telegram') ||\n caps.includes('telegram') ||\n policyName === 'telegram-main'\n}\n\nfunction isAutomationAgent(agent: Agent | null | undefined): boolean {\n return Boolean(\n typeof agent?.meta?.automationId === 'string' ||\n typeof agent?.meta?.automationRunId === 'string' ||\n agent?.tags?.includes('automation')\n )\n}\n\nfunction isSystemAgent(agent: Agent | null | undefined): boolean {\n return isBuiltInAgent(agent) || isChannelAgent(agent) || isAutomationAgent(agent)\n}\n\nexport function agentType(agent: Agent | null | undefined): AgentType {\n if (agent?.id === HUMAN_AGENT_ID) return 'user'\n if (agent?.id === 'system') return 'system'\n if (isChannelAgent(agent)) return 'channel'\n\n const knownProviders = getKnownProviderIds()\n\n // #417: check the authoritative provider field first (exact match) so a name or id\n // containing a provider name as a substring can't mislabel the agent.\n const provider = typeof agent?.meta?.provider === 'string' ? agent.meta.provider.toLowerCase() : undefined\n if (provider && knownProviders.includes(provider)) return provider as AgentType\n\n // Fallback heuristic for agents registered without meta.provider. Only scan tags\n // and meta fields — not id or name, which are free-text and cause false positives.\n const values = [\n ...(agent?.tags || []),\n agent?.meta?.client as string,\n agent?.meta?.runtime as string,\n agent?.meta?.agentType as string,\n ]\n .filter((v): v is string => typeof v === 'string')\n .map((v) => v.toLowerCase())\n\n for (const pid of knownProviders) {\n if (values.some((v) => v.includes(pid))) return pid as AgentType\n }\n return 'agent'\n}\n\nfunction agentTypeIcon(agent: Agent | null | undefined): string {\n return AGENT_TYPE_ICONS[agentType(agent)] ?? AGENT_TYPE_ICONS.agent ?? 'ti-robot'\n}\n\nfunction agentTypeTitle(agent: Agent | null | undefined): string {\n return AGENT_TYPE_TITLES[agentType(agent)] ?? AGENT_TYPE_TITLES.agent ?? 'Agent'\n}\n\nexport function isAgentStale(now: number, agent: Agent | null | undefined): boolean {\n if (!agent?.lastSeen || agent.status === 'offline') return false\n if (agent.id === 'user' || agent.id === 'system') return false\n // A live bus connection is authoritative liveness: an idle-but-connected agent\n // is reachable, not stale, even if lastSeen has aged (e.g. heartbeat keepalive\n // gaps while idle). Genuine death flips transport.connected to false (or the\n // server reaps the agent offline), at which point the lastSeen check applies.\n const transport = agent.meta?.transport\n if (isRecord(transport) && transport.connected === true) return false\n const lastSeenMs = new Date(agent.lastSeen as string).getTime()\n if (!Number.isFinite(lastSeenMs)) return false\n return now - lastSeenMs > 60_000\n}\n\nexport type AgentControlAction = 'restart' | 'shutdown' | 'reconnect' | 'compact' | 'clearContext' | 'resume' | 'interrupt'\n\nexport function agentSupportsControlAction(agent: Agent | null | undefined, action: AgentControlAction): boolean {\n if (!agent || isBuiltInAgent(agent) || isChannelAgent(agent)) return false\n if (action === 'resume') return false\n // Interrupt is provider-independent and only meaningful while the agent is actually mid-turn.\n if (action === 'interrupt') return agent.providerCapabilities?.liveSession?.interrupt === true && agent.status === 'busy'\n const needsTmux = providerUsesLiveTerminal(agent) && (action === 'restart' || action === 'shutdown' || action === 'compact' || action === 'clearContext')\n if (needsTmux && !agentHasTmuxSession(agent)) return false\n const lifecycle = agent.providerCapabilities?.lifecycle\n if (lifecycle) {\n if (action === 'restart') return lifecycle.restartHard === true\n if (action === 'shutdown') return lifecycle.shutdownHard === true\n if (action === 'reconnect') return lifecycle.reconnect === true\n }\n if (action === 'compact') return agent.providerCapabilities?.context?.compact === true\n if (action === 'clearContext') return agent.providerCapabilities?.context?.clear === true\n return agent.meta?.runnerManaged === true && (action === 'restart' || action === 'shutdown')\n}\n\nfunction agentHasTmuxSession(agent: Agent): boolean {\n return typeof agent.meta?.tmuxSession === 'string' && agent.meta.tmuxSession.trim().length > 0\n}\n\nfunction providerUsesLiveTerminal(agent: Agent | null | undefined): boolean {\n const manifest = typeof agent?.meta?.provider === 'string' ? getProviderManifest(agent.meta.provider as string) : undefined\n return manifest?.capabilityDefaults?.terminal?.mode === 'live'\n}\n\nfunction agentSupportsControlActions(agent: Agent | null | undefined): boolean {\n return agentSupportsControlAction(agent, 'restart') ||\n agentSupportsControlAction(agent, 'shutdown') ||\n agentSupportsControlAction(agent, 'reconnect') ||\n agentSupportsControlAction(agent, 'compact') ||\n agentSupportsControlAction(agent, 'clearContext')\n}\n\nexport function agentCanBeForgotten(agent: Agent | null | undefined): boolean {\n return Boolean(agent && !isBuiltInAgent(agent) && !isChannelAgent(agent) && !agentSupportsControlActions(agent) && (agent.status === 'offline' || agent.status === 'stale'))\n}\n\nfunction isRetiredManagedRuntimeAgent(agent: Agent, managedPolicies: ManagedPolicyHealth[]): boolean {\n if (agent.status !== 'offline') return false\n const policyName = typeof agent.meta?.policyName === 'string' ? agent.meta.policyName : ''\n if (!policyName) return false\n const policy = managedPolicies.find((item) => item.policy.name === policyName)\n return Boolean(policy?.state.agentId && policy.state.agentId !== agent.id)\n}\n\nexport function visibleAgents(agents: Agent[], showBuiltIns: boolean, managedPolicies: ManagedPolicyHealth[] = []): Agent[] {\n const activeRuntimeAgents = agents.filter((a) => !isRetiredManagedRuntimeAgent(a, managedPolicies))\n return showBuiltIns ? activeRuntimeAgents : activeRuntimeAgents.filter((a) => !isSystemAgent(a))\n}\n\nexport function displayName(agent: Agent | null | undefined): string {\n if (!agent) return '?'\n return agent.label || agent.name || agent.id.slice(-12)\n}\n\n// Human attribution (#390). Resolve a human message address (`user` / `user:<id>`) to its\n// users-table row, or undefined for a non-human address / unknown id. The single bridge from\n// a wire address → a user record on the client, mirroring the SDK resolver on the server.\nexport function resolveUser(address: string | undefined, usersById: Record<string, User>): User | undefined {\n const userId = userIdFromAddress(address)\n return userId ? usersById[userId] : undefined\n}\n\n// Name to show for a human address. Prefers the user's displayName, then handle, then a\n// generic 'User' so a not-yet-loaded directory (or the seeded default) still reads sensibly —\n// which keeps today's single operator rendering exactly as before.\nexport function humanDisplayName(address: string | undefined, usersById: Record<string, User>): string {\n const user = resolveUser(address, usersById)\n return user?.displayName?.trim() || user?.handle?.trim() || 'User'\n}\n\n// Deterministic accent color per human so multiple operators are visually distinguishable in\n// one thread. Stable for a given user id; the single default operator never needs it (callers\n// only apply this once more than one human exists, preserving back-compat styling).\nconst HUMAN_ACCENT_CLASSES = [\n 'text-sky-300', 'text-amber-300', 'text-emerald-300', 'text-violet-300', 'text-rose-300', 'text-cyan-300',\n]\nexport function humanAccentClass(address: string | undefined): string {\n const userId = userIdFromAddress(address) || ''\n let hash = 0\n for (let i = 0; i < userId.length; i++) hash = (hash * 31 + userId.charCodeAt(i)) >>> 0\n return HUMAN_ACCENT_CLASSES[hash % HUMAN_ACCENT_CLASSES.length]!\n}\n\nexport function displayTarget(target: string, agentsById: Record<string, Agent>): string {\n if (!target) return '?'\n if (target === 'broadcast') return 'broadcast'\n if (target.startsWith('tag:')) return '#' + target.slice(4)\n if (target.startsWith('cap:')) return target.slice(4)\n if (target.startsWith('label:')) return target.slice(6)\n if (target.startsWith('team:')) {\n const teamId = target.slice(5)\n const member = Object.values(agentsById).find((a) => a.teamId === teamId)\n return member ? `team:${displayName(member)}` : `team:${teamId.slice(-8)}`\n }\n const agent = agentsById[target]\n return agent ? displayName(agent) : target.slice(-8)\n}\n\nexport function messageBody(msg: Message | null | undefined): string {\n if (!msg) return ''\n const payload = msg.payload || {}\n const channelMessage = payload.message as Record<string, unknown> | undefined\n if (channelMessage && typeof channelMessage === 'object' && typeof channelMessage.text === 'string' && (channelMessage.text as string).trim()) {\n return channelMessage.text as string\n }\n const interaction = payload.interaction as Record<string, unknown> | undefined\n if (interaction && typeof interaction === 'object') {\n const title = typeof interaction.title === 'string' ? interaction.title.trim() : ''\n const description = typeof interaction.description === 'string' ? interaction.description.trim() : ''\n if (title && description) return title + '\\n' + description\n if (title) return title\n if (description) return description\n }\n const reaction = payload.reaction as Record<string, unknown> | undefined\n if (reaction && typeof reaction === 'object') {\n const name = typeof reaction.name === 'string' ? reaction.name : ''\n const emoji = typeof reaction.emoji === 'string' ? reaction.emoji : ''\n const value = typeof reaction.value === 'string' ? reaction.value : ''\n const displayEmoji = normalizeReactionEmoji(emoji || name || value)\n return ['Reaction', displayEmoji].filter(Boolean).join(': ')\n }\n const activity = payload.activity as Record<string, unknown> | undefined\n if (activity && typeof activity === 'object') {\n const kind = typeof activity.kind === 'string' ? activity.kind : 'activity'\n const state = typeof activity.state === 'string' ? activity.state : ''\n return [kind, state].filter(Boolean).join(' ')\n }\n if (typeof payload.text === 'string' && (payload.text as string).trim()) return payload.text as string\n if (typeof payload.message === 'string' && (payload.message as string).trim()) return payload.message as string\n return extractTextFromJson(msg.body || '') ?? (msg.body || '')\n}\n\nexport function isReactionEventMessage(msg: Message | null | undefined): boolean {\n if (!msg?.payload) return false\n const event = msg.payload.event as Record<string, unknown> | undefined\n return msg.payload.reactionNotification === true || event?.type === 'message.reaction'\n}\n\ninterface ParsedJsonBody {\n text: string\n meta: Array<[string, string]>\n raw: Record<string, unknown>\n}\n\nexport function parseJsonBody(body: string): ParsedJsonBody | null {\n if (!body) return null\n const trimmed = body.trim()\n if (!trimmed.startsWith('{')) return null\n try {\n const obj = JSON.parse(trimmed)\n if (typeof obj !== 'object' || obj === null || Array.isArray(obj)) return null\n const text = typeof obj.text === 'string' ? obj.text\n : typeof obj.message === 'string' ? obj.message\n : null\n if (!text?.trim()) return null\n const skipKeys = new Set(['text', 'message'])\n const meta = Object.entries(obj)\n .filter(([k, v]) => !skipKeys.has(k) && (typeof v === 'string' || typeof v === 'number' || typeof v === 'boolean'))\n .map(([k, v]) => [k, String(v)] as [string, string])\n return { text, meta, raw: obj }\n } catch {\n return null\n }\n}\n\nfunction extractTextFromJson(body: string): string | null {\n const parsed = parseJsonBody(body)\n return parsed?.text ?? null\n}\n\nexport function messagePreview(msg: Message | null | undefined): string {\n const text = msg?.subject || messageBody(msg) || ''\n return text.length > 90 ? text.slice(0, 90) + '...' : text\n}\n\n// De-singletoned human addressing (#393): a thread peer is the non-human side of any message\n// whose other side is a human address — the legacy bare `'user'` sink OR any `user:<id>` in the\n// namespace (`user:default` included). Today's single operator is still `'user'`, so this is a\n// no-op for the live deployment; per-user inbox scoping lands with auth/sessions (#389).\nexport function inboxPeer(msg: Message): string {\n if (isHumanAgentId(msg.from) && msg.to) return msg.to\n if (isHumanAgentId(msg.to) && msg.from) return msg.from\n return ''\n}\n\nexport function isHumanInboundMessage(msg: Message): boolean {\n return isHumanAgentId(msg.to) && !isHumanAgentId(msg.from)\n}\n\nexport function isSessionActivityStep(msg: Message): boolean {\n if (msg.kind !== 'session') return false\n const type = (msg.payload?.session as { type?: string } | undefined)?.type\n return type === 'reasoning' || type === 'tool'\n}\n\nexport function isBadgeWorthy(msg: Message): boolean {\n return msg.kind === 'session' && isWorkFinalMessagePayload(msg.payload)\n}\n\n// True when `block` appears as a whole \\n\\n-delimited segment of a response body —\n// the same boundary extractLastAssistantTurn joins narration on. Matches the entire\n// body (chatCaptureMode \"final\") or any internal block (\"full\") without naive-substring\n// false positives, and is robust to narration blocks that contain their own blank lines.\n// Used to suppress a narration trace step that the closing response bubble already repeats.\nexport function responseBodyContainsBlock(body: string, block: string): boolean {\n const b = body.trim()\n const t = block.trim()\n if (!t) return false\n if (b === t) return true\n return b.startsWith(`${t}\\n\\n`) || b.endsWith(`\\n\\n${t}`) || b.includes(`\\n\\n${t}\\n\\n`)\n}\n\nexport function isUnreadHumanMessage(readCursors: Record<string, number>, peer: string, msg: Message): boolean {\n if (!isHumanInboundMessage(msg)) return false\n if (!isBadgeWorthy(msg)) return false\n if ((msg.readBy || []).includes(HUMAN_AGENT_ID)) return false\n const cursor = Number(readCursors[peer] || 0)\n return msg.id > (Number.isFinite(cursor) ? cursor : 0)\n}\n\nexport function isClaimableTaskWaiting(task: Task): boolean {\n // #834 — only claim-lane tasks are claimable; deliverable Tasks are never claimed.\n return (task.kind ?? 'claim') === 'claim' && WAITING_TASK_STATUSES.has(task.status) && !task.claimedBy\n}\n\nexport function isClaimableMessageWaiting(msg: Message): boolean {\n return Boolean(msg.claimable && !msg.claimedBy && !(msg.kind === 'task' && Number.isSafeInteger((msg.payload as Record<string, unknown>)?.taskId)))\n}\n\nexport function dashboardTargetMatchesAgent(target: string, agent: Agent): boolean {\n if (!target || !agent) return false\n if (target === 'broadcast' || target === agent.id) return true\n if (target.startsWith('tag:')) return (agent.tags || []).includes(target.slice(4))\n if (target.startsWith('cap:')) return (agent.capabilities || []).includes(target.slice(4))\n if (target.startsWith('label:')) return agent.label === target.slice(6)\n if (target.startsWith('team:')) return agent.teamId === target.slice(5)\n return false\n}\n\nexport function messageMatchesAgentChat(agentId: string, message: Message): boolean {\n if (!agentId) return false\n if (message.from === agentId || message.to === agentId) return true\n if (message.resolvedToAgent === agentId) return true\n return false\n}\n\nexport function messageMatchesChannel(message: Message, channel: ChannelSummary): boolean {\n if (!message || !channel) return false\n const channelKeys = [channel.id, channel.type, ...(channel.topicChannels || [])].filter(Boolean)\n if (message.channel && channelKeys.includes(message.channel)) return true\n const payloadChannel = message.payload?.channel as Record<string, unknown> | undefined\n if (payloadChannel && typeof payloadChannel === 'object') {\n const keys = [payloadChannel.agentId, payloadChannel.provider, payloadChannel.accountId].filter(Boolean) as string[]\n if (keys.includes(channel.id) || keys.includes(channel.type) || (channel.accountId && keys.includes(channel.accountId))) return true\n }\n if (channel.agentId && (message.from === channel.agentId || message.to === channel.agentId)) return true\n return false\n}\n\ninterface ActiveSubagentInfo {\n id: string\n label: string\n role?: string\n startedAt?: number\n}\n\ninterface ProviderRuntimeState {\n state: string\n reason?: string\n label: string\n recommendedAction?: string\n source?: string\n raw?: unknown\n updatedAt?: number\n pendingApproval?: ProviderPendingApproval\n}\n\ninterface ProviderPendingApprovalChoice {\n id: 'approve' | 'approve-session' | 'deny' | 'abort'\n label: string\n}\n\ninterface ProviderQuestionOption {\n label: string\n description?: string\n}\n\nexport interface ProviderQuestion {\n question: string\n header?: string\n options: ProviderQuestionOption[]\n multiSelect?: boolean\n}\n\nexport interface ProviderPendingApproval {\n id: string\n provider?: string\n kind?: string\n title: string\n body: string\n choices: ProviderPendingApprovalChoice[]\n // Present when kind === 'questions' (Claude AskUserQuestion). The dashboard\n // renders these as a form and submits an 'answer' decision.\n questions?: ProviderQuestion[]\n}\n\nexport function providerRuntimeState(agent: Agent | null | undefined): ProviderRuntimeState | null {\n const raw = agent?.meta?.providerState\n if (!isRecord(raw) || typeof raw.state !== 'string') return null\n return {\n state: raw.state,\n reason: typeof raw.reason === 'string' ? raw.reason : undefined,\n label: typeof raw.label === 'string' && raw.label ? raw.label : raw.state,\n recommendedAction: typeof raw.recommendedAction === 'string' ? raw.recommendedAction : undefined,\n source: typeof raw.source === 'string' ? raw.source : undefined,\n raw: raw.raw,\n updatedAt: typeof raw.updatedAt === 'number' ? raw.updatedAt : undefined,\n pendingApproval: providerPendingApproval(raw.pendingApproval),\n }\n}\n\nfunction providerPendingApproval(value: unknown): ProviderPendingApproval | undefined {\n if (!isRecord(value) || typeof value.id !== 'string') return undefined\n const choices = Array.isArray(value.choices)\n ? value.choices.filter(isRecord).map((choice) => ({\n id: choice.id,\n label: typeof choice.label === 'string' ? choice.label : String(choice.id || ''),\n })).filter((choice): choice is ProviderPendingApprovalChoice =>\n (choice.id === 'approve' || choice.id === 'approve-session' || choice.id === 'deny' || choice.id === 'abort') && Boolean(choice.label)\n )\n : []\n const questions = Array.isArray(value.questions)\n ? value.questions.filter(isRecord).map((q): ProviderQuestion => ({\n question: typeof q.question === 'string' ? q.question : '',\n header: typeof q.header === 'string' ? q.header : undefined,\n multiSelect: q.multiSelect === true,\n options: Array.isArray(q.options)\n ? q.options.filter(isRecord).map((o) => ({\n label: typeof o.label === 'string' ? o.label : String(o.label ?? ''),\n description: typeof o.description === 'string' ? o.description : undefined,\n })).filter((o) => Boolean(o.label))\n : [],\n })).filter((q) => Boolean(q.question) && q.options.length > 0)\n : undefined\n return {\n id: value.id,\n provider: typeof value.provider === 'string' ? value.provider : undefined,\n kind: typeof value.kind === 'string' ? value.kind : undefined,\n title: typeof value.title === 'string' && value.title ? value.title : 'Permission request',\n body: typeof value.body === 'string' ? value.body : '',\n choices,\n ...(questions && questions.length ? { questions } : {}),\n }\n}\n\nexport function providerBlockedState(agent: Agent | null | undefined): ProviderRuntimeState | null {\n const state = providerRuntimeState(agent)\n return state?.state === 'blocked' ? state : null\n}\n\nexport function isPendingApprovalBadgeWorthy(approval: ProviderPendingApproval | null | undefined): boolean { return Boolean(approval?.id) }\n\nexport function agentNeedsHumanResponse(agent: Agent | null | undefined): boolean { return isPendingApprovalBadgeWorthy(providerBlockedState(agent)?.pendingApproval) }\n\nexport function activeSubagents(agent: Agent | null | undefined): ActiveSubagentInfo[] {\n const raw = agent?.meta?.activeSubagents\n if (!Array.isArray(raw)) {\n const count = typeof agent?.meta?.activeSubagentCount === 'number' ? agent.meta.activeSubagentCount : 0\n return count > 0 ? Array.from({ length: count }, (_, index) => ({ id: `subagent-${index + 1}`, label: `Subagent ${index + 1}` })) : []\n }\n return raw\n .filter(isRecord)\n .map((item, index) => {\n const id = typeof item.id === 'string' && item.id ? item.id : `subagent-${index + 1}`\n const role = typeof item.role === 'string' && item.role ? item.role : undefined\n const label = typeof item.label === 'string' && item.label ? item.label : role || id\n const startedAt = typeof item.startedAt === 'number' ? item.startedAt : undefined\n return { id, label, role, startedAt }\n })\n}\n\n// #502: a background shell (run_in_background) still running for this agent keeps\n// it busy even though its turn ended. The runner surfaces it as a `background-script`\n// work item in meta.activeWork carrying a human label (\"N background tasks\"); return\n// that label for a badge, or null when none are running.\nexport function activeBackgroundScriptLabel(agent: Agent | null | undefined): string | null {\n const raw = agent?.meta?.activeWork\n if (!Array.isArray(raw)) return null\n const item = raw.find((work) => isRecord(work) && work.kind === 'background-script')\n if (!item || !isRecord(item)) return null\n return typeof item.label === 'string' && item.label ? item.label : 'background script'\n}\n\nexport function agentPresence(\n now: number, agent: Agent | null | undefined, attention: AttentionInfo, pair: PairSession | null\n): PresenceInfo {\n const lifecycleAction = typeof agent?.meta?.lifecycleAction === 'string' ? agent.meta.lifecycleAction : ''\n const stale = isAgentStale(now, agent)\n const reconnecting = agent?.status !== 'offline' && !agent?.ready && stale\n const starting = agent?.status !== 'offline' && !agent?.ready && !stale\n const unreadIdle = attention.unread > 0 && agent?.status !== 'busy'\n const blocked = providerBlockedState(agent)\n const badges = presenceBadges(agent, attention, pair)\n\n if (agent?.status === 'offline') return { label: 'offline', tone: 'secondary', icon: 'PlugZap', stale: false, reconnecting: false, badges }\n // Pre-session-destroy window (#183): the runner is running end-of-session work before a\n // compact/clear/restart/shutdown. Distinct from plain \"busy\" and non-addressable.\n if (lifecycleAction.startsWith('finalizing-')) {\n return { label: `wrapping up (${lifecycleAction.slice('finalizing-'.length)})`, tone: 'warning', icon: 'Hourglass', stale, reconnecting, badges }\n }\n if (lifecycleAction === 'shutting-down') return { label: 'shutting down', tone: 'warning', icon: 'Power', stale, reconnecting, badges }\n if (lifecycleAction === 'killing') return { label: 'killing', tone: 'danger', icon: 'Power', stale, reconnecting, badges }\n if (lifecycleAction === 'restarting') return { label: 'restarting', tone: 'warning', icon: 'RefreshCw', stale, reconnecting, badges }\n if (agent?.status === 'stale') return { label: 'stale', tone: 'danger', icon: 'RefreshCw', stale: true, reconnecting: true, badges }\n if (reconnecting) return { label: 'reconnecting', tone: 'danger', icon: 'RefreshCw', stale, reconnecting, badges }\n if (starting) return { label: 'online, not ready', tone: 'warning', icon: 'Loader', stale, reconnecting, badges }\n if (blocked) return { label: `blocked: ${blocked.label}`, tone: 'danger', icon: 'AlertCircle', stale, reconnecting, badges }\n if (agent?.status === 'busy') {\n // #502: busy purely because a background shell outlived the turn (no active\n // provider turn / subagent) reads more truthfully as background work.\n const reasons = Array.isArray(agent?.meta?.busyReasons) ? agent.meta.busyReasons : []\n const backgroundOnly = activeBackgroundScriptLabel(agent) && !reasons.includes('provider-turn') && !reasons.includes('subagent')\n if (backgroundOnly) return { label: 'running background work', tone: 'warning', icon: 'Play', stale, reconnecting, badges }\n return { label: 'busy in turn', tone: 'warning', icon: 'Play', stale, reconnecting, badges }\n }\n if (pair?.status === 'active') return { label: 'paired', tone: 'success', icon: 'Link', stale, reconnecting, badges }\n if (unreadIdle) return { label: 'idle, unread', tone: 'danger', icon: 'Bell', stale, reconnecting, badges }\n return { label: agent?.status === 'idle' ? 'idle' : 'ready', tone: 'success', icon: 'CircleCheck', stale, reconnecting, badges }\n}\n\nfunction presenceBadges(agent: Agent | null | undefined, attention: AttentionInfo, pair: PairSession | null): PresenceBadge[] {\n const badges: PresenceBadge[] = []\n const blocked = providerBlockedState(agent)\n const subagentCount = activeSubagents(agent).length\n if (blocked) badges.push({ label: blocked.reason ? `blocked: ${blocked.reason}` : 'blocked', className: 'bg-red-500/20 text-red-400' })\n if (subagentCount) badges.push({ label: subagentCount === 1 ? '1 subagent' : subagentCount + ' subagents', className: 'bg-cyan-500/20 text-cyan-300' })\n const backgroundScriptLabel = activeBackgroundScriptLabel(agent)\n if (backgroundScriptLabel) badges.push({ label: backgroundScriptLabel, className: 'bg-indigo-500/20 text-indigo-300' })\n if (pair?.status === 'active') badges.push({ label: 'paired', className: 'bg-emerald-500/20 text-emerald-400' })\n if (pair?.status === 'pending') badges.push({ label: 'pair invite', className: 'bg-yellow-500/20 text-yellow-400' })\n if (attention.needsHumanResponse) badges.push({ label: 'needs response', className: 'bg-amber-500/20 text-amber-300' })\n if (attention.unread) badges.push({ label: attention.unread + ' unread', className: 'bg-red-500/20 text-red-400' })\n if (attention.claimableTasks) badges.push({ label: attention.claimableTasks + ' claimable', className: 'bg-orange-500/20 text-orange-400' })\n return badges\n}\n\nexport function emptyAttention(): AttentionInfo {\n return { unread: 0, needsHumanResponse: false, pendingPairInvite: false, claimableTasks: 0, total: 0, score: 0 }\n}\n\n\nexport function channelIsReady(channel: ChannelSummary | null): boolean {\n if (!channel || channel.status === 'offline') return false\n if (channel.targetHealth?.status === 'ok') return true\n if (channel.targetHealth?.status === 'error' || channel.targetHealth?.status === 'warning') return false\n return channel.ready\n}\n\nexport function channelPresence(channel: ChannelSummary | null): PresenceInfo {\n if (!channel) return { label: 'unknown', tone: 'secondary', icon: 'PlugZap', badges: [] }\n if (channel.targetHealth?.status === 'error') return { label: 'target broken', tone: 'danger', icon: 'AlertTriangle', badges: [] }\n if (channel.targetHealth?.status === 'warning') return { label: 'target warning', tone: 'warning', icon: 'AlertCircle', badges: [] }\n if (channel.status === 'offline') return { label: 'offline', tone: 'secondary', icon: 'PlugZap', badges: [] }\n if (channel.status === 'busy') return { label: 'busy', tone: 'warning', icon: 'Activity', badges: [] }\n if (!channelIsReady(channel)) return { label: 'not ready', tone: 'warning', icon: 'Loader', badges: [] }\n return { label: 'ready', tone: 'success', icon: 'CircleCheck', badges: [] }\n}\n\nexport function connectorPresence(connector: ConnectorSummary): PresenceInfo {\n const runtime = connector?.runtime || {}\n if (runtime.status === 'error') return { label: 'error', tone: 'danger', icon: 'AlertTriangle', badges: [] }\n if (runtime.status === 'warn') return { label: 'warning', tone: 'warning', icon: 'AlertCircle', badges: [] }\n if (runtime.running) return { label: 'running', tone: 'success', icon: 'CircleCheck', badges: [] }\n if (runtime.enabled === false) return { label: 'disabled', tone: 'secondary', icon: 'Pause', badges: [] }\n if (runtime.status === 'ok') return { label: 'ok', tone: 'success', icon: 'CircleCheck', badges: [] }\n return { label: 'unknown', tone: 'secondary', icon: 'HelpCircle', badges: [] }\n}\n\nexport function integrationPresence(integration: IntegrationSummary): PresenceInfo {\n const stats = integration?.taskStats || {}\n if ((stats.waitingTasks || 0) > 0) return { label: 'waiting', tone: 'warning', icon: 'AlertCircle', badges: [] }\n if ((stats.openTasks || 0) > 0) return { label: 'active', tone: 'info', icon: 'Activity', badges: [] }\n if (!integration?.configured) return { label: 'observed only', tone: 'secondary', icon: 'Eye', badges: [] }\n if (integration.observed) return { label: 'quiet', tone: 'success', icon: 'CircleCheck', badges: [] }\n return { label: 'configured', tone: 'primary', icon: 'PlugZap', badges: [] }\n}\n\nexport function orchestratorHealthLabel(orch: Orchestrator): string {\n const health = orch?.health\n if (!health || health.status === 'ok') return orch?.version || orch?.package?.version ? 'compatible' : 'unknown version'\n if (health.status === 'upgrade-required') return 'upgrade required'\n if (health.status === 'restart-required') return 'restart required'\n if (health.status === 'unknown') return 'unknown contract'\n if ((health.issues || []).some((i) => i.code === 'protocol-mismatch')) return 'protocol mismatch'\n if ((health.issues || []).some((i) => i.code === 'package-drift')) return 'package drift'\n if (health.restartRequired) return 'restart required'\n return health.status\n}\n\nexport function orchestratorHealthClass(orch: Orchestrator): string {\n const status = orch?.health?.status\n if (status === 'upgrade-required') return 'text-red-400 bg-red-500/10'\n if (status === 'warn' || status === 'restart-required') return 'text-yellow-400 bg-yellow-500/10'\n if (status === 'unknown') return 'text-zinc-400 bg-zinc-500/10'\n return 'text-emerald-400 bg-emerald-500/10'\n}\n\nexport function timeAgo(now: number, iso: string | number | null | undefined): string {\n if (!iso) return ''\n const ts = new Date(iso as string).getTime()\n if (!Number.isFinite(ts)) return ''\n const diff = Math.max(0, (now - ts) / 1000)\n if (diff < 60) return Math.floor(diff) + 's ago'\n if (diff < 3600) return Math.floor(diff / 60) + 'm ago'\n if (diff < 86400) return Math.floor(diff / 3600) + 'h ago'\n return Math.floor(diff / 86400) + 'd ago'\n}\n\nexport function fmtTime(iso: string | number | null | undefined): string {\n if (!iso) return ''\n return new Date(iso as string).toLocaleString()\n}\n\nexport function safeFilename(value: string): string {\n return String(value || 'export').replace(/[^a-z0-9._-]+/gi, '-').replace(/^-+|-+$/g, '').slice(0, 80) || 'export'\n}\n\nexport function healthDiagnostics(checks: HealthCheck[]): HealthDiagnostic[] {\n return checks.filter((c) => c.status !== 'ok').map((check) => {\n const base: HealthDiagnostic = {\n name: check.name,\n status: check.status,\n detail: check.detail || check.name,\n impact: healthImpact(check),\n subjects: check.subjects || [],\n actions: [\n { label: 'Inspect logs', icon: 'FileSearch', copy: 'agent-relay daemon logs' },\n { label: 'Restart daemon', icon: 'RefreshCw', copy: 'agent-relay daemon restart' },\n { label: 'Copy env', icon: 'Copy', copy: 'agent-relay doctor' },\n ],\n }\n if (check.name === 'stale-live-agents') {\n base.actions.unshift(\n { label: 'Run reaper', icon: 'Eraser', api: 'POST', path: '/system/reap' },\n { label: 'Show stale', icon: 'Filter', view: 'agents', preset: 'offline_stale' },\n )\n } else if (check.name === 'channel-delivery-targets') {\n base.actions.unshift(\n { label: 'Open channels', icon: 'MessagesSquare', view: 'channels' },\n { label: 'Run reaper', icon: 'Eraser', api: 'POST', path: '/system/reap' },\n )\n } else if (['expired-message-claims', 'expired-task-claims', 'offline-claimed-tasks'].includes(check.name)) {\n base.actions.unshift(\n { label: 'Run reaper', icon: 'Eraser', api: 'POST', path: '/system/reap' },\n { label: 'Open work', icon: 'ListChecks', view: 'work' },\n )\n }\n return base\n })\n}\n\nfunction healthImpact(check: HealthCheck): string {\n const impacts: Record<string, string> = {\n 'database': 'Relay persistence is unavailable; messages, state, and audit writes may fail.',\n 'stale-live-agents': 'Agents may look online even though their heartbeat has stopped.',\n 'expired-message-claims': 'Claimable messages may be stuck until the reaper releases expired claims.',\n 'expired-task-claims': 'Tasks can appear owned by agents that no longer hold a live lease.',\n 'offline-claimed-tasks': 'Offline agents are still shown as owners for active work.',\n 'channel-delivery-targets': 'Inbound channel messages may be accepted but routed to no live delivery agent.',\n }\n return impacts[check.name] || 'Relay health is degraded for this check.'\n}\n\nfunction toneToBadgeVariant(tone: string): 'default' | 'secondary' | 'destructive' | 'outline' {\n if (tone === 'danger' || tone === 'destructive') return 'destructive'\n if (tone === 'secondary') return 'secondary'\n return 'default'\n}\n\nexport function toneToColor(tone: string): string {\n const map: Record<string, string> = {\n success: 'text-emerald-400',\n warning: 'text-yellow-400',\n danger: 'text-red-400',\n info: 'text-blue-400',\n primary: 'text-blue-400',\n secondary: 'text-zinc-400',\n }\n return map[tone] || 'text-zinc-400'\n}\n\nfunction toneToBg(tone: string): string {\n const map: Record<string, string> = {\n success: 'bg-emerald-500',\n warning: 'bg-yellow-500',\n danger: 'bg-red-500',\n info: 'bg-blue-500',\n primary: 'bg-blue-500',\n secondary: 'bg-zinc-500',\n }\n return map[tone] || 'bg-zinc-500'\n}\n\nexport function statusDotColor(agent: Agent | null, now?: number): string {\n if (!agent) return 'bg-zinc-500 opacity-50'\n if (agent.status === 'offline') return 'bg-zinc-500 opacity-50'\n if (typeof agent.meta?.lifecycleAction === 'string' && agent.meta.lifecycleAction.startsWith('finalizing-')) return 'bg-amber-500 animate-pulse'\n if (agent.meta?.lifecycleAction === 'shutting-down' || agent.meta?.lifecycleAction === 'restarting') return 'bg-yellow-500 animate-pulse'\n if (agent.meta?.lifecycleAction === 'killing') return 'bg-red-500 animate-pulse'\n if (providerBlockedState(agent)) return 'bg-red-500 animate-pulse'\n if (agent.status === 'busy') return 'bg-yellow-500'\n if (now && isAgentStale(now, agent)) return 'bg-red-500 animate-pulse'\n if (!agent.ready) return 'bg-emerald-500 animate-pulse'\n return 'bg-emerald-500 shadow-[0_0_6px_theme(colors.emerald.500)]'\n}\n\nexport function downloadText(filename: string, text: string, type: string) {\n if (typeof document === 'undefined' || typeof URL === 'undefined' || typeof Blob === 'undefined') return\n const url = URL.createObjectURL(new Blob([text], { type }))\n const link = document.createElement('a')\n link.href = url\n link.download = filename\n link.click()\n URL.revokeObjectURL(url)\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"display-aTnwsqQh.js","names":[],"sources":["../../dashboard/src/lib/constants.ts","../../dashboard/src/lib/display.ts"],"sourcesContent":["import type { ComposeState, InboxComposeState, PairMessageState, PairInviteState, ViewName } from '@/types'\n\nconst PREF_PREFIX = 'ar-'\nexport const HUMAN_AGENT_ID = 'user'\nexport const INBOX_OPERATOR_ID = HUMAN_AGENT_ID\nexport const LIVE_REFRESH_MS = 5_000\n// Max live messages retained in memory. Must be >= the largest fetch limit\n// (chat view fetches 300) so SSE appends never trim already-loaded history.\nexport const MESSAGE_BUFFER_CAP = 500\n\nexport const CLOSED_TASK_STATUSES = new Set(['done', 'failed', 'canceled'])\nexport const WAITING_TASK_STATUSES = new Set(['open', 'blocked'])\n\nexport const STATUS_SORT_ORDER: Record<string, number> = { online: 0, idle: 0, busy: 2, offline: 3 }\nexport const CHAT_STATUS_SORT_ORDER: Record<string, number> = { idle: 0, online: 0, busy: 2, offline: 4 }\n\nexport const DEFAULT_COMPOSE: ComposeState = { from: '', to: '', body: '', channel: '', subject: '', claimable: false }\nexport const DEFAULT_INBOX_COMPOSE: InboxComposeState = { toMode: 'agent', to: '', body: '', channel: '', subject: '', claimable: false }\nexport const DEFAULT_PAIR_MESSAGE: PairMessageState = { pairId: '', from: '', body: '', subject: '' }\nexport const DEFAULT_PAIR_INVITE: PairInviteState = { requesterId: '', targetId: '', objective: '' }\n\n\nimport { getKnownProviderIds, getProviderLabel } from './provider-display'\n\nconst SYSTEM_TYPE_ICONS: Record<string, string> = {\n user: 'User',\n system: 'Server',\n channel: 'MessagesSquare',\n agent: 'Bot',\n}\n\nconst SYSTEM_TYPE_TITLES: Record<string, string> = {\n user: 'Human operator',\n system: 'System',\n channel: 'Channel',\n agent: 'Agent',\n}\n\nexport const AGENT_TYPE_ICONS: Record<string, string> = {\n ...SYSTEM_TYPE_ICONS,\n ...Object.fromEntries(getKnownProviderIds().map((id) => [id, 'Bot'])),\n}\n\nexport const AGENT_TYPE_TITLES: Record<string, string> = {\n ...SYSTEM_TYPE_TITLES,\n ...Object.fromEntries(getKnownProviderIds().map((id) => [id, `${getProviderLabel(id)} agent`])),\n}\n\nexport const NAV_ITEMS: Array<{ key: ViewName; label: string; icon: string }> = [\n { key: 'overview', label: 'Overview', icon: 'LayoutDashboard' },\n { key: 'chat', label: 'Chat', icon: 'MessageCircle' },\n { key: 'agents', label: 'Agents', icon: 'Bot' },\n { key: 'managed', label: 'Managed Agents', icon: 'Workflow' },\n { key: 'teams', label: 'Teams', icon: 'Users' },\n { key: 'profiles', label: 'Agent Profiles', icon: 'UserCog' },\n { key: 'orchestrators', label: 'Orchestrators', icon: 'Server' },\n { key: 'workspaces', label: 'Workspaces', icon: 'GitBranch' },\n { key: 'files', label: 'Files', icon: 'FolderTree' },\n { key: 'channels', label: 'Channels', icon: 'MessagesSquare' },\n { key: 'connectors', label: 'Connectors', icon: 'Plug' },\n { key: 'integrations', label: 'Integrations', icon: 'PlugZap' },\n { key: 'security', label: 'Security', icon: 'Shield' },\n { key: 'memory', label: 'Memory', icon: 'BrainCircuit' },\n { key: 'activity', label: 'Activity', icon: 'Activity' },\n { key: 'pairs', label: 'Pairs', icon: 'Link' },\n { key: 'messages', label: 'Messages', icon: 'Mail' },\n { key: 'work', label: 'Work Queue', icon: 'ListChecks' },\n { key: 'tasks', label: 'Tasks', icon: 'ClipboardList' },\n { key: 'automation', label: 'Automation', icon: 'CalendarClock' },\n { key: 'analytics', label: 'Analytics', icon: 'AreaChart' },\n { key: 'insights', label: 'Insights', icon: 'Lightbulb' },\n { key: 'projects', label: 'Projects', icon: 'Boxes' },\n { key: 'prompts', label: 'Prompts', icon: 'FileText' },\n { key: 'registry', label: 'Registry', icon: 'PackagePlus' },\n { key: 'maintenance', label: 'Maintenance', icon: 'Wrench' },\n { key: 'settings', label: 'Settings', icon: 'Settings' },\n]\n\nexport const SEVERITY_COLORS: Record<string, string> = {\n critical: 'text-red-400 bg-red-500/10',\n warning: 'text-yellow-400 bg-yellow-500/10',\n info: 'text-blue-400 bg-blue-500/10',\n}\n\nexport const PAIR_STATUS_COLORS: Record<string, string> = {\n active: 'bg-emerald-500/20 text-emerald-400',\n pending: 'bg-yellow-500/20 text-yellow-400',\n ended: 'bg-zinc-500/20 text-zinc-400',\n rejected: 'bg-red-500/20 text-red-400',\n expired: 'bg-red-500/20 text-red-400',\n}\n","import type {\n Agent, Message, PairSession, Task, ChannelSummary, ConnectorSummary,\n IntegrationSummary, Orchestrator, AgentType, PresenceInfo, PresenceBadge,\n AttentionInfo, InboxThread, HealthCheck, HealthDiagnostic, ManagedPolicyHealth,\n} from '@/types'\nimport type { User } from '@/types'\nimport { HUMAN_AGENT_ID, AGENT_TYPE_ICONS, AGENT_TYPE_TITLES, WAITING_TASK_STATUSES } from './constants'\nimport { getKnownProviderIds, getProviderManifest } from './provider-display'\nimport { isRecord, isHumanAgentId, isWorkFinalMessagePayload, userIdFromAddress } from 'agent-relay-sdk/types'\n\nexport function toTimestamp(value: unknown): number {\n const ts = typeof value === 'number' ? value : new Date((value as string) || 0).getTime()\n return Number.isFinite(ts) ? ts : 0\n}\n\nconst INTERNAL_CAP_PREFIXES = ['lifecycle.', 'commands.', 'capabilities.']\n\nconst REACTION_EMOJI_ALIASES: Record<string, string> = {\n '+1': '👍',\n ':+1:': '👍',\n thumbsup: '👍',\n ':thumbsup:': '👍',\n 'thumbs-up': '👍',\n ':thumbs-up:': '👍',\n thumbs_up: '👍',\n ':thumbs_up:': '👍',\n thumb_up: '👍',\n ':thumb_up:': '👍',\n like: '👍',\n ':like:': '👍',\n heart: '❤️',\n ':heart:': '❤️',\n redheart: '❤️',\n red_heart: '❤️',\n ':red_heart:': '❤️',\n check: '✅',\n ':check:': '✅',\n checkmark: '✅',\n ':checkmark:': '✅',\n white_check_mark: '✅',\n ':white_check_mark:': '✅',\n eyes: '👀',\n ':eyes:': '👀',\n}\n\nexport function normalizeReactionEmoji(value: string): string {\n const trimmed = value.trim()\n return REACTION_EMOJI_ALIASES[trimmed.toLowerCase()] ?? trimmed\n}\n\nexport function userFacingCapabilities(caps: string[]): string[] {\n return caps.filter((c) => !INTERNAL_CAP_PREFIXES.some((p) => c.startsWith(p)))\n}\n\nexport function shortPath(cwd: string | undefined | null, segments = 2): string {\n if (!cwd) return ''\n const parts = cwd.replace(/\\/+$/, '').split('/')\n return parts.length <= segments ? cwd : parts.slice(-segments).join('/')\n}\n\nexport function normalizePathForCompare(path: string): string {\n return path.trim().replace(/\\\\/g, '/').replace(/\\/+$/, '') || '/'\n}\n\nexport function pathWithinBase(path: string | undefined | null, baseDir: string | undefined | null): boolean {\n if (!path?.trim() || !baseDir?.trim()) return false\n const normalizedPath = normalizePathForCompare(path)\n const normalizedBase = normalizePathForCompare(baseDir)\n if (normalizedBase === '/') return normalizedPath.startsWith('/')\n if (normalizedPath === '/') return false\n return normalizedPath === normalizedBase || normalizedPath.startsWith(normalizedBase + '/')\n}\n\nfunction isBuiltInAgent(agent: Agent | null | undefined): boolean {\n return agent?.meta?.builtin === true || agent?.id === HUMAN_AGENT_ID || agent?.id === 'system'\n}\n\nfunction isChannelAgent(agent: Agent | null | undefined): boolean {\n const tags = agent?.tags || []\n const caps = agent?.capabilities || []\n const policyName = typeof agent?.meta?.policyName === 'string' ? agent.meta.policyName : ''\n return agent?.kind === 'channel' ||\n agent?.meta?.kind === 'channel' ||\n tags.includes('channel') ||\n tags.some((tag) => tag.startsWith('channel:')) ||\n caps.includes('channel') ||\n caps.some((cap) => cap.startsWith('channel:')) ||\n tags.includes('telegram') ||\n caps.includes('telegram') ||\n policyName === 'telegram-main'\n}\n\nfunction isAutomationAgent(agent: Agent | null | undefined): boolean {\n return Boolean(\n typeof agent?.meta?.automationId === 'string' ||\n typeof agent?.meta?.automationRunId === 'string' ||\n agent?.tags?.includes('automation')\n )\n}\n\nfunction isSystemAgent(agent: Agent | null | undefined): boolean {\n return isBuiltInAgent(agent) || isChannelAgent(agent) || isAutomationAgent(agent)\n}\n\nexport function agentType(agent: Agent | null | undefined): AgentType {\n if (agent?.id === HUMAN_AGENT_ID) return 'user'\n if (agent?.id === 'system') return 'system'\n if (isChannelAgent(agent)) return 'channel'\n\n const knownProviders = getKnownProviderIds()\n\n // #417: check the authoritative provider field first (exact match) so a name or id\n // containing a provider name as a substring can't mislabel the agent.\n const provider = typeof agent?.meta?.provider === 'string' ? agent.meta.provider.toLowerCase() : undefined\n if (provider && knownProviders.includes(provider)) return provider as AgentType\n\n // Fallback heuristic for agents registered without meta.provider. Only scan tags\n // and meta fields — not id or name, which are free-text and cause false positives.\n const values = [\n ...(agent?.tags || []),\n agent?.meta?.client as string,\n agent?.meta?.runtime as string,\n agent?.meta?.agentType as string,\n ]\n .filter((v): v is string => typeof v === 'string')\n .map((v) => v.toLowerCase())\n\n for (const pid of knownProviders) {\n if (values.some((v) => v.includes(pid))) return pid as AgentType\n }\n return 'agent'\n}\n\nfunction agentTypeIcon(agent: Agent | null | undefined): string {\n return AGENT_TYPE_ICONS[agentType(agent)] ?? AGENT_TYPE_ICONS.agent ?? 'ti-robot'\n}\n\nfunction agentTypeTitle(agent: Agent | null | undefined): string {\n return AGENT_TYPE_TITLES[agentType(agent)] ?? AGENT_TYPE_TITLES.agent ?? 'Agent'\n}\n\nexport function isAgentStale(now: number, agent: Agent | null | undefined): boolean {\n if (!agent?.lastSeen || agent.status === 'offline') return false\n if (agent.id === 'user' || agent.id === 'system') return false\n // A live bus connection is authoritative liveness: an idle-but-connected agent\n // is reachable, not stale, even if lastSeen has aged (e.g. heartbeat keepalive\n // gaps while idle). Genuine death flips transport.connected to false (or the\n // server reaps the agent offline), at which point the lastSeen check applies.\n const transport = agent.meta?.transport\n if (isRecord(transport) && transport.connected === true) return false\n const lastSeenMs = new Date(agent.lastSeen as string).getTime()\n if (!Number.isFinite(lastSeenMs)) return false\n return now - lastSeenMs > 60_000\n}\n\nexport type AgentControlAction = 'restart' | 'shutdown' | 'reconnect' | 'compact' | 'clearContext' | 'resume' | 'interrupt'\n\nexport function agentSupportsControlAction(agent: Agent | null | undefined, action: AgentControlAction): boolean {\n if (!agent || isBuiltInAgent(agent) || isChannelAgent(agent)) return false\n if (action === 'resume') return false\n // Interrupt is provider-independent and only meaningful while the agent is actually mid-turn.\n if (action === 'interrupt') return agent.providerCapabilities?.liveSession?.interrupt === true && agent.status === 'busy'\n const needsTmux = providerUsesLiveTerminal(agent) && (action === 'restart' || action === 'shutdown' || action === 'compact' || action === 'clearContext')\n if (needsTmux && !agentHasTmuxSession(agent)) return false\n const lifecycle = agent.providerCapabilities?.lifecycle\n if (lifecycle) {\n if (action === 'restart') return lifecycle.restartHard === true\n if (action === 'shutdown') return lifecycle.shutdownHard === true\n if (action === 'reconnect') return lifecycle.reconnect === true\n }\n if (action === 'compact') return agent.providerCapabilities?.context?.compact === true\n if (action === 'clearContext') return agent.providerCapabilities?.context?.clear === true\n return agent.meta?.runnerManaged === true && (action === 'restart' || action === 'shutdown')\n}\n\nfunction agentHasTmuxSession(agent: Agent): boolean {\n return typeof agent.meta?.tmuxSession === 'string' && agent.meta.tmuxSession.trim().length > 0\n}\n\nfunction providerUsesLiveTerminal(agent: Agent | null | undefined): boolean {\n const manifest = typeof agent?.meta?.provider === 'string' ? getProviderManifest(agent.meta.provider as string) : undefined\n return manifest?.capabilityDefaults?.terminal?.mode === 'live'\n}\n\nfunction agentSupportsControlActions(agent: Agent | null | undefined): boolean {\n return agentSupportsControlAction(agent, 'restart') ||\n agentSupportsControlAction(agent, 'shutdown') ||\n agentSupportsControlAction(agent, 'reconnect') ||\n agentSupportsControlAction(agent, 'compact') ||\n agentSupportsControlAction(agent, 'clearContext')\n}\n\nexport function agentCanBeForgotten(agent: Agent | null | undefined): boolean {\n return Boolean(agent && !isBuiltInAgent(agent) && !isChannelAgent(agent) && !agentSupportsControlActions(agent) && (agent.status === 'offline' || agent.status === 'stale'))\n}\n\nfunction isRetiredManagedRuntimeAgent(agent: Agent, managedPolicies: ManagedPolicyHealth[]): boolean {\n if (agent.status !== 'offline') return false\n const policyName = typeof agent.meta?.policyName === 'string' ? agent.meta.policyName : ''\n if (!policyName) return false\n const policy = managedPolicies.find((item) => item.policy.name === policyName)\n return Boolean(policy?.state.agentId && policy.state.agentId !== agent.id)\n}\n\nexport function visibleAgents(agents: Agent[], showBuiltIns: boolean, managedPolicies: ManagedPolicyHealth[] = []): Agent[] {\n const activeRuntimeAgents = agents.filter((a) => !isRetiredManagedRuntimeAgent(a, managedPolicies))\n return showBuiltIns ? activeRuntimeAgents : activeRuntimeAgents.filter((a) => !isSystemAgent(a))\n}\n\nexport function displayName(agent: Agent | null | undefined): string {\n if (!agent) return '?'\n return agent.label || agent.name || agent.id.slice(-12)\n}\n\n// Human attribution (#390). Resolve a human message address (`user` / `user:<id>`) to its\n// users-table row, or undefined for a non-human address / unknown id. The single bridge from\n// a wire address → a user record on the client, mirroring the SDK resolver on the server.\nexport function resolveUser(address: string | undefined, usersById: Record<string, User>): User | undefined {\n const userId = userIdFromAddress(address)\n return userId ? usersById[userId] : undefined\n}\n\n// Name to show for a human address. Prefers the user's displayName, then handle, then a\n// generic 'User' so a not-yet-loaded directory (or the seeded default) still reads sensibly —\n// which keeps today's single operator rendering exactly as before.\nexport function humanDisplayName(address: string | undefined, usersById: Record<string, User>): string {\n const user = resolveUser(address, usersById)\n return user?.displayName?.trim() || user?.handle?.trim() || 'User'\n}\n\n// Deterministic accent color per human so multiple operators are visually distinguishable in\n// one thread. Stable for a given user id; the single default operator never needs it (callers\n// only apply this once more than one human exists, preserving back-compat styling).\nconst HUMAN_ACCENT_CLASSES = [\n 'text-sky-300', 'text-amber-300', 'text-emerald-300', 'text-violet-300', 'text-rose-300', 'text-cyan-300',\n]\nexport function humanAccentClass(address: string | undefined): string {\n const userId = userIdFromAddress(address) || ''\n let hash = 0\n for (let i = 0; i < userId.length; i++) hash = (hash * 31 + userId.charCodeAt(i)) >>> 0\n return HUMAN_ACCENT_CLASSES[hash % HUMAN_ACCENT_CLASSES.length]!\n}\n\nexport function displayTarget(target: string, agentsById: Record<string, Agent>): string {\n if (!target) return '?'\n if (target === 'broadcast') return 'broadcast'\n if (target.startsWith('tag:')) return '#' + target.slice(4)\n if (target.startsWith('cap:')) return target.slice(4)\n if (target.startsWith('label:')) return target.slice(6)\n if (target.startsWith('team:')) {\n const teamId = target.slice(5)\n const member = Object.values(agentsById).find((a) => a.teamId === teamId)\n return member ? `team:${displayName(member)}` : `team:${teamId.slice(-8)}`\n }\n const agent = agentsById[target]\n return agent ? displayName(agent) : target.slice(-8)\n}\n\nexport function messageBody(msg: Message | null | undefined): string {\n if (!msg) return ''\n const payload = msg.payload || {}\n const channelMessage = payload.message as Record<string, unknown> | undefined\n if (channelMessage && typeof channelMessage === 'object' && typeof channelMessage.text === 'string' && (channelMessage.text as string).trim()) {\n return channelMessage.text as string\n }\n const interaction = payload.interaction as Record<string, unknown> | undefined\n if (interaction && typeof interaction === 'object') {\n const title = typeof interaction.title === 'string' ? interaction.title.trim() : ''\n const description = typeof interaction.description === 'string' ? interaction.description.trim() : ''\n if (title && description) return title + '\\n' + description\n if (title) return title\n if (description) return description\n }\n const reaction = payload.reaction as Record<string, unknown> | undefined\n if (reaction && typeof reaction === 'object') {\n const name = typeof reaction.name === 'string' ? reaction.name : ''\n const emoji = typeof reaction.emoji === 'string' ? reaction.emoji : ''\n const value = typeof reaction.value === 'string' ? reaction.value : ''\n const displayEmoji = normalizeReactionEmoji(emoji || name || value)\n return ['Reaction', displayEmoji].filter(Boolean).join(': ')\n }\n const activity = payload.activity as Record<string, unknown> | undefined\n if (activity && typeof activity === 'object') {\n const kind = typeof activity.kind === 'string' ? activity.kind : 'activity'\n const state = typeof activity.state === 'string' ? activity.state : ''\n return [kind, state].filter(Boolean).join(' ')\n }\n if (typeof payload.text === 'string' && (payload.text as string).trim()) return payload.text as string\n if (typeof payload.message === 'string' && (payload.message as string).trim()) return payload.message as string\n return extractTextFromJson(msg.body || '') ?? (msg.body || '')\n}\n\nexport function isReactionEventMessage(msg: Message | null | undefined): boolean {\n if (!msg?.payload) return false\n const event = msg.payload.event as Record<string, unknown> | undefined\n return msg.payload.reactionNotification === true || event?.type === 'message.reaction'\n}\n\ninterface ParsedJsonBody {\n text: string\n meta: Array<[string, string]>\n raw: Record<string, unknown>\n}\n\nexport function parseJsonBody(body: string): ParsedJsonBody | null {\n if (!body) return null\n const trimmed = body.trim()\n if (!trimmed.startsWith('{')) return null\n try {\n const obj = JSON.parse(trimmed)\n if (typeof obj !== 'object' || obj === null || Array.isArray(obj)) return null\n const text = typeof obj.text === 'string' ? obj.text\n : typeof obj.message === 'string' ? obj.message\n : null\n if (!text?.trim()) return null\n const skipKeys = new Set(['text', 'message'])\n const meta = Object.entries(obj)\n .filter(([k, v]) => !skipKeys.has(k) && (typeof v === 'string' || typeof v === 'number' || typeof v === 'boolean'))\n .map(([k, v]) => [k, String(v)] as [string, string])\n return { text, meta, raw: obj }\n } catch {\n return null\n }\n}\n\nfunction extractTextFromJson(body: string): string | null {\n const parsed = parseJsonBody(body)\n return parsed?.text ?? null\n}\n\nexport function messagePreview(msg: Message | null | undefined): string {\n const text = msg?.subject || messageBody(msg) || ''\n return text.length > 90 ? text.slice(0, 90) + '...' : text\n}\n\n// De-singletoned human addressing (#393): a thread peer is the non-human side of any message\n// whose other side is a human address — the legacy bare `'user'` sink OR any `user:<id>` in the\n// namespace (`user:default` included). Today's single operator is still `'user'`, so this is a\n// no-op for the live deployment; per-user inbox scoping lands with auth/sessions (#389).\nexport function inboxPeer(msg: Message): string {\n if (isHumanAgentId(msg.from) && msg.to) return msg.to\n if (isHumanAgentId(msg.to) && msg.from) return msg.from\n return ''\n}\n\nexport function isHumanInboundMessage(msg: Message): boolean {\n return isHumanAgentId(msg.to) && !isHumanAgentId(msg.from)\n}\n\nexport function isSessionActivityStep(msg: Message): boolean {\n if (msg.kind !== 'session') return false\n const type = (msg.payload?.session as { type?: string } | undefined)?.type\n return type === 'reasoning' || type === 'tool'\n}\n\nexport function isBadgeWorthy(msg: Message): boolean {\n return msg.kind === 'session' && isWorkFinalMessagePayload(msg.payload)\n}\n\n// True when `block` appears as a whole \\n\\n-delimited segment of a response body —\n// the same boundary extractLastAssistantTurn joins narration on. Matches the entire\n// body (chatCaptureMode \"final\") or any internal block (\"full\") without naive-substring\n// false positives, and is robust to narration blocks that contain their own blank lines.\n// Used to suppress a narration trace step that the closing response bubble already repeats.\nexport function responseBodyContainsBlock(body: string, block: string): boolean {\n const b = body.trim()\n const t = block.trim()\n if (!t) return false\n if (b === t) return true\n return b.startsWith(`${t}\\n\\n`) || b.endsWith(`\\n\\n${t}`) || b.includes(`\\n\\n${t}\\n\\n`)\n}\n\nexport function isUnreadHumanMessage(readCursors: Record<string, number>, peer: string, msg: Message): boolean {\n if (!isHumanInboundMessage(msg)) return false\n if (!isBadgeWorthy(msg)) return false\n if ((msg.readBy || []).includes(HUMAN_AGENT_ID)) return false\n const cursor = Number(readCursors[peer] || 0)\n return msg.id > (Number.isFinite(cursor) ? cursor : 0)\n}\n\nexport function isClaimableTaskWaiting(task: Task): boolean {\n // #834 — only claim-lane tasks are claimable; deliverable Tasks are never claimed.\n return (task.kind ?? 'claim') === 'claim' && WAITING_TASK_STATUSES.has(task.status) && !task.claimedBy\n}\n\nexport function isClaimableMessageWaiting(msg: Message): boolean {\n return Boolean(msg.claimable && !msg.claimedBy && !(msg.kind === 'task' && Number.isSafeInteger((msg.payload as Record<string, unknown>)?.taskId)))\n}\n\nexport function dashboardTargetMatchesAgent(target: string, agent: Agent): boolean {\n if (!target || !agent) return false\n if (target === 'broadcast' || target === agent.id) return true\n if (target.startsWith('tag:')) return (agent.tags || []).includes(target.slice(4))\n if (target.startsWith('cap:')) return (agent.capabilities || []).includes(target.slice(4))\n if (target.startsWith('label:')) return agent.label === target.slice(6)\n if (target.startsWith('team:')) return agent.teamId === target.slice(5)\n return false\n}\n\nexport function messageMatchesAgentChat(agentId: string, message: Message): boolean {\n if (!agentId) return false\n if (message.from === agentId || message.to === agentId) return true\n if (message.resolvedToAgent === agentId) return true\n return false\n}\n\nexport function messageMatchesChannel(message: Message, channel: ChannelSummary): boolean {\n if (!message || !channel) return false\n const channelKeys = [channel.id, channel.type, ...(channel.topicChannels || [])].filter(Boolean)\n if (message.channel && channelKeys.includes(message.channel)) return true\n const payloadChannel = message.payload?.channel as Record<string, unknown> | undefined\n if (payloadChannel && typeof payloadChannel === 'object') {\n const keys = [payloadChannel.agentId, payloadChannel.provider, payloadChannel.accountId].filter(Boolean) as string[]\n if (keys.includes(channel.id) || keys.includes(channel.type) || (channel.accountId && keys.includes(channel.accountId))) return true\n }\n if (channel.agentId && (message.from === channel.agentId || message.to === channel.agentId)) return true\n return false\n}\n\ninterface ActiveSubagentInfo {\n id: string\n label: string\n role?: string\n startedAt?: number\n}\n\ninterface ProviderRuntimeState {\n state: string\n reason?: string\n label: string\n recommendedAction?: string\n source?: string\n raw?: unknown\n updatedAt?: number\n pendingApproval?: ProviderPendingApproval\n}\n\ninterface ProviderPendingApprovalChoice {\n id: 'approve' | 'approve-session' | 'deny' | 'abort'\n label: string\n}\n\ninterface ProviderQuestionOption {\n label: string\n description?: string\n}\n\nexport interface ProviderQuestion {\n question: string\n header?: string\n options: ProviderQuestionOption[]\n multiSelect?: boolean\n}\n\nexport interface ProviderPendingApproval {\n id: string\n provider?: string\n kind?: string\n title: string\n body: string\n choices: ProviderPendingApprovalChoice[]\n // Present when kind === 'questions' (Claude AskUserQuestion). The dashboard\n // renders these as a form and submits an 'answer' decision.\n questions?: ProviderQuestion[]\n}\n\nexport function providerRuntimeState(agent: Agent | null | undefined): ProviderRuntimeState | null {\n const raw = agent?.meta?.providerState\n if (!isRecord(raw) || typeof raw.state !== 'string') return null\n return {\n state: raw.state,\n reason: typeof raw.reason === 'string' ? raw.reason : undefined,\n label: typeof raw.label === 'string' && raw.label ? raw.label : raw.state,\n recommendedAction: typeof raw.recommendedAction === 'string' ? raw.recommendedAction : undefined,\n source: typeof raw.source === 'string' ? raw.source : undefined,\n raw: raw.raw,\n updatedAt: typeof raw.updatedAt === 'number' ? raw.updatedAt : undefined,\n pendingApproval: providerPendingApproval(raw.pendingApproval),\n }\n}\n\nfunction providerPendingApproval(value: unknown): ProviderPendingApproval | undefined {\n if (!isRecord(value) || typeof value.id !== 'string') return undefined\n const choices = Array.isArray(value.choices)\n ? value.choices.filter(isRecord).map((choice) => ({\n id: choice.id,\n label: typeof choice.label === 'string' ? choice.label : String(choice.id || ''),\n })).filter((choice): choice is ProviderPendingApprovalChoice =>\n (choice.id === 'approve' || choice.id === 'approve-session' || choice.id === 'deny' || choice.id === 'abort') && Boolean(choice.label)\n )\n : []\n const questions = Array.isArray(value.questions)\n ? value.questions.filter(isRecord).map((q): ProviderQuestion => ({\n question: typeof q.question === 'string' ? q.question : '',\n header: typeof q.header === 'string' ? q.header : undefined,\n multiSelect: q.multiSelect === true,\n options: Array.isArray(q.options)\n ? q.options.filter(isRecord).map((o) => ({\n label: typeof o.label === 'string' ? o.label : String(o.label ?? ''),\n description: typeof o.description === 'string' ? o.description : undefined,\n })).filter((o) => Boolean(o.label))\n : [],\n })).filter((q) => Boolean(q.question) && q.options.length > 0)\n : undefined\n return {\n id: value.id,\n provider: typeof value.provider === 'string' ? value.provider : undefined,\n kind: typeof value.kind === 'string' ? value.kind : undefined,\n title: typeof value.title === 'string' && value.title ? value.title : 'Permission request',\n body: typeof value.body === 'string' ? value.body : '',\n choices,\n ...(questions && questions.length ? { questions } : {}),\n }\n}\n\nexport function providerBlockedState(agent: Agent | null | undefined): ProviderRuntimeState | null {\n const state = providerRuntimeState(agent)\n return state?.state === 'blocked' ? state : null\n}\n\nexport function isPendingApprovalBadgeWorthy(approval: ProviderPendingApproval | null | undefined): boolean { return Boolean(approval?.id) }\n\nexport function agentNeedsHumanResponse(agent: Agent | null | undefined): boolean { return isPendingApprovalBadgeWorthy(providerBlockedState(agent)?.pendingApproval) }\n\nexport function activeSubagents(agent: Agent | null | undefined): ActiveSubagentInfo[] {\n const raw = agent?.meta?.activeSubagents\n if (!Array.isArray(raw)) {\n const count = typeof agent?.meta?.activeSubagentCount === 'number' ? agent.meta.activeSubagentCount : 0\n return count > 0 ? Array.from({ length: count }, (_, index) => ({ id: `subagent-${index + 1}`, label: `Subagent ${index + 1}` })) : []\n }\n return raw\n .filter(isRecord)\n .map((item, index) => {\n const id = typeof item.id === 'string' && item.id ? item.id : `subagent-${index + 1}`\n const role = typeof item.role === 'string' && item.role ? item.role : undefined\n const label = typeof item.label === 'string' && item.label ? item.label : role || id\n const startedAt = typeof item.startedAt === 'number' ? item.startedAt : undefined\n return { id, label, role, startedAt }\n })\n}\n\n// #502: a background shell (run_in_background) still running for this agent keeps\n// it busy even though its turn ended. The runner surfaces it as a `background-script`\n// work item in meta.activeWork carrying a human label (\"N background tasks\"); return\n// that label for a badge, or null when none are running.\nexport function activeBackgroundScriptLabel(agent: Agent | null | undefined): string | null {\n const raw = agent?.meta?.activeWork\n if (!Array.isArray(raw)) return null\n const item = raw.find((work) => isRecord(work) && work.kind === 'background-script')\n if (!item || !isRecord(item)) return null\n return typeof item.label === 'string' && item.label ? item.label : 'background script'\n}\n\nexport function agentPresence(\n now: number, agent: Agent | null | undefined, attention: AttentionInfo, pair: PairSession | null\n): PresenceInfo {\n const lifecycleAction = typeof agent?.meta?.lifecycleAction === 'string' ? agent.meta.lifecycleAction : ''\n const stale = isAgentStale(now, agent)\n const reconnecting = agent?.status !== 'offline' && !agent?.ready && stale\n const starting = agent?.status !== 'offline' && !agent?.ready && !stale\n const unreadIdle = attention.unread > 0 && agent?.status !== 'busy'\n const blocked = providerBlockedState(agent)\n const badges = presenceBadges(agent, attention, pair)\n\n if (agent?.status === 'offline') return { label: 'offline', tone: 'secondary', icon: 'PlugZap', stale: false, reconnecting: false, badges }\n // Pre-session-destroy window (#183): the runner is running end-of-session work before a\n // compact/clear/restart/shutdown. Distinct from plain \"busy\" and non-addressable.\n if (lifecycleAction.startsWith('finalizing-')) {\n return { label: `wrapping up (${lifecycleAction.slice('finalizing-'.length)})`, tone: 'warning', icon: 'Hourglass', stale, reconnecting, badges }\n }\n if (lifecycleAction === 'shutting-down') return { label: 'shutting down', tone: 'warning', icon: 'Power', stale, reconnecting, badges }\n if (lifecycleAction === 'killing') return { label: 'killing', tone: 'danger', icon: 'Power', stale, reconnecting, badges }\n if (lifecycleAction === 'restarting') return { label: 'restarting', tone: 'warning', icon: 'RefreshCw', stale, reconnecting, badges }\n if (agent?.status === 'stale') return { label: 'stale', tone: 'danger', icon: 'RefreshCw', stale: true, reconnecting: true, badges }\n if (reconnecting) return { label: 'reconnecting', tone: 'danger', icon: 'RefreshCw', stale, reconnecting, badges }\n if (starting) return { label: 'online, not ready', tone: 'warning', icon: 'Loader', stale, reconnecting, badges }\n if (blocked) return { label: `blocked: ${blocked.label}`, tone: 'danger', icon: 'AlertCircle', stale, reconnecting, badges }\n if (agent?.status === 'busy') {\n // #502: busy purely because a background shell outlived the turn (no active\n // provider turn / subagent) reads more truthfully as background work.\n const reasons = Array.isArray(agent?.meta?.busyReasons) ? agent.meta.busyReasons : []\n const backgroundOnly = activeBackgroundScriptLabel(agent) && !reasons.includes('provider-turn') && !reasons.includes('subagent')\n if (backgroundOnly) return { label: 'running background work', tone: 'warning', icon: 'Play', stale, reconnecting, badges }\n return { label: 'busy in turn', tone: 'warning', icon: 'Play', stale, reconnecting, badges }\n }\n if (pair?.status === 'active') return { label: 'paired', tone: 'success', icon: 'Link', stale, reconnecting, badges }\n if (unreadIdle) return { label: 'idle, unread', tone: 'danger', icon: 'Bell', stale, reconnecting, badges }\n return { label: agent?.status === 'idle' ? 'idle' : 'ready', tone: 'success', icon: 'CircleCheck', stale, reconnecting, badges }\n}\n\nfunction presenceBadges(agent: Agent | null | undefined, attention: AttentionInfo, pair: PairSession | null): PresenceBadge[] {\n const badges: PresenceBadge[] = []\n const blocked = providerBlockedState(agent)\n const subagentCount = activeSubagents(agent).length\n if (blocked) badges.push({ label: blocked.reason ? `blocked: ${blocked.reason}` : 'blocked', className: 'bg-red-500/20 text-red-400' })\n if (subagentCount) badges.push({ label: subagentCount === 1 ? '1 subagent' : subagentCount + ' subagents', className: 'bg-cyan-500/20 text-cyan-300' })\n const backgroundScriptLabel = activeBackgroundScriptLabel(agent)\n if (backgroundScriptLabel) badges.push({ label: backgroundScriptLabel, className: 'bg-indigo-500/20 text-indigo-300' })\n if (pair?.status === 'active') badges.push({ label: 'paired', className: 'bg-emerald-500/20 text-emerald-400' })\n if (pair?.status === 'pending') badges.push({ label: 'pair invite', className: 'bg-yellow-500/20 text-yellow-400' })\n if (attention.needsHumanResponse) badges.push({ label: 'needs response', className: 'bg-amber-500/20 text-amber-300' })\n if (attention.unread) badges.push({ label: attention.unread + ' unread', className: 'bg-red-500/20 text-red-400' })\n if (attention.claimableTasks) badges.push({ label: attention.claimableTasks + ' claimable', className: 'bg-orange-500/20 text-orange-400' })\n return badges\n}\n\nexport function emptyAttention(): AttentionInfo {\n return { unread: 0, needsHumanResponse: false, pendingPairInvite: false, claimableTasks: 0, total: 0, score: 0 }\n}\n\n\nexport function channelIsReady(channel: ChannelSummary | null): boolean {\n if (!channel || channel.status === 'offline') return false\n if (channel.targetHealth?.status === 'ok') return true\n if (channel.targetHealth?.status === 'error' || channel.targetHealth?.status === 'warning') return false\n return channel.ready\n}\n\nexport function channelPresence(channel: ChannelSummary | null): PresenceInfo {\n if (!channel) return { label: 'unknown', tone: 'secondary', icon: 'PlugZap', badges: [] }\n if (channel.targetHealth?.status === 'error') return { label: 'target broken', tone: 'danger', icon: 'AlertTriangle', badges: [] }\n if (channel.targetHealth?.status === 'warning') return { label: 'target warning', tone: 'warning', icon: 'AlertCircle', badges: [] }\n if (channel.status === 'offline') return { label: 'offline', tone: 'secondary', icon: 'PlugZap', badges: [] }\n if (channel.status === 'busy') return { label: 'busy', tone: 'warning', icon: 'Activity', badges: [] }\n if (!channelIsReady(channel)) return { label: 'not ready', tone: 'warning', icon: 'Loader', badges: [] }\n return { label: 'ready', tone: 'success', icon: 'CircleCheck', badges: [] }\n}\n\nexport function connectorPresence(connector: ConnectorSummary): PresenceInfo {\n const runtime = connector?.runtime || {}\n if (runtime.status === 'error') return { label: 'error', tone: 'danger', icon: 'AlertTriangle', badges: [] }\n if (runtime.status === 'warn') return { label: 'warning', tone: 'warning', icon: 'AlertCircle', badges: [] }\n if (runtime.running) return { label: 'running', tone: 'success', icon: 'CircleCheck', badges: [] }\n if (runtime.enabled === false) return { label: 'disabled', tone: 'secondary', icon: 'Pause', badges: [] }\n if (runtime.status === 'ok') return { label: 'ok', tone: 'success', icon: 'CircleCheck', badges: [] }\n return { label: 'unknown', tone: 'secondary', icon: 'HelpCircle', badges: [] }\n}\n\nexport function integrationPresence(integration: IntegrationSummary): PresenceInfo {\n const stats = integration?.taskStats || {}\n if ((stats.waitingTasks || 0) > 0) return { label: 'waiting', tone: 'warning', icon: 'AlertCircle', badges: [] }\n if ((stats.openTasks || 0) > 0) return { label: 'active', tone: 'info', icon: 'Activity', badges: [] }\n if (!integration?.configured) return { label: 'observed only', tone: 'secondary', icon: 'Eye', badges: [] }\n if (integration.observed) return { label: 'quiet', tone: 'success', icon: 'CircleCheck', badges: [] }\n return { label: 'configured', tone: 'primary', icon: 'PlugZap', badges: [] }\n}\n\nexport function orchestratorHealthLabel(orch: Orchestrator): string {\n const health = orch?.health\n if (!health || health.status === 'ok') return orch?.version || orch?.package?.version ? 'compatible' : 'unknown version'\n if (health.status === 'upgrade-required') return 'upgrade required'\n if (health.status === 'restart-required') return 'restart required'\n if (health.status === 'unknown') return 'unknown contract'\n if ((health.issues || []).some((i) => i.code === 'protocol-mismatch')) return 'protocol mismatch'\n if ((health.issues || []).some((i) => i.code === 'package-drift')) return 'package drift'\n if (health.restartRequired) return 'restart required'\n return health.status\n}\n\nexport function orchestratorHealthClass(orch: Orchestrator): string {\n const status = orch?.health?.status\n if (status === 'upgrade-required') return 'text-red-400 bg-red-500/10'\n if (status === 'warn' || status === 'restart-required') return 'text-yellow-400 bg-yellow-500/10'\n if (status === 'unknown') return 'text-zinc-400 bg-zinc-500/10'\n return 'text-emerald-400 bg-emerald-500/10'\n}\n\nexport function timeAgo(now: number, iso: string | number | null | undefined): string {\n if (!iso) return ''\n const ts = new Date(iso as string).getTime()\n if (!Number.isFinite(ts)) return ''\n const diff = Math.max(0, (now - ts) / 1000)\n if (diff < 60) return Math.floor(diff) + 's ago'\n if (diff < 3600) return Math.floor(diff / 60) + 'm ago'\n if (diff < 86400) return Math.floor(diff / 3600) + 'h ago'\n return Math.floor(diff / 86400) + 'd ago'\n}\n\nexport function fmtTime(iso: string | number | null | undefined): string {\n if (!iso) return ''\n return new Date(iso as string).toLocaleString()\n}\n\nexport function safeFilename(value: string): string {\n return String(value || 'export').replace(/[^a-z0-9._-]+/gi, '-').replace(/^-+|-+$/g, '').slice(0, 80) || 'export'\n}\n\nexport function healthDiagnostics(checks: HealthCheck[]): HealthDiagnostic[] {\n return checks.filter((c) => c.status !== 'ok').map((check) => {\n const base: HealthDiagnostic = {\n name: check.name,\n status: check.status,\n detail: check.detail || check.name,\n impact: healthImpact(check),\n subjects: check.subjects || [],\n actions: [\n { label: 'Inspect logs', icon: 'FileSearch', copy: 'agent-relay daemon logs' },\n { label: 'Restart daemon', icon: 'RefreshCw', copy: 'agent-relay daemon restart' },\n { label: 'Copy env', icon: 'Copy', copy: 'agent-relay doctor' },\n ],\n }\n if (check.name === 'stale-live-agents') {\n base.actions.unshift(\n { label: 'Run reaper', icon: 'Eraser', api: 'POST', path: '/system/reap' },\n { label: 'Show stale', icon: 'Filter', view: 'agents', preset: 'offline_stale' },\n )\n } else if (check.name === 'channel-delivery-targets') {\n base.actions.unshift(\n { label: 'Open channels', icon: 'MessagesSquare', view: 'channels' },\n { label: 'Run reaper', icon: 'Eraser', api: 'POST', path: '/system/reap' },\n )\n } else if (['expired-message-claims', 'expired-task-claims', 'offline-claimed-tasks'].includes(check.name)) {\n base.actions.unshift(\n { label: 'Run reaper', icon: 'Eraser', api: 'POST', path: '/system/reap' },\n { label: 'Open work', icon: 'ListChecks', view: 'work' },\n )\n }\n return base\n })\n}\n\nfunction healthImpact(check: HealthCheck): string {\n const impacts: Record<string, string> = {\n 'database': 'Relay persistence is unavailable; messages, state, and audit writes may fail.',\n 'stale-live-agents': 'Agents may look online even though their heartbeat has stopped.',\n 'expired-message-claims': 'Claimable messages may be stuck until the reaper releases expired claims.',\n 'expired-task-claims': 'Tasks can appear owned by agents that no longer hold a live lease.',\n 'offline-claimed-tasks': 'Offline agents are still shown as owners for active work.',\n 'channel-delivery-targets': 'Inbound channel messages may be accepted but routed to no live delivery agent.',\n }\n return impacts[check.name] || 'Relay health is degraded for this check.'\n}\n\nfunction toneToBadgeVariant(tone: string): 'default' | 'secondary' | 'destructive' | 'outline' {\n if (tone === 'danger' || tone === 'destructive') return 'destructive'\n if (tone === 'secondary') return 'secondary'\n return 'default'\n}\n\nexport function toneToColor(tone: string): string {\n const map: Record<string, string> = {\n success: 'text-emerald-400',\n warning: 'text-yellow-400',\n danger: 'text-red-400',\n info: 'text-blue-400',\n primary: 'text-blue-400',\n secondary: 'text-zinc-400',\n }\n return map[tone] || 'text-zinc-400'\n}\n\nfunction toneToBg(tone: string): string {\n const map: Record<string, string> = {\n success: 'bg-emerald-500',\n warning: 'bg-yellow-500',\n danger: 'bg-red-500',\n info: 'bg-blue-500',\n primary: 'bg-blue-500',\n secondary: 'bg-zinc-500',\n }\n return map[tone] || 'bg-zinc-500'\n}\n\nexport function statusDotColor(agent: Agent | null, now?: number): string {\n if (!agent) return 'bg-zinc-500 opacity-50'\n if (agent.status === 'offline') return 'bg-zinc-500 opacity-50'\n if (typeof agent.meta?.lifecycleAction === 'string' && agent.meta.lifecycleAction.startsWith('finalizing-')) return 'bg-amber-500 animate-pulse'\n if (agent.meta?.lifecycleAction === 'shutting-down' || agent.meta?.lifecycleAction === 'restarting') return 'bg-yellow-500 animate-pulse'\n if (agent.meta?.lifecycleAction === 'killing') return 'bg-red-500 animate-pulse'\n if (providerBlockedState(agent)) return 'bg-red-500 animate-pulse'\n if (agent.status === 'busy') return 'bg-yellow-500'\n if (now && isAgentStale(now, agent)) return 'bg-red-500 animate-pulse'\n if (!agent.ready) return 'bg-emerald-500 animate-pulse'\n return 'bg-emerald-500 shadow-[0_0_6px_theme(colors.emerald.500)]'\n}\n\nexport function downloadText(filename: string, text: string, type: string) {\n if (typeof document === 'undefined' || typeof URL === 'undefined' || typeof Blob === 'undefined') return\n const url = URL.createObjectURL(new Blob([text], { type }))\n const link = document.createElement('a')\n link.href = url\n link.download = filename\n link.click()\n URL.revokeObjectURL(url)\n}\n"],"mappings":"kFAGA,IAAa,EAAiB,OACjB,EAAoB,EACpB,EAAkB,IAKlB,EAAuB,IAAI,IAAI,CAAC,OAAQ,SAAU,WAAW,CAAC,CAC9D,GAAwB,IAAI,IAAI,CAAC,OAAQ,UAAU,CAAC,CAEpD,GAA4C,CAAE,OAAQ,EAAG,KAAM,EAAG,KAAM,EAAG,QAAS,EAAG,CACvF,EAAiD,CAAE,KAAM,EAAG,OAAQ,EAAG,KAAM,EAAG,QAAS,EAAG,CAE5F,EAAgC,CAAE,KAAM,GAAI,GAAI,GAAI,KAAM,GAAI,QAAS,GAAI,QAAS,GAAI,UAAW,GAAO,CAC1G,EAA2C,CAAE,OAAQ,QAAS,GAAI,GAAI,KAAM,GAAI,QAAS,GAAI,QAAS,GAAI,UAAW,GAAO,CAC5H,EAAyC,CAAE,OAAQ,GAAI,KAAM,GAAI,KAAM,GAAI,QAAS,GAAI,CACxF,EAAuC,CAAE,YAAa,GAAI,SAAU,GAAI,UAAW,GAAI,CAK9F,EAA4C,CAChD,KAAM,OACN,OAAQ,SACR,QAAS,iBACT,MAAO,MACR,CAEK,EAA6C,CACjD,KAAM,iBACN,OAAQ,SACR,QAAS,UACT,MAAO,QACR,EAEuD,CACtD,GAAG,EACH,GAAG,OAAO,YAAY,GAAqB,CAAC,IAAK,GAAO,CAAC,EAAI,MAAM,CAAC,CAAC,CACtE,EAEwD,CACvD,GAAG,EACH,GAAG,OAAO,YAAY,GAAqB,CAAC,IAAK,GAAO,CAAC,EAAI,GAAG,EAAiB,EAAG,CAAC,QAAQ,CAAC,CAAC,CAChG,CAED,IAAa,EAAmE,CAC9E,CAAE,IAAK,WAAY,MAAO,WAAY,KAAM,kBAAmB,CAC/D,CAAE,IAAK,OAAQ,MAAO,OAAQ,KAAM,gBAAiB,CACrD,CAAE,IAAK,SAAU,MAAO,SAAU,KAAM,MAAO,CAC/C,CAAE,IAAK,UAAW,MAAO,iBAAkB,KAAM,WAAY,CAC7D,CAAE,IAAK,QAAS,MAAO,QAAS,KAAM,QAAS,CAC/C,CAAE,IAAK,WAAY,MAAO,iBAAkB,KAAM,UAAW,CAC7D,CAAE,IAAK,gBAAiB,MAAO,gBAAiB,KAAM,SAAU,CAChE,CAAE,IAAK,aAAc,MAAO,aAAc,KAAM,YAAa,CAC7D,CAAE,IAAK,QAAS,MAAO,QAAS,KAAM,aAAc,CACpD,CAAE,IAAK,WAAY,MAAO,WAAY,KAAM,iBAAkB,CAC9D,CAAE,IAAK,aAAc,MAAO,aAAc,KAAM,OAAQ,CACxD,CAAE,IAAK,eAAgB,MAAO,eAAgB,KAAM,UAAW,CAC/D,CAAE,IAAK,WAAY,MAAO,WAAY,KAAM,SAAU,CACtD,CAAE,IAAK,SAAU,MAAO,SAAU,KAAM,eAAgB,CACxD,CAAE,IAAK,WAAY,MAAO,WAAY,KAAM,WAAY,CACxD,CAAE,IAAK,QAAS,MAAO,QAAS,KAAM,OAAQ,CAC9C,CAAE,IAAK,WAAY,MAAO,WAAY,KAAM,OAAQ,CACpD,CAAE,IAAK,OAAQ,MAAO,aAAc,KAAM,aAAc,CACxD,CAAE,IAAK,QAAS,MAAO,QAAS,KAAM,gBAAiB,CACvD,CAAE,IAAK,aAAc,MAAO,aAAc,KAAM,gBAAiB,CACjE,CAAE,IAAK,YAAa,MAAO,YAAa,KAAM,YAAa,CAC3D,CAAE,IAAK,WAAY,MAAO,WAAY,KAAM,YAAa,CACzD,CAAE,IAAK,WAAY,MAAO,WAAY,KAAM,QAAS,CACrD,CAAE,IAAK,UAAW,MAAO,UAAW,KAAM,WAAY,CACtD,CAAE,IAAK,WAAY,MAAO,WAAY,KAAM,cAAe,CAC3D,CAAE,IAAK,cAAe,MAAO,cAAe,KAAM,SAAU,CAC5D,CAAE,IAAK,WAAY,MAAO,WAAY,KAAM,WAAY,CACzD,CAEY,EAA0C,CACrD,SAAU,6BACV,QAAS,mCACT,KAAM,+BACP,CAEY,GAA6C,CACxD,OAAQ,qCACR,QAAS,mCACT,MAAO,+BACP,SAAU,6BACV,QAAS,6BACV,CChFD,SAAgB,GAAY,EAAwB,CAClD,IAAM,EAAK,OAAO,GAAU,SAAW,EAAQ,IAAI,KAAM,GAAoB,EAAE,CAAC,SAAS,CACzF,OAAO,OAAO,SAAS,EAAG,CAAG,EAAK,EAGpC,IAAM,GAAwB,CAAC,aAAc,YAAa,gBAAgB,CAEpE,GAAiD,CACrD,KAAM,KACN,OAAQ,KACR,SAAU,KACV,aAAc,KACd,YAAa,KACb,cAAe,KACf,UAAW,KACX,cAAe,KACf,SAAU,KACV,aAAc,KACd,KAAM,KACN,SAAU,KACV,MAAO,KACP,UAAW,KACX,SAAU,KACV,UAAW,KACX,cAAe,KACf,MAAO,IACP,UAAW,IACX,UAAW,IACX,cAAe,IACf,iBAAkB,IAClB,qBAAsB,IACtB,KAAM,KACN,SAAU,KACX,CAED,SAAgB,EAAuB,EAAuB,CAC5D,IAAM,EAAU,EAAM,MAAM,CAC5B,OAAO,GAAuB,EAAQ,aAAa,GAAK,EAG1D,SAAgB,GAAuB,EAA0B,CAC/D,OAAO,EAAK,OAAQ,GAAM,CAAC,GAAsB,KAAM,GAAM,EAAE,WAAW,EAAE,CAAC,CAAC,CAGhF,SAAgB,GAAU,EAAgC,EAAW,EAAW,CAC9E,GAAI,CAAC,EAAK,MAAO,GACjB,IAAM,EAAQ,EAAI,QAAQ,OAAQ,GAAG,CAAC,MAAM,IAAI,CAChD,OAAO,EAAM,QAAU,EAAW,EAAM,EAAM,MAAM,CAAC,EAAS,CAAC,KAAK,IAAI,CAG1E,SAAgB,EAAwB,EAAsB,CAC5D,OAAO,EAAK,MAAM,CAAC,QAAQ,MAAO,IAAI,CAAC,QAAQ,OAAQ,GAAG,EAAI,IAGhE,SAAgB,GAAe,EAAiC,EAA6C,CAC3G,GAAI,CAAC,GAAM,MAAM,EAAI,CAAC,GAAS,MAAM,CAAE,MAAO,GAC9C,IAAM,EAAiB,EAAwB,EAAK,CAC9C,EAAiB,EAAwB,EAAQ,CAGvD,OAFI,IAAmB,IAAY,EAAe,WAAW,IAAI,CAC7D,IAAmB,IAAY,GAC5B,IAAmB,GAAkB,EAAe,WAAW,EAAiB,IAAI,CAG7F,SAAS,EAAe,EAA0C,CAChE,OAAO,GAAO,MAAM,UAAY,IAAQ,GAAO,KAAA,QAAyB,GAAO,KAAO,SAGxF,SAAS,EAAe,EAA0C,CAChE,IAAM,EAAO,GAAO,MAAQ,EAAE,CACxB,EAAO,GAAO,cAAgB,EAAE,CAChC,EAAa,OAAO,GAAO,MAAM,YAAe,SAAW,EAAM,KAAK,WAAa,GACzF,OAAO,GAAO,OAAS,WACrB,GAAO,MAAM,OAAS,WACtB,EAAK,SAAS,UAAU,EACxB,EAAK,KAAM,GAAQ,EAAI,WAAW,WAAW,CAAC,EAC9C,EAAK,SAAS,UAAU,EACxB,EAAK,KAAM,GAAQ,EAAI,WAAW,WAAW,CAAC,EAC9C,EAAK,SAAS,WAAW,EACzB,EAAK,SAAS,WAAW,EACzB,IAAe,gBAGnB,SAAS,EAAkB,EAA0C,CACnE,MAAO,GACL,OAAO,GAAO,MAAM,cAAiB,UACrC,OAAO,GAAO,MAAM,iBAAoB,UACxC,GAAO,MAAM,SAAS,aAAa,EAIvC,SAAS,EAAc,EAA0C,CAC/D,OAAO,EAAe,EAAM,EAAI,EAAe,EAAM,EAAI,EAAkB,EAAM,CAGnF,SAAgB,EAAU,EAA4C,CACpE,GAAI,GAAO,KAAA,OAAuB,MAAO,OACzC,GAAI,GAAO,KAAO,SAAU,MAAO,SACnC,GAAI,EAAe,EAAM,CAAE,MAAO,UAElC,IAAM,EAAiB,GAAqB,CAItC,EAAW,OAAO,GAAO,MAAM,UAAa,SAAW,EAAM,KAAK,SAAS,aAAa,CAAG,IAAA,GACjG,GAAI,GAAY,EAAe,SAAS,EAAS,CAAE,OAAO,EAI1D,IAAM,EAAS,CACb,GAAI,GAAO,MAAQ,EAAE,CACrB,GAAO,MAAM,OACb,GAAO,MAAM,QACb,GAAO,MAAM,UACd,CACE,OAAQ,GAAmB,OAAO,GAAM,SAAS,CACjD,IAAK,GAAM,EAAE,aAAa,CAAC,CAE9B,IAAK,IAAM,KAAO,EAChB,GAAI,EAAO,KAAM,GAAM,EAAE,SAAS,EAAI,CAAC,CAAE,OAAO,EAElD,MAAO,QAWT,SAAgB,EAAa,EAAa,EAA0C,CAElF,GADI,CAAC,GAAO,UAAY,EAAM,SAAW,WACrC,EAAM,KAAO,QAAU,EAAM,KAAO,SAAU,MAAO,GAKzD,IAAM,EAAY,EAAM,MAAM,UAC9B,GAAI,EAAS,EAAU,EAAI,EAAU,YAAc,GAAM,MAAO,GAChE,IAAM,EAAa,IAAI,KAAK,EAAM,SAAmB,CAAC,SAAS,CAE/D,OADK,OAAO,SAAS,EAAW,CACzB,EAAM,EAAa,IADe,GAM3C,SAAgB,EAA2B,EAAiC,EAAqC,CAE/G,GADI,CAAC,GAAS,EAAe,EAAM,EAAI,EAAe,EAAM,EACxD,IAAW,SAAU,MAAO,GAEhC,GAAI,IAAW,YAAa,OAAO,EAAM,sBAAsB,aAAa,YAAc,IAAQ,EAAM,SAAW,OAEnH,GADkB,EAAyB,EAAM,GAAK,IAAW,WAAa,IAAW,YAAc,IAAW,WAAa,IAAW,iBACzH,CAAC,EAAoB,EAAM,CAAE,MAAO,GACrD,IAAM,EAAY,EAAM,sBAAsB,UAC9C,GAAI,EAAW,CACb,GAAI,IAAW,UAAW,OAAO,EAAU,cAAgB,GAC3D,GAAI,IAAW,WAAY,OAAO,EAAU,eAAiB,GAC7D,GAAI,IAAW,YAAa,OAAO,EAAU,YAAc,GAI7D,OAFI,IAAW,UAAkB,EAAM,sBAAsB,SAAS,UAAY,GAC9E,IAAW,eAAuB,EAAM,sBAAsB,SAAS,QAAU,GAC9E,EAAM,MAAM,gBAAkB,KAAS,IAAW,WAAa,IAAW,YAGnF,SAAS,EAAoB,EAAuB,CAClD,OAAO,OAAO,EAAM,MAAM,aAAgB,UAAY,EAAM,KAAK,YAAY,MAAM,CAAC,OAAS,EAG/F,SAAS,EAAyB,EAA0C,CAE1E,OADiB,OAAO,GAAO,MAAM,UAAa,SAAW,EAAoB,EAAM,KAAK,SAAmB,CAAG,IAAA,KACjG,oBAAoB,UAAU,OAAS,OAG1D,SAAS,EAA4B,EAA0C,CAC7E,OAAO,EAA2B,EAAO,UAAU,EACjD,EAA2B,EAAO,WAAW,EAC7C,EAA2B,EAAO,YAAY,EAC9C,EAA2B,EAAO,UAAU,EAC5C,EAA2B,EAAO,eAAe,CAGrD,SAAgB,EAAoB,EAA0C,CAC5E,MAAO,GAAQ,GAAS,CAAC,EAAe,EAAM,EAAI,CAAC,EAAe,EAAM,EAAI,CAAC,EAA4B,EAAM,GAAK,EAAM,SAAW,WAAa,EAAM,SAAW,UAGrK,SAAS,EAA6B,EAAc,EAAiD,CACnG,GAAI,EAAM,SAAW,UAAW,MAAO,GACvC,IAAM,EAAa,OAAO,EAAM,MAAM,YAAe,SAAW,EAAM,KAAK,WAAa,GACxF,GAAI,CAAC,EAAY,MAAO,GACxB,IAAM,EAAS,EAAgB,KAAM,GAAS,EAAK,OAAO,OAAS,EAAW,CAC9E,MAAO,GAAQ,GAAQ,MAAM,SAAW,EAAO,MAAM,UAAY,EAAM,IAGzE,SAAgB,EAAc,EAAiB,EAAuB,EAAyC,EAAE,CAAW,CAC1H,IAAM,EAAsB,EAAO,OAAQ,GAAM,CAAC,EAA6B,EAAG,EAAgB,CAAC,CACnG,OAAO,EAAe,EAAsB,EAAoB,OAAQ,GAAM,CAAC,EAAc,EAAE,CAAC,CAGlG,SAAgB,EAAY,EAAyC,CAEnE,OADK,EACE,EAAM,OAAS,EAAM,MAAQ,EAAM,GAAG,MAAM,IAAI,CADpC,IAOrB,SAAgB,EAAY,EAA6B,EAAmD,CAC1G,IAAM,EAAS,EAAkB,EAAQ,CACzC,OAAO,EAAS,EAAU,GAAU,IAAA,GAMtC,SAAgB,EAAiB,EAA6B,EAAyC,CACrG,IAAM,EAAO,EAAY,EAAS,EAAU,CAC5C,OAAO,GAAM,aAAa,MAAM,EAAI,GAAM,QAAQ,MAAM,EAAI,OAM9D,IAAM,EAAuB,CAC3B,eAAgB,iBAAkB,mBAAoB,kBAAmB,gBAAiB,gBAC3F,CACD,SAAgB,EAAiB,EAAqC,CACpE,IAAM,EAAS,EAAkB,EAAQ,EAAI,GACzC,EAAO,EACX,IAAK,IAAI,EAAI,EAAG,EAAI,EAAO,OAAQ,IAAK,EAAQ,EAAO,GAAK,EAAO,WAAW,EAAE,GAAM,EACtF,OAAO,EAAqB,EAAO,EAAqB,QAG1D,SAAgB,EAAc,EAAgB,EAA2C,CACvF,GAAI,CAAC,EAAQ,MAAO,IACpB,GAAI,IAAW,YAAa,MAAO,YACnC,GAAI,EAAO,WAAW,OAAO,CAAE,MAAO,IAAM,EAAO,MAAM,EAAE,CAC3D,GAAI,EAAO,WAAW,OAAO,CAAE,OAAO,EAAO,MAAM,EAAE,CACrD,GAAI,EAAO,WAAW,SAAS,CAAE,OAAO,EAAO,MAAM,EAAE,CACvD,GAAI,EAAO,WAAW,QAAQ,CAAE,CAC9B,IAAM,EAAS,EAAO,MAAM,EAAE,CACxB,EAAS,OAAO,OAAO,EAAW,CAAC,KAAM,GAAM,EAAE,SAAW,EAAO,CACzE,OAAO,EAAS,QAAQ,EAAY,EAAO,GAAK,QAAQ,EAAO,MAAM,GAAG,GAE1E,IAAM,EAAQ,EAAW,GACzB,OAAO,EAAQ,EAAY,EAAM,CAAG,EAAO,MAAM,GAAG,CAGtD,SAAgB,EAAY,EAAyC,CACnE,GAAI,CAAC,EAAK,MAAO,GACjB,IAAM,EAAU,EAAI,SAAW,EAAE,CAC3B,EAAiB,EAAQ,QAC/B,GAAI,GAAkB,OAAO,GAAmB,UAAY,OAAO,EAAe,MAAS,UAAa,EAAe,KAAgB,MAAM,CAC3I,OAAO,EAAe,KAExB,IAAM,EAAc,EAAQ,YAC5B,GAAI,GAAe,OAAO,GAAgB,SAAU,CAClD,IAAM,EAAQ,OAAO,EAAY,OAAU,SAAW,EAAY,MAAM,MAAM,CAAG,GAC3E,EAAc,OAAO,EAAY,aAAgB,SAAW,EAAY,YAAY,MAAM,CAAG,GACnG,GAAI,GAAS,EAAa,OAAO,EAAQ;EAAO,EAChD,GAAI,EAAO,OAAO,EAClB,GAAI,EAAa,OAAO,EAE1B,IAAM,EAAW,EAAQ,SACzB,GAAI,GAAY,OAAO,GAAa,SAAU,CAC5C,IAAM,EAAO,OAAO,EAAS,MAAS,SAAW,EAAS,KAAO,GAC3D,EAAQ,OAAO,EAAS,OAAU,SAAW,EAAS,MAAQ,GAC9D,EAAQ,OAAO,EAAS,OAAU,SAAW,EAAS,MAAQ,GAEpE,MAAO,CAAC,WADa,EAAuB,GAAS,GAAQ,EACzC,CAAa,CAAC,OAAO,QAAQ,CAAC,KAAK,KAAK,CAE9D,IAAM,EAAW,EAAQ,SAQzB,OAPI,GAAY,OAAO,GAAa,SAG3B,CAFM,OAAO,EAAS,MAAS,SAAW,EAAS,KAAO,WACnD,OAAO,EAAS,OAAU,SAAW,EAAS,MAAQ,GAChD,CAAC,OAAO,QAAQ,CAAC,KAAK,IAAI,CAE5C,OAAO,EAAQ,MAAS,UAAa,EAAQ,KAAgB,MAAM,CAAS,EAAQ,KACpF,OAAO,EAAQ,SAAY,UAAa,EAAQ,QAAmB,MAAM,CAAS,EAAQ,QACvF,EAAoB,EAAI,MAAQ,GAAG,GAAK,EAAI,MAAQ,IAG7D,SAAgB,EAAuB,EAA0C,CAC/E,GAAI,CAAC,GAAK,QAAS,MAAO,GAC1B,IAAM,EAAQ,EAAI,QAAQ,MAC1B,OAAO,EAAI,QAAQ,uBAAyB,IAAQ,GAAO,OAAS,mBAStE,SAAgB,EAAc,EAAqC,CACjE,GAAI,CAAC,EAAM,OAAO,KAClB,IAAM,EAAU,EAAK,MAAM,CAC3B,GAAI,CAAC,EAAQ,WAAW,IAAI,CAAE,OAAO,KACrC,GAAI,CACF,IAAM,EAAM,KAAK,MAAM,EAAQ,CAC/B,GAAI,OAAO,GAAQ,WAAY,GAAgB,MAAM,QAAQ,EAAI,CAAE,OAAO,KAC1E,IAAM,EAAO,OAAO,EAAI,MAAS,SAAW,EAAI,KAC5C,OAAO,EAAI,SAAY,SAAW,EAAI,QACtC,KACJ,GAAI,CAAC,GAAM,MAAM,CAAE,OAAO,KAC1B,IAAM,EAAW,IAAI,IAAI,CAAC,OAAQ,UAAU,CAAC,CAI7C,MAAO,CAAE,OAAM,KAHF,OAAO,QAAQ,EAAI,CAC7B,QAAQ,CAAC,EAAG,KAAO,CAAC,EAAS,IAAI,EAAE,GAAK,OAAO,GAAM,UAAY,OAAO,GAAM,UAAY,OAAO,GAAM,WAAW,CAClH,KAAK,CAAC,EAAG,KAAO,CAAC,EAAG,OAAO,EAAE,CAAC,CAClB,CAAM,IAAK,EAAK,MACzB,CACN,OAAO,MAIX,SAAS,EAAoB,EAA6B,CAExD,OADe,EAAc,EACtB,EAAQ,MAAQ,KAGzB,SAAgB,EAAe,EAAyC,CACtE,IAAM,EAAO,GAAK,SAAW,EAAY,EAAI,EAAI,GACjD,OAAO,EAAK,OAAS,GAAK,EAAK,MAAM,EAAG,GAAG,CAAG,MAAQ,EAOxD,SAAgB,GAAU,EAAsB,CAG9C,OAFI,EAAe,EAAI,KAAK,EAAI,EAAI,GAAW,EAAI,GAC/C,EAAe,EAAI,GAAG,EAAI,EAAI,KAAa,EAAI,KAC5C,GAGT,SAAgB,EAAsB,EAAuB,CAC3D,OAAO,EAAe,EAAI,GAAG,EAAI,CAAC,EAAe,EAAI,KAAK,CAG5D,SAAgB,GAAsB,EAAuB,CAC3D,GAAI,EAAI,OAAS,UAAW,MAAO,GACnC,IAAM,EAAQ,EAAI,SAAS,SAA2C,KACtE,OAAO,IAAS,aAAe,IAAS,OAG1C,SAAgB,EAAc,EAAuB,CACnD,OAAO,EAAI,OAAS,WAAa,EAA0B,EAAI,QAAQ,CAQzE,SAAgB,GAA0B,EAAc,EAAwB,CAC9E,IAAM,EAAI,EAAK,MAAM,CACf,EAAI,EAAM,MAAM,CAGtB,OAFK,EACD,IAAM,EAAU,GACb,EAAE,WAAW,GAAG,EAAE,MAAM,EAAI,EAAE,SAAS,OAAO,IAAI,EAAI,EAAE,SAAS,OAAO,EAAE,MAAM,CAFxE,GAKjB,SAAgB,GAAqB,EAAqC,EAAc,EAAuB,CAG7G,GAFI,CAAC,EAAsB,EAAI,EAC3B,CAAC,EAAc,EAAI,GAClB,EAAI,QAAU,EAAE,EAAE,SAAA,OAAwB,CAAE,MAAO,GACxD,IAAM,EAAS,OAAO,EAAY,IAAS,EAAE,CAC7C,OAAO,EAAI,IAAM,OAAO,SAAS,EAAO,CAAG,EAAS,GAGtD,SAAgB,GAAuB,EAAqB,CAE1D,OAAQ,EAAK,MAAQ,WAAa,SAAW,GAAsB,IAAI,EAAK,OAAO,EAAI,CAAC,EAAK,UAG/F,SAAgB,GAA0B,EAAuB,CAC/D,MAAO,GAAQ,EAAI,WAAa,CAAC,EAAI,WAAa,EAAE,EAAI,OAAS,QAAU,OAAO,cAAe,EAAI,SAAqC,OAAO,GAGnJ,SAAgB,GAA4B,EAAgB,EAAuB,CAOjF,MANI,CAAC,GAAU,CAAC,EAAc,GAC1B,IAAW,aAAe,IAAW,EAAM,GAAW,GACtD,EAAO,WAAW,OAAO,EAAU,EAAM,MAAQ,EAAE,EAAE,SAAS,EAAO,MAAM,EAAE,CAAC,CAC9E,EAAO,WAAW,OAAO,EAAU,EAAM,cAAgB,EAAE,EAAE,SAAS,EAAO,MAAM,EAAE,CAAC,CACtF,EAAO,WAAW,SAAS,CAAS,EAAM,QAAU,EAAO,MAAM,EAAE,CACnE,EAAO,WAAW,QAAQ,CAAS,EAAM,SAAW,EAAO,MAAM,EAAE,CAChE,GAGT,SAAgB,GAAwB,EAAiB,EAA2B,CAIlF,OAHK,EACD,EAAQ,OAAS,GAAW,EAAQ,KAAO,GAC3C,EAAQ,kBAAoB,EAFX,GAMvB,SAAgB,GAAsB,EAAkB,EAAkC,CACxF,GAAI,CAAC,GAAW,CAAC,EAAS,MAAO,GACjC,IAAM,EAAc,CAAC,EAAQ,GAAI,EAAQ,KAAM,GAAI,EAAQ,eAAiB,EAAE,CAAE,CAAC,OAAO,QAAQ,CAChG,GAAI,EAAQ,SAAW,EAAY,SAAS,EAAQ,QAAQ,CAAE,MAAO,GACrE,IAAM,EAAiB,EAAQ,SAAS,QACxC,GAAI,GAAkB,OAAO,GAAmB,SAAU,CACxD,IAAM,EAAO,CAAC,EAAe,QAAS,EAAe,SAAU,EAAe,UAAU,CAAC,OAAO,QAAQ,CACxG,GAAI,EAAK,SAAS,EAAQ,GAAG,EAAI,EAAK,SAAS,EAAQ,KAAK,EAAK,EAAQ,WAAa,EAAK,SAAS,EAAQ,UAAU,CAAG,MAAO,GAGlI,MADA,GAAI,EAAQ,UAAY,EAAQ,OAAS,EAAQ,SAAW,EAAQ,KAAO,EAAQ,UAmDrF,SAAgB,EAAqB,EAA8D,CACjG,IAAM,EAAM,GAAO,MAAM,cAEzB,MADI,CAAC,EAAS,EAAI,EAAI,OAAO,EAAI,OAAU,SAAiB,KACrD,CACL,MAAO,EAAI,MACX,OAAQ,OAAO,EAAI,QAAW,SAAW,EAAI,OAAS,IAAA,GACtD,MAAO,OAAO,EAAI,OAAU,UAAY,EAAI,MAAQ,EAAI,MAAQ,EAAI,MACpE,kBAAmB,OAAO,EAAI,mBAAsB,SAAW,EAAI,kBAAoB,IAAA,GACvF,OAAQ,OAAO,EAAI,QAAW,SAAW,EAAI,OAAS,IAAA,GACtD,IAAK,EAAI,IACT,UAAW,OAAO,EAAI,WAAc,SAAW,EAAI,UAAY,IAAA,GAC/D,gBAAiB,GAAwB,EAAI,gBAAgB,CAC9D,CAGH,SAAS,GAAwB,EAAqD,CACpF,GAAI,CAAC,EAAS,EAAM,EAAI,OAAO,EAAM,IAAO,SAAU,OACtD,IAAM,EAAU,MAAM,QAAQ,EAAM,QAAQ,CACxC,EAAM,QAAQ,OAAO,EAAS,CAAC,IAAK,IAAY,CAChD,GAAI,EAAO,GACX,MAAO,OAAO,EAAO,OAAU,SAAW,EAAO,MAAQ,OAAO,EAAO,IAAM,GAAG,CACjF,EAAE,CAAC,OAAQ,IACT,EAAO,KAAO,WAAa,EAAO,KAAO,mBAAqB,EAAO,KAAO,QAAU,EAAO,KAAO,UAAY,EAAQ,EAAO,MACjI,CACC,EAAE,CACA,EAAY,MAAM,QAAQ,EAAM,UAAU,CAC5C,EAAM,UAAU,OAAO,EAAS,CAAC,IAAK,IAAyB,CAC/D,SAAU,OAAO,EAAE,UAAa,SAAW,EAAE,SAAW,GACxD,OAAQ,OAAO,EAAE,QAAW,SAAW,EAAE,OAAS,IAAA,GAClD,YAAa,EAAE,cAAgB,GAC/B,QAAS,MAAM,QAAQ,EAAE,QAAQ,CAC7B,EAAE,QAAQ,OAAO,EAAS,CAAC,IAAK,IAAO,CACvC,MAAO,OAAO,EAAE,OAAU,SAAW,EAAE,MAAQ,OAAO,EAAE,OAAS,GAAG,CACpE,YAAa,OAAO,EAAE,aAAgB,SAAW,EAAE,YAAc,IAAA,GAClE,EAAE,CAAC,OAAQ,GAAM,EAAQ,EAAE,MAAO,CACjC,EAAE,CACP,EAAE,CAAC,OAAQ,GAAM,EAAQ,EAAE,UAAa,EAAE,QAAQ,OAAS,EAAE,CAC5D,IAAA,GACJ,MAAO,CACL,GAAI,EAAM,GACV,SAAU,OAAO,EAAM,UAAa,SAAW,EAAM,SAAW,IAAA,GAChE,KAAM,OAAO,EAAM,MAAS,SAAW,EAAM,KAAO,IAAA,GACpD,MAAO,OAAO,EAAM,OAAU,UAAY,EAAM,MAAQ,EAAM,MAAQ,qBACtE,KAAM,OAAO,EAAM,MAAS,SAAW,EAAM,KAAO,GACpD,UACA,GAAI,GAAa,EAAU,OAAS,CAAE,YAAW,CAAG,EAAE,CACvD,CAGH,SAAgB,EAAqB,EAA8D,CACjG,IAAM,EAAQ,EAAqB,EAAM,CACzC,OAAO,GAAO,QAAU,UAAY,EAAQ,KAG9C,SAAgB,GAA6B,EAA+D,CAAE,MAAO,EAAQ,GAAU,GAEvI,SAAgB,GAAwB,EAA0C,CAAE,OAAO,GAA6B,EAAqB,EAAM,EAAE,gBAAgB,CAErK,SAAgB,EAAgB,EAAuD,CACrF,IAAM,EAAM,GAAO,MAAM,gBACzB,GAAI,CAAC,MAAM,QAAQ,EAAI,CAAE,CACvB,IAAM,EAAQ,OAAO,GAAO,MAAM,qBAAwB,SAAW,EAAM,KAAK,oBAAsB,EACtG,OAAO,EAAQ,EAAI,MAAM,KAAK,CAAE,OAAQ,EAAO,EAAG,EAAG,KAAW,CAAE,GAAI,YAAY,EAAQ,IAAK,MAAO,YAAY,EAAQ,IAAK,EAAE,CAAG,EAAE,CAExI,OAAO,EACJ,OAAO,EAAS,CAChB,KAAK,EAAM,IAAU,CACpB,IAAM,EAAK,OAAO,EAAK,IAAO,UAAY,EAAK,GAAK,EAAK,GAAK,YAAY,EAAQ,IAC5E,EAAO,OAAO,EAAK,MAAS,UAAY,EAAK,KAAO,EAAK,KAAO,IAAA,GAGtE,MAAO,CAAE,KAAI,MAFC,OAAO,EAAK,OAAU,UAAY,EAAK,MAAQ,EAAK,MAAQ,GAAQ,EAE9D,OAAM,UADR,OAAO,EAAK,WAAc,SAAW,EAAK,UAAY,IAAA,GACnC,EACrC,CAON,SAAgB,EAA4B,EAAgD,CAC1F,IAAM,EAAM,GAAO,MAAM,WACzB,GAAI,CAAC,MAAM,QAAQ,EAAI,CAAE,OAAO,KAChC,IAAM,EAAO,EAAI,KAAM,GAAS,EAAS,EAAK,EAAI,EAAK,OAAS,oBAAoB,CAEpF,MADI,CAAC,GAAQ,CAAC,EAAS,EAAK,CAAS,KAC9B,OAAO,EAAK,OAAU,UAAY,EAAK,MAAQ,EAAK,MAAQ,oBAGrE,SAAgB,GACd,EAAa,EAAiC,EAA0B,EAC1D,CACd,IAAM,EAAkB,OAAO,GAAO,MAAM,iBAAoB,SAAW,EAAM,KAAK,gBAAkB,GAClG,EAAQ,EAAa,EAAK,EAAM,CAChC,EAAe,GAAO,SAAW,WAAa,CAAC,GAAO,OAAS,EAC/D,EAAW,GAAO,SAAW,WAAa,CAAC,GAAO,OAAS,CAAC,EAC5D,EAAa,EAAU,OAAS,GAAK,GAAO,SAAW,OACvD,EAAU,EAAqB,EAAM,CACrC,EAAS,GAAe,EAAO,EAAW,EAAK,CAErD,GAAI,GAAO,SAAW,UAAW,MAAO,CAAE,MAAO,UAAW,KAAM,YAAa,KAAM,UAAW,MAAO,GAAO,aAAc,GAAO,SAAQ,CAG3I,GAAI,EAAgB,WAAW,cAAc,CAC3C,MAAO,CAAE,MAAO,gBAAgB,EAAgB,MAAM,GAAqB,CAAC,GAAI,KAAM,UAAW,KAAM,YAAa,QAAO,eAAc,SAAQ,CAEnJ,GAAI,IAAoB,gBAAiB,MAAO,CAAE,MAAO,gBAAiB,KAAM,UAAW,KAAM,QAAS,QAAO,eAAc,SAAQ,CACvI,GAAI,IAAoB,UAAW,MAAO,CAAE,MAAO,UAAW,KAAM,SAAU,KAAM,QAAS,QAAO,eAAc,SAAQ,CAC1H,GAAI,IAAoB,aAAc,MAAO,CAAE,MAAO,aAAc,KAAM,UAAW,KAAM,YAAa,QAAO,eAAc,SAAQ,CACrI,GAAI,GAAO,SAAW,QAAS,MAAO,CAAE,MAAO,QAAS,KAAM,SAAU,KAAM,YAAa,MAAO,GAAM,aAAc,GAAM,SAAQ,CACpI,GAAI,EAAc,MAAO,CAAE,MAAO,eAAgB,KAAM,SAAU,KAAM,YAAa,QAAO,eAAc,SAAQ,CAClH,GAAI,EAAU,MAAO,CAAE,MAAO,oBAAqB,KAAM,UAAW,KAAM,SAAU,QAAO,eAAc,SAAQ,CACjH,GAAI,EAAS,MAAO,CAAE,MAAO,YAAY,EAAQ,QAAS,KAAM,SAAU,KAAM,cAAe,QAAO,eAAc,SAAQ,CAC5H,GAAI,GAAO,SAAW,OAAQ,CAG5B,IAAM,EAAU,MAAM,QAAQ,GAAO,MAAM,YAAY,CAAG,EAAM,KAAK,YAAc,EAAE,CAGrF,OAFuB,EAA4B,EAAM,EAAI,CAAC,EAAQ,SAAS,gBAAgB,EAAI,CAAC,EAAQ,SAAS,WAAW,CACrG,CAAE,MAAO,0BAA2B,KAAM,UAAW,KAAM,OAAQ,QAAO,eAAc,SAAQ,CACpH,CAAE,MAAO,eAAgB,KAAM,UAAW,KAAM,OAAQ,QAAO,eAAc,SAAQ,CAI9F,OAFI,GAAM,SAAW,SAAiB,CAAE,MAAO,SAAU,KAAM,UAAW,KAAM,OAAQ,QAAO,eAAc,SAAQ,CACjH,EAAmB,CAAE,MAAO,eAAgB,KAAM,SAAU,KAAM,OAAQ,QAAO,eAAc,SAAQ,CACpG,CAAE,MAAO,GAAO,SAAW,OAAS,OAAS,QAAS,KAAM,UAAW,KAAM,cAAe,QAAO,eAAc,SAAQ,CAGlI,SAAS,GAAe,EAAiC,EAA0B,EAA2C,CAC5H,IAAM,EAA0B,EAAE,CAC5B,EAAU,EAAqB,EAAM,CACrC,EAAgB,EAAgB,EAAM,CAAC,OACzC,GAAS,EAAO,KAAK,CAAE,MAAO,EAAQ,OAAS,YAAY,EAAQ,SAAW,UAAW,UAAW,6BAA8B,CAAC,CACnI,GAAe,EAAO,KAAK,CAAE,MAAO,IAAkB,EAAI,aAAe,EAAgB,aAAc,UAAW,+BAAgC,CAAC,CACvJ,IAAM,EAAwB,EAA4B,EAAM,CAOhE,OANI,GAAuB,EAAO,KAAK,CAAE,MAAO,EAAuB,UAAW,mCAAoC,CAAC,CACnH,GAAM,SAAW,UAAU,EAAO,KAAK,CAAE,MAAO,SAAU,UAAW,qCAAsC,CAAC,CAC5G,GAAM,SAAW,WAAW,EAAO,KAAK,CAAE,MAAO,cAAe,UAAW,mCAAoC,CAAC,CAChH,EAAU,oBAAoB,EAAO,KAAK,CAAE,MAAO,iBAAkB,UAAW,iCAAkC,CAAC,CACnH,EAAU,QAAQ,EAAO,KAAK,CAAE,MAAO,EAAU,OAAS,UAAW,UAAW,6BAA8B,CAAC,CAC/G,EAAU,gBAAgB,EAAO,KAAK,CAAE,MAAO,EAAU,eAAiB,aAAc,UAAW,mCAAoC,CAAC,CACrI,EAGT,SAAgB,IAAgC,CAC9C,MAAO,CAAE,OAAQ,EAAG,mBAAoB,GAAO,kBAAmB,GAAO,eAAgB,EAAG,MAAO,EAAG,MAAO,EAAG,CAIlH,SAAgB,EAAe,EAAyC,CAItE,MAHI,CAAC,GAAW,EAAQ,SAAW,UAAkB,GACjD,EAAQ,cAAc,SAAW,KAAa,GAC9C,EAAQ,cAAc,SAAW,SAAW,EAAQ,cAAc,SAAW,UAAkB,GAC5F,EAAQ,MAGjB,SAAgB,GAAgB,EAA8C,CAO5E,OANK,EACD,EAAQ,cAAc,SAAW,QAAgB,CAAE,MAAO,gBAAiB,KAAM,SAAU,KAAM,gBAAiB,OAAQ,EAAE,CAAE,CAC9H,EAAQ,cAAc,SAAW,UAAkB,CAAE,MAAO,iBAAkB,KAAM,UAAW,KAAM,cAAe,OAAQ,EAAE,CAAE,CAChI,EAAQ,SAAW,UAAkB,CAAE,MAAO,UAAW,KAAM,YAAa,KAAM,UAAW,OAAQ,EAAE,CAAE,CACzG,EAAQ,SAAW,OAAe,CAAE,MAAO,OAAQ,KAAM,UAAW,KAAM,WAAY,OAAQ,EAAE,CAAE,CACjG,EAAe,EAAQ,CACrB,CAAE,MAAO,QAAS,KAAM,UAAW,KAAM,cAAe,OAAQ,EAAE,CAAE,CADtC,CAAE,MAAO,YAAa,KAAM,UAAW,KAAM,SAAU,OAAQ,EAAE,CAAE,CALnF,CAAE,MAAO,UAAW,KAAM,YAAa,KAAM,UAAW,OAAQ,EAAE,CAAE,CAS3F,SAAgB,GAAkB,EAA2C,CAC3E,IAAM,EAAU,GAAW,SAAW,EAAE,CAMxC,OALI,EAAQ,SAAW,QAAgB,CAAE,MAAO,QAAS,KAAM,SAAU,KAAM,gBAAiB,OAAQ,EAAE,CAAE,CACxG,EAAQ,SAAW,OAAe,CAAE,MAAO,UAAW,KAAM,UAAW,KAAM,cAAe,OAAQ,EAAE,CAAE,CACxG,EAAQ,QAAgB,CAAE,MAAO,UAAW,KAAM,UAAW,KAAM,cAAe,OAAQ,EAAE,CAAE,CAC9F,EAAQ,UAAY,GAAc,CAAE,MAAO,WAAY,KAAM,YAAa,KAAM,QAAS,OAAQ,EAAE,CAAE,CACrG,EAAQ,SAAW,KAAa,CAAE,MAAO,KAAM,KAAM,UAAW,KAAM,cAAe,OAAQ,EAAE,CAAE,CAC9F,CAAE,MAAO,UAAW,KAAM,YAAa,KAAM,aAAc,OAAQ,EAAE,CAAE,CAGhF,SAAgB,GAAoB,EAA+C,CACjF,IAAM,EAAQ,GAAa,WAAa,EAAE,CAK1C,OAJK,EAAM,cAAgB,GAAK,EAAU,CAAE,MAAO,UAAW,KAAM,UAAW,KAAM,cAAe,OAAQ,EAAE,CAAE,EAC3G,EAAM,WAAa,GAAK,EAAU,CAAE,MAAO,SAAU,KAAM,OAAQ,KAAM,WAAY,OAAQ,EAAE,CAAE,CACjG,GAAa,WACd,EAAY,SAAiB,CAAE,MAAO,QAAS,KAAM,UAAW,KAAM,cAAe,OAAQ,EAAE,CAAE,CAC9F,CAAE,MAAO,aAAc,KAAM,UAAW,KAAM,UAAW,OAAQ,EAAE,CAAE,CAFvC,CAAE,MAAO,gBAAiB,KAAM,YAAa,KAAM,MAAO,OAAQ,EAAE,CAAE,CAK7G,SAAgB,GAAwB,EAA4B,CAClE,IAAM,EAAS,GAAM,OAQrB,MAPI,CAAC,GAAU,EAAO,SAAW,KAAa,GAAM,SAAW,GAAM,SAAS,QAAU,aAAe,kBACnG,EAAO,SAAW,mBAA2B,mBAC7C,EAAO,SAAW,mBAA2B,mBAC7C,EAAO,SAAW,UAAkB,oBACnC,EAAO,QAAU,EAAE,EAAE,KAAM,GAAM,EAAE,OAAS,oBAAoB,CAAS,qBACzE,EAAO,QAAU,EAAE,EAAE,KAAM,GAAM,EAAE,OAAS,gBAAgB,CAAS,gBACtE,EAAO,gBAAwB,mBAC5B,EAAO,OAGhB,SAAgB,EAAwB,EAA4B,CAClE,IAAM,EAAS,GAAM,QAAQ,OAI7B,OAHI,IAAW,mBAA2B,6BACtC,IAAW,QAAU,IAAW,mBAA2B,mCAC3D,IAAW,UAAkB,+BAC1B,qCAGT,SAAgB,GAAQ,EAAa,EAAiD,CACpF,GAAI,CAAC,EAAK,MAAO,GACjB,IAAM,EAAK,IAAI,KAAK,EAAc,CAAC,SAAS,CAC5C,GAAI,CAAC,OAAO,SAAS,EAAG,CAAE,MAAO,GACjC,IAAM,EAAO,KAAK,IAAI,GAAI,EAAM,GAAM,IAAK,CAI3C,OAHI,EAAO,GAAW,KAAK,MAAM,EAAK,CAAG,QACrC,EAAO,KAAa,KAAK,MAAM,EAAO,GAAG,CAAG,QAC5C,EAAO,MAAc,KAAK,MAAM,EAAO,KAAK,CAAG,QAC5C,KAAK,MAAM,EAAO,MAAM,CAAG,QAGpC,SAAgB,GAAQ,EAAiD,CAEvE,OADK,EACE,IAAI,KAAK,EAAc,CAAC,gBAAgB,CAD9B,GAInB,SAAgB,GAAa,EAAuB,CAClD,OAAO,OAAO,GAAS,SAAS,CAAC,QAAQ,kBAAmB,IAAI,CAAC,QAAQ,WAAY,GAAG,CAAC,MAAM,EAAG,GAAG,EAAI,SAG3G,SAAgB,GAAkB,EAA2C,CAC3E,OAAO,EAAO,OAAQ,GAAM,EAAE,SAAW,KAAK,CAAC,IAAK,GAAU,CAC5D,IAAM,EAAyB,CAC7B,KAAM,EAAM,KACZ,OAAQ,EAAM,OACd,OAAQ,EAAM,QAAU,EAAM,KAC9B,OAAQ,GAAa,EAAM,CAC3B,SAAU,EAAM,UAAY,EAAE,CAC9B,QAAS,CACP,CAAE,MAAO,eAAgB,KAAM,aAAc,KAAM,0BAA2B,CAC9E,CAAE,MAAO,iBAAkB,KAAM,YAAa,KAAM,6BAA8B,CAClF,CAAE,MAAO,WAAY,KAAM,OAAQ,KAAM,qBAAsB,CAChE,CACF,CAiBD,OAhBI,EAAM,OAAS,oBACjB,EAAK,QAAQ,QACX,CAAE,MAAO,aAAc,KAAM,SAAU,IAAK,OAAQ,KAAM,eAAgB,CAC1E,CAAE,MAAO,aAAc,KAAM,SAAU,KAAM,SAAU,OAAQ,gBAAiB,CACjF,CACQ,EAAM,OAAS,2BACxB,EAAK,QAAQ,QACX,CAAE,MAAO,gBAAiB,KAAM,iBAAkB,KAAM,WAAY,CACpE,CAAE,MAAO,aAAc,KAAM,SAAU,IAAK,OAAQ,KAAM,eAAgB,CAC3E,CACQ,CAAC,yBAA0B,sBAAuB,wBAAwB,CAAC,SAAS,EAAM,KAAK,EACxG,EAAK,QAAQ,QACX,CAAE,MAAO,aAAc,KAAM,SAAU,IAAK,OAAQ,KAAM,eAAgB,CAC1E,CAAE,MAAO,YAAa,KAAM,aAAc,KAAM,OAAQ,CACzD,CAEI,GACP,CAGJ,SAAS,GAAa,EAA4B,CAShD,MAAO,CAPL,SAAY,gFACZ,oBAAqB,kEACrB,yBAA0B,4EAC1B,sBAAuB,qEACvB,wBAAyB,4DACzB,2BAA4B,iFAEvB,CAAQ,EAAM,OAAS,2CAShC,SAAgB,GAAY,EAAsB,CAShD,MAAO,CAPL,QAAS,mBACT,QAAS,kBACT,OAAQ,eACR,KAAM,gBACN,QAAS,gBACT,UAAW,gBAEN,CAAI,IAAS,gBAetB,SAAgB,GAAe,EAAqB,EAAsB,CAUxE,MATI,CAAC,GACD,EAAM,SAAW,UAAkB,yBACnC,OAAO,EAAM,MAAM,iBAAoB,UAAY,EAAM,KAAK,gBAAgB,WAAW,cAAc,CAAS,6BAChH,EAAM,MAAM,kBAAoB,iBAAmB,EAAM,MAAM,kBAAoB,aAAqB,8BACxG,EAAM,MAAM,kBAAoB,WAChC,EAAqB,EAAM,CAAS,2BACpC,EAAM,SAAW,OAAe,gBAChC,GAAO,EAAa,EAAK,EAAM,CAAS,2BACvC,EAAM,MACJ,4DADkB,+BAI3B,SAAgB,GAAa,EAAkB,EAAc,EAAc,CACzE,GAAI,OAAO,SAAa,KAAe,OAAO,IAAQ,KAAe,OAAO,KAAS,IAAa,OAClG,IAAM,EAAM,IAAI,gBAAgB,IAAI,KAAK,CAAC,EAAK,CAAE,CAAE,OAAM,CAAC,CAAC,CACrD,EAAO,SAAS,cAAc,IAAI,CACxC,EAAK,KAAO,EACZ,EAAK,SAAW,EAChB,EAAK,OAAO,CACZ,IAAI,gBAAgB,EAAI"}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["./formatted-body-impl-
|
|
2
|
-
import{r as e}from"./chunk-CilyBKbf.js";import{gr as t,rr as n}from"./lucide-react-CoU_Xts2.js";import{t as r}from"./preload-helper-C_JMBXql.js";var i=e(t(),1),a=n(),o=(0,i.lazy)(()=>r(()=>import(`./formatted-body-impl-
|
|
3
|
-
//# sourceMappingURL=formatted-body-
|
|
1
|
+
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["./formatted-body-impl-DO-8giS6.js","./chunk-CilyBKbf.js","./index-De1tR7J4.js","./preload-helper-C_JMBXql.js","./dist-DKmTXfpP.js","./dist-C5z05Vkz.js","./lucide-react-CoU_Xts2.js","./dist-B8tD9ZcR.js","./dist-V3wu3BHw.js","./react-dom-BQICbUuF.js","./dist-CFtFIhu3.js","./dist-CGaHpxnN.js","./dist-BiLuYU6G.js","./dist-BJaV2BD4.js","./dist-CjyfQThq.js","./es2015-5DTJe35n.js","./dist-r8wyUTkK.js","./dist-4VwhnLtj.js","./dist-CrUl2aQp.js","./store-Dl9Z8YUS.js","./display-aTnwsqQh.js","./types-BqeSkWrv.js","./agent-type-icon-B3i0rndK.js","./copy-button-Bil2CjzT.js","./button-C3CQSr4p.js","./task-chip-BHM-e3I8.js","./badge-XEru6wto.js","./input-CXMbJ848.js","./themes-DjSwmAZN.js","./index-C9X_0QBt.css","./lib-BcUW1l-W.js","./lib-Cc7Il-6i.js"])))=>i.map(i=>d[i]);
|
|
2
|
+
import{r as e}from"./chunk-CilyBKbf.js";import{gr as t,rr as n}from"./lucide-react-CoU_Xts2.js";import{t as r}from"./preload-helper-C_JMBXql.js";var i=e(t(),1),a=n(),o=(0,i.lazy)(()=>r(()=>import(`./formatted-body-impl-DO-8giS6.js`).then(e=>({default:e.FormattedBody})),__vite__mapDeps([0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31]),import.meta.url));function s(e){return(0,a.jsx)(i.Suspense,{fallback:(0,a.jsx)(`span`,{className:e.className,children:e.text}),children:(0,a.jsx)(o,{...e})})}export{s as t};
|
|
3
|
+
//# sourceMappingURL=formatted-body-BuLfVMeD.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"mappings":";sKASM,uBACJ,OAAO,qCAAyB,KAAM,IAAO,CAAE,QAAS,EAAE,cAAe,EAAE,2HAC5E,CAID,SAAgB,EAAc,EAA2B,CACvD,OACE,SAAC,WAAD,CAAU,UAAU,SAAC,OAAD,CAAM,UAAW,EAAM,mBAAY,EAAM,KAAY,YACvE,SAAC,EAAD,CAAmB,GAAI,EAAS,EACvB","names":[],"ignoreList":[],"sources":["../../dashboard/src/components/shared/formatted-body.tsx"],"sourcesContent":["import { lazy, Suspense } from 'react'\nimport type { FormattedBodyProps } from './formatted-body-impl'\n\n// Lazy boundary for react-markdown (#201). FormattedBody is statically imported\n// by the always-mounted ThreadModal, which would otherwise drag react-markdown +\n// remark/rehype plugins into the initial bundle. Behind this boundary the\n// markdown chunk loads on first actual render (thread opened, or chat/messages\n// view navigated to). The fallback renders the plain text so there's no blank\n// flash while the chunk resolves on first use.\nconst LazyFormattedBody = lazy(() =>\n import('./formatted-body-impl').then((m) => ({ default: m.FormattedBody })),\n)\n\nexport type { FormattedBodyProps }\n\nexport function FormattedBody(props: FormattedBodyProps) {\n return (\n <Suspense fallback={<span className={props.className}>{props.text}</span>}>\n <LazyFormattedBody {...props} />\n </Suspense>\n )\n}\n"],"file":"formatted-body-
|
|
1
|
+
{"version":3,"mappings":";sKASM,uBACJ,OAAO,qCAAyB,KAAM,IAAO,CAAE,QAAS,EAAE,cAAe,EAAE,2HAC5E,CAID,SAAgB,EAAc,EAA2B,CACvD,OACE,SAAC,WAAD,CAAU,UAAU,SAAC,OAAD,CAAM,UAAW,EAAM,mBAAY,EAAM,KAAY,YACvE,SAAC,EAAD,CAAmB,GAAI,EAAS,EACvB","names":[],"ignoreList":[],"sources":["../../dashboard/src/components/shared/formatted-body.tsx"],"sourcesContent":["import { lazy, Suspense } from 'react'\nimport type { FormattedBodyProps } from './formatted-body-impl'\n\n// Lazy boundary for react-markdown (#201). FormattedBody is statically imported\n// by the always-mounted ThreadModal, which would otherwise drag react-markdown +\n// remark/rehype plugins into the initial bundle. Behind this boundary the\n// markdown chunk loads on first actual render (thread opened, or chat/messages\n// view navigated to). The fallback renders the plain text so there's no blank\n// flash while the chunk resolves on first use.\nconst LazyFormattedBody = lazy(() =>\n import('./formatted-body-impl').then((m) => ({ default: m.FormattedBody })),\n)\n\nexport type { FormattedBodyProps }\n\nexport function FormattedBody(props: FormattedBodyProps) {\n return (\n <Suspense fallback={<span className={props.className}>{props.text}</span>}>\n <LazyFormattedBody {...props} />\n </Suspense>\n )\n}\n"],"file":"formatted-body-BuLfVMeD.js"}
|