@mrpatronz/nexusflow 0.1.0 → 0.1.2

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 (69) hide show
  1. package/.github/dependabot.yml +25 -0
  2. package/.github/workflows/release.yml +90 -0
  3. package/.vscode/launch.json +17 -0
  4. package/.vscode/tasks.json +17 -0
  5. package/README.md +1 -1
  6. package/dist/commands/commit.d.ts +18 -0
  7. package/dist/commands/commit.d.ts.map +1 -0
  8. package/dist/commands/commit.js +105 -0
  9. package/dist/commands/commit.js.map +1 -0
  10. package/dist/commands/diff.d.ts +11 -0
  11. package/dist/commands/diff.d.ts.map +1 -0
  12. package/dist/commands/diff.js +101 -0
  13. package/dist/commands/diff.js.map +1 -0
  14. package/dist/commands/sync.d.ts +11 -0
  15. package/dist/commands/sync.d.ts.map +1 -0
  16. package/dist/commands/sync.js +96 -0
  17. package/dist/commands/sync.js.map +1 -0
  18. package/dist/generators/base.d.ts.map +1 -1
  19. package/dist/generators/base.js +3 -0
  20. package/dist/generators/base.js.map +1 -1
  21. package/dist/generators/index.d.ts +5 -2
  22. package/dist/generators/index.d.ts.map +1 -1
  23. package/dist/generators/index.js +88 -38
  24. package/dist/generators/index.js.map +1 -1
  25. package/dist/generators/plan-generator.d.ts +40 -0
  26. package/dist/generators/plan-generator.d.ts.map +1 -0
  27. package/dist/generators/plan-generator.js +312 -0
  28. package/dist/generators/plan-generator.js.map +1 -0
  29. package/dist/gui/assets/index-B9Ph2bHH.css +2 -0
  30. package/dist/gui/assets/index-s4nRkpqY.js +21 -0
  31. package/dist/gui/index.html +2 -2
  32. package/dist/index.js +57 -0
  33. package/dist/index.js.map +1 -1
  34. package/dist/server.d.ts.map +1 -1
  35. package/dist/server.js +141 -1
  36. package/dist/server.js.map +1 -1
  37. package/dist/types.d.ts +13 -0
  38. package/dist/types.d.ts.map +1 -1
  39. package/dist/utils/multi-git.d.ts +108 -0
  40. package/dist/utils/multi-git.d.ts.map +1 -0
  41. package/dist/utils/multi-git.js +206 -0
  42. package/dist/utils/multi-git.js.map +1 -0
  43. package/extension/package-lock.json +2811 -0
  44. package/extension/package.json +61 -0
  45. package/extension/src/extension.ts +168 -0
  46. package/extension/tsconfig.json +19 -0
  47. package/gui/src/App.tsx +377 -24
  48. package/gui/src/features/changes/ChangesViewer.tsx +212 -0
  49. package/gui/src/features/knowledge/KnowledgeBase.tsx +84 -0
  50. package/gui/src/features/onboarding/OnboardingWizard.tsx +230 -0
  51. package/gui/src/features/plan/ImplementationPlan.tsx +32 -0
  52. package/gui/src/features/services/ServiceConsole.tsx +159 -0
  53. package/gui/src/features/sessions/SessionHistory.tsx +195 -0
  54. package/gui/src/features/workspace/WorkspaceBuilder.tsx +414 -0
  55. package/gui/src/features/workspace/WorkspaceList.tsx +382 -0
  56. package/gui/src/types.ts +61 -0
  57. package/package.json +6 -4
  58. package/src/commands/commit.ts +131 -0
  59. package/src/commands/diff.ts +125 -0
  60. package/src/commands/sync.ts +110 -0
  61. package/src/generators/base.ts +3 -0
  62. package/src/generators/index.ts +95 -40
  63. package/src/generators/plan-generator.ts +390 -0
  64. package/src/index.ts +59 -0
  65. package/src/server.ts +152 -1
  66. package/src/types.ts +17 -0
  67. package/src/utils/multi-git.ts +306 -0
  68. package/dist/gui/assets/index-Cq9V485S.js +0 -21
  69. package/dist/gui/assets/index-Dh1b5gSZ.css +0 -2
