fix: Linting Errors

This commit is contained in:
Yoftahe 2026-02-23 19:42:12 +03:00
parent 9b85a17e53
commit 8709277fb0
4 changed files with 235 additions and 60 deletions

View file

@ -67,7 +67,11 @@ func GetEnabledChannelsInfo(c *Config) []ChannelInfo {
if c == nil { if c == nil {
// return requirements only (not enabled) if config not provided // return requirements only (not enabled) if config not provided
for _, name := range GetAllChannelNames() { 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 return res
} }
@ -139,9 +143,20 @@ func GetSupportedModelNames(c *Config) []string {
// Known providers and their typical credential requirements. // Known providers and their typical credential requirements.
var knownProviders = map[string]ProviderInfo{ var knownProviders = map[string]ProviderInfo{
"anthropic": {Name: "anthropic", RequiredCredentials: []string{"api_key"}, OptionalCredentials: []string{"api_base"}}, "anthropic": {
"openai": {Name: "openai", RequiredCredentials: []string{"api_key"}, OptionalCredentials: []string{"api_base"}}, Name: "anthropic", RequiredCredentials: []string{"api_key"},
"openrouter": {Name: "openrouter", RequiredCredentials: []string{"api_key"}, OptionalCredentials: []string{"api_base"}}, 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"}}, "groq": {Name: "groq", RequiredCredentials: []string{"api_key"}},
"zhipu": {Name: "zhipu", RequiredCredentials: []string{"api_key"}}, "zhipu": {Name: "zhipu", RequiredCredentials: []string{"api_key"}},
"vllm": {Name: "vllm", 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. // ProviderPriority lists popular providers first to present them in a stable order.
var ProviderPriority = []string{ 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: // GetOrderedProviderNames returns provider names in a deterministic order:
@ -271,8 +302,6 @@ func GetProvidersInfo(c *Config) []ProviderInfo {
return res 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 // ParseProtocol extracts the protocol prefix from a model string of the form
// "protocol/model-identifier". If no prefix exists, returns empty string. // "protocol/model-identifier". If no prefix exists, returns empty string.
func ParseProtocol(model string) string { func ParseProtocol(model string) string {

View file

@ -56,7 +56,10 @@ var ProviderModelsList = []ProviderModels{
{ID: "gemini-2.5-pro", Name: "Gemini 2.5 Pro", ContextSize: 200000}, {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-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", 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.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-001", Name: "Gemini 2.0 Flash", ContextSize: 1000000},
{ID: "gemini-2.0-flash-lite-001", Name: "Gemini 2.0 Flash Lite", ContextSize: 1000000}, {ID: "gemini-2.0-flash-lite-001", Name: "Gemini 2.0 Flash Lite", ContextSize: 1000000},

View file

@ -2,6 +2,7 @@ package setup
import ( import (
"fmt" "fmt"
"net"
"strings" "strings"
"github.com/sipeed/picoclaw/pkg/config" "github.com/sipeed/picoclaw/pkg/config"
@ -21,40 +22,79 @@ type ChannelInfo struct {
var channelInfoMap = map[string]ChannelInfo{ var channelInfoMap = map[string]ChannelInfo{
"telegram": { "telegram": {
Fields: []ChannelField{ 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": { "slack": {
Fields: []ChannelField{ 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": { "discord": {
Fields: []ChannelField{ 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": { "whatsapp": {
Fields: []ChannelField{ 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": { "feishu": {
Fields: []ChannelField{ Fields: []ChannelField{
{ID: "app_id", Prompt: "App ID", Placeholder: "cli_xxxxx", Info: "App ID from Feishu Open Platform > App"}, {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": { "dingtalk": {
Fields: []ChannelField{ 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": { "line": {
Fields: []ChannelField{ 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": { "qq": {
@ -64,13 +104,23 @@ var channelInfoMap = map[string]ChannelInfo{
}, },
"onebot": { "onebot": {
Fields: []ChannelField{ 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": { "wecom": {
Fields: []ChannelField{ Fields: []ChannelField{
{ID: "token", Prompt: "Token", Placeholder: "your_token", Info: "Token from Wecom Admin"}, {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": { "wecom_app": {
@ -81,7 +131,12 @@ var channelInfoMap = map[string]ChannelInfo{
}, },
"maixcam": { "maixcam": {
Fields: []ChannelField{ 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 { } else {
modelSuggestions := config.GetPopularModels(selProvider) modelSuggestions := config.GetPopularModels(selProvider)
modelOptions = make([]string, len(modelSuggestions)) modelOptions = make([]string, 0, len(modelSuggestions))
copy(modelOptions, modelSuggestions) copy(modelOptions, modelSuggestions)
} }
modelOptions = append(modelOptions, "custom") modelOptions = append(modelOptions, "custom")
@ -763,7 +818,7 @@ func GetChannelFieldToken(cfg *config.Config, questionID string) string {
case "wecom_app_agent_id": case "wecom_app_agent_id":
return fmt.Sprintf("%d", cfg.Channels.WeComApp.AgentID) return fmt.Sprintf("%d", cfg.Channels.WeComApp.AgentID)
case "maixcam_device_address": 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 "" return ""
} }

View file

@ -130,14 +130,22 @@ func (s *Setup) RunNonInteractive() error {
var b strings.Builder var b strings.Builder
b.WriteString("\n") 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("\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("\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("\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("\n\n")
b.WriteString(lipgloss.NewStyle().PaddingLeft(4).Render(sectionStyle.Render("📁 Workspace:"))) 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(lipgloss.NewStyle().PaddingLeft(4).Render(dimStyle.Render(s.ConfigPath)))
b.WriteString("\n\n") 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("\n\n")
b.WriteString(lipgloss.NewStyle().PaddingLeft(4).Render(sectionStyle.Render("IMPORTANT COMMANDS"))) b.WriteString(lipgloss.NewStyle().PaddingLeft(4).Render(sectionStyle.Render("IMPORTANT COMMANDS")))
b.WriteString("\n") 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("\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("\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("\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("\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("\n\n")
b.WriteString(lipgloss.NewStyle().PaddingLeft(4).Render(sectionStyle.Render("CHANNELS (in config.json)"))) 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("\n")
b.WriteString(lipgloss.NewStyle().PaddingLeft(4).Render(dimStyle.Render(" discord : Discord"))) b.WriteString(lipgloss.NewStyle().PaddingLeft(4).Render(dimStyle.Render(" discord : Discord")))
b.WriteString("\n") 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("\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("\n\n")
b.WriteString(lipgloss.NewStyle().PaddingLeft(4).Render(sectionStyle.Render("NEXT STEPS"))) 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("\n")
b.WriteString(lipgloss.NewStyle().PaddingLeft(4).Render(dimStyle.Render(" 2. Run 'picoclaw agent' to start!"))) b.WriteString(lipgloss.NewStyle().PaddingLeft(4).Render(dimStyle.Render(" 2. Run 'picoclaw agent' to start!")))
b.WriteString("\n\n") 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("\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("\n\n")
@ -217,8 +255,8 @@ type tuiModel struct {
errorMsg string errorMsg string
} }
func newTuiModel(s *Setup) tuiModel { func newTuiModel(s *Setup) *tuiModel {
return tuiModel{ return &tuiModel{
setup: s, setup: s,
state: "intro", state: "intro",
answers: make(map[string]string), 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 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) { switch msg := msg.(type) {
case tea.KeyMsg: case tea.KeyMsg:
switch msg.String() { switch msg.String() {
@ -260,7 +298,7 @@ func (t tuiModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
return t, nil 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() { switch msg.String() {
case "enter": case "enter":
t.state = "questions" t.state = "questions"
@ -274,7 +312,7 @@ func (t tuiModel) handleIntro(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
return t, nil 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] session := t.registry.Sessions[t.sessionIdx]
visible := t.getVisibleQuestions(session) visible := t.getVisibleQuestions(session)
@ -358,7 +396,7 @@ func (t tuiModel) handleQuestions(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
return t, nil 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] session := t.registry.Sessions[t.sessionIdx]
visible := t.getVisibleQuestions(session) visible := t.getVisibleQuestions(session)
@ -409,7 +447,7 @@ func (t tuiModel) proceedToNextSession() (tea.Model, tea.Cmd) {
return t, nil 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] session := t.registry.Sessions[t.sessionIdx]
visible := t.getVisibleQuestions(session) visible := t.getVisibleQuestions(session)
@ -421,7 +459,7 @@ func (t tuiModel) nextQuestion() (tea.Model, tea.Cmd) {
return t, nil return t, nil
} }
func (t tuiModel) prevQuestion() (tea.Model, tea.Cmd) { func (t *tuiModel) prevQuestion() (tea.Model, tea.Cmd) {
if t.questionIdx > 0 { if t.questionIdx > 0 {
t.questionIdx-- t.questionIdx--
t.focusCurrent() 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) titleStyle := lipgloss.NewStyle().Foreground(lipgloss.Color("39")).Bold(true)
promptStyle := lipgloss.NewStyle().Foreground(lipgloss.Color("255")).Bold(true) promptStyle := lipgloss.NewStyle().Foreground(lipgloss.Color("255")).Bold(true)
activeStyle := lipgloss.NewStyle().Foreground(lipgloss.Color("86")).Bold(true) activeStyle := lipgloss.NewStyle().Foreground(lipgloss.Color("86")).Bold(true)
@ -1031,16 +1069,30 @@ func (t tuiModel) View() string {
var b strings.Builder var b strings.Builder
b.WriteString("\n") 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("\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("\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("\n\n")
switch t.state { switch t.state {
case "intro": 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("\n\n")
b.WriteString(lipgloss.NewStyle().PaddingLeft(4).Render(dimStyle.Render("Press q or Ctrl+C to exit"))) 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) 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(lipgloss.NewStyle().PaddingLeft(4).Render(titleStyle.Render(header)))
b.WriteString("\n") 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") b.WriteString("\n\n")
if t.errorMsg != "" { if t.errorMsg != "" {
@ -1112,7 +1168,11 @@ func (t tuiModel) View() string {
b.WriteString("\n") 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("\n")
// Show summary in confirmation session // Show summary in confirmation session
@ -1120,7 +1180,11 @@ func (t tuiModel) View() string {
b.WriteString("\n") b.WriteString("\n")
b.WriteString(lipgloss.NewStyle().PaddingLeft(4).Render(titleStyle.Render("Configuration Summary:"))) b.WriteString(lipgloss.NewStyle().PaddingLeft(4).Render(titleStyle.Render("Configuration Summary:")))
b.WriteString("\n") 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") b.WriteString("\n\n")
summary := t.buildAnswersSummary() summary := t.buildAnswersSummary()
@ -1129,13 +1193,25 @@ func (t tuiModel) View() string {
b.WriteString("\n") b.WriteString("\n")
} }
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("\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("\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": case "done":
workspace := t.setup.Cfg.WorkspacePath() workspace := t.setup.Cfg.WorkspacePath()
@ -1152,23 +1228,35 @@ func (t tuiModel) View() string {
b.WriteString("\n\n") b.WriteString("\n\n")
b.WriteString(lipgloss.NewStyle().PaddingLeft(4).Render(titleStyle.Render("Workspace structure:"))) b.WriteString(lipgloss.NewStyle().PaddingLeft(4).Render(titleStyle.Render("Workspace structure:")))
b.WriteString("\n") 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("\n")
b.WriteString(lipgloss.NewStyle().PaddingLeft(4).Render(dimStyle.Render(" 📁 skills/ - Custom skills"))) b.WriteString(lipgloss.NewStyle().PaddingLeft(4).Render(dimStyle.Render(" 📁 skills/ - Custom skills")))
b.WriteString("\n") 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("\n")
b.WriteString(lipgloss.NewStyle().PaddingLeft(4).Render(dimStyle.Render(" 📄 IDENTITY.md - Agent identity"))) b.WriteString(lipgloss.NewStyle().PaddingLeft(4).Render(dimStyle.Render(" 📄 IDENTITY.md - Agent identity")))
b.WriteString("\n") 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("\n")
b.WriteString(lipgloss.NewStyle().PaddingLeft(4).Render(dimStyle.Render(" 📄 USER.md - User profile"))) b.WriteString(lipgloss.NewStyle().PaddingLeft(4).Render(dimStyle.Render(" 📄 USER.md - User profile")))
b.WriteString("\n\n") 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("\n")
b.WriteString(lipgloss.NewStyle().PaddingLeft(4).Render(dimStyle.Render("Config: ~/.picoclaw/config.json"))) b.WriteString(lipgloss.NewStyle().PaddingLeft(4).Render(dimStyle.Render("Config: ~/.picoclaw/config.json")))
b.WriteString("\n") 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("\n")
b.WriteString(lipgloss.NewStyle().PaddingLeft(4).Render(dimStyle.Render("Press Enter or q to exit"))) b.WriteString(lipgloss.NewStyle().PaddingLeft(4).Render(dimStyle.Render("Press Enter or q to exit")))
} }