11 "charm.land/lipgloss/v2"
12 "github.com/charmbracelet/crush/internal/config"
13 "github.com/charmbracelet/crush/internal/oauth/claude"
14 "github.com/spf13/cobra"
17var loginCmd = &cobra.Command{
18 Aliases: []string{"auth"},
19 Use: "login [platform]",
20 Short: "Login Crush to a platform",
21 Long: `Login Crush to a specified platform.
22The platform should be provided as an argument.
23Available platforms are: claude.`,
25# Authenticate with Claude Code Max
28 ValidArgs: []cobra.Completion{
32 Args: cobra.ExactArgs(1),
33 RunE: func(cmd *cobra.Command, args []string) error {
35 return fmt.Errorf("wrong number of arguments")
37 if len(args) == 0 || args[0] == "" {
41 app, err := setupAppWithProgressBar(cmd)
48 case "anthropic", "claude":
51 return fmt.Errorf("unknown platform: %s", args[0])
56func loginClaude() error {
57 ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt, os.Kill)
64 verifier, challenge, err := claude.GetChallenge()
68 url, err := claude.AuthorizeURL(verifier, challenge)
72 fmt.Println("Open the following URL and follow the instructions to authenticate with Claude Code Max:")
74 fmt.Println(lipgloss.NewStyle().Hyperlink(url, "id=claude").Render(url))
76 fmt.Println("Press enter to continue...")
77 if _, err := fmt.Scanln(); err != nil {
81 fmt.Println("Now paste and code from Anthropic and press enter...")
86 _, _ = fmt.Scanln(&code)
87 code = strings.TrimSpace(code)
91 fmt.Println("Exchanging authorization code...")
92 token, err := claude.ExchangeToken(ctx, code, verifier)
99 cfg.SetConfigField("providers.anthropic.api_key", token.AccessToken),
100 cfg.SetConfigField("providers.anthropic.oauth", token),
106 fmt.Println("You're now authenticated with Claude Code Max!")
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list