@aeriondyseti/vector-memory-mcp 2.2.6 → 2.2.7-dev.1
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/package.json +5 -6
- package/server/core/embeddings.service.ts +95 -18
- package/server/core/migrations.ts +148 -0
- package/server/index.ts +4 -39
- package/server/transports/http/server.ts +1 -29
- package/server/transports/mcp/resources.ts +8 -149
- package/scripts/lancedb-extract.ts +0 -181
- package/scripts/migrate-from-lancedb.ts +0 -56
- package/scripts/smoke-test.ts +0 -699
- package/scripts/sync-version.ts +0 -35
- package/scripts/test-runner.ts +0 -76
- package/scripts/warmup.ts +0 -72
- package/server/migration.ts +0 -203
package/scripts/sync-version.ts
DELETED
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bun
|
|
2
|
-
/**
|
|
3
|
-
* Sync version into .claude-plugin/ manifest files.
|
|
4
|
-
*
|
|
5
|
-
* Usage:
|
|
6
|
-
* bun scripts/sync-version.ts # reads version from package.json
|
|
7
|
-
* bun scripts/sync-version.ts 2.2.3-dev.4 # uses explicit version
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
import { readFileSync, writeFileSync } from "fs";
|
|
11
|
-
import { join } from "path";
|
|
12
|
-
|
|
13
|
-
const ROOT = join(import.meta.dir, "..");
|
|
14
|
-
const PKG_PATH = join(ROOT, "package.json");
|
|
15
|
-
const PLUGIN_PATH = join(ROOT, ".claude-plugin", "plugin.json");
|
|
16
|
-
const MARKETPLACE_PATH = join(ROOT, ".claude-plugin", "marketplace.json");
|
|
17
|
-
|
|
18
|
-
const explicit = process.argv[2];
|
|
19
|
-
const pkg = JSON.parse(readFileSync(PKG_PATH, "utf-8"));
|
|
20
|
-
const version: string = explicit ?? pkg.version;
|
|
21
|
-
|
|
22
|
-
// Stamp plugin.json
|
|
23
|
-
const plugin = JSON.parse(readFileSync(PLUGIN_PATH, "utf-8"));
|
|
24
|
-
plugin.version = version;
|
|
25
|
-
writeFileSync(PLUGIN_PATH, JSON.stringify(plugin, null, 2) + "\n");
|
|
26
|
-
|
|
27
|
-
// Stamp marketplace.json
|
|
28
|
-
const marketplace = JSON.parse(readFileSync(MARKETPLACE_PATH, "utf-8"));
|
|
29
|
-
marketplace.metadata.version = version;
|
|
30
|
-
for (const p of marketplace.plugins) {
|
|
31
|
-
p.version = version;
|
|
32
|
-
}
|
|
33
|
-
writeFileSync(MARKETPLACE_PATH, JSON.stringify(marketplace, null, 2) + "\n");
|
|
34
|
-
|
|
35
|
-
console.error(`Synced version ${version} → plugin.json, marketplace.json`);
|
package/scripts/test-runner.ts
DELETED
|
@@ -1,76 +0,0 @@
|
|
|
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
|
-
// Exclude benchmark tests — they're probabilistic quality metrics, not pass/fail gates.
|
|
12
|
-
// Run benchmarks separately with: bun run benchmark
|
|
13
|
-
const args = ["bun", "test", "--preload", "./tests/preload.ts"];
|
|
14
|
-
|
|
15
|
-
// Collect all test files except benchmarks
|
|
16
|
-
const glob = new Bun.Glob("tests/**/*.test.ts");
|
|
17
|
-
for (const path of glob.scanSync(".")) {
|
|
18
|
-
if (!path.includes("benchmark")) args.push(path);
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
const proc = spawn(args, {
|
|
22
|
-
stdout: "pipe",
|
|
23
|
-
stderr: "pipe",
|
|
24
|
-
env: { ...process.env, FORCE_COLOR: "1" },
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
let stdout = "";
|
|
28
|
-
let stderr = "";
|
|
29
|
-
|
|
30
|
-
const decoder = new TextDecoder();
|
|
31
|
-
|
|
32
|
-
// Stream stdout in real-time
|
|
33
|
-
const stdoutReader = proc.stdout.getReader();
|
|
34
|
-
(async () => {
|
|
35
|
-
while (true) {
|
|
36
|
-
const { done, value } = await stdoutReader.read();
|
|
37
|
-
if (done) break;
|
|
38
|
-
const text = decoder.decode(value);
|
|
39
|
-
stdout += text;
|
|
40
|
-
process.stdout.write(text);
|
|
41
|
-
}
|
|
42
|
-
})();
|
|
43
|
-
|
|
44
|
-
// Stream stderr in real-time
|
|
45
|
-
const stderrReader = proc.stderr.getReader();
|
|
46
|
-
(async () => {
|
|
47
|
-
while (true) {
|
|
48
|
-
const { done, value } = await stderrReader.read();
|
|
49
|
-
if (done) break;
|
|
50
|
-
const text = decoder.decode(value);
|
|
51
|
-
stderr += text;
|
|
52
|
-
process.stderr.write(text);
|
|
53
|
-
}
|
|
54
|
-
})();
|
|
55
|
-
|
|
56
|
-
await proc.exited;
|
|
57
|
-
|
|
58
|
-
// Check if tests actually passed by looking for the summary line
|
|
59
|
-
const output = stdout + stderr;
|
|
60
|
-
const passMatch = output.match(/(\d+) pass/);
|
|
61
|
-
const failMatch = output.match(/(\d+) fail/);
|
|
62
|
-
|
|
63
|
-
const passed = passMatch ? parseInt(passMatch[1], 10) : 0;
|
|
64
|
-
const failed = failMatch ? parseInt(failMatch[1], 10) : 0;
|
|
65
|
-
|
|
66
|
-
// Exit based on test results, not Bun's crash
|
|
67
|
-
if (failed > 0) {
|
|
68
|
-
console.error(`\n❌ ${failed} test(s) failed`);
|
|
69
|
-
process.exit(1);
|
|
70
|
-
} else if (passed > 0) {
|
|
71
|
-
console.log(`\n✅ All ${passed} tests passed (ignoring Bun cleanup crash)`);
|
|
72
|
-
process.exit(0);
|
|
73
|
-
} else {
|
|
74
|
-
console.error("\n⚠️ Could not determine test results");
|
|
75
|
-
process.exit(1);
|
|
76
|
-
}
|
package/scripts/warmup.ts
DELETED
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bun
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Warmup script to pre-download ML models and verify dependencies
|
|
5
|
-
* This runs during installation to ensure everything is ready to use
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import { config } from "../server/config/index.js";
|
|
9
|
-
import { EmbeddingsService } from "../server/core/embeddings.service.js";
|
|
10
|
-
|
|
11
|
-
async function warmup(): Promise<void> {
|
|
12
|
-
console.log("🔥 Warming up vector-memory-mcp...");
|
|
13
|
-
console.log();
|
|
14
|
-
|
|
15
|
-
try {
|
|
16
|
-
// Check native dependencies
|
|
17
|
-
console.log("✓ Checking native dependencies...");
|
|
18
|
-
try {
|
|
19
|
-
await import("onnxruntime-node");
|
|
20
|
-
console.log(" ✓ onnxruntime-node loaded");
|
|
21
|
-
} catch (e) {
|
|
22
|
-
console.error(" ✗ onnxruntime-node failed:", (e as Error).message);
|
|
23
|
-
process.exit(1);
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
try {
|
|
27
|
-
await import("sharp");
|
|
28
|
-
console.log(" ✓ sharp loaded");
|
|
29
|
-
} catch (e) {
|
|
30
|
-
console.error(" ✗ sharp failed:", (e as Error).message);
|
|
31
|
-
process.exit(1);
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
console.log();
|
|
35
|
-
|
|
36
|
-
// Initialize embeddings service to download model
|
|
37
|
-
console.log("📥 Downloading ML model (this may take a minute)...");
|
|
38
|
-
console.log(` Model: ${config.embeddingModel}`);
|
|
39
|
-
console.log(` Cache: ~/.cache/huggingface/`);
|
|
40
|
-
console.log();
|
|
41
|
-
|
|
42
|
-
const embeddings = new EmbeddingsService(
|
|
43
|
-
config.embeddingModel,
|
|
44
|
-
config.embeddingDimension
|
|
45
|
-
);
|
|
46
|
-
|
|
47
|
-
// Trigger model download by generating a test embedding
|
|
48
|
-
const startTime = Date.now();
|
|
49
|
-
await embeddings.embed("warmup test");
|
|
50
|
-
const duration = ((Date.now() - startTime) / 1000).toFixed(2);
|
|
51
|
-
|
|
52
|
-
console.log();
|
|
53
|
-
console.log(`✅ Warmup complete! (${duration}s)`);
|
|
54
|
-
console.log();
|
|
55
|
-
console.log("Ready to use! Configure your MCP client and restart to get started.");
|
|
56
|
-
console.log();
|
|
57
|
-
} catch (error) {
|
|
58
|
-
console.error();
|
|
59
|
-
console.error("❌ Warmup failed:", error);
|
|
60
|
-
console.error();
|
|
61
|
-
console.error("This is not a critical error - the server will download models on first run.");
|
|
62
|
-
console.error("You can try running 'vector-memory-mcp warmup' manually later.");
|
|
63
|
-
process.exit(0); // Exit successfully to not block installation
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
// Only run if this is the main module
|
|
68
|
-
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
69
|
-
warmup();
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
export { warmup };
|
package/server/migration.ts
DELETED
|
@@ -1,203 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* LanceDB -> SQLite migration logic.
|
|
3
|
-
*
|
|
4
|
-
* Reads LanceDB data in a child process (scripts/lancedb-extract.ts) to avoid
|
|
5
|
-
* a native symbol collision between @lancedb/lancedb and bun:sqlite.
|
|
6
|
-
* The extracted JSON is then written to SQLite in-process.
|
|
7
|
-
*
|
|
8
|
-
* @deprecated Will be removed in the next major version once LanceDB
|
|
9
|
-
* support is dropped.
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
import { existsSync, statSync } from "fs";
|
|
13
|
-
import { resolve, dirname } from "path";
|
|
14
|
-
import { fileURLToPath } from "url";
|
|
15
|
-
import { connectToDatabase } from "./core/connection.js";
|
|
16
|
-
import { serializeVector } from "./core/sqlite-utils.js";
|
|
17
|
-
|
|
18
|
-
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
19
|
-
|
|
20
|
-
// ── Detection ───────────────────────────────────────────────────────
|
|
21
|
-
|
|
22
|
-
export function isLanceDbDirectory(dbPath: string): boolean {
|
|
23
|
-
return existsSync(dbPath) && statSync(dbPath).isDirectory();
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
// ── Types ───────────────────────────────────────────────────────────
|
|
27
|
-
|
|
28
|
-
export interface MigrateOptions {
|
|
29
|
-
source: string;
|
|
30
|
-
target: string;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
export interface MigrateResult {
|
|
34
|
-
memoriesMigrated: number;
|
|
35
|
-
conversationChunksMigrated: number;
|
|
36
|
-
outputSizeMB: string;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
interface ExtractedData {
|
|
40
|
-
memories: Array<{
|
|
41
|
-
id: string;
|
|
42
|
-
content: string;
|
|
43
|
-
metadata: string;
|
|
44
|
-
vector: number[];
|
|
45
|
-
created_at: number;
|
|
46
|
-
updated_at: number;
|
|
47
|
-
last_accessed: number | null;
|
|
48
|
-
superseded_by: string | null;
|
|
49
|
-
usefulness: number;
|
|
50
|
-
access_count: number;
|
|
51
|
-
}>;
|
|
52
|
-
conversations: Array<{
|
|
53
|
-
id: string;
|
|
54
|
-
content: string;
|
|
55
|
-
metadata: string;
|
|
56
|
-
vector: number[];
|
|
57
|
-
created_at: number;
|
|
58
|
-
session_id: string;
|
|
59
|
-
role: string;
|
|
60
|
-
message_index_start: number;
|
|
61
|
-
message_index_end: number;
|
|
62
|
-
project: string;
|
|
63
|
-
}>;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
// ── Migration ───────────────────────────────────────────────────────
|
|
67
|
-
|
|
68
|
-
export async function migrate(opts: MigrateOptions): Promise<MigrateResult> {
|
|
69
|
-
const { source, target } = opts;
|
|
70
|
-
|
|
71
|
-
if (!existsSync(source)) {
|
|
72
|
-
throw new Error(`Source not found: ${source}`);
|
|
73
|
-
}
|
|
74
|
-
if (!statSync(source).isDirectory()) {
|
|
75
|
-
throw new Error(`Source is not a directory (expected LanceDB): ${source}`);
|
|
76
|
-
}
|
|
77
|
-
if (existsSync(target)) {
|
|
78
|
-
throw new Error(
|
|
79
|
-
`Target already exists: ${target}\n Delete it first or choose a different target path.`
|
|
80
|
-
);
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
console.error(`📂 Source (LanceDB): ${source}`);
|
|
84
|
-
console.error(`📄 Target (SQLite): ${target}`);
|
|
85
|
-
console.error();
|
|
86
|
-
|
|
87
|
-
// Phase 1: Extract data from LanceDB in a subprocess.
|
|
88
|
-
// This avoids a native symbol collision between @lancedb/lancedb and bun:sqlite.
|
|
89
|
-
const extractScript = resolve(__dirname, "..", "scripts", "lancedb-extract.ts");
|
|
90
|
-
const proc = Bun.spawn(["bun", extractScript, source], {
|
|
91
|
-
stdout: "pipe",
|
|
92
|
-
stderr: "inherit",
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
const output = await new Response(proc.stdout).text();
|
|
96
|
-
const exitCode = await proc.exited;
|
|
97
|
-
|
|
98
|
-
if (exitCode !== 0) {
|
|
99
|
-
throw new Error(`LanceDB extraction failed (exit code ${exitCode})`);
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
const data: ExtractedData = JSON.parse(output);
|
|
103
|
-
|
|
104
|
-
// Phase 2: Write to SQLite (no LanceDB in this process).
|
|
105
|
-
const sqliteDb = connectToDatabase(target);
|
|
106
|
-
|
|
107
|
-
let memoriesMigrated = 0;
|
|
108
|
-
let conversationChunksMigrated = 0;
|
|
109
|
-
|
|
110
|
-
if (data.memories.length > 0) {
|
|
111
|
-
console.error(`\n🧠 Writing ${data.memories.length} memories to SQLite...`);
|
|
112
|
-
|
|
113
|
-
const insertMain = sqliteDb.prepare(
|
|
114
|
-
`INSERT OR REPLACE INTO memories
|
|
115
|
-
(id, content, metadata, created_at, updated_at, superseded_by, usefulness, access_count, last_accessed)
|
|
116
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`
|
|
117
|
-
);
|
|
118
|
-
const deleteVec = sqliteDb.prepare(`DELETE FROM memories_vec WHERE id = ?`);
|
|
119
|
-
const insertVec = sqliteDb.prepare(
|
|
120
|
-
`INSERT INTO memories_vec (id, vector) VALUES (?, ?)`
|
|
121
|
-
);
|
|
122
|
-
const insertFts = sqliteDb.prepare(
|
|
123
|
-
`INSERT OR REPLACE INTO memories_fts (id, content) VALUES (?, ?)`
|
|
124
|
-
);
|
|
125
|
-
|
|
126
|
-
const tx = sqliteDb.transaction(() => {
|
|
127
|
-
for (const row of data.memories) {
|
|
128
|
-
insertMain.run(
|
|
129
|
-
row.id, row.content, row.metadata,
|
|
130
|
-
row.created_at, row.updated_at,
|
|
131
|
-
row.superseded_by, row.usefulness,
|
|
132
|
-
row.access_count, row.last_accessed,
|
|
133
|
-
);
|
|
134
|
-
if (row.vector.length > 0) {
|
|
135
|
-
deleteVec.run(row.id);
|
|
136
|
-
insertVec.run(row.id, serializeVector(row.vector));
|
|
137
|
-
}
|
|
138
|
-
insertFts.run(row.id, row.content);
|
|
139
|
-
}
|
|
140
|
-
});
|
|
141
|
-
tx();
|
|
142
|
-
memoriesMigrated = data.memories.length;
|
|
143
|
-
console.error(` ✅ ${memoriesMigrated} memories migrated`);
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
if (data.conversations.length > 0) {
|
|
147
|
-
console.error(`\n💬 Writing ${data.conversations.length} conversation chunks to SQLite...`);
|
|
148
|
-
|
|
149
|
-
const insertMain = sqliteDb.prepare(
|
|
150
|
-
`INSERT OR REPLACE INTO conversation_history
|
|
151
|
-
(id, content, metadata, created_at, session_id, role, message_index_start, message_index_end, project)
|
|
152
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`
|
|
153
|
-
);
|
|
154
|
-
const deleteVec = sqliteDb.prepare(`DELETE FROM conversation_history_vec WHERE id = ?`);
|
|
155
|
-
const insertVec = sqliteDb.prepare(
|
|
156
|
-
`INSERT INTO conversation_history_vec (id, vector) VALUES (?, ?)`
|
|
157
|
-
);
|
|
158
|
-
const insertFts = sqliteDb.prepare(
|
|
159
|
-
`INSERT OR REPLACE INTO conversation_history_fts (id, content) VALUES (?, ?)`
|
|
160
|
-
);
|
|
161
|
-
|
|
162
|
-
const tx = sqliteDb.transaction(() => {
|
|
163
|
-
for (const row of data.conversations) {
|
|
164
|
-
insertMain.run(
|
|
165
|
-
row.id, row.content, row.metadata,
|
|
166
|
-
row.created_at, row.session_id, row.role,
|
|
167
|
-
row.message_index_start, row.message_index_end, row.project,
|
|
168
|
-
);
|
|
169
|
-
if (row.vector.length > 0) {
|
|
170
|
-
deleteVec.run(row.id);
|
|
171
|
-
insertVec.run(row.id, serializeVector(row.vector));
|
|
172
|
-
}
|
|
173
|
-
insertFts.run(row.id, row.content);
|
|
174
|
-
}
|
|
175
|
-
});
|
|
176
|
-
tx();
|
|
177
|
-
conversationChunksMigrated = data.conversations.length;
|
|
178
|
-
console.error(` ✅ ${conversationChunksMigrated} conversation chunks migrated`);
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
sqliteDb.close();
|
|
182
|
-
|
|
183
|
-
const { size } = statSync(target);
|
|
184
|
-
const outputSizeMB = (size / 1024 / 1024).toFixed(2);
|
|
185
|
-
|
|
186
|
-
return { memoriesMigrated, conversationChunksMigrated, outputSizeMB };
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
export function formatMigrationSummary(
|
|
190
|
-
source: string,
|
|
191
|
-
target: string,
|
|
192
|
-
result: MigrateResult,
|
|
193
|
-
): string {
|
|
194
|
-
return `
|
|
195
|
-
✅ Migration complete! (${result.outputSizeMB} MB)
|
|
196
|
-
${result.memoriesMigrated} memories, ${result.conversationChunksMigrated} conversation chunks
|
|
197
|
-
|
|
198
|
-
Next steps:
|
|
199
|
-
1. Backup: mv "${source}" "${source}.lance-backup"
|
|
200
|
-
2. Activate: mv "${target}" "${source}"
|
|
201
|
-
3. Restart your MCP server
|
|
202
|
-
`;
|
|
203
|
-
}
|