@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,730 @@
1
+ /**
2
+ * ProvisioningProgress - A visually striking progress indicator for workspace provisioning
3
+ *
4
+ * Design: Terminal-inspired with holographic accents, featuring a vertical stage timeline
5
+ * with animated connections, pulsing indicators, and a typewriter terminal output effect.
6
+ */
7
+ import React, { useState, useEffect, useMemo } from 'react';
8
+
9
+ export interface ProvisioningStage {
10
+ id: string;
11
+ name: string;
12
+ description: string;
13
+ estimatedSeconds: number;
14
+ icon: string;
15
+ }
16
+
17
+ export interface ProvisioningProgressProps {
18
+ /** Current stage ID from backend, or null if unknown */
19
+ currentStage?: string | null;
20
+ /** Whether provisioning has started */
21
+ isProvisioning: boolean;
22
+ /** Workspace name being provisioned */
23
+ workspaceName?: string;
24
+ /** Error message if provisioning failed */
25
+ error?: string | null;
26
+ /** Callback when user wants to cancel */
27
+ onCancel?: () => void;
28
+ }
29
+
30
+ const PROVISIONING_STAGES: ProvisioningStage[] = [
31
+ {
32
+ id: 'creating',
33
+ name: 'Initialize',
34
+ description: 'Creating workspace container',
35
+ estimatedSeconds: 5,
36
+ icon: '◈',
37
+ },
38
+ {
39
+ id: 'networking',
40
+ name: 'Network',
41
+ description: 'Configuring DNS & IP allocation',
42
+ estimatedSeconds: 8,
43
+ icon: '◇',
44
+ },
45
+ {
46
+ id: 'secrets',
47
+ name: 'Secure',
48
+ description: 'Encrypting credentials',
49
+ estimatedSeconds: 3,
50
+ icon: '◆',
51
+ },
52
+ {
53
+ id: 'machine',
54
+ name: 'Deploy',
55
+ description: 'Launching cloud instance',
56
+ estimatedSeconds: 25,
57
+ icon: '▣',
58
+ },
59
+ {
60
+ id: 'booting',
61
+ name: 'Boot',
62
+ description: 'Starting relay services',
63
+ estimatedSeconds: 20,
64
+ icon: '▢',
65
+ },
66
+ {
67
+ id: 'health',
68
+ name: 'Verify',
69
+ description: 'Running health checks',
70
+ estimatedSeconds: 15,
71
+ icon: '◉',
72
+ },
73
+ ];
74
+
75
+ // Terminal-style loading messages
76
+ const TERMINAL_MESSAGES = [
77
+ '> Establishing secure connection...',
78
+ '> Allocating compute resources...',
79
+ '> Configuring agent protocols...',
80
+ '> Initializing relay daemon...',
81
+ '> Syncing workspace state...',
82
+ '> Warming up inference engine...',
83
+ '> Connecting to neural mesh...',
84
+ '> Deploying agent swarm...',
85
+ ];
86
+
87
+ export function ProvisioningProgress({
88
+ currentStage,
89
+ isProvisioning,
90
+ workspaceName,
91
+ error,
92
+ onCancel,
93
+ }: ProvisioningProgressProps) {
94
+ const [elapsedSeconds, setElapsedSeconds] = useState(0);
95
+ const [terminalLines, setTerminalLines] = useState<string[]>([]);
96
+ const [cursorVisible, setCursorVisible] = useState(true);
97
+
98
+ // Track elapsed time
99
+ useEffect(() => {
100
+ if (!isProvisioning) {
101
+ setElapsedSeconds(0);
102
+ return;
103
+ }
104
+ const interval = setInterval(() => {
105
+ setElapsedSeconds((prev) => prev + 1);
106
+ }, 1000);
107
+ return () => clearInterval(interval);
108
+ }, [isProvisioning]);
109
+
110
+ // Cursor blink
111
+ useEffect(() => {
112
+ const interval = setInterval(() => {
113
+ setCursorVisible((prev) => !prev);
114
+ }, 530);
115
+ return () => clearInterval(interval);
116
+ }, []);
117
+
118
+ // Add terminal messages over time
119
+ useEffect(() => {
120
+ if (!isProvisioning) {
121
+ setTerminalLines([]);
122
+ return;
123
+ }
124
+
125
+ const addMessage = () => {
126
+ const randomMsg = TERMINAL_MESSAGES[Math.floor(Math.random() * TERMINAL_MESSAGES.length)];
127
+ setTerminalLines((prev) => [...prev.slice(-4), randomMsg]);
128
+ };
129
+
130
+ addMessage(); // Initial message
131
+ const interval = setInterval(addMessage, 3500);
132
+ return () => clearInterval(interval);
133
+ }, [isProvisioning]);
134
+
135
+ // Calculate current stage index
136
+ const currentStageIndex = useMemo(() => {
137
+ if (currentStage) {
138
+ const idx = PROVISIONING_STAGES.findIndex((s) => s.id === currentStage);
139
+ return idx >= 0 ? idx : 0;
140
+ }
141
+ // Estimate based on elapsed time
142
+ let accumulated = 0;
143
+ for (let i = 0; i < PROVISIONING_STAGES.length; i++) {
144
+ accumulated += PROVISIONING_STAGES[i].estimatedSeconds;
145
+ if (elapsedSeconds < accumulated) return i;
146
+ }
147
+ return PROVISIONING_STAGES.length - 1;
148
+ }, [currentStage, elapsedSeconds]);
149
+
150
+ // Calculate progress
151
+ const totalEstimatedSeconds = useMemo(
152
+ () => PROVISIONING_STAGES.reduce((sum, s) => sum + s.estimatedSeconds, 0),
153
+ []
154
+ );
155
+
156
+ const progressPercent = useMemo(() => {
157
+ return Math.min(95, Math.round((elapsedSeconds / totalEstimatedSeconds) * 100));
158
+ }, [elapsedSeconds, totalEstimatedSeconds]);
159
+
160
+ const formatTime = (seconds: number) => {
161
+ const mins = Math.floor(seconds / 60);
162
+ const secs = seconds % 60;
163
+ return mins > 0 ? `${mins}:${secs.toString().padStart(2, '0')}` : `0:${secs.toString().padStart(2, '0')}`;
164
+ };
165
+
166
+ if (error) {
167
+ return (
168
+ <div className="prov-container prov-error">
169
+ <div className="error-glitch">
170
+ <span className="error-icon">✕</span>
171
+ </div>
172
+ <h3 className="error-title">PROVISIONING FAILED</h3>
173
+ <p className="error-message">{error}</p>
174
+ {onCancel && (
175
+ <button onClick={onCancel} className="retry-btn">
176
+ <span>RETRY</span>
177
+ </button>
178
+ )}
179
+ <style>{errorStyles}</style>
180
+ </div>
181
+ );
182
+ }
183
+
184
+ return (
185
+ <div className="prov-container">
186
+ {/* Ambient background effects */}
187
+ <div className="ambient-glow" />
188
+ <div className="scan-line" />
189
+
190
+ {/* Header */}
191
+ <header className="prov-header">
192
+ <div className="header-badge">PROVISIONING</div>
193
+ <h1 className="header-title">
194
+ {workspaceName || 'Workspace'}
195
+ </h1>
196
+ <div className="header-meta">
197
+ <span className="meta-time">{formatTime(elapsedSeconds)}</span>
198
+ <span className="meta-sep">•</span>
199
+ <span className="meta-percent">{progressPercent}%</span>
200
+ </div>
201
+ </header>
202
+
203
+ {/* Progress bar */}
204
+ <div className="progress-track">
205
+ <div
206
+ className="progress-fill"
207
+ style={{ width: `${progressPercent}%` }}
208
+ />
209
+ <div
210
+ className="progress-glow"
211
+ style={{ left: `${progressPercent}%` }}
212
+ />
213
+ </div>
214
+
215
+ {/* Stage timeline */}
216
+ <div className="stages-timeline">
217
+ {PROVISIONING_STAGES.map((stage, index) => {
218
+ const isCompleted = index < currentStageIndex;
219
+ const isCurrent = index === currentStageIndex;
220
+ const isPending = index > currentStageIndex;
221
+
222
+ return (
223
+ <div
224
+ key={stage.id}
225
+ className={`stage-row ${isCompleted ? 'completed' : ''} ${isCurrent ? 'current' : ''} ${isPending ? 'pending' : ''}`}
226
+ >
227
+ {/* Connector */}
228
+ {index > 0 && (
229
+ <div className={`stage-connector ${isCompleted ? 'active' : ''}`}>
230
+ <div className="connector-line" />
231
+ {isCompleted && <div className="connector-pulse" />}
232
+ </div>
233
+ )}
234
+
235
+ {/* Node */}
236
+ <div className="stage-node">
237
+ <span className="node-icon">{stage.icon}</span>
238
+ {isCurrent && <div className="node-ring" />}
239
+ </div>
240
+
241
+ {/* Content */}
242
+ <div className="stage-content">
243
+ <span className="stage-name">{stage.name}</span>
244
+ {isCurrent && (
245
+ <span className="stage-desc">{stage.description}</span>
246
+ )}
247
+ </div>
248
+
249
+ {/* Status */}
250
+ <div className="stage-status">
251
+ {isCompleted && <span className="status-done">DONE</span>}
252
+ {isCurrent && <span className="status-active">ACTIVE</span>}
253
+ {isPending && <span className="status-wait">~{stage.estimatedSeconds}s</span>}
254
+ </div>
255
+ </div>
256
+ );
257
+ })}
258
+ </div>
259
+
260
+ {/* Terminal output */}
261
+ <div className="terminal-window">
262
+ <div className="terminal-header">
263
+ <span className="terminal-dot red" />
264
+ <span className="terminal-dot yellow" />
265
+ <span className="terminal-dot green" />
266
+ <span className="terminal-title">agent-relay</span>
267
+ </div>
268
+ <div className="terminal-body">
269
+ {terminalLines.map((line, i) => (
270
+ <div key={i} className="terminal-line" style={{ animationDelay: `${i * 0.1}s` }}>
271
+ {line}
272
+ </div>
273
+ ))}
274
+ <div className="terminal-cursor">
275
+ <span className="cursor-prompt">$</span>
276
+ <span className={`cursor-block ${cursorVisible ? 'visible' : ''}`}>_</span>
277
+ </div>
278
+ </div>
279
+ </div>
280
+
281
+ {/* Cancel button */}
282
+ {onCancel && (
283
+ <button onClick={onCancel} className="cancel-btn">
284
+ Cancel
285
+ </button>
286
+ )}
287
+
288
+ <style>{mainStyles}</style>
289
+ </div>
290
+ );
291
+ }
292
+
293
+ const mainStyles = `
294
+ .prov-container {
295
+ position: relative;
296
+ display: flex;
297
+ flex-direction: column;
298
+ gap: 24px;
299
+ padding: 40px 32px;
300
+ background: linear-gradient(145deg, rgba(10, 15, 25, 0.95) 0%, rgba(5, 10, 18, 0.98) 100%);
301
+ border: 1px solid rgba(6, 182, 212, 0.15);
302
+ border-radius: 16px;
303
+ overflow: hidden;
304
+ font-family: 'SF Mono', 'JetBrains Mono', 'Fira Code', monospace;
305
+ }
306
+
307
+ /* Ambient effects */
308
+ .ambient-glow {
309
+ position: absolute;
310
+ top: -100px;
311
+ left: 50%;
312
+ transform: translateX(-50%);
313
+ width: 300px;
314
+ height: 200px;
315
+ background: radial-gradient(ellipse, rgba(6, 182, 212, 0.12) 0%, transparent 70%);
316
+ pointer-events: none;
317
+ }
318
+
319
+ .scan-line {
320
+ position: absolute;
321
+ top: 0;
322
+ left: 0;
323
+ right: 0;
324
+ height: 2px;
325
+ background: linear-gradient(90deg, transparent, rgba(6, 182, 212, 0.4), transparent);
326
+ animation: scanMove 3s ease-in-out infinite;
327
+ pointer-events: none;
328
+ }
329
+
330
+ @keyframes scanMove {
331
+ 0%, 100% { top: 0; opacity: 0.5; }
332
+ 50% { top: 100%; opacity: 0.2; }
333
+ }
334
+
335
+ /* Header */
336
+ .prov-header {
337
+ text-align: center;
338
+ position: relative;
339
+ z-index: 1;
340
+ }
341
+
342
+ .header-badge {
343
+ display: inline-block;
344
+ padding: 4px 12px;
345
+ background: rgba(6, 182, 212, 0.1);
346
+ border: 1px solid rgba(6, 182, 212, 0.3);
347
+ border-radius: 4px;
348
+ font-size: 10px;
349
+ font-weight: 600;
350
+ letter-spacing: 2px;
351
+ color: #06b6d4;
352
+ margin-bottom: 12px;
353
+ }
354
+
355
+ .header-title {
356
+ font-size: 22px;
357
+ font-weight: 600;
358
+ color: #f1f5f9;
359
+ margin: 0 0 8px 0;
360
+ letter-spacing: -0.5px;
361
+ }
362
+
363
+ .header-meta {
364
+ display: flex;
365
+ align-items: center;
366
+ justify-content: center;
367
+ gap: 8px;
368
+ font-size: 13px;
369
+ color: #64748b;
370
+ }
371
+
372
+ .meta-time {
373
+ font-variant-numeric: tabular-nums;
374
+ }
375
+
376
+ .meta-percent {
377
+ color: #06b6d4;
378
+ font-weight: 500;
379
+ }
380
+
381
+ .meta-sep {
382
+ opacity: 0.3;
383
+ }
384
+
385
+ /* Progress bar */
386
+ .progress-track {
387
+ position: relative;
388
+ height: 4px;
389
+ background: rgba(100, 116, 139, 0.2);
390
+ border-radius: 2px;
391
+ overflow: visible;
392
+ }
393
+
394
+ .progress-fill {
395
+ height: 100%;
396
+ background: linear-gradient(90deg, #0891b2, #06b6d4, #22d3ee);
397
+ border-radius: 2px;
398
+ transition: width 0.5s ease;
399
+ }
400
+
401
+ .progress-glow {
402
+ position: absolute;
403
+ top: 50%;
404
+ transform: translate(-50%, -50%);
405
+ width: 8px;
406
+ height: 8px;
407
+ background: #22d3ee;
408
+ border-radius: 50%;
409
+ box-shadow: 0 0 16px rgba(34, 211, 238, 0.6);
410
+ transition: left 0.5s ease;
411
+ }
412
+
413
+ /* Stages */
414
+ .stages-timeline {
415
+ display: flex;
416
+ flex-direction: column;
417
+ gap: 0;
418
+ padding: 16px 0;
419
+ }
420
+
421
+ .stage-row {
422
+ display: grid;
423
+ grid-template-columns: 40px 1fr auto;
424
+ align-items: center;
425
+ gap: 12px;
426
+ padding: 10px 0;
427
+ position: relative;
428
+ }
429
+
430
+ .stage-connector {
431
+ position: absolute;
432
+ left: 19px;
433
+ top: -10px;
434
+ width: 2px;
435
+ height: 20px;
436
+ }
437
+
438
+ .connector-line {
439
+ width: 100%;
440
+ height: 100%;
441
+ background: rgba(100, 116, 139, 0.3);
442
+ transition: background 0.3s ease;
443
+ }
444
+
445
+ .stage-connector.active .connector-line {
446
+ background: linear-gradient(180deg, #06b6d4, rgba(6, 182, 212, 0.3));
447
+ }
448
+
449
+ .connector-pulse {
450
+ position: absolute;
451
+ top: 0;
452
+ left: 0;
453
+ width: 100%;
454
+ height: 100%;
455
+ background: linear-gradient(180deg, rgba(34, 211, 238, 0.8), transparent);
456
+ animation: pulseLine 1.5s ease-out infinite;
457
+ }
458
+
459
+ @keyframes pulseLine {
460
+ 0% { opacity: 1; transform: translateY(-100%); }
461
+ 100% { opacity: 0; transform: translateY(100%); }
462
+ }
463
+
464
+ .stage-node {
465
+ width: 40px;
466
+ height: 40px;
467
+ display: flex;
468
+ align-items: center;
469
+ justify-content: center;
470
+ position: relative;
471
+ }
472
+
473
+ .node-icon {
474
+ font-size: 18px;
475
+ color: #475569;
476
+ transition: all 0.3s ease;
477
+ }
478
+
479
+ .stage-row.completed .node-icon {
480
+ color: #06b6d4;
481
+ }
482
+
483
+ .stage-row.current .node-icon {
484
+ color: #22d3ee;
485
+ text-shadow: 0 0 12px rgba(34, 211, 238, 0.5);
486
+ }
487
+
488
+ .node-ring {
489
+ position: absolute;
490
+ inset: 4px;
491
+ border: 2px solid rgba(34, 211, 238, 0.4);
492
+ border-radius: 50%;
493
+ animation: ringPulse 2s ease-in-out infinite;
494
+ }
495
+
496
+ @keyframes ringPulse {
497
+ 0%, 100% { transform: scale(1); opacity: 1; }
498
+ 50% { transform: scale(1.2); opacity: 0.5; }
499
+ }
500
+
501
+ .stage-content {
502
+ display: flex;
503
+ flex-direction: column;
504
+ gap: 2px;
505
+ min-width: 0;
506
+ }
507
+
508
+ .stage-name {
509
+ font-size: 13px;
510
+ font-weight: 500;
511
+ color: #64748b;
512
+ text-transform: uppercase;
513
+ letter-spacing: 0.5px;
514
+ transition: color 0.3s ease;
515
+ }
516
+
517
+ .stage-row.completed .stage-name {
518
+ color: #475569;
519
+ }
520
+
521
+ .stage-row.current .stage-name {
522
+ color: #f1f5f9;
523
+ }
524
+
525
+ .stage-desc {
526
+ font-size: 11px;
527
+ color: #64748b;
528
+ animation: fadeSlideIn 0.3s ease;
529
+ }
530
+
531
+ @keyframes fadeSlideIn {
532
+ from { opacity: 0; transform: translateX(-8px); }
533
+ to { opacity: 1; transform: translateX(0); }
534
+ }
535
+
536
+ .stage-status {
537
+ font-size: 10px;
538
+ font-weight: 600;
539
+ letter-spacing: 1px;
540
+ }
541
+
542
+ .status-done {
543
+ color: #06b6d4;
544
+ }
545
+
546
+ .status-active {
547
+ color: #22d3ee;
548
+ animation: blink 1s ease-in-out infinite;
549
+ }
550
+
551
+ @keyframes blink {
552
+ 0%, 100% { opacity: 1; }
553
+ 50% { opacity: 0.5; }
554
+ }
555
+
556
+ .status-wait {
557
+ color: #475569;
558
+ font-variant-numeric: tabular-nums;
559
+ }
560
+
561
+ /* Terminal */
562
+ .terminal-window {
563
+ background: rgba(0, 0, 0, 0.4);
564
+ border: 1px solid rgba(100, 116, 139, 0.2);
565
+ border-radius: 8px;
566
+ overflow: hidden;
567
+ }
568
+
569
+ .terminal-header {
570
+ display: flex;
571
+ align-items: center;
572
+ gap: 6px;
573
+ padding: 8px 12px;
574
+ background: rgba(30, 41, 59, 0.5);
575
+ border-bottom: 1px solid rgba(100, 116, 139, 0.15);
576
+ }
577
+
578
+ .terminal-dot {
579
+ width: 10px;
580
+ height: 10px;
581
+ border-radius: 50%;
582
+ }
583
+
584
+ .terminal-dot.red { background: #ef4444; }
585
+ .terminal-dot.yellow { background: #eab308; }
586
+ .terminal-dot.green { background: #22c55e; }
587
+
588
+ .terminal-title {
589
+ margin-left: auto;
590
+ font-size: 11px;
591
+ color: #64748b;
592
+ }
593
+
594
+ .terminal-body {
595
+ padding: 12px;
596
+ min-height: 100px;
597
+ }
598
+
599
+ .terminal-line {
600
+ font-size: 12px;
601
+ color: #94a3b8;
602
+ padding: 2px 0;
603
+ animation: typeIn 0.3s ease;
604
+ }
605
+
606
+ @keyframes typeIn {
607
+ from { opacity: 0; transform: translateY(4px); }
608
+ to { opacity: 1; transform: translateY(0); }
609
+ }
610
+
611
+ .terminal-cursor {
612
+ display: flex;
613
+ align-items: center;
614
+ gap: 4px;
615
+ margin-top: 8px;
616
+ }
617
+
618
+ .cursor-prompt {
619
+ color: #06b6d4;
620
+ font-weight: 600;
621
+ }
622
+
623
+ .cursor-block {
624
+ color: #22d3ee;
625
+ opacity: 0;
626
+ transition: opacity 0.1s;
627
+ }
628
+
629
+ .cursor-block.visible {
630
+ opacity: 1;
631
+ }
632
+
633
+ /* Cancel button */
634
+ .cancel-btn {
635
+ align-self: center;
636
+ padding: 8px 20px;
637
+ background: transparent;
638
+ border: 1px solid rgba(100, 116, 139, 0.3);
639
+ border-radius: 6px;
640
+ color: #64748b;
641
+ font-family: inherit;
642
+ font-size: 12px;
643
+ cursor: pointer;
644
+ transition: all 0.2s ease;
645
+ }
646
+
647
+ .cancel-btn:hover {
648
+ border-color: rgba(239, 68, 68, 0.5);
649
+ color: #ef4444;
650
+ }
651
+ `;
652
+
653
+ const errorStyles = `
654
+ .prov-container.prov-error {
655
+ display: flex;
656
+ flex-direction: column;
657
+ align-items: center;
658
+ gap: 16px;
659
+ padding: 48px 32px;
660
+ background: linear-gradient(145deg, rgba(25, 10, 10, 0.95) 0%, rgba(15, 5, 8, 0.98) 100%);
661
+ border: 1px solid rgba(239, 68, 68, 0.2);
662
+ border-radius: 16px;
663
+ text-align: center;
664
+ font-family: 'SF Mono', 'JetBrains Mono', monospace;
665
+ }
666
+
667
+ .error-glitch {
668
+ position: relative;
669
+ width: 64px;
670
+ height: 64px;
671
+ display: flex;
672
+ align-items: center;
673
+ justify-content: center;
674
+ background: rgba(239, 68, 68, 0.1);
675
+ border: 1px solid rgba(239, 68, 68, 0.3);
676
+ border-radius: 12px;
677
+ }
678
+
679
+ .error-icon {
680
+ font-size: 28px;
681
+ color: #ef4444;
682
+ animation: glitch 0.3s ease infinite;
683
+ }
684
+
685
+ @keyframes glitch {
686
+ 0%, 100% { transform: translate(0); }
687
+ 25% { transform: translate(-2px, 1px); }
688
+ 50% { transform: translate(2px, -1px); }
689
+ 75% { transform: translate(-1px, -1px); }
690
+ }
691
+
692
+ .error-title {
693
+ font-size: 14px;
694
+ font-weight: 600;
695
+ letter-spacing: 2px;
696
+ color: #ef4444;
697
+ margin: 0;
698
+ }
699
+
700
+ .error-message {
701
+ font-size: 13px;
702
+ color: #94a3b8;
703
+ max-width: 350px;
704
+ margin: 0;
705
+ line-height: 1.5;
706
+ }
707
+
708
+ .retry-btn {
709
+ margin-top: 8px;
710
+ padding: 10px 28px;
711
+ background: linear-gradient(135deg, rgba(239, 68, 68, 0.2) 0%, rgba(220, 38, 38, 0.2) 100%);
712
+ border: 1px solid rgba(239, 68, 68, 0.4);
713
+ border-radius: 6px;
714
+ color: #ef4444;
715
+ font-family: inherit;
716
+ font-size: 12px;
717
+ font-weight: 600;
718
+ letter-spacing: 1px;
719
+ cursor: pointer;
720
+ transition: all 0.2s ease;
721
+ }
722
+
723
+ .retry-btn:hover {
724
+ background: linear-gradient(135deg, rgba(239, 68, 68, 0.3) 0%, rgba(220, 38, 38, 0.3) 100%);
725
+ border-color: rgba(239, 68, 68, 0.6);
726
+ transform: translateY(-1px);
727
+ }
728
+ `;
729
+
730
+ export default ProvisioningProgress;