monitorProcess signals when the CLI process exits and captures any exit error. processError is intentionally a local: each process lifecycle gets its own error value, so goroutines from previous processes can't overwrite the current one. Closing the channel synchronizes with readers, guaranteeing th
()
| 1960 | // current one. Closing the channel synchronizes with readers, guaranteeing |
| 1961 | // they see the final processError value. |
| 1962 | func (c *Client) monitorProcess() { |
| 1963 | done := make(chan struct{}) |
| 1964 | c.processDone = done |
| 1965 | proc := c.process |
| 1966 | c.osProcess.Store(proc.Process) |
| 1967 | var processError error |
| 1968 | c.processErrorPtr = &processError |
| 1969 | go func() { |
| 1970 | waitErr := proc.Wait() |
| 1971 | var stderrOutput string |
| 1972 | if buf, ok := proc.Stderr.(*truncbuffer.TruncBuffer); ok { |
| 1973 | stderrOutput = strings.TrimSpace(buf.String()) |
| 1974 | } |
| 1975 | if waitErr != nil { |
| 1976 | if stderrOutput != "" { |
| 1977 | processError = fmt.Errorf("CLI process exited: %w\nstderr: %s", waitErr, stderrOutput) |
| 1978 | } else { |
| 1979 | processError = fmt.Errorf("CLI process exited: %w", waitErr) |
| 1980 | } |
| 1981 | } else { |
| 1982 | if stderrOutput != "" { |
| 1983 | processError = fmt.Errorf("CLI process exited unexpectedly\nstderr: %s", stderrOutput) |
| 1984 | } else { |
| 1985 | processError = errors.New("CLI process exited unexpectedly") |
| 1986 | } |
| 1987 | } |
| 1988 | close(done) |
| 1989 | }() |
| 1990 | } |
| 1991 | |
| 1992 | // connectToServer establishes a connection to the server. |
| 1993 | func (c *Client) connectToServer(ctx context.Context) error { |