diff --git a/CONTEXT.md b/CONTEXT.md index 5e5955d344a1..a1ae99e0e091 100644 --- a/CONTEXT.md +++ b/CONTEXT.md @@ -223,3 +223,29 @@ Before stabilizing the client API: ## Flagged ambiguities - Legacy `experimental.chat.system.transform` can mutate the assembled baseline system prompt arbitrarily, but V2 plugins do not yet expose an equivalent hook. Decide separately whether to port it, replace dynamic uses with plugin-defined **Context Sources**, or narrow its semantics. + +--- + +## Projekt-Metadaten (gepflegt von opencode) + +Letzte Änderung: 2026-07-12 + +### Verzeichnisstruktur + +| Pfad | Beschreibung | +|---|---| +| `packages/opencode/src/util/process.ts` | Process-Spawning/-Management inkl. `stop()` | +| `packages/opencode/src/lsp/` | LSP-Integration (client, server, launch) | +| `packages/opencode/src/mcp/` | MCP-Integration | + +### Befehle (aus `packages/opencode/`) + +```bash +bun typecheck # Typ-Prüfung +bun test # Tests (fehlgeschlagene) +bun dev # TUI starten +``` + +### Letzte Änderungen + +- **2026-07-12**: `Process.stop()` in `util/process.ts` gefixt – SIGTERM → 5s Timeout → SIGKILL-Eskalation (bisher nur SIGTERM ohne Fallback). Gleicher Fix in SDK-Kopie `packages/sdk/js/src/process.ts`. diff --git a/packages/opencode/src/util/process.ts b/packages/opencode/src/util/process.ts index 173210f23c95..ec81b9826fdb 100644 --- a/packages/opencode/src/util/process.ts +++ b/packages/opencode/src/util/process.ts @@ -146,20 +146,38 @@ export async function run(cmd: string[], opts: RunOptions = {}): Promise // Duplicated in `packages/sdk/js/src/process.ts` because the SDK cannot import // `opencode` without creating a cycle. Keep both copies in sync. +async function waitForExit(proc: ChildProcess): Promise { + if (proc.exitCode !== null || proc.signalCode !== null) return + await new Promise((resolve) => { + proc.once("exit", () => resolve()) + proc.once("error", () => resolve()) + }) +} + export async function stop(proc: ChildProcess) { if (proc.exitCode !== null || proc.signalCode !== null) return - if (process.platform !== "win32" || !proc.pid) { - proc.kill() - return + if (process.platform === "win32" && proc.pid) { + const out = await run(["taskkill", "/pid", String(proc.pid), "/T", "/F"], { + nothrow: true, + }) + if (out.code === 0) return } - const out = await run(["taskkill", "/pid", String(proc.pid), "/T", "/F"], { - nothrow: true, - }) + proc.kill("SIGTERM") + if (proc.exitCode !== null || proc.signalCode !== null) return - if (out.code === 0) return - proc.kill() + const timeout = 5_000 + const exited = waitForExit(proc) + const timer = new Promise((resolve) => { + setTimeout(() => { + try { + proc.kill("SIGKILL") + } catch {} + resolve() + }, timeout) + }) + await Promise.race([exited, timer]) } export async function text(cmd: string[], opts: RunOptions = {}): Promise { diff --git a/packages/sdk/js/src/process.ts b/packages/sdk/js/src/process.ts index 3111b424aa18..1dd8df0c3163 100644 --- a/packages/sdk/js/src/process.ts +++ b/packages/sdk/js/src/process.ts @@ -8,7 +8,7 @@ export function stop(proc: ChildProcess) { const out = spawnSync("taskkill", ["/pid", String(proc.pid), "/T", "/F"], { windowsHide: true }) if (!out.error && out.status === 0) return } - proc.kill() + proc.kill("SIGTERM") } export function bindAbort(proc: ChildProcess, signal?: AbortSignal, onAbort?: () => void) {