baseguard 1.0.0 โ†’ 1.0.2

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 (156) hide show
  1. package/.baseguardrc.example.json +64 -0
  2. package/.eslintrc.json +1 -1
  3. package/CHANGELOG.md +196 -0
  4. package/DEPLOYMENT.md +625 -0
  5. package/DEPLOYMENT_CHECKLIST.md +239 -0
  6. package/DEPLOYMENT_SUMMARY_v1.0.2.md +202 -0
  7. package/QUICK_START.md +134 -0
  8. package/README.md +447 -52
  9. package/RELEASE_NOTES_v1.0.2.md +434 -0
  10. package/bin/base.js +155 -36
  11. package/dist/ai/agentkit-orchestrator.d.ts +116 -0
  12. package/dist/ai/agentkit-orchestrator.d.ts.map +1 -0
  13. package/dist/ai/agentkit-orchestrator.js +417 -0
  14. package/dist/ai/agentkit-orchestrator.js.map +1 -0
  15. package/dist/ai/gemini-code-fixer.d.ts +85 -0
  16. package/dist/ai/gemini-code-fixer.d.ts.map +1 -0
  17. package/dist/ai/gemini-code-fixer.js +452 -0
  18. package/dist/ai/gemini-code-fixer.js.map +1 -0
  19. package/dist/ai/jules-implementer.d.ts +5 -4
  20. package/dist/ai/jules-implementer.d.ts.map +1 -1
  21. package/dist/ai/jules-implementer.js +6 -5
  22. package/dist/ai/jules-implementer.js.map +1 -1
  23. package/dist/ai/unified-code-fixer.d.ts +69 -0
  24. package/dist/ai/unified-code-fixer.d.ts.map +1 -0
  25. package/dist/ai/unified-code-fixer.js +289 -0
  26. package/dist/ai/unified-code-fixer.js.map +1 -0
  27. package/dist/commands/check.d.ts +3 -1
  28. package/dist/commands/check.d.ts.map +1 -1
  29. package/dist/commands/check.js +166 -34
  30. package/dist/commands/check.js.map +1 -1
  31. package/dist/commands/config.d.ts +4 -0
  32. package/dist/commands/config.d.ts.map +1 -1
  33. package/dist/commands/config.js +183 -0
  34. package/dist/commands/config.js.map +1 -1
  35. package/dist/commands/fix.d.ts.map +1 -1
  36. package/dist/commands/fix.js +89 -91
  37. package/dist/commands/fix.js.map +1 -1
  38. package/dist/commands/index.d.ts +1 -0
  39. package/dist/commands/index.d.ts.map +1 -1
  40. package/dist/commands/index.js +1 -0
  41. package/dist/commands/index.js.map +1 -1
  42. package/dist/commands/init.d.ts.map +1 -1
  43. package/dist/commands/init.js +16 -2
  44. package/dist/commands/init.js.map +1 -1
  45. package/dist/commands/status.d.ts +14 -0
  46. package/dist/commands/status.d.ts.map +1 -0
  47. package/dist/commands/status.js +254 -0
  48. package/dist/commands/status.js.map +1 -0
  49. package/dist/core/baseguard.d.ts +47 -5
  50. package/dist/core/baseguard.d.ts.map +1 -1
  51. package/dist/core/baseguard.js +506 -52
  52. package/dist/core/baseguard.js.map +1 -1
  53. package/dist/core/cache-manager.d.ts.map +1 -1
  54. package/dist/core/cache-manager.js +3 -1
  55. package/dist/core/cache-manager.js.map +1 -1
  56. package/dist/core/configuration-recovery.d.ts +116 -0
  57. package/dist/core/configuration-recovery.d.ts.map +1 -0
  58. package/dist/core/configuration-recovery.js +552 -0
  59. package/dist/core/configuration-recovery.js.map +1 -0
  60. package/dist/core/configuration.d.ts +4 -0
  61. package/dist/core/configuration.d.ts.map +1 -1
  62. package/dist/core/configuration.js +35 -0
  63. package/dist/core/configuration.js.map +1 -1
  64. package/dist/core/debug-logger.d.ts +181 -0
  65. package/dist/core/debug-logger.d.ts.map +1 -0
  66. package/dist/core/debug-logger.js +479 -0
  67. package/dist/core/debug-logger.js.map +1 -0
  68. package/dist/core/file-processor.d.ts.map +1 -1
  69. package/dist/core/file-processor.js +8 -2
  70. package/dist/core/file-processor.js.map +1 -1
  71. package/dist/core/graceful-degradation-manager.d.ts +123 -0
  72. package/dist/core/graceful-degradation-manager.d.ts.map +1 -0
  73. package/dist/core/graceful-degradation-manager.js +512 -0
  74. package/dist/core/graceful-degradation-manager.js.map +1 -0
  75. package/dist/core/index.d.ts +4 -0
  76. package/dist/core/index.d.ts.map +1 -1
  77. package/dist/core/index.js +4 -0
  78. package/dist/core/index.js.map +1 -1
  79. package/dist/core/logger.d.ts +1 -0
  80. package/dist/core/logger.d.ts.map +1 -0
  81. package/dist/core/logger.js +2 -0
  82. package/dist/core/logger.js.map +1 -0
  83. package/dist/core/memory-manager.d.ts +84 -0
  84. package/dist/core/memory-manager.d.ts.map +1 -1
  85. package/dist/core/memory-manager.js +236 -1
  86. package/dist/core/memory-manager.js.map +1 -1
  87. package/dist/core/startup-optimizer.d.ts +12 -0
  88. package/dist/core/startup-optimizer.d.ts.map +1 -1
  89. package/dist/core/startup-optimizer.js +60 -0
  90. package/dist/core/startup-optimizer.js.map +1 -1
  91. package/dist/core/system-error-handler.d.ts +65 -0
  92. package/dist/core/system-error-handler.d.ts.map +1 -0
  93. package/dist/core/system-error-handler.js +646 -0
  94. package/dist/core/system-error-handler.js.map +1 -0
  95. package/dist/git/github-manager.d.ts +5 -16
  96. package/dist/git/github-manager.d.ts.map +1 -1
  97. package/dist/git/github-manager.js +6 -61
  98. package/dist/git/github-manager.js.map +1 -1
  99. package/dist/parsers/react-parser-optimized.d.ts +16 -0
  100. package/dist/parsers/react-parser-optimized.d.ts.map +1 -0
  101. package/dist/parsers/react-parser-optimized.js +147 -0
  102. package/dist/parsers/react-parser-optimized.js.map +1 -0
  103. package/dist/parsers/react-parser.d.ts.map +1 -1
  104. package/dist/parsers/react-parser.js +17 -15
  105. package/dist/parsers/react-parser.js.map +1 -1
  106. package/dist/parsers/svelte-parser.d.ts.map +1 -1
  107. package/dist/parsers/svelte-parser.js +7 -3
  108. package/dist/parsers/svelte-parser.js.map +1 -1
  109. package/dist/parsers/vanilla-parser.d.ts.map +1 -1
  110. package/dist/parsers/vanilla-parser.js +7 -3
  111. package/dist/parsers/vanilla-parser.js.map +1 -1
  112. package/dist/parsers/vue-parser.d.ts +18 -0
  113. package/dist/parsers/vue-parser.d.ts.map +1 -1
  114. package/dist/parsers/vue-parser.js +387 -1
  115. package/dist/parsers/vue-parser.js.map +1 -1
  116. package/dist/types/index.d.ts +4 -0
  117. package/dist/types/index.d.ts.map +1 -1
  118. package/dist/ui/help.js +1 -1
  119. package/dist/ui/help.js.map +1 -1
  120. package/dist/ui/prompts.d.ts +7 -4
  121. package/dist/ui/prompts.d.ts.map +1 -1
  122. package/dist/ui/prompts.js +48 -55
  123. package/dist/ui/prompts.js.map +1 -1
  124. package/package.json +30 -5
  125. package/src/ai/__tests__/gemini-analyzer.test.ts +2 -2
  126. package/src/ai/agentkit-orchestrator.ts +534 -0
  127. package/src/ai/gemini-code-fixer.ts +540 -0
  128. package/src/ai/jules-implementer.ts +6 -5
  129. package/src/ai/unified-code-fixer.ts +347 -0
  130. package/src/commands/config.ts +218 -0
  131. package/src/commands/fix.ts +98 -94
  132. package/src/commands/index.ts +2 -1
  133. package/src/commands/init.ts +16 -2
  134. package/src/commands/status.ts +307 -0
  135. package/src/core/baseguard.ts +36 -22
  136. package/src/core/cache-manager.ts +4 -2
  137. package/src/core/configuration-recovery.ts +3 -6
  138. package/src/core/configuration.ts +37 -0
  139. package/src/core/debug-logger.ts +2 -2
  140. package/src/core/file-processor.ts +10 -3
  141. package/src/core/index.ts +5 -1
  142. package/src/core/memory-manager.ts +4 -3
  143. package/src/core/startup-optimizer.ts +70 -0
  144. package/src/core/system-error-handler.ts +9 -5
  145. package/src/git/github-manager.ts +11 -79
  146. package/src/parsers/react-parser.ts +2 -2
  147. package/src/parsers/svelte-parser.ts +13 -9
  148. package/src/parsers/vanilla-parser.ts +18 -14
  149. package/src/parsers/vue-parser.ts +20 -14
  150. package/src/types/index.ts +4 -0
  151. package/src/ui/help.ts +1 -1
  152. package/src/ui/prompts.ts +54 -61
  153. package/test-build.js +41 -0
  154. package/tests/e2e/git-integration.e2e.test.ts +1 -1
  155. package/tsconfig.json +0 -1
  156. package/vitest.config.ts +4 -2
