From d3d281b5953ec88c6fc4baf23beb6fab40d17dbe Mon Sep 17 00:00:00 2001 From: Satoshi Yamamura <148422227+s-ymmr07@users.noreply.github.com> Date: Fri, 11 Sep 2026 13:44:09 +0900 Subject: [PATCH] fix: hide Git delivery console windows on Windows The Git delivery watcher spawned visible git consoles because _subprocess_runner did not pass CREATE_NO_WINDOW. Match the update-check path from #19 without importing app.py. Co-authored-by: Cursor --- tests/test_git_delivery.py | 21 +++++++++++++++++++++ token_meter/services/git_delivery.py | 18 ++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/tests/test_git_delivery.py b/tests/test_git_delivery.py index 9ca4462..7c39aa1 100644 --- a/tests/test_git_delivery.py +++ b/tests/test_git_delivery.py @@ -148,6 +148,27 @@ def test_subprocess_runner_supplies_a_system_path_for_launch_agents(self): self.assertEqual(run.call_args.kwargs["env"]["PATH"], os.defpath) + def test_subprocess_runner_hides_windows_console(self): + completed = mock.Mock(returncode=0, stdout="", stderr="") + windows = meter.platform_services( + "windows", + environment={"USERPROFILE": r"C:\Users\example"}, + home=r"C:\Users\example", + ) + with mock.patch( + "token_meter.services.git_delivery.platform_services", + return_value=windows, + ), mock.patch( + "token_meter.services.git_delivery.subprocess.run", + return_value=completed, + ) as run: + meter.GitDeliveryService._subprocess_runner( + ["git", "--version"], timeout=1, + ) + + self.assertEqual(run.call_args.kwargs["creationflags"], 0x08000000) + self.assertTrue(run.call_args.kwargs["close_fds"]) + def test_scan_limits_generator_candidates_without_losing_limit_coverage(self): with tempfile.TemporaryDirectory() as tmp: service = meter.GitDeliveryService( diff --git a/token_meter/services/git_delivery.py b/token_meter/services/git_delivery.py index 485bc9c..efe88db 100644 --- a/token_meter/services/git_delivery.py +++ b/token_meter/services/git_delivery.py @@ -10,6 +10,8 @@ import subprocess import threading +from token_meter.platforms import ProcessPurpose, platform_services + LEDGER_SCHEMA_VERSION = 1 GIT_TIMEOUT_SECONDS = 10 @@ -354,6 +356,21 @@ def __init__(self, ledger_path, runner=None, now=None, salt=""): "last_checked": self.ledger.last_checked(), } + @staticmethod + def _platform_subprocess_kwargs(): + """Match app._platform_subprocess_kwargs without importing app.py.""" + options = platform_services().process_options(ProcessPurpose.DEFAULT) + if not options.supported: + return {} + kwargs = {} + if options.close_fds: + kwargs["close_fds"] = True + if options.start_new_session: + kwargs["start_new_session"] = True + if options.creation_flags: + kwargs["creationflags"] = options.creation_flags + return kwargs + @staticmethod def _subprocess_runner(argv, timeout): environment = { @@ -373,6 +390,7 @@ def _subprocess_runner(argv, timeout): encoding="utf-8", errors="replace", env=environment, + **GitDeliveryService._platform_subprocess_kwargs(), ) @staticmethod