1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
//! Stdio safety guard for headless JSON-RPC servers.
//!
//! The `newt worker` and `newt mcp` subcommands use **stdout as the
//! JSON-RPC wire**. Any rogue `println!()` from a dependency would
//! interleave with protocol frames and corrupt the wire. Tracing is
//! already routed to stderr (see the binary `main.rs` files), but
//! `println!` and direct writes to fd 1 are harder to police — we
//! can't statically forbid them across the dep tree.
//!
//! [`redirect_stdout_to_stderr`] solves this structurally on Unix by:
//!
//! 1. `dup(1)` — clone the real stdout file descriptor.
//! 2. `dup2(2, 1)` — redirect fd 1 to where fd 2 (stderr) points.
//!
//! After this, `println!` (and any other write to fd 1) lands on
//! stderr. The returned [`std::fs::File`] is the private copy of the
//! real stdout — hand it to the JSON-RPC server as the writer.
//!
//! On non-Unix platforms this module is a no-op fallback that just
//! returns `std::io::stdout()` wrapped in a file-like interface
//! preserved via stdout; the foot-gun is documented as out-of-scope
//! there.
use File;
use FromRawFd;
/// Redirect process stdout to stderr and return a private file handle
/// pointing at the original stdout.
///
/// After calling this, anything that writes to fd 1 (the `println!`
/// macro, a dependency's stray `write!`, etc.) ends up on stderr.
/// The returned [`File`] is the **only** way to write to the real
/// stdout — the JSON-RPC server must use it as its writer.
///
/// # Safety
///
/// The `dup`/`dup2` calls are technically `unsafe` but the contract
/// is straightforward: we own the resulting raw fd, we wrap it in a
/// `File` so `Drop` closes it, and we never reuse the original fd 1
/// after redirection. Failure of either syscall returns an error
/// instead of panicking — the caller can fall back to plain stdout.
///
/// # Errors
///
/// Returns [`std::io::Error`] if either `dup` or `dup2` fails.
/// Non-Unix fallback: no redirection. Returns `None` and callers
/// should use plain stdout. The stdout-corruption foot-gun is
/// documented as out-of-scope on Windows for now — see the PR body.