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
@@ -127,7 +127,9 @@ class RustWebEnhancement extends EnhancementPack {
127
127
 
128
128
  // ── Structs used as State / AppData ──
129
129
  for (const cls of astSummary.classes || []) {
130
- if (cls.kind !== 'struct') continue;
130
+ if (cls.kind !== 'struct') {
131
+ continue;
132
+ }
131
133
  const nameLower = cls.name.toLowerCase();
132
134
  if (
133
135
  nameLower.includes('state') ||
@@ -164,7 +166,9 @@ class RustWebEnhancement extends EnhancementPack {
164
166
 
165
167
  // ── Middleware / Layer structs ──
166
168
  for (const cls of astSummary.classes || []) {
167
- if (cls.kind !== 'struct') continue;
169
+ if (cls.kind !== 'struct') {
170
+ continue;
171
+ }
168
172
  const nameLower = cls.name.toLowerCase();
169
173
  if (
170
174
  nameLower.includes('middleware') ||
@@ -185,12 +189,12 @@ class RustWebEnhancement extends EnhancementPack {
185
189
 
186
190
  // ── Extractor structs (used as handler params) ──
187
191
  for (const cls of astSummary.classes || []) {
188
- if (cls.kind !== 'struct') continue;
192
+ if (cls.kind !== 'struct') {
193
+ continue;
194
+ }
189
195
  // Derive-heavy DTOs used as Json<T>, Query<T>, Path<T>
190
196
  if (cls.derives && cls.derives.length >= 2) {
191
- const hasSerdeDerive = cls.derives.some(
192
- (d) => d === 'Deserialize' || d === 'Serialize'
193
- );
197
+ const hasSerdeDerive = cls.derives.some((d) => d === 'Deserialize' || d === 'Serialize');
194
198
  if (hasSerdeDerive) {
195
199
  const nameLower = cls.name.toLowerCase();
196
200
  if (
@@ -215,7 +219,9 @@ class RustWebEnhancement extends EnhancementPack {
215
219
 
216
220
  // ── Response structs ──
217
221
  for (const cls of astSummary.classes || []) {
218
- if (cls.kind !== 'struct') continue;
222
+ if (cls.kind !== 'struct') {
223
+ continue;
224
+ }
219
225
  const nameLower = cls.name.toLowerCase();
220
226
  if (
221
227
  nameLower.includes('response') ||
@@ -29,7 +29,8 @@ class VueEnhancement extends EnhancementPack {
29
29
  {
30
30
  id: 'composable-scan',
31
31
  label: 'Composable 函数分析',
32
- guide: 'Composable 函数(useXxx)+ 内部 ref/computed/watch 调用、Composable 组合链、provide/inject 依赖注入模式',
32
+ guide:
33
+ 'Composable 函数(useXxx)+ 内部 ref/computed/watch 调用、Composable 组合链、provide/inject 依赖注入模式',
33
34
  knowledgeTypes: ['code-pattern'],
34
35
  skillWorthy: true,
35
36
  dualOutput: true,
@@ -97,7 +98,8 @@ class VueEnhancement extends EnhancementPack {
97
98
  severity: 'warning',
98
99
  languages: ['typescript', 'javascript'],
99
100
  pattern: /(?:const|let)\s*\{[^}]+\}\s*=\s*(?:reactive|toRefs)\s*\(/,
100
- message: '解构 reactive() 对象会失去响应性,使用 toRefs() 或保持引用访问。Vue 3.5 的 Reactive Props Destructure 除外',
101
+ message:
102
+ '解构 reactive() 对象会失去响应性,使用 toRefs() 或保持引用访问。Vue 3.5 的 Reactive Props Destructure 除外',
101
103
  },
102
104
  {
103
105
  ruleId: 'vue-computed-side-effect',
@@ -105,8 +107,10 @@ class VueEnhancement extends EnhancementPack {
105
107
  dimension: 'file',
106
108
  severity: 'warning',
107
109
  languages: ['typescript', 'javascript'],
108
- pattern: /computed\s*\(\s*(?:\(\)|function\s*\(\))\s*(?:=>)?\s*\{[^}]*(?:fetch|axios|console\.log|\.value\s*=)/,
109
- message: 'computed 中不应有副作用 (网络请求、修改 ref、console.log) — 使用 watch/watchEffect 代替',
110
+ pattern:
111
+ /computed\s*\(\s*(?:\(\)|function\s*\(\))\s*(?:=>)?\s*\{[^}]*(?:fetch|axios|console\.log|\.value\s*=)/,
112
+ message:
113
+ 'computed 中不应有副作用 (网络请求、修改 ref、console.log) — 使用 watch/watchEffect 代替',
110
114
  },
111
115
  {
112
116
  ruleId: 'vue-v-for-with-v-if',
@@ -115,7 +119,8 @@ class VueEnhancement extends EnhancementPack {
115
119
  severity: 'warning',
116
120
  languages: ['typescript', 'javascript'],
117
121
  pattern: /v-for=[\s\S]*?v-if=/,
118
- message: '避免在同一元素上同时使用 v-for 和 v-if — v-if 优先级高于 v-for(Vue 3),用 computed 过滤或包裹 <template>',
122
+ message:
123
+ '避免在同一元素上同时使用 v-for 和 v-if — v-if 优先级高于 v-for(Vue 3),用 computed 过滤或包裹 <template>',
119
124
  },
120
125
  {
121
126
  ruleId: 'vue-no-ref-in-reactive',
@@ -114,7 +114,9 @@ export function autoDetectProvider() {
114
114
  return createProvider({ provider: 'deepseek' });
115
115
  }
116
116
 
117
- logger.info('[AiFactory] 未找到任何 AI API Key,AI 功能已跳过。请在 .env 中配置 ASD_GOOGLE_API_KEY 等。');
117
+ logger.info(
118
+ '[AiFactory] 未找到任何 AI API Key,AI 功能已跳过。请在 .env 中配置 ASD_GOOGLE_API_KEY 等。'
119
+ );
118
120
  return createProvider({ provider: 'mock' });
119
121
  }
120
122
 
@@ -344,7 +344,9 @@ ${files}`;
344
344
  * @returns {string} 语言指令段落(为空则返回空字符串)
345
345
  */
346
346
  _buildLangInstruction(lang) {
347
- if (!lang || lang === 'en') return '';
347
+ if (!lang || lang === 'en') {
348
+ return '';
349
+ }
348
350
  if (lang === 'zh') {
349
351
  return `
350
352
  # 输出语言要求
@@ -71,6 +71,8 @@ export class McpServer {
71
71
  auditLogger: components.auditLogger,
72
72
  gateway: components.gateway,
73
73
  constitution: components.constitution,
74
+ config: components.config,
75
+ skillHooks: components.skillHooks,
74
76
  projectRoot,
75
77
  });
76
78
 
@@ -31,8 +31,7 @@ export const baseDimensions = [
31
31
  dualOutput: true,
32
32
  skillMeta: {
33
33
  name: 'project-code-standard',
34
- description:
35
- 'Project coding standards and naming conventions (auto-generated by bootstrap)',
34
+ description: 'Project coding standards and naming conventions (auto-generated by bootstrap)',
36
35
  },
37
36
  },
38
37
  // ② 代码模式(Candidate)
@@ -22,7 +22,13 @@ const CHECKPOINT_TTL_MS = 3600_000; // 1小时内有效
22
22
  * @param {object} result — 维度执行结果
23
23
  * @param {object} [digest] — DimensionDigest
24
24
  */
25
- export async function saveDimensionCheckpoint(projectRoot, sessionId, dimId, result, digest = null) {
25
+ export async function saveDimensionCheckpoint(
26
+ projectRoot,
27
+ sessionId,
28
+ dimId,
29
+ result,
30
+ digest = null
31
+ ) {
26
32
  try {
27
33
  const checkpointDir = path.join(projectRoot, '.autosnippet', 'bootstrap-checkpoint');
28
34
  await fs.mkdir(checkpointDir, { recursive: true });
@@ -25,14 +25,13 @@ const logger = Logger.getInstance();
25
25
  */
26
26
  export async function runNoAiFallback(fillContext) {
27
27
  const {
28
- ctx,
28
+ // ctx and projectRoot are part of fillContext API but unused in fallback path
29
29
  dimensions,
30
30
  depGraphData,
31
31
  guardAudit,
32
32
  langStats,
33
33
  primaryLang,
34
34
  astProjectSummary,
35
- projectRoot,
36
35
  taskManager,
37
36
  sessionId,
38
37
  } = fillContext;
@@ -45,7 +44,7 @@ export async function runNoAiFallback(fillContext) {
45
44
  const report = { dimensionsProcessed: 0, candidatesCreated: 0, skillsCreated: 0, errors: [] };
46
45
 
47
46
  // ── 收集原始数据 ──
48
- let allFiles = fillContext.allFiles || [];
47
+ const allFiles = fillContext.allFiles || [];
49
48
  const targetFileMap = fillContext.targetFileMap || {};
50
49
  const allTargets = Object.keys(targetFileMap);
51
50
 
@@ -160,7 +159,14 @@ export async function runNoAiFallback(fillContext) {
160
159
  // 维度构建器
161
160
  // ═══════════════════════════════════════════════════════════
162
161
 
163
- function _buildProjectProfile({ langStats, primaryLang, depGraphData, allTargets, allFiles, astProjectSummary }) {
162
+ function _buildProjectProfile({
163
+ langStats,
164
+ primaryLang,
165
+ depGraphData,
166
+ allTargets,
167
+ allFiles,
168
+ astProjectSummary,
169
+ }) {
164
170
  const lines = ['## 项目技术画像', ''];
165
171
 
166
172
  // 语言统计
@@ -183,9 +189,7 @@ function _buildProjectProfile({ langStats, primaryLang, depGraphData, allTargets
183
189
  lines.push(`### 模块结构`, '');
184
190
  lines.push(`项目包含 **${allTargets.length}** 个模块/Target:`, '');
185
191
  for (const t of allTargets.slice(0, 15)) {
186
- const fileCount = Array.isArray(allFiles)
187
- ? allFiles.filter((f) => f.target === t).length
188
- : 0;
192
+ const fileCount = Array.isArray(allFiles) ? allFiles.filter((f) => f.target === t).length : 0;
189
193
  lines.push(`- \`${t}\` (${fileCount} files)`);
190
194
  }
191
195
  if (allTargets.length > 15) {
@@ -207,7 +211,9 @@ function _buildProjectProfile({ langStats, primaryLang, depGraphData, allTargets
207
211
  lines.push(`- 类/结构体: ${astProjectSummary.classes?.length || 0}`);
208
212
  lines.push(`- 协议/接口: ${astProjectSummary.protocols?.length || 0}`);
209
213
  lines.push(`- 方法总数: ${m.totalMethods || 0}`);
210
- if (m.maxNestingDepth) lines.push(`- 最大嵌套深度: ${m.maxNestingDepth}`);
214
+ if (m.maxNestingDepth) {
215
+ lines.push(`- 最大嵌套深度: ${m.maxNestingDepth}`);
216
+ }
211
217
  if (m.complexMethods?.length > 0) {
212
218
  lines.push(`- 高复杂度方法: ${m.complexMethods.length}`);
213
219
  }
@@ -218,7 +224,9 @@ function _buildProjectProfile({ langStats, primaryLang, depGraphData, allTargets
218
224
  }
219
225
 
220
226
  const markdown = lines.join('\n');
221
- if (markdown.length < 50) return null;
227
+ if (markdown.length < 50) {
228
+ return null;
229
+ }
222
230
 
223
231
  return _makeCandidate({
224
232
  title: `项目技术画像 — ${primaryLang}`,
@@ -231,7 +239,9 @@ function _buildProjectProfile({ langStats, primaryLang, depGraphData, allTargets
231
239
  }
232
240
 
233
241
  function _buildArchitecture({ depGraphData, allTargets, targetFileMap, primaryLang }) {
234
- if (!depGraphData?.edges?.length && allTargets.length < 2) return null;
242
+ if (!depGraphData?.edges?.length && allTargets.length < 2) {
243
+ return null;
244
+ }
235
245
 
236
246
  const lines = ['## 模块架构', ''];
237
247
 
@@ -260,8 +270,12 @@ function _buildArchitecture({ depGraphData, allTargets, targetFileMap, primaryLa
260
270
  for (const e of depGraphData.edges) {
261
271
  const from = typeof e.from === 'string' ? e.from : e.source;
262
272
  const to = typeof e.to === 'string' ? e.to : e.target;
263
- if (from) outDeg[from] = (outDeg[from] || 0) + 1;
264
- if (to) inDeg[to] = (inDeg[to] || 0) + 1;
273
+ if (from) {
274
+ outDeg[from] = (outDeg[from] || 0) + 1;
275
+ }
276
+ if (to) {
277
+ inDeg[to] = (inDeg[to] || 0) + 1;
278
+ }
265
279
  }
266
280
 
267
281
  // 核心模块(被依赖最多)
@@ -288,7 +302,9 @@ function _buildArchitecture({ depGraphData, allTargets, targetFileMap, primaryLa
288
302
  }
289
303
 
290
304
  const markdown = lines.join('\n');
291
- if (markdown.length < 80) return null;
305
+ if (markdown.length < 80) {
306
+ return null;
307
+ }
292
308
 
293
309
  return _makeCandidate({
294
310
  title: '模块架构与依赖关系',
@@ -301,7 +317,9 @@ function _buildArchitecture({ depGraphData, allTargets, targetFileMap, primaryLa
301
317
  }
302
318
 
303
319
  function _buildCodeStandard({ astProjectSummary, primaryLang, allFiles }) {
304
- if (!astProjectSummary) return null;
320
+ if (!astProjectSummary) {
321
+ return null;
322
+ }
305
323
 
306
324
  const lines = ['## 代码规范发现', ''];
307
325
 
@@ -310,7 +328,9 @@ function _buildCodeStandard({ astProjectSummary, primaryLang, allFiles }) {
310
328
  // 从 file 级聚合方法
311
329
  if (astProjectSummary.files) {
312
330
  for (const f of astProjectSummary.files) {
313
- if (f.methods) methods.push(...f.methods);
331
+ if (f.methods) {
332
+ methods.push(...f.methods);
333
+ }
314
334
  }
315
335
  }
316
336
 
@@ -389,23 +409,23 @@ function _buildCodeStandard({ astProjectSummary, primaryLang, allFiles }) {
389
409
  lines.push(`- 高圈复杂度方法: ${metrics.complexMethods.length} 个`);
390
410
  for (const m of metrics.complexMethods.slice(0, 5)) {
391
411
  lines.push(
392
- ` - \`${m.className ? m.className + '.' : ''}${m.name}\` — complexity ${m.complexity}`
412
+ ` - \`${m.className ? `${m.className}.` : ''}${m.name}\` — complexity ${m.complexity}`
393
413
  );
394
414
  }
395
415
  }
396
416
  if (metrics.longMethods?.length > 0) {
397
417
  lines.push(`- 过长方法: ${metrics.longMethods.length} 个`);
398
418
  for (const m of metrics.longMethods.slice(0, 5)) {
399
- lines.push(
400
- ` - \`${m.className ? m.className + '.' : ''}${m.name}\` — ${m.bodyLines} 行`
401
- );
419
+ lines.push(` - \`${m.className ? `${m.className}.` : ''}${m.name}\` — ${m.bodyLines} 行`);
402
420
  }
403
421
  }
404
422
  lines.push('');
405
423
  }
406
424
 
407
425
  const markdown = lines.join('\n');
408
- if (markdown.length < 80) return null;
426
+ if (markdown.length < 80) {
427
+ return null;
428
+ }
409
429
 
410
430
  return _makeCandidate({
411
431
  title: '代码规范与命名约定',
@@ -418,7 +438,9 @@ function _buildCodeStandard({ astProjectSummary, primaryLang, allFiles }) {
418
438
  }
419
439
 
420
440
  function _buildBestPractice({ guardAudit, primaryLang }) {
421
- if (!guardAudit?.files?.length) return null;
441
+ if (!guardAudit?.files?.length) {
442
+ return null;
443
+ }
422
444
 
423
445
  // 聚合所有违规
424
446
  const ruleStats = {};
@@ -438,10 +460,11 @@ function _buildBestPractice({ guardAudit, primaryLang }) {
438
460
  }
439
461
  }
440
462
 
441
- const sortedRules = Object.entries(ruleStats)
442
- .sort(([, a], [, b]) => b.count - a.count);
463
+ const sortedRules = Object.entries(ruleStats).sort(([, a], [, b]) => b.count - a.count);
443
464
 
444
- if (sortedRules.length === 0) return null;
465
+ if (sortedRules.length === 0) {
466
+ return null;
467
+ }
445
468
 
446
469
  const lines = ['## 最佳实践(基于 Guard 审计)', ''];
447
470
  lines.push(
@@ -490,7 +513,11 @@ function _buildAgentGuidelines({ guardAudit, primaryLang, astProjectSummary }) {
490
513
  const ruleStats = {};
491
514
  for (const f of guardAudit.files) {
492
515
  for (const v of f.violations || []) {
493
- ruleStats[v.ruleId] = ruleStats[v.ruleId] || { count: 0, message: v.message, severity: v.severity };
516
+ ruleStats[v.ruleId] = ruleStats[v.ruleId] || {
517
+ count: 0,
518
+ message: v.message,
519
+ severity: v.severity,
520
+ };
494
521
  ruleStats[v.ruleId].count++;
495
522
  }
496
523
  }
@@ -540,7 +567,9 @@ function _buildAgentGuidelines({ guardAudit, primaryLang, astProjectSummary }) {
540
567
  }
541
568
 
542
569
  const markdown = lines.join('\n');
543
- if (markdown.length < 100) return null;
570
+ if (markdown.length < 100) {
571
+ return null;
572
+ }
544
573
 
545
574
  return _makeCandidate({
546
575
  title: 'Agent 开发注意事项',
@@ -19,14 +19,14 @@ import { EpisodicConsolidator } from '../../../../../service/chat/EpisodicConsol
19
19
  import { ProducerAgent } from '../../../../../service/chat/ProducerAgent.js';
20
20
  import { ProjectSemanticMemory } from '../../../../../service/chat/ProjectSemanticMemory.js';
21
21
  import { WorkingMemory } from '../../../../../service/chat/WorkingMemory.js';
22
+ import { clearCheckpoints, loadCheckpoints, saveDimensionCheckpoint } from './checkpoint.js';
23
+ import { buildTierReflection, DIMENSION_CONFIGS_V3 } from './dimension-configs.js';
22
24
  import { DimensionContext, parseDimensionDigest } from './dimension-context.js';
23
25
  import { EpisodicMemory } from './EpisodicMemory.js';
24
26
  import { IncrementalBootstrap } from './IncrementalBootstrap.js';
25
27
  import { runNoAiFallback } from './noAiFallback.js';
26
28
  import { ToolResultCache } from './ToolResultCache.js';
27
29
  import { TierScheduler } from './tier-scheduler.js';
28
- import { saveDimensionCheckpoint, loadCheckpoints, clearCheckpoints } from './checkpoint.js';
29
- import { DIMENSION_CONFIGS_V3, buildTierReflection } from './dimension-configs.js';
30
30
 
31
31
  const logger = Logger.getInstance();
32
32
 
@@ -555,7 +555,9 @@ export async function fillDimensionsV3(fillContext) {
555
555
  `[Bootstrap-v3] Producer "${dimId}": ${producerResult.candidateCount} candidates (${Date.now() - dimStartTime}ms total)`
556
556
  );
557
557
  } catch (producerErr) {
558
- logger.error(`[Bootstrap-v3] Producer "${dimId}" failed: ${producerErr.message} — Analyst result preserved for Skill generation`);
558
+ logger.error(
559
+ `[Bootstrap-v3] Producer "${dimId}" failed: ${producerErr.message} — Analyst result preserved for Skill generation`
560
+ );
559
561
  candidateResults.errors.push({ dimId, error: `Producer: ${producerErr.message}` });
560
562
  }
561
563
  }
@@ -741,8 +743,8 @@ export async function fillDimensionsV3(fillContext) {
741
743
  continue;
742
744
  }
743
745
  // 2. 重复行检测(AI 陷入循环输出工具提示等)
744
- const textLines = analysisText.split('\n').filter(l => l.trim().length > 0);
745
- const uniqueLines = new Set(textLines.map(l => l.trim()));
746
+ const textLines = analysisText.split('\n').filter((l) => l.trim().length > 0);
747
+ const uniqueLines = new Set(textLines.map((l) => l.trim()));
746
748
  const uniqueRatio = textLines.length > 0 ? uniqueLines.size / textLines.length : 1;
747
749
  if (textLines.length > 20 && uniqueRatio < 0.3) {
748
750
  logger.warn(
@@ -759,9 +761,7 @@ export async function fillDimensionsV3(fillContext) {
759
761
  /^[-*•]\s/m.test(analysisText) ||
760
762
  /```[\s\S]*?```/.test(analysisText);
761
763
  if (!hasStructure && analysisText.length < 500) {
762
- logger.warn(
763
- `[Bootstrap-v3] Skill "${dim.id}" skipped — no structured content detected`
764
- );
764
+ logger.warn(`[Bootstrap-v3] Skill "${dim.id}" skipped — no structured content detected`);
765
765
  skillResults.failed++;
766
766
  skillResults.errors.push({ dimId: dim.id, error: 'no structured content' });
767
767
  continue;
@@ -74,7 +74,9 @@ export async function bootstrapRefine(ctx, args) {
74
74
  { page: 1, pageSize: 200 }
75
75
  );
76
76
  publishedTitles = (published.items || []).map((e) => e.title).filter(Boolean);
77
- } catch { /* ignore */ }
77
+ } catch {
78
+ /* ignore */
79
+ }
78
80
 
79
81
  // 3. 逐条 AI 润色
80
82
  const results = [];
@@ -46,11 +46,13 @@ import { DimensionCopy } from '../../../shared/DimensionCopyRegistry.js';
46
46
  import { LanguageService } from '../../../shared/LanguageService.js';
47
47
  import pathGuard from '../../../shared/PathGuard.js';
48
48
  import { envelope } from '../envelope.js';
49
+ import { baseDimensions, resolveActiveDimensions } from './bootstrap/base-dimensions.js';
49
50
  import {
50
51
  clearCheckpoints,
51
52
  clearSnapshots,
52
53
  fillDimensionsV3,
53
54
  } from './bootstrap/pipeline/orchestrator.js';
55
+ import { bootstrapRefine } from './bootstrap/refine.js';
54
56
  // ── Sub-modules ──
55
57
  import {
56
58
  enhanceDimensions,
@@ -59,8 +61,6 @@ import {
59
61
  } from './bootstrap/skills.js';
60
62
  import { buildLanguageExtension, detectPrimaryLanguage, inferLang } from './LanguageExtensions.js';
61
63
  import { inferFilePriority, inferTargetRole } from './TargetClassifier.js';
62
- import { baseDimensions, resolveActiveDimensions } from './bootstrap/base-dimensions.js';
63
- import { bootstrapRefine } from './bootstrap/refine.js';
64
64
 
65
65
  // Re-export for external consumers
66
66
  export { loadBootstrapSkills };
@@ -289,9 +289,7 @@ export async function bootstrapKnowledge(ctx, args) {
289
289
  const enhReg = await initEnhancementRegistry();
290
290
  const allPacks = enhReg.all();
291
291
  // 找到第一个提供 preprocessFile 的增强包
292
- const preprocessPack = allPacks.find(
293
- (p) => typeof p.preprocessFile === 'function'
294
- );
292
+ const preprocessPack = allPacks.find((p) => typeof p.preprocessFile === 'function');
295
293
  if (preprocessPack) {
296
294
  sfcPreprocessor = preprocessPack.preprocessFile.bind(preprocessPack);
297
295
  }
@@ -510,11 +508,7 @@ export async function bootstrapKnowledge(ctx, args) {
510
508
  const detectedFrameworks = allTargets
511
509
  .map((t) => (typeof t === 'object' ? t.framework : null))
512
510
  .filter(Boolean);
513
- const activeDimensions = resolveActiveDimensions(
514
- baseDimensions,
515
- primaryLang,
516
- detectedFrameworks
517
- );
511
+ const activeDimensions = resolveActiveDimensions(baseDimensions, primaryLang, detectedFrameworks);
518
512
 
519
513
  // ── Enhancement Pack 动态追加维度 + Guard 规则 ─────────────
520
514
  const enhancementPackInfo = [];
@@ -18,7 +18,9 @@ import { envelope } from '../envelope.js';
18
18
  function _buildActionHint(json) {
19
19
  const doText = json.doClause || '';
20
20
  const whenText = json.whenClause || '';
21
- if (!doText && !whenText) return undefined;
21
+ if (!doText && !whenText) {
22
+ return undefined;
23
+ }
22
24
  return `${whenText ? `${whenText} → ` : ''}${doText}`.replace(/ → $/, '');
23
25
  }
24
26
 
@@ -26,7 +28,9 @@ function _buildActionHint(json) {
26
28
  * 只保留非空关系桶,压缩 Relations 输出体积。
27
29
  */
28
30
  function _compactRelations(relations) {
29
- if (!relations) return undefined;
31
+ if (!relations) {
32
+ return undefined;
33
+ }
30
34
  const compact = {};
31
35
  for (const [type, list] of Object.entries(relations)) {
32
36
  if (Array.isArray(list) && list.length > 0) {
@@ -285,7 +285,9 @@ export async function scanProject(ctx, args) {
285
285
  function _getOrCreateEngine(ctx, GuardCheckEngine) {
286
286
  try {
287
287
  const engine = ctx.container.get('guardCheckEngine');
288
- if (engine) return engine;
288
+ if (engine) {
289
+ return engine;
290
+ }
289
291
  } catch {
290
292
  /* DI not registered — fall back to new instance */
291
293
  }
@@ -300,7 +302,9 @@ function _getOrCreateEngine(ctx, GuardCheckEngine) {
300
302
  */
301
303
  async function _injectEnhancementGuardRules(engine, ctx) {
302
304
  // 幂等保护: 已注入则跳过
303
- if (engine.isEpInjected?.()) return;
305
+ if (engine.isEpInjected?.()) {
306
+ return;
307
+ }
304
308
  try {
305
309
  const { initEnhancementRegistry } = await import('../../../core/enhancement/index.js');
306
310
  const enhReg = await initEnhancementRegistry();
@@ -240,12 +240,16 @@ export function loadSkill(_ctx, args) {
240
240
  fs.readdirSync(SKILLS_DIR, { withFileTypes: true })
241
241
  .filter((d) => d.isDirectory())
242
242
  .forEach((d) => available.add(d.name));
243
- } catch {}
243
+ } catch {
244
+ /* skip: SKILLS_DIR may not exist */
245
+ }
244
246
  try {
245
247
  fs.readdirSync(_getProjectSkillsDir(), { withFileTypes: true })
246
248
  .filter((d) => d.isDirectory())
247
249
  .forEach((d) => available.add(d.name));
248
- } catch {}
250
+ } catch {
251
+ /* skip: project skills dir may not exist */
252
+ }
249
253
 
250
254
  return JSON.stringify({
251
255
  success: false,
@@ -29,13 +29,13 @@ import extractRouter from './routes/extract.js';
29
29
  import guardRuleRouter from './routes/guardRules.js';
30
30
  import healthRouter from './routes/health.js';
31
31
  import knowledgeRouter from './routes/knowledge.js';
32
+ import modulesRouter from './routes/modules.js';
32
33
  import monitoringRouter from './routes/monitoring.js';
33
34
  import recipesRouter from './routes/recipes.js';
34
35
  import searchRouter from './routes/search.js';
35
36
  import skillsRouter from './routes/skills.js';
36
37
  import snippetRouter from './routes/snippets.js';
37
38
  import spmRouter from './routes/spm.js';
38
- import modulesRouter from './routes/modules.js';
39
39
  import violationsRouter from './routes/violations.js';
40
40
  import wikiRouter from './routes/wiki.js';
41
41
 
@@ -77,7 +77,9 @@ router.post(
77
77
  try {
78
78
  const chatAgent = container.get('chatAgent');
79
79
  lang = chatAgent?.getLang?.() || 'en';
80
- } catch { /* chatAgent not available */ }
80
+ } catch {
81
+ /* chatAgent not available */
82
+ }
81
83
  enriched = await aiProvider.enrichCandidates(candidates, { lang });
82
84
  } catch (err) {
83
85
  logger.warn('AI enrichCandidates failed', { error: err.message });
@@ -7,8 +7,8 @@ import { basename } from 'node:path';
7
7
  import express from 'express';
8
8
  import Logger from '../../infrastructure/logging/Logger.js';
9
9
  import { getServiceContainer } from '../../injection/ServiceContainer.js';
10
- import { LanguageService } from '../../shared/LanguageService.js';
11
10
  import { ValidationError } from '../../shared/errors/index.js';
11
+ import { LanguageService } from '../../shared/LanguageService.js';
12
12
  import { asyncHandler } from '../middleware/errorHandler.js';
13
13
 
14
14
  const router = express.Router();
@@ -143,11 +143,10 @@ router.post(
143
143
  const chatAgent = container.get('chatAgent');
144
144
  if (chatAgent) {
145
145
  const lang =
146
- language || (relativePath ? (LanguageService.inferLang(relativePath) || 'unknown') : 'unknown');
146
+ language ||
147
+ (relativePath ? LanguageService.inferLang(relativePath) || 'unknown' : 'unknown');
147
148
  const ext = LanguageService.extForLang(lang) || '.txt';
148
- const fileName = relativePath
149
- ? basename(relativePath)
150
- : `clipboard${ext}`;
149
+ const fileName = relativePath ? basename(relativePath) : `clipboard${ext}`;
151
150
  const aiResult = await chatAgent.executeTool('extract_recipes', {
152
151
  targetName: fileName,
153
152
  files: [{ name: fileName, content: text }],
@@ -5,8 +5,8 @@
5
5
 
6
6
  import express from 'express';
7
7
  import { getServiceContainer } from '../../injection/ServiceContainer.js';
8
- import { LanguageService } from '../../shared/LanguageService.js';
9
8
  import { NotFoundError, ValidationError } from '../../shared/errors/index.js';
9
+ import { LanguageService } from '../../shared/LanguageService.js';
10
10
  import { asyncHandler } from '../middleware/errorHandler.js';
11
11
  import { getContext, safeInt } from '../utils/routeHelpers.js';
12
12
 
@@ -81,7 +81,9 @@ router.get(
81
81
  packageName: pkgName,
82
82
  });
83
83
  for (const d of info?.dependencies || []) {
84
- if (!d?.name) continue;
84
+ if (!d?.name) {
85
+ continue;
86
+ }
85
87
  const depPkg = d?.package || pkgName;
86
88
  edges.push({ from: id, to: `${depPkg}::${d.name}`, source: 'base' });
87
89
  }
@@ -200,7 +202,9 @@ router.post(
200
202
  const result = await moduleService.scanFolder(folderPath, {
201
203
  ...options,
202
204
  onProgress: (evt) => {
203
- if (session) session.push(evt);
205
+ if (session) {
206
+ session.push(evt);
207
+ }
204
208
  },
205
209
  });
206
210
 
@@ -406,7 +410,9 @@ router.get('/scan/events/:sessionId', (req, res) => {
406
410
  }
407
411
 
408
412
  function writeEvent(event) {
409
- if (res.writableEnded) return;
413
+ if (res.writableEnded) {
414
+ return;
415
+ }
410
416
  res.write(`data: ${JSON.stringify(event)}\n\n`);
411
417
  }
412
418