diff --git a/pkg/config/info.go b/pkg/config/info.go index ce2a5eee3..61078225f 100644 --- a/pkg/config/info.go +++ b/pkg/config/info.go @@ -67,7 +67,11 @@ func GetEnabledChannelsInfo(c *Config) []ChannelInfo { if c == nil { // return requirements only (not enabled) if config not provided for _, name := range GetAllChannelNames() { - res = append(res, ChannelInfo{Name: name, Enabled: false, RequiredCredentials: GetChannelRequirements(name)}) + res = append(res, ChannelInfo{ + Name: name, + Enabled: false, + RequiredCredentials: GetChannelRequirements(name), + }) } return res } @@ -139,9 +143,20 @@ func GetSupportedModelNames(c *Config) []string { // Known providers and their typical credential requirements. var knownProviders = map[string]ProviderInfo{ - "anthropic": {Name: "anthropic", RequiredCredentials: []string{"api_key"}, OptionalCredentials: []string{"api_base"}}, - "openai": {Name: "openai", RequiredCredentials: []string{"api_key"}, OptionalCredentials: []string{"api_base"}}, - "openrouter": {Name: "openrouter", RequiredCredentials: []string{"api_key"}, OptionalCredentials: []string{"api_base"}}, + "anthropic": { + Name: "anthropic", RequiredCredentials: []string{"api_key"}, + OptionalCredentials: []string{"api_base"}, + }, + "openai": { + Name: "openai", + RequiredCredentials: []string{"api_key"}, + OptionalCredentials: []string{"api_base"}, + }, + "openrouter": { + Name: "openrouter", + RequiredCredentials: []string{"api_key"}, + OptionalCredentials: []string{"api_base"}, + }, "groq": {Name: "groq", RequiredCredentials: []string{"api_key"}}, "zhipu": {Name: "zhipu", RequiredCredentials: []string{"api_key"}}, "vllm": {Name: "vllm", RequiredCredentials: []string{"api_key"}}, @@ -160,7 +175,23 @@ var knownProviders = map[string]ProviderInfo{ // ProviderPriority lists popular providers first to present them in a stable order. var ProviderPriority = []string{ - "openai", "anthropic", "openrouter", "ollama", "gemini", "groq", "github_copilot", "antigravity", "qwen", "vllm", "nvidia", "moonshot", "shengsuanyun", "deepseek", "cerebras", "volcengine", "zhipu", + "openai", + "anthropic", + "openrouter", + "ollama", + "gemini", + "groq", + "github_copilot", + "antigravity", + "qwen", + "vllm", + "nvidia", + "moonshot", + "shengsuanyun", + "deepseek", + "cerebras", + "volcengine", + "zhipu", } // GetOrderedProviderNames returns provider names in a deterministic order: @@ -271,8 +302,6 @@ func GetProvidersInfo(c *Config) []ProviderInfo { return res } -// parseProtocol extracts the protocol prefix from a model string of the form -// "protocol/model-identifier". If no prefix exists, returns empty string. // ParseProtocol extracts the protocol prefix from a model string of the form // "protocol/model-identifier". If no prefix exists, returns empty string. func ParseProtocol(model string) string { diff --git a/pkg/config/models.go b/pkg/config/models.go index bfbb0bc49..4856fb548 100644 --- a/pkg/config/models.go +++ b/pkg/config/models.go @@ -56,7 +56,10 @@ var ProviderModelsList = []ProviderModels{ {ID: "gemini-2.5-pro", Name: "Gemini 2.5 Pro", ContextSize: 200000}, {ID: "gemini-2.5-pro-preview-06-05", Name: "Gemini 2.5 Pro (Preview)", ContextSize: 200000}, {ID: "gemini-2.5-flash-lite", Name: "Gemini 2.5 Flash Lite", ContextSize: 1000000}, - {ID: "gemini-2.5-flash-lite-preview-09-2025", Name: "Gemini 2.5 Flash Lite (Sep 2025)", ContextSize: 1000000}, + { + ID: "gemini-2.5-flash-lite-preview-09-2025", Name: "Gemini 2.5 Flash Lite (Sep 2025)", + ContextSize: 1000000, + }, {ID: "gemini-2.5-flash-image", Name: "Gemini 2.5 Flash (Image)", ContextSize: 1000000}, {ID: "gemini-2.0-flash-001", Name: "Gemini 2.0 Flash", ContextSize: 1000000}, {ID: "gemini-2.0-flash-lite-001", Name: "Gemini 2.0 Flash Lite", ContextSize: 1000000}, diff --git a/pkg/setup/sessions.go b/pkg/setup/sessions.go index a255833a3..ef5817bc0 100644 --- a/pkg/setup/sessions.go +++ b/pkg/setup/sessions.go @@ -2,6 +2,7 @@ package setup import ( "fmt" + "net" "strings" "github.com/sipeed/picoclaw/pkg/config" @@ -21,40 +22,79 @@ type ChannelInfo struct { var channelInfoMap = map[string]ChannelInfo{ "telegram": { Fields: []ChannelField{ - {ID: "token", Prompt: "Bot Token", Placeholder: "1234567890:ABCdefGHIjklMNOpqrsTUVwxyz", Info: "Get from @BotFather on Telegram"}, + { + ID: "token", Prompt: "Bot Token", Placeholder: "1234567890:ABCdefGHIjklMNOpqrsTUVwxyz", + Info: "Get from @BotFather on Telegram", + }, }, }, "slack": { Fields: []ChannelField{ - {ID: "bot_token", Prompt: "Bot Token", Placeholder: "xoxb-xxxxx-xxxxx", Info: "Bot token from Slack App settings (starts with xoxb-)"}, - {ID: "app_token", Prompt: "App Token", Placeholder: "xoxa-xxxxx-xxxxx", Info: "App token from Slack App settings (starts with xoxa-)"}, + { + ID: "bot_token", Prompt: "Bot Token", Placeholder: "xoxb-xxxxx-xxxxx", + Info: "Bot token from Slack App settings (starts with xoxb-)", + }, + { + ID: "app_token", Prompt: "App Token", Placeholder: "xoxa-xxxxx-xxxxx", + Info: "App token from Slack App settings (starts with xoxa-)", + }, }, }, "discord": { Fields: []ChannelField{ - {ID: "token", Prompt: "Bot Token", Placeholder: "MTExxxxxxxxxxxx.MDExxxxxxxx.xxxxx", Info: "Get from Discord Developer Portal > Bot"}, + { + ID: "token", + Prompt: "Bot Token", + Placeholder: "MTExxxxxxxxxxxx.MDExxxxxxxx.xxxxx", + Info: "Get from Discord Developer Portal > Bot", + }, }, }, "whatsapp": { Fields: []ChannelField{ - {ID: "bridge_url", Prompt: "Bridge URL", Placeholder: "http://localhost:9080", Info: "URL of your WhatsApp bridge service"}, + { + ID: "bridge_url", + Prompt: "Bridge URL", + Placeholder: "http://localhost:9080", + Info: "URL of your WhatsApp bridge service", + }, }, }, "feishu": { Fields: []ChannelField{ {ID: "app_id", Prompt: "App ID", Placeholder: "cli_xxxxx", Info: "App ID from Feishu Open Platform > App"}, - {ID: "app_secret", Prompt: "App Secret", Placeholder: "xxxxxxxxxxxxxxxx", Info: "App Secret from Feishu Open Platform > App"}, + { + ID: "app_secret", + Prompt: "App Secret", + Placeholder: "xxxxxxxxxxxxxxxx", + Info: "App Secret from Feishu Open Platform > App", + }, }, }, "dingtalk": { Fields: []ChannelField{ - {ID: "client_id", Prompt: "Client ID", Placeholder: "dingxxxxx", Info: "Client ID from DingTalk Admin > OAuth"}, - {ID: "client_secret", Prompt: "Client Secret", Placeholder: "xxxxxxxxxxxxxxxx", Info: "Client Secret from DingTalk Admin > OAuth"}, + { + ID: "client_id", + Prompt: "Client ID", + Placeholder: "dingxxxxx", + Info: "Client ID from DingTalk Admin > OAuth", + }, + { + ID: "client_secret", + Prompt: "Client Secret", + Placeholder: "xxxxxxxxxxxxxxxx", + Info: "Client Secret from DingTalk Admin > OAuth", + }, }, }, "line": { Fields: []ChannelField{ - {ID: "channel_access_token", Prompt: "Channel Access Token", Placeholder: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", Info: "Get from LINE Developers > Channel Access Token"}, + { + ID: "channel_access_token", + Prompt: "Channel Access Token", + Placeholder: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", + Info: "Get from LINE Developers > Channel Access Token", + }, }, }, "qq": { @@ -64,13 +104,23 @@ var channelInfoMap = map[string]ChannelInfo{ }, "onebot": { Fields: []ChannelField{ - {ID: "access_token", Prompt: "Access Token", Placeholder: "your_access_token_here", Info: "Access token configured in your OneBot server"}, + { + ID: "access_token", + Prompt: "Access Token", + Placeholder: "your_access_token_here", + Info: "Access token configured in your OneBot server", + }, }, }, "wecom": { Fields: []ChannelField{ {ID: "token", Prompt: "Token", Placeholder: "your_token", Info: "Token from Wecom Admin"}, - {ID: "encoding_aes_key", Prompt: "Encoding AES Key", Placeholder: "your_encoding_aes_key", Info: "Encoding AES Key from Wecom Admin"}, + { + ID: "encoding_aes_key", + Prompt: "Encoding AES Key", + Placeholder: "your_encoding_aes_key", + Info: "Encoding AES Key from Wecom Admin", + }, }, }, "wecom_app": { @@ -81,7 +131,12 @@ var channelInfoMap = map[string]ChannelInfo{ }, "maixcam": { Fields: []ChannelField{ - {ID: "device_address", Prompt: "Device Address", Placeholder: "http://192.168.1.100:8080", Info: "MaixCam device HTTP address"}, + { + ID: "device_address", + Prompt: "Device Address", + Placeholder: "http://192.168.1.100:8080", + Info: "MaixCam device HTTP address", + }, }, }, } @@ -409,7 +464,7 @@ func BuildSessionRegistry(cfg *config.Config) SessionRegistry { } } else { modelSuggestions := config.GetPopularModels(selProvider) - modelOptions = make([]string, len(modelSuggestions)) + modelOptions = make([]string, 0, len(modelSuggestions)) copy(modelOptions, modelSuggestions) } modelOptions = append(modelOptions, "custom") @@ -763,7 +818,7 @@ func GetChannelFieldToken(cfg *config.Config, questionID string) string { case "wecom_app_agent_id": return fmt.Sprintf("%d", cfg.Channels.WeComApp.AgentID) case "maixcam_device_address": - return fmt.Sprintf("http://%s:%d", cfg.Channels.MaixCam.Host, cfg.Channels.MaixCam.Port) + return "http://" + net.JoinHostPort(cfg.Channels.MaixCam.Host, fmt.Sprintf("%d", cfg.Channels.MaixCam.Port)) } return "" } diff --git a/pkg/setup/setup.go b/pkg/setup/setup.go index 30f38b315..d0a7422b6 100644 --- a/pkg/setup/setup.go +++ b/pkg/setup/setup.go @@ -130,14 +130,22 @@ func (s *Setup) RunNonInteractive() error { var b strings.Builder b.WriteString("\n") - b.WriteString(lipgloss.NewStyle().PaddingLeft(4).Render(titleStyle.Render("╔═══════════════════════════════════════════════════════╗"))) + b.WriteString(lipgloss.NewStyle().PaddingLeft(4).Render( + titleStyle.Render("╔═══════════════════════════════════════════════════════╗"))) b.WriteString("\n") - b.WriteString(lipgloss.NewStyle().PaddingLeft(4).Render(titleStyle.Render("║ PicoClaw Setup Complete ║"))) + b.WriteString(lipgloss.NewStyle().PaddingLeft(4).Render( + titleStyle.Render("║ PicoClaw Setup Complete ║"))) b.WriteString("\n") - b.WriteString(lipgloss.NewStyle().PaddingLeft(4).Render(titleStyle.Render("╚═══════════════════════════════════════════════════════╝"))) + b.WriteString( + lipgloss.NewStyle(). + PaddingLeft(4). + Render(titleStyle.Render("╚═══════════════════════════════════════════════════════╝")), + ) b.WriteString("\n\n") - b.WriteString(lipgloss.NewStyle().PaddingLeft(4).Render(successStyle.Render("✓ Workspace config created and is working!"))) + b.WriteString( + lipgloss.NewStyle().PaddingLeft(4).Render(successStyle.Render("✓ Workspace config created and is working!")), + ) b.WriteString("\n\n") b.WriteString(lipgloss.NewStyle().PaddingLeft(4).Render(sectionStyle.Render("📁 Workspace:"))) @@ -150,21 +158,39 @@ func (s *Setup) RunNonInteractive() error { b.WriteString(lipgloss.NewStyle().PaddingLeft(4).Render(dimStyle.Render(s.ConfigPath))) b.WriteString("\n\n") - b.WriteString(lipgloss.NewStyle().PaddingLeft(4).Render(dimStyle.Render("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"))) + b.WriteString( + lipgloss.NewStyle(). + PaddingLeft(4). + Render(dimStyle.Render("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━")), + ) b.WriteString("\n\n") b.WriteString(lipgloss.NewStyle().PaddingLeft(4).Render(sectionStyle.Render("IMPORTANT COMMANDS"))) b.WriteString("\n") - b.WriteString(lipgloss.NewStyle().PaddingLeft(4).Render(highlightStyle.Render(" picoclaw agent - Start chatting"))) + b.WriteString( + lipgloss.NewStyle(). + PaddingLeft(4). + Render(highlightStyle.Render(" picoclaw agent - Start chatting")), + ) b.WriteString("\n") - b.WriteString(lipgloss.NewStyle().PaddingLeft(4).Render(dimStyle.Render(" picoclaw onboard --interactive - Full setup"))) + b.WriteString( + lipgloss.NewStyle().PaddingLeft(4).Render(dimStyle.Render(" picoclaw onboard --interactive - Full setup")), + ) b.WriteString("\n") - b.WriteString(lipgloss.NewStyle().PaddingLeft(4).Render(dimStyle.Render(" picoclaw auth login - Login to providers"))) + b.WriteString( + lipgloss.NewStyle().PaddingLeft(4).Render(dimStyle.Render(" picoclaw auth login - Login to providers")), + ) b.WriteString("\n") - b.WriteString(lipgloss.NewStyle().PaddingLeft(4).Render(dimStyle.Render(" picoclaw status - Show status"))) + b.WriteString( + lipgloss.NewStyle().PaddingLeft(4).Render(dimStyle.Render(" picoclaw status - Show status")), + ) b.WriteString("\n\n") - b.WriteString(lipgloss.NewStyle().PaddingLeft(4).Render(dimStyle.Render("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"))) + b.WriteString( + lipgloss.NewStyle(). + PaddingLeft(4). + Render(dimStyle.Render("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━")), + ) b.WriteString("\n\n") b.WriteString(lipgloss.NewStyle().PaddingLeft(4).Render(sectionStyle.Render("CHANNELS (in config.json)"))) @@ -175,10 +201,18 @@ func (s *Setup) RunNonInteractive() error { b.WriteString("\n") b.WriteString(lipgloss.NewStyle().PaddingLeft(4).Render(dimStyle.Render(" discord : Discord"))) b.WriteString("\n") - b.WriteString(lipgloss.NewStyle().PaddingLeft(4).Render(dimStyle.Render(" + more: whatsapp, feishu, dingtalk, line, qq, etc."))) + b.WriteString( + lipgloss.NewStyle(). + PaddingLeft(4). + Render(dimStyle.Render(" + more: whatsapp, feishu, dingtalk, line, qq, etc.")), + ) b.WriteString("\n\n") - b.WriteString(lipgloss.NewStyle().PaddingLeft(4).Render(dimStyle.Render("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"))) + b.WriteString( + lipgloss.NewStyle(). + PaddingLeft(4). + Render(dimStyle.Render("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━")), + ) b.WriteString("\n\n") b.WriteString(lipgloss.NewStyle().PaddingLeft(4).Render(sectionStyle.Render("NEXT STEPS"))) @@ -187,7 +221,11 @@ func (s *Setup) RunNonInteractive() error { b.WriteString("\n") b.WriteString(lipgloss.NewStyle().PaddingLeft(4).Render(dimStyle.Render(" 2. Run 'picoclaw agent' to start!"))) b.WriteString("\n\n") - b.WriteString(lipgloss.NewStyle().PaddingLeft(4).Render(dimStyle.Render(" Run 'picoclaw onboard --interactive' for guided setup"))) + b.WriteString( + lipgloss.NewStyle(). + PaddingLeft(4). + Render(dimStyle.Render(" Run 'picoclaw onboard --interactive' for guided setup")), + ) b.WriteString("\n") // b.WriteString(lipgloss.NewStyle().PaddingLeft(4).Render(dimStyle.Render("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"))) // b.WriteString("\n\n") @@ -217,8 +255,8 @@ type tuiModel struct { errorMsg string } -func newTuiModel(s *Setup) tuiModel { - return tuiModel{ +func newTuiModel(s *Setup) *tuiModel { + return &tuiModel{ setup: s, state: "intro", answers: make(map[string]string), @@ -227,11 +265,11 @@ func newTuiModel(s *Setup) tuiModel { } } -func (t tuiModel) Init() tea.Cmd { +func (t *tuiModel) Init() tea.Cmd { return nil } -func (t tuiModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { +func (t *tuiModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { switch msg := msg.(type) { case tea.KeyMsg: switch msg.String() { @@ -260,7 +298,7 @@ func (t tuiModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { return t, nil } -func (t tuiModel) handleIntro(msg tea.KeyMsg) (tea.Model, tea.Cmd) { +func (t *tuiModel) handleIntro(msg tea.KeyMsg) (tea.Model, tea.Cmd) { switch msg.String() { case "enter": t.state = "questions" @@ -274,7 +312,7 @@ func (t tuiModel) handleIntro(msg tea.KeyMsg) (tea.Model, tea.Cmd) { return t, nil } -func (t tuiModel) handleQuestions(msg tea.KeyMsg) (tea.Model, tea.Cmd) { +func (t *tuiModel) handleQuestions(msg tea.KeyMsg) (tea.Model, tea.Cmd) { session := t.registry.Sessions[t.sessionIdx] visible := t.getVisibleQuestions(session) @@ -358,7 +396,7 @@ func (t tuiModel) handleQuestions(msg tea.KeyMsg) (tea.Model, tea.Cmd) { return t, nil } -func (t tuiModel) proceedToNextSession() (tea.Model, tea.Cmd) { +func (t *tuiModel) proceedToNextSession() (tea.Model, tea.Cmd) { session := t.registry.Sessions[t.sessionIdx] visible := t.getVisibleQuestions(session) @@ -409,7 +447,7 @@ func (t tuiModel) proceedToNextSession() (tea.Model, tea.Cmd) { return t, nil } -func (t tuiModel) nextQuestion() (tea.Model, tea.Cmd) { +func (t *tuiModel) nextQuestion() (tea.Model, tea.Cmd) { session := t.registry.Sessions[t.sessionIdx] visible := t.getVisibleQuestions(session) @@ -421,7 +459,7 @@ func (t tuiModel) nextQuestion() (tea.Model, tea.Cmd) { return t, nil } -func (t tuiModel) prevQuestion() (tea.Model, tea.Cmd) { +func (t *tuiModel) prevQuestion() (tea.Model, tea.Cmd) { if t.questionIdx > 0 { t.questionIdx-- t.focusCurrent() @@ -1018,7 +1056,7 @@ func (t *tuiModel) applyChannelSelection(channel string, cfg *config.Config) { } } -func (t tuiModel) View() string { +func (t *tuiModel) View() string { titleStyle := lipgloss.NewStyle().Foreground(lipgloss.Color("39")).Bold(true) promptStyle := lipgloss.NewStyle().Foreground(lipgloss.Color("255")).Bold(true) activeStyle := lipgloss.NewStyle().Foreground(lipgloss.Color("86")).Bold(true) @@ -1031,16 +1069,30 @@ func (t tuiModel) View() string { var b strings.Builder b.WriteString("\n") - b.WriteString(lipgloss.NewStyle().PaddingLeft(4).Render(titleStyle.Render("╔════════════════════════════════════════════════╗"))) + b.WriteString( + lipgloss.NewStyle(). + PaddingLeft(4). + Render(titleStyle.Render("╔════════════════════════════════════════════════╗")), + ) b.WriteString("\n") - b.WriteString(lipgloss.NewStyle().PaddingLeft(4).Render(titleStyle.Render("║ PicoClaw Interactive Setup ║"))) + b.WriteString( + lipgloss.NewStyle(). + PaddingLeft(4). + Render(titleStyle.Render("║ PicoClaw Interactive Setup ║")), + ) b.WriteString("\n") - b.WriteString(lipgloss.NewStyle().PaddingLeft(4).Render(titleStyle.Render("╚════════════════════════════════════════════════╝"))) + b.WriteString( + lipgloss.NewStyle(). + PaddingLeft(4). + Render(titleStyle.Render("╚════════════════════════════════════════════════╝")), + ) b.WriteString("\n\n") switch t.state { case "intro": - b.WriteString(lipgloss.NewStyle().PaddingLeft(4).Render(dimStyle.Render("Press Enter to start the configuration wizard"))) + b.WriteString( + lipgloss.NewStyle().PaddingLeft(4).Render(dimStyle.Render("Press Enter to start the configuration wizard")), + ) b.WriteString("\n\n") b.WriteString(lipgloss.NewStyle().PaddingLeft(4).Render(dimStyle.Render("Press q or Ctrl+C to exit"))) @@ -1052,7 +1104,11 @@ func (t tuiModel) View() string { header := fmt.Sprintf("Step %d of %d: %s", t.sessionIdx+1, totalSessions, session.Title) b.WriteString(lipgloss.NewStyle().PaddingLeft(4).Render(titleStyle.Render(header))) b.WriteString("\n") - b.WriteString(lipgloss.NewStyle().PaddingLeft(4).Render(dimStyle.Render("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"))) + b.WriteString( + lipgloss.NewStyle(). + PaddingLeft(4). + Render(dimStyle.Render("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━")), + ) b.WriteString("\n\n") if t.errorMsg != "" { @@ -1112,7 +1168,11 @@ func (t tuiModel) View() string { b.WriteString("\n") } - b.WriteString(lipgloss.NewStyle().PaddingLeft(4).Render(dimStyle.Render("─────────────────────────────────────────────────"))) + b.WriteString( + lipgloss.NewStyle(). + PaddingLeft(4). + Render(dimStyle.Render("─────────────────────────────────────────────────")), + ) b.WriteString("\n") // Show summary in confirmation session @@ -1120,7 +1180,11 @@ func (t tuiModel) View() string { b.WriteString("\n") b.WriteString(lipgloss.NewStyle().PaddingLeft(4).Render(titleStyle.Render("Configuration Summary:"))) b.WriteString("\n") - b.WriteString(lipgloss.NewStyle().PaddingLeft(4).Render(dimStyle.Render("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"))) + b.WriteString( + lipgloss.NewStyle(). + PaddingLeft(4). + Render(dimStyle.Render("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━")), + ) b.WriteString("\n\n") summary := t.buildAnswersSummary() @@ -1129,13 +1193,25 @@ func (t tuiModel) View() string { b.WriteString("\n") } b.WriteString("\n") - b.WriteString(lipgloss.NewStyle().PaddingLeft(4).Render(dimStyle.Render("Press 'e' to go back and edit, or confirm below:"))) + b.WriteString( + lipgloss.NewStyle(). + PaddingLeft(4). + Render(dimStyle.Render("Press 'e' to go back and edit, or confirm below:")), + ) b.WriteString("\n\n") } - b.WriteString(lipgloss.NewStyle().PaddingLeft(4).Render(dimStyle.Render("─────────────────────────────────────────────────"))) + b.WriteString( + lipgloss.NewStyle(). + PaddingLeft(4). + Render(dimStyle.Render("─────────────────────────────────────────────────")), + ) b.WriteString("\n") - b.WriteString(lipgloss.NewStyle().PaddingLeft(4).Render(dimStyle.Render("↑/↓: Select option | Tab/Enter: Next | Esc: Back | e: Edit (in confirm) | q: Quit"))) + b.WriteString( + lipgloss.NewStyle(). + PaddingLeft(4). + Render(dimStyle.Render("↑/↓: Select option | Tab/Enter: Next | Esc: Back | e: Edit (in confirm) | q: Quit")), + ) case "done": workspace := t.setup.Cfg.WorkspacePath() @@ -1152,23 +1228,35 @@ func (t tuiModel) View() string { b.WriteString("\n\n") b.WriteString(lipgloss.NewStyle().PaddingLeft(4).Render(titleStyle.Render("Workspace structure:"))) b.WriteString("\n") - b.WriteString(lipgloss.NewStyle().PaddingLeft(4).Render(dimStyle.Render(" 📁 memory/ - Persistent memory"))) + b.WriteString( + lipgloss.NewStyle().PaddingLeft(4).Render(dimStyle.Render(" 📁 memory/ - Persistent memory")), + ) b.WriteString("\n") b.WriteString(lipgloss.NewStyle().PaddingLeft(4).Render(dimStyle.Render(" 📁 skills/ - Custom skills"))) b.WriteString("\n") - b.WriteString(lipgloss.NewStyle().PaddingLeft(4).Render(dimStyle.Render(" 📄 AGENT.md - Agent configuration"))) + b.WriteString( + lipgloss.NewStyle().PaddingLeft(4).Render(dimStyle.Render(" 📄 AGENT.md - Agent configuration")), + ) b.WriteString("\n") b.WriteString(lipgloss.NewStyle().PaddingLeft(4).Render(dimStyle.Render(" 📄 IDENTITY.md - Agent identity"))) b.WriteString("\n") - b.WriteString(lipgloss.NewStyle().PaddingLeft(4).Render(dimStyle.Render(" 📄 SOUL.md - Agent personality"))) + b.WriteString( + lipgloss.NewStyle().PaddingLeft(4).Render(dimStyle.Render(" 📄 SOUL.md - Agent personality")), + ) b.WriteString("\n") b.WriteString(lipgloss.NewStyle().PaddingLeft(4).Render(dimStyle.Render(" 📄 USER.md - User profile"))) b.WriteString("\n\n") - b.WriteString(lipgloss.NewStyle().PaddingLeft(4).Render(dimStyle.Render("Next: Run 'picoclaw agent' to start chatting!"))) + b.WriteString( + lipgloss.NewStyle().PaddingLeft(4).Render(dimStyle.Render("Next: Run 'picoclaw agent' to start chatting!")), + ) b.WriteString("\n") b.WriteString(lipgloss.NewStyle().PaddingLeft(4).Render(dimStyle.Render("Config: ~/.picoclaw/config.json"))) b.WriteString("\n") - b.WriteString(lipgloss.NewStyle().PaddingLeft(4).Render(dimStyle.Render("─────────────────────────────────────────────────"))) + b.WriteString( + lipgloss.NewStyle(). + PaddingLeft(4). + Render(dimStyle.Render("─────────────────────────────────────────────────")), + ) b.WriteString("\n") b.WriteString(lipgloss.NewStyle().PaddingLeft(4).Render(dimStyle.Render("Press Enter or q to exit"))) }