vibecodingmachine-core 2026.2.20-438 → 2026.2.26-1739
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,614 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Refactoring Rollback
|
|
3
|
+
*
|
|
4
|
+
* Provides rollback capabilities for failed refactoring operations.
|
|
5
|
+
* Ensures safe restoration of original state with comprehensive tracking.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const fs = require('fs');
|
|
9
|
+
const path = require('path');
|
|
10
|
+
const { RollbackManager } = require('../utils/rollback-manager');
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Rollback status
|
|
14
|
+
*/
|
|
15
|
+
const ROLLBACK_STATUS = {
|
|
16
|
+
PENDING: 'pending',
|
|
17
|
+
RUNNING: 'running',
|
|
18
|
+
COMPLETED: 'completed',
|
|
19
|
+
FAILED: 'failed',
|
|
20
|
+
PARTIAL: 'partial'
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Rollback operation class
|
|
25
|
+
*/
|
|
26
|
+
class RollbackOperation {
|
|
27
|
+
constructor(operationId, type, targetPath) {
|
|
28
|
+
this.id = this.generateId();
|
|
29
|
+
this.operationId = operationId;
|
|
30
|
+
this.type = type;
|
|
31
|
+
this.targetPath = targetPath;
|
|
32
|
+
this.status = ROLLBACK_STATUS.PENDING;
|
|
33
|
+
this.startTime = null;
|
|
34
|
+
this.endTime = null;
|
|
35
|
+
this.duration = 0;
|
|
36
|
+
this.success = false;
|
|
37
|
+
this.errors = [];
|
|
38
|
+
this.warnings = [];
|
|
39
|
+
this.metadata = {
|
|
40
|
+
createdAt: new Date().toISOString(),
|
|
41
|
+
backupPath: null,
|
|
42
|
+
originalSize: 0,
|
|
43
|
+
restoredSize: 0
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
generateId() {
|
|
48
|
+
return `rollback_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
setStatus(status) {
|
|
52
|
+
this.status = status;
|
|
53
|
+
if (status === ROLLBACK_STATUS.RUNNING && !this.startTime) {
|
|
54
|
+
this.startTime = new Date().toISOString();
|
|
55
|
+
}
|
|
56
|
+
if ([ROLLBACK_STATUS.COMPLETED, ROLLBACK_STATUS.FAILED, ROLLBACK_STATUS.PARTIAL].includes(status)) {
|
|
57
|
+
this.endTime = new Date().toISOString();
|
|
58
|
+
this.duration = this.endTime && this.startTime ?
|
|
59
|
+
(new Date(this.endTime) - new Date(this.startTime)) / 1000 : 0;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
setSuccess(success) {
|
|
64
|
+
this.success = success;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
addError(error) {
|
|
68
|
+
this.errors.push({
|
|
69
|
+
message: error.message,
|
|
70
|
+
timestamp: new Date().toISOString(),
|
|
71
|
+
stack: error.stack
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
addWarning(warning) {
|
|
76
|
+
this.warnings.push({
|
|
77
|
+
message: warning,
|
|
78
|
+
timestamp: new Date().toISOString()
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
setBackupPath(backupPath) {
|
|
83
|
+
this.metadata.backupPath = backupPath;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
setOriginalSize(size) {
|
|
87
|
+
this.metadata.originalSize = size;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
setRestoredSize(size) {
|
|
91
|
+
this.metadata.restoredSize = size;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
getSummary() {
|
|
95
|
+
return {
|
|
96
|
+
id: this.id,
|
|
97
|
+
operationId: this.operationId,
|
|
98
|
+
type: this.type,
|
|
99
|
+
targetPath: this.targetPath,
|
|
100
|
+
status: this.status,
|
|
101
|
+
success: this.success,
|
|
102
|
+
duration: this.duration,
|
|
103
|
+
errorCount: this.errors.length,
|
|
104
|
+
warningCount: this.warnings.length,
|
|
105
|
+
backupPath: this.metadata.backupPath
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Rollback result class
|
|
112
|
+
*/
|
|
113
|
+
class RollbackResult {
|
|
114
|
+
constructor(rollbackId) {
|
|
115
|
+
this.rollbackId = rollbackId;
|
|
116
|
+
this.operations = [];
|
|
117
|
+
this.status = ROLLBACK_STATUS.PENDING;
|
|
118
|
+
this.success = false;
|
|
119
|
+
this.startTime = null;
|
|
120
|
+
this.endTime = null;
|
|
121
|
+
this.duration = 0;
|
|
122
|
+
this.errors = [];
|
|
123
|
+
this.warnings = [];
|
|
124
|
+
this.metadata = {
|
|
125
|
+
createdAt: new Date().toISOString(),
|
|
126
|
+
triggerReason: '',
|
|
127
|
+
affectedFiles: 0,
|
|
128
|
+
totalFilesRestored: 0
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
addOperation(operation) {
|
|
133
|
+
this.operations.push(operation);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
setStatus(status) {
|
|
137
|
+
this.status = status;
|
|
138
|
+
if (status === ROLLBACK_STATUS.RUNNING && !this.startTime) {
|
|
139
|
+
this.startTime = new Date().toISOString();
|
|
140
|
+
}
|
|
141
|
+
if ([ROLLBACK_STATUS.COMPLETED, ROLLBACK_STATUS.FAILED, ROLLBACK_STATUS.PARTIAL].includes(status)) {
|
|
142
|
+
this.endTime = new Date().toISOString();
|
|
143
|
+
this.duration = this.endTime && this.startTime ?
|
|
144
|
+
(new Date(this.endTime) - new Date(this.startTime)) / 1000 : 0;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
setSuccess(success) {
|
|
149
|
+
this.success = success;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
setTriggerReason(reason) {
|
|
153
|
+
this.metadata.triggerReason = reason;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
addError(error) {
|
|
157
|
+
this.errors.push({
|
|
158
|
+
message: error.message,
|
|
159
|
+
timestamp: new Date().toISOString(),
|
|
160
|
+
stack: error.stack
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
addWarning(warning) {
|
|
165
|
+
this.warnings.push({
|
|
166
|
+
message: warning,
|
|
167
|
+
timestamp: new Date().toISOString()
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
calculateSummary() {
|
|
172
|
+
const successfulOps = this.operations.filter(op => op.success).length;
|
|
173
|
+
const failedOps = this.operations.filter(op => !op.success).length;
|
|
174
|
+
|
|
175
|
+
if (failedOps === 0) {
|
|
176
|
+
this.setStatus(ROLLBACK_STATUS.COMPLETED);
|
|
177
|
+
this.setSuccess(true);
|
|
178
|
+
} else if (successfulOps > 0) {
|
|
179
|
+
this.setStatus(ROLLBACK_STATUS.PARTIAL);
|
|
180
|
+
this.setSuccess(false);
|
|
181
|
+
} else {
|
|
182
|
+
this.setStatus(ROLLBACK_STATUS.FAILED);
|
|
183
|
+
this.setSuccess(false);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
this.metadata.affectedFiles = this.operations.length;
|
|
187
|
+
this.metadata.totalFilesRestored = successfulOps;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
getSummary() {
|
|
191
|
+
this.calculateSummary();
|
|
192
|
+
|
|
193
|
+
return {
|
|
194
|
+
rollbackId: this.rollbackId,
|
|
195
|
+
status: this.status,
|
|
196
|
+
success: this.success,
|
|
197
|
+
duration: this.duration,
|
|
198
|
+
triggerReason: this.metadata.triggerReason,
|
|
199
|
+
affectedFiles: this.metadata.affectedFiles,
|
|
200
|
+
totalFilesRestored: this.metadata.totalFilesRestored,
|
|
201
|
+
operations: this.operations.map(op => op.getSummary()),
|
|
202
|
+
errorCount: this.errors.length,
|
|
203
|
+
warningCount: this.warnings.length
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Refactoring rollback manager class
|
|
210
|
+
*/
|
|
211
|
+
class RefactoringRollback {
|
|
212
|
+
constructor(options = {}) {
|
|
213
|
+
this.options = {
|
|
214
|
+
createBackups: true,
|
|
215
|
+
validateAfterRollback: true,
|
|
216
|
+
preserveRollbackLogs: true,
|
|
217
|
+
maxRollbackAttempts: 3,
|
|
218
|
+
...options
|
|
219
|
+
};
|
|
220
|
+
|
|
221
|
+
this.rollbackManager = new RollbackManager();
|
|
222
|
+
this.rollbackHistory = new Map();
|
|
223
|
+
this.currentRollback = null;
|
|
224
|
+
this.isRollingBack = false;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Create rollback point for a refactoring operation
|
|
229
|
+
*/
|
|
230
|
+
async createRollbackPoint(operationId, operation) {
|
|
231
|
+
console.log(`Creating rollback point for operation: ${operationId}`);
|
|
232
|
+
|
|
233
|
+
try {
|
|
234
|
+
const rollbackOp = new RollbackOperation(operationId, 'create_backup', operation.targetPath);
|
|
235
|
+
|
|
236
|
+
// Create backup for each affected file
|
|
237
|
+
for (const affectedFile of operation.affectedFiles || [operation.targetPath]) {
|
|
238
|
+
if (fs.existsSync(affectedFile)) {
|
|
239
|
+
const backupPath = this.rollbackManager.backupFile(affectedFile);
|
|
240
|
+
rollbackOp.setBackupPath(backupPath);
|
|
241
|
+
rollbackOp.setOriginalSize(fs.statSync(affectedFile).size);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
rollbackOp.setStatus(ROLLBACK_STATUS.COMPLETED);
|
|
246
|
+
rollbackOp.setSuccess(true);
|
|
247
|
+
|
|
248
|
+
// Store rollback operation
|
|
249
|
+
if (!this.rollbackHistory.has(operationId)) {
|
|
250
|
+
this.rollbackHistory.set(operationId, []);
|
|
251
|
+
}
|
|
252
|
+
this.rollbackHistory.get(operationId).push(rollbackOp);
|
|
253
|
+
|
|
254
|
+
console.log(`Rollback point created for ${operationId}`);
|
|
255
|
+
|
|
256
|
+
return rollbackOp;
|
|
257
|
+
|
|
258
|
+
} catch (error) {
|
|
259
|
+
console.error(`Failed to create rollback point for ${operationId}:`, error.message);
|
|
260
|
+
throw error;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* Execute rollback for a failed operation
|
|
266
|
+
*/
|
|
267
|
+
async executeRollback(operationId, reason = 'Operation failed') {
|
|
268
|
+
if (this.isRollingBack) {
|
|
269
|
+
throw new Error('Rollback already in progress');
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
this.isRollingBack = true;
|
|
273
|
+
const rollbackId = this.generateRollbackId();
|
|
274
|
+
const result = new RollbackResult(rollbackId);
|
|
275
|
+
result.setTriggerReason(reason);
|
|
276
|
+
|
|
277
|
+
try {
|
|
278
|
+
console.log(`Executing rollback for operation: ${operationId}`);
|
|
279
|
+
result.setStatus(ROLLBACK_STATUS.RUNNING);
|
|
280
|
+
|
|
281
|
+
// Get rollback operations for the operation
|
|
282
|
+
const rollbackOps = this.rollbackHistory.get(operationId) || [];
|
|
283
|
+
|
|
284
|
+
if (rollbackOps.length === 0) {
|
|
285
|
+
throw new Error(`No rollback point found for operation: ${operationId}`);
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
// Execute rollback operations in reverse order
|
|
289
|
+
const reversedOps = rollbackOps.reverse();
|
|
290
|
+
|
|
291
|
+
for (const rollbackOp of reversedOps) {
|
|
292
|
+
try {
|
|
293
|
+
await this.executeRollbackOperation(rollbackOp);
|
|
294
|
+
result.addOperation(rollbackOp);
|
|
295
|
+
} catch (error) {
|
|
296
|
+
rollbackOp.addError(error);
|
|
297
|
+
rollbackOp.setStatus(ROLLBACK_STATUS.FAILED);
|
|
298
|
+
rollbackOp.setSuccess(false);
|
|
299
|
+
result.addOperation(rollbackOp);
|
|
300
|
+
|
|
301
|
+
// Continue with other operations even if one fails
|
|
302
|
+
console.warn(`Rollback operation failed: ${rollbackOp.id}`, error.message);
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
// Validate rollback if enabled
|
|
307
|
+
if (this.options.validateAfterRollback) {
|
|
308
|
+
await this.validateRollback(result);
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
result.calculateSummary();
|
|
312
|
+
|
|
313
|
+
console.log(`Rollback completed: ${result.success ? 'SUCCESS' : 'PARTIAL/FAILED'}`);
|
|
314
|
+
|
|
315
|
+
} catch (error) {
|
|
316
|
+
result.addError(error);
|
|
317
|
+
result.setStatus(ROLLBACK_STATUS.FAILED);
|
|
318
|
+
result.setSuccess(false);
|
|
319
|
+
console.error(`Rollback execution failed:`, error.message);
|
|
320
|
+
} finally {
|
|
321
|
+
this.isRollingBack = false;
|
|
322
|
+
this.currentRollback = result;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
return result;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
/**
|
|
329
|
+
* Execute individual rollback operation
|
|
330
|
+
*/
|
|
331
|
+
async executeRollbackOperation(rollbackOp) {
|
|
332
|
+
console.log(`Executing rollback operation: ${rollbackOp.id}`);
|
|
333
|
+
rollbackOp.setStatus(ROLLBACK_STATUS.RUNNING);
|
|
334
|
+
|
|
335
|
+
try {
|
|
336
|
+
if (!rollbackOp.metadata.backupPath || !fs.existsSync(rollbackOp.metadata.backupPath)) {
|
|
337
|
+
throw new Error(`Backup file not found: ${rollbackOp.metadata.backupPath}`);
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
// Restore file from backup
|
|
341
|
+
const targetDir = path.dirname(rollbackOp.targetPath);
|
|
342
|
+
if (!fs.existsSync(targetDir)) {
|
|
343
|
+
fs.mkdirSync(targetDir, { recursive: true });
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
fs.copyFileSync(rollbackOp.metadata.backupPath, rollbackOp.targetPath);
|
|
347
|
+
|
|
348
|
+
// Verify restoration
|
|
349
|
+
if (fs.existsSync(rollbackOp.targetPath)) {
|
|
350
|
+
const restoredSize = fs.statSync(rollbackOp.targetPath).size;
|
|
351
|
+
rollbackOp.setRestoredSize(restoredSize);
|
|
352
|
+
|
|
353
|
+
// Check if size matches (basic integrity check)
|
|
354
|
+
if (Math.abs(restoredSize - rollbackOp.metadata.originalSize) > 100) {
|
|
355
|
+
rollbackOp.addWarning('File size difference detected after restoration');
|
|
356
|
+
}
|
|
357
|
+
} else {
|
|
358
|
+
throw new Error('Failed to restore file');
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
rollbackOp.setStatus(ROLLBACK_STATUS.COMPLETED);
|
|
362
|
+
rollbackOp.setSuccess(true);
|
|
363
|
+
|
|
364
|
+
console.log(`Rollback operation completed: ${rollbackOp.id}`);
|
|
365
|
+
|
|
366
|
+
} catch (error) {
|
|
367
|
+
rollbackOp.addError(error);
|
|
368
|
+
rollbackOp.setStatus(ROLLBACK_STATUS.FAILED);
|
|
369
|
+
rollbackOp.setSuccess(false);
|
|
370
|
+
throw error;
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
/**
|
|
375
|
+
* Validate rollback results
|
|
376
|
+
*/
|
|
377
|
+
async validateRollback(result) {
|
|
378
|
+
console.log('Validating rollback results...');
|
|
379
|
+
|
|
380
|
+
for (const operation of result.operations) {
|
|
381
|
+
if (operation.success) {
|
|
382
|
+
try {
|
|
383
|
+
// Basic file existence check
|
|
384
|
+
if (!fs.existsSync(operation.targetPath)) {
|
|
385
|
+
operation.addWarning('Target file does not exist after rollback');
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
// Basic syntax check for JavaScript files
|
|
389
|
+
if (operation.targetPath.endsWith('.js') && fs.existsSync(operation.targetPath)) {
|
|
390
|
+
const content = fs.readFileSync(operation.targetPath, 'utf8');
|
|
391
|
+
this.validateJavaScriptSyntax(content);
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
} catch (error) {
|
|
395
|
+
operation.addError(error);
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
/**
|
|
402
|
+
* Validate JavaScript syntax
|
|
403
|
+
*/
|
|
404
|
+
validateJavaScriptSyntax(content) {
|
|
405
|
+
try {
|
|
406
|
+
const vm = require('vm');
|
|
407
|
+
new vm.Script(content, { filename: 'validation' });
|
|
408
|
+
} catch (error) {
|
|
409
|
+
throw new Error(`JavaScript syntax validation failed: ${error.message}`);
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
/**
|
|
414
|
+
* Cancel current rollback
|
|
415
|
+
*/
|
|
416
|
+
async cancelRollback() {
|
|
417
|
+
if (!this.isRollingBack || !this.currentRollback) {
|
|
418
|
+
return false;
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
this.currentRollback.setStatus(ROLLBACK_STATUS.FAILED);
|
|
422
|
+
this.currentRollback.addError(new Error('Rollback cancelled by user'));
|
|
423
|
+
this.isRollingBack = false;
|
|
424
|
+
|
|
425
|
+
return true;
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
/**
|
|
429
|
+
* Get rollback status
|
|
430
|
+
*/
|
|
431
|
+
getRollbackStatus() {
|
|
432
|
+
return {
|
|
433
|
+
isRollingBack: this.isRollingBack,
|
|
434
|
+
currentRollback: this.currentRollback ? this.currentRollback.getSummary() : null,
|
|
435
|
+
rollbackHistory: Array.from(this.rollbackHistory.entries()).map(([opId, ops]) => ({
|
|
436
|
+
operationId: opId,
|
|
437
|
+
rollbackOperations: ops.length,
|
|
438
|
+
lastRollback: ops[ops.length - 1]?.getSummary()
|
|
439
|
+
}))
|
|
440
|
+
};
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
/**
|
|
444
|
+
* Clean up old rollback points
|
|
445
|
+
*/
|
|
446
|
+
async cleanup(maxAge = 7 * 24 * 60 * 60 * 1000) { // 7 days default
|
|
447
|
+
console.log('Cleaning up old rollback points...');
|
|
448
|
+
|
|
449
|
+
let cleaned = 0;
|
|
450
|
+
const now = Date.now();
|
|
451
|
+
|
|
452
|
+
for (const [operationId, rollbackOps] of this.rollbackHistory.entries()) {
|
|
453
|
+
const recentOps = rollbackOps.filter(op => {
|
|
454
|
+
const createdAt = new Date(op.metadata.createdAt).getTime();
|
|
455
|
+
return (now - createdAt) < maxAge;
|
|
456
|
+
});
|
|
457
|
+
|
|
458
|
+
if (recentOps.length < rollbackOps.length) {
|
|
459
|
+
this.rollbackHistory.set(operationId, recentOps);
|
|
460
|
+
cleaned += rollbackOps.length - recentOps.length;
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
// Clean up rollback manager backups
|
|
465
|
+
const backupCleaned = this.rollbackManager.cleanup(maxAge);
|
|
466
|
+
|
|
467
|
+
console.log(`Cleanup completed: ${cleaned} rollback operations, ${backupCleaned} backup files`);
|
|
468
|
+
|
|
469
|
+
return { rollbackOperations: cleaned, backupFiles: backupCleaned };
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
/**
|
|
473
|
+
* Get rollback statistics
|
|
474
|
+
*/
|
|
475
|
+
getStatistics() {
|
|
476
|
+
const stats = {
|
|
477
|
+
totalRollbackPoints: 0,
|
|
478
|
+
totalRollbacks: 0,
|
|
479
|
+
successfulRollbacks: 0,
|
|
480
|
+
failedRollbacks: 0,
|
|
481
|
+
partialRollbacks: 0,
|
|
482
|
+
averageRollbackTime: 0,
|
|
483
|
+
commonFailureReasons: {},
|
|
484
|
+
oldestRollback: null,
|
|
485
|
+
newestRollback: null
|
|
486
|
+
};
|
|
487
|
+
|
|
488
|
+
let totalTime = 0;
|
|
489
|
+
let oldestTime = null;
|
|
490
|
+
let newestTime = null;
|
|
491
|
+
const failureReasons = {};
|
|
492
|
+
|
|
493
|
+
for (const rollbackOps of this.rollbackHistory.values()) {
|
|
494
|
+
stats.totalRollbackPoints += rollbackOps.length;
|
|
495
|
+
|
|
496
|
+
for (const op of rollbackOps) {
|
|
497
|
+
if (op.endTime) {
|
|
498
|
+
const opTime = new Date(op.endTime);
|
|
499
|
+
if (!oldestTime || opTime < oldestTime) oldestTime = opTime;
|
|
500
|
+
if (!newestTime || opTime > newestTime) newestTime = opTime;
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
stats.oldestRollback = oldestTime ? oldestTime.toISOString() : null;
|
|
506
|
+
stats.newestRollback = newestTime ? newestTime.toISOString() : null;
|
|
507
|
+
|
|
508
|
+
return stats;
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
/**
|
|
512
|
+
* Export rollback data
|
|
513
|
+
*/
|
|
514
|
+
exportRollbackData(format = 'json') {
|
|
515
|
+
const exportData = {
|
|
516
|
+
metadata: {
|
|
517
|
+
exportedAt: new Date().toISOString(),
|
|
518
|
+
version: '1.0.0',
|
|
519
|
+
options: this.options
|
|
520
|
+
},
|
|
521
|
+
rollbackHistory: Array.from(this.rollbackHistory.entries()).map(([opId, ops]) => ({
|
|
522
|
+
operationId: opId,
|
|
523
|
+
operations: ops.map(op => op.getSummary())
|
|
524
|
+
})),
|
|
525
|
+
currentRollback: this.currentRollback ? this.currentRollback.getSummary() : null,
|
|
526
|
+
statistics: this.getStatistics()
|
|
527
|
+
};
|
|
528
|
+
|
|
529
|
+
if (format === 'json') {
|
|
530
|
+
return JSON.stringify(exportData, null, 2);
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
return exportData;
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
/**
|
|
537
|
+
* Generate rollback ID
|
|
538
|
+
*/
|
|
539
|
+
generateRollbackId() {
|
|
540
|
+
return `rollback_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
/**
|
|
544
|
+
* Check if rollback is available for an operation
|
|
545
|
+
*/
|
|
546
|
+
hasRollbackPoint(operationId) {
|
|
547
|
+
const rollbackOps = this.rollbackHistory.get(operationId);
|
|
548
|
+
return rollbackOps && rollbackOps.length > 0;
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
/**
|
|
552
|
+
* Get rollback operations for an operation
|
|
553
|
+
*/
|
|
554
|
+
getRollbackOperations(operationId) {
|
|
555
|
+
return this.rollbackHistory.get(operationId) || [];
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
/**
|
|
559
|
+
* Remove rollback point for an operation
|
|
560
|
+
*/
|
|
561
|
+
removeRollbackPoint(operationId) {
|
|
562
|
+
const rollbackOps = this.rollbackHistory.get(operationId);
|
|
563
|
+
if (rollbackOps) {
|
|
564
|
+
// Clean up backup files
|
|
565
|
+
for (const op of rollbackOps) {
|
|
566
|
+
if (op.metadata.backupPath && fs.existsSync(op.metadata.backupPath)) {
|
|
567
|
+
try {
|
|
568
|
+
fs.unlinkSync(op.metadata.backupPath);
|
|
569
|
+
} catch (error) {
|
|
570
|
+
console.warn(`Failed to cleanup backup file: ${op.metadata.backupPath}`, error.message);
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
this.rollbackHistory.delete(operationId);
|
|
576
|
+
return true;
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
return false;
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
/**
|
|
583
|
+
* Reset all rollback data
|
|
584
|
+
*/
|
|
585
|
+
reset() {
|
|
586
|
+
console.log('Resetting all rollback data...');
|
|
587
|
+
|
|
588
|
+
// Clean up all backup files
|
|
589
|
+
for (const rollbackOps of this.rollbackHistory.values()) {
|
|
590
|
+
for (const op of rollbackOps) {
|
|
591
|
+
if (op.metadata.backupPath && fs.existsSync(op.metadata.backupPath)) {
|
|
592
|
+
try {
|
|
593
|
+
fs.unlinkSync(op.metadata.backupPath);
|
|
594
|
+
} catch (error) {
|
|
595
|
+
console.warn(`Failed to cleanup backup file: ${op.metadata.backupPath}`, error.message);
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
this.rollbackHistory.clear();
|
|
602
|
+
this.currentRollback = null;
|
|
603
|
+
this.isRollingBack = false;
|
|
604
|
+
|
|
605
|
+
console.log('Rollback data reset completed');
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
module.exports = {
|
|
610
|
+
RefactoringRollback,
|
|
611
|
+
RollbackOperation,
|
|
612
|
+
RollbackResult,
|
|
613
|
+
ROLLBACK_STATUS
|
|
614
|
+
};
|