stigmergy 1.2.6 → 1.2.10

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 (82) hide show
  1. package/README.md +69 -20
  2. package/STIGMERGY.md +26 -7
  3. package/docs/MULTI_USER_WIKI_COLLABORATION_SYSTEM.md +523 -0
  4. package/docs/PROMPT_BASED_SKILLS_SYSTEM_DESIGN.md +458 -0
  5. package/docs/SKILL_IMPLEMENTATION_CONSTRAINTS_AND_ALIGNMENT.md +423 -0
  6. package/docs/TECHNICAL_FEASIBILITY_ANALYSIS.md +308 -0
  7. package/examples/multilingual-hook-demo.js +125 -0
  8. package/package.json +30 -19
  9. package/scripts/dependency-analyzer.js +101 -0
  10. package/scripts/generate-cli-docs.js +64 -0
  11. package/scripts/postuninstall.js +46 -0
  12. package/scripts/preuninstall.js +85 -0
  13. package/scripts/run-layered-tests.js +3 -3
  14. package/src/adapters/claude/install_claude_integration.js +37 -37
  15. package/src/adapters/codebuddy/install_codebuddy_integration.js +66 -63
  16. package/src/adapters/codex/install_codex_integration.js +54 -55
  17. package/src/adapters/copilot/install_copilot_integration.js +46 -46
  18. package/src/adapters/gemini/install_gemini_integration.js +68 -68
  19. package/src/adapters/iflow/install_iflow_integration.js +77 -77
  20. package/src/adapters/qoder/install_qoder_integration.js +76 -76
  21. package/src/adapters/qwen/install_qwen_integration.js +23 -23
  22. package/src/cli/router.js +713 -163
  23. package/src/commands/skill-bridge.js +39 -0
  24. package/src/commands/skill-handler.js +150 -0
  25. package/src/commands/skill.js +127 -0
  26. package/src/core/cache_cleaner.js +767 -767
  27. package/src/core/cli_help_analyzer.js +680 -680
  28. package/src/core/cli_parameter_handler.js +132 -132
  29. package/src/core/cli_path_detector.js +573 -0
  30. package/src/core/cli_tools.js +160 -89
  31. package/src/core/coordination/index.js +16 -16
  32. package/src/core/coordination/nodejs/AdapterManager.js +130 -102
  33. package/src/core/coordination/nodejs/CLCommunication.js +132 -132
  34. package/src/core/coordination/nodejs/CLIIntegrationManager.js +272 -272
  35. package/src/core/coordination/nodejs/HealthChecker.js +76 -76
  36. package/src/core/coordination/nodejs/HookDeploymentManager.js +463 -274
  37. package/src/core/coordination/nodejs/StatisticsCollector.js +71 -71
  38. package/src/core/coordination/nodejs/index.js +90 -90
  39. package/src/core/coordination/nodejs/utils/Logger.js +29 -29
  40. package/src/core/directory_permission_manager.js +568 -0
  41. package/src/core/enhanced_cli_installer.js +609 -0
  42. package/src/core/error_handler.js +406 -406
  43. package/src/core/installer.js +263 -119
  44. package/src/core/memory_manager.js +83 -83
  45. package/src/core/multilingual/language-pattern-manager.js +200 -0
  46. package/src/core/persistent_shell_configurator.js +468 -0
  47. package/src/core/rest_client.js +160 -160
  48. package/src/core/skills/StigmergySkillManager.js +357 -0
  49. package/src/core/skills/__tests__/SkillInstaller.test.js +275 -0
  50. package/src/core/skills/__tests__/SkillParser.test.js +202 -0
  51. package/src/core/skills/__tests__/SkillReader.test.js +189 -0
  52. package/src/core/skills/cli-command-test.js +201 -0
  53. package/src/core/skills/comprehensive-e2e-test.js +473 -0
  54. package/src/core/skills/e2e-test.js +267 -0
  55. package/src/core/skills/embedded-openskills/SkillInstaller.js +438 -0
  56. package/src/core/skills/embedded-openskills/SkillParser.js +123 -0
  57. package/src/core/skills/embedded-openskills/SkillReader.js +143 -0
  58. package/src/core/skills/integration-test.js +248 -0
  59. package/src/core/skills/package.json +6 -0
  60. package/src/core/skills/regression-test.js +285 -0
  61. package/src/core/skills/run-all-tests.js +129 -0
  62. package/src/core/skills/sync-test.js +210 -0
  63. package/src/core/skills/test-runner.js +242 -0
  64. package/src/core/smart_router.js +261 -249
  65. package/src/core/upgrade_manager.js +48 -20
  66. package/src/index.js +30 -30
  67. package/src/test/cli-availability-checker.js +194 -194
  68. package/src/test/test-environment.js +289 -289
  69. package/src/utils/helpers.js +18 -35
  70. package/src/utils.js +921 -921
  71. package/src/weatherProcessor.js +228 -228
  72. package/test/multilingual/hook-deployment.test.js +91 -0
  73. package/test/multilingual/language-pattern-manager.test.js +140 -0
  74. package/test/multilingual/system-test.js +85 -0
  75. package/src/auth.js +0 -173
  76. package/src/auth_command.js +0 -208
  77. package/src/calculator.js +0 -313
  78. package/src/core/enhanced_installer.js +0 -479
  79. package/src/core/enhanced_uninstaller.js +0 -638
  80. package/src/data_encryption.js +0 -143
  81. package/src/data_structures.js +0 -440
  82. package/src/deploy.js +0 -55
