@mnemonik/shared 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.
@@ -0,0 +1,60 @@
1
+ /**
2
+ * FileSystemReader — Encapsulates all filesystem operations for scanning.
3
+ *
4
+ * This module is the boundary between disk I/O and the rest of the system.
5
+ * In a cloud deployment, a lightweight client-side agent uses this module
6
+ * locally and pushes results to the server's indexing API; the server
7
+ * itself never touches the filesystem.
8
+ */
9
+ import { CodeChunk } from './codeScanner.js';
10
+ export interface FileData {
11
+ /** Relative path from project root */
12
+ path: string;
13
+ /** SHA-256 hash (content + size + mtime) */
14
+ hash: string;
15
+ }
16
+ export interface ScanFilesResult {
17
+ files: FileData[];
18
+ chunks: CodeChunk[];
19
+ }
20
+ export interface ChangedFilesResult {
21
+ changed: FileData[];
22
+ chunks: CodeChunk[];
23
+ skipped: number;
24
+ }
25
+ export declare class FileSystemReader {
26
+ /**
27
+ * Recursively list all scannable text files in a project directory.
28
+ * Returns absolute paths.
29
+ */
30
+ readProjectFiles(dirPath: string): Promise<string[]>;
31
+ /**
32
+ * Compute SHA-256 hash for a file (content + size + mtime).
33
+ * Returns empty string on error or if the file exceeds MAX_FILE_SIZE.
34
+ */
35
+ calculateFileHash(filePath: string): Promise<string>;
36
+ /**
37
+ * Scan a directory and return files + extracted code chunks.
38
+ */
39
+ scanDirectory(projectPath: string): Promise<ScanFilesResult>;
40
+ /**
41
+ * Determine which files have changed compared to known hashes.
42
+ * Returns changed files plus their extracted code chunks.
43
+ */
44
+ detectChangedFiles(projectPath: string, knownHashes: Map<string, string>): Promise<ChangedFilesResult>;
45
+ /**
46
+ * Read file content with timeout protection.
47
+ */
48
+ readFileContent(filePath: string): Promise<string | null>;
49
+ /**
50
+ * Stat a file with timeout protection.
51
+ */
52
+ statFile(filePath: string): Promise<{
53
+ mtime: Date;
54
+ size: number;
55
+ } | null>;
56
+ private traverseDirectory;
57
+ private isTextFile;
58
+ }
59
+ export declare function getFileSystemReader(): FileSystemReader;
60
+ //# sourceMappingURL=FileSystemReader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FileSystemReader.d.ts","sourceRoot":"","sources":["../src/FileSystemReader.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAOH,OAAO,EAAe,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAgE1D,MAAM,WAAW,QAAQ;IACvB,sCAAsC;IACtC,IAAI,EAAE,MAAM,CAAC;IACb,4CAA4C;IAC5C,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,QAAQ,EAAE,CAAC;IAClB,MAAM,EAAE,SAAS,EAAE,CAAC;CACrB;AAED,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,QAAQ,EAAE,CAAC;IACpB,MAAM,EAAE,SAAS,EAAE,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,qBAAa,gBAAgB;IAC3B;;;OAGG;IACG,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAM1D;;;OAGG;IACG,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAiC1D;;OAEG;IACG,aAAa,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC;IAoBlE;;;OAGG;IACG,kBAAkB,CACtB,WAAW,EAAE,MAAM,EACnB,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GAC/B,OAAO,CAAC,kBAAkB,CAAC;IA0C9B;;OAEG;IACG,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAY/D;;OAEG;IACG,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,KAAK,EAAE,IAAI,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;YAejE,iBAAiB;IAqC/B,OAAO,CAAC,UAAU;CAKnB;AAID,wBAAgB,mBAAmB,IAAI,gBAAgB,CAGtD"}
@@ -0,0 +1,236 @@
1
+ /**
2
+ * FileSystemReader — Encapsulates all filesystem operations for scanning.
3
+ *
4
+ * This module is the boundary between disk I/O and the rest of the system.
5
+ * In a cloud deployment, a lightweight client-side agent uses this module
6
+ * locally and pushes results to the server's indexing API; the server
7
+ * itself never touches the filesystem.
8
+ */
9
+ import { readdir, readFile, stat } from 'fs/promises';
10
+ import { join, relative, isAbsolute } from 'path';
11
+ import { createHash } from 'crypto';
12
+ import { debug as logDebug, warn as logWarn, info as logInfo } from './logger.js';
13
+ import { withTimeout } from './asyncUtils.js';
14
+ import { CodeScanner } from './codeScanner.js';
15
+ const FILE_OP_TIMEOUT_MS = 5000;
16
+ const MAX_FILE_SIZE = 10 * 1024 * 1024; // 10 MB
17
+ const SKIP_DIRS = new Set([
18
+ 'node_modules',
19
+ '.git',
20
+ 'dist',
21
+ 'build',
22
+ '.next',
23
+ 'coverage',
24
+ 'venv',
25
+ '.venv',
26
+ 'env',
27
+ '.env',
28
+ '__pycache__',
29
+ '.cache',
30
+ 'target',
31
+ '.tox',
32
+ '.mypy_cache',
33
+ '.pytest_cache',
34
+ ]);
35
+ const TEXT_EXTENSIONS = new Set([
36
+ 'ts',
37
+ 'tsx',
38
+ 'js',
39
+ 'jsx',
40
+ 'py',
41
+ 'java',
42
+ 'cpp',
43
+ 'c',
44
+ 'h',
45
+ 'hpp',
46
+ 'go',
47
+ 'rs',
48
+ 'php',
49
+ 'rb',
50
+ 'swift',
51
+ 'kt',
52
+ 'scala',
53
+ 'sh',
54
+ 'bash',
55
+ 'sql',
56
+ 'html',
57
+ 'css',
58
+ 'scss',
59
+ 'sass',
60
+ 'less',
61
+ 'json',
62
+ 'yaml',
63
+ 'yml',
64
+ 'toml',
65
+ 'xml',
66
+ 'md',
67
+ 'txt',
68
+ 'vue',
69
+ 'svelte',
70
+ 'astro',
71
+ ]);
72
+ const SKIP_PATTERNS = ['.min.js', '.min.css', '.bundle.js', '.legacy.js', '.map'];
73
+ export class FileSystemReader {
74
+ /**
75
+ * Recursively list all scannable text files in a project directory.
76
+ * Returns absolute paths.
77
+ */
78
+ async readProjectFiles(dirPath) {
79
+ const files = [];
80
+ await this.traverseDirectory(dirPath, files);
81
+ return files;
82
+ }
83
+ /**
84
+ * Compute SHA-256 hash for a file (content + size + mtime).
85
+ * Returns empty string on error or if the file exceeds MAX_FILE_SIZE.
86
+ */
87
+ async calculateFileHash(filePath) {
88
+ try {
89
+ const stats = await withTimeout(stat(filePath), FILE_OP_TIMEOUT_MS, `stat timed out: ${filePath}`);
90
+ if (stats.size > MAX_FILE_SIZE) {
91
+ logDebug('Skipping file hash — exceeds size limit', {
92
+ file: filePath,
93
+ size: stats.size,
94
+ });
95
+ return '';
96
+ }
97
+ const content = await withTimeout(readFile(filePath, 'utf-8'), FILE_OP_TIMEOUT_MS, `readFile timed out: ${filePath}`);
98
+ const hashInput = `${content}\n${stats.size}\n${stats.mtime.getTime()}`;
99
+ return createHash('sha256').update(hashInput).digest('hex');
100
+ }
101
+ catch (error) {
102
+ logWarn('Failed to calculate file hash', {
103
+ file: filePath,
104
+ error: error.message,
105
+ });
106
+ return '';
107
+ }
108
+ }
109
+ /**
110
+ * Scan a directory and return files + extracted code chunks.
111
+ */
112
+ async scanDirectory(projectPath) {
113
+ const scanner = new CodeScanner();
114
+ const chunks = await scanner.scanDirectory(projectPath);
115
+ const files = [];
116
+ const seen = new Set();
117
+ for (const chunk of chunks) {
118
+ if (!seen.has(chunk.filePath)) {
119
+ seen.add(chunk.filePath);
120
+ const absPath = isAbsolute(chunk.filePath)
121
+ ? chunk.filePath
122
+ : join(projectPath, chunk.filePath);
123
+ const hash = await this.calculateFileHash(absPath);
124
+ files.push({ path: chunk.filePath, hash });
125
+ }
126
+ }
127
+ return { files, chunks };
128
+ }
129
+ /**
130
+ * Determine which files have changed compared to known hashes.
131
+ * Returns changed files plus their extracted code chunks.
132
+ */
133
+ async detectChangedFiles(projectPath, knownHashes) {
134
+ const allFiles = await this.readProjectFiles(projectPath);
135
+ const changed = [];
136
+ let skipped = 0;
137
+ for (const absPath of allFiles) {
138
+ try {
139
+ const hash = await this.calculateFileHash(absPath);
140
+ const relPath = relative(projectPath, absPath);
141
+ const known = knownHashes.get(absPath) ?? knownHashes.get(relPath);
142
+ if (!known || known !== hash) {
143
+ changed.push({ path: absPath, hash });
144
+ }
145
+ else {
146
+ skipped++;
147
+ }
148
+ }
149
+ catch (error) {
150
+ logWarn('Failed to process file for incremental scan', {
151
+ file: absPath,
152
+ error: error.message,
153
+ });
154
+ }
155
+ }
156
+ logInfo('Incremental scan analysis', {
157
+ totalFiles: allFiles.length,
158
+ filesToScan: changed.length,
159
+ filesSkipped: skipped,
160
+ });
161
+ if (changed.length === 0) {
162
+ return { changed: [], chunks: [], skipped };
163
+ }
164
+ const scanner = new CodeScanner();
165
+ const chunks = await scanner.scanFiles(changed.map((f) => f.path), projectPath);
166
+ return { changed, chunks, skipped };
167
+ }
168
+ /**
169
+ * Read file content with timeout protection.
170
+ */
171
+ async readFileContent(filePath) {
172
+ try {
173
+ return await withTimeout(readFile(filePath, 'utf-8'), FILE_OP_TIMEOUT_MS, `readFile timed out: ${filePath}`);
174
+ }
175
+ catch {
176
+ return null;
177
+ }
178
+ }
179
+ /**
180
+ * Stat a file with timeout protection.
181
+ */
182
+ async statFile(filePath) {
183
+ try {
184
+ const s = await withTimeout(stat(filePath), FILE_OP_TIMEOUT_MS, `stat timed out: ${filePath}`);
185
+ return { mtime: s.mtime, size: s.size };
186
+ }
187
+ catch {
188
+ return null;
189
+ }
190
+ }
191
+ // ── private helpers ─────────────────────────────────────────────────
192
+ async traverseDirectory(dirPath, files) {
193
+ try {
194
+ const entries = await withTimeout(readdir(dirPath, { withFileTypes: true }), FILE_OP_TIMEOUT_MS, `readdir timed out: ${dirPath}`);
195
+ for (const entry of entries) {
196
+ const fullPath = join(dirPath, entry.name);
197
+ if (entry.isDirectory()) {
198
+ if (SKIP_DIRS.has(entry.name))
199
+ continue;
200
+ await this.traverseDirectory(fullPath, files);
201
+ }
202
+ else if (entry.isFile() && this.isTextFile(entry.name)) {
203
+ try {
204
+ const fileStat = await withTimeout(stat(fullPath), FILE_OP_TIMEOUT_MS, `stat timed out: ${fullPath}`);
205
+ if (fileStat.size <= 100 * 1024) {
206
+ files.push(fullPath);
207
+ }
208
+ }
209
+ catch {
210
+ // can't stat → skip
211
+ }
212
+ }
213
+ }
214
+ }
215
+ catch (error) {
216
+ logWarn('Failed to read directory', {
217
+ path: dirPath,
218
+ error: error.message,
219
+ });
220
+ }
221
+ }
222
+ isTextFile(filename) {
223
+ if (SKIP_PATTERNS.some((p) => filename.endsWith(p)))
224
+ return false;
225
+ const ext = filename.split('.').pop()?.toLowerCase();
226
+ return TEXT_EXTENSIONS.has(ext || '');
227
+ }
228
+ }
229
+ /** Singleton for convenience */
230
+ let _instance = null;
231
+ export function getFileSystemReader() {
232
+ if (!_instance)
233
+ _instance = new FileSystemReader();
234
+ return _instance;
235
+ }
236
+ //# sourceMappingURL=FileSystemReader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FileSystemReader.js","sourceRoot":"","sources":["../src/FileSystemReader.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare function withTimeout<T>(promise: Promise<T>, timeoutMs: number, timeoutMessage?: string): Promise<T>;
2
+ //# sourceMappingURL=asyncUtils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"asyncUtils.d.ts","sourceRoot":"","sources":["../src/asyncUtils.ts"],"names":[],"mappings":"AAAA,wBAAgB,WAAW,CAAC,CAAC,EAC3B,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,EACnB,SAAS,EAAE,MAAM,EACjB,cAAc,CAAC,EAAE,MAAM,GACtB,OAAO,CAAC,CAAC,CAAC,CAWZ"}
@@ -0,0 +1,12 @@
1
+ export function withTimeout(promise, timeoutMs, timeoutMessage) {
2
+ let timer;
3
+ const timeoutPromise = new Promise((_resolve, reject) => {
4
+ timer = setTimeout(() => {
5
+ reject(new Error(timeoutMessage ?? `Operation timed out after ${timeoutMs}ms`));
6
+ }, timeoutMs);
7
+ });
8
+ return Promise.race([promise, timeoutPromise]).finally(() => {
9
+ clearTimeout(timer);
10
+ });
11
+ }
12
+ //# sourceMappingURL=asyncUtils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"asyncUtils.js","sourceRoot":"","sources":["../src/asyncUtils.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,WAAW,CACzB,OAAmB,EACnB,SAAiB,EACjB,cAAuB;IAEvB,IAAI,KAAoC,CAAC;IACzC,MAAM,cAAc,GAAG,IAAI,OAAO,CAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE,EAAE;QAC7D,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE;YACtB,MAAM,CAAC,IAAI,KAAK,CAAC,cAAc,IAAI,6BAA6B,SAAS,IAAI,CAAC,CAAC,CAAC;QAClF,CAAC,EAAE,SAAS,CAAC,CAAC;IAChB,CAAC,CAAC,CAAC;IAEH,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,cAAc,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE;QAC1D,YAAY,CAAC,KAAK,CAAC,CAAC;IACtB,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,96 @@
1
+ /**
2
+ * Code Scanner - Parse and chunk source files for embedding
3
+ */
4
+ export interface CodeChunk {
5
+ content: string;
6
+ filePath: string;
7
+ language: string;
8
+ startLine: number;
9
+ endLine: number;
10
+ chunkType: 'function' | 'class' | 'module' | 'raw';
11
+ contentHash: string;
12
+ metadata: {
13
+ fileName: string;
14
+ extension: string;
15
+ size: number;
16
+ signature?: string;
17
+ symbolName?: string;
18
+ };
19
+ }
20
+ export interface ScanOptions {
21
+ maxChunkSize?: number;
22
+ minChunkSize?: number;
23
+ ignorePatterns?: string[];
24
+ includeExtensions?: string[];
25
+ }
26
+ export declare class CodeScanner {
27
+ private options;
28
+ constructor(options?: ScanOptions);
29
+ /**
30
+ * Maximum directory depth for recursive scanning
31
+ * v2.43: Prevents runaway recursion on deep/symlinked structures
32
+ */
33
+ private static readonly MAX_DEPTH;
34
+ /**
35
+ * Scan a directory recursively and extract code chunks
36
+ * v2.43: Added max depth (10) to prevent infinite recursion
37
+ */
38
+ scanDirectory(rootPath: string): Promise<CodeChunk[]>;
39
+ /**
40
+ * Scan specific files and extract code chunks.
41
+ * Pass rootPath to compute proper relative file paths in chunk metadata.
42
+ */
43
+ scanFiles(filePaths: string[], rootPath: string): Promise<CodeChunk[]>;
44
+ /**
45
+ * Recursively traverse directory
46
+ * v2.43: Added depth parameter with max limit
47
+ */
48
+ private traverseDirectory;
49
+ /**
50
+ * Check if path should be ignored
51
+ * v2.71: Fixed glob-to-regex conversion and substring matching.
52
+ * - Escape regex special chars before replacing * with .*
53
+ * - Replace ALL * occurrences (not just the first)
54
+ * - For non-glob patterns, match on path segments to avoid false positives
55
+ * (e.g., '.env' should not match '.environment.ts')
56
+ */
57
+ private shouldIgnore;
58
+ /**
59
+ * Parse a file and extract code chunks
60
+ * v2.43: Added 10MB file size limit
61
+ */
62
+ private static readonly MAX_FILE_SIZE;
63
+ private parseFile;
64
+ /**
65
+ * Detect language from file extension
66
+ */
67
+ private detectLanguage;
68
+ /**
69
+ * Chunk markdown files by headers
70
+ */
71
+ private chunkMarkdown;
72
+ /**
73
+ * Find the index of the closing brace matching the opening brace at openIndex.
74
+ * Handles nested braces. Skips braces inside string literals, template literals,
75
+ * single-line comments, multi-line comments, and regex literals.
76
+ */
77
+ private findMatchingBrace;
78
+ /**
79
+ * Extract structured chunks (functions, classes)
80
+ * v2.76: Uses brace-matching for TS/JS/Rust so nested braces are not truncated at first \n}
81
+ */
82
+ private extractStructuredChunks;
83
+ /**
84
+ * Get regex patterns for language
85
+ */
86
+ private getLanguagePatterns;
87
+ /**
88
+ * Fall back to raw chunking with overlap
89
+ */
90
+ private chunkRaw;
91
+ /**
92
+ * Generate content hash for drift detection
93
+ */
94
+ private hash;
95
+ }
96
+ //# sourceMappingURL=codeScanner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codeScanner.d.ts","sourceRoot":"","sources":["../src/codeScanner.ts"],"names":[],"mappings":"AAAA;;GAEG;AAaH,MAAM,WAAW,SAAS;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,UAAU,GAAG,OAAO,GAAG,QAAQ,GAAG,KAAK,CAAC;IACnD,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE;QACR,QAAQ,EAAE,MAAM,CAAC;QACjB,SAAS,EAAE,MAAM,CAAC;QAClB,IAAI,EAAE,MAAM,CAAC;QACb,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,UAAU,CAAC,EAAE,MAAM,CAAC;KACrB,CAAC;CACH;AAED,MAAM,WAAW,WAAW;IAC1B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;CAC9B;AA8DD,qBAAa,WAAW;IACtB,OAAO,CAAC,OAAO,CAAwB;gBAE3B,OAAO,GAAE,WAAgB;IAIrC;;;OAGG;IACH,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAM;IAEvC;;;OAGG;IACG,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC;IAM3D;;;OAGG;IACG,SAAS,CAAC,SAAS,EAAE,MAAM,EAAE,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC;IAsB5E;;;OAGG;YACW,iBAAiB;IA+D/B;;;;;;;OAOG;IACH,OAAO,CAAC,YAAY;IAepB;;;OAGG;IACH,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,aAAa,CAAoB;YAE3C,SAAS;IAyFvB;;OAEG;IACH,OAAO,CAAC,cAAc;IAwBtB;;OAEG;IACH,OAAO,CAAC,aAAa;IAoFrB;;;;OAIG;IACH,OAAO,CAAC,iBAAiB;IA0GzB;;;OAGG;IACH,OAAO,CAAC,uBAAuB;IAoE/B;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAqD3B;;OAEG;IACH,OAAO,CAAC,QAAQ;IA+BhB;;OAEG;IACH,OAAO,CAAC,IAAI;CAGb"}