fix(desktop): stop console-window flashing on Windows (#399)

On Windows the daemon shells out to console-subsystem processes without
suppressing the console window. The reaper polls session liveness on a
timer (and the attach loop retries), each call runs a zellij command, and
every invocation pops a console window that instantly closes, so the user
sees rapid blinking.

- Add a platform-split hideWindow(cmd) helper to the zellij package
  (CREATE_NO_WINDOW + HideWindow on Windows, no-op elsewhere) and call it
  in execRunner.Run so list-sessions and friends stop flashing.
- startBackgroundProcess now uses CREATE_NO_WINDOW instead of
  CREATE_NEW_CONSOLE (the latter creates a console then hides it, flashing).
- Pass windowsHide: true to the daemon spawn in main.ts so the daemon's own
  console stays hidden on a Windows GUI launch.

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Harshit Singh Bhandari 2026-06-23 17:49:04 +05:30 committed by GitHub
parent afe0817765
commit 47e3dddff5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 22 additions and 2 deletions

View File

@ -2,7 +2,13 @@
package zellij
import "errors"
import (
"errors"
"os/exec"
)
// hideWindow is a no-op off Windows: only Windows pops a console window.
func hideWindow(*exec.Cmd) {}
// startBackgroundProcess is a stub: the fire-and-forget path is only used by
// the Windows zellij codepath. Non-Windows builds create sessions

View File

@ -10,12 +10,23 @@ import (
"golang.org/x/sys/windows"
)
// hideWindow suppresses the console window for a console-subsystem child so
// frequent zellij calls (e.g. the reaper's list-sessions) don't flash on Windows.
func hideWindow(cmd *exec.Cmd) {
cmd.SysProcAttr = &syscall.SysProcAttr{
HideWindow: true,
CreationFlags: windows.CREATE_NO_WINDOW,
}
}
func startBackgroundProcess(env []string, name string, args ...string) error {
script := "Start-Process -FilePath " + psQuote(name) + " -ArgumentList " + psQuote(windowsCommandLine(args)) + " -WindowStyle Hidden"
cmd := exec.Command("powershell.exe", "-NoLogo", "-NoProfile", "-EncodedCommand", powerShellEncodedCommand(script))
cmd.Env = env
cmd.SysProcAttr = &syscall.SysProcAttr{
CreationFlags: windows.CREATE_NEW_CONSOLE,
// CREATE_NO_WINDOW, not CREATE_NEW_CONSOLE: the latter creates a console
// then hides it, which flashed a window.
CreationFlags: windows.CREATE_NO_WINDOW,
HideWindow: true,
}
if err := cmd.Start(); err != nil {

View File

@ -93,6 +93,7 @@ type execRunner struct{}
func (execRunner) Run(ctx context.Context, env []string, name string, args ...string) ([]byte, error) {
cmd := exec.CommandContext(ctx, name, args...)
cmd.Env = zellijCommandEnv(os.Environ(), env)
hideWindow(cmd)
return cmd.CombinedOutput()
}

View File

@ -506,6 +506,8 @@ async function startDaemonInner(startEpoch: number): Promise<DaemonStatus> {
env: daemonEnv(),
shell: launch.shell,
detached: true,
// Hide the daemon's console on a Windows GUI launch (no flashing terminal).
windowsHide: true,
});
daemonProcess = child;