UNPKG

@botpress/adk-cli

Version:

Command-line interface for the Botpress Agent Development Kit (ADK)

110 lines (107 loc) 3.18 kB
// @bun import { CONSOLE_LOCK_FILE, CONSOLE_PORT_FILE, CONSOLE_SOCKET_PATH, isAdkDevConsolePort } from "./chunk-sgj6770p.js"; // src/server/console-control.ts import { existsSync, unlinkSync } from "fs"; var FETCH_TIMEOUT_MS = 1e4; function isProcessAlive(pid) { try { process.kill(pid, 0); return true; } catch { return false; } } async function shutdownConsole(port) { try { const res = await fetch(`http://localhost:${port}/api/console/shutdown`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({}), signal: AbortSignal.timeout(FETCH_TIMEOUT_MS) }); if (res.status === 404) { return { result: "unavailable" }; } if (!res.ok) { const body = await res.json().catch(() => null); return { result: "failed", error: body?.message ?? `Shutdown request returned HTTP ${res.status}` }; } return { result: "success" }; } catch (err) { const msg = err instanceof Error ? err.message : String(err); if (msg.includes("Connection refused") || msg.includes("ECONNREFUSED") || msg.includes("TimeoutError")) { return { result: "success" }; } return { result: "failed", error: msg }; } } async function waitForConsoleDead(port, timeoutMs = 4000) { const start = Date.now(); while (Date.now() - start < timeoutMs) { const alive = await isAdkDevConsolePort(port).catch(() => false); if (!alive) return true; await new Promise((resolve) => setTimeout(resolve, 250)); } return false; } async function forceKillConsole(pid) { if (pid <= 0 || !isProcessAlive(pid)) return { killed: false }; try { process.kill(pid, "SIGTERM"); } catch { return { killed: false }; } const start = Date.now(); while (Date.now() - start < 3000) { if (!isProcessAlive(pid)) return { killed: true, signal: "SIGTERM" }; await new Promise((resolve) => setTimeout(resolve, 200)); } try { process.kill(pid, "SIGKILL"); } catch { return { killed: !isProcessAlive(pid), signal: "SIGTERM" }; } await new Promise((resolve) => setTimeout(resolve, 500)); return { killed: !isProcessAlive(pid), signal: "SIGKILL" }; } function cleanupConsoleFiles() { const removed = []; for (const [filePath, label] of [ [CONSOLE_PORT_FILE, "console.port"], [CONSOLE_SOCKET_PATH, "console.sock"], [CONSOLE_LOCK_FILE, "console.lock"] ]) { if (existsSync(filePath)) { try { unlinkSync(filePath); removed.push(label); } catch {} } } return removed; } async function shutdownDevConsole(opts) { const { port, pid } = opts; const shutdown = await shutdownConsole(port); if (shutdown.result === "success" && await waitForConsoleDead(port)) { cleanupConsoleFiles(); return { stopped: true, method: "graceful" }; } if (pid && pid > 0 && (await forceKillConsole(pid)).killed) { cleanupConsoleFiles(); return { stopped: true, method: "forced" }; } return { stopped: false, method: "failed" }; } export { shutdownConsole, waitForConsoleDead, forceKillConsole, cleanupConsoleFiles, shutdownDevConsole };