Skip to content

Commit 973e166

Browse files
intel352claude
andcommitted
fix: remove setup-token option and cap autocomplete to chat area height
Problem 1: Anthropic blocked OAuth tokens (sk-ant-oat*) from API access as of Feb 20 2026, making both the setup-token paste and OAuth PKCE flows broken. Reduces Anthropic auth choices from 3 to 2: API key first (recommended) and OAuth second (with restriction warning). Removes setupTokenMode field and all references. Updates stepEnterAPIKey view to show console URL and key prefix hint. Problem 2: Autocomplete dropdown could grow taller than the chat area. Adds height field + SetHeight() to AutocompleteModel. View() caps visible items at height-4 (leaving room for borders, input, status bar). relayout() in chat.go propagates the available height to the autocomplete after each resize. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent e2a3fd9 commit 973e166

3 files changed

Lines changed: 50 additions & 47 deletions

File tree

internal/tui/components/autocomplete.go

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,16 @@ type AutocompleteModel struct {
2323
filter string
2424
cursor int
2525
visible bool
26+
height int
2627
}
2728

2829
// AutocompleteSelectedMsg is sent when a command is selected from the dropdown.
2930
type AutocompleteSelectedMsg struct {
3031
Command string
3132
}
3233

33-
// maxVisibleItems is the maximum number of autocomplete items shown at once.
34-
const maxVisibleItems = 10
34+
// defaultMaxVisibleItems is the default maximum number of autocomplete items shown at once.
35+
const defaultMaxVisibleItems = 10
3536

