History

Fix terminal state infinite loop, test ordering assertion, and redundant updateBranch call

- ChatView: Stabilize terminalIds/terminalGroups dependencies by using JSON.stringify so React compares by value instead of reference, preventing an infinite write loop when normalizeThreadTerminals creates new arrays. - persistenceService.test: Fix catchUp ordering assertion to compare each event's seq against the previous event's seq instead of itself. - BranchToolbar: Remove redundant api.threads.updateBranch call since the useEffect in ChatView already syncs branch changes to the server.

Cursor Agent committed 8 months ago

Commit ab955dd1 parent 384878a3 files · +11 −6Browse files

Unified · Split

3 files
  1. apps/server/src/persistenceService.test.ts +5 −3
  2. apps/web/src/components/BranchToolbar.tsx +0 −1
  3. apps/web/src/components/ChatView.tsx +6 −2
apps/server/src/persistenceService.test.ts+5−3
@@ -125,9 +125,11 @@ describe("PersistenceService", () => { · 124 unmodified lines
125125
126126 const catchUp = service.catchUp({ afterSeq: 0 });
127127 expect(catchUp.events.length).toBeGreaterThan(0);
128− expect(catchUp.events.every((event, index, events) => event.seq === events[index]?.seq)).toBe(
129− true,
130− );
128+ expect(
129+ catchUp.events.every(
130+ (event, index, events) => index === 0 || event.seq > events[index - 1]!.seq,
131+ ),
132+ ).toBe(true);
131133 expect(catchUp.events.some((event) => event.eventType === "project.upsert")).toBe(true);
132134 expect(catchUp.events.some((event) => event.eventType === "thread.upsert")).toBe(true);
133135 expect(catchUp.events.some((event) => event.eventType === "message.upsert")).toBe(true);
apps/web/src/components/BranchToolbar.tsx+0−1
@@ -120,7 +120,6 @@ export default function BranchToolbar({ · 119 unmodified lines
120120 if (sessionId && worktreePath !== activeWorktreePath) {
121121 void api?.providers.stopSession({ sessionId }).catch(() => undefined);
122122 }
123− void api?.threads.updateBranch({ threadId: activeThreadId, branch, worktreePath }).catch(() => undefined);
124123 dispatch({ type: "SET_THREAD_BRANCH", threadId: activeThreadId, branch, worktreePath });
125124 };
126125
apps/web/src/components/ChatView.tsx+6−2
@@ -782,6 +782,9 @@ export default function ChatView({ threadId }: ChatViewProps) { · 781 unmodified lines
782782 .catch(() => undefined);
783783 }, [activeThread?.id, activeThread?.branch, activeThread?.worktreePath, api]);
784784
785+ const terminalIdsKey = JSON.stringify(activeThread?.terminalIds ?? null);
786+ const terminalGroupsKey = JSON.stringify(activeThread?.terminalGroups ?? null);
787+
785788 useEffect(() => {
786789 if (!api || !activeThread) return;
787790 void api.threads
@@ -795,13 +798,14 @@ export default function ChatView({ threadId }: ChatViewProps) { · 7 unmodified lines
795798 activeTerminalGroupId: activeThread.activeTerminalGroupId,
796799 })
797800 .catch(() => undefined);
801+ // eslint-disable-next-line react-hooks/exhaustive-deps
798802 }, [
799803 activeThread?.id,
800804 activeThread?.terminalOpen,
801805 activeThread?.terminalHeight,
802− activeThread?.terminalIds,
806+ terminalIdsKey,
803807 activeThread?.activeTerminalId,
804− activeThread?.terminalGroups,
808+ terminalGroupsKey,
805809 activeThread?.activeTerminalGroupId,
806810 api,
807811 ]);