From c8fd13120dca82261279456ea48f3ea0f50bd766 Mon Sep 17 00:00:00 2001 From: Neil <4138956+nwparker@users.noreply.github.com> Date: Sat, 30 May 2026 12:47:27 -0700 Subject: [PATCH] fix: avoid project group order spread crash (#3675) --- src/main/persistence.test.ts | 30 ++++++++++++++++++++++++++++++ src/main/persistence.ts | 9 +++++---- 2 files changed, 35 insertions(+), 4 deletions(-) diff --git a/src/main/persistence.test.ts b/src/main/persistence.test.ts index 62ed05f03..9eb4236e4 100644 --- a/src/main/persistence.test.ts +++ b/src/main/persistence.test.ts @@ -16,6 +16,7 @@ import { join } from 'path' import { tmpdir } from 'os' import type { PersistedState, + ProjectGroup, Repo, TerminalPaneLayoutNode, TerminalTab, @@ -1518,6 +1519,35 @@ describe('Store', () => { expect(store.getRepo('sibling')?.projectGroupId).toBe(sibling.id) }) + it('creates a project group when persisted group history is very large', async () => { + const projectGroups: ProjectGroup[] = Array.from({ length: 130_000 }, (_, index) => ({ + id: `group-${index}`, + name: `Group ${index}`, + parentPath: null, + parentGroupId: null, + createdFrom: 'manual', + tabOrder: index, + isCollapsed: false, + color: null, + createdAt: index, + updatedAt: index + })) + writeDataFile({ + schemaVersion: 1, + repos: [], + worktreeMeta: {}, + settings: {}, + ui: {}, + githubCache: { pr: {}, issue: {} }, + projectGroups + }) + const store = await createStore() + + const group = store.createProjectGroup({ name: 'New group', createdFrom: 'manual' }) + + expect(group.tabOrder).toBe(projectGroups.length) + }) + it('sanitizes invalid project group updates before persisting a repo', async () => { const store = await createStore() const group = store.createProjectGroup({ name: 'Platform', createdFrom: 'manual' }) diff --git a/src/main/persistence.ts b/src/main/persistence.ts index e3aef6063..2accd1887 100644 --- a/src/main/persistence.ts +++ b/src/main/persistence.ts @@ -2127,10 +2127,11 @@ export class Store { parentGroupId?: string | null createdFrom: ProjectGroup['createdFrom'] }): ProjectGroup { - const maxOrder = Math.max( - -1, - ...(this.state.projectGroups ?? []).map((group) => group.tabOrder) - ) + let maxOrder = -1 + // Why: persisted group lists can be large enough to exceed spread limits. + for (const existingGroup of this.state.projectGroups ?? []) { + maxOrder = Math.max(maxOrder, existingGroup.tabOrder) + } const group = createProjectGroup({ ...input, tabOrder: maxOrder + 1