package/src/cli/router.js CHANGED
@@ -16,6 +16,11 @@ const chalk = require('chalk');
16
16
  const yaml = require('js-yaml');
17
17
  const fs = require('fs/promises');
18
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');
19
24
 
20
25
  // Import our custom modules
21
26
  const SmartRouter = require('../core/smart_router');
@@ -23,7 +28,6 @@ const CLIHelpAnalyzer = require('../core/cli_help_analyzer');
23
28
  const { CLI_TOOLS } = require('../core/cli_tools');
24
29
  const { errorHandler } = require('../core/error_handler');
25
30
  const { executeCommand, executeJSFile } = require('../utils');
26
- const { UserAuthenticator } = require('../auth');
27
31
  const MemoryManager = require('../core/memory_manager');
28
32
  const StigmergyInstaller = require('../core/installer');
29
33
  const UpgradeManager = require('../core/upgrade_manager');
@@ -71,17 +75,26 @@ async function main() {
71
75
  console.log(' version, --version Show version information');
72
76
  console.log(' status Check CLI tools status');
73
77
  console.log(' scan Scan for available AI CLI tools');
74
- console.log(' install Auto-install missing CLI tools');
78
+ console.log(' install Auto-install missing CLI tools (with permission fix)');
75
79
  console.log(' upgrade Upgrade all CLI tools to latest versions');
76
80
  console.log(
77
81
  ' deploy Deploy hooks and integration to installed tools',
78
82
  );
79
83
  console.log(' setup Complete setup and configuration');
80
84
  console.log(
81
- ' init Initialize Stigmergy configuration (alias for setup)',
85
+ ' init Initialize Stigmergy project in current directory',
82
86
  );
83
87
  console.log(' clean (c) Clean temporary files and caches');
84
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)');
85
98
  console.log(' call "<prompt>" Execute prompt with auto-routed AI CLI');
86
99
  console.log(' <tool> "<prompt>" Directly route to specific AI CLI tool');
87
100
  console.log(' Supported tools: claude, gemini, qwen, iflow, qodercli, codebuddy, copilot, codex');
@@ -125,52 +138,106 @@ async function main() {
125
138
  break;
126
139
 
127
140
  case 'init':
128
- // Alias for setup command
129
- console.log('[INIT] Initializing Stigmergy CLI...');
130
- // 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;
131
169
 
132
170
  case 'setup':
133
171
  try {
134
172
  console.log('[SETUP] Starting complete Stigmergy setup...\n');
135
173
 
136
- // Step 1: Download required assets
137
- 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();
138
177
 
139
- // 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...');
140
199
  const { available: setupAvailable, missing: setupMissing } =
141
200
  await installer.scanCLI();
142
- const setupOptions = await installer.showInstallOptions(setupMissing);
143
-
144
- // Step 3: Install missing CLI tools if user chooses
145
- if (setupOptions.length > 0) {
146
- const selectedTools = await installer.getUserSelection(
147
- setupOptions,
148
- setupMissing,
149
- );
150
- if (selectedTools.length > 0) {
151
- console.log(
152
- '\n[INFO] Installing selected tools (this may take several minutes for tools that download binaries)...',
153
- );
154
- 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}`);
155
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}`);
213
+ }
214
+
215
+ console.log('\n[INFO] Or use the enhanced installer:');
216
+ console.log(' node src/core/enhanced_installer.js');
156
217
  } else {
157
- console.log('\n[INFO] All required tools are already installed!');
218
+ console.log('\n[STEP 2] All required tools are already installed!');
158
219
  }
