|
1 | 1 | package root |
2 | 2 |
|
3 | 3 | import ( |
| 4 | + "context" |
4 | 5 | "fmt" |
5 | 6 | "log/slog" |
6 | 7 | "os" |
@@ -50,16 +51,52 @@ func newAPICmd() *cobra.Command { |
50 | 51 | return cmd |
51 | 52 | } |
52 | 53 |
|
| 54 | +// monitorStdin monitors stdin for EOF, which indicates the parent process has died. |
| 55 | +// When spawned with piped stdio, stdin closes when the parent process dies. |
| 56 | +func monitorStdin(ctx context.Context, cancel context.CancelFunc, stdin *os.File) { |
| 57 | + // Close stdin when context is cancelled to unblock the read |
| 58 | + go func() { |
| 59 | + <-ctx.Done() |
| 60 | + stdin.Close() |
| 61 | + }() |
| 62 | + |
| 63 | + buf := make([]byte, 1) |
| 64 | + for { |
| 65 | + n, err := stdin.Read(buf) |
| 66 | + if err != nil || n == 0 { |
| 67 | + // Only log and cancel if context isn't already done (parent died) |
| 68 | + if ctx.Err() == nil { |
| 69 | + slog.Info("stdin closed, parent process likely died, shutting down") |
| 70 | + cancel() |
| 71 | + } |
| 72 | + return |
| 73 | + } |
| 74 | + } |
| 75 | +} |
| 76 | + |
53 | 77 | func (f *apiFlags) runAPICommand(cmd *cobra.Command, args []string) error { |
54 | 78 | telemetry.TrackCommand("api", args) |
55 | 79 |
|
56 | 80 | ctx := cmd.Context() |
| 81 | + |
| 82 | + // Save stdin before clearing it, so we can monitor for parent death |
| 83 | + stdin := os.Stdin |
| 84 | + |
57 | 85 | out := cli.NewPrinter(cmd.OutOrStdout()) |
58 | 86 | agentsPath := args[0] |
59 | 87 |
|
60 | 88 | // Make sure no question is ever asked to the user in api mode. |
61 | 89 | os.Stdin = nil |
62 | 90 |
|
| 91 | + // Monitor stdin for EOF to detect parent process death. |
| 92 | + // When spawned with piped stdio, stdin closes when the parent process dies. |
| 93 | + if stdin != nil { |
| 94 | + var cancel context.CancelFunc |
| 95 | + ctx, cancel = context.WithCancel(ctx) |
| 96 | + defer cancel() |
| 97 | + go monitorStdin(ctx, cancel, stdin) |
| 98 | + } |
| 99 | + |
63 | 100 | // Start fake proxy if --fake is specified |
64 | 101 | cleanup, err := setupFakeProxy(f.fakeResponses, &f.runConfig) |
65 | 102 | if err != nil { |
|
0 commit comments