agent-relay-server 0.123.2 → 0.124.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 +3 -3
- package/public/assets/{MessageBubble-NCggGKTA.js → MessageBubble-SQK8-Mzp.js} +2 -2
- package/public/assets/{MessageBubble-NCggGKTA.js.map → MessageBubble-SQK8-Mzp.js.map} +1 -1
- package/public/assets/{PlanGraphPanel-CSdszmGk.js → PlanGraphPanel-CS-aow4S.js} +2 -2
- package/public/assets/{PlanGraphPanel-CSdszmGk.js.map → PlanGraphPanel-CS-aow4S.js.map} +1 -1
- package/public/assets/{activity-Cyp2nolX.js → activity-W31XvhC2.js} +2 -2
- package/public/assets/{activity-Cyp2nolX.js.map → activity-W31XvhC2.js.map} +1 -1
- package/public/assets/{agent-profiles-D5Izg0Vn.js → agent-profiles-DXysA9To.js} +2 -2
- package/public/assets/{agent-profiles-D5Izg0Vn.js.map → agent-profiles-DXysA9To.js.map} +1 -1
- package/public/assets/{agents-DIOxuJ6M.js → agents-B5GRNRnN.js} +2 -2
- package/public/assets/{agents-DIOxuJ6M.js.map → agents-B5GRNRnN.js.map} +1 -1
- package/public/assets/{automation-Bn6mOLAR.js → automation-DYlgHYcb.js} +2 -2
- package/public/assets/{automation-Bn6mOLAR.js.map → automation-DYlgHYcb.js.map} +1 -1
- package/public/assets/{chat-eUaPz399.js → chat-Clz6qOtn.js} +2 -2
- package/public/assets/{chat-eUaPz399.js.map → chat-Clz6qOtn.js.map} +1 -1
- package/public/assets/{formatted-body-CvrQ2D1J.js → formatted-body-BYQ-SPtj.js} +3 -3
- package/public/assets/{formatted-body-CvrQ2D1J.js.map → formatted-body-BYQ-SPtj.js.map} +1 -1
- package/public/assets/{formatted-body-impl-BJ7jdbpR.js → formatted-body-impl-L1EMnNW6.js} +2 -2
- package/public/assets/{formatted-body-impl-BJ7jdbpR.js.map → formatted-body-impl-L1EMnNW6.js.map} +1 -1
- package/public/assets/{index-DnUo0Zqg.js → index-0uIGXT14.js} +6 -6
- package/public/assets/{index-DnUo0Zqg.js.map → index-0uIGXT14.js.map} +1 -1
- package/public/assets/index-DOJ7KidA.css +2 -0
- package/public/assets/{insights-CQGH5LhD.js → insights-DwZxq1Dn.js} +2 -2
- package/public/assets/{insights-CQGH5LhD.js.map → insights-DwZxq1Dn.js.map} +1 -1
- package/public/assets/{maintenance-7c7UvpAt.js → maintenance-COcmUDnf.js} +2 -2
- package/public/assets/{maintenance-7c7UvpAt.js.map → maintenance-COcmUDnf.js.map} +1 -1
- package/public/assets/{managed-agents-yh4HPO5a.js → managed-agents-D9-dgMeX.js} +2 -2
- package/public/assets/{managed-agents-yh4HPO5a.js.map → managed-agents-D9-dgMeX.js.map} +1 -1
- package/public/assets/{markdown-preview-impl-BuOn5-Uc.js → markdown-preview-impl-DH372bL-.js} +2 -2
- package/public/assets/{markdown-preview-impl-BuOn5-Uc.js.map → markdown-preview-impl-DH372bL-.js.map} +1 -1
- package/public/assets/{memory-Qv0JN8CE.js → memory-B9hRK8sk.js} +2 -2
- package/public/assets/{memory-Qv0JN8CE.js.map → memory-B9hRK8sk.js.map} +1 -1
- package/public/assets/{messages-CgjHJmc2.js → messages-BHkHlXzF.js} +2 -2
- package/public/assets/{messages-CgjHJmc2.js.map → messages-BHkHlXzF.js.map} +1 -1
- package/public/assets/{orchestrators-CgL4CFzb.js → orchestrators-CXy3SDSn.js} +2 -2
- package/public/assets/{orchestrators-CgL4CFzb.js.map → orchestrators-CXy3SDSn.js.map} +1 -1
- package/public/assets/{overview-Bri04eYE.js → overview-D2yRyCQq.js} +2 -2
- package/public/assets/{overview-Bri04eYE.js.map → overview-D2yRyCQq.js.map} +1 -1
- package/public/assets/{pairs-C78LwUH2.js → pairs-5tXdHylI.js} +2 -2
- package/public/assets/{pairs-C78LwUH2.js.map → pairs-5tXdHylI.js.map} +1 -1
- package/public/assets/{prompt-settings-DDEkMqPZ.js → prompt-settings-Bn5mmi9w.js} +2 -2
- package/public/assets/{prompt-settings-DDEkMqPZ.js.map → prompt-settings-Bn5mmi9w.js.map} +1 -1
- package/public/assets/registry-C3sB7qv5.js +4 -0
- package/public/assets/registry-C3sB7qv5.js.map +1 -0
- package/public/assets/{security-wvnRKFvm.js → security-CmD-YE-_.js} +2 -2
- package/public/assets/{security-wvnRKFvm.js.map → security-CmD-YE-_.js.map} +1 -1
- package/public/assets/{select-BIfbVmLf.js → select-C0UlhK2k.js} +2 -2
- package/public/assets/{select-BIfbVmLf.js.map → select-C0UlhK2k.js.map} +1 -1
- package/public/assets/{settings-B6Ntahx7.js → settings-DrqMG5nG.js} +2 -2
- package/public/assets/{settings-B6Ntahx7.js.map → settings-DrqMG5nG.js.map} +1 -1
- package/public/assets/{tasks-CUglafo5.js → tasks-ChQjtXHu.js} +2 -2
- package/public/assets/{tasks-CUglafo5.js.map → tasks-ChQjtXHu.js.map} +1 -1
- package/public/assets/{teams-EE8RHhHM.js → teams-itjNlDLp.js} +2 -2
- package/public/assets/{teams-EE8RHhHM.js.map → teams-itjNlDLp.js.map} +1 -1
- package/public/assets/{terminal-viewer-impl-DBRkdyag.js → terminal-viewer-impl-B9M6s2vB.js} +2 -2
- package/public/assets/{terminal-viewer-impl-DBRkdyag.js.map → terminal-viewer-impl-B9M6s2vB.js.map} +1 -1
- package/public/assets/{work-queue-BFQVVL4T.js → work-queue-Kw0uMkEF.js} +2 -2
- package/public/assets/{work-queue-BFQVVL4T.js.map → work-queue-Kw0uMkEF.js.map} +1 -1
- package/public/index.html +3 -3
- package/runner/plugins/claude/.claude-plugin/plugin.json +1 -1
- package/src/db/provisioning-registry.ts +174 -1
- package/src/routes/provisioning-registry.ts +3 -0
- package/src/routing-policy-store.ts +55 -0
- package/src/spawn-targets.ts +130 -28
- package/public/assets/index-DcmG5gLR.css +0 -2
- package/public/assets/registry-5KhP5FE5.js +0 -2
- package/public/assets/registry-5KhP5FE5.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"overview-Bri04eYE.js","names":[],"sources":["../../dashboard/src/components/views/overview.tsx"],"sourcesContent":["import { useMemo } from 'react'\nimport { useRelayStore, useNow } from '@/store'\nimport { useAttentionSummary, useOnlineCount, useBusyCount } from '@/hooks/use-selectors'\nimport { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'\nimport { Badge } from '@/components/ui/badge'\nimport { ScrollArea } from '@/components/ui/scroll-area'\nimport { Separator } from '@/components/ui/separator'\nimport { StatusDot } from '@/components/shared/status-dot'\nimport { AgentTypeIcon } from '@/components/shared/agent-type-icon'\nimport {\n displayName, displayTarget, timeAgo, messagePreview, healthDiagnostics,\n toneToColor, visibleAgents, toTimestamp,\n} from '@/lib/display'\nimport { STATUS_SORT_ORDER } from '@/lib/constants'\nimport {\n Bot, Mail, Link, Inbox, AlertTriangle, Activity,\n Users, MessageSquare, ListChecks,\n} from 'lucide-react'\nimport type { ViewName } from '@/types'\n\nexport function OverviewView() {\n const stats = useRelayStore((s) => s.stats)\n const agents = useRelayStore((s) => s.agents)\n const messages = useRelayStore((s) => s.messages)\n const health = useRelayStore((s) => s.health)\n const now = useNow()\n const agentsById = useRelayStore((s) => s.agentsById)\n const switchView = useRelayStore((s) => s.switchView)\n const runHealthAction = useRelayStore((s) => s.runHealthAction)\n const managedPolicies = useRelayStore((s) => s.managedPolicies)\n\n const showOffline = useRelayStore((s) => s.showOffline)\n\n const onlineCount = useOnlineCount()\n const busyCount = useBusyCount()\n const attention = useAttentionSummary()\n\n const filteredAgents = useMemo(() => {\n let list = visibleAgents(agents, false, managedPolicies)\n if (!showOffline) list = list.filter((a) => a.status !== 'offline')\n return [...list].sort((a, b) => {\n const s = (STATUS_SORT_ORDER[a.status] ?? 9) - (STATUS_SORT_ORDER[b.status] ?? 9)\n return s || toTimestamp(b.lastSeen) - toTimestamp(a.lastSeen)\n })\n }, [agents, showOffline, managedPolicies])\n const recentAgents = filteredAgents.slice(0, 20)\n const recentMessages = [...messages].sort((a, b) => b.id - a.id).slice(0, 15)\n\n const healthIssues =\n health && health.status !== 'ok'\n ? healthDiagnostics(health.checks || [])\n : []\n\n function nav(view: ViewName) {\n switchView(view)\n }\n\n return (\n <div className=\"space-y-6\">\n {/* Stat cards */}\n <div className=\"grid grid-cols-2 md:grid-cols-4 gap-4\">\n <Card className=\"cursor-pointer hover:border-zinc-600 transition-colors\" onClick={() => nav('agents')}>\n <CardHeader className=\"pb-1 pt-4 px-4\">\n <CardTitle className=\"text-xs font-medium text-muted-foreground flex items-center gap-1.5\">\n <Users className=\"w-3.5 h-3.5\" />\n Agents\n </CardTitle>\n </CardHeader>\n <CardContent className=\"px-4 pb-4\">\n <div className=\"text-2xl font-bold\">{filteredAgents.length}</div>\n <div className=\"text-xs text-muted-foreground mt-0.5\">{onlineCount} online</div>\n </CardContent>\n </Card>\n\n <Card className=\"cursor-pointer hover:border-zinc-600 transition-colors\" onClick={() => nav('agents')}>\n <CardHeader className=\"pb-1 pt-4 px-4\">\n <CardTitle className=\"text-xs font-medium text-muted-foreground flex items-center gap-1.5\">\n <Activity className=\"w-3.5 h-3.5\" />\n Busy\n </CardTitle>\n </CardHeader>\n <CardContent className=\"px-4 pb-4\">\n <div className=\"text-2xl font-bold\">{busyCount}</div>\n <div className=\"text-xs text-muted-foreground mt-0.5\">in a turn now</div>\n </CardContent>\n </Card>\n\n <Card className=\"cursor-pointer hover:border-zinc-600 transition-colors\" onClick={() => nav('messages')}>\n <CardHeader className=\"pb-1 pt-4 px-4\">\n <CardTitle className=\"text-xs font-medium text-muted-foreground flex items-center gap-1.5\">\n <MessageSquare className=\"w-3.5 h-3.5\" />\n Messages 24h\n </CardTitle>\n </CardHeader>\n <CardContent className=\"px-4 pb-4\">\n <div className=\"text-2xl font-bold\">{stats.messagesLast24h ?? '—'}</div>\n <div className=\"text-xs text-muted-foreground mt-0.5\">last 24 hours</div>\n </CardContent>\n </Card>\n\n <Card className=\"cursor-pointer hover:border-zinc-600 transition-colors\" onClick={() => nav('messages')}>\n <CardHeader className=\"pb-1 pt-4 px-4\">\n <CardTitle className=\"text-xs font-medium text-muted-foreground flex items-center gap-1.5\">\n <Mail className=\"w-3.5 h-3.5\" />\n Total Messages\n </CardTitle>\n </CardHeader>\n <CardContent className=\"px-4 pb-4\">\n <div className=\"text-2xl font-bold\">{stats.messages ?? '—'}</div>\n <div className=\"text-xs text-muted-foreground mt-0.5\">all time</div>\n </CardContent>\n </Card>\n </div>\n\n {/* Health alert banner */}\n {healthIssues.length > 0 && (\n <Card className=\"border-yellow-500/40 bg-yellow-500/5\">\n <CardHeader className=\"pb-2 pt-4 px-4\">\n <CardTitle className=\"text-sm font-medium text-yellow-400 flex items-center gap-2\">\n <AlertTriangle className=\"w-4 h-4\" />\n Health Alerts ({healthIssues.length})\n </CardTitle>\n </CardHeader>\n <CardContent className=\"px-4 pb-4 space-y-2\">\n {healthIssues.map((issue) => (\n <div key={issue.name} className=\"text-sm space-y-1\">\n <div className=\"flex items-center gap-2\">\n <Badge\n variant=\"outline\"\n className={issue.status === 'error' ? 'border-red-500/40 text-red-400' : 'border-yellow-500/40 text-yellow-400'}\n >\n {issue.status}\n </Badge>\n <span className=\"font-medium\">{issue.name}</span>\n </div>\n <p className=\"text-xs text-muted-foreground\">{issue.detail}</p>\n {issue.subjects.length > 0 && (\n <div className=\"flex flex-wrap gap-1.5\">\n {issue.subjects.map((subject) => (\n <Badge key={subject.id} variant=\"secondary\" className=\"max-w-full truncate text-[11px]\" title={[subject.id, subject.status, subject.detail].filter(Boolean).join(' · ')}>\n {subject.label || subject.id}\n {subject.status ? ` · ${subject.status}` : ''}\n {subject.detail ? ` · ${subject.detail}` : ''}\n </Badge>\n ))}\n </div>\n )}\n {issue.actions.length > 0 && (\n <div className=\"flex flex-wrap gap-1.5 pt-0.5\">\n {issue.actions.slice(0, 3).map((action) => (\n <button\n key={action.label}\n onClick={() => runHealthAction(action)}\n className=\"text-xs text-blue-400 hover:text-blue-300 underline underline-offset-2\"\n >\n {action.label}\n </button>\n ))}\n </div>\n )}\n </div>\n ))}\n </CardContent>\n </Card>\n )}\n\n {/* Attention shortcuts */}\n <div className=\"grid grid-cols-1 sm:grid-cols-3 gap-4\">\n <Card\n className={`cursor-pointer hover:border-zinc-600 transition-colors ${attention.unreadInbox > 0 ? 'border-red-500/40' : ''}`}\n onClick={() => nav('chat')}\n >\n <CardContent className=\"p-4 flex items-center gap-3\">\n <div className={`p-2 rounded-lg ${attention.unreadInbox > 0 ? 'bg-red-500/15' : 'bg-zinc-800'}`}>\n <Inbox className={`w-4 h-4 ${attention.unreadInbox > 0 ? 'text-red-400' : 'text-zinc-400'}`} />\n </div>\n <div>\n <div className=\"text-lg font-bold\">{attention.unreadInbox}</div>\n <div className=\"text-xs text-muted-foreground\">Unread</div>\n </div>\n </CardContent>\n </Card>\n\n <Card\n className={`cursor-pointer hover:border-zinc-600 transition-colors ${attention.pendingPairInvites > 0 ? 'border-yellow-500/40' : ''}`}\n onClick={() => nav('pairs')}\n >\n <CardContent className=\"p-4 flex items-center gap-3\">\n <div className={`p-2 rounded-lg ${attention.pendingPairInvites > 0 ? 'bg-yellow-500/15' : 'bg-zinc-800'}`}>\n <Link className={`w-4 h-4 ${attention.pendingPairInvites > 0 ? 'text-yellow-400' : 'text-zinc-400'}`} />\n </div>\n <div>\n <div className=\"text-lg font-bold\">{attention.pendingPairInvites}</div>\n <div className=\"text-xs text-muted-foreground\">Pair invites</div>\n </div>\n </CardContent>\n </Card>\n\n <Card\n className={`cursor-pointer hover:border-zinc-600 transition-colors ${attention.claimableTasks > 0 ? 'border-orange-500/40' : ''}`}\n onClick={() => nav('work')}\n >\n <CardContent className=\"p-4 flex items-center gap-3\">\n <div className={`p-2 rounded-lg ${attention.claimableTasks > 0 ? 'bg-orange-500/15' : 'bg-zinc-800'}`}>\n <ListChecks className={`w-4 h-4 ${attention.claimableTasks > 0 ? 'text-orange-400' : 'text-zinc-400'}`} />\n </div>\n <div>\n <div className=\"text-lg font-bold\">{attention.claimableTasks}</div>\n <div className=\"text-xs text-muted-foreground\">Claimable waiting</div>\n </div>\n </CardContent>\n </Card>\n </div>\n\n {/* Two-column: agents + recent activity */}\n <div className=\"grid grid-cols-1 md:grid-cols-2 gap-6\">\n {/* Top agents */}\n <Card>\n <CardHeader className=\"pb-2 pt-4 px-4\">\n <CardTitle className=\"text-sm font-medium flex items-center gap-2\">\n <Bot className=\"w-4 h-4 text-muted-foreground\" />\n Agents\n <span className=\"ml-auto text-xs text-muted-foreground font-normal\">{recentAgents.length}</span>\n </CardTitle>\n </CardHeader>\n <CardContent className=\"px-0 pb-0\">\n <ScrollArea className=\"h-[340px]\">\n {recentAgents.length === 0 ? (\n <div className=\"px-4 pb-4 text-sm text-muted-foreground\">No agents registered.</div>\n ) : (\n <div className=\"space-y-0\">\n {recentAgents.map((agent, i) => (\n <div key={agent.id}>\n {i > 0 && <Separator />}\n <div className=\"flex items-center gap-2.5 px-4 py-2.5 hover:bg-zinc-800/50 transition-colors cursor-pointer\" onClick={() => useRelayStore.getState().openAgentDetail(agent)}>\n <StatusDot agent={agent} now={now} />\n <AgentTypeIcon agent={agent} />\n <div className=\"flex-1 min-w-0\">\n <div className=\"text-sm font-medium truncate\">{displayName(agent)}</div>\n {agent.tags.length > 0 && (\n <div className=\"flex gap-1 mt-0.5 flex-wrap\">\n {agent.tags.slice(0, 2).map((t) => (\n <Badge key={t} variant=\"outline\" className=\"text-[9px] px-1 py-0 h-4\">{t}</Badge>\n ))}\n </div>\n )}\n </div>\n <span className=\"text-xs text-muted-foreground shrink-0\">{timeAgo(now, agent.lastSeen)}</span>\n </div>\n </div>\n ))}\n </div>\n )}\n </ScrollArea>\n </CardContent>\n </Card>\n\n {/* Recent activity */}\n <Card>\n <CardHeader className=\"pb-2 pt-4 px-4\">\n <CardTitle className=\"text-sm font-medium flex items-center gap-2\">\n <Activity className=\"w-4 h-4 text-muted-foreground\" />\n Recent Activity\n <span className=\"ml-auto text-xs text-muted-foreground font-normal\">{recentMessages.length}</span>\n </CardTitle>\n </CardHeader>\n <CardContent className=\"px-0 pb-0\">\n <ScrollArea className=\"h-[340px]\">\n {recentMessages.length === 0 ? (\n <div className=\"px-4 pb-4 text-sm text-muted-foreground\">No recent messages.</div>\n ) : (\n <div className=\"space-y-0\">\n {recentMessages.map((msg, i) => (\n <div key={msg.id}>\n {i > 0 && <Separator />}\n <div className=\"px-4 py-2.5 hover:bg-zinc-800/50 transition-colors\">\n <div className=\"flex items-center gap-1 text-xs text-muted-foreground mb-0.5\">\n <span className=\"text-foreground font-medium truncate max-w-[100px]\">{displayTarget(msg.from, agentsById)}</span>\n <span>→</span>\n <span className=\"truncate max-w-[100px]\">{displayTarget(msg.to, agentsById)}</span>\n <span className=\"ml-auto shrink-0 tabular-nums\"><span className=\"opacity-40 mr-1\">#{msg.id}</span>{timeAgo(now, msg.createdAt)}</span>\n </div>\n <div className=\"text-xs text-foreground line-clamp-2 leading-snug\">{messagePreview(msg)}</div>\n </div>\n </div>\n ))}\n </div>\n )}\n </ScrollArea>\n </CardContent>\n </Card>\n </div>\n </div>\n )\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"overview-D2yRyCQq.js","names":[],"sources":["../../dashboard/src/components/views/overview.tsx"],"sourcesContent":["import { useMemo } from 'react'\nimport { useRelayStore, useNow } from '@/store'\nimport { useAttentionSummary, useOnlineCount, useBusyCount } from '@/hooks/use-selectors'\nimport { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'\nimport { Badge } from '@/components/ui/badge'\nimport { ScrollArea } from '@/components/ui/scroll-area'\nimport { Separator } from '@/components/ui/separator'\nimport { StatusDot } from '@/components/shared/status-dot'\nimport { AgentTypeIcon } from '@/components/shared/agent-type-icon'\nimport {\n displayName, displayTarget, timeAgo, messagePreview, healthDiagnostics,\n toneToColor, visibleAgents, toTimestamp,\n} from '@/lib/display'\nimport { STATUS_SORT_ORDER } from '@/lib/constants'\nimport {\n Bot, Mail, Link, Inbox, AlertTriangle, Activity,\n Users, MessageSquare, ListChecks,\n} from 'lucide-react'\nimport type { ViewName } from '@/types'\n\nexport function OverviewView() {\n const stats = useRelayStore((s) => s.stats)\n const agents = useRelayStore((s) => s.agents)\n const messages = useRelayStore((s) => s.messages)\n const health = useRelayStore((s) => s.health)\n const now = useNow()\n const agentsById = useRelayStore((s) => s.agentsById)\n const switchView = useRelayStore((s) => s.switchView)\n const runHealthAction = useRelayStore((s) => s.runHealthAction)\n const managedPolicies = useRelayStore((s) => s.managedPolicies)\n\n const showOffline = useRelayStore((s) => s.showOffline)\n\n const onlineCount = useOnlineCount()\n const busyCount = useBusyCount()\n const attention = useAttentionSummary()\n\n const filteredAgents = useMemo(() => {\n let list = visibleAgents(agents, false, managedPolicies)\n if (!showOffline) list = list.filter((a) => a.status !== 'offline')\n return [...list].sort((a, b) => {\n const s = (STATUS_SORT_ORDER[a.status] ?? 9) - (STATUS_SORT_ORDER[b.status] ?? 9)\n return s || toTimestamp(b.lastSeen) - toTimestamp(a.lastSeen)\n })\n }, [agents, showOffline, managedPolicies])\n const recentAgents = filteredAgents.slice(0, 20)\n const recentMessages = [...messages].sort((a, b) => b.id - a.id).slice(0, 15)\n\n const healthIssues =\n health && health.status !== 'ok'\n ? healthDiagnostics(health.checks || [])\n : []\n\n function nav(view: ViewName) {\n switchView(view)\n }\n\n return (\n <div className=\"space-y-6\">\n {/* Stat cards */}\n <div className=\"grid grid-cols-2 md:grid-cols-4 gap-4\">\n <Card className=\"cursor-pointer hover:border-zinc-600 transition-colors\" onClick={() => nav('agents')}>\n <CardHeader className=\"pb-1 pt-4 px-4\">\n <CardTitle className=\"text-xs font-medium text-muted-foreground flex items-center gap-1.5\">\n <Users className=\"w-3.5 h-3.5\" />\n Agents\n </CardTitle>\n </CardHeader>\n <CardContent className=\"px-4 pb-4\">\n <div className=\"text-2xl font-bold\">{filteredAgents.length}</div>\n <div className=\"text-xs text-muted-foreground mt-0.5\">{onlineCount} online</div>\n </CardContent>\n </Card>\n\n <Card className=\"cursor-pointer hover:border-zinc-600 transition-colors\" onClick={() => nav('agents')}>\n <CardHeader className=\"pb-1 pt-4 px-4\">\n <CardTitle className=\"text-xs font-medium text-muted-foreground flex items-center gap-1.5\">\n <Activity className=\"w-3.5 h-3.5\" />\n Busy\n </CardTitle>\n </CardHeader>\n <CardContent className=\"px-4 pb-4\">\n <div className=\"text-2xl font-bold\">{busyCount}</div>\n <div className=\"text-xs text-muted-foreground mt-0.5\">in a turn now</div>\n </CardContent>\n </Card>\n\n <Card className=\"cursor-pointer hover:border-zinc-600 transition-colors\" onClick={() => nav('messages')}>\n <CardHeader className=\"pb-1 pt-4 px-4\">\n <CardTitle className=\"text-xs font-medium text-muted-foreground flex items-center gap-1.5\">\n <MessageSquare className=\"w-3.5 h-3.5\" />\n Messages 24h\n </CardTitle>\n </CardHeader>\n <CardContent className=\"px-4 pb-4\">\n <div className=\"text-2xl font-bold\">{stats.messagesLast24h ?? '—'}</div>\n <div className=\"text-xs text-muted-foreground mt-0.5\">last 24 hours</div>\n </CardContent>\n </Card>\n\n <Card className=\"cursor-pointer hover:border-zinc-600 transition-colors\" onClick={() => nav('messages')}>\n <CardHeader className=\"pb-1 pt-4 px-4\">\n <CardTitle className=\"text-xs font-medium text-muted-foreground flex items-center gap-1.5\">\n <Mail className=\"w-3.5 h-3.5\" />\n Total Messages\n </CardTitle>\n </CardHeader>\n <CardContent className=\"px-4 pb-4\">\n <div className=\"text-2xl font-bold\">{stats.messages ?? '—'}</div>\n <div className=\"text-xs text-muted-foreground mt-0.5\">all time</div>\n </CardContent>\n </Card>\n </div>\n\n {/* Health alert banner */}\n {healthIssues.length > 0 && (\n <Card className=\"border-yellow-500/40 bg-yellow-500/5\">\n <CardHeader className=\"pb-2 pt-4 px-4\">\n <CardTitle className=\"text-sm font-medium text-yellow-400 flex items-center gap-2\">\n <AlertTriangle className=\"w-4 h-4\" />\n Health Alerts ({healthIssues.length})\n </CardTitle>\n </CardHeader>\n <CardContent className=\"px-4 pb-4 space-y-2\">\n {healthIssues.map((issue) => (\n <div key={issue.name} className=\"text-sm space-y-1\">\n <div className=\"flex items-center gap-2\">\n <Badge\n variant=\"outline\"\n className={issue.status === 'error' ? 'border-red-500/40 text-red-400' : 'border-yellow-500/40 text-yellow-400'}\n >\n {issue.status}\n </Badge>\n <span className=\"font-medium\">{issue.name}</span>\n </div>\n <p className=\"text-xs text-muted-foreground\">{issue.detail}</p>\n {issue.subjects.length > 0 && (\n <div className=\"flex flex-wrap gap-1.5\">\n {issue.subjects.map((subject) => (\n <Badge key={subject.id} variant=\"secondary\" className=\"max-w-full truncate text-[11px]\" title={[subject.id, subject.status, subject.detail].filter(Boolean).join(' · ')}>\n {subject.label || subject.id}\n {subject.status ? ` · ${subject.status}` : ''}\n {subject.detail ? ` · ${subject.detail}` : ''}\n </Badge>\n ))}\n </div>\n )}\n {issue.actions.length > 0 && (\n <div className=\"flex flex-wrap gap-1.5 pt-0.5\">\n {issue.actions.slice(0, 3).map((action) => (\n <button\n key={action.label}\n onClick={() => runHealthAction(action)}\n className=\"text-xs text-blue-400 hover:text-blue-300 underline underline-offset-2\"\n >\n {action.label}\n </button>\n ))}\n </div>\n )}\n </div>\n ))}\n </CardContent>\n </Card>\n )}\n\n {/* Attention shortcuts */}\n <div className=\"grid grid-cols-1 sm:grid-cols-3 gap-4\">\n <Card\n className={`cursor-pointer hover:border-zinc-600 transition-colors ${attention.unreadInbox > 0 ? 'border-red-500/40' : ''}`}\n onClick={() => nav('chat')}\n >\n <CardContent className=\"p-4 flex items-center gap-3\">\n <div className={`p-2 rounded-lg ${attention.unreadInbox > 0 ? 'bg-red-500/15' : 'bg-zinc-800'}`}>\n <Inbox className={`w-4 h-4 ${attention.unreadInbox > 0 ? 'text-red-400' : 'text-zinc-400'}`} />\n </div>\n <div>\n <div className=\"text-lg font-bold\">{attention.unreadInbox}</div>\n <div className=\"text-xs text-muted-foreground\">Unread</div>\n </div>\n </CardContent>\n </Card>\n\n <Card\n className={`cursor-pointer hover:border-zinc-600 transition-colors ${attention.pendingPairInvites > 0 ? 'border-yellow-500/40' : ''}`}\n onClick={() => nav('pairs')}\n >\n <CardContent className=\"p-4 flex items-center gap-3\">\n <div className={`p-2 rounded-lg ${attention.pendingPairInvites > 0 ? 'bg-yellow-500/15' : 'bg-zinc-800'}`}>\n <Link className={`w-4 h-4 ${attention.pendingPairInvites > 0 ? 'text-yellow-400' : 'text-zinc-400'}`} />\n </div>\n <div>\n <div className=\"text-lg font-bold\">{attention.pendingPairInvites}</div>\n <div className=\"text-xs text-muted-foreground\">Pair invites</div>\n </div>\n </CardContent>\n </Card>\n\n <Card\n className={`cursor-pointer hover:border-zinc-600 transition-colors ${attention.claimableTasks > 0 ? 'border-orange-500/40' : ''}`}\n onClick={() => nav('work')}\n >\n <CardContent className=\"p-4 flex items-center gap-3\">\n <div className={`p-2 rounded-lg ${attention.claimableTasks > 0 ? 'bg-orange-500/15' : 'bg-zinc-800'}`}>\n <ListChecks className={`w-4 h-4 ${attention.claimableTasks > 0 ? 'text-orange-400' : 'text-zinc-400'}`} />\n </div>\n <div>\n <div className=\"text-lg font-bold\">{attention.claimableTasks}</div>\n <div className=\"text-xs text-muted-foreground\">Claimable waiting</div>\n </div>\n </CardContent>\n </Card>\n </div>\n\n {/* Two-column: agents + recent activity */}\n <div className=\"grid grid-cols-1 md:grid-cols-2 gap-6\">\n {/* Top agents */}\n <Card>\n <CardHeader className=\"pb-2 pt-4 px-4\">\n <CardTitle className=\"text-sm font-medium flex items-center gap-2\">\n <Bot className=\"w-4 h-4 text-muted-foreground\" />\n Agents\n <span className=\"ml-auto text-xs text-muted-foreground font-normal\">{recentAgents.length}</span>\n </CardTitle>\n </CardHeader>\n <CardContent className=\"px-0 pb-0\">\n <ScrollArea className=\"h-[340px]\">\n {recentAgents.length === 0 ? (\n <div className=\"px-4 pb-4 text-sm text-muted-foreground\">No agents registered.</div>\n ) : (\n <div className=\"space-y-0\">\n {recentAgents.map((agent, i) => (\n <div key={agent.id}>\n {i > 0 && <Separator />}\n <div className=\"flex items-center gap-2.5 px-4 py-2.5 hover:bg-zinc-800/50 transition-colors cursor-pointer\" onClick={() => useRelayStore.getState().openAgentDetail(agent)}>\n <StatusDot agent={agent} now={now} />\n <AgentTypeIcon agent={agent} />\n <div className=\"flex-1 min-w-0\">\n <div className=\"text-sm font-medium truncate\">{displayName(agent)}</div>\n {agent.tags.length > 0 && (\n <div className=\"flex gap-1 mt-0.5 flex-wrap\">\n {agent.tags.slice(0, 2).map((t) => (\n <Badge key={t} variant=\"outline\" className=\"text-[9px] px-1 py-0 h-4\">{t}</Badge>\n ))}\n </div>\n )}\n </div>\n <span className=\"text-xs text-muted-foreground shrink-0\">{timeAgo(now, agent.lastSeen)}</span>\n </div>\n </div>\n ))}\n </div>\n )}\n </ScrollArea>\n </CardContent>\n </Card>\n\n {/* Recent activity */}\n <Card>\n <CardHeader className=\"pb-2 pt-4 px-4\">\n <CardTitle className=\"text-sm font-medium flex items-center gap-2\">\n <Activity className=\"w-4 h-4 text-muted-foreground\" />\n Recent Activity\n <span className=\"ml-auto text-xs text-muted-foreground font-normal\">{recentMessages.length}</span>\n </CardTitle>\n </CardHeader>\n <CardContent className=\"px-0 pb-0\">\n <ScrollArea className=\"h-[340px]\">\n {recentMessages.length === 0 ? (\n <div className=\"px-4 pb-4 text-sm text-muted-foreground\">No recent messages.</div>\n ) : (\n <div className=\"space-y-0\">\n {recentMessages.map((msg, i) => (\n <div key={msg.id}>\n {i > 0 && <Separator />}\n <div className=\"px-4 py-2.5 hover:bg-zinc-800/50 transition-colors\">\n <div className=\"flex items-center gap-1 text-xs text-muted-foreground mb-0.5\">\n <span className=\"text-foreground font-medium truncate max-w-[100px]\">{displayTarget(msg.from, agentsById)}</span>\n <span>→</span>\n <span className=\"truncate max-w-[100px]\">{displayTarget(msg.to, agentsById)}</span>\n <span className=\"ml-auto shrink-0 tabular-nums\"><span className=\"opacity-40 mr-1\">#{msg.id}</span>{timeAgo(now, msg.createdAt)}</span>\n </div>\n <div className=\"text-xs text-foreground line-clamp-2 leading-snug\">{messagePreview(msg)}</div>\n </div>\n </div>\n ))}\n </div>\n )}\n </ScrollArea>\n </CardContent>\n </Card>\n </div>\n </div>\n )\n}\n"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{Kn as e,_t as t,ct as n,f as r,rr as i,yt as a}from"./lucide-react-CoU_Xts2.js";import{p as o,t as s}from"./store-zFLzd0Jd.js";import{K as c,d as l,h as u,st as d}from"./display-GFbGUG0O.js";import{t as f}from"./badge-XEru6wto.js";import{t as p}from"./button-C3CQSr4p.js";import{G as m}from"./index-
|
|
2
|
-
//# sourceMappingURL=pairs-
|
|
1
|
+
import{Kn as e,_t as t,ct as n,f as r,rr as i,yt as a}from"./lucide-react-CoU_Xts2.js";import{p as o,t as s}from"./store-zFLzd0Jd.js";import{K as c,d as l,h as u,st as d}from"./display-GFbGUG0O.js";import{t as f}from"./badge-XEru6wto.js";import{t as p}from"./button-C3CQSr4p.js";import{G as m}from"./index-0uIGXT14.js";import{o as h,r as g,t as _}from"./card-C5XTIPvq.js";var v=i(),y=[{value:`open`,label:`Active & Pending`},{value:`active`,label:`Active`},{value:`pending`,label:`Pending`},{value:`ended`,label:`Ended`},{value:`rejected`,label:`Rejected`},{value:`expired`,label:`Expired`},{value:``,label:`All`}];function b(){let e=o(),n=s(e=>e.pairs),i=s(e=>e.agentsById),a=s(e=>e.pairStatusFilter),c=s(e=>e.set),u=s(e=>e.fetchPairs),d=s(e=>e.openPairInvite),h=s(e=>e.openPairMessage),g=s(e=>e.doAcceptPair),_=s(e=>e.doRejectPair),b=s(e=>e.doHangupPair),S=n.filter(e=>e.status===`pending`).length;function C(e){c({pairStatusFilter:e}),setTimeout(()=>u(),0)}function w(e){return i[e]?l(i[e]):e.slice(-10)}return(0,v.jsxs)(`div`,{className:`space-y-4`,children:[(0,v.jsxs)(`div`,{className:`flex items-center justify-between flex-wrap gap-2`,children:[(0,v.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,v.jsx)(t,{className:`w-5 h-5 text-muted-foreground`}),(0,v.jsx)(`h2`,{className:`text-lg font-semibold`,children:`Pair Sessions`}),S>0&&(0,v.jsxs)(f,{className:`bg-yellow-500/20 text-yellow-400 border-yellow-500/30 border`,children:[S,` pending`]})]}),(0,v.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,v.jsx)(`select`,{className:`rounded-md border border-input bg-background px-3 py-1.5 text-sm`,value:a,onChange:e=>C(e.target.value),children:y.map(e=>(0,v.jsx)(`option`,{value:e.value,children:e.label},e.value))}),(0,v.jsxs)(p,{size:`sm`,onClick:()=>d(),children:[(0,v.jsx)(r,{className:`w-4 h-4 mr-1`}),` Pair agents`]})]})]}),(0,v.jsx)(m,{className:`h-[calc(100dvh-11rem)]`,children:(0,v.jsxs)(`div`,{className:`space-y-3 pr-2`,children:[n.length===0&&(0,v.jsx)(`div`,{className:`text-center text-muted-foreground py-16 text-sm`,children:`No pair sessions`}),n.map(t=>(0,v.jsx)(x,{pair:t,now:e,agentName:w,onAccept:()=>g(t),onReject:()=>_(t),onMessage:()=>h(t),onHangup:()=>b(t)},t.id))]})})]})}function x({pair:t,now:r,agentName:i,onAccept:o,onReject:s,onMessage:l,onHangup:m}){let y=d[t.status]||`bg-zinc-500/20 text-zinc-400`,b=t.status===`pending`,x=t.status===`active`;return(0,v.jsxs)(_,{children:[(0,v.jsx)(h,{className:`py-3 px-4 pb-0`,children:(0,v.jsxs)(`div`,{className:`flex items-start justify-between gap-2`,children:[(0,v.jsxs)(`div`,{className:`flex items-center gap-2 flex-wrap flex-1 min-w-0`,children:[(0,v.jsx)(f,{className:`${y} border text-xs`,children:t.status}),(0,v.jsxs)(`div`,{className:`flex items-center gap-1.5 text-sm min-w-0`,children:[(0,v.jsx)(`span`,{className:`font-medium truncate max-w-[120px]`,title:t.requesterId,children:i(t.requesterId)}),(0,v.jsx)(e,{className:`w-3.5 h-3.5 text-muted-foreground shrink-0`}),(0,v.jsx)(`span`,{className:`font-medium truncate max-w-[120px]`,title:t.targetId,children:i(t.targetId)})]})]}),(0,v.jsxs)(`div`,{className:`text-right shrink-0`,children:[(0,v.jsx)(`div`,{className:`text-xs font-mono text-muted-foreground/60 truncate max-w-[100px]`,children:t.id.slice(-10)}),(0,v.jsx)(`div`,{className:`text-xs text-muted-foreground`,title:u(t.updatedAt),children:c(r,t.updatedAt)})]})]})}),(0,v.jsxs)(g,{className:`px-4 py-3`,children:[t.objective&&(0,v.jsx)(`p`,{className:`text-xs text-muted-foreground mb-3 line-clamp-2`,children:t.objective}),(0,v.jsxs)(`div`,{className:`flex items-center gap-2 flex-wrap`,children:[b&&(0,v.jsxs)(v.Fragment,{children:[(0,v.jsx)(p,{size:`sm`,className:`bg-emerald-600 hover:bg-emerald-700 text-white h-7 text-xs`,onClick:o,children:`Accept`}),(0,v.jsx)(p,{size:`sm`,variant:`outline`,className:`h-7 text-xs text-red-400 hover:text-red-300`,onClick:s,children:`Reject`})]}),x&&(0,v.jsxs)(v.Fragment,{children:[(0,v.jsxs)(p,{size:`sm`,variant:`outline`,className:`h-7 text-xs`,onClick:l,children:[(0,v.jsx)(n,{className:`w-3.5 h-3.5 mr-1`}),` Message`]}),(0,v.jsxs)(p,{size:`sm`,variant:`outline`,className:`h-7 text-xs text-red-400 hover:text-red-300`,onClick:m,children:[(0,v.jsx)(a,{className:`w-3.5 h-3.5 mr-1`}),` Hang up`]})]})]})]})]})}export{b as PairsView};
|
|
2
|
+
//# sourceMappingURL=pairs-5tXdHylI.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pairs-
|
|
1
|
+
{"version":3,"file":"pairs-5tXdHylI.js","names":[],"sources":["../../dashboard/src/components/views/pairs.tsx"],"sourcesContent":["import { useRelayStore, useNow } from '@/store'\nimport { Card, CardContent, CardHeader } from '@/components/ui/card'\nimport { Badge } from '@/components/ui/badge'\nimport { Button } from '@/components/ui/button'\nimport { ScrollArea } from '@/components/ui/scroll-area'\nimport { Link, Link2Off, Mail, UserPlus, ArrowRight } from 'lucide-react'\nimport { displayName, timeAgo, fmtTime } from '@/lib/display'\nimport { PAIR_STATUS_COLORS } from '@/lib/constants'\nimport type { PairSession } from '@/types'\n\nconst STATUS_OPTIONS = [\n { value: 'open', label: 'Active & Pending' },\n { value: 'active', label: 'Active' },\n { value: 'pending', label: 'Pending' },\n { value: 'ended', label: 'Ended' },\n { value: 'rejected', label: 'Rejected' },\n { value: 'expired', label: 'Expired' },\n { value: '', label: 'All' },\n]\n\nexport function PairsView() {\n const now = useNow()\n const pairs = useRelayStore((s) => s.pairs)\n const agentsById = useRelayStore((s) => s.agentsById)\n const pairStatusFilter = useRelayStore((s) => s.pairStatusFilter)\n const set = useRelayStore((s) => s.set)\n const fetchPairs = useRelayStore((s) => s.fetchPairs)\n const openPairInvite = useRelayStore((s) => s.openPairInvite)\n const openPairMessage = useRelayStore((s) => s.openPairMessage)\n const doAcceptPair = useRelayStore((s) => s.doAcceptPair)\n const doRejectPair = useRelayStore((s) => s.doRejectPair)\n const doHangupPair = useRelayStore((s) => s.doHangupPair)\n\n const pendingCount = pairs.filter((p) => p.status === 'pending').length\n\n function handleStatusChange(value: string) {\n set({ pairStatusFilter: value })\n setTimeout(() => fetchPairs(), 0)\n }\n\n function agentName(id: string) {\n return agentsById[id] ? displayName(agentsById[id]) : id.slice(-10)\n }\n\n return (\n <div className=\"space-y-4\">\n <div className=\"flex items-center justify-between flex-wrap gap-2\">\n <div className=\"flex items-center gap-2\">\n <Link className=\"w-5 h-5 text-muted-foreground\" />\n <h2 className=\"text-lg font-semibold\">Pair Sessions</h2>\n {pendingCount > 0 && (\n <Badge className=\"bg-yellow-500/20 text-yellow-400 border-yellow-500/30 border\">\n {pendingCount} pending\n </Badge>\n )}\n </div>\n <div className=\"flex items-center gap-2\">\n <select\n className=\"rounded-md border border-input bg-background px-3 py-1.5 text-sm\"\n value={pairStatusFilter}\n onChange={(e) => handleStatusChange(e.target.value)}\n >\n {STATUS_OPTIONS.map((o) => <option key={o.value} value={o.value}>{o.label}</option>)}\n </select>\n <Button size=\"sm\" onClick={() => openPairInvite()}>\n <UserPlus className=\"w-4 h-4 mr-1\" /> Pair agents\n </Button>\n </div>\n </div>\n\n <ScrollArea className=\"h-[calc(100dvh-11rem)]\">\n <div className=\"space-y-3 pr-2\">\n {pairs.length === 0 && (\n <div className=\"text-center text-muted-foreground py-16 text-sm\">No pair sessions</div>\n )}\n {pairs.map((pair) => (\n <PairCard\n key={pair.id}\n pair={pair}\n now={now}\n agentName={agentName}\n onAccept={() => doAcceptPair(pair)}\n onReject={() => doRejectPair(pair)}\n onMessage={() => openPairMessage(pair)}\n onHangup={() => doHangupPair(pair)}\n />\n ))}\n </div>\n </ScrollArea>\n </div>\n )\n}\n\nfunction PairCard({\n pair, now, agentName, onAccept, onReject, onMessage, onHangup,\n}: {\n pair: PairSession\n now: number\n agentName: (id: string) => string\n onAccept: () => void\n onReject: () => void\n onMessage: () => void\n onHangup: () => void\n}) {\n const colorClass = PAIR_STATUS_COLORS[pair.status] || 'bg-zinc-500/20 text-zinc-400'\n const isPending = pair.status === 'pending'\n const isActive = pair.status === 'active'\n\n return (\n <Card>\n <CardHeader className=\"py-3 px-4 pb-0\">\n <div className=\"flex items-start justify-between gap-2\">\n <div className=\"flex items-center gap-2 flex-wrap flex-1 min-w-0\">\n <Badge className={`${colorClass} border text-xs`}>{pair.status}</Badge>\n <div className=\"flex items-center gap-1.5 text-sm min-w-0\">\n <span className=\"font-medium truncate max-w-[120px]\" title={pair.requesterId}>{agentName(pair.requesterId)}</span>\n <ArrowRight className=\"w-3.5 h-3.5 text-muted-foreground shrink-0\" />\n <span className=\"font-medium truncate max-w-[120px]\" title={pair.targetId}>{agentName(pair.targetId)}</span>\n </div>\n </div>\n <div className=\"text-right shrink-0\">\n <div className=\"text-xs font-mono text-muted-foreground/60 truncate max-w-[100px]\">{pair.id.slice(-10)}</div>\n <div className=\"text-xs text-muted-foreground\" title={fmtTime(pair.updatedAt)}>\n {timeAgo(now, pair.updatedAt)}\n </div>\n </div>\n </div>\n </CardHeader>\n <CardContent className=\"px-4 py-3\">\n {pair.objective && (\n <p className=\"text-xs text-muted-foreground mb-3 line-clamp-2\">{pair.objective}</p>\n )}\n <div className=\"flex items-center gap-2 flex-wrap\">\n {isPending && (\n <>\n <Button size=\"sm\" className=\"bg-emerald-600 hover:bg-emerald-700 text-white h-7 text-xs\" onClick={onAccept}>\n Accept\n </Button>\n <Button size=\"sm\" variant=\"outline\" className=\"h-7 text-xs text-red-400 hover:text-red-300\" onClick={onReject}>\n Reject\n </Button>\n </>\n )}\n {isActive && (\n <>\n <Button size=\"sm\" variant=\"outline\" className=\"h-7 text-xs\" onClick={onMessage}>\n <Mail className=\"w-3.5 h-3.5 mr-1\" /> Message\n </Button>\n <Button size=\"sm\" variant=\"outline\" className=\"h-7 text-xs text-red-400 hover:text-red-300\" onClick={onHangup}>\n <Link2Off className=\"w-3.5 h-3.5 mr-1\" /> Hang up\n </Button>\n </>\n )}\n </div>\n </CardContent>\n </Card>\n )\n}\n"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{r as e}from"./chunk-CilyBKbf.js";import{F as t,In as n,M as r,R as ee,Wt as i,gr as a,ir as o,rr as s,tr as c,xn as l}from"./lucide-react-CoU_Xts2.js";import{d as u}from"./types-CRptbSYh.js";import{K as d}from"./display-GFbGUG0O.js";import{t as f}from"./badge-XEru6wto.js";import{t as p}from"./button-C3CQSr4p.js";import{W as m}from"./index-DnUo0Zqg.js";import{a as h,i as g,o as _,r as v,s as y,t as b}from"./card-C5XTIPvq.js";var x=e(a(),1),S=s(),C=`all`;function w(e){return e.split(/[^a-zA-Z0-9]+/).filter(Boolean).map(e=>e.charAt(0).toUpperCase()+e.slice(1)).join(` `)}function T(e){return Array.isArray(e)?[...e].sort((e,t)=>{let n=e.category.localeCompare(t.category);if(n!==0)return n;let r=e.title.localeCompare(t.title);return r===0?e.slug.localeCompare(t.slug):r}):[]}function E(){let[e,a]=(0,x.useState)([]),[s,E]=(0,x.useState)(!0),[D,O]=(0,x.useState)(``),[k,A]=(0,x.useState)(``),[j,M]=(0,x.useState)(``),[N,P]=(0,x.useState)(C),[F,I]=(0,x.useState)(``),[L,R]=(0,x.useState)({}),[z,B]=(0,x.useState)(``),[V,H]=(0,x.useState)(()=>Date.now());async function U(){E(!0),O(``);try{a(T((await o(`GET`,`/settings/prompts`)).templates)),H(Date.now())}catch(e){O(u(e))}finally{E(!1)}}(0,x.useEffect)(()=>{U()},[]);let W=(0,x.useMemo)(()=>{let t=new Map;for(let n of e)t.set(n.category,(t.get(n.category)??0)+1);return[...t.entries()].sort(([e],[t])=>e.localeCompare(t)).map(([e,t])=>({key:e,count:t,label:w(e)}))},[e]),G=N===C||W.some(e=>e.key===N)?N:C,K=(0,x.useMemo)(()=>G===C?e:e.filter(e=>e.category===G),[G,e]),q=K.some(e=>e.slug===F)?F:K[0]?.slug??``,J=K.find(e=>e.slug===q)??null,Y=J?L[J.slug]??J.template:``,X=J?Y!==J.template:!1,Z=e.filter(e=>e.template!==e.defaultTemplate).length,Q=J?z===J.slug:!1;function te(e){I(e),A(``),M(``)}function $(e){a(t=>T(t.map(t=>t.slug===e.slug?e:t))),R(t=>({...t,[e.slug]:e.template})),H(Date.now())}async function ne(){if(!(!J||!X)){B(J.slug),A(``),M(``);try{let e=await o(`PUT`,`/settings/prompts/${encodeURIComponent(J.slug)}`,{template:Y});$(e),M(`Saved ${e.title}.`)}catch(e){A(u(e))}finally{B(``)}}}async function re(){if(!(!J||J.template===J.defaultTemplate)){B(J.slug),A(``),M(``);try{let e=await o(`POST`,`/settings/prompts/${encodeURIComponent(J.slug)}/reset`);$(e),M(`Reset ${e.title} to the built-in default.`)}catch(e){A(u(e))}finally{B(``)}}}function ie(){J&&(R(e=>({...e,[J.slug]:J.template})),A(``),M(`Unsaved edits discarded.`))}return(0,S.jsxs)(`div`,{className:`space-y-4 p-4`,children:[(0,S.jsxs)(`div`,{className:`flex flex-wrap items-start justify-between gap-3`,children:[(0,S.jsxs)(`div`,{children:[(0,S.jsx)(`h1`,{className:`text-lg font-semibold`,children:`Prompts`}),(0,S.jsx)(`p`,{className:`text-sm text-muted-foreground`,children:`View and edit the externalized prompt templates used across Relay lifecycle, routing, workspace, and automation flows.`})]}),(0,S.jsxs)(`div`,{className:`flex flex-wrap items-center gap-2`,children:[(0,S.jsxs)(f,{variant:`outline`,className:`gap-1`,children:[(0,S.jsx)(i,{className:`size-3`}),e.length,` template`,e.length===1?``:`s`]}),(0,S.jsxs)(f,{variant:`outline`,className:c(`gap-1`,Z>0&&`border-amber-500/40 bg-amber-500/10 text-amber-300`),children:[Z,` modified`]}),(0,S.jsxs)(p,{variant:`outline`,size:`sm`,onClick:()=>void U(),disabled:s,children:[(0,S.jsx)(ee,{className:c(`size-4`,s&&`animate-spin`)}),`Refresh`]})]})]}),D&&(0,S.jsxs)(`div`,{className:`flex items-start gap-2 rounded-lg border border-destructive/40 bg-destructive/10 p-3 text-sm text-destructive`,children:[(0,S.jsx)(l,{className:`mt-0.5 size-4`}),(0,S.jsx)(`span`,{children:D})]}),s&&e.length===0?(0,S.jsx)(b,{size:`sm`,children:(0,S.jsx)(v,{className:`text-sm text-muted-foreground`,children:`Loading prompt templates…`})}):e.length===0?(0,S.jsx)(b,{children:(0,S.jsx)(v,{className:`py-10 text-center text-sm text-muted-foreground`,children:`No prompt templates are available yet.`})}):(0,S.jsxs)(`div`,{className:`grid gap-4 xl:grid-cols-[220px_minmax(0,0.9fr)_minmax(0,1.1fr)]`,children:[(0,S.jsxs)(`nav`,{className:`space-y-1 xl:sticky xl:top-4 xl:self-start`,children:[(0,S.jsxs)(`button`,{type:`button`,className:c(`w-full rounded-md border px-3 py-2 text-left text-sm transition-colors`,G===C?`border-primary/50 bg-primary/10 text-foreground`:`border-transparent hover:border-border hover:bg-accent`),onClick:()=>P(C),children:[(0,S.jsxs)(`span`,{className:`flex items-center gap-2`,children:[(0,S.jsx)(`span`,{className:`font-medium`,children:`All`}),(0,S.jsx)(f,{variant:`outline`,className:`ml-auto h-4 px-1 text-[10px]`,children:e.length})]}),(0,S.jsx)(`span`,{className:`block truncate text-xs text-muted-foreground`,children:`Every externalized prompt template`})]}),W.map(e=>(0,S.jsxs)(`button`,{type:`button`,className:c(`w-full rounded-md border px-3 py-2 text-left text-sm transition-colors`,G===e.key?`border-primary/50 bg-primary/10 text-foreground`:`border-transparent hover:border-border hover:bg-accent`),onClick:()=>P(e.key),children:[(0,S.jsxs)(`span`,{className:`flex items-center gap-2`,children:[(0,S.jsx)(`span`,{className:`font-medium`,children:e.label}),(0,S.jsx)(f,{variant:`outline`,className:`ml-auto h-4 px-1 text-[10px]`,children:e.count})]}),(0,S.jsx)(`span`,{className:`block truncate text-xs font-mono text-muted-foreground`,children:e.key})]},e.key))]}),(0,S.jsxs)(`div`,{className:`min-w-0 space-y-3`,children:[(0,S.jsx)(`div`,{className:`flex items-center justify-between gap-2 px-1`,children:(0,S.jsxs)(`div`,{children:[(0,S.jsx)(`h2`,{className:`text-sm font-semibold`,children:G===C?`All templates`:`${w(G)} templates`}),(0,S.jsxs)(`p`,{className:`text-xs text-muted-foreground`,children:[K.length,` template`,K.length===1?``:`s`,` in this view`]})]})}),K.map(e=>{let t=e.slug===q,n=e.template!==e.defaultTemplate;return(0,S.jsx)(`button`,{type:`button`,className:c(`w-full rounded-xl border p-4 text-left transition-colors`,t?`border-primary/50 bg-primary/10 ring-1 ring-primary/20`:`border-border bg-card hover:border-primary/30 hover:bg-accent`),onClick:()=>te(e.slug),children:(0,S.jsx)(`div`,{className:`flex flex-wrap items-start gap-2`,children:(0,S.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,S.jsxs)(`div`,{className:`flex flex-wrap items-center gap-2`,children:[(0,S.jsx)(`span`,{className:`font-medium text-foreground`,children:e.title}),n&&(0,S.jsx)(f,{className:`bg-amber-500/15 text-amber-300 hover:bg-amber-500/15`,children:`Modified`}),(0,S.jsx)(f,{variant:`outline`,className:`text-[10px]`,children:w(e.category)})]}),(0,S.jsx)(`div`,{className:`mt-1 font-mono text-[11px] text-muted-foreground`,children:e.slug}),e.description&&(0,S.jsx)(`p`,{className:`mt-2 line-clamp-2 text-sm text-muted-foreground`,children:e.description}),(0,S.jsxs)(`div`,{className:`mt-3 flex flex-wrap items-center gap-3 text-[11px] text-muted-foreground`,children:[(0,S.jsxs)(`span`,{children:[e.variables.length,` variable`,e.variables.length===1?``:`s`]}),(0,S.jsxs)(`span`,{children:[`Updated `,d(V,e.updatedAt)]})]})]})})},e.slug)})]}),(0,S.jsx)(`div`,{className:`min-w-0`,children:J?(0,S.jsxs)(b,{children:[(0,S.jsxs)(_,{className:`border-b border-border`,children:[(0,S.jsxs)(y,{className:`flex flex-wrap items-center gap-2`,children:[(0,S.jsx)(`span`,{children:J.title}),J.template!==J.defaultTemplate&&(0,S.jsx)(f,{className:`bg-amber-500/15 text-amber-300 hover:bg-amber-500/15`,children:`Customized`}),X&&(0,S.jsx)(f,{variant:`outline`,children:`Unsaved`})]}),(0,S.jsxs)(g,{className:`space-y-1`,children:[(0,S.jsx)(`div`,{className:`font-mono text-[11px]`,children:J.slug}),J.description&&(0,S.jsx)(`div`,{children:J.description})]})]}),(0,S.jsxs)(v,{className:`space-y-4 pt-4`,children:[k&&(0,S.jsxs)(`div`,{className:`flex items-start gap-2 rounded-md border border-destructive/40 bg-destructive/10 p-2 text-xs text-destructive`,children:[(0,S.jsx)(l,{className:`mt-0.5 size-3.5`}),(0,S.jsx)(`span`,{children:k})]}),j&&(0,S.jsx)(`div`,{className:`rounded-md border border-emerald-500/30 bg-emerald-500/10 px-3 py-2 text-xs text-emerald-300`,children:j}),(0,S.jsxs)(`div`,{className:`space-y-2`,children:[(0,S.jsxs)(`div`,{className:`flex items-center gap-2 text-xs font-medium text-muted-foreground`,children:[(0,S.jsx)(n,{className:`size-3.5`}),`Available variables`]}),J.variables.length>0?(0,S.jsx)(`div`,{className:`flex flex-wrap gap-1.5`,children:J.variables.map(e=>(0,S.jsx)(f,{variant:`secondary`,className:`font-mono text-[11px]`,children:`{{${e}}}`},e))}):(0,S.jsx)(`div`,{className:`text-xs text-muted-foreground`,children:`This template has no placeholder variables.`})]}),J.template!==J.defaultTemplate&&(0,S.jsx)(`div`,{className:`rounded-lg border border-amber-500/30 bg-amber-500/10 px-3 py-2 text-xs text-amber-200`,children:`This template differs from the built-in default. Reset will restore the original text.`}),(0,S.jsxs)(`div`,{className:`space-y-1.5`,children:[(0,S.jsx)(`label`,{htmlFor:`prompt-template-editor`,className:`text-xs font-medium text-muted-foreground`,children:`Template text`}),(0,S.jsx)(m,{id:`prompt-template-editor`,value:Y,onChange:e=>{let t=e.target.value;R(e=>({...e,[J.slug]:t})),k&&A(``),j&&M(``)},rows:18,spellCheck:!1,className:`min-h-[360px] resize-y font-mono text-xs leading-5`})]})]}),(0,S.jsxs)(h,{className:`flex flex-wrap items-center justify-between gap-2`,children:[(0,S.jsx)(`div`,{className:`text-xs text-muted-foreground`,children:X?`Editing local changes.`:`Updated ${d(V,J.updatedAt)}.`}),(0,S.jsxs)(`div`,{className:`flex flex-wrap items-center gap-2`,children:[J.template!==J.defaultTemplate&&(0,S.jsxs)(p,{variant:`outline`,size:`sm`,onClick:()=>void re(),disabled:Q,children:[(0,S.jsx)(t,{className:`size-4`}),`Reset to default`]}),(0,S.jsx)(p,{variant:`outline`,size:`sm`,onClick:ie,disabled:!X||Q,children:`Cancel`}),(0,S.jsxs)(p,{size:`sm`,onClick:()=>void ne(),disabled:!X||Q,children:[(0,S.jsx)(r,{className:`size-4`}),`Save`]})]})]})]}):(0,S.jsx)(b,{size:`sm`,children:(0,S.jsx)(v,{className:`text-sm text-muted-foreground`,children:`Select a prompt template to edit it.`})})})]})]})}export{E as PromptSettingsView};
|
|
2
|
-
//# sourceMappingURL=prompt-settings-
|
|
1
|
+
import{r as e}from"./chunk-CilyBKbf.js";import{F as t,In as n,M as r,R as ee,Wt as i,gr as a,ir as o,rr as s,tr as c,xn as l}from"./lucide-react-CoU_Xts2.js";import{d as u}from"./types-CRptbSYh.js";import{K as d}from"./display-GFbGUG0O.js";import{t as f}from"./badge-XEru6wto.js";import{t as p}from"./button-C3CQSr4p.js";import{W as m}from"./index-0uIGXT14.js";import{a as h,i as g,o as _,r as v,s as y,t as b}from"./card-C5XTIPvq.js";var x=e(a(),1),S=s(),C=`all`;function w(e){return e.split(/[^a-zA-Z0-9]+/).filter(Boolean).map(e=>e.charAt(0).toUpperCase()+e.slice(1)).join(` `)}function T(e){return Array.isArray(e)?[...e].sort((e,t)=>{let n=e.category.localeCompare(t.category);if(n!==0)return n;let r=e.title.localeCompare(t.title);return r===0?e.slug.localeCompare(t.slug):r}):[]}function E(){let[e,a]=(0,x.useState)([]),[s,E]=(0,x.useState)(!0),[D,O]=(0,x.useState)(``),[k,A]=(0,x.useState)(``),[j,M]=(0,x.useState)(``),[N,P]=(0,x.useState)(C),[F,I]=(0,x.useState)(``),[L,R]=(0,x.useState)({}),[z,B]=(0,x.useState)(``),[V,H]=(0,x.useState)(()=>Date.now());async function U(){E(!0),O(``);try{a(T((await o(`GET`,`/settings/prompts`)).templates)),H(Date.now())}catch(e){O(u(e))}finally{E(!1)}}(0,x.useEffect)(()=>{U()},[]);let W=(0,x.useMemo)(()=>{let t=new Map;for(let n of e)t.set(n.category,(t.get(n.category)??0)+1);return[...t.entries()].sort(([e],[t])=>e.localeCompare(t)).map(([e,t])=>({key:e,count:t,label:w(e)}))},[e]),G=N===C||W.some(e=>e.key===N)?N:C,K=(0,x.useMemo)(()=>G===C?e:e.filter(e=>e.category===G),[G,e]),q=K.some(e=>e.slug===F)?F:K[0]?.slug??``,J=K.find(e=>e.slug===q)??null,Y=J?L[J.slug]??J.template:``,X=J?Y!==J.template:!1,Z=e.filter(e=>e.template!==e.defaultTemplate).length,Q=J?z===J.slug:!1;function te(e){I(e),A(``),M(``)}function $(e){a(t=>T(t.map(t=>t.slug===e.slug?e:t))),R(t=>({...t,[e.slug]:e.template})),H(Date.now())}async function ne(){if(!(!J||!X)){B(J.slug),A(``),M(``);try{let e=await o(`PUT`,`/settings/prompts/${encodeURIComponent(J.slug)}`,{template:Y});$(e),M(`Saved ${e.title}.`)}catch(e){A(u(e))}finally{B(``)}}}async function re(){if(!(!J||J.template===J.defaultTemplate)){B(J.slug),A(``),M(``);try{let e=await o(`POST`,`/settings/prompts/${encodeURIComponent(J.slug)}/reset`);$(e),M(`Reset ${e.title} to the built-in default.`)}catch(e){A(u(e))}finally{B(``)}}}function ie(){J&&(R(e=>({...e,[J.slug]:J.template})),A(``),M(`Unsaved edits discarded.`))}return(0,S.jsxs)(`div`,{className:`space-y-4 p-4`,children:[(0,S.jsxs)(`div`,{className:`flex flex-wrap items-start justify-between gap-3`,children:[(0,S.jsxs)(`div`,{children:[(0,S.jsx)(`h1`,{className:`text-lg font-semibold`,children:`Prompts`}),(0,S.jsx)(`p`,{className:`text-sm text-muted-foreground`,children:`View and edit the externalized prompt templates used across Relay lifecycle, routing, workspace, and automation flows.`})]}),(0,S.jsxs)(`div`,{className:`flex flex-wrap items-center gap-2`,children:[(0,S.jsxs)(f,{variant:`outline`,className:`gap-1`,children:[(0,S.jsx)(i,{className:`size-3`}),e.length,` template`,e.length===1?``:`s`]}),(0,S.jsxs)(f,{variant:`outline`,className:c(`gap-1`,Z>0&&`border-amber-500/40 bg-amber-500/10 text-amber-300`),children:[Z,` modified`]}),(0,S.jsxs)(p,{variant:`outline`,size:`sm`,onClick:()=>void U(),disabled:s,children:[(0,S.jsx)(ee,{className:c(`size-4`,s&&`animate-spin`)}),`Refresh`]})]})]}),D&&(0,S.jsxs)(`div`,{className:`flex items-start gap-2 rounded-lg border border-destructive/40 bg-destructive/10 p-3 text-sm text-destructive`,children:[(0,S.jsx)(l,{className:`mt-0.5 size-4`}),(0,S.jsx)(`span`,{children:D})]}),s&&e.length===0?(0,S.jsx)(b,{size:`sm`,children:(0,S.jsx)(v,{className:`text-sm text-muted-foreground`,children:`Loading prompt templates…`})}):e.length===0?(0,S.jsx)(b,{children:(0,S.jsx)(v,{className:`py-10 text-center text-sm text-muted-foreground`,children:`No prompt templates are available yet.`})}):(0,S.jsxs)(`div`,{className:`grid gap-4 xl:grid-cols-[220px_minmax(0,0.9fr)_minmax(0,1.1fr)]`,children:[(0,S.jsxs)(`nav`,{className:`space-y-1 xl:sticky xl:top-4 xl:self-start`,children:[(0,S.jsxs)(`button`,{type:`button`,className:c(`w-full rounded-md border px-3 py-2 text-left text-sm transition-colors`,G===C?`border-primary/50 bg-primary/10 text-foreground`:`border-transparent hover:border-border hover:bg-accent`),onClick:()=>P(C),children:[(0,S.jsxs)(`span`,{className:`flex items-center gap-2`,children:[(0,S.jsx)(`span`,{className:`font-medium`,children:`All`}),(0,S.jsx)(f,{variant:`outline`,className:`ml-auto h-4 px-1 text-[10px]`,children:e.length})]}),(0,S.jsx)(`span`,{className:`block truncate text-xs text-muted-foreground`,children:`Every externalized prompt template`})]}),W.map(e=>(0,S.jsxs)(`button`,{type:`button`,className:c(`w-full rounded-md border px-3 py-2 text-left text-sm transition-colors`,G===e.key?`border-primary/50 bg-primary/10 text-foreground`:`border-transparent hover:border-border hover:bg-accent`),onClick:()=>P(e.key),children:[(0,S.jsxs)(`span`,{className:`flex items-center gap-2`,children:[(0,S.jsx)(`span`,{className:`font-medium`,children:e.label}),(0,S.jsx)(f,{variant:`outline`,className:`ml-auto h-4 px-1 text-[10px]`,children:e.count})]}),(0,S.jsx)(`span`,{className:`block truncate text-xs font-mono text-muted-foreground`,children:e.key})]},e.key))]}),(0,S.jsxs)(`div`,{className:`min-w-0 space-y-3`,children:[(0,S.jsx)(`div`,{className:`flex items-center justify-between gap-2 px-1`,children:(0,S.jsxs)(`div`,{children:[(0,S.jsx)(`h2`,{className:`text-sm font-semibold`,children:G===C?`All templates`:`${w(G)} templates`}),(0,S.jsxs)(`p`,{className:`text-xs text-muted-foreground`,children:[K.length,` template`,K.length===1?``:`s`,` in this view`]})]})}),K.map(e=>{let t=e.slug===q,n=e.template!==e.defaultTemplate;return(0,S.jsx)(`button`,{type:`button`,className:c(`w-full rounded-xl border p-4 text-left transition-colors`,t?`border-primary/50 bg-primary/10 ring-1 ring-primary/20`:`border-border bg-card hover:border-primary/30 hover:bg-accent`),onClick:()=>te(e.slug),children:(0,S.jsx)(`div`,{className:`flex flex-wrap items-start gap-2`,children:(0,S.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,S.jsxs)(`div`,{className:`flex flex-wrap items-center gap-2`,children:[(0,S.jsx)(`span`,{className:`font-medium text-foreground`,children:e.title}),n&&(0,S.jsx)(f,{className:`bg-amber-500/15 text-amber-300 hover:bg-amber-500/15`,children:`Modified`}),(0,S.jsx)(f,{variant:`outline`,className:`text-[10px]`,children:w(e.category)})]}),(0,S.jsx)(`div`,{className:`mt-1 font-mono text-[11px] text-muted-foreground`,children:e.slug}),e.description&&(0,S.jsx)(`p`,{className:`mt-2 line-clamp-2 text-sm text-muted-foreground`,children:e.description}),(0,S.jsxs)(`div`,{className:`mt-3 flex flex-wrap items-center gap-3 text-[11px] text-muted-foreground`,children:[(0,S.jsxs)(`span`,{children:[e.variables.length,` variable`,e.variables.length===1?``:`s`]}),(0,S.jsxs)(`span`,{children:[`Updated `,d(V,e.updatedAt)]})]})]})})},e.slug)})]}),(0,S.jsx)(`div`,{className:`min-w-0`,children:J?(0,S.jsxs)(b,{children:[(0,S.jsxs)(_,{className:`border-b border-border`,children:[(0,S.jsxs)(y,{className:`flex flex-wrap items-center gap-2`,children:[(0,S.jsx)(`span`,{children:J.title}),J.template!==J.defaultTemplate&&(0,S.jsx)(f,{className:`bg-amber-500/15 text-amber-300 hover:bg-amber-500/15`,children:`Customized`}),X&&(0,S.jsx)(f,{variant:`outline`,children:`Unsaved`})]}),(0,S.jsxs)(g,{className:`space-y-1`,children:[(0,S.jsx)(`div`,{className:`font-mono text-[11px]`,children:J.slug}),J.description&&(0,S.jsx)(`div`,{children:J.description})]})]}),(0,S.jsxs)(v,{className:`space-y-4 pt-4`,children:[k&&(0,S.jsxs)(`div`,{className:`flex items-start gap-2 rounded-md border border-destructive/40 bg-destructive/10 p-2 text-xs text-destructive`,children:[(0,S.jsx)(l,{className:`mt-0.5 size-3.5`}),(0,S.jsx)(`span`,{children:k})]}),j&&(0,S.jsx)(`div`,{className:`rounded-md border border-emerald-500/30 bg-emerald-500/10 px-3 py-2 text-xs text-emerald-300`,children:j}),(0,S.jsxs)(`div`,{className:`space-y-2`,children:[(0,S.jsxs)(`div`,{className:`flex items-center gap-2 text-xs font-medium text-muted-foreground`,children:[(0,S.jsx)(n,{className:`size-3.5`}),`Available variables`]}),J.variables.length>0?(0,S.jsx)(`div`,{className:`flex flex-wrap gap-1.5`,children:J.variables.map(e=>(0,S.jsx)(f,{variant:`secondary`,className:`font-mono text-[11px]`,children:`{{${e}}}`},e))}):(0,S.jsx)(`div`,{className:`text-xs text-muted-foreground`,children:`This template has no placeholder variables.`})]}),J.template!==J.defaultTemplate&&(0,S.jsx)(`div`,{className:`rounded-lg border border-amber-500/30 bg-amber-500/10 px-3 py-2 text-xs text-amber-200`,children:`This template differs from the built-in default. Reset will restore the original text.`}),(0,S.jsxs)(`div`,{className:`space-y-1.5`,children:[(0,S.jsx)(`label`,{htmlFor:`prompt-template-editor`,className:`text-xs font-medium text-muted-foreground`,children:`Template text`}),(0,S.jsx)(m,{id:`prompt-template-editor`,value:Y,onChange:e=>{let t=e.target.value;R(e=>({...e,[J.slug]:t})),k&&A(``),j&&M(``)},rows:18,spellCheck:!1,className:`min-h-[360px] resize-y font-mono text-xs leading-5`})]})]}),(0,S.jsxs)(h,{className:`flex flex-wrap items-center justify-between gap-2`,children:[(0,S.jsx)(`div`,{className:`text-xs text-muted-foreground`,children:X?`Editing local changes.`:`Updated ${d(V,J.updatedAt)}.`}),(0,S.jsxs)(`div`,{className:`flex flex-wrap items-center gap-2`,children:[J.template!==J.defaultTemplate&&(0,S.jsxs)(p,{variant:`outline`,size:`sm`,onClick:()=>void re(),disabled:Q,children:[(0,S.jsx)(t,{className:`size-4`}),`Reset to default`]}),(0,S.jsx)(p,{variant:`outline`,size:`sm`,onClick:ie,disabled:!X||Q,children:`Cancel`}),(0,S.jsxs)(p,{size:`sm`,onClick:()=>void ne(),disabled:!X||Q,children:[(0,S.jsx)(r,{className:`size-4`}),`Save`]})]})]})]}):(0,S.jsx)(b,{size:`sm`,children:(0,S.jsx)(v,{className:`text-sm text-muted-foreground`,children:`Select a prompt template to edit it.`})})})]})]})}export{E as PromptSettingsView};
|
|
2
|
+
//# sourceMappingURL=prompt-settings-Bn5mmi9w.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prompt-settings-DDEkMqPZ.js","names":[],"sources":["../../dashboard/src/components/views/prompt-settings.tsx"],"sourcesContent":["import { useEffect, useMemo, useState } from 'react'\nimport { api } from '@/lib/api'\nimport { cn } from '@/lib/utils'\nimport { timeAgo } from '@/lib/display'\nimport { Badge } from '@/components/ui/badge'\nimport { Button } from '@/components/ui/button'\nimport { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from '@/components/ui/card'\nimport { Textarea } from '@/components/ui/textarea'\nimport { AlertCircle, Braces, FileText, RefreshCw, RotateCcw, Save } from 'lucide-react'\nimport { errMessage } from 'agent-relay-sdk/types'\n\ninterface PromptTemplate {\n slug: string\n category: string\n title: string\n description?: string\n template: string\n defaultTemplate: string\n variables: string[]\n updatedAt: number\n createdAt: number\n}\n\nconst ALL_CATEGORY = 'all'\n\n\nfunction titleCaseCategory(category: string): string {\n return category\n .split(/[^a-zA-Z0-9]+/)\n .filter(Boolean)\n .map((part) => part.charAt(0).toUpperCase() + part.slice(1))\n .join(' ')\n}\n\nfunction sortTemplates(items: unknown): PromptTemplate[] {\n if (!Array.isArray(items)) return []\n return [...(items as PromptTemplate[])].sort((a, b) => {\n const category = a.category.localeCompare(b.category)\n if (category !== 0) return category\n const title = a.title.localeCompare(b.title)\n if (title !== 0) return title\n return a.slug.localeCompare(b.slug)\n })\n}\n\nexport function PromptSettingsView() {\n const [templates, setTemplates] = useState<PromptTemplate[]>([])\n const [loading, setLoading] = useState(true)\n const [loadError, setLoadError] = useState('')\n const [actionError, setActionError] = useState('')\n const [notice, setNotice] = useState('')\n const [activeCategory, setActiveCategory] = useState(ALL_CATEGORY)\n const [selectedSlug, setSelectedSlug] = useState('')\n const [drafts, setDrafts] = useState<Record<string, string>>({})\n const [savingSlug, setSavingSlug] = useState('')\n const [now, setNow] = useState(() => Date.now())\n\n async function reload() {\n setLoading(true)\n setLoadError('')\n try {\n const result = await api<{ templates: PromptTemplate[] }>('GET', '/settings/prompts')\n setTemplates(sortTemplates(result.templates))\n setNow(Date.now())\n } catch (error) {\n setLoadError(errMessage(error))\n } finally {\n setLoading(false)\n }\n }\n\n useEffect(() => {\n void reload()\n }, [])\n\n const categories = useMemo(() => {\n const counts = new Map<string, number>()\n for (const template of templates) counts.set(template.category, (counts.get(template.category) ?? 0) + 1)\n return [...counts.entries()]\n .sort(([a], [b]) => a.localeCompare(b))\n .map(([key, count]) => ({ key, count, label: titleCaseCategory(key) }))\n }, [templates])\n\n const effectiveCategory = activeCategory === ALL_CATEGORY || categories.some((item) => item.key === activeCategory)\n ? activeCategory\n : ALL_CATEGORY\n\n const visibleTemplates = useMemo(() => {\n if (effectiveCategory === ALL_CATEGORY) return templates\n return templates.filter((template) => template.category === effectiveCategory)\n }, [effectiveCategory, templates])\n\n const resolvedSelectedSlug = visibleTemplates.some((template) => template.slug === selectedSlug)\n ? selectedSlug\n : (visibleTemplates[0]?.slug ?? '')\n\n const selectedTemplate = visibleTemplates.find((template) => template.slug === resolvedSelectedSlug) ?? null\n const draft = selectedTemplate ? (drafts[selectedTemplate.slug] ?? selectedTemplate.template) : ''\n const hasUnsavedChanges = selectedTemplate ? draft !== selectedTemplate.template : false\n const modifiedCount = templates.filter((template) => template.template !== template.defaultTemplate).length\n const saving = selectedTemplate ? savingSlug === selectedTemplate.slug : false\n\n function selectTemplate(slug: string) {\n setSelectedSlug(slug)\n setActionError('')\n setNotice('')\n }\n\n function replaceTemplate(updated: PromptTemplate) {\n setTemplates((current) => sortTemplates(current.map((template) => template.slug === updated.slug ? updated : template)))\n setDrafts((current) => ({ ...current, [updated.slug]: updated.template }))\n setNow(Date.now())\n }\n\n async function saveTemplate() {\n if (!selectedTemplate || !hasUnsavedChanges) return\n setSavingSlug(selectedTemplate.slug)\n setActionError('')\n setNotice('')\n try {\n const updated = await api<PromptTemplate>('PUT', `/settings/prompts/${encodeURIComponent(selectedTemplate.slug)}`, {\n template: draft,\n })\n replaceTemplate(updated)\n setNotice(`Saved ${updated.title}.`)\n } catch (error) {\n setActionError(errMessage(error))\n } finally {\n setSavingSlug('')\n }\n }\n\n async function resetTemplate() {\n if (!selectedTemplate || selectedTemplate.template === selectedTemplate.defaultTemplate) return\n setSavingSlug(selectedTemplate.slug)\n setActionError('')\n setNotice('')\n try {\n const updated = await api<PromptTemplate>('POST', `/settings/prompts/${encodeURIComponent(selectedTemplate.slug)}/reset`)\n replaceTemplate(updated)\n setNotice(`Reset ${updated.title} to the built-in default.`)\n } catch (error) {\n setActionError(errMessage(error))\n } finally {\n setSavingSlug('')\n }\n }\n\n function cancelDraft() {\n if (!selectedTemplate) return\n setDrafts((current) => ({ ...current, [selectedTemplate.slug]: selectedTemplate.template }))\n setActionError('')\n setNotice('Unsaved edits discarded.')\n }\n\n return (\n <div className=\"space-y-4 p-4\">\n <div className=\"flex flex-wrap items-start justify-between gap-3\">\n <div>\n <h1 className=\"text-lg font-semibold\">Prompts</h1>\n <p className=\"text-sm text-muted-foreground\">View and edit the externalized prompt templates used across Relay lifecycle, routing, workspace, and automation flows.</p>\n </div>\n <div className=\"flex flex-wrap items-center gap-2\">\n <Badge variant=\"outline\" className=\"gap-1\">\n <FileText className=\"size-3\" />\n {templates.length} template{templates.length === 1 ? '' : 's'}\n </Badge>\n <Badge variant=\"outline\" className={cn('gap-1', modifiedCount > 0 && 'border-amber-500/40 bg-amber-500/10 text-amber-300')}>\n {modifiedCount} modified\n </Badge>\n <Button variant=\"outline\" size=\"sm\" onClick={() => void reload()} disabled={loading}>\n <RefreshCw className={cn('size-4', loading && 'animate-spin')} />\n Refresh\n </Button>\n </div>\n </div>\n\n {loadError && (\n <div className=\"flex items-start gap-2 rounded-lg border border-destructive/40 bg-destructive/10 p-3 text-sm text-destructive\">\n <AlertCircle className=\"mt-0.5 size-4\" />\n <span>{loadError}</span>\n </div>\n )}\n\n {loading && templates.length === 0 ? (\n <Card size=\"sm\">\n <CardContent className=\"text-sm text-muted-foreground\">Loading prompt templates…</CardContent>\n </Card>\n ) : templates.length === 0 ? (\n <Card>\n <CardContent className=\"py-10 text-center text-sm text-muted-foreground\">\n No prompt templates are available yet.\n </CardContent>\n </Card>\n ) : (\n <div className=\"grid gap-4 xl:grid-cols-[220px_minmax(0,0.9fr)_minmax(0,1.1fr)]\">\n <nav className=\"space-y-1 xl:sticky xl:top-4 xl:self-start\">\n <button\n type=\"button\"\n className={cn(\n 'w-full rounded-md border px-3 py-2 text-left text-sm transition-colors',\n effectiveCategory === ALL_CATEGORY ? 'border-primary/50 bg-primary/10 text-foreground' : 'border-transparent hover:border-border hover:bg-accent',\n )}\n onClick={() => setActiveCategory(ALL_CATEGORY)}\n >\n <span className=\"flex items-center gap-2\">\n <span className=\"font-medium\">All</span>\n <Badge variant=\"outline\" className=\"ml-auto h-4 px-1 text-[10px]\">{templates.length}</Badge>\n </span>\n <span className=\"block truncate text-xs text-muted-foreground\">Every externalized prompt template</span>\n </button>\n\n {categories.map((category) => (\n <button\n key={category.key}\n type=\"button\"\n className={cn(\n 'w-full rounded-md border px-3 py-2 text-left text-sm transition-colors',\n effectiveCategory === category.key ? 'border-primary/50 bg-primary/10 text-foreground' : 'border-transparent hover:border-border hover:bg-accent',\n )}\n onClick={() => setActiveCategory(category.key)}\n >\n <span className=\"flex items-center gap-2\">\n <span className=\"font-medium\">{category.label}</span>\n <Badge variant=\"outline\" className=\"ml-auto h-4 px-1 text-[10px]\">{category.count}</Badge>\n </span>\n <span className=\"block truncate text-xs font-mono text-muted-foreground\">{category.key}</span>\n </button>\n ))}\n </nav>\n\n <div className=\"min-w-0 space-y-3\">\n <div className=\"flex items-center justify-between gap-2 px-1\">\n <div>\n <h2 className=\"text-sm font-semibold\">\n {effectiveCategory === ALL_CATEGORY ? 'All templates' : `${titleCaseCategory(effectiveCategory)} templates`}\n </h2>\n <p className=\"text-xs text-muted-foreground\">{visibleTemplates.length} template{visibleTemplates.length === 1 ? '' : 's'} in this view</p>\n </div>\n </div>\n\n {visibleTemplates.map((template) => {\n const selected = template.slug === resolvedSelectedSlug\n const modified = template.template !== template.defaultTemplate\n return (\n <button\n key={template.slug}\n type=\"button\"\n className={cn(\n 'w-full rounded-xl border p-4 text-left transition-colors',\n selected ? 'border-primary/50 bg-primary/10 ring-1 ring-primary/20' : 'border-border bg-card hover:border-primary/30 hover:bg-accent',\n )}\n onClick={() => selectTemplate(template.slug)}\n >\n <div className=\"flex flex-wrap items-start gap-2\">\n <div className=\"min-w-0 flex-1\">\n <div className=\"flex flex-wrap items-center gap-2\">\n <span className=\"font-medium text-foreground\">{template.title}</span>\n {modified && (\n <Badge className=\"bg-amber-500/15 text-amber-300 hover:bg-amber-500/15\">Modified</Badge>\n )}\n <Badge variant=\"outline\" className=\"text-[10px]\">{titleCaseCategory(template.category)}</Badge>\n </div>\n <div className=\"mt-1 font-mono text-[11px] text-muted-foreground\">{template.slug}</div>\n {template.description && (\n <p className=\"mt-2 line-clamp-2 text-sm text-muted-foreground\">{template.description}</p>\n )}\n <div className=\"mt-3 flex flex-wrap items-center gap-3 text-[11px] text-muted-foreground\">\n <span>{template.variables.length} variable{template.variables.length === 1 ? '' : 's'}</span>\n <span>Updated {timeAgo(now, template.updatedAt)}</span>\n </div>\n </div>\n </div>\n </button>\n )\n })}\n </div>\n\n <div className=\"min-w-0\">\n {selectedTemplate ? (\n <Card>\n <CardHeader className=\"border-b border-border\">\n <CardTitle className=\"flex flex-wrap items-center gap-2\">\n <span>{selectedTemplate.title}</span>\n {selectedTemplate.template !== selectedTemplate.defaultTemplate && (\n <Badge className=\"bg-amber-500/15 text-amber-300 hover:bg-amber-500/15\">Customized</Badge>\n )}\n {hasUnsavedChanges && <Badge variant=\"outline\">Unsaved</Badge>}\n </CardTitle>\n <CardDescription className=\"space-y-1\">\n <div className=\"font-mono text-[11px]\">{selectedTemplate.slug}</div>\n {selectedTemplate.description && <div>{selectedTemplate.description}</div>}\n </CardDescription>\n </CardHeader>\n\n <CardContent className=\"space-y-4 pt-4\">\n {actionError && (\n <div className=\"flex items-start gap-2 rounded-md border border-destructive/40 bg-destructive/10 p-2 text-xs text-destructive\">\n <AlertCircle className=\"mt-0.5 size-3.5\" />\n <span>{actionError}</span>\n </div>\n )}\n\n {notice && (\n <div className=\"rounded-md border border-emerald-500/30 bg-emerald-500/10 px-3 py-2 text-xs text-emerald-300\">\n {notice}\n </div>\n )}\n\n <div className=\"space-y-2\">\n <div className=\"flex items-center gap-2 text-xs font-medium text-muted-foreground\">\n <Braces className=\"size-3.5\" />\n Available variables\n </div>\n {selectedTemplate.variables.length > 0 ? (\n <div className=\"flex flex-wrap gap-1.5\">\n {selectedTemplate.variables.map((variable) => (\n <Badge key={variable} variant=\"secondary\" className=\"font-mono text-[11px]\">\n {`{{${variable}}}`}\n </Badge>\n ))}\n </div>\n ) : (\n <div className=\"text-xs text-muted-foreground\">This template has no placeholder variables.</div>\n )}\n </div>\n\n {selectedTemplate.template !== selectedTemplate.defaultTemplate && (\n <div className=\"rounded-lg border border-amber-500/30 bg-amber-500/10 px-3 py-2 text-xs text-amber-200\">\n This template differs from the built-in default. Reset will restore the original text.\n </div>\n )}\n\n <div className=\"space-y-1.5\">\n <label htmlFor=\"prompt-template-editor\" className=\"text-xs font-medium text-muted-foreground\">\n Template text\n </label>\n <Textarea\n id=\"prompt-template-editor\"\n value={draft}\n onChange={(event) => {\n const next = event.target.value\n setDrafts((current) => ({ ...current, [selectedTemplate.slug]: next }))\n if (actionError) setActionError('')\n if (notice) setNotice('')\n }}\n rows={18}\n spellCheck={false}\n className=\"min-h-[360px] resize-y font-mono text-xs leading-5\"\n />\n </div>\n </CardContent>\n\n <CardFooter className=\"flex flex-wrap items-center justify-between gap-2\">\n <div className=\"text-xs text-muted-foreground\">\n {hasUnsavedChanges ? 'Editing local changes.' : `Updated ${timeAgo(now, selectedTemplate.updatedAt)}.`}\n </div>\n <div className=\"flex flex-wrap items-center gap-2\">\n {selectedTemplate.template !== selectedTemplate.defaultTemplate && (\n <Button variant=\"outline\" size=\"sm\" onClick={() => void resetTemplate()} disabled={saving}>\n <RotateCcw className=\"size-4\" />\n Reset to default\n </Button>\n )}\n <Button variant=\"outline\" size=\"sm\" onClick={cancelDraft} disabled={!hasUnsavedChanges || saving}>\n Cancel\n </Button>\n <Button size=\"sm\" onClick={() => void saveTemplate()} disabled={!hasUnsavedChanges || saving}>\n <Save className=\"size-4\" />\n Save\n </Button>\n </div>\n </CardFooter>\n </Card>\n ) : (\n <Card size=\"sm\">\n <CardContent className=\"text-sm text-muted-foreground\">\n Select a prompt template to edit it.\n </CardContent>\n </Card>\n )}\n </div>\n </div>\n )}\n </div>\n )\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"prompt-settings-Bn5mmi9w.js","names":[],"sources":["../../dashboard/src/components/views/prompt-settings.tsx"],"sourcesContent":["import { useEffect, useMemo, useState } from 'react'\nimport { api } from '@/lib/api'\nimport { cn } from '@/lib/utils'\nimport { timeAgo } from '@/lib/display'\nimport { Badge } from '@/components/ui/badge'\nimport { Button } from '@/components/ui/button'\nimport { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from '@/components/ui/card'\nimport { Textarea } from '@/components/ui/textarea'\nimport { AlertCircle, Braces, FileText, RefreshCw, RotateCcw, Save } from 'lucide-react'\nimport { errMessage } from 'agent-relay-sdk/types'\n\ninterface PromptTemplate {\n slug: string\n category: string\n title: string\n description?: string\n template: string\n defaultTemplate: string\n variables: string[]\n updatedAt: number\n createdAt: number\n}\n\nconst ALL_CATEGORY = 'all'\n\n\nfunction titleCaseCategory(category: string): string {\n return category\n .split(/[^a-zA-Z0-9]+/)\n .filter(Boolean)\n .map((part) => part.charAt(0).toUpperCase() + part.slice(1))\n .join(' ')\n}\n\nfunction sortTemplates(items: unknown): PromptTemplate[] {\n if (!Array.isArray(items)) return []\n return [...(items as PromptTemplate[])].sort((a, b) => {\n const category = a.category.localeCompare(b.category)\n if (category !== 0) return category\n const title = a.title.localeCompare(b.title)\n if (title !== 0) return title\n return a.slug.localeCompare(b.slug)\n })\n}\n\nexport function PromptSettingsView() {\n const [templates, setTemplates] = useState<PromptTemplate[]>([])\n const [loading, setLoading] = useState(true)\n const [loadError, setLoadError] = useState('')\n const [actionError, setActionError] = useState('')\n const [notice, setNotice] = useState('')\n const [activeCategory, setActiveCategory] = useState(ALL_CATEGORY)\n const [selectedSlug, setSelectedSlug] = useState('')\n const [drafts, setDrafts] = useState<Record<string, string>>({})\n const [savingSlug, setSavingSlug] = useState('')\n const [now, setNow] = useState(() => Date.now())\n\n async function reload() {\n setLoading(true)\n setLoadError('')\n try {\n const result = await api<{ templates: PromptTemplate[] }>('GET', '/settings/prompts')\n setTemplates(sortTemplates(result.templates))\n setNow(Date.now())\n } catch (error) {\n setLoadError(errMessage(error))\n } finally {\n setLoading(false)\n }\n }\n\n useEffect(() => {\n void reload()\n }, [])\n\n const categories = useMemo(() => {\n const counts = new Map<string, number>()\n for (const template of templates) counts.set(template.category, (counts.get(template.category) ?? 0) + 1)\n return [...counts.entries()]\n .sort(([a], [b]) => a.localeCompare(b))\n .map(([key, count]) => ({ key, count, label: titleCaseCategory(key) }))\n }, [templates])\n\n const effectiveCategory = activeCategory === ALL_CATEGORY || categories.some((item) => item.key === activeCategory)\n ? activeCategory\n : ALL_CATEGORY\n\n const visibleTemplates = useMemo(() => {\n if (effectiveCategory === ALL_CATEGORY) return templates\n return templates.filter((template) => template.category === effectiveCategory)\n }, [effectiveCategory, templates])\n\n const resolvedSelectedSlug = visibleTemplates.some((template) => template.slug === selectedSlug)\n ? selectedSlug\n : (visibleTemplates[0]?.slug ?? '')\n\n const selectedTemplate = visibleTemplates.find((template) => template.slug === resolvedSelectedSlug) ?? null\n const draft = selectedTemplate ? (drafts[selectedTemplate.slug] ?? selectedTemplate.template) : ''\n const hasUnsavedChanges = selectedTemplate ? draft !== selectedTemplate.template : false\n const modifiedCount = templates.filter((template) => template.template !== template.defaultTemplate).length\n const saving = selectedTemplate ? savingSlug === selectedTemplate.slug : false\n\n function selectTemplate(slug: string) {\n setSelectedSlug(slug)\n setActionError('')\n setNotice('')\n }\n\n function replaceTemplate(updated: PromptTemplate) {\n setTemplates((current) => sortTemplates(current.map((template) => template.slug === updated.slug ? updated : template)))\n setDrafts((current) => ({ ...current, [updated.slug]: updated.template }))\n setNow(Date.now())\n }\n\n async function saveTemplate() {\n if (!selectedTemplate || !hasUnsavedChanges) return\n setSavingSlug(selectedTemplate.slug)\n setActionError('')\n setNotice('')\n try {\n const updated = await api<PromptTemplate>('PUT', `/settings/prompts/${encodeURIComponent(selectedTemplate.slug)}`, {\n template: draft,\n })\n replaceTemplate(updated)\n setNotice(`Saved ${updated.title}.`)\n } catch (error) {\n setActionError(errMessage(error))\n } finally {\n setSavingSlug('')\n }\n }\n\n async function resetTemplate() {\n if (!selectedTemplate || selectedTemplate.template === selectedTemplate.defaultTemplate) return\n setSavingSlug(selectedTemplate.slug)\n setActionError('')\n setNotice('')\n try {\n const updated = await api<PromptTemplate>('POST', `/settings/prompts/${encodeURIComponent(selectedTemplate.slug)}/reset`)\n replaceTemplate(updated)\n setNotice(`Reset ${updated.title} to the built-in default.`)\n } catch (error) {\n setActionError(errMessage(error))\n } finally {\n setSavingSlug('')\n }\n }\n\n function cancelDraft() {\n if (!selectedTemplate) return\n setDrafts((current) => ({ ...current, [selectedTemplate.slug]: selectedTemplate.template }))\n setActionError('')\n setNotice('Unsaved edits discarded.')\n }\n\n return (\n <div className=\"space-y-4 p-4\">\n <div className=\"flex flex-wrap items-start justify-between gap-3\">\n <div>\n <h1 className=\"text-lg font-semibold\">Prompts</h1>\n <p className=\"text-sm text-muted-foreground\">View and edit the externalized prompt templates used across Relay lifecycle, routing, workspace, and automation flows.</p>\n </div>\n <div className=\"flex flex-wrap items-center gap-2\">\n <Badge variant=\"outline\" className=\"gap-1\">\n <FileText className=\"size-3\" />\n {templates.length} template{templates.length === 1 ? '' : 's'}\n </Badge>\n <Badge variant=\"outline\" className={cn('gap-1', modifiedCount > 0 && 'border-amber-500/40 bg-amber-500/10 text-amber-300')}>\n {modifiedCount} modified\n </Badge>\n <Button variant=\"outline\" size=\"sm\" onClick={() => void reload()} disabled={loading}>\n <RefreshCw className={cn('size-4', loading && 'animate-spin')} />\n Refresh\n </Button>\n </div>\n </div>\n\n {loadError && (\n <div className=\"flex items-start gap-2 rounded-lg border border-destructive/40 bg-destructive/10 p-3 text-sm text-destructive\">\n <AlertCircle className=\"mt-0.5 size-4\" />\n <span>{loadError}</span>\n </div>\n )}\n\n {loading && templates.length === 0 ? (\n <Card size=\"sm\">\n <CardContent className=\"text-sm text-muted-foreground\">Loading prompt templates…</CardContent>\n </Card>\n ) : templates.length === 0 ? (\n <Card>\n <CardContent className=\"py-10 text-center text-sm text-muted-foreground\">\n No prompt templates are available yet.\n </CardContent>\n </Card>\n ) : (\n <div className=\"grid gap-4 xl:grid-cols-[220px_minmax(0,0.9fr)_minmax(0,1.1fr)]\">\n <nav className=\"space-y-1 xl:sticky xl:top-4 xl:self-start\">\n <button\n type=\"button\"\n className={cn(\n 'w-full rounded-md border px-3 py-2 text-left text-sm transition-colors',\n effectiveCategory === ALL_CATEGORY ? 'border-primary/50 bg-primary/10 text-foreground' : 'border-transparent hover:border-border hover:bg-accent',\n )}\n onClick={() => setActiveCategory(ALL_CATEGORY)}\n >\n <span className=\"flex items-center gap-2\">\n <span className=\"font-medium\">All</span>\n <Badge variant=\"outline\" className=\"ml-auto h-4 px-1 text-[10px]\">{templates.length}</Badge>\n </span>\n <span className=\"block truncate text-xs text-muted-foreground\">Every externalized prompt template</span>\n </button>\n\n {categories.map((category) => (\n <button\n key={category.key}\n type=\"button\"\n className={cn(\n 'w-full rounded-md border px-3 py-2 text-left text-sm transition-colors',\n effectiveCategory === category.key ? 'border-primary/50 bg-primary/10 text-foreground' : 'border-transparent hover:border-border hover:bg-accent',\n )}\n onClick={() => setActiveCategory(category.key)}\n >\n <span className=\"flex items-center gap-2\">\n <span className=\"font-medium\">{category.label}</span>\n <Badge variant=\"outline\" className=\"ml-auto h-4 px-1 text-[10px]\">{category.count}</Badge>\n </span>\n <span className=\"block truncate text-xs font-mono text-muted-foreground\">{category.key}</span>\n </button>\n ))}\n </nav>\n\n <div className=\"min-w-0 space-y-3\">\n <div className=\"flex items-center justify-between gap-2 px-1\">\n <div>\n <h2 className=\"text-sm font-semibold\">\n {effectiveCategory === ALL_CATEGORY ? 'All templates' : `${titleCaseCategory(effectiveCategory)} templates`}\n </h2>\n <p className=\"text-xs text-muted-foreground\">{visibleTemplates.length} template{visibleTemplates.length === 1 ? '' : 's'} in this view</p>\n </div>\n </div>\n\n {visibleTemplates.map((template) => {\n const selected = template.slug === resolvedSelectedSlug\n const modified = template.template !== template.defaultTemplate\n return (\n <button\n key={template.slug}\n type=\"button\"\n className={cn(\n 'w-full rounded-xl border p-4 text-left transition-colors',\n selected ? 'border-primary/50 bg-primary/10 ring-1 ring-primary/20' : 'border-border bg-card hover:border-primary/30 hover:bg-accent',\n )}\n onClick={() => selectTemplate(template.slug)}\n >\n <div className=\"flex flex-wrap items-start gap-2\">\n <div className=\"min-w-0 flex-1\">\n <div className=\"flex flex-wrap items-center gap-2\">\n <span className=\"font-medium text-foreground\">{template.title}</span>\n {modified && (\n <Badge className=\"bg-amber-500/15 text-amber-300 hover:bg-amber-500/15\">Modified</Badge>\n )}\n <Badge variant=\"outline\" className=\"text-[10px]\">{titleCaseCategory(template.category)}</Badge>\n </div>\n <div className=\"mt-1 font-mono text-[11px] text-muted-foreground\">{template.slug}</div>\n {template.description && (\n <p className=\"mt-2 line-clamp-2 text-sm text-muted-foreground\">{template.description}</p>\n )}\n <div className=\"mt-3 flex flex-wrap items-center gap-3 text-[11px] text-muted-foreground\">\n <span>{template.variables.length} variable{template.variables.length === 1 ? '' : 's'}</span>\n <span>Updated {timeAgo(now, template.updatedAt)}</span>\n </div>\n </div>\n </div>\n </button>\n )\n })}\n </div>\n\n <div className=\"min-w-0\">\n {selectedTemplate ? (\n <Card>\n <CardHeader className=\"border-b border-border\">\n <CardTitle className=\"flex flex-wrap items-center gap-2\">\n <span>{selectedTemplate.title}</span>\n {selectedTemplate.template !== selectedTemplate.defaultTemplate && (\n <Badge className=\"bg-amber-500/15 text-amber-300 hover:bg-amber-500/15\">Customized</Badge>\n )}\n {hasUnsavedChanges && <Badge variant=\"outline\">Unsaved</Badge>}\n </CardTitle>\n <CardDescription className=\"space-y-1\">\n <div className=\"font-mono text-[11px]\">{selectedTemplate.slug}</div>\n {selectedTemplate.description && <div>{selectedTemplate.description}</div>}\n </CardDescription>\n </CardHeader>\n\n <CardContent className=\"space-y-4 pt-4\">\n {actionError && (\n <div className=\"flex items-start gap-2 rounded-md border border-destructive/40 bg-destructive/10 p-2 text-xs text-destructive\">\n <AlertCircle className=\"mt-0.5 size-3.5\" />\n <span>{actionError}</span>\n </div>\n )}\n\n {notice && (\n <div className=\"rounded-md border border-emerald-500/30 bg-emerald-500/10 px-3 py-2 text-xs text-emerald-300\">\n {notice}\n </div>\n )}\n\n <div className=\"space-y-2\">\n <div className=\"flex items-center gap-2 text-xs font-medium text-muted-foreground\">\n <Braces className=\"size-3.5\" />\n Available variables\n </div>\n {selectedTemplate.variables.length > 0 ? (\n <div className=\"flex flex-wrap gap-1.5\">\n {selectedTemplate.variables.map((variable) => (\n <Badge key={variable} variant=\"secondary\" className=\"font-mono text-[11px]\">\n {`{{${variable}}}`}\n </Badge>\n ))}\n </div>\n ) : (\n <div className=\"text-xs text-muted-foreground\">This template has no placeholder variables.</div>\n )}\n </div>\n\n {selectedTemplate.template !== selectedTemplate.defaultTemplate && (\n <div className=\"rounded-lg border border-amber-500/30 bg-amber-500/10 px-3 py-2 text-xs text-amber-200\">\n This template differs from the built-in default. Reset will restore the original text.\n </div>\n )}\n\n <div className=\"space-y-1.5\">\n <label htmlFor=\"prompt-template-editor\" className=\"text-xs font-medium text-muted-foreground\">\n Template text\n </label>\n <Textarea\n id=\"prompt-template-editor\"\n value={draft}\n onChange={(event) => {\n const next = event.target.value\n setDrafts((current) => ({ ...current, [selectedTemplate.slug]: next }))\n if (actionError) setActionError('')\n if (notice) setNotice('')\n }}\n rows={18}\n spellCheck={false}\n className=\"min-h-[360px] resize-y font-mono text-xs leading-5\"\n />\n </div>\n </CardContent>\n\n <CardFooter className=\"flex flex-wrap items-center justify-between gap-2\">\n <div className=\"text-xs text-muted-foreground\">\n {hasUnsavedChanges ? 'Editing local changes.' : `Updated ${timeAgo(now, selectedTemplate.updatedAt)}.`}\n </div>\n <div className=\"flex flex-wrap items-center gap-2\">\n {selectedTemplate.template !== selectedTemplate.defaultTemplate && (\n <Button variant=\"outline\" size=\"sm\" onClick={() => void resetTemplate()} disabled={saving}>\n <RotateCcw className=\"size-4\" />\n Reset to default\n </Button>\n )}\n <Button variant=\"outline\" size=\"sm\" onClick={cancelDraft} disabled={!hasUnsavedChanges || saving}>\n Cancel\n </Button>\n <Button size=\"sm\" onClick={() => void saveTemplate()} disabled={!hasUnsavedChanges || saving}>\n <Save className=\"size-4\" />\n Save\n </Button>\n </div>\n </CardFooter>\n </Card>\n ) : (\n <Card size=\"sm\">\n <CardContent className=\"text-sm text-muted-foreground\">\n Select a prompt template to edit it.\n </CardContent>\n </Card>\n )}\n </div>\n </div>\n )}\n </div>\n )\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import{r as e}from"./chunk-CilyBKbf.js";import{H as t,R as n,W as r,Z as i,gr as a,ir as o,ln as s,rr as c,tn as l,vn as u,xn as d}from"./lucide-react-CoU_Xts2.js";import{d as f,h as p,m}from"./types-CRptbSYh.js";import{t as h}from"./badge-XEru6wto.js";import{t as g}from"./button-C3CQSr4p.js";import{t as _}from"./input-CXMbJ848.js";import{U as v,W as y,yt as b}from"./index-0uIGXT14.js";import{o as x,r as S,s as C,t as w}from"./card-C5XTIPvq.js";var T=e(a(),1),E=c(),D=[{value:`none`,label:`None (host must already provide it)`},{value:`npm-global`,label:`npm install -g (pinned version)`},{value:`download`,label:`Download + checksum`},{value:`bundled`,label:`Bundled with relay`}],O=[`stdio`,`ws`,`http`],k=[`shared`,`per-agent`],A=[`none`,`tcp`,`http`];function j(e){return e.split(`,`).map(e=>e.trim()).filter(Boolean)}function M(e){let t={};for(let n of e.split(`
|
|
2
|
+
`)){let e=n.trim();if(!e)continue;let r=e.indexOf(`=`);r<=0||(t[e.slice(0,r).trim()]=e.slice(r+1).trim())}return t}var N=[{value:`all`,label:`All`},{value:`skill`,label:`Skills`},{value:`plugin`,label:`Plugins`},{value:`mcp`,label:`MCP`},{value:`hook`,label:`Hooks`}],P=[`any`,...m()];function F(e){return e===`skill`?`bg-blue-500/10 text-blue-400 border-blue-500/30`:e===`plugin`?`bg-violet-500/10 text-violet-400 border-violet-500/30`:e===`hook`?`bg-amber-500/10 text-amber-400 border-amber-500/30`:`bg-emerald-500/10 text-emerald-400 border-emerald-500/30`}function I(e){return e===`any`?`bg-zinc-500/10 text-zinc-400 border-zinc-500/30`:p(e)}function L(e){return e===`approved`?`bg-emerald-500/10 text-emerald-400 border-emerald-500/30`:e===`rejected`?`bg-red-500/10 text-red-400 border-red-500/30`:`bg-yellow-500/10 text-yellow-400 border-yellow-500/30`}function R({status:e}){return e===`valid`?(0,E.jsx)(u,{className:`h-3.5 w-3.5 text-emerald-400`}):e===`invalid`?(0,E.jsx)(d,{className:`h-3.5 w-3.5 text-red-400`}):(0,E.jsx)(s,{className:`h-3.5 w-3.5 text-zinc-400`})}var z={kind:`skill`,slug:``,title:``},B={githubUrl:``,ref:`main`,subpath:``,provider:`any`,versionConstraint:``},V={command:``,args:``,url:``,approvalStatus:`pending`,versionConstraint:``,setupKind:`none`,setupPkg:``,setupVersion:``,setupUrl:``,setupSha256:``,setupBin:``,runCommand:``,runArgs:``,runEnv:``,runTransport:`stdio`,healthProbeKind:`none`,healthProbePath:``,listenerMode:`shared`,applicabilityProviders:``,applicabilityProfiles:``};function H({variant:e,onToggle:t,onUpdate:n,onValidate:i,busy:a}){let o=a===e.id,s=e.kind===`mcp`?e.definition:void 0;return(0,E.jsxs)(`div`,{className:`rounded-md border border-border bg-card/60 p-3 space-y-2`,children:[(0,E.jsxs)(`div`,{className:`flex flex-wrap items-center gap-2`,children:[(0,E.jsx)(h,{variant:`outline`,className:`text-[10px] ${I(e.provider)}`,children:e.provider}),(0,E.jsx)(`span`,{className:`text-xs font-medium font-mono`,children:e.name}),e.approvalStatus&&(0,E.jsx)(h,{variant:`outline`,className:`text-[10px] ${L(e.approvalStatus)}`,children:e.approvalStatus}),(0,E.jsxs)(`span`,{className:`text-[10px] text-muted-foreground flex items-center gap-1 ml-auto`,children:[(0,E.jsx)(R,{status:e.validationStatus}),e.validationStatus??`unvalidated`]}),(0,E.jsx)(b,{size:`sm`,checked:e.enabled,disabled:o,onCheckedChange:n=>t(e.id,n)})]}),(e.sourceUrl||e.sourceRef)&&(0,E.jsxs)(`div`,{className:`text-[10px] text-muted-foreground font-mono truncate`,title:e.sourceUrl,children:[e.sourceUrl,e.sourceRef?`@${e.resolvedRef??e.sourceRef}`:``,e.sourceSubpath?` · ${e.sourceSubpath}`:``]}),s&&(s.setup||s.runConfig||s.applicability)&&(0,E.jsxs)(`div`,{className:`flex flex-wrap items-center gap-1.5`,children:[s.setup&&(0,E.jsxs)(h,{variant:`outline`,className:`text-[10px] bg-sky-500/10 text-sky-400 border-sky-500/30`,children:[`setup: `,s.setup.kind]}),s.runConfig&&(0,E.jsxs)(E.Fragment,{children:[(0,E.jsxs)(h,{variant:`outline`,className:`text-[10px] bg-teal-500/10 text-teal-400 border-teal-500/30`,children:[`transport: `,s.runConfig.transport]}),(0,E.jsxs)(h,{variant:`outline`,className:`text-[10px] bg-teal-500/10 text-teal-400 border-teal-500/30`,children:[`listener: `,s.runConfig.listenerMode]})]}),s.applicability?.providers?.length?(0,E.jsxs)(h,{variant:`outline`,className:`text-[10px] bg-fuchsia-500/10 text-fuchsia-400 border-fuchsia-500/30`,children:[`providers: `,s.applicability.providers.join(`, `)]}):null,s.applicability?.profiles?.length?(0,E.jsxs)(h,{variant:`outline`,className:`text-[10px] bg-fuchsia-500/10 text-fuchsia-400 border-fuchsia-500/30`,children:[`profiles: `,s.applicability.profiles.join(`, `)]}):null]}),(0,E.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,E.jsxs)(g,{variant:`outline`,size:`sm`,className:`h-6 text-xs`,disabled:o||!e.sourceRef,onClick:()=>n(e.id),title:`Pull latest from source ref`,children:[(0,E.jsx)(l,{className:`h-3 w-3 mr-1`}),`Update ref`]}),(0,E.jsxs)(g,{variant:`outline`,size:`sm`,className:`h-6 text-xs`,disabled:o,onClick:()=>i(e.id),children:[(0,E.jsx)(r,{className:`h-3 w-3 mr-1`}),`Validate`]})]})]})}function U({form:e,onChange:t,onSubmit:n,onCancel:r,busy:i,error:a}){return(0,E.jsxs)(`div`,{className:`rounded-md border border-border bg-card/60 p-3 space-y-3`,children:[(0,E.jsx)(`div`,{className:`text-sm font-medium`,children:`New Capability`}),a&&(0,E.jsx)(`div`,{className:`text-xs text-destructive`,children:a}),(0,E.jsxs)(`div`,{children:[(0,E.jsx)(v,{className:`text-xs`,children:`Kind`}),(0,E.jsxs)(`select`,{className:`mt-1 w-full rounded-md border border-input bg-background px-2 py-1.5 text-sm`,value:e.kind,onChange:e=>t({kind:e.target.value}),children:[(0,E.jsx)(`option`,{value:`skill`,children:`Skill`}),(0,E.jsx)(`option`,{value:`plugin`,children:`Plugin`}),(0,E.jsx)(`option`,{value:`mcp`,children:`MCP Server`}),(0,E.jsx)(`option`,{value:`hook`,children:`Hook`})]})]}),(0,E.jsxs)(`div`,{children:[(0,E.jsx)(v,{className:`text-xs`,children:`Slug`}),(0,E.jsx)(_,{value:e.slug,onChange:e=>t({slug:e.target.value}),placeholder:`my-capability`,className:`mt-1 text-sm font-mono`})]}),(0,E.jsxs)(`div`,{children:[(0,E.jsx)(v,{className:`text-xs`,children:`Title (optional)`}),(0,E.jsx)(_,{value:e.title,onChange:e=>t({title:e.target.value}),placeholder:`My Capability`,className:`mt-1 text-sm`})]}),(0,E.jsxs)(`div`,{className:`flex gap-2`,children:[(0,E.jsx)(g,{size:`sm`,onClick:n,disabled:i||!e.slug.trim(),children:i?`Creating…`:`Create`}),(0,E.jsx)(g,{size:`sm`,variant:`outline`,onClick:r,children:`Cancel`})]})]})}function W({form:e,onChange:t,onSubmit:n,onCancel:r,busy:i,error:a}){return(0,E.jsxs)(`div`,{className:`rounded-md border border-border bg-card/60 p-3 space-y-3`,children:[(0,E.jsx)(`div`,{className:`text-sm font-medium`,children:`Import from GitHub`}),a&&(0,E.jsx)(`div`,{className:`text-xs text-destructive`,children:a}),(0,E.jsxs)(`div`,{children:[(0,E.jsx)(v,{className:`text-xs`,children:`GitHub URL`}),(0,E.jsx)(_,{value:e.githubUrl,onChange:e=>t({githubUrl:e.target.value}),placeholder:`https://github.com/owner/repo`,className:`mt-1 text-sm font-mono`})]}),(0,E.jsxs)(`div`,{className:`grid grid-cols-2 gap-2`,children:[(0,E.jsxs)(`div`,{children:[(0,E.jsx)(v,{className:`text-xs`,children:`Ref`}),(0,E.jsx)(_,{value:e.ref,onChange:e=>t({ref:e.target.value}),placeholder:`main`,className:`mt-1 text-sm font-mono`})]}),(0,E.jsxs)(`div`,{children:[(0,E.jsx)(v,{className:`text-xs`,children:`Subpath (optional)`}),(0,E.jsx)(_,{value:e.subpath,onChange:e=>t({subpath:e.target.value}),placeholder:`skills/my-skill`,className:`mt-1 text-sm font-mono`})]})]}),(0,E.jsxs)(`div`,{className:`grid grid-cols-2 gap-2`,children:[(0,E.jsxs)(`div`,{children:[(0,E.jsx)(v,{className:`text-xs`,children:`Provider`}),(0,E.jsx)(`select`,{className:`mt-1 w-full rounded-md border border-input bg-background px-2 py-1.5 text-sm`,value:e.provider,onChange:e=>t({provider:e.target.value}),children:P.map(e=>(0,E.jsx)(`option`,{value:e,children:e},e))})]}),(0,E.jsxs)(`div`,{children:[(0,E.jsx)(v,{className:`text-xs`,children:`Version constraint (optional)`}),(0,E.jsx)(_,{value:e.versionConstraint,onChange:e=>t({versionConstraint:e.target.value}),placeholder:`>=1.0.0`,className:`mt-1 text-sm font-mono`})]})]}),(0,E.jsxs)(`div`,{className:`flex gap-2`,children:[(0,E.jsx)(g,{size:`sm`,onClick:n,disabled:i||!e.githubUrl.trim()||!e.ref.trim(),children:i?`Importing…`:`Import`}),(0,E.jsx)(g,{size:`sm`,variant:`outline`,onClick:r,children:`Cancel`})]})]})}function G({form:e,onChange:t,onSubmit:n,onCancel:r,busy:i,error:a}){return(0,E.jsxs)(`div`,{className:`rounded-md border border-border bg-card/60 p-3 space-y-3`,children:[(0,E.jsx)(`div`,{className:`text-sm font-medium`,children:`Add MCP Server Variant`}),a&&(0,E.jsx)(`div`,{className:`text-xs text-destructive`,children:a}),(0,E.jsxs)(`div`,{children:[(0,E.jsx)(v,{className:`text-xs`,children:`Command (for stdio type)`}),(0,E.jsx)(_,{value:e.command,onChange:e=>t({command:e.target.value}),placeholder:`npx -y @modelcontextprotocol/server-foo`,className:`mt-1 text-sm font-mono`})]}),(0,E.jsxs)(`div`,{children:[(0,E.jsx)(v,{className:`text-xs`,children:`Args (space-separated, overrides command split)`}),(0,E.jsx)(_,{value:e.args,onChange:e=>t({args:e.target.value}),placeholder:`--port 3000`,className:`mt-1 text-sm font-mono`})]}),(0,E.jsxs)(`div`,{children:[(0,E.jsx)(v,{className:`text-xs`,children:`URL (for http/sse type)`}),(0,E.jsx)(_,{value:e.url,onChange:e=>t({url:e.target.value}),placeholder:`http://localhost:3000/mcp`,className:`mt-1 text-sm font-mono`})]}),(0,E.jsxs)(`div`,{className:`grid grid-cols-2 gap-2`,children:[(0,E.jsxs)(`div`,{children:[(0,E.jsx)(v,{className:`text-xs`,children:`Approval status`}),(0,E.jsxs)(`select`,{className:`mt-1 w-full rounded-md border border-input bg-background px-2 py-1.5 text-sm`,value:e.approvalStatus,onChange:e=>t({approvalStatus:e.target.value}),children:[(0,E.jsx)(`option`,{value:`pending`,children:`Pending`}),(0,E.jsx)(`option`,{value:`approved`,children:`Approved`})]})]}),(0,E.jsxs)(`div`,{children:[(0,E.jsx)(v,{className:`text-xs`,children:`Version constraint (optional)`}),(0,E.jsx)(_,{value:e.versionConstraint,onChange:e=>t({versionConstraint:e.target.value}),placeholder:`>=1.0.0`,className:`mt-1 text-sm font-mono`})]})]}),(0,E.jsxs)(`div`,{className:`border-t border-border pt-3 space-y-3`,children:[(0,E.jsx)(`div`,{className:`text-xs font-medium text-muted-foreground`,children:`Setup recipe (#1030) — how a host without this server obtains it`}),(0,E.jsxs)(`div`,{children:[(0,E.jsx)(v,{className:`text-xs`,children:`Recipe kind`}),(0,E.jsx)(`select`,{className:`mt-1 w-full rounded-md border border-input bg-background px-2 py-1.5 text-sm`,value:e.setupKind,onChange:e=>t({setupKind:e.target.value}),children:D.map(e=>(0,E.jsx)(`option`,{value:e.value,children:e.label},e.value))})]}),e.setupKind===`npm-global`&&(0,E.jsxs)(`div`,{className:`grid grid-cols-2 gap-2`,children:[(0,E.jsxs)(`div`,{children:[(0,E.jsx)(v,{className:`text-xs`,children:`Package`}),(0,E.jsx)(_,{value:e.setupPkg,onChange:e=>t({setupPkg:e.target.value}),placeholder:`@scope/mcp-server`,className:`mt-1 text-sm font-mono`})]}),(0,E.jsxs)(`div`,{children:[(0,E.jsx)(v,{className:`text-xs`,children:`Version (exact, pinned)`}),(0,E.jsx)(_,{value:e.setupVersion,onChange:e=>t({setupVersion:e.target.value}),placeholder:`1.2.3`,className:`mt-1 text-sm font-mono`})]})]}),e.setupKind===`download`&&(0,E.jsxs)(`div`,{className:`space-y-2`,children:[(0,E.jsxs)(`div`,{children:[(0,E.jsx)(v,{className:`text-xs`,children:`Download URL (https)`}),(0,E.jsx)(_,{value:e.setupUrl,onChange:e=>t({setupUrl:e.target.value}),placeholder:`https://example.com/server.tar.gz`,className:`mt-1 text-sm font-mono`})]}),(0,E.jsxs)(`div`,{className:`grid grid-cols-2 gap-2`,children:[(0,E.jsxs)(`div`,{children:[(0,E.jsx)(v,{className:`text-xs`,children:`sha256 checksum`}),(0,E.jsx)(_,{value:e.setupSha256,onChange:e=>t({setupSha256:e.target.value}),placeholder:`64 hex chars`,className:`mt-1 text-sm font-mono`})]}),(0,E.jsxs)(`div`,{children:[(0,E.jsx)(v,{className:`text-xs`,children:`Binary name`}),(0,E.jsx)(_,{value:e.setupBin,onChange:e=>t({setupBin:e.target.value}),placeholder:`server-bin`,className:`mt-1 text-sm font-mono`})]})]})]}),(0,E.jsx)(`div`,{className:`text-xs font-medium text-muted-foreground pt-1`,children:`Run config (#1030) — how the orchestrator launches + supervises it`}),(0,E.jsxs)(`div`,{className:`grid grid-cols-2 gap-2`,children:[(0,E.jsxs)(`div`,{children:[(0,E.jsx)(v,{className:`text-xs`,children:`Launch command`}),(0,E.jsx)(_,{value:e.runCommand,onChange:e=>t({runCommand:e.target.value}),placeholder:`server-bin`,className:`mt-1 text-sm font-mono`})]}),(0,E.jsxs)(`div`,{children:[(0,E.jsx)(v,{className:`text-xs`,children:`Launch args (space-separated)`}),(0,E.jsx)(_,{value:e.runArgs,onChange:e=>t({runArgs:e.target.value}),placeholder:`--stdio`,className:`mt-1 text-sm font-mono`})]})]}),(0,E.jsxs)(`div`,{children:[(0,E.jsx)(v,{className:`text-xs`,children:`Env (one KEY=VALUE per line; use secret:/env:/file: refs for secrets, never literal values)`}),(0,E.jsx)(y,{value:e.runEnv,onChange:e=>t({runEnv:e.target.value}),placeholder:`API_TOKEN=secret:my-server-token
|
|
3
|
+
MODE=server`,className:`mt-1 text-sm font-mono`,rows:2})]}),(0,E.jsxs)(`div`,{className:`grid grid-cols-3 gap-2`,children:[(0,E.jsxs)(`div`,{children:[(0,E.jsx)(v,{className:`text-xs`,children:`Transport`}),(0,E.jsx)(`select`,{className:`mt-1 w-full rounded-md border border-input bg-background px-2 py-1.5 text-sm`,value:e.runTransport,onChange:e=>t({runTransport:e.target.value}),children:O.map(e=>(0,E.jsx)(`option`,{value:e,children:e},e))})]}),(0,E.jsxs)(`div`,{children:[(0,E.jsx)(v,{className:`text-xs`,children:`Listener mode`}),(0,E.jsx)(`select`,{className:`mt-1 w-full rounded-md border border-input bg-background px-2 py-1.5 text-sm`,value:e.listenerMode,onChange:e=>t({listenerMode:e.target.value}),children:k.map(e=>(0,E.jsx)(`option`,{value:e,children:e},e))})]}),(0,E.jsxs)(`div`,{children:[(0,E.jsx)(v,{className:`text-xs`,children:`Health probe`}),(0,E.jsx)(`select`,{className:`mt-1 w-full rounded-md border border-input bg-background px-2 py-1.5 text-sm`,value:e.healthProbeKind,onChange:e=>t({healthProbeKind:e.target.value}),children:A.map(e=>(0,E.jsx)(`option`,{value:e,children:e},e))})]})]}),e.healthProbeKind===`http`&&(0,E.jsxs)(`div`,{children:[(0,E.jsx)(v,{className:`text-xs`,children:`Health probe path`}),(0,E.jsx)(_,{value:e.healthProbePath,onChange:e=>t({healthProbePath:e.target.value}),placeholder:`/health`,className:`mt-1 text-sm font-mono`})]}),(0,E.jsx)(`div`,{className:`text-xs font-medium text-muted-foreground pt-1`,children:`Applicability (#1030) — which profiles/providers may use this server (empty = unrestricted)`}),(0,E.jsxs)(`div`,{className:`grid grid-cols-2 gap-2`,children:[(0,E.jsxs)(`div`,{children:[(0,E.jsx)(v,{className:`text-xs`,children:`Providers (comma-separated)`}),(0,E.jsx)(_,{value:e.applicabilityProviders,onChange:e=>t({applicabilityProviders:e.target.value}),placeholder:`claude, codex`,className:`mt-1 text-sm font-mono`})]}),(0,E.jsxs)(`div`,{children:[(0,E.jsx)(v,{className:`text-xs`,children:`Profiles (comma-separated)`}),(0,E.jsx)(_,{value:e.applicabilityProfiles,onChange:e=>t({applicabilityProfiles:e.target.value}),placeholder:`worker, coordinator`,className:`mt-1 text-sm font-mono`})]})]})]}),(0,E.jsxs)(`div`,{className:`flex gap-2`,children:[(0,E.jsx)(g,{size:`sm`,onClick:n,disabled:i||!e.command.trim()&&!e.url.trim(),children:i?`Adding…`:`Add MCP Variant`}),(0,E.jsx)(g,{size:`sm`,variant:`outline`,onClick:r,children:`Cancel`})]})]})}function K(){let[e,r]=(0,T.useState)([]),[a,s]=(0,T.useState)(`all`),[c,l]=(0,T.useState)(``),[u,d]=(0,T.useState)(!0),[p,m]=(0,T.useState)(null),[_,v]=(0,T.useState)(`none`),[y,b]=(0,T.useState)(!1),[D,O]=(0,T.useState)(null),[k,A]=(0,T.useState)(null),[P,I]=(0,T.useState)(z),[L,R]=(0,T.useState)(B),[K,q]=(0,T.useState)(V);async function J(){m(null);try{let e=await o(`GET`,`/provisioning/capabilities${a===`all`?``:`?kind=${a}`}`);r(e.capabilities),!c&&e.capabilities.length>0&&l(e.capabilities[0].capability.id)}catch(e){m(f(e))}finally{d(!1)}}(0,T.useEffect)(()=>{d(!0),J()},[a]);let Y=e.find(e=>e.capability.id===c)??null;function X(e){v(e),O(null),b(!1),I(z),R(B),q(V)}async function Z(){b(!0),O(null);try{await o(`POST`,`/provisioning/capabilities`,{kind:P.kind,slug:P.slug.trim(),title:P.title.trim()||void 0}),v(`none`),await J()}catch(e){O(f(e))}finally{b(!1)}}async function Q(){if(Y){b(!0),O(null);try{await o(`POST`,`/provisioning/capabilities/${encodeURIComponent(Y.capability.id)}/variants/import`,{githubUrl:L.githubUrl.trim(),ref:L.ref.trim(),subpath:L.subpath.trim()||void 0,provider:L.provider,versionConstraint:L.versionConstraint.trim()||void 0}),v(`none`),await J()}catch(e){O(f(e))}finally{b(!1)}}}async function ee(){if(Y){b(!0),O(null);try{let e={};if(K.url.trim())e.type=`http`,e.url=K.url.trim();else{e.type=`stdio`;let t=K.command.trim().split(/\s+/);e.command=t[0];let n=K.args.trim()?K.args.trim().split(/\s+/):t.slice(1);n.length>0&&(e.args=n)}let t;K.setupKind===`npm-global`?t={kind:`npm-global`,pkg:K.setupPkg.trim(),version:K.setupVersion.trim()}:K.setupKind===`download`?t={kind:`download`,url:K.setupUrl.trim(),sha256:K.setupSha256.trim(),bin:K.setupBin.trim()}:K.setupKind===`bundled`&&(t={kind:`bundled`});let n;if(K.runCommand.trim()){let e=M(K.runEnv);n={command:K.runCommand.trim(),...K.runArgs.trim()?{args:K.runArgs.trim().split(/\s+/)}:{},...Object.keys(e).length?{env:e}:{},transport:K.runTransport,...K.healthProbeKind===`none`?{}:{healthProbe:{kind:K.healthProbeKind,...K.healthProbePath.trim()?{path:K.healthProbePath.trim()}:{}}},listenerMode:K.listenerMode}}let r=j(K.applicabilityProviders),i=j(K.applicabilityProfiles),a=r.length||i.length?{...r.length?{providers:r}:{},...i.length?{profiles:i}:{}}:void 0;await o(`POST`,`/provisioning/capabilities/${encodeURIComponent(Y.capability.id)}/variants/mcp`,{server:e,...t?{setup:t}:{},...n?{runConfig:n}:{},...a?{applicability:a}:{},approvalStatus:K.approvalStatus,versionConstraint:K.versionConstraint.trim()||void 0}),v(`none`),await J()}catch(e){O(f(e))}finally{b(!1)}}}async function te(e,t){A(e);try{await o(`PATCH`,`/provisioning/variants/${encodeURIComponent(e)}`,{enabled:t}),r(n=>n.map(n=>({...n,variants:n.variants.map(n=>n.id===e?{...n,enabled:t}:n)})))}catch(e){m(f(e))}finally{A(null)}}async function ne(e){let t=Y?.variants.find(t=>t.id===e);if(t?.sourceRef){A(e);try{await o(`POST`,`/provisioning/variants/${encodeURIComponent(e)}/update`,{ref:t.sourceRef,subpath:t.sourceSubpath}),await J()}catch(e){m(f(e))}finally{A(null)}}}async function re(e){A(e);try{await o(`POST`,`/provisioning/variants/${encodeURIComponent(e)}/validate`,{}),await J()}catch(e){m(f(e))}finally{A(null)}}let $=Y?.capability;return(0,E.jsxs)(`div`,{className:`space-y-4 p-4`,children:[(0,E.jsxs)(`div`,{className:`flex flex-wrap items-center gap-2`,children:[(0,E.jsx)(i,{className:`size-5 text-primary`}),(0,E.jsx)(`h1`,{className:`text-lg font-semibold`,children:`Registry`}),(0,E.jsx)(`span`,{className:`text-xs text-muted-foreground`,children:`provisioning capability registry · #561`}),(0,E.jsxs)(`div`,{className:`ml-auto flex items-center gap-2`,children:[N.map(e=>(0,E.jsx)(`button`,{type:`button`,onClick:()=>s(e.value),className:`rounded-md border px-2.5 py-1 text-xs transition-colors ${a===e.value?`border-primary/40 bg-primary/10 text-primary`:`border-border text-muted-foreground hover:bg-accent`}`,children:e.label},e.value)),(0,E.jsx)(g,{variant:`outline`,size:`sm`,onClick:()=>void J(),children:(0,E.jsx)(n,{className:`size-4`})})]})]}),p&&(0,E.jsx)(`div`,{className:`rounded-md border border-destructive/40 bg-destructive/10 px-3 py-2 text-sm text-destructive`,children:p}),(0,E.jsxs)(`div`,{className:`grid grid-cols-1 gap-4 xl:grid-cols-[300px_1fr]`,children:[(0,E.jsxs)(`div`,{className:`space-y-2`,children:[(0,E.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,E.jsxs)(`span`,{className:`text-xs text-muted-foreground font-medium`,children:[e.length,` capabilities`]}),(0,E.jsxs)(g,{size:`sm`,variant:`outline`,className:`h-7 text-xs gap-1`,onClick:()=>X(`new-capability`),children:[(0,E.jsx)(t,{className:`h-3 w-3`}),`New`]})]}),_===`new-capability`&&(0,E.jsx)(U,{form:P,onChange:e=>I(t=>({...t,...e})),onSubmit:()=>void Z(),onCancel:()=>v(`none`),busy:y,error:D}),u&&e.length===0&&(0,E.jsx)(`div`,{className:`py-8 text-center text-sm text-muted-foreground`,children:`Loading…`}),!u&&e.length===0&&(0,E.jsx)(w,{children:(0,E.jsx)(S,{className:`py-10 text-center text-sm text-muted-foreground`,children:`No capabilities yet. Click New to create one.`})}),e.map(({capability:e,variants:t})=>(0,E.jsxs)(`button`,{type:`button`,onClick:()=>{l(e.id),v(`none`)},className:`w-full rounded-md border p-3 text-left transition-colors ${c===e.id?`border-primary/50 bg-primary/5`:`border-border bg-card/60 hover:bg-accent`}`,children:[(0,E.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,E.jsx)(h,{variant:`outline`,className:`text-[10px] ${F(e.kind)}`,children:e.kind}),(0,E.jsx)(`span`,{className:`text-xs font-medium font-mono truncate flex-1`,children:e.slug}),(0,E.jsxs)(`span`,{className:`text-[10px] text-muted-foreground shrink-0`,children:[t.length,`v`]})]}),e.title&&(0,E.jsx)(`div`,{className:`mt-1 text-xs text-muted-foreground truncate`,children:e.title}),(0,E.jsxs)(`div`,{className:`mt-1 flex items-center gap-1.5`,children:[(0,E.jsx)(`span`,{className:`inline-block h-1.5 w-1.5 rounded-full ${e.status===`active`?`bg-emerald-500`:`bg-zinc-500`}`}),(0,E.jsx)(`span`,{className:`text-[10px] text-muted-foreground`,children:e.status})]})]},e.id))]}),$?(0,E.jsxs)(`div`,{className:`space-y-3`,children:[(0,E.jsxs)(w,{children:[(0,E.jsx)(x,{children:(0,E.jsxs)(C,{className:`flex flex-wrap items-center gap-2`,children:[(0,E.jsx)(h,{variant:`outline`,className:F($.kind),children:$.kind}),(0,E.jsx)(`span`,{className:`font-mono text-base`,children:$.slug}),$.title&&(0,E.jsxs)(`span`,{className:`text-sm font-normal text-muted-foreground`,children:[`· `,$.title]}),(0,E.jsx)(h,{variant:$.status===`active`?`secondary`:`outline`,className:`ml-auto text-[10px]`,children:$.status})]})}),$.description&&(0,E.jsx)(S,{className:`pt-0 text-sm text-muted-foreground`,children:$.description})]}),(0,E.jsxs)(w,{children:[(0,E.jsx)(x,{children:(0,E.jsxs)(C,{className:`flex items-center gap-2 text-base`,children:[`Variants`,(0,E.jsxs)(`span`,{className:`text-xs font-normal text-muted-foreground`,children:[`(`,Y?.variants.length??0,`)`]}),(0,E.jsxs)(`div`,{className:`ml-auto flex items-center gap-2`,children:[(0,E.jsxs)(g,{size:`sm`,variant:`outline`,className:`h-7 text-xs gap-1`,onClick:()=>X(_===`import-github`?`none`:`import-github`),children:[(0,E.jsx)(t,{className:`h-3 w-3`}),`GitHub`]}),$.kind===`mcp`&&(0,E.jsxs)(g,{size:`sm`,variant:`outline`,className:`h-7 text-xs gap-1`,onClick:()=>X(_===`import-mcp`?`none`:`import-mcp`),children:[(0,E.jsx)(t,{className:`h-3 w-3`}),`MCP Server`]})]})]})}),(0,E.jsxs)(S,{className:`space-y-3`,children:[_===`import-github`&&(0,E.jsx)(W,{form:L,onChange:e=>R(t=>({...t,...e})),onSubmit:()=>void Q(),onCancel:()=>v(`none`),busy:y,error:D}),_===`import-mcp`&&(0,E.jsx)(G,{form:K,onChange:e=>q(t=>({...t,...e})),onSubmit:()=>void ee(),onCancel:()=>v(`none`),busy:y,error:D}),Y&&Y.variants.length===0&&_===`none`&&(0,E.jsxs)(`div`,{className:`py-6 text-center text-sm text-muted-foreground`,children:[`No variants yet. Add one via GitHub import`,$.kind===`mcp`?` or MCP Server`:``,`.`]}),Y?.variants.map(e=>(0,E.jsx)(H,{variant:e,onToggle:(e,t)=>void te(e,t),onUpdate:e=>void ne(e),onValidate:e=>void re(e),busy:k},e.id))]})]})]}):!u&&(0,E.jsx)(w,{children:(0,E.jsx)(S,{className:`py-16 text-center text-sm text-muted-foreground`,children:`Select a capability to view details and variants.`})})]})]})}export{K as RegistryView};
|
|
4
|
+
//# sourceMappingURL=registry-C3sB7qv5.js.map
|