stigmergy 1.2.13 → 1.3.1

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 (88) 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 +146 -136
  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 +403 -0
  24. package/skills/resumesession/README.md +381 -0
  25. package/skills/resumesession/SKILL.md +211 -0
  26. package/skills/resumesession/__init__.py +33 -0
  27. package/skills/resumesession/implementations/simple-resume.js +13 -0
  28. package/skills/resumesession/independent-resume.js +750 -0
  29. package/skills/resumesession/package.json +1 -0
  30. package/skills/resumesession/skill.json +1 -0
  31. package/src/adapters/claude/install_claude_integration.js +9 -1
  32. package/src/adapters/codebuddy/install_codebuddy_integration.js +3 -1
  33. package/src/adapters/codex/install_codex_integration.js +15 -5
  34. package/src/adapters/gemini/install_gemini_integration.js +3 -1
  35. package/src/adapters/qwen/install_qwen_integration.js +3 -1
  36. package/src/cli/commands/autoinstall.js +65 -0
  37. package/src/cli/commands/errors.js +190 -0
  38. package/src/cli/commands/independent-resume.js +395 -0
  39. package/src/cli/commands/install.js +179 -0
  40. package/src/cli/commands/permissions.js +108 -0
  41. package/src/cli/commands/project.js +485 -0
  42. package/src/cli/commands/scan.js +97 -0
  43. package/src/cli/commands/simple-resume.js +377 -0
  44. package/src/cli/commands/skills.js +158 -0
  45. package/src/cli/commands/status.js +113 -0
  46. package/src/cli/commands/stigmergy-resume.js +775 -0
  47. package/src/cli/commands/system.js +301 -0
  48. package/src/cli/commands/universal-resume.js +394 -0
  49. package/src/cli/router-beta.js +471 -0
  50. package/src/cli/utils/environment.js +75 -0
  51. package/src/cli/utils/formatters.js +47 -0
  52. package/src/cli/utils/skills_cache.js +92 -0
  53. package/src/core/cache_cleaner.js +1 -0
  54. package/src/core/cli_adapters.js +345 -0
  55. package/src/core/cli_help_analyzer.js +1236 -680
  56. package/src/core/cli_path_detector.js +702 -709
  57. package/src/core/cli_tools.js +515 -160
  58. package/src/core/coordination/nodejs/CLIIntegrationManager.js +18 -0
  59. package/src/core/coordination/nodejs/HookDeploymentManager.js +242 -412
  60. package/src/core/coordination/nodejs/HookDeploymentManager.refactored.js +323 -0
  61. package/src/core/coordination/nodejs/generators/CLIAdapterGenerator.js +363 -0
  62. package/src/core/coordination/nodejs/generators/ResumeSessionGenerator.js +932 -0
  63. package/src/core/coordination/nodejs/generators/SkillsIntegrationGenerator.js +1395 -0
  64. package/src/core/coordination/nodejs/generators/index.js +12 -0
  65. package/src/core/enhanced_cli_installer.js +1208 -608
  66. package/src/core/enhanced_cli_parameter_handler.js +402 -0
  67. package/src/core/execution_mode_detector.js +222 -0
  68. package/src/core/installer.js +151 -106
  69. package/src/core/local_skill_scanner.js +732 -0
  70. package/src/core/multilingual/language-pattern-manager.js +1 -1
  71. package/src/core/skills/BuiltinSkillsDeployer.js +188 -0
  72. package/src/core/skills/StigmergySkillManager.js +123 -16
  73. package/src/core/skills/embedded-openskills/SkillParser.js +7 -3
  74. package/src/core/smart_router.js +550 -261
  75. package/src/index.js +10 -4
  76. package/src/utils.js +66 -7
  77. package/test/cli-integration.test.js +304 -0
  78. package/test/direct_smart_router_test.js +88 -0
  79. package/test/enhanced-cli-agent-skill-test.js +485 -0
  80. package/test/simple_test.js +82 -0
  81. package/test/smart_router_test_runner.js +123 -0
  82. package/test/smart_routing_edge_cases.test.js +284 -0
  83. package/test/smart_routing_simple_verification.js +139 -0
  84. package/test/smart_routing_verification.test.js +346 -0
  85. package/test/specific-cli-agent-skill-analysis.js +385 -0
  86. package/test/unit/smart_router.test.js +295 -0
  87. package/test/very_simple_test.js +54 -0
  88. package/src/cli/router.js +0 -1783
