fix: capture TERM from PTY request to restore terminal colors on SSH sessions
Tests / Run Tests (pull_request) Successful in 2m4s
SonarQube Scan / SonarQube Trigger (push) Successful in 3m40s

This commit is contained in:
2026-03-10 20:47:52 +07:00
parent 88149088f0
commit a3ee50174b
2 changed files with 54 additions and 9 deletions
+32 -8
View File
@@ -53,6 +53,8 @@ type interaction struct {
cancel context.CancelFunc cancel context.CancelFunc
mode types.InteractiveMode mode types.InteractiveMode
programMu sync.Mutex programMu sync.Mutex
width int
height int
} }
func (i *interaction) SetMode(m types.InteractiveMode) { func (i *interaction) SetMode(m types.InteractiveMode) {
@@ -71,8 +73,14 @@ func (i *interaction) Send(message string) error {
return nil return nil
} }
func (i *interaction) SetWH(w, h int) { func (i *interaction) SetWH(w, h int) {
if i.program != nil { i.programMu.Lock()
i.program.Send(tea.WindowSizeMsg{ i.width = w
i.height = h
prog := i.program
i.programMu.Unlock()
if prog != nil {
prog.Send(tea.WindowSizeMsg{
Width: w, Width: w,
Height: h, Height: h,
}) })
@@ -158,8 +166,13 @@ func (m *model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
} }
func (i *interaction) Redraw() { func (i *interaction) Redraw() {
if i.program != nil { i.programMu.Lock()
i.program.Send(tea.WindowSizeMsg{}) prog := i.program
w, h := i.width, i.height
i.programMu.Unlock()
if prog != nil {
prog.Send(tea.WindowSizeMsg{Width: w, Height: h})
} }
} }
@@ -246,18 +259,29 @@ func (i *interaction) Start() {
} }
i.programMu.Lock() i.programMu.Lock()
i.program = tea.NewProgram( w, h := i.width, i.height
m, i.programMu.Unlock()
opts := []tea.ProgramOption{
tea.WithInput(i.channel), tea.WithInput(i.channel),
tea.WithOutput(i.channel), tea.WithOutput(i.channel),
tea.WithColorProfile(colorprofile.TrueColor), tea.WithColorProfile(colorprofile.TrueColor),
tea.WithoutSignals(), tea.WithoutSignals(),
tea.WithoutSignalHandler(), tea.WithoutSignalHandler(),
tea.WithFPS(30), tea.WithFPS(30),
) tea.WithEnvironment([]string{"TERM=xterm-256color", "COLORTERM=truecolor"}),
}
if w > 0 && h > 0 {
opts = append(opts, tea.WithWindowSize(w, h))
}
prog := tea.NewProgram(m, opts...)
i.programMu.Lock()
i.program = prog
i.programMu.Unlock() i.programMu.Unlock()
_, err := i.program.Run() _, err := prog.Run()
if err != nil { if err != nil {
log.Printf("Cannot close tea: %s \n", err) log.Printf("Cannot close tea: %s \n", err)
} }
+22 -1
View File
@@ -232,13 +232,34 @@ func (s *session) handleWindowChange(req *ssh.Request) error {
return req.Reply(true, nil) return req.Reply(true, nil)
} }
func (s *session) handlePtyReq(req *ssh.Request) error {
var ptyPayload struct {
Term string
Width uint32
Height uint32
PxW uint32
PxH uint32
Modes string
}
if err := ssh.Unmarshal(req.Payload, &ptyPayload); err == nil {
if ptyPayload.Width > 0 && ptyPayload.Height > 0 {
s.interaction.SetWH(int(ptyPayload.Width), int(ptyPayload.Height))
}
}
return req.Reply(true, nil)
}
func (s *session) HandleGlobalRequest(GlobalRequest <-chan *ssh.Request) error { func (s *session) HandleGlobalRequest(GlobalRequest <-chan *ssh.Request) error {
for req := range GlobalRequest { for req := range GlobalRequest {
switch req.Type { switch req.Type {
case "shell", "pty-req": case "shell":
if err := req.Reply(true, nil); err != nil { if err := req.Reply(true, nil); err != nil {
return err return err
} }
case "pty-req":
if err := s.handlePtyReq(req); err != nil {
return err
}
case "window-change": case "window-change":
if err := s.handleWindowChange(req); err != nil { if err := s.handleWindowChange(req); err != nil {
return err return err