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