autosnippet 3.0.11 → 3.0.13
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/cli.js +64 -1
- package/config/default.json +9 -0
- package/dashboard/dist/assets/{index-I2ySoCmF.js → index-Bnm26ulL.js} +47 -47
- package/dashboard/dist/index.html +1 -1
- package/lib/cli/SetupService.js +92 -5
- package/lib/cli/UpgradeService.js +14 -5
- package/lib/core/discovery/GenericDiscoverer.js +4 -28
- package/lib/external/mcp/handlers/bootstrap/base-dimensions.js +246 -0
- package/lib/external/mcp/handlers/bootstrap/pipeline/checkpoint.js +80 -0
- package/lib/external/mcp/handlers/bootstrap/pipeline/dimension-configs.js +275 -0
- package/lib/external/mcp/handlers/bootstrap/pipeline/noAiFallback.js +600 -0
- package/lib/external/mcp/handlers/bootstrap/pipeline/orchestrator.js +125 -342
- package/lib/external/mcp/handlers/bootstrap/refine.js +362 -0
- package/lib/external/mcp/handlers/bootstrap.js +6 -590
- package/lib/external/mcp/handlers/browse.js +119 -9
- package/lib/external/mcp/handlers/guard.js +25 -6
- package/lib/external/mcp/handlers/search.js +56 -24
- package/lib/http/routes/guardRules.js +9 -17
- package/lib/injection/ServiceContainer.js +12 -3
- package/lib/platform/ios/xcode/XcodeImportResolver.js +434 -0
- package/lib/platform/ios/xcode/XcodeIntegration.js +40 -659
- package/lib/platform/ios/xcode/XcodeWriteUtils.js +220 -0
- package/lib/service/chat/ChatAgent.js +39 -418
- package/lib/service/chat/ChatAgentPrompts.js +149 -0
- package/lib/service/chat/ChatAgentTasks.js +297 -0
- package/lib/service/chat/tools/_shared.js +61 -0
- package/lib/service/chat/tools/ai-analysis.js +284 -0
- package/lib/service/chat/tools/ast-graph.js +681 -0
- package/lib/service/chat/tools/composite.js +496 -0
- package/lib/service/chat/tools/guard.js +265 -0
- package/lib/service/chat/tools/index.js +250 -0
- package/lib/service/chat/tools/infrastructure.js +222 -0
- package/lib/service/chat/tools/knowledge-graph.js +234 -0
- package/lib/service/chat/tools/lifecycle.js +469 -0
- package/lib/service/chat/tools/project-access.js +923 -0
- package/lib/service/chat/tools/query.js +264 -0
- package/lib/service/chat/tools.js +14 -3994
- package/lib/service/cursor/AgentInstructionsGenerator.js +395 -0
- package/lib/service/cursor/CursorDeliveryPipeline.js +70 -11
- package/lib/service/cursor/FileProtection.js +116 -0
- package/lib/service/cursor/KnowledgeCompressor.js +61 -11
- package/lib/service/cursor/SkillsSyncer.js +5 -3
- package/lib/service/cursor/TopicClassifier.js +19 -3
- package/lib/service/guard/ExclusionManager.js +26 -2
- package/lib/service/guard/GuardCheckEngine.js +38 -370
- package/lib/service/guard/GuardCodeChecks.js +362 -0
- package/lib/service/guard/GuardCrossFileChecks.js +307 -0
- package/lib/service/guard/GuardPatternUtils.js +180 -0
- package/lib/service/guard/GuardService.js +80 -38
- package/lib/service/module/ModuleService.js +1 -0
- package/lib/service/search/SearchEngine.js +10 -2
- package/lib/service/wiki/WikiGenerator.js +226 -1532
- package/lib/service/wiki/WikiRenderers.js +1878 -0
- package/lib/service/wiki/WikiUtils.js +907 -0
- package/lib/shared/LanguageService.js +299 -0
- package/package.json +1 -1
|
@@ -22,348 +22,14 @@ import { WorkingMemory } from '../../../../../service/chat/WorkingMemory.js';
|
|
|
22
22
|
import { DimensionContext, parseDimensionDigest } from './dimension-context.js';
|
|
23
23
|
import { EpisodicMemory } from './EpisodicMemory.js';
|
|
24
24
|
import { IncrementalBootstrap } from './IncrementalBootstrap.js';
|
|
25
|
+
import { runNoAiFallback } from './noAiFallback.js';
|
|
25
26
|
import { ToolResultCache } from './ToolResultCache.js';
|
|
26
27
|
import { TierScheduler } from './tier-scheduler.js';
|
|
28
|
+
import { saveDimensionCheckpoint, loadCheckpoints, clearCheckpoints } from './checkpoint.js';
|
|
29
|
+
import { DIMENSION_CONFIGS_V3, buildTierReflection } from './dimension-configs.js';
|
|
27
30
|
|
|
28
31
|
const logger = Logger.getInstance();
|
|
29
32
|
|
|
30
|
-
// ──────────────────────────────────────────────────────────────────
|
|
31
|
-
// P3: 断点续传 — Checkpoint 存储/恢复
|
|
32
|
-
// ──────────────────────────────────────────────────────────────────
|
|
33
|
-
|
|
34
|
-
const CHECKPOINT_TTL_MS = 3600_000; // 1小时内有效
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* 保存维度级 checkpoint
|
|
38
|
-
* @param {string} projectRoot
|
|
39
|
-
* @param {string} sessionId
|
|
40
|
-
* @param {string} dimId
|
|
41
|
-
* @param {object} result — 维度执行结果
|
|
42
|
-
* @param {object} [digest] — DimensionDigest
|
|
43
|
-
*/
|
|
44
|
-
async function saveDimensionCheckpoint(projectRoot, sessionId, dimId, result, digest = null) {
|
|
45
|
-
try {
|
|
46
|
-
const checkpointDir = path.join(projectRoot, '.autosnippet', 'bootstrap-checkpoint');
|
|
47
|
-
await fs.mkdir(checkpointDir, { recursive: true });
|
|
48
|
-
await fs.writeFile(
|
|
49
|
-
path.join(checkpointDir, `${dimId}.json`),
|
|
50
|
-
JSON.stringify({ dimId, sessionId, ...result, digest, completedAt: Date.now() })
|
|
51
|
-
);
|
|
52
|
-
} catch (err) {
|
|
53
|
-
logger.warn(`[Bootstrap-v3] checkpoint save failed for "${dimId}": ${err.message}`);
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* 加载有效的 checkpoints
|
|
59
|
-
* @param {string} projectRoot
|
|
60
|
-
* @returns {Promise<Map<string, object>>} dimId → checkpoint data
|
|
61
|
-
*/
|
|
62
|
-
async function loadCheckpoints(projectRoot) {
|
|
63
|
-
const checkpoints = new Map();
|
|
64
|
-
try {
|
|
65
|
-
const checkpointDir = path.join(projectRoot, '.autosnippet', 'bootstrap-checkpoint');
|
|
66
|
-
const files = await fs.readdir(checkpointDir).catch(() => []);
|
|
67
|
-
const now = Date.now();
|
|
68
|
-
for (const file of files) {
|
|
69
|
-
if (!file.endsWith('.json')) {
|
|
70
|
-
continue;
|
|
71
|
-
}
|
|
72
|
-
try {
|
|
73
|
-
const content = await fs.readFile(path.join(checkpointDir, file), 'utf-8');
|
|
74
|
-
const data = JSON.parse(content);
|
|
75
|
-
if (data.completedAt && now - data.completedAt < CHECKPOINT_TTL_MS) {
|
|
76
|
-
checkpoints.set(data.dimId, data);
|
|
77
|
-
}
|
|
78
|
-
} catch {
|
|
79
|
-
/* skip corrupt checkpoint */
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
} catch {
|
|
83
|
-
/* checkpoint dir doesn't exist */
|
|
84
|
-
}
|
|
85
|
-
return checkpoints;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
/**
|
|
89
|
-
* 清理 checkpoint 目录
|
|
90
|
-
* @param {string} projectRoot
|
|
91
|
-
*/
|
|
92
|
-
async function clearCheckpoints(projectRoot) {
|
|
93
|
-
try {
|
|
94
|
-
const checkpointDir = path.join(projectRoot, '.autosnippet', 'bootstrap-checkpoint');
|
|
95
|
-
await fs.rm(checkpointDir, { recursive: true, force: true });
|
|
96
|
-
} catch {
|
|
97
|
-
/* ignore */
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
// ──────────────────────────────────────────────────────────────────
|
|
102
|
-
// v3.0 维度配置 (增加 focusAreas 用于 Analyst prompt)
|
|
103
|
-
// ──────────────────────────────────────────────────────────────────
|
|
104
|
-
|
|
105
|
-
const DIMENSION_CONFIGS_V3 = {
|
|
106
|
-
'project-profile': {
|
|
107
|
-
label: '项目概貌',
|
|
108
|
-
guide: '分析项目的整体结构、技术栈、模块划分和入口点。',
|
|
109
|
-
focusAreas: ['项目结构和模块划分', '技术栈和框架依赖', '核心入口点和启动流程'],
|
|
110
|
-
outputType: 'dual',
|
|
111
|
-
allowedKnowledgeTypes: ['architecture'],
|
|
112
|
-
},
|
|
113
|
-
'objc-deep-scan': {
|
|
114
|
-
label: '深度扫描(常量/Hook)',
|
|
115
|
-
guide: '扫描 #define 宏、extern/static 常量、Method Swizzling hook。',
|
|
116
|
-
focusAreas: [
|
|
117
|
-
'#define 值宏和函数宏',
|
|
118
|
-
'extern/static 常量定义',
|
|
119
|
-
'Method Swizzling hook 和 load/initialize 方法',
|
|
120
|
-
],
|
|
121
|
-
outputType: 'dual',
|
|
122
|
-
allowedKnowledgeTypes: ['code-standard', 'code-pattern'],
|
|
123
|
-
},
|
|
124
|
-
'category-scan': {
|
|
125
|
-
label: '基础类分类方法扫描',
|
|
126
|
-
guide: '扫描 Foundation/UIKit 的 Category/Extension 方法及其实现。',
|
|
127
|
-
focusAreas: [
|
|
128
|
-
'NSString/NSArray/NSDictionary 等基础类的 Category',
|
|
129
|
-
'UIView/UIColor/UIImage 等 UI 组件的 Category',
|
|
130
|
-
'各 Category 方法的使用场景和频率',
|
|
131
|
-
],
|
|
132
|
-
outputType: 'dual',
|
|
133
|
-
allowedKnowledgeTypes: ['code-standard', 'code-pattern'],
|
|
134
|
-
},
|
|
135
|
-
'code-standard': {
|
|
136
|
-
label: '代码规范',
|
|
137
|
-
guide: '分析项目的命名约定、注释风格、文件组织方式。',
|
|
138
|
-
focusAreas: [
|
|
139
|
-
'类名前缀和命名约定 (BD/BDUIKit 等)',
|
|
140
|
-
'方法签名风格和 API 命名',
|
|
141
|
-
'注释风格 (语言/格式/MARK 分段)',
|
|
142
|
-
'文件组织和目录规范',
|
|
143
|
-
],
|
|
144
|
-
outputType: 'dual',
|
|
145
|
-
allowedKnowledgeTypes: ['code-standard', 'code-style'],
|
|
146
|
-
},
|
|
147
|
-
architecture: {
|
|
148
|
-
label: '架构模式',
|
|
149
|
-
guide: '分析项目的分层架构、模块职责和依赖关系。',
|
|
150
|
-
focusAreas: [
|
|
151
|
-
'分层架构 (MVC/MVVM/其他)',
|
|
152
|
-
'模块间通信方式 (Protocol/Notification/Target-Action)',
|
|
153
|
-
'依赖管理和服务注册',
|
|
154
|
-
'模块边界约束',
|
|
155
|
-
],
|
|
156
|
-
outputType: 'dual',
|
|
157
|
-
allowedKnowledgeTypes: ['architecture', 'module-dependency', 'boundary-constraint'],
|
|
158
|
-
},
|
|
159
|
-
'code-pattern': {
|
|
160
|
-
label: '设计模式',
|
|
161
|
-
guide: '识别项目中使用的设计模式和架构模式。',
|
|
162
|
-
focusAreas: [
|
|
163
|
-
'创建型模式 (Singleton, Factory, Builder)',
|
|
164
|
-
'结构型模式 (Proxy, Adapter, Decorator, Composite)',
|
|
165
|
-
'行为型模式 (Observer, Strategy, Template Method, Delegate)',
|
|
166
|
-
'架构模式 (MVC/MVVM, Service Locator, Coordinator)',
|
|
167
|
-
],
|
|
168
|
-
outputType: 'candidate',
|
|
169
|
-
allowedKnowledgeTypes: ['code-pattern', 'code-relation', 'inheritance'],
|
|
170
|
-
},
|
|
171
|
-
'event-and-data-flow': {
|
|
172
|
-
label: '事件与数据流',
|
|
173
|
-
guide: '分析事件传播和数据状态管理方式。',
|
|
174
|
-
focusAreas: [
|
|
175
|
-
'事件传播 (Delegate/Notification/Block/Target-Action)',
|
|
176
|
-
'数据状态管理 (KVO/属性观察/响应式)',
|
|
177
|
-
'数据持久化方案',
|
|
178
|
-
'数据流转路径和状态同步',
|
|
179
|
-
],
|
|
180
|
-
outputType: 'candidate',
|
|
181
|
-
allowedKnowledgeTypes: ['call-chain', 'data-flow', 'event-and-data-flow'],
|
|
182
|
-
},
|
|
183
|
-
'best-practice': {
|
|
184
|
-
label: '最佳实践',
|
|
185
|
-
guide: '分析错误处理、并发安全、内存管理等工程实践。',
|
|
186
|
-
focusAreas: [
|
|
187
|
-
'错误处理策略和模式',
|
|
188
|
-
'并发安全 (GCD/NSOperation/锁)',
|
|
189
|
-
'内存管理 (ARC 下的弱引用/循环引用处理)',
|
|
190
|
-
'日志规范和调试基础设施',
|
|
191
|
-
],
|
|
192
|
-
outputType: 'candidate',
|
|
193
|
-
allowedKnowledgeTypes: ['best-practice'],
|
|
194
|
-
},
|
|
195
|
-
'agent-guidelines': {
|
|
196
|
-
label: 'Agent 开发注意事项',
|
|
197
|
-
guide: '总结 Agent 在此项目开发时必须遵守的规则和约束。',
|
|
198
|
-
focusAreas: [
|
|
199
|
-
'命名强制规则和前缀约定',
|
|
200
|
-
'线程安全约束',
|
|
201
|
-
'已废弃 API 标记',
|
|
202
|
-
'架构约束注释 (TODO/FIXME)',
|
|
203
|
-
],
|
|
204
|
-
outputType: 'skill',
|
|
205
|
-
allowedKnowledgeTypes: ['boundary-constraint', 'code-standard'],
|
|
206
|
-
},
|
|
207
|
-
|
|
208
|
-
// ── 语言条件维度(v3.1: 多语言支持)──────────────────────
|
|
209
|
-
|
|
210
|
-
'module-export-scan': {
|
|
211
|
-
label: '模块导出分析',
|
|
212
|
-
guide: '分析 TS/JS 模块的导出结构和 public API surface。',
|
|
213
|
-
focusAreas: [
|
|
214
|
-
'barrel export 结构和 re-export 链路',
|
|
215
|
-
'public API surface 合规性',
|
|
216
|
-
'tree-shaking 兼容性',
|
|
217
|
-
'循环依赖检测',
|
|
218
|
-
],
|
|
219
|
-
outputType: 'dual',
|
|
220
|
-
allowedKnowledgeTypes: ['code-standard', 'architecture'],
|
|
221
|
-
},
|
|
222
|
-
'framework-convention-scan': {
|
|
223
|
-
label: '框架约定扫描',
|
|
224
|
-
guide: '分析前端框架约定(组件结构、状态管理、路由)。',
|
|
225
|
-
focusAreas: [
|
|
226
|
-
'组件目录结构和命名约定',
|
|
227
|
-
'状态管理模式 (Redux/Vuex/Pinia/Zustand)',
|
|
228
|
-
'路由约定和数据获取模式',
|
|
229
|
-
'样式约定 (CSS Module/Tailwind/CSS-in-JS)',
|
|
230
|
-
],
|
|
231
|
-
outputType: 'dual',
|
|
232
|
-
allowedKnowledgeTypes: ['code-standard', 'architecture'],
|
|
233
|
-
},
|
|
234
|
-
'python-package-scan': {
|
|
235
|
-
label: 'Python 包结构分析',
|
|
236
|
-
guide: '分析 Python 包的导入风格、类型标注和 __init__.py 策略。',
|
|
237
|
-
focusAreas: [
|
|
238
|
-
'__init__.py 导出策略和 __all__ 定义',
|
|
239
|
-
'相对/绝对导入风格',
|
|
240
|
-
'type hints 覆盖率和 Protocol 使用',
|
|
241
|
-
'decorator 使用模式',
|
|
242
|
-
],
|
|
243
|
-
outputType: 'dual',
|
|
244
|
-
allowedKnowledgeTypes: ['code-standard', 'architecture'],
|
|
245
|
-
},
|
|
246
|
-
'jvm-annotation-scan': {
|
|
247
|
-
label: '注解/Annotation 扫描',
|
|
248
|
-
guide: '扫描 Java/Kotlin 项目中的 DI、ORM、API 注解使用模式。',
|
|
249
|
-
focusAreas: [
|
|
250
|
-
'DI 注解 (@Inject/@Autowired/@Component)',
|
|
251
|
-
'ORM 注解 (@Entity/@Table/@Column)',
|
|
252
|
-
'API 注解 (@RestController/@RequestMapping)',
|
|
253
|
-
'自定义注解和元编程模式',
|
|
254
|
-
],
|
|
255
|
-
outputType: 'dual',
|
|
256
|
-
allowedKnowledgeTypes: ['code-pattern', 'architecture'],
|
|
257
|
-
},
|
|
258
|
-
};
|
|
259
|
-
|
|
260
|
-
// ──────────────────────────────────────────────────────────────────
|
|
261
|
-
// v4.0: Tier Reflection — 综合分析 (规则化, 不需要 AI)
|
|
262
|
-
// ──────────────────────────────────────────────────────────────────
|
|
263
|
-
|
|
264
|
-
/**
|
|
265
|
-
* 构建 Tier 级 Reflection — 在每个 Tier 完成后调用
|
|
266
|
-
*
|
|
267
|
-
* 无需 AI 调用,通过规则化聚合维度发现:
|
|
268
|
-
* - 收集所有维度的关键发现并按重要性排序
|
|
269
|
-
* - 检测跨维度重复模式
|
|
270
|
-
* - 为下一 Tier 生成建议
|
|
271
|
-
*
|
|
272
|
-
* @param {number} tierIndex — Tier 索引 (0-based)
|
|
273
|
-
* @param {Map<string, object>} tierResults — 本 Tier 的维度结果
|
|
274
|
-
* @param {import('./EpisodicMemory.js').EpisodicMemory} episodicMemory
|
|
275
|
-
* @returns {object} TierReflection
|
|
276
|
-
*/
|
|
277
|
-
function buildTierReflection(tierIndex, tierResults, episodicMemory) {
|
|
278
|
-
const completedDimensions = [...tierResults.keys()];
|
|
279
|
-
|
|
280
|
-
// 收集本 Tier 所有维度的 findings
|
|
281
|
-
const allFindings = [];
|
|
282
|
-
for (const dimId of completedDimensions) {
|
|
283
|
-
const report = episodicMemory.getDimensionReport(dimId);
|
|
284
|
-
if (report?.findings) {
|
|
285
|
-
for (const f of report.findings) {
|
|
286
|
-
allFindings.push({ dimId, ...f });
|
|
287
|
-
}
|
|
288
|
-
}
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
// Top findings by importance
|
|
292
|
-
const topFindings = allFindings
|
|
293
|
-
.sort((a, b) => (b.importance || 5) - (a.importance || 5))
|
|
294
|
-
.slice(0, 10);
|
|
295
|
-
|
|
296
|
-
// 检测跨维度模式 (多个维度提到同一文件/关键词)
|
|
297
|
-
const fileMentions = {};
|
|
298
|
-
const keywordMentions = {};
|
|
299
|
-
|
|
300
|
-
for (const f of allFindings) {
|
|
301
|
-
// 统计文件引用频率
|
|
302
|
-
if (f.evidence) {
|
|
303
|
-
const file = f.evidence.split(':')[0];
|
|
304
|
-
if (file) {
|
|
305
|
-
fileMentions[file] = (fileMentions[file] || 0) + 1;
|
|
306
|
-
}
|
|
307
|
-
}
|
|
308
|
-
// 统计关键词
|
|
309
|
-
const words = (f.finding || '').split(/[\s,,。.]+/).filter((w) => w.length > 3);
|
|
310
|
-
for (const w of words) {
|
|
311
|
-
keywordMentions[w] = (keywordMentions[w] || 0) + 1;
|
|
312
|
-
}
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
const crossDimensionPatterns = [];
|
|
316
|
-
|
|
317
|
-
// 多维度引用的文件 = 跨维度热点
|
|
318
|
-
for (const [file, count] of Object.entries(fileMentions)) {
|
|
319
|
-
if (count >= 2) {
|
|
320
|
-
crossDimensionPatterns.push(`文件 "${file}" 被 ${count} 个维度引用 — 可能是系统核心组件`);
|
|
321
|
-
}
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
// 多维度提及的关键词
|
|
325
|
-
for (const [word, count] of Object.entries(keywordMentions)) {
|
|
326
|
-
if (count >= 3) {
|
|
327
|
-
crossDimensionPatterns.push(`关键词 "${word}" 出现 ${count} 次 — 跨维度关联主题`);
|
|
328
|
-
}
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
// 为下一 Tier 生成建议
|
|
332
|
-
const suggestionsForNextTier = [];
|
|
333
|
-
|
|
334
|
-
// 找出 gaps (各维度报告的未覆盖方面)
|
|
335
|
-
for (const dimId of completedDimensions) {
|
|
336
|
-
const report = episodicMemory.getDimensionReport(dimId);
|
|
337
|
-
const gaps = report?.digest?.gaps || [];
|
|
338
|
-
for (const gap of gaps) {
|
|
339
|
-
if (gap && typeof gap === 'string' && gap.length > 5) {
|
|
340
|
-
suggestionsForNextTier.push(`[${dimId}] 未覆盖: ${gap}`);
|
|
341
|
-
}
|
|
342
|
-
}
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
// remainingTasks
|
|
346
|
-
for (const dimId of completedDimensions) {
|
|
347
|
-
const report = episodicMemory.getDimensionReport(dimId);
|
|
348
|
-
const remaining = report?.digest?.remainingTasks || [];
|
|
349
|
-
for (const task of remaining) {
|
|
350
|
-
if (task?.signal) {
|
|
351
|
-
suggestionsForNextTier.push(
|
|
352
|
-
`[${dimId}] 遗留信号: ${task.signal} (${task.reason || '未处理'})`
|
|
353
|
-
);
|
|
354
|
-
}
|
|
355
|
-
}
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
return {
|
|
359
|
-
tierIndex,
|
|
360
|
-
completedDimensions,
|
|
361
|
-
topFindings,
|
|
362
|
-
crossDimensionPatterns: crossDimensionPatterns.slice(0, 5),
|
|
363
|
-
suggestionsForNextTier: suggestionsForNextTier.slice(0, 8),
|
|
364
|
-
};
|
|
365
|
-
}
|
|
366
|
-
|
|
367
33
|
// ──────────────────────────────────────────────────────────────────
|
|
368
34
|
// fillDimensionsV3 — v3.0 管线入口
|
|
369
35
|
// ──────────────────────────────────────────────────────────────────
|
|
@@ -412,12 +78,128 @@ export async function fillDimensionsV3(fillContext) {
|
|
|
412
78
|
}
|
|
413
79
|
|
|
414
80
|
if (!chatAgent) {
|
|
415
|
-
logger.info('[Bootstrap-v3] AI not available —
|
|
81
|
+
logger.info('[Bootstrap-v3] AI not available — entering rule-based fallback');
|
|
416
82
|
taskManager?.emitProgress('bootstrap:ai-unavailable', {
|
|
417
|
-
message: 'AI
|
|
83
|
+
message: 'AI 不可用,将使用规则化降级提取基础知识。请配置 AI Provider 以获取完整分析。',
|
|
418
84
|
});
|
|
419
|
-
|
|
420
|
-
|
|
85
|
+
|
|
86
|
+
// ── 规则化降级: 从 Phase 0-4 数据中提取基础知识 ──
|
|
87
|
+
try {
|
|
88
|
+
fillContext.allFiles = allFiles;
|
|
89
|
+
const fallbackResult = await runNoAiFallback(fillContext);
|
|
90
|
+
|
|
91
|
+
// ── 持久化候选到数据库 (KnowledgeService.create) ──
|
|
92
|
+
let persistedCount = 0;
|
|
93
|
+
if (fallbackResult.candidates.length > 0) {
|
|
94
|
+
try {
|
|
95
|
+
const knowledgeService = ctx.container.get('knowledgeService');
|
|
96
|
+
for (const candidate of fallbackResult.candidates) {
|
|
97
|
+
try {
|
|
98
|
+
await knowledgeService.create(
|
|
99
|
+
{
|
|
100
|
+
title: candidate.title,
|
|
101
|
+
content: candidate.content,
|
|
102
|
+
language: candidate.language || primaryLang || '',
|
|
103
|
+
category: candidate.category || '',
|
|
104
|
+
knowledgeType: candidate.knowledgeType || 'code-pattern',
|
|
105
|
+
source: 'bootstrap-fallback',
|
|
106
|
+
difficulty: candidate.difficulty || 'beginner',
|
|
107
|
+
scope: candidate.scope || 'project-specific',
|
|
108
|
+
reasoning: candidate.reasoning || {},
|
|
109
|
+
tags: ['bootstrap-fallback', 'rule-based'],
|
|
110
|
+
},
|
|
111
|
+
{ userId: 'bootstrap-fallback' }
|
|
112
|
+
);
|
|
113
|
+
persistedCount++;
|
|
114
|
+
} catch (entryErr) {
|
|
115
|
+
logger.warn(
|
|
116
|
+
`[Bootstrap-fallback] Candidate "${candidate.title}" persist failed: ${entryErr.message}`
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
logger.info(
|
|
121
|
+
`[Bootstrap-fallback] ${persistedCount}/${fallbackResult.candidates.length} candidates persisted to DB`
|
|
122
|
+
);
|
|
123
|
+
} catch (svcErr) {
|
|
124
|
+
logger.warn(
|
|
125
|
+
`[Bootstrap-fallback] KnowledgeService not available — candidates not persisted: ${svcErr.message}`
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// ── 持久化 Skill 文件 ──
|
|
131
|
+
let skillsCreated = 0;
|
|
132
|
+
if (fallbackResult.skills.length > 0) {
|
|
133
|
+
try {
|
|
134
|
+
const { createSkill } = await import('../../skill.js');
|
|
135
|
+
for (const sk of fallbackResult.skills) {
|
|
136
|
+
try {
|
|
137
|
+
const result = createSkill(ctx, {
|
|
138
|
+
name: sk.name,
|
|
139
|
+
description: sk.description,
|
|
140
|
+
content: sk.content,
|
|
141
|
+
overwrite: true,
|
|
142
|
+
createdBy: 'bootstrap-fallback',
|
|
143
|
+
});
|
|
144
|
+
const parsed = JSON.parse(result);
|
|
145
|
+
if (parsed.success) {
|
|
146
|
+
skillsCreated++;
|
|
147
|
+
logger.info(`[Bootstrap-fallback] Skill "${sk.name}" created`);
|
|
148
|
+
}
|
|
149
|
+
} catch (skErr) {
|
|
150
|
+
logger.warn(`[Bootstrap-fallback] Skill "${sk.name}" write failed: ${skErr.message}`);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
} catch (importErr) {
|
|
154
|
+
logger.warn(`[Bootstrap-fallback] Skill module import failed: ${importErr.message}`);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// ── 写入降级报告 ──
|
|
159
|
+
try {
|
|
160
|
+
const reportDir = path.join(projectRoot, '.autosnippet');
|
|
161
|
+
await fs.mkdir(reportDir, { recursive: true });
|
|
162
|
+
await fs.writeFile(
|
|
163
|
+
path.join(reportDir, 'bootstrap-report.json'),
|
|
164
|
+
JSON.stringify(
|
|
165
|
+
{
|
|
166
|
+
version: '2.7.0',
|
|
167
|
+
timestamp: new Date().toISOString(),
|
|
168
|
+
mode: 'no-ai-fallback',
|
|
169
|
+
project: {
|
|
170
|
+
name: path.basename(projectRoot),
|
|
171
|
+
files: allFiles?.length || 0,
|
|
172
|
+
lang: primaryLang || 'unknown',
|
|
173
|
+
},
|
|
174
|
+
fallback: fallbackResult.report,
|
|
175
|
+
persisted: { candidates: persistedCount, skills: skillsCreated },
|
|
176
|
+
},
|
|
177
|
+
null,
|
|
178
|
+
2
|
|
179
|
+
)
|
|
180
|
+
);
|
|
181
|
+
} catch {
|
|
182
|
+
/* non-critical */
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// ── 通知前端降级产出已完成 ──
|
|
186
|
+
taskManager?.emitProgress('bootstrap:fallback-complete', {
|
|
187
|
+
message: `降级产出完成: ${persistedCount} 条知识已入库, ${skillsCreated} 个 Skill 已生成`,
|
|
188
|
+
candidates: persistedCount,
|
|
189
|
+
skills: skillsCreated,
|
|
190
|
+
errors: fallbackResult.report.errors.length,
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
logger.info(
|
|
194
|
+
`[Bootstrap-fallback] Completed: ${persistedCount} candidates persisted, ` +
|
|
195
|
+
`${skillsCreated} skills written, ${fallbackResult.report.errors.length} errors`
|
|
196
|
+
);
|
|
197
|
+
} catch (fallbackErr) {
|
|
198
|
+
logger.error(`[Bootstrap-fallback] Fallback failed: ${fallbackErr.message}`);
|
|
199
|
+
// 即使降级也失败,仍标记所有维度为 skipped
|
|
200
|
+
for (const dim of dimensions) {
|
|
201
|
+
taskManager?.markTaskCompleted(dim.id, { type: 'skipped', reason: 'fallback-failed' });
|
|
202
|
+
}
|
|
421
203
|
}
|
|
422
204
|
return;
|
|
423
205
|
}
|
|
@@ -1289,7 +1071,8 @@ export async function fillDimensionsV3(fillContext) {
|
|
|
1289
1071
|
`A: ${deliveryResult.channelA.rulesCount} rules, ` +
|
|
1290
1072
|
`B: ${deliveryResult.channelB.topicCount} topics, ` +
|
|
1291
1073
|
`C: ${deliveryResult.channelC.synced} skills, ` +
|
|
1292
|
-
`D: ${deliveryResult.channelD?.documentsCount || 0} documents`
|
|
1074
|
+
`D: ${deliveryResult.channelD?.documentsCount || 0} documents, ` +
|
|
1075
|
+
`F: ${deliveryResult.channelF?.filesWritten || 0} agent files`
|
|
1293
1076
|
);
|
|
1294
1077
|
}
|
|
1295
1078
|
} catch (deliveryErr) {
|