stigmergy 1.2.13 ā 1.3.2-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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 +16 -5
- package/scripts/analyze-router.js +168 -0
- package/scripts/run-comprehensive-tests.js +230 -0
- package/scripts/run-quick-tests.js +90 -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 +204 -416
- 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 +703 -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 +375 -31
- package/src/core/enhanced_cli_parameter_handler.js +395 -0
- package/src/core/execution_mode_detector.js +222 -0
- package/src/core/installer.js +83 -67
- 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,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
|
+
};
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Error Reporting Commands
|
|
3
|
+
* Modular implementation for error reporting and system troubleshooting
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const chalk = require('chalk');
|
|
7
|
+
const { errorHandler } = require('../../core/error_handler');
|
|
8
|
+
const fs = require('fs').promises;
|
|
9
|
+
const path = require('path');
|
|
10
|
+
const os = require('os');
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Handle errors command - Generate comprehensive error report
|
|
14
|
+
* @param {Object} options - Command options
|
|
15
|
+
*/
|
|
16
|
+
async function handleErrorsCommand(options = {}) {
|
|
17
|
+
try {
|
|
18
|
+
console.log(chalk.cyan('[ERRORS] Generating Stigmergy CLI error report...\n'));
|
|
19
|
+
|
|
20
|
+
const report = {
|
|
21
|
+
timestamp: new Date().toISOString(),
|
|
22
|
+
system: {},
|
|
23
|
+
environment: {},
|
|
24
|
+
errors: [],
|
|
25
|
+
diagnostics: {}
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
// System information
|
|
29
|
+
console.log(chalk.blue('š„ļø System Information:'));
|
|
30
|
+
report.system = {
|
|
31
|
+
platform: os.platform(),
|
|
32
|
+
arch: os.arch(),
|
|
33
|
+
nodeVersion: process.version,
|
|
34
|
+
memory: Math.round(os.totalmem() / 1024 / 1024) + ' MB',
|
|
35
|
+
freeMemory: Math.round(os.freemem() / 1024 / 1024) + ' MB'
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
Object.entries(report.system).forEach(([key, value]) => {
|
|
39
|
+
console.log(` ${key}: ${chalk.green(value)}`);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
// Environment information
|
|
43
|
+
console.log(chalk.blue('\nš Environment Information:'));
|
|
44
|
+
report.environment = {
|
|
45
|
+
pwd: process.cwd(),
|
|
46
|
+
home: os.homedir(),
|
|
47
|
+
shell: process.env.SHELL || process.env.COMSPEC || 'unknown',
|
|
48
|
+
path: process.env.PATH ? process.env.PATH.split(path.delimiter).slice(0, 3).join(path.delimiter) + '...' : 'unknown',
|
|
49
|
+
nodeEnv: process.env.NODE_ENV || 'undefined',
|
|
50
|
+
debugMode: process.env.DEBUG === 'true'
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
Object.entries(report.environment).forEach(([key, value]) => {
|
|
54
|
+
console.log(` ${key}: ${chalk.green(value)}`);
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
// Error handler report (if available)
|
|
58
|
+
console.log(chalk.blue('\nš Error Handler Report:'));
|
|
59
|
+
try {
|
|
60
|
+
if (errorHandler && typeof errorHandler.printErrorReport === 'function') {
|
|
61
|
+
await errorHandler.printErrorReport();
|
|
62
|
+
console.log(chalk.green(' ā
Error handler report generated'));
|
|
63
|
+
} else {
|
|
64
|
+
console.log(chalk.yellow(' ā ļø Error handler not available'));
|
|
65
|
+
}
|
|
66
|
+
} catch (error) {
|
|
67
|
+
console.log(chalk.red(` ā Error handler failed: ${error.message}`));
|
|
68
|
+
report.errors.push({
|
|
69
|
+
type: 'error_handler',
|
|
70
|
+
message: error.message,
|
|
71
|
+
timestamp: new Date().toISOString()
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Check for common issues
|
|
76
|
+
console.log(chalk.blue('\nš Common Issues Check:'));
|
|
77
|
+
|
|
78
|
+
const checks = [
|
|
79
|
+
{
|
|
80
|
+
name: 'Current directory writable',
|
|
81
|
+
check: async () => {
|
|
82
|
+
try {
|
|
83
|
+
await fs.access(process.cwd(), fs.constants.W_OK);
|
|
84
|
+
return true;
|
|
85
|
+
} catch {
|
|
86
|
+
return false;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
name: 'Home directory accessible',
|
|
92
|
+
check: async () => {
|
|
93
|
+
try {
|
|
94
|
+
await fs.access(os.homedir(), fs.constants.R_OK);
|
|
95
|
+
return true;
|
|
96
|
+
} catch {
|
|
97
|
+
return false;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
name: 'Node modules accessible',
|
|
103
|
+
check: async () => {
|
|
104
|
+
try {
|
|
105
|
+
await fs.access(path.join(process.cwd(), 'node_modules'), fs.constants.R_OK);
|
|
106
|
+
return true;
|
|
107
|
+
} catch {
|
|
108
|
+
return false;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
name: 'Package.json exists',
|
|
114
|
+
check: async () => {
|
|
115
|
+
try {
|
|
116
|
+
await fs.access(path.join(process.cwd(), 'package.json'), fs.constants.R_OK);
|
|
117
|
+
return true;
|
|
118
|
+
} catch {
|
|
119
|
+
return false;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
];
|
|
124
|
+
|
|
125
|
+
for (const check of checks) {
|
|
126
|
+
try {
|
|
127
|
+
const passed = await check.check();
|
|
128
|
+
const icon = passed ? chalk.green('ā
') : chalk.red('ā');
|
|
129
|
+
console.log(` ${icon} ${check.name}`);
|
|
130
|
+
|
|
131
|
+
if (!passed) {
|
|
132
|
+
report.errors.push({
|
|
133
|
+
type: 'common_issue',
|
|
134
|
+
message: `${check.name} failed`,
|
|
135
|
+
timestamp: new Date().toISOString()
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
} catch (error) {
|
|
139
|
+
console.log(` ${chalk.yellow('ā ļø')} ${check.name} - Check failed`);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// Log files check
|
|
144
|
+
console.log(chalk.blue('\nš Log Files:'));
|
|
145
|
+
const logLocations = [
|
|
146
|
+
path.join(os.homedir(), '.stigmergy', 'logs'),
|
|
147
|
+
path.join(process.cwd(), 'logs'),
|
|
148
|
+
path.join(os.tmpdir(), 'stigmergy-logs')
|
|
149
|
+
];
|
|
150
|
+
|
|
151
|
+
for (const logLocation of logLocations) {
|
|
152
|
+
try {
|
|
153
|
+
const stats = await fs.stat(logLocation);
|
|
154
|
+
console.log(` ${chalk.green('ā
')} ${logLocation} (${stats.size} bytes)`);
|
|
155
|
+
} catch {
|
|
156
|
+
console.log(` ${chalk.gray('āŖ')} ${logLocation} (not found)`);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// Summary
|
|
161
|
+
console.log(chalk.blue('\nš Error Report Summary:'));
|
|
162
|
+
const errorCount = report.errors.length;
|
|
163
|
+
const warningCount = report.environment.debugMode ? 1 : 0;
|
|
164
|
+
|
|
165
|
+
console.log(` Errors: ${chalk.red(errorCount)}`);
|
|
166
|
+
console.log(` Warnings: ${chalk.yellow(warningCount)}`);
|
|
167
|
+
|
|
168
|
+
if (errorCount === 0) {
|
|
169
|
+
console.log(chalk.green('\nā
No critical errors detected!'));
|
|
170
|
+
} else {
|
|
171
|
+
console.log(chalk.red(`\nā ${errorCount} issue(s) found - see details above`));
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// Save report to file if requested
|
|
175
|
+
if (options.save) {
|
|
176
|
+
const reportPath = path.join(process.cwd(), `stigmergy-error-report-${Date.now()}.json`);
|
|
177
|
+
await fs.writeFile(reportPath, JSON.stringify(report, null, 2));
|
|
178
|
+
console.log(chalk.blue(`\nš¾ Report saved to: ${reportPath}`));
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
return { success: true, report };
|
|
182
|
+
} catch (error) {
|
|
183
|
+
console.error(chalk.red('[ERROR] Failed to generate error report:'), error.message);
|
|
184
|
+
return { success: false, error: error.message };
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
module.exports = {
|
|
189
|
+
handleErrorsCommand
|
|
190
|
+
};
|