feat: add support for SSH RemoteCommand and RequestTTY in host configuration and TUI forms

- Allow users to specify a RemoteCommand to execute on SSH connection, both via TUI and config file
- Add RequestTTY option (yes, no, force, auto) to host configuration and forms
- Update config parsing and writing to handle new fields
- Improve TUI forms to support editing and adding these options
- Fix edit form standalone mode to allow proper quit/save via keyboard shortcuts
This commit is contained in:
2025-10-12 20:25:20 +02:00
parent 12d97270f0
commit c1457af73a
4 changed files with 171 additions and 58 deletions

View File

@@ -13,15 +13,17 @@ import (
// SSHHost represents an SSH host configuration
type SSHHost struct {
Name string
Hostname string
User string
Port string
Identity string
ProxyJump string
Options string
Tags []string
SourceFile string // Path to the config file where this host is defined
Name string
Hostname string
User string
Port string
Identity string
ProxyJump string
Options string
RemoteCommand string // Command to execute after SSH connection
RequestTTY string // Request TTY (yes, no, force, auto)
Tags []string
SourceFile string // Path to the config file where this host is defined
// Temporary field to handle multiple aliases during parsing
aliasNames []string `json:"-"` // Do not serialize this field
@@ -326,6 +328,14 @@ func parseSSHConfigFileWithProcessedFiles(configPath string, processedFiles map[
if currentHost != nil {
currentHost.ProxyJump = value
}
case "remotecommand":
if currentHost != nil {
currentHost.RemoteCommand = value
}
case "requesttty":
if currentHost != nil {
currentHost.RequestTTY = value
}
default:
// Handle other SSH options
if currentHost != nil && strings.TrimSpace(line) != "" {
@@ -603,6 +613,20 @@ func AddSSHHostToFile(host SSHHost, configPath string) error {
}
}
if host.RemoteCommand != "" {
_, err = file.WriteString(fmt.Sprintf(" RemoteCommand %s\n", host.RemoteCommand))
if err != nil {
return err
}
}
if host.RequestTTY != "" {
_, err = file.WriteString(fmt.Sprintf(" RequestTTY %s\n", host.RequestTTY))
if err != nil {
return err
}
}
// Write SSH options
if host.Options != "" {
// Split options by newlines and write each one
@@ -1020,6 +1044,12 @@ func UpdateSSHHostInFile(oldName string, newHost SSHHost, configPath string) err
if newHost.ProxyJump != "" {
newLines = append(newLines, " ProxyJump "+newHost.ProxyJump)
}
if newHost.RemoteCommand != "" {
newLines = append(newLines, " RemoteCommand "+newHost.RemoteCommand)
}
if newHost.RequestTTY != "" {
newLines = append(newLines, " RequestTTY "+newHost.RequestTTY)
}
// Write SSH options
if newHost.Options != "" {
options := strings.Split(newHost.Options, "\n")
@@ -1068,6 +1098,12 @@ func UpdateSSHHostInFile(oldName string, newHost SSHHost, configPath string) err
if newHost.ProxyJump != "" {
newLines = append(newLines, " ProxyJump "+newHost.ProxyJump)
}
if newHost.RemoteCommand != "" {
newLines = append(newLines, " RemoteCommand "+newHost.RemoteCommand)
}
if newHost.RequestTTY != "" {
newLines = append(newLines, " RequestTTY "+newHost.RequestTTY)
}
// Write SSH options
if newHost.Options != "" {
options := strings.Split(newHost.Options, "\n")
@@ -1152,6 +1188,12 @@ func UpdateSSHHostInFile(oldName string, newHost SSHHost, configPath string) err
if newHost.ProxyJump != "" {
newLines = append(newLines, " ProxyJump "+newHost.ProxyJump)
}
if newHost.RemoteCommand != "" {
newLines = append(newLines, " RemoteCommand "+newHost.RemoteCommand)
}
if newHost.RequestTTY != "" {
newLines = append(newLines, " RequestTTY "+newHost.RequestTTY)
}
// Write SSH options
if newHost.Options != "" {
options := strings.Split(newHost.Options, "\n")
@@ -1200,6 +1242,12 @@ func UpdateSSHHostInFile(oldName string, newHost SSHHost, configPath string) err
if newHost.ProxyJump != "" {
newLines = append(newLines, " ProxyJump "+newHost.ProxyJump)
}
if newHost.RemoteCommand != "" {
newLines = append(newLines, " RemoteCommand "+newHost.RemoteCommand)
}
if newHost.RequestTTY != "" {
newLines = append(newLines, " RequestTTY "+newHost.RequestTTY)
}
// Write SSH options
if newHost.Options != "" {
options := strings.Split(newHost.Options, "\n")
@@ -1694,6 +1742,12 @@ func UpdateMultiHostBlock(originalHosts, newHosts []string, commonProperties SSH
if commonProperties.ProxyJump != "" {
newLines = append(newLines, " ProxyJump "+commonProperties.ProxyJump)
}
if commonProperties.RemoteCommand != "" {
newLines = append(newLines, " RemoteCommand "+commonProperties.RemoteCommand)
}
if commonProperties.RequestTTY != "" {
newLines = append(newLines, " RequestTTY "+commonProperties.RequestTTY)
}
// Write SSH options
if commonProperties.Options != "" {
@@ -1774,6 +1828,12 @@ func UpdateMultiHostBlock(originalHosts, newHosts []string, commonProperties SSH
if commonProperties.ProxyJump != "" {
newLines = append(newLines, " ProxyJump "+commonProperties.ProxyJump)
}
if commonProperties.RemoteCommand != "" {
newLines = append(newLines, " RemoteCommand "+commonProperties.RemoteCommand)
}
if commonProperties.RequestTTY != "" {
newLines = append(newLines, " RequestTTY "+commonProperties.RequestTTY)
}
// Write SSH options
if commonProperties.Options != "" {