package cmd import ( "bufio" "cursor-api-proxy/internal/agent" "cursor-api-proxy/internal/env" "fmt" "os" "os/exec" "os/signal" "path/filepath" "regexp" "syscall" "time" ) var loginURLRe = regexp.MustCompile(`https://cursor\.com/loginDeepControl.*?redirectTarget=cli`) func HandleLogin(accountName string, proxies []string) error { e := env.OsEnvToMap() loaded := env.LoadEnvConfig(e, "") agentBin := loaded.AgentBin if accountName == "" { accountName = fmt.Sprintf("account-%d", time.Now().UnixMilli()%10000) } accountsDir := agent.AccountsDir() configDir := filepath.Join(accountsDir, accountName) dirWasNew := !fileExists(configDir) if err := os.MkdirAll(accountsDir, 0755); err != nil { return fmt.Errorf("failed to create accounts dir: %w", err) } if err := os.MkdirAll(configDir, 0755); err != nil { return fmt.Errorf("failed to create config dir: %w", err) } fmt.Printf("Logging into Cursor account: %s\n", accountName) fmt.Printf("Config: %s\n\n", configDir) fmt.Println("Run the login command — complete the login in your browser.") fmt.Println("") cleanupDir := func() { if dirWasNew { _ = os.RemoveAll(configDir) } } cmdEnv := make([]string, 0, len(e)+2) for k, v := range e { cmdEnv = append(cmdEnv, k+"="+v) } cmdEnv = append(cmdEnv, "CURSOR_CONFIG_DIR="+configDir) cmdEnv = append(cmdEnv, "NO_OPEN_BROWSER=1") child := exec.Command(agentBin, "login") child.Env = cmdEnv child.Stdin = os.Stdin child.Stderr = os.Stderr stdoutPipe, err := child.StdoutPipe() if err != nil { return fmt.Errorf("failed to create stdout pipe: %w", err) } if err := child.Start(); err != nil { cleanupDir() if os.IsNotExist(err) { return fmt.Errorf("could not find '%s'. Make sure the Cursor CLI is installed", agentBin) } return fmt.Errorf("error launching agent login: %w", err) } // Handle cancellation signals sigCh := make(chan os.Signal, 1) signal.Notify(sigCh, syscall.SIGINT, syscall.SIGTERM, syscall.SIGHUP) go func() { sig := <-sigCh _ = child.Process.Kill() cleanupDir() if sig == syscall.SIGINT { fmt.Println("\n\nLogin cancelled.") } os.Exit(0) }() defer signal.Stop(sigCh) var stdoutBuf string scanner := bufio.NewScanner(stdoutPipe) for scanner.Scan() { line := scanner.Text() fmt.Println(line) stdoutBuf += line + "\n" if loginURLRe.MatchString(stdoutBuf) { match := loginURLRe.FindString(stdoutBuf) if match != "" { fmt.Printf("\nOpen this URL in your browser (incognito recommended):\n%s\n\n", match) } } } if err := child.Wait(); err != nil { if exitErr, ok := err.(*exec.ExitError); ok { cleanupDir() return fmt.Errorf("login failed with code %d", exitErr.ExitCode()) } return err } // Cache keychain token for this account token := agent.ReadKeychainToken() if token != "" { agent.WriteCachedToken(configDir, token) } fmt.Printf("\nAccount '%s' saved — it will be auto-discovered when you start the proxy.\n", accountName) return nil } func fileExists(path string) bool { _, err := os.Stat(path) return err == nil }