autosnippet 2.13.0 → 2.14.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/README.md CHANGED
@@ -240,7 +240,7 @@ asd install:vscode-copilot # 配置 MCP 和 Copilot 指令
240
240
 
241
241
  ## MCP 工具一览
242
242
 
243
- 38 个 MCP 工具按功能分组(省略了 **autosnippet_** 前缀):
243
+ 39 个 MCP 工具按功能分组(省略了 **autosnippet_** 前缀):
244
244
 
245
245
  | 分类 | 工具 |
246
246
  |------|------|
@@ -248,6 +248,7 @@ asd install:vscode-copilot # 配置 MCP 和 Copilot 指令
248
248
  | **搜索** | `search`(统合入口)、`context_search`(4 层漏斗)、`keyword_search`、`semantic_search` |
249
249
  | **Recipe 浏览** | `list_recipes`、`get_recipe`、`list_rules`、`patterns`、`list_facts`、`recipe_insights`、`confirm_usage` |
250
250
  | **候选管理** | `validate_candidate`、`check_duplicate`、`submit_knowledge`、`submit_knowledge_batch`、`enrich_candidates` |
251
+ | **开发文档** | `save_document` |
251
252
  | **知识图谱** | `graph_query`、`graph_impact`、`graph_path`、`graph_stats` |
252
253
  | **项目结构** | `get_targets`、`get_target_files`、`get_target_metadata` |
253
254
  | **Guard** | `guard_check`、`guard_audit_files`、`scan_project` |
package/bin/cli.js CHANGED
@@ -658,6 +658,7 @@ program
658
658
  console.log(` Channel A (Always-On Rules): ${result.channelA.rulesCount} 条规则 (${result.channelA.tokensUsed} tokens)`);
659
659
  console.log(` Channel B (Smart Rules): ${result.channelB.topicCount} 个主题, ${result.channelB.patternsCount} 个模式 (${result.channelB.totalTokens} tokens)`);
660
660
  console.log(` Channel C (Agent Skills): ${result.channelC.synced} 个 Skills 已同步`);
661
+ console.log(` Channel D (Dev Documents): ${result.channelD?.documentsCount || 0} 篇文档`);
661
662
  if (result.channelC.errors > 0) {
662
663
  console.log(` ⚠️ ${result.channelC.errors} 个错误`);
663
664
  }
@@ -181,7 +181,8 @@ export class UpgradeService {
181
181
  pipeline.deliver()
182
182
  .then(result => {
183
183
  console.log(` ✅ Cursor Delivery: ${result.channelA.rulesCount} rules, ` +
184
- `${result.channelB.topicCount} topics, ${result.channelC.synced} skills`);
184
+ `${result.channelB.topicCount} topics, ${result.channelC.synced} skills, ` +
185
+ `${result.channelD?.documentsCount || 0} documents`);
185
186
  })
