autosnippet 3.0.13 → 3.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.
- package/bin/api-server.js +2 -0
- package/bin/cli.js +24 -19
- package/config/default.json +1 -1
- package/lib/bootstrap.js +4 -4
- package/lib/cli/SetupService.js +29 -29
- package/lib/cli/UpgradeService.js +3 -2
- package/lib/core/AstAnalyzer.js +1 -1
- package/lib/core/ast/ensure-grammars.js +1 -1
- package/lib/core/ast/index.js +62 -11
- package/lib/core/ast/lang-dart.js +27 -21
- package/lib/core/ast/lang-go.js +6 -20
- package/lib/core/ast/lang-rust.js +53 -28
- package/lib/core/ast/parser-init.js +9 -5
- package/lib/core/discovery/DartDiscoverer.js +4 -10
- package/lib/core/discovery/GoDiscoverer.js +45 -25
- package/lib/core/discovery/NodeDiscoverer.js +1 -3
- package/lib/core/discovery/PythonDiscoverer.js +7 -1
- package/lib/core/discovery/RustDiscoverer.js +111 -38
- package/lib/core/discovery/index.js +2 -2
- package/lib/core/enhancement/django-enhancement.js +10 -4
- package/lib/core/enhancement/fastapi-enhancement.js +16 -9
- package/lib/core/enhancement/go-grpc-enhancement.js +2 -1
- package/lib/core/enhancement/go-web-enhancement.js +3 -6
- package/lib/core/enhancement/ml-enhancement.js +6 -3
- package/lib/core/enhancement/nextjs-enhancement.js +17 -7
- package/lib/core/enhancement/node-server-enhancement.js +4 -2
- package/lib/core/enhancement/react-enhancement.js +6 -3
- package/lib/core/enhancement/rust-tokio-enhancement.js +6 -2
- package/lib/core/enhancement/rust-web-enhancement.js +13 -7
- package/lib/core/enhancement/vue-enhancement.js +10 -5
- package/lib/external/ai/AiFactory.js +3 -1
- package/lib/external/ai/AiProvider.js +3 -1
- package/lib/external/mcp/McpServer.js +2 -0
- package/lib/external/mcp/handlers/bootstrap/base-dimensions.js +1 -2
- package/lib/external/mcp/handlers/bootstrap/pipeline/checkpoint.js +7 -1
- package/lib/external/mcp/handlers/bootstrap/pipeline/noAiFallback.js +55 -26
- package/lib/external/mcp/handlers/bootstrap/pipeline/orchestrator.js +8 -8
- package/lib/external/mcp/handlers/bootstrap/refine.js +3 -1
- package/lib/external/mcp/handlers/bootstrap.js +4 -10
- package/lib/external/mcp/handlers/browse.js +6 -2
- package/lib/external/mcp/handlers/guard.js +6 -2
- package/lib/external/mcp/handlers/skill.js +6 -2
- package/lib/http/HttpServer.js +1 -1
- package/lib/http/routes/candidates.js +3 -1
- package/lib/http/routes/extract.js +4 -5
- package/lib/http/routes/guardRules.js +1 -1
- package/lib/http/routes/modules.js +9 -3
- package/lib/http/routes/skills.js +54 -6
- package/lib/http/routes/violations.js +4 -3
- package/lib/infrastructure/external/ClipboardManager.js +24 -7
- package/lib/infrastructure/external/NativeUi.js +3 -1
- package/lib/infrastructure/external/OpenBrowser.js +1 -0
- package/lib/infrastructure/external/XcodeAutomation.js +5 -5
- package/lib/infrastructure/vector/IndexingPipeline.js +14 -5
- package/lib/injection/ServiceContainer.js +34 -11
- package/lib/platform/ios/index.js +20 -25
- package/lib/platform/ios/routes/spm.js +6 -3
- package/lib/platform/ios/snippet/PlaceholderConverter.js +6 -2
- package/lib/platform/ios/snippet/XcodeCodec.js +4 -2
- package/lib/platform/ios/spm/SpmDiscoverer.js +1 -1
- package/lib/platform/ios/spm/SpmService.js +3 -1
- package/lib/platform/ios/xcode/XcodeIntegration.js +10 -12
- package/lib/platform/ios/xcode/XcodeWriteUtils.js +6 -1
- package/lib/service/automation/FileWatcher.js +1 -3
- package/lib/service/automation/handlers/CreateHandler.js +3 -5
- package/lib/service/automation/handlers/GuardHandler.js +11 -32
- package/lib/service/automation/handlers/SearchHandler.js +9 -9
- package/lib/service/chat/CandidateGuardrail.js +11 -6
- package/lib/service/chat/ChatAgent.js +31 -22
- package/lib/service/chat/HandoffProtocol.js +5 -2
- package/lib/service/chat/tools/composite.js +3 -2
- package/lib/service/chat/tools/index.js +60 -71
- package/lib/service/chat/tools/infrastructure.js +9 -4
- package/lib/service/chat/tools/lifecycle.js +22 -5
- package/lib/service/chat/tools/project-access.js +5 -9
- package/lib/service/chat/tools.js +1 -2
- package/lib/service/cursor/AgentInstructionsGenerator.js +33 -15
- package/lib/service/cursor/CursorDeliveryPipeline.js +2 -1
- package/lib/service/cursor/KnowledgeCompressor.js +16 -7
- package/lib/service/guard/ComplianceReporter.js +5 -2
- package/lib/service/guard/GuardCheckEngine.js +53 -26
- package/lib/service/guard/GuardCodeChecks.js +217 -188
- package/lib/service/guard/GuardCrossFileChecks.js +203 -184
- package/lib/service/guard/GuardPatternUtils.js +17 -10
- package/lib/service/module/ModuleService.js +180 -56
- package/lib/service/recipe/RecipeCandidateValidator.js +11 -8
- package/lib/service/snippet/SnippetFactory.js +3 -3
- package/lib/service/snippet/SnippetInstaller.js +35 -11
- package/lib/service/snippet/codecs/VSCodeCodec.js +2 -2
- package/lib/service/wiki/WikiGenerator.js +67 -40
- package/lib/service/wiki/WikiRenderers.js +105 -80
- package/lib/service/wiki/WikiUtils.js +217 -80
- package/lib/shared/LanguageService.js +111 -53
- package/lib/shared/PathGuard.js +0 -8
- package/package.json +3 -9
- package/scripts/bench-real-projects.mjs +29 -29
- package/scripts/generate-recipe-drafts.js +17 -27
- package/scripts/init-snippets.js +43 -24
- package/scripts/install-vscode-copilot.js +3 -19
- package/scripts/setup-mcp-config.js +0 -4
|
@@ -110,15 +110,12 @@ export async function handleGuard(watcher, fullPath, code, guardLine) {
|
|
|
110
110
|
}
|
|
111
111
|
|
|
112
112
|
const scopeLabel = scope === 'project' ? '整个项目' : '当前目录';
|
|
113
|
-
console.log(`\n🔍 Guard 审计 — ${scopeLabel} (${scanRoot})`);
|
|
114
113
|
const sourcePaths = await collectSourceFiles(scanRoot);
|
|
115
114
|
|
|
116
115
|
if (sourcePaths.length === 0) {
|
|
117
|
-
console.log(' ℹ️ 未找到可审计的源文件');
|
|
118
116
|
watcher._notify?.('未找到可审计的源文件');
|
|
119
117
|
return;
|
|
120
118
|
}
|
|
121
|
-
console.log(` 📁 扫描到 ${sourcePaths.length} 个源文件`);
|
|
122
119
|
|
|
123
120
|
// 读取所有文件内容
|
|
124
121
|
const fileEntries = [];
|
|
@@ -140,47 +137,36 @@ export async function handleGuard(watcher, fullPath, code, guardLine) {
|
|
|
140
137
|
const { summary } = report;
|
|
141
138
|
|
|
142
139
|
if (summary.totalViolations === 0) {
|
|
143
|
-
console.log(`\n ✅ 审计通过 — ${fileEntries.length} 个文件,无违规`);
|
|
144
140
|
watcher._notify?.(`${scopeLabel}审计通过 ✅ ${fileEntries.length} 个文件,无违规`);
|
|
145
141
|
} else {
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
142
|
+
watcher._notify?.(
|
|
143
|
+
`${scopeLabel}审计: ${summary.totalViolations} 个问题 (${summary.errors ?? 0} 错误, ${summary.warnings ?? 0} 警告)`
|
|
144
|
+
);
|
|
149
145
|
const filesWithIssues = report.files.filter((f) => f.summary.total > 0);
|
|
150
146
|
for (const file of filesWithIssues.slice(0, 10)) {
|
|
151
|
-
const
|
|
147
|
+
const _rel = file.filePath.replace(`${scanRoot}/`, '');
|
|
152
148
|
const errors = file.violations.filter((v) => v.severity === 'error');
|
|
153
149
|
const warnings = file.violations.filter((v) => v.severity === 'warning');
|
|
154
|
-
|
|
155
|
-
for (const v of errors.slice(0, 5)) {
|
|
156
|
-
console.log(` 🔴 [${v.ruleId || 'unknown'}] ${v.message}${v.line ? ` (行 ${v.line})` : ''}`);
|
|
150
|
+
for (const _v of errors.slice(0, 5)) {
|
|
157
151
|
}
|
|
158
152
|
if (errors.length > 5) {
|
|
159
|
-
console.log(` ... 还有 ${errors.length - 5} 个错误`);
|
|
160
153
|
}
|
|
161
|
-
for (const
|
|
162
|
-
console.log(` 🟡 [${v.ruleId || 'unknown'}] ${v.message}${v.line ? ` (行 ${v.line})` : ''}`);
|
|
154
|
+
for (const _v of warnings.slice(0, 3)) {
|
|
163
155
|
}
|
|
164
156
|
if (warnings.length > 3) {
|
|
165
|
-
console.log(` ... 还有 ${warnings.length - 3} 个警告`);
|
|
166
157
|
}
|
|
167
158
|
}
|
|
168
159
|
if (filesWithIssues.length > 10) {
|
|
169
|
-
console.log(`\n ... 还有 ${filesWithIssues.length - 10} 个文件有问题`);
|
|
170
160
|
}
|
|
171
161
|
|
|
172
162
|
// 跨文件问题汇总
|
|
173
163
|
if (report.crossFileViolations?.length > 0) {
|
|
174
|
-
console.log(`\n 🔗 跨文件问题 (${report.crossFileViolations.length} 个):`);
|
|
175
164
|
for (const v of report.crossFileViolations.slice(0, 10)) {
|
|
176
|
-
console.log(` ⚠️ [${v.ruleId || 'cross-file'}] ${v.message}`);
|
|
177
165
|
if (v.locations) {
|
|
178
166
|
for (const loc of v.locations.slice(0, 5)) {
|
|
179
|
-
const
|
|
180
|
-
console.log(` 📍 ${relLoc}${loc.line ? `:${loc.line}` : ''}`);
|
|
167
|
+
const _relLoc = loc.filePath.replace(`${scanRoot}/`, '');
|
|
181
168
|
}
|
|
182
169
|
if (v.locations.length > 5) {
|
|
183
|
-
console.log(` ... 还有 ${v.locations.length - 5} 个位置`);
|
|
184
170
|
}
|
|
185
171
|
}
|
|
186
172
|
}
|
|
@@ -197,9 +183,7 @@ export async function handleGuard(watcher, fullPath, code, guardLine) {
|
|
|
197
183
|
const results = await searchEngine.search(rest, { limit: 3, mode: 'keyword' });
|
|
198
184
|
const items = Array.isArray(results) ? results : results.items || [];
|
|
199
185
|
if (items.length > 0) {
|
|
200
|
-
|
|
201
|
-
for (const r of items) {
|
|
202
|
-
console.log(` • ${r.title || r.name || r.id}`);
|
|
186
|
+
for (const _r of items) {
|
|
203
187
|
}
|
|
204
188
|
}
|
|
205
189
|
} catch {
|
|
@@ -219,27 +203,22 @@ function _auditSingleFile(watcher, engine, fullPath, code, detectLanguage, scope
|
|
|
219
203
|
const violations = engine.checkCode(code, language, { scope });
|
|
220
204
|
|
|
221
205
|
if (violations.length === 0) {
|
|
222
|
-
console.log(`\n ✅ Guard 审计通过 — 无违规 (${fullPath.split('/').pop()})`);
|
|
223
206
|
watcher._notify?.('审计通过 ✅ 无违规');
|
|
224
207
|
} else {
|
|
225
208
|
const errors = violations.filter((v) => v.severity === 'error');
|
|
226
209
|
const warnings = violations.filter((v) => v.severity === 'warning');
|
|
227
|
-
|
|
228
|
-
|
|
210
|
+
watcher._notify?.(
|
|
211
|
+
`审计: ${violations.length} 个问题 (${errors.length} 错误, ${warnings.length} 警告)`
|
|
212
|
+
);
|
|
229
213
|
for (const v of errors) {
|
|
230
|
-
console.log(` 🔴 [${v.ruleId || 'unknown'}] ${v.message}${v.line ? ` (行 ${v.line})` : ''}`);
|
|
231
214
|
if (v.fixSuggestion) {
|
|
232
|
-
console.log(` 💡 建议: ${v.fixSuggestion}`);
|
|
233
215
|
}
|
|
234
216
|
}
|
|
235
217
|
for (const v of warnings.slice(0, 5)) {
|
|
236
|
-
console.log(` 🟡 [${v.ruleId || 'unknown'}] ${v.message}${v.line ? ` (行 ${v.line})` : ''}`);
|
|
237
218
|
if (v.fixSuggestion) {
|
|
238
|
-
console.log(` 💡 建议: ${v.fixSuggestion}`);
|
|
239
219
|
}
|
|
240
220
|
}
|
|
241
221
|
if (warnings.length > 5) {
|
|
242
|
-
console.log(` ... 还有 ${warnings.length - 5} 个警告`);
|
|
243
222
|
}
|
|
244
223
|
}
|
|
245
224
|
|
|
@@ -292,14 +292,14 @@ function _stripMarkdownFormatting(md) {
|
|
|
292
292
|
return '';
|
|
293
293
|
}
|
|
294
294
|
return md
|
|
295
|
-
.replace(/```[\w]*\n[\s\S]*?```/g, '')
|
|
296
|
-
.replace(/^#{1,6}\s+/gm, '')
|
|
297
|
-
.replace(/\*\*([^*]+)\*\*/g, '$1')
|
|
298
|
-
.replace(/\*([^*]+)\*/g, '$1')
|
|
299
|
-
.replace(/`([^`]+)`/g, '$1')
|
|
300
|
-
.replace(/^\s*[-*+]\s+/gm, '')
|
|
301
|
-
.replace(/^\s*\d+\.\s+/gm, '')
|
|
302
|
-
.replace(/\[([^\]]+)\]\([^)]+\)/g, '$1')
|
|
303
|
-
.replace(/\n{3,}/g, '\n\n')
|
|
295
|
+
.replace(/```[\w]*\n[\s\S]*?```/g, '') // 移除代码块
|
|
296
|
+
.replace(/^#{1,6}\s+/gm, '') // 移除标题标记
|
|
297
|
+
.replace(/\*\*([^*]+)\*\*/g, '$1') // 移除粗体
|
|
298
|
+
.replace(/\*([^*]+)\*/g, '$1') // 移除斜体
|
|
299
|
+
.replace(/`([^`]+)`/g, '$1') // 移除行内代码
|
|
300
|
+
.replace(/^\s*[-*+]\s+/gm, '') // 移除列表标记
|
|
301
|
+
.replace(/^\s*\d+\.\s+/gm, '') // 移除有序列表
|
|
302
|
+
.replace(/\[([^\]]+)\]\([^)]+\)/g, '$1') // 移除链接,保留文字
|
|
303
|
+
.replace(/\n{3,}/g, '\n\n') // 压缩多余空行
|
|
304
304
|
.trim();
|
|
305
305
|
}
|
|
@@ -16,9 +16,9 @@
|
|
|
16
16
|
*/
|
|
17
17
|
function codeFingerprint(code) {
|
|
18
18
|
return (code || '')
|
|
19
|
-
.replace(/\/\/[^\n]*/g, '')
|
|
19
|
+
.replace(/\/\/[^\n]*/g, '') // 移除单行注释
|
|
20
20
|
.replace(/\/\*[\s\S]*?\*\//g, '') // 移除多行注释
|
|
21
|
-
.replace(/[\s]+/g, '')
|
|
21
|
+
.replace(/[\s]+/g, '') // 移除所有空白
|
|
22
22
|
.toLowerCase()
|
|
23
23
|
.slice(0, 200);
|
|
24
24
|
}
|
|
@@ -101,7 +101,10 @@ export class CandidateGuardrail {
|
|
|
101
101
|
|
|
102
102
|
// headers 必填(数组,空项目也需传 [])
|
|
103
103
|
if (!Array.isArray(candidate.headers)) {
|
|
104
|
-
return {
|
|
104
|
+
return {
|
|
105
|
+
valid: false,
|
|
106
|
+
error: '缺少必填字段: headers — 需为 import 语句数组,无 import 时传 []',
|
|
107
|
+
};
|
|
105
108
|
}
|
|
106
109
|
|
|
107
110
|
// knowledgeType 约束 — 自动修正为允许列表中第一个类型
|
|
@@ -114,7 +117,10 @@ export class CandidateGuardrail {
|
|
|
114
117
|
|
|
115
118
|
// reasoning 必填
|
|
116
119
|
if (!candidate.reasoning || typeof candidate.reasoning !== 'object') {
|
|
117
|
-
return {
|
|
120
|
+
return {
|
|
121
|
+
valid: false,
|
|
122
|
+
error: '缺少必填字段: reasoning — 需包含 whyStandard + sources + confidence',
|
|
123
|
+
};
|
|
118
124
|
}
|
|
119
125
|
if (!candidate.reasoning.whyStandard?.trim()) {
|
|
120
126
|
return { valid: false, error: '缺少必填字段: reasoning.whyStandard' };
|
|
@@ -173,8 +179,7 @@ export class CandidateGuardrail {
|
|
|
173
179
|
}
|
|
174
180
|
|
|
175
181
|
// 检查是否包含代码引用或文件路径
|
|
176
|
-
const hasCodeBlock =
|
|
177
|
-
/```[\s\S]*?```/.test(content) || /\.\w{1,10}(:\d+)?/.test(content);
|
|
182
|
+
const hasCodeBlock = /```[\s\S]*?```/.test(content) || /\.\w{1,10}(:\d+)?/.test(content);
|
|
178
183
|
const hasSourceRef =
|
|
179
184
|
/来源[::]|[Ss]ource[::]|\(\w+\.\w+:\d+\)/.test(content) ||
|
|
180
185
|
/[A-Z]\w+\.(?:m|h|swift|java|kt|js|ts|go|py|rs|rb|cs|cpp|c)/.test(content);
|
|
@@ -26,23 +26,23 @@ import fs from 'node:fs';
|
|
|
26
26
|
import path from 'node:path';
|
|
27
27
|
import { fileURLToPath } from 'node:url';
|
|
28
28
|
import Logger from '../../infrastructure/logging/Logger.js';
|
|
29
|
-
import {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
29
|
+
import {
|
|
30
|
+
buildNativeToolSystemPrompt,
|
|
31
|
+
buildProjectBriefing,
|
|
32
|
+
cleanFinalAnswer,
|
|
33
|
+
} from './ChatAgentPrompts.js';
|
|
34
34
|
import {
|
|
35
35
|
taskCheckAndSubmit,
|
|
36
36
|
taskDiscoverAllRelations,
|
|
37
37
|
taskFullEnrich,
|
|
38
|
-
taskQualityAudit,
|
|
39
38
|
taskGuardFullScan,
|
|
39
|
+
taskQualityAudit,
|
|
40
40
|
} from './ChatAgentTasks.js';
|
|
41
|
-
import {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
} from './
|
|
41
|
+
import { ContextWindow, limitToolResult, PhaseRouter } from './ContextWindow.js';
|
|
42
|
+
import { ConversationStore } from './ConversationStore.js';
|
|
43
|
+
import { Memory } from './Memory.js';
|
|
44
|
+
import { ReasoningLayer } from './ReasoningLayer.js';
|
|
45
|
+
import { TaskPipeline } from './TaskPipeline.js';
|
|
46
46
|
|
|
47
47
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
48
48
|
const PROJECT_ROOT = path.resolve(__dirname, '../../..');
|
|
@@ -420,21 +420,25 @@ export class ChatAgent {
|
|
|
420
420
|
isSystem && !disablePhaseRouter ? new PhaseRouter(budget, isSkillOnly) : null;
|
|
421
421
|
|
|
422
422
|
// ── 系统提示词 (支持外部覆盖) ──
|
|
423
|
-
let baseSystemPrompt =
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
423
|
+
let baseSystemPrompt =
|
|
424
|
+
systemPromptOverride ||
|
|
425
|
+
buildNativeToolSystemPrompt({
|
|
426
|
+
currentSource: this.#currentSource,
|
|
427
|
+
projectBriefingCache: this.#projectBriefingCache,
|
|
428
|
+
memory: this.#memory,
|
|
429
|
+
semanticMemory: this.#semanticMemory,
|
|
430
|
+
budget,
|
|
431
|
+
soulPath: SOUL_PATH,
|
|
432
|
+
});
|
|
431
433
|
|
|
432
434
|
// ── 统一注入语言指令(对所有来源生效: user 对话 / system bootstrap / analyst / producer)──
|
|
433
435
|
const effectiveLang = this.#currentLang;
|
|
434
436
|
if (effectiveLang === 'en') {
|
|
435
|
-
baseSystemPrompt +=
|
|
437
|
+
baseSystemPrompt +=
|
|
438
|
+
'\n\n## Language\nYou MUST respond in English. All output text, analysis, titles and descriptions must be in English.';
|
|
436
439
|
} else if (effectiveLang === 'zh') {
|
|
437
|
-
baseSystemPrompt +=
|
|
440
|
+
baseSystemPrompt +=
|
|
441
|
+
'\n\n## 语言\n你必须使用中文回复。所有输出文本、分析、标题和描述都必须是中文。';
|
|
438
442
|
}
|
|
439
443
|
|
|
440
444
|
// 统一注入轮次预算,确保 AI 始终知道具体数字和节奏
|
|
@@ -1008,7 +1012,12 @@ export class ChatAgent {
|
|
|
1008
1012
|
// 记录代码模式指纹用于跨维度去重
|
|
1009
1013
|
const pattern = fc.args?.content?.pattern || '';
|
|
1010
1014
|
if (pattern.length >= 30) {
|
|
1011
|
-
const fp = pattern
|
|
1015
|
+
const fp = pattern
|
|
1016
|
+
.replace(/\/\/[^\n]*/g, '')
|
|
1017
|
+
.replace(/\/\*[\s\S]*?\*\//g, '')
|
|
1018
|
+
.replace(/[\s]+/g, '')
|
|
1019
|
+
.toLowerCase()
|
|
1020
|
+
.slice(0, 200);
|
|
1012
1021
|
if (fp.length >= 20) {
|
|
1013
1022
|
this.#globalSubmittedPatterns.add(fp);
|
|
1014
1023
|
}
|
|
@@ -129,7 +129,9 @@ export function buildAnalysisReport(analystResult, dimensionId, projectGraph = n
|
|
|
129
129
|
}
|
|
130
130
|
// 从搜索结果中提取文件路径
|
|
131
131
|
if (typeof result === 'string') {
|
|
132
|
-
const fileMatches = result.match(
|
|
132
|
+
const fileMatches = result.match(
|
|
133
|
+
/(?:^|\n)([\w/.-]+\.(?:go|mod|sum|py|pyi|java|kt|kts|js|ts|jsx|tsx|mjs|cjs|swift|m|h|c|cpp|cc|hpp|cs|rb|rs|sql|json|yaml|yml|toml|xml|html|css|scss|less|sh|md|txt|gradle|properties|proto|vue|svelte|graphql|cfg|conf|ini|env|lock|rst))(?::\d+)?/gi
|
|
134
|
+
);
|
|
133
135
|
if (fileMatches) {
|
|
134
136
|
for (const m of fileMatches) {
|
|
135
137
|
const clean = m.trim().replace(/:\d+$/, '').replace(/^\n/, '');
|
|
@@ -170,7 +172,8 @@ export function buildAnalysisReport(analystResult, dimensionId, projectGraph = n
|
|
|
170
172
|
|
|
171
173
|
// 从分析文本中提取文件路径(支持多语言项目)
|
|
172
174
|
const text = sanitizeAnalysisText(analystResult.reply || '');
|
|
173
|
-
const FILE_EXT_RE =
|
|
175
|
+
const FILE_EXT_RE =
|
|
176
|
+
/[\w/.-]+\.(?:go|mod|sum|py|pyi|java|kt|kts|js|ts|jsx|tsx|mjs|cjs|swift|m|h|c|cpp|cc|hpp|cs|rb|rs|sql|json|yaml|yml|toml|xml|html|css|scss|less|sh|md|txt|gradle|properties|proto|vue|svelte|graphql|cfg|conf|ini|env|lock|rst)\b/gi;
|
|
174
177
|
const textFileRefs = text.match(FILE_EXT_RE);
|
|
175
178
|
if (textFileRefs) {
|
|
176
179
|
for (const f of textFileRefs) {
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
12
|
import { findSimilarRecipes } from '../../candidate/SimilarityService.js';
|
|
13
|
-
import {
|
|
13
|
+
import { checkDimensionType, DIMENSION_DISPLAY_GROUP } from './_shared.js';
|
|
14
14
|
|
|
15
15
|
// ────────────────────────────────────────────────────────────
|
|
16
16
|
// 34. analyze_code — 组合工具 (Guard + Recipe 搜索)
|
|
@@ -157,7 +157,8 @@ export const submitWithCheck = {
|
|
|
157
157
|
properties: {
|
|
158
158
|
content: {
|
|
159
159
|
type: 'object',
|
|
160
|
-
description:
|
|
160
|
+
description:
|
|
161
|
+
'{ markdown: "项目特写 Markdown", pattern: "核心代码 3-8 行,必须语法完整(括号配对、不能以 } 开头或 { 结尾)" }',
|
|
161
162
|
},
|
|
162
163
|
title: { type: 'string', description: '候选标题' },
|
|
163
164
|
description: { type: 'string', description: '中文简述 ≤80 字' },
|
|
@@ -4,99 +4,88 @@
|
|
|
4
4
|
* 从各子模块导入所有工具,按原始顺序组装 ALL_TOOLS 数组并导出。
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
// ── 项目数据访问 (5) ──
|
|
8
|
-
import {
|
|
9
|
-
searchProjectCode,
|
|
10
|
-
readProjectFile,
|
|
11
|
-
listProjectStructure,
|
|
12
|
-
getFileSummary,
|
|
13
|
-
semanticSearchCode,
|
|
14
|
-
} from './project-access.js';
|
|
15
|
-
|
|
16
|
-
// ── 查询类 (6) ──
|
|
17
|
-
import {
|
|
18
|
-
searchRecipes,
|
|
19
|
-
searchCandidates,
|
|
20
|
-
getRecipeDetail,
|
|
21
|
-
getProjectStats,
|
|
22
|
-
searchKnowledge,
|
|
23
|
-
getRelatedRecipes,
|
|
24
|
-
} from './query.js';
|
|
25
|
-
|
|
26
7
|
// ── AI 分析类 (4) ──
|
|
27
8
|
import {
|
|
28
|
-
summarizeCode,
|
|
29
|
-
extractRecipes,
|
|
30
9
|
enrichCandidate,
|
|
10
|
+
extractRecipes,
|
|
31
11
|
refineBootstrapCandidates,
|
|
12
|
+
summarizeCode,
|
|
32
13
|
} from './ai-analysis.js';
|
|
14
|
+
// ── AST 结构化分析 + Agent Memory (10) ──
|
|
15
|
+
import {
|
|
16
|
+
getCategoryMap,
|
|
17
|
+
getClassHierarchy,
|
|
18
|
+
getClassInfo,
|
|
19
|
+
getMethodOverrides,
|
|
20
|
+
getPreviousAnalysis,
|
|
21
|
+
getPreviousEvidence,
|
|
22
|
+
getProjectOverview,
|
|
23
|
+
getProtocolInfo,
|
|
24
|
+
noteFinding,
|
|
25
|
+
queryCodeGraph,
|
|
26
|
+
} from './ast-graph.js';
|
|
27
|
+
// ── 组合工具 + 元工具 (6) ──
|
|
28
|
+
import {
|
|
29
|
+
analyzeCode,
|
|
30
|
+
getToolDetails,
|
|
31
|
+
knowledgeOverview,
|
|
32
|
+
planTask,
|
|
33
|
+
reviewMyOutput,
|
|
34
|
+
submitWithCheck,
|
|
35
|
+
} from './composite.js';
|
|
33
36
|
|
|
34
37
|
// ── Guard 安全类 (6) ──
|
|
35
38
|
import {
|
|
36
|
-
listGuardRules,
|
|
37
|
-
getRecommendations,
|
|
38
39
|
aiTranslate,
|
|
40
|
+
generateGuardRule,
|
|
41
|
+
getRecommendations,
|
|
39
42
|
guardCheckCode,
|
|
43
|
+
listGuardRules,
|
|
40
44
|
queryViolations,
|
|
41
|
-
generateGuardRule,
|
|
42
45
|
} from './guard.js';
|
|
43
|
-
|
|
44
|
-
// ── 知识图谱类 (3) ──
|
|
46
|
+
// ── 基础设施类 (7) ──
|
|
45
47
|
import {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
48
|
+
bootstrapKnowledgeTool,
|
|
49
|
+
createSkillTool,
|
|
50
|
+
graphImpactAnalysis,
|
|
51
|
+
loadSkill,
|
|
52
|
+
queryAuditLog,
|
|
53
|
+
rebuildIndex,
|
|
54
|
+
suggestSkills,
|
|
55
|
+
} from './infrastructure.js';
|
|
56
|
+
// ── 知识图谱类 (3) ──
|
|
57
|
+
import { addGraphEdge, checkDuplicate, discoverRelations } from './knowledge-graph.js';
|
|
51
58
|
// ── 生命周期操作类 (11) ──
|
|
52
59
|
import {
|
|
53
|
-
submitCandidate,
|
|
54
|
-
saveDocument,
|
|
55
60
|
approveCandidate,
|
|
56
|
-
rejectCandidate,
|
|
57
|
-
publishRecipe,
|
|
58
61
|
deprecateRecipe,
|
|
59
|
-
|
|
60
|
-
|
|
62
|
+
getFeedbackStats,
|
|
63
|
+
publishRecipe,
|
|
61
64
|
qualityScore,
|
|
65
|
+
recordUsage,
|
|
66
|
+
rejectCandidate,
|
|
67
|
+
saveDocument,
|
|
68
|
+
submitCandidate,
|
|
69
|
+
updateRecipe,
|
|
62
70
|
validateCandidate,
|
|
63
|
-
getFeedbackStats,
|
|
64
71
|
} from './lifecycle.js';
|
|
65
|
-
|
|
66
|
-
// ── 基础设施类 (7) ──
|
|
67
|
-
import {
|
|
68
|
-
graphImpactAnalysis,
|
|
69
|
-
rebuildIndex,
|
|
70
|
-
queryAuditLog,
|
|
71
|
-
loadSkill,
|
|
72
|
-
createSkillTool,
|
|
73
|
-
suggestSkills,
|
|
74
|
-
bootstrapKnowledgeTool,
|
|
75
|
-
} from './infrastructure.js';
|
|
76
|
-
|
|
77
|
-
// ── 组合工具 + 元工具 (6) ──
|
|
72
|
+
// ── 项目数据访问 (5) ──
|
|
78
73
|
import {
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
// ── AST 结构化分析 + Agent Memory (10) ──
|
|
74
|
+
getFileSummary,
|
|
75
|
+
listProjectStructure,
|
|
76
|
+
readProjectFile,
|
|
77
|
+
searchProjectCode,
|
|
78
|
+
semanticSearchCode,
|
|
79
|
+
} from './project-access.js';
|
|
80
|
+
// ── 查询类 (6) ──
|
|
88
81
|
import {
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
noteFinding,
|
|
97
|
-
getPreviousEvidence,
|
|
98
|
-
queryCodeGraph,
|
|
99
|
-
} from './ast-graph.js';
|
|
82
|
+
getProjectStats,
|
|
83
|
+
getRecipeDetail,
|
|
84
|
+
getRelatedRecipes,
|
|
85
|
+
searchCandidates,
|
|
86
|
+
searchKnowledge,
|
|
87
|
+
searchRecipes,
|
|
88
|
+
} from './query.js';
|
|
100
89
|
|
|
101
90
|
// ── Re-export 所有工具 ──
|
|
102
91
|
export {
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
import fs from 'node:fs';
|
|
14
14
|
import path from 'node:path';
|
|
15
15
|
import Logger from '../../../infrastructure/logging/Logger.js';
|
|
16
|
-
import {
|
|
16
|
+
import { PROJECT_SKILLS_DIR, SKILLS_DIR } from './_shared.js';
|
|
17
17
|
|
|
18
18
|
// ────────────────────────────────────────────────────────────
|
|
19
19
|
// 29. graph_impact_analysis
|
|
@@ -99,7 +99,8 @@ export const loadSkill = {
|
|
|
99
99
|
properties: {
|
|
100
100
|
skillName: {
|
|
101
101
|
type: 'string',
|
|
102
|
-
description:
|
|
102
|
+
description:
|
|
103
|
+
'Skill 目录名(如 autosnippet-coldstart, autosnippet-reference-swift, autosnippet-reference-go 等)',
|
|
103
104
|
},
|
|
104
105
|
},
|
|
105
106
|
required: ['skillName'],
|
|
@@ -119,12 +120,16 @@ export const loadSkill = {
|
|
|
119
120
|
fs.readdirSync(SKILLS_DIR, { withFileTypes: true })
|
|
120
121
|
.filter((d) => d.isDirectory())
|
|
121
122
|
.forEach((d) => available.add(d.name));
|
|
122
|
-
} catch {
|
|
123
|
+
} catch {
|
|
124
|
+
/* skip: SKILLS_DIR may not exist */
|
|
125
|
+
}
|
|
123
126
|
try {
|
|
124
127
|
fs.readdirSync(PROJECT_SKILLS_DIR, { withFileTypes: true })
|
|
125
128
|
.filter((d) => d.isDirectory())
|
|
126
129
|
.forEach((d) => available.add(d.name));
|
|
127
|
-
} catch {
|
|
130
|
+
} catch {
|
|
131
|
+
/* skip: project skills dir may not exist */
|
|
132
|
+
}
|
|
128
133
|
return { error: `Skill "${params.skillName}" not found`, availableSkills: [...available] };
|
|
129
134
|
}
|
|
130
135
|
},
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
17
|
import { CandidateGuardrail } from '../CandidateGuardrail.js';
|
|
18
|
-
import {
|
|
18
|
+
import { checkDimensionType, DIMENSION_DISPLAY_GROUP } from './_shared.js';
|
|
19
19
|
|
|
20
20
|
// ────────────────────────────────────────────────────────────
|
|
21
21
|
// 16. submit_knowledge
|
|
@@ -29,7 +29,8 @@ export const submitCandidate = {
|
|
|
29
29
|
// ── 内容(V3 content 子对象) ──
|
|
30
30
|
content: {
|
|
31
31
|
type: 'object',
|
|
32
|
-
description:
|
|
32
|
+
description:
|
|
33
|
+
'{ markdown: "项目特写 Markdown(≥200字)", pattern: "核心代码 3-8 行", rationale: "设计原理" }',
|
|
33
34
|
},
|
|
34
35
|
|
|
35
36
|
// ── 基本信息 ──
|
|
@@ -71,11 +72,23 @@ export const submitCandidate = {
|
|
|
71
72
|
items: { type: 'string' },
|
|
72
73
|
description: '依赖的 import/require 行(无 import 时传 [])',
|
|
73
74
|
},
|
|
74
|
-
knowledgeType: {
|
|
75
|
+
knowledgeType: {
|
|
76
|
+
type: 'string',
|
|
77
|
+
description: '知识维度:code-pattern / architecture / best-practice 等',
|
|
78
|
+
},
|
|
75
79
|
usageGuide: { type: 'string', description: '使用指南 Markdown(### 章节格式)' },
|
|
76
80
|
sourceFile: { type: 'string', description: '来源文件相对路径' },
|
|
77
81
|
},
|
|
78
|
-
required: [
|
|
82
|
+
required: [
|
|
83
|
+
'content',
|
|
84
|
+
'title',
|
|
85
|
+
'trigger',
|
|
86
|
+
'kind',
|
|
87
|
+
'doClause',
|
|
88
|
+
'description',
|
|
89
|
+
'headers',
|
|
90
|
+
'reasoning',
|
|
91
|
+
],
|
|
79
92
|
},
|
|
80
93
|
handler: async (params, ctx) => {
|
|
81
94
|
const knowledgeService = ctx.container.get('knowledgeService');
|
|
@@ -103,7 +116,11 @@ export const submitCandidate = {
|
|
|
103
116
|
params._category = DIMENSION_DISPLAY_GROUP[dimMeta.id] || dimMeta.id;
|
|
104
117
|
|
|
105
118
|
// ── CandidateGuardrail 质量验证 ──
|
|
106
|
-
const guardrail = new CandidateGuardrail(
|
|
119
|
+
const guardrail = new CandidateGuardrail(
|
|
120
|
+
ctx._submittedTitles || new Set(),
|
|
121
|
+
dimMeta,
|
|
122
|
+
ctx._submittedPatterns || new Set()
|
|
123
|
+
);
|
|
107
124
|
const guardResult = guardrail.validate(params);
|
|
108
125
|
if (!guardResult.valid) {
|
|
109
126
|
ctx.logger?.info(`[submit_knowledge] ✗ guardrail rejected: ${guardResult.error}`);
|
|
@@ -646,24 +646,21 @@ const SUMMARY_EXTRACTORS = {
|
|
|
646
646
|
},
|
|
647
647
|
go: {
|
|
648
648
|
imports: /^\s*(?:import\s+"[^"]+"|import\s+\w+\s+"[^"]+")/gm,
|
|
649
|
-
declarations:
|
|
650
|
-
|
|
651
|
-
methods:
|
|
652
|
-
/^\s*func\s+(?:\(\s*\w+\s+\*?\w+\s*\)\s+)?\w+\s*\([^)]*\)[^{]*/gm,
|
|
649
|
+
declarations: /^\s*(?:type\s+\w+\s+(?:struct|interface|func)\b.*)/gm,
|
|
650
|
+
methods: /^\s*func\s+(?:\(\s*\w+\s+\*?\w+\s*\)\s+)?\w+\s*\([^)]*\)[^{]*/gm,
|
|
653
651
|
},
|
|
654
652
|
java: {
|
|
655
653
|
imports: /^\s*import\s+(?:static\s+)?[\w.]+\*?;/gm,
|
|
656
654
|
declarations:
|
|
657
655
|
/^\s*(?:public|private|protected)?\s*(?:abstract|final|static)?\s*(?:class|interface|enum|record|@interface)\s+\w+/gm,
|
|
658
656
|
methods:
|
|
659
|
-
/^\s*(?:public|private|protected)?\s*(?:abstract|static|final|synchronized|default)?\s*(?:<[^>]+>\s+)?\w[\w
|
|
657
|
+
/^\s*(?:public|private|protected)?\s*(?:abstract|static|final|synchronized|default)?\s*(?:<[^>]+>\s+)?\w[\w<>[\],\s]*\s+\w+\s*\([^)]*\)/gm,
|
|
660
658
|
},
|
|
661
659
|
kotlin: {
|
|
662
660
|
imports: /^\s*import\s+[\w.]+/gm,
|
|
663
661
|
declarations:
|
|
664
662
|
/^\s*(?:open|abstract|data|sealed|inner|value|inline)?\s*(?:class|interface|object|enum\s+class|fun\s+interface)\s+\w+/gm,
|
|
665
|
-
methods:
|
|
666
|
-
/^\s*(?:override\s+)?(?:suspend\s+)?(?:fun|val|var)\s+(?:<[^>]+>\s+)?\w+/gm,
|
|
663
|
+
methods: /^\s*(?:override\s+)?(?:suspend\s+)?(?:fun|val|var)\s+(?:<[^>]+>\s+)?\w+/gm,
|
|
667
664
|
},
|
|
668
665
|
dart: {
|
|
669
666
|
imports: /^\s*import\s+['"][^'"]+['"];?/gm,
|
|
@@ -671,8 +668,7 @@ const SUMMARY_EXTRACTORS = {
|
|
|
671
668
|
/^\s*(?:abstract\s+|sealed\s+)?(?:class|mixin|extension|enum|typedef)\s+\w+[^{]*/gm,
|
|
672
669
|
methods:
|
|
673
670
|
/^\s*(?:@override\s+)?(?:static\s+)?(?:Future|Stream|void|\w[\w<>?]*)?\s+\w+\s*\([^)]*\)/gm,
|
|
674
|
-
properties:
|
|
675
|
-
/^\s*(?:static\s+)?(?:final\s+|late\s+|const\s+)?(?:\w[\w<>?]*)\s+\w+\s*[;=]/gm,
|
|
671
|
+
properties: /^\s*(?:static\s+)?(?:final\s+|late\s+|const\s+)?(?:\w[\w<>?]*)\s+\w+\s*[;=]/gm,
|
|
676
672
|
},
|
|
677
673
|
};
|
|
678
674
|
SUMMARY_EXTRACTORS['objectivec++'] = SUMMARY_EXTRACTORS.objectivec;
|