Skip to content

Commit 4f0c1c6

Browse files
authored
feat: add configuration persistence for model selections (#154)
1 parent e8b4bb0 commit 4f0c1c6

File tree

1 file changed

+58
-51
lines changed

1 file changed

+58
-51
lines changed

internal/config/config.go

Lines changed: 58 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ type Provider struct {
5757

5858
// Data defines storage configuration.
5959
type Data struct {
60-
Directory string `json:"directory"`
60+
Directory string `json:"directory,omitempty"`
6161
}
6262

6363
// LSPConfig defines configuration for Language Server Protocol integration.
@@ -86,7 +86,7 @@ type Config struct {
8686
MCPServers map[string]MCPServer `json:"mcpServers,omitempty"`
8787
Providers map[models.ModelProvider]Provider `json:"providers,omitempty"`
8888
LSP map[string]LSPConfig `json:"lsp,omitempty"`
89-
Agents map[AgentName]Agent `json:"agents"`
89+
Agents map[AgentName]Agent `json:"agents,omitempty"`
9090
Debug bool `json:"debug,omitempty"`
9191
DebugLSP bool `json:"debugLSP,omitempty"`
9292
ContextPaths []string `json:"contextPaths,omitempty"`
@@ -721,6 +721,52 @@ func setDefaultModelForAgent(agent AgentName) bool {
721721
return false
722722
}
723723

724+
func updateCfgFile(updateCfg func(config *Config)) error {
725+
if cfg == nil {
726+
return fmt.Errorf("config not loaded")
727+
}
728+
729+
// Get the config file path
730+
configFile := viper.ConfigFileUsed()
731+
var configData []byte
732+
if configFile == "" {
733+
homeDir, err := os.UserHomeDir()
734+
if err != nil {
735+
return fmt.Errorf("failed to get home directory: %w", err)
736+
}
737+
configFile = filepath.Join(homeDir, fmt.Sprintf(".%s.json", appName))
738+
logging.Info("config file not found, creating new one", "path", configFile)
739+
configData = []byte(`{}`)
740+
} else {
741+
// Read the existing config file
742+
data, err := os.ReadFile(configFile)
743+
if err != nil {
744+
return fmt.Errorf("failed to read config file: %w", err)
745+
}
746+
configData = data
747+
}
748+
749+
// Parse the JSON
750+
var userCfg *Config
751+
if err := json.Unmarshal(configData, &userCfg); err != nil {
752+
return fmt.Errorf("failed to parse config file: %w", err)
753+
}
754+
755+
updateCfg(userCfg)
756+
757+
// Write the updated config back to file
758+
updatedData, err := json.MarshalIndent(userCfg, "", " ")
759+
if err != nil {
760+
return fmt.Errorf("failed to marshal config: %w", err)
761+
}
762+
763+
if err := os.WriteFile(configFile, updatedData, 0o644); err != nil {
764+
return fmt.Errorf("failed to write config file: %w", err)
765+
}
766+
767+
return nil
768+
}
769+
724770
// Get returns the current configuration.
725771
// It's safe to call this function multiple times.
726772
func Get() *Config {
@@ -765,7 +811,12 @@ func UpdateAgentModel(agentName AgentName, modelID models.ModelID) error {
765811
return fmt.Errorf("failed to update agent model: %w", err)
766812
}
767813

768-
return nil
814+
return updateCfgFile(func(config *Config) {
815+
if config.Agents == nil {
816+
config.Agents = make(map[AgentName]Agent)
817+
}
818+
config.Agents[agentName] = newAgentCfg
819+
})
769820
}
770821

771822
// UpdateTheme updates the theme in the configuration and writes it to the config file.
@@ -777,52 +828,8 @@ func UpdateTheme(themeName string) error {
777828
// Update the in-memory config
778829
cfg.TUI.Theme = themeName
779830

780-
// Get the config file path
781-
configFile := viper.ConfigFileUsed()
782-
var configData []byte
783-
if configFile == "" {
784-
homeDir, err := os.UserHomeDir()
785-
if err != nil {
786-
return fmt.Errorf("failed to get home directory: %w", err)
787-
}
788-
configFile = filepath.Join(homeDir, fmt.Sprintf(".%s.json", appName))
789-
logging.Info("config file not found, creating new one", "path", configFile)
790-
configData = []byte(`{}`)
791-
} else {
792-
// Read the existing config file
793-
data, err := os.ReadFile(configFile)
794-
if err != nil {
795-
return fmt.Errorf("failed to read config file: %w", err)
796-
}
797-
configData = data
798-
}
799-
800-
// Parse the JSON
801-
var configMap map[string]interface{}
802-
if err := json.Unmarshal(configData, &configMap); err != nil {
803-
return fmt.Errorf("failed to parse config file: %w", err)
804-
}
805-
806-
// Update just the theme value
807-
tuiConfig, ok := configMap["tui"].(map[string]interface{})
808-
if !ok {
809-
// TUI config doesn't exist yet, create it
810-
configMap["tui"] = map[string]interface{}{"theme": themeName}
811-
} else {
812-
// Update existing TUI config
813-
tuiConfig["theme"] = themeName
814-
configMap["tui"] = tuiConfig
815-
}
816-
817-
// Write the updated config back to file
818-
updatedData, err := json.MarshalIndent(configMap, "", " ")
819-
if err != nil {
820-
return fmt.Errorf("failed to marshal config: %w", err)
821-
}
822-
823-
if err := os.WriteFile(configFile, updatedData, 0o644); err != nil {
824-
return fmt.Errorf("failed to write config file: %w", err)
825-
}
826-
827-
return nil
831+
// Update the file config
832+
return updateCfgFile(func(config *Config) {
833+
config.TUI.Theme = themeName
834+
})
828835
}

0 commit comments

Comments
 (0)