mirror of
https://github.com/sipeed/picoclaw.git
synced 2026-06-12 18:08:54 +00:00
3f653161e3
Add resetAppConfig API function, AlertDialog-confirmed factory reset button in config page, and i18n keys for en/zh/pt-br locales.
156 lines
6.0 KiB
Go
156 lines
6.0 KiB
Go
// 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)
|
|
}
|
|
}
|