186
187
  .catch(err => {
187
188
  console.log(` ⚠️ Cursor Delivery 跳过: ${err.message}`);
@@ -85,6 +85,7 @@ const KIND_MAP = {
85
85
  'call-chain': 'fact',
86
86
  'data-flow': 'fact',
87
87
  'module-dependency': 'fact',
88
+ 'dev-document': 'fact',
88
89
  };
89
90
 
90
91
  /**
@@ -163,6 +163,7 @@ export class McpServer {
163
163
  case 'autosnippet_submit_knowledge': return knowledgeHandlers.submitKnowledge(ctx, args);
164
164
  case 'autosnippet_submit_knowledge_batch': return knowledgeHandlers.submitKnowledgeBatch(ctx, args);
165
165
  case 'autosnippet_knowledge_lifecycle': return knowledgeHandlers.knowledgeLifecycle(ctx, args);
166
+ case 'autosnippet_save_document': return knowledgeHandlers.saveDocument(ctx, args);
166
167
  default: throw new Error(`Unknown tool: ${name}`);
167
168
  }
168
169
  }
@@ -1108,7 +1108,8 @@ export async function fillDimensionsV3(fillContext) {
1108
1108
  logger.info(`[Bootstrap-v3] 🚀 Cursor Delivery complete — ` +
1109
1109
  `A: ${deliveryResult.channelA.rulesCount} rules, ` +
1110
1110
  `B: ${deliveryResult.channelB.topicCount} topics, ` +
1111
- `C: ${deliveryResult.channelC.synced} skills`);
1111
+ `C: ${deliveryResult.channelC.synced} skills, ` +
1112
+ `D: ${deliveryResult.channelD?.documentsCount || 0} documents`);
1112
1113
  }
1113
1114
  } catch (deliveryErr) {
1114
1115
  logger.warn(`[Bootstrap-v3] Cursor Delivery failed (non-blocking): ${deliveryErr.message}`);
@@ -237,6 +237,80 @@ export async function knowledgeLifecycle(ctx, args) {
237
237
 
238
238
  // ─── 内部辅助 ──────────────────────────────────────────────
239
239
 
240
+ /**
241
+ * 保存开发文档 (autosnippet_save_document)
242
+ *
243
+ * 精简入口:仅需 title + markdown。
244
+ * 自动设置 knowledgeType='dev-document', kind='fact', source='agent'。
245
+ * 不走 RecipeReadiness 检查(文档无需 doClause/trigger)。
246
+ * 支持 autoApprove — 文档直接进入 active 状态。
247
+ */
248
+ export async function saveDocument(ctx, args) {
249
+ if (!args.title || !args.title.trim()) {
250
+ throw new Error('title 必填');
251
+ }
252
+ if (!args.markdown || !args.markdown.trim()) {
253
+ throw new Error('markdown 必填');
254
+ }
255
+
256
+ // 限流
257
+ const blocked = await _checkRateLimit('autosnippet_save_document', args.client_id);
258
+ if (blocked) return blocked;
259
+
260
+ const service = ctx.container.get('knowledgeService');
261
+
262
+ const data = {
263
+ title: args.title.trim(),
264
+ description: args.description || '',
265
+ knowledgeType: 'dev-document',
266
+ kind: 'fact',
267
+ source: args.source || 'agent',
268
+ scope: args.scope || 'project-specific',
269
+ tags: args.tags || [],
270
+ content: {
271
+ markdown: args.markdown,
272
+ pattern: '',
273
+ },
274
+ // 文档不需要 Cursor Delivery 字段
275
+ trigger: '',
276
+ doClause: '',
277
+ dontClause: '',
278
+ whenClause: '',
279
+ topicHint: '',
280
+ coreCode: '',
281
+ // 基础推理
282
+ reasoning: {
283
+ whyStandard: 'Agent development document — preserved for team knowledge',
284
+ sources: ['agent'],
285
+ confidence: 0.8,
286
+ },
287
+ };
288
+
289
+ const entry = await service.create(data, { userId: 'mcp' });
290
+
291
+ // 自动发布(dev-document 不需要人工审核)
292
+ try {
293
+ await service.publish(entry.id, { userId: 'mcp' });
294
+ } catch {
295
+ // 发布失败保持 pending — 非阻塞
296
+ }
297
+
298
+ return envelope({
299
+ success: true,
300
+ data: {
301
+ id: entry.id,
302
+ lifecycle: 'active',
303
+ title: entry.title,
304
+ kind: 'fact',
305
+ knowledgeType: 'dev-document',
306
+ },
307
+ message: `文档「${entry.title}」已保存到知识库。`,
308
+ meta: { tool: 'autosnippet_save_document' },
309
+ });
310
+ }
311
+
312
+ // ─── 内部辅助 ──────────────────────────────────────────────
313
+
240
314
  /**
241
315
  * V3 wire format → RecipeReadinessChecker 兼容格式
242
316
  */
@@ -23,6 +23,7 @@ export const TOOL_GATEWAY_MAP = {
23
23
  autosnippet_submit_knowledge: { action: 'knowledge:create', resource: 'knowledge' },
24
24
  autosnippet_submit_knowledge_batch: { action: 'knowledge:create', resource: 'knowledge' },
25
25
  autosnippet_knowledge_lifecycle: { action: 'knowledge:update', resource: 'knowledge' },
26
+ autosnippet_save_document: { action: 'knowledge:create', resource: 'knowledge' },
26
27
  };
27
28
 
28
29
  export const TOOLS = [
@@ -751,4 +752,26 @@ export const TOOLS = [
751
752
  required: ['id', 'action'],
752
753
  },
753
754
  },
755
+ // 39. 保存开发文档
756
+ {
757
+ name: 'autosnippet_save_document',
758
+ description:
759
+ '保存开发文档到知识库(架构设计、排查报告、决策记录、调研笔记等)。\n' +
760
+ '仅需 title + markdown,无需填写 kind/doClause/trigger 等 Cursor Delivery 字段。\n' +
761
+ '文档自动以 dev-document 类型存储,不参与 Cursor Rules 压缩,保持原文完整性。\n' +
762
+ '交付路径: Channel D → .cursor/skills/autosnippet-devdocs/references/*.md。\n' +
763
+ 'Agent 可通过 autosnippet_search 全文检索已保存的文档。',
764
+ inputSchema: {
765
+ type: 'object',
766
+ properties: {
767
+ title: { type: 'string', description: '文档标题(中英文皆可)' },
768
+ markdown: { type: 'string', description: '文档 Markdown 全文' },
769
+ description: { type: 'string', description: '一句话摘要(可选)' },
770
+ tags: { type: 'array', items: { type: 'string' }, description: '标签列表,如 ["adr", "debug-report", "design-doc", "research"]' },
771
+ scope: { type: 'string', enum: ['universal', 'project-specific'], default: 'project-specific', description: '适用范围' },
772
+ source: { type: 'string', description: '来源标识(默认 agent)' },
773
+ },
774
+ required: ['title', 'markdown'],
775
+ },
776
+ },
754
777
  ];
@@ -1844,6 +1844,68 @@ const submitCandidate = {
1844
1844
  },
1845
1845
  };
