diff --git a/packages/kilo-jetbrains/backend/src/main/kotlin/ai/kilocode/backend/cli/KiloBackendCliManager.kt b/packages/kilo-jetbrains/backend/src/main/kotlin/ai/kilocode/backend/cli/KiloBackendCliManager.kt index abecec7e738..0d3e218470a 100644 --- a/packages/kilo-jetbrains/backend/src/main/kotlin/ai/kilocode/backend/cli/KiloBackendCliManager.kt +++ b/packages/kilo-jetbrains/backend/src/main/kotlin/ai/kilocode/backend/cli/KiloBackendCliManager.kt @@ -275,20 +275,30 @@ internal fun killCliProcessTree( .onFailure { log.warn("killProcessTree failed for pid ${proc.pid()}", it) } .getOrDefault(false) if (ok) return - proc.toHandle().descendants().toList().asReversed().forEach { it.destroyForcibly() } + descendants(proc).forEach { it.destroyForcibly() } proc.destroyForcibly() return } - proc.toHandle().descendants().toList().asReversed().forEach { it.destroy() } + val kids = descendants(proc) + kids.forEach { it.destroy() } proc.destroy() if (!wait) return if (!proc.waitFor(timeoutSeconds, TimeUnit.SECONDS)) { log.warn("CLI process did not exit after SIGTERM, sending SIGKILL") - proc.toHandle().descendants().toList().asReversed().forEach { it.destroyForcibly() } + kids.forEach { it.destroyForcibly() } proc.destroyForcibly() + return + } + val alive = kids.filter { it.isAlive } + if (alive.isNotEmpty()) { + log.warn("CLI child processes did not exit after SIGTERM, sending SIGKILL") + alive.forEach { it.destroyForcibly() } } } +private fun descendants(proc: Process): List = + proc.toHandle().descendants().toList().asReversed() + internal fun startupDiagnostics(cli: File, env: Map, log: KiloLog): String { val home = System.getProperty("user.home").orEmpty() val profile = EnvironmentUtil.getValue("USERPROFILE").orEmpty()