From 28a6247c2746d49205ef1a1c5916cae3edefecc4 Mon Sep 17 00:00:00 2001 From: Teigen Date: Thu, 2 Apr 2026 21:35:00 +0800 Subject: [PATCH] fix: auto-attach PTY to surviving tmux sessions on server restart Previously, restoreMuxSessions() only created Session objects without attaching PTY processes. Sessions stayed at pid=null until the client manually selected them, causing terminals to appear "closed" after deploy. Now the server calls startInteractive() for each recovered session during startup, so all sessions resume capturing output immediately. The frontend auto-attach condition is also relaxed from (pid===null && status==='idle') to (pid===null && !_ended) as a safety net for edge cases. --- src/web/public/app.js | 5 +++-- src/web/server.ts | 29 +++++++++++++++++++++-------- 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/src/web/public/app.js b/src/web/public/app.js index 35b10fb5..8c9a297f 100644 --- a/src/web/public/app.js +++ b/src/web/public/app.js @@ -2105,8 +2105,9 @@ class CodemanApp { // Track working directory for path normalization in Project Insights this.currentSessionWorkingDir = session?.workingDir || null; - if (session && session.pid === null && session.status === 'idle') { - // This is a restored session - attach to the existing screen/shell + if (session && session.pid === null && !session._ended) { + // Session has no PTY attached — either restored after server restart + // or detached for some other reason. Re-attach regardless of status. try { const endpoint = session.mode === 'shell' ? `/api/sessions/${sessionId}/shell` diff --git a/src/web/server.ts b/src/web/server.ts index 5395d04b..e93df334 100644 --- a/src/web/server.ts +++ b/src/web/server.ts @@ -1766,15 +1766,28 @@ export class WebServer extends EventEmitter { this.sessions.set(session.id, session); await this.setupSessionListeners(session); - this.persistSessionState(session); - // Mark it as restored (not started yet - user needs to attach) - getLifecycleLog().log({ - event: 'recovered', - sessionId: session.id, - name: session.name, - }); - console.log(`[Server] Restored session ${session.id} from mux ${muxSession.muxName}`); + // Auto-attach PTY to the surviving tmux session immediately. + // This ensures ALL sessions resume capturing output right away, + // not just the one the client happens to select first. + try { + await session.startInteractive(); + getLifecycleLog().log({ + event: 'recovered', + sessionId: session.id, + name: session.name, + }); + console.log(`[Server] Restored and attached session ${session.id} from mux ${muxSession.muxName}`); + } catch (attachErr) { + console.error(`[Server] Failed to attach session ${session.id}, keeping as detached:`, attachErr); + getLifecycleLog().log({ + event: 'recovered', + sessionId: session.id, + name: session.name, + }); + } + + this.persistSessionState(session); } }