stigmergy 1.2.8 → 1.2.11

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 (48) hide show
  1. package/README.md +40 -6
  2. package/STIGMERGY.md +10 -0
  3. package/package.json +19 -5
  4. package/scripts/preuninstall.js +10 -0
  5. package/src/adapters/claude/install_claude_integration.js +21 -21
  6. package/src/adapters/codebuddy/install_codebuddy_integration.js +54 -51
  7. package/src/adapters/codex/install_codex_integration.js +27 -28
  8. package/src/adapters/gemini/install_gemini_integration.js +60 -60
  9. package/src/adapters/iflow/install_iflow_integration.js +72 -72
  10. package/src/adapters/qoder/install_qoder_integration.js +64 -64
  11. package/src/adapters/qwen/install_qwen_integration.js +7 -7
  12. package/src/cli/router.js +581 -175
  13. package/src/commands/skill-bridge.js +39 -0
  14. package/src/commands/skill-handler.js +150 -0
  15. package/src/commands/skill.js +127 -0
  16. package/src/core/cli_path_detector.js +710 -0
  17. package/src/core/cli_tools.js +72 -1
  18. package/src/core/coordination/nodejs/AdapterManager.js +29 -1
  19. package/src/core/directory_permission_manager.js +568 -0
  20. package/src/core/enhanced_cli_installer.js +609 -0
  21. package/src/core/installer.js +232 -88
  22. package/src/core/multilingual/language-pattern-manager.js +78 -50
  23. package/src/core/persistent_shell_configurator.js +468 -0
  24. package/src/core/skills/StigmergySkillManager.js +357 -0
  25. package/src/core/skills/__tests__/SkillInstaller.test.js +275 -0
  26. package/src/core/skills/__tests__/SkillParser.test.js +202 -0
  27. package/src/core/skills/__tests__/SkillReader.test.js +189 -0
  28. package/src/core/skills/cli-command-test.js +201 -0
  29. package/src/core/skills/comprehensive-e2e-test.js +473 -0
  30. package/src/core/skills/e2e-test.js +267 -0
  31. package/src/core/skills/embedded-openskills/SkillInstaller.js +438 -0
  32. package/src/core/skills/embedded-openskills/SkillParser.js +123 -0
  33. package/src/core/skills/embedded-openskills/SkillReader.js +143 -0
  34. package/src/core/skills/integration-test.js +248 -0
  35. package/src/core/skills/package.json +6 -0
  36. package/src/core/skills/regression-test.js +285 -0
  37. package/src/core/skills/run-all-tests.js +129 -0
  38. package/src/core/skills/sync-test.js +210 -0
  39. package/src/core/skills/test-runner.js +242 -0
  40. package/src/utils/helpers.js +3 -20
  41. package/src/auth.js +0 -173
  42. package/src/auth_command.js +0 -208
  43. package/src/calculator.js +0 -313
  44. package/src/core/enhanced_installer.js +0 -479
  45. package/src/core/enhanced_uninstaller.js +0 -638
  46. package/src/data_encryption.js +0 -143
  47. package/src/data_structures.js +0 -440
  48. package/src/deploy.js +0 -55
package/src/cli/router.js CHANGED
@@ -18,13 +18,16 @@ const fs = require('fs/promises');
18
18
  const fsSync = require('fs');
19
19
  const { spawnSync } = require('child_process');
20
20
 
21
+ // Import permission management components
22
+ const DirectoryPermissionManager = require('../core/directory_permission_manager');
23
+ const { setupCLIPaths, getCLIPath } = require('../core/cli_tools');
24
+
21
25
  // Import our custom modules
22
26
  const SmartRouter = require('../core/smart_router');
23
27
  const CLIHelpAnalyzer = require('../core/cli_help_analyzer');
24
28
  const { CLI_TOOLS } = require('../core/cli_tools');
25
29
  const { errorHandler } = require('../core/error_handler');
26
30
  const { executeCommand, executeJSFile } = require('../utils');
27
- const { UserAuthenticator } = require('../auth');
28
31
  const MemoryManager = require('../core/memory_manager');
29
32
  const StigmergyInstaller = require('../core/installer');
30
33
  const UpgradeManager = require('../core/upgrade_manager');
