import { ChildProcess, spawn, SpawnOptions } from "child_process"; import { OpenCodeProcess } from "./OpenCodeProcess"; export class WindowsProcess implements OpenCodeProcess { start( command: string, args: string[], options: SpawnOptions ): ChildProcess { return spawn(command, args, { ...options, shell: true, windowsHide: true, }); } async stop(process: ChildProcess): Promise { const pid = process.pid; if (!pid) { return; } console.log("[OpenCode] Stopping server process tree, PID:", pid); // Use taskkill with /T flag to kill process tree await this.execAsync(`taskkill /T /F /PID ${pid}`); // Wait for process to exit await this.waitForExit(process, 5000); } async verifyCommand(command: string): Promise { // Use 'where' command to check if executable exists in PATH try { await this.execAsync(`where "${command}"`); return null; } catch { return `Executable not found at '${command}'. Check Settings → OpenCode path, or click "Autodetect"`; } } private async waitForExit( process: ChildProcess, timeoutMs: number ): Promise { if (process.exitCode !== null || process.signalCode !== null) { return; // Already exited } return new Promise((resolve) => { const timeout = setTimeout(() => { cleanup(); resolve(); }, timeoutMs); const onExit = () => { cleanup(); resolve(); }; const cleanup = () => { clearTimeout(timeout); process.off("exit", onExit); process.off("error", onExit); }; process.once("exit", onExit); process.once("error", onExit); }); } private execAsync(command: string): Promise { return new Promise((resolve, reject) => { const { exec } = require("child_process"); exec(command, (error: Error | null) => { if (error) { reject(error); } else { resolve(); } }); }); } }