// PicoClaw - Ultra-lightweight personal AI agent // Inspired by and based on nanobot: https://github.com/HKUDS/nanobot // License: MIT // // Copyright (c) 2026 PicoClaw contributors package main import ( "fmt" "os" "time" "github.com/spf13/cobra" "github.com/sipeed/picoclaw/cmd/picoclaw/internal" "github.com/sipeed/picoclaw/cmd/picoclaw/internal/agent" "github.com/sipeed/picoclaw/cmd/picoclaw/internal/auth" "github.com/sipeed/picoclaw/cmd/picoclaw/internal/cliui" configcmd "github.com/sipeed/picoclaw/cmd/picoclaw/internal/config" "github.com/sipeed/picoclaw/cmd/picoclaw/internal/cron" "github.com/sipeed/picoclaw/cmd/picoclaw/internal/gateway" "github.com/sipeed/picoclaw/cmd/picoclaw/internal/mcp" "github.com/sipeed/picoclaw/cmd/picoclaw/internal/migrate" "github.com/sipeed/picoclaw/cmd/picoclaw/internal/model" "github.com/sipeed/picoclaw/cmd/picoclaw/internal/onboard" "github.com/sipeed/picoclaw/cmd/picoclaw/internal/skills" "github.com/sipeed/picoclaw/cmd/picoclaw/internal/status" "github.com/sipeed/picoclaw/cmd/picoclaw/internal/version" "github.com/sipeed/picoclaw/pkg/config" "github.com/sipeed/picoclaw/pkg/updater" ) var rootNoColor bool func syncCliUIColor(root *cobra.Command) { no, _ := root.PersistentFlags().GetBool("no-color") cliui.Init(no || os.Getenv("NO_COLOR") != "" || os.Getenv("TERM") == "dumb") } // earlyColorDisabled matches lipgloss/banner behavior from env and argv before Cobra parses flags. func earlyColorDisabled() bool { if os.Getenv("NO_COLOR") != "" || os.Getenv("TERM") == "dumb" { return true } for i := 1; i < len(os.Args); i++ { arg := os.Args[i] if arg == "--no-color" || arg == "--no-color=true" || arg == "--no-color=1" { return true } } return false } func NewPicoclawCommand() *cobra.Command { short := fmt.Sprintf("%s PicoClaw — personal AI assistant", internal.Logo) long := fmt.Sprintf(`%s PicoClaw is a lightweight personal AI assistant. Version: %s`, internal.Logo, config.FormatVersion()) cmd := &cobra.Command{ Use: "picoclaw", Short: short, Long: long, Example: `picoclaw version picoclaw onboard picoclaw --no-color status`, SilenceErrors: true, // Avoid plain UsageString() on stderr/stdout when a command fails; cliui // renders matching panels on stderr instead. SilenceUsage: true, PersistentPreRun: func(c *cobra.Command, _ []string) { syncCliUIColor(c.Root()) }, } cmd.PersistentFlags().BoolVar(&rootNoColor, "no-color", false, "Disable colors (boxed layout unchanged)") cmd.SetHelpFunc(func(c *cobra.Command, _ []string) { syncCliUIColor(c.Root()) fmt.Fprint(c.OutOrStdout(), cliui.RenderCommandHelp(c)) }) cmd.AddCommand( configcmd.NewConfigCommand(), onboard.NewOnboardCommand(), agent.NewAgentCommand(), auth.NewAuthCommand(), gateway.NewGatewayCommand(), status.NewStatusCommand(), cron.NewCronCommand(), mcp.NewMCPCommand(), migrate.NewMigrateCommand(), skills.NewSkillsCommand(), model.NewModelCommand(), updater.NewUpdateCommand("picoclaw"), version.NewVersionCommand(), ) return cmd } const ( 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" + colorBlue + "██╔═══╝ ██║██║ ██║ ██║" + colorRed + "██║ ██║ ██╔══██║██║███╗██║\n" + colorBlue + "██║ ██║╚██████╗╚██████╔╝" + colorRed + "╚██████╗███████╗██║ ██║╚███╔███╔╝\n" + colorBlue + "╚═╝ ╚═╝ ╚═════╝ ╚═════╝ " + colorRed + " ╚═════╝╚══════╝╚═╝ ╚═╝ ╚══╝╚══╝\n " + "\033[0m\r\n" plainBanner = "\r\n" + "██████╗ ██╗ ██████╗ ██████╗ ██████╗██╗ █████╗ ██╗ ██╗\n" + "██╔══██╗██║██╔════╝██╔═══██╗██╔════╝██║ ██╔══██╗██║ ██║\n" + "██████╔╝██║██║ ██║ ██║██║ ██║ ███████║██║ █╗ ██║\n" + "██╔═══╝ ██║██║ ██║ ██║██║ ██║ ██╔══██║██║███╗██║\n" + "██║ ██║╚██████╗╚██████╔╝╚██████╗███████╗██║ ██║╚███╔███╔╝\n" + "╚═╝ ╚═╝ ╚═════╝ ╚═════╝ ╚═════╝╚══════╝╚═╝ ╚═╝ ╚══╝╚══╝\n " + "\r\n" ) func main() { cliui.Init(earlyColorDisabled()) if earlyColorDisabled() { fmt.Print(plainBanner) } else { fmt.Printf("%s", banner) } tzEnv := os.Getenv("TZ") if tzEnv != "" { fmt.Println("TZ environment:", tzEnv) zoneinfoEnv := os.Getenv("ZONEINFO") fmt.Println("ZONEINFO environment:", zoneinfoEnv) loc, err := time.LoadLocation(tzEnv) if err != nil { fmt.Println("Error loading time zone:", err) } else { fmt.Println("Time zone loaded successfully:", loc) time.Local = loc //nolint:gosmopolitan // We intentionally set local timezone from TZ env } } cmd := NewPicoclawCommand() last, err := cmd.ExecuteC() if err != nil { syncCliUIColor(cmd) fmt.Fprint(os.Stderr, cliui.FormatCLIError(err.Error(), last)) os.Exit(1) } }