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.
Files changed (202) hide show
  1. package/README.md +240 -0
  2. package/package.json +10 -2
  3. package/src/agents/Agent.js +300 -0
  4. package/src/agents/AgentAdditionService.js +311 -0
  5. package/src/agents/AgentCheckService.js +690 -0
  6. package/src/agents/AgentInstallationService.js +140 -0
  7. package/src/agents/AgentSetupService.js +467 -0
  8. package/src/agents/AgentStatus.js +183 -0
  9. package/src/agents/AgentVerificationService.js +634 -0
  10. package/src/agents/ConfigurationSchemaValidator.js +543 -0
  11. package/src/agents/EnvironmentConfigurationManager.js +602 -0
  12. package/src/agents/InstallationErrorHandler.js +372 -0
  13. package/src/agents/InstallationLog.js +363 -0
  14. package/src/agents/InstallationMethod.js +510 -0
  15. package/src/agents/InstallationOrchestrator.js +352 -0
  16. package/src/agents/InstallationProgressReporter.js +372 -0
  17. package/src/agents/InstallationRetryManager.js +322 -0
  18. package/src/agents/InstallationType.js +254 -0
  19. package/src/agents/OperationTypes.js +310 -0
  20. package/src/agents/PerformanceMetricsCollector.js +493 -0
  21. package/src/agents/SecurityValidationService.js +534 -0
  22. package/src/agents/VerificationTest.js +354 -0
  23. package/src/agents/VerificationType.js +226 -0
  24. package/src/agents/WindowsPermissionHandler.js +518 -0
  25. package/src/agents/config/AgentConfigManager.js +393 -0
  26. package/src/agents/config/AgentDefaultsRegistry.js +373 -0
  27. package/src/agents/config/ConfigValidator.js +281 -0
  28. package/src/agents/discovery/AgentDiscoveryService.js +707 -0
  29. package/src/agents/logging/AgentLogger.js +511 -0
  30. package/src/agents/status/AgentStatusManager.js +481 -0
  31. package/src/agents/storage/FileManager.js +454 -0
  32. package/src/agents/verification/AgentCommunicationTester.js +474 -0
  33. package/src/agents/verification/BaseVerifier.js +430 -0
  34. package/src/agents/verification/CommandVerifier.js +480 -0
  35. package/src/agents/verification/FileOperationVerifier.js +453 -0
  36. package/src/agents/verification/ResultAnalyzer.js +707 -0
  37. package/src/agents/verification/TestRequirementManager.js +495 -0
  38. package/src/agents/verification/VerificationRunner.js +433 -0
  39. package/src/agents/windows/BaseWindowsInstaller.js +441 -0
  40. package/src/agents/windows/ChocolateyInstaller.js +509 -0
  41. package/src/agents/windows/DirectInstaller.js +443 -0
  42. package/src/agents/windows/InstallerFactory.js +391 -0
  43. package/src/agents/windows/NpmInstaller.js +505 -0
  44. package/src/agents/windows/PowerShellInstaller.js +458 -0
  45. package/src/agents/windows/WinGetInstaller.js +390 -0
  46. package/src/analysis/analysis-reporter.js +132 -0
  47. package/src/analysis/boundary-detector.js +712 -0
  48. package/src/analysis/categorizer.js +340 -0
  49. package/src/analysis/codebase-scanner.js +384 -0
  50. package/src/analysis/line-counter.js +513 -0
  51. package/src/analysis/priority-calculator.js +679 -0
  52. package/src/analysis/report/analysis-report.js +250 -0
  53. package/src/analysis/report/package-analyzer.js +278 -0
  54. package/src/analysis/report/recommendation-generator.js +382 -0
  55. package/src/analysis/report/statistics-generator.js +515 -0
  56. package/src/analysis/reports/analysis-report-model.js +101 -0
  57. package/src/analysis/reports/recommendation-generator.js +283 -0
  58. package/src/analysis/reports/report-generators.js +191 -0
  59. package/src/analysis/reports/statistics-calculator.js +231 -0
  60. package/src/analysis/reports/trend-analyzer.js +219 -0
  61. package/src/analysis/strategy-generator.js +814 -0
  62. package/src/auto-mode/AutoModeBusinessLogic.js +836 -0
  63. package/src/config/refactoring-config.js +307 -0
  64. package/src/health-tracking/json-storage.js +38 -2
  65. package/src/ide-integration/applescript-manager-core.js +233 -0
  66. package/src/ide-integration/applescript-manager.cjs +357 -28
  67. package/src/ide-integration/applescript-manager.js +89 -3599
  68. package/src/ide-integration/cdp-manager.js +306 -0
  69. package/src/ide-integration/claude-code-cli-manager.cjs +1 -1
  70. package/src/ide-integration/continuation-handler.js +337 -0
  71. package/src/ide-integration/ide-status-checker.js +292 -0
  72. package/src/ide-integration/macos-ide-manager.js +627 -0
  73. package/src/ide-integration/macos-text-sender.js +528 -0
  74. package/src/ide-integration/response-reader.js +548 -0
  75. package/src/ide-integration/windows-automation-manager.js +121 -0
  76. package/src/ide-integration/windows-ide-manager.js +373 -0
  77. package/src/index.cjs +25 -3
  78. package/src/index.js +15 -1
  79. package/src/llm/direct-llm-manager.cjs +90 -2
  80. package/src/models/compliance-report.js +538 -0
  81. package/src/models/file-analysis.js +681 -0
  82. package/src/models/refactoring-plan.js +770 -0
  83. package/src/monitoring/alert-system.js +834 -0
  84. package/src/monitoring/compliance-progress-tracker.js +437 -0
  85. package/src/monitoring/continuous-scan-notifications.js +661 -0
  86. package/src/monitoring/continuous-scanner.js +279 -0
  87. package/src/monitoring/file-monitor/file-analyzer.js +262 -0
  88. package/src/monitoring/file-monitor/file-monitor.js +237 -0
  89. package/src/monitoring/file-monitor/watcher.js +194 -0
  90. package/src/monitoring/file-monitor.js +17 -0
  91. package/src/monitoring/notification-manager.js +437 -0
  92. package/src/monitoring/scanner-core.js +368 -0
  93. package/src/monitoring/scanner-events.js +214 -0
  94. package/src/monitoring/violation-notification-system.js +515 -0
  95. package/src/refactoring/boundaries/cohesion-analyzer.js +316 -0
  96. package/src/refactoring/boundaries/extraction-result.js +285 -0
  97. package/src/refactoring/boundaries/extraction-strategies.js +392 -0
  98. package/src/refactoring/boundaries/module-boundary.js +209 -0
  99. package/src/refactoring/boundary/boundary-detector.js +741 -0
  100. package/src/refactoring/boundary/boundary-types.js +405 -0
  101. package/src/refactoring/boundary/extraction-strategies.js +554 -0
  102. package/src/refactoring/boundary-extraction-result.js +77 -0
  103. package/src/refactoring/boundary-extraction-strategies.js +330 -0
  104. package/src/refactoring/boundary-extractor.js +384 -0
  105. package/src/refactoring/boundary-types.js +46 -0
  106. package/src/refactoring/circular/circular-dependency.js +88 -0
  107. package/src/refactoring/circular/cycle-detection.js +147 -0
  108. package/src/refactoring/circular/dependency-node.js +82 -0
  109. package/src/refactoring/circular/dependency-result.js +107 -0
  110. package/src/refactoring/circular/dependency-types.js +58 -0
  111. package/src/refactoring/circular/graph-builder.js +213 -0
  112. package/src/refactoring/circular/resolution-strategy.js +72 -0
  113. package/src/refactoring/circular/strategy-generator.js +229 -0
  114. package/src/refactoring/circular-dependency-resolver-original.js +809 -0
  115. package/src/refactoring/circular-dependency-resolver.js +200 -0
  116. package/src/refactoring/code-mover.js +761 -0
  117. package/src/refactoring/file-splitter.js +696 -0
  118. package/src/refactoring/functionality-validator.js +816 -0
  119. package/src/refactoring/import-manager.js +774 -0
  120. package/src/refactoring/module-boundary.js +107 -0
  121. package/src/refactoring/refactoring-executor.js +672 -0
  122. package/src/refactoring/refactoring-rollback.js +614 -0
  123. package/src/refactoring/test-validator.js +631 -0
  124. package/src/requirement-management/default-requirement-manager.js +321 -0
  125. package/src/requirement-management/requirement-file-parser.js +159 -0
  126. package/src/requirement-management/requirement-sequencer.js +221 -0
  127. package/src/rui/commands/AgentCommandParser.js +600 -0
  128. package/src/rui/commands/AgentCommands.js +487 -0
  129. package/src/rui/commands/AgentResponseFormatter.js +832 -0
  130. package/src/scripts/verify-full-compliance.js +269 -0
  131. package/src/sync/sync-engine-core.js +1 -0
  132. package/src/sync/sync-engine-remote-handlers.js +135 -0
  133. package/src/task-generation/automated-task-generator.js +351 -0
  134. package/src/task-generation/prioritizer.js +287 -0
  135. package/src/task-generation/task-list-updater.js +215 -0
  136. package/src/task-generation/task-management-integration.js +480 -0
  137. package/src/task-generation/task-manager-integration.js +270 -0
  138. package/src/task-generation/violation-task-generator.js +474 -0
  139. package/src/task-management/continuous-scan-integration.js +342 -0
  140. package/src/timeout-management/index.js +12 -3
  141. package/src/timeout-management/response-time-tracker.js +167 -0
  142. package/src/timeout-management/timeout-calculator.js +159 -0
  143. package/src/timeout-management/timeout-config-manager.js +172 -0
  144. package/src/utils/ast-analyzer.js +417 -0
  145. package/src/utils/current-requirement-manager.js +276 -0
  146. package/src/utils/current-requirement-operations.js +472 -0
  147. package/src/utils/dependency-mapper.js +456 -0
  148. package/src/utils/download-with-progress.js +4 -2
  149. package/src/utils/electron-update-checker.js +4 -1
  150. package/src/utils/file-size-analyzer.js +272 -0
  151. package/src/utils/import-updater.js +280 -0
  152. package/src/utils/refactoring-tools.js +512 -0
  153. package/src/utils/report-generator.js +569 -0
  154. package/src/utils/reports/report-analysis.js +218 -0
  155. package/src/utils/reports/report-types.js +55 -0
  156. package/src/utils/reports/summary-generators.js +102 -0
  157. package/src/utils/requirement-file-management.js +157 -0
  158. package/src/utils/requirement-helpers/requirement-file-ops.js +392 -0
  159. package/src/utils/requirement-helpers/requirement-mover.js +414 -0
  160. package/src/utils/requirement-helpers/requirement-parser.js +326 -0
  161. package/src/utils/requirement-helpers/requirement-status.js +320 -0
  162. package/src/utils/requirement-helpers-new.js +55 -0
  163. package/src/utils/requirement-helpers-refactored.js +367 -0
  164. package/src/utils/requirement-helpers.js +291 -1191
  165. package/src/utils/requirement-movement-operations.js +450 -0
  166. package/src/utils/requirement-movement.js +312 -0
  167. package/src/utils/requirement-parsing-helpers.js +56 -0
  168. package/src/utils/requirement-statistics.js +200 -0
  169. package/src/utils/requirement-text-utils.js +58 -0
  170. package/src/utils/rollback/rollback-handlers.js +125 -0
  171. package/src/utils/rollback/rollback-operation.js +63 -0
  172. package/src/utils/rollback/rollback-recorder.js +166 -0
  173. package/src/utils/rollback/rollback-state-manager.js +175 -0
  174. package/src/utils/rollback/rollback-types.js +33 -0
  175. package/src/utils/rollback/rollback-utils.js +110 -0
  176. package/src/utils/rollback-manager-original.js +569 -0
  177. package/src/utils/rollback-manager.js +202 -0
  178. package/src/utils/smoke-test-cli.js +362 -0
  179. package/src/utils/smoke-test-gui.js +351 -0
  180. package/src/utils/smoke-test-orchestrator.js +321 -0
  181. package/src/utils/smoke-test-runner.js +60 -0
  182. package/src/utils/smoke-test-web.js +347 -0
  183. package/src/utils/specification-helpers.js +39 -13
  184. package/src/utils/specification-migration.js +97 -0
  185. package/src/utils/test-runner.js +579 -0
  186. package/src/utils/validation-framework.js +518 -0
  187. package/src/validation/compliance-analyzer.js +197 -0
  188. package/src/validation/compliance-report-generator.js +343 -0
  189. package/src/validation/compliance-reporter.js +711 -0
  190. package/src/validation/compliance-rules.js +127 -0
  191. package/src/validation/constitution-validator-new.js +196 -0
  192. package/src/validation/constitution-validator.js +17 -0
  193. package/src/validation/file-validators.js +170 -0
  194. package/src/validation/line-limit/file-analyzer.js +201 -0
  195. package/src/validation/line-limit/line-limit-validator.js +208 -0
  196. package/src/validation/line-limit/validation-result.js +144 -0
  197. package/src/validation/line-limit-core.js +225 -0
  198. package/src/validation/line-limit-reporter.js +134 -0
  199. package/src/validation/line-limit-result.js +125 -0
  200. package/src/validation/line-limit-validator.js +41 -0
  201. package/src/validation/metrics-calculator.js +660 -0
  202. 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;