diff --git a/apps/server/src/terminal/Layers/Manager.test.ts b/apps/server/src/terminal/Layers/Manager.test.ts index 2ebf8481957..2b36148d6f8 100644 --- a/apps/server/src/terminal/Layers/Manager.test.ts +++ b/apps/server/src/terminal/Layers/Manager.test.ts @@ -983,7 +983,10 @@ it.layer( it.effect("escalates terminal shutdown to SIGKILL when process does not exit in time", () => Effect.gen(function* () { - const { manager, ptyAdapter } = yield* createManager(5, { processKillGraceMs: 10 }); + const { manager, ptyAdapter } = yield* createManager(5, { + platform: "linux", + processKillGraceMs: 10, + }); yield* manager.open(openInput()); const process = ptyAdapter.processes[0]; expect(process).toBeDefined(); @@ -999,6 +1002,25 @@ it.layer( }).pipe(Effect.provide(TestClock.layer())), ); + it.effect("kills the terminal without a signal on Windows", () => + Effect.gen(function* () { + const { manager, ptyAdapter } = yield* createManager(5, { + platform: "win32", + subprocessInspector: () => + Effect.succeed({ hasRunningSubprocess: false, childCommand: null }), + }); + yield* manager.open(openInput()); + const process = ptyAdapter.processes[0]; + expect(process).toBeDefined(); + if (!process) return; + + yield* manager.close({ threadId: "thread-1" }); + yield* waitFor(Effect.sync(() => process.killed)); + + expect(process.killSignals).toEqual([undefined]); + }), + ); + it.effect("publishes closed events when terminals are explicitly closed", () => Effect.gen(function* () { const { manager, getEvents } = yield* createManager(); @@ -1501,6 +1523,7 @@ it.layer( Effect.gen(function* () { const scope = yield* Scope.make("sequential"); const { manager, ptyAdapter } = yield* createManager(5, { + platform: "linux", processKillGraceMs: 10, }).pipe(Effect.provideService(Scope.Scope, scope)); yield* manager.open(openInput()); diff --git a/apps/server/src/terminal/Layers/Manager.ts b/apps/server/src/terminal/Layers/Manager.ts index cd490de1e3f..7271105ac16 100644 --- a/apps/server/src/terminal/Layers/Manager.ts +++ b/apps/server/src/terminal/Layers/Manager.ts @@ -75,7 +75,7 @@ class TerminalProcessSignalError extends Schema.TaggedErrorClass process.kill(), + catch: (cause) => + new TerminalProcessSignalError({ + message: "Failed to kill terminal console process tree.", + cause, + }), + }).pipe( + Effect.catch((error) => + Effect.logWarning("failed to kill terminal process", { + threadId, + terminalId, + error: error.message, + }), + ), + ); + return; + } + const terminated = yield* Effect.try({ try: () => process.kill("SIGTERM"), catch: (cause) =>