stigmergy 1.3.29-beta.0 → 1.3.30-beta.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "stigmergy",
3
- "version": "1.3.29-beta.0",
3
+ "version": "1.3.30-beta.0",
4
4
  "description": "Stigmergy CLI - Multi-Agents Cross-AI CLI Tools Collaboration System",
5
5
  "main": "src/index.js",
6
6
  "bin": {
@@ -273,12 +273,20 @@ class CLIHelpAnalyzer {
273
273
  */
274
274
  async analyzeAllCLI() {
275
275
  const results = {};
276
- for (const [cliName, _] of Object.entries(this.cliTools)) {
276
+ const cliNames = Object.keys(this.cliTools);
277
+
278
+ // 优化:并行分析所有 CLI,添加超时保护
279
+ const analysisPromises = cliNames.map(async (cliName) => {
277
280
  try {
278
281
  if (process.env.DEBUG === 'true') {
279
282
  console.log(`Analyzing ${cliName}...`);
280
283
  }
281
- results[cliName] = await this.analyzeCLI(cliName);
284
+ // 添加超时保护,单个 CLI 分析最多 60 秒(因为需要尝试多个 help 方法)
285
+ const timeoutPromise = new Promise((_, reject) =>
286
+ setTimeout(() => reject(new Error('Analysis timeout')), 60000)
287
+ );
288
+ const result = await Promise.race([this.analyzeCLI(cliName), timeoutPromise]);
289
+ return { cliName, result };
282
290
  } catch (error) {
283
291
  // Only log important errors, suppress expected file not found errors
284
292
  if (
@@ -286,7 +294,8 @@ class CLIHelpAnalyzer {
286
294
  !error.message.includes('no such file or directory') &&
287
295
  !error.message.includes(
288
296
  'not recognized as an internal or external command',
289
- )
297
+ ) &&
298
+ !error.message.includes('Analysis timeout')
290
299
  ) {
291
300
  await errorHandler.logError(
292
301
  error,
@@ -294,9 +303,21 @@ class CLIHelpAnalyzer {
294
303
  `CLIHelpAnalyzer.analyzeAllCLI.${cliName}`,
295
304
  );
296
305
  }
297
- results[cliName] = { success: false, error: error.message };
306
+ return { cliName, result: { success: false, error: error.message } };
298
307
  }
308
+ });
309
+
310
+ // 等待所有分析完成,添加整体超时保护
311
+ const overallTimeoutPromise = new Promise((_, reject) =>
312
+ setTimeout(() => reject(new Error('Overall analysis timeout')), 120000)
313
+ );
314
+ const analysisResults = await Promise.race([Promise.all(analysisPromises), overallTimeoutPromise]);
315
+
316
+ // 整理结果
317
+ for (const { cliName, result } of analysisResults) {
318
+ results[cliName] = result;
299
319
  }
320
+
300
321
  return results;
301
322
  }
302
323
 
@@ -309,6 +330,24 @@ class CLIHelpAnalyzer {
309
330
  throw new Error(`CLI tool ${cliName} not found in configuration`);
310
331
  }
311
332
  try {
333
+ // 优化:检查缓存版本,只在版本变化时重新分析
334
+ const cachedAnalysis = await this.getCachedAnalysis(cliName);
335
+ if (cachedAnalysis && cachedAnalysis.success) {
336
+ // 获取当前版本
337
+ const currentVersion = await this.getCurrentVersion(cliName, cliConfig);
338
+ // 如果版本未变化,使用缓存
339
+ if (currentVersion === cachedAnalysis.version && !this.isCacheExpired(cachedAnalysis.timestamp)) {
340
+ if (process.env.DEBUG === 'true') {
341
+ console.log(`[DEBUG] ${cliName}: 使用缓存的分析结果 (版本: ${cachedAnalysis.version})`);
342
+ }
343
+ return cachedAnalysis;
344
+ } else {
345
+ if (process.env.DEBUG === 'true') {
346
+ console.log(`[DEBUG] ${cliName}: 版本变化 (${cachedAnalysis.version} -> ${currentVersion}) 或缓存过期,重新分析`);
347
+ }
348
+ }
349
+ }
350
+
312
351
  // Get help information
313
352
  const helpInfo = await this.getHelpInfo(cliName, cliConfig);
314
353
  // Detect CLI type
@@ -368,14 +407,8 @@ class CLIHelpAnalyzer {
368
407
  }
369
408
 
370
409
  const helpMethods = [
371
- ['--help'],
372
- ['-h'],
373
- ['help'],
374
- ['--usage'],
375
- [''],
376
- ['version'],
377
- ['--version'],
378
- ['-v'],
410
+ ['--help'], // 最常用
411
+ ['-h'], // 常用
379
412
  ];
380
413
  let rawHelp = '';
381
414
  let version = 'unknown';
@@ -385,7 +418,7 @@ class CLIHelpAnalyzer {
385
418
  try {
386
419
  const result = spawnSync(cliName, helpArgs, {
387
420
  encoding: 'utf8',
388
- timeout: 15000,
421
+ timeout: 5000,
389
422
  shell: true,
390
423
  });
391
424
  if (result.status === 0 && result.stdout) {
@@ -407,11 +440,10 @@ class CLIHelpAnalyzer {
407
440
  try {
408
441
  const versionCmd = cliConfig.version.split(' ');
409
442
  const versionResult = spawnSync(versionCmd[0], versionCmd.slice(1), {
410
- encoding: 'utf8',
411
- timeout: 10000,
412
- shell: true,
413
- });
414
- if (versionResult.status === 0) {
443
+ encoding: 'utf8',
444
+ timeout: 3000, // 优化:减少超时时间从 10 秒到 3 秒
445
+ shell: true,
446
+ }); if (versionResult.status === 0) {
415
447
  version = versionResult.stdout.trim() || versionResult.stderr.trim();
416
448
  }
417
449
  } catch (error) {
@@ -720,7 +752,23 @@ class CLIHelpAnalyzer {
720
752
  * Get CLI pattern (wrapper for getCachedAnalysis)
721
753
  */
722
754
  async getCLIPattern(cliName) {
723
- return await this.getCachedAnalysis(cliName);
755
+ const cached = await this.getCachedAnalysis(cliName);
756
+
757
+ // 优化:添加版本变化检测
758
+ if (cached && cached.success && cached.timestamp && !this.isCacheExpired(cached.timestamp)) {
759
+ // 检查版本是否变化
760
+ const cliConfig = this.cliTools[cliName];
761
+ if (cliConfig) {
762
+ const currentVersion = await this.getCurrentVersion(cliName, cliConfig);
763
+ // 如果版本未变化,使用缓存
764
+ if (currentVersion === cached.version) {
765
+ return cached;
766
+ }
767
+ }
768
+ }
769
+
770
+ // 版本变化或缓存过期,重新分析
771
+ return await this.analyzeCLI(cliName);
724
772
  }
725
773
 
726
774
  /**
@@ -775,6 +823,28 @@ class CLIHelpAnalyzer {
775
823
  }
776
824
  }
777
825
 
826
+ /**
827
+ * Get current CLI version
828
+ */
829
+ async getCurrentVersion(cliName, cliConfig) {
830
+ try {
831
+ const versionCmd = cliConfig.version || `${cliName} --version`;
832
+ const result = spawnSync(versionCmd.split(' ')[0], versionCmd.split(' ').slice(1), {
833
+ encoding: 'utf8',
834
+ shell: true,
835
+ timeout: 3000,
836
+ stdio: ['ignore', 'pipe', 'pipe']
837
+ });
838
+
839
+ if (result.status === 0) {
840
+ return (result.stdout.trim() || result.stderr.trim()).split('\n')[0];
841
+ }
842
+ return 'unknown';
843
+ } catch (error) {
844
+ return 'unknown';
845
+ }
846
+ }
847
+
778
848
  /**
779
849
  * Record failed attempt
780
850
  */
@@ -980,23 +1050,32 @@ class CLIHelpAnalyzer {
980
1050
  async getEnhancedCLIPattern(cliName) {
981
1051
  const cached = await this.getCachedAnalysis(cliName);
982
1052
 
983
- if (cached && cached.timestamp && !this.isCacheExpired(cached.timestamp)) {
984
- // Enhance cached data with agent/skill information
985
- const enhancedPatterns = this.enhancedPatterns[cliName];
986
- if (enhancedPatterns) {
987
- cached.agentSkillSupport = {
988
- supportsAgents: enhancedPatterns.agentDetection || false,
989
- supportsSkills: enhancedPatterns.skillDetection || false,
990
- naturalLanguageSupport: enhancedPatterns.naturalLanguageSupport || false,
991
- skillPrefixRequired: enhancedPatterns.skillPrefixRequired || false,
992
- positionalArgs: enhancedPatterns.positionalArgs || false,
993
- agentTypes: enhancedPatterns.agentTypes || [],
994
- skillKeywords: enhancedPatterns.skillKeywords || [],
995
- commandFormat: enhancedPatterns.commandFormat || '',
996
- examples: enhancedPatterns.examples || []
997
- };
1053
+ // 优化:添加版本变化检测
1054
+ if (cached && cached.success && cached.timestamp && !this.isCacheExpired(cached.timestamp)) {
1055
+ // 检查版本是否变化
1056
+ const cliConfig = this.cliTools[cliName];
1057
+ if (cliConfig) {
1058
+ const currentVersion = await this.getCurrentVersion(cliName, cliConfig);
1059
+ // 如果版本未变化,使用缓存
1060
+ if (currentVersion === cached.version) {
1061
+ // Enhance cached data with agent/skill information
1062
+ const enhancedPatterns = this.enhancedPatterns[cliName];
1063
+ if (enhancedPatterns) {
1064
+ cached.agentSkillSupport = {
1065
+ supportsAgents: enhancedPatterns.agentDetection || false,
1066
+ supportsSkills: enhancedPatterns.skillDetection || false,
1067
+ naturalLanguageSupport: enhancedPatterns.naturalLanguageSupport || false,
1068
+ skillPrefixRequired: enhancedPatterns.skillPrefixRequired || false,
1069
+ positionalArgs: enhancedPatterns.positionalArgs || false,
1070
+ agentTypes: enhancedPatterns.agentTypes || [],
1071
+ skillKeywords: enhancedPatterns.skillKeywords || [],
1072
+ commandFormat: enhancedPatterns.commandFormat || '',
1073
+ examples: enhancedPatterns.examples || []
1074
+ };
1075
+ }
1076
+ return cached;
1077
+ }
998
1078
  }
999
- return cached;
1000
1079
  }
1001
1080
 
1002
1081
  // Perform enhanced analysis
@@ -649,38 +649,36 @@ async function checkInstallation(toolName) {
649
649
  }
650
650
 
651
651
  // Check if the tool is actually executable, not just if the path exists
652
- // 完全跳过耗时的可执行性测试,只检查路径
653
- const isExecutable = true;
654
- const installed = !!toolPath && isExecutable;
655
-
652
+ // 优化:合并可执行性测试和版本检查,只执行一次命令
656
653
  let version = null;
657
- if (installed) {
654
+ let isExecutable = false;
655
+
656
+ if (toolPath) {
658
657
  try {
659
658
  const { spawnSync } = require('child_process');
660
659
  const toolConfig = CLI_TOOLS[toolName];
661
660
  const versionCmd = toolConfig.version || `${toolName} --version`;
662
661
 
663
- // 跳过慢速 CLI 的版本检查
664
- const slowCLIs = ['iflow', 'qodercli', 'copilot'];
665
- if (slowCLIs.includes(toolName)) {
666
- version = 'unknown';
667
- } else {
668
- const result = spawnSync(versionCmd.split(' ')[0], versionCmd.split(' ').slice(1), {
669
- encoding: 'utf8',
670
- shell: true,
671
- timeout: 3000,
672
- stdio: ['ignore', 'pipe', 'pipe']
673
- });
662
+ const result = spawnSync(versionCmd.split(' ')[0], versionCmd.split(' ').slice(1), {
663
+ encoding: 'utf8',
664
+ shell: true,
665
+ timeout: 5000,
666
+ stdio: ['ignore', 'pipe', 'pipe']
667
+ });
674
668
 
675
- if (result.status === 0) {
676
- version = result.stdout.trim() || result.stderr.trim();
677
- }
669
+ // 如果版本检查成功,说明 CLI 可执行
670
+ isExecutable = result.status === 0;
671
+
672
+ if (isExecutable) {
673
+ version = result.stdout.trim() || result.stderr.trim();
678
674
  }
679
675
  } catch (error) {
680
- // Version check failed, but tool is still installed
676
+ isExecutable = false;
681
677
  }
682
678
  }
683
679
 
680
+ const installed = !!toolPath && isExecutable;
681
+
684
682
  return {
685
683
  installed,
686
684
  path: toolPath,