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.
Files changed (72) hide show
  1. package/bin/cli.js +35 -0
  2. package/dashboard/dist/assets/{icons-Dtm0E6DS.js → icons-Cq4-iQhP.js} +152 -87
  3. package/dashboard/dist/assets/index-DBxH7pVn.css +1 -0
  4. package/dashboard/dist/assets/index-Dw2F6qAS.js +197 -0
  5. package/dashboard/dist/assets/{react-markdown-CWxUbOf4.js → react-markdown-BA6FB2NP.js} +1 -1
  6. package/dashboard/dist/assets/{syntax-highlighter-CJ2drQQb.js → syntax-highlighter-CVLHn9O5.js} +1 -1
  7. package/dashboard/dist/assets/{vendor-f83ah6cm.js → vendor-BotF760a.js} +61 -61
  8. package/dashboard/dist/index.html +6 -6
  9. package/lib/bootstrap.js +1 -1
  10. package/lib/cli/SetupService.js +33 -8
  11. package/lib/cli/UpgradeService.js +139 -2
  12. package/lib/core/ast/ProjectGraph.js +599 -0
  13. package/lib/core/gateway/Gateway.js +19 -4
  14. package/lib/core/gateway/GatewayActionRegistry.js +2 -2
  15. package/lib/domain/recipe/Recipe.js +3 -0
  16. package/lib/external/ai/AiProvider.js +117 -10
  17. package/lib/external/ai/providers/ClaudeProvider.js +197 -0
  18. package/lib/external/ai/providers/GoogleGeminiProvider.js +235 -1
  19. package/lib/external/ai/providers/OpenAiProvider.js +131 -0
  20. package/lib/external/mcp/McpServer.js +2 -1
  21. package/lib/external/mcp/handlers/bootstrap/pipeline/dimension-context.js +216 -0
  22. package/lib/external/mcp/handlers/bootstrap/pipeline/orchestrator.js +468 -0
  23. package/lib/external/mcp/handlers/bootstrap/pipeline/tier-scheduler.js +162 -0
  24. package/lib/external/mcp/handlers/bootstrap/skills.js +225 -0
  25. package/lib/external/mcp/handlers/bootstrap.js +151 -1634
  26. package/lib/external/mcp/handlers/browse.js +1 -1
  27. package/lib/external/mcp/handlers/candidate.js +1 -33
  28. package/lib/external/mcp/handlers/skill.js +126 -31
  29. package/lib/external/mcp/tools.js +25 -3
  30. package/lib/http/middleware/requestLogger.js +23 -4
  31. package/lib/http/routes/ai.js +3 -1
  32. package/lib/http/routes/auth.js +3 -2
  33. package/lib/http/routes/candidates.js +49 -25
  34. package/lib/http/routes/commands.js +0 -8
  35. package/lib/http/routes/guardRules.js +1 -16
  36. package/lib/http/routes/recipes.js +4 -17
  37. package/lib/http/routes/search.js +16 -22
  38. package/lib/http/routes/skills.js +40 -3
  39. package/lib/http/routes/snippets.js +0 -33
  40. package/lib/http/routes/spm.js +37 -63
  41. package/lib/http/utils/routeHelpers.js +31 -0
  42. package/lib/infrastructure/audit/AuditStore.js +18 -0
  43. package/lib/infrastructure/config/Paths.js +9 -0
  44. package/lib/infrastructure/logging/Logger.js +86 -3
  45. package/lib/infrastructure/realtime/RealtimeService.js +2 -5
  46. package/lib/infrastructure/vector/JsonVectorAdapter.js +24 -1
  47. package/lib/injection/ServiceContainer.js +62 -3
  48. package/lib/service/bootstrap/BootstrapTaskManager.js +400 -0
  49. package/lib/service/candidate/CandidateFileWriter.js +68 -27
  50. package/lib/service/candidate/CandidateService.js +156 -10
  51. package/lib/service/chat/AnalystAgent.js +216 -0
  52. package/lib/service/chat/CandidateGuardrail.js +134 -0
  53. package/lib/service/chat/ChatAgent.js +1272 -155
  54. package/lib/service/chat/ContextWindow.js +730 -0
  55. package/lib/service/chat/ConversationStore.js +377 -0
  56. package/lib/service/chat/HandoffProtocol.js +180 -0
  57. package/lib/service/chat/Memory.js +40 -10
  58. package/lib/service/chat/ProducerAgent.js +240 -0
  59. package/lib/service/chat/ToolRegistry.js +149 -5
  60. package/lib/service/chat/tools.js +1493 -60
  61. package/lib/service/recipe/RecipeFileWriter.js +12 -1
  62. package/lib/service/skills/EventAggregator.js +187 -0
  63. package/lib/service/skills/SignalCollector.js +549 -0
  64. package/lib/service/skills/SkillAdvisor.js +324 -0
  65. package/lib/service/skills/SkillHooks.js +13 -5
  66. package/lib/service/spm/SpmService.js +2 -2
  67. package/package.json +1 -1
  68. package/templates/copilot-instructions.md +20 -3
  69. package/templates/cursor-rules/autosnippet-conventions.mdc +21 -4
  70. package/templates/cursor-rules/autosnippet-skills.mdc +45 -0
  71. package/dashboard/dist/assets/index-B7VpZOCz.css +0 -1
  72. package/dashboard/dist/assets/index-D87IZTmZ.js +0 -187
