vibecodingmachine-core 2026.2.20-438 ā 2026.2.26-1642
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 +240 -0
- package/package.json +10 -2
- package/src/agents/Agent.js +300 -0
- package/src/agents/AgentAdditionService.js +311 -0
- package/src/agents/AgentCheckService.js +690 -0
- package/src/agents/AgentInstallationService.js +140 -0
- package/src/agents/AgentSetupService.js +467 -0
- package/src/agents/AgentStatus.js +183 -0
- package/src/agents/AgentVerificationService.js +634 -0
- package/src/agents/ConfigurationSchemaValidator.js +543 -0
- package/src/agents/EnvironmentConfigurationManager.js +602 -0
- package/src/agents/InstallationErrorHandler.js +372 -0
- package/src/agents/InstallationLog.js +363 -0
- package/src/agents/InstallationMethod.js +510 -0
- package/src/agents/InstallationOrchestrator.js +352 -0
- package/src/agents/InstallationProgressReporter.js +372 -0
- package/src/agents/InstallationRetryManager.js +322 -0
- package/src/agents/InstallationType.js +254 -0
- package/src/agents/OperationTypes.js +310 -0
- package/src/agents/PerformanceMetricsCollector.js +493 -0
- package/src/agents/SecurityValidationService.js +534 -0
- package/src/agents/VerificationTest.js +354 -0
- package/src/agents/VerificationType.js +226 -0
- package/src/agents/WindowsPermissionHandler.js +518 -0
- package/src/agents/config/AgentConfigManager.js +393 -0
- package/src/agents/config/AgentDefaultsRegistry.js +373 -0
- package/src/agents/config/ConfigValidator.js +281 -0
- package/src/agents/discovery/AgentDiscoveryService.js +707 -0
- package/src/agents/logging/AgentLogger.js +511 -0
- package/src/agents/status/AgentStatusManager.js +481 -0
- package/src/agents/storage/FileManager.js +454 -0
- package/src/agents/verification/AgentCommunicationTester.js +474 -0
- package/src/agents/verification/BaseVerifier.js +430 -0
- package/src/agents/verification/CommandVerifier.js +480 -0
- package/src/agents/verification/FileOperationVerifier.js +453 -0
- package/src/agents/verification/ResultAnalyzer.js +707 -0
- package/src/agents/verification/TestRequirementManager.js +495 -0
- package/src/agents/verification/VerificationRunner.js +433 -0
- package/src/agents/windows/BaseWindowsInstaller.js +441 -0
- package/src/agents/windows/ChocolateyInstaller.js +509 -0
- package/src/agents/windows/DirectInstaller.js +443 -0
- package/src/agents/windows/InstallerFactory.js +391 -0
- package/src/agents/windows/NpmInstaller.js +505 -0
- package/src/agents/windows/PowerShellInstaller.js +458 -0
- package/src/agents/windows/WinGetInstaller.js +390 -0
- package/src/analysis/analysis-reporter.js +132 -0
- package/src/analysis/boundary-detector.js +712 -0
- package/src/analysis/categorizer.js +340 -0
- package/src/analysis/codebase-scanner.js +384 -0
- package/src/analysis/line-counter.js +513 -0
- package/src/analysis/priority-calculator.js +679 -0
- package/src/analysis/report/analysis-report.js +250 -0
- package/src/analysis/report/package-analyzer.js +278 -0
- package/src/analysis/report/recommendation-generator.js +382 -0
- package/src/analysis/report/statistics-generator.js +515 -0
- package/src/analysis/reports/analysis-report-model.js +101 -0
- package/src/analysis/reports/recommendation-generator.js +283 -0
- package/src/analysis/reports/report-generators.js +191 -0
- package/src/analysis/reports/statistics-calculator.js +231 -0
- package/src/analysis/reports/trend-analyzer.js +219 -0
- package/src/analysis/strategy-generator.js +814 -0
- package/src/auto-mode/AutoModeBusinessLogic.js +836 -0
- package/src/config/refactoring-config.js +307 -0
- package/src/health-tracking/json-storage.js +38 -2
- package/src/ide-integration/applescript-manager-core.js +233 -0
- package/src/ide-integration/applescript-manager.cjs +357 -28
- package/src/ide-integration/applescript-manager.js +89 -3599
- package/src/ide-integration/cdp-manager.js +306 -0
- package/src/ide-integration/claude-code-cli-manager.cjs +1 -1
- package/src/ide-integration/continuation-handler.js +337 -0
- package/src/ide-integration/ide-status-checker.js +292 -0
- package/src/ide-integration/macos-ide-manager.js +627 -0
- package/src/ide-integration/macos-text-sender.js +528 -0
- package/src/ide-integration/response-reader.js +548 -0
- package/src/ide-integration/windows-automation-manager.js +121 -0
- package/src/ide-integration/windows-ide-manager.js +373 -0
- package/src/index.cjs +25 -3
- package/src/index.js +15 -1
- package/src/llm/direct-llm-manager.cjs +90 -2
- package/src/models/compliance-report.js +538 -0
- package/src/models/file-analysis.js +681 -0
- package/src/models/refactoring-plan.js +770 -0
- package/src/monitoring/alert-system.js +834 -0
- package/src/monitoring/compliance-progress-tracker.js +437 -0
- package/src/monitoring/continuous-scan-notifications.js +661 -0
- package/src/monitoring/continuous-scanner.js +279 -0
- package/src/monitoring/file-monitor/file-analyzer.js +262 -0
- package/src/monitoring/file-monitor/file-monitor.js +237 -0
- package/src/monitoring/file-monitor/watcher.js +194 -0
- package/src/monitoring/file-monitor.js +17 -0
- package/src/monitoring/notification-manager.js +437 -0
- package/src/monitoring/scanner-core.js +368 -0
- package/src/monitoring/scanner-events.js +214 -0
- package/src/monitoring/violation-notification-system.js +515 -0
- package/src/refactoring/boundaries/cohesion-analyzer.js +316 -0
- package/src/refactoring/boundaries/extraction-result.js +285 -0
- package/src/refactoring/boundaries/extraction-strategies.js +392 -0
- package/src/refactoring/boundaries/module-boundary.js +209 -0
- package/src/refactoring/boundary/boundary-detector.js +741 -0
- package/src/refactoring/boundary/boundary-types.js +405 -0
- package/src/refactoring/boundary/extraction-strategies.js +554 -0
- package/src/refactoring/boundary-extraction-result.js +77 -0
- package/src/refactoring/boundary-extraction-strategies.js +330 -0
- package/src/refactoring/boundary-extractor.js +384 -0
- package/src/refactoring/boundary-types.js +46 -0
- package/src/refactoring/circular/circular-dependency.js +88 -0
- package/src/refactoring/circular/cycle-detection.js +147 -0
- package/src/refactoring/circular/dependency-node.js +82 -0
- package/src/refactoring/circular/dependency-result.js +107 -0
- package/src/refactoring/circular/dependency-types.js +58 -0
- package/src/refactoring/circular/graph-builder.js +213 -0
- package/src/refactoring/circular/resolution-strategy.js +72 -0
- package/src/refactoring/circular/strategy-generator.js +229 -0
- package/src/refactoring/circular-dependency-resolver-original.js +809 -0
- package/src/refactoring/circular-dependency-resolver.js +200 -0
- package/src/refactoring/code-mover.js +761 -0
- package/src/refactoring/file-splitter.js +696 -0
- package/src/refactoring/functionality-validator.js +816 -0
- package/src/refactoring/import-manager.js +774 -0
- package/src/refactoring/module-boundary.js +107 -0
- package/src/refactoring/refactoring-executor.js +672 -0
- package/src/refactoring/refactoring-rollback.js +614 -0
- package/src/refactoring/test-validator.js +631 -0
- package/src/requirement-management/default-requirement-manager.js +321 -0
- package/src/requirement-management/requirement-file-parser.js +159 -0
- package/src/requirement-management/requirement-sequencer.js +221 -0
- package/src/rui/commands/AgentCommandParser.js +600 -0
- package/src/rui/commands/AgentCommands.js +487 -0
- package/src/rui/commands/AgentResponseFormatter.js +832 -0
- package/src/scripts/verify-full-compliance.js +269 -0
- package/src/sync/sync-engine-core.js +1 -0
- package/src/sync/sync-engine-remote-handlers.js +135 -0
- package/src/task-generation/automated-task-generator.js +351 -0
- package/src/task-generation/prioritizer.js +287 -0
- package/src/task-generation/task-list-updater.js +215 -0
- package/src/task-generation/task-management-integration.js +480 -0
- package/src/task-generation/task-manager-integration.js +270 -0
- package/src/task-generation/violation-task-generator.js +474 -0
- package/src/task-management/continuous-scan-integration.js +342 -0
- package/src/timeout-management/index.js +12 -3
- package/src/timeout-management/response-time-tracker.js +167 -0
- package/src/timeout-management/timeout-calculator.js +159 -0
- package/src/timeout-management/timeout-config-manager.js +172 -0
- package/src/utils/ast-analyzer.js +417 -0
- package/src/utils/current-requirement-manager.js +276 -0
- package/src/utils/current-requirement-operations.js +472 -0
- package/src/utils/dependency-mapper.js +456 -0
- package/src/utils/download-with-progress.js +4 -2
- package/src/utils/electron-update-checker.js +4 -1
- package/src/utils/file-size-analyzer.js +272 -0
- package/src/utils/import-updater.js +280 -0
- package/src/utils/refactoring-tools.js +512 -0
- package/src/utils/report-generator.js +569 -0
- package/src/utils/reports/report-analysis.js +218 -0
- package/src/utils/reports/report-types.js +55 -0
- package/src/utils/reports/summary-generators.js +102 -0
- package/src/utils/requirement-file-management.js +157 -0
- package/src/utils/requirement-helpers/requirement-file-ops.js +392 -0
- package/src/utils/requirement-helpers/requirement-mover.js +414 -0
- package/src/utils/requirement-helpers/requirement-parser.js +326 -0
- package/src/utils/requirement-helpers/requirement-status.js +320 -0
- package/src/utils/requirement-helpers-new.js +55 -0
- package/src/utils/requirement-helpers-refactored.js +367 -0
- package/src/utils/requirement-helpers.js +291 -1191
- package/src/utils/requirement-movement-operations.js +450 -0
- package/src/utils/requirement-movement.js +312 -0
- package/src/utils/requirement-parsing-helpers.js +56 -0
- package/src/utils/requirement-statistics.js +200 -0
- package/src/utils/requirement-text-utils.js +58 -0
- package/src/utils/rollback/rollback-handlers.js +125 -0
- package/src/utils/rollback/rollback-operation.js +63 -0
- package/src/utils/rollback/rollback-recorder.js +166 -0
- package/src/utils/rollback/rollback-state-manager.js +175 -0
- package/src/utils/rollback/rollback-types.js +33 -0
- package/src/utils/rollback/rollback-utils.js +110 -0
- package/src/utils/rollback-manager-original.js +569 -0
- package/src/utils/rollback-manager.js +202 -0
- package/src/utils/smoke-test-cli.js +362 -0
- package/src/utils/smoke-test-gui.js +351 -0
- package/src/utils/smoke-test-orchestrator.js +321 -0
- package/src/utils/smoke-test-runner.js +60 -0
- package/src/utils/smoke-test-web.js +347 -0
- package/src/utils/specification-helpers.js +39 -13
- package/src/utils/specification-migration.js +97 -0
- package/src/utils/test-runner.js +579 -0
- package/src/utils/validation-framework.js +518 -0
- package/src/validation/compliance-analyzer.js +197 -0
- package/src/validation/compliance-report-generator.js +343 -0
- package/src/validation/compliance-reporter.js +711 -0
- package/src/validation/compliance-rules.js +127 -0
- package/src/validation/constitution-validator-new.js +196 -0
- package/src/validation/constitution-validator.js +17 -0
- package/src/validation/file-validators.js +170 -0
- package/src/validation/line-limit/file-analyzer.js +201 -0
- package/src/validation/line-limit/line-limit-validator.js +208 -0
- package/src/validation/line-limit/validation-result.js +144 -0
- package/src/validation/line-limit-core.js +225 -0
- package/src/validation/line-limit-reporter.js +134 -0
- package/src/validation/line-limit-result.js +125 -0
- package/src/validation/line-limit-validator.js +41 -0
- package/src/validation/metrics-calculator.js +660 -0
- package/src/sync/sync-engine-backup.js +0 -559
|
@@ -0,0 +1,351 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GUI Smoke Testing Utility
|
|
3
|
+
*
|
|
4
|
+
* Provides smoke testing functionality for the GUI (Electron) interface
|
|
5
|
+
* to ensure it starts without critical errors.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const { spawn } = require('child_process');
|
|
9
|
+
const path = require('path');
|
|
10
|
+
const fs = require('fs');
|
|
11
|
+
|
|
12
|
+
class GuiSmokeTest {
|
|
13
|
+
constructor(options = {}) {
|
|
14
|
+
this.guiPath = options.guiPath || path.join(__dirname, '../../../electron-app');
|
|
15
|
+
this.mainScript = options.mainScript || 'src/main.js';
|
|
16
|
+
this.timeout = options.timeout || 45000; // 45 seconds for Electron startup
|
|
17
|
+
this.verbose = options.verbose || false;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Run comprehensive GUI smoke tests
|
|
22
|
+
* @returns {Promise<Object>} Test results
|
|
23
|
+
*/
|
|
24
|
+
async runSmokeTests() {
|
|
25
|
+
const results = {
|
|
26
|
+
passed: 0,
|
|
27
|
+
failed: 0,
|
|
28
|
+
total: 0,
|
|
29
|
+
details: []
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const tests = [
|
|
33
|
+
{ name: 'GUI Directory Exists', test: () => this.testGuiDirectoryExists() },
|
|
34
|
+
{ name: 'Package.json Exists', test: () => this.testPackageJsonExists() },
|
|
35
|
+
{ name: 'Main Script Exists', test: () => this.testMainScriptExists() },
|
|
36
|
+
{ name: 'Dependencies Available', test: () => this.testDependenciesAvailable() },
|
|
37
|
+
{ name: 'GUI Starts Without Crashing', test: () => this.testGuiStarts() }
|
|
38
|
+
];
|
|
39
|
+
|
|
40
|
+
for (const test of tests) {
|
|
41
|
+
results.total++;
|
|
42
|
+
try {
|
|
43
|
+
const result = await test.test();
|
|
44
|
+
if (result.passed) {
|
|
45
|
+
results.passed++;
|
|
46
|
+
if (this.verbose) {
|
|
47
|
+
console.log(`ā
${test.name}: PASSED`);
|
|
48
|
+
}
|
|
49
|
+
} else {
|
|
50
|
+
results.failed++;
|
|
51
|
+
console.error(`ā ${test.name}: FAILED - ${result.error}`);
|
|
52
|
+
}
|
|
53
|
+
results.details.push({
|
|
54
|
+
name: test.name,
|
|
55
|
+
passed: result.passed,
|
|
56
|
+
error: result.error,
|
|
57
|
+
details: result.details
|
|
58
|
+
});
|
|
59
|
+
} catch (error) {
|
|
60
|
+
results.failed++;
|
|
61
|
+
console.error(`ā ${test.name}: ERROR - ${error.message}`);
|
|
62
|
+
results.details.push({
|
|
63
|
+
name: test.name,
|
|
64
|
+
passed: false,
|
|
65
|
+
error: error.message,
|
|
66
|
+
details: null
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return {
|
|
72
|
+
success: results.failed === 0,
|
|
73
|
+
...results
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Test if GUI directory exists
|
|
79
|
+
*/
|
|
80
|
+
async testGuiDirectoryExists() {
|
|
81
|
+
try {
|
|
82
|
+
const exists = fs.existsSync(this.guiPath);
|
|
83
|
+
if (!exists) {
|
|
84
|
+
return { passed: false, error: `GUI directory not found: ${this.guiPath}` };
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const stats = fs.statSync(this.guiPath);
|
|
88
|
+
if (!stats.isDirectory()) {
|
|
89
|
+
return { passed: false, error: `GUI path is not a directory: ${this.guiPath}` };
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return { passed: true, details: { path: this.guiPath } };
|
|
93
|
+
} catch (error) {
|
|
94
|
+
return { passed: false, error: error.message };
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Test if package.json exists in GUI directory
|
|
100
|
+
*/
|
|
101
|
+
async testPackageJsonExists() {
|
|
102
|
+
try {
|
|
103
|
+
const packageJsonPath = path.join(this.guiPath, 'package.json');
|
|
104
|
+
const exists = fs.existsSync(packageJsonPath);
|
|
105
|
+
if (!exists) {
|
|
106
|
+
return { passed: false, error: `package.json not found: ${packageJsonPath}` };
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
|
|
110
|
+
return {
|
|
111
|
+
passed: true,
|
|
112
|
+
details: {
|
|
113
|
+
name: packageJson.name,
|
|
114
|
+
version: packageJson.version,
|
|
115
|
+
hasMain: !!packageJson.main
|
|
116
|
+
}
|
|
117
|
+
};
|
|
118
|
+
} catch (error) {
|
|
119
|
+
return { passed: false, error: `package.json error: ${error.message}` };
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Test if main script exists
|
|
125
|
+
*/
|
|
126
|
+
async testMainScriptExists() {
|
|
127
|
+
try {
|
|
128
|
+
const mainScriptPath = path.join(this.guiPath, this.mainScript);
|
|
129
|
+
const exists = fs.existsSync(mainScriptPath);
|
|
130
|
+
if (!exists) {
|
|
131
|
+
return { passed: false, error: `Main script not found: ${mainScriptPath}` };
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const stats = fs.statSync(mainScriptPath);
|
|
135
|
+
return {
|
|
136
|
+
passed: true,
|
|
137
|
+
details: {
|
|
138
|
+
path: mainScriptPath,
|
|
139
|
+
size: stats.size
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
} catch (error) {
|
|
143
|
+
return { passed: false, error: error.message };
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Test if dependencies are available
|
|
149
|
+
*/
|
|
150
|
+
async testDependenciesAvailable() {
|
|
151
|
+
try {
|
|
152
|
+
const packageJsonPath = path.join(this.guiPath, 'package.json');
|
|
153
|
+
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
|
|
154
|
+
const nodeModulesPath = path.join(this.guiPath, 'node_modules');
|
|
155
|
+
|
|
156
|
+
const nodeModulesExists = fs.existsSync(nodeModulesPath);
|
|
157
|
+
const hasDependencies = packageJson.dependencies && Object.keys(packageJson.dependencies).length > 0;
|
|
158
|
+
|
|
159
|
+
if (!nodeModulesExists && hasDependencies) {
|
|
160
|
+
return {
|
|
161
|
+
passed: false,
|
|
162
|
+
error: 'node_modules directory not found but dependencies exist in package.json'
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// Check for key Electron dependencies
|
|
167
|
+
const keyDeps = ['electron'];
|
|
168
|
+
const missingDeps = keyDeps.filter(dep =>
|
|
169
|
+
packageJson.dependencies && packageJson.dependencies[dep] &&
|
|
170
|
+
!fs.existsSync(path.join(nodeModulesPath, dep))
|
|
171
|
+
);
|
|
172
|
+
|
|
173
|
+
if (missingDeps.length > 0) {
|
|
174
|
+
return {
|
|
175
|
+
passed: false,
|
|
176
|
+
error: `Missing key dependencies: ${missingDeps.join(', ')}`
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
return {
|
|
181
|
+
passed: true,
|
|
182
|
+
details: {
|
|
183
|
+
nodeModulesExists,
|
|
184
|
+
dependencyCount: hasDependencies ? Object.keys(packageJson.dependencies).length : 0,
|
|
185
|
+
hasElectron: packageJson.dependencies && !!packageJson.dependencies.electron
|
|
186
|
+
}
|
|
187
|
+
};
|
|
188
|
+
} catch (error) {
|
|
189
|
+
return { passed: false, error: `Dependency check error: ${error.message}` };
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Test if GUI starts without crashing
|
|
195
|
+
* Note: This is a basic startup test - we don't actually launch the full GUI
|
|
196
|
+
* as that would require a display environment
|
|
197
|
+
*/
|
|
198
|
+
async testGuiStarts() {
|
|
199
|
+
return new Promise((resolve) => {
|
|
200
|
+
const startTime = Date.now();
|
|
201
|
+
|
|
202
|
+
// Try to run electron with --version to test if it can start
|
|
203
|
+
const electronPath = path.join(this.guiPath, 'node_modules', '.bin', 'electron');
|
|
204
|
+
const packageJsonPath = path.join(this.guiPath, 'package.json');
|
|
205
|
+
|
|
206
|
+
// Check if electron binary exists
|
|
207
|
+
if (!fs.existsSync(electronPath)) {
|
|
208
|
+
// Try alternative paths
|
|
209
|
+
const electronPaths = [
|
|
210
|
+
path.join(this.guiPath, 'node_modules', 'electron', 'dist', 'electron'),
|
|
211
|
+
path.join(this.guiPath, 'node_modules', '.bin', 'electron.cmd'),
|
|
212
|
+
'npx electron'
|
|
213
|
+
];
|
|
214
|
+
|
|
215
|
+
let foundElectron = false;
|
|
216
|
+
for (const ePath of electronPaths) {
|
|
217
|
+
if (ePath.includes('npx') || fs.existsSync(ePath)) {
|
|
218
|
+
foundElectron = true;
|
|
219
|
+
break;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
if (!foundElectron) {
|
|
224
|
+
resolve({
|
|
225
|
+
passed: false,
|
|
226
|
+
error: 'Electron binary not found'
|
|
227
|
+
});
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// Test electron version
|
|
233
|
+
const child = spawn('npm', ['run', 'electron:version'], {
|
|
234
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
235
|
+
cwd: this.guiPath,
|
|
236
|
+
timeout: this.timeout
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
let stdout = '';
|
|
240
|
+
let stderr = '';
|
|
241
|
+
|
|
242
|
+
child.stdout.on('data', (data) => {
|
|
243
|
+
stdout += data.toString();
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
child.stderr.on('data', (data) => {
|
|
247
|
+
stderr += data.toString();
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
const timeoutId = setTimeout(() => {
|
|
251
|
+
child.kill('SIGTERM');
|
|
252
|
+
resolve({
|
|
253
|
+
passed: false,
|
|
254
|
+
error: `GUI startup test timeout after ${this.timeout}ms`,
|
|
255
|
+
details: { stdout, stderr }
|
|
256
|
+
});
|
|
257
|
+
}, this.timeout);
|
|
258
|
+
|
|
259
|
+
child.on('close', (code) => {
|
|
260
|
+
clearTimeout(timeoutId);
|
|
261
|
+
const duration = Date.now() - startTime;
|
|
262
|
+
|
|
263
|
+
// If electron:version script doesn't exist, try alternative test
|
|
264
|
+
if (code === 1 && stderr.includes('Missing script')) {
|
|
265
|
+
// Try to validate package.json main entry point
|
|
266
|
+
try {
|
|
267
|
+
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
|
|
268
|
+
const mainEntry = packageJson.main || this.mainScript;
|
|
269
|
+
const mainEntryPath = path.join(this.guiPath, mainEntry);
|
|
270
|
+
|
|
271
|
+
if (fs.existsSync(mainEntryPath)) {
|
|
272
|
+
resolve({
|
|
273
|
+
passed: true,
|
|
274
|
+
details: {
|
|
275
|
+
test: 'package-json-validation',
|
|
276
|
+
mainEntry,
|
|
277
|
+
mainEntryExists: true,
|
|
278
|
+
duration
|
|
279
|
+
}
|
|
280
|
+
});
|
|
281
|
+
} else {
|
|
282
|
+
resolve({
|
|
283
|
+
passed: false,
|
|
284
|
+
error: `Main entry point not found: ${mainEntryPath}`,
|
|
285
|
+
details: { mainEntry, duration }
|
|
286
|
+
});
|
|
287
|
+
}
|
|
288
|
+
} catch (error) {
|
|
289
|
+
resolve({
|
|
290
|
+
passed: false,
|
|
291
|
+
error: `Package.json validation failed: ${error.message}`,
|
|
292
|
+
details: { duration }
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
} else if (code === 0) {
|
|
296
|
+
resolve({
|
|
297
|
+
passed: true,
|
|
298
|
+
details: {
|
|
299
|
+
exitCode: code,
|
|
300
|
+
duration,
|
|
301
|
+
electronVersion: stdout.trim()
|
|
302
|
+
}
|
|
303
|
+
});
|
|
304
|
+
} else {
|
|
305
|
+
resolve({
|
|
306
|
+
passed: false,
|
|
307
|
+
error: `GUI startup test failed - exit code: ${code}`,
|
|
308
|
+
details: { exitCode: code, stdout, stderr, duration }
|
|
309
|
+
});
|
|
310
|
+
}
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
child.on('error', (error) => {
|
|
314
|
+
clearTimeout(timeoutId);
|
|
315
|
+
|
|
316
|
+
// If npm script fails, try basic validation
|
|
317
|
+
try {
|
|
318
|
+
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
|
|
319
|
+
const mainEntry = packageJson.main || this.mainScript;
|
|
320
|
+
const mainEntryPath = path.join(this.guiPath, mainEntry);
|
|
321
|
+
|
|
322
|
+
if (fs.existsSync(mainEntryPath)) {
|
|
323
|
+
resolve({
|
|
324
|
+
passed: true,
|
|
325
|
+
details: {
|
|
326
|
+
test: 'fallback-validation',
|
|
327
|
+
mainEntry,
|
|
328
|
+
mainEntryExists: true,
|
|
329
|
+
note: 'npm script failed but main entry exists'
|
|
330
|
+
}
|
|
331
|
+
});
|
|
332
|
+
} else {
|
|
333
|
+
resolve({
|
|
334
|
+
passed: false,
|
|
335
|
+
error: `Main entry point not found: ${mainEntryPath}`,
|
|
336
|
+
details: { error: error.message }
|
|
337
|
+
});
|
|
338
|
+
}
|
|
339
|
+
} catch (validationError) {
|
|
340
|
+
resolve({
|
|
341
|
+
passed: false,
|
|
342
|
+
error: `GUI startup test error: ${error.message}`,
|
|
343
|
+
details: { error: error.message }
|
|
344
|
+
});
|
|
345
|
+
}
|
|
346
|
+
});
|
|
347
|
+
});
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
module.exports = { GuiSmokeTest };
|
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Smoke Test Orchestrator
|
|
3
|
+
*
|
|
4
|
+
* Coordinates smoke testing across all interfaces (CLI, GUI, Web)
|
|
5
|
+
* and provides unified reporting and rollback triggering.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const { CliSmokeTest } = require('./smoke-test-cli');
|
|
9
|
+
const { GuiSmokeTest } = require('./smoke-test-gui');
|
|
10
|
+
const { WebSmokeTest } = require('./smoke-test-web');
|
|
11
|
+
|
|
12
|
+
class SmokeTestOrchestrator {
|
|
13
|
+
constructor(options = {}) {
|
|
14
|
+
this.options = {
|
|
15
|
+
cliPath: options.cliPath,
|
|
16
|
+
guiPath: options.guiPath,
|
|
17
|
+
webPath: options.webPath,
|
|
18
|
+
timeout: options.timeout || 120000, // 2 minutes total
|
|
19
|
+
parallel: options.parallel !== false, // Run tests in parallel by default
|
|
20
|
+
verbose: options.verbose || false,
|
|
21
|
+
rollbackTrigger: options.rollbackTrigger || null
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
this.testers = {
|
|
25
|
+
cli: new CliSmokeTest({
|
|
26
|
+
cliPath: this.options.cliPath,
|
|
27
|
+
verbose: this.options.verbose
|
|
28
|
+
}),
|
|
29
|
+
gui: new GuiSmokeTest({
|
|
30
|
+
guiPath: this.options.guiPath,
|
|
31
|
+
verbose: this.options.verbose
|
|
32
|
+
}),
|
|
33
|
+
web: new WebSmokeTest({
|
|
34
|
+
webPath: this.options.webPath,
|
|
35
|
+
verbose: this.options.verbose
|
|
36
|
+
})
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Run smoke tests for all interfaces
|
|
42
|
+
* @param {string} phase - 'pre-refactor' or 'post-refactor'
|
|
43
|
+
* @returns {Promise<Object>} Comprehensive test results
|
|
44
|
+
*/
|
|
45
|
+
async runSmokeTests(phase = 'pre-refactor') {
|
|
46
|
+
const startTime = Date.now();
|
|
47
|
+
const results = {
|
|
48
|
+
phase,
|
|
49
|
+
timestamp: new Date().toISOString(),
|
|
50
|
+
totalDuration: 0,
|
|
51
|
+
interfaces: {},
|
|
52
|
+
summary: {
|
|
53
|
+
totalTests: 0,
|
|
54
|
+
passedTests: 0,
|
|
55
|
+
failedTests: 0,
|
|
56
|
+
interfacesPassed: 0,
|
|
57
|
+
interfacesFailed: 0
|
|
58
|
+
},
|
|
59
|
+
success: false,
|
|
60
|
+
rollbackTriggered: false
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
if (this.options.verbose) {
|
|
64
|
+
console.log(`\nš„ Running ${phase} smoke tests...`);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const interfaceTests = [
|
|
68
|
+
{ name: 'cli', tester: this.testers.cli, required: true },
|
|
69
|
+
{ name: 'gui', tester: this.testers.gui, required: false }, // GUI might not be always available
|
|
70
|
+
{ name: 'web', tester: this.testers.web, required: false } // Web might not be always available
|
|
71
|
+
];
|
|
72
|
+
|
|
73
|
+
if (this.options.parallel) {
|
|
74
|
+
// Run all tests in parallel
|
|
75
|
+
const testPromises = interfaceTests.map(async (interfaceTest) => {
|
|
76
|
+
try {
|
|
77
|
+
const testResult = await interfaceTest.tester.runSmokeTests();
|
|
78
|
+
return {
|
|
79
|
+
name: interfaceTest.name,
|
|
80
|
+
required: interfaceTest.required,
|
|
81
|
+
result: testResult
|
|
82
|
+
};
|
|
83
|
+
} catch (error) {
|
|
84
|
+
return {
|
|
85
|
+
name: interfaceTest.name,
|
|
86
|
+
required: interfaceTest.required,
|
|
87
|
+
result: {
|
|
88
|
+
success: false,
|
|
89
|
+
error: error.message,
|
|
90
|
+
passed: 0,
|
|
91
|
+
failed: 0,
|
|
92
|
+
total: 0,
|
|
93
|
+
details: []
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
const interfaceResults = await Promise.all(testPromises);
|
|
100
|
+
|
|
101
|
+
// Process results
|
|
102
|
+
interfaceResults.forEach(({ name, required, result }) => {
|
|
103
|
+
results.interfaces[name] = {
|
|
104
|
+
...result,
|
|
105
|
+
required,
|
|
106
|
+
available: true
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
results.summary.totalTests += result.total;
|
|
110
|
+
results.summary.passedTests += result.passed;
|
|
111
|
+
results.summary.failedTests += result.failed;
|
|
112
|
+
|
|
113
|
+
if (result.success) {
|
|
114
|
+
results.summary.interfacesPassed++;
|
|
115
|
+
} else {
|
|
116
|
+
results.summary.interfacesFailed++;
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
} else {
|
|
120
|
+
// Run tests sequentially
|
|
121
|
+
for (const interfaceTest of interfaceTests) {
|
|
122
|
+
try {
|
|
123
|
+
const testResult = await interfaceTest.tester.runSmokeTests();
|
|
124
|
+
results.interfaces[interfaceTest.name] = {
|
|
125
|
+
...testResult,
|
|
126
|
+
required: interfaceTest.required,
|
|
127
|
+
available: true
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
results.summary.totalTests += testResult.total;
|
|
131
|
+
results.summary.passedTests += testResult.passed;
|
|
132
|
+
results.summary.failedTests += testResult.failed;
|
|
133
|
+
|
|
134
|
+
if (testResult.success) {
|
|
135
|
+
results.summary.interfacesPassed++;
|
|
136
|
+
} else {
|
|
137
|
+
results.summary.interfacesFailed++;
|
|
138
|
+
}
|
|
139
|
+
} catch (error) {
|
|
140
|
+
results.interfaces[interfaceTest.name] = {
|
|
141
|
+
success: false,
|
|
142
|
+
error: error.message,
|
|
143
|
+
passed: 0,
|
|
144
|
+
failed: 0,
|
|
145
|
+
total: 0,
|
|
146
|
+
details: [],
|
|
147
|
+
required: interfaceTest.required,
|
|
148
|
+
available: false
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
results.summary.interfacesFailed++;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
results.totalDuration = Date.now() - startTime;
|
|
157
|
+
|
|
158
|
+
// Determine overall success
|
|
159
|
+
const requiredInterfaces = interfaceTests
|
|
160
|
+
.filter(iface => iface.required)
|
|
161
|
+
.map(iface => iface.name);
|
|
162
|
+
|
|
163
|
+
const requiredInterfacesPassed = requiredInterfaces
|
|
164
|
+
.filter(name => results.interfaces[name] && results.interfaces[name].success)
|
|
165
|
+
.length;
|
|
166
|
+
|
|
167
|
+
// Success if all required interfaces pass
|
|
168
|
+
results.success = requiredInterfacesPassed === requiredInterfaces.length;
|
|
169
|
+
|
|
170
|
+
// Trigger rollback if this is post-refactor and tests failed
|
|
171
|
+
if (phase === 'post-refactor' && !results.success && this.options.rollbackTrigger) {
|
|
172
|
+
if (this.options.verbose) {
|
|
173
|
+
console.log('šØ Smoke tests failed - triggering rollback');
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
try {
|
|
177
|
+
await this.options.rollbackTrigger({
|
|
178
|
+
reason: 'Smoke tests failed',
|
|
179
|
+
phase,
|
|
180
|
+
results
|
|
181
|
+
});
|
|
182
|
+
results.rollbackTriggered = true;
|
|
183
|
+
} catch (rollbackError) {
|
|
184
|
+
console.error('Rollback trigger failed:', rollbackError.message);
|
|
185
|
+
results.rollbackError = rollbackError.message;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// Print summary
|
|
190
|
+
this.printSummary(results);
|
|
191
|
+
|
|
192
|
+
return results;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Run pre-refactor smoke tests
|
|
197
|
+
*/
|
|
198
|
+
async runPreRefactorTests() {
|
|
199
|
+
return this.runSmokeTests('pre-refactor');
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* Run post-refactor smoke tests
|
|
204
|
+
*/
|
|
205
|
+
async runPostRefactorTests() {
|
|
206
|
+
return this.runSmokeTests('post-refactor');
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Print test summary to console
|
|
211
|
+
*/
|
|
212
|
+
printSummary(results) {
|
|
213
|
+
if (this.options.verbose) {
|
|
214
|
+
console.log(`\nš Smoke Test Results - ${results.phase.toUpperCase()}`);
|
|
215
|
+
console.log(`ā±ļø Duration: ${results.totalDuration}ms`);
|
|
216
|
+
console.log(`š Summary: ${results.summary.passedTests}/${results.summary.totalTests} tests passed`);
|
|
217
|
+
console.log(`š„ļø Interfaces: ${results.summary.interfacesPassed}/${results.summary.interfacesPassed + results.summary.interfacesFailed} passed`);
|
|
218
|
+
|
|
219
|
+
Object.entries(results.interfaces).forEach(([name, result]) => {
|
|
220
|
+
const status = result.success ? 'ā
' : 'ā';
|
|
221
|
+
const availability = result.available ? '' : ' (not available)';
|
|
222
|
+
const requirement = result.required ? ' (required)' : ' (optional)';
|
|
223
|
+
console.log(` ${status} ${name.toUpperCase()}${availability}${requirement}: ${result.passed}/${result.total} tests passed`);
|
|
224
|
+
|
|
225
|
+
if (!result.success && result.error) {
|
|
226
|
+
console.log(` Error: ${result.error}`);
|
|
227
|
+
}
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
if (results.success) {
|
|
231
|
+
console.log('š All required interfaces passed smoke tests!');
|
|
232
|
+
} else {
|
|
233
|
+
console.log('š„ Some required interfaces failed smoke tests!');
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
if (results.rollbackTriggered) {
|
|
237
|
+
console.log('š Rollback was triggered due to failures');
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Generate detailed report
|
|
244
|
+
*/
|
|
245
|
+
generateReport(results) {
|
|
246
|
+
const report = {
|
|
247
|
+
metadata: {
|
|
248
|
+
phase: results.phase,
|
|
249
|
+
timestamp: results.timestamp,
|
|
250
|
+
duration: results.totalDuration,
|
|
251
|
+
orchestratorVersion: '1.0.0'
|
|
252
|
+
},
|
|
253
|
+
summary: results.summary,
|
|
254
|
+
interfaces: {},
|
|
255
|
+
recommendations: []
|
|
256
|
+
};
|
|
257
|
+
|
|
258
|
+
// Process each interface result
|
|
259
|
+
Object.entries(results.interfaces).forEach(([name, result]) => {
|
|
260
|
+
report.interfaces[name] = {
|
|
261
|
+
available: result.available,
|
|
262
|
+
required: result.required,
|
|
263
|
+
success: result.success,
|
|
264
|
+
testSummary: {
|
|
265
|
+
total: result.total,
|
|
266
|
+
passed: result.passed,
|
|
267
|
+
failed: result.failed
|
|
268
|
+
},
|
|
269
|
+
error: result.error || null,
|
|
270
|
+
testDetails: result.details || []
|
|
271
|
+
};
|
|
272
|
+
|
|
273
|
+
// Generate recommendations
|
|
274
|
+
if (!result.success) {
|
|
275
|
+
if (result.error && result.error.includes('not found')) {
|
|
276
|
+
report.recommendations.push({
|
|
277
|
+
interface: name,
|
|
278
|
+
priority: 'high',
|
|
279
|
+
issue: 'Missing files or dependencies',
|
|
280
|
+
suggestion: `Ensure ${name} interface is properly installed and dependencies are available`
|
|
281
|
+
});
|
|
282
|
+
} else if (result.error && result.error.includes('timeout')) {
|
|
283
|
+
report.recommendations.push({
|
|
284
|
+
interface: name,
|
|
285
|
+
priority: 'medium',
|
|
286
|
+
issue: 'Startup timeout',
|
|
287
|
+
suggestion: `Check ${name} configuration and increase timeout if necessary`
|
|
288
|
+
});
|
|
289
|
+
} else {
|
|
290
|
+
report.recommendations.push({
|
|
291
|
+
interface: name,
|
|
292
|
+
priority: 'high',
|
|
293
|
+
issue: 'Unknown error',
|
|
294
|
+
suggestion: `Investigate ${name} interface logs and configuration`
|
|
295
|
+
});
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
});
|
|
299
|
+
|
|
300
|
+
return report;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
/**
|
|
304
|
+
* Save report to file
|
|
305
|
+
*/
|
|
306
|
+
async saveReport(results, filePath) {
|
|
307
|
+
const fs = require('fs').promises;
|
|
308
|
+
const report = this.generateReport(results);
|
|
309
|
+
|
|
310
|
+
try {
|
|
311
|
+
await fs.writeFile(filePath, JSON.stringify(report, null, 2));
|
|
312
|
+
if (this.options.verbose) {
|
|
313
|
+
console.log(`š Report saved to: ${filePath}`);
|
|
314
|
+
}
|
|
315
|
+
} catch (error) {
|
|
316
|
+
console.error(`Failed to save report: ${error.message}`);
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
module.exports = { SmokeTestOrchestrator };
|