diff --git a/cmd/picoclaw-launcher-tui/config/config.go b/cmd/picoclaw-launcher-tui/config/config.go index 64d479285..227b9fa3d 100644 --- a/cmd/picoclaw-launcher-tui/config/config.go +++ b/cmd/picoclaw-launcher-tui/config/config.go @@ -14,6 +14,7 @@ import ( "path/filepath" "github.com/BurntSushi/toml" + "github.com/sipeed/picoclaw/pkg/fileutil" ) @@ -160,44 +161,44 @@ func SyncSelectedModelToMainConfig(scheme Scheme, user User, modelID string) err } mainConfigPath := filepath.Join(home, ".picoclaw", "config.json") - var cfg map[string]interface{} - if data, err := os.ReadFile(mainConfigPath); err == nil { - if err := json.Unmarshal(data, &cfg); err != nil { - cfg = make(map[string]interface{}) + var cfg map[string]any + if data, readErr := os.ReadFile(mainConfigPath); readErr == nil { + if unmarshalErr := json.Unmarshal(data, &cfg); unmarshalErr != nil { + cfg = make(map[string]any) } } else { - cfg = make(map[string]interface{}) + cfg = make(map[string]any) } if _, ok := cfg["agents"]; !ok { - cfg["agents"] = make(map[string]interface{}) + cfg["agents"] = make(map[string]any) } - agents, ok := cfg["agents"].(map[string]interface{}) + agents, ok := cfg["agents"].(map[string]any) if ok { if _, ok := agents["defaults"]; !ok { - agents["defaults"] = make(map[string]interface{}) + agents["defaults"] = make(map[string]any) } - defaults, ok := agents["defaults"].(map[string]interface{}) + defaults, ok := agents["defaults"].(map[string]any) if ok { defaults["model"] = "tui-prefer" } } - tuiModel := map[string]interface{}{ + tuiModel := map[string]any{ "model_name": "tui-prefer", "model": modelID, "api_key": user.Key, "api_base": scheme.BaseURL, } - modelList := []interface{}{} - if ml, ok := cfg["model_list"].([]interface{}); ok { + modelList := []any{} + if ml, ok := cfg["model_list"].([]any); ok { modelList = ml } found := false for i, m := range modelList { - if entry, ok := m.(map[string]interface{}); ok { + if entry, ok := m.(map[string]any); ok { if name, ok := entry["model_name"].(string); ok && name == "tui-prefer" { modelList[i] = tuiModel found = true diff --git a/cmd/picoclaw-launcher-tui/ui/app.go b/cmd/picoclaw-launcher-tui/ui/app.go index 512277129..a65693b01 100644 --- a/cmd/picoclaw-launcher-tui/ui/app.go +++ b/cmd/picoclaw-launcher-tui/ui/app.go @@ -11,6 +11,7 @@ import ( "github.com/gdamore/tcell/v2" "github.com/rivo/tview" + tuicfg "github.com/sipeed/picoclaw/cmd/picoclaw-launcher-tui/config" ) @@ -79,7 +80,6 @@ func (a *App) refreshModelCache(onDone func()) { continue } wg.Add(1) - u := u bURL := baseURL go func() { defer wg.Done() diff --git a/cmd/picoclaw-launcher-tui/ui/channels.go b/cmd/picoclaw-launcher-tui/ui/channels.go index 4ba87b617..c976f1fcd 100644 --- a/cmd/picoclaw-launcher-tui/ui/channels.go +++ b/cmd/picoclaw-launcher-tui/ui/channels.go @@ -19,10 +19,15 @@ import ( func (a *App) newChannelsPage() tview.Primitive { list := tview.NewList() - list.SetBorder(true).SetTitle(" [#00f0ff::b] COMMUNICATION CHANNELS ").SetTitleColor(tcell.NewHexColor(0x00f0ff)).SetBorderColor(tcell.NewHexColor(0x00f0ff)) + list.SetBorder(true). + SetTitle(" [#00f0ff::b] COMMUNICATION CHANNELS "). + SetTitleColor(tcell.NewHexColor(0x00f0ff)). + SetBorderColor(tcell.NewHexColor(0x00f0ff)) list.SetMainTextColor(tcell.NewHexColor(0xe0e0e0)) list.SetSecondaryTextColor(tcell.NewHexColor(0x808080)) - list.SetSelectedStyle(tcell.StyleDefault.Background(tcell.NewHexColor(0xff00ff)).Foreground(tcell.NewHexColor(0x050510))) + list.SetSelectedStyle( + tcell.StyleDefault.Background(tcell.NewHexColor(0xff00ff)).Foreground(tcell.NewHexColor(0x050510)), + ) list.SetHighlightFullLine(true) list.SetBackgroundColor(tcell.NewHexColor(0x050510)) @@ -36,14 +41,14 @@ func (a *App) newChannelsPage() tview.Primitive { } configPath := filepath.Join(home, ".picoclaw", "config.json") - var cfg map[string]interface{} + var cfg map[string]any if data, err := os.ReadFile(configPath); err == nil { _ = json.Unmarshal(data, &cfg) } - if chRaw, ok := cfg["channels"].(map[string]interface{}); ok { + if chRaw, ok := cfg["channels"].(map[string]any); ok { for name, ch := range chRaw { - chMap, ok := ch.(map[string]interface{}) + chMap, ok := ch.(map[string]any) enabled := "disabled" if ok { if e, ok := chMap["enabled"].(bool); ok && e { @@ -74,9 +79,12 @@ func (a *App) newChannelsPage() tview.Primitive { return a.buildShell("channels", list, " [#ff00ff]Enter:[-] edit [#ff2a2a]ESC:[-] back ") } -func (a *App) showChannelEditForm(configPath, channelName string, existing map[string]interface{}) { +func (a *App) showChannelEditForm(configPath, channelName string, existing map[string]any) { form := tview.NewForm() - form.SetBorder(true).SetTitle(" [::b]EDIT CHANNEL ").SetTitleColor(tcell.NewHexColor(0x39ff14)).SetBorderColor(tcell.NewHexColor(0x00f0ff)) + form.SetBorder(true). + SetTitle(" [::b]EDIT CHANNEL "). + SetTitleColor(tcell.NewHexColor(0x39ff14)). + SetBorderColor(tcell.NewHexColor(0x00f0ff)) form.SetBackgroundColor(tcell.NewHexColor(0x1a1a2e)) form.SetFieldBackgroundColor(tcell.NewHexColor(0x050510)) form.SetFieldTextColor(tcell.NewHexColor(0x00f0ff)) @@ -109,21 +117,21 @@ func (a *App) showChannelEditForm(configPath, channelName string, existing map[s } form.AddButton("SAVE", func() { - var cfg map[string]interface{} + var cfg map[string]any if data, err := os.ReadFile(configPath); err == nil { if err := json.Unmarshal(data, &cfg); err != nil { - cfg = make(map[string]interface{}) + cfg = make(map[string]any) } } else { - cfg = make(map[string]interface{}) + cfg = make(map[string]any) } if _, ok := cfg["channels"]; !ok { - cfg["channels"] = make(map[string]interface{}) + cfg["channels"] = make(map[string]any) } - channels, ok := cfg["channels"].(map[string]interface{}) + channels, ok := cfg["channels"].(map[string]any) if !ok { - channels = make(map[string]interface{}) + channels = make(map[string]any) cfg["channels"] = channels } @@ -136,7 +144,7 @@ func (a *App) showChannelEditForm(configPath, channelName string, existing map[s finalName = nameField.GetText() } - updated := make(map[string]interface{}) + updated := make(map[string]any) if existing != nil { for k, v := range existing { updated[k] = v diff --git a/cmd/picoclaw-launcher-tui/ui/gateway.go b/cmd/picoclaw-launcher-tui/ui/gateway.go index d71f7b488..1138c12db 100644 --- a/cmd/picoclaw-launcher-tui/ui/gateway.go +++ b/cmd/picoclaw-launcher-tui/ui/gateway.go @@ -98,7 +98,14 @@ func startGateway() error { time.Sleep(1 * time.Second) if runtime.GOOS == "windows" { - cmd := exec.Command("wmic", "process", "where", "name='picoclaw.exe' and commandline like '%gateway%'", "get", "processid") + cmd := exec.Command( + "wmic", + "process", + "where", + "name='picoclaw.exe' and commandline like '%gateway%'", + "get", + "processid", + ) output, err := cmd.Output() if err != nil { return fmt.Errorf("failed to get gateway PID: %w", err) @@ -154,7 +161,10 @@ func stopGateway() error { func (a *App) newGatewayPage() tview.Primitive { flex := tview.NewFlex().SetDirection(tview.FlexRow) - flex.SetBorder(true).SetTitle(" [#00f0ff::b] GATEWAY MANAGEMENT ").SetTitleColor(tcell.NewHexColor(0x00f0ff)).SetBorderColor(tcell.NewHexColor(0x00f0ff)) + flex.SetBorder(true). + SetTitle(" [#00f0ff::b] GATEWAY MANAGEMENT "). + SetTitleColor(tcell.NewHexColor(0x00f0ff)). + SetBorderColor(tcell.NewHexColor(0x00f0ff)) flex.SetBackgroundColor(tcell.NewHexColor(0x050510)) statusTV := tview.NewTextView(). diff --git a/cmd/picoclaw-launcher-tui/ui/home.go b/cmd/picoclaw-launcher-tui/ui/home.go index 6d906eccd..74a7769cf 100644 --- a/cmd/picoclaw-launcher-tui/ui/home.go +++ b/cmd/picoclaw-launcher-tui/ui/home.go @@ -15,10 +15,15 @@ import ( func (a *App) newHomePage() tview.Primitive { list := tview.NewList() - list.SetBorder(true).SetTitle(" [#00f0ff::b] ACTIVE CONFIGURATION ").SetTitleColor(tcell.NewHexColor(0x00f0ff)).SetBorderColor(tcell.NewHexColor(0x00f0ff)) + list.SetBorder(true). + SetTitle(" [#00f0ff::b] ACTIVE CONFIGURATION "). + SetTitleColor(tcell.NewHexColor(0x00f0ff)). + SetBorderColor(tcell.NewHexColor(0x00f0ff)) list.SetMainTextColor(tcell.NewHexColor(0xe0e0e0)) list.SetSecondaryTextColor(tcell.NewHexColor(0x808080)) - list.SetSelectedStyle(tcell.StyleDefault.Background(tcell.NewHexColor(0x39ff14)).Foreground(tcell.NewHexColor(0x050510))) + list.SetSelectedStyle( + tcell.StyleDefault.Background(tcell.NewHexColor(0x39ff14)).Foreground(tcell.NewHexColor(0x050510)), + ) list.SetHighlightFullLine(true) list.SetBackgroundColor(tcell.NewHexColor(0x050510)) @@ -28,9 +33,14 @@ func (a *App) newHomePage() tview.Primitive { list.AddItem("MODEL: "+a.cfg.CurrentModelLabel(), "Select to configure AI model", 'm', func() { a.navigateTo("schemes", a.newSchemesPage()) }) - list.AddItem("CHANNELS: Configure communication channels", "Manage Telegram/Discord/WeChat channels", 'n', func() { - a.navigateTo("channels", a.newChannelsPage()) - }) + list.AddItem( + "CHANNELS: Configure communication channels", + "Manage Telegram/Discord/WeChat channels", + 'n', + func() { + a.navigateTo("channels", a.newChannelsPage()) + }, + ) list.AddItem("GATEWAY MANAGEMENT", "Manage PicoClaw gateway daemon", 'g', func() { a.navigateTo("gateway", a.newGatewayPage()) }) @@ -52,5 +62,9 @@ func (a *App) newHomePage() tview.Primitive { a.pageRefreshFns["home"] = rebuildList - return a.buildShell("home", list, " [#00f0ff]m:[-] model [#00f0ff]n:[-] channels [#00f0ff]g:[-] gateway [#00f0ff]c:[-] chat [#ff2a2a]q:[-] quit ") + return a.buildShell( + "home", + list, + " [#00f0ff]m:[-] model [#00f0ff]n:[-] channels [#00f0ff]g:[-] gateway [#00f0ff]c:[-] chat [#ff2a2a]q:[-] quit ", + ) } diff --git a/cmd/picoclaw-launcher-tui/ui/models.go b/cmd/picoclaw-launcher-tui/ui/models.go index 1f9484b26..20e5f0182 100644 --- a/cmd/picoclaw-launcher-tui/ui/models.go +++ b/cmd/picoclaw-launcher-tui/ui/models.go @@ -15,6 +15,7 @@ import ( "github.com/gdamore/tcell/v2" "github.com/rivo/tview" + tuicfg "github.com/sipeed/picoclaw/cmd/picoclaw-launcher-tui/config" ) @@ -33,8 +34,13 @@ func (a *App) newModelsPage(schemeName, userName, baseURL string) tview.Primitiv SetBorders(false). SetSelectable(true, false). SetFixed(0, 0) - table.SetBorder(true).SetTitle(fmt.Sprintf(" [#00f0ff::b] MODELS · %s / %s ", schemeName, userName)).SetTitleColor(tcell.NewHexColor(0x00f0ff)).SetBorderColor(tcell.NewHexColor(0x00f0ff)) - table.SetSelectedStyle(tcell.StyleDefault.Background(tcell.NewHexColor(0xff00ff)).Foreground(tcell.NewHexColor(0xffffff))) + table.SetBorder(true). + SetTitle(fmt.Sprintf(" [#00f0ff::b] MODELS · %s / %s ", schemeName, userName)). + SetTitleColor(tcell.NewHexColor(0x00f0ff)). + SetBorderColor(tcell.NewHexColor(0x00f0ff)) + table.SetSelectedStyle( + tcell.StyleDefault.Background(tcell.NewHexColor(0xff00ff)).Foreground(tcell.NewHexColor(0xffffff)), + ) table.SetBackgroundColor(tcell.NewHexColor(0x050510)) var modelIDs []string @@ -187,5 +193,8 @@ func fetchModels(baseURL, apiKey string) ([]modelEntry, error) { return arr, nil } - return nil, fmt.Errorf("decode response: unrecognised shape: %s", strings.TrimSpace(string(body[:min(len(body), 256)]))) + return nil, fmt.Errorf( + "decode response: unrecognized shape: %s", + strings.TrimSpace(string(body[:min(len(body), 256)])), + ) } diff --git a/cmd/picoclaw-launcher-tui/ui/schemes.go b/cmd/picoclaw-launcher-tui/ui/schemes.go index 70375eccc..e38d7fa86 100644 --- a/cmd/picoclaw-launcher-tui/ui/schemes.go +++ b/cmd/picoclaw-launcher-tui/ui/schemes.go @@ -10,6 +10,7 @@ import ( "github.com/gdamore/tcell/v2" "github.com/rivo/tview" + tuicfg "github.com/sipeed/picoclaw/cmd/picoclaw-launcher-tui/config" ) @@ -17,8 +18,13 @@ func (a *App) newSchemesPage() tview.Primitive { table := tview.NewTable(). SetBorders(false). SetSelectable(true, false) - table.SetBorder(true).SetTitle(" [#00f0ff::b] PROVIDER SCHEMES ").SetTitleColor(tcell.NewHexColor(0x00f0ff)).SetBorderColor(tcell.NewHexColor(0x00f0ff)) - table.SetSelectedStyle(tcell.StyleDefault.Background(tcell.NewHexColor(0xff00ff)).Foreground(tcell.NewHexColor(0xffffff))) + table.SetBorder(true). + SetTitle(" [#00f0ff::b] PROVIDER SCHEMES "). + SetTitleColor(tcell.NewHexColor(0x00f0ff)). + SetBorderColor(tcell.NewHexColor(0x00f0ff)) + table.SetSelectedStyle( + tcell.StyleDefault.Background(tcell.NewHexColor(0xff00ff)).Foreground(tcell.NewHexColor(0xffffff)), + ) table.SetBackgroundColor(tcell.NewHexColor(0x050510)) rowToIdx := func(row int) int { return row / 2 } @@ -165,7 +171,11 @@ func (a *App) newSchemesPage() tview.Primitive { return event }) - return a.buildShell("schemes", table, " [#00f0ff]a:[-] add [#00f0ff]e:[-] edit [#ff2a2a]d:[-] delete [#39ff14]Enter:[-] open [#ff00ff]ESC:[-] back ") + return a.buildShell( + "schemes", + table, + " [#00f0ff]a:[-] add [#00f0ff]e:[-] edit [#ff2a2a]d:[-] delete [#39ff14]Enter:[-] open [#ff00ff]ESC:[-] back ", + ) } func (a *App) showSchemeForm(existing *tuicfg.Scheme, onSave func(tuicfg.Scheme)) { @@ -220,7 +230,10 @@ func (a *App) showSchemeForm(existing *tuicfg.Scheme, onSave func(tuicfg.Scheme) a.hideModal("scheme-form") }) - form.SetBorder(true).SetTitle(" [::b]" + title + " ").SetTitleColor(tcell.NewHexColor(0x39ff14)).SetBorderColor(tcell.NewHexColor(0x00f0ff)) + form.SetBorder(true). + SetTitle(" [::b]" + title + " "). + SetTitleColor(tcell.NewHexColor(0x39ff14)). + SetBorderColor(tcell.NewHexColor(0x00f0ff)) form.SetBackgroundColor(tcell.NewHexColor(0x1a1a2e)) form.SetFieldBackgroundColor(tcell.NewHexColor(0x050510)) form.SetFieldTextColor(tcell.NewHexColor(0x00f0ff)) diff --git a/cmd/picoclaw-launcher-tui/ui/users.go b/cmd/picoclaw-launcher-tui/ui/users.go index 4a877d3c7..b00fc8982 100644 --- a/cmd/picoclaw-launcher-tui/ui/users.go +++ b/cmd/picoclaw-launcher-tui/ui/users.go @@ -10,6 +10,7 @@ import ( "github.com/gdamore/tcell/v2" "github.com/rivo/tview" + tuicfg "github.com/sipeed/picoclaw/cmd/picoclaw-launcher-tui/config" ) @@ -17,8 +18,13 @@ func (a *App) newUsersPage(schemeName string) tview.Primitive { table := tview.NewTable(). SetBorders(false). SetSelectable(true, false) - table.SetBorder(true).SetTitle(fmt.Sprintf(" [#00f0ff::b] USERS · %s ", schemeName)).SetTitleColor(tcell.NewHexColor(0x00f0ff)).SetBorderColor(tcell.NewHexColor(0x00f0ff)) - table.SetSelectedStyle(tcell.StyleDefault.Background(tcell.NewHexColor(0xff00ff)).Foreground(tcell.NewHexColor(0xffffff))) + table.SetBorder(true). + SetTitle(fmt.Sprintf(" [#00f0ff::b] USERS · %s ", schemeName)). + SetTitleColor(tcell.NewHexColor(0x00f0ff)). + SetBorderColor(tcell.NewHexColor(0x00f0ff)) + table.SetSelectedStyle( + tcell.StyleDefault.Background(tcell.NewHexColor(0xff00ff)).Foreground(tcell.NewHexColor(0xffffff)), + ) table.SetBackgroundColor(tcell.NewHexColor(0x050510)) visibleUsers := func() []tuicfg.User { @@ -179,7 +185,11 @@ func (a *App) newUsersPage(schemeName string) tview.Primitive { return event }) - return a.buildShell("users", table, " [#00f0ff]a:[-] add [#00f0ff]e:[-] edit [#ff2a2a]d:[-] delete [#39ff14]Enter:[-] models [#ff00ff]ESC:[-] back ") + return a.buildShell( + "users", + table, + " [#00f0ff]a:[-] add [#00f0ff]e:[-] edit [#ff2a2a]d:[-] delete [#39ff14]Enter:[-] models [#ff00ff]ESC:[-] back ", + ) } func (a *App) showUserForm(schemeName string, existing *tuicfg.User, onSave func(tuicfg.User)) { @@ -229,7 +239,10 @@ func (a *App) showUserForm(schemeName string, existing *tuicfg.User, onSave func a.hideModal("user-form") }) - form.SetBorder(true).SetTitle(" [::b]" + title + " ").SetTitleColor(tcell.NewHexColor(0x39ff14)).SetBorderColor(tcell.NewHexColor(0x00f0ff)) + form.SetBorder(true). + SetTitle(" [::b]" + title + " "). + SetTitleColor(tcell.NewHexColor(0x39ff14)). + SetBorderColor(tcell.NewHexColor(0x00f0ff)) form.SetBackgroundColor(tcell.NewHexColor(0x1a1a2e)) form.SetFieldBackgroundColor(tcell.NewHexColor(0x050510)) form.SetFieldTextColor(tcell.NewHexColor(0x00f0ff))