@siteboon/claude-code-ui 1.8.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 (106) hide show
  1. package/.env.example +12 -0
  2. package/.nvmrc +1 -0
  3. package/LICENSE +675 -0
  4. package/README.md +275 -0
  5. package/index.html +48 -0
  6. package/package.json +84 -0
  7. package/postcss.config.js +6 -0
  8. package/public/convert-icons.md +53 -0
  9. package/public/favicon.png +0 -0
  10. package/public/favicon.svg +9 -0
  11. package/public/generate-icons.js +49 -0
  12. package/public/icons/claude-ai-icon.svg +1 -0
  13. package/public/icons/cursor.svg +1 -0
  14. package/public/icons/generate-icons.md +19 -0
  15. package/public/icons/icon-128x128.png +0 -0
  16. package/public/icons/icon-128x128.svg +12 -0
  17. package/public/icons/icon-144x144.png +0 -0
  18. package/public/icons/icon-144x144.svg +12 -0
  19. package/public/icons/icon-152x152.png +0 -0
  20. package/public/icons/icon-152x152.svg +12 -0
  21. package/public/icons/icon-192x192.png +0 -0
  22. package/public/icons/icon-192x192.svg +12 -0
  23. package/public/icons/icon-384x384.png +0 -0
  24. package/public/icons/icon-384x384.svg +12 -0
  25. package/public/icons/icon-512x512.png +0 -0
  26. package/public/icons/icon-512x512.svg +12 -0
  27. package/public/icons/icon-72x72.png +0 -0
  28. package/public/icons/icon-72x72.svg +12 -0
  29. package/public/icons/icon-96x96.png +0 -0
  30. package/public/icons/icon-96x96.svg +12 -0
  31. package/public/icons/icon-template.svg +12 -0
  32. package/public/logo.svg +9 -0
  33. package/public/manifest.json +61 -0
  34. package/public/screenshots/cli-selection.png +0 -0
  35. package/public/screenshots/desktop-main.png +0 -0
  36. package/public/screenshots/mobile-chat.png +0 -0
  37. package/public/screenshots/tools-modal.png +0 -0
  38. package/public/sw.js +49 -0
  39. package/server/claude-cli.js +391 -0
  40. package/server/cursor-cli.js +250 -0
  41. package/server/database/db.js +86 -0
  42. package/server/database/init.sql +16 -0
  43. package/server/index.js +1167 -0
  44. package/server/middleware/auth.js +80 -0
  45. package/server/projects.js +1063 -0
  46. package/server/routes/auth.js +135 -0
  47. package/server/routes/cursor.js +794 -0
  48. package/server/routes/git.js +823 -0
  49. package/server/routes/mcp-utils.js +48 -0
  50. package/server/routes/mcp.js +552 -0
  51. package/server/routes/taskmaster.js +1971 -0
  52. package/server/utils/mcp-detector.js +198 -0
  53. package/server/utils/taskmaster-websocket.js +129 -0
  54. package/src/App.jsx +751 -0
  55. package/src/components/ChatInterface.jsx +3485 -0
  56. package/src/components/ClaudeLogo.jsx +11 -0
  57. package/src/components/ClaudeStatus.jsx +107 -0
  58. package/src/components/CodeEditor.jsx +422 -0
  59. package/src/components/CreateTaskModal.jsx +88 -0
  60. package/src/components/CursorLogo.jsx +9 -0
  61. package/src/components/DarkModeToggle.jsx +35 -0
  62. package/src/components/DiffViewer.jsx +41 -0
  63. package/src/components/ErrorBoundary.jsx +73 -0
  64. package/src/components/FileTree.jsx +480 -0
  65. package/src/components/GitPanel.jsx +1283 -0
  66. package/src/components/ImageViewer.jsx +54 -0
  67. package/src/components/LoginForm.jsx +110 -0
  68. package/src/components/MainContent.jsx +577 -0
  69. package/src/components/MicButton.jsx +272 -0
  70. package/src/components/MobileNav.jsx +88 -0
  71. package/src/components/NextTaskBanner.jsx +695 -0
  72. package/src/components/PRDEditor.jsx +871 -0
  73. package/src/components/ProtectedRoute.jsx +44 -0
  74. package/src/components/QuickSettingsPanel.jsx +262 -0
  75. package/src/components/Settings.jsx +2023 -0
  76. package/src/components/SetupForm.jsx +135 -0
  77. package/src/components/Shell.jsx +663 -0
  78. package/src/components/Sidebar.jsx +1665 -0
  79. package/src/components/StandaloneShell.jsx +106 -0
  80. package/src/components/TaskCard.jsx +210 -0
  81. package/src/components/TaskDetail.jsx +406 -0
  82. package/src/components/TaskIndicator.jsx +108 -0
  83. package/src/components/TaskList.jsx +1054 -0
  84. package/src/components/TaskMasterSetupWizard.jsx +603 -0
  85. package/src/components/TaskMasterStatus.jsx +86 -0
  86. package/src/components/TodoList.jsx +91 -0
  87. package/src/components/Tooltip.jsx +91 -0
  88. package/src/components/ui/badge.jsx +31 -0
  89. package/src/components/ui/button.jsx +46 -0
  90. package/src/components/ui/input.jsx +19 -0
  91. package/src/components/ui/scroll-area.jsx +23 -0
  92. package/src/contexts/AuthContext.jsx +158 -0
  93. package/src/contexts/TaskMasterContext.jsx +324 -0
  94. package/src/contexts/TasksSettingsContext.jsx +95 -0
  95. package/src/contexts/ThemeContext.jsx +94 -0
  96. package/src/contexts/WebSocketContext.jsx +29 -0
  97. package/src/hooks/useAudioRecorder.js +109 -0
  98. package/src/hooks/useVersionCheck.js +39 -0
  99. package/src/index.css +822 -0
  100. package/src/lib/utils.js +6 -0
  101. package/src/main.jsx +10 -0
  102. package/src/utils/api.js +141 -0
  103. package/src/utils/websocket.js +109 -0
  104. package/src/utils/whisper.js +37 -0
  105. package/tailwind.config.js +63 -0
  106. package/vite.config.js +29 -0
