fix windows desktop terminal popups (#1199)
This commit is contained in:
@@ -231,9 +231,6 @@ export async function startWebUiServer(port = DEFAULT_PORT): Promise<string> {
|
||||
const bundledPython = isWin
|
||||
? join(pythonDir(), 'python.exe')
|
||||
: join(pythonDir(), 'bin', 'python3')
|
||||
const bundledPythonNoWindow = isWin
|
||||
? join(pythonDir(), 'pythonw.exe')
|
||||
: bundledPython
|
||||
const bridgePort = await getFreeTcpPort()
|
||||
const workerPortBase = await getFreeTcpPortInRange(20000, 59000)
|
||||
const loginShellPath = await getLoginShellPath()
|
||||
@@ -257,7 +254,7 @@ export async function startWebUiServer(port = DEFAULT_PORT): Promise<string> {
|
||||
// ready handshakes. Use python.exe on Windows and hide windows at the
|
||||
// process creation layer instead of switching the bridge to pythonw.exe.
|
||||
HERMES_AGENT_BRIDGE_PYTHON: bundledPython,
|
||||
HERMES_AGENT_CLI_PYTHON: existsSync(bundledPythonNoWindow) ? bundledPythonNoWindow : bundledPython,
|
||||
HERMES_AGENT_CLI_PYTHON: bundledPython,
|
||||
HERMES_AGENT_ROOT: pythonDir(),
|
||||
// Force TCP loopback for the agent bridge. The default `ipc:///tmp/...`
|
||||
// unix socket is rejected on macOS in some EDR/sandbox setups (silent
|
||||
|
||||
@@ -10,6 +10,7 @@ delimited JSON request/response protocol over a local socket.
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import asyncio
|
||||
import atexit
|
||||
import copy
|
||||
import errno
|
||||
@@ -71,6 +72,14 @@ def _hidden_subprocess_kwargs() -> dict[str, int]:
|
||||
return {"creationflags": getattr(subprocess, "CREATE_NO_WINDOW", 0)}
|
||||
|
||||
|
||||
def _add_hidden_creationflags(kwargs: dict[str, Any], create_no_window: int) -> None:
|
||||
flags = kwargs.get("creationflags", 0) or 0
|
||||
try:
|
||||
kwargs["creationflags"] = int(flags) | create_no_window
|
||||
except Exception:
|
||||
kwargs["creationflags"] = create_no_window
|
||||
|
||||
|
||||
def _install_windows_hidden_subprocess_defaults() -> None:
|
||||
"""Hide console windows for subprocesses launched inside desktop bridge runs.
|
||||
|
||||
@@ -87,18 +96,26 @@ def _install_windows_hidden_subprocess_defaults() -> None:
|
||||
return
|
||||
|
||||
original_popen = subprocess.Popen
|
||||
original_create_subprocess_exec = asyncio.create_subprocess_exec
|
||||
original_create_subprocess_shell = asyncio.create_subprocess_shell
|
||||
create_no_window = getattr(subprocess, "CREATE_NO_WINDOW", 0) or 0x08000000
|
||||
|
||||
class HiddenPopen(original_popen): # type: ignore[misc, valid-type]
|
||||
def __init__(self, *args: Any, **kwargs: Any) -> None:
|
||||
flags = kwargs.get("creationflags", 0) or 0
|
||||
try:
|
||||
kwargs["creationflags"] = int(flags) | create_no_window
|
||||
except Exception:
|
||||
kwargs["creationflags"] = create_no_window
|
||||
_add_hidden_creationflags(kwargs, create_no_window)
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
async def hidden_create_subprocess_exec(*args: Any, **kwargs: Any) -> Any:
|
||||
_add_hidden_creationflags(kwargs, create_no_window)
|
||||
return await original_create_subprocess_exec(*args, **kwargs)
|
||||
|
||||
async def hidden_create_subprocess_shell(*args: Any, **kwargs: Any) -> Any:
|
||||
_add_hidden_creationflags(kwargs, create_no_window)
|
||||
return await original_create_subprocess_shell(*args, **kwargs)
|
||||
|
||||
subprocess.Popen = HiddenPopen # type: ignore[assignment]
|
||||
asyncio.create_subprocess_exec = hidden_create_subprocess_exec # type: ignore[assignment]
|
||||
asyncio.create_subprocess_shell = hidden_create_subprocess_shell # type: ignore[assignment]
|
||||
subprocess._hermes_hidden_defaults_installed = True # type: ignore[attr-defined]
|
||||
|
||||
|
||||
|
||||
@@ -22,12 +22,15 @@ function bundledCliPythonForWindows(hermesBin: string): string | null {
|
||||
if (envPython) return envPython
|
||||
|
||||
if (basename(hermesBin).toLowerCase() !== 'hermes.exe') return null
|
||||
const pythonw = resolve(dirname(hermesBin), '..', 'pythonw.exe')
|
||||
if (existsSync(pythonw)) return pythonw
|
||||
const python = resolve(dirname(hermesBin), '..', 'python.exe')
|
||||
return existsSync(python) ? python : null
|
||||
}
|
||||
|
||||
function withWindowsHide<T extends ExecFileOptions | SpawnOptions>(options?: T): T {
|
||||
if (process.platform !== 'win32') return (options || {}) as T
|
||||
return { windowsHide: true, ...(options || {}) } as T
|
||||
}
|
||||
|
||||
export function resolveHermesInvocation(hermesBin = resolveHermesBin()): HermesInvocation {
|
||||
if (process.platform === 'win32') {
|
||||
const python = bundledCliPythonForWindows(hermesBin)
|
||||
@@ -47,7 +50,7 @@ export function execHermesWithBin(
|
||||
execFile(
|
||||
invocation.command,
|
||||
[...invocation.argsPrefix, ...args],
|
||||
{ ...options, encoding: 'utf8' },
|
||||
{ ...withWindowsHide(options), encoding: 'utf8' },
|
||||
(error, stdout, stderr) => {
|
||||
if (error) {
|
||||
rejectExec(Object.assign(error, { stdout, stderr }))
|
||||
@@ -69,7 +72,7 @@ export function spawnHermesWithBin(
|
||||
options?: SpawnOptions,
|
||||
): ChildProcess {
|
||||
const invocation = resolveHermesInvocation(hermesBin)
|
||||
return spawn(invocation.command, [...invocation.argsPrefix, ...args], options || {})
|
||||
return spawn(invocation.command, [...invocation.argsPrefix, ...args], withWindowsHide(options))
|
||||
}
|
||||
|
||||
export function spawnHermes(args: readonly string[], options?: SpawnOptions): ChildProcess {
|
||||
|
||||
Reference in New Issue
Block a user