mta-mcp 1.9.0 → 2.2.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 (117) hide show
  1. package/README.md +140 -2
  2. package/build/core/analyzers/eslint.d.ts +51 -0
  3. package/build/core/analyzers/eslint.d.ts.map +1 -0
  4. package/build/core/analyzers/eslint.js +259 -0
  5. package/build/core/analyzers/eslint.js.map +1 -0
  6. package/build/core/analyzers/index.d.ts +9 -0
  7. package/build/core/analyzers/index.d.ts.map +1 -0
  8. package/build/core/analyzers/index.js +9 -0
  9. package/build/core/analyzers/index.js.map +1 -0
  10. package/build/core/analyzers/registry.d.ts +59 -0
  11. package/build/core/analyzers/registry.d.ts.map +1 -0
  12. package/build/core/analyzers/registry.js +241 -0
  13. package/build/core/analyzers/registry.js.map +1 -0
  14. package/build/core/analyzers/tsconfig.d.ts +45 -0
  15. package/build/core/analyzers/tsconfig.d.ts.map +1 -0
  16. package/build/core/analyzers/tsconfig.js +197 -0
  17. package/build/core/analyzers/tsconfig.js.map +1 -0
  18. package/build/core/analyzers/types.d.ts +176 -0
  19. package/build/core/analyzers/types.d.ts.map +1 -0
  20. package/build/core/analyzers/types.js +39 -0
  21. package/build/core/analyzers/types.js.map +1 -0
  22. package/build/core/analyzers/vite.d.ts +46 -0
  23. package/build/core/analyzers/vite.d.ts.map +1 -0
  24. package/build/core/analyzers/vite.js +211 -0
  25. package/build/core/analyzers/vite.js.map +1 -0
  26. package/build/core/enhancedProjectAnalyzer.d.ts +102 -0
  27. package/build/core/enhancedProjectAnalyzer.d.ts.map +1 -0
  28. package/build/core/enhancedProjectAnalyzer.js +312 -0
  29. package/build/core/enhancedProjectAnalyzer.js.map +1 -0
  30. package/build/core/errors.d.ts +84 -0
  31. package/build/core/errors.d.ts.map +1 -0
  32. package/build/core/errors.js +151 -0
  33. package/build/core/errors.js.map +1 -0
  34. package/build/core/index.d.ts +11 -0
  35. package/build/core/index.d.ts.map +1 -0
  36. package/build/core/index.js +14 -0
  37. package/build/core/index.js.map +1 -0
  38. package/build/core/logger.d.ts +91 -0
  39. package/build/core/logger.d.ts.map +1 -0
  40. package/build/core/logger.js +164 -0
  41. package/build/core/logger.js.map +1 -0
  42. package/build/core/mappings/index.d.ts +5 -0
  43. package/build/core/mappings/index.d.ts.map +1 -0
  44. package/build/core/mappings/index.js +5 -0
  45. package/build/core/mappings/index.js.map +1 -0
  46. package/build/core/mappings/scenarioMappings.d.ts +51 -0
  47. package/build/core/mappings/scenarioMappings.d.ts.map +1 -0
  48. package/build/core/mappings/scenarioMappings.js +105 -0
  49. package/build/core/mappings/scenarioMappings.js.map +1 -0
  50. package/build/core/matching/index.d.ts +8 -0
  51. package/build/core/matching/index.d.ts.map +1 -0
  52. package/build/core/matching/index.js +8 -0
  53. package/build/core/matching/index.js.map +1 -0
  54. package/build/core/matching/intentAnalyzer.d.ts +78 -0
  55. package/build/core/matching/intentAnalyzer.d.ts.map +1 -0
  56. package/build/core/matching/intentAnalyzer.js +255 -0
  57. package/build/core/matching/intentAnalyzer.js.map +1 -0
  58. package/build/core/matching/standardMatcher.d.ts +101 -0
  59. package/build/core/matching/standardMatcher.d.ts.map +1 -0
  60. package/build/core/matching/standardMatcher.js +299 -0
  61. package/build/core/matching/standardMatcher.js.map +1 -0
  62. package/build/core/matching/weights.d.ts +64 -0
  63. package/build/core/matching/weights.d.ts.map +1 -0
  64. package/build/core/matching/weights.js +334 -0
  65. package/build/core/matching/weights.js.map +1 -0
  66. package/build/core/scenarioDetector.d.ts +2 -0
  67. package/build/core/scenarioDetector.d.ts.map +1 -0
  68. package/build/core/scenarioDetector.js +2 -0
  69. package/build/core/scenarioDetector.js.map +1 -0
  70. package/build/core/templates/discovery.d.ts +41 -0
  71. package/build/core/templates/discovery.d.ts.map +1 -0
  72. package/build/core/templates/discovery.js +262 -0
  73. package/build/core/templates/discovery.js.map +1 -0
  74. package/build/core/templates/types.d.ts +80 -0
  75. package/build/core/templates/types.d.ts.map +1 -0
  76. package/build/core/templates/types.js +10 -0
  77. package/build/core/templates/types.js.map +1 -0
  78. package/build/core/types.d.ts +2 -0
  79. package/build/core/types.d.ts.map +1 -1
  80. package/build/core/types.js +4 -3
  81. package/build/core/types.js.map +1 -1
  82. package/build/index.js +136 -23
  83. package/build/index.js.map +1 -1
  84. package/build/tools/getStandardById.d.ts +42 -0
  85. package/build/tools/getStandardById.d.ts.map +1 -0
  86. package/build/tools/getStandardById.js +289 -0
  87. package/build/tools/getStandardById.js.map +1 -0
  88. package/build/tools/getTemplate.d.ts +37 -0
  89. package/build/tools/getTemplate.d.ts.map +1 -0
  90. package/build/tools/getTemplate.js +78 -0
  91. package/build/tools/getTemplate.js.map +1 -0
  92. package/build/tools/listTemplates.d.ts +41 -0
  93. package/build/tools/listTemplates.d.ts.map +1 -0
  94. package/build/tools/listTemplates.js +81 -0
  95. package/build/tools/listTemplates.js.map +1 -0
  96. package/build/tools/queryMappings.d.ts +55 -0
  97. package/build/tools/queryMappings.d.ts.map +1 -0
  98. package/build/tools/queryMappings.js +119 -0
  99. package/build/tools/queryMappings.js.map +1 -0
  100. package/package.json +25 -8
  101. package/src/core/autoInitializer.ts +0 -170
  102. package/src/core/codeValidator.ts +0 -357
  103. package/src/core/githubClient.ts +0 -64
  104. package/src/core/i18nDetector.ts +0 -357
  105. package/src/core/smartAgentMatcher.ts +0 -490
  106. package/src/core/standardsManager.ts +0 -769
  107. package/src/core/types.ts +0 -72
  108. package/src/index.ts +0 -519
  109. package/src/tools/analyzeProject.ts +0 -94
  110. package/src/tools/autoSetup.ts +0 -312
  111. package/src/tools/generateConfig.ts +0 -429
  112. package/src/tools/getCompactStandards.ts +0 -413
  113. package/src/tools/getSmartStandards.ts +0 -225
  114. package/src/tools/healthCheck.ts +0 -261
  115. package/src/tools/listAgents.ts +0 -91
  116. package/src/tools/matchAgents.ts +0 -80
  117. package/src/tools/usePreset.ts +0 -180