@@ -1,3 +1,4 @@
1
+ const chalk = require('chalk');
1
2
  const path = require('path');
2
3
  const fs = require('fs/promises');
3
4
  const os = require('os');
@@ -6,12 +7,16 @@ const inquirer = require('inquirer');
6
7
  const SmartRouter = require('./smart_router');
7
8
  const { errorHandler } = require('./error_handler');
8
9
  const MemoryManager = require('./memory_manager');
10
+ const EnhancedCLIInstaller = require('./enhanced_cli_installer');
9
11
 
10
- class StigmergyInstaller {
11
- constructor() {
12
+ class StigmergyInstaller extends EnhancedCLIInstaller {
13
+ constructor(options = {}) {
14
+ super(options);
15
+ this.concurrency = options.concurrency || 6;
12
16
  this.router = new SmartRouter();
13
17
  this.memory = new MemoryManager();
14
18
  this.configDir = path.join(os.homedir(), '.stigmergy');
19
+ this.scanCache = new Map(); // 缓存扫描结果
15
20
  }
16
21
 
17
22
  async checkCLI(toolName) {
@@ -48,36 +53,38 @@ class StigmergyInstaller {
48
53
  codexPath.endsWith('/codex') ||
49
54
  codexPath.endsWith('\\codex')
50
55
  ) {
51
- // Read the script to find the JS file path
52
- const fsSync = require('fs');
53
- const scriptContent = fsSync.readFileSync(codexPath, 'utf8');
54
-
55
- // Look for JS file reference in the script
56
- const jsFileMatch = scriptContent.match(
57
- /(["'])(.*?codex\.js.*?)\1/,
58
- );
59
- if (jsFileMatch) {
60
- const jsFilePath = jsFileMatch[2];
61
- // Check if JS file exists and is not empty
62
- if (fsSync.existsSync(jsFilePath)) {
63
- const stats = fsSync.statSync(jsFilePath);
64
- if (stats.size === 0) {
65
- console.log(
66
- '[DEBUG] Codex JS file is empty, marking as unavailable',
67
- );
68
- return false;
56
+ // Try to verify JS file, but don't fail if we can't
57
+ // The actual --version test below is more reliable
58
+ try {
59
+ const fsSync = require('fs');
60
+ const scriptContent = fsSync.readFileSync(codexPath, 'utf8');
61
+
62
+ // Look for JS file reference in the script
63
+ // Match node_modules/@openai/codex/bin/codex.js pattern
64
+ const jsFileMatch = scriptContent.match(/node_modules\/@openai\/codex\/bin\/codex\.js/);
65
+ if (jsFileMatch) {
66
+ // Construct actual path based on npm global directory
67
+ const npmGlobalDir = require('path').dirname(codexPath);
68
+ const jsFilePath = require('path').join(npmGlobalDir, jsFileMatch[0]);
69
+
70
+ if (fsSync.existsSync(jsFilePath)) {
71
+ const stats = fsSync.statSync(jsFilePath);
72
+ if (stats.size === 0) {
73
+ console.log('[DEBUG] Codex JS file is empty, marking as unavailable');
74
+ return false;
75
+ }
76
+ // File exists and has content - continue to version check
77
+ } else {
78
+ console.log('[DEBUG] Codex JS file not found at expected path, will try version check');
69
79
  }
70
- } else {
71
- console.log(
72
- '[DEBUG] Codex JS file does not exist, marking as unavailable',
73
- );
74
- return false;
75
80
  }
81
+ } catch (scriptError) {
82
+ console.log(`[DEBUG] Could not verify codex script: ${scriptError.message}`);
83
+ // Continue anyway - the version check below is more reliable
76
84
  }
77
85
  }
78
86
 
79
- // If we got here, the codex command exists and seems valid
80
- // Continue with normal checks below
87
+ // If we got here, the codex command exists - continue with normal checks below
81
88
  } else {
82
89
  // Codex command doesn't exist
83
90
  return false;
@@ -109,8 +116,9 @@ class StigmergyInstaller {
109
116
  };
110
117
 
111
118
  // Additional protection for codex
119
+ // Note: codex requires shell=true on Windows to work properly
112
120
  if (toolName === 'codex') {
113
- testOptions.shell = false;
121
+ // Keep shell=true for codex (don't override)
114
122
  testOptions.windowsHide = true;
115
123
  testOptions.detached = false;
116
124
  }
@@ -132,6 +140,7 @@ class StigmergyInstaller {
132
140
  // Special handling for codex to avoid opening files
133
141
  if (toolName === 'codex') {
134
142
  // For codex, only try --help and --version with extra precautions
143
+ // Note: codex requires shell=true on Windows
135
144
  const codexChecks = [
136
145
  { args: ['--help'], expected: 0 },
137
146
  { args: ['--version'], expected: 0 },
@@ -143,7 +152,7 @@ class StigmergyInstaller {
143
152
  encoding: 'utf8',
144
153
  timeout: 10000,
145
154
  stdio: ['pipe', 'pipe', 'pipe'], // Ensure all IO is piped
146
- shell: false, // Don't use shell to avoid extra window opening
155
+ shell: true, // Use shell for codex compatibility
147
156
  windowsHide: true, // Hide console window on Windows
148
157
  detached: false, // Don't detach process
149
158
  });
@@ -201,36 +210,60 @@ class StigmergyInstaller {
201
210
 
202
211
  async scanCLI() {
203
212
  console.log('[SCAN] Scanning for AI CLI tools...');
213
+
214
+ // 检查缓存
215
+ const cacheKey = 'scan_results';
216
+ if (this.scanCache.has(cacheKey)) {
217
+ console.log('[SCAN] Using cached scan results');
218
+ return this.scanCache.get(cacheKey);
219
+ }
220
+
204
221
  const available = {};
205
222
  const missing = {};
223
+ const tools = Object.entries(this.router.tools);
224
+
225
+ // 并行扫描所有工具
226
+ const scanPromises = tools.map(async ([toolName, toolInfo]) => {
227
+ // Skip internal functions without install command
228
+ if (!toolInfo.install) {
229
+ return { toolName, status: 'skip' };
230
+ }
206
231
 
207
- for (const [toolName, toolInfo] of Object.entries(this.router.tools)) {
208
232
  try {
209
- console.log(`[SCAN] Checking ${toolInfo.name}...`);
210
233
  const isAvailable = await this.checkCLI(toolName);
211
-
212
- if (isAvailable) {
213
- console.log(`[OK] ${toolInfo.name} is available`);
214
- available[toolName] = toolInfo;
215
- } else {
216
- console.log(`[MISSING] ${toolInfo.name} is not installed`);
217
- missing[toolName] = toolInfo;
218
- }
234
+ return { toolName, status: isAvailable ? 'available' : 'missing', toolInfo };
219
235
  } catch (error) {
220
236
  await errorHandler.logError(
221
237
  error,
222
238
  'WARN',
223
239
  `StigmergyInstaller.scanCLI.${toolName}`,
224
240
  );
225
- console.log(
226
- `[ERROR] Failed to check ${toolInfo.name}: ${error.message}`,
227
- );
228
- console.log(`[MISSING] ${toolInfo.name} is not installed`);
229
- missing[toolName] = toolInfo;
241
+ return { toolName, status: 'missing', toolInfo };
242
+ }
243
+ });
244
+
245
+ const results = await Promise.all(scanPromises);
246
+
247
+ // 处理结果
248
+ for (const result of results) {
249
+ if (result.status === 'skip') {
250
+ continue;
251
+ }
252
+
253
+ if (result.status === 'available') {
254
+ console.log(`[OK] ${result.toolInfo.name} is available`);
255
+ available[result.toolName] = result.toolInfo;
256
+ } else {
257
+ console.log(`[MISSING] ${result.toolInfo.name} is not installed`);
258
+ missing[result.toolName] = result.toolInfo;
230
259
  }
231
260
  }
232
261
 
233
- return { available, missing };
262
+ // 缓存结果
263
+ const scanResults = { available, missing };
264
+ this.scanCache.set(cacheKey, scanResults);
265
+
266
+ return scanResults;
234
267
  }
235
268
 
236
269
  /**
@@ -305,52 +338,56 @@ class StigmergyInstaller {
305
338
 
306
339
  /**
307
340
  * Install selected CLI tools
341
+ * 统一调用父类EnhancedCLIInstaller的实现
308
342
  */
309
343
  async installTools(selectedTools, missingTools) {
310
- const chalk = require('chalk');
311
- let successCount = 0;
312
-
313
- for (const toolName of selectedTools) {
314
- const toolInfo = missingTools[toolName];
315
- if (!toolInfo) continue;
316
-
317
- console.log(`\n[INSTALL] Installing ${toolInfo.name}...`);
318
- console.log(chalk.yellow(`Command: ${toolInfo.install}`));
319
-
320
- try {
321
- // Parse the install command
322
- const [command, ...args] = toolInfo.install.split(' ');
323
-
324
- // Execute the installation command
325
- const result = spawnSync(command, args, {
326
- stdio: 'inherit', // Show output in real-time
327
- shell: true, // Use shell for npm commands
328
- encoding: 'utf-8'
329
- });
330
-
331
- if (result.status === 0) {
332
- console.log(chalk.green(`[OK] Successfully installed ${toolInfo.name}`));
333
- successCount++;
334
- } else {
335
- console.log(chalk.red(`[ERROR] Failed to install ${toolInfo.name}. Exit code: ${result.status}`));
336
- // Continue with other tools
344
+ // 调用父类的增强安装功能
345
+ const result = await super.installTools(selectedTools, missingTools);
346
+
347
+ // 保留StigmergyInstaller的特有功能:生成cross-CLI hooks
348
+ if (result && result.successful > 0) {
349
+ console.log('\n[HOOKS] Generating cross-CLI integration hooks...');
350
+ for (const toolName of selectedTools) {
351
+ const toolInfo = missingTools[toolName];
352
+ if (toolInfo && this.results.installations[toolName]?.success) {
353
+ try {
354
+ await this.generateToolHook(toolName, toolInfo);
355
+ } catch (error) {
356
+ console.log(`[WARN] Failed to generate hook for ${toolName}: ${error.message}`);
357
+ }
337
358
  }
338
- } catch (error) {
339
- console.log(chalk.red(`[ERROR] Installation failed for ${toolInfo.name}: ${error.message}`));
340
- // Continue with other tools
341
359
  }
342
360
  }
343
361
 
344
- if (successCount > 0) {
345
- console.log(chalk.green(`\n[INSTALL] Successfully installed ${successCount}/${selectedTools.length} tools`));
362
+ return result;
363
+ }
346
364
 
347
- // Add a short delay to ensure installations are complete
348
- await new Promise(resolve => setTimeout(resolve, 2000));
365
+ /**
366
+ * Generate hook for a specific CLI tool
367
+ * @param {string} toolName - Name of the CLI tool
368
+ * @param {Object} toolInfo - Tool information object
369
+ */
370
+ async generateToolHook(toolName, toolInfo) {
371
+ console.log(`[HOOK] Generating hook for ${toolName}...`);
349
372
 
350
- return true;
351
- } else {
352
- console.log(chalk.red('[INSTALL] No tools were successfully installed'));
353
- return false;
373
+ const HookDeploymentManager = require('./coordination/nodejs/HookDeploymentManager');
374
+ const hookManager = new HookDeploymentManager();
375
+
376
+ await hookManager.initialize();
377
+
378
+ try {
379
+ const deploySuccess = await hookManager.deployHooksForCLI(toolName);
380
+
381
+ if (deploySuccess) {
382
+ console.log(`[OK] Hook generated successfully for ${toolName}`);
383
+ return true;
384
+ } else {
385
+ console.log(`[WARN] Hook generation failed for ${toolName}`);
386
+ return false;
387
+ }
388
+ } catch (error) {
389
+ console.error(`[ERROR] Hook generation error for ${toolName}:`, error.message);
390
+ throw error;
354
391
  }
355
392
  }
356
393
 
@@ -359,43 +396,39 @@ class StigmergyInstaller {
359
396
  */
360
397
  async deployHooks(available) {
361
398
  console.log('\n[DEPLOY] Deploying cross-CLI integration hooks...');
399
+ console.log(chalk.blue(`[INFO] Using parallel deployment with concurrency: ${this.concurrency || 6}`));
362
400
 
363
401
  const HookDeploymentManager = require('./coordination/nodejs/HookDeploymentManager');
364
402
  const hookManager = new HookDeploymentManager();
365
403
 
366
404
  await hookManager.initialize();
367
405
 
406
+ const toolEntries = Object.entries(available);
368
407
  let successCount = 0;
369
- let totalCount = Object.keys(available).length;
370
-
371
- for (const [toolName, toolInfo] of Object.entries(available)) {
372
- console.log(`\n[DEPLOY] Deploying hooks for ${toolInfo.name}...`);
408
+ let totalCount = toolEntries.length;
409
+ const concurrency = this.concurrency || 6;
373
410
 
411
+ const deployForTool = async ([toolName, toolInfo]) => {
412
+ const startTime = Date.now();
413
+
374
414
  try {
375
415
  const fs = require('fs/promises');
376
416
  const path = require('path');
377
417
 
378
- // Create hooks directory
379
418
  await fs.mkdir(toolInfo.hooksDir, { recursive: true });
380
- console.log(`[OK] Created hooks directory: ${toolInfo.hooksDir}`);
381
-
382
- // Create config directory
383
419
  const configDir = path.dirname(toolInfo.config);
384
420
  await fs.mkdir(configDir, { recursive: true });
385
- console.log(`[OK] Created config directory: ${configDir}`);
386
421
 
387
- // Use HookDeploymentManager to deploy Node.js hooks
388
422
  const deploySuccess = await hookManager.deployHooksForCLI(toolName);
389
423
 
390
424
  if (deploySuccess) {
391
- console.log(`[OK] Node.js hooks deployed successfully for ${toolInfo.name}`);
425
+ await this.installToolIntegration(toolName, toolInfo);
426
+ const duration = Date.now() - startTime;
427
+ console.log(`[OK] ${toolInfo.name} deployed successfully (${duration}ms)`);
428
+ return { success: true, toolName, duration };
392
429
  }
393
430
 
394
- // Run JavaScript-based installation for each tool
395
- await this.installToolIntegration(toolName, toolInfo);
396
-
397
- console.log(`[OK] Hooks deployed successfully for ${toolInfo.name}`);
398
- successCount++;
431
+ return { success: false, toolName, duration: Date.now() - startTime };
399
432
 
400
433
  } catch (error) {
401
434
  const { errorHandler } = require('./error_handler');
@@ -404,16 +437,28 @@ class StigmergyInstaller {
404
437
  'ERROR',
405
438
  `StigmergyInstaller.deployHooks.${toolName}`,
406
439
  );
407
- console.log(
408
- `[ERROR] Failed to deploy hooks for ${toolInfo.name}: ${error.message}`,
409
- );
410
- console.log('[INFO] Continuing with other tools...');
440
+
441
+ const duration = Date.now() - startTime;
442
+ console.log(`[ERROR] Failed to deploy hooks for ${toolInfo.name}: ${error.message} (${duration}ms)`);
443
+
444
+ return { success: false, toolName, duration, error: error.message };
411
445
  }
446
+ };
447
+
448
+ const results = [];
449
+ for (let i = 0; i < toolEntries.length; i += concurrency) {
450
+ const batch = toolEntries.slice(i, i + concurrency);
451
+ const batchResults = await Promise.all(batch.map(deployForTool));
452
+ results.push(...batchResults);
412
453
  }
413
454
 
414
- console.log(
415
- `\n[SUMMARY] Hook deployment completed: ${successCount}/${totalCount} tools successful`,
416
- );
455
+ successCount = results.filter(r => r.success).length;
456
+ const totalDuration = Math.max(...results.map(r => r.duration));
457
+
458
+ console.log(`\n[SUMMARY] Hook deployment completed: ${successCount}/${totalCount} tools successful`);
459
+ console.log(chalk.blue(`[PERFORMANCE] Total deployment time: ${totalDuration}ms`));
460
+ console.log(chalk.blue(`[PERFORMANCE] Average per tool: ${Math.round(totalDuration / totalCount)}ms`));
461
+
417
462
  return successCount > 0;
418
463
  }
419
464