Compare commits

..
2 Commits
Author SHA1 Message Date
stefankoelle 37be0707ad Fix Windows: run tmux setup commands individually, attach via ExecProcess
psmux on Windows doesn't handle ; separators when args are passed
individually via exec.Command. Instead of chaining commands with ;,
run each setup command (new-session, set-option, split-window, etc.)
as individual exec.Command calls. Only tmux attach uses ExecProcess
so it properly takes over the terminal.
2026-08-09 21:34:46 +02:00
stefankoelle 9e6acdedc2 Fix Windows: use cmd.exe /c for tmux command chain
psmux on Windows doesn't handle ; separators when args are passed
individually via exec.Command. On Windows, build the full tmux
command string and run it through cmd.exe /c instead.
2026-08-09 21:27:37 +02:00
+22 -17
View File
@@ -280,35 +280,40 @@ func (m *fullModel) startTmuxSession() tea.Cmd {
ctxA := m.cfg.ResolveContext(envA, m.selectedContext) ctxA := m.cfg.ResolveContext(envA, m.selectedContext)
k9sCmdA := fmt.Sprintf("k9s --context %s -n %s", ctxA, m.selectedNamespace) k9sCmdA := fmt.Sprintf("k9s --context %s -n %s", ctxA, m.selectedNamespace)
// Kill stale session first (ignore error if none exists).
killErr := exec.Command("tmux", "kill-session", "-t", "kctl").Run()
fmt.Fprintf(os.Stderr, "[debug] selfPath=%s\n", selfPath) fmt.Fprintf(os.Stderr, "[debug] selfPath=%s\n", selfPath)
fmt.Fprintf(os.Stderr, "[debug] panelCmd=%s\n", panelCmd) fmt.Fprintf(os.Stderr, "[debug] panelCmd=%s\n", panelCmd)
fmt.Fprintf(os.Stderr, "[debug] kill-session err=%v\n", killErr)
args := []string{ // Kill stale session first (ignore error if none exists).
"new-session", "-d", "-s", "kctl", exec.Command("tmux", "kill-session", "-t", "kctl").Run()
panelCmd, ";",
"set-option", "-t", "kctl", "remain-on-exit", "on", ";", // Run setup commands individually — this avoids the ; separator
"split-window", "-v", "-t", "kctl:0.0", k9sCmdA, ";", // issue on Windows where psmux doesn't handle chained args.
setup := [][]string{
{"new-session", "-d", "-s", "kctl", panelCmd},
{"set-option", "-t", "kctl", "remain-on-exit", "on"},
{"split-window", "-v", "-t", "kctl:0.0", k9sCmdA},
} }
if len(m.cfg.Envs) > 1 { if len(m.cfg.Envs) > 1 {
envB := m.cfg.Envs[1] envB := m.cfg.Envs[1]
ctxB := m.cfg.ResolveContext(envB, m.selectedContext) ctxB := m.cfg.ResolveContext(envB, m.selectedContext)
k9sCmdB := fmt.Sprintf("k9s --context %s -n %s", ctxB, m.selectedNamespace) k9sCmdB := fmt.Sprintf("k9s --context %s -n %s", ctxB, m.selectedNamespace)
args = append(args, setup = append(setup, []string{"split-window", "-v", "-t", "kctl:0.1", k9sCmdB})
"split-window", "-v", "-t", "kctl:0.1", k9sCmdB, ";",
)
} }
args = append(args, setup = append(setup,
"select-layout", "-t", "kctl", "even-vertical", ";", []string{"select-layout", "-t", "kctl", "even-vertical"},
"select-pane", "-t", "kctl:0.0", ";", []string{"select-pane", "-t", "kctl:0.0"},
"attach", "-t", "kctl",
) )
fmt.Fprintf(os.Stderr, "[debug] tmux args: %v\n", args) for _, args := range setup {
c := exec.Command("tmux", args...) if out, err := exec.Command("tmux", args...).CombinedOutput(); err != nil {
fmt.Fprintf(os.Stderr, "[debug] tmux %s failed: %v\n%s\n", args[0], err, out)
return func() tea.Msg { return tmuxDoneMsg{err: fmt.Errorf("tmux %s: %w", args[0], err)} }
}
}
// Only attach uses tea.ExecProcess so it takes over the terminal.
fmt.Fprintf(os.Stderr, "[debug] tmux attach -t kctl\n")
c := exec.Command("tmux", "attach", "-t", "kctl")
return tea.ExecProcess(c, func(err error) tea.Msg { return tea.ExecProcess(c, func(err error) tea.Msg {
return tmuxDoneMsg{err: err} return tmuxDoneMsg{err: err}
}) })