autosnippet 3.3.6 → 3.3.7
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/dashboard/dist/assets/icons-FHns2ypa.js +1 -0
- package/dashboard/dist/assets/index-BRJv5Y3r.js +135 -0
- package/dashboard/dist/assets/index-DzoB7kxK.css +1 -0
- package/dashboard/dist/index.html +3 -3
- package/dist/bin/cli.js +1 -0
- package/dist/lib/agent/AgentRuntime.d.ts +2 -2
- package/dist/lib/agent/AgentRuntime.js +26 -18
- package/dist/lib/agent/domain/ChatAgentTasks.js +4 -0
- package/dist/lib/agent/forced-summary.js +7 -2
- package/dist/lib/cli/AiScanService.js +4 -4
- package/dist/lib/core/discovery/ConfigWatcher.d.ts +64 -0
- package/dist/lib/core/discovery/ConfigWatcher.js +336 -0
- package/dist/lib/core/discovery/CustomConfigDiscoverer.d.ts +30 -0
- package/dist/lib/core/discovery/CustomConfigDiscoverer.js +1305 -0
- package/dist/lib/core/discovery/DiscovererPreference.d.ts +44 -0
- package/dist/lib/core/discovery/DiscovererPreference.js +141 -0
- package/dist/lib/core/discovery/DiscovererRegistry.d.ts +10 -1
- package/dist/lib/core/discovery/DiscovererRegistry.js +42 -2
- package/dist/lib/core/discovery/ProjectDiscoverer.d.ts +19 -0
- package/dist/lib/core/discovery/index.d.ts +2 -0
- package/dist/lib/core/discovery/index.js +4 -0
- package/dist/lib/core/discovery/parsers/CMakeParser.d.ts +32 -0
- package/dist/lib/core/discovery/parsers/CMakeParser.js +148 -0
- package/dist/lib/core/discovery/parsers/GradleDslParser.d.ts +43 -0
- package/dist/lib/core/discovery/parsers/GradleDslParser.js +171 -0
- package/dist/lib/core/discovery/parsers/JsonConfigParser.d.ts +45 -0
- package/dist/lib/core/discovery/parsers/JsonConfigParser.js +122 -0
- package/dist/lib/core/discovery/parsers/RubyDslParser.d.ts +49 -0
- package/dist/lib/core/discovery/parsers/RubyDslParser.js +282 -0
- package/dist/lib/core/discovery/parsers/StarlarkParser.d.ts +33 -0
- package/dist/lib/core/discovery/parsers/StarlarkParser.js +229 -0
- package/dist/lib/core/discovery/parsers/YamlConfigParser.d.ts +37 -0
- package/dist/lib/core/discovery/parsers/YamlConfigParser.js +212 -0
- package/dist/lib/domain/knowledge/KnowledgeEntry.d.ts +7 -1
- package/dist/lib/domain/knowledge/KnowledgeEntry.js +17 -3
- package/dist/lib/external/ai/AiProvider.d.ts +12 -0
- package/dist/lib/external/ai/AiProvider.js +24 -0
- package/dist/lib/external/ai/AiProviderManager.d.ts +101 -0
- package/dist/lib/external/ai/AiProviderManager.js +193 -0
- package/dist/lib/external/ai/providers/ClaudeProvider.js +11 -0
- package/dist/lib/external/ai/providers/GoogleGeminiProvider.js +18 -0
- package/dist/lib/external/ai/providers/MockProvider.d.ts +21 -3
- package/dist/lib/external/ai/providers/MockProvider.js +290 -14
- package/dist/lib/external/ai/providers/OpenAiProvider.js +16 -0
- package/dist/lib/external/lark/LarkTransport.d.ts +5 -1
- package/dist/lib/external/lark/LarkTransport.js +10 -2
- package/dist/lib/external/mcp/handlers/bootstrap/pipeline/mock-pipeline.d.ts +20 -0
- package/dist/lib/external/mcp/handlers/bootstrap/pipeline/mock-pipeline.js +432 -0
- package/dist/lib/external/mcp/handlers/bootstrap/pipeline/orchestrator.js +16 -8
- package/dist/lib/external/mcp/handlers/bootstrap/refine.js +8 -0
- package/dist/lib/external/mcp/handlers/bootstrap-external.d.ts +9 -0
- package/dist/lib/external/mcp/handlers/bootstrap-external.js +2 -0
- package/dist/lib/external/mcp/handlers/bootstrap-internal.js +2 -0
- package/dist/lib/external/mcp/handlers/consolidated.js +2 -1
- package/dist/lib/external/mcp/handlers/dimension-complete-external.js +2 -1
- package/dist/lib/external/mcp/handlers/evolve-external.js +5 -2
- package/dist/lib/external/mcp/handlers/knowledge.js +5 -4
- package/dist/lib/http/routes/ai.js +111 -30
- package/dist/lib/http/routes/candidates.js +11 -4
- package/dist/lib/http/routes/commands.js +10 -1
- package/dist/lib/http/routes/health.js +11 -0
- package/dist/lib/http/routes/modules.js +27 -0
- package/dist/lib/http/routes/recipes.js +7 -0
- package/dist/lib/http/utils/routeHelpers.js +2 -1
- package/dist/lib/injection/ServiceContainer.d.ts +6 -5
- package/dist/lib/injection/ServiceContainer.js +11 -27
- package/dist/lib/injection/ServiceMap.d.ts +2 -0
- package/dist/lib/injection/modules/AiModule.d.ts +6 -9
- package/dist/lib/injection/modules/AiModule.js +82 -39
- package/dist/lib/injection/modules/PanoramaModule.js +1 -1
- package/dist/lib/service/cleanup/CleanupService.d.ts +54 -7
- package/dist/lib/service/cleanup/CleanupService.js +284 -37
- package/dist/lib/service/knowledge/CodeEntityGraph.d.ts +6 -0
- package/dist/lib/service/knowledge/CodeEntityGraph.js +16 -0
- package/dist/lib/service/knowledge/KnowledgeService.js +23 -10
- package/dist/lib/service/module/ModuleService.js +10 -19
- package/dist/lib/service/panorama/CouplingAnalyzer.d.ts +10 -1
- package/dist/lib/service/panorama/CouplingAnalyzer.js +44 -2
- package/dist/lib/service/panorama/DimensionAnalyzer.d.ts +1 -1
- package/dist/lib/service/panorama/DimensionAnalyzer.js +31 -17
- package/dist/lib/service/panorama/LayerInferrer.d.ts +16 -1
- package/dist/lib/service/panorama/LayerInferrer.js +118 -1
- package/dist/lib/service/panorama/ModuleDiscoverer.d.ts +9 -0
- package/dist/lib/service/panorama/ModuleDiscoverer.js +58 -2
- package/dist/lib/service/panorama/PanoramaAggregator.d.ts +6 -2
- package/dist/lib/service/panorama/PanoramaAggregator.js +84 -6
- package/dist/lib/service/panorama/PanoramaScanner.js +28 -0
- package/dist/lib/service/panorama/PanoramaService.js +10 -5
- package/dist/lib/service/panorama/PanoramaTypes.d.ts +38 -0
- package/dist/lib/service/panorama/RoleRefiner.d.ts +2 -0
- package/dist/lib/service/panorama/RoleRefiner.js +41 -0
- package/dist/lib/service/panorama/TechStackProfiler.d.ts +13 -0
- package/dist/lib/service/panorama/TechStackProfiler.js +191 -0
- package/dist/lib/service/skills/SignalCollector.d.ts +1 -0
- package/dist/lib/service/skills/SignalCollector.js +6 -5
- package/dist/lib/service/vector/ContextualEnricher.d.ts +1 -0
- package/dist/lib/service/vector/ContextualEnricher.js +4 -0
- package/dist/lib/shared/LanguageService.js +3 -0
- package/dist/lib/shared/developer-identity.d.ts +18 -0
- package/dist/lib/shared/developer-identity.js +62 -0
- package/dist/lib/shared/schemas/http-requests.d.ts +8 -17
- package/dist/lib/shared/schemas/http-requests.js +9 -6
- package/dist/lib/types/knowledge-wire.d.ts +1 -0
- package/package.json +1 -1
- package/dashboard/dist/assets/icons-D1aVZYFW.js +0 -1
- package/dashboard/dist/assets/index-CxHOu8Hd.css +0 -1
- package/dashboard/dist/assets/index-DDdAOpYT.js +0 -128
|
@@ -0,0 +1,432 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* mock-pipeline.ts — Mock AI Bootstrap 轻量管线
|
|
3
|
+
*
|
|
4
|
+
* 当 AI Provider 为 mock 时,利用 Phase 1-4 已收集的真实数据
|
|
5
|
+
* (AST、依赖图、文件列表、Panorama) 为每个维度生成模板化候选知识。
|
|
6
|
+
*
|
|
7
|
+
* 不调用 AI,但走完完整的 submit → dimension_complete 流程,
|
|
8
|
+
* 使 Dashboard 能正常展示知识库、健康雷达等 UI。
|
|
9
|
+
*
|
|
10
|
+
* @module pipeline/mock-pipeline
|
|
11
|
+
*/
|
|
12
|
+
import path from 'node:path';
|
|
13
|
+
import Logger from '#infra/logging/Logger.js';
|
|
14
|
+
import { BootstrapEventEmitter } from '#service/bootstrap/BootstrapEventEmitter.js';
|
|
15
|
+
const logger = Logger.getInstance();
|
|
16
|
+
// ── 模板生成器 ────────────────────────────────────────────
|
|
17
|
+
/** 从 AST 指标提取代码统计 */
|
|
18
|
+
function extractAstStats(ast) {
|
|
19
|
+
if (!ast) {
|
|
20
|
+
return { classes: 0, protocols: 0, functions: 0 };
|
|
21
|
+
}
|
|
22
|
+
const pm = (ast.projectMetrics ?? ast);
|
|
23
|
+
return {
|
|
24
|
+
classes: pm.totalClasses ?? 0,
|
|
25
|
+
protocols: pm.totalProtocols ?? 0,
|
|
26
|
+
functions: pm.totalFunctions ?? 0,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
/** 从文件列表中按 target 分组并提取代表性文件 */
|
|
30
|
+
function getRepresentativeFiles(files, targetFileMap) {
|
|
31
|
+
const result = new Map();
|
|
32
|
+
if (targetFileMap) {
|
|
33
|
+
for (const [target, paths] of Object.entries(targetFileMap)) {
|
|
34
|
+
result.set(target, paths.slice(0, 5));
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
else if (files) {
|
|
38
|
+
const grouped = new Map();
|
|
39
|
+
for (const f of files) {
|
|
40
|
+
const target = f.targetName || 'default';
|
|
41
|
+
const list = grouped.get(target) || [];
|
|
42
|
+
list.push(f.relativePath || f.name);
|
|
43
|
+
grouped.set(target, list);
|
|
44
|
+
}
|
|
45
|
+
for (const [target, paths] of grouped) {
|
|
46
|
+
result.set(target, paths.slice(0, 5));
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return result;
|
|
50
|
+
}
|
|
51
|
+
/** 从文件内容中提取 import 语句(作为 headers)*/
|
|
52
|
+
function extractImports(content, lang) {
|
|
53
|
+
const imports = [];
|
|
54
|
+
const lines = content.split('\n').slice(0, 30);
|
|
55
|
+
for (const line of lines) {
|
|
56
|
+
const trimmed = line.trim();
|
|
57
|
+
if (lang === 'swift' && trimmed.startsWith('import ')) {
|
|
58
|
+
imports.push(trimmed);
|
|
59
|
+
}
|
|
60
|
+
else if ((lang === 'typescript' || lang === 'javascript') && trimmed.startsWith('import ')) {
|
|
61
|
+
imports.push(trimmed);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return [...new Set(imports)].slice(0, 5);
|
|
65
|
+
}
|
|
66
|
+
/** 从文件内容中提取类/结构体/协议名 */
|
|
67
|
+
function extractTypes(content) {
|
|
68
|
+
const types = [];
|
|
69
|
+
for (const m of content.matchAll(/(?:class|struct|protocol|enum|interface|type)\s+(\w+)/g)) {
|
|
70
|
+
types.push(m[1]);
|
|
71
|
+
}
|
|
72
|
+
return [...new Set(types)].slice(0, 10);
|
|
73
|
+
}
|
|
74
|
+
/** 生成 kebab-case trigger */
|
|
75
|
+
function toKebab(text) {
|
|
76
|
+
return text
|
|
77
|
+
.replace(/([a-z])([A-Z])/g, '$1-$2')
|
|
78
|
+
.replace(/[\s_]+/g, '-')
|
|
79
|
+
.toLowerCase()
|
|
80
|
+
.replace(/[^a-z0-9-]/g, '')
|
|
81
|
+
.slice(0, 40);
|
|
82
|
+
}
|
|
83
|
+
// ── 维度级候选生成 ────────────────────────────────────────
|
|
84
|
+
/** 为单个维度生成 Mock 候选 */
|
|
85
|
+
function generateDimensionCandidates(dimId, dimLabel, files, lang, projectName, astStats, targetFiles) {
|
|
86
|
+
const candidates = [];
|
|
87
|
+
// 从文件中收集有代表性的类型和源文件
|
|
88
|
+
const allTypes = [];
|
|
89
|
+
const allSources = [];
|
|
90
|
+
const allImports = [];
|
|
91
|
+
const dimFiles = files?.filter((f) => {
|
|
92
|
+
const p = f.relativePath?.toLowerCase() || f.name.toLowerCase();
|
|
93
|
+
// 根据维度 ID 做简单相关性匹配
|
|
94
|
+
switch (dimId) {
|
|
95
|
+
case 'architecture':
|
|
96
|
+
return (p.includes('coordinator') ||
|
|
97
|
+
p.includes('delegate') ||
|
|
98
|
+
p.includes('service') ||
|
|
99
|
+
p.includes('manager'));
|
|
100
|
+
case 'code-pattern':
|
|
101
|
+
return p.includes('extension') || p.includes('helper') || p.includes('util');
|
|
102
|
+
case 'naming-style':
|
|
103
|
+
return true; // 全局适用
|
|
104
|
+
case 'error-handling':
|
|
105
|
+
return p.includes('error') || p.includes('result') || p.includes('handler');
|
|
106
|
+
case 'networking':
|
|
107
|
+
return (p.includes('network') ||
|
|
108
|
+
p.includes('api') ||
|
|
109
|
+
p.includes('request') ||
|
|
110
|
+
p.includes('http'));
|
|
111
|
+
case 'data-model':
|
|
112
|
+
return p.includes('model') || p.includes('entity') || p.includes('dto');
|
|
113
|
+
case 'testing-quality':
|
|
114
|
+
return p.includes('test') || p.includes('spec') || p.includes('mock');
|
|
115
|
+
case 'ui-patterns':
|
|
116
|
+
return (p.includes('view') ||
|
|
117
|
+
p.includes('controller') ||
|
|
118
|
+
p.includes('cell') ||
|
|
119
|
+
p.includes('component'));
|
|
120
|
+
case 'concurrency':
|
|
121
|
+
return (p.includes('actor') ||
|
|
122
|
+
p.includes('async') ||
|
|
123
|
+
p.includes('queue') ||
|
|
124
|
+
p.includes('dispatch'));
|
|
125
|
+
case 'storage':
|
|
126
|
+
return (p.includes('store') ||
|
|
127
|
+
p.includes('cache') ||
|
|
128
|
+
p.includes('database') ||
|
|
129
|
+
p.includes('persist'));
|
|
130
|
+
default:
|
|
131
|
+
return true;
|
|
132
|
+
}
|
|
133
|
+
}) || [];
|
|
134
|
+
// 提取文件中的类型和导入
|
|
135
|
+
for (const f of dimFiles.slice(0, 10)) {
|
|
136
|
+
allTypes.push(...extractTypes(f.content || ''));
|
|
137
|
+
allSources.push(f.relativePath || f.name);
|
|
138
|
+
allImports.push(...extractImports(f.content || '', lang));
|
|
139
|
+
}
|
|
140
|
+
// 如果没找到相关文件,用全部文件兜底
|
|
141
|
+
if (allTypes.length === 0 && files) {
|
|
142
|
+
for (const f of files.slice(0, 5)) {
|
|
143
|
+
allTypes.push(...extractTypes(f.content || ''));
|
|
144
|
+
allSources.push(f.relativePath || f.name);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
const uniqueTypes = [...new Set(allTypes)].slice(0, 8);
|
|
148
|
+
const uniqueSources = [...new Set(allSources)].slice(0, 5);
|
|
149
|
+
const uniqueImports = [...new Set(allImports)].slice(0, 5);
|
|
150
|
+
// 为每个维度生成 3 个候选
|
|
151
|
+
const templates = getDimensionTemplates(dimId, dimLabel, uniqueTypes, uniqueSources, lang, projectName, astStats);
|
|
152
|
+
for (const tpl of templates.slice(0, 3)) {
|
|
153
|
+
candidates.push({
|
|
154
|
+
...tpl,
|
|
155
|
+
headers: uniqueImports,
|
|
156
|
+
sourceRefs: uniqueSources.slice(0, 3),
|
|
157
|
+
reasoning: {
|
|
158
|
+
whyStandard: `基于 ${projectName} 项目 ${dimFiles.length} 个相关文件的代码分析(Mock 模式自动生成)`,
|
|
159
|
+
sources: uniqueSources.slice(0, 3),
|
|
160
|
+
confidence: 0.7,
|
|
161
|
+
},
|
|
162
|
+
tags: ['mock-generated', dimId, lang],
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
return candidates;
|
|
166
|
+
}
|
|
167
|
+
/** 根据维度 ID 返回候选模板 */
|
|
168
|
+
function getDimensionTemplates(dimId, dimLabel, types, sources, lang, projectName, ast) {
|
|
169
|
+
const typeList = types.length > 0 ? types.slice(0, 3).join('、') : '核心模块';
|
|
170
|
+
const typeFirst = types[0] || 'AppModule';
|
|
171
|
+
const srcFirst = sources[0] || 'Sources/Main.swift';
|
|
172
|
+
const base = {
|
|
173
|
+
language: lang,
|
|
174
|
+
knowledgeType: dimId,
|
|
175
|
+
};
|
|
176
|
+
switch (dimId) {
|
|
177
|
+
case 'architecture':
|
|
178
|
+
return [
|
|
179
|
+
{
|
|
180
|
+
...base,
|
|
181
|
+
title: `${projectName} 分层架构模式`,
|
|
182
|
+
description: `项目采用分层架构,包含 ${ast.classes} 个类、${ast.protocols} 个协议`,
|
|
183
|
+
trigger: `@${toKebab(projectName)}-layered-arch`,
|
|
184
|
+
kind: 'pattern',
|
|
185
|
+
category: 'Architecture',
|
|
186
|
+
topicHint: 'architecture',
|
|
187
|
+
content: {
|
|
188
|
+
markdown: `### ${projectName} 分层架构\n\n项目基于分层架构设计,核心类型包括 ${typeList}。\n\n**层次结构**:\n- 表现层: View/Controller\n- 业务层: Service/Manager\n- 数据层: Repository/Store\n\n**来源**: \`${srcFirst}\`\n\n> ⚠️ 此条目由 Mock AI 基于代码结构自动生成`,
|
|
189
|
+
rationale: `分层架构是 ${projectName} 的核心设计决策,确保模块间关注点分离`,
|
|
190
|
+
},
|
|
191
|
+
coreCode: `// ${lang === 'swift' ? 'protocol' : 'interface'} ${typeFirst}Service { ... }`,
|
|
192
|
+
doClause: `Follow the layered architecture with ${typeFirst} as the core service boundary`,
|
|
193
|
+
dontClause: 'Do not bypass service layer to access data layer directly',
|
|
194
|
+
whenClause: 'When adding new features or modules to the project',
|
|
195
|
+
usageGuide: `### 使用指南\n\n遵循 ${projectName} 的分层架构进行模块设计。`,
|
|
196
|
+
},
|
|
197
|
+
{
|
|
198
|
+
...base,
|
|
199
|
+
title: `${typeFirst} 依赖注入约定`,
|
|
200
|
+
description: `${typeFirst} 等核心类型通过依赖注入管理生命周期`,
|
|
201
|
+
trigger: `@${toKebab(typeFirst)}-di-pattern`,
|
|
202
|
+
kind: 'pattern',
|
|
203
|
+
category: 'Architecture',
|
|
204
|
+
topicHint: 'architecture',
|
|
205
|
+
content: {
|
|
206
|
+
markdown: `### 依赖注入约定\n\n${projectName} 使用依赖注入管理 ${typeList} 等组件的生命周期。\n\n**来源**: \`${srcFirst}\`\n\n> ⚠️ Mock AI 自动生成`,
|
|
207
|
+
rationale: '依赖注入提高可测试性和模块解耦',
|
|
208
|
+
},
|
|
209
|
+
coreCode: `${lang === 'swift' ? `class ${typeFirst} {\n init(service: Service) { }\n}` : `class ${typeFirst} {\n constructor(private service: Service) {}\n}`}`,
|
|
210
|
+
doClause: `Use constructor injection for ${typeFirst} dependencies`,
|
|
211
|
+
dontClause: 'Do not use service locator or global singletons',
|
|
212
|
+
whenClause: `When creating or modifying ${typeFirst} and its dependencies`,
|
|
213
|
+
usageGuide: `### 使用指南\n\n通过构造器注入依赖项。`,
|
|
214
|
+
},
|
|
215
|
+
{
|
|
216
|
+
...base,
|
|
217
|
+
title: `${projectName} 模块通信约定`,
|
|
218
|
+
description: `模块间通过协议/接口进行通信,避免直接耦合`,
|
|
219
|
+
trigger: `@${toKebab(projectName)}-module-comm`,
|
|
220
|
+
kind: 'rule',
|
|
221
|
+
category: 'Architecture',
|
|
222
|
+
topicHint: 'architecture',
|
|
223
|
+
content: {
|
|
224
|
+
markdown: `### 模块通信\n\n${projectName} 的模块通信遵循接口隔离原则,${ast.protocols} 个协议定义了清晰的边界。\n\n> ⚠️ Mock AI 自动生成`,
|
|
225
|
+
rationale: '接口隔离确保模块可独立演进和测试',
|
|
226
|
+
},
|
|
227
|
+
coreCode: `${lang === 'swift' ? `protocol ${typeFirst}Protocol {\n func execute() async\n}` : `interface I${typeFirst} {\n execute(): Promise<void>\n}`}`,
|
|
228
|
+
doClause: 'Define protocols/interfaces for all cross-module communication',
|
|
229
|
+
dontClause: 'Do not import concrete implementations across module boundaries',
|
|
230
|
+
whenClause: 'When modules need to communicate or share data',
|
|
231
|
+
usageGuide: `### 使用指南\n\n定义协议作为模块间通信契约。`,
|
|
232
|
+
},
|
|
233
|
+
];
|
|
234
|
+
case 'code-pattern':
|
|
235
|
+
return [
|
|
236
|
+
{
|
|
237
|
+
...base,
|
|
238
|
+
title: `${typeFirst} 扩展方法约定`,
|
|
239
|
+
description: `使用扩展方法为 ${typeFirst} 添加功能,保持核心类型精简`,
|
|
240
|
+
trigger: `@${toKebab(typeFirst)}-extension-pattern`,
|
|
241
|
+
kind: 'pattern',
|
|
242
|
+
category: 'Tool',
|
|
243
|
+
topicHint: 'conventions',
|
|
244
|
+
content: {
|
|
245
|
+
markdown: `### 扩展方法约定\n\n${projectName} 广泛使用扩展方法组织代码,${typeList} 等类型均采用此模式。\n\n**来源**: \`${srcFirst}\`\n\n> ⚠️ Mock AI 自动生成`,
|
|
246
|
+
rationale: '扩展方法使核心类型保持精简,增强可读性',
|
|
247
|
+
},
|
|
248
|
+
coreCode: `${lang === 'swift' ? `extension ${typeFirst} {\n func helper() { }\n}` : `// ${typeFirst}.extensions.ts`}`,
|
|
249
|
+
doClause: `Group related functionality in ${lang === 'swift' ? 'extensions' : 'utility modules'}`,
|
|
250
|
+
dontClause: 'Do not bloat core types with unrelated methods',
|
|
251
|
+
whenClause: `When adding utility or convenience methods to ${typeFirst}`,
|
|
252
|
+
usageGuide: `### 使用指南\n\n按功能分组创建扩展文件。`,
|
|
253
|
+
},
|
|
254
|
+
{
|
|
255
|
+
...base,
|
|
256
|
+
title: `${projectName} 类型安全惯例`,
|
|
257
|
+
description: `项目统一使用强类型和类型守卫确保安全`,
|
|
258
|
+
trigger: `@${toKebab(projectName)}-type-safety`,
|
|
259
|
+
kind: 'rule',
|
|
260
|
+
category: 'Tool',
|
|
261
|
+
topicHint: 'conventions',
|
|
262
|
+
content: {
|
|
263
|
+
markdown: `### 类型安全\n\n${projectName} 强制类型安全,包含 ${ast.classes} 个类和 ${ast.protocols} 个协议定义。\n\n> ⚠️ Mock AI 自动生成`,
|
|
264
|
+
rationale: '类型安全减少运行时错误',
|
|
265
|
+
},
|
|
266
|
+
coreCode: `${lang === 'swift' ? 'guard let value = optional else { return }' : 'if (value === undefined) { return; }'}`,
|
|
267
|
+
doClause: 'Use type guards and optional binding for safe access',
|
|
268
|
+
dontClause: 'Do not use force unwrapping or type casting without checks',
|
|
269
|
+
whenClause: 'When handling optional values or type conversions',
|
|
270
|
+
usageGuide: `### 使用指南\n\n始终使用安全的类型转换。`,
|
|
271
|
+
},
|
|
272
|
+
{
|
|
273
|
+
...base,
|
|
274
|
+
title: `${projectName} 命名约定`,
|
|
275
|
+
description: `文件和类型命名遵循一致的约定`,
|
|
276
|
+
trigger: `@${toKebab(projectName)}-naming-conventions`,
|
|
277
|
+
kind: 'rule',
|
|
278
|
+
category: 'Tool',
|
|
279
|
+
topicHint: 'conventions',
|
|
280
|
+
content: {
|
|
281
|
+
markdown: `### 命名约定\n\n${projectName} 使用一致的命名风格。类型: PascalCase, 方法/属性: camelCase。\n\n> ⚠️ Mock AI 自动生成`,
|
|
282
|
+
rationale: '统一命名提高代码可读性',
|
|
283
|
+
},
|
|
284
|
+
coreCode: `// ${typeFirst}.swift / ${typeFirst}.ts`,
|
|
285
|
+
doClause: 'Follow PascalCase for types and camelCase for members',
|
|
286
|
+
dontClause: 'Do not use abbreviations or inconsistent casing',
|
|
287
|
+
whenClause: 'When naming new types, methods, or properties',
|
|
288
|
+
usageGuide: `### 使用指南\n\n遵循项目既有命名风格。`,
|
|
289
|
+
},
|
|
290
|
+
];
|
|
291
|
+
default:
|
|
292
|
+
return [
|
|
293
|
+
{
|
|
294
|
+
...base,
|
|
295
|
+
title: `${projectName} ${dimLabel}实践`,
|
|
296
|
+
description: `${dimLabel}维度的最佳实践,基于 ${typeList} 等代码分析`,
|
|
297
|
+
trigger: `@${toKebab(projectName)}-${toKebab(dimLabel)}-practice`,
|
|
298
|
+
kind: 'pattern',
|
|
299
|
+
category: 'Tool',
|
|
300
|
+
topicHint: dimId.includes('network')
|
|
301
|
+
? 'networking'
|
|
302
|
+
: dimId.includes('ui')
|
|
303
|
+
? 'ui'
|
|
304
|
+
: 'conventions',
|
|
305
|
+
content: {
|
|
306
|
+
markdown: `### ${dimLabel}\n\n${projectName} 在 ${dimLabel} 方面的实践,涉及 ${typeList} 等核心类型。\n\n**文件统计**: ${ast.classes} 类, ${ast.protocols} 协议, ${ast.functions} 函数\n\n**来源**: \`${srcFirst}\`\n\n> ⚠️ Mock AI 自动生成`,
|
|
307
|
+
rationale: `${dimLabel}是项目质量的重要维度`,
|
|
308
|
+
},
|
|
309
|
+
coreCode: `// See ${srcFirst}`,
|
|
310
|
+
doClause: `Follow established ${dimLabel} patterns in the project`,
|
|
311
|
+
dontClause: `Do not deviate from the project's ${dimLabel} conventions`,
|
|
312
|
+
whenClause: `When working on ${dimLabel}-related code`,
|
|
313
|
+
usageGuide: `### 使用指南\n\n遵循项目的 ${dimLabel} 约定。`,
|
|
314
|
+
},
|
|
315
|
+
{
|
|
316
|
+
...base,
|
|
317
|
+
title: `${typeFirst} ${dimLabel}约定`,
|
|
318
|
+
description: `${typeFirst} 相关的 ${dimLabel} 约定`,
|
|
319
|
+
trigger: `@${toKebab(typeFirst)}-${toKebab(dimLabel)}`,
|
|
320
|
+
kind: 'rule',
|
|
321
|
+
category: 'Tool',
|
|
322
|
+
topicHint: dimId.includes('network') ? 'networking' : 'conventions',
|
|
323
|
+
content: {
|
|
324
|
+
markdown: `### ${typeFirst} ${dimLabel}\n\n${typeFirst} 遵循的 ${dimLabel} 约定。\n\n> ⚠️ Mock AI 自动生成`,
|
|
325
|
+
rationale: `基于 ${typeFirst} 的实际代码模式`,
|
|
326
|
+
},
|
|
327
|
+
coreCode: `// ${typeFirst} — ${dimLabel}`,
|
|
328
|
+
doClause: `Apply ${dimLabel} patterns consistent with ${typeFirst}`,
|
|
329
|
+
dontClause: `Do not introduce inconsistent ${dimLabel} approaches`,
|
|
330
|
+
whenClause: `When modifying ${typeFirst} or related components`,
|
|
331
|
+
usageGuide: `### 使用指南\n\n参考 ${typeFirst} 的既有实现。`,
|
|
332
|
+
},
|
|
333
|
+
{
|
|
334
|
+
...base,
|
|
335
|
+
title: `${projectName} ${dimLabel}检查清单`,
|
|
336
|
+
description: `${dimLabel}方面的代码审查清单`,
|
|
337
|
+
trigger: `@${toKebab(projectName)}-${toKebab(dimLabel)}-checklist`,
|
|
338
|
+
kind: 'fact',
|
|
339
|
+
category: 'Tool',
|
|
340
|
+
topicHint: 'conventions',
|
|
341
|
+
content: {
|
|
342
|
+
markdown: `### ${dimLabel} 检查清单\n\n1. 遵循项目既有模式\n2. 确保类型安全\n3. 添加适当的错误处理\n4. 保持代码一致性\n\n> ⚠️ Mock AI 自动生成`,
|
|
343
|
+
rationale: `${dimLabel}检查清单帮助保持代码质量`,
|
|
344
|
+
},
|
|
345
|
+
coreCode: `// ${dimLabel} checklist applied`,
|
|
346
|
+
doClause: `Review code against the ${dimLabel} checklist before committing`,
|
|
347
|
+
dontClause: `Do not skip ${dimLabel} review for shortcuts`,
|
|
348
|
+
whenClause: `During code review for ${dimLabel}-related changes`,
|
|
349
|
+
usageGuide: `### 使用指南\n\n在代码审查时参考此清单。`,
|
|
350
|
+
},
|
|
351
|
+
];
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
// ── Mock Pipeline 入口 ────────────────────────────────────────
|
|
355
|
+
/**
|
|
356
|
+
* fillDimensionsMock — Mock AI 轻量管线
|
|
357
|
+
*
|
|
358
|
+
* 利用 Phase 1-4 的真实数据(AST、文件列表、Panorama)自动生成候选知识,
|
|
359
|
+
* 不调用任何 AI API,但走完 submit → dimension_complete 的完整流程。
|
|
360
|
+
*/
|
|
361
|
+
export async function fillDimensionsMock(view, dimensions) {
|
|
362
|
+
const { snapshot, projectRoot } = view;
|
|
363
|
+
const ctx = view.ctx;
|
|
364
|
+
const emitter = new BootstrapEventEmitter(ctx.container);
|
|
365
|
+
const projectName = path.basename(projectRoot);
|
|
366
|
+
const primaryLang = snapshot.language.primaryLang ?? 'unknown';
|
|
367
|
+
const astStats = extractAstStats(snapshot.ast);
|
|
368
|
+
const allFiles = snapshot.allFiles;
|
|
369
|
+
const targetFileMap = view.targetFileMap;
|
|
370
|
+
const repFiles = getRepresentativeFiles(allFiles, targetFileMap);
|
|
371
|
+
logger.info(`[MockPipeline] ═══ Starting Mock bootstrap — ${dimensions.length} dimensions, ` +
|
|
372
|
+
`${allFiles?.length || 0} files, lang=${primaryLang}`);
|
|
373
|
+
emitter.emitProgress('bootstrap:mock-mode', {
|
|
374
|
+
message: '🧪 Mock AI 模式 — 基于代码结构自动生成知识候选(非 AI 深度分析)',
|
|
375
|
+
mockMode: true,
|
|
376
|
+
});
|
|
377
|
+
const knowledgeService = ctx.container.get('knowledgeService');
|
|
378
|
+
let totalCreated = 0;
|
|
379
|
+
for (const dim of dimensions) {
|
|
380
|
+
const dimStartTime = Date.now();
|
|
381
|
+
const dimLabel = dim.label ?? dim.id;
|
|
382
|
+
emitter.emitProgress('bootstrap:dimension-start', {
|
|
383
|
+
dimensionId: dim.id,
|
|
384
|
+
dimensionLabel: dimLabel,
|
|
385
|
+
mockMode: true,
|
|
386
|
+
});
|
|
387
|
+
logger.info(`[MockPipeline] ── Dimension "${dim.id}" (${dimLabel}) ──`);
|
|
388
|
+
// 生成候选
|
|
389
|
+
const candidates = generateDimensionCandidates(dim.id, dimLabel, allFiles, primaryLang, projectName, astStats, repFiles);
|
|
390
|
+
const createdIds = [];
|
|
391
|
+
for (const candidate of candidates) {
|
|
392
|
+
try {
|
|
393
|
+
const entry = await knowledgeService.create({
|
|
394
|
+
...candidate,
|
|
395
|
+
source: 'mock-bootstrap',
|
|
396
|
+
}, { userId: 'mock-ai' });
|
|
397
|
+
createdIds.push(entry.id);
|
|
398
|
+
totalCreated++;
|
|
399
|
+
// 尝试自动评分(非关键路径)
|
|
400
|
+
try {
|
|
401
|
+
await knowledgeService.updateQuality?.(entry.id, { userId: 'mock-ai' });
|
|
402
|
+
}
|
|
403
|
+
catch {
|
|
404
|
+
/* best effort */
|
|
405
|
+
}
|
|
406
|
+
logger.info(`[MockPipeline] ✅ Created: "${candidate.title}" → ${entry.id}`);
|
|
407
|
+
}
|
|
408
|
+
catch (err) {
|
|
409
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
410
|
+
logger.warn(`[MockPipeline] ⚠️ Failed to create "${candidate.title}": ${msg}`);
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
const durationMs = Date.now() - dimStartTime;
|
|
414
|
+
emitter.emitDimensionComplete(dim.id, {
|
|
415
|
+
type: 'candidate',
|
|
416
|
+
extracted: candidates.length,
|
|
417
|
+
created: createdIds.length,
|
|
418
|
+
status: 'mock-pipeline-complete',
|
|
419
|
+
degraded: false,
|
|
420
|
+
durationMs,
|
|
421
|
+
toolCallCount: 0,
|
|
422
|
+
source: 'mock-pipeline',
|
|
423
|
+
});
|
|
424
|
+
logger.info(`[MockPipeline] ✅ "${dim.id}": ${createdIds.length}/${candidates.length} candidates, ${durationMs}ms`);
|
|
425
|
+
}
|
|
426
|
+
emitter.emitProgress('bootstrap:mock-complete', {
|
|
427
|
+
message: `🧪 Mock Bootstrap 完成: ${totalCreated} 个候选知识已生成`,
|
|
428
|
+
totalCreated,
|
|
429
|
+
mockMode: true,
|
|
430
|
+
});
|
|
431
|
+
logger.info(`[MockPipeline] ═══ Mock bootstrap complete — ${totalCreated} candidates from ${dimensions.length} dimensions`);
|
|
432
|
+
}
|
|
@@ -32,6 +32,7 @@ import { clearCheckpoints, loadCheckpoints, saveDimensionCheckpoint } from './ch
|
|
|
32
32
|
import { buildTierReflection, DIMENSION_CONFIGS_V3, getFullDimensionConfig, } from './dimension-configs.js';
|
|
33
33
|
import { DimensionContext, parseDimensionDigest } from './dimension-context.js';
|
|
34
34
|
import { IncrementalBootstrap } from './IncrementalBootstrap.js';
|
|
35
|
+
import { fillDimensionsMock } from './mock-pipeline.js';
|
|
35
36
|
import { TierScheduler } from './tier-scheduler.js';
|
|
36
37
|
const logger = Logger.getInstance();
|
|
37
38
|
// ──────────────────────────────────────────────────────────────────
|
|
@@ -116,21 +117,22 @@ export async function fillDimensionsV3(view, dimensions) {
|
|
|
116
117
|
logger.info(`[Insight-v3] ═══ fillDimensionsV3 entered — ${isIncremental ? 'INCREMENTAL' : 'FULL'} pipeline`);
|
|
117
118
|
let allFiles = snapshot.allFiles;
|
|
118
119
|
// ═══════════════════════════════════════════════════════════
|
|
119
|
-
// Step 0: AI 可用性检查 (v7.2: 使用 AgentFactory)
|
|
120
|
+
// Step 0: AI 可用性检查 (v7.2: 使用 AgentFactory + AiProviderManager)
|
|
120
121
|
// ═══════════════════════════════════════════════════════════
|
|
121
122
|
let agentFactory = null;
|
|
123
|
+
let isMockMode = false;
|
|
122
124
|
try {
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
if (!
|
|
127
|
-
agentFactory =
|
|
125
|
+
// 通过 AiProviderManager 统一检查 mock 模式
|
|
126
|
+
const manager = ctx.container.singletons?._aiProviderManager;
|
|
127
|
+
isMockMode = manager?.isMock ?? false;
|
|
128
|
+
if (!isMockMode) {
|
|
129
|
+
agentFactory = ctx.container.get('agentFactory');
|
|
128
130
|
}
|
|
129
131
|
}
|
|
130
132
|
catch {
|
|
131
133
|
/* not available */
|
|
132
134
|
}
|
|
133
|
-
if (!agentFactory) {
|
|
135
|
+
if (!agentFactory && !isMockMode) {
|
|
134
136
|
logger.error('[Insight-v3] AI Provider not available — bootstrap requires AI');
|
|
135
137
|
emitter.emitProgress('bootstrap:ai-unavailable', {
|
|
136
138
|
message: 'AI Provider 不可用,Bootstrap 需要 AI 才能运行。请先配置 AI Provider(如 OpenAI、Anthropic 等)后重试。',
|
|
@@ -140,6 +142,12 @@ export async function fillDimensionsV3(view, dimensions) {
|
|
|
140
142
|
}
|
|
141
143
|
return;
|
|
142
144
|
}
|
|
145
|
+
// Mock AI: 走 mock-pipeline 轻量管线
|
|
146
|
+
if (isMockMode) {
|
|
147
|
+
logger.info('[Insight-v3] Mock AI detected — routing to mock-pipeline');
|
|
148
|
+
await fillDimensionsMock(view, dimensions);
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
143
151
|
// ═══════════════════════════════════════════════════════════
|
|
144
152
|
// Step 0.5: 构建 ProjectGraph
|
|
145
153
|
// ═══════════════════════════════════════════════════════════
|
|
@@ -579,7 +587,7 @@ export async function fillDimensionsV3(view, dimensions) {
|
|
|
579
587
|
modules: Object.keys(targetFileMap || {}),
|
|
580
588
|
},
|
|
581
589
|
// ── 引擎增强参数 (PipelineStrategy → reactLoop 透传) ──
|
|
582
|
-
contextWindow: agentFactory
|
|
590
|
+
contextWindow: agentFactory?.createContextWindow({ isSystem: true }),
|
|
583
591
|
// B1 fix: 分析阶段使用 analyst 策略 (SCAN→EXPLORE→VERIFY→SUMMARIZE)
|
|
584
592
|
// 而非 bootstrap (EXPLORE→PRODUCE→SUMMARIZE),避免 PRODUCE nudge 浪费轮次
|
|
585
593
|
// B3 fix: 透传完整 ANALYST_BUDGET (searchBudget/maxSubmits/softSubmitLimit/idleRoundsToExit)
|
|
@@ -21,6 +21,14 @@ export async function bootstrapRefine(ctx, args) {
|
|
|
21
21
|
errorCode: 'MISSING_AI_PROVIDER',
|
|
22
22
|
});
|
|
23
23
|
}
|
|
24
|
+
// Mock 模式下跳过 AI 润色
|
|
25
|
+
if (aiProvider.name === 'mock') {
|
|
26
|
+
return envelope({
|
|
27
|
+
success: false,
|
|
28
|
+
message: 'AI Provider 未配置,当前为 Mock 模式。请先配置 API Key。',
|
|
29
|
+
errorCode: 'MOCK_MODE',
|
|
30
|
+
});
|
|
31
|
+
}
|
|
24
32
|
// 接入 BootstrapTaskManager 双通道推送 refine:* 事件
|
|
25
33
|
let onProgress = null;
|
|
26
34
|
try {
|
|
@@ -62,6 +62,15 @@ export declare function bootstrapExternal(ctx: McpContext): Promise<{
|
|
|
62
62
|
clearedTables: number;
|
|
63
63
|
dbCleared: boolean;
|
|
64
64
|
errors: string[];
|
|
65
|
+
trash: {
|
|
66
|
+
folder: string;
|
|
67
|
+
movedItems: number;
|
|
68
|
+
dbSnapshotRows: number;
|
|
69
|
+
} | null;
|
|
70
|
+
purgedTrash: {
|
|
71
|
+
count: number;
|
|
72
|
+
freedBytes: number;
|
|
73
|
+
} | null;
|
|
65
74
|
};
|
|
66
75
|
} | null;
|
|
67
76
|
meta: {
|
|
@@ -133,6 +133,8 @@ export async function bootstrapExternal(ctx) {
|
|
|
133
133
|
clearedTables: cleanupResult.clearedTables.length,
|
|
134
134
|
dbCleared: true,
|
|
135
135
|
errors: cleanupResult.errors,
|
|
136
|
+
trash: cleanupResult.trash ?? null,
|
|
137
|
+
purgedTrash: cleanupResult.purgedTrash ?? null,
|
|
136
138
|
},
|
|
137
139
|
...briefing,
|
|
138
140
|
},
|
|
@@ -223,6 +223,8 @@ export async function bootstrapKnowledge(ctx, args) {
|
|
|
223
223
|
clearedTables: cleanupResult.clearedTables.length,
|
|
224
224
|
dbCleared: true,
|
|
225
225
|
errors: cleanupResult.errors,
|
|
226
|
+
trash: cleanupResult.trash ?? null,
|
|
227
|
+
purgedTrash: cleanupResult.purgedTrash ?? null,
|
|
226
228
|
},
|
|
227
229
|
report,
|
|
228
230
|
targets: targetsSummary ||
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
* autosnippet_bootstrap 已迁移到 bootstrap-external.js(外部 Agent 路径)。
|
|
10
10
|
*/
|
|
11
11
|
import { getRequiredFieldsDescription } from '#domain/knowledge/FieldSpec.js';
|
|
12
|
+
import { getDeveloperIdentity } from '#shared/developer-identity.js';
|
|
12
13
|
import { envelope } from '../envelope.js';
|
|
13
14
|
import * as browseHandlers from './browse.js';
|
|
14
15
|
import * as guardHandlers from './guard.js';
|
|
@@ -285,7 +286,7 @@ export async function enhancedSubmitKnowledge(ctx, args) {
|
|
|
285
286
|
skipConsolidation,
|
|
286
287
|
supersedes,
|
|
287
288
|
existingTitles,
|
|
288
|
-
userId:
|
|
289
|
+
userId: getDeveloperIdentity(),
|
|
289
290
|
},
|
|
290
291
|
});
|
|
291
292
|
// ── Step 4: Bootstrap session 追踪 ──
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
*/
|
|
17
17
|
import Logger from '#infra/logging/Logger.js';
|
|
18
18
|
import { BootstrapEventEmitter } from '#service/bootstrap/BootstrapEventEmitter.js';
|
|
19
|
+
import { getDeveloperIdentity } from '#shared/developer-identity.js';
|
|
19
20
|
import { envelope } from '../envelope.js';
|
|
20
21
|
import { saveDimensionCheckpoint } from './bootstrap/pipeline/checkpoint.js';
|
|
21
22
|
import { BOOTSTRAP_COMPLETE_ACTIONS } from './bootstrap/shared/dimension-text.js';
|
|
@@ -160,7 +161,7 @@ export async function dimensionComplete(ctx, args) {
|
|
|
160
161
|
await knowledgeService.update(recipeId, {
|
|
161
162
|
category: dimensionId,
|
|
162
163
|
tags: newTags,
|
|
163
|
-
}, { userId:
|
|
164
|
+
}, { userId: getDeveloperIdentity() });
|
|
164
165
|
recipesBound++;
|
|
165
166
|
}
|
|
166
167
|
}
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
*
|
|
13
13
|
* @module handlers/evolve-external
|
|
14
14
|
*/
|
|
15
|
+
import { getDeveloperIdentity } from '#shared/developer-identity.js';
|
|
15
16
|
import { envelope } from '../envelope.js';
|
|
16
17
|
// ── 主入口 ─────────────────────────────────────────────────
|
|
17
18
|
export async function evolveExternal(ctx, args) {
|
|
@@ -121,7 +122,7 @@ export async function evolveExternal(ctx, args) {
|
|
|
121
122
|
// Supervisor 拒绝(可能状态不允许直接转 deprecated),回退到 KnowledgeService
|
|
122
123
|
if (knowledgeService) {
|
|
123
124
|
await knowledgeService.deprecate(decision.recipeId, reason, {
|
|
124
|
-
userId:
|
|
125
|
+
userId: getDeveloperIdentity(),
|
|
125
126
|
});
|
|
126
127
|
}
|
|
127
128
|
else {
|
|
@@ -135,7 +136,9 @@ export async function evolveExternal(ctx, args) {
|
|
|
135
136
|
}
|
|
136
137
|
else if (knowledgeService) {
|
|
137
138
|
// P3: 添加 await
|
|
138
|
-
await knowledgeService.deprecate(decision.recipeId, reason, {
|
|
139
|
+
await knowledgeService.deprecate(decision.recipeId, reason, {
|
|
140
|
+
userId: getDeveloperIdentity(),
|
|
141
|
+
});
|
|
139
142
|
}
|
|
140
143
|
else {
|
|
141
144
|
result.errors.push({
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
* submitKnowledge, submitKnowledgeBatch, knowledgeLifecycle
|
|
4
4
|
*/
|
|
5
5
|
import { UnifiedValidator } from '#domain/knowledge/UnifiedValidator.js';
|
|
6
|
+
import { getDeveloperIdentity } from '#shared/developer-identity.js';
|
|
6
7
|
import { resolveProjectRoot } from '#shared/resolveProjectRoot.js';
|
|
7
8
|
import { envelope } from '../envelope.js';
|
|
8
9
|
// ─── 限流 ──────────────────────────────────────────────────
|
|
@@ -69,7 +70,7 @@ export async function submitKnowledge(ctx, args) {
|
|
|
69
70
|
const service = ctx.container.get('knowledgeService');
|
|
70
71
|
// V3 字段增强
|
|
71
72
|
const enrichedData = _enrichToV3(args, ctx.container);
|
|
72
|
-
const entry = await service.create(enrichedData, { userId:
|
|
73
|
+
const entry = await service.create(enrichedData, { userId: getDeveloperIdentity() });
|
|
73
74
|
// ── QualityScorer 自动评分(R9: create 后置执行)──
|
|
74
75
|
try {
|
|
75
76
|
await service.updateQuality(entry.id, { userId: 'mcp' });
|
|
@@ -193,10 +194,10 @@ export async function submitKnowledgeBatch(ctx, args) {
|
|
|
193
194
|
}
|
|
194
195
|
try {
|
|
195
196
|
const itemData = _enrichToV3({ ...items[i], source }, ctx.container);
|
|
196
|
-
const entry = await service.create(itemData, { userId:
|
|
197
|
+
const entry = await service.create(itemData, { userId: getDeveloperIdentity() });
|
|
197
198
|
// ── QualityScorer 自动评分(R9: create 后置执行)──
|
|
198
199
|
try {
|
|
199
|
-
await service.updateQuality(entry.id, { userId:
|
|
200
|
+
await service.updateQuality(entry.id, { userId: getDeveloperIdentity() });
|
|
200
201
|
}
|
|
201
202
|
catch {
|
|
202
203
|
/* best effort — 不阻塞批量提交 */
|
|
@@ -269,7 +270,7 @@ export async function knowledgeLifecycle(ctx, args) {
|
|
|
269
270
|
throw new Error(`[PERMISSION_DENIED] 外部 Agent 不允许执行 "${action}" 操作,仅支持: reactivate。发布、废弃等操作请在 Dashboard 中完成。提交新知识请使用 autosnippet_submit_knowledge 工具。`);
|
|
270
271
|
}
|
|
271
272
|
const service = ctx.container.get('knowledgeService');
|
|
272
|
-
const context = { userId:
|
|
273
|
+
const context = { userId: getDeveloperIdentity() };
|
|
273
274
|
const entry = await service.reactivate(id, context);
|
|
274
275
|
return envelope({
|
|
275
276
|
success: true,
|