@@ -9,7 +9,6 @@ import (
99 "charm.land/bubbles/v2/spinner"
1010 tea "charm.land/bubbletea/v2"
1111 "charm.land/lipgloss/v2"
12− "github.com/atotto/clipboard"
1312 "github.com/charmbracelet/catwalk/pkg/catwalk"
1413 "github.com/charmbracelet/crush/internal/agent"
1514 hyperp "github.com/charmbracelet/crush/internal/agent/hyper"
@@ -18,7 +17,6 @@ import (
1817 "github.com/charmbracelet/crush/internal/tui/components/chat"
1918 "github.com/charmbracelet/crush/internal/tui/components/core"
2019 "github.com/charmbracelet/crush/internal/tui/components/core/layout"
21− "github.com/charmbracelet/crush/internal/tui/components/dialogs/claude"
2220 "github.com/charmbracelet/crush/internal/tui/components/dialogs/copilot"
2321 "github.com/charmbracelet/crush/internal/tui/components/dialogs/hyper"
2422 "github.com/charmbracelet/crush/internal/tui/components/dialogs/models"
@@ -47,18 +45,6 @@ type Splash interface {
4745 // IsAPIKeyValid returns whether the API key is valid
4846 IsAPIKeyValid() bool
4947
50− // IsShowingClaudeAuthMethodChooser returns whether showing Claude auth method chooser
51− IsShowingClaudeAuthMethodChooser() bool
52−
53− // IsShowingClaudeOAuth2 returns whether showing Claude OAuth2 flow
54− IsShowingClaudeOAuth2() bool
55−
56− // IsClaudeOAuthURLState returns whether in OAuth URL state
57− IsClaudeOAuthURLState() bool
58−
59− // IsClaudeOAuthComplete returns whether Claude OAuth flow is complete
60− IsClaudeOAuthComplete() bool
61−
6248 // IsShowingClaudeOAuth2 returns whether showing Hyper OAuth2 flow
6349 IsShowingHyperOAuth2() bool
6450
@@ -103,12 +89,6 @@ type splashCmp struct {
10389 // Copilot device flow state
10490 copilotDeviceFlow *copilot.DeviceFlow
10591 showCopilotDeviceFlow bool
106−
107− // Claude state
108− claudeAuthMethodChooser *claude.AuthMethodChooser
109− claudeOAuth2 *claude.OAuth2
110− showClaudeAuthMethodChooser bool
111− showClaudeOAuth2 bool
11292}
11393
11494func New() Splash {
@@ -134,9 +114,6 @@ func New() Splash {
134114 modelList: modelList,
135115 apiKeyInput: apiKeyInput,
136116 selectedNo: false,
137−
138− claudeAuthMethodChooser: claude.NewAuthMethodChooser(),
139− claudeOAuth2: claude.NewOAuth2(),
140117 }
141118}
142119
@@ -158,8 +135,6 @@ func (s *splashCmp) Init() tea.Cmd {
158135 return tea.Batch(
159136 s.modelList.Init(),
160137 s.apiKeyInput.Init(),
161− s.claudeAuthMethodChooser.Init(),
162− s.claudeOAuth2.Init(),
163138 )
164139}
165140
@@ -176,7 +151,6 @@ func (s *splashCmp) SetSize(width int, height int) tea.Cmd {
176151 s.listHeight = s.height - lipgloss.Height(s.logoRendered) - (SplashScreenPaddingY * 2) - s.logoGap() - 2
177152 listWidth := min(60, width)
178153 s.apiKeyInput.SetWidth(width - 2)
179− s.claudeAuthMethodChooser.SetWidth(min(width-2, 60))
180154 return s.modelList.SetSize(listWidth, s.listHeight)
181155}
182156
@@ -185,24 +159,6 @@ func (s *splashCmp) Update(msg tea.Msg) (util.Model, tea.Cmd) {
185159 switch msg := msg.(type) {
186160 case tea.WindowSizeMsg:
187161 return s, s.SetSize(msg.Width, msg.Height)
188− case claude.ValidationCompletedMsg:
189− var cmds []tea.Cmd
190− u, cmd := s.claudeOAuth2.Update(msg)
191− s.claudeOAuth2 = u.(*claude.OAuth2)
192− cmds = append(cmds, cmd)
193−
194− if msg.State == claude.OAuthValidationStateValid {
195− cmds = append(
196− cmds,
197− s.saveAPIKeyAndContinue(msg.Token, false),
198− func() tea.Msg {
199− time.Sleep(5 * time.Second)
200− return claude.AuthenticationCompleteMsg{}
201− },
202− )
203− }
204−
205− return s, tea.Batch(cmds...)
206162 case hyper.DeviceFlowCompletedMsg:
207163 s.showHyperDeviceFlow = false
208164 return s, s.saveAPIKeyAndContinue(msg.Token, true)
@@ -223,10 +179,6 @@ func (s *splashCmp) Update(msg tea.Msg) (util.Model, tea.Cmd) {
223179 case copilot.DeviceFlowCompletedMsg:
224180 s.showCopilotDeviceFlow = false
225181 return s, s.saveAPIKeyAndContinue(msg.Token, true)
226− case claude.AuthenticationCompleteMsg:
227− s.showClaudeAuthMethodChooser = false
228− s.showClaudeOAuth2 = false
229− return s, util.CmdHandler(OnboardingCompleteMsg{})
230182 case models.APIKeyStateChangeMsg:
231183 u, cmd := s.apiKeyInput.Update(msg)
232184 s.apiKeyInput = u.(*models.APIKeyInput)
@@ -246,34 +198,8 @@ func (s *splashCmp) Update(msg tea.Msg) (util.Model, tea.Cmd) {
246198 return s, s.hyperDeviceFlow.CopyCode()
247199 case key.Matches(msg, s.keyMap.Copy) && s.showCopilotDeviceFlow:
248200 return s, s.copilotDeviceFlow.CopyCode()
249− case key.Matches(msg, s.keyMap.Copy) && s.showClaudeOAuth2 && s.claudeOAuth2.State == claude.OAuthStateURL:
250− return s, tea.Sequence(
251− tea.SetClipboard(s.claudeOAuth2.URL),
252− func() tea.Msg {
253− _ = clipboard.WriteAll(s.claudeOAuth2.URL)
254− return nil
255− },
256− util.ReportInfo("URL copied to clipboard"),
257− )
258− case key.Matches(msg, s.keyMap.Copy) && s.showClaudeAuthMethodChooser:
259− u, cmd := s.claudeAuthMethodChooser.Update(msg)
260− s.claudeAuthMethodChooser = u.(*claude.AuthMethodChooser)
261− return s, cmd
262− case key.Matches(msg, s.keyMap.Copy) && s.showClaudeOAuth2:
263− u, cmd := s.claudeOAuth2.Update(msg)
264− s.claudeOAuth2 = u.(*claude.OAuth2)
265− return s, cmd
266201 case key.Matches(msg, s.keyMap.Back):
267202 switch {
268− case s.showClaudeAuthMethodChooser:
269− s.claudeAuthMethodChooser.SetDefaults()
270− s.showClaudeAuthMethodChooser = false
271− return s, nil
272− case s.showClaudeOAuth2:
273− s.claudeOAuth2.SetDefaults()
274− s.showClaudeOAuth2 = false
275− s.showClaudeAuthMethodChooser = true
276− return s, nil
277203 case s.showHyperDeviceFlow:
278204 s.hyperDeviceFlow = nil
279205 s.showHyperDeviceFlow = false
@@ -285,9 +211,6 @@ func (s *splashCmp) Update(msg tea.Msg) (util.Model, tea.Cmd) {
285211 case s.isAPIKeyValid:
286212 return s, nil
287213 case s.needsAPIKey:
288− if s.selectedModel.Provider.ID == catwalk.InferenceProviderAnthropic {
289− s.showClaudeAuthMethodChooser = true
290− }
291214 s.needsAPIKey = false
292215 s.selectedModel = nil
293216 s.isAPIKeyValid = false
@@ -297,28 +220,6 @@ func (s *splashCmp) Update(msg tea.Msg) (util.Model, tea.Cmd) {
297220 }
298221 case key.Matches(msg, s.keyMap.Select):
299222 switch {
300− case s.showClaudeAuthMethodChooser:
301− selectedItem := s.modelList.SelectedModel()
302− if selectedItem == nil {
303− return s, nil
304− }
305−
306− switch s.claudeAuthMethodChooser.State {
307− case claude.AuthMethodAPIKey:
308− s.showClaudeAuthMethodChooser = false
309− s.needsAPIKey = true
310− s.selectedModel = selectedItem
311− s.apiKeyInput.SetProviderName(selectedItem.Provider.Name)
312− case claude.AuthMethodOAuth2:
313− s.selectedModel = selectedItem
314− s.showClaudeAuthMethodChooser = false
315− s.showClaudeOAuth2 = true
316− }
317− return s, nil
318− case s.showClaudeOAuth2:
319− m2, cmd2 := s.claudeOAuth2.ValidationConfirm()
320− s.claudeOAuth2 = m2.(*claude.OAuth2)
321− return s, cmd2
322223 case s.showHyperDeviceFlow:
323224 return s, s.hyperDeviceFlow.CopyCodeAndOpenURL()
324225 case s.showCopilotDeviceFlow:
@@ -336,9 +237,6 @@ func (s *splashCmp) Update(msg tea.Msg) (util.Model, tea.Cmd) {
336237 return s, tea.Batch(cmd, util.CmdHandler(OnboardingCompleteMsg{}))
337238 } else {
338239 switch selectedItem.Provider.ID {
339− case catwalk.InferenceProviderAnthropic:
340− s.showClaudeAuthMethodChooser = true
341− return s, nil
342240 case hyperp.Name:
343241 s.selectedModel = selectedItem
344242 s.showHyperDeviceFlow = true
@@ -407,10 +305,6 @@ func (s *splashCmp) Update(msg tea.Msg) (util.Model, tea.Cmd) {
407305 return s, s.initializeProject()
408306 }
409307 case key.Matches(msg, s.keyMap.Tab, s.keyMap.LeftRight):
410− if s.showClaudeAuthMethodChooser {
411− s.claudeAuthMethodChooser.ToggleChoice()
412− return s, nil
413− }
414308 if s.needsAPIKey {
415309 u, cmd := s.apiKeyInput.Update(msg)
416310 s.apiKeyInput = u.(*models.APIKeyInput)
@@ -452,14 +346,6 @@ func (s *splashCmp) Update(msg tea.Msg) (util.Model, tea.Cmd) {
452346 }
453347 default:
454348 switch {
455− case s.showClaudeAuthMethodChooser:
456− u, cmd := s.claudeAuthMethodChooser.Update(msg)
457− s.claudeAuthMethodChooser = u.(*claude.AuthMethodChooser)
458− return s, cmd
459− case s.showClaudeOAuth2:
460− u, cmd := s.claudeOAuth2.Update(msg)
461− s.claudeOAuth2 = u.(*claude.OAuth2)
462− return s, cmd
463349 case s.showHyperDeviceFlow:
464350 u, cmd := s.hyperDeviceFlow.Update(msg)
465351 s.hyperDeviceFlow = u.(*hyper.DeviceFlow)
@@ -480,10 +366,6 @@ func (s *splashCmp) Update(msg tea.Msg) (util.Model, tea.Cmd) {
480366 }
481367 case tea.PasteMsg:
482368 switch {
483− case s.showClaudeOAuth2:
484− u, cmd := s.claudeOAuth2.Update(msg)
485− s.claudeOAuth2 = u.(*claude.OAuth2)
486− return s, cmd
487369 case s.showHyperDeviceFlow:
488370 u, cmd := s.hyperDeviceFlow.Update(msg)
489371 s.hyperDeviceFlow = u.(*hyper.DeviceFlow)
@@ -503,10 +385,6 @@ func (s *splashCmp) Update(msg tea.Msg) (util.Model, tea.Cmd) {
503385 }
504386 case spinner.TickMsg:
505387 switch {
506− case s.showClaudeOAuth2:
507− u, cmd := s.claudeOAuth2.Update(msg)
508− s.claudeOAuth2 = u.(*claude.OAuth2)
509− return s, cmd
510388 case s.showHyperDeviceFlow:
511389 u, cmd := s.hyperDeviceFlow.Update(msg)
512390 s.hyperDeviceFlow = u.(*hyper.DeviceFlow)
@@ -655,38 +533,6 @@ func (s *splashCmp) View() string {
655533 var content string
656534
657535 switch {
658− case s.showClaudeAuthMethodChooser:
659− remainingHeight := s.height - lipgloss.Height(s.logoRendered) - SplashScreenPaddingY
660− chooserView := s.claudeAuthMethodChooser.View()
661− authMethodSelector := t.S().Base.AlignVertical(lipgloss.Bottom).Height(remainingHeight).Render(
662− lipgloss.JoinVertical(
663− lipgloss.Left,
664− t.S().Base.PaddingLeft(1).Foreground(t.Primary).Render("Let's Auth Anthropic"),
665− "",
666− chooserView,
667− ),
668− )
669− content = lipgloss.JoinVertical(
670− lipgloss.Left,
671− s.logoRendered,
672− authMethodSelector,
673− )
674− case s.showClaudeOAuth2:
675− remainingHeight := s.height - lipgloss.Height(s.logoRendered) - SplashScreenPaddingY
676− oauth2View := s.claudeOAuth2.View()
677− oauthSelector := t.S().Base.AlignVertical(lipgloss.Bottom).Height(remainingHeight).Render(
678− lipgloss.JoinVertical(
679− lipgloss.Left,
680− t.S().Base.PaddingLeft(1).Foreground(t.Primary).Render("Let's Auth Anthropic"),
681− "",
682− oauth2View,
683− ),
684− )
685− content = lipgloss.JoinVertical(
686− lipgloss.Left,
687− s.logoRendered,
688− oauthSelector,
689− )
690536 case s.showHyperDeviceFlow:
691537 remainingHeight := s.height - lipgloss.Height(s.logoRendered) - SplashScreenPaddingY
692538 hyperView := s.hyperDeviceFlow.View()
@@ -816,14 +662,6 @@ func (s *splashCmp) View() string {
816662
817663func (s *splashCmp) Cursor() *tea.Cursor {
818664 switch {
819− case s.showClaudeAuthMethodChooser:
820− return nil
821− case s.showClaudeOAuth2:
822− if cursor := s.claudeOAuth2.CodeInput.Cursor(); cursor != nil {
823− cursor.Y += 2 // FIXME(@andreynering): Why do we need this?
824− return s.moveCursor(cursor)
825− }
826− return nil
827665 case s.needsAPIKey:
828666 cursor := s.apiKeyInput.Cursor()
829667 if cursor != nil {
@@ -894,16 +732,10 @@ func (s *splashCmp) moveCursor(cursor *tea.Cursor) *tea.Cursor {
894732 }
895733 // Calculate the correct Y offset based on current state
896734 logoHeight := lipgloss.Height(s.logoRendered)
897− if s.needsAPIKey || s.showClaudeOAuth2 {
898− var view string
899− if s.needsAPIKey {
900− view = s.apiKeyInput.View()
901− } else {
902− view = s.claudeOAuth2.View()
903− }
735+ if s.needsAPIKey {
904736 infoSectionHeight := lipgloss.Height(s.infoSection())
905737 baseOffset := logoHeight + SplashScreenPaddingY + infoSectionHeight
906− remainingHeight := s.height - baseOffset - lipgloss.Height(view) - SplashScreenPaddingY
738+ remainingHeight := s.height - baseOffset - lipgloss.Height(s.apiKeyInput.View()) - SplashScreenPaddingY
907739 offset := baseOffset + remainingHeight
908740 cursor.Y += offset
909741 cursor.X += 1
@@ -926,20 +758,6 @@ func (s *splashCmp) logoGap() int {
926758// Bindings implements SplashPage.
927759func (s *splashCmp) Bindings() []key.Binding {
928760 switch {
929− case s.showClaudeAuthMethodChooser:
930− return []key.Binding{
931− s.keyMap.Select,
932− s.keyMap.Tab,
933− s.keyMap.Back,
934− }
935− case s.showClaudeOAuth2:
936− bindings := []key.Binding{
937− s.keyMap.Select,
938− }
939− if s.claudeOAuth2.State == claude.OAuthStateURL {
940− bindings = append(bindings, s.keyMap.Copy)
941− }
942− return bindings
943761 case s.needsAPIKey:
944762 return []key.Binding{
945763 s.keyMap.Select,
@@ -1047,22 +865,6 @@ func (s *splashCmp) IsAPIKeyValid() bool {
1047865 return s.isAPIKeyValid
1048866}
1049867
1050−func (s *splashCmp) IsShowingClaudeAuthMethodChooser() bool {
1051− return s.showClaudeAuthMethodChooser
1052−}
1053−
1054−func (s *splashCmp) IsShowingClaudeOAuth2() bool {
1055− return s.showClaudeOAuth2
1056−}
1057−
1058−func (s *splashCmp) IsClaudeOAuthURLState() bool {
1059− return s.showClaudeOAuth2 && s.claudeOAuth2.State == claude.OAuthStateURL
1060−}
1061−
1062−func (s *splashCmp) IsClaudeOAuthComplete() bool {
1063− return s.showClaudeOAuth2 && s.claudeOAuth2.State == claude.OAuthStateCode && s.claudeOAuth2.ValidationState == claude.OAuthValidationStateValid
1064−}
1065−
1066868func (s *splashCmp) IsShowingHyperOAuth2() bool {
1067869 return s.showHyperDeviceFlow
1068870}