@aeriondyseti/vector-memory-mcp 0.4.0 ā 0.8.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 +37 -23
- package/hooks/session-start.ts +100 -0
- package/package.json +22 -6
- package/scripts/publish.ts +61 -0
- package/scripts/test-runner.ts +66 -0
- package/scripts/warmup.ts +1 -2
- package/src/config/index.ts +57 -11
- package/src/db/memory.repository.ts +21 -0
- package/src/db/schema.ts +1 -0
- package/src/http/mcp-transport.ts +255 -0
- package/src/http/server.ts +190 -0
- package/src/index.ts +43 -4
- package/src/mcp/handlers.ts +169 -33
- package/src/mcp/server.ts +1 -1
- package/src/mcp/tools.ts +165 -42
- package/src/services/embeddings.service.ts +5 -3
- package/src/services/memory.service.ts +109 -31
- package/src/types/memory.ts +0 -4
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
A production-ready MCP (Model Context Protocol) server that provides semantic memory storage for AI assistants. Uses local embeddings and vector search to automatically retrieve relevant context without cloud dependencies.
|
|
6
6
|
|
|
7
|
-
**Perfect for:** Software teams maintaining architectural knowledge, developers juggling multiple projects, and anyone building with AI assistants
|
|
7
|
+
**Perfect for:** Software teams maintaining architectural knowledge, developers juggling multiple projects, and anyone building with MCP-compatible AI assistants.
|
|
8
8
|
|
|
9
9
|
[](https://opensource.org/licenses/MIT)
|
|
10
10
|
[](https://www.typescriptlang.org/)
|
|
@@ -36,9 +36,7 @@ A production-ready MCP (Model Context Protocol) server that provides semantic me
|
|
|
36
36
|
- CPU-optimized local embeddings (no GPU required)
|
|
37
37
|
|
|
38
38
|
### š **MCP Native Integration**
|
|
39
|
-
-
|
|
40
|
-
- Session hooks for automatic context injection
|
|
41
|
-
- Standard MCP protocol (compatible with future clients)
|
|
39
|
+
- Standard MCP protocol (compatible with any client)
|
|
42
40
|
|
|
43
41
|
### š ļø **Developer-Friendly**
|
|
44
42
|
- Zero-configuration setup
|
|
@@ -53,7 +51,7 @@ A production-ready MCP (Model Context Protocol) server that provides semantic me
|
|
|
53
51
|
### Prerequisites
|
|
54
52
|
|
|
55
53
|
- [Bun](https://bun.sh/) 1.0+
|
|
56
|
-
-
|
|
54
|
+
- An MCP-compatible client
|
|
57
55
|
|
|
58
56
|
> **Note:** This server requires Bun to run.
|
|
59
57
|
|
|
@@ -68,12 +66,18 @@ bun install -g @aeriondyseti/vector-memory-mcp
|
|
|
68
66
|
|
|
69
67
|
> **Note:** The installation automatically downloads ML models (~90MB) and verifies native dependencies. This may take a minute on first install.
|
|
70
68
|
|
|
71
|
-
**Configure
|
|
69
|
+
**Configure your MCP client** (example config for clients that use `~/.claude/config.json`):
|
|
72
70
|
```json
|
|
73
71
|
{
|
|
74
72
|
"mcpServers": {
|
|
75
73
|
"memory": {
|
|
76
|
-
"
|
|
74
|
+
"type": "stdio",
|
|
75
|
+
"command": "bunx",
|
|
76
|
+
"args": [
|
|
77
|
+
"--bun",
|
|
78
|
+
"@aeriondyseti/vector-memory-mcp"
|
|
79
|
+
],
|
|
80
|
+
"env": {}
|
|
77
81
|
}
|
|
78
82
|
}
|
|
79
83
|
}
|
|
@@ -88,7 +92,7 @@ cd vector-memory-mcp
|
|
|
88
92
|
bun install
|
|
89
93
|
```
|
|
90
94
|
|
|
91
|
-
**Configure
|
|
95
|
+
**Configure your MCP client** (example config for clients that use `~/.claude/config.json`):
|
|
92
96
|
```json
|
|
93
97
|
{
|
|
94
98
|
"mcpServers": {
|
|
@@ -113,11 +117,14 @@ bun install
|
|
|
113
117
|
|
|
114
118
|
### Start Using It
|
|
115
119
|
|
|
116
|
-
That's it! Restart
|
|
117
|
-
- `
|
|
120
|
+
That's it! Restart your MCP client and you'll have access to memory tools:
|
|
121
|
+
- `store_memories` - Save memories for later recall (always pass array)
|
|
118
122
|
- `search_memories` - Find relevant memories semantically
|
|
119
|
-
- `
|
|
120
|
-
- `
|
|
123
|
+
- `get_memories` - Retrieve memories by ID (always pass array)
|
|
124
|
+
- `update_memories` - Update existing memories in place
|
|
125
|
+
- `delete_memories` - Remove memories (always pass array of IDs)
|
|
126
|
+
- `store_handoff` - Store a handoff-style project snapshot
|
|
127
|
+
- `get_handoff` - Retrieve the latest handoff (includes referenced memories)
|
|
121
128
|
|
|
122
129
|
---
|
|
123
130
|
|
|
@@ -125,14 +132,14 @@ That's it! Restart Claude Code and you'll have access to memory tools:
|
|
|
125
132
|
|
|
126
133
|
### Storing Memories
|
|
127
134
|
|
|
128
|
-
Ask
|
|
135
|
+
Ask your MCP client/agent to remember things for you:
|
|
129
136
|
|
|
130
137
|
```
|
|
131
138
|
You: "Remember that we use Drizzle ORM for database access"
|
|
132
|
-
Claude: [calls
|
|
139
|
+
Claude: [calls store_memories tool]
|
|
133
140
|
```
|
|
134
141
|
|
|
135
|
-
Or
|
|
142
|
+
Or your MCP client/agent can store memories directly:
|
|
136
143
|
```json
|
|
137
144
|
{
|
|
138
145
|
"content": "Use Drizzle ORM for type-safe database access",
|
|
@@ -145,7 +152,7 @@ Or Claude Code can store memories directly:
|
|
|
145
152
|
|
|
146
153
|
### Searching Memories
|
|
147
154
|
|
|
148
|
-
|
|
155
|
+
Your MCP client/agent can automatically search memories when relevant, or you can ask:
|
|
149
156
|
|
|
150
157
|
```
|
|
151
158
|
You: "What did we decide about the database?"
|
|
@@ -217,7 +224,7 @@ vector-memory-mcp/
|
|
|
217
224
|
### 1. Memory Storage
|
|
218
225
|
|
|
219
226
|
```
|
|
220
|
-
|
|
227
|
+
An MCP client calls store_memories tool
|
|
221
228
|
ā
|
|
222
229
|
Content ā @huggingface/transformers ā 384d vector
|
|
223
230
|
ā
|
|
@@ -229,7 +236,7 @@ Store in LanceDB with metadata
|
|
|
229
236
|
### 2. Memory Retrieval
|
|
230
237
|
|
|
231
238
|
```
|
|
232
|
-
|
|
239
|
+
An MCP client calls search_memories
|
|
233
240
|
ā
|
|
234
241
|
Query ā @huggingface/transformers ā 384d vector
|
|
235
242
|
ā
|
|
@@ -246,7 +253,9 @@ Return top N relevant memories
|
|
|
246
253
|
|
|
247
254
|
The server uses environment variables for configuration:
|
|
248
255
|
|
|
249
|
-
- `VECTOR_MEMORY_DB_PATH` - Custom database path (default:
|
|
256
|
+
- `VECTOR_MEMORY_DB_PATH` - Custom database path (default: `./.claude/vector-memories.db`)
|
|
257
|
+
|
|
258
|
+
> Note: if you point multiple projects at the same DB path, `store_handoff` uses UUID.ZERO and will overwrite the previous handoff (by design).
|
|
250
259
|
- `VECTOR_MEMORY_MODEL` - Embedding model to use (default: `Xenova/all-MiniLM-L6-v2`)
|
|
251
260
|
|
|
252
261
|
Example:
|
|
@@ -255,7 +264,7 @@ export VECTOR_MEMORY_DB_PATH="/path/to/custom/memories.db"
|
|
|
255
264
|
export VECTOR_MEMORY_MODEL="Xenova/all-MiniLM-L6-v2"
|
|
256
265
|
```
|
|
257
266
|
|
|
258
|
-
Or in your
|
|
267
|
+
Or in your MCP client config:
|
|
259
268
|
```json
|
|
260
269
|
{
|
|
261
270
|
"mcpServers": {
|
|
@@ -276,7 +285,10 @@ Or in your Claude Code config:
|
|
|
276
285
|
### Running Tests
|
|
277
286
|
|
|
278
287
|
```bash
|
|
279
|
-
# Run all tests
|
|
288
|
+
# Run all tests (recommended - includes model preload)
|
|
289
|
+
bun run test
|
|
290
|
+
|
|
291
|
+
# Run tests directly (skips 19 embedding tests, faster)
|
|
280
292
|
bun test
|
|
281
293
|
|
|
282
294
|
# Run with coverage
|
|
@@ -286,6 +298,8 @@ bun test --coverage
|
|
|
286
298
|
bun run typecheck
|
|
287
299
|
```
|
|
288
300
|
|
|
301
|
+
> **Note:** `bun run test` uses a wrapper that preloads the embedding model, running all 98 tests. `bun test` directly is faster but skips embedding-specific tests.
|
|
302
|
+
|
|
289
303
|
### Development Mode
|
|
290
304
|
|
|
291
305
|
```bash
|
|
@@ -381,7 +395,7 @@ MIT License - see [LICENSE](LICENSE) for details.
|
|
|
381
395
|
## š Related Projects
|
|
382
396
|
|
|
383
397
|
- [Model Context Protocol](https://modelcontextprotocol.io) - Official MCP specification
|
|
384
|
-
-
|
|
398
|
+
- Any MCP-compatible client
|
|
385
399
|
- [LanceDB](https://lancedb.com/) - Fast, local vector search
|
|
386
400
|
- [Transformers.js](https://huggingface.co/docs/transformers.js) - Run transformers in JavaScript
|
|
387
401
|
|
|
@@ -402,7 +416,7 @@ MIT License - see [LICENSE](LICENSE) for details.
|
|
|
402
416
|
```
|
|
403
417
|
You: "Remember that we decided to use Drizzle ORM for type-safe database access"
|
|
404
418
|
Claude: I'll store that for you.
|
|
405
|
-
[Calls
|
|
419
|
+
[Calls store_memories tool with content and metadata]
|
|
406
420
|
ā Memory stored successfully
|
|
407
421
|
```
|
|
408
422
|
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
/**
|
|
3
|
+
* SessionStart hook for Claude Code
|
|
4
|
+
*
|
|
5
|
+
* Fetches config from the running vector-memory server's /health endpoint,
|
|
6
|
+
* then retrieves and outputs the latest handoff.
|
|
7
|
+
*
|
|
8
|
+
* Requires the server to be running with HTTP enabled.
|
|
9
|
+
*
|
|
10
|
+
* Usage in ~/.claude/settings.json:
|
|
11
|
+
* {
|
|
12
|
+
* "hooks": {
|
|
13
|
+
* "SessionStart": [{
|
|
14
|
+
* "hooks": [{
|
|
15
|
+
* "type": "command",
|
|
16
|
+
* "command": "bun /path/to/vector-memory-mcp/hooks/session-start.ts"
|
|
17
|
+
* }]
|
|
18
|
+
* }]
|
|
19
|
+
* }
|
|
20
|
+
* }
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
import { existsSync } from "fs";
|
|
24
|
+
import { connectToDatabase } from "../src/db/connection.js";
|
|
25
|
+
import { MemoryRepository } from "../src/db/memory.repository.js";
|
|
26
|
+
import { EmbeddingsService } from "../src/services/embeddings.service.js";
|
|
27
|
+
import { MemoryService } from "../src/services/memory.service.js";
|
|
28
|
+
|
|
29
|
+
const VECTOR_MEMORY_URL = process.env.VECTOR_MEMORY_URL ?? "http://127.0.0.1:3271";
|
|
30
|
+
|
|
31
|
+
interface HealthResponse {
|
|
32
|
+
status: string;
|
|
33
|
+
config: {
|
|
34
|
+
dbPath: string;
|
|
35
|
+
embeddingModel: string;
|
|
36
|
+
embeddingDimension: number;
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
async function main() {
|
|
41
|
+
// Get config from running server
|
|
42
|
+
let health: HealthResponse;
|
|
43
|
+
try {
|
|
44
|
+
const response = await fetch(`${VECTOR_MEMORY_URL}/health`);
|
|
45
|
+
if (!response.ok) {
|
|
46
|
+
throw new Error(`Server returned ${response.status}`);
|
|
47
|
+
}
|
|
48
|
+
health = await response.json();
|
|
49
|
+
} catch (error) {
|
|
50
|
+
if (error instanceof Error && error.message.includes("ECONNREFUSED")) {
|
|
51
|
+
console.log("Vector memory server not running. Starting fresh session.");
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
throw error;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const { dbPath, embeddingModel, embeddingDimension } = health.config;
|
|
58
|
+
|
|
59
|
+
// Check if DB exists
|
|
60
|
+
if (!existsSync(dbPath)) {
|
|
61
|
+
console.log("Vector memory database not found. Starting fresh session.");
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const db = await connectToDatabase(dbPath);
|
|
66
|
+
const repository = new MemoryRepository(db);
|
|
67
|
+
const embeddings = new EmbeddingsService(embeddingModel, embeddingDimension);
|
|
68
|
+
const service = new MemoryService(repository, embeddings);
|
|
69
|
+
|
|
70
|
+
const handoff = await service.getLatestHandoff();
|
|
71
|
+
|
|
72
|
+
if (!handoff) {
|
|
73
|
+
console.log("No handoff found. Starting fresh session.");
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Fetch referenced memories if any
|
|
78
|
+
const memoryIds = (handoff.metadata.memory_ids as string[] | undefined) ?? [];
|
|
79
|
+
let memoriesSection = "";
|
|
80
|
+
|
|
81
|
+
if (memoryIds.length > 0) {
|
|
82
|
+
const memories: string[] = [];
|
|
83
|
+
for (const id of memoryIds) {
|
|
84
|
+
const memory = await service.get(id);
|
|
85
|
+
if (memory) {
|
|
86
|
+
memories.push(`### Memory: ${id}\n${memory.content}`);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
if (memories.length > 0) {
|
|
90
|
+
memoriesSection = `\n\n## Referenced Memories\n\n${memories.join("\n\n")}`;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
console.log(handoff.content + memoriesSection);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
main().catch((err) => {
|
|
98
|
+
console.error("Error loading handoff:", err.message);
|
|
99
|
+
process.exit(1);
|
|
100
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aeriondyseti/vector-memory-mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"description": "A zero-configuration RAG memory server for MCP clients",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.ts",
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
"files": [
|
|
11
11
|
"src",
|
|
12
12
|
"scripts",
|
|
13
|
+
"hooks",
|
|
13
14
|
"README.md",
|
|
14
15
|
"LICENSE"
|
|
15
16
|
],
|
|
@@ -25,20 +26,32 @@
|
|
|
25
26
|
"scripts": {
|
|
26
27
|
"start": "bun run src/index.ts",
|
|
27
28
|
"dev": "bun --watch run src/index.ts",
|
|
29
|
+
"build": "bun run typecheck",
|
|
28
30
|
"typecheck": "bunx tsc --noEmit",
|
|
29
|
-
"test": "bun
|
|
31
|
+
"test": "bun run scripts/test-runner.ts",
|
|
32
|
+
"test:raw": "bun test --preload ./tests/preload.ts",
|
|
30
33
|
"test:quick": "bun test",
|
|
31
34
|
"test:coverage": "bun test --preload ./tests/preload.ts --coverage",
|
|
32
35
|
"test:preload": "bun run tests/preload.ts",
|
|
33
36
|
"warmup": "bun run scripts/warmup.ts",
|
|
34
|
-
"postinstall": "bun run scripts/warmup.ts"
|
|
37
|
+
"postinstall": "bun run scripts/warmup.ts",
|
|
38
|
+
"publish:check": "bun run scripts/publish.ts --dry-run",
|
|
39
|
+
"publish:npm": "bun run scripts/publish.ts"
|
|
35
40
|
},
|
|
36
|
-
"keywords": [
|
|
41
|
+
"keywords": [
|
|
42
|
+
"mcp",
|
|
43
|
+
"memory",
|
|
44
|
+
"rag",
|
|
45
|
+
"embeddings",
|
|
46
|
+
"lancedb"
|
|
47
|
+
],
|
|
37
48
|
"license": "MIT",
|
|
38
49
|
"dependencies": {
|
|
50
|
+
"@huggingface/transformers": "^3.8.0",
|
|
39
51
|
"@lancedb/lancedb": "^0.22.3",
|
|
40
52
|
"@modelcontextprotocol/sdk": "^1.0.0",
|
|
41
|
-
"
|
|
53
|
+
"arg": "^5.0.2",
|
|
54
|
+
"hono": "^4.11.3"
|
|
42
55
|
},
|
|
43
56
|
"devDependencies": {
|
|
44
57
|
"@types/bun": "latest",
|
|
@@ -48,5 +61,8 @@
|
|
|
48
61
|
"onnxruntime-node",
|
|
49
62
|
"protobufjs",
|
|
50
63
|
"sharp"
|
|
51
|
-
]
|
|
64
|
+
],
|
|
65
|
+
"overrides": {
|
|
66
|
+
"onnxruntime-node": "1.23.2"
|
|
67
|
+
}
|
|
52
68
|
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
/**
|
|
3
|
+
* Publish script for vector-memory-mcp
|
|
4
|
+
*
|
|
5
|
+
* Prerequisites:
|
|
6
|
+
* 1. Create a granular access token at https://www.npmjs.com/settings/tokens
|
|
7
|
+
* 2. Store it: npm config set //registry.npmjs.org/:_authToken=npm_YOUR_TOKEN
|
|
8
|
+
* Or set NPM_TOKEN environment variable
|
|
9
|
+
*
|
|
10
|
+
* Usage: bun run scripts/publish.ts [--dry-run]
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { $ } from "bun";
|
|
14
|
+
|
|
15
|
+
const dryRun = process.argv.includes("--dry-run");
|
|
16
|
+
|
|
17
|
+
async function main() {
|
|
18
|
+
// Check for authentication
|
|
19
|
+
console.log("š Checking NPM authentication...");
|
|
20
|
+
try {
|
|
21
|
+
const whoami = await $`npm whoami`.text();
|
|
22
|
+
console.log(`ā
Authenticated as: ${whoami.trim()}`);
|
|
23
|
+
} catch {
|
|
24
|
+
console.error("ā Not authenticated with NPM.");
|
|
25
|
+
console.error(" Option 1: npm login");
|
|
26
|
+
console.error(" Option 2: npm config set //registry.npmjs.org/:_authToken=npm_YOUR_TOKEN");
|
|
27
|
+
console.error(" Option 3: Set NPM_TOKEN environment variable");
|
|
28
|
+
process.exit(1);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Run tests
|
|
32
|
+
console.log("š§Ŗ Running tests...");
|
|
33
|
+
const testResult = await $`bun run test`.quiet();
|
|
34
|
+
if (testResult.exitCode !== 0) {
|
|
35
|
+
console.error("ā Tests failed. Aborting publish.");
|
|
36
|
+
process.exit(1);
|
|
37
|
+
}
|
|
38
|
+
console.log("ā
Tests passed");
|
|
39
|
+
|
|
40
|
+
// Build
|
|
41
|
+
console.log("šØ Building...");
|
|
42
|
+
await $`bun run build`;
|
|
43
|
+
console.log("ā
Build complete");
|
|
44
|
+
|
|
45
|
+
// Get version info
|
|
46
|
+
const pkg = await Bun.file("package.json").json();
|
|
47
|
+
console.log(`\nš¦ Publishing ${pkg.name}@${pkg.version}...`);
|
|
48
|
+
|
|
49
|
+
if (dryRun) {
|
|
50
|
+
console.log("š Dry run - would publish:");
|
|
51
|
+
await $`npm publish --dry-run`;
|
|
52
|
+
} else {
|
|
53
|
+
await $`npm publish --access public`;
|
|
54
|
+
console.log(`\nā
Published ${pkg.name}@${pkg.version}`);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
main().catch((err) => {
|
|
59
|
+
console.error("ā Publish failed:", err.message);
|
|
60
|
+
process.exit(1);
|
|
61
|
+
});
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
/**
|
|
3
|
+
* Test runner wrapper that handles Bun's post-test crash gracefully.
|
|
4
|
+
*
|
|
5
|
+
* Bun crashes during native module cleanup after tests complete successfully.
|
|
6
|
+
* This wrapper captures the output, verifies tests passed, and exits cleanly.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { spawn } from "bun";
|
|
10
|
+
|
|
11
|
+
const proc = spawn(["bun", "test", "--preload", "./tests/preload.ts"], {
|
|
12
|
+
stdout: "pipe",
|
|
13
|
+
stderr: "pipe",
|
|
14
|
+
env: { ...process.env, FORCE_COLOR: "1" },
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
let stdout = "";
|
|
18
|
+
let stderr = "";
|
|
19
|
+
|
|
20
|
+
const decoder = new TextDecoder();
|
|
21
|
+
|
|
22
|
+
// Stream stdout in real-time
|
|
23
|
+
const stdoutReader = proc.stdout.getReader();
|
|
24
|
+
(async () => {
|
|
25
|
+
while (true) {
|
|
26
|
+
const { done, value } = await stdoutReader.read();
|
|
27
|
+
if (done) break;
|
|
28
|
+
const text = decoder.decode(value);
|
|
29
|
+
stdout += text;
|
|
30
|
+
process.stdout.write(text);
|
|
31
|
+
}
|
|
32
|
+
})();
|
|
33
|
+
|
|
34
|
+
// Stream stderr in real-time
|
|
35
|
+
const stderrReader = proc.stderr.getReader();
|
|
36
|
+
(async () => {
|
|
37
|
+
while (true) {
|
|
38
|
+
const { done, value } = await stderrReader.read();
|
|
39
|
+
if (done) break;
|
|
40
|
+
const text = decoder.decode(value);
|
|
41
|
+
stderr += text;
|
|
42
|
+
process.stderr.write(text);
|
|
43
|
+
}
|
|
44
|
+
})();
|
|
45
|
+
|
|
46
|
+
await proc.exited;
|
|
47
|
+
|
|
48
|
+
// Check if tests actually passed by looking for the summary line
|
|
49
|
+
const output = stdout + stderr;
|
|
50
|
+
const passMatch = output.match(/(\d+) pass/);
|
|
51
|
+
const failMatch = output.match(/(\d+) fail/);
|
|
52
|
+
|
|
53
|
+
const passed = passMatch ? parseInt(passMatch[1], 10) : 0;
|
|
54
|
+
const failed = failMatch ? parseInt(failMatch[1], 10) : 0;
|
|
55
|
+
|
|
56
|
+
// Exit based on test results, not Bun's crash
|
|
57
|
+
if (failed > 0) {
|
|
58
|
+
console.error(`\nā ${failed} test(s) failed`);
|
|
59
|
+
process.exit(1);
|
|
60
|
+
} else if (passed > 0) {
|
|
61
|
+
console.log(`\nā
All ${passed} tests passed (ignoring Bun cleanup crash)`);
|
|
62
|
+
process.exit(0);
|
|
63
|
+
} else {
|
|
64
|
+
console.error("\nā ļø Could not determine test results");
|
|
65
|
+
process.exit(1);
|
|
66
|
+
}
|
package/scripts/warmup.ts
CHANGED
|
@@ -52,8 +52,7 @@ async function warmup(): Promise<void> {
|
|
|
52
52
|
console.log();
|
|
53
53
|
console.log(`ā
Warmup complete! (${duration}s)`);
|
|
54
54
|
console.log();
|
|
55
|
-
console.log("Ready to use! Configure
|
|
56
|
-
console.log("See: https://github.com/AerionDyseti/vector-memory-mcp#configure-claude-code");
|
|
55
|
+
console.log("Ready to use! Configure your MCP client and restart to get started.");
|
|
57
56
|
console.log();
|
|
58
57
|
} catch (error) {
|
|
59
58
|
console.error();
|
package/src/config/index.ts
CHANGED
|
@@ -1,29 +1,75 @@
|
|
|
1
|
+
import arg from "arg";
|
|
1
2
|
import { join } from "path";
|
|
2
|
-
|
|
3
|
+
|
|
4
|
+
export type TransportMode = "stdio" | "http" | "both";
|
|
3
5
|
|
|
4
6
|
export interface Config {
|
|
5
7
|
dbPath: string;
|
|
6
8
|
embeddingModel: string;
|
|
7
9
|
embeddingDimension: number;
|
|
10
|
+
httpPort: number;
|
|
11
|
+
httpHost: string;
|
|
12
|
+
enableHttp: boolean;
|
|
13
|
+
transportMode: TransportMode;
|
|
8
14
|
}
|
|
9
15
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
);
|
|
16
|
+
export interface ConfigOverrides {
|
|
17
|
+
dbPath?: string;
|
|
18
|
+
httpPort?: number;
|
|
19
|
+
enableHttp?: boolean;
|
|
20
|
+
transportMode?: TransportMode;
|
|
21
|
+
}
|
|
17
22
|
|
|
23
|
+
// Defaults - always use repo-local .vector-memory folder
|
|
24
|
+
const DEFAULT_DB_PATH = join(process.cwd(), ".vector-memory", "memories.db");
|
|
18
25
|
const DEFAULT_EMBEDDING_MODEL = "Xenova/all-MiniLM-L6-v2";
|
|
19
26
|
const DEFAULT_EMBEDDING_DIMENSION = 384;
|
|
27
|
+
const DEFAULT_HTTP_PORT = 3271;
|
|
28
|
+
const DEFAULT_HTTP_HOST = "127.0.0.1";
|
|
29
|
+
|
|
30
|
+
function resolvePath(path: string): string {
|
|
31
|
+
return path.startsWith("/") ? path : join(process.cwd(), path);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function loadConfig(overrides: ConfigOverrides = {}): Config {
|
|
35
|
+
const transportMode = overrides.transportMode ?? "stdio";
|
|
36
|
+
// HTTP enabled by default (needed for hooks), can disable with --no-http
|
|
37
|
+
const enableHttp = overrides.enableHttp ?? true;
|
|
20
38
|
|
|
21
|
-
export function loadConfig(): Config {
|
|
22
39
|
return {
|
|
23
|
-
dbPath:
|
|
24
|
-
embeddingModel:
|
|
40
|
+
dbPath: resolvePath(overrides.dbPath ?? DEFAULT_DB_PATH),
|
|
41
|
+
embeddingModel: DEFAULT_EMBEDDING_MODEL,
|
|
25
42
|
embeddingDimension: DEFAULT_EMBEDDING_DIMENSION,
|
|
43
|
+
httpPort: overrides.httpPort ?? DEFAULT_HTTP_PORT,
|
|
44
|
+
httpHost: DEFAULT_HTTP_HOST,
|
|
45
|
+
enableHttp,
|
|
46
|
+
transportMode,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Parse CLI arguments into config overrides.
|
|
52
|
+
*/
|
|
53
|
+
export function parseCliArgs(argv: string[]): ConfigOverrides {
|
|
54
|
+
const args = arg(
|
|
55
|
+
{
|
|
56
|
+
"--db-file": String,
|
|
57
|
+
"--port": Number,
|
|
58
|
+
"--no-http": Boolean,
|
|
59
|
+
|
|
60
|
+
// Aliases
|
|
61
|
+
"-d": "--db-file",
|
|
62
|
+
"-p": "--port",
|
|
63
|
+
},
|
|
64
|
+
{ argv, permissive: true }
|
|
65
|
+
);
|
|
66
|
+
|
|
67
|
+
return {
|
|
68
|
+
dbPath: args["--db-file"],
|
|
69
|
+
httpPort: args["--port"],
|
|
70
|
+
enableHttp: args["--no-http"] ? false : undefined,
|
|
26
71
|
};
|
|
27
72
|
}
|
|
28
73
|
|
|
74
|
+
// Default config for imports that don't use CLI args
|
|
29
75
|
export const config = loadConfig();
|
|
@@ -33,6 +33,27 @@ export class MemoryRepository {
|
|
|
33
33
|
]);
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
+
async upsert(memory: Memory): Promise<void> {
|
|
37
|
+
const table = await this.getTable();
|
|
38
|
+
const existing = await table.query().where(`id = '${memory.id}'`).limit(1).toArray();
|
|
39
|
+
|
|
40
|
+
if (existing.length === 0) {
|
|
41
|
+
return await this.insert(memory);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
await table.update({
|
|
45
|
+
where: `id = '${memory.id}'`,
|
|
46
|
+
values: {
|
|
47
|
+
vector: memory.embedding,
|
|
48
|
+
content: memory.content,
|
|
49
|
+
metadata: JSON.stringify(memory.metadata),
|
|
50
|
+
created_at: memory.createdAt.getTime(),
|
|
51
|
+
updated_at: memory.updatedAt.getTime(),
|
|
52
|
+
superseded_by: memory.supersededBy,
|
|
53
|
+
},
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
|
|
36
57
|
async findById(id: string): Promise<Memory | null> {
|
|
37
58
|
const table = await this.getTable();
|
|
38
59
|
const results = await table.query().where(`id = '${id}'`).limit(1).toArray();
|
package/src/db/schema.ts
CHANGED