159
220
 
160
- // Step 4: Deploy hooks to available CLI tools
161
- await installer.deployHooks(setupAvailable);
162
-
163
- // Step 5: Deploy project documentation
164
- await installer.deployProjectDocumentation();
165
-
166
- // Step 6: Initialize configuration
167
- 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
+ }
168
228
 
169
- // Step 7: Show usage instructions
170
- 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
+
171
236
  } catch (error) {
172
- await errorHandler.logError(error, 'ERROR', 'main.setup');
173
- 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
+ }
174
241
  console.log('\n[TROUBLESHOOTING] To manually complete setup:');
175
242
  console.log('1. Run: stigmergy deploy # Deploy hooks manually');
176
243
  console.log('2. Run: stigmergy setup # Try setup again');
@@ -221,146 +288,129 @@ async function main() {
221
288
 
222
289
  case 'upgrade': {
223
290
  try {
224
- console.log('[UPGRADE] Starting CLI tools upgrade process...');
225
- const upgrader = new UpgradeManager();
226
- await upgrader.initialize();
227
-
291
+ console.log('[UPGRADE] Starting AI CLI tools upgrade process...\n');
292
+
228
293
  // č§£ęžå‘½ä»¤č”Œé€‰é”¹
229
294
  const upgradeArgs = args.slice(1);
230
295
  const options = {
231
296
  dryRun: upgradeArgs.includes('--dry-run'),
232
297
  force: upgradeArgs.includes('--force'),
233
- verbose: upgradeArgs.includes('--verbose'),
234
- diagnose: upgradeArgs.includes('--diagnose'),
235
- suggest: upgradeArgs.includes('--suggest')
298
+ verbose: upgradeArgs.includes('--verbose')
236
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
+ });
237
308
 
238
- if (options.diagnose) {
239
- console.log('\nšŸ” DIAGNOSTIC MODE - Checking for issues...\n');
240
- const deprecations = await upgrader.checkDeprecations();
309
+ // čŽ·å–å·²å®‰č£…ēš„å·„å…·åˆ—č”Ø - 使用全局installerę‰«ę
310
+ const { available: installedTools } = await installer.scanCLI();
241
311
 
242
- if (deprecations.length === 0) {
243
- console.log('āœ… No issues detected.');
244
- } else {
245
- console.log('āŒ Issues found:');
246
- deprecations.forEach((dep, index) => {
247
- console.log(`\n${index + 1}. ${dep.type || 'Unknown'}`);
248
- if (dep.dependency) console.log(` Dependency: ${dep.dependency}`);
249
- console.log(` Issues: ${dep.issues.join(', ')}`);
250
- });
251
- }
312
+ if (Object.keys(installedTools).length === 0) {
313
+ console.log('[INFO] No AI CLI tools found. Please install tools first with: stigmergy install');
252
314
  break;
253
315
  }
254
316
 
255
- if (options.suggest) {
256
- console.log('\nšŸ’” SUGGESTION MODE - Generating recommendations...\n');
257
- const plan = await upgrader.generateUpgradePlan(options);
258
-
259
- console.log('šŸ“‹ Recommendations:');
260
- if (plan.upgrades.length > 0) {
261
- console.log('\nšŸ”ŗ Available Upgrades:');
262
- plan.upgrades.forEach(upgrade => {
263
- console.log(` • ${upgrade.tool}: ${upgrade.from} → ${upgrade.to}`);
264
- });
265
- }
266
-
267
- if (plan.fixes.length > 0) {
268
- console.log('\nšŸ”§ Recommended Fixes:');
269
- plan.fixes.forEach(fix => {
270
- console.log(` • ${fix.type}: ${fix.description}`);
271
- });
272
- }
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
+ }
273
321
 
274
- if (plan.upgrades.length === 0 && plan.fixes.length === 0) {
275
- console.log('āœ… Everything is up to date!');
276
- }
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');
277
325
  break;
278
326
  }
279
327
 
280
- // ē”Ÿęˆå‡ēŗ§č®”åˆ’
281
- console.log('\nšŸ“‹ Generating upgrade plan...\n');
282
- 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');
283
331
 
284
- // ę˜¾ē¤ŗč®”åˆ’
285
- console.log('šŸ“Š UPGRADE PLAN');
286
- console.log('='.repeat(50));
332
+ console.log('\nšŸš€ Upgrading AI CLI tools with automatic permission handling...\n');
287
333
 
288
- if (plan.upgrades.length > 0) {
289
- console.log('\nšŸ”ŗ CLI Tool Upgrades:');
290
- plan.upgrades.forEach(upgrade => {
291
- console.log(` • ${upgrade.tool.padEnd(12)} ${upgrade.from} → ${upgrade.to}`);
292
- });
293
- } else {
294
- console.log('\nāœ… All CLI tools are up to date');
295
- }
334
+ // ę‰¹é‡å‡ēŗ§ę‰€ęœ‰å·„å…·ļ¼Œäø€ę¬”ęƒé™ę£€ęµ‹
335
+ console.log(`[INFO] Starting batch upgrade of ${Object.keys(installedTools).length} tools...`);
296
336
 
297
- if (plan.fixes.length > 0) {
298
- console.log('\nšŸ”§ Issues to Fix:');
299
- plan.fixes.forEach(fix => {
300
- console.log(` • ${fix.type}: ${fix.description}`);
301
- });
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
+ };
302
344
  }
303
345
 
304
- if (plan.warnings.length > 0) {
305
- console.log('\nāš ļø Warnings:');
306
- plan.warnings.forEach(warning => {
307
- console.log(` • ${warning.tool || 'Unknown'}: ${warning.error}`);
308
- });
309
- }
346
+ const upgradeResult = await enhancedInstaller.upgradeTools(
347
+ Object.keys(installedTools),
348
+ upgradeToolInfos
349
+ );
310
350
 
311
- if (options.dryRun) {
312
- console.log('\nšŸ” DRY RUN MODE - No changes will be made');
313
- console.log(' Use --force to execute the upgrade plan');
314
- break;
315
- }
351
+ // ę•“ē†ē»“ęžœ
352
+ const results = {
353
+ successful: [],
354
+ failed: [],
355
+ permissionHandled: []
356
+ };
316
357
 
317
- // ē”®č®¤ę‰§č”Œ
318
- if (!options.force) {
319
- const { confirm } = await inquirer.prompt([{
320
- type: 'confirm',
321
- name: 'confirm',
322
- message: 'Do you want to proceed with this upgrade plan?',
323
- default: false
324
- }]);
325
-
326
- if (!confirm) {
327
- console.log('\nāŒ Upgrade cancelled by user');
328
- 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
+ });
329
369
  }
