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,454 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* File-based Storage Manager
|
|
3
|
+
*
|
|
4
|
+
* Manages file-based storage for agent data and logs.
|
|
5
|
+
* Follows constitutional requirements: <555 lines, test-first approach.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const fs = require('fs').promises;
|
|
9
|
+
const path = require('path');
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* File-based storage manager class
|
|
13
|
+
*/
|
|
14
|
+
class FileManager {
|
|
15
|
+
/**
|
|
16
|
+
* Create file manager instance
|
|
17
|
+
* @param {Object} options - Storage options
|
|
18
|
+
* @param {string} options.baseDir - Base directory for storage
|
|
19
|
+
* @param {string} options.configDir - Configuration directory
|
|
20
|
+
* @param {string} options.logsDir - Logs directory
|
|
21
|
+
*/
|
|
22
|
+
constructor(options = {}) {
|
|
23
|
+
this.baseDir = options.baseDir || path.join(process.cwd(), '.vibecodingmachine');
|
|
24
|
+
this.configDir = options.configDir || path.join(this.baseDir, 'config');
|
|
25
|
+
this.logsDir = options.logsDir || path.join(this.baseDir, 'logs');
|
|
26
|
+
this.statusFile = path.join(this.configDir, 'agent-status.json');
|
|
27
|
+
this.initialized = false;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Initialize storage directories
|
|
32
|
+
* @returns {Promise<void>}
|
|
33
|
+
*/
|
|
34
|
+
async initialize() {
|
|
35
|
+
try {
|
|
36
|
+
await this.ensureDirectory(this.baseDir);
|
|
37
|
+
await this.ensureDirectory(this.configDir);
|
|
38
|
+
await this.ensureDirectory(this.logsDir);
|
|
39
|
+
this.initialized = true;
|
|
40
|
+
} catch (error) {
|
|
41
|
+
throw new Error(`Failed to initialize storage: ${error.message}`);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Ensure directory exists
|
|
47
|
+
* @param {string} dirPath - Directory path
|
|
48
|
+
* @returns {Promise<void>}
|
|
49
|
+
*/
|
|
50
|
+
async ensureDirectory(dirPath) {
|
|
51
|
+
try {
|
|
52
|
+
await fs.access(dirPath);
|
|
53
|
+
} catch {
|
|
54
|
+
await fs.mkdir(dirPath, { recursive: true });
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Save agent status data
|
|
60
|
+
* @param {Object} statusData - Agent status data
|
|
61
|
+
* @returns {Promise<void>}
|
|
62
|
+
*/
|
|
63
|
+
async saveAgentStatus(statusData) {
|
|
64
|
+
if (!this.initialized) {
|
|
65
|
+
await this.initialize();
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
try {
|
|
69
|
+
await fs.writeFile(this.statusFile, JSON.stringify(statusData, null, 2), 'utf8');
|
|
70
|
+
} catch (error) {
|
|
71
|
+
throw new Error(`Failed to save agent status: ${error.message}`);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Load agent status data
|
|
77
|
+
* @returns {Promise<Object>} - Agent status data
|
|
78
|
+
*/
|
|
79
|
+
async loadAgentStatus() {
|
|
80
|
+
if (!this.initialized) {
|
|
81
|
+
await this.initialize();
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
try {
|
|
85
|
+
const data = await fs.readFile(this.statusFile, 'utf8');
|
|
86
|
+
return JSON.parse(data);
|
|
87
|
+
} catch (error) {
|
|
88
|
+
if (error.code === 'ENOENT') {
|
|
89
|
+
// Return empty status if file doesn't exist
|
|
90
|
+
return {
|
|
91
|
+
lastUpdated: new Date().toISOString(),
|
|
92
|
+
agents: {}
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
throw new Error(`Failed to load agent status: ${error.message}`);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Update individual agent status
|
|
101
|
+
* @param {string} agentId - Agent identifier
|
|
102
|
+
* @param {Object} agentStatus - Agent status data
|
|
103
|
+
* @returns {Promise<void>}
|
|
104
|
+
*/
|
|
105
|
+
async updateAgentStatus(agentId, agentStatus) {
|
|
106
|
+
const statusData = await this.loadAgentStatus();
|
|
107
|
+
statusData.agents[agentId] = {
|
|
108
|
+
...agentStatus,
|
|
109
|
+
lastUpdated: new Date().toISOString()
|
|
110
|
+
};
|
|
111
|
+
statusData.lastUpdated = new Date().toISOString();
|
|
112
|
+
await this.saveAgentStatus(statusData);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Get agent status
|
|
117
|
+
* @param {string} agentId - Agent identifier
|
|
118
|
+
* @returns {Promise<Object|null>} - Agent status data
|
|
119
|
+
*/
|
|
120
|
+
async getAgentStatus(agentId) {
|
|
121
|
+
const statusData = await this.loadAgentStatus();
|
|
122
|
+
return statusData.agents[agentId] || null;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Delete agent status
|
|
127
|
+
* @param {string} agentId - Agent identifier
|
|
128
|
+
* @returns {Promise<boolean>} - True if status was deleted
|
|
129
|
+
*/
|
|
130
|
+
async deleteAgentStatus(agentId) {
|
|
131
|
+
const statusData = await this.loadAgentStatus();
|
|
132
|
+
|
|
133
|
+
if (statusData.agents[agentId]) {
|
|
134
|
+
delete statusData.agents[agentId];
|
|
135
|
+
statusData.lastUpdated = new Date().toISOString();
|
|
136
|
+
await this.saveAgentStatus(statusData);
|
|
137
|
+
return true;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
return false;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Write log entry to log file
|
|
145
|
+
* @param {string} logType - Type of log (installation, verification, error)
|
|
146
|
+
* @param {Object} logEntry - Log entry data
|
|
147
|
+
* @returns {Promise<void>}
|
|
148
|
+
*/
|
|
149
|
+
async writeLog(logType, logEntry) {
|
|
150
|
+
if (!this.initialized) {
|
|
151
|
+
await this.initialize();
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const logFile = path.join(this.logsDir, `${logType}.log`);
|
|
155
|
+
const logLine = JSON.stringify({
|
|
156
|
+
...logEntry,
|
|
157
|
+
timestamp: logEntry.timestamp || new Date().toISOString()
|
|
158
|
+
}) + '\n';
|
|
159
|
+
|
|
160
|
+
try {
|
|
161
|
+
await fs.appendFile(logFile, logLine, 'utf8');
|
|
162
|
+
} catch (error) {
|
|
163
|
+
throw new Error(`Failed to write log entry: ${error.message}`);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Read log entries
|
|
169
|
+
* @param {string} logType - Type of log
|
|
170
|
+
* @param {Object} options - Read options
|
|
171
|
+
* @param {number} options.limit - Maximum number of entries to read
|
|
172
|
+
* @param {number} options.offset - Number of entries to skip
|
|
173
|
+
* @param {Date} options.since - Only entries since this date
|
|
174
|
+
* @returns {Promise<Array>} - Array of log entries
|
|
175
|
+
*/
|
|
176
|
+
async readLogs(logType, options = {}) {
|
|
177
|
+
if (!this.initialized) {
|
|
178
|
+
await this.initialize();
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
const { limit = 100, offset = 0, since = null } = options;
|
|
182
|
+
const logFile = path.join(this.logsDir, `${logType}.log`);
|
|
183
|
+
|
|
184
|
+
try {
|
|
185
|
+
const data = await fs.readFile(logFile, 'utf8');
|
|
186
|
+
const lines = data.trim().split('\n').filter(line => line.length > 0);
|
|
187
|
+
|
|
188
|
+
let entries = lines.map(line => {
|
|
189
|
+
try {
|
|
190
|
+
return JSON.parse(line);
|
|
191
|
+
} catch {
|
|
192
|
+
return null;
|
|
193
|
+
}
|
|
194
|
+
}).filter(entry => entry !== null);
|
|
195
|
+
|
|
196
|
+
// Filter by date if specified
|
|
197
|
+
if (since) {
|
|
198
|
+
const sinceTime = since.getTime();
|
|
199
|
+
entries = entries.filter(entry => {
|
|
200
|
+
const entryTime = new Date(entry.timestamp).getTime();
|
|
201
|
+
return entryTime >= sinceTime;
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// Sort by timestamp (newest first)
|
|
206
|
+
entries.sort((a, b) => new Date(b.timestamp) - new Date(a.timestamp));
|
|
207
|
+
|
|
208
|
+
// Apply offset and limit
|
|
209
|
+
return entries.slice(offset, offset + limit);
|
|
210
|
+
} catch (error) {
|
|
211
|
+
if (error.code === 'ENOENT') {
|
|
212
|
+
return [];
|
|
213
|
+
}
|
|
214
|
+
throw new Error(`Failed to read logs: ${error.message}`);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Get log statistics
|
|
220
|
+
* @param {string} logType - Type of log
|
|
221
|
+
* @returns {Promise<Object>} - Log statistics
|
|
222
|
+
*/
|
|
223
|
+
async getLogStats(logType) {
|
|
224
|
+
if (!this.initialized) {
|
|
225
|
+
await this.initialize();
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
const logFile = path.join(this.logsDir, `${logType}.log`);
|
|
229
|
+
|
|
230
|
+
try {
|
|
231
|
+
const stats = await fs.stat(logFile);
|
|
232
|
+
const entries = await this.readLogs(logType, { limit: 10000 }); // Read up to 10k entries for stats
|
|
233
|
+
|
|
234
|
+
const statsData = {
|
|
235
|
+
fileExists: true,
|
|
236
|
+
fileSize: stats.size,
|
|
237
|
+
lastModified: stats.mtime.toISOString(),
|
|
238
|
+
totalEntries: entries.length,
|
|
239
|
+
dateRange: null
|
|
240
|
+
};
|
|
241
|
+
|
|
242
|
+
if (entries.length > 0) {
|
|
243
|
+
const timestamps = entries.map(entry => new Date(entry.timestamp));
|
|
244
|
+
const minDate = new Date(Math.min(...timestamps));
|
|
245
|
+
const maxDate = new Date(Math.max(...timestamps));
|
|
246
|
+
|
|
247
|
+
statsData.dateRange = {
|
|
248
|
+
earliest: minDate.toISOString(),
|
|
249
|
+
latest: maxDate.toISOString()
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
return statsData;
|
|
254
|
+
} catch (error) {
|
|
255
|
+
if (error.code === 'ENOENT') {
|
|
256
|
+
return {
|
|
257
|
+
fileExists: false,
|
|
258
|
+
fileSize: 0,
|
|
259
|
+
lastModified: null,
|
|
260
|
+
totalEntries: 0,
|
|
261
|
+
dateRange: null
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
throw new Error(`Failed to get log stats: ${error.message}`);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* Clean old log entries
|
|
270
|
+
* @param {string} logType - Type of log
|
|
271
|
+
* @param {number} olderThanDays - Remove entries older than this many days
|
|
272
|
+
* @returns {Promise<number>} - Number of entries removed
|
|
273
|
+
*/
|
|
274
|
+
async cleanOldLogs(logType, olderThanDays = 30) {
|
|
275
|
+
if (!this.initialized) {
|
|
276
|
+
await this.initialize();
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
const cutoffDate = new Date();
|
|
280
|
+
cutoffDate.setDate(cutoffDate.getDate() - olderThanDays);
|
|
281
|
+
|
|
282
|
+
const entries = await this.readLogs(logType, { limit: 10000 });
|
|
283
|
+
const recentEntries = entries.filter(entry => {
|
|
284
|
+
return new Date(entry.timestamp) >= cutoffDate;
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
const logFile = path.join(this.logsDir, `${logType}.log`);
|
|
288
|
+
|
|
289
|
+
// Rewrite log file with only recent entries
|
|
290
|
+
const logLines = recentEntries.map(entry => JSON.stringify(entry) + '\n');
|
|
291
|
+
await fs.writeFile(logFile, logLines.join(''), 'utf8');
|
|
292
|
+
|
|
293
|
+
return entries.length - recentEntries.length;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* Rotate log files (move current log to backup and create new one)
|
|
298
|
+
* @param {string} logType - Type of log
|
|
299
|
+
* @returns {Promise<void>}
|
|
300
|
+
*/
|
|
301
|
+
async rotateLog(logType) {
|
|
302
|
+
if (!this.initialized) {
|
|
303
|
+
await this.initialize();
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
const logFile = path.join(this.logsDir, `${logType}.log`);
|
|
307
|
+
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
|
|
308
|
+
const backupFile = path.join(this.logsDir, `${logType}-${timestamp}.log`);
|
|
309
|
+
|
|
310
|
+
try {
|
|
311
|
+
await fs.access(logFile);
|
|
312
|
+
await fs.rename(logFile, backupFile);
|
|
313
|
+
} catch (error) {
|
|
314
|
+
if (error.code !== 'ENOENT') {
|
|
315
|
+
throw new Error(`Failed to rotate log: ${error.message}`);
|
|
316
|
+
}
|
|
317
|
+
// If file doesn't exist, no rotation needed
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
/**
|
|
322
|
+
* Get storage usage statistics
|
|
323
|
+
* @returns {Promise<Object>} - Storage usage data
|
|
324
|
+
*/
|
|
325
|
+
async getStorageUsage() {
|
|
326
|
+
if (!this.initialized) {
|
|
327
|
+
await this.initialize();
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
const usage = {
|
|
331
|
+
baseDir: this.baseDir,
|
|
332
|
+
totalSize: 0,
|
|
333
|
+
directories: {},
|
|
334
|
+
files: []
|
|
335
|
+
};
|
|
336
|
+
|
|
337
|
+
try {
|
|
338
|
+
// Calculate directory sizes
|
|
339
|
+
const dirs = ['config', 'logs'];
|
|
340
|
+
|
|
341
|
+
for (const dir of dirs) {
|
|
342
|
+
const dirPath = path.join(this.baseDir, dir);
|
|
343
|
+
try {
|
|
344
|
+
const dirSize = await this.calculateDirectorySize(dirPath);
|
|
345
|
+
usage.directories[dir] = dirSize;
|
|
346
|
+
usage.totalSize += dirSize;
|
|
347
|
+
} catch {
|
|
348
|
+
usage.directories[dir] = 0;
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
// List files
|
|
353
|
+
const files = await this.listFiles(this.baseDir);
|
|
354
|
+
usage.files = files;
|
|
355
|
+
} catch (error) {
|
|
356
|
+
throw new Error(`Failed to get storage usage: ${error.message}`);
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
return usage;
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
/**
|
|
363
|
+
* Calculate directory size
|
|
364
|
+
* @param {string} dirPath - Directory path
|
|
365
|
+
* @returns {Promise<number>} - Directory size in bytes
|
|
366
|
+
*/
|
|
367
|
+
async calculateDirectorySize(dirPath) {
|
|
368
|
+
let totalSize = 0;
|
|
369
|
+
|
|
370
|
+
try {
|
|
371
|
+
const items = await fs.readdir(dirPath);
|
|
372
|
+
|
|
373
|
+
for (const item of items) {
|
|
374
|
+
const itemPath = path.join(dirPath, item);
|
|
375
|
+
const stats = await fs.stat(itemPath);
|
|
376
|
+
|
|
377
|
+
if (stats.isDirectory()) {
|
|
378
|
+
totalSize += await this.calculateDirectorySize(itemPath);
|
|
379
|
+
} else {
|
|
380
|
+
totalSize += stats.size;
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
} catch {
|
|
384
|
+
// Directory doesn't exist or can't be accessed
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
return totalSize;
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
/**
|
|
391
|
+
* List files in directory recursively
|
|
392
|
+
* @param {string} dirPath - Directory path
|
|
393
|
+
* @param {number} maxDepth - Maximum recursion depth
|
|
394
|
+
* @returns {Promise<Array>} - Array of file information
|
|
395
|
+
*/
|
|
396
|
+
async listFiles(dirPath, maxDepth = 3) {
|
|
397
|
+
const files = [];
|
|
398
|
+
|
|
399
|
+
try {
|
|
400
|
+
const items = await fs.readdir(dirPath);
|
|
401
|
+
|
|
402
|
+
for (const item of items) {
|
|
403
|
+
const itemPath = path.join(dirPath, item);
|
|
404
|
+
const stats = await fs.stat(itemPath);
|
|
405
|
+
const relativePath = path.relative(this.baseDir, itemPath);
|
|
406
|
+
|
|
407
|
+
if (stats.isDirectory() && maxDepth > 0) {
|
|
408
|
+
const subFiles = await this.listFiles(itemPath, maxDepth - 1);
|
|
409
|
+
files.push(...subFiles);
|
|
410
|
+
} else if (stats.isFile()) {
|
|
411
|
+
files.push({
|
|
412
|
+
path: relativePath,
|
|
413
|
+
size: stats.size,
|
|
414
|
+
modified: stats.mtime.toISOString(),
|
|
415
|
+
type: path.extname(itemPath).slice(1) || 'file'
|
|
416
|
+
});
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
} catch {
|
|
420
|
+
// Directory doesn't exist or can't be accessed
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
return files;
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
/**
|
|
427
|
+
* Backup storage data
|
|
428
|
+
* @param {string} backupPath - Backup directory path
|
|
429
|
+
* @returns {Promise<void>}
|
|
430
|
+
*/
|
|
431
|
+
async backup(backupPath) {
|
|
432
|
+
if (!this.initialized) {
|
|
433
|
+
await this.initialize();
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
const { execSync } = require('child_process');
|
|
437
|
+
|
|
438
|
+
try {
|
|
439
|
+
// Create backup directory
|
|
440
|
+
await fs.mkdir(backupPath, { recursive: true });
|
|
441
|
+
|
|
442
|
+
// Copy storage directory
|
|
443
|
+
const command = process.platform === 'win32'
|
|
444
|
+
? `xcopy "${this.baseDir}" "${backupPath}" /E /I /H /Y`
|
|
445
|
+
: `cp -r "${this.baseDir}"/* "${backupPath}/"`;
|
|
446
|
+
|
|
447
|
+
execSync(command, { stdio: 'ignore' });
|
|
448
|
+
} catch (error) {
|
|
449
|
+
throw new Error(`Failed to backup storage: ${error.message}`);
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
module.exports = FileManager;
|