stigmergy 1.2.13 → 1.3.1-beta

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 (84) hide show
  1. package/README.md +39 -3
  2. package/STIGMERGY.md +3 -0
  3. package/config/builtin-skills.json +43 -0
  4. package/config/enhanced-cli-config.json +438 -0
  5. package/docs/CLI_TOOLS_AGENT_SKILL_ANALYSIS.md +463 -0
  6. package/docs/DESIGN_CLI_HELP_ANALYZER_REFACTOR.md +726 -0
  7. package/docs/ENHANCED_CLI_AGENT_SKILL_CONFIG.md +285 -0
  8. package/docs/IMPLEMENTATION_CHECKLIST_CLI_HELP_ANALYZER_REFACTOR.md +1268 -0
  9. package/docs/INSTALLER_ARCHITECTURE.md +257 -0
  10. package/docs/LESSONS_LEARNED.md +252 -0
  11. package/docs/SPECS_CLI_HELP_ANALYZER_REFACTOR.md +287 -0
  12. package/docs/SUDO_PROBLEM_AND_SOLUTION.md +529 -0
  13. package/docs/correct-skillsio-implementation.md +368 -0
  14. package/docs/development_guidelines.md +276 -0
  15. package/docs/independent-resume-implementation.md +198 -0
  16. package/docs/resumesession-final-implementation.md +195 -0
  17. package/docs/resumesession-usage.md +87 -0
  18. package/package.json +19 -9
  19. package/scripts/analyze-router.js +168 -0
  20. package/scripts/run-comprehensive-tests.js +230 -0
  21. package/scripts/run-quick-tests.js +90 -0
  22. package/scripts/test-runner.js +344 -0
  23. package/skills/resumesession/INDEPENDENT_SKILL.md +171 -0
  24. package/skills/resumesession/SKILL.md +127 -0
  25. package/skills/resumesession/__init__.py +33 -0
  26. package/skills/resumesession/implementations/simple-resume.js +13 -0
  27. package/src/adapters/claude/install_claude_integration.js +9 -1
  28. package/src/adapters/codebuddy/install_codebuddy_integration.js +3 -1
  29. package/src/adapters/codex/install_codex_integration.js +15 -5
  30. package/src/adapters/gemini/install_gemini_integration.js +3 -1
  31. package/src/adapters/qwen/install_qwen_integration.js +3 -1
  32. package/src/cli/commands/autoinstall.js +65 -0
  33. package/src/cli/commands/errors.js +190 -0
  34. package/src/cli/commands/independent-resume.js +395 -0
  35. package/src/cli/commands/install.js +179 -0
  36. package/src/cli/commands/permissions.js +108 -0
  37. package/src/cli/commands/project.js +485 -0
  38. package/src/cli/commands/scan.js +97 -0
  39. package/src/cli/commands/simple-resume.js +377 -0
  40. package/src/cli/commands/skills.js +158 -0
  41. package/src/cli/commands/status.js +113 -0
  42. package/src/cli/commands/stigmergy-resume.js +775 -0
  43. package/src/cli/commands/system.js +301 -0
  44. package/src/cli/commands/universal-resume.js +394 -0
  45. package/src/cli/router-beta.js +471 -0
  46. package/src/cli/utils/environment.js +75 -0
  47. package/src/cli/utils/formatters.js +47 -0
  48. package/src/cli/utils/skills_cache.js +92 -0
  49. package/src/core/cache_cleaner.js +1 -0
  50. package/src/core/cli_adapters.js +345 -0
  51. package/src/core/cli_help_analyzer.js +582 -26
  52. package/src/core/cli_path_detector.js +702 -709
  53. package/src/core/cli_tools.js +515 -160
  54. package/src/core/coordination/nodejs/CLIIntegrationManager.js +18 -0
  55. package/src/core/coordination/nodejs/HookDeploymentManager.js +242 -412
  56. package/src/core/coordination/nodejs/HookDeploymentManager.refactored.js +323 -0
  57. package/src/core/coordination/nodejs/generators/CLIAdapterGenerator.js +363 -0
  58. package/src/core/coordination/nodejs/generators/ResumeSessionGenerator.js +932 -0
  59. package/src/core/coordination/nodejs/generators/SkillsIntegrationGenerator.js +1395 -0
  60. package/src/core/coordination/nodejs/generators/index.js +12 -0
  61. package/src/core/enhanced_cli_installer.js +1208 -608
  62. package/src/core/enhanced_cli_parameter_handler.js +402 -0
  63. package/src/core/execution_mode_detector.js +222 -0
  64. package/src/core/installer.js +151 -106
  65. package/src/core/local_skill_scanner.js +732 -0
  66. package/src/core/multilingual/language-pattern-manager.js +1 -1
  67. package/src/core/skills/BuiltinSkillsDeployer.js +188 -0
  68. package/src/core/skills/StigmergySkillManager.js +123 -16
  69. package/src/core/skills/embedded-openskills/SkillParser.js +7 -3
  70. package/src/core/smart_router.js +291 -2
  71. package/src/index.js +10 -4
  72. package/src/utils.js +66 -7
  73. package/test/cli-integration.test.js +304 -0
  74. package/test/direct_smart_router_test.js +88 -0
  75. package/test/enhanced-cli-agent-skill-test.js +485 -0
  76. package/test/simple_test.js +82 -0
  77. package/test/smart_router_test_runner.js +123 -0
  78. package/test/smart_routing_edge_cases.test.js +284 -0
  79. package/test/smart_routing_simple_verification.js +139 -0
  80. package/test/smart_routing_verification.test.js +346 -0
  81. package/test/specific-cli-agent-skill-analysis.js +385 -0
  82. package/test/unit/smart_router.test.js +295 -0
  83. package/test/very_simple_test.js +54 -0
  84. package/src/cli/router.js +0 -1783
