on main help sign in
fix(copilot): change import to happen on demand, and also on onboarding
68ad298Andrey Nering
internal/config/config.go+4−1
@@ -9,6 +9,7 @@ import (
9 "net/http"
9 "net/http"
10 "net/url"
10 "net/url"
11 "os"
11 "os"
12+ "path/filepath"
12 "slices"
13 "slices"
13 "strings"
14 "strings"
14 "time"
15 "time"
@@ -498,7 +499,6 @@ func (c *Config) HasConfigField(key string) bool {
498}
499}
499
500
500func (c *Config) SetConfigField(key string, value any) error {
501func (c *Config) SetConfigField(key string, value any) error {
501− // read the data
502 data, err := os.ReadFile(c.dataConfigDir)
502 data, err := os.ReadFile(c.dataConfigDir)
503 if err != nil {
503 if err != nil {
504 if os.IsNotExist(err) {
504 if os.IsNotExist(err) {
@@ -512,6 +512,9 @@ func (c *Config) SetConfigField(key string, value any) error {
512 if err != nil {
512 if err != nil {
513 return fmt.Errorf("failed to set config field %s: %w", key, err)
513 return fmt.Errorf("failed to set config field %s: %w", key, err)
514 }
514 }
515+ if err := os.MkdirAll(filepath.Dir(c.dataConfigDir), 0o755); err != nil {
516+ return fmt.Errorf("failed to create config directory %q: %w", c.dataConfigDir, err)
517+ }
515 if err := os.WriteFile(c.dataConfigDir, []byte(newValue), 0o600); err != nil {
518 if err := os.WriteFile(c.dataConfigDir, []byte(newValue), 0o600); err != nil {
516 return fmt.Errorf("failed to write config file: %w", err)
519 return fmt.Errorf("failed to write config file: %w", err)
517 }
520 }
internal/config/copilot.go+6−1
@@ -6,11 +6,12 @@ import (
6 "log/slog"
6 "log/slog"
7 "testing"
7 "testing"
8
8
9+ "github.com/charmbracelet/catwalk/pkg/catwalk"
9 "github.com/charmbracelet/crush/internal/oauth"
10 "github.com/charmbracelet/crush/internal/oauth"
10 "github.com/charmbracelet/crush/internal/oauth/copilot"
11 "github.com/charmbracelet/crush/internal/oauth/copilot"
11)
12)
12
13
13−func (c *Config) importCopilot() (*oauth.Token, bool) {
14+func (c *Config) ImportCopilot() (*oauth.Token, bool) {
14 if testing.Testing() {
15 if testing.Testing() {
15 return nil, false
16 return nil, false
16 }
17 }
@@ -31,6 +32,10 @@ func (c *Config) importCopilot() (*oauth.Token, bool) {
31 return nil, false
32 return nil, false
32 }
33 }
33
34
35+ if err := c.SetProviderAPIKey(string(catwalk.InferenceProviderCopilot), token); err != nil {
36+ return token, false
37+ }
38+
34 if err := cmp.Or(
39 if err := cmp.Or(
35 c.SetConfigField("providers.copilot.api_key", token.AccessToken),
40 c.SetConfigField("providers.copilot.api_key", token.AccessToken),
36 c.SetConfigField("providers.copilot.oauth", token),
41 c.SetConfigField("providers.copilot.oauth", token),
internal/config/load.go−7
@@ -133,8 +133,6 @@ func PushPopCrushEnv() func() {
133}
133}
134
134
135func (c *Config) configureProviders(env env.Env, resolver VariableResolver, knownProviders []catwalk.Provider) error {
135func (c *Config) configureProviders(env env.Env, resolver VariableResolver, knownProviders []catwalk.Provider) error {
136− c.importCopilot()
137−
138 knownProviderNames := make(map[string]bool)
136 knownProviderNames := make(map[string]bool)
139 restore := PushPopCrushEnv()
137 restore := PushPopCrushEnv()
140 defer restore()
138 defer restore()
@@ -206,11 +204,6 @@ func (c *Config) configureProviders(env env.Env, resolver VariableResolver, know
206 case p.ID == catwalk.InferenceProviderAnthropic && config.OAuthToken != nil:
204 case p.ID == catwalk.InferenceProviderAnthropic && config.OAuthToken != nil:
207 prepared.SetupClaudeCode()
205 prepared.SetupClaudeCode()
208 case p.ID == catwalk.InferenceProviderCopilot:
206 case p.ID == catwalk.InferenceProviderCopilot:
209− if config.OAuthToken != nil {
210− if token, ok := c.importCopilot(); ok {
211− prepared.OAuthToken = token
212− }
213− }
214 if config.OAuthToken != nil {
207 if config.OAuthToken != nil {
215 prepared.SetupGitHubCopilot()
208 prepared.SetupGitHubCopilot()
216 }
209 }
internal/tui/components/chat/splash/splash.go+4
@@ -346,6 +346,10 @@ func (s *splashCmp) Update(msg tea.Msg) (util.Model, tea.Cmd) {
346 s.hyperDeviceFlow.SetWidth(min(s.width-2, 60))
346 s.hyperDeviceFlow.SetWidth(min(s.width-2, 60))
347 return s, s.hyperDeviceFlow.Init()
347 return s, s.hyperDeviceFlow.Init()
348 case catwalk.InferenceProviderCopilot:
348 case catwalk.InferenceProviderCopilot:
349+ if token, ok := config.Get().ImportCopilot(); ok {
350+ s.selectedModel = selectedItem
351+ return s, s.saveAPIKeyAndContinue(token, true)
352+ }
349 s.selectedModel = selectedItem
353 s.selectedModel = selectedItem
350 s.showCopilotDeviceFlow = true
354 s.showCopilotDeviceFlow = true
351 s.copilotDeviceFlow = copilot.NewDeviceFlow()
355 s.copilotDeviceFlow = copilot.NewDeviceFlow()
internal/tui/components/dialogs/models/models.go+5
@@ -307,6 +307,11 @@ func (m *modelDialogCmp) Update(msg tea.Msg) (util.Model, tea.Cmd) {
307 m.hyperDeviceFlow.SetWidth(m.width - 2)
307 m.hyperDeviceFlow.SetWidth(m.width - 2)
308 return m, m.hyperDeviceFlow.Init()
308 return m, m.hyperDeviceFlow.Init()
309 case catwalk.InferenceProviderCopilot:
309 case catwalk.InferenceProviderCopilot:
310+ if token, ok := config.Get().ImportCopilot(); ok {
311+ m.selectedModel = selectedItem
312+ m.selectedModelType = modelType
313+ return m, m.saveOauthTokenAndContinue(token, true)
314+ }
310 m.showCopilotDeviceFlow = true
315 m.showCopilotDeviceFlow = true
311 m.selectedModel = selectedItem
316 m.selectedModel = selectedItem
312 m.selectedModelType = modelType
317 m.selectedModelType = modelType