From 370d4d55a03e398780af018182873ff5478f0d00 Mon Sep 17 00:00:00 2001 From: Hibryda Date: Thu, 26 Mar 2026 00:28:52 +0100 Subject: [PATCH] fix: MCP agor-start uses spawn+detach instead of blocking execSync --- .claude/mcp-servers/agor-launcher/index.mjs | 71 ++++++++++++++++++++- 1 file changed, 69 insertions(+), 2 deletions(-) diff --git a/.claude/mcp-servers/agor-launcher/index.mjs b/.claude/mcp-servers/agor-launcher/index.mjs index 5d1c1d2..2b83585 100644 --- a/.claude/mcp-servers/agor-launcher/index.mjs +++ b/.claude/mcp-servers/agor-launcher/index.mjs @@ -8,6 +8,10 @@ import { createInterface } from "readline"; const SCRIPT = "/home/hibryda/code/ai/agent-orchestrator/scripts/launch.sh"; +const ROOT = "/home/hibryda/code/ai/agent-orchestrator"; +const EBUN = `${ROOT}/ui-electrobun`; +const PTYD = `${ROOT}/agor-pty/target/release/agor-ptyd`; + function run(cmd, timeout = 30000) { try { return execSync(`bash ${SCRIPT} ${cmd}`, { @@ -20,11 +24,74 @@ function run(cmd, timeout = 30000) { } } +/** Start the app: stop old → start PTY → start Vite → launch Electrobun (backgrounded) */ +function startApp(clean = false) { + const steps = []; + + // Step 1: Stop old instances + try { + execSync('pkill -f "electrobun|WebKit|AgentOrch|launcher" 2>/dev/null; fuser -k 9760/tcp 2>/dev/null; true', { + timeout: 5000, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"], + }); + steps.push("[1/4] Stopped old instances"); + } catch { steps.push("[1/4] Stop (nothing running)"); } + + // Step 1.5: Clean if requested + if (clean) { + try { + execSync(`rm -rf ${EBUN}/build/ ${EBUN}/node_modules/.electrobun-cache/`, { timeout: 5000 }); + steps.push("[1.5] Cleaned build cache"); + } catch { steps.push("[1.5] Clean skipped"); } + } + + // Step 2: Start PTY daemon (if not running) + try { + const ptydCount = execSync("pgrep -fc agor-ptyd 2>/dev/null || echo 0", { encoding: "utf-8" }).trim(); + if (ptydCount === "0") { + const ptyd = spawn(PTYD, [], { detached: true, stdio: "ignore" }); + ptyd.unref(); + steps.push("[2/4] PTY daemon started"); + } else { + steps.push(`[2/4] PTY daemon already running (${ptydCount})`); + } + } catch (e) { steps.push(`[2/4] PTY daemon error: ${e.message}`); } + + // Step 3: Start Vite (if port 9760 not in use) + try { + const portCheck = execSync("fuser 9760/tcp 2>/dev/null || echo free", { encoding: "utf-8" }).trim(); + if (portCheck === "free") { + const vite = spawn("npx", ["vite", "dev", "--port", "9760", "--host", "localhost"], { + cwd: EBUN, detached: true, stdio: "ignore", + }); + vite.unref(); + steps.push("[3/4] Vite started on :9760"); + } else { + steps.push("[3/4] Vite already running on :9760"); + } + } catch (e) { steps.push(`[3/4] Vite error: ${e.message}`); } + + // Wait for Vite to be ready + try { execSync("sleep 3", { timeout: 5000 }); } catch {} + + // Step 4: Launch Electrobun (detached, output to log) + try { + const ebun = spawn("npx", ["electrobun", "dev"], { + cwd: EBUN, + detached: true, + stdio: ["ignore", "ignore", "ignore"], + }); + ebun.unref(); + steps.push(`[4/4] Electrobun launched (PID ${ebun.pid})`); + } catch (e) { steps.push(`[4/4] Electrobun error: ${e.message}`); } + + return steps.join("\n"); +} + const TOOLS = { "agor-start": { description: "Start Electrobun app (kills old instances first). Pass clean=true to remove build cache.", schema: { type: "object", properties: { clean: { type: "boolean", default: false } } }, - handler: ({ clean }) => run(clean ? "start --clean" : "start", 60000), + handler: ({ clean }) => startApp(clean), }, "agor-stop": { description: "Stop all running Electrobun/PTY/Vite instances.", @@ -34,7 +101,7 @@ const TOOLS = { "agor-restart": { description: "Restart Electrobun app. Pass clean=true for clean restart.", schema: { type: "object", properties: { clean: { type: "boolean", default: false } } }, - handler: ({ clean }) => run(clean ? "restart --clean" : "restart", 60000), + handler: ({ clean }) => { run("stop"); return startApp(clean); }, }, "agor-clean": { description: "Remove build artifacts, caches, and temp files.",