Full Code of wangffei/wf-cursor-auto-free for AI

main a9f50d3f6db8 cached
43 files
569.4 KB
195.3k tokens
266 symbols
1 requests
Download .txt
Showing preview only (618K chars total). Download the full file or copy to clipboard to get everything.
Repository: wangffei/wf-cursor-auto-free
Branch: main
Commit: a9f50d3f6db8
Files: 43
Total size: 569.4 KB

Directory structure:
gitextract_m5ok1t6j/

├── .github/
│   └── workflows/
│       ├── build.yml
│       ├── remove-old-artifacts.yml
│       └── temp-build.yml
├── .gitignore
├── README.md
├── browser_utils.py
├── build.bat
├── build.mac.command
├── build.py
├── build.sh
├── config.py
├── cursor_auth_manager.py
├── cursor_pro_gui.py
├── cursor_pro_keep_alive.py
├── disable_auto_update.py
├── example_usage.py
├── exit_cursor.py
├── get_email_code.py
├── go_cursor_help.py
├── gui/
│   ├── about_tab.py
│   ├── account_tab.py
│   ├── env_tab.py
│   ├── home_tab.py
│   ├── log_viewer.py
│   ├── register_tab.py
│   ├── reset_tab.py
│   └── settings_tab.py
├── language.py
├── logger.py
├── logo.py
├── names-dataset.txt
├── patch_cursor_get_machine_id.py
├── requirements.txt
├── reset_machine.py
├── settings.json
├── start_cursor.py
├── test/
│   └── get_veri_code_test.py
├── test_email.py
├── test_session_token.py
├── turnstilePatch/
│   ├── manifest.json
│   ├── readme.txt
│   └── script.js
└── utils.py

================================================
FILE CONTENTS
================================================

================================================
FILE: .github/workflows/build.yml
================================================
name: Build Executables

on:
  push:
    tags:
      - 'v*'  # 添加标签触发条件,匹配 v1.0.0 这样的标签
  workflow_dispatch:  # 手动触发工作流

jobs:
  build-windows:
    runs-on: windows-latest
    
    steps:
    - uses: actions/checkout@v2
    
    - name: Set up Python
      uses: actions/setup-python@v2
      with:
        python-version: '3.x'
    
    - name: Install dependencies
      run: |
        python -m pip install --upgrade pip
        pip install pyinstaller
        pip install -r requirements.txt
        
    - name: Build EXE
      run: |
        pyinstaller CursorKeepAlive.spec
        
    - name: Build GUI EXE
      run: |
        pyinstaller CursorProGUI.spec
        
    - name: Upload Windows artifact
      uses: actions/upload-artifact@v4
      with:
        name: CursorPro-Windows
        path: dist/CursorPro.exe
        
    - name: Upload Windows GUI artifact
      uses: actions/upload-artifact@v4
      with:
        name: CursorProGUI-Windows
        path: dist/CursorProGUI.exe

  build-macos-arm64:
    runs-on: macos-latest
    
    steps:
    - uses: actions/checkout@v2
    
    - name: Set up Python
      uses: actions/setup-python@v2
      with:
        python-version: '3.x'
    
    - name: Install dependencies
      run: |
        python -m pip install --upgrade pip
        pip install pyinstaller
        pip install -r requirements.txt
        
    - name: Build MacOS ARM executable
      run: |
        pyinstaller CursorKeepAlive.spec
        
    - name: Build MacOS ARM GUI executable
      run: |
        pyinstaller CursorProGUI.spec
        
    - name: Upload MacOS ARM artifact
      uses: actions/upload-artifact@v4
      with:
        name: CursorPro-MacOS-ARM64
        path: dist/CursorPro
        
    - name: Upload MacOS ARM GUI artifact
      uses: actions/upload-artifact@v4
      with:
        name: CursorProGUI-MacOS-ARM64
        path: dist/CursorProGUI

  build-linux:
    runs-on: ubuntu-22.04
    
    steps:
    - uses: actions/checkout@v2
    
    - name: Set up Python
      uses: actions/setup-python@v2
      with:
        python-version: '3.x'
    
    - name: Install dependencies
      run: |
        python -m pip install --upgrade pip
        pip install pyinstaller
        pip install -r requirements.txt
        
    - name: Build Linux executable
      run: |
        pyinstaller CursorKeepAlive.spec
        
    - name: Build Linux GUI executable
      run: |
        pyinstaller CursorProGUI.spec
        
    - name: Upload Linux artifact
      uses: actions/upload-artifact@v4
      with:
        name: CursorPro-Linux
        path: dist/CursorPro
        
    - name: Upload Linux GUI artifact
      uses: actions/upload-artifact@v4
      with:
        name: CursorProGUI-Linux
        path: dist/CursorProGUI

  build-macos-intel:
    runs-on: macos-latest

    steps:
    - uses: actions/checkout@v2

    - name: Set up Python
      uses: actions/setup-python@v2
      with:
        python-version: '3.x'

    - name: Install dependencies
      run: |
        arch -x86_64 pip3 install --upgrade pip
        arch -x86_64 pip3 install pyinstaller
        arch -x86_64 pip3 install -r requirements.txt

    - name: Build MacOS Intel executable
      env:
        TARGET_ARCH: 'x86_64'
      run: |
        arch -x86_64 python3 -m PyInstaller CursorKeepAlive.spec
        
    - name: Build MacOS Intel GUI executable
      env:
        TARGET_ARCH: 'x86_64'
      run: |
        arch -x86_64 python3 -m PyInstaller CursorProGUI.spec
        
    - name: Upload MacOS Intel artifact
      uses: actions/upload-artifact@v4
      with:
        name: CursorPro-MacOS-Intel
        path: dist/CursorPro
        
    - name: Upload MacOS Intel GUI artifact
      uses: actions/upload-artifact@v4
      with:
        name: CursorProGUI-MacOS-Intel
        path: dist/CursorProGUI

  create-release:
    needs: [build-windows, build-macos-arm64, build-linux, build-macos-intel]
    runs-on: ubuntu-22.04
    if: startsWith(github.ref, 'refs/tags/')
    
    steps:
      - name: Download all artifacts
        uses: actions/download-artifact@v4
        with:
          path: artifacts
          
      - name: Create release archives
        run: |
          cd artifacts
          zip -r CursorPro-Windows.zip CursorPro-Windows/
          zip -r CursorProGUI-Windows.zip CursorProGUI-Windows/
          zip -r CursorPro-MacOS-ARM64.zip CursorPro-MacOS-ARM64/
          zip -r CursorProGUI-MacOS-ARM64.zip CursorProGUI-MacOS-ARM64/
          zip -r CursorPro-Linux.zip CursorPro-Linux/
          zip -r CursorProGUI-Linux.zip CursorProGUI-Linux/
          zip -r CursorPro-MacOS-Intel.zip CursorPro-MacOS-Intel/
          zip -r CursorProGUI-MacOS-Intel.zip CursorProGUI-MacOS-Intel/


      - name: Create Release
        uses: softprops/action-gh-release@v1
        with:
          files: |
            artifacts/CursorPro-Windows.zip
            artifacts/CursorProGUI-Windows.zip
            artifacts/CursorPro-MacOS-ARM64.zip
            artifacts/CursorProGUI-MacOS-ARM64.zip
            artifacts/CursorPro-Linux.zip
            artifacts/CursorProGUI-Linux.zip
            artifacts/CursorPro-MacOS-Intel.zip
            artifacts/CursorProGUI-MacOS-Intel.zip

        env:
          GITHUB_TOKEN: ${{ secrets.TOKEN }}

================================================
FILE: .github/workflows/remove-old-artifacts.yml
================================================
name: Remove old artifacts

on:
  schedule:
    # Every day at 1am
    - cron: '0 1 * * *'
  # 手动
  workflow_dispatch:


jobs:
  remove-old-artifacts:
    runs-on: ubuntu-latest
    timeout-minutes: 10

    steps:
    - name: Remove old artifacts
      uses: c-hive/gha-remove-artifacts@v1
      with:
        GITHUB_TOKEN: ${{ secrets.TOKEN }}
        age: '5 days' # '<number> <unit>', e.g. 5 days, 2 years, 90 seconds, parsed by Moment.js
        # Optional inputs
        # skip-tags: true
        # skip-recent: 5

================================================
FILE: .github/workflows/temp-build.yml
================================================
name: temp Build Executables

on:
  workflow_dispatch:  # 手动触发工作流

jobs:
  build-windows:
    runs-on: windows-latest
    
    steps:
    - uses: actions/checkout@v2
    
    - name: Set up Python
      uses: actions/setup-python@v2
      with:
        python-version: '3.x'
    
    - name: Install dependencies
      run: |
        python -m pip install --upgrade pip
        pip install pyinstaller
        pip install -r requirements.txt
        
    - name: Build EXE
      run: |
        pyinstaller CursorKeepAlive.spec
        
    - name: Upload Windows artifact
      uses: actions/upload-artifact@v4
      with:
        name: CursorPro-Windows
        path: dist/CursorPro.exe

  build-macos-arm64:
    runs-on: macos-latest
    
    steps:
    - uses: actions/checkout@v2
    
    - name: Set up Python
      uses: actions/setup-python@v2
      with:
        python-version: '3.x'
    
    - name: Install dependencies
      run: |
        python -m pip install --upgrade pip
        pip install pyinstaller
        pip install -r requirements.txt
        
    - name: Build MacOS ARM executable
      run: |
        pyinstaller CursorKeepAlive.spec
        
    - name: Upload MacOS ARM artifact
      uses: actions/upload-artifact@v4
      with:
        name: CursorPro-MacOS-ARM64
        path: dist/CursorPro

  build-linux:
    runs-on: ubuntu-22.04
    
    steps:
    - uses: actions/checkout@v2
    
    - name: Set up Python
      uses: actions/setup-python@v2
      with:
        python-version: '3.x'
    
    - name: Install dependencies
      run: |
        python -m pip install --upgrade pip
        pip install pyinstaller
        pip install -r requirements.txt
        
    - name: Build Linux executable
      run: |
        pyinstaller CursorKeepAlive.spec
        
    - name: Upload Linux artifact
      uses: actions/upload-artifact@v4
      with:
        name: CursorPro-Linux
        path: dist/CursorPro

  build-macos-intel:
    runs-on: macos-latest

    steps:
    - uses: actions/checkout@v2

    - name: Set up Python
      uses: actions/setup-python@v2
      with:
        python-version: '3.x'

    - name: Install dependencies
      run: |
        arch -x86_64 pip3 install --upgrade pip
        arch -x86_64 pip3 install pyinstaller
        arch -x86_64 pip3 install -r requirements.txt

    - name: Build MacOS Intel executable
      env:
        TARGET_ARCH: 'x86_64'
      run: |
        arch -x86_64 python3 -m PyInstaller CursorKeepAlive.spec
        
    - name: Upload MacOS Intel artifact
      uses: actions/upload-artifact@v4
      with:
        name: CursorPro-MacOS-Intel
        path: dist/CursorPro

================================================
FILE: .gitignore
================================================
# PyInstaller
build/
dist/
*.spec
!CursorKeepAlive.mac.spec
!CursorKeepAlive.win.spec

# Python
__pycache__/
*.py[cod]
*$py.class

# Logs
*.log

# IDE
.vscode/
.idea/

# Mac
.DS_Store

venv/

node_modules/

.env

screenshots/

================================================
FILE: README.md
================================================
# Cursor Pro 自动化工具

## 项目说明

