From 4a40e8b25160609cb15244c7e9180804df575721 Mon Sep 17 00:00:00 2001 From: raymondginger Date: Fri, 25 Sep 2026 22:22:16 +0800 Subject: [PATCH] fix(service): start the detached service without a console window on Windows DETACHED_PROCESS makes Windows allocate a brand-new console for the child. With Windows Terminal (ConPTY) as the default terminal handler that console surfaces as a real, visible WindowsTerminal window on every `service start`, which floods the desktop when the CLI is driven from a harness that starts and stops the service repeatedly. CREATE_NO_WINDOW keeps the process windowless -- the console is private to the child and never inherited -- while still outliving the launcher, so the detached contract is unchanged. CREATE_NO_WINDOW is ignored when it is combined with DETACHED_PROCESS, hence the replacement rather than an addition; CREATE_NEW_PROCESS_GROUP is kept. The replica in tests/app_server/test_service.py mirrors the flag, so the detached parametrization stops spawning a console window as well. --- cli/service_cli.py | 7 ++++++- tests/app_server/test_service.py | 4 +++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/cli/service_cli.py b/cli/service_cli.py index 3538fcce..d1dfbe97 100644 --- a/cli/service_cli.py +++ b/cli/service_cli.py @@ -170,8 +170,13 @@ def _start_detached( stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, start_new_session=os.name != "nt", + # CREATE_NO_WINDOW, not DETACHED_PROCESS: DETACHED_PROCESS makes Windows + # allocate a brand-new console for the service, which the default + # terminal surfaces as a visible window on every `service start`. + # CREATE_NO_WINDOW still runs without any window and still outlives the + # launcher (the console is private to the child, never inherited). creationflags=( - subprocess.DETACHED_PROCESS | subprocess.CREATE_NEW_PROCESS_GROUP + subprocess.CREATE_NO_WINDOW | subprocess.CREATE_NEW_PROCESS_GROUP ) if os.name == "nt" else 0, diff --git a/tests/app_server/test_service.py b/tests/app_server/test_service.py index f700f469..b1a35ab6 100644 --- a/tests/app_server/test_service.py +++ b/tests/app_server/test_service.py @@ -213,7 +213,9 @@ def test_service_exits_cleanly_after_control_stop(tmp_path, log_to_file, detache cwd=Path(__file__).resolve().parents[2], start_new_session=detached and os.name != "nt", creationflags=( - subprocess.DETACHED_PROCESS | subprocess.CREATE_NEW_PROCESS_GROUP + # Mirror the launcher: CREATE_NO_WINDOW, so the detached leg does + # not pop a console window on Windows (DETACHED_PROCESS would). + subprocess.CREATE_NO_WINDOW | subprocess.CREATE_NEW_PROCESS_GROUP if detached and os.name == "nt" else 0 ),