From 19b8f64ed9e9bcb6ea7ee028e0bf4d942728f6a1 Mon Sep 17 00:00:00 2001 From: Neil <4138956+nwparker@users.noreply.github.com> Date: Sat, 30 May 2026 05:20:11 -0700 Subject: [PATCH] fix: hydrate large daemon pty session lists --- .../memory/hydrate-local-pty-registry.test.ts | 20 +++++++++++++++++++ src/main/memory/hydrate-local-pty-registry.ts | 10 +++++++++- 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/src/main/memory/hydrate-local-pty-registry.test.ts b/src/main/memory/hydrate-local-pty-registry.test.ts index 3cb4f888e86..7f54e0605c8 100644 --- a/src/main/memory/hydrate-local-pty-registry.test.ts +++ b/src/main/memory/hydrate-local-pty-registry.test.ts @@ -206,4 +206,24 @@ describe('hydrateLocalPtyRegistryAtBoot', () => { expect(entry!.pid).toBe(4242) expect(entry!.worktreeId).toBe('repo-a::/local/Triton') }) + + it('registers daemon session lists larger than the JavaScript argument limit', async () => { + const { hydrate, listRegisteredPtys } = await loadFresh() + + const sessions = Array.from({ length: 130_000 }, (_, index) => { + const ptyId = `repo-a::/local/Triton@@session-${index}` + return { sessionId: ptyId, pid: index + 1, cwd: '/local/Triton' } as unknown as SessionInfo + }) + const provider = makeProvider(sessions) + getDaemonProviderMock.mockReturnValue(provider) + listRepoWorktreesMock.mockResolvedValue([ + { path: '/local/Triton', head: '', branch: '', isBare: false, isMainWorktree: true } + ]) + + const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {}) + await hydrate(makeStore([{ id: 'repo-a', connectionId: null }])) + warnSpy.mockRestore() + + expect(listRegisteredPtys()).toHaveLength(sessions.length) + }) }) diff --git a/src/main/memory/hydrate-local-pty-registry.ts b/src/main/memory/hydrate-local-pty-registry.ts index bfa2d2d5052..3f311fd7b3c 100644 --- a/src/main/memory/hydrate-local-pty-registry.ts +++ b/src/main/memory/hydrate-local-pty-registry.ts @@ -146,7 +146,7 @@ async function collectSessionInfos( for (const adapter of adapters) { try { const sessions = await adapter.listSessions() - out.push(...sessions) + appendSessionInfos(out, sessions) } catch (err) { // Why: a single adapter failing should not abort hydration of the // others — the current adapter and any legacy daemons each have @@ -159,3 +159,11 @@ async function collectSessionInfos( } return out } + +function appendSessionInfos(target: SessionInfo[], source: readonly SessionInfo[]): void { + // Why: a daemon can return an unexpectedly large live-session list; spreading + // it into push would look like an adapter failure and drop every session. + for (const session of source) { + target.push(session) + } +}