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