From 5bce6a5401b3affeee0d111d92d6d6364ad7efdb Mon Sep 17 00:00:00 2001 From: Fornax <23104993+0xfornax@users.noreply.github.com> Date: Tue, 18 Aug 2026 14:04:28 -0300 Subject: [PATCH 1/5] error out and print a message when the user terminal is not supported to run the TUI --- rocketpool-cli/service/service.go | 6 +--- rocketpool-cli/service/tui_term.go | 48 ++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 5 deletions(-) create mode 100644 rocketpool-cli/service/tui_term.go diff --git a/rocketpool-cli/service/service.go b/rocketpool-cli/service/service.go index 45b73a7b6..74d28d04e 100644 --- a/rocketpool-cli/service/service.go +++ b/rocketpool-cli/service/service.go @@ -9,7 +9,6 @@ import ( "time" "github.com/mitchellh/go-homedir" - "github.com/rivo/tview" "github.com/urfave/cli/v3" "gopkg.in/yaml.v2" @@ -19,7 +18,6 @@ import ( cliutils "github.com/rocket-pool/smartnode/rocketpool-cli/cli" "github.com/rocket-pool/smartnode/rocketpool-cli/cli/color" "github.com/rocket-pool/smartnode/rocketpool-cli/cli/prompt" - cliconfig "github.com/rocket-pool/smartnode/rocketpool-cli/service/config" "github.com/rocket-pool/smartnode/shared" "github.com/rocket-pool/smartnode/shared/services/config" "github.com/rocket-pool/smartnode/shared/services/rocketpool" @@ -259,9 +257,7 @@ func configureService(configPath string, isNative, yes bool, composeFiles []stri isUpdate := !isNew && oldCfg != nil - app := tview.NewApplication() - md := cliconfig.NewMainDisplay(app, oldCfg, cfg, isNew, isUpdate, isNative) - err = app.Run() + md, err := runConfigTUI(oldCfg, cfg, isNew, isUpdate, isNative) if err != nil { return err } diff --git a/rocketpool-cli/service/tui_term.go b/rocketpool-cli/service/tui_term.go new file mode 100644 index 000000000..aab052126 --- /dev/null +++ b/rocketpool-cli/service/tui_term.go @@ -0,0 +1,48 @@ +package service + +import ( + "fmt" + "os" + "strings" + + "github.com/rivo/tview" + + cliconfig "github.com/rocket-pool/smartnode/rocketpool-cli/service/config" + snconfig "github.com/rocket-pool/smartnode/shared/services/config" +) + +func unsupportedTUITermError(term, termProgram string) error { + if term == "" { + term = "" + } + reason := fmt.Sprintf("TERM=%s", term) + if termProgram != "" { + reason += fmt.Sprintf(" (TERM_PROGRAM=%s)", termProgram) + } + return fmt.Errorf("the configuration UI does not support this terminal (%s).\nRetry with: TERM=xterm-256color rocketpool service config", reason) +} + +func isUnsupportedTUITerm(term, termProgram string) bool { + if term == "" || strings.EqualFold(term, "dumb") { + return true + } + if strings.Contains(strings.ToLower(term), "ghostty") { + return true + } + return strings.EqualFold(termProgram, "ghostty") +} + +func runConfigTUI(oldCfg, cfg *snconfig.RocketPoolConfig, isNew, isUpdate, isNative bool) (*cliconfig.MainDisplay, error) { + term := os.Getenv("TERM") + termProgram := os.Getenv("TERM_PROGRAM") + if isUnsupportedTUITerm(term, termProgram) { + return nil, unsupportedTUITermError(term, termProgram) + } + + app := tview.NewApplication() + md := cliconfig.NewMainDisplay(app, oldCfg, cfg, isNew, isUpdate, isNative) + if err := app.Run(); err != nil { + return nil, unsupportedTUITermError(term, termProgram) + } + return md, nil +} From f4ec5a6a3dca7cb109be07c388594a2ee5e8d619 Mon Sep 17 00:00:00 2001 From: Fornax <23104993+0xfornax@users.noreply.github.com> Date: Tue, 18 Aug 2026 14:46:41 -0300 Subject: [PATCH 2/5] Check for the specific ErrTermNotFound error --- rocketpool-cli/service/tui_term.go | 31 ++++++++++-------------------- 1 file changed, 10 insertions(+), 21 deletions(-) diff --git a/rocketpool-cli/service/tui_term.go b/rocketpool-cli/service/tui_term.go index aab052126..278ccfbfa 100644 --- a/rocketpool-cli/service/tui_term.go +++ b/rocketpool-cli/service/tui_term.go @@ -1,48 +1,37 @@ package service import ( + "errors" "fmt" "os" - "strings" + "github.com/gdamore/tcell/v2" + "github.com/gdamore/tcell/v2/terminfo" "github.com/rivo/tview" cliconfig "github.com/rocket-pool/smartnode/rocketpool-cli/service/config" snconfig "github.com/rocket-pool/smartnode/shared/services/config" ) -func unsupportedTUITermError(term, termProgram string) error { +func unsupportedTUITermError(term string) error { if term == "" { term = "" } - reason := fmt.Sprintf("TERM=%s", term) - if termProgram != "" { - reason += fmt.Sprintf(" (TERM_PROGRAM=%s)", termProgram) - } - return fmt.Errorf("the configuration UI does not support this terminal (%s).\nRetry with: TERM=xterm-256color rocketpool service config", reason) -} - -func isUnsupportedTUITerm(term, termProgram string) bool { - if term == "" || strings.EqualFold(term, "dumb") { - return true - } - if strings.Contains(strings.ToLower(term), "ghostty") { - return true - } - return strings.EqualFold(termProgram, "ghostty") + return fmt.Errorf("the configuration UI does not support this terminal (TERM=%s).\nRetry with: TERM=xterm-256color rocketpool service config", term) } func runConfigTUI(oldCfg, cfg *snconfig.RocketPoolConfig, isNew, isUpdate, isNative bool) (*cliconfig.MainDisplay, error) { term := os.Getenv("TERM") - termProgram := os.Getenv("TERM_PROGRAM") - if isUnsupportedTUITerm(term, termProgram) { - return nil, unsupportedTUITermError(term, termProgram) + // tcell.LookupTerminfo discards ErrTermNotFound and falls back to infocmp, + // which returns a raw exec.ExitError. Check the static database first. + if _, err := terminfo.LookupTerminfo(term); errors.Is(err, tcell.ErrTermNotFound) { + return nil, unsupportedTUITermError(term) } app := tview.NewApplication() md := cliconfig.NewMainDisplay(app, oldCfg, cfg, isNew, isUpdate, isNative) if err := app.Run(); err != nil { - return nil, unsupportedTUITermError(term, termProgram) + return nil, err } return md, nil } From 9a3d55993ad15b88670f2224c30dd3e89bf9ceb5 Mon Sep 17 00:00:00 2001 From: Fornax <23104993+0xfornax@users.noreply.github.com> Date: Tue, 18 Aug 2026 15:05:29 -0300 Subject: [PATCH 3/5] Bump tcell version --- go.mod | 6 +++--- go.sum | 15 +++++++-------- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/go.mod b/go.mod index 9ec424b40..95c2524ab 100644 --- a/go.mod +++ b/go.mod @@ -14,7 +14,7 @@ require ( github.com/fatih/color v1.19.0 github.com/felixge/fgprof v0.9.5 github.com/ferranbt/fastssz v0.1.4 - github.com/gdamore/tcell/v2 v2.6.0 + github.com/gdamore/tcell/v2 v2.13.9 github.com/glendc/go-external-ip v0.1.0 github.com/go-openapi/errors v0.21.0 github.com/go-openapi/runtime v0.27.1 @@ -87,7 +87,7 @@ require ( github.com/felixge/httpsnoop v1.1.0 // indirect github.com/fjl/jsonw v0.1.0 // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect - github.com/gdamore/encoding v1.0.0 // indirect + github.com/gdamore/encoding v1.0.1 // indirect github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect github.com/go-git/go-billy/v5 v5.9.0 // indirect github.com/go-git/go-git/v5 v5.19.2 // indirect @@ -122,7 +122,7 @@ require ( github.com/kevinburke/ssh_config v1.2.0 // indirect github.com/klauspost/cpuid/v2 v2.3.0 // indirect github.com/libp2p/go-buffer-pool v0.1.0 // indirect - github.com/lucasb-eyer/go-colorful v1.2.0 // indirect + github.com/lucasb-eyer/go-colorful v1.3.0 // indirect github.com/mailru/easyjson v0.7.7 // indirect github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-isatty v0.0.20 // indirect diff --git a/go.sum b/go.sum index eb8dd09a9..a6af279e1 100644 --- a/go.sum +++ b/go.sum @@ -265,10 +265,10 @@ github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4 github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08 h1:f6D9Hr8xV8uYKlyuj8XIruxlh9WjVjdh1gIicAS7ays= github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww= -github.com/gdamore/encoding v1.0.0 h1:+7OoQ1Bc6eTm5niUzBa0Ctsh6JbMW6Ra+YNuAtDBdko= -github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg= -github.com/gdamore/tcell/v2 v2.6.0 h1:OKbluoP9VYmJwZwq/iLb4BxwKcwGthaa1YNBJIyCySg= -github.com/gdamore/tcell/v2 v2.6.0/go.mod h1:be9omFATkdr0D9qewWW3d+MEvl5dha+Etb5y65J2H8Y= +github.com/gdamore/encoding v1.0.1 h1:YzKZckdBL6jVt2Gc+5p82qhrGiqMdG/eNs6Wy0u3Uhw= +github.com/gdamore/encoding v1.0.1/go.mod h1:0Z0cMFinngz9kS1QfMjCP8TY7em3bZYeeklsSDPivEo= +github.com/gdamore/tcell/v2 v2.13.9 h1:uI5l3DYPcFvHINKlGft+en23evOKL+dwtD21QR8ejVA= +github.com/gdamore/tcell/v2 v2.13.9/go.mod h1:+Wfe208WDdB7INEtCsNrAN6O2m+wsTPk1RAovjaILlo= github.com/getsentry/sentry-go v0.27.0 h1:Pv98CIbtB3LkMWmXi4Joa5OOcwbmnX88sF5qbK3r3Ps= github.com/getsentry/sentry-go v0.27.0/go.mod h1:lc76E2QywIyW8WuBnwl8Lc4bkmQH4+w1gwTf25trprY= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= @@ -597,8 +597,8 @@ github.com/libp2p/go-nat v0.2.0 h1:Tyz+bUFAYqGyJ/ppPPymMGbIgNRH+WqC5QrT5fKrrGk= github.com/libp2p/go-nat v0.2.0/go.mod h1:3MJr+GRpRkyT65EpVPBstXLvOlAPzUVlG6Pwg9ohLJk= github.com/libp2p/go-netroute v0.2.1 h1:V8kVrpD8GK0Riv15/7VN6RbUQ3URNZVosw7H2v9tksU= github.com/libp2p/go-netroute v0.2.1/go.mod h1:hraioZr0fhBjG0ZRXJJ6Zj2IVEVNx6tDTFQfSmcq7mQ= -github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= -github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= +github.com/lucasb-eyer/go-colorful v1.3.0 h1:2/yBRLdWBZKrf7gB40FoiKfAWYQ0lqNcbuQwVHXptag= +github.com/lucasb-eyer/go-colorful v1.3.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= @@ -622,7 +622,6 @@ github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWE github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk= -github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U= github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d h1:5PJl274Y63IEHC+7izoQE9x6ikvDFZS2mDVS3drnohI= @@ -842,7 +841,6 @@ github.com/rivo/tview v0.0.0-20230208211350-7dfff1ce7854 h1:/IIOjnKLbuO5YtZUZaJV github.com/rivo/tview v0.0.0-20230208211350-7dfff1ce7854/go.mod h1:lBUy/T5kyMudFzWUH/C2moN+NlU5qF505vzOyINXuUQ= github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= -github.com/rivo/uniseg v0.4.3/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/rocket-pool/go-merkletree v1.0.1-0.20220406020931-c262d9b976dd h1:p9KuetSKB9nte9I/MkkiM3pwKFVQgqxxPTQ0y56Ff6s= @@ -1253,6 +1251,7 @@ golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.40.0 h1:Ub2Z6/xjgF1WrYQz2nuITOEegKFtiIy+rieRJ5lHZKs= golang.org/x/text v0.40.0/go.mod h1:hpnzDAfGV753zIKo+wk3u1bVKCGPbrnF7+7LBF/UHVY= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= From f66a693f08abc3ff99f04c9287eda0d18c3484ee Mon Sep 17 00:00:00 2001 From: Fornax <23104993+0xfornax@users.noreply.github.com> Date: Tue, 18 Aug 2026 15:11:56 -0300 Subject: [PATCH 4/5] Revert "Check for the specific ErrTermNotFound error" This reverts commit f4ec5a6a3dca7cb109be07c388594a2ee5e8d619. --- rocketpool-cli/service/tui_term.go | 31 ++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/rocketpool-cli/service/tui_term.go b/rocketpool-cli/service/tui_term.go index 278ccfbfa..aab052126 100644 --- a/rocketpool-cli/service/tui_term.go +++ b/rocketpool-cli/service/tui_term.go @@ -1,37 +1,48 @@ package service import ( - "errors" "fmt" "os" + "strings" - "github.com/gdamore/tcell/v2" - "github.com/gdamore/tcell/v2/terminfo" "github.com/rivo/tview" cliconfig "github.com/rocket-pool/smartnode/rocketpool-cli/service/config" snconfig "github.com/rocket-pool/smartnode/shared/services/config" ) -func unsupportedTUITermError(term string) error { +func unsupportedTUITermError(term, termProgram string) error { if term == "" { term = "" } - return fmt.Errorf("the configuration UI does not support this terminal (TERM=%s).\nRetry with: TERM=xterm-256color rocketpool service config", term) + reason := fmt.Sprintf("TERM=%s", term) + if termProgram != "" { + reason += fmt.Sprintf(" (TERM_PROGRAM=%s)", termProgram) + } + return fmt.Errorf("the configuration UI does not support this terminal (%s).\nRetry with: TERM=xterm-256color rocketpool service config", reason) +} + +func isUnsupportedTUITerm(term, termProgram string) bool { + if term == "" || strings.EqualFold(term, "dumb") { + return true + } + if strings.Contains(strings.ToLower(term), "ghostty") { + return true + } + return strings.EqualFold(termProgram, "ghostty") } func runConfigTUI(oldCfg, cfg *snconfig.RocketPoolConfig, isNew, isUpdate, isNative bool) (*cliconfig.MainDisplay, error) { term := os.Getenv("TERM") - // tcell.LookupTerminfo discards ErrTermNotFound and falls back to infocmp, - // which returns a raw exec.ExitError. Check the static database first. - if _, err := terminfo.LookupTerminfo(term); errors.Is(err, tcell.ErrTermNotFound) { - return nil, unsupportedTUITermError(term) + termProgram := os.Getenv("TERM_PROGRAM") + if isUnsupportedTUITerm(term, termProgram) { + return nil, unsupportedTUITermError(term, termProgram) } app := tview.NewApplication() md := cliconfig.NewMainDisplay(app, oldCfg, cfg, isNew, isUpdate, isNative) if err := app.Run(); err != nil { - return nil, err + return nil, unsupportedTUITermError(term, termProgram) } return md, nil } From 52ff72f08db74b6f3903bfc68ca1f2788f10e162 Mon Sep 17 00:00:00 2001 From: Fornax <23104993+0xfornax@users.noreply.github.com> Date: Tue, 18 Aug 2026 15:11:56 -0300 Subject: [PATCH 5/5] Revert "error out and print a message when the user terminal is not supported to run the TUI" This reverts commit 5bce6a5401b3affeee0d111d92d6d6364ad7efdb. --- rocketpool-cli/service/service.go | 6 +++- rocketpool-cli/service/tui_term.go | 48 ------------------------------ 2 files changed, 5 insertions(+), 49 deletions(-) delete mode 100644 rocketpool-cli/service/tui_term.go diff --git a/rocketpool-cli/service/service.go b/rocketpool-cli/service/service.go index 74d28d04e..45b73a7b6 100644 --- a/rocketpool-cli/service/service.go +++ b/rocketpool-cli/service/service.go @@ -9,6 +9,7 @@ import ( "time" "github.com/mitchellh/go-homedir" + "github.com/rivo/tview" "github.com/urfave/cli/v3" "gopkg.in/yaml.v2" @@ -18,6 +19,7 @@ import ( cliutils "github.com/rocket-pool/smartnode/rocketpool-cli/cli" "github.com/rocket-pool/smartnode/rocketpool-cli/cli/color" "github.com/rocket-pool/smartnode/rocketpool-cli/cli/prompt" + cliconfig "github.com/rocket-pool/smartnode/rocketpool-cli/service/config" "github.com/rocket-pool/smartnode/shared" "github.com/rocket-pool/smartnode/shared/services/config" "github.com/rocket-pool/smartnode/shared/services/rocketpool" @@ -257,7 +259,9 @@ func configureService(configPath string, isNative, yes bool, composeFiles []stri isUpdate := !isNew && oldCfg != nil - md, err := runConfigTUI(oldCfg, cfg, isNew, isUpdate, isNative) + app := tview.NewApplication() + md := cliconfig.NewMainDisplay(app, oldCfg, cfg, isNew, isUpdate, isNative) + err = app.Run() if err != nil { return err } diff --git a/rocketpool-cli/service/tui_term.go b/rocketpool-cli/service/tui_term.go deleted file mode 100644 index aab052126..000000000 --- a/rocketpool-cli/service/tui_term.go +++ /dev/null @@ -1,48 +0,0 @@ -package service - -import ( - "fmt" - "os" - "strings" - - "github.com/rivo/tview" - - cliconfig "github.com/rocket-pool/smartnode/rocketpool-cli/service/config" - snconfig "github.com/rocket-pool/smartnode/shared/services/config" -) - -func unsupportedTUITermError(term, termProgram string) error { - if term == "" { - term = "" - } - reason := fmt.Sprintf("TERM=%s", term) - if termProgram != "" { - reason += fmt.Sprintf(" (TERM_PROGRAM=%s)", termProgram) - } - return fmt.Errorf("the configuration UI does not support this terminal (%s).\nRetry with: TERM=xterm-256color rocketpool service config", reason) -} - -func isUnsupportedTUITerm(term, termProgram string) bool { - if term == "" || strings.EqualFold(term, "dumb") { - return true - } - if strings.Contains(strings.ToLower(term), "ghostty") { - return true - } - return strings.EqualFold(termProgram, "ghostty") -} - -func runConfigTUI(oldCfg, cfg *snconfig.RocketPoolConfig, isNew, isUpdate, isNative bool) (*cliconfig.MainDisplay, error) { - term := os.Getenv("TERM") - termProgram := os.Getenv("TERM_PROGRAM") - if isUnsupportedTUITerm(term, termProgram) { - return nil, unsupportedTUITermError(term, termProgram) - } - - app := tview.NewApplication() - md := cliconfig.NewMainDisplay(app, oldCfg, cfg, isNew, isUpdate, isNative) - if err := app.Run(); err != nil { - return nil, unsupportedTUITermError(term, termProgram) - } - return md, nil -}