autosnippet 2.9.0 → 2.10.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 (97) hide show
  1. package/README.md +4 -4
  2. package/bin/cli.js +5 -33
  3. package/config/constitution.yaml +9 -2
  4. package/dashboard/dist/assets/{icons-CH-H9x0E.js → icons-BkT3XrKf.js} +105 -100
  5. package/dashboard/dist/assets/index-BsB7DzW4.css +1 -0
  6. package/dashboard/dist/assets/index-DdmQMrJJ.js +155 -0
  7. package/dashboard/dist/index.html +3 -3
  8. package/lib/cli/AiScanService.js +13 -11
  9. package/lib/cli/KnowledgeSyncService.js +343 -0
  10. package/lib/cli/SetupService.js +8 -26
  11. package/lib/core/gateway/GatewayActionRegistry.js +48 -58
  12. package/lib/domain/index.js +16 -11
  13. package/lib/domain/knowledge/KnowledgeEntry.js +351 -0
  14. package/lib/domain/knowledge/KnowledgeRepository.js +123 -0
  15. package/lib/domain/knowledge/Lifecycle.js +109 -0
  16. package/lib/domain/knowledge/index.js +27 -0
  17. package/lib/domain/knowledge/values/Constraints.js +125 -0
  18. package/lib/domain/knowledge/values/Content.js +86 -0
  19. package/lib/domain/knowledge/values/Quality.js +93 -0
  20. package/lib/domain/knowledge/values/Reasoning.js +69 -0
  21. package/lib/domain/knowledge/values/Relations.js +168 -0
  22. package/lib/domain/knowledge/values/Stats.js +87 -0
  23. package/lib/domain/knowledge/values/index.js +9 -0
  24. package/lib/external/ai/AiProvider.js +48 -0
  25. package/lib/external/mcp/McpServer.js +7 -5
  26. package/lib/external/mcp/handlers/bootstrap/pipeline/orchestrator.js +2 -2
  27. package/lib/external/mcp/handlers/bootstrap.js +116 -11
  28. package/lib/external/mcp/handlers/browse.js +77 -73
  29. package/lib/external/mcp/handlers/candidate.js +29 -276
  30. package/lib/external/mcp/handlers/guard.js +2 -0
  31. package/lib/external/mcp/handlers/knowledge.js +205 -0
  32. package/lib/external/mcp/handlers/structure.js +25 -23
  33. package/lib/external/mcp/handlers/system.js +10 -12
  34. package/lib/external/mcp/tools.js +125 -138
  35. package/lib/http/HttpServer.js +4 -8
  36. package/lib/http/routes/extract.js +48 -4
  37. package/lib/http/routes/knowledge.js +246 -0
  38. package/lib/http/routes/search.js +12 -17
  39. package/lib/infrastructure/database/migrations/016_unified_knowledge_entries.js +395 -0
  40. package/lib/infrastructure/external/XcodeAutomation.js +187 -103
  41. package/lib/injection/ServiceContainer.js +49 -60
  42. package/lib/repository/knowledge/KnowledgeRepository.impl.js +373 -0
  43. package/lib/service/automation/DirectiveDetector.js +2 -3
  44. package/lib/service/automation/FileWatcher.js +67 -28
  45. package/lib/service/automation/XcodeIntegration.js +931 -156
  46. package/lib/service/automation/handlers/AlinkHandler.js +6 -4
  47. package/lib/service/automation/handlers/CreateHandler.js +53 -18
  48. package/lib/service/automation/handlers/GuardHandler.js +183 -20
  49. package/lib/service/automation/handlers/SearchHandler.js +35 -17
  50. package/lib/service/chat/CandidateGuardrail.js +1 -1
  51. package/lib/service/chat/ChatAgent.js +46 -45
  52. package/lib/service/chat/ContextWindow.js +5 -5
  53. package/lib/service/chat/ProducerAgent.js +7 -7
  54. package/lib/service/chat/tools.js +130 -123
  55. package/lib/service/guard/GuardCheckEngine.js +114 -10
  56. package/lib/service/guard/GuardService.js +59 -48
  57. package/lib/service/knowledge/ConfidenceRouter.js +159 -0
  58. package/lib/service/knowledge/KnowledgeFileWriter.js +602 -0
  59. package/lib/service/knowledge/KnowledgeService.js +725 -0
  60. package/lib/service/search/SearchEngine.js +92 -19
  61. package/lib/service/skills/SignalCollector.js +12 -7
  62. package/lib/service/skills/SkillAdvisor.js +13 -11
  63. package/lib/service/snippet/SnippetFactory.js +5 -5
  64. package/package.json +1 -1
  65. package/scripts/install-cursor-skill.js +0 -6
  66. package/scripts/migrate-md-to-knowledge.mjs +364 -0
  67. package/skills/autosnippet-analysis/SKILL.md +15 -7
  68. package/skills/autosnippet-candidates/SKILL.md +6 -6
  69. package/skills/autosnippet-coldstart/SKILL.md +7 -3
  70. package/skills/autosnippet-concepts/SKILL.md +7 -6
  71. package/skills/autosnippet-create/SKILL.md +13 -13
  72. package/skills/autosnippet-intent/SKILL.md +3 -2
  73. package/skills/autosnippet-lifecycle/SKILL.md +5 -5
  74. package/skills/autosnippet-recipes/SKILL.md +16 -4
  75. package/templates/constitution.yaml +1 -1
  76. package/templates/copilot-instructions.md +6 -6
  77. package/templates/recipes-setup/README.md +3 -3
  78. package/dashboard/dist/assets/index-CqJRvYRL.js +0 -197
  79. package/dashboard/dist/assets/index-DICm9PNa.css +0 -1
  80. package/lib/cli/CandidateSyncService.js +0 -261
  81. package/lib/cli/SyncService.js +0 -356
  82. package/lib/domain/candidate/Candidate.js +0 -196
  83. package/lib/domain/candidate/CandidateRepository.js +0 -107
  84. package/lib/domain/candidate/Reasoning.js +0 -52
  85. package/lib/domain/recipe/Recipe.js +0 -421
  86. package/lib/domain/recipe/RecipeRepository.js +0 -54
  87. package/lib/domain/types/CandidateStatus.js +0 -52
  88. package/lib/http/routes/candidates.js +0 -559
  89. package/lib/http/routes/recipes.js +0 -397
  90. package/lib/repository/candidate/CandidateRepository.impl.js +0 -230
  91. package/lib/repository/recipe/RecipeRepository.impl.js +0 -498
  92. package/lib/service/candidate/CandidateAggregator.js +0 -52
  93. package/lib/service/candidate/CandidateFileWriter.js +0 -383
  94. package/lib/service/candidate/CandidateService.js +0 -1001
  95. package/lib/service/recipe/RecipeFileWriter.js +0 -514
  96. package/lib/service/recipe/RecipeService.js +0 -786
  97. package/lib/service/recipe/RecipeStatsTracker.js +0 -148
