@aeriondyseti/vector-memory-mcp 2.3.0-rc.1 → 2.3.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aeriondyseti/vector-memory-mcp",
3
- "version": "2.3.0-rc.1",
3
+ "version": "2.3.0",
4
4
  "description": "A zero-configuration RAG memory server for MCP clients",
5
5
  "type": "module",
6
6
  "main": "server/index.ts",
@@ -1,4 +1,6 @@
1
1
  import type { Database } from "bun:sqlite";
2
+ import type { EmbeddingsService } from "./embeddings.service.js";
3
+ import { serializeVector } from "./sqlite-utils.js";
2
4
 
3
5
  /**
4
6
  * Pre-migration step: remove vec0 virtual table entries from sqlite_master
@@ -113,3 +115,91 @@ export function runMigrations(db: Database): void {
113
115
  db.exec(`CREATE INDEX IF NOT EXISTS idx_conversation_role ON conversation_history(role)`);
114
116
  db.exec(`CREATE INDEX IF NOT EXISTS idx_conversation_created_at ON conversation_history(created_at)`);
115
117
  }
118
+
119
+ /**
120
+ * Backfill missing vectors in memories_vec and conversation_history_vec.
121
+ *
122
+ * After the vec0-to-BLOB migration, existing rows may lack vector embeddings.
123
+ * This re-embeds their content and inserts into the _vec tables.
124
+ * Idempotent: skips rows that already have vectors. Fast no-op when fully backfilled.
125
+ */
126
+ export async function backfillVectors(
127
+ db: Database,
128
+ embeddings: EmbeddingsService,
129
+ ): Promise<void> {
130
+ // ── Memories ──────────────────────────────────────────────────────
131
+ // Catch both missing rows (v.id IS NULL) and corrupt 0-byte BLOBs
132
+ const missingMemories = db
133
+ .prepare(
134
+ `SELECT m.id, m.content, json_extract(m.metadata, '$.type') AS type
135
+ FROM memories m
136
+ LEFT JOIN memories_vec v ON m.id = v.id
137
+ WHERE v.id IS NULL OR length(v.vector) = 0`,
138
+ )
139
+ .all() as Array<{ id: string; content: string; type: string | null }>;
140
+
141
+ if (missingMemories.length > 0) {
142
+ console.error(
143
+ `[vector-memory-mcp] Backfilling vectors for ${missingMemories.length} memories...`,
144
+ );
145
+
146
+ const insertVec = db.prepare(
147
+ "INSERT OR REPLACE INTO memories_vec (id, vector) VALUES (?, ?)",
148
+ );
149
+
150
+ const zeroVector = serializeVector(
151
+ new Array(embeddings.dimension).fill(0),
152
+ );
153
+
154
+ for (const row of missingMemories) {
155
+ // Waypoints use a zero vector (not semantically searched)
156
+ const blob =
157
+ row.type === "waypoint"
158
+ ? zeroVector
159
+ : serializeVector(await embeddings.embed(row.content));
160
+
161
+ insertVec.run(row.id, blob);
162
+ }
163
+
164
+ console.error(
165
+ `[vector-memory-mcp] Backfilled ${missingMemories.length} memory vectors`,
166
+ );
167
+ }
168
+
169
+ // ── Conversation history ──────────────────────────────────────────
170
+ const missingConvos = db
171
+ .prepare(
172
+ `SELECT c.id, c.content
173
+ FROM conversation_history c
174
+ LEFT JOIN conversation_history_vec v ON c.id = v.id
175
+ WHERE v.id IS NULL OR length(v.vector) = 0`,
176
+ )
177
+ .all() as Array<{ id: string; content: string }>;
178
+
179
+ if (missingConvos.length > 0) {
180
+ console.error(
181
+ `[vector-memory-mcp] Backfilling vectors for ${missingConvos.length} conversation chunks...`,
182
+ );
183
+
184
+ const insertConvoVec = db.prepare(
185
+ "INSERT OR REPLACE INTO conversation_history_vec (id, vector) VALUES (?, ?)",
186
+ );
187
+
188
+ for (let i = 0; i < missingConvos.length; i++) {
189
+ const row = missingConvos[i];
190
+ const vec = serializeVector(await embeddings.embed(row.content));
191
+ insertConvoVec.run(row.id, vec);
192
+
193
+ // Log progress every 100 chunks
194
+ if ((i + 1) % 100 === 0) {
195
+ console.error(
196
+ `[vector-memory-mcp] ...${i + 1}/${missingConvos.length} conversation chunks`,
197
+ );
198
+ }
199
+ }
200
+
201
+ console.error(
202
+ `[vector-memory-mcp] Backfilled ${missingConvos.length} conversation vectors`,
203
+ );
204
+ }
205
+ }
package/server/index.ts CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  import { loadConfig, parseCliArgs } from "./config/index.js";
4
4
  import { connectToDatabase } from "./core/connection.js";
