Skip to content

Commit 73c9559

Browse files
committed
🤖 fix: avoid infinite rerender for live bash output
Change-Id: Idb868686d632862e0ed5c9b472670fd49ecd6e8a Signed-off-by: Thomas Kosiewski <tk@coder.com>
1 parent d80a0bd commit 73c9559

File tree

2 files changed

+12
-4
lines changed

2 files changed

+12
-4
lines changed

src/browser/stores/WorkspaceStore.test.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -671,8 +671,14 @@ describe("WorkspaceStore", () => {
671671

672672
const live = store.getBashToolLiveOutput(workspaceId, "call-1");
673673
expect(live).not.toBeNull();
674-
expect(live?.stdout).toContain("out");
675-
expect(live?.stderr).toContain("err");
674+
if (!live) throw new Error("Expected live output");
675+
676+
// getSnapshot in useSyncExternalStore requires referential stability when unchanged.
677+
const liveAgain = store.getBashToolLiveOutput(workspaceId, "call-1");
678+
expect(liveAgain).toBe(live);
679+
680+
expect(live.stdout).toContain("out");
681+
expect(live.stderr).toContain("err");
676682
});
677683

678684
it("clears live output when bash tool result includes output", async () => {

src/browser/stores/WorkspaceStore.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@ import type { LanguageModelV2Usage } from "@ai-sdk/provider";
3434
import { createFreshRetryState } from "@/browser/utils/messages/retryState";
3535
import {
3636
appendLiveBashOutputChunk,
37-
toLiveBashOutputView,
3837
type LiveBashOutputInternal,
3938
type LiveBashOutputView,
4039
} from "@/browser/utils/messages/liveBashOutputBuffer";
@@ -704,7 +703,10 @@ export class WorkspaceStore {
704703
getBashToolLiveOutput(workspaceId: string, toolCallId: string): LiveBashOutputView | null {
705704
const perWorkspace = this.liveBashOutput.get(workspaceId);
706705
const state = perWorkspace?.get(toolCallId);
707-
return state ? toLiveBashOutputView(state) : null;
706+
707+
// Important: return the stored object reference so useSyncExternalStore sees a stable snapshot.
708+
// (Returning a fresh object every call can trigger an infinite re-render loop.)
709+
return state ?? null;
708710
}
709711

710712
/**

0 commit comments

Comments
 (0)