@@ -0,0 +1,726 @@
1
+ # CLI Help Analyzer 重构 - 设计文档 (DESIGN)
2
+
3
+ ## 1. 设计概述
4
+
5
+ ### 1.1 设计目标
6
+ - 简化方法调用链,减少代码冗余
7
+ - 统一分析入口,便于维护和扩展
8
+ - 保持向后兼容,不影响现有功能
9
+ - 提升代码可读性和可维护性
10
+
11
+ ### 1.2 设计原则
12
+ 1. **单一职责原则**:每个方法只做一件事
13
+ 2. **开闭原则**:对扩展开放,对修改封闭
14
+ 3. **依赖倒置原则**:依赖抽象而非具体实现
15
+ 4. **接口隔离原则**:接口精简,职责明确
16
+
17
+ ### 1.3 命名规范
18
+
19
+ #### 1.3.1 现有方法命名(保持向后兼容)
20
+ - `analyzeCLI()` - 核心分析方法
21
+ - `analyzeCLIEnhanced()` - 增强分析方法
22
+ - `getCLIPattern()` - 获取CLI模式
23
+ - `getEnhancedCLIPattern()` - 获取增强CLI模式
24
+ - `analyzeAllCLI()` - 分析所有CLI
25
+
26
+ #### 1.3.2 命名规范说明
27
+ - **核心分析方法**:使用 `analyze` 前缀,表示执行分析操作
28
+ - **数据获取方法**:使用 `get` 前缀,表示获取已分析的数据
29
+ - **批量操作方法**:使用 `analyzeAll` 前缀,表示批量分析
30
+
31
+ #### 1.3.3 新增方法命名规范
32
+ - 新增分析方法:使用 `analyze` 前缀
33
+ - 新增获取方法:使用 `get` 前缀
34
+ - 新增批量方法:使用 `analyzeAll` 前缀
35
+
36
+ **注意**:为保持向后兼容性,现有方法名保持不变,不进行重命名。
37
+
38
+ ## 2. 架构设计
39
+
40
+ ### 2.1 当前架构问题
41
+
42
+ ```
43
+ 当前调用链:
44
+ analyzeCLI() ← 核心方法
45
+ ├── analyzeCLIEnhanced() → 调用 analyzeCLI()
46
+ ├── getCLIPattern() → 调用 analyzeCLI()
47
+ ├── getEnhancedCLIPattern() → 调用 analyzeCLIEnhanced() → analyzeCLI()
48
+ └── analyzeAllCLI() → 调用 analyzeCLI()
49
+
50
+ 问题:
51
+ 1. 5个方法,实际核心逻辑只有1个
52
+ 2. 调用链过长,难以追踪
53
+ 3. 职责不清,边界模糊
54
+ 4. 维护困难,容易出错
55
+ ```
56
+
57
+ ### 2.2 重构后架构
58
+
59
+ ```
60
+ 重构后调用链:
61
+ analyzeCLI(cliName, options) ← 唯一核心入口
62
+ ├── options.enhanced = false → 基础分析
63
+ ├── options.enhanced = true → 增强分析
64
+ └── options.forceRefresh = true → 强制刷新
65
+
66
+ 包装器方法(向后兼容):
67
+ ├── getCLIPattern(cliName) → analyzeCLI(cliName, { enhanced: false })
68
+ ├── getEnhancedCLIPattern(cliName) → analyzeCLI(cliName, { enhanced: true })
69
+ └── analyzeCLIEnhanced(cliName) → analyzeCLI(cliName, { enhanced: true })
70
+
71
+ 优势:
72
+ 1. 单一入口,逻辑集中
73
+ 2. 参数控制,灵活扩展
74
+ 3. 向后兼容,平滑迁移
75
+ 4. 职责清晰,易于维护
76
+ ```
77
+
78
+ ## 3. 详细设计
79
+
80
+ ### 3.1 核心方法设计
81
+
82
+ #### 3.1.1 analyzeCLI() 方法
83
+
84
+ **方法签名**:
85
+ ```javascript
86
+ async analyzeCLI(cliName, options = {})
87
+ ```
88
+
89
+ **参数**:
90
+ - `cliName` (string): CLI工具名称,如 'claude', 'gemini'
91
+ - `options` (object): 可选配置对象
92
+ - `enhanced` (boolean): 是否返回增强信息,默认 false
93
+ - `forceRefresh` (boolean): 是否强制刷新缓存,默认 false
94
+
95
+ **返回值**:
96
+ ```javascript
97
+ {
98
+ success: boolean,
99
+ cliName: string,
100
+ cliType: string,
101
+ version: string,
102
+ helpMethod: string,
103
+ patterns: object,
104
+ commandStructure: object,
105
+ examples: array,
106
+ interactionMode: string,
107
+ agentSkillSupport?: object, // 当 enhanced=true 时存在
108
+ timestamp: string
109
+ }
110
+ ```
111
+
112
+ **流程图**:
113
+ ```
114
+ 开始
115
+
116
+ 检查参数有效性
117
+
118
+ 检查缓存
119
+
120
+ 缓存存在且未过期且版本未变化且 forceRefresh=false?
121
+ ↓ 是
122
+ 返回缓存结果
123
+ ↓ 否
124
+ 执行分析
125
+ ├── 获取帮助信息
126
+ ├── 检测CLI类型
127
+ ├── 提取模式
128
+ ├── 分析命令结构
129
+ ├── 提取使用示例
130
+ └── 确定交互模式
131
+
132
+ enhanced=true?
133
+ ↓ 是
134
+ 添加增强信息
135
+ ↓ 否
136
+ 保存到缓存
137
+
138
+ 返回分析结果
139
+
140
+ 结束
141
+ ```
142
+
143
+ **伪代码**:
144
+ ```javascript
145
+ async analyzeCLI(cliName, options = {}) {
146
+ const { enhanced = false, forceRefresh = false } = options;
147
+
148
+ // 1. 参数验证
149
+ if (!this.cliTools[cliName]) {
150
+ throw new Error(`CLI tool ${cliName} not found`);
151
+ }
152
+
153
+ // 2. 检查缓存
154
+ if (!forceRefresh) {
155
+ const cachedAnalysis = await this.getCachedAnalysis(cliName);
156
+ if (cachedAnalysis && cachedAnalysis.success) {
157
+ const currentVersion = await this.getCurrentVersion(cliName);
158
+ if (currentVersion === cachedAnalysis.version &&
159
+ !this.isCacheExpired(cachedAnalysis.timestamp)) {
160
+ if (enhanced) {
161
+ return this.addEnhancedInfo(cachedAnalysis, cliName);
162
+ }
163
+ return cachedAnalysis;
164
+ }
165
+ }
166
+ }
167
+
168
+ // 3. 执行分析
169
+ const analysis = await this.performAnalysis(cliName);
170
+
171
+ // 4. 添加增强信息
172
+ if (enhanced) {
173
+ return this.addEnhancedInfo(analysis, cliName);
174
+ }
175
+
176
+ // 5. 保存缓存
177
+ await this.cacheAnalysis(cliName, analysis);
178
+
179
+ return analysis;
180
+ }
181
+ ```
182
+
183
+ #### 3.1.2 addEnhancedInfo() 方法
184
+
185
+ **方法签名**:
186
+ ```javascript
187
+ addEnhancedInfo(analysis, cliName)
188
+ ```
189
+
190
+ **参数**:
191
+ - `analysis` (object): 基础分析结果
192
+ - `cliName` (string): CLI工具名称
193
+
194
+ **返回值**:
195
+ ```javascript
196
+ {
197
+ ...analysis, // 原始分析结果
198
+ agentSkillSupport: {
199
+ supportsAgents: boolean,
200
+ supportsSkills: boolean,
201
+ naturalLanguageSupport: boolean,
202
+ skillPrefixRequired: boolean,
203
+ positionalArgs: boolean,
204
+ agentTypes: array,
205
+ skillKeywords: array,
206
+ commandFormat: string,
207
+ examples: array
208
+ }
209
+ }
210
+ ```
211
+
212
+ **重要说明**:
213
+ - ⚠️ **必须返回新对象,不能修改原对象**
214
+ - ⚠️ 使用展开运算符 `...analysis` 创建新对象
215
+ - ⚠️ 遵循不可变原则,避免副作用
216
+ - ⚠️ 原始 `analysis` 对象必须保持不变
217
+
218
+ **伪代码**:
219
+ ```javascript
220
+ addEnhancedInfo(analysis, cliName) {
221
+ const enhancedPatterns = this.enhancedPatterns[cliName] || {};
222
+
223
+ // 使用展开运算符创建新对象,不修改原对象
224
+ return {
225
+ ...analysis,
226
+ agentSkillSupport: {
227
+ supportsAgents: enhancedPatterns.agentDetection || false,
228
+ supportsSkills: enhancedPatterns.skillDetection || false,
229
+ naturalLanguageSupport: enhancedPatterns.naturalLanguageSupport || false,
230
+ skillPrefixRequired: enhancedPatterns.skillPrefixRequired || false,
231
+ positionalArgs: enhancedPatterns.positionalArgs || false,
232
+ agentTypes: enhancedPatterns.agentTypes || [],
233
+ skillKeywords: enhancedPatterns.skillKeywords || [],
234
+ commandFormat: enhancedPatterns.commandFormat || '',
235
+ examples: enhancedPatterns.examples || []
236
+ }
237
+ };
238
+ }
239
+ ```
240
+
241
+ **与现有代码的差异**:
242
+ 现有代码 `analyzeCLIEnhanced()` 直接修改原对象:
243
+ ```javascript
244
+ // ❌ 错误:直接修改原对象
245
+ basicAnalysis.agentSkillSupport = { ... };
246
+ return basicAnalysis;
247
+ ```
248
+
249
+ 重构后必须使用展开运算符:
250
+ ```javascript
251
+ // ✅ 正确:返回新对象
252
+ return {
253
+ ...basicAnalysis,
254
+ agentSkillSupport: { ... }
255
+ };
256
+ ```
257
+
258
+ #### 3.1.3 包装器方法设计
259
+
260
+ ```javascript
261
+ // 基础模式获取
262
+ async getCLIPattern(cliName) {
263
+ return await this.analyzeCLI(cliName, { enhanced: false });
264
+ }
265
+
266
+ // 增强模式获取
267
+ async getEnhancedCLIPattern(cliName) {
268
+ return await this.analyzeCLI(cliName, { enhanced: true });
269
+ }
270
+
271
+ // 增强分析
272
+ async analyzeCLIEnhanced(cliName) {
273
+ return await this.analyzeCLI(cliName, { enhanced: true });
274
+ }
275
+ ```
276
+
277
+ ### 3.2 数据结构设计
278
+
279
+ #### 3.2.1 Options 对象
280
+
281
+ ```typescript
282
+ interface AnalyzeOptions {
283
+ enhanced?: boolean; // 是否返回增强信息
284
+ forceRefresh?: boolean; // 是否强制刷新缓存
285
+ }
286
+ ```
287
+
288
+ #### 3.2.2 AnalysisResult 对象
289
+
290
+ ```typescript
291
+ interface AnalysisResult {
292
+ success: boolean;
293
+ cliName: string;
294
+ cliType: string;
295
+ version: string;
296
+ helpMethod: string;
297
+ patterns: object;
298
+ commandStructure: object;
299
+ examples: array;
300
+ interactionMode: string;
301
+ timestamp: string;
302
+ agentSkillSupport?: AgentSkillSupport; // 可选字段
303
+ }
304
+
305
+ interface AgentSkillSupport {
306
+ supportsAgents: boolean;
307
+ supportsSkills: boolean;
308
+ naturalLanguageSupport: boolean;
309
+ skillPrefixRequired: boolean;
310
+ positionalArgs: boolean;
311
+ agentTypes: string[];
312
+ skillKeywords: string[];
313
+ commandFormat: string;
314
+ examples: string[];
315
+ }
316
+ ```
317
+
318
+ ### 3.3 类结构设计
319
+
320
+ ```javascript
321
+ class CLIHelpAnalyzer {
322
+ // 构造函数
323
+ constructor()
324
+
325
+ // 核心方法
326
+ async analyzeCLI(cliName, options = {})
327
+ addEnhancedInfo(analysis, cliName)
328
+
329
+ // 包装器方法(向后兼容)
330
+ async getCLIPattern(cliName)
331
+ async getEnhancedCLIPattern(cliName)
332
+ async analyzeCLIEnhanced(cliName)
333
+
334
+ // 批量分析方法
335
+ async analyzeAllCLI(options = {})
336
+
337
+ // 私有方法(内部使用)
338
+ async performAnalysis(cliName)
339
+ async getHelpInfo(cliName, cliConfig)
340
+ detectCLIType(rawHelp, cliName)
341
+ extractPatterns(rawHelp, cliType, cliName)
342
+ analyzeCommandStructure(patterns)
343
+ extractUsageExamples(rawHelp, cliType)
344
+ determineInteractionMode(helpInfo, patterns)
345
+
346
+ // 缓存相关方法
347
+ async cacheAnalysis(cliName, analysis)
348
+ async getCachedAnalysis(cliName)
349
+ isCacheExpired(timestamp)
350
+ async loadPersistentConfig()
351
+ async savePersistentConfig(config)
352
+
353
+ // 版本检测方法
354
+ async getCurrentVersion(cliName, cliConfig)
355
+
356
+ // 工具方法
357
+ async fileExists(filePath)
358
+ async recordFailedAttempt(cliName, error)
359
+ async updatePatternOnFailure(cliName, error, attemptedCommand)
360
+ async updatePatternOnAgentSkillFailure(cliName, error, attemptedCommand, userPrompt)
361
+ }
362
+ ```
363
+
364
+ ## 4. 接口设计
365
+
366
+ ### 4.1 公共API
367
+
368
+ #### 4.1.1 analyzeCLI()
369
+
370
+ ```javascript
371
+ /**
372
+ * 分析CLI工具
373
+ * @param {string} cliName - CLI工具名称
374
+ * @param {Object} options - 分析选项
375
+ * @param {boolean} options.enhanced - 是否返回增强信息
376
+ * @param {boolean} options.forceRefresh - 是否强制刷新缓存
377
+ * @returns {Promise<Object>} 分析结果
378
+ */
379
+ async analyzeCLI(cliName, options = {})
380
+ ```
381
+
382
+ **使用示例**:
383
+ ```javascript
384
+ // 基础分析
385
+ const pattern = await analyzer.analyzeCLI('claude');
386
+
387
+ // 增强分析
388
+ const enhancedPattern = await analyzer.analyzeCLI('claude', { enhanced: true });
389
+
390
+ // 强制刷新
391
+ const freshPattern = await analyzer.analyzeCLI('claude', { forceRefresh: true });
392
+
393
+ // 组合使用
394
+ const result = await analyzer.analyzeCLI('claude', {
395
+ enhanced: true,
396
+ forceRefresh: true
397
+ });
398
+ ```
399
+
400
+ #### 4.1.2 getCLIPattern()
401
+
402
+ ```javascript
403
+ /**
404
+ * 获取CLI模式(向后兼容)
405
+ * @deprecated 建议使用 analyzeCLI(cliName, { enhanced: false })
406
+ * @param {string} cliName - CLI工具名称
407
+ * @returns {Promise<Object>} 分析结果
408
+ */
409
+ async getCLIPattern(cliName)
410
+ ```
411
+
412
+ #### 4.1.3 getEnhancedCLIPattern()
413
+
414
+ ```javascript
415
+ /**
416
+ * 获取增强CLI模式(向后兼容)
417
+ * @deprecated 建议使用 analyzeCLI(cliName, { enhanced: true })
418
+ * @param {string} cliName - CLI工具名称
419
+ * @returns {Promise<Object>} 增强分析结果
420
+ */
421
+ async getEnhancedCLIPattern(cliName)
422
+ ```
423
+
424
+ #### 4.1.4 analyzeCLIEnhanced()
425
+
426
+ ```javascript
427
+ /**
428
+ * 增强分析(向后兼容)
429
+ * @deprecated 建议使用 analyzeCLI(cliName, { enhanced: true })
430
+ * @param {string} cliName - CLI工具名称
431
+ * @returns {Promise<Object>} 增强分析结果
432
+ */
433
+ async analyzeCLIEnhanced(cliName)
434
+ ```
435
+
436
+ #### 4.1.5 analyzeAllCLI()
437
+
438
+ ```javascript
439
+ /**
440
+ * 分析所有CLI工具
441
+ * @param {Object} options - 分析选项
442
+ * @param {boolean} options.enhanced - 是否返回增强信息
443
+ * @param {boolean} options.forceRefresh - 是否强制刷新缓存
444
+ * @returns {Promise<Object>} 所有CLI的分析结果
445
+ */
446
+ async analyzeAllCLI(options = {})
447
+ ```
448
+
449
+ ### 4.2 内部API
450
+
451
+ #### 4.2.1 addEnhancedInfo()
452
+
453
+ ```javascript
454
+ /**
455
+ * 添加增强信息
456
+ * @param {Object} analysis - 基础分析结果
457
+ * @param {string} cliName - CLI工具名称
458
+ * @returns {Object} 增强分析结果
459
+ */
460
+ addEnhancedInfo(analysis, cliName)
461
+ ```
462
+
463
+ ## 5. 错误处理设计
464
+
465
+ ### 5.1 错误类型
466
+
467
+ ```javascript
468
+ // CLI工具不存在
469
+ class CLINotFoundError extends Error {
470
+ constructor(cliName) {
471
+ super(`CLI tool ${cliName} not found in configuration`);
472
+ this.name = 'CLINotFoundError';
473
+ }
474
+ }
475
+
476
+ // 分析失败
477
+ class AnalysisFailedError extends Error {
478
+ constructor(cliName, originalError) {
479
+ super(`Failed to analyze ${cliName}: ${originalError.message}`);
480
+ this.name = 'AnalysisFailedError';
481
+ this.originalError = originalError;
482
+ }
483
+ }
484
+
485
+ // 缓存错误
486
+ class CacheError extends Error {
487
+ constructor(message) {
488
+ super(`Cache error: ${message}`);
489
+ this.name = 'CacheError';
490
+ }
491
+ }
492
+ ```
493
+
494
+ ### 5.2 错误处理策略
495
+
496
+ ```javascript
497
+ async analyzeCLI(cliName, options = {}) {
498
+ try {
499
+ // 参数验证
500
+ if (!this.cliTools[cliName]) {
501
+ throw new CLINotFoundError(cliName);
502
+ }
503
+
504
+ // 执行分析
505
+ const analysis = await this.performAnalysis(cliName);
506
+
507
+ return analysis;
508
+ } catch (error) {
509
+ // 记录失败
510
+ await this.recordFailedAttempt(cliName, error);
511
+
512
+ // 重新抛出
513
+ throw new AnalysisFailedError(cliName, error);
514
+ }
515
+ }
516
+ ```
517
+
518
+ ## 6. 测试设计
519
+
520
+ ### 6.1 单元测试
521
+
522
+ #### 6.1.1 analyzeCLI() 测试
523
+
524
+ ```javascript
525
+ describe('analyzeCLI()', () => {
526
+ test('should return basic analysis when enhanced=false', async () => {
527
+ const result = await analyzer.analyzeCLI('claude', { enhanced: false });
528
+ expect(result.success).toBe(true);
529
+ expect(result.agentSkillSupport).toBeUndefined();
530
+ });
531
+
532
+ test('should return enhanced analysis when enhanced=true', async () => {
533
+ const result = await analyzer.analyzeCLI('claude', { enhanced: true });
534
+ expect(result.success).toBe(true);
535
+ expect(result.agentSkillSupport).toBeDefined();
536
+ });
537
+
538
+ test('should use cache when version unchanged', async () => {
539
+ // 第一次调用
540
+ const result1 = await analyzer.analyzeCLI('claude');
541
+ // 第二次调用应该使用缓存
542
+ const result2 = await analyzer.analyzeCLI('claude');
543
+ expect(result2).toEqual(result1);
544
+ });
545
+
546
+ test('should force refresh when forceRefresh=true', async () => {
547
+ const result1 = await analyzer.analyzeCLI('claude');
548
+ // 强制刷新
549
+ const result2 = await analyzer.analyzeCLI('claude', { forceRefresh: true });
550
+ expect(result2.timestamp).not.toEqual(result1.timestamp);
551
+ });
552
+ });
553
+ ```
554
+
555
+ #### 6.1.2 addEnhancedInfo() 测试
556
+
557
+ ```javascript
558
+ describe('addEnhancedInfo()', () => {
559
+ test('should add agentSkillSupport to analysis', () => {
560
+ const basicAnalysis = { cliName: 'claude', version: '2.1.4' };
561
+ const enhancedAnalysis = analyzer.addEnhancedInfo(basicAnalysis, 'claude');
562
+
563
+ expect(enhancedAnalysis.agentSkillSupport).toBeDefined();
564
+ expect(enhancedAnalysis.agentSkillSupport.supportsAgents).toBe(true);
565
+ });
566
+
567
+ test('should not modify original analysis', () => {
568
+ const basicAnalysis = { cliName: 'claude', version: '2.1.4' };
569
+ const enhancedAnalysis = analyzer.addEnhancedInfo(basicAnalysis, 'claude');
570
+
571
+ expect(basicAnalysis.agentSkillSupport).toBeUndefined();
572
+ });
573
+ });
574
+ ```
575
+
576
+ #### 6.1.3 包装器方法测试
577
+
578
+ ```javascript
579
+ describe('wrapper methods', () => {
580
+ test('getCLIPattern() should call analyzeCLI with enhanced=false', async () => {
581
+ const spy = jest.spyOn(analyzer, 'analyzeCLI');
582
+ await analyzer.getCLIPattern('claude');
583
+
584
+ expect(spy).toHaveBeenCalledWith('claude', { enhanced: false });
585
+ });
586
+
587
+ test('getEnhancedCLIPattern() should call analyzeCLI with enhanced=true', async () => {
588
+ const spy = jest.spyOn(analyzer, 'analyzeCLI');
589
+ await analyzer.getEnhancedCLIPattern('claude');
590
+
591
+ expect(spy).toHaveBeenCalledWith('claude', { enhanced: true });
592
+ });
593
+
594
+ test('analyzeCLIEnhanced() should call analyzeCLI with enhanced=true', async () => {
595
+ const spy = jest.spyOn(analyzer, 'analyzeCLI');
596
+ await analyzer.analyzeCLIEnhanced('claude');
597
+
598
+ expect(spy).toHaveBeenCalledWith('claude', { enhanced: true });
599
+ });
600
+ });
601
+ ```
602
+
603
+ ### 6.2 集成测试
604
+
605
+ ```javascript
606
+ describe('Integration Tests', () => {
607
+ test('should analyze all CLI tools', async () => {
608
+ const results = await analyzer.analyzeAllCLI();
609
+
610
+ expect(Object.keys(results).length).toBeGreaterThan(0);
611
+ Object.values(results).forEach(result => {
612
+ expect(result.success).toBe(true);
613
+ });
614
+ });
615
+
616
+ test('should work with smart_router', async () => {
617
+ const router = new SmartRouter();
618
+ const pattern = await router.getEnhancedCLIPattern('claude');
619
+
620
+ expect(pattern.success).toBe(true);
621
+ expect(pattern.agentSkillSupport).toBeDefined();
622
+ });
623
+ });
624
+ ```
625
+
626
+ ### 6.3 性能测试
627
+
628
+ ```javascript
629
+ describe('Performance Tests', () => {
630
+ test('cache hit should be fast (< 3s)', async () => {
631
+ const start = Date.now();
632
+ await analyzer.analyzeCLI('claude');
633
+ const elapsed = Date.now() - start;
634
+
635
+ expect(elapsed).toBeLessThan(3000);
636
+ });
637
+
638
+ test('first analysis should be reasonable (< 10s)', async () => {
639
+ const start = Date.now();
640
+ await analyzer.analyzeCLI('claude', { forceRefresh: true });
641
+ const elapsed = Date.now() - start;
642
+
643
+ expect(elapsed).toBeLessThan(10000);
644
+ });
645
+ });
646
+ ```
647
+
648
+ ## 7. 迁移策略
649
+
650
+ ### 7.1 阶段1:重构核心方法
651
+ - 修改 `analyzeCLI()` 添加 `options` 参数
652
+ - 提取 `addEnhancedInfo()` 方法
653
+ - 更新内部调用使用 `options`
654
+
655
+ ### 7.2 阶段2:简化包装器
656
+ - 简化 `getCLIPattern()` 为包装器
657
+ - 简化 `getEnhancedCLIPattern()` 为包装器
658
+ - 简化 `analyzeCLIEnhanced()` 为包装器
659
+
660
+ ### 7.3 阶段3:更新外部调用(可选)
661
+ - 更新 `smart_router.js` 使用统一方法
662
+ - 更新 `enhanced_cli_parameter_handler.js` 使用统一方法
663
+
664
+ ### 7.4 阶段4:测试验证
665
+ - 运行所有单元测试
666
+ - 运行所有集成测试
667
+ - 运行性能测试
668
+ - 验证向后兼容性
669
+
670
+ ## 8. 风险缓解
671
+
672
+ ### 8.1 向后兼容性风险
673
+ **风险**:破坏现有API
674
+ **缓解措施**:
675
+ - 保留所有包装器方法
676
+ - 保持方法签名不变
677
+ - 充分测试所有调用场景
678
+
679
+ ### 8.2 性能风险
680
+ **风险**:性能下降
681
+ **缓解措施**:
682
+ - 性能基准测试
683
+ - 优化热点代码
684
+ - 保持缓存逻辑
685
+
686
+ ### 8.3 缓存一致性风险
687
+ **风险**:缓存逻辑错误
688
+ **缓解措施**:
689
+ - 单元测试覆盖所有缓存场景
690
+ - 集成测试验证缓存行为
691
+ - 添加缓存失效机制
692
+
693
+ ## 9. 设计决策记录
694
+
695
+ ### DDR-001: 为什么保留包装器方法?
696
+ **决策**:保留 `getCLIPattern()`, `getEnhancedCLIPattern()`, `analyzeCLIEnhanced()` 作为包装器
697
+ **理由**:
698
+ - 保持向后兼容性
699
+ - 不影响现有代码
700
+ - 便于平滑迁移
701
+ **替代方案**:删除包装器,强制所有代码使用新API
702
+ **拒绝理由**:破坏向后兼容性,影响范围大
703
+
704
+ ### DDR-002: 为什么使用 options 对象而不是多个参数?
705
+ **决策**:使用 `options` 对象传递配置
706
+ **理由**:
707
+ - 参数扩展性好
708
+ - 调用清晰易读
709
+ - 便于添加新选项
710
+ **替代方案**:使用多个布尔参数 `analyzeCLI(cliName, enhanced, forceRefresh)`
711
+ **拒绝理由**:参数顺序容易混淆,扩展性差
712
+
713
+ ### DDR-003: 为什么 addEnhancedInfo() 不修改原对象?
714
+ **决策**:返回新对象,不修改原对象
715
+ **理由**:
716
+ - 遵循不可变原则
717
+ - 避免副作用
718
+ - 便于调试和测试
719
+ **替代方案**:直接修改原对象
720
+ **拒绝理由**:违反不可变原则,容易产生副作用
721
+
722
+ ## 10. 变更历史
723
+
724
+ | 版本 | 日期 | 作者 | 变更说明 |
725
+ |------|------|------|----------|
726
+ | 1.0 | 2026-01-11 | iFlow | 初始版本 |