fix(windows): чёрные окна консоли выскакивали каждую минуту
Хаб — оконное приложение без консоли, поэтому каждый запуск консольного exe открывал отдельное окно. Пока проверка аккаунтов шла по нажатию, это было незаметно. A50 сделал проверку автоматической раз в минуту, и окна agy.exe стали появляться постоянно, мешая работе. Добавлен hidden_process_kwargs(): CREATE_NO_WINDOW плюс STARTUPINFO с SW_HIDE, на не-Windows пусто. Применён ко всем ФОНОВЫМ вызовам: опрос моделей agy, выполнение запроса agy, чтение ключей, codex_oauth, launcher_bootstrap, git rev-parse и проверка версии в обновлении. Вызовы, где окно нужно видимым, не тронуты: вход по OAuth сознательно использует CREATE_NEW_CONSOLE, запуск установщика тоже должен быть виден. 574 passed, ruff clean. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
d17360bc2f
commit
f0d06e4994
5 changed files with 32 additions and 1 deletions
|
|
@ -162,6 +162,7 @@ def discover_models(profile_id: str | None = None) -> dict[str, str]:
|
|||
errors="replace",
|
||||
env=env,
|
||||
stdin=subprocess.DEVNULL,
|
||||
**hidden_process_kwargs(),
|
||||
)
|
||||
raw = result.stdout.strip()
|
||||
if not raw or result.returncode != 0:
|
||||
|
|
@ -618,6 +619,26 @@ BLOCKED_SECRET_PATTERNS: tuple[str, ...] = (
|
|||
)
|
||||
|
||||
|
||||
def hidden_process_kwargs() -> dict:
|
||||
"""Флаги запуска подпроцесса без видимого окна консоли (только Windows).
|
||||
|
||||
Хаб — оконное приложение без консоли, поэтому каждый запуск консольного
|
||||
exe (agy.exe и прочие) открывал отдельное чёрное окно. Пока проверка шла
|
||||
по нажатию, это было незаметно. После A50 проверка аккаунтов запускается
|
||||
сама раз в минуту, и окна стали появляться постоянно, мешая работе.
|
||||
|
||||
Применять ко всем ФОНОВЫМ вызовам. Для входа по OAuth окно нужно
|
||||
видимым — там сознательно используется CREATE_NEW_CONSOLE.
|
||||
"""
|
||||
if os.name != "nt":
|
||||
return {}
|
||||
flags = getattr(subprocess, "CREATE_NO_WINDOW", 0x08000000)
|
||||
startupinfo = subprocess.STARTUPINFO()
|
||||
startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
|
||||
startupinfo.wShowWindow = subprocess.SW_HIDE
|
||||
return {"creationflags": flags, "startupinfo": startupinfo}
|
||||
|
||||
|
||||
def build_safe_subprocess_env(
|
||||
base_env: dict[str, str] | None = None,
|
||||
allow_extra_keys: set[str] | list[str] | None = None,
|
||||
|
|
@ -748,6 +769,7 @@ def agy_generate(
|
|||
encoding="utf-8",
|
||||
errors="replace",
|
||||
env=custom_env if custom_env is not None else build_safe_subprocess_env(),
|
||||
**hidden_process_kwargs(),
|
||||
)
|
||||
except subprocess.TimeoutExpired:
|
||||
return _error_completion(model_raw, "agy subprocess timed out")
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import tempfile
|
|||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
from typing import Any, Callable
|
||||
from antigravity_provider.agy_subprocess import hidden_process_kwargs
|
||||
|
||||
|
||||
def _hermes_home() -> Path:
|
||||
|
|
@ -94,6 +95,7 @@ def load_agy_keychain_credentials(*, runner: Callable[[], str] | None = None) ->
|
|||
["security", "find-generic-password", "-a", "antigravity", "-s", "gemini", "-w"],
|
||||
stderr=subprocess.DEVNULL,
|
||||
timeout=5,
|
||||
**hidden_process_kwargs(),
|
||||
).decode("utf-8")
|
||||
|
||||
try:
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ from pathlib import Path
|
|||
from typing import Any, Dict, Optional, Tuple
|
||||
|
||||
from antigravity_provider.router.profile_manager import ProfileAuthManager, mask_email
|
||||
from antigravity_provider.agy_subprocess import hidden_process_kwargs
|
||||
|
||||
logger = logging.getLogger("hermes.router.codex_oauth")
|
||||
|
||||
|
|
@ -380,6 +381,7 @@ def stop_running_codex_processes() -> list[int]:
|
|||
out = subprocess.check_output(
|
||||
["tasklist", "/FI", f"IMAGENAME eq {proc_name}", "/FO", "CSV", "/NH"],
|
||||
stderr=subprocess.DEVNULL,
|
||||
**hidden_process_kwargs(),
|
||||
text=True,
|
||||
)
|
||||
for line in out.strip().splitlines():
|
||||
|
|
@ -389,7 +391,7 @@ def stop_running_codex_processes() -> list[int]:
|
|||
pid_str = parts[1].strip('"')
|
||||
if pid_str.isdigit():
|
||||
pid = int(pid_str)
|
||||
subprocess.run(["taskkill", "/F", "/PID", str(pid)], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
||||
subprocess.run(["taskkill", "/F", "/PID", str(pid)], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, **hidden_process_kwargs())
|
||||
stopped_pids.append(pid)
|
||||
except Exception:
|
||||
pass
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ import sys
|
|||
import traceback
|
||||
from pathlib import Path
|
||||
from typing import Dict, List, Tuple
|
||||
from antigravity_provider.agy_subprocess import hidden_process_kwargs
|
||||
|
||||
|
||||
def get_startup_log_path() -> Path:
|
||||
|
|
@ -96,6 +97,7 @@ def self_heal_dependencies(missing_packages: List[str]) -> Tuple[bool, str]:
|
|||
capture_output=True,
|
||||
text=True,
|
||||
timeout=90,
|
||||
**hidden_process_kwargs(),
|
||||
)
|
||||
if res.returncode == 0:
|
||||
log_startup("Self-healing successful. Re-verifying package imports...")
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ from typing import Any, Callable, Dict, Optional, Tuple
|
|||
|
||||
from antigravity_provider import paths
|
||||
from antigravity_provider.version import __version__, CHANNEL, MINIMUM_HERMES_VERSION
|
||||
from antigravity_provider.agy_subprocess import hidden_process_kwargs
|
||||
|
||||
logger = logging.getLogger("hermes.hub.updater")
|
||||
|
||||
|
|
@ -119,6 +120,7 @@ def get_installed_commit() -> str:
|
|||
capture_output=True,
|
||||
text=True,
|
||||
timeout=5,
|
||||
**hidden_process_kwargs(),
|
||||
)
|
||||
if res.returncode == 0 and res.stdout.strip():
|
||||
return res.stdout.strip()
|
||||
|
|
@ -778,6 +780,7 @@ class UpdateManager:
|
|||
capture_output=True,
|
||||
text=True,
|
||||
timeout=15,
|
||||
**hidden_process_kwargs(),
|
||||
)
|
||||
if res.returncode != 0 or "OK" not in res.stdout:
|
||||
raise RuntimeError(f"Post-update verification failed: {res.stderr or res.stdout}")
|
||||
|
|
|
|||
Loading…
Reference in a new issue