stigmergy 1.2.13 → 1.3.2-beta.0
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.
- package/README.md +39 -3
- package/STIGMERGY.md +3 -0
- package/config/enhanced-cli-config.json +438 -0
- package/docs/CLI_TOOLS_AGENT_SKILL_ANALYSIS.md +463 -0
- package/docs/ENHANCED_CLI_AGENT_SKILL_CONFIG.md +285 -0
- package/docs/INSTALLER_ARCHITECTURE.md +257 -0
- package/docs/SUDO_PROBLEM_AND_SOLUTION.md +529 -0
- package/package.json +14 -5
- package/scripts/analyze-router.js +168 -0
- package/scripts/test-runner.js +344 -0
- package/src/cli/commands/autoinstall.js +158 -0
- package/src/cli/commands/errors.js +190 -0
- package/src/cli/commands/install.js +142 -0
- package/src/cli/commands/permissions.js +108 -0
- package/src/cli/commands/project.js +449 -0
- package/src/cli/commands/resume.js +136 -0
- package/src/cli/commands/scan.js +97 -0
- package/src/cli/commands/skills.js +158 -0
- package/src/cli/commands/status.js +106 -0
- package/src/cli/commands/system.js +301 -0
- package/src/cli/router-beta.js +477 -0
- package/src/cli/utils/environment.js +75 -0
- package/src/cli/utils/formatters.js +47 -0
- package/src/cli/utils/skills_cache.js +92 -0
- package/src/core/cache_cleaner.js +1 -0
- package/src/core/cli_adapters.js +345 -0
- package/src/core/cli_help_analyzer.js +473 -1
- package/src/core/cli_path_detector.js +2 -1
- package/src/core/cli_tools.js +107 -0
- package/src/core/coordination/nodejs/HookDeploymentManager.js +185 -422
- package/src/core/coordination/nodejs/HookDeploymentManager.refactored.js +323 -0
- package/src/core/coordination/nodejs/generators/CLIAdapterGenerator.js +363 -0
- package/src/core/coordination/nodejs/generators/ResumeSessionGenerator.js +701 -0
- package/src/core/coordination/nodejs/generators/SkillsIntegrationGenerator.js +1210 -0
- package/src/core/coordination/nodejs/generators/index.js +12 -0
- package/src/core/enhanced_cli_installer.js +220 -30
- package/src/core/enhanced_cli_parameter_handler.js +395 -0
- package/src/core/execution_mode_detector.js +222 -0
- package/src/core/installer.js +51 -70
- package/src/core/local_skill_scanner.js +732 -0
- package/src/core/multilingual/language-pattern-manager.js +1 -1
- package/src/core/skills/StigmergySkillManager.js +26 -8
- package/src/core/smart_router.js +279 -2
- package/src/index.js +10 -4
- package/test/cli-integration.test.js +304 -0
- package/test/enhanced-cli-agent-skill-test.js +485 -0
- package/test/specific-cli-agent-skill-analysis.js +385 -0
- package/src/cli/router.js +0 -1783
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// Generators Module Index
|
|
2
|
+
// 导出所有生成器模块
|
|
3
|
+
|
|
4
|
+
const ResumeSessionGenerator = require('./ResumeSessionGenerator');
|
|
5
|
+
const SkillsIntegrationGenerator = require('./SkillsIntegrationGenerator');
|
|
6
|
+
const CLIAdapterGenerator = require('./CLIAdapterGenerator');
|
|
7
|
+
|
|
8
|
+
module.exports = {
|
|
9
|
+
ResumeSessionGenerator,
|
|
10
|
+
SkillsIntegrationGenerator,
|
|
11
|
+
CLIAdapterGenerator
|
|
12
|
+
};
|
|
@@ -219,34 +219,67 @@ class EnhancedCLIInstaller {
|
|
|
219
219
|
* Setup Unix elevated context
|
|
220
220
|
*/
|
|
221
221
|
async setupUnixElevatedContext() {
|
|
222
|
-
this.log('info', 'Unix: Checking
|
|
222
|
+
this.log('info', 'Unix: Checking privilege escalation methods...');
|
|
223
|
+
|
|
224
|
+
// List of privilege escalation tools to check (in order of preference)
|
|
225
|
+
const privilegeEscalationTools = [
|
|
226
|
+
{ name: 'sudo', testCmd: 'sudo', testArgs: ['-n', 'true'] },
|
|
227
|
+
{ name: 'doas', testCmd: 'doas', testArgs: ['-n', 'true'] },
|
|
228
|
+
{ name: 'run0', testCmd: 'run0', testArgs: ['-n', 'true'] },
|
|
229
|
+
{ name: 'pkexec', testCmd: 'pkexec', testArgs: ['--help'] },
|
|
230
|
+
];
|
|
223
231
|
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
stdio: 'pipe',
|
|
227
|
-
timeout: 5000
|
|
228
|
-
});
|
|
232
|
+
let availableTool = null;
|
|
233
|
+
let requiresPassword = false;
|
|
229
234
|
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
235
|
+
for (const tool of privilegeEscalationTools) {
|
|
236
|
+
try {
|
|
237
|
+
const result = spawnSync(tool.testCmd, tool.testArgs, {
|
|
238
|
+
stdio: 'pipe',
|
|
239
|
+
timeout: 5000
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
// Tool exists
|
|
243
|
+
if (result.status === 0 || (result.status !== null && result.error?.code !== 'ENOENT')) {
|
|
244
|
+
// Check if it's passwordless
|
|
245
|
+
if (result.status === 0) {
|
|
246
|
+
availableTool = tool.name;
|
|
247
|
+
requiresPassword = false;
|
|
248
|
+
this.log('success', `Found ${tool.name} (passwordless)`);
|
|
249
|
+
break;
|
|
250
|
+
} else if (result.error?.code !== 'ENOENT') {
|
|
251
|
+
// Tool exists but requires password
|
|
252
|
+
availableTool = tool.name;
|
|
253
|
+
requiresPassword = true;
|
|
254
|
+
this.log('info', `Found ${tool.name} (requires password)`);
|
|
255
|
+
break;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
} catch (error) {
|
|
259
|
+
// Tool doesn't exist, continue to next
|
|
260
|
+
continue;
|
|
244
261
|
}
|
|
245
|
-
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
if (availableTool) {
|
|
246
265
|
return {
|
|
247
|
-
success:
|
|
266
|
+
success: true,
|
|
267
|
+
platform: 'unix',
|
|
268
|
+
privilegeTool: availableTool,
|
|
269
|
+
requiresPassword: requiresPassword,
|
|
270
|
+
note: requiresPassword ? 'Will prompt for password per installation' : 'Passwordless access available'
|
|
271
|
+
};
|
|
272
|
+
} else {
|
|
273
|
+
// No privilege escalation tool found
|
|
274
|
+
this.log('warn', 'No privilege escalation tool found (sudo, doas, run0, pkexec)');
|
|
275
|
+
this.log('info', 'Will attempt user-space installation without privileges');
|
|
276
|
+
return {
|
|
277
|
+
success: true,
|
|
248
278
|
platform: 'unix',
|
|
249
|
-
|
|
279
|
+
privilegeTool: null,
|
|
280
|
+
requiresPassword: false,
|
|
281
|
+
userSpaceOnly: true,
|
|
282
|
+
note: 'Installation will be performed in user directory without privileges'
|
|
250
283
|
};
|
|
251
284
|
}
|
|
252
285
|
}
|
|
@@ -255,6 +288,12 @@ class EnhancedCLIInstaller {
|
|
|
255
288
|
* Install a tool using the pre-configured permission mode
|
|
256
289
|
*/
|
|
257
290
|
async installTool(toolName, toolInfo, retryCount = 0) {
|
|
291
|
+
// Check if install command exists
|
|
292
|
+
if (!toolInfo.install) {
|
|
293
|
+
this.log('warn', `Tool ${toolName} has no install command, skipping...`);
|
|
294
|
+
return false;
|
|
295
|
+
}
|
|
296
|
+
|
|
258
297
|
// Ensure permissions are configured first
|
|
259
298
|
if (!this.permissionConfigured) {
|
|
260
299
|
await this.setupPermissions();
|
|
@@ -338,6 +377,14 @@ class EnhancedCLIInstaller {
|
|
|
338
377
|
*/
|
|
339
378
|
async executeStandardInstallation(toolInfo) {
|
|
340
379
|
try {
|
|
380
|
+
// Check if install command exists
|
|
381
|
+
if (!toolInfo.install) {
|
|
382
|
+
return {
|
|
383
|
+
success: false,
|
|
384
|
+
error: `No install command specified for ${toolInfo.name || 'unknown tool'}`
|
|
385
|
+
};
|
|
386
|
+
}
|
|
387
|
+
|
|
341
388
|
const [command, ...args] = toolInfo.install.split(' ');
|
|
342
389
|
|
|
343
390
|
this.log('debug', `Executing: ${toolInfo.install}`);
|
|
@@ -438,10 +485,19 @@ class EnhancedCLIInstaller {
|
|
|
438
485
|
* Execute Unix elevated installation
|
|
439
486
|
*/
|
|
440
487
|
async executeUnixElevatedInstallation(toolInfo) {
|
|
441
|
-
const
|
|
488
|
+
const permissionSetup = await this.setupPermissions();
|
|
489
|
+
|
|
490
|
+
// If no privilege escalation tool is available, use user-space installation
|
|
491
|
+
if (permissionSetup.userSpaceOnly) {
|
|
492
|
+
return await this.executeUserSpaceInstallation(toolInfo);
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
// Use the detected privilege escalation tool
|
|
496
|
+
const privilegeTool = permissionSetup.privilegeTool || 'sudo';
|
|
497
|
+
const command = `${privilegeTool} ${toolInfo.install}`;
|
|
442
498
|
|
|
443
499
|
try {
|
|
444
|
-
this.log('info', `Using
|
|
500
|
+
this.log('info', `Using ${privilegeTool} for elevated installation of: ${toolInfo.name}`);
|
|
445
501
|
|
|
446
502
|
const result = spawnSync('bash', ['-c', command], {
|
|
447
503
|
stdio: this.options.verbose ? 'inherit' : 'pipe',
|
|
@@ -453,19 +509,137 @@ class EnhancedCLIInstaller {
|
|
|
453
509
|
return { success: true, error: null };
|
|
454
510
|
} else {
|
|
455
511
|
const errorMessage = result.stderr || result.stdout || `Exit code ${result.status}`;
|
|
456
|
-
|
|
512
|
+
// If privilege escalation failed, try user-space installation as fallback
|
|
513
|
+
this.log('warn', `Privilege escalation failed, trying user-space installation...`);
|
|
514
|
+
return await this.executeUserSpaceInstallation(toolInfo);
|
|
515
|
+
}
|
|
516
|
+
} catch (error) {
|
|
517
|
+
this.log('warn', `Privilege escalation error: ${error.message}, trying user-space installation...`);
|
|
518
|
+
return await this.executeUserSpaceInstallation(toolInfo);
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
/**
|
|
523
|
+
* Execute user-space installation (no privileges required)
|
|
524
|
+
*/
|
|
525
|
+
async executeUserSpaceInstallation(toolInfo) {
|
|
526
|
+
try {
|
|
527
|
+
// Install to user directory using --prefix flag
|
|
528
|
+
const os = require('os');
|
|
529
|
+
const path = require('path');
|
|
530
|
+
|
|
531
|
+
// Get user's npm global directory
|
|
532
|
+
let userNpmDir = process.env.NPM_CONFIG_PREFIX ||
|
|
533
|
+
path.join(os.homedir(), '.npm-global');
|
|
534
|
+
|
|
535
|
+
// Ensure directory exists
|
|
536
|
+
const fs = require('fs');
|
|
537
|
+
if (!fs.existsSync(userNpmDir)) {
|
|
538
|
+
fs.mkdirSync(userNpmDir, { recursive: true, mode: 0o755 });
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
// Extract package name from install command
|
|
542
|
+
// Format: "npm install -g @package/tool" or "npm install -g tool"
|
|
543
|
+
const installMatch = toolInfo.install.match(/npm\s+(?:install|upgrade)\s+(?:-g\s+)?(.+)/);
|
|
544
|
+
if (!installMatch) {
|
|
545
|
+
throw new Error('Cannot parse install command');
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
const packageName = installMatch[1].trim();
|
|
549
|
+
|
|
550
|
+
// Create user-space install command
|
|
551
|
+
const userCommand = `npm install -g --prefix "${userNpmDir}" ${packageName}`;
|
|
552
|
+
|
|
553
|
+
this.log('info', `Installing ${toolInfo.name} to user directory: ${userNpmDir}`);
|
|
554
|
+
this.log('info', `Command: ${userCommand}`);
|
|
555
|
+
|
|
556
|
+
// Set PATH to include user npm directory
|
|
557
|
+
const env = {
|
|
558
|
+
...process.env,
|
|
559
|
+
PATH: `${path.join(userNpmDir, 'bin')}:${process.env.PATH}`
|
|
560
|
+
};
|
|
561
|
+
|
|
562
|
+
const result = spawnSync('bash', ['-c', userCommand], {
|
|
563
|
+
stdio: this.options.verbose ? 'inherit' : 'pipe',
|
|
564
|
+
timeout: this.options.timeout * 3, // Longer timeout for user-space install
|
|
565
|
+
encoding: 'utf8',
|
|
566
|
+
env: env
|
|
567
|
+
});
|
|
568
|
+
|
|
569
|
+
if (result.status === 0) {
|
|
570
|
+
this.log('success', `Successfully installed ${toolInfo.name} to user directory`);
|
|
571
|
+
|
|
572
|
+
// Provide PATH setup instructions
|
|
573
|
+
const binDir = path.join(userNpmDir, 'bin');
|
|
574
|
+
this.log('info', '⚠️ Make sure to add the bin directory to your PATH:');
|
|
575
|
+
this.log('info', ` export PATH="${binDir}:$PATH"`);
|
|
576
|
+
|
|
577
|
+
// Add to shell config files automatically
|
|
578
|
+
await this.addPathToShellConfig(binDir);
|
|
579
|
+
|
|
580
|
+
return { success: true, error: null, userSpace: true, binDir };
|
|
581
|
+
} else {
|
|
582
|
+
const errorMessage = result.stderr || result.stdout || `Exit code ${result.status}`;
|
|
583
|
+
return { success: false, error: `User-space installation failed: ${errorMessage}` };
|
|
457
584
|
}
|
|
458
585
|
} catch (error) {
|
|
459
586
|
return { success: false, error: error.message };
|
|
460
587
|
}
|
|
461
588
|
}
|
|
462
589
|
|
|
590
|
+
/**
|
|
591
|
+
* Add PATH to shell configuration files
|
|
592
|
+
*/
|
|
593
|
+
async addPathToShellConfig(binDir) {
|
|
594
|
+
const os = require('os');
|
|
595
|
+
const path = require('path');
|
|
596
|
+
const fs = require('fs/promises');
|
|
597
|
+
|
|
598
|
+
const shellConfigs = [
|
|
599
|
+
{ file: path.join(os.homedir(), '.bashrc'), marker: '# Stigmergy CLI PATH' },
|
|
600
|
+
{ file: path.join(os.homedir(), '.zshrc'), marker: '# Stigmergy CLI PATH' },
|
|
601
|
+
{ file: path.join(os.homedir(), '.profile'), marker: '# Stigmergy CLI PATH' },
|
|
602
|
+
];
|
|
603
|
+
|
|
604
|
+
const pathLine = `export PATH="${binDir}:$PATH"\n`;
|
|
605
|
+
|
|
606
|
+
for (const config of shellConfigs) {
|
|
607
|
+
try {
|
|
608
|
+
let content = '';
|
|
609
|
+
try {
|
|
610
|
+
content = await fs.readFile(config.file, 'utf8');
|
|
611
|
+
} catch (err) {
|
|
612
|
+
// File doesn't exist, will create it
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
// Check if PATH is already configured
|
|
616
|
+
if (content.includes(config.marker)) {
|
|
617
|
+
continue; // Already configured
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
// Append PATH configuration
|
|
621
|
+
await fs.appendFile(config.file, `\n${config.marker}\n${pathLine}`);
|
|
622
|
+
this.log('info', `Added PATH to ${path.basename(config.file)}`);
|
|
623
|
+
} catch (error) {
|
|
624
|
+
// Ignore errors for config files
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
|
|
463
629
|
/**
|
|
464
630
|
* Fallback installation method
|
|
465
631
|
*/
|
|
466
632
|
async executeFallbackInstallation(toolInfo) {
|
|
467
633
|
this.log('warn', 'Attempting fallback installation method...');
|
|
468
634
|
|
|
635
|
+
// Check if install command exists
|
|
636
|
+
if (!toolInfo.install) {
|
|
637
|
+
return {
|
|
638
|
+
success: false,
|
|
639
|
+
error: `No install command specified for ${toolInfo.name || 'unknown tool'}`
|
|
640
|
+
};
|
|
641
|
+
}
|
|
642
|
+
|
|
469
643
|
// Try without some npm flags that might cause permission issues
|
|
470
644
|
const [command, ...args] = toolInfo.install.split(' ');
|
|
471
645
|
const fallbackArgs = args.filter(arg => !arg.startsWith('--'));
|
|
@@ -531,6 +705,12 @@ class EnhancedCLIInstaller {
|
|
|
531
705
|
const toolInfo = toolInfos[toolName];
|
|
532
706
|
if (!toolInfo) continue;
|
|
533
707
|
|
|
708
|
+
// Skip tools without install command (internal functions)
|
|
709
|
+
if (!toolInfo.install) {
|
|
710
|
+
this.log('debug', `Tool ${toolName} has no install command, skipping...`);
|
|
711
|
+
continue;
|
|
712
|
+
}
|
|
713
|
+
|
|
534
714
|
this.results.installations[toolName] = {
|
|
535
715
|
startTime: Date.now(),
|
|
536
716
|
...this.results.installations[toolName]
|
|
@@ -572,14 +752,24 @@ class EnhancedCLIInstaller {
|
|
|
572
752
|
this.log('info', `Upgrading ${totalCount} CLI tools in ${this.permissionMode} mode...`);
|
|
573
753
|
|
|
574
754
|
for (const toolName of toolNames) {
|
|
755
|
+
const originalInfo = toolInfos[toolName];
|
|
756
|
+
if (!originalInfo) {
|
|
757
|
+
this.log('warn', `Tool ${toolName} not found in toolInfos, skipping...`);
|
|
758
|
+
continue;
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
// Skip tools without install command (internal functions)
|
|
762
|
+
if (!originalInfo.install) {
|
|
763
|
+
this.log('debug', `Tool ${toolName} has no install command, skipping upgrade...`);
|
|
764
|
+
continue;
|
|
765
|
+
}
|
|
766
|
+
|
|
575
767
|
const toolInfo = {
|
|
576
|
-
...
|
|
768
|
+
...originalInfo,
|
|
577
769
|
install: `npm upgrade -g ${toolName}`,
|
|
578
|
-
name: `${
|
|
770
|
+
name: `${originalInfo.name} (Upgrade)`
|
|
579
771
|
};
|
|
580
772
|
|
|
581
|
-
if (!toolInfo) continue;
|
|
582
|
-
|
|
583
773
|
const success = await this.installTool(toolName, toolInfo);
|
|
584
774
|
if (success) {
|
|
585
775
|
successCount++;
|