1846
1846
 
1847
+ // ────────────────────────────────────────────────────────────
1848
+ // 16b. save_document — 保存开发文档到知识库
1849
+ // ────────────────────────────────────────────────────────────
1850
+ const saveDocument = {
1851
+ name: 'save_document',
1852
+ description: '保存开发文档到知识库(架构设计、排查报告、决策记录、调研笔记等)。仅需 title + markdown,无需 Cursor Delivery 字段。文档自动发布,可通过 autosnippet_search 检索。',
1853
+ parameters: {
1854
+ type: 'object',
1855
+ properties: {
1856
+ title: { type: 'string', description: '文档标题' },
1857
+ markdown: { type: 'string', description: '文档 Markdown 全文' },
1858
+ description: { type: 'string', description: '一句话摘要(可选)' },
1859
+ tags: { type: 'array', items: { type: 'string' }, description: '标签: adr, debug-report, design-doc, research, performance 等' },
1860
+ scope: { type: 'string', enum: ['universal', 'project-specific'], description: '适用范围(默认 project-specific)' },
1861
+ },
1862
+ required: ['title', 'markdown'],
1863
+ },
1864
+ handler: async (params, ctx) => {
1865
+ const knowledgeService = ctx.container.get('knowledgeService');
1866
+
1867
+ const data = {
1868
+ title: params.title.trim(),
1869
+ description: params.description || '',
1870
+ knowledgeType: 'dev-document',
1871
+ kind: 'fact',
1872
+ source: 'agent',
1873
+ scope: params.scope || 'project-specific',
1874
+ tags: params.tags || [],
1875
+ content: {
1876
+ markdown: params.markdown,
1877
+ pattern: '',
1878
+ },
1879
+ trigger: '',
1880
+ doClause: '',
1881
+ dontClause: '',
1882
+ whenClause: '',
1883
+ topicHint: '',
1884
+ coreCode: '',
1885
+ reasoning: {
1886
+ whyStandard: 'Agent development document',
1887
+ sources: ['agent'],
1888
+ confidence: 0.8,
1889
+ },
1890
+ };
1891
+
1892
+ const saved = await knowledgeService.create(data, { userId: 'agent' });
1893
+
1894
+ // 自动发布(文档不需要人工审核)
1895
+ try {
1896
+ await knowledgeService.publish(saved.id, { userId: 'agent' });
1897
+ } catch { /* best effort */ }
1898
+
1899
+ return {
1900
+ id: saved.id,
1901
+ title: saved.title,
1902
+ lifecycle: 'active',
1903
+ knowledgeType: 'dev-document',
1904
+ message: `文档「${saved.title}」已保存到知识库`,
1905
+ };
1906
+ },
1907
+ };
1908
+
1847
1909
  // ────────────────────────────────────────────────────────────
