stigmergy 1.2.12 → 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 -1737
package/src/cli/router.js DELETED
@@ -1,1737 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- /**
4
- * Stigmergy CLI - Multi-Agents Cross-AI CLI Tools Collaboration System
5
- * Unified Entry Point
6
- * International Version - Pure English & ANSI Only
7
- * Version: 1.0.94
8
- */
9
-
10
- // Import all components
11
- const path = require('path');
12
- const os = require('os');
13
- const { Command } = require('commander');
14
- const inquirer = require('inquirer');
15
- const chalk = require('chalk');
16
- const yaml = require('js-yaml');
17
- const fs = require('fs/promises');
18
- const fsSync = require('fs');
19
- const { spawnSync } = require('child_process');
20
-
21
- // Import permission management components
22
- const DirectoryPermissionManager = require('../core/directory_permission_manager');
23
- const { setupCLIPaths, getCLIPath } = require('../core/cli_tools');
24
-
25
- // Import our custom modules
26
- const SmartRouter = require('../core/smart_router');
27
- const CLIHelpAnalyzer = require('../core/cli_help_analyzer');
28
- const { CLI_TOOLS } = require('../core/cli_tools');
29
- const { errorHandler } = require('../core/error_handler');
30
- const { executeCommand, executeJSFile } = require('../utils');
31
- const MemoryManager = require('../core/memory_manager');
32
- const StigmergyInstaller = require('../core/installer');
33
- const UpgradeManager = require('../core/upgrade_manager');
34
- const { maxOfTwo, isAuthenticated } = require('../utils/helpers');
35
-
36
- // Set up global error handlers using our error handler module
37
- const { setupGlobalErrorHandlers } = require('../core/error_handler');
38
- setupGlobalErrorHandlers();
39
-
40
- // Helper function to format bytes
41
- function formatBytes(bytes) {
42
- const sizes = ['Bytes', 'KB', 'MB', 'GB'];
43
- if (bytes === 0) return '0 Bytes';
44
- const i = Math.floor(Math.log(bytes) / Math.log(1024));
45
- return Math.round(bytes / Math.pow(1024, i) * 100) / 100 + ' ' + sizes[i];
46
- }
47
-
48
- // Helper function to get appropriate working directory for CLI tools
49
- function getWorkingDirectoryForTool(toolName) {
50
- switch (toolName) {
51
- case 'qwen':
52
- // For Qwen CLI, use user home directory to avoid module resolution issues
53
- return os.homedir();
54
- case 'claude':
55
- // For Claude CLI, use user home directory
56
- return os.homedir();
57
- case 'gemini':
58
- // For Gemini CLI, use user home directory
59
- return os.homedir();
60
- case 'iflow':
61
- // For iFlow CLI, use user home directory
62
- return os.homedir();
63
- case 'qodercli':
64
- // For Qoder CLI, use user home directory
65
- return os.homedir();
66
- default:
67
- // For other tools, use current directory
68
- return process.cwd();
69
- }
70
- }
71
-
72
- async function main() {
73
- const args = process.argv.slice(2);
74
-
75
- // Debug mode
76
- if (process.env.DEBUG === 'true') {
77
- console.log('[DEBUG] Main function called with args:', process.argv);
78
- }
79
-
80
- // Create instances
81
- const memory = new MemoryManager();
82
- const installer = new StigmergyInstaller();
83
- const router = new SmartRouter();
84
-
85
- // Handle help command early
86
- if (
87
- args.length === 0 ||
88
- args.includes('-h') ||
89
- args.includes('--help') ||
90
- args.includes('help')
91
- ) {
92
- console.log('Stigmergy CLI - Multi-Agents Cross-AI CLI Tools Collaboration System');
93
- console.log('=====================================================================');
94
- console.log('');
95
- console.log('Usage: stigmergy <command> [options]');
96
- console.log('');
97
- console.log('Commands:');
98
- console.log(' help, --help Show this help message');
99
- console.log(' version, --version Show version information');
100
- console.log(' status Check CLI tools status');
101
- console.log(' scan Scan for available AI CLI tools');
102
- console.log(' install Auto-install missing CLI tools (with permission fix)');
103
- console.log(' upgrade Upgrade all CLI tools to latest versions');
104
- console.log(
105
- ' deploy Deploy hooks and integration to installed tools',
106
- );
107
- console.log(' setup Complete setup and configuration');
108
- console.log(
109
- ' init Initialize Stigmergy project in current directory',
110
- );
111
- console.log(' clean (c) Clean temporary files and caches');
112
- console.log(' diagnostic (d) Show system diagnostic information');
113
- console.log(' fix-perms Fix directory permissions for installation');
114
- console.log(' perm-check Check current directory permissions');
115
- console.log(' skill <action> Manage skills across CLIs (install/read/list/sync/remove)');
116
- console.log(' skill-i <src> Install skills (shortcut for: skill install)');
117
- console.log(' skill-l List skills (shortcut for: skill list)');
118
- console.log(' skill-r <name> Read skill (shortcut for: skill read)');
119
- console.log(' skill-v <name> View/validate skill (auto-detect read or validate)');
120
- console.log(' skill-d <name> Delete/remove skill (shortcut for: skill remove)');
121
- console.log(' skill Sync skills to all CLI configs (shortcut for: skill sync)');
122
- console.log(' call "<prompt>" Execute prompt with auto-routed AI CLI');
123
- console.log(' <tool> "<prompt>" Directly route to specific AI CLI tool');
124
- console.log(' Supported tools: claude, gemini, qwen, iflow, qodercli, codebuddy, copilot, codex');
125
- console.log('');
126
-
127
- console.log('[QUICK START] Getting Started:');
128
- console.log(' 1. npm install -g stigmergy # Install Stigmergy (auto-cleans cache)');
129
- console.log(' 2. stigmergy d # System diagnostic');
130
- console.log(' 3. stigmergy inst # Install missing AI CLI tools');
131
- console.log(' 4. stigmergy deploy # Deploy hooks for CLI integration');
132
-
133
- console.log('');
134
- console.log(
135
- 'For more information, visit: https://github.com/ptreezh/stigmergy-CLI-Multi-Agents',
136
- );
137
- return;
138
- }
139
-
140
- const command = args[0];
141
-
142
- switch (command) {
143
- case 'version':
144
- case '--version': {
145
- // Use the version from package.json instead of hardcoding
146
- const packageJson = require('../../package.json');
147
- console.log(`Stigmergy CLI v${packageJson.version}`);
148
- break;
149
- }
150
-
151
- case 'errors':
152
- try {
153
- console.log('[ERRORS] Generating Stigmergy CLI error report...\n');
154
- await errorHandler.printErrorReport();
155
- } catch (error) {
156
- console.error(
157
- '[ERROR] Failed to generate error report:',
158
- error.message,
159
- );
160
- process.exit(1);
161
- }
162
- break;
163
-
164
- case 'init':
165
- try {
166
- console.log('[INIT] Initializing Stigmergy project in current directory...\n');
167
-
168
- // Quick path detection for better tool availability
169
- console.log('[INIT] Detecting CLI tool paths...');
170
- const pathSetup = await setupCLIPaths();
171
-
172
- console.log(`[INIT] CLI tool detection: ${pathSetup.report.summary.found}/${pathSetup.report.summary.total} tools found`);
173
-
174
- // Initialize project files in current directory
175
- await installer.createProjectFiles();
176
-
177
- console.log('[INIT] Project initialization completed successfully!');
178
- console.log('\n[INFO] Created:');
179
- console.log(' - PROJECT_SPEC.json (project specification)');
180
- console.log(' - PROJECT_CONSTITUTION.md (collaboration guidelines)');
181
- console.log(' - CLI path detection cache in ~/.stigmergy/cli-paths/');
182
-
183
- if (pathSetup.report.summary.missing > 0) {
184
- console.log('\n[INFO] For full CLI integration, run:');
185
- console.log(' stigmergy setup # Complete setup with PATH configuration');
186
- }
187
- } catch (error) {
188
- await errorHandler.logError(error, 'ERROR', 'main.init');
189
- console.log(`[ERROR] Project initialization failed: ${error.message}`);
190
- process.exit(1);
191
- }
192
- break;
193
-
194
- case 'setup':
195
- try {
196
- console.log('[SETUP] Starting complete Stigmergy setup...\n');
197
-
198
- // Step 0: Setup CLI paths detection and configuration
199
- console.log('[STEP 0] Setting up CLI path detection...');
200
- const pathSetup = await setupCLIPaths();
201
-
202
- console.log(`[PATH] Path detection complete:`);
203
- console.log(` - Found: ${pathSetup.report.summary.found} CLI tools`);
204
- console.log(` - Missing: ${pathSetup.report.summary.missing} CLI tools`);
205
-
206
- if (pathSetup.pathStatus.updated) {
207
- console.log('\n[PATH] ✓ All npm global directories are now available in PATH');
208
- console.log('[PATH] CLI tools will be globally accessible after terminal restart');
209
- } else {
210
- console.log('\n[PATH] ⚠️ PATH update failed:');
211
- console.log(` Error: ${pathSetup.pathStatus.message}`);
212
- console.log('\n[PATH] Manual update required:');
213
- console.log(' Run the generated scripts to update PATH:');
214
- if (pathSetup.pathStatus.scriptPath) {
215
- console.log(` - Script directory: ${pathSetup.pathStatus.scriptPath}`);
216
- }
217
- console.log(' - Windows: Run PowerShell as Administrator and execute the scripts');
218
- console.log(' - Unix/Linux: Source the shell script (source update-path.sh)');
219
- }
220
-
221
- // Step 1: Scan for CLI tools
222
- console.log('\n[STEP 1] Scanning for AI CLI tools...');
223
- const { available: setupAvailable, missing: setupMissing } =
224
- await installer.scanCLI();
225
-
226
- // Step 2: Install missing CLI tools
227
- if (Object.keys(setupMissing).length > 0) {
228
- console.log('\n[STEP 2] Installing missing tools...');
229
- console.log('[INFO] Missing tools found:');
230
- for (const [toolName, toolInfo] of Object.entries(setupMissing)) {
231
- console.log(` - ${toolInfo.name}: ${toolInfo.install}`);
232
- }
233
-
234
- console.log('\n[INFO] To install missing tools, run:');
235
- for (const [toolName, toolInfo] of Object.entries(setupMissing)) {
236
- console.log(` ${toolInfo.install}`);
237
- }
238
-
239
- console.log('\n[INFO] Or use the enhanced installer:');
240
- console.log(' node src/core/enhanced_installer.js');
241
- } else {
242
- console.log('\n[STEP 2] All required tools are already installed!');
243
- }
244
-
245
- // Step 3: Deploy hooks to available CLI tools
246
- if (Object.keys(setupAvailable).length > 0) {
247
- console.log('\n[STEP 3] Deploying hooks to available tools...');
248
- await installer.deployHooks(setupAvailable);
249
- } else {
250
- console.log('\n[STEP 3] No tools available for hook deployment');
251
- }
252
-
253
- console.log('\n🎉 Setup completed successfully!');
254
- console.log('\n[USAGE] Get started with these commands:');
255
- console.log(' stigmergy d - System diagnostic (recommended first)');
256
- console.log(' stigmergy inst - Install missing AI CLI tools');
257
- console.log(' stigmergy deploy - Deploy hooks to installed tools');
258
- console.log(' stigmergy call - Execute prompts with auto-routing');
259
-
260
- } catch (error) {
261
- console.error('[ERROR] Setup failed:', error.message);
262
- if (process.env.DEBUG === 'true') {
263
- console.error(error.stack);
264
- }
265
- console.log('\n[TROUBLESHOOTING] To manually complete setup:');
266
- console.log('1. Run: stigmergy deploy # Deploy hooks manually');
267
- console.log('2. Run: stigmergy setup # Try setup again');
268
- process.exit(1);
269
- }
270
- break;
271
-
272
- case 'status':
273
- try {
274
- const { available, missing } = await installer.scanCLI();
275
- console.log('\n[STATUS] AI CLI Tools Status Report');
276
- console.log('=====================================');
277
-
278
- if (Object.keys(available).length > 0) {
279
- console.log('\n✅ Available Tools:');
280
- for (const [toolName, toolInfo] of Object.entries(available)) {
281
- console.log(` - ${toolInfo.name} (${toolName})`);
282
- }
283
- }
284
-
285
- if (Object.keys(missing).length > 0) {
286
- console.log('\n❌ Missing Tools:');
287
- for (const [toolName, toolInfo] of Object.entries(missing)) {
288
- console.log(` - ${toolInfo.name} (${toolName})`);
289
- console.log(` Install command: ${toolInfo.install}`);
290
- }
291
- }
292
-
293
- console.log(
294
- `\n[SUMMARY] ${Object.keys(available).length} available, ${Object.keys(missing).length} missing`,
295
- );
296
- } catch (error) {
297
- await errorHandler.logError(error, 'ERROR', 'main.status');
298
- console.log(`[ERROR] Failed to get status: ${error.message}`);
299
- process.exit(1);
300
- }
301
- break;
302
-
303
- case 'scan':
304
- try {
305
- await installer.scanCLI();
306
- } catch (error) {
307
- await errorHandler.logError(error, 'ERROR', 'main.scan');
308
- console.log(`[ERROR] Failed to scan CLI tools: ${error.message}`);
309
- process.exit(1);
310
- }
311
- break;
312
-
313
- case 'upgrade': {
314
- try {
315
- console.log('[UPGRADE] Starting AI CLI tools upgrade process...\n');
316
-
317
- // 解析命令行选项
318
- const upgradeArgs = args.slice(1);
319
- const options = {
320
- dryRun: upgradeArgs.includes('--dry-run'),
321
- force: upgradeArgs.includes('--force'),
322
- verbose: upgradeArgs.includes('--verbose')
323
- };
324
-
325
- // 使用EnhancedCLIInstaller进行升级
326
- const EnhancedCLIInstaller = require(path.resolve(__dirname, '../core/enhanced_cli_installer'));
327
- const enhancedInstaller = new EnhancedCLIInstaller({
328
- verbose: process.env.DEBUG === 'true' || options.verbose,
329
- autoRetry: true,
330
- maxRetries: 2
331
- });
332
-
333
- // 获取已安装的工具列表 - 使用全局installer扫描
334
- const { available: installedTools } = await installer.scanCLI();
335
-
336
- if (Object.keys(installedTools).length === 0) {
337
- console.log('[INFO] No AI CLI tools found. Please install tools first with: stigmergy install');
338
- break;
339
- }
340
-
341
- console.log(`[INFO] Found ${Object.keys(installedTools).length} installed AI CLI tools:`);
342
- for (const [toolName, toolInfo] of Object.entries(installedTools)) {
343
- console.log(` - ${toolInfo.name} (${toolName})`);
344
- }
345
-
346
- if (options.dryRun) {
347
- console.log('\n🔍 DRY RUN MODE - No changes will be made');
348
- console.log(' Use --force to execute the upgrade');
349
- break;
350
- }
351
-
352
- // 默认直接执行升级,无需用户确认
353
- console.log(`\n[UPGRADE] Upgrading ${Object.keys(installedTools).length} AI CLI tools...`);
354
- console.log('[INFO] Use --dry-run to preview upgrades without executing');
355
-
356
- console.log('\n🚀 Upgrading AI CLI tools with automatic permission handling...\n');
357
-
358
- // 批量升级所有工具,一次权限检测
359
- console.log(`[INFO] Starting batch upgrade of ${Object.keys(installedTools).length} tools...`);
360
-
361
- const upgradeToolInfos = {};
362
- for (const [toolName, toolInfo] of Object.entries(installedTools)) {
363
- upgradeToolInfos[toolName] = {
364
- ...toolInfo,
365
- install: `npm upgrade -g ${toolName}`,
366
- name: `${toolInfo.name} (Upgrade)`
367
- };
368
- }
369
-
370
- const upgradeResult = await enhancedInstaller.upgradeTools(
371
- Object.keys(installedTools),
372
- upgradeToolInfos
373
- );
374
-
375
- // 整理结果
376
- const results = {
377
- successful: [],
378
- failed: [],
379
- permissionHandled: []
380
- };
381
-
382
- for (const [toolName, installation] of Object.entries(upgradeResult.results.installations || {})) {
383
- if (installation.success) {
384
- results.successful.push(toolName);
385
- if (installation.permissionHandled) {
386
- results.permissionHandled.push(toolName);
387
- }
388
- } else {
389
- results.failed.push({
390
- tool: toolName,
391
- error: installation.error || 'Installation failed'
392
- });
393
- }
394
- }
395
-
396
- // 显示结果
397
- console.log('\n📊 UPGRADE RESULTS');
398
- console.log('='.repeat(50));
399
-
400
- if (results.successful.length > 0) {
401
- console.log(`\n✅ Successful (${results.successful.length}):`);
402
- results.successful.forEach(tool => {
403
- console.log(` • ${tool}`);
404
- });
405
- }
406
-
407
- if (results.permissionHandled.length > 0) {
408
- console.log(`\n🔧 Auto-handled permissions (${results.permissionHandled.length}):`);
409
- results.permissionHandled.forEach(tool => {
410
- console.log(` • ${tool}`);
411
- });
412
- }
413
-
414
- if (results.failed.length > 0) {
415
- console.log(`\n❌ Failed (${results.failed.length}):`);
416
- results.failed.forEach(result => {
417
- console.log(` • ${result.tool}: ${result.error}`);
418
- });
419
-
420
- // Provide guidance for permission issues
421
- if (results.failed.length > 0) {
422
- console.log('\n💡 如果遇到权限问题,请尝试:');
423
- console.log(' Windows: 以管理员身份运行PowerShell,然后执行 stigmergy upgrade');
424
- console.log(' macOS/Linux: sudo stigmergy upgrade');
425
- }
426
- }
427
-
428
- if (results.permissionHandled.length > 0) {
429
- console.log('\n✅ 权限问题已自动处理');
430
- console.log(`🔧 自动提升权限升级了 ${results.permissionHandled.length} 个工具`);
431
- }
432
-
433
- console.log('\n🎉 Upgrade process completed!');
434
-
435
- } catch (error) {
436
- console.error('[ERROR] Upgrade failed:', error.message);
437
- if (process.env.DEBUG === 'true') {
438
- console.error(error.stack);
439
- }
440
- process.exit(1);
441
- }
442
- break;
443
- }
444
-
445
- case 'install':
446
- case 'inst':
447
- try {
448
- console.log('[INSTALL] Starting AI CLI tools installation...');
449
-
450
- // Check directory permissions first
451
- const permissionManager = new DirectoryPermissionManager({ verbose: process.env.DEBUG === 'true' });
452
- const hasWritePermission = await permissionManager.checkWritePermission();
453
-
454
- if (!hasWritePermission) {
455
- console.log('\n⚠️ Current directory lacks write permission');
456
- console.log('🔧 Using permission-aware installation...');
457
-
458
- // Use permission-aware installer
459
- const permAwareInstaller = new PermissionAwareInstaller({
460
- verbose: process.env.DEBUG === 'true',
461
- skipPermissionCheck: false
462
- });
463
-
464
- const result = await permAwareInstaller.install();
465
- if (result.success) {
466
- console.log('\n✅ Permission-aware installation completed successfully!');
467
- } else {
468
- console.log('\n❌ Permission-aware installation failed');
469
- process.exit(1);
470
- }
471
- break;
472
- }
473
-
474
- // Normal installation if directory has write permission
475
- const { missing: missingTools, available: availableTools } = await installer.scanCLI();
476
-
477
- if (Object.keys(missingTools).length === 0) {
478
- console.log('[INFO] All AI CLI tools are already installed!');
479
- console.log('\nAvailable tools:');
480
- for (const [toolName, toolInfo] of Object.entries(availableTools)) {
481
- console.log(` - ${toolInfo.name} (${toolName})`);
482
- }
483
- } else {
484
- console.log(`\n[INFO] Found ${Object.keys(missingTools).length} missing AI CLI tools:`);
485
- for (const [toolName, toolInfo] of Object.entries(missingTools)) {
486
- console.log(` - ${toolInfo.name}: ${toolInfo.install}`);
487
- }
488
-
489
- // 默认自动安装所有缺失的工具
490
- console.log(`\n[AUTO-INSTALL] Installing ${Object.keys(missingTools).length} missing AI CLI tools...`);
491
-
492
- const selectedTools = Object.keys(missingTools);
493
-
494
- // Use EnhancedCLIInstaller with batch permission handling
495
- const EnhancedCLIInstaller = require(path.resolve(__dirname, '../core/enhanced_cli_installer'));
496
- const installer = new EnhancedCLIInstaller({
497
- verbose: process.env.DEBUG === 'true',
498
- autoRetry: true,
499
- maxRetries: 2
500
- });
501
-
502
- console.log(`[INFO] Installing ${selectedTools.length} CLI tools with optimized permission handling...`);
503
- const installResult = await installer.installTools(selectedTools, missingTools);
504
-
505
- if (installResult) {
506
- console.log(`\n[SUCCESS] Installed ${selectedTools.length} AI CLI tools!`);
507
-
508
- // Check if any permissions were handled automatically
509
- const installations = installer.results.installations || {};
510
- const permissionHandledTools = Object.entries(installations)
511
- .filter(([name, result]) => result.success && result.permissionHandled)
512
- .map(([name]) => name);
513
-
514
- if (permissionHandledTools.length > 0) {
515
- console.log('✅ 权限问题已自动处理');
516
- console.log(`🔧 自动提升权限安装了 ${permissionHandledTools.length} 个工具: ${permissionHandledTools.join(', ')}`);
517
- }
518
-
519
- // Show permission mode used
520
- console.log(`🔧 权限模式: ${installResult.permissionMode}`);
521
- } else {
522
- console.log('\n[WARN] Some tools may not have installed successfully. Check the logs above for details.');
523
-
524
- // Provide manual guidance for permission issues
525
- const failedInstallations = installer.results.failedInstallations || [];
526
- if (failedInstallations.length > 0) {
527
- console.log('\n💡 如果遇到权限问题,请尝试:');
528
- console.log(' Windows: 以管理员身份运行PowerShell,然后执行 stigmergy install');
529
- console.log(' macOS/Linux: sudo stigmergy install');
530
- }
531
- }
532
- }
533
-
534
- console.log('\n[INFO] Installation process completed.');
535
- } catch (error) {
536
- console.error('[ERROR] Installation failed:', error.message);
537
- if (process.env.DEBUG === 'true') {
538
- console.error(error.stack);
539
- }
540
- process.exit(1);
541
- }
542
- break;
543
-
544
- case 'deploy':
545
- try {
546
- const { available: deployedTools } = await installer.scanCLI();
547
- await installer.deployHooks(deployedTools);
548
- } catch (error) {
549
- await errorHandler.logError(error, 'ERROR', 'main.deploy');
550
- console.log(`[ERROR] Deployment failed: ${error.message}`);
551
- process.exit(1);
552
- }
553
- break;
554
-
555
- case 'call': {
556
- if (args.length < 2) {
557
- console.log('[ERROR] Usage: stigmergy call "<prompt>"');
558
- process.exit(1);
559
- }
560
-
561
- // Get the prompt (everything after the command)
562
- const prompt = args.slice(1).join(' ');
563
-
564
- // Use smart router to determine which tool to use
565
- const router = new SmartRouter();
566
- await router.initialize(); // Initialize the router first
567
- const route = await router.smartRoute(prompt);
568
-
569
- console.log(`[CALL] Routing to ${route.tool}: ${route.prompt}`);
570
-
571
- // Execute the routed command
572
- try {
573
- // Get the actual executable path for the tool using which/where command
574
- let toolPath = route.tool;
575
- try {
576
- const whichCmd = process.platform === 'win32' ? 'where' : 'which';
577
- const whichResult = spawnSync(whichCmd, [route.tool], {
578
- encoding: 'utf8',
579
- timeout: 10000,
580
- stdio: ['pipe', 'pipe', 'pipe'],
581
- shell: true,
582
- });
583
-
584
- if (whichResult.status === 0 && whichResult.stdout.trim()) {
585
- // Get the first match (most likely the one that would be executed)
586
- toolPath = whichResult.stdout.trim().split('\n')[0].trim();
587
- }
588
- } catch (whichError) {
589
- // If which/where fails, continue with the tool name
590
- if (process.env.DEBUG === 'true') {
591
- console.log(`[DEBUG] which/where command failed for ${route.tool}: ${whichError.message}`);
592
- }
593
- }
594
-
595
- // SPECIAL TEST CASE: Simulate a non-existent tool for testing
596
- // This is for demonstration purposes only
597
- /*
598
- if (route.tool === "nonexistenttool") {
599
- toolPath = "this_tool_definitely_does_not_exist_12345";
600
- }
601
- */
602
-
603
- console.log(
604
- `[DEBUG] Tool path: ${toolPath}, Prompt: ${route.prompt}`,
605
- );
606
-
607
- // For different tools, we need to pass the prompt differently
608
- // Use unified parameter handler for better parameter handling
609
- let toolArgs = [];
610
-
611
- try {
612
- // Get CLI pattern for this tool
613
- const cliPattern = await router.analyzer.getCLIPattern(route.tool);
614
-
615
- // Log the CLI pattern to debug command format issues
616
- if (process.env.DEBUG === 'true' && cliPattern) {
617
- console.log(`[DEBUG] CLI Pattern for ${route.tool}:`, JSON.stringify(cliPattern, null, 2));
618
- }
619
-
620
- // Use the unified CLI parameter handler
621
- const CLIParameterHandler = require('../core/cli_parameter_handler');
622
- toolArgs = CLIParameterHandler.generateArguments(
623
- route.tool,
624
- route.prompt,
625
- cliPattern,
626
- );
627
- } catch (patternError) {
628
- // Fallback to original logic if pattern analysis fails
629
- if (route.tool === 'claude') {
630
- // Claude CLI expects the prompt with -p flag for non-interactive mode
631
- toolArgs = ['-p', `"${route.prompt}"`];
632
- } else if (route.tool === 'qodercli' || route.tool === 'iflow') {
633
- // Qoder CLI and iFlow expect the prompt with -p flag
634
- toolArgs = ['-p', `"${route.prompt}"`];
635
- } else if (route.tool === 'codex') {
636
- // Codex CLI needs 'exec' subcommand for non-interactive mode
637
- toolArgs = ['exec', '-p', `"${route.prompt}"`];
638
- } else {
639
- // For other tools, pass the prompt with -p flag
640
- toolArgs = ['-p', `"${route.prompt}"`];
641
- }
642
- }
643
-
644
- // Use the reliable cross-platform execution function
645
- try {
646
- // Validate that the tool exists before attempting to execute
647
- if (!toolPath || typeof toolPath !== 'string') {
648
- throw new Error(`Invalid tool path: ${toolPath}`);
649
- }
650
-
651
- // Special handling for JS files to ensure proper execution
652
- if (toolPath.endsWith('.js') || toolPath.endsWith('.cjs')) {
653
- // Use safe JS file execution
654
- if (process.env.DEBUG === 'true') {
655
- console.log(
656
- `[EXEC] Safely executing JS file: ${toolPath} ${toolArgs.join(' ')}`,
657
- );
658
- }
659
- const result = await executeJSFile(toolPath, toolArgs, {
660
- stdio: 'inherit',
661
- shell: true,
662
- });
663
-
664
- if (!result.success) {
665
- console.log(
666
- `[WARN] ${route.tool} exited with code ${result.code}`,
667
- );
668
- }
669
- process.exit(result.code || 0);
670
- } else {
671
- // Regular command execution
672
- if (process.env.DEBUG === 'true') {
673
- console.log(`[EXEC] Running: ${toolPath} ${toolArgs.join(' ')}`);
674
- }
675
-
676
- // Special handling for Windows to construct the command properly
677
- let execCommand = toolPath;
678
- let execArgs = toolArgs;
679
- if (process.platform === 'win32') {
680
- // On Windows, we construct the full command line and pass it as a single string
681
- if (toolArgs.length > 0) {
682
- // For Windows, we need to properly quote the entire command line
683
- const argsString = toolArgs.map(arg => {
684
- // If arg contains spaces and is not already quoted, quote it
685
- if (arg.includes(' ') && !(arg.startsWith('"') && arg.endsWith('"'))) {
686
- return `"${arg}"`;
687
- }
688
- return arg;
689
- }).join(' ');
690
- execCommand = `${toolPath} ${argsString}`;
691
- execArgs = [];
692
- console.log(`[DEBUG] Windows full command: ${execCommand}`);
693
- }
694
- }
695
-
696
- // Special handling for Claude on Windows to bypass the wrapper script
697
- if (process.platform === 'win32' && route.tool === 'claude') {
698
- // Use detected path to avoid the wrapper script that interferes with parameter passing
699
- const detectedPath = await getCLIPath('claude');
700
- if (detectedPath) {
701
- execCommand = detectedPath;
702
- console.log(`[DEBUG] Using detected Claude path: ${execCommand}`);
703
- } else {
704
- execCommand = 'C:\\npm_global\\claude';
705
- console.log(`[DEBUG] Using default Claude path: ${execCommand}`);
706
- }
707
-
708
- if (toolArgs.length > 0) {
709
- const argsString = toolArgs.map(arg => {
710
- if (arg.includes(' ') && !(arg.startsWith('"') && arg.endsWith('"'))) {
711
- return `"${arg}"`;
712
- }
713
- return arg;
714
- }).join(' ');
715
- execCommand = `${execCommand} ${argsString}`;
716
- execArgs = [];
717
- console.log(`[DEBUG] Windows direct Claude command: ${execCommand}`);
718
- }
719
- }
720
-
721
- // Use detected paths for all CLI tools on all platforms
722
- const supportedTools = ['claude', 'copilot', 'qodercli', 'gemini', 'qwen', 'iflow', 'codebuddy', 'codex'];
723
-
724
- if (supportedTools.includes(route.tool)) {
725
- // Use detected path for all CLI tools regardless of platform
726
- const detectedPath = await getCLIPath(route.tool);
727
- if (detectedPath) {
728
- execCommand = detectedPath;
729
- console.log(`[DEBUG] Using detected ${route.tool} path: ${execCommand}`);
730
- } else {
731
- // Fallback to system PATH for tools not detected
732
- console.log(`[DEBUG] Using system PATH for ${route.tool}: ${route.tool}`);
733
- }
734
- }
735
-
736
- // Platform-specific command construction
737
- if (process.platform === 'win32') {
738
- // Special handling for Windows CLI tools
739
- if (route.tool === 'claude' && toolArgs.length > 0) {
740
- // Special parameter handling for Claude to avoid wrapper script issues
741
- const argsString = toolArgs.map(arg => {
742
- if (arg.includes(' ') && !(arg.startsWith('"') && arg.endsWith('"'))) {
743
- return `"${arg}"`;
744
- }
745
- return arg;
746
- }).join(' ');
747
- execCommand = `${execCommand} ${argsString}`;
748
- execArgs = [];
749
- console.log(`[DEBUG] Windows ${route.tool} direct command: ${execCommand}`);
750
- } else if (route.tool === 'copilot') {
751
- // Copilot doesn't use -p parameter format
752
- execArgs = [];
753
- console.log(`[DEBUG] Windows ${route.tool} direct command: ${execCommand}`);
754
- } else if (toolArgs.length > 0) {
755
- // For other Windows tools, construct full command line
756
- const argsString = toolArgs.map(arg => {
757
- if (arg.includes(' ') && !(arg.startsWith('"') && arg.endsWith('"'))) {
758
- return `"${arg}"`;
759
- }
760
- return arg;
761
- }).join(' ');
762
- execCommand = `${execCommand} ${argsString}`;
763
- execArgs = [];
764
- console.log(`[DEBUG] Windows full command: ${execCommand}`);
765
- }
766
- }
767
-
768
- // Apply the same Windows handling logic to ensure consistency
769
- // This ensures consistency between direct routing and call command routing
770
- if (process.platform === 'win32' && execArgs.length > 0) {
771
- // For Windows, we need to properly quote the entire command line
772
- const argsString = execArgs.map(arg => {
773
- // If arg contains spaces and is not already quoted, quote it
774
- if (arg.includes(' ') && !(arg.startsWith('"') && arg.endsWith('"'))) {
775
- return `"${arg}"`;
776
- }
777
- return arg;
778
- }).join(' ');
779
- execCommand = `${execCommand} ${argsString}`;
780
- execArgs = [];
781
- console.log(`[DEBUG] Windows unified command: ${execCommand}`);
782
- }
783
-
784
- // Set environment for tools that need specific working directories
785
- const env = { ...process.env };
786
- if (route.tool === 'qwen') {
787
- // For Qwen CLI, clear NODE_PATH to avoid import conflicts
788
- delete env.NODE_PATH;
789
- }
790
-
791
- const result = await executeCommand(execCommand, execArgs, {
792
- stdio: 'inherit',
793
- shell: true,
794
- cwd: getWorkingDirectoryForTool(route.tool),
795
- env,
796
- });
797
-
798
- if (!result.success) {
799
- console.log(
800
- `[WARN] ${route.tool} exited with code ${result.code}`,
801
- );
802
- }
803
- process.exit(result.code || 0);
804
- }
805
- } catch (executionError) {
806
- // Check for specific errors that might not be actual failures
807
- const errorMessage = executionError.error?.message || executionError.message || executionError;
808
-
809
- // For some tools like Claude, they may output to stdout and return non-zero codes
810
- // without actually failing - handle these cases more gracefully
811
- if (errorMessage.includes('not recognized as an internal or external command') ||
812
- errorMessage.includes('command not found') ||
813
- errorMessage.includes('ENOENT')) {
814
- // This is a genuine error - tool is not installed
815
- const cliError = await errorHandler.handleCLIError(
816
- route.tool,
817
- executionError.error || executionError,
818
- toolArgs.join(' '),
819
- );
820
-
821
- // Provide clear ANSI English error message
822
- console.log('==================================================');
823
- console.log('ERROR: Failed to execute AI CLI tool');
824
- console.log('==================================================');
825
- console.log(`Tool: ${route.tool}`);
826
- console.log(`Error: ${cliError.message}`);
827
- if (executionError.stderr) {
828
- console.log(`Stderr: ${executionError.stderr}`);
829
- }
830
- console.log('');
831
- console.log('Possible solutions:');
832
- console.log('1. Check if the AI CLI tool is properly installed');
833
- console.log('2. Verify the tool is in your system PATH');
834
- console.log('3. Try reinstalling the tool with: stigmergy install');
835
- console.log('4. Run stigmergy status to check tool availability');
836
- console.log('');
837
- console.log('For manual execution, you can run:');
838
- console.log(`${toolPath} ${toolArgs.join(' ')}`);
839
- console.log('==================================================');
840
- process.exit(1);
841
- } else {
842
- // For other execution errors, try to execute the command directly
843
- // which handles cases where the tool executed successfully but returned an error object
844
- console.log(`[EXEC] Running: ${toolPath} ${toolArgs.join(' ')}`);
845
- // Set environment for tools that need specific working directories
846
- const env = { ...process.env };
847
- if (route.tool === 'qwen') {
848
- delete env.NODE_PATH;
849
- }
850
-
851
- const result = await executeCommand(toolPath, toolArgs, {
852
- stdio: 'inherit',
853
- shell: true,
854
- cwd: getWorkingDirectoryForTool(route.tool),
855
- env,
856
- });
857
-
858
- if (!result.success) {
859
- console.log(`[WARN] ${route.tool} exited with code ${result.code}`);
860
- }
861
- process.exit(result.code || 0);
862
- }
863
- }
864
- } catch (error) {
865
- const cliError = await errorHandler.handleCLIError(
866
- route.tool,
867
- error,
868
- prompt,
869
- );
870
- console.log(
871
- `[ERROR] Failed to execute ${route.tool}:`,
872
- cliError.message,
873
- );
874
- process.exit(1);
875
- }
876
- break;
877
- }
878
-
879
- case 'auto-install':
880
- // Auto-install mode for npm postinstall - NON-INTERACTIVE with permission awareness
881
- // Force immediate output visibility during npm install
882
-
883
- // Detect npm environment for better output visibility
884
- const isNpmPostinstall = process.env.npm_lifecycle_event === 'postinstall';
885
-
886
- // Use stderr for critical messages in npm environment (more likely to be shown)
887
- const criticalLog = isNpmPostinstall ? console.error : console.log;
888
-
889
- criticalLog('🚀 STIGMERGY CLI AUTO-INSTALL STARTING');
890
- criticalLog('='.repeat(60));
891
- criticalLog('Installing cross-CLI integration and scanning for AI tools...');
892
- criticalLog('='.repeat(60));
893
- console.log('[AUTO-INSTALL] Stigmergy CLI automated setup');
894
- console.log('='.repeat(60));
895
-
896
- // Check directory permissions
897
- const autoPermissionManager = new DirectoryPermissionManager({ verbose: process.env.DEBUG === 'true' });
898
- const autoHasWritePermission = await autoPermissionManager.checkWritePermission();
899
-
900
- if (!autoHasWritePermission && !process.env.STIGMERGY_SKIP_PERMISSION_CHECK) {
901
- criticalLog('⚠️ Directory permission detected, setting up permission-aware installation...');
902
-
903
- try {
904
- const permResult = await autoPermissionManager.setupWorkingDirectory();
905
- if (permResult.success) {
906
- criticalLog('✅ Working directory configured with proper permissions');
907
- } else {
908
- criticalLog('⚠️ Could not configure working directory, continuing with limited functionality');
909
- }
910
- } catch (error) {
911
- criticalLog(`⚠️ Permission setup failed: ${error.message}`);
912
- }
913
- }
914
-
915
- // Force stdout flush to ensure visibility during npm install
916
- if (process.stdout && process.stdout.write) {
917
- process.stdout.write('');
918
- if (process.stdout.flush) {
919
- process.stdout.flush();
920
- }
921
- }
922
-
923
- // Add a small delay to ensure output is visible
924
- await new Promise(resolve => setTimeout(resolve, 100));
925
-
926
- try {
927
- // Step 1: Download required assets
928
- try {
929
- console.log('[STEP] Downloading required assets...');
930
- // Force flush to ensure visibility
931
- if (process.stdout.flush) process.stdout.flush();
932
-
933
- await installer.downloadRequiredAssets();
934
- console.log('[OK] Assets downloaded successfully');
935
- if (process.stdout.flush) process.stdout.flush();
936
- } catch (error) {
937
- console.log(`[WARN] Failed to download assets: ${error.message}`);
938
- console.log('[INFO] Continuing with installation...');
939
- if (process.stdout.flush) process.stdout.flush();
940
- }
941
-
942
- // Step 2: Scan for CLI tools
943
- let autoAvailable = {},
944
- autoMissing = {};
945
- try {
946
- console.log('[STEP] Scanning for CLI tools...');
947
- if (process.stdout.flush) process.stdout.flush();
948
-
949
- const scanResult = await installer.scanCLI();
950
- autoAvailable = scanResult.available;
951
- autoMissing = scanResult.missing;
952
- console.log('[OK] CLI tools scanned successfully');
953
- if (process.stdout.flush) process.stdout.flush();
954
- } catch (error) {
955
- console.log(`[WARN] Failed to scan CLI tools: ${error.message}`);
956
- console.log('[INFO] Continuing with installation...');
957
- if (process.stdout.flush) process.stdout.flush();
958
- }
959
-
960
- // Step 4: Show usage instructions using existing scan results
961
- try {
962
- console.log('\n' + '='.repeat(60));
963
- console.log('[SUCCESS] Stigmergy CLI installation completed!');
964
- console.log('='.repeat(60));
965
-
966
- console.log(`\n[SCAN RESULT] Found ${Object.keys(autoAvailable).length} available AI CLI tools:`);
967
-
968
- if (Object.keys(autoAvailable).length > 0) {
969
- for (const [toolName, toolInfo] of Object.entries(autoAvailable)) {
970
- const status = toolInfo.installed ? '✓ Installed' : '✗ Not Installed';
971
- console.log(` ✓ ${toolInfo.name} (${toolName}) - ${status}`);
972
- if (toolInfo.path) {
973
- console.log(` Path: ${toolInfo.path}`);
974
- }
975
- if (toolInfo.version) {
976
- console.log(` Version: ${toolInfo.version}`);
977
- }
978
- }
979
- } else {
980
- console.log(' [INFO] No AI CLI tools found on your system');
981
- }
982
-
983
- if (Object.keys(autoMissing).length > 0) {
984
- console.log(`\n[MISSING] ${Object.keys(autoMissing).length} tools not found:`);
985
- for (const [toolName, toolInfo] of Object.entries(autoMissing)) {
986
- console.log(` ✗ ${toolInfo.name} (${toolName})`);
987
- console.log(` Install with: ${toolInfo.installCommand}`);
988
- }
989
-
990
- // Check if auto-install is enabled for npm postinstall
991
- const autoInstallEnabled = process.env.STIGMERGY_AUTO_INSTALL !== 'false';
992
-
993
- if (autoInstallEnabled && !process.env.CI) {
994
- console.log('\n[AUTO-INSTALL] Installing missing CLI tools automatically...');
995
- console.log('[INFO] Set STIGMERGY_AUTO_INSTALL=false to disable this behavior');
996
-
997
- try {
998
- const selectedTools = Object.keys(autoMissing);
999
-
1000
- // Use EnhancedCLIInstaller with batch permission handling
1001
- const EnhancedCLIInstaller = require(path.resolve(__dirname, '../core/enhanced_cli_installer'));
1002
- const installer = new EnhancedCLIInstaller({
1003
- verbose: process.env.DEBUG === 'true',
1004
- autoRetry: true,
1005
- maxRetries: 2
1006
- });
1007
-
1008
- console.log(`[INFO] Installing ${selectedTools.length} CLI tools with optimized permission handling...`);
1009
- const installResult = await installer.installTools(selectedTools, autoMissing);
1010
-
1011
- if (installResult) {
1012
- console.log(`[SUCCESS] Auto-installed ${selectedTools.length} CLI tools!`);
1013
-
1014
- // Check if permissions were handled automatically
1015
- const installations = installer.results.installations || {};
1016
- const permissionHandledTools = Object.entries(installations)
1017
- .filter(([name, result]) => result.success && result.permissionHandled)
1018
- .map(([name]) => name);
1019
-
1020
- if (permissionHandledTools.length > 0) {
1021
- console.log('✅ 权限问题已自动处理');
1022
- console.log(`🔧 自动提升权限安装了 ${permissionHandledTools.length} 个工具: ${permissionHandledTools.join(', ')}`);
1023
- }
1024
-
1025
- // Show permission mode used
1026
- console.log(`🔧 权限模式: ${installResult.permissionMode}`);
1027
- } else {
1028
- console.log('[WARN] Some tools may not have installed successfully');
1029
-
1030
- // Provide manual guidance for permission issues
1031
- const failedInstallations = installer.results.failedInstallations || [];
1032
- if (failedInstallations.length > 0) {
1033
- console.log('\n💡 如果遇到权限问题,请尝试:');
1034
- console.log(' Windows: 以管理员身份运行PowerShell,然后执行 stigmergy install');
1035
- console.log(' macOS/Linux: sudo stigmergy install');
1036
- }
1037
- }
1038
- } catch (installError) {
1039
- console.log(`[ERROR] Auto-install failed: ${installError.message}`);
1040
- console.log('[INFO] You can manually install tools with: stigmergy install --auto');
1041
-
1042
- // Check if it's a permission error
1043
- const permissionIndicators = ['EACCES', 'EPERM', 'permission denied', 'access denied'];
1044
- const isPermissionError = permissionIndicators.some(indicator =>
1045
- installError.message.toLowerCase().includes(indicator.toLowerCase())
1046
- );
1047
-
1048
- if (isPermissionError) {
1049
- console.log('\n💡 这看起来像是权限问题,请尝试:');
1050
- console.log(' Windows: 以管理员身份运行PowerShell,然后执行 stigmergy install');
1051
- console.log(' macOS/Linux: sudo stigmergy install');
1052
- }
1053
- }
1054
- } else {
1055
- console.log('\n[INFO] You can install missing tools with: stigmergy install --auto');
1056
- if (process.env.CI) {
1057
- console.log('[CI] Auto-install disabled in CI environment');
1058
- }
1059
- }
1060
- }
1061
-
1062
- console.log('\n[USAGE] Get started with these commands:');
1063
- console.log(' stigmergy d - System diagnostic (recommended first)');
1064
- console.log(' stigmergy inst - Install missing CLI tools');
1065
- console.log(' stigmergy deploy - Deploy hooks for CLI integration');
1066
- console.log(' stigmergy c - Clean caches if needed');
1067
- console.log('\n[INFO] Stigmergy CLI enables collaboration between multiple AI CLI tools!');
1068
- console.log('[INFO] Try "stigmergy" to see all available commands and abbreviations.');
1069
-
1070
- } catch (error) {
1071
- console.log(`[WARN] Failed to show usage instructions: ${error.message}`);
1072
- if (process.stdout.flush) process.stdout.flush();
1073
- }
1074
-
1075
- // Step 4: Deploy hooks to available CLI tools (with Linux-specific error handling)
1076
- try {
1077
- console.log('[STEP] Deploying hooks to available CLI tools...');
1078
- if (process.stdout.flush) process.stdout.flush();
1079
-
1080
- await installer.deployHooks(autoAvailable);
1081
- console.log('[OK] Hooks deployed successfully');
1082
- if (process.stdout.flush) process.stdout.flush();
1083
- } catch (error) {
1084
- // Linux-specific error handling
1085
- const errorMessage = error.message || error.toString();
1086
- console.log(`[ERROR] Failed to deploy hooks: ${errorMessage}`);
1087
-
1088
- if (process.platform === 'linux') {
1089
- if (errorMessage.includes('EACCES') || errorMessage.includes('permission')) {
1090
- console.log('[LINUX-INFO] Permission denied. This may be normal if hooks are being placed in system directories.');
1091
- console.log('[LINUX-INFO] You can try running with sudo or check directory permissions.');
1092
- } else if (errorMessage.includes('ENOENT') || errorMessage.includes('no such file')) {
1093
- console.log('[LINUX-INFO] Some directories do not exist. This is normal for tools that are not installed.');
1094
- } else if (errorMessage.includes('EPERM')) {
1095
- console.log('[LINUX-INFO] Operation not permitted. This may be due to filesystem permissions.');
1096
- }
1097
- }
1098
-
1099
- console.log('[INFO] You can manually deploy hooks later by running: stigmergy deploy');
1100
- if (process.stdout.flush) process.stdout.flush();
1101
- }
1102
-
1103
- // Step 5: Deploy project documentation
1104
- try {
1105
- console.log('[STEP] Deploying project documentation...');
1106
- if (process.stdout.flush) process.stdout.flush();
1107
-
1108
- await installer.deployProjectDocumentation();
1109
- console.log('[OK] Documentation deployed successfully');
1110
- if (process.stdout.flush) process.stdout.flush();
1111
- } catch (error) {
1112
- console.log(
1113
- `[WARN] Failed to deploy documentation: ${error.message}`,
1114
- );
1115
- console.log('[INFO] Continuing with installation...');
1116
- if (process.stdout.flush) process.stdout.flush();
1117
- }
1118
-
1119
- // Step 6: Initialize configuration
1120
- try {
1121
- console.log('[STEP] Initializing configuration...');
1122
- if (process.stdout.flush) process.stdout.flush();
1123
-
1124
- await installer.initializeConfig();
1125
- console.log('[OK] Configuration initialized successfully');
1126
- if (process.stdout.flush) process.stdout.flush();
1127
- } catch (error) {
1128
- console.log(
1129
- `[ERROR] Failed to initialize configuration: ${error.message}`,
1130
- );
1131
- console.log(
1132
- '[INFO] You can manually initialize configuration later by running: stigmergy setup',
1133
- );
1134
- if (process.stdout.flush) process.stdout.flush();
1135
- }
1136
-
1137
- // Step 7: Show final message to guide users
1138
- console.log('\n[SUCCESS] Stigmergy CLI installed successfully!');
1139
- console.log(
1140
- '[USAGE] Run "stigmergy setup" to complete full configuration and install missing AI CLI tools.',
1141
- );
1142
- console.log(
1143
- '[USAGE] Run "stigmergy install" to install only missing AI CLI tools.',
1144
- );
1145
- console.log(
1146
- '[USAGE] Run "stigmergy --help" to see all available commands.',
1147
- );
1148
-
1149
- // Force final flush to ensure all output is visible
1150
- if (process.stdout.flush) process.stdout.flush();
1151
- if (process.stderr.flush) process.stderr.flush();
1152
- } catch (fatalError) {
1153
- await errorHandler.logError(fatalError, 'ERROR', 'main.auto-install');
1154
- console.error(
1155
- '[FATAL] Auto-install process failed:',
1156
- fatalError.message,
1157
- );
1158
- console.log('\n[TROUBLESHOOTING] To manually complete installation:');
1159
- console.log('1. Run: stigmergy setup # Complete setup');
1160
- console.log('2. Run: stigmergy install # Install missing tools');
1161
- console.log('3. Run: stigmergy deploy # Deploy hooks manually');
1162
- process.exit(1);
1163
- }
1164
- break;
1165
-
1166
- // Skill命令简化别名
1167
- case 'skill-i': // install
1168
- case 'skill-l': // list
1169
- case 'skill-v': // validate/read
1170
- case 'skill-r': // read
1171
- case 'skill-d': // remove/delete
1172
- case 'skill-m': // remove (移除)
1173
- case 'skill': {
1174
- try {
1175
- // Skill命令通过桥接器调用ES模块
1176
- const { handleSkillCommand } = require('../commands/skill-handler');
1177
-
1178
- // 处理简化命令
1179
- let skillAction;
1180
- let skillArgs;
1181
-
1182
- switch (command) {
1183
- case 'skill-i':
1184
- skillAction = 'install';
1185
- skillArgs = args.slice(1);
1186
- break;
1187
- case 'skill-l':
1188
- skillAction = 'list';
1189
- skillArgs = args.slice(1);
1190
- break;
1191
- case 'skill-v':
1192
- // skill-v可以是validate或read,根据参数判断
1193
- skillAction = args[1] && (args[1].endsWith('.md') || args[1].includes('/') || args[1].includes('\\'))
1194
- ? 'validate'
1195
- : 'read';
1196
- skillArgs = args.slice(1);
1197
- break;
1198
- case 'skill-r':
1199
- skillAction = 'read';
1200
- skillArgs = args.slice(1);
1201
- break;
1202
- case 'skill-d':
1203
- case 'skill-m':
1204
- skillAction = 'remove';
1205
- skillArgs = args.slice(1);
1206
- break;
1207
- default:
1208
- // 标准skill命令
1209
- skillAction = args[1];
1210
- skillArgs = args.slice(2);
1211
-
1212
- // 如果没有子命令,默认执行sync
1213
- if (!skillAction) {
1214
- skillAction = 'sync';
1215
- skillArgs = [];
1216
- }
1217
- }
1218
-
1219
- const skillOptions = {
1220
- force: args.includes('--force'),
1221
- verbose: args.includes('--verbose'),
1222
- autoSync: !args.includes('--no-auto-sync')
1223
- };
1224
-
1225
- const exitCode = await handleSkillCommand(skillAction, skillArgs, skillOptions);
1226
- process.exit(exitCode || 0);
1227
- } catch (error) {
1228
- await errorHandler.logError(error, 'ERROR', 'main.skill');
1229
- console.error(`[ERROR] Skill command failed: ${error.message}`);
1230
- process.exit(1);
1231
- }
1232
- break;
1233
- }
1234
-
1235
- case 'clean':
1236
- case 'c': {
1237
- try {
1238
- console.log('[CLEAN] Starting intelligent cache cleaning...\n');
1239
-
1240
- // Import our enhanced cache cleaner
1241
- const CacheCleaner = require('../core/cache_cleaner');
1242
- const cleaner = new CacheCleaner({
1243
- dryRun: false,
1244
- force: true,
1245
- verbose: true,
1246
- preserveRecent: 60 * 60 * 1000 // Preserve files from last hour
1247
- });
1248
-
1249
- // Show options if arguments provided
1250
- if (args.includes('--dry-run')) {
1251
- console.log('[DRY RUN] Preview mode - no files will be deleted\n');
1252
- await cleaner.cleanAllCaches({
1253
- cleanStigmergy: args.includes('--stigmergy') || args.includes('--all'),
1254
- cleanNPX: args.includes('--npx') || args.includes('--all'),
1255
- cleanNPM: args.includes('--npm') || args.includes('--all'),
1256
- cleanCLI: args.includes('--cli') || args.includes('--all'),
1257
- cleanTemp: true // Always clean temp files
1258
- });
1259
- break;
1260
- }
1261
-
1262
- // Default clean: safe options
1263
- console.log('[OPTIONS] Running safe cache cleaning...');
1264
- console.log('[INFO] This will remove temporary files and NPX cache only\n');
1265
-
1266
- const results = await cleaner.cleanAllCaches({
1267
- cleanStigmergy: false, // Don't clean main config
1268
- cleanNPX: true, // Clean NPX cache (safe)
1269
- cleanNPM: false, // Don't clean NPM cache during normal run
1270
- cleanCLI: false, // Don't clean CLI configs during normal run
1271
- cleanTemp: true // Clean temporary files (always safe)
1272
- });
1273
-
1274
- console.log('\n[SUMMARY] Cache cleaning completed:');
1275
- console.log(` 📄 Files removed: ${results.filesRemoved}`);
1276
- console.log(` 📁 Directories removed: ${results.directoriesRemoved}`);
1277
- console.log(` 💾 Space freed: ${formatBytes(results.bytesFreed)}`);
1278
-
1279
- if (results.errors.length > 0) {
1280
- console.log(`\n⚠️ Warnings: ${results.errors.length} files couldn't be removed`);
1281
- }
1282
-
1283
- } catch (error) {
1284
- console.error('[ERROR] Cache cleaning failed:', error.message);
1285
- process.exit(1);
1286
- }
1287
- break;
1288
- }
1289
-
1290
- case 'diagnostic':
1291
- case 'diag':
1292
- case 'd': {
1293
- try {
1294
- console.log('[DIAGNOSTIC] Stigmergy CLI System Diagnostic...\n');
1295
-
1296
- // System information
1297
- const packageJson = require('../../package.json');
1298
- console.log(`📦 Stigmergy CLI v${packageJson.version}`);
1299
- console.log(`🔧 Node.js: ${process.version}`);
1300
- console.log(`💻 Platform: ${process.platform} (${process.arch})\n`);
1301
-
1302
- // Check cache cleaner availability
1303
- try {
1304
- const CacheCleaner = require('../core/cache_cleaner');
1305
- const cleaner = new CacheCleaner({ dryRun: true });
1306
-
1307
- const plan = await cleaner.createInstallationPlan();
1308
- console.log('🧹 Cache Analysis:');
1309
- console.log(` 📊 Estimated space to clean: ${formatBytes(plan.estimatedSize)}`);
1310
- console.log(` 🗂️ Temporary files detected: ${plan.files.length}`);
1311
- } catch (error) {
1312
- console.log('⚠️ Cache cleaner not available');
1313
- }
1314
-
1315
- // CLI tools status
1316
- try {
1317
- const { available, missing } = await installer.scanCLI();
1318
- console.log('\n🔧 CLI Tools Status:');
1319
- console.log(` ✅ Available: ${Object.keys(available).length}`);
1320
- console.log(` ❌ Missing: ${Object.keys(missing).length}`);
1321
-
1322
- if (Object.keys(missing).length > 0) {
1323
- console.log('\nMissing Tools:');
1324
- for (const [toolName, toolInfo] of Object.entries(missing)) {
1325
- console.log(` - ${toolInfo.name}`);
1326
- }
1327
- }
1328
- } catch (error) {
1329
- console.log('⚠️ CLI scan failed');
1330
- }
1331
-
1332
- // Installation suggestions
1333
- console.log('\n💡 Recommendations:');
1334
- console.log(' • Run "stigmergy install" to install missing CLI tools');
1335
- console.log(' • Run "stigmergy clean" to free up disk space');
1336
- console.log(' • Run "stigmergy setup" for complete configuration');
1337
-
1338
- if (args.includes('--verbose')) {
1339
- console.log('\n📋 Advanced Options:');
1340
- console.log(' • stigmergy clean --all - Clean all caches');
1341
- console.log(' • stigmergy clean --dry-run - Preview cleaning');
1342
- console.log(' • npm uninstall -g stigmergy - Uninstall Stigmergy completely (runs enhanced cleanup)');
1343
- console.log(' • See remaining items after uninstall (individual CLI tools, docs, etc.)');
1344
- }
1345
-
1346
- } catch (error) {
1347
- console.error('[ERROR] Diagnostic failed:', error.message);
1348
- process.exit(1);
1349
- }
1350
- break;
1351
- }
1352
-
1353
- case 'fix-perms': {
1354
- try {
1355
- console.log('[FIX-PERMS] Setting up working directory with proper permissions...\n');
1356
-
1357
- const permAwareInstaller = new PermissionAwareInstaller({
1358
- verbose: process.env.DEBUG === 'true',
1359
- skipPermissionCheck: false,
1360
- autoConfigureShell: true
1361
- });
1362
-
1363
- const result = await permAwareInstaller.install();
1364
-
1365
- if (result.success) {
1366
- console.log('\n✅ Permission setup completed successfully!');
1367
- permAwareInstaller.permissionManager.displayResults(result.permissionSetup);
1368
- } else {
1369
- console.log('\n❌ Permission setup failed');
1370
- console.log(`Error: ${result.error || 'Unknown error'}`);
1371
- process.exit(1);
1372
- }
1373
-
1374
- } catch (error) {
1375
- console.error('[ERROR] Permission setup failed:', error.message);
1376
- if (process.env.DEBUG === 'true') {
1377
- console.error(error.stack);
1378
- }
1379
- process.exit(1);
1380
- }
1381
- break;
1382
- }
1383
-
1384
- case 'perm-check': {
1385
- try {
1386
- console.log('[PERM-CHECK] Checking current directory permissions...\n');
1387
-
1388
- const permissionManager = new DirectoryPermissionManager({ verbose: process.env.DEBUG === 'true' });
1389
- const hasWritePermission = await permissionManager.checkWritePermission();
1390
-
1391
- console.log(`📍 Current directory: ${process.cwd()}`);
1392
- console.log(`🔧 Write permission: ${hasWritePermission ? '✅ Yes' : '❌ No'}`);
1393
-
1394
- if (!hasWritePermission) {
1395
- console.log('\n💡 Suggestions:');
1396
- console.log('1. Run: stigmergy fix-perms # Fix permissions automatically');
1397
- console.log('2. Change to user directory: cd ~');
1398
- console.log('3. Create project directory: mkdir ~/stigmergy && cd ~/stigmergy');
1399
- console.log('\n🔍 System Info:');
1400
- const sysInfo = permissionManager.getSystemInfo();
1401
- console.log(` Platform: ${sysInfo.platform}`);
1402
- console.log(` Shell: ${sysInfo.shell}`);
1403
- console.log(` Home: ${sysInfo.homeDir}`);
1404
- } else {
1405
- console.log('\n✅ Current directory is ready for installation');
1406
- }
1407
-
1408
- } catch (error) {
1409
- console.error('[ERROR] Permission check failed:', error.message);
1410
- if (process.env.DEBUG === 'true') {
1411
- console.error(error.stack);
1412
- }
1413
- process.exit(1);
1414
- }
1415
- break;
1416
- }
1417
-
1418
- default:
1419
- // Check if the command matches a direct CLI tool name
1420
- if (CLI_TOOLS[command]) {
1421
- const toolName = command;
1422
- const toolInfo = CLI_TOOLS[toolName];
1423
-
1424
- // Get the prompt (everything after the tool name)
1425
- const prompt = args.slice(1).join(' ');
1426
-
1427
- if (!prompt) {
1428
- console.log(`[ERROR] Usage: stigmergy ${toolName} "<prompt>"`);
1429
- process.exit(1);
1430
- }
1431
-
1432
- console.log(`[DIRECT] Routing to ${toolInfo.name}: ${prompt}`);
1433
-
1434
- // Use smart router to handle the execution
1435
- const router = new SmartRouter();
1436
- await router.initialize();
1437
-
1438
- // Create a route object similar to what smartRoute would return
1439
- const route = {
1440
- tool: toolName,
1441
- prompt: prompt
1442
- };
1443
-
1444
- // Execute the routed command (reusing the call command logic)
1445
- try {
1446
- // Get the actual executable path for the tool using which/where command
1447
- let toolPath = toolName;
1448
- try {
1449
- const whichCmd = process.platform === 'win32' ? 'where' : 'which';
1450
- const whichResult = spawnSync(whichCmd, [toolName], {
1451
- encoding: 'utf8',
1452
- timeout: 10000,
1453
- stdio: ['pipe', 'pipe', 'pipe'],
1454
- shell: true,
1455
- });
1456
-
1457
- if (whichResult.status === 0 && whichResult.stdout.trim()) {
1458
- // Get the first match (most likely the one that would be executed)
1459
- toolPath = whichResult.stdout.trim().split('\n')[0].trim();
1460
- }
1461
- } catch (whichError) {
1462
- // If which/where fails, continue with the tool name
1463
- if (process.env.DEBUG === 'true') {
1464
- console.log(`[DEBUG] which/where command failed for ${toolName}: ${whichError.message}`);
1465
- }
1466
- }
1467
-
1468
- console.log(`[DEBUG] Tool path: ${toolPath}, Prompt: ${route.prompt}`);
1469
-
1470
- // For different tools, we need to pass the prompt differently
1471
- // Use unified parameter handler for better parameter handling
1472
- let toolArgs = [];
1473
-
1474
- try {
1475
- // Get CLI pattern for this tool
1476
- console.log(`[DEBUG] Attempting to get CLI pattern for: ${route.tool}`);
1477
- const cliPattern = await router.analyzer.getCLIPattern(route.tool);
1478
- console.log(`[DEBUG] Got CLI pattern: ${JSON.stringify(cliPattern)}`);
1479
-
1480
- // Log the CLI pattern to debug command format issues
1481
- if (process.env.DEBUG === 'true' && cliPattern) {
1482
- console.log(
1483
- `[DEBUG] CLI Pattern for ${route.tool}:`,
1484
- JSON.stringify(cliPattern, null, 2),
1485
- );
1486
- }
1487
-
1488
- // Use the unified CLI parameter handler
1489
- const CLIParameterHandler = require('../core/cli_parameter_handler');
1490
- toolArgs = CLIParameterHandler.generateArguments(
1491
- route.tool,
1492
- route.prompt,
1493
- cliPattern,
1494
- );
1495
-
1496
- // Add debug logging for the final arguments
1497
- console.log(`[DEBUG] Final toolArgs: ${JSON.stringify(toolArgs)}`);
1498
- } catch (patternError) {
1499
- // Fallback to original logic if pattern analysis fails
1500
- console.log(`[DEBUG] Pattern analysis failed, using fallback logic: ${patternError.message}`);
1501
- if (route.tool === 'claude') {
1502
- // Claude CLI expects the prompt with -p flag for non-interactive mode
1503
- toolArgs = ['-p', `"${route.prompt}"`];
1504
- } else if (route.tool === 'qodercli' || route.tool === 'iflow') {
1505
- // Qoder CLI and iFlow expect the prompt with -p flag
1506
- toolArgs = ['-p', `"${route.prompt}"`];
1507
- } else if (route.tool === 'codex') {
1508
- // Codex CLI needs 'exec' subcommand for non-interactive mode
1509
- toolArgs = ['exec', '-p', `"${route.prompt}"`];
1510
- } else {
1511
- // For other tools, pass the prompt with -p flag
1512
- toolArgs = ['-p', `"${route.prompt}"`];
1513
- }
1514
-
1515
- // Add debug logging for the fallback arguments
1516
- console.log(`[DEBUG] Fallback toolArgs: ${JSON.stringify(toolArgs)}`);
1517
- }
1518
-
1519
- // Use the reliable cross-platform execution function
1520
- try {
1521
- // Validate that the tool exists before attempting to execute
1522
- if (!toolPath || typeof toolPath !== 'string') {
1523
- throw new Error(`Invalid tool path: ${toolPath}`);
1524
- }
1525
-
1526
- // Special handling for JS files to ensure proper execution
1527
- if (toolPath.endsWith('.js') || toolPath.endsWith('.cjs')) {
1528
- // Use safe JS file execution
1529
- if (process.env.DEBUG === 'true') {
1530
- console.log(
1531
- `[EXEC] Safely executing JS file: ${toolPath} ${toolArgs.join(' ')}`,
1532
- );
1533
- }
1534
- const result = await executeJSFile(toolPath, toolArgs, {
1535
- stdio: 'inherit',
1536
- shell: true,
1537
- });
1538
-
1539
- if (!result.success) {
1540
- console.log(
1541
- `[WARN] ${route.tool} exited with code ${result.code}`,
1542
- );
1543
- }
1544
- process.exit(result.code || 0);
1545
- } else {
1546
- // Regular command execution
1547
- if (process.env.DEBUG === 'true') {
1548
- console.log(`[EXEC] Running: ${toolPath} ${toolArgs.join(' ')}`);
1549
- }
1550
- console.log(`[DEBUG] About to execute: ${toolPath} with args: ${JSON.stringify(toolArgs)}`);
1551
-
1552
- // Special handling for Windows to construct the command properly
1553
- let execCommand = toolPath;
1554
- let execArgs = toolArgs;
1555
- if (process.platform === 'win32') {
1556
- // On Windows, we construct the full command line and pass it as a single string
1557
- if (toolArgs.length > 0) {
1558
- // For Windows, we need to properly quote the entire command line
1559
- const argsString = toolArgs.map(arg => {
1560
- // If arg contains spaces and is not already quoted, quote it
1561
- if (arg.includes(' ') && !(arg.startsWith('"') && arg.endsWith('"'))) {
1562
- return `"${arg}"`;
1563
- }
1564
- return arg;
1565
- }).join(' ');
1566
- execCommand = `${toolPath} ${argsString}`;
1567
- execArgs = [];
1568
- console.log(`[DEBUG] Windows full command: ${execCommand}`);
1569
- }
1570
- }
1571
-
1572
- // Use detected paths for all CLI tools on all platforms
1573
- const supportedTools = ['claude', 'copilot', 'qodercli', 'gemini', 'qwen', 'iflow', 'codebuddy', 'codex'];
1574
-
1575
- if (supportedTools.includes(route.tool)) {
1576
- // Use detected path for all CLI tools regardless of platform
1577
- const detectedPath = await getCLIPath(route.tool);
1578
- if (detectedPath) {
1579
- execCommand = detectedPath;
1580
- console.log(`[DEBUG] Using detected ${route.tool} path: ${execCommand}`);
1581
- } else {
1582
- // Fallback to system PATH for tools not detected
1583
- console.log(`[DEBUG] Using system PATH for ${route.tool}: ${route.tool}`);
1584
- }
1585
- }
1586
-
1587
- // Platform-specific command construction
1588
- if (process.platform === 'win32') {
1589
- // Special handling for Windows CLI tools
1590
- if (route.tool === 'claude' && toolArgs.length > 0) {
1591
- // Special parameter handling for Claude to avoid wrapper script issues
1592
- const argsString = toolArgs.map(arg => {
1593
- if (arg.includes(' ') && !(arg.startsWith('"') && arg.endsWith('"'))) {
1594
- return `"${arg}"`;
1595
- }
1596
- return arg;
1597
- }).join(' ');
1598
- execCommand = `${execCommand} ${argsString}`;
1599
- execArgs = [];
1600
- console.log(`[DEBUG] Windows ${route.tool} direct command: ${execCommand}`);
1601
- } else if (route.tool === 'copilot') {
1602
- // Copilot doesn't use -p parameter format
1603
- execArgs = [];
1604
- console.log(`[DEBUG] Windows ${route.tool} direct command: ${execCommand}`);
1605
- } else if (toolArgs.length > 0) {
1606
- // For other Windows tools, construct full command line
1607
- const argsString = toolArgs.map(arg => {
1608
- if (arg.includes(' ') && !(arg.startsWith('"') && arg.endsWith('"'))) {
1609
- return `"${arg}"`;
1610
- }
1611
- return arg;
1612
- }).join(' ');
1613
- execCommand = `${execCommand} ${argsString}`;
1614
- execArgs = [];
1615
- console.log(`[DEBUG] Windows full command: ${execCommand}`);
1616
- }
1617
- }
1618
-
1619
-
1620
- // Apply the same Windows handling logic to ensure consistency
1621
- // This ensures consistency between direct routing and call command routing
1622
- if (process.platform === 'win32' && execArgs.length > 0) {
1623
- // For Windows, we need to properly quote the entire command line
1624
- const argsString = execArgs.map(arg => {
1625
- // If arg contains spaces and is not already quoted, quote it
1626
- if (arg.includes(' ') && !(arg.startsWith('"') && arg.endsWith('"'))) {
1627
- return `"${arg}"`;
1628
- }
1629
- return arg;
1630
- }).join(' ');
1631
- execCommand = `${execCommand} ${argsString}`;
1632
- execArgs = [];
1633
- console.log(`[DEBUG] Windows unified command: ${execCommand}`);
1634
- }
1635
-
1636
- const result = await executeCommand(execCommand, execArgs, {
1637
- stdio: 'inherit',
1638
- shell: true,
1639
- });
1640
-
1641
- if (!result.success) {
1642
- console.log(
1643
- `[WARN] ${route.tool} exited with code ${result.code}`,
1644
- );
1645
- }
1646
- process.exit(result.code || 0);
1647
- }
1648
- } catch (executionError) {
1649
- // Check for specific errors that might not be actual failures
1650
- const errorMessage =
1651
- executionError.error?.message ||
1652
- executionError.message ||
1653
- executionError;
1654
-
1655
- // For some tools like Claude, they may output to stdout and return non-zero codes
1656
- // without actually failing - handle these cases more gracefully
1657
- if (
1658
- errorMessage.includes(
1659
- 'not recognized as an internal or external command',
1660
- ) ||
1661
- errorMessage.includes('command not found') ||
1662
- errorMessage.includes('ENOENT')
1663
- ) {
1664
- // This is a genuine error - tool is not installed
1665
- const cliError = await errorHandler.handleCLIError(
1666
- route.tool,
1667
- executionError.error || executionError,
1668
- toolArgs.join(' '),
1669
- );
1670
-
1671
- // Provide clear ANSI English error message
1672
- console.log('==================================================');
1673
- console.log('ERROR: Failed to execute AI CLI tool');
1674
- console.log('==================================================');
1675
- console.log(`Tool: ${route.tool}`);
1676
- console.log(`Error: ${cliError.message}`);
1677
- if (executionError.stderr) {
1678
- console.log(`Stderr: ${executionError.stderr}`);
1679
- }
1680
- console.log('');
1681
- console.log('Possible solutions:');
1682
- console.log('1. Check if the AI CLI tool is properly installed');
1683
- console.log('2. Verify the tool is in your system PATH');
1684
- console.log('3. Try reinstalling the tool with: stigmergy install');
1685
- console.log('4. Run stigmergy status to check tool availability');
1686
- console.log('');
1687
- console.log('For manual execution, you can run:');
1688
- console.log(`${toolPath} ${toolArgs.join(' ')}`);
1689
- console.log('==================================================');
1690
- process.exit(1);
1691
- } else {
1692
- // For other execution errors, try to execute the command directly
1693
- // which handles cases where the tool executed successfully but returned an error object
1694
- console.log(`[EXEC] Running: ${toolPath} ${toolArgs.join(' ')}`);
1695
-
1696
- // Set environment for tools that need specific working directories
1697
- const env = { ...process.env };
1698
- if (route.tool === 'qwen') {
1699
- delete env.NODE_PATH;
1700
- }
1701
-
1702
- const result = await executeCommand(toolPath, toolArgs, {
1703
- stdio: 'inherit',
1704
- shell: true,
1705
- cwd: getWorkingDirectoryForTool(route.tool),
1706
- env,
1707
- });
1708
-
1709
- if (!result.success) {
1710
- console.log(
1711
- `[WARN] ${route.tool} exited with code ${result.code}`,
1712
- );
1713
- }
1714
- process.exit(result.code || 0);
1715
- }
1716
- }
1717
- } catch (error) {
1718
- const cliError = await errorHandler.handleCLIError(
1719
- route.tool,
1720
- error,
1721
- prompt,
1722
- );
1723
- console.log(
1724
- `[ERROR] Failed to execute ${route.tool}:`,
1725
- cliError.message,
1726
- );
1727
- process.exit(1);
1728
- }
1729
- } else {
1730
- console.log(`[ERROR] Unknown command: ${command}`);
1731
- console.log('[INFO] Run "stigmergy --help" for usage information');
1732
- process.exit(1);
1733
- }
1734
- }
1735
- }
1736
-
1737
- module.exports = main;