@@ -1,148 +0,0 @@
1
- /**
2
- * RecipeStatsTracker — Recipe 使用统计追踪器
3
- * 记录 guard/human/ai 三档使用次数,计算热度和权威分
4
- * 持久化到 AutoSnippet/recipe-stats.json(Git 友好)
5
- */
6
-
7
- import { readFileSync, writeFileSync, mkdirSync, existsSync, unlinkSync } from 'node:fs';
8
- import { join, dirname } from 'node:path';
9
- import Logger from '../../infrastructure/logging/Logger.js';
10
- import pathGuard from '../../shared/PathGuard.js';
11
-
12
- const SCHEMA_VERSION = 1;
13
- const DEFAULT_HEAT_WEIGHTS = { guard: 1.0, human: 2.0, ai: 1.5 };
14
- const AUTHORITY_ALPHA = 0.6;
15
-
16
- export class RecipeStatsTracker {
17
- #statsPath;
18
- #data; // { schemaVersion, byTrigger: {}, byFile: {} }
19
-
20
- constructor(projectRoot, options = {}) {
21
- const kbDir = options.knowledgeBaseDir || 'AutoSnippet';
22
- this.#statsPath = join(projectRoot, kbDir, 'recipe-stats.json');
23
- pathGuard.assertProjectWriteSafe(this.#statsPath);
24
- this.#migrateOldPath(projectRoot, options.internalDir || '.autosnippet');
25
- this.#data = this.#load();
26
- }
27
-
28
- /**
29
- * 记录一次 Recipe 使用
30
- * @param {{ trigger?: string, recipeFilePath?: string, source: 'guard'|'human'|'ai' }} usage
31
- */
32
- recordUsage(usage) {
33
- const { trigger, recipeFilePath, source = 'human' } = usage;
34
- const key = trigger || recipeFilePath;
35
- if (!key) return;
36
-
37
- const store = trigger ? this.#data.byTrigger : this.#data.byFile;
38
- if (!store[key]) {
39
- store[key] = { guardUsageCount: 0, humanUsageCount: 0, aiUsageCount: 0, lastUsedAt: null, authority: 0 };
40
- }
41
-
42
- const entry = store[key];
43
- if (source === 'guard') entry.guardUsageCount++;
44
- else if (source === 'ai') entry.aiUsageCount++;
45
- else entry.humanUsageCount++;
46
- entry.lastUsedAt = new Date().toISOString();
47
-
48
- this.#save();
49
- }
50
-
51
- /**
52
- * 设置权威分 (0-5)
53
- */
54
- setAuthority(key, value) {
55
- const entry = this.#data.byTrigger[key] || this.#data.byFile[key];
56
- if (entry) {
57
- entry.authority = Math.max(0, Math.min(5, value));
58
- this.#save();
59
- }
60
- }
61
-
62
- /**
63
- * 计算使用热度
64
- * heat = w_guard * guard + w_human * human + w_ai * ai
65
- */
66
- getUsageHeat(entry, weights = DEFAULT_HEAT_WEIGHTS) {
67
- if (!entry) return 0;
68
- return (entry.guardUsageCount || 0) * weights.guard
69
- + (entry.humanUsageCount || 0) * weights.human
70
- + (entry.aiUsageCount || 0) * weights.ai;
71
- }
72
-
73
- /**
74
- * 综合权威分 = α * normalize(heat) + (1-α) * (authority/5)
75
- */
76
- getAuthorityScore(entry, allEntries = null) {
77
- if (!entry) return 0;
78
- const heat = this.getUsageHeat(entry);
79
- const maxHeat = allEntries
80
- ? Math.max(...Object.values(allEntries).map(e => this.getUsageHeat(e)), 1)
81
- : Math.max(heat, 1);
82
- const normalizedHeat = heat / maxHeat;
83
- const normalizedAuthority = (entry.authority || 0) / 5;
84
- return AUTHORITY_ALPHA * normalizedHeat + (1 - AUTHORITY_ALPHA) * normalizedAuthority;
85
- }
86
-
87
- /**
88
- * 获取所有统计
89
- */
90
- getStats() {
91
- return { ...this.#data };
92
- }
93
-
94
- /**
95
- * 获取指定 Recipe 的统计
96
- */
97
- getEntryStats(key) {
98
- return this.#data.byTrigger[key] || this.#data.byFile[key] || null;
99
- }
100
-
101
- /**
102
- * 获取热门 Recipes (top N)
103
- */
104
- getTopRecipes(n = 10) {
105
- const allEntries = { ...this.#data.byTrigger, ...this.#data.byFile };
106
- return Object.entries(allEntries)
107
- .map(([key, entry]) => ({
108
- key,
109
- heat: this.getUsageHeat(entry),
110
- authorityScore: this.getAuthorityScore(entry, allEntries),
111
- ...entry,
112
- }))
113
- .sort((a, b) => b.authorityScore - a.authorityScore)
114
- .slice(0, n);
115
- }
116
-
117
- #load() {
118
- try {
119
- if (existsSync(this.#statsPath)) {
120
- return JSON.parse(readFileSync(this.#statsPath, 'utf-8'));
121
- }
122
- } catch { /* silent */ }
123
- return { schemaVersion: SCHEMA_VERSION, byTrigger: {}, byFile: {} };
124
- }
125
-
126
- #save() {
127
- try {
128
- const dir = dirname(this.#statsPath);
129
- if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
130
- writeFileSync(this.#statsPath, JSON.stringify(this.#data, null, 2));
131
- } catch (err) {
132
- Logger.getInstance().warn('RecipeStatsTracker: failed to persist stats', { error: err.message });
133
- }
134
- }
135
-
136
- #migrateOldPath(projectRoot, internalDir) {
137
- try {
138
- const oldPath = join(projectRoot, internalDir, 'recipe-stats.json');
139
- if (existsSync(oldPath) && !existsSync(this.#statsPath)) {
140
- const content = readFileSync(oldPath, 'utf-8');
141
- const dir = dirname(this.#statsPath);
142
- if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
143
- writeFileSync(this.#statsPath, content);
144
- unlinkSync(oldPath);
145
- }
146
- } catch { /* 迁移失败不阻断启动 */ }
147
- }
148
- }