@mrxkun/mcfast-mcp 4.1.10 → 4.1.11
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/package.json +2 -2
- package/src/index.js +176 -21
- package/src/memory/memory-engine.js +213 -13
- package/src/memory/stores/base-database.js +223 -0
- package/src/memory/utils/chunker.js +1 -0
- package/src/memory/utils/indexer.js +110 -4
- package/src/memory/utils/logger.js +162 -0
- package/src/memory/utils/vector-index.js +241 -0
- package/src/memory/watchers/file-watcher.js +255 -103
- package/src/tools/project_analyze.js +491 -0
- package/src/utils/audit-queue.js +1 -0
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base Database Class
|
|
3
|
+
* Common methods for MemoryDatabase and CodebaseDatabase
|
|
4
|
+
* Reduces code duplication between the two database classes
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import Database from 'better-sqlite3';
|
|
8
|
+
import path from 'path';
|
|
9
|
+
import fs from 'fs/promises';
|
|
10
|
+
|
|
11
|
+
export class BaseDatabase {
|
|
12
|
+
constructor(dbPath = null, options = {}) {
|
|
13
|
+
this.dbPath = dbPath;
|
|
14
|
+
this.db = null;
|
|
15
|
+
this.isInitialized = false;
|
|
16
|
+
this.options = options;
|
|
17
|
+
|
|
18
|
+
// Logger (can be replaced with proper logger)
|
|
19
|
+
this.logger = options.logger || console;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
async initialize() {
|
|
23
|
+
if (this.isInitialized) return;
|
|
24
|
+
|
|
25
|
+
await fs.mkdir(path.dirname(this.dbPath), { recursive: true });
|
|
26
|
+
|
|
27
|
+
this.db = new Database(this.dbPath);
|
|
28
|
+
this.db.pragma('journal_mode = WAL');
|
|
29
|
+
|
|
30
|
+
this.createTables();
|
|
31
|
+
this.isInitialized = true;
|
|
32
|
+
|
|
33
|
+
this._log(`Initialized at: ${this.dbPath}`);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Override in subclass to create specific tables
|
|
38
|
+
*/
|
|
39
|
+
createTables() {
|
|
40
|
+
throw new Error('createTables must be implemented in subclass');
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Common chunk operations
|
|
45
|
+
*/
|
|
46
|
+
insertChunk(chunk) {
|
|
47
|
+
throw new Error('insertChunk must be implemented in subclass');
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
deleteChunksByFile(filePath) {
|
|
51
|
+
throw new Error('deleteChunksByFile must be implemented in subclass');
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
getChunksByFile(filePath, limit = 100) {
|
|
55
|
+
throw new Error('getChunksByFile must be implemented in subclass');
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
getRecentChunks(limit = 100) {
|
|
59
|
+
throw new Error('getRecentChunks must be implemented in subclass');
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Common embedding operations
|
|
64
|
+
*/
|
|
65
|
+
insertEmbedding(embedding) {
|
|
66
|
+
throw new Error('insertEmbedding must be implemented in subclass');
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
getEmbedding(chunkId) {
|
|
70
|
+
throw new Error('getEmbedding must be implemented in subclass');
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
getAllEmbeddings() {
|
|
74
|
+
throw new Error('getAllEmbeddings must be implemented in subclass');
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Common search operations (FTS5)
|
|
79
|
+
*/
|
|
80
|
+
searchFTS(query, limit = 20) {
|
|
81
|
+
const startTime = performance.now();
|
|
82
|
+
|
|
83
|
+
const stmt = this.db.prepare(`
|
|
84
|
+
SELECT
|
|
85
|
+
c.*,
|
|
86
|
+
rank as bm25_score
|
|
87
|
+
FROM chunks_fts fts
|
|
88
|
+
JOIN chunks c ON fts.rowid = c.id
|
|
89
|
+
WHERE chunks_fts MATCH ?
|
|
90
|
+
ORDER BY rank
|
|
91
|
+
LIMIT ?
|
|
92
|
+
`);
|
|
93
|
+
|
|
94
|
+
const results = stmt.all(query, limit);
|
|
95
|
+
const duration = performance.now() - startTime;
|
|
96
|
+
|
|
97
|
+
// Log search
|
|
98
|
+
this.logSearch(query, 'fts', results.length, duration);
|
|
99
|
+
|
|
100
|
+
return {
|
|
101
|
+
results: results.map(r => ({
|
|
102
|
+
...r,
|
|
103
|
+
score: 1 / (1 + Math.max(0, r.bm25_score))
|
|
104
|
+
})),
|
|
105
|
+
metadata: {
|
|
106
|
+
method: 'fts5',
|
|
107
|
+
duration: duration.toFixed(2) + 'ms',
|
|
108
|
+
candidates: results.length
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Common search history logging
|
|
115
|
+
*/
|
|
116
|
+
logSearch(query, method, resultsCount, durationMs) {
|
|
117
|
+
try {
|
|
118
|
+
const stmt = this.db.prepare(`
|
|
119
|
+
INSERT INTO search_history (query, method, results_count, duration_ms, timestamp)
|
|
120
|
+
VALUES (?, ?, ?, ?, ?)
|
|
121
|
+
`);
|
|
122
|
+
stmt.run(query, method, resultsCount, Math.round(durationMs), Date.now());
|
|
123
|
+
} catch (error) {
|
|
124
|
+
// Silent fail - don't break search for logging
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
getSearchStats(days = 7) {
|
|
129
|
+
const since = Date.now() - (days * 24 * 60 * 60 * 1000);
|
|
130
|
+
return this.db.prepare(`
|
|
131
|
+
SELECT
|
|
132
|
+
method,
|
|
133
|
+
COUNT(*) as count,
|
|
134
|
+
AVG(duration_ms) as avg_duration,
|
|
135
|
+
AVG(results_count) as avg_results
|
|
136
|
+
FROM search_history
|
|
137
|
+
WHERE timestamp > ?
|
|
138
|
+
GROUP BY method
|
|
139
|
+
`).all(since);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Common file tracking operations
|
|
144
|
+
*/
|
|
145
|
+
upsertFile(file) {
|
|
146
|
+
throw new Error('upsertFile must be implemented in subclass');
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
getFile(filePath) {
|
|
150
|
+
throw new Error('getFile must be implemented in subclass');
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
isFileIndexed(filePath, contentHash) {
|
|
154
|
+
const file = this.getFile(filePath);
|
|
155
|
+
return file && file.content_hash === contentHash;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
deleteFile(filePath) {
|
|
159
|
+
throw new Error('deleteFile must be implemented in subclass');
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Common stats
|
|
164
|
+
*/
|
|
165
|
+
getStats() {
|
|
166
|
+
throw new Error('getStats must be implemented in subclass');
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Maintenance
|
|
171
|
+
*/
|
|
172
|
+
vacuum() {
|
|
173
|
+
this.db.exec('VACUUM');
|
|
174
|
+
this.db.exec('ANALYZE');
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
close() {
|
|
178
|
+
if (this.db) {
|
|
179
|
+
this.db.close();
|
|
180
|
+
this.isInitialized = false;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Internal logger
|
|
186
|
+
*/
|
|
187
|
+
_log(message, level = 'info') {
|
|
188
|
+
const prefix = `[${this.constructor.name}]`;
|
|
189
|
+
if (level === 'error') {
|
|
190
|
+
console.error(`${prefix} ${message}`);
|
|
191
|
+
} else if (level === 'warn') {
|
|
192
|
+
console.warn(`${prefix} ${message}`);
|
|
193
|
+
} else {
|
|
194
|
+
console.error(`${prefix} ${message}`);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Safe execute with error handling
|
|
200
|
+
*/
|
|
201
|
+
safeExecute(fn, errorMessage = 'Operation failed') {
|
|
202
|
+
try {
|
|
203
|
+
return fn();
|
|
204
|
+
} catch (error) {
|
|
205
|
+
this._log(`${errorMessage}: ${error.message}`, 'error');
|
|
206
|
+
return null;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* Safe async execute with error handling
|
|
212
|
+
*/
|
|
213
|
+
async safeExecuteAsync(fn, errorMessage = 'Operation failed') {
|
|
214
|
+
try {
|
|
215
|
+
return await fn();
|
|
216
|
+
} catch (error) {
|
|
217
|
+
this._log(`${errorMessage}: ${error.message}`, 'error');
|
|
218
|
+
return null;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
export default BaseDatabase;
|
|
@@ -77,6 +77,7 @@ export class Chunker {
|
|
|
77
77
|
id: this.generateChunkId(filePath, startLine),
|
|
78
78
|
file_id: this.generateFileId(filePath),
|
|
79
79
|
content: content,
|
|
80
|
+
content_hash: crypto.createHash('md5').update(content).digest('hex'),
|
|
80
81
|
start_line: startLine,
|
|
81
82
|
end_line: endLine,
|
|
82
83
|
token_count: tokens
|
|
@@ -59,12 +59,12 @@ export class CodeIndexer {
|
|
|
59
59
|
const fileId = this.generateFileId(filePath);
|
|
60
60
|
|
|
61
61
|
try {
|
|
62
|
-
//
|
|
62
|
+
// Try tree-sitter query first (for functions)
|
|
63
63
|
const query = await getQuery(language, 'definitions');
|
|
64
|
-
|
|
65
|
-
if (query) {
|
|
64
|
+
|
|
65
|
+
if (query && ast?.rootNode) {
|
|
66
66
|
const captures = query.captures(ast.rootNode);
|
|
67
|
-
|
|
67
|
+
|
|
68
68
|
for (const capture of captures) {
|
|
69
69
|
if (capture.name === 'name' || capture.name === 'function') {
|
|
70
70
|
facts.push({
|
|
@@ -81,6 +81,95 @@ export class CodeIndexer {
|
|
|
81
81
|
}
|
|
82
82
|
}
|
|
83
83
|
}
|
|
84
|
+
|
|
85
|
+
// Fallback/enhancement: Extract more facts using regex patterns
|
|
86
|
+
// This works across languages and captures additional symbols
|
|
87
|
+
const content = ast?.text || '';
|
|
88
|
+
|
|
89
|
+
// Extract classes
|
|
90
|
+
const classMatches = content.matchAll(/class\s+(\w+)(?:\s+extends\s+(\w+))?/g);
|
|
91
|
+
for (const match of classMatches) {
|
|
92
|
+
if (!facts.find(f => f.type === 'class' && f.name === match[1])) {
|
|
93
|
+
facts.push({
|
|
94
|
+
id: this.generateFactId(fileId, match[1], 'class'),
|
|
95
|
+
file_id: fileId,
|
|
96
|
+
type: 'class',
|
|
97
|
+
name: match[1],
|
|
98
|
+
line_start: this.findLineNumber(content, match[0]) || 0,
|
|
99
|
+
line_end: 0,
|
|
100
|
+
signature: match[2] ? `extends ${match[2]}` : '',
|
|
101
|
+
exported: this.isExported(content, match[1]),
|
|
102
|
+
confidence: 0.9
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Extract interfaces (TypeScript)
|
|
108
|
+
if (language === 'typescript') {
|
|
109
|
+
const interfaceMatches = content.matchAll(/interface\s+(\w+)(?:\s+extends\s+([^{]+))?/g);
|
|
110
|
+
for (const match of interfaceMatches) {
|
|
111
|
+
if (!facts.find(f => f.type === 'interface' && f.name === match[1])) {
|
|
112
|
+
facts.push({
|
|
113
|
+
id: this.generateFactId(fileId, match[1], 'interface'),
|
|
114
|
+
file_id: fileId,
|
|
115
|
+
type: 'interface',
|
|
116
|
+
name: match[1],
|
|
117
|
+
line_start: this.findLineNumber(content, match[0]) || 0,
|
|
118
|
+
line_end: 0,
|
|
119
|
+
signature: match[2] ? `extends ${match[2].trim()}` : '',
|
|
120
|
+
exported: this.isExported(content, match[1]),
|
|
121
|
+
confidence: 0.9
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Extract imports
|
|
128
|
+
const importMatches = content.matchAll(/import\s+(?:(\w+)|\{\s*([^}]+)\s*\}|\*\s+as\s+(\w+))\s+from\s+['"]([^'"]+)['"]/g);
|
|
129
|
+
for (const match of importMatches) {
|
|
130
|
+
const imported = match[1] || match[2]?.split(',').map(s => s.trim().split(' ')[0]).join(', ') || match[3];
|
|
131
|
+
facts.push({
|
|
132
|
+
id: this.generateFactId(fileId, imported, 'import'),
|
|
133
|
+
file_id: fileId,
|
|
134
|
+
type: 'import',
|
|
135
|
+
name: imported,
|
|
136
|
+
line_start: this.findLineNumber(content, match[0]) || 0,
|
|
137
|
+
line_end: 0,
|
|
138
|
+
signature: match[4],
|
|
139
|
+
exported: false,
|
|
140
|
+
confidence: 1.0
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// Extract exports
|
|
145
|
+
const exportMatches = content.matchAll(/export\s+(?:default\s+)?(?:const|let|var|function|class|interface|type)\s+(\w+)/g);
|
|
146
|
+
for (const match of exportMatches) {
|
|
147
|
+
if (!facts.find(f => f.name === match[1] && f.exported)) {
|
|
148
|
+
const existing = facts.find(f => f.name === match[1]);
|
|
149
|
+
if (existing) {
|
|
150
|
+
existing.exported = true;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// Extract type definitions (TypeScript)
|
|
156
|
+
if (language === 'typescript') {
|
|
157
|
+
const typeMatches = content.matchAll(/type\s+(\w+)\s*=/g);
|
|
158
|
+
for (const match of typeMatches) {
|
|
159
|
+
facts.push({
|
|
160
|
+
id: this.generateFactId(fileId, match[1], 'type'),
|
|
161
|
+
file_id: fileId,
|
|
162
|
+
type: 'type',
|
|
163
|
+
name: match[1],
|
|
164
|
+
line_start: this.findLineNumber(content, match[0]) || 0,
|
|
165
|
+
line_end: 0,
|
|
166
|
+
signature: 'type alias',
|
|
167
|
+
exported: this.isExported(content, match[1]),
|
|
168
|
+
confidence: 0.8
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
84
173
|
} catch (error) {
|
|
85
174
|
console.warn(`[Indexer] Failed to extract facts:`, error.message);
|
|
86
175
|
}
|
|
@@ -88,6 +177,23 @@ export class CodeIndexer {
|
|
|
88
177
|
return facts;
|
|
89
178
|
}
|
|
90
179
|
|
|
180
|
+
// Helper to find line number of a string in content
|
|
181
|
+
findLineNumber(content, searchStr) {
|
|
182
|
+
const lines = content.split('\n');
|
|
183
|
+
for (let i = 0; i < lines.length; i++) {
|
|
184
|
+
if (lines[i].includes(searchStr)) {
|
|
185
|
+
return i + 1;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
return 0;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// Check if a symbol is exported
|
|
192
|
+
isExported(content, symbolName) {
|
|
193
|
+
return new RegExp(`export\\s+.*\\b${symbolName}\\b`).test(content) ||
|
|
194
|
+
new RegExp(`export\\s+default`).test(content);
|
|
195
|
+
}
|
|
196
|
+
|
|
91
197
|
async generateEmbeddings(chunks, language = 'javascript') {
|
|
92
198
|
const embeddings = [];
|
|
93
199
|
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Logger Utility for Memory System
|
|
3
|
+
* Provides structured logging with different levels
|
|
4
|
+
*
|
|
5
|
+
* Features:
|
|
6
|
+
* - Log levels: debug, info, warn, error
|
|
7
|
+
* - Timestamp formatting
|
|
8
|
+
* - Module context
|
|
9
|
+
* - Configurable output
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
const LOG_LEVELS = {
|
|
13
|
+
debug: 0,
|
|
14
|
+
info: 1,
|
|
15
|
+
warn: 2,
|
|
16
|
+
error: 3
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
class Logger {
|
|
20
|
+
constructor(options = {}) {
|
|
21
|
+
this.module = options.module || 'Memory';
|
|
22
|
+
this.level = options.level || 'info';
|
|
23
|
+
this.prefix = options.prefix || '';
|
|
24
|
+
|
|
25
|
+
// Set minimum level
|
|
26
|
+
this.minLevel = LOG_LEVELS[options.minLevel?.toLowerCase()] ?? LOG_LEVELS.info;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Set log level
|
|
31
|
+
*/
|
|
32
|
+
setLevel(level) {
|
|
33
|
+
this.minLevel = LOG_LEVELS[level?.toLowerCase()] ?? LOG_LEVELS.info;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Format timestamp
|
|
38
|
+
*/
|
|
39
|
+
_formatTime() {
|
|
40
|
+
return new Date().toISOString();
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Format log message
|
|
45
|
+
*/
|
|
46
|
+
_format(level, message, data = null) {
|
|
47
|
+
const timestamp = this._formatTime();
|
|
48
|
+
const context = this.prefix ? `[${this.prefix}]` : `[${this.module}]`;
|
|
49
|
+
|
|
50
|
+
let formatted = `${timestamp} ${context} ${level.toUpperCase()}: ${message}`;
|
|
51
|
+
|
|
52
|
+
if (data) {
|
|
53
|
+
if (data instanceof Error) {
|
|
54
|
+
formatted += `\n Stack: ${data.stack}`;
|
|
55
|
+
} else if (typeof data === 'object') {
|
|
56
|
+
formatted += `\n Data: ${JSON.stringify(data, null, 2)}`;
|
|
57
|
+
} else {
|
|
58
|
+
formatted += `\n ${data}`;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return formatted;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Debug level logging
|
|
67
|
+
*/
|
|
68
|
+
debug(message, data = null) {
|
|
69
|
+
if (this.minLevel > LOG_LEVELS.debug) return;
|
|
70
|
+
console.error(this._format('debug', message, data));
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Info level logging
|
|
75
|
+
*/
|
|
76
|
+
info(message, data = null) {
|
|
77
|
+
if (this.minLevel > LOG_LEVELS.info) return;
|
|
78
|
+
console.error(this._format('info', message, data));
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Warn level logging
|
|
83
|
+
*/
|
|
84
|
+
warn(message, data = null) {
|
|
85
|
+
if (this.minLevel > LOG_LEVELS.warn) return;
|
|
86
|
+
console.error(this._format('warn', message, data));
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Error level logging
|
|
91
|
+
*/
|
|
92
|
+
error(message, data = null) {
|
|
93
|
+
if (this.minLevel > LOG_LEVELS.error) return;
|
|
94
|
+
console.error(this._format('error', message, data));
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Create child logger with additional context
|
|
99
|
+
*/
|
|
100
|
+
child(options = {}) {
|
|
101
|
+
return new Logger({
|
|
102
|
+
...options,
|
|
103
|
+
module: this.module,
|
|
104
|
+
minLevel: Object.keys(LOG_LEVELS).find(key => LOG_LEVELS[key] === this.minLevel)
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Timer for performance tracking
|
|
110
|
+
*/
|
|
111
|
+
timer(label = 'operation') {
|
|
112
|
+
return new Timer(this, label);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Timer class for performance tracking
|
|
118
|
+
*/
|
|
119
|
+
class Timer {
|
|
120
|
+
constructor(logger, label) {
|
|
121
|
+
this.logger = logger;
|
|
122
|
+
this.label = label;
|
|
123
|
+
this.start = performance.now();
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
end() {
|
|
127
|
+
const duration = performance.now() - this.start;
|
|
128
|
+
this.logger.debug(`${this.label} completed in ${duration.toFixed(2)}ms`);
|
|
129
|
+
return duration;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// Pre-configured loggers for common modules
|
|
134
|
+
export const loggers = {
|
|
135
|
+
memory: new Logger({ module: 'MemoryEngine', minLevel: 'info' }),
|
|
136
|
+
watcher: new Logger({ module: 'FileWatcher', minLevel: 'info' }),
|
|
137
|
+
indexer: new Logger({ module: 'Indexer', minLevel: 'info' }),
|
|
138
|
+
database: new Logger({ module: 'Database', minLevel: 'info' }),
|
|
139
|
+
embedder: new Logger({ module: 'Embedder', minLevel: 'info' }),
|
|
140
|
+
intelligence: new Logger({ module: 'Intelligence', minLevel: 'info' })
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Get logger for specific module
|
|
145
|
+
*/
|
|
146
|
+
export function getLogger(module, options = {}) {
|
|
147
|
+
if (loggers[module]) {
|
|
148
|
+
return loggers[module].child(options);
|
|
149
|
+
}
|
|
150
|
+
return new Logger({ module, ...options });
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Set global log level
|
|
155
|
+
*/
|
|
156
|
+
export function setGlobalLevel(level) {
|
|
157
|
+
Object.values(loggers).forEach(logger => {
|
|
158
|
+
logger.setLevel(level);
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
export default Logger;
|