@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/writer.js
ADDED
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import { cache } from './cache.js';
|
|
2
|
+
import { writeQueue } from './queue.js';
|
|
3
|
+
import { updateIndex } from './index-gen.js';
|
|
4
|
+
import { log } from './logger.js';
|
|
5
|
+
// Maximum file size: 1MB (GitHub API limit for base64 content)
|
|
6
|
+
const MAX_FILE_SIZE = 1 * 1024 * 1024;
|
|
7
|
+
/**
|
|
8
|
+
* Async writer manager - handles non-blocking GitHub operations
|
|
9
|
+
* Updates cache immediately, returns to agent, syncs GitHub in background
|
|
10
|
+
*/
|
|
11
|
+
export class AsyncWriter {
|
|
12
|
+
github;
|
|
13
|
+
pendingWrites = new Set();
|
|
14
|
+
constructor(github) {
|
|
15
|
+
this.github = github;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Save a file - updates cache immediately, syncs GitHub async
|
|
19
|
+
* Returns immediately after cache update
|
|
20
|
+
*/
|
|
21
|
+
async save(category, name, content) {
|
|
22
|
+
// Validate file size
|
|
23
|
+
const contentSize = Buffer.byteLength(content, 'utf-8');
|
|
24
|
+
if (contentSize > MAX_FILE_SIZE) {
|
|
25
|
+
return {
|
|
26
|
+
success: false,
|
|
27
|
+
path: '',
|
|
28
|
+
error: `File size (${Math.round(contentSize / 1024)}KB) exceeds maximum allowed size (${MAX_FILE_SIZE / 1024}KB)`,
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
// Normalize category and name
|
|
32
|
+
const normalizedCategory = category.toLowerCase().replace(/[^a-z0-9-]/g, '-');
|
|
33
|
+
const normalizedName = name.endsWith('.md') || name.endsWith('.yaml') || name.endsWith('.json')
|
|
34
|
+
? name
|
|
35
|
+
: `${name}.md`;
|
|
36
|
+
const path = `${normalizedCategory}/${normalizedName}`;
|
|
37
|
+
// Get existing SHA if file exists in cache
|
|
38
|
+
const existing = cache.get(path);
|
|
39
|
+
const sha = existing?.sha;
|
|
40
|
+
// Update cache immediately (optimistic)
|
|
41
|
+
cache.set(path, content, sha ?? 'pending');
|
|
42
|
+
// Fire-and-forget GitHub sync
|
|
43
|
+
this.syncToGitHub(path, content, sha);
|
|
44
|
+
return { success: true, path };
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Delete a file - removes from cache immediately, syncs GitHub async
|
|
48
|
+
*/
|
|
49
|
+
async delete(path) {
|
|
50
|
+
const existing = cache.get(path);
|
|
51
|
+
if (!existing) {
|
|
52
|
+
return { success: false, error: `File not found: ${path}` };
|
|
53
|
+
}
|
|
54
|
+
// Remove from cache immediately
|
|
55
|
+
cache.delete(path);
|
|
56
|
+
// Fire-and-forget GitHub delete
|
|
57
|
+
this.deleteFromGitHub(path, existing.sha);
|
|
58
|
+
return { success: true };
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Sync a file to GitHub (async, non-blocking)
|
|
62
|
+
*/
|
|
63
|
+
async syncToGitHub(path, content, sha) {
|
|
64
|
+
// Prevent duplicate syncs
|
|
65
|
+
if (this.pendingWrites.has(path)) {
|
|
66
|
+
log('writer', `Sync already pending for: ${path}`);
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
this.pendingWrites.add(path);
|
|
70
|
+
try {
|
|
71
|
+
log('writer', `Starting async sync: ${path}`);
|
|
72
|
+
const newSha = await this.github.putFile(path, content, sha);
|
|
73
|
+
// Update cache with real SHA
|
|
74
|
+
cache.set(path, content, newSha);
|
|
75
|
+
// Update index
|
|
76
|
+
await this.updateIndexSafe();
|
|
77
|
+
// Remove from queue if it was there
|
|
78
|
+
writeQueue.remove(path);
|
|
79
|
+
log('writer', `Sync complete: ${path}`);
|
|
80
|
+
}
|
|
81
|
+
catch (error) {
|
|
82
|
+
log('writer', `Sync failed for ${path}: ${error}`);
|
|
83
|
+
// Add to queue for retry
|
|
84
|
+
writeQueue.enqueue(path, content, 'save');
|
|
85
|
+
}
|
|
86
|
+
finally {
|
|
87
|
+
this.pendingWrites.delete(path);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Delete a file from GitHub (async, non-blocking)
|
|
92
|
+
*/
|
|
93
|
+
async deleteFromGitHub(path, sha) {
|
|
94
|
+
if (this.pendingWrites.has(path)) {
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
this.pendingWrites.add(path);
|
|
98
|
+
try {
|
|
99
|
+
log('writer', `Starting async delete: ${path}`);
|
|
100
|
+
await this.github.deleteFile(path, sha);
|
|
101
|
+
// Update index
|
|
102
|
+
await this.updateIndexSafe();
|
|
103
|
+
// Remove from queue if it was there
|
|
104
|
+
writeQueue.remove(path);
|
|
105
|
+
log('writer', `Delete complete: ${path}`);
|
|
106
|
+
}
|
|
107
|
+
catch (error) {
|
|
108
|
+
log('writer', `Delete failed for ${path}: ${error}`);
|
|
109
|
+
// Add to queue for retry
|
|
110
|
+
writeQueue.enqueue(path, '', 'delete');
|
|
111
|
+
}
|
|
112
|
+
finally {
|
|
113
|
+
this.pendingWrites.delete(path);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Update index without blocking on errors
|
|
118
|
+
*/
|
|
119
|
+
async updateIndexSafe() {
|
|
120
|
+
try {
|
|
121
|
+
await updateIndex(this.github, cache);
|
|
122
|
+
}
|
|
123
|
+
catch (error) {
|
|
124
|
+
log('writer', `Index update failed: ${error}`);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Drain the write queue - called on startup and after successful operations
|
|
129
|
+
*/
|
|
130
|
+
async drainQueue() {
|
|
131
|
+
const items = writeQueue.getAll();
|
|
132
|
+
if (items.length === 0) {
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
log('queue', `Draining ${items.length} queued items`);
|
|
136
|
+
for (const item of items) {
|
|
137
|
+
try {
|
|
138
|
+
if (item.operation === 'save') {
|
|
139
|
+
const existing = cache.get(item.path);
|
|
140
|
+
await this.github.putFile(item.path, item.content, existing?.sha);
|
|
141
|
+
writeQueue.remove(item.path);
|
|
142
|
+
log('queue', `Drained: ${item.path}`);
|
|
143
|
+
}
|
|
144
|
+
else if (item.operation === 'delete') {
|
|
145
|
+
const existing = cache.get(item.path);
|
|
146
|
+
if (existing) {
|
|
147
|
+
await this.github.deleteFile(item.path, existing.sha);
|
|
148
|
+
}
|
|
149
|
+
writeQueue.remove(item.path);
|
|
150
|
+
log('queue', `Drained delete: ${item.path}`);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
catch (error) {
|
|
154
|
+
log('queue', `Failed to drain ${item.path}: ${error}`);
|
|
155
|
+
writeQueue.incrementRetry(item.path);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
// Update index after draining
|
|
159
|
+
await this.updateIndexSafe();
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
//# sourceMappingURL=writer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"writer.js","sourceRoot":"","sources":["../src/writer.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@lesgo/memory-mcp",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Personal External Brain MCP Server - A stateless MCP server for syncing templates, standards, and knowledge via GitHub",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"memory-mcp": "./dist/index.js"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"dist"
|
|
12
|
+
],
|
|
13
|
+
"repository": {
|
|
14
|
+
"type": "git",
|
|
15
|
+
"url": "https://github.com/clayton-duarte/memory-mcp.git"
|
|
16
|
+
},
|
|
17
|
+
"scripts": {
|
|
18
|
+
"build": "tsc",
|
|
19
|
+
"dev": "tsc --watch",
|
|
20
|
+
"start": "node dist/index.js",
|
|
21
|
+
"prepublishOnly": "npm run build"
|
|
22
|
+
},
|
|
23
|
+
"keywords": [
|
|
24
|
+
"mcp",
|
|
25
|
+
"model-context-protocol",
|
|
26
|
+
"ai",
|
|
27
|
+
"github",
|
|
28
|
+
"knowledge-base"
|
|
29
|
+
],
|
|
30
|
+
"author": "",
|
|
31
|
+
"license": "MIT",
|
|
32
|
+
"dependencies": {
|
|
33
|
+
"@modelcontextprotocol/sdk": "^1.0.0",
|
|
34
|
+
"@octokit/rest": "^20.0.0",
|
|
35
|
+
"zod": "^3.22.0"
|
|
36
|
+
},
|
|
37
|
+
"devDependencies": {
|
|
38
|
+
"@types/node": "^20.0.0",
|
|
39
|
+
"typescript": "^5.3.0"
|
|
40
|
+
},
|
|
41
|
+
"engines": {
|
|
42
|
+
"node": ">=18.0.0"
|
|
43
|
+
}
|
|
44
|
+
}
|