refactor(config): centralize config loading and add model selection

- Introduce config.Load() to handle centralized configuration loading in TOML format
- Add --model flag support across commands with alias resolution via GetModel
- Update root command to load config in PersistentPreRun
- Remove redundant config init and set defaults for model and temperature
This commit is contained in:
Greg Gauthier 2026-02-28 20:52:03 +00:00
parent 5112f13fdd
commit 349346eb4e
9 changed files with 65 additions and 20 deletions

View File

@ -8,6 +8,7 @@ import (
"github.com/fatih/color"
"github.com/spf13/cobra"
"gmgauthier.com/grokkit/config"
"gmgauthier.com/grokkit/internal/grok"
)
@ -21,6 +22,9 @@ var chatCmd = &cobra.Command{
history := []map[string]string{}
scanner := bufio.NewScanner(os.Stdin)
modelFlag, _ := cmd.Flags().GetString("model")
model := config.GetModel(modelFlag)
for {
fmt.Print(color.YellowString("You: "))
if !scanner.Scan() {
@ -36,7 +40,7 @@ var chatCmd = &cobra.Command{
history = append(history, map[string]string{"role": "user", "content": input})
color.Green("Grok: ")
reply := client.Stream(history, "grok-4")
reply := client.Stream(history, model)
history = append(history, map[string]string{"role": "assistant", "content": reply})
}
},

View File

@ -6,6 +6,7 @@ import (
"github.com/fatih/color"
"github.com/spf13/cobra"
"gmgauthier.com/grokkit/config"
"gmgauthier.com/grokkit/internal/git"
"gmgauthier.com/grokkit/internal/grok"
)
@ -19,13 +20,16 @@ var commitCmd = &cobra.Command{
color.Yellow("No staged changes!")
return
}
modelFlag, _ := cmd.Flags().GetString("model")
model := config.GetModel(modelFlag)
client := grok.NewClient()
messages := []map[string]string{
{"role": "system", "content": "Return ONLY a conventional commit message (type(scope): subject\n\nbody)."},
{"role": "user", "content": fmt.Sprintf("Staged changes:\n%s", diff)},
}
color.Yellow("Generating commit message...")
msg := client.Stream(messages, "grok-4")
msg := client.Stream(messages, model)
color.Cyan("\nProposed commit message:\n%s", msg)
var confirm string

View File

@ -5,6 +5,7 @@ import (
"github.com/fatih/color"
"github.com/spf13/cobra"
"gmgauthier.com/grokkit/config"
"gmgauthier.com/grokkit/internal/git"
"gmgauthier.com/grokkit/internal/grok"
)
@ -18,12 +19,15 @@ var commitMsgCmd = &cobra.Command{
color.Yellow("No staged changes!")
return
}
modelFlag, _ := cmd.Flags().GetString("model")
model := config.GetModel(modelFlag)
client := grok.NewClient()
messages := []map[string]string{
{"role": "system", "content": "Return ONLY a conventional commit message (type(scope): subject\n\nbody)."},
{"role": "user", "content": fmt.Sprintf("Staged changes:\n%s", diff)},
}
color.Yellow("Generating commit message...")
client.Stream(messages, "grok-4")
client.Stream(messages, model)
},
}

View File

@ -7,6 +7,7 @@ import (
"github.com/fatih/color"
"github.com/spf13/cobra"
"gmgauthier.com/grokkit/config"
"gmgauthier.com/grokkit/internal/grok"
)
@ -18,6 +19,9 @@ var editCmd = &cobra.Command{
filePath := args[0]
instruction := args[1]
modelFlag, _ := cmd.Flags().GetString("model")
model := config.GetModel(modelFlag)
if _, err := os.Stat(filePath); os.IsNotExist(err) {
color.Red("File not found: %s", filePath)
os.Exit(1)
@ -34,7 +38,7 @@ var editCmd = &cobra.Command{
}
color.Yellow("Asking Grok to %s...", instruction)
raw := client.Stream(messages, "grok-4-1-fast-non-reasoning")
raw := client.Stream(messages, model)
newContent := grok.CleanCodeResponse(raw)
// Nice unified diff preview

View File

@ -3,6 +3,7 @@ package cmd
import (
"github.com/fatih/color"
"github.com/spf13/cobra"
"gmgauthier.com/grokkit/config"
"gmgauthier.com/grokkit/internal/git"
"gmgauthier.com/grokkit/internal/grok"
)
@ -16,12 +17,16 @@ var historyCmd = &cobra.Command{
color.Yellow("No commits found.")
return
}
modelFlag, _ := cmd.Flags().GetString("model")
model := config.GetModel(modelFlag)
client := grok.NewClient()
messages := []map[string]string{
{"role": "system", "content": "Summarize the recent git history in 3-5 bullet points."},
{"role": "user", "content": log},
}
color.Yellow("Summarizing recent commits...")
client.Stream(messages, "grok-4")
client.Stream(messages, model)
},
}

