mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-24 16:54:43 +00:00
fix(windows): hide console flashes in GUI-reachable exec paths and provider transports (#56747)
Six spawn sites reachable from the desktop GUI / TUI gateway lacked CREATE_NO_WINDOW, so a windowless parent (pythonw/Electron) flashed a conhost per spawn: cli.exec RPC, quick-commands exec dispatch, and shell.exec RPC in tui_gateway/server.py; the CLI REPL quick-commands exec in cli.py; and the per-session provider transports in agent/copilot_acp_client.py and agent/transports/codex_app_server.py (Popen, hide-only so PIPE stdio stays intact). All use hermes_cli._subprocess_compat.windows_hide_flags() (no-op on POSIX), matching the pattern already used at three other sites in tui_gateway/server.py. Deliberately hide-only — no detach flags, no Electron changes (per the #54220 revert history). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
1c58fe4362
commit
714d7cc1a4
4 changed files with 25 additions and 1 deletions
|
|
@ -503,6 +503,10 @@ class CopilotACPClient:
|
|||
|
||||
def _run_prompt(self, prompt_text: str, *, timeout_seconds: float) -> tuple[str, str]:
|
||||
try:
|
||||
# Hide the console the CLI child would otherwise flash on Windows
|
||||
# (#56747). Hide-only — stdio pipes stay intact for the ACP wire.
|
||||
from hermes_cli._subprocess_compat import windows_hide_flags
|
||||
|
||||
proc = subprocess.Popen(
|
||||
[self._acp_command] + self._acp_args,
|
||||
stdin=subprocess.PIPE,
|
||||
|
|
@ -512,6 +516,7 @@ class CopilotACPClient:
|
|||
bufsize=1,
|
||||
cwd=self._acp_cwd,
|
||||
env=_build_subprocess_env(),
|
||||
creationflags=windows_hide_flags(),
|
||||
)
|
||||
except FileNotFoundError as exc:
|
||||
raise RuntimeError(
|
||||
|
|
|
|||
|
|
@ -127,6 +127,10 @@ class CodexAppServerClient:
|
|||
# Codex emits tracing to stderr; default WARN keeps it quiet for users.
|
||||
spawn_env.setdefault("RUST_LOG", "warn")
|
||||
|
||||
# Hide the console the codex child would otherwise flash on Windows
|
||||
# (#56747). Hide-only — stdio pipes stay intact for the app-server wire.
|
||||
from hermes_cli._subprocess_compat import windows_hide_flags
|
||||
|
||||
self._proc = subprocess.Popen(
|
||||
cmd,
|
||||
stdin=subprocess.PIPE,
|
||||
|
|
@ -134,6 +138,7 @@ class CodexAppServerClient:
|
|||
stderr=subprocess.PIPE,
|
||||
bufsize=0,
|
||||
env=spawn_env,
|
||||
creationflags=windows_hide_flags(),
|
||||
)
|
||||
self._next_id = 1
|
||||
self._pending: dict[int, _Pending] = {}
|
||||
|
|
|
|||
5
cli.py
5
cli.py
|
|
@ -9481,9 +9481,12 @@ class HermesCLI(CLIAgentSetupMixin, CLICommandsMixin, CLIBillingMixin):
|
|||
# has all API keys in os.environ.
|
||||
from tools.environments.local import _sanitize_subprocess_env
|
||||
sanitized_env = _sanitize_subprocess_env(os.environ.copy())
|
||||
from hermes_cli._subprocess_compat import windows_hide_flags
|
||||
result = subprocess.run(
|
||||
exec_cmd, shell=True, capture_output=True,
|
||||
text=True, timeout=30, env=sanitized_env
|
||||
text=True, timeout=30, env=sanitized_env,
|
||||
# No console flash on Windows (#56747).
|
||||
creationflags=windows_hide_flags(),
|
||||
)
|
||||
output = result.stdout.strip() or result.stderr.strip()
|
||||
if output:
|
||||
|
|
|
|||
|
|
@ -13841,6 +13841,10 @@ def _(rid, params: dict) -> dict:
|
|||
if hint:
|
||||
return _ok(rid, {"blocked": True, "hint": hint, "code": -1, "output": ""})
|
||||
try:
|
||||
# CREATE_NO_WINDOW on Windows — under the desktop GUI's windowless
|
||||
# parent, this spawn otherwise flashes a console (#56747).
|
||||
from hermes_cli._subprocess_compat import windows_hide_flags
|
||||
|
||||
r = subprocess.run(
|
||||
[sys.executable, "-m", "hermes_cli.main", *argv],
|
||||
capture_output=True,
|
||||
|
|
@ -13851,6 +13855,7 @@ def _(rid, params: dict) -> dict:
|
|||
# needs provider credentials. Tier-1 secrets still stripped (#29157).
|
||||
env=hermes_subprocess_env(inherit_credentials=True),
|
||||
stdin=subprocess.DEVNULL,
|
||||
creationflags=windows_hide_flags(),
|
||||
)
|
||||
parts = [r.stdout or "", r.stderr or ""]
|
||||
out = "\n".join(p for p in parts if p).strip() or "(no output)"
|
||||
|
|
@ -13910,6 +13915,8 @@ def _(rid, params: dict) -> dict:
|
|||
# has all API keys in os.environ.
|
||||
from tools.environments.local import _sanitize_subprocess_env
|
||||
sanitized_env = _sanitize_subprocess_env(os.environ.copy())
|
||||
from hermes_cli._subprocess_compat import windows_hide_flags
|
||||
|
||||
r = subprocess.run(
|
||||
qc.get("command", ""),
|
||||
shell=True,
|
||||
|
|
@ -13918,6 +13925,7 @@ def _(rid, params: dict) -> dict:
|
|||
timeout=30,
|
||||
stdin=subprocess.DEVNULL,
|
||||
env=sanitized_env,
|
||||
creationflags=windows_hide_flags(),
|
||||
)
|
||||
output = (
|
||||
(r.stdout or "")
|
||||
|
|
@ -16984,9 +16992,12 @@ def _(rid, params: dict) -> dict:
|
|||
except ImportError:
|
||||
return _err(rid, 5001, "shell.exec unavailable: approval safety module not importable")
|
||||
try:
|
||||
from hermes_cli._subprocess_compat import windows_hide_flags
|
||||
|
||||
r = subprocess.run(
|
||||
cmd, shell=True, capture_output=True, text=True, timeout=30, cwd=os.getcwd(),
|
||||
stdin=subprocess.DEVNULL,
|
||||
creationflags=windows_hide_flags(),
|
||||
)
|
||||
return _ok(
|
||||
rid,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue