mcp-code-context 3.0.6 → 3.4.1
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/CHANGELOG.md +84 -1
- package/CHANGELOG_v3.2.0.md +196 -0
- package/CHANGELOG_v3.3.0.md +266 -0
- package/README.md +1 -1
- package/SECURITY.md +177 -0
- package/dist/src/core/engine.d.ts +2 -2
- package/dist/src/core/engine.js +24 -8
- package/dist/src/core/engine.js.map +1 -1
- package/dist/src/core/validator.d.ts +2 -2
- package/dist/src/core/validator.js +8 -7
- package/dist/src/core/validator.js.map +1 -1
- package/dist/src/index.d.ts +6 -6
- package/dist/src/index.js +499 -158
- package/dist/src/index.js.map +1 -1
- package/dist/src/operations/compress.d.ts +18 -0
- package/dist/src/operations/compress.js +89 -0
- package/dist/src/operations/compress.js.map +1 -0
- package/dist/src/operations/confirmationStore.d.ts +53 -0
- package/dist/src/operations/confirmationStore.js +91 -0
- package/dist/src/operations/confirmationStore.js.map +1 -0
- package/dist/src/operations/read.d.ts +50 -0
- package/dist/src/operations/read.js +228 -0
- package/dist/src/operations/read.js.map +1 -0
- package/dist/src/operations/write.d.ts +16 -4
- package/dist/src/operations/write.js +142 -48
- package/dist/src/operations/write.js.map +1 -1
- package/dist/src/parsers/base.d.ts +7 -2
- package/dist/src/parsers/base.js +18 -1
- package/dist/src/parsers/base.js.map +1 -1
- package/dist/src/parsers/dartTreeSitter.d.ts +3 -3
- package/dist/src/parsers/dartTreeSitter.js +6 -11
- package/dist/src/parsers/dartTreeSitter.js.map +1 -1
- package/dist/src/parsers/php.d.ts +2 -2
- package/dist/src/parsers/php.js +5 -10
- package/dist/src/parsers/php.js.map +1 -1
- package/dist/src/parsers/python.d.ts +2 -2
- package/dist/src/parsers/python.js +5 -10
- package/dist/src/parsers/python.js.map +1 -1
- package/dist/src/parsers/registry.d.ts +1 -1
- package/dist/src/parsers/registry.js +2 -2
- package/dist/src/parsers/registry.js.map +1 -1
- package/dist/src/parsers/typescript.d.ts +2 -2
- package/dist/src/parsers/typescript.js +8 -13
- package/dist/src/parsers/typescript.js.map +1 -1
- package/dist/src/utils/auditLogger.d.ts +90 -0
- package/dist/src/utils/auditLogger.js +271 -0
- package/dist/src/utils/auditLogger.js.map +1 -0
- package/dist/src/utils/backupManager.d.ts +33 -0
- package/dist/src/utils/backupManager.js +130 -0
- package/dist/src/utils/backupManager.js.map +1 -0
- package/dist/src/utils/constants.d.ts +12 -0
- package/dist/src/utils/constants.js +33 -0
- package/dist/src/utils/constants.js.map +1 -0
- package/dist/src/utils/diff.d.ts +13 -0
- package/dist/src/utils/diff.js +124 -0
- package/dist/src/utils/diff.js.map +1 -0
- package/dist/src/utils/fileLock.d.ts +63 -0
- package/dist/src/utils/fileLock.js +123 -0
- package/dist/src/utils/fileLock.js.map +1 -0
- package/dist/src/utils/rateLimiter.d.ts +61 -0
- package/dist/src/utils/rateLimiter.js +114 -0
- package/dist/src/utils/rateLimiter.js.map +1 -0
- package/dist/src/utils/safeRegex.d.ts +41 -0
- package/dist/src/utils/safeRegex.js +137 -0
- package/dist/src/utils/safeRegex.js.map +1 -0
- package/dist/src/utils/streaming.d.ts +43 -0
- package/dist/src/utils/streaming.js +175 -0
- package/dist/src/utils/streaming.js.map +1 -0
- package/dist/src/utils/telemetry.d.ts +91 -0
- package/dist/src/utils/telemetry.js +185 -0
- package/dist/src/utils/telemetry.js.map +1 -0
- package/llms.txt +46 -28
- package/package.json +5 -5
- package/scripts/replace-version.js +59 -0
- package/mcp-code-context-3.0.2.tgz +0 -0
- package/tsconfig.tests.json +0 -27
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Parser Registry - v3.
|
|
2
|
+
* Parser Registry - v3.4.1
|
|
3
3
|
* Manages all language parsers
|
|
4
4
|
*/
|
|
5
5
|
import { TypeScriptParser } from "./typescript.js";
|
|
@@ -57,7 +57,7 @@ export class ParserRegistry {
|
|
|
57
57
|
const dartParser = new DartTreeSitterParser();
|
|
58
58
|
await dartParser.init(this.engine.createParser(), dartLang);
|
|
59
59
|
this.parsers.set("dart", dartParser);
|
|
60
|
-
console.
|
|
60
|
+
console.error("✅ Parsers loaded: TS/Python/PHP/Dart (WASM)");
|
|
61
61
|
}
|
|
62
62
|
getParser(fileExtension) {
|
|
63
63
|
const language = this.extensionMap.get(fileExtension);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../../../src/parsers/registry.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../../../src/parsers/registry.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* TypeScript Parser - v3.
|
|
2
|
+
* TypeScript Parser - v3.4.1
|
|
3
3
|
* Tree-sitter based TS/JS parser
|
|
4
|
+
* CLEANUP: replaceSymbol removed (inherited from BaseParser)
|
|
4
5
|
*/
|
|
5
6
|
import { Tree } from "web-tree-sitter";
|
|
6
7
|
import { BaseParser, SymbolInfo } from "./base.js";
|
|
7
8
|
export declare class TypeScriptParser extends BaseParser {
|
|
8
9
|
constructor();
|
|
9
10
|
extractSymbol(tree: Tree, symbolName: string, className?: string): string | null;
|
|
10
|
-
replaceSymbol(content: string, tree: Tree, symbolName: string, newContent: string, className?: string): string;
|
|
11
11
|
findSymbols(tree: Tree): SymbolInfo[];
|
|
12
12
|
private findParentClass;
|
|
13
13
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* TypeScript Parser - v3.
|
|
2
|
+
* TypeScript Parser - v3.4.1
|
|
3
3
|
* Tree-sitter based TS/JS parser
|
|
4
|
+
* CLEANUP: replaceSymbol removed (inherited from BaseParser)
|
|
4
5
|
*/
|
|
5
6
|
import { BaseParser } from "./base.js";
|
|
6
7
|
export class TypeScriptParser extends BaseParser {
|
|
@@ -15,7 +16,10 @@ export class TypeScriptParser extends BaseParser {
|
|
|
15
16
|
node.type === "class_declaration" ||
|
|
16
17
|
node.type === "interface_declaration" ||
|
|
17
18
|
node.type === "type_alias_declaration" ||
|
|
18
|
-
node.type === "method_definition"
|
|
19
|
+
node.type === "method_definition" ||
|
|
20
|
+
node.type === "lexical_declaration" ||
|
|
21
|
+
node.type === "variable_declaration" ||
|
|
22
|
+
node.type === "export_statement") {
|
|
19
23
|
const nameNode = node.childForFieldName("name");
|
|
20
24
|
if (nameNode && nameNode.text === symbolName) {
|
|
21
25
|
if (className) {
|
|
@@ -44,17 +48,6 @@ export class TypeScriptParser extends BaseParser {
|
|
|
44
48
|
};
|
|
45
49
|
return search();
|
|
46
50
|
}
|
|
47
|
-
replaceSymbol(content, tree, symbolName, newContent, className) {
|
|
48
|
-
const extracted = this.extractSymbol(tree, symbolName, className);
|
|
49
|
-
if (!extracted) {
|
|
50
|
-
throw new Error(`Symbol "${symbolName}" not found`);
|
|
51
|
-
}
|
|
52
|
-
const index = content.indexOf(extracted);
|
|
53
|
-
if (index === -1) {
|
|
54
|
-
throw new Error("Could not locate symbol in content");
|
|
55
|
-
}
|
|
56
|
-
return content.substring(0, index) + newContent + content.substring(index + extracted.length);
|
|
57
|
-
}
|
|
58
51
|
findSymbols(tree) {
|
|
59
52
|
const symbols = [];
|
|
60
53
|
const cursor = tree.walk();
|
|
@@ -67,11 +60,13 @@ export class TypeScriptParser extends BaseParser {
|
|
|
67
60
|
node.type === "method_definition") {
|
|
68
61
|
const nameNode = node.childForFieldName("name");
|
|
69
62
|
if (nameNode) {
|
|
63
|
+
const parentClass = this.findParentClass(node);
|
|
70
64
|
symbols.push({
|
|
71
65
|
name: nameNode.text,
|
|
72
66
|
type: node.type,
|
|
73
67
|
startIndex: node.startIndex,
|
|
74
68
|
endIndex: node.endIndex,
|
|
69
|
+
className: parentClass?.childForFieldName("name")?.text,
|
|
75
70
|
});
|
|
76
71
|
}
|
|
77
72
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"typescript.js","sourceRoot":"","sources":["../../../src/parsers/typescript.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"typescript.js","sourceRoot":"","sources":["../../../src/parsers/typescript.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Audit Logger - v3.4.1
|
|
3
|
+
* Comprehensive audit trail for all operations
|
|
4
|
+
*/
|
|
5
|
+
export interface AuditEntry {
|
|
6
|
+
timestamp: number;
|
|
7
|
+
level: "info" | "warn" | "error" | "security";
|
|
8
|
+
operation: string;
|
|
9
|
+
clientId?: string;
|
|
10
|
+
filePath?: string;
|
|
11
|
+
details: Record<string, any>;
|
|
12
|
+
result: "success" | "failure";
|
|
13
|
+
error?: string;
|
|
14
|
+
duration?: number;
|
|
15
|
+
}
|
|
16
|
+
export interface AuditLogConfig {
|
|
17
|
+
logDir: string;
|
|
18
|
+
maxFileSize: number;
|
|
19
|
+
maxFiles: number;
|
|
20
|
+
enableConsole: boolean;
|
|
21
|
+
enableFile: boolean;
|
|
22
|
+
}
|
|
23
|
+
export declare class AuditLogger {
|
|
24
|
+
private config;
|
|
25
|
+
private currentLogFile;
|
|
26
|
+
private currentLogSize;
|
|
27
|
+
private logBuffer;
|
|
28
|
+
private flushInterval;
|
|
29
|
+
private _ready;
|
|
30
|
+
constructor(config?: Partial<AuditLogConfig>);
|
|
31
|
+
/**
|
|
32
|
+
* Log an audit entry
|
|
33
|
+
*/
|
|
34
|
+
log(entry: Omit<AuditEntry, "timestamp">): Promise<void>;
|
|
35
|
+
/**
|
|
36
|
+
* Log security event
|
|
37
|
+
*/
|
|
38
|
+
logSecurity(operation: string, details: Record<string, any>, result: "success" | "failure", error?: string): Promise<void>;
|
|
39
|
+
/**
|
|
40
|
+
* Log write operation
|
|
41
|
+
*/
|
|
42
|
+
logWrite(operation: string, filePath: string, clientId: string, result: "success" | "failure", details?: Record<string, any>, error?: string): Promise<void>;
|
|
43
|
+
/**
|
|
44
|
+
* Log read operation
|
|
45
|
+
*/
|
|
46
|
+
logRead(operation: string, filePath: string, clientId: string, duration: number, result: "success" | "failure", error?: string): Promise<void>;
|
|
47
|
+
/**
|
|
48
|
+
* Flush buffer to file
|
|
49
|
+
*/
|
|
50
|
+
flush(): Promise<void>;
|
|
51
|
+
/**
|
|
52
|
+
* Query audit logs
|
|
53
|
+
*/
|
|
54
|
+
query(filters: {
|
|
55
|
+
startTime?: number;
|
|
56
|
+
endTime?: number;
|
|
57
|
+
level?: AuditEntry["level"];
|
|
58
|
+
operation?: string;
|
|
59
|
+
clientId?: string;
|
|
60
|
+
result?: "success" | "failure";
|
|
61
|
+
limit?: number;
|
|
62
|
+
}): Promise<AuditEntry[]>;
|
|
63
|
+
/**
|
|
64
|
+
* Get audit statistics
|
|
65
|
+
*/
|
|
66
|
+
getStats(timeRange?: {
|
|
67
|
+
start: number;
|
|
68
|
+
end: number;
|
|
69
|
+
}): Promise<{
|
|
70
|
+
totalEntries: number;
|
|
71
|
+
byLevel: Record<string, number>;
|
|
72
|
+
byOperation: Record<string, number>;
|
|
73
|
+
byResult: Record<string, number>;
|
|
74
|
+
securityEvents: number;
|
|
75
|
+
}>;
|
|
76
|
+
/**
|
|
77
|
+
* Stop logger and flush
|
|
78
|
+
*/
|
|
79
|
+
stop(): Promise<void>;
|
|
80
|
+
private initLogDir;
|
|
81
|
+
private ensureLogFile;
|
|
82
|
+
private rotateLog;
|
|
83
|
+
private getLogFiles;
|
|
84
|
+
private logToConsole;
|
|
85
|
+
private startFlushInterval;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Global audit logger instance
|
|
89
|
+
*/
|
|
90
|
+
export declare const globalAuditLogger: AuditLogger;
|
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Audit Logger - v3.4.1
|
|
3
|
+
* Comprehensive audit trail for all operations
|
|
4
|
+
*/
|
|
5
|
+
import * as fs from "node:fs/promises";
|
|
6
|
+
import * as path from "node:path";
|
|
7
|
+
export class AuditLogger {
|
|
8
|
+
config;
|
|
9
|
+
currentLogFile = null;
|
|
10
|
+
currentLogSize = 0;
|
|
11
|
+
logBuffer = [];
|
|
12
|
+
flushInterval = null;
|
|
13
|
+
_ready = Promise.resolve();
|
|
14
|
+
constructor(config = {}) {
|
|
15
|
+
this.config = {
|
|
16
|
+
logDir: config.logDir || "./.mcp-audit-logs",
|
|
17
|
+
maxFileSize: config.maxFileSize || 10 * 1024 * 1024, // 10MB
|
|
18
|
+
maxFiles: config.maxFiles || 10,
|
|
19
|
+
enableConsole: config.enableConsole ?? true,
|
|
20
|
+
enableFile: config.enableFile ?? true,
|
|
21
|
+
};
|
|
22
|
+
if (this.config.enableFile) {
|
|
23
|
+
// Properly await dir creation before any writes
|
|
24
|
+
this._ready = this.initLogDir();
|
|
25
|
+
this.startFlushInterval();
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Log an audit entry
|
|
30
|
+
*/
|
|
31
|
+
async log(entry) {
|
|
32
|
+
const fullEntry = {
|
|
33
|
+
...entry,
|
|
34
|
+
timestamp: Date.now(),
|
|
35
|
+
};
|
|
36
|
+
// Console output
|
|
37
|
+
if (this.config.enableConsole) {
|
|
38
|
+
this.logToConsole(fullEntry);
|
|
39
|
+
}
|
|
40
|
+
// File output
|
|
41
|
+
if (this.config.enableFile) {
|
|
42
|
+
this.logBuffer.push(fullEntry);
|
|
43
|
+
// Flush if buffer is large
|
|
44
|
+
if (this.logBuffer.length >= 100) {
|
|
45
|
+
await this.flush();
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Log security event
|
|
51
|
+
*/
|
|
52
|
+
async logSecurity(operation, details, result, error) {
|
|
53
|
+
await this.log({
|
|
54
|
+
level: "security",
|
|
55
|
+
operation,
|
|
56
|
+
details,
|
|
57
|
+
result,
|
|
58
|
+
error,
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Log write operation
|
|
63
|
+
*/
|
|
64
|
+
async logWrite(operation, filePath, clientId, result, details = {}, error) {
|
|
65
|
+
await this.log({
|
|
66
|
+
level: result === "success" ? "info" : "error",
|
|
67
|
+
operation,
|
|
68
|
+
clientId,
|
|
69
|
+
filePath,
|
|
70
|
+
details,
|
|
71
|
+
result,
|
|
72
|
+
error,
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Log read operation
|
|
77
|
+
*/
|
|
78
|
+
async logRead(operation, filePath, clientId, duration, result, error) {
|
|
79
|
+
await this.log({
|
|
80
|
+
level: "info",
|
|
81
|
+
operation,
|
|
82
|
+
clientId,
|
|
83
|
+
filePath,
|
|
84
|
+
details: {},
|
|
85
|
+
result,
|
|
86
|
+
error,
|
|
87
|
+
duration,
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Flush buffer to file
|
|
92
|
+
*/
|
|
93
|
+
async flush() {
|
|
94
|
+
if (this.logBuffer.length === 0)
|
|
95
|
+
return;
|
|
96
|
+
await this._ready;
|
|
97
|
+
try {
|
|
98
|
+
await this.ensureLogFile();
|
|
99
|
+
const logLines = this.logBuffer.map((entry) => JSON.stringify(entry)).join("\n") + "\n";
|
|
100
|
+
const logSize = Buffer.byteLength(logLines, "utf-8");
|
|
101
|
+
await fs.appendFile(this.currentLogFile, logLines, "utf-8");
|
|
102
|
+
this.currentLogSize += logSize;
|
|
103
|
+
this.logBuffer = [];
|
|
104
|
+
// Rotate if needed
|
|
105
|
+
if (this.currentLogSize >= this.config.maxFileSize) {
|
|
106
|
+
await this.rotateLog();
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
catch (error) {
|
|
110
|
+
console.error("Failed to flush audit log:", error);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Query audit logs
|
|
115
|
+
*/
|
|
116
|
+
async query(filters) {
|
|
117
|
+
const results = [];
|
|
118
|
+
const limit = filters.limit || 1000;
|
|
119
|
+
try {
|
|
120
|
+
const files = await this.getLogFiles();
|
|
121
|
+
for (const file of files.reverse()) {
|
|
122
|
+
if (results.length >= limit)
|
|
123
|
+
break;
|
|
124
|
+
const content = await fs.readFile(file, "utf-8");
|
|
125
|
+
const lines = content.split("\n").filter((line) => line.trim());
|
|
126
|
+
for (const line of lines.reverse()) {
|
|
127
|
+
if (results.length >= limit)
|
|
128
|
+
break;
|
|
129
|
+
try {
|
|
130
|
+
const entry = JSON.parse(line);
|
|
131
|
+
// Apply filters
|
|
132
|
+
if (filters.startTime && entry.timestamp < filters.startTime)
|
|
133
|
+
continue;
|
|
134
|
+
if (filters.endTime && entry.timestamp > filters.endTime)
|
|
135
|
+
continue;
|
|
136
|
+
if (filters.level && entry.level !== filters.level)
|
|
137
|
+
continue;
|
|
138
|
+
if (filters.operation && entry.operation !== filters.operation)
|
|
139
|
+
continue;
|
|
140
|
+
if (filters.clientId && entry.clientId !== filters.clientId)
|
|
141
|
+
continue;
|
|
142
|
+
if (filters.result && entry.result !== filters.result)
|
|
143
|
+
continue;
|
|
144
|
+
results.push(entry);
|
|
145
|
+
}
|
|
146
|
+
catch {
|
|
147
|
+
// Skip invalid lines
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
catch (error) {
|
|
153
|
+
console.error("Failed to query audit logs:", error);
|
|
154
|
+
}
|
|
155
|
+
return results;
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Get audit statistics
|
|
159
|
+
*/
|
|
160
|
+
async getStats(timeRange) {
|
|
161
|
+
const entries = await this.query({
|
|
162
|
+
startTime: timeRange?.start,
|
|
163
|
+
endTime: timeRange?.end,
|
|
164
|
+
limit: 100000,
|
|
165
|
+
});
|
|
166
|
+
const stats = {
|
|
167
|
+
totalEntries: entries.length,
|
|
168
|
+
byLevel: {},
|
|
169
|
+
byOperation: {},
|
|
170
|
+
byResult: {},
|
|
171
|
+
securityEvents: 0,
|
|
172
|
+
};
|
|
173
|
+
for (const entry of entries) {
|
|
174
|
+
stats.byLevel[entry.level] = (stats.byLevel[entry.level] || 0) + 1;
|
|
175
|
+
stats.byOperation[entry.operation] = (stats.byOperation[entry.operation] || 0) + 1;
|
|
176
|
+
stats.byResult[entry.result] = (stats.byResult[entry.result] || 0) + 1;
|
|
177
|
+
if (entry.level === "security") {
|
|
178
|
+
stats.securityEvents++;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
return stats;
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Stop logger and flush
|
|
185
|
+
*/
|
|
186
|
+
async stop() {
|
|
187
|
+
if (this.flushInterval) {
|
|
188
|
+
clearInterval(this.flushInterval);
|
|
189
|
+
this.flushInterval = null;
|
|
190
|
+
}
|
|
191
|
+
await this.flush();
|
|
192
|
+
}
|
|
193
|
+
// Private methods
|
|
194
|
+
async initLogDir() {
|
|
195
|
+
try {
|
|
196
|
+
await fs.mkdir(this.config.logDir, { recursive: true });
|
|
197
|
+
}
|
|
198
|
+
catch (error) {
|
|
199
|
+
console.error("Failed to create audit log directory:", error);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
async ensureLogFile() {
|
|
203
|
+
if (!this.currentLogFile) {
|
|
204
|
+
const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
|
|
205
|
+
this.currentLogFile = path.join(this.config.logDir, `audit-${timestamp}.log`);
|
|
206
|
+
this.currentLogSize = 0;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
async rotateLog() {
|
|
210
|
+
this.currentLogFile = null;
|
|
211
|
+
this.currentLogSize = 0;
|
|
212
|
+
// Cleanup old logs
|
|
213
|
+
const files = await this.getLogFiles();
|
|
214
|
+
if (files.length > this.config.maxFiles) {
|
|
215
|
+
const toDelete = files.slice(0, files.length - this.config.maxFiles);
|
|
216
|
+
for (const file of toDelete) {
|
|
217
|
+
try {
|
|
218
|
+
await fs.unlink(file);
|
|
219
|
+
}
|
|
220
|
+
catch {
|
|
221
|
+
// Ignore errors
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
async getLogFiles() {
|
|
227
|
+
try {
|
|
228
|
+
const entries = await fs.readdir(this.config.logDir);
|
|
229
|
+
const files = entries
|
|
230
|
+
.filter((name) => name.startsWith("audit-") && name.endsWith(".log"))
|
|
231
|
+
.map((name) => path.join(this.config.logDir, name));
|
|
232
|
+
// Sort by creation time
|
|
233
|
+
const stats = await Promise.all(files.map(async (file) => ({
|
|
234
|
+
file,
|
|
235
|
+
mtime: (await fs.stat(file)).mtime.getTime(),
|
|
236
|
+
})));
|
|
237
|
+
return stats.sort((a, b) => a.mtime - b.mtime).map((s) => s.file);
|
|
238
|
+
}
|
|
239
|
+
catch {
|
|
240
|
+
return [];
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
logToConsole(entry) {
|
|
244
|
+
const emoji = {
|
|
245
|
+
info: "ℹ️",
|
|
246
|
+
warn: "⚠️",
|
|
247
|
+
error: "❌",
|
|
248
|
+
security: "🔒",
|
|
249
|
+
}[entry.level];
|
|
250
|
+
const timestamp = new Date(entry.timestamp).toISOString();
|
|
251
|
+
const message = `${emoji} [${timestamp}] ${entry.operation} - ${entry.result}`;
|
|
252
|
+
if (entry.level === "error" || entry.level === "security") {
|
|
253
|
+
console.error(message, entry.error || "");
|
|
254
|
+
}
|
|
255
|
+
else {
|
|
256
|
+
console.error(message);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
startFlushInterval() {
|
|
260
|
+
this.flushInterval = setInterval(() => {
|
|
261
|
+
this.flush().catch((error) => {
|
|
262
|
+
console.error("Failed to flush audit log:", error);
|
|
263
|
+
});
|
|
264
|
+
}, 5000); // Flush every 5 seconds
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* Global audit logger instance
|
|
269
|
+
*/
|
|
270
|
+
export const globalAuditLogger = new AuditLogger();
|
|
271
|
+
//# sourceMappingURL=auditLogger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auditLogger.js","sourceRoot":"","sources":["../../../src/utils/auditLogger.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Backup Manager - v3.4.1
|
|
3
|
+
* Handles rolling backups for file modifications
|
|
4
|
+
*/
|
|
5
|
+
export declare class BackupManager {
|
|
6
|
+
private static readonly MAX_BACKUPS;
|
|
7
|
+
private static readonly BACKUP_DIR_NAME;
|
|
8
|
+
/**
|
|
9
|
+
* Creates a backup of the specified file before it gets modified
|
|
10
|
+
*/
|
|
11
|
+
static createBackup(filePath: string, projectRoot: string): Promise<void>;
|
|
12
|
+
/**
|
|
13
|
+
* Restores a file to its previous state
|
|
14
|
+
* @param steps How many versions to go back (1 = last version)
|
|
15
|
+
*/
|
|
16
|
+
static rollback(filePath: string, projectRoot: string, steps?: number): Promise<{
|
|
17
|
+
success: boolean;
|
|
18
|
+
error?: string;
|
|
19
|
+
restoredFrom?: string;
|
|
20
|
+
}>;
|
|
21
|
+
/**
|
|
22
|
+
* Deletes all backups for a project
|
|
23
|
+
*/
|
|
24
|
+
static clean(projectRoot: string): Promise<{
|
|
25
|
+
success: boolean;
|
|
26
|
+
error?: string;
|
|
27
|
+
deletedCount?: number;
|
|
28
|
+
}>;
|
|
29
|
+
/**
|
|
30
|
+
* Private helper to delete oldest backups if exceeding limit
|
|
31
|
+
*/
|
|
32
|
+
private static enforceBackupLimit;
|
|
33
|
+
}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Backup Manager - v3.4.1
|
|
3
|
+
* Handles rolling backups for file modifications
|
|
4
|
+
*/
|
|
5
|
+
import * as fs from "node:fs/promises";
|
|
6
|
+
import * as path from "node:path";
|
|
7
|
+
import * as crypto from "node:crypto";
|
|
8
|
+
export class BackupManager {
|
|
9
|
+
static MAX_BACKUPS = 5;
|
|
10
|
+
static BACKUP_DIR_NAME = ".mcp-backups";
|
|
11
|
+
/**
|
|
12
|
+
* Creates a backup of the specified file before it gets modified
|
|
13
|
+
*/
|
|
14
|
+
static async createBackup(filePath, projectRoot) {
|
|
15
|
+
try {
|
|
16
|
+
// Check if original file exists before backing up
|
|
17
|
+
await fs.access(filePath);
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
// File doesn't exist yet (it's a new file), no backup needed
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
const backupDir = path.join(projectRoot, this.BACKUP_DIR_NAME);
|
|
24
|
+
await fs.mkdir(backupDir, { recursive: true });
|
|
25
|
+
// Generate a safe identifier for the file (hash of its path to avoid deep nesting in backup dir)
|
|
26
|
+
const relativePath = path.relative(projectRoot, filePath);
|
|
27
|
+
const safeName = crypto.createHash('md5').update(relativePath).digest('hex').substring(0, 8) + "_" + path.basename(filePath);
|
|
28
|
+
// Save backup with timestamp
|
|
29
|
+
const timestamp = Date.now();
|
|
30
|
+
const backupFileName = `${safeName}_${timestamp}.bak`;
|
|
31
|
+
const backupFilePath = path.join(backupDir, backupFileName);
|
|
32
|
+
// Copy original file to backup
|
|
33
|
+
await fs.copyFile(filePath, backupFilePath);
|
|
34
|
+
// Enforce rolling backup limit per file
|
|
35
|
+
await this.enforceBackupLimit(backupDir, safeName);
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Restores a file to its previous state
|
|
39
|
+
* @param steps How many versions to go back (1 = last version)
|
|
40
|
+
*/
|
|
41
|
+
static async rollback(filePath, projectRoot, steps = 1) {
|
|
42
|
+
try {
|
|
43
|
+
const backupDir = path.join(projectRoot, this.BACKUP_DIR_NAME);
|
|
44
|
+
const relativePath = path.relative(projectRoot, filePath);
|
|
45
|
+
const safeName = crypto.createHash('md5').update(relativePath).digest('hex').substring(0, 8) + "_" + path.basename(filePath);
|
|
46
|
+
let files;
|
|
47
|
+
try {
|
|
48
|
+
files = await fs.readdir(backupDir);
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
return { success: false, error: "No backups found for this project." };
|
|
52
|
+
}
|
|
53
|
+
// Filter backups for this specific file and sort by timestamp descending (newest first)
|
|
54
|
+
const fileBackups = files
|
|
55
|
+
.filter(f => f.startsWith(safeName + "_") && f.endsWith(".bak"))
|
|
56
|
+
.sort((a, b) => b.localeCompare(a)); // String comparison of timestamps works because they are unix ms
|
|
57
|
+
if (fileBackups.length === 0) {
|
|
58
|
+
return { success: false, error: `No backups found for file: ${path.basename(filePath)}` };
|
|
59
|
+
}
|
|
60
|
+
// Determine which backup to restore
|
|
61
|
+
const targetIndex = Math.min(steps - 1, fileBackups.length - 1);
|
|
62
|
+
const targetBackup = fileBackups[targetIndex];
|
|
63
|
+
const backupFilePath = path.join(backupDir, targetBackup);
|
|
64
|
+
// Restore: copy backup back to original location
|
|
65
|
+
await fs.copyFile(backupFilePath, filePath);
|
|
66
|
+
return { success: true, restoredFrom: targetBackup };
|
|
67
|
+
}
|
|
68
|
+
catch (error) {
|
|
69
|
+
return { success: false, error: error instanceof Error ? error.message : String(error) };
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Deletes all backups for a project
|
|
74
|
+
*/
|
|
75
|
+
static async clean(projectRoot) {
|
|
76
|
+
try {
|
|
77
|
+
const backupDir = path.join(projectRoot, this.BACKUP_DIR_NAME);
|
|
78
|
+
try {
|
|
79
|
+
const files = await fs.readdir(backupDir);
|
|
80
|
+
let deletedCount = 0;
|
|
81
|
+
for (const file of files) {
|
|
82
|
+
const filePath = path.join(backupDir, file);
|
|
83
|
+
const stat = await fs.stat(filePath);
|
|
84
|
+
if (stat.isDirectory()) {
|
|
85
|
+
await fs.rm(filePath, { recursive: true, force: true });
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
await fs.unlink(filePath);
|
|
89
|
+
}
|
|
90
|
+
deletedCount++;
|
|
91
|
+
}
|
|
92
|
+
await fs.rmdir(backupDir);
|
|
93
|
+
return { success: true, deletedCount };
|
|
94
|
+
}
|
|
95
|
+
catch (e) {
|
|
96
|
+
if (e.code === 'ENOENT') {
|
|
97
|
+
// Directory doesn't exist
|
|
98
|
+
return { success: true, deletedCount: 0 };
|
|
99
|
+
}
|
|
100
|
+
throw e;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
catch (error) {
|
|
104
|
+
return { success: false, error: error instanceof Error ? error.message : String(error) };
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Private helper to delete oldest backups if exceeding limit
|
|
109
|
+
*/
|
|
110
|
+
static async enforceBackupLimit(backupDir, safeName) {
|
|
111
|
+
try {
|
|
112
|
+
const files = await fs.readdir(backupDir);
|
|
113
|
+
const fileBackups = files
|
|
114
|
+
.filter(f => f.startsWith(safeName + "_") && f.endsWith(".bak"))
|
|
115
|
+
.sort((a, b) => b.localeCompare(a)); // Newest first
|
|
116
|
+
// If we have more than MAX_BACKUPS, delete the oldest ones
|
|
117
|
+
if (fileBackups.length > this.MAX_BACKUPS) {
|
|
118
|
+
const backupsToDelete = fileBackups.slice(this.MAX_BACKUPS);
|
|
119
|
+
for (const backup of backupsToDelete) {
|
|
120
|
+
await fs.unlink(path.join(backupDir, backup));
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
catch (error) {
|
|
125
|
+
// Non-fatal, just logging silently
|
|
126
|
+
console.error(`Failed to enforce backup limits in ${backupDir}`, error);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
//# sourceMappingURL=backupManager.js.map
|