@@ -1,769 +0,0 @@
1
- import * as fs from 'fs';
2
- import * as path from 'path';
3
- import { fileURLToPath } from 'url';
4
-
5
- const __filename = fileURLToPath(import.meta.url);
6
- const __dirname = path.dirname(__filename);
7
-
8
- /**
9
- * 缓存条目
10
- */
11
- interface CacheEntry {
12
- content: string;
13
- timestamp: number;
14
- accessCount: number;
15
- }
16
-
17
- /**
18
- * 使用统计
19
- */
20
- interface UsageStats {
21
- standardCombinations: Map<string, number>; // 规范组合 -> 使用次数
22
- individualStandards: Map<string, number>; // 单个规范 -> 使用次数
23
- averageTokens: number; // 平均 token 消耗
24
- totalCalls: number; // 总调用次数
25
- }
26
-
27
- /**
28
- * 性能指标
29
- */
30
- interface PerformanceMetrics {
31
- totalCalls: number;
32
- cacheHits: number;
33
- cacheMisses: number;
34
- averageResponseTime: number;
35
- totalTokensSaved: number;
36
- cacheHitRate?: string; // 可选,在 getPerformanceMetrics 中添加
37
- }
38
-
39
- /**
40
- * 规范资源管理器(Phase 3 增强)
41
- */
42
- export class StandardsManager {
43
- private standardsPath: string;
44
-
45
- // v1.2.0: 底层必须加载的核心规范
46
- private readonly MANDATORY_CORE_STANDARDS = [
47
- 'standards://core/code-style', // 代码风格规范(命名、格式等)
48
- 'standards://core/typescript-base', // TypeScript基础规范
49
- 'standards://core/code-generation' // 代码生成规范(注释、文档等)
50
- ];
51
-
52
- // Phase 3: 缓存系统
53
- private contentCache: Map<string, CacheEntry> = new Map();
54
- private readonly CACHE_DURATION = 30 * 60 * 1000; // 30分钟
55
- private readonly MAX_CACHE_SIZE = 50; // 最多缓存50个条目
56
-
57
- // Phase 3: 使用统计
58
- private stats: UsageStats = {
59
- standardCombinations: new Map(),
60
- individualStandards: new Map(),
61
- averageTokens: 0,
62
- totalCalls: 0
63
- };
64
-
65
- // Phase 3: 性能指标
66
- private metrics: PerformanceMetrics = {
67
- totalCalls: 0,
68
- cacheHits: 0,
69
- cacheMisses: 0,
70
- averageResponseTime: 0,
71
- totalTokensSaved: 0
72
- };
73
-
74
- constructor() {
75
- // 标准规范目录路径
76
- // 开发环境: mcp-server/build/core -> copilot-prompts/standards
77
- // npm 包环境: node_modules/mta-mcp/build/core -> node_modules/mta-mcp/standards
78
- const devPath = path.resolve(__dirname, '../../../standards');
79
- const npmPath = path.resolve(__dirname, '../../standards');
80
-
81
- // 优先使用 npm 包内的路径,如果不存在则使用开发路径
82
- this.standardsPath = fs.existsSync(npmPath) ? npmPath : devPath;
83
- }
84
-
85
- /**
86
- * 获取所有可用的规范资源
87
- */
88
- getAvailableStandards(): Array<{ uri: string; name: string; description: string; category: string }> {
89
- const standards: Array<{ uri: string; name: string; description: string; category: string }> = [];
90
-
91
- const categories = [
92
- { dir: 'core', name: '核心规范' },
93
- { dir: 'frameworks', name: '框架规范' },
94
- { dir: 'libraries', name: '库规范' },
95
- { dir: 'patterns', name: '设计模式' }
96
- ];
97
-
98
- categories.forEach(({ dir, name: categoryName }) => {
99
- const categoryPath = path.join(this.standardsPath, dir);
100
-
101
- if (!fs.existsSync(categoryPath)) {
102
- return;
103
- }
104
-
105
- const files = fs.readdirSync(categoryPath)
106
- .filter(file => file.endsWith('.md'));
107
-
108
- files.forEach(file => {
109
- const standardId = file.replace('.md', '');
110
- standards.push({
111
- uri: `standards://${dir}/${standardId}`,
112
- name: this.getStandardName(dir, standardId),
113
- description: `${categoryName} - ${this.getStandardDescription(dir, standardId)}`,
114
- category: dir
115
- });
116
- });
117
- });
118
-
119
- return standards;
120
- }
121
-
122
- /**
123
- * 读取特定规范内容(Phase 3: 带缓存)
124
- */
125
- readStandard(uri: string): string {
126
- const startTime = Date.now();
127
-
128
- // 检查缓存
129
- const cached = this.contentCache.get(uri);
130
- if (cached && (Date.now() - cached.timestamp) < this.CACHE_DURATION) {
131
- cached.accessCount++;
132
- this.metrics.cacheHits++;
133
- return cached.content;
134
- }
135
-
136
- this.metrics.cacheMisses++;
137
-
138
- // 解析 URI: standards://category/standard-name
139
- const match = uri.match(/^standards:\/\/([^/]+)\/(.+)$/);
140
-
141
- if (!match) {
142
- throw new Error(`Invalid standards URI: ${uri}`);
143
- }
144
-
145
- const [, category, standardId] = match;
146
- const filePath = path.join(this.standardsPath, category, `${standardId}.md`);
147
-
148
- if (!fs.existsSync(filePath)) {
149
- throw new Error(`Standard not found: ${uri}`);
150
- }
151
-
152
- const content = fs.readFileSync(filePath, 'utf-8');
153
-
154
- // 更新缓存
155
- this.updateCache(uri, content);
156
-
157
- // 更新统计
158
- this.stats.individualStandards.set(
159
- uri,
160
- (this.stats.individualStandards.get(uri) || 0) + 1
161
- );
162
-
163
- // 记录响应时间
164
- const responseTime = Date.now() - startTime;
165
- this.updateAverageResponseTime(responseTime);
166
-
167
- return content;
168
- }
169
-
170
- /**
171
- * 更新缓存
172
- */
173
- private updateCache(uri: string, content: string): void {
174
- // 如果缓存已满,移除最少使用的条目
175
- if (this.contentCache.size >= this.MAX_CACHE_SIZE) {
176
- let minAccessCount = Infinity;
177
- let lruKey: string | null = null;
178
-
179
- this.contentCache.forEach((entry, key) => {
180
- if (entry.accessCount < minAccessCount) {
181
- minAccessCount = entry.accessCount;
182
- lruKey = key;
183
- }
184
- });
185
-
186
- if (lruKey) {
187
- this.contentCache.delete(lruKey);
188
- }
189
- }
190
-
191
- this.contentCache.set(uri, {
192
- content,
193
- timestamp: Date.now(),
194
- accessCount: 1
195
- });
196
- }
197
-
198
- /**
199
- * 根据技术栈获取相关规范(增强版 - Phase 2)
200
- */
201
- getRelevantStandards(context: {
202
- fileType?: string;
203
- imports?: string[];
204
- scenario?: string;
205
- fileContent?: string; // 新增:文件内容(用于自动检测)
206
- }): string[] {
207
- const standardScores = new Map<string, number>();
208
-
209
- // 权重系统
210
- const WEIGHTS = {
211
- CORE: 100, // 核心规范始终包含
212
- FILE_TYPE: 50, // 文件类型匹配
213
- IMPORT_DIRECT: 40, // 直接导入匹配
214
- IMPORT_RELATED: 20, // 相关导入匹配
215
- SCENARIO: 30, // 场景匹配
216
- CONTENT: 15, // 内容关键词匹配
217
- THRESHOLD: 10 // 最低阈值
218
- };
219
-
220
- // v1.2.0: 始终包含底层必须加载的核心规范
221
- this.MANDATORY_CORE_STANDARDS.forEach(standard => {
222
- standardScores.set(standard, WEIGHTS.CORE);
223
- });
224
-
225
- // 自动检测导入(如果提供了文件内容)
226
- let detectedImports = context.imports || [];
227
- if (context.fileContent && !context.imports) {
228
- detectedImports = this.detectImports(context.fileContent);
229
- }
230
-
231
- // 根据文件类型评分
232
- if (context.fileType) {
233
- this.scoreByFileType(context.fileType, standardScores, WEIGHTS);
234
- }
235
-
236
- // 根据导入评分
237
- if (detectedImports.length > 0) {
238
- this.scoreByImports(detectedImports, standardScores, WEIGHTS);
239
- }
240
-
241
- // 根据场景评分
242
- if (context.scenario) {
243
- this.scoreByScenario(context.scenario, standardScores, WEIGHTS);
244
- }
245
-
246
- // 根据内容关键词评分
247
- if (context.fileContent) {
248
- this.scoreByContent(context.fileContent, standardScores, WEIGHTS);
249
- }
250
-
251
- // 过滤并排序
252
- const sortedStandards = Array.from(standardScores.entries())
253
- .filter(([_, score]) => score >= WEIGHTS.THRESHOLD)
254
- .sort((a, b) => b[1] - a[1])
255
- .map(([uri]) => uri);
256
-
257
- // Phase 3: 记录使用统计
258
- this.stats.totalCalls++;
259
- const combinationKey = sortedStandards.join('|');
260
- this.stats.standardCombinations.set(
261
- combinationKey,
262
- (this.stats.standardCombinations.get(combinationKey) || 0) + 1
263
- );
264
-
265
- return sortedStandards;
266
- }
267
-
268
- /**
269
- * 自动检测文件中的导入语句
270
- */
271
- private detectImports(content: string): string[] {
272
- const imports: string[] = [];
273
-
274
- // 匹配 ES6 import 语句
275
- const importRegex = /import\s+(?:(?:{[^}]*}|\*\s+as\s+\w+|\w+)\s+from\s+)?['"]([^'"]+)['"]/g;
276
- let match;
277
-
278
- while ((match = importRegex.exec(content)) !== null) {
279
- imports.push(match[1]);
280
- }
281
-
282
- // 匹配 require 语句
283
- const requireRegex = /require\(['"]([^'"]+)['"]\)/g;
284
- while ((match = requireRegex.exec(content)) !== null) {
285
- imports.push(match[1]);
286
- }
287
-
288
- return imports;
289
- }
290
-
291
- /**
292
- * 根据文件类型评分
293
- */
294
- private scoreByFileType(
295
- fileType: string,
296
- scores: Map<string, number>,
297
- weights: Record<string, number>
298
- ): void {
299
- const type = fileType.toLowerCase();
300
-
301
- if (type === 'vue' || type.endsWith('.vue')) {
302
- this.addScore(scores, 'standards://frameworks/vue3-composition', weights.FILE_TYPE);
303
- this.addScore(scores, 'standards://patterns/component-design', weights.FILE_TYPE * 0.6);
304
- }
305
-
306
- // 微信小程序文件类型
307
- if (type === 'wxml' || type.endsWith('.wxml') ||
308
- type === 'wxss' || type.endsWith('.wxss') ||
309
- type === 'wxs' || type.endsWith('.wxs')) {
310
- this.addScore(scores, 'standards://frameworks/wechat-miniprogram', weights.FILE_TYPE);
311
- }
312
-
313
- if (type === 'ts' || type === 'typescript' || type.endsWith('.ts')) {
314
- // TypeScript 文件,略微提升 TS 规范权重
315
- this.addScore(scores, 'standards://core/typescript-base', weights.FILE_TYPE * 0.3);
316
- }
317
-
318
- // Flutter/Dart 文件类型
319
- if (type === 'dart' || type.endsWith('.dart')) {
320
- this.addScore(scores, 'standards://frameworks/flutter', weights.FILE_TYPE);
321
- this.addScore(scores, 'standards://frameworks/flutter-ui-system', weights.FILE_TYPE);
322
- this.addScore(scores, 'standards://core/dart-base', weights.FILE_TYPE * 0.5);
323
- }
324
- }
325
-
326
- /**
327
- * 根据导入评分
328
- */
329
- private scoreByImports(
330
- imports: string[],
331
- scores: Map<string, number>,
332
- weights: Record<string, number>
333
- ): void {
334
- imports.forEach(imp => {
335
- const normalized = imp.toLowerCase();
336
-
337
- // Vue 生态
338
- if (normalized === 'vue' || normalized.startsWith('vue/')) {
339
- this.addScore(scores, 'standards://frameworks/vue3-composition', weights.IMPORT_DIRECT);
340
- } else if (normalized.includes('vue')) {
341
- this.addScore(scores, 'standards://frameworks/vue3-composition', weights.IMPORT_RELATED);
342
- }
343
-
344
- // Pinia
345
- if (normalized === 'pinia' || normalized.startsWith('pinia/')) {
346
- this.addScore(scores, 'standards://frameworks/pinia', weights.IMPORT_DIRECT);
347
- }
348
-
349
- // Element Plus
350
- if (normalized === 'element-plus' || normalized.startsWith('element-plus/')) {
351
- this.addScore(scores, 'standards://libraries/element-plus', weights.IMPORT_DIRECT);
352
- } else if (normalized.includes('element')) {
353
- this.addScore(scores, 'standards://libraries/element-plus', weights.IMPORT_RELATED);
354
- }
355
-
356
- // i18n
357
- if (normalized === 'vue-i18n' || normalized.includes('i18n')) {
358
- this.addScore(scores, 'standards://libraries/i18n', weights.IMPORT_DIRECT);
359
- }
360
-
361
- // 微信小程序
362
- if (normalized === 'wx' || normalized.includes('weixin') ||
363
- normalized.includes('miniprogram')) {
364
- this.addScore(scores, 'standards://frameworks/wechat-miniprogram', weights.IMPORT_DIRECT);
365
- }
366
-
367
- // Axios / API 相关
368
- if (normalized === 'axios' || normalized.includes('axios')) {
369
- this.addScore(scores, 'standards://patterns/api-layer', weights.IMPORT_DIRECT);
370
- }
371
-
372
- // 通用组件库导入提示组件设计
373
- if (normalized.includes('component') || normalized.startsWith('./components/')) {
374
- this.addScore(scores, 'standards://patterns/component-design', weights.IMPORT_RELATED);
375
- }
376
-
377
- // Flutter 相关
378
- if (normalized === 'flutter' || normalized.startsWith('flutter/') ||
379
- normalized.startsWith('package:flutter')) {
380
- this.addScore(scores, 'standards://frameworks/flutter', weights.IMPORT_DIRECT);
381
- this.addScore(scores, 'standards://frameworks/flutter-ui-system', weights.IMPORT_DIRECT);
382
- }
383
-
384
- // GetX 状态管理
385
- if (normalized === 'get' || normalized.startsWith('get/') ||
386
- normalized.startsWith('package:get')) {
387
- this.addScore(scores, 'standards://frameworks/flutter', weights.IMPORT_DIRECT);
388
- }
389
- });
390
- }
391
-
392
- /**
393
- * 根据场景评分
394
- */
395
- private scoreByScenario(
396
- scenario: string,
397
- scores: Map<string, number>,
398
- weights: Record<string, number>
399
- ): void {
400
- const normalized = scenario.toLowerCase();
401
-
402
- // API 相关场景
403
- if (normalized.includes('api') || normalized.includes('request') ||
404
- normalized.includes('fetch') || normalized.includes('axios')) {
405
- this.addScore(scores, 'standards://patterns/api-layer', weights.SCENARIO);
406
- }
407
-
408
- // 组件相关场景
409
- if (normalized.includes('component') || normalized.includes('组件') ||
410
- normalized.includes('widget') || normalized.includes('封装')) {
411
- this.addScore(scores, 'standards://patterns/component-design', weights.SCENARIO);
412
- }
413
-
414
- // 表单场景
415
- if (normalized.includes('form') || normalized.includes('表单') ||
416
- normalized.includes('input') || normalized.includes('validation')) {
417
- this.addScore(scores, 'standards://libraries/element-plus', weights.SCENARIO);
418
- this.addScore(scores, 'standards://patterns/component-design', weights.SCENARIO * 0.5);
419
- }
420
-
421
- // 状态管理场景
422
- if (normalized.includes('store') || normalized.includes('state') ||
423
- normalized.includes('状态') || normalized.includes('pinia')) {
424
- this.addScore(scores, 'standards://frameworks/pinia', weights.SCENARIO);
425
- }
426
-
427
- // 国际化场景
428
- if (normalized.includes('i18n') || normalized.includes('translate') ||
429
- normalized.includes('国际化') || normalized.includes('翻译') ||
430
- normalized.includes('locale') || normalized.includes('多语言') ||
431
- normalized.includes('messages.ts') || normalized.includes('$t(')) {
432
- this.addScore(scores, 'standards://libraries/i18n', weights.SCENARIO);
433
- }
434
-
435
- // Vue CSS 嵌套场景
436
- if (normalized.includes('css') || normalized.includes('样式') ||
437
- normalized.includes('style') || normalized.includes('scoped') ||
438
- normalized.includes('嵌套') || normalized.includes('nesting') ||
439
- normalized.includes('内联') || normalized.includes('inline') ||
440
- normalized.includes('工具类') || normalized.includes('utilities') ||
441
- normalized.includes('.ml_') || normalized.includes('.mr_') ||
442
- normalized.includes('.mt_') || normalized.includes('.mb_') ||
443
- normalized.includes('.w_') || normalized.includes(':deep(')) {
444
- this.addScore(scores, 'standards://patterns/vue-css-nesting', weights.SCENARIO);
445
- }
446
-
447
- // 微信小程序场景
448
- if (normalized.includes('小程序') || normalized.includes('miniprogram') ||
449
- normalized.includes('wechat') || normalized.includes('微信') ||
450
- normalized.includes('wx.') || normalized.includes('page(') ||
451
- normalized.includes('component(') || normalized.includes('云开发') ||
452
- normalized.includes('云函数') || normalized.includes('云数据库') ||
453
- normalized.includes('云存储')) {
454
- this.addScore(scores, 'standards://frameworks/wechat-miniprogram', weights.SCENARIO);
455
- }
456
-
457
- // Flutter UI 系统场景
458
- if (normalized.includes('flutter') || normalized.includes('dart') ||
459
- normalized.includes('widget') || normalized.includes('ui系统') ||
460
- normalized.includes('ui 系统') || normalized.includes('flutter ui') ||
461
- normalized.includes('design token') || normalized.includes('token') ||
462
- normalized.includes('主题') || normalized.includes('theme')) {
463
- this.addScore(scores, 'standards://frameworks/flutter', weights.SCENARIO);
464
- this.addScore(scores, 'standards://frameworks/flutter-ui-system', weights.SCENARIO);
465
- }
466
-
467
- // Flex 组件场景
468
- if (normalized.includes('flexbutton') || normalized.includes('flexcard') ||
469
- normalized.includes('flexinput') || normalized.includes('flex组件') ||
470
- normalized.includes('$c') || normalized.includes('$s') ||
471
- normalized.includes('$t') || normalized.includes('$r')) {
472
- this.addScore(scores, 'standards://frameworks/flutter-ui-system', weights.SCENARIO * 1.5);
473
- }
474
- }
475
-
476
- /**
477
- * 根据文件内容关键词评分
478
- */
479
- private scoreByContent(
480
- content: string,
481
- scores: Map<string, number>,
482
- weights: Record<string, number>
483
- ): void {
484
- const normalized = content.toLowerCase();
485
-
486
- // Vue Composition API 关键词
487
- if (normalized.includes('defineprops') || normalized.includes('defineemits') ||
488
- normalized.includes('ref(') || normalized.includes('computed(') ||
489
- normalized.includes('watch(') || normalized.includes('onmounted')) {
490
- this.addScore(scores, 'standards://frameworks/vue3-composition', weights.CONTENT);
491
- }
492
-
493
- // Pinia 关键词
494
- if (normalized.includes('definestore') || normalized.includes('usestore') ||
495
- normalized.includes('$patch') || normalized.includes('$subscribe')) {
496
- this.addScore(scores, 'standards://frameworks/pinia', weights.CONTENT);
497
- }
498
-
499
- // Element Plus 关键词
500
- if (normalized.includes('el-form') || normalized.includes('el-table') ||
501
- normalized.includes('el-dialog') || normalized.includes('elmessage')) {
502
- this.addScore(scores, 'standards://libraries/element-plus', weights.CONTENT);
503
- }
504
-
505
- // i18n 关键词
506
- if (normalized.includes('$t(') || normalized.includes('t(\'') ||
507
- normalized.includes('usei18n') || normalized.includes('locale') ||
508
- normalized.includes('messages.ts') || normalized.includes('localestore') ||
509
- normalized.includes('setlocale') || normalized.includes('togglelocale')) {
510
- this.addScore(scores, 'standards://libraries/i18n', weights.CONTENT);
511
- }
512
-
513
- // Vue CSS 嵌套关键词
514
- if (normalized.includes('<style scoped>') || normalized.includes('&:hover') ||
515
- normalized.includes('&.active') || normalized.includes('&::before') ||
516
- normalized.includes(':deep(') || normalized.includes(':global(') ||
517
- normalized.includes('style="') || normalized.includes('class="ml_') ||
518
- normalized.includes('class="mr_') || normalized.includes('class="mt_') ||
519
- normalized.includes('class="w_')) {
520
- this.addScore(scores, 'standards://patterns/vue-css-nesting', weights.CONTENT);
521
- }
522
-
523
- // 微信小程序关键词
524
- if (normalized.includes('wx.') || normalized.includes('page({') ||
525
- normalized.includes('component({') || normalized.includes('setdata') ||
526
- normalized.includes('onload') || normalized.includes('onshow') ||
527
- normalized.includes('wx:for') || normalized.includes('wx:if') ||
528
- normalized.includes('wx.cloud') || normalized.includes('cloudfunctions') ||
529
- normalized.includes('callfunction') || normalized.includes('wx-server-sdk') ||
530
- normalized.includes('cloud.init') || normalized.includes('exports.main')) {
531
- this.addScore(scores, 'standards://frameworks/wechat-miniprogram', weights.CONTENT);
532
- }
533
-
534
- // API 层关键词
535
- if (normalized.includes('axios.') || normalized.includes('.get(') ||
536
- normalized.includes('.post(') || normalized.includes('interceptor')) {
537
- this.addScore(scores, 'standards://patterns/api-layer', weights.CONTENT);
538
- }
539
-
540
- // Flutter Widget 关键词
541
- if (normalized.includes('statelesswidget') || normalized.includes('statefulwidget') ||
542
- normalized.includes('buildcontext') || normalized.includes('@override') ||
543
- normalized.includes('widget build(') || normalized.includes('getx') ||
544
- normalized.includes('get.find') || normalized.includes('obx(')) {
545
- this.addScore(scores, 'standards://frameworks/flutter', weights.CONTENT);
546
- }
547
-
548
- // Flutter UI Token 系统关键词
549
- if (normalized.includes('$c.') || normalized.includes('$s.') ||
550
- normalized.includes('$t.') || normalized.includes('$r.') ||
551
- normalized.includes('$shadow.') || normalized.includes('$b.') ||
552
- normalized.includes('flexbutton') || normalized.includes('flexcard') ||
553
- normalized.includes('flexinput') || normalized.includes('flexbox') ||
554
- normalized.includes('tokenmanager') || normalized.includes('designtokens') ||
555
- normalized.includes('thememanager') || normalized.includes('gap(')) {
556
- this.addScore(scores, 'standards://frameworks/flutter-ui-system', weights.CONTENT * 2);
557
- }
558
- }
559
-
560
- /**
561
- * 添加分数(累加)
562
- */
563
- private addScore(scores: Map<string, number>, uri: string, points: number): void {
564
- const current = scores.get(uri) || 0;
565
- scores.set(uri, current + points);
566
- }
567
-
568
- /**
569
- * 组合多个规范内容(Phase 3: 优化去重与顺序)
570
- */
571
- combineStandards(uris: string[]): string {
572
- const startTime = Date.now();
573
-
574
- // 去重(保持顺序)
575
- const uniqueUris = Array.from(new Set(uris));
576
-
577
- // 优化顺序:核心规范放在最前面
578
- const coreUris = uniqueUris.filter(uri => uri.startsWith('standards://core/'));
579
- const otherUris = uniqueUris.filter(uri => !uri.startsWith('standards://core/'));
580
- const sortedUris = [...coreUris, ...otherUris];
581
-
582
- const contents: string[] = [];
583
- let totalSize = 0;
584
-
585
- sortedUris.forEach(uri => {
586
- try {
587
- const content = this.readStandard(uri);
588
- const standardName = this.extractStandardName(uri);
589
-
590
- const section = `\n## 📚 ${standardName}\n\n${content}\n`;
591
- contents.push(section);
592
- totalSize += section.length;
593
- } catch (error) {
594
- console.error(`Failed to read standard ${uri}:`, error);
595
- }
596
- });
597
-
598
- const combined = contents.join('\n---\n');
599
-
600
- // 计算 token 节省(假设完整规范 ~10000 tokens)
601
- const estimatedTokens = Math.ceil(combined.length / 4);
602
- const baselineTokens = 10000;
603
- const tokensSaved = baselineTokens - estimatedTokens;
604
-
605
- this.metrics.totalTokensSaved += Math.max(0, tokensSaved);
606
-
607
- // 记录处理时间
608
- const processingTime = Date.now() - startTime;
609
- console.log(`[StandardsManager] Combined ${sortedUris.length} standards in ${processingTime}ms, ~${estimatedTokens} tokens (saved ${tokensSaved})`);
610
-
611
- return combined;
612
- }
613
-
614
- /**
615
- * 提取规范名称
616
- */
617
- private extractStandardName(uri: string): string {
618
- const match = uri.match(/^standards:\/\/([^/]+)\/(.+)$/);
619
- if (match) {
620
- const [, category, standardId] = match;
621
- return this.getStandardName(category, standardId);
622
- }
623
- return uri;
624
- }
625
-
626
- /**
627
- * 获取规范显示名称
628
- */
629
- private getStandardName(category: string, standardId: string): string {
630
- const nameMap: Record<string, Record<string, string>> = {
631
- core: {
632
- 'code-style': '代码风格规范',
633
- 'typescript-base': 'TypeScript 基础',
634
- 'dart-base': 'Dart 基础'
635
- },
636
- frameworks: {
637
- 'vue3-composition': 'Vue 3 Composition API',
638
- 'pinia': 'Pinia 状态管理',
639
- 'flutter': 'Flutter 开发规范',
640
- 'flutter-ui-system': 'Flutter UI 系统规范',
641
- 'wechat-miniprogram': '微信小程序开发'
642
- },
643
- libraries: {
644
- 'element-plus': 'Element Plus 组件库',
645
- 'i18n': '国际化 (i18n)'
646
- },
647
- patterns: {
648
- 'api-layer': 'API 层设计',
649
- 'component-design': '组件设计模式',
650
- 'vue-css-nesting': 'Vue CSS 嵌套写法',
651
- 'vue-api-mock-layer': 'Vue API Mock 层'
652
- }
653
- };
654
-
655
- return nameMap[category]?.[standardId] || standardId;
656
- }
657
-
658
- /**
659
- * 获取规范描述
660
- */
661
- private getStandardDescription(category: string, standardId: string): string {
662
- const descMap: Record<string, Record<string, string>> = {
663
- core: {
664
- 'code-style': '命名规范、代码组织、注释规范',
665
- 'typescript-base': '基础类型、函数、泛型使用',
666
- 'dart-base': '空安全、异步编程、类和对象'
667
- },
668
- frameworks: {
669
- 'vue3-composition': 'Props、Emits、生命周期、Composables',
670
- 'pinia': 'Store 定义、状态管理、持久化',
671
- 'flutter': 'Widget 设计、状态管理、性能优化',
672
- 'flutter-ui-system': 'Design Token、Flex组件、主题系统、$快捷方式',
673
- 'wechat-miniprogram': 'Page/Component、网络请求、性能优化'
674
- },
675
- libraries: {
676
- 'element-plus': '表单、表格、对话框、消息提示',
677
- 'i18n': '翻译文件、组件使用、参数化'
678
- },
679
- patterns: {
680
- 'api-layer': 'Axios 配置、API 模块化、错误处理',
681
- 'component-design': '组件通信、Props 验证、性能优化',
682
- 'vue-css-nesting': '原生嵌套语法、伪类伪元素、深度选择器',
683
- 'vue-api-mock-layer': 'Axios封装、Mock数据、模块化API'
684
- }
685
- };
686
-
687
- return descMap[category]?.[standardId] || '';
688
- }
689
-
690
- /**
691
- * 更新平均响应时间
692
- */
693
- private updateAverageResponseTime(responseTime: number): void {
694
- const { totalCalls, averageResponseTime } = this.metrics;
695
- this.metrics.totalCalls++;
696
- this.metrics.averageResponseTime =
697
- (averageResponseTime * totalCalls + responseTime) / this.metrics.totalCalls;
698
- }
699
-
700
- /**
701
- * 获取性能指标
702
- */
703
- getPerformanceMetrics(): PerformanceMetrics {
704
- return {
705
- ...this.metrics,
706
- cacheHitRate: this.metrics.totalCalls > 0
707
- ? (this.metrics.cacheHits / this.metrics.totalCalls * 100).toFixed(2) + '%'
708
- : '0%'
709
- } as any;
710
- }
711
-
712
- /**
713
- * 获取使用统计
714
- */
715
- getUsageStats(): {
716
- topCombinations: Array<{ combination: string; count: number }>;
717
- topStandards: Array<{ standard: string; count: number }>;
718
- totalCalls: number;
719
- } {
720
- // 获取最常用的规范组合(Top 5)
721
- const topCombinations = Array.from(this.stats.standardCombinations.entries())
722
- .sort((a, b) => b[1] - a[1])
723
- .slice(0, 5)
724
- .map(([combination, count]) => ({ combination, count }));
725
-
726
- // 获取最常用的单个规范(Top 5)
727
- const topStandards = Array.from(this.stats.individualStandards.entries())
728
- .sort((a, b) => b[1] - a[1])
729
- .slice(0, 5)
730
- .map(([standard, count]) => ({ standard, count }));
731
-
732
- return {
733
- topCombinations,
734
- topStandards,
735
- totalCalls: this.stats.totalCalls
736
- };
737
- }
738
-
739
- /**
740
- * 清除缓存
741
- */
742
- clearCache(): void {
743
- this.contentCache.clear();
744
- console.log('[StandardsManager] Cache cleared');
745
- }
746
-
747
- /**
748
- * 获取缓存统计
749
- */
750
- getCacheStats(): {
751
- size: number;
752
- maxSize: number;
753
- entries: Array<{ uri: string; accessCount: number; age: number }>;
754
- } {
755
- const entries = Array.from(this.contentCache.entries())
756
- .map(([uri, entry]) => ({
757
- uri,
758
- accessCount: entry.accessCount,
759
- age: Math.floor((Date.now() - entry.timestamp) / 1000) // 秒
760
- }))
761
- .sort((a, b) => b.accessCount - a.accessCount);
762
-
763
- return {
764
- size: this.contentCache.size,
765
- maxSize: this.MAX_CACHE_SIZE,
766
- entries
767
- };
768
- }
769
- }