diff --git a/docker/scribus-novnc/bridge/server.py b/docker/scribus-novnc/bridge/server.py index 6747c9d..dc7bca6 100644 --- a/docker/scribus-novnc/bridge/server.py +++ b/docker/scribus-novnc/bridge/server.py @@ -96,7 +96,12 @@ def start_scribus(): global _scribus_proc if _scribus_proc and _scribus_proc.poll() is None: - return jsonify({"ok": True, "message": "Scribus already running", "pid": _scribus_proc.pid}) + if os.path.exists(SOCKET_PATH): + return jsonify({"ok": True, "message": "Scribus already running", "pid": _scribus_proc.pid}) + # Process alive but runner socket missing — kill and restart + _scribus_proc.kill() + _scribus_proc.wait(timeout=5) + _scribus_proc = None # Clean up stale socket if os.path.exists(SOCKET_PATH): diff --git a/modules/rdesign/design-agent-route.ts b/modules/rdesign/design-agent-route.ts index 6b566e6..f7a0ba8 100644 --- a/modules/rdesign/design-agent-route.ts +++ b/modules/rdesign/design-agent-route.ts @@ -61,7 +61,7 @@ async function bridgeState(): Promise { } } -/** Start Scribus if not running. */ +/** Start Scribus if not running, verify runner is connected. */ async function ensureScribusRunning(): Promise { const headers: Record = { "Content-Type": "application/json" }; if (BRIDGE_SECRET) headers["X-Bridge-Secret"] = BRIDGE_SECRET; @@ -72,7 +72,25 @@ async function ensureScribusRunning(): Promise { headers, signal: AbortSignal.timeout(20_000), }); - return await res.json(); + const result = await res.json(); + if (result.error) return result; + + // Verify runner is actually connected by checking state + const stateRes = await fetch(`${SCRIBUS_BRIDGE_URL}/api/scribus/state`, { + headers, + signal: AbortSignal.timeout(10_000), + }); + const state = await stateRes.json(); + if (!state.error) return result; + + // Runner not connected — force restart by calling start again + // (server.py now kills zombie Scribus when socket is missing) + const retryRes = await fetch(`${SCRIBUS_BRIDGE_URL}/api/scribus/start`, { + method: "POST", + headers, + signal: AbortSignal.timeout(20_000), + }); + return await retryRes.json(); } catch (e: any) { return { error: `Bridge unreachable: ${e.message}` }; }