From df19b8c708268a7641a13121afae850c5f3c25da Mon Sep 17 00:00:00 2001 From: XYSK-lilong007 <267018309+XYSK-lilong007@users.noreply.github.com> Date: Thu, 12 Mar 2026 01:21:29 +0800 Subject: [PATCH 1/3] fix: suppress banner in completion and redirected output --- cmd/picoclaw/main.go | 38 ++++++++++++++++++++++++++++++++++---- cmd/picoclaw/main_test.go | 25 +++++++++++++++++++++++++ 2 files changed, 59 insertions(+), 4 deletions(-) diff --git a/cmd/picoclaw/main.go b/cmd/picoclaw/main.go index b82475905..020adcce8 100644 --- a/cmd/picoclaw/main.go +++ b/cmd/picoclaw/main.go @@ -9,8 +9,10 @@ package main import ( "fmt" "os" + "strings" "github.com/spf13/cobra" + "golang.org/x/term" "github.com/sipeed/picoclaw/cmd/picoclaw/internal" "github.com/sipeed/picoclaw/cmd/picoclaw/internal/agent" @@ -50,9 +52,10 @@ func NewPicoclawCommand() *cobra.Command { } const ( - colorBlue = "\033[1;38;2;62;93;185m" - colorRed = "\033[1;38;2;213;70;70m" - banner = "\r\n" + + colorBlue = "\033[1;38;2;62;93;185m" + colorRed = "\033[1;38;2;213;70;70m" + noBannerEnv = "PICOCLAW_NO_BANNER" + banner = "\r\n" + colorBlue + "██████╗ ██╗ ██████╗ ██████╗ " + colorRed + " ██████╗██╗ █████╗ ██╗ ██╗\n" + colorBlue + "██╔══██╗██║██╔════╝██╔═══██╗" + colorRed + "██╔════╝██║ ██╔══██╗██║ ██║\n" + colorBlue + "██████╔╝██║██║ ██║ ██║" + colorRed + "██║ ██║ ███████║██║ █╗ ██║\n" + @@ -62,8 +65,35 @@ const ( "\033[0m\r\n" ) +func bannerDisabledByEnv() bool { + value := strings.TrimSpace(strings.ToLower(os.Getenv(noBannerEnv))) + switch value { + case "", "0", "false", "no", "off": + return false + default: + return true + } +} + +func shouldPrintBanner(args []string, stdoutIsTerminal bool) bool { + if bannerDisabledByEnv() || !stdoutIsTerminal { + return false + } + + if len(args) > 1 { + switch args[1] { + case "completion", cobra.ShellCompRequestCmd, cobra.ShellCompNoDescRequestCmd: + return false + } + } + + return true +} + func main() { - fmt.Printf("%s", banner) + if shouldPrintBanner(os.Args, term.IsTerminal(int(os.Stdout.Fd()))) { + fmt.Printf("%s", banner) + } cmd := NewPicoclawCommand() if err := cmd.Execute(); err != nil { os.Exit(1) diff --git a/cmd/picoclaw/main_test.go b/cmd/picoclaw/main_test.go index e622675ee..0096988af 100644 --- a/cmd/picoclaw/main_test.go +++ b/cmd/picoclaw/main_test.go @@ -5,6 +5,7 @@ import ( "slices" "testing" + "github.com/spf13/cobra" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -55,3 +56,27 @@ func TestNewPicoclawCommand(t *testing.T) { assert.False(t, subcmd.Hidden) } } + +func TestShouldPrintBanner(t *testing.T) { + t.Run("interactive command prints banner", func(t *testing.T) { + t.Setenv(noBannerEnv, "") + assert.True(t, shouldPrintBanner([]string{"picoclaw", "agent"}, true)) + }) + + t.Run("redirected stdout suppresses banner", func(t *testing.T) { + t.Setenv(noBannerEnv, "") + assert.False(t, shouldPrintBanner([]string{"picoclaw", "agent"}, false)) + }) + + t.Run("completion command suppresses banner", func(t *testing.T) { + t.Setenv(noBannerEnv, "") + assert.False(t, shouldPrintBanner([]string{"picoclaw", "completion", "zsh"}, true)) + assert.False(t, shouldPrintBanner([]string{"picoclaw", cobra.ShellCompRequestCmd}, true)) + assert.False(t, shouldPrintBanner([]string{"picoclaw", cobra.ShellCompNoDescRequestCmd}, true)) + }) + + t.Run("env disables banner", func(t *testing.T) { + t.Setenv(noBannerEnv, "1") + assert.False(t, shouldPrintBanner([]string{"picoclaw", "agent"}, true)) + }) +} From 73a1dbc8a6f1a07a37bb2877887079ebea66b306 Mon Sep 17 00:00:00 2001 From: XYSK-lilong007 <267018309+XYSK-lilong007@users.noreply.github.com> Date: Thu, 12 Mar 2026 01:58:14 +0800 Subject: [PATCH 2/3] test: extend banner guard coverage --- cmd/picoclaw/main.go | 9 +++++---- cmd/picoclaw/main_test.go | 19 +++++++++++++++++++ 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/cmd/picoclaw/main.go b/cmd/picoclaw/main.go index 020adcce8..7d8b22749 100644 --- a/cmd/picoclaw/main.go +++ b/cmd/picoclaw/main.go @@ -52,10 +52,9 @@ func NewPicoclawCommand() *cobra.Command { } const ( - colorBlue = "\033[1;38;2;62;93;185m" - colorRed = "\033[1;38;2;213;70;70m" - noBannerEnv = "PICOCLAW_NO_BANNER" - banner = "\r\n" + + colorBlue = "\033[1;38;2;62;93;185m" + colorRed = "\033[1;38;2;213;70;70m" + banner = "\r\n" + colorBlue + "██████╗ ██╗ ██████╗ ██████╗ " + colorRed + " ██████╗██╗ █████╗ ██╗ ██╗\n" + colorBlue + "██╔══██╗██║██╔════╝██╔═══██╗" + colorRed + "██╔════╝██║ ██╔══██╗██║ ██║\n" + colorBlue + "██████╔╝██║██║ ██║ ██║" + colorRed + "██║ ██║ ███████║██║ █╗ ██║\n" + @@ -65,6 +64,8 @@ const ( "\033[0m\r\n" ) +const noBannerEnv = "PICOCLAW_NO_BANNER" + func bannerDisabledByEnv() bool { value := strings.TrimSpace(strings.ToLower(os.Getenv(noBannerEnv))) switch value { diff --git a/cmd/picoclaw/main_test.go b/cmd/picoclaw/main_test.go index 0096988af..21106e734 100644 --- a/cmd/picoclaw/main_test.go +++ b/cmd/picoclaw/main_test.go @@ -79,4 +79,23 @@ func TestShouldPrintBanner(t *testing.T) { t.Setenv(noBannerEnv, "1") assert.False(t, shouldPrintBanner([]string{"picoclaw", "agent"}, true)) }) + + t.Run("common truthy env values disable banner", func(t *testing.T) { + for _, value := range []string{"true", "yes", "on"} { + t.Run(value, func(t *testing.T) { + t.Setenv(noBannerEnv, value) + assert.False(t, shouldPrintBanner([]string{"picoclaw", "agent"}, true)) + }) + } + }) + + t.Run("root command still prints banner in terminal", func(t *testing.T) { + t.Setenv(noBannerEnv, "") + assert.True(t, shouldPrintBanner([]string{"picoclaw"}, true)) + }) + + t.Run("unknown subcommand still prints banner in terminal", func(t *testing.T) { + t.Setenv(noBannerEnv, "") + assert.True(t, shouldPrintBanner([]string{"picoclaw", "unknown"}, true)) + }) } From fedfb6d84c66ca906368fa4fb04df9b537f18ad4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=BE=99=200668001470?= Date: Thu, 12 Mar 2026 23:27:29 +0800 Subject: [PATCH 3/3] test: cover normalized no-banner env values --- cmd/picoclaw/main_test.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cmd/picoclaw/main_test.go b/cmd/picoclaw/main_test.go index 21106e734..ab61ce0dc 100644 --- a/cmd/picoclaw/main_test.go +++ b/cmd/picoclaw/main_test.go @@ -80,9 +80,9 @@ func TestShouldPrintBanner(t *testing.T) { assert.False(t, shouldPrintBanner([]string{"picoclaw", "agent"}, true)) }) - t.Run("common truthy env values disable banner", func(t *testing.T) { - for _, value := range []string{"true", "yes", "on"} { - t.Run(value, func(t *testing.T) { + t.Run("truthy env values disable banner after normalization", func(t *testing.T) { + for _, value := range []string{"true", "yes", "on", " TrUe ", "\tON\n"} { + t.Run(fmt.Sprintf("%q", value), func(t *testing.T) { t.Setenv(noBannerEnv, value) assert.False(t, shouldPrintBanner([]string{"picoclaw", "agent"}, true)) })