330
370
  }
331
-
332
- // ę‰§č”Œå‡ēŗ§
333
- console.log('\nšŸš€ Executing upgrade plan...\n');
334
- const results = await upgrader.executeUpgrade(plan, options);
335
-
371
+
336
372
  // ę˜¾ē¤ŗē»“ęžœ
337
373
  console.log('\nšŸ“Š UPGRADE RESULTS');
338
374
  console.log('='.repeat(50));
339
375
 
340
376
  if (results.successful.length > 0) {
341
377
  console.log(`\nāœ… Successful (${results.successful.length}):`);
342
- results.successful.forEach(result => {
343
- const name = result.tool || result.type;
344
- 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}`);
345
387
  });
346
388
  }
347
389
 
348
390
  if (results.failed.length > 0) {
349
391
  console.log(`\nāŒ Failed (${results.failed.length}):`);
350
392
  results.failed.forEach(result => {
351
- const name = result.tool || result.type;
352
- console.log(` • ${name}: ${result.error}`);
393
+ console.log(` • ${result.tool}: ${result.error}`);
353
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
+ }
354
402
  }
355
403
 
356
- // 记录旄志
357
- await upgrader.logUpgrade(plan, results);
404
+ if (results.permissionHandled.length > 0) {
405
+ console.log('\nāœ… ęƒé™é—®é¢˜å·²č‡ŖåŠØå¤„ē†');
406
+ console.log(`šŸ”§ č‡ŖåŠØęå‡ęƒé™å‡ēŗ§äŗ† ${results.permissionHandled.length} äøŖå·„å…·`);
407
+ }
358
408
 
359
409
  console.log('\nšŸŽ‰ Upgrade process completed!');
360
-
410
+
361
411
  } catch (error) {
362
412
  console.error('[ERROR] Upgrade failed:', error.message);
363
- if (options.verbose) {
413
+ if (process.env.DEBUG === 'true') {
364
414
  console.error(error.stack);
365
415
  }
366
416
  process.exit(1);
@@ -368,30 +418,101 @@ async function main() {
368
418
  break;
369
419
  }
370
420
 
371
- case 'install':
421
+ case 'install':
372
422
  case 'inst':
373
423
  try {
374
424
  console.log('[INSTALL] Starting AI CLI tools installation...');
375
- const { missing: missingTools } = await installer.scanCLI();
376
- const options = await installer.showInstallOptions(missingTools);
377
425
 
378
- if (options.length > 0) {
379
- const selectedTools = await installer.getUserSelection(
380
- options,
381
- missingTools,
382
- );
383
- if (selectedTools.length > 0) {
384
- console.log(
385
- '\n[INFO] Installing selected tools (this may take several minutes for tools that download binaries)...',
386
- );
387
- 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})`);
388
458
  }