@@ -5,14 +5,14 @@
5
5
  <link rel="icon" type="image/svg+xml" href="/vite.svg" />
6
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
7
  <title>AutoSnippet Dashboard</title>
8
- <script type="module" crossorigin src="/assets/index-D87IZTmZ.js"></script>
8
+ <script type="module" crossorigin src="/assets/index-Dw2F6qAS.js"></script>
9
9
  <link rel="modulepreload" crossorigin href="/assets/yaml-qRaU8Ldn.js">
10
- <link rel="modulepreload" crossorigin href="/assets/vendor-f83ah6cm.js">
10
+ <link rel="modulepreload" crossorigin href="/assets/vendor-BotF760a.js">
11
11
  <link rel="modulepreload" crossorigin href="/assets/axios-C0Zqfgkc.js">
12
- <link rel="modulepreload" crossorigin href="/assets/icons-Dtm0E6DS.js">
13
- <link rel="modulepreload" crossorigin href="/assets/syntax-highlighter-CJ2drQQb.js">
14
- <link rel="modulepreload" crossorigin href="/assets/react-markdown-CWxUbOf4.js">
15
- <link rel="stylesheet" crossorigin href="/assets/index-B7VpZOCz.css">
12
+ <link rel="modulepreload" crossorigin href="/assets/icons-Cq4-iQhP.js">
13
+ <link rel="modulepreload" crossorigin href="/assets/syntax-highlighter-CVLHn9O5.js">
14
+ <link rel="modulepreload" crossorigin href="/assets/react-markdown-BA6FB2NP.js">
15
+ <link rel="stylesheet" crossorigin href="/assets/index-DBxH7pVn.css">
16
16
  </head>
17
17
  <body>
18
18
  <div id="root"></div>
