From 30af757a30c24d4f6fa17f781e752f5baed5ae14 Mon Sep 17 00:00:00 2001 From: Neil <4138956+nwparker@users.noreply.github.com> Date: Sat, 30 May 2026 05:56:35 -0700 Subject: [PATCH] fix: load large legacy pane alias migrations --- src/main/persistence.test.ts | 54 ++++++++++++++++++++++++++++++++++++ src/main/persistence.ts | 10 +++++-- 2 files changed, 62 insertions(+), 2 deletions(-) diff --git a/src/main/persistence.test.ts b/src/main/persistence.test.ts index 6bde67ff4aa..a08f8b78e4b 100644 --- a/src/main/persistence.test.ts +++ b/src/main/persistence.test.ts @@ -17,6 +17,7 @@ import { tmpdir } from 'os' import type { PersistedState, Repo, + TerminalPaneLayoutNode, TerminalTab, WorktreeLineage, WorkspaceSessionState @@ -219,6 +220,19 @@ function makeSessionWithBrowserHistory(count: number): WorkspaceSessionState { } } +function makeBalancedLegacyPaneLayout(start: number, end: number): TerminalPaneLayoutNode { + if (end - start === 1) { + return { type: 'leaf', leafId: `pane:${start + 1}` } + } + const midpoint = Math.floor((start + end) / 2) + return { + type: 'split', + direction: 'horizontal', + first: makeBalancedLegacyPaneLayout(start, midpoint), + second: makeBalancedLegacyPaneLayout(midpoint, end) + } +} + describe('Store', () => { beforeEach(() => { testState.dir = mkdtempSync(join(tmpdir(), 'orca-test-')) @@ -3609,6 +3623,46 @@ describe('Store', () => { ) }) + it('loads legacy pane aliases from very large persisted split layouts', async () => { + const leafCount = 130_000 + writeDataFile({ + schemaVersion: 1, + repos: [], + worktreeMeta: {}, + settings: {}, + ui: {}, + githubCache: { pr: {}, issue: {} }, + workspaceSession: { + activeRepoId: 'r1', + activeWorktreeId: 'wt1', + activeTabId: 'tab1', + tabsByWorktree: { + wt1: [ + { + id: 'tab1', + worktreeId: 'wt1', + title: 'Terminal', + customTitle: null, + color: null, + sortOrder: 0, + createdAt: 1, + ptyId: 'large-pty' + } + ] + }, + terminalLayoutsByTabId: { + tab1: { + root: makeBalancedLegacyPaneLayout(0, leafCount), + activeLeafId: 'pane:1', + expandedLeafId: null + } + } + } + }) + + await expect(createStore()).resolves.toBeDefined() + }) + it('converts unambiguous dev migration rows into persisted aliases', async () => { const stablePaneKey = makePaneKey('tab1', TEST_LEAF_1) writeDataFile({ diff --git a/src/main/persistence.ts b/src/main/persistence.ts index 864129326ac..654f7c983fa 100644 --- a/src/main/persistence.ts +++ b/src/main/persistence.ts @@ -1013,8 +1013,14 @@ function normalizeWorkspaceSessionPaneIdentities( normalizedLayout: normalized.snapshot, leafIdByInputLeafId: normalized.leafIdByInputLeafId }) - migrationUnsupportedEntries.push(...migrationEntries.migrationUnsupportedEntries) - legacyPaneKeyAliasEntries.push(...migrationEntries.legacyPaneKeyAliasEntries) + // Why: old persisted split layouts can generate enough alias rows to + // exceed V8's argument limit if the arrays are spread into push(). + for (const entry of migrationEntries.migrationUnsupportedEntries) { + migrationUnsupportedEntries.push(entry) + } + for (const entry of migrationEntries.legacyPaneKeyAliasEntries) { + legacyPaneKeyAliasEntries.push(entry) + } const leafIdByPtyId = new Map() const duplicatePtyIds = new Set() for (const [leafId, ptyId] of Object.entries(normalized.snapshot.ptyIdsByLeafId ?? {})) {