stigmergy 1.2.13 โ†’ 1.3.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.
Files changed (88) hide show
  1. package/README.md +39 -3
  2. package/STIGMERGY.md +3 -0
  3. package/config/builtin-skills.json +43 -0
  4. package/config/enhanced-cli-config.json +438 -0
  5. package/docs/CLI_TOOLS_AGENT_SKILL_ANALYSIS.md +463 -0
  6. package/docs/DESIGN_CLI_HELP_ANALYZER_REFACTOR.md +726 -0
  7. package/docs/ENHANCED_CLI_AGENT_SKILL_CONFIG.md +285 -0
  8. package/docs/IMPLEMENTATION_CHECKLIST_CLI_HELP_ANALYZER_REFACTOR.md +1268 -0
  9. package/docs/INSTALLER_ARCHITECTURE.md +257 -0
  10. package/docs/LESSONS_LEARNED.md +252 -0
  11. package/docs/SPECS_CLI_HELP_ANALYZER_REFACTOR.md +287 -0
  12. package/docs/SUDO_PROBLEM_AND_SOLUTION.md +529 -0
  13. package/docs/correct-skillsio-implementation.md +368 -0
  14. package/docs/development_guidelines.md +276 -0
  15. package/docs/independent-resume-implementation.md +198 -0
  16. package/docs/resumesession-final-implementation.md +195 -0
  17. package/docs/resumesession-usage.md +87 -0
  18. package/package.json +146 -136
  19. package/scripts/analyze-router.js +168 -0
  20. package/scripts/run-comprehensive-tests.js +230 -0
  21. package/scripts/run-quick-tests.js +90 -0
  22. package/scripts/test-runner.js +344 -0
  23. package/skills/resumesession/INDEPENDENT_SKILL.md +403 -0
  24. package/skills/resumesession/README.md +381 -0
  25. package/skills/resumesession/SKILL.md +211 -0
  26. package/skills/resumesession/__init__.py +33 -0
  27. package/skills/resumesession/implementations/simple-resume.js +13 -0
  28. package/skills/resumesession/independent-resume.js +750 -0
  29. package/skills/resumesession/package.json +1 -0
  30. package/skills/resumesession/skill.json +1 -0
  31. package/src/adapters/claude/install_claude_integration.js +9 -1
  32. package/src/adapters/codebuddy/install_codebuddy_integration.js +3 -1
  33. package/src/adapters/codex/install_codex_integration.js +15 -5
  34. package/src/adapters/gemini/install_gemini_integration.js +3 -1
  35. package/src/adapters/qwen/install_qwen_integration.js +3 -1
  36. package/src/cli/commands/autoinstall.js +65 -0
  37. package/src/cli/commands/errors.js +190 -0
  38. package/src/cli/commands/independent-resume.js +395 -0
  39. package/src/cli/commands/install.js +179 -0
  40. package/src/cli/commands/permissions.js +108 -0
  41. package/src/cli/commands/project.js +485 -0
  42. package/src/cli/commands/scan.js +97 -0
  43. package/src/cli/commands/simple-resume.js +377 -0
  44. package/src/cli/commands/skills.js +158 -0
  45. package/src/cli/commands/status.js +113 -0
  46. package/src/cli/commands/stigmergy-resume.js +775 -0
  47. package/src/cli/commands/system.js +301 -0
  48. package/src/cli/commands/universal-resume.js +394 -0
  49. package/src/cli/router-beta.js +471 -0
  50. package/src/cli/utils/environment.js +75 -0
  51. package/src/cli/utils/formatters.js +47 -0
  52. package/src/cli/utils/skills_cache.js +92 -0
  53. package/src/core/cache_cleaner.js +1 -0
  54. package/src/core/cli_adapters.js +345 -0
  55. package/src/core/cli_help_analyzer.js +1236 -680
  56. package/src/core/cli_path_detector.js +702 -709
  57. package/src/core/cli_tools.js +515 -160
  58. package/src/core/coordination/nodejs/CLIIntegrationManager.js +18 -0
  59. package/src/core/coordination/nodejs/HookDeploymentManager.js +242 -412
  60. package/src/core/coordination/nodejs/HookDeploymentManager.refactored.js +323 -0
  61. package/src/core/coordination/nodejs/generators/CLIAdapterGenerator.js +363 -0
  62. package/src/core/coordination/nodejs/generators/ResumeSessionGenerator.js +932 -0
  63. package/src/core/coordination/nodejs/generators/SkillsIntegrationGenerator.js +1395 -0
  64. package/src/core/coordination/nodejs/generators/index.js +12 -0
  65. package/src/core/enhanced_cli_installer.js +1208 -608
  66. package/src/core/enhanced_cli_parameter_handler.js +402 -0
  67. package/src/core/execution_mode_detector.js +222 -0
  68. package/src/core/installer.js +151 -106
  69. package/src/core/local_skill_scanner.js +732 -0
  70. package/src/core/multilingual/language-pattern-manager.js +1 -1
  71. package/src/core/skills/BuiltinSkillsDeployer.js +188 -0
  72. package/src/core/skills/StigmergySkillManager.js +123 -16
  73. package/src/core/skills/embedded-openskills/SkillParser.js +7 -3
  74. package/src/core/smart_router.js +550 -261
  75. package/src/index.js +10 -4
  76. package/src/utils.js +66 -7
  77. package/test/cli-integration.test.js +304 -0
  78. package/test/direct_smart_router_test.js +88 -0
  79. package/test/enhanced-cli-agent-skill-test.js +485 -0
  80. package/test/simple_test.js +82 -0
  81. package/test/smart_router_test_runner.js +123 -0
  82. package/test/smart_routing_edge_cases.test.js +284 -0
  83. package/test/smart_routing_simple_verification.js +139 -0
  84. package/test/smart_routing_verification.test.js +346 -0
  85. package/test/specific-cli-agent-skill-analysis.js +385 -0
  86. package/test/unit/smart_router.test.js +295 -0
  87. package/test/very_simple_test.js +54 -0
  88. package/src/cli/router.js +0 -1783
