@epiphytic/claudecodeui 1.0.0

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 (142) hide show
  1. package/LICENSE +675 -0
  2. package/README.md +414 -0
  3. package/dist/api-docs.html +879 -0
  4. package/dist/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
  5. package/dist/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
  6. package/dist/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
  7. package/dist/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
  8. package/dist/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
  9. package/dist/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
  10. package/dist/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
  11. package/dist/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
  12. package/dist/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
  13. package/dist/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
  14. package/dist/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
  15. package/dist/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
  16. package/dist/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
  17. package/dist/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
  18. package/dist/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
  19. package/dist/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
  20. package/dist/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
  21. package/dist/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
  22. package/dist/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
  23. package/dist/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
  24. package/dist/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
  25. package/dist/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
  26. package/dist/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
  27. package/dist/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
  28. package/dist/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
  29. package/dist/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
  30. package/dist/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
  31. package/dist/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
  32. package/dist/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
  33. package/dist/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
  34. package/dist/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
  35. package/dist/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
  36. package/dist/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
  37. package/dist/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
  38. package/dist/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
  39. package/dist/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
  40. package/dist/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
  41. package/dist/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
  42. package/dist/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
  43. package/dist/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
  44. package/dist/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
  45. package/dist/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
  46. package/dist/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
  47. package/dist/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
  48. package/dist/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
  49. package/dist/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
  50. package/dist/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
  51. package/dist/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
  52. package/dist/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
  53. package/dist/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
  54. package/dist/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
  55. package/dist/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
  56. package/dist/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
  57. package/dist/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
  58. package/dist/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
  59. package/dist/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
  60. package/dist/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
  61. package/dist/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
  62. package/dist/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
  63. package/dist/assets/index-DfR9xEkp.css +32 -0
  64. package/dist/assets/index-DvlVn6Eb.js +1231 -0
  65. package/dist/assets/vendor-codemirror-CJLzwpLB.js +39 -0
  66. package/dist/assets/vendor-react-DcyRfQm3.js +59 -0
  67. package/dist/assets/vendor-xterm-DfaPXD3y.js +66 -0
  68. package/dist/clear-cache.html +85 -0
  69. package/dist/convert-icons.md +53 -0
  70. package/dist/favicon.png +0 -0
  71. package/dist/favicon.svg +9 -0
  72. package/dist/generate-icons.js +49 -0
  73. package/dist/icons/claude-ai-icon.svg +1 -0
  74. package/dist/icons/codex-white.svg +3 -0
  75. package/dist/icons/codex.svg +3 -0
  76. package/dist/icons/cursor-white.svg +12 -0
  77. package/dist/icons/cursor.svg +1 -0
  78. package/dist/icons/generate-icons.md +19 -0
  79. package/dist/icons/icon-128x128.png +0 -0
  80. package/dist/icons/icon-128x128.svg +12 -0
  81. package/dist/icons/icon-144x144.png +0 -0
  82. package/dist/icons/icon-144x144.svg +12 -0
  83. package/dist/icons/icon-152x152.png +0 -0
  84. package/dist/icons/icon-152x152.svg +12 -0
  85. package/dist/icons/icon-192x192.png +0 -0
  86. package/dist/icons/icon-192x192.svg +12 -0
  87. package/dist/icons/icon-384x384.png +0 -0
  88. package/dist/icons/icon-384x384.svg +12 -0
  89. package/dist/icons/icon-512x512.png +0 -0
  90. package/dist/icons/icon-512x512.svg +12 -0
  91. package/dist/icons/icon-72x72.png +0 -0
  92. package/dist/icons/icon-72x72.svg +12 -0
  93. package/dist/icons/icon-96x96.png +0 -0
  94. package/dist/icons/icon-96x96.svg +12 -0
  95. package/dist/icons/icon-template.svg +12 -0
  96. package/dist/index.html +52 -0
  97. package/dist/logo-128.png +0 -0
  98. package/dist/logo-256.png +0 -0
  99. package/dist/logo-32.png +0 -0
  100. package/dist/logo-512.png +0 -0
  101. package/dist/logo-64.png +0 -0
  102. package/dist/logo.svg +17 -0
  103. package/dist/manifest.json +61 -0
  104. package/dist/screenshots/cli-selection.png +0 -0
  105. package/dist/screenshots/desktop-main.png +0 -0
  106. package/dist/screenshots/mobile-chat.png +0 -0
  107. package/dist/screenshots/tools-modal.png +0 -0
  108. package/dist/sw.js +107 -0
  109. package/package.json +120 -0
  110. package/server/claude-sdk.js +721 -0
  111. package/server/cli.js +469 -0
  112. package/server/cursor-cli.js +267 -0
  113. package/server/database/db.js +554 -0
  114. package/server/database/init.sql +54 -0
  115. package/server/index.js +2120 -0
  116. package/server/middleware/auth.js +161 -0
  117. package/server/openai-codex.js +389 -0
  118. package/server/orchestrator/client.js +989 -0
  119. package/server/orchestrator/github-auth.js +308 -0
  120. package/server/orchestrator/index.js +216 -0
  121. package/server/orchestrator/protocol.js +299 -0
  122. package/server/orchestrator/proxy.js +364 -0
  123. package/server/orchestrator/status-tracker.js +226 -0
  124. package/server/projects.js +1604 -0
  125. package/server/routes/agent.js +1230 -0
  126. package/server/routes/auth.js +135 -0
  127. package/server/routes/cli-auth.js +341 -0
  128. package/server/routes/codex.js +345 -0
  129. package/server/routes/commands.js +521 -0
  130. package/server/routes/cursor.js +795 -0
  131. package/server/routes/git.js +1128 -0
  132. package/server/routes/mcp-utils.js +48 -0
  133. package/server/routes/mcp.js +650 -0
  134. package/server/routes/projects.js +378 -0
  135. package/server/routes/settings.js +178 -0
  136. package/server/routes/taskmaster.js +1963 -0
  137. package/server/routes/user.js +106 -0
  138. package/server/utils/commandParser.js +303 -0
  139. package/server/utils/gitConfig.js +24 -0
  140. package/server/utils/mcp-detector.js +198 -0
  141. package/server/utils/taskmaster-websocket.js +129 -0
  142. package/shared/modelConstants.js +65 -0
