From 868f64cfcb0ea4a4649a6428f4fe5d0ccacb2bec Mon Sep 17 00:00:00 2001 From: PostHog Code Date: Thu, 7 May 2026 19:36:06 +0000 Subject: [PATCH 1/2] fix: stop terminal resize loop on dead shell session MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When a shell pty exits, TerminalManager.handleExit only emitted an "exit" event — it never reset instance.isReady or disconnected the ResizeObserver. The instance is kept around so the buffer remains viewable, but the next layout shift caused the ResizeObserver to fire shell.resize against a session the main process had already discarded. That call rejects, the catch logs, the failed call updates layout, and the observer fires again. Tight enough to wedge the renderer when the tab stays attached after a setup script finishes. Set isReady to false and disconnect the ResizeObserver in handleExit so no further resize calls go out for the dead session. The instance itself is still kept until destroy() so the terminal buffer remains visible. Generated-By: PostHog Code Task-Id: 39eb3a58-c962-49af-a1ed-2c621ba04d6e --- .../features/terminal/services/TerminalManager.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/apps/code/src/renderer/features/terminal/services/TerminalManager.ts b/apps/code/src/renderer/features/terminal/services/TerminalManager.ts index 1c5c5f242..5289364d3 100644 --- a/apps/code/src/renderer/features/terminal/services/TerminalManager.ts +++ b/apps/code/src/renderer/features/terminal/services/TerminalManager.ts @@ -273,6 +273,14 @@ class TerminalManagerImpl { handleExit(sessionId: string, exitCode?: number): void { const instance = this.instances.get(sessionId); if (instance) { + // Without this, ResizeObserver keeps firing shell.resize against the dead + // session on every layout shift, producing a TRPC error per call and + // wedging the renderer. + instance.isReady = false; + if (instance.resizeObserver) { + instance.resizeObserver.disconnect(); + instance.resizeObserver = null; + } this.emit("exit", { sessionId, persistenceKey: instance.persistenceKey, From 28489ab5eccf0c7525d0e43eef9f3f97b0666127 Mon Sep 17 00:00:00 2001 From: pauldambra Date: Thu, 7 May 2026 21:56:31 +0100 Subject: [PATCH 2/2] refactor: extract disconnectResizeObserver helper Three call sites in TerminalManager were repeating the same observer disconnect dance: attach(), detach(), and the new handleExit() block from the prior commit. Extract a private disconnectResizeObserver helper and call it from all three. Behaviour is unchanged. Motivated by qa-swarm feedback (3 reviewers converged on this dedup). Generated-By: PostHog Code Task-Id: c406af31-2216-42c6-a282-7fd75721a14d --- .../terminal/services/TerminalManager.ts | 22 +++++++++---------- 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/apps/code/src/renderer/features/terminal/services/TerminalManager.ts b/apps/code/src/renderer/features/terminal/services/TerminalManager.ts index 5289364d3..bd15de20c 100644 --- a/apps/code/src/renderer/features/terminal/services/TerminalManager.ts +++ b/apps/code/src/renderer/features/terminal/services/TerminalManager.ts @@ -277,10 +277,7 @@ class TerminalManagerImpl { // session on every layout shift, producing a TRPC error per call and // wedging the renderer. instance.isReady = false; - if (instance.resizeObserver) { - instance.resizeObserver.disconnect(); - instance.resizeObserver = null; - } + this.disconnectResizeObserver(instance); this.emit("exit", { sessionId, persistenceKey: instance.persistenceKey, @@ -289,6 +286,13 @@ class TerminalManagerImpl { } } + private disconnectResizeObserver(instance: TerminalInstance): void { + if (instance.resizeObserver) { + instance.resizeObserver.disconnect(); + instance.resizeObserver = null; + } + } + private scheduleSave(sessionId: string, instance: TerminalInstance): void { if (instance.saveTimeout) { clearTimeout(instance.saveTimeout); @@ -315,10 +319,7 @@ class TerminalManagerImpl { return; } - if (instance.resizeObserver) { - instance.resizeObserver.disconnect(); - instance.resizeObserver = null; - } + this.disconnectResizeObserver(instance); instance.attachedElement = element; @@ -363,10 +364,7 @@ class TerminalManagerImpl { return; } - if (instance.resizeObserver) { - instance.resizeObserver.disconnect(); - instance.resizeObserver = null; - } + this.disconnectResizeObserver(instance); const serialized = instance.serializeAddon.serialize(); this.emit("stateChange", {