feat(claude-loop): Windows ConPTY proxy — live human-typing detection (#281, strategy B)#10
Merged
Conversation
…on (#281, strategy B) Port the claude-loop PTY proxy (#269) to Windows. The Unix proxy is POSIX-only (pty/termios/AF_UNIX); Windows needs ConPTY + a named pipe. New crate `windows/cl-pty-proxy/` (Rust, GNU toolchain — no MSVC needed): - Nested ConPTY for claude via portable-pty (same layer psmux uses); bridges human-stdin / claude-output / named-pipe wake injection. - Detects win32-input-mode keystrokes (ESC[Vk;Sc;Uc;Kd;Cs;Rc_) — what psmux/ConPTY actually delivers, not raw VT — so the human-typing marker fires busy-included. 7 unit tests on captured sequences. - Markers (human-typing, PID-stamped proxy-alive), @cl_human painting, resize + exit-code propagation, fail-safe direct-run on ConPTY failure. Wiring: - cli.ts: launch the .exe on win32 when built (Python proxy gated to non-Windows — its POSIX APIs would crash the pane); `check` probe. - state.ts: injectWakePhrase → named pipe (\.\pipe\cl-inject-<name>) via Node net, gated on proxyIsAlive; injectPipeName() helper. The .exe is a platform-specific build artifact (target/ gitignored); build with `cargo build --release --manifest-path windows/cl-pty-proxy`. Without it, claude-loop falls back to idle-only pane-diff detection. Known limit: double conhost (nested ConPTY) can glitch complex TUIs — docs/PTY-PROXY-WINDOWS.md documents this and proposes strategy A (psmux emits the signal natively, no nested PTY) as the follow-up PR.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Ports the claude-loop PTY proxy (#269) to Windows. The Unix proxy is POSIX-only (
pty/termios/AF_UNIX); Windows needs ConPTY + a named pipe. This is strategy B — a standalone nested-ConPTY proxy that ships the feature now; strategy A (psmux emits the signal natively) is the planned follow-up (see the design doc).Same feature as the Unix side: tell a human typing apart from claude's output and from the loop's own wake injection — live, busy included.
New crate:
windows/cl-pty-proxy/(Rust)x86_64-pc-windows-gnu) — no MSVC / VS Build Tools needed.portable-pty(same layer psmux is built on); bridges three channels: human stdin → claude, claude output → stdout, named-pipe injection → claude (marker untouched).ESC[Vk;Sc;Uc;Kd;Cs;Rc_, not raw VT, so every keystroke starts with ESC. A naive "first byte printable" test never fires. The parser extracts the unicode + key-down to detect text keystrokes. 7 unit tests on real captured sequences.human-typing, PID-stampedproxy-alive),@cl_humanpainting (#274 parity), resize + exit-code propagation, fail-safe direct-run if ConPTY init fails (pane never bricked).Wiring
cli.ts: on win32, launchcl-pty-proxy.exe -- claude …when the binary exists; the Python proxy branch is gated to non-Windows (its POSIX APIs would crash the pane).claude-loop checkreports proxy active/inactive.state.ts:injectWakePhrase→ named pipe\.\pipe\cl-inject-<name>via Nodenet(named pipes are first-class, no native dep), gated onproxyIsAlive(a pipe can't bestat-ed). NewinjectPipeName()helper.Validation (under real psmux)
human-typingmarker +@cl_human=stop, reverts toloopafter TTL-9leaves a stale marker handled by the PID-liveness check (#278 contract)claude-loop startcargo test(7),cargo clippy, TStypecheck+eslintall cleanBuild (not committed — platform-specific artifact,
target/gitignored)Without it, claude-loop still works — falls back to idle-only pane-diff detection.
Known limitation → motivates strategy A
claude runs under a second ConPTY nested inside psmux's ConPTY (double conhost). Basic rendering / resize work, but complex TUI cases can glitch. This is inherent to any nested-proxy approach. Strategy A (psmux touches the marker natively in
forward_key_to_active— no nested PTY, no double translation, no native dep) is documented indocs/PTY-PROXY-WINDOWS.mdas the follow-up PR; strategy B validates the markers/named-pipe/status wiring that A would reuse.Docs
docs/PTY-PROXY-WINDOWS.md— full design + strategy A proposal.docs/WIN-INSTALL.md— optional build step.