@@ -0,0 +1,230 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Comprehensive Test Runner
5
+ * Runs all tests and generates detailed coverage report
6
+ */
7
+
8
+ const { execSync } = require('child_process');
9
+ const fs = require('fs');
10
+ const path = require('path');
11
+
12
+ console.log('๐ŸŽฏ COMPREHENSIVE TEST SUITE');
13
+ console.log('='.repeat(70));
14
+
15
+ // ANSI color codes
16
+ const colors = {
17
+ reset: '\x1b[0m',
18
+ green: '\x1b[32m',
19
+ red: '\x1b[31m',
20
+ yellow: '\x1b[33m',
21
+ blue: '\x1b[34m',
22
+ cyan: '\x1b[36m'
23
+ };
24
+
25
+ function log(message, color = 'reset') {
26
+ console.log(`${colors[color]}${message}${colors.reset}`);
27
+ }
28
+
29
+ function runCommand(command, description) {
30
+ log(`\n๐Ÿ“ฆ ${description}...`, 'cyan');
31
+
32
+ try {
33
+ const output = execSync(command, {
34
+ stdio: 'inherit',
35
+ cwd: process.cwd()
36
+ });
37
+ log(`โœ… ${description} completed`, 'green');
38
+ return true;
39
+ } catch (error) {
40
+ log(`โŒ ${description} failed`, 'red');
41
+ log(`Error: ${error.message}`, 'red');
42
+ return false;
43
+ }
44
+ }
45
+
46
+ function ensureDirectories() {
47
+ const dirs = [
48
+ 'tests/comprehensive/cli',
49
+ 'tests/comprehensive/cli/commands',
50
+ 'tests/comprehensive/core',
51
+ 'tests/comprehensive/coordination',
52
+ 'tests/comprehensive/adapters',
53
+ 'tests/comprehensive/utils',
54
+ 'coverage'
55
+ ];
56
+
57
+ dirs.forEach(dir => {
58
+ const fullPath = path.join(process.cwd(), dir);
59
+ if (!fs.existsSync(fullPath)) {
60
+ fs.mkdirSync(fullPath, { recursive: true });
61
+ }
62
+ });
63
+ }
64
+
65
+ function countTestFiles() {
66
+ const testDirs = [
67
+ 'tests/unit',
68
+ 'tests/integration',
69
+ 'tests/e2e',
70
+ 'tests/comprehensive',
71
+ 'tests/regression'
72
+ ];
73
+
74
+ let totalTests = 0;
75
+ testDirs.forEach(dir => {
76
+ const testPath = path.join(process.cwd(), dir);
77
+ if (fs.existsSync(testPath)) {
78
+ const files = fs.readdirSync(testPath)
79
+ .filter(f => f.endsWith('.test.js'));
80
+ totalTests += files.length;
81
+ }
82
+ });
83
+
84
+ return totalTests;
85
+ }
86
+
87
+ function countSourceFiles() {
88
+ const srcPath = path.join(process.cwd(), 'src');
89
+
90
+ function countDir(dir) {
91
+ let count = 0;
92
+ const items = fs.readdirSync(dir, { withFileTypes: true });
93
+
94
+ items.forEach(item => {
95
+ if (item.isDirectory()) {
96
+ count += countDir(path.join(dir, item.name));
97
+ } else if (item.name.endsWith('.js')) {
98
+ count++;
99
+ }
100
+ });
101
+
102
+ return count;
103
+ }
104
+
105
+ return countDir(srcPath);
106
+ }
107
+
108
+ function printSummary() {
109
+ log('\n' + '='.repeat(70), 'cyan');
110
+ log('๐Ÿ“Š TEST SUITE SUMMARY', 'cyan');
111
+ log('='.repeat(70), 'cyan');
112
+
113
+ const sourceFiles = countSourceFiles();
114
+ const testFiles = countTestFiles();
115
+ const coverage = ((testFiles / sourceFiles) * 100).toFixed(1);
116
+
117
+ log(`\n๐Ÿ“ Source Files: ${sourceFiles}`);
118
+ log(`๐Ÿงช Test Files: ${testFiles}`);
119
+ log(`๐Ÿ“ˆ Test Coverage: ${coverage}%`);
120
+
121
+ log('\n' + '='.repeat(70), 'cyan');
122
+ }
123
+
124
+ function readCoverageReport() {
125
+ const coveragePath = path.join(process.cwd(), 'coverage', 'coverage-summary.json');
126
+
127
+ if (!fs.existsSync(coveragePath)) {
128
+ log('\nโš ๏ธ Coverage report not found', 'yellow');
129
+ return;
130
+ }
131
+
132
+ const coverage = JSON.parse(fs.readFileSync(coveragePath, 'utf8'));
133
+
134
+ log('\n' + '='.repeat(70), 'cyan');
135
+ log('๐Ÿ“Š DETAILED COVERAGE REPORT', 'cyan');
136
+ log('='.repeat(70), 'cyan');
137
+
138
+ const total = coverage.total;
139
+ log(`\n๐Ÿ“ˆ Overall Coverage:`, 'cyan');
140
+ log(` Statements: ${total.statements.pct}% (${total.statements.covered}/${total.statements.total})`);
141
+ log(` Branches: ${total.branches.pct}% (${total.branches.covered}/${total.branches.total})`);
142
+ log(` Functions: ${total.functions.pct}% (${total.functions.covered}/${total.functions.total})`);
143
+ log(` Lines: ${total.lines.pct}% (${total.lines.covered}/${total.lines.total})`);
144
+
145
+ // Find files with low coverage
146
+ log('\n๐Ÿ“‰ Files with Low Coverage (< 80%):', 'yellow');
147
+ let lowCoverageFound = false;
148
+
149
+ Object.entries(coverage).forEach(([file, data]) => {
150
+ if (file !== 'total' && data.statements.pct < 80) {
151
+ lowCoverageFound = true;
152
+ const relativePath = file.replace(process.cwd(), '');
153
+ log(` ${relativePath}: ${data.statements.pct}%`, 'red');
154
+ }
155
+ });
156
+
157
+ if (!lowCoverageFound) {
158
+ log(' โœ… All files have good coverage!', 'green');
159
+ }
160
+
161
+ log('\n' + '='.repeat(70), 'cyan');
162
+ }
163
+
164
+ async function main() {
165
+ const startTime = Date.now();
166
+
167
+ try {
168
+ // Ensure test directories exist
169
+ ensureDirectories();
170
+
171
+ // Print initial summary
172
+ log('\n๐Ÿ” Test Environment:', 'blue');
173
+ log(` Node.js: ${process.version}`);
174
+ log(` Platform: ${process.platform}`);
175
+ log(` CWD: ${process.cwd()}`);
176
+
177
+ // Run pre-test cleanup
178
+ log('\n๐Ÿงน Cleaning test environment...', 'blue');
179
+ try {
180
+ execSync('npm run clean 2>/dev/null || true', { stdio: 'ignore' });
181
+ } catch (e) {
182
+ // Ignore cleanup errors
183
+ }
184
+
185
+ // Run tests by category
186
+ const results = {
187
+ unit: runCommand('npm run test:unit -- --silent', 'Unit Tests'),
188
+ integration: runCommand('npm run test:integration -- --silent', 'Integration Tests'),
189
+ comprehensive: runCommand('jest tests/comprehensive --coverage --silent', 'Comprehensive Tests')
190
+ };
191
+
192
+ // Generate coverage report
193
+ if (results.comprehensive) {
194
+ readCoverageReport();
195
+ }
196
+
197
+ // Calculate duration
198
+ const duration = ((Date.now() - startTime) / 1000).toFixed(2);
199
+
200
+ // Print final summary
201
+ printSummary();
202
+
203
+ log(`\nโฑ๏ธ Total Duration: ${duration}s`, 'blue');
204
+
205
+ // Determine success
206
+ const allPassed = Object.values(results).every(r => r === true);
207
+
208
+ if (allPassed) {
209
+ log('\nโœ… ALL TESTS PASSED!', 'green');
210
+ log('\n๐ŸŽ‰ Great job! Your test suite is comprehensive.', 'green');
211
+ process.exit(0);
212
+ } else {
213
+ log('\nโŒ SOME TESTS FAILED', 'red');
214
+ log('\n๐Ÿ’ก Run with --verbose to see detailed error messages', 'yellow');
215
+ process.exit(1);
216
+ }
217
+
218
+ } catch (error) {
219
+ log(`\n๐Ÿ’ฅ Fatal Error: ${error.message}`, 'red');
220
+ console.error(error);
221
+ process.exit(1);
222
+ }
223
+ }
224
+
225
+ // Run if executed directly
226
+ if (require.main === module) {
227
+ main();
228
+ }
229
+
230
+ module.exports = { runCommand, readCoverageReport, printSummary };
@@ -0,0 +1,90 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Quick Test Runner
5
+ * Runs only the comprehensive tests without legacy tests
6
+ */
7
+
8
+ const { execSync } = require('child_process');
9
+ const fs = require('fs');
10
+ const path = require('path');
11
+
12
+ console.log('๐ŸŽฏ QUICK COMPREHENSIVE TEST SUITE');
13
+ console.log('='.repeat(70));
14
+
15
+ // ANSI colors
16
+ const colors = {
17
+ reset: '\x1b[0m',
18
+ green: '\x1b[32m',
19
+ red: '\x1b[31m',
20
+ yellow: '\x1b[33m',
21
+ blue: '\x1b[34m',
22
+ cyan: '\x1b[36m'
23
+ };
24
+
25
+ function log(message, color = 'reset') {
26
+ console.log(`${colors[color]}${message}${colors.reset}`);
27
+ }
28
+
29
+ function runCommand(command, description) {
30
+ log(`\n๐Ÿ“ฆ ${description}...`, 'cyan');
31
+
32
+ try {
33
+ const output = execSync(command, {
34
+ stdio: 'inherit',
35
+ cwd: process.cwd()
36
+ });
37
+ log(`โœ… ${description} completed`, 'green');
38
+ return true;
39
+ } catch (error) {
40
+ log(`โŒ ${description} failed`, 'red');
41
+ return false;
42
+ }
43
+ }
44
+
45
+ async function main() {
46
+ const startTime = Date.now();
47
+
48
+ try {
49
+ log('\n๐Ÿ” Running comprehensive tests only...', 'blue');
50
+
51
+ // Ensure directories exist
52
+ const dirs = ['tests/comprehensive/cli/commands', 'tests/comprehensive/core', 'tests/comprehensive/coordination'];
53
+ dirs.forEach(dir => {
54
+ const fullPath = path.join(process.cwd(), dir);
55
+ if (!fs.existsSync(fullPath)) {
56
+ fs.mkdirSync(fullPath, { recursive: true });
57
+ }
58
+ });
59
+
60
+ // Run comprehensive tests only
61
+ const result = runCommand(
62
+ 'jest tests/comprehensive --coverage',
63
+ 'Comprehensive Tests'
64
+ );
65
+
66
+ // Calculate duration
67
+ const duration = ((Date.now() - startTime) / 1000).toFixed(2);
68
+
69
+ log(`\nโฑ๏ธ Duration: ${duration}s`, 'blue');
70
+
71
+ if (result) {
72
+ log('\nโœ… ALL TESTS PASSED!', 'green');
73
+ process.exit(0);
74
+ } else {
75
+ log('\nโŒ SOME TESTS FAILED', 'red');
76
+ log('\n๐Ÿ’ก Check the output above for details', 'yellow');
77
+ process.exit(1);
78
+ }
79
+
80
+ } catch (error) {
81
+ log(`\n๐Ÿ’ฅ Fatal Error: ${error.message}`, 'red');
82
+ process.exit(1);
83
+ }
84
+ }
85
+
86
+ if (require.main === module) {
87
+ main();
88
+ }
89
+
90
+ module.exports = { runCommand };
@@ -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;