Documentation
¶
Index ¶
- Variables
- func GenerateEnvVarName(providerName string) string
- func GenerateExportLine(providerName, apiKey string) string
- func GetBackLabel(screen Screen) string
- func GetExportPreview(providerName, apiKey string) string
- func GetScreenTitle(screen Screen) string
- func ValidateHost(host string) bool
- func ValidatePort(port string) bool
- type ProviderPreset
- type Screen
- type ShellConfig
- func (s *ShellConfig) AddToShellConfig(providerName, apiKey string) error
- func (s *ShellConfig) RemoveFromShellConfig(providerName string) error
- func (s *ShellConfig) SourceAllNow(apiKeys map[string]string)
- func (s *ShellConfig) SourceNow(providerName, apiKey string) error
- func (s *ShellConfig) SyncAllShellExports(apiKeys map[string]string) error
- func (s *ShellConfig) WriteEnvFile(apiKeys map[string]string) (string, error)
- type TestConnectionResult
- type TestConnectionResultMsg
- type WizardKeyMap
- type WizardModel
- type WizardState
Constants ¶
This section is empty.
Variables ¶
var ( // Background colors (kept for selected/interactive elements only) BaseBackground = lipgloss.AdaptiveColor{Light: "#f8f8f2", Dark: "#1e1e2e"} PanelBackground = lipgloss.AdaptiveColor{Light: "#ffffff", Dark: "#313244"} AltRowBackground = lipgloss.AdaptiveColor{Light: "#eff0eb", Dark: "#45475a"} // Text colors PrimaryText = lipgloss.AdaptiveColor{Light: "#282a36", Dark: "#cdd6f4"} SecondaryText = lipgloss.AdaptiveColor{Light: "#6272a4", Dark: "#a6adc8"} HeaderText = lipgloss.AdaptiveColor{Light: "#bd93f9", Dark: "#cba6f7"} // Accent colors SelectionAccent = lipgloss.AdaptiveColor{Light: "#8be9fd", Dark: "#89b4fa"} BorderColor = lipgloss.AdaptiveColor{Light: "#44475a", Dark: "#585b70"} // Status colors SuccessColor = lipgloss.AdaptiveColor{Light: "#2e7d32", Dark: "#a6e3a1"} SuccessBorder = lipgloss.AdaptiveColor{Light: "#1b5e20", Dark: "#4e8254"} ErrorColor = lipgloss.AdaptiveColor{Light: "#c62828", Dark: "#f38ba8"} ErrorBorder = lipgloss.AdaptiveColor{Light: "#8e0000", Dark: "#b34d4d"} WarningColor = lipgloss.AdaptiveColor{Light: "#e65100", Dark: "#fab387"} InfoColor = lipgloss.AdaptiveColor{Light: "#1565c0", Dark: "#89b4fa"} )
Wizard color palette - Adaptive (light/dark terminal themes)
var ( // Main container MainContainerStyle = lipgloss.NewStyle(). Foreground(PrimaryText). Width(64). Border(lipgloss.RoundedBorder()). BorderForeground(BorderColor). Padding(1, 2) // Title style TitleStyle = lipgloss.NewStyle(). Bold(true). Foreground(HeaderText). Width(60). Align(lipgloss.Center) // Section header SectionHeaderStyle = lipgloss.NewStyle(). Bold(true). Foreground(HeaderText). Padding(0, 1) // Menu item - unselected MenuItemStyle = lipgloss.NewStyle(). Foreground(PrimaryText). Padding(0, 2) // Menu item - selected (keeps background for visual distinction) MenuItemSelectedStyle = lipgloss.NewStyle(). Foreground(PrimaryText). Background(SelectionAccent). Bold(true). Padding(0, 2) // Menu item - dimmed (for info display) MenuItemDimmedStyle = lipgloss.NewStyle(). Foreground(SecondaryText). Padding(0, 2) // Menu item description (used when item is selected) MenuItemDescriptionStyle = lipgloss.NewStyle(). Foreground(PrimaryText). Background(SelectionAccent). Padding(0, 2) // Input field InputFieldStyle = lipgloss.NewStyle(). Foreground(PrimaryText). Border(lipgloss.NormalBorder()). BorderForeground(BorderColor). Padding(0, 1) // Input field focused InputFieldFocusedStyle = lipgloss.NewStyle(). Foreground(PrimaryText). Border(lipgloss.NormalBorder()). BorderForeground(SelectionAccent). Padding(0, 1) // Button - unselected ButtonStyle = lipgloss.NewStyle(). Foreground(PrimaryText). Background(PanelBackground). Border(lipgloss.NormalBorder()). BorderForeground(BorderColor). Padding(0, 2) // Button - selected/active (keeps background) ButtonActiveStyle = lipgloss.NewStyle(). Foreground(PrimaryText). Background(SelectionAccent). Bold(true). Border(lipgloss.NormalBorder()). BorderForeground(SelectionAccent). Padding(0, 2) // Primary button (keeps background) ButtonPrimaryStyle = lipgloss.NewStyle(). Foreground(BaseBackground). Background(SuccessColor). Bold(true). Border(lipgloss.NormalBorder()). BorderForeground(SuccessBorder). Padding(0, 2) // Danger button (keeps background) ButtonDangerStyle = lipgloss.NewStyle(). Foreground(BaseBackground). Background(ErrorColor). Bold(true). Border(lipgloss.NormalBorder()). BorderForeground(ErrorBorder). Padding(0, 2) // Checkbox - unchecked CheckboxUncheckedStyle = lipgloss.NewStyle(). Foreground(SecondaryText). SetString("[ ]") // Checkbox - checked CheckboxCheckedStyle = lipgloss.NewStyle(). Foreground(SuccessColor). SetString("[✓]") // Checkbox - unchecked + focused (cyan highlight) CheckboxUncheckedFocusedStyle = lipgloss.NewStyle(). Foreground(SelectionAccent). Bold(true). SetString("[ ]") // Checkbox - checked + focused (cyan highlight) CheckboxCheckedFocusedStyle = lipgloss.NewStyle(). Foreground(SelectionAccent). Bold(true). SetString("[✓]") // Input field - disabled (dimmed, no border) InputFieldDisabledStyle = lipgloss.NewStyle(). Foreground(SecondaryText). Padding(0, 1) // Focused row highlight background FocusedRowStyle = lipgloss.NewStyle(). Background(AltRowBackground). Padding(0, 1) // Status indicators StatusOKStyle = lipgloss.NewStyle().Foreground(SuccessColor) StatusErrorStyle = lipgloss.NewStyle().Foreground(ErrorColor) StatusPendingStyle = lipgloss.NewStyle().Foreground(WarningColor).SetString("⟳") // List item - unselected ListItemStyle = lipgloss.NewStyle(). Foreground(PrimaryText). Padding(0, 1) // List item - selected (keeps background) ListItemSelectedStyle = lipgloss.NewStyle(). Foreground(PrimaryText). Background(SelectionAccent). Padding(0, 1) // List item - invalid (provider/model not found) ListItemInvalidStyle = lipgloss.NewStyle(). Foreground(ErrorColor). Padding(0, 1) // List item - invalid + selected ListItemInvalidSelectedStyle = lipgloss.NewStyle(). Foreground(ErrorColor). Background(SelectionAccent). Padding(0, 1) // Table header TableHeaderStyle = lipgloss.NewStyle(). Bold(true). Foreground(HeaderText). Border(lipgloss.NormalBorder()). BorderBottom(true). BorderForeground(BorderColor) // Table row TableRowStyle = lipgloss.NewStyle(). Foreground(PrimaryText) // Table row - alternate (keeps background for visual distinction) TableRowAltStyle = lipgloss.NewStyle(). Foreground(PrimaryText). Background(AltRowBackground) // Modal/Overlay ModalStyle = lipgloss.NewStyle(). Foreground(PrimaryText). Background(PanelBackground). Width(50). Height(9). Border(lipgloss.RoundedBorder()). BorderForeground(HeaderText). Padding(1, 2). Align(lipgloss.Center) // Dropdown floating panel (keeps background for overlay distinction) DropdownStyle = lipgloss.NewStyle(). Border(lipgloss.RoundedBorder()). BorderForeground(SelectionAccent). Background(PanelBackground). Padding(0, 1). Width(42) // Error message ErrorStyle = lipgloss.NewStyle(). Foreground(ErrorColor). Padding(0, 1) // Warning message (inline, no padding) WarningStyle = lipgloss.NewStyle(). Foreground(ErrorColor) // Help text HelpTextStyle = lipgloss.NewStyle(). Foreground(SecondaryText). Padding(0, 1) // Key hint KeyHintStyle = lipgloss.NewStyle(). Foreground(SelectionAccent). SetString("[" + "key" + "]") // Profile tab styles TabStyle = lipgloss.NewStyle(). Foreground(SecondaryText). Padding(0, 1). MarginRight(1) TabActiveStyle = lipgloss.NewStyle(). Foreground(PrimaryText). Background(SelectionAccent). Bold(true). Padding(0, 1). MarginRight(1) TabAddStyle = lipgloss.NewStyle(). Foreground(HeaderText). Padding(0, 1). MarginRight(1) TabAddActiveStyle = lipgloss.NewStyle(). Foreground(PrimaryText). Background(HeaderText). Bold(true). Padding(0, 1). MarginRight(1) // Launch profile indicator (★) LaunchProfileIndicator = lipgloss.NewStyle(). Foreground(SuccessColor). SetString("★") // Profile modal styles ProfileModalStyle = lipgloss.NewStyle(). Foreground(PrimaryText). Background(PanelBackground). Width(56). Border(lipgloss.RoundedBorder()). BorderForeground(HeaderText). Padding(1, 2) )
Base styles (no backgrounds on non-interactive elements — terminal native bg shows through)
var LogDestinationOptions = []string{"stdout", "stderr", "file"}
LogDestinationOptions are the available log destination options.
var LogLevelOptions = []string{"debug", "info", "warn", "error"}
LogLevelOptions are the available log level options.
var PredefinedRouteNames = []string{
"default",
"background",
"think",
"thinkMore",
"ultrathink",
"longContext",
"image",
"webSearch",
}
PredefinedRouteNames are the built-in route names.
var ProviderPresets = map[string]ProviderPreset{ "alicloud": { BaseURL: "https://coding.dashscope.aliyuncs.com/apps/anthropic", Transformer: "glm_anthropic", Models: []string{"MiniMax-M2.5", "kimi-k2.5", "qwen3-coder-plus", "glm-5", "glm-4.7"}, }, "anthropic": { BaseURL: "https://api.anthropic.com", Transformer: "anthropic", Models: []string{"claude-haiku-4.5", "claude-sonnet-4.6", "claude-opus-4.5", "claude-opus-4.6"}, }, "bigmodel": { BaseURL: "https://open.bigmodel.cn/api", Transformer: "glm_anthropic", Models: []string{"glm-4.6v", "glm-4.7", "glm-5-turbo", "glm-5v-turbo", "glm-5.1"}, }, "openrouter": { BaseURL: "https://openrouter.ai/api", Transformer: "anthropic", Models: []string{"openai/gpt-5.4", "openai/gpt-5.4-mini", "openai/gpt-5.3-codex", "google/gemini-2.5-flash", "google/gemini-2.5-pro"}, }, "openrouter-openai": { BaseURL: "https://openrouter.ai/api", Transformer: "anthropic", Models: []string{"openai/gpt-5.4", "openai/gpt-5.4-mini", "openai/gpt-5.3-codex"}, }, "openrouter-anthropic": { BaseURL: "https://openrouter.ai/api", Transformer: "anthropic", Models: []string{"anthropic/claude-haiku-4.5", "anthropic/claude-sonnet-4.5", "anthropic/claude-sonnet-4.6", "anthropic/claude-opus-4.5", "anthropic/claude-opus-4.6"}, }, }
ProviderPresets contains all available provider presets.
var TransformerOptions = []string{"anthropic", "openai", "glm_anthropic", "gemini"}
TransformerOptions are the available transformer options.
Functions ¶
func GenerateEnvVarName ¶
GenerateEnvVarName generates the environment variable name for a provider.
func GenerateExportLine ¶
GenerateExportLine generates the shell export line for an API key.
func GetBackLabel ¶
GetBackLabel returns the back label for a screen.
func GetExportPreview ¶
GetExportPreview returns a preview of what will be added to the shell config.
func GetScreenTitle ¶
GetScreenTitle returns the title for a screen.
func ValidateHost ¶
ValidateHost validates that the host is not empty.
func ValidatePort ¶
ValidatePort validates that the port is in the valid range.
Types ¶
type ProviderPreset ¶
ProviderPreset defines preset provider configurations.
type ShellConfig ¶
ShellConfig handles shell configuration for API keys.
func GetShellConfig ¶
func GetShellConfig() (*ShellConfig, error)
GetShellConfig returns the appropriate shell configuration.
func (*ShellConfig) AddToShellConfig ¶
func (s *ShellConfig) AddToShellConfig(providerName, apiKey string) error
AddToShellConfig adds the API key export to the shell RC file. Uses a two-phase approach: remove all existing ccrouter entries for this provider, then append a single fresh comment+export pair.
func (*ShellConfig) RemoveFromShellConfig ¶
func (s *ShellConfig) RemoveFromShellConfig(providerName string) error
RemoveFromShellConfig removes the API key export for a provider from the RC file. Uses the same Phase 1 filtering as AddToShellConfig but without Phase 2 append.
func (*ShellConfig) SourceAllNow ¶
func (s *ShellConfig) SourceAllNow(apiKeys map[string]string)
SourceAllNow exports all API keys in the current process environment.
func (*ShellConfig) SourceNow ¶
func (s *ShellConfig) SourceNow(providerName, apiKey string) error
SourceNow exports the API key in the current process environment.
func (*ShellConfig) SyncAllShellExports ¶
func (s *ShellConfig) SyncAllShellExports(apiKeys map[string]string) error
SyncAllShellExports removes ALL ccrouter entries from the RC file, then re-adds entries for the given apiKeys map (provider name → real API key value). This ensures the RC file is fully reconciled with the current config.
func (*ShellConfig) WriteEnvFile ¶
func (s *ShellConfig) WriteEnvFile(apiKeys map[string]string) (string, error)
WriteEnvFile writes a shell env file at ~/.cc-modelrouter/shell_env.sh containing export lines for the given API keys. Returns the file path.
type TestConnectionResult ¶
type TestConnectionResult struct {
Success bool
Latency time.Duration
Error string
InputTokens int
OutputTokens int
CostEstimate string
}
TestConnectionResult contains the result of a connection test.
func TestProviderConnection ¶
func TestProviderConnection(providerName string, providerCfg config.ProviderConfig, model string) *TestConnectionResult
TestProviderConnection tests connectivity to a provider with a specific model.
type TestConnectionResultMsg ¶
type WizardKeyMap ¶
type WizardKeyMap struct {
Up key.Binding
Down key.Binding
Enter key.Binding
Escape key.Binding
Delete key.Binding
Tab key.Binding
}
WizardKeyMap defines the key bindings for the wizard.
func DefaultKeyMap ¶
func DefaultKeyMap() WizardKeyMap
DefaultKeyMap returns the default key bindings.
type WizardModel ¶
type WizardModel struct {
// contains filtered or unexported fields
}
WizardModel is the main Bubble Tea model for the wizard.
func NewWizardModel ¶
func NewWizardModel(cfg *config.Config, configPath string) *WizardModel
NewWizardModel creates a new wizard model.
func (*WizardModel) ResolvedKeys ¶
func (m *WizardModel) ResolvedKeys() map[string]string
ResolvedKeys returns the resolved API keys map from the wizard model.
type WizardState ¶
type WizardState struct {
// Navigation
CurrentScreen Screen
PreviousScreen Screen
// Config being edited
Config *config.Config
ConfigPath string
HasChanges bool
OriginalCfg *config.Config // For detecting changes
// Main menu state
MainMenuCursor int // saved main menu cursor when entering sub-screens
// Provider list screen state
ProviderCursor int
// Add/Edit provider state (Step 1)
NewProviderName string
NewProviderBaseURL string
NewProviderTransformer string
NewProviderModels string
ProviderPreset string // "anthropic", "openrouter", "bigmodel", "gemini", "custom"
EditingProvider bool // true when editing an existing provider
// Add provider state (Step 2)
NewProviderAPIKey string
AddToShellConfig bool
SourceImmediately bool
// Routes screen state
RouteCursor int
// Edit route state
EditRouteName string
EditRouteChain []config.RouteTarget
EditRouteChainCursor int // selected chain item index
SelectedProvider string
SelectedModel string
// Server screen state
ServerHost string
ServerPort string
PortStatus string // non-empty = port availability status (warning or success)
PortTesting bool // true while port availability test is running
// Logging screen state
LoggingEnabled bool
LoggingLevel string
LoggingDestination string
LoggingFilePath string
// Logging dropdown state
ShowLogLevelDropdown bool
LogLevelDropdownCursor int
ShowLogDestDropdown bool
LogDestDropdownCursor int
// Test connection state
TestProvider string
TestModel string
TestStatus string // "testing", "success", "error"
TestError string
TestLatency float64
// Modal/Confirmation
ShowConfirm bool
ConfirmMessage string
ConfirmAction func() bool
ConfirmCursor int // 0 = Yes focused, 1 = No focused
// Resolved API keys (real values, not ${CCROUTER_...} placeholders)
ResolvedAPIKeys map[string]string
OriginalResolvedKeys map[string]string // snapshot for change detection
// Error message
ErrorMessage string
// Dropdown state (Add Provider screen)
ShowDropdown bool
DropdownCursor int
// Model dropdown state (Add Provider screen)
ShowModelDropdown bool
ModelDropdownCursor int
// Route name dropdown state (Edit Route screen)
ShowRouteNameDropdown bool
RouteNameDropdownCursor int
// Profile tabs state (Routes screen)
ProfileTabIndex int // Current tab index (0 = legacy, 1 = default, 2 = ...)
ProfileTabKeys []string // Tab keys in order: ["legacy", "default", "cost-opt", ...]
// Profile edit state (when creating/editing profile metadata)
EditProfileKey string // Profile key being edited (empty when creating new)
EditProfileName string // Profile display name (for rename/create)
EditProfileDesc string // Profile description
ShowProfileEditModal bool // Show profile name/description edit modal (deprecated - use ScreenEditProfile instead)
IsCreatingProfile bool // true when creating new profile, false when editing existing
// Migration state (when creating first profile with legacy routes)
ShowMigrationModal bool // Show migration confirmation modal
MigrationChoice int // 0 = copy routes, 1 = start empty
}
WizardState holds all state for the configuration wizard.
func NewWizardState ¶
func NewWizardState(cfg *config.Config, configPath string) *WizardState
NewWizardState creates a new wizard state with defaults.
func (*WizardState) HasUnsavedChanges ¶
func (s *WizardState) HasUnsavedChanges() bool
HasUnsavedChanges returns true if the config has been modified.