@agent-relay/dashboard 2.0.81 → 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.
Files changed (244) hide show
  1. package/out/404.html +1 -1
  2. package/out/_next/static/chunks/{118-4c8241b0218335de.js → 118-ae2b650136a5a5fc.js} +1 -1
  3. package/out/_next/static/chunks/407-0c82986cf79c8ecb.js +1 -0
  4. package/out/_next/static/chunks/app/app/[[...slug]]/{page-1e81c047cff17212.js → page-f7eca1b66fb4249b.js} +1 -1
  5. package/out/_next/static/chunks/app/{page-6892fe2dd07fb48b.js → page-0ee604f7070d14c0.js} +1 -1
  6. package/out/_next/static/css/8968d98ed4c4d33f.css +1 -0
  7. package/out/about.html +2 -2
  8. package/out/about.txt +1 -1
  9. package/out/app/onboarding.html +1 -1
  10. package/out/app/onboarding.txt +1 -1
  11. package/out/app.html +1 -1
  12. package/out/app.txt +2 -2
  13. package/out/blog/go-to-bed-wake-up-to-a-finished-product.html +2 -2
  14. package/out/blog/go-to-bed-wake-up-to-a-finished-product.txt +1 -1
  15. package/out/blog/let-them-cook-multi-agent-orchestration.html +2 -2
  16. package/out/blog/let-them-cook-multi-agent-orchestration.txt +2 -2
  17. package/out/blog.html +2 -2
  18. package/out/blog.txt +1 -1
  19. package/out/careers.html +2 -2
  20. package/out/careers.txt +1 -1
  21. package/out/changelog.html +2 -2
  22. package/out/changelog.txt +1 -1
  23. package/out/cloud/link.html +1 -1
  24. package/out/cloud/link.txt +2 -2
  25. package/out/complete-profile.html +2 -2
  26. package/out/complete-profile.txt +1 -1
  27. package/out/connect-repos.html +1 -1
  28. package/out/connect-repos.txt +1 -1
  29. package/out/contact.html +2 -2
  30. package/out/contact.txt +1 -1
  31. package/out/docs.html +2 -2
  32. package/out/docs.txt +1 -1
  33. package/out/history.html +1 -1
  34. package/out/history.txt +2 -2
  35. package/out/index.html +1 -1
  36. package/out/index.txt +2 -2
  37. package/out/login.html +2 -2
  38. package/out/login.txt +1 -1
  39. package/out/metrics.html +1 -1
  40. package/out/metrics.txt +2 -2
  41. package/out/pricing.html +2 -2
  42. package/out/pricing.txt +1 -1
  43. package/out/privacy.html +2 -2
  44. package/out/privacy.txt +1 -1
  45. package/out/providers/setup/claude.html +1 -1
  46. package/out/providers/setup/claude.txt +1 -1
  47. package/out/providers/setup/codex.html +1 -1
  48. package/out/providers/setup/codex.txt +1 -1
  49. package/out/providers/setup/cursor.html +1 -1
  50. package/out/providers/setup/cursor.txt +1 -1
  51. package/out/providers.html +1 -1
  52. package/out/providers.txt +1 -1
  53. package/out/security.html +2 -2
  54. package/out/security.txt +1 -1
  55. package/out/signup.html +2 -2
  56. package/out/signup.txt +1 -1
  57. package/out/terms.html +2 -2
  58. package/out/terms.txt +1 -1
  59. package/package.json +7 -1
  60. package/src/app/about/page.tsx +7 -0
  61. package/src/app/app/[[...slug]]/DashboardPageClient.tsx +853 -0
  62. package/src/app/app/[[...slug]]/page.tsx +23 -0
  63. package/src/app/app/onboarding/page.tsx +394 -0
  64. package/src/app/apple-icon.png +0 -0
  65. package/src/app/blog/go-to-bed-wake-up-to-a-finished-product/page.tsx +88 -0
  66. package/src/app/blog/let-them-cook-multi-agent-orchestration/page.tsx +93 -0
  67. package/src/app/blog/page.tsx +15 -0
  68. package/src/app/careers/page.tsx +7 -0
  69. package/src/app/changelog/page.tsx +7 -0
  70. package/src/app/cloud/link/page.tsx +464 -0
  71. package/src/app/complete-profile/page.tsx +204 -0
  72. package/src/app/connect-repos/page.tsx +410 -0
  73. package/src/app/contact/page.tsx +7 -0
  74. package/src/app/docs/page.tsx +7 -0
  75. package/src/app/favicon.png +0 -0
  76. package/src/app/globals.css +200 -0
  77. package/src/app/history/page.tsx +658 -0
  78. package/src/app/layout.tsx +25 -0
  79. package/src/app/login/page.tsx +424 -0
  80. package/src/app/metrics/page.tsx +781 -0
  81. package/src/app/page.tsx +59 -0
  82. package/src/app/pricing/page.tsx +7 -0
  83. package/src/app/privacy/page.tsx +7 -0
  84. package/src/app/providers/page.tsx +193 -0
  85. package/src/app/providers/setup/[provider]/ProviderSetupClient.tsx +197 -0
  86. package/src/app/providers/setup/[provider]/constants.ts +35 -0
  87. package/src/app/providers/setup/[provider]/page.tsx +42 -0
  88. package/src/app/security/page.tsx +7 -0
  89. package/src/app/signup/page.tsx +533 -0
  90. package/src/app/terms/page.tsx +7 -0
  91. package/src/components/ActivityFeed.tsx +216 -0
  92. package/src/components/AddWorkspaceModal.tsx +170 -0
  93. package/src/components/AgentCard.test.tsx +134 -0
  94. package/src/components/AgentCard.tsx +585 -0
  95. package/src/components/AgentList.test.tsx +147 -0
  96. package/src/components/AgentList.tsx +419 -0
  97. package/src/components/AgentLogPreview.tsx +173 -0
  98. package/src/components/AgentProfilePanel.tsx +569 -0
  99. package/src/components/App.tsx +3424 -0
  100. package/src/components/BillingPanel.tsx +922 -0
  101. package/src/components/BillingResult.tsx +447 -0
  102. package/src/components/BroadcastComposer.tsx +690 -0
  103. package/src/components/ChannelAdminPanel.tsx +773 -0
  104. package/src/components/ChannelBrowser.tsx +385 -0
  105. package/src/components/ChannelChat.tsx +261 -0
  106. package/src/components/ChannelSidebar.tsx +399 -0
  107. package/src/components/CloudSessionProvider.tsx +130 -0
  108. package/src/components/CommandPalette.tsx +815 -0
  109. package/src/components/ConfirmationDialog.tsx +133 -0
  110. package/src/components/ConversationHistory.tsx +518 -0
  111. package/src/components/CoordinatorPanel.tsx +956 -0
  112. package/src/components/DecisionQueue.tsx +717 -0
  113. package/src/components/DirectMessageView.tsx +164 -0
  114. package/src/components/FileAutocomplete.tsx +368 -0
  115. package/src/components/FleetOverview.tsx +278 -0
  116. package/src/components/LogViewer.tsx +310 -0
  117. package/src/components/LogViewerPanel.tsx +482 -0
  118. package/src/components/Logo.tsx +284 -0
  119. package/src/components/MentionAutocomplete.tsx +384 -0
  120. package/src/components/MessageComposer.tsx +473 -0
  121. package/src/components/MessageList.tsx +725 -0
  122. package/src/components/MessageSenderName.tsx +91 -0
  123. package/src/components/MessageStatusIndicator.tsx +142 -0
  124. package/src/components/NewConversationModal.tsx +400 -0
  125. package/src/components/NotificationToast.tsx +488 -0
  126. package/src/components/OnlineUsersIndicator.tsx +164 -0
  127. package/src/components/Pagination.tsx +124 -0
  128. package/src/components/PricingPlans.tsx +386 -0
  129. package/src/components/ProjectList.tsx +711 -0
  130. package/src/components/ProviderAuthFlow.tsx +343 -0
  131. package/src/components/ProviderConnectionList.tsx +375 -0
  132. package/src/components/ProvisioningProgress.tsx +730 -0
  133. package/src/components/ReactionChips.tsx +70 -0
  134. package/src/components/ReactionPicker.tsx +121 -0
  135. package/src/components/RepoAccessPanel.tsx +787 -0
  136. package/src/components/RepositoriesPanel.tsx +901 -0
  137. package/src/components/ServerCard.tsx +202 -0
  138. package/src/components/SessionExpiredModal.tsx +128 -0
  139. package/src/components/SpawnModal.test.tsx +190 -0
  140. package/src/components/SpawnModal.tsx +1001 -0
  141. package/src/components/TaskAssignmentUI.tsx +375 -0
  142. package/src/components/TerminalProviderSetup.tsx +517 -0
  143. package/src/components/ThemeProvider.tsx +159 -0
  144. package/src/components/ThinkingIndicator.tsx +231 -0
  145. package/src/components/ThreadList.tsx +198 -0
  146. package/src/components/ThreadPanel.tsx +405 -0
  147. package/src/components/TrajectoryViewer.tsx +698 -0
  148. package/src/components/TypingIndicator.tsx +69 -0
  149. package/src/components/UsageBanner.tsx +231 -0
  150. package/src/components/UserProfilePanel.tsx +233 -0
  151. package/src/components/WorkspaceContext.tsx +95 -0
  152. package/src/components/WorkspaceSelector.tsx +234 -0
  153. package/src/components/WorkspaceStatusIndicator.tsx +396 -0
  154. package/src/components/XTermInteractive.tsx +516 -0
  155. package/src/components/XTermLogViewer.tsx +719 -0
  156. package/src/components/channels/ChannelDialogs.tsx +1411 -0
  157. package/src/components/channels/ChannelHeader.tsx +317 -0
  158. package/src/components/channels/ChannelMessageList.tsx +463 -0
  159. package/src/components/channels/ChannelViewV1.tsx +146 -0
  160. package/src/components/channels/MessageInput.tsx +302 -0
  161. package/src/components/channels/SearchInput.tsx +172 -0
  162. package/src/components/channels/SearchResults.tsx +336 -0
  163. package/src/components/channels/api.test.ts +1527 -0
  164. package/src/components/channels/api.ts +703 -0
  165. package/src/components/channels/index.ts +76 -0
  166. package/src/components/channels/mockApi.ts +344 -0
  167. package/src/components/channels/types.ts +566 -0
  168. package/src/components/hooks/index.ts +58 -0
  169. package/src/components/hooks/useAgentLogs.ts +504 -0
  170. package/src/components/hooks/useAgents.ts +127 -0
  171. package/src/components/hooks/useBroadcastDedup.test.ts +371 -0
  172. package/src/components/hooks/useBroadcastDedup.ts +86 -0
  173. package/src/components/hooks/useChannelAdmin.ts +329 -0
  174. package/src/components/hooks/useChannelBrowser.ts +239 -0
  175. package/src/components/hooks/useChannelCommands.ts +138 -0
  176. package/src/components/hooks/useChannels.ts +367 -0
  177. package/src/components/hooks/useDebounce.ts +29 -0
  178. package/src/components/hooks/useDirectMessage.test.ts +952 -0
  179. package/src/components/hooks/useDirectMessage.ts +141 -0
  180. package/src/components/hooks/useMessages.ts +310 -0
  181. package/src/components/hooks/useOrchestrator.test.ts +165 -0
  182. package/src/components/hooks/useOrchestrator.ts +424 -0
  183. package/src/components/hooks/usePinnedAgents.test.ts +356 -0
  184. package/src/components/hooks/usePinnedAgents.ts +140 -0
  185. package/src/components/hooks/usePresence.test.ts +245 -0
  186. package/src/components/hooks/usePresence.ts +377 -0
  187. package/src/components/hooks/useRecentRepos.ts +130 -0
  188. package/src/components/hooks/useSession.ts +209 -0
  189. package/src/components/hooks/useThread.ts +138 -0
  190. package/src/components/hooks/useTrajectory.ts +265 -0
  191. package/src/components/hooks/useWebSocket.ts +290 -0
  192. package/src/components/hooks/useWorkspaceMembers.ts +132 -0
  193. package/src/components/hooks/useWorkspaceRepos.ts +73 -0
  194. package/src/components/hooks/useWorkspaceStatus.ts +237 -0
  195. package/src/components/index.ts +81 -0
  196. package/src/components/layout/Header.tsx +311 -0
  197. package/src/components/layout/RepoContextHeader.tsx +361 -0
  198. package/src/components/layout/Sidebar.archive.test.tsx +126 -0
  199. package/src/components/layout/Sidebar.test.tsx +691 -0
  200. package/src/components/layout/Sidebar.tsx +900 -0
  201. package/src/components/layout/index.ts +7 -0
  202. package/src/components/settings/BillingSettingsPanel.tsx +564 -0
  203. package/src/components/settings/SettingsPage.tsx +683 -0
  204. package/src/components/settings/TeamSettingsPanel.tsx +560 -0
  205. package/src/components/settings/WorkspaceSettingsPanel.tsx +1368 -0
  206. package/src/components/settings/index.ts +11 -0
  207. package/src/components/settings/types.ts +79 -0
  208. package/src/components/utils/messageFormatting.test.tsx +331 -0
  209. package/src/components/utils/messageFormatting.tsx +597 -0
  210. package/src/index.ts +63 -0
  211. package/src/landing/AboutPage.tsx +77 -0
  212. package/src/landing/BlogContent.tsx +187 -0
  213. package/src/landing/BlogPage.tsx +47 -0
  214. package/src/landing/CareersPage.tsx +53 -0
  215. package/src/landing/ChangelogPage.tsx +33 -0
  216. package/src/landing/ContactPage.tsx +41 -0
  217. package/src/landing/DocsPage.tsx +43 -0
  218. package/src/landing/LandingPage.tsx +702 -0
  219. package/src/landing/PricingPage.tsx +549 -0
  220. package/src/landing/PrivacyPage.tsx +117 -0
  221. package/src/landing/SecurityPage.tsx +42 -0
  222. package/src/landing/StaticPage.tsx +165 -0
  223. package/src/landing/TermsPage.tsx +125 -0
  224. package/src/landing/blogData.ts +312 -0
  225. package/src/landing/index.ts +18 -0
  226. package/src/landing/styles.css +3673 -0
  227. package/src/lib/agent-merge.test.ts +43 -0
  228. package/src/lib/agent-merge.ts +35 -0
  229. package/src/lib/api.ts +1294 -0
  230. package/src/lib/cloudApi.ts +893 -0
  231. package/src/lib/colors.test.ts +175 -0
  232. package/src/lib/colors.ts +218 -0
  233. package/src/lib/config.ts +109 -0
  234. package/src/lib/hierarchy.ts +242 -0
  235. package/src/lib/stuckDetection.ts +142 -0
  236. package/src/lib/useUrlRouting.ts +190 -0
  237. package/src/types/index.ts +317 -0
  238. package/src/types/threading.ts +7 -0
  239. package/out/_next/static/chunks/285-dc644487a8d6500d.js +0 -1
  240. package/out/_next/static/css/4c58d9cf493aa626.css +0 -1
  241. /package/out/_next/static/{dYlczDQI12PIQ3tqq3N4Y → IxfA6RZu4trcsEMYlkQra}/_buildManifest.js +0 -0
  242. /package/out/_next/static/{dYlczDQI12PIQ3tqq3N4Y → IxfA6RZu4trcsEMYlkQra}/_ssgManifest.js +0 -0
  243. /package/out/_next/static/chunks/{528-d375bc8b46912d2c.js → 528-f5f676996d613c25.js} +0 -0
  244. /package/out/_next/static/chunks/app/blog/let-them-cook-multi-agent-orchestration/{page-a58308f43557b908.js → page-b194f207fbd91862.js} +0 -0
