@siteboon/claude-code-ui 1.13.0 → 1.13.1
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.
- package/dist/api-docs.html +30 -8
- package/dist/assets/{index-Zq2roSUR.js → index-BL1HpeHJ.js} +156 -156
- package/dist/index.html +1 -1
- package/package.json +1 -1
- package/server/claude-sdk.js +12 -11
- package/server/cursor-cli.js +24 -24
- package/server/index.js +43 -14
- package/server/openai-codex.js +7 -6
- package/server/routes/agent.js +13 -5
- package/server/routes/commands.js +6 -57
- package/server/routes/cursor.js +2 -1
- package/server/database/auth.db +0 -0
package/dist/index.html
CHANGED
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
|
|
26
26
|
<!-- Prevent zoom on iOS -->
|
|
27
27
|
<meta name="format-detection" content="telephone=no" />
|
|
28
|
-
<script type="module" crossorigin src="/assets/index-
|
|
28
|
+
<script type="module" crossorigin src="/assets/index-BL1HpeHJ.js"></script>
|
|
29
29
|
<link rel="modulepreload" crossorigin href="/assets/vendor-react-DVSKlM5e.js">
|
|
30
30
|
<link rel="modulepreload" crossorigin href="/assets/vendor-codemirror-CnTQH7Pk.js">
|
|
31
31
|
<link rel="modulepreload" crossorigin href="/assets/vendor-xterm-DfaPXD3y.js">
|
package/package.json
CHANGED
package/server/claude-sdk.js
CHANGED
|
@@ -16,6 +16,7 @@ import { query } from '@anthropic-ai/claude-agent-sdk';
|
|
|
16
16
|
import { promises as fs } from 'fs';
|
|
17
17
|
import path from 'path';
|
|
18
18
|
import os from 'os';
|
|
19
|
+
import { CLAUDE_MODELS } from '../shared/modelConstants.js';
|
|
19
20
|
|
|
20
21
|
// Session tracking: Map of session IDs to active query instances
|
|
21
22
|
const activeSessions = new Map();
|
|
@@ -77,7 +78,7 @@ function mapCliOptionsToSDK(options = {}) {
|
|
|
77
78
|
|
|
78
79
|
// Map model (default to sonnet)
|
|
79
80
|
// Valid models: sonnet, opus, haiku, opusplan, sonnet[1m]
|
|
80
|
-
sdkOptions.model = options.model ||
|
|
81
|
+
sdkOptions.model = options.model || CLAUDE_MODELS.DEFAULT;
|
|
81
82
|
console.log(`Using model: ${sdkOptions.model}`);
|
|
82
83
|
|
|
83
84
|
// Map system prompt configuration
|
|
@@ -397,10 +398,10 @@ async function queryClaudeSDK(command, options = {}, ws) {
|
|
|
397
398
|
// Send session-created event only once for new sessions
|
|
398
399
|
if (!sessionId && !sessionCreatedSent) {
|
|
399
400
|
sessionCreatedSent = true;
|
|
400
|
-
ws.send(
|
|
401
|
+
ws.send({
|
|
401
402
|
type: 'session-created',
|
|
402
403
|
sessionId: capturedSessionId
|
|
403
|
-
})
|
|
404
|
+
});
|
|
404
405
|
} else {
|
|
405
406
|
console.log('Not sending session-created. sessionId:', sessionId, 'sessionCreatedSent:', sessionCreatedSent);
|
|
406
407
|
}
|
|
@@ -410,20 +411,20 @@ async function queryClaudeSDK(command, options = {}, ws) {
|
|
|
410
411
|
|
|
411
412
|
// Transform and send message to WebSocket
|
|
412
413
|
const transformedMessage = transformMessage(message);
|
|
413
|
-
ws.send(
|
|
414
|
+
ws.send({
|
|
414
415
|
type: 'claude-response',
|
|
415
416
|
data: transformedMessage
|
|
416
|
-
})
|
|
417
|
+
});
|
|
417
418
|
|
|
418
419
|
// Extract and send token budget updates from result messages
|
|
419
420
|
if (message.type === 'result') {
|
|
420
421
|
const tokenBudget = extractTokenBudget(message);
|
|
421
422
|
if (tokenBudget) {
|
|
422
423
|
console.log('Token budget from modelUsage:', tokenBudget);
|
|
423
|
-
ws.send(
|
|
424
|
+
ws.send({
|
|
424
425
|
type: 'token-budget',
|
|
425
426
|
data: tokenBudget
|
|
426
|
-
})
|
|
427
|
+
});
|
|
427
428
|
}
|
|
428
429
|
}
|
|
429
430
|
}
|
|
@@ -438,12 +439,12 @@ async function queryClaudeSDK(command, options = {}, ws) {
|
|
|
438
439
|
|
|
439
440
|
// Send completion event
|
|
440
441
|
console.log('Streaming complete, sending claude-complete event');
|
|
441
|
-
ws.send(
|
|
442
|
+
ws.send({
|
|
442
443
|
type: 'claude-complete',
|
|
443
444
|
sessionId: capturedSessionId,
|
|
444
445
|
exitCode: 0,
|
|
445
446
|
isNewSession: !sessionId && !!command
|
|
446
|
-
})
|
|
447
|
+
});
|
|
447
448
|
console.log('claude-complete event sent');
|
|
448
449
|
|
|
449
450
|
} catch (error) {
|
|
@@ -458,10 +459,10 @@ async function queryClaudeSDK(command, options = {}, ws) {
|
|
|
458
459
|
await cleanupTempFiles(tempImagePaths, tempDir);
|
|
459
460
|
|
|
460
461
|
// Send error to WebSocket
|
|
461
|
-
ws.send(
|
|
462
|
+
ws.send({
|
|
462
463
|
type: 'claude-error',
|
|
463
464
|
error: error.message
|
|
464
|
-
})
|
|
465
|
+
});
|
|
465
466
|
|
|
466
467
|
throw error;
|
|
467
468
|
}
|
package/server/cursor-cli.js
CHANGED
|
@@ -102,29 +102,29 @@ async function spawnCursor(command, options = {}, ws) {
|
|
|
102
102
|
// Send session-created event only once for new sessions
|
|
103
103
|
if (!sessionId && !sessionCreatedSent) {
|
|
104
104
|
sessionCreatedSent = true;
|
|
105
|
-
ws.send(
|
|
105
|
+
ws.send({
|
|
106
106
|
type: 'session-created',
|
|
107
107
|
sessionId: capturedSessionId,
|
|
108
108
|
model: response.model,
|
|
109
109
|
cwd: response.cwd
|
|
110
|
-
})
|
|
110
|
+
});
|
|
111
111
|
}
|
|
112
112
|
}
|
|
113
113
|
|
|
114
114
|
// Send system info to frontend
|
|
115
|
-
ws.send(
|
|
115
|
+
ws.send({
|
|
116
116
|
type: 'cursor-system',
|
|
117
117
|
data: response
|
|
118
|
-
})
|
|
118
|
+
});
|
|
119
119
|
}
|
|
120
120
|
break;
|
|
121
121
|
|
|
122
122
|
case 'user':
|
|
123
123
|
// Forward user message
|
|
124
|
-
ws.send(
|
|
124
|
+
ws.send({
|
|
125
125
|
type: 'cursor-user',
|
|
126
126
|
data: response
|
|
127
|
-
})
|
|
127
|
+
});
|
|
128
128
|
break;
|
|
129
129
|
|
|
130
130
|
case 'assistant':
|
|
@@ -134,7 +134,7 @@ async function spawnCursor(command, options = {}, ws) {
|
|
|
134
134
|
messageBuffer += textContent;
|
|
135
135
|
|
|
136
136
|
// Send as Claude-compatible format for frontend
|
|
137
|
-
ws.send(
|
|
137
|
+
ws.send({
|
|
138
138
|
type: 'claude-response',
|
|
139
139
|
data: {
|
|
140
140
|
type: 'content_block_delta',
|
|
@@ -143,7 +143,7 @@ async function spawnCursor(command, options = {}, ws) {
|
|
|
143
143
|
text: textContent
|
|
144
144
|
}
|
|
145
145
|
}
|
|
146
|
-
})
|
|
146
|
+
});
|
|
147
147
|
}
|
|
148
148
|
break;
|
|
149
149
|
|
|
@@ -153,37 +153,37 @@ async function spawnCursor(command, options = {}, ws) {
|
|
|
153
153
|
|
|
154
154
|
// Send final message if we have buffered content
|
|
155
155
|
if (messageBuffer) {
|
|
156
|
-
ws.send(
|
|
156
|
+
ws.send({
|
|
157
157
|
type: 'claude-response',
|
|
158
158
|
data: {
|
|
159
159
|
type: 'content_block_stop'
|
|
160
160
|
}
|
|
161
|
-
})
|
|
161
|
+
});
|
|
162
162
|
}
|
|
163
163
|
|
|
164
164
|
// Send completion event
|
|
165
|
-
ws.send(
|
|
165
|
+
ws.send({
|
|
166
166
|
type: 'cursor-result',
|
|
167
167
|
sessionId: capturedSessionId || sessionId,
|
|
168
168
|
data: response,
|
|
169
169
|
success: response.subtype === 'success'
|
|
170
|
-
})
|
|
170
|
+
});
|
|
171
171
|
break;
|
|
172
172
|
|
|
173
173
|
default:
|
|
174
174
|
// Forward any other message types
|
|
175
|
-
ws.send(
|
|
175
|
+
ws.send({
|
|
176
176
|
type: 'cursor-response',
|
|
177
177
|
data: response
|
|
178
|
-
})
|
|
178
|
+
});
|
|
179
179
|
}
|
|
180
180
|
} catch (parseError) {
|
|
181
181
|
console.log('📄 Non-JSON response:', line);
|
|
182
182
|
// If not JSON, send as raw text
|
|
183
|
-
ws.send(
|
|
183
|
+
ws.send({
|
|
184
184
|
type: 'cursor-output',
|
|
185
185
|
data: line
|
|
186
|
-
})
|
|
186
|
+
});
|
|
187
187
|
}
|
|
188
188
|
}
|
|
189
189
|
});
|
|
@@ -191,10 +191,10 @@ async function spawnCursor(command, options = {}, ws) {
|
|
|
191
191
|
// Handle stderr
|
|
192
192
|
cursorProcess.stderr.on('data', (data) => {
|
|
193
193
|
console.error('Cursor CLI stderr:', data.toString());
|
|
194
|
-
ws.send(
|
|
194
|
+
ws.send({
|
|
195
195
|
type: 'cursor-error',
|
|
196
196
|
error: data.toString()
|
|
197
|
-
})
|
|
197
|
+
});
|
|
198
198
|
});
|
|
199
199
|
|
|
200
200
|
// Handle process completion
|
|
@@ -205,12 +205,12 @@ async function spawnCursor(command, options = {}, ws) {
|
|
|
205
205
|
const finalSessionId = capturedSessionId || sessionId || processKey;
|
|
206
206
|
activeCursorProcesses.delete(finalSessionId);
|
|
207
207
|
|
|
208
|
-
ws.send(
|
|
208
|
+
ws.send({
|
|
209
209
|
type: 'claude-complete',
|
|
210
210
|
sessionId: finalSessionId,
|
|
211
211
|
exitCode: code,
|
|
212
212
|
isNewSession: !sessionId && !!command // Flag to indicate this was a new session
|
|
213
|
-
})
|
|
213
|
+
});
|
|
214
214
|
|
|
215
215
|
if (code === 0) {
|
|
216
216
|
resolve();
|
|
@@ -226,12 +226,12 @@ async function spawnCursor(command, options = {}, ws) {
|
|
|
226
226
|
// Clean up process reference on error
|
|
227
227
|
const finalSessionId = capturedSessionId || sessionId || processKey;
|
|
228
228
|
activeCursorProcesses.delete(finalSessionId);
|
|
229
|
-
|
|
230
|
-
ws.send(
|
|
229
|
+
|
|
230
|
+
ws.send({
|
|
231
231
|
type: 'cursor-error',
|
|
232
232
|
error: error.message
|
|
233
|
-
})
|
|
234
|
-
|
|
233
|
+
});
|
|
234
|
+
|
|
235
235
|
reject(error);
|
|
236
236
|
});
|
|
237
237
|
|
package/server/index.js
CHANGED
|
@@ -717,6 +717,32 @@ wss.on('connection', (ws, request) => {
|
|
|
717
717
|
}
|
|
718
718
|
});
|
|
719
719
|
|
|
720
|
+
/**
|
|
721
|
+
* WebSocket Writer - Wrapper for WebSocket to match SSEStreamWriter interface
|
|
722
|
+
*/
|
|
723
|
+
class WebSocketWriter {
|
|
724
|
+
constructor(ws) {
|
|
725
|
+
this.ws = ws;
|
|
726
|
+
this.sessionId = null;
|
|
727
|
+
this.isWebSocketWriter = true; // Marker for transport detection
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
send(data) {
|
|
731
|
+
if (this.ws.readyState === 1) { // WebSocket.OPEN
|
|
732
|
+
// Providers send raw objects, we stringify for WebSocket
|
|
733
|
+
this.ws.send(JSON.stringify(data));
|
|
734
|
+
}
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
setSessionId(sessionId) {
|
|
738
|
+
this.sessionId = sessionId;
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
getSessionId() {
|
|
742
|
+
return this.sessionId;
|
|
743
|
+
}
|
|
744
|
+
}
|
|
745
|
+
|
|
720
746
|
// Handle chat WebSocket connections
|
|
721
747
|
function handleChatConnection(ws) {
|
|
722
748
|
console.log('[INFO] Chat WebSocket connected');
|
|
@@ -724,6 +750,9 @@ function handleChatConnection(ws) {
|
|
|
724
750
|
// Add to connected clients for project updates
|
|
725
751
|
connectedClients.add(ws);
|
|
726
752
|
|
|
753
|
+
// Wrap WebSocket with writer for consistent interface with SSEStreamWriter
|
|
754
|
+
const writer = new WebSocketWriter(ws);
|
|
755
|
+
|
|
727
756
|
ws.on('message', async (message) => {
|
|
728
757
|
try {
|
|
729
758
|
const data = JSON.parse(message);
|
|
@@ -734,19 +763,19 @@ function handleChatConnection(ws) {
|
|
|
734
763
|
console.log('🔄 Session:', data.options?.sessionId ? 'Resume' : 'New');
|
|
735
764
|
|
|
736
765
|
// Use Claude Agents SDK
|
|
737
|
-
await queryClaudeSDK(data.command, data.options,
|
|
766
|
+
await queryClaudeSDK(data.command, data.options, writer);
|
|
738
767
|
} else if (data.type === 'cursor-command') {
|
|
739
768
|
console.log('[DEBUG] Cursor message:', data.command || '[Continue/Resume]');
|
|
740
769
|
console.log('📁 Project:', data.options?.cwd || 'Unknown');
|
|
741
770
|
console.log('🔄 Session:', data.options?.sessionId ? 'Resume' : 'New');
|
|
742
771
|
console.log('🤖 Model:', data.options?.model || 'default');
|
|
743
|
-
await spawnCursor(data.command, data.options,
|
|
772
|
+
await spawnCursor(data.command, data.options, writer);
|
|
744
773
|
} else if (data.type === 'codex-command') {
|
|
745
774
|
console.log('[DEBUG] Codex message:', data.command || '[Continue/Resume]');
|
|
746
775
|
console.log('📁 Project:', data.options?.projectPath || data.options?.cwd || 'Unknown');
|
|
747
776
|
console.log('🔄 Session:', data.options?.sessionId ? 'Resume' : 'New');
|
|
748
777
|
console.log('🤖 Model:', data.options?.model || 'default');
|
|
749
|
-
await queryCodex(data.command, data.options,
|
|
778
|
+
await queryCodex(data.command, data.options, writer);
|
|
750
779
|
} else if (data.type === 'cursor-resume') {
|
|
751
780
|
// Backward compatibility: treat as cursor-command with resume and no prompt
|
|
752
781
|
console.log('[DEBUG] Cursor resume session (compat):', data.sessionId);
|
|
@@ -754,7 +783,7 @@ function handleChatConnection(ws) {
|
|
|
754
783
|
sessionId: data.sessionId,
|
|
755
784
|
resume: true,
|
|
756
785
|
cwd: data.options?.cwd
|
|
757
|
-
},
|
|
786
|
+
}, writer);
|
|
758
787
|
} else if (data.type === 'abort-session') {
|
|
759
788
|
console.log('[DEBUG] Abort session request:', data.sessionId);
|
|
760
789
|
const provider = data.provider || 'claude';
|
|
@@ -769,21 +798,21 @@ function handleChatConnection(ws) {
|
|
|
769
798
|
success = await abortClaudeSDKSession(data.sessionId);
|
|
770
799
|
}
|
|
771
800
|
|
|
772
|
-
|
|
801
|
+
writer.send({
|
|
773
802
|
type: 'session-aborted',
|
|
774
803
|
sessionId: data.sessionId,
|
|
775
804
|
provider,
|
|
776
805
|
success
|
|
777
|
-
})
|
|
806
|
+
});
|
|
778
807
|
} else if (data.type === 'cursor-abort') {
|
|
779
808
|
console.log('[DEBUG] Abort Cursor session:', data.sessionId);
|
|
780
809
|
const success = abortCursorSession(data.sessionId);
|
|
781
|
-
|
|
810
|
+
writer.send({
|
|
782
811
|
type: 'session-aborted',
|
|
783
812
|
sessionId: data.sessionId,
|
|
784
813
|
provider: 'cursor',
|
|
785
814
|
success
|
|
786
|
-
})
|
|
815
|
+
});
|
|
787
816
|
} else if (data.type === 'check-session-status') {
|
|
788
817
|
// Check if a specific session is currently processing
|
|
789
818
|
const provider = data.provider || 'claude';
|
|
@@ -799,12 +828,12 @@ function handleChatConnection(ws) {
|
|
|
799
828
|
isActive = isClaudeSDKSessionActive(sessionId);
|
|
800
829
|
}
|
|
801
830
|
|
|
802
|
-
|
|
831
|
+
writer.send({
|
|
803
832
|
type: 'session-status',
|
|
804
833
|
sessionId,
|
|
805
834
|
provider,
|
|
806
835
|
isProcessing: isActive
|
|
807
|
-
})
|
|
836
|
+
});
|
|
808
837
|
} else if (data.type === 'get-active-sessions') {
|
|
809
838
|
// Get all currently active sessions
|
|
810
839
|
const activeSessions = {
|
|
@@ -812,17 +841,17 @@ function handleChatConnection(ws) {
|
|
|
812
841
|
cursor: getActiveCursorSessions(),
|
|
813
842
|
codex: getActiveCodexSessions()
|
|
814
843
|
};
|
|
815
|
-
|
|
844
|
+
writer.send({
|
|
816
845
|
type: 'active-sessions',
|
|
817
846
|
sessions: activeSessions
|
|
818
|
-
})
|
|
847
|
+
});
|
|
819
848
|
}
|
|
820
849
|
} catch (error) {
|
|
821
850
|
console.error('[ERROR] Chat WebSocket error:', error.message);
|
|
822
|
-
|
|
851
|
+
writer.send({
|
|
823
852
|
type: 'error',
|
|
824
853
|
error: error.message
|
|
825
|
-
})
|
|
854
|
+
});
|
|
826
855
|
}
|
|
827
856
|
});
|
|
828
857
|
|
package/server/openai-codex.js
CHANGED
|
@@ -213,7 +213,8 @@ export async function queryCodex(command, options = {}, ws) {
|
|
|
213
213
|
workingDirectory,
|
|
214
214
|
skipGitRepoCheck: true,
|
|
215
215
|
sandboxMode,
|
|
216
|
-
approvalPolicy
|
|
216
|
+
approvalPolicy,
|
|
217
|
+
model
|
|
217
218
|
};
|
|
218
219
|
|
|
219
220
|
// Start or resume thread
|
|
@@ -359,12 +360,12 @@ export function getActiveCodexSessions() {
|
|
|
359
360
|
*/
|
|
360
361
|
function sendMessage(ws, data) {
|
|
361
362
|
try {
|
|
362
|
-
if (
|
|
363
|
-
//
|
|
363
|
+
if (ws.isSSEStreamWriter || ws.isWebSocketWriter) {
|
|
364
|
+
// Writer handles stringification (SSEStreamWriter or WebSocketWriter)
|
|
365
|
+
ws.send(data);
|
|
366
|
+
} else if (typeof ws.send === 'function') {
|
|
367
|
+
// Raw WebSocket - stringify here
|
|
364
368
|
ws.send(JSON.stringify(data));
|
|
365
|
-
} else if (typeof ws.write === 'function') {
|
|
366
|
-
// SSE writer (for agent API)
|
|
367
|
-
ws.write(`data: ${JSON.stringify(data)}\n\n`);
|
|
368
369
|
}
|
|
369
370
|
} catch (error) {
|
|
370
371
|
console.error('[Codex] Error sending message:', error);
|
package/server/routes/agent.js
CHANGED
|
@@ -10,6 +10,7 @@ import { queryClaudeSDK } from '../claude-sdk.js';
|
|
|
10
10
|
import { spawnCursor } from '../cursor-cli.js';
|
|
11
11
|
import { queryCodex } from '../openai-codex.js';
|
|
12
12
|
import { Octokit } from '@octokit/rest';
|
|
13
|
+
import { CLAUDE_MODELS, CURSOR_MODELS, CODEX_MODELS } from '../../shared/modelConstants.js';
|
|
13
14
|
|
|
14
15
|
const router = express.Router();
|
|
15
16
|
|
|
@@ -450,6 +451,7 @@ class SSEStreamWriter {
|
|
|
450
451
|
constructor(res) {
|
|
451
452
|
this.res = res;
|
|
452
453
|
this.sessionId = null;
|
|
454
|
+
this.isSSEStreamWriter = true; // Marker for transport detection
|
|
453
455
|
}
|
|
454
456
|
|
|
455
457
|
send(data) {
|
|
@@ -457,7 +459,7 @@ class SSEStreamWriter {
|
|
|
457
459
|
return;
|
|
458
460
|
}
|
|
459
461
|
|
|
460
|
-
// Format as SSE
|
|
462
|
+
// Format as SSE - providers send raw objects, we stringify
|
|
461
463
|
this.res.write(`data: ${JSON.stringify(data)}\n\n`);
|
|
462
464
|
}
|
|
463
465
|
|
|
@@ -634,9 +636,14 @@ class ResponseCollector {
|
|
|
634
636
|
* - true: Returns text/event-stream with incremental updates
|
|
635
637
|
* - false: Returns complete JSON response after completion
|
|
636
638
|
*
|
|
637
|
-
* @param {string} model - (Optional) Model identifier for
|
|
638
|
-
*
|
|
639
|
-
*
|
|
639
|
+
* @param {string} model - (Optional) Model identifier for providers.
|
|
640
|
+
*
|
|
641
|
+
* Claude models: 'sonnet' (default), 'opus', 'haiku', 'opusplan', 'sonnet[1m]'
|
|
642
|
+
* Cursor models: 'gpt-5' (default), 'gpt-5.2', 'gpt-5.2-high', 'sonnet-4.5', 'opus-4.5',
|
|
643
|
+
* 'gemini-3-pro', 'composer-1', 'auto', 'gpt-5.1', 'gpt-5.1-high',
|
|
644
|
+
* 'gpt-5.1-codex', 'gpt-5.1-codex-high', 'gpt-5.1-codex-max',
|
|
645
|
+
* 'gpt-5.1-codex-max-high', 'opus-4.1', 'grok', and thinking variants
|
|
646
|
+
* Codex models: 'gpt-5.2' (default), 'gpt-5.1-codex-max', 'o3', 'o4-mini'
|
|
640
647
|
*
|
|
641
648
|
* @param {boolean} cleanup - (Optional) Auto-cleanup project directory after completion.
|
|
642
649
|
* Default: true
|
|
@@ -939,6 +946,7 @@ router.post('/', validateExternalApiKey, async (req, res) => {
|
|
|
939
946
|
projectPath: finalProjectPath,
|
|
940
947
|
cwd: finalProjectPath,
|
|
941
948
|
sessionId: null, // New session
|
|
949
|
+
model: model,
|
|
942
950
|
permissionMode: 'bypassPermissions' // Bypass all permissions for API calls
|
|
943
951
|
}, writer);
|
|
944
952
|
|
|
@@ -959,7 +967,7 @@ router.post('/', validateExternalApiKey, async (req, res) => {
|
|
|
959
967
|
projectPath: finalProjectPath,
|
|
960
968
|
cwd: finalProjectPath,
|
|
961
969
|
sessionId: null,
|
|
962
|
-
model: model ||
|
|
970
|
+
model: model || CODEX_MODELS.DEFAULT,
|
|
963
971
|
permissionMode: 'bypassPermissions'
|
|
964
972
|
}, writer);
|
|
965
973
|
}
|
|
@@ -4,6 +4,7 @@ import path from 'path';
|
|
|
4
4
|
import { fileURLToPath } from 'url';
|
|
5
5
|
import os from 'os';
|
|
6
6
|
import matter from 'gray-matter';
|
|
7
|
+
import { CLAUDE_MODELS, CURSOR_MODELS, CODEX_MODELS } from '../../shared/modelConstants.js';
|
|
7
8
|
|
|
8
9
|
const __filename = fileURLToPath(import.meta.url);
|
|
9
10
|
const __dirname = path.dirname(__filename);
|
|
@@ -182,23 +183,15 @@ Custom commands can be created in:
|
|
|
182
183
|
},
|
|
183
184
|
|
|
184
185
|
'/model': async (args, context) => {
|
|
185
|
-
// Read available models from
|
|
186
|
+
// Read available models from centralized constants
|
|
186
187
|
const availableModels = {
|
|
187
|
-
claude:
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
'claude-opus-4',
|
|
191
|
-
'claude-sonnet-3.5'
|
|
192
|
-
],
|
|
193
|
-
cursor: [
|
|
194
|
-
'gpt-5',
|
|
195
|
-
'sonnet-4',
|
|
196
|
-
'opus-4.1'
|
|
197
|
-
]
|
|
188
|
+
claude: CLAUDE_MODELS.OPTIONS.map(o => o.value),
|
|
189
|
+
cursor: CURSOR_MODELS.OPTIONS.map(o => o.value),
|
|
190
|
+
codex: CODEX_MODELS.OPTIONS.map(o => o.value)
|
|
198
191
|
};
|
|
199
192
|
|
|
200
193
|
const currentProvider = context?.provider || 'claude';
|
|
201
|
-
const currentModel = context?.model ||
|
|
194
|
+
const currentModel = context?.model || CLAUDE_MODELS.DEFAULT;
|
|
202
195
|
|
|
203
196
|
return {
|
|
204
197
|
type: 'builtin',
|
|
@@ -216,50 +209,6 @@ Custom commands can be created in:
|
|
|
216
209
|
};
|
|
217
210
|
},
|
|
218
211
|
|
|
219
|
-
'/cost': async (args, context) => {
|
|
220
|
-
// Calculate token usage and cost
|
|
221
|
-
const sessionId = context?.sessionId;
|
|
222
|
-
const tokenUsage = context?.tokenUsage || { used: 0, total: 200000 };
|
|
223
|
-
|
|
224
|
-
const costPerMillion = {
|
|
225
|
-
'claude-sonnet-4.5': { input: 3, output: 15 },
|
|
226
|
-
'claude-sonnet-4': { input: 3, output: 15 },
|
|
227
|
-
'claude-opus-4': { input: 15, output: 75 },
|
|
228
|
-
'gpt-5': { input: 5, output: 15 }
|
|
229
|
-
};
|
|
230
|
-
|
|
231
|
-
const model = context?.model || 'claude-sonnet-4.5';
|
|
232
|
-
const rates = costPerMillion[model] || costPerMillion['claude-sonnet-4.5'];
|
|
233
|
-
|
|
234
|
-
// Estimate 70% input, 30% output
|
|
235
|
-
const estimatedInputTokens = Math.floor(tokenUsage.used * 0.7);
|
|
236
|
-
const estimatedOutputTokens = Math.floor(tokenUsage.used * 0.3);
|
|
237
|
-
|
|
238
|
-
const inputCost = (estimatedInputTokens / 1000000) * rates.input;
|
|
239
|
-
const outputCost = (estimatedOutputTokens / 1000000) * rates.output;
|
|
240
|
-
const totalCost = inputCost + outputCost;
|
|
241
|
-
|
|
242
|
-
return {
|
|
243
|
-
type: 'builtin',
|
|
244
|
-
action: 'cost',
|
|
245
|
-
data: {
|
|
246
|
-
tokenUsage: {
|
|
247
|
-
used: tokenUsage.used,
|
|
248
|
-
total: tokenUsage.total,
|
|
249
|
-
percentage: ((tokenUsage.used / tokenUsage.total) * 100).toFixed(1)
|
|
250
|
-
},
|
|
251
|
-
cost: {
|
|
252
|
-
input: inputCost.toFixed(4),
|
|
253
|
-
output: outputCost.toFixed(4),
|
|
254
|
-
total: totalCost.toFixed(4),
|
|
255
|
-
currency: 'USD'
|
|
256
|
-
},
|
|
257
|
-
model,
|
|
258
|
-
rates
|
|
259
|
-
}
|
|
260
|
-
};
|
|
261
|
-
},
|
|
262
|
-
|
|
263
212
|
'/status': async (args, context) => {
|
|
264
213
|
// Read version from package.json
|
|
265
214
|
const packageJsonPath = path.join(path.dirname(__dirname), '..', 'package.json');
|
package/server/routes/cursor.js
CHANGED
|
@@ -6,6 +6,7 @@ import { spawn } from 'child_process';
|
|
|
6
6
|
import sqlite3 from 'sqlite3';
|
|
7
7
|
import { open } from 'sqlite';
|
|
8
8
|
import crypto from 'crypto';
|
|
9
|
+
import { CURSOR_MODELS } from '../../shared/modelConstants.js';
|
|
9
10
|
|
|
10
11
|
const router = express.Router();
|
|
11
12
|
|
|
@@ -33,7 +34,7 @@ router.get('/config', async (req, res) => {
|
|
|
33
34
|
config: {
|
|
34
35
|
version: 1,
|
|
35
36
|
model: {
|
|
36
|
-
modelId:
|
|
37
|
+
modelId: CURSOR_MODELS.DEFAULT,
|
|
37
38
|
displayName: "GPT-5"
|
|
38
39
|
},
|
|
39
40
|
permissions: {
|
package/server/database/auth.db
DELETED
|
Binary file
|