389
459
  } else {
390
- 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
+ }
391
508
  }
509
+
510
+ console.log('\n[INFO] Installation process completed.');
392
511
  } catch (error) {
393
- await errorHandler.logError(error, 'ERROR', 'main.install');
394
- 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
+ }
395
516
  process.exit(1);
396
517
  }
397
518
  break;
@@ -425,8 +546,27 @@ async function main() {
425
546
 
426
547
  // Execute the routed command
427
548
  try {
428
- // Get the actual executable path for the tool
429
- const toolPath = route.tool;
549
+ // Get the actual executable path for the tool using which/where command
550
+ let toolPath = route.tool;
551
+ try {
552
+ const whichCmd = process.platform === 'win32' ? 'where' : 'which';
553
+ const whichResult = spawnSync(whichCmd, [route.tool], {
554
+ encoding: 'utf8',
555
+ timeout: 10000,
556
+ stdio: ['pipe', 'pipe', 'pipe'],
557
+ shell: true,
558
+ });
559
+
560
+ if (whichResult.status === 0 && whichResult.stdout.trim()) {
561
+ // Get the first match (most likely the one that would be executed)
562
+ toolPath = whichResult.stdout.trim().split('\n')[0].trim();
563
+ }
564
+ } catch (whichError) {
565
+ // If which/where fails, continue with the tool name
566
+ if (process.env.DEBUG === 'true') {
567
+ console.log(`[DEBUG] which/where command failed for ${route.tool}: ${whichError.message}`);
568
+ }
569
+ }
430
570
 
431
571
  // SPECIAL TEST CASE: Simulate a non-existent tool for testing
432
572
  // This is for demonstration purposes only
@@ -508,7 +648,116 @@ async function main() {
508
648
  if (process.env.DEBUG === 'true') {
509
649
  console.log(`[EXEC] Running: ${toolPath} ${toolArgs.join(' ')}`);
510
650
  }
511
- const result = await executeCommand(toolPath, toolArgs, {
651
+
652
+ // Special handling for Windows to construct the command properly
653
+ let execCommand = toolPath;
654
+ let execArgs = toolArgs;
655
+ if (process.platform === 'win32') {
656
+ // On Windows, we construct the full command line and pass it as a single string
657
+ if (toolArgs.length > 0) {
658
+ // For Windows, we need to properly quote the entire command line
659
+ const argsString = toolArgs.map(arg => {
660
+ // If arg contains spaces and is not already quoted, quote it
661
+ if (arg.includes(' ') && !(arg.startsWith('"') && arg.endsWith('"'))) {
662
+ return `"${arg}"`;
663
+ }
664
+ return arg;
665
+ }).join(' ');
666
+ execCommand = `${toolPath} ${argsString}`;
667
+ execArgs = [];
668
+ console.log(`[DEBUG] Windows full command: ${execCommand}`);
669
+ }
670
+ }
671
+
672
+ // Special handling for Claude on Windows to bypass the wrapper script
673
+ if (process.platform === 'win32' && route.tool === '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
+
684
+ if (toolArgs.length > 0) {
685
+ const argsString = toolArgs.map(arg => {
686
+ if (arg.includes(' ') && !(arg.startsWith('"') && arg.endsWith('"'))) {
687
+ return `"${arg}"`;
688
+ }
689
+ return arg;
690
+ }).join(' ');
691
+ execCommand = `${execCommand} ${argsString}`;
692
+ execArgs = [];
693
+ console.log(`[DEBUG] Windows direct Claude command: ${execCommand}`);
694
+ }
695
+ }
696
+
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
732
+ const argsString = toolArgs.map(arg => {
733
+ if (arg.includes(' ') && !(arg.startsWith('"') && arg.endsWith('"'))) {
734
+ return `"${arg}"`;
735
+ }
736
+ return arg;
737
+ }).join(' ');
738
+ execCommand = `${execCommand} ${argsString}`;
739
+ execArgs = [];
740
+ console.log(`[DEBUG] Windows full command: ${execCommand}`);
741
+ }
742
+ }
743
+
744
+ // Apply the same Windows handling logic to ensure consistency
745
+ // This ensures consistency between direct routing and call command routing
746
+ if (process.platform === 'win32' && execArgs.length > 0) {
747
+ // For Windows, we need to properly quote the entire command line
748
+ const argsString = execArgs.map(arg => {
749
+ // If arg contains spaces and is not already quoted, quote it
750
+ if (arg.includes(' ') && !(arg.startsWith('"') && arg.endsWith('"'))) {
751
+ return `"${arg}"`;
752
+ }
753
+ return arg;
754
+ }).join(' ');
755
+ execCommand = `${execCommand} ${argsString}`;
756
+ execArgs = [];
757
+ console.log(`[DEBUG] Windows unified command: ${execCommand}`);
758
+ }
759
+
760
+ const result = await executeCommand(execCommand, execArgs, {
512
761
  stdio: 'inherit',
513
762
  shell: true,
514
763
  });
@@ -587,11 +836,41 @@ async function main() {
587
836
  }
588
837
 
589
838
  case 'auto-install':
590
- // Auto-install mode for npm postinstall - NON-INTERACTIVE
839
+ // Auto-install mode for npm postinstall - NON-INTERACTIVE with permission awareness
591
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));
592
852
  console.log('[AUTO-INSTALL] Stigmergy CLI automated setup');
593
853
  console.log('='.repeat(60));
594
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
+
595
874
  // Force stdout flush to ensure visibility during npm install
596
875
  if (process.stdout && process.stdout.write) {
597
876
  process.stdout.write('');
@@ -666,7 +945,77 @@ async function main() {
666
945
  console.log(` āœ— ${toolInfo.name} (${toolName})`);
667
946
  console.log(` Install with: ${toolInfo.installCommand}`);
668
947
  }
669
- 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
+ }
670
1019
  }
