mirror of
https://github.com/multica-ai/multica.git
synced 2026-07-27 21:33:41 +02:00
* fix(agent/codex): diagnose thread start timeouts (KAP-1051) Co-authored-by: multica-agent <github@multica.ai> * fix(agent/codex): validate thread ID before success lifecycle Co-authored-by: multica-agent <github@multica.ai> * fix(agent/codex): confirm process tree cleanup Co-authored-by: multica-agent <github@multica.ai> * fix(agent/codex): bound Windows pipe cleanup Co-authored-by: multica-agent <github@multica.ai> * ci: run bounded Codex cleanup test on Windows Co-authored-by: multica-agent <github@multica.ai> * fix(agent): reap initialize timeout process groups * fix(agent): redact initialize timeout stderr * fix(agent): redact initialize context failures --------- Co-authored-by: multica-agent <github@multica.ai>
57 lines
2.2 KiB
Go
57 lines
2.2 KiB
Go
//go:build windows
|
|
|
|
package agent
|
|
|
|
import (
|
|
"os"
|
|
"os/exec"
|
|
"syscall"
|
|
"time"
|
|
)
|
|
|
|
// createNewConsole allocates a fresh console for the child process. Combined
|
|
// with HideWindow=true (STARTF_USESHOWWINDOW + SW_HIDE) the console window
|
|
// stays off-screen, and — critically — any grandchildren the agent spawns
|
|
// (tool subprocesses like bash, cmd, netstat, findstr) inherit this hidden
|
|
// console instead of each allocating their own visible one.
|
|
//
|
|
// Using CREATE_NO_WINDOW here instead would strip the console entirely,
|
|
// which forces Windows to allocate a new visible console per grandchild
|
|
// when the grandchild is a console-subsystem program that doesn't itself
|
|
// pass CREATE_NO_WINDOW — the exact popup storm reported in #1521.
|
|
const createNewConsole = 0x00000010
|
|
|
|
// hideAgentWindow configures cmd to suppress the console window on Windows
|
|
// while still giving descendant processes a hidden console to inherit.
|
|
// Stdio pipes set via cmd.StdoutPipe/StdinPipe keep working because
|
|
// STARTF_USESTDHANDLES takes precedence over the new console's stdio.
|
|
func hideAgentWindow(cmd *exec.Cmd) {
|
|
if cmd.SysProcAttr == nil {
|
|
cmd.SysProcAttr = &syscall.SysProcAttr{}
|
|
}
|
|
cmd.SysProcAttr.HideWindow = true
|
|
cmd.SysProcAttr.CreationFlags |= createNewConsole
|
|
}
|
|
|
|
// configureProcessGroup is a no-op on Windows: there is no Setpgid/process-group
|
|
// signalling. Descendant cleanup relies on the hidden console group set up by
|
|
// hideAgentWindow plus exec.CommandContext / WaitDelay terminating the child.
|
|
func configureProcessGroup(cmd *exec.Cmd) {}
|
|
|
|
// codexInitializeRetrySupported remains false until Codex children are owned
|
|
// by a Job Object and descendant termination can be positively confirmed.
|
|
func codexInitializeRetrySupported() bool { return false }
|
|
|
|
// signalProcessGroup terminates the process on Windows. Windows has no
|
|
// SIGTERM/SIGKILL distinction or process-group signalling, so the signal is
|
|
// ignored and the process is killed directly (TerminateProcess via Kill). The
|
|
// caller's grace window still applies before this is invoked with SIGKILL.
|
|
func signalProcessGroup(p *os.Process, _ syscall.Signal) {
|
|
if p == nil {
|
|
return
|
|
}
|
|
_ = p.Kill()
|
|
}
|
|
|
|
func waitProcessGroupGone(_ *os.Process, _ time.Duration) bool { return false }
|