From e1863234f0370a2b6325e203ed83910dbb754112 Mon Sep 17 00:00:00 2001 From: SiYue <2835601846@qq.com> Date: Fri, 24 Apr 2026 16:50:19 +0800 Subject: [PATCH] fix(launcher): hide windows child-process console flashes - hide windows when launching gateway process from launcher - hide windows for powershell/tasklist process inspection commands --- web/backend/api/exec_nonwindows.go | 11 +++++++++++ web/backend/api/exec_windows.go | 24 ++++++++++++++++++++++++ web/backend/api/gateway.go | 9 +++++---- 3 files changed, 40 insertions(+), 4 deletions(-) create mode 100644 web/backend/api/exec_nonwindows.go create mode 100644 web/backend/api/exec_windows.go diff --git a/web/backend/api/exec_nonwindows.go b/web/backend/api/exec_nonwindows.go new file mode 100644 index 000000000..a68a3bfd7 --- /dev/null +++ b/web/backend/api/exec_nonwindows.go @@ -0,0 +1,11 @@ +//go:build !windows + +package api + +import "os/exec" + +func launcherExecCommand(name string, args ...string) *exec.Cmd { + return exec.Command(name, args...) +} + +func applyLauncherWindowsProcAttrs(_ *exec.Cmd) {} diff --git a/web/backend/api/exec_windows.go b/web/backend/api/exec_windows.go new file mode 100644 index 000000000..1e76f8c73 --- /dev/null +++ b/web/backend/api/exec_windows.go @@ -0,0 +1,24 @@ +//go:build windows + +package api + +import ( + "os/exec" + "syscall" +) + +func launcherExecCommand(name string, args ...string) *exec.Cmd { + cmd := exec.Command(name, args...) + applyLauncherWindowsProcAttrs(cmd) + return cmd +} + +func applyLauncherWindowsProcAttrs(cmd *exec.Cmd) { + if cmd == nil { + return + } + if cmd.SysProcAttr == nil { + cmd.SysProcAttr = &syscall.SysProcAttr{} + } + cmd.SysProcAttr.HideWindow = true +} diff --git a/web/backend/api/gateway.go b/web/backend/api/gateway.go index 201000ff3..d3e5ae1d5 100644 --- a/web/backend/api/gateway.go +++ b/web/backend/api/gateway.go @@ -164,7 +164,7 @@ func isLikelyGatewayProcess(pid int) (bool, bool) { `$p=Get-CimInstance Win32_Process -Filter "ProcessId = %d"; if ($null -eq $p) { "" } else { $p.CommandLine }`, pid, ) - out, err := exec.Command("powershell", "-NoProfile", "-NonInteractive", "-Command", psCmd).Output() + out, err := launcherExecCommand("powershell", "-NoProfile", "-NonInteractive", "-Command", psCmd).Output() if err == nil { cmdline := strings.TrimSpace(string(out)) if cmdline != "" { @@ -173,7 +173,7 @@ func isLikelyGatewayProcess(pid int) (bool, bool) { } // Fallback: determine only whether the process still exists. - out, err = exec.Command("tasklist", "/FI", "PID eq "+strconv.Itoa(pid), "/FO", "CSV", "/NH").Output() + out, err = launcherExecCommand("tasklist", "/FI", "PID eq "+strconv.Itoa(pid), "/FO", "CSV", "/NH").Output() if err != nil { return false, false } @@ -187,7 +187,7 @@ func isLikelyGatewayProcess(pid int) (bool, bool) { if strings.Contains(line, "\"picoclaw.exe\"") { return true, true } - return false, false + return false, true } if strings.Contains(line, "no tasks are running") { return false, true @@ -195,7 +195,7 @@ func isLikelyGatewayProcess(pid int) (bool, bool) { return false, true } - out, err := exec.Command("ps", "-o", "command=", "-p", strconv.Itoa(pid)).Output() + out, err := launcherExecCommand("ps", "-o", "command=", "-p", strconv.Itoa(pid)).Output() if err != nil { return false, false } @@ -706,6 +706,7 @@ func (h *Handler) startGatewayLocked(initialStatus string, existingPid int) (int logger.InfoC("gateway", fmt.Sprintf("Starting gateway process (%s)", execPath)) cmd = gatewayExecCommand(execPath, h.gatewayCommandArgs()...) + applyLauncherWindowsProcAttrs(cmd) cmd.Env = os.Environ() // Forward the launcher's config path via the environment variable that // GetConfigPath() already reads, so the gateway sub-process uses the same