import { randomBytes } from "node:crypto"; import { mkdtemp, readFile, rm } from "node:fs/promises"; import { tmpdir } from "node:os"; import { join } from "node:path"; import { config } from "../src/config.js"; import { assertModelCheckPassed, modelCheckReportSchema, modelCheckTargets } from "../src/runtime/model-check.js"; import { serviceOpencodeConfig } from "../src/runtime/opencode2-config.js"; import { startOpencode2 } from "../src/runtime/opencode2-server.js"; // Validate the saved configuration in a fresh OpenCode, without model inference. const controller = new AbortController(); let root: string | undefined; let runtime: Awaited> | undefined; const cancel = (exitCode: number) => { if (controller.signal.aborted) return; process.exitCode = exitCode; controller.abort(); }; const onInterrupt = () => cancel(130); const onTerminate = () => cancel(143); process.on("SIGINT", onInterrupt); process.on("SIGTERM", onTerminate); try { root = await mkdtemp(join(tmpdir(), "tjwater-model-check-")); runtime = await startOpencode2({ command: config.OPENCODE_COMMAND, hostname: "127.0.0.1", port: 0, timeout: 30_000, signal: controller.signal, config: serviceOpencodeConfig(JSON.parse(await readFile("opencode.json", "utf8")), config.MODEL_CONFIG), env: { AGENT_INTERNAL_TOKEN: randomBytes(32).toString("hex"), TJWATER_AGENT_WORKSPACE_ROOT: join(root, "workspaces"), XDG_DATA_HOME: join(root, "data"), XDG_CONFIG_HOME: join(root, "config"), XDG_CACHE_HOME: join(root, "cache"), XDG_STATE_HOME: join(root, "state"), }, }); const result = await runtime.client.rpc.call({ rpcID: "tjwater.tools", method: "check_models", input: modelCheckTargets(config.MODEL_CONFIG), location: { directory: process.cwd() } }, { signal: AbortSignal.any([controller.signal, AbortSignal.timeout(30_000)]) }); const report = modelCheckReportSchema.parse(result.output); console.log(JSON.stringify(report, null, 2)); assertModelCheckPassed(report); console.log(`OpenCode model check passed: ${report.models.length} models; no inference requests.`); } catch (error) { if (controller.signal.aborted) console.error("OpenCode model check cancelled."); else { console.error(error instanceof Error ? error.message : "OpenCode model check failed"); process.exitCode = 1; } } finally { runtime?.close(); if (runtime) await runtime.exited; if (root) await rm(root, { recursive: true, force: true }); process.removeListener("SIGINT", onInterrupt); process.removeListener("SIGTERM", onTerminate); }