mcp-code-context 3.6.3 → 3.7.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/CHANGELOG.md +140 -278
- package/INSTRUCTIONS.md +23 -9
- package/README.md +217 -97
- package/SECURITY.md +55 -21
- package/dist/src/core/cacheManager.d.ts +4 -5
- package/dist/src/core/cacheManager.js +49 -33
- package/dist/src/core/cacheManager.js.map +1 -1
- package/dist/src/core/engine.d.ts +1 -1
- package/dist/src/core/engine.js +3 -3
- package/dist/src/core/engine.js.map +1 -1
- package/dist/src/core/indexManager.d.ts +58 -0
- package/dist/src/core/indexManager.js +252 -0
- package/dist/src/core/indexManager.js.map +1 -0
- package/dist/src/core/indexManagerQueries.d.ts +14 -0
- package/dist/src/core/indexManagerQueries.js +95 -0
- package/dist/src/core/indexManagerQueries.js.map +1 -0
- package/dist/src/core/sessionManager.d.ts +117 -0
- package/dist/src/core/sessionManager.js +231 -0
- package/dist/src/core/sessionManager.js.map +1 -0
- package/dist/src/core/validator.d.ts +1 -1
- package/dist/src/core/validator.js +18 -10
- package/dist/src/core/validator.js.map +1 -1
- package/dist/src/index.d.ts +1 -13
- package/dist/src/index.js +25 -999
- package/dist/src/index.js.map +1 -1
- package/dist/src/operations/astTransform.d.ts +38 -0
- package/dist/src/operations/astTransform.js +239 -0
- package/dist/src/operations/astTransform.js.map +1 -0
- package/dist/src/operations/compress.d.ts +5 -3
- package/dist/src/operations/compress.js +73 -7
- package/dist/src/operations/compress.js.map +1 -1
- package/dist/src/operations/confirmationStore.d.ts +35 -8
- package/dist/src/operations/confirmationStore.js +112 -14
- package/dist/src/operations/confirmationStore.js.map +1 -1
- package/dist/src/operations/impactAnalysis.d.ts +9 -0
- package/dist/src/operations/impactAnalysis.js +61 -0
- package/dist/src/operations/impactAnalysis.js.map +1 -0
- package/dist/src/operations/pendingStore.d.ts +51 -0
- package/dist/src/operations/pendingStore.js +201 -0
- package/dist/src/operations/pendingStore.js.map +1 -0
- package/dist/src/operations/pendingStoreInit.d.ts +6 -0
- package/dist/src/operations/pendingStoreInit.js +42 -0
- package/dist/src/operations/pendingStoreInit.js.map +1 -0
- package/dist/src/operations/read.d.ts +6 -92
- package/dist/src/operations/read.js +4 -449
- package/dist/src/operations/read.js.map +1 -1
- package/dist/src/operations/readCore.d.ts +33 -0
- package/dist/src/operations/readCore.js +142 -0
- package/dist/src/operations/readCore.js.map +1 -0
- package/dist/src/operations/rename.d.ts +13 -0
- package/dist/src/operations/rename.js +130 -0
- package/dist/src/operations/rename.js.map +1 -0
- package/dist/src/operations/searchOperation.d.ts +16 -0
- package/dist/src/operations/searchOperation.js +113 -0
- package/dist/src/operations/searchOperation.js.map +1 -0
- package/dist/src/operations/symbolQuery.d.ts +38 -0
- package/dist/src/operations/symbolQuery.js +194 -0
- package/dist/src/operations/symbolQuery.js.map +1 -0
- package/dist/src/operations/write.d.ts +11 -14
- package/dist/src/operations/write.js +6 -125
- package/dist/src/operations/write.js.map +1 -1
- package/dist/src/parsers/base.d.ts +1 -1
- package/dist/src/parsers/base.js +1 -1
- package/dist/src/parsers/csharp.d.ts +12 -0
- package/dist/src/parsers/csharp.js +67 -0
- package/dist/src/parsers/csharp.js.map +1 -0
- package/dist/src/parsers/dartTreeSitter.d.ts +1 -1
- package/dist/src/parsers/dartTreeSitter.js +1 -1
- package/dist/src/parsers/go.d.ts +11 -0
- package/dist/src/parsers/go.js +74 -0
- package/dist/src/parsers/go.js.map +1 -0
- package/dist/src/parsers/java.d.ts +12 -0
- package/dist/src/parsers/java.js +62 -0
- package/dist/src/parsers/java.js.map +1 -0
- package/dist/src/parsers/kotlin.d.ts +12 -0
- package/dist/src/parsers/kotlin.js +75 -0
- package/dist/src/parsers/kotlin.js.map +1 -0
- package/dist/src/parsers/php.d.ts +1 -1
- package/dist/src/parsers/php.js +1 -1
- package/dist/src/parsers/python.d.ts +1 -1
- package/dist/src/parsers/python.js +1 -1
- package/dist/src/parsers/registry.d.ts +1 -1
- package/dist/src/parsers/registry.js +63 -2
- package/dist/src/parsers/registry.js.map +1 -1
- package/dist/src/parsers/ruby.d.ts +12 -0
- package/dist/src/parsers/ruby.js +73 -0
- package/dist/src/parsers/ruby.js.map +1 -0
- package/dist/src/parsers/rust.d.ts +12 -0
- package/dist/src/parsers/rust.js +66 -0
- package/dist/src/parsers/rust.js.map +1 -0
- package/dist/src/parsers/typescript.d.ts +1 -1
- package/dist/src/parsers/typescript.js +28 -38
- package/dist/src/parsers/typescript.js.map +1 -1
- package/dist/src/tools/adminHandlers.d.ts +67 -0
- package/dist/src/tools/adminHandlers.js +129 -0
- package/dist/src/tools/adminHandlers.js.map +1 -0
- package/dist/src/tools/context.d.ts +9 -0
- package/dist/src/tools/context.js +21 -0
- package/dist/src/tools/context.js.map +1 -0
- package/dist/src/tools/handlers.d.ts +4 -0
- package/dist/src/tools/handlers.js +5 -0
- package/dist/src/tools/handlers.js.map +1 -0
- package/dist/src/tools/pipeline.d.ts +6 -0
- package/dist/src/tools/pipeline.js +100 -0
- package/dist/src/tools/pipeline.js.map +1 -0
- package/dist/src/tools/readHandlers.d.ts +55 -0
- package/dist/src/tools/readHandlers.js +220 -0
- package/dist/src/tools/readHandlers.js.map +1 -0
- package/dist/src/tools/toolDefinitions.d.ts +1037 -0
- package/dist/src/tools/toolDefinitions.js +13 -0
- package/dist/src/tools/toolDefinitions.js.map +1 -0
- package/dist/src/tools/toolDefinitionsAdmin.d.ts +89 -0
- package/dist/src/tools/toolDefinitionsAdmin.js +99 -0
- package/dist/src/tools/toolDefinitionsAdmin.js.map +1 -0
- package/dist/src/tools/toolDefinitionsCore.d.ts +949 -0
- package/dist/src/tools/toolDefinitionsCore.js +267 -0
- package/dist/src/tools/toolDefinitionsCore.js.map +1 -0
- package/dist/src/tools/writeHandlers.d.ts +37 -0
- package/dist/src/tools/writeHandlers.js +199 -0
- package/dist/src/tools/writeHandlers.js.map +1 -0
- package/dist/src/utils/appDir.d.ts +19 -0
- package/dist/src/utils/appDir.js +50 -0
- package/dist/src/utils/appDir.js.map +1 -0
- package/dist/src/utils/auditLogWriter.d.ts +9 -0
- package/dist/src/utils/auditLogWriter.js +49 -0
- package/dist/src/utils/auditLogWriter.js.map +1 -0
- package/dist/src/utils/auditLogger.d.ts +1 -10
- package/dist/src/utils/auditLogger.js +14 -109
- package/dist/src/utils/auditLogger.js.map +1 -1
- package/dist/src/utils/auditQuery.d.ts +23 -0
- package/dist/src/utils/auditQuery.js +67 -0
- package/dist/src/utils/auditQuery.js.map +1 -0
- package/dist/src/utils/backupManager.d.ts +2 -2
- package/dist/src/utils/backupManager.js +29 -12
- package/dist/src/utils/backupManager.js.map +1 -1
- package/dist/src/utils/constants.d.ts +1 -1
- package/dist/src/utils/constants.js +8 -1
- package/dist/src/utils/constants.js.map +1 -1
- package/dist/src/utils/diff.d.ts +12 -1
- package/dist/src/utils/diff.js +41 -1
- package/dist/src/utils/diff.js.map +1 -1
- package/dist/src/utils/fileLock.d.ts +7 -2
- package/dist/src/utils/fileLock.js +14 -11
- package/dist/src/utils/fileLock.js.map +1 -1
- package/dist/src/utils/fileWalker.d.ts +1 -1
- package/dist/src/utils/fileWalker.js +1 -1
- package/dist/src/utils/fileWatcher.d.ts +1 -1
- package/dist/src/utils/fileWatcher.js +1 -1
- package/dist/src/utils/fuzzySearch.d.ts +1 -1
- package/dist/src/utils/fuzzySearch.js +1 -1
- package/dist/src/utils/logger.d.ts +1 -1
- package/dist/src/utils/logger.js +2 -2
- package/dist/src/utils/logger.js.map +1 -1
- package/dist/src/utils/rateLimiter.d.ts +9 -1
- package/dist/src/utils/rateLimiter.js +12 -1
- package/dist/src/utils/rateLimiter.js.map +1 -1
- package/dist/src/utils/regexValidator.d.ts +12 -0
- package/dist/src/utils/regexValidator.js +48 -0
- package/dist/src/utils/regexValidator.js.map +1 -0
- package/dist/src/utils/safeRegex.d.ts +2 -92
- package/dist/src/utils/safeRegex.js +41 -222
- package/dist/src/utils/safeRegex.js.map +1 -1
- package/dist/src/utils/safeRegexApi.d.ts +56 -0
- package/dist/src/utils/safeRegexApi.js +99 -0
- package/dist/src/utils/safeRegexApi.js.map +1 -0
- package/dist/src/utils/safeRegexPool.d.ts +7 -0
- package/dist/src/utils/safeRegexPool.js +102 -0
- package/dist/src/utils/safeRegexPool.js.map +1 -0
- package/dist/src/utils/searchTools.js +6 -6
- package/dist/src/utils/searchTools.js.map +1 -1
- package/dist/src/utils/streaming.d.ts +4 -3
- package/dist/src/utils/streaming.js +1 -1
- package/dist/src/utils/streaming.js.map +1 -1
- package/dist/src/utils/telemetry.d.ts +1 -1
- package/dist/src/utils/telemetry.js +1 -1
- package/dist/src/utils/toctou.d.ts +7 -0
- package/dist/src/utils/toctou.js +24 -0
- package/dist/src/utils/toctou.js.map +1 -0
- package/llms.txt +173 -21
- package/package.json +2 -2
- package/scripts/replace-version.js +0 -59
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Index Manager query operations
|
|
3
|
+
*/
|
|
4
|
+
import * as fs from "node:fs/promises";
|
|
5
|
+
import { existsSync } from "fs";
|
|
6
|
+
export function searchSymbolsInDb(db, query, options = {}) {
|
|
7
|
+
const { fuzzy = false, types, maxResults = 50 } = options;
|
|
8
|
+
const results = [];
|
|
9
|
+
const typeFilter = types && types.length > 0 ? `AND type IN (${types.map(() => "?").join(",")})` : "";
|
|
10
|
+
let sql;
|
|
11
|
+
let params;
|
|
12
|
+
if (fuzzy) {
|
|
13
|
+
sql = `
|
|
14
|
+
SELECT file_path, name, type, start_line, end_line, class_name
|
|
15
|
+
FROM symbols WHERE LOWER(name) LIKE LOWER(?) ${typeFilter}
|
|
16
|
+
ORDER BY CASE WHEN LOWER(name) = LOWER(?) THEN 0 WHEN LOWER(name) LIKE LOWER(?) THEN 1 ELSE 2 END, name
|
|
17
|
+
LIMIT ?`;
|
|
18
|
+
params = [`%${query}%`, ...(types ?? []), query, `${query}%`, maxResults];
|
|
19
|
+
}
|
|
20
|
+
else {
|
|
21
|
+
sql = `
|
|
22
|
+
SELECT file_path, name, type, start_line, end_line, class_name
|
|
23
|
+
FROM symbols WHERE LOWER(name) = LOWER(?) ${typeFilter} ORDER BY name LIMIT ?`;
|
|
24
|
+
params = [query, ...(types ?? []), maxResults];
|
|
25
|
+
}
|
|
26
|
+
const stmt = db.prepare(sql);
|
|
27
|
+
stmt.bind(params);
|
|
28
|
+
while (stmt.step()) {
|
|
29
|
+
const row = stmt.getAsObject();
|
|
30
|
+
results.push({
|
|
31
|
+
filePath: row.file_path,
|
|
32
|
+
name: row.name,
|
|
33
|
+
type: row.type,
|
|
34
|
+
startLine: row.start_line,
|
|
35
|
+
endLine: row.end_line,
|
|
36
|
+
className: row.class_name ?? undefined,
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
stmt.free();
|
|
40
|
+
return results;
|
|
41
|
+
}
|
|
42
|
+
export function getDependentsFromDb(db, filePath) {
|
|
43
|
+
const results = [];
|
|
44
|
+
const stmt = db.prepare("SELECT from_file FROM dependencies WHERE to_file = ?");
|
|
45
|
+
stmt.bind([filePath]);
|
|
46
|
+
while (stmt.step()) {
|
|
47
|
+
results.push(stmt.getAsObject().from_file);
|
|
48
|
+
}
|
|
49
|
+
stmt.free();
|
|
50
|
+
return results;
|
|
51
|
+
}
|
|
52
|
+
export function getDependenciesFromDb(db, filePath) {
|
|
53
|
+
const results = [];
|
|
54
|
+
const stmt = db.prepare("SELECT to_file FROM dependencies WHERE from_file = ?");
|
|
55
|
+
stmt.bind([filePath]);
|
|
56
|
+
while (stmt.step()) {
|
|
57
|
+
results.push(stmt.getAsObject().to_file);
|
|
58
|
+
}
|
|
59
|
+
stmt.free();
|
|
60
|
+
return results;
|
|
61
|
+
}
|
|
62
|
+
export function hasIndexInDb(db) {
|
|
63
|
+
const stmt = db.prepare("SELECT COUNT(*) as count FROM files");
|
|
64
|
+
stmt.step();
|
|
65
|
+
const count = stmt.getAsObject().count;
|
|
66
|
+
stmt.free();
|
|
67
|
+
return count > 0;
|
|
68
|
+
}
|
|
69
|
+
export async function getIndexStatsFromDb(db, dbPath) {
|
|
70
|
+
const files = db.prepare("SELECT COUNT(*) as c FROM files");
|
|
71
|
+
files.step();
|
|
72
|
+
const filesCount = files.getAsObject().c;
|
|
73
|
+
files.free();
|
|
74
|
+
const syms = db.prepare("SELECT COUNT(*) as c FROM symbols");
|
|
75
|
+
syms.step();
|
|
76
|
+
const symsCount = syms.getAsObject().c;
|
|
77
|
+
syms.free();
|
|
78
|
+
const deps = db.prepare("SELECT COUNT(*) as c FROM dependencies");
|
|
79
|
+
deps.step();
|
|
80
|
+
const depsCount = deps.getAsObject().c;
|
|
81
|
+
deps.free();
|
|
82
|
+
const last = db.prepare("SELECT MAX(indexed_at) as t FROM files");
|
|
83
|
+
last.step();
|
|
84
|
+
const lastAt = last.getAsObject().t;
|
|
85
|
+
last.free();
|
|
86
|
+
const dbSize = existsSync(dbPath) ? (await fs.stat(dbPath)).size : 0;
|
|
87
|
+
return {
|
|
88
|
+
filesIndexed: filesCount,
|
|
89
|
+
symbolsIndexed: symsCount,
|
|
90
|
+
dependenciesIndexed: depsCount,
|
|
91
|
+
dbSizeBytes: dbSize,
|
|
92
|
+
lastIndexedAt: lastAt,
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
//# sourceMappingURL=indexManagerQueries.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"indexManagerQueries.js","sourceRoot":"","sources":["../../../src/core/indexManagerQueries.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session Manager - v3.7.0
|
|
3
|
+
* Manages per-MCP-client state isolation
|
|
4
|
+
* Prevents state leakage between concurrent clients
|
|
5
|
+
*/
|
|
6
|
+
import { FileLockManager } from "../utils/fileLock.js";
|
|
7
|
+
import { ConfirmationStore } from "../operations/confirmationStore.js";
|
|
8
|
+
import { RateLimiter } from "../utils/rateLimiter.js";
|
|
9
|
+
import { CacheManager } from "./cacheManager.js";
|
|
10
|
+
interface CacheEntry {
|
|
11
|
+
cache: CacheManager;
|
|
12
|
+
lastUsed: number;
|
|
13
|
+
}
|
|
14
|
+
interface SessionState {
|
|
15
|
+
sessionId: string;
|
|
16
|
+
lockManager: FileLockManager;
|
|
17
|
+
confirmationStore: ConfirmationStore;
|
|
18
|
+
rateLimiter: RateLimiter;
|
|
19
|
+
cacheManagers: Map<string, CacheEntry>;
|
|
20
|
+
createdAt: number;
|
|
21
|
+
lastActivity: number;
|
|
22
|
+
}
|
|
23
|
+
export interface SessionStats {
|
|
24
|
+
exists: boolean;
|
|
25
|
+
sessionId?: string;
|
|
26
|
+
createdAt?: number;
|
|
27
|
+
lastActivity?: number;
|
|
28
|
+
pendingOperations: number;
|
|
29
|
+
locksHeld: number;
|
|
30
|
+
rateLimiterTokens: number;
|
|
31
|
+
cacheManagers: number;
|
|
32
|
+
}
|
|
33
|
+
export interface PendingOperationSummary {
|
|
34
|
+
token: string;
|
|
35
|
+
filePath: string;
|
|
36
|
+
operation: string;
|
|
37
|
+
createdAt: number;
|
|
38
|
+
expiresAt: number;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* SessionManager - Manages isolated state per MCP client connection
|
|
42
|
+
*
|
|
43
|
+
* Each MCP client connection gets:
|
|
44
|
+
* - Dedicated FileLockManager (no lock conflicts)
|
|
45
|
+
* - Dedicated ConfirmationStore (no token leakage)
|
|
46
|
+
* - Dedicated RateLimiter bucket (fair quota)
|
|
47
|
+
* - Dedicated CacheManager pool (no cache pollution)
|
|
48
|
+
*/
|
|
49
|
+
export declare class SessionManager {
|
|
50
|
+
private sessions;
|
|
51
|
+
private cleanupTimer;
|
|
52
|
+
constructor();
|
|
53
|
+
/**
|
|
54
|
+
* Get or create session state for a client
|
|
55
|
+
*
|
|
56
|
+
* @param sessionId - Unique identifier for MCP client connection
|
|
57
|
+
* @returns Isolated session state
|
|
58
|
+
*/
|
|
59
|
+
getOrCreate(sessionId: string, projectRoot?: string): SessionState;
|
|
60
|
+
/**
|
|
61
|
+
* Get CacheManager for a project within this session
|
|
62
|
+
*
|
|
63
|
+
* @param sessionId - Session identifier
|
|
64
|
+
* @param projectRoot - Project root path
|
|
65
|
+
* @returns CacheManager instance
|
|
66
|
+
*/
|
|
67
|
+
getCacheManager(sessionId: string, projectRoot: string): CacheManager;
|
|
68
|
+
/**
|
|
69
|
+
* Cleanup session and release all resources
|
|
70
|
+
*
|
|
71
|
+
* @param sessionId - Session to cleanup
|
|
72
|
+
*/
|
|
73
|
+
cleanup(sessionId: string): Promise<void>;
|
|
74
|
+
/**
|
|
75
|
+
* Get stats for a specific session
|
|
76
|
+
*
|
|
77
|
+
* @param sessionId - Session identifier
|
|
78
|
+
* @returns Session statistics
|
|
79
|
+
*/
|
|
80
|
+
getSessionStats(sessionId: string): SessionStats;
|
|
81
|
+
/**
|
|
82
|
+
* Clear cache for a specific session
|
|
83
|
+
*
|
|
84
|
+
* @param sessionId - Session identifier
|
|
85
|
+
* @param projectRoot - Project root path
|
|
86
|
+
* @returns Number of cache entries cleared
|
|
87
|
+
*/
|
|
88
|
+
clearSessionCache(sessionId: string, projectRoot?: string): Promise<number>;
|
|
89
|
+
/**
|
|
90
|
+
* List all pending operations for a session
|
|
91
|
+
*
|
|
92
|
+
* @param sessionId - Session identifier
|
|
93
|
+
* @returns Array of pending operations
|
|
94
|
+
*/
|
|
95
|
+
listPendingOperations(sessionId: string): PendingOperationSummary[];
|
|
96
|
+
/**
|
|
97
|
+
* Get count of active sessions
|
|
98
|
+
*/
|
|
99
|
+
getActiveSessionCount(): number;
|
|
100
|
+
/**
|
|
101
|
+
* Auto-cleanup inactive sessions
|
|
102
|
+
*/
|
|
103
|
+
private startCleanupTimer;
|
|
104
|
+
/**
|
|
105
|
+
* Stop cleanup timer
|
|
106
|
+
*/
|
|
107
|
+
stop(): void;
|
|
108
|
+
/**
|
|
109
|
+
* Cleanup all sessions on shutdown
|
|
110
|
+
*/
|
|
111
|
+
shutdownAll(): Promise<void>;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Global session manager instance
|
|
115
|
+
*/
|
|
116
|
+
export declare const globalSessionManager: SessionManager;
|
|
117
|
+
export {};
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session Manager - v3.7.0
|
|
3
|
+
* Manages per-MCP-client state isolation
|
|
4
|
+
* Prevents state leakage between concurrent clients
|
|
5
|
+
*/
|
|
6
|
+
import { FileLockManager } from "../utils/fileLock.js";
|
|
7
|
+
import { ConfirmationStore } from "../operations/confirmationStore.js";
|
|
8
|
+
import { RateLimiter } from "../utils/rateLimiter.js";
|
|
9
|
+
import { CacheManager } from "./cacheManager.js";
|
|
10
|
+
const MAX_CACHE_MANAGERS = 10;
|
|
11
|
+
const SESSION_TIMEOUT_MS = 30 * 60 * 1000; // 30 minutes
|
|
12
|
+
/**
|
|
13
|
+
* SessionManager - Manages isolated state per MCP client connection
|
|
14
|
+
*
|
|
15
|
+
* Each MCP client connection gets:
|
|
16
|
+
* - Dedicated FileLockManager (no lock conflicts)
|
|
17
|
+
* - Dedicated ConfirmationStore (no token leakage)
|
|
18
|
+
* - Dedicated RateLimiter bucket (fair quota)
|
|
19
|
+
* - Dedicated CacheManager pool (no cache pollution)
|
|
20
|
+
*/
|
|
21
|
+
export class SessionManager {
|
|
22
|
+
sessions = new Map();
|
|
23
|
+
cleanupTimer = null;
|
|
24
|
+
constructor() {
|
|
25
|
+
this.startCleanupTimer();
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Get or create session state for a client
|
|
29
|
+
*
|
|
30
|
+
* @param sessionId - Unique identifier for MCP client connection
|
|
31
|
+
* @returns Isolated session state
|
|
32
|
+
*/
|
|
33
|
+
getOrCreate(sessionId, projectRoot) {
|
|
34
|
+
let session = this.sessions.get(sessionId);
|
|
35
|
+
if (!session) {
|
|
36
|
+
session = {
|
|
37
|
+
sessionId,
|
|
38
|
+
lockManager: new FileLockManager(),
|
|
39
|
+
// Pass sessionId + projectRoot so SQLite crash recovery activates
|
|
40
|
+
confirmationStore: new ConfirmationStore(sessionId, projectRoot),
|
|
41
|
+
rateLimiter: new RateLimiter(),
|
|
42
|
+
cacheManagers: new Map(),
|
|
43
|
+
createdAt: Date.now(),
|
|
44
|
+
lastActivity: Date.now(),
|
|
45
|
+
};
|
|
46
|
+
this.sessions.set(sessionId, session);
|
|
47
|
+
}
|
|
48
|
+
else if (projectRoot && !session.confirmationStore.hasPersistentStore()) {
|
|
49
|
+
// Session existed but was created without projectRoot — activate SQLite now
|
|
50
|
+
session.confirmationStore.activatePersistence(sessionId, projectRoot);
|
|
51
|
+
}
|
|
52
|
+
session.lastActivity = Date.now();
|
|
53
|
+
return session;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Get CacheManager for a project within this session
|
|
57
|
+
*
|
|
58
|
+
* @param sessionId - Session identifier
|
|
59
|
+
* @param projectRoot - Project root path
|
|
60
|
+
* @returns CacheManager instance
|
|
61
|
+
*/
|
|
62
|
+
getCacheManager(sessionId, projectRoot) {
|
|
63
|
+
// Pass projectRoot so crash recovery SQLite activates on first real tool call
|
|
64
|
+
const session = this.getOrCreate(sessionId, projectRoot);
|
|
65
|
+
const now = Date.now();
|
|
66
|
+
if (session.cacheManagers.has(projectRoot)) {
|
|
67
|
+
const entry = session.cacheManagers.get(projectRoot);
|
|
68
|
+
entry.lastUsed = now;
|
|
69
|
+
return entry.cache;
|
|
70
|
+
}
|
|
71
|
+
// Evict LRU if at capacity
|
|
72
|
+
if (session.cacheManagers.size >= MAX_CACHE_MANAGERS) {
|
|
73
|
+
let oldestKey = null;
|
|
74
|
+
let oldestTime = Infinity;
|
|
75
|
+
for (const [key, entry] of session.cacheManagers.entries()) {
|
|
76
|
+
if (entry.lastUsed < oldestTime) {
|
|
77
|
+
oldestTime = entry.lastUsed;
|
|
78
|
+
oldestKey = key;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
if (oldestKey) {
|
|
82
|
+
const evicted = session.cacheManagers.get(oldestKey);
|
|
83
|
+
evicted.cache.persistOnExit();
|
|
84
|
+
evicted.cache.close();
|
|
85
|
+
session.cacheManagers.delete(oldestKey);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
const cache = new CacheManager(projectRoot);
|
|
89
|
+
session.cacheManagers.set(projectRoot, { cache, lastUsed: now });
|
|
90
|
+
return cache;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Cleanup session and release all resources
|
|
94
|
+
*
|
|
95
|
+
* @param sessionId - Session to cleanup
|
|
96
|
+
*/
|
|
97
|
+
async cleanup(sessionId) {
|
|
98
|
+
const session = this.sessions.get(sessionId);
|
|
99
|
+
if (!session)
|
|
100
|
+
return;
|
|
101
|
+
// Release all file locks
|
|
102
|
+
await session.lockManager.releaseAll();
|
|
103
|
+
// Stop rate limiter timer
|
|
104
|
+
session.rateLimiter.stop();
|
|
105
|
+
// Close all cache managers (persist + stop watchers + free WASM heap)
|
|
106
|
+
for (const entry of session.cacheManagers.values()) {
|
|
107
|
+
entry.cache.persistOnExit();
|
|
108
|
+
entry.cache.close();
|
|
109
|
+
}
|
|
110
|
+
session.cacheManagers.clear();
|
|
111
|
+
// Clear confirmation store
|
|
112
|
+
session.confirmationStore.clearAll();
|
|
113
|
+
this.sessions.delete(sessionId);
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Get stats for a specific session
|
|
117
|
+
*
|
|
118
|
+
* @param sessionId - Session identifier
|
|
119
|
+
* @returns Session statistics
|
|
120
|
+
*/
|
|
121
|
+
getSessionStats(sessionId) {
|
|
122
|
+
const session = this.sessions.get(sessionId);
|
|
123
|
+
if (!session) {
|
|
124
|
+
return {
|
|
125
|
+
exists: false,
|
|
126
|
+
pendingOperations: 0,
|
|
127
|
+
locksHeld: 0,
|
|
128
|
+
rateLimiterTokens: 0,
|
|
129
|
+
cacheManagers: 0,
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
return {
|
|
133
|
+
exists: true,
|
|
134
|
+
sessionId: session.sessionId,
|
|
135
|
+
createdAt: session.createdAt,
|
|
136
|
+
lastActivity: session.lastActivity,
|
|
137
|
+
pendingOperations: session.confirmationStore.getPendingCount(),
|
|
138
|
+
locksHeld: session.lockManager.getActiveLockCount(),
|
|
139
|
+
rateLimiterTokens: session.rateLimiter.getTokens(sessionId),
|
|
140
|
+
cacheManagers: session.cacheManagers.size,
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Clear cache for a specific session
|
|
145
|
+
*
|
|
146
|
+
* @param sessionId - Session identifier
|
|
147
|
+
* @param projectRoot - Project root path
|
|
148
|
+
* @returns Number of cache entries cleared
|
|
149
|
+
*/
|
|
150
|
+
async clearSessionCache(sessionId, projectRoot) {
|
|
151
|
+
const session = this.sessions.get(sessionId);
|
|
152
|
+
if (!session)
|
|
153
|
+
return 0;
|
|
154
|
+
if (projectRoot) {
|
|
155
|
+
const entry = session.cacheManagers.get(projectRoot);
|
|
156
|
+
if (entry) {
|
|
157
|
+
await entry.cache.clear();
|
|
158
|
+
return 1;
|
|
159
|
+
}
|
|
160
|
+
return 0;
|
|
161
|
+
}
|
|
162
|
+
// Clear all caches for this session
|
|
163
|
+
let cleared = 0;
|
|
164
|
+
for (const entry of session.cacheManagers.values()) {
|
|
165
|
+
await entry.cache.clear();
|
|
166
|
+
cleared++;
|
|
167
|
+
}
|
|
168
|
+
return cleared;
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* List all pending operations for a session
|
|
172
|
+
*
|
|
173
|
+
* @param sessionId - Session identifier
|
|
174
|
+
* @returns Array of pending operations
|
|
175
|
+
*/
|
|
176
|
+
listPendingOperations(sessionId) {
|
|
177
|
+
const session = this.sessions.get(sessionId);
|
|
178
|
+
if (!session)
|
|
179
|
+
return [];
|
|
180
|
+
return session.confirmationStore.listAll();
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Get count of active sessions
|
|
184
|
+
*/
|
|
185
|
+
getActiveSessionCount() {
|
|
186
|
+
return this.sessions.size;
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Auto-cleanup inactive sessions
|
|
190
|
+
*/
|
|
191
|
+
startCleanupTimer() {
|
|
192
|
+
this.cleanupTimer = setInterval(async () => {
|
|
193
|
+
const now = Date.now();
|
|
194
|
+
const toCleanup = [];
|
|
195
|
+
for (const [sessionId, session] of this.sessions.entries()) {
|
|
196
|
+
const inactive = now - session.lastActivity;
|
|
197
|
+
if (inactive > SESSION_TIMEOUT_MS) {
|
|
198
|
+
toCleanup.push(sessionId);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
for (const sessionId of toCleanup) {
|
|
202
|
+
await this.cleanup(sessionId);
|
|
203
|
+
}
|
|
204
|
+
}, 60 * 1000); // Check every minute
|
|
205
|
+
if (this.cleanupTimer.unref) {
|
|
206
|
+
this.cleanupTimer.unref();
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Stop cleanup timer
|
|
211
|
+
*/
|
|
212
|
+
stop() {
|
|
213
|
+
if (this.cleanupTimer) {
|
|
214
|
+
clearInterval(this.cleanupTimer);
|
|
215
|
+
this.cleanupTimer = null;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Cleanup all sessions on shutdown
|
|
220
|
+
*/
|
|
221
|
+
async shutdownAll() {
|
|
222
|
+
this.stop();
|
|
223
|
+
const sessionIds = Array.from(this.sessions.keys());
|
|
224
|
+
await Promise.all(sessionIds.map(id => this.cleanup(id)));
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* Global session manager instance
|
|
229
|
+
*/
|
|
230
|
+
export const globalSessionManager = new SessionManager();
|
|
231
|
+
//# sourceMappingURL=sessionManager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sessionManager.js","sourceRoot":"","sources":["../../../src/core/sessionManager.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Security Validator - v3.
|
|
2
|
+
* Security Validator - v3.7.0
|
|
3
3
|
* CRITICAL FIX: Path traversal check AFTER normalization
|
|
4
4
|
*/
|
|
5
5
|
import * as path from "node:path";
|
|
@@ -7,29 +7,37 @@ import * as fs from "node:fs/promises";
|
|
|
7
7
|
export class SecurityValidator {
|
|
8
8
|
projectRoot;
|
|
9
9
|
constructor(projectRoot) {
|
|
10
|
-
|
|
10
|
+
// normalize: resolve + lowercase for case-insensitive Windows FS comparison
|
|
11
|
+
this.projectRoot = path.resolve(projectRoot).toLowerCase();
|
|
11
12
|
}
|
|
12
13
|
async validateFilePath(filePath) {
|
|
13
|
-
// Resolve FIRST, then check
|
|
14
14
|
const resolved = path.resolve(filePath);
|
|
15
|
-
|
|
16
|
-
if (
|
|
15
|
+
const resolvedNorm = resolved.toLowerCase();
|
|
16
|
+
if (resolvedNorm !== this.projectRoot && !resolvedNorm.startsWith(this.projectRoot + path.sep)) {
|
|
17
17
|
return {
|
|
18
18
|
valid: false,
|
|
19
|
-
error: `Security: Path "${filePath}" is outside project boundary "${this.projectRoot}"
|
|
19
|
+
error: `Security: Path "${filePath}" is outside project boundary "${this.projectRoot}"`,
|
|
20
20
|
};
|
|
21
21
|
}
|
|
22
|
-
// Existence check
|
|
23
22
|
try {
|
|
24
|
-
await fs.
|
|
23
|
+
const realPath = await fs.realpath(resolved);
|
|
24
|
+
const realPathNorm = realPath.toLowerCase();
|
|
25
|
+
if (realPathNorm !== this.projectRoot && !realPathNorm.startsWith(this.projectRoot + path.sep)) {
|
|
26
|
+
return {
|
|
27
|
+
valid: false,
|
|
28
|
+
error: `Security: Symlink "${filePath}" resolves outside project boundary "${this.projectRoot}"`,
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
await fs.access(realPath);
|
|
32
|
+
return { valid: true, resolvedPath: realPath };
|
|
25
33
|
}
|
|
26
34
|
catch {
|
|
35
|
+
// fs.realpath or fs.access failed — file does not exist or is inaccessible
|
|
27
36
|
return {
|
|
28
37
|
valid: false,
|
|
29
|
-
error: `File not found: "${filePath}" (resolved to "${resolved}")
|
|
38
|
+
error: `File not found: "${filePath}" (resolved to "${resolved}")`,
|
|
30
39
|
};
|
|
31
40
|
}
|
|
32
|
-
return { valid: true, resolvedPath: resolved };
|
|
33
41
|
}
|
|
34
42
|
async validateFileSize(filePath, maxSize = 10 * 1024 * 1024) {
|
|
35
43
|
try {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validator.js","sourceRoot":"","sources":["../../../src/core/validator.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAQvC,MAAM,OAAO,iBAAiB;IACpB,WAAW,CAAS;IAE5B,YAAY,WAAmB;QAC7B,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"validator.js","sourceRoot":"","sources":["../../../src/core/validator.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAQvC,MAAM,OAAO,iBAAiB;IACpB,WAAW,CAAS;IAE5B,YAAY,WAAmB;QAC7B,4EAA4E;QAC5E,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,WAAW,EAAE,CAAC;IAC7D,CAAC;IAED,KAAK,CAAC,gBAAgB,CAAC,QAAgB;QACrC,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QACxC,MAAM,YAAY,GAAG,QAAQ,CAAC,WAAW,EAAE,CAAC;QAE5C,IAAI,YAAY,KAAK,IAAI,CAAC,WAAW,IAAI,CAAC,YAAY,CAAC,UAAU,CAAC,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;YAC/F,OAAO;gBACL,KAAK,EAAE,KAAK;gBACZ,KAAK,EAAE,mBAAmB,QAAQ,kCAAkC,IAAI,CAAC,WAAW,GAAG;aACxF,CAAC;QACJ,CAAC;QAED,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;YAC7C,MAAM,YAAY,GAAG,QAAQ,CAAC,WAAW,EAAE,CAAC;YAE5C,IAAI,YAAY,KAAK,IAAI,CAAC,WAAW,IAAI,CAAC,YAAY,CAAC,UAAU,CAAC,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;gBAC/F,OAAO;oBACL,KAAK,EAAE,KAAK;oBACZ,KAAK,EAAE,sBAAsB,QAAQ,wCAAwC,IAAI,CAAC,WAAW,GAAG;iBACjG,CAAC;YACJ,CAAC;YAED,MAAM,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;YAC1B,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,YAAY,EAAE,QAAQ,EAAE,CAAC;QACjD,CAAC;QAAC,MAAM,CAAC;YACP,2EAA2E;YAC3E,OAAO;gBACL,KAAK,EAAE,KAAK;gBACZ,KAAK,EAAE,oBAAoB,QAAQ,mBAAmB,QAAQ,IAAI;aACnE,CAAC;QACJ,CAAC;IACH,CAAC;IAED,KAAK,CAAC,gBAAgB,CAAC,QAAgB,EAAE,UAAkB,EAAE,GAAG,IAAI,GAAG,IAAI;QACzE,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YACrC,IAAI,IAAI,CAAC,IAAI,GAAG,OAAO,EAAE,CAAC;gBACxB,MAAM,MAAM,GAAG,CAAC,IAAI,CAAC,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;gBACpD,MAAM,KAAK,GAAG,CAAC,OAAO,GAAG,IAAI,GAAG,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;gBACjD,OAAO;oBACL,KAAK,EAAE,KAAK;oBACZ,KAAK,EAAE,mBAAmB,MAAM,sBAAsB,KAAK,IAAI;iBAChE,CAAC;YACJ,CAAC;YACD,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;QACzB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO;gBACL,KAAK,EAAE,KAAK;gBACZ,KAAK,EAAE,kCAAkC,QAAQ,MAAM,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE;aAChH,CAAC;QACJ,CAAC;IACH,CAAC;CACF"}
|
package/dist/src/index.d.ts
CHANGED
|
@@ -1,17 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
|
-
* mcp-code-context v3.
|
|
4
|
-
*
|
|
5
|
-
* Production-ready with:
|
|
6
|
-
* - Tree-sitter WASM for 100% AST accuracy (TypeScript, Python, PHP, Dart)
|
|
7
|
-
* - Zero native dependencies — 100% portable across Windows/Mac/Linux
|
|
8
|
-
* - Two-phase write workflow (dry-run + confirmation token)
|
|
9
|
-
* - Middleware pipeline: rate limiting, file locking, audit logging, telemetry
|
|
10
|
-
* - Mandatory security boundaries on ALL handlers
|
|
11
|
-
* - Persistent WASM SQLite cache with <100ms hits
|
|
12
|
-
* - Structured logging with pino (JSON to stderr, MCP-safe)
|
|
13
|
-
* - File watcher with chokidar for auto cache invalidation
|
|
14
|
-
* - Fuzzy search with fuse.js + pagination
|
|
15
|
-
* - Token optimization: compact diffs, auto-optimize output
|
|
3
|
+
* mcp-code-context v3.7.0 - Tree-sitter WASM Edition (thin bootstrap)
|
|
16
4
|
*/
|
|
17
5
|
export {};
|