autosnippet 3.0.13 → 3.1.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 (100) hide show
  1. package/bin/api-server.js +2 -0
  2. package/bin/cli.js +24 -19
  3. package/config/default.json +1 -1
  4. package/lib/bootstrap.js +4 -4
  5. package/lib/cli/SetupService.js +29 -29
  6. package/lib/cli/UpgradeService.js +3 -2
  7. package/lib/core/AstAnalyzer.js +1 -1
  8. package/lib/core/ast/ensure-grammars.js +1 -1
  9. package/lib/core/ast/index.js +62 -11
  10. package/lib/core/ast/lang-dart.js +27 -21
  11. package/lib/core/ast/lang-go.js +6 -20
  12. package/lib/core/ast/lang-rust.js +53 -28
  13. package/lib/core/ast/parser-init.js +9 -5
  14. package/lib/core/discovery/DartDiscoverer.js +4 -10
  15. package/lib/core/discovery/GoDiscoverer.js +45 -25
  16. package/lib/core/discovery/NodeDiscoverer.js +1 -3
  17. package/lib/core/discovery/PythonDiscoverer.js +7 -1
  18. package/lib/core/discovery/RustDiscoverer.js +111 -38
  19. package/lib/core/discovery/index.js +2 -2
  20. package/lib/core/enhancement/django-enhancement.js +10 -4
  21. package/lib/core/enhancement/fastapi-enhancement.js +16 -9
  22. package/lib/core/enhancement/go-grpc-enhancement.js +2 -1
  23. package/lib/core/enhancement/go-web-enhancement.js +3 -6
  24. package/lib/core/enhancement/ml-enhancement.js +6 -3
  25. package/lib/core/enhancement/nextjs-enhancement.js +17 -7
  26. package/lib/core/enhancement/node-server-enhancement.js +4 -2
  27. package/lib/core/enhancement/react-enhancement.js +6 -3
  28. package/lib/core/enhancement/rust-tokio-enhancement.js +6 -2
  29. package/lib/core/enhancement/rust-web-enhancement.js +13 -7
  30. package/lib/core/enhancement/vue-enhancement.js +10 -5
  31. package/lib/external/ai/AiFactory.js +3 -1
  32. package/lib/external/ai/AiProvider.js +3 -1
  33. package/lib/external/mcp/McpServer.js +2 -0
  34. package/lib/external/mcp/handlers/bootstrap/base-dimensions.js +1 -2
  35. package/lib/external/mcp/handlers/bootstrap/pipeline/checkpoint.js +7 -1
  36. package/lib/external/mcp/handlers/bootstrap/pipeline/noAiFallback.js +55 -26
  37. package/lib/external/mcp/handlers/bootstrap/pipeline/orchestrator.js +8 -8
  38. package/lib/external/mcp/handlers/bootstrap/refine.js +3 -1
  39. package/lib/external/mcp/handlers/bootstrap.js +4 -10
  40. package/lib/external/mcp/handlers/browse.js +6 -2
  41. package/lib/external/mcp/handlers/guard.js +6 -2
  42. package/lib/external/mcp/handlers/skill.js +6 -2
  43. package/lib/http/HttpServer.js +1 -1
  44. package/lib/http/routes/candidates.js +3 -1
  45. package/lib/http/routes/extract.js +4 -5
  46. package/lib/http/routes/guardRules.js +1 -1
  47. package/lib/http/routes/modules.js +9 -3
  48. package/lib/http/routes/skills.js +54 -6
  49. package/lib/http/routes/violations.js +4 -3
  50. package/lib/infrastructure/external/ClipboardManager.js +24 -7
  51. package/lib/infrastructure/external/NativeUi.js +3 -1
  52. package/lib/infrastructure/external/OpenBrowser.js +1 -0
  53. package/lib/infrastructure/external/XcodeAutomation.js +5 -5
  54. package/lib/infrastructure/vector/IndexingPipeline.js +14 -5
  55. package/lib/injection/ServiceContainer.js +34 -11
  56. package/lib/platform/ios/index.js +20 -25
  57. package/lib/platform/ios/routes/spm.js +6 -3
  58. package/lib/platform/ios/snippet/PlaceholderConverter.js +6 -2
  59. package/lib/platform/ios/snippet/XcodeCodec.js +4 -2
  60. package/lib/platform/ios/spm/SpmDiscoverer.js +1 -1
  61. package/lib/platform/ios/spm/SpmService.js +3 -1
  62. package/lib/platform/ios/xcode/XcodeIntegration.js +10 -12
  63. package/lib/platform/ios/xcode/XcodeWriteUtils.js +6 -1
  64. package/lib/service/automation/FileWatcher.js +1 -3
  65. package/lib/service/automation/handlers/CreateHandler.js +3 -5
  66. package/lib/service/automation/handlers/GuardHandler.js +11 -32
  67. package/lib/service/automation/handlers/SearchHandler.js +9 -9
  68. package/lib/service/chat/CandidateGuardrail.js +11 -6
  69. package/lib/service/chat/ChatAgent.js +31 -22
  70. package/lib/service/chat/HandoffProtocol.js +5 -2
  71. package/lib/service/chat/tools/composite.js +3 -2
  72. package/lib/service/chat/tools/index.js +60 -71
  73. package/lib/service/chat/tools/infrastructure.js +9 -4
  74. package/lib/service/chat/tools/lifecycle.js +22 -5
  75. package/lib/service/chat/tools/project-access.js +5 -9
  76. package/lib/service/chat/tools.js +1 -2
  77. package/lib/service/cursor/AgentInstructionsGenerator.js +33 -15
  78. package/lib/service/cursor/CursorDeliveryPipeline.js +2 -1
  79. package/lib/service/cursor/KnowledgeCompressor.js +16 -7
  80. package/lib/service/guard/ComplianceReporter.js +5 -2
  81. package/lib/service/guard/GuardCheckEngine.js +53 -26
  82. package/lib/service/guard/GuardCodeChecks.js +217 -188
  83. package/lib/service/guard/GuardCrossFileChecks.js +203 -184
  84. package/lib/service/guard/GuardPatternUtils.js +17 -10
  85. package/lib/service/module/ModuleService.js +180 -56
  86. package/lib/service/recipe/RecipeCandidateValidator.js +11 -8
  87. package/lib/service/snippet/SnippetFactory.js +3 -3
  88. package/lib/service/snippet/SnippetInstaller.js +35 -11
  89. package/lib/service/snippet/codecs/VSCodeCodec.js +2 -2
  90. package/lib/service/wiki/WikiGenerator.js +54 -36
  91. package/lib/service/wiki/WikiRenderers.js +105 -80
  92. package/lib/service/wiki/WikiUtils.js +217 -80
  93. package/lib/shared/LanguageService.js +111 -53
  94. package/lib/shared/PathGuard.js +0 -8
  95. package/package.json +3 -9
  96. package/scripts/bench-real-projects.mjs +29 -29
  97. package/scripts/generate-recipe-drafts.js +17 -27
  98. package/scripts/init-snippets.js +43 -24
  99. package/scripts/install-vscode-copilot.js +3 -19
  100. package/scripts/setup-mcp-config.js +0 -4
