@mrxkun/mcfast-mcp 4.0.1 → 4.0.3
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/README.md +59 -3
- package/package.json +2 -2
- package/src/index.js +476 -322
- package/src/intelligence/index.js +12 -0
- package/src/intelligence/pattern-detector.js +338 -0
- package/src/intelligence/strategy-selector.js +362 -0
- package/src/intelligence/suggestion-engine.js +489 -0
- package/src/memory/index.js +3 -0
- package/src/memory/memory-engine.js +150 -4
- package/src/memory/utils/chunker.js +5 -2
- package/src/memory/utils/sync-engine.js +32 -17
- package/src/tools/memory_get.js +311 -204
- package/src/tools/memory_search.js +170 -251
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Sync Engine
|
|
3
3
|
* Local ↔ Cloud synchronization for memory
|
|
4
|
+
* Uses MCFAST_TOKEN for authentication (same as Dashboard)
|
|
4
5
|
*/
|
|
5
6
|
|
|
6
7
|
import fs from 'fs';
|
|
@@ -11,8 +12,11 @@ import crypto from 'crypto';
|
|
|
11
12
|
export class SyncEngine {
|
|
12
13
|
constructor(options = {}) {
|
|
13
14
|
this.memoryPath = options.memoryPath || path.join(os.homedir(), '.mcfast', 'memory');
|
|
14
|
-
|
|
15
|
-
|
|
15
|
+
|
|
16
|
+
// Use Dashboard URL for sync (same as DashboardClient)
|
|
17
|
+
this.baseUrl = options.baseUrl || process.env.MCFAST_DASHBOARD_URL || 'https://mcfast.vercel.app';
|
|
18
|
+
this.apiKey = options.apiKey || process.env.MCFAST_TOKEN;
|
|
19
|
+
|
|
16
20
|
this.syncInterval = options.syncInterval || 5 * 60 * 1000; // 5 minutes
|
|
17
21
|
this.lastSyncTime = null;
|
|
18
22
|
this.syncQueue = [];
|
|
@@ -28,6 +32,17 @@ export class SyncEngine {
|
|
|
28
32
|
}
|
|
29
33
|
}
|
|
30
34
|
|
|
35
|
+
/**
|
|
36
|
+
* Get headers for API calls
|
|
37
|
+
*/
|
|
38
|
+
getHeaders() {
|
|
39
|
+
return {
|
|
40
|
+
'Content-Type': 'application/json',
|
|
41
|
+
'Authorization': `Bearer ${this.apiKey}`,
|
|
42
|
+
'X-MCP-Client': 'mcfast-mcp-v4'
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
|
|
31
46
|
/**
|
|
32
47
|
* Initialize sync engine
|
|
33
48
|
*/
|
|
@@ -144,8 +159,8 @@ export class SyncEngine {
|
|
|
144
159
|
* Perform sync
|
|
145
160
|
*/
|
|
146
161
|
async sync() {
|
|
147
|
-
if (!this.isOnline || this.isSyncing || !this.
|
|
148
|
-
return { status: this.isOnline ? 'idle' : 'offline', queued: this.syncQueue.length };
|
|
162
|
+
if (!this.isOnline || this.isSyncing || !this.apiKey) {
|
|
163
|
+
return { status: !this.apiKey ? 'no_token' : this.isOnline ? 'idle' : 'offline', queued: this.syncQueue.length };
|
|
149
164
|
}
|
|
150
165
|
|
|
151
166
|
this.isSyncing = true;
|
|
@@ -155,7 +170,7 @@ export class SyncEngine {
|
|
|
155
170
|
// 1. Get local changes since last sync
|
|
156
171
|
const localChanges = await this.getLocalChanges();
|
|
157
172
|
|
|
158
|
-
// 2. Push local changes to cloud
|
|
173
|
+
// 2. Push local changes to cloud (via Dashboard API)
|
|
159
174
|
if (localChanges.length > 0) {
|
|
160
175
|
await this.pushToCloud(localChanges);
|
|
161
176
|
}
|
|
@@ -233,15 +248,14 @@ export class SyncEngine {
|
|
|
233
248
|
}
|
|
234
249
|
|
|
235
250
|
/**
|
|
236
|
-
* Push changes to cloud
|
|
251
|
+
* Push changes to cloud via Dashboard API
|
|
237
252
|
*/
|
|
238
253
|
async pushToCloud(changes) {
|
|
239
|
-
const
|
|
254
|
+
const url = `${this.baseUrl}/api/v1/memory/sync/push`;
|
|
255
|
+
|
|
256
|
+
const response = await fetch(url, {
|
|
240
257
|
method: 'POST',
|
|
241
|
-
headers:
|
|
242
|
-
'Content-Type': 'application/json',
|
|
243
|
-
'Authorization': `Bearer ${this.apiKey}`
|
|
244
|
-
},
|
|
258
|
+
headers: this.getHeaders(),
|
|
245
259
|
body: JSON.stringify({
|
|
246
260
|
changes,
|
|
247
261
|
lastSyncTime: this.lastSyncTime
|
|
@@ -256,14 +270,14 @@ export class SyncEngine {
|
|
|
256
270
|
}
|
|
257
271
|
|
|
258
272
|
/**
|
|
259
|
-
* Pull changes from cloud
|
|
273
|
+
* Pull changes from cloud via Dashboard API
|
|
260
274
|
*/
|
|
261
275
|
async pullFromCloud() {
|
|
262
|
-
const
|
|
276
|
+
const url = `${this.baseUrl}/api/v1/memory/sync/pull?since=${this.lastSyncTime || 0}`;
|
|
277
|
+
|
|
278
|
+
const response = await fetch(url, {
|
|
263
279
|
method: 'GET',
|
|
264
|
-
headers:
|
|
265
|
-
'Authorization': `Bearer ${this.apiKey}`
|
|
266
|
-
}
|
|
280
|
+
headers: this.getHeaders()
|
|
267
281
|
});
|
|
268
282
|
|
|
269
283
|
if (!response.ok) {
|
|
@@ -327,7 +341,8 @@ export class SyncEngine {
|
|
|
327
341
|
isSyncing: this.isSyncing,
|
|
328
342
|
lastSyncTime: this.lastSyncTime,
|
|
329
343
|
queueLength: this.syncQueue.length,
|
|
330
|
-
syncInterval: this.syncInterval
|
|
344
|
+
syncInterval: this.syncInterval,
|
|
345
|
+
hasToken: !!this.apiKey
|
|
331
346
|
};
|
|
332
347
|
}
|
|
333
348
|
|
package/src/tools/memory_get.js
CHANGED
|
@@ -1,12 +1,27 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* memory_get Tool
|
|
3
|
-
* Read content from memory storage
|
|
4
|
-
* Version:
|
|
2
|
+
* memory_get Tool v2.0
|
|
3
|
+
* Read content from memory storage using MemoryEngine
|
|
4
|
+
* Version: 2.0.0
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
import fs from 'fs/promises';
|
|
8
|
+
import path from 'path';
|
|
9
|
+
import os from 'os';
|
|
10
|
+
import { MemoryEngine } from '../memory/index.js';
|
|
11
|
+
|
|
12
|
+
// Memory engine instance (initialized lazily)
|
|
13
|
+
let memoryEngine = null;
|
|
14
|
+
|
|
15
|
+
async function getMemoryEngine() {
|
|
16
|
+
if (!memoryEngine) {
|
|
17
|
+
memoryEngine = new MemoryEngine({
|
|
18
|
+
apiKey: process.env.MCFAST_TOKEN,
|
|
19
|
+
enableSync: true
|
|
20
|
+
});
|
|
21
|
+
await memoryEngine.initialize(process.cwd());
|
|
22
|
+
}
|
|
23
|
+
return memoryEngine;
|
|
24
|
+
}
|
|
10
25
|
|
|
11
26
|
/**
|
|
12
27
|
* Execute memory get
|
|
@@ -14,222 +29,314 @@ const os = require('os');
|
|
|
14
29
|
* @param {string} args.path - Path to memory file (relative to ~/.mcfast/memory/)
|
|
15
30
|
* @param {number} [args.from=1] - Start line
|
|
16
31
|
* @param {number} [args.lines=50] - Number of lines to read
|
|
17
|
-
* @param {Object} context - Runtime context
|
|
18
32
|
* @returns {Promise<Object>} File content
|
|
19
33
|
*/
|
|
20
|
-
async function execute(args
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
if (!relativePath) {
|
|
28
|
-
return {
|
|
29
|
-
content: [{
|
|
30
|
-
type: "text",
|
|
31
|
-
text: "❌ Error: 'path' parameter is required"
|
|
32
|
-
}],
|
|
33
|
-
isError: true
|
|
34
|
-
};
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
try {
|
|
38
|
-
// Security: Only allow reading from memory directory
|
|
39
|
-
if (!relativePath.startsWith('memory/') && !relativePath.startsWith('/')) {
|
|
40
|
-
return {
|
|
41
|
-
content: [{
|
|
42
|
-
type: "text",
|
|
43
|
-
text: "❌ Error: Invalid path. Must be in memory/ directory"
|
|
44
|
-
}],
|
|
45
|
-
isError: true
|
|
46
|
-
};
|
|
47
|
-
}
|
|
34
|
+
export async function execute(args) {
|
|
35
|
+
const {
|
|
36
|
+
path: relativePath,
|
|
37
|
+
from = 1,
|
|
38
|
+
lines = 50
|
|
39
|
+
} = args;
|
|
48
40
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
type: "text",
|
|
58
|
-
text: "❌ Error: Path traversal not allowed"
|
|
59
|
-
}],
|
|
60
|
-
isError: true
|
|
61
|
-
};
|
|
41
|
+
if (!relativePath) {
|
|
42
|
+
return {
|
|
43
|
+
content: [{
|
|
44
|
+
type: "text",
|
|
45
|
+
text: "❌ Error: 'path' parameter is required"
|
|
46
|
+
}],
|
|
47
|
+
isError: true
|
|
48
|
+
};
|
|
62
49
|
}
|
|
63
50
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
51
|
+
try {
|
|
52
|
+
// Special paths
|
|
53
|
+
if (relativePath === 'logs' || relativePath === 'memory/logs') {
|
|
54
|
+
return await getMemoryLogs(from, lines);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (relativePath === 'stats' || relativePath === 'memory/stats') {
|
|
58
|
+
return await getMemoryStats();
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (relativePath === 'today' || relativePath === 'memory/today') {
|
|
62
|
+
return await getTodayLog();
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if (relativePath === 'curated' || relativePath === 'memory/curated') {
|
|
66
|
+
return await getCuratedMemories();
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Security: Only allow reading from memory directory
|
|
70
|
+
if (!relativePath.startsWith('memory/') && !relativePath.startsWith('/')) {
|
|
71
|
+
return {
|
|
72
|
+
content: [{
|
|
73
|
+
type: "text",
|
|
74
|
+
text: "❌ Error: Invalid path. Must be in memory/ directory"
|
|
75
|
+
}],
|
|
76
|
+
isError: true
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Construct full path
|
|
81
|
+
const memoryDir = path.join(os.homedir(), '.mcfast', 'memory');
|
|
82
|
+
const fullPath = path.join(memoryDir, relativePath.replace(/^\//, ''));
|
|
83
|
+
|
|
84
|
+
// Security: Ensure path is within memory directory
|
|
85
|
+
if (!fullPath.startsWith(memoryDir)) {
|
|
86
|
+
return {
|
|
87
|
+
content: [{
|
|
88
|
+
type: "text",
|
|
89
|
+
text: "❌ Error: Path traversal not allowed"
|
|
90
|
+
}],
|
|
91
|
+
isError: true
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Check if file exists
|
|
96
|
+
try {
|
|
97
|
+
const stats = await fs.stat(fullPath);
|
|
98
|
+
if (!stats.isFile()) {
|
|
99
|
+
return {
|
|
100
|
+
content: [{
|
|
101
|
+
type: "text",
|
|
102
|
+
text: "❌ Path is not a file"
|
|
103
|
+
}],
|
|
104
|
+
isError: true
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
} catch (e) {
|
|
108
|
+
return {
|
|
109
|
+
content: [{
|
|
110
|
+
type: "text",
|
|
111
|
+
text: `❌ File not found: ${relativePath}`
|
|
112
|
+
}],
|
|
113
|
+
isError: true
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// Read file content
|
|
118
|
+
const content = await fs.readFile(fullPath, 'utf8');
|
|
119
|
+
const allLines = content.split('\n');
|
|
120
|
+
|
|
121
|
+
// Extract specific lines
|
|
122
|
+
const startLine = Math.max(1, from);
|
|
123
|
+
const endLine = Math.min(allLines.length, from - 1 + lines);
|
|
124
|
+
const extractedLines = allLines.slice(startLine - 1, endLine);
|
|
125
|
+
const extractedContent = extractedLines.join('\n');
|
|
126
|
+
|
|
127
|
+
// Format output
|
|
128
|
+
let output = `📄 Memory: ${relativePath}\n`;
|
|
129
|
+
output += `Lines: ${startLine}-${endLine} of ${allLines.length}\n`;
|
|
130
|
+
output += '─'.repeat(40) + '\n';
|
|
131
|
+
output += extractedContent;
|
|
132
|
+
|
|
133
|
+
return {
|
|
134
|
+
content: [{
|
|
135
|
+
type: "text",
|
|
136
|
+
text: output
|
|
137
|
+
}],
|
|
138
|
+
metadata: {
|
|
139
|
+
path: relativePath,
|
|
140
|
+
lines: extractedLines.length,
|
|
141
|
+
totalLines: allLines.length
|
|
142
|
+
}
|
|
143
|
+
};
|
|
144
|
+
} catch (error) {
|
|
145
|
+
console.error('[memory_get] Error:', error);
|
|
146
|
+
return {
|
|
147
|
+
content: [{
|
|
148
|
+
type: "text",
|
|
149
|
+
text: `❌ Error reading memory: ${error.message}`
|
|
150
|
+
}],
|
|
151
|
+
isError: true
|
|
152
|
+
};
|
|
82
153
|
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Get today's daily log
|
|
158
|
+
*/
|
|
159
|
+
async function getTodayLog() {
|
|
160
|
+
try {
|
|
161
|
+
const engine = await getMemoryEngine();
|
|
162
|
+
const todayLog = engine.getTodayLog();
|
|
163
|
+
|
|
164
|
+
if (!todayLog || todayLog.length === 0) {
|
|
165
|
+
return {
|
|
166
|
+
content: [{
|
|
167
|
+
type: "text",
|
|
168
|
+
text: "📝 No activity logged today"
|
|
169
|
+
}],
|
|
170
|
+
metadata: { empty: true }
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
let output = `📅 Today's Activity Log\n`;
|
|
175
|
+
output += '─'.repeat(40) + '\n\n';
|
|
176
|
+
output += todayLog;
|
|
83
177
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
178
|
+
return {
|
|
179
|
+
content: [{
|
|
180
|
+
type: "text",
|
|
181
|
+
text: output
|
|
182
|
+
}]
|
|
183
|
+
};
|
|
184
|
+
} catch (error) {
|
|
185
|
+
return {
|
|
186
|
+
content: [{
|
|
187
|
+
type: "text",
|
|
188
|
+
text: `❌ Error getting today's log: ${error.message}`
|
|
189
|
+
}],
|
|
190
|
+
isError: true
|
|
191
|
+
};
|
|
93
192
|
}
|
|
193
|
+
}
|
|
94
194
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
195
|
+
/**
|
|
196
|
+
* Get curated memories
|
|
197
|
+
*/
|
|
198
|
+
async function getCuratedMemories() {
|
|
199
|
+
try {
|
|
200
|
+
const engine = await getMemoryEngine();
|
|
201
|
+
const memories = engine.getCuratedMemories();
|
|
202
|
+
|
|
203
|
+
if (!memories || memories.length === 0) {
|
|
204
|
+
return {
|
|
205
|
+
content: [{
|
|
206
|
+
type: "text",
|
|
207
|
+
text: "📝 No curated memories found"
|
|
208
|
+
}],
|
|
209
|
+
metadata: { empty: true }
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
let output = `📚 Curated Memories\n`;
|
|
214
|
+
output += `Found: ${memories.length} memory(s)\n`;
|
|
215
|
+
output += '─'.repeat(40) + '\n\n';
|
|
216
|
+
|
|
217
|
+
memories.forEach((memory, idx) => {
|
|
218
|
+
output += `[${idx + 1}] ${memory.title}\n`;
|
|
219
|
+
output += `Tags: ${memory.tags?.join(', ') || 'none'}\n`;
|
|
220
|
+
output += `${memory.content?.substring(0, 200) || ''}...\n\n`;
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
return {
|
|
224
|
+
content: [{
|
|
225
|
+
type: "text",
|
|
226
|
+
text: output
|
|
227
|
+
}]
|
|
228
|
+
};
|
|
229
|
+
} catch (error) {
|
|
230
|
+
return {
|
|
231
|
+
content: [{
|
|
232
|
+
type: "text",
|
|
233
|
+
text: `❌ Error getting curated memories: ${error.message}`
|
|
234
|
+
}],
|
|
235
|
+
isError: true
|
|
236
|
+
};
|
|
237
|
+
}
|
|
132
238
|
}
|
|
133
239
|
|
|
134
240
|
/**
|
|
135
241
|
* Get memory logs (daily logs)
|
|
136
242
|
*/
|
|
137
|
-
async function getMemoryLogs(
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
243
|
+
async function getMemoryLogs(from, lines) {
|
|
244
|
+
const memoryDir = path.join(os.homedir(), '.mcfast', 'memory');
|
|
245
|
+
const logsDir = path.join(memoryDir, 'logs');
|
|
246
|
+
|
|
247
|
+
try {
|
|
248
|
+
const entries = await fs.readdir(logsDir);
|
|
249
|
+
const logFiles = entries
|
|
250
|
+
.filter(f => f.endsWith('.md'))
|
|
251
|
+
.sort()
|
|
252
|
+
.reverse();
|
|
253
|
+
|
|
254
|
+
if (logFiles.length === 0) {
|
|
255
|
+
return {
|
|
256
|
+
content: [{
|
|
257
|
+
type: "text",
|
|
258
|
+
text: "📝 No memory logs found"
|
|
259
|
+
}],
|
|
260
|
+
metadata: { empty: true }
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
// Read latest logs
|
|
265
|
+
let output = `📝 Memory Logs\n`;
|
|
266
|
+
output += `Found: ${logFiles.length} log file(s)\n`;
|
|
267
|
+
output += '─'.repeat(40) + '\n\n';
|
|
268
|
+
|
|
269
|
+
const filesToRead = logFiles.slice(0, 5);
|
|
270
|
+
for (const file of filesToRead) {
|
|
271
|
+
const filePath = path.join(logsDir, file);
|
|
272
|
+
const content = await fs.readFile(filePath, 'utf8');
|
|
273
|
+
const fileLines = content.split('\n').slice(0, 20);
|
|
274
|
+
|
|
275
|
+
output += `📅 ${file.replace('.md', '')}\n`;
|
|
276
|
+
output += fileLines.join('\n');
|
|
277
|
+
output += '\n\n---\n\n';
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
return {
|
|
281
|
+
content: [{
|
|
282
|
+
type: "text",
|
|
283
|
+
text: output
|
|
284
|
+
}]
|
|
285
|
+
};
|
|
286
|
+
} catch (e) {
|
|
287
|
+
return {
|
|
288
|
+
content: [{
|
|
289
|
+
type: "text",
|
|
290
|
+
text: "📝 No memory logs found"
|
|
291
|
+
}],
|
|
292
|
+
metadata: { empty: true }
|
|
293
|
+
};
|
|
294
|
+
}
|
|
188
295
|
}
|
|
189
296
|
|
|
190
297
|
/**
|
|
191
298
|
* Get memory statistics
|
|
192
299
|
*/
|
|
193
|
-
async function getMemoryStats(
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
300
|
+
async function getMemoryStats() {
|
|
301
|
+
try {
|
|
302
|
+
const engine = await getMemoryEngine();
|
|
303
|
+
const stats = engine.getStats();
|
|
304
|
+
const syncStatus = engine.getSyncStatus();
|
|
305
|
+
|
|
306
|
+
let output = `📊 Memory Statistics\n`;
|
|
307
|
+
output += '─'.repeat(40) + '\n';
|
|
308
|
+
output += `Indexed Files: ${stats.files || 0}\n`;
|
|
309
|
+
output += `Facts Stored: ${stats.facts || 0}\n`;
|
|
310
|
+
output += `Code Chunks: ${stats.chunks || 0}\n`;
|
|
311
|
+
output += `Embeddings: ${stats.embeddings || 0}\n`;
|
|
312
|
+
output += `Edit History: ${stats.edits || 0}\n\n`;
|
|
313
|
+
|
|
314
|
+
output += `Sync Engine: ${syncStatus.enabled ? '✅ Enabled' : '❌ Disabled'}\n`;
|
|
315
|
+
if (syncStatus.enabled) {
|
|
316
|
+
output += `Sync Status: ${syncStatus.status || 'unknown'}\n`;
|
|
317
|
+
output += `Last Sync: ${syncStatus.lastSync ? new Date(syncStatus.lastSync).toISOString() : 'Never'}\n`;
|
|
318
|
+
output += `Pending Changes: ${syncStatus.pendingChanges || 0}\n`;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
output += `\nProject: ${stats.projectPath || 'N/A'}\n`;
|
|
322
|
+
output += `Smart Routing: ${engine.smartRoutingEnabled ? '✅ Enabled' : '❌ Disabled'}\n`;
|
|
323
|
+
|
|
324
|
+
return {
|
|
325
|
+
content: [{
|
|
326
|
+
type: "text",
|
|
327
|
+
text: output
|
|
328
|
+
}],
|
|
329
|
+
metadata: stats
|
|
330
|
+
};
|
|
331
|
+
} catch (error) {
|
|
332
|
+
return {
|
|
333
|
+
content: [{
|
|
334
|
+
type: "text",
|
|
335
|
+
text: `❌ Error getting stats: ${error.message}`
|
|
336
|
+
}],
|
|
337
|
+
isError: true
|
|
338
|
+
};
|
|
339
|
+
}
|
|
233
340
|
}
|
|
234
341
|
|
|
235
|
-
|
|
342
|
+
export default { execute };
|