const { spawn, spawnSync } = require("child_process"); const fs = require("fs"); const path = require("path"); const PORT = String(process.env.PORT || 7860); const HOST = "0.0.0.0"; const HOME = process.env.HOME || "/home/node"; const WORKSPACE_DIR = process.env.WORKSPACE_DIR || HOME; function resolveOpencodeBin() { const localBin = path.join(__dirname, "node_modules", ".bin", "opencode"); if (fs.existsSync(localBin)) return localBin; return "opencode"; } function spawnSyncSafe(cmd, args) { const r = spawnSync(cmd, args, { encoding: "utf-8" }); if (r.error) return "not found"; return (r.stdout || r.stderr || "").trim().split("\n")[0] || "ok"; } function buildEnv() { const env = { ...process.env }; if (!env.OPENCODE_SERVER_PASSWORD && env.OPENCODE_PASSWORD) { env.OPENCODE_SERVER_PASSWORD = env.OPENCODE_PASSWORD; } if (!env.OPENCODE_SERVER_USERNAME) { env.OPENCODE_SERVER_USERNAME = env.OPENCODE_USERNAME || "opencode"; } const prefix = "/home/node/app/node_modules/.bin:/usr/local/bun/bin"; env.PATH = env.PATH ? `${prefix}:${env.PATH}` : prefix; env.OPENCODE_BACKGROUND_CONCURRENCY = env.OPENCODE_BACKGROUND_CONCURRENCY || "1"; env.OPENCODE_MODEL_CONCURRENCY = env.OPENCODE_MODEL_CONCURRENCY || "1"; return env; } function ensureUserDirs() { for (const d of ["chat", "temp", "project"]) { fs.mkdirSync(path.join(HOME, d), { recursive: true }); } } let child = null; function startOpenCode() { ensureUserDirs(); fs.mkdirSync(WORKSPACE_DIR, { recursive: true }); const opencodeBin = resolveOpencodeBin(); const env = buildEnv(); console.log(`[start] HOME=${HOME}`); console.log(`[start] workspace=${WORKSPACE_DIR}`); console.log(`[start] opencode=${opencodeBin}`); console.log(`[start] git=${spawnSyncSafe("git", ["--version"])}`); console.log(`[start] curl=${spawnSyncSafe("curl", ["--version"])}`); console.log(`[start] rg=${spawnSyncSafe("rg", ["--version"])}`); console.log(`[start] jq=${spawnSyncSafe("jq", ["--version"])}`); console.log(`[start] python3=${spawnSyncSafe("python3", ["--version"])}`); console.log(`[start] bun=${spawnSyncSafe("bun", ["--version"])}`); if (!env.OPENCODE_SERVER_PASSWORD) { console.log("[start] WARNING: OPENCODE_SERVER_PASSWORD is NOT set (public access)."); } console.log(`[start] Starting OpenCode web on ${HOST}:${PORT}`); child = spawn(opencodeBin, ["web", "--port", PORT, "--hostname", HOST], { env, cwd: WORKSPACE_DIR, stdio: "inherit", }); child.on("close", (code) => { console.log(`[start] OpenCode exited with code ${code}. Restarting in 5 seconds...`); setTimeout(startOpenCode, 5000); }); } process.on("SIGTERM", () => child?.kill("SIGTERM")); process.on("SIGINT", () => child?.kill("SIGINT")); startOpenCode();