@@ -0,0 +1,603 @@
1
+ import React, { useState, useEffect } from 'react';
2
+ import { X, ChevronRight, ChevronLeft, CheckCircle, AlertCircle, Settings, Server, FileText, Sparkles, ExternalLink, Copy } from 'lucide-react';
3
+ import { cn } from '../lib/utils';
4
+ import { api } from '../utils/api';
5
+
6
+ const TaskMasterSetupWizard = ({
7
+ isOpen = true,
8
+ onClose,
9
+ onComplete,
10
+ currentProject,
11
+ className = ''
12
+ }) => {
13
+ const [currentStep, setCurrentStep] = useState(1);
14
+ const [loading, setLoading] = useState(false);
15
+ const [error, setError] = useState(null);
16
+ const [setupData, setSetupData] = useState({
17
+ projectRoot: '',
18
+ initGit: true,
19
+ storeTasksInGit: true,
20
+ addAliases: true,
21
+ skipInstall: false,
22
+ rules: ['claude'],
23
+ mcpConfigured: false,
24
+ prdContent: ''
25
+ });
26
+
27
+ const totalSteps = 4;
28
+
29
+ useEffect(() => {
30
+ if (currentProject) {
31
+ setSetupData(prev => ({
32
+ ...prev,
33
+ projectRoot: currentProject.path || ''
34
+ }));
35
+ }
36
+ }, [currentProject]);
37
+
38
+ const steps = [
39
+ {
40
+ id: 1,
41
+ title: 'Project Configuration',
42
+ description: 'Configure basic TaskMaster settings for your project'
43
+ },
44
+ {
45
+ id: 2,
46
+ title: 'MCP Server Setup',
47
+ description: 'Ensure TaskMaster MCP server is properly configured'
48
+ },
49
+ {
50
+ id: 3,
51
+ title: 'PRD Creation',
52
+ description: 'Create or import a Product Requirements Document'
53
+ },
54
+ {
55
+ id: 4,
56
+ title: 'Complete Setup',
57
+ description: 'Initialize TaskMaster and generate initial tasks'
58
+ }
59
+ ];
60
+
61
+ const handleNext = async () => {
62
+ setError(null);
63
+
64
+ try {
65
+ if (currentStep === 1) {
66
+ // Validate project configuration
67
+ if (!setupData.projectRoot) {
68
+ setError('Project root path is required');
69
+ return;
70
+ }
71
+ setCurrentStep(2);
72
+ } else if (currentStep === 2) {
73
+ // Check MCP server status
74
+ setLoading(true);
75
+ try {
76
+ const mcpStatus = await api.get('/mcp-utils/taskmaster-server');
77
+ setSetupData(prev => ({
78
+ ...prev,
79
+ mcpConfigured: mcpStatus.hasMCPServer && mcpStatus.isConfigured
80
+ }));
81
+ setCurrentStep(3);
82
+ } catch (err) {
83
+ setError('Failed to check MCP server status. You can continue but some features may not work.');
84
+ setCurrentStep(3);
85
+ }
86
+ } else if (currentStep === 3) {
87
+ // Validate PRD step
88
+ if (!setupData.prdContent.trim()) {
89
+ setError('Please create or import a PRD to continue');
90
+ return;
91
+ }
92
+ setCurrentStep(4);
93
+ } else if (currentStep === 4) {
94
+ // Complete setup
95
+ await completeSetup();
96
+ }
97
+ } catch (err) {
98
+ setError(err.message || 'An error occurred');
99
+ } finally {
100
+ setLoading(false);
101
+ }
102
+ };
103
+
104
+ const handlePrevious = () => {
105
+ if (currentStep > 1) {
106
+ setCurrentStep(currentStep - 1);
107
+ setError(null);
108
+ }
109
+ };
110
+
111
+ const completeSetup = async () => {
112
+ setLoading(true);
113
+ try {
114
+ // Initialize TaskMaster project
115
+ const initResponse = await api.post('/taskmaster/initialize', {
116
+ projectRoot: setupData.projectRoot,
117
+ initGit: setupData.initGit,
118
+ storeTasksInGit: setupData.storeTasksInGit,
119
+ addAliases: setupData.addAliases,
120
+ skipInstall: setupData.skipInstall,
121
+ rules: setupData.rules,
122
+ yes: true
123
+ });
124
+
125
+ if (!initResponse.ok) {
126
+ throw new Error('Failed to initialize TaskMaster project');
127
+ }
128
+
129
+ // Save PRD content if provided
130
+ if (setupData.prdContent.trim()) {
131
+ const prdResponse = await api.post('/taskmaster/save-prd', {
132
+ projectRoot: setupData.projectRoot,
133
+ content: setupData.prdContent
134
+ });
135
+
136
+ if (!prdResponse.ok) {
137
+ console.warn('Failed to save PRD content');
138
+ }
139
+ }
140
+
141
+ // Parse PRD to generate initial tasks
142
+ if (setupData.prdContent.trim()) {
143
+ const parseResponse = await api.post('/taskmaster/parse-prd', {
144
+ projectRoot: setupData.projectRoot,
145
+ input: '.taskmaster/docs/prd.txt',
146
+ numTasks: '10',
147
+ research: false,
148
+ force: false
149
+ });
150
+
151
+ if (!parseResponse.ok) {
152
+ console.warn('Failed to parse PRD and generate tasks');
153
+ }
154
+ }
155
+
156
+ onComplete?.();
157
+ onClose?.();
158
+ } catch (err) {
159
+ setError(err.message || 'Failed to complete TaskMaster setup');
160
+ } finally {
161
+ setLoading(false);
162
+ }
163
+ };
164
+
165
+ const copyMCPConfig = () => {
166
+ const mcpConfig = `{
167
+ "mcpServers": {
168
+ "": {
169
+ "command": "npx",
170
+ "args": ["-y", "--package=task-master-ai", "task-master-ai"],
171
+ "env": {
172
+ "ANTHROPIC_API_KEY": "your_anthropic_key_here",
173
+ "PERPLEXITY_API_KEY": "your_perplexity_key_here"
174
+ }
175
+ }
176
+ }
177
+ }`;
178
+ navigator.clipboard.writeText(mcpConfig);
179
+ };
180
+
181
+ const renderStepContent = () => {
182
+ switch (currentStep) {
183
+ case 1:
184
+ return (
185
+ <div className="space-y-6">
186
+ <div className="text-center">
187
+ <Settings className="w-12 h-12 text-blue-600 mx-auto mb-4" />
188
+ <h3 className="text-lg font-semibold text-gray-900 dark:text-white mb-2">
189
+ Project Configuration
190
+ </h3>
191
+ <p className="text-gray-600 dark:text-gray-400">
192
+ Configure TaskMaster settings for your project
193
+ </p>
194
+ </div>
195
+
196
+ <div className="space-y-4">
197
+ <div>
198
+ <label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
199
+ Project Root Path
200
+ </label>
201
+ <input
202
+ type="text"
203
+ value={setupData.projectRoot}
204
+ onChange={(e) => setSetupData(prev => ({ ...prev, projectRoot: e.target.value }))}
205
+ className="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-md focus:ring-2 focus:ring-blue-500 focus:border-blue-500 bg-white dark:bg-gray-800 text-gray-900 dark:text-white"
206
+ placeholder="/path/to/your/project"
207
+ />
208
+ </div>
209
+
210
+ <div className="space-y-3">
211
+ <h4 className="font-medium text-gray-900 dark:text-white">Options</h4>
212
+
213
+ <label className="flex items-center gap-3">
214
+ <input
215
+ type="checkbox"
216
+ checked={setupData.initGit}
217
+ onChange={(e) => setSetupData(prev => ({ ...prev, initGit: e.target.checked }))}
218
+ className="w-4 h-4 text-blue-600 rounded focus:ring-2 focus:ring-blue-500"
219
+ />
220
+ <span className="text-sm text-gray-700 dark:text-gray-300">Initialize Git repository</span>
221
+ </label>
222
+
223
+ <label className="flex items-center gap-3">
224
+ <input
225
+ type="checkbox"
226
+ checked={setupData.storeTasksInGit}
227
+ onChange={(e) => setSetupData(prev => ({ ...prev, storeTasksInGit: e.target.checked }))}
228
+ className="w-4 h-4 text-blue-600 rounded focus:ring-2 focus:ring-blue-500"
229
+ />
230
+ <span className="text-sm text-gray-700 dark:text-gray-300">Store tasks in Git</span>
231
+ </label>
232
+
233
+ <label className="flex items-center gap-3">
234
+ <input
235
+ type="checkbox"
236
+ checked={setupData.addAliases}
237
+ onChange={(e) => setSetupData(prev => ({ ...prev, addAliases: e.target.checked }))}
238
+ className="w-4 h-4 text-blue-600 rounded focus:ring-2 focus:ring-blue-500"
239
+ />
240
+ <span className="text-sm text-gray-700 dark:text-gray-300">Add shell aliases (tm, taskmaster)</span>
241
+ </label>
242
+ </div>
243
+
244
+ <div>
245
+ <label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
246
+ Rule Profiles
247
+ </label>
248
+ <div className="grid grid-cols-3 gap-2">
249
+ {['claude', 'cursor', 'vscode', 'roo', 'cline', 'windsurf'].map(rule => (
250
+ <label key={rule} className="flex items-center gap-2">
251
+ <input
252
+ type="checkbox"
253
+ checked={setupData.rules.includes(rule)}
254
+ onChange={(e) => {
255
+ if (e.target.checked) {
256
+ setSetupData(prev => ({ ...prev, rules: [...prev.rules, rule] }));
257
+ } else {
258
+ setSetupData(prev => ({ ...prev, rules: prev.rules.filter(r => r !== rule) }));
259
+ }
260
+ }}
261
+ className="w-4 h-4 text-blue-600 rounded focus:ring-2 focus:ring-blue-500"
262
+ />
263
+ <span className="text-sm text-gray-700 dark:text-gray-300 capitalize">{rule}</span>
264
+ </label>
265
+ ))}
266
+ </div>
267
+ </div>
268
+ </div>
269
+ </div>
270
+ );
271
+
272
+ case 2:
273
+ return (
274
+ <div className="space-y-6">
275
+ <div className="text-center">
276
+ <Server className="w-12 h-12 text-purple-600 mx-auto mb-4" />
277
+ <h3 className="text-lg font-semibold text-gray-900 dark:text-white mb-2">
278
+ MCP Server Setup
279
+ </h3>
280
+ <p className="text-gray-600 dark:text-gray-400">
281
+ TaskMaster works best with the MCP server configured
282
+ </p>
283
+ </div>
284
+
285
+ <div className="bg-blue-50 dark:bg-blue-950 border border-blue-200 dark:border-blue-800 rounded-lg p-4">
286
+ <div className="flex items-start gap-3">
287
+ <AlertCircle className="w-5 h-5 text-blue-600 dark:text-blue-400 mt-0.5" />
288
+ <div>
289
+ <h4 className="font-medium text-blue-900 dark:text-blue-100 mb-1">
290
+ MCP Server Configuration
291
+ </h4>
292
+ <p className="text-sm text-blue-800 dark:text-blue-200 mb-3">
293
+ To enable full TaskMaster integration, add the MCP server configuration to your Claude settings.
294
+ </p>
295
+
296
+ <div className="bg-white dark:bg-gray-800 rounded border p-3 mb-3">
297
+ <div className="flex items-center justify-between mb-2">
298
+ <span className="text-sm font-mono text-gray-600 dark:text-gray-400">.mcp.json</span>
299
+ <button
300
+ onClick={copyMCPConfig}
301
+ className="flex items-center gap-1 px-2 py-1 text-xs bg-gray-100 dark:bg-gray-700 text-gray-600 dark:text-gray-300 rounded hover:bg-gray-200 dark:hover:bg-gray-600 transition-colors"
302
+ >
303
+ <Copy className="w-3 h-3" />
304
+ Copy
305
+ </button>
306
+ </div>
307
+ <pre className="text-xs text-gray-800 dark:text-gray-200 whitespace-pre-wrap">
308
+ {`{
309
+ "mcpServers": {
310
+ "task-master-ai": {
311
+ "command": "npx",
312
+ "args": ["-y", "--package=task-master-ai", "task-master-ai"],
313
+ "env": {
314
+ "ANTHROPIC_API_KEY": "your_anthropic_key_here",
315
+ "PERPLEXITY_API_KEY": "your_perplexity_key_here"
316
+ }
317
+ }
318
+ }
319
+ }`}
320
+ </pre>
321
+ </div>
322
+
323
+ <div className="flex items-center gap-2 text-sm">
324
+ <a
325
+ href="https://docs.anthropic.com/en/docs/build-with-claude/tool-use/mcp-servers"
326
+ target="_blank"
327
+ rel="noopener noreferrer"
328
+ className="text-blue-600 dark:text-blue-400 hover:text-blue-700 dark:hover:text-blue-300 flex items-center gap-1"
329
+ >
330
+ Learn about MCP setup
331
+ <ExternalLink className="w-3 h-3" />
332
+ </a>
333
+ </div>
334
+ </div>
335
+ </div>
336
+ </div>
337
+
338
+ <div className="bg-gray-50 dark:bg-gray-800 rounded-lg p-4">
339
+ <h4 className="font-medium text-gray-900 dark:text-white mb-2">Current Status</h4>
340
+ <div className="flex items-center gap-2">
341
+ {setupData.mcpConfigured ? (
342
+ <>
343
+ <CheckCircle className="w-4 h-4 text-green-500" />
344
+ <span className="text-sm text-green-700 dark:text-green-300">MCP server is configured</span>
345
+ </>
346
+ ) : (
347
+ <>
348
+ <AlertCircle className="w-4 h-4 text-amber-500" />
349
+ <span className="text-sm text-amber-700 dark:text-amber-300">MCP server not detected (optional)</span>
350
+ </>
351
+ )}
352
+ </div>
353
+ </div>
354
+ </div>
355
+ );
356
+
357
+ case 3:
358
+ return (
359
+ <div className="space-y-6">
360
+ <div className="text-center">
361
+ <FileText className="w-12 h-12 text-green-600 mx-auto mb-4" />
362
+ <h3 className="text-lg font-semibold text-gray-900 dark:text-white mb-2">
363
+ Product Requirements Document
364
+ </h3>
365
+ <p className="text-gray-600 dark:text-gray-400">
366
+ Create or import a PRD to generate initial tasks
367
+ </p>
368
+ </div>
369
+
370
+ <div className="space-y-4">
371
+ <div>
372
+ <label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
373
+ PRD Content
374
+ </label>
375
+ <textarea
376
+ value={setupData.prdContent}
377
+ onChange={(e) => setSetupData(prev => ({ ...prev, prdContent: e.target.value }))}
378
+ rows={12}
379
+ className="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-md focus:ring-2 focus:ring-blue-500 focus:border-blue-500 bg-white dark:bg-gray-800 text-gray-900 dark:text-white font-mono text-sm"
380
+ placeholder="# Product Requirements Document
381
+
382
+ ## 1. Overview
383
+ Describe your project or feature...
384
+
385
+ ## 2. Objectives
386
+ - Primary goal
387
+ - Success metrics
388
+
389
+ ## 3. User Stories
390
+ - As a user, I want...
391
+
392
+ ## 4. Requirements
393
+ - Feature requirements
394
+ - Technical requirements
395
+
396
+ ## 5. Implementation Plan
397
+ - Phase 1: Core features
398
+ - Phase 2: Enhancements"
399
+ />
400
+ </div>
401
+
402
+ <div className="bg-blue-50 dark:bg-blue-950 border border-blue-200 dark:border-blue-800 rounded-lg p-4">
403
+ <div className="flex items-start gap-3">
404
+ <Sparkles className="w-5 h-5 text-blue-600 dark:text-blue-400 mt-0.5" />
405
+ <div>
406
+ <h4 className="font-medium text-blue-900 dark:text-blue-100 mb-1">
407
+ AI Task Generation
408
+ </h4>
409
+ <p className="text-sm text-blue-800 dark:text-blue-200">
410
+ TaskMaster will analyze your PRD and automatically generate a structured task list with dependencies, priorities, and implementation details.
411
+ </p>
412
+ </div>
413
+ </div>
414
+ </div>
415
+ </div>
416
+ </div>
417
+ );
418
+
419
+ case 4:
420
+ return (
421
+ <div className="space-y-6">
422
+ <div className="text-center">
423
+ <CheckCircle className="w-12 h-12 text-green-600 mx-auto mb-4" />
424
+ <h3 className="text-lg font-semibold text-gray-900 dark:text-white mb-2">
425
+ Complete Setup
426
+ </h3>
427
+ <p className="text-gray-600 dark:text-gray-400">
428
+ Ready to initialize TaskMaster for your project
429
+ </p>
430
+ </div>
431
+
432
+ <div className="bg-green-50 dark:bg-green-950 border border-green-200 dark:border-green-800 rounded-lg p-4">
433
+ <h4 className="font-medium text-green-900 dark:text-green-100 mb-3">
434
+ Setup Summary
435
+ </h4>
436
+ <ul className="space-y-2 text-sm text-green-800 dark:text-green-200">
437
+ <li className="flex items-center gap-2">
438
+ <CheckCircle className="w-4 h-4" />
439
+ Project: {setupData.projectRoot}
440
+ </li>
441
+ <li className="flex items-center gap-2">
442
+ <CheckCircle className="w-4 h-4" />
443
+ Rules: {setupData.rules.join(', ')}
444
+ </li>
445
+ {setupData.mcpConfigured && (
446
+ <li className="flex items-center gap-2">
447
+ <CheckCircle className="w-4 h-4" />
448
+ MCP server configured
449
+ </li>
450
+ )}
451
+ <li className="flex items-center gap-2">
452
+ <CheckCircle className="w-4 h-4" />
453
+ PRD content ready ({setupData.prdContent.length} characters)
454
+ </li>
455
+ </ul>
456
+ </div>
457
+
458
+ <div className="bg-blue-50 dark:bg-blue-950 border border-blue-200 dark:border-blue-800 rounded-lg p-4">
459
+ <h4 className="font-medium text-blue-900 dark:text-blue-100 mb-2">
460
+ What happens next?
461
+ </h4>
462
+ <ol className="list-decimal list-inside space-y-1 text-sm text-blue-800 dark:text-blue-200">
463
+ <li>Initialize TaskMaster project structure</li>
464
+ <li>Save your PRD to <code>.taskmaster/docs/prd.txt</code></li>
465
+ <li>Generate initial tasks from your PRD</li>
466
+ <li>Set up project configuration and rules</li>
467
+ </ol>
468
+ </div>
469
+ </div>
470
+ );
471
+
472
+ default:
473
+ return null;
474
+ }
475
+ };
476
+
477
+ if (!isOpen) return null;
478
+
479
+ return (
480
+ <div className="modal-backdrop fixed inset-0 flex items-center justify-center z-[100] md:p-4 bg-black/50">
481
+ <div className={cn(
482
+ 'bg-white dark:bg-gray-900 border border-gray-200 dark:border-gray-700 md:rounded-lg shadow-xl',
483
+ 'w-full md:max-w-4xl h-full md:h-[90vh] flex flex-col',
484
+ className
485
+ )}>
486
+ {/* Header */}
487
+ <div className="flex items-center justify-between p-4 md:p-6 border-b border-gray-200 dark:border-gray-700 flex-shrink-0">
488
+ <div className="flex items-center gap-3">
489
+ <Sparkles className="w-6 h-6 text-blue-600" />
490
+ <div>
491
+ <h1 className="text-xl font-semibold text-gray-900 dark:text-white">
492
+ TaskMaster Setup Wizard
493
+ </h1>
494
+ <p className="text-sm text-gray-600 dark:text-gray-400">
495
+ Step {currentStep} of {totalSteps}: {steps[currentStep - 1]?.description}
496
+ </p>
497
+ </div>
498
+ </div>
499
+
500
+ <button
501
+ onClick={onClose}
502
+ className="p-2 text-gray-500 hover:text-gray-700 hover:bg-gray-100 dark:hover:bg-gray-800 rounded-md transition-colors"
503
+ title="Close"
504
+ >
505
+ <X className="w-5 h-5" />
506
+ </button>
507
+ </div>
508
+
509
+ {/* Progress Bar */}
510
+ <div className="px-4 md:px-6 py-4 border-b border-gray-200 dark:border-gray-700">
511
+ <div className="flex items-center justify-between mb-2">
512
+ {steps.map((step, index) => (
513
+ <div key={step.id} className="flex items-center">
514
+ <div className={cn(
515
+ 'w-8 h-8 rounded-full flex items-center justify-center text-sm font-medium transition-colors',
516
+ currentStep > step.id
517
+ ? 'bg-green-500 text-white'
518
+ : currentStep === step.id
519
+ ? 'bg-blue-500 text-white'
520
+ : 'bg-gray-200 dark:bg-gray-700 text-gray-600 dark:text-gray-400'
521
+ )}>
522
+ {currentStep > step.id ? (
523
+ <CheckCircle className="w-4 h-4" />
524
+ ) : (
525
+ step.id
526
+ )}
527
+ </div>
528
+ {index < steps.length - 1 && (
529
+ <div className={cn(
530
+ 'w-16 h-1 mx-2 rounded',
531
+ currentStep > step.id
532
+ ? 'bg-green-500'
533
+ : 'bg-gray-200 dark:bg-gray-700'
534
+ )} />
535
+ )}
536
+ </div>
537
+ ))}
538
+ </div>
539
+ <div className="flex justify-between text-xs text-gray-600 dark:text-gray-400">
540
+ {steps.map(step => (
541
+ <span key={step.id} className="text-center">
542
+ {step.title}
543
+ </span>
544
+ ))}
545
+ </div>
546
+ </div>
547
+
548
+ {/* Content */}
549
+ <div className="flex-1 overflow-y-auto p-4 md:p-6">
550
+ {renderStepContent()}
551
+
552
+ {error && (
553
+ <div className="mt-4 bg-red-50 dark:bg-red-950 border border-red-200 dark:border-red-800 rounded-lg p-4">
554
+ <div className="flex items-start gap-3">
555
+ <AlertCircle className="w-5 h-5 text-red-600 dark:text-red-400 mt-0.5" />
556
+ <div>
557
+ <h4 className="font-medium text-red-900 dark:text-red-100 mb-1">Error</h4>
558
+ <p className="text-sm text-red-800 dark:text-red-200">{error}</p>
559
+ </div>
560
+ </div>
561
+ </div>
562
+ )}
563
+ </div>
564
+
565
+ {/* Footer */}
566
+ <div className="flex items-center justify-between p-4 md:p-6 border-t border-gray-200 dark:border-gray-700 flex-shrink-0">
567
+ <button
568
+ onClick={handlePrevious}
569
+ disabled={currentStep === 1}
570
+ className="flex items-center gap-2 px-4 py-2 text-gray-700 dark:text-gray-300 bg-gray-100 dark:bg-gray-800 hover:bg-gray-200 dark:hover:bg-gray-700 rounded-md transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
571
+ >
572
+ <ChevronLeft className="w-4 h-4" />
573
+ Previous
574
+ </button>
575
+
576
+ <div className="text-sm text-gray-500 dark:text-gray-400">
577
+ {currentStep} of {totalSteps}
578
+ </div>
579
+
580
+ <button
581
+ onClick={handleNext}
582
+ disabled={loading}
583
+ className="flex items-center gap-2 px-4 py-2 bg-blue-600 hover:bg-blue-700 text-white rounded-md transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
584
+ >
585
+ {loading ? (
586
+ <>
587
+ <div className="animate-spin rounded-full h-4 w-4 border-b-2 border-white"></div>
588
+ {currentStep === totalSteps ? 'Setting up...' : 'Processing...'}
589
+ </>
590
+ ) : (
591
+ <>
592
+ {currentStep === totalSteps ? 'Complete Setup' : 'Next'}
593
+ <ChevronRight className="w-4 h-4" />
594
+ </>
595
+ )}
596
+ </button>
597
+ </div>
598
+ </div>
599
+ </div>
600
+ );
601
+ };
602
+
603
+ export default TaskMasterSetupWizard;
@@ -0,0 +1,86 @@
1
+ import React from 'react';
2
+ import { useTaskMaster } from '../contexts/TaskMasterContext';
3
+ import TaskIndicator from './TaskIndicator';
4
+
5
+ const TaskMasterStatus = () => {
6
+ const {
7
+ currentProject,
8
+ projectTaskMaster,
9
+ mcpServerStatus,
10
+ isLoading,
11
+ isLoadingMCP,
12
+ error
13
+ } = useTaskMaster();
14
+
15
+ if (isLoading || isLoadingMCP) {
16
+ return (
17
+ <div className="flex items-center text-sm text-gray-500 dark:text-gray-400">
18
+ <div className="animate-spin w-3 h-3 border border-gray-300 border-t-blue-500 rounded-full mr-2"></div>
19
+ Loading TaskMaster status...
20
+ </div>
21
+ );
22
+ }
23
+
24
+ if (error) {
25
+ return (
26
+ <div className="flex items-center text-sm text-red-500 dark:text-red-400">
27
+ <span className="w-2 h-2 bg-red-500 rounded-full mr-2"></span>
28
+ TaskMaster Error
29
+ </div>
30
+ );
31
+ }
32
+
33
+ // Show MCP server status
34
+ const mcpConfigured = mcpServerStatus?.hasMCPServer && mcpServerStatus?.isConfigured;
35
+
36
+ // Show project TaskMaster status
37
+ const projectConfigured = currentProject?.taskmaster?.hasTaskmaster;
38
+ const taskCount = currentProject?.taskmaster?.metadata?.taskCount || 0;
39
+ const completedCount = currentProject?.taskmaster?.metadata?.completed || 0;
40
+
41
+ if (!currentProject) {
42
+ return (
43
+ <div className="flex items-center text-sm text-gray-500 dark:text-gray-400">
44
+ <span className="w-2 h-2 bg-gray-400 rounded-full mr-2"></span>
45
+ No project selected
46
+ </div>
47
+ );
48
+ }
49
+
50
+ // Determine overall status for TaskIndicator
51
+ let overallStatus = 'not-configured';
52
+ if (projectConfigured && mcpConfigured) {
53
+ overallStatus = 'fully-configured';
54
+ } else if (projectConfigured) {
55
+ overallStatus = 'taskmaster-only';
56
+ } else if (mcpConfigured) {
57
+ overallStatus = 'mcp-only';
58
+ }
59
+
60
+ return (
61
+ <div className="flex items-center gap-3">
62
+ {/* TaskMaster Status Indicator */}
63
+ <TaskIndicator
64
+ status={overallStatus}
65
+ size="md"
66
+ showLabel={true}
67
+ />
68
+
69
+ {/* Task Progress Info */}
70
+ {projectConfigured && (
71
+ <div className="text-xs text-gray-600 dark:text-gray-400">
72
+ <span className="font-medium">
73
+ {completedCount}/{taskCount} tasks
74
+ </span>
75
+ {taskCount > 0 && (
76
+ <span className="ml-2 opacity-75">
77
+ ({Math.round((completedCount / taskCount) * 100)}%)
78
+ </span>
79
+ )}
80
+ </div>
81
+ )}
82
+ </div>
83
+ );
84
+ };
85
+
86
+ export default TaskMasterStatus;