minimem 0.0.6 → 0.1.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 +7 -4
- package/dist/cli/chunk-BIYUNXYX.js +2689 -0
- package/dist/cli/chunk-BIYUNXYX.js.map +1 -0
- package/dist/cli/index.js +656 -2892
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/minimem-MQXSBGNG.js +8 -0
- package/dist/cli/minimem-MQXSBGNG.js.map +1 -0
- package/dist/index.cjs +391 -8
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +198 -1
- package/dist/index.d.ts +198 -1
- package/dist/index.js +378 -8
- package/dist/index.js.map +1 -1
- package/package.json +3 -2
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/minimem.ts","../src/search/hybrid.ts","../src/search/search.ts","../src/db/schema.ts","../src/search/graph.ts","../src/db/sqlite-vec.ts","../src/embeddings/embeddings.ts","../src/embeddings/batch-openai.ts","../src/embeddings/batch-gemini.ts","../src/server/tools.ts","../src/server/mcp.ts","../src/core/indexer.ts","../src/core/searcher.ts"],"sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { DatabaseSync } from \"node:sqlite\";\nimport chokidar, { type FSWatcher } from \"chokidar\";\n\nimport {\n buildFileEntry,\n chunkMarkdown,\n ensureDir,\n extractChunkMetadata,\n hashText,\n listMemoryFiles,\n logError,\n type MemoryChunk,\n type MemoryFileEntry,\n parseEmbedding,\n vectorToBlob,\n} from \"./internal.js\";\nimport { bm25RankToScore, buildFtsQuery, mergeHybridResults } from \"./search/hybrid.js\";\nimport { searchKeyword, searchVector, buildKnowledgeFilterSql } from \"./search/search.js\";\nimport { ensureMemoryIndexSchema } from \"./db/schema.js\";\nimport { parseFrontmatter, type MemoryFrontmatter, type KnowledgeLink } from \"./session.js\";\nimport {\n getLinksFrom,\n getLinksTo,\n getNeighbors,\n getPathBetween,\n type GraphLink,\n type GraphNeighbor,\n} from \"./search/graph.js\";\nimport { loadSqliteVecExtension } from \"./db/sqlite-vec.js\";\nimport {\n createEmbeddingProvider,\n type EmbeddingProvider,\n type EmbeddingProviderOptions,\n type OpenAiEmbeddingClient,\n type GeminiEmbeddingClient,\n} from \"./embeddings/embeddings.js\";\nimport { runOpenAiEmbeddingBatches, type OpenAiBatchRequest, OPENAI_BATCH_ENDPOINT } from \"./embeddings/batch-openai.js\";\nimport { runGeminiEmbeddingBatches, type GeminiBatchRequest } from \"./embeddings/batch-gemini.js\";\n\nconst META_KEY = \"memory_index_meta_v1\";\nconst SNIPPET_MAX_CHARS = 700;\nconst VECTOR_TABLE = \"chunks_vec\";\nconst FTS_TABLE = \"chunks_fts\";\nconst EMBEDDING_CACHE_TABLE = \"embedding_cache\";\nconst EMBEDDING_BATCH_MAX_TOKENS = 8000;\nconst EMBEDDING_APPROX_CHARS_PER_TOKEN = 1;\nconst EMBEDDING_INDEX_CONCURRENCY = 4;\nconst EMBEDDING_RETRY_MAX_ATTEMPTS = 3;\nconst EMBEDDING_RETRY_BASE_DELAY_MS = 500;\nconst EMBEDDING_RETRY_MAX_DELAY_MS = 8000;\nconst VECTOR_LOAD_TIMEOUT_MS = 30_000;\nconst EMBEDDING_QUERY_TIMEOUT_REMOTE_MS = 60_000;\nconst EMBEDDING_QUERY_TIMEOUT_LOCAL_MS = 5 * 60_000;\n\nexport type MinimemConfig = {\n /** Directory containing memory files (MEMORY.md, memory/*.md) */\n memoryDir: string;\n /** Path to SQLite database. Defaults to memoryDir/.minimem/index.db */\n dbPath?: string;\n /** Embedding provider options */\n embedding: EmbeddingProviderOptions;\n /** Chunking configuration */\n chunking?: {\n /** Tokens per chunk (default: 256) */\n tokens?: number;\n /** Overlap tokens between chunks (default: 32) */\n overlap?: number;\n };\n /** Embedding cache configuration */\n cache?: {\n /** Enable embedding cache (default: true) */\n enabled?: boolean;\n /** Max cache entries before LRU pruning (default: 10000) */\n maxEntries?: number;\n };\n /** Hybrid search configuration */\n hybrid?: {\n /** Enable hybrid search (default: true) */\n enabled?: boolean;\n /** Weight for vector search (default: 0.7) */\n vectorWeight?: number;\n /** Weight for keyword search (default: 0.3) */\n textWeight?: number;\n /** Candidate multiplier for search (default: 2.0) */\n candidateMultiplier?: number;\n };\n /** Query configuration */\n query?: {\n /** Max results (default: 10) */\n maxResults?: number;\n /** Min score threshold (default: 0.3) */\n minScore?: number;\n };\n /** File watching configuration */\n watch?: {\n /** Enable file watching (default: true) */\n enabled?: boolean;\n /** Debounce delay in ms (default: 1000) */\n debounceMs?: number;\n };\n /** Batch embedding configuration */\n batch?: {\n /** Enable batch embedding API (default: false) */\n enabled?: boolean;\n /** Wait for batch completion (default: true) */\n wait?: boolean;\n /** Concurrent batch requests (default: 2) */\n concurrency?: number;\n /** Poll interval in ms (default: 2000) */\n pollIntervalMs?: number;\n /** Timeout in ms (default: 60 minutes) */\n timeoutMs?: number;\n };\n /** sqlite-vec extension path (optional) */\n vectorExtensionPath?: string;\n /** Debug logging function */\n debug?: (message: string, data?: Record<string, unknown>) => void;\n};\n\nexport type MinimemSearchResult = {\n path: string;\n startLine: number;\n endLine: number;\n score: number;\n snippet: string;\n};\n\ntype MemoryIndexMeta = {\n model: string;\n provider: string;\n providerKey?: string;\n chunkTokens: number;\n chunkOverlap: number;\n vectorDims?: number;\n};\n\nexport class Minimem {\n private readonly memoryDir: string;\n private readonly dbPath: string;\n private readonly chunking: { tokens: number; overlap: number };\n private readonly cache: { enabled: boolean; maxEntries: number };\n private readonly hybrid: {\n enabled: boolean;\n vectorWeight: number;\n textWeight: number;\n candidateMultiplier: number;\n };\n private readonly queryConfig: { maxResults: number; minScore: number };\n private readonly watchConfig: { enabled: boolean; debounceMs: number };\n private readonly batchConfig: {\n enabled: boolean;\n wait: boolean;\n concurrency: number;\n pollIntervalMs: number;\n timeoutMs: number;\n };\n private readonly vectorExtensionPath?: string;\n private readonly debug?: (message: string, data?: Record<string, unknown>) => void;\n\n private provider!: EmbeddingProvider;\n private openAi?: OpenAiEmbeddingClient;\n private gemini?: GeminiEmbeddingClient;\n private providerKey: string = \"\";\n private providerFallbackReason?: string;\n private db!: DatabaseSync;\n\n private readonly vector: {\n enabled: boolean;\n available: boolean | null;\n extensionPath?: string;\n loadError?: string;\n dims?: number;\n };\n private readonly fts: {\n enabled: boolean;\n available: boolean;\n loadError?: string;\n };\n\n private vectorReady: Promise<boolean> | null = null;\n private watcher: FSWatcher | null = null;\n private watchTimer: NodeJS.Timeout | null = null;\n private closed = false;\n private dirty = true;\n private syncing: Promise<void> | null = null;\n private syncLock = false;\n private embeddingOptions: EmbeddingProviderOptions;\n\n private constructor(config: MinimemConfig) {\n this.memoryDir = path.resolve(config.memoryDir);\n this.dbPath = config.dbPath ?? path.join(this.memoryDir, \".minimem\", \"index.db\");\n this.chunking = {\n tokens: config.chunking?.tokens ?? 256,\n overlap: config.chunking?.overlap ?? 32,\n };\n this.cache = {\n enabled: config.cache?.enabled ?? true,\n maxEntries: config.cache?.maxEntries ?? 10000,\n };\n this.hybrid = {\n enabled: config.hybrid?.enabled ?? true,\n vectorWeight: config.hybrid?.vectorWeight ?? 0.7,\n textWeight: config.hybrid?.textWeight ?? 0.3,\n candidateMultiplier: config.hybrid?.candidateMultiplier ?? 2.0,\n };\n this.queryConfig = {\n maxResults: config.query?.maxResults ?? 10,\n minScore: config.query?.minScore ?? 0.3,\n };\n this.watchConfig = {\n enabled: config.watch?.enabled ?? true,\n debounceMs: config.watch?.debounceMs ?? 1000,\n };\n this.batchConfig = {\n enabled: config.batch?.enabled ?? false,\n wait: config.batch?.wait ?? true,\n concurrency: config.batch?.concurrency ?? 2,\n pollIntervalMs: config.batch?.pollIntervalMs ?? 2000,\n timeoutMs: config.batch?.timeoutMs ?? 60 * 60 * 1000,\n };\n this.vectorExtensionPath = config.vectorExtensionPath;\n this.debug = config.debug;\n this.embeddingOptions = config.embedding;\n\n this.vector = {\n enabled: true,\n available: null,\n extensionPath: this.vectorExtensionPath,\n };\n this.fts = { enabled: this.hybrid.enabled, available: false };\n }\n\n static async create(config: MinimemConfig): Promise<Minimem> {\n const instance = new Minimem(config);\n await instance.initialize();\n return instance;\n }\n\n private async initialize(): Promise<void> {\n // Create embedding provider\n const providerResult = await createEmbeddingProvider(this.embeddingOptions);\n this.provider = providerResult.provider;\n this.openAi = providerResult.openAi;\n this.gemini = providerResult.gemini;\n this.providerKey = this.computeProviderKey();\n this.providerFallbackReason = providerResult.fallbackReason;\n\n // Log warning if in BM25-only fallback mode\n if (this.provider.id === \"none\") {\n this.debug?.(\"Running in BM25-only mode (no embedding API available)\");\n }\n\n // Open database\n this.db = this.openDatabase();\n this.ensureSchema();\n\n // Check for existing vector dims\n const meta = this.readMeta();\n if (meta?.vectorDims) {\n this.vector.dims = meta.vectorDims;\n }\n\n // Start file watcher\n if (this.watchConfig.enabled) {\n this.ensureWatcher();\n }\n }\n\n private openDatabase(): DatabaseSync {\n const dbDir = path.dirname(this.dbPath);\n ensureDir(dbDir);\n return new DatabaseSync(this.dbPath);\n }\n\n private ensureSchema(): void {\n const result = ensureMemoryIndexSchema({\n db: this.db,\n embeddingCacheTable: EMBEDDING_CACHE_TABLE,\n ftsTable: FTS_TABLE,\n ftsEnabled: this.fts.enabled,\n });\n this.fts.available = result.ftsAvailable;\n if (result.ftsError) {\n this.fts.loadError = result.ftsError;\n }\n }\n\n private computeProviderKey(): string {\n const parts: string[] = [this.provider.id, this.provider.model];\n if (this.openAi) {\n parts.push(this.openAi.baseUrl);\n }\n if (this.gemini) {\n parts.push(this.gemini.baseUrl);\n }\n return hashText(parts.join(\":\"));\n }\n\n private readMeta(): MemoryIndexMeta | null {\n try {\n const row = this.db.prepare(`SELECT value FROM meta WHERE key = ?`).get(META_KEY) as\n | { value: string }\n | undefined;\n if (!row?.value) return null;\n return JSON.parse(row.value) as MemoryIndexMeta;\n } catch {\n return null;\n }\n }\n\n private writeMeta(meta: MemoryIndexMeta): void {\n this.db\n .prepare(`INSERT OR REPLACE INTO meta (key, value) VALUES (?, ?)`)\n .run(META_KEY, JSON.stringify(meta));\n }\n\n private ensureWatcher(): void {\n if (this.watcher) return;\n const memorySubDir = path.join(this.memoryDir, \"memory\");\n const memoryFile = path.join(this.memoryDir, \"MEMORY.md\");\n\n this.watcher = chokidar.watch([memoryFile, memorySubDir], {\n ignoreInitial: true,\n persistent: true,\n awaitWriteFinish: { stabilityThreshold: 200, pollInterval: 50 },\n });\n\n const scheduleSync = () => {\n this.dirty = true;\n if (this.watchTimer) clearTimeout(this.watchTimer);\n this.watchTimer = setTimeout(() => {\n void this.sync({ reason: \"watch\" }).catch((err) => {\n this.debug?.(`memory sync failed (watch): ${String(err)}`);\n });\n }, this.watchConfig.debounceMs);\n };\n\n this.watcher.on(\"add\", scheduleSync);\n this.watcher.on(\"change\", scheduleSync);\n this.watcher.on(\"unlink\", scheduleSync);\n }\n\n /**\n * Check if the index is stale by comparing file mtimes against stored values.\n * This is a lightweight check (stat calls only, no file reads).\n */\n private async isStale(): Promise<boolean> {\n try {\n const files = await listMemoryFiles(this.memoryDir);\n\n // Get stored file records\n const stored = this.db\n .prepare(`SELECT path, mtime FROM files WHERE source = ?`)\n .all(\"memory\") as Array<{ path: string; mtime: number }>;\n\n // Quick check: different file count means stale\n if (files.length !== stored.length) {\n this.debug?.(`Stale: file count changed (${stored.length} -> ${files.length})`);\n return true;\n }\n\n // Build lookup map of stored mtimes\n const storedMap = new Map(stored.map((f) => [f.path, f.mtime]));\n\n // Check each file's mtime against stored value\n for (const absPath of files) {\n const relPath = path.relative(this.memoryDir, absPath).replace(/\\\\/g, \"/\");\n const storedMtime = storedMap.get(relPath);\n\n // File not in index = stale\n if (storedMtime === undefined) {\n this.debug?.(`Stale: new file ${relPath}`);\n return true;\n }\n\n // Check mtime\n const stat = await fs.stat(absPath);\n const currentMtime = Math.floor(stat.mtimeMs);\n if (currentMtime !== storedMtime) {\n this.debug?.(`Stale: mtime changed for ${relPath}`);\n return true;\n }\n }\n\n return false;\n } catch (err) {\n // On error, assume stale to be safe\n this.debug?.(`Stale check failed: ${String(err)}`);\n return true;\n }\n }\n\n async search(\n query: string,\n opts?: { maxResults?: number; minScore?: number; type?: string },\n ): Promise<MinimemSearchResult[]> {\n // Check staleness: use dirty flag if watcher is on, otherwise check mtimes\n if (this.dirty || (!this.watchConfig.enabled && (await this.isStale()))) {\n await this.sync({ reason: \"search\" });\n }\n\n const cleaned = query.trim();\n if (!cleaned) return [];\n\n const minScore = opts?.minScore ?? this.queryConfig.minScore;\n const maxResults = opts?.maxResults ?? this.queryConfig.maxResults;\n const candidates = Math.min(\n 200,\n Math.max(1, Math.floor(maxResults * this.hybrid.candidateMultiplier)),\n );\n\n const sourceFilter = { sql: \"\", params: [] as string[] };\n\n const keywordResults = this.hybrid.enabled && this.fts.available\n ? await searchKeyword({\n db: this.db,\n ftsTable: FTS_TABLE,\n providerModel: this.provider.model,\n query: cleaned,\n limit: candidates,\n snippetMaxChars: SNIPPET_MAX_CHARS,\n sourceFilter,\n buildFtsQuery,\n bm25RankToScore,\n }).catch(() => [])\n : [];\n\n const queryVec = await this.embedQueryWithTimeout(cleaned);\n const hasVector = queryVec.some((v) => v !== 0);\n const vectorResults = hasVector\n ? await searchVector({\n db: this.db,\n vectorTable: VECTOR_TABLE,\n providerModel: this.provider.model,\n queryVec,\n limit: candidates,\n snippetMaxChars: SNIPPET_MAX_CHARS,\n ensureVectorReady: (dims) => this.ensureVectorReady(dims),\n sourceFilterVec: sourceFilter,\n sourceFilterChunks: sourceFilter,\n }).catch(() => [])\n : [];\n\n // Apply type filter if specified\n const typeFilterFn = opts?.type\n ? (id: string) => {\n const row = this.db\n .prepare(`SELECT type FROM chunks WHERE id = ?`)\n .get(id) as { type: string | null } | undefined;\n return row?.type === opts.type;\n }\n : undefined;\n\n if (!this.hybrid.enabled) {\n let results = vectorResults;\n if (typeFilterFn) results = results.filter((r) => typeFilterFn(r.id));\n return results\n .filter((entry) => entry.score >= minScore)\n .slice(0, maxResults)\n .map((r) => ({\n path: r.path,\n startLine: r.startLine,\n endLine: r.endLine,\n score: r.score,\n snippet: r.snippet,\n }));\n }\n\n let filteredVector = vectorResults;\n let filteredKeyword = keywordResults;\n if (typeFilterFn) {\n filteredVector = vectorResults.filter((r) => typeFilterFn(r.id));\n filteredKeyword = keywordResults.filter((r) => typeFilterFn(r.id));\n }\n\n const merged = mergeHybridResults({\n vector: filteredVector.map((r) => ({\n id: r.id,\n path: r.path,\n startLine: r.startLine,\n endLine: r.endLine,\n source: r.source,\n snippet: r.snippet,\n vectorScore: r.score,\n })),\n keyword: filteredKeyword.map((r) => ({\n id: r.id,\n path: r.path,\n startLine: r.startLine,\n endLine: r.endLine,\n source: r.source,\n snippet: r.snippet,\n textScore: r.textScore,\n })),\n vectorWeight: this.hybrid.vectorWeight,\n textWeight: this.hybrid.textWeight,\n });\n\n return merged\n .filter((entry) => entry.score >= minScore)\n .slice(0, maxResults)\n .map((r) => ({\n path: r.path,\n startLine: r.startLine,\n endLine: r.endLine,\n score: r.score,\n snippet: r.snippet,\n }));\n }\n\n async sync(opts?: { reason?: string; force?: boolean }): Promise<void> {\n // If a sync is already running, wait for it instead of starting another\n if (this.syncing) {\n await this.syncing;\n return;\n }\n\n // Use a synchronous flag to prevent the race window between\n // checking this.syncing and assigning to it\n if (this.syncLock) {\n return;\n }\n this.syncLock = true;\n\n this.syncing = this.runSync(opts);\n try {\n await this.syncing;\n } finally {\n this.syncing = null;\n this.syncLock = false;\n }\n }\n\n private async runSync(opts?: { reason?: string; force?: boolean }): Promise<void> {\n this.debug?.(`memory sync starting`, { reason: opts?.reason });\n\n await this.ensureVectorReady();\n const meta = this.readMeta();\n const needsFullReindex =\n opts?.force ||\n !meta ||\n meta.model !== this.provider.model ||\n meta.provider !== this.provider.id ||\n meta.providerKey !== this.providerKey ||\n meta.chunkTokens !== this.chunking.tokens ||\n meta.chunkOverlap !== this.chunking.overlap ||\n (this.vector.available && !meta?.vectorDims);\n\n const files = await listMemoryFiles(this.memoryDir);\n const activePaths = new Set<string>();\n\n for (const absPath of files) {\n const entry = await buildFileEntry(absPath, this.memoryDir);\n activePaths.add(entry.path);\n\n const record = this.db\n .prepare(`SELECT hash FROM files WHERE path = ? AND source = ?`)\n .get(entry.path, \"memory\") as { hash: string } | undefined;\n\n if (!needsFullReindex && record?.hash === entry.hash) {\n continue;\n }\n\n await this.indexFile(entry);\n }\n\n // Delete stale entries\n const staleRows = this.db\n .prepare(`SELECT path FROM files WHERE source = ?`)\n .all(\"memory\") as Array<{ path: string }>;\n\n for (const stale of staleRows) {\n if (activePaths.has(stale.path)) continue;\n this.db.prepare(`DELETE FROM files WHERE path = ? AND source = ?`).run(stale.path, \"memory\");\n try {\n this.db\n .prepare(\n `DELETE FROM ${VECTOR_TABLE} WHERE id IN (SELECT id FROM chunks WHERE path = ? AND source = ?)`,\n )\n .run(stale.path, \"memory\");\n } catch (err) {\n logError(\"deleteStaleVectorEntries\", err, this.debug);\n }\n this.db.prepare(`DELETE FROM chunks WHERE path = ? AND source = ?`).run(stale.path, \"memory\");\n this.db.prepare(`DELETE FROM knowledge_links WHERE source_path = ?`).run(stale.path);\n if (this.fts.enabled && this.fts.available) {\n try {\n this.db\n .prepare(`DELETE FROM ${FTS_TABLE} WHERE path = ? AND source = ? AND model = ?`)\n .run(stale.path, \"memory\", this.provider.model);\n } catch (err) {\n logError(\"deleteStaleFtsEntries\", err, this.debug);\n }\n }\n }\n\n // Write meta\n this.writeMeta({\n model: this.provider.model,\n provider: this.provider.id,\n providerKey: this.providerKey,\n chunkTokens: this.chunking.tokens,\n chunkOverlap: this.chunking.overlap,\n vectorDims: this.vector.dims,\n });\n\n // Prune embedding cache\n this.pruneEmbeddingCacheIfNeeded();\n\n this.dirty = false;\n this.debug?.(`memory sync complete`, { files: files.length });\n }\n\n private async indexFile(entry: MemoryFileEntry): Promise<void> {\n const content = await fs.readFile(entry.absPath, \"utf-8\");\n const chunks = chunkMarkdown(content, this.chunking);\n\n // Extract knowledge frontmatter\n const { frontmatter } = parseFrontmatter(content);\n const knowledgeType = frontmatter?.type ?? null;\n const knowledgeId = frontmatter?.id ?? null;\n const domains = frontmatter?.domain ?? null;\n const entities = frontmatter?.entities ?? null;\n const confidence = frontmatter?.confidence ?? null;\n const links = frontmatter?.links ?? null;\n\n // Get embeddings\n const embeddings = await this.embedChunks(chunks);\n\n // Update files table\n this.db\n .prepare(\n `INSERT OR REPLACE INTO files (path, source, hash, mtime, size) VALUES (?, ?, ?, ?, ?)`,\n )\n .run(entry.path, \"memory\", entry.hash, Math.floor(entry.mtimeMs), entry.size);\n\n // Delete old chunks for this file\n try {\n this.db\n .prepare(\n `DELETE FROM ${VECTOR_TABLE} WHERE id IN (SELECT id FROM chunks WHERE path = ? AND source = ?)`,\n )\n .run(entry.path, \"memory\");\n } catch (err) {\n logError(\"deleteOldVectorChunks\", err, this.debug);\n }\n this.db.prepare(`DELETE FROM chunks WHERE path = ? AND source = ?`).run(entry.path, \"memory\");\n if (this.fts.enabled && this.fts.available) {\n try {\n this.db\n .prepare(`DELETE FROM ${FTS_TABLE} WHERE path = ? AND source = ? AND model = ?`)\n .run(entry.path, \"memory\", this.provider.model);\n } catch (err) {\n logError(\"deleteOldFtsChunks\", err, this.debug);\n }\n }\n\n // Delete old knowledge links for this file path on re-index\n this.db.prepare(`DELETE FROM knowledge_links WHERE source_path = ?`).run(entry.path);\n\n // Insert new chunks\n const now = Date.now();\n for (let i = 0; i < chunks.length; i++) {\n const chunk = chunks[i];\n const embedding = embeddings[i] ?? [];\n const chunkId = randomUUID();\n const meta = extractChunkMetadata(chunk.text);\n\n this.db\n .prepare(\n `INSERT INTO chunks (id, path, source, start_line, end_line, hash, model, text, embedding, updated_at, type, knowledge_type, knowledge_id, domains, entities, confidence)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,\n )\n .run(\n chunkId,\n entry.path,\n \"memory\",\n chunk.startLine,\n chunk.endLine,\n chunk.hash,\n this.provider.model,\n chunk.text,\n JSON.stringify(embedding),\n now,\n meta.type ?? null,\n knowledgeType,\n knowledgeId,\n domains ? JSON.stringify(domains) : null,\n entities ? JSON.stringify(entities) : null,\n confidence,\n );\n\n // Insert into vector table if available\n if (this.vector.available && embedding.length > 0) {\n if (!this.vector.dims) {\n this.vector.dims = embedding.length;\n this.ensureVectorTable(embedding.length);\n }\n try {\n this.db\n .prepare(`INSERT INTO ${VECTOR_TABLE} (id, embedding) VALUES (?, ?)`)\n .run(chunkId, vectorToBlob(embedding));\n } catch (err) {\n logError(\"insertVectorChunk\", err, this.debug);\n }\n }\n\n // Insert into FTS table if available\n if (this.fts.enabled && this.fts.available) {\n try {\n this.db\n .prepare(\n `INSERT INTO ${FTS_TABLE} (text, id, path, source, model, start_line, end_line)\n VALUES (?, ?, ?, ?, ?, ?, ?)`,\n )\n .run(\n chunk.text,\n chunkId,\n entry.path,\n \"memory\",\n this.provider.model,\n chunk.startLine,\n chunk.endLine,\n );\n } catch (err) {\n logError(\"insertFtsChunk\", err, this.debug);\n }\n }\n }\n\n // Upsert knowledge links if present\n if (links && knowledgeId) {\n const upsertLink = this.db.prepare(\n `INSERT OR REPLACE INTO knowledge_links (from_id, to_id, relation, layer, weight, source_path, created_at)\n VALUES (?, ?, ?, ?, ?, ?, ?)`,\n );\n for (const link of links) {\n upsertLink.run(\n knowledgeId,\n link.target,\n link.relation,\n link.layer ?? null,\n 0.5,\n entry.path,\n now,\n );\n }\n }\n }\n\n private async embedChunks(chunks: MemoryChunk[]): Promise<number[][]> {\n if (chunks.length === 0) return [];\n\n const hashes = chunks.map((c) => c.hash);\n const cached = this.loadEmbeddingCache(hashes);\n const missing: Array<{ index: number; chunk: MemoryChunk }> = [];\n\n for (let i = 0; i < chunks.length; i++) {\n if (!cached.has(hashes[i])) {\n missing.push({ index: i, chunk: chunks[i] });\n }\n }\n\n if (missing.length > 0) {\n const texts = missing.map((m) => m.chunk.text);\n const newEmbeddings = await this.embedBatchWithRetry(texts);\n\n for (let i = 0; i < missing.length; i++) {\n const hash = missing[i].chunk.hash;\n const embedding = newEmbeddings[i] ?? [];\n cached.set(hash, embedding);\n this.upsertEmbeddingCache(hash, embedding);\n }\n }\n\n return hashes.map((h) => cached.get(h) ?? []);\n }\n\n private async embedBatchWithRetry(texts: string[]): Promise<number[][]> {\n if (texts.length === 0) return [];\n\n // Try batch API first if enabled\n if (this.batchConfig.enabled) {\n try {\n return await this.embedWithBatchApi(texts);\n } catch (err) {\n this.debug?.(`batch embedding failed, falling back to direct: ${String(err)}`);\n }\n }\n\n // Fall back to direct embedding\n let lastError: Error | null = null;\n for (let attempt = 0; attempt < EMBEDDING_RETRY_MAX_ATTEMPTS; attempt++) {\n try {\n return await this.provider.embedBatch(texts);\n } catch (err) {\n lastError = err instanceof Error ? err : new Error(String(err));\n if (attempt < EMBEDDING_RETRY_MAX_ATTEMPTS - 1) {\n const delay = Math.min(\n EMBEDDING_RETRY_MAX_DELAY_MS,\n EMBEDDING_RETRY_BASE_DELAY_MS * Math.pow(2, attempt),\n );\n await new Promise((resolve) => setTimeout(resolve, delay));\n }\n }\n }\n throw lastError;\n }\n\n private async embedWithBatchApi(texts: string[]): Promise<number[][]> {\n if (this.openAi) {\n const requests: OpenAiBatchRequest[] = texts.map((text, i) => ({\n custom_id: `chunk-${i}`,\n method: \"POST\",\n url: OPENAI_BATCH_ENDPOINT,\n body: { model: this.openAi!.model, input: text },\n }));\n\n const results = await runOpenAiEmbeddingBatches({\n openAi: this.openAi,\n source: \"minimem\",\n requests,\n wait: this.batchConfig.wait,\n pollIntervalMs: this.batchConfig.pollIntervalMs,\n timeoutMs: this.batchConfig.timeoutMs,\n concurrency: this.batchConfig.concurrency,\n debug: this.debug,\n });\n\n return texts.map((_, i) => results.get(`chunk-${i}`) ?? []);\n }\n\n if (this.gemini) {\n const requests: GeminiBatchRequest[] = texts.map((text, i) => ({\n custom_id: `chunk-${i}`,\n content: { parts: [{ text }] },\n taskType: \"RETRIEVAL_DOCUMENT\",\n }));\n\n const results = await runGeminiEmbeddingBatches({\n gemini: this.gemini,\n source: \"minimem\",\n requests,\n wait: this.batchConfig.wait,\n pollIntervalMs: this.batchConfig.pollIntervalMs,\n timeoutMs: this.batchConfig.timeoutMs,\n concurrency: this.batchConfig.concurrency,\n debug: this.debug,\n });\n\n return texts.map((_, i) => results.get(`chunk-${i}`) ?? []);\n }\n\n throw new Error(\"Batch API not available for local embeddings\");\n }\n\n private async embedQueryWithTimeout(text: string): Promise<number[]> {\n const timeout =\n this.provider.id === \"local\" ? EMBEDDING_QUERY_TIMEOUT_LOCAL_MS : EMBEDDING_QUERY_TIMEOUT_REMOTE_MS;\n\n const ac = new AbortController();\n const timer = setTimeout(() => ac.abort(), timeout);\n\n try {\n const result = await Promise.race([\n this.provider.embedQuery(text),\n new Promise<number[]>((_, reject) => {\n ac.signal.addEventListener(\"abort\", () =>\n reject(new Error(\"embedding query timeout\")),\n );\n }),\n ]);\n return result;\n } finally {\n clearTimeout(timer);\n }\n }\n\n private loadEmbeddingCache(hashes: string[]): Map<string, number[]> {\n const result = new Map<string, number[]>();\n if (!this.cache.enabled || hashes.length === 0) return result;\n\n const placeholders = hashes.map(() => \"?\").join(\",\");\n const rows = this.db\n .prepare(\n `SELECT hash, embedding FROM ${EMBEDDING_CACHE_TABLE}\n WHERE provider = ? AND model = ? AND provider_key = ? AND hash IN (${placeholders})`,\n )\n .all(this.provider.id, this.provider.model, this.providerKey, ...hashes) as Array<{\n hash: string;\n embedding: string;\n }>;\n\n const now = Date.now();\n for (const row of rows) {\n result.set(row.hash, parseEmbedding(row.embedding));\n // Touch for LRU\n this.db\n .prepare(\n `UPDATE ${EMBEDDING_CACHE_TABLE} SET updated_at = ?\n WHERE provider = ? AND model = ? AND provider_key = ? AND hash = ?`,\n )\n .run(now, this.provider.id, this.provider.model, this.providerKey, row.hash);\n }\n\n return result;\n }\n\n private upsertEmbeddingCache(hash: string, embedding: number[]): void {\n if (!this.cache.enabled) return;\n const now = Date.now();\n this.db\n .prepare(\n `INSERT OR REPLACE INTO ${EMBEDDING_CACHE_TABLE}\n (provider, model, provider_key, hash, embedding, dims, updated_at)\n VALUES (?, ?, ?, ?, ?, ?, ?)`,\n )\n .run(\n this.provider.id,\n this.provider.model,\n this.providerKey,\n hash,\n JSON.stringify(embedding),\n embedding.length,\n now,\n );\n }\n\n private pruneEmbeddingCacheIfNeeded(): void {\n if (!this.cache.enabled) return;\n const row = this.db\n .prepare(`SELECT COUNT(*) as count FROM ${EMBEDDING_CACHE_TABLE}`)\n .get() as { count: number };\n if (row.count <= this.cache.maxEntries) return;\n\n const excess = row.count - this.cache.maxEntries;\n this.db\n .prepare(\n `DELETE FROM ${EMBEDDING_CACHE_TABLE}\n WHERE rowid IN (\n SELECT rowid FROM ${EMBEDDING_CACHE_TABLE}\n ORDER BY updated_at ASC\n LIMIT ?\n )`,\n )\n .run(excess);\n }\n\n private async ensureVectorReady(dimensions?: number): Promise<boolean> {\n if (this.vector.available === true) return true;\n if (this.vector.available === false) return false;\n\n if (!this.vectorReady) {\n this.vectorReady = this.loadVectorExtension();\n }\n\n const ready = await this.vectorReady;\n if (ready && dimensions && !this.vector.dims) {\n this.vector.dims = dimensions;\n this.ensureVectorTable(dimensions);\n }\n return ready;\n }\n\n private async loadVectorExtension(): Promise<boolean> {\n const result = await loadSqliteVecExtension({\n db: this.db,\n extensionPath: this.vectorExtensionPath,\n });\n\n this.vector.available = result.ok;\n if (result.error) {\n this.vector.loadError = result.error;\n this.debug?.(`sqlite-vec load failed: ${result.error}`);\n }\n if (result.extensionPath) {\n this.vector.extensionPath = result.extensionPath;\n }\n\n return result.ok;\n }\n\n private ensureVectorTable(dimensions: number): void {\n if (!this.vector.available) return;\n try {\n this.db.exec(\n `CREATE VIRTUAL TABLE IF NOT EXISTS ${VECTOR_TABLE} USING vec0(\n id TEXT PRIMARY KEY,\n embedding FLOAT[${dimensions}]\n )`,\n );\n } catch (err) {\n this.debug?.(`vector table creation failed: ${String(err)}`);\n }\n }\n\n async readFile(relativePath: string): Promise<string | null> {\n const absPath = path.join(this.memoryDir, relativePath);\n try {\n return await fs.readFile(absPath, \"utf-8\");\n } catch {\n return null;\n }\n }\n\n /**\n * Read specific lines from a memory file\n */\n async readLines(\n relativePath: string,\n opts?: { from?: number; lines?: number },\n ): Promise<{ content: string; startLine: number; endLine: number } | null> {\n const content = await this.readFile(relativePath);\n if (content === null) return null;\n\n const allLines = content.split(\"\\n\");\n const from = Math.max(1, opts?.from ?? 1);\n const lines = opts?.lines ?? allLines.length;\n\n const startIdx = from - 1;\n const endIdx = Math.min(startIdx + lines, allLines.length);\n const selectedLines = allLines.slice(startIdx, endIdx);\n\n return {\n content: selectedLines.join(\"\\n\"),\n startLine: from,\n endLine: startIdx + selectedLines.length,\n };\n }\n\n /**\n * Write content to a memory file (creates or overwrites)\n */\n async writeFile(relativePath: string, content: string): Promise<void> {\n this.validateMemoryPath(relativePath);\n const absPath = path.join(this.memoryDir, relativePath);\n const dir = path.dirname(absPath);\n await fs.mkdir(dir, { recursive: true });\n await fs.writeFile(absPath, content, \"utf-8\");\n this.dirty = true;\n this.debug?.(`memory write: ${relativePath}`);\n }\n\n /**\n * Append content to a memory file (creates if doesn't exist)\n */\n async appendFile(relativePath: string, content: string): Promise<void> {\n this.validateMemoryPath(relativePath);\n const absPath = path.join(this.memoryDir, relativePath);\n const dir = path.dirname(absPath);\n await fs.mkdir(dir, { recursive: true });\n\n // Ensure newline separation\n let toAppend = content;\n try {\n const existing = await fs.readFile(absPath, \"utf-8\");\n if (existing.length > 0 && !existing.endsWith(\"\\n\")) {\n toAppend = \"\\n\" + content;\n }\n } catch {\n // File doesn't exist, will be created\n }\n\n await fs.appendFile(absPath, toAppend, \"utf-8\");\n this.dirty = true;\n this.debug?.(`memory append: ${relativePath}`);\n }\n\n /**\n * Append content to today's daily log (memory/YYYY-MM-DD.md)\n */\n async appendToday(content: string): Promise<string> {\n const today = new Date().toISOString().split(\"T\")[0]; // YYYY-MM-DD\n const relativePath = `memory/${today}.md`;\n await this.appendFile(relativePath, content);\n return relativePath;\n }\n\n /**\n * List all memory files\n */\n async listFiles(): Promise<string[]> {\n const files = await listMemoryFiles(this.memoryDir);\n return files.map((f) => path.relative(this.memoryDir, f).replace(/\\\\/g, \"/\"));\n }\n\n /**\n * Validate that a path is within allowed memory locations\n */\n private validateMemoryPath(relativePath: string): void {\n const normalized = relativePath.replace(/\\\\/g, \"/\").replace(/^\\.\\//, \"\");\n\n // Allow MEMORY.md at root\n if (normalized === \"MEMORY.md\" || normalized === \"memory.md\") {\n return;\n }\n\n // Allow anything under memory/\n if (normalized.startsWith(\"memory/\") && normalized.endsWith(\".md\")) {\n // Prevent path traversal\n if (normalized.includes(\"..\")) {\n throw new Error(`Invalid memory path: ${relativePath} (path traversal not allowed)`);\n }\n return;\n }\n\n throw new Error(\n `Invalid memory path: ${relativePath}. Must be MEMORY.md or memory/*.md`,\n );\n }\n\n async status(): Promise<{\n memoryDir: string;\n dbPath: string;\n provider: string;\n model: string;\n vectorAvailable: boolean;\n ftsAvailable: boolean;\n bm25Only: boolean;\n fallbackReason?: string;\n fileCount: number;\n chunkCount: number;\n cacheCount: number;\n }> {\n const fileRow = this.db.prepare(`SELECT COUNT(*) as count FROM files`).get() as { count: number };\n const chunkRow = this.db.prepare(`SELECT COUNT(*) as count FROM chunks`).get() as { count: number };\n const cacheRow = this.db\n .prepare(`SELECT COUNT(*) as count FROM ${EMBEDDING_CACHE_TABLE}`)\n .get() as { count: number };\n\n return {\n memoryDir: this.memoryDir,\n dbPath: this.dbPath,\n provider: this.provider.id,\n model: this.provider.model,\n vectorAvailable: this.vector.available === true,\n ftsAvailable: this.fts.available,\n bm25Only: this.provider.id === \"none\",\n fallbackReason: this.providerFallbackReason,\n fileCount: fileRow.count,\n chunkCount: chunkRow.count,\n cacheCount: cacheRow.count,\n };\n }\n\n /**\n * Search with knowledge metadata filters (domain, entities, confidence, type).\n * Runs a standard search then post-filters by knowledge columns.\n */\n async knowledgeSearch(\n query: string,\n opts?: {\n maxResults?: number;\n minScore?: number;\n domain?: string[];\n entities?: string[];\n minConfidence?: number;\n knowledgeType?: string;\n },\n ): Promise<MinimemSearchResult[]> {\n // Ensure index is up to date\n if (this.dirty || (!this.watchConfig.enabled && (await this.isStale()))) {\n await this.sync({ reason: \"knowledgeSearch\" });\n }\n\n const cleaned = query.trim();\n if (!cleaned) return [];\n\n const minScore = opts?.minScore ?? this.queryConfig.minScore;\n const maxResults = opts?.maxResults ?? this.queryConfig.maxResults;\n\n // Build knowledge filter SQL\n const { sql: knowledgeWhere, params: knowledgeParams } =\n buildKnowledgeFilterSql({\n domain: opts?.domain,\n entities: opts?.entities,\n minConfidence: opts?.minConfidence,\n knowledgeType: opts?.knowledgeType,\n });\n\n // If no knowledge filters, delegate to regular search\n if (!knowledgeWhere) {\n return this.search(query, { maxResults, minScore });\n }\n\n // Get all chunk IDs matching knowledge filters\n const matchingRows = this.db\n .prepare(\n `SELECT id FROM chunks c WHERE c.model = ? AND c.source = 'memory'${knowledgeWhere}`,\n )\n .all(this.provider.model, ...knowledgeParams) as Array<{ id: string }>;\n\n const matchingIds = new Set(matchingRows.map((r) => r.id));\n\n if (matchingIds.size === 0) return [];\n\n // Run standard search with extra candidates to compensate for filtering\n const overFetch = Math.max(maxResults * 3, 30);\n const results = await this.search(query, {\n maxResults: overFetch,\n minScore,\n });\n\n // Post-filter: look up chunk IDs for each result and keep only matching ones\n const filtered: MinimemSearchResult[] = [];\n for (const r of results) {\n const row = this.db\n .prepare(\n `SELECT id FROM chunks WHERE path = ? AND start_line = ? AND end_line = ? AND model = ?`,\n )\n .get(r.path, r.startLine, r.endLine, this.provider.model) as { id: string } | undefined;\n if (row && matchingIds.has(row.id)) {\n filtered.push(r);\n if (filtered.length >= maxResults) break;\n }\n }\n\n return filtered;\n }\n\n /**\n * Get knowledge graph links from or to a node.\n */\n getLinks(\n nodeId: string,\n direction: \"from\" | \"to\" = \"from\",\n opts?: { relation?: string; layer?: string },\n ): GraphLink[] {\n if (direction === \"from\") {\n return getLinksFrom(this.db, nodeId, opts);\n }\n return getLinksTo(this.db, nodeId, opts);\n }\n\n /**\n * Get neighbor nodes via BFS traversal.\n */\n getGraphNeighbors(\n nodeId: string,\n depth: number = 1,\n opts?: { relation?: string; layer?: string },\n ): GraphNeighbor[] {\n return getNeighbors(this.db, nodeId, depth, opts);\n }\n\n /**\n * Find shortest path between two knowledge nodes.\n */\n getGraphPath(fromId: string, toId: string, maxDepth: number = 3): GraphLink[] {\n return getPathBetween(this.db, fromId, toId, maxDepth);\n }\n\n close(): void {\n if (this.closed) return;\n this.closed = true;\n\n if (this.watchTimer) {\n clearTimeout(this.watchTimer);\n this.watchTimer = null;\n }\n\n if (this.watcher) {\n void this.watcher.close();\n this.watcher = null;\n }\n\n try {\n this.db.close();\n } catch (err) {\n logError(\"dbClose\", err, this.debug);\n }\n }\n}\n","export type HybridSource = string;\n\nexport type HybridVectorResult = {\n id: string;\n path: string;\n startLine: number;\n endLine: number;\n source: HybridSource;\n snippet: string;\n vectorScore: number;\n};\n\nexport type HybridKeywordResult = {\n id: string;\n path: string;\n startLine: number;\n endLine: number;\n source: HybridSource;\n snippet: string;\n textScore: number;\n};\n\nexport function buildFtsQuery(raw: string): string | null {\n const tokens =\n raw\n .match(/[A-Za-z0-9_]+/g)\n ?.map((t) => t.trim())\n .filter(Boolean) ?? [];\n if (tokens.length === 0) return null;\n const quoted = tokens.map((t) => `\"${t.replaceAll('\"', \"\")}\"`);\n return quoted.join(\" AND \");\n}\n\n/**\n * Convert BM25 rank from SQLite FTS5 to a 0-1 score.\n *\n * FTS5 BM25 ranks are NEGATIVE numbers where more negative = better match.\n * A rank of 0 means no match, -10 is better than -1.\n *\n * We use absolute value to convert to positive, then normalize to 0-1\n * using the formula: score = 1 / (1 + absRank)\n *\n * Examples:\n * - rank 0 (no match) -> score 1.0\n * - rank -1 (weak match) -> score 0.5\n * - rank -10 (strong match) -> score ~0.09\n *\n * Note: Higher absolute rank magnitude = better match = higher score after conversion.\n */\nexport function bm25RankToScore(rank: number): number {\n // Handle non-finite values (NaN, Infinity)\n if (!Number.isFinite(rank)) {\n return 0;\n }\n\n // BM25 ranks from FTS5 are negative (more negative = better match)\n // Use absolute value to get the magnitude\n const absRank = Math.abs(rank);\n\n // Convert to 0-1 score where higher magnitude = higher score\n // Using 1/(1+x) gives us a nice 0-1 range that decreases smoothly\n return 1 / (1 + absRank);\n}\n\nexport function mergeHybridResults(params: {\n vector: HybridVectorResult[];\n keyword: HybridKeywordResult[];\n vectorWeight: number;\n textWeight: number;\n}): Array<{\n path: string;\n startLine: number;\n endLine: number;\n score: number;\n snippet: string;\n source: HybridSource;\n}> {\n const byId = new Map<\n string,\n {\n id: string;\n path: string;\n startLine: number;\n endLine: number;\n source: HybridSource;\n snippet: string;\n vectorScore: number;\n textScore: number;\n }\n >();\n\n for (const r of params.vector) {\n byId.set(r.id, {\n id: r.id,\n path: r.path,\n startLine: r.startLine,\n endLine: r.endLine,\n source: r.source,\n snippet: r.snippet,\n vectorScore: r.vectorScore,\n textScore: 0,\n });\n }\n\n for (const r of params.keyword) {\n const existing = byId.get(r.id);\n if (existing) {\n existing.textScore = r.textScore;\n if (r.snippet && r.snippet.length > 0) existing.snippet = r.snippet;\n } else {\n byId.set(r.id, {\n id: r.id,\n path: r.path,\n startLine: r.startLine,\n endLine: r.endLine,\n source: r.source,\n snippet: r.snippet,\n vectorScore: 0,\n textScore: r.textScore,\n });\n }\n }\n\n // When one side of the hybrid search has no results, normalize weights\n // so the available side scores at full strength. Without this, BM25-only\n // results would be scaled to 0.3 * textScore which is too low to pass\n // the default minScore threshold.\n let vw = params.vectorWeight;\n let tw = params.textWeight;\n if (params.vector.length === 0 && params.keyword.length > 0) {\n vw = 0;\n tw = 1;\n } else if (params.keyword.length === 0 && params.vector.length > 0) {\n vw = 1;\n tw = 0;\n }\n\n const merged = Array.from(byId.values()).map((entry) => {\n const score = vw * entry.vectorScore + tw * entry.textScore;\n return {\n path: entry.path,\n startLine: entry.startLine,\n endLine: entry.endLine,\n score,\n snippet: entry.snippet,\n source: entry.source,\n };\n });\n\n return merged.sort((a, b) => b.score - a.score);\n}\n","import type { DatabaseSync } from \"node:sqlite\";\n\nimport { cosineSimilarity, parseEmbedding, truncateUtf16Safe, vectorToBlob } from \"../internal.js\";\n\nexport type SearchSource = string;\n\nexport type SearchRowResult = {\n id: string;\n path: string;\n startLine: number;\n endLine: number;\n score: number;\n snippet: string;\n source: SearchSource;\n};\n\n/**\n * Options for filtering search results by knowledge metadata\n */\nexport type KnowledgeSearchOptions = {\n /** Filter to chunks matching any of these domains */\n domain?: string[];\n /** Filter to chunks referencing any of these entities */\n entities?: string[];\n /** Minimum confidence threshold */\n minConfidence?: number;\n /** Filter to a specific knowledge type */\n knowledgeType?: string;\n};\n\n/**\n * Build SQL WHERE clause fragments for knowledge filters.\n * Uses json_each() for array column filtering.\n */\nexport function buildKnowledgeFilterSql(opts: KnowledgeSearchOptions): {\n sql: string;\n params: (string | number)[];\n} {\n const clauses: string[] = [];\n const params: (string | number)[] = [];\n\n if (opts.knowledgeType) {\n clauses.push(` AND c.knowledge_type = ?`);\n params.push(opts.knowledgeType);\n }\n\n if (opts.minConfidence !== undefined) {\n clauses.push(` AND c.confidence >= ?`);\n params.push(opts.minConfidence);\n }\n\n if (opts.domain && opts.domain.length > 0) {\n // At least one of the provided domains must appear in the JSON array\n const domainPlaceholders = opts.domain.map(() => \"?\").join(\", \");\n clauses.push(\n ` AND EXISTS (SELECT 1 FROM json_each(c.domains) AS d WHERE d.value IN (${domainPlaceholders}))`,\n );\n params.push(...opts.domain);\n }\n\n if (opts.entities && opts.entities.length > 0) {\n const entityPlaceholders = opts.entities.map(() => \"?\").join(\", \");\n clauses.push(\n ` AND EXISTS (SELECT 1 FROM json_each(c.entities) AS e WHERE e.value IN (${entityPlaceholders}))`,\n );\n params.push(...opts.entities);\n }\n\n return { sql: clauses.join(\"\"), params };\n}\n\n/**\n * Perform a vector similarity search against indexed memory chunks.\n *\n * First attempts to use sqlite-vec for fast approximate nearest neighbor search.\n * Falls back to brute-force cosine similarity over all chunks if the vector\n * extension is unavailable.\n *\n * @returns Matching chunks sorted by descending similarity score (0-1 range).\n */\nexport async function searchVector(params: {\n db: DatabaseSync;\n vectorTable: string;\n providerModel: string;\n queryVec: number[];\n limit: number;\n snippetMaxChars: number;\n ensureVectorReady: (dimensions: number) => Promise<boolean>;\n sourceFilterVec: { sql: string; params: SearchSource[] };\n sourceFilterChunks: { sql: string; params: SearchSource[] };\n}): Promise<SearchRowResult[]> {\n if (params.queryVec.length === 0 || params.limit <= 0) return [];\n if (await params.ensureVectorReady(params.queryVec.length)) {\n const rows = params.db\n .prepare(\n `SELECT c.id, c.path, c.start_line, c.end_line, c.text,\\n` +\n ` c.source,\\n` +\n ` vec_distance_cosine(v.embedding, ?) AS dist\\n` +\n ` FROM ${params.vectorTable} v\\n` +\n ` JOIN chunks c ON c.id = v.id\\n` +\n ` WHERE c.model = ?${params.sourceFilterVec.sql}\\n` +\n ` ORDER BY dist ASC\\n` +\n ` LIMIT ?`,\n )\n .all(\n vectorToBlob(params.queryVec),\n params.providerModel,\n ...params.sourceFilterVec.params,\n params.limit,\n ) as Array<{\n id: string;\n path: string;\n start_line: number;\n end_line: number;\n text: string;\n source: SearchSource;\n dist: number;\n }>;\n return rows.map((row) => ({\n id: row.id,\n path: row.path,\n startLine: row.start_line,\n endLine: row.end_line,\n score: 1 - row.dist,\n snippet: truncateUtf16Safe(row.text, params.snippetMaxChars),\n source: row.source,\n }));\n }\n\n const candidates = listChunks({\n db: params.db,\n providerModel: params.providerModel,\n sourceFilter: params.sourceFilterChunks,\n });\n const scored = candidates\n .map((chunk) => ({\n chunk,\n score: cosineSimilarity(params.queryVec, chunk.embedding),\n }))\n .filter((entry) => Number.isFinite(entry.score));\n return scored\n .sort((a, b) => b.score - a.score)\n .slice(0, params.limit)\n .map((entry) => ({\n id: entry.chunk.id,\n path: entry.chunk.path,\n startLine: entry.chunk.startLine,\n endLine: entry.chunk.endLine,\n score: entry.score,\n snippet: truncateUtf16Safe(entry.chunk.text, params.snippetMaxChars),\n source: entry.chunk.source,\n }));\n}\n\n/**\n * List all indexed chunks for a given embedding model and source filter.\n * Used as a fallback when sqlite-vec is not available for vector search.\n *\n * @returns All matching chunks with their parsed embedding vectors.\n */\nexport function listChunks(params: {\n db: DatabaseSync;\n providerModel: string;\n sourceFilter: { sql: string; params: SearchSource[] };\n}): Array<{\n id: string;\n path: string;\n startLine: number;\n endLine: number;\n text: string;\n embedding: number[];\n source: SearchSource;\n}> {\n const rows = params.db\n .prepare(\n `SELECT id, path, start_line, end_line, text, embedding, source\\n` +\n ` FROM chunks\\n` +\n ` WHERE model = ?${params.sourceFilter.sql}`,\n )\n .all(params.providerModel, ...params.sourceFilter.params) as Array<{\n id: string;\n path: string;\n start_line: number;\n end_line: number;\n text: string;\n embedding: string;\n source: SearchSource;\n }>;\n\n return rows.map((row) => ({\n id: row.id,\n path: row.path,\n startLine: row.start_line,\n endLine: row.end_line,\n text: row.text,\n embedding: parseEmbedding(row.embedding),\n source: row.source,\n }));\n}\n\n/**\n * Perform a full-text keyword search using SQLite FTS5 with BM25 ranking.\n *\n * Tokenizes the query into quoted AND terms and runs them against the FTS index.\n * Results are scored using BM25 rank converted to a 0-1 range.\n *\n * @returns Matching chunks sorted by BM25 relevance, with both score and textScore fields.\n */\nexport async function searchKeyword(params: {\n db: DatabaseSync;\n ftsTable: string;\n providerModel: string;\n query: string;\n limit: number;\n snippetMaxChars: number;\n sourceFilter: { sql: string; params: SearchSource[] };\n buildFtsQuery: (raw: string) => string | null;\n bm25RankToScore: (rank: number) => number;\n}): Promise<Array<SearchRowResult & { textScore: number }>> {\n if (params.limit <= 0) return [];\n const ftsQuery = params.buildFtsQuery(params.query);\n if (!ftsQuery) return [];\n\n const rows = params.db\n .prepare(\n `SELECT id, path, source, start_line, end_line, text,\\n` +\n ` bm25(${params.ftsTable}) AS rank\\n` +\n ` FROM ${params.ftsTable}\\n` +\n ` WHERE ${params.ftsTable} MATCH ? AND model = ?${params.sourceFilter.sql}\\n` +\n ` ORDER BY rank ASC\\n` +\n ` LIMIT ?`,\n )\n .all(ftsQuery, params.providerModel, ...params.sourceFilter.params, params.limit) as Array<{\n id: string;\n path: string;\n source: SearchSource;\n start_line: number;\n end_line: number;\n text: string;\n rank: number;\n }>;\n\n return rows.map((row) => {\n const textScore = params.bm25RankToScore(row.rank);\n return {\n id: row.id,\n path: row.path,\n startLine: row.start_line,\n endLine: row.end_line,\n score: textScore,\n textScore,\n snippet: truncateUtf16Safe(row.text, params.snippetMaxChars),\n source: row.source,\n };\n });\n}\n","import type { DatabaseSync } from \"node:sqlite\";\n\n/**\n * Current schema version. Increment this when making breaking schema changes.\n *\n * Version history:\n * - 1: Initial schema (meta, files, chunks, embedding_cache, FTS5)\n * - 2: Added source column to files and chunks tables\n * - 3: Added type column to chunks table for observation type metadata\n * - 4: Added knowledge columns to chunks + knowledge_links table\n */\nexport const SCHEMA_VERSION = 4;\n\nexport function ensureMemoryIndexSchema(params: {\n db: DatabaseSync;\n embeddingCacheTable: string;\n ftsTable: string;\n ftsEnabled: boolean;\n}): { ftsAvailable: boolean; ftsError?: string; migrated?: boolean } {\n // Create meta table first (needed for version tracking)\n params.db.exec(`\n CREATE TABLE IF NOT EXISTS meta (\n key TEXT PRIMARY KEY,\n value TEXT NOT NULL\n );\n `);\n\n // Check schema version and handle migration\n const migrated = migrateIfNeeded(params.db, params.ftsTable);\n\n params.db.exec(`\n CREATE TABLE IF NOT EXISTS files (\n path TEXT PRIMARY KEY,\n source TEXT NOT NULL DEFAULT 'memory',\n hash TEXT NOT NULL,\n mtime INTEGER NOT NULL,\n size INTEGER NOT NULL\n );\n `);\n params.db.exec(`\n CREATE TABLE IF NOT EXISTS chunks (\n id TEXT PRIMARY KEY,\n path TEXT NOT NULL,\n source TEXT NOT NULL DEFAULT 'memory',\n start_line INTEGER NOT NULL,\n end_line INTEGER NOT NULL,\n hash TEXT NOT NULL,\n model TEXT NOT NULL,\n text TEXT NOT NULL,\n embedding TEXT NOT NULL,\n updated_at INTEGER NOT NULL\n );\n `);\n params.db.exec(`\n CREATE TABLE IF NOT EXISTS ${params.embeddingCacheTable} (\n provider TEXT NOT NULL,\n model TEXT NOT NULL,\n provider_key TEXT NOT NULL,\n hash TEXT NOT NULL,\n embedding TEXT NOT NULL,\n dims INTEGER,\n updated_at INTEGER NOT NULL,\n PRIMARY KEY (provider, model, provider_key, hash)\n );\n `);\n params.db.exec(\n `CREATE INDEX IF NOT EXISTS idx_embedding_cache_updated_at ON ${params.embeddingCacheTable}(updated_at);`,\n );\n\n let ftsAvailable = false;\n let ftsError: string | undefined;\n if (params.ftsEnabled) {\n try {\n params.db.exec(\n `CREATE VIRTUAL TABLE IF NOT EXISTS ${params.ftsTable} USING fts5(\\n` +\n ` text,\\n` +\n ` id UNINDEXED,\\n` +\n ` path UNINDEXED,\\n` +\n ` source UNINDEXED,\\n` +\n ` model UNINDEXED,\\n` +\n ` start_line UNINDEXED,\\n` +\n ` end_line UNINDEXED\\n` +\n `);`,\n );\n ftsAvailable = true;\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n ftsAvailable = false;\n ftsError = message;\n }\n }\n\n ensureColumn(params.db, \"files\", \"source\", \"TEXT NOT NULL DEFAULT 'memory'\");\n ensureColumn(params.db, \"chunks\", \"source\", \"TEXT NOT NULL DEFAULT 'memory'\");\n ensureColumn(params.db, \"chunks\", \"type\", \"TEXT\");\n ensureColumn(params.db, \"chunks\", \"knowledge_type\", \"TEXT\");\n ensureColumn(params.db, \"chunks\", \"knowledge_id\", \"TEXT\");\n ensureColumn(params.db, \"chunks\", \"domains\", \"TEXT\");\n ensureColumn(params.db, \"chunks\", \"entities\", \"TEXT\");\n ensureColumn(params.db, \"chunks\", \"confidence\", \"REAL\");\n params.db.exec(`CREATE INDEX IF NOT EXISTS idx_chunks_path ON chunks(path);`);\n params.db.exec(`CREATE INDEX IF NOT EXISTS idx_chunks_source ON chunks(source);`);\n params.db.exec(`CREATE INDEX IF NOT EXISTS idx_chunks_type ON chunks(type);`);\n params.db.exec(`CREATE INDEX IF NOT EXISTS idx_chunks_knowledge_type ON chunks(knowledge_type);`);\n params.db.exec(`CREATE INDEX IF NOT EXISTS idx_chunks_knowledge_id ON chunks(knowledge_id);`);\n\n // Knowledge links table for graph traversal\n params.db.exec(`\n CREATE TABLE IF NOT EXISTS knowledge_links (\n from_id TEXT NOT NULL,\n to_id TEXT NOT NULL,\n relation TEXT NOT NULL,\n layer TEXT,\n weight REAL DEFAULT 0.5,\n source_path TEXT,\n created_at INTEGER,\n PRIMARY KEY (from_id, to_id, relation)\n );\n `);\n params.db.exec(`CREATE INDEX IF NOT EXISTS idx_kl_from ON knowledge_links(from_id);`);\n params.db.exec(`CREATE INDEX IF NOT EXISTS idx_kl_to ON knowledge_links(to_id);`);\n params.db.exec(`CREATE INDEX IF NOT EXISTS idx_kl_layer ON knowledge_links(layer);`);\n\n // Store current schema version\n params.db.prepare(\n `INSERT OR REPLACE INTO meta (key, value) VALUES ('schema_version', ?)`,\n ).run(String(SCHEMA_VERSION));\n\n return { ftsAvailable, ...(ftsError ? { ftsError } : {}), ...(migrated ? { migrated } : {}) };\n}\n\n/**\n * Check the stored schema version and migrate if needed.\n * For breaking changes, drops data tables so they get recreated fresh.\n * The embedding cache is preserved across migrations when possible.\n *\n * @returns true if a migration was performed, false otherwise.\n */\nfunction migrateIfNeeded(db: DatabaseSync, ftsTable: string): boolean {\n let storedVersion = 0;\n try {\n const row = db.prepare(\n `SELECT value FROM meta WHERE key = 'schema_version'`,\n ).get() as { value: string } | undefined;\n if (row) {\n storedVersion = parseInt(row.value, 10) || 0;\n }\n } catch {\n // meta table may not have the key yet (pre-versioning databases)\n storedVersion = 0;\n }\n\n if (storedVersion >= SCHEMA_VERSION) return false;\n\n if (storedVersion > 0 && storedVersion < SCHEMA_VERSION) {\n // Breaking schema change: drop and recreate data tables.\n // Embedding cache is preserved since embeddings are content-addressed\n // and will be reused on re-index.\n db.exec(`DROP TABLE IF EXISTS files`);\n db.exec(`DROP TABLE IF EXISTS chunks`);\n db.exec(`DROP TABLE IF EXISTS knowledge_links`);\n db.exec(`DROP TABLE IF EXISTS ${ftsTable}`);\n // Also drop the vector table if it exists\n try {\n db.exec(`DROP TABLE IF EXISTS chunks_vec`);\n } catch {\n // sqlite-vec table may not exist\n }\n }\n\n return storedVersion > 0;\n}\n\nfunction ensureColumn(\n db: DatabaseSync,\n table: \"files\" | \"chunks\",\n column: string,\n definition: string,\n): void {\n const rows = db.prepare(`PRAGMA table_info(${table})`).all() as Array<{ name: string }>;\n if (rows.some((row) => row.name === column)) return;\n db.exec(`ALTER TABLE ${table} ADD COLUMN ${column} ${definition}`);\n}\n","import type { DatabaseSync } from \"node:sqlite\";\n\n/**\n * A knowledge graph link between two nodes\n */\nexport type GraphLink = {\n fromId: string;\n toId: string;\n relation: string;\n layer: string | null;\n weight: number;\n sourcePath: string | null;\n};\n\n/**\n * A neighbor node discovered during graph traversal\n */\nexport type GraphNeighbor = {\n id: string;\n depth: number;\n link: GraphLink;\n};\n\n/**\n * Get all outgoing links from a node.\n */\nexport function getLinksFrom(\n db: DatabaseSync,\n fromId: string,\n opts?: { relation?: string; layer?: string },\n): GraphLink[] {\n let sql = `SELECT from_id, to_id, relation, layer, weight, source_path FROM knowledge_links WHERE from_id = ?`;\n const params: (string | number)[] = [fromId];\n\n if (opts?.relation) {\n sql += ` AND relation = ?`;\n params.push(opts.relation);\n }\n if (opts?.layer) {\n sql += ` AND layer = ?`;\n params.push(opts.layer);\n }\n\n const rows = db.prepare(sql).all(...params) as Array<{\n from_id: string;\n to_id: string;\n relation: string;\n layer: string | null;\n weight: number;\n source_path: string | null;\n }>;\n\n return rows.map(toGraphLink);\n}\n\n/**\n * Get all incoming links to a node.\n */\nexport function getLinksTo(\n db: DatabaseSync,\n toId: string,\n opts?: { relation?: string; layer?: string },\n): GraphLink[] {\n let sql = `SELECT from_id, to_id, relation, layer, weight, source_path FROM knowledge_links WHERE to_id = ?`;\n const params: (string | number)[] = [toId];\n\n if (opts?.relation) {\n sql += ` AND relation = ?`;\n params.push(opts.relation);\n }\n if (opts?.layer) {\n sql += ` AND layer = ?`;\n params.push(opts.layer);\n }\n\n const rows = db.prepare(sql).all(...params) as Array<{\n from_id: string;\n to_id: string;\n relation: string;\n layer: string | null;\n weight: number;\n source_path: string | null;\n }>;\n\n return rows.map(toGraphLink);\n}\n\n/**\n * BFS traversal to find neighbors up to a given depth.\n *\n * @param db - Database handle\n * @param startId - The starting node ID\n * @param depth - Maximum traversal depth (default: 1)\n * @param opts - Optional filters for relation and layer\n * @returns Array of neighbor nodes with their depth and connecting link\n */\nexport function getNeighbors(\n db: DatabaseSync,\n startId: string,\n depth: number = 1,\n opts?: { relation?: string; layer?: string },\n): GraphNeighbor[] {\n const visited = new Set<string>([startId]);\n const result: GraphNeighbor[] = [];\n let frontier = [startId];\n\n for (let d = 1; d <= depth; d++) {\n const nextFrontier: string[] = [];\n\n for (const nodeId of frontier) {\n // Follow outgoing links\n const outgoing = getLinksFrom(db, nodeId, opts);\n for (const link of outgoing) {\n if (!visited.has(link.toId)) {\n visited.add(link.toId);\n nextFrontier.push(link.toId);\n result.push({ id: link.toId, depth: d, link });\n }\n }\n\n // Follow incoming links\n const incoming = getLinksTo(db, nodeId, opts);\n for (const link of incoming) {\n if (!visited.has(link.fromId)) {\n visited.add(link.fromId);\n nextFrontier.push(link.fromId);\n result.push({ id: link.fromId, depth: d, link });\n }\n }\n }\n\n frontier = nextFrontier;\n if (frontier.length === 0) break;\n }\n\n return result;\n}\n\n/**\n * BFS shortest path between two nodes, max depth 3.\n *\n * @returns Array of links forming the path, or empty if no path found.\n */\nexport function getPathBetween(\n db: DatabaseSync,\n fromId: string,\n toId: string,\n maxDepth: number = 3,\n): GraphLink[] {\n if (fromId === toId) return [];\n\n // BFS with parent tracking\n const visited = new Set<string>([fromId]);\n // Maps each visited node to the link that discovered it\n const parentLink = new Map<string, GraphLink>();\n let frontier = [fromId];\n\n for (let d = 0; d < maxDepth; d++) {\n const nextFrontier: string[] = [];\n\n for (const nodeId of frontier) {\n // Follow outgoing links\n const outgoing = getLinksFrom(db, nodeId);\n for (const link of outgoing) {\n if (!visited.has(link.toId)) {\n visited.add(link.toId);\n parentLink.set(link.toId, link);\n if (link.toId === toId) {\n return reconstructPath(parentLink, fromId, toId);\n }\n nextFrontier.push(link.toId);\n }\n }\n\n // Follow incoming links\n const incoming = getLinksTo(db, nodeId);\n for (const link of incoming) {\n if (!visited.has(link.fromId)) {\n visited.add(link.fromId);\n parentLink.set(link.fromId, link);\n if (link.fromId === toId) {\n return reconstructPath(parentLink, fromId, toId);\n }\n nextFrontier.push(link.fromId);\n }\n }\n }\n\n frontier = nextFrontier;\n if (frontier.length === 0) break;\n }\n\n return []; // No path found\n}\n\n/**\n * Reconstruct the path from BFS parent map.\n */\nfunction reconstructPath(\n parentLink: Map<string, GraphLink>,\n fromId: string,\n toId: string,\n): GraphLink[] {\n const path: GraphLink[] = [];\n let current = toId;\n\n while (current !== fromId) {\n const link = parentLink.get(current);\n if (!link) break;\n path.unshift(link);\n // Determine which side led to `current`\n current = link.toId === current ? link.fromId : link.toId;\n }\n\n return path;\n}\n\nfunction toGraphLink(row: {\n from_id: string;\n to_id: string;\n relation: string;\n layer: string | null;\n weight: number;\n source_path: string | null;\n}): GraphLink {\n return {\n fromId: row.from_id,\n toId: row.to_id,\n relation: row.relation,\n layer: row.layer,\n weight: row.weight,\n sourcePath: row.source_path,\n };\n}\n","import type { DatabaseSync } from \"node:sqlite\";\n\nexport async function loadSqliteVecExtension(params: {\n db: DatabaseSync;\n extensionPath?: string;\n}): Promise<{ ok: boolean; extensionPath?: string; error?: string }> {\n try {\n const sqliteVec = await import(\"sqlite-vec\");\n const resolvedPath = params.extensionPath?.trim() ? params.extensionPath.trim() : undefined;\n const extensionPath = resolvedPath ?? sqliteVec.getLoadablePath();\n\n params.db.enableLoadExtension(true);\n if (resolvedPath) {\n params.db.loadExtension(extensionPath);\n } else {\n sqliteVec.load(params.db);\n }\n\n return { ok: true, extensionPath };\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n return { ok: false, error: message };\n }\n}\n","import fsSync from \"node:fs\";\nimport path from \"node:path\";\nimport os from \"node:os\";\n\nimport type { Llama, LlamaEmbeddingContext, LlamaModel } from \"node-llama-cpp\";\n\nexport type EmbeddingProvider = {\n id: string;\n model: string;\n embedQuery: (text: string) => Promise<number[]>;\n embedBatch: (texts: string[]) => Promise<number[][]>;\n};\n\nexport type EmbeddingProviderResult = {\n provider: EmbeddingProvider;\n requestedProvider: \"openai\" | \"local\" | \"gemini\" | \"auto\" | \"none\";\n fallbackFrom?: \"openai\" | \"local\" | \"gemini\" | \"auto\";\n fallbackReason?: string;\n openAi?: OpenAiEmbeddingClient;\n gemini?: GeminiEmbeddingClient;\n};\n\nexport type EmbeddingProviderOptions = {\n provider: \"openai\" | \"local\" | \"gemini\" | \"auto\" | \"none\";\n model?: string;\n fallback?: \"openai\" | \"gemini\" | \"local\" | \"none\";\n openai?: {\n apiKey?: string;\n baseUrl?: string;\n headers?: Record<string, string>;\n };\n gemini?: {\n apiKey?: string;\n baseUrl?: string;\n headers?: Record<string, string>;\n };\n local?: {\n modelPath?: string;\n modelCacheDir?: string;\n };\n};\n\nexport type OpenAiEmbeddingClient = {\n baseUrl: string;\n headers: Record<string, string>;\n model: string;\n};\n\nexport type GeminiEmbeddingClient = {\n baseUrl: string;\n headers: Record<string, string>;\n model: string;\n modelPath: string;\n};\n\nconst DEFAULT_LOCAL_MODEL = \"hf:ggml-org/embeddinggemma-300M-GGUF/embeddinggemma-300M-Q8_0.gguf\";\nconst DEFAULT_OPENAI_EMBEDDING_MODEL = \"text-embedding-3-small\";\nconst DEFAULT_OPENAI_BASE_URL = \"https://api.openai.com/v1\";\nconst DEFAULT_GEMINI_EMBEDDING_MODEL = \"gemini-embedding-001\";\nconst DEFAULT_GEMINI_BASE_URL = \"https://generativelanguage.googleapis.com/v1beta\";\n\n/**\n * Creates a no-op embedding provider that returns empty vectors.\n * Used for BM25-only mode when no embedding API is available.\n */\nfunction createNoOpEmbeddingProvider(): EmbeddingProvider {\n return {\n id: \"none\",\n model: \"bm25-only\",\n embedQuery: async () => [],\n embedBatch: async (texts) => texts.map(() => []),\n };\n}\n\nfunction resolveUserPath(filePath: string): string {\n if (filePath.startsWith(\"~/\")) {\n return path.join(os.homedir(), filePath.slice(2));\n }\n return filePath;\n}\n\nfunction canAutoSelectLocal(options: EmbeddingProviderOptions): boolean {\n const modelPath = options.local?.modelPath?.trim();\n if (!modelPath) return false;\n if (/^(hf:|https?:)/i.test(modelPath)) return false;\n const resolved = resolveUserPath(modelPath);\n try {\n return fsSync.statSync(resolved).isFile();\n } catch {\n return false;\n }\n}\n\nfunction isMissingApiKeyError(err: unknown): boolean {\n const message = formatError(err);\n return message.includes(\"API key\") || message.includes(\"apiKey\");\n}\n\nasync function importNodeLlamaCpp() {\n const llama = await import(\"node-llama-cpp\");\n return llama;\n}\n\nasync function createLocalEmbeddingProvider(\n options: EmbeddingProviderOptions,\n): Promise<EmbeddingProvider> {\n const modelPath = options.local?.modelPath?.trim() || DEFAULT_LOCAL_MODEL;\n const modelCacheDir = options.local?.modelCacheDir?.trim();\n\n const { getLlama, resolveModelFile, LlamaLogLevel } = await importNodeLlamaCpp();\n\n let llama: Llama | null = null;\n let embeddingModel: LlamaModel | null = null;\n let embeddingContext: LlamaEmbeddingContext | null = null;\n\n const ensureContext = async () => {\n if (!llama) {\n llama = await getLlama({ logLevel: LlamaLogLevel.error });\n }\n if (!embeddingModel) {\n const resolved = await resolveModelFile(modelPath, modelCacheDir || undefined);\n embeddingModel = await llama.loadModel({ modelPath: resolved });\n }\n if (!embeddingContext) {\n embeddingContext = await embeddingModel.createEmbeddingContext();\n }\n return embeddingContext;\n };\n\n return {\n id: \"local\",\n model: modelPath,\n embedQuery: async (text) => {\n const ctx = await ensureContext();\n const embedding = await ctx.getEmbeddingFor(text);\n return Array.from(embedding.vector) as number[];\n },\n embedBatch: async (texts) => {\n const ctx = await ensureContext();\n const embeddings = await Promise.all(\n texts.map(async (text) => {\n const embedding = await ctx.getEmbeddingFor(text);\n return Array.from(embedding.vector) as number[];\n }),\n );\n return embeddings;\n },\n };\n}\n\nfunction normalizeOpenAiModel(model: string): string {\n const trimmed = model.trim();\n if (!trimmed) return DEFAULT_OPENAI_EMBEDDING_MODEL;\n if (trimmed.startsWith(\"openai/\")) return trimmed.slice(\"openai/\".length);\n return trimmed;\n}\n\nfunction resolveOpenAiApiKey(options: EmbeddingProviderOptions): string {\n const apiKey = options.openai?.apiKey?.trim();\n if (apiKey) return apiKey;\n const envKey = process.env.OPENAI_API_KEY?.trim();\n if (envKey) return envKey;\n throw new Error(\"OpenAI API key not found. Set OPENAI_API_KEY env var or pass openai.apiKey option.\");\n}\n\nexport async function createOpenAiEmbeddingProvider(\n options: EmbeddingProviderOptions,\n): Promise<{ provider: EmbeddingProvider; client: OpenAiEmbeddingClient }> {\n const apiKey = resolveOpenAiApiKey(options);\n const baseUrl = options.openai?.baseUrl?.trim() || DEFAULT_OPENAI_BASE_URL;\n const headerOverrides = options.openai?.headers ?? {};\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${apiKey}`,\n ...headerOverrides,\n };\n const model = normalizeOpenAiModel(options.model || \"\");\n const client: OpenAiEmbeddingClient = { baseUrl, headers, model };\n const url = `${baseUrl.replace(/\\/$/, \"\")}/embeddings`;\n\n const embed = async (input: string[]): Promise<number[][]> => {\n if (input.length === 0) return [];\n const res = await fetch(url, {\n method: \"POST\",\n headers: client.headers,\n body: JSON.stringify({ model: client.model, input }),\n });\n if (!res.ok) {\n const text = await res.text();\n throw new Error(`openai embeddings failed: ${res.status} ${text}`);\n }\n const payload = (await res.json()) as {\n data?: Array<{ embedding?: number[] }>;\n };\n const data = payload.data ?? [];\n return data.map((entry) => entry.embedding ?? []);\n };\n\n return {\n provider: {\n id: \"openai\",\n model: client.model,\n embedQuery: async (text) => {\n const [vec] = await embed([text]);\n return vec ?? [];\n },\n embedBatch: embed,\n },\n client,\n };\n}\n\nfunction normalizeGeminiModel(model: string): string {\n const trimmed = model.trim();\n if (!trimmed) return DEFAULT_GEMINI_EMBEDDING_MODEL;\n const withoutPrefix = trimmed.replace(/^models\\//, \"\");\n if (withoutPrefix.startsWith(\"gemini/\")) return withoutPrefix.slice(\"gemini/\".length);\n if (withoutPrefix.startsWith(\"google/\")) return withoutPrefix.slice(\"google/\".length);\n return withoutPrefix;\n}\n\nfunction normalizeGeminiBaseUrl(raw: string): string {\n const trimmed = raw.replace(/\\/+$/, \"\");\n const openAiIndex = trimmed.indexOf(\"/openai\");\n if (openAiIndex > -1) return trimmed.slice(0, openAiIndex);\n return trimmed;\n}\n\nfunction buildGeminiModelPath(model: string): string {\n return model.startsWith(\"models/\") ? model : `models/${model}`;\n}\n\nfunction resolveGeminiApiKey(options: EmbeddingProviderOptions): string {\n const apiKey = options.gemini?.apiKey?.trim();\n if (apiKey) return apiKey;\n const googleKey = process.env.GOOGLE_API_KEY?.trim();\n if (googleKey) return googleKey;\n const geminiKey = process.env.GEMINI_API_KEY?.trim();\n if (geminiKey) return geminiKey;\n throw new Error(\"Gemini API key not found. Set GOOGLE_API_KEY or GEMINI_API_KEY env var or pass gemini.apiKey option.\");\n}\n\nexport async function createGeminiEmbeddingProvider(\n options: EmbeddingProviderOptions,\n): Promise<{ provider: EmbeddingProvider; client: GeminiEmbeddingClient }> {\n const apiKey = resolveGeminiApiKey(options);\n const rawBaseUrl = options.gemini?.baseUrl?.trim() || DEFAULT_GEMINI_BASE_URL;\n const baseUrl = normalizeGeminiBaseUrl(rawBaseUrl);\n const headerOverrides = options.gemini?.headers ?? {};\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n \"x-goog-api-key\": apiKey,\n ...headerOverrides,\n };\n const model = normalizeGeminiModel(options.model || \"\");\n const modelPath = buildGeminiModelPath(model);\n const client: GeminiEmbeddingClient = { baseUrl, headers, model, modelPath };\n\n const embedUrl = `${baseUrl}/${modelPath}:embedContent`;\n const batchUrl = `${baseUrl}/${modelPath}:batchEmbedContents`;\n\n const embedQuery = async (text: string): Promise<number[]> => {\n if (!text.trim()) return [];\n const res = await fetch(embedUrl, {\n method: \"POST\",\n headers: client.headers,\n body: JSON.stringify({\n content: { parts: [{ text }] },\n taskType: \"RETRIEVAL_QUERY\",\n }),\n });\n if (!res.ok) {\n const payload = await res.text();\n throw new Error(`gemini embeddings failed: ${res.status} ${payload}`);\n }\n const payload = (await res.json()) as { embedding?: { values?: number[] } };\n return payload.embedding?.values ?? [];\n };\n\n const embedBatch = async (texts: string[]): Promise<number[][]> => {\n if (texts.length === 0) return [];\n const requests = texts.map((text) => ({\n model: modelPath,\n content: { parts: [{ text }] },\n taskType: \"RETRIEVAL_DOCUMENT\",\n }));\n const res = await fetch(batchUrl, {\n method: \"POST\",\n headers: client.headers,\n body: JSON.stringify({ requests }),\n });\n if (!res.ok) {\n const payload = await res.text();\n throw new Error(`gemini embeddings failed: ${res.status} ${payload}`);\n }\n const payload = (await res.json()) as { embeddings?: Array<{ values?: number[] }> };\n const embeddings = Array.isArray(payload.embeddings) ? payload.embeddings : [];\n return texts.map((_, index) => embeddings[index]?.values ?? []);\n };\n\n return {\n provider: {\n id: \"gemini\",\n model: client.model,\n embedQuery,\n embedBatch,\n },\n client,\n };\n}\n\nexport async function createEmbeddingProvider(\n options: EmbeddingProviderOptions,\n): Promise<EmbeddingProviderResult> {\n const requestedProvider = options.provider;\n const fallback = options.fallback ?? \"none\";\n\n // Handle explicit \"none\" provider (BM25-only mode)\n if (requestedProvider === \"none\") {\n return {\n provider: createNoOpEmbeddingProvider(),\n requestedProvider: \"none\",\n };\n }\n\n const createProvider = async (id: \"openai\" | \"local\" | \"gemini\") => {\n if (id === \"local\") {\n const provider = await createLocalEmbeddingProvider(options);\n return { provider };\n }\n if (id === \"gemini\") {\n const { provider, client } = await createGeminiEmbeddingProvider(options);\n return { provider, gemini: client };\n }\n const { provider, client } = await createOpenAiEmbeddingProvider(options);\n return { provider, openAi: client };\n };\n\n const formatPrimaryError = (err: unknown, provider: \"openai\" | \"local\" | \"gemini\") =>\n provider === \"local\" ? formatLocalSetupError(err) : formatError(err);\n\n if (requestedProvider === \"auto\") {\n const missingKeyErrors: string[] = [];\n let localError: string | null = null;\n\n if (canAutoSelectLocal(options)) {\n try {\n const local = await createProvider(\"local\");\n return { ...local, requestedProvider };\n } catch (err) {\n localError = formatLocalSetupError(err);\n }\n }\n\n for (const provider of [\"openai\", \"gemini\"] as const) {\n try {\n const result = await createProvider(provider);\n return { ...result, requestedProvider };\n } catch (err) {\n const message = formatPrimaryError(err, provider);\n if (isMissingApiKeyError(err)) {\n missingKeyErrors.push(message);\n continue;\n }\n throw new Error(message);\n }\n }\n\n // Fall back to BM25-only mode instead of throwing\n // This allows the system to work without any API keys using full-text search only\n return {\n provider: createNoOpEmbeddingProvider(),\n requestedProvider,\n fallbackFrom: \"auto\",\n fallbackReason: \"No embedding API available. Using BM25 full-text search only.\",\n };\n }\n\n try {\n const primary = await createProvider(requestedProvider);\n return { ...primary, requestedProvider };\n } catch (primaryErr) {\n const reason = formatPrimaryError(primaryErr, requestedProvider);\n if (fallback && fallback !== \"none\" && fallback !== requestedProvider) {\n try {\n const fallbackResult = await createProvider(fallback);\n return {\n ...fallbackResult,\n requestedProvider,\n fallbackFrom: requestedProvider,\n fallbackReason: reason,\n };\n } catch (fallbackErr) {\n throw new Error(`${reason}\\n\\nFallback to ${fallback} failed: ${formatError(fallbackErr)}`);\n }\n }\n throw new Error(reason);\n }\n}\n\nfunction formatError(err: unknown): string {\n if (err instanceof Error) return err.message;\n return String(err);\n}\n\nfunction isNodeLlamaCppMissing(err: unknown): boolean {\n if (!(err instanceof Error)) return false;\n const code = (err as Error & { code?: unknown }).code;\n if (code === \"ERR_MODULE_NOT_FOUND\") {\n return err.message.includes(\"node-llama-cpp\");\n }\n return false;\n}\n\nfunction formatLocalSetupError(err: unknown): string {\n const detail = formatError(err);\n const missing = isNodeLlamaCppMissing(err);\n return [\n \"Local embeddings unavailable.\",\n missing\n ? \"Reason: optional dependency node-llama-cpp is missing (or failed to install).\"\n : detail\n ? `Reason: ${detail}`\n : undefined,\n missing && detail ? `Detail: ${detail}` : null,\n \"To enable local embeddings:\",\n \"1) Use Node 22 LTS (recommended for installs/updates)\",\n missing ? \"2) Install node-llama-cpp: npm install node-llama-cpp\" : null,\n \"3) If you use pnpm: pnpm approve-builds (select node-llama-cpp), then pnpm rebuild node-llama-cpp\",\n 'Or set provider = \"openai\" or \"gemini\" (remote).',\n ]\n .filter(Boolean)\n .join(\"\\n\");\n}\n","import type { OpenAiEmbeddingClient } from \"./embeddings.js\";\nimport { hashText } from \"../internal.js\";\n\nexport type OpenAiBatchRequest = {\n custom_id: string;\n method: \"POST\";\n url: \"/v1/embeddings\";\n body: {\n model: string;\n input: string;\n };\n};\n\nexport type OpenAiBatchStatus = {\n id?: string;\n status?: string;\n output_file_id?: string | null;\n error_file_id?: string | null;\n};\n\nexport type OpenAiBatchOutputLine = {\n custom_id?: string;\n response?: {\n status_code?: number;\n body?: {\n data?: Array<{ embedding?: number[]; index?: number }>;\n error?: { message?: string };\n };\n };\n error?: { message?: string };\n};\n\nexport const OPENAI_BATCH_ENDPOINT = \"/v1/embeddings\";\nconst OPENAI_BATCH_COMPLETION_WINDOW = \"24h\";\nconst OPENAI_BATCH_MAX_REQUESTS = 50000;\n\nfunction getOpenAiBaseUrl(openAi: OpenAiEmbeddingClient): string {\n return openAi.baseUrl?.replace(/\\/$/, \"\") ?? \"\";\n}\n\nfunction getOpenAiHeaders(\n openAi: OpenAiEmbeddingClient,\n params: { json: boolean },\n): Record<string, string> {\n const headers = openAi.headers ? { ...openAi.headers } : {};\n if (params.json) {\n if (!headers[\"Content-Type\"] && !headers[\"content-type\"]) {\n headers[\"Content-Type\"] = \"application/json\";\n }\n } else {\n delete headers[\"Content-Type\"];\n delete headers[\"content-type\"];\n }\n return headers;\n}\n\nfunction splitOpenAiBatchRequests(requests: OpenAiBatchRequest[]): OpenAiBatchRequest[][] {\n if (requests.length <= OPENAI_BATCH_MAX_REQUESTS) return [requests];\n const groups: OpenAiBatchRequest[][] = [];\n for (let i = 0; i < requests.length; i += OPENAI_BATCH_MAX_REQUESTS) {\n groups.push(requests.slice(i, i + OPENAI_BATCH_MAX_REQUESTS));\n }\n return groups;\n}\n\nasync function retryAsync<T>(\n fn: () => Promise<T>,\n opts: {\n attempts: number;\n minDelayMs: number;\n maxDelayMs: number;\n jitter: number;\n shouldRetry: (err: unknown) => boolean;\n },\n): Promise<T> {\n let lastError: unknown;\n for (let attempt = 0; attempt < opts.attempts; attempt++) {\n try {\n return await fn();\n } catch (err) {\n lastError = err;\n if (!opts.shouldRetry(err) || attempt === opts.attempts - 1) {\n throw err;\n }\n const delay = Math.min(\n opts.maxDelayMs,\n opts.minDelayMs * Math.pow(2, attempt) * (1 + Math.random() * opts.jitter),\n );\n await new Promise((resolve) => setTimeout(resolve, delay));\n }\n }\n throw lastError;\n}\n\nasync function submitOpenAiBatch(params: {\n openAi: OpenAiEmbeddingClient;\n requests: OpenAiBatchRequest[];\n source: string;\n}): Promise<OpenAiBatchStatus> {\n const baseUrl = getOpenAiBaseUrl(params.openAi);\n const jsonl = params.requests.map((request) => JSON.stringify(request)).join(\"\\n\");\n const form = new FormData();\n form.append(\"purpose\", \"batch\");\n form.append(\n \"file\",\n new Blob([jsonl], { type: \"application/jsonl\" }),\n `memory-embeddings.${hashText(String(Date.now()))}.jsonl`,\n );\n\n const fileRes = await fetch(`${baseUrl}/files`, {\n method: \"POST\",\n headers: getOpenAiHeaders(params.openAi, { json: false }),\n body: form,\n });\n if (!fileRes.ok) {\n const text = await fileRes.text();\n throw new Error(`openai batch file upload failed: ${fileRes.status} ${text}`);\n }\n const filePayload = (await fileRes.json()) as { id?: string };\n if (!filePayload.id) {\n throw new Error(\"openai batch file upload failed: missing file id\");\n }\n\n const batchRes = await retryAsync(\n async () => {\n const res = await fetch(`${baseUrl}/batches`, {\n method: \"POST\",\n headers: getOpenAiHeaders(params.openAi, { json: true }),\n body: JSON.stringify({\n input_file_id: filePayload.id,\n endpoint: OPENAI_BATCH_ENDPOINT,\n completion_window: OPENAI_BATCH_COMPLETION_WINDOW,\n metadata: {\n source: params.source,\n },\n }),\n });\n if (!res.ok) {\n const text = await res.text();\n const err = new Error(`openai batch create failed: ${res.status} ${text}`) as Error & {\n status?: number;\n };\n err.status = res.status;\n throw err;\n }\n return res;\n },\n {\n attempts: 3,\n minDelayMs: 300,\n maxDelayMs: 2000,\n jitter: 0.2,\n shouldRetry: (err) => {\n const status = (err as { status?: number }).status;\n return status === 429 || (typeof status === \"number\" && status >= 500);\n },\n },\n );\n return (await batchRes.json()) as OpenAiBatchStatus;\n}\n\nasync function fetchOpenAiBatchStatus(params: {\n openAi: OpenAiEmbeddingClient;\n batchId: string;\n}): Promise<OpenAiBatchStatus> {\n const baseUrl = getOpenAiBaseUrl(params.openAi);\n const res = await fetch(`${baseUrl}/batches/${params.batchId}`, {\n headers: getOpenAiHeaders(params.openAi, { json: true }),\n });\n if (!res.ok) {\n const text = await res.text();\n throw new Error(`openai batch status failed: ${res.status} ${text}`);\n }\n return (await res.json()) as OpenAiBatchStatus;\n}\n\nasync function fetchOpenAiFileContent(params: {\n openAi: OpenAiEmbeddingClient;\n fileId: string;\n}): Promise<string> {\n const baseUrl = getOpenAiBaseUrl(params.openAi);\n const res = await fetch(`${baseUrl}/files/${params.fileId}/content`, {\n headers: getOpenAiHeaders(params.openAi, { json: true }),\n });\n if (!res.ok) {\n const text = await res.text();\n throw new Error(`openai batch file content failed: ${res.status} ${text}`);\n }\n return await res.text();\n}\n\nfunction parseOpenAiBatchOutput(text: string): OpenAiBatchOutputLine[] {\n if (!text.trim()) return [];\n return text\n .split(\"\\n\")\n .map((line) => line.trim())\n .filter(Boolean)\n .map((line) => JSON.parse(line) as OpenAiBatchOutputLine);\n}\n\nasync function readOpenAiBatchError(params: {\n openAi: OpenAiEmbeddingClient;\n errorFileId: string;\n}): Promise<string | undefined> {\n try {\n const content = await fetchOpenAiFileContent({\n openAi: params.openAi,\n fileId: params.errorFileId,\n });\n const lines = parseOpenAiBatchOutput(content);\n const first = lines.find((line) => line.error?.message || line.response?.body?.error);\n const message =\n first?.error?.message ??\n (typeof first?.response?.body?.error?.message === \"string\"\n ? first?.response?.body?.error?.message\n : undefined);\n return message;\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n return message ? `error file unavailable: ${message}` : undefined;\n }\n}\n\nasync function waitForOpenAiBatch(params: {\n openAi: OpenAiEmbeddingClient;\n batchId: string;\n wait: boolean;\n pollIntervalMs: number;\n timeoutMs: number;\n debug?: (message: string, data?: Record<string, unknown>) => void;\n initial?: OpenAiBatchStatus;\n}): Promise<{ outputFileId: string; errorFileId?: string }> {\n const start = Date.now();\n let current: OpenAiBatchStatus | undefined = params.initial;\n while (true) {\n const status =\n current ??\n (await fetchOpenAiBatchStatus({\n openAi: params.openAi,\n batchId: params.batchId,\n }));\n const state = status.status ?? \"unknown\";\n if (state === \"completed\") {\n if (!status.output_file_id) {\n throw new Error(`openai batch ${params.batchId} completed without output file`);\n }\n return {\n outputFileId: status.output_file_id,\n errorFileId: status.error_file_id ?? undefined,\n };\n }\n if ([\"failed\", \"expired\", \"cancelled\", \"canceled\"].includes(state)) {\n const detail = status.error_file_id\n ? await readOpenAiBatchError({ openAi: params.openAi, errorFileId: status.error_file_id })\n : undefined;\n const suffix = detail ? `: ${detail}` : \"\";\n throw new Error(`openai batch ${params.batchId} ${state}${suffix}`);\n }\n if (!params.wait) {\n throw new Error(`openai batch ${params.batchId} still ${state}; wait disabled`);\n }\n if (Date.now() - start > params.timeoutMs) {\n throw new Error(`openai batch ${params.batchId} timed out after ${params.timeoutMs}ms`);\n }\n params.debug?.(`openai batch ${params.batchId} ${state}; waiting ${params.pollIntervalMs}ms`);\n await new Promise((resolve) => setTimeout(resolve, params.pollIntervalMs));\n current = undefined;\n }\n}\n\nasync function runWithConcurrency<T>(tasks: Array<() => Promise<T>>, limit: number): Promise<T[]> {\n if (tasks.length === 0) return [];\n const resolvedLimit = Math.max(1, Math.min(limit, tasks.length));\n const results: T[] = Array.from({ length: tasks.length });\n let next = 0;\n let firstError: unknown = null;\n\n const workers = Array.from({ length: resolvedLimit }, async () => {\n while (true) {\n if (firstError) return;\n const index = next;\n next += 1;\n if (index >= tasks.length) return;\n try {\n results[index] = await tasks[index]();\n } catch (err) {\n firstError = err;\n return;\n }\n }\n });\n\n await Promise.allSettled(workers);\n if (firstError) throw firstError;\n return results;\n}\n\nexport async function runOpenAiEmbeddingBatches(params: {\n openAi: OpenAiEmbeddingClient;\n source: string;\n requests: OpenAiBatchRequest[];\n wait: boolean;\n pollIntervalMs: number;\n timeoutMs: number;\n concurrency: number;\n debug?: (message: string, data?: Record<string, unknown>) => void;\n}): Promise<Map<string, number[]>> {\n if (params.requests.length === 0) return new Map();\n const groups = splitOpenAiBatchRequests(params.requests);\n const byCustomId = new Map<string, number[]>();\n\n const tasks = groups.map((group, groupIndex) => async () => {\n const batchInfo = await submitOpenAiBatch({\n openAi: params.openAi,\n requests: group,\n source: params.source,\n });\n if (!batchInfo.id) {\n throw new Error(\"openai batch create failed: missing batch id\");\n }\n\n params.debug?.(\"memory embeddings: openai batch created\", {\n batchId: batchInfo.id,\n status: batchInfo.status,\n group: groupIndex + 1,\n groups: groups.length,\n requests: group.length,\n });\n\n if (!params.wait && batchInfo.status !== \"completed\") {\n throw new Error(\n `openai batch ${batchInfo.id} submitted; enable batch.wait to await completion`,\n );\n }\n\n const completed =\n batchInfo.status === \"completed\"\n ? {\n outputFileId: batchInfo.output_file_id ?? \"\",\n errorFileId: batchInfo.error_file_id ?? undefined,\n }\n : await waitForOpenAiBatch({\n openAi: params.openAi,\n batchId: batchInfo.id,\n wait: params.wait,\n pollIntervalMs: params.pollIntervalMs,\n timeoutMs: params.timeoutMs,\n debug: params.debug,\n initial: batchInfo,\n });\n if (!completed.outputFileId) {\n throw new Error(`openai batch ${batchInfo.id} completed without output file`);\n }\n\n const content = await fetchOpenAiFileContent({\n openAi: params.openAi,\n fileId: completed.outputFileId,\n });\n const outputLines = parseOpenAiBatchOutput(content);\n const errors: string[] = [];\n const remaining = new Set(group.map((request) => request.custom_id));\n\n for (const line of outputLines) {\n const customId = line.custom_id;\n if (!customId) continue;\n remaining.delete(customId);\n if (line.error?.message) {\n errors.push(`${customId}: ${line.error.message}`);\n continue;\n }\n const response = line.response;\n const statusCode = response?.status_code ?? 0;\n if (statusCode >= 400) {\n const message =\n response?.body?.error?.message ??\n (typeof response?.body === \"string\" ? response.body : undefined) ??\n \"unknown error\";\n errors.push(`${customId}: ${message}`);\n continue;\n }\n const data = response?.body?.data ?? [];\n const embedding = data[0]?.embedding ?? [];\n if (embedding.length === 0) {\n errors.push(`${customId}: empty embedding`);\n continue;\n }\n byCustomId.set(customId, embedding);\n }\n\n if (errors.length > 0) {\n throw new Error(`openai batch ${batchInfo.id} failed: ${errors.join(\"; \")}`);\n }\n if (remaining.size > 0) {\n throw new Error(`openai batch ${batchInfo.id} missing ${remaining.size} embedding responses`);\n }\n });\n\n params.debug?.(\"memory embeddings: openai batch submit\", {\n requests: params.requests.length,\n groups: groups.length,\n wait: params.wait,\n concurrency: params.concurrency,\n pollIntervalMs: params.pollIntervalMs,\n timeoutMs: params.timeoutMs,\n });\n\n await runWithConcurrency(tasks, params.concurrency);\n return byCustomId;\n}\n","import type { GeminiEmbeddingClient } from \"./embeddings.js\";\nimport { hashText } from \"../internal.js\";\n\nexport type GeminiBatchRequest = {\n custom_id: string;\n content: { parts: Array<{ text: string }> };\n taskType: \"RETRIEVAL_DOCUMENT\" | \"RETRIEVAL_QUERY\";\n};\n\nexport type GeminiBatchStatus = {\n name?: string;\n state?: string;\n outputConfig?: { file?: string; fileId?: string };\n metadata?: {\n output?: {\n responsesFile?: string;\n };\n };\n error?: { message?: string };\n};\n\nexport type GeminiBatchOutputLine = {\n key?: string;\n custom_id?: string;\n request_id?: string;\n embedding?: { values?: number[] };\n response?: {\n embedding?: { values?: number[] };\n error?: { message?: string };\n };\n error?: { message?: string };\n};\n\nconst GEMINI_BATCH_MAX_REQUESTS = 50000;\n\nfunction getGeminiBaseUrl(gemini: GeminiEmbeddingClient): string {\n return gemini.baseUrl?.replace(/\\/$/, \"\") ?? \"\";\n}\n\nfunction getGeminiHeaders(\n gemini: GeminiEmbeddingClient,\n params: { json: boolean },\n): Record<string, string> {\n const headers = gemini.headers ? { ...gemini.headers } : {};\n if (params.json) {\n if (!headers[\"Content-Type\"] && !headers[\"content-type\"]) {\n headers[\"Content-Type\"] = \"application/json\";\n }\n } else {\n delete headers[\"Content-Type\"];\n delete headers[\"content-type\"];\n }\n return headers;\n}\n\nfunction getGeminiUploadUrl(baseUrl: string): string {\n if (baseUrl.includes(\"/v1beta\")) {\n return baseUrl.replace(/\\/v1beta\\/?$/, \"/upload/v1beta\");\n }\n return `${baseUrl.replace(/\\/$/, \"\")}/upload`;\n}\n\nfunction splitGeminiBatchRequests(requests: GeminiBatchRequest[]): GeminiBatchRequest[][] {\n if (requests.length <= GEMINI_BATCH_MAX_REQUESTS) return [requests];\n const groups: GeminiBatchRequest[][] = [];\n for (let i = 0; i < requests.length; i += GEMINI_BATCH_MAX_REQUESTS) {\n groups.push(requests.slice(i, i + GEMINI_BATCH_MAX_REQUESTS));\n }\n return groups;\n}\n\nfunction buildGeminiUploadBody(params: { jsonl: string; displayName: string }): {\n body: Blob;\n contentType: string;\n} {\n const boundary = `minimem-${hashText(params.displayName)}`;\n const jsonPart = JSON.stringify({\n file: {\n displayName: params.displayName,\n mimeType: \"application/jsonl\",\n },\n });\n const delimiter = `--${boundary}\\r\\n`;\n const closeDelimiter = `--${boundary}--\\r\\n`;\n const parts = [\n `${delimiter}Content-Type: application/json; charset=UTF-8\\r\\n\\r\\n${jsonPart}\\r\\n`,\n `${delimiter}Content-Type: application/jsonl; charset=UTF-8\\r\\n\\r\\n${params.jsonl}\\r\\n`,\n closeDelimiter,\n ];\n const body = new Blob([parts.join(\"\")], { type: \"multipart/related\" });\n return {\n body,\n contentType: `multipart/related; boundary=${boundary}`,\n };\n}\n\nasync function submitGeminiBatch(params: {\n gemini: GeminiEmbeddingClient;\n requests: GeminiBatchRequest[];\n source: string;\n}): Promise<GeminiBatchStatus> {\n const baseUrl = getGeminiBaseUrl(params.gemini);\n const jsonl = params.requests\n .map((request) =>\n JSON.stringify({\n key: request.custom_id,\n request: {\n content: request.content,\n task_type: request.taskType,\n },\n }),\n )\n .join(\"\\n\");\n const displayName = `memory-embeddings-${hashText(String(Date.now()))}`;\n const uploadPayload = buildGeminiUploadBody({ jsonl, displayName });\n\n const uploadUrl = `${getGeminiUploadUrl(baseUrl)}/files?uploadType=multipart`;\n const fileRes = await fetch(uploadUrl, {\n method: \"POST\",\n headers: {\n ...getGeminiHeaders(params.gemini, { json: false }),\n \"Content-Type\": uploadPayload.contentType,\n },\n body: uploadPayload.body,\n });\n if (!fileRes.ok) {\n const text = await fileRes.text();\n throw new Error(`gemini batch file upload failed: ${fileRes.status} ${text}`);\n }\n const filePayload = (await fileRes.json()) as { name?: string; file?: { name?: string } };\n const fileId = filePayload.name ?? filePayload.file?.name;\n if (!fileId) {\n throw new Error(\"gemini batch file upload failed: missing file id\");\n }\n\n const batchBody = {\n batch: {\n displayName: `memory-embeddings-${params.source}`,\n inputConfig: {\n file_name: fileId,\n },\n },\n };\n\n const batchEndpoint = `${baseUrl}/${params.gemini.modelPath}:asyncBatchEmbedContent`;\n const batchRes = await fetch(batchEndpoint, {\n method: \"POST\",\n headers: getGeminiHeaders(params.gemini, { json: true }),\n body: JSON.stringify(batchBody),\n });\n if (batchRes.ok) {\n return (await batchRes.json()) as GeminiBatchStatus;\n }\n const text = await batchRes.text();\n if (batchRes.status === 404) {\n throw new Error(\n \"gemini batch create failed: 404 (asyncBatchEmbedContent not available for this model/baseUrl). Disable batch.enabled or switch providers.\",\n );\n }\n throw new Error(`gemini batch create failed: ${batchRes.status} ${text}`);\n}\n\nasync function fetchGeminiBatchStatus(params: {\n gemini: GeminiEmbeddingClient;\n batchName: string;\n}): Promise<GeminiBatchStatus> {\n const baseUrl = getGeminiBaseUrl(params.gemini);\n const name = params.batchName.startsWith(\"batches/\")\n ? params.batchName\n : `batches/${params.batchName}`;\n const statusUrl = `${baseUrl}/${name}`;\n const res = await fetch(statusUrl, {\n headers: getGeminiHeaders(params.gemini, { json: true }),\n });\n if (!res.ok) {\n const text = await res.text();\n throw new Error(`gemini batch status failed: ${res.status} ${text}`);\n }\n return (await res.json()) as GeminiBatchStatus;\n}\n\nasync function fetchGeminiFileContent(params: {\n gemini: GeminiEmbeddingClient;\n fileId: string;\n}): Promise<string> {\n const baseUrl = getGeminiBaseUrl(params.gemini);\n const file = params.fileId.startsWith(\"files/\") ? params.fileId : `files/${params.fileId}`;\n const downloadUrl = `${baseUrl}/${file}:download`;\n const res = await fetch(downloadUrl, {\n headers: getGeminiHeaders(params.gemini, { json: true }),\n });\n if (!res.ok) {\n const text = await res.text();\n throw new Error(`gemini batch file content failed: ${res.status} ${text}`);\n }\n return await res.text();\n}\n\nfunction parseGeminiBatchOutput(text: string): GeminiBatchOutputLine[] {\n if (!text.trim()) return [];\n return text\n .split(\"\\n\")\n .map((line) => line.trim())\n .filter(Boolean)\n .map((line) => JSON.parse(line) as GeminiBatchOutputLine);\n}\n\nasync function waitForGeminiBatch(params: {\n gemini: GeminiEmbeddingClient;\n batchName: string;\n wait: boolean;\n pollIntervalMs: number;\n timeoutMs: number;\n debug?: (message: string, data?: Record<string, unknown>) => void;\n initial?: GeminiBatchStatus;\n}): Promise<{ outputFileId: string }> {\n const start = Date.now();\n let current: GeminiBatchStatus | undefined = params.initial;\n while (true) {\n const status =\n current ??\n (await fetchGeminiBatchStatus({\n gemini: params.gemini,\n batchName: params.batchName,\n }));\n const state = status.state ?? \"UNKNOWN\";\n if ([\"SUCCEEDED\", \"COMPLETED\", \"DONE\"].includes(state)) {\n const outputFileId =\n status.outputConfig?.file ??\n status.outputConfig?.fileId ??\n status.metadata?.output?.responsesFile;\n if (!outputFileId) {\n throw new Error(`gemini batch ${params.batchName} completed without output file`);\n }\n return { outputFileId };\n }\n if ([\"FAILED\", \"CANCELLED\", \"CANCELED\", \"EXPIRED\"].includes(state)) {\n const message = status.error?.message ?? \"unknown error\";\n throw new Error(`gemini batch ${params.batchName} ${state}: ${message}`);\n }\n if (!params.wait) {\n throw new Error(`gemini batch ${params.batchName} still ${state}; wait disabled`);\n }\n if (Date.now() - start > params.timeoutMs) {\n throw new Error(`gemini batch ${params.batchName} timed out after ${params.timeoutMs}ms`);\n }\n params.debug?.(`gemini batch ${params.batchName} ${state}; waiting ${params.pollIntervalMs}ms`);\n await new Promise((resolve) => setTimeout(resolve, params.pollIntervalMs));\n current = undefined;\n }\n}\n\nasync function runWithConcurrency<T>(tasks: Array<() => Promise<T>>, limit: number): Promise<T[]> {\n if (tasks.length === 0) return [];\n const resolvedLimit = Math.max(1, Math.min(limit, tasks.length));\n const results: T[] = Array.from({ length: tasks.length });\n let next = 0;\n let firstError: unknown = null;\n\n const workers = Array.from({ length: resolvedLimit }, async () => {\n while (true) {\n if (firstError) return;\n const index = next;\n next += 1;\n if (index >= tasks.length) return;\n try {\n results[index] = await tasks[index]();\n } catch (err) {\n firstError = err;\n return;\n }\n }\n });\n\n await Promise.allSettled(workers);\n if (firstError) throw firstError;\n return results;\n}\n\nexport async function runGeminiEmbeddingBatches(params: {\n gemini: GeminiEmbeddingClient;\n source: string;\n requests: GeminiBatchRequest[];\n wait: boolean;\n pollIntervalMs: number;\n timeoutMs: number;\n concurrency: number;\n debug?: (message: string, data?: Record<string, unknown>) => void;\n}): Promise<Map<string, number[]>> {\n if (params.requests.length === 0) return new Map();\n const groups = splitGeminiBatchRequests(params.requests);\n const byCustomId = new Map<string, number[]>();\n\n const tasks = groups.map((group, groupIndex) => async () => {\n const batchInfo = await submitGeminiBatch({\n gemini: params.gemini,\n requests: group,\n source: params.source,\n });\n const batchName = batchInfo.name ?? \"\";\n if (!batchName) {\n throw new Error(\"gemini batch create failed: missing batch name\");\n }\n\n params.debug?.(\"memory embeddings: gemini batch created\", {\n batchName,\n state: batchInfo.state,\n group: groupIndex + 1,\n groups: groups.length,\n requests: group.length,\n });\n\n if (\n !params.wait &&\n batchInfo.state &&\n ![\"SUCCEEDED\", \"COMPLETED\", \"DONE\"].includes(batchInfo.state)\n ) {\n throw new Error(\n `gemini batch ${batchName} submitted; enable batch.wait to await completion`,\n );\n }\n\n const completed =\n batchInfo.state && [\"SUCCEEDED\", \"COMPLETED\", \"DONE\"].includes(batchInfo.state)\n ? {\n outputFileId:\n batchInfo.outputConfig?.file ??\n batchInfo.outputConfig?.fileId ??\n batchInfo.metadata?.output?.responsesFile ??\n \"\",\n }\n : await waitForGeminiBatch({\n gemini: params.gemini,\n batchName,\n wait: params.wait,\n pollIntervalMs: params.pollIntervalMs,\n timeoutMs: params.timeoutMs,\n debug: params.debug,\n initial: batchInfo,\n });\n if (!completed.outputFileId) {\n throw new Error(`gemini batch ${batchName} completed without output file`);\n }\n\n const content = await fetchGeminiFileContent({\n gemini: params.gemini,\n fileId: completed.outputFileId,\n });\n const outputLines = parseGeminiBatchOutput(content);\n const errors: string[] = [];\n const remaining = new Set(group.map((request) => request.custom_id));\n\n for (const line of outputLines) {\n const customId = line.key ?? line.custom_id ?? line.request_id;\n if (!customId) continue;\n remaining.delete(customId);\n if (line.error?.message) {\n errors.push(`${customId}: ${line.error.message}`);\n continue;\n }\n if (line.response?.error?.message) {\n errors.push(`${customId}: ${line.response.error.message}`);\n continue;\n }\n const embedding = line.embedding?.values ?? line.response?.embedding?.values ?? [];\n if (embedding.length === 0) {\n errors.push(`${customId}: empty embedding`);\n continue;\n }\n byCustomId.set(customId, embedding);\n }\n\n if (errors.length > 0) {\n throw new Error(`gemini batch ${batchName} failed: ${errors.join(\"; \")}`);\n }\n if (remaining.size > 0) {\n throw new Error(`gemini batch ${batchName} missing ${remaining.size} embedding responses`);\n }\n });\n\n params.debug?.(\"memory embeddings: gemini batch submit\", {\n requests: params.requests.length,\n groups: groups.length,\n wait: params.wait,\n concurrency: params.concurrency,\n pollIntervalMs: params.pollIntervalMs,\n timeoutMs: params.timeoutMs,\n });\n\n await runWithConcurrency(tasks, params.concurrency);\n return byCustomId;\n}\n","/**\n * Tool definitions for memory operations\n *\n * These tools are compatible with:\n * - MCP (Model Context Protocol)\n * - Anthropic Claude tool use\n * - OpenAI function calling\n *\n * Note: Only memory_search is provided since the memory system is file-based.\n * Agents can use filesystem tools directly for read/write operations.\n */\n\nimport type { Minimem, MinimemSearchResult } from \"../minimem.js\";\n\n/**\n * JSON Schema for tool parameters (MCP/OpenAI/Anthropic compatible)\n */\nexport type ToolInputSchema = {\n type: \"object\";\n properties: Record<\n string,\n {\n type: string;\n description?: string;\n enum?: string[];\n items?: { type: string };\n default?: unknown;\n }\n >;\n required?: string[];\n};\n\n/**\n * Tool definition compatible with MCP, Anthropic, and OpenAI\n */\nexport type ToolDefinition = {\n name: string;\n description: string;\n inputSchema: ToolInputSchema;\n};\n\n/**\n * Tool execution result\n */\nexport type ToolResult = {\n content: Array<{ type: \"text\"; text: string }>;\n isError?: boolean;\n};\n\n/**\n * Memory search tool parameters\n */\nexport type MemorySearchParams = {\n query: string;\n maxResults?: number;\n minScore?: number;\n directories?: string[];\n /** \"compact\" returns lightweight index; \"full\" returns complete snippets (default: \"compact\") */\n detail?: \"compact\" | \"full\";\n /** Filter by observation type (e.g., \"decision\", \"bugfix\", \"feature\", \"discovery\") */\n type?: string;\n};\n\n/**\n * Memory get details tool parameters\n */\nexport type MemoryGetDetailsParams = {\n results: Array<{ path: string; startLine: number; endLine: number }>;\n directories?: string[];\n};\n\n/**\n * Knowledge search tool parameters\n */\nexport type KnowledgeSearchParams = {\n query: string;\n domain?: string[];\n entities?: string[];\n minConfidence?: number;\n knowledgeType?: string;\n maxResults?: number;\n minScore?: number;\n directories?: string[];\n};\n\n/**\n * Knowledge graph traversal parameters\n */\nexport type KnowledgeGraphParams = {\n nodeId: string;\n depth?: number;\n relation?: string;\n layer?: string;\n directories?: string[];\n};\n\n/**\n * Knowledge path parameters\n */\nexport type KnowledgePathParams = {\n fromId: string;\n toId: string;\n maxDepth?: number;\n directories?: string[];\n};\n\n/**\n * Search result with source directory\n */\ntype SearchResultWithSource = MinimemSearchResult & {\n memoryDir: string;\n};\n\nexport const MEMORY_SEARCH_TOOL: ToolDefinition = {\n name: \"memory_search\",\n description:\n \"Semantically search through memory files (MEMORY.md and memory/*.md). \" +\n \"Use this to recall prior decisions, facts, preferences, people, dates, or context. \" +\n \"Returns ranked snippets with file paths and line numbers. \" +\n \"When multiple memory directories are configured, searches all by default.\",\n inputSchema: {\n type: \"object\",\n properties: {\n query: {\n type: \"string\",\n description: \"Natural language search query\",\n },\n maxResults: {\n type: \"number\",\n description: \"Maximum number of results to return (default: 10)\",\n },\n minScore: {\n type: \"number\",\n description: \"Minimum relevance score threshold 0-1 (default: 0.3)\",\n },\n directories: {\n type: \"array\",\n items: { type: \"string\" },\n description:\n \"Optional: filter to specific memory directories by name/path. \" +\n \"If omitted, searches all configured directories.\",\n },\n detail: {\n type: \"string\",\n enum: [\"compact\", \"full\"],\n description:\n \"Result detail level. 'compact' returns a lightweight index with short previews (~80 chars). \" +\n \"'full' returns complete snippets. Use 'compact' first, then memory_get_details for selected results. \" +\n \"(default: 'compact')\",\n },\n type: {\n type: \"string\",\n description:\n \"Filter by observation type. Matches <!-- type: X --> comments in memory entries. \" +\n \"Common types: decision, bugfix, feature, discovery, context, note.\",\n },\n },\n required: [\"query\"],\n },\n};\n\nexport const MEMORY_GET_DETAILS_TOOL: ToolDefinition = {\n name: \"memory_get_details\",\n description:\n \"Fetch full text for specific memory chunks identified by path and line range. \" +\n \"Use after memory_search with compact results to get details for selected items only. \" +\n \"This two-step approach significantly reduces token usage.\",\n inputSchema: {\n type: \"object\",\n properties: {\n results: {\n type: \"array\",\n items: { type: \"object\" },\n description:\n \"Array of { path, startLine, endLine } objects from compact search results.\",\n },\n directories: {\n type: \"array\",\n items: { type: \"string\" },\n description: \"Optional: filter to specific memory directories.\",\n },\n },\n required: [\"results\"],\n },\n};\n\nexport const KNOWLEDGE_SEARCH_TOOL: ToolDefinition = {\n name: \"knowledge_search\",\n description:\n \"Search memory with knowledge metadata filters. \" +\n \"Filter by domain, entities, confidence level, or knowledge type (observation, entity, domain-summary). \" +\n \"Combines semantic search with structured knowledge filtering.\",\n inputSchema: {\n type: \"object\",\n properties: {\n query: {\n type: \"string\",\n description: \"Natural language search query\",\n },\n domain: {\n type: \"array\",\n items: { type: \"string\" },\n description: \"Filter to entries in these knowledge domains\",\n },\n entities: {\n type: \"array\",\n items: { type: \"string\" },\n description: \"Filter to entries referencing these entities\",\n },\n minConfidence: {\n type: \"number\",\n description: \"Minimum confidence threshold (0-1)\",\n },\n knowledgeType: {\n type: \"string\",\n description: \"Filter by knowledge type: observation, entity, domain-summary\",\n },\n maxResults: {\n type: \"number\",\n description: \"Maximum number of results (default: 10)\",\n },\n minScore: {\n type: \"number\",\n description: \"Minimum relevance score 0-1 (default: 0.3)\",\n },\n directories: {\n type: \"array\",\n items: { type: \"string\" },\n description: \"Optional: filter to specific memory directories\",\n },\n },\n required: [\"query\"],\n },\n};\n\nexport const KNOWLEDGE_GRAPH_TOOL: ToolDefinition = {\n name: \"knowledge_graph\",\n description:\n \"Traverse knowledge graph links from a note. \" +\n \"Returns neighbor nodes connected by typed relationships (e.g., relates-to, supports, contradicts). \" +\n \"Use depth parameter for multi-hop traversal.\",\n inputSchema: {\n type: \"object\",\n properties: {\n nodeId: {\n type: \"string\",\n description: \"The knowledge node ID to start traversal from\",\n },\n depth: {\n type: \"number\",\n description: \"Maximum traversal depth (default: 1, max: 3)\",\n default: 1,\n },\n relation: {\n type: \"string\",\n description: \"Optional: filter to specific relation type\",\n },\n layer: {\n type: \"string\",\n description: \"Optional: filter to specific graph layer\",\n },\n directories: {\n type: \"array\",\n items: { type: \"string\" },\n description: \"Optional: filter to specific memory directories\",\n },\n },\n required: [\"nodeId\"],\n },\n};\n\nexport const KNOWLEDGE_PATH_TOOL: ToolDefinition = {\n name: \"knowledge_path\",\n description:\n \"Find the shortest path between two knowledge nodes in the graph. \" +\n \"Uses BFS traversal up to a configurable max depth. \" +\n \"Returns the sequence of links connecting the two nodes.\",\n inputSchema: {\n type: \"object\",\n properties: {\n fromId: {\n type: \"string\",\n description: \"Starting knowledge node ID\",\n },\n toId: {\n type: \"string\",\n description: \"Target knowledge node ID\",\n },\n maxDepth: {\n type: \"number\",\n description: \"Maximum path length (default: 3)\",\n default: 3,\n },\n directories: {\n type: \"array\",\n items: { type: \"string\" },\n description: \"Optional: filter to specific memory directories\",\n },\n },\n required: [\"fromId\", \"toId\"],\n },\n};\n\n/**\n * All available memory tools\n */\nexport const MEMORY_TOOLS: ToolDefinition[] = [\n MEMORY_SEARCH_TOOL,\n MEMORY_GET_DETAILS_TOOL,\n KNOWLEDGE_SEARCH_TOOL,\n KNOWLEDGE_GRAPH_TOOL,\n KNOWLEDGE_PATH_TOOL,\n];\n\n/**\n * Get tool definitions for use with LLM APIs\n */\nexport function getToolDefinitions(): ToolDefinition[] {\n return MEMORY_TOOLS;\n}\n\n/**\n * Memory instance with its directory path\n */\nexport type MemoryInstance = {\n minimem: Minimem;\n memoryDir: string;\n name?: string;\n};\n\n/**\n * Tool executor that handles memory search across multiple directories\n */\nexport class MemoryToolExecutor {\n private instances: MemoryInstance[];\n\n constructor(instances: Minimem | MemoryInstance | MemoryInstance[]) {\n // Normalize to array of MemoryInstance\n if (Array.isArray(instances)) {\n this.instances = instances;\n } else if (\"minimem\" in instances) {\n this.instances = [instances];\n } else {\n // Legacy: single Minimem instance without directory info\n this.instances = [{ minimem: instances, memoryDir: \"default\" }];\n }\n }\n\n /**\n * Get list of configured directory names/paths\n */\n getDirectories(): string[] {\n return this.instances.map((i) => i.name ?? i.memoryDir);\n }\n\n /**\n * Execute a tool by name with given parameters\n */\n async execute(\n toolName: string,\n params: Record<string, unknown>,\n ): Promise<ToolResult> {\n try {\n switch (toolName) {\n case \"memory_search\":\n return await this.memorySearch(params as MemorySearchParams);\n case \"memory_get_details\":\n return await this.memoryGetDetails(params as MemoryGetDetailsParams);\n case \"knowledge_search\":\n return await this.knowledgeSearch(params as KnowledgeSearchParams);\n case \"knowledge_graph\":\n return await this.knowledgeGraph(params as KnowledgeGraphParams);\n case \"knowledge_path\":\n return await this.knowledgePath(params as KnowledgePathParams);\n default:\n return {\n content: [{ type: \"text\", text: `Unknown tool: ${toolName}` }],\n isError: true,\n };\n }\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n return {\n content: [{ type: \"text\", text: `Error: ${message}` }],\n isError: true,\n };\n }\n }\n\n /**\n * Filter instances by directory names/paths\n */\n private filterInstances(directories?: string[]): MemoryInstance[] | null {\n if (!directories || directories.length === 0) return this.instances;\n\n const dirFilter = new Set(directories.map((d) => d.toLowerCase()));\n const filtered = this.instances.filter((i) => {\n const name = (i.name ?? i.memoryDir).toLowerCase();\n const dir = i.memoryDir.toLowerCase();\n return (\n dirFilter.has(name) ||\n dirFilter.has(dir) ||\n [...dirFilter].some((f) => dir.includes(f) || name.includes(f))\n );\n });\n\n return filtered.length > 0 ? filtered : null;\n }\n\n private async memorySearch(params: MemorySearchParams): Promise<ToolResult> {\n const maxResults = params.maxResults ?? 10;\n const minScore = params.minScore;\n const detail = params.detail ?? \"compact\";\n\n const instancesToSearch = this.filterInstances(params.directories);\n if (!instancesToSearch) {\n const available = this.getDirectories().join(\", \");\n return {\n content: [\n {\n type: \"text\",\n text: `No matching directories found. Available: ${available}`,\n },\n ],\n isError: true,\n };\n }\n\n // Search all matching instances\n const allResults: SearchResultWithSource[] = [];\n\n for (const instance of instancesToSearch) {\n const perDirMax = Math.ceil(maxResults * 1.5);\n const results = await instance.minimem.search(params.query, {\n maxResults: perDirMax,\n minScore,\n type: params.type,\n });\n\n for (const result of results) {\n allResults.push({\n ...result,\n memoryDir: instance.name ?? instance.memoryDir,\n });\n }\n }\n\n // Sort by score and limit\n allResults.sort((a, b) => b.score - a.score);\n const topResults = allResults.slice(0, maxResults);\n\n if (topResults.length === 0) {\n return {\n content: [{ type: \"text\", text: \"No results found.\" }],\n };\n }\n\n const showSource = instancesToSearch.length > 1;\n\n if (detail === \"compact\") {\n return this.formatCompactResults(topResults, showSource, instancesToSearch.length);\n }\n\n return this.formatFullResults(topResults, showSource, instancesToSearch.length);\n }\n\n private formatCompactResults(\n results: SearchResultWithSource[],\n showSource: boolean,\n dirCount: number,\n ): ToolResult {\n const formatted = results\n .map((r, i) => {\n const location = `${r.path}:${r.startLine}-${r.endLine}`;\n const score = (r.score * 100).toFixed(0);\n const source = showSource ? ` [${r.memoryDir}]` : \"\";\n const preview = compactPreview(r.snippet);\n return `[${i}] ${location}${source} (${score}%) — ${preview}`;\n })\n .join(\"\\n\");\n\n const hint = \"\\n\\nUse memory_get_details to fetch full text for selected results.\";\n const dirSummary = dirCount > 1 ? `\\n(Searched ${dirCount} directories)` : \"\";\n\n return {\n content: [{ type: \"text\", text: formatted + dirSummary + hint }],\n };\n }\n\n private formatFullResults(\n results: SearchResultWithSource[],\n showSource: boolean,\n dirCount: number,\n ): ToolResult {\n const formatted = results\n .map((r, i) => {\n const location = `${r.path}:${r.startLine}-${r.endLine}`;\n const score = (r.score * 100).toFixed(1);\n const source = showSource ? ` [${r.memoryDir}]` : \"\";\n return `[${i + 1}] ${location}${source} (${score}% match)\\n${r.snippet}`;\n })\n .join(\"\\n\\n\");\n\n const dirSummary =\n dirCount > 1 ? `\\n\\n(Searched ${dirCount} directories)` : \"\";\n\n return {\n content: [{ type: \"text\", text: formatted + dirSummary }],\n };\n }\n\n private async memoryGetDetails(params: MemoryGetDetailsParams): Promise<ToolResult> {\n if (!params.results || params.results.length === 0) {\n return {\n content: [{ type: \"text\", text: \"No results specified.\" }],\n isError: true,\n };\n }\n\n const instancesToSearch = this.filterInstances(params.directories);\n if (!instancesToSearch) {\n const available = this.getDirectories().join(\", \");\n return {\n content: [\n {\n type: \"text\",\n text: `No matching directories found. Available: ${available}`,\n },\n ],\n isError: true,\n };\n }\n\n const details: string[] = [];\n\n for (const ref of params.results) {\n let found = false;\n\n for (const instance of instancesToSearch) {\n const lineCount = ref.endLine - ref.startLine + 1;\n const result = await instance.minimem.readLines(ref.path, {\n from: ref.startLine,\n lines: lineCount,\n });\n\n if (result) {\n const location = `${ref.path}:${result.startLine}-${result.endLine}`;\n details.push(`--- ${location} ---\\n${result.content}`);\n found = true;\n break;\n }\n }\n\n if (!found) {\n details.push(`--- ${ref.path}:${ref.startLine}-${ref.endLine} ---\\n(not found)`);\n }\n }\n\n return {\n content: [{ type: \"text\", text: details.join(\"\\n\\n\") }],\n };\n }\n\n private async knowledgeSearch(params: KnowledgeSearchParams): Promise<ToolResult> {\n const instancesToSearch = this.filterInstances(params.directories);\n if (!instancesToSearch) {\n const available = this.getDirectories().join(\", \");\n return {\n content: [{ type: \"text\", text: `No matching directories found. Available: ${available}` }],\n isError: true,\n };\n }\n\n const maxResults = params.maxResults ?? 10;\n const allResults: SearchResultWithSource[] = [];\n\n for (const instance of instancesToSearch) {\n const results = await instance.minimem.knowledgeSearch(params.query, {\n maxResults: Math.ceil(maxResults * 1.5),\n minScore: params.minScore,\n domain: params.domain,\n entities: params.entities,\n minConfidence: params.minConfidence,\n knowledgeType: params.knowledgeType,\n });\n\n for (const result of results) {\n allResults.push({\n ...result,\n memoryDir: instance.name ?? instance.memoryDir,\n });\n }\n }\n\n allResults.sort((a, b) => b.score - a.score);\n const topResults = allResults.slice(0, maxResults);\n\n if (topResults.length === 0) {\n return { content: [{ type: \"text\", text: \"No knowledge results found.\" }] };\n }\n\n const formatted = topResults\n .map((r, i) => {\n const location = `${r.path}:${r.startLine}-${r.endLine}`;\n const score = (r.score * 100).toFixed(0);\n const preview = compactPreview(r.snippet);\n return `[${i}] ${location} (${score}%) — ${preview}`;\n })\n .join(\"\\n\");\n\n return { content: [{ type: \"text\", text: formatted }] };\n }\n\n private async knowledgeGraph(params: KnowledgeGraphParams): Promise<ToolResult> {\n const instancesToSearch = this.filterInstances(params.directories);\n if (!instancesToSearch) {\n const available = this.getDirectories().join(\", \");\n return {\n content: [{ type: \"text\", text: `No matching directories found. Available: ${available}` }],\n isError: true,\n };\n }\n\n const depth = Math.min(params.depth ?? 1, 3);\n const allNeighbors: Array<{ id: string; depth: number; relation: string; layer: string | null; memoryDir: string }> = [];\n\n for (const instance of instancesToSearch) {\n const neighbors = instance.minimem.getGraphNeighbors(params.nodeId, depth, {\n relation: params.relation,\n layer: params.layer,\n });\n\n for (const n of neighbors) {\n allNeighbors.push({\n id: n.id,\n depth: n.depth,\n relation: n.link.relation,\n layer: n.link.layer,\n memoryDir: instance.name ?? instance.memoryDir,\n });\n }\n }\n\n if (allNeighbors.length === 0) {\n return { content: [{ type: \"text\", text: `No neighbors found for node \"${params.nodeId}\".` }] };\n }\n\n const formatted = allNeighbors\n .map((n) => ` [depth=${n.depth}] ${n.id} —(${n.relation})${n.layer ? ` [${n.layer}]` : \"\"}`)\n .join(\"\\n\");\n\n return {\n content: [{ type: \"text\", text: `Neighbors of \"${params.nodeId}\":\\n${formatted}` }],\n };\n }\n\n private async knowledgePath(params: KnowledgePathParams): Promise<ToolResult> {\n const instancesToSearch = this.filterInstances(params.directories);\n if (!instancesToSearch) {\n const available = this.getDirectories().join(\", \");\n return {\n content: [{ type: \"text\", text: `No matching directories found. Available: ${available}` }],\n isError: true,\n };\n }\n\n const maxDepth = Math.min(params.maxDepth ?? 3, 5);\n\n // Try each instance until a path is found\n for (const instance of instancesToSearch) {\n const path = instance.minimem.getGraphPath(params.fromId, params.toId, maxDepth);\n if (path.length > 0) {\n const steps = path\n .map((link) => ` ${link.fromId} —(${link.relation})→ ${link.toId}`)\n .join(\"\\n\");\n return {\n content: [{\n type: \"text\",\n text: `Path from \"${params.fromId}\" to \"${params.toId}\" (${path.length} steps):\\n${steps}`,\n }],\n };\n }\n }\n\n return {\n content: [{\n type: \"text\",\n text: `No path found from \"${params.fromId}\" to \"${params.toId}\" within depth ${maxDepth}.`,\n }],\n };\n }\n}\n\n/**\n * Generate a compact preview from a snippet (~80 chars).\n * Prefers the first heading or first non-empty line.\n */\nfunction compactPreview(snippet: string): string {\n const maxLen = 80;\n const lines = snippet.split(\"\\n\").filter((l) => l.trim());\n if (lines.length === 0) return \"(empty)\";\n\n // Prefer a heading line\n const heading = lines.find((l) => l.startsWith(\"#\"));\n const text = heading ?? lines[0];\n // Strip markdown heading markers for cleaner display\n const cleaned = text.replace(/^#+\\s*/, \"\").trim();\n\n if (cleaned.length <= maxLen) return `\"${cleaned}\"`;\n return `\"${cleaned.slice(0, maxLen - 3)}...\"`;\n}\n\n/**\n * Create a tool executor for the given Minimem instance(s)\n */\nexport function createToolExecutor(\n instances: Minimem | MemoryInstance | MemoryInstance[],\n): MemoryToolExecutor {\n return new MemoryToolExecutor(instances);\n}\n","/**\n * MCP (Model Context Protocol) Server for Minimem\n *\n * Provides memory tools via JSON-RPC 2.0 over stdio.\n * Compatible with Claude Desktop, Cursor, and other MCP clients.\n *\n * Usage:\n * import { Minimem } from \"minimem\";\n * import { createMcpServer, runMcpServer } from \"minimem/mcp\";\n *\n * const minimem = await Minimem.create({ ... });\n * const server = createMcpServer(minimem);\n * await runMcpServer(server); // Runs over stdio\n */\n\nimport * as readline from \"node:readline\";\nimport type { Minimem } from \"../minimem.js\";\nimport {\n MEMORY_TOOLS,\n type ToolDefinition,\n type ToolResult,\n type MemoryInstance,\n MemoryToolExecutor,\n} from \"./tools.js\";\n\nconst PROTOCOL_VERSION = \"2024-11-05\";\nconst SERVER_NAME = \"minimem\";\nconst SERVER_VERSION = \"0.1.0\";\n\n/**\n * JSON-RPC 2.0 request\n */\ntype JsonRpcRequest = {\n jsonrpc: \"2.0\";\n id: string | number;\n method: string;\n params?: Record<string, unknown>;\n};\n\n/**\n * JSON-RPC 2.0 response\n */\ntype JsonRpcResponse = {\n jsonrpc: \"2.0\";\n id: string | number | null;\n result?: unknown;\n error?: {\n code: number;\n message: string;\n data?: unknown;\n };\n};\n\n/**\n * JSON-RPC 2.0 notification (no id)\n */\ntype JsonRpcNotification = {\n jsonrpc: \"2.0\";\n method: string;\n params?: Record<string, unknown>;\n};\n\n/**\n * MCP Server capabilities\n */\ntype ServerCapabilities = {\n tools?: {\n listChanged?: boolean;\n };\n};\n\n/**\n * MCP Server info\n */\ntype ServerInfo = {\n name: string;\n version: string;\n};\n\n/**\n * MCP Initialize result\n */\ntype InitializeResult = {\n protocolVersion: string;\n capabilities: ServerCapabilities;\n serverInfo: ServerInfo;\n};\n\n/**\n * MCP Tool in list format\n */\ntype McpTool = {\n name: string;\n description: string;\n inputSchema: {\n type: \"object\";\n properties: Record<string, unknown>;\n required?: string[];\n };\n};\n\n/**\n * MCP Server implementation\n */\nexport class McpServer {\n private executor: MemoryToolExecutor;\n private initialized = false;\n\n constructor(instances: Minimem | MemoryInstance | MemoryInstance[]) {\n this.executor = new MemoryToolExecutor(instances);\n }\n\n /**\n * Handle a JSON-RPC request and return a response\n */\n async handleRequest(request: JsonRpcRequest): Promise<JsonRpcResponse> {\n try {\n const result = await this.dispatch(request.method, request.params);\n return {\n jsonrpc: \"2.0\",\n id: request.id,\n result,\n };\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n const code = err instanceof McpError ? err.code : -32603;\n return {\n jsonrpc: \"2.0\",\n id: request.id,\n error: { code, message },\n };\n }\n }\n\n /**\n * Dispatch a method call\n */\n private async dispatch(\n method: string,\n params?: Record<string, unknown>,\n ): Promise<unknown> {\n switch (method) {\n case \"initialize\":\n return this.initialize(params);\n case \"initialized\":\n // Notification, no response needed\n return {};\n case \"tools/list\":\n return this.listTools();\n case \"tools/call\":\n return this.callTool(params);\n case \"ping\":\n return {};\n default:\n throw new McpError(-32601, `Method not found: ${method}`);\n }\n }\n\n /**\n * Handle initialize request\n */\n private initialize(\n params?: Record<string, unknown>,\n ): InitializeResult {\n this.initialized = true;\n return {\n protocolVersion: PROTOCOL_VERSION,\n capabilities: {\n tools: {\n listChanged: false,\n },\n },\n serverInfo: {\n name: SERVER_NAME,\n version: SERVER_VERSION,\n },\n };\n }\n\n /**\n * List available tools\n */\n private listTools(): { tools: McpTool[] } {\n const tools: McpTool[] = MEMORY_TOOLS.map((tool) => ({\n name: tool.name,\n description: tool.description,\n inputSchema: tool.inputSchema,\n }));\n return { tools };\n }\n\n /**\n * Call a tool\n */\n private async callTool(\n params?: Record<string, unknown>,\n ): Promise<{ content: Array<{ type: string; text: string }>; isError?: boolean }> {\n if (!params?.name || typeof params.name !== \"string\") {\n throw new McpError(-32602, \"Missing tool name\");\n }\n\n const toolName = params.name;\n const toolParams = (params.arguments ?? {}) as Record<string, unknown>;\n\n const result = await this.executor.execute(toolName, toolParams);\n return result;\n }\n}\n\n/**\n * Custom error class for MCP errors\n */\nclass McpError extends Error {\n constructor(\n public code: number,\n message: string,\n ) {\n super(message);\n this.name = \"McpError\";\n }\n}\n\n/**\n * Create an MCP server for the given Minimem instance(s)\n */\nexport function createMcpServer(\n instances: Minimem | MemoryInstance | MemoryInstance[],\n): McpServer {\n return new McpServer(instances);\n}\n\n/**\n * Run the MCP server over stdio\n */\nexport async function runMcpServer(server: McpServer): Promise<void> {\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n terminal: false,\n });\n\n const send = (message: JsonRpcResponse | JsonRpcNotification) => {\n const json = JSON.stringify(message);\n process.stdout.write(json + \"\\n\");\n };\n\n rl.on(\"line\", async (line) => {\n if (!line.trim()) return;\n\n try {\n const request = JSON.parse(line) as JsonRpcRequest;\n\n if (request.jsonrpc !== \"2.0\") {\n send({\n jsonrpc: \"2.0\",\n id: request.id ?? null,\n error: { code: -32600, message: \"Invalid JSON-RPC version\" },\n });\n return;\n }\n\n // Handle notification (no id)\n if (request.id === undefined) {\n await server.handleRequest({ ...request, id: 0 });\n return;\n }\n\n const response = await server.handleRequest(request);\n send(response);\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n send({\n jsonrpc: \"2.0\",\n id: null,\n error: { code: -32700, message: `Parse error: ${message}` },\n });\n }\n });\n\n rl.on(\"close\", () => {\n process.exit(0);\n });\n\n // Keep the process alive\n await new Promise(() => {});\n}\n\n/**\n * MCP server configuration for claude_desktop_config.json\n *\n * Example:\n * {\n * \"mcpServers\": {\n * \"minimem\": {\n * \"command\": \"node\",\n * \"args\": [\"path/to/your/mcp-server.js\"],\n * \"env\": {\n * \"MEMORY_DIR\": \"/path/to/memory\"\n * }\n * }\n * }\n * }\n */\nexport type McpServerConfig = {\n command: string;\n args: string[];\n env?: Record<string, string>;\n};\n\n/**\n * Generate MCP server config for Claude Desktop\n */\nexport function generateMcpConfig(opts: {\n serverPath: string;\n memoryDir: string;\n embeddingProvider?: \"openai\" | \"gemini\" | \"local\" | \"auto\";\n}): McpServerConfig {\n return {\n command: \"node\",\n args: [opts.serverPath],\n env: {\n MEMORY_DIR: opts.memoryDir,\n ...(opts.embeddingProvider ? { EMBEDDING_PROVIDER: opts.embeddingProvider } : {}),\n },\n };\n}\n","/**\n * MemoryIndexer - Handles file indexing and embedding management\n *\n * Responsible for:\n * - Processing memory files into chunks\n * - Computing and caching embeddings\n * - Managing file records in the database\n * - Detecting stale content\n */\n\nimport { randomUUID } from \"node:crypto\";\nimport fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport type { DatabaseSync } from \"node:sqlite\";\n\nimport {\n buildFileEntry,\n chunkMarkdown,\n hashText,\n listMemoryFiles,\n type MemoryChunk,\n type MemoryFileEntry,\n parseEmbedding,\n vectorToBlob,\n type DebugFn,\n} from \"../internal.js\";\nimport type {\n EmbeddingProvider,\n OpenAiEmbeddingClient,\n GeminiEmbeddingClient,\n} from \"../embeddings/embeddings.js\";\nimport {\n runOpenAiEmbeddingBatches,\n type OpenAiBatchRequest,\n OPENAI_BATCH_ENDPOINT,\n} from \"../embeddings/batch-openai.js\";\nimport { runGeminiEmbeddingBatches, type GeminiBatchRequest } from \"../embeddings/batch-gemini.js\";\n\nconst META_KEY = \"memory_index_meta_v1\";\nconst EMBEDDING_CACHE_TABLE = \"embedding_cache\";\nconst VECTOR_TABLE = \"chunks_vec\";\nconst FTS_TABLE = \"chunks_fts\";\nconst EMBEDDING_RETRY_MAX_ATTEMPTS = 3;\nconst EMBEDDING_RETRY_BASE_DELAY_MS = 500;\nconst EMBEDDING_RETRY_MAX_DELAY_MS = 8000;\n\nexport type IndexerConfig = {\n memoryDir: string;\n chunking: { tokens: number; overlap: number };\n cache: { enabled: boolean; maxEntries: number };\n batch: {\n enabled: boolean;\n wait: boolean;\n concurrency: number;\n pollIntervalMs: number;\n timeoutMs: number;\n };\n ftsEnabled: boolean;\n debug?: DebugFn;\n};\n\nexport type MemoryIndexMeta = {\n model: string;\n provider: string;\n providerKey?: string;\n chunkTokens: number;\n chunkOverlap: number;\n vectorDims?: number;\n};\n\nexport type IndexStats = {\n filesProcessed: number;\n chunksCreated: number;\n staleRemoved: number;\n};\n\n/**\n * MemoryIndexer handles file indexing, chunking, and embedding management\n */\nexport class MemoryIndexer {\n private readonly config: IndexerConfig;\n private readonly db: DatabaseSync;\n private readonly provider: EmbeddingProvider;\n private readonly providerKey: string;\n private readonly openAi?: OpenAiEmbeddingClient;\n private readonly gemini?: GeminiEmbeddingClient;\n\n // Vector/FTS state (shared with parent)\n private vectorState: {\n available: boolean;\n dims?: number;\n };\n private ftsAvailable: boolean;\n\n constructor(\n db: DatabaseSync,\n provider: EmbeddingProvider,\n config: IndexerConfig,\n options?: {\n openAi?: OpenAiEmbeddingClient;\n gemini?: GeminiEmbeddingClient;\n vectorState?: { available: boolean; dims?: number };\n ftsAvailable?: boolean;\n }\n ) {\n this.db = db;\n this.provider = provider;\n this.config = config;\n this.openAi = options?.openAi;\n this.gemini = options?.gemini;\n this.vectorState = options?.vectorState ?? { available: false };\n this.ftsAvailable = options?.ftsAvailable ?? false;\n this.providerKey = this.computeProviderKey();\n }\n\n /**\n * Update vector/FTS availability (called by parent when extensions load)\n */\n setVectorState(state: { available: boolean; dims?: number }): void {\n this.vectorState = state;\n }\n\n setFtsAvailable(available: boolean): void {\n this.ftsAvailable = available;\n }\n\n getVectorDims(): number | undefined {\n return this.vectorState.dims;\n }\n\n /**\n * Compute a unique key for the current provider configuration\n */\n private computeProviderKey(): string {\n const parts: string[] = [this.provider.id, this.provider.model];\n if (this.openAi) {\n parts.push(this.openAi.baseUrl);\n }\n if (this.gemini) {\n parts.push(this.gemini.baseUrl);\n }\n return hashText(parts.join(\":\"));\n }\n\n /**\n * Read index metadata from database\n */\n readMeta(): MemoryIndexMeta | null {\n try {\n const row = this.db.prepare(`SELECT value FROM meta WHERE key = ?`).get(META_KEY) as\n | { value: string }\n | undefined;\n if (!row?.value) return null;\n return JSON.parse(row.value) as MemoryIndexMeta;\n } catch {\n return null;\n }\n }\n\n /**\n * Write index metadata to database\n */\n writeMeta(meta: MemoryIndexMeta): void {\n this.db\n .prepare(`INSERT OR REPLACE INTO meta (key, value) VALUES (?, ?)`)\n .run(META_KEY, JSON.stringify(meta));\n }\n\n /**\n * Check if the index is stale by comparing file mtimes\n */\n async isStale(): Promise<boolean> {\n try {\n const files = await listMemoryFiles(this.config.memoryDir);\n\n const stored = this.db\n .prepare(`SELECT path, mtime FROM files WHERE source = ?`)\n .all(\"memory\") as Array<{ path: string; mtime: number }>;\n\n if (files.length !== stored.length) {\n this.config.debug?.(`Stale: file count changed (${stored.length} -> ${files.length})`);\n return true;\n }\n\n const storedMap = new Map(stored.map((f) => [f.path, f.mtime]));\n\n for (const absPath of files) {\n const relPath = path.relative(this.config.memoryDir, absPath).replace(/\\\\/g, \"/\");\n const storedMtime = storedMap.get(relPath);\n\n if (storedMtime === undefined) {\n this.config.debug?.(`Stale: new file ${relPath}`);\n return true;\n }\n\n const stat = await fs.stat(absPath);\n const currentMtime = Math.floor(stat.mtimeMs);\n if (currentMtime !== storedMtime) {\n this.config.debug?.(`Stale: mtime changed for ${relPath}`);\n return true;\n }\n }\n\n return false;\n } catch (err) {\n this.config.debug?.(`Stale check failed: ${String(err)}`);\n return true;\n }\n }\n\n /**\n * Check if a full reindex is needed based on configuration changes\n */\n needsFullReindex(force?: boolean): boolean {\n const meta = this.readMeta();\n return (\n force === true ||\n !meta ||\n meta.model !== this.provider.model ||\n meta.provider !== this.provider.id ||\n meta.providerKey !== this.providerKey ||\n meta.chunkTokens !== this.config.chunking.tokens ||\n meta.chunkOverlap !== this.config.chunking.overlap ||\n (this.vectorState.available && !meta?.vectorDims)\n );\n }\n\n /**\n * Index all memory files, returns stats\n */\n async indexAll(force?: boolean): Promise<IndexStats> {\n const needsFullReindex = this.needsFullReindex(force);\n const files = await listMemoryFiles(this.config.memoryDir);\n const activePaths = new Set<string>();\n let filesProcessed = 0;\n let chunksCreated = 0;\n\n for (const absPath of files) {\n const entry = await buildFileEntry(absPath, this.config.memoryDir);\n activePaths.add(entry.path);\n\n const record = this.db\n .prepare(`SELECT hash FROM files WHERE path = ? AND source = ?`)\n .get(entry.path, \"memory\") as { hash: string } | undefined;\n\n if (!needsFullReindex && record?.hash === entry.hash) {\n continue;\n }\n\n const chunkCount = await this.indexFile(entry);\n filesProcessed++;\n chunksCreated += chunkCount;\n }\n\n // Delete stale entries\n const staleRemoved = this.removeStaleEntries(activePaths);\n\n // Write meta\n this.writeMeta({\n model: this.provider.model,\n provider: this.provider.id,\n providerKey: this.providerKey,\n chunkTokens: this.config.chunking.tokens,\n chunkOverlap: this.config.chunking.overlap,\n vectorDims: this.vectorState.dims,\n });\n\n // Prune embedding cache\n this.pruneEmbeddingCacheIfNeeded();\n\n return { filesProcessed, chunksCreated, staleRemoved };\n }\n\n /**\n * Index a single file\n */\n async indexFile(entry: MemoryFileEntry): Promise<number> {\n const content = await fs.readFile(entry.absPath, \"utf-8\");\n const chunks = chunkMarkdown(content, this.config.chunking);\n\n const embeddings = await this.embedChunks(chunks);\n\n // Update files table\n this.db\n .prepare(\n `INSERT OR REPLACE INTO files (path, source, hash, mtime, size) VALUES (?, ?, ?, ?, ?)`\n )\n .run(entry.path, \"memory\", entry.hash, Math.floor(entry.mtimeMs), entry.size);\n\n // Delete old chunks\n this.deleteChunksForFile(entry.path);\n\n // Insert new chunks\n const now = Date.now();\n for (let i = 0; i < chunks.length; i++) {\n const chunk = chunks[i];\n const embedding = embeddings[i] ?? [];\n this.insertChunk(entry.path, chunk, embedding, now);\n }\n\n return chunks.length;\n }\n\n /**\n * Delete all chunks for a file\n */\n private deleteChunksForFile(filePath: string): void {\n try {\n this.db\n .prepare(\n `DELETE FROM ${VECTOR_TABLE} WHERE id IN (SELECT id FROM chunks WHERE path = ? AND source = ?)`\n )\n .run(filePath, \"memory\");\n } catch {\n // Vector table may not exist\n }\n this.db.prepare(`DELETE FROM chunks WHERE path = ? AND source = ?`).run(filePath, \"memory\");\n if (this.config.ftsEnabled && this.ftsAvailable) {\n try {\n this.db\n .prepare(`DELETE FROM ${FTS_TABLE} WHERE path = ? AND source = ? AND model = ?`)\n .run(filePath, \"memory\", this.provider.model);\n } catch {\n // FTS table may not exist\n }\n }\n }\n\n /**\n * Insert a chunk into the database\n */\n private insertChunk(\n filePath: string,\n chunk: MemoryChunk,\n embedding: number[],\n timestamp: number\n ): void {\n const chunkId = randomUUID();\n\n this.db\n .prepare(\n `INSERT INTO chunks (id, path, source, start_line, end_line, hash, model, text, embedding, updated_at)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`\n )\n .run(\n chunkId,\n filePath,\n \"memory\",\n chunk.startLine,\n chunk.endLine,\n chunk.hash,\n this.provider.model,\n chunk.text,\n JSON.stringify(embedding),\n timestamp\n );\n\n // Insert into vector table if available\n if (this.vectorState.available && embedding.length > 0) {\n if (!this.vectorState.dims) {\n this.vectorState.dims = embedding.length;\n this.ensureVectorTable(embedding.length);\n }\n try {\n this.db\n .prepare(`INSERT INTO ${VECTOR_TABLE} (id, embedding) VALUES (?, ?)`)\n .run(chunkId, vectorToBlob(embedding));\n } catch {\n // Vector insertion may fail\n }\n }\n\n // Insert into FTS table if available\n if (this.config.ftsEnabled && this.ftsAvailable) {\n try {\n this.db\n .prepare(\n `INSERT INTO ${FTS_TABLE} (text, id, path, source, model, start_line, end_line)\n VALUES (?, ?, ?, ?, ?, ?, ?)`\n )\n .run(\n chunk.text,\n chunkId,\n filePath,\n \"memory\",\n this.provider.model,\n chunk.startLine,\n chunk.endLine\n );\n } catch {\n // FTS insertion may fail\n }\n }\n }\n\n /**\n * Remove stale file entries that no longer exist\n */\n private removeStaleEntries(activePaths: Set<string>): number {\n const staleRows = this.db\n .prepare(`SELECT path FROM files WHERE source = ?`)\n .all(\"memory\") as Array<{ path: string }>;\n\n let removed = 0;\n for (const stale of staleRows) {\n if (activePaths.has(stale.path)) continue;\n\n this.db\n .prepare(`DELETE FROM files WHERE path = ? AND source = ?`)\n .run(stale.path, \"memory\");\n this.deleteChunksForFile(stale.path);\n removed++;\n }\n\n return removed;\n }\n\n /**\n * Create vector table with the given dimensions\n */\n ensureVectorTable(dimensions: number): void {\n if (!this.vectorState.available) return;\n try {\n this.db.exec(\n `CREATE VIRTUAL TABLE IF NOT EXISTS ${VECTOR_TABLE} USING vec0(\n id TEXT PRIMARY KEY,\n embedding FLOAT[${dimensions}]\n )`\n );\n } catch (err) {\n this.config.debug?.(`vector table creation failed: ${String(err)}`);\n }\n }\n\n /**\n * Get embeddings for chunks, using cache when available\n */\n async embedChunks(chunks: MemoryChunk[]): Promise<number[][]> {\n if (chunks.length === 0) return [];\n\n const hashes = chunks.map((c) => c.hash);\n const cached = this.loadEmbeddingCache(hashes);\n const missing: Array<{ index: number; chunk: MemoryChunk }> = [];\n\n for (let i = 0; i < chunks.length; i++) {\n if (!cached.has(hashes[i])) {\n missing.push({ index: i, chunk: chunks[i] });\n }\n }\n\n if (missing.length > 0) {\n const texts = missing.map((m) => m.chunk.text);\n const newEmbeddings = await this.embedBatchWithRetry(texts);\n\n for (let i = 0; i < missing.length; i++) {\n const hash = missing[i].chunk.hash;\n const embedding = newEmbeddings[i] ?? [];\n cached.set(hash, embedding);\n this.upsertEmbeddingCache(hash, embedding);\n }\n }\n\n return hashes.map((h) => cached.get(h) ?? []);\n }\n\n /**\n * Embed texts with retry logic\n */\n private async embedBatchWithRetry(texts: string[]): Promise<number[][]> {\n if (texts.length === 0) return [];\n\n // Try batch API first if enabled\n if (this.config.batch.enabled) {\n try {\n return await this.embedWithBatchApi(texts);\n } catch (err) {\n this.config.debug?.(`batch embedding failed, falling back to direct: ${String(err)}`);\n }\n }\n\n // Fall back to direct embedding\n let lastError: Error | null = null;\n for (let attempt = 0; attempt < EMBEDDING_RETRY_MAX_ATTEMPTS; attempt++) {\n try {\n return await this.provider.embedBatch(texts);\n } catch (err) {\n lastError = err instanceof Error ? err : new Error(String(err));\n if (attempt < EMBEDDING_RETRY_MAX_ATTEMPTS - 1) {\n const delay = Math.min(\n EMBEDDING_RETRY_MAX_DELAY_MS,\n EMBEDDING_RETRY_BASE_DELAY_MS * Math.pow(2, attempt)\n );\n await new Promise((resolve) => setTimeout(resolve, delay));\n }\n }\n }\n throw lastError;\n }\n\n /**\n * Use batch API for large embedding jobs\n */\n private async embedWithBatchApi(texts: string[]): Promise<number[][]> {\n if (this.openAi) {\n const requests: OpenAiBatchRequest[] = texts.map((text, i) => ({\n custom_id: `chunk-${i}`,\n method: \"POST\",\n url: OPENAI_BATCH_ENDPOINT,\n body: { model: this.openAi!.model, input: text },\n }));\n\n const results = await runOpenAiEmbeddingBatches({\n openAi: this.openAi,\n source: \"minimem\",\n requests,\n wait: this.config.batch.wait,\n pollIntervalMs: this.config.batch.pollIntervalMs,\n timeoutMs: this.config.batch.timeoutMs,\n concurrency: this.config.batch.concurrency,\n debug: this.config.debug,\n });\n\n return texts.map((_, i) => results.get(`chunk-${i}`) ?? []);\n }\n\n if (this.gemini) {\n const requests: GeminiBatchRequest[] = texts.map((text, i) => ({\n custom_id: `chunk-${i}`,\n content: { parts: [{ text }] },\n taskType: \"RETRIEVAL_DOCUMENT\",\n }));\n\n const results = await runGeminiEmbeddingBatches({\n gemini: this.gemini,\n source: \"minimem\",\n requests,\n wait: this.config.batch.wait,\n pollIntervalMs: this.config.batch.pollIntervalMs,\n timeoutMs: this.config.batch.timeoutMs,\n concurrency: this.config.batch.concurrency,\n debug: this.config.debug,\n });\n\n return texts.map((_, i) => results.get(`chunk-${i}`) ?? []);\n }\n\n throw new Error(\"Batch API not available for local embeddings\");\n }\n\n /**\n * Load embeddings from cache\n */\n private loadEmbeddingCache(hashes: string[]): Map<string, number[]> {\n const result = new Map<string, number[]>();\n if (!this.config.cache.enabled || hashes.length === 0) return result;\n\n const placeholders = hashes.map(() => \"?\").join(\",\");\n const rows = this.db\n .prepare(\n `SELECT hash, embedding FROM ${EMBEDDING_CACHE_TABLE}\n WHERE provider = ? AND model = ? AND provider_key = ? AND hash IN (${placeholders})`\n )\n .all(this.provider.id, this.provider.model, this.providerKey, ...hashes) as Array<{\n hash: string;\n embedding: string;\n }>;\n\n const now = Date.now();\n for (const row of rows) {\n result.set(row.hash, parseEmbedding(row.embedding));\n // Touch for LRU\n this.db\n .prepare(\n `UPDATE ${EMBEDDING_CACHE_TABLE} SET updated_at = ?\n WHERE provider = ? AND model = ? AND provider_key = ? AND hash = ?`\n )\n .run(now, this.provider.id, this.provider.model, this.providerKey, row.hash);\n }\n\n return result;\n }\n\n /**\n * Save embedding to cache\n */\n private upsertEmbeddingCache(hash: string, embedding: number[]): void {\n if (!this.config.cache.enabled) return;\n const now = Date.now();\n this.db\n .prepare(\n `INSERT OR REPLACE INTO ${EMBEDDING_CACHE_TABLE}\n (provider, model, provider_key, hash, embedding, dims, updated_at)\n VALUES (?, ?, ?, ?, ?, ?, ?)`\n )\n .run(\n this.provider.id,\n this.provider.model,\n this.providerKey,\n hash,\n JSON.stringify(embedding),\n embedding.length,\n now\n );\n }\n\n /**\n * Prune old cache entries if over limit\n */\n private pruneEmbeddingCacheIfNeeded(): void {\n if (!this.config.cache.enabled) return;\n const row = this.db\n .prepare(`SELECT COUNT(*) as count FROM ${EMBEDDING_CACHE_TABLE}`)\n .get() as { count: number };\n if (row.count <= this.config.cache.maxEntries) return;\n\n const excess = row.count - this.config.cache.maxEntries;\n this.db\n .prepare(\n `DELETE FROM ${EMBEDDING_CACHE_TABLE}\n WHERE rowid IN (\n SELECT rowid FROM ${EMBEDDING_CACHE_TABLE}\n ORDER BY updated_at ASC\n LIMIT ?\n )`\n )\n .run(excess);\n }\n}\n","/**\n * MemorySearcher - Handles search operations\n *\n * Responsible for:\n * - Executing vector searches\n * - Executing keyword (FTS) searches\n * - Merging results with hybrid scoring\n */\n\nimport type { DatabaseSync } from \"node:sqlite\";\n\nimport { bm25RankToScore, buildFtsQuery, mergeHybridResults } from \"../search/hybrid.js\";\nimport { searchKeyword, searchVector } from \"../search/search.js\";\nimport type { EmbeddingProvider } from \"../embeddings/embeddings.js\";\nimport type { DebugFn } from \"../internal.js\";\n\nconst SNIPPET_MAX_CHARS = 700;\nconst VECTOR_TABLE = \"chunks_vec\";\nconst FTS_TABLE = \"chunks_fts\";\nconst EMBEDDING_QUERY_TIMEOUT_REMOTE_MS = 60_000;\nconst EMBEDDING_QUERY_TIMEOUT_LOCAL_MS = 5 * 60_000;\n\nexport type SearchConfig = {\n hybrid: {\n enabled: boolean;\n vectorWeight: number;\n textWeight: number;\n candidateMultiplier: number;\n };\n query: {\n maxResults: number;\n minScore: number;\n };\n debug?: DebugFn;\n};\n\nexport type SearchResult = {\n path: string;\n startLine: number;\n endLine: number;\n score: number;\n snippet: string;\n};\n\n/**\n * MemorySearcher handles search queries against the indexed memory\n */\nexport class MemorySearcher {\n private readonly db: DatabaseSync;\n private readonly provider: EmbeddingProvider;\n private readonly config: SearchConfig;\n\n // State from parent\n private vectorState: {\n available: boolean;\n dims?: number;\n };\n private ftsAvailable: boolean;\n\n // Callback to ensure vector is ready\n private ensureVectorReadyFn?: (dims?: number) => Promise<boolean>;\n\n constructor(\n db: DatabaseSync,\n provider: EmbeddingProvider,\n config: SearchConfig,\n options?: {\n vectorState?: { available: boolean; dims?: number };\n ftsAvailable?: boolean;\n ensureVectorReady?: (dims?: number) => Promise<boolean>;\n }\n ) {\n this.db = db;\n this.provider = provider;\n this.config = config;\n this.vectorState = options?.vectorState ?? { available: false };\n this.ftsAvailable = options?.ftsAvailable ?? false;\n this.ensureVectorReadyFn = options?.ensureVectorReady;\n }\n\n /**\n * Update vector/FTS availability (called by parent when extensions load)\n */\n setVectorState(state: { available: boolean; dims?: number }): void {\n this.vectorState = state;\n }\n\n setFtsAvailable(available: boolean): void {\n this.ftsAvailable = available;\n }\n\n /**\n * Execute a search query\n */\n async search(\n query: string,\n opts?: { maxResults?: number; minScore?: number }\n ): Promise<SearchResult[]> {\n const cleaned = query.trim();\n if (!cleaned) return [];\n\n const minScore = opts?.minScore ?? this.config.query.minScore;\n const maxResults = opts?.maxResults ?? this.config.query.maxResults;\n const candidates = Math.min(\n 200,\n Math.max(1, Math.floor(maxResults * this.config.hybrid.candidateMultiplier))\n );\n\n const sourceFilter = { sql: \"\", params: [] as string[] };\n\n // Execute keyword search if hybrid is enabled\n const keywordResults =\n this.config.hybrid.enabled && this.ftsAvailable\n ? await searchKeyword({\n db: this.db,\n ftsTable: FTS_TABLE,\n providerModel: this.provider.model,\n query: cleaned,\n limit: candidates,\n snippetMaxChars: SNIPPET_MAX_CHARS,\n sourceFilter,\n buildFtsQuery,\n bm25RankToScore,\n }).catch(() => [])\n : [];\n\n // Embed query and execute vector search\n const queryVec = await this.embedQueryWithTimeout(cleaned);\n const hasVector = queryVec.some((v) => v !== 0);\n const vectorResults = hasVector\n ? await searchVector({\n db: this.db,\n vectorTable: VECTOR_TABLE,\n providerModel: this.provider.model,\n queryVec,\n limit: candidates,\n snippetMaxChars: SNIPPET_MAX_CHARS,\n ensureVectorReady: (dims) => this.ensureVectorReady(dims),\n sourceFilterVec: sourceFilter,\n sourceFilterChunks: sourceFilter,\n }).catch(() => [])\n : [];\n\n // If hybrid is disabled, return vector results only\n if (!this.config.hybrid.enabled) {\n return vectorResults\n .filter((entry) => entry.score >= minScore)\n .slice(0, maxResults)\n .map((r) => ({\n path: r.path,\n startLine: r.startLine,\n endLine: r.endLine,\n score: r.score,\n snippet: r.snippet,\n }));\n }\n\n // Merge results with hybrid scoring\n const merged = mergeHybridResults({\n vector: vectorResults.map((r) => ({\n id: r.id,\n path: r.path,\n startLine: r.startLine,\n endLine: r.endLine,\n source: r.source,\n snippet: r.snippet,\n vectorScore: r.score,\n })),\n keyword: keywordResults.map((r) => ({\n id: r.id,\n path: r.path,\n startLine: r.startLine,\n endLine: r.endLine,\n source: r.source,\n snippet: r.snippet,\n textScore: r.textScore,\n })),\n vectorWeight: this.config.hybrid.vectorWeight,\n textWeight: this.config.hybrid.textWeight,\n });\n\n return merged\n .filter((entry) => entry.score >= minScore)\n .slice(0, maxResults)\n .map((r) => ({\n path: r.path,\n startLine: r.startLine,\n endLine: r.endLine,\n score: r.score,\n snippet: r.snippet,\n }));\n }\n\n /**\n * Embed a query string with timeout\n */\n private async embedQueryWithTimeout(text: string): Promise<number[]> {\n const timeout =\n this.provider.id === \"local\"\n ? EMBEDDING_QUERY_TIMEOUT_LOCAL_MS\n : EMBEDDING_QUERY_TIMEOUT_REMOTE_MS;\n\n return Promise.race([\n this.provider.embedQuery(text),\n new Promise<number[]>((_, reject) =>\n setTimeout(() => reject(new Error(\"embedding query timeout\")), timeout)\n ),\n ]);\n }\n\n /**\n * Ensure vector extension is ready\n */\n private async ensureVectorReady(dims?: number): Promise<boolean> {\n if (this.vectorState.available) return true;\n if (this.ensureVectorReadyFn) {\n return this.ensureVectorReadyFn(dims);\n }\n return false;\n }\n}\n"],"mappings":"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","names":["path","path","payload","provider","client","text","runWithConcurrency","path","path","randomUUID","fs","path","META_KEY","EMBEDDING_CACHE_TABLE","VECTOR_TABLE","FTS_TABLE","EMBEDDING_RETRY_MAX_ATTEMPTS","EMBEDDING_RETRY_BASE_DELAY_MS","EMBEDDING_RETRY_MAX_DELAY_MS","path","fs","randomUUID","SNIPPET_MAX_CHARS","VECTOR_TABLE","FTS_TABLE","EMBEDDING_QUERY_TIMEOUT_REMOTE_MS","EMBEDDING_QUERY_TIMEOUT_LOCAL_MS"]}
|
|
1
|
+
{"version":3,"sources":["../src/minimem.ts","../src/search/hybrid.ts","../src/search/search.ts","../src/db/schema.ts","../src/search/graph.ts","../src/db/sqlite-vec.ts","../src/embeddings/embeddings.ts","../src/embeddings/batch-openai.ts","../src/embeddings/batch-gemini.ts","../src/server/tools.ts","../src/server/mcp.ts","../src/core/indexer.ts","../src/core/searcher.ts","../src/store/store-graph.ts","../src/store/manifest.ts","../src/store/materialize.ts"],"sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport fs from \"node:fs/promises\";\nimport fsSync from \"node:fs\";\nimport path from \"node:path\";\nimport { DatabaseSync } from \"node:sqlite\";\nimport chokidar, { type FSWatcher } from \"chokidar\";\n\nimport {\n buildFileEntry,\n chunkMarkdown,\n ensureDir,\n extractChunkMetadata,\n hashText,\n listMemoryFiles,\n logError,\n type MemoryChunk,\n type MemoryFileEntry,\n parseEmbedding,\n vectorToBlob,\n} from \"./internal.js\";\nimport { bm25RankToScore, buildFtsQuery, mergeHybridResults } from \"./search/hybrid.js\";\nimport { searchKeyword, searchVector, buildKnowledgeFilterSql } from \"./search/search.js\";\nimport { ensureMemoryIndexSchema } from \"./db/schema.js\";\nimport { parseFrontmatter, type MemoryFrontmatter, type KnowledgeLink } from \"./session.js\";\nimport {\n getLinksFrom,\n getLinksTo,\n getNeighbors,\n getPathBetween,\n type GraphLink,\n type GraphNeighbor,\n} from \"./search/graph.js\";\nimport { loadSqliteVecExtension } from \"./db/sqlite-vec.js\";\nimport {\n createEmbeddingProvider,\n type EmbeddingProvider,\n type EmbeddingProviderOptions,\n type OpenAiEmbeddingClient,\n type GeminiEmbeddingClient,\n} from \"./embeddings/embeddings.js\";\nimport { runOpenAiEmbeddingBatches, type OpenAiBatchRequest, OPENAI_BATCH_ENDPOINT } from \"./embeddings/batch-openai.js\";\nimport { runGeminiEmbeddingBatches, type GeminiBatchRequest } from \"./embeddings/batch-gemini.js\";\n\n/**\n * Resolve which subdirectory holds minimem config/data.\n * Priority: MINIMEM_CONFIG_DIR env var > contained (config.json at root) > .swarm/minimem > .minimem\n */\nfunction resolveMinimemSubdir(memoryDir: string): string {\n const envDir = process.env.MINIMEM_CONFIG_DIR;\n if (envDir) return envDir;\n // Contained layout: config.json directly in memoryDir (no subdir)\n if (fsSync.existsSync(path.join(memoryDir, \"config.json\"))) return \".\";\n const swarmDir = path.join(memoryDir, \".swarm\", \"minimem\");\n if (fsSync.existsSync(path.join(swarmDir, \"config.json\"))) return path.join(\".swarm\", \"minimem\");\n return \".minimem\";\n}\n\nconst META_KEY = \"memory_index_meta_v1\";\nconst SNIPPET_MAX_CHARS = 700;\nconst VECTOR_TABLE = \"chunks_vec\";\nconst FTS_TABLE = \"chunks_fts\";\nconst EMBEDDING_CACHE_TABLE = \"embedding_cache\";\nconst EMBEDDING_BATCH_MAX_TOKENS = 8000;\nconst EMBEDDING_APPROX_CHARS_PER_TOKEN = 1;\nconst EMBEDDING_INDEX_CONCURRENCY = 4;\nconst EMBEDDING_RETRY_MAX_ATTEMPTS = 3;\nconst EMBEDDING_RETRY_BASE_DELAY_MS = 500;\nconst EMBEDDING_RETRY_MAX_DELAY_MS = 8000;\nconst VECTOR_LOAD_TIMEOUT_MS = 30_000;\nconst EMBEDDING_QUERY_TIMEOUT_REMOTE_MS = 60_000;\nconst EMBEDDING_QUERY_TIMEOUT_LOCAL_MS = 5 * 60_000;\n\nexport type MinimemConfig = {\n /** Directory containing memory files (MEMORY.md, memory/*.md) */\n memoryDir: string;\n /** Path to SQLite database. Defaults to memoryDir/.minimem/index.db */\n dbPath?: string;\n /** Embedding provider options */\n embedding: EmbeddingProviderOptions;\n /** Chunking configuration */\n chunking?: {\n /** Tokens per chunk (default: 256) */\n tokens?: number;\n /** Overlap tokens between chunks (default: 32) */\n overlap?: number;\n };\n /** Embedding cache configuration */\n cache?: {\n /** Enable embedding cache (default: true) */\n enabled?: boolean;\n /** Max cache entries before LRU pruning (default: 10000) */\n maxEntries?: number;\n };\n /** Hybrid search configuration */\n hybrid?: {\n /** Enable hybrid search (default: true) */\n enabled?: boolean;\n /** Weight for vector search (default: 0.7) */\n vectorWeight?: number;\n /** Weight for keyword search (default: 0.3) */\n textWeight?: number;\n /** Candidate multiplier for search (default: 2.0) */\n candidateMultiplier?: number;\n };\n /** Query configuration */\n query?: {\n /** Max results (default: 10) */\n maxResults?: number;\n /** Min score threshold (default: 0.3) */\n minScore?: number;\n };\n /** File watching configuration */\n watch?: {\n /** Enable file watching (default: true) */\n enabled?: boolean;\n /** Debounce delay in ms (default: 1000) */\n debounceMs?: number;\n };\n /** Batch embedding configuration */\n batch?: {\n /** Enable batch embedding API (default: false) */\n enabled?: boolean;\n /** Wait for batch completion (default: true) */\n wait?: boolean;\n /** Concurrent batch requests (default: 2) */\n concurrency?: number;\n /** Poll interval in ms (default: 2000) */\n pollIntervalMs?: number;\n /** Timeout in ms (default: 60 minutes) */\n timeoutMs?: number;\n };\n /** sqlite-vec extension path (optional) */\n vectorExtensionPath?: string;\n /** Debug logging function */\n debug?: (message: string, data?: Record<string, unknown>) => void;\n};\n\nexport type MinimemSearchResult = {\n path: string;\n startLine: number;\n endLine: number;\n score: number;\n snippet: string;\n};\n\ntype MemoryIndexMeta = {\n model: string;\n provider: string;\n providerKey?: string;\n chunkTokens: number;\n chunkOverlap: number;\n vectorDims?: number;\n};\n\nexport class Minimem {\n private readonly memoryDir: string;\n private readonly dbPath: string;\n private readonly chunking: { tokens: number; overlap: number };\n private readonly cache: { enabled: boolean; maxEntries: number };\n private readonly hybrid: {\n enabled: boolean;\n vectorWeight: number;\n textWeight: number;\n candidateMultiplier: number;\n };\n private readonly queryConfig: { maxResults: number; minScore: number };\n private readonly watchConfig: { enabled: boolean; debounceMs: number };\n private readonly batchConfig: {\n enabled: boolean;\n wait: boolean;\n concurrency: number;\n pollIntervalMs: number;\n timeoutMs: number;\n };\n private readonly vectorExtensionPath?: string;\n private readonly debug?: (message: string, data?: Record<string, unknown>) => void;\n\n private provider!: EmbeddingProvider;\n private openAi?: OpenAiEmbeddingClient;\n private gemini?: GeminiEmbeddingClient;\n private providerKey: string = \"\";\n private providerFallbackReason?: string;\n private db!: DatabaseSync;\n\n private readonly vector: {\n enabled: boolean;\n available: boolean | null;\n extensionPath?: string;\n loadError?: string;\n dims?: number;\n };\n private readonly fts: {\n enabled: boolean;\n available: boolean;\n loadError?: string;\n };\n\n private vectorReady: Promise<boolean> | null = null;\n private watcher: FSWatcher | null = null;\n private watchTimer: NodeJS.Timeout | null = null;\n private closed = false;\n private dirty = true;\n private syncing: Promise<void> | null = null;\n private syncLock = false;\n private embeddingOptions: EmbeddingProviderOptions;\n\n private constructor(config: MinimemConfig) {\n this.memoryDir = path.resolve(config.memoryDir);\n this.dbPath = config.dbPath ?? path.join(this.memoryDir, resolveMinimemSubdir(this.memoryDir), \"index.db\");\n this.chunking = {\n tokens: config.chunking?.tokens ?? 256,\n overlap: config.chunking?.overlap ?? 32,\n };\n this.cache = {\n enabled: config.cache?.enabled ?? true,\n maxEntries: config.cache?.maxEntries ?? 10000,\n };\n this.hybrid = {\n enabled: config.hybrid?.enabled ?? true,\n vectorWeight: config.hybrid?.vectorWeight ?? 0.7,\n textWeight: config.hybrid?.textWeight ?? 0.3,\n candidateMultiplier: config.hybrid?.candidateMultiplier ?? 2.0,\n };\n this.queryConfig = {\n maxResults: config.query?.maxResults ?? 10,\n minScore: config.query?.minScore ?? 0.3,\n };\n this.watchConfig = {\n enabled: config.watch?.enabled ?? true,\n debounceMs: config.watch?.debounceMs ?? 1000,\n };\n this.batchConfig = {\n enabled: config.batch?.enabled ?? false,\n wait: config.batch?.wait ?? true,\n concurrency: config.batch?.concurrency ?? 2,\n pollIntervalMs: config.batch?.pollIntervalMs ?? 2000,\n timeoutMs: config.batch?.timeoutMs ?? 60 * 60 * 1000,\n };\n this.vectorExtensionPath = config.vectorExtensionPath;\n this.debug = config.debug;\n this.embeddingOptions = config.embedding;\n\n this.vector = {\n enabled: true,\n available: null,\n extensionPath: this.vectorExtensionPath,\n };\n this.fts = { enabled: this.hybrid.enabled, available: false };\n }\n\n static async create(config: MinimemConfig): Promise<Minimem> {\n const instance = new Minimem(config);\n await instance.initialize();\n return instance;\n }\n\n private async initialize(): Promise<void> {\n // Create embedding provider\n const providerResult = await createEmbeddingProvider(this.embeddingOptions);\n this.provider = providerResult.provider;\n this.openAi = providerResult.openAi;\n this.gemini = providerResult.gemini;\n this.providerKey = this.computeProviderKey();\n this.providerFallbackReason = providerResult.fallbackReason;\n\n // Log warning if in BM25-only fallback mode\n if (this.provider.id === \"none\") {\n this.debug?.(\"Running in BM25-only mode (no embedding API available)\");\n }\n\n // Open database\n this.db = this.openDatabase();\n this.ensureSchema();\n\n // Check for existing vector dims\n const meta = this.readMeta();\n if (meta?.vectorDims) {\n this.vector.dims = meta.vectorDims;\n }\n\n // Start file watcher\n if (this.watchConfig.enabled) {\n this.ensureWatcher();\n }\n }\n\n private openDatabase(): DatabaseSync {\n const dbDir = path.dirname(this.dbPath);\n ensureDir(dbDir);\n return new DatabaseSync(this.dbPath);\n }\n\n private ensureSchema(): void {\n const result = ensureMemoryIndexSchema({\n db: this.db,\n embeddingCacheTable: EMBEDDING_CACHE_TABLE,\n ftsTable: FTS_TABLE,\n ftsEnabled: this.fts.enabled,\n });\n this.fts.available = result.ftsAvailable;\n if (result.ftsError) {\n this.fts.loadError = result.ftsError;\n }\n }\n\n private computeProviderKey(): string {\n const parts: string[] = [this.provider.id, this.provider.model];\n if (this.openAi) {\n parts.push(this.openAi.baseUrl);\n }\n if (this.gemini) {\n parts.push(this.gemini.baseUrl);\n }\n return hashText(parts.join(\":\"));\n }\n\n private readMeta(): MemoryIndexMeta | null {\n try {\n const row = this.db.prepare(`SELECT value FROM meta WHERE key = ?`).get(META_KEY) as\n | { value: string }\n | undefined;\n if (!row?.value) return null;\n return JSON.parse(row.value) as MemoryIndexMeta;\n } catch {\n return null;\n }\n }\n\n private writeMeta(meta: MemoryIndexMeta): void {\n this.db\n .prepare(`INSERT OR REPLACE INTO meta (key, value) VALUES (?, ?)`)\n .run(META_KEY, JSON.stringify(meta));\n }\n\n private ensureWatcher(): void {\n if (this.watcher) return;\n const memorySubDir = path.join(this.memoryDir, \"memory\");\n const memoryFile = path.join(this.memoryDir, \"MEMORY.md\");\n\n this.watcher = chokidar.watch([memoryFile, memorySubDir], {\n ignoreInitial: true,\n persistent: true,\n awaitWriteFinish: { stabilityThreshold: 200, pollInterval: 50 },\n });\n\n const scheduleSync = () => {\n this.dirty = true;\n if (this.watchTimer) clearTimeout(this.watchTimer);\n this.watchTimer = setTimeout(() => {\n void this.sync({ reason: \"watch\" }).catch((err) => {\n this.debug?.(`memory sync failed (watch): ${String(err)}`);\n });\n }, this.watchConfig.debounceMs);\n };\n\n this.watcher.on(\"add\", scheduleSync);\n this.watcher.on(\"change\", scheduleSync);\n this.watcher.on(\"unlink\", scheduleSync);\n }\n\n /**\n * Check if the index is stale by comparing file mtimes against stored values.\n * This is a lightweight check (stat calls only, no file reads).\n */\n private async isStale(): Promise<boolean> {\n try {\n const files = await listMemoryFiles(this.memoryDir);\n\n // Get stored file records\n const stored = this.db\n .prepare(`SELECT path, mtime FROM files WHERE source = ?`)\n .all(\"memory\") as Array<{ path: string; mtime: number }>;\n\n // Quick check: different file count means stale\n if (files.length !== stored.length) {\n this.debug?.(`Stale: file count changed (${stored.length} -> ${files.length})`);\n return true;\n }\n\n // Build lookup map of stored mtimes\n const storedMap = new Map(stored.map((f) => [f.path, f.mtime]));\n\n // Check each file's mtime against stored value\n for (const absPath of files) {\n const relPath = path.relative(this.memoryDir, absPath).replace(/\\\\/g, \"/\");\n const storedMtime = storedMap.get(relPath);\n\n // File not in index = stale\n if (storedMtime === undefined) {\n this.debug?.(`Stale: new file ${relPath}`);\n return true;\n }\n\n // Check mtime\n const stat = await fs.stat(absPath);\n const currentMtime = Math.floor(stat.mtimeMs);\n if (currentMtime !== storedMtime) {\n this.debug?.(`Stale: mtime changed for ${relPath}`);\n return true;\n }\n }\n\n return false;\n } catch (err) {\n // On error, assume stale to be safe\n this.debug?.(`Stale check failed: ${String(err)}`);\n return true;\n }\n }\n\n async search(\n query: string,\n opts?: { maxResults?: number; minScore?: number; type?: string },\n ): Promise<MinimemSearchResult[]> {\n // Check staleness: use dirty flag if watcher is on, otherwise check mtimes\n if (this.dirty || (!this.watchConfig.enabled && (await this.isStale()))) {\n await this.sync({ reason: \"search\" });\n }\n\n const cleaned = query.trim();\n if (!cleaned) return [];\n\n const minScore = opts?.minScore ?? this.queryConfig.minScore;\n const maxResults = opts?.maxResults ?? this.queryConfig.maxResults;\n const candidates = Math.min(\n 200,\n Math.max(1, Math.floor(maxResults * this.hybrid.candidateMultiplier)),\n );\n\n const sourceFilter = { sql: \"\", params: [] as string[] };\n\n const keywordResults = this.hybrid.enabled && this.fts.available\n ? await searchKeyword({\n db: this.db,\n ftsTable: FTS_TABLE,\n providerModel: this.provider.model,\n query: cleaned,\n limit: candidates,\n snippetMaxChars: SNIPPET_MAX_CHARS,\n sourceFilter,\n buildFtsQuery,\n bm25RankToScore,\n }).catch(() => [])\n : [];\n\n const queryVec = await this.embedQueryWithTimeout(cleaned);\n const hasVector = queryVec.some((v) => v !== 0);\n const vectorResults = hasVector\n ? await searchVector({\n db: this.db,\n vectorTable: VECTOR_TABLE,\n providerModel: this.provider.model,\n queryVec,\n limit: candidates,\n snippetMaxChars: SNIPPET_MAX_CHARS,\n ensureVectorReady: (dims) => this.ensureVectorReady(dims),\n sourceFilterVec: sourceFilter,\n sourceFilterChunks: sourceFilter,\n }).catch(() => [])\n : [];\n\n // Apply type filter if specified\n const typeFilterFn = opts?.type\n ? (id: string) => {\n const row = this.db\n .prepare(`SELECT type FROM chunks WHERE id = ?`)\n .get(id) as { type: string | null } | undefined;\n return row?.type === opts.type;\n }\n : undefined;\n\n if (!this.hybrid.enabled) {\n let results = vectorResults;\n if (typeFilterFn) results = results.filter((r) => typeFilterFn(r.id));\n return results\n .filter((entry) => entry.score >= minScore)\n .slice(0, maxResults)\n .map((r) => ({\n path: r.path,\n startLine: r.startLine,\n endLine: r.endLine,\n score: r.score,\n snippet: r.snippet,\n }));\n }\n\n let filteredVector = vectorResults;\n let filteredKeyword = keywordResults;\n if (typeFilterFn) {\n filteredVector = vectorResults.filter((r) => typeFilterFn(r.id));\n filteredKeyword = keywordResults.filter((r) => typeFilterFn(r.id));\n }\n\n const merged = mergeHybridResults({\n vector: filteredVector.map((r) => ({\n id: r.id,\n path: r.path,\n startLine: r.startLine,\n endLine: r.endLine,\n source: r.source,\n snippet: r.snippet,\n vectorScore: r.score,\n })),\n keyword: filteredKeyword.map((r) => ({\n id: r.id,\n path: r.path,\n startLine: r.startLine,\n endLine: r.endLine,\n source: r.source,\n snippet: r.snippet,\n textScore: r.textScore,\n })),\n vectorWeight: this.hybrid.vectorWeight,\n textWeight: this.hybrid.textWeight,\n });\n\n return merged\n .filter((entry) => entry.score >= minScore)\n .slice(0, maxResults)\n .map((r) => ({\n path: r.path,\n startLine: r.startLine,\n endLine: r.endLine,\n score: r.score,\n snippet: r.snippet,\n }));\n }\n\n async sync(opts?: { reason?: string; force?: boolean }): Promise<void> {\n // If a sync is already running, wait for it instead of starting another\n if (this.syncing) {\n await this.syncing;\n return;\n }\n\n // Use a synchronous flag to prevent the race window between\n // checking this.syncing and assigning to it\n if (this.syncLock) {\n return;\n }\n this.syncLock = true;\n\n this.syncing = this.runSync(opts);\n try {\n await this.syncing;\n } finally {\n this.syncing = null;\n this.syncLock = false;\n }\n }\n\n private async runSync(opts?: { reason?: string; force?: boolean }): Promise<void> {\n this.debug?.(`memory sync starting`, { reason: opts?.reason });\n\n await this.ensureVectorReady();\n const meta = this.readMeta();\n const needsFullReindex =\n opts?.force ||\n !meta ||\n meta.model !== this.provider.model ||\n meta.provider !== this.provider.id ||\n meta.providerKey !== this.providerKey ||\n meta.chunkTokens !== this.chunking.tokens ||\n meta.chunkOverlap !== this.chunking.overlap ||\n (this.vector.available && !meta?.vectorDims);\n\n const files = await listMemoryFiles(this.memoryDir);\n const activePaths = new Set<string>();\n\n for (const absPath of files) {\n const entry = await buildFileEntry(absPath, this.memoryDir);\n activePaths.add(entry.path);\n\n const record = this.db\n .prepare(`SELECT hash FROM files WHERE path = ? AND source = ?`)\n .get(entry.path, \"memory\") as { hash: string } | undefined;\n\n if (!needsFullReindex && record?.hash === entry.hash) {\n continue;\n }\n\n await this.indexFile(entry);\n }\n\n // Delete stale entries\n const staleRows = this.db\n .prepare(`SELECT path FROM files WHERE source = ?`)\n .all(\"memory\") as Array<{ path: string }>;\n\n for (const stale of staleRows) {\n if (activePaths.has(stale.path)) continue;\n this.db.prepare(`DELETE FROM files WHERE path = ? AND source = ?`).run(stale.path, \"memory\");\n try {\n this.db\n .prepare(\n `DELETE FROM ${VECTOR_TABLE} WHERE id IN (SELECT id FROM chunks WHERE path = ? AND source = ?)`,\n )\n .run(stale.path, \"memory\");\n } catch (err) {\n logError(\"deleteStaleVectorEntries\", err, this.debug);\n }\n this.db.prepare(`DELETE FROM chunks WHERE path = ? AND source = ?`).run(stale.path, \"memory\");\n this.db.prepare(`DELETE FROM knowledge_links WHERE source_path = ?`).run(stale.path);\n if (this.fts.enabled && this.fts.available) {\n try {\n this.db\n .prepare(`DELETE FROM ${FTS_TABLE} WHERE path = ? AND source = ? AND model = ?`)\n .run(stale.path, \"memory\", this.provider.model);\n } catch (err) {\n logError(\"deleteStaleFtsEntries\", err, this.debug);\n }\n }\n }\n\n // Write meta\n this.writeMeta({\n model: this.provider.model,\n provider: this.provider.id,\n providerKey: this.providerKey,\n chunkTokens: this.chunking.tokens,\n chunkOverlap: this.chunking.overlap,\n vectorDims: this.vector.dims,\n });\n\n // Prune embedding cache\n this.pruneEmbeddingCacheIfNeeded();\n\n this.dirty = false;\n this.debug?.(`memory sync complete`, { files: files.length });\n }\n\n private async indexFile(entry: MemoryFileEntry): Promise<void> {\n const content = await fs.readFile(entry.absPath, \"utf-8\");\n const chunks = chunkMarkdown(content, this.chunking);\n\n // Extract knowledge frontmatter\n const { frontmatter } = parseFrontmatter(content);\n const knowledgeType = frontmatter?.type ?? null;\n const knowledgeId = frontmatter?.id ?? null;\n const domains = frontmatter?.domain ?? null;\n const entities = frontmatter?.entities ?? null;\n const confidence = frontmatter?.confidence ?? null;\n const links = frontmatter?.links ?? null;\n\n // Get embeddings\n const embeddings = await this.embedChunks(chunks);\n\n // Update files table\n this.db\n .prepare(\n `INSERT OR REPLACE INTO files (path, source, hash, mtime, size) VALUES (?, ?, ?, ?, ?)`,\n )\n .run(entry.path, \"memory\", entry.hash, Math.floor(entry.mtimeMs), entry.size);\n\n // Delete old chunks for this file\n try {\n this.db\n .prepare(\n `DELETE FROM ${VECTOR_TABLE} WHERE id IN (SELECT id FROM chunks WHERE path = ? AND source = ?)`,\n )\n .run(entry.path, \"memory\");\n } catch (err) {\n logError(\"deleteOldVectorChunks\", err, this.debug);\n }\n this.db.prepare(`DELETE FROM chunks WHERE path = ? AND source = ?`).run(entry.path, \"memory\");\n if (this.fts.enabled && this.fts.available) {\n try {\n this.db\n .prepare(`DELETE FROM ${FTS_TABLE} WHERE path = ? AND source = ? AND model = ?`)\n .run(entry.path, \"memory\", this.provider.model);\n } catch (err) {\n logError(\"deleteOldFtsChunks\", err, this.debug);\n }\n }\n\n // Delete old knowledge links for this file path on re-index\n this.db.prepare(`DELETE FROM knowledge_links WHERE source_path = ?`).run(entry.path);\n\n // Insert new chunks\n const now = Date.now();\n for (let i = 0; i < chunks.length; i++) {\n const chunk = chunks[i];\n const embedding = embeddings[i] ?? [];\n const chunkId = randomUUID();\n const meta = extractChunkMetadata(chunk.text);\n\n this.db\n .prepare(\n `INSERT INTO chunks (id, path, source, start_line, end_line, hash, model, text, embedding, updated_at, type, knowledge_type, knowledge_id, domains, entities, confidence)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,\n )\n .run(\n chunkId,\n entry.path,\n \"memory\",\n chunk.startLine,\n chunk.endLine,\n chunk.hash,\n this.provider.model,\n chunk.text,\n JSON.stringify(embedding),\n now,\n meta.type ?? null,\n knowledgeType,\n knowledgeId,\n domains ? JSON.stringify(domains) : null,\n entities ? JSON.stringify(entities) : null,\n confidence,\n );\n\n // Insert into vector table if available\n if (this.vector.available && embedding.length > 0) {\n if (!this.vector.dims) {\n this.vector.dims = embedding.length;\n this.ensureVectorTable(embedding.length);\n }\n try {\n this.db\n .prepare(`INSERT INTO ${VECTOR_TABLE} (id, embedding) VALUES (?, ?)`)\n .run(chunkId, vectorToBlob(embedding));\n } catch (err) {\n logError(\"insertVectorChunk\", err, this.debug);\n }\n }\n\n // Insert into FTS table if available\n if (this.fts.enabled && this.fts.available) {\n try {\n this.db\n .prepare(\n `INSERT INTO ${FTS_TABLE} (text, id, path, source, model, start_line, end_line)\n VALUES (?, ?, ?, ?, ?, ?, ?)`,\n )\n .run(\n chunk.text,\n chunkId,\n entry.path,\n \"memory\",\n this.provider.model,\n chunk.startLine,\n chunk.endLine,\n );\n } catch (err) {\n logError(\"insertFtsChunk\", err, this.debug);\n }\n }\n }\n\n // Upsert knowledge links if present\n if (links && knowledgeId) {\n const upsertLink = this.db.prepare(\n `INSERT OR REPLACE INTO knowledge_links (from_id, to_id, relation, layer, weight, source_path, created_at)\n VALUES (?, ?, ?, ?, ?, ?, ?)`,\n );\n for (const link of links) {\n upsertLink.run(\n knowledgeId,\n link.target,\n link.relation,\n link.layer ?? null,\n 0.5,\n entry.path,\n now,\n );\n }\n }\n }\n\n private async embedChunks(chunks: MemoryChunk[]): Promise<number[][]> {\n if (chunks.length === 0) return [];\n\n const hashes = chunks.map((c) => c.hash);\n const cached = this.loadEmbeddingCache(hashes);\n const missing: Array<{ index: number; chunk: MemoryChunk }> = [];\n\n for (let i = 0; i < chunks.length; i++) {\n if (!cached.has(hashes[i])) {\n missing.push({ index: i, chunk: chunks[i] });\n }\n }\n\n if (missing.length > 0) {\n const texts = missing.map((m) => m.chunk.text);\n const newEmbeddings = await this.embedBatchWithRetry(texts);\n\n for (let i = 0; i < missing.length; i++) {\n const hash = missing[i].chunk.hash;\n const embedding = newEmbeddings[i] ?? [];\n cached.set(hash, embedding);\n this.upsertEmbeddingCache(hash, embedding);\n }\n }\n\n return hashes.map((h) => cached.get(h) ?? []);\n }\n\n private async embedBatchWithRetry(texts: string[]): Promise<number[][]> {\n if (texts.length === 0) return [];\n\n // Try batch API first if enabled\n if (this.batchConfig.enabled) {\n try {\n return await this.embedWithBatchApi(texts);\n } catch (err) {\n this.debug?.(`batch embedding failed, falling back to direct: ${String(err)}`);\n }\n }\n\n // Fall back to direct embedding\n let lastError: Error | null = null;\n for (let attempt = 0; attempt < EMBEDDING_RETRY_MAX_ATTEMPTS; attempt++) {\n try {\n return await this.provider.embedBatch(texts);\n } catch (err) {\n lastError = err instanceof Error ? err : new Error(String(err));\n if (attempt < EMBEDDING_RETRY_MAX_ATTEMPTS - 1) {\n const delay = Math.min(\n EMBEDDING_RETRY_MAX_DELAY_MS,\n EMBEDDING_RETRY_BASE_DELAY_MS * Math.pow(2, attempt),\n );\n await new Promise((resolve) => setTimeout(resolve, delay));\n }\n }\n }\n throw lastError;\n }\n\n private async embedWithBatchApi(texts: string[]): Promise<number[][]> {\n if (this.openAi) {\n const requests: OpenAiBatchRequest[] = texts.map((text, i) => ({\n custom_id: `chunk-${i}`,\n method: \"POST\",\n url: OPENAI_BATCH_ENDPOINT,\n body: { model: this.openAi!.model, input: text },\n }));\n\n const results = await runOpenAiEmbeddingBatches({\n openAi: this.openAi,\n source: \"minimem\",\n requests,\n wait: this.batchConfig.wait,\n pollIntervalMs: this.batchConfig.pollIntervalMs,\n timeoutMs: this.batchConfig.timeoutMs,\n concurrency: this.batchConfig.concurrency,\n debug: this.debug,\n });\n\n return texts.map((_, i) => results.get(`chunk-${i}`) ?? []);\n }\n\n if (this.gemini) {\n const requests: GeminiBatchRequest[] = texts.map((text, i) => ({\n custom_id: `chunk-${i}`,\n content: { parts: [{ text }] },\n taskType: \"RETRIEVAL_DOCUMENT\",\n }));\n\n const results = await runGeminiEmbeddingBatches({\n gemini: this.gemini,\n source: \"minimem\",\n requests,\n wait: this.batchConfig.wait,\n pollIntervalMs: this.batchConfig.pollIntervalMs,\n timeoutMs: this.batchConfig.timeoutMs,\n concurrency: this.batchConfig.concurrency,\n debug: this.debug,\n });\n\n return texts.map((_, i) => results.get(`chunk-${i}`) ?? []);\n }\n\n throw new Error(\"Batch API not available for local embeddings\");\n }\n\n private async embedQueryWithTimeout(text: string): Promise<number[]> {\n const timeout =\n this.provider.id === \"local\" ? EMBEDDING_QUERY_TIMEOUT_LOCAL_MS : EMBEDDING_QUERY_TIMEOUT_REMOTE_MS;\n\n const ac = new AbortController();\n const timer = setTimeout(() => ac.abort(), timeout);\n\n try {\n const result = await Promise.race([\n this.provider.embedQuery(text),\n new Promise<number[]>((_, reject) => {\n ac.signal.addEventListener(\"abort\", () =>\n reject(new Error(\"embedding query timeout\")),\n );\n }),\n ]);\n return result;\n } finally {\n clearTimeout(timer);\n }\n }\n\n private loadEmbeddingCache(hashes: string[]): Map<string, number[]> {\n const result = new Map<string, number[]>();\n if (!this.cache.enabled || hashes.length === 0) return result;\n\n const placeholders = hashes.map(() => \"?\").join(\",\");\n const rows = this.db\n .prepare(\n `SELECT hash, embedding FROM ${EMBEDDING_CACHE_TABLE}\n WHERE provider = ? AND model = ? AND provider_key = ? AND hash IN (${placeholders})`,\n )\n .all(this.provider.id, this.provider.model, this.providerKey, ...hashes) as Array<{\n hash: string;\n embedding: string;\n }>;\n\n const now = Date.now();\n for (const row of rows) {\n result.set(row.hash, parseEmbedding(row.embedding));\n // Touch for LRU\n this.db\n .prepare(\n `UPDATE ${EMBEDDING_CACHE_TABLE} SET updated_at = ?\n WHERE provider = ? AND model = ? AND provider_key = ? AND hash = ?`,\n )\n .run(now, this.provider.id, this.provider.model, this.providerKey, row.hash);\n }\n\n return result;\n }\n\n private upsertEmbeddingCache(hash: string, embedding: number[]): void {\n if (!this.cache.enabled) return;\n const now = Date.now();\n this.db\n .prepare(\n `INSERT OR REPLACE INTO ${EMBEDDING_CACHE_TABLE}\n (provider, model, provider_key, hash, embedding, dims, updated_at)\n VALUES (?, ?, ?, ?, ?, ?, ?)`,\n )\n .run(\n this.provider.id,\n this.provider.model,\n this.providerKey,\n hash,\n JSON.stringify(embedding),\n embedding.length,\n now,\n );\n }\n\n private pruneEmbeddingCacheIfNeeded(): void {\n if (!this.cache.enabled) return;\n const row = this.db\n .prepare(`SELECT COUNT(*) as count FROM ${EMBEDDING_CACHE_TABLE}`)\n .get() as { count: number };\n if (row.count <= this.cache.maxEntries) return;\n\n const excess = row.count - this.cache.maxEntries;\n this.db\n .prepare(\n `DELETE FROM ${EMBEDDING_CACHE_TABLE}\n WHERE rowid IN (\n SELECT rowid FROM ${EMBEDDING_CACHE_TABLE}\n ORDER BY updated_at ASC\n LIMIT ?\n )`,\n )\n .run(excess);\n }\n\n private async ensureVectorReady(dimensions?: number): Promise<boolean> {\n if (this.vector.available === true) return true;\n if (this.vector.available === false) return false;\n\n if (!this.vectorReady) {\n this.vectorReady = this.loadVectorExtension();\n }\n\n const ready = await this.vectorReady;\n if (ready && dimensions && !this.vector.dims) {\n this.vector.dims = dimensions;\n this.ensureVectorTable(dimensions);\n }\n return ready;\n }\n\n private async loadVectorExtension(): Promise<boolean> {\n const result = await loadSqliteVecExtension({\n db: this.db,\n extensionPath: this.vectorExtensionPath,\n });\n\n this.vector.available = result.ok;\n if (result.error) {\n this.vector.loadError = result.error;\n this.debug?.(`sqlite-vec load failed: ${result.error}`);\n }\n if (result.extensionPath) {\n this.vector.extensionPath = result.extensionPath;\n }\n\n return result.ok;\n }\n\n private ensureVectorTable(dimensions: number): void {\n if (!this.vector.available) return;\n try {\n this.db.exec(\n `CREATE VIRTUAL TABLE IF NOT EXISTS ${VECTOR_TABLE} USING vec0(\n id TEXT PRIMARY KEY,\n embedding FLOAT[${dimensions}]\n )`,\n );\n } catch (err) {\n this.debug?.(`vector table creation failed: ${String(err)}`);\n }\n }\n\n async readFile(relativePath: string): Promise<string | null> {\n const absPath = path.join(this.memoryDir, relativePath);\n try {\n return await fs.readFile(absPath, \"utf-8\");\n } catch {\n return null;\n }\n }\n\n /**\n * Read specific lines from a memory file\n */\n async readLines(\n relativePath: string,\n opts?: { from?: number; lines?: number },\n ): Promise<{ content: string; startLine: number; endLine: number } | null> {\n const content = await this.readFile(relativePath);\n if (content === null) return null;\n\n const allLines = content.split(\"\\n\");\n const from = Math.max(1, opts?.from ?? 1);\n const lines = opts?.lines ?? allLines.length;\n\n const startIdx = from - 1;\n const endIdx = Math.min(startIdx + lines, allLines.length);\n const selectedLines = allLines.slice(startIdx, endIdx);\n\n return {\n content: selectedLines.join(\"\\n\"),\n startLine: from,\n endLine: startIdx + selectedLines.length,\n };\n }\n\n /**\n * Write content to a memory file (creates or overwrites)\n */\n async writeFile(relativePath: string, content: string): Promise<void> {\n this.validateMemoryPath(relativePath);\n const absPath = path.join(this.memoryDir, relativePath);\n const dir = path.dirname(absPath);\n await fs.mkdir(dir, { recursive: true });\n await fs.writeFile(absPath, content, \"utf-8\");\n this.dirty = true;\n this.debug?.(`memory write: ${relativePath}`);\n }\n\n /**\n * Append content to a memory file (creates if doesn't exist)\n */\n async appendFile(relativePath: string, content: string): Promise<void> {\n this.validateMemoryPath(relativePath);\n const absPath = path.join(this.memoryDir, relativePath);\n const dir = path.dirname(absPath);\n await fs.mkdir(dir, { recursive: true });\n\n // Ensure newline separation\n let toAppend = content;\n try {\n const existing = await fs.readFile(absPath, \"utf-8\");\n if (existing.length > 0 && !existing.endsWith(\"\\n\")) {\n toAppend = \"\\n\" + content;\n }\n } catch {\n // File doesn't exist, will be created\n }\n\n await fs.appendFile(absPath, toAppend, \"utf-8\");\n this.dirty = true;\n this.debug?.(`memory append: ${relativePath}`);\n }\n\n /**\n * Append content to today's daily log (memory/YYYY-MM-DD.md)\n */\n async appendToday(content: string): Promise<string> {\n const today = new Date().toISOString().split(\"T\")[0]; // YYYY-MM-DD\n const relativePath = `memory/${today}.md`;\n await this.appendFile(relativePath, content);\n return relativePath;\n }\n\n /**\n * List all memory files\n */\n async listFiles(): Promise<string[]> {\n const files = await listMemoryFiles(this.memoryDir);\n return files.map((f) => path.relative(this.memoryDir, f).replace(/\\\\/g, \"/\"));\n }\n\n /**\n * Validate that a path is within allowed memory locations\n */\n private validateMemoryPath(relativePath: string): void {\n const normalized = relativePath.replace(/\\\\/g, \"/\").replace(/^\\.\\//, \"\");\n\n // Allow MEMORY.md at root\n if (normalized === \"MEMORY.md\" || normalized === \"memory.md\") {\n return;\n }\n\n // Allow anything under memory/\n if (normalized.startsWith(\"memory/\") && normalized.endsWith(\".md\")) {\n // Prevent path traversal\n if (normalized.includes(\"..\")) {\n throw new Error(`Invalid memory path: ${relativePath} (path traversal not allowed)`);\n }\n return;\n }\n\n throw new Error(\n `Invalid memory path: ${relativePath}. Must be MEMORY.md or memory/*.md`,\n );\n }\n\n async status(): Promise<{\n memoryDir: string;\n dbPath: string;\n provider: string;\n model: string;\n vectorAvailable: boolean;\n ftsAvailable: boolean;\n bm25Only: boolean;\n fallbackReason?: string;\n fileCount: number;\n chunkCount: number;\n cacheCount: number;\n }> {\n const fileRow = this.db.prepare(`SELECT COUNT(*) as count FROM files`).get() as { count: number };\n const chunkRow = this.db.prepare(`SELECT COUNT(*) as count FROM chunks`).get() as { count: number };\n const cacheRow = this.db\n .prepare(`SELECT COUNT(*) as count FROM ${EMBEDDING_CACHE_TABLE}`)\n .get() as { count: number };\n\n return {\n memoryDir: this.memoryDir,\n dbPath: this.dbPath,\n provider: this.provider.id,\n model: this.provider.model,\n vectorAvailable: this.vector.available === true,\n ftsAvailable: this.fts.available,\n bm25Only: this.provider.id === \"none\",\n fallbackReason: this.providerFallbackReason,\n fileCount: fileRow.count,\n chunkCount: chunkRow.count,\n cacheCount: cacheRow.count,\n };\n }\n\n /**\n * Search with knowledge metadata filters (domain, entities, confidence, type).\n * Runs a standard search then post-filters by knowledge columns.\n */\n async knowledgeSearch(\n query: string,\n opts?: {\n maxResults?: number;\n minScore?: number;\n domain?: string[];\n entities?: string[];\n minConfidence?: number;\n knowledgeType?: string;\n },\n ): Promise<MinimemSearchResult[]> {\n // Ensure index is up to date\n if (this.dirty || (!this.watchConfig.enabled && (await this.isStale()))) {\n await this.sync({ reason: \"knowledgeSearch\" });\n }\n\n const cleaned = query.trim();\n if (!cleaned) return [];\n\n const minScore = opts?.minScore ?? this.queryConfig.minScore;\n const maxResults = opts?.maxResults ?? this.queryConfig.maxResults;\n\n // Build knowledge filter SQL\n const { sql: knowledgeWhere, params: knowledgeParams } =\n buildKnowledgeFilterSql({\n domain: opts?.domain,\n entities: opts?.entities,\n minConfidence: opts?.minConfidence,\n knowledgeType: opts?.knowledgeType,\n });\n\n // If no knowledge filters, delegate to regular search\n if (!knowledgeWhere) {\n return this.search(query, { maxResults, minScore });\n }\n\n // Get all chunk IDs matching knowledge filters\n const matchingRows = this.db\n .prepare(\n `SELECT id FROM chunks c WHERE c.model = ? AND c.source = 'memory'${knowledgeWhere}`,\n )\n .all(this.provider.model, ...knowledgeParams) as Array<{ id: string }>;\n\n const matchingIds = new Set(matchingRows.map((r) => r.id));\n\n if (matchingIds.size === 0) return [];\n\n // Run standard search with extra candidates to compensate for filtering\n const overFetch = Math.max(maxResults * 3, 30);\n const results = await this.search(query, {\n maxResults: overFetch,\n minScore,\n });\n\n // Post-filter: look up chunk IDs for each result and keep only matching ones\n const filtered: MinimemSearchResult[] = [];\n for (const r of results) {\n const row = this.db\n .prepare(\n `SELECT id FROM chunks WHERE path = ? AND start_line = ? AND end_line = ? AND model = ?`,\n )\n .get(r.path, r.startLine, r.endLine, this.provider.model) as { id: string } | undefined;\n if (row && matchingIds.has(row.id)) {\n filtered.push(r);\n if (filtered.length >= maxResults) break;\n }\n }\n\n return filtered;\n }\n\n /**\n * Get knowledge graph links from or to a node.\n */\n getLinks(\n nodeId: string,\n direction: \"from\" | \"to\" = \"from\",\n opts?: { relation?: string; layer?: string },\n ): GraphLink[] {\n if (direction === \"from\") {\n return getLinksFrom(this.db, nodeId, opts);\n }\n return getLinksTo(this.db, nodeId, opts);\n }\n\n /**\n * Get neighbor nodes via BFS traversal.\n */\n getGraphNeighbors(\n nodeId: string,\n depth: number = 1,\n opts?: { relation?: string; layer?: string },\n ): GraphNeighbor[] {\n return getNeighbors(this.db, nodeId, depth, opts);\n }\n\n /**\n * Find shortest path between two knowledge nodes.\n */\n getGraphPath(fromId: string, toId: string, maxDepth: number = 3): GraphLink[] {\n return getPathBetween(this.db, fromId, toId, maxDepth);\n }\n\n close(): void {\n if (this.closed) return;\n this.closed = true;\n\n if (this.watchTimer) {\n clearTimeout(this.watchTimer);\n this.watchTimer = null;\n }\n\n if (this.watcher) {\n void this.watcher.close();\n this.watcher = null;\n }\n\n try {\n this.db.close();\n } catch (err) {\n logError(\"dbClose\", err, this.debug);\n }\n }\n}\n","export type HybridSource = string;\n\nexport type HybridVectorResult = {\n id: string;\n path: string;\n startLine: number;\n endLine: number;\n source: HybridSource;\n snippet: string;\n vectorScore: number;\n};\n\nexport type HybridKeywordResult = {\n id: string;\n path: string;\n startLine: number;\n endLine: number;\n source: HybridSource;\n snippet: string;\n textScore: number;\n};\n\nexport function buildFtsQuery(raw: string): string | null {\n const tokens =\n raw\n .match(/[A-Za-z0-9_]+/g)\n ?.map((t) => t.trim())\n .filter(Boolean) ?? [];\n if (tokens.length === 0) return null;\n const quoted = tokens.map((t) => `\"${t.replaceAll('\"', \"\")}\"`);\n return quoted.join(\" AND \");\n}\n\n/**\n * Convert BM25 rank from SQLite FTS5 to a 0-1 score.\n *\n * FTS5 BM25 ranks are NEGATIVE numbers where more negative = better match.\n * A rank of 0 means no match, -10 is better than -1.\n *\n * We use absolute value to convert to positive, then normalize to 0-1\n * using the formula: score = 1 / (1 + absRank)\n *\n * Examples:\n * - rank 0 (no match) -> score 1.0\n * - rank -1 (weak match) -> score 0.5\n * - rank -10 (strong match) -> score ~0.09\n *\n * Note: Higher absolute rank magnitude = better match = higher score after conversion.\n */\nexport function bm25RankToScore(rank: number): number {\n // Handle non-finite values (NaN, Infinity)\n if (!Number.isFinite(rank)) {\n return 0;\n }\n\n // BM25 ranks from FTS5 are negative (more negative = better match)\n // Use absolute value to get the magnitude\n const absRank = Math.abs(rank);\n\n // Convert to 0-1 score where higher magnitude = higher score\n // Using 1/(1+x) gives us a nice 0-1 range that decreases smoothly\n return 1 / (1 + absRank);\n}\n\nexport function mergeHybridResults(params: {\n vector: HybridVectorResult[];\n keyword: HybridKeywordResult[];\n vectorWeight: number;\n textWeight: number;\n}): Array<{\n path: string;\n startLine: number;\n endLine: number;\n score: number;\n snippet: string;\n source: HybridSource;\n}> {\n const byId = new Map<\n string,\n {\n id: string;\n path: string;\n startLine: number;\n endLine: number;\n source: HybridSource;\n snippet: string;\n vectorScore: number;\n textScore: number;\n }\n >();\n\n for (const r of params.vector) {\n byId.set(r.id, {\n id: r.id,\n path: r.path,\n startLine: r.startLine,\n endLine: r.endLine,\n source: r.source,\n snippet: r.snippet,\n vectorScore: r.vectorScore,\n textScore: 0,\n });\n }\n\n for (const r of params.keyword) {\n const existing = byId.get(r.id);\n if (existing) {\n existing.textScore = r.textScore;\n if (r.snippet && r.snippet.length > 0) existing.snippet = r.snippet;\n } else {\n byId.set(r.id, {\n id: r.id,\n path: r.path,\n startLine: r.startLine,\n endLine: r.endLine,\n source: r.source,\n snippet: r.snippet,\n vectorScore: 0,\n textScore: r.textScore,\n });\n }\n }\n\n // When one side of the hybrid search has no results, normalize weights\n // so the available side scores at full strength. Without this, BM25-only\n // results would be scaled to 0.3 * textScore which is too low to pass\n // the default minScore threshold.\n let vw = params.vectorWeight;\n let tw = params.textWeight;\n if (params.vector.length === 0 && params.keyword.length > 0) {\n vw = 0;\n tw = 1;\n } else if (params.keyword.length === 0 && params.vector.length > 0) {\n vw = 1;\n tw = 0;\n }\n\n const merged = Array.from(byId.values()).map((entry) => {\n const score = vw * entry.vectorScore + tw * entry.textScore;\n return {\n path: entry.path,\n startLine: entry.startLine,\n endLine: entry.endLine,\n score,\n snippet: entry.snippet,\n source: entry.source,\n };\n });\n\n return merged.sort((a, b) => b.score - a.score);\n}\n","import type { DatabaseSync } from \"node:sqlite\";\n\nimport { cosineSimilarity, parseEmbedding, truncateUtf16Safe, vectorToBlob } from \"../internal.js\";\n\nexport type SearchSource = string;\n\nexport type SearchRowResult = {\n id: string;\n path: string;\n startLine: number;\n endLine: number;\n score: number;\n snippet: string;\n source: SearchSource;\n};\n\n/**\n * Options for filtering search results by knowledge metadata\n */\nexport type KnowledgeSearchOptions = {\n /** Filter to chunks matching any of these domains */\n domain?: string[];\n /** Filter to chunks referencing any of these entities */\n entities?: string[];\n /** Minimum confidence threshold */\n minConfidence?: number;\n /** Filter to a specific knowledge type */\n knowledgeType?: string;\n};\n\n/**\n * Build SQL WHERE clause fragments for knowledge filters.\n * Uses json_each() for array column filtering.\n */\nexport function buildKnowledgeFilterSql(opts: KnowledgeSearchOptions): {\n sql: string;\n params: (string | number)[];\n} {\n const clauses: string[] = [];\n const params: (string | number)[] = [];\n\n if (opts.knowledgeType) {\n clauses.push(` AND c.knowledge_type = ?`);\n params.push(opts.knowledgeType);\n }\n\n if (opts.minConfidence !== undefined) {\n clauses.push(` AND c.confidence >= ?`);\n params.push(opts.minConfidence);\n }\n\n if (opts.domain && opts.domain.length > 0) {\n // At least one of the provided domains must appear in the JSON array\n const domainPlaceholders = opts.domain.map(() => \"?\").join(\", \");\n clauses.push(\n ` AND EXISTS (SELECT 1 FROM json_each(c.domains) AS d WHERE d.value IN (${domainPlaceholders}))`,\n );\n params.push(...opts.domain);\n }\n\n if (opts.entities && opts.entities.length > 0) {\n const entityPlaceholders = opts.entities.map(() => \"?\").join(\", \");\n clauses.push(\n ` AND EXISTS (SELECT 1 FROM json_each(c.entities) AS e WHERE e.value IN (${entityPlaceholders}))`,\n );\n params.push(...opts.entities);\n }\n\n return { sql: clauses.join(\"\"), params };\n}\n\n/**\n * Perform a vector similarity search against indexed memory chunks.\n *\n * First attempts to use sqlite-vec for fast approximate nearest neighbor search.\n * Falls back to brute-force cosine similarity over all chunks if the vector\n * extension is unavailable.\n *\n * @returns Matching chunks sorted by descending similarity score (0-1 range).\n */\nexport async function searchVector(params: {\n db: DatabaseSync;\n vectorTable: string;\n providerModel: string;\n queryVec: number[];\n limit: number;\n snippetMaxChars: number;\n ensureVectorReady: (dimensions: number) => Promise<boolean>;\n sourceFilterVec: { sql: string; params: SearchSource[] };\n sourceFilterChunks: { sql: string; params: SearchSource[] };\n}): Promise<SearchRowResult[]> {\n if (params.queryVec.length === 0 || params.limit <= 0) return [];\n if (await params.ensureVectorReady(params.queryVec.length)) {\n const rows = params.db\n .prepare(\n `SELECT c.id, c.path, c.start_line, c.end_line, c.text,\\n` +\n ` c.source,\\n` +\n ` vec_distance_cosine(v.embedding, ?) AS dist\\n` +\n ` FROM ${params.vectorTable} v\\n` +\n ` JOIN chunks c ON c.id = v.id\\n` +\n ` WHERE c.model = ?${params.sourceFilterVec.sql}\\n` +\n ` ORDER BY dist ASC\\n` +\n ` LIMIT ?`,\n )\n .all(\n vectorToBlob(params.queryVec),\n params.providerModel,\n ...params.sourceFilterVec.params,\n params.limit,\n ) as Array<{\n id: string;\n path: string;\n start_line: number;\n end_line: number;\n text: string;\n source: SearchSource;\n dist: number;\n }>;\n return rows.map((row) => ({\n id: row.id,\n path: row.path,\n startLine: row.start_line,\n endLine: row.end_line,\n score: 1 - row.dist,\n snippet: truncateUtf16Safe(row.text, params.snippetMaxChars),\n source: row.source,\n }));\n }\n\n const candidates = listChunks({\n db: params.db,\n providerModel: params.providerModel,\n sourceFilter: params.sourceFilterChunks,\n });\n const scored = candidates\n .map((chunk) => ({\n chunk,\n score: cosineSimilarity(params.queryVec, chunk.embedding),\n }))\n .filter((entry) => Number.isFinite(entry.score));\n return scored\n .sort((a, b) => b.score - a.score)\n .slice(0, params.limit)\n .map((entry) => ({\n id: entry.chunk.id,\n path: entry.chunk.path,\n startLine: entry.chunk.startLine,\n endLine: entry.chunk.endLine,\n score: entry.score,\n snippet: truncateUtf16Safe(entry.chunk.text, params.snippetMaxChars),\n source: entry.chunk.source,\n }));\n}\n\n/**\n * List all indexed chunks for a given embedding model and source filter.\n * Used as a fallback when sqlite-vec is not available for vector search.\n *\n * @returns All matching chunks with their parsed embedding vectors.\n */\nexport function listChunks(params: {\n db: DatabaseSync;\n providerModel: string;\n sourceFilter: { sql: string; params: SearchSource[] };\n}): Array<{\n id: string;\n path: string;\n startLine: number;\n endLine: number;\n text: string;\n embedding: number[];\n source: SearchSource;\n}> {\n const rows = params.db\n .prepare(\n `SELECT id, path, start_line, end_line, text, embedding, source\\n` +\n ` FROM chunks\\n` +\n ` WHERE model = ?${params.sourceFilter.sql}`,\n )\n .all(params.providerModel, ...params.sourceFilter.params) as Array<{\n id: string;\n path: string;\n start_line: number;\n end_line: number;\n text: string;\n embedding: string;\n source: SearchSource;\n }>;\n\n return rows.map((row) => ({\n id: row.id,\n path: row.path,\n startLine: row.start_line,\n endLine: row.end_line,\n text: row.text,\n embedding: parseEmbedding(row.embedding),\n source: row.source,\n }));\n}\n\n/**\n * Perform a full-text keyword search using SQLite FTS5 with BM25 ranking.\n *\n * Tokenizes the query into quoted AND terms and runs them against the FTS index.\n * Results are scored using BM25 rank converted to a 0-1 range.\n *\n * @returns Matching chunks sorted by BM25 relevance, with both score and textScore fields.\n */\nexport async function searchKeyword(params: {\n db: DatabaseSync;\n ftsTable: string;\n providerModel: string;\n query: string;\n limit: number;\n snippetMaxChars: number;\n sourceFilter: { sql: string; params: SearchSource[] };\n buildFtsQuery: (raw: string) => string | null;\n bm25RankToScore: (rank: number) => number;\n}): Promise<Array<SearchRowResult & { textScore: number }>> {\n if (params.limit <= 0) return [];\n const ftsQuery = params.buildFtsQuery(params.query);\n if (!ftsQuery) return [];\n\n const rows = params.db\n .prepare(\n `SELECT id, path, source, start_line, end_line, text,\\n` +\n ` bm25(${params.ftsTable}) AS rank\\n` +\n ` FROM ${params.ftsTable}\\n` +\n ` WHERE ${params.ftsTable} MATCH ? AND model = ?${params.sourceFilter.sql}\\n` +\n ` ORDER BY rank ASC\\n` +\n ` LIMIT ?`,\n )\n .all(ftsQuery, params.providerModel, ...params.sourceFilter.params, params.limit) as Array<{\n id: string;\n path: string;\n source: SearchSource;\n start_line: number;\n end_line: number;\n text: string;\n rank: number;\n }>;\n\n return rows.map((row) => {\n const textScore = params.bm25RankToScore(row.rank);\n return {\n id: row.id,\n path: row.path,\n startLine: row.start_line,\n endLine: row.end_line,\n score: textScore,\n textScore,\n snippet: truncateUtf16Safe(row.text, params.snippetMaxChars),\n source: row.source,\n };\n });\n}\n","import type { DatabaseSync } from \"node:sqlite\";\n\n/**\n * Current schema version. Increment this when making breaking schema changes.\n *\n * Version history:\n * - 1: Initial schema (meta, files, chunks, embedding_cache, FTS5)\n * - 2: Added source column to files and chunks tables\n * - 3: Added type column to chunks table for observation type metadata\n * - 4: Added knowledge columns to chunks + knowledge_links table\n */\nexport const SCHEMA_VERSION = 4;\n\nexport function ensureMemoryIndexSchema(params: {\n db: DatabaseSync;\n embeddingCacheTable: string;\n ftsTable: string;\n ftsEnabled: boolean;\n}): { ftsAvailable: boolean; ftsError?: string; migrated?: boolean } {\n // Create meta table first (needed for version tracking)\n params.db.exec(`\n CREATE TABLE IF NOT EXISTS meta (\n key TEXT PRIMARY KEY,\n value TEXT NOT NULL\n );\n `);\n\n // Check schema version and handle migration\n const migrated = migrateIfNeeded(params.db, params.ftsTable);\n\n params.db.exec(`\n CREATE TABLE IF NOT EXISTS files (\n path TEXT PRIMARY KEY,\n source TEXT NOT NULL DEFAULT 'memory',\n hash TEXT NOT NULL,\n mtime INTEGER NOT NULL,\n size INTEGER NOT NULL\n );\n `);\n params.db.exec(`\n CREATE TABLE IF NOT EXISTS chunks (\n id TEXT PRIMARY KEY,\n path TEXT NOT NULL,\n source TEXT NOT NULL DEFAULT 'memory',\n start_line INTEGER NOT NULL,\n end_line INTEGER NOT NULL,\n hash TEXT NOT NULL,\n model TEXT NOT NULL,\n text TEXT NOT NULL,\n embedding TEXT NOT NULL,\n updated_at INTEGER NOT NULL\n );\n `);\n params.db.exec(`\n CREATE TABLE IF NOT EXISTS ${params.embeddingCacheTable} (\n provider TEXT NOT NULL,\n model TEXT NOT NULL,\n provider_key TEXT NOT NULL,\n hash TEXT NOT NULL,\n embedding TEXT NOT NULL,\n dims INTEGER,\n updated_at INTEGER NOT NULL,\n PRIMARY KEY (provider, model, provider_key, hash)\n );\n `);\n params.db.exec(\n `CREATE INDEX IF NOT EXISTS idx_embedding_cache_updated_at ON ${params.embeddingCacheTable}(updated_at);`,\n );\n\n let ftsAvailable = false;\n let ftsError: string | undefined;\n if (params.ftsEnabled) {\n try {\n params.db.exec(\n `CREATE VIRTUAL TABLE IF NOT EXISTS ${params.ftsTable} USING fts5(\\n` +\n ` text,\\n` +\n ` id UNINDEXED,\\n` +\n ` path UNINDEXED,\\n` +\n ` source UNINDEXED,\\n` +\n ` model UNINDEXED,\\n` +\n ` start_line UNINDEXED,\\n` +\n ` end_line UNINDEXED\\n` +\n `);`,\n );\n ftsAvailable = true;\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n ftsAvailable = false;\n ftsError = message;\n }\n }\n\n ensureColumn(params.db, \"files\", \"source\", \"TEXT NOT NULL DEFAULT 'memory'\");\n ensureColumn(params.db, \"chunks\", \"source\", \"TEXT NOT NULL DEFAULT 'memory'\");\n ensureColumn(params.db, \"chunks\", \"type\", \"TEXT\");\n ensureColumn(params.db, \"chunks\", \"knowledge_type\", \"TEXT\");\n ensureColumn(params.db, \"chunks\", \"knowledge_id\", \"TEXT\");\n ensureColumn(params.db, \"chunks\", \"domains\", \"TEXT\");\n ensureColumn(params.db, \"chunks\", \"entities\", \"TEXT\");\n ensureColumn(params.db, \"chunks\", \"confidence\", \"REAL\");\n params.db.exec(`CREATE INDEX IF NOT EXISTS idx_chunks_path ON chunks(path);`);\n params.db.exec(`CREATE INDEX IF NOT EXISTS idx_chunks_source ON chunks(source);`);\n params.db.exec(`CREATE INDEX IF NOT EXISTS idx_chunks_type ON chunks(type);`);\n params.db.exec(`CREATE INDEX IF NOT EXISTS idx_chunks_knowledge_type ON chunks(knowledge_type);`);\n params.db.exec(`CREATE INDEX IF NOT EXISTS idx_chunks_knowledge_id ON chunks(knowledge_id);`);\n\n // Knowledge links table for graph traversal\n params.db.exec(`\n CREATE TABLE IF NOT EXISTS knowledge_links (\n from_id TEXT NOT NULL,\n to_id TEXT NOT NULL,\n relation TEXT NOT NULL,\n layer TEXT,\n weight REAL DEFAULT 0.5,\n source_path TEXT,\n created_at INTEGER,\n PRIMARY KEY (from_id, to_id, relation)\n );\n `);\n params.db.exec(`CREATE INDEX IF NOT EXISTS idx_kl_from ON knowledge_links(from_id);`);\n params.db.exec(`CREATE INDEX IF NOT EXISTS idx_kl_to ON knowledge_links(to_id);`);\n params.db.exec(`CREATE INDEX IF NOT EXISTS idx_kl_layer ON knowledge_links(layer);`);\n\n // Store current schema version\n params.db.prepare(\n `INSERT OR REPLACE INTO meta (key, value) VALUES ('schema_version', ?)`,\n ).run(String(SCHEMA_VERSION));\n\n return { ftsAvailable, ...(ftsError ? { ftsError } : {}), ...(migrated ? { migrated } : {}) };\n}\n\n/**\n * Check the stored schema version and migrate if needed.\n * For breaking changes, drops data tables so they get recreated fresh.\n * The embedding cache is preserved across migrations when possible.\n *\n * @returns true if a migration was performed, false otherwise.\n */\nfunction migrateIfNeeded(db: DatabaseSync, ftsTable: string): boolean {\n let storedVersion = 0;\n try {\n const row = db.prepare(\n `SELECT value FROM meta WHERE key = 'schema_version'`,\n ).get() as { value: string } | undefined;\n if (row) {\n storedVersion = parseInt(row.value, 10) || 0;\n }\n } catch {\n // meta table may not have the key yet (pre-versioning databases)\n storedVersion = 0;\n }\n\n if (storedVersion >= SCHEMA_VERSION) return false;\n\n if (storedVersion > 0 && storedVersion < SCHEMA_VERSION) {\n // Breaking schema change: drop and recreate data tables.\n // Embedding cache is preserved since embeddings are content-addressed\n // and will be reused on re-index.\n db.exec(`DROP TABLE IF EXISTS files`);\n db.exec(`DROP TABLE IF EXISTS chunks`);\n db.exec(`DROP TABLE IF EXISTS knowledge_links`);\n db.exec(`DROP TABLE IF EXISTS ${ftsTable}`);\n // Also drop the vector table if it exists\n try {\n db.exec(`DROP TABLE IF EXISTS chunks_vec`);\n } catch {\n // sqlite-vec table may not exist\n }\n }\n\n return storedVersion > 0;\n}\n\nfunction ensureColumn(\n db: DatabaseSync,\n table: \"files\" | \"chunks\",\n column: string,\n definition: string,\n): void {\n const rows = db.prepare(`PRAGMA table_info(${table})`).all() as Array<{ name: string }>;\n if (rows.some((row) => row.name === column)) return;\n db.exec(`ALTER TABLE ${table} ADD COLUMN ${column} ${definition}`);\n}\n","import type { DatabaseSync } from \"node:sqlite\";\n\n/**\n * A knowledge graph link between two nodes\n */\nexport type GraphLink = {\n fromId: string;\n toId: string;\n relation: string;\n layer: string | null;\n weight: number;\n sourcePath: string | null;\n};\n\n/**\n * A neighbor node discovered during graph traversal\n */\nexport type GraphNeighbor = {\n id: string;\n depth: number;\n link: GraphLink;\n};\n\n/**\n * Get all outgoing links from a node.\n */\nexport function getLinksFrom(\n db: DatabaseSync,\n fromId: string,\n opts?: { relation?: string; layer?: string },\n): GraphLink[] {\n let sql = `SELECT from_id, to_id, relation, layer, weight, source_path FROM knowledge_links WHERE from_id = ?`;\n const params: (string | number)[] = [fromId];\n\n if (opts?.relation) {\n sql += ` AND relation = ?`;\n params.push(opts.relation);\n }\n if (opts?.layer) {\n sql += ` AND layer = ?`;\n params.push(opts.layer);\n }\n\n const rows = db.prepare(sql).all(...params) as Array<{\n from_id: string;\n to_id: string;\n relation: string;\n layer: string | null;\n weight: number;\n source_path: string | null;\n }>;\n\n return rows.map(toGraphLink);\n}\n\n/**\n * Get all incoming links to a node.\n */\nexport function getLinksTo(\n db: DatabaseSync,\n toId: string,\n opts?: { relation?: string; layer?: string },\n): GraphLink[] {\n let sql = `SELECT from_id, to_id, relation, layer, weight, source_path FROM knowledge_links WHERE to_id = ?`;\n const params: (string | number)[] = [toId];\n\n if (opts?.relation) {\n sql += ` AND relation = ?`;\n params.push(opts.relation);\n }\n if (opts?.layer) {\n sql += ` AND layer = ?`;\n params.push(opts.layer);\n }\n\n const rows = db.prepare(sql).all(...params) as Array<{\n from_id: string;\n to_id: string;\n relation: string;\n layer: string | null;\n weight: number;\n source_path: string | null;\n }>;\n\n return rows.map(toGraphLink);\n}\n\n/**\n * BFS traversal to find neighbors up to a given depth.\n *\n * @param db - Database handle\n * @param startId - The starting node ID\n * @param depth - Maximum traversal depth (default: 1)\n * @param opts - Optional filters for relation and layer\n * @returns Array of neighbor nodes with their depth and connecting link\n */\nexport function getNeighbors(\n db: DatabaseSync,\n startId: string,\n depth: number = 1,\n opts?: { relation?: string; layer?: string },\n): GraphNeighbor[] {\n const visited = new Set<string>([startId]);\n const result: GraphNeighbor[] = [];\n let frontier = [startId];\n\n for (let d = 1; d <= depth; d++) {\n const nextFrontier: string[] = [];\n\n for (const nodeId of frontier) {\n // Follow outgoing links\n const outgoing = getLinksFrom(db, nodeId, opts);\n for (const link of outgoing) {\n if (!visited.has(link.toId)) {\n visited.add(link.toId);\n nextFrontier.push(link.toId);\n result.push({ id: link.toId, depth: d, link });\n }\n }\n\n // Follow incoming links\n const incoming = getLinksTo(db, nodeId, opts);\n for (const link of incoming) {\n if (!visited.has(link.fromId)) {\n visited.add(link.fromId);\n nextFrontier.push(link.fromId);\n result.push({ id: link.fromId, depth: d, link });\n }\n }\n }\n\n frontier = nextFrontier;\n if (frontier.length === 0) break;\n }\n\n return result;\n}\n\n/**\n * BFS shortest path between two nodes, max depth 3.\n *\n * @returns Array of links forming the path, or empty if no path found.\n */\nexport function getPathBetween(\n db: DatabaseSync,\n fromId: string,\n toId: string,\n maxDepth: number = 3,\n): GraphLink[] {\n if (fromId === toId) return [];\n\n // BFS with parent tracking\n const visited = new Set<string>([fromId]);\n // Maps each visited node to the link that discovered it\n const parentLink = new Map<string, GraphLink>();\n let frontier = [fromId];\n\n for (let d = 0; d < maxDepth; d++) {\n const nextFrontier: string[] = [];\n\n for (const nodeId of frontier) {\n // Follow outgoing links\n const outgoing = getLinksFrom(db, nodeId);\n for (const link of outgoing) {\n if (!visited.has(link.toId)) {\n visited.add(link.toId);\n parentLink.set(link.toId, link);\n if (link.toId === toId) {\n return reconstructPath(parentLink, fromId, toId);\n }\n nextFrontier.push(link.toId);\n }\n }\n\n // Follow incoming links\n const incoming = getLinksTo(db, nodeId);\n for (const link of incoming) {\n if (!visited.has(link.fromId)) {\n visited.add(link.fromId);\n parentLink.set(link.fromId, link);\n if (link.fromId === toId) {\n return reconstructPath(parentLink, fromId, toId);\n }\n nextFrontier.push(link.fromId);\n }\n }\n }\n\n frontier = nextFrontier;\n if (frontier.length === 0) break;\n }\n\n return []; // No path found\n}\n\n/**\n * Reconstruct the path from BFS parent map.\n */\nfunction reconstructPath(\n parentLink: Map<string, GraphLink>,\n fromId: string,\n toId: string,\n): GraphLink[] {\n const path: GraphLink[] = [];\n let current = toId;\n\n while (current !== fromId) {\n const link = parentLink.get(current);\n if (!link) break;\n path.unshift(link);\n // Determine which side led to `current`\n current = link.toId === current ? link.fromId : link.toId;\n }\n\n return path;\n}\n\nfunction toGraphLink(row: {\n from_id: string;\n to_id: string;\n relation: string;\n layer: string | null;\n weight: number;\n source_path: string | null;\n}): GraphLink {\n return {\n fromId: row.from_id,\n toId: row.to_id,\n relation: row.relation,\n layer: row.layer,\n weight: row.weight,\n sourcePath: row.source_path,\n };\n}\n","import type { DatabaseSync } from \"node:sqlite\";\n\nexport async function loadSqliteVecExtension(params: {\n db: DatabaseSync;\n extensionPath?: string;\n}): Promise<{ ok: boolean; extensionPath?: string; error?: string }> {\n try {\n const sqliteVec = await import(\"sqlite-vec\");\n const resolvedPath = params.extensionPath?.trim() ? params.extensionPath.trim() : undefined;\n const extensionPath = resolvedPath ?? sqliteVec.getLoadablePath();\n\n params.db.enableLoadExtension(true);\n if (resolvedPath) {\n params.db.loadExtension(extensionPath);\n } else {\n sqliteVec.load(params.db);\n }\n\n return { ok: true, extensionPath };\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n return { ok: false, error: message };\n }\n}\n","import fsSync from \"node:fs\";\nimport path from \"node:path\";\nimport os from \"node:os\";\n\nimport type { Llama, LlamaEmbeddingContext, LlamaModel } from \"node-llama-cpp\";\n\nexport type EmbeddingProvider = {\n id: string;\n model: string;\n embedQuery: (text: string) => Promise<number[]>;\n embedBatch: (texts: string[]) => Promise<number[][]>;\n};\n\nexport type EmbeddingProviderResult = {\n provider: EmbeddingProvider;\n requestedProvider: \"openai\" | \"local\" | \"gemini\" | \"auto\" | \"none\";\n fallbackFrom?: \"openai\" | \"local\" | \"gemini\" | \"auto\";\n fallbackReason?: string;\n openAi?: OpenAiEmbeddingClient;\n gemini?: GeminiEmbeddingClient;\n};\n\nexport type EmbeddingProviderOptions = {\n provider: \"openai\" | \"local\" | \"gemini\" | \"auto\" | \"none\";\n model?: string;\n fallback?: \"openai\" | \"gemini\" | \"local\" | \"none\";\n openai?: {\n apiKey?: string;\n baseUrl?: string;\n headers?: Record<string, string>;\n };\n gemini?: {\n apiKey?: string;\n baseUrl?: string;\n headers?: Record<string, string>;\n };\n local?: {\n modelPath?: string;\n modelCacheDir?: string;\n };\n};\n\nexport type OpenAiEmbeddingClient = {\n baseUrl: string;\n headers: Record<string, string>;\n model: string;\n};\n\nexport type GeminiEmbeddingClient = {\n baseUrl: string;\n headers: Record<string, string>;\n model: string;\n modelPath: string;\n};\n\nconst DEFAULT_LOCAL_MODEL = \"hf:ggml-org/embeddinggemma-300M-GGUF/embeddinggemma-300M-Q8_0.gguf\";\nconst DEFAULT_OPENAI_EMBEDDING_MODEL = \"text-embedding-3-small\";\nconst DEFAULT_OPENAI_BASE_URL = \"https://api.openai.com/v1\";\nconst DEFAULT_GEMINI_EMBEDDING_MODEL = \"gemini-embedding-001\";\nconst DEFAULT_GEMINI_BASE_URL = \"https://generativelanguage.googleapis.com/v1beta\";\n\n/**\n * Creates a no-op embedding provider that returns empty vectors.\n * Used for BM25-only mode when no embedding API is available.\n */\nfunction createNoOpEmbeddingProvider(): EmbeddingProvider {\n return {\n id: \"none\",\n model: \"bm25-only\",\n embedQuery: async () => [],\n embedBatch: async (texts) => texts.map(() => []),\n };\n}\n\nfunction resolveUserPath(filePath: string): string {\n if (filePath.startsWith(\"~/\")) {\n return path.join(os.homedir(), filePath.slice(2));\n }\n return filePath;\n}\n\nfunction canAutoSelectLocal(options: EmbeddingProviderOptions): boolean {\n const modelPath = options.local?.modelPath?.trim();\n if (!modelPath) return false;\n if (/^(hf:|https?:)/i.test(modelPath)) return false;\n const resolved = resolveUserPath(modelPath);\n try {\n return fsSync.statSync(resolved).isFile();\n } catch {\n return false;\n }\n}\n\nfunction isMissingApiKeyError(err: unknown): boolean {\n const message = formatError(err);\n return message.includes(\"API key\") || message.includes(\"apiKey\");\n}\n\nasync function importNodeLlamaCpp() {\n const llama = await import(\"node-llama-cpp\");\n return llama;\n}\n\nasync function createLocalEmbeddingProvider(\n options: EmbeddingProviderOptions,\n): Promise<EmbeddingProvider> {\n const modelPath = options.local?.modelPath?.trim() || DEFAULT_LOCAL_MODEL;\n const modelCacheDir = options.local?.modelCacheDir?.trim();\n\n const { getLlama, resolveModelFile, LlamaLogLevel } = await importNodeLlamaCpp();\n\n let llama: Llama | null = null;\n let embeddingModel: LlamaModel | null = null;\n let embeddingContext: LlamaEmbeddingContext | null = null;\n\n const ensureContext = async () => {\n if (!llama) {\n llama = await getLlama({ logLevel: LlamaLogLevel.error });\n }\n if (!embeddingModel) {\n const resolved = await resolveModelFile(modelPath, modelCacheDir || undefined);\n embeddingModel = await llama.loadModel({ modelPath: resolved });\n }\n if (!embeddingContext) {\n embeddingContext = await embeddingModel.createEmbeddingContext();\n }\n return embeddingContext;\n };\n\n return {\n id: \"local\",\n model: modelPath,\n embedQuery: async (text) => {\n const ctx = await ensureContext();\n const embedding = await ctx.getEmbeddingFor(text);\n return Array.from(embedding.vector) as number[];\n },\n embedBatch: async (texts) => {\n const ctx = await ensureContext();\n const embeddings = await Promise.all(\n texts.map(async (text) => {\n const embedding = await ctx.getEmbeddingFor(text);\n return Array.from(embedding.vector) as number[];\n }),\n );\n return embeddings;\n },\n };\n}\n\nfunction normalizeOpenAiModel(model: string): string {\n const trimmed = model.trim();\n if (!trimmed) return DEFAULT_OPENAI_EMBEDDING_MODEL;\n if (trimmed.startsWith(\"openai/\")) return trimmed.slice(\"openai/\".length);\n return trimmed;\n}\n\nfunction resolveOpenAiApiKey(options: EmbeddingProviderOptions): string {\n const apiKey = options.openai?.apiKey?.trim();\n if (apiKey) return apiKey;\n const envKey = process.env.OPENAI_API_KEY?.trim();\n if (envKey) return envKey;\n throw new Error(\"OpenAI API key not found. Set OPENAI_API_KEY env var or pass openai.apiKey option.\");\n}\n\nexport async function createOpenAiEmbeddingProvider(\n options: EmbeddingProviderOptions,\n): Promise<{ provider: EmbeddingProvider; client: OpenAiEmbeddingClient }> {\n const apiKey = resolveOpenAiApiKey(options);\n const baseUrl = options.openai?.baseUrl?.trim() || DEFAULT_OPENAI_BASE_URL;\n const headerOverrides = options.openai?.headers ?? {};\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${apiKey}`,\n ...headerOverrides,\n };\n const model = normalizeOpenAiModel(options.model || \"\");\n const client: OpenAiEmbeddingClient = { baseUrl, headers, model };\n const url = `${baseUrl.replace(/\\/$/, \"\")}/embeddings`;\n\n const embed = async (input: string[]): Promise<number[][]> => {\n if (input.length === 0) return [];\n const res = await fetch(url, {\n method: \"POST\",\n headers: client.headers,\n body: JSON.stringify({ model: client.model, input }),\n });\n if (!res.ok) {\n const text = await res.text();\n throw new Error(`openai embeddings failed: ${res.status} ${text}`);\n }\n const payload = (await res.json()) as {\n data?: Array<{ embedding?: number[] }>;\n };\n const data = payload.data ?? [];\n return data.map((entry) => entry.embedding ?? []);\n };\n\n return {\n provider: {\n id: \"openai\",\n model: client.model,\n embedQuery: async (text) => {\n const [vec] = await embed([text]);\n return vec ?? [];\n },\n embedBatch: embed,\n },\n client,\n };\n}\n\nfunction normalizeGeminiModel(model: string): string {\n const trimmed = model.trim();\n if (!trimmed) return DEFAULT_GEMINI_EMBEDDING_MODEL;\n const withoutPrefix = trimmed.replace(/^models\\//, \"\");\n if (withoutPrefix.startsWith(\"gemini/\")) return withoutPrefix.slice(\"gemini/\".length);\n if (withoutPrefix.startsWith(\"google/\")) return withoutPrefix.slice(\"google/\".length);\n return withoutPrefix;\n}\n\nfunction normalizeGeminiBaseUrl(raw: string): string {\n const trimmed = raw.replace(/\\/+$/, \"\");\n const openAiIndex = trimmed.indexOf(\"/openai\");\n if (openAiIndex > -1) return trimmed.slice(0, openAiIndex);\n return trimmed;\n}\n\nfunction buildGeminiModelPath(model: string): string {\n return model.startsWith(\"models/\") ? model : `models/${model}`;\n}\n\nfunction resolveGeminiApiKey(options: EmbeddingProviderOptions): string {\n const apiKey = options.gemini?.apiKey?.trim();\n if (apiKey) return apiKey;\n const googleKey = process.env.GOOGLE_API_KEY?.trim();\n if (googleKey) return googleKey;\n const geminiKey = process.env.GEMINI_API_KEY?.trim();\n if (geminiKey) return geminiKey;\n throw new Error(\"Gemini API key not found. Set GOOGLE_API_KEY or GEMINI_API_KEY env var or pass gemini.apiKey option.\");\n}\n\nexport async function createGeminiEmbeddingProvider(\n options: EmbeddingProviderOptions,\n): Promise<{ provider: EmbeddingProvider; client: GeminiEmbeddingClient }> {\n const apiKey = resolveGeminiApiKey(options);\n const rawBaseUrl = options.gemini?.baseUrl?.trim() || DEFAULT_GEMINI_BASE_URL;\n const baseUrl = normalizeGeminiBaseUrl(rawBaseUrl);\n const headerOverrides = options.gemini?.headers ?? {};\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n \"x-goog-api-key\": apiKey,\n ...headerOverrides,\n };\n const model = normalizeGeminiModel(options.model || \"\");\n const modelPath = buildGeminiModelPath(model);\n const client: GeminiEmbeddingClient = { baseUrl, headers, model, modelPath };\n\n const embedUrl = `${baseUrl}/${modelPath}:embedContent`;\n const batchUrl = `${baseUrl}/${modelPath}:batchEmbedContents`;\n\n const embedQuery = async (text: string): Promise<number[]> => {\n if (!text.trim()) return [];\n const res = await fetch(embedUrl, {\n method: \"POST\",\n headers: client.headers,\n body: JSON.stringify({\n content: { parts: [{ text }] },\n taskType: \"RETRIEVAL_QUERY\",\n }),\n });\n if (!res.ok) {\n const payload = await res.text();\n throw new Error(`gemini embeddings failed: ${res.status} ${payload}`);\n }\n const payload = (await res.json()) as { embedding?: { values?: number[] } };\n return payload.embedding?.values ?? [];\n };\n\n const embedBatch = async (texts: string[]): Promise<number[][]> => {\n if (texts.length === 0) return [];\n const requests = texts.map((text) => ({\n model: modelPath,\n content: { parts: [{ text }] },\n taskType: \"RETRIEVAL_DOCUMENT\",\n }));\n const res = await fetch(batchUrl, {\n method: \"POST\",\n headers: client.headers,\n body: JSON.stringify({ requests }),\n });\n if (!res.ok) {\n const payload = await res.text();\n throw new Error(`gemini embeddings failed: ${res.status} ${payload}`);\n }\n const payload = (await res.json()) as { embeddings?: Array<{ values?: number[] }> };\n const embeddings = Array.isArray(payload.embeddings) ? payload.embeddings : [];\n return texts.map((_, index) => embeddings[index]?.values ?? []);\n };\n\n return {\n provider: {\n id: \"gemini\",\n model: client.model,\n embedQuery,\n embedBatch,\n },\n client,\n };\n}\n\nexport async function createEmbeddingProvider(\n options: EmbeddingProviderOptions,\n): Promise<EmbeddingProviderResult> {\n const requestedProvider = options.provider;\n const fallback = options.fallback ?? \"none\";\n\n // Handle explicit \"none\" provider (BM25-only mode)\n if (requestedProvider === \"none\") {\n return {\n provider: createNoOpEmbeddingProvider(),\n requestedProvider: \"none\",\n };\n }\n\n const createProvider = async (id: \"openai\" | \"local\" | \"gemini\") => {\n if (id === \"local\") {\n const provider = await createLocalEmbeddingProvider(options);\n return { provider };\n }\n if (id === \"gemini\") {\n const { provider, client } = await createGeminiEmbeddingProvider(options);\n return { provider, gemini: client };\n }\n const { provider, client } = await createOpenAiEmbeddingProvider(options);\n return { provider, openAi: client };\n };\n\n const formatPrimaryError = (err: unknown, provider: \"openai\" | \"local\" | \"gemini\") =>\n provider === \"local\" ? formatLocalSetupError(err) : formatError(err);\n\n if (requestedProvider === \"auto\") {\n const missingKeyErrors: string[] = [];\n let localError: string | null = null;\n\n if (canAutoSelectLocal(options)) {\n try {\n const local = await createProvider(\"local\");\n return { ...local, requestedProvider };\n } catch (err) {\n localError = formatLocalSetupError(err);\n }\n }\n\n for (const provider of [\"openai\", \"gemini\"] as const) {\n try {\n const result = await createProvider(provider);\n return { ...result, requestedProvider };\n } catch (err) {\n const message = formatPrimaryError(err, provider);\n if (isMissingApiKeyError(err)) {\n missingKeyErrors.push(message);\n continue;\n }\n throw new Error(message);\n }\n }\n\n // Fall back to BM25-only mode instead of throwing\n // This allows the system to work without any API keys using full-text search only\n return {\n provider: createNoOpEmbeddingProvider(),\n requestedProvider,\n fallbackFrom: \"auto\",\n fallbackReason: \"No embedding API available. Using BM25 full-text search only.\",\n };\n }\n\n try {\n const primary = await createProvider(requestedProvider);\n return { ...primary, requestedProvider };\n } catch (primaryErr) {\n const reason = formatPrimaryError(primaryErr, requestedProvider);\n if (fallback && fallback !== \"none\" && fallback !== requestedProvider) {\n try {\n const fallbackResult = await createProvider(fallback);\n return {\n ...fallbackResult,\n requestedProvider,\n fallbackFrom: requestedProvider,\n fallbackReason: reason,\n };\n } catch (fallbackErr) {\n throw new Error(`${reason}\\n\\nFallback to ${fallback} failed: ${formatError(fallbackErr)}`);\n }\n }\n throw new Error(reason);\n }\n}\n\nfunction formatError(err: unknown): string {\n if (err instanceof Error) return err.message;\n return String(err);\n}\n\nfunction isNodeLlamaCppMissing(err: unknown): boolean {\n if (!(err instanceof Error)) return false;\n const code = (err as Error & { code?: unknown }).code;\n if (code === \"ERR_MODULE_NOT_FOUND\") {\n return err.message.includes(\"node-llama-cpp\");\n }\n return false;\n}\n\nfunction formatLocalSetupError(err: unknown): string {\n const detail = formatError(err);\n const missing = isNodeLlamaCppMissing(err);\n return [\n \"Local embeddings unavailable.\",\n missing\n ? \"Reason: optional dependency node-llama-cpp is missing (or failed to install).\"\n : detail\n ? `Reason: ${detail}`\n : undefined,\n missing && detail ? `Detail: ${detail}` : null,\n \"To enable local embeddings:\",\n \"1) Use Node 22 LTS (recommended for installs/updates)\",\n missing ? \"2) Install node-llama-cpp: npm install node-llama-cpp\" : null,\n \"3) If you use pnpm: pnpm approve-builds (select node-llama-cpp), then pnpm rebuild node-llama-cpp\",\n 'Or set provider = \"openai\" or \"gemini\" (remote).',\n ]\n .filter(Boolean)\n .join(\"\\n\");\n}\n","import type { OpenAiEmbeddingClient } from \"./embeddings.js\";\nimport { hashText } from \"../internal.js\";\n\nexport type OpenAiBatchRequest = {\n custom_id: string;\n method: \"POST\";\n url: \"/v1/embeddings\";\n body: {\n model: string;\n input: string;\n };\n};\n\nexport type OpenAiBatchStatus = {\n id?: string;\n status?: string;\n output_file_id?: string | null;\n error_file_id?: string | null;\n};\n\nexport type OpenAiBatchOutputLine = {\n custom_id?: string;\n response?: {\n status_code?: number;\n body?: {\n data?: Array<{ embedding?: number[]; index?: number }>;\n error?: { message?: string };\n };\n };\n error?: { message?: string };\n};\n\nexport const OPENAI_BATCH_ENDPOINT = \"/v1/embeddings\";\nconst OPENAI_BATCH_COMPLETION_WINDOW = \"24h\";\nconst OPENAI_BATCH_MAX_REQUESTS = 50000;\n\nfunction getOpenAiBaseUrl(openAi: OpenAiEmbeddingClient): string {\n return openAi.baseUrl?.replace(/\\/$/, \"\") ?? \"\";\n}\n\nfunction getOpenAiHeaders(\n openAi: OpenAiEmbeddingClient,\n params: { json: boolean },\n): Record<string, string> {\n const headers = openAi.headers ? { ...openAi.headers } : {};\n if (params.json) {\n if (!headers[\"Content-Type\"] && !headers[\"content-type\"]) {\n headers[\"Content-Type\"] = \"application/json\";\n }\n } else {\n delete headers[\"Content-Type\"];\n delete headers[\"content-type\"];\n }\n return headers;\n}\n\nfunction splitOpenAiBatchRequests(requests: OpenAiBatchRequest[]): OpenAiBatchRequest[][] {\n if (requests.length <= OPENAI_BATCH_MAX_REQUESTS) return [requests];\n const groups: OpenAiBatchRequest[][] = [];\n for (let i = 0; i < requests.length; i += OPENAI_BATCH_MAX_REQUESTS) {\n groups.push(requests.slice(i, i + OPENAI_BATCH_MAX_REQUESTS));\n }\n return groups;\n}\n\nasync function retryAsync<T>(\n fn: () => Promise<T>,\n opts: {\n attempts: number;\n minDelayMs: number;\n maxDelayMs: number;\n jitter: number;\n shouldRetry: (err: unknown) => boolean;\n },\n): Promise<T> {\n let lastError: unknown;\n for (let attempt = 0; attempt < opts.attempts; attempt++) {\n try {\n return await fn();\n } catch (err) {\n lastError = err;\n if (!opts.shouldRetry(err) || attempt === opts.attempts - 1) {\n throw err;\n }\n const delay = Math.min(\n opts.maxDelayMs,\n opts.minDelayMs * Math.pow(2, attempt) * (1 + Math.random() * opts.jitter),\n );\n await new Promise((resolve) => setTimeout(resolve, delay));\n }\n }\n throw lastError;\n}\n\nasync function submitOpenAiBatch(params: {\n openAi: OpenAiEmbeddingClient;\n requests: OpenAiBatchRequest[];\n source: string;\n}): Promise<OpenAiBatchStatus> {\n const baseUrl = getOpenAiBaseUrl(params.openAi);\n const jsonl = params.requests.map((request) => JSON.stringify(request)).join(\"\\n\");\n const form = new FormData();\n form.append(\"purpose\", \"batch\");\n form.append(\n \"file\",\n new Blob([jsonl], { type: \"application/jsonl\" }),\n `memory-embeddings.${hashText(String(Date.now()))}.jsonl`,\n );\n\n const fileRes = await fetch(`${baseUrl}/files`, {\n method: \"POST\",\n headers: getOpenAiHeaders(params.openAi, { json: false }),\n body: form,\n });\n if (!fileRes.ok) {\n const text = await fileRes.text();\n throw new Error(`openai batch file upload failed: ${fileRes.status} ${text}`);\n }\n const filePayload = (await fileRes.json()) as { id?: string };\n if (!filePayload.id) {\n throw new Error(\"openai batch file upload failed: missing file id\");\n }\n\n const batchRes = await retryAsync(\n async () => {\n const res = await fetch(`${baseUrl}/batches`, {\n method: \"POST\",\n headers: getOpenAiHeaders(params.openAi, { json: true }),\n body: JSON.stringify({\n input_file_id: filePayload.id,\n endpoint: OPENAI_BATCH_ENDPOINT,\n completion_window: OPENAI_BATCH_COMPLETION_WINDOW,\n metadata: {\n source: params.source,\n },\n }),\n });\n if (!res.ok) {\n const text = await res.text();\n const err = new Error(`openai batch create failed: ${res.status} ${text}`) as Error & {\n status?: number;\n };\n err.status = res.status;\n throw err;\n }\n return res;\n },\n {\n attempts: 3,\n minDelayMs: 300,\n maxDelayMs: 2000,\n jitter: 0.2,\n shouldRetry: (err) => {\n const status = (err as { status?: number }).status;\n return status === 429 || (typeof status === \"number\" && status >= 500);\n },\n },\n );\n return (await batchRes.json()) as OpenAiBatchStatus;\n}\n\nasync function fetchOpenAiBatchStatus(params: {\n openAi: OpenAiEmbeddingClient;\n batchId: string;\n}): Promise<OpenAiBatchStatus> {\n const baseUrl = getOpenAiBaseUrl(params.openAi);\n const res = await fetch(`${baseUrl}/batches/${params.batchId}`, {\n headers: getOpenAiHeaders(params.openAi, { json: true }),\n });\n if (!res.ok) {\n const text = await res.text();\n throw new Error(`openai batch status failed: ${res.status} ${text}`);\n }\n return (await res.json()) as OpenAiBatchStatus;\n}\n\nasync function fetchOpenAiFileContent(params: {\n openAi: OpenAiEmbeddingClient;\n fileId: string;\n}): Promise<string> {\n const baseUrl = getOpenAiBaseUrl(params.openAi);\n const res = await fetch(`${baseUrl}/files/${params.fileId}/content`, {\n headers: getOpenAiHeaders(params.openAi, { json: true }),\n });\n if (!res.ok) {\n const text = await res.text();\n throw new Error(`openai batch file content failed: ${res.status} ${text}`);\n }\n return await res.text();\n}\n\nfunction parseOpenAiBatchOutput(text: string): OpenAiBatchOutputLine[] {\n if (!text.trim()) return [];\n return text\n .split(\"\\n\")\n .map((line) => line.trim())\n .filter(Boolean)\n .map((line) => JSON.parse(line) as OpenAiBatchOutputLine);\n}\n\nasync function readOpenAiBatchError(params: {\n openAi: OpenAiEmbeddingClient;\n errorFileId: string;\n}): Promise<string | undefined> {\n try {\n const content = await fetchOpenAiFileContent({\n openAi: params.openAi,\n fileId: params.errorFileId,\n });\n const lines = parseOpenAiBatchOutput(content);\n const first = lines.find((line) => line.error?.message || line.response?.body?.error);\n const message =\n first?.error?.message ??\n (typeof first?.response?.body?.error?.message === \"string\"\n ? first?.response?.body?.error?.message\n : undefined);\n return message;\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n return message ? `error file unavailable: ${message}` : undefined;\n }\n}\n\nasync function waitForOpenAiBatch(params: {\n openAi: OpenAiEmbeddingClient;\n batchId: string;\n wait: boolean;\n pollIntervalMs: number;\n timeoutMs: number;\n debug?: (message: string, data?: Record<string, unknown>) => void;\n initial?: OpenAiBatchStatus;\n}): Promise<{ outputFileId: string; errorFileId?: string }> {\n const start = Date.now();\n let current: OpenAiBatchStatus | undefined = params.initial;\n while (true) {\n const status =\n current ??\n (await fetchOpenAiBatchStatus({\n openAi: params.openAi,\n batchId: params.batchId,\n }));\n const state = status.status ?? \"unknown\";\n if (state === \"completed\") {\n if (!status.output_file_id) {\n throw new Error(`openai batch ${params.batchId} completed without output file`);\n }\n return {\n outputFileId: status.output_file_id,\n errorFileId: status.error_file_id ?? undefined,\n };\n }\n if ([\"failed\", \"expired\", \"cancelled\", \"canceled\"].includes(state)) {\n const detail = status.error_file_id\n ? await readOpenAiBatchError({ openAi: params.openAi, errorFileId: status.error_file_id })\n : undefined;\n const suffix = detail ? `: ${detail}` : \"\";\n throw new Error(`openai batch ${params.batchId} ${state}${suffix}`);\n }\n if (!params.wait) {\n throw new Error(`openai batch ${params.batchId} still ${state}; wait disabled`);\n }\n if (Date.now() - start > params.timeoutMs) {\n throw new Error(`openai batch ${params.batchId} timed out after ${params.timeoutMs}ms`);\n }\n params.debug?.(`openai batch ${params.batchId} ${state}; waiting ${params.pollIntervalMs}ms`);\n await new Promise((resolve) => setTimeout(resolve, params.pollIntervalMs));\n current = undefined;\n }\n}\n\nasync function runWithConcurrency<T>(tasks: Array<() => Promise<T>>, limit: number): Promise<T[]> {\n if (tasks.length === 0) return [];\n const resolvedLimit = Math.max(1, Math.min(limit, tasks.length));\n const results: T[] = Array.from({ length: tasks.length });\n let next = 0;\n let firstError: unknown = null;\n\n const workers = Array.from({ length: resolvedLimit }, async () => {\n while (true) {\n if (firstError) return;\n const index = next;\n next += 1;\n if (index >= tasks.length) return;\n try {\n results[index] = await tasks[index]();\n } catch (err) {\n firstError = err;\n return;\n }\n }\n });\n\n await Promise.allSettled(workers);\n if (firstError) throw firstError;\n return results;\n}\n\nexport async function runOpenAiEmbeddingBatches(params: {\n openAi: OpenAiEmbeddingClient;\n source: string;\n requests: OpenAiBatchRequest[];\n wait: boolean;\n pollIntervalMs: number;\n timeoutMs: number;\n concurrency: number;\n debug?: (message: string, data?: Record<string, unknown>) => void;\n}): Promise<Map<string, number[]>> {\n if (params.requests.length === 0) return new Map();\n const groups = splitOpenAiBatchRequests(params.requests);\n const byCustomId = new Map<string, number[]>();\n\n const tasks = groups.map((group, groupIndex) => async () => {\n const batchInfo = await submitOpenAiBatch({\n openAi: params.openAi,\n requests: group,\n source: params.source,\n });\n if (!batchInfo.id) {\n throw new Error(\"openai batch create failed: missing batch id\");\n }\n\n params.debug?.(\"memory embeddings: openai batch created\", {\n batchId: batchInfo.id,\n status: batchInfo.status,\n group: groupIndex + 1,\n groups: groups.length,\n requests: group.length,\n });\n\n if (!params.wait && batchInfo.status !== \"completed\") {\n throw new Error(\n `openai batch ${batchInfo.id} submitted; enable batch.wait to await completion`,\n );\n }\n\n const completed =\n batchInfo.status === \"completed\"\n ? {\n outputFileId: batchInfo.output_file_id ?? \"\",\n errorFileId: batchInfo.error_file_id ?? undefined,\n }\n : await waitForOpenAiBatch({\n openAi: params.openAi,\n batchId: batchInfo.id,\n wait: params.wait,\n pollIntervalMs: params.pollIntervalMs,\n timeoutMs: params.timeoutMs,\n debug: params.debug,\n initial: batchInfo,\n });\n if (!completed.outputFileId) {\n throw new Error(`openai batch ${batchInfo.id} completed without output file`);\n }\n\n const content = await fetchOpenAiFileContent({\n openAi: params.openAi,\n fileId: completed.outputFileId,\n });\n const outputLines = parseOpenAiBatchOutput(content);\n const errors: string[] = [];\n const remaining = new Set(group.map((request) => request.custom_id));\n\n for (const line of outputLines) {\n const customId = line.custom_id;\n if (!customId) continue;\n remaining.delete(customId);\n if (line.error?.message) {\n errors.push(`${customId}: ${line.error.message}`);\n continue;\n }\n const response = line.response;\n const statusCode = response?.status_code ?? 0;\n if (statusCode >= 400) {\n const message =\n response?.body?.error?.message ??\n (typeof response?.body === \"string\" ? response.body : undefined) ??\n \"unknown error\";\n errors.push(`${customId}: ${message}`);\n continue;\n }\n const data = response?.body?.data ?? [];\n const embedding = data[0]?.embedding ?? [];\n if (embedding.length === 0) {\n errors.push(`${customId}: empty embedding`);\n continue;\n }\n byCustomId.set(customId, embedding);\n }\n\n if (errors.length > 0) {\n throw new Error(`openai batch ${batchInfo.id} failed: ${errors.join(\"; \")}`);\n }\n if (remaining.size > 0) {\n throw new Error(`openai batch ${batchInfo.id} missing ${remaining.size} embedding responses`);\n }\n });\n\n params.debug?.(\"memory embeddings: openai batch submit\", {\n requests: params.requests.length,\n groups: groups.length,\n wait: params.wait,\n concurrency: params.concurrency,\n pollIntervalMs: params.pollIntervalMs,\n timeoutMs: params.timeoutMs,\n });\n\n await runWithConcurrency(tasks, params.concurrency);\n return byCustomId;\n}\n","import type { GeminiEmbeddingClient } from \"./embeddings.js\";\nimport { hashText } from \"../internal.js\";\n\nexport type GeminiBatchRequest = {\n custom_id: string;\n content: { parts: Array<{ text: string }> };\n taskType: \"RETRIEVAL_DOCUMENT\" | \"RETRIEVAL_QUERY\";\n};\n\nexport type GeminiBatchStatus = {\n name?: string;\n state?: string;\n outputConfig?: { file?: string; fileId?: string };\n metadata?: {\n output?: {\n responsesFile?: string;\n };\n };\n error?: { message?: string };\n};\n\nexport type GeminiBatchOutputLine = {\n key?: string;\n custom_id?: string;\n request_id?: string;\n embedding?: { values?: number[] };\n response?: {\n embedding?: { values?: number[] };\n error?: { message?: string };\n };\n error?: { message?: string };\n};\n\nconst GEMINI_BATCH_MAX_REQUESTS = 50000;\n\nfunction getGeminiBaseUrl(gemini: GeminiEmbeddingClient): string {\n return gemini.baseUrl?.replace(/\\/$/, \"\") ?? \"\";\n}\n\nfunction getGeminiHeaders(\n gemini: GeminiEmbeddingClient,\n params: { json: boolean },\n): Record<string, string> {\n const headers = gemini.headers ? { ...gemini.headers } : {};\n if (params.json) {\n if (!headers[\"Content-Type\"] && !headers[\"content-type\"]) {\n headers[\"Content-Type\"] = \"application/json\";\n }\n } else {\n delete headers[\"Content-Type\"];\n delete headers[\"content-type\"];\n }\n return headers;\n}\n\nfunction getGeminiUploadUrl(baseUrl: string): string {\n if (baseUrl.includes(\"/v1beta\")) {\n return baseUrl.replace(/\\/v1beta\\/?$/, \"/upload/v1beta\");\n }\n return `${baseUrl.replace(/\\/$/, \"\")}/upload`;\n}\n\nfunction splitGeminiBatchRequests(requests: GeminiBatchRequest[]): GeminiBatchRequest[][] {\n if (requests.length <= GEMINI_BATCH_MAX_REQUESTS) return [requests];\n const groups: GeminiBatchRequest[][] = [];\n for (let i = 0; i < requests.length; i += GEMINI_BATCH_MAX_REQUESTS) {\n groups.push(requests.slice(i, i + GEMINI_BATCH_MAX_REQUESTS));\n }\n return groups;\n}\n\nfunction buildGeminiUploadBody(params: { jsonl: string; displayName: string }): {\n body: Blob;\n contentType: string;\n} {\n const boundary = `minimem-${hashText(params.displayName)}`;\n const jsonPart = JSON.stringify({\n file: {\n displayName: params.displayName,\n mimeType: \"application/jsonl\",\n },\n });\n const delimiter = `--${boundary}\\r\\n`;\n const closeDelimiter = `--${boundary}--\\r\\n`;\n const parts = [\n `${delimiter}Content-Type: application/json; charset=UTF-8\\r\\n\\r\\n${jsonPart}\\r\\n`,\n `${delimiter}Content-Type: application/jsonl; charset=UTF-8\\r\\n\\r\\n${params.jsonl}\\r\\n`,\n closeDelimiter,\n ];\n const body = new Blob([parts.join(\"\")], { type: \"multipart/related\" });\n return {\n body,\n contentType: `multipart/related; boundary=${boundary}`,\n };\n}\n\nasync function submitGeminiBatch(params: {\n gemini: GeminiEmbeddingClient;\n requests: GeminiBatchRequest[];\n source: string;\n}): Promise<GeminiBatchStatus> {\n const baseUrl = getGeminiBaseUrl(params.gemini);\n const jsonl = params.requests\n .map((request) =>\n JSON.stringify({\n key: request.custom_id,\n request: {\n content: request.content,\n task_type: request.taskType,\n },\n }),\n )\n .join(\"\\n\");\n const displayName = `memory-embeddings-${hashText(String(Date.now()))}`;\n const uploadPayload = buildGeminiUploadBody({ jsonl, displayName });\n\n const uploadUrl = `${getGeminiUploadUrl(baseUrl)}/files?uploadType=multipart`;\n const fileRes = await fetch(uploadUrl, {\n method: \"POST\",\n headers: {\n ...getGeminiHeaders(params.gemini, { json: false }),\n \"Content-Type\": uploadPayload.contentType,\n },\n body: uploadPayload.body,\n });\n if (!fileRes.ok) {\n const text = await fileRes.text();\n throw new Error(`gemini batch file upload failed: ${fileRes.status} ${text}`);\n }\n const filePayload = (await fileRes.json()) as { name?: string; file?: { name?: string } };\n const fileId = filePayload.name ?? filePayload.file?.name;\n if (!fileId) {\n throw new Error(\"gemini batch file upload failed: missing file id\");\n }\n\n const batchBody = {\n batch: {\n displayName: `memory-embeddings-${params.source}`,\n inputConfig: {\n file_name: fileId,\n },\n },\n };\n\n const batchEndpoint = `${baseUrl}/${params.gemini.modelPath}:asyncBatchEmbedContent`;\n const batchRes = await fetch(batchEndpoint, {\n method: \"POST\",\n headers: getGeminiHeaders(params.gemini, { json: true }),\n body: JSON.stringify(batchBody),\n });\n if (batchRes.ok) {\n return (await batchRes.json()) as GeminiBatchStatus;\n }\n const text = await batchRes.text();\n if (batchRes.status === 404) {\n throw new Error(\n \"gemini batch create failed: 404 (asyncBatchEmbedContent not available for this model/baseUrl). Disable batch.enabled or switch providers.\",\n );\n }\n throw new Error(`gemini batch create failed: ${batchRes.status} ${text}`);\n}\n\nasync function fetchGeminiBatchStatus(params: {\n gemini: GeminiEmbeddingClient;\n batchName: string;\n}): Promise<GeminiBatchStatus> {\n const baseUrl = getGeminiBaseUrl(params.gemini);\n const name = params.batchName.startsWith(\"batches/\")\n ? params.batchName\n : `batches/${params.batchName}`;\n const statusUrl = `${baseUrl}/${name}`;\n const res = await fetch(statusUrl, {\n headers: getGeminiHeaders(params.gemini, { json: true }),\n });\n if (!res.ok) {\n const text = await res.text();\n throw new Error(`gemini batch status failed: ${res.status} ${text}`);\n }\n return (await res.json()) as GeminiBatchStatus;\n}\n\nasync function fetchGeminiFileContent(params: {\n gemini: GeminiEmbeddingClient;\n fileId: string;\n}): Promise<string> {\n const baseUrl = getGeminiBaseUrl(params.gemini);\n const file = params.fileId.startsWith(\"files/\") ? params.fileId : `files/${params.fileId}`;\n const downloadUrl = `${baseUrl}/${file}:download`;\n const res = await fetch(downloadUrl, {\n headers: getGeminiHeaders(params.gemini, { json: true }),\n });\n if (!res.ok) {\n const text = await res.text();\n throw new Error(`gemini batch file content failed: ${res.status} ${text}`);\n }\n return await res.text();\n}\n\nfunction parseGeminiBatchOutput(text: string): GeminiBatchOutputLine[] {\n if (!text.trim()) return [];\n return text\n .split(\"\\n\")\n .map((line) => line.trim())\n .filter(Boolean)\n .map((line) => JSON.parse(line) as GeminiBatchOutputLine);\n}\n\nasync function waitForGeminiBatch(params: {\n gemini: GeminiEmbeddingClient;\n batchName: string;\n wait: boolean;\n pollIntervalMs: number;\n timeoutMs: number;\n debug?: (message: string, data?: Record<string, unknown>) => void;\n initial?: GeminiBatchStatus;\n}): Promise<{ outputFileId: string }> {\n const start = Date.now();\n let current: GeminiBatchStatus | undefined = params.initial;\n while (true) {\n const status =\n current ??\n (await fetchGeminiBatchStatus({\n gemini: params.gemini,\n batchName: params.batchName,\n }));\n const state = status.state ?? \"UNKNOWN\";\n if ([\"SUCCEEDED\", \"COMPLETED\", \"DONE\"].includes(state)) {\n const outputFileId =\n status.outputConfig?.file ??\n status.outputConfig?.fileId ??\n status.metadata?.output?.responsesFile;\n if (!outputFileId) {\n throw new Error(`gemini batch ${params.batchName} completed without output file`);\n }\n return { outputFileId };\n }\n if ([\"FAILED\", \"CANCELLED\", \"CANCELED\", \"EXPIRED\"].includes(state)) {\n const message = status.error?.message ?? \"unknown error\";\n throw new Error(`gemini batch ${params.batchName} ${state}: ${message}`);\n }\n if (!params.wait) {\n throw new Error(`gemini batch ${params.batchName} still ${state}; wait disabled`);\n }\n if (Date.now() - start > params.timeoutMs) {\n throw new Error(`gemini batch ${params.batchName} timed out after ${params.timeoutMs}ms`);\n }\n params.debug?.(`gemini batch ${params.batchName} ${state}; waiting ${params.pollIntervalMs}ms`);\n await new Promise((resolve) => setTimeout(resolve, params.pollIntervalMs));\n current = undefined;\n }\n}\n\nasync function runWithConcurrency<T>(tasks: Array<() => Promise<T>>, limit: number): Promise<T[]> {\n if (tasks.length === 0) return [];\n const resolvedLimit = Math.max(1, Math.min(limit, tasks.length));\n const results: T[] = Array.from({ length: tasks.length });\n let next = 0;\n let firstError: unknown = null;\n\n const workers = Array.from({ length: resolvedLimit }, async () => {\n while (true) {\n if (firstError) return;\n const index = next;\n next += 1;\n if (index >= tasks.length) return;\n try {\n results[index] = await tasks[index]();\n } catch (err) {\n firstError = err;\n return;\n }\n }\n });\n\n await Promise.allSettled(workers);\n if (firstError) throw firstError;\n return results;\n}\n\nexport async function runGeminiEmbeddingBatches(params: {\n gemini: GeminiEmbeddingClient;\n source: string;\n requests: GeminiBatchRequest[];\n wait: boolean;\n pollIntervalMs: number;\n timeoutMs: number;\n concurrency: number;\n debug?: (message: string, data?: Record<string, unknown>) => void;\n}): Promise<Map<string, number[]>> {\n if (params.requests.length === 0) return new Map();\n const groups = splitGeminiBatchRequests(params.requests);\n const byCustomId = new Map<string, number[]>();\n\n const tasks = groups.map((group, groupIndex) => async () => {\n const batchInfo = await submitGeminiBatch({\n gemini: params.gemini,\n requests: group,\n source: params.source,\n });\n const batchName = batchInfo.name ?? \"\";\n if (!batchName) {\n throw new Error(\"gemini batch create failed: missing batch name\");\n }\n\n params.debug?.(\"memory embeddings: gemini batch created\", {\n batchName,\n state: batchInfo.state,\n group: groupIndex + 1,\n groups: groups.length,\n requests: group.length,\n });\n\n if (\n !params.wait &&\n batchInfo.state &&\n ![\"SUCCEEDED\", \"COMPLETED\", \"DONE\"].includes(batchInfo.state)\n ) {\n throw new Error(\n `gemini batch ${batchName} submitted; enable batch.wait to await completion`,\n );\n }\n\n const completed =\n batchInfo.state && [\"SUCCEEDED\", \"COMPLETED\", \"DONE\"].includes(batchInfo.state)\n ? {\n outputFileId:\n batchInfo.outputConfig?.file ??\n batchInfo.outputConfig?.fileId ??\n batchInfo.metadata?.output?.responsesFile ??\n \"\",\n }\n : await waitForGeminiBatch({\n gemini: params.gemini,\n batchName,\n wait: params.wait,\n pollIntervalMs: params.pollIntervalMs,\n timeoutMs: params.timeoutMs,\n debug: params.debug,\n initial: batchInfo,\n });\n if (!completed.outputFileId) {\n throw new Error(`gemini batch ${batchName} completed without output file`);\n }\n\n const content = await fetchGeminiFileContent({\n gemini: params.gemini,\n fileId: completed.outputFileId,\n });\n const outputLines = parseGeminiBatchOutput(content);\n const errors: string[] = [];\n const remaining = new Set(group.map((request) => request.custom_id));\n\n for (const line of outputLines) {\n const customId = line.key ?? line.custom_id ?? line.request_id;\n if (!customId) continue;\n remaining.delete(customId);\n if (line.error?.message) {\n errors.push(`${customId}: ${line.error.message}`);\n continue;\n }\n if (line.response?.error?.message) {\n errors.push(`${customId}: ${line.response.error.message}`);\n continue;\n }\n const embedding = line.embedding?.values ?? line.response?.embedding?.values ?? [];\n if (embedding.length === 0) {\n errors.push(`${customId}: empty embedding`);\n continue;\n }\n byCustomId.set(customId, embedding);\n }\n\n if (errors.length > 0) {\n throw new Error(`gemini batch ${batchName} failed: ${errors.join(\"; \")}`);\n }\n if (remaining.size > 0) {\n throw new Error(`gemini batch ${batchName} missing ${remaining.size} embedding responses`);\n }\n });\n\n params.debug?.(\"memory embeddings: gemini batch submit\", {\n requests: params.requests.length,\n groups: groups.length,\n wait: params.wait,\n concurrency: params.concurrency,\n pollIntervalMs: params.pollIntervalMs,\n timeoutMs: params.timeoutMs,\n });\n\n await runWithConcurrency(tasks, params.concurrency);\n return byCustomId;\n}\n","/**\n * Tool definitions for memory operations\n *\n * These tools are compatible with:\n * - MCP (Model Context Protocol)\n * - Anthropic Claude tool use\n * - OpenAI function calling\n *\n * Note: Only memory_search is provided since the memory system is file-based.\n * Agents can use filesystem tools directly for read/write operations.\n */\n\nimport type { Minimem, MinimemSearchResult } from \"../minimem.js\";\n\n/**\n * JSON Schema for tool parameters (MCP/OpenAI/Anthropic compatible)\n */\nexport type ToolInputSchema = {\n type: \"object\";\n properties: Record<\n string,\n {\n type: string;\n description?: string;\n enum?: string[];\n items?: { type: string };\n default?: unknown;\n }\n >;\n required?: string[];\n};\n\n/**\n * Tool definition compatible with MCP, Anthropic, and OpenAI\n */\nexport type ToolDefinition = {\n name: string;\n description: string;\n inputSchema: ToolInputSchema;\n};\n\n/**\n * Tool execution result\n */\nexport type ToolResult = {\n content: Array<{ type: \"text\"; text: string }>;\n isError?: boolean;\n};\n\n/**\n * Memory search tool parameters\n */\nexport type MemorySearchParams = {\n query: string;\n maxResults?: number;\n minScore?: number;\n directories?: string[];\n /** \"compact\" returns lightweight index; \"full\" returns complete snippets (default: \"compact\") */\n detail?: \"compact\" | \"full\";\n /** Filter by observation type (e.g., \"decision\", \"bugfix\", \"feature\", \"discovery\") */\n type?: string;\n};\n\n/**\n * Memory get details tool parameters\n */\nexport type MemoryGetDetailsParams = {\n results: Array<{ path: string; startLine: number; endLine: number }>;\n directories?: string[];\n};\n\n/**\n * Knowledge search tool parameters\n */\nexport type KnowledgeSearchParams = {\n query: string;\n domain?: string[];\n entities?: string[];\n minConfidence?: number;\n knowledgeType?: string;\n maxResults?: number;\n minScore?: number;\n directories?: string[];\n};\n\n/**\n * Knowledge graph traversal parameters\n */\nexport type KnowledgeGraphParams = {\n nodeId: string;\n depth?: number;\n relation?: string;\n layer?: string;\n directories?: string[];\n};\n\n/**\n * Knowledge path parameters\n */\nexport type KnowledgePathParams = {\n fromId: string;\n toId: string;\n maxDepth?: number;\n directories?: string[];\n};\n\n/**\n * Search result with source directory\n */\ntype SearchResultWithSource = MinimemSearchResult & {\n memoryDir: string;\n};\n\nexport const MEMORY_SEARCH_TOOL: ToolDefinition = {\n name: \"memory_search\",\n description:\n \"Semantically search through memory files (MEMORY.md and memory/*.md). \" +\n \"Use this to recall prior decisions, facts, preferences, people, dates, or context. \" +\n \"Returns ranked snippets with file paths and line numbers. \" +\n \"When multiple memory directories are configured, searches all by default.\",\n inputSchema: {\n type: \"object\",\n properties: {\n query: {\n type: \"string\",\n description: \"Natural language search query\",\n },\n maxResults: {\n type: \"number\",\n description: \"Maximum number of results to return (default: 10)\",\n },\n minScore: {\n type: \"number\",\n description: \"Minimum relevance score threshold 0-1 (default: 0.3)\",\n },\n directories: {\n type: \"array\",\n items: { type: \"string\" },\n description:\n \"Optional: filter to specific memory directories by name/path. \" +\n \"If omitted, searches all configured directories.\",\n },\n detail: {\n type: \"string\",\n enum: [\"compact\", \"full\"],\n description:\n \"Result detail level. 'compact' returns a lightweight index with short previews (~80 chars). \" +\n \"'full' returns complete snippets. Use 'compact' first, then memory_get_details for selected results. \" +\n \"(default: 'compact')\",\n },\n type: {\n type: \"string\",\n description:\n \"Filter by observation type. Matches <!-- type: X --> comments in memory entries. \" +\n \"Common types: decision, bugfix, feature, discovery, context, note.\",\n },\n },\n required: [\"query\"],\n },\n};\n\nexport const MEMORY_GET_DETAILS_TOOL: ToolDefinition = {\n name: \"memory_get_details\",\n description:\n \"Fetch full text for specific memory chunks identified by path and line range. \" +\n \"Use after memory_search with compact results to get details for selected items only. \" +\n \"This two-step approach significantly reduces token usage.\",\n inputSchema: {\n type: \"object\",\n properties: {\n results: {\n type: \"array\",\n items: { type: \"object\" },\n description:\n \"Array of { path, startLine, endLine } objects from compact search results.\",\n },\n directories: {\n type: \"array\",\n items: { type: \"string\" },\n description: \"Optional: filter to specific memory directories.\",\n },\n },\n required: [\"results\"],\n },\n};\n\nexport const KNOWLEDGE_SEARCH_TOOL: ToolDefinition = {\n name: \"knowledge_search\",\n description:\n \"Search memory with knowledge metadata filters. \" +\n \"Filter by domain, entities, confidence level, or knowledge type (observation, entity, domain-summary). \" +\n \"Combines semantic search with structured knowledge filtering.\",\n inputSchema: {\n type: \"object\",\n properties: {\n query: {\n type: \"string\",\n description: \"Natural language search query\",\n },\n domain: {\n type: \"array\",\n items: { type: \"string\" },\n description: \"Filter to entries in these knowledge domains\",\n },\n entities: {\n type: \"array\",\n items: { type: \"string\" },\n description: \"Filter to entries referencing these entities\",\n },\n minConfidence: {\n type: \"number\",\n description: \"Minimum confidence threshold (0-1)\",\n },\n knowledgeType: {\n type: \"string\",\n description: \"Filter by knowledge type: observation, entity, domain-summary\",\n },\n maxResults: {\n type: \"number\",\n description: \"Maximum number of results (default: 10)\",\n },\n minScore: {\n type: \"number\",\n description: \"Minimum relevance score 0-1 (default: 0.3)\",\n },\n directories: {\n type: \"array\",\n items: { type: \"string\" },\n description: \"Optional: filter to specific memory directories\",\n },\n },\n required: [\"query\"],\n },\n};\n\nexport const KNOWLEDGE_GRAPH_TOOL: ToolDefinition = {\n name: \"knowledge_graph\",\n description:\n \"Traverse knowledge graph links from a note. \" +\n \"Returns neighbor nodes connected by typed relationships (e.g., relates-to, supports, contradicts). \" +\n \"Use depth parameter for multi-hop traversal.\",\n inputSchema: {\n type: \"object\",\n properties: {\n nodeId: {\n type: \"string\",\n description: \"The knowledge node ID to start traversal from\",\n },\n depth: {\n type: \"number\",\n description: \"Maximum traversal depth (default: 1, max: 3)\",\n default: 1,\n },\n relation: {\n type: \"string\",\n description: \"Optional: filter to specific relation type\",\n },\n layer: {\n type: \"string\",\n description: \"Optional: filter to specific graph layer\",\n },\n directories: {\n type: \"array\",\n items: { type: \"string\" },\n description: \"Optional: filter to specific memory directories\",\n },\n },\n required: [\"nodeId\"],\n },\n};\n\nexport const KNOWLEDGE_PATH_TOOL: ToolDefinition = {\n name: \"knowledge_path\",\n description:\n \"Find the shortest path between two knowledge nodes in the graph. \" +\n \"Uses BFS traversal up to a configurable max depth. \" +\n \"Returns the sequence of links connecting the two nodes.\",\n inputSchema: {\n type: \"object\",\n properties: {\n fromId: {\n type: \"string\",\n description: \"Starting knowledge node ID\",\n },\n toId: {\n type: \"string\",\n description: \"Target knowledge node ID\",\n },\n maxDepth: {\n type: \"number\",\n description: \"Maximum path length (default: 3)\",\n default: 3,\n },\n directories: {\n type: \"array\",\n items: { type: \"string\" },\n description: \"Optional: filter to specific memory directories\",\n },\n },\n required: [\"fromId\", \"toId\"],\n },\n};\n\n/**\n * All available memory tools\n */\nexport const MEMORY_TOOLS: ToolDefinition[] = [\n MEMORY_SEARCH_TOOL,\n MEMORY_GET_DETAILS_TOOL,\n KNOWLEDGE_SEARCH_TOOL,\n KNOWLEDGE_GRAPH_TOOL,\n KNOWLEDGE_PATH_TOOL,\n];\n\n/**\n * Get tool definitions for use with LLM APIs\n */\nexport function getToolDefinitions(): ToolDefinition[] {\n return MEMORY_TOOLS;\n}\n\n/**\n * Memory instance with its directory path\n */\nexport type MemoryInstance = {\n minimem: Minimem;\n memoryDir: string;\n name?: string;\n};\n\n/**\n * Tool executor that handles memory search across multiple directories\n */\nexport class MemoryToolExecutor {\n private instances: MemoryInstance[];\n\n constructor(instances: Minimem | MemoryInstance | MemoryInstance[]) {\n // Normalize to array of MemoryInstance\n if (Array.isArray(instances)) {\n this.instances = instances;\n } else if (\"minimem\" in instances) {\n this.instances = [instances];\n } else {\n // Legacy: single Minimem instance without directory info\n this.instances = [{ minimem: instances, memoryDir: \"default\" }];\n }\n }\n\n /**\n * Get list of configured directory names/paths\n */\n getDirectories(): string[] {\n return this.instances.map((i) => i.name ?? i.memoryDir);\n }\n\n /**\n * Execute a tool by name with given parameters\n */\n async execute(\n toolName: string,\n params: Record<string, unknown>,\n ): Promise<ToolResult> {\n try {\n switch (toolName) {\n case \"memory_search\":\n return await this.memorySearch(params as MemorySearchParams);\n case \"memory_get_details\":\n return await this.memoryGetDetails(params as MemoryGetDetailsParams);\n case \"knowledge_search\":\n return await this.knowledgeSearch(params as KnowledgeSearchParams);\n case \"knowledge_graph\":\n return await this.knowledgeGraph(params as KnowledgeGraphParams);\n case \"knowledge_path\":\n return await this.knowledgePath(params as KnowledgePathParams);\n default:\n return {\n content: [{ type: \"text\", text: `Unknown tool: ${toolName}` }],\n isError: true,\n };\n }\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n return {\n content: [{ type: \"text\", text: `Error: ${message}` }],\n isError: true,\n };\n }\n }\n\n /**\n * Filter instances by directory names/paths\n */\n private filterInstances(directories?: string[]): MemoryInstance[] | null {\n if (!directories || directories.length === 0) return this.instances;\n\n const dirFilter = new Set(directories.map((d) => d.toLowerCase()));\n const filtered = this.instances.filter((i) => {\n const name = (i.name ?? i.memoryDir).toLowerCase();\n const dir = i.memoryDir.toLowerCase();\n return (\n dirFilter.has(name) ||\n dirFilter.has(dir) ||\n [...dirFilter].some((f) => dir.includes(f) || name.includes(f))\n );\n });\n\n return filtered.length > 0 ? filtered : null;\n }\n\n private async memorySearch(params: MemorySearchParams): Promise<ToolResult> {\n const maxResults = params.maxResults ?? 10;\n const minScore = params.minScore;\n const detail = params.detail ?? \"compact\";\n\n const instancesToSearch = this.filterInstances(params.directories);\n if (!instancesToSearch) {\n const available = this.getDirectories().join(\", \");\n return {\n content: [\n {\n type: \"text\",\n text: `No matching directories found. Available: ${available}`,\n },\n ],\n isError: true,\n };\n }\n\n // Search all matching instances\n const allResults: SearchResultWithSource[] = [];\n\n for (const instance of instancesToSearch) {\n const perDirMax = Math.ceil(maxResults * 1.5);\n const results = await instance.minimem.search(params.query, {\n maxResults: perDirMax,\n minScore,\n type: params.type,\n });\n\n for (const result of results) {\n allResults.push({\n ...result,\n memoryDir: instance.name ?? instance.memoryDir,\n });\n }\n }\n\n // Sort by score and limit\n allResults.sort((a, b) => b.score - a.score);\n const topResults = allResults.slice(0, maxResults);\n\n if (topResults.length === 0) {\n return {\n content: [{ type: \"text\", text: \"No results found.\" }],\n };\n }\n\n const showSource = instancesToSearch.length > 1;\n\n if (detail === \"compact\") {\n return this.formatCompactResults(topResults, showSource, instancesToSearch.length);\n }\n\n return this.formatFullResults(topResults, showSource, instancesToSearch.length);\n }\n\n private formatCompactResults(\n results: SearchResultWithSource[],\n showSource: boolean,\n dirCount: number,\n ): ToolResult {\n const formatted = results\n .map((r, i) => {\n const location = `${r.path}:${r.startLine}-${r.endLine}`;\n const score = (r.score * 100).toFixed(0);\n const source = showSource ? ` [${r.memoryDir}]` : \"\";\n const preview = compactPreview(r.snippet);\n return `[${i}] ${location}${source} (${score}%) — ${preview}`;\n })\n .join(\"\\n\");\n\n const hint = \"\\n\\nUse memory_get_details to fetch full text for selected results.\";\n const dirSummary = dirCount > 1 ? `\\n(Searched ${dirCount} directories)` : \"\";\n\n return {\n content: [{ type: \"text\", text: formatted + dirSummary + hint }],\n };\n }\n\n private formatFullResults(\n results: SearchResultWithSource[],\n showSource: boolean,\n dirCount: number,\n ): ToolResult {\n const formatted = results\n .map((r, i) => {\n const location = `${r.path}:${r.startLine}-${r.endLine}`;\n const score = (r.score * 100).toFixed(1);\n const source = showSource ? ` [${r.memoryDir}]` : \"\";\n return `[${i + 1}] ${location}${source} (${score}% match)\\n${r.snippet}`;\n })\n .join(\"\\n\\n\");\n\n const dirSummary =\n dirCount > 1 ? `\\n\\n(Searched ${dirCount} directories)` : \"\";\n\n return {\n content: [{ type: \"text\", text: formatted + dirSummary }],\n };\n }\n\n private async memoryGetDetails(params: MemoryGetDetailsParams): Promise<ToolResult> {\n if (!params.results || params.results.length === 0) {\n return {\n content: [{ type: \"text\", text: \"No results specified.\" }],\n isError: true,\n };\n }\n\n const instancesToSearch = this.filterInstances(params.directories);\n if (!instancesToSearch) {\n const available = this.getDirectories().join(\", \");\n return {\n content: [\n {\n type: \"text\",\n text: `No matching directories found. Available: ${available}`,\n },\n ],\n isError: true,\n };\n }\n\n const details: string[] = [];\n\n for (const ref of params.results) {\n let found = false;\n\n for (const instance of instancesToSearch) {\n const lineCount = ref.endLine - ref.startLine + 1;\n const result = await instance.minimem.readLines(ref.path, {\n from: ref.startLine,\n lines: lineCount,\n });\n\n if (result) {\n const location = `${ref.path}:${result.startLine}-${result.endLine}`;\n details.push(`--- ${location} ---\\n${result.content}`);\n found = true;\n break;\n }\n }\n\n if (!found) {\n details.push(`--- ${ref.path}:${ref.startLine}-${ref.endLine} ---\\n(not found)`);\n }\n }\n\n return {\n content: [{ type: \"text\", text: details.join(\"\\n\\n\") }],\n };\n }\n\n private async knowledgeSearch(params: KnowledgeSearchParams): Promise<ToolResult> {\n const instancesToSearch = this.filterInstances(params.directories);\n if (!instancesToSearch) {\n const available = this.getDirectories().join(\", \");\n return {\n content: [{ type: \"text\", text: `No matching directories found. Available: ${available}` }],\n isError: true,\n };\n }\n\n const maxResults = params.maxResults ?? 10;\n const allResults: SearchResultWithSource[] = [];\n\n for (const instance of instancesToSearch) {\n const results = await instance.minimem.knowledgeSearch(params.query, {\n maxResults: Math.ceil(maxResults * 1.5),\n minScore: params.minScore,\n domain: params.domain,\n entities: params.entities,\n minConfidence: params.minConfidence,\n knowledgeType: params.knowledgeType,\n });\n\n for (const result of results) {\n allResults.push({\n ...result,\n memoryDir: instance.name ?? instance.memoryDir,\n });\n }\n }\n\n allResults.sort((a, b) => b.score - a.score);\n const topResults = allResults.slice(0, maxResults);\n\n if (topResults.length === 0) {\n return { content: [{ type: \"text\", text: \"No knowledge results found.\" }] };\n }\n\n const formatted = topResults\n .map((r, i) => {\n const location = `${r.path}:${r.startLine}-${r.endLine}`;\n const score = (r.score * 100).toFixed(0);\n const preview = compactPreview(r.snippet);\n return `[${i}] ${location} (${score}%) — ${preview}`;\n })\n .join(\"\\n\");\n\n return { content: [{ type: \"text\", text: formatted }] };\n }\n\n private async knowledgeGraph(params: KnowledgeGraphParams): Promise<ToolResult> {\n const instancesToSearch = this.filterInstances(params.directories);\n if (!instancesToSearch) {\n const available = this.getDirectories().join(\", \");\n return {\n content: [{ type: \"text\", text: `No matching directories found. Available: ${available}` }],\n isError: true,\n };\n }\n\n const depth = Math.min(params.depth ?? 1, 3);\n const allNeighbors: Array<{ id: string; depth: number; relation: string; layer: string | null; memoryDir: string }> = [];\n\n for (const instance of instancesToSearch) {\n const neighbors = instance.minimem.getGraphNeighbors(params.nodeId, depth, {\n relation: params.relation,\n layer: params.layer,\n });\n\n for (const n of neighbors) {\n allNeighbors.push({\n id: n.id,\n depth: n.depth,\n relation: n.link.relation,\n layer: n.link.layer,\n memoryDir: instance.name ?? instance.memoryDir,\n });\n }\n }\n\n if (allNeighbors.length === 0) {\n return { content: [{ type: \"text\", text: `No neighbors found for node \"${params.nodeId}\".` }] };\n }\n\n const formatted = allNeighbors\n .map((n) => ` [depth=${n.depth}] ${n.id} —(${n.relation})${n.layer ? ` [${n.layer}]` : \"\"}`)\n .join(\"\\n\");\n\n return {\n content: [{ type: \"text\", text: `Neighbors of \"${params.nodeId}\":\\n${formatted}` }],\n };\n }\n\n private async knowledgePath(params: KnowledgePathParams): Promise<ToolResult> {\n const instancesToSearch = this.filterInstances(params.directories);\n if (!instancesToSearch) {\n const available = this.getDirectories().join(\", \");\n return {\n content: [{ type: \"text\", text: `No matching directories found. Available: ${available}` }],\n isError: true,\n };\n }\n\n const maxDepth = Math.min(params.maxDepth ?? 3, 5);\n\n // Try each instance until a path is found\n for (const instance of instancesToSearch) {\n const path = instance.minimem.getGraphPath(params.fromId, params.toId, maxDepth);\n if (path.length > 0) {\n const steps = path\n .map((link) => ` ${link.fromId} —(${link.relation})→ ${link.toId}`)\n .join(\"\\n\");\n return {\n content: [{\n type: \"text\",\n text: `Path from \"${params.fromId}\" to \"${params.toId}\" (${path.length} steps):\\n${steps}`,\n }],\n };\n }\n }\n\n return {\n content: [{\n type: \"text\",\n text: `No path found from \"${params.fromId}\" to \"${params.toId}\" within depth ${maxDepth}.`,\n }],\n };\n }\n}\n\n/**\n * Generate a compact preview from a snippet (~80 chars).\n * Prefers the first heading or first non-empty line.\n */\nfunction compactPreview(snippet: string): string {\n const maxLen = 80;\n const lines = snippet.split(\"\\n\").filter((l) => l.trim());\n if (lines.length === 0) return \"(empty)\";\n\n // Prefer a heading line\n const heading = lines.find((l) => l.startsWith(\"#\"));\n const text = heading ?? lines[0];\n // Strip markdown heading markers for cleaner display\n const cleaned = text.replace(/^#+\\s*/, \"\").trim();\n\n if (cleaned.length <= maxLen) return `\"${cleaned}\"`;\n return `\"${cleaned.slice(0, maxLen - 3)}...\"`;\n}\n\n/**\n * Create a tool executor for the given Minimem instance(s)\n */\nexport function createToolExecutor(\n instances: Minimem | MemoryInstance | MemoryInstance[],\n): MemoryToolExecutor {\n return new MemoryToolExecutor(instances);\n}\n","/**\n * MCP (Model Context Protocol) Server for Minimem\n *\n * Provides memory tools via JSON-RPC 2.0 over stdio.\n * Compatible with Claude Desktop, Cursor, and other MCP clients.\n *\n * Usage:\n * import { Minimem } from \"minimem\";\n * import { createMcpServer, runMcpServer } from \"minimem/mcp\";\n *\n * const minimem = await Minimem.create({ ... });\n * const server = createMcpServer(minimem);\n * await runMcpServer(server); // Runs over stdio\n */\n\nimport * as readline from \"node:readline\";\nimport type { Minimem } from \"../minimem.js\";\nimport {\n MEMORY_TOOLS,\n type ToolDefinition,\n type ToolResult,\n type MemoryInstance,\n MemoryToolExecutor,\n} from \"./tools.js\";\n\nconst PROTOCOL_VERSION = \"2024-11-05\";\nconst SERVER_NAME = \"minimem\";\nconst SERVER_VERSION = \"0.1.0\";\n\n/**\n * JSON-RPC 2.0 request\n */\ntype JsonRpcRequest = {\n jsonrpc: \"2.0\";\n id: string | number;\n method: string;\n params?: Record<string, unknown>;\n};\n\n/**\n * JSON-RPC 2.0 response\n */\ntype JsonRpcResponse = {\n jsonrpc: \"2.0\";\n id: string | number | null;\n result?: unknown;\n error?: {\n code: number;\n message: string;\n data?: unknown;\n };\n};\n\n/**\n * JSON-RPC 2.0 notification (no id)\n */\ntype JsonRpcNotification = {\n jsonrpc: \"2.0\";\n method: string;\n params?: Record<string, unknown>;\n};\n\n/**\n * MCP Server capabilities\n */\ntype ServerCapabilities = {\n tools?: {\n listChanged?: boolean;\n };\n};\n\n/**\n * MCP Server info\n */\ntype ServerInfo = {\n name: string;\n version: string;\n};\n\n/**\n * MCP Initialize result\n */\ntype InitializeResult = {\n protocolVersion: string;\n capabilities: ServerCapabilities;\n serverInfo: ServerInfo;\n};\n\n/**\n * MCP Tool in list format\n */\ntype McpTool = {\n name: string;\n description: string;\n inputSchema: {\n type: \"object\";\n properties: Record<string, unknown>;\n required?: string[];\n };\n};\n\n/**\n * MCP Server implementation\n */\nexport class McpServer {\n private executor: MemoryToolExecutor;\n private initialized = false;\n\n constructor(instances: Minimem | MemoryInstance | MemoryInstance[]) {\n this.executor = new MemoryToolExecutor(instances);\n }\n\n /**\n * Handle a JSON-RPC request and return a response\n */\n async handleRequest(request: JsonRpcRequest): Promise<JsonRpcResponse> {\n try {\n const result = await this.dispatch(request.method, request.params);\n return {\n jsonrpc: \"2.0\",\n id: request.id,\n result,\n };\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n const code = err instanceof McpError ? err.code : -32603;\n return {\n jsonrpc: \"2.0\",\n id: request.id,\n error: { code, message },\n };\n }\n }\n\n /**\n * Dispatch a method call\n */\n private async dispatch(\n method: string,\n params?: Record<string, unknown>,\n ): Promise<unknown> {\n switch (method) {\n case \"initialize\":\n return this.initialize(params);\n case \"initialized\":\n // Notification, no response needed\n return {};\n case \"tools/list\":\n return this.listTools();\n case \"tools/call\":\n return this.callTool(params);\n case \"ping\":\n return {};\n default:\n throw new McpError(-32601, `Method not found: ${method}`);\n }\n }\n\n /**\n * Handle initialize request\n */\n private initialize(\n params?: Record<string, unknown>,\n ): InitializeResult {\n this.initialized = true;\n return {\n protocolVersion: PROTOCOL_VERSION,\n capabilities: {\n tools: {\n listChanged: false,\n },\n },\n serverInfo: {\n name: SERVER_NAME,\n version: SERVER_VERSION,\n },\n };\n }\n\n /**\n * List available tools\n */\n private listTools(): { tools: McpTool[] } {\n const tools: McpTool[] = MEMORY_TOOLS.map((tool) => ({\n name: tool.name,\n description: tool.description,\n inputSchema: tool.inputSchema,\n }));\n return { tools };\n }\n\n /**\n * Call a tool\n */\n private async callTool(\n params?: Record<string, unknown>,\n ): Promise<{ content: Array<{ type: string; text: string }>; isError?: boolean }> {\n if (!params?.name || typeof params.name !== \"string\") {\n throw new McpError(-32602, \"Missing tool name\");\n }\n\n const toolName = params.name;\n const toolParams = (params.arguments ?? {}) as Record<string, unknown>;\n\n const result = await this.executor.execute(toolName, toolParams);\n return result;\n }\n}\n\n/**\n * Custom error class for MCP errors\n */\nclass McpError extends Error {\n constructor(\n public code: number,\n message: string,\n ) {\n super(message);\n this.name = \"McpError\";\n }\n}\n\n/**\n * Create an MCP server for the given Minimem instance(s)\n */\nexport function createMcpServer(\n instances: Minimem | MemoryInstance | MemoryInstance[],\n): McpServer {\n return new McpServer(instances);\n}\n\n/**\n * Run the MCP server over stdio\n */\nexport async function runMcpServer(server: McpServer): Promise<void> {\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n terminal: false,\n });\n\n const send = (message: JsonRpcResponse | JsonRpcNotification) => {\n const json = JSON.stringify(message);\n process.stdout.write(json + \"\\n\");\n };\n\n rl.on(\"line\", async (line) => {\n if (!line.trim()) return;\n\n try {\n const request = JSON.parse(line) as JsonRpcRequest;\n\n if (request.jsonrpc !== \"2.0\") {\n send({\n jsonrpc: \"2.0\",\n id: request.id ?? null,\n error: { code: -32600, message: \"Invalid JSON-RPC version\" },\n });\n return;\n }\n\n // Handle notification (no id)\n if (request.id === undefined) {\n await server.handleRequest({ ...request, id: 0 });\n return;\n }\n\n const response = await server.handleRequest(request);\n send(response);\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n send({\n jsonrpc: \"2.0\",\n id: null,\n error: { code: -32700, message: `Parse error: ${message}` },\n });\n }\n });\n\n rl.on(\"close\", () => {\n process.exit(0);\n });\n\n // Keep the process alive\n await new Promise(() => {});\n}\n\n/**\n * MCP server configuration for claude_desktop_config.json\n *\n * Example:\n * {\n * \"mcpServers\": {\n * \"minimem\": {\n * \"command\": \"node\",\n * \"args\": [\"path/to/your/mcp-server.js\"],\n * \"env\": {\n * \"MEMORY_DIR\": \"/path/to/memory\"\n * }\n * }\n * }\n * }\n */\nexport type McpServerConfig = {\n command: string;\n args: string[];\n env?: Record<string, string>;\n};\n\n/**\n * Generate MCP server config for Claude Desktop\n */\nexport function generateMcpConfig(opts: {\n serverPath: string;\n memoryDir: string;\n embeddingProvider?: \"openai\" | \"gemini\" | \"local\" | \"auto\";\n}): McpServerConfig {\n return {\n command: \"node\",\n args: [opts.serverPath],\n env: {\n MEMORY_DIR: opts.memoryDir,\n ...(opts.embeddingProvider ? { EMBEDDING_PROVIDER: opts.embeddingProvider } : {}),\n },\n };\n}\n","/**\n * MemoryIndexer - Handles file indexing and embedding management\n *\n * Responsible for:\n * - Processing memory files into chunks\n * - Computing and caching embeddings\n * - Managing file records in the database\n * - Detecting stale content\n */\n\nimport { randomUUID } from \"node:crypto\";\nimport fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport type { DatabaseSync } from \"node:sqlite\";\n\nimport {\n buildFileEntry,\n chunkMarkdown,\n hashText,\n listMemoryFiles,\n type MemoryChunk,\n type MemoryFileEntry,\n parseEmbedding,\n vectorToBlob,\n type DebugFn,\n} from \"../internal.js\";\nimport type {\n EmbeddingProvider,\n OpenAiEmbeddingClient,\n GeminiEmbeddingClient,\n} from \"../embeddings/embeddings.js\";\nimport {\n runOpenAiEmbeddingBatches,\n type OpenAiBatchRequest,\n OPENAI_BATCH_ENDPOINT,\n} from \"../embeddings/batch-openai.js\";\nimport { runGeminiEmbeddingBatches, type GeminiBatchRequest } from \"../embeddings/batch-gemini.js\";\n\nconst META_KEY = \"memory_index_meta_v1\";\nconst EMBEDDING_CACHE_TABLE = \"embedding_cache\";\nconst VECTOR_TABLE = \"chunks_vec\";\nconst FTS_TABLE = \"chunks_fts\";\nconst EMBEDDING_RETRY_MAX_ATTEMPTS = 3;\nconst EMBEDDING_RETRY_BASE_DELAY_MS = 500;\nconst EMBEDDING_RETRY_MAX_DELAY_MS = 8000;\n\nexport type IndexerConfig = {\n memoryDir: string;\n chunking: { tokens: number; overlap: number };\n cache: { enabled: boolean; maxEntries: number };\n batch: {\n enabled: boolean;\n wait: boolean;\n concurrency: number;\n pollIntervalMs: number;\n timeoutMs: number;\n };\n ftsEnabled: boolean;\n debug?: DebugFn;\n};\n\nexport type MemoryIndexMeta = {\n model: string;\n provider: string;\n providerKey?: string;\n chunkTokens: number;\n chunkOverlap: number;\n vectorDims?: number;\n};\n\nexport type IndexStats = {\n filesProcessed: number;\n chunksCreated: number;\n staleRemoved: number;\n};\n\n/**\n * MemoryIndexer handles file indexing, chunking, and embedding management\n */\nexport class MemoryIndexer {\n private readonly config: IndexerConfig;\n private readonly db: DatabaseSync;\n private readonly provider: EmbeddingProvider;\n private readonly providerKey: string;\n private readonly openAi?: OpenAiEmbeddingClient;\n private readonly gemini?: GeminiEmbeddingClient;\n\n // Vector/FTS state (shared with parent)\n private vectorState: {\n available: boolean;\n dims?: number;\n };\n private ftsAvailable: boolean;\n\n constructor(\n db: DatabaseSync,\n provider: EmbeddingProvider,\n config: IndexerConfig,\n options?: {\n openAi?: OpenAiEmbeddingClient;\n gemini?: GeminiEmbeddingClient;\n vectorState?: { available: boolean; dims?: number };\n ftsAvailable?: boolean;\n }\n ) {\n this.db = db;\n this.provider = provider;\n this.config = config;\n this.openAi = options?.openAi;\n this.gemini = options?.gemini;\n this.vectorState = options?.vectorState ?? { available: false };\n this.ftsAvailable = options?.ftsAvailable ?? false;\n this.providerKey = this.computeProviderKey();\n }\n\n /**\n * Update vector/FTS availability (called by parent when extensions load)\n */\n setVectorState(state: { available: boolean; dims?: number }): void {\n this.vectorState = state;\n }\n\n setFtsAvailable(available: boolean): void {\n this.ftsAvailable = available;\n }\n\n getVectorDims(): number | undefined {\n return this.vectorState.dims;\n }\n\n /**\n * Compute a unique key for the current provider configuration\n */\n private computeProviderKey(): string {\n const parts: string[] = [this.provider.id, this.provider.model];\n if (this.openAi) {\n parts.push(this.openAi.baseUrl);\n }\n if (this.gemini) {\n parts.push(this.gemini.baseUrl);\n }\n return hashText(parts.join(\":\"));\n }\n\n /**\n * Read index metadata from database\n */\n readMeta(): MemoryIndexMeta | null {\n try {\n const row = this.db.prepare(`SELECT value FROM meta WHERE key = ?`).get(META_KEY) as\n | { value: string }\n | undefined;\n if (!row?.value) return null;\n return JSON.parse(row.value) as MemoryIndexMeta;\n } catch {\n return null;\n }\n }\n\n /**\n * Write index metadata to database\n */\n writeMeta(meta: MemoryIndexMeta): void {\n this.db\n .prepare(`INSERT OR REPLACE INTO meta (key, value) VALUES (?, ?)`)\n .run(META_KEY, JSON.stringify(meta));\n }\n\n /**\n * Check if the index is stale by comparing file mtimes\n */\n async isStale(): Promise<boolean> {\n try {\n const files = await listMemoryFiles(this.config.memoryDir);\n\n const stored = this.db\n .prepare(`SELECT path, mtime FROM files WHERE source = ?`)\n .all(\"memory\") as Array<{ path: string; mtime: number }>;\n\n if (files.length !== stored.length) {\n this.config.debug?.(`Stale: file count changed (${stored.length} -> ${files.length})`);\n return true;\n }\n\n const storedMap = new Map(stored.map((f) => [f.path, f.mtime]));\n\n for (const absPath of files) {\n const relPath = path.relative(this.config.memoryDir, absPath).replace(/\\\\/g, \"/\");\n const storedMtime = storedMap.get(relPath);\n\n if (storedMtime === undefined) {\n this.config.debug?.(`Stale: new file ${relPath}`);\n return true;\n }\n\n const stat = await fs.stat(absPath);\n const currentMtime = Math.floor(stat.mtimeMs);\n if (currentMtime !== storedMtime) {\n this.config.debug?.(`Stale: mtime changed for ${relPath}`);\n return true;\n }\n }\n\n return false;\n } catch (err) {\n this.config.debug?.(`Stale check failed: ${String(err)}`);\n return true;\n }\n }\n\n /**\n * Check if a full reindex is needed based on configuration changes\n */\n needsFullReindex(force?: boolean): boolean {\n const meta = this.readMeta();\n return (\n force === true ||\n !meta ||\n meta.model !== this.provider.model ||\n meta.provider !== this.provider.id ||\n meta.providerKey !== this.providerKey ||\n meta.chunkTokens !== this.config.chunking.tokens ||\n meta.chunkOverlap !== this.config.chunking.overlap ||\n (this.vectorState.available && !meta?.vectorDims)\n );\n }\n\n /**\n * Index all memory files, returns stats\n */\n async indexAll(force?: boolean): Promise<IndexStats> {\n const needsFullReindex = this.needsFullReindex(force);\n const files = await listMemoryFiles(this.config.memoryDir);\n const activePaths = new Set<string>();\n let filesProcessed = 0;\n let chunksCreated = 0;\n\n for (const absPath of files) {\n const entry = await buildFileEntry(absPath, this.config.memoryDir);\n activePaths.add(entry.path);\n\n const record = this.db\n .prepare(`SELECT hash FROM files WHERE path = ? AND source = ?`)\n .get(entry.path, \"memory\") as { hash: string } | undefined;\n\n if (!needsFullReindex && record?.hash === entry.hash) {\n continue;\n }\n\n const chunkCount = await this.indexFile(entry);\n filesProcessed++;\n chunksCreated += chunkCount;\n }\n\n // Delete stale entries\n const staleRemoved = this.removeStaleEntries(activePaths);\n\n // Write meta\n this.writeMeta({\n model: this.provider.model,\n provider: this.provider.id,\n providerKey: this.providerKey,\n chunkTokens: this.config.chunking.tokens,\n chunkOverlap: this.config.chunking.overlap,\n vectorDims: this.vectorState.dims,\n });\n\n // Prune embedding cache\n this.pruneEmbeddingCacheIfNeeded();\n\n return { filesProcessed, chunksCreated, staleRemoved };\n }\n\n /**\n * Index a single file\n */\n async indexFile(entry: MemoryFileEntry): Promise<number> {\n const content = await fs.readFile(entry.absPath, \"utf-8\");\n const chunks = chunkMarkdown(content, this.config.chunking);\n\n const embeddings = await this.embedChunks(chunks);\n\n // Update files table\n this.db\n .prepare(\n `INSERT OR REPLACE INTO files (path, source, hash, mtime, size) VALUES (?, ?, ?, ?, ?)`\n )\n .run(entry.path, \"memory\", entry.hash, Math.floor(entry.mtimeMs), entry.size);\n\n // Delete old chunks\n this.deleteChunksForFile(entry.path);\n\n // Insert new chunks\n const now = Date.now();\n for (let i = 0; i < chunks.length; i++) {\n const chunk = chunks[i];\n const embedding = embeddings[i] ?? [];\n this.insertChunk(entry.path, chunk, embedding, now);\n }\n\n return chunks.length;\n }\n\n /**\n * Delete all chunks for a file\n */\n private deleteChunksForFile(filePath: string): void {\n try {\n this.db\n .prepare(\n `DELETE FROM ${VECTOR_TABLE} WHERE id IN (SELECT id FROM chunks WHERE path = ? AND source = ?)`\n )\n .run(filePath, \"memory\");\n } catch {\n // Vector table may not exist\n }\n this.db.prepare(`DELETE FROM chunks WHERE path = ? AND source = ?`).run(filePath, \"memory\");\n if (this.config.ftsEnabled && this.ftsAvailable) {\n try {\n this.db\n .prepare(`DELETE FROM ${FTS_TABLE} WHERE path = ? AND source = ? AND model = ?`)\n .run(filePath, \"memory\", this.provider.model);\n } catch {\n // FTS table may not exist\n }\n }\n }\n\n /**\n * Insert a chunk into the database\n */\n private insertChunk(\n filePath: string,\n chunk: MemoryChunk,\n embedding: number[],\n timestamp: number\n ): void {\n const chunkId = randomUUID();\n\n this.db\n .prepare(\n `INSERT INTO chunks (id, path, source, start_line, end_line, hash, model, text, embedding, updated_at)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`\n )\n .run(\n chunkId,\n filePath,\n \"memory\",\n chunk.startLine,\n chunk.endLine,\n chunk.hash,\n this.provider.model,\n chunk.text,\n JSON.stringify(embedding),\n timestamp\n );\n\n // Insert into vector table if available\n if (this.vectorState.available && embedding.length > 0) {\n if (!this.vectorState.dims) {\n this.vectorState.dims = embedding.length;\n this.ensureVectorTable(embedding.length);\n }\n try {\n this.db\n .prepare(`INSERT INTO ${VECTOR_TABLE} (id, embedding) VALUES (?, ?)`)\n .run(chunkId, vectorToBlob(embedding));\n } catch {\n // Vector insertion may fail\n }\n }\n\n // Insert into FTS table if available\n if (this.config.ftsEnabled && this.ftsAvailable) {\n try {\n this.db\n .prepare(\n `INSERT INTO ${FTS_TABLE} (text, id, path, source, model, start_line, end_line)\n VALUES (?, ?, ?, ?, ?, ?, ?)`\n )\n .run(\n chunk.text,\n chunkId,\n filePath,\n \"memory\",\n this.provider.model,\n chunk.startLine,\n chunk.endLine\n );\n } catch {\n // FTS insertion may fail\n }\n }\n }\n\n /**\n * Remove stale file entries that no longer exist\n */\n private removeStaleEntries(activePaths: Set<string>): number {\n const staleRows = this.db\n .prepare(`SELECT path FROM files WHERE source = ?`)\n .all(\"memory\") as Array<{ path: string }>;\n\n let removed = 0;\n for (const stale of staleRows) {\n if (activePaths.has(stale.path)) continue;\n\n this.db\n .prepare(`DELETE FROM files WHERE path = ? AND source = ?`)\n .run(stale.path, \"memory\");\n this.deleteChunksForFile(stale.path);\n removed++;\n }\n\n return removed;\n }\n\n /**\n * Create vector table with the given dimensions\n */\n ensureVectorTable(dimensions: number): void {\n if (!this.vectorState.available) return;\n try {\n this.db.exec(\n `CREATE VIRTUAL TABLE IF NOT EXISTS ${VECTOR_TABLE} USING vec0(\n id TEXT PRIMARY KEY,\n embedding FLOAT[${dimensions}]\n )`\n );\n } catch (err) {\n this.config.debug?.(`vector table creation failed: ${String(err)}`);\n }\n }\n\n /**\n * Get embeddings for chunks, using cache when available\n */\n async embedChunks(chunks: MemoryChunk[]): Promise<number[][]> {\n if (chunks.length === 0) return [];\n\n const hashes = chunks.map((c) => c.hash);\n const cached = this.loadEmbeddingCache(hashes);\n const missing: Array<{ index: number; chunk: MemoryChunk }> = [];\n\n for (let i = 0; i < chunks.length; i++) {\n if (!cached.has(hashes[i])) {\n missing.push({ index: i, chunk: chunks[i] });\n }\n }\n\n if (missing.length > 0) {\n const texts = missing.map((m) => m.chunk.text);\n const newEmbeddings = await this.embedBatchWithRetry(texts);\n\n for (let i = 0; i < missing.length; i++) {\n const hash = missing[i].chunk.hash;\n const embedding = newEmbeddings[i] ?? [];\n cached.set(hash, embedding);\n this.upsertEmbeddingCache(hash, embedding);\n }\n }\n\n return hashes.map((h) => cached.get(h) ?? []);\n }\n\n /**\n * Embed texts with retry logic\n */\n private async embedBatchWithRetry(texts: string[]): Promise<number[][]> {\n if (texts.length === 0) return [];\n\n // Try batch API first if enabled\n if (this.config.batch.enabled) {\n try {\n return await this.embedWithBatchApi(texts);\n } catch (err) {\n this.config.debug?.(`batch embedding failed, falling back to direct: ${String(err)}`);\n }\n }\n\n // Fall back to direct embedding\n let lastError: Error | null = null;\n for (let attempt = 0; attempt < EMBEDDING_RETRY_MAX_ATTEMPTS; attempt++) {\n try {\n return await this.provider.embedBatch(texts);\n } catch (err) {\n lastError = err instanceof Error ? err : new Error(String(err));\n if (attempt < EMBEDDING_RETRY_MAX_ATTEMPTS - 1) {\n const delay = Math.min(\n EMBEDDING_RETRY_MAX_DELAY_MS,\n EMBEDDING_RETRY_BASE_DELAY_MS * Math.pow(2, attempt)\n );\n await new Promise((resolve) => setTimeout(resolve, delay));\n }\n }\n }\n throw lastError;\n }\n\n /**\n * Use batch API for large embedding jobs\n */\n private async embedWithBatchApi(texts: string[]): Promise<number[][]> {\n if (this.openAi) {\n const requests: OpenAiBatchRequest[] = texts.map((text, i) => ({\n custom_id: `chunk-${i}`,\n method: \"POST\",\n url: OPENAI_BATCH_ENDPOINT,\n body: { model: this.openAi!.model, input: text },\n }));\n\n const results = await runOpenAiEmbeddingBatches({\n openAi: this.openAi,\n source: \"minimem\",\n requests,\n wait: this.config.batch.wait,\n pollIntervalMs: this.config.batch.pollIntervalMs,\n timeoutMs: this.config.batch.timeoutMs,\n concurrency: this.config.batch.concurrency,\n debug: this.config.debug,\n });\n\n return texts.map((_, i) => results.get(`chunk-${i}`) ?? []);\n }\n\n if (this.gemini) {\n const requests: GeminiBatchRequest[] = texts.map((text, i) => ({\n custom_id: `chunk-${i}`,\n content: { parts: [{ text }] },\n taskType: \"RETRIEVAL_DOCUMENT\",\n }));\n\n const results = await runGeminiEmbeddingBatches({\n gemini: this.gemini,\n source: \"minimem\",\n requests,\n wait: this.config.batch.wait,\n pollIntervalMs: this.config.batch.pollIntervalMs,\n timeoutMs: this.config.batch.timeoutMs,\n concurrency: this.config.batch.concurrency,\n debug: this.config.debug,\n });\n\n return texts.map((_, i) => results.get(`chunk-${i}`) ?? []);\n }\n\n throw new Error(\"Batch API not available for local embeddings\");\n }\n\n /**\n * Load embeddings from cache\n */\n private loadEmbeddingCache(hashes: string[]): Map<string, number[]> {\n const result = new Map<string, number[]>();\n if (!this.config.cache.enabled || hashes.length === 0) return result;\n\n const placeholders = hashes.map(() => \"?\").join(\",\");\n const rows = this.db\n .prepare(\n `SELECT hash, embedding FROM ${EMBEDDING_CACHE_TABLE}\n WHERE provider = ? AND model = ? AND provider_key = ? AND hash IN (${placeholders})`\n )\n .all(this.provider.id, this.provider.model, this.providerKey, ...hashes) as Array<{\n hash: string;\n embedding: string;\n }>;\n\n const now = Date.now();\n for (const row of rows) {\n result.set(row.hash, parseEmbedding(row.embedding));\n // Touch for LRU\n this.db\n .prepare(\n `UPDATE ${EMBEDDING_CACHE_TABLE} SET updated_at = ?\n WHERE provider = ? AND model = ? AND provider_key = ? AND hash = ?`\n )\n .run(now, this.provider.id, this.provider.model, this.providerKey, row.hash);\n }\n\n return result;\n }\n\n /**\n * Save embedding to cache\n */\n private upsertEmbeddingCache(hash: string, embedding: number[]): void {\n if (!this.config.cache.enabled) return;\n const now = Date.now();\n this.db\n .prepare(\n `INSERT OR REPLACE INTO ${EMBEDDING_CACHE_TABLE}\n (provider, model, provider_key, hash, embedding, dims, updated_at)\n VALUES (?, ?, ?, ?, ?, ?, ?)`\n )\n .run(\n this.provider.id,\n this.provider.model,\n this.providerKey,\n hash,\n JSON.stringify(embedding),\n embedding.length,\n now\n );\n }\n\n /**\n * Prune old cache entries if over limit\n */\n private pruneEmbeddingCacheIfNeeded(): void {\n if (!this.config.cache.enabled) return;\n const row = this.db\n .prepare(`SELECT COUNT(*) as count FROM ${EMBEDDING_CACHE_TABLE}`)\n .get() as { count: number };\n if (row.count <= this.config.cache.maxEntries) return;\n\n const excess = row.count - this.config.cache.maxEntries;\n this.db\n .prepare(\n `DELETE FROM ${EMBEDDING_CACHE_TABLE}\n WHERE rowid IN (\n SELECT rowid FROM ${EMBEDDING_CACHE_TABLE}\n ORDER BY updated_at ASC\n LIMIT ?\n )`\n )\n .run(excess);\n }\n}\n","/**\n * MemorySearcher - Handles search operations\n *\n * Responsible for:\n * - Executing vector searches\n * - Executing keyword (FTS) searches\n * - Merging results with hybrid scoring\n */\n\nimport type { DatabaseSync } from \"node:sqlite\";\n\nimport { bm25RankToScore, buildFtsQuery, mergeHybridResults } from \"../search/hybrid.js\";\nimport { searchKeyword, searchVector } from \"../search/search.js\";\nimport type { EmbeddingProvider } from \"../embeddings/embeddings.js\";\nimport type { DebugFn } from \"../internal.js\";\n\nconst SNIPPET_MAX_CHARS = 700;\nconst VECTOR_TABLE = \"chunks_vec\";\nconst FTS_TABLE = \"chunks_fts\";\nconst EMBEDDING_QUERY_TIMEOUT_REMOTE_MS = 60_000;\nconst EMBEDDING_QUERY_TIMEOUT_LOCAL_MS = 5 * 60_000;\n\nexport type SearchConfig = {\n hybrid: {\n enabled: boolean;\n vectorWeight: number;\n textWeight: number;\n candidateMultiplier: number;\n };\n query: {\n maxResults: number;\n minScore: number;\n };\n debug?: DebugFn;\n};\n\nexport type SearchResult = {\n path: string;\n startLine: number;\n endLine: number;\n score: number;\n snippet: string;\n};\n\n/**\n * MemorySearcher handles search queries against the indexed memory\n */\nexport class MemorySearcher {\n private readonly db: DatabaseSync;\n private readonly provider: EmbeddingProvider;\n private readonly config: SearchConfig;\n\n // State from parent\n private vectorState: {\n available: boolean;\n dims?: number;\n };\n private ftsAvailable: boolean;\n\n // Callback to ensure vector is ready\n private ensureVectorReadyFn?: (dims?: number) => Promise<boolean>;\n\n constructor(\n db: DatabaseSync,\n provider: EmbeddingProvider,\n config: SearchConfig,\n options?: {\n vectorState?: { available: boolean; dims?: number };\n ftsAvailable?: boolean;\n ensureVectorReady?: (dims?: number) => Promise<boolean>;\n }\n ) {\n this.db = db;\n this.provider = provider;\n this.config = config;\n this.vectorState = options?.vectorState ?? { available: false };\n this.ftsAvailable = options?.ftsAvailable ?? false;\n this.ensureVectorReadyFn = options?.ensureVectorReady;\n }\n\n /**\n * Update vector/FTS availability (called by parent when extensions load)\n */\n setVectorState(state: { available: boolean; dims?: number }): void {\n this.vectorState = state;\n }\n\n setFtsAvailable(available: boolean): void {\n this.ftsAvailable = available;\n }\n\n /**\n * Execute a search query\n */\n async search(\n query: string,\n opts?: { maxResults?: number; minScore?: number }\n ): Promise<SearchResult[]> {\n const cleaned = query.trim();\n if (!cleaned) return [];\n\n const minScore = opts?.minScore ?? this.config.query.minScore;\n const maxResults = opts?.maxResults ?? this.config.query.maxResults;\n const candidates = Math.min(\n 200,\n Math.max(1, Math.floor(maxResults * this.config.hybrid.candidateMultiplier))\n );\n\n const sourceFilter = { sql: \"\", params: [] as string[] };\n\n // Execute keyword search if hybrid is enabled\n const keywordResults =\n this.config.hybrid.enabled && this.ftsAvailable\n ? await searchKeyword({\n db: this.db,\n ftsTable: FTS_TABLE,\n providerModel: this.provider.model,\n query: cleaned,\n limit: candidates,\n snippetMaxChars: SNIPPET_MAX_CHARS,\n sourceFilter,\n buildFtsQuery,\n bm25RankToScore,\n }).catch(() => [])\n : [];\n\n // Embed query and execute vector search\n const queryVec = await this.embedQueryWithTimeout(cleaned);\n const hasVector = queryVec.some((v) => v !== 0);\n const vectorResults = hasVector\n ? await searchVector({\n db: this.db,\n vectorTable: VECTOR_TABLE,\n providerModel: this.provider.model,\n queryVec,\n limit: candidates,\n snippetMaxChars: SNIPPET_MAX_CHARS,\n ensureVectorReady: (dims) => this.ensureVectorReady(dims),\n sourceFilterVec: sourceFilter,\n sourceFilterChunks: sourceFilter,\n }).catch(() => [])\n : [];\n\n // If hybrid is disabled, return vector results only\n if (!this.config.hybrid.enabled) {\n return vectorResults\n .filter((entry) => entry.score >= minScore)\n .slice(0, maxResults)\n .map((r) => ({\n path: r.path,\n startLine: r.startLine,\n endLine: r.endLine,\n score: r.score,\n snippet: r.snippet,\n }));\n }\n\n // Merge results with hybrid scoring\n const merged = mergeHybridResults({\n vector: vectorResults.map((r) => ({\n id: r.id,\n path: r.path,\n startLine: r.startLine,\n endLine: r.endLine,\n source: r.source,\n snippet: r.snippet,\n vectorScore: r.score,\n })),\n keyword: keywordResults.map((r) => ({\n id: r.id,\n path: r.path,\n startLine: r.startLine,\n endLine: r.endLine,\n source: r.source,\n snippet: r.snippet,\n textScore: r.textScore,\n })),\n vectorWeight: this.config.hybrid.vectorWeight,\n textWeight: this.config.hybrid.textWeight,\n });\n\n return merged\n .filter((entry) => entry.score >= minScore)\n .slice(0, maxResults)\n .map((r) => ({\n path: r.path,\n startLine: r.startLine,\n endLine: r.endLine,\n score: r.score,\n snippet: r.snippet,\n }));\n }\n\n /**\n * Embed a query string with timeout\n */\n private async embedQueryWithTimeout(text: string): Promise<number[]> {\n const timeout =\n this.provider.id === \"local\"\n ? EMBEDDING_QUERY_TIMEOUT_LOCAL_MS\n : EMBEDDING_QUERY_TIMEOUT_REMOTE_MS;\n\n return Promise.race([\n this.provider.embedQuery(text),\n new Promise<number[]>((_, reject) =>\n setTimeout(() => reject(new Error(\"embedding query timeout\")), timeout)\n ),\n ]);\n }\n\n /**\n * Ensure vector extension is ready\n */\n private async ensureVectorReady(dims?: number): Promise<boolean> {\n if (this.vectorState.available) return true;\n if (this.ensureVectorReadyFn) {\n return this.ensureVectorReadyFn(dims);\n }\n return false;\n }\n}\n","/**\n * StoreGraph: meta-layer above Minimem for managing linked stores.\n *\n * A StoreGraph resolves a store and its dependencies (depth 1),\n * materializes them as needed, and produces an array of MemoryInstance\n * objects that can be passed to MemoryToolExecutor or used directly.\n *\n * The Minimem class is unchanged — StoreGraph just orchestrates\n * multiple independent Minimem instances.\n */\n\nimport path from \"node:path\";\n\nimport { Minimem, type MinimemConfig } from \"../minimem.js\";\nimport type { MemoryInstance } from \"../server/tools.js\";\nimport {\n loadManifest,\n getLinkedStoreNames,\n resolveStore,\n resolveStoreName,\n type StoreManifest,\n type StoreDefinition,\n} from \"./manifest.js\";\nimport { materializeStore, type MaterializeResult } from \"./materialize.js\";\n\nexport type StoreGraphOptions = {\n /** Path to the global manifest file (default: ~/.config/minimem/stores.json) */\n manifestPath?: string;\n /** Factory to create a MinimemConfig for a given store directory */\n configFactory?: (memoryDir: string, storeName: string) => Promise<MinimemConfig>;\n /** Debug logging */\n debug?: (message: string) => void;\n};\n\nexport type ResolvedStore = {\n name: string;\n definition: StoreDefinition;\n materialization: MaterializeResult;\n instance: Minimem;\n};\n\nexport class StoreGraph {\n private manifest: StoreManifest;\n private resolved: Map<string, ResolvedStore> = new Map();\n private configFactory: (memoryDir: string, storeName: string) => Promise<MinimemConfig>;\n private debug?: (message: string) => void;\n\n private constructor(\n manifest: StoreManifest,\n opts?: StoreGraphOptions,\n ) {\n this.manifest = manifest;\n this.debug = opts?.debug;\n this.configFactory = opts?.configFactory ?? defaultConfigFactory;\n }\n\n /**\n * Create a StoreGraph from the global manifest.\n */\n static async create(opts?: StoreGraphOptions): Promise<StoreGraph> {\n const manifest = await loadManifest(opts?.manifestPath);\n return new StoreGraph(manifest, opts);\n }\n\n /**\n * Create a StoreGraph from an explicit manifest object (useful for testing).\n */\n static fromManifest(\n manifest: StoreManifest,\n opts?: StoreGraphOptions,\n ): StoreGraph {\n return new StoreGraph(manifest, opts);\n }\n\n /**\n * Get the loaded manifest.\n */\n getManifest(): StoreManifest {\n return this.manifest;\n }\n\n /**\n * Resolve a store by name: materialize it and all its linked stores (depth 1).\n * Returns an array of MemoryInstance objects ready for search.\n *\n * Linked stores that fail to materialize are skipped with a warning.\n */\n async resolve(storeName: string): Promise<MemoryInstance[]> {\n const instances: MemoryInstance[] = [];\n\n // Resolve the primary store\n const primary = await this.resolveOne(storeName);\n if (!primary) {\n throw new Error(`Store \"${storeName}\" not found or unavailable`);\n }\n instances.push({\n minimem: primary.instance,\n memoryDir: primary.materialization.path,\n name: storeName,\n });\n\n // Resolve linked stores (depth 1)\n const linkedNames = await getLinkedStoreNames(this.manifest, storeName);\n for (const linkedName of linkedNames) {\n if (linkedName === storeName) continue; // skip self-links\n\n try {\n const linked = await this.resolveOne(linkedName);\n if (linked) {\n instances.push({\n minimem: linked.instance,\n memoryDir: linked.materialization.path,\n name: linkedName,\n });\n } else {\n this.debug?.(`Linked store \"${linkedName}\" unavailable, skipping`);\n }\n } catch (err) {\n this.debug?.(\n `Failed to resolve linked store \"${linkedName}\": ${String(err)}`,\n );\n }\n }\n\n return instances;\n }\n\n /**\n * Resolve a store by directory path (looks up the store name in the manifest).\n * Falls back to creating a standalone instance if the directory isn't in the manifest.\n */\n async resolveByPath(dirPath: string): Promise<MemoryInstance[]> {\n const storeName = resolveStoreName(this.manifest, dirPath);\n if (storeName) {\n return this.resolve(storeName);\n }\n\n // Not in manifest — return standalone instance with no links\n this.debug?.(`Directory \"${dirPath}\" not in manifest, using standalone`);\n const config = await this.configFactory(dirPath, path.basename(dirPath));\n const instance = await Minimem.create(config);\n return [\n {\n minimem: instance,\n memoryDir: dirPath,\n name: path.basename(dirPath),\n },\n ];\n }\n\n /**\n * List all known stores from the manifest with their link info.\n */\n async listStores(): Promise<\n Array<{\n name: string;\n path: string;\n remote?: string;\n links: string[];\n available: boolean;\n }>\n > {\n const result: Array<{\n name: string;\n path: string;\n remote?: string;\n links: string[];\n available: boolean;\n }> = [];\n\n for (const [name, def] of Object.entries(this.manifest.stores)) {\n const links = await getLinkedStoreNames(this.manifest, name);\n const { existsSync } = await import(\"node:fs\");\n const available = existsSync(def.path) || !!def.remote;\n\n result.push({\n name,\n path: def.path,\n remote: def.remote,\n links,\n available,\n });\n }\n\n return result;\n }\n\n /**\n * Close all resolved Minimem instances and clean up materializations.\n */\n async close(): Promise<void> {\n for (const [, store] of this.resolved) {\n try {\n store.instance.close();\n } catch {\n // best effort\n }\n try {\n await store.materialization.cleanup();\n } catch {\n // best effort\n }\n }\n this.resolved.clear();\n }\n\n /**\n * Resolve a single store by name.\n * Returns cached instance if already resolved.\n */\n private async resolveOne(storeName: string): Promise<ResolvedStore | null> {\n // Return cached if available\n const cached = this.resolved.get(storeName);\n if (cached) return cached;\n\n const def = resolveStore(this.manifest, storeName);\n if (!def) return null;\n\n // Materialize\n const materialization = await materializeStore(storeName, def);\n if (!materialization) return null;\n\n // Create Minimem instance\n const config = await this.configFactory(materialization.path, storeName);\n const instance = await Minimem.create(config);\n\n const resolved: ResolvedStore = {\n name: storeName,\n definition: def,\n materialization,\n instance,\n };\n\n this.resolved.set(storeName, resolved);\n return resolved;\n }\n}\n\n/**\n * Default config factory: creates a minimal config with auto embedding.\n * In practice, the CLI will provide a factory that respects per-store configs.\n */\nasync function defaultConfigFactory(\n memoryDir: string,\n _storeName: string,\n): Promise<MinimemConfig> {\n return {\n memoryDir,\n embedding: { provider: \"auto\" },\n watch: { enabled: false },\n };\n}\n","/**\n * Store manifest: defines known stores and their relationships.\n *\n * Manifests can live in two places:\n * 1. Global: ~/.config/minimem/stores.json (user-wide registry)\n * 2. Per-store: .minimem/links.json (declares that store's dependencies)\n *\n * The global manifest is the source of truth for store metadata (path, remote).\n * Per-store link files declare which other stores a store depends on.\n */\n\nimport fs from \"node:fs/promises\";\nimport fsSync from \"node:fs\";\nimport path from \"node:path\";\nimport os from \"node:os\";\n\n/**\n * A single store definition in the global manifest.\n */\nexport type StoreDefinition = {\n /** Absolute path to the store's memory directory */\n path: string;\n /** Git remote URL for remote materialization */\n remote?: string;\n /** Human-readable description */\n description?: string;\n};\n\n/**\n * Global store manifest (~/.config/minimem/stores.json)\n */\nexport type StoreManifest = {\n stores: Record<string, StoreDefinition>;\n};\n\n/**\n * Per-store links file (.minimem/links.json or .swarm/minimem/links.json)\n * Declares which other stores this store depends on.\n */\nexport type StoreLinks = {\n /** Store names that this store links to (depth-1 only) */\n links: string[];\n};\n\nconst GLOBAL_MANIFEST_PATH = path.join(\n os.homedir(),\n \".config\",\n \"minimem\",\n \"stores.json\",\n);\n\nconst LINKS_FILENAME = \"links.json\";\n\n/**\n * Load the global store manifest.\n * Returns an empty manifest if the file doesn't exist.\n */\nexport async function loadManifest(\n manifestPath?: string,\n): Promise<StoreManifest> {\n const filePath = manifestPath ?? GLOBAL_MANIFEST_PATH;\n try {\n const content = await fs.readFile(filePath, \"utf-8\");\n const parsed = JSON.parse(content) as StoreManifest;\n // Expand ~ in paths\n for (const [name, def] of Object.entries(parsed.stores ?? {})) {\n parsed.stores[name] = {\n ...def,\n path: expandHome(def.path),\n };\n }\n return { stores: parsed.stores ?? {} };\n } catch {\n return { stores: {} };\n }\n}\n\n/**\n * Save the global store manifest.\n */\nexport async function saveManifest(\n manifest: StoreManifest,\n manifestPath?: string,\n): Promise<void> {\n const filePath = manifestPath ?? GLOBAL_MANIFEST_PATH;\n await fs.mkdir(path.dirname(filePath), { recursive: true });\n await fs.writeFile(filePath, JSON.stringify(manifest, null, 2), \"utf-8\");\n}\n\n/**\n * Load per-store links from a memory directory.\n * Checks .minimem/links.json, .swarm/minimem/links.json, and links.json (contained layout).\n */\nexport async function loadStoreLinks(memoryDir: string): Promise<StoreLinks> {\n const candidates = [\n path.join(memoryDir, \".minimem\", LINKS_FILENAME),\n path.join(memoryDir, \".swarm\", \"minimem\", LINKS_FILENAME),\n path.join(memoryDir, LINKS_FILENAME),\n ];\n\n for (const candidate of candidates) {\n try {\n const content = await fs.readFile(candidate, \"utf-8\");\n const parsed = JSON.parse(content) as StoreLinks;\n return { links: parsed.links ?? [] };\n } catch {\n continue;\n }\n }\n\n return { links: [] };\n}\n\n/**\n * Save per-store links to a memory directory.\n * Writes to the first config subdirectory that exists.\n */\nexport async function saveStoreLinks(\n memoryDir: string,\n links: StoreLinks,\n): Promise<void> {\n // Find existing config subdirectory\n const candidates = [\n path.join(memoryDir, \".minimem\"),\n path.join(memoryDir, \".swarm\", \"minimem\"),\n memoryDir, // contained layout\n ];\n\n let targetDir = candidates[0]; // default to .minimem\n for (const candidate of candidates) {\n if (fsSync.existsSync(candidate)) {\n targetDir = candidate;\n break;\n }\n }\n\n await fs.mkdir(targetDir, { recursive: true });\n await fs.writeFile(\n path.join(targetDir, LINKS_FILENAME),\n JSON.stringify(links, null, 2),\n \"utf-8\",\n );\n}\n\n/**\n * Resolve store name to its definition.\n * Looks up the store in the global manifest.\n */\nexport function resolveStore(\n manifest: StoreManifest,\n storeName: string,\n): StoreDefinition | null {\n return manifest.stores[storeName] ?? null;\n}\n\n/**\n * Resolve a directory path to its store name in the manifest.\n * Returns the first store whose path matches.\n */\nexport function resolveStoreName(\n manifest: StoreManifest,\n dirPath: string,\n): string | null {\n const resolved = path.resolve(dirPath);\n for (const [name, def] of Object.entries(manifest.stores)) {\n if (path.resolve(def.path) === resolved) {\n return name;\n }\n }\n return null;\n}\n\n/**\n * Get all linked store names for a given store (depth 1 only).\n * Merges links from the global manifest and per-store links file.\n */\nexport async function getLinkedStoreNames(\n manifest: StoreManifest,\n storeName: string,\n): Promise<string[]> {\n const storeDef = manifest.stores[storeName];\n if (!storeDef) return [];\n\n // Load per-store links\n const storeLinks = await loadStoreLinks(storeDef.path);\n\n // Deduplicate\n return [...new Set(storeLinks.links)];\n}\n\n/**\n * Get the default global manifest path.\n */\nexport function getManifestPath(): string {\n return GLOBAL_MANIFEST_PATH;\n}\n\nfunction expandHome(filePath: string): string {\n if (filePath.startsWith(\"~/\")) {\n return path.join(os.homedir(), filePath.slice(2));\n }\n return filePath;\n}\n","/**\n * Store materialization strategies.\n *\n * Two strategies for making a linked store accessible:\n *\n * A. Remote materialization: clone/fetch a git remote into a cache directory\n * Used when the store isn't available locally.\n *\n * B. Symlink materialization: create temporary symlinks to a local store\n * Used when the store is already present on disk.\n * Symlinks go into a temp directory with unique subdirectory names\n * to avoid path collisions between stores.\n */\n\nimport fs from \"node:fs/promises\";\nimport fsSync from \"node:fs\";\nimport path from \"node:path\";\nimport os from \"node:os\";\nimport { execFile } from \"node:child_process\";\nimport { promisify } from \"node:util\";\n\nimport type { StoreDefinition } from \"./manifest.js\";\n\nconst execFileAsync = promisify(execFile);\n\nconst CACHE_BASE = path.join(os.homedir(), \".cache\", \"minimem\", \"stores\");\n\nexport type MaterializeResult = {\n /** The directory path to use for creating a Minimem instance */\n path: string;\n /** How the store was materialized */\n strategy: \"local\" | \"symlink\" | \"remote\";\n /** Cleanup function to call when done (removes symlinks, etc.) */\n cleanup: () => Promise<void>;\n};\n\n/**\n * Materialize a store so it can be accessed by a Minimem instance.\n *\n * Resolution order:\n * 1. If the store path exists locally → use directly (no materialization needed)\n * 2. If the store has a remote → clone/fetch into cache\n * 3. Otherwise → return null (store unavailable)\n */\nexport async function materializeStore(\n storeName: string,\n storeDef: StoreDefinition,\n opts?: {\n /** Force refresh from remote even if cache exists */\n refresh?: boolean;\n },\n): Promise<MaterializeResult | null> {\n // Strategy B: local store exists — use symlink to temp dir\n if (fsSync.existsSync(storeDef.path)) {\n return materializeLocal(storeName, storeDef.path);\n }\n\n // Strategy A: remote store — clone/fetch into cache\n if (storeDef.remote) {\n return materializeRemote(storeName, storeDef, opts?.refresh ?? false);\n }\n\n // Store is unavailable\n return null;\n}\n\n/**\n * Strategy B: symlink materialization for local stores.\n *\n * Creates a temporary directory with a uniquely-named subdirectory\n * containing a symlink to the source store. This avoids collisions\n * when multiple stores are materialized simultaneously.\n */\nasync function materializeLocal(\n storeName: string,\n storePath: string,\n): Promise<MaterializeResult> {\n // Create temp dir: /tmp/minimem-stores-<random>/<storeName>/\n const tmpBase = await fs.mkdtemp(\n path.join(os.tmpdir(), \"minimem-stores-\"),\n );\n const symlinkDir = path.join(tmpBase, storeName);\n\n // Create symlink: tmpBase/<storeName> → storePath\n await fs.symlink(storePath, symlinkDir, \"dir\");\n\n return {\n // The Minimem instance should use the original path for its DB,\n // but the symlink path can be used for discovery/resolution.\n // We return the original path since Minimem works directly with it.\n path: storePath,\n strategy: \"symlink\",\n cleanup: async () => {\n try {\n await fs.unlink(symlinkDir);\n await fs.rmdir(tmpBase);\n } catch {\n // Best-effort cleanup\n }\n },\n };\n}\n\n/**\n * Strategy A: remote materialization via git clone/fetch.\n *\n * Clones the remote into ~/.cache/minimem/stores/<storeName>/\n * On subsequent calls, does a git fetch + reset to update.\n */\nasync function materializeRemote(\n storeName: string,\n storeDef: StoreDefinition,\n refresh: boolean,\n): Promise<MaterializeResult | null> {\n const cacheDir = path.join(CACHE_BASE, storeName);\n\n try {\n if (fsSync.existsSync(path.join(cacheDir, \".git\"))) {\n // Cache exists — optionally refresh\n if (refresh) {\n await gitFetch(cacheDir);\n }\n } else {\n // Clone fresh\n await gitClone(storeDef.remote!, cacheDir);\n }\n\n return {\n path: cacheDir,\n strategy: \"remote\",\n cleanup: async () => {\n // Remote cache is persistent — no cleanup needed per session.\n // Users can manually clear ~/.cache/minimem/stores/ if desired.\n },\n };\n } catch {\n // Git operation failed — store unavailable\n return null;\n }\n}\n\nasync function gitClone(remote: string, targetDir: string): Promise<void> {\n await fs.mkdir(path.dirname(targetDir), { recursive: true });\n await execFileAsync(\"git\", [\"clone\", \"--depth\", \"1\", remote, targetDir], {\n timeout: 60_000,\n });\n}\n\nasync function gitFetch(cacheDir: string): Promise<void> {\n await execFileAsync(\"git\", [\"fetch\", \"--depth\", \"1\", \"origin\"], {\n cwd: cacheDir,\n timeout: 60_000,\n });\n await execFileAsync(\"git\", [\"reset\", \"--hard\", \"origin/HEAD\"], {\n cwd: cacheDir,\n timeout: 30_000,\n });\n}\n\n/**\n * Get the cache directory for remote stores.\n */\nexport function getRemoteCacheDir(): string {\n return CACHE_BASE;\n}\n\n/**\n * List cached remote stores.\n */\nexport async function listCachedStores(): Promise<string[]> {\n try {\n const entries = await fs.readdir(CACHE_BASE);\n return entries;\n } catch {\n return [];\n }\n}\n\n/**\n * Clear the cache for a specific remote store.\n */\nexport async function clearStoreCache(storeName: string): Promise<void> {\n const cacheDir = path.join(CACHE_BASE, storeName);\n await fs.rm(cacheDir, { recursive: true, force: true });\n}\n"],"mappings":"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","names":["fsSync","path","path","payload","provider","client","text","runWithConcurrency","fsSync","path","path","path","randomUUID","fs","path","META_KEY","EMBEDDING_CACHE_TABLE","VECTOR_TABLE","FTS_TABLE","EMBEDDING_RETRY_MAX_ATTEMPTS","EMBEDDING_RETRY_BASE_DELAY_MS","EMBEDDING_RETRY_MAX_DELAY_MS","path","fs","randomUUID","SNIPPET_MAX_CHARS","VECTOR_TABLE","FTS_TABLE","EMBEDDING_QUERY_TIMEOUT_REMOTE_MS","EMBEDDING_QUERY_TIMEOUT_LOCAL_MS","path","fs","fsSync","path","os","fs","fsSync","path","os","path"]}
|