1848
1910
  // 17. approve_candidate
1849
1911
  // ────────────────────────────────────────────────────────────
@@ -3273,6 +3335,7 @@ export const ALL_TOOLS = [
3273
3335
  generateGuardRule,
3274
3336
  // 生命周期操作类 (7)
3275
3337
  submitCandidate,
3338
+ saveDocument,
3276
3339
  approveCandidate,
3277
3340
  rejectCandidate,
3278
3341
  publishRecipe,
@@ -16,6 +16,7 @@ import { RulesGenerator } from './RulesGenerator.js';
16
16
  import { SkillsSyncer } from './SkillsSyncer.js';
17
17
  import { estimateTokens, BUDGET } from './TokenBudget.js';
18
18
  import path from 'node:path';
19
+ import fs from 'node:fs';
19
20
 
20
21
  export class CursorDeliveryPipeline {
21
22
  /**
@@ -48,6 +49,7 @@ export class CursorDeliveryPipeline {
48
49
  channelA: { rulesCount: 0, tokensUsed: 0 },
49
50
  channelB: { topicCount: 0, patternsCount: 0, totalTokens: 0 },
50
51
  channelC: { synced: 0, skipped: 0, errors: 0 },
52
+ channelD: { documentsCount: 0, filesWritten: 0 },
51
53
  totalTokensUsed: 0,
52
54
  duration: 0,
53
55
  };
@@ -57,9 +59,9 @@ export class CursorDeliveryPipeline {
57
59
  const entries = await this._loadEntries();
58
60
  this.logger.info?.(`[CursorDelivery] Loaded ${entries.length} knowledge entries`);
59
61
 
60
- // 2. 分类:rules vs patterns vs facts
61
- const { rules, patterns } = this._classify(entries);
62
- this.logger.info?.(`[CursorDelivery] Classified: ${rules.length} rules, ${patterns.length} patterns`);
62
+ // 2. 分类:rules vs patterns vs facts vs documents
63
+ const { rules, patterns, documents } = this._classify(entries);
64
+ this.logger.info?.(`[CursorDelivery] Classified: ${rules.length} rules, ${patterns.length} patterns, ${documents.length} documents`);
63
65
 
64
66
  // 3. 清理旧的动态生成文件
65
67
  this.rulesGenerator.cleanDynamicFiles();
@@ -76,6 +78,10 @@ export class CursorDeliveryPipeline {
76
78
  const channelC = await this._generateChannelC();
77
79
  stats.channelC = channelC;
78
80
 
81
+ // ── Channel D: Dev Documents → references ──
82
+ const channelD = this._generateChannelD(documents);
83
+ stats.channelD = channelD;
84
+
79
85
  // 统计
80
86
  stats.totalTokensUsed = channelA.tokensUsed + channelB.totalTokens;
81
87
  stats.duration = Date.now() - startTime;
@@ -83,9 +89,10 @@ export class CursorDeliveryPipeline {
83
89
  this.logger.info?.(`[CursorDelivery] Done in ${stats.duration}ms — ` +
84
90
  `A: ${channelA.rulesCount} rules (${channelA.tokensUsed} tokens), ` +
85
91
  `B: ${channelB.topicCount} topics (${channelB.totalTokens} tokens), ` +
86
- `C: ${channelC.synced} skills synced`);
92
+ `C: ${channelC.synced} skills synced, ` +
93
+ `D: ${channelD.documentsCount} documents`);
87
94
 
88
- return { channelA, channelB, channelC, stats };
95
+ return { channelA, channelB, channelC, channelD, stats };
89
96
  } catch (error) {
90
97
  this.logger.error?.(`[CursorDelivery] Error: ${error.message}`);
91
98
  throw error;
@@ -146,16 +153,23 @@ export class CursorDeliveryPipeline {
146
153
 
147
154
  /**
148
155
  * 按 kind 分类知识条目
156
+ * dev-document 类型单独分流,不进入 Channel A/B 压缩
149
157
  * @private
150
158
  */
151
159
  _classify(entries) {
152
- const rules = [], patterns = [], facts = [];
160
+ const rules = [], patterns = [], facts = [], documents = [];
153
161
  for (const entry of entries) {
154
- if (entry.kind === 'rule') rules.push(entry);
155
- else if (entry.kind === 'fact') facts.push(entry);
156
- else patterns.push(entry); // 无 kind kind='pattern' → pattern
162
+ if (entry.knowledgeType === 'dev-document') {
163
+ documents.push(entry);
164
+ } else if (entry.kind === 'rule') {
165
+ rules.push(entry);
166
+ } else if (entry.kind === 'fact') {
167
+ facts.push(entry);
168
+ } else {
169
+ patterns.push(entry); // 无 kind 或 kind='pattern' → pattern
170
+ }
157
171
  }
158
- return { rules, patterns, facts };
172
+ return { rules, patterns, facts, documents };
159
173
  }
160
174
 
161
175
  /**
@@ -267,6 +281,98 @@ export class CursorDeliveryPipeline {
267
281
  }
268
282
  }
269
283
 
284
+ /**
285
+ * Channel D — Dev Documents 生成
286
+ * 将 knowledgeType='dev-document' 的条目以原始 MD 写入
287
+ * .cursor/skills/autosnippet-devdocs/references/ 目录
288
+ * @private
289
+ */
290
+ _generateChannelD(documents) {
291
+ const result = { documentsCount: 0, filesWritten: 0, filePaths: [] };
292
+ if (!documents || documents.length === 0) {
293
+ return result;
294
+ }
295
+
296
+ const devdocsDir = path.join(this.projectRoot, '.cursor', 'skills', 'autosnippet-devdocs');
297
+ const refsDir = path.join(devdocsDir, 'references');
298
+ fs.mkdirSync(refsDir, { recursive: true });
299
+
300
+ // 生成 SKILL.md(索引页)
301
+ const skillLines = [
302
+ '---',
303
+ 'name: autosnippet-devdocs',
304
+ `description: "Development documents and knowledge artifacts for ${this.projectName}. Use when looking up architecture decisions, debug reports, design docs, or analysis notes."`,
305
+ '---',
306
+ '',
307
+ `# Dev Documents — ${this.projectName}`,
308
+ '',
309
+ 'Use this skill when:',
310
+ '- Looking up architecture decisions or design rationale',
311
+ '- Reviewing debug reports or performance analysis',
312
+ '- Finding previous research or investigation notes',
313
+ '- Understanding project-specific decisions and trade-offs',
314
+ '',
315
+ '## Document Index',
316
+ '',
317
+ '| Title | Tags | Updated |',
318
+ '|-------|------|---------|',
319
+ ];
320
+
321
+ for (const doc of documents) {
322
+ const tags = (doc.tags || []).join(', ') || '-';
323
+ const updated = doc.updatedAt
324
+ ? new Date(doc.updatedAt * 1000).toISOString().split('T')[0]
325
+ : '-';
326
+ const slug = this._slugify(doc.title || doc.id);
327
+ skillLines.push(`| [${doc.title}](references/${slug}.md) | ${tags} | ${updated} |`);
328
+
329
+ // 写入单个文档 MD
330
+ const markdown = doc.content?.markdown || doc.description || '';
331
+ const docContent = [
332
+ `# ${doc.title || 'Untitled'}`,
333
+ '',
334
+ doc.description ? `> ${doc.description}` : '',
335
+ '',
336
+ `**Tags:** ${tags} `,
337
+ `**Scope:** ${doc.scope || 'universal'} `,
338
+ `**Created:** ${doc.createdAt ? new Date(doc.createdAt * 1000).toISOString().split('T')[0] : '-'}`,
339
+ '',
340
+ '---',
341
+ '',
342
+ markdown,
343
+ ].filter(Boolean).join('\n');
344
+
345
+ const docPath = path.join(refsDir, `${slug}.md`);
346
+ fs.writeFileSync(docPath, docContent, 'utf8');
347
+ result.filePaths.push(docPath);
348
+ result.filesWritten++;
349
+ }
350
+
351
+ skillLines.push('');
352
+ skillLines.push('## Deeper Knowledge');
353
+ skillLines.push('');
354
+ skillLines.push('For full-text search across all documents:');
355
+ skillLines.push('- `autosnippet_search("your query")`');
356
+
357
+ fs.writeFileSync(path.join(devdocsDir, 'SKILL.md'), skillLines.join('\n') + '\n', 'utf8');
358
+ result.documentsCount = documents.length;
359
+
360
+ this.logger.info?.(`[CursorDelivery] Channel D: ${result.documentsCount} documents → ${refsDir}`);
361
+ return result;
362
+ }
363
+
364
+ /**
365
+ * 文件名安全 slug 化
366
+ * @private
367
+ */
368
+ _slugify(text) {
369
+ return text
370
+ .toLowerCase()
371
+ .replace(/[^a-z0-9\u4e00-\u9fff]+/g, '-')
372
+ .replace(/^-+|-+$/g, '')
373
+ .substring(0, 80) || 'untitled';
374
+ }
375
+
270
376
  /**
271
377
  * 从项目路径推断项目名称
272
378
  * @private
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "autosnippet",
3
- "version": "2.13.0",
3
+ "version": "2.14.0",
4
4
  "description": "AutoSnippet - 连接开发者、AI 与项目知识库的工具",
5
5
  "type": "module",
6
6
  "main": "lib/bootstrap.js",
@@ -82,7 +82,7 @@ Every candidate submitted via `submit_candidate` or `submit_candidates` supports
82
82
  | Field | Type | Values / Example |
83
83
  |-------|------|-----------------|
84
84
  | **category** | string | View / Service / Tool / Model / Network / Storage / UI / Utility |
85
- | **knowledgeType** | string | `code-pattern` \| `architecture` \| `best-practice` \| `code-standard` \| `code-relation` \| `inheritance` \| `call-chain` \| `data-flow` \| `module-dependency` \| `boundary-constraint` \| `code-style` \| `solution` |
85
+ | **knowledgeType** | string | `code-pattern` \| `architecture` \| `best-practice` \| `code-standard` \| `code-relation` \| `inheritance` \| `call-chain` \| `data-flow` \| `module-dependency` \| `boundary-constraint` \| `code-style` \| `solution` \| `dev-document` |
86
86
  | **complexity** | string | `beginner` \| `intermediate` \| `advanced` |
87
87
  | **scope** | string | `universal` (通用) \| `project-specific` (本项目) \| `target-specific` (特定 Target) |
88
88
  | **tags** | string[] | `["networking", "async-await", "error-handling"]` |
@@ -165,6 +165,7 @@ Watch parses all such blocks and adds each as a separate candidate; prompt may s
165
165
  | `autosnippet_submit_knowledge_batch` | Submit draft .md as candidates: prefer draft folder + multiple files (not one big file); supports intro-only docs (no code—no Snippet). Pass `filePaths`, optional `targetName`, `deleteAfterSubmit`. **Delete the draft folder after submit** (e.g. `deleteAfterSubmit: true` or `rm -rf .autosnippet-drafts`). |
166
166
  | `autosnippet_submit_knowledge_batch` | Submit structured items (title, summary, trigger, language, code, usageGuide) for batch scan, etc. |
167
167
  | `autosnippet_submit_knowledge` | Submit single structured candidate with full V3 fields. |
168
+ | `autosnippet_save_document` | Save a development document (design doc, debug report, ADR) — only needs title + markdown. See **autosnippet-devdocs** skill. |
168
169
  | `autosnippet_validate_candidate` | Pre-validate candidate quality before submission. |
169
170
  | `autosnippet_check_duplicate` | Check for duplicate Recipes before submission. |
170
171
 
@@ -0,0 +1,90 @@
1
+ ---
2
+ name: autosnippet-devdocs
3
+ description: Teaches the agent how to save development documents (architecture decisions, debug reports, design docs, research notes) to the AutoSnippet knowledge base using autosnippet_save_document. Use when the agent finishes analysis, debugging, design, or research and wants to persist the findings.
4
+ ---
5
+
6
+ # AutoSnippet — Save Development Documents
7
+
8
+ This skill tells the agent how to **save development documents** (architecture decisions, debug reports, design docs, research notes) to the AutoSnippet knowledge base, so they can be retrieved by future sessions.
9
+
10
+ ## When to use this skill
11
+
12
+ - After finishing a **debug/troubleshooting session** — save the root cause analysis
13
+ - After making an **architecture or design decision** — save the ADR (Architecture Decision Record)
14
+ - After completing a **research or investigation** — save findings and conclusions
15
+ - After a **performance analysis** — save the benchmark results and optimization notes
16
+ - When the user says "保存这个分析" / "记录一下" / "save this to KB"
17
+
18
+ ## MCP Tool
19
+
20
+ | Tool | Description |
21
+ |------|-------------|
22
+ | `autosnippet_save_document` | Save a development document to KB. Only needs `title` + `markdown`. Auto-published, no review needed. |
23
+ | `autosnippet_search` | Search saved documents by keyword or semantic query. |
24
+
25
+ ## How to save a document
26
+
27
+ Call `autosnippet_save_document` with:
28
+
29
+ ```json
30
+ {
31
+ "title": "BiliDemo 冷启动性能分析",
32
+ "markdown": "## 问题背景\n\n冷启动耗时 8s...\n\n## 根因分析\n\n...\n\n## 解决方案\n\n...",
33
+ "description": "冷启动耗时 8s 的根因分析和优化方案",
34
+ "tags": ["debug-report", "performance"],
35
+ "scope": "project-specific"
36
+ }
37
+ ```
38
+
39
+ ### Required fields
40
+
41
+ | Field | Description |
42
+ |-------|-------------|
43
+ | `title` | Document title (Chinese or English) |
44
+ | `markdown` | Full Markdown content |
45
+
46
+ ### Optional fields
47
+
48
+ | Field | Default | Description |
49
+ |-------|---------|-------------|
50
+ | `description` | `""` | One-line summary |
51
+ | `tags` | `[]` | Labels for filtering: `adr`, `debug-report`, `design-doc`, `research`, `performance`, `refactoring` |
52
+ | `scope` | `project-specific` | `universal` or `project-specific` |
53
+
54
+ ## Recommended tags
55
+
56
+ | Tag | Use case |
57
+ |-----|----------|
58
+ | `adr` | Architecture Decision Record |
59
+ | `debug-report` | Bug investigation / root cause analysis |
60
+ | `design-doc` | Module/feature design document |
61
+ | `research` | Technology research or investigation |
62
+ | `performance` | Benchmark results, profiling analysis |
63
+ | `refactoring` | Refactoring plan or post-mortem |
64
+ | `migration` | Migration guide or plan |
65
+ | `meeting-notes` | Technical meeting summary |
66
+
67
+ ## How documents are delivered to Cursor
68
+
69
+ Documents are stored as `knowledgeType: 'dev-document'` in the knowledge DB. They follow a dedicated delivery path:
70
+
71
+ 1. **NOT compressed** into Cursor Rules (Channel A/B skip dev-documents)
72
+ 2. **Full text** written to `.cursor/skills/autosnippet-devdocs/references/*.md` (Channel D)
73
+ 3. **Searchable** via `autosnippet_search("your query")` — full-text search hits documents
74
+
75
+ ## Document format tips
76
+
77
+ - Use **clear headings** (`##`, `###`) — helps search and scanning
78
+ - Include a **summary section** at the top
79
+ - Reference **file paths** and **class names** concretely — improves search relevance
80
+ - For ADRs, use the structure: Context → Decision → Consequences
81
+ - For debug reports: Symptom → Investigation → Root Cause → Fix
82
+
83
+ ## Relation to other skills
84
+
85
+ | Skill | When to use |
86
+ |-------|-------------|
87
+ | `autosnippet-create` | Saving **code patterns/recipes** (needs trigger, doClause, etc.) |
88
+ | `autosnippet-devdocs` (this) | Saving **prose documents** (only needs title + markdown) |
89
+ | `autosnippet-recipes` | Looking up existing knowledge |
90
+ | `autosnippet-concepts` | Understanding AutoSnippet concepts |
@@ -112,6 +112,7 @@ Recipe is the core knowledge unit. V3 uses a unified structured model:
112
112
  | autosnippet_submit_knowledge | Submit single candidate (supports structured content) |
113
113
  | autosnippet_submit_knowledge_batch | Batch submit candidates |
114
114
  | autosnippet_submit_knowledge_batch | Submit draft .md files as candidates |
115
+ | autosnippet_save_document | Save development document (design doc, debug report, ADR) — title + markdown only |
115
116
  | autosnippet_validate_candidate | Validate candidate quality |
116
117
  | autosnippet_check_duplicate | Dedup check |
117
118
  | autosnippet_enrich_candidates | AI semantic field enrichment for candidates |