diff --git a/src/main/ipc/pty/ipc/spawn-commit-persist.ts b/src/main/ipc/pty/ipc/spawn-commit-persist.ts index 33b54fb8a6d..be9cb31394a 100644 --- a/src/main/ipc/pty/ipc/spawn-commit-persist.ts +++ b/src/main/ipc/pty/ipc/spawn-commit-persist.ts @@ -84,7 +84,10 @@ export async function persistPtyIpcSpawnCommit(ctx: PtyIpcSpawnState): Promise<{ }) } if (ctx.preAllocatedHandle && !ctx.stablePaneOwner?.handle) { - ctx.deps.runtime?.registerPreAllocatedHandleForPty(ctx.result.id, ctx.preAllocatedHandle) + if (ctx.deps.runtime?.registerPreAllocatedHandleForPty) { + ctx.deps.runtime.registerPreAllocatedHandleForPty(ctx.result.id, ctx.preAllocatedHandle) + ctx.agentTeamsLeaderHandle = null + } } ptySizes.set(ctx.result.id, { cols: args.cols, rows: args.rows }) if (ctx.effectiveSessionAppId !== undefined && ctx.effectiveSessionAppId !== ctx.result.id) { diff --git a/src/main/ipc/pty/ipc/spawn-commit.ts b/src/main/ipc/pty/ipc/spawn-commit.ts index 7711ba3c3e1..82a3aea1b74 100644 --- a/src/main/ipc/pty/ipc/spawn-commit.ts +++ b/src/main/ipc/pty/ipc/spawn-commit.ts @@ -25,7 +25,6 @@ import { persistPtyIpcSpawnCommit } from './spawn-commit-persist' export async function commitPtyIpcSpawn(ctx: PtyIpcSpawnState): Promise { const args = ctx.args const { rendererPreSignaled, rendererAlreadyRegistered } = await persistPtyIpcSpawnCommit(ctx) - ctx.agentTeamsLeaderHandle = null // Why: seed the headless emulator before registerPty so concurrent live PTY data lands on top of the seed, not replacing it (mobile keeps the daemon-restored scrollback). // Skip when the renderer will be authoritative — its xterm buffer is richer than the daemon snapshot. diff --git a/src/main/ipc/pty/ipc/spawn-run.ts b/src/main/ipc/pty/ipc/spawn-run.ts index 71f290a457f..748eb5d8f62 100644 --- a/src/main/ipc/pty/ipc/spawn-run.ts +++ b/src/main/ipc/pty/ipc/spawn-run.ts @@ -38,7 +38,10 @@ export async function runPtyIpcSpawn(deps: PtySpawnIpcDeps, args: PtySpawnIpcArg try { await preparePtyIpcSpawnPreflight(ctx) await assemblePtyIpcSpawnEnv(ctx) - const earlyReserved = await buildPtyIpcSpawnOptions(ctx) + const earlyReserved = await buildPtyIpcSpawnOptions(ctx).catch((error: unknown) => { + restoreProvisionalPtySize(ctx) + throw error + }) if (earlyReserved) { // Why: this request lost the pane to the reservation winner, so its // pre-allocated leader handle never binds to a PTY. Nothing else can @@ -51,7 +54,6 @@ export async function runPtyIpcSpawn(deps: PtySpawnIpcDeps, args: PtySpawnIpcArg return await commitPtyIpcSpawn(ctx) } catch (err) { releaseAbandonedAgentTeamsLeader(ctx) - restoreProvisionalPtySize(ctx) if (ctx.preSpawnHiddenMarkId !== null) { ctx.deps.transitionSpawnHiddenRendererPtyDeliveryState(ctx.preSpawnHiddenMarkId, false) } diff --git a/src/main/ipc/pty/runtime/spawn.ts b/src/main/ipc/pty/runtime/spawn.ts index 48768a31dc4..2af050cd796 100644 --- a/src/main/ipc/pty/runtime/spawn.ts +++ b/src/main/ipc/pty/runtime/spawn.ts @@ -87,14 +87,16 @@ export async function spawnPtyFromRuntimeController( if (earlyAdopt) { return toRuntimeSpawnReply(earlyAdopt) } - const earlyReserved = await buildRuntimePtySpawnOptions(ctx) + const earlyReserved = await buildRuntimePtySpawnOptions(ctx).catch((error: unknown) => { + restoreProvisionalPtySize(ctx) + throw error + }) if (earlyReserved) { return toRuntimeSpawnReply(earlyReserved) } await executeRuntimePtySpawn(ctx) return toRuntimeSpawnReply(await commitRuntimePtySpawn(ctx)) } catch (err) { - restoreProvisionalPtySize(ctx) if (ctx.pendingRegistrationPtyId) { deps.runtime?.cancelPendingPtyRegistration?.( ctx.pendingRegistrationPtyId,