@@ -0,0 +1,267 @@
1
+ import { spawn } from 'child_process';
2
+ import crossSpawn from 'cross-spawn';
3
+ import { promises as fs } from 'fs';
4
+ import path from 'path';
5
+ import os from 'os';
6
+
7
+ // Use cross-spawn on Windows for better command execution
8
+ const spawnFunction = process.platform === 'win32' ? crossSpawn : spawn;
9
+
10
+ let activeCursorProcesses = new Map(); // Track active processes by session ID
11
+
12
+ async function spawnCursor(command, options = {}, ws) {
13
+ return new Promise(async (resolve, reject) => {
14
+ const { sessionId, projectPath, cwd, resume, toolsSettings, skipPermissions, model, images } = options;
15
+ let capturedSessionId = sessionId; // Track session ID throughout the process
16
+ let sessionCreatedSent = false; // Track if we've already sent session-created event
17
+ let messageBuffer = ''; // Buffer for accumulating assistant messages
18
+
19
+ // Use tools settings passed from frontend, or defaults
20
+ const settings = toolsSettings || {
21
+ allowedShellCommands: [],
22
+ skipPermissions: false
23
+ };
24
+
25
+ // Build Cursor CLI command
26
+ const args = [];
27
+
28
+ // Build flags allowing both resume and prompt together (reply in existing session)
29
+ // Treat presence of sessionId as intention to resume, regardless of resume flag
30
+ if (sessionId) {
31
+ args.push('--resume=' + sessionId);
32
+ }
33
+
34
+ if (command && command.trim()) {
35
+ // Provide a prompt (works for both new and resumed sessions)
36
+ args.push('-p', command);
37
+
38
+ // Add model flag if specified (only meaningful for new sessions; harmless on resume)
39
+ if (!sessionId && model) {
40
+ args.push('--model', model);
41
+ }
42
+
43
+ // Request streaming JSON when we are providing a prompt
44
+ args.push('--output-format', 'stream-json');
45
+ }
46
+
47
+ // Add skip permissions flag if enabled
48
+ if (skipPermissions || settings.skipPermissions) {
49
+ args.push('-f');
50
+ console.log('⚠️ Using -f flag (skip permissions)');
51
+ }
52
+
53
+ // Use cwd (actual project directory) instead of projectPath
54
+ const workingDir = cwd || projectPath || process.cwd();
55
+
56
+ console.log('Spawning Cursor CLI:', 'cursor-agent', args.join(' '));
57
+ console.log('Working directory:', workingDir);
58
+ console.log('Session info - Input sessionId:', sessionId, 'Resume:', resume);
59
+
60
+ const cursorProcess = spawnFunction('cursor-agent', args, {
61
+ cwd: workingDir,
62
+ stdio: ['pipe', 'pipe', 'pipe'],
63
+ env: { ...process.env } // Inherit all environment variables
64
+ });
65
+
66
+ // Store process reference for potential abort
67
+ const processKey = capturedSessionId || Date.now().toString();
68
+ activeCursorProcesses.set(processKey, cursorProcess);
69
+
70
+ // Handle stdout (streaming JSON responses)
71
+ cursorProcess.stdout.on('data', (data) => {
72
+ const rawOutput = data.toString();
73
+ console.log('📤 Cursor CLI stdout:', rawOutput);
74
+
75
+ const lines = rawOutput.split('\n').filter(line => line.trim());
76
+
77
+ for (const line of lines) {
78
+ try {
79
+ const response = JSON.parse(line);
80
+ console.log('📄 Parsed JSON response:', response);
81
+
82
+ // Handle different message types
83
+ switch (response.type) {
84
+ case 'system':
85
+ if (response.subtype === 'init') {
86
+ // Capture session ID
87
+ if (response.session_id && !capturedSessionId) {
88
+ capturedSessionId = response.session_id;
89
+ console.log('📝 Captured session ID:', capturedSessionId);
90
+
91
+ // Update process key with captured session ID
92
+ if (processKey !== capturedSessionId) {
93
+ activeCursorProcesses.delete(processKey);
94
+ activeCursorProcesses.set(capturedSessionId, cursorProcess);
95
+ }
96
+
97
+ // Set session ID on writer (for API endpoint compatibility)
98
+ if (ws.setSessionId && typeof ws.setSessionId === 'function') {
99
+ ws.setSessionId(capturedSessionId);
100
+ }
101
+
102
+ // Send session-created event only once for new sessions
103
+ if (!sessionId && !sessionCreatedSent) {
104
+ sessionCreatedSent = true;
105
+ ws.send({
106
+ type: 'session-created',
107
+ sessionId: capturedSessionId,
108
+ model: response.model,
109
+ cwd: response.cwd
110
+ });
111
+ }
112
+ }
113
+
114
+ // Send system info to frontend
115
+ ws.send({
116
+ type: 'cursor-system',
117
+ data: response
118
+ });
119
+ }
120
+ break;
121
+
122
+ case 'user':
123
+ // Forward user message
124
+ ws.send({
125
+ type: 'cursor-user',
126
+ data: response
127
+ });
128
+ break;
129
+
130
+ case 'assistant':
131
+ // Accumulate assistant message chunks
132
+ if (response.message && response.message.content && response.message.content.length > 0) {
133
+ const textContent = response.message.content[0].text;
134
+ messageBuffer += textContent;
135
+
136
+ // Send as Claude-compatible format for frontend
137
+ ws.send({
138
+ type: 'claude-response',
139
+ data: {
140
+ type: 'content_block_delta',
141
+ delta: {
142
+ type: 'text_delta',
143
+ text: textContent
144
+ }
145
+ }
146
+ });
147
+ }
148
+ break;
149
+
150
+ case 'result':
151
+ // Session complete
152
+ console.log('Cursor session result:', response);
153
+
154
+ // Send final message if we have buffered content
155
+ if (messageBuffer) {
156
+ ws.send({
157
+ type: 'claude-response',
158
+ data: {
159
+ type: 'content_block_stop'
160
+ }
161
+ });
162
+ }
163
+
164
+ // Send completion event
165
+ ws.send({
166
+ type: 'cursor-result',
167
+ sessionId: capturedSessionId || sessionId,
168
+ data: response,
169
+ success: response.subtype === 'success'
170
+ });
171
+ break;
172
+
173
+ default:
174
+ // Forward any other message types
175
+ ws.send({
176
+ type: 'cursor-response',
177
+ data: response
178
+ });
179
+ }
180
+ } catch (parseError) {
181
+ console.log('📄 Non-JSON response:', line);
182
+ // If not JSON, send as raw text
183
+ ws.send({
184
+ type: 'cursor-output',
185
+ data: line
186
+ });
187
+ }
188
+ }
189
+ });
190
+
191
+ // Handle stderr
192
+ cursorProcess.stderr.on('data', (data) => {
193
+ console.error('Cursor CLI stderr:', data.toString());
194
+ ws.send({
195
+ type: 'cursor-error',
196
+ error: data.toString()
197
+ });
198
+ });
199
+
200
+ // Handle process completion
201
+ cursorProcess.on('close', async (code) => {
202
+ console.log(`Cursor CLI process exited with code ${code}`);
203
+
204
+ // Clean up process reference
205
+ const finalSessionId = capturedSessionId || sessionId || processKey;
206
+ activeCursorProcesses.delete(finalSessionId);
207
+
208
+ ws.send({
209
+ type: 'claude-complete',
210
+ sessionId: finalSessionId,
211
+ exitCode: code,
212
+ isNewSession: !sessionId && !!command // Flag to indicate this was a new session
213
+ });
214
+
215
+ if (code === 0) {
216
+ resolve();
217
+ } else {
218
+ reject(new Error(`Cursor CLI exited with code ${code}`));
219
+ }
220
+ });
221
+
222
+ // Handle process errors
223
+ cursorProcess.on('error', (error) => {
224
+ console.error('Cursor CLI process error:', error);
225
+
226
+ // Clean up process reference on error
227
+ const finalSessionId = capturedSessionId || sessionId || processKey;
228
+ activeCursorProcesses.delete(finalSessionId);
229
+
230
+ ws.send({
231
+ type: 'cursor-error',
232
+ error: error.message
233
+ });
234
+
235
+ reject(error);
236
+ });
237
+
238
+ // Close stdin since Cursor doesn't need interactive input
239
+ cursorProcess.stdin.end();
240
+ });
241
+ }
242
+
243
+ function abortCursorSession(sessionId) {
244
+ const process = activeCursorProcesses.get(sessionId);
245
+ if (process) {
246
+ console.log(`🛑 Aborting Cursor session: ${sessionId}`);
247
+ process.kill('SIGTERM');
248
+ activeCursorProcesses.delete(sessionId);
249
+ return true;
250
+ }
251
+ return false;
252
+ }
253
+
254
+ function isCursorSessionActive(sessionId) {
255
+ return activeCursorProcesses.has(sessionId);
256
+ }
257
+
258
+ function getActiveCursorSessions() {
259
+ return Array.from(activeCursorProcesses.keys());
260
+ }
261
+
262
+ export {
263
+ spawnCursor,
264
+ abortCursorSession,
265
+ isCursorSessionActive,
266
+ getActiveCursorSessions
267
+ };