@lesgo/memory-mcp 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.
- package/README.md +128 -0
- package/dist/cache.d.ts +62 -0
- package/dist/cache.d.ts.map +1 -0
- package/dist/cache.js +141 -0
- package/dist/cache.js.map +1 -0
- package/dist/github.d.ts +39 -0
- package/dist/github.d.ts.map +1 -0
- package/dist/github.js +120 -0
- package/dist/github.js.map +1 -0
- package/dist/index-gen.d.ts +19 -0
- package/dist/index-gen.d.ts.map +1 -0
- package/dist/index-gen.js +41 -0
- package/dist/index-gen.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +324 -0
- package/dist/index.js.map +1 -0
- package/dist/logger.d.ts +8 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +9 -0
- package/dist/logger.js.map +1 -0
- package/dist/queue.d.ts +49 -0
- package/dist/queue.d.ts.map +1 -0
- package/dist/queue.js +109 -0
- package/dist/queue.js.map +1 -0
- package/dist/writer.d.ts +43 -0
- package/dist/writer.d.ts.map +1 -0
- package/dist/writer.js +162 -0
- package/dist/writer.js.map +1 -0
- package/package.json +44 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,324 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
3
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
4
|
+
import { CallToolRequestSchema, ListToolsRequestSchema, } from '@modelcontextprotocol/sdk/types.js';
|
|
5
|
+
import { z } from 'zod';
|
|
6
|
+
import { GitHubClient } from './github.js';
|
|
7
|
+
import { cache } from './cache.js';
|
|
8
|
+
import { AsyncWriter } from './writer.js';
|
|
9
|
+
import { parseIndex } from './index-gen.js';
|
|
10
|
+
import { log } from './logger.js';
|
|
11
|
+
// Configuration schema - passed via MCP settings
|
|
12
|
+
const ConfigSchema = z.object({
|
|
13
|
+
repo: z.string().regex(/^[^/]+\/[^/]+$/, 'Must be in format "owner/repo"'),
|
|
14
|
+
token: z.string().min(1, 'GitHub token is required'),
|
|
15
|
+
});
|
|
16
|
+
// Tool input schemas
|
|
17
|
+
const ReadMemorySchema = z.object({
|
|
18
|
+
path: z.string().describe('Path to the memory file (e.g., "templates/user-story.md")'),
|
|
19
|
+
});
|
|
20
|
+
const SaveMemorySchema = z.object({
|
|
21
|
+
category: z.string().describe('Category folder (e.g., "templates", "standards", "knowledge"). Will be created if it does not exist.'),
|
|
22
|
+
name: z.string().describe('File name (e.g., "user-story.md" or "user-story")'),
|
|
23
|
+
content: z.string().describe('Content of the memory file'),
|
|
24
|
+
});
|
|
25
|
+
const DeleteMemorySchema = z.object({
|
|
26
|
+
path: z.string().describe('Path to the memory file to delete'),
|
|
27
|
+
});
|
|
28
|
+
const SearchMemorySchema = z.object({
|
|
29
|
+
query: z.string().describe('Search query (searches paths and content)'),
|
|
30
|
+
});
|
|
31
|
+
// Tool definitions
|
|
32
|
+
const TOOLS = [
|
|
33
|
+
{
|
|
34
|
+
name: 'list_knowledge',
|
|
35
|
+
description: 'List all available memory files organized by category. Returns the index of templates, standards, and knowledge files.',
|
|
36
|
+
inputSchema: {
|
|
37
|
+
type: 'object',
|
|
38
|
+
properties: {},
|
|
39
|
+
required: [],
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
name: 'read_memory',
|
|
44
|
+
description: 'Read the content of a specific memory file. Fast cached reads.',
|
|
45
|
+
inputSchema: {
|
|
46
|
+
type: 'object',
|
|
47
|
+
properties: {
|
|
48
|
+
path: {
|
|
49
|
+
type: 'string',
|
|
50
|
+
description: 'Path to the memory file (e.g., "templates/user-story.md")',
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
required: ['path'],
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
name: 'save_memory',
|
|
58
|
+
description: 'Create or update a memory file. Saves are async and non-blocking. Category folders are auto-created.',
|
|
59
|
+
inputSchema: {
|
|
60
|
+
type: 'object',
|
|
61
|
+
properties: {
|
|
62
|
+
category: {
|
|
63
|
+
type: 'string',
|
|
64
|
+
description: 'Category folder (e.g., "templates", "standards", "knowledge")',
|
|
65
|
+
},
|
|
66
|
+
name: {
|
|
67
|
+
type: 'string',
|
|
68
|
+
description: 'File name (e.g., "user-story.md")',
|
|
69
|
+
},
|
|
70
|
+
content: {
|
|
71
|
+
type: 'string',
|
|
72
|
+
description: 'Content of the memory file',
|
|
73
|
+
},
|
|
74
|
+
},
|
|
75
|
+
required: ['category', 'name', 'content'],
|
|
76
|
+
},
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
name: 'delete_memory',
|
|
80
|
+
description: 'Delete a memory file. Deletes are async and non-blocking.',
|
|
81
|
+
inputSchema: {
|
|
82
|
+
type: 'object',
|
|
83
|
+
properties: {
|
|
84
|
+
path: {
|
|
85
|
+
type: 'string',
|
|
86
|
+
description: 'Path to the memory file to delete',
|
|
87
|
+
},
|
|
88
|
+
},
|
|
89
|
+
required: ['path'],
|
|
90
|
+
},
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
name: 'search_memory',
|
|
94
|
+
description: 'Search across all memory files by keyword. Searches both file paths and content.',
|
|
95
|
+
inputSchema: {
|
|
96
|
+
type: 'object',
|
|
97
|
+
properties: {
|
|
98
|
+
query: {
|
|
99
|
+
type: 'string',
|
|
100
|
+
description: 'Search query',
|
|
101
|
+
},
|
|
102
|
+
},
|
|
103
|
+
required: ['query'],
|
|
104
|
+
},
|
|
105
|
+
},
|
|
106
|
+
];
|
|
107
|
+
class MemoryMCPServer {
|
|
108
|
+
server;
|
|
109
|
+
github = null;
|
|
110
|
+
writer = null;
|
|
111
|
+
config = null;
|
|
112
|
+
constructor() {
|
|
113
|
+
this.server = new Server({
|
|
114
|
+
name: 'memory-mcp',
|
|
115
|
+
version: '1.0.0',
|
|
116
|
+
}, {
|
|
117
|
+
capabilities: {
|
|
118
|
+
tools: {},
|
|
119
|
+
},
|
|
120
|
+
});
|
|
121
|
+
this.setupHandlers();
|
|
122
|
+
}
|
|
123
|
+
setupHandlers() {
|
|
124
|
+
// List available tools
|
|
125
|
+
this.server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
126
|
+
return { tools: TOOLS };
|
|
127
|
+
});
|
|
128
|
+
// Handle tool calls
|
|
129
|
+
this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
130
|
+
const { name, arguments: args } = request.params;
|
|
131
|
+
try {
|
|
132
|
+
switch (name) {
|
|
133
|
+
case 'list_knowledge':
|
|
134
|
+
return await this.handleListKnowledge();
|
|
135
|
+
case 'read_memory':
|
|
136
|
+
return await this.handleReadMemory(args);
|
|
137
|
+
case 'save_memory':
|
|
138
|
+
return await this.handleSaveMemory(args);
|
|
139
|
+
case 'delete_memory':
|
|
140
|
+
return await this.handleDeleteMemory(args);
|
|
141
|
+
case 'search_memory':
|
|
142
|
+
return await this.handleSearchMemory(args);
|
|
143
|
+
default:
|
|
144
|
+
return {
|
|
145
|
+
content: [{ type: 'text', text: `Unknown tool: ${name}` }],
|
|
146
|
+
isError: true,
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
catch (error) {
|
|
151
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
152
|
+
return {
|
|
153
|
+
content: [{ type: 'text', text: `Error: ${message}` }],
|
|
154
|
+
isError: true,
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
async handleListKnowledge() {
|
|
160
|
+
const indexEntry = cache.get('index.json');
|
|
161
|
+
if (indexEntry) {
|
|
162
|
+
const index = parseIndex(indexEntry.content);
|
|
163
|
+
return {
|
|
164
|
+
content: [{
|
|
165
|
+
type: 'text',
|
|
166
|
+
text: JSON.stringify(index, null, 2),
|
|
167
|
+
}],
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
// Generate index from cache if index.json doesn't exist
|
|
171
|
+
const files = cache.keys()
|
|
172
|
+
.filter((path) => path !== 'index.json')
|
|
173
|
+
.map((path) => {
|
|
174
|
+
const parts = path.split('/');
|
|
175
|
+
return { path, category: parts.length > 1 ? parts[0] : 'root' };
|
|
176
|
+
});
|
|
177
|
+
const categories = [...new Set(files.map((f) => f.category))].sort();
|
|
178
|
+
return {
|
|
179
|
+
content: [{
|
|
180
|
+
type: 'text',
|
|
181
|
+
text: JSON.stringify({ categories, files, lastUpdated: new Date().toISOString() }, null, 2),
|
|
182
|
+
}],
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
async handleReadMemory(args) {
|
|
186
|
+
const { path } = ReadMemorySchema.parse(args);
|
|
187
|
+
// Try cache first (fast path)
|
|
188
|
+
let entry = cache.get(path);
|
|
189
|
+
if (!entry && this.github) {
|
|
190
|
+
// Cache miss - fetch from GitHub
|
|
191
|
+
const file = await this.github.getFile(path);
|
|
192
|
+
if (!file) {
|
|
193
|
+
return {
|
|
194
|
+
content: [{ type: 'text', text: `File not found: ${path}` }],
|
|
195
|
+
isError: true,
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
cache.set(path, file.content, file.sha);
|
|
199
|
+
entry = { content: file.content, sha: file.sha };
|
|
200
|
+
}
|
|
201
|
+
if (!entry) {
|
|
202
|
+
return {
|
|
203
|
+
content: [{ type: 'text', text: `File not found: ${path}` }],
|
|
204
|
+
isError: true,
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
return {
|
|
208
|
+
content: [{ type: 'text', text: entry.content }],
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
async handleSaveMemory(args) {
|
|
212
|
+
const { category, name, content } = SaveMemorySchema.parse(args);
|
|
213
|
+
if (!this.writer) {
|
|
214
|
+
return {
|
|
215
|
+
content: [{ type: 'text', text: 'Server not initialized' }],
|
|
216
|
+
isError: true,
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
const result = await this.writer.save(category, name, content);
|
|
220
|
+
if (!result.success) {
|
|
221
|
+
return {
|
|
222
|
+
content: [{ type: 'text', text: result.error ?? 'Save failed' }],
|
|
223
|
+
isError: true,
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
return {
|
|
227
|
+
content: [{ type: 'text', text: `Saved: ${result.path}` }],
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
async handleDeleteMemory(args) {
|
|
231
|
+
const { path } = DeleteMemorySchema.parse(args);
|
|
232
|
+
if (!this.writer) {
|
|
233
|
+
return {
|
|
234
|
+
content: [{ type: 'text', text: 'Server not initialized' }],
|
|
235
|
+
isError: true,
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
const result = await this.writer.delete(path);
|
|
239
|
+
if (!result.success) {
|
|
240
|
+
return {
|
|
241
|
+
content: [{ type: 'text', text: result.error ?? 'Delete failed' }],
|
|
242
|
+
isError: true,
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
return {
|
|
246
|
+
content: [{ type: 'text', text: `Deleted: ${path}` }],
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
async handleSearchMemory(args) {
|
|
250
|
+
const { query } = SearchMemorySchema.parse(args);
|
|
251
|
+
const results = cache.search(query);
|
|
252
|
+
if (results.length === 0) {
|
|
253
|
+
return {
|
|
254
|
+
content: [{ type: 'text', text: `No results found for: "${query}"` }],
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
const formatted = results
|
|
258
|
+
.map((r) => `**${r.path}**\n${r.snippet}`)
|
|
259
|
+
.join('\n\n---\n\n');
|
|
260
|
+
return {
|
|
261
|
+
content: [{ type: 'text', text: formatted }],
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
async initialize(config) {
|
|
265
|
+
log('init', `Initializing with repo: ${config.repo}`);
|
|
266
|
+
this.config = config;
|
|
267
|
+
this.github = new GitHubClient(config);
|
|
268
|
+
this.writer = new AsyncWriter(this.github);
|
|
269
|
+
// Validate GitHub access
|
|
270
|
+
const hasAccess = await this.github.validateAccess();
|
|
271
|
+
if (!hasAccess) {
|
|
272
|
+
throw new Error(`Cannot access repository: ${config.repo}. Check token permissions.`);
|
|
273
|
+
}
|
|
274
|
+
// Fetch full tree and populate cache
|
|
275
|
+
log('init', 'Fetching repository contents...');
|
|
276
|
+
const tree = await this.github.listTree();
|
|
277
|
+
log('init', `Found ${tree.length} files in repository`);
|
|
278
|
+
// Fetch content for all files
|
|
279
|
+
for (const { path, sha } of tree) {
|
|
280
|
+
try {
|
|
281
|
+
const file = await this.github.getFile(path);
|
|
282
|
+
if (file) {
|
|
283
|
+
cache.set(path, file.content, file.sha);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
catch (error) {
|
|
287
|
+
log('init', `Failed to fetch ${path}: ${error}`);
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
log('init', `Cache populated with ${cache.size} files`);
|
|
291
|
+
// Drain any pending writes from previous session
|
|
292
|
+
await this.writer.drainQueue();
|
|
293
|
+
log('init', 'Server ready');
|
|
294
|
+
}
|
|
295
|
+
async run() {
|
|
296
|
+
const transport = new StdioServerTransport();
|
|
297
|
+
await this.server.connect(transport);
|
|
298
|
+
log('server', 'MCP server running on stdio');
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
// Main entry point
|
|
302
|
+
async function main() {
|
|
303
|
+
// Parse config from environment or command line
|
|
304
|
+
// MCP clients pass config via environment variables
|
|
305
|
+
const repo = process.env.MEMORY_MCP_REPO;
|
|
306
|
+
const token = process.env.MEMORY_MCP_TOKEN;
|
|
307
|
+
if (!repo || !token) {
|
|
308
|
+
console.error('Error: MEMORY_MCP_REPO and MEMORY_MCP_TOKEN environment variables are required.');
|
|
309
|
+
console.error('Configure these in your MCP client settings.');
|
|
310
|
+
process.exit(1);
|
|
311
|
+
}
|
|
312
|
+
try {
|
|
313
|
+
const config = ConfigSchema.parse({ repo, token });
|
|
314
|
+
const server = new MemoryMCPServer();
|
|
315
|
+
await server.initialize(config);
|
|
316
|
+
await server.run();
|
|
317
|
+
}
|
|
318
|
+
catch (error) {
|
|
319
|
+
console.error('Fatal error:', error);
|
|
320
|
+
process.exit(1);
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
main();
|
|
324
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/logger.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
type LogCategory = 'init' | 'cache' | 'github' | 'queue' | 'writer' | 'server';
|
|
2
|
+
/**
|
|
3
|
+
* Log to stderr with category prefix
|
|
4
|
+
* MCP servers communicate via stdio, so all logging must go to stderr
|
|
5
|
+
*/
|
|
6
|
+
export declare function log(category: LogCategory, message: string): void;
|
|
7
|
+
export {};
|
|
8
|
+
//# sourceMappingURL=logger.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAAA,KAAK,WAAW,GAAG,MAAM,GAAG,OAAO,GAAG,QAAQ,GAAG,OAAO,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAE/E;;;GAGG;AACH,wBAAgB,GAAG,CAAC,QAAQ,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAGhE"}
|
package/dist/logger.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Log to stderr with category prefix
|
|
3
|
+
* MCP servers communicate via stdio, so all logging must go to stderr
|
|
4
|
+
*/
|
|
5
|
+
export function log(category, message) {
|
|
6
|
+
const timestamp = new Date().toISOString();
|
|
7
|
+
console.error(`[${timestamp}] [${category}] ${message}`);
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=logger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.js","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,MAAM,UAAU,GAAG,CAAC,QAAqB,EAAE,OAAe;IACxD,MAAM,SAAS,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAC3C,OAAO,CAAC,KAAK,CAAC,IAAI,SAAS,MAAM,QAAQ,KAAK,OAAO,EAAE,CAAC,CAAC;AAC3D,CAAC"}
|
package/dist/queue.d.ts
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
export interface QueueItem {
|
|
2
|
+
path: string;
|
|
3
|
+
content: string;
|
|
4
|
+
operation: 'save' | 'delete';
|
|
5
|
+
timestamp: number;
|
|
6
|
+
retryCount: number;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Persistent write queue for failed GitHub operations
|
|
10
|
+
* Stores pending writes to disk and retries on next operation
|
|
11
|
+
*/
|
|
12
|
+
export declare class WriteQueue {
|
|
13
|
+
private items;
|
|
14
|
+
constructor();
|
|
15
|
+
/**
|
|
16
|
+
* Load queue from disk
|
|
17
|
+
*/
|
|
18
|
+
private load;
|
|
19
|
+
/**
|
|
20
|
+
* Persist queue to disk
|
|
21
|
+
*/
|
|
22
|
+
private save;
|
|
23
|
+
/**
|
|
24
|
+
* Add an item to the queue
|
|
25
|
+
*/
|
|
26
|
+
enqueue(path: string, content: string, operation: 'save' | 'delete'): void;
|
|
27
|
+
/**
|
|
28
|
+
* Get all pending items
|
|
29
|
+
*/
|
|
30
|
+
getAll(): QueueItem[];
|
|
31
|
+
/**
|
|
32
|
+
* Remove an item from the queue (after successful sync)
|
|
33
|
+
*/
|
|
34
|
+
remove(path: string): void;
|
|
35
|
+
/**
|
|
36
|
+
* Increment retry count and remove if max retries exceeded
|
|
37
|
+
*/
|
|
38
|
+
incrementRetry(path: string): boolean;
|
|
39
|
+
/**
|
|
40
|
+
* Check if queue is empty
|
|
41
|
+
*/
|
|
42
|
+
get isEmpty(): boolean;
|
|
43
|
+
/**
|
|
44
|
+
* Get queue size
|
|
45
|
+
*/
|
|
46
|
+
get size(): number;
|
|
47
|
+
}
|
|
48
|
+
export declare const writeQueue: WriteQueue;
|
|
49
|
+
//# sourceMappingURL=queue.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"queue.d.ts","sourceRoot":"","sources":["../src/queue.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,GAAG,QAAQ,CAAC;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;CACpB;AAKD;;;GAGG;AACH,qBAAa,UAAU;IACrB,OAAO,CAAC,KAAK,CAAmB;;IAMhC;;OAEG;IACH,OAAO,CAAC,IAAI;IAaZ;;OAEG;IACH,OAAO,CAAC,IAAI;IAQZ;;OAEG;IACH,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI;IAgB1E;;OAEG;IACH,MAAM,IAAI,SAAS,EAAE;IAIrB;;OAEG;IACH,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAU1B;;OAEG;IACH,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAkBrC;;OAEG;IACH,IAAI,OAAO,IAAI,OAAO,CAErB;IAED;;OAEG;IACH,IAAI,IAAI,IAAI,MAAM,CAEjB;CACF;AAGD,eAAO,MAAM,UAAU,YAAmB,CAAC"}
|
package/dist/queue.js
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { readFileSync, writeFileSync, existsSync } from 'fs';
|
|
2
|
+
import { homedir } from 'os';
|
|
3
|
+
import { join } from 'path';
|
|
4
|
+
import { log } from './logger.js';
|
|
5
|
+
const QUEUE_FILE = join(homedir(), '.memory-mcp-queue.json');
|
|
6
|
+
const MAX_RETRIES = 3;
|
|
7
|
+
/**
|
|
8
|
+
* Persistent write queue for failed GitHub operations
|
|
9
|
+
* Stores pending writes to disk and retries on next operation
|
|
10
|
+
*/
|
|
11
|
+
export class WriteQueue {
|
|
12
|
+
items = [];
|
|
13
|
+
constructor() {
|
|
14
|
+
this.load();
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Load queue from disk
|
|
18
|
+
*/
|
|
19
|
+
load() {
|
|
20
|
+
try {
|
|
21
|
+
if (existsSync(QUEUE_FILE)) {
|
|
22
|
+
const data = readFileSync(QUEUE_FILE, 'utf-8');
|
|
23
|
+
this.items = JSON.parse(data);
|
|
24
|
+
log('queue', `Loaded ${this.items.length} pending items from queue`);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
catch (error) {
|
|
28
|
+
log('queue', `Failed to load queue file: ${error}`);
|
|
29
|
+
this.items = [];
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Persist queue to disk
|
|
34
|
+
*/
|
|
35
|
+
save() {
|
|
36
|
+
try {
|
|
37
|
+
writeFileSync(QUEUE_FILE, JSON.stringify(this.items, null, 2));
|
|
38
|
+
}
|
|
39
|
+
catch (error) {
|
|
40
|
+
log('queue', `Failed to save queue file: ${error}`);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Add an item to the queue
|
|
45
|
+
*/
|
|
46
|
+
enqueue(path, content, operation) {
|
|
47
|
+
// Remove any existing item for the same path
|
|
48
|
+
this.items = this.items.filter((item) => item.path !== path);
|
|
49
|
+
this.items.push({
|
|
50
|
+
path,
|
|
51
|
+
content,
|
|
52
|
+
operation,
|
|
53
|
+
timestamp: Date.now(),
|
|
54
|
+
retryCount: 0,
|
|
55
|
+
});
|
|
56
|
+
this.save();
|
|
57
|
+
log('queue', `Enqueued ${operation} for: ${path}`);
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Get all pending items
|
|
61
|
+
*/
|
|
62
|
+
getAll() {
|
|
63
|
+
return [...this.items];
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Remove an item from the queue (after successful sync)
|
|
67
|
+
*/
|
|
68
|
+
remove(path) {
|
|
69
|
+
const before = this.items.length;
|
|
70
|
+
this.items = this.items.filter((item) => item.path !== path);
|
|
71
|
+
if (this.items.length < before) {
|
|
72
|
+
this.save();
|
|
73
|
+
log('queue', `Removed from queue: ${path}`);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Increment retry count and remove if max retries exceeded
|
|
78
|
+
*/
|
|
79
|
+
incrementRetry(path) {
|
|
80
|
+
const item = this.items.find((i) => i.path === path);
|
|
81
|
+
if (!item)
|
|
82
|
+
return false;
|
|
83
|
+
item.retryCount++;
|
|
84
|
+
if (item.retryCount >= MAX_RETRIES) {
|
|
85
|
+
this.items = this.items.filter((i) => i.path !== path);
|
|
86
|
+
log('queue', `Max retries reached, dropping: ${path}`);
|
|
87
|
+
this.save();
|
|
88
|
+
return false;
|
|
89
|
+
}
|
|
90
|
+
this.save();
|
|
91
|
+
log('queue', `Retry ${item.retryCount}/${MAX_RETRIES} for: ${path}`);
|
|
92
|
+
return true;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Check if queue is empty
|
|
96
|
+
*/
|
|
97
|
+
get isEmpty() {
|
|
98
|
+
return this.items.length === 0;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Get queue size
|
|
102
|
+
*/
|
|
103
|
+
get size() {
|
|
104
|
+
return this.items.length;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
// Global queue instance
|
|
108
|
+
export const writeQueue = new WriteQueue();
|
|
109
|
+
//# sourceMappingURL=queue.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"queue.js","sourceRoot":"","sources":["../src/queue.ts"],"names":[],"mappings":"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"}
|
package/dist/writer.d.ts
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { GitHubClient } from './github.js';
|
|
2
|
+
/**
|
|
3
|
+
* Async writer manager - handles non-blocking GitHub operations
|
|
4
|
+
* Updates cache immediately, returns to agent, syncs GitHub in background
|
|
5
|
+
*/
|
|
6
|
+
export declare class AsyncWriter {
|
|
7
|
+
private github;
|
|
8
|
+
private pendingWrites;
|
|
9
|
+
constructor(github: GitHubClient);
|
|
10
|
+
/**
|
|
11
|
+
* Save a file - updates cache immediately, syncs GitHub async
|
|
12
|
+
* Returns immediately after cache update
|
|
13
|
+
*/
|
|
14
|
+
save(category: string, name: string, content: string): Promise<{
|
|
15
|
+
success: boolean;
|
|
16
|
+
path: string;
|
|
17
|
+
error?: string;
|
|
18
|
+
}>;
|
|
19
|
+
/**
|
|
20
|
+
* Delete a file - removes from cache immediately, syncs GitHub async
|
|
21
|
+
*/
|
|
22
|
+
delete(path: string): Promise<{
|
|
23
|
+
success: boolean;
|
|
24
|
+
error?: string;
|
|
25
|
+
}>;
|
|
26
|
+
/**
|
|
27
|
+
* Sync a file to GitHub (async, non-blocking)
|
|
28
|
+
*/
|
|
29
|
+
private syncToGitHub;
|
|
30
|
+
/**
|
|
31
|
+
* Delete a file from GitHub (async, non-blocking)
|
|
32
|
+
*/
|
|
33
|
+
private deleteFromGitHub;
|
|
34
|
+
/**
|
|
35
|
+
* Update index without blocking on errors
|
|
36
|
+
*/
|
|
37
|
+
private updateIndexSafe;
|
|
38
|
+
/**
|
|
39
|
+
* Drain the write queue - called on startup and after successful operations
|
|
40
|
+
*/
|
|
41
|
+
drainQueue(): Promise<void>;
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=writer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"writer.d.ts","sourceRoot":"","sources":["../src/writer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAS3C;;;GAGG;AACH,qBAAa,WAAW;IACtB,OAAO,CAAC,MAAM,CAAe;IAC7B,OAAO,CAAC,aAAa,CAA0B;gBAEnC,MAAM,EAAE,YAAY;IAIhC;;;OAGG;IACG,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAgCxH;;OAEG;IACG,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAgBzE;;OAEG;YACW,YAAY;IAiC1B;;OAEG;YACW,gBAAgB;IA4B9B;;OAEG;YACW,eAAe;IAQ7B;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;CAiClC"}
|