3637
// NewAutocomplete creates an autocomplete model with all known commands.
3738
func NewAutocomplete() AutocompleteModel {
@@ -63,6 +64,12 @@ func NewAutocomplete() AutocompleteModel {
6364
// Visible returns whether the autocomplete dropdown is showing.
6465
func (m AutocompleteModel) Visible() bool { return m.visible }
6566

67+
// SetHeight sets the available height so View() can cap the dropdown size.
68+
func (m AutocompleteModel) SetHeight(h int) AutocompleteModel {
69+
m.height = h
70+
return m
71+
}
72+
6673
// SetFilter updates the autocomplete based on current input text.
6774
func (m AutocompleteModel) SetFilter(input string) AutocompleteModel {
6875
// Do NOT TrimSpace — a trailing space (e.g. after autocomplete selection)
@@ -152,15 +159,27 @@ func (m AutocompleteModel) View(t theme.Theme, width int) string {
152159

153160
total := len(m.matches)
154161

155-
// Compute a window of maxVisibleItems around the cursor.
156-
start := m.cursor - maxVisibleItems/2
162+
// Cap visible items based on available height (leaving room for borders + input + status bar).
163+
maxVisible := defaultMaxVisibleItems
164+
if m.height > 0 {
165+
heightCap := m.height - 4
166+
if heightCap < 1 {
167+
heightCap = 1
168+
}
169+
if heightCap < maxVisible {
170+
maxVisible = heightCap
171+
}
172+
}
173+
174+
// Compute a window of maxVisible around the cursor.
175+
start := m.cursor - maxVisible/2
157176
if start < 0 {
158177
start = 0
159178
}
160-
end := start + maxVisibleItems
179+
end := start + maxVisible
161180
if end > total {
162181
end = total
163-
start = end - maxVisibleItems
182+
start = end - maxVisible
164183
if start < 0 {
165184
start = 0
166185
}

internal/tui/pages/chat.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,9 @@ func (m *ChatModel) relayout() {
260260
m.viewport.SetWidth(m.width)
261261
m.statusBar.Width = m.width
262262
m.input.SetWidth(m.width)
263+
// Autocomplete height = space above the input (viewport + 1 newline).
264+
acHeight := vpHeight + 1
265+
m.autocomplete = m.autocomplete.SetHeight(acHeight)
263266
m.refreshViewport()
264267
}
265268

internal/tui/pages/onboarding.go

Lines changed: 22 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,6 @@ type OnboardingModel struct {
134134
authCancel context.CancelFunc
135135
deviceUserCode string // device flow: code to display to user
136136
deviceVerificationURI string // device flow: URL to open
137-
setupTokenMode bool // true when user chose "Paste setup-token" for Anthropic
138137

139138
// Model listing
140139
fetchingModels bool
@@ -208,7 +207,6 @@ func (m OnboardingModel) Update(msg tea.Msg) (OnboardingModel, tea.Cmd) {
208207
}
209208
m.authing = false
210209
m.authError = ""
211-
m.setupTokenMode = false
212210
m.step = stepSelectProvider
213211
// Restore cursor to the previously-selected provider so the list
214212
// highlights the right row when returning to the selection screen.
@@ -435,7 +433,7 @@ func (m OnboardingModel) updateAnthropicAuthChoice(msg tea.Msg) (OnboardingModel
435433
m.cursor = m.providerIdx
436434
return m, nil
437435
case "j", "down":
438-
if m.cursor < 2 {
436+
if m.cursor < 1 {
439437
m.cursor++
440438
}
441439
case "k", "up":
@@ -446,30 +444,21 @@ func (m OnboardingModel) updateAnthropicAuthChoice(msg tea.Msg) (OnboardingModel
446444
m.cursor = 0
447445
case "2":
448446
m.cursor = 1
449-
case "3":
450-
m.cursor = 2
451447
case "enter", " ":
452448
switch m.cursor {
453449
case 0:
454-
// Claude subscription OAuth
450+
// Manual API key (recommended)
451+
m.step = stepEnterAPIKey
452+
m.apiKeyInput.Placeholder = "sk-ant-api03-..."
453+
return m, m.apiKeyInput.Focus()
454+
case 1:
455+
// Claude subscription OAuth (may have restrictions)
455456
m.step = stepBrowserAuth
456457
m.authing = true
457458
m.browserOpened = true
458459
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
459460
m.authCancel = cancel
460461
return m, tea.Batch(m.spinner.Tick, m.startAnthropicAuth(ctx))
461-
case 1:
462-
// Setup-token paste (from `claude setup-token`)
463-
m.setupTokenMode = true
464-
m.step = stepEnterAPIKey
465-
m.apiKeyInput.Placeholder = "Paste setup-token here..."
466-
return m, m.apiKeyInput.Focus()
467-
case 2:
468-
// Manual API key
469-
m.setupTokenMode = false
470-
m.step = stepEnterAPIKey
471-
m.apiKeyInput.Placeholder = "sk-ant-..."
472-
return m, m.apiKeyInput.Focus()
473462
}
474463
}
475464
}
@@ -500,7 +489,6 @@ func (m OnboardingModel) updateEnterAPIKey(msg tea.Msg) (OnboardingModel, tea.Cm
500489
case "escape":
501490
m.apiKeyInput.SetValue("")
502491
m.authError = ""
503-
m.setupTokenMode = false
504492
// Go back to Anthropic auth choice if this is an Anthropic provider
505493
p := m.selectedProvider()
506494
if p.auth == authBrowser {
@@ -744,9 +732,8 @@ func (m OnboardingModel) View(t theme.Theme, width, height int) string {
744732
case stepAnthropicAuthChoice:
745733
sb.WriteString("Sign in with Anthropic\n\n")
746734
choices := []string{
747-
"Sign in with Claude account (Pro/Team/Enterprise)",
748-
"Paste setup-token (from claude setup-token)",
749-
"Enter API key manually",
735+
"Enter API key (recommended)",
736+
"Sign in with Claude account (OAuth — may have restrictions)",
750737
}
751738
for i, label := range choices {
752739
cursor := " "
@@ -757,7 +744,7 @@ func (m OnboardingModel) View(t theme.Theme, width, height int) string {
757744
}
758745
sb.WriteString(style.Render(fmt.Sprintf("%s%d. %s", cursor, i+1, label)) + "\n")
759746
}
760-
sb.WriteString("\n" + mutedStyle.Render("↑/↓ or 1-3: select Enter: confirm Esc: back"))
747+
sb.WriteString("\n" + mutedStyle.Render("↑/↓ or 1-2: select Enter: confirm Esc: back"))
761748

762749
case stepBrowserAuth:
763750
p := m.selectedProvider()
@@ -786,26 +773,20 @@ func (m OnboardingModel) View(t theme.Theme, width, height int) string {
786773

787774
case stepEnterAPIKey:
788775
p := m.selectedProvider()
789-
if m.setupTokenMode {
790-
sb.WriteString("Paste your Claude setup-token:\n\n")
791-
sb.WriteString(mutedStyle.Render("Generate one by running:") + "\n")
792-
sb.WriteString(lipgloss.NewStyle().Bold(true).Foreground(t.Accent).Render(" claude setup-token") + "\n\n")
793-
sb.WriteString(mutedStyle.Render("This uses your Claude Pro/Team/Enterprise subscription.") + "\n\n")
794-
} else {
795-
switch p.auth {
796-
case authBrowser:
797-
sb.WriteString("Paste your Anthropic API key:\n\n")
798-
sb.WriteString(mutedStyle.Render("Get one at console.anthropic.com/settings/keys") + "\n\n")
799-
case authGHCLI:
800-
sb.WriteString("Paste your GitHub token:\n\n")
801-
sb.WriteString(mutedStyle.Render("Run: gh auth token") + "\n")
802-
sb.WriteString(mutedStyle.Render("Or create a PAT at github.com/settings/tokens") + "\n\n")
803-
default:
804-
fmt.Fprintf(&sb, "Enter your %s API key:\n\n", p.displayName)
805-
}
776+
switch p.auth {
777+
case authBrowser:
778+
sb.WriteString("Enter your Anthropic API key:\n\n")
779+
sb.WriteString(mutedStyle.Render("Get one at console.anthropic.com/settings/keys") + "\n")
780+
sb.WriteString(mutedStyle.Render("Keys start with sk-ant-api03-...") + "\n\n")
781+
case authGHCLI:
782+
sb.WriteString("Paste your GitHub token:\n\n")
783+
sb.WriteString(mutedStyle.Render("Run: gh auth token") + "\n")
784+
sb.WriteString(mutedStyle.Render("Or create a PAT at github.com/settings/tokens") + "\n\n")
785+
default:
786+
fmt.Fprintf(&sb, "Enter your %s API key:\n\n", p.displayName)
806787
}
807788
sb.WriteString("Key: " + m.apiKeyInput.View() + "\n\n")
808-
sb.WriteString(mutedStyle.Render("Your key is stored locally and never shared.") + "\n\n")
789+
sb.WriteString(mutedStyle.Render("Your key is stored locally and never shared.") + "\n")
809790
sb.WriteString(mutedStyle.Render("Enter: continue Esc: back"))
810791

811792
case stepEnterBaseURL:

0 commit comments

Comments
 (0)