本项目基于 [@chengazhen/cursor-auto-free](https://github.com/chengazhen/cursor-auto-free) 开源项目进行二次开发,在此特别感谢原作者的无私分享和贡献!

## 功能改进

在原项目基础上,本工具主要解决了以下问题:

1. 解决部分用户首次打开就需要验证的问题
2. 解决注册完成需要重新登录的问题
3. 新增仅注册功能,可保存账号信息到JSON文件
4. 新增禁止Cursor自动更新功能
5. 新增选择已保存账号并一键应用功能
6. 优化了整体使用体验

## 功能演示

![功能演示](./screen/image.png)

## 功能说明

### 1. 重置机器码
仅重置机器码,适用于已有Cursor账号但需要刷新机器码的用户。

### 2. 完整注册流程
注册新账号并自动重置机器码,一步到位完成全部设置。

### 3. 仅注册
注册新账号并保存账号信息(邮箱、密码、token)到JSON文件,方便后续手动登录。

### 4. 禁止自动更新
禁用Cursor的自动更新功能,避免更新后需要重新激活的问题,保持软件稳定运行。

### 5. 选择已保存账号并应用
列出之前注册并保存的所有账号,选择其中一个自动应用并重置机器码,无需再次注册。

## 使用指南

[详细使用文档](https://cursor-auto-free-doc.vercel.app)

## QQ交流群(有问题先发qq群,qq群会及时发最新版本)

QQ群号:996321868

![公众号](./screen/qrcode_for_gh_c985615b5f2b_258.jpg)

## 声明

- 本项目仅供学习交流使用,请勿用于商业用途
- 本项目不承担任何法律责任,使用本项目造成的任何后果,由使用者自行承担
- 本项目采用 [CC BY-NC-ND 4.0](https://creativecommons.org/licenses/by-nc-nd/4.0/) 许可证

## 英文名字集

本项目使用的英文名字数据集来源: [usa-names-dataset](https://github.com/toniprada/usa-names-dataset)

## 支持作者

开源不易,如果这个项目对你有所帮助,可以请我喝杯咖啡:

<img src="./screen/image copy.png" width="300" alt="支付宝收款码"/>
<img src="./screen/image copy 2.png" width="300" alt="微信收款码"/>

## 特别鸣谢

- [chengazhen/cursor-auto-free](https://github.com/chengazhen/cursor-auto-free) - 本项目的基础,提供了 Cursor Pro 自动化的核心功能
- [linuxDo](https://linux.do/) - 一个真正的技术社区,提供了宝贵的支持和帮助




================================================
FILE: browser_utils.py
================================================
from DrissionPage import ChromiumOptions, Chromium
import sys
import os
import logging
from dotenv import load_dotenv

load_dotenv()


class BrowserManager:
    def __init__(self):
        self.browser = None

    def init_browser(self, user_agent=None):
        """初始化浏览器"""
        co = self._get_browser_options(user_agent)
        self.browser = Chromium(co)
        return self.browser

    def _get_browser_options(self, user_agent=None):
        """获取浏览器配置"""
        co = ChromiumOptions()
        try:
            extension_path = self._get_extension_path("turnstilePatch")
            co.add_extension(extension_path)
        except FileNotFoundError as e:
            logging.warning(f"警告: {e}")

        browser_path = os.getenv("BROWSER_PATH")
        if browser_path:
            co.set_paths(browser_path=browser_path)

        co.set_pref("credentials_enable_service", False)
        co.set_argument("--hide-crash-restore-bubble")
        proxy = os.getenv("BROWSER_PROXY")
        if proxy:
            co.set_proxy(proxy)

        co.auto_port()
        if user_agent:
            co.set_user_agent(user_agent)

        co.headless(
            os.getenv("BROWSER_HEADLESS", "True").lower() == "true"
        )  # 生产环境使用无头模式

        # Mac 系统特殊处理
        if sys.platform == "darwin":
            co.set_argument("--no-sandbox")
            co.set_argument("--disable-gpu")

        return co

    def _get_extension_path(self,exname='turnstilePatch'):
        """获取插件路径"""
        root_dir = os.getcwd()
        extension_path = os.path.join(root_dir, exname)

        if hasattr(sys, "_MEIPASS"):
            extension_path = os.path.join(sys._MEIPASS, exname)

        if not os.path.exists(extension_path):
            raise FileNotFoundError(f"插件不存在: {extension_path}")

        return extension_path

    def quit(self):
        """关闭浏览器"""
        if self.browser:
            try:
                self.browser.quit()
            except:
                pass


================================================
FILE: build.bat
================================================
@echo off
set PYTHONWARNINGS=ignore::SyntaxWarning:DrissionPage
echo Building Cursor Keep Alive...

:: Check if virtual environment exists
if not exist "venv" (
    python -m venv venv
    if errorlevel 1 (
        echo Failed to create virtual environment!
        exit /b 1
    )
)

:: Activate virtual environment and wait for activation to complete
call venv\Scripts\activate.bat
timeout /t 2 /nobreak > nul

:: Install dependencies
echo Installing dependencies...
python -m pip install --upgrade pip
pip install -r requirements.txt

:: Run build script
echo Starting build process...
python build.py

:: Deactivate virtual environment
deactivate

:: Keep window open
echo Build completed!
pause 

================================================
FILE: build.mac.command
================================================
#!/bin/bash
export PYTHONWARNINGS=ignore::SyntaxWarning:DrissionPage

# Get script directory
cd "$(dirname "$0")"

echo "Creating virtual environment..."

# Check if virtual environment exists
if [ ! -d "venv" ]; then
    python3 -m venv venv
    if [ $? -ne 0 ]; then
        echo "Failed to create virtual environment!"
        exit 1
    fi
fi

# Activate virtual environment
source venv/bin/activate

# Install dependencies
echo "Installing dependencies..."
python -m pip install --upgrade pip
pip install -r requirements.txt

# Run build script
echo "Starting build process..."
python build.py

# Keep window open
echo "Build completed!"
echo "Press any key to exit..."
read -n 1 

================================================
FILE: build.py
================================================
import warnings
import os
import platform
import subprocess
import time
import threading

# Ignore specific SyntaxWarning
warnings.filterwarnings("ignore", category=SyntaxWarning, module="DrissionPage")

CURSOR_LOGO = """
   ██████╗██╗   ██╗██████╗ ███████╗ ██████╗ ██████╗ 
  ██╔════╝██║   ██║██╔══██╗██╔════╝██╔═══██╗██╔══██╗
  ██║     ██║   ██║██████╔╝███████╗██║   ██║██████╔╝
  ██║     ██║   ██║██╔══██╗╚════██║██║   ██║██╔══██╗
  ╚██████╗╚██████╔╝██║  ██║███████║╚██████╔╝██║  ██║
   ╚═════╝ ╚═════╝ ╚═╝  ╚═╝╚══════╝ ╚═════╝ ╚═╝  ╚═╝
"""


class LoadingAnimation:
    def __init__(self):
        self.is_running = False
        self.animation_thread = None

    def start(self, message="Building"):
        self.is_running = True
        self.animation_thread = threading.Thread(target=self._animate, args=(message,))
        self.animation_thread.start()

    def stop(self):
        self.is_running = False
        if self.animation_thread:
            self.animation_thread.join()
        print("\r" + " " * 70 + "\r", end="", flush=True)  # Clear the line

    def _animate(self, message):
        animation = "|/-\\"
        idx = 0
        while self.is_running:
            print(f"\r{message} {animation[idx % len(animation)]}", end="", flush=True)
            idx += 1
            time.sleep(0.1)


def print_logo():
    print("\033[96m" + CURSOR_LOGO + "\033[0m")
    print("\033[93m" + "Building Cursor Keep Alive...".center(56) + "\033[0m\n")


def progress_bar(progress, total, prefix="", length=50):
    filled = int(length * progress // total)
    bar = "█" * filled + "░" * (length - filled)
    percent = f"{100 * progress / total:.1f}"
    print(f"\r{prefix} |{bar}| {percent}% Complete", end="", flush=True)
    if progress == total:
        print()


def simulate_progress(message, duration=1.0, steps=20):
    print(f"\033[94m{message}\033[0m")
    for i in range(steps + 1):
        time.sleep(duration / steps)
        progress_bar(i, steps, prefix="Progress:", length=40)


def filter_output(output):
    """ImportantMessage"""
    if not output:
        return ""
    important_lines = []
    for line in output.split("\n"):
        # Only keep lines containing specific keywords
        if any(
            keyword in line.lower()
            for keyword in ["error:", "failed:", "completed", "directory:"]
        ):
            important_lines.append(line)
    return "\n".join(important_lines)


def build():
    # Clear screen
    os.system("cls" if platform.system().lower() == "windows" else "clear")

    # Print logo
    print_logo()

    system = platform.system().lower()
    spec_file = os.path.join("CursorKeepAlive.spec")

    # if system not in ["darwin", "windows"]:
    #     print(f"\033[91mUnsupported operating system: {system}\033[0m")
    #     return

    output_dir = f"dist/{system if system != 'darwin' else 'mac'}"

    # Create output directory
    os.makedirs(output_dir, exist_ok=True)
    simulate_progress("Creating output directory...", 0.5)

    # Run PyInstaller with loading animation
    pyinstaller_command = [
        "pyinstaller",
        spec_file,
        "--distpath",
        output_dir,
        "--workpath",
        f"build/{system}",
        "--noconfirm",
    ]

    loading = LoadingAnimation()
    try:
        simulate_progress("Running PyInstaller...", 2.0)
        loading.start("Building in progress")
        result = subprocess.run(
            pyinstaller_command, check=True, capture_output=True, text=True
        )
        loading.stop()

        if result.stderr:
            filtered_errors = [
                line
                for line in result.stderr.split("\n")
                if any(
                    keyword in line.lower()
                    for keyword in ["error:", "failed:", "completed", "directory:"]
                )
            ]
            if filtered_errors:
                print("\033[93mBuild Warnings/Errors:\033[0m")
                print("\n".join(filtered_errors))

    except subprocess.CalledProcessError as e:
        loading.stop()
        print(f"\033[91mBuild failed with error code {e.returncode}\033[0m")
        if e.stderr:
            print("\033[91mError Details:\033[0m")
            print(e.stderr)
        return
    except FileNotFoundError:
        loading.stop()
        print(
            "\033[91mError: Please ensure PyInstaller is installed (pip install pyinstaller)\033[0m"
        )
        return
    except KeyboardInterrupt:
        loading.stop()
        print("\n\033[91mBuild cancelled by user\033[0m")
        return
    finally:
        loading.stop()

    # Copy config file
    if os.path.exists("config.ini.example"):
        simulate_progress("Copying configuration file...", 0.5)
        if system == "windows":
            subprocess.run(
                ["copy", "config.ini.example", f"{output_dir}\\config.ini"], shell=True
            )
        else:
            subprocess.run(["cp", "config.ini.example", f"{output_dir}/config.ini"])

    # Copy .env.example file
    if os.path.exists(".env.example"):
        simulate_progress("Copying environment file...", 0.5)
        if system == "windows":
            subprocess.run(["copy", ".env.example", f"{output_dir}\\.env"], shell=True)
        else:
            subprocess.run(["cp", ".env.example", f"{output_dir}/.env"])

    print(
        f"\n\033[92mBuild completed successfully! Output directory: {output_dir}\033[0m"
    )


if __name__ == "__main__":
    build()


================================================
FILE: build.sh
================================================
#!/bin/bash
export PYTHONWARNINGS=ignore::SyntaxWarning:DrissionPage

echo "Creating virtual environment..."

# Check if virtual environment exists
if [ ! -d "venv" ]; then
    python3 -m venv venv
    if [ $? -ne 0 ]; then
        echo "Failed to create virtual environment!"
        exit 1
    fi
fi

# Activate virtual environment
source venv/bin/activate

# Install dependencies
echo "Installing dependencies..."
python -m pip install --upgrade pip
pip install -r requirements.txt

# Run build script
echo "Starting build process..."
python build.py

# Complete
echo "Build completed!"

================================================
FILE: config.py
================================================
from dotenv import load_dotenv
import os
import sys
from logger import logging
from language import get_translation


class Config:
    def __init__(self):
        # 获取应用程序的根目录路径
        if getattr(sys, "frozen", False):
            # 如果是打包后的可执行文件
            application_path = os.path.dirname(sys.executable)
        else:
            # 如果是开发环境
            application_path = os.path.dirname(os.path.abspath(__file__))

        # 指定 .env 文件的路径
        dotenv_path = os.path.join(application_path, ".env")

        if not os.path.exists(dotenv_path):
            raise FileNotFoundError(get_translation("file_not_exists", path=dotenv_path))

        # 加载 .env 文件
        load_dotenv(dotenv_path)

        self.imap = False
        self.temp_mail = os.getenv("TEMP_MAIL", "").strip().split("@")[0]
        self.temp_mail_epin = os.getenv("TEMP_MAIL_EPIN", "").strip()
        self.temp_mail_ext = os.getenv("TEMP_MAIL_EXT", "").strip()
        self.domain = os.getenv("DOMAIN", "").strip()

        # 如果临时邮箱为null则加载IMAP
        if self.temp_mail == "null":
            self.imap = True
            self.imap_server = os.getenv("IMAP_SERVER", "").strip()
            self.imap_port = os.getenv("IMAP_PORT", "").strip()
            self.imap_user = os.getenv("IMAP_USER", "").strip()
            self.imap_pass = os.getenv("IMAP_PASS", "").strip()
            self.imap_dir = os.getenv("IMAP_DIR", "inbox").strip()

        self.check_config()

    def get_temp_mail(self):

        return self.temp_mail

    def get_temp_mail_epin(self):

        return self.temp_mail_epin

    def get_temp_mail_ext(self):

        return self.temp_mail_ext

    def get_imap(self):
        if not self.imap:
            return False
        return {
            "imap_server": self.imap_server,
            "imap_port": self.imap_port,
            "imap_user": self.imap_user,
            "imap_pass": self.imap_pass,
            "imap_dir": self.imap_dir,
        }

    def get_domain(self):
        return self.domain

    def get_protocol(self):
        """获取邮件协议类型
        
        Returns:
            str: 'IMAP' 或 'POP3'
        """
        return os.getenv('IMAP_PROTOCOL', 'POP3')

    def check_config(self):
        """检查配置项是否有效

        检查规则:
        1. 如果使用 tempmail.plus,需要配置 TEMP_MAIL 和 DOMAIN
        2. 如果使用 IMAP,需要配置 IMAP_SERVER、IMAP_PORT、IMAP_USER、IMAP_PASS
        3. IMAP_DIR 是可选的
        """
        # 基础配置检查
        required_configs = {
            "domain": "domain_not_configured",
        }

        # 检查基础配置
        for key, error_key in required_configs.items():
            if not self.check_is_valid(getattr(self, key)):
                raise ValueError(get_translation(error_key))

        # 检查邮箱配置
        if self.temp_mail != "null":
            # tempmail.plus 模式
            if not self.check_is_valid(self.temp_mail):
                raise ValueError(get_translation("temp_mail_not_configured"))
        else:
            # IMAP 模式
            imap_configs = {
                "imap_server": "imap_server_not_configured",
                "imap_port": "imap_port_not_configured",
                "imap_user": "imap_user_not_configured",
                "imap_pass": "imap_pass_not_configured",
            }

            for key, error_key in imap_configs.items():
                value = getattr(self, key)
                if value == "null" or not self.check_is_valid(value):
                    raise ValueError(get_translation(error_key))

            # IMAP_DIR 是可选的,如果设置了就检查其有效性
            if self.imap_dir != "null" and not self.check_is_valid(self.imap_dir):
                raise ValueError(get_translation("imap_dir_invalid"))

    def check_is_valid(self, value):
        """检查配置项是否有效

        Args:
            value: 配置项的值

        Returns:
            bool: 配置项是否有效
        """
        return isinstance(value, str) and len(str(value).strip()) > 0

    def print_config(self):
        if self.imap:
            logging.info(get_translation("imap_server", server=self.imap_server))
            logging.info(get_translation("imap_port", port=self.imap_port))
            logging.info(get_translation("imap_username", username=self.imap_user))
            logging.info(get_translation("imap_password", password='*' * len(self.imap_pass)))
            logging.info(get_translation("imap_inbox_dir", dir=self.imap_dir))
        if self.temp_mail != "null":
            logging.info(get_translation("temp_mail", mail=f"{self.temp_mail}{self.temp_mail_ext}"))
        logging.info(get_translation("domain", domain=self.domain))


# 使用示例
if __name__ == "__main__":
    try:
        config = Config()
        print(get_translation("env_variables_loaded"))
        config.print_config()
    except ValueError as e:
        print(get_translation("error_prefix", error=e))


================================================
FILE: cursor_auth_manager.py
================================================
import sqlite3
import os
import sys


class CursorAuthManager:
    """Cursor认证信息管理器"""

    def __init__(self):
        # 判断操作系统
        if sys.platform == "win32":  # Windows
            appdata = os.getenv("APPDATA")
            if appdata is None:
                raise EnvironmentError("APPDATA 环境变量未设置")
            self.db_path = os.path.join(
                appdata, "Cursor", "User", "globalStorage", "state.vscdb"
            )
        elif sys.platform == "darwin": # macOS
            self.db_path = os.path.abspath(os.path.expanduser(
                "~/Library/Application Support/Cursor/User/globalStorage/state.vscdb"
            ))
        elif sys.platform == "linux" : # Linux 和其他类Unix系统
            self.db_path = os.path.abspath(os.path.expanduser(
                "~/.config/Cursor/User/globalStorage/state.vscdb"
            ))
        else:
            raise NotImplementedError(f"不支持的操作系统: {sys.platform}")

    def update_auth(self, email=None, access_token=None, refresh_token=None):
        """
        更新Cursor的认证信息
        :param email: 新的邮箱地址
        :param access_token: 新的访问令牌
        :param refresh_token: 新的刷新令牌
        :return: bool 是否成功更新
        """
        updates = []
        # 登录状态
        updates.append(("cursorAuth/cachedSignUpType", "Auth_0"))

        if email is not None:
            updates.append(("cursorAuth/cachedEmail", email))
        if access_token is not None:
            updates.append(("cursorAuth/accessToken", access_token))
        if refresh_token is not None:
            updates.append(("cursorAuth/refreshToken", refresh_token))

        if not updates:
            print("没有提供任何要更新的值")
            return False

        conn = None
        try:
            conn = sqlite3.connect(self.db_path)
            cursor = conn.cursor()

            for key, value in updates:

                # 如果没有更新任何行,说明key不存在,执行插入
                # 检查 accessToken 是否存在
                check_query = f"SELECT COUNT(*) FROM itemTable WHERE key = ?"
                cursor.execute(check_query, (key,))
                if cursor.fetchone()[0] == 0:
                    insert_query = "INSERT INTO itemTable (key, value) VALUES (?, ?)"
                    cursor.execute(insert_query, (key, value))
                else:
                    update_query = "UPDATE itemTable SET value = ? WHERE key = ?"
                    cursor.execute(update_query, (value, key))

                if cursor.rowcount > 0:
                    print(f"成功更新 {key.split('/')[-1]}")
                else:
                    print(f"未找到 {key.split('/')[-1]} 或值未变化")

            conn.commit()
            return True

        except sqlite3.Error as e:
            print("数据库错误:", str(e))
            return False
        except Exception as e:
            print("发生错误:", str(e))
            return False
        finally:
            if conn:
                conn.close()


================================================
FILE: cursor_pro_gui.py
================================================
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# pyinstaller: --noconsole, --onefile, --name=CursorProGUI, --uac-admin, --add-data=turnstilePatch:turnstilePatch

"""
Cursor Pro GUI - 基于PyQt5的图形界面程序
用于调用cursor_pro_keep_alive.py提供的API功能
"""

import sys
import os
import logging
import platform

# 设置日志配置 - 打包后使用文件日志而非控制台
is_packaged = getattr(sys, 'frozen', False)
if is_packaged:
    # 运行在打包后的环境中,重定向日志到文件
    log_dir = os.path.join(os.path.expanduser('~'), 'CursorProGUI_logs')
    if not os.path.exists(log_dir):
        os.makedirs(log_dir)
    log_file = os.path.join(log_dir, 'cursorpro_gui.log')
    logging.basicConfig(
        filename=log_file,
        level=logging.INFO,
        format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
    )
else:
    # 开发环境,使用控制台日志
    logging.basicConfig(
        level=logging.INFO,
        format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
    )

# 提前导入管理员权限检查函数,这样如果有错误我们可以尽早捕获
try:
    from utils import is_admin
    # 记录权限状态
    if is_admin():
        logging.info("以管理员权限运行")
    else:
        logging.warning("未以管理员权限运行,某些功能可能受限")
except Exception as e:
    logging.error(f"导入权限检查模块时出错: {str(e)}")
    
# 导入PyQt5相关库
from PyQt5.QtWidgets import QApplication, QMainWindow, QTabWidget, QWidget, QVBoxLayout, QStatusBar, QLabel, QMessageBox
from PyQt5.QtCore import QTranslator, QLocale, QSettings, Qt
from PyQt5.QtGui import QIcon, QPalette, QColor

# 导入各个标签页
from gui.home_tab import HomeTab
from gui.reset_tab import ResetTab
from gui.register_tab import RegisterTab
from gui.account_tab import AccountTab
from gui.env_tab import EnvTab
from gui.about_tab import AboutTab

# 定义应用程序样式表
STYLE_SHEET = """
/* 全局样式 */
QWidget {
    font-family: "Microsoft YaHei", "Segoe UI", Arial, sans-serif;
    font-size: 10pt;
}

/* 主窗口样式 */
QMainWindow {
    background-color: #f5f5f5;
}

/* 状态栏样式 */
QStatusBar {
    background-color: #1a73e8;
    color: white;
    font-weight: bold;
    padding: 3px 10px;
    border-top: 1px solid #0d47a1;
}

QStatusBar QLabel {
    color: white;
}

/* 标签页样式 */
QTabWidget::pane {
    border: 1px solid #cccccc;
    background-color: white;
    border-radius: 3px;
}

QTabBar::tab {
    background-color: #e0e0e0;
    color: #505050;
    min-width: 80px;
    padding: 8px 10px;
    margin-right: 2px;
    border-top-left-radius: 3px;
    border-top-right-radius: 3px;
}

QTabBar::tab:selected {
    background-color: white;
    color: #1a73e8;
    border: 1px solid #cccccc;
    border-bottom: 2px solid #1a73e8;
}

QTabBar::tab:hover:!selected {
    background-color: #d0d0d0;
}

/* 按钮样式 */
QPushButton {
    background-color: #1a73e8;
    color: white;
    border: none;
    padding: 8px 16px;
    border-radius: 4px;
    min-height: 30px;
}

QPushButton:hover {
    background-color: #4285f4;
}

QPushButton:pressed {
    background-color: #0d47a1;
}

QPushButton:disabled {
    background-color: #cccccc;
    color: #888888;
}

/* 次要按钮样式 */
QPushButton[secondary="true"] {
    background-color: #e0e0e0;
    color: #505050;
    border: 1px solid #bbbbbb;
}

QPushButton[secondary="true"]:hover {
    background-color: #d0d0d0;
}

/* 分组框样式 */
QGroupBox {
    border: 1px solid #cccccc;
    border-radius: 4px;
    margin-top: 1.5ex;
    font-weight: bold;
    color: #404040;
}

QGroupBox::title {
    subcontrol-origin: margin;
    subcontrol-position: top left;
    padding: 0 5px;
    color: #1a73e8;
}

/* 文本编辑区域样式 */
QTextEdit {
    background-color: white;
    border: 1px solid #cccccc;
    border-radius: 3px;
    padding: 2px;
}

QTextEdit:focus {
    border: 1px solid #4285f4;
}

/* 行编辑样式 */
QLineEdit {
    background-color: white;
    border: 1px solid #cccccc;
    border-radius: 3px;
    padding: 5px;
    selection-background-color: #4285f4;
}

QLineEdit:focus {
    border: 1px solid #4285f4;
}

/* 列表部件样式 */
QListWidget {
    background-color: white;
    border: 1px solid #cccccc;
    border-radius: 3px;
    alternate-background-color: #f9f9f9;
}

QListWidget::item {
    padding: 5px;
    border-bottom: 1px solid #f0f0f0;
}

QListWidget::item:selected {
    background-color: #e7f0fd;
    color: #1a73e8;
    border-left: 3px solid #1a73e8;
}

QListWidget::item:hover:!selected {
    background-color: #f5f5f5;
}

/* 进度条样式 */
QProgressBar {
    border: 1px solid #cccccc;
    border-radius: 3px;
    background-color: #f0f0f0;
    color: #404040;
    text-align: center;
}

QProgressBar::chunk {
    background-color: #1a73e8;
    border-radius: 2px;
}

/* 标签样式 */
QLabel {
    color: #404040;
}

QLabel[heading="true"] {
    font-size: 14pt;
    font-weight: bold;
    color: #1a73e8;
}

/* 单选按钮样式 */
QRadioButton {
    spacing: 8px;
}

QRadioButton::indicator {
    width: 16px;
    height: 16px;
}

/* 滚动条样式 */
QScrollBar:vertical {
    border: none;
    background-color: #f0f0f0;
    width: 10px;
    margin: 0px;
}

QScrollBar::handle:vertical {
    background-color: #c0c0c0;
    min-height: 20px;
    border-radius: 5px;
}

QScrollBar::handle:vertical:hover {
    background-color: #a0a0a0;
}

QScrollBar:horizontal {
    border: none;
    background-color: #f0f0f0;
    height: 10px;
    margin: 0px;
}

QScrollBar::handle:horizontal {
    background-color: #c0c0c0;
    min-width: 20px;
    border-radius: 5px;
}

QScrollBar::handle:horizontal:hover {
    background-color: #a0a0a0;
}
"""

class CursorProGUI(QMainWindow):
    """Cursor Pro GUI主窗口类"""
    
    def __init__(self):
        """初始化主窗口"""
        super().__init__()
        self.setWindowTitle("Cursor Pro")
        self.setWindowIcon(QIcon(os.path.join(os.path.dirname(os.path.abspath(__file__)), "icons", "logo.png")))
        
        # 设置翻译器
        self.translator = QTranslator()
        
        # 设置窗口基本属性
        self.settings = QSettings("CursorPro", "CursorProGUI")
        
        # 初始化UI
        self.init_ui()
        
        # 初始化语言设置
        self.init_language()
        
        # 恢复窗口大小和位置
        if self.settings.contains("window/geometry"):
            self.restoreGeometry(self.settings.value("window/geometry"))
        else:
            # 如果没有存储的大小/位置,则居中显示窗口
            self.center_window()
    
    def init_ui(self):
        """初始化用户界面"""
        # 创建标签页控件
        self.tabs = QTabWidget()
        self.tabs.setDocumentMode(True)  # 更现代的标签页外观
        self.tabs.setTabPosition(QTabWidget.North)
        
        # 添加各功能标签页
        self.home_tab = HomeTab(self)
        self.reset_tab = ResetTab(self)
        self.register_tab = RegisterTab(self)
        self.account_tab = AccountTab(self)
        self.env_tab = EnvTab(self)
        self.about_tab = AboutTab(self)
        
        # 将标签页添加到标签页控件
        self.tabs.addTab(self.home_tab, self.tr("首页"))
        self.tabs.addTab(self.reset_tab, self.tr("重置机器码"))
        self.tabs.addTab(self.register_tab, self.tr("注册账号"))
        self.tabs.addTab(self.account_tab, self.tr("账号管理"))
        self.tabs.addTab(self.env_tab, self.tr("环境配置"))
        self.tabs.addTab(self.about_tab, self.tr("关于"))
        
        # 设置中心部件
        self.setCentralWidget(self.tabs)
        
        # 创建状态栏
        self.statusBar = QStatusBar()
        self.setStatusBar(self.statusBar)
        
        # 设置默认状态消息
        self.statusBar.showMessage(self.tr("就绪 - 访问「关于」标签页获取更多信息"))
    
    def center_window(self):
        """将窗口置于屏幕中央"""
        frame_geometry = self.frameGeometry()
        screen_center = QApplication.desktop().availableGeometry().center()
        frame_geometry.moveCenter(screen_center)
        self.move(frame_geometry.topLeft())
    
    def init_language(self):
        """初始化语言设置"""
        # 获取当前语言设置
        current_locale = self.settings.value("language", QLocale.system().name())
        self.change_language(current_locale)
    
    def change_language(self, locale):
        """
        切换应用程序语言
        
        Args:
            locale: 语言/地区代码(如 'zh_CN', 'en_US')
        """
        # 加载翻译文件
        if locale in ['zh_CN', 'zh-CN', 'zh']:
            translation_loaded = self.translator.load("translations/cursor_pro_zh_CN.qm")
        else:
            translation_loaded = self.translator.load("translations/cursor_pro_en_US.qm")
        
        # 应用翻译
        if translation_loaded:
            QApplication.installTranslator(self.translator)
        else:
            QApplication.removeTranslator(self.translator)
        
        # 保存语言设置
        self.settings.setValue("language", locale)
        
        # 刷新UI文本
        self.retranslate_ui()
    
    def retranslate_ui(self):
        """更新UI文本翻译"""
        # 更新标签页标题
        self.tabs.setTabText(0, self.tr("首页"))
        self.tabs.setTabText(1, self.tr("重置机器码"))
        self.tabs.setTabText(2, self.tr("注册账号"))
        self.tabs.setTabText(3, self.tr("账号管理"))
        self.tabs.setTabText(4, self.tr("环境配置"))
        self.tabs.setTabText(5, self.tr("关于"))
        
        # 更新窗口标题
        self.setWindowTitle(self.tr("Cursor Pro GUI"))
        
        # 更新状态栏消息
        self.statusBar.showMessage(self.tr("就绪 - 访问「关于」标签页获取更多信息"))
        
        # 更新各标签页翻译
        self.home_tab.retranslate_ui()
        self.reset_tab.retranslate_ui()
        self.register_tab.retranslate_ui()
        self.account_tab.retranslate_ui()
        self.env_tab.retranslate_ui()
        self.about_tab.retranslate_ui()
    
    def update_status(self, message):
        """更新状态栏消息"""
        self.statusBar.showMessage(message)
    
    def closeEvent(self, event):
        """窗口关闭事件处理"""
        # 保存窗口大小和位置
        self.settings.setValue("window/geometry", self.saveGeometry())
        # 接受关闭事件
        event.accept()

def main():
    """主函数入口"""
    try:
        # 记录应用启动信息
        is_frozen = getattr(sys, 'frozen', False)
        current_platform = platform.system()
        logging.info(f"应用启动 - 打包状态: {'已打包' if is_frozen else '开发环境'}, 平台: {current_platform}")
        
        # 处理管理员权限
        from utils import is_admin
        admin_status = is_admin()
        
        # 创建应用程序实例
        app = QApplication(sys.argv)
        
        # 如果未以管理员权限运行且不是打包状态,显示警告
        # 注意:如果是打包状态,打包器设置应该已经请求了管理员权限
        if not admin_status and not is_frozen:
            msg_box = QMessageBox()
            msg_box.setIcon(QMessageBox.Warning)
            msg_box.setWindowTitle("权限警告")
            msg_box.setText("应用程序未以管理员权限运行,部分功能可能不可用。")
            msg_box.setInformativeText("要获得完整功能,请以管理员身份运行此应用程序。")
            msg_box.setStandardButtons(QMessageBox.Ok | QMessageBox.Cancel)
            
            # 用户选择取消,则退出
            if msg_box.exec_() == QMessageBox.Cancel:
                return 1
        
        # 平台特定设置
        if current_platform == 'Darwin':  # macOS
            app.setAttribute(Qt.AA_UseHighDpiPixmaps)
            app.setAttribute(Qt.AA_DontUseNativeMenuBar, True)
            
            # 如果是打包后的应用,设置应用名称
            if is_frozen:
                app.setApplicationName("CursorProGUI")
                
        # 应用样式表
        app.setStyleSheet(STYLE_SHEET)
        
        # 创建主窗口
        window = CursorProGUI()
        
        # 根据管理员状态更新状态栏
        if admin_status:
            window.update_status("以管理员权限运行")
        else:
            window.update_status("警告:未以管理员权限运行,部分功能可能受限")
        
        # 显示主窗口
        window.show()
        logging.info("应用主窗口已显示")
        
        # 运行应用程序事件循环
        return app.exec_()
    except Exception as e:
        logging.error(f"应用启动失败: {str(e)}")
        logging.exception("发生异常:")
        return 1

if __name__ == "__main__":
    sys.exit(main()) 

================================================
FILE: cursor_pro_keep_alive.py
================================================
import os
import platform
import json
import sys
from colorama import Fore, Style
from enum import Enum
from typing import Optional, Dict, Any, Tuple, List, Union, Callable
import traceback
import secrets
import base64
import hmac
import hashlib
import uuid
import requests
from disable_auto_update import AutoUpdateDisabler 

from exit_cursor import ExitCursor
from start_cursor import StartCursor
import go_cursor_help
import patch_cursor_get_machine_id
from reset_machine import MachineIDResetter
from language import language, get_translation

os.environ["PYTHONVERBOSE"] = "0"
os.environ["PYINSTALLER_VERBOSE"] = "0"

import time
import random
from cursor_auth_manager import CursorAuthManager
import os
from logger import logging
from browser_utils import BrowserManager
from get_email_code import EmailVerificationHandler
from logo import print_logo
from config import Config
from datetime import datetime

# 定义URL常量
LOGIN_URL = "https://authenticator.cursor.sh"
SIGN_UP_URL = "https://authenticator.cursor.sh/sign-up"
SETTINGS_URL = "https://www.cursor.com/settings"
MAIL_URL = "https://tempmail.plus"

# Define EMOJI dictionary
EMOJI = {"ERROR": get_translation("error"), "WARNING": get_translation("warning"), "INFO": get_translation("info")}

index = 0

class VerificationStatus(Enum):
    """Verification status enum"""
    SIGN_UP = "@name=first_name"
    PASSWORD_PAGE = "@name=password"
    CAPTCHA_PAGE = "@data-index=0"
    ACCOUNT_SETTINGS = "Account Settings"
    TOKEN_REFRESH = "You're currently logged in as:"


class TurnstileError(Exception):
    """Turnstile verification related exception"""
    pass


class CursorProKeepAlive:
    """主类,封装所有Cursor相关操作"""
    
    def __init__(self):
        """初始化CursorProKeepAlive实例"""
        self.browser_manager = None
        self.browser = None
        self.tab = None
        self.email_generator = None
        self.email_handler = None
        self.account = None
        self.password = None
        self.first_name = None
        self.last_name = None
        self.access_token = None
        self.refresh_token = None
        self.greater_than_0_45 = self.check_cursor_version()
        
    def init_browser(self) -> bool:
        """初始化浏览器实例"""
        try:
            logging.info(get_translation("initializing_browser"))
            
            # 获取用户代理
            user_agent = self.get_user_agent()
            if not user_agent:
                logging.error(get_translation("get_user_agent_failed"))
                user_agent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"
            
            # 移除"HeadlessChrome"
            user_agent = user_agent.replace("HeadlessChrome", "Chrome")
            
            # 初始化浏览器
            self.browser_manager = BrowserManager()
            self.browser = self.browser_manager.init_browser(user_agent)
            self.tab = self.browser.latest_tab
            
            # 验证用户代理设置成功
            actual_user_agent = self.tab.run_js("return navigator.userAgent")
            logging.debug(f"Browser user agent: {actual_user_agent}")
            
            return True
        except Exception as e:
            logging.error(f"Browser initialization failed: {str(e)}")
            return False
    
    def cleanup(self):
        """清理浏览器资源"""
        if self.browser_manager:
            logging.info(get_translation("closing_browser"))
            self.browser_manager.quit()
    
    def get_user_agent(self) -> Optional[str]:
        """获取用户代理字符串"""
        try:
            # 使用JavaScript获取用户代理
            temp_browser_manager = BrowserManager()
            temp_browser = temp_browser_manager.init_browser()
            user_agent = temp_browser.latest_tab.run_js("return navigator.userAgent")
            temp_browser_manager.quit()
            return user_agent
        except Exception as e:
            logging.error(f"Failed to get user agent: {str(e)}")
            return None
    
    def check_cursor_version(self) -> bool:
        """检查Cursor版本"""
        pkg_path, main_path = patch_cursor_get_machine_id.get_cursor_paths()
        with open(pkg_path, "r", encoding="utf-8") as f:
            version = json.load(f)["version"]
        return patch_cursor_get_machine_id.version_check(version, min_version="0.45.0")
    
    def reset_machine_id(self) -> bool:
        """重置机器ID"""
        try:
            logging.info(get_translation("resetting_machine_code"))
            if self.greater_than_0_45:
                # 提示手动执行脚本
                go_cursor_help.go_cursor_help()
            else:
                MachineIDResetter().reset_machine_ids()
            logging.info(get_translation("machine_code_reset_complete"))
            return True
        except Exception as e:
            logging.error(f"Failed to reset machine ID: {str(e)}")
            return False
    
    def disable_auto_update(self) -> bool:
        """禁用自动更新"""
        try:
            logging.info(get_translation("disabling_auto_update"))
            AutoUpdateDisabler().disable_auto_update()
            logging.info(get_translation("auto_update_disabled"))
            return True
        except Exception as e:
            logging.error(f"Failed to disable auto update: {str(e)}")
            return False
    
    def update_cursor_auth(self, email: str = None, access_token: str = None, refresh_token: str = None) -> bool:
        """更新Cursor身份验证信息"""
        try:
            email = email or self.account
            access_token = access_token or self.access_token
            refresh_token = refresh_token or self.refresh_token
            
            auth_manager = CursorAuthManager()
            result = auth_manager.update_auth(email, access_token, refresh_token)
            
            if result:
                logging.info(get_translation("auth_info_updated"))
            else:
                logging.error(get_translation("auth_update_failed"))
                
            return result
        except Exception as e:
            logging.error(f"Failed to update auth info: {str(e)}")
            return False
    
    def start_cursor(self) -> None:
        """启动Cursor"""
        if os.getenv("BROWSER_HEADLESS", "True").lower() == "true":
            StartCursor()
    
    def generate_account(self) -> Dict[str, str]:
        """生成随机账号信息"""
        try:
            logging.info(get_translation("generating_random_account"))
            
            self.email_generator = EmailGenerator()
            self.first_name = self.email_generator.default_first_name
            self.last_name = self.email_generator.default_last_name
            self.account = self.email_generator.generate_email()
            self.password = self.email_generator.default_password
            
            logging.info(get_translation("generated_email_account", email=self.account))
            
            # 初始化邮件验证处理器
            self.email_handler = EmailVerificationHandler(self.account)
            
            return {
                "email": self.account,
                "password": self.password,
                "first_name": self.first_name,
                "last_name": self.last_name
            }
        except Exception as e:
            logging.error(f"Failed to generate account: {str(e)}")
            return {}
    
    def print_end_message(self) -> None:
        """打印结束消息"""
        logging.info("\n\n\n\n\n")
        logging.info("=" * 30)
        logging.info(get_translation("all_operations_completed"))
        logging.info("\n=== Get More Information ===")
        logging.info("🔥 WeChat Official Account: wf5569")
        logging.info("=" * 30)
        logging.info(
            "Please visit the open source project for more information: https://github.com/wangffei/wf-cursor-auto-free.git"
        )

    def save_account_info(self, email: str = None, password: str = None, 
                         access_token: str = None, refresh_token: str = None) -> bool:
        """
        将账号信息保存为JSON文件
        
        Args:
            email: 注册邮箱
            password: 账号密码
            access_token: 访问令牌
            refresh_token: 刷新令牌
        """
        email = email or self.account
        password = password or self.password
        access_token = access_token or self.access_token
        refresh_token = refresh_token or self.refresh_token
        
        logging.info(get_translation("saving_account_info"))
        
        # 创建accounts目录(如果不存在)
        accounts_dir = "accounts"
        if not os.path.exists(accounts_dir):
            os.makedirs(accounts_dir)
        
        # 生成文件名(使用时间戳确保唯一性)
        timestamp = datetime.now().strftime("%Y%m%d%H%M%S")
        filename = f"cursor_account_{timestamp}.json"
        filepath = os.path.join(accounts_dir, filename)
        
        # 创建账号信息字典
        account_info = {
            "email": email,
            "password": password,
            "access_token": access_token,
            "refresh_token": refresh_token,
            "created_time": datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        }
        
        # 写入JSON文件
        try:
            with open(filepath, "w", encoding="utf-8") as f:
                json.dump(account_info, f, indent=4, ensure_ascii=False)
            logging.info(get_translation("account_saved_successfully", path=filepath))
            # 在控制台打印账号信息和保存路径
            print("\n" + "="*50)
            print(f"📁 {get_translation('account_saved_successfully', path=filepath)}")
            print(f"📧 Email: {email}")
            print(f"🔑 Password: {password}")
            print("="*50 + "\n")
            return True
        except Exception as e:
            logging.error(get_translation("account_save_failed", error=str(e)))
            return False
            
    def list_and_apply_saved_accounts(self) -> bool:
        """
        列出保存的账号并允许用户选择一个应用
        """
        accounts_dir = "accounts"
        if not os.path.exists(accounts_dir):
            logging.error(get_translation("accounts_dir_not_found", dir=accounts_dir))
            return False
        
        # 获取所有JSON文件
        account_files = [f for f in os.listdir(accounts_dir) if f.endswith('.json')]
        if not account_files:
            logging.error(get_translation("no_account_files_found", dir=accounts_dir))
            return False
        
        # 排序按照创建时间(文件名中包含的时间戳)
        account_files.sort(reverse=True)
        
        # 显示账号列表
        print(get_translation("saved_accounts_title"))
        for i, filename in enumerate(account_files):
            try:
                filepath = os.path.join(accounts_dir, filename)
                with open(filepath, 'r', encoding='utf-8') as f:
                    account_data = json.load(f)
                    email = account_data.get('email', 'N/A')
                    created_time = account_data.get('created_time', get_translation("account_created_time"))
                    print(f"{i+1}. {email} ({get_translation('account_created_time')}: {created_time})")
            except Exception as e:
                print(f"{i+1}. {filename} [{get_translation('reading_error')}: {str(e)}]")
        
        # 用户选择
        print(f"\n0. {get_translation('return_to_main_menu')}")
        while True:
            try:
                choice = int(input(f"{get_translation('select_account_number')}: ").strip())
                if choice == 0:
                    return False
                elif 1 <= choice <= len(account_files):
                    selected_file = account_files[choice-1]
                    return self.apply_account_from_file(os.path.join(accounts_dir, selected_file))
                else:
                    print(get_translation("invalid_selection"))
            except ValueError:
                print(get_translation("please_enter_number"))

    def apply_account_from_file(self, filepath: str) -> bool:
        """
        从文件中加载账号信息并应用
        
        Args:
            filepath: 账号信息文件路径
        
        Returns:
            bool: 是否成功应用
        """
        try:
            logging.info(get_translation("loading_account_info", path=filepath))
            
            with open(filepath, 'r', encoding='utf-8') as f:
                account_data = json.load(f)
            
            email = account_data.get('email')
            access_token = account_data.get('access_token')
            refresh_token = account_data.get('refresh_token')
            
            if not email or not access_token or not refresh_token:
                logging.error(get_translation("incomplete_account_info"))
                return False
            
            # 更新实例变量
            self.account = email
            self.access_token = access_token
            self.refresh_token = refresh_token
            
            logging.info(get_translation("using_account", email=email))
            logging.info(get_translation("updating_auth_info"))
            
            result = self.update_cursor_auth()
            
            if result:
                logging.info(
                    "Please visit the open source project for more information: https://github.com/wangffei/wf-cursor-auto-free.git"
                )
                self.reset_machine_id()
                logging.info(get_translation("all_operations_completed"))
                self.print_end_message()
                self.start_cursor()
                return True
            else:
                logging.error(get_translation("apply_account_failed"))
                return False
                
        except Exception as e:
            logging.error(get_translation("apply_account_error", error=str(e)))
            return False

    # 主要操作函数封装
    def option_reset_machine_id(self) -> bool:
        """选项1: 仅重置机器码"""
        try:
            ExitCursor()
            result = self.reset_machine_id()
            self.print_end_message()
            return result
        except Exception as e:
            logging.error(f"Failed to reset machine ID: {str(e)}")
            return False
            
    def option_disable_auto_update(self) -> bool:
        """选项4: 禁用自动更新"""
        try:
            ExitCursor()
            return self.disable_auto_update()
        except Exception as e:
            logging.error(f"Failed to disable auto update: {str(e)}")
            return False
            
    def option_apply_saved_account(self) -> bool:
        """选项5: 选择并应用已保存的账号"""
        try:
            ExitCursor()
            return self.list_and_apply_saved_accounts()
        except Exception as e:
            logging.error(f"Failed to apply saved account: {str(e)}")
            return False

    def handle_turnstile(self, tab=None, max_retries: int = 2, retry_interval: tuple = (1, 2)) -> bool:
        """
        处理Turnstile验证
        
        Args:
            tab: 浏览器标签对象
            max_retries: 最大重试次数
            retry_interval: 重试间隔范围(最小值, 最大值)
            
        Returns:
            bool: 验证是否成功
            
        Raises:
            TurnstileError: 验证过程中的异常
        """
        tab = tab or self.tab
        
        logging.info(get_translation("detecting_turnstile"))
        save_screenshot(tab, "start")
        
        retry_count = 0
        
        try:
            while retry_count < max_retries:
                retry_count += 1
                logging.debug(get_translation("retry_verification", count=retry_count))
                
                try:
                    element = None
                    try:
                        element = (
                            tab.ele(".main-content")  # 找到 .main-content 元素
                            .ele("tag:div")        # 找到第一个子 div
                            .ele("tag:div")        # 找到第二个子 div
                            .ele("tag:div")        # 找到第三个子 div
                        )
                    except Exception as e:
                        pass
                    if element:
                        # Locate verification frame element
                        challenge_check = (
                            element
                            .shadow_root.ele("tag:iframe")
                            .ele("tag:body")
                            .sr("tag:input")
                        )
                    else:
                        # Locate verification frame element
                        challenge_check = (
                            tab.ele("@id=cf-turnstile", timeout=2)
                            .child()
                            .shadow_root.ele("tag:iframe")
                            .ele("tag:body")
                            .sr("tag:input")
                        )
                        
                    if challenge_check:
                        logging.info(get_translation("detected_turnstile"))
                        # Random delay before clicking verification
                        time.sleep(random.uniform(1, 3))
                        challenge_check.click()
                        time.sleep(2)
                        
                        # Save screenshot after verification
                        save_screenshot(tab, "clicked")
                        
                        # Check verification result
                        if check_verification_success(tab):
                            save_screenshot(tab, "success")
                            return True
                        
                except Exception as e:
                    logging.debug(f"Current attempt unsuccessful: {str(e)}")
                    
                # Check if already verified
                if check_verification_success(tab):
                    return True
                    
                # Random delay before next attempt
                time.sleep(random.uniform(*retry_interval))
                
            # Exceeded maximum retries
            logging.error(get_translation("verification_failed_max_retries", max_retries=max_retries))
            logging.error(
                "Please visit the open source project for more information: https://github.com/wangffei/wf-cursor-auto-free.git"
            )
            save_screenshot(tab, "failed")
            return False
            
        except Exception as e:
            error_msg = get_translation("turnstile_exception", error=str(e))
            logging.error(error_msg)
            save_screenshot(tab, "error")
            raise TurnstileError(error_msg)
    
    def generate_auth_params(self) -> Dict[str, str]:
        """
        生成身份验证参数
        
        Returns:
            Dict[str, str]: 包含验证参数的字典
        """
        # 1. 生成 code_verifier (t) - 32字节随机数
        t = os.urandom(32)  # 等效于 JS 的 crypto.getRandomValues(new Uint8Array(32))
        
        # 2. 生成 s: 对 t 进行 Base64 URL 安全编码
        def tb(data):
            # Base64 URL 安全编码(替换 +/ 为 -_,去除末尾的 =)
            return base64.urlsafe_b64encode(data).decode().rstrip('=')
        
        s = tb(t)  # 对应 JS 的 this.tb(t)
        
        # 3. 生成 n: 对 s 进行 SHA-256 哈希 + Base64 URL 编码
        def ub(s_str):
            # 等效于 JS 的 TextEncoder().encode(s) + SHA-256
            return hashlib.sha256(s_str.encode()).digest()
        
        hashed = ub(s)
        n = tb(hashed)  # 对应 JS 的 this.tb(new Uint8Array(hashed))
        
        # 4. 生成 r: UUID v4
        r = str(uuid.uuid4())  # 对应 JS 的 $t()
        
        return {
            "t": t.hex(),      # 原始字节转十六进制字符串(方便查看)
            "s": s,
            "n": n,
            "r": r
        }
    
    def poll_for_login_result(self, uuid: str, challenge: str) -> Tuple[Optional[str], Optional[str], Optional[str]]:
        """
        轮询获取登录结果
        
        Args:
            uuid: 身份验证UUID
            challenge: 验证挑战码
            
        Returns:
            Tuple[Optional[str], Optional[str], Optional[str]]: (authId, accessToken, refreshToken)
        """
        poll_url = f"https://api2.cursor.sh/auth/poll?uuid={uuid}&verifier={challenge}"
        headers = {
            "Content-Type": "application/json"
        }
        max_attempts = 30
        attempt = 0
        
        while attempt < max_attempts:
            logging.info(get_translation("polling_login_result"))
            try:
                response = requests.get(poll_url, headers=headers)
                
                if response.status_code == 404:
                    logging.info(get_translation("login_not_completed"))
                elif response.status_code == 200:
                    data = response.json()
                    
                    if "authId" in data and "accessToken" in data and "refreshToken" in data:
                        logging.info(get_translation("login_successful"))
                        logging.debug(f"Auth ID: {data['authId']}")
                        logging.debug(f"Access Token: {data['accessToken'][:10]}...")
                        logging.debug(f"Refresh Token: {data['refreshToken'][:10]}...")
                        return data['authId'], data['accessToken'], data['refreshToken']
                
            except Exception as e:
                logging.error(f"Error during polling: {e}")
                
            attempt += 1
            time.sleep(2)  # 每 2 秒轮询一次
            
        if attempt >= max_attempts:
            logging.error(get_translation("polling_timed_out"))
            
        return None, None, None
    
    def get_cursor_session_token(self, tab=None, max_attempts=3, retry_interval=2) -> Tuple[Optional[str], Optional[str]]:
        """
        获取Cursor会话令牌
        
        Args:
            tab: 浏览器标签对象
            max_attempts: 最大尝试次数
            retry_interval: 重试间隔(秒)
            
        Returns:
            Tuple[Optional[str], Optional[str]]: (accessToken, refreshToken)
        """
        tab = tab or self.tab
        
        params = self.generate_auth_params()
        url = f"https://www.cursor.com/cn/loginDeepControl?challenge={params['n']}&uuid={params['r']}&mode=login"
        tab.get(url)
        
        attempts = 0
        
        while attempts < max_attempts:
            # 检查是否到达登录界面
            status = check_verification_success(tab, VerificationStatus.TOKEN_REFRESH)
            if status:
                break
                
            attempts += 1
            
            if attempts < max_attempts:
                time.sleep(retry_interval)
                
        time.sleep(2)
        
        # 使用精确的CSS选择器在Python中查找元素并点击
        tab.run_js("""
            try {
                const button = document.querySelectorAll(".min-h-screen")[1].querySelectorAll(".gap-4")[1].querySelectorAll("button")[1];
                if (button) {
                    button.click();
                    return true;
                } else {
                    return false;
                }
            } catch (e) {
                console.error("选择器错误:", e);
                return false;
            }
        """)
        
        _, access_token, refresh_token = self.poll_for_login_result(params["r"], params["s"])
        
        # 更新实例变量
        if access_token and refresh_token:
            self.access_token = access_token
            self.refresh_token = refresh_token
            
        return access_token, refresh_token
    
    def sign_up_account(self, browser=None, tab=None) -> bool:
        """
        注册新账号
        
        Args:
            browser: 浏览器实例
            tab: 浏览器标签对象
            
        Returns:
            bool: 是否成功注册
        """
        browser = browser or self.browser
        tab = tab or self.tab
        
        logging.info(get_translation("start_account_registration"))
        logging.info(get_translation("visiting_registration_page", url=SIGN_UP_URL))
        tab.get(SIGN_UP_URL)
        
        # 首次注册需要验证的
        if not tab.ele(VerificationStatus.SIGN_UP.value):
            self.handle_turnstile(tab)
            
        try:
            if tab.ele("@name=first_name"):
                logging.info(get_translation("filling_personal_info"))
                tab.actions.click("@name=first_name").input(self.first_name)
                logging.info(get_translation("input_first_name", name=self.first_name))
                time.sleep(random.uniform(1, 3))
                
                tab.actions.click("@name=last_name").input(self.last_name)
                logging.info(get_translation("input_last_name", name=self.last_name))
                time.sleep(random.uniform(1, 3))
                
                tab.actions.click("@name=email").input(self.account)
                logging.info(get_translation("input_email", email=self.account))
                time.sleep(random.uniform(1, 3))
                
                logging.info(get_translation("submitting_personal_info"))
                tab.actions.click("@type=submit")
                
        except Exception as e:
            logging.error(get_translation("registration_page_access_failed", error=str(e)))
            return False
            
        self.handle_turnstile(tab)
        
        try:
            if tab.ele("@name=password"):
                logging.info(get_translation("setting_password"))
                tab.ele("@name=password").input(self.password)
                time.sleep(random.uniform(1, 3))
                
                logging.info(get_translation("submitting_password"))
                tab.ele("@type=submit").click()
                logging.info(get_translation("password_setup_complete"))
                
        except Exception as e:
            logging.error(get_translation("password_setup_failed", error=str(e)))
            return False
            
        if tab.ele("This email is not available."):
            logging.error(get_translation("registration_failed_email_used"))
            return False
            
        self.handle_turnstile(tab)
        
        while True:
            try:
                if tab.ele("Account Settings"):
                    logging.info(get_translation("registration_success"))
                    break
                if tab.ele("@data-index=0"):
                    logging.info(get_translation("getting_email_verification"))
                    code = self.email_handler.get_verification_code()
                    if not code:
                        logging.error(get_translation("verification_code_failure"))
                        return False
                        
                    logging.info(get_translation("verification_code_success", code=code))
                    logging.info(get_translation("inputting_verification_code"))
                    i = 0
                    for digit in code:
                        tab.ele(f"@data-index={i}").input(digit)
                        time.sleep(random.uniform(0.1, 0.3))
                        i += 1
                    logging.info(get_translation("verification_code_input_complete"))
                    break
            except Exception as e:
                logging.error(get_translation("verification_code_process_error", error=str(e)))
                
        self.handle_turnstile(tab)
        wait_time = random.randint(3, 6)
        for i in range(wait_time):
            logging.info(get_translation("waiting_system_processing", seconds=wait_time-i))
            time.sleep(1)
            
        logging.info(get_translation("getting_account_info"))
        tab.get(SETTINGS_URL)
        try:
            usage_selector = (
                "css:div.col-span-2 > div > div > div > div > "
                "div:nth-child(1) > div.flex.items-center.justify-between.gap-2 > "
                "span.font-mono.text-sm\\/\\[0\\.875rem\\]"
            )
            usage_ele = tab.ele(usage_selector)
            if usage_ele:
                usage_info = usage_ele.text
                total_usage = usage_info.split("/")[-1].strip()
                logging.info(get_translation("account_usage_limit", limit=total_usage))
                logging.info(
                    "Please visit the open source project for more information: https://github.com/wangffei/wf-cursor-auto-free.git"
                )
        except Exception as e:
            logging.error(get_translation("account_usage_info_failure", error=str(e)))
            
        logging.info(get_translation("registration_complete"))
        account_info = get_translation("cursor_account_info", email=self.account, password=self.password)
        logging.info(account_info)
        time.sleep(5)
        return True

    def option_sign_up_only(self) -> bool:
        """选项3: 仅注册账号"""
        try:
            if not self.init_browser():
                return False
                
            self.generate_account()
            
            # 准备浏览器
            self.tab.run_js("try { turnstile.reset() } catch(e) { }")
            
            logging.info(get_translation("starting_registration"))
            logging.info(get_translation("visiting_login_page", url=LOGIN_URL))
            self.tab.get(LOGIN_URL)
            
            if self.sign_up_account():
                logging.info(get_translation("getting_session_token"))
                access_token, refresh_token = self.get_cursor_session_token()
                
                # 将账号密码写入一个json文件中
                if access_token and refresh_token:
                    if self.save_account_info():
                        logging.info(get_translation("account_info_saved"))
                        self.print_end_message()
                    else:
                        logging.error(get_translation("failed_to_save_account_info"))
                else:
                    logging.error(get_translation("session_token_failed"))
                    # 即使没有token,也保存账号和密码信息
                    self.save_account_info(access_token="", refresh_token="")
                return True
            return False
        except Exception as e:
            logging.error(f"Failed to sign up account: {str(e)}")
            return False
        finally:
            self.cleanup()
            
    def option_complete_registration(self) -> bool:
        """选项2: 完整注册流程"""
        try:
            ExitCursor()
            
            if not self.init_browser():
                return False
                
            self.generate_account()
            
            # 准备浏览器
            self.tab.run_js("try { turnstile.reset() } catch(e) { }")
            
            logging.info(get_translation("starting_registration"))
            logging.info(get_translation("visiting_login_page", url=LOGIN_URL))
            self.tab.get(LOGIN_URL)
            
            if self.sign_up_account():
                logging.info(get_translation("getting_session_token"))
                access_token, refresh_token = self.get_cursor_session_token()
                
                if access_token and refresh_token:
                    logging.info(get_translation("updating_auth_info"))
                    self.update_cursor_auth()
                    
                    logging.info(
                        "Please visit the open source project for more information: https://github.com/wangffei/wf-cursor-auto-free.git"
                    )
                    
                    self.reset_machine_id()
                    logging.info(get_translation("all_operations_completed"))
                    self.print_end_message()
                    
                    # 注册完成,启动cursor
                    self.start_cursor()
                    return True
                else:
                    logging.error(get_translation("session_token_failed"))
                    return False
            return False
        except Exception as e:
            logging.error(f"Failed to complete registration: {str(e)}")
            return False
        finally:
            self.cleanup()

def save_screenshot(tab, stage: str, timestamp: bool = True) -> None:
    """
    Save a screenshot of the page

    Args:
        tab: Browser tab object
        stage: Stage identifier for the screenshot
        timestamp: Whether to add a timestamp
    """
    try:
        # Create screenshots directory
        screenshot_dir = "screenshots"
        if not os.path.exists(screenshot_dir):
            os.makedirs(screenshot_dir)

        # Generate filename
        if timestamp:
            filename = f"turnstile_{stage}_{int(time.time())}.png"
        else:
            filename = f"turnstile_{stage}.png"

        filepath = os.path.join(screenshot_dir, filename)

        # Save screenshot
        tab.get_screenshot(filepath)
        logging.debug(f"Screenshot saved: {filepath}")
    except Exception as e:
        logging.warning(f"Failed to save screenshot: {str(e)}")

def check_verification_success(tab, default_status=None) -> Optional[VerificationStatus]:
    global index
    """
    Check if verification was successful

    Returns:
        VerificationStatus: The corresponding status if successful, None if failed
    """
    if default_status:
        if tab.ele(default_status.value):
            logging.info(get_translation("verification_success", status=default_status.name))
            return default_status
        else:
            return None
    for idx,status in enumerate(VerificationStatus):
        if(idx == 0 and index != 0):
            continue
        if tab.ele(status.value):
            index = index + 1
            logging.info(get_translation("verification_success", status=status.name))
            return status
    return None

def handle_turnstile(tab, max_retries: int = 2, retry_interval: tuple = (1, 2)) -> bool:
    """
    Handle Turnstile verification

    Args:
        tab: Browser tab object
        max_retries: Maximum number of retries
        retry_interval: Retry interval range (min, max)

    Returns:
        bool: Whether verification was successful

    Raises:
        TurnstileError: Exception during verification process
    """
    logging.info(get_translation("detecting_turnstile"))
    save_screenshot(tab, "start")

    retry_count = 0

    try:
        while retry_count < max_retries:
            retry_count += 1
            logging.debug(get_translation("retry_verification", count=retry_count))

            try:
                element = None
                try:
                    element = (
                        tab.ele(".main-content")  # 找到 .main-content 元素
                        .ele("tag:div")        # 找到第一个子 div
                        .ele("tag:div")        # 找到第二个子 div
                        .ele("tag:div")        # 找到第三个子 div
                    )
                except Exception as e:
                    pass
                if element:
                    # Locate verification frame element
                    challenge_check = (
                        element
                        .shadow_root.ele("tag:iframe")
                        .ele("tag:body")
                        .sr("tag:input")
                    )
                else:
                    # Locate verification frame element
                    challenge_check = (
                        tab.ele("@id=cf-turnstile", timeout=2)
                        .child()
                        .shadow_root.ele("tag:iframe")
                        .ele("tag:body")
                        .sr("tag:input")
                    )

                if challenge_check:
                    logging.info(get_translation("detected_turnstile"))
                    # Random delay before clicking verification
                    time.sleep(random.uniform(1, 3))
                    challenge_check.click()
                    time.sleep(2)

                    # Save screenshot after verification
                    save_screenshot(tab, "clicked")

                    # Check verification result
                    if check_verification_success(tab):
                        logging.info(get_translation("turnstile_verification_passed"))
                        save_screenshot(tab, "success")
                        return True

            except Exception as e:
                # exc_type, exc_value, exc_traceback = sys.exc_info()
                # traceback.print_tb(exc_traceback)
                logging.debug(f"Current attempt unsuccessful: {str(e)}")

            # Check if already verified
            if check_verification_success(tab):
                return True

            # Random delay before next attempt
            time.sleep(random.uniform(*retry_interval))

        # Exceeded maximum retries
        logging.error(get_translation("verification_failed_max_retries", max_retries=max_retries))
        logging.error(
            "Please visit the open source project for more information: https://github.com/wangffei/wf-cursor-auto-free.git"
        )
        save_screenshot(tab, "failed")
        return False

    except Exception as e:
        error_msg = get_translation("turnstile_exception", error=str(e))
        logging.error(error_msg)
        save_screenshot(tab, "error")
        raise TurnstileError(error_msg)


def get_cursor_session_token(tab, max_attempts=3, retry_interval=2):
    """
    Get Cursor session token with retry mechanism
    :param tab: Browser tab
    :param max_attempts: Maximum number of attempts
    :param retry_interval: Retry interval (seconds)
    :return: Session token or None
    """
    # logging.info(get_translation("getting_cookie"))
    # attempts = 0

    # while attempts < max_attempts:
    #     try:
    #         cookies = tab.cookies()
    #         for cookie in cookies:
    #             if cookie.get("name") == "WorkosCursorSessionToken":
    #                 return cookie["value"].split("%3A%3A")[1]

    #         attempts += 1
    #         if attempts < max_attempts:
    #             logging.warning(
    #                 get_translation("cookie_attempt_failed", attempts=attempts, retry_interval=retry_interval)
    #             )
    #             time.sleep(retry_interval)
    #         else:
    #             logging.error(
    #                 get_translation("cookie_max_attempts", max_attempts=max_attempts)
    #             )

    #     except Exception as e:
    #         logging.error(get_translation("cookie_failure", error=str(e)))
    #         attempts += 1
    #         if attempts < max_attempts:
    #             logging.info(get_translation("retry_in_seconds", seconds=retry_interval))
    #             time.sleep(retry_interval)


    params = generate_auth_params()
    url = "https://www.cursor.com/cn/loginDeepControl?challenge="+params["n"] +"&uuid="+params["r"]+"&mode=login"
    tab.get(url)

    attempts = 0

    while attempts < max_attempts:
        # 检查是否到达登录界面
        status = check_verification_success(tab, VerificationStatus.TOKEN_REFRESH)
        if status:
            break

        attempts += 1

        if attempts < max_attempts:
            time.sleep(retry_interval)

    time.sleep(2)

    # 使用精确的CSS选择器在Python中查找元素并点击
    tab.run_js("""
        try {
            const button = document.querySelectorAll(".min-h-screen")[1].querySelectorAll(".gap-4")[1].querySelectorAll("button")[1];
            if (button) {
                button.click();
                return true;
            } else {
                return false;
            }
        } catch (e) {
            console.error("选择器错误:", e);
            return false;
        }
    """)

    _,accessToken,refreshToken = poll_for_login_result(params["r"], params["s"])

    return accessToken,refreshToken


def update_cursor_auth(email=None, access_token=None, refresh_token=None):
    """
    Update Cursor authentication information
    """
    auth_manager = CursorAuthManager()
    return auth_manager.update_auth(email, access_token, refresh_token)

def generate_auth_params():
    # 1. 生成 code_verifier (t) - 32字节随机数
    t = os.urandom(32)  # 等效于 JS 的 crypto.getRandomValues(new Uint8Array(32))

    # 2. 生成 s: 对 t 进行 Base64 URL 安全编码
    def tb(data):
        # Base64 URL 安全编码(替换 +/ 为 -_,去除末尾的 =)
        return base64.urlsafe_b64encode(data).decode().rstrip('=')
    
    s = tb(t)  # 对应 JS 的 this.tb(t)

    # 3. 生成 n: 对 s 进行 SHA-256 哈希 + Base64 URL 编码
    def ub(s_str):
        # 等效于 JS 的 TextEncoder().encode(s) + SHA-256
        return hashlib.sha256(s_str.encode()).digest()
    
    hashed = ub(s)
    n = tb(hashed)  # 对应 JS 的 this.tb(new Uint8Array(hashed))

    # 4. 生成 r: UUID v4
    r = str(uuid.uuid4())  # 对应 JS 的 $t()

    return {
        "t": t.hex(),      # 原始字节转十六进制字符串(方便查看)
        "s": s,
        "n": n,
        "r": r
    }

def poll_for_login_result(uuid, challenge):
        """轮询获取登录结果"""
        poll_url = f"https://api2.cursor.sh/auth/poll?uuid={uuid}&verifier={challenge}"
        headers = {
            "Content-Type": "application/json"
        }
        max_attempts = 30
        attempt = 0

        while attempt < max_attempts:
            print("Polling for login result...")
            try:
                response = requests.get(poll_url, headers=headers)

                if response.status_code == 404:
                    print("Login not completed yet.")
                elif response.status_code == 200:
                    data = response.json()

                    if "authId" in data and "accessToken" in data and "refreshToken" in data:
                        print("Login successful!")
                        print(f"Auth ID: {data['authId']}")
                        print(f"Access Token: {data['accessToken']}")
                        print(f"Refresh Token: {data['refreshToken']}")
                        return data['authId'],data['accessToken'],data['refreshToken']

            except Exception as e:
                print(f"Error during polling: {e}")

            attempt += 1
            time.sleep(2)  # 每 2 秒轮询一次

        if attempt >= max_attempts:
            print("Polling timed out.")

        return None, None, None

def sign_up_account(browser, tab):
    logging.info(get_translation("start_account_registration"))
    logging.info(get_translation("visiting_registration_page", url=sign_up_url))
    tab.get(sign_up_url)

    # 首次注册需要验证的
    if not tab.ele(VerificationStatus.SIGN_UP.value):
        handle_turnstile(tab)

    try:
        if tab.ele("@name=first_name"):
            logging.info(get_translation("filling_personal_info"))
            tab.actions.click("@name=first_name").input(first_name)
            logging.info(get_translation("input_first_name", name=first_name))
            time.sleep(random.uniform(1, 3))

            tab.actions.click("@name=last_name").input(last_name)
            logging.info(get_translation("input_last_name", name=last_name))
            time.sleep(random.uniform(1, 3))

            tab.actions.click("@name=email").input(account)
            logging.info(get_translation("input_email", email=account))
            time.sleep(random.uniform(1, 3))

            logging.info(get_translation("submitting_personal_info"))
            tab.actions.click("@type=submit")

    except Exception as e:
        logging.error(get_translation("registration_page_access_failed", error=str(e)))
        return False

    handle_turnstile(tab)

    try:
        if tab.ele("@name=password"):
            logging.info(get_translation("setting_password"))
            tab.ele("@name=password").input(password)
            time.sleep(random.uniform(1, 3))

            logging.info(get_translation("submitting_password"))
            tab.ele("@type=submit").click()
            logging.info(get_translation("password_setup_complete"))

    except Exception as e:
        logging.error(get_translation("password_setup_failed", error=str(e)))
        return False

    if tab.ele("This email is not available."):
        logging.error(get_translation("registration_failed_email_used"))
        return False

    handle_turnstile(tab)

    while True:
        try:
            if tab.ele("Account Settings"):
                logging.info(get_translation("registration_success"))
                break
            if tab.ele("@data-index=0"):
                logging.info(get_translation("getting_email_verification"))
                code = email_handler.get_verification_code()
                if not code:
                    logging.error(get_translation("verification_code_failure"))
                    return False

                logging.info(get_translation("verification_code_success", code=code))
                logging.info(get_translation("inputting_verification_code"))
                i = 0
                for digit in code:
                    tab.ele(f"@data-index={i}").input(digit)
                    time.sleep(random.uniform(0.1, 0.3))
                    i += 1
                logging.info(get_translation("verification_code_input_complete"))
                break
        except Exception as e:
            logging.error(get_translation("verification_code_process_error", error=str(e)))

    handle_turnstile(tab)
    wait_time = random.randint(3, 6)
    for i in range(wait_time):
        logging.info(get_translation("waiting_system_processing", seconds=wait_time-i))
        time.sleep(1)

    logging.info(get_translation("getting_account_info"))
    tab.get(settings_url)
    try:
        usage_selector = (
            "css:div.col-span-2 > div > div > div > div > "
            "div:nth-child(1) > div.flex.items-center.justify-between.gap-2 > "
            "span.font-mono.text-sm\\/\\[0\\.875rem\\]"
        )
        usage_ele = tab.ele(usage_selector)
        if usage_ele:
            usage_info = usage_ele.text
            total_usage = usage_info.split("/")[-1].strip()
            logging.info(get_translation("account_usage_limit", limit=total_usage))
            logging.info(
                "Please visit the open source project for more information: https://github.com/wangffei/wf-cursor-auto-free.git"
            )
    except Exception as e:
        logging.error(get_translation("account_usage_info_failure", error=str(e)))

    logging.info(get_translation("registration_complete"))
    account_info = get_translation("cursor_account_info", email=account, password=password)
    logging.info(account_info)
    time.sleep(5)
    return True


class EmailGenerator:
    """邮箱生成器类"""
    
    def __init__(
        self,
        password="".join(
            random.choices(
                "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*",
                k=12,
            )
        ),
    ):
        """
        初始化邮箱生成器
        
        Args:
            password: 可选的默认密码
        """
        configInstance = Config()
        configInstance.print_config()
        self.domain = configInstance.get_domain()
        self.names = self.load_names()
        self.default_password = password
        self.default_first_name = self.generate_random_name()
        self.default_last_name = self.generate_random_name()

    def load_names(self) -> List[str]:
        """
        加载随机名称数据集
        
        Returns:
            List[str]: 名称列表
        """
        try:
            with open("names-dataset.txt", "r") as file:
                return file.read().split()
        except FileNotFoundError:
            logging.warning(get_translation("names_file_not_found"))
            # 如果找不到文件,使用默认名称集
            return ["John", "Jane", "Alex", "Emma", "Michael", "Olivia", "William", "Sophia", 
                    "James", "Isabella", "Robert", "Mia", "David", "Charlotte", "Joseph", "Amelia"]

    def generate_random_name(self) -> str:
        """
        生成随机用户名
        
        Returns:
            str: 随机名称
        """
        return random.choice(self.names)

    def generate_email(self, length=4) -> str:
        """
        生成随机邮箱地址
    
    Args:
            length: 时间戳位数
            
        Returns:
            str: 生成的邮箱地址
        """
        length = random.randint(0, length)  # 生成0到length之间的随机整数
        timestamp = str(int(time.time()))[-length:]  # 使用时间戳的最后length位
        return f"{self.default_first_name}{timestamp}@{self.domain}"
        
    def get_account_info(self) -> Dict[str, str]:
        """
        获取完整的账号信息
    
    Returns:
            Dict[str, str]: 账号信息字典
        """
        return {
            "email": self.generate_email(),
            "password": self.default_password,
            "first_name": self.default_first_name,
            "last_name": self.default_last_name,
        }


def main():
    """主函数入口"""
    print_logo()
    
    # 添加语言选择
    print("\n")
    # language.select_language_prompt()
    
    cursor_pro = CursorProKeepAlive()
    
    try:
        logging.info(get_translation("initializing_program"))

        # 提示用户选择操作模式
        print(get_translation("select_operation_mode"))
        print(get_translation("reset_machine_code_only"))
        print(get_translation("complete_registration"))
        print(get_translation("only_sign_up"))
        print(get_translation("disable_auto_update"))
        print(get_translation("select_saved_account"))

        while True:
            try:
                choice = int(input(get_translation("enter_option")).strip())
                if choice in [1, 2, 3, 4, 5]:
                    break
                else:
                    print(get_translation("invalid_option"))
            except ValueError:
                print(get_translation("enter_valid_number"))

        # 根据用户选择执行不同的操作
        if choice == 1:  # 仅重置机器码
            cursor_pro.option_reset_machine_id()
        elif choice == 2:  # 完整注册
            cursor_pro.option_complete_registration()
        elif choice == 3:  # 仅注册
            cursor_pro.option_sign_up_only()
        elif choice == 4:  # 禁用自动更新
            cursor_pro.option_disable_auto_update()
        elif choice == 5:  # 选择已保存的账号
            cursor_pro.option_apply_saved_account()
                
    except Exception as e:
        logging.error(get_translation("program_error", error=str(e)))
    finally:
        cursor_pro.cleanup()
        input(get_translation("program_exit_message"))


# 添加API接口函数,直接放在main()函数前面

def api_reset_machine_id():
    """API: 仅重置机器码"""
    cursor_pro = CursorProKeepAlive()
    return cursor_pro.option_reset_machine_id()
    
def api_complete_registration():
    """API: 完整注册流程"""
    cursor_pro = CursorProKeepAlive()
    return cursor_pro.option_complete_registration()
    
def api_sign_up_only():
    """API: 仅注册账号"""
    cursor_pro = CursorProKeepAlive()
    return cursor_pro.option_sign_up_only()
    
def api_disable_auto_update():
    """API: 禁用自动更新"""
    cursor_pro = CursorProKeepAlive()
    return cursor_pro.option_disable_auto_update()
    
def api_apply_saved_account(account_file_path=None):
    """
    API: 应用已保存的账号
    
    Args:
        account_file_path: 账号文件路径,如果为None则显示选择界面
        
    Returns:
        bool: 操作是否成功
    """
    cursor_pro = CursorProKeepAlive()
    if account_file_path:
        return cursor_pro.apply_account_from_file(account_file_path)
    else:
        return cursor_pro.option_apply_saved_account()
    
def api_get_account_info():
    """
    API: 生成账号信息但不进行注册
    
    Returns:
        Dict[str, str]: 包含账号信息的字典
    """
    email_generator = EmailGenerator()
    return email_generator.get_account_info()
    
def api_save_account_info(email, password, access_token="", refresh_token=""):
    """
    API: 保存账号信息到文件
    
    Args:
        email: 邮箱地址
        password: 密码
        access_token: 访问令牌
        refresh_token: 刷新令牌
        
    Returns:
        bool: 操作是否成功
    """
    cursor_pro = CursorProKeepAlive()
    return cursor_pro.save_account_info(email, password, access_token, refresh_token)
    
def api_update_cursor_auth(email, access_token, refresh_token):
    """
    API: 更新Cursor身份验证信息
    
    Args:
        email: 邮箱地址
        access_token: 访问令牌
        refresh_token: 刷新令牌
        
    Returns:
        bool: 操作是否成功
    """
    cursor_pro = CursorProKeepAlive()
    return cursor_pro.update_cursor_auth(email, access_token, refresh_token)

def api_start_cursor():
    """API: 启动Cursor"""
    cursor_pro = CursorProKeepAlive()
    cursor_pro.start_cursor()
    
# 现在其他Python程序可以直接导入并调用这些函数
# 例如: from cursor_pro_keep_alive import api_reset_machine_id

if __name__ == "__main__":
    main()


================================================
FILE: disable_auto_update.py
================================================
import os
import sys
import platform
import shutil
from colorama import Fore, Style, init
import subprocess
from utils import get_linux_cursor_path, get_default_driver_path, get_default_browser_path
import re
import tempfile
from language import get_translation

# Initialize colorama
init()

# Define emoji constants
EMOJI = {
    "PROCESS": "🔄",
    "SUCCESS": "✅",
    "ERROR": "❌",
    "INFO": "ℹ️",
    "FOLDER": "📁",
    "FILE": "📄",
    "STOP": "🛑",
    "CHECK": "✔️"
}

class AutoUpdateDisabler:
    def __init__(self, translator=None):
        self.translator = translator
        self.system = platform.system()
        
        # Get path from configuration file
        config = self._get_config()
        if config:
            if self.system == "Windows":
                self.updater_path = self._get_config_item(config, 'WindowsPaths', 'updater_path', os.path.join(os.getenv("LOCALAPPDATA", ""), "cursor-updater"))
                self.update_yml_path = self._get_config_item(config, 'WindowsPaths', 'update_yml_path', os.path.join(os.getenv("LOCALAPPDATA", ""), "Programs", "Cursor", "resources", "app", "update.yml"))
                self.product_json_path = self._get_config_item(config, 'WindowsPaths', 'product_json_path', os.path.join(os.getenv("LOCALAPPDATA", ""), "Programs", "Cursor", "resources", "app", "product.json"))
            elif self.system == "Darwin":
                self.updater_path = self._get_config_item(config, 'MacPaths', 'updater_path', os.path.expanduser("~/Library/Application Support/cursor-updater"))
                self.update_yml_path = self._get_config_item(config, 'MacPaths', 'update_yml_path', "/Applications/Cursor.app/Contents/Resources/app-update.yml")
                self.product_json_path = self._get_config_item(config, 'MacPaths', 'product_json_path', "/Applications/Cursor.app/Contents/Resources/app/product.json")
            elif self.system == "Linux":
                self.updater_path = self._get_config_item(config, 'LinuxPaths', 'updater_path', os.path.expanduser("~/.config/cursor-updater"))
                self.update_yml_path = self._get_config_item(config, 'LinuxPaths', 'update_yml_path', os.path.expanduser("~/.config/cursor/resources/app-update.yml"))
                self.product_json_path = self._get_config_item(config, 'LinuxPaths', 'product_json_path', os.path.expanduser("~/.config/cursor/resources/app/product.json"))
        else:
            # If configuration loading fails, use default paths
            self.updater_paths = {
                "Windows": os.path.join(os.getenv("LOCALAPPDATA", ""), "cursor-updater"),
                "Darwin": os.path.expanduser("~/Library/Application Support/cursor-updater"),
                "Linux": os.path.expanduser("~/.config/cursor-updater")
            }
            self.updater_path = self.updater_paths.get(self.system)
            
            self.update_yml_paths = {
                "Windows": os.path.join(os.getenv("LOCALAPPDATA", ""), "Programs", "Cursor", "resources", "app", "update.yml"),
                "Darwin": "/Applications/Cursor.app/Contents/Resources/app-update.yml",
                "Linux": os.path.expanduser("~/.config/cursor/resources/app-update.yml")
            }
            self.update_yml_path = self.update_yml_paths.get(self.system)

            self.product_json_paths = {
                "Windows": os.path.join(os.getenv("LOCALAPPDATA", ""), "Programs", "Cursor", "resources", "app", "product.json"),
                "Darwin": "/Applications/Cursor.app/Contents/Resources/app/product.json",
                "Linux": os.path.expanduser("~/.config/cursor/resources/app/product.json")
            }
            self.product_json_path = self.product_json_paths.get(self.system)

    def _get_config_item(self,config, key1, key2, default):
        if not config[key1]:
            return default
        if not config[key1][key2]:
            return default
        return config[key1][key2]
    
    def _get_config(self):
        # Default configuration
        default_config = {
            'Browser': {
                'default_browser': 'chrome',
                'chrome_path': get_default_browser_path('chrome'),
                'chrome_driver_path': get_default_driver_path('chrome'),
                'edge_path': get_default_browser_path('edge'),
                'edge_driver_path': get_default_driver_path('edge'),
                'firefox_path': get_default_browser_path('firefox'),
                'firefox_driver_path': get_default_driver_path('firefox'),
                'brave_path': get_default_browser_path('brave'),
                'brave_driver_path': get_default_driver_path('brave'),
                'opera_path': get_default_browser_path('opera'),
                'opera_driver_path': get_default_driver_path('opera'),
                'operagx_path': get_default_browser_path('operagx'),
                'operagx_driver_path': get_default_driver_path('chrome')  # Opera GX 使用 Chrome 驱动
            },
            'Turnstile': {
                'handle_turnstile_time': '2',
                'handle_turnstile_random_time': '1-3'
            },
            'Timing': {
                'min_random_time': '0.1',
                'max_random_time': '0.8',
                'page_load_wait': '0.1-0.8',
                'input_wait': '0.3-0.8',
                'submit_wait': '0.5-1.5',
                'verification_code_input': '0.1-0.3',
                'verification_success_wait': '2-3',
                'verification_retry_wait': '2-3',
                'email_check_initial_wait': '4-6',
                'email_refresh_wait': '2-4',
                'settings_page_load_wait': '1-2',
                'failed_retry_time': '0.5-1',
                'retry_interval': '8-12',
                'max_timeout': '160'
            },
            'Utils': {
                'enabled_update_check': 'True',
                'enabled_force_update': 'False',
                'enabled_account_info': 'True'
            },
            'OAuth': {
                'show_selection_alert': False,  # 默认不显示选择提示弹窗
                'timeout': 120,
                'max_attempts': 3
            },
            'Token': {
                'refresh_server': 'https://token.cursorpro.com.cn',
                'enable_refresh': True
            }
        }

        # Add system-specific path configuration
        if sys.platform == "win32":
            appdata = os.getenv("APPDATA")
            localappdata = os.getenv("LOCALAPPDATA", "")
            default_config['WindowsPaths'] = {
                'storage_path': os.path.join(appdata, "Cursor", "User", "globalStorage", "storage.json"),
                'sqlite_path': os.path.join(appdata, "Cursor", "User", "globalStorage", "state.vscdb"),
                'machine_id_path': os.path.join(appdata, "Cursor", "machineId"),
                'cursor_path': os.path.join(localappdata, "Programs", "Cursor", "resources", "app"),
                'updater_path': os.path.join(localappdata, "cursor-updater"),
                'update_yml_path': os.path.join(localappdata, "Programs", "Cursor", "resources", "app-update.yml"),
                'product_json_path': os.path.join(localappdata, "Programs", "Cursor", "resources", "app", "product.json")
            }
            # Create storage directory
            os.makedirs(os.path.dirname(default_config['WindowsPaths']['storage_path']), exist_ok=True)
            
        elif sys.platform == "darwin":
            default_config['MacPaths'] = {
                'storage_path': os.path.abspath(os.path.expanduser("~/Library/Application Support/Cursor/User/globalStorage/storage.json")),
                'sqlite_path': os.path.abspath(os.path.expanduser("~/Library/Application Support/Cursor/User/globalStorage/state.vscdb")),
                'machine_id_path': os.path.expanduser("~/Library/Application Support/Cursor/machineId"),
                'cursor_path': "/Applications/Cursor.app/Contents/Resources/app",
                'updater_path': os.path.expanduser("~/Library/Application Support/cursor-updater"),
                'update_yml_path': "/Applications/Cursor.app/Contents/Resources/app-update.yml",
                'product_json_path': "/Applications/Cursor.app/Contents/Resources/app/product.json"
            }
            # Create storage directory
            os.makedirs(os.path.dirname(default_config['MacPaths']['storage_path']), exist_ok=True)
            
        elif sys.platform == "linux":
            # Get the actual user's home directory, handling both sudo and normal cases
            sudo_user = os.environ.get('SUDO_USER')
            current_user = sudo_user if sudo_user else (os.getenv('USER') or os.getenv('USERNAME'))
            
            if not current_user:
                current_user = os.path.expanduser('~').split('/')[-1]
            
            # Handle sudo case
            if sudo_user:
                actual_home = f"/home/{sudo_user}"
                root_home = "/root"
            else:
                actual_home = f"/home/{current_user}"
                root_home = None
            
            if not os.path.exists(actual_home):
                actual_home = os.path.expanduser("~")
            
            # Define base config directory
            config_base = os.path.join(actual_home, ".config")
            
            # Try both "Cursor" and "cursor" directory names in both user and root locations
            cursor_dir = None
            possible_paths = [
                os.path.join(config_base, "Cursor"),
                os.path.join(config_base, "cursor"),
                os.path.join(root_home, ".config", "Cursor") if root_home else None,
                os.path.join(root_home, ".config", "cursor") if root_home else None
            ]
            
            for path in possible_paths:
                if path and os.path.exists(path):
                    cursor_dir = path
                    break
            
            if not cursor_dir:
                print(f"{Fore.YELLOW}{EMOJI['WARNING']} {get_translation('cursor_dir_not_found', dir=config_base)}{Style.RESET_ALL}")
                if root_home:
                    print(f"{Fore.YELLOW}{EMOJI['INFO']} {get_translation('also_checked_dir', dir=f'{root_home}/.config')}{Style.RESET_ALL}")
                print(f"{Fore.YELLOW}{EMOJI['INFO']} {get_translation('cursor_install_reminder')}{Style.RESET_ALL}")
            
            # Define Linux paths using the found cursor directory
            storage_path = os.path.abspath(os.path.join(cursor_dir, "User/globalStorage/storage.json")) if cursor_dir else ""
            storage_dir = os.path.dirname(storage_path) if storage_path else ""
            
            # Verify paths and permissions
            try:
                # Check storage directory
                if storage_dir and not os.path.exists(storage_dir):
                    print(f"{Fore.YELLOW}{EMOJI['WARNING']} {get_translation('storage_dir_not_found', dir=storage_dir)}{Style.RESET_ALL}")
                    print(f"{Fore.YELLOW}{EMOJI['INFO']} {get_translation('cursor_install_reminder')}{Style.RESET_ALL}")
                
                # Check storage.json with more detailed verification
                if storage_path and os.path.exists(storage_path):
                    # Get file stats
                    try:
                        stat = os.stat(storage_path)
                        print(f"{Fore.GREEN}{EMOJI['INFO']} {get_translation('storage_file_found', path=storage_path)}{Style.RESET_ALL}")
                        print(f"{Fore.GREEN}{EMOJI['INFO']} {get_translation('file_size', size=stat.st_size)}{Style.RESET_ALL}")
                        print(f"{Fore.GREEN}{EMOJI['INFO']} {get_translation('file_permissions', permissions=oct(stat.st_mode & 0o777))}{Style.RESET_ALL}")
                        print(f"{Fore.GREEN}{EMOJI['INFO']} {get_translation('file_owner', owner=stat.st_uid)}{Style.RESET_ALL}")
                        print(f"{Fore.GREEN}{EMOJI['INFO']} {get_translation('file_group', group=stat.st_gid)}{Style.RESET_ALL}")
                    except Exception as e:
                        print(f"{Fore.RED}{EMOJI['ERROR']} {get_translation('file_stats_error', error=str(e))}{Style.RESET_ALL}")
                    
                    # Check if file is readable and writable
                    if not os.access(storage_path, os.R_OK | os.W_OK):
                        print(f"{Fore.RED}{EMOJI['ERROR']} {get_translation('permission_denied', path=storage_path)}{Style.RESET_ALL}")
                        if sudo_user:
                            print(f"{Fore.YELLOW}{EMOJI['INFO']} {get_translation('try_chown', user=sudo_user, path=storage_path)}{Style.RESET_ALL}")
                            print(f"{Fore.YELLOW}{EMOJI['INFO']} {get_translation('try_chmod', path=storage_path)}{Style.RESET_ALL}")
                        else:
                            print(f"{Fore.YELLOW}{EMOJI['INFO']} {get_translation('try_chown', user=current_user, path=storage_path)}{Style.RESET_ALL}")
                            print(f"{Fore.YELLOW}{EMOJI['INFO']} {get_translation('try_chmod', path=storage_path)}{Style.RESET_ALL}")
                    
                    # Try to read the file to verify it's not corrupted
                    try:
                        with open(storage_path, 'r') as f:
                            content = f.read()
                            if not content.strip():
                                print(f"{Fore.YELLOW}{EMOJI['WARNING']} {get_translation('storage_file_empty', path=storage_path)}{Style.RESET_ALL}")
                                print(f"{Fore.YELLOW}{EMOJI['INFO']} {get_translation('file_corrupted')}{Style.RESET_ALL}")
                            else:
                                print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {get_translation('storage_file_valid')}{Style.RESET_ALL}")
                    except Exception as e:
                        print(f"{Fore.RED}{EMOJI['ERROR']} {get_translation('storage_file_read_error', error=str(e))}{Style.RESET_ALL}")
                        print(f"{Fore.YELLOW}{EMOJI['INFO']} {get_translation('file_corrupted_reinstall')}{Style.RESET_ALL}")
                elif storage_path:
                    print(f"{Fore.YELLOW}{EMOJI['WARNING']} {get_translation('storage_file_not_found', path=storage_path)}{Style.RESET_ALL}")
                    print(f"{Fore.YELLOW}{EMOJI['INFO']} {get_translation('cursor_install_reminder')}{Style.RESET_ALL}")
                
            except (OSError, IOError) as e:
                print(f"{Fore.RED}{EMOJI['ERROR']} {get_translation('linux_paths_error', error=str(e))}{Style.RESET_ALL}")
            
            # Define all paths using the found cursor directory
            default_config['LinuxPaths'] = {
                'storage_path': storage_path,
                'sqlite_path': os.path.abspath(os.path.join(cursor_dir, "User/globalStorage/state.vscdb")) if cursor_dir else "",
                'machine_id_path': os.path.join(cursor_dir, "machineid") if cursor_dir else "",
                'cursor_path': get_linux_cursor_path(),
                'updater_path': os.path.join(config_base, "cursor-updater"),
                'update_yml_path': os.path.join(cursor_dir, "resources/app-update.yml") if cursor_dir else "",
                'product_json_path': os.path.join(cursor_dir, "resources/app/product.json") if cursor_dir else ""
            }

        return default_config

    def _remove_update_url(self):
        """删除更新URL"""
        try:
            original_stat = os.stat(self.product_json_path)
            original_mode = original_stat.st_mode
            original_uid = original_stat.st_uid
            original_gid = original_stat.st_gid

            with tempfile.NamedTemporaryFile(mode="w", delete=False) as tmp_file:
                with open(self.product_json_path, "r", encoding="utf-8") as product_json_file:
                    content = product_json_file.read()
                
                patterns = {
                    r"https://api2.cursor.sh/aiserver.v1.AuthService/DownloadUpdate": r"",
                    r"https://api2.cursor.sh/updates": r"",
                    r"http://cursorapi.com/updates": r"",
                }
                
                for pattern, replacement in patterns.items():
                    content = re.sub(pattern, replacement, content)

                tmp_file.write(content)
                tmp_path = tmp_file.name

            shutil.copy2(self.product_json_path, self.product_json_path + ".old")
            shutil.move(tmp_path, self.product_json_path)

            os.chmod(self.product_json_path, original_mode)
            if os.name != "nt":
                os.chown(self.product_json_path, original_uid, original_gid)

            print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {get_translation('file_modified')}{Style.RESET_ALL}")
            return True

        except Exception as e:
            print(f"{Fore.RED}{EMOJI['ERROR']} {get_translation('file_modify_failed', error=str(e))}{Style.RESET_ALL}")
            if "tmp_path" in locals():
                os.unlink(tmp_path)
            return False

    def _kill_cursor_processes(self):
        """终止所有 Cursor 进程"""
        try:
            print(f"{Fore.CYAN}{EMOJI['PROCESS']} {get_translation('terminating_cursor_processes')}{Style.RESET_ALL}")
            
            if self.system == "Windows":
                subprocess.run(['taskkill', '/F', '/IM', 'Cursor.exe', '/T'], capture_output=True)
            else:
                subprocess.run(['pkill', '-f', 'Cursor'], capture_output=True)
                
            print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {get_translation('cursor_processes_terminated')}{Style.RESET_ALL}")
            return True
            
        except Exception as e:
            print(f"{Fore.RED}{EMOJI['ERROR']} {get_translation('process_termination_failed', error=str(e))}{Style.RESET_ALL}")
            return False

    def _remove_updater_directory(self):
        """删除更新程序目录"""
        try:
            updater_path = self.updater_path
            if not updater_path:
                raise OSError(get_translation('unsupported_os'))

            print(f"{Fore.CYAN}{EMOJI['FOLDER']} {get_translation('removing_updater_directory')}{Style.RESET_ALL}")
            
            if os.path.exists(updater_path):
                try:
                    if os.path.isdir(updater_path):
                        shutil.rmtree(updater_path)
                    else:
                        os.remove(updater_path)
                    print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {get_translation('updater_directory_removed')}{Style.RESET_ALL}")
                except PermissionError:
                    print(f"{Fore.YELLOW}{EMOJI['INFO']} {get_translation('updater_directory_locked', path=updater_path)}{Style.RESET_ALL}")
            return True
            
        except Exception as e:
            print(f"{Fore.RED}{EMOJI['ERROR']} {get_translation('directory_removal_failed', error=str(e))}{Style.RESET_ALL}")
            return True
    
    def _clear_update_yml_file(self):
        """清空更新配置文件"""
        try:
            update_yml_path = self.update_yml_path
            if not update_yml_path:
                raise OSError(get_translation('unsupported_os'))
            
            print(f"{Fore.CYAN}{EMOJI['FILE']} {get_translation('clearing_update_config')}{Style.RESET_ALL}")
            
            if os.path.exists(update_yml_path):
                try:
                    with open(update_yml_path, 'w') as f:
                        f.write('')
                    print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {get_translation('update_config_cleared')}{Style.RESET_ALL}")
                except PermissionError:
                    print(f"{Fore.YELLOW}{EMOJI['INFO']} {get_translation('update_config_locked')}{Style.RESET_ALL}")
            else:
                print(f"{Fore.YELLOW}{EMOJI['INFO']} {get_translation('update_config_not_exist')}{Style.RESET_ALL}")
            return True
                
        except Exception as e:
            print(f"{Fore.RED}{EMOJI['ERROR']} {get_translation('clear_config_failed', error=str(e))}{Style.RESET_ALL}")
            return False

    def _create_blocking_file(self):
        """创建阻止文件"""
        try:
            # 检查 updater_path
            updater_path = self.updater_path
            if not updater_path:
                raise OSError(get_translation('unsupported_os_with_name', system=self.system))

            print(f"{Fore.CYAN}{EMOJI['FILE']} {get_translation('creating_blocking_files')}{Style.RESET_ALL}")
            
            # 创建 updater_path 阻止文件
            try:
                os.makedirs(os.path.dirname(updater_path), exist_ok=True)
                open(updater_path, 'w').close()
                
                # 设置 updater_path 为只读
                if self.system == "Windows":
                    os.system(f'attrib +r "{updater_path}"')
                else:
                    os.chmod(updater_path, 0o444)  # 设置为只读
                
                print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {get_translation('blocking_file_created', path=updater_path)}{Style.RESET_ALL}")
            except PermissionError:
                print(f"{Fore.YELLOW}{EMOJI['INFO']} {get_translation('blocking_file_locked')}{Style.RESET_ALL}")
            
            # 检查 update_yml_path
            update_yml_path = self.update_yml_path
            if update_yml_path and os.path.exists(os.path.dirname(update_yml_path)):
                try:
                    # 创建 update_yml_path 阻止文件
                    with open(update_yml_path, 'w') as f:
                        f.write(get_translation('update_config_content'))
                    
                    # 设置 update_yml_path 为只读
                    if self.system == "Windows":
                        os.system(f'attrib +r "{update_yml_path}"')
                    else:
                        os.chmod(update_yml_path, 0o444)  # 设置为只读
                    
                    print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {get_translation('update_config_locked_success', path=update_yml_path)}{Style.RESET_ALL}")
                except PermissionError:
                    print(f"{Fore.YELLOW}{EMOJI['INFO']} {get_translation('update_config_already_locked')}{Style.RESET_ALL}")
            
            return True
            
        except Exception as e:
            print(f"{Fore.RED}{EMOJI['ERROR']} {get_translation('create_blocking_file_failed', error=str(e))}{Style.RESET_ALL}")
            return True  # 返回 True 以继续执行后续步骤

    def disable_auto_update(self):
        """禁用自动更新"""
        try:
            print(f"{Fore.CYAN}{EMOJI['INFO']} {get_translation('starting_disable_update')}{Style.RESET_ALL}")
            
            # 1. 终止进程
            if not self._kill_cursor_processes():
                return False
                
            # 2. 删除目录 - 即使失败也继续执行
            self._remove_updater_directory()
                
            # 3. 清空更新配置文件
            if not self._clear_update_yml_file():
                return False
                
            # 4. 创建阻止文件
            if not self._create_blocking_file():
                return False
                
            # 5. 从 product.json 移除更新 URL
            if not self._remove_update_url():
                return False
                
            print(f"{Fore.GREEN}{EMOJI['CHECK']} {get_translation('auto_update_disabled')}{Style.RESET_ALL}")
            return True
            
        except Exception as e:
            print(f"{Fore.RED}{EMOJI['ERROR']} {get_translation('disable_update_failed', error=str(e))}{Style.RESET_ALL}")
            return False

def run(translator=None):
    """方便直接调用禁用功能的函数"""
    print(f"\n{Fore.CYAN}{'='*50}{Style.RESET_ALL}")
    print(f"{Fore.CYAN}{EMOJI['STOP']} {get_translation('disable_cursor_auto_update_title')}{Style.RESET_ALL}")
    print(f"{Fore.CYAN}{'='*50}{Style.RESET_ALL}")

    disabler = AutoUpdateDisabler(translator)
    disabler.disable_auto_update()

    print(f"\n{Fore.CYAN}{'='*50}{Style.RESET_ALL}")
    input(f"{EMOJI['INFO']} {get_translation('press_enter_continue')}")

if __name__ == "__main__":
    run(None) 

================================================
FILE: example_usage.py
================================================
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

"""
示例程序:演示如何使用重构后的cursor_pro_keep_alive.py API接口
"""

import sys
import time
from cursor_pro_keep_alive import (
    api_reset_machine_id,
    api_complete_registration,
    api_sign_up_only,
    api_disable_auto_update,
    api_apply_saved_account,
    api_get_account_info,
    api_save_account_info,
    api_update_cursor_auth,
    api_start_cursor
)

def show_menu():
    """显示操作菜单"""
    print("\n===== Cursor Pro API 使用示例 =====")
    print("1. 仅重置机器码")
    print("2. 完整注册流程")
    print("3. 仅注册账号")
    print("4. 禁用自动更新")
    print("5. 选择并应用已保存的账号")
    print("6. 指定账号文件应用")
    print("7. 获取随机账号信息")
    print("8. 手动保存账号信息")
    print("9. 手动更新认证信息")
    print("0. 退出程序")
    print("==================================")

def main():
    """主函数"""
    while True:
        show_menu()
        try:
            choice = int(input("\n请输入选项: ").strip())
            
            if choice == 0:
                print("程序退出")
                break
                
            elif choice == 1:
                print("执行: 仅重置机器码")
                result = api_reset_machine_id()
                print(f"操作结果: {'成功' if result else '失败'}")
                
            elif choice == 2:
                print("执行: 完整注册流程")
                result = api_complete_registration()
                print(f"操作结果: {'成功' if result else '失败'}")
                
            elif choice == 3:
                print("执行: 仅注册账号")
                result = api_sign_up_only()
                print(f"操作结果: {'成功' if result else '失败'}")
                
            elif choice == 4:
                print("执行: 禁用自动更新")
                result = api_disable_auto_update()
                print(f"操作结果: {'成功' if result else '失败'}")
                
            elif choice == 5:
                print("执行: 选择并应用已保存的账号")
                result = api_apply_saved_account()
                print(f"操作结果: {'成功' if result else '失败'}")
                
            elif choice == 6:
                filepath = input("请输入账号文件路径: ").strip()
                print(f"执行: 应用指定账号文件 '{filepath}'")
                result = api_apply_saved_account(filepath)
                print(f"操作结果: {'成功' if result else '失败'}")
                
            elif choice == 7:
                print("执行: 获取随机账号信息")
                account_info = api_get_account_info()
                print("\n随机账号信息:")
                for key, value in account_info.items():
                    print(f"  {key}: {value}")
                    
            elif choice == 8:
                email = input("请输入邮箱: ").strip()
                password = input("请输入密码: ").strip()
                access_token = input("请输入访问令牌(可选): ").strip() or ""
                refresh_token = input("请输入刷新令牌(可选): ").strip() or ""
                
                print(f"执行: 手动保存账号信息 '{email}'")
                result = api_save_account_info(email, password, access_token, refresh_token)
                print(f"操作结果: {'成功' if result else '失败'}")
                
            elif choice == 9:
                email = input("请输入邮箱: ").strip()
                access_token = input("请输入访问令牌: ").strip()
                refresh_token = input("请输入刷新令牌: ").strip()
                
                print(f"执行: 手动更新认证信息 '{email}'")
                result = api_update_cursor_auth(email, access_token, refresh_token)
                print(f"操作结果: {'成功' if result else '失败'}")
                
            else:
                print("无效选项,请重新输入")
                
            # 操作后的间隔
            time.sleep(1)
                
        except ValueError:
            print("请输入有效的数字选项")
        except KeyboardInterrupt:
            print("\n程序被用户中断")
            break
        except Exception as e:
            print(f"操作出错: {str(e)}")

if __name__ == "__main__":
    main() 

================================================
FILE: exit_cursor.py
================================================
import psutil
from logger import logging  
import time

def ExitCursor(timeout=5):
    """
    温和地关闭 Cursor 进程
    
    Args:
        timeout (int): 等待进程自然终止的超时时间(秒)
    Returns:
        bool: 是否成功关闭所有进程
    """
    try:
        logging.info("开始退出Cursor...")
        cursor_processes = []
        # 收集所有 Cursor 进程
        for proc in psutil.process_iter(['pid', 'name']):
            try:
                if proc.info['name'].lower() in ['cursor.exe', 'cursor']:
                    cursor_processes.append(proc)
            except (psutil.NoSuchProcess, psutil.AccessDenied):
                continue

        if not cursor_processes:
            logging.info("未发现运行中的 Cursor 进程")
            return True

        # 温和地请求进程终止
        for proc in cursor_processes:
            try:
                if proc.is_running():
                    proc.terminate()  # 发送终止信号
            except (psutil.NoSuchProcess, psutil.AccessDenied):
                continue

        # 等待进程自然终止
        start_time = time.time()
        while time.time() - start_time < timeout:
            still_running = []
            for proc in cursor_processes:
                try:
                    if proc.is_running():
                        still_running.append(proc)
                except (psutil.NoSuchProcess, psutil.AccessDenied):
                    continue
            
            if not still_running:
                logging.info("所有 Cursor 进程已正常关闭")
                return True
                
            # 等待一小段时间再检查
            time.sleep(0.5)
            
        # 如果超时后仍有进程在运行
        if still_running:
            process_list = ", ".join([str(p.pid) for p in still_running])
            logging.warning(f"以下进程未能在规定时间内关闭: {process_list}")
            return False
            
        return True

    except Exception as e:
        logging.error(f"关闭 Cursor 进程时发生错误: {str(e)}")
        return False

if __name__ == "__main__":
    ExitCursor()


================================================
FILE: get_email_code.py
================================================
from datetime import datetime
import logging
import time
import re
from config import Config
import requests
import email
import imaplib
import poplib
from email.parser import Parser


class EmailVerificationHandler:
    def __init__(self,account):
        self.imap = Config().get_imap()
        self.username = Config().get_temp_mail()
        self.epin = Config().get_temp_mail_epin()
        self.session = requests.Session()
        self.emailExtension = Config().get_temp_mail_ext()
        # 获取协议类型,默认为 POP3
        self.protocol = Config().get_protocol() or 'POP3'
        self.account = account

    def get_verification_code(self, max_retries=5, retry_interval=60):
        """
        获取验证码,带有重试机制。

        Args:
            max_retries: 最大重试次数。
            retry_interval: 重试间隔时间(秒)。

        Returns:
            验证码 (字符串或 None)。
        """

        for attempt in range(max_retries):
            try:
                logging.info(f"尝试获取验证码 (第 {attempt + 1}/{max_retries} 次)...")

                if not self.imap:
                    verify_code, first_id = self._get_latest_mail_code()
                    if verify_code is not None and first_id is not None:
                        self._cleanup_mail(first_id)
                        return verify_code
                else:
                    if self.protocol.upper() == 'IMAP':
                        verify_code = self._get_mail_code_by_imap()
                    else:
                        verify_code = self._get_mail_code_by_pop3()
                    if verify_code is not None:
                        return verify_code

                if attempt < max_retries - 1:  # 除了最后一次尝试,都等待
                    logging.warning(f"未获取到验证码,{retry_interval} 秒后重试...")
                    time.sleep(retry_interval)

            except Exception as e:
                logging.error(f"获取验证码失败: {e}")  # 记录更一般的异常
                if attempt < max_retries - 1:
                    logging.error(f"发生错误,{retry_interval} 秒后重试...")
                    time.sleep(retry_interval)
                else:
                    raise Exception(f"获取验证码失败且已达最大重试次数: {e}") from e

        raise Exception(f"经过 {max_retries} 次尝试后仍未获取到验证码。")

    # 使用imap获取邮件
    def _get_mail_code_by_imap(self, retry = 0):
        if retry > 0:
            time.sleep(3)
        if retry >= 20:
            raise Exception("获取验证码超时")
        try:
            # 连接到IMAP服务器
            mail = imaplib.IMAP4_SSL(self.imap['imap_server'], self.imap['imap_port'])
            mail.login(self.imap['imap_user'], self.imap['imap_pass'])
            search_by_date=False
            # 针对网易系邮箱,imap登录后需要附带联系信息,且后续邮件搜索逻辑更改为获取当天的未读邮件
            if self.imap['imap_user'].endswith(('@163.com', '@126.com', '@yeah.net')):                
                imap_id = ("name", self.imap['imap_user'].split('@')[0], "contact", self.imap['imap_user'], "version", "1.0.0", "vendor", "imaplib")
                mail.xatom('ID', '("' + '" "'.join(imap_id) + '")')
                search_by_date=True
            mail.select(self.imap['imap_dir'])
            if search_by_date:
                date = datetime.now().strftime("%d-%b-%Y")
                status, messages = mail.search(None, f'ON {date} UNSEEN')
            else:
                status, messages = mail.search(None, 'TO', '"'+self.account+'"')
            if status != 'OK':
                return None

            mail_ids = messages[0].split()
            if not mail_ids:
                # 没有获取到,就在获取一次
                return self._get_mail_code_by_imap(retry=retry + 1)

            for mail_id in reversed(mail_ids):
                status, msg_data = mail.fetch(mail_id, '(RFC822)')
                if status != 'OK':
                    continue
                raw_email = msg_data[0][1]
                email_message = email.message_from_bytes(raw_email)

                # 如果是按日期搜索的邮件,需要进一步核对收件人地址是否对应
                if search_by_date and email_message['to'] !=self.account:
                    continue
                body = self._extract_imap_body(email_message)
                if body:
                    # 避免 6 位数字的域名被误识别成验证码
                    body = body.replace(self.account, '')
                    code_match = re.search(r"\b\d{6}\b", body)
                    if code_match:
                        code = code_match.group()
                        # 删除找到验证码的邮件
                        mail.store(mail_id, '+FLAGS', '\\Deleted')
                        mail.expunge()
                        mail.logout()
                        return code
            # print("未找到验证码")
            mail.logout()
            return None
        except Exception as e:
            print(f"发生错误: {e}")
            return None

    def _extract_imap_body(self, email_message):
        # 提取邮件正文
        if email_message.is_multipart():
            for part in email_message.walk():
                content_type = part.get_content_type()
                content_disposition = str(part.get("Content-Disposition"))
                if content_type == "text/plain" and "attachment" not in content_disposition:
                    charset = part.get_content_charset() or 'utf-8'
                    try:
                        body = part.get_payload(decode=True).decode(charset, errors='ignore')
                        return body
                    except Exception as e:
                        logging.error(f"解码邮件正文失败: {e}")
        else:
            content_type = email_message.get_content_type()
            if content_type == "text/plain":
                charset = email_message.get_content_charset() or 'utf-8'
                try:
                    body = email_message.get_payload(decode=True).decode(charset, errors='ignore')
                    return body
                except Exception as e:
                    logging.error(f"解码邮件正文失败: {e}")
        return ""

    # 使用 POP3 获取邮件
    def _get_mail_code_by_pop3(self, retry = 0):
        if retry > 0:
            time.sleep(3)
        if retry >= 20:
            raise Exception("获取验证码超时")
        
        pop3 = None
        try:
            # 连接到服务器
            pop3 = poplib.POP3_SSL(self.imap['imap_server'], int(self.imap['imap_port']))
            pop3.user(self.imap['imap_user'])
            pop3.pass_(self.imap['imap_pass'])
            
            # 获取最新的10封邮件
            num_messages = len(pop3.list()[1])
            for i in range(num_messages, max(1, num_messages-9), -1):
                response, lines, octets = pop3.retr(i)
                msg_content = b'\r\n'.join(lines).decode('utf-8')
                msg = Parser().parsestr(msg_content)
                
                # 检查发件人
                if 'no-reply@cursor.sh' in msg.get('From', ''):
                    # 提取邮件正文
                    body = self._extract_pop3_body(msg)
                    if body:
                        # 查找验证码
                        code_match = re.search(r"\b\d{6}\b", body)
                        if code_match:
                            code = code_match.group()
                            pop3.quit()
                            return code
            
            pop3.quit()
            return self._get_mail_code_by_pop3(retry=retry + 1)
            
        except Exception as e:
            print(f"发生错误: {e}")
            if pop3:
                try:
                    pop3.quit()
                except:
                    pass
            return None

    def _extract_pop3_body(self, email_message):
        # 提取邮件正文
        if email_message.is_multipart():
            for part in email_message.walk():
                content_type = part.get_content_type()
                content_disposition = str(part.get("Content-Disposition"))
                if content_type == "text/plain" and "attachment" not in content_disposition:
                    try:
                        body = part.get_payload(decode=True).decode('utf-8', errors='ignore')
                        return body
                    except Exception as e:
                        logging.error(f"解码邮件正文失败: {e}")
        else:
            try:
                body = email_message.get_payload(decode=True).decode('utf-8', errors='ignore')
                return body
            except Exception as e:
                logging.error(f"解码邮件正文失败: {e}")
        return ""

    # 手动输入验证码
    def _get_latest_mail_code(self):
        # 获取邮件列表
        mail_list_url = f"https://tempmail.plus/api/mails?email={self.username}{self.emailExtension}&limit=20&epin={self.epin}"
        mail_list_response = self.session.get(mail_list_url)
        mail_list_data = mail_list_response.json()
        time.sleep(0.5)
        if not mail_list_data.get("result"):
            return None, None

        # 获取最新邮件的ID
        first_id = mail_list_data.get("first_id")
        if not first_id:
            return None, None

        # 获取具体邮件内容
        mail_detail_url = f"https://tempmail.plus/api/mails/{first_id}?email={self.username}{self.emailExtension}&epin={self.epin}"
        mail_detail_response = self.session.get(mail_detail_url)
        mail_detail_data = mail_detail_response.json()
        time.sleep(0.5)
        if not mail_detail_data.get("result"):
            return None, None

        # 从邮件文本中提取6位数字验证码
        mail_text = mail_detail_data.get("text", "")
        mail_subject = mail_detail_data.get("subject", "")
        logging.info(f"找到邮件主题: {mail_subject}")
        # 修改正则表达式,确保 6 位数字不紧跟在字母或域名相关符号后面
        code_match = re.search(r"(?<![a-zA-Z@.])\b\d{6}\b", mail_text)

        if code_match:
            return code_match.group(), first_id
        return None, None

    def _cleanup_mail(self, first_id):
        # 构造删除请求的URL和数据
        delete_url = "https://tempmail.plus/api/mails/"
        payload = {
            "email": f"{self.username}{self.emailExtension}",
            "first_id": first_id,
            "epin": f"{self.epin}",
        }

        # 最多尝试5次
        for _ in range(5):
            response = self.session.delete(delete_url, data=payload)
            try:
                result = response.json().get("result")
                if result is True:
                    return True
            except:
                pass

            # 如果失败,等待0.5秒后重试
            time.sleep(0.5)

        return False


if __name__ == "__main__":
    email_handler = EmailVerificationHandler()
    code = email_handler.get_verification_code()
    print(code)


================================================
FILE: go_cursor_help.py
================================================
import platform
import os
import subprocess
from logger import logging
from language import get_translation

def go_cursor_help():
    system = platform.system()
    logging.info(get_translation("current_operating_system", system=system))
    
    base_url = "https://aizaozao.com/accelerate.php/https://raw.githubusercontent.com/yuaotian/go-cursor-help/refs/heads/master/scripts/run"
    
    if system == "Darwin":  # macOS
        cmd = f'curl -k -fsSL {base_url}/cursor_mac_id_modifier.sh | sudo bash'
        logging.info(get_translation("executing_macos_command"))
        os.system(cmd)
    elif system == "Linux":
        cmd = f'curl -fsSL {base_url}/cursor_linux_id_modifier.sh | sudo bash'
        logging.info(get_translation("executing_linux_command"))
        os.system(cmd)
    elif system == "Windows":
        cmd = f'irm {base_url}/cursor_win_id_modifier.ps1 | iex'
        logging.info(get_translation("executing_windows_command"))
        # Use PowerShell to execute command on Windows
        subprocess.run(["powershell", "-Command", cmd], shell=True)
    else:
        logging.error(get_translation("unsupported_operating_system", system=system))
        return False
    
    return True

def main():
    go_cursor_help()

if __name__ == "__main__":
    main()

================================================
FILE: gui/about_tab.py
================================================
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

"""
关于标签页 - 显示应用程序信息和版权声明
"""

from PyQt5.QtWidgets import (
    QWidget, QVBoxLayout, QHBoxLayout, QLabel, QPushButton, 
    QGroupBox, QTextBrowser, QSpacerItem, QSizePolicy
)
from PyQt5.QtCore import Qt, QSize
from PyQt5.QtGui import QFont, QPixmap, QIcon

class AboutTab(QWidget):
    """关于标签页类"""
    
    def __init__(self, parent=None):
        """初始化关于标签页"""
        super().__init__(parent)
        self.parent = parent
        self.init_ui()
    
    def init_ui(self):
        """初始化用户界面"""
        # 创建主布局
        main_layout = QVBoxLayout()
        main_layout.setContentsMargins(20, 20, 20, 20)
        main_layout.setSpacing(15)
        
        # 添加标题和Logo
        title_layout = QHBoxLayout()
        
        # Logo部分
        try:
            logo_label = QLabel()
            logo_pixmap = QPixmap("icons/cursor.png")
            if not logo_pixmap.isNull():
                logo_label.setPixmap(logo_pixmap.scaled(64, 64, Qt.KeepAspectRatio, Qt.SmoothTransformation))
                title_layout.addWidget(logo_label, 0, Qt.AlignRight)
        except:
            pass  # 没有logo图片不报错,继续执行
        
        # 标题部分
        title_label = QLabel(self.tr("Cursor Pro"))
        title_font = QFont()
        title_font.setPointSize(24)
        title_font.setBold(True)
        title_label.setFont(title_font)
        title_layout.addWidget(title_label, 1, Qt.AlignCenter)
        
        main_layout.addLayout(title_layout)
        
        # 版本信息
        version_label = QLabel(self.tr("版本: 1.0.4"))
        version_label.setAlignment(Qt.AlignCenter)
        main_layout.addWidget(version_label)
        
        # 应用描述
        desc_group = QGroupBox(self.tr("应用程序描述"))
        desc_layout = QVBoxLayout()
        
        description = QTextBrowser()
        description.setOpenExternalLinks(True)
        description.setHtml(self.tr("""
        <p><strong>Cursor Pro</strong> 是一款专为Cursor用户设计的工具,提供了多种实用功能:</p>
        <ul>
            <li>重置机器码 - 解决授权过期问题</li>
            <li>账号注册 - 自动注册Cursor账号</li>
            <li>账号管理 - 管理已保存的账号信息</li>
            <li>环境配置 - 管理.env环境变量文件</li>
        </ul>
        <p>本工具旨在简化Cursor用户的日常使用体验,提高工作效率。</p>
        """))
        description.setMinimumHeight(150)
        desc_layout.addWidget(description)
        
        desc_group.setLayout(desc_layout)
        main_layout.addWidget(desc_group)
        
        # 作者信息
        author_group = QGroupBox(self.tr("作者信息"))
        author_layout = QVBoxLayout()
        
        author_info = QTextBrowser()
        author_info.setOpenExternalLinks(True)
        author_info.setHtml(self.tr("""
        <p><strong>开发者:</strong> WangFFei</p>
        <p><strong>微信联系方式:</strong> wf-5569</p>
        <p><strong>QQ交流群:</strong> 996321868</p>
        <p><strong>项目GitHub地址:</strong> <a href="https://github.com/wangffei/wf-cursor-auto-free">https://github.com/wangffei/wf-cursor-auto-free</a></p>
        """))
        
        author_layout.addWidget(author_info)
        author_group.setLayout(author_layout)
        main_layout.addWidget(author_group)
        
        # 版权信息
        copyright_group = QGroupBox(self.tr("版权和许可"))
        copyright_layout = QVBoxLayout()
        
        copyright_info = QTextBrowser()
        copyright_info.setOpenExternalLinks(True)
        copyright_info.setHtml(self.tr("""
        <p>版权所有 © 2023-2024 WF Cursor Pro Team</p>
        <p>本软件按"原样"提供,不提供任何形式的明示或暗示担保。</p>
        <p>使用本软件的风险由用户自行承担。</p>
        """))
        
        copyright_layout.addWidget(copyright_info)
        copyright_group.setLayout(copyright_layout)
        main_layout.addWidget(copyright_group)
        
        # 添加弹性空间
        main_layout.addItem(QSpacerItem(20, 20, QSizePolicy.Minimum, QSizePolicy.Expanding))
        
        # 设置主布局
        self.setLayout(main_layout)
    
    def retranslate_ui(self):
        """更新UI文本翻译"""
        try:
            # 标题部分
            for i in range(self.layout().count()):
                item = self.layout().itemAt(i)
                if isinstance(item.layout(), QHBoxLayout):
                    for j in range(item.layout().count()):
                        widget = item.layout().itemAt(j).widget()
                        if isinstance(widget, QLabel) and widget.font().pointSize() > 20:
                            widget.setText(self.tr("Cursor Pro"))
                            break
                    break
            
            # 版本信息
            for i in range(self.layout().count()):
                item = self.layout().itemAt(i)
                if isinstance(item.widget(), QLabel) and "版本" in item.widget().text():
                    item.widget().setText(self.tr("版本: 1.0.4"))
                    break
            
            # 应用描述组
            for i in range(self.layout().count()):
                item = self.layout().itemAt(i)
                if isinstance(item.widget(), QGroupBox) and "描述" in item.widget().title():
                    item.widget().setTitle(self.tr("应用程序描述"))
                    # 更新描述文本
                    desc_layout = item.widget().layout()
                    if desc_layout and desc_layout.count() > 0:
                        browser = desc_layout.itemAt(0).widget()
                        if isinstance(browser, QTextBrowser):
                            browser.setHtml(self.tr("""
                            <p><strong>Cursor Pro</strong> 是一款专为Cursor用户设计的工具,提供了多种实用功能:</p>
                            <ul>
                                <li>重置机器码 - 解决授权过期问题</li>
                                <li>账号注册 - 自动注册Cursor账号</li>
                                <li>账号管理 - 管理已保存的账号信息</li>
                                <li>环境配置 - 管理.env环境变量文件</li>
                            </ul>
                            <p>本工具旨在简化Cursor用户的日常使用体验,提高工作效率。</p>
                            """))
                    break
            
            # 作者信息组
            for i in range(self.layout().count()):
                item = self.layout().itemAt(i)
                if isinstance(item.widget(), QGroupBox) and "作者" in item.widget().title():
                    item.widget().setTitle(self.tr("作者信息"))
                    # 更新作者信息文本
                    author_layout = item.widget().layout()
                    if author_layout and author_layout.count() > 0:
                        browser = author_layout.itemAt(0).widget()
                        if isinstance(browser, QTextBrowser):
                            browser.setHtml(self.tr("""
                            <p><strong>开发者:</strong> WangFFei</p>
                            <p><strong>微信联系方式:</strong> wf-5569</p>
                            <p><strong>QQ交流群:</strong> 996321868</p>
                            <p><strong>项目GitHub地址:</strong> <a href="https://github.com/wangffei/wf-cursor-auto-free">https://github.com/wangffei/wf-cursor-auto-free</a></p>
                            """))
                    break
            
            # 版权信息组
            for i in range(self.layout().count()):
                item = self.layout().itemAt(i)
                if isinstance(item.widget(), QGroupBox) and "版权" in item.widget().title():
                    item.widget().setTitle(self.tr("版权和许可"))
                    # 更新版权信息文本
                    copyright_layout = item.widget().layout()
                    if copyright_layout and copyright_layout.count() > 0:
                        browser = copyright_layout.itemAt(0).widget()
                        if isinstance(browser, QTextBrowser):
                            browser.setHtml(self.tr("""
                            <p>版权所有 © 2023-2024 WF Cursor Pro Team</p>
                            <p>本软件按"原样"提供,不提供任何形式的明示或暗示担保。</p>
                            <p>使用本软件的风险由用户自行承担。</p>
                            """))
                    break
                    
        except Exception as e:
            print(f"About标签页翻译UI时出错: {str(e)}") 

================================================
FILE: gui/account_tab.py
================================================
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

"""
账号管理标签页 - 提供账号管理功能
"""

from PyQt5.QtWidgets import (
    QWidget, QVBoxLayout, QHBoxLayout, QLabel, QPushButton, 
    QGroupBox, QTextEdit, QProgressBar, QMessageBox, QListWidget,
    QFormLayout, QLineEdit, QFileDialog, QSplitter, QListWidgetItem,
    QApplication, QSizePolicy
)
from PyQt5.QtCore import Qt, QThread, pyqtSignal
from PyQt5.QtGui import QFont, QIcon

import threading
import time
import traceback
import os
import json
import logging

# 导入日志查看器组件
from gui.log_viewer import LogViewer

# 导入Cursor Pro API
from cursor_pro_keep_alive import (
    api_apply_saved_account, 
    api_update_cursor_auth, 
    api_save_account_info, 
    api_get_account_info
)

class WorkerThread(QThread):
    """工作线程类,用于执行耗时操作"""
    
    # 信号定义
    progress_signal = pyqtSignal(int)  # 进度更新信号
    finished_signal = pyqtSignal(bool, str)  # 完成信号,带结果和消息
    
    def __init__(self, task, args=None, kwargs=None, parent=None):
        """
        初始化工作线程
        
        Args:
            task: 要执行的任务函数
            args: 位置参数
            kwargs: 关键字参数
            parent: 父对象
        """
        super().__init__(parent)
        self.task = task
        self.args = args or []
        self.kwargs = kwargs or {}
        self.running = True
    
    def run(self):
        """线程运行方法"""
        try:
            # 更新进度条
            self.progress_signal.emit(10)
            time.sleep(0.5)
            
            # 执行任务
            logging.info(self.tr("正在执行任务..."))
            self.progress_signal.emit(30)
            
            # 调用API
            result = self.task(*self.args, **self.kwargs)
            
            self.progress_signal.emit(80)
            time.sleep(0.5)
            
            # 发送结果
            if result:
                logging.info(self.tr("操作成功!"))
                self.finished_signal.emit(True, self.tr("操作成功!"))
            else:
                logging.error(self.tr("操作失败!"))
                self.finished_signal.emit(False, self.tr("操作失败!"))
                
            self.progress_signal.emit(100)
            
        except Exception as e:
            # 处理异常
            error_msg = str(e)
            trace = traceback.format_exc()
            logging.error(f"{self.tr('发生错误')}: {error_msg}\n{trace}")
            self.finished_signal.emit(False, f"{self.tr('发生错误')}: {error_msg}")
            self.progress_signal.emit(100)

class AccountTab(QWidget):
    """账号管理标签页类"""
    
    def __init__(self, parent=None):
        """初始化账号管理标签页"""
        super().__init__(parent)
        self.parent = parent
        self.worker_thread = None
        self.init_ui()
        
        # 初始加载账号列表
        self.load_account_list()
    
    def init_ui(self):
        """初始化用户界面"""
        # 创建主布局
        main_layout = QVBoxLayout()
        main_layout.setContentsMargins(15, 15, 15, 15)
        main_layout.setSpacing(12)  # 合理的间距
        
        # 添加说明文本
        info_label = QLabel(self.tr("管理已保存的Cursor账号,查看账号信息并应用到Cursor。"))
        info_label.setWordWrap(True)
        info_label.setMinimumHeight(40)
        info_label.setStyleSheet("QLabel { line-height: 150%; font-size: 10pt; }")
        main_layout.addWidget(info_label)
        
        # 创建内容区域
        content_container = QWidget()
        content_layout = QVBoxLayout(content_container)
        content_layout.setContentsMargins(0, 5, 0, 0)
        content_layout.setSpacing(15)
        
        # 创建水平分割器
        splitter = QSplitter(Qt.Horizontal)
        splitter.setHandleWidth(6)  # 分割器手柄宽度
        splitter.setStyleSheet("""
            QSplitter::handle {
                background-color: #E0E0E0;
                border-radius: 2px;
                margin: 1px 1px;
            }
            QSplitter::handle:hover {
                background-color: #BDBDBD;
            }
            QSplitter::handle:pressed {
                background-color: #9E9E9E;
            }
        """)
        
        # 左侧:账号列表
        account_group = QGroupBox(self.tr("已保存账号"))
        account_layout = QVBoxLayout()
        account_layout.setContentsMargins(12, 15, 12, 12)
        account_layout.setSpacing(10)
        
        self.account_list = QListWidget()
        self.account_list.setMinimumWidth(280)
        self.account_list.setAlternatingRowColors(True)
        self.account_list.currentItemChanged.connect(self.on_account_selected)
        # 设置列表样式
        self.account_list.setStyleSheet("""
            QListWidget {
                border: 1px solid #E0E0E0;
                border-radius: 4px;
                background-color: #FFFFFF;
                font-size: 10pt;
                padding: 5px;
            }
            QListWidget::item {
                border-bottom: 1px solid #F0F0F0;
                padding: 5px;
                margin: 2px 0;
                min-height: 20px;
            }
            QListWidget::item:selected {
                background-color: #E3F2FD;
                color: #000000;
                border-left: 3px solid #2196F3;
            }
            QListWidget::item:hover {
                background-color: #F5F5F5;
            }
        """)
        self.account_list.setMinimumHeight(200)
        account_layout.addWidget(self.account_list)
        
        # 账号列表下方的按钮
        list_buttons_layout = QHBoxLayout()
        list_buttons_layout.setSpacing(8)
        
        # 帮助按钮
        self.help_button = QPushButton(self.tr("操作指南"))
        self.help_button.setFixedHeight(32)
        self.help_button.clicked.connect(self.show_help)
        
        self.refresh_button = QPushButton(QIcon("icons/refresh.png"), self.tr("刷新"))
        self.refresh_button.setProperty("secondary", True)
        self.refresh_button.clicked.connect(self.load_account_list)
        self.refresh_button.setFixedHeight(32)
        
        self.apply_button = QPushButton(QIcon("icons/apply.png"), self.tr("应用账号"))
        self.apply_button.clicked.connect(self.apply_account)
        self.apply_button.setFixedHeight(32)
        # 设置主按钮样式
        self.apply_button.setStyleSheet("""
            QPushButton {
                background-color: #4CAF50;
                color: white;
                font-weight: bold;
                border-radius: 4px;
                padding: 5px 10px;
                font-size: 10pt;
            }
            QPushButton:hover {
                background-color: #43A047;
            }
            QPushButton:pressed {
                background-color: #388E3C;
            }
        """)
        
        self.delete_button = QPushButton(QIcon("icons/delete.png"), self.tr("删除"))
        self.delete_button.setProperty("secondary", True)
        self.delete_button.clicked.connect(self.delete_account)
        self.delete_button.setFixedHeight(32)
        # 设置次要按钮样式
        button_style = """
            QPushButton {
                background-color: #F5F5F5;
                border: 1px solid #E0E0E0;
                color: #424242;
                border-radius: 4px;
                padding: 5px 10px;
                font-size: 10pt;
            }
            QPushButton:hover {
                background-color: #EEEEEE;
                border-color: #BDBDBD;
            }
            QPushButton:pressed {
                background-color: #E0E0E0;
            }
        """
        self.help_button.setStyleSheet(button_style)
        self.refresh_button.setStyleSheet(button_style)
        self.delete_button.setStyleSheet(button_style)
        
        list_buttons_layout.addWidget(self.help_button)
        list_buttons_layout.addWidget(self.refresh_button)
        list_buttons_layout.addStretch()
        list_buttons_layout.addWidget(self.delete_button)
        list_buttons_layout.addWidget(self.apply_button)
        
        account_layout.addLayout(list_buttons_layout)
        account_group.setLayout(account_layout)
        
        # 右侧:账号详情
        details_group = QGroupBox(self.tr("账号详情"))
        details_layout = QVBoxLayout()
        details_layout.setContentsMargins(12, 15, 12, 12)
        
        # 使用只读的文本编辑区域显示账号详情
        self.details_text = QTextEdit()
        self.details_text.setReadOnly(True)
        self.details_text.setMinimumHeight(200)
        details_layout.addWidget(self.details_text)
        
        details_group.setLayout(details_layout)
        
        # 添加部件到分割器
        splitter.addWidget(account_group)
        splitter.addWidget(details_group)
        
        # 设置分割比例 (40% - 60%)
        splitter.setSizes([380, 420])
        
        content_layout.addWidget(splitter, 2)
        
        # 底部工具区域
        bottom_container = QWidget()
        bottom_layout = QVBoxLayout(bottom_container)
        bottom_layout.setContentsMargins(0, 0, 0, 0)
        bottom_layout.setSpacing(10)
        
        # 日志查看器
        log_group = QGroupBox(self.tr("操作日志"))
        log_layout = QVBoxLayout()
        log_layout.setContentsMargins(12, 15, 12, 12)
        
        # 使用LogViewer组件
        self.log_viewer = LogViewer(min_height=220)
        log_layout.addWidget(self.log_viewer)
        
        log_group.setLayout(log_layout)
        log_group.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        
        # 进度条
        self.progress_bar = QProgressBar()
        self.progress_bar.setRange(0, 100)
        self.progress_bar.setValue(0)
        self.progress_bar.setFixedHeight(20)
        # 设置进度条样式
        self.progress_bar.setStyleSheet("""
            QProgressBar {
                border: 1px solid #E0E0E0;
                border-radius: 4px;
                text-align: center;
                background-color: #F5F5F5;
                font-size: 10pt;
            }
            QProgressBar::chunk {
                background-color: #4CAF50;
                border-radius: 3px;
            }
        """)
        
        bottom_layout.addWidget(log_group, 1)
        bottom_layout.addWidget(self.progress_bar)
        
        # 将区域添加到主布局
        content_layout.addWidget(bottom_container, 1)
        
        # 设置内容区域的大小策略
        content_container.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        main_layout.addWidget(content_container, 1)
        
        # 设置整体最小尺寸
        self.setMinimumSize(800, 600)
        
        # 设置主布局
        self.setLayout(main_layout)
        
        # 记录页面加载完成
        logging.info(self.tr("账号管理页面已加载"))
    
    def load_account_list(self):
        """加载账号列表"""
        self.account_list.clear()
        
        # 检查accounts目录
        accounts_dir = "accounts"
        if not os.path.exists(accounts_dir):
            os.makedirs(accounts_dir)
            logging.info(self.tr("创建账号目录"))
        
        # 获取所有JSON文件
        account_files = [f for f in os.listdir(accounts_dir) if f.endswith('.json')]
        if not account_files:
            logging.warning(self.tr("未找到保存的账号文件"))
            return
        
        # 排序按创建时间(文件名中包含的时间戳)
        account_files.sort(reverse=True)
        
        # 添加到列表
        for filename in account_files:
            try:
                filepath = os.path.join(accounts_dir, filename)
                with open(filepath, 'r', encoding='utf-8') as f:
                    account_data = json.load(f)
                    email = account_data.get('email', '未知')
                    created_time = account_data.get('created_time', self.tr("未知时间"))
                    
                    # 将文件路径存储在用户数据中
                    display_text = f"{email} ({created_time})"
                    item = QListWidgetItem(display_text)
                    
                    # 设置图标并调整项目外观
                    item.setIcon(QIcon("icons/account.png"))
                    # 可选:设置提示文本
                    item.setToolTip(f"{self.tr('文件')}: {filename}\n{self.tr('邮箱')}: {email}\n{self.tr('时间')}: {created_time}")
                    
                    item.setData(Qt.UserRole, filepath)
                    self.account_list.addItem(item)
            except Exception as e:
                logging.error(f"{self.tr('读取账号文件失败')}: {filename} - {str(e)}")
        
        logging.info(self.tr("账号列表已刷新"))
    
    def on_account_selected(self, current, previous):
        """账号选择改变事件"""
        if not current:
            return
        
        # 获取文件路径
        filepath = current.data(Qt.UserRole)
        if not filepath or not os.path.exists(filepath):
            return
        
        try:
            # 读取账号数据
            with open(filepath, 'r', encoding='utf-8') as f:
                account_data = json.load(f)
            
            # 更新详情显示
            self.display_account_details(account_data)
            
            logging.info(self.tr("已加载账号详情"))
        except Exception as e:
            logging.error(f"{self.tr('读取账号详情失败')}: {str(e)}")
    
    def display_account_details(self, account_data):
        """显示账号详细信息"""
        email = account_data.get('email', self.tr('未知'))
        password = account_data.get('password', self.tr('未设置'))
        created_time = account_data.get('created_time', self.tr('未知'))
        access_token = account_data.get('access_token', '')
        refresh_token = account_data.get('refresh_token', '')
        
        # 构建格式化的HTML显示,使用更现代的卡片样式和垂直布局
        html = f"""
        <style>
            body {{
                font-family: 'Microsoft YaHei', 'Segoe UI', Arial, sans-serif;
                background-color: white;
                margin: 0;
                padding: 0;
            }}
            .card {{
                border-radius: 8px;
                background-color: #f8f9fa;
                padding: 15px;
                margin-bottom: 15px;
                border-left: 4px solid #1a73e8;
                box-shadow: 0 2px 5px rgba(0,0,0,0.05);
            }}
            .card-title {{
                color: #1a73e8;
                font-size: 16px;
                font-weight: bold;
                margin-top: 0;
                margin-bottom: 12px;
                border-bottom: 1px solid #e0e0e0;
                padding-bottom: 8px;
            }}
            .field {{
                margin-bottom: 12px;
            }}
            .field-name {{
                font-weight: bold;
                color: #555;
                margin-bottom: 4px;
            }}
            .field-value {{
                background-color: #ffffff;
                padding: 6px 10px;
                border-radius: 4px;
                border: 1px solid #e0e0e0;
            }}
            .token {{
                color: #707070;
                font-family: monospace;
                font-size: 12px;
                background-color: #f1f3f4;
                padding: 8px;
                border-radius: 4px;
                word-break: break-all;
                border: 1px solid #e0e0e0;
                max-height: 100px;
                overflow-y: auto;
            }}
            .timestamp {{
                color: #0d47a1;
                font-weight: bold;
            }}
        </style>
        
        <div class="card">
            <h3 class="card-title">{self.tr('基本信息')}</h3>
            
            <div class="field">
                <div class="field-name">{self.tr('电子邮箱')}</div>
                <div class="field-value">{email}</div>
            </div>
            
            <div class="field">
                <div class="field-name">{self.tr('密码')}</div>
                <div class="field-value">{password}</div>
            </div>
            
            <div class="field">
                <div class="field-name">{self.tr('创建时间')}</div>
                <div class="field-value timestamp">{created_time}</div>
            </div>
        </div>
        
        <div class="card">
            <h3 class="card-title">{self.tr('授权令牌')}</h3>
            
            <div class="field">
                <div class="field-name">{self.tr('访问令牌')}</div>
                <div class="token">{access_token if access_token else self.tr('未设置')}</div>
            </div>
            
            <div class="field">
                <div class="field-name">{self.tr('刷新令牌')}</div>
                <div class="token">{refresh_token if refresh_token else self.tr('未设置')}</div>
            </div>
        </div>
        """
        
        self.details_text.setHtml(html)
    
    def apply_account(self):
        """应用选中的账号"""
        # 获取当前选中的账号
        current_item = self.account_list.currentItem()
        if not current_item:
            QMessageBox.warning(
                self,
                self.tr("警告"),
                self.tr("请先选择一个账号")
            )
            return
        
        # 获取文件路径
        filepath = current_item.data(Qt.UserRole)
        if not filepath or not os.path.exists(filepath):
            QMessageBox.warning(
                self,
                self.tr("警告"),
                self.tr("账号文件路径无效")
            )
            return
        
        # 执行应用操作
        self.run_task(
            api_apply_saved_account,
            [filepath],
            {},
            self.tr("正在应用账号...")
        )
    
    def delete_account(self):
        """删除选中的账号"""
        # 获取当前选中的账号
        current_item = self.account_list.currentItem()
        if not current_item:
            QMessageBox.warning(
                self,
                self.tr("警告"),
                self.tr("请先选择一个账号")
            )
            return
        
        # 获取文件路径
        filepath = current_item.data(Qt.UserRole)
        if not filepath or not os.path.exists(filepath):
            QMessageBox.warning(
                self,
                self.tr("警告"),
                self.tr("账号文件路径无效")
            )
            return
        
        # 执行删除操作
        try:
            os.remove(filepath)
            logging.info(self.tr("已删除账号文件"))
            
            # 刷新列表
            self.load_account_list()
        except Exception as e:
            logging.error(f"{self.tr('删除账号文件失败')}: {str(e)}")
            QMessageBox.critical(
                self,
                self.tr("错误"),
                self.tr("删除账号文件失败") + f": {str(e)}"
            )
    
    def run_task(self, task_func, args, kwargs, start_message):
        """运行任务"""
        # 已经有线程在运行
        if self.worker_thread and self.worker_thread.isRunning():
            QMessageBox.warning(
                self,
                self.tr("警告"),
                self.tr("操作正在进行中,请等待完成")
            )
            return
        
        # 记录开始消息
        logging.info(start_message)
        
        # 创建并启动工作线程
        self.worker_thread = WorkerThread(task_func, args, kwargs)
        self.worker_thread.progress_signal.connect(self.update_progress)
        self.worker_thread.finished_signal.connect(self.on_task_finished)
        self.worker_thread.start()
    
    def log(self, message, level="info"):
        """
        兼容旧的日志接口,现在使用logging模块记录日志
        
        Args:
            message: 日志消息
            level: 日志级别,可选值:info, success, warning, error
        """
        # 日志级别映射
        level_map = {
            "info": logging.INFO,
            "success": logging.INFO,
            "warning": logging.WARNING,
            "error": logging.ERROR
        }
        
        # 获取对应的日志级别
        log_level = level_map.get(level, logging.INFO)
        
        # 记录日志
        logging.log(log_level, message)
    
    def update_progress(self, value):
        """更新进度条"""
        self.progress_bar.setValue(value)
    
    def on_task_finished(self, success, message):
        """任务完成处理"""
        # 显示结果消息
        if success:
            # 记录成功日志
            logging.info(message)
            
            QMessageBox.information(
                self,
                self.tr("操作成功"),
                message
            )
            # 刷新账号列表
            self.load_account_list()
        else:
            # 记录错误日志
            logging.error(message)
            
            QMessageBox.critical(
                self,
                self.tr("操作失败"),
                message
            )
    
    def retranslate_ui(self):
        """更新界面翻译"""
        try:
            # 获取主布局
            main_layout = self.layout()
            if not main_layout or main_layout.count() == 0:
                logging.warning("主布局为空或没有控件")
                return
            
            # 更新描述文本
            info_label = main_layout.itemAt(0).widget()
            if info_label:
                info_label.setText(self.tr("管理已保存的Cursor账号,查看账号信息并应用到Cursor。"))
            
            # 获取内容容器
            if main_layout.count() > 1:
                content_container = main_layout.itemAt(1).widget()
                if not content_container:
                    logging.warning("内容容器不存在")
                    return
                
                content_layout = content_container.layout()
                if not content_layout or content_layout.count() == 0:
                    logging.warning("内容布局为空或没有控件")
                    return
                
                # 获取分割器
                splitter = content_layout.itemAt(0).widget()
                if splitter and splitter.count() >= 2:
                    # 更新左侧和右侧组件标题
                    account_group = splitter.widget(0)
                    details_group = splitter.widget(1)
                    
                    if account_group:
                        account_group.setTitle(self.tr("已保存账号"))
                        
                        # 更新账号列表下方的按钮
                        account_layout = account_group.layout()
                        if account_layout and account_layout.count() > 1:
                            buttons_layout = account_layout.itemAt(1).layout()
                            if buttons_layout and buttons_layout.count() >= 5:
                                help_button = buttons_layout.itemAt(0).widget()
                                refresh_button = buttons_layout.itemAt(1).widget()
                                delete_button = buttons_layout.itemAt(3).widget()
                                apply_button = buttons_layout.itemAt(4).widget()
                                
                                if help_button:
                                    help_button.setText(self.tr("操作指南"))
                                    self.help_button = help_button
                                    
                                if refresh_button:
                                    refresh_button.setText(self.tr("刷新"))
                                    self.refresh_button = refresh_button
                                    
                                if delete_button:
                                    delete_button.setText(self.tr("删除"))
                                    self.delete_button = delete_button
                                    
                                if apply_button:
                                    apply_button.setText(self.tr("应用账号"))
                                    self.apply_button = apply_button
                    
                    if details_group:
                        details_group.setTitle(self.tr("账号详情"))
                
                # 获取底部容器
                if content_layout.count() > 1:
                    bottom_container = content_layout.itemAt(1).widget()
                    if bottom_container:
                        bottom_layout = bottom_container.layout()
                        if bottom_layout and bottom_layout.count() > 0:
                            # 更新日志组标题
                            log_group = bottom_layout.itemAt(0).widget()
                            if log_group:
                                log_group.setTitle(self.tr("操作日志"))
                                
                                # 更新日志查看器
                                log_layout = log_group.layout()
                                if log_layout and log_layout.count() > 0:
                                    log_viewer = log_layout.itemAt(0).widget()
                                    if log_viewer:
                                        self.log_viewer = log_viewer
                                        self.log_viewer.retranslate_ui()
            
            # 如果当前选中了账号,刷新详情视图
            if self.account_list and self.account_list.currentItem():
                self.on_account_selected(self.account_list.currentItem(), None)
                
        except Exception as e:
            # 使用日志记录错误,而不是打印
            logging.error(f"重新翻译UI时出错: {str(e)}")
            # 追加异常堆栈信息以便调试
            logging.debug(f"异常详情: {traceback.format_exc()}")
    
    def show_help(self):
        """显示帮助信息"""
        help_text = self.tr(
            '<h3>账号管理操作指南</h3>'
            '<p><b>查看账号:</b></p>'
            '<ol>'
            '<li>在左侧列表中选择要查看的账号</li>'
            '<li>账号详情会显示在右侧面板中</li>'
            '</ol>'
            '<p><b>应用账号:</b></p>'
            '<ol>'
            '<li>在左侧列表中选择要应用的账号</li>'
            '<li>点击"应用账号"按钮</li>'
            '<li>确认操作后等待完成</li>'
            '</ol>'
            '<p><b>删除账号:</b></p>'
            '<ol>'
            '<li>在左侧列表中选择要删除的账号</li>'
            '<li>点击"删除账号"按钮</li>'
            '<li>确认删除操作</li>'
            '</ol>'
            '<p><b>刷新账号列表:</b></p>'
            '<ul>'
            '<li>点击"刷新"按钮更新账号列表</li>'
            '</ul>'
        )
        
        QMessageBox.information(
            self,
            self.tr("操作指南"),
            help_text
        ) 

================================================
FILE: gui/env_tab.py
================================================
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

"""
环境配置标签页 - 提供.env文件操作和环境变量管理功能
"""

import os
import re
from datetime import datetime
from PyQt5.QtWidgets import (
    QWidget, QVBoxLayout, QHBoxLayout, QLabel, QPushButton,
    QTableWidget, QTableWidgetItem, QHeaderView, QFileDialog,
    QMessageBox, QLineEdit, QGroupBox, QSplitter, QTextEdit,
    QDialog, QFormLayout, QDialogButtonBox
)
from PyQt5.QtCore import Qt, pyqtSignal, QSize
from PyQt5.QtGui import QIcon, QColor

class EnvVariableDialog(QDialog):
    """环境变量编辑对话框"""
    
    def __init__(self, parent=None, key="", value=""):
        """初始化对话框"""
        super().__init__(parent)
        self.setWindowTitle(self.tr("编辑环境变量"))
        self.resize(400, 150)
        
        # 创建表单布局
        form_layout = QFormLayout(self)
        
        # 创建控件
        self.key_edit = QLineEdit(key)
        self.value_edit = QLineEdit(value)
        
        # 添加表单项
        form_layout.addRow(self.tr("变量名:"), self.key_edit)
        form_layout.addRow(self.tr("变量值:"), self.value_edit)
        
        # 创建按钮
        self.button_box = QDialogButtonBox(
            QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
        self.button_box.accepted.connect(self.accept)
        self.button_box.rejected.connect(self.reject)
        
        # 添加按钮到布局
        form_layout.addRow(self.button_box)
    
    def get_data(self):
        """返回用户输入的数据"""
        return self.key_edit.text(), self.value_edit.text()

class EnvTab(QWidget):
    """环境配置标签页"""
    
    # 定义信号
    log_message = pyqtSignal(str)
    env_changed = pyqtSignal()
    
    def __init__(self, parent=None):
        """初始化标签页"""
        super().__init__(parent)
        self.current_file = None
        self.env_data = {}
        self.modified = False
        
        # 初始化UI
        self.init_ui()
        
        # 尝试自动加载.env文件
        self.try_load_default_env()
    
    def init_ui(self):
        """初始化用户界面"""
        # 创建主布局
        main_layout = QVBoxLayout(self)
        main_layout.setContentsMargins(10, 10, 10, 10)
        
        # 创建分割器
        splitter = QSplitter(Qt.Vertical)
        
        # === 上部分: 文件操作区和表格区 ===
        top_widget = QWidget()
        top_layout = QVBoxLayout(top_widget)
        top_layout.setContentsMargins(0, 0, 0, 0)
        
        # 文件操作区
        file_group = QGroupBox(self.tr("文件操作"))
        file_layout = QHBoxLayout(file_group)
        
        # 文件路径显示
        self.file_path_label = QLabel(self.tr("当前文件: 未选择"))
        file_layout.addWidget(self.file_path_label, 1)
        
        # 文件操作按钮
        self.open_button = QPushButton(self.tr("打开"))
        self.open_button.clicked.connect(self.open_env_file)
        file_layout.addWidget(self.open_button)
        
        self.save_button = QPushButton(self.tr("保存"))
        self.save_button.clicked.connect(self.save_env_file)
        file_layout.addWidget(self.save_button)
        
        self.save_as_button = QPushButton(self.tr("另存为"))
        self.save_as_button.clicked.connect(self.save_env_as)
        file_layout.addWidget(self.save_as_button)
        
        self.new_button = QPushButton(self.tr("新建"))
        self.new_button.clicked.connect(self.new_env_file)
        file_layout.addWidget(self.new_button)
        
        # 将文件组添加到顶部布局
        top_layout.addWidget(file_group)
        
        # 表格操作区
        env_group = QGroupBox(self.tr("环境变量"))
        env_layout = QVBoxLayout(env_group)
        
        # 创建表格
        self.env_table = QTableWidget(0, 2)
        self.env_table.setHorizontalHeaderLabels([self.tr("变量名"), self.tr("变量值")])
        self.env_table.horizontalHeader().setSectionResizeMode(0, QHeaderView.Stretch)
        self.env_table.horizontalHeader().setSectionResizeMode(1, QHeaderView.Stretch)
        self.env_table.verticalHeader().setVisible(False)
        self.env_table.setAlternatingRowColors(True)
        self.env_table.itemChanged.connect(self.on_table_item_changed)
        
        # 添加表格到布局
        env_layout.addWidget(self.env_table)
        
        # 表格操作按钮
        buttons_layout = QHBoxLayout()
        
        self.add_button = QPushButton(self.tr("添加"))
        self.add_button.clicked.connect(self.add_env_variable)
        buttons_layout.addWidget(self.add_button)
        
        self.edit_button = QPushButton(self.tr("编辑"))
        self.edit_button.clicked.connect(self.edit_env_variable)
        buttons_layout.addWidget(self.edit_button)
        
        self.delete_button = QPushButton(self.tr("删除"))
        self.delete_button.clicked.connect(self.delete_env_variable)
        buttons_layout.addWidget(self.delete_button)
        
        self.reload_button = QPushButton(self.tr("重新加载"))
        self.reload_button.clicked.connect(self.reload_env_file)
        buttons_layout.addWidget(self.reload_button)
        
        # 添加按钮布局到环境变量组
        env_layout.addLayout(buttons_layout)
        
        # 添加环境变量组到顶部布局
        top_layout.addWidget(env_group)
        
        # === 下部分: 日志区 ===
        bottom_widget = QWidget()
        bottom_layout = QVBoxLayout(bottom_widget)
        bottom_layout.setContentsMargins(0, 0, 0, 0)
        
        # 日志组
        log_group = QGroupBox(self.tr("操作日志"))
        log_layout = QVBoxLayout(log_group)
        
        # 日志文本区域
        self.log_text = QTextEdit()
        self.log_text.setReadOnly(True)
        log_layout.addWidget(self.log_text)
        
        # 清除日志按钮
        self.clear_log_button = QPushButton(self.tr("清除日志"))
        self.clear_log_button.clicked.connect(self.clear_log)
        log_layout.addWidget(self.clear_log_button)
        
        # 添加日志组到底部布局
        bottom_layout.addWidget(log_group)
        
        # 添加部件到分割器
        splitter.addWidget(top_widget)
        splitter.addWidget(bottom_widget)
        splitter.setSizes([600, 200])  # 设置初始大小比例
        
        # 添加分割器到主布局
        main_layout.addWidget(splitter)
        
        # 连接自身信号
        self.log_message.connect(self.add_log)
    
    def retranslate_ui(self):
        """更新UI文本翻译"""
        # 文件操作组
        self.file_path_label.setText(self.tr("当前文件: ") + (self.current_file if self.current_file else self.tr("未选择")))
        self.open_button.setText(self.tr("打开"))
        self.save_button.setText(self.tr("保存"))
        self.save_as_button.setText(self.tr("另存为"))
        self.new_button.setText(self.tr("新建"))
        
        # 环境变量操作
        self.env_table.setHorizontalHeaderLabels([self.tr("变量名"), self.tr("变量值")])
        self.add_button.setText(self.tr("添加"))
        self.edit_button.setText(self.tr("编辑"))
        self.delete_button.setText(self.tr("删除"))
        self.reload_button.setText(self.tr("重新加载"))
        
        # 日志操作
        self.clear_log_button.setText(self.tr("清除日志"))
    
    def try_load_default_env(self):
        """尝试加载默认的.env文件,如果不存在则创建"""
        default_env = ".env"
        if os.path.exists(default_env):
            self.load_env_file(default_env)
            self.log_message.emit(self.tr(f"自动加载默认配置文件: {default_env}"))
        else:
            # 创建默认的.env文件
            self.log_message.emit(self.tr(f"默认配置文件不存在,正在创建: {default_env}"))
            self.current_file = default_env
            self.env_data = {
                "CURSOR_PRO_VERSION": "1.0.4",
                "DEBUG_MODE": "false",
                "LOG_LEVEL": "info"
            }
            self.save_env_data_to_file(default_env)
            self.update_env_table()
            self.file_path_label.setText(self.tr("当前文件: ") + default_env)
            self.modified = False
    
    def load_env_file(self, file_path):
        """加载环境变量文件"""
        if not os.path.exists(file_path):
            QMessageBox.warning(self, self.tr("错误"), self.tr(f"文件不存在: {file_path}"))
            return False
        
        try:
            self.env_data = {}
            
            with open(file_path, 'r', encoding='utf-8') as f:
                lines = f.readlines()
                
                for line in lines:
                    line = line.strip()
                    # 跳过空行和注释行
                    if not line or line.startswith('#'):
                        continue
                    
                    # 解析环境变量
                    match = re.match(r'^([^=]+)=(.*)$', line)
                    if match:
                        key = match.group(1).strip()
                        value = match.group(2).strip()
                        
                        # 去除值周围的引号
                        if (value.startswith('"') and value.endswith('"')) or \
                           (value.startswith("'") and value.endswith("'")):
                            value = value[1:-1]
                        
                        self.env_data[key] = value
            
            # 更新UI
            self.current_file = file_path
            self.file_path_label.setText(self.tr("当前文件: ") + file_path)
            self.update_env_table()
            self.modified = False
            
            self.log_message.emit(self.tr(f"已加载文件: {file_path}"))
            return True
            
        except Exception as e:
            QMessageBox.critical(self, self.tr("错误"), self.tr(f"加载文件失败: {str(e)}"))
            self.log_message.emit(self.tr(f"加载文件失败: {str(e)}"))
            return False
    
    def update_env_table(self):
        """更新环境变量表格"""
        # 断开信号连接,避免在填充表格时触发修改信号
        self.env_table.blockSignals(True)
        
        # 清空表格
        self.env_table.setRowCount(0)
        
        # 填充表格
        for i, (key, value) in enumerate(self.env_data.items()):
            self.env_table.insertRow(i)
            
            key_item = QTableWidgetItem(key)
            value_item = QTableWidgetItem(value)
            
            self.env_table.setItem(i, 0, key_item)
            self.env_table.setItem(i, 1, value_item)
        
        # 恢复信号连接
        self.env_table.blockSignals(False)
    
    def save_env_file(self):
        """保存环境变量文件"""
        if not self.current_file:
            return self.save_env_as()
        
        # 强制重新保存文件
        success = self.save_env_data_to_file(self.current_file)
        
        # 验证保存结果
        if success:
            self.log_message.emit(self.tr(f"成功保存到文件: {self.current_file}"))
            # 显示保存成功的对话框
            QMessageBox.information(self, self.tr("保存成功"), 
                self.tr(f"环境变量已成功保存到 {self.current_file}"))
        else:
            self.log_message.emit(self.tr(f"保存失败,请检查文件权限: {self.current_file}"))
        
        return success
    
    def save_env_data_to_file(self, file_path):
        """保存环境变量数据到文件"""
        try:
            # 确保目标文件所在目录存在
            directory = os.path.dirname(file_path)
            if directory and not os.path.exists(directory):
                os.makedirs(directory)
                self.log_message.emit(self.tr(f"创建目录: {directory}"))
            
            # 使用绝对路径处理文件
            abs_file_path = os.path.abspath(file_path)
            self.log_message.emit(self.tr(f"正在保存到文件: {abs_file_path}"))
            
            # 备份原文件(如果存在)
            if os.path.exists(abs_file_path):
                backup_file = f"{abs_file_path}.bak"
                try:
                    import shutil
                    shutil.copy2(abs_file_path, backup_file)
                    self.log_message.emit(self.tr(f"创建备份文件: {backup_file}"))
                except Exception as e:
                    self.log_message.emit(self.tr(f"创建备份文件失败: {str(e)}"))
            
            # 直接写入目标文件
            with open(abs_file_path, 'w', encoding='utf-8') as f:
                f.write("# 环境变量配置文件\n")
                f.write(f"# 生成时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n\n")
                
                for key, value in self.env_data.items():
                    # 如果值包含空格等特殊字符,则用引号包围
                    if ' ' in value or '\t' in value or '\n' in value or '"' in value or "'" in value:
                        # 优先使用双引号
                        if '"' not in value:
                            value = f'"{value}"'
                        else:
                            value = f"'{value}'"
                    
                    f.write(f"{key}={value}\n")
            
            # 验证文件是否确实被保存
            if not os.path.exists(abs_file_path):
                raise FileNotFoundError(f"无法创建文件: {abs_file_path}")
            
            # 尝试读取文件内容以验证写入是否成功
            with open(abs_file_path, 'r', encoding='utf-8') as f:
                content = f.read()
                if not content:
                    raise IOError(f"文件内容为空,可能写入失败: {abs_file_path}")
            
            # 设置当前文件
            self.current_file = file_path
            self.file_path_label.setText(self.tr("当前文件: ") + file_path)
            self.modified = False
            
            self.log_message.emit(self.tr(f"成功保存文件: {abs_file_path}"))
            self.env_changed.emit()  # 发送环境变量已改变信号
            return True
            
        except Exception as e:
            error_msg = str(e)
            self.log_message.emit(self.tr(f"保存文件失败: {error_msg}"))
            QMessageBox.critical(self, self.tr("错误"), self.tr(f"保存文件失败: {error_msg}"))
            import traceback
            traceback_info = traceback.format_exc()
            self.log_message.emit(f"异常详情: {traceback_info}")
            return False
    
    def check_save_changes(self):
        """检查是否需要保存更改"""
        if not self.modified:
            return True
        
        reply = QMessageBox.question(
            self, 
            self.tr("保存更改"),
            self.tr("当前文件已修改,是否保存更改?"),
            QMessageBox.Save | QMessageBox.Discard | QMessageBox.Cancel
        )
        
        if reply == QMessageBox.Save:
            return self.save_env_file()
        elif reply == QMessageBox.Cancel:
            return False
        
        return True  # 选择不保存
    
    # === 槽函数 ===
    
    def open_env_file(self):
        """打开环境变量文件"""
        if not self.check_save_changes():
            return
        
        options = QFileDialog.Options()
        file_path, _ = QFileDialog.getOpenFileName(
            self,
            self.tr("打开环境变量文件"),
            "",
            self.tr("环境变量文件 (*.env);;所有文件 (*)"),
            options=options
        )
        
        if file_path:
            self.load_env_file(file_path)
    
    def save_env_as(self):
        """另存为环境变量文件"""
        options = QFileDialog.Options()
        file_path, _ = QFileDialog.getSaveFileName(
            self,
            self.tr("保存环境变量文件"),
            "",
            self.tr("环境变量文件 (*.env);;所有文件 (*)"),
            options=options
        )
        
        if file_path:
            # 确保文件有.env扩展名
            if not file_path.lower().endswith('.env'):
                file_path += '.env'
            
            return self.save_env_data_to_file(file_path)
        
        return False
    
    def new_env_file(self):
        """新建环境变量文件"""
        if not self.check_save_changes():
            return
        
        self.current_file = None
        self.env_data = {}
        self.update_env_table()
        self.file_path_label.setText(self.tr("当前文件: 未选择"))
        self.modified = False
        
        self.log_message.emit(self.tr("新建环境变量文件"))
    
    def reload_env_file(self):
        """重新加载当前环境变量文件"""
        if not self.current_file:
            QMessageBox.warning(self, self.tr("错误"), self.tr("当前没有打开的文件"))
            return
        
        if not self.check_save_changes():
            return
        
        self.load_env_file(self.current_file)
    
    def add_env_variable(self):
        """添加环境变量"""
        dialog = EnvVariableDialog(self)
        
        if dialog.exec_() == QDialog.Accepted:
            key, value = dialog.get_data()
            
            # 检查键是否为空
            if not key:
                QMessageBox.warning(self, self.tr("错误"), self.tr("变量名不能为空"))
                return
            
            # 检查键是否已存在
            if key in self.env_data:
                reply = QMessageBox.question(
                    self, 
                    self.tr("覆盖确认"),
                    self.tr(f"变量 '{key}' 已存在,是否覆盖?"),
                    QMessageBox.Yes | QMessageBox.No
                )
                
                if reply != QMessageBox.Yes:
                    return
            
            # 更新数据
            self.env_data[key] = value
            self.update_env_table()
            self.modified = True
            
            self.log_message.emit(self.tr(f"添加环境变量: {key}={value}"))
    
    def edit_env_variable(self):
        """编辑环境变量"""
        # 获取当前选中的行
        selected_rows = self.env_table.selectedItems()
        
        if not selected_rows:
            QMessageBox.warning(self, self.tr("错误"), self.tr("请先选择一个变量"))
            return
        
        # 获取当前行的键和值
        row = selected_rows[0].row()
        key = self.env_table.item(row, 0).text()
        value = self.env_table.item(row, 1).text()
        
        # 打开编辑对话框
        dialog = EnvVariableDialog(self, key, value)
        
        if dialog.exec_() == QDialog.Accepted:
            new_key, new_value = dialog.get_data()
            
            # 检查键是否为空
            if not new_key:
                QMessageBox.warning(self, self.tr("错误"), self.tr("变量名不能为空"))
                return
            
            # 检查新键是否与其他键冲突
            if new_key != key and new_key in self.env_data:
                reply = QMessageBox.question(
                    self, 
                    self.tr("覆盖确认"),
                    self.tr(f"变量 '{new_key}' 已存在,是否覆盖?"),
                    QMessageBox.Yes | QMessageBox.No
                )
                
                if reply != QMessageBox.Yes:
                    return
            
            # 更新数据
            if new_key != key:
                del self.env_data[key]
            
            self.env_data[new_key] = new_value
            self.update_env_table()
            self.modified = True
            
            self.log_message.emit(self.tr(f"编辑环境变量: {key} -> {new_key}={new_value}"))
    
    def delete_env_variable(self):
        """删除环境变量"""
        # 获取当前选中的行
        selected_rows = self.env_table.selectedItems()
        
        if not selected_rows:
            QMessageBox.warning(self, self.tr("错误"), self.tr("请先选择一个变量"))
            return
        
        # 获取当前行的键
        row = selected_rows[0].row()
        key = self.env_table.item(row, 0).text()
        
        # 确认删除
        reply = QMessageBox.question(
            self, 
            self.tr("删除确认"),
            self.tr(f"确定要删除变量 '{key}' 吗?"),
            QMessageBox.Yes | QMessageBox.No
        )
        
        if reply == QMessageBox.Yes:
            # 更新数据
            del self.env_data[key]
            self.update_env_table()
            self.modified = True
            
            self.log_message.emit(self.tr(f"删除环境变量: {key}"))
    
    def on_table_item_changed(self, item):
        """表格项目变更处理"""
        # 如果在更新表格时触发了此事件则忽略
        if self.env_table.signalsBlocked():
            return
        
        row = item.row()
        col = item.column()
        
        # 获取当前行的键和值
        key_item = self.env_table.item(row, 0)
        value_item = self.env_table.item(row, 1)
        
        if not key_item or not value_item:
            return
        
        key = key_item.text()
        value = value_item.text()
        
        # 检查键是否为空
        if col == 0 and not key:
            QMessageBox.warning(self, self.tr("错误"), self.tr("变量名不能为空"))
            
            # 恢复原键
            old_key = list(self.env_data.keys())[row]
            key_item.setText(old_key)
            return
        
        # 如果是键变更
        if col == 0:
            old_key = list(self.env_data.keys())[row]
            
            # 检查新键是否与其他键冲突
            if key != old_key and key in self.env_data:
                reply = QMessageBox.question(
                    self, 
                    self.tr("覆盖确认"),
                    self.tr(f"变量 '{key}' 已存在,是否覆盖?"),
                    QMessageBox.Yes | QMessageBox.No
                )
                
                if reply != QMessageBox.Yes:
                    # 恢复原键
                    key_item.setText(old_key)
                    return
                
                # 删除冲突的键
                del self.env_data[key]
            
            # 更新数据
            self.env_data[key] = self.env_data.pop(old_key)
            self.log_message.emit(self.tr(f"重命名环境变量: {old_key} -> {key}"))
        
        # 如果是值变更
        elif col == 1:
            old_value = self.env_data[key]
            self.env_data[key] = value
            self.log_message.emit(self.tr(f"修改环境变量值: {key}={value}"))
        
        self.modified = True
    
    def add_log(self, message):
        """添加日志消息"""
        timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        self.log_text.append(f"[{timestamp}] {message}")
    
    def clear_log(self):
        """清除日志"""
        self.log_text.clear()
        self.log_message.emit(self.tr("日志已清除")) 

================================================
FILE: gui/home_tab.py
================================================
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

"""
首页标签 - 显示主要功能和欢迎信息
"""

from PyQt5.QtWidgets import (
    QWidget, QVBoxLayout, QHBoxLayout, QLabel, QPushButton, 
    QGroupBox, QGridLayout, QSpacerItem, QSizePolicy
)
from PyQt5.QtCore import Qt, pyqtSignal
from PyQt5.QtGui import QFont, QPixmap, QIcon

class HomeTab(QWidget):
    """首页标签类"""
    
    # 信号定义
    switch_tab_signal = pyqtSignal(int)
    
    def __init__(self, parent=None):
        """初始化首页标签"""
        super().__init__(parent)
        self.parent = parent
        self.init_ui()
    
    def init_ui(self):
        """初始化用户界面"""
        # 创建主布局
        main_layout = QVBoxLayout()
        main_layout.setContentsMargins(20, 20, 20, 20)
        main_layout.setSpacing(15)
        
        # 添加标题
        title_layout = QHBoxLayout()
        title_label = QLabel(self.tr("Cursor Pro 工具箱"))
        title_font = QFont()
        title_font.setPointSize(24)
        title_font.setBold(True)
        title_label.setFont(title_font)
        title_label.setAlignment(Qt.AlignCenter)
        
        # 添加Logo (如果存在)
        try:
            logo_label = QLabel()
            logo_pixmap = QPixmap("icons/cursor.png")
            if not logo_pixmap.isNull():
                logo_label.setPixmap(logo_pixmap.scaled(64, 64, Qt.KeepAspectRatio, Qt.SmoothTransformation))
                title_layout.addWidget(logo_label, 0, Qt.AlignRight)
        except:
            pass  # 没有logo图片也没关系
            
        title_layout.addWidget(title_label, 1)
        main_layout.addLayout(title_layout)
        
        # 添加欢迎信息
        welcome_label = QLabel(self.tr("欢迎使用Cursor Pro图形界面工具。请选择下方功能开始使用。"))
        welcome_label.setWordWrap(True)
        welcome_label.setAlignment(Qt.AlignCenter)
        main_layout.addWidget(welcome_label)
        
        # 创建功能区
        features_group = QGroupBox(self.tr("可用功能"))
        features_layout = QGridLayout()
        features_layout.setSpacing(10)
        
        # 功能按钮样式
        button_style = """
        QPushButton {
            min-height: 100px;
            font-size: 16px;
            font-weight: bold;
            text-align: center;
        }
        """
        
        # 添加功能按钮
        reset_btn = QPushButton(QIcon("icons/reset.png"), self.tr("重置机器码"))
        reset_btn.setStyleSheet(button_style)
        reset_btn.clicked.connect(lambda: self.switch_tab_signal.emit(1))
        
        register_btn = QPushButton(QIcon("icons/register.png"), self.tr("注册账号"))
        register_btn.setStyleSheet(button_style)
        register_btn.clicked.connect(lambda: self.switch_tab_signal.emit(2))
        
        account_btn = QPushButton(QIcon("icons/account.png"), self.tr("账号管理"))
        account_btn.setStyleSheet(button_style)
        account_btn.clicked.connect(lambda: self.switch_tab_signal.emit(3))
        
        env_btn = QPushButton(QIcon("icons/env.png"), self.tr("环境配置"))
        env_btn.setStyleSheet(button_style)
        env_btn.clicked.connect(lambda: self.switch_tab_signal.emit(4))
        
        about_btn = QPushButton(QIcon("icons/about.png"), self.tr("关于"))
        about_btn.setStyleSheet(button_style)
        about_btn.clicked.connect(lambda: self.switch_tab_signal.emit(5))
        
        # 添加按钮到网格布局
        features_layout.addWidget(reset_btn, 0, 0)
        features_layout.addWidget(register_btn, 0, 1)
        features_layout.addWidget(account_btn, 1, 0)
        features_layout.addWidget(env_btn, 1, 1)
        features_layout.addWidget(about_btn, 2, 0, 1, 2)  # 修改为跨两列
        
        features_group.setLayout(features_layout)
        main_layout.addWidget(features_group)
        
        # 添加弹性空间
        main_layout.addItem(QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding))
        
        # 设置主布局
        self.setLayout(main_layout)
        
        # 连接信号
        self.switch_tab_signal.connect(self.parent.tabs.setCurrentIndex)
    
    def retranslate_ui(self):
        """更新UI文本翻译"""
        # 此处更新所有可翻译文本
        # 更安全的方式更新文本,避免索引错误
        try:
            # 标题标签
            for i in range(self.layout().count()):
                item = self.layout().itemAt(i)
                if isinstance(item.layout(), QHBoxLayout) and item.layout().count() > 0:
                    for j in range(item.layout().count()):
                        widget = item.layout().itemAt(j).widget()
                        if isinstance(widget, QLabel) and widget.font().pointSize() > 20:
                            widget.setText(self.tr("Cursor Pro 工具箱"))
                            break
            
            # 欢迎信息
            for i in range(self.layout().count()):
                item = self.layout().itemAt(i)
                if isinstance(item.widget(), QLabel) and not item.widget().font().bold():
                    item.widget().setText(self.tr("欢迎使用Cursor Pro图形界面工具。请选择下方功能开始使用。"))
                    break
            
            # 功能组标题
            for i in range(self.layout().count()):
                item = self.layout().itemAt(i)
                if isinstance(item.widget(), QGroupBox):
                    item.widget().setTitle(self.tr("可用功能"))
                    
                    # 更新按钮文本
                    grid_layout = item.widget().layout()
                    if isinstance(grid_layout, QGridLayout):
                        # 重置机器码按钮
                        button = grid_layout.itemAtPosition(0, 0).widget()
                        if button: button.setText(self.tr("重置机器码"))
                        
                        # 注册账号按钮
                        button = grid_layout.itemAtPosition(0, 1).widget()
                        if button: button.setText(self.tr("注册账号"))
                        
                        # 账号管理按钮
                        button = grid_layout.itemAtPosition(1, 0).widget()
                        if button: button.setText(self.tr("账号管理"))
                        
                        # 环境配置按钮
                        button = grid_layout.itemAtPosition(1, 1).widget()
                        if button: button.setText(self.tr("环境配置"))
                        
                        # 关于按钮
                        button = grid_layout.itemAtPosition(2, 0).widget()
                        if button: button.setText(self.tr("关于"))
                    break
            
        except Exception as e:
            print(f"翻译UI时出错: {str(e)}") 

================================================
FILE: gui/log_viewer.py
================================================
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

"""
日志查看器组件 - 捕获logger模块的日志并在GUI中显示
"""

import logging
import time
from PyQt5.QtWidgets import (
    QWidget, QVBoxLayout, QTextEdit, QApplication, 
    QHBoxLayout, QPushButton, QComboBox, QLabel,
    QSizePolicy, QScrollArea
)
from PyQt5.QtCore import Qt, QObject, pyqtSignal, pyqtSlot, QTimer, QSize
from PyQt5.QtGui import QFont, QTextCursor, QIcon, QColor

class LogSignalHandler(QObject, logging.Handler):
    """将日志记录发送到Qt信号的自定义日志处理器"""
    
    # 定义Qt信号,用于向UI组件发送日志消息
    log_signal = pyqtSignal(str, int, str)  # 参数:消息文本、日志级别、记录时间
    
    def __init__(self):
        super().__init__()
        # 初始化基类
        QObject.__init__(self)
        logging.Handler.__init__(self)
        
        # 设置格式化器 - 使用较简单的格式,由显示组件来负责布局美化
        self.setFormatter(logging.Formatter('%(message)s'))
        
        # 日志级别映射
        self.level_map = {
            logging.DEBUG: 0,
            logging.INFO: 1,
            logging.WARNING: 2,
            logging.ERROR: 3,
            logging.CRITICAL: 4
        }
    
    def emit(self, record):
        """发出日志记录时的处理"""
        try:
            # 格式化日志记录 - 保留原始消息格式
            log_message = self.format(record)
            
            # 获取日志级别索引(默认为INFO级别)
            level_idx = self.level_map.get(record.levelno, 1)
            
            # 获取时间戳
            time_str = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(record.created))
            
            # 发送信号
            self.log_signal.emit(log_message, level_idx, time_str)
        except Exception:
            self.handleError(record)

class LogViewer(QWidget):
    """日志查看器组件,用于在GUI中显示日志"""
    
    def __init__(self, parent=None, min_height=250):
        """初始化日志查看器"""
        super().__init__(parent)
        self.parent = parent
        self.min_height = min_height
        self.log_handler = None
        self.log_buffer = []  # 用于存储最近的日志记录
        self.max_buffer_size = 1000  # 最大缓冲区大小
        self.auto_scroll = True  # 是否自动滚动
        self.init_ui()
        self.setup_logger()
        
        # 定时刷新UI,避免频繁的UI更新操作
        self.refresh_timer = QTimer(self)
        self.refresh_timer.timeout.connect(self.update_display)
        self.refresh_timer.start(100)  # 每100毫秒更新一次UI
    
    def init_ui(self):
        """初始化用户界面"""
        # 创建主布局
        layout = QVBoxLayout(self)
        layout.setContentsMargins(0, 0, 0, 0)
        layout.setSpacing(5)
        
        # 工具栏
        toolbar = QHBoxLayout()
        toolbar.setContentsMargins(0, 0, 0, 0)
        toolbar.setSpacing(10)
        
        # 日志级别选择
        level_label = QLabel(self.tr("日志级别:"))
        level_label.setFixedWidth(60)
        self.level_combo = QComboBox()
        self.level_combo.addItems([
            self.tr("调试 (DEBUG)"),
            self.tr("信息 (INFO)"),
            self.tr("警告 (WARNING)"),
            self.tr("错误 (ERROR)"),
            self.tr("严重 (CRITICAL)")
        ])
        self.level_combo.setCurrentIndex(1)  # 默认INFO级别
        self.level_combo.currentIndexChanged.connect(self.change_log_level)
        
        # 自动滚动选项
        self.auto_scroll_button = QPushButton(self.tr("自动滚动"))
        self.auto_scroll_button.setCheckable(True)
        self.auto_scroll_button.setChecked(True)
        self.auto_scroll_button.clicked.connect(self.toggle_auto_scroll)
        
        # 清除按钮
        self.clear_button = QPushButton(self.tr("清除日志"))
        self.clear_button.clicked.connect(self.clear_logs)
        
        # 设置按钮和组件大小
        self.level_combo.setFixedWidth
Download .txt
gitextract_m5ok1t6j/

├── .github/
│   └── workflows/
│       ├── build.yml
│       ├── remove-old-artifacts.yml
│       └── temp-build.yml
├── .gitignore
├── README.md
├── browser_utils.py
├── build.bat
├── build.mac.command
├── build.py
├── build.sh
├── config.py
├── cursor_auth_manager.py
├── cursor_pro_gui.py
├── cursor_pro_keep_alive.py
├── disable_auto_update.py
├── example_usage.py
├── exit_cursor.py
├── get_email_code.py
├── go_cursor_help.py
├── gui/
│   ├── about_tab.py
│   ├── account_tab.py
│   ├── env_tab.py
│   ├── home_tab.py
│   ├── log_viewer.py
│   ├── register_tab.py
│   ├── reset_tab.py
│   └── settings_tab.py
├── language.py
├── logger.py
├── logo.py
├── names-dataset.txt
├── patch_cursor_get_machine_id.py
├── requirements.txt
├── reset_machine.py
├── settings.json
├── start_cursor.py
├── test/
│   └── get_veri_code_test.py
├── test_email.py
├── test_session_token.py
├── turnstilePatch/
│   ├── manifest.json
│   ├── readme.txt
│   └── script.js
└── utils.py
Download .txt
SYMBOL INDEX (266 symbols across 30 files)

FILE: browser_utils.py
  class BrowserManager (line 10) | class BrowserManager:
    method __init__ (line 11) | def __init__(self):
    method init_browser (line 14) | def init_browser(self, user_agent=None):
    method _get_browser_options (line 20) | def _get_browser_options(self, user_agent=None):
    method _get_extension_path (line 54) | def _get_extension_path(self,exname='turnstilePatch'):
    method quit (line 67) | def quit(self):

FILE: build.py
  class LoadingAnimation (line 21) | class LoadingAnimation:
    method __init__ (line 22) | def __init__(self):
    method start (line 26) | def start(self, message="Building"):
    method stop (line 31) | def stop(self):
    method _animate (line 37) | def _animate(self, message):
  function print_logo (line 46) | def print_logo():
  function progress_bar (line 51) | def progress_bar(progress, total, prefix="", length=50):
  function simulate_progress (line 60) | def simulate_progress(message, duration=1.0, steps=20):
  function filter_output (line 67) | def filter_output(output):
  function build (line 82) | def build():

FILE: config.py
  class Config (line 8) | class Config:
    method __init__ (line 9) | def __init__(self):
    method get_temp_mail (line 44) | def get_temp_mail(self):
    method get_temp_mail_epin (line 48) | def get_temp_mail_epin(self):
    method get_temp_mail_ext (line 52) | def get_temp_mail_ext(self):
    method get_imap (line 56) | def get_imap(self):
    method get_domain (line 67) | def get_domain(self):
    method get_protocol (line 70) | def get_protocol(self):
    method check_config (line 78) | def check_config(self):
    method check_is_valid (line 119) | def check_is_valid(self, value):
    method print_config (line 130) | def print_config(self):

FILE: cursor_auth_manager.py
  class CursorAuthManager (line 6) | class CursorAuthManager:
    method __init__ (line 9) | def __init__(self):
    method update_auth (line 29) | def update_auth(self, email=None, access_token=None, refresh_token=None):

FILE: cursor_pro_gui.py
  class CursorProGUI (line 282) | class CursorProGUI(QMainWindow):
    method __init__ (line 285) | def __init__(self):
    method init_ui (line 310) | def init_ui(self):
    method center_window (line 343) | def center_window(self):
    method init_language (line 350) | def init_language(self):
    method change_language (line 356) | def change_language(self, locale):
    method retranslate_ui (line 381) | def retranslate_ui(self):
    method update_status (line 405) | def update_status(self, message):
    method closeEvent (line 409) | def closeEvent(self, event):
  function main (line 416) | def main():

FILE: cursor_pro_keep_alive.py
  class VerificationStatus (line 49) | class VerificationStatus(Enum):
  class TurnstileError (line 58) | class TurnstileError(Exception):
  class CursorProKeepAlive (line 63) | class CursorProKeepAlive:
    method __init__ (line 66) | def __init__(self):
    method init_browser (line 81) | def init_browser(self) -> bool:
    method cleanup (line 109) | def cleanup(self):
    method get_user_agent (line 115) | def get_user_agent(self) -> Optional[str]:
    method check_cursor_version (line 128) | def check_cursor_version(self) -> bool:
    method reset_machine_id (line 135) | def reset_machine_id(self) -> bool:
    method disable_auto_update (line 150) | def disable_auto_update(self) -> bool:
    method update_cursor_auth (line 161) | def update_cursor_auth(self, email: str = None, access_token: str = No...
    method start_cursor (line 181) | def start_cursor(self) -> None:
    method generate_account (line 186) | def generate_account(self) -> Dict[str, str]:
    method print_end_message (line 212) | def print_end_message(self) -> None:
    method save_account_info (line 224) | def save_account_info(self, email: str = None, password: str = None,
    method list_and_apply_saved_accounts (line 277) | def list_and_apply_saved_accounts(self) -> bool:
    method apply_account_from_file (line 323) | def apply_account_from_file(self, filepath: str) -> bool:
    method option_reset_machine_id (line 375) | def option_reset_machine_id(self) -> bool:
    method option_disable_auto_update (line 386) | def option_disable_auto_update(self) -> bool:
    method option_apply_saved_account (line 395) | def option_apply_saved_account(self) -> bool:
    method handle_turnstile (line 404) | def handle_turnstile(self, tab=None, max_retries: int = 2, retry_inter...
    method generate_auth_params (line 499) | def generate_auth_params(self) -> Dict[str, str]:
    method poll_for_login_result (line 534) | def poll_for_login_result(self, uuid: str, challenge: str) -> Tuple[Op...
    method get_cursor_session_token (line 580) | def get_cursor_session_token(self, tab=None, max_attempts=3, retry_int...
    method sign_up_account (line 638) | def sign_up_account(self, browser=None, tab=None) -> bool:
    method option_sign_up_only (line 759) | def option_sign_up_only(self) -> bool:
    method option_complete_registration (line 797) | def option_complete_registration(self) -> bool:
  function save_screenshot (line 843) | def save_screenshot(tab, stage: str, timestamp: bool = True) -> None:
  function check_verification_success (line 872) | def check_verification_success(tab, default_status=None) -> Optional[Ver...
  function handle_turnstile (line 895) | def handle_turnstile(tab, max_retries: int = 2, retry_interval: tuple = ...
  function get_cursor_session_token (line 992) | def get_cursor_session_token(tab, max_attempts=3, retry_interval=2):
  function update_cursor_auth (line 1069) | def update_cursor_auth(email=None, access_token=None, refresh_token=None):
  function generate_auth_params (line 1076) | def generate_auth_params():
  function poll_for_login_result (line 1105) | def poll_for_login_result(uuid, challenge):
  function sign_up_account (line 1142) | def sign_up_account(browser, tab):
  class EmailGenerator (line 1251) | class EmailGenerator:
    method __init__ (line 1254) | def __init__(
    method load_names (line 1277) | def load_names(self) -> List[str]:
    method generate_random_name (line 1293) | def generate_random_name(self) -> str:
    method generate_email (line 1302) | def generate_email(self, length=4) -> str:
    method get_account_info (line 1316) | def get_account_info(self) -> Dict[str, str]:
  function main (line 1331) | def main():
  function api_reset_machine_id (line 1383) | def api_reset_machine_id():
  function api_complete_registration (line 1388) | def api_complete_registration():
  function api_sign_up_only (line 1393) | def api_sign_up_only():
  function api_disable_auto_update (line 1398) | def api_disable_auto_update():
  function api_apply_saved_account (line 1403) | def api_apply_saved_account(account_file_path=None):
  function api_get_account_info (line 1419) | def api_get_account_info():
  function api_save_account_info (line 1429) | def api_save_account_info(email, password, access_token="", refresh_toke...
  function api_update_cursor_auth (line 1445) | def api_update_cursor_auth(email, access_token, refresh_token):
  function api_start_cursor (line 1460) | def api_start_cursor():

FILE: disable_auto_update.py
  class AutoUpdateDisabler (line 27) | class AutoUpdateDisabler:
    method __init__ (line 28) | def __init__(self, translator=None):
    method _get_config_item (line 70) | def _get_config_item(self,config, key1, key2, default):
    method _get_config (line 77) | def _get_config(self):
    method _remove_update_url (line 268) | def _remove_update_url(self):
    method _kill_cursor_processes (line 308) | def _kill_cursor_processes(self):
    method _remove_updater_directory (line 325) | def _remove_updater_directory(self):
    method _clear_update_yml_file (line 349) | def _clear_update_yml_file(self):
    method _create_blocking_file (line 373) | def _create_blocking_file(self):
    method disable_auto_update (line 422) | def disable_auto_update(self):
  function run (line 453) | def run(translator=None):

FILE: example_usage.py
  function show_menu (line 22) | def show_menu():
  function main (line 37) | def main():

FILE: exit_cursor.py
  function ExitCursor (line 5) | def ExitCursor(timeout=5):

FILE: get_email_code.py
  class EmailVerificationHandler (line 13) | class EmailVerificationHandler:
    method __init__ (line 14) | def __init__(self,account):
    method get_verification_code (line 24) | def get_verification_code(self, max_retries=5, retry_interval=60):
    method _get_mail_code_by_imap (line 68) | def _get_mail_code_by_imap(self, retry = 0):
    method _extract_imap_body (line 126) | def _extract_imap_body(self, email_message):
    method _get_mail_code_by_pop3 (line 151) | def _get_mail_code_by_pop3(self, retry = 0):
    method _extract_pop3_body (line 195) | def _extract_pop3_body(self, email_message):
    method _get_latest_mail_code (line 216) | def _get_latest_mail_code(self):
    method _cleanup_mail (line 249) | def _cleanup_mail(self, first_id):

FILE: go_cursor_help.py
  function go_cursor_help (line 7) | def go_cursor_help():
  function main (line 32) | def main():

FILE: gui/about_tab.py
  class AboutTab (line 15) | class AboutTab(QWidget):
    method __init__ (line 18) | def __init__(self, parent=None):
    method init_ui (line 24) | def init_ui(self):
    method retranslate_ui (line 120) | def retranslate_ui(self):

FILE: gui/account_tab.py
  class WorkerThread (line 35) | class WorkerThread(QThread):
    method __init__ (line 42) | def __init__(self, task, args=None, kwargs=None, parent=None):
    method run (line 58) | def run(self):
  class AccountTab (line 93) | class AccountTab(QWidget):
    method __init__ (line 96) | def __init__(self, parent=None):
    method init_ui (line 106) | def init_ui(self):
    method load_account_list (line 329) | def load_account_list(self):
    method on_account_selected (line 373) | def on_account_selected(self, current, previous):
    method display_account_details (line 395) | def display_account_details(self, account_data):
    method apply_account (line 497) | def apply_account(self):
    method delete_account (line 527) | def delete_account(self):
    method run_task (line 564) | def run_task(self, task_func, args, kwargs, start_message):
    method log (line 584) | def log(self, message, level="info"):
    method update_progress (line 606) | def update_progress(self, value):
    method on_task_finished (line 610) | def on_task_finished(self, success, message):
    method retranslate_ui (line 634) | def retranslate_ui(self):
    method show_help (line 728) | def show_help(self):

FILE: gui/env_tab.py
  class EnvVariableDialog (line 20) | class EnvVariableDialog(QDialog):
    method __init__ (line 23) | def __init__(self, parent=None, key="", value=""):
    method get_data (line 49) | def get_data(self):
  class EnvTab (line 53) | class EnvTab(QWidget):
    method __init__ (line 60) | def __init__(self, parent=None):
    method init_ui (line 73) | def init_ui(self):
    method retranslate_ui (line 189) | def retranslate_ui(self):
    method try_load_default_env (line 208) | def try_load_default_env(self):
    method load_env_file (line 228) | def load_env_file(self, file_path):
    method update_env_table (line 273) | def update_env_table(self):
    method save_env_file (line 294) | def save_env_file(self):
    method save_env_data_to_file (line 313) | def save_env_data_to_file(self, file_path):
    method check_save_changes (line 380) | def check_save_changes(self):
    method open_env_file (line 401) | def open_env_file(self):
    method save_env_as (line 418) | def save_env_as(self):
    method new_env_file (line 438) | def new_env_file(self):
    method reload_env_file (line 451) | def reload_env_file(self):
    method add_env_variable (line 462) | def add_env_variable(self):
    method edit_env_variable (line 493) | def edit_env_variable(self):
    method delete_env_variable (line 540) | def delete_env_variable(self):
    method on_table_item_changed (line 569) | def on_table_item_changed(self, item):
    method add_log (line 630) | def add_log(self, message):
    method clear_log (line 635) | def clear_log(self):

FILE: gui/home_tab.py
  class HomeTab (line 15) | class HomeTab(QWidget):
    method __init__ (line 21) | def __init__(self, parent=None):
    method init_ui (line 27) | def init_ui(self):
    method retranslate_ui (line 117) | def retranslate_ui(self):

FILE: gui/log_viewer.py
  class LogSignalHandler (line 18) | class LogSignalHandler(QObject, logging.Handler):
    method __init__ (line 24) | def __init__(self):
    method emit (line 42) | def emit(self, record):
  class LogViewer (line 59) | class LogViewer(QWidget):
    method __init__ (line 62) | def __init__(self, parent=None, min_height=250):
    method init_ui (line 79) | def init_ui(self):
    method toggle_auto_scroll (line 217) | def toggle_auto_scroll(self, checked):
    method setup_logger (line 225) | def setup_logger(self):
    method on_log_message (line 242) | def on_log_message(self, message, level, time_str):
    method update_display (line 258) | def update_display(self):
    method change_log_level (line 308) | def change_log_level(self, index):
    method refresh_logs (line 328) | def refresh_logs(self):
    method clear_logs (line 336) | def clear_logs(self):
    method sizeHint (line 341) | def sizeHint(self):
    method minimumSizeHint (line 345) | def minimumSizeHint(self):
    method retranslate_ui (line 349) | def retranslate_ui(self):
    method resizeEvent (line 361) | def resizeEvent(self, event):

FILE: gui/register_tab.py
  class WorkerThread (line 28) | class WorkerThread(QThread):
    method __init__ (line 35) | def __init__(self, task, parent=None):
    method run (line 47) | def run(self):
  class RegisterTab (line 82) | class RegisterTab(QWidget):
    method __init__ (line 85) | def __init__(self, parent=None):
    method init_ui (line 92) | def init_ui(self):
    method register_account (line 242) | def register_account(self):
    method log (line 275) | def log(self, message):
    method update_progress (line 279) | def update_progress(self, value):
    method on_task_finished (line 283) | def on_task_finished(self, success, message):
    method retranslate_ui (line 302) | def retranslate_ui(self):
    method show_help (line 372) | def show_help(self):

FILE: gui/reset_tab.py
  class WorkerThread (line 27) | class WorkerThread(QThread):
    method __init__ (line 34) | def __init__(self, task, parent=None):
    method run (line 46) | def run(self):
  class ResetTab (line 81) | class ResetTab(QWidget):
    method __init__ (line 84) | def __init__(self, parent=None):
    method init_ui (line 91) | def init_ui(self):
    method reset_machine_id (line 243) | def reset_machine_id(self):
    method log (line 266) | def log(self, message):
    method update_progress (line 270) | def update_progress(self, value):
    method on_task_finished (line 274) | def on_task_finished(self, success, message):
    method retranslate_ui (line 293) | def retranslate_ui(self):
    method show_help (line 365) | def show_help(self):

FILE: gui/settings_tab.py
  class SettingsTab (line 18) | class SettingsTab(QWidget):
    method __init__ (line 24) | def __init__(self, parent=None):
    method init_ui (line 38) | def init_ui(self):
    method load_settings (line 131) | def load_settings(self):
    method apply_settings_to_ui (line 149) | def apply_settings_to_ui(self):
    method save_settings (line 169) | def save_settings(self):
    method reset_settings (line 195) | def reset_settings(self):
    method language_selection_changed (line 219) | def language_selection_changed(self, index):
    method retranslate_ui (line 243) | def retranslate_ui(self):

FILE: language.py
  class Language (line 3) | class Language:
    method __init__ (line 4) | def __init__(self):
    method set_language (line 437) | def set_language(self, language_code):
    method get (line 444) | def get(self, key, **kwargs):
    method select_language_prompt (line 463) | def select_language_prompt(self):
  function get_translation (line 488) | def get_translation(key, **kwargs):

FILE: logger.py
  function get_translation (line 8) | def get_translation(key, **kwargs):
  class PrefixFormatter (line 21) | class PrefixFormatter(logging.Formatter):
    method format (line 24) | def format(self, record):
  function main_task (line 61) | def main_task():
  function some_condition (line 82) | def some_condition():

FILE: logo.py
  function print_logo (line 11) | def print_logo():

FILE: patch_cursor_get_machine_id.py
  function setup_logging (line 16) | def setup_logging() -> logging.Logger:
  function get_cursor_paths (line 32) | def get_cursor_paths() -> Tuple[str, str]:
  function check_system_requirements (line 89) | def check_system_requirements(pkg_path: str, main_path: str) -> bool:
  function version_check (line 112) | def version_check(version: str, min_version: str = "", max_version: str ...
  function modify_main_js (line 150) | def modify_main_js(main_path: str) -> bool:
  function backup_files (line 202) | def backup_files(pkg_path: str, main_path: str) -> bool:
  function restore_backup_files (line 226) | def restore_backup_files(pkg_path: str, main_path: str) -> bool:
  function patch_cursor_get_machine_id (line 252) | def patch_cursor_get_machine_id(restore_mode=False) -> None:

FILE: reset_machine.py
  class MachineIDResetter (line 23) | class MachineIDResetter:
    method __init__ (line 24) | def __init__(self):
    method generate_new_ids (line 46) | def generate_new_ids(self):
    method reset_machine_ids (line 67) | def reset_machine_ids(self):

FILE: start_cursor.py
  class CursorStarter (line 10) | class CursorStarter:
    method __init__ (line 14) | def __init__(self):
    method _get_cursor_paths (line 18) | def _get_cursor_paths(self):
    method _is_cursor_running (line 50) | def _is_cursor_running(self):
    method start_cursor (line 60) | def start_cursor(self, wait_time=5):
  function StartCursor (line 116) | def StartCursor(wait_time=5):

FILE: test/get_veri_code_test.py
  function get_extension_path (line 9) | def get_extension_path():
  function get_browser_options (line 28) | def get_browser_options():
  function get_veri_code (line 51) | def get_veri_code(username):

FILE: test_email.py
  function test_temp_mail (line 6) | def test_temp_mail():
  function test_email_server (line 17) | def test_email_server():
  function print_config (line 30) | def print_config():
  function main (line 41) | def main():

FILE: test_session_token.py
  function generate_auth_params (line 6) | def generate_auth_params():

FILE: turnstilePatch/script.js
  function getRandomInt (line 1) | function getRandomInt(min, max) {

FILE: utils.py
  function is_admin (line 12) | def is_admin():
  function restart_as_admin (line 29) | def restart_as_admin():
  function ensure_admin (line 109) | def ensure_admin():
  function get_user_documents_path (line 125) | def get_user_documents_path():
  function get_default_driver_path (line 132) | def get_default_driver_path(browser_type='chrome'):
  function get_default_chrome_driver_path (line 148) | def get_default_chrome_driver_path():
  function get_default_edge_driver_path (line 157) | def get_default_edge_driver_path():
  function get_default_firefox_driver_path (line 166) | def get_default_firefox_driver_path():
  function get_default_brave_driver_path (line 175) | def get_default_brave_driver_path():
  function get_default_browser_path (line 180) | def get_default_browser_path(browser_type='chrome'):
  function get_linux_cursor_path (line 297) | def get_linux_cursor_path():
  function get_random_wait_time (line 310) | def get_random_wait_time(config, timing_key):
  function request_admin_for_task (line 346) | def request_admin_for_task(task_description="执行系统操作", silent=False):
Condensed preview — 43 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (666K chars).
[
  {
    "path": ".github/workflows/build.yml",
    "chars": 5300,
    "preview": "name: Build Executables\n\non:\n  push:\n    tags:\n      - 'v*'  # 添加标签触发条件,匹配 v1.0.0 这样的标签\n  workflow_dispatch:  # 手动触发工作流\n"
  },
  {
    "path": ".github/workflows/remove-old-artifacts.yml",
    "chars": 518,
    "preview": "name: Remove old artifacts\n\non:\n  schedule:\n    # Every day at 1am\n    - cron: '0 1 * * *'\n  # 手动\n  workflow_dispatch:\n\n"
  },
  {
    "path": ".github/workflows/temp-build.yml",
    "chars": 2659,
    "preview": "name: temp Build Executables\n\non:\n  workflow_dispatch:  # 手动触发工作流\n\njobs:\n  build-windows:\n    runs-on: windows-latest\n  "
  },
  {
    "path": ".gitignore",
    "chars": 225,
    "preview": "# PyInstaller\nbuild/\ndist/\n*.spec\n!CursorKeepAlive.mac.spec\n!CursorKeepAlive.win.spec\n\n# Python\n__pycache__/\n*.py[cod]\n*"
  },
  {
    "path": "README.md",
    "chars": 1353,
    "preview": "# Cursor Pro 自动化工具\n\n## 项目说明\n\n本项目基于 [@chengazhen/cursor-auto-free](https://github.com/chengazhen/cursor-auto-free) 开源项目进行"
  },
  {
    "path": "browser_utils.py",
    "chars": 1983,
    "preview": "from DrissionPage import ChromiumOptions, Chromium\nimport sys\nimport os\nimport logging\nfrom dotenv import load_dotenv\n\nl"
  },
  {
    "path": "build.bat",
    "chars": 700,
    "preview": "@echo off\nset PYTHONWARNINGS=ignore::SyntaxWarning:DrissionPage\necho Building Cursor Keep Alive...\n\n:: Check if virtual "
  },
  {
    "path": "build.mac.command",
    "chars": 685,
    "preview": "#!/bin/bash\nexport PYTHONWARNINGS=ignore::SyntaxWarning:DrissionPage\n\n# Get script directory\ncd \"$(dirname \"$0\")\"\n\necho "
  },
  {
    "path": "build.py",
    "chars": 5492,
    "preview": "import warnings\nimport os\nimport platform\nimport subprocess\nimport time\nimport threading\n\n# Ignore specific SyntaxWarnin"
  },
  {
    "path": "build.sh",
    "chars": 589,
    "preview": "#!/bin/bash\nexport PYTHONWARNINGS=ignore::SyntaxWarning:DrissionPage\n\necho \"Creating virtual environment...\"\n\n# Check if"
  },
  {
    "path": "config.py",
    "chars": 4798,
    "preview": "from dotenv import load_dotenv\nimport os\nimport sys\nfrom logger import logging\nfrom language import get_translation\n\n\ncl"
  },
  {
    "path": "cursor_auth_manager.py",
    "chars": 2898,
    "preview": "import sqlite3\nimport os\nimport sys\n\n\nclass CursorAuthManager:\n    \"\"\"Cursor认证信息管理器\"\"\"\n\n    def __init__(self):\n        "
  },
  {
    "path": "cursor_pro_gui.py",
    "chars": 11467,
    "preview": "#!/usr/bin/env python3\n# -*- coding: utf-8 -*-\n# pyinstaller: --noconsole, --onefile, --name=CursorProGUI, --uac-admin, "
  },
  {
    "path": "cursor_pro_keep_alive.py",
    "chars": 52312,
    "preview": "import os\nimport platform\nimport json\nimport sys\nfrom colorama import Fore, Style\nfrom enum import Enum\nfrom typing impo"
  },
  {
    "path": "disable_auto_update.py",
    "chars": 24276,
    "preview": "import os\nimport sys\nimport platform\nimport shutil\nfrom colorama import Fore, Style, init\nimport subprocess\nfrom utils i"
  },
  {
    "path": "example_usage.py",
    "chars": 3836,
    "preview": "#!/usr/bin/env python3\n# -*- coding: utf-8 -*-\n\n\"\"\"\n示例程序:演示如何使用重构后的cursor_pro_keep_alive.py API接口\n\"\"\"\n\nimport sys\nimport"
  },
  {
    "path": "exit_cursor.py",
    "chars": 1943,
    "preview": "import psutil\nfrom logger import logging  \nimport time\n\ndef ExitCursor(timeout=5):\n    \"\"\"\n    温和地关闭 Cursor 进程\n    \n    "
  },
  {
    "path": "get_email_code.py",
    "chars": 10427,
    "preview": "from datetime import datetime\nimport logging\nimport time\nimport re\nfrom config import Config\nimport requests\nimport emai"
  },
  {
    "path": "go_cursor_help.py",
    "chars": 1284,
    "preview": "import platform\nimport os\nimport subprocess\nfrom logger import logging\nfrom language import get_translation\n\ndef go_curs"
  },
  {
    "path": "gui/about_tab.py",
    "chars": 7924,
    "preview": "#!/usr/bin/env python3\n# -*- coding: utf-8 -*-\n\n\"\"\"\n关于标签页 - 显示应用程序信息和版权声明\n\"\"\"\n\nfrom PyQt5.QtWidgets import (\n    QWidget"
  },
  {
    "path": "gui/account_tab.py",
    "chars": 25396,
    "preview": "#!/usr/bin/env python3\n# -*- coding: utf-8 -*-\n\n\"\"\"\n账号管理标签页 - 提供账号管理功能\n\"\"\"\n\nfrom PyQt5.QtWidgets import (\n    QWidget, Q"
  },
  {
    "path": "gui/env_tab.py",
    "chars": 21032,
    "preview": "#!/usr/bin/env python3\n# -*- coding: utf-8 -*-\n\n\"\"\"\n环境配置标签页 - 提供.env文件操作和环境变量管理功能\n\"\"\"\n\nimport os\nimport re\nfrom datetime"
  },
  {
    "path": "gui/home_tab.py",
    "chars": 6384,
    "preview": "#!/usr/bin/env python3\n# -*- coding: utf-8 -*-\n\n\"\"\"\n首页标签 - 显示主要功能和欢迎信息\n\"\"\"\n\nfrom PyQt5.QtWidgets import (\n    QWidget, Q"
  },
  {
    "path": "gui/log_viewer.py",
    "chars": 11182,
    "preview": "#!/usr/bin/env python3\n# -*- coding: utf-8 -*-\n\n\"\"\"\n日志查看器组件 - 捕获logger模块的日志并在GUI中显示\n\"\"\"\n\nimport logging\nimport time\nfrom"
  },
  {
    "path": "gui/register_tab.py",
    "chars": 13795,
    "preview": "#!/usr/bin/env python3\n# -*- coding: utf-8 -*-\n\n\"\"\"\n注册账号标签页 - 提供账号注册功能\n\"\"\"\n\nfrom PyQt5.QtWidgets import (\n    QWidget, Q"
  },
  {
    "path": "gui/reset_tab.py",
    "chars": 13107,
    "preview": "#!/usr/bin/env python3\n# -*- coding: utf-8 -*-\n\n\"\"\"\n重置机器码标签页 - 提供重置机器码功能\n\"\"\"\n\nfrom PyQt5.QtWidgets import (\n    QWidget,"
  },
  {
    "path": "gui/settings_tab.py",
    "chars": 8626,
    "preview": "#!/usr/bin/env python3\n# -*- coding: utf-8 -*-\n\n\"\"\"\n设置标签页 - 提供应用程序设置功能\n\"\"\"\n\nfrom PyQt5.QtWidgets import (\n    QWidget, Q"
  },
  {
    "path": "language.py",
    "chars": 29806,
    "preview": "import os\n\nclass Language:\n    def __init__(self):\n        self.current_language = \"cn\"  # Default language is Chinese\n "
  },
  {
    "path": "logger.py",
    "chars": 2798,
    "preview": "import logging\nimport os\nfrom datetime import datetime\ntry:\n    from language import get_translation\nexcept ImportError:"
  },
  {
    "path": "logo.py",
    "chars": 428,
    "preview": "CURSOR_LOGO = \"\"\"\n  ██████╗██╗   ██╗██████╗ ███████╗ ██████╗ ██████╗ \n  ██╔════╝██║   ██║██╔══██╗██╔════╝██╔═══██╗██╔══█"
  },
  {
    "path": "names-dataset.txt",
    "chars": 269653,
    "preview": "satara\nbritiney\nrory\ncharelle\nelizeo\ndago\npoetry\njhase\nderika\nlarsen\njazzmon\nkatianna\nayodeji\ndestane\nnechole\ndestani\nde"
  },
  {
    "path": "patch_cursor_get_machine_id.py",
    "chars": 8190,
    "preview": "#!/usr/bin/env python3\n# -*- coding: utf-8 -*-\n\nimport json\nimport logging\nimport os\nimport platform\nimport re\nimport sh"
  },
  {
    "path": "requirements.txt",
    "chars": 94,
    "preview": "DrissionPage==4.1.0.9\ncolorama==0.4.6\npython-dotenv\npyinstaller>=6.3.0\nPyQt5==5.15.10\nrequests"
  },
  {
    "path": "reset_machine.py",
    "chars": 4279,
    "preview": "import os\nimport sys\nimport json\nimport uuid\nimport hashlib\nimport shutil\nfrom colorama import Fore, Style, init\n\n# 初始化c"
  },
  {
    "path": "settings.json",
    "chars": 106,
    "preview": "{\n    \"language\": \"zh_CN\",\n    \"theme\": \"light\",\n    \"auto_check_update\": true,\n    \"log_level\": \"debug\"\n}"
  },
  {
    "path": "start_cursor.py",
    "chars": 4167,
    "preview": "import os\nimport sys\nimport platform\nimport subprocess\nimport time\nimport psutil\nfrom logger import logging\nfrom languag"
  },
  {
    "path": "test/get_veri_code_test.py",
    "chars": 3368,
    "preview": "from DrissionPage import ChromiumOptions, Chromium\nfrom DrissionPage.common import Keys\nimport time\nimport re\nimport sys"
  },
  {
    "path": "test_email.py",
    "chars": 1588,
    "preview": "import os\nfrom dotenv import load_dotenv\nfrom get_email_code import EmailVerificationHandler\nimport logging\n\ndef test_te"
  },
  {
    "path": "test_session_token.py",
    "chars": 883,
    "preview": "import os\nimport base64\nimport hashlib\nimport uuid\n\ndef generate_auth_params():\n    # 1. 生成 code_verifier (t) - 32字节随机数\n"
  },
  {
    "path": "turnstilePatch/manifest.json",
    "chars": 370,
    "preview": "{\n    \"manifest_version\": 3,\n    \"name\": \"Turnstile Patcher\",\n    \"version\": \"2.1\",\n    \"content_scripts\": [\n        {\n "
  },
  {
    "path": "turnstilePatch/readme.txt",
    "chars": 1,
    "preview": "\n"
  },
  {
    "path": "turnstilePatch/script.js",
    "chars": 372,
    "preview": "function getRandomInt(min, max) {\n    return Math.floor(Math.random() * (max - min + 1)) + min;\n}\n\n// old method wouldn'"
  },
  {
    "path": "utils.py",
    "chars": 16799,
    "preview": "import os\nimport sys\nimport platform\nimport random\nimport subprocess\nimport ctypes\nimport sys\nimport traceback\nimport ti"
  }
]

About this extraction

This page contains the full source code of the wangffei/wf-cursor-auto-free GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 43 files (569.4 KB), approximately 195.3k tokens, and a symbol index with 266 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!