import { spawn } from "node:child_process"; import net from "node:net"; export function isPortFree(host: string, port: number): Promise { return new Promise((resolve) => { const socket = net.connect({ host, port, timeout: 500 }); socket.once("connect", () => { socket.destroy(); resolve(false); }); socket.once("timeout", () => { socket.destroy(); resolve(true); }); socket.once("error", () => { resolve(true); }); }); } export async function waitUntilReady( url: string, timeoutMs: number, intervalMs = 400, ): Promise { const deadline = Date.now() + timeoutMs; while (Date.now() < deadline) { try { const response = await fetch(url, { signal: AbortSignal.timeout(1500) }); if (response.status === 200) return true; } catch { // not ready yet } await new Promise((resolve) => setTimeout(resolve, intervalMs)); } return false; } export function openBrowser(url: string): void { const command = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open"; const args = process.platform === "win32" ? ["", url] : [url]; try { spawn(command, args, { detached: true, stdio: "ignore", shell: process.platform === "win32" }).unref(); } catch { // best-effort - not fatal if no browser opener is available } }