autosnippet 3.0.10 → 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.
Files changed (56) hide show
  1. package/bin/cli.js +64 -1
  2. package/config/default.json +9 -0
  3. package/dashboard/dist/assets/{index-I2ySoCmF.js → index-Bnm26ulL.js} +47 -47
  4. package/dashboard/dist/index.html +1 -1
  5. package/lib/cli/SetupService.js +92 -5
  6. package/lib/cli/UpgradeService.js +14 -5
  7. package/lib/core/discovery/GenericDiscoverer.js +4 -28
  8. package/lib/external/mcp/handlers/bootstrap/base-dimensions.js +246 -0
  9. package/lib/external/mcp/handlers/bootstrap/pipeline/checkpoint.js +80 -0
  10. package/lib/external/mcp/handlers/bootstrap/pipeline/dimension-configs.js +275 -0
  11. package/lib/external/mcp/handlers/bootstrap/pipeline/noAiFallback.js +600 -0
  12. package/lib/external/mcp/handlers/bootstrap/pipeline/orchestrator.js +125 -342
  13. package/lib/external/mcp/handlers/bootstrap/refine.js +362 -0
  14. package/lib/external/mcp/handlers/bootstrap.js +6 -590
  15. package/lib/external/mcp/handlers/browse.js +119 -9
  16. package/lib/external/mcp/handlers/guard.js +25 -6
  17. package/lib/external/mcp/handlers/search.js +56 -24
  18. package/lib/http/routes/guardRules.js +9 -17
  19. package/lib/injection/ServiceContainer.js +12 -3
  20. package/lib/platform/ios/xcode/XcodeImportResolver.js +434 -0
  21. package/lib/platform/ios/xcode/XcodeIntegration.js +40 -659
  22. package/lib/platform/ios/xcode/XcodeWriteUtils.js +220 -0
  23. package/lib/service/chat/ChatAgent.js +39 -418
  24. package/lib/service/chat/ChatAgentPrompts.js +149 -0
  25. package/lib/service/chat/ChatAgentTasks.js +297 -0
  26. package/lib/service/chat/tools/_shared.js +61 -0
  27. package/lib/service/chat/tools/ai-analysis.js +284 -0
  28. package/lib/service/chat/tools/ast-graph.js +681 -0
  29. package/lib/service/chat/tools/composite.js +496 -0
  30. package/lib/service/chat/tools/guard.js +265 -0
  31. package/lib/service/chat/tools/index.js +250 -0
  32. package/lib/service/chat/tools/infrastructure.js +222 -0
  33. package/lib/service/chat/tools/knowledge-graph.js +234 -0
  34. package/lib/service/chat/tools/lifecycle.js +469 -0
  35. package/lib/service/chat/tools/project-access.js +923 -0
  36. package/lib/service/chat/tools/query.js +264 -0
  37. package/lib/service/chat/tools.js +14 -3994
  38. package/lib/service/cursor/AgentInstructionsGenerator.js +395 -0
  39. package/lib/service/cursor/CursorDeliveryPipeline.js +70 -11
  40. package/lib/service/cursor/FileProtection.js +116 -0
  41. package/lib/service/cursor/KnowledgeCompressor.js +61 -11
  42. package/lib/service/cursor/SkillsSyncer.js +5 -3
  43. package/lib/service/cursor/TopicClassifier.js +19 -3
  44. package/lib/service/guard/ExclusionManager.js +26 -2
  45. package/lib/service/guard/GuardCheckEngine.js +38 -370
  46. package/lib/service/guard/GuardCodeChecks.js +362 -0
  47. package/lib/service/guard/GuardCrossFileChecks.js +307 -0
  48. package/lib/service/guard/GuardPatternUtils.js +180 -0
  49. package/lib/service/guard/GuardService.js +80 -38
  50. package/lib/service/module/ModuleService.js +1 -0
  51. package/lib/service/search/SearchEngine.js +10 -2
  52. package/lib/service/wiki/WikiGenerator.js +226 -1532
  53. package/lib/service/wiki/WikiRenderers.js +1878 -0
  54. package/lib/service/wiki/WikiUtils.js +907 -0
  55. package/lib/shared/LanguageService.js +299 -0
  56. package/package.json +1 -1