@@ -0,0 +1,646 @@
1
+ import chalk from 'chalk';
2
+ import { promises as fs } from 'fs';
3
+ import path from 'path';
4
+ export class SystemError extends Error {
5
+ code;
6
+ context;
7
+ recoverable;
8
+ severity;
9
+ constructor(message, code, context, recoverable = true, severity = 'medium') {
10
+ super(message);
11
+ this.code = code;
12
+ this.context = context;
13
+ this.recoverable = recoverable;
14
+ this.severity = severity;
15
+ this.name = 'SystemError';
16
+ this.context = {
17
+ operation: context?.operation || 'unknown',
18
+ file: context?.file,
19
+ line: context?.line,
20
+ details: context?.details,
21
+ timestamp: new Date(),
22
+ userId: context?.userId
23
+ };
24
+ }
25
+ }
26
+ export class SystemErrorHandler {
27
+ static retryAttempts = new Map();
28
+ static maxRetries = 3;
29
+ static backoffBase = 1000; // 1 second
30
+ static errorLog = [];
31
+ static maxLogSize = 100;
32
+ static recoveryStrategies = new Map();
33
+ static gracefulDegradationEnabled = true;
34
+ static offlineMode = false;
35
+ static async withRetry(operation, context, maxRetries = SystemErrorHandler.maxRetries, customBackoff) {
36
+ const key = `${context.operation}-${context.file || 'global'}`;
37
+ let attempts = SystemErrorHandler.retryAttempts.get(key) || 0;
38
+ try {
39
+ const result = await operation();
40
+ SystemErrorHandler.retryAttempts.delete(key); // Reset on success
41
+ return result;
42
+ }
43
+ catch (error) {
44
+ attempts++;
45
+ SystemErrorHandler.retryAttempts.set(key, attempts);
46
+ const wrappedError = SystemErrorHandler.wrapError(error, context);
47
+ SystemErrorHandler.logError(wrappedError);
48
+ if (attempts >= maxRetries) {
49
+ SystemErrorHandler.retryAttempts.delete(key);
50
+ // Try recovery strategies before giving up
51
+ const recovered = await SystemErrorHandler.attemptRecovery(wrappedError);
52
+ if (!recovered) {
53
+ throw wrappedError;
54
+ }
55
+ // If recovery succeeded, try the operation once more
56
+ SystemErrorHandler.retryAttempts.delete(key);
57
+ return SystemErrorHandler.withRetry(operation, context, 1); // One more try after recovery
58
+ }
59
+ const delay = customBackoff ? customBackoff(attempts) : SystemErrorHandler.backoffBase * Math.pow(2, attempts - 1);
60
+ console.warn(chalk.yellow(`โš ๏ธ Retry ${attempts}/${maxRetries} for ${context.operation} in ${delay}ms`));
61
+ await SystemErrorHandler.sleep(delay);
62
+ return SystemErrorHandler.withRetry(operation, context, maxRetries, customBackoff);
63
+ }
64
+ }
65
+ static async handleGracefully(operation, fallback, context, options = {}) {
66
+ const { logError = true, showWarning = true, attemptRecovery = true } = options;
67
+ try {
68
+ return await operation();
69
+ }
70
+ catch (error) {
71
+ const wrappedError = SystemErrorHandler.wrapError(error, context);
72
+ if (logError) {
73
+ SystemErrorHandler.logError(wrappedError);
74
+ }
75
+ if (showWarning) {
76
+ console.warn(chalk.yellow(`โš ๏ธ ${context.operation} failed: ${error instanceof Error ? error.message : 'Unknown error'}`));
77
+ }
78
+ // Attempt recovery if enabled
79
+ if (attemptRecovery && wrappedError.recoverable) {
80
+ const recovered = await SystemErrorHandler.attemptRecovery(wrappedError);
81
+ if (recovered) {
82
+ try {
83
+ return await operation();
84
+ }
85
+ catch (retryError) {
86
+ // Recovery didn't work, fall back
87
+ }
88
+ }
89
+ }
90
+ // Use fallback
91
+ const fallbackValue = typeof fallback === 'function' ? await fallback() : fallback;
92
+ if (showWarning) {
93
+ console.warn(chalk.cyan('๐Ÿ”„ Using fallback strategy'));
94
+ }
95
+ return fallbackValue;
96
+ }
97
+ }
98
+ static wrapError(error, context) {
99
+ if (error instanceof SystemError) {
100
+ return error;
101
+ }
102
+ let code = 'UNKNOWN_ERROR';
103
+ let recoverable = true;
104
+ let severity = 'medium';
105
+ // Categorize errors with enhanced detection
106
+ if (error.code === 'ENOENT') {
107
+ code = 'FILE_NOT_FOUND';
108
+ severity = 'low';
109
+ }
110
+ else if (error.code === 'EACCES' || error.code === 'EPERM') {
111
+ code = 'PERMISSION_DENIED';
112
+ recoverable = false;
113
+ severity = 'high';
114
+ }
115
+ else if (error.code === 'ENOTDIR') {
116
+ code = 'INVALID_PATH';
117
+ severity = 'medium';
118
+ }
119
+ else if (error.name === 'SyntaxError') {
120
+ code = 'SYNTAX_ERROR';
121
+ severity = 'low';
122
+ }
123
+ else if (error.code === 'NETWORK_ERROR' || error.code === 'ECONNREFUSED' || error.code === 'ENOTFOUND') {
124
+ code = 'NETWORK_ERROR';
125
+ severity = 'medium';
126
+ }
127
+ else if (error.code === 'ETIMEDOUT') {
128
+ code = 'TIMEOUT_ERROR';
129
+ severity = 'medium';
130
+ }
131
+ else if (error.name === 'TypeError' && error.message.includes('fetch')) {
132
+ code = 'API_ERROR';
133
+ severity = 'medium';
134
+ }
135
+ else if (error.code === 'EMFILE' || error.code === 'ENFILE') {
136
+ code = 'TOO_MANY_FILES';
137
+ severity = 'high';
138
+ }
139
+ else if (error.code === 'ENOSPC') {
140
+ code = 'DISK_FULL';
141
+ recoverable = false;
142
+ severity = 'critical';
143
+ }
144
+ else if (error.message?.includes('out of memory') || error.code === 'ERR_MEMORY_ALLOCATION_FAILED') {
145
+ code = 'OUT_OF_MEMORY';
146
+ recoverable = false;
147
+ severity = 'critical';
148
+ }
149
+ else if (error.message?.includes('configuration') || error.message?.includes('config')) {
150
+ code = 'CONFIGURATION_ERROR';
151
+ severity = 'medium';
152
+ }
153
+ else if (error.message?.includes('parser') || error.message?.includes('parsing')) {
154
+ code = 'PARSER_ERROR';
155
+ severity = 'low';
156
+ }
157
+ return new SystemError(error.message || 'An unknown error occurred', code, context, recoverable, severity);
158
+ }
159
+ static displayError(error, options = {}) {
160
+ const { verbose = false, showRecovery = true } = options;
161
+ // Color based on severity
162
+ const severityColors = {
163
+ low: chalk.yellow,
164
+ medium: chalk.red,
165
+ high: chalk.redBright,
166
+ critical: chalk.bgRed.white
167
+ };
168
+ const colorFn = severityColors[error.severity];
169
+ console.error(colorFn('โŒ System Error:'), error.message);
170
+ if (error.context?.file) {
171
+ console.error(chalk.dim(` File: ${error.context.file}`));
172
+ }
173
+ if (error.context?.line) {
174
+ console.error(chalk.dim(` Line: ${error.context.line}`));
175
+ }
176
+ if (verbose && error.context?.details) {
177
+ console.error(chalk.dim(` Details: ${JSON.stringify(error.context.details, null, 2)}`));
178
+ }
179
+ // Show recovery options
180
+ if (showRecovery && error.recoverable) {
181
+ SystemErrorHandler.showRecoveryOptions(error);
182
+ }
183
+ // Provide helpful suggestions
184
+ SystemErrorHandler.provideSuggestions(error);
185
+ }
186
+ static async attemptRecovery(error) {
187
+ const strategies = SystemErrorHandler.recoveryStrategies.get(error.code) || [];
188
+ if (strategies.length === 0) {
189
+ return false;
190
+ }
191
+ console.log(chalk.cyan('๐Ÿ”ง Attempting automatic recovery...'));
192
+ // Sort strategies by priority
193
+ strategies.sort((a, b) => b.priority - a.priority);
194
+ for (const strategy of strategies) {
195
+ try {
196
+ console.log(chalk.dim(` Trying: ${strategy.description}`));
197
+ const success = await strategy.execute();
198
+ if (success) {
199
+ console.log(chalk.green(`โœ… Recovery successful: ${strategy.name}`));
200
+ return true;
201
+ }
202
+ }
203
+ catch (recoveryError) {
204
+ console.log(chalk.dim(` Recovery failed: ${recoveryError instanceof Error ? recoveryError.message : 'Unknown error'}`));
205
+ }
206
+ }
207
+ console.log(chalk.yellow('โš ๏ธ Automatic recovery failed'));
208
+ return false;
209
+ }
210
+ static showRecoveryOptions(error) {
211
+ const strategies = SystemErrorHandler.recoveryStrategies.get(error.code) || [];
212
+ if (strategies.length > 0) {
213
+ console.error(chalk.cyan('\n๐Ÿ”ง Available recovery options:'));
214
+ strategies.forEach((strategy, index) => {
215
+ console.error(chalk.cyan(` ${index + 1}. ${strategy.description}`));
216
+ });
217
+ }
218
+ }
219
+ static provideSuggestions(error) {
220
+ const suggestions = [];
221
+ switch (error.code) {
222
+ case 'FILE_NOT_FOUND':
223
+ suggestions.push('Check if the file path is correct');
224
+ suggestions.push('Ensure the file exists and is accessible');
225
+ suggestions.push('Verify the working directory is correct');
226
+ break;
227
+ case 'PERMISSION_DENIED':
228
+ suggestions.push('Check file permissions with ls -la (Unix) or dir (Windows)');
229
+ suggestions.push('Run with appropriate privileges if needed');
230
+ suggestions.push('Ensure the file is not locked by another process');
231
+ break;
232
+ case 'SYNTAX_ERROR':
233
+ suggestions.push('Check the file syntax with your editor');
234
+ suggestions.push('Ensure the file is valid for its type');
235
+ suggestions.push('Look for missing brackets, quotes, or semicolons');
236
+ break;
237
+ case 'NETWORK_ERROR':
238
+ suggestions.push('Check your internet connection');
239
+ suggestions.push('Verify API endpoints are accessible');
240
+ suggestions.push('Consider running in offline mode with --offline flag');
241
+ suggestions.push('Check if you\'re behind a proxy or firewall');
242
+ break;
243
+ case 'API_ERROR':
244
+ suggestions.push('Verify your API keys are correct');
245
+ suggestions.push('Check API rate limits and quotas');
246
+ suggestions.push('Ensure the API service is available');
247
+ break;
248
+ case 'TIMEOUT_ERROR':
249
+ suggestions.push('Increase timeout with --timeout flag');
250
+ suggestions.push('Check network stability');
251
+ suggestions.push('Try again later if the service is overloaded');
252
+ break;
253
+ case 'TOO_MANY_FILES':
254
+ suggestions.push('Close unnecessary applications');
255
+ suggestions.push('Increase system file descriptor limits');
256
+ suggestions.push('Process files in smaller batches');
257
+ break;
258
+ case 'DISK_FULL':
259
+ suggestions.push('Free up disk space');
260
+ suggestions.push('Clean temporary files');
261
+ suggestions.push('Move files to another drive');
262
+ break;
263
+ case 'OUT_OF_MEMORY':
264
+ suggestions.push('Close other applications to free memory');
265
+ suggestions.push('Process files in smaller batches');
266
+ suggestions.push('Increase system memory if possible');
267
+ break;
268
+ case 'CONFIGURATION_ERROR':
269
+ suggestions.push('Run "base init" to reconfigure BaseGuard');
270
+ suggestions.push('Check .baseguardrc.json for syntax errors');
271
+ suggestions.push('Verify all required configuration fields are present');
272
+ break;
273
+ case 'PARSER_ERROR':
274
+ suggestions.push('Check file syntax and encoding');
275
+ suggestions.push('Ensure file extension matches content type');
276
+ suggestions.push('Try with a simpler version of the file');
277
+ break;
278
+ }
279
+ if (suggestions.length > 0) {
280
+ console.error(chalk.cyan('\n๐Ÿ’ก Suggestions:'));
281
+ suggestions.forEach(suggestion => {
282
+ console.error(chalk.cyan(` โ€ข ${suggestion}`));
283
+ });
284
+ }
285
+ // Show degradation options
286
+ if (SystemErrorHandler.gracefulDegradationEnabled) {
287
+ SystemErrorHandler.showDegradationOptions(error);
288
+ }
289
+ }
290
+ static showDegradationOptions(error) {
291
+ const degradationOptions = [];
292
+ switch (error.code) {
293
+ case 'NETWORK_ERROR':
294
+ case 'API_ERROR':
295
+ degradationOptions.push('Continue with baseline-only checking (no AI analysis)');
296
+ degradationOptions.push('Use cached results if available');
297
+ degradationOptions.push('Switch to offline mode automatically');
298
+ break;
299
+ case 'SYNTAX_ERROR':
300
+ case 'PARSER_ERROR':
301
+ degradationOptions.push('Skip malformed files and continue with others');
302
+ degradationOptions.push('Use basic text parsing as fallback');
303
+ degradationOptions.push('Report parsing issues and continue');
304
+ break;
305
+ case 'TOO_MANY_FILES':
306
+ degradationOptions.push('Process files in smaller batches');
307
+ degradationOptions.push('Skip non-essential file types');
308
+ degradationOptions.push('Use streaming processing to reduce memory usage');
309
+ break;
310
+ case 'CONFIGURATION_ERROR':
311
+ degradationOptions.push('Use default configuration settings');
312
+ degradationOptions.push('Skip optional features that require configuration');
313
+ degradationOptions.push('Continue with basic compatibility checking');
314
+ break;
315
+ }
316
+ if (degradationOptions.length > 0) {
317
+ console.error(chalk.magenta('\n๐Ÿ”„ Graceful degradation options:'));
318
+ degradationOptions.forEach(option => {
319
+ console.error(chalk.magenta(` โ€ข ${option}`));
320
+ });
321
+ }
322
+ }
323
+ static logError(error) {
324
+ SystemErrorHandler.errorLog.push(error);
325
+ // Keep log size manageable
326
+ if (SystemErrorHandler.errorLog.length > SystemErrorHandler.maxLogSize) {
327
+ SystemErrorHandler.errorLog.shift();
328
+ }
329
+ }
330
+ static async saveErrorLog(filePath) {
331
+ const logPath = filePath || path.join(process.cwd(), '.baseguard-errors.log');
332
+ const logData = {
333
+ timestamp: new Date().toISOString(),
334
+ version: process.env.npm_package_version || 'unknown',
335
+ platform: process.platform,
336
+ nodeVersion: process.version,
337
+ errors: SystemErrorHandler.errorLog.map(error => ({
338
+ message: error.message,
339
+ code: error.code,
340
+ severity: error.severity,
341
+ context: error.context,
342
+ recoverable: error.recoverable
343
+ }))
344
+ };
345
+ try {
346
+ await fs.writeFile(logPath, JSON.stringify(logData, null, 2));
347
+ console.log(chalk.dim(`Error log saved to: ${logPath}`));
348
+ }
349
+ catch (writeError) {
350
+ console.warn(chalk.yellow(`Failed to save error log: ${writeError instanceof Error ? writeError.message : 'Unknown error'}`));
351
+ }
352
+ }
353
+ static getErrorSummary() {
354
+ const summary = {
355
+ total: SystemErrorHandler.errorLog.length,
356
+ bySeverity: { low: 0, medium: 0, high: 0, critical: 0 },
357
+ byCode: {},
358
+ recoverable: 0,
359
+ critical: 0
360
+ };
361
+ SystemErrorHandler.errorLog.forEach(error => {
362
+ summary.bySeverity[error.severity]++;
363
+ summary.byCode[error.code] = (summary.byCode[error.code] || 0) + 1;
364
+ if (error.recoverable)
365
+ summary.recoverable++;
366
+ if (error.severity === 'critical')
367
+ summary.critical++;
368
+ });
369
+ return summary;
370
+ }
371
+ static registerRecoveryStrategy(errorCode, strategy) {
372
+ if (!SystemErrorHandler.recoveryStrategies.has(errorCode)) {
373
+ SystemErrorHandler.recoveryStrategies.set(errorCode, []);
374
+ }
375
+ SystemErrorHandler.recoveryStrategies.get(errorCode).push(strategy);
376
+ }
377
+ static enableGracefulDegradation(enabled = true) {
378
+ SystemErrorHandler.gracefulDegradationEnabled = enabled;
379
+ }
380
+ static setOfflineMode(offline = true) {
381
+ SystemErrorHandler.offlineMode = offline;
382
+ if (offline) {
383
+ console.log(chalk.cyan('๐Ÿ”Œ Offline mode enabled - AI features disabled'));
384
+ }
385
+ }
386
+ static isOfflineMode() {
387
+ return SystemErrorHandler.offlineMode || process.env.BASEGUARD_OFFLINE === 'true';
388
+ }
389
+ static clearErrorLog() {
390
+ SystemErrorHandler.errorLog = [];
391
+ }
392
+ static async createCorruptionRecovery(configPath) {
393
+ try {
394
+ // Backup corrupted config
395
+ const backupPath = `${configPath}.backup.${Date.now()}`;
396
+ await fs.copyFile(configPath, backupPath);
397
+ console.log(chalk.yellow(`Corrupted config backed up to: ${backupPath}`));
398
+ // Create minimal working config
399
+ const minimalConfig = {
400
+ version: '1.0.0',
401
+ targets: [{ browser: 'chrome', minVersion: 'baseline' }],
402
+ apiKeys: { jules: null, gemini: null },
403
+ automation: { enabled: false }
404
+ };
405
+ await fs.writeFile(configPath, JSON.stringify(minimalConfig, null, 2));
406
+ console.log(chalk.green('โœ… Created minimal working configuration'));
407
+ return true;
408
+ }
409
+ catch (error) {
410
+ console.error(chalk.red('Failed to recover from configuration corruption'));
411
+ return false;
412
+ }
413
+ }
414
+ static async handleProcessSignals() {
415
+ const gracefulShutdown = async (signal) => {
416
+ console.log(chalk.yellow(`\nโš ๏ธ Received ${signal}, shutting down gracefully...`));
417
+ // Save error log before exit
418
+ try {
419
+ await SystemErrorHandler.saveErrorLog();
420
+ }
421
+ catch (error) {
422
+ // Ignore errors during shutdown
423
+ }
424
+ // Show error summary if there were issues
425
+ const summary = SystemErrorHandler.getErrorSummary();
426
+ if (summary.total > 0) {
427
+ console.log(chalk.cyan(`\n๐Ÿ“Š Session summary: ${summary.total} errors encountered`));
428
+ if (summary.critical > 0) {
429
+ console.log(chalk.red(` ${summary.critical} critical errors require attention`));
430
+ }
431
+ }
432
+ process.exit(0);
433
+ };
434
+ process.on('SIGINT', () => gracefulShutdown('SIGINT'));
435
+ process.on('SIGTERM', () => gracefulShutdown('SIGTERM'));
436
+ // Handle uncaught exceptions
437
+ process.on('uncaughtException', (error) => {
438
+ const systemError = SystemErrorHandler.wrapError(error, {
439
+ operation: 'uncaught-exception',
440
+ details: { stack: error.stack }
441
+ });
442
+ SystemErrorHandler.displayError(systemError, { verbose: true });
443
+ SystemErrorHandler.saveErrorLog().finally(() => {
444
+ process.exit(1);
445
+ });
446
+ });
447
+ // Handle unhandled promise rejections
448
+ process.on('unhandledRejection', (reason, promise) => {
449
+ const systemError = SystemErrorHandler.wrapError(reason, {
450
+ operation: 'unhandled-rejection',
451
+ details: { promise: promise.toString() }
452
+ });
453
+ SystemErrorHandler.displayError(systemError, { verbose: true });
454
+ SystemErrorHandler.saveErrorLog().finally(() => {
455
+ process.exit(1);
456
+ });
457
+ });
458
+ }
459
+ static sleep(ms) {
460
+ return new Promise(resolve => setTimeout(resolve, ms));
461
+ }
462
+ // Initialize default recovery strategies
463
+ static initializeRecoveryStrategies() {
464
+ // File not found recovery
465
+ SystemErrorHandler.registerRecoveryStrategy('FILE_NOT_FOUND', {
466
+ name: 'Create missing directories',
467
+ description: 'Create missing parent directories',
468
+ priority: 3,
469
+ execute: async () => {
470
+ try {
471
+ // Try to create parent directories for common paths
472
+ const commonPaths = ['src', 'app', 'components', 'pages', '.baseguard'];
473
+ for (const dirPath of commonPaths) {
474
+ try {
475
+ await fs.mkdir(dirPath, { recursive: true });
476
+ }
477
+ catch (error) {
478
+ // Ignore if directory already exists
479
+ }
480
+ }
481
+ return true;
482
+ }
483
+ catch (error) {
484
+ return false;
485
+ }
486
+ }
487
+ });
488
+ // Network error recovery
489
+ SystemErrorHandler.registerRecoveryStrategy('NETWORK_ERROR', {
490
+ name: 'Switch to offline mode',
491
+ description: 'Continue with offline-only features',
492
+ priority: 2,
493
+ execute: async () => {
494
+ console.log(chalk.cyan('๐Ÿ”Œ Switching to offline mode...'));
495
+ SystemErrorHandler.setOfflineMode(true);
496
+ process.env.BASEGUARD_OFFLINE = 'true';
497
+ return true;
498
+ }
499
+ });
500
+ // API error recovery
501
+ SystemErrorHandler.registerRecoveryStrategy('API_ERROR', {
502
+ name: 'Use cached responses',
503
+ description: 'Fall back to cached API responses',
504
+ priority: 1,
505
+ execute: async () => {
506
+ try {
507
+ // Check if cache directory exists and has content
508
+ const cacheDir = path.join(process.cwd(), '.baseguard', 'cache');
509
+ const cacheExists = await fs.access(cacheDir).then(() => true).catch(() => false);
510
+ if (cacheExists) {
511
+ const files = await fs.readdir(cacheDir);
512
+ if (files.length > 0) {
513
+ console.log(chalk.cyan('๐Ÿ“ฆ Using cached API responses'));
514
+ return true;
515
+ }
516
+ }
517
+ // Enable offline mode as fallback
518
+ SystemErrorHandler.setOfflineMode(true);
519
+ return true;
520
+ }
521
+ catch (error) {
522
+ return false;
523
+ }
524
+ }
525
+ });
526
+ // Syntax error recovery
527
+ SystemErrorHandler.registerRecoveryStrategy('SYNTAX_ERROR', {
528
+ name: 'Skip malformed file',
529
+ description: 'Skip the file with syntax errors and continue',
530
+ priority: 1,
531
+ execute: async () => {
532
+ console.log(chalk.cyan('โญ๏ธ Skipping malformed file and continuing...'));
533
+ return true;
534
+ }
535
+ });
536
+ // Configuration error recovery
537
+ SystemErrorHandler.registerRecoveryStrategy('CONFIGURATION_ERROR', {
538
+ name: 'Create minimal config',
539
+ description: 'Create a minimal working configuration',
540
+ priority: 2,
541
+ execute: async () => {
542
+ const configPath = path.join(process.cwd(), '.baseguardrc.json');
543
+ return await SystemErrorHandler.createCorruptionRecovery(configPath);
544
+ }
545
+ });
546
+ // Parser error recovery
547
+ SystemErrorHandler.registerRecoveryStrategy('PARSER_ERROR', {
548
+ name: 'Use fallback parser',
549
+ description: 'Try with a simpler parsing strategy',
550
+ priority: 1,
551
+ execute: async () => {
552
+ console.log(chalk.cyan('๐Ÿ”„ Using fallback parser strategy...'));
553
+ return true;
554
+ }
555
+ });
556
+ // Memory error recovery
557
+ SystemErrorHandler.registerRecoveryStrategy('OUT_OF_MEMORY', {
558
+ name: 'Reduce processing batch size',
559
+ description: 'Process files in smaller batches to reduce memory usage',
560
+ priority: 3,
561
+ execute: async () => {
562
+ console.log(chalk.cyan('๐Ÿง  Reducing memory usage by processing smaller batches...'));
563
+ process.env.BASEGUARD_BATCH_SIZE = '10'; // Reduce from default
564
+ return true;
565
+ }
566
+ });
567
+ // Too many files recovery
568
+ SystemErrorHandler.registerRecoveryStrategy('TOO_MANY_FILES', {
569
+ name: 'Limit file processing',
570
+ description: 'Reduce the number of files processed simultaneously',
571
+ priority: 2,
572
+ execute: async () => {
573
+ console.log(chalk.cyan('๐Ÿ“ Limiting concurrent file processing...'));
574
+ process.env.BASEGUARD_MAX_FILES = '100'; // Reduce from default
575
+ return true;
576
+ }
577
+ });
578
+ // Timeout error recovery
579
+ SystemErrorHandler.registerRecoveryStrategy('TIMEOUT_ERROR', {
580
+ name: 'Increase timeout and retry',
581
+ description: 'Increase timeout settings and retry the operation',
582
+ priority: 2,
583
+ execute: async () => {
584
+ console.log(chalk.cyan('โฑ๏ธ Increasing timeout settings...'));
585
+ process.env.BASEGUARD_TIMEOUT = '60000'; // 60 seconds
586
+ return true;
587
+ }
588
+ });
589
+ // Permission denied recovery
590
+ SystemErrorHandler.registerRecoveryStrategy('PERMISSION_DENIED', {
591
+ name: 'Skip protected files',
592
+ description: 'Skip files that cannot be accessed and continue',
593
+ priority: 1,
594
+ execute: async () => {
595
+ console.log(chalk.cyan('๐Ÿ”’ Skipping protected files and continuing...'));
596
+ return true;
597
+ }
598
+ });
599
+ // Disk full recovery
600
+ SystemErrorHandler.registerRecoveryStrategy('DISK_FULL', {
601
+ name: 'Clean temporary files',
602
+ description: 'Clean up temporary files to free space',
603
+ priority: 3,
604
+ execute: async () => {
605
+ try {
606
+ console.log(chalk.cyan('๐Ÿงน Cleaning temporary files...'));
607
+ // Clean BaseGuard temp files
608
+ const tempDir = path.join(process.cwd(), '.baseguard', 'temp');
609
+ try {
610
+ await fs.rm(tempDir, { recursive: true, force: true });
611
+ await fs.mkdir(tempDir, { recursive: true });
612
+ }
613
+ catch (error) {
614
+ // Ignore if temp dir doesn't exist
615
+ }
616
+ // Clean system temp files (be careful here)
617
+ const systemTemp = process.env.TMPDIR || process.env.TEMP || '/tmp';
618
+ const baseguardTempPattern = path.join(systemTemp, 'baseguard-*');
619
+ try {
620
+ const { glob } = await import('glob');
621
+ const tempFiles = await glob(baseguardTempPattern);
622
+ for (const file of tempFiles) {
623
+ try {
624
+ await fs.rm(file, { recursive: true, force: true });
625
+ }
626
+ catch (error) {
627
+ // Ignore individual file errors
628
+ }
629
+ }
630
+ }
631
+ catch (error) {
632
+ // Ignore if glob fails
633
+ }
634
+ return true;
635
+ }
636
+ catch (error) {
637
+ return false;
638
+ }
639
+ }
640
+ });
641
+ }
642
+ }
643
+ // Initialize recovery strategies and signal handlers when module loads
644
+ SystemErrorHandler.initializeRecoveryStrategies();
645
+ SystemErrorHandler.handleProcessSignals();
646
+ //# sourceMappingURL=system-error-handler.js.map