autosnippet 2.5.0 → 2.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/cli.js +35 -0
- package/dashboard/dist/assets/{icons-Dtm0E6DS.js → icons-Cq4-iQhP.js} +152 -87
- package/dashboard/dist/assets/index-DBxH7pVn.css +1 -0
- package/dashboard/dist/assets/index-Dw2F6qAS.js +197 -0
- package/dashboard/dist/assets/{react-markdown-CWxUbOf4.js → react-markdown-BA6FB2NP.js} +1 -1
- package/dashboard/dist/assets/{syntax-highlighter-CJ2drQQb.js → syntax-highlighter-CVLHn9O5.js} +1 -1
- package/dashboard/dist/assets/{vendor-f83ah6cm.js → vendor-BotF760a.js} +61 -61
- package/dashboard/dist/index.html +6 -6
- package/lib/bootstrap.js +1 -1
- package/lib/cli/SetupService.js +33 -8
- package/lib/cli/UpgradeService.js +139 -2
- package/lib/core/ast/ProjectGraph.js +599 -0
- package/lib/core/gateway/Gateway.js +19 -4
- package/lib/core/gateway/GatewayActionRegistry.js +2 -2
- package/lib/domain/recipe/Recipe.js +3 -0
- package/lib/external/ai/AiProvider.js +117 -10
- package/lib/external/ai/providers/ClaudeProvider.js +197 -0
- package/lib/external/ai/providers/GoogleGeminiProvider.js +235 -1
- package/lib/external/ai/providers/OpenAiProvider.js +131 -0
- package/lib/external/mcp/McpServer.js +2 -1
- package/lib/external/mcp/handlers/bootstrap/pipeline/dimension-context.js +216 -0
- package/lib/external/mcp/handlers/bootstrap/pipeline/orchestrator.js +468 -0
- package/lib/external/mcp/handlers/bootstrap/pipeline/tier-scheduler.js +162 -0
- package/lib/external/mcp/handlers/bootstrap/skills.js +225 -0
- package/lib/external/mcp/handlers/bootstrap.js +151 -1634
- package/lib/external/mcp/handlers/browse.js +1 -1
- package/lib/external/mcp/handlers/candidate.js +1 -33
- package/lib/external/mcp/handlers/skill.js +126 -31
- package/lib/external/mcp/tools.js +25 -3
- package/lib/http/middleware/requestLogger.js +23 -4
- package/lib/http/routes/ai.js +3 -1
- package/lib/http/routes/auth.js +3 -2
- package/lib/http/routes/candidates.js +49 -25
- package/lib/http/routes/commands.js +0 -8
- package/lib/http/routes/guardRules.js +1 -16
- package/lib/http/routes/recipes.js +4 -17
- package/lib/http/routes/search.js +16 -22
- package/lib/http/routes/skills.js +40 -3
- package/lib/http/routes/snippets.js +0 -33
- package/lib/http/routes/spm.js +37 -63
- package/lib/http/utils/routeHelpers.js +31 -0
- package/lib/infrastructure/audit/AuditStore.js +18 -0
- package/lib/infrastructure/config/Paths.js +9 -0
- package/lib/infrastructure/logging/Logger.js +86 -3
- package/lib/infrastructure/realtime/RealtimeService.js +2 -5
- package/lib/infrastructure/vector/JsonVectorAdapter.js +24 -1
- package/lib/injection/ServiceContainer.js +62 -3
- package/lib/service/bootstrap/BootstrapTaskManager.js +400 -0
- package/lib/service/candidate/CandidateFileWriter.js +68 -27
- package/lib/service/candidate/CandidateService.js +156 -10
- package/lib/service/chat/AnalystAgent.js +216 -0
- package/lib/service/chat/CandidateGuardrail.js +134 -0
- package/lib/service/chat/ChatAgent.js +1272 -155
- package/lib/service/chat/ContextWindow.js +730 -0
- package/lib/service/chat/ConversationStore.js +377 -0
- package/lib/service/chat/HandoffProtocol.js +180 -0
- package/lib/service/chat/Memory.js +40 -10
- package/lib/service/chat/ProducerAgent.js +240 -0
- package/lib/service/chat/ToolRegistry.js +149 -5
- package/lib/service/chat/tools.js +1493 -60
- package/lib/service/recipe/RecipeFileWriter.js +12 -1
- package/lib/service/skills/EventAggregator.js +187 -0
- package/lib/service/skills/SignalCollector.js +549 -0
- package/lib/service/skills/SkillAdvisor.js +324 -0
- package/lib/service/skills/SkillHooks.js +13 -5
- package/lib/service/spm/SpmService.js +2 -2
- package/package.json +1 -1
- package/templates/copilot-instructions.md +20 -3
- package/templates/cursor-rules/autosnippet-conventions.mdc +21 -4
- package/templates/cursor-rules/autosnippet-skills.mdc +45 -0
- package/dashboard/dist/assets/index-B7VpZOCz.css +0 -1
- package/dashboard/dist/assets/index-D87IZTmZ.js +0 -187
|
@@ -0,0 +1,324 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SkillAdvisor — 基于使用模式的 Skill 推荐引擎
|
|
3
|
+
*
|
|
4
|
+
* 分析项目使用行为并推荐创建 Skill:
|
|
5
|
+
* 1. Guard 违规模式 — 同类违规反复出现 → 编码规范 Skill
|
|
6
|
+
* 2. Memory 偏好积累 — 用户偏好超过阈值 → 约定总结 Skill
|
|
7
|
+
* 3. Recipe 分布缺口 — 某类 Recipe 高频使用但无对应 Skill
|
|
8
|
+
* 4. 搜索 miss — 高频搜索但低命中 → 知识盲区 Skill
|
|
9
|
+
*
|
|
10
|
+
* 设计原则:
|
|
11
|
+
* - 只做分析和推荐,不自动创建(由 Agent 决策执行 create_skill)
|
|
12
|
+
* - 静默降级:任何数据源读取失败不影响其他维度
|
|
13
|
+
* - 零 AI 调用 — 纯规则分析,确保即时返回
|
|
14
|
+
* - 推荐结果包含 draft 草稿(name + description + rationale),
|
|
15
|
+
* Agent 可直接调用 create_skill 创建
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
import fs from 'node:fs';
|
|
19
|
+
import path from 'node:path';
|
|
20
|
+
import { getProjectSkillsPath } from '../../infrastructure/config/Paths.js';
|
|
21
|
+
|
|
22
|
+
export class SkillAdvisor {
|
|
23
|
+
#projectRoot;
|
|
24
|
+
#db;
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* @param {string} projectRoot — 用户项目根目录
|
|
28
|
+
* @param {object} [opts]
|
|
29
|
+
* @param {object} [opts.database] — better-sqlite3 实例(可选)
|
|
30
|
+
*/
|
|
31
|
+
constructor(projectRoot, { database } = {}) {
|
|
32
|
+
this.#projectRoot = projectRoot;
|
|
33
|
+
this.#db = database || null;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* 生成 Skill 推荐列表
|
|
38
|
+
*
|
|
39
|
+
* @returns {{
|
|
40
|
+
* suggestions: Array<{
|
|
41
|
+
* name: string,
|
|
42
|
+
* description: string,
|
|
43
|
+
* rationale: string,
|
|
44
|
+
* source: string,
|
|
45
|
+
* priority: 'high' | 'medium' | 'low',
|
|
46
|
+
* signals: object
|
|
47
|
+
* }>,
|
|
48
|
+
* analysisContext: object
|
|
49
|
+
* }}
|
|
50
|
+
*/
|
|
51
|
+
suggest() {
|
|
52
|
+
const existingSkills = this.#listExistingProjectSkills();
|
|
53
|
+
const suggestions = [];
|
|
54
|
+
const analysisContext = {};
|
|
55
|
+
|
|
56
|
+
// ── 维度 1: Guard 违规模式 ──
|
|
57
|
+
try {
|
|
58
|
+
const guardInsights = this.#analyzeGuardPatterns();
|
|
59
|
+
analysisContext.guard = guardInsights.summary;
|
|
60
|
+
suggestions.push(...guardInsights.suggestions.filter(
|
|
61
|
+
s => !existingSkills.has(s.name),
|
|
62
|
+
));
|
|
63
|
+
} catch { /* silent */ }
|
|
64
|
+
|
|
65
|
+
// ── 维度 2: Memory 偏好积累 ──
|
|
66
|
+
try {
|
|
67
|
+
const memoryInsights = this.#analyzeMemoryPatterns();
|
|
68
|
+
analysisContext.memory = memoryInsights.summary;
|
|
69
|
+
suggestions.push(...memoryInsights.suggestions.filter(
|
|
70
|
+
s => !existingSkills.has(s.name),
|
|
71
|
+
));
|
|
72
|
+
} catch { /* silent */ }
|
|
73
|
+
|
|
74
|
+
// ── 维度 3: Recipe 分布与使用 ──
|
|
75
|
+
try {
|
|
76
|
+
const recipeInsights = this.#analyzeRecipePatterns();
|
|
77
|
+
analysisContext.recipes = recipeInsights.summary;
|
|
78
|
+
suggestions.push(...recipeInsights.suggestions.filter(
|
|
79
|
+
s => !existingSkills.has(s.name),
|
|
80
|
+
));
|
|
81
|
+
} catch { /* silent */ }
|
|
82
|
+
|
|
83
|
+
// ── 维度 4: 候选积压 ──
|
|
84
|
+
try {
|
|
85
|
+
const candidateInsights = this.#analyzeCandidatePatterns();
|
|
86
|
+
analysisContext.candidates = candidateInsights.summary;
|
|
87
|
+
suggestions.push(...candidateInsights.suggestions.filter(
|
|
88
|
+
s => !existingSkills.has(s.name),
|
|
89
|
+
));
|
|
90
|
+
} catch { /* silent */ }
|
|
91
|
+
|
|
92
|
+
// 按优先级排序:high > medium > low
|
|
93
|
+
const priorityOrder = { high: 0, medium: 1, low: 2 };
|
|
94
|
+
suggestions.sort((a, b) => (priorityOrder[a.priority] || 2) - (priorityOrder[b.priority] || 2));
|
|
95
|
+
|
|
96
|
+
return {
|
|
97
|
+
suggestions,
|
|
98
|
+
existingProjectSkills: [...existingSkills],
|
|
99
|
+
analysisContext,
|
|
100
|
+
hint: suggestions.length > 0
|
|
101
|
+
? `发现 ${suggestions.length} 个 Skill 创建建议。你可以使用 autosnippet_create_skill 工具直接创建,也可以根据 rationale 自行判断是否需要。`
|
|
102
|
+
: '当前项目使用模式暂无明确的 Skill 创建建议。继续使用后会积累更多信号。',
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// ═══════════════════════════════════════════════════════
|
|
107
|
+
// 维度 1: Guard 违规模式分析
|
|
108
|
+
// ═══════════════════════════════════════════════════════
|
|
109
|
+
|
|
110
|
+
#analyzeGuardPatterns() {
|
|
111
|
+
const suggestions = [];
|
|
112
|
+
if (!this.#db) return { summary: 'DB 不可用', suggestions };
|
|
113
|
+
|
|
114
|
+
try {
|
|
115
|
+
// 查询 Guard 违规记录(audit_logs 中 action LIKE 'guard%' + result='violation')
|
|
116
|
+
const rows = this.#db.prepare(`
|
|
117
|
+
SELECT json_extract(operation_data, '$.ruleName') as ruleName,
|
|
118
|
+
COUNT(*) as cnt
|
|
119
|
+
FROM audit_logs
|
|
120
|
+
WHERE action LIKE 'guard%'
|
|
121
|
+
AND result = 'violation'
|
|
122
|
+
GROUP BY ruleName
|
|
123
|
+
HAVING cnt >= 3
|
|
124
|
+
ORDER BY cnt DESC
|
|
125
|
+
LIMIT 5
|
|
126
|
+
`).all();
|
|
127
|
+
|
|
128
|
+
if (rows.length > 0) {
|
|
129
|
+
const topRule = rows[0];
|
|
130
|
+
suggestions.push({
|
|
131
|
+
name: `project-guard-${_kebab(topRule.ruleName || 'common')}`,
|
|
132
|
+
description: `项目编码规范 — 基于高频 Guard 违规「${topRule.ruleName}」(${topRule.cnt} 次)自动推荐`,
|
|
133
|
+
rationale: `Guard 规则「${topRule.ruleName}」被违反 ${topRule.cnt} 次,说明团队可能不了解此规范。创建 Skill 可以让 AI 在编码时主动提醒,并提供正确写法参考。`,
|
|
134
|
+
source: 'guard_violations',
|
|
135
|
+
priority: topRule.cnt >= 10 ? 'high' : 'medium',
|
|
136
|
+
signals: { ruleName: topRule.ruleName, violationCount: topRule.cnt, allRules: rows },
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
return {
|
|
141
|
+
summary: { violationRules: rows.length, topViolations: rows.slice(0, 3) },
|
|
142
|
+
suggestions,
|
|
143
|
+
};
|
|
144
|
+
} catch {
|
|
145
|
+
return { summary: 'Guard audit_log 查询失败', suggestions };
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// ═══════════════════════════════════════════════════════
|
|
150
|
+
// 维度 2: Memory 偏好分析
|
|
151
|
+
// ═══════════════════════════════════════════════════════
|
|
152
|
+
|
|
153
|
+
#analyzeMemoryPatterns() {
|
|
154
|
+
const suggestions = [];
|
|
155
|
+
const memoryPath = path.join(this.#projectRoot, '.autosnippet', 'memory.jsonl');
|
|
156
|
+
|
|
157
|
+
if (!fs.existsSync(memoryPath)) {
|
|
158
|
+
return { summary: '无 Memory 记录', suggestions };
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
try {
|
|
162
|
+
const raw = fs.readFileSync(memoryPath, 'utf-8').trim();
|
|
163
|
+
if (!raw) return { summary: '无 Memory 记录', suggestions };
|
|
164
|
+
|
|
165
|
+
const entries = raw.split('\n')
|
|
166
|
+
.map(l => { try { return JSON.parse(l); } catch { return null; } })
|
|
167
|
+
.filter(Boolean);
|
|
168
|
+
|
|
169
|
+
const preferences = entries.filter(e => e.type === 'preference');
|
|
170
|
+
|
|
171
|
+
if (preferences.length >= 5) {
|
|
172
|
+
// 有足够多的偏好积累 → 建议归纳为 Skill
|
|
173
|
+
const sample = preferences.slice(-5).map(p => p.content).join('\n- ');
|
|
174
|
+
suggestions.push({
|
|
175
|
+
name: 'project-conventions',
|
|
176
|
+
description: `项目约定总结 — 基于 ${preferences.length} 条团队偏好自动推荐`,
|
|
177
|
+
rationale: `Memory 中已积累 ${preferences.length} 条用户偏好(如"我们不用…"、"以后都…"),建议归纳为一个 Skill 文档,让 AI 在每次对话中都能参考:\n- ${sample}`,
|
|
178
|
+
source: 'memory_preferences',
|
|
179
|
+
priority: preferences.length >= 10 ? 'high' : 'medium',
|
|
180
|
+
signals: { totalPreferences: preferences.length, recentSamples: preferences.slice(-5) },
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
return {
|
|
185
|
+
summary: { totalEntries: entries.length, preferences: preferences.length },
|
|
186
|
+
suggestions,
|
|
187
|
+
};
|
|
188
|
+
} catch {
|
|
189
|
+
return { summary: 'Memory 读取失败', suggestions };
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// ═══════════════════════════════════════════════════════
|
|
194
|
+
// 维度 3: Recipe 分布与使用热度
|
|
195
|
+
// ═══════════════════════════════════════════════════════
|
|
196
|
+
|
|
197
|
+
#analyzeRecipePatterns() {
|
|
198
|
+
const suggestions = [];
|
|
199
|
+
if (!this.#db) return { summary: 'DB 不可用', suggestions };
|
|
200
|
+
|
|
201
|
+
try {
|
|
202
|
+
// 按 category 分布
|
|
203
|
+
const categories = this.#db.prepare(`
|
|
204
|
+
SELECT category, COUNT(*) as cnt
|
|
205
|
+
FROM recipes
|
|
206
|
+
WHERE category IS NOT NULL AND category != ''
|
|
207
|
+
GROUP BY category
|
|
208
|
+
ORDER BY cnt DESC
|
|
209
|
+
`).all();
|
|
210
|
+
|
|
211
|
+
// 按 language 分布
|
|
212
|
+
const languages = this.#db.prepare(`
|
|
213
|
+
SELECT language, COUNT(*) as cnt
|
|
214
|
+
FROM recipes
|
|
215
|
+
WHERE language IS NOT NULL AND language != ''
|
|
216
|
+
GROUP BY language
|
|
217
|
+
ORDER BY cnt DESC
|
|
218
|
+
`).all();
|
|
219
|
+
|
|
220
|
+
// 高频使用但无自定义 Skill 的 category
|
|
221
|
+
const topCategory = categories[0];
|
|
222
|
+
if (topCategory && topCategory.cnt >= 10) {
|
|
223
|
+
const catName = topCategory.category.toLowerCase();
|
|
224
|
+
suggestions.push({
|
|
225
|
+
name: `project-${_kebab(catName)}-patterns`,
|
|
226
|
+
description: `${topCategory.category} 模式汇总 — 该类 Recipe 数量最多(${topCategory.cnt} 条),建议创建专属开发指南`,
|
|
227
|
+
rationale: `项目中 ${topCategory.category} 类 Recipe 高达 ${topCategory.cnt} 条,占比最大。创建一个 Skill 汇总此类别的核心设计模式、常见用法和注意事项,让 AI 在处理相关代码时有更精准的参考。`,
|
|
228
|
+
source: 'recipe_distribution',
|
|
229
|
+
priority: 'low',
|
|
230
|
+
signals: { category: topCategory.category, recipeCount: topCategory.cnt, allCategories: categories },
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// 高使用量 Recipe 统计(adoption_count + application_count >= 5)
|
|
235
|
+
let hotRecipes = [];
|
|
236
|
+
try {
|
|
237
|
+
hotRecipes = this.#db.prepare(`
|
|
238
|
+
SELECT title, category,
|
|
239
|
+
(adoption_count + application_count) as total_usage
|
|
240
|
+
FROM recipes
|
|
241
|
+
WHERE (adoption_count + application_count) >= 5
|
|
242
|
+
ORDER BY total_usage DESC
|
|
243
|
+
LIMIT 10
|
|
244
|
+
`).all();
|
|
245
|
+
} catch { /* 查询失败时降级为空 */ }
|
|
246
|
+
|
|
247
|
+
return {
|
|
248
|
+
summary: { categories: categories.length, languages, hotRecipeCount: hotRecipes.length },
|
|
249
|
+
suggestions,
|
|
250
|
+
};
|
|
251
|
+
} catch {
|
|
252
|
+
return { summary: 'Recipe 查询失败', suggestions };
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
// ═══════════════════════════════════════════════════════
|
|
257
|
+
// 维度 4: 候选积压分析
|
|
258
|
+
// ═══════════════════════════════════════════════════════
|
|
259
|
+
|
|
260
|
+
#analyzeCandidatePatterns() {
|
|
261
|
+
const suggestions = [];
|
|
262
|
+
if (!this.#db) return { summary: 'DB 不可用', suggestions };
|
|
263
|
+
|
|
264
|
+
try {
|
|
265
|
+
const stats = this.#db.prepare(`
|
|
266
|
+
SELECT
|
|
267
|
+
COUNT(*) as total,
|
|
268
|
+
SUM(CASE WHEN status='pending' THEN 1 ELSE 0 END) as pending,
|
|
269
|
+
SUM(CASE WHEN status='rejected' THEN 1 ELSE 0 END) as rejected
|
|
270
|
+
FROM candidates
|
|
271
|
+
`).get();
|
|
272
|
+
|
|
273
|
+
// 大量被拒绝 → 提示候选质量 Skill
|
|
274
|
+
if (stats && stats.rejected >= 10) {
|
|
275
|
+
suggestions.push({
|
|
276
|
+
name: 'project-candidate-quality',
|
|
277
|
+
description: `候选提交质量指南 — ${stats.rejected} 条候选被拒,建议创建提交标准 Skill`,
|
|
278
|
+
rationale: `已有 ${stats.rejected} 条候选被驳回(总计 ${stats.total} 条)。创建一个 Skill 明确项目的候选提交标准(哪些代码值得提取、必填字段要求、质量标杆),可以减少返工。`,
|
|
279
|
+
source: 'candidate_rejection',
|
|
280
|
+
priority: stats.rejected >= 20 ? 'high' : 'medium',
|
|
281
|
+
signals: { total: stats.total, pending: stats.pending, rejected: stats.rejected },
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
return {
|
|
286
|
+
summary: stats || {},
|
|
287
|
+
suggestions,
|
|
288
|
+
};
|
|
289
|
+
} catch {
|
|
290
|
+
return { summary: '候选查询失败', suggestions };
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
// ═══════════════════════════════════════════════════════
|
|
295
|
+
// 辅助方法
|
|
296
|
+
// ═══════════════════════════════════════════════════════
|
|
297
|
+
|
|
298
|
+
/**
|
|
299
|
+
* 列出已有的项目级 Skill 名称集合(避免重复推荐)
|
|
300
|
+
*/
|
|
301
|
+
#listExistingProjectSkills() {
|
|
302
|
+
const names = new Set();
|
|
303
|
+
const dir = getProjectSkillsPath(this.#projectRoot);
|
|
304
|
+
try {
|
|
305
|
+
fs.readdirSync(dir, { withFileTypes: true })
|
|
306
|
+
.filter(d => d.isDirectory())
|
|
307
|
+
.forEach(d => names.add(d.name));
|
|
308
|
+
} catch { /* no project skills */ }
|
|
309
|
+
return names;
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
/**
|
|
314
|
+
* 字符串转 kebab-case(简化版)
|
|
315
|
+
*/
|
|
316
|
+
function _kebab(str) {
|
|
317
|
+
return (str || 'unknown')
|
|
318
|
+
.replace(/[^a-zA-Z0-9\s-]/g, '')
|
|
319
|
+
.replace(/\s+/g, '-')
|
|
320
|
+
.toLowerCase()
|
|
321
|
+
.substring(0, 30);
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
export default SkillAdvisor;
|
|
@@ -10,18 +10,26 @@
|
|
|
10
10
|
* - onGuardCheck(violation, ctx) → violation (可修改)
|
|
11
11
|
* - onBootstrapComplete(stats, ctx) → void
|
|
12
12
|
*
|
|
13
|
-
* 加载顺序: 内置 skills/ → 项目级
|
|
13
|
+
* 加载顺序: 内置 skills/ → 项目级 AutoSnippet/skills/(同名覆盖)
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
16
|
import fs from 'node:fs';
|
|
17
17
|
import path from 'node:path';
|
|
18
18
|
import { fileURLToPath } from 'node:url';
|
|
19
19
|
import Logger from '../../infrastructure/logging/Logger.js';
|
|
20
|
+
import { getProjectSkillsPath } from '../../infrastructure/config/Paths.js';
|
|
20
21
|
|
|
21
22
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
22
|
-
const
|
|
23
|
-
|
|
24
|
-
|
|
23
|
+
const SKILLS_DIR = path.resolve(__dirname, '../../../skills');
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* 获取项目级 Skills 目录(运行时动态解析)
|
|
27
|
+
* 路径: {projectRoot}/AutoSnippet/skills/
|
|
28
|
+
*/
|
|
29
|
+
function _getProjectSkillsDir() {
|
|
30
|
+
const projectRoot = process.env.ASD_PROJECT_DIR || process.cwd();
|
|
31
|
+
return getProjectSkillsPath(projectRoot);
|
|
32
|
+
}
|
|
25
33
|
|
|
26
34
|
const HOOK_NAMES = [
|
|
27
35
|
'onCandidateSubmit',
|
|
@@ -48,7 +56,7 @@ export class SkillHooks {
|
|
|
48
56
|
await this.#loadFromDir(SKILLS_DIR, loaded);
|
|
49
57
|
|
|
50
58
|
// 2. 项目级 skills(覆盖同名)
|
|
51
|
-
await this.#loadFromDir(
|
|
59
|
+
await this.#loadFromDir(_getProjectSkillsDir(), loaded);
|
|
52
60
|
|
|
53
61
|
// 3. 注册所有钩子
|
|
54
62
|
for (const [skillName, mod] of loaded) {
|
|
@@ -650,7 +650,7 @@ export class SpmService {
|
|
|
650
650
|
const CODE_EXTS = isDirectoryTarget
|
|
651
651
|
? new Set(['.swift', '.m', '.mm', '.h', '.c', '.cpp', '.js', '.ts', '.tsx', '.jsx', '.py', '.java', '.kt', '.go', '.rs', '.rb', '.vue', '.mjs', '.cjs'])
|
|
652
652
|
: new Set(['.swift', '.m', '.h', '.c', '.cpp', '.mm']);
|
|
653
|
-
const SKIP_DIRS = new Set(['node_modules', '.git', 'dist', 'build', '.next', 'Pods', '.build', 'DerivedData', 'vendor', '__pycache__', '.venv', 'target']);
|
|
653
|
+
const SKIP_DIRS = new Set(['node_modules', '.git', 'dist', 'build', '.next', 'Pods', 'Carthage', '.build', 'DerivedData', 'vendor', '__pycache__', '.venv', 'target']);
|
|
654
654
|
const MAX_FILES = 300;
|
|
655
655
|
|
|
656
656
|
const files = [];
|
|
@@ -889,7 +889,7 @@ export class SpmService {
|
|
|
889
889
|
// 非 SPM 项目:直接扫描常见源码目录(fallback)
|
|
890
890
|
this.#logger.info('[SpmService] scanProject: No SPM targets, falling back to directory scan');
|
|
891
891
|
const CODE_EXTS = new Set(['.swift', '.m', '.mm', '.h', '.js', '.ts', '.tsx', '.jsx', '.py', '.java', '.kt', '.go', '.rs', '.rb', '.vue', '.mjs', '.cjs']);
|
|
892
|
-
const SKIP_DIRS = new Set(['node_modules', '.git', 'dist', 'build', '.next', 'Pods', '.build', 'DerivedData', 'vendor', '__pycache__', '.venv', 'target']);
|
|
892
|
+
const SKIP_DIRS = new Set(['node_modules', '.git', 'dist', 'build', '.next', 'Pods', 'Carthage', '.build', 'DerivedData', 'vendor', '__pycache__', '.venv', 'target']);
|
|
893
893
|
const srcDirs = ['Sources', 'src', 'lib', 'app', 'pages', 'components', 'modules', 'packages'];
|
|
894
894
|
|
|
895
895
|
const walkDir = (dir, targetName) => {
|
package/package.json
CHANGED
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
## 知识库与结构
|
|
10
10
|
- 知识库根目录:`AutoSnippet/`(用户项目可通过 boxspec `knowledgeBase.dir` 自定义)
|
|
11
11
|
- Recipe:`AutoSnippet/recipes/*.md`(Markdown + Frontmatter + Snippet + Usage Guide)
|
|
12
|
+
- **Project Skills**:`AutoSnippet/skills/<name>/SKILL.md`(项目级 AI 知识增强文档,跟随 Git)
|
|
12
13
|
- constitution.yaml:`AutoSnippet/constitution.yaml`(权限宪法:角色 + 能力 + 治理规则)
|
|
13
14
|
- 运行时 DB:`.autosnippet/autosnippet.db`(SQLite,recipes/candidates/snippets 索引缓存)
|
|
14
15
|
- 向量索引:`.autosnippet/context/`(`asd embed` 生成)
|
|
@@ -51,14 +52,21 @@
|
|
|
51
52
|
- `autosnippet_submit_draft_recipes` — 解析草稿 Markdown 文件
|
|
52
53
|
- `autosnippet_enrich_candidates` — AI 补全缺失语义字段
|
|
53
54
|
|
|
54
|
-
### 项目扫描
|
|
55
|
+
### 项目扫描 & 冷启动
|
|
55
56
|
- `autosnippet_get_targets` / `autosnippet_get_target_files` / `autosnippet_get_target_metadata`
|
|
56
57
|
- `autosnippet_scan_project` — 轻量探查(文件清单 + Guard 审计)
|
|
57
|
-
- `autosnippet_bootstrap_knowledge` — 冷启动知识库初始化(9
|
|
58
|
+
- `autosnippet_bootstrap_knowledge` — 冷启动知识库初始化(9 维度 + 自动生成 Project Skills)
|
|
59
|
+
- `autosnippet_bootstrap_refine` — Bootstrap 候选 AI 润色(summary/insight/relations)
|
|
58
60
|
|
|
59
61
|
### Guard & 治理
|
|
60
62
|
- `autosnippet_guard_check` / `autosnippet_guard_audit_files` / `autosnippet_compliance_report`
|
|
61
63
|
|
|
64
|
+
### Skills
|
|
65
|
+
- `autosnippet_list_skills` — 列出所有可用 Skills(内置 + 项目级)
|
|
66
|
+
- `autosnippet_load_skill` — 加载 Skill 完整文档
|
|
67
|
+
- `autosnippet_create_skill` — 创建项目级 Skill(写入 `AutoSnippet/skills/`)
|
|
68
|
+
- `autosnippet_suggest_skills` — 基于使用模式推荐创建 Skill
|
|
69
|
+
|
|
62
70
|
### 其它
|
|
63
71
|
- `autosnippet_health` / `autosnippet_capabilities` / `autosnippet_confirm_usage`
|
|
64
72
|
|
|
@@ -67,10 +75,19 @@
|
|
|
67
75
|
- Frontmatter 必填字段(7):`title`、`trigger`(@开头)、`category`(8 选 1)、`language`、`summary_cn`、`summary_en`、`headers`。
|
|
68
76
|
- Usage Guide 必须用 `###` 三级标题分段,列表式书写,禁止一行文字墙。
|
|
69
77
|
|
|
78
|
+
## Project Skills
|
|
79
|
+
- **发现**:`autosnippet_list_skills` — 列出所有可用 Skills(内置 + 项目级)
|
|
80
|
+
- **加载**:`autosnippet_load_skill(skillName)` — 获取 Skill 完整操作指南
|
|
81
|
+
- **创建**:`autosnippet_create_skill(name, description, content)` — 创建项目级 Skill
|
|
82
|
+
- **推荐**:`autosnippet_suggest_skills` — 基于使用模式推荐创建 Skill
|
|
83
|
+
- **Bootstrap 自动生成**:冷启动 Phase 5.5 自动生成 4 个 Project Skills(code-standard, architecture, project-profile, agent-guidelines)
|
|
84
|
+
- **优先级**:项目级 Skill 同名覆盖内置;宏观知识查 Skill,微观代码模式查 Recipe
|
|
85
|
+
|
|
70
86
|
## 推荐工作流
|
|
71
87
|
- **查找**:`autosnippet_search`(推荐)或 `autosnippet_context_search`(上下文感知)。
|
|
72
88
|
- **产出候选**:`autosnippet_validate_candidate` 预校验 → `autosnippet_submit_candidate` 提交。
|
|
73
|
-
-
|
|
89
|
+
- **冷启动**:`autosnippet_bootstrap_knowledge` → `autosnippet_enrich_candidates` → `autosnippet_bootstrap_refine` → 逐 Target 深入 → `autosnippet_submit_candidates`。
|
|
90
|
+
- **Skills 创建**:`autosnippet_suggest_skills` 分析 → `autosnippet_create_skill` 固化知识。
|
|
74
91
|
- **采纳反馈**:`autosnippet_confirm_usage`(记录使用量影响排序权重)。
|
|
75
92
|
|
|
76
93
|
## 与 Cursor 规则联动
|
|
@@ -41,9 +41,19 @@ Recipes are classified into three kinds:
|
|
|
41
41
|
- **Retry policy**: If an MCP call fails, do not retry within the same agent turn; fall back to static docs or already-read context.
|
|
42
42
|
- **Adoption tracking**: Tool `autosnippet_confirm_usage` records that a Recipe was adopted or applied (affects usage stats and authority ranking). Show it when the user explicitly adopts a recipe, not immediately after presenting one.
|
|
43
43
|
- **Batch scan**: Ask Cursor in natural language (e.g. "scan all targets in this project", "batch extract candidates") to trigger the batch-scan workflow. The workflow calls `autosnippet_get_targets` → `autosnippet_get_target_files` → extract per file → `autosnippet_submit_candidates` automatically.
|
|
44
|
-
- **Cold start**: Use `autosnippet_bootstrap_knowledge` for full project knowledge initialization covering 9 dimensions
|
|
44
|
+
- **Cold start**: Use `autosnippet_bootstrap_knowledge` for full project knowledge initialization covering 9 dimensions. Phase 5.5 auto-generates 4 Project Skills (code-standard, architecture, project-profile, agent-guidelines) to `AutoSnippet/skills/`.
|
|
45
45
|
|
|
46
|
-
##
|
|
46
|
+
## Project Skills
|
|
47
|
+
|
|
48
|
+
- **Skills 目录**: `AutoSnippet/skills/<name>/SKILL.md` — 跟随项目 Git 管理
|
|
49
|
+
- **发现**: `autosnippet_list_skills` — 列出所有可用 Skills(内置 + 项目级)
|
|
50
|
+
- **加载**: `autosnippet_load_skill(skillName)` — 获取 Skill 完整文档
|
|
51
|
+
- **创建**: `autosnippet_create_skill(name, description, content)` — 创建项目级 Skill
|
|
52
|
+
- **推荐**: `autosnippet_suggest_skills` — 基于使用模式推荐创建 Skill
|
|
53
|
+
- **优先级**: 项目级 Skill 同名覆盖内置 Skill;Skill > Recipe(宏观知识优先查 Skill)
|
|
54
|
+
- **Bootstrap 自动生成**: 冷启动会自动生成 `project-code-standard`、`project-architecture`、`project-profile`、`project-agent-guidelines` 四个 Project Skills
|
|
55
|
+
|
|
56
|
+
## MCP tools (36 total)
|
|
47
57
|
|
|
48
58
|
### Search (prefer search / context_search)
|
|
49
59
|
- `autosnippet_search` — Unified search (auto: BM25 + semantic fusion)
|
|
@@ -66,14 +76,21 @@ Recipes are classified into three kinds:
|
|
|
66
76
|
- `autosnippet_submit_draft_recipes` — Parse draft Markdown files
|
|
67
77
|
- `autosnippet_enrich_candidates` — AI-fill missing semantic fields
|
|
68
78
|
|
|
69
|
-
### Project scanning
|
|
79
|
+
### Project scanning & bootstrap
|
|
70
80
|
- `autosnippet_get_targets` / `autosnippet_get_target_files` / `autosnippet_get_target_metadata`
|
|
71
81
|
- `autosnippet_scan_project` — Lightweight probe (file list + Guard audit)
|
|
72
|
-
- `autosnippet_bootstrap_knowledge` — Cold-start knowledge initialization
|
|
82
|
+
- `autosnippet_bootstrap_knowledge` — Cold-start knowledge initialization (9 dimensions + auto Project Skills)
|
|
83
|
+
- `autosnippet_bootstrap_refine` — AI refinement for bootstrap candidates (summary/insight/relations)
|
|
73
84
|
|
|
74
85
|
### Guard & governance
|
|
75
86
|
- `autosnippet_guard_check` / `autosnippet_guard_audit_files` / `autosnippet_compliance_report`
|
|
76
87
|
|
|
88
|
+
### Skills
|
|
89
|
+
- `autosnippet_list_skills` — List all available Skills (builtin + project)
|
|
90
|
+
- `autosnippet_load_skill` — Load a Skill's full document
|
|
91
|
+
- `autosnippet_create_skill` — Create a project-level Skill in `AutoSnippet/skills/`
|
|
92
|
+
- `autosnippet_suggest_skills` — Recommend Skills based on usage patterns
|
|
93
|
+
|
|
77
94
|
### Other
|
|
78
95
|
- `autosnippet_health` / `autosnippet_capabilities` / `autosnippet_confirm_usage`
|
|
79
96
|
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: AutoSnippet Project Skills — 项目级知识增强文档索引与使用指引
|
|
3
|
+
alwaysApply: true
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# AutoSnippet Project Skills
|
|
7
|
+
|
|
8
|
+
Project Skills 是针对当前项目自动生成或手动创建的 AI Agent 知识增强文档。
|
|
9
|
+
它们存放在 `AutoSnippet/skills/` 目录下,跟随项目 Git 管理。
|
|
10
|
+
|
|
11
|
+
## 如何发现与加载
|
|
12
|
+
|
|
13
|
+
1. **列出所有 Skills**:调用 `autosnippet_list_skills` 查看当前可用的 Skills(含内置 + 项目级)
|
|
14
|
+
2. **加载完整内容**:调用 `autosnippet_load_skill(skillName)` 获取具体 Skill 的完整文档
|
|
15
|
+
3. **按需加载**:不确定该用哪个 Skill 时,先加载 `autosnippet-intent` 做意图路由
|
|
16
|
+
4. **创建 Skill**:调用 `autosnippet_create_skill(name, description, content)` 创建项目级 Skill
|
|
17
|
+
5. **Skill 推荐**:调用 `autosnippet_suggest_skills` 获取基于使用模式的 Skill 创建建议
|
|
18
|
+
|
|
19
|
+
## Bootstrap 自动生成的 Project Skills
|
|
20
|
+
|
|
21
|
+
冷启动(`autosnippet_bootstrap_knowledge`)Phase 5.5 会自动为 4 个宏观维度生成 Project Skills:
|
|
22
|
+
|
|
23
|
+
| Skill | 维度 | 说明 |
|
|
24
|
+
|-------|------|------|
|
|
25
|
+
| `project-code-standard` | 代码规范 | 命名约定、文件组织规范 |
|
|
26
|
+
| `project-architecture` | 架构模式 | 分层架构、模块边界、依赖图 |
|
|
27
|
+
| `project-profile` | 项目特征 | 技术栈、模块结构、代码指标 |
|
|
28
|
+
| `project-agent-guidelines` | Agent 约束 | 强制规则、TODO/FIXME、WARNING |
|
|
29
|
+
|
|
30
|
+
生成后的 Skill 文件位于 `AutoSnippet/skills/<name>/SKILL.md`,自动跟随 Git。
|
|
31
|
+
调用 `autosnippet_load_skill` 可加载完整内容。
|
|
32
|
+
|
|
33
|
+
## 推荐工作流
|
|
34
|
+
|
|
35
|
+
冷启动完整流程:
|
|
36
|
+
1. `autosnippet_bootstrap_knowledge` — 9 维度分析 + 自动生成 Project Skills
|
|
37
|
+
2. `autosnippet_enrich_candidates` — 补全缺失语义字段
|
|
38
|
+
3. `autosnippet_bootstrap_refine` — AI 润色 summary/insight/relations
|
|
39
|
+
4. 逐 Target 深入分析 → `autosnippet_submit_candidates`
|
|
40
|
+
|
|
41
|
+
## 使用优先级
|
|
42
|
+
|
|
43
|
+
- **Project Skills > 内置 Skills**:同名时项目级覆盖内置
|
|
44
|
+
- **Skill > Recipe**:宏观架构/规范知识优先查 Skill,微观代码模式查 Recipe
|
|
45
|
+
- **Skills 是只读参考**:不要直接修改 SKILL.md,应通过 `autosnippet_create_skill` 工具创建或更新
|