From b04bda09eb6cdf5b5b9d52839246066603262d7c Mon Sep 17 00:00:00 2001 From: Jonathan Liebig Date: Sat, 12 Sep 2026 18:24:58 +0200 Subject: [PATCH 1/2] feat: start remote servers in the signed-in windows desktop refs #3651 --- Cargo.lock | 1 + Cargo.toml | 7 + .../src/content/docs/connecting-machines.mdx | 1 + .../src/content/docs/persistence-remote.mdx | 10 + .../website/src/content/docs/windows-beta.mdx | 3 + src/cli/machine.rs | 24 +- src/cli/status.rs | 2 + src/cli/target.rs | 1 + src/client/catalog_reload.rs | 2 +- src/client/endpoint/activation_tests.rs | 1 + src/client/endpoint/catalog.rs | 52 +- src/client/endpoint/supervisor.rs | 25 +- src/client/shell/tests/endpoint_requests.rs | 1 + src/client/shell/tests/endpoints.rs | 1 + src/client/shell/tests/mobile.rs | 1 + src/main.rs | 28 +- src/platform/mod.rs | 10 + src/platform/windows.rs | 13 +- src/platform/windows/desktop_bootstrap.rs | 181 ++++++ src/platform/windows/desktop_host.rs | 564 ++++++++++++++++++ src/remote.rs | 53 +- src/remote/args.rs | 17 + src/remote/attach.rs | 116 +++- src/remote/attach/desktop.rs | 336 +++++++++++ src/remote/host.rs | 15 +- src/remote/saved.rs | 30 +- src/server/headless/tests/surface_interest.rs | 1 + 27 files changed, 1412 insertions(+), 84 deletions(-) create mode 100644 src/platform/windows/desktop_bootstrap.rs create mode 100644 src/platform/windows/desktop_host.rs create mode 100644 src/remote/attach/desktop.rs diff --git a/Cargo.lock b/Cargo.lock index 08fe5cc63f..dd25678d0b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -699,6 +699,7 @@ dependencies = [ "tracing-subscriber", "unicode-width", "widestring", + "windows", "windows-sys", "wmi", ] diff --git a/Cargo.toml b/Cargo.toml index d28ba46b24..328716f4a6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -54,6 +54,12 @@ portable-pty = { path = "vendor/portable-pty" } # UTF-16 SDDL input for interprocess security descriptors. widestring = "1.2" wmi = { version = "0.18.4", default-features = false } +windows = { version = "0.62.2", features = [ + "Win32_System_Com", + "Win32_System_Ole", + "Win32_System_TaskScheduler", + "Win32_System_Variant", +] } windows-sys = { version = "0.61.2", features = [ "Wdk_System_Threading", "Win32_Foundation", @@ -69,6 +75,7 @@ windows-sys = { version = "0.61.2", features = [ "Win32_System_Memory", "Win32_System_Ole", "Win32_System_Pipes", + "Win32_System_RemoteDesktop", "Win32_System_Threading", "Win32_UI_Input_Ime", "Win32_UI_Input_KeyboardAndMouse", diff --git a/docs/next/website/src/content/docs/connecting-machines.mdx b/docs/next/website/src/content/docs/connecting-machines.mdx index a849727079..ab556c9fa6 100644 --- a/docs/next/website/src/content/docs/connecting-machines.mdx +++ b/docs/next/website/src/content/docs/connecting-machines.mdx @@ -58,6 +58,7 @@ When a connection is lost, the last workspace and agent state remains visible bu Read profile IDs from the list rather than deriving them from labels or hostnames: ```bash +herdr machine add windows-workbox --label "Desktop agents" --remote-desktop herdr machine list herdr machine rename --label "New name" herdr machine disable diff --git a/docs/next/website/src/content/docs/persistence-remote.mdx b/docs/next/website/src/content/docs/persistence-remote.mdx index bdfe5177c4..7d31448762 100644 --- a/docs/next/website/src/content/docs/persistence-remote.mdx +++ b/docs/next/website/src/content/docs/persistence-remote.mdx @@ -50,6 +50,16 @@ herdr --remote ssh://you@server:2222 In this mode, the remote server owns the running panes and sends their terminal content and session state over SSH. Your local Herdr draws the UI, including its sidebar, menus, and theme. Because the client runs locally, Herdr can bridge local desktop features such as image clipboard paste into the remote session by copying the image to a remote temp file and pasting that path. +Windows SSH normally starts processes outside the signed-in desktop. To let agents on a Windows target interact with desktop apps, opt in explicitly: + +```bash +herdr --remote windows-workbox --remote-desktop +``` + +Install a Windows Herdr package that supports desktop hosting first. Herdr checks `PATH` and the active managed package, but this option does not install or update the remote binary. + +To start a desktop server, Herdr requires exactly one active desktop login for the SSH account. It asks for confirmation, creates a one-time Windows task to launch the server in that login, and removes the task after the server is ready. Automatic reconnects only attach; they do not create tasks or start a server. A server with the same Herdr session name in Windows Session 0 or another login is left running and reported as a conflict. Use a different `--session` or stop that server explicitly. This option does not sign in, unlock Windows, or move existing panes between Windows sessions. + By default, `herdr --remote` uses your local Herdr keybindings for that attach. This keeps local muscle memory even when the remote server has different config. After editing local keybindings, use the UI's `reload config` action to apply them without detaching. Use `--remote-keybindings server` when you want the remote server config instead. Local custom command keybindings are not sent, because those commands would run on the remote host. For repeat targets, use your SSH config: diff --git a/docs/next/website/src/content/docs/windows-beta.mdx b/docs/next/website/src/content/docs/windows-beta.mdx index 8f34dfb9f5..9664cbf9ed 100644 --- a/docs/next/website/src/content/docs/windows-beta.mdx +++ b/docs/next/website/src/content/docs/windows-beta.mdx @@ -33,6 +33,7 @@ For internal testing, `HERDR_MANIFEST_URL` can point the installer at a custom m | Native panes through ConPTY | supported | | Windows Terminal / PowerShell app attach | supported | | `herdr --remote` and saved SSH machines to Linux/macOS/Windows hosts | supported; Windows requires a compatible package with remote host support on `PATH` | +| Remote agents in the signed-in Windows desktop | supported with `--remote-desktop`; install a desktop-capable package first | | Remote clipboard images and image-file drops | supported | | `cmd.exe` panes | supported | | Native keyboard and mouse input | supported | @@ -49,6 +50,8 @@ For internal testing, `HERDR_MANIFEST_URL` can point the installer at a custom m Local persistent sessions continue running after the client detaches or its terminal window closes. Servers and pane processes launched through Windows OpenSSH also survive logout; run `herdr` again to reconnect. +Windows OpenSSH starts its normal server in Windows Session 0. Add `--remote-desktop` to a direct remote attach or `machine add` command when agents must interact with apps in the SSH account's active desktop login. Herdr asks before it uses a one-time Windows task for the initial start, removes the task after readiness, and leaves an existing server in another Windows session untouched. + Windows agent process detection scans descendants of the pane shell and recognizes direct agents plus common command wrappers, including npm/Node and Git Bash process chains. It follows Git Bash-launched agents across emulated `exec` boundaries, but it is not the same as Unix foreground process-group detection. Windows integration installation currently supports Pi, OMP, Claude Code, Codex, GitHub Copilot CLI, Devin CLI, OpenCode, Kilo Code CLI, Droid, Kimi Code CLI, Qoder CLI, and Antigravity CLI. Availability is narrower than on Unix; Herdr hides or rejects integrations whose install format is not supported on Windows. diff --git a/src/cli/machine.rs b/src/cli/machine.rs index ab84041e9d..0d207bcf24 100644 --- a/src/cli/machine.rs +++ b/src/cli/machine.rs @@ -4,7 +4,7 @@ use crate::client::endpoint::{EndpointCatalog, ProfileId}; const HELP: &str = "Usage: herdr machine list [--json] - herdr machine add --label