diff --git a/src/index.ts b/src/index.ts index d1419f4..9a77996 100644 --- a/src/index.ts +++ b/src/index.ts @@ -129,6 +129,10 @@ export const OpenCodeMemPlugin: Plugin = async (ctx: PluginInput) => { } const cleanupPlugin = async () => { + if (idleTimeout) { + clearTimeout(idleTimeout); + idleTimeout = null; + } if (webServer) await webServer.stop(); if (memoryClient) memoryClient.close(); }; @@ -136,10 +140,9 @@ export const OpenCodeMemPlugin: Plugin = async (ctx: PluginInput) => { const shutdownHandler = async () => { try { await cleanupPlugin(); - process.exit(0); } catch (error) { log("Shutdown error", { error: String(error) }); - process.exit(1); + process.exitCode = 1; } }; diff --git a/tests/plugin-shutdown.test.ts b/tests/plugin-shutdown.test.ts new file mode 100644 index 0000000..0a14071 --- /dev/null +++ b/tests/plugin-shutdown.test.ts @@ -0,0 +1,17 @@ +import { describe, expect, it } from "bun:test"; +import { readFileSync } from "node:fs"; + +describe("plugin shutdown", () => { + it("does not force host process exit from signal handlers", () => { + const source = readFileSync(new URL("../src/index.ts", import.meta.url), "utf-8"); + + expect(source).not.toContain("process.exit("); + }); + + it("clears pending idle auto-capture work during cleanup", () => { + const source = readFileSync(new URL("../src/index.ts", import.meta.url), "utf-8"); + + expect(source).toContain("clearTimeout(idleTimeout)"); + expect(source).toContain("idleTimeout = null"); + }); +});