Command stdin and interactive shell: stdin() builders, RemoteProcess.stdin(), and a CLI shell subcommand - #144
Conversation
…stdin(), CLI shell subcommand (#136) Phase 1 - stdin for commands (library): - New WSMan Send envelope (rsp:Send, base64 stdin stream, End="true" on the final chunk) and a send(byte[], end) / interrupt() seam on RemoteCommand and CommandCursor; input larger than one envelope is chunked automatically. - stdin(String|Path|InputStream) on CommandRequest: pre-supplied input, delivered in full right after startup and ending with the End mark; it switches the remote stdin to pipe semantics (WINRS_CONSOLEMODE_STDIN=FALSE) so filters like sort see EOF. Works with execute() and start(). - RemoteProcess.stdin() completes the java.lang.Process shape: flush() emits one WSMan Send, close() marks the end of input. RemoteProcess.interrupt() sends the new ctrl_c Signal (a console Ctrl+C that leaves the session alive), and RemoteProcess.poll(Duration) exposes one bounded round trip. - Cleanup discipline from #134 carries over: closing stdin after completion or an early close is a silent local no-op - no stray requests, no revived transport, no exit code hidden behind cleanup failures. Phase 2 - interactive shell subcommand (CLI): - winrm-java ... shell starts cmd.exe remotely and bridges it to the local terminal until it exits: a single-threaded pump (drain queued local input -> Send -> bounded poll -> forward output) with one helper thread reading local stdin, line-oriented like winrs. Local EOF sends End="true"; Ctrl+C is rerouted (sun.misc.Signal, reflective with graceful fallback) to the WSMan ctrl_c Signal; the remote exit code uses the CLI exit-code contract. - command forwards piped/redirected local stdin as the remote command's stdin: winrm-java ... command sort < data.txt just works. Bounded-poll fix exposed by the pump (latent from #134): the WSMan service clamps OperationTimeout below 500 ms up to 500 ms (measured on Windows Server 2008 R2), so a wire poll shorter than the floor plus transit slack always lost the race between the "nothing yet" fault and its own socket cut. Wire polls now require a 750 ms budget (shorter waits are waited out locally) and never ask the server for less than the 500 ms floor. FakeWsmanServer learns Send (decodes and records stdin chunks with their End flag); new CommandStdinTest and InteractiveShellTest cover content, chunking, End, console-mode option on the wire, a scripted REPL round trip, Ctrl+C, exit-code propagation, and the cleanup invariants. Verified live against a real Windows Server 2008 R2 host (piped sort and a full shell session). Closes #136 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 5db84956ad
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
… End tracking, shell timeout floor - stdin() (no argument) on CommandRequest declares interactive input for start(): pipe semantics (WINRS_CONSOLEMODE_STDIN=FALSE) without pre-supplied content, so RemoteProcess.stdin().close() actually delivers EOF to filters like sort. execute() rejects the declaration up front - it cannot take interactive input, and a command waiting on a never-fed pipe would hang for a whole timeout. Plain start() keeps the historical console semantics (what the interactive CLI shell wants). - New ChunkEncoder (the mirror image of ChunkDecoder) carries the charset encoder state across stdin flushes: a byte-order mark is emitted once, not per flush, and a surrogate pair split by a flush boundary is withheld and completed by the next write instead of becoming two replacements. - RemoteCommand.send() tracks the delivered End mark and rejects later sends locally, so direct CommandCursor users cannot append input after EOF. - The CLI rejects a shell --timeout below 1000 ms: it caps each bounded poll of the session pump, and a poll below the WSMan 500 ms floor plus transit slack never reaches the wire - the shell would spin locally without ever fetching output. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
@codex please review again |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: e9a471a4bd
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…or timeouts keep polling - WindowsRemoteExecutor.startCommand(4-arg) default now delegates console-mode requests to the historical three-argument variant, so a pre-existing executor that overrides only that variant keeps working for ordinary commands after the upgrade; only pipe-mode stdin is unsupported by default. The three-argument default throws again (as before this PR), and LightWinRMService overrides both variants explicitly. - The bounded poll's cap by the per-round-trip timeout no longer pushes a caller's wait below the wire-poll minimum: a process configured with an inactivity timeout under 750 ms could otherwise never issue a Receive from poll()/waitFor(Duration) and never observe completion. Same clamp for the bounded completion Signal. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
@codex please review again |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: d23a612d8c
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
… shell input batches - The shell pump no longer fails the session when a line (or the local EOF) gets queued while the final Done-carrying Receive is in flight: the cursor-level IllegalStateException is treated as "the command is gone, stop forwarding", and the next poll reports the exit code normally. - Redirected input is forwarded in bounded batches (32 KiB of characters per round, the rest stays queued) so a fire hose of input cannot starve the output side of the pump or balloon the local buffers, and the reader thread's queue is capped (1024 lines) for backpressure toward the local stdin. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
@codex please review again |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 6a4f6566f4
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…ssed cleanup, closed writer - Send and the ctrl_c Signal now go through the same streaming timeout translation as command startup and Receive: a server staying quiet for a whole inactivity timeout surfaces as the documented WinRMTimeoutException (CLI exit 124), not as a generic connection or protocol failure. - A failed pre-supplied stdin delivery is no longer masked when the cleanup terminate Signal fails too: the original exception wins, the cleanup failure travels as suppressed. - With pre-supplied stdin, the RemoteProcess.stdin() writer is now actually closed at construction: writes are rejected immediately instead of being buffered into the void by the BufferedWriter layer. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
@codex please review again |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 76d1cd5586
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…l cadence from response transit - Stdin forwarding no longer keys on System.console() alone, which is also null when only the OUTPUT is redirected (command hostname > result.txt) and would then hang the CLI consuming an interactive terminal. The input itself is probed: bytes already waiting at startup can only come from a pipe or a redirected file; an untouched terminal reports nothing available. - New cadence variant of the bounded poll, poll(ask, maxWait): the server is asked to answer within the polling cadence, but the answer itself may take up to the inactivity timeout to arrive - one slow answer from a loaded server no longer kills the interactive session at the 1-second cadence. RemoteProcess.poll(Duration) now uses it (the wait is the cadence, the request timeout governs transit); waitFor(Duration) keeps the hard bound for deadlines, including against a dead peer. Verified live against a real Windows Server 2008 R2 host again (interactive shell session, exit-code propagation). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
@codex please review again |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 494b652a0c
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
… oversized shell input records - Stdin redirection detection no longer relies on buffered bytes alone: a seekable descriptor 0 is a redirected file (catching empty files and the null device - verified live: `command sort < /dev/null` now completes immediately instead of hanging), while waiting bytes still catch pipes. The one undetectable case - a pipe whose producer writes only after the CLI started - gets the new explicit -i/--stdin option (command subcommand only), which forces forwarding regardless of detection. - The shell pump now splits an input record larger than one round's budget: the surplus leads the next round instead of being encoded and sent whole, so a giant newline-free record (minified JSON, base64) keeps memory bounded and the input/output rounds alternating. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
@codex please review again |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 6dfdd05280
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…at the reader - The stdin ChunkEncoder is now created on first actual input rather than with the RemoteProcess: a legal decode-only charset (x-JISAutoDetect, ISO-2022-CN) throws on Charset.newEncoder(), which previously failed start() AFTER the cursor was acquired - leaking the running command and the client's serial connection - even for callers that only read output. The failure now hits exactly the flush that actually needs an encoder, and a bare close of the untouched writer stays silent. - The shell's local reader thread no longer materializes whole lines (BufferedReader.readLine() would heap out on a giant newline-free record before any downstream bound applied): it reads and queues bounded pieces (4 KiB), normalizing every line-ending flavor (LF, CRLF, lone CR) to the CRLF the remote cmd.exe expects. The pump's InputSource seam moves from lines to terminator-included pieces accordingly, so the byte-bounded backpressure (256-piece queue) actually bounds memory by characters. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
@codex please review again |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 71e299dcc8
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
stdin() (no argument) now discards previously pre-supplied input, so a reusable request switched to interactive mode actually behaves interactively: start() no longer pre-sends the stale source, and execute() rejects the declaration as documented. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
@codex please review again |
The shell subcommand now runs `cmd.exe /Q` (cmd's command echo off) over pipe-mode stdin (WINRS_CONSOLEMODE_STDIN=FALSE, the winrs -noecho equivalent): the forwarded input is never repeated back by the remote side - the local terminal already shows what the user types, and the output stream carries the prompts and command output only. Pipe-mode stdin also turns the local end-of-input into a real EOF: cmd.exe exits on it, so a piped session ends cleanly without an explicit `exit`. Verified live against a real Windows Server 2008 R2 host: no input echo, prompts and output intact, exit-code propagation unchanged, and an EOF-only session terminates with the shell's exit code. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
@codex please review again |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: f244e14cf1
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
- The shell's local input is no longer decoded with Charset.defaultCharset(), which is UTF-8 on modern JDKs even when a Windows console feeds System.in with its OEM code page (mangling non-ASCII commands). The real encoding is probed in order: stdin.encoding (recent JDKs), sun.stdin.encoding (Windows consoles on older JDKs), Console.charset() (Java 17+, reached reflectively), native.encoding (Java 18+), then the process default. - A local stdin read failure no longer masquerades as a normal end of input (which closed the remote stdin, let the shell run the truncated input, and reported success): the failure travels through the queue and fails the bridge, so the CLI exits nonzero with the actual error. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
@codex please review again |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: a3f81a559a
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…iguration
The ctrl_c-requires-console-mode claim is refuted by a live probe against a
real Windows Server 2008 R2 host: with WINRS_CONSOLEMODE_STDIN=FALSE, the
WSMan ctrl_c Signal interrupted a 29-second ping after 0.6 s ("Control-C"
in the output) and the session kept running - the Signal is delivered as a
console ctrl event to the command's process group regardless of the stdin
mode option. Production keeps pipe-mode stdin (echo-free, real EOF).
The valid part of the finding: the pump tests started a plain cmd.exe with
console-mode stdin instead of what the shell subcommand actually runs. They
now start the production configuration (cmd.exe /Q over pipe-mode stdin)
through a shared helper.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
@codex please review again |
|
Codex Review: Didn't find any major issues. Can't wait for the next one! Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
…din, ANSI-encoded Typing "echo testé" in the shell produced "test????". Diagnosed against a real Windows host by probing every combination of stdin mode and input encoding: - cmd.exe reading its COMMAND LINES from a PIPED stdin under console code page 65001 decodes them one byte at a time, so every non-ASCII byte becomes U+FFFD. No client-side encoding fixes it: UTF-8, CP1252, CP850 and CP437 all come back corrupted. This is what the echo-suppression change (pipe mode) exposed. - With CONSOLE-mode stdin the WinRM service converts the bytes itself, using the remote machine's ANSI code page: the same line encoded in windows-1252 round-trips intact on a French host, and output stays UTF-8 (full Unicode). - DATA piped to an ordinary program (sort, findstr) is unaffected in either mode - it never goes through cmd's parser - so the stdin(...) builders keep pipe semantics and UTF-8, verified intact. The shell therefore goes back to console-mode stdin and encodes what the user types with the remote ANSI code page, queried once per session from Win32_OperatingSystem.CodeSet (fallback windows-1252). Echo stays off: cmd.exe /Q alone suppresses it, and console-mode stdin never echoes. Console mode has no end of input, so the pump now translates the local EOF into an "exit" command; the remote exit code still propagates. New CommandRequest.stdinCharset(Charset) carries the asymmetry: output follows the console code page (UTF-8), console-mode input follows the ANSI one. Verified live on Windows Server 2008 R2: "echo testé français" echoes back intact, no input echo, EOF-only session exits 0, "exit 9" propagates 9. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
@codex please review again |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 674b9a96af
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…se of the mangled input The previous fix was wrong about the mechanism and only helped on Windows Server 2008 R2. Probing both a 2008 R2 and a 2022 host, in both stdin modes, with four input encodings each, gives one consistent answer: the culprit is console code page 65001 itself. A remote cmd.exe decodes the command lines it reads from its standard input ONE BYTE AT A TIME under 65001, so every non-ASCII byte becomes U+FFFD whatever the client sends - console mode only appeared to work on 2008 R2 because that version's service converted the bytes with the ANSI page first. Under ANY single-byte console code page (1252, 850, 437) every combination round-trips intact on both hosts. The shell therefore runs under the remote machine's ANSI code page, queried once per session from Win32_OperatingSystem.CodeSet (fallback 1252), with the matching charset on both directions. That page must be set when the shell is created, so the console code page is now a client-level setting (WinRMClient.Builder.consoleCodePage, plumbed to WINRS_CODEPAGE) and the CLI opens the session on a second connection once the probe has answered. Pipe-mode stdin comes back with it: under a single-byte page it carries non-ASCII fine, cmd.exe /Q keeps the echo off, and the local end-of-input is a real EOF again (no synthetic "exit" needed). Everything else keeps code page 65001 and UTF-8: wql, command, and data piped to a program never go through cmd's command-line parser. Verified live on Windows Server 2022 (French) and 2008 R2: "echo testé français" round-trips intact, banner correct, no echo, EOF exits, exit codes propagate. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
@codex please review again |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 8087838597
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…ls within the configured timeout - The consoleCodePage Javadoc had been inserted between the timeout Javadoc and timeout(Duration), leaving that public method undocumented. Moved back. - A bounded poll's budget is capped by the per-round-trip timeout STRICTLY again: raising it to the wire minimum made a poll outlast the inactivity tolerance its caller configured, contradicting both the CommandCursor and RemoteProcess contracts. A timeout below the protocol floor therefore keeps bounded polls local (no wire), which the Javadoc and the test now state explicitly - the unbounded paths (waitFor, the readers) still advance such a process, and the CLI's shell already rejects timeouts under 1 s. Re-verified live on Windows Server 2022: "echo testé français" intact, exit code propagated. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
@codex please review again |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 991c6dc6b3
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…one decision charsetOfCodePage() could fall back to windows-1252 while the shell was still created under the code page the host reported. The dangerous case is a host configured for UTF-8: it reports 65001 as its ANSI page, so the session would have run under exactly the code page an interactive cmd.exe cannot read command lines from - with a mismatched charset on top, corrupting both directions. sessionEncoding() now returns the code page AND the charset together, so they can never disagree, and refuses two answers by falling back on both counts: 65001 (unusable for a shell by construction) and any page this JVM has no charset for. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
@codex please review again |
|
Codex Review: Didn't find any major issues. Another round soon, please! Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
Closes #136 — phase 3 of the API modernization, built directly on the bounded-poll primitive of #111 (PR #134).
Phase 1 — stdin for commands (library)
Sendenvelope (rsp:Send, base64stdinstream,End="true"on the final chunk), thectrl_cSignal code next toterminate, and asend(byte[], end)/interrupt()seam onWsmanClient.RemoteCommandandCommandCursor. Input larger than one envelope is split automatically (96 KiB raw per Send, under the advertisedMaxEnvelopeSizeafter base64).stdin(String | Path | InputStream)onCommandRequest: pre-supplied input, delivered in full right after startup and ending with the End mark so the remote stdin reaches EOF. Supplying input switches the command to pipe semantics (WINRS_CONSOLEMODE_STDIN=FALSE) — filters likesortconsume it and terminate, exactly like a local< fileredirection; without it the historical console semantics (TRUE) are kept. Works with bothexecute()andstart().RemoteProcess.stdin()completes thejava.lang.Processshape: written text buffers locally,flush()emits one WSMan Send,close()sends the final chunk withEnd="true". Writes and reads alternate on the caller's thread — same serial connection, no concurrency — and the classic pipe deadlock is documented as the caller's to avoid, likeProcess.RemoteProcess.interrupt(): thectrl_cSignal — interrupts the remote child like a console Ctrl+C without ending the command or the session.RemoteProcess.poll(Duration): one bounded protocol round trip (the building block of the shell pump below); returns as soon as the server answers, expiry is not a failure.java.lang.Processpipe's).Phase 2 — interactive
shellsubcommand (CLI)cmd.exeremotely (console-mode stdin, likewinrs) and bridges it to the local terminal until it exits. The pump is single-threaded on the wire: drain queued local input → Send → bounded poll → forward decoded stdout/stderr; the only helper thread reads local stdin into a queue. An idle session never trips the inactivity timeout — every poll completes with output or the protocol's "nothing yet" fault.End="true"; Ctrl+C is rerouted (reflectivesun.misc.Signal, graceful fallback when absent) to the WSManctrl_cSignal, interrupting the remote child without killing the session; the remote exit code follows the existing CLI exit-code contract.commandbonus: piped/redirected local stdin is forwarded as the remote command's stdin —winrm-java ... command sort < data.txtjust works (console detection is injected, so tests stay deterministic).Bounded-poll fix (latent #134 bug exposed by the pump)
The WSMan service clamps
OperationTimeoutbelow 500 ms up to 500 ms (measured on a real Windows Server 2008 R2 host): a wire poll with a 200–500 ms budget always lost the race between the server's "nothing yet" fault (answered at the floor, not at the requested time) and its own socket cut, killing the connection.FakeWsmanServeranswers instantly, so no fake-server test could catch this. Wire polls now require a 750 ms budget (shorter waits are waited out locally, protocol untouched) and never ask the server for less than the 500 ms floor; the shell poll cadence is 1 s — it paces idle rounds only, output still echoes back with sub-second latency because a poll returns as soon as output exists.Tests & docs
FakeWsmanServerlearns Send: stdin chunks are decrypted, decoded, and exposed with theirEndflag (stdinChunks());FakeWsmanResponses.sendResponse()added.CommandStdinTest(9 tests): content, chunking (both the 64 KiB feed buffers and the 96 KiB envelope split),Endflag, console-mode option on the wire, a scripted write → flush → read REPL round trip, early close with stdin open, stdin after completion,ctrl_con the wire.InteractiveShellTest(4 tests): scripted pump rounds — input line → Send, scripted output → local stdout, output-before-input ordering, EOF →End="true", Ctrl+C →ctrl_cSignal with the session surviving, exit-code propagation.printf 'pear\napple\n' | ... command sortreturns the sorted lines, and a fullshellsession (banner,ver,echo %USERNAME%,exit 42) propagates exit code 42.cli.md(shell manual section, stdin forwarding, timeout semantics forshell),commands.md(stdin API, pipe-vs-console semantics, deadlock caveat), README one-liners.mvn verify sitegreen: 164 tests + IT, checkstyle / PMD / SpotBugs all at zero.🤖 Generated with Claude Code