From fe8d75129444532c217ad561668a4a79bb5fa30e Mon Sep 17 00:00:00 2001 From: mitosky07 Date: Wed, 12 Aug 2026 02:03:53 -0600 Subject: [PATCH 1/2] fix(server): skip killing completed provider updates Avoid redundant process-group cleanup after successful updates, which can invoke taskkill through cmd.exe on Windows. --- .../providerMaintenanceRunner.test.ts | 35 +++++++++++++++++-- .../src/provider/providerMaintenanceRunner.ts | 7 +++- 2 files changed, 39 insertions(+), 3 deletions(-) diff --git a/apps/server/src/provider/providerMaintenanceRunner.test.ts b/apps/server/src/provider/providerMaintenanceRunner.test.ts index 641c9b52e56..0e6867e471b 100644 --- a/apps/server/src/provider/providerMaintenanceRunner.test.ts +++ b/apps/server/src/provider/providerMaintenanceRunner.test.ts @@ -109,12 +109,14 @@ function mockHandle(result: { readonly stderr?: string; readonly code?: number; readonly exitCode?: Effect.Effect; + readonly isRunning?: Effect.Effect; + readonly kill?: () => Effect.Effect; }) { return ChildProcessSpawner.makeHandle({ pid: ChildProcessSpawner.ProcessId(1), exitCode: result.exitCode ?? Effect.succeed(ChildProcessSpawner.ExitCode(result.code ?? 0)), - isRunning: Effect.succeed(false), - kill: () => Effect.void, + isRunning: result.isRunning ?? Effect.succeed(false), + kill: result.kill ?? (() => Effect.void), unref: Effect.succeed(Effect.void), stdin: Sink.drain, stdout: Stream.make(encoder.encode(result.stdout ?? "")), @@ -134,6 +136,8 @@ function mockSpawnerLayer( readonly stderr?: string; readonly code?: number; readonly exitCode?: Effect.Effect; + readonly isRunning?: Effect.Effect; + readonly kill?: () => Effect.Effect; }, ) { return Layer.succeed( @@ -217,6 +221,33 @@ const makeTestRunner = (registry: ProviderRegistryShape) => ); describe("providerMaintenanceRunner", () => { + it.effect("does not kill an updater that already exited", () => { + let killCalls = 0; + return Effect.gen(function* () { + const { registry } = yield* makeRegistry(baseCursorProvider); + const updater = yield* makeTestRunner(registry); + + yield* updater.updateProvider(CURSOR_DRIVER); + + assert.strictEqual(killCalls, 0); + }).pipe( + Effect.provide( + Layer.mergeAll( + NonWindowsPlatform, + latestVersionHttpClient("0.0.0"), + mockSpawnerLayer(() => ({ + stdout: "updated", + isRunning: Effect.succeed(false), + kill: () => + Effect.sync(() => { + killCalls += 1; + }), + })), + ), + ), + ); + }); + it.effect("runs the allowlisted provider update command and records success", () => { const calls: Array<{ command: string; args: ReadonlyArray }> = []; return Effect.gen(function* () { diff --git a/apps/server/src/provider/providerMaintenanceRunner.ts b/apps/server/src/provider/providerMaintenanceRunner.ts index 3c114dd83d8..d4798d6ab75 100644 --- a/apps/server/src/provider/providerMaintenanceRunner.ts +++ b/apps/server/src/provider/providerMaintenanceRunner.ts @@ -93,7 +93,12 @@ const runProviderMaintenanceCommandWithSpawner = Effect.fn("ProviderMaintenanceR }), ), ); - yield* Effect.addFinalizer(() => child.kill().pipe(Effect.ignore)); + yield* Effect.addFinalizer(() => + child.isRunning.pipe( + Effect.flatMap((isRunning) => (isRunning ? child.kill() : Effect.void)), + Effect.ignore, + ), + ); const [stdout, stderr, exitCode] = yield* Effect.all( [ From 94424133ee32f3a44f6b0a55312f0ee6da88fb82 Mon Sep 17 00:00:00 2001 From: Manuel Conteras Covarrubias Date: Wed, 12 Aug 2026 02:13:40 -0600 Subject: [PATCH 2/2] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- apps/server/src/provider/providerMaintenanceRunner.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/server/src/provider/providerMaintenanceRunner.ts b/apps/server/src/provider/providerMaintenanceRunner.ts index d4798d6ab75..623f9d06b25 100644 --- a/apps/server/src/provider/providerMaintenanceRunner.ts +++ b/apps/server/src/provider/providerMaintenanceRunner.ts @@ -95,6 +95,7 @@ const runProviderMaintenanceCommandWithSpawner = Effect.fn("ProviderMaintenanceR ); yield* Effect.addFinalizer(() => child.isRunning.pipe( + Effect.orElseSucceed(() => true), Effect.flatMap((isRunning) => (isRunning ? child.kill() : Effect.void)), Effect.ignore, ),