Spaces:
Configuration error
Configuration error
| import type { DatabaseSync } from "node:sqlite"; | |
| import { createSubsystemLogger } from "../logging/subsystem.js"; | |
| import { buildFileEntry, listMemoryFiles, type MemoryFileEntry } from "./internal.js"; | |
| const log = createSubsystemLogger("memory"); | |
| type ProgressState = { | |
| completed: number; | |
| total: number; | |
| label?: string; | |
| report: (update: { completed: number; total: number; label?: string }) => void; | |
| }; | |
| export async function syncMemoryFiles(params: { | |
| workspaceDir: string; | |
| db: DatabaseSync; | |
| needsFullReindex: boolean; | |
| progress?: ProgressState; | |
| batchEnabled: boolean; | |
| concurrency: number; | |
| runWithConcurrency: <T>(tasks: Array<() => Promise<T>>, concurrency: number) => Promise<T[]>; | |
| indexFile: (entry: MemoryFileEntry) => Promise<void>; | |
| vectorTable: string; | |
| ftsTable: string; | |
| ftsEnabled: boolean; | |
| ftsAvailable: boolean; | |
| model: string; | |
| }) { | |
| const files = await listMemoryFiles(params.workspaceDir); | |
| const fileEntries = await Promise.all( | |
| files.map(async (file) => buildFileEntry(file, params.workspaceDir)), | |
| ); | |
| log.debug("memory sync: indexing memory files", { | |
| files: fileEntries.length, | |
| needsFullReindex: params.needsFullReindex, | |
| batch: params.batchEnabled, | |
| concurrency: params.concurrency, | |
| }); | |
| const activePaths = new Set(fileEntries.map((entry) => entry.path)); | |
| if (params.progress) { | |
| params.progress.total += fileEntries.length; | |
| params.progress.report({ | |
| completed: params.progress.completed, | |
| total: params.progress.total, | |
| label: params.batchEnabled ? "Indexing memory files (batch)..." : "Indexing memory files…", | |
| }); | |
| } | |
| const tasks = fileEntries.map((entry) => async () => { | |
| const record = params.db | |
| .prepare(`SELECT hash FROM files WHERE path = ? AND source = ?`) | |
| .get(entry.path, "memory") as { hash: string } | undefined; | |
| if (!params.needsFullReindex && record?.hash === entry.hash) { | |
| if (params.progress) { | |
| params.progress.completed += 1; | |
| params.progress.report({ | |
| completed: params.progress.completed, | |
| total: params.progress.total, | |
| }); | |
| } | |
| return; | |
| } | |
| await params.indexFile(entry); | |
| if (params.progress) { | |
| params.progress.completed += 1; | |
| params.progress.report({ | |
| completed: params.progress.completed, | |
| total: params.progress.total, | |
| }); | |
| } | |
| }); | |
| await params.runWithConcurrency(tasks, params.concurrency); | |
| const staleRows = params.db | |
| .prepare(`SELECT path FROM files WHERE source = ?`) | |
| .all("memory") as Array<{ path: string }>; | |
| for (const stale of staleRows) { | |
| if (activePaths.has(stale.path)) continue; | |
| params.db.prepare(`DELETE FROM files WHERE path = ? AND source = ?`).run(stale.path, "memory"); | |
| try { | |
| params.db | |
| .prepare( | |
| `DELETE FROM ${params.vectorTable} WHERE id IN (SELECT id FROM chunks WHERE path = ? AND source = ?)`, | |
| ) | |
| .run(stale.path, "memory"); | |
| } catch {} | |
| params.db.prepare(`DELETE FROM chunks WHERE path = ? AND source = ?`).run(stale.path, "memory"); | |
| if (params.ftsEnabled && params.ftsAvailable) { | |
| try { | |
| params.db | |
| .prepare(`DELETE FROM ${params.ftsTable} WHERE path = ? AND source = ? AND model = ?`) | |
| .run(stale.path, "memory", params.model); | |
| } catch {} | |
| } | |
| } | |
| } | |