@@ -0,0 +1,375 @@
1
+ /**
2
+ * ProviderConnectionList - Shared component for AI provider connection UI
3
+ *
4
+ * Used by both /app (onboarding) and /providers pages to ensure consistent UX.
5
+ * Handles Claude (terminal), Codex (CLI-assisted), and other providers.
6
+ */
7
+
8
+ import React, { useState, useCallback } from 'react';
9
+ import { TerminalProviderSetup } from './TerminalProviderSetup';
10
+ import { ProviderAuthFlow } from './ProviderAuthFlow';
11
+
12
+ export interface ProviderInfo {
13
+ id: string;
14
+ name: string;
15
+ displayName: string;
16
+ color: string;
17
+ cliCommand?: string;
18
+ isConnected?: boolean;
19
+ description?: string;
20
+ /** For OAuth providers, whether they need URL copy (localhost callback) */
21
+ requiresUrlCopy?: boolean;
22
+ /** Provider is not yet fully tested/available */
23
+ comingSoon?: boolean;
24
+ }
25
+
26
+ // Provider auth configuration
27
+ const PROVIDER_AUTH_CONFIG: Record<string, {
28
+ authMethod: 'terminal' | 'oauth';
29
+ requiresUrlCopy?: boolean;
30
+ }> = {
31
+ anthropic: { authMethod: 'oauth', requiresUrlCopy: true },
32
+ codex: { authMethod: 'oauth', requiresUrlCopy: true },
33
+ openai: { authMethod: 'oauth', requiresUrlCopy: true },
34
+ // Gemini uses terminal - CLI shows interactive menu for OAuth vs API key
35
+ google: { authMethod: 'terminal' },
36
+ opencode: { authMethod: 'terminal' },
37
+ droid: { authMethod: 'terminal' },
38
+ cursor: { authMethod: 'oauth', requiresUrlCopy: true },
39
+ };
40
+
41
+ export interface ProviderConnectionListProps {
42
+ providers: ProviderInfo[];
43
+ connectedProviders: string[];
44
+ workspaceId: string;
45
+ csrfToken?: string;
46
+ onProviderConnected: (providerId: string) => void;
47
+ onConnectAnother?: () => void;
48
+ onContinue?: () => void;
49
+ /** Show expanded info sections for Claude/Codex */
50
+ showDetailedInfo?: boolean;
51
+ }
52
+
53
+ export function ProviderConnectionList({
54
+ providers,
55
+ connectedProviders,
56
+ workspaceId,
57
+ csrfToken,
58
+ onProviderConnected,
59
+ onConnectAnother,
60
+ onContinue,
61
+ showDetailedInfo = true,
62
+ }: ProviderConnectionListProps) {
63
+ const [connectingProvider, setConnectingProvider] = useState<string | null>(null);
64
+ const [connectionMode, setConnectionMode] = useState<'select' | 'terminal' | 'oauth'>('select');
65
+ const [error, setError] = useState<string | null>(null);
66
+
67
+ const handleConnectProvider = (provider: ProviderInfo) => {
68
+ const authConfig = PROVIDER_AUTH_CONFIG[provider.id];
69
+
70
+ if (authConfig?.authMethod === 'terminal') {
71
+ // Terminal-based setup (Claude, Cursor, etc.)
72
+ setConnectingProvider(provider.id);
73
+ setConnectionMode('terminal');
74
+ } else if (authConfig?.authMethod === 'oauth') {
75
+ // OAuth-based setup (Codex, etc.)
76
+ setConnectingProvider(provider.id);
77
+ setConnectionMode('oauth');
78
+ } else {
79
+ // Default to terminal
80
+ setConnectingProvider(provider.id);
81
+ setConnectionMode('terminal');
82
+ }
83
+ setError(null);
84
+ };
85
+
86
+ const handleSuccess = (providerId: string) => {
87
+ onProviderConnected(providerId);
88
+ setConnectingProvider(null);
89
+ setConnectionMode('select');
90
+ };
91
+
92
+ const handleCancel = () => {
93
+ setConnectingProvider(null);
94
+ setConnectionMode('select');
95
+ };
96
+
97
+ const handleError = (err: string) => {
98
+ setError(err);
99
+ setConnectingProvider(null);
100
+ setConnectionMode('select');
101
+ };
102
+
103
+ const isProviderConnected = (providerId: string) => {
104
+ // Handle openai/codex mapping
105
+ if (providerId === 'codex') {
106
+ return connectedProviders.includes('codex') || connectedProviders.includes('openai');
107
+ }
108
+ return connectedProviders.includes(providerId);
109
+ };
110
+
111
+ // If actively connecting, show the connection flow
112
+ if (connectingProvider && connectionMode !== 'select') {
113
+ const provider = providers.find(p => p.id === connectingProvider);
114
+ if (!provider) return null;
115
+
116
+ const authConfig = PROVIDER_AUTH_CONFIG[provider.id];
117
+
118
+ return (
119
+ <div className="bg-bg-primary/80 backdrop-blur-sm border border-border-subtle rounded-2xl p-6">
120
+ {/* Header */}
121
+ <div className="flex items-center gap-3 mb-4">
122
+ <div
123
+ className="w-10 h-10 rounded-lg flex items-center justify-center text-white font-bold"
124
+ style={{ backgroundColor: provider.color }}
125
+ >
126
+ {provider.displayName[0]}
127
+ </div>
128
+ <div>
129
+ <h3 className="text-lg font-semibold text-white">{provider.displayName} Setup</h3>
130
+ <p className="text-sm text-text-muted">
131
+ {connectionMode === 'terminal' ? 'Interactive terminal' : 'OAuth authentication'}
132
+ </p>
133
+ </div>
134
+ <button
135
+ onClick={handleCancel}
136
+ className="ml-auto p-2 text-text-muted hover:text-white transition-colors"
137
+ aria-label="Close"
138
+ >
139
+ <svg className="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
140
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
141
+ </svg>
142
+ </button>
143
+ </div>
144
+
145
+ {error && (
146
+ <div className="mb-4 p-3 bg-error/10 border border-error/20 rounded-lg">
147
+ <p className="text-error text-sm">{error}</p>
148
+ </div>
149
+ )}
150
+
151
+ {/* Terminal setup */}
152
+ {connectionMode === 'terminal' && (
153
+ <TerminalProviderSetup
154
+ provider={{
155
+ id: provider.cliCommand || provider.id,
156
+ name: provider.id,
157
+ displayName: provider.displayName,
158
+ color: provider.color,
159
+ }}
160
+ workspaceId={workspaceId}
161
+ csrfToken={csrfToken}
162
+ maxHeight="400px"
163
+ showHeader={false}
164
+ onSuccess={() => handleSuccess(provider.id)}
165
+ onCancel={handleCancel}
166
+ onConnectAnother={() => {
167
+ handleSuccess(provider.id);
168
+ onConnectAnother?.();
169
+ }}
170
+ onError={handleError}
171
+ />
172
+ )}
173
+
174
+ {/* OAuth setup */}
175
+ {connectionMode === 'oauth' && authConfig && (
176
+ <ProviderAuthFlow
177
+ provider={{
178
+ id: provider.id,
179
+ name: provider.cliCommand || provider.id,
180
+ displayName: provider.displayName,
181
+ color: provider.color,
182
+ requiresUrlCopy: authConfig.requiresUrlCopy,
183
+ }}
184
+ workspaceId={workspaceId}
185
+ csrfToken={csrfToken}
186
+ onSuccess={() => handleSuccess(provider.id)}
187
+ onCancel={handleCancel}
188
+ onError={handleError}
189
+ />
190
+ )}
191
+
192
+ {/* Back button */}
193
+ <button
194
+ onClick={handleCancel}
195
+ className="mt-4 text-sm text-text-muted hover:text-white transition-colors"
196
+ >
197
+ &larr; Back to provider list
198
+ </button>
199
+ </div>
200
+ );
201
+ }
202
+
203
+ // Show provider list
204
+ return (
205
+ <div className="bg-bg-primary/80 backdrop-blur-sm border border-border-subtle rounded-2xl p-6">
206
+ <h2 className="text-lg font-semibold text-white mb-4">Choose an AI Provider</h2>
207
+
208
+ {error && (
209
+ <div className="mb-4 p-3 bg-error/10 border border-error/20 rounded-lg">
210
+ <p className="text-error text-sm">{error}</p>
211
+ </div>
212
+ )}
213
+
214
+ <div className="space-y-3">
215
+ {providers.map((provider) => {
216
+ const connected = isProviderConnected(provider.id);
217
+ const authConfig = PROVIDER_AUTH_CONFIG[provider.id];
218
+ const isTerminal = authConfig?.authMethod === 'terminal';
219
+ const isOAuth = authConfig?.authMethod === 'oauth';
220
+
221
+ // Expanded card for Claude/Codex/Cursor when showDetailedInfo is true
222
+ if (showDetailedInfo && (provider.id === 'anthropic' || provider.id === 'codex' || provider.id === 'cursor')) {
223
+ return (
224
+ <div
225
+ key={provider.id}
226
+ className={`p-4 bg-bg-tertiary rounded-xl border space-y-4 ${
227
+ connected ? 'border-green-500/50' : 'border-border-subtle'
228
+ }`}
229
+ >
230
+ {/* Provider header */}
231
+ <div className="flex items-center gap-3">
232
+ <div
233
+ className="w-10 h-10 rounded-lg flex items-center justify-center text-white font-bold flex-shrink-0 relative"
234
+ style={{ backgroundColor: provider.color }}
235
+ >
236
+ {provider.displayName[0]}
237
+ {connected && (
238
+ <div className="absolute -top-1 -right-1 w-5 h-5 bg-green-500 rounded-full flex items-center justify-center">
239
+ <svg className="w-3 h-3 text-white" fill="none" viewBox="0 0 24 24" stroke="currentColor">
240
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={3} d="M5 13l4 4L19 7" />
241
+ </svg>
242
+ </div>
243
+ )}
244
+ </div>
245
+ <div className="flex-1">
246
+ <p className="text-white font-medium">{provider.displayName}</p>
247
+ <p className="text-text-muted text-sm">{provider.name}</p>
248
+ </div>
249
+ {connected && (
250
+ <span className="text-green-400 text-sm font-medium">Connected</span>
251
+ )}
252
+ </div>
253
+
254
+ {!connected && (
255
+ <>
256
+ {/* Info section */}
257
+ <div className="p-3 bg-accent-cyan/10 border border-accent-cyan/30 rounded-lg">
258
+ <p className="text-sm text-accent-cyan font-medium mb-1">
259
+ {isTerminal ? 'Interactive terminal setup' : 'CLI-assisted authentication'}
260
+ </p>
261
+ <p className="text-xs text-accent-cyan/80">
262
+ {isTerminal
263
+ ? `Connect ${provider.displayName} using an interactive terminal. You'll see the CLI start up and can complete the OAuth login directly in the terminal.`
264
+ : `${provider.displayName} auth uses a CLI command to capture the OAuth callback locally. Click the button below and we'll show you a command with a unique session token to run in your terminal.`
265
+ }
266
+ </p>
267
+ </div>
268
+
269
+ {/* Connect button */}
270
+ <button
271
+ onClick={() => handleConnectProvider(provider)}
272
+ className="w-full flex items-center justify-center gap-2 p-3 bg-gradient-to-r from-accent-cyan to-[#00b8d9] text-bg-deep font-semibold rounded-xl hover:shadow-glow-cyan transition-all"
273
+ >
274
+ <svg className="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
275
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M8 9l3 3-3 3m5 0h3M5 20h14a2 2 0 002-2V6a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" />
276
+ </svg>
277
+ Connect with {provider.displayName}
278
+ </button>
279
+
280
+ </>
281
+ )}
282
+ </div>
283
+ );
284
+ }
285
+
286
+ // Standard provider button
287
+ return (
288
+ <button
289
+ key={provider.id}
290
+ onClick={() => !connected && !provider.comingSoon && handleConnectProvider(provider)}
291
+ disabled={connected || provider.comingSoon}
292
+ className={`w-full flex items-center gap-3 p-4 bg-bg-tertiary rounded-xl border transition-colors text-left ${
293
+ provider.comingSoon
294
+ ? 'border-border-subtle opacity-60 cursor-not-allowed'
295
+ : connected
296
+ ? 'border-green-500/50 cursor-default'
297
+ : 'border-border-subtle hover:border-accent-cyan/50'
298
+ }`}
299
+ >
300
+ <div
301
+ className={`w-10 h-10 rounded-lg flex items-center justify-center text-white font-bold flex-shrink-0 relative ${
302
+ provider.comingSoon ? 'grayscale' : ''
303
+ }`}
304
+ style={{ backgroundColor: provider.color }}
305
+ >
306
+ {provider.displayName[0]}
307
+ {connected && (
308
+ <div className="absolute -top-1 -right-1 w-5 h-5 bg-green-500 rounded-full flex items-center justify-center">
309
+ <svg className="w-3 h-3 text-white" fill="none" viewBox="0 0 24 24" stroke="currentColor">
310
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={3} d="M5 13l4 4L19 7" />
311
+ </svg>
312
+ </div>
313
+ )}
314
+ </div>
315
+ <div className="flex-1">
316
+ <p className="text-white font-medium flex items-center gap-2">
317
+ {provider.displayName}
318
+ {provider.comingSoon && (
319
+ <span className="px-2 py-0.5 bg-amber-400/20 text-amber-400 text-xs font-medium rounded-full">
320
+ Coming Soon
321
+ </span>
322
+ )}
323
+ </p>
324
+ <p className="text-text-muted text-sm">{provider.description || provider.name}</p>
325
+ </div>
326
+ {provider.comingSoon ? (
327
+ <span className="text-text-muted text-sm">Not available yet</span>
328
+ ) : connected ? (
329
+ <span className="text-green-400 text-sm font-medium">Connected</span>
330
+ ) : (
331
+ <svg className="w-5 h-5 text-text-muted" fill="none" viewBox="0 0 24 24" stroke="currentColor">
332
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 5l7 7-7 7" />
333
+ </svg>
334
+ )}
335
+ </button>
336
+ );
337
+ })}
338
+ </div>
339
+
340
+ {/* Footer actions */}
341
+ {(onConnectAnother || onContinue) && connectedProviders.length > 0 && (
342
+ <div className="mt-6 pt-4 border-t border-border-subtle space-y-3">
343
+ {onConnectAnother && (
344
+ <button
345
+ onClick={onConnectAnother}
346
+ className="w-full py-3 px-4 bg-bg-tertiary border border-border-subtle text-white rounded-xl text-center hover:border-accent-cyan/50 transition-colors"
347
+ >
348
+ Connect Another Provider
349
+ </button>
350
+ )}
351
+ {onContinue && (
352
+ <button
353
+ onClick={onContinue}
354
+ className="w-full py-3 px-4 bg-gradient-to-r from-accent-cyan to-[#00b8d9] text-bg-deep font-semibold rounded-xl text-center hover:shadow-glow-cyan transition-all"
355
+ >
356
+ Continue to Dashboard
357
+ </button>
358
+ )}
359
+ </div>
360
+ )}
361
+
362
+ {/* Skip link when no providers connected */}
363
+ {connectedProviders.length === 0 && onContinue && (
364
+ <div className="mt-6 text-center">
365
+ <button
366
+ onClick={onContinue}
367
+ className="text-text-muted hover:text-white transition-colors text-sm"
368
+ >
369
+ Skip for now - I&apos;ll connect later
370
+ </button>
371
+ </div>
372
+ )}
373
+ </div>
374
+ );
375
+ }