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,168 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Router.js Structure Analysis Tool
|
|
5
|
+
* Analyzes the router.js file to identify modularization opportunities
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const fs = require('fs');
|
|
9
|
+
const path = require('path');
|
|
10
|
+
|
|
11
|
+
console.log('š Router.js Structure Analysis');
|
|
12
|
+
console.log('='.repeat(50));
|
|
13
|
+
|
|
14
|
+
const routerPath = path.join(__dirname, '../src/cli/router.js');
|
|
15
|
+
|
|
16
|
+
if (!fs.existsSync(routerPath)) {
|
|
17
|
+
console.error('ā router.js file not found');
|
|
18
|
+
process.exit(1);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const content = fs.readFileSync(routerPath, 'utf8');
|
|
22
|
+
const lines = content.split('\n');
|
|
23
|
+
|
|
24
|
+
console.log(`š Total Lines: ${lines.length}`);
|
|
25
|
+
console.log(`š File Size: ${(fs.statSync(routerPath).size / 1024).toFixed(2)} KB`);
|
|
26
|
+
console.log('');
|
|
27
|
+
|
|
28
|
+
// Analyze imports
|
|
29
|
+
console.log('š¦ Import Analysis:');
|
|
30
|
+
const importRegex = /const\s+(.+?)\s*=\s*require\(['"](.+?)['"]\)/g;
|
|
31
|
+
const imports = [];
|
|
32
|
+
let match;
|
|
33
|
+
|
|
34
|
+
while ((match = importRegex.exec(content)) !== null) {
|
|
35
|
+
imports.push({
|
|
36
|
+
name: match[1],
|
|
37
|
+
path: match[2],
|
|
38
|
+
line: content.substring(0, match.index).split('\n').length
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
console.log(`Found ${imports.length} imports:`);
|
|
43
|
+
imports.forEach(imp => {
|
|
44
|
+
console.log(` š ${imp.name} <- ${imp.path} (line ${imp.line})`);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
// Analyze functions
|
|
48
|
+
console.log('\nš§ Function Analysis:');
|
|
49
|
+
const functionRegex = /(?:function\s+(\w+)|const\s+(\w+)\s*=\s*(?:async\s+)?(?:function|\([^)]*\)\s*=>))/g;
|
|
50
|
+
const functions = [];
|
|
51
|
+
let funcMatch;
|
|
52
|
+
|
|
53
|
+
while ((funcMatch = functionRegex.exec(content)) !== null) {
|
|
54
|
+
const funcName = funcMatch[1] || funcMatch[2];
|
|
55
|
+
const funcStart = content.substring(0, funcMatch.index).split('\n').length;
|
|
56
|
+
functions.push({
|
|
57
|
+
name: funcName,
|
|
58
|
+
line: funcStart,
|
|
59
|
+
isAsync: content.includes('async') && content.substring(funcMatch.index - 50, funcMatch.index).includes('async')
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
console.log(`Found ${functions.length} functions:`);
|
|
64
|
+
functions.forEach(func => {
|
|
65
|
+
console.log(` āļø ${func.name}${func.isAsync ? ' (async)' : ''} (line ${func.line})`);
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
// Analyze main sections
|
|
69
|
+
console.log('\nš Section Analysis:');
|
|
70
|
+
|
|
71
|
+
// Look for main sections
|
|
72
|
+
const sections = [
|
|
73
|
+
{ name: 'Import Section', pattern: /const.*require/ },
|
|
74
|
+
{ name: 'Setup Section', pattern: /setupGlobalErrorHandlers|program\.version/ },
|
|
75
|
+
{ name: 'Command Definitions', pattern: /program\.command/ },
|
|
76
|
+
{ name: 'CLI Tools Routing', pattern: /SmartRouter|routeToCLI/ },
|
|
77
|
+
{ name: 'Error Handling', pattern: /errorHandler|catch.*error/ },
|
|
78
|
+
{ name: 'Helper Functions', pattern: /function formatBytes|function getWorkingDirectory/ },
|
|
79
|
+
{ name: 'Main Execution', pattern: /async function main|if \(require\.main/ }
|
|
80
|
+
];
|
|
81
|
+
|
|
82
|
+
sections.forEach(section => {
|
|
83
|
+
const sectionMatch = content.match(section.pattern);
|
|
84
|
+
if (sectionMatch) {
|
|
85
|
+
const lineNum = content.substring(0, sectionMatch.index).split('\n').length;
|
|
86
|
+
console.log(` š ${section.name} (around line ${lineNum})`);
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
// Look for command definitions
|
|
91
|
+
console.log('\nšÆ Command Definitions:');
|
|
92
|
+
const commandRegex = /program\.command\(['"]([^'"]+)['"]\)/g;
|
|
93
|
+
const commands = [];
|
|
94
|
+
let cmdMatch;
|
|
95
|
+
|
|
96
|
+
while ((cmdMatch = commandRegex.exec(content)) !== null) {
|
|
97
|
+
commands.push(cmdMatch[1]);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
console.log(`Found ${commands.length} CLI commands:`);
|
|
101
|
+
commands.forEach(cmd => {
|
|
102
|
+
console.log(` š» ${cmd}`);
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
// Look for CLI tools routing
|
|
106
|
+
console.log('\nš£ļø CLI Tools Routing:');
|
|
107
|
+
const toolRegex = /(?:case|if).*['"]([^'"]+)['"].*?:/g;
|
|
108
|
+
const tools = [];
|
|
109
|
+
let toolMatch;
|
|
110
|
+
|
|
111
|
+
while ((toolMatch = toolRegex.exec(content)) !== null) {
|
|
112
|
+
const tool = toolMatch[1];
|
|
113
|
+
if (!tools.includes(tool) && ['claude', 'gemini', 'qwen', 'codebuddy', 'codex', 'iflow', 'qodercli', 'copilot'].includes(tool)) {
|
|
114
|
+
tools.push(tool);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
console.log(`Found routing for ${tools.length} CLI tools:`);
|
|
119
|
+
tools.forEach(tool => {
|
|
120
|
+
console.log(` š ${tool}`);
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
// Suggest modularization strategy
|
|
124
|
+
console.log('\nš” Modularization Suggestions:');
|
|
125
|
+
console.log('');
|
|
126
|
+
|
|
127
|
+
console.log('šļø Recommended Module Structure:');
|
|
128
|
+
console.log(' src/cli/');
|
|
129
|
+
console.log(' āāā router.js (main entry, ~200 lines)');
|
|
130
|
+
console.log(' āāā commands/');
|
|
131
|
+
console.log(' ā āāā index.js (command registry)');
|
|
132
|
+
console.log(' ā āāā install.js (install commands)');
|
|
133
|
+
console.log(' ā āāā status.js (status commands)');
|
|
134
|
+
console.log(' ā āāā scan.js (scan commands)');
|
|
135
|
+
console.log(' ā āāā deploy.js (deploy commands)');
|
|
136
|
+
console.log(' āāā routing/');
|
|
137
|
+
console.log(' ā āāā index.js (routing coordinator)');
|
|
138
|
+
console.log(' ā āāā cli-router.js (CLI tools routing)');
|
|
139
|
+
console.log(' ā āāā command-router.js (command routing)');
|
|
140
|
+
console.log(' āāā utils/');
|
|
141
|
+
console.log(' ā āāā formatters.js (format helpers)');
|
|
142
|
+
console.log(' ā āāā validators.js (input validation)');
|
|
143
|
+
console.log(' ā āāā executors.js (command execution)');
|
|
144
|
+
console.log(' āāā config/');
|
|
145
|
+
console.log(' āāā program-setup.js (commander setup)');
|
|
146
|
+
console.log(' āāā environment.js (environment setup)');
|
|
147
|
+
|
|
148
|
+
console.log('');
|
|
149
|
+
console.log('šÆ TDD Migration Strategy:');
|
|
150
|
+
console.log(' 1. ā
Create comprehensive test suite for current router.js');
|
|
151
|
+
console.log(' 2. š Extract helper functions first (low risk)');
|
|
152
|
+
console.log(' 3. š Extract command definitions (medium risk)');
|
|
153
|
+
console.log(' 4. š Extract CLI routing logic (medium risk)');
|
|
154
|
+
console.log(' 5. š Create modular command handlers (high risk)');
|
|
155
|
+
console.log(' 6. ā
Maintain backward compatibility');
|
|
156
|
+
console.log(' 7. ā
Create rollback mechanism');
|
|
157
|
+
|
|
158
|
+
console.log('');
|
|
159
|
+
console.log('ā ļø Risk Assessment:');
|
|
160
|
+
console.log(' š¢ LOW: Helper functions (formatBytes, etc.)');
|
|
161
|
+
console.log(' š” MEDIUM: Command definitions and routing');
|
|
162
|
+
console.log(' š“ HIGH: Core CLI execution logic');
|
|
163
|
+
console.log('');
|
|
164
|
+
console.log('š”ļø Safety Measures:');
|
|
165
|
+
console.log(' ā
Backup original file');
|
|
166
|
+
console.log(' ā
Create feature branch');
|
|
167
|
+
console.log(' ā
Test before and after each extraction');
|
|
168
|
+
console.log(' ā
Gradual migration with rollback points');
|
|
@@ -0,0 +1,344 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Enhanced Test Runner for HookDeploymentManager Test Suite
|
|
5
|
+
* Provides comprehensive testing with reporting and analysis
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const { execSync } = require('child_process');
|
|
9
|
+
const fs = require('fs-extra');
|
|
10
|
+
const path = require('path');
|
|
11
|
+
const chalk = require('chalk');
|
|
12
|
+
|
|
13
|
+
class TestRunner {
|
|
14
|
+
constructor() {
|
|
15
|
+
this.testResults = {
|
|
16
|
+
unit: { passed: 0, failed: 0, total: 0, duration: 0 },
|
|
17
|
+
integration: { passed: 0, failed: 0, total: 0, duration: 0 },
|
|
18
|
+
regression: { passed: 0, failed: 0, total: 0, duration: 0 },
|
|
19
|
+
performance: { passed: 0, failed: 0, total: 0, duration: 0 }
|
|
20
|
+
};
|
|
21
|
+
this.startTime = Date.now();
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
log(message, type = 'info') {
|
|
25
|
+
const colors = {
|
|
26
|
+
info: chalk.blue,
|
|
27
|
+
success: chalk.green,
|
|
28
|
+
warning: chalk.yellow,
|
|
29
|
+
error: chalk.red
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
console.log(colors[type](`[${new Date().toLocaleTimeString()}] ${message}`));
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
async runCommand(command, description) {
|
|
36
|
+
this.log(`Running: ${description}...`);
|
|
37
|
+
const startTime = Date.now();
|
|
38
|
+
|
|
39
|
+
try {
|
|
40
|
+
const output = execSync(command, {
|
|
41
|
+
encoding: 'utf8',
|
|
42
|
+
stdio: 'pipe'
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
const duration = Date.now() - startTime;
|
|
46
|
+
this.log(`${description} completed successfully (${duration}ms)`, 'success');
|
|
47
|
+
|
|
48
|
+
return {
|
|
49
|
+
success: true,
|
|
50
|
+
output,
|
|
51
|
+
duration
|
|
52
|
+
};
|
|
53
|
+
} catch (error) {
|
|
54
|
+
const duration = Date.now() - startTime;
|
|
55
|
+
this.log(`${description} failed after ${duration}ms`, 'error');
|
|
56
|
+
|
|
57
|
+
return {
|
|
58
|
+
success: false,
|
|
59
|
+
error: error.message,
|
|
60
|
+
output: error.stdout,
|
|
61
|
+
duration
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
parseJestOutput(output) {
|
|
67
|
+
const lines = output.split('\n');
|
|
68
|
+
const results = {
|
|
69
|
+
passed: 0,
|
|
70
|
+
failed: 0,
|
|
71
|
+
total: 0,
|
|
72
|
+
suites: 0
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
lines.forEach(line => {
|
|
76
|
+
const match = line.match(/Tests:\s+(\d+)\s+passed,\s+(\d+)\s+failed/);
|
|
77
|
+
if (match) {
|
|
78
|
+
results.passed = parseInt(match[1]);
|
|
79
|
+
results.failed = parseInt(match[2]);
|
|
80
|
+
results.total = results.passed + results.failed;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const suiteMatch = line.match(/Test Suites:\s+(\d+)\s+passed,\s+(\d+)\s+failed/);
|
|
84
|
+
if (suiteMatch) {
|
|
85
|
+
results.suites = parseInt(suiteMatch[1]) + parseInt(suiteMatch[2]);
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
return results;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
async runUnitTests() {
|
|
93
|
+
this.log('\nš§Ŗ Running Unit Tests', 'info');
|
|
94
|
+
|
|
95
|
+
const result = await this.runCommand(
|
|
96
|
+
'npm run test:unit -- --verbose --json',
|
|
97
|
+
'Unit Tests'
|
|
98
|
+
);
|
|
99
|
+
|
|
100
|
+
if (result.success) {
|
|
101
|
+
const jestOutput = result.output;
|
|
102
|
+
try {
|
|
103
|
+
const jsonMatch = jestOutput.match(/\{[\s\S]*\}/);
|
|
104
|
+
if (jsonMatch) {
|
|
105
|
+
const jestResults = JSON.parse(jsonMatch[0]);
|
|
106
|
+
this.testResults.unit.passed = jestResults.numPassedTests || 0;
|
|
107
|
+
this.testResults.unit.failed = jestResults.numFailedTests || 0;
|
|
108
|
+
this.testResults.unit.total = jestResults.numTotalTests || 0;
|
|
109
|
+
this.testResults.unit.duration = jestResults.testResults?.reduce(
|
|
110
|
+
(total, test) => total + (test.duration || 0), 0
|
|
111
|
+
) || 0;
|
|
112
|
+
} else {
|
|
113
|
+
const parsed = this.parseJestOutput(result.output);
|
|
114
|
+
Object.assign(this.testResults.unit, parsed);
|
|
115
|
+
}
|
|
116
|
+
} catch (parseError) {
|
|
117
|
+
this.log('Failed to parse Jest output, using fallback parsing', 'warning');
|
|
118
|
+
const parsed = this.parseJestOutput(result.output);
|
|
119
|
+
Object.assign(this.testResults.unit, parsed);
|
|
120
|
+
}
|
|
121
|
+
} else {
|
|
122
|
+
this.testResults.unit.failed = 1;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
return result.success;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
async runIntegrationTests() {
|
|
129
|
+
this.log('\nš Running Integration Tests', 'info');
|
|
130
|
+
|
|
131
|
+
const result = await this.runCommand(
|
|
132
|
+
'npm run test:integration -- --verbose',
|
|
133
|
+
'Integration Tests'
|
|
134
|
+
);
|
|
135
|
+
|
|
136
|
+
if (result.success) {
|
|
137
|
+
const parsed = this.parseJestOutput(result.output);
|
|
138
|
+
Object.assign(this.testResults.integration, parsed);
|
|
139
|
+
this.testResults.integration.duration = result.duration;
|
|
140
|
+
} else {
|
|
141
|
+
this.testResults.integration.failed = 1;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
return result.success;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
async runRegressionTests() {
|
|
148
|
+
this.log('\nš Running Regression Tests', 'info');
|
|
149
|
+
|
|
150
|
+
const result = await this.runCommand(
|
|
151
|
+
'npm run test:regression -- --verbose',
|
|
152
|
+
'Regression Tests'
|
|
153
|
+
);
|
|
154
|
+
|
|
155
|
+
if (result.success) {
|
|
156
|
+
const parsed = this.parseJestOutput(result.output);
|
|
157
|
+
Object.assign(this.testResults.regression, parsed);
|
|
158
|
+
this.testResults.regression.duration = result.duration;
|
|
159
|
+
} else {
|
|
160
|
+
this.testResults.regression.failed = 1;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
return result.success;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
async runPerformanceTests() {
|
|
167
|
+
this.log('\nā” Running Performance Tests', 'info');
|
|
168
|
+
|
|
169
|
+
const result = await this.runCommand(
|
|
170
|
+
'npm run test:performance -- --verbose',
|
|
171
|
+
'Performance Tests'
|
|
172
|
+
);
|
|
173
|
+
|
|
174
|
+
if (result.success) {
|
|
175
|
+
const parsed = this.parseJestOutput(result.output);
|
|
176
|
+
Object.assign(this.testResults.performance, parsed);
|
|
177
|
+
this.testResults.performance.duration = result.duration;
|
|
178
|
+
} else {
|
|
179
|
+
this.testResults.performance.failed = 1;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
return result.success;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
generateReport() {
|
|
186
|
+
const totalDuration = Date.now() - this.startTime;
|
|
187
|
+
const allTests = Object.values(this.testResults);
|
|
188
|
+
const totalPassed = allTests.reduce((sum, cat) => sum + cat.passed, 0);
|
|
189
|
+
const totalFailed = allTests.reduce((sum, cat) => sum + cat.failed, 0);
|
|
190
|
+
const totalTests = totalPassed + totalFailed;
|
|
191
|
+
|
|
192
|
+
console.log('\n' + '='.repeat(80));
|
|
193
|
+
console.log(chalk.bold.blue('š TEST SUITE REPORT'));
|
|
194
|
+
console.log('='.repeat(80));
|
|
195
|
+
|
|
196
|
+
// Summary
|
|
197
|
+
console.log(chalk.bold('\nš SUMMARY:'));
|
|
198
|
+
console.log(`Total Duration: ${(totalDuration / 1000).toFixed(2)}s`);
|
|
199
|
+
console.log(`Total Tests: ${totalTests}`);
|
|
200
|
+
console.log(`Passed: ${chalk.green(totalPassed)}`);
|
|
201
|
+
console.log(`Failed: ${chalk.red(totalFailed)}`);
|
|
202
|
+
console.log(`Success Rate: ${((totalPassed / totalTests) * 100).toFixed(1)}%`);
|
|
203
|
+
|
|
204
|
+
// Category breakdown
|
|
205
|
+
console.log(chalk.bold('\nš TEST CATEGORIES:'));
|
|
206
|
+
|
|
207
|
+
const categories = [
|
|
208
|
+
{ name: 'Unit Tests', key: 'unit', icon: 'š§Ŗ' },
|
|
209
|
+
{ name: 'Integration Tests', key: 'integration', icon: 'š' },
|
|
210
|
+
{ name: 'Regression Tests', key: 'regression', icon: 'š' },
|
|
211
|
+
{ name: 'Performance Tests', key: 'performance', icon: 'ā”' }
|
|
212
|
+
];
|
|
213
|
+
|
|
214
|
+
categories.forEach(category => {
|
|
215
|
+
const results = this.testResults[category.key];
|
|
216
|
+
const success = results.failed === 0;
|
|
217
|
+
const status = success ? 'ā
' : 'ā';
|
|
218
|
+
const color = success ? chalk.green : chalk.red;
|
|
219
|
+
|
|
220
|
+
console.log(`\n${category.icon} ${category.name}: ${status}`);
|
|
221
|
+
console.log(` Tests: ${results.total}`);
|
|
222
|
+
console.log(` Passed: ${color(results.passed)}`);
|
|
223
|
+
console.log(` Failed: ${results.failed > 0 ? chalk.red(results.failed) : results.failed}`);
|
|
224
|
+
console.log(` Duration: ${(results.duration / 1000).toFixed(2)}s`);
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
// Coverage information if available
|
|
228
|
+
const coveragePath = path.join(process.cwd(), 'coverage', 'coverage-summary.json');
|
|
229
|
+
if (fs.existsSync(coveragePath)) {
|
|
230
|
+
try {
|
|
231
|
+
const coverage = fs.readJsonSync(coveragePath);
|
|
232
|
+
console.log(chalk.bold('\nš COVERAGE SUMMARY:'));
|
|
233
|
+
console.log(`Lines: ${coverage.total.lines.pct}%`);
|
|
234
|
+
console.log(`Functions: ${coverage.total.functions.pct}%`);
|
|
235
|
+
console.log(`Branches: ${coverage.total.branches.pct}%`);
|
|
236
|
+
console.log(`Statements: ${coverage.total.statements.pct}%`);
|
|
237
|
+
} catch (error) {
|
|
238
|
+
this.log('Could not read coverage information', 'warning');
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
console.log('\n' + '='.repeat(80));
|
|
243
|
+
|
|
244
|
+
// Exit with appropriate code
|
|
245
|
+
const exitCode = totalFailed > 0 ? 1 : 0;
|
|
246
|
+
|
|
247
|
+
if (exitCode === 0) {
|
|
248
|
+
console.log(chalk.green.bold('\nš ALL TESTS PASSED!'));
|
|
249
|
+
} else {
|
|
250
|
+
console.log(chalk.red.bold(`\nā ${totalFailed} TEST(S) FAILED!`));
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
return exitCode;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
async runTestSuite() {
|
|
257
|
+
console.log(chalk.bold.blue('š Starting HookDeploymentManager Test Suite'));
|
|
258
|
+
console.log(`Node.js version: ${process.version}`);
|
|
259
|
+
console.log(`Platform: ${process.platform}`);
|
|
260
|
+
console.log(`Working directory: ${process.cwd()}`);
|
|
261
|
+
|
|
262
|
+
try {
|
|
263
|
+
// Clean previous results
|
|
264
|
+
await fs.remove('coverage');
|
|
265
|
+
await fs.remove('test-results');
|
|
266
|
+
|
|
267
|
+
const unitSuccess = await this.runUnitTests();
|
|
268
|
+
const integrationSuccess = await this.runIntegrationTests();
|
|
269
|
+
const regressionSuccess = await this.runRegressionTests();
|
|
270
|
+
|
|
271
|
+
// Run performance tests only if others pass (to save time)
|
|
272
|
+
let performanceSuccess = true;
|
|
273
|
+
if (unitSuccess && integrationSuccess && regressionSuccess) {
|
|
274
|
+
performanceSuccess = await this.runPerformanceTests();
|
|
275
|
+
} else {
|
|
276
|
+
this.log('Skipping performance tests due to failures in other categories', 'warning');
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
// Generate report and exit
|
|
280
|
+
const exitCode = this.generateReport();
|
|
281
|
+
process.exit(exitCode);
|
|
282
|
+
|
|
283
|
+
} catch (error) {
|
|
284
|
+
this.log(`Test runner error: ${error.message}`, 'error');
|
|
285
|
+
console.error(error.stack);
|
|
286
|
+
process.exit(1);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
// CLI interface
|
|
292
|
+
if (require.main === module) {
|
|
293
|
+
const runner = new TestRunner();
|
|
294
|
+
|
|
295
|
+
// Parse command line arguments
|
|
296
|
+
const args = process.argv.slice(2);
|
|
297
|
+
|
|
298
|
+
if (args.includes('--help') || args.includes('-h')) {
|
|
299
|
+
console.log(`
|
|
300
|
+
HookDeploymentManager Test Runner
|
|
301
|
+
|
|
302
|
+
Usage: node scripts/test-runner.js [options]
|
|
303
|
+
|
|
304
|
+
Options:
|
|
305
|
+
--help, -h Show this help message
|
|
306
|
+
--unit-only Run only unit tests
|
|
307
|
+
--integration-only Run only integration tests
|
|
308
|
+
--regression-only Run only regression tests
|
|
309
|
+
--performance-only Run only performance tests
|
|
310
|
+
--no-performance Skip performance tests
|
|
311
|
+
--verbose Enable verbose output
|
|
312
|
+
|
|
313
|
+
Examples:
|
|
314
|
+
node scripts/test-runner.js # Run all tests
|
|
315
|
+
node scripts/test-runner.js --unit-only # Run only unit tests
|
|
316
|
+
node scripts/test-runner.js --no-performance # Skip performance tests
|
|
317
|
+
`);
|
|
318
|
+
process.exit(0);
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
// Handle specific test category requests
|
|
322
|
+
if (args.includes('--unit-only')) {
|
|
323
|
+
runner.runUnitTests().then(success => {
|
|
324
|
+
process.exit(success ? 0 : 1);
|
|
325
|
+
});
|
|
326
|
+
} else if (args.includes('--integration-only')) {
|
|
327
|
+
runner.runIntegrationTests().then(success => {
|
|
328
|
+
process.exit(success ? 0 : 1);
|
|
329
|
+
});
|
|
330
|
+
} else if (args.includes('--regression-only')) {
|
|
331
|
+
runner.runRegressionTests().then(success => {
|
|
332
|
+
process.exit(success ? 0 : 1);
|
|
333
|
+
});
|
|
334
|
+
} else if (args.includes('--performance-only')) {
|
|
335
|
+
runner.runPerformanceTests().then(success => {
|
|
336
|
+
process.exit(success ? 0 : 1);
|
|
337
|
+
});
|
|
338
|
+
} else {
|
|
339
|
+
// Run all tests
|
|
340
|
+
runner.runTestSuite();
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
module.exports = TestRunner;
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auto-install Command
|
|
3
|
+
* Modular implementation for automated CLI tool installation (npm postinstall)
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const chalk = require('chalk');
|
|
7
|
+
const { handleInstallCommand } = require('./install');
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Handle auto-install command - Automated installation for npm postinstall
|
|
11
|
+
* @param {Object} options - Command options
|
|
12
|
+
*/
|
|
13
|
+
async function handleAutoInstallCommand(options = {}) {
|
|
14
|
+
try {
|
|
15
|
+
// Detect npm environment for better output visibility
|
|
16
|
+
const isNpmPostinstall = process.env.npm_lifecycle_event === 'postinstall';
|
|
17
|
+
|
|
18
|
+
// Use stderr for critical messages in npm environment (more likely to be shown)
|
|
19
|
+
const criticalLog = isNpmPostinstall ? console.error : console.log;
|
|
20
|
+
|
|
21
|
+
criticalLog(chalk.cyan('š STIGMERGY CLI AUTO-INSTALL STARTING'));
|
|
22
|
+
criticalLog('='.repeat(60));
|
|
23
|
+
criticalLog('Installing cross-CLI integration and scanning for AI tools...');
|
|
24
|
+
criticalLog('='.repeat(60));
|
|
25
|
+
|
|
26
|
+
console.log(chalk.blue('[AUTO-INSTALL] Stigmergy CLI automated setup'));
|
|
27
|
+
console.log('='.repeat(60));
|
|
28
|
+
|
|
29
|
+
// Check if we're in npm postinstall environment
|
|
30
|
+
if (isNpmPostinstall) {
|
|
31
|
+
console.log(chalk.yellow('š¦ Detected npm postinstall environment'));
|
|
32
|
+
console.log(chalk.gray('Setting up CLI integrations automatically...'));
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Auto-install options - non-interactive mode
|
|
36
|
+
const autoInstallOptions = {
|
|
37
|
+
cli: 'all', // Install all available CLI tools
|
|
38
|
+
verbose: options.verbose || process.env.DEBUG === 'true',
|
|
39
|
+
force: options.force || false,
|
|
40
|
+
nonInteractive: true, // Critical for automated installation
|
|
41
|
+
autoDetect: true, // Auto-detect available tools
|
|
42
|
+
skipPermissionCheck: process.env.STIGMERGY_SKIP_PERMISSION_CHECK === 'true'
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
console.log(chalk.blue('š Scanning for available CLI tools...'));
|
|
46
|
+
|
|
47
|
+
// Run the installation
|
|
48
|
+
console.log(chalk.blue('š ļø Starting automated CLI tool installation...'));
|
|
49
|
+
|
|
50
|
+
const installResult = await handleInstallCommand(autoInstallOptions);
|
|
51
|
+
|
|
52
|
+
if (installResult.success) {
|
|
53
|
+
console.log(chalk.green('\nā
Auto-install completed successfully!'));
|
|
54
|
+
|
|
55
|
+
if (isNpmPostinstall) {
|
|
56
|
+
criticalLog(chalk.green('ā
STIGMERGY CLI SETUP COMPLETE'));
|
|
57
|
+
criticalLog(chalk.gray('You can now use: stigmergy <tool> <command>'));
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Show summary of what was installed
|
|
61
|
+
if (installResult.installed && installResult.installed.length > 0) {
|
|
62
|
+
console.log(chalk.blue('\nš Installation Summary:'));
|
|
63
|
+
installResult.installed.forEach(tool => {
|
|
64
|
+
console.log(` ${chalk.green('ā
')} ${tool}`);
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (installResult.failed && installResult.failed.length > 0) {
|
|
69
|
+
console.log(chalk.blue('\nā Failed Tools:'));
|
|
70
|
+
installResult.failed.forEach(tool => {
|
|
71
|
+
console.log(` ${chalk.red('ā')} ${tool} (installation failed)`);
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (installResult.existing && installResult.existing.length > 0) {
|
|
76
|
+
console.log(chalk.blue('\nš§ Already Available:'));
|
|
77
|
+
installResult.existing.forEach(tool => {
|
|
78
|
+
console.log(` ${chalk.yellow('ā ļø')} ${tool} (already installed)`);
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
} else {
|
|
83
|
+
console.log(chalk.red('\nā Auto-install encountered issues'));
|
|
84
|
+
|
|
85
|
+
if (isNpmPostinstall) {
|
|
86
|
+
criticalLog(chalk.red('ā STIGMERGY CLI SETUP INCOMPLETE'));
|
|
87
|
+
criticalLog(chalk.yellow('Run: stigmergy install to complete setup manually'));
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (installResult.error) {
|
|
91
|
+
console.log(chalk.red(`Error: ${installResult.error}`));
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Setup verification
|
|
96
|
+
console.log(chalk.blue('\nš Verifying installation...'));
|
|
97
|
+
|
|
98
|
+
// Quick verification of core functionality
|
|
99
|
+
const verificationChecks = [
|
|
100
|
+
{ name: 'Core modules accessible', check: () => require('../utils/formatters') && require('../utils/environment') },
|
|
101
|
+
{ name: 'Error handler available', check: () => require('../../core/error_handler') },
|
|
102
|
+
{ name: 'Smart router available', check: () => require('../../core/smart_router') }
|
|
103
|
+
];
|
|
104
|
+
|
|
105
|
+
let verificationPassed = 0;
|
|
106
|
+
for (const check of verificationChecks) {
|
|
107
|
+
try {
|
|
108
|
+
check.check();
|
|
109
|
+
console.log(` ${chalk.green('ā
')} ${check.name}`);
|
|
110
|
+
verificationPassed++;
|
|
111
|
+
} catch (error) {
|
|
112
|
+
console.log(` ${chalk.red('ā')} ${check.name}`);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
if (verificationPassed === verificationChecks.length) {
|
|
117
|
+
console.log(chalk.green('\nā
All verification checks passed!'));
|
|
118
|
+
|
|
119
|
+
if (isNpmPostinstall) {
|
|
120
|
+
criticalLog(chalk.green('š STIGMERGY CLI IS READY TO USE!'));
|
|
121
|
+
}
|
|
122
|
+
} else {
|
|
123
|
+
console.log(chalk.yellow('\nā ļø Some verification checks failed'));
|
|
124
|
+
console.log(chalk.yellow('Run: stigmergy diagnostic for full system check'));
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Final summary for npm environment
|
|
128
|
+
if (isNpmPostinstall) {
|
|
129
|
+
criticalLog('='.repeat(60));
|
|
130
|
+
criticalLog(chalk.cyan('šÆ STIGMERGY CLI AUTO-INSTALL FINISHED'));
|
|
131
|
+
criticalLog('='.repeat(60));
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
return {
|
|
135
|
+
success: installResult.success,
|
|
136
|
+
verificationPassed,
|
|
137
|
+
installed: installResult.installed || [],
|
|
138
|
+
existing: installResult.existing || []
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
} catch (error) {
|
|
142
|
+
const isNpmPostinstall = process.env.npm_lifecycle_event === 'postinstall';
|
|
143
|
+
const criticalLog = isNpmPostinstall ? console.error : console.log;
|
|
144
|
+
|
|
145
|
+
console.error(chalk.red('[ERROR] Auto-install failed:'), error.message);
|
|
146
|
+
|
|
147
|
+
if (isNpmPostinstall) {
|
|
148
|
+
criticalLog(chalk.red('š„ AUTO-INSTALL FAILED'));
|
|
149
|
+
criticalLog(chalk.yellow('Run: stigmergy install --verbose for detailed installation'));
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
return { success: false, error: error.message };
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
module.exports = {
|
|
157
|
+
handleAutoInstallCommand
|
|
158
|
+
};
|