@siteboon/claude-code-ui 1.12.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/README.md +19 -16
- package/dist/api-docs.html +30 -8
- package/dist/assets/index-BL1HpeHJ.js +1206 -0
- package/dist/assets/index-Cc6pl7ji.css +32 -0
- package/dist/assets/{vendor-xterm-jI4BCHEb.js → vendor-xterm-DfaPXD3y.js} +12 -12
- package/dist/icons/codex-white.svg +3 -0
- package/dist/icons/codex.svg +3 -0
- package/dist/icons/cursor-white.svg +12 -0
- package/dist/index.html +4 -4
- package/dist/logo-128.png +0 -0
- package/dist/logo-256.png +0 -0
- package/dist/logo-32.png +0 -0
- package/dist/logo-512.png +0 -0
- package/dist/logo-64.png +0 -0
- package/dist/logo.svg +17 -9
- package/package.json +4 -1
- package/server/claude-sdk.js +32 -30
- package/server/cursor-cli.js +24 -24
- package/server/database/db.js +64 -0
- package/server/database/init.sql +4 -1
- package/server/index.js +278 -31
- package/server/openai-codex.js +388 -0
- package/server/projects.js +448 -7
- package/server/routes/agent.js +54 -8
- package/server/routes/cli-auth.js +263 -0
- package/server/routes/codex.js +310 -0
- package/server/routes/commands.js +6 -57
- package/server/routes/cursor.js +2 -1
- package/server/routes/git.js +123 -28
- package/server/routes/taskmaster.js +2 -10
- package/server/routes/user.js +106 -0
- package/server/utils/gitConfig.js +24 -0
- package/dist/assets/index-DXtzL-q9.css +0 -32
- package/dist/assets/index-Do2w3FiK.js +0 -1189
- package/server/database/auth.db +0 -0
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
<svg viewBox="100 100 520 520" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<path d="M304.246 295.411V249.828C304.246 245.989 305.687 243.109 309.044 241.191L400.692 188.412C413.167 181.215 428.042 177.858 443.394 177.858C500.971 177.858 537.44 222.482 537.44 269.982C537.44 273.34 537.44 277.179 536.959 281.018L441.954 225.358C436.197 222 430.437 222 424.68 225.358L304.246 295.411ZM518.245 472.945V364.024C518.245 357.304 515.364 352.507 509.608 349.149L389.174 279.096L428.519 256.543C431.877 254.626 434.757 254.626 438.115 256.543L529.762 309.323C556.154 324.679 573.905 357.304 573.905 388.971C573.905 425.436 552.315 459.024 518.245 472.941V472.945ZM275.937 376.982L236.592 353.952C233.235 352.034 231.794 349.154 231.794 345.315V239.756C231.794 188.416 271.139 149.548 324.4 149.548C344.555 149.548 363.264 156.268 379.102 168.262L284.578 222.964C278.822 226.321 275.942 231.119 275.942 237.838V376.986L275.937 376.982ZM360.626 425.922L304.246 394.255V327.083L360.626 295.416L417.002 327.083V394.255L360.626 425.922ZM396.852 571.789C376.698 571.789 357.989 565.07 342.151 553.075L436.674 498.374C442.431 495.017 445.311 490.219 445.311 483.499V344.352L485.138 367.382C488.495 369.299 489.936 372.179 489.936 376.018V481.577C489.936 532.917 450.109 571.785 396.852 571.785V571.789ZM283.134 464.79L191.486 412.01C165.094 396.654 147.343 364.029 147.343 332.362C147.343 295.416 169.415 262.309 203.48 248.393V357.791C203.48 364.51 206.361 369.308 212.117 372.665L332.074 442.237L292.729 464.79C289.372 466.707 286.491 466.707 283.134 464.79ZM277.859 543.48C223.639 543.48 183.813 502.695 183.813 452.314C183.813 448.475 184.294 444.636 184.771 440.797L279.295 495.498C285.051 498.856 290.812 498.856 296.568 495.498L417.002 425.927V471.509C417.002 475.349 415.562 478.229 412.204 480.146L320.557 532.926C308.081 540.122 293.206 543.48 277.854 543.48H277.859ZM396.852 600.576C454.911 600.576 503.37 559.313 514.41 504.612C568.149 490.696 602.696 440.315 602.696 388.976C602.696 355.387 588.303 322.762 562.392 299.25C564.791 289.173 566.231 279.096 566.231 269.024C566.231 200.411 510.571 149.067 446.274 149.067C433.322 149.067 420.846 150.984 408.37 155.305C386.775 134.192 357.026 120.758 324.4 120.758C266.342 120.758 217.883 162.02 206.843 216.721C153.104 230.637 118.557 281.018 118.557 332.357C118.557 365.946 132.95 398.571 158.861 422.083C156.462 432.16 155.022 442.237 155.022 452.309C155.022 520.922 210.682 572.266 274.978 572.266C287.931 572.266 300.407 570.349 312.883 566.028C334.473 587.141 364.222 600.576 396.852 600.576Z" fill="white"/>
|
|
3
|
+
</svg>
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
<svg viewBox="100 100 520 520" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<path d="M304.246 294.611V249.028C304.246 245.189 305.687 242.309 309.044 240.392L400.692 187.612C413.167 180.415 428.042 177.058 443.394 177.058C500.971 177.058 537.44 221.682 537.44 269.182C537.44 272.54 537.44 276.379 536.959 280.218L441.954 224.558C436.197 221.201 430.437 221.201 424.68 224.558L304.246 294.611ZM518.245 472.145V363.224C518.245 356.505 515.364 351.707 509.608 348.349L389.174 278.296L428.519 255.743C431.877 253.826 434.757 253.826 438.115 255.743L529.762 308.523C556.154 323.879 573.905 356.505 573.905 388.171C573.905 424.636 552.315 458.225 518.245 472.141V472.145ZM275.937 376.182L236.592 353.152C233.235 351.235 231.794 348.354 231.794 344.515V238.956C231.794 187.617 271.139 148.749 324.4 148.749C344.555 148.749 363.264 155.468 379.102 167.463L284.578 222.164C278.822 225.521 275.942 230.319 275.942 237.039V376.186L275.937 376.182ZM360.626 425.122L304.246 393.455V326.283L360.626 294.616L417.002 326.283V393.455L360.626 425.122ZM396.852 570.989C376.698 570.989 357.989 564.27 342.151 552.276L436.674 497.574C442.431 494.217 445.311 489.419 445.311 482.699V343.552L485.138 366.582C488.495 368.499 489.936 371.379 489.936 375.219V480.778C489.936 532.117 450.109 570.985 396.852 570.985V570.989ZM283.134 463.99L191.486 411.211C165.094 395.854 147.343 363.229 147.343 331.562C147.343 294.616 169.415 261.509 203.48 247.593V356.991C203.48 363.71 206.361 368.508 212.117 371.866L332.074 441.437L292.729 463.99C289.372 465.907 286.491 465.907 283.134 463.99ZM277.859 542.68C223.639 542.68 183.813 501.895 183.813 451.514C183.813 447.675 184.294 443.836 184.771 439.997L279.295 494.698C285.051 498.056 290.812 498.056 296.568 494.698L417.002 425.127V470.71C417.002 474.549 415.562 477.429 412.204 479.346L320.557 532.126C308.081 539.323 293.206 542.68 277.854 542.68H277.859ZM396.852 599.776C454.911 599.776 503.37 558.513 514.41 503.812C568.149 489.896 602.696 439.515 602.696 388.176C602.696 354.587 588.303 321.962 562.392 298.45C564.791 288.373 566.231 278.296 566.231 268.224C566.231 199.611 510.571 148.267 446.274 148.267C433.322 148.267 420.846 150.184 408.37 154.505C386.775 133.392 357.026 119.958 324.4 119.958C266.342 119.958 217.883 161.22 206.843 215.921C153.104 229.837 118.557 280.218 118.557 331.557C118.557 365.146 132.95 397.771 158.861 421.283C156.462 431.36 155.022 441.437 155.022 451.51C155.022 520.123 210.682 571.466 274.978 571.466C287.931 571.466 300.407 569.549 312.883 565.228C334.473 586.341 364.222 599.776 396.852 599.776Z" fill="currentColor"/>
|
|
3
|
+
</svg>
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<svg id="Ebene_1" xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 466.73 532.09">
|
|
3
|
+
<!-- Generator: Adobe Illustrator 29.6.1, SVG Export Plug-In . SVG Version: 2.1.1 Build 9) -->
|
|
4
|
+
<defs>
|
|
5
|
+
<style>
|
|
6
|
+
.st0 {
|
|
7
|
+
fill: #edecec;
|
|
8
|
+
}
|
|
9
|
+
</style>
|
|
10
|
+
</defs>
|
|
11
|
+
<path class="st0" d="M457.43,125.94L244.42,2.96c-6.84-3.95-15.28-3.95-22.12,0L9.3,125.94c-5.75,3.32-9.3,9.46-9.3,16.11v247.99c0,6.65,3.55,12.79,9.3,16.11l213.01,122.98c6.84,3.95,15.28,3.95,22.12,0l213.01-122.98c5.75-3.32,9.3-9.46,9.3-16.11v-247.99c0-6.65-3.55-12.79-9.3-16.11h-.01ZM444.05,151.99l-205.63,356.16c-1.39,2.4-5.06,1.42-5.06-1.36v-233.21c0-4.66-2.49-8.97-6.53-11.31L24.87,145.67c-2.4-1.39-1.42-5.06,1.36-5.06h411.26c5.84,0,9.49,6.33,6.57,11.39h-.01Z"/>
|
|
12
|
+
</svg>
|
package/dist/index.html
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
<link rel="manifest" href="/manifest.json" />
|
|
12
12
|
|
|
13
13
|
<!-- iOS Safari PWA Meta Tags -->
|
|
14
|
-
<meta name="
|
|
14
|
+
<meta name="mobile-web-app-capable" content="yes" />
|
|
15
15
|
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
|
|
16
16
|
<meta name="apple-mobile-web-app-title" content="Claude UI" />
|
|
17
17
|
|
|
@@ -25,11 +25,11 @@
|
|
|
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
|
-
<link rel="modulepreload" crossorigin href="/assets/vendor-xterm-
|
|
32
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
31
|
+
<link rel="modulepreload" crossorigin href="/assets/vendor-xterm-DfaPXD3y.js">
|
|
32
|
+
<link rel="stylesheet" crossorigin href="/assets/index-Cc6pl7ji.css">
|
|
33
33
|
</head>
|
|
34
34
|
<body>
|
|
35
35
|
<div id="root"></div>
|
|
Binary file
|
|
Binary file
|
package/dist/logo-32.png
ADDED
|
Binary file
|
|
Binary file
|
package/dist/logo-64.png
ADDED
|
Binary file
|
package/dist/logo.svg
CHANGED
|
@@ -1,9 +1,17 @@
|
|
|
1
|
-
<svg
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
1
|
+
<svg
|
|
2
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
3
|
+
width="32"
|
|
4
|
+
height="32"
|
|
5
|
+
viewBox="0 0 32 32"
|
|
6
|
+
fill="none"
|
|
7
|
+
>
|
|
8
|
+
<rect width="32" height="32" rx="8" fill="hsl(221.2 83.2% 53.3%)"/>
|
|
9
|
+
<path
|
|
10
|
+
d="M8 9C8 8.44772 8.44772 8 9 8H23C23.5523 8 24 8.44772 24 9V18C24 18.5523 23.5523 19 23 19H12L8 23V9Z"
|
|
11
|
+
stroke="white"
|
|
12
|
+
strokeWidth="2"
|
|
13
|
+
strokeLinecap="round"
|
|
14
|
+
strokeLinejoin="round"
|
|
15
|
+
fill="none"
|
|
16
|
+
/>
|
|
17
|
+
</svg>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@siteboon/claude-code-ui",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.13.1",
|
|
4
4
|
"description": "A web-based UI for Claude Code CLI",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "server/index.js",
|
|
@@ -49,12 +49,15 @@
|
|
|
49
49
|
"@codemirror/lang-python": "^6.2.1",
|
|
50
50
|
"@codemirror/merge": "^6.11.1",
|
|
51
51
|
"@codemirror/theme-one-dark": "^6.1.2",
|
|
52
|
+
"@iarna/toml": "^2.2.5",
|
|
52
53
|
"@octokit/rest": "^22.0.0",
|
|
54
|
+
"@openai/codex-sdk": "^0.75.0",
|
|
53
55
|
"@replit/codemirror-minimap": "^0.5.2",
|
|
54
56
|
"@tailwindcss/typography": "^0.5.16",
|
|
55
57
|
"@uiw/react-codemirror": "^4.23.13",
|
|
56
58
|
"@xterm/addon-clipboard": "^0.1.0",
|
|
57
59
|
"@xterm/addon-fit": "^0.10.0",
|
|
60
|
+
"@xterm/addon-web-links": "^0.11.0",
|
|
58
61
|
"@xterm/addon-webgl": "^0.18.0",
|
|
59
62
|
"@xterm/xterm": "^5.5.0",
|
|
60
63
|
"bcrypt": "^6.0.0",
|
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();
|
|
@@ -57,7 +58,7 @@ function mapCliOptionsToSDK(options = {}) {
|
|
|
57
58
|
|
|
58
59
|
// Add plan mode default tools
|
|
59
60
|
if (permissionMode === 'plan') {
|
|
60
|
-
const planModeTools = ['Read', 'Task', 'exit_plan_mode', 'TodoRead', 'TodoWrite'];
|
|
61
|
+
const planModeTools = ['Read', 'Task', 'exit_plan_mode', 'TodoRead', 'TodoWrite', 'WebFetch', 'WebSearch'];
|
|
61
62
|
for (const tool of planModeTools) {
|
|
62
63
|
if (!allowedTools.includes(tool)) {
|
|
63
64
|
allowedTools.push(tool);
|
|
@@ -76,8 +77,9 @@ function mapCliOptionsToSDK(options = {}) {
|
|
|
76
77
|
}
|
|
77
78
|
|
|
78
79
|
// Map model (default to sonnet)
|
|
79
|
-
//
|
|
80
|
-
sdkOptions.model = options.model ||
|
|
80
|
+
// Valid models: sonnet, opus, haiku, opusplan, sonnet[1m]
|
|
81
|
+
sdkOptions.model = options.model || CLAUDE_MODELS.DEFAULT;
|
|
82
|
+
console.log(`Using model: ${sdkOptions.model}`);
|
|
81
83
|
|
|
82
84
|
// Map system prompt configuration
|
|
83
85
|
sdkOptions.systemPrompt = {
|
|
@@ -183,7 +185,7 @@ function extractTokenBudget(resultMessage) {
|
|
|
183
185
|
// This is the user's budget limit, not the model's context window
|
|
184
186
|
const contextWindow = parseInt(process.env.CONTEXT_WINDOW) || 160000;
|
|
185
187
|
|
|
186
|
-
console.log(
|
|
188
|
+
console.log(`Token calculation: input=${inputTokens}, output=${outputTokens}, cache=${cacheReadTokens + cacheCreationTokens}, total=${totalUsed}/${contextWindow}`);
|
|
187
189
|
|
|
188
190
|
return {
|
|
189
191
|
used: totalUsed,
|
|
@@ -239,7 +241,7 @@ async function handleImages(command, images, cwd) {
|
|
|
239
241
|
modifiedCommand = command + imageNote;
|
|
240
242
|
}
|
|
241
243
|
|
|
242
|
-
console.log(
|
|
244
|
+
console.log(`Processed ${tempImagePaths.length} images to temp directory: ${tempDir}`);
|
|
243
245
|
return { modifiedCommand, tempImagePaths, tempDir };
|
|
244
246
|
} catch (error) {
|
|
245
247
|
console.error('Error processing images for SDK:', error);
|
|
@@ -272,7 +274,7 @@ async function cleanupTempFiles(tempImagePaths, tempDir) {
|
|
|
272
274
|
);
|
|
273
275
|
}
|
|
274
276
|
|
|
275
|
-
console.log(
|
|
277
|
+
console.log(`Cleaned up ${tempImagePaths.length} temp image files`);
|
|
276
278
|
} catch (error) {
|
|
277
279
|
console.error('Error during temp file cleanup:', error);
|
|
278
280
|
}
|
|
@@ -292,7 +294,7 @@ async function loadMcpConfig(cwd) {
|
|
|
292
294
|
await fs.access(claudeConfigPath);
|
|
293
295
|
} catch (error) {
|
|
294
296
|
// File doesn't exist, return null
|
|
295
|
-
console.log('
|
|
297
|
+
console.log('No ~/.claude.json found, proceeding without MCP servers');
|
|
296
298
|
return null;
|
|
297
299
|
}
|
|
298
300
|
|
|
@@ -302,7 +304,7 @@ async function loadMcpConfig(cwd) {
|
|
|
302
304
|
const configContent = await fs.readFile(claudeConfigPath, 'utf8');
|
|
303
305
|
claudeConfig = JSON.parse(configContent);
|
|
304
306
|
} catch (error) {
|
|
305
|
-
console.error('
|
|
307
|
+
console.error('Failed to parse ~/.claude.json:', error.message);
|
|
306
308
|
return null;
|
|
307
309
|
}
|
|
308
310
|
|
|
@@ -312,7 +314,7 @@ async function loadMcpConfig(cwd) {
|
|
|
312
314
|
// Add global MCP servers
|
|
313
315
|
if (claudeConfig.mcpServers && typeof claudeConfig.mcpServers === 'object') {
|
|
314
316
|
mcpServers = { ...claudeConfig.mcpServers };
|
|
315
|
-
console.log(
|
|
317
|
+
console.log(`Loaded ${Object.keys(mcpServers).length} global MCP servers`);
|
|
316
318
|
}
|
|
317
319
|
|
|
318
320
|
// Add/override with project-specific MCP servers
|
|
@@ -320,20 +322,20 @@ async function loadMcpConfig(cwd) {
|
|
|
320
322
|
const projectConfig = claudeConfig.claudeProjects[cwd];
|
|
321
323
|
if (projectConfig && projectConfig.mcpServers && typeof projectConfig.mcpServers === 'object') {
|
|
322
324
|
mcpServers = { ...mcpServers, ...projectConfig.mcpServers };
|
|
323
|
-
console.log(
|
|
325
|
+
console.log(`Loaded ${Object.keys(projectConfig.mcpServers).length} project-specific MCP servers`);
|
|
324
326
|
}
|
|
325
327
|
}
|
|
326
328
|
|
|
327
329
|
// Return null if no servers found
|
|
328
330
|
if (Object.keys(mcpServers).length === 0) {
|
|
329
|
-
console.log('
|
|
331
|
+
console.log('No MCP servers configured');
|
|
330
332
|
return null;
|
|
331
333
|
}
|
|
332
334
|
|
|
333
|
-
console.log(
|
|
335
|
+
console.log(`Total MCP servers loaded: ${Object.keys(mcpServers).length}`);
|
|
334
336
|
return mcpServers;
|
|
335
337
|
} catch (error) {
|
|
336
|
-
console.error('
|
|
338
|
+
console.error('Error loading MCP config:', error.message);
|
|
337
339
|
return null;
|
|
338
340
|
}
|
|
339
341
|
}
|
|
@@ -380,7 +382,7 @@ async function queryClaudeSDK(command, options = {}, ws) {
|
|
|
380
382
|
}
|
|
381
383
|
|
|
382
384
|
// Process streaming messages
|
|
383
|
-
console.log('
|
|
385
|
+
console.log('Starting async generator loop for session:', capturedSessionId || 'NEW');
|
|
384
386
|
for await (const message of queryInstance) {
|
|
385
387
|
// Capture session ID from first message
|
|
386
388
|
if (message.session_id && !capturedSessionId) {
|
|
@@ -396,33 +398,33 @@ async function queryClaudeSDK(command, options = {}, ws) {
|
|
|
396
398
|
// Send session-created event only once for new sessions
|
|
397
399
|
if (!sessionId && !sessionCreatedSent) {
|
|
398
400
|
sessionCreatedSent = true;
|
|
399
|
-
ws.send(
|
|
401
|
+
ws.send({
|
|
400
402
|
type: 'session-created',
|
|
401
403
|
sessionId: capturedSessionId
|
|
402
|
-
})
|
|
404
|
+
});
|
|
403
405
|
} else {
|
|
404
|
-
console.log('
|
|
406
|
+
console.log('Not sending session-created. sessionId:', sessionId, 'sessionCreatedSent:', sessionCreatedSent);
|
|
405
407
|
}
|
|
406
408
|
} else {
|
|
407
|
-
console.log('
|
|
409
|
+
console.log('No session_id in message or already captured. message.session_id:', message.session_id, 'capturedSessionId:', capturedSessionId);
|
|
408
410
|
}
|
|
409
411
|
|
|
410
412
|
// Transform and send message to WebSocket
|
|
411
413
|
const transformedMessage = transformMessage(message);
|
|
412
|
-
ws.send(
|
|
414
|
+
ws.send({
|
|
413
415
|
type: 'claude-response',
|
|
414
416
|
data: transformedMessage
|
|
415
|
-
})
|
|
417
|
+
});
|
|
416
418
|
|
|
417
419
|
// Extract and send token budget updates from result messages
|
|
418
420
|
if (message.type === 'result') {
|
|
419
421
|
const tokenBudget = extractTokenBudget(message);
|
|
420
422
|
if (tokenBudget) {
|
|
421
|
-
console.log('
|
|
422
|
-
ws.send(
|
|
423
|
+
console.log('Token budget from modelUsage:', tokenBudget);
|
|
424
|
+
ws.send({
|
|
423
425
|
type: 'token-budget',
|
|
424
426
|
data: tokenBudget
|
|
425
|
-
})
|
|
427
|
+
});
|
|
426
428
|
}
|
|
427
429
|
}
|
|
428
430
|
}
|
|
@@ -436,14 +438,14 @@ async function queryClaudeSDK(command, options = {}, ws) {
|
|
|
436
438
|
await cleanupTempFiles(tempImagePaths, tempDir);
|
|
437
439
|
|
|
438
440
|
// Send completion event
|
|
439
|
-
console.log('
|
|
440
|
-
ws.send(
|
|
441
|
+
console.log('Streaming complete, sending claude-complete event');
|
|
442
|
+
ws.send({
|
|
441
443
|
type: 'claude-complete',
|
|
442
444
|
sessionId: capturedSessionId,
|
|
443
445
|
exitCode: 0,
|
|
444
446
|
isNewSession: !sessionId && !!command
|
|
445
|
-
})
|
|
446
|
-
console.log('
|
|
447
|
+
});
|
|
448
|
+
console.log('claude-complete event sent');
|
|
447
449
|
|
|
448
450
|
} catch (error) {
|
|
449
451
|
console.error('SDK query error:', error);
|
|
@@ -457,10 +459,10 @@ async function queryClaudeSDK(command, options = {}, ws) {
|
|
|
457
459
|
await cleanupTempFiles(tempImagePaths, tempDir);
|
|
458
460
|
|
|
459
461
|
// Send error to WebSocket
|
|
460
|
-
ws.send(
|
|
462
|
+
ws.send({
|
|
461
463
|
type: 'claude-error',
|
|
462
464
|
error: error.message
|
|
463
|
-
})
|
|
465
|
+
});
|
|
464
466
|
|
|
465
467
|
throw error;
|
|
466
468
|
}
|
|
@@ -480,7 +482,7 @@ async function abortClaudeSDKSession(sessionId) {
|
|
|
480
482
|
}
|
|
481
483
|
|
|
482
484
|
try {
|
|
483
|
-
console.log(
|
|
485
|
+
console.log(`Aborting SDK session: ${sessionId}`);
|
|
484
486
|
|
|
485
487
|
// Call interrupt() on the query instance
|
|
486
488
|
await session.instance.interrupt();
|
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/database/db.js
CHANGED
|
@@ -55,12 +55,40 @@ if (process.env.DATABASE_PATH) {
|
|
|
55
55
|
console.log(c.dim('═'.repeat(60)));
|
|
56
56
|
console.log('');
|
|
57
57
|
|
|
58
|
+
const runMigrations = () => {
|
|
59
|
+
try {
|
|
60
|
+
const tableInfo = db.prepare("PRAGMA table_info(users)").all();
|
|
61
|
+
const columnNames = tableInfo.map(col => col.name);
|
|
62
|
+
|
|
63
|
+
if (!columnNames.includes('git_name')) {
|
|
64
|
+
console.log('Running migration: Adding git_name column');
|
|
65
|
+
db.exec('ALTER TABLE users ADD COLUMN git_name TEXT');
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (!columnNames.includes('git_email')) {
|
|
69
|
+
console.log('Running migration: Adding git_email column');
|
|
70
|
+
db.exec('ALTER TABLE users ADD COLUMN git_email TEXT');
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (!columnNames.includes('has_completed_onboarding')) {
|
|
74
|
+
console.log('Running migration: Adding has_completed_onboarding column');
|
|
75
|
+
db.exec('ALTER TABLE users ADD COLUMN has_completed_onboarding BOOLEAN DEFAULT 0');
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
console.log('Database migrations completed successfully');
|
|
79
|
+
} catch (error) {
|
|
80
|
+
console.error('Error running migrations:', error.message);
|
|
81
|
+
throw error;
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
|
|
58
85
|
// Initialize database with schema
|
|
59
86
|
const initializeDatabase = async () => {
|
|
60
87
|
try {
|
|
61
88
|
const initSQL = fs.readFileSync(INIT_SQL_PATH, 'utf8');
|
|
62
89
|
db.exec(initSQL);
|
|
63
90
|
console.log('Database initialized successfully');
|
|
91
|
+
runMigrations();
|
|
64
92
|
} catch (error) {
|
|
65
93
|
console.error('Error initializing database:', error.message);
|
|
66
94
|
throw error;
|
|
@@ -126,6 +154,42 @@ const userDb = {
|
|
|
126
154
|
} catch (err) {
|
|
127
155
|
throw err;
|
|
128
156
|
}
|
|
157
|
+
},
|
|
158
|
+
|
|
159
|
+
updateGitConfig: (userId, gitName, gitEmail) => {
|
|
160
|
+
try {
|
|
161
|
+
const stmt = db.prepare('UPDATE users SET git_name = ?, git_email = ? WHERE id = ?');
|
|
162
|
+
stmt.run(gitName, gitEmail, userId);
|
|
163
|
+
} catch (err) {
|
|
164
|
+
throw err;
|
|
165
|
+
}
|
|
166
|
+
},
|
|
167
|
+
|
|
168
|
+
getGitConfig: (userId) => {
|
|
169
|
+
try {
|
|
170
|
+
const row = db.prepare('SELECT git_name, git_email FROM users WHERE id = ?').get(userId);
|
|
171
|
+
return row;
|
|
172
|
+
} catch (err) {
|
|
173
|
+
throw err;
|
|
174
|
+
}
|
|
175
|
+
},
|
|
176
|
+
|
|
177
|
+
completeOnboarding: (userId) => {
|
|
178
|
+
try {
|
|
179
|
+
const stmt = db.prepare('UPDATE users SET has_completed_onboarding = 1 WHERE id = ?');
|
|
180
|
+
stmt.run(userId);
|
|
181
|
+
} catch (err) {
|
|
182
|
+
throw err;
|
|
183
|
+
}
|
|
184
|
+
},
|
|
185
|
+
|
|
186
|
+
hasCompletedOnboarding: (userId) => {
|
|
187
|
+
try {
|
|
188
|
+
const row = db.prepare('SELECT has_completed_onboarding FROM users WHERE id = ?').get(userId);
|
|
189
|
+
return row?.has_completed_onboarding === 1;
|
|
190
|
+
} catch (err) {
|
|
191
|
+
throw err;
|
|
192
|
+
}
|
|
129
193
|
}
|
|
130
194
|
};
|
|
131
195
|
|
package/server/database/init.sql
CHANGED
|
@@ -8,7 +8,10 @@ CREATE TABLE IF NOT EXISTS users (
|
|
|
8
8
|
password_hash TEXT NOT NULL,
|
|
9
9
|
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
10
10
|
last_login DATETIME,
|
|
11
|
-
is_active BOOLEAN DEFAULT 1
|
|
11
|
+
is_active BOOLEAN DEFAULT 1,
|
|
12
|
+
git_name TEXT,
|
|
13
|
+
git_email TEXT,
|
|
14
|
+
has_completed_onboarding BOOLEAN DEFAULT 0
|
|
12
15
|
);
|
|
13
16
|
|
|
14
17
|
-- Indexes for performance
|