fix(windows): reconcile stale pre-#45610 cmd.exe gateway autostart launchers - #53321
fix(windows): reconcile stale pre-#45610 cmd.exe gateway autostart launchers#53321briandevans wants to merge 2 commits into
Conversation
…autostart launchers NousResearch#45610 migrated the Windows gateway autostart from a cmd.exe launcher to a console-less .vbs run via wscript.exe, but only for fresh installs. Machines installed earlier and later updated keep the old cmd.exe Scheduled-Task action and a legacy Startup-folder .cmd, which respawn visible console windows at logon and let the half-started gateway be killed by the logon console-close event. Add an idempotent, elevation-safe reconcile_autostart_launchers() that detects the stale form (legacy Startup .cmd present > Scheduled-Task action != wscript.exe) and rewrites it to the console-less .vbs/wscript launcher, removing the legacy Startup .cmd, reusing the existing _write_task_script / _install_scheduled_task / _install_startup_entry builders. Wire a Windows-only hermes doctor check that runs it and warns (pointing at an elevated 'hermes gateway install') when reconcile needs elevation it doesn't have.
There was a problem hiding this comment.
Pull request overview
This PR extends Hermes’ Windows gateway autostart support by teaching hermes doctor to detect and repair “pre-#45610” legacy autostart launchers (Scheduled Task running cmd.exe/.cmd, plus a Startup-folder .cmd) and migrate them to the console-less wscript.exe + .vbs launcher format introduced in #45610.
Changes:
- Added stale-launcher detection and an idempotent reconciliation helper in
hermes_cli/gateway_windows.py. - Wired a Windows-only
hermes doctorcheck to detect and attempt reconciliation, reporting status to the user. - Added regression tests covering detection, reconciliation, idempotency, and “schtasks query failure” non-false-positive behavior.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
hermes_cli/gateway_windows.py |
Adds stale autostart detection and a reconcile helper to rewrite legacy cmd.exe launchers to wscript.exe/.vbs. |
hermes_cli/doctor.py |
Adds a Windows-only doctor check that detects stale launchers and attempts repair (or warns). |
tests/hermes_cli/test_gateway_windows.py |
Adds tests validating stale detection, migration behavior, idempotency, and query-failure safety. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| script_path = _write_task_script() | ||
| notes: list[str] = [] | ||
| if is_task_registered(): | ||
| ok, detail = _install_scheduled_task(get_task_name(), script_path) | ||
| if ok: | ||
| notes.append("re-pointed Scheduled Task at wscript.exe/.vbs") | ||
| else: | ||
| # Access-denied (no elevation) is non-fatal: the Startup .vbs | ||
| # fallback below still removes the console-spawning launcher. | ||
| notes.append(f"Scheduled Task not updated ({detail})") | ||
| _install_startup_entry(script_path) | ||
| notes.append("rewrote Startup launcher (.vbs) and removed legacy .cmd") | ||
| return (True, "; ".join(notes)) |
There was a problem hiding this comment.
@copilot Good catch — fixed in 7fe2758. reconcile_autostart_launchers() now re-probes has_stale_autostart_launcher() after the rewrite attempt and returns (False, …) when the launcher is still stale (e.g. the Scheduled-Task /Create was denied for lack of elevation and the action still points at cmd.exe). _check_windows_gateway_launcher() in doctor.py then takes its warn branch and surfaces the "reinstall from an elevated prompt" remediation instead of reporting a false green. Added a fail-before/pass-after regression test (test_residual_stale_task_after_failed_update_reports_unchanged) that mocks _install_scheduled_task to fail with Access Denied and asserts changed is False with the task still stale.
…o-elevation reconcile reconcile_autostart_launchers() returned changed=True whenever the Startup .vbs fallback ran, even if the Scheduled-Task rewrite failed for lack of elevation (Access Denied) and the task kept pointing at cmd.exe/.cmd. doctor then reported a false green and never prompted the user to rerun elevated. Re-probe has_stale_autostart_launcher() after the rewrite attempt; when the launcher is still stale, return (False, ...) so _check_windows_gateway_launcher warns and surfaces the "reinstall from an elevated prompt" remediation.
|
Closing to keep the queue focused on the fixes drawing review — this hasn't picked up any reviewer engagement in ~2 weeks. Happy to reopen if maintainers want the Windows stale-autostart reconcile picked up. |
|
@briandevans — for the record: the Windows stale-autostart reconciliation originally proposed in #53321 was incorporated into #81362 (fixes #80569). |
What does this PR do?
Makes
hermes doctordetect and repair pre-#45610 Windows gateway autostart launchers. #45610 (433db17) migrated the autostart from acmd.exelauncher to a console-less.vbsrun viawscript.exe, but only for fresh installs — machines installed earlier and later updated keep the oldcmd.exeScheduled-Task action and a legacy Startup-folder.cmd, which respawn visible console windows at logon and let the half-started gateway be killed by the logon console-close event.This adds an idempotent, elevation-safe
reconcile_autostart_launchers()that detects the stale form and rewrites it to the console-less.vbs/wscriptlauncher, removing the legacy Startup.cmd, plus a Windows-onlyhermes doctorcheck that runs it.Detection precedence mirrored: legacy Startup
.cmdpresent > Scheduled-Task action !=wscript.exe.Related Issue
Fixes #53173
Type of Change
Changes Made
hermes_cli/gateway_windows.py: add_scheduled_task_action_is_stale(),has_stale_autostart_launcher(), and idempotent elevation-safereconcile_autostart_launchers(), reusing the existing_write_task_script/_install_scheduled_task/_install_startup_entry(which already removes the legacy.cmd) builders.hermes_cli/doctor.py: add_check_windows_gateway_launcher(issues)(Windows-only) that reports OK on the console-less form, migrates a stale launcher, and warns (pointing athermes gateway installfrom an elevated prompt) when reconcile cannot complete without elevation. Wired next to_check_gateway_service_linger/_check_s6_supervision.tests/hermes_cli/test_gateway_windows.py: regression tests — a stalecmd.exeaction + legacy Startup.cmdis detected and reconciled towscript/.vbs; reconcile is idempotent (second call is a no-op); a currentwscriptaction is not flagged; a schtasks query failure does not false-positive.How to Test
uv run --with pytest --with pytest-xdist --with pytest-asyncio python3 -m pytest tests/hermes_cli/test_gateway_windows.py -vgateway_windowsfunctions removed, all four new tests fail withAttributeError; restored, they pass (43 passed in the file).tests/hermes_cli/test_doctor.py(64 passed) — the doctor check no-ops on non-Windows.Checklist
Code
fix(scope):)Documentation & Housekeeping
cli-config.yaml.exampleif I added/changed config keys — N/ACONTRIBUTING.mdorAGENTS.mdif I changed architecture or workflows — N/Aos.name != "nt"returns immediately); no behavior change on macOS/Linux.Contract Protected
Invariant: when the gateway autostart is installed on Windows, the on-disk launchers (Scheduled-Task action + Startup-folder entry) must run the console-less
wscript.exe/.vbsform, never the legacycmd.exe/.cmdform.cmd.exe/*.cmdand/or a legacy Startup.cmd→ reconciled towscript/.vbs..cmdis caught.wscriptaction with no legacy.cmdis left untouched (reconcile is a no-op); a schtasks query failure never reports stale (no false repair).