fix(setup): offer gateway service install on Windows (#22099)

Both setup wizards (hermes setup and hermes gateway setup) gated the
service install/start/restart prompts behind 'supports_systemd or
is_macos()' and fell through to 'run in foreground' on Windows, even
though _is_service_installed() / _is_service_running() already call
gateway_windows.is_installed() and the Windows backend has a full
install/start/stop/restart contract.

Wire the Windows branch into both wizards:
- supports_service_manager now includes is_windows().
- Install offer reads 'Scheduled Task service' on Windows.
- install() on Windows starts the task inline via schtasks /Run (or
  direct-spawn fallback) so the separate 'Start the service now?'
  prompt is skipped.
- Start and Restart delegate to gateway_windows.start() / .restart().

hermes_cli/setup.py  +30 -4
hermes_cli/gateway.py +28 -4
This commit is contained in:
Teknium 2026-05-08 14:59:59 -07:00 committed by GitHub
parent 66320de52e
commit a54cae60d4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 50 additions and 8 deletions

View file

@ -4717,6 +4717,9 @@ def gateway_setup():
systemd_restart()
elif is_macos():
launchd_restart()
elif is_windows():
from hermes_cli import gateway_windows
gateway_windows.restart()
else:
stop_profile_gateway()
print_info("Start manually: hermes gateway")
@ -4738,6 +4741,9 @@ def gateway_setup():
systemd_start()
elif is_macos():
launchd_start()
elif is_windows():
from hermes_cli import gateway_windows
gateway_windows.start()
except UserSystemdUnavailableError as e:
print_error(" Start failed — user systemd not reachable:")
for line in str(e).splitlines():
@ -4749,20 +4755,34 @@ def gateway_setup():
print_error(f" Start failed: {e}")
else:
print()
if supports_systemd_services() or is_macos():
platform_name = "systemd" if supports_systemd_services() else "launchd"
if supports_systemd_services() or is_macos() or is_windows():
if supports_systemd_services():
platform_name = "systemd"
elif is_macos():
platform_name = "launchd"
else:
platform_name = "Scheduled Task"
wsl_note = " (note: services may not survive WSL restarts)" if is_wsl() else ""
if prompt_yes_no(f" Install the gateway as a {platform_name} service?{wsl_note} (runs in background, starts on boot)", True):
try:
installed_scope = None
did_install = False
started_inline = False
if supports_systemd_services():
installed_scope, did_install = install_linux_gateway_from_setup(force=False)
else:
elif is_macos():
launchd_install(force=False)
did_install = True
else:
# gateway_windows.install() registers the Scheduled
# Task AND starts it (schtasks /Run or direct-spawn
# fallback), so no separate start prompt is needed.
from hermes_cli import gateway_windows
gateway_windows.install(force=False)
did_install = True
started_inline = True
print()
if did_install and prompt_yes_no(" Start the service now?", True):
if did_install and not started_inline and prompt_yes_no(" Start the service now?", True):
try:
if supports_systemd_services():
systemd_start(system=installed_scope == "system")

View file

@ -2446,6 +2446,7 @@ def setup_gateway(config: dict):
_is_linux = _platform.system() == "Linux"
_is_macos = _platform.system() == "Darwin"
_is_windows = _platform.system() == "Windows"
from hermes_cli.gateway import (
_is_service_installed,
@ -2470,7 +2471,7 @@ def setup_gateway(config: dict):
service_installed = _is_service_installed()
service_running = _is_service_running()
supports_systemd = supports_systemd_services()
supports_service_manager = supports_systemd or _is_macos
supports_service_manager = supports_systemd or _is_macos or _is_windows
print()
if supports_systemd and has_conflicting_systemd_units():
@ -2490,6 +2491,9 @@ def setup_gateway(config: dict):
systemd_restart()
elif _is_macos:
launchd_restart()
elif _is_windows:
from hermes_cli import gateway_windows
gateway_windows.restart()
except UserSystemdUnavailableError as e:
print_error(" Restart failed — user systemd not reachable:")
for line in str(e).splitlines():
@ -2512,6 +2516,9 @@ def setup_gateway(config: dict):
systemd_start()
elif _is_macos:
launchd_start()
elif _is_windows:
from hermes_cli import gateway_windows
gateway_windows.start()
except UserSystemdUnavailableError as e:
print_error(" Start failed — user systemd not reachable:")
for line in str(e).splitlines():
@ -2522,7 +2529,12 @@ def setup_gateway(config: dict):
except Exception as e:
print_error(f" Start failed: {e}")
elif supports_service_manager:
svc_name = "systemd" if supports_systemd else "launchd"
if supports_systemd:
svc_name = "systemd"
elif _is_macos:
svc_name = "launchd"
else:
svc_name = "Scheduled Task"
if prompt_yes_no(
f" Install the gateway as a {svc_name} service? (runs in background, starts on boot)",
True,
@ -2530,13 +2542,23 @@ def setup_gateway(config: dict):
try:
installed_scope = None
did_install = False
started_inline = False
if supports_systemd:
installed_scope, did_install = install_linux_gateway_from_setup(force=False)
else:
elif _is_macos:
launchd_install(force=False)
did_install = True
else:
# gateway_windows.install() registers the Scheduled
# Task AND starts it immediately (via schtasks /Run
# or a direct spawn fallback), so no separate start
# prompt is needed here.
from hermes_cli import gateway_windows
gateway_windows.install(force=False)
did_install = True
started_inline = True
print()
if did_install and prompt_yes_no(" Start the service now?", True):
if did_install and not started_inline and prompt_yes_no(" Start the service now?", True):
try:
if supports_systemd:
systemd_start(system=installed_scope == "system")