Files
opencode-obsidian/src/server/process/WindowsProcess.ts
2026-02-14 17:13:11 +01:00

85 lines
2.0 KiB
TypeScript

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<void> {
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<string | null> {
// 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<void> {
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<void> {
return new Promise((resolve, reject) => {
const { exec } = require("child_process");
exec(command, (error: Error | null) => {
if (error) {
reject(error);
} else {
resolve();
}
});
});
}
}