671
1020
 
672
1021
  console.log('\n[USAGE] Get started with these commands:');
@@ -773,6 +1122,75 @@ async function main() {
773
1122
  }
774
1123
  break;
775
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
+
776
1194
  case 'clean':
777
1195
  case 'c': {
778
1196
  try {
@@ -880,7 +1298,8 @@ async function main() {
880
1298
  console.log('\nšŸ“‹ Advanced Options:');
881
1299
  console.log(' • stigmergy clean --all - Clean all caches');
882
1300
  console.log(' • stigmergy clean --dry-run - Preview cleaning');
883
- console.log(' • npm run uninstall - Uninstall Stigmergy completely');
1301
+ console.log(' • npm uninstall -g stigmergy - Uninstall Stigmergy completely (runs enhanced cleanup)');
1302
+ console.log(' • See remaining items after uninstall (individual CLI tools, docs, etc.)');
884
1303
  }
885
1304
 
886
1305
  } catch (error) {
@@ -890,6 +1309,71 @@ async function main() {
890
1309
  break;
891
1310
  }
892
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
+
893
1377
  default:
894
1378
  // Check if the command matches a direct CLI tool name
895
1379
  if (CLI_TOOLS[command]) {
@@ -918,8 +1402,27 @@ async function main() {
918
1402
 
919
1403
  // Execute the routed command (reusing the call command logic)
920
1404
  try {
921
- // Get the actual executable path for the tool
922
- const toolPath = toolName;
1405
+ // Get the actual executable path for the tool using which/where command
1406
+ let toolPath = toolName;
1407
+ try {
1408
+ const whichCmd = process.platform === 'win32' ? 'where' : 'which';
1409
+ const whichResult = spawnSync(whichCmd, [toolName], {
1410
+ encoding: 'utf8',
1411
+ timeout: 10000,
1412
+ stdio: ['pipe', 'pipe', 'pipe'],
1413
+ shell: true,
1414
+ });
1415
+
1416
+ if (whichResult.status === 0 && whichResult.stdout.trim()) {
1417
+ // Get the first match (most likely the one that would be executed)
1418
+ toolPath = whichResult.stdout.trim().split('\n')[0].trim();
1419
+ }
1420
+ } catch (whichError) {
1421
+ // If which/where fails, continue with the tool name
1422
+ if (process.env.DEBUG === 'true') {
1423
+ console.log(`[DEBUG] which/where command failed for ${toolName}: ${whichError.message}`);
1424
+ }
1425
+ }
923
1426
 
924
1427
  console.log(`[DEBUG] Tool path: ${toolPath}, Prompt: ${route.prompt}`);
925
1428
 
@@ -1024,12 +1527,42 @@ async function main() {
1024
1527
  console.log(`[DEBUG] Windows full command: ${execCommand}`);
1025
1528
  }
1026
1529
  }
1027
-
1028
- // Special handling for Claude on Windows to bypass the wrapper script
1029
- if (process.platform === 'win32' && route.tool === 'claude') {
1030
- // Use the direct path to avoid the wrapper script that interferes with parameter passing
1031
- execCommand = 'C:\\npm_global\\claude';
1032
- if (toolArgs.length > 0) {
1530
+
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
1551
+ const argsString = toolArgs.map(arg => {
1552
+ if (arg.includes(' ') && !(arg.startsWith('"') && arg.endsWith('"'))) {
1553
+ return `"${arg}"`;
1554
+ }
1555
+ return arg;
1556
+ }).join(' ');
1557
+ execCommand = `${execCommand} ${argsString}`;
1558
+ execArgs = [];
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
1033
1566
  const argsString = toolArgs.map(arg => {
1034
1567
  if (arg.includes(' ') && !(arg.startsWith('"') && arg.endsWith('"'))) {
1035
1568
  return `"${arg}"`;
@@ -1038,9 +1571,26 @@ async function main() {
1038
1571
  }).join(' ');
1039
1572
  execCommand = `${execCommand} ${argsString}`;
1040
1573
  execArgs = [];
1041
- console.log(`[DEBUG] Windows direct Claude command: ${execCommand}`);
1574
+ console.log(`[DEBUG] Windows full command: ${execCommand}`);
1042
1575
  }
1043
1576
  }
1577
+
1578
+
1579
+ // Apply the same Windows handling logic to ensure consistency
1580
+ // This ensures consistency between direct routing and call command routing
1581
+ if (process.platform === 'win32' && execArgs.length > 0) {
1582
+ // For Windows, we need to properly quote the entire command line
1583
+ const argsString = execArgs.map(arg => {
1584
+ // If arg contains spaces and is not already quoted, quote it
1585
+ if (arg.includes(' ') && !(arg.startsWith('"') && arg.endsWith('"'))) {
1586
+ return `"${arg}"`;
1587
+ }
1588
+ return arg;
1589
+ }).join(' ');
1590
+ execCommand = `${execCommand} ${argsString}`;
1591
+ execArgs = [];
1592
+ console.log(`[DEBUG] Windows unified command: ${execCommand}`);
1593
+ }
1044
1594
 
1045
1595
  const result = await executeCommand(execCommand, execArgs, {
1046
1596
  stdio: 'inherit',