mirror of
https://github.com/sipeed/picoclaw.git
synced 2026-06-12 18:08:54 +00:00
fix(launcher): hide console flashes in all Windows child processes (#3061)
* fix(launcher): hide console flashes in all Windows child processes PR #2654 only applied HideWindow to child processes in gateway.go (powershell, tasklist, ps). Several other files still use exec.Command directly, causing visible console windows on Windows. - startup.go: reg query/add/delete for autostart registry - version.go: picoclaw version subcommand - runtime.go: rundll32 for browser launch - onboard.go: picoclaw onboard subcommand Add launcherExecCommand to the utils package (matching the api package pattern) and replace all bare exec.Command calls on Windows paths. * refactor: consolidate launcherExecCommand into utils package Export LauncherExecCommand and ApplyLauncherProcAttrs from the utils package as the single source of truth. The api package now imports and delegates to these exported functions, eliminating code duplication. Addresses review feedback from imguoguo on PR #3061.
This commit is contained in:
@@ -2,10 +2,16 @@
|
||||
|
||||
package api
|
||||
|
||||
import "os/exec"
|
||||
import (
|
||||
"os/exec"
|
||||
|
||||
"github.com/sipeed/picoclaw/web/backend/utils"
|
||||
)
|
||||
|
||||
func launcherExecCommand(name string, args ...string) *exec.Cmd {
|
||||
return exec.Command(name, args...)
|
||||
return utils.LauncherExecCommand(name, args...)
|
||||
}
|
||||
|
||||
func applyLauncherProcAttrs(_ *exec.Cmd) {}
|
||||
func applyLauncherProcAttrs(cmd *exec.Cmd) {
|
||||
utils.ApplyLauncherProcAttrs(cmd)
|
||||
}
|
||||
|
||||
@@ -4,21 +4,14 @@ package api
|
||||
|
||||
import (
|
||||
"os/exec"
|
||||
"syscall"
|
||||
|
||||
"github.com/sipeed/picoclaw/web/backend/utils"
|
||||
)
|
||||
|
||||
func launcherExecCommand(name string, args ...string) *exec.Cmd {
|
||||
cmd := exec.Command(name, args...)
|
||||
applyLauncherProcAttrs(cmd)
|
||||
return cmd
|
||||
return utils.LauncherExecCommand(name, args...)
|
||||
}
|
||||
|
||||
func applyLauncherProcAttrs(cmd *exec.Cmd) {
|
||||
if cmd == nil {
|
||||
return
|
||||
}
|
||||
if cmd.SysProcAttr == nil {
|
||||
cmd.SysProcAttr = &syscall.SysProcAttr{}
|
||||
}
|
||||
cmd.SysProcAttr.HideWindow = true
|
||||
utils.ApplyLauncherProcAttrs(cmd)
|
||||
}
|
||||
|
||||
@@ -277,7 +277,11 @@ func windowsCommandLine(exePath string, args []string) string {
|
||||
}
|
||||
|
||||
func windowsRunKeyExists() (bool, error) {
|
||||
cmd := exec.Command("reg", "query", `HKCU\Software\Microsoft\Windows\CurrentVersion\Run`, "/v", autoStartEntryName)
|
||||
cmd := launcherExecCommand(
|
||||
"reg", "query",
|
||||
`HKCU\Software\Microsoft\Windows\CurrentVersion\Run`,
|
||||
"/v", autoStartEntryName,
|
||||
)
|
||||
if err := cmd.Run(); err != nil {
|
||||
var exitErr *exec.ExitError
|
||||
if errors.As(err, &exitErr) {
|
||||
@@ -292,11 +296,15 @@ func setWindowsAutoStart(enabled bool, exePath string, args []string) error {
|
||||
key := `HKCU\Software\Microsoft\Windows\CurrentVersion\Run`
|
||||
if enabled {
|
||||
commandLine := windowsCommandLine(exePath, args)
|
||||
cmd := exec.Command("reg", "add", key, "/v", autoStartEntryName, "/t", "REG_SZ", "/d", commandLine, "/f")
|
||||
cmd := launcherExecCommand(
|
||||
"reg", "add", key,
|
||||
"/v", autoStartEntryName,
|
||||
"/t", "REG_SZ", "/d", commandLine, "/f",
|
||||
)
|
||||
return cmd.Run()
|
||||
}
|
||||
|
||||
cmd := exec.Command("reg", "delete", key, "/v", autoStartEntryName, "/f")
|
||||
cmd := launcherExecCommand("reg", "delete", key, "/v", autoStartEntryName, "/f")
|
||||
if err := cmd.Run(); err != nil {
|
||||
var exitErr *exec.ExitError
|
||||
if errors.As(err, &exitErr) {
|
||||
|
||||
@@ -259,7 +259,9 @@ func (c *systemVersionCache) resetForTest() {
|
||||
// executePicoclawVersion runs the version subcommand against the
|
||||
// discovered picoclaw executable.
|
||||
func executePicoclawVersion(ctx context.Context, execPath string) (string, error) {
|
||||
out, err := exec.CommandContext(ctx, execPath, "version").CombinedOutput()
|
||||
cmd := exec.CommandContext(ctx, execPath, "version")
|
||||
applyLauncherProcAttrs(cmd)
|
||||
out, err := cmd.CombinedOutput()
|
||||
if err == nil {
|
||||
return string(out), nil
|
||||
}
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
//go:build !windows
|
||||
|
||||
package utils
|
||||
|
||||
import "os/exec"
|
||||
|
||||
// LauncherExecCommand creates an exec.Cmd. On non-Windows platforms, this is
|
||||
// a simple wrapper around exec.Command.
|
||||
func LauncherExecCommand(name string, args ...string) *exec.Cmd {
|
||||
return exec.Command(name, args...)
|
||||
}
|
||||
|
||||
// ApplyLauncherProcAttrs is a no-op on non-Windows platforms.
|
||||
func ApplyLauncherProcAttrs(_ *exec.Cmd) {}
|
||||
@@ -0,0 +1,28 @@
|
||||
//go:build windows
|
||||
|
||||
package utils
|
||||
|
||||
import (
|
||||
"os/exec"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
// LauncherExecCommand creates an exec.Cmd with the HideWindow attribute set
|
||||
// to prevent console window flashes on Windows.
|
||||
func LauncherExecCommand(name string, args ...string) *exec.Cmd {
|
||||
cmd := exec.Command(name, args...)
|
||||
ApplyLauncherProcAttrs(cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
// ApplyLauncherProcAttrs applies Windows-specific process attributes to hide
|
||||
// the console window. It is safe to call with a nil cmd.
|
||||
func ApplyLauncherProcAttrs(cmd *exec.Cmd) {
|
||||
if cmd == nil {
|
||||
return
|
||||
}
|
||||
if cmd.SysProcAttr == nil {
|
||||
cmd.SysProcAttr = &syscall.SysProcAttr{}
|
||||
}
|
||||
cmd.SysProcAttr.HideWindow = true
|
||||
}
|
||||
@@ -3,13 +3,12 @@ package utils
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
|
||||
"github.com/sipeed/picoclaw/pkg/config"
|
||||
)
|
||||
|
||||
var execCommand = exec.Command
|
||||
var execCommand = LauncherExecCommand
|
||||
|
||||
func EnsureOnboarded(configPath string) error {
|
||||
_, err := os.Stat(configPath)
|
||||
|
||||
@@ -150,7 +150,7 @@ func OpenBrowser(url string) error {
|
||||
case "linux":
|
||||
return exec.Command("xdg-open", url).Start()
|
||||
case "windows":
|
||||
return exec.Command("rundll32", "url.dll,FileProtocolHandler", url).Start()
|
||||
return LauncherExecCommand("rundll32", "url.dll,FileProtocolHandler", url).Start()
|
||||
case "darwin":
|
||||
return exec.Command("open", url).Start()
|
||||
default:
|
||||
|
||||
Reference in New Issue
Block a user