//go:build windows package terminal import ( "io" "os" "os/exec" procgrp "github.com/yan1h/agent-coding-workflow/internal/infra/proc" ) // stdioBridge 把 shell 的 stdin(写端)与合并后的 stdout/stderr(读端)合成一个 // io.ReadWriteCloser,供降级实现使用。 type stdioBridge struct { stdin io.WriteCloser stdout io.ReadCloser } func (b *stdioBridge) Read(p []byte) (int, error) { return b.stdout.Read(p) } func (b *stdioBridge) Write(p []byte) (int, error) { return b.stdin.Write(p) } func (b *stdioBridge) Close() error { _ = b.stdin.Close() return b.stdout.Close() } // startPTY 是 Windows 降级实现:用普通管道桥接 stdin/stdout,无 PTY、无 resize, // 仅供本地开发调试,不追求生产可用(无行编辑/光标控制/作业控制)。 // // stdout/stderr 合并:手动建 os.Pipe,把写端同时交给子进程的 Stdout/Stderr,父进程 // Start 后立即关闭自己持有的写端;子进程退出后读端 pr 收到 EOF,read pump 据此感知结束。 func startPTY(shell string, env []string, rows, cols uint16) (*ptySession, error) { cmd := exec.Command(shell) cmd.Env = env pr, pw, err := os.Pipe() if err != nil { return nil, err } cmd.Stdout = pw cmd.Stderr = pw stdin, err := cmd.StdinPipe() if err != nil { _ = pr.Close() _ = pw.Close() return nil, err } group := procgrp.NewGroup() group.Prepare(cmd) // Windows: no-op if err := cmd.Start(); err != nil { _ = pr.Close() _ = pw.Close() _ = stdin.Close() return nil, err } _ = pw.Close() // 父进程放掉写端;子进程仍持有,退出后 pr 读到 EOF if err := group.Adopt(cmd); err != nil { if cmd.Process != nil { _ = cmd.Process.Kill() } _ = pr.Close() _ = stdin.Close() return nil, err } return &ptySession{ cmd: cmd, group: group, rw: &stdioBridge{stdin: stdin, stdout: pr}, resizeFn: nil, // 降级实现不支持 resize }, nil }