Skip to content

feat(#1952): native Windows support for bootstrap and terminal - #3449

Closed
rodboev wants to merge 2 commits into
nesquena:masterfrom
rodboev:pr/native-windows-support
Closed

rodboev wants to merge 2 commits into
nesquena:masterfrom
rodboev:pr/native-windows-support

Conversation

@rodboev

@rodboev rodboev commented Jun 2, 2026

Copy link
Copy Markdown
Contributor
  • fix(terminal): guard POSIX-only imports for Windows compatibility
  • feat(bootstrap): unblock native Windows bootstrap

Thinking Path

What Changed

  • api/terminal.py: Moved fcntl, select, termios imports behind a _TERMINAL_SUPPORTED = sys.platform != "win32" guard. Added NotImplementedError early returns to start_terminal, write_terminal, resize_terminal. close_terminal returns False (no-op), get_terminal returns None. Guarded the module-level _ensure_spawn_supervisor() call. Pattern matches api/turn_journal.py:18 and api/providers.py:28.

  • bootstrap.py: Replaced RuntimeError in ensure_supported_platform() with a warning via info(). Added RuntimeError guard in install_hermes_agent() (calls /bin/bash, which does not exist on native Windows). Added sys.platform == "win32" branch in the foreground path to use subprocess.Popen + sys.exit(0) instead of os.execv (which on Windows spawns a child process rather than replacing the image, orphaning it from supervisors).

  • tests/test_windows_native_support.py: 14 tests covering both changes. Terminal tests verify _TERMINAL_SUPPORTED flag, NotImplementedError on Windows, and graceful no-ops for close_terminal/get_terminal. Bootstrap tests verify ensure_supported_platform does not raise, install_hermes_agent raises on Windows, and the foreground path routes to Popen on Windows vs execv on POSIX.

Why It Matters

Windows users can run python bootstrap.py (or python server.py) natively without WSL. The chat, model picker, workspace, and all non-terminal features work. The terminal gracefully reports "not supported" instead of crashing the server import.

Verification

# Unit tests (--noconftest because upstream conftest.py test_server has a pre-existing
# Windows symlink privilege issue unrelated to this PR)
python -m pytest tests/test_windows_native_support.py -v --timeout=60 --noconftest

# Manual: start the server on Windows
python bootstrap.py --foreground

# Manual: verify terminal endpoint returns clean error
curl -X POST http://127.0.0.1:8787/api/terminal/start -H "Content-Type: application/json" -d '{"session_id":"test","workspace":"C:\\Users"}'
# Expected: 500 with "Embedded terminal is not supported on Windows"

Risks / Follow-ups

  • No PTY on Windows: The embedded terminal relies on os.openpty() and POSIX signals (SIGHUP, SIGWINCH, SIGKILL). A Windows equivalent would need ConPTY or similar, which is a separate feature.
  • os.killpg in close_terminal/_reap_abandoned_spawn: These POSIX-only calls are unreachable on Windows because start_terminal guards early, but a future refactor should consider them.
  • conftest.py symlink issue: The upstream tests/conftest.py:537 calls symlink_to() which fails on Windows without developer mode. This is pre-existing and unrelated to this PR; tests must run with --noconftest on Windows.
  • scripts/windows/setup_webui_autostart.ps1: Existing script targets WSL. A native Windows autostart script (Task Scheduler) could be a follow-up.

Model Used

Claude Opus 4.6 via Claude Code CLI

@nesquena-hermes

Copy link
Copy Markdown
Collaborator

Shipped in v0.51.236 (Release HD) via release PR #3491 — thank you @rodboev! 🙏

Native Windows support for bootstrap.py + the embedded terminal is now on master and tagged. This was the first Phase-3 (deep-review) pick this session, selected for high impact + well-mitigated risk + your strong recent contributor track record (this is your third merged fix today, after #3446 and #3486).

Absorbed a few things on the way in (reviewed fresh after each):

  • subprocess.CREATE_NEW_PROCESS_GROUP → getattr(subprocess, "CREATE_NEW_PROCESS_GROUP", 0) — the constant is Windows-only, so the win32-simulating test AttributeError'd when run on the Linux CI box. Mirrors your own SO_EXCLUSIVEADDRUSE getattr guard from fix(server): disable SO_REUSEADDR to prevent silent port sharing (#3289) #3446.
  • Two tests in test_windows_native_support.py: test_install_hermes_agent_allowed_in_wsl was launching a real installer subprocess (unstubbed subprocess.run) — now stubbed and deterministic; removed two unused imports.
  • test_onboarding_static.py asserted the OLD "Native Windows is not supported" hard-block string your PR intentionally replaces — updated it to assert the new experimental-warning + the auto-install native-Windows guard.
  • --foreground help text now mentions the Windows Popen path (was "via os.execv" only).

Both pre-release reviewers (Codex regression + Opus correctness) confirmed the POSIX path is provably unchanged and the Windows guards are complete. The Windows runtime couldn't be exercised on the Linux box — it was reviewed statically + via your 209-line monkeypatched test. Authorship preserved via Co-authored-by and credited in the CHANGELOG. Closes #1952.

Closing as merged-via-release-stage (the change is in master, recommitted on the stage branch).

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants