From 85e27d5f05f06652aaa96ad3ab29bb0c58184610 Mon Sep 17 00:00:00 2001 From: EyJunge1 <149941075+EyJunge1@users.noreply.github.com> Date: Mon, 2 Nov 2026 11:26:35 +0100 Subject: [PATCH 1/2] chore(release): release v2.40.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 02b1ee73..f41063cd 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "opencode-mem", - "version": "2.39.0", + "version": "2.40.0", "description": "OpenCode plugin that gives coding agents persistent memory using local Turso/libSQL vector search", "type": "module", "main": "dist/plugin.js", From f4bcd071c7837a7133bd2fa4f7b6edb3b10c8542 Mon Sep 17 00:00:00 2001 From: EyJunge1 <149941075+EyJunge1@users.noreply.github.com> Date: Mon, 2 Nov 2026 11:32:23 +0100 Subject: [PATCH 2/2] fix(test): restore embeddingService after turso refcount close stub Leaving a stub pipe object after the lease test poisoned later profile-write embeds in the full suite. --- tests/plugin-turso-refcount.test.ts | 57 +++++++++++++++++++---------- 1 file changed, 38 insertions(+), 19 deletions(-) diff --git a/tests/plugin-turso-refcount.test.ts b/tests/plugin-turso-refcount.test.ts index f8511c03..3631d44a 100644 --- a/tests/plugin-turso-refcount.test.ts +++ b/tests/plugin-turso-refcount.test.ts @@ -79,26 +79,45 @@ describe("plugin Turso refcount (#443)", () => { const id = await userPromptManager.savePrompt("sess-b", "msg-b", "/tmp/p", "world"); // Fake a warmed local model so the close path has something to release. - // Provide dispose explicitly: earlier suite mocks may replace embeddingService - // with a stub that lacks the real EmbeddingService methods. + // Restore afterwards: leaving a stub `pipe` object poisons later suite embeds + // (`pipe is not a function` in profile-write). const { embeddingService } = await import("../src/services/embedding.js"); const released: string[] = []; - Object.assign(embeddingService, { - pipe: { dispose: async () => released.push("dispose") }, - isWarmedUp: true, - async dispose() { - await (this as { pipe?: { dispose?: () => Promise } }).pipe?.dispose?.(); - }, - }); - - await memoryClient.close(); - expect(pluginTursoRefCount()).toBe(1); - expect((await userPromptManager.getPromptById(id))?.content).toBe("world"); - // Sibling instance still live: the process-wide model must stay loaded. - expect(released).toEqual([]); - - await memoryClient.close(); - expect(pluginTursoRefCount()).toBe(0); - expect(released).toEqual(["dispose"]); + const previous = { + pipe: embeddingService.pipe, + isWarmedUp: embeddingService.isWarmedUp, + dispose: embeddingService.dispose, + }; + try { + Object.assign(embeddingService, { + pipe: { dispose: async () => released.push("dispose") }, + isWarmedUp: true, + }); + // Earlier suite mocks may replace embeddingService without dispose. + if (typeof embeddingService.dispose !== "function") { + Object.assign(embeddingService, { + async dispose() { + const pipe = this.pipe as { dispose?: () => Promise } | null; + this.pipe = null; + this.isWarmedUp = false; + await pipe?.dispose?.(); + }, + }); + } + + await memoryClient.close(); + expect(pluginTursoRefCount()).toBe(1); + expect((await userPromptManager.getPromptById(id))?.content).toBe("world"); + // Sibling instance still live: the process-wide model must stay loaded. + expect(released).toEqual([]); + + await memoryClient.close(); + expect(pluginTursoRefCount()).toBe(0); + expect(released).toEqual(["dispose"]); + } finally { + embeddingService.pipe = previous.pipe; + embeddingService.isWarmedUp = previous.isWarmedUp; + embeddingService.dispose = previous.dispose; + } }); });