@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,44 @@
1
+ import React from 'react';
2
+ import { useAuth } from '../contexts/AuthContext';
3
+ import SetupForm from './SetupForm';
4
+ import LoginForm from './LoginForm';
5
+ import { MessageSquare } from 'lucide-react';
6
+
7
+ const LoadingScreen = () => (
8
+ <div className="min-h-screen bg-background flex items-center justify-center p-4">
9
+ <div className="text-center">
10
+ <div className="flex justify-center mb-4">
11
+ <div className="w-16 h-16 bg-primary rounded-lg flex items-center justify-center shadow-sm">
12
+ <MessageSquare className="w-8 h-8 text-primary-foreground" />
13
+ </div>
14
+ </div>
15
+ <h1 className="text-2xl font-bold text-foreground mb-2">Claude Code UI</h1>
16
+ <div className="flex items-center justify-center space-x-2">
17
+ <div className="w-2 h-2 bg-blue-500 rounded-full animate-bounce"></div>
18
+ <div className="w-2 h-2 bg-blue-500 rounded-full animate-bounce" style={{ animationDelay: '0.1s' }}></div>
19
+ <div className="w-2 h-2 bg-blue-500 rounded-full animate-bounce" style={{ animationDelay: '0.2s' }}></div>
20
+ </div>
21
+ <p className="text-muted-foreground mt-2">Loading...</p>
22
+ </div>
23
+ </div>
24
+ );
25
+
26
+ const ProtectedRoute = ({ children }) => {
27
+ const { user, isLoading, needsSetup } = useAuth();
28
+
29
+ if (isLoading) {
30
+ return <LoadingScreen />;
31
+ }
32
+
33
+ if (needsSetup) {
34
+ return <SetupForm />;
35
+ }
36
+
37
+ if (!user) {
38
+ return <LoginForm />;
39
+ }
40
+
41
+ return children;
42
+ };
43
+
44
+ export default ProtectedRoute;
@@ -0,0 +1,262 @@
1
+ import React, { useState, useEffect } from 'react';
2
+ import {
3
+ ChevronLeft,
4
+ ChevronRight,
5
+ Maximize2,
6
+ Eye,
7
+ Settings2,
8
+ Moon,
9
+ Sun,
10
+ ArrowDown,
11
+ Mic,
12
+ Brain,
13
+ Sparkles,
14
+ FileText,
15
+ Languages
16
+ } from 'lucide-react';
17
+ import DarkModeToggle from './DarkModeToggle';
18
+ import { useTheme } from '../contexts/ThemeContext';
19
+
20
+ const QuickSettingsPanel = ({
21
+ isOpen,
22
+ onToggle,
23
+ autoExpandTools,
24
+ onAutoExpandChange,
25
+ showRawParameters,
26
+ onShowRawParametersChange,
27
+ autoScrollToBottom,
28
+ onAutoScrollChange,
29
+ sendByCtrlEnter,
30
+ onSendByCtrlEnterChange,
31
+ isMobile
32
+ }) => {
33
+ const [localIsOpen, setLocalIsOpen] = useState(isOpen);
34
+ const [whisperMode, setWhisperMode] = useState(() => {
35
+ return localStorage.getItem('whisperMode') || 'default';
36
+ });
37
+ const { isDarkMode } = useTheme();
38
+
39
+ useEffect(() => {
40
+ setLocalIsOpen(isOpen);
41
+ }, [isOpen]);
42
+
43
+ const handleToggle = () => {
44
+ const newState = !localIsOpen;
45
+ setLocalIsOpen(newState);
46
+ onToggle(newState);
47
+ };
48
+
49
+ return (
50
+ <>
51
+ {/* Pull Tab */}
52
+ <div
53
+ className={`fixed ${isMobile ? 'bottom-44' : 'top-1/2 -translate-y-1/2'} ${
54
+ localIsOpen ? 'right-64' : 'right-0'
55
+ } z-50 transition-all duration-150 ease-out`}
56
+ >
57
+ <button
58
+ onClick={handleToggle}
59
+ className="bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-l-md p-2 hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors shadow-lg"
60
+ aria-label={localIsOpen ? 'Close settings panel' : 'Open settings panel'}
61
+ >
62
+ {localIsOpen ? (
63
+ <ChevronRight className="h-5 w-5 text-gray-600 dark:text-gray-400" />
64
+ ) : (
65
+ <ChevronLeft className="h-5 w-5 text-gray-600 dark:text-gray-400" />
66
+ )}
67
+ </button>
68
+ </div>
69
+
70
+ {/* Panel */}
71
+ <div
72
+ className={`fixed top-0 right-0 h-full w-64 bg-white dark:bg-gray-900 border-l border-gray-200 dark:border-gray-700 shadow-xl transform transition-transform duration-150 ease-out z-40 ${
73
+ localIsOpen ? 'translate-x-0' : 'translate-x-full'
74
+ } ${isMobile ? 'h-screen' : ''}`}
75
+ >
76
+ <div className="h-full flex flex-col">
77
+ {/* Header */}
78
+ <div className="p-4 border-b border-gray-200 dark:border-gray-700 bg-gray-50 dark:bg-gray-900">
79
+ <h3 className="text-lg font-semibold text-gray-900 dark:text-white flex items-center gap-2">
80
+ <Settings2 className="h-5 w-5 text-gray-600 dark:text-gray-400" />
81
+ Quick Settings
82
+ </h3>
83
+ </div>
84
+
85
+ {/* Settings Content */}
86
+ <div className={`flex-1 overflow-y-auto overflow-x-hidden p-4 space-y-6 bg-white dark:bg-gray-900 ${isMobile ? 'pb-20' : ''}`}>
87
+ {/* Appearance Settings */}
88
+ <div className="space-y-2">
89
+ <h4 className="text-xs font-semibold uppercase tracking-wider text-gray-500 dark:text-gray-400 mb-2">Appearance</h4>
90
+
91
+ <div className="flex items-center justify-between p-3 rounded-lg bg-gray-50 dark:bg-gray-800 hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors border border-transparent hover:border-gray-300 dark:hover:border-gray-600">
92
+ <span className="flex items-center gap-2 text-sm text-gray-900 dark:text-white">
93
+ {isDarkMode ? <Moon className="h-4 w-4 text-gray-600 dark:text-gray-400" /> : <Sun className="h-4 w-4 text-gray-600 dark:text-gray-400" />}
94
+ Dark Mode
95
+ </span>
96
+ <DarkModeToggle />
97
+ </div>
98
+ </div>
99
+
100
+ {/* Tool Display Settings */}
101
+ <div className="space-y-2">
102
+ <h4 className="text-xs font-semibold uppercase tracking-wider text-gray-500 dark:text-gray-400 mb-2">Tool Display</h4>
103
+
104
+ <label className="flex items-center justify-between p-3 rounded-lg bg-gray-50 dark:bg-gray-800 hover:bg-gray-100 dark:hover:bg-gray-700 cursor-pointer transition-colors border border-transparent hover:border-gray-300 dark:hover:border-gray-600">
105
+ <span className="flex items-center gap-2 text-sm text-gray-900 dark:text-white">
106
+ <Maximize2 className="h-4 w-4 text-gray-600 dark:text-gray-400" />
107
+ Auto-expand tools
108
+ </span>
109
+ <input
110
+ type="checkbox"
111
+ checked={autoExpandTools}
112
+ onChange={(e) => onAutoExpandChange(e.target.checked)}
113
+ className="h-4 w-4 rounded border-gray-300 dark:border-gray-600 text-blue-600 dark:text-blue-500 focus:ring-blue-500 dark:focus:ring-blue-400 dark:bg-gray-800 dark:checked:bg-blue-600"
114
+ />
115
+ </label>
116
+
117
+ <label className="flex items-center justify-between p-3 rounded-lg bg-gray-50 dark:bg-gray-800 hover:bg-gray-100 dark:hover:bg-gray-700 cursor-pointer transition-colors border border-transparent hover:border-gray-300 dark:hover:border-gray-600">
118
+ <span className="flex items-center gap-2 text-sm text-gray-900 dark:text-white">
119
+ <Eye className="h-4 w-4 text-gray-600 dark:text-gray-400" />
120
+ Show raw parameters
121
+ </span>
122
+ <input
123
+ type="checkbox"
124
+ checked={showRawParameters}
125
+ onChange={(e) => onShowRawParametersChange(e.target.checked)}
126
+ className="h-4 w-4 rounded border-gray-300 dark:border-gray-600 text-blue-600 dark:text-blue-500 focus:ring-blue-500 dark:focus:ring-blue-400 dark:bg-gray-800 dark:checked:bg-blue-600"
127
+ />
128
+ </label>
129
+ </div>
130
+ {/* View Options */}
131
+ <div className="space-y-2">
132
+ <h4 className="text-xs font-semibold uppercase tracking-wider text-gray-500 dark:text-gray-400 mb-2">View Options</h4>
133
+
134
+ <label className="flex items-center justify-between p-3 rounded-lg bg-gray-50 dark:bg-gray-800 hover:bg-gray-100 dark:hover:bg-gray-700 cursor-pointer transition-colors border border-transparent hover:border-gray-300 dark:hover:border-gray-600">
135
+ <span className="flex items-center gap-2 text-sm text-gray-900 dark:text-white">
136
+ <ArrowDown className="h-4 w-4 text-gray-600 dark:text-gray-400" />
137
+ Auto-scroll to bottom
138
+ </span>
139
+ <input
140
+ type="checkbox"
141
+ checked={autoScrollToBottom}
142
+ onChange={(e) => onAutoScrollChange(e.target.checked)}
143
+ className="h-4 w-4 rounded border-gray-300 dark:border-gray-600 text-blue-600 dark:text-blue-500 focus:ring-blue-500 dark:focus:ring-blue-400 dark:bg-gray-800 dark:checked:bg-blue-600"
144
+ />
145
+ </label>
146
+ </div>
147
+
148
+ {/* Input Settings */}
149
+ <div className="space-y-2">
150
+ <h4 className="text-xs font-semibold uppercase tracking-wider text-gray-500 dark:text-gray-400 mb-2">Input Settings</h4>
151
+
152
+ <label className="flex items-center justify-between p-3 rounded-lg bg-gray-50 dark:bg-gray-800 hover:bg-gray-100 dark:hover:bg-gray-700 cursor-pointer transition-colors border border-transparent hover:border-gray-300 dark:hover:border-gray-600">
153
+ <span className="flex items-center gap-2 text-sm text-gray-900 dark:text-white">
154
+ <Languages className="h-4 w-4 text-gray-600 dark:text-gray-400" />
155
+ Send by Ctrl+Enter
156
+ </span>
157
+ <input
158
+ type="checkbox"
159
+ checked={sendByCtrlEnter}
160
+ onChange={(e) => onSendByCtrlEnterChange(e.target.checked)}
161
+ className="h-4 w-4 rounded border-gray-300 dark:border-gray-600 text-blue-600 dark:text-blue-500 focus:ring-blue-500 dark:focus:ring-blue-400 dark:bg-gray-800 dark:checked:bg-blue-600"
162
+ />
163
+ </label>
164
+ <p className="text-xs text-gray-500 dark:text-gray-400 ml-3">
165
+ When enabled, pressing Ctrl+Enter will send the message instead of just Enter. This is useful for IME users to avoid accidental sends.
166
+ </p>
167
+ </div>
168
+
169
+ {/* Whisper Dictation Settings - HIDDEN */}
170
+ <div className="space-y-2" style={{ display: 'none' }}>
171
+ <h4 className="text-xs font-semibold uppercase tracking-wider text-gray-500 dark:text-gray-400 mb-2">Whisper Dictation</h4>
172
+
173
+ <div className="space-y-2">
174
+ <label className="flex items-start p-3 rounded-lg bg-gray-50 dark:bg-gray-800 hover:bg-gray-100 dark:hover:bg-gray-700 cursor-pointer transition-colors border border-transparent hover:border-gray-300 dark:hover:border-gray-600">
175
+ <input
176
+ type="radio"
177
+ name="whisperMode"
178
+ value="default"
179
+ checked={whisperMode === 'default'}
180
+ onChange={() => {
181
+ setWhisperMode('default');
182
+ localStorage.setItem('whisperMode', 'default');
183
+ window.dispatchEvent(new Event('whisperModeChanged'));
184
+ }}
185
+ className="mt-0.5 h-4 w-4 border-gray-300 dark:border-gray-600 text-blue-600 dark:text-blue-500 focus:ring-blue-500 dark:focus:ring-blue-400 dark:bg-gray-800 dark:checked:bg-blue-600"
186
+ />
187
+ <div className="ml-3 flex-1">
188
+ <span className="flex items-center gap-2 text-sm font-medium text-gray-900 dark:text-white">
189
+ <Mic className="h-4 w-4 text-gray-600 dark:text-gray-400" />
190
+ Default Mode
191
+ </span>
192
+ <p className="text-xs text-gray-500 dark:text-gray-400 mt-1">
193
+ Direct transcription of your speech
194
+ </p>
195
+ </div>
196
+ </label>
197
+
198
+ <label className="flex items-start p-3 rounded-lg bg-gray-50 dark:bg-gray-800 hover:bg-gray-100 dark:hover:bg-gray-700 cursor-pointer transition-colors border border-transparent hover:border-gray-300 dark:hover:border-gray-600">
199
+ <input
200
+ type="radio"
201
+ name="whisperMode"
202
+ value="prompt"
203
+ checked={whisperMode === 'prompt'}
204
+ onChange={() => {
205
+ setWhisperMode('prompt');
206
+ localStorage.setItem('whisperMode', 'prompt');
207
+ window.dispatchEvent(new Event('whisperModeChanged'));
208
+ }}
209
+ className="mt-0.5 h-4 w-4 border-gray-300 dark:border-gray-600 text-blue-600 dark:text-blue-500 focus:ring-blue-500 dark:focus:ring-blue-400 dark:bg-gray-800 dark:checked:bg-blue-600"
210
+ />
211
+ <div className="ml-3 flex-1">
212
+ <span className="flex items-center gap-2 text-sm font-medium text-gray-900 dark:text-white">
213
+ <Sparkles className="h-4 w-4 text-gray-600 dark:text-gray-400" />
214
+ Prompt Enhancement
215
+ </span>
216
+ <p className="text-xs text-gray-500 dark:text-gray-400 mt-1">
217
+ Transform rough ideas into clear, detailed AI prompts
218
+ </p>
219
+ </div>
220
+ </label>
221
+
222
+ <label className="flex items-start p-3 rounded-lg bg-gray-50 dark:bg-gray-800 hover:bg-gray-100 dark:hover:bg-gray-700 cursor-pointer transition-colors border border-transparent hover:border-gray-300 dark:hover:border-gray-600">
223
+ <input
224
+ type="radio"
225
+ name="whisperMode"
226
+ value="vibe"
227
+ checked={whisperMode === 'vibe' || whisperMode === 'instructions' || whisperMode === 'architect'}
228
+ onChange={() => {
229
+ setWhisperMode('vibe');
230
+ localStorage.setItem('whisperMode', 'vibe');
231
+ window.dispatchEvent(new Event('whisperModeChanged'));
232
+ }}
233
+ className="mt-0.5 h-4 w-4 border-gray-300 dark:border-gray-600 text-blue-600 dark:text-blue-500 focus:ring-blue-500 dark:focus:ring-blue-400 dark:bg-gray-800 dark:checked:bg-blue-600"
234
+ />
235
+ <div className="ml-3 flex-1">
236
+ <span className="flex items-center gap-2 text-sm font-medium text-gray-900 dark:text-white">
237
+ <FileText className="h-4 w-4 text-gray-600 dark:text-gray-400" />
238
+ Vibe Mode
239
+ </span>
240
+ <p className="text-xs text-gray-500 dark:text-gray-400 mt-1">
241
+ Format ideas as clear agent instructions with details
242
+ </p>
243
+ </div>
244
+ </label>
245
+ </div>
246
+ </div>
247
+ </div>
248
+ </div>
249
+ </div>
250
+
251
+ {/* Backdrop */}
252
+ {localIsOpen && (
253
+ <div
254
+ className="fixed inset-0 bg-background/80 backdrop-blur-sm z-30 transition-opacity duration-150 ease-out"
255
+ onClick={handleToggle}
256
+ />
257
+ )}
258
+ </>
259
+ );
260
+ };
261
+
262
+ export default QuickSettingsPanel;