Files
zero/internal/tools/bash_proc_windows.go
anandh8x fcc6c72c34 fix(windows): prefer PowerShell for command execution
Detect PowerShell 7 or Windows PowerShell before falling back to cmd.exe, and share the selected host shell across agent tools and the interactive shell escape.

Configure UTF-8 output, preserve restricted-sandbox MSYS safeguards, and add Windows coverage for pipelines, workspace writes, and interactive stdin sessions.
2026-07-24 19:35:42 +05:30

44 lines
1.5 KiB
Go

//go:build windows
package tools
import (
"os/exec"
"syscall"
"time"
"github.com/Gitlawb/zero/internal/execution"
zeroSandbox "github.com/Gitlawb/zero/internal/sandbox"
)
// bashWaitDelay bounds how long Wait blocks for the I/O pipes to drain after the
// process has exited or the context's Cancel has run, so a backgrounded child
// holding the pipes cannot make Run() hang past the timeout. Var (not const) so
// tests can shorten it.
var bashWaitDelay = 2 * time.Second
// hardenProcessLifetime makes a Windows shell command killable as a process
// tree. cmd.exe starts helper commands as child processes, so killing only the
// shell can leave a long-running child alive and holding cwd/temp handles after
// Zero exits.
func hardenProcessLifetime(command *exec.Cmd) {
command.WaitDelay = bashWaitDelay
command.Cancel = func() error {
if command.Process == nil {
return nil
}
return execution.KillProcessTree(command.Process.Pid)
}
}
// applyWindowsShellCommandLine overrides the cmd.exe fallback's raw child
// command line so commandText reaches cmd.exe unescaped. PowerShell consumes
// ordinary argv quoting and must not take this path. Wrapped commands are
// handled after unwrapping by the Windows sandbox runner.
func applyWindowsShellCommandLine(command *exec.Cmd, commandText string, wrapped bool, cmdFallback bool) {
if wrapped || !cmdFallback {
return
}
command.SysProcAttr = &syscall.SysProcAttr{CmdLine: zeroSandbox.WindowsShellCommandLine(commandText)}
}