@@ -72,17 +75,26 @@ async function main() {
72
75
  console.log(' version, --version Show version information');
73
76
  console.log(' status Check CLI tools status');
74
77
  console.log(' scan Scan for available AI CLI tools');
75
- console.log(' install Auto-install missing CLI tools');
78
+ console.log(' install Auto-install missing CLI tools (with permission fix)');
76
79
  console.log(' upgrade Upgrade all CLI tools to latest versions');
77
80
  console.log(
78
81
  ' deploy Deploy hooks and integration to installed tools',
79
82
  );
80
83
  console.log(' setup Complete setup and configuration');
81
84
  console.log(
82
- ' init Initialize Stigmergy configuration (alias for setup)',
85
+ ' init Initialize Stigmergy project in current directory',
83
86
  );
84
87
  console.log(' clean (c) Clean temporary files and caches');
85
88
  console.log(' diagnostic (d) Show system diagnostic information');
89
+ console.log(' fix-perms Fix directory permissions for installation');
90
+ console.log(' perm-check Check current directory permissions');
91
+ console.log(' skill <action> Manage skills across CLIs (install/read/list/sync/remove)');
92
+ console.log(' skill-i <src> Install skills (shortcut for: skill install)');
93
+ console.log(' skill-l List skills (shortcut for: skill list)');
94
+ console.log(' skill-r <name> Read skill (shortcut for: skill read)');
95
+ console.log(' skill-v <name> View/validate skill (auto-detect read or validate)');
96
+ console.log(' skill-d <name> Delete/remove skill (shortcut for: skill remove)');
97
+ console.log(' skill Sync skills to all CLI configs (shortcut for: skill sync)');
86
98
  console.log(' call "<prompt>" Execute prompt with auto-routed AI CLI');
87
99
  console.log(' <tool> "<prompt>" Directly route to specific AI CLI tool');
88
100
  console.log(' Supported tools: claude, gemini, qwen, iflow, qodercli, codebuddy, copilot, codex');
@@ -126,52 +138,106 @@ async function main() {
126
138
  break;
127
139
 
128
140
  case 'init':
129
- // Alias for setup command
130
- console.log('[INIT] Initializing Stigmergy CLI...');
131
- // Fall through to setup case
141
+ try {
142
+ console.log('[INIT] Initializing Stigmergy project in current directory...\n');
143
+
144
+ // Quick path detection for better tool availability
145
+ console.log('[INIT] Detecting CLI tool paths...');
146
+ const pathSetup = await setupCLIPaths();
147
+
148
+ console.log(`[INIT] CLI tool detection: ${pathSetup.report.summary.found}/${pathSetup.report.summary.total} tools found`);
149
+
150
+ // Initialize project files in current directory
151
+ await installer.createProjectFiles();
152
+
153
+ console.log('[INIT] Project initialization completed successfully!');
154
+ console.log('\n[INFO] Created:');
155
+ console.log(' - PROJECT_SPEC.json (project specification)');
156
+ console.log(' - PROJECT_CONSTITUTION.md (collaboration guidelines)');
157
+ console.log(' - CLI path detection cache in ~/.stigmergy/cli-paths/');
158
+
159
+ if (pathSetup.report.summary.missing > 0) {
160
+ console.log('\n[INFO] For full CLI integration, run:');
161
+ console.log(' stigmergy setup # Complete setup with PATH configuration');
162
+ }
163
+ } catch (error) {
164
+ await errorHandler.logError(error, 'ERROR', 'main.init');
165
+ console.log(`[ERROR] Project initialization failed: ${error.message}`);
166
+ process.exit(1);
167
+ }
168
+ break;
132
169
 
133
170
  case 'setup':
134
171
  try {
135
172
  console.log('[SETUP] Starting complete Stigmergy setup...\n');
136
173
 
137
- // Step 1: Download required assets
138
- await installer.downloadRequiredAssets();
174
+ // Step 0: Setup CLI paths detection and configuration
175
+ console.log('[STEP 0] Setting up CLI path detection...');
176
+ const pathSetup = await setupCLIPaths();
139
177
 
140
- // Step 2: Scan for CLI tools
178
+ console.log(`[PATH] Path detection complete:`);
179
+ console.log(` - Found: ${pathSetup.report.summary.found} CLI tools`);
180
+ console.log(` - Missing: ${pathSetup.report.summary.missing} CLI tools`);
181
+
182
+ if (pathSetup.pathStatus.updated) {
183
+ console.log('\n[PATH] ✓ All npm global directories are now available in PATH');
184
+ console.log('[PATH] CLI tools will be globally accessible after terminal restart');
185
+ } else {
186
+ console.log('\n[PATH] ⚠️ PATH update failed:');
187
+ console.log(` Error: ${pathSetup.pathStatus.message}`);
188
+ console.log('\n[PATH] Manual update required:');
189
+ console.log(' Run the generated scripts to update PATH:');
190
+ if (pathSetup.pathStatus.scriptPath) {
191
+ console.log(` - Script directory: ${pathSetup.pathStatus.scriptPath}`);
192
+ }
193
+ console.log(' - Windows: Run PowerShell as Administrator and execute the scripts');
194
+ console.log(' - Unix/Linux: Source the shell script (source update-path.sh)');
195
+ }
196
+
197
+ // Step 1: Scan for CLI tools
198
+ console.log('\n[STEP 1] Scanning for AI CLI tools...');
141
199
  const { available: setupAvailable, missing: setupMissing } =
142
200
  await installer.scanCLI();
143
- const setupOptions = await installer.showInstallOptions(setupMissing);
144
-
145
- // Step 3: Install missing CLI tools if user chooses
146
- if (setupOptions.length > 0) {
147
- const selectedTools = await installer.getUserSelection(
148
- setupOptions,
149
- setupMissing,
150
- );
151
- if (selectedTools.length > 0) {
152
- console.log(
153
- '\n[INFO] Installing selected tools (this may take several minutes for tools that download binaries)...',
154
- );
155
- await installer.installTools(selectedTools, setupMissing);
201
+
202
+ // Step 2: Install missing CLI tools
203
+ if (Object.keys(setupMissing).length > 0) {
204
+ console.log('\n[STEP 2] Installing missing tools...');
205
+ console.log('[INFO] Missing tools found:');
206
+ for (const [toolName, toolInfo] of Object.entries(setupMissing)) {
207
+ console.log(` - ${toolInfo.name}: ${toolInfo.install}`);
208
+ }
209
+
210
+ console.log('\n[INFO] To install missing tools, run:');
211
+ for (const [toolName, toolInfo] of Object.entries(setupMissing)) {
212
+ console.log(` ${toolInfo.install}`);
156
213
  }
214
+
215
+ console.log('\n[INFO] Or use the enhanced installer:');
216
+ console.log(' node src/core/enhanced_installer.js');
157
217
  } else {
158
- console.log('\n[INFO] All required tools are already installed!');
218
+ console.log('\n[STEP 2] All required tools are already installed!');
159
219
  }
160
220
 
161
- // Step 4: Deploy hooks to available CLI tools
162
- await installer.deployHooks(setupAvailable);
163
-
164
- // Step 5: Deploy project documentation
165
- await installer.deployProjectDocumentation();
166
-
167
- // Step 6: Initialize configuration
168
- await installer.initializeConfig();
221
+ // Step 3: Deploy hooks to available CLI tools
222
+ if (Object.keys(setupAvailable).length > 0) {
223
+ console.log('\n[STEP 3] Deploying hooks to available tools...');
224
+ await installer.deployHooks(setupAvailable);
225
+ } else {
226
+ console.log('\n[STEP 3] No tools available for hook deployment');
227
+ }
169
228
 
170
- // Step 7: Show usage instructions
171
- installer.showUsageInstructions();
229
+ console.log('\n🎉 Setup completed successfully!');
230
+ console.log('\n[USAGE] Get started with these commands:');
231
+ console.log(' stigmergy d - System diagnostic (recommended first)');
232
+ console.log(' stigmergy inst - Install missing AI CLI tools');
233
+ console.log(' stigmergy deploy - Deploy hooks to installed tools');
234
+ console.log(' stigmergy call - Execute prompts with auto-routing');
235
+
172
236
  } catch (error) {
173
- await errorHandler.logError(error, 'ERROR', 'main.setup');
174
- console.log(`[ERROR] Setup failed: ${error.message}`);
237
+ console.error('[ERROR] Setup failed:', error.message);
238
+ if (process.env.DEBUG === 'true') {
239
+ console.error(error.stack);
240
+ }
175
241
  console.log('\n[TROUBLESHOOTING] To manually complete setup:');
176
242
  console.log('1. Run: stigmergy deploy # Deploy hooks manually');
177
243
  console.log('2. Run: stigmergy setup # Try setup again');
@@ -222,146 +288,129 @@ async function main() {
222
288
 
223
289
  case 'upgrade': {
224
290
  try {
225
- console.log('[UPGRADE] Starting CLI tools upgrade process...');
226
- const upgrader = new UpgradeManager();
227
- await upgrader.initialize();
228
-
291
+ console.log('[UPGRADE] Starting AI CLI tools upgrade process...\n');
292
+
229
293
  // 解析命令行选项
230
294
  const upgradeArgs = args.slice(1);
231
295
  const options = {
232
296
  dryRun: upgradeArgs.includes('--dry-run'),
233
297
  force: upgradeArgs.includes('--force'),
234
- verbose: upgradeArgs.includes('--verbose'),
235
- diagnose: upgradeArgs.includes('--diagnose'),
236
- suggest: upgradeArgs.includes('--suggest')
298
+ verbose: upgradeArgs.includes('--verbose')
237
299
  };
300
+
301
+ // 使用EnhancedCLIInstaller进行升级
302
+ const EnhancedCLIInstaller = require(path.resolve(__dirname, '../core/enhanced_cli_installer'));
303
+ const enhancedInstaller = new EnhancedCLIInstaller({
304
+ verbose: process.env.DEBUG === 'true' || options.verbose,
305
+ autoRetry: true,
306
+ maxRetries: 2
307
+ });
238
308
 
239
- if (options.diagnose) {
240
- console.log('\n🔍 DIAGNOSTIC MODE - Checking for issues...\n');
241
- const deprecations = await upgrader.checkDeprecations();
309
+ // 获取已安装的工具列表 - 使用全局installer扫描
310
+ const { available: installedTools } = await installer.scanCLI();
242
311
 
243
- if (deprecations.length === 0) {
244
- console.log(' No issues detected.');
245
- } else {
246
- console.log('❌ Issues found:');
247
- deprecations.forEach((dep, index) => {
248
- console.log(`\n${index + 1}. ${dep.type || 'Unknown'}`);
249
- if (dep.dependency) console.log(` Dependency: ${dep.dependency}`);
250
- console.log(` Issues: ${dep.issues.join(', ')}`);
251
- });
252
- }
312
+ if (Object.keys(installedTools).length === 0) {
313
+ console.log('[INFO] No AI CLI tools found. Please install tools first with: stigmergy install');
253
314
  break;
254
315
  }
255
316
 
256
- if (options.suggest) {
257
- console.log('\n💡 SUGGESTION MODE - Generating recommendations...\n');
258
- const plan = await upgrader.generateUpgradePlan(options);
259
-
260
- console.log('📋 Recommendations:');
261
- if (plan.upgrades.length > 0) {
262
- console.log('\n🔺 Available Upgrades:');
263
- plan.upgrades.forEach(upgrade => {
264
- console.log(` • ${upgrade.tool}: ${upgrade.from} → ${upgrade.to}`);
265
- });
266
- }
267
-
268
- if (plan.fixes.length > 0) {
269
- console.log('\n🔧 Recommended Fixes:');
270
- plan.fixes.forEach(fix => {
271
- console.log(` • ${fix.type}: ${fix.description}`);
272
- });
273
- }
317
+ console.log(`[INFO] Found ${Object.keys(installedTools).length} installed AI CLI tools:`);
318
+ for (const [toolName, toolInfo] of Object.entries(installedTools)) {
319
+ console.log(` - ${toolInfo.name} (${toolName})`);
320
+ }
274
321
 
275
- if (plan.upgrades.length === 0 && plan.fixes.length === 0) {
276
- console.log(' Everything is up to date!');
277
- }
322
+ if (options.dryRun) {
323
+ console.log('\n🔍 DRY RUN MODE - No changes will be made');
324
+ console.log(' Use --force to execute the upgrade');
278
325
  break;
279
326
  }
280
327
 
281
- // 生成升级计划
282
- console.log('\n📋 Generating upgrade plan...\n');
283
- const plan = await upgrader.generateUpgradePlan(options);
328
+ // 默认直接执行升级,无需用户确认
329
+ console.log(`\n[UPGRADE] Upgrading ${Object.keys(installedTools).length} AI CLI tools...`);
330
+ console.log('[INFO] Use --dry-run to preview upgrades without executing');
284
331
 
285
- // 显示计划
286
- console.log('📊 UPGRADE PLAN');
287
- console.log('='.repeat(50));
332
+ console.log('\n🚀 Upgrading AI CLI tools with automatic permission handling...\n');
288
333
 
289
- if (plan.upgrades.length > 0) {
290
- console.log('\n🔺 CLI Tool Upgrades:');
291
- plan.upgrades.forEach(upgrade => {
292
- console.log(` • ${upgrade.tool.padEnd(12)} ${upgrade.from} → ${upgrade.to}`);
293
- });
294
- } else {
295
- console.log('\n✅ All CLI tools are up to date');
296
- }
334
+ // 批量升级所有工具,一次权限检测
335
+ console.log(`[INFO] Starting batch upgrade of ${Object.keys(installedTools).length} tools...`);
297
336
 
298
- if (plan.fixes.length > 0) {
299
- console.log('\n🔧 Issues to Fix:');
300
- plan.fixes.forEach(fix => {
301
- console.log(` • ${fix.type}: ${fix.description}`);
302
- });
337
+ const upgradeToolInfos = {};
338
+ for (const [toolName, toolInfo] of Object.entries(installedTools)) {
339
+ upgradeToolInfos[toolName] = {
340
+ ...toolInfo,
341
+ install: `npm upgrade -g ${toolName}`,
342
+ name: `${toolInfo.name} (Upgrade)`
343
+ };
303
344
  }
304
345
 
305
- if (plan.warnings.length > 0) {
306
- console.log('\n⚠️ Warnings:');
307
- plan.warnings.forEach(warning => {
308
- console.log(` • ${warning.tool || 'Unknown'}: ${warning.error}`);
309
- });
310
- }
346
+ const upgradeResult = await enhancedInstaller.upgradeTools(
347
+ Object.keys(installedTools),
348
+ upgradeToolInfos
349
+ );
311
350
 
312
- if (options.dryRun) {
313
- console.log('\n🔍 DRY RUN MODE - No changes will be made');
314
- console.log(' Use --force to execute the upgrade plan');
315
- break;
316
- }
351
+ // 整理结果
352
+ const results = {
353
+ successful: [],
354
+ failed: [],
355
+ permissionHandled: []
356
+ };
317
357
 
318
- // 确认执行
319
- if (!options.force) {
320
- const { confirm } = await inquirer.prompt([{
321
- type: 'confirm',
322
- name: 'confirm',
323
- message: 'Do you want to proceed with this upgrade plan?',
324
- default: false
325
- }]);
326
-
327
- if (!confirm) {
328
- console.log('\n❌ Upgrade cancelled by user');
329
- break;
358
+ for (const [toolName, installation] of Object.entries(upgradeResult.results.installations || {})) {
359
+ if (installation.success) {
360
+ results.successful.push(toolName);
361
+ if (installation.permissionHandled) {
362
+ results.permissionHandled.push(toolName);
363
+ }
364
+ } else {
365
+ results.failed.push({
366
+ tool: toolName,
367
+ error: installation.error || 'Installation failed'
368
+ });
330
369
  }
331
370
  }
332
-
333
- // 执行升级
334
- console.log('\n🚀 Executing upgrade plan...\n');
335
- const results = await upgrader.executeUpgrade(plan, options);
336
-
371
+
337
372
  // 显示结果
338
373
  console.log('\n📊 UPGRADE RESULTS');
339
374
  console.log('='.repeat(50));
340
375
 
341
376
  if (results.successful.length > 0) {
342
377
  console.log(`\n✅ Successful (${results.successful.length}):`);
343
- results.successful.forEach(result => {
344
- const name = result.tool || result.type;
345
- console.log(` • ${name}`);
378
+ results.successful.forEach(tool => {
379
+ console.log(` • ${tool}`);
380
+ });
381
+ }
382
+
383
+ if (results.permissionHandled.length > 0) {
384
+ console.log(`\n🔧 Auto-handled permissions (${results.permissionHandled.length}):`);
385
+ results.permissionHandled.forEach(tool => {
386
+ console.log(` • ${tool}`);
346
387
  });
347
388
  }
348
389
 
349
390
  if (results.failed.length > 0) {
350
391
  console.log(`\n❌ Failed (${results.failed.length}):`);
351
392
  results.failed.forEach(result => {
352
- const name = result.tool || result.type;
353
- console.log(` • ${name}: ${result.error}`);
393
+ console.log(` • ${result.tool}: ${result.error}`);
354
394
  });
395
+
396
+ // Provide guidance for permission issues
397
+ if (results.failed.length > 0) {
398
+ console.log('\n💡 如果遇到权限问题,请尝试:');
399
+ console.log(' Windows: 以管理员身份运行PowerShell,然后执行 stigmergy upgrade');
400
+ console.log(' macOS/Linux: sudo stigmergy upgrade');
401
+ }
355
402
  }
356
403
 
357
- // 记录日志
358
- await upgrader.logUpgrade(plan, results);
404
+ if (results.permissionHandled.length > 0) {
405
+ console.log('\n✅ 权限问题已自动处理');
406
+ console.log(`🔧 自动提升权限升级了 ${results.permissionHandled.length} 个工具`);
407
+ }
359
408
 
360
409
  console.log('\n🎉 Upgrade process completed!');
361
-
410
+
362
411
  } catch (error) {
363
412
  console.error('[ERROR] Upgrade failed:', error.message);
364
- if (options.verbose) {
413
+ if (process.env.DEBUG === 'true') {
365
414
  console.error(error.stack);
366
415
  }
367
416
  process.exit(1);
@@ -369,30 +418,101 @@ async function main() {
369
418
  break;
370
419
  }
371
420
 
372
- case 'install':
421
+ case 'install':
373
422
  case 'inst':
374
423
  try {
375
424
  console.log('[INSTALL] Starting AI CLI tools installation...');
376
- const { missing: missingTools } = await installer.scanCLI();
377
- const options = await installer.showInstallOptions(missingTools);
378
425
 
379
- if (options.length > 0) {
380
- const selectedTools = await installer.getUserSelection(
381
- options,
382
- missingTools,
383
- );
384
- if (selectedTools.length > 0) {
385
- console.log(
386
- '\n[INFO] Installing selected tools (this may take several minutes for tools that download binaries)...',
387
- );
388
- await installer.installTools(selectedTools, missingTools);
426
+ // Check directory permissions first
427
+ const permissionManager = new DirectoryPermissionManager({ verbose: process.env.DEBUG === 'true' });
428
+ const hasWritePermission = await permissionManager.checkWritePermission();
429
+
430
+ if (!hasWritePermission) {
431
+ console.log('\n⚠️ Current directory lacks write permission');
432
+ console.log('🔧 Using permission-aware installation...');
433
+
434
+ // Use permission-aware installer
435
+ const permAwareInstaller = new PermissionAwareInstaller({
436
+ verbose: process.env.DEBUG === 'true',
437
+ skipPermissionCheck: false
438
+ });
439
+
440
+ const result = await permAwareInstaller.install();
441
+ if (result.success) {
442
+ console.log('\n✅ Permission-aware installation completed successfully!');
443
+ } else {
444
+ console.log('\n❌ Permission-aware installation failed');
445
+ process.exit(1);
446
+ }
447
+ break;
448
+ }
449
+
450
+ // Normal installation if directory has write permission
451
+ const { missing: missingTools, available: availableTools } = await installer.scanCLI();
452
+
453
+ if (Object.keys(missingTools).length === 0) {
454
+ console.log('[INFO] All AI CLI tools are already installed!');
455
+ console.log('\nAvailable tools:');
456
+ for (const [toolName, toolInfo] of Object.entries(availableTools)) {
457
+ console.log(` - ${toolInfo.name} (${toolName})`);
389
458
  }
390
459
  } else {
391
- console.log('\n[INFO] All required tools are already installed!');
460
+ console.log(`\n[INFO] Found ${Object.keys(missingTools).length} missing AI CLI tools:`);
461
+ for (const [toolName, toolInfo] of Object.entries(missingTools)) {
462
+ console.log(` - ${toolInfo.name}: ${toolInfo.install}`);
463
+ }
464
+
465
+ // 默认自动安装所有缺失的工具
466
+ console.log(`\n[AUTO-INSTALL] Installing ${Object.keys(missingTools).length} missing AI CLI tools...`);
467
+
468
+ const selectedTools = Object.keys(missingTools);
469
+
470
+ // Use EnhancedCLIInstaller with batch permission handling
471
+ const EnhancedCLIInstaller = require(path.resolve(__dirname, '../core/enhanced_cli_installer'));
472
+ const installer = new EnhancedCLIInstaller({
473
+ verbose: process.env.DEBUG === 'true',
474
+ autoRetry: true,
475
+ maxRetries: 2
476
+ });
477
+
478
+ console.log(`[INFO] Installing ${selectedTools.length} CLI tools with optimized permission handling...`);
479
+ const installResult = await installer.installTools(selectedTools, missingTools);
480
+
481
+ if (installResult) {
482
+ console.log(`\n[SUCCESS] Installed ${selectedTools.length} AI CLI tools!`);
483
+
484
+ // Check if any permissions were handled automatically
485
+ const installations = installer.results.installations || {};
486
+ const permissionHandledTools = Object.entries(installations)
487
+ .filter(([name, result]) => result.success && result.permissionHandled)
488
+ .map(([name]) => name);
489
+
490
+ if (permissionHandledTools.length > 0) {
491
+ console.log('✅ 权限问题已自动处理');
492
+ console.log(`🔧 自动提升权限安装了 ${permissionHandledTools.length} 个工具: ${permissionHandledTools.join(', ')}`);
493
+ }
494
+
495
+ // Show permission mode used
496
+ console.log(`🔧 权限模式: ${installResult.permissionMode}`);
497
+ } else {
498
+ console.log('\n[WARN] Some tools may not have installed successfully. Check the logs above for details.');
499
+
500
+ // Provide manual guidance for permission issues
501
+ const failedInstallations = installer.results.failedInstallations || [];
502
+ if (failedInstallations.length > 0) {
503
+ console.log('\n💡 如果遇到权限问题,请尝试:');
504
+ console.log(' Windows: 以管理员身份运行PowerShell,然后执行 stigmergy install');
505
+ console.log(' macOS/Linux: sudo stigmergy install');
506
+ }
507
+ }
392
508
  }
509
+
510
+ console.log('\n[INFO] Installation process completed.');
393
511
  } catch (error) {
394
- await errorHandler.logError(error, 'ERROR', 'main.install');
395
- console.log(`[ERROR] Installation failed: ${error.message}`);
512
+ console.error('[ERROR] Installation failed:', error.message);
513
+ if (process.env.DEBUG === 'true') {
514
+ console.error(error.stack);
515
+ }
396
516
  process.exit(1);
397
517
  }
398
518
  break;
@@ -432,7 +552,7 @@ async function main() {
432
552
  const whichCmd = process.platform === 'win32' ? 'where' : 'which';
433
553
  const whichResult = spawnSync(whichCmd, [route.tool], {
434
554
  encoding: 'utf8',
435
- timeout: 3000,
555
+ timeout: 10000,
436
556
  stdio: ['pipe', 'pipe', 'pipe'],
437
557
  shell: true,
438
558
  });
@@ -551,8 +671,16 @@ async function main() {
551
671
 
552
672
  // Special handling for Claude on Windows to bypass the wrapper script
553
673
  if (process.platform === 'win32' && route.tool === 'claude') {
554
- // Use the direct path to avoid the wrapper script that interferes with parameter passing
555
- execCommand = 'C:\\npm_global\\claude';
674
+ // Use detected path to avoid the wrapper script that interferes with parameter passing
675
+ const detectedPath = await getCLIPath('claude');
676
+ if (detectedPath) {
677
+ execCommand = detectedPath;
678
+ console.log(`[DEBUG] Using detected Claude path: ${execCommand}`);
679
+ } else {
680
+ execCommand = 'C:\\npm_global\\claude';
681
+ console.log(`[DEBUG] Using default Claude path: ${execCommand}`);
682
+ }
683
+
556
684
  if (toolArgs.length > 0) {
557
685
  const argsString = toolArgs.map(arg => {
558
686
  if (arg.includes(' ') && !(arg.startsWith('"') && arg.endsWith('"'))) {
@@ -566,11 +694,41 @@ async function main() {
566
694
  }
567
695
  }
568
696
 
569
- // Special handling for Copilot on Windows
570
- if (process.platform === 'win32' && route.tool === 'copilot') {
571
- // Use the direct path for Copilot as well
572
- execCommand = 'C:\\npm_global\\copilot';
573
- if (toolArgs.length > 0) {
697
+ // Use detected paths for all CLI tools on all platforms
698
+ const supportedTools = ['claude', 'copilot', 'qodercli', 'gemini', 'qwen', 'iflow', 'codebuddy', 'codex'];
699
+
700
+ if (supportedTools.includes(route.tool)) {
701
+ // Use detected path for all CLI tools regardless of platform
702
+ const detectedPath = await getCLIPath(route.tool);
703
+ if (detectedPath) {
704
+ execCommand = detectedPath;
705
+ console.log(`[DEBUG] Using detected ${route.tool} path: ${execCommand}`);
706
+ } else {
707
+ // Fallback to system PATH for tools not detected
708
+ console.log(`[DEBUG] Using system PATH for ${route.tool}: ${route.tool}`);
709
+ }
710
+ }
711
+
712
+ // Platform-specific command construction
713
+ if (process.platform === 'win32') {
714
+ // Special handling for Windows CLI tools
715
+ if (route.tool === 'claude' && toolArgs.length > 0) {
716
+ // Special parameter handling for Claude to avoid wrapper script issues
717
+ const argsString = toolArgs.map(arg => {
718
+ if (arg.includes(' ') && !(arg.startsWith('"') && arg.endsWith('"'))) {
719
+ return `"${arg}"`;
720
+ }
721
+ return arg;
722
+ }).join(' ');
723
+ execCommand = `${execCommand} ${argsString}`;
724
+ execArgs = [];
725
+ console.log(`[DEBUG] Windows ${route.tool} direct command: ${execCommand}`);
726
+ } else if (route.tool === 'copilot') {
727
+ // Copilot doesn't use -p parameter format
728
+ execArgs = [];
729
+ console.log(`[DEBUG] Windows ${route.tool} direct command: ${execCommand}`);
730
+ } else if (toolArgs.length > 0) {
731
+ // For other Windows tools, construct full command line
574
732
  const argsString = toolArgs.map(arg => {
575
733
  if (arg.includes(' ') && !(arg.startsWith('"') && arg.endsWith('"'))) {
576
734
  return `"${arg}"`;
@@ -579,7 +737,7 @@ async function main() {
579
737
  }).join(' ');
580
738
  execCommand = `${execCommand} ${argsString}`;
581
739
  execArgs = [];
582
- console.log(`[DEBUG] Windows direct Copilot command: ${execCommand}`);
740
+ console.log(`[DEBUG] Windows full command: ${execCommand}`);
583
741
  }
584
742
  }
585
743
 
@@ -678,11 +836,41 @@ async function main() {
678
836
  }
679
837
 
680
838
  case 'auto-install':
681
- // Auto-install mode for npm postinstall - NON-INTERACTIVE
839
+ // Auto-install mode for npm postinstall - NON-INTERACTIVE with permission awareness
682
840
  // Force immediate output visibility during npm install
841
+
842
+ // Detect npm environment for better output visibility
843
+ const isNpmPostinstall = process.env.npm_lifecycle_event === 'postinstall';
844
+
845
+ // Use stderr for critical messages in npm environment (more likely to be shown)
846
+ const criticalLog = isNpmPostinstall ? console.error : console.log;
847
+
848
+ criticalLog('🚀 STIGMERGY CLI AUTO-INSTALL STARTING');
849
+ criticalLog('='.repeat(60));
850
+ criticalLog('Installing cross-CLI integration and scanning for AI tools...');
851
+ criticalLog('='.repeat(60));
683
852
  console.log('[AUTO-INSTALL] Stigmergy CLI automated setup');
684
853
  console.log('='.repeat(60));
685
854
 
855
+ // Check directory permissions
856
+ const autoPermissionManager = new DirectoryPermissionManager({ verbose: process.env.DEBUG === 'true' });
857
+ const autoHasWritePermission = await autoPermissionManager.checkWritePermission();
858
+
859
+ if (!autoHasWritePermission && !process.env.STIGMERGY_SKIP_PERMISSION_CHECK) {
860
+ criticalLog('⚠️ Directory permission detected, setting up permission-aware installation...');
861
+
862
+ try {
863
+ const permResult = await autoPermissionManager.setupWorkingDirectory();
864
+ if (permResult.success) {
865
+ criticalLog('✅ Working directory configured with proper permissions');
866
+ } else {
867
+ criticalLog('⚠️ Could not configure working directory, continuing with limited functionality');
868
+ }
869
+ } catch (error) {
870
+ criticalLog(`⚠️ Permission setup failed: ${error.message}`);
871
+ }
872
+ }
873
+
686
874
  // Force stdout flush to ensure visibility during npm install
687
875
  if (process.stdout && process.stdout.write) {
688
876
  process.stdout.write('');
@@ -757,7 +945,77 @@ async function main() {
757
945
  console.log(` ✗ ${toolInfo.name} (${toolName})`);
758
946
  console.log(` Install with: ${toolInfo.installCommand}`);
759
947
  }
760
- console.log('\n[INFO] You can install missing tools with: stigmergy install');
948
+
949
+ // Check if auto-install is enabled for npm postinstall
950
+ const autoInstallEnabled = process.env.STIGMERGY_AUTO_INSTALL !== 'false';
951
+
952
+ if (autoInstallEnabled && !process.env.CI) {
953
+ console.log('\n[AUTO-INSTALL] Installing missing CLI tools automatically...');
954
+ console.log('[INFO] Set STIGMERGY_AUTO_INSTALL=false to disable this behavior');
955
+
956
+ try {
957
+ const selectedTools = Object.keys(autoMissing);
958
+
959
+ // Use EnhancedCLIInstaller with batch permission handling
960
+ const EnhancedCLIInstaller = require(path.resolve(__dirname, '../core/enhanced_cli_installer'));
961
+ const installer = new EnhancedCLIInstaller({
962
+ verbose: process.env.DEBUG === 'true',
963
+ autoRetry: true,
964
+ maxRetries: 2
965
+ });
966
+
967
+ console.log(`[INFO] Installing ${selectedTools.length} CLI tools with optimized permission handling...`);
968
+ const installResult = await installer.installTools(selectedTools, autoMissing);
969
+
970
+ if (installResult) {
971
+ console.log(`[SUCCESS] Auto-installed ${selectedTools.length} CLI tools!`);
972
+
973
+ // Check if permissions were handled automatically
974
+ const installations = installer.results.installations || {};
975
+ const permissionHandledTools = Object.entries(installations)
976
+ .filter(([name, result]) => result.success && result.permissionHandled)
977
+ .map(([name]) => name);
978
+
979
+ if (permissionHandledTools.length > 0) {
980
+ console.log('✅ 权限问题已自动处理');
981
+ console.log(`🔧 自动提升权限安装了 ${permissionHandledTools.length} 个工具: ${permissionHandledTools.join(', ')}`);
982
+ }
983
+
984
+ // Show permission mode used
985
+ console.log(`🔧 权限模式: ${installResult.permissionMode}`);
986
+ } else {
987
+ console.log('[WARN] Some tools may not have installed successfully');
988
+
989
+ // Provide manual guidance for permission issues
990
+ const failedInstallations = installer.results.failedInstallations || [];
991
+ if (failedInstallations.length > 0) {
992
+ console.log('\n💡 如果遇到权限问题,请尝试:');
993
+ console.log(' Windows: 以管理员身份运行PowerShell,然后执行 stigmergy install');
994
+ console.log(' macOS/Linux: sudo stigmergy install');
995
+ }
996
+ }
997
+ } catch (installError) {
998
+ console.log(`[ERROR] Auto-install failed: ${installError.message}`);
999
+ console.log('[INFO] You can manually install tools with: stigmergy install --auto');
1000
+
1001
+ // Check if it's a permission error
1002
+ const permissionIndicators = ['EACCES', 'EPERM', 'permission denied', 'access denied'];
1003
+ const isPermissionError = permissionIndicators.some(indicator =>
1004
+ installError.message.toLowerCase().includes(indicator.toLowerCase())
1005
+ );
1006
+
1007
+ if (isPermissionError) {
1008
+ console.log('\n💡 这看起来像是权限问题,请尝试:');
1009
+ console.log(' Windows: 以管理员身份运行PowerShell,然后执行 stigmergy install');
1010
+ console.log(' macOS/Linux: sudo stigmergy install');
1011
+ }
1012
+ }
1013
+ } else {
1014
+ console.log('\n[INFO] You can install missing tools with: stigmergy install --auto');
1015
+ if (process.env.CI) {
1016
+ console.log('[CI] Auto-install disabled in CI environment');
1017
+ }
1018
+ }
761
1019
  }
762
1020
 
763
1021
  console.log('\n[USAGE] Get started with these commands:');
@@ -864,6 +1122,75 @@ async function main() {
864
1122
  }
865
1123
  break;
866
1124
 
1125
+ // Skill命令简化别名
1126
+ case 'skill-i': // install
1127
+ case 'skill-l': // list
1128
+ case 'skill-v': // validate/read
1129
+ case 'skill-r': // read
1130
+ case 'skill-d': // remove/delete
1131
+ case 'skill-m': // remove (移除)
1132
+ case 'skill': {
1133
+ try {
1134
+ // Skill命令通过桥接器调用ES模块
1135
+ const { handleSkillCommand } = require('../commands/skill-handler');
1136
+
1137
+ // 处理简化命令
1138
+ let skillAction;
1139
+ let skillArgs;
1140
+
1141
+ switch (command) {
1142
+ case 'skill-i':
1143
+ skillAction = 'install';
1144
+ skillArgs = args.slice(1);
1145
+ break;
1146
+ case 'skill-l':
1147
+ skillAction = 'list';
1148
+ skillArgs = args.slice(1);
1149
+ break;
1150
+ case 'skill-v':
1151
+ // skill-v可以是validate或read,根据参数判断
1152
+ skillAction = args[1] && (args[1].endsWith('.md') || args[1].includes('/') || args[1].includes('\\'))
1153
+ ? 'validate'
1154
+ : 'read';
1155
+ skillArgs = args.slice(1);
1156
+ break;
1157
+ case 'skill-r':
1158
+ skillAction = 'read';
1159
+ skillArgs = args.slice(1);
1160
+ break;
1161
+ case 'skill-d':
1162
+ case 'skill-m':
1163
+ skillAction = 'remove';
1164
+ skillArgs = args.slice(1);
1165
+ break;
1166
+ default:
1167
+ // 标准skill命令
1168
+ skillAction = args[1];
1169
+ skillArgs = args.slice(2);
1170
+
1171
+ // 如果没有子命令,默认执行sync
1172
+ if (!skillAction) {
1173
+ skillAction = 'sync';
1174
+ skillArgs = [];
1175
+ }
1176
+ }
1177
+
1178
+ const skillOptions = {
1179
+ force: args.includes('--force'),
1180
+ verbose: args.includes('--verbose'),
1181
+ autoSync: !args.includes('--no-auto-sync')
1182
+ };
1183
+
1184
+ const exitCode = await handleSkillCommand(skillAction, skillArgs, skillOptions);
1185
+ process.exit(exitCode || 0);
1186
+ } catch (error) {
1187
+ await errorHandler.logError(error, 'ERROR', 'main.skill');
1188
+ console.error(`[ERROR] Skill command failed: ${error.message}`);
1189
+ process.exit(1);
1190
+ }
1191
+ break;
1192
+ }
1193
+
867
1194
  case 'clean':
868
1195
  case 'c': {
869
1196
  try {
@@ -982,6 +1309,71 @@ async function main() {
982
1309
  break;
983
1310
  }
984
1311
 
1312
+ case 'fix-perms': {
1313
+ try {
1314
+ console.log('[FIX-PERMS] Setting up working directory with proper permissions...\n');
1315
+
1316
+ const permAwareInstaller = new PermissionAwareInstaller({
1317
+ verbose: process.env.DEBUG === 'true',
1318
+ skipPermissionCheck: false,
1319
+ autoConfigureShell: true
1320
+ });
1321
+
1322
+ const result = await permAwareInstaller.install();
1323
+
1324
+ if (result.success) {
1325
+ console.log('\n✅ Permission setup completed successfully!');
1326
+ permAwareInstaller.permissionManager.displayResults(result.permissionSetup);
1327
+ } else {
1328
+ console.log('\n❌ Permission setup failed');
1329
+ console.log(`Error: ${result.error || 'Unknown error'}`);
1330
+ process.exit(1);
1331
+ }
1332
+
1333
+ } catch (error) {
1334
+ console.error('[ERROR] Permission setup failed:', error.message);
1335
+ if (process.env.DEBUG === 'true') {
1336
+ console.error(error.stack);
1337
+ }
1338
+ process.exit(1);
1339
+ }
1340
+ break;
1341
+ }
1342
+
1343
+ case 'perm-check': {
1344
+ try {
1345
+ console.log('[PERM-CHECK] Checking current directory permissions...\n');
1346
+
1347
+ const permissionManager = new DirectoryPermissionManager({ verbose: process.env.DEBUG === 'true' });
1348
+ const hasWritePermission = await permissionManager.checkWritePermission();
1349
+
1350
+ console.log(`📍 Current directory: ${process.cwd()}`);
1351
+ console.log(`🔧 Write permission: ${hasWritePermission ? '✅ Yes' : '❌ No'}`);
1352
+
1353
+ if (!hasWritePermission) {
1354
+ console.log('\n💡 Suggestions:');
1355
+ console.log('1. Run: stigmergy fix-perms # Fix permissions automatically');
1356
+ console.log('2. Change to user directory: cd ~');
1357
+ console.log('3. Create project directory: mkdir ~/stigmergy && cd ~/stigmergy');
1358
+ console.log('\n🔍 System Info:');
1359
+ const sysInfo = permissionManager.getSystemInfo();
1360
+ console.log(` Platform: ${sysInfo.platform}`);
1361
+ console.log(` Shell: ${sysInfo.shell}`);
1362
+ console.log(` Home: ${sysInfo.homeDir}`);
1363
+ } else {
1364
+ console.log('\n✅ Current directory is ready for installation');
1365
+ }
1366
+
1367
+ } catch (error) {
1368
+ console.error('[ERROR] Permission check failed:', error.message);
1369
+ if (process.env.DEBUG === 'true') {
1370
+ console.error(error.stack);
1371
+ }
1372
+ process.exit(1);
1373
+ }
1374
+ break;
1375
+ }
1376
+
985
1377
  default:
986
1378
  // Check if the command matches a direct CLI tool name
987
1379
  if (CLI_TOOLS[command]) {
@@ -1016,7 +1408,7 @@ async function main() {
1016
1408
  const whichCmd = process.platform === 'win32' ? 'where' : 'which';
1017
1409
  const whichResult = spawnSync(whichCmd, [toolName], {
1018
1410
  encoding: 'utf8',
1019
- timeout: 3000,
1411
+ timeout: 10000,
1020
1412
  stdio: ['pipe', 'pipe', 'pipe'],
1021
1413
  shell: true,
1022
1414
  });
@@ -1136,11 +1528,26 @@ async function main() {
1136
1528
  }
1137
1529
  }
1138
1530
 
1139
- // Special handling for Claude on Windows to bypass the wrapper script
1140
- if (process.platform === 'win32' && route.tool === 'claude') {
1141
- // Use the direct path to avoid the wrapper script that interferes with parameter passing
1142
- execCommand = 'C:\\npm_global\\claude';
1143
- if (toolArgs.length > 0) {
1531
+ // Use detected paths for all CLI tools on all platforms
1532
+ const supportedTools = ['claude', 'copilot', 'qodercli', 'gemini', 'qwen', 'iflow', 'codebuddy', 'codex'];
1533
+
1534
+ if (supportedTools.includes(route.tool)) {
1535
+ // Use detected path for all CLI tools regardless of platform
1536
+ const detectedPath = await getCLIPath(route.tool);
1537
+ if (detectedPath) {
1538
+ execCommand = detectedPath;
1539
+ console.log(`[DEBUG] Using detected ${route.tool} path: ${execCommand}`);
1540
+ } else {
1541
+ // Fallback to system PATH for tools not detected
1542
+ console.log(`[DEBUG] Using system PATH for ${route.tool}: ${route.tool}`);
1543
+ }
1544
+ }
1545
+
1546
+ // Platform-specific command construction
1547
+ if (process.platform === 'win32') {
1548
+ // Special handling for Windows CLI tools
1549
+ if (route.tool === 'claude' && toolArgs.length > 0) {
1550
+ // Special parameter handling for Claude to avoid wrapper script issues
1144
1551
  const argsString = toolArgs.map(arg => {
1145
1552
  if (arg.includes(' ') && !(arg.startsWith('"') && arg.endsWith('"'))) {
1146
1553
  return `"${arg}"`;
@@ -1149,15 +1556,13 @@ async function main() {
1149
1556
  }).join(' ');
1150
1557
  execCommand = `${execCommand} ${argsString}`;
1151
1558
  execArgs = [];
1152
- console.log(`[DEBUG] Windows direct Claude command: ${execCommand}`);
1153
- }
1154
- }
1155
-
1156
- // Special handling for Copilot on Windows
1157
- if (process.platform === 'win32' && route.tool === 'copilot') {
1158
- // Use the direct path for Copilot as well
1159
- execCommand = 'C:\\npm_global\\copilot';
1160
- if (toolArgs.length > 0) {
1559
+ console.log(`[DEBUG] Windows ${route.tool} direct command: ${execCommand}`);
1560
+ } else if (route.tool === 'copilot') {
1561
+ // Copilot doesn't use -p parameter format
1562
+ execArgs = [];
1563
+ console.log(`[DEBUG] Windows ${route.tool} direct command: ${execCommand}`);
1564
+ } else if (toolArgs.length > 0) {
1565
+ // For other Windows tools, construct full command line
1161
1566
  const argsString = toolArgs.map(arg => {
1162
1567
  if (arg.includes(' ') && !(arg.startsWith('"') && arg.endsWith('"'))) {
1163
1568
  return `"${arg}"`;
@@ -1166,10 +1571,11 @@ async function main() {
1166
1571
  }).join(' ');
1167
1572
  execCommand = `${execCommand} ${argsString}`;
1168
1573
  execArgs = [];
1169
- console.log(`[DEBUG] Windows direct Copilot command: ${execCommand}`);
1574
+ console.log(`[DEBUG] Windows full command: ${execCommand}`);
1170
1575
  }
1171
1576
  }
1172
1577
 
1578
+
1173
1579
  // Apply the same Windows handling logic to ensure consistency
1174
1580
  // This ensures consistency between direct routing and call command routing
1175
1581
  if (process.platform === 'win32' && execArgs.length > 0) {