@@ -0,0 +1,414 @@
1
+ import React from 'react';
2
+ import { Sparkles, Terminal, Check, ArrowRight, ArrowLeft, Search, RefreshCw, FolderOpen } from 'lucide-react';
3
+ import type { RepoInfo, DetectedAI, DetectedEditor } from '../../types.js';
4
+
5
+ interface WorkspaceBuilderProps {
6
+ branchName: string;
7
+ setBranchName: (val: string) => void;
8
+ description: string;
9
+ setDescription: (val: string) => void;
10
+ activeStep: number;
11
+ setActiveStep: (val: number) => void;
12
+ repoSearch: string;
13
+ setRepoSearch: (val: string) => void;
14
+ filteredRepos: RepoInfo[];
15
+ selectedRepos: RepoInfo[];
16
+ handleToggleRepo: (repo: RepoInfo) => void;
17
+ aiAssistants: DetectedAI[];
18
+ selectedAI: string[];
19
+ handleToggleAI: (aiName: string) => void;
20
+ editors: DetectedEditor[];
21
+ selectedEditor: DetectedEditor | null;
22
+ setSelectedEditor: (ed: DetectedEditor | null) => void;
23
+ testCommand: string;
24
+ setTestCommand: (val: string) => void;
25
+ mockCommand: string;
26
+ setMockCommand: (val: string) => void;
27
+ startCommand: string;
28
+ setStartCommand: (val: string) => void;
29
+ creating: boolean;
30
+ createdWorkspace: { path: string } | null;
31
+ reposLoading: boolean;
32
+ handleCreateWorkspace: () => Promise<void>;
33
+ handleOpenInEditor: (path: string) => Promise<void>;
34
+ setView: (view: 'guide' | 'create' | 'workspaces' | 'settings') => void;
35
+ fetchWorkspaces: () => Promise<void>;
36
+ setActiveWsId: (id: string | null) => void;
37
+ }
38
+
39
+ export const WorkspaceBuilder: React.FC<WorkspaceBuilderProps> = ({
40
+ branchName,
41
+ setBranchName,
42
+ description,
43
+ setDescription,
44
+ activeStep,
45
+ setActiveStep,
46
+ repoSearch,
47
+ setRepoSearch,
48
+ filteredRepos,
49
+ selectedRepos,
50
+ handleToggleRepo,
51
+ aiAssistants,
52
+ selectedAI,
53
+ handleToggleAI,
54
+ editors,
55
+ selectedEditor,
56
+ setSelectedEditor,
57
+ testCommand,
58
+ setTestCommand,
59
+ mockCommand,
60
+ setMockCommand,
61
+ startCommand,
62
+ setStartCommand,
63
+ creating,
64
+ createdWorkspace,
65
+ reposLoading,
66
+ handleCreateWorkspace,
67
+ handleOpenInEditor,
68
+ setView,
69
+ fetchWorkspaces,
70
+ setActiveWsId,
71
+ }) => {
72
+ return (
73
+ <div className="max-w-4xl mx-auto">
74
+ <header className="mb-10">
75
+ <h1 className="text-3xl font-extrabold tracking-tight text-white mb-2">New Feature Workspace</h1>
76
+ <p className="text-sm text-gray-400">
77
+ Set up unified git worktrees, scan tech stacks, and write contextual configurations for your AI assistant.
78
+ </p>
79
+ </header>
80
+
81
+ {/* Progress Circle bar */}
82
+ <div className="flex justify-between items-center max-w-xl mx-auto mb-14 relative px-4">
83
+ <div className="absolute top-4 left-6 right-6 h-[2px] bg-gray-800 -z-10"></div>
84
+ <div
85
+ className="absolute top-4 left-6 h-[2px] bg-gradient-to-r from-cyan-400 to-indigo-500 -z-10 transition-all duration-300"
86
+ style={{ width: `${(activeStep / 3) * 92}%` }}
87
+ ></div>
88
+ <div className="flex flex-col items-center gap-2">
89
+ <div className={`w-8 h-8 rounded-full border-2 flex items-center justify-center font-bold text-xs transition-all ${
90
+ activeStep > 0 ? 'bg-emerald-500 border-emerald-500 text-white' : activeStep === 0 ? 'border-indigo-500 bg-[#0b0f19] text-white shadow-lg shadow-indigo-500/20' : 'border-gray-800 bg-gray-900 text-gray-500'
91
+ }`}>
92
+ {activeStep > 0 ? <Check size={14} /> : '1'}
93
+ </div>
94
+ <span className={`text-[11px] font-semibold tracking-wide uppercase ${activeStep === 0 ? 'text-white' : 'text-gray-500'}`}>Details</span>
95
+ </div>
96
+ <div className="flex flex-col items-center gap-2">
97
+ <div className={`w-8 h-8 rounded-full border-2 flex items-center justify-center font-bold text-xs transition-all ${
98
+ activeStep > 1 ? 'bg-emerald-500 border-emerald-500 text-white' : activeStep === 1 ? 'border-indigo-500 bg-[#0b0f19] text-white shadow-lg shadow-indigo-500/20' : 'border-gray-800 bg-gray-900 text-gray-500'
99
+ }`}>
100
+ {activeStep > 1 ? <Check size={14} /> : '2'}
101
+ </div>
102
+ <span className={`text-[11px] font-semibold tracking-wide uppercase ${activeStep === 1 ? 'text-white' : 'text-gray-500'}`}>Repos</span>
103
+ </div>
104
+ <div className="flex flex-col items-center gap-2">
105
+ <div className={`w-8 h-8 rounded-full border-2 flex items-center justify-center font-bold text-xs transition-all ${
106
+ activeStep > 2 ? 'bg-emerald-500 border-emerald-500 text-white' : activeStep === 2 ? 'border-indigo-500 bg-[#0b0f19] text-white shadow-lg shadow-indigo-500/20' : 'border-gray-800 bg-gray-900 text-gray-500'
107
+ }`}>
108
+ {activeStep > 2 ? <Check size={14} /> : '3'}
109
+ </div>
110
+ <span className={`text-[11px] font-semibold tracking-wide uppercase ${activeStep === 2 ? 'text-white' : 'text-gray-500'}`}>Assistant</span>
111
+ </div>
112
+ <div className="flex flex-col items-center gap-2">
113
+ <div className={`w-8 h-8 rounded-full border-2 flex items-center justify-center font-bold text-xs transition-all ${
114
+ activeStep === 3 ? 'border-emerald-500 bg-[#0b0f19] text-emerald-400 shadow-lg shadow-emerald-500/20' : 'border-gray-800 bg-gray-900 text-gray-500'
115
+ }`}>
116
+ 4
117
+ </div>
118
+ <span className={`text-[11px] font-semibold tracking-wide uppercase ${activeStep === 3 ? 'text-emerald-400' : 'text-gray-500'}`}>Complete</span>
119
+ </div>
120
+ </div>
121
+
122
+ {/* Step 0: Name & Description */}
123
+ {activeStep === 0 && (
124
+ <div className="bg-[#111827]/40 border border-gray-800/80 rounded-xl p-8 shadow-xl backdrop-blur-sm">
125
+ <div className="mb-6">
126
+ <label className="block text-xs font-semibold text-gray-400 uppercase tracking-wider mb-2">Feature Branch Name</label>
127
+ <input
128
+ type="text"
129
+ className="w-full bg-[#111827] border border-gray-800 focus:border-indigo-500 focus:ring-1 focus:ring-indigo-500 rounded-lg px-4 py-3 text-white placeholder-gray-600 transition-all outline-none text-sm shadow-inner"
130
+ placeholder="e.g., feature/oauth-authentication-flow"
131
+ value={branchName}
132
+ onChange={(e) => setBranchName(e.target.value)}
133
+ />
134
+ </div>
135
+ <div className="mb-8">
136
+ <label className="block text-xs font-semibold text-gray-400 uppercase tracking-wider mb-2">Feature Purpose & Context</label>
137
+ <textarea
138
+ className="w-full bg-[#111827] border border-gray-800 focus:border-indigo-500 focus:ring-1 focus:ring-indigo-500 rounded-lg px-4 py-3 text-white placeholder-gray-600 transition-all outline-none text-sm min-h-[140px] resize-y shadow-inner"
139
+ placeholder="Describe what you want to build. This helps AI assistants analyze context and produce matching plans."
140
+ value={description}
141
+ onChange={(e) => setDescription(e.target.value)}
142
+ />
143
+ </div>
144
+ <div className="flex justify-end">
145
+ <button
146
+ className="inline-flex items-center justify-center gap-2 px-5 py-3 rounded-lg text-sm font-semibold bg-gradient-to-r from-indigo-500 to-indigo-600 hover:from-indigo-600 hover:to-indigo-700 text-white shadow-md shadow-indigo-500/10 transition-all cursor-pointer disabled:opacity-40 disabled:cursor-not-allowed hover:-translate-y-0.5 active:translate-y-0"
147
+ disabled={!branchName || !description}
148
+ onClick={() => setActiveStep(1)}
149
+ >
150
+ Next Step <ArrowRight size={16} />
151
+ </button>
152
+ </div>
153
+ </div>
154
+ )}
155
+
156
+ {/* Step 1: Repo Selector */}
157
+ {activeStep === 1 && (
158
+ <div className="bg-[#111827]/40 border border-gray-800/80 rounded-xl p-8 shadow-xl backdrop-blur-sm">
159
+ <div className="flex justify-between items-center mb-6">
160
+ <label className="block text-xs font-semibold text-gray-400 uppercase tracking-wider">Select Repositories</label>
161
+ <div className="relative w-64">
162
+ <Search size={14} className="absolute left-3 top-3 text-gray-500" />
163
+ <input
164
+ type="text"
165
+ className="w-full bg-[#111827] border border-gray-800 focus:border-indigo-500 focus:ring-1 focus:ring-indigo-500 rounded-lg pl-9 pr-4 py-2 text-white placeholder-gray-600 transition-all outline-none text-xs"
166
+ placeholder="Search repo name..."
167
+ value={repoSearch}
168
+ onChange={(e) => setRepoSearch(e.target.value)}
169
+ />
170
+ </div>
171
+ </div>
172
+
173
+ {reposLoading ? (
174
+ <div className="flex flex-col items-center py-20 gap-3 text-gray-500">
175
+ <RefreshCw className="animate-spin text-indigo-400" size={24} />
176
+ <span className="text-xs">Scanning local projects directory...</span>
177
+ </div>
178
+ ) : (
179
+ <div className="grid grid-cols-1 md:grid-cols-2 gap-4 max-h-[380px] overflow-y-auto p-2 border border-gray-800/60 rounded-lg bg-gray-950/20 mb-8">
180
+ {filteredRepos.map((repo) => {
181
+ const isSelected = selectedRepos.some((r) => r.path === repo.path);
182
+ return (
183
+ <div
184
+ key={repo.path}
185
+ className={`bg-[#111827]/60 border rounded-xl p-4 flex items-start gap-3 cursor-pointer hover:bg-gray-800/20 hover:border-gray-700 transition-all ${
186
+ isSelected ? 'border-indigo-500 bg-indigo-500/5' : 'border-gray-800/80'
187
+ }`}
188
+ onClick={() => handleToggleRepo(repo)}
189
+ >
190
+ <input
191
+ type="checkbox"
192
+ className="mt-1 h-4 w-4 accent-indigo-500 rounded cursor-pointer"
193
+ checked={isSelected}
194
+ readOnly
195
+ />
196
+ <div className="flex-1 min-w-0">
197
+ <div className="text-sm font-semibold text-white truncate">{repo.name}</div>
198
+ <div className="text-[10px] text-gray-500 truncate mt-1">{repo.path}</div>
199
+ </div>
200
+ <span className="text-[9px] px-2 py-0.5 rounded bg-gray-800 text-gray-400 font-semibold uppercase">{repo.defaultBranch}</span>
201
+ </div>
202
+ );
203
+ })}
204
+ </div>
205
+ )}
206
+
207
+ <div className="flex justify-between">
208
+ <button
209
+ className="inline-flex items-center justify-center gap-2 px-5 py-3 rounded-lg text-sm font-semibold bg-gray-900 border border-gray-800 hover:bg-gray-800 hover:border-gray-700 text-white transition-all cursor-pointer"
210
+ onClick={() => setActiveStep(0)}
211
+ >
212
+ <ArrowLeft size={16} /> Back
213
+ </button>
214
+ <button
215
+ className="inline-flex items-center justify-center gap-2 px-5 py-3 rounded-lg text-sm font-semibold bg-gradient-to-r from-indigo-500 to-indigo-600 hover:from-indigo-600 hover:to-indigo-700 text-white shadow-md shadow-indigo-500/10 transition-all cursor-pointer disabled:opacity-40 disabled:cursor-not-allowed hover:-translate-y-0.5 active:translate-y-0"
216
+ disabled={selectedRepos.length === 0}
217
+ onClick={() => setActiveStep(2)}
218
+ >
219
+ Next Step <ArrowRight size={16} />
220
+ </button>
221
+ </div>
222
+ </div>
223
+ )}
224
+
225
+ {/* Step 2: AI & Editor Settings */}
226
+ {activeStep === 2 && (
227
+ <div className="bg-[#111827]/40 border border-gray-800/80 rounded-xl p-8 shadow-xl backdrop-blur-sm">
228
+ <div className="mb-8">
229
+ <label className="block text-xs font-semibold text-gray-400 uppercase tracking-wider mb-2">Target AI Assistant(s)</label>
230
+ <p className="text-xs text-gray-500 mb-4">
231
+ We generate context configurations matching the specifications of each checked assistant.
232
+ </p>
233
+ <div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
234
+ {aiAssistants.map((ai) => {
235
+ const isSelected = selectedAI.includes(ai.name);
236
+ return (
237
+ <div
238
+ key={ai.name}
239
+ className={`bg-[#111827]/60 border rounded-xl p-4 flex flex-col gap-3 cursor-pointer hover:border-gray-700 transition-all ${
240
+ isSelected ? 'border-indigo-500 bg-indigo-500/5' : 'border-gray-800/80'
241
+ }`}
242
+ onClick={() => handleToggleAI(ai.name)}
243
+ >
244
+ <div className="flex justify-between items-center">
245
+ <span className="text-sm font-bold text-white">{ai.displayName}</span>
246
+ <span className={`text-[9px] px-2 py-0.5 rounded font-semibold uppercase ${
247
+ ai.detected ? 'bg-emerald-500/10 text-emerald-400' : 'bg-gray-800 text-gray-500'
248
+ }`}>
249
+ {ai.detected ? 'Installed' : 'Missing'}
250
+ </span>
251
+ </div>
252
+ <p className="text-[11px] text-gray-500">
253
+ {ai.name === 'claude' && 'CLAUDE.md guidelines'}
254
+ {ai.name === 'antigravity' && 'CLAUDE.md guidelines (harness)'}
255
+ {ai.name === 'codex' && 'AGENTS.md config structure'}
256
+ {ai.name === 'copilot' && 'GitHub Copilot Workspace configs'}
257
+ {ai.name === 'cursor' && 'Cursor MDC rules and instructions'}
258
+ </p>
259
+ </div>
260
+ );
261
+ })}
262
+ </div>
263
+ </div>
264
+
265
+ <div className="mb-8">
266
+ <label className="block text-xs font-semibold text-gray-400 uppercase tracking-wider mb-2">Open Workspace In</label>
267
+ <div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 gap-4">
268
+ {editors.map((ed) => {
269
+ const isSelected = selectedEditor?.command === ed.command;
270
+ return (
271
+ <div
272
+ key={ed.command}
273
+ className={`bg-[#111827]/60 border rounded-xl p-4 flex flex-col cursor-pointer hover:border-gray-700 transition-all ${
274
+ isSelected ? 'border-indigo-500 bg-indigo-500/5' : 'border-gray-800/80'
275
+ }`}
276
+ onClick={() => setSelectedEditor(ed)}
277
+ >
278
+ <span className="text-sm font-bold text-white">{ed.name}</span>
279
+ <span className={`text-[9px] mt-2 w-max px-2 py-0.5 rounded font-semibold uppercase ${
280
+ ed.detected ? 'bg-emerald-500/10 text-emerald-400' : 'bg-gray-800 text-gray-500'
281
+ }`}>
282
+ {ed.detected ? 'Detected' : 'Missing'}
283
+ </span>
284
+ </div>
285
+ );
286
+ })}
287
+ <div
288
+ className={`bg-[#111827]/60 border rounded-xl p-4 flex flex-col cursor-pointer hover:border-gray-700 transition-all ${
289
+ selectedEditor === null ? 'border-indigo-500 bg-indigo-500/5' : 'border-gray-800/80'
290
+ }`}
291
+ onClick={() => setSelectedEditor(null)}
292
+ >
293
+ <span className="text-sm font-bold text-white">None</span>
294
+ <span className="text-[9px] mt-2 w-max px-2 py-0.5 rounded font-semibold uppercase bg-gray-800 text-gray-500">
295
+ Skip opening
296
+ </span>
297
+ </div>
298
+ </div>
299
+ </div>
300
+
301
+ <div className="mb-8 border border-gray-800/80 rounded-xl p-5 bg-gray-950/20">
302
+ <h4 className="text-xs font-bold text-gray-400 uppercase tracking-wider mb-4 flex items-center gap-2">
303
+ <Terminal size={14} className="text-indigo-400" /> Advanced Session Resumption Settings
304
+ </h4>
305
+ <p className="text-[11px] text-gray-550 mb-4">
306
+ Configure setup and verification test commands. AI assistants and the dashboard use these to resume your sessions green.
307
+ </p>
308
+ <div className="space-y-4">
309
+ <div>
310
+ <label className="block text-[11px] font-semibold text-gray-400 mb-1.5">Verification / Test Command</label>
311
+ <input
312
+ type="text"
313
+ className="w-full bg-[#030408] border border-gray-800 focus:border-indigo-500 rounded-lg px-3 py-2 text-xs font-mono text-white outline-none transition-all"
314
+ placeholder="e.g., npm run test or vitest run"
315
+ value={testCommand}
316
+ onChange={(e) => setTestCommand(e.target.value)}
317
+ />
318
+ </div>
319
+ <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
320
+ <div>
321
+ <label className="block text-[11px] font-semibold text-gray-400 mb-1.5">Mock / Database Command (Optional)</label>
322
+ <input
323
+ type="text"
324
+ className="w-full bg-[#030408] border border-gray-800 focus:border-indigo-500 rounded-lg px-3 py-2 text-xs font-mono text-white outline-none transition-all"
325
+ placeholder="e.g., docker compose up -d redis"
326
+ value={mockCommand}
327
+ onChange={(e) => setMockCommand(e.target.value)}
328
+ />
329
+ </div>
330
+ <div>
331
+ <label className="block text-[11px] font-semibold text-gray-400 mb-1.5">Start / Run Command (Optional)</label>
332
+ <input
333
+ type="text"
334
+ className="w-full bg-[#030408] border border-gray-800 focus:border-indigo-500 rounded-lg px-3 py-2 text-xs font-mono text-white outline-none transition-all"
335
+ placeholder="e.g., npm run start:dev"
336
+ value={startCommand}
337
+ onChange={(e) => setStartCommand(e.target.value)}
338
+ />
339
+ </div>
340
+ </div>
341
+ </div>
342
+ </div>
343
+
344
+ <div className="flex justify-between">
345
+ <button
346
+ className="inline-flex items-center justify-center gap-2 px-5 py-3 rounded-lg text-sm font-semibold bg-gray-900 border border-gray-800 hover:bg-gray-800 hover:border-gray-700 text-white transition-all cursor-pointer"
347
+ onClick={() => setActiveStep(1)}
348
+ >
349
+ <ArrowLeft size={16} /> Back
350
+ </button>
351
+ <button
352
+ className="inline-flex items-center justify-center gap-2 px-6 py-3 rounded-lg text-sm font-semibold bg-gradient-to-r from-indigo-500 to-indigo-600 hover:from-indigo-600 hover:to-indigo-700 text-white shadow-lg shadow-indigo-500/20 transition-all cursor-pointer hover:-translate-y-0.5 active:translate-y-0 disabled:opacity-40 disabled:cursor-not-allowed"
353
+ disabled={creating}
354
+ onClick={handleCreateWorkspace}
355
+ >
356
+ {creating ? (
357
+ <>
358
+ <RefreshCw className="animate-spin" size={14} /> Building...
359
+ </>
360
+ ) : (
361
+ <>
362
+ <Sparkles size={14} /> Build Workspace
363
+ </>
364
+ )}
365
+ </button>
366
+ </div>
367
+ </div>
368
+ )}
369
+
370
+ {/* Step 3: Success Screen */}
371
+ {activeStep === 3 && createdWorkspace && (
372
+ <div className="bg-[#111827]/40 border border-gray-800/80 rounded-xl p-10 text-center shadow-xl backdrop-blur-sm">
373
+ <div className="inline-flex items-center justify-center p-3 rounded-full bg-emerald-500/10 border border-emerald-500/20 text-emerald-400 mb-6">
374
+ <Check size={36} />
375
+ </div>
376
+ <h2 className="text-2xl font-bold text-white mb-2">Workspace Generated!</h2>
377
+ <p className="text-gray-400 text-sm max-w-lg mx-auto mb-8">
378
+ We spun up git worktrees for your branch <code>{branchName}</code>, analyzed the code architectures, and generated your AI assistant instructions.
379
+ </p>
380
+
381
+ <div className="flex flex-col gap-3 bg-gray-950/40 border border-gray-800/60 rounded-xl p-5 w-fit min-w-[360px] mx-auto text-left text-xs mb-8">
382
+ <div className="flex justify-between items-center">
383
+ <span className="text-gray-500 font-medium">Branch name:</span>
384
+ <code className="text-indigo-400 font-bold">{branchName}</code>
385
+ </div>
386
+ <div className="flex justify-between items-center gap-4">
387
+ <span className="text-gray-500 font-medium">Location:</span>
388
+ <code className="text-gray-400 font-mono text-[10px] break-all">{createdWorkspace.path}</code>
389
+ </div>
390
+ </div>
391
+
392
+ <div className="flex justify-center gap-4">
393
+ <button
394
+ className="inline-flex items-center justify-center gap-2 px-5 py-3 rounded-lg text-sm font-semibold bg-gray-900 border border-gray-800 hover:bg-gray-800 hover:border-gray-700 text-white transition-all cursor-pointer"
395
+ onClick={() => {
396
+ setView('workspaces');
397
+ fetchWorkspaces();
398
+ setActiveWsId(branchName);
399
+ }}
400
+ >
401
+ <Terminal size={14} className="text-cyan-400" /> Manage Services
402
+ </button>
403
+ <button
404
+ className="inline-flex items-center justify-center gap-2 px-5 py-3 rounded-lg text-sm font-semibold bg-gradient-to-r from-indigo-500 to-indigo-600 hover:from-indigo-600 hover:to-indigo-700 text-white shadow-md shadow-indigo-500/10 transition-all cursor-pointer hover:-translate-y-0.5 active:translate-y-0"
405
+ onClick={() => handleOpenInEditor(createdWorkspace.path)}
406
+ >
407
+ <FolderOpen size={14} /> Open Editor
408
+ </button>
409
+ </div>
410
+ </div>
411
+ )}
412
+ </div>
413
+ );
414
+ };