You've already forked agentic-coding-workflow
76 lines
1.9 KiB
Go
76 lines
1.9 KiB
Go
//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
|
|
}
|