@cybermem/mcp 0.13.16 → 0.14.4
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/CHANGELOG.md +12 -0
- package/dist/env.js +4 -4
- package/dist/index.js +84 -135
- package/package.json +5 -3
- package/src/env.ts +4 -6
- package/src/index.ts +94 -137
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# @cybermem/mcp
|
|
2
|
+
|
|
3
|
+
## 0.14.4
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#86](https://github.com/mikhailkogan17/cybermem/pull/86) [`ffca5dd`](https://github.com/mikhailkogan17/cybermem/commit/ffca5dd374a50f594c1a935f1fe81ee1e1e3c6fe) Thanks [@copilot-swe-agent](https://github.com/apps/copilot-swe-agent)! - Migrate version management to Changesets
|
|
8
|
+
|
|
9
|
+
- Remove custom bash scripts (version-bump.sh, release.sh)
|
|
10
|
+
- Add Changesets for automated versioning and changelog generation
|
|
11
|
+
- Update publish workflow to use Changesets
|
|
12
|
+
- Add documentation for new release process
|
package/dist/env.js
CHANGED
|
@@ -7,11 +7,11 @@ const dotenv_1 = __importDefault(require("dotenv"));
|
|
|
7
7
|
const os_1 = __importDefault(require("os"));
|
|
8
8
|
const path_1 = __importDefault(require("path"));
|
|
9
9
|
dotenv_1.default.config();
|
|
10
|
-
//
|
|
10
|
+
// Auto-set CYBERMEM_INSTANCE for stdio mode (npx @cybermem/mcp)
|
|
11
|
+
// When started via @cybermem/cli, CYBERMEM_INSTANCE is already set.
|
|
11
12
|
if (!process.env.CYBERMEM_INSTANCE) {
|
|
12
|
-
|
|
13
|
-
console.error(
|
|
14
|
-
process.exit(1);
|
|
13
|
+
process.env.CYBERMEM_INSTANCE = `local-${os_1.default.hostname()}`;
|
|
14
|
+
console.error(`[MCP] No CYBERMEM_INSTANCE set, defaulting to "${process.env.CYBERMEM_INSTANCE}"`);
|
|
15
15
|
}
|
|
16
16
|
// Normalize OM_DB_PATH early so all components (SDK, exporters) use the same file
|
|
17
17
|
const homedir = os_1.default.homedir();
|
package/dist/index.js
CHANGED
|
@@ -10,7 +10,6 @@ const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js");
|
|
|
10
10
|
const streamableHttp_js_1 = require("@modelcontextprotocol/sdk/server/streamableHttp.js");
|
|
11
11
|
const types_js_1 = require("@modelcontextprotocol/sdk/types.js");
|
|
12
12
|
const async_hooks_1 = require("async_hooks");
|
|
13
|
-
const axios_1 = __importDefault(require("axios"));
|
|
14
13
|
const cors_1 = __importDefault(require("cors"));
|
|
15
14
|
const express_1 = __importDefault(require("express"));
|
|
16
15
|
const zod_1 = require("zod");
|
|
@@ -25,8 +24,6 @@ async function startServer() {
|
|
|
25
24
|
const idx = args.indexOf(name);
|
|
26
25
|
return idx !== -1 && args[idx + 1] ? args[idx + 1] : undefined;
|
|
27
26
|
};
|
|
28
|
-
const cliUrl = getArg("--url");
|
|
29
|
-
const cliToken = getArg("--token") || getArg("--api-key");
|
|
30
27
|
const cliEnv = getArg("--env");
|
|
31
28
|
if (cliEnv === "staging") {
|
|
32
29
|
console.error("[MCP] Running in Staging environment");
|
|
@@ -73,65 +70,46 @@ For full protocol: https://docs.cybermem.dev/agent-protocol`;
|
|
|
73
70
|
});
|
|
74
71
|
// --- IMPLEMENTATION LOGIC ---
|
|
75
72
|
let memory = null;
|
|
76
|
-
let apiClient = null;
|
|
77
73
|
let sdk_update_memory = null;
|
|
78
74
|
let sdk_reinforce_memory = null;
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
75
|
+
// LOCAL SDK MODE
|
|
76
|
+
const dbPath = process.env.OM_DB_PATH;
|
|
77
|
+
const fs = await import("fs");
|
|
78
|
+
const path = await import("path");
|
|
79
|
+
try {
|
|
80
|
+
const dir = path.dirname(dbPath);
|
|
81
|
+
if (dir)
|
|
82
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
83
|
+
}
|
|
84
|
+
catch { }
|
|
85
|
+
try {
|
|
86
|
+
const { Memory } = await import("openmemory-js/dist/core/memory.js");
|
|
87
|
+
const hsg = await import("openmemory-js/dist/memory/hsg.js");
|
|
88
|
+
sdk_update_memory = hsg.update_memory;
|
|
89
|
+
sdk_reinforce_memory = hsg.reinforce_memory;
|
|
90
|
+
memory = new Memory();
|
|
91
|
+
server._memoryReady = true;
|
|
92
|
+
// Initialize Tables
|
|
93
|
+
const sqlite3 = await import("sqlite3");
|
|
94
|
+
const db = new sqlite3.default.Database(dbPath);
|
|
95
|
+
db.configure("busyTimeout", 5000);
|
|
96
|
+
db.serialize(() => {
|
|
97
|
+
db.run("CREATE TABLE IF NOT EXISTS cybermem_stats (id INTEGER PRIMARY KEY AUTOINCREMENT, client_name TEXT NOT NULL, operation TEXT NOT NULL, count INTEGER DEFAULT 0, errors INTEGER DEFAULT 0, last_updated INTEGER NOT NULL, UNIQUE(client_name, operation));");
|
|
98
|
+
db.run("CREATE TABLE IF NOT EXISTS cybermem_access_log (id INTEGER PRIMARY KEY AUTOINCREMENT, timestamp INTEGER NOT NULL, client_name TEXT NOT NULL, client_version TEXT, method TEXT NOT NULL, endpoint TEXT NOT NULL, operation TEXT NOT NULL, status TEXT NOT NULL, is_error INTEGER DEFAULT 0);");
|
|
99
|
+
db.run("CREATE TABLE IF NOT EXISTS access_keys (id TEXT PRIMARY KEY DEFAULT (lower(hex(randomblob(16)))), key_hash TEXT NOT NULL, name TEXT DEFAULT 'default', user_id TEXT DEFAULT 'default', created_at TEXT DEFAULT (datetime('now')), last_used_at TEXT, is_active INTEGER DEFAULT 1);");
|
|
95
100
|
});
|
|
101
|
+
db.close();
|
|
96
102
|
}
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
try {
|
|
103
|
-
const dir = path.dirname(dbPath);
|
|
104
|
-
if (dir)
|
|
105
|
-
fs.mkdirSync(dir, { recursive: true });
|
|
106
|
-
}
|
|
107
|
-
catch { }
|
|
108
|
-
try {
|
|
109
|
-
const { Memory } = await import("openmemory-js/dist/core/memory.js");
|
|
110
|
-
const hsg = await import("openmemory-js/dist/memory/hsg.js");
|
|
111
|
-
sdk_update_memory = hsg.update_memory;
|
|
112
|
-
sdk_reinforce_memory = hsg.reinforce_memory;
|
|
113
|
-
memory = new Memory();
|
|
114
|
-
server._memoryReady = true;
|
|
115
|
-
// Initialize Tables
|
|
116
|
-
const sqlite3 = await import("sqlite3");
|
|
117
|
-
const db = new sqlite3.default.Database(dbPath);
|
|
118
|
-
db.configure("busyTimeout", 5000);
|
|
119
|
-
db.serialize(() => {
|
|
120
|
-
db.run("CREATE TABLE IF NOT EXISTS cybermem_stats (id INTEGER PRIMARY KEY AUTOINCREMENT, client_name TEXT NOT NULL, operation TEXT NOT NULL, count INTEGER DEFAULT 0, errors INTEGER DEFAULT 0, last_updated INTEGER NOT NULL, UNIQUE(client_name, operation));");
|
|
121
|
-
db.run("CREATE TABLE IF NOT EXISTS cybermem_access_log (id INTEGER PRIMARY KEY AUTOINCREMENT, timestamp INTEGER NOT NULL, client_name TEXT NOT NULL, client_version TEXT, method TEXT NOT NULL, endpoint TEXT NOT NULL, operation TEXT NOT NULL, status TEXT NOT NULL, is_error INTEGER DEFAULT 0);");
|
|
122
|
-
db.run("CREATE TABLE IF NOT EXISTS access_keys (id TEXT PRIMARY KEY DEFAULT (lower(hex(randomblob(16)))), key_hash TEXT NOT NULL, name TEXT DEFAULT 'default', user_id TEXT DEFAULT 'default', created_at TEXT DEFAULT (datetime('now')), last_used_at TEXT, is_active INTEGER DEFAULT 1);");
|
|
123
|
-
});
|
|
124
|
-
db.close();
|
|
125
|
-
}
|
|
126
|
-
catch (e) {
|
|
127
|
-
console.error("Failed to initialize OpenMemory SDK:", e);
|
|
128
|
-
server._memoryReady = false;
|
|
129
|
-
}
|
|
103
|
+
catch (e) {
|
|
104
|
+
console.error("Failed to initialize OpenMemory SDK:", e);
|
|
105
|
+
console.error("[FATAL] CyberMem cannot start without a working database. " +
|
|
106
|
+
"Check OM_DB_PATH and ensure sqlite3 native bindings are installed.");
|
|
107
|
+
process.exit(1);
|
|
130
108
|
}
|
|
131
109
|
// PERSISTENT LOGGING DB
|
|
132
110
|
let loggingDb = null;
|
|
133
111
|
const initLoggingDb = async () => {
|
|
134
|
-
if (loggingDb
|
|
112
|
+
if (loggingDb)
|
|
135
113
|
return loggingDb;
|
|
136
114
|
const dbPath = process.env.OM_DB_PATH;
|
|
137
115
|
const sqlite3 = await import("sqlite3");
|
|
@@ -145,7 +123,7 @@ For full protocol: https://docs.cybermem.dev/agent-protocol`;
|
|
|
145
123
|
});
|
|
146
124
|
};
|
|
147
125
|
const logActivity = async (operation, opts = {}) => {
|
|
148
|
-
if (
|
|
126
|
+
if (!memory)
|
|
149
127
|
return;
|
|
150
128
|
const { client: providedClient, method = "POST", endpoint = "/mcp", status = 200, } = opts;
|
|
151
129
|
const ctx = requestContext.getStore();
|
|
@@ -182,37 +160,25 @@ For full protocol: https://docs.cybermem.dev/agent-protocol`;
|
|
|
182
160
|
tags: zod_1.z.array(zod_1.z.string()).optional(),
|
|
183
161
|
}),
|
|
184
162
|
}, async (args) => {
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
method: "POST",
|
|
193
|
-
endpoint: "/memory/add",
|
|
194
|
-
status: 200,
|
|
195
|
-
});
|
|
196
|
-
return { content: [{ type: "text", text: JSON.stringify(res) }] };
|
|
197
|
-
}
|
|
163
|
+
const res = await memory.add(args.content, { tags: args.tags });
|
|
164
|
+
await logActivity("create", {
|
|
165
|
+
method: "POST",
|
|
166
|
+
endpoint: "/memory/add",
|
|
167
|
+
status: 200,
|
|
168
|
+
});
|
|
169
|
+
return { content: [{ type: "text", text: JSON.stringify(res) }] };
|
|
198
170
|
});
|
|
199
171
|
server.registerTool("query_memory", {
|
|
200
172
|
description: "Search memories.",
|
|
201
173
|
inputSchema: zod_1.z.object({ query: zod_1.z.string(), k: zod_1.z.number().default(5) }),
|
|
202
174
|
}, async (args) => {
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
method: "POST",
|
|
211
|
-
endpoint: "/memory/query",
|
|
212
|
-
status: 200,
|
|
213
|
-
});
|
|
214
|
-
return { content: [{ type: "text", text: JSON.stringify(res) }] };
|
|
215
|
-
}
|
|
175
|
+
const res = await memory.search(args.query, { limit: args.k });
|
|
176
|
+
await logActivity("read", {
|
|
177
|
+
method: "POST",
|
|
178
|
+
endpoint: "/memory/query",
|
|
179
|
+
status: 200,
|
|
180
|
+
});
|
|
181
|
+
return { content: [{ type: "text", text: JSON.stringify(res) }] };
|
|
216
182
|
});
|
|
217
183
|
server.registerTool("update_memory", {
|
|
218
184
|
description: "Mutate existing memory (content/tags). HIGH COST: re-embeds and re-links. Use for corrections.",
|
|
@@ -222,74 +188,57 @@ For full protocol: https://docs.cybermem.dev/agent-protocol`;
|
|
|
222
188
|
tags: zod_1.z.array(zod_1.z.string()).optional(),
|
|
223
189
|
}),
|
|
224
190
|
}, async (args) => {
|
|
225
|
-
if (
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
method: "PATCH",
|
|
235
|
-
endpoint: `/memory/${args.id}`,
|
|
236
|
-
status: 200,
|
|
237
|
-
});
|
|
238
|
-
return { content: [{ type: "text", text: JSON.stringify(res) }] };
|
|
239
|
-
}
|
|
191
|
+
if (!sdk_update_memory)
|
|
192
|
+
throw new Error("Update not available in SDK");
|
|
193
|
+
const res = await sdk_update_memory(args.id, args.content, args.tags);
|
|
194
|
+
await logActivity("update", {
|
|
195
|
+
method: "PATCH",
|
|
196
|
+
endpoint: `/memory/${args.id}`,
|
|
197
|
+
status: 200,
|
|
198
|
+
});
|
|
199
|
+
return { content: [{ type: "text", text: JSON.stringify(res) }] };
|
|
240
200
|
});
|
|
241
201
|
server.registerTool("reinforce_memory", {
|
|
242
202
|
description: "Metabolic boost (salience). LOW COST: prevents decay without mutation. Use for active topics.",
|
|
243
203
|
inputSchema: zod_1.z.object({ id: zod_1.z.string(), boost: zod_1.z.number().default(0.1) }),
|
|
244
204
|
}, async (args) => {
|
|
245
|
-
if (
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
method: "POST",
|
|
255
|
-
endpoint: `/memory/${args.id}/reinforce`,
|
|
256
|
-
status: 200,
|
|
257
|
-
});
|
|
258
|
-
return { content: [{ type: "text", text: "Reinforced" }] };
|
|
259
|
-
}
|
|
205
|
+
if (!sdk_reinforce_memory)
|
|
206
|
+
throw new Error("Reinforce not available in SDK");
|
|
207
|
+
await sdk_reinforce_memory(args.id, args.boost);
|
|
208
|
+
await logActivity("update", {
|
|
209
|
+
method: "POST",
|
|
210
|
+
endpoint: `/memory/${args.id}/reinforce`,
|
|
211
|
+
status: 200,
|
|
212
|
+
});
|
|
213
|
+
return { content: [{ type: "text", text: "Reinforced" }] };
|
|
260
214
|
});
|
|
261
215
|
server.registerTool("delete_memory", {
|
|
262
216
|
description: "Delete memory",
|
|
263
217
|
inputSchema: zod_1.z.object({ id: zod_1.z.string() }),
|
|
264
218
|
}, async (args) => {
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
db.close();
|
|
278
|
-
await logActivity("delete", {
|
|
279
|
-
method: "DELETE",
|
|
280
|
-
endpoint: `/memory/${args.id}`,
|
|
281
|
-
status: err ? 500 : 200,
|
|
282
|
-
});
|
|
283
|
-
if (err)
|
|
284
|
-
reject(err);
|
|
285
|
-
else
|
|
286
|
-
resolve({ content: [{ type: "text", text: "Deleted" }] });
|
|
219
|
+
const dbPath = process.env.OM_DB_PATH;
|
|
220
|
+
const sqlite3 = await import("sqlite3");
|
|
221
|
+
const db = new sqlite3.default.Database(dbPath);
|
|
222
|
+
return new Promise((resolve, reject) => {
|
|
223
|
+
db.serialize(() => {
|
|
224
|
+
db.run("DELETE FROM memories WHERE id = ?", [args.id]);
|
|
225
|
+
db.run("DELETE FROM vectors WHERE id = ?", [args.id], async (err) => {
|
|
226
|
+
db.close();
|
|
227
|
+
await logActivity("delete", {
|
|
228
|
+
method: "DELETE",
|
|
229
|
+
endpoint: `/memory/${args.id}`,
|
|
230
|
+
status: err ? 500 : 200,
|
|
287
231
|
});
|
|
232
|
+
if (err)
|
|
233
|
+
reject(err);
|
|
234
|
+
else
|
|
235
|
+
resolve({ content: [{ type: "text", text: "Deleted" }] });
|
|
288
236
|
});
|
|
289
237
|
});
|
|
290
|
-
}
|
|
238
|
+
});
|
|
291
239
|
});
|
|
292
240
|
// EXPRESS SERVER
|
|
241
|
+
// HTTP server mode for Docker/Traefik deployment
|
|
293
242
|
const useHttp = args.includes("--http") || args.includes("--port");
|
|
294
243
|
if (useHttp) {
|
|
295
244
|
const port = parseInt(getArg("--port") || "3100", 10);
|
|
@@ -302,7 +251,7 @@ For full protocol: https://docs.cybermem.dev/agent-protocol`;
|
|
|
302
251
|
requestContext.run({ clientName }, next);
|
|
303
252
|
// next(); // DELETED! Correctly handled by requestContext.run
|
|
304
253
|
});
|
|
305
|
-
if (
|
|
254
|
+
if (memory) {
|
|
306
255
|
app.post("/add", async (req, res) => {
|
|
307
256
|
try {
|
|
308
257
|
const result = await memory.add(req.body.content, {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cybermem/mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.14.4",
|
|
4
4
|
"description": "CyberMem MCP Server - AI Memory with openmemory-js SDK",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -11,7 +11,9 @@
|
|
|
11
11
|
"start": "node dist/index.js",
|
|
12
12
|
"dev": "ts-node src/index.ts",
|
|
13
13
|
"lint": "tsc --noEmit",
|
|
14
|
-
"test:e2e": "playwright test"
|
|
14
|
+
"test:e2e": "playwright test",
|
|
15
|
+
"inspect": "mcp-inspector npx ts-node src/index.ts",
|
|
16
|
+
"inspect:built": "mcp-inspector node dist/index.js"
|
|
15
17
|
},
|
|
16
18
|
"repository": {
|
|
17
19
|
"type": "git",
|
|
@@ -37,7 +39,6 @@
|
|
|
37
39
|
},
|
|
38
40
|
"dependencies": {
|
|
39
41
|
"@modelcontextprotocol/sdk": "^1.0.0",
|
|
40
|
-
"axios": "^1.13.2",
|
|
41
42
|
"cors": "^2.8.5",
|
|
42
43
|
"dotenv": "^16.0.0",
|
|
43
44
|
"express": "^5.2.1",
|
|
@@ -52,6 +53,7 @@
|
|
|
52
53
|
"@types/cors": "^2.8.19",
|
|
53
54
|
"@types/express": "^5.0.6",
|
|
54
55
|
"@types/node": "^18.0.0",
|
|
56
|
+
"@modelcontextprotocol/inspector": "^0.19.0",
|
|
55
57
|
"ts-node": "^10.9.1",
|
|
56
58
|
"typescript": "^5.0.0"
|
|
57
59
|
}
|
package/src/env.ts
CHANGED
|
@@ -4,15 +4,13 @@ import path from "path";
|
|
|
4
4
|
|
|
5
5
|
dotenv.config();
|
|
6
6
|
|
|
7
|
-
//
|
|
7
|
+
// Auto-set CYBERMEM_INSTANCE for stdio mode (npx @cybermem/mcp)
|
|
8
|
+
// When started via @cybermem/cli, CYBERMEM_INSTANCE is already set.
|
|
8
9
|
if (!process.env.CYBERMEM_INSTANCE) {
|
|
10
|
+
process.env.CYBERMEM_INSTANCE = `local-${os.hostname()}`;
|
|
9
11
|
console.error(
|
|
10
|
-
|
|
12
|
+
`[MCP] No CYBERMEM_INSTANCE set, defaulting to "${process.env.CYBERMEM_INSTANCE}"`,
|
|
11
13
|
);
|
|
12
|
-
console.error(
|
|
13
|
-
"Manual 'npm start' or 'docker-compose up' without CLI tagging is forbidden.\n",
|
|
14
|
-
);
|
|
15
|
-
process.exit(1);
|
|
16
14
|
}
|
|
17
15
|
|
|
18
16
|
// Normalize OM_DB_PATH early so all components (SDK, exporters) use the same file
|
package/src/index.ts
CHANGED
|
@@ -6,7 +6,6 @@ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
|
|
|
6
6
|
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
|
|
7
7
|
import { InitializeRequestSchema } from "@modelcontextprotocol/sdk/types.js";
|
|
8
8
|
import { AsyncLocalStorage } from "async_hooks";
|
|
9
|
-
import axios from "axios";
|
|
10
9
|
import cors from "cors";
|
|
11
10
|
import express from "express";
|
|
12
11
|
import { z } from "zod";
|
|
@@ -29,8 +28,6 @@ async function startServer() {
|
|
|
29
28
|
return idx !== -1 && args[idx + 1] ? args[idx + 1] : undefined;
|
|
30
29
|
};
|
|
31
30
|
|
|
32
|
-
const cliUrl = getArg("--url");
|
|
33
|
-
const cliToken = getArg("--token") || getArg("--api-key");
|
|
34
31
|
const cliEnv = getArg("--env");
|
|
35
32
|
|
|
36
33
|
if (cliEnv === "staging") {
|
|
@@ -93,71 +90,55 @@ For full protocol: https://docs.cybermem.dev/agent-protocol`;
|
|
|
93
90
|
// --- IMPLEMENTATION LOGIC ---
|
|
94
91
|
|
|
95
92
|
let memory: any = null;
|
|
96
|
-
let apiClient: any = null;
|
|
97
93
|
let sdk_update_memory: any = null;
|
|
98
94
|
let sdk_reinforce_memory: any = null;
|
|
99
95
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
"Content-Type": "application/json",
|
|
109
|
-
},
|
|
110
|
-
});
|
|
111
|
-
apiClient.interceptors.request.use((config: any) => {
|
|
112
|
-
const ctx = requestContext.getStore();
|
|
113
|
-
config.headers["X-Client-Name"] =
|
|
114
|
-
ctx?.clientName || stdioClientName || "antigravity-client";
|
|
115
|
-
return config;
|
|
116
|
-
});
|
|
117
|
-
} else {
|
|
118
|
-
// LOCAL SDK MODE
|
|
119
|
-
const dbPath = process.env.OM_DB_PATH!;
|
|
120
|
-
const fs = await import("fs");
|
|
121
|
-
const path = await import("path");
|
|
122
|
-
try {
|
|
123
|
-
const dir = path.dirname(dbPath);
|
|
124
|
-
if (dir) fs.mkdirSync(dir, { recursive: true });
|
|
125
|
-
} catch {}
|
|
96
|
+
// LOCAL SDK MODE
|
|
97
|
+
const dbPath = process.env.OM_DB_PATH!;
|
|
98
|
+
const fs = await import("fs");
|
|
99
|
+
const path = await import("path");
|
|
100
|
+
try {
|
|
101
|
+
const dir = path.dirname(dbPath);
|
|
102
|
+
if (dir) fs.mkdirSync(dir, { recursive: true });
|
|
103
|
+
} catch {}
|
|
126
104
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
105
|
+
try {
|
|
106
|
+
const { Memory } = await import("openmemory-js/dist/core/memory.js");
|
|
107
|
+
const hsg = await import("openmemory-js/dist/memory/hsg.js");
|
|
108
|
+
sdk_update_memory = hsg.update_memory;
|
|
109
|
+
sdk_reinforce_memory = hsg.reinforce_memory;
|
|
110
|
+
memory = new Memory();
|
|
111
|
+
(server as any)._memoryReady = true;
|
|
134
112
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
113
|
+
// Initialize Tables
|
|
114
|
+
const sqlite3 = await import("sqlite3");
|
|
115
|
+
const db = new sqlite3.default.Database(dbPath);
|
|
116
|
+
db.configure("busyTimeout", 5000);
|
|
117
|
+
db.serialize(() => {
|
|
118
|
+
db.run(
|
|
119
|
+
"CREATE TABLE IF NOT EXISTS cybermem_stats (id INTEGER PRIMARY KEY AUTOINCREMENT, client_name TEXT NOT NULL, operation TEXT NOT NULL, count INTEGER DEFAULT 0, errors INTEGER DEFAULT 0, last_updated INTEGER NOT NULL, UNIQUE(client_name, operation));",
|
|
120
|
+
);
|
|
121
|
+
db.run(
|
|
122
|
+
"CREATE TABLE IF NOT EXISTS cybermem_access_log (id INTEGER PRIMARY KEY AUTOINCREMENT, timestamp INTEGER NOT NULL, client_name TEXT NOT NULL, client_version TEXT, method TEXT NOT NULL, endpoint TEXT NOT NULL, operation TEXT NOT NULL, status TEXT NOT NULL, is_error INTEGER DEFAULT 0);",
|
|
123
|
+
);
|
|
124
|
+
db.run(
|
|
125
|
+
"CREATE TABLE IF NOT EXISTS access_keys (id TEXT PRIMARY KEY DEFAULT (lower(hex(randomblob(16)))), key_hash TEXT NOT NULL, name TEXT DEFAULT 'default', user_id TEXT DEFAULT 'default', created_at TEXT DEFAULT (datetime('now')), last_used_at TEXT, is_active INTEGER DEFAULT 1);",
|
|
126
|
+
);
|
|
127
|
+
});
|
|
128
|
+
db.close();
|
|
129
|
+
} catch (e) {
|
|
130
|
+
console.error("Failed to initialize OpenMemory SDK:", e);
|
|
131
|
+
console.error(
|
|
132
|
+
"[FATAL] CyberMem cannot start without a working database. " +
|
|
133
|
+
"Check OM_DB_PATH and ensure sqlite3 native bindings are installed.",
|
|
134
|
+
);
|
|
135
|
+
process.exit(1);
|
|
155
136
|
}
|
|
156
137
|
|
|
157
138
|
// PERSISTENT LOGGING DB
|
|
158
139
|
let loggingDb: any = null;
|
|
159
140
|
const initLoggingDb = async () => {
|
|
160
|
-
if (loggingDb
|
|
141
|
+
if (loggingDb) return loggingDb;
|
|
161
142
|
const dbPath = process.env.OM_DB_PATH!;
|
|
162
143
|
const sqlite3 = await import("sqlite3");
|
|
163
144
|
loggingDb = new sqlite3.default.Database(dbPath);
|
|
@@ -179,7 +160,7 @@ For full protocol: https://docs.cybermem.dev/agent-protocol`;
|
|
|
179
160
|
status?: number;
|
|
180
161
|
} = {},
|
|
181
162
|
) => {
|
|
182
|
-
if (
|
|
163
|
+
if (!memory) return;
|
|
183
164
|
const {
|
|
184
165
|
client: providedClient,
|
|
185
166
|
method = "POST",
|
|
@@ -231,18 +212,13 @@ For full protocol: https://docs.cybermem.dev/agent-protocol`;
|
|
|
231
212
|
}),
|
|
232
213
|
},
|
|
233
214
|
async (args: any) => {
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
endpoint: "/memory/add",
|
|
242
|
-
status: 200,
|
|
243
|
-
});
|
|
244
|
-
return { content: [{ type: "text", text: JSON.stringify(res) }] };
|
|
245
|
-
}
|
|
215
|
+
const res = await memory!.add(args.content, { tags: args.tags });
|
|
216
|
+
await logActivity("create", {
|
|
217
|
+
method: "POST",
|
|
218
|
+
endpoint: "/memory/add",
|
|
219
|
+
status: 200,
|
|
220
|
+
});
|
|
221
|
+
return { content: [{ type: "text", text: JSON.stringify(res) }] };
|
|
246
222
|
},
|
|
247
223
|
);
|
|
248
224
|
|
|
@@ -253,18 +229,13 @@ For full protocol: https://docs.cybermem.dev/agent-protocol`;
|
|
|
253
229
|
inputSchema: z.object({ query: z.string(), k: z.number().default(5) }),
|
|
254
230
|
},
|
|
255
231
|
async (args: any) => {
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
endpoint: "/memory/query",
|
|
264
|
-
status: 200,
|
|
265
|
-
});
|
|
266
|
-
return { content: [{ type: "text", text: JSON.stringify(res) }] };
|
|
267
|
-
}
|
|
232
|
+
const res = await memory!.search(args.query, { limit: args.k });
|
|
233
|
+
await logActivity("read", {
|
|
234
|
+
method: "POST",
|
|
235
|
+
endpoint: "/memory/query",
|
|
236
|
+
status: 200,
|
|
237
|
+
});
|
|
238
|
+
return { content: [{ type: "text", text: JSON.stringify(res) }] };
|
|
268
239
|
},
|
|
269
240
|
);
|
|
270
241
|
|
|
@@ -280,19 +251,14 @@ For full protocol: https://docs.cybermem.dev/agent-protocol`;
|
|
|
280
251
|
}),
|
|
281
252
|
},
|
|
282
253
|
async (args: any) => {
|
|
283
|
-
if (
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
endpoint: `/memory/${args.id}`,
|
|
292
|
-
status: 200,
|
|
293
|
-
});
|
|
294
|
-
return { content: [{ type: "text", text: JSON.stringify(res) }] };
|
|
295
|
-
}
|
|
254
|
+
if (!sdk_update_memory) throw new Error("Update not available in SDK");
|
|
255
|
+
const res = await sdk_update_memory(args.id, args.content, args.tags);
|
|
256
|
+
await logActivity("update", {
|
|
257
|
+
method: "PATCH",
|
|
258
|
+
endpoint: `/memory/${args.id}`,
|
|
259
|
+
status: 200,
|
|
260
|
+
});
|
|
261
|
+
return { content: [{ type: "text", text: JSON.stringify(res) }] };
|
|
296
262
|
},
|
|
297
263
|
);
|
|
298
264
|
|
|
@@ -304,20 +270,15 @@ For full protocol: https://docs.cybermem.dev/agent-protocol`;
|
|
|
304
270
|
inputSchema: z.object({ id: z.string(), boost: z.number().default(0.1) }),
|
|
305
271
|
},
|
|
306
272
|
async (args: any) => {
|
|
307
|
-
if (
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
endpoint: `/memory/${args.id}/reinforce`,
|
|
317
|
-
status: 200,
|
|
318
|
-
});
|
|
319
|
-
return { content: [{ type: "text", text: "Reinforced" }] };
|
|
320
|
-
}
|
|
273
|
+
if (!sdk_reinforce_memory)
|
|
274
|
+
throw new Error("Reinforce not available in SDK");
|
|
275
|
+
await sdk_reinforce_memory(args.id, args.boost);
|
|
276
|
+
await logActivity("update", {
|
|
277
|
+
method: "POST",
|
|
278
|
+
endpoint: `/memory/${args.id}/reinforce`,
|
|
279
|
+
status: 200,
|
|
280
|
+
});
|
|
281
|
+
return { content: [{ type: "text", text: "Reinforced" }] };
|
|
321
282
|
},
|
|
322
283
|
);
|
|
323
284
|
|
|
@@ -328,37 +289,33 @@ For full protocol: https://docs.cybermem.dev/agent-protocol`;
|
|
|
328
289
|
inputSchema: z.object({ id: z.string() }),
|
|
329
290
|
},
|
|
330
291
|
async (args: any) => {
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
if (err) reject(err);
|
|
352
|
-
else resolve({ content: [{ type: "text", text: "Deleted" }] });
|
|
353
|
-
},
|
|
354
|
-
);
|
|
355
|
-
});
|
|
292
|
+
const dbPath = process.env.OM_DB_PATH!;
|
|
293
|
+
const sqlite3 = await import("sqlite3");
|
|
294
|
+
const db = new sqlite3.default.Database(dbPath);
|
|
295
|
+
return new Promise((resolve, reject) => {
|
|
296
|
+
db.serialize(() => {
|
|
297
|
+
db.run("DELETE FROM memories WHERE id = ?", [args.id]);
|
|
298
|
+
db.run(
|
|
299
|
+
"DELETE FROM vectors WHERE id = ?",
|
|
300
|
+
[args.id],
|
|
301
|
+
async (err: any) => {
|
|
302
|
+
db.close();
|
|
303
|
+
await logActivity("delete", {
|
|
304
|
+
method: "DELETE",
|
|
305
|
+
endpoint: `/memory/${args.id}`,
|
|
306
|
+
status: err ? 500 : 200,
|
|
307
|
+
});
|
|
308
|
+
if (err) reject(err);
|
|
309
|
+
else resolve({ content: [{ type: "text", text: "Deleted" }] });
|
|
310
|
+
},
|
|
311
|
+
);
|
|
356
312
|
});
|
|
357
|
-
}
|
|
313
|
+
});
|
|
358
314
|
},
|
|
359
315
|
);
|
|
360
316
|
|
|
361
317
|
// EXPRESS SERVER
|
|
318
|
+
// HTTP server mode for Docker/Traefik deployment
|
|
362
319
|
const useHttp = args.includes("--http") || args.includes("--port");
|
|
363
320
|
if (useHttp) {
|
|
364
321
|
const port = parseInt(getArg("--port") || "3100", 10);
|
|
@@ -374,7 +331,7 @@ For full protocol: https://docs.cybermem.dev/agent-protocol`;
|
|
|
374
331
|
// next(); // DELETED! Correctly handled by requestContext.run
|
|
375
332
|
});
|
|
376
333
|
|
|
377
|
-
if (
|
|
334
|
+
if (memory) {
|
|
378
335
|
app.post("/add", async (req, res) => {
|
|
379
336
|
try {
|
|
380
337
|
const result = await (memory as any)!.add(req.body.content, {
|