agentstudio 0.1.8 → 0.1.10
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 +481 -37
- package/README.zh-CN.md +525 -0
- package/{dist → backend/dist}/bin/agentstudio.js +7 -5
- package/backend/dist/bin/agentstudio.js.map +1 -0
- package/backend/dist/index.d.ts +3 -0
- package/backend/dist/index.d.ts.map +1 -0
- package/{dist → backend/dist}/index.js +9 -28
- package/{dist → backend/dist}/index.js.map +1 -1
- package/{dist → backend/dist}/routes/settings.js +1 -1
- package/{dist → backend/dist}/routes/settings.js.map +1 -1
- package/package.json +35 -43
- package/.cc-sessions/ppt-editor/session_1756253549429_uau1hm6lh.json +0 -665
- package/.cc-sessions/ppt-editor/session_1756257240855_v0wa26mde.json +0 -394
- package/.env +0 -15
- package/dist/bin/agentstudio.js.map +0 -1
- package/dist/index.d.ts +0 -2
- package/dist/index.d.ts.map +0 -1
- package/docs/chat-clean-1.svg +0 -1
- package/docs/chat-clean.md +0 -60
- package/docs/chat-comprehensive-1.svg +0 -1
- package/docs/chat-comprehensive.md +0 -166
- package/docs/chat_api_sequence_diagram.md +0 -58
- package/docs/command-detection-logic.md +0 -306
- package/docs/command-detection-sequence.md +0 -186
- package/frontend/dist/assets/AgentsPage-Dqb_aqAA.js +0 -1
- package/frontend/dist/assets/ChatPage-BvQmXfcP.css +0 -1
- package/frontend/dist/assets/ChatPage-L8Paywyc.js +0 -91
- package/frontend/dist/assets/CommandForm-DLl7EIMS.js +0 -7
- package/frontend/dist/assets/CommandsPage-Bzavq0Ec.js +0 -1
- package/frontend/dist/assets/DashboardPage-B3o4AYFT.js +0 -15
- package/frontend/dist/assets/FileBrowser-DL3ayaqb.js +0 -1
- package/frontend/dist/assets/GeneralSettingsPage-CBN_de-V.js +0 -1
- package/frontend/dist/assets/LandingPage-Dl4ioKos.js +0 -1
- package/frontend/dist/assets/LoginPage-4QqRdiSi.js +0 -12
- package/frontend/dist/assets/McpPage-CY3tYiqj.js +0 -39
- package/frontend/dist/assets/MemorySettingsPage-DGxrok5K.js +0 -1
- package/frontend/dist/assets/ProjectSelector-hgmGYVFh.js +0 -1
- package/frontend/dist/assets/ProjectsPage-D399IM0c.js +0 -14
- package/frontend/dist/assets/SettingsLayout-CL_K-lzJ.js +0 -1
- package/frontend/dist/assets/SubagentForm-DXtTTIKg.js +0 -7
- package/frontend/dist/assets/SubagentsPage-Chbhj8p2.js +0 -1
- package/frontend/dist/assets/ToastTestPage-DT4wuN5C.js +0 -1
- package/frontend/dist/assets/UnifiedToolSelector-CsM9qBvs.js +0 -1
- package/frontend/dist/assets/VersionSettingsPage-74Q-LVgA.js +0 -5
- package/frontend/dist/assets/agents-ClAzIJTw.js +0 -1
- package/frontend/dist/assets/agents-DwCY2K8p.css +0 -1
- package/frontend/dist/assets/authFetch-BATQyPG5.js +0 -1
- package/frontend/dist/assets/data-structures-DLJedtzx.js +0 -27
- package/frontend/dist/assets/dateFormat-CXa8VnEC.js +0 -1
- package/frontend/dist/assets/index-B9YHa7XT.css +0 -1
- package/frontend/dist/assets/index-B_CTNvca.js +0 -268
- package/frontend/dist/assets/monaco-editor-C7Z4sOhS.js +0 -19
- package/frontend/dist/assets/syntax-highlighting-YWvMU4Hm.js +0 -24
- package/frontend/dist/assets/tabManager-DV8urRBM.js +0 -30
- package/frontend/dist/assets/table-D6q1rytw.js +0 -1
- package/frontend/dist/assets/tools-C4EPanYi.js +0 -1
- package/frontend/dist/assets/ui-components-Cw21Epuw.js +0 -481
- package/frontend/dist/assets/useAgents-DwnOE1_k.js +0 -2
- package/frontend/dist/assets/useClaudeVersions-CQdGnCqv.js +0 -1
- package/frontend/dist/assets/useCommands-CCVaurbt.js +0 -1
- package/frontend/dist/cc-studio.png +0 -0
- package/frontend/dist/index.html +0 -70
- package/frontend/dist/vite.svg +0 -1
- package/scripts/README.md +0 -76
- package/scripts/fix-project-names.js +0 -113
- package/scripts/migrate-projects.js +0 -159
- package/shared/index.d.ts +0 -6
- package/shared/index.d.ts.map +0 -1
- package/shared/index.js +0 -7
- package/shared/types/agents.d.ts +0 -80
- package/shared/types/agents.d.ts.map +0 -1
- package/shared/types/agents.js +0 -145
- package/shared/types/claude-history.d.ts +0 -61
- package/shared/types/claude-history.d.ts.map +0 -1
- package/shared/types/claude-history.js +0 -2
- package/shared/types/claude-versions.d.ts +0 -40
- package/shared/types/claude-versions.d.ts.map +0 -1
- package/shared/types/claude-versions.js +0 -1
- package/shared/types/commands.d.ts +0 -48
- package/shared/types/commands.d.ts.map +0 -1
- package/shared/types/commands.js +0 -19
- package/shared/types/projects.d.ts +0 -35
- package/shared/types/projects.d.ts.map +0 -1
- package/shared/types/projects.js +0 -2
- package/shared/types/subagents.d.ts +0 -26
- package/shared/types/subagents.d.ts.map +0 -1
- package/shared/types/subagents.js +0 -1
- package/shared/utils/agentStorage.d.ts +0 -27
- package/shared/utils/agentStorage.d.ts.map +0 -1
- package/shared/utils/agentStorage.js +0 -392
- package/shared/utils/claudeVersionStorage.d.ts +0 -16
- package/shared/utils/claudeVersionStorage.d.ts.map +0 -1
- package/shared/utils/claudeVersionStorage.js +0 -230
- package/shared/utils/projectMetadataStorage.d.ts +0 -94
- package/shared/utils/projectMetadataStorage.d.ts.map +0 -1
- package/shared/utils/projectMetadataStorage.js +0 -422
- package/shared/utils/toolMapping.d.ts +0 -56
- package/shared/utils/toolMapping.d.ts.map +0 -1
- package/shared/utils/toolMapping.js +0 -71
- package/src/bin/agentstudio.ts +0 -130
- package/src/index.ts +0 -183
- package/src/middleware/auth.ts +0 -26
- package/src/routes/agents.ts +0 -884
- package/src/routes/auth.ts +0 -73
- package/src/routes/commands.ts +0 -441
- package/src/routes/files.ts +0 -352
- package/src/routes/mcp.ts +0 -751
- package/src/routes/media.ts +0 -140
- package/src/routes/projects.ts +0 -601
- package/src/routes/sessions.ts +0 -809
- package/src/routes/settings.ts +0 -718
- package/src/routes/slides.ts +0 -170
- package/src/routes/subagents.ts +0 -364
- package/src/services/claudeSession.ts +0 -293
- package/src/services/messageQueue.ts +0 -71
- package/src/services/sessionManager.ts +0 -532
- package/src/utils/jwt.ts +0 -36
- package/tsconfig.json +0 -27
- /package/{dist → backend/dist}/bin/agentstudio.d.ts +0 -0
- /package/{dist → backend/dist}/bin/agentstudio.d.ts.map +0 -0
- /package/{dist → backend/dist}/middleware/auth.d.ts +0 -0
- /package/{dist → backend/dist}/middleware/auth.d.ts.map +0 -0
- /package/{dist → backend/dist}/middleware/auth.js +0 -0
- /package/{dist → backend/dist}/middleware/auth.js.map +0 -0
- /package/{dist → backend/dist}/routes/agents.d.ts +0 -0
- /package/{dist → backend/dist}/routes/agents.d.ts.map +0 -0
- /package/{dist → backend/dist}/routes/agents.js +0 -0
- /package/{dist → backend/dist}/routes/agents.js.map +0 -0
- /package/{dist → backend/dist}/routes/auth.d.ts +0 -0
- /package/{dist → backend/dist}/routes/auth.d.ts.map +0 -0
- /package/{dist → backend/dist}/routes/auth.js +0 -0
- /package/{dist → backend/dist}/routes/auth.js.map +0 -0
- /package/{dist → backend/dist}/routes/commands.d.ts +0 -0
- /package/{dist → backend/dist}/routes/commands.d.ts.map +0 -0
- /package/{dist → backend/dist}/routes/commands.js +0 -0
- /package/{dist → backend/dist}/routes/commands.js.map +0 -0
- /package/{dist → backend/dist}/routes/files.d.ts +0 -0
- /package/{dist → backend/dist}/routes/files.d.ts.map +0 -0
- /package/{dist → backend/dist}/routes/files.js +0 -0
- /package/{dist → backend/dist}/routes/files.js.map +0 -0
- /package/{dist → backend/dist}/routes/mcp.d.ts +0 -0
- /package/{dist → backend/dist}/routes/mcp.d.ts.map +0 -0
- /package/{dist → backend/dist}/routes/mcp.js +0 -0
- /package/{dist → backend/dist}/routes/mcp.js.map +0 -0
- /package/{dist → backend/dist}/routes/media.d.ts +0 -0
- /package/{dist → backend/dist}/routes/media.d.ts.map +0 -0
- /package/{dist → backend/dist}/routes/media.js +0 -0
- /package/{dist → backend/dist}/routes/media.js.map +0 -0
- /package/{dist → backend/dist}/routes/projects.d.ts +0 -0
- /package/{dist → backend/dist}/routes/projects.d.ts.map +0 -0
- /package/{dist → backend/dist}/routes/projects.js +0 -0
- /package/{dist → backend/dist}/routes/projects.js.map +0 -0
- /package/{dist → backend/dist}/routes/sessions.d.ts +0 -0
- /package/{dist → backend/dist}/routes/sessions.d.ts.map +0 -0
- /package/{dist → backend/dist}/routes/sessions.js +0 -0
- /package/{dist → backend/dist}/routes/sessions.js.map +0 -0
- /package/{dist → backend/dist}/routes/settings.d.ts +0 -0
- /package/{dist → backend/dist}/routes/settings.d.ts.map +0 -0
- /package/{dist → backend/dist}/routes/slides.d.ts +0 -0
- /package/{dist → backend/dist}/routes/slides.d.ts.map +0 -0
- /package/{dist → backend/dist}/routes/slides.js +0 -0
- /package/{dist → backend/dist}/routes/slides.js.map +0 -0
- /package/{dist → backend/dist}/routes/subagents.d.ts +0 -0
- /package/{dist → backend/dist}/routes/subagents.d.ts.map +0 -0
- /package/{dist → backend/dist}/routes/subagents.js +0 -0
- /package/{dist → backend/dist}/routes/subagents.js.map +0 -0
- /package/{dist → backend/dist}/services/claudeSession.d.ts +0 -0
- /package/{dist → backend/dist}/services/claudeSession.d.ts.map +0 -0
- /package/{dist → backend/dist}/services/claudeSession.js +0 -0
- /package/{dist → backend/dist}/services/claudeSession.js.map +0 -0
- /package/{dist → backend/dist}/services/messageQueue.d.ts +0 -0
- /package/{dist → backend/dist}/services/messageQueue.d.ts.map +0 -0
- /package/{dist → backend/dist}/services/messageQueue.js +0 -0
- /package/{dist → backend/dist}/services/messageQueue.js.map +0 -0
- /package/{dist → backend/dist}/services/sessionManager.d.ts +0 -0
- /package/{dist → backend/dist}/services/sessionManager.d.ts.map +0 -0
- /package/{dist → backend/dist}/services/sessionManager.js +0 -0
- /package/{dist → backend/dist}/services/sessionManager.js.map +0 -0
- /package/{dist → backend/dist}/utils/jwt.d.ts +0 -0
- /package/{dist → backend/dist}/utils/jwt.d.ts.map +0 -0
- /package/{dist → backend/dist}/utils/jwt.js +0 -0
- /package/{dist → backend/dist}/utils/jwt.js.map +0 -0
|
@@ -1,392 +0,0 @@
|
|
|
1
|
-
import * as fs from 'fs';
|
|
2
|
-
import * as path from 'path';
|
|
3
|
-
import * as os from 'os';
|
|
4
|
-
import { BUILTIN_AGENTS } from '../types/agents.js';
|
|
5
|
-
import { query } from '@anthropic-ai/claude-code';
|
|
6
|
-
export class AgentStorage {
|
|
7
|
-
agentsDir;
|
|
8
|
-
workingDir;
|
|
9
|
-
constructor(workingDir = process.cwd()) {
|
|
10
|
-
const baseDir = path.join(os.homedir(), '.claude-agent');
|
|
11
|
-
this.agentsDir = path.join(baseDir, 'agents');
|
|
12
|
-
this.workingDir = workingDir;
|
|
13
|
-
// Ensure directories exist
|
|
14
|
-
this.ensureDirectoriesExist();
|
|
15
|
-
// Initialize built-in agents if not exists
|
|
16
|
-
this.initializeBuiltinAgents();
|
|
17
|
-
}
|
|
18
|
-
ensureDirectoriesExist() {
|
|
19
|
-
// Ensure global agents directory exists
|
|
20
|
-
if (!fs.existsSync(this.agentsDir)) {
|
|
21
|
-
fs.mkdirSync(this.agentsDir, { recursive: true });
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
getSessionsDir() {
|
|
25
|
-
const sessionsDir = path.join(this.workingDir, '.cc-sessions');
|
|
26
|
-
// console.log('AgentStorage getSessionsDir - workingDir:', this.workingDir, 'sessionsDir:', sessionsDir);
|
|
27
|
-
if (!fs.existsSync(sessionsDir)) {
|
|
28
|
-
fs.mkdirSync(sessionsDir, { recursive: true });
|
|
29
|
-
}
|
|
30
|
-
return sessionsDir;
|
|
31
|
-
}
|
|
32
|
-
initializeBuiltinAgents() {
|
|
33
|
-
BUILTIN_AGENTS.forEach(agentTemplate => {
|
|
34
|
-
const agentPath = path.join(this.agentsDir, `${agentTemplate.id}.json`);
|
|
35
|
-
if (!fs.existsSync(agentPath)) {
|
|
36
|
-
const now = new Date().toISOString();
|
|
37
|
-
const fullAgent = {
|
|
38
|
-
version: '1.0.0',
|
|
39
|
-
maxTurns: 25,
|
|
40
|
-
permissionMode: 'acceptEdits',
|
|
41
|
-
author: 'Claude Agent System',
|
|
42
|
-
createdAt: now,
|
|
43
|
-
updatedAt: now,
|
|
44
|
-
...agentTemplate
|
|
45
|
-
};
|
|
46
|
-
this.saveAgent(fullAgent);
|
|
47
|
-
}
|
|
48
|
-
});
|
|
49
|
-
}
|
|
50
|
-
// Agent management
|
|
51
|
-
getAllAgents() {
|
|
52
|
-
const agentFiles = fs.readdirSync(this.agentsDir)
|
|
53
|
-
.filter(file => file.endsWith('.json'));
|
|
54
|
-
const agents = [];
|
|
55
|
-
for (const file of agentFiles) {
|
|
56
|
-
try {
|
|
57
|
-
const filePath = path.join(this.agentsDir, file);
|
|
58
|
-
const agentData = JSON.parse(fs.readFileSync(filePath, 'utf-8'));
|
|
59
|
-
agents.push(agentData);
|
|
60
|
-
}
|
|
61
|
-
catch (error) {
|
|
62
|
-
console.error(`Failed to read agent file ${file}:`, error);
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
return agents.sort((a, b) => a.name.localeCompare(b.name));
|
|
66
|
-
}
|
|
67
|
-
getAgent(agentId) {
|
|
68
|
-
try {
|
|
69
|
-
const filePath = path.join(this.agentsDir, `${agentId}.json`);
|
|
70
|
-
if (!fs.existsSync(filePath)) {
|
|
71
|
-
return null;
|
|
72
|
-
}
|
|
73
|
-
return JSON.parse(fs.readFileSync(filePath, 'utf-8'));
|
|
74
|
-
}
|
|
75
|
-
catch (error) {
|
|
76
|
-
console.error(`Failed to read agent ${agentId}:`, error);
|
|
77
|
-
return null;
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
saveAgent(agent) {
|
|
81
|
-
try {
|
|
82
|
-
agent.updatedAt = new Date().toISOString();
|
|
83
|
-
const filePath = path.join(this.agentsDir, `${agent.id}.json`);
|
|
84
|
-
fs.writeFileSync(filePath, JSON.stringify(agent, null, 2), 'utf-8');
|
|
85
|
-
}
|
|
86
|
-
catch (error) {
|
|
87
|
-
console.error(`Failed to save agent ${agent.id}:`, error);
|
|
88
|
-
throw error;
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
deleteAgent(agentId) {
|
|
92
|
-
try {
|
|
93
|
-
const filePath = path.join(this.agentsDir, `${agentId}.json`);
|
|
94
|
-
if (fs.existsSync(filePath)) {
|
|
95
|
-
// Don't delete built-in agents, just disable them
|
|
96
|
-
const agent = this.getAgent(agentId);
|
|
97
|
-
if (agent && BUILTIN_AGENTS.some(builtin => builtin.id === agentId)) {
|
|
98
|
-
agent.enabled = false;
|
|
99
|
-
this.saveAgent(agent);
|
|
100
|
-
return true;
|
|
101
|
-
}
|
|
102
|
-
fs.unlinkSync(filePath);
|
|
103
|
-
// Also delete all sessions for this agent
|
|
104
|
-
this.deleteAgentSessions(agentId);
|
|
105
|
-
return true;
|
|
106
|
-
}
|
|
107
|
-
return false;
|
|
108
|
-
}
|
|
109
|
-
catch (error) {
|
|
110
|
-
console.error(`Failed to delete agent ${agentId}:`, error);
|
|
111
|
-
return false;
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
createAgent(agentData) {
|
|
115
|
-
const now = new Date().toISOString();
|
|
116
|
-
const agent = {
|
|
117
|
-
...agentData,
|
|
118
|
-
createdAt: now,
|
|
119
|
-
updatedAt: now
|
|
120
|
-
};
|
|
121
|
-
this.saveAgent(agent);
|
|
122
|
-
return agent;
|
|
123
|
-
}
|
|
124
|
-
// Session management
|
|
125
|
-
getAgentSessionsDir(agentId) {
|
|
126
|
-
const dir = path.join(this.getSessionsDir(), agentId);
|
|
127
|
-
if (!fs.existsSync(dir)) {
|
|
128
|
-
fs.mkdirSync(dir, { recursive: true });
|
|
129
|
-
}
|
|
130
|
-
return dir;
|
|
131
|
-
}
|
|
132
|
-
getAgentSessions(agentId, searchTerm) {
|
|
133
|
-
const sessionsDir = this.getAgentSessionsDir(agentId);
|
|
134
|
-
const sessionFiles = fs.readdirSync(sessionsDir)
|
|
135
|
-
.filter(file => file.endsWith('.json'));
|
|
136
|
-
const sessions = [];
|
|
137
|
-
for (const file of sessionFiles) {
|
|
138
|
-
try {
|
|
139
|
-
const filePath = path.join(sessionsDir, file);
|
|
140
|
-
const sessionData = JSON.parse(fs.readFileSync(filePath, 'utf-8'));
|
|
141
|
-
sessions.push(sessionData);
|
|
142
|
-
}
|
|
143
|
-
catch (error) {
|
|
144
|
-
console.error(`Failed to read session file ${file}:`, error);
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
let filteredSessions = sessions;
|
|
148
|
-
// Filter by search term if provided
|
|
149
|
-
if (searchTerm && searchTerm.trim()) {
|
|
150
|
-
const searchTermLower = searchTerm.trim().toLowerCase();
|
|
151
|
-
filteredSessions = sessions.filter(session => {
|
|
152
|
-
if (session.title.toLowerCase().includes(searchTermLower)) {
|
|
153
|
-
return true;
|
|
154
|
-
}
|
|
155
|
-
return session.messages.some(message => {
|
|
156
|
-
if (message.content && message.content.toLowerCase().includes(searchTermLower)) {
|
|
157
|
-
return true;
|
|
158
|
-
}
|
|
159
|
-
if (message.messageParts) {
|
|
160
|
-
return message.messageParts.some(part => {
|
|
161
|
-
if (part.type === 'text' && part.content && part.content.toLowerCase().includes(searchTermLower)) {
|
|
162
|
-
return true;
|
|
163
|
-
}
|
|
164
|
-
if (part.type === 'tool' && part.toolData) {
|
|
165
|
-
if (part.toolData.toolName.toLowerCase().includes(searchTermLower)) {
|
|
166
|
-
return true;
|
|
167
|
-
}
|
|
168
|
-
const inputStr = JSON.stringify(part.toolData.toolInput).toLowerCase();
|
|
169
|
-
if (inputStr.includes(searchTermLower)) {
|
|
170
|
-
return true;
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
return false;
|
|
174
|
-
});
|
|
175
|
-
}
|
|
176
|
-
return false;
|
|
177
|
-
});
|
|
178
|
-
});
|
|
179
|
-
}
|
|
180
|
-
return filteredSessions.sort((a, b) => b.lastUpdated - a.lastUpdated);
|
|
181
|
-
}
|
|
182
|
-
getSession(agentId, sessionId) {
|
|
183
|
-
try {
|
|
184
|
-
const sessionsDir = this.getAgentSessionsDir(agentId);
|
|
185
|
-
const filePath = path.join(sessionsDir, `${sessionId}.json`);
|
|
186
|
-
if (!fs.existsSync(filePath)) {
|
|
187
|
-
return null;
|
|
188
|
-
}
|
|
189
|
-
return JSON.parse(fs.readFileSync(filePath, 'utf-8'));
|
|
190
|
-
}
|
|
191
|
-
catch (error) {
|
|
192
|
-
console.error(`Failed to read session ${sessionId} for agent ${agentId}:`, error);
|
|
193
|
-
return null;
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
createSession(agentId, title) {
|
|
197
|
-
const sessionId = `session_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
|
198
|
-
const agent = this.getAgent(agentId);
|
|
199
|
-
const session = {
|
|
200
|
-
id: sessionId,
|
|
201
|
-
agentId,
|
|
202
|
-
title: title || `${agent?.name || 'Agent'} 会话 ${new Date().toLocaleString()}`,
|
|
203
|
-
createdAt: Date.now(),
|
|
204
|
-
lastUpdated: Date.now(),
|
|
205
|
-
messages: []
|
|
206
|
-
};
|
|
207
|
-
this.saveSession(session);
|
|
208
|
-
return session;
|
|
209
|
-
}
|
|
210
|
-
createSessionWithId(agentId, sessionId, title) {
|
|
211
|
-
const agent = this.getAgent(agentId);
|
|
212
|
-
const session = {
|
|
213
|
-
id: sessionId, // Use AI-provided session_id
|
|
214
|
-
agentId,
|
|
215
|
-
title: title || `${agent?.name || 'Agent'} 会话 ${new Date().toLocaleString()}`,
|
|
216
|
-
createdAt: Date.now(),
|
|
217
|
-
lastUpdated: Date.now(),
|
|
218
|
-
messages: []
|
|
219
|
-
// claudeSessionId will be set when AI returns it in init message
|
|
220
|
-
};
|
|
221
|
-
this.saveSession(session);
|
|
222
|
-
return session;
|
|
223
|
-
}
|
|
224
|
-
saveSession(session) {
|
|
225
|
-
try {
|
|
226
|
-
const sessionsDir = this.getAgentSessionsDir(session.agentId);
|
|
227
|
-
const filePath = path.join(sessionsDir, `${session.id}.json`);
|
|
228
|
-
fs.writeFileSync(filePath, JSON.stringify(session, null, 2), 'utf-8');
|
|
229
|
-
}
|
|
230
|
-
catch (error) {
|
|
231
|
-
console.error(`Failed to save session ${session.id}:`, error);
|
|
232
|
-
throw error;
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
deleteSession(agentId, sessionId) {
|
|
236
|
-
try {
|
|
237
|
-
const sessionsDir = this.getAgentSessionsDir(agentId);
|
|
238
|
-
const filePath = path.join(sessionsDir, `${sessionId}.json`);
|
|
239
|
-
if (fs.existsSync(filePath)) {
|
|
240
|
-
fs.unlinkSync(filePath);
|
|
241
|
-
return true;
|
|
242
|
-
}
|
|
243
|
-
return false;
|
|
244
|
-
}
|
|
245
|
-
catch (error) {
|
|
246
|
-
console.error(`Failed to delete session ${sessionId}:`, error);
|
|
247
|
-
return false;
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
deleteAgentSessions(agentId) {
|
|
251
|
-
try {
|
|
252
|
-
const sessionsDir = this.getAgentSessionsDir(agentId);
|
|
253
|
-
const sessionFiles = fs.readdirSync(sessionsDir);
|
|
254
|
-
for (const file of sessionFiles) {
|
|
255
|
-
if (file.endsWith('.json')) {
|
|
256
|
-
fs.unlinkSync(path.join(sessionsDir, file));
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
catch (error) {
|
|
261
|
-
console.error(`Failed to delete sessions for agent ${agentId}:`, error);
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
// Helper method to check if session title should be updated
|
|
265
|
-
shouldUpdateTitle(title) {
|
|
266
|
-
return title.includes('会话') && title.includes(new Date().toLocaleString().split(' ')[0]);
|
|
267
|
-
}
|
|
268
|
-
// Generate intelligent session title based on first user message using Claude Code SDK
|
|
269
|
-
async updateSessionTitle(session) {
|
|
270
|
-
// Only update if it's still the default title
|
|
271
|
-
if (!this.shouldUpdateTitle(session.title)) {
|
|
272
|
-
return;
|
|
273
|
-
}
|
|
274
|
-
// Find the first user message
|
|
275
|
-
const firstUserMessage = session.messages.find(msg => msg.role === 'user');
|
|
276
|
-
if (!firstUserMessage) {
|
|
277
|
-
return;
|
|
278
|
-
}
|
|
279
|
-
let userQuestion = '';
|
|
280
|
-
// Extract text content from the message
|
|
281
|
-
if (firstUserMessage.content) {
|
|
282
|
-
userQuestion = firstUserMessage.content;
|
|
283
|
-
}
|
|
284
|
-
else if (firstUserMessage.messageParts) {
|
|
285
|
-
userQuestion = firstUserMessage.messageParts
|
|
286
|
-
.filter(part => part.type === 'text')
|
|
287
|
-
.map(part => part.content)
|
|
288
|
-
.join(' ');
|
|
289
|
-
}
|
|
290
|
-
if (userQuestion) {
|
|
291
|
-
try {
|
|
292
|
-
// Use Claude Code SDK to generate a concise title
|
|
293
|
-
const titlePrompt = `请为以下用户问题生成一个简洁的标题(不超过25个字符),用于会话列表显示:
|
|
294
|
-
|
|
295
|
-
用户问题:${userQuestion}
|
|
296
|
-
|
|
297
|
-
要求:
|
|
298
|
-
1. 提取问题的核心要点
|
|
299
|
-
2. 使用简洁明了的中文
|
|
300
|
-
3. 不超过25个字符
|
|
301
|
-
4. 不需要引号或其他标点符号
|
|
302
|
-
5. 直接输出标题内容,不要任何前缀或后缀`;
|
|
303
|
-
const queryOptions = {
|
|
304
|
-
customSystemPrompt: "你是一个专门生成简洁标题的助手。请直接输出标题内容,不要任何解释或格式化。",
|
|
305
|
-
allowedTools: [], // No tools needed for title generation
|
|
306
|
-
maxTurns: 1,
|
|
307
|
-
cwd: process.cwd()
|
|
308
|
-
};
|
|
309
|
-
let generatedTitle = '';
|
|
310
|
-
for await (const sdkMessage of query({
|
|
311
|
-
prompt: titlePrompt,
|
|
312
|
-
options: queryOptions
|
|
313
|
-
})) {
|
|
314
|
-
if (sdkMessage.type === 'assistant' && sdkMessage.message?.content) {
|
|
315
|
-
for (const block of sdkMessage.message.content) {
|
|
316
|
-
if (block.type === 'text') {
|
|
317
|
-
generatedTitle += block.text;
|
|
318
|
-
}
|
|
319
|
-
}
|
|
320
|
-
}
|
|
321
|
-
}
|
|
322
|
-
if (generatedTitle.trim()) {
|
|
323
|
-
// Clean the generated title
|
|
324
|
-
let cleanTitle = generatedTitle.trim()
|
|
325
|
-
.replace(/^["'"']|["'"']$/g, '') // Remove quotes
|
|
326
|
-
.replace(/\n/g, ' ') // Replace newlines
|
|
327
|
-
.replace(/\s+/g, ' '); // Collapse spaces
|
|
328
|
-
// Ensure it's not too long
|
|
329
|
-
if (cleanTitle.length > 30) {
|
|
330
|
-
cleanTitle = cleanTitle.substring(0, 27) + '...';
|
|
331
|
-
}
|
|
332
|
-
session.title = cleanTitle;
|
|
333
|
-
console.log(`Generated title for session ${session.id}: "${cleanTitle}"`);
|
|
334
|
-
}
|
|
335
|
-
else {
|
|
336
|
-
// Fallback to simple truncation if AI generation fails
|
|
337
|
-
this.fallbackTitleGeneration(session, userQuestion);
|
|
338
|
-
}
|
|
339
|
-
}
|
|
340
|
-
catch (error) {
|
|
341
|
-
console.error('Failed to update session title with Claude SDK:', error);
|
|
342
|
-
// Fallback to simple truncation
|
|
343
|
-
this.fallbackTitleGeneration(session, userQuestion);
|
|
344
|
-
}
|
|
345
|
-
}
|
|
346
|
-
}
|
|
347
|
-
// Fallback title generation when Claude SDK fails
|
|
348
|
-
fallbackTitleGeneration(session, userQuestion) {
|
|
349
|
-
let fallbackTitle = userQuestion.trim()
|
|
350
|
-
.replace(/\n/g, ' ')
|
|
351
|
-
.replace(/\s+/g, ' ')
|
|
352
|
-
.substring(0, 25);
|
|
353
|
-
// Take first sentence if it's reasonable
|
|
354
|
-
const firstSentence = fallbackTitle.split(/[.!?。!?]/)[0];
|
|
355
|
-
if (firstSentence.length > 8 && firstSentence.length < 25) {
|
|
356
|
-
fallbackTitle = firstSentence;
|
|
357
|
-
}
|
|
358
|
-
if (fallbackTitle.length > 22) {
|
|
359
|
-
fallbackTitle = fallbackTitle.substring(0, 22) + '...';
|
|
360
|
-
}
|
|
361
|
-
session.title = fallbackTitle;
|
|
362
|
-
console.log(`Fallback title for session ${session.id}: "${fallbackTitle}"`);
|
|
363
|
-
}
|
|
364
|
-
addMessageToSession(agentId, sessionId, message) {
|
|
365
|
-
const session = this.getSession(agentId, sessionId);
|
|
366
|
-
if (!session) {
|
|
367
|
-
return null;
|
|
368
|
-
}
|
|
369
|
-
const newMessage = {
|
|
370
|
-
...message,
|
|
371
|
-
id: `msg_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
|
|
372
|
-
timestamp: Date.now(),
|
|
373
|
-
messageParts: message.messageParts || [],
|
|
374
|
-
agentId
|
|
375
|
-
};
|
|
376
|
-
session.messages.push(newMessage);
|
|
377
|
-
session.lastUpdated = Date.now();
|
|
378
|
-
// Save session first, then update title asynchronously
|
|
379
|
-
this.saveSession(session);
|
|
380
|
-
// Update session title based on first user message (async, doesn't block)
|
|
381
|
-
if (message.role === 'user' && this.shouldUpdateTitle(session.title)) {
|
|
382
|
-
this.updateSessionTitle(session).then(() => {
|
|
383
|
-
// Save again after title is updated
|
|
384
|
-
this.saveSession(session);
|
|
385
|
-
console.log(`Session title updated to: "${session.title}"`);
|
|
386
|
-
}).catch(err => {
|
|
387
|
-
console.error('Failed to update session title:', err);
|
|
388
|
-
});
|
|
389
|
-
}
|
|
390
|
-
return newMessage;
|
|
391
|
-
}
|
|
392
|
-
}
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import { ClaudeVersion, ClaudeVersionCreate, ClaudeVersionUpdate } from '../types/claude-versions.js';
|
|
2
|
-
interface VersionStorage {
|
|
3
|
-
versions: ClaudeVersion[];
|
|
4
|
-
defaultVersionId: string | null;
|
|
5
|
-
}
|
|
6
|
-
export declare function loadClaudeVersions(): Promise<VersionStorage>;
|
|
7
|
-
export declare function saveClaudeVersions(storage: VersionStorage): Promise<void>;
|
|
8
|
-
export declare function getAllVersions(): Promise<ClaudeVersion[]>;
|
|
9
|
-
export declare function getDefaultVersionId(): Promise<string | null>;
|
|
10
|
-
export declare function setDefaultVersion(versionId: string): Promise<void>;
|
|
11
|
-
export declare function createVersion(data: ClaudeVersionCreate): Promise<ClaudeVersion>;
|
|
12
|
-
export declare function updateVersion(versionId: string, data: ClaudeVersionUpdate): Promise<ClaudeVersion>;
|
|
13
|
-
export declare function deleteVersion(versionId: string): Promise<void>;
|
|
14
|
-
export declare function initializeSystemVersion(executablePath: string): Promise<ClaudeVersion>;
|
|
15
|
-
export {};
|
|
16
|
-
//# sourceMappingURL=claudeVersionStorage.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"claudeVersionStorage.d.ts","sourceRoot":"","sources":["../../src/utils/claudeVersionStorage.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,aAAa,EAAE,mBAAmB,EAAE,mBAAmB,EAAe,MAAM,6BAA6B,CAAC;AAqBnH,UAAU,cAAc;IACtB,QAAQ,EAAE,aAAa,EAAE,CAAC;IAC1B,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;CACjC;AAuCD,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,cAAc,CAAC,CAwBlE;AAGD,wBAAsB,kBAAkB,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAK/E;AAQD,wBAAsB,cAAc,IAAI,OAAO,CAAC,aAAa,EAAE,CAAC,CAG/D;AAGD,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAGlE;AAGD,wBAAsB,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAWxE;AAGD,wBAAsB,aAAa,CAAC,IAAI,EAAE,mBAAmB,GAAG,OAAO,CAAC,aAAa,CAAC,CAiCrF;AAGD,wBAAsB,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,mBAAmB,GAAG,OAAO,CAAC,aAAa,CAAC,CA6CxG;AAGD,wBAAsB,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAuBpE;AAGD,wBAAsB,uBAAuB,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CAyC5F"}
|
|
@@ -1,230 +0,0 @@
|
|
|
1
|
-
import { readFile, writeFile, mkdir } from 'fs/promises';
|
|
2
|
-
import { join } from 'path';
|
|
3
|
-
import { homedir } from 'os';
|
|
4
|
-
// 默认模型配置(用于Claude系统版本)
|
|
5
|
-
const DEFAULT_MODELS = [
|
|
6
|
-
{
|
|
7
|
-
id: 'sonnet',
|
|
8
|
-
name: 'Sonnet',
|
|
9
|
-
isVision: true,
|
|
10
|
-
description: 'Claude 3.5 Sonnet - 平衡性能和成本的模型'
|
|
11
|
-
},
|
|
12
|
-
{
|
|
13
|
-
id: 'opus',
|
|
14
|
-
name: 'Opus',
|
|
15
|
-
isVision: true,
|
|
16
|
-
description: 'Claude 3 Opus - 最强大的模型'
|
|
17
|
-
}
|
|
18
|
-
];
|
|
19
|
-
const CLAUDE_AGENT_DIR = join(homedir(), '.claude-agent');
|
|
20
|
-
const VERSIONS_FILE = join(CLAUDE_AGENT_DIR, 'claude-versions.json');
|
|
21
|
-
// 确保目录存在
|
|
22
|
-
async function ensureClaudeAgentDir() {
|
|
23
|
-
try {
|
|
24
|
-
await mkdir(CLAUDE_AGENT_DIR, { recursive: true });
|
|
25
|
-
}
|
|
26
|
-
catch (error) {
|
|
27
|
-
// 忽略目录已存在的错误
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
// 数据迁移:为旧版本添加models字段
|
|
31
|
-
function migrateVersionData(storage) {
|
|
32
|
-
let needsSave = false;
|
|
33
|
-
const migratedVersions = storage.versions.map(version => {
|
|
34
|
-
// 如果版本没有models字段,添加默认模型
|
|
35
|
-
if (!version.models || version.models.length === 0) {
|
|
36
|
-
needsSave = true;
|
|
37
|
-
return {
|
|
38
|
-
...version,
|
|
39
|
-
models: DEFAULT_MODELS
|
|
40
|
-
};
|
|
41
|
-
}
|
|
42
|
-
return version;
|
|
43
|
-
});
|
|
44
|
-
const result = {
|
|
45
|
-
...storage,
|
|
46
|
-
versions: migratedVersions
|
|
47
|
-
};
|
|
48
|
-
// 标记是否需要保存
|
|
49
|
-
result._needsSave = needsSave;
|
|
50
|
-
return result;
|
|
51
|
-
}
|
|
52
|
-
// 读取版本配置
|
|
53
|
-
export async function loadClaudeVersions() {
|
|
54
|
-
await ensureClaudeAgentDir();
|
|
55
|
-
try {
|
|
56
|
-
const content = await readFile(VERSIONS_FILE, 'utf-8');
|
|
57
|
-
const storage = JSON.parse(content);
|
|
58
|
-
// 执行数据迁移
|
|
59
|
-
const migrated = migrateVersionData(storage);
|
|
60
|
-
// 如果数据有变化,保存回文件
|
|
61
|
-
if (migrated._needsSave) {
|
|
62
|
-
delete migrated._needsSave;
|
|
63
|
-
await saveClaudeVersions(migrated);
|
|
64
|
-
}
|
|
65
|
-
return migrated;
|
|
66
|
-
}
|
|
67
|
-
catch (error) {
|
|
68
|
-
// 文件不存在或解析失败,返回默认配置
|
|
69
|
-
return {
|
|
70
|
-
versions: [],
|
|
71
|
-
defaultVersionId: null
|
|
72
|
-
};
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
// 保存版本配置
|
|
76
|
-
export async function saveClaudeVersions(storage) {
|
|
77
|
-
await ensureClaudeAgentDir();
|
|
78
|
-
const content = JSON.stringify(storage, null, 2);
|
|
79
|
-
await writeFile(VERSIONS_FILE, content, 'utf-8');
|
|
80
|
-
}
|
|
81
|
-
// 生成唯一ID
|
|
82
|
-
function generateId() {
|
|
83
|
-
return Date.now().toString(36) + Math.random().toString(36).substr(2);
|
|
84
|
-
}
|
|
85
|
-
// 获取所有版本
|
|
86
|
-
export async function getAllVersions() {
|
|
87
|
-
const storage = await loadClaudeVersions();
|
|
88
|
-
return storage.versions;
|
|
89
|
-
}
|
|
90
|
-
// 获取默认版本ID
|
|
91
|
-
export async function getDefaultVersionId() {
|
|
92
|
-
const storage = await loadClaudeVersions();
|
|
93
|
-
return storage.defaultVersionId;
|
|
94
|
-
}
|
|
95
|
-
// 设置默认版本
|
|
96
|
-
export async function setDefaultVersion(versionId) {
|
|
97
|
-
const storage = await loadClaudeVersions();
|
|
98
|
-
// 检查版本是否存在
|
|
99
|
-
const version = storage.versions.find(v => v.id === versionId);
|
|
100
|
-
if (!version) {
|
|
101
|
-
throw new Error('版本不存在');
|
|
102
|
-
}
|
|
103
|
-
storage.defaultVersionId = versionId;
|
|
104
|
-
await saveClaudeVersions(storage);
|
|
105
|
-
}
|
|
106
|
-
// 创建新版本
|
|
107
|
-
export async function createVersion(data) {
|
|
108
|
-
const storage = await loadClaudeVersions();
|
|
109
|
-
// 检查别名是否已存在
|
|
110
|
-
const existingAlias = storage.versions.find(v => v.alias === data.alias);
|
|
111
|
-
if (existingAlias) {
|
|
112
|
-
throw new Error('别名已存在');
|
|
113
|
-
}
|
|
114
|
-
const now = new Date().toISOString();
|
|
115
|
-
const newVersion = {
|
|
116
|
-
id: generateId(),
|
|
117
|
-
name: data.name,
|
|
118
|
-
alias: data.alias,
|
|
119
|
-
description: data.description,
|
|
120
|
-
executablePath: data.executablePath,
|
|
121
|
-
isDefault: storage.versions.length === 0, // 第一个版本默认为默认版本
|
|
122
|
-
isSystem: false,
|
|
123
|
-
environmentVariables: data.environmentVariables || {},
|
|
124
|
-
models: data.models || DEFAULT_MODELS, // 使用提供的模型或默认模型
|
|
125
|
-
createdAt: now,
|
|
126
|
-
updatedAt: now
|
|
127
|
-
};
|
|
128
|
-
storage.versions.push(newVersion);
|
|
129
|
-
// 如果这是第一个版本,设置为默认版本
|
|
130
|
-
if (storage.versions.length === 1) {
|
|
131
|
-
storage.defaultVersionId = newVersion.id;
|
|
132
|
-
}
|
|
133
|
-
await saveClaudeVersions(storage);
|
|
134
|
-
return newVersion;
|
|
135
|
-
}
|
|
136
|
-
// 更新版本
|
|
137
|
-
export async function updateVersion(versionId, data) {
|
|
138
|
-
const storage = await loadClaudeVersions();
|
|
139
|
-
const versionIndex = storage.versions.findIndex(v => v.id === versionId);
|
|
140
|
-
if (versionIndex === -1) {
|
|
141
|
-
throw new Error('版本不存在');
|
|
142
|
-
}
|
|
143
|
-
const version = storage.versions[versionIndex];
|
|
144
|
-
// 检查别名冲突(如果修改了别名)
|
|
145
|
-
if (data.alias && data.alias !== version.alias) {
|
|
146
|
-
const existingAlias = storage.versions.find(v => v.alias === data.alias && v.id !== versionId);
|
|
147
|
-
if (existingAlias) {
|
|
148
|
-
throw new Error('别名已存在');
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
// 不允许修改系统版本的某些属性
|
|
152
|
-
if (version.isSystem) {
|
|
153
|
-
if (data.executablePath && data.executablePath !== version.executablePath) {
|
|
154
|
-
throw new Error('不允许修改系统版本的可执行路径');
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
// 合并更新数据,允许 undefined 值以便删除字段
|
|
158
|
-
const updatedVersion = {
|
|
159
|
-
...version,
|
|
160
|
-
...data,
|
|
161
|
-
updatedAt: new Date().toISOString()
|
|
162
|
-
};
|
|
163
|
-
// 对于明确设置为 undefined 的可选字段,从对象中删除
|
|
164
|
-
// 这样 JSON.stringify 就不会保存这些字段
|
|
165
|
-
if (data.executablePath === undefined) {
|
|
166
|
-
delete updatedVersion.executablePath;
|
|
167
|
-
}
|
|
168
|
-
if (data.description === undefined) {
|
|
169
|
-
delete updatedVersion.description;
|
|
170
|
-
}
|
|
171
|
-
storage.versions[versionIndex] = updatedVersion;
|
|
172
|
-
await saveClaudeVersions(storage);
|
|
173
|
-
return updatedVersion;
|
|
174
|
-
}
|
|
175
|
-
// 删除版本
|
|
176
|
-
export async function deleteVersion(versionId) {
|
|
177
|
-
const storage = await loadClaudeVersions();
|
|
178
|
-
const versionIndex = storage.versions.findIndex(v => v.id === versionId);
|
|
179
|
-
if (versionIndex === -1) {
|
|
180
|
-
throw new Error('版本不存在');
|
|
181
|
-
}
|
|
182
|
-
const version = storage.versions[versionIndex];
|
|
183
|
-
// 不允许删除系统版本
|
|
184
|
-
if (version.isSystem) {
|
|
185
|
-
throw new Error('不允许删除系统版本');
|
|
186
|
-
}
|
|
187
|
-
storage.versions.splice(versionIndex, 1);
|
|
188
|
-
// 如果删除的是默认版本,选择一个新的默认版本
|
|
189
|
-
if (storage.defaultVersionId === versionId) {
|
|
190
|
-
storage.defaultVersionId = storage.versions.length > 0 ? storage.versions[0].id : null;
|
|
191
|
-
}
|
|
192
|
-
await saveClaudeVersions(storage);
|
|
193
|
-
}
|
|
194
|
-
// 初始化系统版本(在启动时调用)
|
|
195
|
-
export async function initializeSystemVersion(executablePath) {
|
|
196
|
-
const storage = await loadClaudeVersions();
|
|
197
|
-
// 检查是否已存在系统版本
|
|
198
|
-
let systemVersion = storage.versions.find(v => v.isSystem);
|
|
199
|
-
if (systemVersion) {
|
|
200
|
-
// 更新系统版本的路径(如果有变化)
|
|
201
|
-
if (systemVersion.executablePath !== executablePath) {
|
|
202
|
-
systemVersion.executablePath = executablePath;
|
|
203
|
-
systemVersion.updatedAt = new Date().toISOString();
|
|
204
|
-
await saveClaudeVersions(storage);
|
|
205
|
-
}
|
|
206
|
-
return systemVersion;
|
|
207
|
-
}
|
|
208
|
-
// 创建系统版本
|
|
209
|
-
const now = new Date().toISOString();
|
|
210
|
-
systemVersion = {
|
|
211
|
-
id: 'system',
|
|
212
|
-
name: 'System Claude',
|
|
213
|
-
alias: 'system',
|
|
214
|
-
description: '系统默认的 Claude Code 版本(通过 which claude 查找)',
|
|
215
|
-
executablePath,
|
|
216
|
-
isDefault: storage.versions.length === 0,
|
|
217
|
-
isSystem: true,
|
|
218
|
-
environmentVariables: {},
|
|
219
|
-
models: DEFAULT_MODELS, // 系统版本使用默认模型
|
|
220
|
-
createdAt: now,
|
|
221
|
-
updatedAt: now
|
|
222
|
-
};
|
|
223
|
-
storage.versions.unshift(systemVersion); // 系统版本放在最前面
|
|
224
|
-
// 如果这是第一个版本,设置为默认版本
|
|
225
|
-
if (storage.versions.length === 1) {
|
|
226
|
-
storage.defaultVersionId = systemVersion.id;
|
|
227
|
-
}
|
|
228
|
-
await saveClaudeVersions(storage);
|
|
229
|
-
return systemVersion;
|
|
230
|
-
}
|