package/lib/bootstrap.js CHANGED
@@ -152,7 +152,7 @@ export class Bootstrap {
152
152
  this.components.auditLogger = auditLogger;
153
153
  logger.info('Audit system initialized');
154
154
 
155
- // Skill Hooks (扫描 skills/*/hooks.js + .autosnippet/skills/*/hooks.js)
155
+ // Skill Hooks (扫描 skills/*/hooks.js + AutoSnippet/skills/*/hooks.js)
156
156
  const skillHooks = new SkillHooks();
157
157
  await skillHooks.load();
158
158
  this.components.skillHooks = skillHooks;
@@ -4,8 +4,8 @@
4
4
  * 一键初始化 AutoSnippet V2 工作空间,5 步完成:
5
5
  *
6
6
  * Step 1 .autosnippet/ 运行时目录 + config.json + .gitignore
7
- * Step 2 AutoSnippet/ 子仓库(核心数据 + 权限能力)
8
- * Step 3 IDE 集成(VSCode MCP + Cursor MCP + copilot-instructions + cursor-rules)
7
+ * Step 2 AutoSnippet/ 子仓库(核心数据 + 权限能力 + skills/)
8
+ * Step 3 IDE 集成(VSCode MCP + Cursor MCP + copilot-instructions + cursor-rules + skills-template
9
9
  * Step 4 SQLite 数据库 + V1 数据迁移
10
10
  * Step 5 平台相关初始化(macOS → Xcode Snippets)
11
11
  *
@@ -17,6 +17,7 @@
17
17
  * ├─ constitution.yaml 权限宪法:角色 + 权限矩阵 + 治理规则 + 能力探测
18
18
  * ├─ boxspec.json 项目规格定义
19
19
  * ├─ recipes/*.md 统一知识实体(代码规范/模式/架构/调用链/数据流/...)
20
+ * ├─ skills/ Project Skills(冷启动自动生成 + 手动创建)
20
21
  * └─ README.md
21
22
  *
22
23
  * .autosnippet/ (运行时缓存,gitignored)
@@ -76,6 +77,7 @@ export class SetupService {
76
77
  this.coreDir = join(this.projectRoot, 'AutoSnippet');
77
78
  this.recipesDir = join(this.coreDir, 'recipes');
78
79
  this.candidatesDir = join(this.coreDir, 'candidates');
80
+ this.skillsDir = join(this.coreDir, 'skills');
79
81
  }
80
82
 
81
83
  /* ═══ 公共入口 ═══════════════════════════════════════ */
@@ -121,6 +123,7 @@ export class SetupService {
121
123
  console.log(' ├─ boxspec.json 项目规格');
122
124
  console.log(' ├─ recipes/*.md 统一知识实体 ← 受 git push 保护');
123
125
  console.log(' ├─ candidates/*.md 候选代码片段 ← 受 git push 保护');
126
+ console.log(' ├─ skills/ Project Skills(冷启动自动生成 + 手动创建)');
124
127
  console.log(' └─ *.json 运行数据(统计/反馈/规则学习/排除策略)');
125
128
  console.log(' .autosnippet/ 运行时缓存(gitignored)');
126
129
  console.log(' ├─ config.json 项目配置');
@@ -195,7 +198,7 @@ export class SetupService {
195
198
  const alreadyRepo = existsSync(coreGit);
196
199
 
197
200
  // 创建目录结构
198
- for (const d of [this.coreDir, this.recipesDir, this.candidatesDir]) {
201
+ for (const d of [this.coreDir, this.recipesDir, this.candidatesDir, this.skillsDir]) {
199
202
  mkdirSync(d, { recursive: true });
200
203
  }
201
204
 
@@ -366,6 +369,8 @@ export class SetupService {
366
369
  '│ ├── naming-rules.md 代码规范示例',
367
370
  '│ ├── mvvm-arch.md 架构模式示例',
368
371
  '│ └── ... 代码模式/调用链/数据流/约束/风格/...',
372
+ '├── skills/ Project Skills(冷启动自动生成 + 手动创建)',
373
+ '│ └── <name>/SKILL.md AI Agent 知识增强文档',
369
374
  '└── README.md',
370
375
  '```',
371
376
  '',
@@ -429,8 +434,9 @@ export class SetupService {
429
434
  this._configureCursorMCP(mcpServerPath);
430
435
  this._copyCopilotInstructions();
431
436
  this._copyCursorRules();
437
+ this._copySkillsTemplate();
432
438
 
433
- return { configured: ['vscode-mcp', 'cursor-mcp', 'copilot-instructions', 'cursor-rules'] };
439
+ return { configured: ['vscode-mcp', 'cursor-mcp', 'copilot-instructions', 'cursor-rules', 'skills-template'] };
434
440
  }
435
441
 
436
442
  /** @private VSCode settings.json → Copilot MCP */
@@ -519,6 +525,23 @@ export class SetupService {
519
525
  console.log(' ✅ .cursor/rules/autosnippet-conventions.mdc');
520
526
  }
521
527
 
528
+ /** @private .cursor/rules/autosnippet-skills.mdc — Project Skills 索引模板 */
529
+ _copySkillsTemplate() {
530
+ const src = join(REPO_ROOT, 'templates', 'cursor-rules', 'autosnippet-skills.mdc');
531
+ if (!existsSync(src)) return;
532
+
533
+ const destDir = join(this.projectRoot, '.cursor', 'rules');
534
+ const dest = join(destDir, 'autosnippet-skills.mdc');
535
+ if (existsSync(dest) && !this.force) {
536
+ console.log(' ℹ️ skills template 已存在');
537
+ return;
538
+ }
539
+
540
+ mkdirSync(destDir, { recursive: true });
541
+ copyFileSync(src, dest);
542
+ console.log(' ✅ .cursor/rules/autosnippet-skills.mdc');
543
+ }
544
+
522
545
  /* ═══ Step 4: 数据库初始化 ═══════════════════════════ */
523
546
 
524
547
  async stepDatabase() {
@@ -649,11 +672,13 @@ export class SetupService {
649
672
  console.log(' ✅ .gitignore += !.autosnippet/config.json');
650
673
  }
651
674
 
652
- // ── 必须跟踪:.autosnippet/skills/(项目级 Skill 文档) ──
653
- if (!content.includes('!.autosnippet/skills/')) {
654
- content += `!.autosnippet/skills/\n`;
675
+ // Skills 已迁移到 AutoSnippet/skills/(知识库目录内),自动跟随 Git
676
+
677
+ // ── 清理旧版本的 .autosnippet/skills/ negation(已迁移,不再需要)──
678
+ if (content.includes('!.autosnippet/skills/')) {
679
+ content = content.replace(/^!?\.autosnippet\/skills\/.*\n?/gm, '');
655
680
  changed = true;
656
- console.log(' ✅ .gitignore += !.autosnippet/skills/');
681
+ console.log(' ✅ .gitignore: 移除旧版 .autosnippet/skills/ 规则(已迁移到 AutoSnippet/skills/)');
657
682
  }
658
683
 
659
684
  // ── 必须跟踪:AutoSnippet/(知识库子仓库)──
@@ -4,14 +4,17 @@
4
4
  * 当 AutoSnippet 发布新版本后,老用户执行 `asd upgrade` 即可更新:
5
5
  * ① MCP 配置(.cursor/mcp.json + .vscode/settings.json)
6
6
  * ② Cursor Skills(.cursor/skills/)
7
- * ③ Cursor Rules(.cursor/rules/autosnippet-conventions.mdc)
7
+ * ③ Cursor Rules(.cursor/rules/autosnippet-conventions.mdc + autosnippet-skills.mdc
8
8
  * ④ Copilot Instructions(.github/copilot-instructions.md)
9
+ * ⑤ Constitution(AutoSnippet/constitution.yaml)
10
+ * ⑥ .gitignore(升级规则 + 清理旧版本残留)
11
+ * ⑦ Skills 路径迁移(.autosnippet/skills/ → AutoSnippet/skills/)
9
12
  *
10
13
  * 不会重建数据库、子仓库或运行时目录。
11
14
  */
12
15
 
13
16
  import {
14
- existsSync, mkdirSync, readFileSync, writeFileSync, copyFileSync,
17
+ existsSync, mkdirSync, readFileSync, writeFileSync, copyFileSync, readdirSync,
15
18
  } from 'fs';
16
19
  import { join, resolve, dirname } from 'path';
17
20
  import { fileURLToPath } from 'url';
@@ -39,8 +42,12 @@ export class UpgradeService {
39
42
  }
40
43
  if (!skillsOnly && !mcpOnly) {
41
44
  results.push(this._upgradeCursorRules());
45
+ results.push(this._upgradeSkillsTemplate());
42
46
  results.push(this._upgradeCopilotInstructions());
43
47
  results.push(this._upgradeConstitution());
48
+ results.push(this._upgradeGitignore());
49
+ results.push(this._migrateSkillsPath());
50
+ results.push(this._ensureSkillsDir());
44
51
  }
45
52
 
46
53
  console.log('');
@@ -217,6 +224,136 @@ export class UpgradeService {
217
224
  console.log(' cd AutoSnippet && git add constitution.yaml && git commit -m "Upgrade constitution" && git push');
218
225
  }
219
226
  }
227
+ /* ═══ Skills Template ════════════════════════════════ */
228
+
229
+ _upgradeSkillsTemplate() {
230
+ console.log('[Skills Template] 更新 autosnippet-skills.mdc...');
231
+
232
+ const src = join(REPO_ROOT, 'templates', 'cursor-rules', 'autosnippet-skills.mdc');
233
+ if (!existsSync(src)) {
234
+ console.log(' ⚠️ 模板不存在,跳过');
235
+ return;
236
+ }
237
+
238
+ const destDir = join(this.projectRoot, '.cursor', 'rules');
239
+ const dest = join(destDir, 'autosnippet-skills.mdc');
240
+ mkdirSync(destDir, { recursive: true });
241
+ copyFileSync(src, dest);
242
+ console.log(' ✅ .cursor/rules/autosnippet-skills.mdc');
243
+ }
244
+
245
+ /* ═══ .gitignore ════════════════════════════════════ */
246
+
247
+ _upgradeGitignore() {
248
+ console.log('[Gitignore] 更新 .gitignore 规则...');
249
+
250
+ const giPath = join(this.projectRoot, '.gitignore');
251
+ if (!existsSync(giPath)) {
252
+ console.log(' ℹ️ .gitignore 不存在,跳过');
253
+ return;
254
+ }
255
+
256
+ let content = readFileSync(giPath, 'utf8');
257
+ let changed = false;
258
+
259
+ // v2.4.0 迁移:旧格式 ".autosnippet/" → 新格式 ".autosnippet/*"
260
+ if (content.includes('.autosnippet/') && !content.includes('.autosnippet/*')) {
261
+ content = content.replace(/^\.autosnippet\/$/m, '.autosnippet/*');
262
+ changed = true;
263
+ console.log(' ✅ .autosnippet/ → .autosnippet/*(升级为精细忽略)');
264
+ }
265
+
266
+ // 确保有 .autosnippet/*
267
+ if (!content.includes('.autosnippet/') && !content.includes('.autosnippet/*')) {
268
+ content += `\n# AutoSnippet 运行时缓存(不入库)\n.autosnippet/*\n`;
269
+ changed = true;
270
+ console.log(' ✅ += .autosnippet/*');
271
+ }
272
+
273
+ // 确保 config.json 跟踪
274
+ if (!content.includes('!.autosnippet/config.json')) {
275
+ content += `!.autosnippet/config.json\n`;
276
+ changed = true;
277
+ console.log(' ✅ += !.autosnippet/config.json');
278
+ }
279
+
280
+ // 清理旧版本的 .autosnippet/skills/ negation(已迁移到 AutoSnippet/skills/)
281
+ if (content.includes('!.autosnippet/skills/')) {
282
+ content = content.replace(/^!?\.autosnippet\/skills\/.*\n?/gm, '');
283
+ changed = true;
284
+ console.log(' ✅ 移除旧版 .autosnippet/skills/ 规则(已迁移到 AutoSnippet/skills/)');
285
+ }
286
+
287
+ // 确保 AutoSnippet/ 不被忽略
288
+ const lines = content.split('\n');
289
+ const hasIgnoreAS = lines.some(l => {
290
+ const t = l.trim();
291
+ return (t === 'AutoSnippet/' || t === 'AutoSnippet') && !t.startsWith('#') && !t.startsWith('!');
292
+ });
293
+ const hasNegation = lines.some(l => l.trim() === '!AutoSnippet/');
294
+ if (hasIgnoreAS && !hasNegation) {
295
+ content += `\n# AutoSnippet 知识库必须入库(取消上方忽略)\n!AutoSnippet/\n`;
296
+ changed = true;
297
+ console.log(' ✅ += !AutoSnippet/ (取消忽略)');
298
+ }
299
+
300
+ if (changed) {
301
+ writeFileSync(giPath, content);
302
+ } else {
303
+ console.log(' ℹ️ .gitignore 已是最新版本');
304
+ }
305
+ }
306
+
307
+ /* ═══ Skills 路径迁移 ═══════════════════════════════ */
308
+
309
+ _migrateSkillsPath() {
310
+ const oldSkillsDir = join(this.projectRoot, '.autosnippet', 'skills');
311
+ const newSkillsDir = join(this.projectRoot, 'AutoSnippet', 'skills');
312
+
313
+ if (!existsSync(oldSkillsDir)) return;
314
+ if (!existsSync(join(this.projectRoot, 'AutoSnippet'))) return;
315
+
316
+ console.log('[Migration] 迁移 Skills: .autosnippet/skills/ → AutoSnippet/skills/...');
317
+
318
+ try {
319
+ mkdirSync(newSkillsDir, { recursive: true });
320
+ const entries = readdirSync(oldSkillsDir, { withFileTypes: true });
321
+ let migrated = 0;
322
+
323
+ for (const entry of entries) {
324
+ if (!entry.isDirectory()) continue;
325
+ const src = join(oldSkillsDir, entry.name);
326
+ const dest = join(newSkillsDir, entry.name);
327
+ if (existsSync(dest)) {
328
+ console.log(` ℹ️ ${entry.name} 已存在于新路径,跳过`);
329
+ continue;
330
+ }
331
+ // 复制目录
332
+ execSync(`cp -r "${src}" "${dest}"`, { stdio: 'pipe' });
333
+ migrated++;
334
+ }
335
+
336
+ if (migrated > 0) {
337
+ console.log(` ✅ 已迁移 ${migrated} 个 Skill 到 AutoSnippet/skills/`);
338
+ console.log(' 💡 确认迁移无误后可删除旧目录: rm -rf .autosnippet/skills/');
339
+ } else {
340
+ console.log(' ℹ️ 无需迁移(所有 Skill 已存在于新路径)');
341
+ }
342
+ } catch (e) {
343
+ console.error(` ❌ 迁移失败: ${e.message}`);
344
+ }
345
+ }
346
+
347
+ /* ═══ 确保 Skills 目录存在 ══════════════════════════ */
348
+
349
+ _ensureSkillsDir() {
350
+ const skillsDir = join(this.projectRoot, 'AutoSnippet', 'skills');
351
+ if (!existsSync(join(this.projectRoot, 'AutoSnippet'))) return;
352
+ if (existsSync(skillsDir)) return;
353
+
354
+ mkdirSync(skillsDir, { recursive: true });
355
+ console.log('[Skills] ✅ 创建 AutoSnippet/skills/ 目录');
356
+ }
220
357
  }
221
358
 
222
359
  export default UpgradeService;