From 024425e9795f9a4aaa45f82f5c1434ed01b52c1d Mon Sep 17 00:00:00 2001 From: arkon Date: Thu, 22 Jan 2026 21:23:59 +0100 Subject: [PATCH] fix: add screens.json fallback for respawn recovery state.json is now the primary source for session recovery, but screens.json is used as a fallback for respawn config since it was the proven working path before. This provides double-redundancy: both files would need to be lost for respawn state to disappear. Co-Authored-By: Claude Opus 4.5 --- src/web/server.ts | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/web/server.ts b/src/web/server.ts index 8d62d516..e7f2851e 100644 --- a/src/web/server.ts +++ b/src/web/server.ts @@ -2030,6 +2030,32 @@ export class WebServer extends EventEmitter { } } + // Fallback: restore respawn from screens.json if state.json didn't have it + if (!this.respawnControllers.has(session.id) && screen.respawnConfig?.enabled) { + try { + const controller = new RespawnController(session, { + idleTimeoutMs: screen.respawnConfig.idleTimeoutMs, + updatePrompt: screen.respawnConfig.updatePrompt, + interStepDelayMs: screen.respawnConfig.interStepDelayMs, + enabled: true, + sendClear: screen.respawnConfig.sendClear, + sendInit: screen.respawnConfig.sendInit, + kickstartPrompt: screen.respawnConfig.kickstartPrompt, + }); + this.respawnControllers.set(session.id, controller); + this.setupRespawnListeners(session.id, controller); + controller.start(); + + if (screen.respawnConfig.durationMinutes && screen.respawnConfig.durationMinutes > 0) { + this.setupTimedRespawn(session.id, screen.respawnConfig.durationMinutes); + } + + console.log(`[Server] Restored respawn controller from screens.json for session ${session.id}`); + } catch (err) { + console.error(`[Server] Failed to restore respawn from screens.json for session ${session.id}:`, err); + } + } + // Fallback: restore Ralph state from state-inner.json if not already set if (!session.ralphTracker.enabled) { const ralphState = this.store.getRalphState(screen.sessionId);