@@ -0,0 +1,362 @@
1
+ /**
2
+ * bootstrapRefine — Phase 6 AI 润色
3
+ *
4
+ * 对 Bootstrap Phase 5 产出的知识条目进行 AI 二次精炼:
5
+ * - 改善模板化描述 → 更自然精准
6
+ * - 补充高阶架构洞察
7
+ * - 推断并填充 relations 关联
8
+ * - 调整 confidence 评分
9
+ *
10
+ * 从 bootstrap.js 提取为独立模块
11
+ */
12
+
13
+ import { envelope } from '../../envelope.js';
14
+
15
+ /**
16
+ * @param {object} ctx MCP context { container, logger }
17
+ * @param {object} args { candidateIds?: string[], userPrompt?: string, dryRun?: boolean }
18
+ */
19
+ export async function bootstrapRefine(ctx, args) {
20
+ const t0 = Date.now();
21
+ const knowledgeService = ctx.container.get('knowledgeService');
22
+ const aiProvider = ctx.container.get('aiProvider');
23
+
24
+ if (!aiProvider) {
25
+ return envelope({
26
+ success: false,
27
+ message: 'AI provider not configured',
28
+ errorCode: 'MISSING_AI_PROVIDER',
29
+ });
30
+ }
31
+
32
+ // 接入 BootstrapTaskManager 双通道推送 refine:* 事件
33
+ let onProgress = null;
34
+ try {
35
+ const taskManager = ctx.container.get('bootstrapTaskManager');
36
+ onProgress = (eventName, data) => taskManager.emitProgress(eventName, data);
37
+ } catch {
38
+ /* optional */
39
+ }
40
+
41
+ // 1. 收集待润色条目
42
+ let entries;
43
+ if (args.candidateIds?.length) {
44
+ entries = [];
45
+ for (const id of args.candidateIds) {
46
+ const e = await knowledgeService.get(id);
47
+ if (e) {
48
+ entries.push(typeof e.toJSON === 'function' ? e.toJSON() : e);
49
+ }
50
+ }
51
+ } else {
52
+ const result = await knowledgeService.list(
53
+ { lifecycle: 'pending', source: 'bootstrap' },
54
+ { page: 1, pageSize: 200 }
55
+ );
56
+ entries = (result.items || []).map((e) => (typeof e.toJSON === 'function' ? e.toJSON() : e));
57
+ }
58
+
59
+ if (entries.length === 0) {
60
+ return envelope({
61
+ success: true,
62
+ data: { refined: 0, total: 0, errors: [], results: [] },
63
+ meta: { tool: 'autosnippet_bootstrap', responseTimeMs: Date.now() - t0 },
64
+ });
65
+ }
66
+
67
+ onProgress?.('refine:started', { total: entries.length, candidateIds: entries.map((e) => e.id) });
68
+
69
+ // 2. 收集已发布 Recipe 标题(关联关系只能指向已发布 Recipe,不能在候选之间互关联)
70
+ let publishedTitles = [];
71
+ try {
72
+ const published = await knowledgeService.list(
73
+ { lifecycle: 'active' },
74
+ { page: 1, pageSize: 200 }
75
+ );
76
+ publishedTitles = (published.items || []).map((e) => e.title).filter(Boolean);
77
+ } catch { /* ignore */ }
78
+
79
+ // 3. 逐条 AI 润色
80
+ const results = [];
81
+ const errors = [];
82
+ let refined = 0;
83
+ let processed = 0;
84
+
85
+ for (const entry of entries) {
86
+ processed++;
87
+ onProgress?.('refine:item-started', {
88
+ candidateId: entry.id,
89
+ title: entry.title,
90
+ current: processed,
91
+ total: entries.length,
92
+ progress: Math.round(((processed - 1) / entries.length) * 100),
93
+ });
94
+
95
+ try {
96
+ const before = {
97
+ title: entry.title || '',
98
+ description: entry.description || '',
99
+ pattern: entry.content?.pattern || '',
100
+ markdown: entry.content?.markdown || '',
101
+ rationale: entry.content?.rationale || '',
102
+ tags: entry.tags || [],
103
+ confidence: entry.reasoning?.confidence ?? 0.6,
104
+ relations: entry.relations || {},
105
+ aiInsight: entry.aiInsight || null,
106
+ agentNotes: entry.agentNotes || null,
107
+ };
108
+
109
+ const refineInstruction = args.userPrompt
110
+ ? args.userPrompt
111
+ : '请改善描述使其更专业简洁,补充高阶架构洞察';
112
+
113
+ const prompt = `你是一位高级代码知识管理专家。请改进以下知识条目。
114
+
115
+ ## ⭐ JSON key 规范(最高优先级)
116
+
117
+ 返回的 JSON 必须且只能使用以下 9 个 key,大小写必须完全一致:
118
+
119
+ description → 摘要(string)
120
+ pattern → 代码/标准用法(string)
121
+ markdown → Markdown 文档(string)
122
+ rationale → 设计原理(string)
123
+ tags → 标签(string[])
124
+ confidence → 置信度(number 0.0–1.0)
125
+ aiInsight → AI 洞察(string | null)
126
+ agentNotes → Agent 笔记(string[] | null)
127
+ relations → 关联关系(object)
128
+
129
+ ## 当前条目信息
130
+
131
+ 标题: ${before.title}
132
+ 类型: ${entry.knowledgeType || '未知'}
133
+ 语言: ${entry.language || '未知'}
134
+
135
+ 【description】摘要
136
+ ${before.description || '(空)'}
137
+
138
+ 【pattern】代码/标准用法
139
+ ${(before.pattern || '(空)').substring(0, 2000)}
140
+
141
+ 【markdown】Markdown 文档
142
+ ${(before.markdown || '(空)').substring(0, 2000)}
143
+
144
+ 【rationale】设计原理
145
+ ${before.rationale || '(空)'}
146
+
147
+ 【tags】标签
148
+ ${JSON.stringify(before.tags)}
149
+
150
+ 【confidence】置信度
151
+ ${before.confidence}
152
+
153
+ 【relations】关联关系
154
+ ${JSON.stringify(before.relations)}
155
+
156
+ 【aiInsight】AI 洞察
157
+ ${before.aiInsight || '(空)'}
158
+
159
+ 【agentNotes】Agent 笔记
160
+ ${JSON.stringify(before.agentNotes || [])}
161
+
162
+ ${publishedTitles.length > 0 ? `已发布的 Recipe: ${publishedTitles.slice(0, 20).join(', ')}` : '(尚无已发布的 Recipe)'}
163
+
164
+ ## 润色指令
165
+
166
+ ${refineInstruction}
167
+
168
+ ## 约束
169
+
170
+ 1. 只修改需要改进的字段,未涉及的必须原样返回。
171
+ 2. tags 采用合并策略(保留原有 + 补充新建议),不要删除已有标签。
172
+ 3. relations 为 object 格式,key 为关系类型(如 inherits/implements/calls/depends_on/extends/related),value 为 string[]。
173
+ 4. relations 只能指向已发布的 Recipe,不能在候选之间建立关联。如果没有已发布的 Recipe,relations 应保持为空 {}。
174
+ 5. 每个 key 都必须存在,key 名称必须与上述完全一致。
175
+
176
+ 仅返回 JSON,不要添加任何其他文字或代码块标记。`;
177
+
178
+ const parsed = await aiProvider.chatWithStructuredOutput(prompt, { temperature: 0.3 });
179
+
180
+ if (!parsed) {
181
+ errors.push({ id: entry.id, title: entry.title, error: 'AI returned no valid JSON' });
182
+ onProgress?.('refine:item-failed', {
183
+ candidateId: entry.id,
184
+ title: entry.title,
185
+ error: 'No valid JSON',
186
+ current: processed,
187
+ total: entries.length,
188
+ progress: Math.round((processed / entries.length) * 100),
189
+ });
190
+ continue;
191
+ }
192
+
193
+ if (args.dryRun) {
194
+ results.push({ id: entry.id, title: entry.title, preview: parsed });
195
+ onProgress?.('refine:item-completed', {
196
+ candidateId: entry.id,
197
+ title: entry.title,
198
+ refined: false,
199
+ current: processed,
200
+ total: entries.length,
201
+ progress: Math.round((processed / entries.length) * 100),
202
+ });
203
+ continue;
204
+ }
205
+
206
+ // ─── key 别名归一化(与 candidates.js 保持一致) ───
207
+ const KEY_ALIASES = {
208
+ summary: 'description',
209
+ desc: 'description',
210
+ content: 'pattern',
211
+ design: 'rationale',
212
+ designRationale: 'rationale',
213
+ markdownDoc: 'markdown',
214
+ doc: 'markdown',
215
+ tag: 'tags',
216
+ label: 'tags',
217
+ labels: 'tags',
218
+ score: 'confidence',
219
+ ai_insight: 'aiInsight',
220
+ insight: 'aiInsight',
221
+ aiinsight: 'aiInsight',
222
+ agent_notes: 'agentNotes',
223
+ notes: 'agentNotes',
224
+ agentnotes: 'agentNotes',
225
+ relation: 'relations',
226
+ };
227
+ const VALID_KEYS = new Set([
228
+ 'description',
229
+ 'pattern',
230
+ 'markdown',
231
+ 'rationale',
232
+ 'tags',
233
+ 'confidence',
234
+ 'aiInsight',
235
+ 'agentNotes',
236
+ 'relations',
237
+ ]);
238
+ const normalized = {};
239
+ for (const [key, value] of Object.entries(parsed)) {
240
+ if (VALID_KEYS.has(key)) {
241
+ normalized[key] = value;
242
+ } else {
243
+ const mapped = KEY_ALIASES[key] || KEY_ALIASES[key.toLowerCase?.()];
244
+ if (mapped && !(mapped in normalized)) {
245
+ normalized[mapped] = value;
246
+ }
247
+ }
248
+ }
249
+ for (const k of VALID_KEYS) {
250
+ if (!(k in normalized)) {
251
+ normalized[k] = before[k];
252
+ }
253
+ }
254
+
255
+ // 构建更新数据
256
+ const updateData = {};
257
+ let changed = false;
258
+
259
+ if (normalized.description != null && normalized.description !== before.description) {
260
+ updateData.description = normalized.description;
261
+ changed = true;
262
+ }
263
+ // tags 采用合并策略
264
+ if (normalized.tags != null && Array.isArray(normalized.tags)) {
265
+ const merged = [...new Set([...(before.tags || []), ...normalized.tags])];
266
+ if (JSON.stringify(merged) !== JSON.stringify(before.tags)) {
267
+ updateData.tags = merged;
268
+ changed = true;
269
+ }
270
+ }
271
+ if (
272
+ typeof normalized.confidence === 'number' &&
273
+ normalized.confidence !== before.confidence
274
+ ) {
275
+ updateData.reasoning = { ...(entry.reasoning || {}), confidence: normalized.confidence };
276
+ changed = true;
277
+ }
278
+ if (normalized.aiInsight != null && normalized.aiInsight !== before.aiInsight) {
279
+ updateData.aiInsight = normalized.aiInsight;
280
+ changed = true;
281
+ }
282
+ if (normalized.agentNotes !== undefined) {
283
+ const newNotes = JSON.stringify(normalized.agentNotes);
284
+ if (newNotes !== JSON.stringify(before.agentNotes)) {
285
+ updateData.agentNotes = normalized.agentNotes;
286
+ changed = true;
287
+ }
288
+ }
289
+ if (normalized.relations !== undefined) {
290
+ const newRels = JSON.stringify(normalized.relations);
291
+ if (newRels !== JSON.stringify(before.relations)) {
292
+ updateData.relations = normalized.relations;
293
+ changed = true;
294
+ }
295
+ }
296
+ // content 嵌套写入
297
+ const contentPatch = { ...(entry.content || {}) };
298
+ let contentChanged = false;
299
+ if (normalized.pattern != null && normalized.pattern !== before.pattern) {
300
+ contentPatch.pattern = normalized.pattern;
301
+ contentChanged = true;
302
+ }
303
+ if (normalized.markdown != null && normalized.markdown !== before.markdown) {
304
+ contentPatch.markdown = normalized.markdown;
305
+ contentChanged = true;
306
+ }
307
+ if (normalized.rationale != null && normalized.rationale !== before.rationale) {
308
+ contentPatch.rationale = normalized.rationale;
309
+ contentChanged = true;
310
+ }
311
+ if (contentChanged) {
312
+ updateData.content = contentPatch;
313
+ changed = true;
314
+ }
315
+
316
+ if (changed) {
317
+ await knowledgeService.update(entry.id, updateData);
318
+ refined++;
319
+ }
320
+
321
+ results.push({
322
+ id: entry.id,
323
+ title: entry.title,
324
+ refined: changed,
325
+ fields: Object.keys(parsed),
326
+ });
327
+ onProgress?.('refine:item-completed', {
328
+ candidateId: entry.id,
329
+ title: entry.title,
330
+ refined: changed,
331
+ current: processed,
332
+ total: entries.length,
333
+ progress: Math.round((processed / entries.length) * 100),
334
+ refinedSoFar: refined,
335
+ });
336
+ } catch (err) {
337
+ errors.push({ id: entry.id, title: entry.title, error: err.message });
338
+ onProgress?.('refine:item-failed', {
339
+ candidateId: entry.id,
340
+ title: entry.title,
341
+ error: err.message,
342
+ current: processed,
343
+ total: entries.length,
344
+ progress: Math.round((processed / entries.length) * 100),
345
+ });
346
+ }
347
+ }
348
+
349
+ onProgress?.('refine:completed', { total: entries.length, refined, failed: errors.length });
350
+
351
+ return envelope({
352
+ success: true,
353
+ data: {
354
+ refined,
355
+ total: entries.length,
356
+ errors,
357
+ results,
358
+ message: `Phase 6 AI 润色完成: ${refined}/${entries.length} 条知识条目已更新${args.dryRun ? '(预览模式)' : ''}`,
359
+ },
360
+ meta: { tool: 'autosnippet_bootstrap', responseTimeMs: Date.now() - t0 },
361
+ });
362
+ }