@agent-relay/dashboard 2.0.80 → 2.0.82
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/out/404.html +1 -1
- package/out/_next/static/chunks/{118-4c8241b0218335de.js → 118-ae2b650136a5a5fc.js} +1 -1
- package/out/_next/static/chunks/407-0c82986cf79c8ecb.js +1 -0
- package/out/_next/static/chunks/app/app/[[...slug]]/{page-1e81c047cff17212.js → page-f7eca1b66fb4249b.js} +1 -1
- package/out/_next/static/chunks/app/{page-6892fe2dd07fb48b.js → page-0ee604f7070d14c0.js} +1 -1
- package/out/_next/static/css/8968d98ed4c4d33f.css +1 -0
- package/out/about.html +2 -2
- package/out/about.txt +1 -1
- package/out/app/onboarding.html +1 -1
- package/out/app/onboarding.txt +1 -1
- package/out/app.html +1 -1
- package/out/app.txt +2 -2
- package/out/blog/go-to-bed-wake-up-to-a-finished-product.html +2 -2
- package/out/blog/go-to-bed-wake-up-to-a-finished-product.txt +1 -1
- package/out/blog/let-them-cook-multi-agent-orchestration.html +2 -2
- package/out/blog/let-them-cook-multi-agent-orchestration.txt +2 -2
- package/out/blog.html +2 -2
- package/out/blog.txt +1 -1
- package/out/careers.html +2 -2
- package/out/careers.txt +1 -1
- package/out/changelog.html +2 -2
- package/out/changelog.txt +1 -1
- package/out/cloud/link.html +1 -1
- package/out/cloud/link.txt +2 -2
- package/out/complete-profile.html +2 -2
- package/out/complete-profile.txt +1 -1
- package/out/connect-repos.html +1 -1
- package/out/connect-repos.txt +1 -1
- package/out/contact.html +2 -2
- package/out/contact.txt +1 -1
- package/out/docs.html +2 -2
- package/out/docs.txt +1 -1
- package/out/history.html +1 -1
- package/out/history.txt +2 -2
- package/out/index.html +1 -1
- package/out/index.txt +2 -2
- package/out/login.html +2 -2
- package/out/login.txt +1 -1
- package/out/metrics.html +1 -1
- package/out/metrics.txt +2 -2
- package/out/pricing.html +2 -2
- package/out/pricing.txt +1 -1
- package/out/privacy.html +2 -2
- package/out/privacy.txt +1 -1
- package/out/providers/setup/claude.html +1 -1
- package/out/providers/setup/claude.txt +1 -1
- package/out/providers/setup/codex.html +1 -1
- package/out/providers/setup/codex.txt +1 -1
- package/out/providers/setup/cursor.html +1 -1
- package/out/providers/setup/cursor.txt +1 -1
- package/out/providers.html +1 -1
- package/out/providers.txt +1 -1
- package/out/security.html +2 -2
- package/out/security.txt +1 -1
- package/out/signup.html +2 -2
- package/out/signup.txt +1 -1
- package/out/terms.html +2 -2
- package/out/terms.txt +1 -1
- package/package.json +7 -1
- package/src/app/about/page.tsx +7 -0
- package/src/app/app/[[...slug]]/DashboardPageClient.tsx +853 -0
- package/src/app/app/[[...slug]]/page.tsx +23 -0
- package/src/app/app/onboarding/page.tsx +394 -0
- package/src/app/apple-icon.png +0 -0
- package/src/app/blog/go-to-bed-wake-up-to-a-finished-product/page.tsx +88 -0
- package/src/app/blog/let-them-cook-multi-agent-orchestration/page.tsx +93 -0
- package/src/app/blog/page.tsx +15 -0
- package/src/app/careers/page.tsx +7 -0
- package/src/app/changelog/page.tsx +7 -0
- package/src/app/cloud/link/page.tsx +464 -0
- package/src/app/complete-profile/page.tsx +204 -0
- package/src/app/connect-repos/page.tsx +410 -0
- package/src/app/contact/page.tsx +7 -0
- package/src/app/docs/page.tsx +7 -0
- package/src/app/favicon.png +0 -0
- package/src/app/globals.css +200 -0
- package/src/app/history/page.tsx +658 -0
- package/src/app/layout.tsx +25 -0
- package/src/app/login/page.tsx +424 -0
- package/src/app/metrics/page.tsx +781 -0
- package/src/app/page.tsx +59 -0
- package/src/app/pricing/page.tsx +7 -0
- package/src/app/privacy/page.tsx +7 -0
- package/src/app/providers/page.tsx +193 -0
- package/src/app/providers/setup/[provider]/ProviderSetupClient.tsx +197 -0
- package/src/app/providers/setup/[provider]/constants.ts +35 -0
- package/src/app/providers/setup/[provider]/page.tsx +42 -0
- package/src/app/security/page.tsx +7 -0
- package/src/app/signup/page.tsx +533 -0
- package/src/app/terms/page.tsx +7 -0
- package/src/components/ActivityFeed.tsx +216 -0
- package/src/components/AddWorkspaceModal.tsx +170 -0
- package/src/components/AgentCard.test.tsx +134 -0
- package/src/components/AgentCard.tsx +585 -0
- package/src/components/AgentList.test.tsx +147 -0
- package/src/components/AgentList.tsx +419 -0
- package/src/components/AgentLogPreview.tsx +173 -0
- package/src/components/AgentProfilePanel.tsx +569 -0
- package/src/components/App.tsx +3424 -0
- package/src/components/BillingPanel.tsx +922 -0
- package/src/components/BillingResult.tsx +447 -0
- package/src/components/BroadcastComposer.tsx +690 -0
- package/src/components/ChannelAdminPanel.tsx +773 -0
- package/src/components/ChannelBrowser.tsx +385 -0
- package/src/components/ChannelChat.tsx +261 -0
- package/src/components/ChannelSidebar.tsx +399 -0
- package/src/components/CloudSessionProvider.tsx +130 -0
- package/src/components/CommandPalette.tsx +815 -0
- package/src/components/ConfirmationDialog.tsx +133 -0
- package/src/components/ConversationHistory.tsx +518 -0
- package/src/components/CoordinatorPanel.tsx +956 -0
- package/src/components/DecisionQueue.tsx +717 -0
- package/src/components/DirectMessageView.tsx +164 -0
- package/src/components/FileAutocomplete.tsx +368 -0
- package/src/components/FleetOverview.tsx +278 -0
- package/src/components/LogViewer.tsx +310 -0
- package/src/components/LogViewerPanel.tsx +482 -0
- package/src/components/Logo.tsx +284 -0
- package/src/components/MentionAutocomplete.tsx +384 -0
- package/src/components/MessageComposer.tsx +473 -0
- package/src/components/MessageList.tsx +725 -0
- package/src/components/MessageSenderName.tsx +91 -0
- package/src/components/MessageStatusIndicator.tsx +142 -0
- package/src/components/NewConversationModal.tsx +400 -0
- package/src/components/NotificationToast.tsx +488 -0
- package/src/components/OnlineUsersIndicator.tsx +164 -0
- package/src/components/Pagination.tsx +124 -0
- package/src/components/PricingPlans.tsx +386 -0
- package/src/components/ProjectList.tsx +711 -0
- package/src/components/ProviderAuthFlow.tsx +343 -0
- package/src/components/ProviderConnectionList.tsx +375 -0
- package/src/components/ProvisioningProgress.tsx +730 -0
- package/src/components/ReactionChips.tsx +70 -0
- package/src/components/ReactionPicker.tsx +121 -0
- package/src/components/RepoAccessPanel.tsx +787 -0
- package/src/components/RepositoriesPanel.tsx +901 -0
- package/src/components/ServerCard.tsx +202 -0
- package/src/components/SessionExpiredModal.tsx +128 -0
- package/src/components/SpawnModal.test.tsx +190 -0
- package/src/components/SpawnModal.tsx +1001 -0
- package/src/components/TaskAssignmentUI.tsx +375 -0
- package/src/components/TerminalProviderSetup.tsx +517 -0
- package/src/components/ThemeProvider.tsx +159 -0
- package/src/components/ThinkingIndicator.tsx +231 -0
- package/src/components/ThreadList.tsx +198 -0
- package/src/components/ThreadPanel.tsx +405 -0
- package/src/components/TrajectoryViewer.tsx +698 -0
- package/src/components/TypingIndicator.tsx +69 -0
- package/src/components/UsageBanner.tsx +231 -0
- package/src/components/UserProfilePanel.tsx +233 -0
- package/src/components/WorkspaceContext.tsx +95 -0
- package/src/components/WorkspaceSelector.tsx +234 -0
- package/src/components/WorkspaceStatusIndicator.tsx +396 -0
- package/src/components/XTermInteractive.tsx +516 -0
- package/src/components/XTermLogViewer.tsx +719 -0
- package/src/components/channels/ChannelDialogs.tsx +1411 -0
- package/src/components/channels/ChannelHeader.tsx +317 -0
- package/src/components/channels/ChannelMessageList.tsx +463 -0
- package/src/components/channels/ChannelViewV1.tsx +146 -0
- package/src/components/channels/MessageInput.tsx +302 -0
- package/src/components/channels/SearchInput.tsx +172 -0
- package/src/components/channels/SearchResults.tsx +336 -0
- package/src/components/channels/api.test.ts +1527 -0
- package/src/components/channels/api.ts +703 -0
- package/src/components/channels/index.ts +76 -0
- package/src/components/channels/mockApi.ts +344 -0
- package/src/components/channels/types.ts +566 -0
- package/src/components/hooks/index.ts +58 -0
- package/src/components/hooks/useAgentLogs.ts +504 -0
- package/src/components/hooks/useAgents.ts +127 -0
- package/src/components/hooks/useBroadcastDedup.test.ts +371 -0
- package/src/components/hooks/useBroadcastDedup.ts +86 -0
- package/src/components/hooks/useChannelAdmin.ts +329 -0
- package/src/components/hooks/useChannelBrowser.ts +239 -0
- package/src/components/hooks/useChannelCommands.ts +138 -0
- package/src/components/hooks/useChannels.ts +367 -0
- package/src/components/hooks/useDebounce.ts +29 -0
- package/src/components/hooks/useDirectMessage.test.ts +952 -0
- package/src/components/hooks/useDirectMessage.ts +141 -0
- package/src/components/hooks/useMessages.ts +310 -0
- package/src/components/hooks/useOrchestrator.test.ts +165 -0
- package/src/components/hooks/useOrchestrator.ts +424 -0
- package/src/components/hooks/usePinnedAgents.test.ts +356 -0
- package/src/components/hooks/usePinnedAgents.ts +140 -0
- package/src/components/hooks/usePresence.test.ts +245 -0
- package/src/components/hooks/usePresence.ts +377 -0
- package/src/components/hooks/useRecentRepos.ts +130 -0
- package/src/components/hooks/useSession.ts +209 -0
- package/src/components/hooks/useThread.ts +138 -0
- package/src/components/hooks/useTrajectory.ts +265 -0
- package/src/components/hooks/useWebSocket.ts +290 -0
- package/src/components/hooks/useWorkspaceMembers.ts +132 -0
- package/src/components/hooks/useWorkspaceRepos.ts +73 -0
- package/src/components/hooks/useWorkspaceStatus.ts +237 -0
- package/src/components/index.ts +81 -0
- package/src/components/layout/Header.tsx +311 -0
- package/src/components/layout/RepoContextHeader.tsx +361 -0
- package/src/components/layout/Sidebar.archive.test.tsx +126 -0
- package/src/components/layout/Sidebar.test.tsx +691 -0
- package/src/components/layout/Sidebar.tsx +900 -0
- package/src/components/layout/index.ts +7 -0
- package/src/components/settings/BillingSettingsPanel.tsx +564 -0
- package/src/components/settings/SettingsPage.tsx +683 -0
- package/src/components/settings/TeamSettingsPanel.tsx +560 -0
- package/src/components/settings/WorkspaceSettingsPanel.tsx +1368 -0
- package/src/components/settings/index.ts +11 -0
- package/src/components/settings/types.ts +79 -0
- package/src/components/utils/messageFormatting.test.tsx +331 -0
- package/src/components/utils/messageFormatting.tsx +597 -0
- package/src/index.ts +63 -0
- package/src/landing/AboutPage.tsx +77 -0
- package/src/landing/BlogContent.tsx +187 -0
- package/src/landing/BlogPage.tsx +47 -0
- package/src/landing/CareersPage.tsx +53 -0
- package/src/landing/ChangelogPage.tsx +33 -0
- package/src/landing/ContactPage.tsx +41 -0
- package/src/landing/DocsPage.tsx +43 -0
- package/src/landing/LandingPage.tsx +702 -0
- package/src/landing/PricingPage.tsx +549 -0
- package/src/landing/PrivacyPage.tsx +117 -0
- package/src/landing/SecurityPage.tsx +42 -0
- package/src/landing/StaticPage.tsx +165 -0
- package/src/landing/TermsPage.tsx +125 -0
- package/src/landing/blogData.ts +312 -0
- package/src/landing/index.ts +18 -0
- package/src/landing/styles.css +3673 -0
- package/src/lib/agent-merge.test.ts +43 -0
- package/src/lib/agent-merge.ts +35 -0
- package/src/lib/api.ts +1294 -0
- package/src/lib/cloudApi.ts +893 -0
- package/src/lib/colors.test.ts +175 -0
- package/src/lib/colors.ts +218 -0
- package/src/lib/config.ts +109 -0
- package/src/lib/hierarchy.ts +242 -0
- package/src/lib/stuckDetection.ts +142 -0
- package/src/lib/useUrlRouting.ts +190 -0
- package/src/types/index.ts +317 -0
- package/src/types/threading.ts +7 -0
- package/out/_next/static/chunks/285-dc644487a8d6500d.js +0 -1
- package/out/_next/static/css/4c58d9cf493aa626.css +0 -1
- /package/out/_next/static/{AqelRhy1vr2nBUcU0Iqcp → IxfA6RZu4trcsEMYlkQra}/_buildManifest.js +0 -0
- /package/out/_next/static/{AqelRhy1vr2nBUcU0Iqcp → IxfA6RZu4trcsEMYlkQra}/_ssgManifest.js +0 -0
- /package/out/_next/static/chunks/{528-d375bc8b46912d2c.js → 528-f5f676996d613c25.js} +0 -0
- /package/out/_next/static/chunks/app/blog/let-them-cook-multi-agent-orchestration/{page-a58308f43557b908.js → page-b194f207fbd91862.js} +0 -0
|
@@ -0,0 +1,585 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AgentCard Component
|
|
3
|
+
*
|
|
4
|
+
* Displays an agent with a distinctive neural/holographic design language.
|
|
5
|
+
* Features gradient backgrounds, animated status indicators, and depth effects.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import React from 'react';
|
|
9
|
+
import type { Agent } from '../types';
|
|
10
|
+
import {
|
|
11
|
+
getAgentColor,
|
|
12
|
+
getAgentInitials,
|
|
13
|
+
STATUS_COLORS,
|
|
14
|
+
type AgentStatus,
|
|
15
|
+
} from '../lib/colors';
|
|
16
|
+
import { getAgentDisplayName, getAgentBreadcrumb } from '../lib/hierarchy';
|
|
17
|
+
import { ThinkingIndicator, ThinkingDot } from './ThinkingIndicator';
|
|
18
|
+
import { getStuckDuration, formatStuckDuration } from '../lib/stuckDetection';
|
|
19
|
+
|
|
20
|
+
export interface AgentCardProps {
|
|
21
|
+
agent: Agent;
|
|
22
|
+
isSelected?: boolean;
|
|
23
|
+
showBreadcrumb?: boolean;
|
|
24
|
+
compact?: boolean;
|
|
25
|
+
displayNameOverride?: string;
|
|
26
|
+
/** Whether the agent is pinned to the top */
|
|
27
|
+
isPinned?: boolean;
|
|
28
|
+
/** Whether max pins has been reached (disables pin button for unpinned agents) */
|
|
29
|
+
isMaxPinned?: boolean;
|
|
30
|
+
onClick?: (agent: Agent) => void;
|
|
31
|
+
onMessageClick?: (agent: Agent) => void;
|
|
32
|
+
onReleaseClick?: (agent: Agent) => void;
|
|
33
|
+
onLogsClick?: (agent: Agent) => void;
|
|
34
|
+
onProfileClick?: (agent: Agent) => void;
|
|
35
|
+
/** Handler for pin/unpin toggle */
|
|
36
|
+
onPinToggle?: (agent: Agent) => void;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Get a descriptive tooltip for an agent's connection status.
|
|
41
|
+
*/
|
|
42
|
+
function getStatusTooltip(status: AgentStatus, isProcessing?: boolean, isStuck?: boolean, stuckDuration?: number): string {
|
|
43
|
+
if (isStuck && stuckDuration) {
|
|
44
|
+
return `Stuck - Agent received message ${formatStuckDuration(stuckDuration)} ago but hasn't responded`;
|
|
45
|
+
}
|
|
46
|
+
if (isProcessing) {
|
|
47
|
+
return 'Processing - Agent is actively working';
|
|
48
|
+
}
|
|
49
|
+
switch (status) {
|
|
50
|
+
case 'online':
|
|
51
|
+
return 'Connected - Agent is online and ready';
|
|
52
|
+
case 'offline':
|
|
53
|
+
return 'Disconnected - Agent is not connected';
|
|
54
|
+
case 'busy':
|
|
55
|
+
return 'Busy - Agent is occupied with a task';
|
|
56
|
+
case 'processing':
|
|
57
|
+
return 'Processing - Agent is actively working';
|
|
58
|
+
case 'error':
|
|
59
|
+
return 'Error - Agent encountered an error';
|
|
60
|
+
case 'attention':
|
|
61
|
+
return 'Attention - Agent requires user input';
|
|
62
|
+
case 'stuck':
|
|
63
|
+
return 'Stuck - Agent may be blocked or unresponsive';
|
|
64
|
+
default:
|
|
65
|
+
return `Status: ${status}`;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export function AgentCard({
|
|
70
|
+
agent,
|
|
71
|
+
isSelected = false,
|
|
72
|
+
showBreadcrumb = false,
|
|
73
|
+
compact = false,
|
|
74
|
+
displayNameOverride,
|
|
75
|
+
isPinned = false,
|
|
76
|
+
isMaxPinned = false,
|
|
77
|
+
onClick,
|
|
78
|
+
onMessageClick,
|
|
79
|
+
onReleaseClick,
|
|
80
|
+
onLogsClick,
|
|
81
|
+
onProfileClick,
|
|
82
|
+
onPinToggle,
|
|
83
|
+
}: AgentCardProps) {
|
|
84
|
+
const colors = getAgentColor(agent.name);
|
|
85
|
+
const initials = getAgentInitials(agent.name);
|
|
86
|
+
const displayName = displayNameOverride || getAgentDisplayName(agent.name);
|
|
87
|
+
const stuckDuration = getStuckDuration(agent);
|
|
88
|
+
const isStuck = agent.isStuck || stuckDuration > 0;
|
|
89
|
+
const statusColor = isStuck ? STATUS_COLORS.stuck : (STATUS_COLORS[agent.status] || STATUS_COLORS.offline);
|
|
90
|
+
const isOnline = agent.status === 'online';
|
|
91
|
+
const statusTooltip = getStatusTooltip(agent.status, agent.isProcessing, isStuck, stuckDuration);
|
|
92
|
+
|
|
93
|
+
const handleClick = () => {
|
|
94
|
+
onClick?.(agent);
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
const handleMessageClick = (e: React.MouseEvent) => {
|
|
98
|
+
e.stopPropagation();
|
|
99
|
+
onMessageClick?.(agent);
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
const handleReleaseClick = (e: React.MouseEvent) => {
|
|
103
|
+
e.stopPropagation();
|
|
104
|
+
onReleaseClick?.(agent);
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
const handleLogsClick = (e: React.MouseEvent) => {
|
|
108
|
+
e.stopPropagation();
|
|
109
|
+
onLogsClick?.(agent);
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
const handleProfileClick = (e: React.MouseEvent) => {
|
|
113
|
+
e.stopPropagation();
|
|
114
|
+
onProfileClick?.(agent);
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
const handlePinToggle = (e: React.MouseEvent) => {
|
|
118
|
+
e.stopPropagation();
|
|
119
|
+
onPinToggle?.(agent);
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
if (compact) {
|
|
123
|
+
return (
|
|
124
|
+
<div
|
|
125
|
+
className={`
|
|
126
|
+
group relative flex items-start gap-3 py-2.5 px-3 rounded-lg cursor-pointer
|
|
127
|
+
transition-all duration-300 ease-out
|
|
128
|
+
hover:bg-bg-hover
|
|
129
|
+
${isSelected ? 'bg-bg-active' : ''}
|
|
130
|
+
`}
|
|
131
|
+
onClick={handleClick}
|
|
132
|
+
style={{
|
|
133
|
+
borderLeft: isSelected ? `2px solid ${colors.primary}` : '2px solid transparent',
|
|
134
|
+
boxShadow: isSelected ? `inset 4px 0 12px -4px ${colors.primary}40` : 'none',
|
|
135
|
+
}}
|
|
136
|
+
>
|
|
137
|
+
{/* Agent Avatar with Glow */}
|
|
138
|
+
<div className="relative">
|
|
139
|
+
<div
|
|
140
|
+
className={`
|
|
141
|
+
w-8 h-8 rounded-lg flex items-center justify-center font-bold text-[11px] tracking-wide
|
|
142
|
+
transition-all duration-300 relative overflow-hidden
|
|
143
|
+
${isOnline ? 'shadow-lg' : 'opacity-60'}
|
|
144
|
+
`}
|
|
145
|
+
style={{
|
|
146
|
+
background: `linear-gradient(135deg, ${colors.primary}, ${colors.primary}99)`,
|
|
147
|
+
boxShadow: isOnline ? `0 2px 12px ${colors.primary}50` : 'none',
|
|
148
|
+
}}
|
|
149
|
+
>
|
|
150
|
+
{/* Subtle shine effect */}
|
|
151
|
+
<div
|
|
152
|
+
className="absolute inset-0 opacity-30"
|
|
153
|
+
style={{
|
|
154
|
+
background: 'linear-gradient(135deg, rgba(255,255,255,0.3) 0%, transparent 50%)',
|
|
155
|
+
}}
|
|
156
|
+
/>
|
|
157
|
+
<span className="relative z-10" style={{ color: colors.text }}>{initials}</span>
|
|
158
|
+
</div>
|
|
159
|
+
{/* Status Ring */}
|
|
160
|
+
{isOnline && (
|
|
161
|
+
<div
|
|
162
|
+
className="absolute -bottom-0.5 -right-0.5 w-3 h-3 rounded-full border-2 border-bg-primary"
|
|
163
|
+
style={{
|
|
164
|
+
backgroundColor: statusColor,
|
|
165
|
+
boxShadow: `0 0 8px ${statusColor}`,
|
|
166
|
+
}}
|
|
167
|
+
title={statusTooltip}
|
|
168
|
+
/>
|
|
169
|
+
)}
|
|
170
|
+
</div>
|
|
171
|
+
|
|
172
|
+
{/* Agent Info */}
|
|
173
|
+
<div className="flex-1 min-w-0 flex flex-col">
|
|
174
|
+
<div className="flex items-start gap-1.5 flex-wrap">
|
|
175
|
+
<span
|
|
176
|
+
className={`
|
|
177
|
+
text-[13px] font-semibold tracking-tight transition-colors duration-200
|
|
178
|
+
whitespace-normal break-words leading-snug
|
|
179
|
+
${isOnline ? 'text-text-primary' : 'text-text-secondary'}
|
|
180
|
+
`}
|
|
181
|
+
>
|
|
182
|
+
{displayName}
|
|
183
|
+
</span>
|
|
184
|
+
{agent.isLocal && (
|
|
185
|
+
<span
|
|
186
|
+
className="inline-flex items-center px-1.5 py-0.5 rounded text-[9px] font-medium uppercase tracking-wider
|
|
187
|
+
bg-warning-light text-warning border border-warning/30"
|
|
188
|
+
title={`Local agent from ${agent.daemonName || 'linked daemon'}`}
|
|
189
|
+
>
|
|
190
|
+
Local
|
|
191
|
+
</span>
|
|
192
|
+
)}
|
|
193
|
+
{isPinned && (
|
|
194
|
+
<span
|
|
195
|
+
className="inline-flex items-center text-amber-400"
|
|
196
|
+
title="Pinned to top"
|
|
197
|
+
>
|
|
198
|
+
<PinIcon size={12} filled />
|
|
199
|
+
</span>
|
|
200
|
+
)}
|
|
201
|
+
</div>
|
|
202
|
+
{agent.cli && (
|
|
203
|
+
<span className="text-[10px] text-text-muted truncate font-mono opacity-70 mt-0.5">
|
|
204
|
+
{agent.cli}
|
|
205
|
+
</span>
|
|
206
|
+
)}
|
|
207
|
+
{(agent.model || agent.profile?.model) && (
|
|
208
|
+
<span className="text-[9px] text-accent-muted font-mono opacity-80 mt-0.5" title={`Model: ${agent.model || agent.profile?.model}`}>
|
|
209
|
+
{agent.model || agent.profile?.model}
|
|
210
|
+
</span>
|
|
211
|
+
)}
|
|
212
|
+
|
|
213
|
+
{/* Actions & Status */}
|
|
214
|
+
<div className="mt-2 flex items-center flex-wrap gap-2">
|
|
215
|
+
{onPinToggle && (
|
|
216
|
+
<button
|
|
217
|
+
className={`
|
|
218
|
+
relative bg-transparent border border-transparent p-1.5 cursor-pointer
|
|
219
|
+
flex items-center justify-center rounded-md transition-all duration-200
|
|
220
|
+
${isPinned
|
|
221
|
+
? 'text-amber-400 hover:bg-amber-400/10 hover:border-amber-400/30'
|
|
222
|
+
: 'text-text-dim hover:bg-amber-400/10 hover:border-amber-400/30 hover:text-amber-400'}
|
|
223
|
+
${!isPinned && isMaxPinned ? 'opacity-40 cursor-not-allowed' : ''}
|
|
224
|
+
`}
|
|
225
|
+
onClick={handlePinToggle}
|
|
226
|
+
title={isPinned ? 'Unpin from top' : isMaxPinned ? 'Maximum pins reached (5)' : 'Pin to top'}
|
|
227
|
+
disabled={!isPinned && isMaxPinned}
|
|
228
|
+
>
|
|
229
|
+
<PinIcon size={16} filled={isPinned} />
|
|
230
|
+
</button>
|
|
231
|
+
)}
|
|
232
|
+
{onProfileClick && (
|
|
233
|
+
<button
|
|
234
|
+
className="relative bg-transparent border border-transparent text-text-dim p-1.5 cursor-pointer
|
|
235
|
+
flex items-center justify-center rounded-md transition-all duration-200
|
|
236
|
+
opacity-100
|
|
237
|
+
hover:bg-accent-purple/10 hover:border-accent-purple/30 hover:text-accent-purple"
|
|
238
|
+
onClick={handleProfileClick}
|
|
239
|
+
title="View profile"
|
|
240
|
+
>
|
|
241
|
+
<ProfileIcon />
|
|
242
|
+
</button>
|
|
243
|
+
)}
|
|
244
|
+
{onLogsClick && (
|
|
245
|
+
<button
|
|
246
|
+
className="relative bg-transparent border border-transparent text-text-dim p-1.5 cursor-pointer
|
|
247
|
+
flex items-center justify-center rounded-md transition-all duration-200
|
|
248
|
+
opacity-100
|
|
249
|
+
hover:bg-accent-cyan/10 hover:border-accent-cyan/30 hover:text-accent-cyan"
|
|
250
|
+
onClick={handleLogsClick}
|
|
251
|
+
title="View logs"
|
|
252
|
+
>
|
|
253
|
+
<LogsIcon />
|
|
254
|
+
</button>
|
|
255
|
+
)}
|
|
256
|
+
{agent.isSpawned && onReleaseClick && (
|
|
257
|
+
<button
|
|
258
|
+
className="relative bg-transparent border border-transparent text-text-dim p-1.5 cursor-pointer
|
|
259
|
+
flex items-center justify-center rounded-md transition-all duration-200
|
|
260
|
+
opacity-100
|
|
261
|
+
hover:bg-error/10 hover:border-error/30 hover:text-error"
|
|
262
|
+
onClick={handleReleaseClick}
|
|
263
|
+
title="Kill agent"
|
|
264
|
+
>
|
|
265
|
+
<ReleaseIcon />
|
|
266
|
+
</button>
|
|
267
|
+
)}
|
|
268
|
+
{agent.isProcessing ? (
|
|
269
|
+
<div title={statusTooltip}>
|
|
270
|
+
<ThinkingDot isProcessing={true} />
|
|
271
|
+
</div>
|
|
272
|
+
) : (
|
|
273
|
+
<div
|
|
274
|
+
className={`
|
|
275
|
+
w-2 h-2 rounded-full transition-all duration-300
|
|
276
|
+
${isOnline ? 'animate-pulse' : ''}
|
|
277
|
+
`}
|
|
278
|
+
style={{
|
|
279
|
+
backgroundColor: statusColor,
|
|
280
|
+
boxShadow: isOnline ? `0 0 6px ${statusColor}` : 'none',
|
|
281
|
+
}}
|
|
282
|
+
title={statusTooltip}
|
|
283
|
+
/>
|
|
284
|
+
)}
|
|
285
|
+
{isStuck && (
|
|
286
|
+
<div
|
|
287
|
+
className="flex items-center gap-1 px-1.5 py-0.5 rounded bg-warning-light text-warning text-[10px] font-medium animate-pulse"
|
|
288
|
+
title={statusTooltip}
|
|
289
|
+
>
|
|
290
|
+
<StuckIcon />
|
|
291
|
+
<span>{formatStuckDuration(stuckDuration)}</span>
|
|
292
|
+
</div>
|
|
293
|
+
)}
|
|
294
|
+
</div>
|
|
295
|
+
</div>
|
|
296
|
+
</div>
|
|
297
|
+
);
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
return (
|
|
301
|
+
<div
|
|
302
|
+
className={`
|
|
303
|
+
rounded-lg p-3 cursor-pointer transition-all duration-200
|
|
304
|
+
hover:shadow-md hover:-translate-y-px
|
|
305
|
+
${isSelected ? 'border-2 shadow-[0_0_0_2px_rgba(74,158,255,0.15)]' : 'border'}
|
|
306
|
+
`}
|
|
307
|
+
onClick={handleClick}
|
|
308
|
+
style={{
|
|
309
|
+
backgroundColor: colors.light,
|
|
310
|
+
borderColor: colors.primary,
|
|
311
|
+
}}
|
|
312
|
+
>
|
|
313
|
+
<div className="flex items-center gap-3">
|
|
314
|
+
<div
|
|
315
|
+
className="w-10 h-10 rounded-lg flex items-center justify-center font-semibold text-sm relative"
|
|
316
|
+
style={{ backgroundColor: colors.primary }}
|
|
317
|
+
>
|
|
318
|
+
<span style={{ color: colors.text }}>{initials}</span>
|
|
319
|
+
<div
|
|
320
|
+
className="absolute -bottom-0.5 -right-0.5 w-3 h-3 rounded-full border-2 border-bg-secondary"
|
|
321
|
+
style={{ backgroundColor: statusColor }}
|
|
322
|
+
title={statusTooltip}
|
|
323
|
+
/>
|
|
324
|
+
</div>
|
|
325
|
+
<div className="flex-1 min-w-0">
|
|
326
|
+
<div className="flex items-center gap-2">
|
|
327
|
+
<span className="font-semibold text-sm text-text-primary">{displayName}</span>
|
|
328
|
+
{agent.isLocal && (
|
|
329
|
+
<span
|
|
330
|
+
className="inline-flex items-center px-1.5 py-0.5 rounded text-[9px] font-medium uppercase tracking-wider
|
|
331
|
+
bg-warning-light text-warning border border-warning/30"
|
|
332
|
+
title={`Local agent from ${agent.daemonName || 'linked daemon'}`}
|
|
333
|
+
>
|
|
334
|
+
Local
|
|
335
|
+
</span>
|
|
336
|
+
)}
|
|
337
|
+
{isPinned && (
|
|
338
|
+
<span
|
|
339
|
+
className="inline-flex items-center text-amber-400"
|
|
340
|
+
title="Pinned to top"
|
|
341
|
+
>
|
|
342
|
+
<PinIcon size={14} filled />
|
|
343
|
+
</span>
|
|
344
|
+
)}
|
|
345
|
+
{agent.needsAttention && (
|
|
346
|
+
<span className="bg-error text-white text-[10px] font-bold w-4 h-4 rounded-full flex items-center justify-center" title="Needs Attention - Agent requires user input or has pending decisions">!</span>
|
|
347
|
+
)}
|
|
348
|
+
{isStuck && (
|
|
349
|
+
<span className="bg-warning text-white text-[10px] font-bold px-1.5 py-0.5 rounded flex items-center gap-1" title={statusTooltip}>
|
|
350
|
+
<StuckIcon /> {formatStuckDuration(stuckDuration)}
|
|
351
|
+
</span>
|
|
352
|
+
)}
|
|
353
|
+
</div>
|
|
354
|
+
{showBreadcrumb ? (
|
|
355
|
+
<span className="text-xs text-text-muted truncate block">{agent.isLocal ? agent.daemonName || agent.machineId : getAgentBreadcrumb(agent.name)}</span>
|
|
356
|
+
) : (
|
|
357
|
+
<span className="text-xs text-text-muted truncate block">{agent.isLocal ? agent.daemonName || agent.machineId : agent.name}</span>
|
|
358
|
+
)}
|
|
359
|
+
{agent.agentId && (
|
|
360
|
+
<span className="text-[10px] text-text-muted font-mono opacity-70" title="Agent ID (use to resume)">
|
|
361
|
+
ID: {agent.agentId}
|
|
362
|
+
</span>
|
|
363
|
+
)}
|
|
364
|
+
</div>
|
|
365
|
+
</div>
|
|
366
|
+
|
|
367
|
+
{agent.isProcessing && (
|
|
368
|
+
<div className="mt-2 p-2 bg-accent-light rounded flex items-center gap-2 border border-accent/20">
|
|
369
|
+
<ThinkingIndicator
|
|
370
|
+
isProcessing={true}
|
|
371
|
+
processingStartedAt={agent.processingStartedAt}
|
|
372
|
+
size="medium"
|
|
373
|
+
showElapsed={true}
|
|
374
|
+
/>
|
|
375
|
+
<span className="text-xs text-accent font-medium">Thinking...</span>
|
|
376
|
+
</div>
|
|
377
|
+
)}
|
|
378
|
+
|
|
379
|
+
{agent.currentTask && !agent.isProcessing && (
|
|
380
|
+
<div className="mt-2 p-2 bg-bg-hover rounded text-xs">
|
|
381
|
+
<span className="text-text-muted mr-1">Working on:</span>
|
|
382
|
+
<span className="text-text-primary line-clamp-2" title={agent.currentTask}>{agent.currentTask}</span>
|
|
383
|
+
</div>
|
|
384
|
+
)}
|
|
385
|
+
|
|
386
|
+
<div className="mt-3 flex justify-between items-center">
|
|
387
|
+
<div className="flex gap-2 text-xs text-text-muted flex-wrap">
|
|
388
|
+
{agent.cli && <span className="bg-bg-hover py-0.5 px-1.5 rounded">{agent.cli}</span>}
|
|
389
|
+
{(agent.model || agent.profile?.model) && (
|
|
390
|
+
<span className="bg-accent-cyan/10 text-accent-cyan py-0.5 px-1.5 rounded font-mono text-[10px]" title={`Model: ${agent.model || agent.profile?.model}`}>
|
|
391
|
+
{agent.model || agent.profile?.model}
|
|
392
|
+
</span>
|
|
393
|
+
)}
|
|
394
|
+
{agent.messageCount !== undefined && agent.messageCount > 0 && (
|
|
395
|
+
<span style={{ color: colors.primary }}>{agent.messageCount} msgs</span>
|
|
396
|
+
)}
|
|
397
|
+
{agent.isSpawned && (
|
|
398
|
+
<span className="bg-accent-light text-accent text-[10px] py-0.5 px-1.5 rounded uppercase font-medium">spawned</span>
|
|
399
|
+
)}
|
|
400
|
+
</div>
|
|
401
|
+
<div className="flex gap-1.5">
|
|
402
|
+
{onPinToggle && (
|
|
403
|
+
<button
|
|
404
|
+
className={`
|
|
405
|
+
rounded-md py-1.5 px-2.5 cursor-pointer flex items-center justify-center gap-1 transition-all duration-200
|
|
406
|
+
border
|
|
407
|
+
${isPinned
|
|
408
|
+
? 'bg-amber-500/10 text-amber-400 border-amber-500/30 hover:bg-amber-500/20'
|
|
409
|
+
: 'bg-bg-tertiary text-text-muted border-border hover:bg-amber-500/10 hover:text-amber-400 hover:border-amber-500/30'}
|
|
410
|
+
${!isPinned && isMaxPinned ? 'opacity-40 cursor-not-allowed' : 'hover:scale-105'}
|
|
411
|
+
active:scale-[0.98]
|
|
412
|
+
`}
|
|
413
|
+
onClick={handlePinToggle}
|
|
414
|
+
title={isPinned ? 'Unpin from top' : isMaxPinned ? 'Maximum pins reached (5)' : 'Pin to top'}
|
|
415
|
+
disabled={!isPinned && isMaxPinned}
|
|
416
|
+
>
|
|
417
|
+
<PinIcon size={16} filled={isPinned} />
|
|
418
|
+
</button>
|
|
419
|
+
)}
|
|
420
|
+
{onProfileClick && (
|
|
421
|
+
<button
|
|
422
|
+
className="bg-accent-purple/10 text-accent-purple border border-accent-purple/30 rounded-md py-1.5 px-2.5 cursor-pointer flex items-center justify-center gap-1 transition-all duration-200 hover:bg-accent-purple/20 hover:scale-105 active:scale-[0.98]"
|
|
423
|
+
onClick={handleProfileClick}
|
|
424
|
+
title="View profile"
|
|
425
|
+
>
|
|
426
|
+
<ProfileIcon />
|
|
427
|
+
</button>
|
|
428
|
+
)}
|
|
429
|
+
{onLogsClick && (
|
|
430
|
+
<button
|
|
431
|
+
className="bg-accent-cyan/10 text-accent-cyan border border-accent-cyan/30 rounded-md py-1.5 px-2.5 cursor-pointer flex items-center justify-center gap-1 transition-all duration-200 hover:bg-accent-cyan/20 hover:scale-105 active:scale-[0.98]"
|
|
432
|
+
onClick={handleLogsClick}
|
|
433
|
+
title="View logs"
|
|
434
|
+
>
|
|
435
|
+
<LogsIcon />
|
|
436
|
+
</button>
|
|
437
|
+
)}
|
|
438
|
+
{agent.isSpawned && onReleaseClick && (
|
|
439
|
+
<button
|
|
440
|
+
className="bg-error/10 text-error border border-error/30 rounded-md py-1.5 px-2.5 cursor-pointer flex items-center justify-center gap-1 transition-all duration-200 hover:bg-error/20 hover:scale-105 active:scale-[0.98]"
|
|
441
|
+
onClick={handleReleaseClick}
|
|
442
|
+
title="Release agent"
|
|
443
|
+
>
|
|
444
|
+
<ReleaseIcon />
|
|
445
|
+
</button>
|
|
446
|
+
)}
|
|
447
|
+
{onMessageClick && (
|
|
448
|
+
<button
|
|
449
|
+
className="text-white border-none rounded py-1 px-2 cursor-pointer flex items-center justify-center transition-opacity duration-200 hover:opacity-90"
|
|
450
|
+
style={{ backgroundColor: colors.primary }}
|
|
451
|
+
onClick={handleMessageClick}
|
|
452
|
+
title="Send message"
|
|
453
|
+
>
|
|
454
|
+
<MessageIcon />
|
|
455
|
+
</button>
|
|
456
|
+
)}
|
|
457
|
+
</div>
|
|
458
|
+
</div>
|
|
459
|
+
</div>
|
|
460
|
+
);
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
function MessageIcon() {
|
|
464
|
+
return (
|
|
465
|
+
<svg
|
|
466
|
+
width="16"
|
|
467
|
+
height="16"
|
|
468
|
+
viewBox="0 0 24 24"
|
|
469
|
+
fill="none"
|
|
470
|
+
stroke="currentColor"
|
|
471
|
+
strokeWidth="2"
|
|
472
|
+
strokeLinecap="round"
|
|
473
|
+
strokeLinejoin="round"
|
|
474
|
+
>
|
|
475
|
+
<path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z" />
|
|
476
|
+
</svg>
|
|
477
|
+
);
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
function ReleaseIcon() {
|
|
481
|
+
return (
|
|
482
|
+
<svg
|
|
483
|
+
width="16"
|
|
484
|
+
height="16"
|
|
485
|
+
viewBox="0 0 24 24"
|
|
486
|
+
fill="none"
|
|
487
|
+
className="release-icon"
|
|
488
|
+
>
|
|
489
|
+
<path
|
|
490
|
+
d="M12 22c5.523 0 10-4.477 10-10a9.96 9.96 0 0 0-3-7.141"
|
|
491
|
+
stroke="currentColor"
|
|
492
|
+
strokeWidth="2"
|
|
493
|
+
strokeLinecap="round"
|
|
494
|
+
/>
|
|
495
|
+
<path
|
|
496
|
+
d="M12 22C6.477 22 2 17.523 2 12a9.96 9.96 0 0 1 3-7.141"
|
|
497
|
+
stroke="currentColor"
|
|
498
|
+
strokeWidth="2"
|
|
499
|
+
strokeLinecap="round"
|
|
500
|
+
/>
|
|
501
|
+
<line
|
|
502
|
+
x1="12"
|
|
503
|
+
y1="2"
|
|
504
|
+
x2="12"
|
|
505
|
+
y2="12"
|
|
506
|
+
stroke="currentColor"
|
|
507
|
+
strokeWidth="2.5"
|
|
508
|
+
strokeLinecap="round"
|
|
509
|
+
/>
|
|
510
|
+
</svg>
|
|
511
|
+
);
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
function LogsIcon() {
|
|
515
|
+
return (
|
|
516
|
+
<svg
|
|
517
|
+
width="16"
|
|
518
|
+
height="16"
|
|
519
|
+
viewBox="0 0 24 24"
|
|
520
|
+
fill="none"
|
|
521
|
+
stroke="currentColor"
|
|
522
|
+
strokeWidth="2"
|
|
523
|
+
strokeLinecap="round"
|
|
524
|
+
strokeLinejoin="round"
|
|
525
|
+
>
|
|
526
|
+
<polyline points="4 17 10 11 4 5" />
|
|
527
|
+
<line x1="12" y1="19" x2="20" y2="19" />
|
|
528
|
+
</svg>
|
|
529
|
+
);
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
function StuckIcon() {
|
|
533
|
+
return (
|
|
534
|
+
<svg
|
|
535
|
+
width="12"
|
|
536
|
+
height="12"
|
|
537
|
+
viewBox="0 0 24 24"
|
|
538
|
+
fill="none"
|
|
539
|
+
stroke="currentColor"
|
|
540
|
+
strokeWidth="2"
|
|
541
|
+
strokeLinecap="round"
|
|
542
|
+
strokeLinejoin="round"
|
|
543
|
+
>
|
|
544
|
+
<circle cx="12" cy="12" r="10" />
|
|
545
|
+
<line x1="12" y1="8" x2="12" y2="12" />
|
|
546
|
+
<line x1="12" y1="16" x2="12.01" y2="16" />
|
|
547
|
+
</svg>
|
|
548
|
+
);
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
function ProfileIcon() {
|
|
552
|
+
return (
|
|
553
|
+
<svg
|
|
554
|
+
width="16"
|
|
555
|
+
height="16"
|
|
556
|
+
viewBox="0 0 24 24"
|
|
557
|
+
fill="none"
|
|
558
|
+
stroke="currentColor"
|
|
559
|
+
strokeWidth="2"
|
|
560
|
+
strokeLinecap="round"
|
|
561
|
+
strokeLinejoin="round"
|
|
562
|
+
>
|
|
563
|
+
<path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2" />
|
|
564
|
+
<circle cx="12" cy="7" r="4" />
|
|
565
|
+
</svg>
|
|
566
|
+
);
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
function PinIcon({ size = 16, filled = false }: { size?: number; filled?: boolean }) {
|
|
570
|
+
return (
|
|
571
|
+
<svg
|
|
572
|
+
width={size}
|
|
573
|
+
height={size}
|
|
574
|
+
viewBox="0 0 24 24"
|
|
575
|
+
fill={filled ? 'currentColor' : 'none'}
|
|
576
|
+
stroke="currentColor"
|
|
577
|
+
strokeWidth="2"
|
|
578
|
+
strokeLinecap="round"
|
|
579
|
+
strokeLinejoin="round"
|
|
580
|
+
>
|
|
581
|
+
<path d="M12 17v5" />
|
|
582
|
+
<path d="M9 10.76a2 2 0 0 1-1.11 1.79l-1.78.9A2 2 0 0 0 5 15.24V17h14v-1.76a2 2 0 0 0-1.11-1.79l-1.78-.9A2 2 0 0 1 15 10.76V6a2 2 0 0 0-2-2h-2a2 2 0 0 0-2 2v4.76Z" />
|
|
583
|
+
</svg>
|
|
584
|
+
);
|
|
585
|
+
}
|