5
+ import { backfillVectors } from "./core/migrations.js";
5
6
  import { MemoryRepository } from "./core/memory.repository.js";
6
7
  import { ConversationRepository } from "./core/conversation.repository.js";
7
8
  import { EmbeddingsService } from "./core/embeddings.service.js";
@@ -9,26 +10,6 @@ import { MemoryService } from "./core/memory.service.js";
9
10
  import { ConversationHistoryService } from "./core/conversation.service.js";
10
11
  import { startServer } from "./transports/mcp/server.js";
11
12
  import { startHttpServer } from "./transports/http/server.js";
12
- import { isLanceDbDirectory, migrate, formatMigrationSummary } from "./migration.js";
13
-
14
- async function runMigrate(args: string[]): Promise<void> {
15
- const overrides = parseCliArgs(args.slice(1)); // skip "migrate"
16
- const config = loadConfig(overrides);
17
-
18
- const source = config.dbPath;
19
- const target = source.endsWith(".sqlite") ? source.replace(/\.sqlite$/, "-migrated.sqlite") : source + ".sqlite";
20
-
21
- if (!isLanceDbDirectory(source)) {
22
- console.error(
23
- `[vector-memory-mcp] No LanceDB data found at ${source}\n` +
24
- ` Nothing to migrate. The server will create a fresh SQLite database on startup.`
25
- );
26
- return;
27
- }
28
-
29
- const result = await migrate({ source, target });
30
- console.error(formatMigrationSummary(source, target, result));
31
- }
32
13
 
