| 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(); |