feat: Add gt config command for managing agent settings

Implements GitHub issue #127 - allow custom agent configuration
through a CLI interface instead of command-line aliases.

The gt config command provides:
- gt config agent list [--json]    List all agents
- gt config agent get <name>       Show agent configuration
- gt config agent set <name> <cmd> Set custom agent command
- gt config agent remove <name>    Remove custom agent
- gt config default-agent [name]   Get/set default agent

Users can now define custom agents (e.g., claude-glm) and
override built-in presets (claude, gemini, codex) through
town settings instead of shell aliases.

Changes:
- Add SaveTownSettings() to internal/config/loader.go
- Add internal/cmd/config.go with full config command implementation
- Add comprehensive unit tests for both SaveTownSettings and
  all config subcommands (17 test cases covering success and
  error scenarios)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Darko Luketic
2026-01-05 06:58:46 +01:00
parent f0c94db99e
commit 5787a16067
4 changed files with 1206 additions and 0 deletions

View File

@@ -691,6 +691,31 @@ func LoadOrCreateTownSettings(path string) (*TownSettings, error) {
return &settings, nil
}
// SaveTownSettings saves town settings to a file.
func SaveTownSettings(path string, settings *TownSettings) error {
if settings.Type != "town-settings" && settings.Type != "" {
return fmt.Errorf("%w: expected type 'town-settings', got '%s'", ErrInvalidType, settings.Type)
}
if settings.Version > CurrentTownSettingsVersion {
return fmt.Errorf("%w: got %d, max supported %d", ErrInvalidVersion, settings.Version, CurrentTownSettingsVersion)
}
if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil {
return fmt.Errorf("creating directory: %w", err)
}
data, err := json.MarshalIndent(settings, "", " ")
if err != nil {
return fmt.Errorf("encoding settings: %w", err)
}
if err := os.WriteFile(path, data, 0644); err != nil { //nolint:gosec // G306: settings files don't contain secrets
return fmt.Errorf("writing settings: %w", err)
}
return nil
}
// ResolveAgentConfig resolves the agent configuration for a rig.
// It looks up the agent by name in town settings (custom agents) and built-in presets.
//