mirror of
https://gitea.toothfairyai.com/ToothFairyAI/tf_code.git
synced 2026-03-31 06:12:26 +00:00
71 lines
2.1 KiB
TypeScript
71 lines
2.1 KiB
TypeScript
import { Flag } from "@/flag/flag"
|
|
import { lazy } from "@/util/lazy"
|
|
import { Filesystem } from "@/util/filesystem"
|
|
import { which } from "@/util/which"
|
|
import path from "path"
|
|
import { spawn, type ChildProcess } from "child_process"
|
|
import { setTimeout as sleep } from "node:timers/promises"
|
|
|
|
const SIGKILL_TIMEOUT_MS = 200
|
|
|
|
export namespace Shell {
|
|
export async function killTree(proc: ChildProcess, opts?: { exited?: () => boolean }): Promise<void> {
|
|
const pid = proc.pid
|
|
if (!pid || opts?.exited?.()) return
|
|
|
|
if (process.platform === "win32") {
|
|
await new Promise<void>((resolve) => {
|
|
const killer = spawn("taskkill", ["/pid", String(pid), "/f", "/t"], { stdio: "ignore" })
|
|
killer.once("exit", () => resolve())
|
|
killer.once("error", () => resolve())
|
|
})
|
|
return
|
|
}
|
|
|
|
try {
|
|
process.kill(-pid, "SIGTERM")
|
|
await sleep(SIGKILL_TIMEOUT_MS)
|
|
if (!opts?.exited?.()) {
|
|
process.kill(-pid, "SIGKILL")
|
|
}
|
|
} catch (_e) {
|
|
proc.kill("SIGTERM")
|
|
await sleep(SIGKILL_TIMEOUT_MS)
|
|
if (!opts?.exited?.()) {
|
|
proc.kill("SIGKILL")
|
|
}
|
|
}
|
|
}
|
|
const BLACKLIST = new Set(["fish", "nu"])
|
|
|
|
function fallback() {
|
|
if (process.platform === "win32") {
|
|
if (Flag.OPENCODE_GIT_BASH_PATH) return Flag.OPENCODE_GIT_BASH_PATH
|
|
const git = which("git")
|
|
if (git) {
|
|
// git.exe is typically at: C:\Program Files\Git\cmd\git.exe
|
|
// bash.exe is at: C:\Program Files\Git\bin\bash.exe
|
|
const bash = path.join(git, "..", "..", "bin", "bash.exe")
|
|
if (Filesystem.stat(bash)?.size) return bash
|
|
}
|
|
return process.env.COMSPEC || "cmd.exe"
|
|
}
|
|
if (process.platform === "darwin") return "/bin/zsh"
|
|
const bash = which("bash")
|
|
if (bash) return bash
|
|
return "/bin/sh"
|
|
}
|
|
|
|
export const preferred = lazy(() => {
|
|
const s = process.env.SHELL
|
|
if (s) return s
|
|
return fallback()
|
|
})
|
|
|
|
export const acceptable = lazy(() => {
|
|
const s = process.env.SHELL
|
|
if (s && !BLACKLIST.has(process.platform === "win32" ? path.win32.basename(s) : path.basename(s))) return s
|
|
return fallback()
|
|
})
|
|
}
|