@@ -33,10 +33,22 @@ const AGENT_BUDGET = Object.freeze({
33
33
  * MCP 工具清单 — 精简版(跟随实际 MCP handler 注册名称)
34
34
  */
35
35
  const MCP_TOOLS_SUMMARY = [
36
- { name: 'autosnippet_search', desc: 'Search knowledge base (mode: auto/context/keyword/semantic)' },
37
- { name: 'autosnippet_knowledge', desc: 'Knowledge CRUD (operation: list/get/insights/confirm_usage)' },
38
- { name: 'autosnippet_submit_knowledge', desc: 'Submit a knowledge candidate (strict validation)' },
39
- { name: 'autosnippet_submit_knowledge_batch', desc: 'Batch submit candidates (with dedup + throttle)' },
36
+ {
37
+ name: 'autosnippet_search',
38
+ desc: 'Search knowledge base (mode: auto/context/keyword/semantic)',
39
+ },
40
+ {
41
+ name: 'autosnippet_knowledge',
42
+ desc: 'Knowledge CRUD (operation: list/get/insights/confirm_usage)',
43
+ },
44
+ {
45
+ name: 'autosnippet_submit_knowledge',
46
+ desc: 'Submit a knowledge candidate (strict validation)',
47
+ },
48
+ {
49
+ name: 'autosnippet_submit_knowledge_batch',
50
+ desc: 'Batch submit candidates (with dedup + throttle)',
51
+ },
40
52
  { name: 'autosnippet_guard', desc: 'Code compliance check (single file or batch audit)' },
41
53
  { name: 'autosnippet_structure', desc: 'Project structure discovery (targets/files/metadata)' },
42
54
  { name: 'autosnippet_graph', desc: 'Knowledge graph query (query/impact/path/stats)' },
@@ -126,7 +138,9 @@ export class AgentInstructionsGenerator {
126
138
  // 有明确否定词的统一为 "Do NOT",否则保留原文(如 "Avoid ...")
127
139
  const hasNegPrefix = /^(Don't|Do not|Never)\s+/i.test(e.dontClause);
128
140
  if (hasNegPrefix) {
129
- const stripped = e.dontClause.replace(/^(Don't|Do not|Never)\s+/i, '').replace(/\.+$/, '');
141
+ const stripped = e.dontClause
142
+ .replace(/^(Don't|Do not|Never)\s+/i, '')
143
+ .replace(/\.+$/, '');
130
144
  line += `. Do NOT ${stripped}`;
131
145
  } else {
132
146
  line += `. ${e.dontClause.replace(/\.+$/, '')}`;
@@ -147,14 +161,10 @@ export class AgentInstructionsGenerator {
147
161
  });
148
162
 
149
163
  // Skills 列表
150
- const skillLines = skills
151
- .slice(0, AGENT_BUDGET.MAX_SKILLS)
152
- .map((s) => `- \`${s}\``);
164
+ const skillLines = skills.slice(0, AGENT_BUDGET.MAX_SKILLS).map((s) => `- \`${s}\``);
153
165
 
154
166
  // MCP 工具列表
155
- const toolLines = MCP_TOOLS_SUMMARY.map(
156
- (t) => `- \`${t.name}\` — ${t.desc}`
157
- );
167
+ const toolLines = MCP_TOOLS_SUMMARY.map((t) => `- \`${t.name}\` — ${t.desc}`);
158
168
 
159
169
  return { ruleLines, patternRows, skillLines, toolLines };
160
170
  }
@@ -267,10 +277,18 @@ export class AgentInstructionsGenerator {
267
277
 
268
278
  // Key tools highlight for Claude
269
279
  lines.push('### Recommended Workflow', '');
270
- lines.push('1. **Before writing code**: `autosnippet_search({ query: "<topic>" })` to find relevant patterns');
271
- lines.push('2. **Check compliance**: `autosnippet_guard({ code: "<your code>" })` before committing');
272
- lines.push('3. **Record knowledge**: `autosnippet_submit_knowledge({ ... })` when discovering reusable patterns');
273
- lines.push('4. **Confirm adoption**: `autosnippet_knowledge({ operation: "confirm_usage", id: "<id>" })`');
280
+ lines.push(
281
+ '1. **Before writing code**: `autosnippet_search({ query: "<topic>" })` to find relevant patterns'
282
+ );
283
+ lines.push(
284
+ '2. **Check compliance**: `autosnippet_guard({ code: "<your code>" })` before committing'
285
+ );
286
+ lines.push(
287
+ '3. **Record knowledge**: `autosnippet_submit_knowledge({ ... })` when discovering reusable patterns'
288
+ );
289
+ lines.push(
290
+ '4. **Confirm adoption**: `autosnippet_knowledge({ operation: "confirm_usage", id: "<id>" })`'
291
+ );
274
292
  lines.push('');
275
293
 
276
294
  // Skills
@@ -101,7 +101,8 @@ export class CursorDeliveryPipeline {
101
101
 
102
102
  // NOTE: .qoder/ .trae/ 镜像不再自动执行,由 `asd mirror` 按需触发
103
103
 
104
- stats.totalTokensUsed = channelA.tokensUsed + channelB.totalTokens + (channelF.totalTokens || 0);
104
+ stats.totalTokensUsed =
105
+ channelA.tokensUsed + channelB.totalTokens + (channelF.totalTokens || 0);
105
106
  stats.duration = Date.now() - startTime;
106
107
 
107
108
  this.logger.info?.(
@@ -15,16 +15,22 @@
15
15
 
16
16
  /** 从 rationale 提取首句(≤120 字符),用于 Channel B 的 Why 行 */
17
17
  function _extractFirstSentence(rationale) {
18
- if (!rationale) return '';
18
+ if (!rationale) {
19
+ return '';
20
+ }
19
21
  // 优先按句号或换行分割
20
22
  const first = rationale.split(/[.\n。!?!?]/)[0]?.trim();
21
- if (!first) return '';
23
+ if (!first) {
24
+ return '';
25
+ }
22
26
  return first.length > 120 ? `${first.slice(0, 117)}...` : first;
23
27
  }
24
28
 
25
29
  /** 骨架化 coreCode:去注释 + 截断 ≤ maxLines 行 */
26
30
  function _skeletonize(code, maxLines = 15) {
27
- if (!code) return '';
31
+ if (!code) {
32
+ return '';
33
+ }
28
34
  const lines = code
29
35
  .split('\n')
30
36
  // 去掉纯注释行(// 或 /* 或 * (JSDoc续行) 或 # 开头)
@@ -37,7 +43,9 @@ function _skeletonize(code, maxLines = 15) {
37
43
  acc.push(line);
38
44
  return acc;
39
45
  }, []);
40
- if (lines.length <= maxLines) return lines.join('\n');
46
+ if (lines.length <= maxLines) {
47
+ return lines.join('\n');
48
+ }
41
49
  return `${lines.slice(0, maxLines).join('\n')}\n// ... (truncated)`;
42
50
  }
43
51
 
@@ -56,13 +64,14 @@ export class KnowledgeCompressor {
56
64
  .filter((e) => e.doClause) // 无 doClause → 跳过,不猜
57
65
  .map((e) => {
58
66
  // 可选 language 前缀
59
- const langPrefix =
60
- e.language && e.scope !== 'universal' ? `[${e.language}] ` : '';
67
+ const langPrefix = e.language && e.scope !== 'universal' ? `[${e.language}] ` : '';
61
68
  const doText = e.doClause.replace(/\.+$/, ''); // 去尾 .
62
69
  let line = `${langPrefix}${doText}`;
63
70
  if (e.dontClause) {
64
71
  // AI 可能返回 "Don't ..." / "Do not ..." / "Never ..." 开头,去掉冗余前缀后统一为 "Do NOT"
65
- const stripped = e.dontClause.replace(/^(Don't|Do not|Never)\s+/i, '').replace(/\.+$/, '');
72
+ const stripped = e.dontClause
73
+ .replace(/^(Don't|Do not|Never)\s+/i, '')
74
+ .replace(/\.+$/, '');
66
75
  line += `. Do NOT ${stripped}`;
67
76
  }
68
77
  return `- ${line}.`;
@@ -283,11 +283,14 @@ export class ComplianceReporter {
283
283
 
284
284
  const lines = [];
285
285
  lines.push(`${gateIcon} Quality Gate: ${qualityGate.status} Score: ${qualityGate.score}/100`);
286
- lines.push(` Files: ${summary.filesScanned} Errors: ${summary.errors} Warnings: ${summary.warnings} Infos: ${summary.infos || 0}`);
286
+ lines.push(
287
+ ` Files: ${summary.filesScanned} Errors: ${summary.errors} Warnings: ${summary.warnings} Infos: ${summary.infos || 0}`
288
+ );
287
289
 
288
290
  if (trend.hasHistory) {
289
291
  const errTrend = trend.errorsChange > 0 ? `+${trend.errorsChange}` : `${trend.errorsChange}`;
290
- const warnTrend = trend.warningsChange > 0 ? `+${trend.warningsChange}` : `${trend.warningsChange}`;
292
+ const warnTrend =
293
+ trend.warningsChange > 0 ? `+${trend.warningsChange}` : `${trend.warningsChange}`;
291
294
  lines.push(` Trend: Errors ${errTrend} Warnings ${warnTrend}`);
292
295
  }
293
296
 
@@ -8,9 +8,15 @@
8
8
  import * as AstAnalyzerModule from '../../core/AstAnalyzer.js';
9
9
  import Logger from '../../infrastructure/logging/Logger.js';
10
10
  import { LanguageService } from '../../shared/LanguageService.js';
11
- import { compilePattern, clearPatternCache, buildTestBlockMask, buildCommentMask, detectLanguage } from './GuardPatternUtils.js';
12
11
  import { runCodeLevelChecks } from './GuardCodeChecks.js';
13
12
  import { runCrossFileChecks } from './GuardCrossFileChecks.js';
13
+ import {
14
+ buildCommentMask,
15
+ buildTestBlockMask,
16
+ clearPatternCache,
17
+ compilePattern,
18
+ detectLanguage,
19
+ } from './GuardPatternUtils.js';
14
20
 
15
21
  /**
16
22
  * 内置默认规则集 — 多语言基础规则
@@ -125,7 +131,8 @@ const BUILT_IN_RULES = {
125
131
  languages: ['javascript', 'typescript'],
126
132
  dimension: 'file',
127
133
  category: 'style',
128
- excludePaths: /(?:^|[\/\\])(?:test|tests|__tests__|spec|__mocks__|mock|mocks|fixtures?)[\/\\]|[\/\\](?:test_|spec_)[^\/\\]*\.(?:js|ts)$|\.(?:test|spec)\.(?:js|ts)$/,
134
+ excludePaths:
135
+ /(?:^|[/\\])(?:test|tests|__tests__|spec|__mocks__|mock|mocks|fixtures?)[/\\]|[/\\](?:test_|spec_)[^/\\]*\.(?:js|ts)$|\.(?:test|spec)\.(?:js|ts)$/,
129
136
  },
130
137
  'js-no-console-log': {
131
138
  message: '生产代码应移除 console.log,使用专用日志库',
@@ -134,7 +141,8 @@ const BUILT_IN_RULES = {
134
141
  languages: ['javascript', 'typescript'],
135
142
  dimension: 'file',
136
143
  category: 'style',
137
- excludePaths: /(?:^|[\/\\])(?:test|tests|__tests__|spec|mock|mocks|__mocks__|scripts|tools|debug)[\/\\]|[\/\\](?:test_|spec_|mock)[^\/\\]*\.(?:js|ts)$|\.(?:test|spec)\.(?:js|ts)$/,
144
+ excludePaths:
145
+ /(?:^|[/\\])(?:test|tests|__tests__|spec|mock|mocks|__mocks__|scripts|tools|debug)[/\\]|[/\\](?:test_|spec_|mock)[^/\\]*\.(?:js|ts)$|\.(?:test|spec)\.(?:js|ts)$/,
138
146
  },
139
147
  'js-no-debugger': {
140
148
  message: '生产代码中不应包含 debugger 语句',
@@ -204,7 +212,7 @@ const BUILT_IN_RULES = {
204
212
  languages: ['python'],
205
213
  dimension: 'file',
206
214
  category: 'correctness',
207
- excludePaths: /(?:^|[\/\\])tests?[\/\\]|[\/\\]test_[^\/\\]*\.py$|_test\.py$/,
215
+ excludePaths: /(?:^|[/\\])tests?[/\\]|[/\\]test_[^/\\]*\.py$|_test\.py$/,
208
216
  },
209
217
 
210
218
  // ══════════════════════════════════════════════════════════
@@ -272,7 +280,7 @@ const BUILT_IN_RULES = {
272
280
  languages: ['go'],
273
281
  dimension: 'file',
274
282
  category: 'correctness',
275
- excludePaths: /(?:^|[\/\\])(?:tests?|testdata|_test)[\/\\]|_test\.go$/,
283
+ excludePaths: /(?:^|[/\\])(?:tests?|testdata|_test)[/\\]|_test\.go$/,
276
284
  },
277
285
  'go-no-init-abuse': {
278
286
  message: 'init() 函数副作用难以追踪,避免在 init 中执行复杂逻辑',
@@ -289,7 +297,7 @@ const BUILT_IN_RULES = {
289
297
  languages: ['go'],
290
298
  dimension: 'file',
291
299
  category: 'style',
292
- excludePaths: /(?:^|[\/\\])(?:tests?|testdata)[\/\\]|_test\.go$/,
300
+ excludePaths: /(?:^|[/\\])(?:tests?|testdata)[/\\]|_test\.go$/,
293
301
  },
294
302
 
295
303
  // ══════════════════════════════════════════════════════════
@@ -311,7 +319,8 @@ const BUILT_IN_RULES = {
311
319
  languages: ['dart'],
312
320
  dimension: 'file',
313
321
  category: 'style',
314
- fixSuggestion: '使用 Object? 或具体类型替代 dynamic;Map<String, dynamic> 用于 JSON 序列化时可保留',
322
+ fixSuggestion:
323
+ '使用 Object? 或具体类型替代 dynamic;Map<String, dynamic> 用于 JSON 序列化时可保留',
315
324
  },
316
325
  'dart-no-set-state-after-dispose': {
317
326
  message: 'setState 调用前应检查 mounted 状态,避免 disposed 后调用',
@@ -344,7 +353,7 @@ const BUILT_IN_RULES = {
344
353
  'dart-no-relative-import': {
345
354
  message: 'lib/ 目录内应使用 package: 形式的绝对导入,避免相对路径导入',
346
355
  severity: 'info',
347
- pattern: "import\\s+['\"]\\.\\.?/",
356
+ pattern: 'import\\s+[\'"]\\.\\.?/',
348
357
  languages: ['dart'],
349
358
  dimension: 'file',
350
359
  category: 'style',
@@ -352,7 +361,8 @@ const BUILT_IN_RULES = {
352
361
  'dart-dispose-controller': {
353
362
  message: 'TextEditingController/AnimationController 等须在 dispose() 中释放',
354
363
  severity: 'warning',
355
- pattern: '(?:TextEditingController|AnimationController|ScrollController|FocusNode|TabController)\\(',
364
+ pattern:
365
+ '(?:TextEditingController|AnimationController|ScrollController|FocusNode|TabController)\\(',
356
366
  languages: ['dart'],
357
367
  dimension: 'file',
358
368
  category: 'correctness',
@@ -380,7 +390,8 @@ const BUILT_IN_RULES = {
380
390
  dimension: 'file',
381
391
  category: 'correctness',
382
392
  fixSuggestion: '使用 ? 操作符传播错误,或 .unwrap_or_default() / .expect("原因")',
383
- excludePaths: /(?:^|[\/\\])(?:tests?|test_helpers|benches|examples)[\/\\]|[\/\\]test_[^\/\\]*\.rs$|_test\.rs$/,
393
+ excludePaths:
394
+ /(?:^|[/\\])(?:tests?|test_helpers|benches|examples)[/\\]|[/\\]test_[^/\\]*\.rs$|_test\.rs$/,
384
395
  skipComments: true,
385
396
  skipTestBlocks: true,
386
397
  },
@@ -409,7 +420,7 @@ const BUILT_IN_RULES = {
409
420
  languages: ['rust'],
410
421
  dimension: 'file',
411
422
  category: 'correctness',
412
- excludePaths: /(?:^|[\/\\])(?:tests?|test_helpers|benches|examples)[\/\\]|_test\.rs$/,
423
+ excludePaths: /(?:^|[/\\])(?:tests?|test_helpers|benches|examples)[/\\]|_test\.rs$/,
413
424
  skipComments: true,
414
425
  skipTestBlocks: true,
415
426
  },
@@ -421,7 +432,7 @@ const BUILT_IN_RULES = {
421
432
  dimension: 'file',
422
433
  category: 'performance',
423
434
  fixSuggestion: '分析是否可用 &T 借用替代,或使用 Cow<T> 延迟克隆',
424
- excludePaths: /(?:^|[\/\\])(?:tests?|test_helpers|benches|examples)[\/\\]|_test\.rs$/,
435
+ excludePaths: /(?:^|[/\\])(?:tests?|test_helpers|benches|examples)[/\\]|_test\.rs$/,
425
436
  skipComments: true,
426
437
  skipTestBlocks: true,
427
438
  },
@@ -432,7 +443,7 @@ const BUILT_IN_RULES = {
432
443
  languages: ['rust'],
433
444
  dimension: 'file',
434
445
  category: 'correctness',
435
- excludePaths: /(?:^|[\/\\])(?:tests?|test_helpers|benches|examples)[\/\\]|main\.rs$/,
446
+ excludePaths: /(?:^|[/\\])(?:tests?|test_helpers|benches|examples)[/\\]|main\.rs$/,
436
447
  skipComments: true,
437
448
  skipTestBlocks: true,
438
449
  },
@@ -454,7 +465,6 @@ const BUILT_IN_RULES = {
454
465
  category: 'performance',
455
466
  fixSuggestion: '使用 Vec<&str> 收集后 .join(),或 String::with_capacity 预分配',
456
467
  },
457
-
458
468
  };
459
469
 
460
470
  // 向后兼容: 从 GuardPatternUtils 重新导出 detectLanguage
@@ -489,13 +499,20 @@ export class GuardCheckEngine {
489
499
  * @param {Array<{ruleId: string, pattern: RegExp|string, severity: string, message: string, category?: string, dimension?: string, languages?: string[], fixSuggestion?: string}>} rules
490
500
  */
491
501
  injectExternalRules(rules) {
492
- if (!Array.isArray(rules)) return;
502
+ if (!Array.isArray(rules)) {
503
+ return;
504
+ }
493
505
  for (const rule of rules) {
494
- if (!rule.ruleId) continue;
506
+ if (!rule.ruleId) {
507
+ continue;
508
+ }
495
509
  // 已注入的 ruleId 跳过(幂等)
496
- if (this._externalRules.has(rule.ruleId)) continue;
510
+ if (this._externalRules.has(rule.ruleId)) {
511
+ continue;
512
+ }
497
513
  // 跳过与 BUILT_IN_RULES 重复的模式(通过比较 pattern 源文本)
498
- const rulePatternStr = rule.pattern instanceof RegExp ? rule.pattern.source : String(rule.pattern || '');
514
+ const rulePatternStr =
515
+ rule.pattern instanceof RegExp ? rule.pattern.source : String(rule.pattern || '');
499
516
  const isDuplicate = Object.entries(this._builtInRules).some(([, builtIn]) => {
500
517
  return builtIn.pattern === rulePatternStr;
501
518
  });
@@ -517,14 +534,20 @@ export class GuardCheckEngine {
517
534
  fixSuggestion: rule.fixSuggestion || null,
518
535
  });
519
536
  }
520
- this.logger.debug(`[GuardCheckEngine] External rules injected: ${this._externalRules.size} active`);
537
+ this.logger.debug(
538
+ `[GuardCheckEngine] External rules injected: ${this._externalRules.size} active`
539
+ );
521
540
  }
522
541
 
523
542
  /**
524
543
  * EP 注入幂等标记 — 调用者可用此判断是否已完成注入,避免重复加载 EnhancementRegistry
525
544
  */
526
- isEpInjected() { return this._epInjected; }
527
- markEpInjected() { this._epInjected = true; }
545
+ isEpInjected() {
546
+ return this._epInjected;
547
+ }
548
+ markEpInjected() {
549
+ this._epInjected = true;
550
+ }
528
551
 
529
552
  /**
530
553
  * 获取所有启用的规则 (数据库 + 内置)
@@ -665,7 +688,9 @@ export class GuardCheckEngine {
665
688
  // 按 excludePaths 过滤(测试文件排除等)
666
689
  if (filePath) {
667
690
  rules = rules.filter((r) => {
668
- if (!r.excludePaths) return true;
691
+ if (!r.excludePaths) {
692
+ return true;
693
+ }
669
694
  const re = r.excludePaths instanceof RegExp ? r.excludePaths : new RegExp(r.excludePaths);
670
695
  return !re.test(filePath);
671
696
  });
@@ -735,10 +760,12 @@ export class GuardCheckEngine {
735
760
  }
736
761
 
737
762
  // Code-level 检查(不依赖正则)
738
- violations.push(...runCodeLevelChecks(code, language, lines, {
739
- disabledRules: this._guardConfig.disabledRules,
740
- codeLevelThresholds: this._guardConfig.codeLevelThresholds,
741
- }));
763
+ violations.push(
764
+ ...runCodeLevelChecks(code, language, lines, {
765
+ disabledRules: this._guardConfig.disabledRules,
766
+ codeLevelThresholds: this._guardConfig.codeLevelThresholds,
767
+ })
768
+ );
742
769
 
743
770
  // AST 语义规则检查
744
771
  violations.push(...this._runAstRuleChecks(code, language));