@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.
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/{AqelRhy1vr2nBUcU0Iqcp → IxfA6RZu4trcsEMYlkQra}/_buildManifest.js +0 -0
  242. /package/out/_next/static/{AqelRhy1vr2nBUcU0Iqcp → 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,23 @@
1
+ /**
2
+ * Catch-all route for /app/* URLs (Server Component wrapper)
3
+ *
4
+ * Handles all /app routes including:
5
+ * - /app (base route)
6
+ * - /app/agent/Leader
7
+ * - /app/channel/general
8
+ * - /app/settings/workspace
9
+ *
10
+ * The actual routing is handled client-side by useUrlRouting hook.
11
+ */
12
+
13
+ import DashboardPageClient from './DashboardPageClient';
14
+
15
+ // Required for static export with optional catch-all routes
16
+ // Return one entry for the base /app route - subsequent routing is client-side
17
+ export function generateStaticParams() {
18
+ return [{ slug: undefined }];
19
+ }
20
+
21
+ export default function DashboardPage() {
22
+ return <DashboardPageClient />;
23
+ }
@@ -0,0 +1,394 @@
1
+ /**
2
+ * Onboarding Page - Dedicated route for new users and post-deletion flow
3
+ *
4
+ * This page provides a cleaner onboarding experience separate from workspace selection.
5
+ * It handles two scenarios:
6
+ * 1. First-time users with no workspaces
7
+ * 2. Users who just deleted their workspace
8
+ *
9
+ * URL params:
10
+ * - reason=deleted: User just deleted a workspace
11
+ * - reason=new: First-time user (default)
12
+ */
13
+
14
+ 'use client';
15
+
16
+ import React, { useState, useEffect, useCallback, Suspense } from 'react';
17
+ import { useSearchParams } from 'next/navigation';
18
+ import { LogoIcon } from '../../../components/Logo';
19
+
20
+ interface Repository {
21
+ id: string;
22
+ fullName: string;
23
+ isPrivate: boolean;
24
+ defaultBranch: string;
25
+ syncStatus: string;
26
+ hasNangoConnection: boolean;
27
+ }
28
+
29
+ type OnboardingReason = 'new' | 'deleted';
30
+
31
+ // Analytics event types for onboarding funnel
32
+ type OnboardingEvent =
33
+ | 'onboarding_page_view'
34
+ | 'onboarding_repo_selected'
35
+ | 'onboarding_workspace_created'
36
+ | 'onboarding_connect_repos_clicked'
37
+ | 'onboarding_skipped';
38
+
39
+ // Simple analytics hook - can be extended to integrate with actual analytics service
40
+ function useOnboardingAnalytics() {
41
+ const trackEvent = useCallback((event: OnboardingEvent, properties?: Record<string, unknown>) => {
42
+ // Log to console in development
43
+ if (process.env.NODE_ENV === 'development') {
44
+ console.log('[Onboarding Analytics]', event, properties);
45
+ }
46
+
47
+ // TODO: Integrate with actual analytics service (e.g., Posthog, Mixpanel, etc.)
48
+ // Example: posthog.capture(event, properties);
49
+
50
+ // For now, send to a hypothetical analytics endpoint
51
+ try {
52
+ fetch('/api/analytics/track', {
53
+ method: 'POST',
54
+ headers: { 'Content-Type': 'application/json' },
55
+ credentials: 'include',
56
+ body: JSON.stringify({ event, properties, timestamp: Date.now() }),
57
+ }).catch(() => {
58
+ // Silently fail - analytics should not block user experience
59
+ });
60
+ } catch {
61
+ // Silently fail
62
+ }
63
+ }, []);
64
+
65
+ return { trackEvent };
66
+ }
67
+
68
+ function OnboardingContent() {
69
+ const searchParams = useSearchParams();
70
+ const reason = (searchParams.get('reason') as OnboardingReason) || 'new';
71
+
72
+ const [repos, setRepos] = useState<Repository[]>([]);
73
+ const [isLoading, setIsLoading] = useState(true);
74
+ const [isCreating, setIsCreating] = useState(false);
75
+ const [error, setError] = useState<string | null>(null);
76
+ const [csrfToken, setCsrfToken] = useState<string | null>(null);
77
+
78
+ const { trackEvent } = useOnboardingAnalytics();
79
+
80
+ // Fetch repositories and check session
81
+ useEffect(() => {
82
+ const init = async () => {
83
+ try {
84
+ // Check session
85
+ const sessionRes = await fetch('/api/auth/session', { credentials: 'include' });
86
+
87
+ if (sessionRes.status === 404) {
88
+ // Local mode - redirect to main app
89
+ window.location.href = '/app';
90
+ return;
91
+ }
92
+
93
+ // Capture CSRF token
94
+ const token = sessionRes.headers.get('X-CSRF-Token');
95
+ if (token) {
96
+ setCsrfToken(token);
97
+ }
98
+
99
+ const session = await sessionRes.json();
100
+
101
+ if (!session.authenticated) {
102
+ window.location.href = '/login';
103
+ return;
104
+ }
105
+
106
+ // Check if user already has workspaces - if so, redirect to /app
107
+ const workspacesRes = await fetch('/api/workspaces', { credentials: 'include' });
108
+ if (workspacesRes.ok) {
109
+ const workspacesData = await workspacesRes.json();
110
+ if ((workspacesData.workspaces || []).length > 0) {
111
+ // User has workspaces, redirect to main app
112
+ window.location.href = '/app';
113
+ return;
114
+ }
115
+ }
116
+
117
+ // Fetch repos
118
+ const reposRes = await fetch('/api/github-app/repos', { credentials: 'include' });
119
+ if (reposRes.ok) {
120
+ const reposData = await reposRes.json();
121
+ setRepos(reposData.repositories || []);
122
+ }
123
+
124
+ // Track page view
125
+ trackEvent('onboarding_page_view', { reason });
126
+
127
+ setIsLoading(false);
128
+ } catch (err) {
129
+ console.error('Onboarding init error:', err);
130
+ setError(err instanceof Error ? err.message : 'Failed to initialize');
131
+ setIsLoading(false);
132
+ }
133
+ };
134
+
135
+ init();
136
+ }, [reason, trackEvent]);
137
+
138
+ const handleCreateWorkspace = useCallback(async (repoFullName: string) => {
139
+ setIsCreating(true);
140
+ setError(null);
141
+
142
+ trackEvent('onboarding_repo_selected', { repository: repoFullName });
143
+
144
+ try {
145
+ const headers: Record<string, string> = { 'Content-Type': 'application/json' };
146
+ if (csrfToken) {
147
+ headers['X-CSRF-Token'] = csrfToken;
148
+ }
149
+
150
+ const res = await fetch('/api/workspaces/quick', {
151
+ method: 'POST',
152
+ credentials: 'include',
153
+ headers,
154
+ body: JSON.stringify({ repositoryFullName: repoFullName }),
155
+ });
156
+
157
+ const data = await res.json();
158
+
159
+ if (!res.ok) {
160
+ throw new Error(data.error || 'Failed to create workspace');
161
+ }
162
+
163
+ trackEvent('onboarding_workspace_created', {
164
+ workspaceId: data.workspaceId,
165
+ repository: repoFullName,
166
+ });
167
+
168
+ // Redirect to main app - it will handle provisioning state
169
+ window.location.href = '/app';
170
+ } catch (err) {
171
+ console.error('Create workspace error:', err);
172
+ setError(err instanceof Error ? err.message : 'Failed to create workspace');
173
+ setIsCreating(false);
174
+ }
175
+ }, [csrfToken, trackEvent]);
176
+
177
+ const handleConnectRepos = useCallback(() => {
178
+ trackEvent('onboarding_connect_repos_clicked', { reason });
179
+ window.location.href = '/connect-repos';
180
+ }, [reason, trackEvent]);
181
+
182
+ // Loading state
183
+ if (isLoading) {
184
+ return (
185
+ <div className="min-h-screen bg-gradient-to-br from-[#0a0a0f] via-[#0d1117] to-[#0a0a0f] flex items-center justify-center">
186
+ <div className="text-center">
187
+ <svg className="w-8 h-8 text-accent-cyan animate-spin mx-auto" fill="none" viewBox="0 0 24 24">
188
+ <circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4" />
189
+ <path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z" />
190
+ </svg>
191
+ <p className="mt-4 text-text-muted">Loading...</p>
192
+ </div>
193
+ </div>
194
+ );
195
+ }
196
+
197
+ // Creating workspace state
198
+ if (isCreating) {
199
+ return (
200
+ <div className="min-h-screen bg-gradient-to-br from-[#0a0a0f] via-[#0d1117] to-[#0a0a0f] flex items-center justify-center">
201
+ <div className="text-center">
202
+ <svg className="w-8 h-8 text-accent-cyan animate-spin mx-auto" fill="none" viewBox="0 0 24 24">
203
+ <circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4" />
204
+ <path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z" />
205
+ </svg>
206
+ <p className="mt-4 text-white font-medium">Creating your workspace...</p>
207
+ <p className="mt-2 text-text-muted text-sm">This may take a few minutes</p>
208
+ </div>
209
+ </div>
210
+ );
211
+ }
212
+
213
+ // Determine content based on reason
214
+ const isDeletedWorkspace = reason === 'deleted';
215
+
216
+ return (
217
+ <div className="min-h-screen bg-gradient-to-br from-[#0a0a0f] via-[#0d1117] to-[#0a0a0f] flex flex-col items-center justify-center p-4">
218
+ {/* Background grid */}
219
+ <div className="fixed inset-0 opacity-10 pointer-events-none">
220
+ <div
221
+ className="absolute inset-0"
222
+ style={{
223
+ backgroundImage: `linear-gradient(rgba(0, 217, 255, 0.1) 1px, transparent 1px),
224
+ linear-gradient(90deg, rgba(0, 217, 255, 0.1) 1px, transparent 1px)`,
225
+ backgroundSize: '50px 50px',
226
+ }}
227
+ />
228
+ </div>
229
+
230
+ <div className="relative z-10 w-full max-w-2xl">
231
+ {/* Logo and Header */}
232
+ <div className="flex flex-col items-center mb-8">
233
+ <LogoIcon size={56} withGlow={true} />
234
+ <h1 className="mt-6 text-3xl font-bold text-white">
235
+ {isDeletedWorkspace ? 'Workspace Deleted' : 'Welcome to Agent Relay'}
236
+ </h1>
237
+ <p className="mt-3 text-text-muted text-center max-w-md">
238
+ {isDeletedWorkspace
239
+ ? 'Your workspace has been deleted. Create a new one to continue working with AI agents.'
240
+ : 'Get started by creating your first workspace. Connect a repository and let AI agents help you build.'}
241
+ </p>
242
+ </div>
243
+
244
+ {/* Error message */}
245
+ {error && (
246
+ <div className="mb-6 p-4 bg-error/10 border border-error/20 rounded-xl">
247
+ <p className="text-error text-center">{error}</p>
248
+ </div>
249
+ )}
250
+
251
+ {/* Main content card */}
252
+ <div className="bg-bg-primary/80 backdrop-blur-sm border border-border-subtle rounded-2xl p-8">
253
+ {/* Step indicator for first-time users */}
254
+ {!isDeletedWorkspace && (
255
+ <div className="flex items-center justify-center gap-3 mb-8">
256
+ <div className="flex items-center gap-2">
257
+ <div className="w-8 h-8 rounded-full bg-accent-cyan flex items-center justify-center text-bg-deep font-semibold text-sm">
258
+ 1
259
+ </div>
260
+ <span className="text-white font-medium">Select Repository</span>
261
+ </div>
262
+ <div className="w-12 h-px bg-border-subtle" />
263
+ <div className="flex items-center gap-2">
264
+ <div className="w-8 h-8 rounded-full bg-bg-tertiary border border-border-subtle flex items-center justify-center text-text-muted font-semibold text-sm">
265
+ 2
266
+ </div>
267
+ <span className="text-text-muted">Connect AI Provider</span>
268
+ </div>
269
+ <div className="w-12 h-px bg-border-subtle" />
270
+ <div className="flex items-center gap-2">
271
+ <div className="w-8 h-8 rounded-full bg-bg-tertiary border border-border-subtle flex items-center justify-center text-text-muted font-semibold text-sm">
272
+ 3
273
+ </div>
274
+ <span className="text-text-muted">Start Building</span>
275
+ </div>
276
+ </div>
277
+ )}
278
+
279
+ <h2 className="text-xl font-semibold text-white mb-2">
280
+ {isDeletedWorkspace ? 'Create a New Workspace' : 'Choose a Repository'}
281
+ </h2>
282
+ <p className="text-text-muted mb-6">
283
+ {isDeletedWorkspace
284
+ ? 'Select a repository to create a new workspace for your AI agents.'
285
+ : 'Your workspace will be set up with this repository. You can add more repos later.'}
286
+ </p>
287
+
288
+ {repos.length > 0 ? (
289
+ <div className="space-y-3">
290
+ {repos.map((repo) => (
291
+ <button
292
+ key={repo.id}
293
+ onClick={() => handleCreateWorkspace(repo.fullName)}
294
+ disabled={isCreating}
295
+ className="w-full flex items-center gap-4 p-4 bg-bg-tertiary rounded-xl border border-border-subtle hover:border-accent-cyan/50 hover:bg-bg-hover transition-all text-left group disabled:opacity-50 disabled:cursor-not-allowed"
296
+ >
297
+ <div className="w-12 h-12 rounded-lg bg-bg-card border border-border-subtle flex items-center justify-center flex-shrink-0 group-hover:border-accent-cyan/30 transition-colors">
298
+ <svg className="w-6 h-6 text-text-muted group-hover:text-accent-cyan transition-colors" fill="currentColor" viewBox="0 0 16 16">
299
+ <path d="M2 2.5A2.5 2.5 0 014.5 0h8.75a.75.75 0 01.75.75v12.5a.75.75 0 01-.75.75h-2.5a.75.75 0 110-1.5h1.75v-2h-8a1 1 0 00-.714 1.7.75.75 0 01-1.072 1.05A2.495 2.495 0 012 11.5v-9zm10.5-1V9h-8c-.356 0-.694.074-1 .208V2.5a1 1 0 011-1h8z" />
300
+ </svg>
301
+ </div>
302
+ <div className="flex-1 min-w-0">
303
+ <p className="text-white font-medium truncate group-hover:text-accent-cyan transition-colors">
304
+ {repo.fullName}
305
+ </p>
306
+ <p className="text-text-muted text-sm mt-0.5">
307
+ {repo.isPrivate ? 'Private repository' : 'Public repository'} · {repo.defaultBranch}
308
+ </p>
309
+ </div>
310
+ <svg className="w-5 h-5 text-text-muted group-hover:text-accent-cyan group-hover:translate-x-1 transition-all" fill="none" viewBox="0 0 24 24" stroke="currentColor">
311
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 5l7 7-7 7" />
312
+ </svg>
313
+ </button>
314
+ ))}
315
+ </div>
316
+ ) : (
317
+ <div className="text-center py-12 bg-bg-tertiary rounded-xl border border-border-subtle">
318
+ <div className="w-16 h-16 mx-auto mb-4 bg-bg-card rounded-full flex items-center justify-center">
319
+ <svg className="w-8 h-8 text-text-muted" fill="currentColor" viewBox="0 0 24 24">
320
+ <path d="M12 0C5.37 0 0 5.37 0 12c0 5.31 3.435 9.795 8.205 11.385.6.105.825-.255.825-.57 0-.285-.015-1.23-.015-2.235-3.015.555-3.795-.735-4.035-1.41-.135-.345-.72-1.41-1.23-1.695-.42-.225-1.02-.78-.015-.795.945-.015 1.62.87 1.845 1.23 1.08 1.815 2.805 1.305 3.495.99.105-.78.42-1.305.765-1.605-2.67-.3-5.46-1.335-5.46-5.925 0-1.305.465-2.385 1.23-3.225-.12-.3-.54-1.53.12-3.18 0 0 1.005-.315 3.3 1.23.96-.27 1.98-.405 3-.405s2.04.135 3 .405c2.295-1.56 3.3-1.23 3.3-1.23.66 1.65.24 2.88.12 3.18.765.84 1.23 1.905 1.23 3.225 0 4.605-2.805 5.625-5.475 5.925.435.375.81 1.095.81 2.22 0 1.605-.015 2.895-.015 3.3 0 .315.225.69.825.57A12.02 12.02 0 0024 12c0-6.63-5.37-12-12-12z" />
321
+ </svg>
322
+ </div>
323
+ <h3 className="text-lg font-semibold text-white mb-2">No Repositories Connected</h3>
324
+ <p className="text-text-muted mb-6 max-w-sm mx-auto">
325
+ Connect your GitHub repositories to create a workspace and start working with AI agents.
326
+ </p>
327
+ <button
328
+ onClick={handleConnectRepos}
329
+ className="inline-flex items-center gap-2 py-3 px-6 bg-gradient-to-r from-accent-cyan to-[#00b8d9] text-bg-deep font-semibold rounded-xl hover:shadow-glow-cyan transition-all"
330
+ >
331
+ <svg className="w-5 h-5" fill="currentColor" viewBox="0 0 24 24">
332
+ <path d="M12 0C5.37 0 0 5.37 0 12c0 5.31 3.435 9.795 8.205 11.385.6.105.825-.255.825-.57 0-.285-.015-1.23-.015-2.235-3.015.555-3.795-.735-4.035-1.41-.135-.345-.72-1.41-1.23-1.695-.42-.225-1.02-.78-.015-.795.945-.015 1.62.87 1.845 1.23 1.08 1.815 2.805 1.305 3.495.99.105-.78.42-1.305.765-1.605-2.67-.3-5.46-1.335-5.46-5.925 0-1.305.465-2.385 1.23-3.225-.12-.3-.54-1.53.12-3.18 0 0 1.005-.315 3.3 1.23.96-.27 1.98-.405 3-.405s2.04.135 3 .405c2.295-1.56 3.3-1.23 3.3-1.23.66 1.65.24 2.88.12 3.18.765.84 1.23 1.905 1.23 3.225 0 4.605-2.805 5.625-5.475 5.925.435.375.81 1.095.81 2.22 0 1.605-.015 2.895-.015 3.3 0 .315.225.69.825.57A12.02 12.02 0 0024 12c0-6.63-5.37-12-12-12z" />
333
+ </svg>
334
+ Connect GitHub
335
+ </button>
336
+ </div>
337
+ )}
338
+ </div>
339
+
340
+ {/* Footer navigation */}
341
+ <div className="mt-8 flex justify-center gap-6 text-sm">
342
+ {repos.length > 0 && (
343
+ <button
344
+ onClick={handleConnectRepos}
345
+ className="text-text-muted hover:text-white transition-colors"
346
+ >
347
+ Connect More Repositories
348
+ </button>
349
+ )}
350
+ <a
351
+ href="/app"
352
+ className="text-text-muted hover:text-white transition-colors"
353
+ >
354
+ Back to Dashboard
355
+ </a>
356
+ <button
357
+ onClick={async () => {
358
+ const headers: Record<string, string> = {};
359
+ if (csrfToken) {
360
+ headers['X-CSRF-Token'] = csrfToken;
361
+ }
362
+ await fetch('/api/auth/logout', { method: 'POST', credentials: 'include', headers });
363
+ window.location.href = '/login';
364
+ }}
365
+ className="text-text-muted hover:text-white transition-colors"
366
+ >
367
+ Sign Out
368
+ </button>
369
+ </div>
370
+ </div>
371
+ </div>
372
+ );
373
+ }
374
+
375
+ // Wrap in Suspense for useSearchParams
376
+ export default function OnboardingPage() {
377
+ return (
378
+ <Suspense
379
+ fallback={
380
+ <div className="min-h-screen bg-gradient-to-br from-[#0a0a0f] via-[#0d1117] to-[#0a0a0f] flex items-center justify-center">
381
+ <div className="text-center">
382
+ <svg className="w-8 h-8 text-accent-cyan animate-spin mx-auto" fill="none" viewBox="0 0 24 24">
383
+ <circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4" />
384
+ <path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z" />
385
+ </svg>
386
+ <p className="mt-4 text-text-muted">Loading...</p>
387
+ </div>
388
+ </div>
389
+ }
390
+ >
391
+ <OnboardingContent />
392
+ </Suspense>
393
+ );
394
+ }
Binary file
@@ -0,0 +1,88 @@
1
+ import { Metadata } from 'next';
2
+ import { notFound } from 'next/navigation';
3
+ import { StaticPage } from '../../../landing/StaticPage';
4
+ import { getBlogPost } from '../../../landing/blogData';
5
+ import { renderBlogContent } from '../../../landing/BlogContent';
6
+ import '../../../landing/styles.css';
7
+
8
+ const POST_ID = 'go-to-bed-wake-up-to-a-finished-product';
9
+
10
+ const OG_IMAGE = 'https://agent-relay.com/blog/go-to-bed-wake-up-to-a-finished-product.svg';
11
+
12
+ export const metadata: Metadata = {
13
+ title: 'Go to Bed, Wake Up to a Finished Product | Agent Relay Blog',
14
+ description: 'Agent-to-agent communication is weird, fascinating, and potentially revolutionary. Here\'s how I built a system where agents work autonomously while I sleep.',
15
+ openGraph: {
16
+ title: 'Go to Bed, Wake Up to a Finished Product',
17
+ description: 'How agent-to-agent communication is changing autonomous development',
18
+ type: 'article',
19
+ siteName: 'Agent Relay',
20
+ url: 'https://agent-relay.com/blog/go-to-bed-wake-up-to-a-finished-product',
21
+ authors: ['Khaliq Gant'],
22
+ publishedTime: '2026-02-01',
23
+ images: [
24
+ {
25
+ url: OG_IMAGE,
26
+ width: 1200,
27
+ height: 630,
28
+ alt: 'Go to Bed, Wake Up to a Finished Product - Agent Relay',
29
+ },
30
+ ],
31
+ },
32
+ twitter: {
33
+ card: 'summary_large_image',
34
+ title: 'Go to Bed, Wake Up to a Finished Product',
35
+ description: 'How agent-to-agent communication is changing autonomous development',
36
+ images: [OG_IMAGE],
37
+ },
38
+ };
39
+
40
+ export default function BlogPostPage() {
41
+ const post = getBlogPost(POST_ID);
42
+
43
+ if (!post) {
44
+ notFound();
45
+ }
46
+
47
+ return (
48
+ <StaticPage
49
+ title="Blog"
50
+ titleLink="/blog"
51
+ subtitle="News, tutorials, and insights from the Agent Relay team."
52
+ >
53
+ <article className="blog-post">
54
+ <img
55
+ src="/blog/go-to-bed-wake-up-to-a-finished-product.svg"
56
+ alt={post.title}
57
+ style={{
58
+ width: '100%',
59
+ height: 'auto',
60
+ borderRadius: '12px',
61
+ marginBottom: '32px',
62
+ }}
63
+ />
64
+
65
+ <div className="blog-post-header">
66
+ <div className="blog-meta">
67
+ <span className="blog-category">{post.category}</span>
68
+ <span>{post.date}</span>
69
+ <span className="blog-author">by <a href="https://x.com/khaliqgant" target="_blank" rel="noopener noreferrer">{post.author}</a></span>
70
+ </div>
71
+ <h2 className="blog-post-title">{post.title}</h2>
72
+ <p className="blog-post-subtitle">{post.subtitle}</p>
73
+ </div>
74
+
75
+ <div className="blog-post-content">
76
+ {renderBlogContent(post.content)}
77
+ </div>
78
+ </article>
79
+
80
+ <hr style={{ border: 'none', borderTop: '1px solid var(--border-subtle)', margin: '48px 0' }} />
81
+
82
+ <h2>Stay Updated</h2>
83
+ <p>
84
+ Follow us on <a href="https://twitter.com/agent_relay" target="_blank" rel="noopener noreferrer">Twitter</a> for the latest updates and more content.
85
+ </p>
86
+ </StaticPage>
87
+ );
88
+ }
@@ -0,0 +1,93 @@
1
+ import { Metadata } from 'next';
2
+ import { notFound } from 'next/navigation';
3
+ import Script from 'next/script';
4
+ import { StaticPage } from '../../../landing/StaticPage';
5
+ import { getBlogPost } from '../../../landing/blogData';
6
+ import { renderBlogContent } from '../../../landing/BlogContent';
7
+ import '../../../landing/styles.css';
8
+
9
+ const POST_ID = 'let-them-cook-multi-agent-orchestration';
10
+
11
+ const OG_IMAGE = 'https://agent-relay.com/blog/let-them-cook-multi-agent-orchestration.svg';
12
+
13
+ export const metadata: Metadata = {
14
+ title: 'Let Them Cook: Lessons from 6 Weeks of Multi-Agent Orchestration | Agent Relay Blog',
15
+ description: 'Multi-agent orchestration is a step change in how tasks get done. After 6 weeks of building with agent swarms, here\'s what works, what breaks, and why the planning phase becomes everything.',
16
+ openGraph: {
17
+ title: 'Let Them Cook: Lessons from 6 Weeks of Multi-Agent Orchestration',
18
+ description: 'What I learned watching AI agents coordinate, communicate, and occasionally fall apart',
19
+ type: 'article',
20
+ siteName: 'Agent Relay',
21
+ url: 'https://agent-relay.com/blog/let-them-cook-multi-agent-orchestration',
22
+ authors: ['Khaliq Gant'],
23
+ publishedTime: '2026-02-04',
24
+ images: [
25
+ {
26
+ url: OG_IMAGE,
27
+ width: 1200,
28
+ height: 630,
29
+ alt: 'Let Them Cook: Multi-Agent Orchestration - Agent Relay',
30
+ },
31
+ ],
32
+ },
33
+ twitter: {
34
+ card: 'summary_large_image',
35
+ title: 'Let Them Cook: Lessons from 6 Weeks of Multi-Agent Orchestration',
36
+ description: 'What I learned watching AI agents coordinate, communicate, and occasionally fall apart',
37
+ images: [OG_IMAGE],
38
+ },
39
+ };
40
+
41
+ export default function BlogPostPage() {
42
+ const post = getBlogPost(POST_ID);
43
+
44
+ if (!post) {
45
+ notFound();
46
+ }
47
+
48
+ return (
49
+ <StaticPage
50
+ title="Blog"
51
+ titleLink="/blog"
52
+ subtitle="News, tutorials, and insights from the Agent Relay team."
53
+ >
54
+ <article className="blog-post">
55
+ <img
56
+ src="/blog/let-them-cook-multi-agent-orchestration.svg"
57
+ alt={post.title}
58
+ style={{
59
+ width: '100%',
60
+ height: 'auto',
61
+ borderRadius: '12px',
62
+ marginBottom: '32px',
63
+ }}
64
+ />
65
+
66
+ <div className="blog-post-header">
67
+ <div className="blog-meta">
68
+ <span className="blog-category">{post.category}</span>
69
+ <span>{post.date}</span>
70
+ <span className="blog-author">by <a href="https://x.com/khaliqgant" target="_blank" rel="noopener noreferrer">{post.author}</a></span>
71
+ </div>
72
+ <h2 className="blog-post-title">{post.title}</h2>
73
+ <p className="blog-post-subtitle">{post.subtitle}</p>
74
+ </div>
75
+
76
+ <div className="blog-post-content">
77
+ {renderBlogContent(post.content)}
78
+ </div>
79
+ </article>
80
+
81
+ <hr style={{ border: 'none', borderTop: '1px solid var(--border-subtle)', margin: '48px 0' }} />
82
+
83
+ <h2>Stay Updated</h2>
84
+ <p>
85
+ Follow us on <a href="https://twitter.com/agent_relay" target="_blank" rel="noopener noreferrer">Twitter</a> for the latest updates and more content.
86
+ </p>
87
+ <Script
88
+ src="https://platform.twitter.com/widgets.js"
89
+ strategy="lazyOnload"
90
+ />
91
+ </StaticPage>
92
+ );
93
+ }
@@ -0,0 +1,15 @@
1
+ import { Metadata } from 'next';
2
+ import { BlogPage } from '../../landing/BlogPage';
3
+
4
+ export const metadata: Metadata = {
5
+ title: 'Blog | Agent Relay',
6
+ description: 'News, tutorials, and insights from the Agent Relay team.',
7
+ openGraph: {
8
+ title: 'Agent Relay Blog',
9
+ description: 'News, tutorials, and insights from the Agent Relay team.',
10
+ },
11
+ };
12
+
13
+ export default function BlogRoute() {
14
+ return <BlogPage />;
15
+ }
@@ -0,0 +1,7 @@
1
+ 'use client';
2
+
3
+ import { CareersPage } from '../../landing';
4
+
5
+ export default function CareersRoute() {
6
+ return <CareersPage />;
7
+ }
@@ -0,0 +1,7 @@
1
+ 'use client';
2
+
3
+ import { ChangelogPage } from '../../landing';
4
+
5
+ export default function ChangelogRoute() {
6
+ return <ChangelogPage />;
7
+ }