From 349346eb4e0a44244824ce8b9c254a6ee685e15d Mon Sep 17 00:00:00 2001 From: Greg Gauthier Date: Sat, 28 Feb 2026 20:52:03 +0000 Subject: [PATCH] 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 --- cmd/chat.go | 6 +++++- cmd/commit.go | 6 +++++- cmd/commitmsg.go | 6 +++++- cmd/edit.go | 6 +++++- cmd/history.go | 7 ++++++- cmd/prdescribe.go | 6 +++++- cmd/review.go | 6 +++++- cmd/root.go | 8 +++----- config/config.go | 34 ++++++++++++++++++++++++++-------- 9 files changed, 65 insertions(+), 20 deletions(-) diff --git a/cmd/chat.go b/cmd/chat.go index 4a9a334..de36c30 100644 --- a/cmd/chat.go +++ b/cmd/chat.go @@ -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}) } }, diff --git a/cmd/commit.go b/cmd/commit.go index 5ab7ccf..17c41fe 100644 --- a/cmd/commit.go +++ b/cmd/commit.go @@ -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 diff --git a/cmd/commitmsg.go b/cmd/commitmsg.go index 658a740..5881ac6 100644 --- a/cmd/commitmsg.go +++ b/cmd/commitmsg.go @@ -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) }, } diff --git a/cmd/edit.go b/cmd/edit.go index 25ab4f4..5442071 100644 --- a/cmd/edit.go +++ b/cmd/edit.go @@ -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 diff --git a/cmd/history.go b/cmd/history.go index 9d8018b..7f9d453 100644 --- a/cmd/history.go +++ b/cmd/history.go @@ -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) }, } diff --git a/cmd/prdescribe.go b/cmd/prdescribe.go index 39619dc..9c73132 100644 --- a/cmd/prdescribe.go +++ b/cmd/prdescribe.go @@ -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) }, } diff --git a/cmd/review.go b/cmd/review.go index 484b834..90dce62 100644 --- a/cmd/review.go +++ b/cmd/review.go @@ -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) }, } diff --git a/cmd/root.go b/cmd/root.go index 963718f..73ef26f 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -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) diff --git a/config/config.go b/config/config.go index 7d47b0e..ecd9199 100644 --- a/config/config.go +++ b/config/config.go @@ -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") }