Skip to content

fix(windows): reconcile stale pre-#45610 cmd.exe gateway autostart launchers - #53321

Closed
briandevans wants to merge 2 commits into
NousResearch:mainfrom
briandevans:fix/cli-windows-stale-autostart-reconcile-53173
Closed

fix(windows): reconcile stale pre-#45610 cmd.exe gateway autostart launchers#53321
briandevans wants to merge 2 commits into
NousResearch:mainfrom
briandevans:fix/cli-windows-stale-autostart-reconcile-53173

Conversation

@briandevans

Copy link
Copy Markdown
Contributor

What does this PR do?

Makes hermes doctor detect and repair pre-#45610 Windows gateway autostart launchers. #45610 (433db17) migrated the 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.

This adds an idempotent, elevation-safe reconcile_autostart_launchers() that detects the stale form and rewrites it to the console-less .vbs/wscript launcher, removing the legacy Startup .cmd, plus a Windows-only hermes doctor check that runs it.

Detection precedence mirrored: legacy Startup .cmd present > Scheduled-Task action != wscript.exe.

Related Issue

Fixes #53173

Type of Change

  • 🐛 Bug fix (non-breaking change that fixes an issue)

Changes Made

  • hermes_cli/gateway_windows.py: add _scheduled_task_action_is_stale(), has_stale_autostart_launcher(), and idempotent elevation-safe reconcile_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 at hermes gateway install from 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 stale cmd.exe action + legacy Startup .cmd is detected and reconciled to wscript/.vbs; reconcile is idempotent (second call is a no-op); a current wscript action is not flagged; a schtasks query failure does not false-positive.

How to Test

  1. uv run --with pytest --with pytest-xdist --with pytest-asyncio python3 -m pytest tests/hermes_cli/test_gateway_windows.py -v
  2. Fail-before / pass-after verified: with the three new gateway_windows functions removed, all four new tests fail with AttributeError; restored, they pass (43 passed in the file).
  3. Adjacent: tests/hermes_cli/test_doctor.py (64 passed) — the doctor check no-ops on non-Windows.

Checklist

Code

  • I've read the Contributing Guide
  • My commit messages follow Conventional Commits (fix(scope):)
  • I searched for existing PRs to make sure this isn't a duplicate
  • My PR contains only changes related to this fix (no unrelated commits)
  • I've run the focused + adjacent tests and they pass
  • I've added tests for my changes (fail-before / pass-after)
  • I've tested on my platform:

Documentation & Housekeeping

  • I've updated relevant documentation (docstrings) — or N/A
  • I've updated cli-config.yaml.example if I added/changed config keys — N/A
  • I've updated CONTRIBUTING.md or AGENTS.md if I changed architecture or workflows — N/A
  • I've considered cross-platform impact — the doctor check is Windows-gated (os.name != "nt" returns immediately); no behavior change on macOS/Linux.

Sibling code path intentionally left out of this PR's scope to keep the diff small: wiring reconcile_autostart_launchers() directly into the hermes update completion path (cmd_update in hermes_cli/main.py) so the migration also runs non-interactively on update, not just via hermes doctor. Happy to widen if preferred — the reconcile helper is already idempotent and elevation-safe.

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/.vbs form, never the legacy cmd.exe/.cmd form.

  • Known-bad input: a Scheduled-Task action of cmd.exe/*.cmd and/or a legacy Startup .cmd → reconciled to wscript/.vbs.
  • Future-input coverage: detection keys off the action command + legacy-startup presence, so any new stale-launcher shape pointing at .cmd is caught.
  • Negative case: a current wscript action with no legacy .cmd is left untouched (reconcile is a no-op); a schtasks query failure never reports stale (no false repair).

…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.
Copilot AI review requested due to automatic review settings June 26, 2026 23:35

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 doctor check 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.

Comment on lines +1332 to +1344
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))

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@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.

@alt-glitch alt-glitch added type/bug Something isn't working comp/cli CLI entry point, hermes_cli/, setup wizard platform/windows Native Windows-specific behavior or breakage sweeper:risk-platform-windows Sweeper risk: may break or behave differently on native Windows P2 Medium — degraded but workaround exists labels Jun 26, 2026
…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.
@briandevans

Copy link
Copy Markdown
Contributor Author

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.

@DavidMetcalfe

Copy link
Copy Markdown
Contributor

@briandevans — for the record: the Windows stale-autostart reconciliation originally proposed in #53321 was incorporated into #81362 (fixes #80569). hermes doctor now runs an idempotent, elevation-free reconcile that removes redundant Startup entries (legacy .cmd + .vbs fallback) when the Scheduled Task is registered, and migrates legacy .cmd-only installs to the console-less .vbs form; install() and hermes update converge as well.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/cli CLI entry point, hermes_cli/, setup wizard P2 Medium — degraded but workaround exists platform/windows Native Windows-specific behavior or breakage sweeper:risk-platform-windows Sweeper risk: may break or behave differently on native Windows type/bug Something isn't working

Projects

None yet

4 participants