From ad7d8534ab019ee6a4dfe6e3da7c90bb428e8ebd Mon Sep 17 00:00:00 2001 From: Stefan Koelle Date: Wed, 16 Sep 2026 22:20:42 +0200 Subject: [PATCH] feat: improve Windows Terminal split ratios and update error handling - Split ratios: panel 25%, k9sA 37.5%, k9sB 37.5% (was 50/25/25) - Update failures now exit with error code 1 instead of continuing with old version --- cmd/kctl-tui/full.go | 6 ++++-- cmd/kctl-tui/main.go | 7 ++++++- cmd/kctl-tui/update.go | 24 ++++++++++++------------ 3 files changed, 22 insertions(+), 15 deletions(-) diff --git a/cmd/kctl-tui/full.go b/cmd/kctl-tui/full.go index 3d5334d..2bd99ff 100644 --- a/cmd/kctl-tui/full.go +++ b/cmd/kctl-tui/full.go @@ -337,6 +337,8 @@ func (m *fullModel) startTmuxSessionTmux() tea.Cmd { // split-pane feature. This avoids the psmux focus-freeze issue on Windows. // Note: In Windows Terminal, -H (horizontal) stacks panes top/bottom, // while -V (vertical) places them side by side — opposite of tmux. +// The -s flag controls the split ratio: first split gives k9sA 75% +// (panel keeps 25%), second split divides k9sA equally (37.5% each). func (m *fullModel) startWtSession() tea.Cmd { selfPath, err := os.Executable() if err != nil { @@ -353,14 +355,14 @@ func (m *fullModel) startWtSession() tea.Cmd { kubeexec.VerboseLog("[debug] panelCmd=%s\n", panelCmd) kubeexec.VerboseLog("[debug] k9sCmdA=%s\n", k9sCmdA) - wtCmd := fmt.Sprintf("wt new-tab %s ; split-pane -H %s", panelCmd, k9sCmdA) + wtCmd := fmt.Sprintf("wt new-tab %s ; split-pane -H -s 0.75 %s", panelCmd, k9sCmdA) if len(m.cfg.Envs) > 1 { envB := m.cfg.Envs[1] ctxB := m.cfg.ResolveContext(envB, m.selectedContext) k9sCmdB := fmt.Sprintf("k9s --context %s --namespace %s --command pods", ctxB, m.selectedNamespace) kubeexec.VerboseLog("[debug] k9sCmdB=%s\n", k9sCmdB) - wtCmd += fmt.Sprintf(" ; split-pane -H %s", k9sCmdB) + wtCmd += fmt.Sprintf(" ; split-pane -H -s 0.5 %s", k9sCmdB) } c := exec.Command("cmd", "/c", wtCmd) diff --git a/cmd/kctl-tui/main.go b/cmd/kctl-tui/main.go index e863e4e..d1bf7c9 100644 --- a/cmd/kctl-tui/main.go +++ b/cmd/kctl-tui/main.go @@ -94,7 +94,12 @@ func main() { fmt.Fprintf(os.Stderr, "WARNING: failed to load config: %v\n", cfgErr) } if cfgErr == nil && cfg.IsAutoUpdateCheckEnabled() { - if checkForUpdateInteractive(verbose) { + updated, err := checkForUpdateInteractive(verbose) + if err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + if updated { os.Exit(0) } } diff --git a/cmd/kctl-tui/update.go b/cmd/kctl-tui/update.go index c9572e2..c77de5d 100644 --- a/cmd/kctl-tui/update.go +++ b/cmd/kctl-tui/update.go @@ -83,14 +83,15 @@ func runUpdate(verbose bool) error { } // checkForUpdateInteractive checks for a new version and prompts the user to update. -// Returns true if an update was applied. -func checkForUpdateInteractive(verbose bool) bool { +// Returns (true, nil) if an update was applied successfully, (false, nil) if no +// update was needed or the user declined, and (false, err) if the update failed. +func checkForUpdateInteractive(verbose bool) (bool, error) { if version == "dev" { - return false + return false, nil } if !term.IsTerminal(int(os.Stdin.Fd())) { - return false + return false, nil } updater, err := initUpdater(verbose) @@ -98,7 +99,7 @@ func checkForUpdateInteractive(verbose bool) bool { if verbose { fmt.Fprintf(os.Stderr, "Update check failed: %v\n", err) } - return false + return false, nil } ctx, cancel := context.WithTimeout(context.Background(), updateTimeout) @@ -110,10 +111,10 @@ func checkForUpdateInteractive(verbose bool) bool { if verbose { fmt.Fprintf(os.Stderr, "Update check failed: %v\n", err) } - return false + return false, nil } if !found { - return false + return false, nil } current, _ := semver.NewVersion(version) @@ -121,7 +122,7 @@ func checkForUpdateInteractive(verbose bool) bool { newVer, _ := semver.NewVersion(newVersion) if current != nil && !current.LessThan(newVer) { - return false + return false, nil } fmt.Printf("New version %s available (current: %s). Update now? [y/N] ", newVersion, version) @@ -131,17 +132,16 @@ func checkForUpdateInteractive(verbose bool) bool { answer = strings.TrimSpace(strings.ToLower(answer)) if answer != "y" && answer != "yes" { - return false + return false, nil } fmt.Println("Updating...") if err := updater.UpdateTo(ctx, rel, ""); err != nil { - fmt.Fprintf(os.Stderr, "Update failed: %v\n", err) - return false + return false, fmt.Errorf("update failed: %w", err) } fmt.Printf("Updated to %s. Please restart kctl-tui.\n", newVersion) - return true + return true, nil } type verboseLogger struct{}