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,590 @@
|
|
|
1
|
+
import { promises as fs } from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import chalk from 'chalk';
|
|
4
|
+
import { SystemError } from './system-error-handler.js';
|
|
5
|
+
|
|
6
|
+
export enum LogLevel {
|
|
7
|
+
ERROR = 0,
|
|
8
|
+
WARN = 1,
|
|
9
|
+
INFO = 2,
|
|
10
|
+
DEBUG = 3,
|
|
11
|
+
TRACE = 4
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface LogEntry {
|
|
15
|
+
timestamp: Date;
|
|
16
|
+
level: LogLevel;
|
|
17
|
+
category: string;
|
|
18
|
+
message: string;
|
|
19
|
+
context?: any;
|
|
20
|
+
error?: Error;
|
|
21
|
+
performance?: {
|
|
22
|
+
duration?: number;
|
|
23
|
+
memory?: number;
|
|
24
|
+
cpu?: number;
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface DebugSession {
|
|
29
|
+
id: string;
|
|
30
|
+
startTime: Date;
|
|
31
|
+
endTime?: Date;
|
|
32
|
+
entries: LogEntry[];
|
|
33
|
+
summary: {
|
|
34
|
+
errors: number;
|
|
35
|
+
warnings: number;
|
|
36
|
+
performance: {
|
|
37
|
+
totalDuration: number;
|
|
38
|
+
peakMemory: number;
|
|
39
|
+
operations: number;
|
|
40
|
+
};
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Enhanced logging and debugging system for BaseGuard
|
|
46
|
+
*/
|
|
47
|
+
export class DebugLogger {
|
|
48
|
+
private static instance: DebugLogger | null = null;
|
|
49
|
+
private logLevel: LogLevel = LogLevel.INFO;
|
|
50
|
+
private logDir: string;
|
|
51
|
+
private currentSession: DebugSession | null = null;
|
|
52
|
+
private logBuffer: LogEntry[] = [];
|
|
53
|
+
private maxBufferSize = 1000;
|
|
54
|
+
private flushInterval: NodeJS.Timeout | null = null;
|
|
55
|
+
private performanceMarks = new Map<string, number>();
|
|
56
|
+
|
|
57
|
+
constructor() {
|
|
58
|
+
this.logDir = path.join(process.cwd(), '.baseguard', 'logs');
|
|
59
|
+
this.initializeLogging();
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Get singleton instance
|
|
64
|
+
*/
|
|
65
|
+
static getInstance(): DebugLogger {
|
|
66
|
+
if (!DebugLogger.instance) {
|
|
67
|
+
DebugLogger.instance = new DebugLogger();
|
|
68
|
+
}
|
|
69
|
+
return DebugLogger.instance;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Initialize logging system
|
|
74
|
+
*/
|
|
75
|
+
private async initializeLogging(): Promise<void> {
|
|
76
|
+
try {
|
|
77
|
+
await fs.mkdir(this.logDir, { recursive: true });
|
|
78
|
+
|
|
79
|
+
// Set log level from environment
|
|
80
|
+
const envLevel = process.env.BASEGUARD_LOG_LEVEL?.toUpperCase();
|
|
81
|
+
if (envLevel && envLevel in LogLevel) {
|
|
82
|
+
this.logLevel = LogLevel[envLevel as keyof typeof LogLevel];
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Start auto-flush
|
|
86
|
+
this.flushInterval = setInterval(() => {
|
|
87
|
+
this.flushLogs();
|
|
88
|
+
}, 5000); // Flush every 5 seconds
|
|
89
|
+
|
|
90
|
+
// Handle process exit
|
|
91
|
+
process.on('exit', () => this.cleanup());
|
|
92
|
+
process.on('SIGINT', () => this.cleanup());
|
|
93
|
+
process.on('SIGTERM', () => this.cleanup());
|
|
94
|
+
} catch (error) {
|
|
95
|
+
console.warn('Failed to initialize debug logging:', error);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Start a new debug session
|
|
101
|
+
*/
|
|
102
|
+
startSession(sessionId?: string): string {
|
|
103
|
+
const id = sessionId || `session-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
104
|
+
|
|
105
|
+
this.currentSession = {
|
|
106
|
+
id,
|
|
107
|
+
startTime: new Date(),
|
|
108
|
+
entries: [],
|
|
109
|
+
summary: {
|
|
110
|
+
errors: 0,
|
|
111
|
+
warnings: 0,
|
|
112
|
+
performance: {
|
|
113
|
+
totalDuration: 0,
|
|
114
|
+
peakMemory: 0,
|
|
115
|
+
operations: 0
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
this.info('session', `Debug session started: ${id}`);
|
|
121
|
+
return id;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* End current debug session
|
|
126
|
+
*/
|
|
127
|
+
async endSession(): Promise<DebugSession | null> {
|
|
128
|
+
if (!this.currentSession) {
|
|
129
|
+
return null;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
this.currentSession.endTime = new Date();
|
|
133
|
+
this.currentSession.summary.totalDuration =
|
|
134
|
+
this.currentSession.endTime.getTime() - this.currentSession.startTime.getTime();
|
|
135
|
+
|
|
136
|
+
this.info('session', `Debug session ended: ${this.currentSession.id}`);
|
|
137
|
+
|
|
138
|
+
// Save session to file
|
|
139
|
+
await this.saveSession(this.currentSession);
|
|
140
|
+
|
|
141
|
+
const session = this.currentSession;
|
|
142
|
+
this.currentSession = null;
|
|
143
|
+
|
|
144
|
+
return session;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Log error message
|
|
149
|
+
*/
|
|
150
|
+
error(category: string, message: string, context?: any, error?: Error): void {
|
|
151
|
+
this.log(LogLevel.ERROR, category, message, context, error);
|
|
152
|
+
|
|
153
|
+
if (this.currentSession) {
|
|
154
|
+
this.currentSession.summary.errors++;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Log warning message
|
|
160
|
+
*/
|
|
161
|
+
warn(category: string, message: string, context?: any): void {
|
|
162
|
+
this.log(LogLevel.WARN, category, message, context);
|
|
163
|
+
|
|
164
|
+
if (this.currentSession) {
|
|
165
|
+
this.currentSession.summary.warnings++;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Log info message
|
|
171
|
+
*/
|
|
172
|
+
info(category: string, message: string, context?: any): void {
|
|
173
|
+
this.log(LogLevel.INFO, category, message, context);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Log debug message
|
|
178
|
+
*/
|
|
179
|
+
debug(category: string, message: string, context?: any): void {
|
|
180
|
+
this.log(LogLevel.DEBUG, category, message, context);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Log trace message
|
|
185
|
+
*/
|
|
186
|
+
trace(category: string, message: string, context?: any): void {
|
|
187
|
+
this.log(LogLevel.TRACE, category, message, context);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Start performance measurement
|
|
192
|
+
*/
|
|
193
|
+
startPerformance(operation: string): void {
|
|
194
|
+
this.performanceMarks.set(operation, Date.now());
|
|
195
|
+
this.trace('performance', `Started: ${operation}`);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* End performance measurement
|
|
200
|
+
*/
|
|
201
|
+
endPerformance(operation: string, context?: any): number {
|
|
202
|
+
const startTime = this.performanceMarks.get(operation);
|
|
203
|
+
if (!startTime) {
|
|
204
|
+
this.warn('performance', `No start mark found for operation: ${operation}`);
|
|
205
|
+
return 0;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
const duration = Date.now() - startTime;
|
|
209
|
+
this.performanceMarks.delete(operation);
|
|
210
|
+
|
|
211
|
+
const memoryUsage = process.memoryUsage();
|
|
212
|
+
const performance = {
|
|
213
|
+
duration,
|
|
214
|
+
memory: memoryUsage.heapUsed,
|
|
215
|
+
cpu: process.cpuUsage().user
|
|
216
|
+
};
|
|
217
|
+
|
|
218
|
+
this.info('performance', `Completed: ${operation} (${duration}ms)`, {
|
|
219
|
+
...context,
|
|
220
|
+
performance
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
if (this.currentSession) {
|
|
224
|
+
this.currentSession.summary.performance.operations++;
|
|
225
|
+
this.currentSession.summary.performance.peakMemory = Math.max(
|
|
226
|
+
this.currentSession.summary.performance.peakMemory,
|
|
227
|
+
memoryUsage.heapUsed
|
|
228
|
+
);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
return duration;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* Log system error with enhanced context
|
|
236
|
+
*/
|
|
237
|
+
logSystemError(error: SystemError): void {
|
|
238
|
+
this.error('system', error.message, {
|
|
239
|
+
code: error.code,
|
|
240
|
+
severity: error.severity,
|
|
241
|
+
recoverable: error.recoverable,
|
|
242
|
+
context: error.context,
|
|
243
|
+
stack: error.stack
|
|
244
|
+
}, error);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* Log API operation
|
|
249
|
+
*/
|
|
250
|
+
logApiOperation(service: string, operation: string, success: boolean, duration: number, context?: any): void {
|
|
251
|
+
const level = success ? LogLevel.INFO : LogLevel.ERROR;
|
|
252
|
+
const message = `${service}.${operation}: ${success ? 'SUCCESS' : 'FAILED'} (${duration}ms)`;
|
|
253
|
+
|
|
254
|
+
this.log(level, 'api', message, {
|
|
255
|
+
service,
|
|
256
|
+
operation,
|
|
257
|
+
success,
|
|
258
|
+
duration,
|
|
259
|
+
...context
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* Log file processing operation
|
|
265
|
+
*/
|
|
266
|
+
logFileProcessing(file: string, operation: string, success: boolean, duration?: number, context?: any): void {
|
|
267
|
+
const level = success ? LogLevel.DEBUG : LogLevel.WARN;
|
|
268
|
+
const message = `${operation}: ${file} ${success ? 'SUCCESS' : 'FAILED'}${duration ? ` (${duration}ms)` : ''}`;
|
|
269
|
+
|
|
270
|
+
this.log(level, 'file', message, {
|
|
271
|
+
file,
|
|
272
|
+
operation,
|
|
273
|
+
success,
|
|
274
|
+
duration,
|
|
275
|
+
...context
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
* Core logging method
|
|
281
|
+
*/
|
|
282
|
+
private log(level: LogLevel, category: string, message: string, context?: any, error?: Error): void {
|
|
283
|
+
if (level > this.logLevel) {
|
|
284
|
+
return;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
const entry: LogEntry = {
|
|
288
|
+
timestamp: new Date(),
|
|
289
|
+
level,
|
|
290
|
+
category,
|
|
291
|
+
message,
|
|
292
|
+
context,
|
|
293
|
+
error
|
|
294
|
+
};
|
|
295
|
+
|
|
296
|
+
// Add to buffer
|
|
297
|
+
this.logBuffer.push(entry);
|
|
298
|
+
|
|
299
|
+
// Add to current session
|
|
300
|
+
if (this.currentSession) {
|
|
301
|
+
this.currentSession.entries.push(entry);
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
// Console output for important messages
|
|
305
|
+
if (level <= LogLevel.WARN || (level === LogLevel.INFO && process.env.BASEGUARD_VERBOSE === 'true')) {
|
|
306
|
+
this.outputToConsole(entry);
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
// Flush if buffer is full
|
|
310
|
+
if (this.logBuffer.length >= this.maxBufferSize) {
|
|
311
|
+
this.flushLogs();
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
/**
|
|
316
|
+
* Output log entry to console
|
|
317
|
+
*/
|
|
318
|
+
private outputToConsole(entry: LogEntry): void {
|
|
319
|
+
const timestamp = entry.timestamp.toISOString();
|
|
320
|
+
const levelName = LogLevel[entry.level];
|
|
321
|
+
|
|
322
|
+
let color = chalk.white;
|
|
323
|
+
let icon = '';
|
|
324
|
+
|
|
325
|
+
switch (entry.level) {
|
|
326
|
+
case LogLevel.ERROR:
|
|
327
|
+
color = chalk.red;
|
|
328
|
+
icon = '❌';
|
|
329
|
+
break;
|
|
330
|
+
case LogLevel.WARN:
|
|
331
|
+
color = chalk.yellow;
|
|
332
|
+
icon = '⚠️';
|
|
333
|
+
break;
|
|
334
|
+
case LogLevel.INFO:
|
|
335
|
+
color = chalk.cyan;
|
|
336
|
+
icon = 'ℹ️';
|
|
337
|
+
break;
|
|
338
|
+
case LogLevel.DEBUG:
|
|
339
|
+
color = chalk.dim;
|
|
340
|
+
icon = '🔍';
|
|
341
|
+
break;
|
|
342
|
+
case LogLevel.TRACE:
|
|
343
|
+
color = chalk.dim;
|
|
344
|
+
icon = '📍';
|
|
345
|
+
break;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
const prefix = `${icon} [${levelName}] ${entry.category}:`;
|
|
349
|
+
console.log(color(`${prefix} ${entry.message}`));
|
|
350
|
+
|
|
351
|
+
if (entry.context && process.env.BASEGUARD_DEBUG === 'true') {
|
|
352
|
+
console.log(chalk.dim(` Context: ${JSON.stringify(entry.context, null, 2)}`));
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
if (entry.error && entry.level <= LogLevel.WARN) {
|
|
356
|
+
console.log(chalk.dim(` Error: ${entry.error.stack || entry.error.message}`));
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
/**
|
|
361
|
+
* Flush log buffer to file
|
|
362
|
+
*/
|
|
363
|
+
private async flushLogs(): Promise<void> {
|
|
364
|
+
if (this.logBuffer.length === 0) {
|
|
365
|
+
return;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
try {
|
|
369
|
+
const logFile = path.join(this.logDir, `baseguard-${new Date().toISOString().split('T')[0]}.log`);
|
|
370
|
+
const logLines = this.logBuffer.map(entry => this.formatLogEntry(entry));
|
|
371
|
+
|
|
372
|
+
await fs.appendFile(logFile, logLines.join('\n') + '\n');
|
|
373
|
+
this.logBuffer = [];
|
|
374
|
+
} catch (error) {
|
|
375
|
+
console.warn('Failed to flush logs:', error);
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
/**
|
|
380
|
+
* Format log entry for file output
|
|
381
|
+
*/
|
|
382
|
+
private formatLogEntry(entry: LogEntry): string {
|
|
383
|
+
const timestamp = entry.timestamp.toISOString();
|
|
384
|
+
const level = LogLevel[entry.level].padEnd(5);
|
|
385
|
+
const category = entry.category.padEnd(12);
|
|
386
|
+
|
|
387
|
+
let line = `${timestamp} [${level}] ${category} ${entry.message}`;
|
|
388
|
+
|
|
389
|
+
if (entry.context) {
|
|
390
|
+
line += ` | Context: ${JSON.stringify(entry.context)}`;
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
if (entry.error) {
|
|
394
|
+
line += ` | Error: ${entry.error.message}`;
|
|
395
|
+
if (entry.error.stack) {
|
|
396
|
+
line += ` | Stack: ${entry.error.stack.replace(/\n/g, '\\n')}`;
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
return line;
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
/**
|
|
404
|
+
* Save debug session to file
|
|
405
|
+
*/
|
|
406
|
+
private async saveSession(session: DebugSession): Promise<void> {
|
|
407
|
+
try {
|
|
408
|
+
const sessionFile = path.join(this.logDir, `session-${session.id}.json`);
|
|
409
|
+
await fs.writeFile(sessionFile, JSON.stringify(session, null, 2));
|
|
410
|
+
} catch (error) {
|
|
411
|
+
console.warn('Failed to save debug session:', error);
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
/**
|
|
416
|
+
* Get recent log entries
|
|
417
|
+
*/
|
|
418
|
+
getRecentLogs(count: number = 100): LogEntry[] {
|
|
419
|
+
const allEntries = [
|
|
420
|
+
...this.logBuffer,
|
|
421
|
+
...(this.currentSession?.entries || [])
|
|
422
|
+
];
|
|
423
|
+
|
|
424
|
+
return allEntries
|
|
425
|
+
.sort((a, b) => b.timestamp.getTime() - a.timestamp.getTime())
|
|
426
|
+
.slice(0, count);
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
/**
|
|
430
|
+
* Get logs by category
|
|
431
|
+
*/
|
|
432
|
+
getLogsByCategory(category: string, count: number = 50): LogEntry[] {
|
|
433
|
+
return this.getRecentLogs(count * 2)
|
|
434
|
+
.filter(entry => entry.category === category)
|
|
435
|
+
.slice(0, count);
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
/**
|
|
439
|
+
* Get error summary
|
|
440
|
+
*/
|
|
441
|
+
getErrorSummary(): {
|
|
442
|
+
totalErrors: number;
|
|
443
|
+
totalWarnings: number;
|
|
444
|
+
errorsByCategory: Record<string, number>;
|
|
445
|
+
recentErrors: LogEntry[];
|
|
446
|
+
} {
|
|
447
|
+
const recentLogs = this.getRecentLogs(500);
|
|
448
|
+
const errors = recentLogs.filter(entry => entry.level === LogLevel.ERROR);
|
|
449
|
+
const warnings = recentLogs.filter(entry => entry.level === LogLevel.WARN);
|
|
450
|
+
|
|
451
|
+
const errorsByCategory: Record<string, number> = {};
|
|
452
|
+
errors.forEach(entry => {
|
|
453
|
+
errorsByCategory[entry.category] = (errorsByCategory[entry.category] || 0) + 1;
|
|
454
|
+
});
|
|
455
|
+
|
|
456
|
+
return {
|
|
457
|
+
totalErrors: errors.length,
|
|
458
|
+
totalWarnings: warnings.length,
|
|
459
|
+
errorsByCategory,
|
|
460
|
+
recentErrors: errors.slice(0, 10)
|
|
461
|
+
};
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
/**
|
|
465
|
+
* Generate debug report
|
|
466
|
+
*/
|
|
467
|
+
async generateDebugReport(): Promise<string> {
|
|
468
|
+
const summary = this.getErrorSummary();
|
|
469
|
+
const memoryUsage = process.memoryUsage();
|
|
470
|
+
const uptime = process.uptime();
|
|
471
|
+
|
|
472
|
+
const report = {
|
|
473
|
+
timestamp: new Date().toISOString(),
|
|
474
|
+
version: process.env.npm_package_version || 'unknown',
|
|
475
|
+
platform: {
|
|
476
|
+
os: process.platform,
|
|
477
|
+
arch: process.arch,
|
|
478
|
+
node: process.version
|
|
479
|
+
},
|
|
480
|
+
runtime: {
|
|
481
|
+
uptime: Math.round(uptime),
|
|
482
|
+
memory: {
|
|
483
|
+
heapUsed: Math.round(memoryUsage.heapUsed / 1024 / 1024),
|
|
484
|
+
heapTotal: Math.round(memoryUsage.heapTotal / 1024 / 1024),
|
|
485
|
+
external: Math.round(memoryUsage.external / 1024 / 1024)
|
|
486
|
+
}
|
|
487
|
+
},
|
|
488
|
+
session: this.currentSession ? {
|
|
489
|
+
id: this.currentSession.id,
|
|
490
|
+
duration: Date.now() - this.currentSession.startTime.getTime(),
|
|
491
|
+
entries: this.currentSession.entries.length,
|
|
492
|
+
summary: this.currentSession.summary
|
|
493
|
+
} : null,
|
|
494
|
+
errors: summary,
|
|
495
|
+
recentLogs: this.getRecentLogs(20)
|
|
496
|
+
};
|
|
497
|
+
|
|
498
|
+
const reportFile = path.join(this.logDir, `debug-report-${Date.now()}.json`);
|
|
499
|
+
await fs.writeFile(reportFile, JSON.stringify(report, null, 2));
|
|
500
|
+
|
|
501
|
+
return reportFile;
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
/**
|
|
505
|
+
* Set log level
|
|
506
|
+
*/
|
|
507
|
+
setLogLevel(level: LogLevel): void {
|
|
508
|
+
this.logLevel = level;
|
|
509
|
+
this.info('logger', `Log level set to ${LogLevel[level]}`);
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
/**
|
|
513
|
+
* Enable verbose logging
|
|
514
|
+
*/
|
|
515
|
+
enableVerbose(): void {
|
|
516
|
+
this.setLogLevel(LogLevel.DEBUG);
|
|
517
|
+
process.env.BASEGUARD_VERBOSE = 'true';
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
/**
|
|
521
|
+
* Enable debug mode
|
|
522
|
+
*/
|
|
523
|
+
enableDebug(): void {
|
|
524
|
+
this.setLogLevel(LogLevel.TRACE);
|
|
525
|
+
process.env.BASEGUARD_DEBUG = 'true';
|
|
526
|
+
process.env.BASEGUARD_VERBOSE = 'true';
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
/**
|
|
530
|
+
* Clean up old log files
|
|
531
|
+
*/
|
|
532
|
+
async cleanupOldLogs(maxAgeDays: number = 7): Promise<void> {
|
|
533
|
+
try {
|
|
534
|
+
const files = await fs.readdir(this.logDir);
|
|
535
|
+
const now = Date.now();
|
|
536
|
+
const maxAge = maxAgeDays * 24 * 60 * 60 * 1000;
|
|
537
|
+
|
|
538
|
+
for (const file of files) {
|
|
539
|
+
const filePath = path.join(this.logDir, file);
|
|
540
|
+
const stats = await fs.stat(filePath);
|
|
541
|
+
|
|
542
|
+
if (now - stats.mtime.getTime() > maxAge) {
|
|
543
|
+
await fs.unlink(filePath);
|
|
544
|
+
this.debug('cleanup', `Removed old log file: ${file}`);
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
} catch (error) {
|
|
548
|
+
this.warn('cleanup', 'Failed to cleanup old logs', { error: error instanceof Error ? error.message : 'Unknown error' });
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
/**
|
|
553
|
+
* Cleanup resources
|
|
554
|
+
*/
|
|
555
|
+
private cleanup(): void {
|
|
556
|
+
if (this.flushInterval) {
|
|
557
|
+
clearInterval(this.flushInterval);
|
|
558
|
+
this.flushInterval = null;
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
// Final flush
|
|
562
|
+
this.flushLogs().catch(() => {
|
|
563
|
+
// Ignore errors during cleanup
|
|
564
|
+
});
|
|
565
|
+
|
|
566
|
+
if (this.currentSession) {
|
|
567
|
+
this.endSession().catch(() => {
|
|
568
|
+
// Ignore errors during cleanup
|
|
569
|
+
});
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
/**
|
|
574
|
+
* Create logger for specific category
|
|
575
|
+
*/
|
|
576
|
+
createCategoryLogger(category: string) {
|
|
577
|
+
return {
|
|
578
|
+
error: (message: string, context?: any, error?: Error) => this.error(category, message, context, error),
|
|
579
|
+
warn: (message: string, context?: any) => this.warn(category, message, context),
|
|
580
|
+
info: (message: string, context?: any) => this.info(category, message, context),
|
|
581
|
+
debug: (message: string, context?: any) => this.debug(category, message, context),
|
|
582
|
+
trace: (message: string, context?: any) => this.trace(category, message, context),
|
|
583
|
+
startPerformance: (operation: string) => this.startPerformance(`${category}.${operation}`),
|
|
584
|
+
endPerformance: (operation: string, context?: any) => this.endPerformance(`${category}.${operation}`, context)
|
|
585
|
+
};
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
// Export singleton instance
|
|
590
|
+
export const logger = DebugLogger.getInstance();
|