agentstudio 0.1.0 → 0.1.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.
Files changed (131) hide show
  1. package/.cc-sessions/ppt-editor/session_1756253549429_uau1hm6lh.json +665 -0
  2. package/.cc-sessions/ppt-editor/session_1756257240855_v0wa26mde.json +394 -0
  3. package/README.md +39 -41
  4. package/dist/bin/agentstudio.js +4 -27
  5. package/dist/bin/agentstudio.js.map +1 -1
  6. package/dist/index.d.ts +1 -1
  7. package/dist/index.d.ts.map +1 -1
  8. package/dist/index.js +121 -52
  9. package/dist/index.js.map +1 -1
  10. package/dist/routes/agents.d.ts.map +1 -1
  11. package/dist/routes/agents.js +18 -19
  12. package/dist/routes/agents.js.map +1 -1
  13. package/dist/routes/commands.d.ts +4 -0
  14. package/dist/routes/commands.d.ts.map +1 -0
  15. package/dist/routes/commands.js +395 -0
  16. package/dist/routes/commands.js.map +1 -0
  17. package/dist/routes/projects.d.ts +4 -0
  18. package/dist/routes/projects.d.ts.map +1 -0
  19. package/dist/routes/projects.js +528 -0
  20. package/dist/routes/projects.js.map +1 -0
  21. package/dist/routes/sessions.d.ts +4 -0
  22. package/dist/routes/sessions.d.ts.map +1 -0
  23. package/dist/routes/sessions.js +733 -0
  24. package/dist/routes/sessions.js.map +1 -0
  25. package/dist/routes/settings.d.ts +4 -0
  26. package/dist/routes/settings.d.ts.map +1 -0
  27. package/dist/routes/settings.js +658 -0
  28. package/dist/routes/settings.js.map +1 -0
  29. package/dist/routes/subagents.d.ts +4 -0
  30. package/dist/routes/subagents.d.ts.map +1 -0
  31. package/dist/routes/subagents.js +326 -0
  32. package/dist/routes/subagents.js.map +1 -0
  33. package/docs/chat-clean-1.svg +1 -0
  34. package/docs/chat-clean.md +60 -0
  35. package/docs/chat-comprehensive-1.svg +1 -0
  36. package/docs/chat-comprehensive.md +166 -0
  37. package/docs/chat_api_sequence_diagram.md +58 -0
  38. package/docs/command-detection-logic.md +306 -0
  39. package/docs/command-detection-sequence.md +186 -0
  40. package/frontend/dist/assets/AgentsPage-Dqb_aqAA.js +1 -0
  41. package/frontend/dist/assets/ChatPage-BvQmXfcP.css +1 -0
  42. package/frontend/dist/assets/ChatPage-L8Paywyc.js +91 -0
  43. package/frontend/dist/assets/CommandForm-DLl7EIMS.js +7 -0
  44. package/frontend/dist/assets/CommandsPage-Bzavq0Ec.js +1 -0
  45. package/frontend/dist/assets/DashboardPage-B3o4AYFT.js +15 -0
  46. package/frontend/dist/assets/FileBrowser-DL3ayaqb.js +1 -0
  47. package/frontend/dist/assets/GeneralSettingsPage-CBN_de-V.js +1 -0
  48. package/frontend/dist/assets/LandingPage-Dl4ioKos.js +1 -0
  49. package/frontend/dist/assets/LoginPage-4QqRdiSi.js +12 -0
  50. package/frontend/dist/assets/McpPage-CY3tYiqj.js +39 -0
  51. package/frontend/dist/assets/MemorySettingsPage-DGxrok5K.js +1 -0
  52. package/frontend/dist/assets/ProjectSelector-hgmGYVFh.js +1 -0
  53. package/frontend/dist/assets/ProjectsPage-D399IM0c.js +14 -0
  54. package/frontend/dist/assets/SettingsLayout-CL_K-lzJ.js +1 -0
  55. package/frontend/dist/assets/SubagentForm-DXtTTIKg.js +7 -0
  56. package/frontend/dist/assets/SubagentsPage-Chbhj8p2.js +1 -0
  57. package/frontend/dist/assets/ToastTestPage-DT4wuN5C.js +1 -0
  58. package/frontend/dist/assets/UnifiedToolSelector-CsM9qBvs.js +1 -0
  59. package/frontend/dist/assets/VersionSettingsPage-74Q-LVgA.js +5 -0
  60. package/frontend/dist/assets/agents-ClAzIJTw.js +1 -0
  61. package/frontend/dist/assets/agents-DwCY2K8p.css +1 -0
  62. package/frontend/dist/assets/authFetch-BATQyPG5.js +1 -0
  63. package/frontend/dist/assets/data-structures-DLJedtzx.js +27 -0
  64. package/frontend/dist/assets/dateFormat-CXa8VnEC.js +1 -0
  65. package/frontend/dist/assets/index-B9YHa7XT.css +1 -0
  66. package/frontend/dist/assets/index-B_CTNvca.js +268 -0
  67. package/frontend/dist/assets/monaco-editor-C7Z4sOhS.js +19 -0
  68. package/frontend/dist/assets/syntax-highlighting-YWvMU4Hm.js +24 -0
  69. package/frontend/dist/assets/tabManager-DV8urRBM.js +30 -0
  70. package/frontend/dist/assets/table-D6q1rytw.js +1 -0
  71. package/frontend/dist/assets/tools-C4EPanYi.js +1 -0
  72. package/frontend/dist/assets/ui-components-Cw21Epuw.js +481 -0
  73. package/frontend/dist/assets/useAgents-DwnOE1_k.js +2 -0
  74. package/frontend/dist/assets/useClaudeVersions-CQdGnCqv.js +1 -0
  75. package/frontend/dist/assets/useCommands-CCVaurbt.js +1 -0
  76. package/frontend/dist/cc-studio.png +0 -0
  77. package/frontend/dist/index.html +68 -84
  78. package/frontend/dist/vite.svg +1 -0
  79. package/package.json +27 -27
  80. package/scripts/README.md +76 -0
  81. package/scripts/fix-project-names.js +113 -0
  82. package/scripts/migrate-projects.js +159 -0
  83. package/src/bin/agentstudio.ts +90 -121
  84. package/src/index.ts +139 -57
  85. package/src/routes/agents.ts +28 -29
  86. package/src/routes/{commands.ts.bak → commands.ts} +1 -1
  87. package/src/routes/{projects.ts.bak → projects.ts} +3 -3
  88. package/src/routes/{sessions.ts.bak → sessions.ts} +2 -2
  89. package/src/routes/{settings.ts.bak → settings.ts} +11 -11
  90. package/src/routes/{subagents.ts.bak → subagents.ts} +1 -1
  91. package/tsconfig.json +13 -12
  92. package/dist/types/claude-history.d.ts +0 -48
  93. package/dist/types/claude-history.d.ts.map +0 -1
  94. package/dist/types/claude-history.js +0 -2
  95. package/dist/types/claude-history.js.map +0 -1
  96. package/dist/types/claude-versions.d.ts +0 -31
  97. package/dist/types/claude-versions.d.ts.map +0 -1
  98. package/dist/types/claude-versions.js +0 -2
  99. package/dist/types/claude-versions.js.map +0 -1
  100. package/dist/types/commands.d.ts +0 -32
  101. package/dist/types/commands.d.ts.map +0 -1
  102. package/dist/types/commands.js +0 -2
  103. package/dist/types/commands.js.map +0 -1
  104. package/dist/types/index.d.ts +0 -81
  105. package/dist/types/index.d.ts.map +0 -1
  106. package/dist/types/index.js +0 -150
  107. package/dist/types/index.js.map +0 -1
  108. package/dist/types/subagents.d.ts +0 -88
  109. package/dist/types/subagents.d.ts.map +0 -1
  110. package/dist/types/subagents.js +0 -2
  111. package/dist/types/subagents.js.map +0 -1
  112. package/dist/utils/agentStorage.d.ts +0 -19
  113. package/dist/utils/agentStorage.d.ts.map +0 -1
  114. package/dist/utils/agentStorage.js +0 -110
  115. package/dist/utils/agentStorage.js.map +0 -1
  116. package/dist/utils/claudeVersionStorage.d.ts +0 -33
  117. package/dist/utils/claudeVersionStorage.d.ts.map +0 -1
  118. package/dist/utils/claudeVersionStorage.js +0 -168
  119. package/dist/utils/claudeVersionStorage.js.map +0 -1
  120. package/dist/utils/projectMetadataStorage.d.ts +0 -21
  121. package/dist/utils/projectMetadataStorage.d.ts.map +0 -1
  122. package/dist/utils/projectMetadataStorage.js +0 -68
  123. package/dist/utils/projectMetadataStorage.js.map +0 -1
  124. package/src/types/claude-history.ts +0 -50
  125. package/src/types/claude-versions.ts +0 -33
  126. package/src/types/commands.ts +0 -35
  127. package/src/types/index.ts +0 -248
  128. package/src/types/subagents.ts +0 -106
  129. package/src/utils/agentStorage.ts +0 -126
  130. package/src/utils/claudeVersionStorage.ts +0 -199
  131. package/src/utils/projectMetadataStorage.ts +0 -86