View File

@ -5,6 +5,7 @@ import (
"github.com/fatih/color"
"github.com/spf13/cobra"
"gmgauthier.com/grokkit/config"
"gmgauthier.com/grokkit/internal/git"
"gmgauthier.com/grokkit/internal/grok"
)
@ -21,12 +22,15 @@ var prDescribeCmd = &cobra.Command{
color.Yellow("No changes on this branch compared to main/origin/main.")
return
}
modelFlag, _ := cmd.Flags().GetString("model")
model := config.GetModel(modelFlag)
client := grok.NewClient()
messages := []map[string]string{
{"role": "system", "content": "Write a professional GitHub PR title + detailed body (changes, motivation, testing notes)."},
{"role": "user", "content": fmt.Sprintf("Diff:\n%s", diff)},
}
color.Yellow("Writing PR description...")
client.Stream(messages, "grok-4")
client.Stream(messages, model)
},
}

View File

@ -5,6 +5,7 @@ import (
"github.com/fatih/color"
"github.com/spf13/cobra"
"gmgauthier.com/grokkit/config"
"gmgauthier.com/grokkit/internal/git"
"gmgauthier.com/grokkit/internal/grok"
)
@ -13,6 +14,9 @@ var reviewCmd = &cobra.Command{
Use: "review [path]",
Short: "Review the current repository or directory",
Run: func(cmd *cobra.Command, args []string) {
modelFlag, _ := cmd.Flags().GetString("model")
model := config.GetModel(modelFlag)
client := grok.NewClient()
diff := git.Run([]string{"diff", "--no-color"})
status := git.Run([]string{"status", "--short"})
@ -22,6 +26,6 @@ var reviewCmd = &cobra.Command{
{"role": "user", "content": fmt.Sprintf("Git status:\n%s\n\nGit diff:\n%s", status, diff)},
}
color.Yellow("Grok is reviewing the repo...")
client.Stream(messages, "grok-4")
client.Stream(messages, model)
},
}

View File

@ -4,7 +4,6 @@ import (
"os"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"gmgauthier.com/grokkit/config"
)
@ -12,6 +11,9 @@ var rootCmd = &cobra.Command{
Use: "grokkit",
Short: "Personal Grok / xAI command-line toolkit",
Long: `A fast, native Go CLI for Grok. Chat, edit files, and supercharge your git workflow.`,
PersistentPreRun: func(cmd *cobra.Command, args []string) {
config.Load()
},
}
func Execute() {
@ -21,10 +23,6 @@ func Execute() {
}
func init() {
config.InitConfig()
rootCmd.PersistentFlags().StringP("model", "m", "grok-4", "Grok model (grok-4, grok-3, etc.)")
viper.BindPFlag("model", rootCmd.PersistentFlags().Lookup("model"))
rootCmd.AddCommand(chatCmd)
rootCmd.AddCommand(editCmd)
rootCmd.AddCommand(reviewCmd)

View File

@ -2,17 +2,35 @@ package config
import (
"os"
"path/filepath"
"github.com/spf13/viper"
)
func InitConfig() {
viper.SetConfigName("grokkit")
viper.SetConfigType("yaml")
func Load() {
home, _ := os.UserHomeDir()
viper.AddConfigPath(home + "/.config/grokkit")
viper.SetDefault("model", "grok-4")
viper.SetDefault("chat.history_file", home+"/.config/grokkit/chat_history.json")
viper.AutomaticEnv()
_ = viper.ReadInConfig()
configPath := filepath.Join(home, ".config", "grokkit")
viper.SetConfigName("config")
viper.SetConfigType("toml")
viper.AddConfigPath(configPath)
viper.AddConfigPath(".")
viper.AutomaticEnv() // XAI_API_KEY etc.
viper.SetDefault("default_model", "grok-4")
viper.SetDefault("temperature", 0.7)
_ = viper.ReadInConfig() // ignore error if no config yet
}
// GetModel returns the model, respecting --model flag or alias
func GetModel(flagModel string) string {
if flagModel != "" {
// Check alias first
if alias := viper.GetString("aliases." + flagModel); alias != "" {
return alias
}
return flagModel
}
return viper.GetString("default_model")
}