diff --git a/harnesses/cursor/extension/hivemind-cursor-extension-0.1.4.vsix b/harnesses/cursor/extension/hivemind-cursor-extension-0.1.5.vsix similarity index 97% rename from harnesses/cursor/extension/hivemind-cursor-extension-0.1.4.vsix rename to harnesses/cursor/extension/hivemind-cursor-extension-0.1.5.vsix index 2f0cf1be..d023c9c2 100644 Binary files a/harnesses/cursor/extension/hivemind-cursor-extension-0.1.4.vsix and b/harnesses/cursor/extension/hivemind-cursor-extension-0.1.5.vsix differ diff --git a/harnesses/cursor/extension/package-lock.json b/harnesses/cursor/extension/package-lock.json index 5a2ad990..4c7c73be 100644 --- a/harnesses/cursor/extension/package-lock.json +++ b/harnesses/cursor/extension/package-lock.json @@ -1,12 +1,12 @@ { "name": "hivemind-cursor-extension", - "version": "0.1.4", + "version": "0.1.5", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "hivemind-cursor-extension", - "version": "0.1.4", + "version": "0.1.5", "devDependencies": { "@types/node": "^20.11.0", "@types/vscode": "^1.85.0", diff --git a/harnesses/cursor/extension/package.json b/harnesses/cursor/extension/package.json index 34454cda..abb14f81 100644 --- a/harnesses/cursor/extension/package.json +++ b/harnesses/cursor/extension/package.json @@ -2,7 +2,7 @@ "name": "hivemind-cursor-extension", "displayName": "Hivemind for Cursor", "description": "Shared memory, health checks, dashboard, and codebase graph inside Cursor", - "version": "0.1.4", + "version": "0.1.5", "publisher": "deeplake", "engines": { "vscode": "^1.85.0" diff --git a/src/shell/grep-core.ts b/src/shell/grep-core.ts index cf7e116e..3a169107 100644 --- a/src/shell/grep-core.ts +++ b/src/shell/grep-core.ts @@ -633,10 +633,30 @@ export async function grepBothTables( queryEmbedding?: number[] | null, ): Promise { const meta = { truncated: false }; - const rows = await searchDeeplakeTables(api, memoryTable, sessionsTable, { - ...buildGrepSearchOptions(params, targetPath), - queryEmbedding, - }, meta); + const baseOptions = buildGrepSearchOptions(params, targetPath); + let usedEmbedding = queryEmbedding ?? null; + let rows: ContentRow[]; + try { + rows = await searchDeeplakeTables(api, memoryTable, sessionsTable, { + ...baseOptions, + queryEmbedding, + }, meta); + } catch (e) { + // Semantic search can fail at the DB level (e.g. inconsistent + // summary_embedding dimensions in the memory table -> "Can't stack + // arrays with different dimensions"). Rather than give up on recall, + // retry once with lexical search so memory still resolves. Auto-recovers + // when the embedding column is re-indexed. + if (queryEmbedding && queryEmbedding.length > 0) { + usedEmbedding = null; + rows = await searchDeeplakeTables(api, memoryTable, sessionsTable, { + ...baseOptions, + queryEmbedding: null, + }, meta); + } else { + throw e; + } + } // Defensive path dedup — memory and sessions tables use disjoint path // prefixes in every schema we ship (/summaries/… vs /sessions/…), so the // overlap is theoretical, but we dedupe to match grep-interceptor.ts and @@ -651,7 +671,7 @@ export async function grepBothTables( // pattern (the whole point of semantic). Return every non-empty normalized // line from the top-K rows, prefixed with the path so Claude can follow up // with Read. The downstream output-cap keeps the response bounded. - if (queryEmbedding && queryEmbedding.length > 0) { + if (usedEmbedding && usedEmbedding.length > 0) { const emitAllLines = process.env.HIVEMIND_SEMANTIC_EMIT_ALL !== "false"; if (emitAllLines) { const lines: string[] = [];