@@ -33,6 +33,20 @@ type Stdio struct {
33
33
notifyMu sync.RWMutex
34
34
}
35
35
36
+ // NewIO returns a new stdio-based transport using existing input, output, and
37
+ // logging streams instead of spawning a subprocess.
38
+ // This is useful for testing and simulating client behavior.
39
+ func NewIO (input io.Reader , output io.WriteCloser , logging io.ReadCloser ) * Stdio {
40
+ return & Stdio {
41
+ stdin : output ,
42
+ stdout : bufio .NewReader (input ),
43
+ stderr : logging ,
44
+
45
+ responses : make (map [int64 ]chan * JSONRPCResponse ),
46
+ done : make (chan struct {}),
47
+ }
48
+ }
49
+
36
50
// NewStdio creates a new stdio transport to communicate with a subprocess.
37
51
// It launches the specified command with given arguments and sets up stdin/stdout pipes for communication.
38
52
// Returns an error if the subprocess cannot be started or the pipes cannot be created.
@@ -55,6 +69,26 @@ func NewStdio(
55
69
}
56
70
57
71
func (c * Stdio ) Start (ctx context.Context ) error {
72
+ if err := c .startProc (ctx ); err != nil {
73
+ return err
74
+ }
75
+
76
+ ready := make (chan struct {})
77
+ go func () {
78
+ close (ready )
79
+ c .readResponses ()
80
+ }()
81
+ <- ready
82
+
83
+ return nil
84
+ }
85
+
86
+ // startProc spawns a new process running c.command.
87
+ func (c * Stdio ) startProc (ctx context.Context ) error {
88
+ if c .command == "" {
89
+ return nil
90
+ }
91
+
58
92
cmd := exec .CommandContext (ctx , c .command , c .args ... )
59
93
60
94
mergedEnv := os .Environ ()
@@ -86,14 +120,6 @@ func (c *Stdio) Start(ctx context.Context) error {
86
120
return fmt .Errorf ("failed to start command: %w" , err )
87
121
}
88
122
89
- // Start reading responses in a goroutine and wait for it to be ready
90
- ready := make (chan struct {})
91
- go func () {
92
- close (ready )
93
- c .readResponses ()
94
- }()
95
- <- ready
96
-
97
123
return nil
98
124
}
99
125
@@ -107,7 +133,12 @@ func (c *Stdio) Close() error {
107
133
if err := c .stderr .Close (); err != nil {
108
134
return fmt .Errorf ("failed to close stderr: %w" , err )
109
135
}
110
- return c .cmd .Wait ()
136
+
137
+ if c .cmd != nil {
138
+ return c .cmd .Wait ()
139
+ }
140
+
141
+ return nil
111
142
}
112
143
113
144
// OnNotification registers a handler function to be called when notifications are received.
0 commit comments