33
14
  async function main(): Promise<void> {
34
15
  const args = process.argv.slice(2);
@@ -40,27 +21,10 @@ async function main(): Promise<void> {
40
21
  return;
41
22
  }
42
23
 
43
- // Check for migrate command
44
- if (args[0] === "migrate") {
45
- await runMigrate(args);
46
- return;
47
- }
48
-
49
24
  // Parse CLI args and load config
50
25
  const overrides = parseCliArgs(args);
51
26
  const config = loadConfig(overrides);
52
27
 
53
- // Detect legacy LanceDB data and warn
54
- if (isLanceDbDirectory(config.dbPath)) {
55
- console.error(
56
- `[vector-memory-mcp] ⚠️ Legacy LanceDB data detected at ${config.dbPath}\n` +
57
- ` Your data must be migrated to the new SQLite format.\n` +
58
- ` Run: vector-memory-mcp migrate\n` +
59
- ` Or: bun run server/index.ts migrate\n`
60
- );
61
- process.exit(1);
62
- }
63
-
64
28
  // Initialize database
65
29
  const db = connectToDatabase(config.dbPath);
66
30
 
@@ -69,6 +33,9 @@ async function main(): Promise<void> {
69
33
  const embeddings = new EmbeddingsService(config.embeddingModel, config.embeddingDimension);
70
34
  const memoryService = new MemoryService(repository, embeddings);
71
35
 
36
+ // Backfill any missing vectors (e.g. after vec0-to-BLOB migration)
37
+ await backfillVectors(db, embeddings);
38
+
72
39
  if (config.pluginMode) {
73
40
  console.error("[vector-memory-mcp] Running in plugin mode");
74
41
  }
@@ -8,7 +8,7 @@ import type { Config } from "../../config/index.js";
8
8
  import { isDeleted } from "../../core/memory.js";
9
9
  import { createMcpRoutes } from "./mcp-transport.js";
10
10
  import type { Memory, SearchIntent } from "../../core/memory.js";
11
- import { MigrationService } from "../../core/migration.service.js";
11
+
12
12
 
13
13
  /**
14
14
  * Check if a port is available by attempting to bind to it
@@ -245,34 +245,6 @@ export function createHttpApp(memoryService: MemoryService, config: Config): Hon
245
245
  }
246
246
  });
247
247
 
248
- // Migrate from external memory database
249
- app.post("/migrate", async (c) => {
250
- try {
251
- const body = await c.req.json().catch(() => null);
252
- if (!body || typeof body !== "object") {
253
- return c.json({ error: "Invalid or missing JSON body" }, 400);
254
- }
255
- const source = body.source;
256
-
257
- if (!source || typeof source !== "string") {
258
- return c.json({ error: "Missing or invalid 'source' field" }, 400);
259
- }
260
-
261
- const repository = memoryService.getRepository();
262
- const migrationService = new MigrationService(
263
- repository,
264
- memoryService.getEmbeddings(),
265
- repository.getDb(),
266
- );
267
-
268
- const result = await migrationService.migrate(source);
269
- return c.json(result);
270
- } catch (error) {
271
- const message = error instanceof Error ? error.message : "Unknown error";
272
- return c.json({ error: message }, 500);
273
- }
274
- });
275
-
276
248
  // Get single memory
277
249
  app.get("/memories/:id", async (c) => {
278
250
  try {
@@ -1,152 +1,11 @@
1
- const MIGRATE_GUIDE = `# Migrating External Memory Databases
2
-
3
- The vector-memory-mcp server exposes a \`POST /migrate\` HTTP endpoint that imports
4
- memories from other database formats into the running instance. All imported
5
- content is re-embedded with the server's current embedding model to guarantee
6
- consistency.
7
-
8
- ## Endpoint
9
-
10
- \`\`\`
11
- POST http://<host>:<port>/migrate
12
- Content-Type: application/json
13
-
14
- { "source": "/absolute/path/to/source/database" }
15
- \`\`\`
16
-
17
- ## Discovering the Server Port
18
-
19
- The HTTP server writes a lockfile at \`.vector-memory/server.lock\` in the
20
- project's working directory. Read it to discover the current port:
21
-
22
- \`\`\`json
23
- { "port": 3271, "pid": 12345 }
24
- \`\`\`
25
-
26
- ## Supported Source Formats
27
-
28
- The endpoint auto-detects the source format from the path provided.
29
-
30
- ### 1. LanceDB Directory
31
- Provide the path to a LanceDB data directory (contains \`.lance\` files or
32
- \`_versions\`/\`_indices\` subdirectories). Both memories and conversation
33
- history are imported.
34
-
35
- \`\`\`json
36
- { "source": "/path/to/project/.vector-memory" }
37
- \`\`\`
38
-
39
- ### 2. Own SQLite (Current or Older Schema)
40
- Provide the path to a \`.db\` file that was created by any version of
41
- vector-memory-mcp. The migrator handles missing columns (e.g. \`usefulness\`,
42
- \`access_count\`) by using sensible defaults. Both memories and conversation
43
- history are imported.
44
-
45
- \`\`\`json
46
- { "source": "/path/to/old-project/.vector-memory/memories.db" }
47
- \`\`\`
48
-
49
- ### 3. CCCMemory SQLite
50
- Provide the path to a CCCMemory database. The migrator extracts from the
51
- \`decisions\`, \`mistakes\`, \`methodologies\`, \`research_findings\`,
52
- \`solution_patterns\`, and \`working_memory\` tables. Each record is tagged
53
- with \`source_type: "cccmemory"\` and the appropriate \`memory_type\` in
54
- metadata.
55
-
56
- \`\`\`json
57
- { "source": "/path/to/cccmemory.db" }
58
- \`\`\`
59
-
60
- ### 4. MCP Memory Service SQLite
61
- Provide the path to an mcp-memory-service database. Memories with
62
- \`deleted_at IS NULL\` are imported. Tags and memory type are preserved in
63
- metadata.
64
-
65
- \`\`\`json
66
- { "source": "/path/to/mcp-memory-service.db" }
67
- \`\`\`
68
-
69
- ### 5. MIF JSON (Shodh Memory Interchange Format)
70
- Provide the path to a \`.json\` file exported from Shodh Memory. The file must
71
- contain a top-level \`memories\` array. Memory type, tags, entities, and source
72
- metadata are preserved.
73
-
74
- \`\`\`json
75
- { "source": "/path/to/export.mif.json" }
76
- \`\`\`
77
-
78
- ## Response
79
-
80
- The endpoint returns a JSON summary upon completion:
81
-
82
- \`\`\`json
83
- {
84
- "source": "/path/to/source",
85
- "format": "own-sqlite",
86
- "memoriesImported": 142,
87
- "memoriesSkipped": 3,
88
- "conversationsImported": 0,
89
- "conversationsSkipped": 0,
90
- "errors": [],
91
- "durationMs": 8320
92
- }
93
- \`\`\`
94
-
95
- - **memoriesImported**: Number of new memories written to the database.
96
- - **memoriesSkipped**: Records skipped because a memory with the same ID
97
- already exists (safe for idempotent re-runs).
98
- - **conversationsImported / conversationsSkipped**: Same, for conversation
99
- history chunks (LanceDB and own-sqlite formats only).
100
- - **errors**: Per-record errors that did not abort the migration.
101
- - **durationMs**: Wall-clock time for the entire operation.
102
-
103
- ## Important Notes
104
-
105
- - **Re-embedding**: All content is re-embedded regardless of the source format.
106
- This ensures vector consistency with the server's current model but means the
107
- operation can take time for large databases (~50ms per record).
108
- - **Idempotent**: Running the same migration twice is safe. Duplicate IDs are
109
- skipped.
110
- - **Non-destructive**: The source database is opened read-only and is never
111
- modified.
112
- - **Batched writes**: Records are inserted in batches of 100 within
113
- transactions. If the process is interrupted, already-committed batches are
114
- durable.
115
- - **Error isolation**: A single bad record does not abort the migration. Check
116
- the \`errors\` array in the response for any per-record failures.
117
-
118
- ## Workflow Example
119
-
120
- 1. Locate the source database file or directory.
121
- 2. Read \`.vector-memory/server.lock\` to get the port.
122
- 3. Send the migrate request:
123
- \`\`\`bash
124
- curl -X POST http://127.0.0.1:3271/migrate \\
125
- -H "Content-Type: application/json" \\
126
- -d '{"source": "/path/to/old/memories.db"}'
127
- \`\`\`
128
- 4. Inspect the response summary.
129
- 5. Verify imported memories with a search:
130
- \`\`\`bash
131
- curl -X POST http://127.0.0.1:3271/search \\
132
- -H "Content-Type: application/json" \\
133
- -d '{"query": "test query", "limit": 5}'
134
- \`\`\`
135
- `;
136
-
137
- export const resources = [
138
- {
139
- uri: "vector-memory://guides/migrate",
140
- name: "Migration Guide",
141
- description:
142
- "How to use the POST /migrate HTTP endpoint to import memories from external database formats (LanceDB, older SQLite, CCCMemory, MCP Memory Service, MIF JSON) into the running vector-memory instance.",
143
- mimeType: "text/markdown",
144
- },
145
- ];
146
-
147
- const RESOURCE_CONTENT: Record<string, string> = {
148
- "vector-memory://guides/migrate": MIGRATE_GUIDE,
149
- };
1
+ export const resources: Array<{
2
+ uri: string;
3
+ name: string;
4
+ description: string;
5
+ mimeType: string;
6
+ }> = [];
7
+
8
+ const RESOURCE_CONTENT: Record<string, string> = {};
150
9
 
151
10
  export function readResource(uri: string): {
152
11
  contents: Array<{ uri: string; mimeType: string; text: string }>;
@@ -1,56 +0,0 @@
1
- #!/usr/bin/env bun
2
- /**
3
- * Standalone migration script: LanceDB → SQLite (sqlite-vec)
4
- *
5
- * This is a thin wrapper around server/migration.ts for direct invocation.
6
- * The preferred way to migrate is `vector-memory-mcp migrate`.
7
- *
8
- * Usage:
9
- * bun scripts/migrate-from-lancedb.ts [--source <lancedb-dir>] [--target <sqlite-file>]
10
- *
11
- * Defaults:
12
- * --source .vector-memory/memories.db (the old LanceDB directory)
13
- * --target .vector-memory/memories.db.sqlite (new SQLite file)
14
- *
15
- * @deprecated Use `vector-memory-mcp migrate` instead. This script will be
16
- * removed in the next major version.
17
- */
18
-
19
- import { migrate, formatMigrationSummary } from "../server/migration.js";
20
-
21
- function parseArgs(): { source: string; target: string } {
22
- const args = process.argv.slice(2);
23
- let source = ".vector-memory/memories.db";
24
- let target = ".vector-memory/memories.db.sqlite";
25
-
26
- for (let i = 0; i < args.length; i++) {
27
- if (args[i] === "--source" && args[i + 1]) source = args[++i];
28
- else if (args[i] === "--target" && args[i + 1]) target = args[++i];
29
- else if (args[i] === "--help" || args[i] === "-h") {
30
- console.log(`
31
- Usage: bun scripts/migrate-from-lancedb.ts [options]
32
-
33
- Prefer: vector-memory-mcp migrate
34
-
35
- Options:
36
- --source <path> LanceDB directory (default: .vector-memory/memories.db)
37
- --target <path> SQLite output file (default: .vector-memory/memories.db.sqlite)
38
- --help Show this help
39
- `);
40
- process.exit(0);
41
- }
42
- }
43
-
44
- return { source, target };
45
- }
46
-
47
- async function main() {
48
- const { source, target } = parseArgs();
49
- const result = await migrate({ source, target });
50
- console.error(formatMigrationSummary(source, target, result));
51
- }
52
-
53
- main().catch((err) => {
54
- console.error("❌ Migration failed:", err.message ?? err);
55
- process.exit(1);
56
- });
@@ -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
- }