diff --git a/cmd/config.go b/cmd/config.go index 0607f61..5caca37 100644 --- a/cmd/config.go +++ b/cmd/config.go @@ -122,7 +122,7 @@ func runInteractiveConfig() { // Dynamically generate available models for OpenAI availableModels := map[string][]string{ "openai": {}, - "copilot": {"gpt-5-mini"}, // TODO: update if copilot models are dynamic + "copilot": {"openai/gpt-5-mini"}, // TODO: update if copilot models are dynamic } modelDisplayToID := map[string]string{} diff --git a/internal/config/config.go b/internal/config/config.go index 36191a4..6a96550 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -5,6 +5,7 @@ import ( "fmt" "net/url" "os" + "os/exec" "path/filepath" "runtime" "strings" @@ -13,8 +14,8 @@ import ( ) type ProviderConfig struct { - APIKey string `mapstructure:"api_key"` - Model string `mapstructure:"model"` + APIKey string `mapstructure:"api_key"` + Model string `mapstructure:"model"` EndpointURL string `mapstructure:"endpoint_url"` } @@ -37,7 +38,7 @@ func InitConfig() { viper.SetDefault("providers.copilot.model", "openai/gpt-5-mini") } else { viper.SetDefault("active_provider", "openai") - viper.SetDefault("providers.openai.model", "gpt-5-mini") + viper.SetDefault("providers.openai.model", "openai/gpt-5-mini") } viper.AutomaticEnv() @@ -90,9 +91,6 @@ func GetAPIKey() (string, error) { if cfg == nil { InitConfig() } - if cfg.ActiveProvider == "copilot" { - return LoadGitHubToken() - } providerConfig, err := GetActiveProviderConfig() if err != nil { @@ -213,12 +211,9 @@ func SetEndpoint(provider, endpoint string) error { } func LoadGitHubToken() (string, error) { - if token := os.Getenv("GITHUB_TOKEN"); token != "" { - return token, nil - } - - if token := os.Getenv("GITHUB_MODELS_TOKEN"); token != "" { - return token, nil + tok, err := tryGetTokenFromGHCLI() + if err == nil && tok != "" { + return tok, nil } configDir := getConfigDir() @@ -248,20 +243,30 @@ func LoadGitHubToken() (string, error) { } } - return "", fmt.Errorf("GitHub token not found. Please set GITHUB_TOKEN or GITHUB_MODELS_TOKEN environment variable with a Personal Access Token that has 'models' scope") + return "", fmt.Errorf("GitHub token not found via 'gh auth token'; run 'gh auth login' to authenticate the GitHub CLI") +} +func tryGetTokenFromGHCLI() (string, error) { + out, err := exec.Command("gh", "auth", "token").Output() + if err != nil { + return "", err + } + tok := strings.TrimSpace(string(out)) + if tok == "" { + return "", fmt.Errorf("gh returned empty token") + } + return tok, nil } func getConfigDir() string { if xdgConfig := os.Getenv("XDG_CONFIG_HOME"); xdgConfig != "" { return xdgConfig - - // WARNING: The code is not woking } else if runtime.GOOS == "windows" { - if localAppData := os.Getenv("LOCALAPPDATA"); localAppData != "" { - return localAppData - } else { - return filepath.Join(os.Getenv("HOME"), "AppData", "Local") + homeDir, err := os.UserHomeDir() + if err != nil { + fmt.Println("Error getting user home directory:", err) + os.Exit(1) } + return filepath.Join(homeDir, "AppData", "Local") } else { return filepath.Join(os.Getenv("HOME"), ".config") } diff --git a/internal/provider/copilot.go b/internal/provider/copilot.go index aa6e040..12d8235 100644 --- a/internal/provider/copilot.go +++ b/internal/provider/copilot.go @@ -2,7 +2,6 @@ package provider import ( "context" - "encoding/json" "fmt" "net/http" "os" @@ -59,39 +58,6 @@ func normalizeCopilotModel(model string) string { return m } -func (c *CopilotProvider) exchangeGitHubToken(ctx context.Context, githubToken string) (string, error) { - req, err := http.NewRequestWithContext(ctx, http.MethodGet, "https://api.github.com/copilot_internal/v2/token", nil) - if err != nil { - return "", fmt.Errorf("failed creating token request: %w", err) - } - req.Header.Set("Authorization", "Token "+githubToken) - req.Header.Set("User-Agent", "lazycommit/1.0") - - resp, err := c.httpClient.Do(req) - if err != nil { - return "", fmt.Errorf("failed exchanging token: %w", err) - } - defer resp.Body.Close() - if resp.StatusCode != http.StatusOK { - var body struct { - Message string `json:"message"` - } - _ = json.NewDecoder(resp.Body).Decode(&body) - return "", fmt.Errorf("token exchange failed: %d %s", resp.StatusCode, body.Message) - } - var tr struct { - Token string `json:"token"` - ExpiresAt int64 `json:"expires_at"` - } - if err := json.NewDecoder(resp.Body).Decode(&tr); err != nil { - return "", fmt.Errorf("failed decoding token response: %w", err) - } - if tr.Token == "" { - return "", fmt.Errorf("empty copilot bearer token") - } - return tr.Token, nil -} - func (c *CopilotProvider) getGitHubToken() string { if c.apiKey != "" { return c.apiKey @@ -122,10 +88,7 @@ func (c *CopilotProvider) GenerateCommitMessages(ctx context.Context, diff strin return nil, fmt.Errorf("GitHub token is required for Copilot provider") } - bearer, err := c.exchangeGitHubToken(ctx, githubToken) - if err != nil { - return nil, err - } + bearer := githubToken client := openai.NewClient( option.WithBaseURL(c.endpoint),