@@ -0,0 +1,658 @@
1
+ import express from 'express';
2
+ import { readFile, writeFile } from 'fs/promises';
3
+ import { join } from 'path';
4
+ import { homedir } from 'os';
5
+ import { exec } from 'child_process';
6
+ import { promisify } from 'util';
7
+ import { getAllVersions, getDefaultVersionId, setDefaultVersion, createVersion, updateVersion, deleteVersion, initializeSystemVersion } from '@agentstudio/shared/utils/claudeVersionStorage';
8
+ const router = express.Router();
9
+ const execAsync = promisify(exec);
10
+ // Package manager detection and utilities
11
+ const detectPackageManagers = async () => {
12
+ const managers = {
13
+ npm: false,
14
+ pnpm: false,
15
+ yarn: false
16
+ };
17
+ // Check npm
18
+ try {
19
+ await execAsync('npm --version');
20
+ managers.npm = true;
21
+ }
22
+ catch (error) {
23
+ // npm not available
24
+ }
25
+ // Check pnpm
26
+ try {
27
+ await execAsync('pnpm --version');
28
+ managers.pnpm = true;
29
+ }
30
+ catch (error) {
31
+ // pnpm not available
32
+ }
33
+ // Check yarn
34
+ try {
35
+ await execAsync('yarn --version');
36
+ managers.yarn = true;
37
+ }
38
+ catch (error) {
39
+ // yarn not available
40
+ }
41
+ return managers;
42
+ };
43
+ // Detect which package manager installed Claude Code
44
+ const detectClaudeCodeInstallationSource = async () => {
45
+ try {
46
+ // Get Claude Code executable path
47
+ const { stdout: claudePath } = await execAsync('which claude');
48
+ if (!claudePath)
49
+ return null;
50
+ const cleanPath = claudePath.trim();
51
+ console.log('Claude Code executable path:', cleanPath);
52
+ // Skip local node_modules paths - we want global installation
53
+ if (cleanPath.includes('node_modules/.bin')) {
54
+ console.log('Skipping local node_modules path, looking for global installation');
55
+ // Try to find global installation by checking PATH without local node_modules
56
+ try {
57
+ const { stdout: allClaudes } = await execAsync('which -a claude');
58
+ const claudes = allClaudes.trim().split('\n');
59
+ // Find the first non-local installation
60
+ for (const claudePathOption of claudes) {
61
+ if (!claudePathOption.includes('node_modules/.bin')) {
62
+ console.log('Found global Claude installation:', claudePathOption);
63
+ const globalPath = claudePathOption.trim();
64
+ // Check for pnpm patterns
65
+ if (globalPath.includes('/pnpm/') || globalPath.includes('pnpm')) {
66
+ console.log('Detected pnpm installation from global path');
67
+ return 'pnpm';
68
+ }
69
+ // Continue with other checks using this global path
70
+ const cleanGlobalPath = globalPath;
71
+ // Check for yarn patterns
72
+ if (cleanGlobalPath.includes('/yarn/') || cleanGlobalPath.includes('yarn')) {
73
+ console.log('Detected yarn installation from global path');
74
+ return 'yarn';
75
+ }
76
+ // Check npm patterns
77
+ try {
78
+ const { stdout: npmPrefix } = await execAsync('npm config get prefix');
79
+ if (cleanGlobalPath.startsWith(npmPrefix.trim())) {
80
+ console.log('Detected npm installation from global path');
81
+ return 'npm';
82
+ }
83
+ }
84
+ catch (error) {
85
+ // Ignore npm prefix error
86
+ }
87
+ break; // Use the first non-local path found
88
+ }
89
+ }
90
+ }
91
+ catch (error) {
92
+ console.log('Could not find alternative Claude installations');
93
+ }
94
+ }
95
+ // Check for pnpm patterns
96
+ if (cleanPath.includes('/pnpm/') || cleanPath.includes('pnpm')) {
97
+ console.log('Detected pnpm installation from path');
98
+ return 'pnpm';
99
+ }
100
+ // Check for yarn patterns
101
+ if (cleanPath.includes('/yarn/') || cleanPath.includes('yarn')) {
102
+ return 'yarn';
103
+ }
104
+ // Check npm patterns - could be in node_modules or npm prefix
105
+ try {
106
+ const { stdout: npmPrefix } = await execAsync('npm config get prefix');
107
+ if (cleanPath.startsWith(npmPrefix.trim())) {
108
+ return 'npm';
109
+ }
110
+ }
111
+ catch (error) {
112
+ // Ignore npm prefix error
113
+ }
114
+ // Additional checks for npm global installation patterns
115
+ if (cleanPath.includes('/node_modules/.bin/') ||
116
+ cleanPath.includes('/npm/') ||
117
+ cleanPath.includes('/.npm/')) {
118
+ return 'npm';
119
+ }
120
+ // Fallback: check for the presence of Claude Code in different package managers' global directories
121
+ const managers = await detectPackageManagers();
122
+ // Check pnpm global directory
123
+ if (managers.pnpm) {
124
+ try {
125
+ const { stdout: pnpmRoot } = await execAsync('pnpm root -g');
126
+ const pnpmClaudePath = `${pnpmRoot.trim()}/@anthropic-ai/claude-code`;
127
+ await execAsync(`test -d "${pnpmClaudePath}"`);
128
+ return 'pnpm';
129
+ }
130
+ catch (error) {
131
+ // Claude Code not found in pnpm global
132
+ }
133
+ }
134
+ // Check yarn global directory
135
+ if (managers.yarn) {
136
+ try {
137
+ const { stdout: yarnGlobalDir } = await execAsync('yarn global dir');
138
+ const yarnClaudePath = `${yarnGlobalDir.trim()}/node_modules/@anthropic-ai/claude-code`;
139
+ await execAsync(`test -d "${yarnClaudePath}"`);
140
+ return 'yarn';
141
+ }
142
+ catch (error) {
143
+ // Claude Code not found in yarn global
144
+ }
145
+ }
146
+ // Check npm global directory
147
+ if (managers.npm) {
148
+ try {
149
+ const { stdout: npmPrefix } = await execAsync('npm config get prefix');
150
+ const npmClaudePath = `${npmPrefix.trim()}/lib/node_modules/@anthropic-ai/claude-code`;
151
+ await execAsync(`test -d "${npmClaudePath}"`);
152
+ return 'npm';
153
+ }
154
+ catch (error) {
155
+ // Claude Code not found in npm global
156
+ }
157
+ }
158
+ return null;
159
+ }
160
+ catch (error) {
161
+ console.error('Error detecting Claude Code installation source:', error);
162
+ return null;
163
+ }
164
+ };
165
+ // Get preferred package manager for global installs
166
+ const getPreferredPackageManager = async () => {
167
+ // First try to detect which package manager installed Claude Code
168
+ const claudeInstallSource = await detectClaudeCodeInstallationSource();
169
+ if (claudeInstallSource) {
170
+ return claudeInstallSource;
171
+ }
172
+ // Fallback to priority order if detection fails
173
+ const managers = await detectPackageManagers();
174
+ if (managers.pnpm)
175
+ return 'pnpm';
176
+ if (managers.yarn)
177
+ return 'yarn';
178
+ if (managers.npm)
179
+ return 'npm';
180
+ return null;
181
+ };
182
+ // Get package manager version
183
+ const getPackageManagerVersion = async (manager) => {
184
+ try {
185
+ const { stdout } = await execAsync(`${manager} --version`);
186
+ return stdout.trim();
187
+ }
188
+ catch (error) {
189
+ return 'Not found';
190
+ }
191
+ };
192
+ // Get user's home directory
193
+ const getUserHomeDir = () => homedir();
194
+ const getGlobalMemoryPath = () => join(getUserHomeDir(), '.claude', 'CLAUDE.md');
195
+ // GET /api/settings/global-memory - Read global memory file
196
+ router.get('/global-memory', async (req, res) => {
197
+ try {
198
+ const filePath = getGlobalMemoryPath();
199
+ try {
200
+ const content = await readFile(filePath, 'utf-8');
201
+ res.type('text/plain').send(content);
202
+ }
203
+ catch (error) {
204
+ if (error.code === 'ENOENT') {
205
+ // File doesn't exist, return empty content
206
+ res.type('text/plain').send('');
207
+ }
208
+ else {
209
+ throw error;
210
+ }
211
+ }
212
+ }
213
+ catch (error) {
214
+ console.error('Error reading global memory:', error);
215
+ res.status(500).json({
216
+ error: 'Failed to read global memory',
217
+ message: error instanceof Error ? error.message : 'Unknown error'
218
+ });
219
+ }
220
+ });
221
+ // POST /api/settings/global-memory - Write global memory file
222
+ router.post('/global-memory', express.text({ type: 'text/plain' }), async (req, res) => {
223
+ try {
224
+ const content = req.body;
225
+ if (typeof content !== 'string') {
226
+ return res.status(400).json({
227
+ error: 'Invalid content type',
228
+ message: 'Content must be a string'
229
+ });
230
+ }
231
+ const filePath = getGlobalMemoryPath();
232
+ await writeFile(filePath, content, 'utf-8');
233
+ res.json({
234
+ success: true,
235
+ message: 'Global memory saved successfully',
236
+ filePath
237
+ });
238
+ }
239
+ catch (error) {
240
+ console.error('Error writing global memory:', error);
241
+ res.status(500).json({
242
+ error: 'Failed to save global memory',
243
+ message: error instanceof Error ? error.message : 'Unknown error'
244
+ });
245
+ }
246
+ });
247
+ // GET /api/settings/global-memory/path - Get the path to the global memory file
248
+ router.get('/global-memory/path', (req, res) => {
249
+ try {
250
+ const filePath = getGlobalMemoryPath();
251
+ res.json({
252
+ path: filePath,
253
+ homeDir: getUserHomeDir()
254
+ });
255
+ }
256
+ catch (error) {
257
+ console.error('Error getting global memory path:', error);
258
+ res.status(500).json({
259
+ error: 'Failed to get file path',
260
+ message: error instanceof Error ? error.message : 'Unknown error'
261
+ });
262
+ }
263
+ });
264
+ // GET /api/settings/versions - Get version information for Claude Code, Node.js, and package managers
265
+ router.get('/versions', async (req, res) => {
266
+ try {
267
+ const availableManagers = await detectPackageManagers();
268
+ const preferredManager = await getPreferredPackageManager();
269
+ const claudeInstallSource = await detectClaudeCodeInstallationSource();
270
+ const versions = {
271
+ nodejs: null,
272
+ packageManagers: {},
273
+ preferredManager: preferredManager,
274
+ claudeInstallSource: claudeInstallSource,
275
+ claudeCode: null,
276
+ lastChecked: new Date().toISOString()
277
+ };
278
+ // Get Node.js version
279
+ try {
280
+ const { stdout: nodeVersion } = await execAsync('node --version');
281
+ versions.nodejs = nodeVersion.trim();
282
+ }
283
+ catch (error) {
284
+ console.error('Failed to get Node.js version:', error);
285
+ versions.nodejs = 'Not found';
286
+ }
287
+ // Get all available package manager versions
288
+ for (const [manager, available] of Object.entries(availableManagers)) {
289
+ if (available) {
290
+ versions.packageManagers[manager] = await getPackageManagerVersion(manager);
291
+ }
292
+ else {
293
+ versions.packageManagers[manager] = 'Not installed';
294
+ }
295
+ }
296
+ // Get Claude Code version using the correct global path
297
+ try {
298
+ let claudeCommand = 'claude --version';
299
+ // If we detected a specific installation source, try to use the correct path
300
+ if (claudeInstallSource) {
301
+ try {
302
+ const { stdout: claudePath } = await execAsync('which claude');
303
+ if (claudePath && claudePath.includes('node_modules/.bin')) {
304
+ // We're getting the local version, try to find the global one
305
+ const { stdout: allClaudes } = await execAsync('which -a claude');
306
+ const claudes = allClaudes.trim().split('\n');
307
+ for (const claudePathOption of claudes) {
308
+ if (!claudePathOption.includes('node_modules/.bin')) {
309
+ claudeCommand = `"${claudePathOption.trim()}" --version`;
310
+ console.log('Using global Claude path for version:', claudePathOption.trim());
311
+ break;
312
+ }
313
+ }
314
+ }
315
+ }
316
+ catch (error) {
317
+ // Fallback to default command
318
+ }
319
+ }
320
+ const { stdout: claudeVersion } = await execAsync(claudeCommand);
321
+ versions.claudeCode = claudeVersion.trim();
322
+ console.log('Claude Code version detected:', claudeVersion.trim());
323
+ }
324
+ catch (error) {
325
+ console.error('Failed to get Claude Code version:', error);
326
+ versions.claudeCode = 'Not installed';
327
+ }
328
+ res.json(versions);
329
+ }
330
+ catch (error) {
331
+ console.error('Error getting version information:', error);
332
+ res.status(500).json({
333
+ error: 'Failed to get version information',
334
+ message: error instanceof Error ? error.message : 'Unknown error'
335
+ });
336
+ }
337
+ });
338
+ // POST /api/settings/update-claude - Update Claude Code using preferred package manager
339
+ router.post('/update-claude', async (req, res) => {
340
+ try {
341
+ const preferredManager = await getPreferredPackageManager();
342
+ if (!preferredManager) {
343
+ return res.status(400).json({
344
+ success: false,
345
+ error: 'No package manager available',
346
+ message: 'Please install npm, pnpm, or yarn to update Claude Code'
347
+ });
348
+ }
349
+ // Different commands for different package managers
350
+ let updateCommand;
351
+ switch (preferredManager) {
352
+ case 'pnpm':
353
+ updateCommand = 'pnpm add -g @anthropic-ai/claude-code@latest';
354
+ break;
355
+ case 'yarn':
356
+ updateCommand = 'yarn global add @anthropic-ai/claude-code@latest';
357
+ break;
358
+ case 'npm':
359
+ default:
360
+ updateCommand = 'npm update -g @anthropic-ai/claude-code';
361
+ break;
362
+ }
363
+ console.log(`Updating Claude Code using ${preferredManager}: ${updateCommand}`);
364
+ const { stdout, stderr } = await execAsync(updateCommand);
365
+ res.json({
366
+ success: true,
367
+ message: `Claude Code update completed using ${preferredManager}`,
368
+ packageManager: preferredManager,
369
+ command: updateCommand,
370
+ output: stdout,
371
+ error: stderr || null
372
+ });
373
+ }
374
+ catch (error) {
375
+ console.error('Failed to update Claude Code:', error);
376
+ res.status(500).json({
377
+ success: false,
378
+ error: 'Failed to update Claude Code',
379
+ message: error.message,
380
+ output: error.stdout || null,
381
+ stderr: error.stderr || null
382
+ });
383
+ }
384
+ });
385
+ // Claude 版本管理 API
386
+ // GET /api/settings/claude-versions - 获取所有 Claude 版本
387
+ router.get('/claude-versions', async (req, res) => {
388
+ try {
389
+ // 首先确保系统版本存在
390
+ try {
391
+ const { stdout: claudePath } = await execAsync('which claude');
392
+ if (claudePath) {
393
+ await initializeSystemVersion(claudePath.trim());
394
+ }
395
+ }
396
+ catch (error) {
397
+ console.warn('No system claude found:', error);
398
+ }
399
+ const versions = await getAllVersions();
400
+ const defaultVersionId = await getDefaultVersionId();
401
+ res.json({
402
+ versions,
403
+ defaultVersionId
404
+ });
405
+ }
406
+ catch (error) {
407
+ console.error('Error getting Claude versions:', error);
408
+ res.status(500).json({
409
+ error: 'Failed to get Claude versions',
410
+ message: error instanceof Error ? error.message : 'Unknown error'
411
+ });
412
+ }
413
+ });
414
+ // POST /api/settings/claude-versions - 创建新的 Claude 版本
415
+ router.post('/claude-versions', async (req, res) => {
416
+ try {
417
+ const data = req.body;
418
+ // 验证必填字段
419
+ if (!data.name || !data.alias) {
420
+ return res.status(400).json({
421
+ error: 'Missing required fields',
422
+ message: 'name and alias are required'
423
+ });
424
+ }
425
+ const version = await createVersion(data);
426
+ res.json(version);
427
+ }
428
+ catch (error) {
429
+ console.error('Error creating Claude version:', error);
430
+ const status = error instanceof Error && error.message.includes('已存在') ? 409 : 500;
431
+ res.status(status).json({
432
+ error: 'Failed to create Claude version',
433
+ message: error instanceof Error ? error.message : 'Unknown error'
434
+ });
435
+ }
436
+ });
437
+ // PUT /api/settings/claude-versions/:id - 更新 Claude 版本
438
+ router.put('/claude-versions/:id', async (req, res) => {
439
+ try {
440
+ const { id } = req.params;
441
+ const data = req.body;
442
+ const version = await updateVersion(id, data);
443
+ res.json(version);
444
+ }
445
+ catch (error) {
446
+ console.error('Error updating Claude version:', error);
447
+ const status = error instanceof Error && (error.message.includes('不存在') ||
448
+ error.message.includes('已存在') ||
449
+ error.message.includes('不允许')) ? 400 : 500;
450
+ res.status(status).json({
451
+ error: 'Failed to update Claude version',
452
+ message: error instanceof Error ? error.message : 'Unknown error'
453
+ });
454
+ }
455
+ });
456
+ // DELETE /api/settings/claude-versions/:id - 删除 Claude 版本
457
+ router.delete('/claude-versions/:id', async (req, res) => {
458
+ try {
459
+ const { id } = req.params;
460
+ await deleteVersion(id);
461
+ res.json({ success: true });
462
+ }
463
+ catch (error) {
464
+ console.error('Error deleting Claude version:', error);
465
+ const status = error instanceof Error && (error.message.includes('不存在') ||
466
+ error.message.includes('不允许')) ? 400 : 500;
467
+ res.status(status).json({
468
+ error: 'Failed to delete Claude version',
469
+ message: error instanceof Error ? error.message : 'Unknown error'
470
+ });
471
+ }
472
+ });
473
+ // PUT /api/settings/claude-versions/:id/set-default - 设置默认版本
474
+ router.put('/claude-versions/:id/set-default', async (req, res) => {
475
+ try {
476
+ const { id } = req.params;
477
+ await setDefaultVersion(id);
478
+ res.json({ success: true });
479
+ }
480
+ catch (error) {
481
+ console.error('Error setting default Claude version:', error);
482
+ const status = error instanceof Error && error.message.includes('不存在') ? 400 : 500;
483
+ res.status(status).json({
484
+ error: 'Failed to set default Claude version',
485
+ message: error instanceof Error ? error.message : 'Unknown error'
486
+ });
487
+ }
488
+ });
489
+ // POST /api/settings/claude-versions/detect - 检测 Claude CLI 安装
490
+ router.post('/claude-versions/detect', async (req, res) => {
491
+ try {
492
+ const result = {
493
+ userInstalled: false,
494
+ systemInstalled: false,
495
+ userPath: null,
496
+ systemPath: null,
497
+ version: null,
498
+ packageManager: null
499
+ };
500
+ // 检测用户自己安装的 Claude CLI (全局安装)
501
+ try {
502
+ const { stdout: claudePath } = await execAsync('which claude');
503
+ if (claudePath) {
504
+ const cleanPath = claudePath.trim();
505
+ // 检测是否是系统 npm 包自带的 (在项目 node_modules 中)
506
+ const projectRoot = process.cwd();
507
+ const isSystemPackage = cleanPath.includes(`${projectRoot}/node_modules`);
508
+ if (isSystemPackage) {
509
+ result.systemInstalled = true;
510
+ result.systemPath = cleanPath;
511
+ }
512
+ else {
513
+ result.userInstalled = true;
514
+ result.userPath = cleanPath;
515
+ }
516
+ // 获取版本
517
+ try {
518
+ const { stdout: version } = await execAsync(`"${cleanPath}" --version`);
519
+ result.version = version.trim();
520
+ }
521
+ catch (error) {
522
+ console.error('Failed to get Claude version:', error);
523
+ }
524
+ // 检测包管理器
525
+ if (result.userInstalled) {
526
+ result.packageManager = await detectClaudeCodeInstallationSource();
527
+ }
528
+ }
529
+ }
530
+ catch (error) {
531
+ console.log('No Claude CLI found in PATH');
532
+ }
533
+ // 如果没有找到全局安装的,检查系统 npm 包(在 backend/node_modules 中)
534
+ if (!result.systemInstalled) {
535
+ try {
536
+ const projectRoot = process.cwd();
537
+ // 在 workspace 项目中,backend 的依赖在 backend/node_modules
538
+ const systemClaudePath = join(projectRoot, 'backend', 'node_modules', '.bin', 'claude');
539
+ // 检查文件是否存在(.bin/claude 是符号链接,用 -e 而不是 -f)
540
+ const { stdout } = await execAsync(`test -e "${systemClaudePath}" && echo "exists"`);
541
+ if (stdout.trim() === 'exists') {
542
+ result.systemInstalled = true;
543
+ result.systemPath = systemClaudePath;
544
+ // 尝试获取版本
545
+ if (!result.version) {
546
+ try {
547
+ const { stdout: version } = await execAsync(`"${systemClaudePath}" --version`);
548
+ result.version = version.trim();
549
+ }
550
+ catch (error) {
551
+ console.error('Failed to get system package version:', error);
552
+ }
553
+ }
554
+ }
555
+ }
556
+ catch (error) {
557
+ console.log('System package not found:', error);
558
+ }
559
+ }
560
+ res.json(result);
561
+ }
562
+ catch (error) {
563
+ console.error('Error detecting Claude CLI:', error);
564
+ res.status(500).json({
565
+ error: 'Failed to detect Claude CLI',
566
+ message: error instanceof Error ? error.message : 'Unknown error'
567
+ });
568
+ }
569
+ });
570
+ // POST /api/settings/claude-versions/init-system - 初始化系统版本
571
+ router.post('/claude-versions/init-system', async (req, res) => {
572
+ try {
573
+ const { useUserInstalled, authToken, skipAuthToken } = req.body;
574
+ let claudePath = null;
575
+ // 根据用户选择获取 Claude 路径
576
+ if (useUserInstalled) {
577
+ // 使用用户自己安装的
578
+ try {
579
+ const { stdout } = await execAsync('which claude');
580
+ const cleanPath = stdout.trim();
581
+ const projectRoot = process.cwd();
582
+ // 确保不是项目内的
583
+ if (!cleanPath.includes(`${projectRoot}/node_modules`)) {
584
+ claudePath = cleanPath;
585
+ }
586
+ else {
587
+ return res.status(400).json({
588
+ error: 'Invalid selection',
589
+ message: '未找到用户全局安装的 Claude CLI'
590
+ });
591
+ }
592
+ }
593
+ catch (error) {
594
+ return res.status(400).json({
595
+ error: 'Claude CLI not found',
596
+ message: '未找到用户安装的 Claude CLI'
597
+ });
598
+ }
599
+ }
600
+ else {
601
+ // 使用系统 npm 包自带的(在 backend/node_modules 中)
602
+ try {
603
+ const projectRoot = process.cwd();
604
+ const systemClaudePath = join(projectRoot, 'backend', 'node_modules', '.bin', 'claude');
605
+ const { stdout } = await execAsync(`test -e "${systemClaudePath}" && echo "exists"`);
606
+ if (stdout.trim() === 'exists') {
607
+ claudePath = systemClaudePath;
608
+ }
609
+ else {
610
+ return res.status(400).json({
611
+ error: 'System Claude not found',
612
+ message: '系统 npm 包中未找到 Claude CLI'
613
+ });
614
+ }
615
+ }
616
+ catch (error) {
617
+ return res.status(400).json({
618
+ error: 'System Claude not found',
619
+ message: '系统 npm 包中未找到 Claude CLI'
620
+ });
621
+ }
622
+ }
623
+ if (!claudePath) {
624
+ return res.status(400).json({
625
+ error: 'No Claude CLI found',
626
+ message: '未找到可用的 Claude CLI'
627
+ });
628
+ }
629
+ // 准备环境变量
630
+ const environmentVariables = {};
631
+ if (authToken && !skipAuthToken) {
632
+ environmentVariables.ANTHROPIC_AUTH_TOKEN = authToken;
633
+ }
634
+ // 创建或更新系统版本
635
+ const storage = await import('@agentstudio/shared/utils/claudeVersionStorage');
636
+ let systemVersion = await storage.initializeSystemVersion(claudePath);
637
+ // 更新环境变量
638
+ if (Object.keys(environmentVariables).length > 0) {
639
+ systemVersion = await storage.updateVersion(systemVersion.id, {
640
+ environmentVariables
641
+ });
642
+ }
643
+ res.json({
644
+ success: true,
645
+ version: systemVersion,
646
+ message: '系统版本初始化成功'
647
+ });
648
+ }
649
+ catch (error) {
650
+ console.error('Error initializing system version:', error);
651
+ res.status(500).json({
652
+ error: 'Failed to initialize system version',
653
+ message: error instanceof Error ? error.message : 'Unknown error'
654
+ });
655
+ }
656
+ });
657
+ export default router;
658
+ //# sourceMappingURL=settings.js.map