mr-sliy 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +145 -0
- package/database/schema.sql +187 -0
- package/package.json +74 -0
- package/scripts/download-tree-sitter.js +171 -0
- package/scripts/postinstall.js +134 -0
- package/src/agent/agent.js +563 -0
- package/src/agent.js +87 -0
- package/src/cli/index.js +1643 -0
- package/src/config/index.js +232 -0
- package/src/engine/dualModeEngine.js +486 -0
- package/src/index.js +165 -0
- package/src/middlewares/errorHandler.js +166 -0
- package/src/middlewares/index.js +23 -0
- package/src/routes/aiRoutes.js +117 -0
- package/src/routes/configRoutes.js +31 -0
- package/src/routes/index.js +75 -0
- package/src/routes/issueRoutes.js +195 -0
- package/src/routes/projectRoutes.js +46 -0
- package/src/routes/reportRoutes.js +40 -0
- package/src/routes/scanRoutes.js +245 -0
- package/src/routes/userRoutes.js +47 -0
- package/src/services/ast/parser.js +503 -0
- package/src/services/detection/detector.js +934 -0
- package/src/services/llm/providers.js +1107 -0
- package/src/services/rag/agent.js +375 -0
- package/src/services/vector/knowledgeBase.js +863 -0
- package/src/skills/Skill.js +38 -0
- package/src/skills/code-analysis/index.js +272 -0
- package/src/skills/code-detection/index.js +166 -0
- package/src/skills/code-detection/rules/console-log.js +45 -0
- package/src/skills/code-detection/rules/deep-nesting.js +76 -0
- package/src/skills/code-detection/rules/duplicate-code.js +57 -0
- package/src/skills/code-detection/rules/high-complexity.js +109 -0
- package/src/skills/code-detection/rules/index.js +59 -0
- package/src/skills/code-detection/rules/long-functions.js +54 -0
- package/src/skills/code-detection/rules/magic-numbers.js +48 -0
- package/src/skills/code-detection/rules/missing-comment.js +64 -0
- package/src/skills/code-detection/rules/null-check.js +71 -0
- package/src/skills/code-detection/rules/unnecessary-else.js +46 -0
- package/src/skills/code-detection/rules/unused-functions.js +57 -0
- package/src/skills/code-detection/rules/unused-imports.js +57 -0
- package/src/skills/code-detection/rules/unused-variables.js +54 -0
- package/src/skills/code-optimization/index.js +319 -0
- package/src/skills/index.js +152 -0
- package/src/utils/crypto.js +212 -0
- package/src/utils/database.js +125 -0
- package/src/utils/helpers.js +226 -0
- package/src/utils/logger.js +202 -0
- package/src/utils/mysql.js +198 -0
- package/src/utils/response.js +124 -0
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 安装后脚本
|
|
3
|
+
* 用于自动初始化数据库和下载 Tree-sitter WASM 文件
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const fs = require('fs');
|
|
7
|
+
const path = require('path');
|
|
8
|
+
const { exec } = require('child_process');
|
|
9
|
+
|
|
10
|
+
// 颜色输出
|
|
11
|
+
const colors = {
|
|
12
|
+
reset: '\x1b[0m',
|
|
13
|
+
bright: '\x1b[1m',
|
|
14
|
+
green: '\x1b[32m',
|
|
15
|
+
yellow: '\x1b[33m',
|
|
16
|
+
blue: '\x1b[34m',
|
|
17
|
+
red: '\x1b[31m'
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
function log(message, color = 'reset') {
|
|
21
|
+
console.log(`${colors[color]}${message}${colors.reset}`);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function checkAndCreateEnvFile() {
|
|
25
|
+
const envPath = path.join(__dirname, '../.env');
|
|
26
|
+
const envExamplePath = path.join(__dirname, '../.env.example');
|
|
27
|
+
|
|
28
|
+
if (!fs.existsSync(envPath)) {
|
|
29
|
+
if (fs.existsSync(envExamplePath)) {
|
|
30
|
+
log('📝 检测到 .env.example,正在创建 .env...', 'yellow');
|
|
31
|
+
fs.copyFileSync(envExamplePath, envPath);
|
|
32
|
+
log('✅ .env 文件已创建', 'green');
|
|
33
|
+
log('⚠️ 请编辑 .env 文件,配置您的 API Key', 'yellow');
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function initializeDatabase() {
|
|
39
|
+
return new Promise((resolve, reject) => {
|
|
40
|
+
const dbPath = path.join(__dirname, '../database/code_optimizer.db');
|
|
41
|
+
|
|
42
|
+
if (fs.existsSync(dbPath)) {
|
|
43
|
+
log('📦 数据库已存在,跳过初始化', 'blue');
|
|
44
|
+
resolve();
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
log('🗄️ 正在初始化数据库...', 'yellow');
|
|
49
|
+
|
|
50
|
+
try {
|
|
51
|
+
// 动态导入 init 函数
|
|
52
|
+
const { initDatabase } = require('../database/init.js');
|
|
53
|
+
initDatabase();
|
|
54
|
+
log('✅ 数据库初始化完成', 'green');
|
|
55
|
+
resolve();
|
|
56
|
+
} catch (error) {
|
|
57
|
+
log(`⚠️ 数据库初始化失败: ${error.message}`, 'yellow');
|
|
58
|
+
log(' 请手动运行: npm run init', 'yellow');
|
|
59
|
+
resolve(); // 不阻塞安装
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function downloadWasmFiles() {
|
|
65
|
+
return new Promise((resolve) => {
|
|
66
|
+
const wasmDir = path.join(__dirname, '../wasm');
|
|
67
|
+
let wasmFilesExist = false;
|
|
68
|
+
|
|
69
|
+
try {
|
|
70
|
+
const files = fs.readdirSync(wasmDir);
|
|
71
|
+
const wasmFiles = files.filter(f => f.endsWith('.wasm'));
|
|
72
|
+
wasmFilesExist = wasmFiles.some(f => {
|
|
73
|
+
const stat = fs.statSync(path.join(wasmDir, f));
|
|
74
|
+
return stat.size > 0;
|
|
75
|
+
});
|
|
76
|
+
} catch (error) {
|
|
77
|
+
wasmFilesExist = false;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (wasmFilesExist) {
|
|
81
|
+
log('📦 Tree-sitter WASM 文件已存在,跳过下载', 'blue');
|
|
82
|
+
resolve();
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
log('🌐 正在下载 Tree-sitter WASM 文件...', 'yellow');
|
|
87
|
+
|
|
88
|
+
try {
|
|
89
|
+
const { downloadAllWasm } = require('./download-tree-sitter.js');
|
|
90
|
+
downloadAllWasm()
|
|
91
|
+
.then(() => {
|
|
92
|
+
log('✅ Tree-sitter WASM 文件下载完成', 'green');
|
|
93
|
+
resolve();
|
|
94
|
+
})
|
|
95
|
+
.catch((error) => {
|
|
96
|
+
log(`⚠️ WASM 文件下载失败: ${error.message}`, 'yellow');
|
|
97
|
+
log(' 请稍后手动运行: npm run download-wasm', 'yellow');
|
|
98
|
+
resolve(); // 不阻塞安装
|
|
99
|
+
});
|
|
100
|
+
} catch (error) {
|
|
101
|
+
log(`⚠️ WASM 下载脚本加载失败: ${error.message}`, 'yellow');
|
|
102
|
+
resolve();
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
async function main() {
|
|
108
|
+
log('\n🔧 Mr.Sliy 安装后配置...\n', 'bright');
|
|
109
|
+
|
|
110
|
+
try {
|
|
111
|
+
// 1. 检查并创建 .env 文件
|
|
112
|
+
checkAndCreateEnvFile();
|
|
113
|
+
|
|
114
|
+
// 2. 初始化数据库
|
|
115
|
+
await initializeDatabase();
|
|
116
|
+
|
|
117
|
+
// 3. 下载 WASM 文件
|
|
118
|
+
await downloadWasmFiles();
|
|
119
|
+
|
|
120
|
+
log('\n🎉 安装完成!', 'green');
|
|
121
|
+
log('\n下一步:');
|
|
122
|
+
log('1. 编辑 .env 文件配置您的 API Key', 'blue');
|
|
123
|
+
log('2. 运行 npm run start 启动智能体', 'blue');
|
|
124
|
+
log('\n或使用以下命令快速开始:', 'blue');
|
|
125
|
+
log(' npm run setup # 初始化数据库', 'yellow');
|
|
126
|
+
log(' npm start # 启动智能体', 'yellow');
|
|
127
|
+
log('\n');
|
|
128
|
+
} catch (error) {
|
|
129
|
+
log(`\n❌ 安装后配置失败: ${error.message}`, 'red');
|
|
130
|
+
process.exit(1);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
main();
|
|
@@ -0,0 +1,563 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Code Optimizer Agent 核心
|
|
3
|
+
* 智能体主逻辑:状态管理、任务调度、结果处理
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const { engine } = require('../engine/dualModeEngine');
|
|
7
|
+
const { providerManager } = require('../services/llm/providers');
|
|
8
|
+
const { knowledgeBase } = require('../services/vector/knowledgeBase');
|
|
9
|
+
const { logger } = require('../utils/logger');
|
|
10
|
+
const { getDatabase } = require('../utils/database');
|
|
11
|
+
const { generateUUID } = require('../utils/helpers');
|
|
12
|
+
const { skillManager } = require('../skills');
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Agent状态
|
|
16
|
+
*/
|
|
17
|
+
const AgentState = {
|
|
18
|
+
IDLE: 'idle',
|
|
19
|
+
ANALYZING: 'analyzing',
|
|
20
|
+
OPTIMIZING: 'optimizing',
|
|
21
|
+
LEARNING: 'learning',
|
|
22
|
+
ERROR: 'error'
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* 代码优化智能体
|
|
27
|
+
*/
|
|
28
|
+
class CodeOptimizerAgent {
|
|
29
|
+
constructor() {
|
|
30
|
+
this.state = AgentState.IDLE;
|
|
31
|
+
this.currentTask = null;
|
|
32
|
+
this.taskHistory = [];
|
|
33
|
+
this.chatHistory = [];
|
|
34
|
+
this.config = {
|
|
35
|
+
mode: 'auto',
|
|
36
|
+
autoSave: true,
|
|
37
|
+
maxIssuesPerFile: 100
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* 初始化Agent
|
|
43
|
+
*/
|
|
44
|
+
async init() {
|
|
45
|
+
engine.init();
|
|
46
|
+
await skillManager.init();
|
|
47
|
+
logger.info('Code Optimizer Agent 初始化完成');
|
|
48
|
+
return this.getStatus();
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* 配置Agent
|
|
53
|
+
*/
|
|
54
|
+
configure(options) {
|
|
55
|
+
Object.assign(this.config, options);
|
|
56
|
+
|
|
57
|
+
if (options.mode) {
|
|
58
|
+
engine.setMode(options.mode);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// 配置LLM提供商
|
|
62
|
+
if (options.providers) {
|
|
63
|
+
Object.entries(options.providers).forEach(([name, config]) => {
|
|
64
|
+
providerManager.register(name, config);
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// 设置活跃提供商
|
|
69
|
+
if (options.activeProvider) {
|
|
70
|
+
providerManager.setActiveProvider(options.activeProvider);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
logger.info('Agent配置已更新');
|
|
74
|
+
return this.getStatus();
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* 分析单个文件
|
|
79
|
+
*/
|
|
80
|
+
async analyzeFile(filePath) {
|
|
81
|
+
this.setState(AgentState.ANALYZING);
|
|
82
|
+
this.currentTask = { type: 'analyze_file', filePath, id: generateUUID() };
|
|
83
|
+
|
|
84
|
+
try {
|
|
85
|
+
const result = await engine.analyzeFile(filePath);
|
|
86
|
+
|
|
87
|
+
if (result.success && this.config.autoSave) {
|
|
88
|
+
this.saveTaskResult(this.currentTask, result);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
this.addToHistory(this.currentTask, result);
|
|
92
|
+
this.setState(AgentState.IDLE);
|
|
93
|
+
|
|
94
|
+
return result;
|
|
95
|
+
} catch (error) {
|
|
96
|
+
this.setState(AgentState.ERROR);
|
|
97
|
+
logger.error('分析文件失败:', error);
|
|
98
|
+
throw error;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* 分析代码片段
|
|
104
|
+
*/
|
|
105
|
+
async analyzeSnippet(code, language = 'javascript') {
|
|
106
|
+
this.setState(AgentState.ANALYZING);
|
|
107
|
+
this.currentTask = { type: 'analyze_snippet', language, id: generateUUID() };
|
|
108
|
+
|
|
109
|
+
try {
|
|
110
|
+
const result = await engine.analyzeSnippet(code, language, { generalOptimize: true });
|
|
111
|
+
|
|
112
|
+
this.addToHistory(this.currentTask, result);
|
|
113
|
+
this.setState(AgentState.IDLE);
|
|
114
|
+
|
|
115
|
+
return result;
|
|
116
|
+
} catch (error) {
|
|
117
|
+
this.setState(AgentState.ERROR);
|
|
118
|
+
logger.error('分析代码片段失败:', error);
|
|
119
|
+
throw error;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* 分析整个项目
|
|
125
|
+
*/
|
|
126
|
+
async analyzeProject(projectPath, options = {}) {
|
|
127
|
+
this.setState(AgentState.ANALYZING);
|
|
128
|
+
this.currentTask = { type: 'analyze_project', projectPath, id: generateUUID() };
|
|
129
|
+
|
|
130
|
+
try {
|
|
131
|
+
const result = await engine.analyzeProject(projectPath, options);
|
|
132
|
+
|
|
133
|
+
if (result.success && this.config.autoSave) {
|
|
134
|
+
this.saveTaskResult(this.currentTask, result);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
this.addToHistory(this.currentTask, result);
|
|
138
|
+
this.setState(AgentState.IDLE);
|
|
139
|
+
|
|
140
|
+
return result;
|
|
141
|
+
} catch (error) {
|
|
142
|
+
this.setState(AgentState.ERROR);
|
|
143
|
+
logger.error('分析项目失败:', error);
|
|
144
|
+
throw error;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* 优化单个代码片段(直接优化)
|
|
150
|
+
*/
|
|
151
|
+
async optimize(code, language = 'javascript', context = {}) {
|
|
152
|
+
this.setState(AgentState.OPTIMIZING);
|
|
153
|
+
this.currentTask = { type: 'optimize', language, id: generateUUID() };
|
|
154
|
+
|
|
155
|
+
try {
|
|
156
|
+
const issue = {
|
|
157
|
+
codeSnippet: code,
|
|
158
|
+
language,
|
|
159
|
+
issueType: context.issueType || 'general',
|
|
160
|
+
message: context.message || '代码优化'
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
const mode = engine.getActualMode();
|
|
164
|
+
const result = await engine.optimizeIssue(issue, code, mode);
|
|
165
|
+
|
|
166
|
+
this.addToHistory(this.currentTask, result);
|
|
167
|
+
this.setState(AgentState.IDLE);
|
|
168
|
+
|
|
169
|
+
return result;
|
|
170
|
+
} catch (error) {
|
|
171
|
+
this.setState(AgentState.ERROR);
|
|
172
|
+
logger.error('优化失败:', error);
|
|
173
|
+
throw error;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* 添加知识到本地知识库
|
|
179
|
+
*/
|
|
180
|
+
async learn(content, options = {}) {
|
|
181
|
+
this.setState(AgentState.LEARNING);
|
|
182
|
+
|
|
183
|
+
try {
|
|
184
|
+
let id;
|
|
185
|
+
if (options.type === 'case' && options.originalCode && options.optimizedCode) {
|
|
186
|
+
id = knowledgeBase.addCase(
|
|
187
|
+
options.originalCode,
|
|
188
|
+
options.optimizedCode,
|
|
189
|
+
content,
|
|
190
|
+
{
|
|
191
|
+
language: options.language,
|
|
192
|
+
issueType: options.issueType
|
|
193
|
+
}
|
|
194
|
+
);
|
|
195
|
+
} else {
|
|
196
|
+
id = knowledgeBase.addEntry(content, {
|
|
197
|
+
type: options.type || 'general',
|
|
198
|
+
language: options.language,
|
|
199
|
+
tags: options.tags,
|
|
200
|
+
source: options.source
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
this.setState(AgentState.IDLE);
|
|
205
|
+
return { success: true, id, message: '知识已添加到本地知识库' };
|
|
206
|
+
} catch (error) {
|
|
207
|
+
this.setState(AgentState.ERROR);
|
|
208
|
+
logger.error('学习失败:', error);
|
|
209
|
+
throw error;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* 查询知识库
|
|
215
|
+
*/
|
|
216
|
+
queryKnowledge(query, options = {}) {
|
|
217
|
+
const cases = knowledgeBase.searchCases(query, {
|
|
218
|
+
language: options.language,
|
|
219
|
+
issueType: options.issueType,
|
|
220
|
+
topK: options.topK || 5
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
const entries = knowledgeBase.searchEntries(query, {
|
|
224
|
+
language: options.language,
|
|
225
|
+
topK: options.topK || 5
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
return {
|
|
229
|
+
cases,
|
|
230
|
+
entries,
|
|
231
|
+
total: cases.length + entries.length
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* 切换LLM提供商
|
|
237
|
+
*/
|
|
238
|
+
switchProvider(providerName) {
|
|
239
|
+
try {
|
|
240
|
+
providerManager.setActiveProvider(providerName);
|
|
241
|
+
return {
|
|
242
|
+
success: true,
|
|
243
|
+
provider: providerName,
|
|
244
|
+
message: `已切换至 ${providerName} 提供商`
|
|
245
|
+
};
|
|
246
|
+
} catch (error) {
|
|
247
|
+
return {
|
|
248
|
+
success: false,
|
|
249
|
+
message: error.message
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* 搜索知识库
|
|
256
|
+
*/
|
|
257
|
+
async searchKnowledge(query, options = {}) {
|
|
258
|
+
const entries = knowledgeBase.searchEntries(query, options);
|
|
259
|
+
const cases = knowledgeBase.searchCases(query, options);
|
|
260
|
+
return [...entries, ...cases].slice(0, options.limit || 10);
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* 获取知识库统计
|
|
265
|
+
*/
|
|
266
|
+
getKnowledgeStats() {
|
|
267
|
+
return knowledgeBase.getStats();
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* 导出知识库
|
|
272
|
+
*/
|
|
273
|
+
exportKnowledge(filePath) {
|
|
274
|
+
const path = require('path');
|
|
275
|
+
const exportPath = filePath || path.join(__dirname, '../../data/knowledge-export.json');
|
|
276
|
+
return knowledgeBase.exportToFile(exportPath);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
* 导入知识库
|
|
281
|
+
*/
|
|
282
|
+
importKnowledge(filePath, options = {}) {
|
|
283
|
+
return knowledgeBase.importFromFile(filePath, options);
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* 同步知识库到云端
|
|
288
|
+
*/
|
|
289
|
+
async syncKnowledgeToCloud() {
|
|
290
|
+
return await knowledgeBase.syncToCloud();
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
/**
|
|
294
|
+
* 从云端同步知识库
|
|
295
|
+
*/
|
|
296
|
+
async syncKnowledgeFromCloud() {
|
|
297
|
+
return await knowledgeBase.syncFromCloud();
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
/**
|
|
301
|
+
* 测试云端连接
|
|
302
|
+
*/
|
|
303
|
+
async testCloudConnection() {
|
|
304
|
+
return await knowledgeBase.testCloudConnection();
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
/**
|
|
308
|
+
* 获取可用提供商列表
|
|
309
|
+
*/
|
|
310
|
+
getProviders() {
|
|
311
|
+
return providerManager.getAvailableProviders();
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
/**
|
|
315
|
+
* 注册新的LLM提供商
|
|
316
|
+
*/
|
|
317
|
+
registerProvider(name, config) {
|
|
318
|
+
try {
|
|
319
|
+
providerManager.register(name, config);
|
|
320
|
+
return {
|
|
321
|
+
success: true,
|
|
322
|
+
provider: name,
|
|
323
|
+
message: `已注册 ${name} 提供商`
|
|
324
|
+
};
|
|
325
|
+
} catch (error) {
|
|
326
|
+
return {
|
|
327
|
+
success: false,
|
|
328
|
+
message: error.message
|
|
329
|
+
};
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
/**
|
|
334
|
+
* 更新提供商配置(如API Key)
|
|
335
|
+
*/
|
|
336
|
+
updateProviderConfig(name, config) {
|
|
337
|
+
providerManager.updateProviderConfig(name, config);
|
|
338
|
+
return {
|
|
339
|
+
success: true,
|
|
340
|
+
message: `已更新 ${name} 配置`
|
|
341
|
+
};
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
/**
|
|
345
|
+
* 设置工作模式
|
|
346
|
+
*/
|
|
347
|
+
setMode(mode) {
|
|
348
|
+
engine.setMode(mode);
|
|
349
|
+
this.config.mode = mode;
|
|
350
|
+
return {
|
|
351
|
+
success: true,
|
|
352
|
+
mode,
|
|
353
|
+
actualMode: engine.getActualMode()
|
|
354
|
+
};
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
/**
|
|
358
|
+
* 获取所有可用技能
|
|
359
|
+
*/
|
|
360
|
+
getSkills() {
|
|
361
|
+
return skillManager.getAllSkills();
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
/**
|
|
365
|
+
* 获取已启用的技能
|
|
366
|
+
*/
|
|
367
|
+
getEnabledSkills() {
|
|
368
|
+
return skillManager.getEnabledSkills();
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
/**
|
|
372
|
+
* 执行技能
|
|
373
|
+
*/
|
|
374
|
+
async executeSkill(skillName, context = {}) {
|
|
375
|
+
return await skillManager.executeSkill(skillName, context);
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
/**
|
|
379
|
+
* 启用技能
|
|
380
|
+
*/
|
|
381
|
+
enableSkill(skillName) {
|
|
382
|
+
return skillManager.enableSkill(skillName);
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
/**
|
|
386
|
+
* 禁用技能
|
|
387
|
+
*/
|
|
388
|
+
disableSkill(skillName) {
|
|
389
|
+
return skillManager.disableSkill(skillName);
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
/**
|
|
393
|
+
* 获取Agent状态
|
|
394
|
+
*/
|
|
395
|
+
getStatus() {
|
|
396
|
+
return {
|
|
397
|
+
state: this.state,
|
|
398
|
+
currentTask: this.currentTask,
|
|
399
|
+
config: this.config,
|
|
400
|
+
engine: engine.getStatus(),
|
|
401
|
+
historyCount: this.taskHistory.length
|
|
402
|
+
};
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
/**
|
|
406
|
+
* 获取任务历史
|
|
407
|
+
*/
|
|
408
|
+
getHistory(limit = 10) {
|
|
409
|
+
return this.taskHistory.slice(-limit);
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
/**
|
|
413
|
+
* 与AI聊天
|
|
414
|
+
*/
|
|
415
|
+
async chat(message, options = {}) {
|
|
416
|
+
const provider = providerManager.getActiveProvider();
|
|
417
|
+
if (!provider) {
|
|
418
|
+
throw new Error('未配置活跃的LLM提供商,请先在提供商管理中配置');
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
this.chatHistory.push({ role: 'user', content: message });
|
|
422
|
+
|
|
423
|
+
const messages = [
|
|
424
|
+
{
|
|
425
|
+
role: 'system',
|
|
426
|
+
content: `你是一个专业的代码优化助手,精通多种编程语言和代码优化技术。
|
|
427
|
+
你可以:
|
|
428
|
+
1. 回答代码相关的问题
|
|
429
|
+
2. 提供代码优化建议
|
|
430
|
+
3. 根据用户需求调用智能体的功能
|
|
431
|
+
|
|
432
|
+
可用功能列表:
|
|
433
|
+
- analyze_file: 分析单个文件的代码缺陷
|
|
434
|
+
- scan_project: 扫描项目目录
|
|
435
|
+
- optimize_code: 优化代码片段
|
|
436
|
+
- search_knowledge: 搜索知识库
|
|
437
|
+
- get_status: 获取系统状态
|
|
438
|
+
- switch_provider: 切换LLM提供商
|
|
439
|
+
- switch_mode: 切换工作模式
|
|
440
|
+
|
|
441
|
+
当用户需要调用功能时,请使用以下格式输出:
|
|
442
|
+
<function_call>
|
|
443
|
+
{
|
|
444
|
+
"function": "功能名称",
|
|
445
|
+
"params": {参数对象}
|
|
446
|
+
}
|
|
447
|
+
</function_call>
|
|
448
|
+
|
|
449
|
+
如果不需要调用功能,直接回答用户问题即可。`
|
|
450
|
+
},
|
|
451
|
+
...this.chatHistory.slice(-10)
|
|
452
|
+
];
|
|
453
|
+
|
|
454
|
+
const result = await provider.chat(messages, options);
|
|
455
|
+
|
|
456
|
+
this.chatHistory.push({ role: 'assistant', content: result.content });
|
|
457
|
+
|
|
458
|
+
return result;
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
/**
|
|
462
|
+
* 清空聊天历史
|
|
463
|
+
*/
|
|
464
|
+
clearChatHistory() {
|
|
465
|
+
this.chatHistory = [];
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
/**
|
|
469
|
+
* 设置状态
|
|
470
|
+
*/
|
|
471
|
+
setState(state) {
|
|
472
|
+
this.state = state;
|
|
473
|
+
logger.info(`Agent状态: ${state}`);
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
/**
|
|
477
|
+
* 添加任务到历史
|
|
478
|
+
*/
|
|
479
|
+
addToHistory(task, result) {
|
|
480
|
+
this.taskHistory.push({
|
|
481
|
+
task,
|
|
482
|
+
result: {
|
|
483
|
+
success: result.success,
|
|
484
|
+
totalIssues: result.totalIssues,
|
|
485
|
+
mode: result.mode,
|
|
486
|
+
durationMs: result.durationMs
|
|
487
|
+
},
|
|
488
|
+
timestamp: new Date().toISOString()
|
|
489
|
+
});
|
|
490
|
+
|
|
491
|
+
// 限制历史记录数量
|
|
492
|
+
if (this.taskHistory.length > 100) {
|
|
493
|
+
this.taskHistory = this.taskHistory.slice(-50);
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
/**
|
|
498
|
+
* 保存任务结果到数据库
|
|
499
|
+
*/
|
|
500
|
+
saveTaskResult(task, result) {
|
|
501
|
+
try {
|
|
502
|
+
const db = getDatabase();
|
|
503
|
+
|
|
504
|
+
// 创建扫描任务记录
|
|
505
|
+
const taskStmt = db.prepare(`
|
|
506
|
+
INSERT INTO scan_task (project_id, task_name, scan_mode, scan_type,
|
|
507
|
+
target_path, file_count, issue_count, duration_ms, status)
|
|
508
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
509
|
+
`);
|
|
510
|
+
|
|
511
|
+
const taskResult = taskStmt.run(
|
|
512
|
+
null,
|
|
513
|
+
task.type,
|
|
514
|
+
result.mode,
|
|
515
|
+
task.type === 'analyze_project' ? 'full_project' : 'single_file',
|
|
516
|
+
task.filePath || task.projectPath || 'snippet',
|
|
517
|
+
result.totalFiles || 1,
|
|
518
|
+
result.totalIssues || 0,
|
|
519
|
+
result.durationMs || 0,
|
|
520
|
+
'completed'
|
|
521
|
+
);
|
|
522
|
+
|
|
523
|
+
const taskId = taskResult.lastInsertRowid;
|
|
524
|
+
|
|
525
|
+
// 保存代码缺陷
|
|
526
|
+
if (result.issues && result.issues.length > 0) {
|
|
527
|
+
const issueStmt = db.prepare(`
|
|
528
|
+
INSERT INTO code_issue (task_id, file_path, file_name, language, issue_type,
|
|
529
|
+
severity, message, suggestion, line_start, code_snippet)
|
|
530
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
531
|
+
`);
|
|
532
|
+
|
|
533
|
+
result.issues.forEach(issue => {
|
|
534
|
+
issueStmt.run(
|
|
535
|
+
taskId,
|
|
536
|
+
issue.filePath || 'snippet',
|
|
537
|
+
issue.fileName || 'snippet',
|
|
538
|
+
issue.language || 'unknown',
|
|
539
|
+
issue.issueType,
|
|
540
|
+
issue.severity,
|
|
541
|
+
issue.message,
|
|
542
|
+
issue.suggestion || '',
|
|
543
|
+
issue.lineStart || 1,
|
|
544
|
+
issue.codeSnippet || ''
|
|
545
|
+
);
|
|
546
|
+
});
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
logger.info(`任务结果已保存: ${taskId}`);
|
|
550
|
+
} catch (error) {
|
|
551
|
+
logger.error('保存任务结果失败:', error);
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
// 单例实例
|
|
557
|
+
const agent = new CodeOptimizerAgent();
|
|
558
|
+
|
|
559
|
+
module.exports = {
|
|
560
|
+
CodeOptimizerAgent,
|
|
561
|
+
agent,
|
|
562
|
+
AgentState
|
|
563
|
+
};
|