Full Code of yuaotian/go-cursor-help for AI

master 444e334027c1 cached
12 files
369.2 KB
119.6k tokens
11 symbols
1 requests
Download .txt
Showing preview only (380K chars total). Download the full file or copy to clipboard to get everything.
Repository: yuaotian/go-cursor-help
Branch: master
Commit: 444e334027c1
Files: 12
Total size: 369.2 KB

Directory structure:
gitextract_anthe1ep/

├── .github/
│   └── workflows/
│       └── auto-tag-release.yml
├── .gitignore
├── LICENSE
├── README.md
├── README_CN.md
├── README_JP.md
└── scripts/
    ├── hook/
    │   ├── cursor_hook.js
    │   ├── inject_hook_unix.sh
    │   └── inject_hook_win.ps1
    └── run/
        ├── cursor_linux_id_modifier.sh
        ├── cursor_mac_id_modifier.sh
        └── cursor_win_id_modifier.ps1

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

================================================
FILE: .github/workflows/auto-tag-release.yml
================================================
# This workflow requires Ubuntu 22.04 or 24.04

name: Auto Tag & Release

on:
  push:
    branches:
      - master
      - main
    tags:
      - "v*"
    paths-ignore:
      - "**.md"
      - "LICENSE"
      - ".gitignore"
  workflow_call: {}

permissions:
  contents: write
  packages: write
  actions: write

jobs:
  pre_job:
    runs-on: ubuntu-22.04
    outputs:
      should_skip: ${{ steps.skip_check.outputs.should_skip }}
    steps:
      - id: skip_check
        uses: fkirc/skip-duplicate-actions@v5.3.0
        with:
          cancel_others: "true"
          concurrent_skipping: "same_content"

  auto-tag-release:
    needs: pre_job
    if: |
      needs.pre_job.outputs.should_skip != 'true' ||
      startsWith(github.ref, 'refs/tags/v')
    runs-on: ubuntu-22.04
    timeout-minutes: 15
    outputs:
      version: ${{ steps.get_latest_tag.outputs.version }}
    concurrency:
      group: ${{ github.workflow }}-${{ github.ref }}
      cancel-in-progress: true

    steps:
      - name: Checkout
        uses: actions/checkout@v3
        with:
          fetch-depth: 0
          lfs: true
          submodules: recursive

      - name: Setup Go
        uses: actions/setup-go@v3
        with:
          go-version: "1.21"
          check-latest: true
          cache: true

      - name: Cache
        uses: actions/cache@v3
        with:
          path: |
            ~/.cache/go-build
            ~/go/pkg/mod
            ~/.cache/git
          key: ${{ runner.os }}-build-${{ hashFiles('**/go.sum') }}
          restore-keys: |
            ${{ runner.os }}-build-
            ${{ runner.os }}-

      # 只在非tag推送时执行自动打tag
      - name: Get latest tag
        if: ${{ !startsWith(github.ref, 'refs/tags/v') }}
        id: get_latest_tag
        run: |
          set -euo pipefail
          git fetch --tags --force || {
            echo "::error::Failed to fetch tags"
            exit 1
          }
          latest_tag=$(git tag -l 'v*' --sort=-v:refname | head -n 1)
          if [ -z "$latest_tag" ]; then
            new_version="v0.1.0"
          else
            major=$(echo $latest_tag | cut -d. -f1)
            minor=$(echo $latest_tag | cut -d. -f2)
            patch=$(echo $latest_tag | cut -d. -f3)
            new_patch=$((patch + 1))
            new_version="$major.$minor.$new_patch"
          fi
          echo "version=$new_version" >> "$GITHUB_OUTPUT"
          echo "Generated version: $new_version"

      - name: Validate version
        if: ${{ !startsWith(github.ref, 'refs/tags/v') }}
        run: |
          set -euo pipefail
          new_tag="${{ steps.get_latest_tag.outputs.version }}"
          echo "Validating version: $new_tag"
          if [[ ! $new_tag =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
            echo "::error::Invalid version format: $new_tag"
            exit 1
          fi
          major=$(echo $new_tag | cut -d. -f1 | tr -d 'v')
          minor=$(echo $new_tag | cut -d. -f2)
          patch=$(echo $new_tag | cut -d. -f3)
          if [[ $major -gt 99 || $minor -gt 99 || $patch -gt 999 ]]; then
            echo "::error::Version numbers out of valid range"
            exit 1
          fi
          echo "Version validation passed"

      - name: Create new tag
        if: ${{ !startsWith(github.ref, 'refs/tags/v') }}
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: |
          new_tag=${{ steps.get_latest_tag.outputs.version }}
          git config --global user.name 'github-actions[bot]'
          git config --global user.email 'github-actions[bot]@users.noreply.github.com'
          git tag -a $new_tag -m "Release $new_tag"
          git push origin $new_tag

      # 在 Run GoReleaser 之前添加配置检查步骤
      - name: Check GoReleaser config
        run: |
          if [ ! -f ".goreleaser.yml" ] && [ ! -f ".goreleaser.yaml" ]; then
            echo "::error::GoReleaser configuration file not found"
            exit 1
          fi

      # 添加依赖检查步骤
      - name: Check Dependencies
        run: |
          go mod verify
          go mod download
          # 如果使用 vendor 模式,则执行以下命令
          if [ -d "vendor" ]; then
            go mod vendor
          fi

      # 添加构建环境准备步骤
      - name: Prepare Build Environment
        run: |
          echo "Building version: ${VERSION:-development}"
          echo "GOOS=${GOOS:-$(go env GOOS)}" >> $GITHUB_ENV
          echo "GOARCH=${GOARCH:-$(go env GOARCH)}" >> $GITHUB_ENV
          echo "GO111MODULE=on" >> $GITHUB_ENV

      # 添加清理步骤
      - name: Cleanup workspace
        run: |
          rm -rf /tmp/go/
          rm -rf .cache/
          rm -rf dist/
          git clean -fdx
          git status

      # 修改 GoReleaser 步骤
      - name: Run GoReleaser
        if: ${{ startsWith(github.ref, 'refs/tags/v') || (success() && steps.get_latest_tag.outputs.version != '') }}
        uses: goreleaser/goreleaser-action@v3
        with:
          distribution: goreleaser
          version: latest
          args: release --clean --timeout 60m
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          VERSION: ${{ steps.get_latest_tag.outputs.version }}
          CGO_ENABLED: 0
          GOPATH: /tmp/go
          GOROOT: ${{ env.GOROOT }}
          GOCACHE: /tmp/.cache/go-build
          GOMODCACHE: /tmp/go/pkg/mod
          GORELEASER_DEBUG: 1
          GORELEASER_CURRENT_TAG: ${{ steps.get_latest_tag.outputs.version }}
          # 添加额外的构建信息
          BUILD_TIME: ${{ steps.get_latest_tag.outputs.version }}
          BUILD_COMMIT: ${{ github.sha }}

      # 优化 vendor 同步步骤
      - name: Sync vendor directory
        run: |
          echo "Syncing vendor directory..."
          go mod tidy
          go mod vendor
          go mod verify
          # 验证 vendor 目录
          if [ -d "vendor" ]; then
            echo "Verifying vendor directory..."
            go mod verify
            # 检查是否有未跟踪的文件
            if [ -n "$(git status --porcelain vendor/)" ]; then
              echo "Warning: Vendor directory has uncommitted changes"
              git status vendor/
            fi
          fi

      # 添加错误检查步骤
      - name: Check GoReleaser Output
        if: failure()
        run: |
          echo "::group::GoReleaser Debug Info"
          cat dist/artifacts.json || true
          echo "::endgroup::"

          echo "::group::GoReleaser Config"
          cat .goreleaser.yml
          echo "::endgroup::"

          echo "::group::Environment Info"
          go version
          go env
          echo "::endgroup::"

      - name: Set Release Version
        if: startsWith(github.ref, 'refs/tags/v')
        run: |
          echo "VERSION=${GITHUB_REF#refs/tags/}" >> $GITHUB_ENV

      # 改进验证步骤
      - name: Verify Release
        if: ${{ startsWith(github.ref, 'refs/tags/v') || (success() && steps.get_latest_tag.outputs.version != '') }}
        run: |
          echo "Verifying release artifacts..."
          if [ ! -d "dist" ]; then
            echo "::error::Release artifacts not found"
            exit 1
          fi
          # 验证生成的二进制文件
          for file in dist/cursor-id-modifier_*; do
            if [ -f "$file" ]; then
              echo "Verifying: $file"
              if [[ "$file" == *.exe ]]; then
                # Windows 二进制文件检查
                if ! [ -x "$file" ]; then
                  echo "::error::$file is not executable"
                  exit 1
                fi
              else
                # Unix 二进制文件检查
                if ! [ -x "$file" ]; then
                  echo "::error::$file is not executable"
                  exit 1
                fi
              fi
            fi
          done

      - name: Notify on failure
        if: failure()
        run: |
          echo "::error::Release process failed"

      # 修改构建摘要步骤
      - name: Build Summary
        if: always()
        run: |
          echo "## Build Summary" >> $GITHUB_STEP_SUMMARY
          echo "- Go Version: $(go version)" >> $GITHUB_STEP_SUMMARY
          echo "- Release Version: ${VERSION:-N/A}" >> $GITHUB_STEP_SUMMARY
          echo "- GPG Signing: Disabled" >> $GITHUB_STEP_SUMMARY
          echo "- Build Status: ${{ job.status }}" >> $GITHUB_STEP_SUMMARY

          if [ -d "dist" ]; then
            echo "### Generated Artifacts" >> $GITHUB_STEP_SUMMARY
            ls -lh dist/ | awk '{print "- "$9" ("$5")"}' >> $GITHUB_STEP_SUMMARY
          fi


================================================
FILE: .gitignore
================================================
# Compiled binary
/cursor-id-modifier
/cursor-id-modifier.exe

# Build output directories
bin/
dist/

# Go specific
go.sum
go/
.cache/

# IDE and editor files
.vscode/
.idea/
*.swp
*.swo

# OS specific
.DS_Store
Thumbs.db

# Build and release artifacts
releases/
*.syso
*.exe
*.exe~
*.dll
*.so
*.dylib

# Test files
*.test
*.out
coverage.txt

# Temporary files
*.tmp
*~
*.bak
*.log

.cunzhi*/
.sanshu*/
docs/

================================================
FILE: LICENSE
================================================
MIT License

Copyright (c) 2024 dacrab

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE. 

================================================
FILE: README.md
================================================
# 🚀 Cursor Free Trial Reset Tool

<div align="center">

[![Release](https://img.shields.io/github/v/release/yuaotian/go-cursor-help?style=flat-square&logo=github&color=blue)](https://github.com/yuaotian/go-cursor-help/releases/latest)
[![License](https://img.shields.io/badge/license-MIT-blue.svg?style=flat-square&logo=bookstack)](https://github.com/yuaotian/go-cursor-help/blob/master/LICENSE)
[![Stars](https://img.shields.io/github/stars/yuaotian/go-cursor-help?style=flat-square&logo=github)](https://github.com/yuaotian/go-cursor-help/stargazers)

[🌟 English](README.md) | [🌏 中文](README_CN.md) | [🌏 日本語](README_JP.md)

<img src="/img/cursor.png" alt="Cursor Logo" width="120"/>

</div>

---

<div align="center">

## ⚡️ [Flash Sale] Cursor Pro High‑Credit Accounts

<img src="https://img.shields.io/badge/🔥_Private_&_Exclusive-30_Days_Stable-FF6B6B?style=for-the-badge" alt="Private & Exclusive"/> <img src="https://img.shields.io/badge/💎_Legit_Top--up-NOT_Cracked-4ECDC4?style=for-the-badge" alt="Legit Top-up"/> <img src="https://img.shields.io/badge/⭐_Official_Account-Full_Warranty-45B7D1?style=for-the-badge" alt="Official Account"/>

> 💡 Get **$20 ~ $40+** usage value for only **$15**! | 📖 [Official Pricing Reference](https://cursor.com/cn/docs/account/pricing)

<!-- ==================== 📦 Cursor Product Plans Overview ==================== -->

<div align="center">

### 🗓️ MONTHLY PLAN (STANDARD)

> 🚀 **Cursor Pro Monthly** | 💰 **Price: $15** (Official:  $20~$40+)

| 📋 Specs | 📅 Validity | 🛡️ Warranty |
| :---: | :---: | :---: |
| Standard Pro features. Good for daily usage. | ~30 Days | 7-Day Warranty (Pro-rated refund) |

**(⚠️ Best value for steady developers)**

</div>

---


| Type | Plan | 💰 Price | 📊 Official | 💎 Total Value / Note |
|:---:|:---|:---:|:---:|:---|
| **🚀 Pro** | **Cursor Pro Monthly** 🗓️ `STANDARD` |  $15 | $20~$40+ | **Standard Pro features** (7-Day Warranty, Pro-rated refund) |
| **🎯 Limited** | **7-Day Pass $100** 🏷️ |  $30 | $100 | 7-Day Exclusive $100 Credit, Official Billing, Daily Support |
| **🎯 Limited** | **7-Day Pass $500** 💎 |  $150 | $500 | 7-Day Exclusive $500 Credit, High-Intensity Dev |
| **🎯 Limited** | **7-Day Pass $1000** 🔥 |  $350 | $1000 | 7-Day Exclusive $1000 Credit, Ultra-High Intensity |
| **🆕 Basic** | **Cursor Trial Acct** | **$5** /each | — | Guaranteed working, Bulk discount |
| **🆕 Basic** | **Gemini 3.0 Pro** 💎 | $50 | — | 1-Year Sub, Stable Google Acct, 3-Day Warranty |

> ℹ️ **Value Note**: Member plan total value = Base Credits + Rewards + Overdraft (monthly resets apply).

<details>
<summary>📋 <b>Product Details</b> (Click to expand)</summary>

<br>

---



#### 🏷️ 7-Day Business Pass Series Details
> **⚠️ Important: The 7-Day Pass is valid for exactly 7 days (from delivery). Account auto-deleted upon expiration!**

| Version | Credit | Price | Description |
|:---|:---|:---|:---|
| **$100 Pass** | $100 | **¥210** / $30 | 7-Day Exclusive $100 Credit, Official Billing, Daily Support |
| **$500 Pass** | $500 | **¥1050** / $150 | 7-Day Exclusive $500 Credit, Best for High-Intensity Dev |
| **$1000 Pass** | $1000 | **¥2450** / $350 | 7-Day Exclusive $1000 Credit, Ultra-High Intensity Dev |

| General Info | Content |
|:---|:---|
| **Service** | Cursor Official Business Member - 7-Day Weekly Pass |
| **Official Benefits** | Private Exclusive Official Account, Full Access, No Speed Limit |
| **Usage Limits** | Official usage-based billing, stops when credits depleted. BYO Network Accelerator required |

---

#### 💳 Cursor Trial Account Details
| Item | Description |
|:---|:---|
| **Delivery Format** | `Account ---- Cursor Password ---- Email Password ---- Long-term cookies` |
| **Warranty** | Check within **1 hour** of receipt. No support after timeout |
| **Login URL** | cursor.com (Direct Login) |

---

#### 💎 Gemini 3.0 Pro Details
| Item | Description |
|:---|:---|
| **Description** | 3-Day Warranty. Super stable Google accounts (6mo-1yr+). Quality far exceeds temporary email accounts. Suitable even for GCP |
| **Account Format** | `Account----Password----Recovery Email----2FA` |
| **Instructions** | ① Immediately bind your own recovery email, password, and phone number after login ② **Important**: Keep using the same IP address for the first 3 days |

</details>

---

<!-- ==================== 📢 Purchase Notice & Contact ==================== -->

| ⚠️ **Before You Buy** | 📱 **Contact** |
|:---|:---|
| 💎 Legit top-up, private account | <img src="https://img.shields.io/badge/Telegram-2CA5E0?style=flat-square&logo=telegram&logoColor=white"/> [@yuaotian](https://t.me/yuaotian) |
| ⏱️ Valid 25–30 days \| 💻 Recommended ≤3 devices | <img src="https://img.shields.io/badge/WeChat-07C160?style=flat-square&logo=wechat&logoColor=white"/> `JavaRookie666` |
| 🛡️ 7-day warranty (replacement / pro-rated refund) | |

---

### 📢 Advertising Space

> 🔥 **Ad Space Available** - Contact for partnership opportunities
>
> 📧 Contact: Telegram [@yuaotian](https://t.me/yuaotian) | WeChat: `JavaRookie666`

---

</div>

> ⚠️ **IMPORTANT NOTICE**
> 
> This tool currently supports:
> - ✅ Windows: Latest 2.x.x versions (Supported)
> - ✅ Mac/Linux: Latest 2.x.x versions (Supported, feedback welcome)
>
> Please check your Cursor version before using this tool.

---

### 🚀 One-Click Solution

<details open>
<summary><b>Global Users</b></summary>

**macOS**

```bash
curl -fsSL https://raw.githubusercontent.com/yuaotian/go-cursor-help/refs/heads/master/scripts/run/cursor_mac_id_modifier.sh -o ./cursor_mac_id_modifier.sh && sudo bash ./cursor_mac_id_modifier.sh && rm ./cursor_mac_id_modifier.sh
```

**Linux**

```bash
curl -fsSL https://raw.githubusercontent.com/yuaotian/go-cursor-help/refs/heads/master/scripts/run/cursor_linux_id_modifier.sh | sudo bash 
```

> **Note for Linux users:** The script attempts to find your Cursor installation by checking common paths (`/usr/bin`, `/usr/local/bin`, `$HOME/.local/bin`, `/opt/cursor`, `/snap/bin`), using the `which cursor` command, and searching within `/usr`, `/opt`, and `$HOME/.local`. If Cursor is installed elsewhere or not found via these methods, the script may fail. Ensure Cursor is accessible via one of these standard locations or methods.

**Windows**

```powershell
irm https://raw.githubusercontent.com/yuaotian/go-cursor-help/refs/heads/master/scripts/run/cursor_win_id_modifier.ps1 | iex
```

**Tip (Windows):** If you suspect a cached old script (mirror/proxy cache), append a timestamp query parameter to bypass cache:

```powershell
irm "https://raw.githubusercontent.com/yuaotian/go-cursor-help/refs/heads/master/scripts/run/cursor_win_id_modifier.ps1?$(Get-Date -Format yyyyMMddHHmmss)" | iex
```



</details>


<details open>
<summary><b>China Users (Recommended)</b></summary>

**macOS**

```bash
curl -fsSL https://wget.la/https://raw.githubusercontent.com/yuaotian/go-cursor-help/refs/heads/master/scripts/run/cursor_mac_id_modifier.sh -o ./cursor_mac_id_modifier.sh && sudo bash ./cursor_mac_id_modifier.sh && rm ./cursor_mac_id_modifier.sh
```

**Linux**

```bash
curl -fsSL https://wget.la/https://raw.githubusercontent.com/yuaotian/go-cursor-help/refs/heads/master/scripts/run/cursor_linux_id_modifier.sh | sudo bash
```

**Windows**

```powershell
irm https://wget.la/https://raw.githubusercontent.com/yuaotian/go-cursor-help/refs/heads/master/scripts/run/cursor_win_id_modifier.ps1 | iex
```

**Tip (Windows):** If the mirror caches old content, append `?$(Get-Date -Format yyyyMMddHHmmss)` to the URL:

```powershell
irm "https://wget.la/https://raw.githubusercontent.com/yuaotian/go-cursor-help/refs/heads/master/scripts/run/cursor_win_id_modifier.ps1?$(Get-Date -Format yyyyMMddHHmmss)" | iex
```

</details>


<div align="center">
<img src="img/run_success.png" alt="Run Success" width="600"/>
</div>

<details open>
<summary><b>Windows Terminal Run and Configuration</b></summary>

#### How to Open Administrator Terminal in Windows:

##### Method 1: Using Win + X Shortcut
```md
1. Press Win + X key combination
2. Select one of these options from the menu:
   - "Windows PowerShell (Administrator)"
   - "Windows Terminal (Administrator)"
   - "Terminal (Administrator)"
   (Options may vary depending on Windows version)
```

##### Method 2: Using Win + R Run Command
```md
1. Press Win + R key combination
2. Type powershell or pwsh in the Run dialog
3. Press Ctrl + Shift + Enter to run as administrator
   or type in the opened window: Start-Process pwsh -Verb RunAs
4. Enter the reset script in the administrator terminal:

irm https://wget.la/https://raw.githubusercontent.com/yuaotian/go-cursor-help/refs/heads/master/scripts/run/cursor_win_id_modifier.ps1 | iex
```

For the enhanced version:
```powershell
irm https://wget.la/https://raw.githubusercontent.com/yuaotian/go-cursor-help/refs/heads/master/scripts/run/cursor_win_id_modifier.ps1 | iex
```

##### Method 3: Using Search
>![Search PowerShell](img/pwsh_1.png)
>
>Type pwsh in the search box, right-click and select "Run as administrator"
>![Run as Administrator](img/pwsh_2.png)

Enter the reset script in the administrator terminal:
```powershell
irm https://wget.la/https://raw.githubusercontent.com/yuaotian/go-cursor-help/refs/heads/master/scripts/run/cursor_win_id_modifier.ps1 | iex
```

For the enhanced version:
```powershell
irm https://wget.la/https://raw.githubusercontent.com/yuaotian/go-cursor-help/refs/heads/master/scripts/run/cursor_win_id_modifier.ps1 | iex
```

### 🔧 PowerShell Installation Guide 

If PowerShell is not installed on your system, you can install it using one of these methods:

#### Method 1: Install via Winget (Recommended)

1. Open Command Prompt or PowerShell
2. Run the following command:
```powershell
winget install --id Microsoft.PowerShell --source winget
```

#### Method 2: Manual Installation

1. Download the installer for your system:
   - [PowerShell-7.4.6-win-x64.msi](https://github.com/PowerShell/PowerShell/releases/download/v7.4.6/PowerShell-7.4.6-win-x64.msi) (64-bit systems)
   - [PowerShell-7.4.6-win-x86.msi](https://github.com/PowerShell/PowerShell/releases/download/v7.4.6/PowerShell-7.4.6-win-x86.msi) (32-bit systems)
   - [PowerShell-7.4.6-win-arm64.msi](https://github.com/PowerShell/PowerShell/releases/download/v7.4.6/PowerShell-7.4.6-win-arm64.msi) (ARM64 systems)

2. Double-click the downloaded installer and follow the installation prompts

> 💡 If you encounter any issues, please refer to the [Microsoft Official Installation Guide](https://learn.microsoft.com/en-us/powershell/scripting/install/installing-powershell-on-windows)

</details>

#### Windows 安装特性:

- 🔍 Automatically detects and uses PowerShell 7 if available
- 🛡️ Requests administrator privileges via UAC prompt
- 📝 Falls back to Windows PowerShell if PS7 isn't found
- 💡 Provides manual instructions if elevation fails

That's it! The script will:

1. ✨ Install the tool automatically
2. 🔄 Reset your Cursor trial immediately

### 📦 Manual Installation

> Download the appropriate file for your system from [releases](https://github.com/yuaotian/go-cursor-help/releases/latest)

<details>
<summary>Windows Packages</summary>

- 64-bit: `cursor-id-modifier_windows_x64.exe`
- 32-bit: `cursor-id-modifier_windows_x86.exe`
</details>

<details>
<summary>macOS Packages</summary>

- Intel: `cursor-id-modifier_darwin_x64_intel`
- M1/M2: `cursor-id-modifier_darwin_arm64_apple_silicon`
</details>

<details>
<summary>Linux Packages</summary>

- 64-bit: `cursor-id-modifier_linux_x64`
- 32-bit: `cursor-id-modifier_linux_x86`
- ARM64: `cursor-id-modifier_linux_arm64`
</details>

### 🔧 Technical Details

<details>
<summary><b>Configuration Files</b></summary>

The program modifies Cursor's `storage.json` config file located at:

- Windows: `%APPDATA%\Cursor\User\globalStorage\storage.json`
- macOS: `~/Library/Application Support/Cursor/User/globalStorage/storage.json`
- Linux: `~/.config/Cursor/User/globalStorage/storage.json`
</details>

<details>
<summary><b>Modified Fields</b></summary>

The tool generates new unique identifiers for:

- `telemetry.machineId`
- `telemetry.macMachineId`
- `telemetry.devDeviceId`
- `telemetry.sqmId`
</details>

<details>
<summary><b>Manual Auto-Update Disable</b></summary>

Windows users can manually disable the auto-update feature:

1. Close all Cursor processes
2. Delete directory: `C:\Users\username\AppData\Local\cursor-updater`
3. Create a file with the same name: `cursor-updater` (without extension)

macOS/Linux users can try to locate similar `cursor-updater` directory in their system and perform the same operation.

</details>

<details>
<summary><b>Safety Features</b></summary>

- ✅ Safe process termination
- ✅ Atomic file operations
- ✅ Error handling and recovery
</details>

<details>
<summary><b>Registry Modification Notice</b></summary>

> ⚠️ **Important: This tool modifies the Windows Registry**

#### Modified Registry
- Path: `Computer\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography`
- Key: `MachineGuid`

#### Potential Impact
Modifying this registry key may affect:
- Windows system's unique device identification
- Device recognition and authorization status of certain software
- System features based on hardware identification

#### Safety Measures
1. Automatic Backup
   - Original value is automatically backed up before modification
   - Backup location: `%APPDATA%\Cursor\User\globalStorage\backups`
   - Backup file format: `MachineGuid.backup_YYYYMMDD_HHMMSS`

2. Manual Recovery Steps
   - Open Registry Editor (regedit)
   - Navigate to: `Computer\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography`
   - Right-click on `MachineGuid`
   - Select "Modify"
   - Paste the value from backup file

#### Important Notes
- Verify backup file existence before modification
- Use backup file to restore original value if needed
- Administrator privileges required for registry modification
</details>

---

### 📚 Recommended Reading

- [Cursor Issues Collection and Solutions](https://mp.weixin.qq.com/s/pnJrH7Ifx4WZvseeP1fcEA)
- [AI Universal Development Assistant Prompt Guide](https://mp.weixin.qq.com/s/PRPz-qVkFJSgkuEKkTdzwg)

---

## 💬 Feedback & Suggestions

We value your feedback on the new enhanced script! If you've tried the `cursor_win_id_modifier.ps1` script, please share your experience:

- 🐛 **Bug Reports**: Found any issues? Let us know!
- 💡 **Feature Suggestions**: Have ideas for improvements?
- ⭐ **Success Stories**: Share how the tool helped you!
- 🔧 **Technical Feedback**: Performance, compatibility, or usability insights

Your feedback helps us improve the tool for everyone. Feel free to open an issue or contribute to the project!

---

##  Support

<div align="center">
<b>If you find this helpful, consider buying me a spicy gluten snack (Latiao) as appreciation~ 💁☕️</b>
<table>
<tr>

<td align="center">
<b>微信赞赏</b><br>
<img src="img/wx_zsm2.png" width="500" alt="微信赞赏码"><br>
<small>要到饭咧?啊咧?啊咧?不给也没事~ 请随意打赏</small>
</td>
<td align="center">
<b>支付宝赞赏</b><br>
<img src="img/alipay.png" width="500" alt="支付宝赞赏码"><br>
<small>如果觉得有帮助,来包辣条犒劳一下吧~</small>
</td>
<td align="center">
<b>Alipay</b><br>
<img src="img/alipay_scan_pay.jpg" width="500" alt="Alipay"><br>
<em>1 Latiao = 1 AI thought cycle</em>
</td>
<td align="center">
<b>WeChat</b><br>
<img src="img/qun-22.jpg" width="500" alt="WeChat"><br>
<em>二维码7天内(3月6日前前)有效,过期请加微信或者公众号`煎饼果子卷AI`</em>
</td>
<!-- <td align="center">
<b>ETC</b><br>
<img src="img/etc.png" width="100" alt="ETC Address"><br>
ETC: 0xa2745f4CD5d32310AC01694ABDB28bA32D125a6b
</td>
<td align="center"> -->
</td>
</tr>
</table>
</div>

### 💳 Payment Methods (Donate / Remove Ads)

- 🪙 **USDT (Tether)**
  - 🔴 TRC-20 (Tron): `TFbJnoY5Lep5ZrDwBbT8rV1i8xR4ZhX53k`
  - 🟡 Polygon / BSC / Arbitrum: `0x44f8925b9f93b3d6da8d5ad26a3516e3e652cc88`
- 🟦 **Litecoin (LTC)**: `LVrigKxtWfPymMRtRqL3z2eZxfncR3dPV7`

---

## ⭐ Project Stats

<div align="center">

[![Star History Chart](https://api.star-history.com/svg?repos=yuaotian/go-cursor-help&type=Date)](https://star-history.com/#yuaotian/go-cursor-help&Date)

![Repobeats analytics image](https://repobeats.axiom.co/api/embed/ddaa9df9a94b0029ec3fad399e1c1c4e75755477.svg "Repobeats analytics image")

</div>

## 📄 License

<details>
<summary><b>MIT License</b></summary>

Copyright (c) 2024

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

</details>



================================================
FILE: README_CN.md
================================================
# 🚀 Cursor 免费试用重置工具

<div align="center">

[![Release](https://img.shields.io/github/v/release/yuaotian/go-cursor-help?style=flat-square&logo=github&color=blue)](https://github.com/yuaotian/go-cursor-help/releases/latest)
[![License](https://img.shields.io/badge/license-MIT-blue.svg?style=flat-square&logo=bookstack)](https://github.com/yuaotian/go-cursor-help/blob/master/LICENSE)
[![Stars](https://img.shields.io/github/stars/yuaotian/go-cursor-help?style=flat-square&logo=github)](https://github.com/yuaotian/go-cursor-help/stargazers)

[🌟 English](README.md) | [🌏 中文](README_CN.md) | [🌏 日本語](README_JP.md)

<img src="/img/cursor.png" alt="Cursor Logo" width="120"/>

</div>

---

<div align="center">

## ⚡️【限时特惠】Cursor 高额度成品号

<img src="https://img.shields.io/badge/🔥_独享专属-30天稳定-FF6B6B?style=for-the-badge" alt="独享专属"/> <img src="https://img.shields.io/badge/💎_正规充值-非破解试用-4ECDC4?style=for-the-badge" alt="正规充值"/> <img src="https://img.shields.io/badge/⭐_官方账号-全程质保-45B7D1?style=for-the-badge" alt="官方账号"/>

<div align="center">

> 💡 仅需 **¥105** 即可获得 **$20 ~ $40** 使用价值! | 📖 [官网定价参考](https://cursor.com/cn/docs/account/pricing)

#### 🗓️ 月付套餐(标准版)

> 🚀 **Cursor Pro 月付** | 💰 **售价: ¥105 / $15**(官方:  $20~$40)

| 📋 规格 | 📅 有效期 | 🛡️ 质保 |
| :---: | :---: | :---: |
| 标准 Pro 功能,满足日常开发需求 | ~30天 | 7天质保(支持按天退款) |

**(⚠️ 稳定开发者的最佳选择)**

</div>

<!-- ==================== 📦 Cursor 产品套餐一览 ==================== -->

| 类型 | 套餐 | 💰 售价 | 📊 官方价 | 💎 总价值 / 说明 |
|:---:|:---|:---:|:---:|:---|
| **🚀 Pro** | **Cursor Pro 月付** �️ `标准` | **¥105** / $15 | $20~$40 | **标准 Pro 功能**(7天质保,支持按天退款) |
| **🎯 限定** | **7天周卡 $100** 🏷️ | **¥210** / $30 | $100 | 7天独享 $100 额度,官方计费,按天售后 |
| **🎯 限定** | **7天周卡 $500** 💎 | **¥1050** / $150 | $500 | 7天独享 $500 额度,适合高强度开发 |
| **🎯 限定** | **7天周卡 $1000** 🔥 | **¥2450** / $350 | $1000 | 7天独享 $1000 额度,超高强度开发 |
| **🆕 基础** | **Cursor 试用号** | **$5** /个 | — | 保证可用,批量优惠 |
| **🆕 基础** | **Gemini 3.0 Pro** 💎 | **¥350** / $50 | — | 一年订阅,稳定谷歌老号,质保3天 |

> ℹ️ **价值说明**:会员套餐总价值 = Base Credits(基础额度)+ Rewards(奖励)+ Overdraft(透支),每月重置。

<details>
<summary>📋 <b>各产品详细说明</b>(点击展开)</summary>

<br>


---

#### 🏷️ 7天商业版周卡系列详情
> **⚠️ 重要提醒:7天周卡系列有效期为7天整(从发货时间起算),到期自动删号!**

| 版本 | 额度 | 售价 | 说明 |
|:---|:---|:---|:---|
| **$100版** | $100 | **¥210** / $30 | 7天独享 $100 额度,官方计费,按天售后 |
| **$500版** | $500 | **¥1050** / $150 | 7天独享 $500 额度,高强度开发首选 |
| **$1000版** | $1000 | **¥2450** / $350 | 7天独享 $1000 额度,超高强度开发 |

| 通用说明 | 内容 |
|:---|:---|
| **服务内容** | Cursor 官网商业版会员 - 7天周卡 |
| **官方权益** | 个人独享官方账号,全功能开放,无限速 |
| **使用限制** | 官方按量计费,额度用完即止。需自备网络加速工具 |

---

#### 💳 Cursor 试用号详情
| 项目 | 说明 |
|:---|:---|
| **发货格式** | `账号 ---- Cursor密码 ---- 邮箱密码 ---- 长效cookies` |
| **质保说明** | 质保到手,请在 **1小时内** 检查并反馈,超时不提供售后 |
| **登录地址** | cursor.com(直登账号) |

---

#### 💎 Gemini 3.0 Pro 详情
| 项目 | 说明 |
|:---|:---|
| **商品描述** | 质保三天,超级稳定的谷歌号注册(6月-1年以上),品质远超市面短效邮箱,开GCP都没问题 |
| **账号格式** | `账号----密码----辅助邮箱----2fa` |
| **使用须知** | ① 登录后第一时间绑定自己的辅助邮箱、密码及手机号 ② **切忌**:三天内尽量保持使用同一个IP登录 |

</details>

---

<!-- ==================== 📢 购买须知 & 联系方式 ==================== -->

| ⚠️ **购买须知** | 📱 **联系方式** |
|:---|:---|
| 💎 正规真金充值,独享账号 | <img src="https://img.shields.io/badge/Telegram-2CA5E0?style=flat-square&logo=telegram&logoColor=white"/> [@yuaotian](https://t.me/yuaotian) |
| ⏱️ 有效期 25–30 天 \| 💻 建议 ≤3 台设备 | <img src="https://img.shields.io/badge/WeChat-07C160?style=flat-square&logo=wechat&logoColor=white"/> `JavaRookie666` |
| 🛡️ 7天质保(换号 / 按天退款) | |

---

### 📢 招聘广告位

> 🔥 **广告位招租** - 欢迎联系洽谈合作
>
> 📧 联系方式:Telegram [@yuaotian](https://t.me/yuaotian) | WeChat: `JavaRookie666`

---

</div>

> ⚠️ **重要提示**
> 
> 本工具当前支持版本:
> - ✅ Windows: 最新的 2.x.x 版本(已支持)
> - ✅ Mac/Linux: 最新的 2.x.x 版本(已支持,欢迎测试并反馈问题)
 
> 使用前请确认您的 Cursor 版本。

---


### 🚀 系统支持

<table>
<tr>
<td>

**Windows** ✅

- x64 & x86

</td>
<td>

**macOS** ✅

- Intel & M-series

</td>
<td>

**Linux** ✅

- x64 & ARM64

</td>
</tr>
</table>



### 🚀 一键解决方案

<details open>
<summary><b>国内用户(推荐)</b></summary>

**macOS**

```bash
curl -fsSL https://wget.la/https://raw.githubusercontent.com/yuaotian/go-cursor-help/refs/heads/master/scripts/run/cursor_mac_id_modifier.sh -o ./cursor_mac_id_modifier.sh && sudo bash ./cursor_mac_id_modifier.sh && rm ./cursor_mac_id_modifier.sh
```

**Linux**

```bash
curl -fsSL https://wget.la/https://raw.githubusercontent.com/yuaotian/go-cursor-help/refs/heads/master/scripts/run/cursor_linux_id_modifier.sh | sudo bash
```

> **Linux 用户请注意:** 该脚本通过检查常用路径(`/usr/bin`, `/usr/local/bin`, `$HOME/.local/bin`, `/opt/cursor`, `/snap/bin`)、使用 `which cursor` 命令以及在 `/usr`、`/opt` 和 `$HOME/.local` 目录内搜索,来尝试定位您的 Cursor 安装。如果 Cursor 安装在其他位置或通过这些方法无法找到,脚本可能会失败。请确保可以通过这些标准位置或方法之一访问到 Cursor。

**Windows**

```powershell
irm https://wget.la/https://raw.githubusercontent.com/yuaotian/go-cursor-help/refs/heads/master/scripts/run/cursor_win_id_modifier.ps1 | iex
```

**缓存提示(Windows):** 如果镜像/代理缓存导致拉到旧脚本,可在 URL 末尾追加时间戳参数绕缓存(推荐 raw + 时间戳):  

```powershell
irm "https://raw.githubusercontent.com/yuaotian/go-cursor-help/refs/heads/master/scripts/run/cursor_win_id_modifier.ps1?$(Get-Date -Format yyyyMMddHHmmss)" | iex
```

如果必须继续使用 `wget.la` 镜像,同样可以在镜像 URL 末尾追加时间戳参数:  

```powershell
irm "https://wget.la/https://raw.githubusercontent.com/yuaotian/go-cursor-help/refs/heads/master/scripts/run/cursor_win_id_modifier.ps1?$(Get-Date -Format yyyyMMddHHmmss)" | iex
```


</details>

<div align="center">
<img src="img/run_success.png" alt="运行成功" width="600"/>
</div>


<details open>
<summary><b>Windows 管理员终端运行和手动安装</b></summary>

#### Windows 系统打开管理员终端的方法:

##### 方法一:使用 Win + X 快捷键
```md
1. 按下 Win + X 组合键
2. 在弹出的菜单中选择以下任一选项:
   - "Windows PowerShell (管理员)"
   - "Windows Terminal (管理员)" 
   - "终端(管理员)"
   (具体选项因Windows版本而异)
```

##### 方法二:使用 Win + R 运行命令
```md
1. 按下 Win + R 组合键
2. 在运行框中输入 powershell 或 pwsh
3. 按 Ctrl + Shift + Enter 以管理员身份运行
   或在打开的窗口中输入: Start-Process pwsh -Verb RunAs
4. 在管理员终端中输入以下重置脚本:

irm https://wget.la/https://raw.githubusercontent.com/yuaotian/go-cursor-help/refs/heads/master/scripts/run/cursor_win_id_modifier.ps1 | iex
```

增强版脚本:
```powershell
irm https://wget.la/https://raw.githubusercontent.com/yuaotian/go-cursor-help/refs/heads/master/scripts/run/cursor_win_id_modifier.ps1 | iex
```

##### 方法三:通过搜索启动
>![搜索 PowerShell](img/pwsh_1.png)
>
>在搜索框中输入 pwsh,右键选择"以管理员身份运行"
>![管理员运行](img/pwsh_2.png)

在管理员终端中输入重置脚本:
```powershell
irm https://wget.la/https://raw.githubusercontent.com/yuaotian/go-cursor-help/refs/heads/master/scripts/run/cursor_win_id_modifier.ps1 | iex
```

增强版脚本:
```powershell
irm https://wget.la/https://raw.githubusercontent.com/yuaotian/go-cursor-help/refs/heads/master/scripts/run/cursor_win_id_modifier.ps1 | iex
```

### 🔧 PowerShell 安装指南

如果您的系统没有安装 PowerShell,可以通过以下方法安装:

#### 方法一:使用 Winget 安装(推荐)

1. 打开命令提示符或 PowerShell
2. 运行以下命令:
```powershell
winget install --id Microsoft.PowerShell --source winget
```

#### 方法二:手动下载安装

1. 下载对应系统的安装包:
   - [PowerShell-7.4.6-win-x64.msi](https://github.com/PowerShell/PowerShell/releases/download/v7.4.6/PowerShell-7.4.6-win-x64.msi) (64位系统)
   - [PowerShell-7.4.6-win-x86.msi](https://github.com/PowerShell/PowerShell/releases/download/v7.4.6/PowerShell-7.4.6-win-x86.msi) (32位系统)
   - [PowerShell-7.4.6-win-arm64.msi](https://github.com/PowerShell/PowerShell/releases/download/v7.4.6/PowerShell-7.4.6-win-arm64.msi) (ARM64系统)

2. 双击下载的安装包,按提示完成安装

> 💡 如果仍然遇到问题,可以参考 [Microsoft 官方安装指南](https://learn.microsoft.com/zh-cn/powershell/scripting/install/installing-powershell-on-windows)

</details>

#### Windows 安装特性:

- 🔍 自动检测并使用 PowerShell 7(如果可用)
- 🛡️ 通过 UAC 提示请求管理员权限
- 📝 如果没有 PS7 则使用 Windows PowerShell
- 💡 如果提权失败会提供手动说明

完成后,脚本将:

1. ✨ 自动安装工具
2. 🔄 立即重置 Cursor 试用期

### 📦 手动安装

> 从 [releases](https://github.com/yuaotian/go-cursor-help/releases/latest) 下载适合您系统的文件

<details>
<summary>Windows 安装包</summary>

- 64 位: `cursor-id-modifier_windows_x64.exe`
- 32 位: `cursor-id-modifier_windows_x86.exe`
</details>

<details>
<summary>macOS 安装包</summary>

- Intel: `cursor-id-modifier_darwin_x64_intel`
- M1/M2: `cursor-id-modifier_darwin_arm64_apple_silicon`
</details>

<details>
<summary>Linux 安装包</summary>

- 64 位: `cursor-id-modifier_linux_x64`
- 32 位: `cursor-id-modifier_linux_x86`
- ARM64: `cursor-id-modifier_linux_arm64`
</details>

### 🔧 技术细节

<details>
<summary><b>注册表修改说明</b></summary>

> ⚠️ **重要提示:本工具会修改系统注册表**

#### 修改内容
- 路径:`计算机\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography`
- 项目:`MachineGuid`

#### 潜在影响
修改此注册表项可能会影响:
- Windows 系统对设备的唯一标识
- 某些软件的设备识别和授权状态
- 基于硬件标识的系统功能

#### 安全措施
1. 自动备份
   - 每次修改前会自动备份原始值
   - 备份保存在:`%APPDATA%\Cursor\User\globalStorage\backups`
   - 备份文件格式:`MachineGuid.backup_YYYYMMDD_HHMMSS`

2. 手动恢复方法
   - 打开注册表编辑器(regedit)
   - 定位到:`计算机\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography`
   - 右键点击 `MachineGuid`
   - 选择"修改"
   - 粘贴备份文件中的值

#### 注意事项
- 建议在修改前先确认备份文件的存在
- 如遇问题可通过备份文件恢复原始值
- 必须以管理员权限运行才能修改注册表
</details>

<details>
<summary><b>配置文件</b></summary>

程序修改 Cursor 的`storage.json`配置文件,位于:

- Windows: `%APPDATA%\Cursor\User\globalStorage\`
- macOS: `~/Library/Application Support/Cursor/User/globalStorage/`
- Linux: `~/.config/Cursor/User/globalStorage/`
</details>

<details>
<summary><b>修改字段</b></summary>

工具会生成新的唯一标识符:

- `telemetry.machineId`
- `telemetry.macMachineId`
- `telemetry.devDeviceId`
- `telemetry.sqmId`
</details>

<details>
<summary><b>手动禁用自动更新</b></summary>

Windows 用户可以手动禁用自动更新功能:

1. 关闭所有 Cursor 进程
2. 删除目录:`C:\Users\用户名\AppData\Local\cursor-updater`
3. 创建同名文件:`cursor-updater`(不带扩展名)

Linux用户可以尝试在系统中找到类似的`cursor-updater`目录进行相同操作。

MacOS用户按照以下步骤操作:

```bash
# 注意:经测试,此方法仅适用于0.45.11及以下版本,不支持0.46.*版本
# 关闭所有 Cursor 进程
pkill -f "Cursor"

# 备份app-update.yml并创建空的只读文件代替原文件
cd /Applications/Cursor.app/Contents/Resources
mv app-update.yml app-update.yml.bak
touch app-update.yml
chmod 444 app-update.yml

# 打开Cursor设置,将更新模式设置为"无",该步骤必须执行,否则Cursor依然会自动检查更新
# 步骤:Settings -> Application -> Update, 将Mode设置为none

# 注意: cursor-updater修改方法可能已失效。但为了以防万一,还是删除更新目录并创建阻止文件
rm -rf ~/Library/Application\ Support/Caches/cursor-updater
touch ~/Library/Application\ Support/Caches/cursor-updater
```
</details>

<details>
<summary><b>安全特性</b></summary>

- ✅ 安全的进程终止
- ✅ 原子文件操作
- ✅ 错误处理和恢复
</details>

<details>
<summary><b>重置 Cursor 免费试用</b></summary>

### 使用 `cursor_free_trial_reset.sh` 脚本

#### macOS

```bash
curl -fsSL https://raw.githubusercontent.com/yuaotian/go-cursor-help/refs/heads/master/scripts/run/cursor_free_trial_reset.sh -o ./cursor_free_trial_reset.sh && sudo bash ./cursor_free_trial_reset.sh && rm ./cursor_free_trial_reset.sh
```

#### Linux

```bash
curl -fsSL https://raw.githubusercontent.com/yuaotian/go-cursor-help/refs/heads/master/scripts/run/cursor_free_trial_reset.sh | sudo bash
```

#### Windows

```powershell
irm https://raw.githubusercontent.com/yuaotian/go-cursor-help/refs/heads/master/scripts/run/cursor_free_trial_reset.sh | iex
```

</details>

## 联系方式

<div align="center">
<table>
<tr>
<td align="center">
<b>个人微信</b><br>
<img src="img/wx_me.png" width="250" alt="作者微信"><br>
<b>微信:JavaRookie666</b>
</td>
<td align="center">
<b>微信交流群</b><br>
<img src="img/qun-22.jpg" width="500" alt="WeChat"><br>
<small>二维码7天内(3月6日前)有效,过期请加微信或者公众号`煎饼果子卷AI`</small>
</td>
<td align="center">
<b>公众号</b><br>
<img src="img/wx_public_2.png" width="250" alt="微信公众号"><br>
<small>获取更多AI开发资源</small>
</td>
<td align="center">
<b>微信赞赏</b><br>
<img src="img/wx_zsm2.png" width="500" alt="微信赞赏码"><br>
<small>要到饭咧?啊咧?啊咧?不给也没事~ 请随意打赏</small>
</td>
<td align="center">
<b>支付宝赞赏</b><br>
<img src="img/alipay.png" width="500" alt="支付宝赞赏码"><br>
<small>如果觉得有帮助,来包辣条犒劳一下吧~</small>
</td>
</tr>
</table>
</div>

### 💳 付款方式(捐赠)

- 🪙 **USDT(泰达币)**
  - 🔴 TRC-20(波场):`TFbJnoY5Lep5ZrDwBbT8rV1i8xR4ZhX53k`
  - 🟡 Polygon / BSC / Arbitrum:`0x44f8925b9f93b3d6da8d5ad26a3516e3e652cc88`
- 🟦 **莱特币(LTC)**:`LVrigKxtWfPymMRtRqL3z2eZxfncR3dPV7`


---

### 📚 推荐阅读

- [Cursor 异常问题收集和解决方案](https://mp.weixin.qq.com/s/pnJrH7Ifx4WZvseeP1fcEA)
- [AI 通用开发助手提示词指南](https://mp.weixin.qq.com/s/PRPz-qVkFJSgkuEKkTdzwg)

---

## 💬 反馈与建议

我们非常重视您对新增强脚本的反馈!如果您已经尝试了 `cursor_win_id_modifier.ps1` 脚本,请分享您的使用体验:

- 🐛 **错误报告**:发现任何问题?请告诉我们!
- 💡 **功能建议**:有改进想法?
- ⭐ **成功案例**:分享工具如何帮助到您!
- 🔧 **技术反馈**:性能、兼容性或易用性方面的见解

您的反馈帮助我们为所有人改进工具。欢迎提交issue或为项目做出贡献!

---

## ⭐ 项目统计

<div align="center">

[![Star History Chart](https://api.star-history.com/svg?repos=yuaotian/go-cursor-help&type=Date)](https://star-history.com/#yuaotian/go-cursor-help&Date)

![Repobeats analytics image](https://repobeats.axiom.co/api/embed/ddaa9df9a94b0029ec3fad399e1c1c4e75755477.svg "Repobeats analytics image")

</div>

## 📄 许可证

<details>
<summary><b>MIT 许可证</b></summary>

Copyright (c) 2024

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

</details>


================================================
FILE: README_JP.md
================================================
# 🚀 Cursor 無料試用リセットツール

<div align="center">

[![Release](https://img.shields.io/github/v/release/yuaotian/go-cursor-help?style=flat-square&logo=github&color=blue)](https://github.com/yuaotian/go-cursor-help/releases/latest)
[![License](https://img.shields.io/badge/license-MIT-blue.svg?style=flat-square&logo=bookstack)](https://github.com/yuaotian/go-cursor-help/blob/master/LICENSE)
[![Stars](https://img.shields.io/github/stars/yuaotian/go-cursor-help?style=flat-square&logo=github)](https://github.com/yuaotian/go-cursor-help/stargazers)

[🌟 English](README.md) | [🌏 中文](README_CN.md) | [🌏 日本語](README_JP.md)

<img src="https://ai-cursor.com/wp-content/uploads/2024/09/logo-cursor-ai-png.webp" alt="Cursor Logo" width="120"/>

</div>

---

<div align="center">

## ⚡️【フラッシュセール】Cursor 高クレジットアカウント

<img src="https://img.shields.io/badge/🔥_専用&独占-30日間安定-FF6B6B?style=for-the-badge" alt="専用&独占"/> <img src="https://img.shields.io/badge/💎_正規チャージ-クラック版ではない-4ECDC4?style=for-the-badge" alt="正規チャージ"/> <img src="https://img.shields.io/badge/⭐_公式アカウント-完全保証-45B7D1?style=for-the-badge" alt="公式アカウント"/>

> 💡 わずか **$15** で **$20 ~ $40** の利用価値を獲得! | 📖 [公式料金参考](https://cursor.com/cn/docs/account/pricing)

<!-- ==================== 📦 Cursor 製品プラン一覧 ==================== -->

### 🗓️ 月額プラン(スタンダード)

> 🚀 **Cursor Pro 月額** | 💰 **価格: $15**(公式:  $20~$40)

| 📋 スペック | 📅 有効期間 | 🛡️ 保証 |
| :---: | :---: | :---: |
| 標準Pro機能。日常開発に最適。 | ~30日間 | 7日間保証(日割り返金可) |

**(⚠️ 安定した開発者に最適)**

---

| タイプ | プラン | 💰 価格 | 📊 公式価格 | 💎 総価値 / 説明 |
|:---:|:---|:---:|:---:|:---|
| **🚀 Pro** | **Cursor Pro 月額** 🗓️ `スタンダード` | $15 |  $20~$40 | **標準Pro機能**(7日間保証、日割り返金可) |
| **🎯 限定** | **7日間パス $100** 🏷️ | **¥210** / $30 | $100 | 7日間専用 $100 クレジット、公式課金、日割りサポート |
| **🎯 限定** | **7日間パス $500** 💎 | **¥1050** / $150 | $500 | 7日間専用 $500 クレジット、高強度開発向け |
| **🎯 限定** | **7日間パス $1000** 🔥 | **¥2450** / $350 | $1000 | 7日間専用 $1000 クレジット、超高強度開発 |
| **🆕 基本** | **Cursor 試用アカウント** | **$5** /個 | — | 動作保証、大量購入割引 |
| **🆕 基本** | **Gemini 3.0 Pro** 💎 | **¥350** / $50 | — | 1年サブスク、安定Google垢、3日間保証 |

> ℹ️ **価値説明**:会員プラン総価値 = Base Credits(基本枠)+ Rewards(報酬)+ Overdraft(超過分)、月次リセットあり。

<details>
<summary>📋 <b>各製品の詳細説明</b>(クリックで展開)</summary>

<br>

---

#### 🗓️ Cursor Pro 月額詳細
| 項目 | 説明 |
|:---|:---|
| **商品名** | Cursor Pro 月額プラン |
| **価格** | $15(公式: $20) |
| **スペック** | 標準Pro機能。日常開発に最適。 |
| **有効期間** | ~30日間 |
| **保証** | 7日間保証(日割り返金可) |

**(⚠️ 安定した開発者に最適)**

---

#### 🏷️ 7天商業版周卡系列详情
> **⚠️ 重要提醒:7天周卡系列有效期为7天整(从发货时间起算),到期自动删号!**

| 版本 | 额度 | 售价 | 说明 |
|:---|:---|:---|:---|
| **$100版** | $100 | **¥210** / $30 | 7天独享 $100 额度,官方计费,按天售后 |
| **$500版** | $500 | **¥1050** / $150 | 7天独享 $500 额度,高强度开发首选 |
| **$1000版** | $1000 | **¥2450** / $350 | 7天独享 $1000 额度,超高强度开发 |

| 通用说明 | 内容 |
|:---|:---|
| **服务内容** | Cursor 官网商业版会员 - 7天周卡 |
| **官方权益** | 個人独享公式账号,全機能開放,無限速 |
| **使用限制** | 官方按量計費,額度用完即止。需自備網絡加速工具 |

---

#### 💳 Cursor 試用アカウント詳細
| 項目 | 説明 |
|:---|:---|
| **納品形式** | `アカウント ---- Cursorパスワード ---- メールパスワード ---- 長期Cookie` |
| **保証について** | 受け取り後 **1時間以内** に確認してください。時間を過ぎた場合はサポート対象外 |
| **ログインアドレス** | cursor.com(直接ログイン) |

---

#### 💎 Gemini 3.0 Pro 詳細
| 項目 | 説明 |
|:---|:---|
| **商品説明** | 3日間保証。超安定したGoogleアカウント(6ヶ月-1年以上)。品質は短期メールアドレスを大幅に上回る。GCP開設にも使える高品質 |
| **アカウント形式** | `アカウント----パスワード----予備メール----2FA` |
| **使用上の注意** | ① ログイン後すぐに自身の予備メール、パスワード、電話番号を紐付け ② **重要**:最初の3日間は同じIPアドレスでログインを維持 |

</details>

---

<!-- ==================== 📢 購入須知 & 連絡先 ==================== -->

| ⚠️ **購入前に** | 📱 **連絡先** |
|:---|:---|
| 💎 正規チャージ、専用アカウント | <img src="https://img.shields.io/badge/Telegram-2CA5E0?style=flat-square&logo=telegram&logoColor=white"/> [@yuaotian](https://t.me/yuaotian) |
| ⏱️ 有効期間 25〜30日 \| 💻 推奨 ≤3台 | <img src="https://img.shields.io/badge/WeChat-07C160?style=flat-square&logo=wechat&logoColor=white"/> `JavaRookie666` |
| 🛡️ 7日保証(交換 / 日割り返金) | |

---

### 📢 広告スペース

> 🔥 **広告枠募集中** - パートナーシップのお問い合わせ歓迎
>
> 📧 連絡先: Telegram [@yuaotian](https://t.me/yuaotian) | WeChat: `JavaRookie666`

---

</div>

> ⚠️ **重要なお知らせ**
> 
> このツールは現在以下のバージョンをサポートしています:
> - ✅ Windows: 最新の1.0.xバージョン(サポート済み)
> - ✅ Mac/Linux: 最新の1.0.xバージョン(サポート済み、フィードバック歓迎)
>
> このツールを使用する前に、Cursorのバージョンを確認してください。

<details open>
<summary><b>📦 バージョン履歴とダウンロード</b></summary>

<div class="version-card" style="background: linear-gradient(135deg, #6e8efb, #a777e3); border-radius: 8px; padding: 15px; margin: 10px 0; color: white;">

### 🌟 最新バージョン

[完全なバージョン履歴を見る]([CursorHistoryDown.md](https://github.com/oslook/cursor-ai-downloads?tab=readme-ov-file))

</div>

</details>

⚠️ **Cursorの一般的な解決策**
> 1.  Cursorを閉じ、アカウントからログアウトし、公式サイトの設定からアカウントを削除します(IPノードを更新:日本、シンガポール、アメリカ、香港など、低遅延を優先。必須ではありませんが条件が整えば変更してください。Windowsユーザーの場合はDNSキャッシュの更新をお勧めします:`ipconfig /flushdns`)
> Cursor公式サイトで現在のアカウントを削除します
> 手順:ユーザーアイコン->設定->左下のAdvanced▼->Delete Account
>
> 2.  マシンコードリセットスクリプトを実行します。下記のスクリプトアドレスを参照してください。
> 
> 3.  アカウントを再登録し、ログインして、Cursorを開くと、正常に使用できるようになります。
>
> 4.  代替案:ステップ[**3**]の後でもまだ使用できない場合、またはアカウント登録に失敗したり、アカウントを削除できないなどの問題が発生した場合、これは通常、ブラウザがターゲットサイトに識別または制限されている(リスク管理)ことを意味します。この場合、Edge、Google Chrome、Firefoxなど別のブラウザを試してみてください(または、ブラウザのフィンガープリント情報を変更またはランダム化できるブラウザの使用を検討してください)。


---

⚠️ **MACアドレス変更警告**
> 
> Macユーザーの皆様へ: このスクリプトにはMACアドレス変更機能が含まれています。以下の操作が行われます:
> - ネットワークインターフェースのMACアドレスを変更します
> - 変更前に元のMACアドレスをバックアップします
> - この変更により一時的にネットワーク接続が影響を受ける可能性があります
> - 実行中にこのステップをスキップすることができます
>

<details >
<summary><b>🔒 自動更新機能の無効化</b></summary>

> Cursorがサポートされていない新しいバージョンに自動的に更新されるのを防ぐために、自動更新機能を無効にすることができます。

#### 方法1: 組み込みスクリプトを使用する(推奨)

リセットツールを実行するとき、スクリプトは自動更新を無効にするかどうかを尋ねます:
```text
[質問] Cursorの自動更新機能を無効にしますか?
0) いいえ - デフォルト設定を維持(Enterキーを押す)
1) はい - 自動更新を無効にする
```

`1`を選択して無効化操作を自動的に完了します。

#### 方法2: 手動で無効化

**Windows:**
1. すべてのCursorプロセスを閉じます
2. ディレクトリを削除します: `%LOCALAPPDATA%\cursor-updater`
3. 同じ名前のファイルを作成します(拡張子なし)

**macOS:**
```bash
# 注意: テスト済みでは、この方法はバージョン0.45.11およびそれ以前のバージョンでのみ機能します。
# Cursorを閉じます
pkill -f "Cursor"
# app-update.ymlを空の読み取り専用ファイルに置き換えます
cd /Applications/Cursor.app/Contents/Resources
mv app-update.yml app-update.yml.bak
touch app-update.yml
chmod 444 app-update.yml

# 設定 -> アプリケーション -> 更新、モードをnoneに設定します。
# これを行わないと、Cursorは更新をチェックし続けます。

# 注意: cursor-updaterの変更方法はもはや有効ではないかもしれません
# いずれにせよ、更新ディレクトリを削除し、ブロックファイルを作成します
rm -rf ~/Library/Application\ Support/Caches/cursor-updater
touch ~/Library/Application\ Support/Caches/cursor-updater
```

**Linux:**
```bash
# Cursorを閉じます
pkill -f "Cursor"
# 更新ディレクトリを削除し、ブロックファイルを作成します
rm -rf ~/.config/cursor-updater
touch ~/.config/cursor-updater
```

> ⚠️ **注意:** 自動更新を無効にした後、新しいバージョンを手動でダウンロードしてインストールする必要があります。新しいバージョンが互換性があることを確認した後に更新することをお勧めします。

</details>

---

### 📝 説明

> これらのメッセージのいずれかに遭遇した場合:

#### 問題1: 試用アカウント制限 <p align="right"><a href="#issue1"><img src="https://img.shields.io/badge/Move%20to%20Solution-Blue?style=plastic" alt="Back To Top"></a></p>

```text
Too many free trial accounts used on this machine.
Please upgrade to pro. We have this limit in place
to prevent abuse. Please let us know if you believe
this is a mistake.
```

#### 問題2: APIキー制限 <p align="right"><a href="#issue2"><img src="https://img.shields.io/badge/Move%20to%20Solution-green?style=plastic" alt="Back To Top"></a></p>

```text
[New Issue]

Composer relies on custom models that cannot be billed to an API key.
Please disable API keys and use a Pro or Business subscription.
Request ID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
```

#### 問題3: 試用リクエスト制限

> これは、VIP無料試用期間中に使用制限に達したことを示しています:

```text
You've reached your trial request limit.
```

#### 問題4: Claude 3.7 高負荷 <p align="right"><a href="#issue4"><img src="https://img.shields.io/badge/Move%20to%20Solution-purple?style=plastic" alt="Back To Top"></a></p>

```text
High Load 
We're experiencing high demand for Claude 3.7 Sonnet right now. Please upgrade to Pro, or switch to the
'default' model, Claude 3.5 sonnet, another model, or try again in a few moments.
```

<br>

<p id="issue2"></p>

#### 解決策 : Cursorを完全にアンインストールして再インストールする(APIキーの問題)

1. [Geek.exeアンインストーラー[無料]](https://geekuninstaller.com/download)をダウンロードします
2. Cursorアプリを完全にアンインストールします
3. Cursorアプリを再インストールします
4. 解決策1を続行します

<br>

<p id="issue1"></p>

> 一時的な解決策:

#### 解決策1: クイックリセット(推奨)

1. Cursorアプリケーションを閉じます
2. マシンコードリセットスクリプトを実行します(以下のインストール手順を参照)
3. Cursorを再度開いて使用を続けます

#### 解決策2: アカウントの切り替え

1. ファイル -> Cursor設定 -> サインアウト
2. Cursorを閉じます
3. マシンコードリセットスクリプトを実行します
4. 新しいアカウントでログインします

#### 解決策3: ネットワークの最適化

上記の解決策が機能しない場合は、次のことを試してください:

- 低遅延ノードに切り替えます(推奨地域:日本、シンガポール、米国、香港)
- ネットワークの安定性を確保します
- ブラウザのキャッシュをクリアして再試行します

#### 解決策4: Claude 3.7 アクセス問題(高負荷)

Claude 3.7 Sonnetの"High Load"メッセージが表示された場合、これはCursorが特定の時間帯に無料試用アカウントの3.7モデルの使用を制限していることを示しています。次のことを試してください:

1. Gmailで作成した新しいアカウントに切り替えます。異なるIPアドレスを使用して接続することをお勧めします
2. 非ピーク時間帯にアクセスを試みます(通常、5-10 AMまたは3-7 PMの間に制限が少ないです)
3. Proにアップグレードしてアクセスを保証します
4. Claude 3.5 Sonnetを代替オプションとして使用します

> 注意: Cursorがリソース配分ポリシーを調整するにつれて、これらのアクセスパターンは変更される可能性があります。

### 💻 システムサポート

<table>
<tr>
<td>

**Windows** ✅

- x64 (64ビット)
- x86 (32ビット)

</td>
<td>

**macOS** ✅

- Intel (x64)
- Apple Silicon (M1/M2)

</td>
<td>

**Linux** ✅

- x64 (64ビット)
- x86 (32ビット)
- ARM64

</td>
</tr>
</table>



### 🚀 ワンクリックソリューション

<details open>
<summary><b>グローバルユーザー</b></summary>

**macOS**

```bash
# 方法2
curl -fsSL https://raw.githubusercontent.com/yuaotian/go-cursor-help/refs/heads/master/scripts/run/cursor_mac_id_modifier.sh -o ./cursor_mac_id_modifier.sh && sudo bash ./cursor_mac_id_modifier.sh && rm ./cursor_mac_id_modifier.sh
```

**Linux**

```bash
curl -fsSL https://raw.githubusercontent.com/yuaotian/go-cursor-help/refs/heads/master/scripts/run/cursor_linux_id_modifier.sh | sudo bash 
```

**Windows**

```powershell
irm https://raw.githubusercontent.com/yuaotian/go-cursor-help/refs/heads/master/scripts/run/cursor_win_id_modifier.ps1 | iex
```

**Windows (強化版)**

```powershell
irm https://raw.githubusercontent.com/yuaotian/go-cursor-help/refs/heads/master/scripts/run/cursor_win_id_modifier.ps1 | iex
```
> デュアルモード操作とトライアルリセット機能を備えた強化版Cursorマシンコード修正ツール

**キャッシュ回避(Windows):** ミラー/プロキシのキャッシュで古いスクリプトが取得される場合、URL 末尾にタイムスタンプのクエリを付けて回避できます(GitHub raw + タイムスタンプ推奨):

```powershell
irm "https://raw.githubusercontent.com/yuaotian/go-cursor-help/refs/heads/master/scripts/run/cursor_win_id_modifier.ps1?$(Get-Date -Format yyyyMMddHHmmss)" | iex
```

`wget.la` などのミラーを使う場合も同様に、URL 末尾へタイムスタンプを追加できます:

```powershell
irm "https://wget.la/https://raw.githubusercontent.com/yuaotian/go-cursor-help/refs/heads/master/scripts/run/cursor_win_id_modifier.ps1?$(Get-Date -Format yyyyMMddHHmmss)" | iex
```

<div align="center">
<img src="img/run_success.png" alt="Run Success" width="600"/>
</div>

</details>

<details open>
<summary><b>中国ユーザー(推奨)</b></summary>

**macOS**

```bash
curl -fsSL https://wget.la/https://raw.githubusercontent.com/yuaotian/go-cursor-help/refs/heads/master/scripts/run/cursor_mac_id_modifier.sh -o ./cursor_mac_id_modifier.sh && sudo bash ./cursor_mac_id_modifier.sh && rm ./cursor_mac_id_modifier.sh
```

**Linux**

```bash
curl -fsSL https://wget.la/https://raw.githubusercontent.com/yuaotian/go-cursor-help/refs/heads/master/scripts/run/cursor_linux_id_modifier.sh | sudo bash
```

> **Linuxユーザーへの注意:** スクリプトは、一般的なパス(`/usr/bin`, `/usr/local/bin`, `$HOME/.local/bin`, `/opt/cursor`, `/snap/bin`)の確認、`which cursor` コマンドの使用、および `/usr`、`/opt`、`$HOME/.local` ディレクトリ内の検索によって、Cursor のインストールを見つけようとします。Cursorが他の場所にインストールされているか、これらの方法で見つからない場合、スクリプトは失敗する可能性があります。これらの標準的な場所または方法のいずれかを通じてCursorにアクセスできることを確認してください。

**Windows**

```powershell
irm https://wget.la/https://raw.githubusercontent.com/yuaotian/go-cursor-help/refs/heads/master/scripts/run/cursor_win_id_modifier.ps1 | iex
```

**Windows (強化版)**

```powershell
irm https://wget.la/https://raw.githubusercontent.com/yuaotian/go-cursor-help/refs/heads/master/scripts/run/cursor_win_id_modifier.ps1 | iex
```
> デュアルモード操作とトライアルリセット機能を備えた強化版Cursorマシンコード修正ツール

</details>

<details open>
<summary><b>Windowsターミナルの実行と構成</b></summary>

#### Windowsで管理者ターミナルを開く方法:

##### 方法1: Win + Xショートカットを使用する
```md
1. Win + Xキーの組み合わせを押します
2. メニューから次のオプションのいずれかを選択します:
   - "Windows PowerShell (管理者)"
   - "Windows Terminal (管理者)"
   - "ターミナル (管理者)"
   (Windowsのバージョンによってオプションが異なる場合があります)
```

##### 方法2: Win + R実行コマンドを使用する
```md
1. Win + Rキーの組み合わせを押します
2. 実行ダイアログにpowershellまたはpwshと入力します
3. Ctrl + Shift + Enterを押して管理者として実行します
   または開いたウィンドウに次のように入力します: Start-Process pwsh -Verb RunAs
4. 管理者ターミナルにリセットスクリプトを入力します:

irm https://wget.la/https://raw.githubusercontent.com/yuaotian/go-cursor-help/refs/heads/master/scripts/run/cursor_win_id_modifier.ps1 | iex
```

強化版スクリプト:
```powershell
irm https://wget.la/https://raw.githubusercontent.com/yuaotian/go-cursor-help/refs/heads/master/scripts/run/cursor_win_id_modifier.ps1 | iex
```

##### 方法3: 検索を使用する
>![PowerShellを検索](img/pwsh_1.png)
>
>検索ボックスにpwshと入力し、右クリックして「管理者として実行」を選択します
>![管理者として実行](img/pwsh_2.png)

管理者ターミナルにリセットスクリプトを入力します:
```powershell
irm https://wget.la/https://raw.githubusercontent.com/yuaotian/go-cursor-help/refs/heads/master/scripts/run/cursor_win_id_modifier.ps1 | iex
```

強化版スクリプト:
```powershell
irm https://wget.la/https://raw.githubusercontent.com/yuaotian/go-cursor-help/refs/heads/master/scripts/run/cursor_win_id_modifier.ps1 | iex
```

### 🔧 PowerShellインストールガイド

システムにPowerShellがインストールされていない場合は、次の方法でインストールできます:

#### 方法1: Wingetを使用してインストール(推奨)

1. コマンドプロンプトまたはPowerShellを開きます
2. 次のコマンドを実行します:
```powershell
winget install --id Microsoft.PowerShell --source winget
```

#### 方法2: 手動でインストール

1. システムに適したインストーラーをダウンロードします:
   - [PowerShell-7.4.6-win-x64.msi](https://github.com/PowerShell/PowerShell/releases/download/v7.4.6/PowerShell-7.4.6-win-x64.msi)(64ビットシステム用)
   - [PowerShell-7.4.6-win-x86.msi](https://github.com/PowerShell/PowerShell/releases/download/v7.4.6/PowerShell-7.4.6-win-x86.msi)(32ビットシステム用)
   - [PowerShell-7.4.6-win-arm64.msi](https://github.com/PowerShell/PowerShell/releases/download/v7.4.6/PowerShell-7.4.6-win-arm64.msi)(ARM64システム用)

2. ダウンロードしたインストーラーをダブルクリックし、インストールの指示に従います

> 💡 問題が発生した場合は、[Microsoft公式インストールガイド](https://learn.microsoft.com/ja-jp/powershell/scripting/install/installing-powershell-on-windows)を参照してください

</details>

#### Windowsインストール機能:

- 🔍 PowerShell 7が利用可能な場合は自動的に検出して使用します
- 🛡️ UACプロンプトを介して管理者権限を要求します
- 📝 PS7が見つからない場合はWindows PowerShellにフォールバックします
- 💡 権限昇格に失敗した場合は手動の指示を提供します

これで完了です!スクリプトは次のことを行います:

1. ✨ ツールを自動的にインストールします
2. 🔄 Cursorの試用期間を即座にリセットします

### 📦 手動インストール

> [リリース](https://github.com/yuaotian/go-cursor-help/releases/latest)からシステムに適したファイルをダウンロードします

<details>
<summary>Windowsパッケージ</summary>

- 64ビット: `cursor-id-modifier_windows_x64.exe`
- 32ビット: `cursor-id-modifier_windows_x86.exe`
</details>

<details>
<summary>macOSパッケージ</summary>

- Intel: `cursor-id-modifier_darwin_x64_intel`
- M1/M2: `cursor-id-modifier_darwin_arm64_apple_silicon`
</details>

<details>
<summary>Linuxパッケージ</summary>

- 64ビット: `cursor-id-modifier_linux_x64`
- 32ビット: `cursor-id-modifier_linux_x86`
- ARM64: `cursor-id-modifier_linux_arm64`
</details>

### 🔧 技術的詳細

<details>
<summary><b>構成ファイル</b></summary>

プログラムはCursorの`storage.json`構成ファイルを変更します。場所は次のとおりです:

- Windows: `%APPDATA%\Cursor\User\globalStorage\storage.json`
- macOS: `~/Library/Application Support/Cursor/User/globalStorage/storage.json`
- Linux: `~/.config/Cursor/User/globalStorage/storage.json`
</details>

<details>
<summary><b>変更されたフィールド</b></summary>

ツールは次の新しい一意の識別子を生成します:

- `telemetry.machineId`
- `telemetry.macMachineId`
- `telemetry.devDeviceId`
- `telemetry.sqmId`
</details>

<details>
<summary><b>手動自動更新無効化</b></summary>

Windowsユーザーは自動更新機能を手動で無効にすることができます:

1. すべてのCursorプロセスを閉じます
2. ディレクトリを削除します: `C:\Users\username\AppData\Local\cursor-updater`
3. 同じ名前のファイルを作成します: `cursor-updater`(拡張子なし)

macOS/Linuxユーザーはシステム内で同様の`cursor-updater`ディレクトリを見つけて同じ操作を行うことができます。

</details>

<details>
<summary><b>安全機能</b></summary>

- ✅ 安全なプロセス終了
- ✅ アトミックファイル操作
- ✅ エラーハンドリングとリカバリ
</details>

<details>
<summary><b>レジストリ変更通知</b></summary>

> ⚠️ **重要: このツールはWindowsレジストリを変更します**

#### 変更されたレジストリ
- パス: `コンピュータ\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography`
- キー: `MachineGuid`

#### 潜在的な影響
このレジストリキーを変更すると、次のことに影響を与える可能性があります:
- Windowsシステムの一意のデバイス識別
- 特定のソフトウェアのデバイス認識と認証状態
- ハードウェア識別に基づくシステム機能

#### 安全対策
1. 自動バックアップ
   - 変更前に元の値が自動的にバックアップされます
   - バックアップ場所: `%APPDATA%\Cursor\User\globalStorage\backups`
   - バックアップファイル形式: `MachineGuid.backup_YYYYMMDD_HHMMSS`

2. 手動復元手順
   - レジストリエディタ(regedit)を開きます
   - 次の場所に移動します: `コンピュータ\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography`
   - `MachineGuid`を右クリックします
   - 「修正」を選択します
   - バックアップファイルの値を貼り付けます

#### 重要な注意事項
- 変更前にバックアップファイルの存在を確認します
- 必要に応じてバックアップファイルを使用して元の値を復元します
- レジストリの変更には管理者権限が必要です
</details>

---

### 📚 推奨読書

- [Cursorの問題収集と解決策](https://mp.weixin.qq.com/s/pnJrH7Ifx4WZvseeP1fcEA)
- [AIユニバーサル開発アシスタントプロンプトガイド](https://mp.weixin.qq.com/s/PRPz-qVkFJSgkuEKkTdzwg)

---

##  サポート

<div align="center">
<b>このツールが役立つと感じた場合、スパイシーグルテンのおやつ(Latiao)を買っていただけると嬉しいです~ 💁☕️</b>
<table>
<tr>

<td align="center">
<b>WeChat Pay</b><br>
<img src="img/wx_zsm2.png" width="500" alt="WeChat Pay"><br>
<small>要到饭咧?啊咧?啊咧?不给也没事~ 请随意打赏</small>
</td>
<td align="center">
<b>Alipay</b><br>
<img src="img/alipay.png" width="500" alt="Alipay"><br>
<small>如果觉得有帮助,来包辣条犒劳一下吧~</small>
</td>
<td align="center">
<b>Alipay</b><br>
<img src="img/alipay_scan_pay.jpg" width="500" alt="Alipay"><br>
<em>1 Latiao = 1 AI thought cycle</em>
</td>
<td align="center">
<b>WeChat</b><br>
<img src="img/qun-22.jpg" width="500" alt="WeChat"><br>
<em>二维码7天内(3月6日前前)有效,过期请加微信或者公众号`煎饼果子卷AI`</em>
</td>
<!-- <td align="center">
<b>ETC</b><br>
<img src="img/etc.png" width="100" alt="ETC Address"><br>
ETC: 0xa2745f4CD5d32310AC01694ABDB28bA32D125a6b
</td>
<td align="center"> -->
</td>
</tr>
</table>
</div>

### 💳 お支払い方法(寄付 / 広告削除)

- 🪙 **USDT(Tether)**
  - 🔴 TRC-20(Tron):`TFbJnoY5Lep5ZrDwBbT8rV1i8xR4ZhX53k`
  - 🟡 Polygon / BSC / Arbitrum:`0x44f8925b9f93b3d6da8d5ad26a3516e3e652cc88`
- 🟦 **Litecoin(LTC)**:`LVrigKxtWfPymMRtRqL3z2eZxfncR3dPV7`

---

## 💬 フィードバック&提案

新しい強化スクリプトに関するフィードバックをお待ちしています!`cursor_win_id_modifier.ps1` スクリプトをお試しいただいた方は、ぜひご体験をお聞かせください:

- 🐛 **バグレポート**:問題を発見されましたか?お知らせください!
- 💡 **機能提案**:改善のアイデアはありますか?
- ⭐ **成功事例**:ツールがどのようにお役に立ったかお聞かせください!
- 🔧 **技術的フィードバック**:パフォーマンス、互換性、使いやすさに関するご意見

皆様のフィードバックは、すべてのユーザーのためにツールを改善するのに役立ちます。お気軽にissueを開いたり、プロジェクトに貢献してください!

---

## ⭐ プロジェクト統計

<div align="center">

[![Star History Chart](https://api.star-history.com/svg?repos=yuaotian/go-cursor-help&type=Date)](https://star-history.com/#yuaotian/go-cursor-help&Date)

![Repobeats analytics image](https://repobeats.axiom.co/api/embed/ddaa9df9a94b0029ec3fad399e1c1c4e75755477.svg "Repobeats analytics image")

</div>

## 📄 ライセンス

<details>
<summary><b>MITライセンス</b></summary>

Copyright (c) 2024

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

</details>


================================================
FILE: scripts/hook/cursor_hook.js
================================================
/**
 * Cursor 设备标识符 Hook 模块
 * 
 * 🎯 功能:从底层拦截所有设备标识符的生成,实现一劳永逸的机器码修改
 * 
 * 🔧 Hook 点:
 * 1. child_process.execSync - 拦截 REG.exe 查询 MachineGuid
 * 2. crypto.createHash - 拦截 SHA256 哈希计算
 * 3. @vscode/deviceid - 拦截 devDeviceId 获取
 * 4. @vscode/windows-registry - 拦截注册表读取
 * 5. os.networkInterfaces - 拦截 MAC 地址获取
 * 6. fs.writeFileSync/writeFile - 拦截 storage.json 写入,保护 telemetry 字段
 * 
 * 📦 使用方式:
 * 将此代码注入到 main.js 文件顶部(Sentry 初始化之后)
 * 
 * ⚙️ 配置方式:
 * 1. 环境变量:CURSOR_MACHINE_ID, CURSOR_MAC_MACHINE_ID, CURSOR_DEV_DEVICE_ID, CURSOR_SQM_ID
 * 2. 配置文件:~/.cursor_ids.json
 * 3. 自动生成:如果没有配置,则自动生成并持久化
 */

// ==================== 配置区域 ====================
// 使用 var 确保在 ES Module 环境中也能正常工作
var __cursor_hook_config__ = {
    // 是否启用 Hook(设置为 false 可临时禁用)
    enabled: true,
    // 是否输出调试日志(设置为 true 可查看详细日志)
    debug: false,
    // 配置文件路径(相对于用户目录)
    configFileName: '.cursor_ids.json',
    // 标记:防止重复注入
    injected: false
};

// ==================== Hook 实现 ====================
// 使用 IIFE 确保代码立即执行
(function() {
    'use strict';

    // 防止重复注入
    if (globalThis.__cursor_patched__ || __cursor_hook_config__.injected) {
        return;
    }
    globalThis.__cursor_patched__ = true;
    __cursor_hook_config__.injected = true;

    // 调试日志函数
    const log = (...args) => {
        if (__cursor_hook_config__.debug) {
            console.log('[CursorHook]', ...args);
        }
    };

    // ==================== ID 生成和管理 ====================

    // 生成 UUID v4
    const generateUUID = () => {
        return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
            const r = Math.random() * 16 | 0;
            const v = c === 'x' ? r : (r & 0x3 | 0x8);
            return v.toString(16);
        });
    };

    // 生成 64 位十六进制字符串(用于 machineId)
    const generateHex64 = () => {
        let hex = '';
        for (let i = 0; i < 64; i++) {
            hex += Math.floor(Math.random() * 16).toString(16);
        }
        return hex;
    };

    // 生成 MAC 地址格式的字符串
    const generateMacAddress = () => {
        const hex = '0123456789ABCDEF';
        let mac = '';
        for (let i = 0; i < 6; i++) {
            if (i > 0) mac += ':';
            mac += hex[Math.floor(Math.random() * 16)];
            mac += hex[Math.floor(Math.random() * 16)];
        }
        return mac;
    };

    // 加载或生成 ID 配置
    // 注意:该 Hook 由脚本注入的 Loader 通过 CommonJS(require) 方式加载,
    // 为避免出现 import.meta 等仅 ESM 支持的语法导致 Cursor 启动期解析失败,这里保持纯 CommonJS 写法。
    const loadOrGenerateIds = () => {
        const fs = require('fs');
        const path = require('path');
        const os = require('os');

        const configPath = path.join(os.homedir(), __cursor_hook_config__.configFileName);

        let ids = null;

        // 尝试从环境变量读取
        if (process.env.CURSOR_MACHINE_ID) {
            ids = {
                machineId: process.env.CURSOR_MACHINE_ID,
                // machineGuid 用于模拟注册表 MachineGuid/IOPlatformUUID
                machineGuid: process.env.CURSOR_MACHINE_GUID || generateUUID(),
                macMachineId: process.env.CURSOR_MAC_MACHINE_ID || generateHex64(),
                devDeviceId: process.env.CURSOR_DEV_DEVICE_ID || generateUUID(),
                sqmId: process.env.CURSOR_SQM_ID || `{${generateUUID().toUpperCase()}}`,
                macAddress: process.env.CURSOR_MAC_ADDRESS || generateMacAddress(),
                sessionId: process.env.CURSOR_SESSION_ID || generateUUID(),
                firstSessionDate: process.env.CURSOR_FIRST_SESSION_DATE || new Date().toISOString()
            };
            log('从环境变量加载 ID 配置');
            return ids;
        }

        // 尝试从配置文件读取
        try {
            if (fs.existsSync(configPath)) {
                const content = fs.readFileSync(configPath, 'utf8');
                ids = JSON.parse(content);
                // 补全缺失字段,保持向后兼容
                let updated = false;
                // 🔧 补齐核心 ID 字段(用于 Hook 与 storage.json 保护)
                if (!ids.machineId || typeof ids.machineId !== 'string') {
                    ids.machineId = generateHex64();
                    updated = true;
                }
                if (!ids.macMachineId || typeof ids.macMachineId !== 'string') {
                    ids.macMachineId = generateHex64();
                    updated = true;
                }
                if (!ids.devDeviceId || typeof ids.devDeviceId !== 'string') {
                    ids.devDeviceId = generateUUID();
                    updated = true;
                }
                if (!ids.sqmId || typeof ids.sqmId !== 'string') {
                    ids.sqmId = `{${generateUUID().toUpperCase()}}`;
                    updated = true;
                }
                if (!ids.machineGuid) {
                    ids.machineGuid = generateUUID();
                    updated = true;
                }
                if (!ids.macAddress) {
                    ids.macAddress = generateMacAddress();
                    updated = true;
                }
                if (!ids.sessionId) {
                    ids.sessionId = generateUUID();
                    updated = true;
                }
                if (!ids.firstSessionDate) {
                    ids.firstSessionDate = new Date().toISOString();
                    updated = true;
                }
                if (updated) {
                    try {
                        fs.writeFileSync(configPath, JSON.stringify(ids, null, 2), 'utf8');
                        log('已补全并更新 ID 配置:', configPath);
                    } catch (e) {
                        log('补全配置文件失败:', e.message);
                    }
                }
                log('从配置文件加载 ID 配置:', configPath);
                return ids;
            }
        } catch (e) {
            log('读取配置文件失败:', e.message);
        }

        // 生成新的 ID
        ids = {
            machineId: generateHex64(),
            machineGuid: generateUUID(),
            macMachineId: generateHex64(),
            devDeviceId: generateUUID(),
            sqmId: `{${generateUUID().toUpperCase()}}`,
            macAddress: generateMacAddress(),
            sessionId: generateUUID(),
            firstSessionDate: new Date().toISOString(),
            createdAt: new Date().toISOString()
        };

        // 保存到配置文件
        try {
            fs.writeFileSync(configPath, JSON.stringify(ids, null, 2), 'utf8');
            log('已生成并保存新的 ID 配置:', configPath);
        } catch (e) {
            log('保存配置文件失败:', e.message);
        }

        return ids;
    };

    // 加载 ID 配置
    const __cursor_ids__ = loadOrGenerateIds();
    // 统一获取 MachineGuid,缺失时回退到 machineId 的前 36 位
    const getMachineGuid = () => __cursor_ids__.machineGuid || __cursor_ids__.machineId.substring(0, 36);
    log('当前 ID 配置:', __cursor_ids__);
    
    // ==================== Module Hook ====================
    
    const Module = require('module');
    const originalRequire = Module.prototype.require;
    
    // 缓存已 Hook 的模块
    const hookedModules = new Map();
    
    Module.prototype.require = function(id) {
        // 兼容 node: 前缀
        const normalizedId = (typeof id === 'string' && id.startsWith('node:')) ? id.slice(5) : id;
        const result = originalRequire.apply(this, arguments);
        
        // 如果已经 Hook 过,直接返回缓存
        if (hookedModules.has(normalizedId)) {
            return hookedModules.get(normalizedId);
        }
        
        let hooked = result;
        
        // Hook child_process 模块
        if (normalizedId === 'child_process') {
            hooked = hookChildProcess(result);
        }
        // Hook os 模块
        else if (normalizedId === 'os') {
            hooked = hookOs(result);
        }
        // Hook fs 模块 (新增:保护 storage.json)
        else if (normalizedId === 'fs') {
            hooked = hookFs(result);
        }
        // Hook crypto 模块
        else if (normalizedId === 'crypto') {
            hooked = hookCrypto(result);
        }
        // Hook @vscode/deviceid 模块
        else if (normalizedId === '@vscode/deviceid') {
            hooked = hookDeviceId(result);
        }
        // Hook @vscode/windows-registry 模块
        else if (normalizedId === '@vscode/windows-registry') {
            hooked = hookWindowsRegistry(result);
        }

        // 缓存 Hook 结果
        if (hooked !== result) {
            hookedModules.set(normalizedId, hooked);
            log(`已 Hook 模块: ${normalizedId}`);
        }
        
        return hooked;
    };

    // ==================== child_process Hook ====================

    function hookChildProcess(cp) {
        const originalExecSync = cp.execSync;
        const originalExecFileSync = cp.execFileSync;

        cp.execSync = function(command, options) {
            const cmdStr = String(command).toLowerCase();

            // 拦截 MachineGuid 查询
            if (cmdStr.includes('reg') && cmdStr.includes('machineguid')) {
                log('拦截 MachineGuid 查询');
                // 返回格式化的注册表输出
                return Buffer.from(`\r\n    MachineGuid    REG_SZ    ${getMachineGuid()}\r\n`);
            }

            // 拦截 ioreg 命令 (macOS)
            if (cmdStr.includes('ioreg') && cmdStr.includes('ioplatformexpertdevice')) {
                log('拦截 IOPlatformUUID 查询');
                return Buffer.from(`"IOPlatformUUID" = "${getMachineGuid().toUpperCase()}"`);
            }

            // 拦截 machine-id 读取 (Linux)
            if (cmdStr.includes('machine-id') || cmdStr.includes('hostname')) {
                log('拦截 machine-id 查询');
                return Buffer.from(__cursor_ids__.machineId.substring(0, 32));
            }

            return originalExecSync.apply(this, arguments);
        };

        // 兼容 execFileSync(部分版本会直接调用可执行文件)
        if (typeof originalExecFileSync === 'function') {
            cp.execFileSync = function(file, args, options) {
                const cmdStr = [file].concat(args || []).join(' ').toLowerCase();

                if (cmdStr.includes('reg') && cmdStr.includes('machineguid')) {
                    log('拦截 MachineGuid 查询(execFileSync)');
                    return Buffer.from(`\r\n    MachineGuid    REG_SZ    ${getMachineGuid()}\r\n`);
                }

                if (cmdStr.includes('ioreg') && cmdStr.includes('ioplatformexpertdevice')) {
                    log('拦截 IOPlatformUUID 查询(execFileSync)');
                    return Buffer.from(`"IOPlatformUUID" = "${getMachineGuid().toUpperCase()}"`);
                }

                if (cmdStr.includes('machine-id') || cmdStr.includes('hostname')) {
                    log('拦截 machine-id 查询(execFileSync)');
                    return Buffer.from(__cursor_ids__.machineId.substring(0, 32));
                }

                return originalExecFileSync.apply(this, arguments);
            };
        }

        return cp;
    }

    // ==================== os Hook ====================

    function hookOs(os) {
        const originalNetworkInterfaces = os.networkInterfaces;

        os.networkInterfaces = function() {
            log('拦截 networkInterfaces 调用');
            // 返回虚拟的网络接口,使用固定的 MAC 地址
            return {
                'Ethernet': [{
                    address: '192.168.1.100',
                    netmask: '255.255.255.0',
                    family: 'IPv4',
                    mac: __cursor_ids__.macAddress || '00:00:00:00:00:00',
                    internal: false
                }]
            };
        };

        return os;
    }

    // ==================== fs Hook (新增) ====================
    // 🔧 拦截 storage.json 写入操作,保护 telemetry 字段不被覆盖

    // 需要保护的 telemetry 字段列表
    const PROTECTED_TELEMETRY_KEYS = [
        'telemetry.machineId',
        'telemetry.macMachineId',
        'telemetry.devDeviceId',
        'telemetry.sqmId'
    ];

    // 规范化 filePath(兼容 string/Buffer/URL 等)
    function normalizeFilePath(filePath) {
        try {
            if (filePath === undefined || filePath === null) return '';
            if (typeof filePath === 'string') return filePath;
            if (Buffer.isBuffer(filePath)) return filePath.toString('utf8');

            // WHATWG URL (fs 支持 URL 对象)
            if (typeof filePath === 'object' && typeof filePath.href === 'string') {
                // 优先将 file:// URL 转为本地路径,避免传递 "file:///..." 字符串导致 existsSync/readFileSync 失败
                if (typeof filePath.protocol === 'string' && filePath.protocol === 'file:') {
                    try {
                        const url = require('url');
                        if (url && typeof url.fileURLToPath === 'function') {
                            return url.fileURLToPath(filePath);
                        }
                    } catch (_) {
                        // ignore
                    }
                }
                return filePath.href;
            }

            return String(filePath);
        } catch (_) {
            return '';
        }
    }

    function previewValue(value) {
        try {
            const s = String(value);
            return s.length > 16 ? s.slice(0, 16) + '...' : s;
        } catch (_) {
            return '<unprintable>';
        }
    }

    // 将写入内容转为 utf8 文本,并提供回写为“同类类型”的包装器
    function coerceContentToUtf8Text(content) {
        try {
            if (typeof content === 'string') {
                return { text: content, wrap: (s) => s };
            }
            if (Buffer.isBuffer(content)) {
                return { text: content.toString('utf8'), wrap: (s) => Buffer.from(s, 'utf8') };
            }
            // TypedArray / DataView
            if (content && typeof content === 'object') {
                if (content instanceof Uint8Array) {
                    // Buffer 也属于 Uint8Array,但已在上面处理
                    const buf = Buffer.from(content);
                    return { text: buf.toString('utf8'), wrap: (s) => new Uint8Array(Buffer.from(s, 'utf8')) };
                }
                if (typeof ArrayBuffer !== 'undefined' && content instanceof ArrayBuffer) {
                    const buf = Buffer.from(content);
                    return { text: buf.toString('utf8'), wrap: (s) => Buffer.from(s, 'utf8') };
                }
                if (typeof ArrayBuffer !== 'undefined' && typeof ArrayBuffer.isView === 'function' && ArrayBuffer.isView(content)) {
                    const buf = Buffer.from(content.buffer, content.byteOffset, content.byteLength);
                    return { text: buf.toString('utf8'), wrap: (s) => Buffer.from(s, 'utf8') };
                }
            }
        } catch (_) {
            // ignore
        }
        return null;
    }

    // 检查路径是否为 storage.json
    function isStorageJsonPath(filePath) {
        const raw = normalizeFilePath(filePath);
        if (!raw) return false;
        const normalized = raw.replace(/\\/g, '/').toLowerCase();
        return normalized.includes('globalstorage/storage.json');
    }

    // 保护 storage.json 中的 telemetry 字段
    function protectStorageJson(content, filePath) {
        if (!isStorageJsonPath(filePath)) return content;
        
        try {
            const fs = require('fs');
            const coerced = coerceContentToUtf8Text(content);
            if (!coerced) return content;

            let newData;
            try {
                newData = JSON.parse(coerced.text);
            } catch (_) {
                return content;
            }
            
            // 如果写入的内容不是有效的 JSON 对象,直接返回
            if (typeof newData !== 'object' || newData === null) {
                return content;
            }
            
            // 保护值优先级:
            // 1) __cursor_ids__(Hook 配置/环境变量/自动生成)
            // 2) 现有 storage.json 中已存在的值
            // 3) 本次写入值(最低)
            const protectedValues = {
                'telemetry.machineId': __cursor_ids__ && __cursor_ids__.machineId,
                'telemetry.macMachineId': __cursor_ids__ && __cursor_ids__.macMachineId,
                'telemetry.devDeviceId': __cursor_ids__ && __cursor_ids__.devDeviceId,
                'telemetry.sqmId': __cursor_ids__ && __cursor_ids__.sqmId
            };

            // 仅当 Hook 配置不完整时,才读取旧文件值作为二级兜底
            let existingProtected = {};
            const needExisting = PROTECTED_TELEMETRY_KEYS.some((k) => !(typeof protectedValues[k] === 'string' && protectedValues[k]));
            if (needExisting) {
                try {
                    if (fs.existsSync(filePath)) {
                        const existingText = fs.readFileSync(filePath, 'utf8');
                        const existing = JSON.parse(existingText);
                        if (existing && typeof existing === 'object') {
                            for (const key of PROTECTED_TELEMETRY_KEYS) {
                                if (typeof existing[key] === 'string' && existing[key]) {
                                    existingProtected[key] = existing[key];
                                }
                            }
                        }
                    }
                } catch (_) {
                    // ignore
                }
            }
            
            let modified = false;
            for (const key of PROTECTED_TELEMETRY_KEYS) {
                const fromIds = protectedValues[key];
                const desired = (typeof fromIds === 'string' && fromIds) ? fromIds
                    : (typeof existingProtected[key] === 'string' && existingProtected[key]) ? existingProtected[key]
                    : undefined;

                if (desired === undefined) {
                    continue;
                }

                // 方案B:无论写入内容是否包含该字段,都确保最终值稳定(缺失则补齐)
                if (newData[key] !== desired) {
                    log(`[fs Hook] 固定 ${key}: ${previewValue(newData[key])} -> ${previewValue(desired)}`);
                    newData[key] = desired;
                    modified = true;
                }
            }
            
            if (modified) {
                log('[fs Hook] storage.json telemetry 字段已保护');
                const nextText = JSON.stringify(newData, null, '\t');
                return coerced.wrap(nextText);
            }
        } catch (e) {
            const msg = e && e.message ? e.message : String(e);
            log('[fs Hook] 处理 storage.json 失败:', msg);
        }
        
        return content;
    }

    function hookFs(fsModule) {
        const originalWriteFileSync = fsModule.writeFileSync;
        const originalWriteFile = fsModule.writeFile;
        const originalAppendFileSync = fsModule.appendFileSync;
        const originalAppendFile = fsModule.appendFile;
        const originalCreateWriteStream = fsModule.createWriteStream;
        const originalOpenSync = fsModule.openSync;
        const originalOpen = fsModule.open;
        const originalCloseSync = fsModule.closeSync;
        const originalClose = fsModule.close;

        // fd 追踪:覆盖 open/close 路径(仅用于 storage.json)
        const storageJsonFds = new Map();
        let inFdFix = false;

        const fixStorageJsonFile = (filePath) => {
            if (inFdFix) return;
            inFdFix = true;
            try {
                const current = fsModule.readFileSync(filePath, 'utf8');
                const next = protectStorageJson(current, filePath);
                if (typeof next === 'string' && next !== current) {
                    originalWriteFileSync.call(fsModule, filePath, next, 'utf8');
                    log('[fs Hook] close-fix: storage.json telemetry 字段已重新保护');
                }
            } catch (e) {
                const msg = e && e.message ? e.message : String(e);
                log('[fs Hook] close-fix 失败:', msg);
            } finally {
                inFdFix = false;
            }
        };

        // Hook writeFileSync
        fsModule.writeFileSync = function(filePath, data, options) {
            const protectedData = protectStorageJson(data, filePath);
            return originalWriteFileSync.call(this, filePath, protectedData, options);
        };

        // Hook writeFile (异步版本)
        fsModule.writeFile = function(filePath, data, options, callback) {
            // 处理参数重载: writeFile(path, data, callback) 或 writeFile(path, data, options, callback)
            if (typeof options === 'function') {
                callback = options;
                options = undefined;
            }
            const protectedData = protectStorageJson(data, filePath);
            return originalWriteFile.call(this, filePath, protectedData, options, callback);
        };

        // Hook promises API (fs.promises.writeFile)
        if (fsModule.promises) {
            const originalPromisesWriteFile = fsModule.promises.writeFile;
            fsModule.promises.writeFile = async function(filePath, data, options) {
                const protectedData = protectStorageJson(data, filePath);
                return originalPromisesWriteFile.call(this, filePath, protectedData, options);
            };

            if (typeof fsModule.promises.appendFile === 'function') {
                const originalPromisesAppendFile = fsModule.promises.appendFile;
                fsModule.promises.appendFile = async function(filePath, data, options) {
                    const protectedData = protectStorageJson(data, filePath);
                    return originalPromisesAppendFile.call(this, filePath, protectedData, options);
                };
            }
        }

        // Hook appendFileSync
        if (typeof originalAppendFileSync === 'function') {
            fsModule.appendFileSync = function(filePath, data, options) {
                const protectedData = protectStorageJson(data, filePath);
                return originalAppendFileSync.call(this, filePath, protectedData, options);
            };
        }

        // Hook appendFile (异步版本)
        if (typeof originalAppendFile === 'function') {
            fsModule.appendFile = function(filePath, data, options, callback) {
                if (typeof options === 'function') {
                    callback = options;
                    options = undefined;
                }
                const protectedData = protectStorageJson(data, filePath);
                return originalAppendFile.call(this, filePath, protectedData, options, callback);
            };
        }

        // Hook createWriteStream(仅对 storage.json:保持原生 WriteStream,但 close 后做补救性修正)
        if (typeof originalCreateWriteStream === 'function') {
            fsModule.createWriteStream = function(filePath, options) {
                const stream = originalCreateWriteStream.apply(this, arguments);
                if (isStorageJsonPath(filePath) && stream && typeof stream.on === 'function') {
                    stream.on('close', () => {
                        try {
                            fixStorageJsonFile(filePath);
                        } catch (_) {
                            // ignore
                        }
                    });
                }
                return stream;
            };
        }

        // Hook open/openSync:追踪 storage.json 的 fd
        if (typeof originalOpenSync === 'function') {
            fsModule.openSync = function(filePath) {
                const fd = originalOpenSync.apply(this, arguments);
                try {
                    if (!inFdFix && isStorageJsonPath(filePath)) {
                        storageJsonFds.set(fd, filePath);
                    }
                } catch (_) {
                    // ignore
                }
                return fd;
            };
        }

        if (typeof originalOpen === 'function') {
            fsModule.open = function(filePath, flags, mode, callback) {
                if (typeof mode === 'function') {
                    callback = mode;
                    mode = undefined;
                }

                const wrapped = function(err, fd) {
                    try {
                        if (!err && !inFdFix && isStorageJsonPath(filePath)) {
                            storageJsonFds.set(fd, filePath);
                        }
                    } catch (_) {
                        // ignore
                    }
                    if (typeof callback === 'function') {
                        return callback.apply(this, arguments);
                    }
                };

                if (mode === undefined) {
                    return originalOpen.call(this, filePath, flags, wrapped);
                }
                return originalOpen.call(this, filePath, flags, mode, wrapped);
            };
        }

        // Hook close/closeSync:关闭后再做一次“落盘后修正”(覆盖 fd 写入路径)
        if (typeof originalCloseSync === 'function') {
            fsModule.closeSync = function(fd) {
                const filePath = storageJsonFds.get(fd);
                const ret = originalCloseSync.apply(this, arguments);
                if (filePath !== undefined) {
                    storageJsonFds.delete(fd);
                    fixStorageJsonFile(filePath);
                }
                return ret;
            };
        }

        if (typeof originalClose === 'function') {
            fsModule.close = function(fd, callback) {
                const filePath = storageJsonFds.get(fd);
                const wrapped = function(err) {
                    try {
                        if (!err && filePath !== undefined) {
                            storageJsonFds.delete(fd);
                            fixStorageJsonFile(filePath);
                        }
                    } catch (_) {
                        // ignore
                    }
                    if (typeof callback === 'function') {
                        return callback.apply(this, arguments);
                    }
                };
                return originalClose.call(this, fd, wrapped);
            };
        }

        log('[fs Hook] 已启用 storage.json 写入保护');
        return fsModule;
    }

    // ==================== crypto Hook ====================

    function hookCrypto(crypto) {
        const originalCreateHash = crypto.createHash;
        const originalRandomUUID = crypto.randomUUID;

        // Hook createHash - 用于拦截 machineId 的 SHA256 计算
        crypto.createHash = function(algorithm) {
            const hash = originalCreateHash.apply(this, arguments);

            if (algorithm.toLowerCase() === 'sha256') {
                const originalUpdate = hash.update.bind(hash);
                const originalDigest = hash.digest.bind(hash);

                let inputData = '';

                hash.update = function(data, encoding) {
                    inputData += String(data);
                    return originalUpdate(data, encoding);
                };

                hash.digest = function(encoding) {
                    // 检查是否是 machineId 相关的哈希计算
                    if (inputData.includes('MachineGuid') ||
                        inputData.includes('IOPlatformUUID') ||
                        inputData.length === 32 ||
                        inputData.length === 36) {
                        log('拦截 SHA256 哈希计算,返回固定 machineId');
                        if (encoding === 'hex') {
                            return __cursor_ids__.machineId;
                        }
                        return Buffer.from(__cursor_ids__.machineId, 'hex');
                    }
                    return originalDigest(encoding);
                };
            }

            return hash;
        };

        // Hook randomUUID - 用于拦截 devDeviceId 生成
        if (originalRandomUUID) {
            let uuidCallCount = 0;
            crypto.randomUUID = function() {
                uuidCallCount++;
                // 第一次调用返回固定的 devDeviceId
                if (uuidCallCount <= 2) {
                    log('拦截 randomUUID 调用,返回固定 devDeviceId');
                    return __cursor_ids__.devDeviceId;
                }
                return originalRandomUUID.apply(this, arguments);
            };
        }

        return crypto;
    }

    // ==================== @vscode/deviceid Hook ====================

    function hookDeviceId(deviceIdModule) {
        log('Hook @vscode/deviceid 模块');

        return {
            ...deviceIdModule,
            getDeviceId: async function() {
                log('拦截 getDeviceId 调用');
                return __cursor_ids__.devDeviceId;
            }
        };
    }

    // ==================== @vscode/windows-registry Hook ====================

    function hookWindowsRegistry(registryModule) {
        log('Hook @vscode/windows-registry 模块');

        const originalGetStringRegKey = registryModule.GetStringRegKey;

        return {
            ...registryModule,
            GetStringRegKey: function(hive, path, name) {
                const pathStr = (typeof path === 'string') ? path : '';
                // 拦截 MachineId 读取
                if (name === 'MachineId' || pathStr.includes('SQMClient')) {
                    log('拦截注册表 MachineId/SQMClient 读取');
                    return __cursor_ids__.sqmId;
                }
                // 拦截 MachineGuid 读取
                if (name === 'MachineGuid' || pathStr.includes('Cryptography')) {
                    log('拦截注册表 MachineGuid 读取');
                    return getMachineGuid();
                }
                if (typeof originalGetStringRegKey === 'function') {
                    return originalGetStringRegKey.apply(this, arguments) || '';
                }
                return '';
            }
        };
    }

    // ==================== 动态 import Hook ====================

    // Cursor 使用动态 import() 加载模块,我们需要 Hook 这些模块
    // 由于 ES Module 的限制,我们通过 Hook 全局对象来实现

    // 存储已 Hook 的动态导入模块
    const hookedDynamicModules = new Map();

    // Hook crypto 模块的动态导入
    const hookDynamicCrypto = (cryptoModule) => {
        if (hookedDynamicModules.has('crypto')) {
            return hookedDynamicModules.get('crypto');
        }

        const hooked = { ...cryptoModule };

        // Hook createHash
        if (cryptoModule.createHash) {
            const originalCreateHash = cryptoModule.createHash;
            hooked.createHash = function(algorithm) {
                const hash = originalCreateHash.apply(this, arguments);

                if (algorithm.toLowerCase() === 'sha256') {
                    const originalDigest = hash.digest.bind(hash);
                    let inputData = '';

                    const originalUpdate = hash.update.bind(hash);
                    hash.update = function(data, encoding) {
                        inputData += String(data);
                        return originalUpdate(data, encoding);
                    };

                    hash.digest = function(encoding) {
                        // 检测 machineId 相关的哈希
                        if (inputData.includes('MachineGuid') ||
                            inputData.includes('IOPlatformUUID') ||
                            (inputData.length >= 32 && inputData.length <= 40)) {
                            log('动态导入: 拦截 SHA256 哈希');
                            return encoding === 'hex' ? __cursor_ids__.machineId : Buffer.from(__cursor_ids__.machineId, 'hex');
                        }
                        return originalDigest(encoding);
                    };
                }
                return hash;
            };
        }

        hookedDynamicModules.set('crypto', hooked);
        return hooked;
    };

    // Hook @vscode/deviceid 模块的动态导入
    const hookDynamicDeviceId = (deviceIdModule) => {
        if (hookedDynamicModules.has('@vscode/deviceid')) {
            return hookedDynamicModules.get('@vscode/deviceid');
        }

        const hooked = {
            ...deviceIdModule,
            getDeviceId: async () => {
                log('动态导入: 拦截 getDeviceId');
                return __cursor_ids__.devDeviceId;
            }
        };

        hookedDynamicModules.set('@vscode/deviceid', hooked);
        return hooked;
    };

    // Hook @vscode/windows-registry 模块的动态导入
    const hookDynamicWindowsRegistry = (registryModule) => {
        if (hookedDynamicModules.has('@vscode/windows-registry')) {
            return hookedDynamicModules.get('@vscode/windows-registry');
        }

        const originalGetStringRegKey = registryModule.GetStringRegKey;
        const hooked = {
            ...registryModule,
            GetStringRegKey: function(hive, path, name) {
                const pathStr = (typeof path === 'string') ? path : '';
                if (name === 'MachineId' || pathStr.includes('SQMClient')) {
                    log('动态导入: 拦截 SQMClient');
                    return __cursor_ids__.sqmId;
                }
                if (name === 'MachineGuid' || pathStr.includes('Cryptography')) {
                    log('动态导入: 拦截 MachineGuid');
                    return getMachineGuid();
                }
                if (typeof originalGetStringRegKey === 'function') {
                    return originalGetStringRegKey.apply(this, arguments) || '';
                }
                return '';
            }
        };

        hookedDynamicModules.set('@vscode/windows-registry', hooked);
        return hooked;
    };

    // Hook fs 模块的动态导入 (新增:保护 storage.json)
    const hookDynamicFs = (fsModule) => {
        if (hookedDynamicModules.has('fs')) {
            return hookedDynamicModules.get('fs');
        }

        const hooked = { ...fsModule };
        const originalWriteFileSync = fsModule.writeFileSync;
        const originalWriteFile = fsModule.writeFile;
        const originalAppendFileSync = fsModule.appendFileSync;
        const originalAppendFile = fsModule.appendFile;
        const originalCreateWriteStream = fsModule.createWriteStream;
        const originalOpenSync = fsModule.openSync;
        const originalOpen = fsModule.open;
        const originalCloseSync = fsModule.closeSync;
        const originalClose = fsModule.close;

        const storageJsonFds = new Map();
        let inFdFix = false;

        const fixStorageJsonFile = (filePath) => {
            if (inFdFix) return;
            inFdFix = true;
            try {
                const current = fsModule.readFileSync(filePath, 'utf8');
                const next = protectStorageJson(current, filePath);
                if (typeof next === 'string' && next !== current) {
                    originalWriteFileSync.call(fsModule, filePath, next, 'utf8');
                    log('动态导入: close-fix storage.json telemetry 字段已重新保护');
                }
            } catch (e) {
                const msg = e && e.message ? e.message : String(e);
                log('动态导入: close-fix 失败:', msg);
            } finally {
                inFdFix = false;
            }
        };

        hooked.writeFileSync = function(filePath, data, options) {
            const protectedData = protectStorageJson(data, filePath);
            return originalWriteFileSync.call(this, filePath, protectedData, options);
        };

        hooked.writeFile = function(filePath, data, options, callback) {
            if (typeof options === 'function') {
                callback = options;
                options = undefined;
            }
            const protectedData = protectStorageJson(data, filePath);
            return originalWriteFile.call(this, filePath, protectedData, options, callback);
        };

        // Hook promises API
        if (fsModule.promises) {
            const originalPromisesWriteFile = fsModule.promises.writeFile;
            hooked.promises = {
                ...fsModule.promises,
                writeFile: async function(filePath, data, options) {
                    const protectedData = protectStorageJson(data, filePath);
                    return originalPromisesWriteFile.call(this, filePath, protectedData, options);
                }
            };

            if (typeof fsModule.promises.appendFile === 'function') {
                const originalPromisesAppendFile = fsModule.promises.appendFile;
                hooked.promises.appendFile = async function(filePath, data, options) {
                    const protectedData = protectStorageJson(data, filePath);
                    return originalPromisesAppendFile.call(this, filePath, protectedData, options);
                };
            }
        }

        if (typeof originalAppendFileSync === 'function') {
            hooked.appendFileSync = function(filePath, data, options) {
                const protectedData = protectStorageJson(data, filePath);
                return originalAppendFileSync.call(this, filePath, protectedData, options);
            };
        }

        if (typeof originalAppendFile === 'function') {
            hooked.appendFile = function(filePath, data, options, callback) {
                if (typeof options === 'function') {
                    callback = options;
                    options = undefined;
                }
                const protectedData = protectStorageJson(data, filePath);
                return originalAppendFile.call(this, filePath, protectedData, options, callback);
            };
        }

        if (typeof originalCreateWriteStream === 'function') {
            hooked.createWriteStream = function(filePath, options) {
                const stream = originalCreateWriteStream.apply(this, arguments);
                if (isStorageJsonPath(filePath) && stream && typeof stream.on === 'function') {
                    stream.on('close', () => {
                        try {
                            fixStorageJsonFile(filePath);
                        } catch (_) {
                            // ignore
                        }
                    });
                }
                return stream;
            };
        }

        if (typeof originalOpenSync === 'function') {
            hooked.openSync = function(filePath) {
                const fd = originalOpenSync.apply(this, arguments);
                try {
                    if (!inFdFix && isStorageJsonPath(filePath)) {
                        storageJsonFds.set(fd, filePath);
                    }
                } catch (_) {
                    // ignore
                }
                return fd;
            };
        }

        if (typeof originalOpen === 'function') {
            hooked.open = function(filePath, flags, mode, callback) {
                if (typeof mode === 'function') {
                    callback = mode;
                    mode = undefined;
                }

                const wrapped = function(err, fd) {
                    try {
                        if (!err && !inFdFix && isStorageJsonPath(filePath)) {
                            storageJsonFds.set(fd, filePath);
                        }
                    } catch (_) {
                        // ignore
                    }
                    if (typeof callback === 'function') {
                        return callback.apply(this, arguments);
                    }
                };

                if (mode === undefined) {
                    return originalOpen.call(this, filePath, flags, wrapped);
                }
                return originalOpen.call(this, filePath, flags, mode, wrapped);
            };
        }

        if (typeof originalCloseSync === 'function') {
            hooked.closeSync = function(fd) {
                const filePath = storageJsonFds.get(fd);
                const ret = originalCloseSync.apply(this, arguments);
                if (filePath !== undefined) {
                    storageJsonFds.delete(fd);
                    fixStorageJsonFile(filePath);
                }
                return ret;
            };
        }

        if (typeof originalClose === 'function') {
            hooked.close = function(fd, callback) {
                const filePath = storageJsonFds.get(fd);
                const wrapped = function(err) {
                    try {
                        if (!err && filePath !== undefined) {
                            storageJsonFds.delete(fd);
                            fixStorageJsonFile(filePath);
                        }
                    } catch (_) {
                        // ignore
                    }
                    if (typeof callback === 'function') {
                        return callback.apply(this, arguments);
                    }
                };
                return originalClose.call(this, fd, wrapped);
            };
        }

        log('动态导入: 已 Hook fs 模块');
        hookedDynamicModules.set('fs', hooked);
        return hooked;
    };

    // 将 Hook 函数暴露到全局,供后续使用
    globalThis.__cursor_hook_dynamic__ = {
        crypto: hookDynamicCrypto,
        deviceId: hookDynamicDeviceId,
        windowsRegistry: hookDynamicWindowsRegistry,
        fs: hookDynamicFs,  // 新增 fs Hook
        ids: __cursor_ids__
    };

    log('Cursor Hook 初始化完成');
    log('machineId:', __cursor_ids__.machineId.substring(0, 16) + '...');
    log('machineGuid:', getMachineGuid().substring(0, 16) + '...');
    log('devDeviceId:', __cursor_ids__.devDeviceId);
    log('sqmId:', __cursor_ids__.sqmId);

})();

// ==================== 导出配置(供外部使用) ====================
if (typeof module !== 'undefined' && module.exports) {
    module.exports = { __cursor_hook_config__ };
}

// ==================== ES Module 兼容性 ====================
// 如果在 ES Module 环境中,也暴露配置
if (typeof globalThis !== 'undefined') {
    globalThis.__cursor_hook_config__ = __cursor_hook_config__;
}


================================================
FILE: scripts/hook/inject_hook_unix.sh
================================================
#!/bin/bash

# ========================================
# Cursor Hook 注入脚本 (macOS/Linux)
# ========================================
#
# 🎯 功能:将 cursor_hook.js 注入到 Cursor 的 main.js 文件顶部
# 
# 📦 使用方式:
# chmod +x inject_hook_unix.sh
# ./inject_hook_unix.sh
#
# 参数:
#   --rollback  回滚到原始版本
#   --force     强制重新注入
#   --debug     启用调试模式
#
# ========================================

set -e

# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'

# 参数解析
ROLLBACK=false
FORCE=false
DEBUG=false

for arg in "$@"; do
    case $arg in
        --rollback) ROLLBACK=true ;;
        --force) FORCE=true ;;
        --debug) DEBUG=true ;;
    esac
done

# 日志函数
log_info() { echo -e "${GREEN}[INFO]${NC} $1"; }
log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
log_error() { echo -e "${RED}[ERROR]${NC} $1"; }
log_debug() { if $DEBUG; then echo -e "${BLUE}[DEBUG]${NC} $1"; fi; }

# 获取脚本所在目录
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
HOOK_SCRIPT="$SCRIPT_DIR/cursor_hook.js"

# 获取 Cursor main.js 路径
get_cursor_path() {
    local paths=()
    
    if [[ "$OSTYPE" == "darwin"* ]]; then
        # macOS
        paths=(
            "/Applications/Cursor.app/Contents/Resources/app/out/main.js"
            "$HOME/Applications/Cursor.app/Contents/Resources/app/out/main.js"
        )
    else
        # Linux
        paths=(
            "/opt/Cursor/resources/app/out/main.js"
            "/usr/share/cursor/resources/app/out/main.js"
            "$HOME/.local/share/cursor/resources/app/out/main.js"
            "/snap/cursor/current/resources/app/out/main.js"
        )
    fi
    
    for path in "${paths[@]}"; do
        if [[ -f "$path" ]]; then
            echo "$path"
            return 0
        fi
    done
    
    return 1
}

# 检查是否已注入
check_already_injected() {
    local main_js="$1"
    grep -q "__cursor_patched__" "$main_js" 2>/dev/null
}

# 备份原始文件
backup_main_js() {
    local main_js="$1"
    local backup_dir="$(dirname "$main_js")/backups"
    
    mkdir -p "$backup_dir"
    
    local timestamp=$(date +%Y%m%d_%H%M%S)
    local backup_path="$backup_dir/main.js.backup_$timestamp"
    local original_backup="$backup_dir/main.js.original"
    
    # 创建原始备份(如果不存在)
    if [[ ! -f "$original_backup" ]]; then
        cp "$main_js" "$original_backup"
        log_info "已创建原始备份: $original_backup"
    fi
    
    cp "$main_js" "$backup_path"
    log_info "已创建时间戳备份: $backup_path"
    
    echo "$original_backup"
}

# 回滚到原始版本
restore_main_js() {
    local main_js="$1"
    local backup_dir="$(dirname "$main_js")/backups"
    local original_backup="$backup_dir/main.js.original"
    
    if [[ -f "$original_backup" ]]; then
        cp "$original_backup" "$main_js"
        log_info "已回滚到原始版本"
        return 0
    else
        log_error "未找到原始备份文件"
        return 1
    fi
}

# 关闭 Cursor 进程
stop_cursor_process() {
    if [[ "$OSTYPE" == "darwin"* ]]; then
        # macOS
        pkill -x "Cursor" 2>/dev/null || true
        pkill -x "Cursor Helper" 2>/dev/null || true
    else
        # Linux
        pkill -f "cursor" 2>/dev/null || true
    fi
    
    sleep 2
    log_info "Cursor 进程已关闭"
}

# 注入 Hook 代码
inject_hook() {
    local main_js="$1"
    local hook_script="$2"
    
    # 读取 Hook 脚本内容
    local hook_content=$(cat "$hook_script")
    
    # 创建临时文件
    local temp_file=$(mktemp)
    
    # 读取 main.js 并注入 Hook
    # 在版权声明之后注入
    awk -v hook="$hook_content" '
    /^\*\// && !injected {
        print
        print ""
        print "// ========== Cursor Hook 注入开始 =========="
        print hook
        print "// ========== Cursor Hook 注入结束 =========="
        print ""
        injected = 1
        next
    }
    { print }
    ' "$main_js" > "$temp_file"
    
    # 替换原文件
    mv "$temp_file" "$main_js"

    return 0
}

# 主函数
main() {
    echo ""
    echo -e "${BLUE}========================================${NC}"
    echo -e "${BLUE}   Cursor Hook 注入工具 (Unix)         ${NC}"
    echo -e "${BLUE}========================================${NC}"
    echo ""

    # 获取 Cursor main.js 路径
    local main_js
    main_js=$(get_cursor_path) || {
        log_error "未找到 Cursor 安装路径"
        log_error "请确保 Cursor 已正确安装"
        exit 1
    }
    log_info "找到 Cursor main.js: $main_js"

    # 回滚模式
    if $ROLLBACK; then
        log_info "执行回滚操作..."
        stop_cursor_process
        if restore_main_js "$main_js"; then
            log_info "回滚成功!"
        else
            log_error "回滚失败!"
            exit 1
        fi
        exit 0
    fi

    # 检查是否已注入
    if check_already_injected "$main_js" && ! $FORCE; then
        log_warn "Hook 已经注入,无需重复操作"
        log_info "如需强制重新注入,请使用 --force 参数"
        exit 0
    fi

    # 检查 Hook 脚本是否存在
    if [[ ! -f "$HOOK_SCRIPT" ]]; then
        log_error "未找到 cursor_hook.js 文件"
        log_error "请确保 cursor_hook.js 与此脚本在同一目录"
        exit 1
    fi
    log_info "找到 Hook 脚本: $HOOK_SCRIPT"

    # 关闭 Cursor 进程
    stop_cursor_process

    # 备份原始文件
    log_info "正在备份原始文件..."
    backup_main_js "$main_js"

    # 注入 Hook 代码
    log_info "正在注入 Hook 代码..."
    if inject_hook "$main_js" "$HOOK_SCRIPT"; then
        log_info "Hook 注入成功!"
    else
        log_error "Hook 注入失败!"
        log_warn "正在回滚..."
        restore_main_js "$main_js"
        exit 1
    fi

    echo ""
    echo -e "${GREEN}========================================${NC}"
    echo -e "${GREEN}   ✅ Hook 注入完成!                   ${NC}"
    echo -e "${GREEN}========================================${NC}"
    echo ""
    log_info "现在可以启动 Cursor 了"
    log_info "ID 配置文件位置: ~/.cursor_ids.json"
    echo ""
    echo -e "${YELLOW}提示:${NC}"
    echo "  - 如需回滚,请运行: ./inject_hook_unix.sh --rollback"
    echo "  - 如需强制重新注入,请运行: ./inject_hook_unix.sh --force"
    echo "  - 如需启用调试日志,请运行: ./inject_hook_unix.sh --debug"
    echo ""
}

# 执行主函数
main



================================================
FILE: scripts/hook/inject_hook_win.ps1
================================================
# ========================================
# Cursor Hook 注入脚本 (Windows)
# ========================================
#
# 🎯 功能:将 cursor_hook.js 注入到 Cursor 的 main.js 文件顶部
# 
# 📦 使用方式:
# 1. 以管理员权限运行 PowerShell
# 2. 执行: .\inject_hook_win.ps1
#
# ⚠️ 注意事项:
# - 会自动备份原始 main.js 文件
# - 支持回滚到原始版本
# - Cursor 更新后需要重新注入
#
# ========================================

param(
    [switch]$Rollback,  # 回滚到原始版本
    [switch]$Force,     # 强制重新注入
    [switch]$Debug      # 启用调试模式
)

# 颜色定义
$RED = "`e[31m"
$GREEN = "`e[32m"
$YELLOW = "`e[33m"
$BLUE = "`e[34m"
$NC = "`e[0m"

# 日志函数
function Write-Log {
    param([string]$Message, [string]$Level = "INFO")
    $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
    switch ($Level) {
        "INFO"  { Write-Host "$GREEN[INFO]$NC $Message" }
        "WARN"  { Write-Host "$YELLOW[WARN]$NC $Message" }
        "ERROR" { Write-Host "$RED[ERROR]$NC $Message" }
        "DEBUG" { if ($Debug) { Write-Host "$BLUE[DEBUG]$NC $Message" } }
    }
}

# 获取 Cursor 安装路径
function Get-CursorPath {
    $possiblePaths = @(
        "$env:LOCALAPPDATA\Programs\cursor\resources\app\out\main.js",
        "$env:LOCALAPPDATA\Programs\Cursor\resources\app\out\main.js",
        "C:\Program Files\Cursor\resources\app\out\main.js",
        "C:\Program Files (x86)\Cursor\resources\app\out\main.js"
    )
    
    foreach ($path in $possiblePaths) {
        if (Test-Path $path) {
            return $path
        }
    }
    
    return $null
}

# 获取 Hook 脚本路径
function Get-HookScriptPath {
    $scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
    $hookPath = Join-Path $scriptDir "cursor_hook.js"
    
    if (Test-Path $hookPath) {
        return $hookPath
    }
    
    # 尝试从当前目录查找
    $currentDir = Get-Location
    $hookPath = Join-Path $currentDir "cursor_hook.js"
    
    if (Test-Path $hookPath) {
        return $hookPath
    }
    
    return $null
}

# 检查是否已注入
function Test-AlreadyInjected {
    param([string]$MainJsPath)
    
    $content = Get-Content $MainJsPath -Raw -Encoding UTF8
    return $content -match "__cursor_patched__"
}

# 备份原始文件
function Backup-MainJs {
    param([string]$MainJsPath)
    
    $backupDir = Join-Path (Split-Path -Parent $MainJsPath) "backups"
    if (-not (Test-Path $backupDir)) {
        New-Item -ItemType Directory -Path $backupDir -Force | Out-Null
    }
    
    $timestamp = Get-Date -Format "yyyyMMdd_HHmmss"
    $backupPath = Join-Path $backupDir "main.js.backup_$timestamp"
    
    # 检查是否有原始备份
    $originalBackup = Join-Path $backupDir "main.js.original"
    if (-not (Test-Path $originalBackup)) {
        Copy-Item $MainJsPath $originalBackup -Force
        Write-Log "已创建原始备份: $originalBackup"
    }
    
    Copy-Item $MainJsPath $backupPath -Force
    Write-Log "已创建时间戳备份: $backupPath"
    
    return $originalBackup
}

# 回滚到原始版本
function Restore-MainJs {
    param([string]$MainJsPath)
    
    $backupDir = Join-Path (Split-Path -Parent $MainJsPath) "backups"
    $originalBackup = Join-Path $backupDir "main.js.original"
    
    if (Test-Path $originalBackup) {
        Copy-Item $originalBackup $MainJsPath -Force
        Write-Log "已回滚到原始版本" "INFO"
        return $true
    } else {
        Write-Log "未找到原始备份文件" "ERROR"
        return $false
    }
}

# 注入 Hook 代码
function Inject-Hook {
    param(
        [string]$MainJsPath,
        [string]$HookScriptPath
    )
    
    # 读取 Hook 脚本内容
    $hookContent = Get-Content $HookScriptPath -Raw -Encoding UTF8
    
    # 读取 main.js 内容
    $mainContent = Get-Content $MainJsPath -Raw -Encoding UTF8
    
    # 查找注入点:在 Sentry 初始化代码之后
    # Sentry 初始化代码特征: _sentryDebugIds
    $sentryPattern = '(?<=\}\(\);)\s*(?=var\s+\w+\s*=\s*function)'
    
    if ($mainContent -match $sentryPattern) {
        # 在 Sentry 初始化之后注入
        $injectionPoint = $mainContent.IndexOf('}();') + 4
        $newContent = $mainContent.Substring(0, $injectionPoint) + "`n`n// ========== Cursor Hook 注入开始 ==========`n" + $hookContent + "`n// ========== Cursor Hook 注入结束 ==========`n`n" + $mainContent.Substring($injectionPoint)
    } else {
        # 如果找不到 Sentry,直接在文件开头注入(在版权声明之后)
        $copyrightEnd = $mainContent.IndexOf('*/') + 2
        if ($copyrightEnd -gt 2) {
            $newContent = $mainContent.Substring(0, $copyrightEnd) + "`n`n// ========== Cursor Hook 注入开始 ==========`n" + $hookContent + "`n// ========== Cursor Hook 注入结束 ==========`n`n" + $mainContent.Substring($copyrightEnd)
        } else {
            $newContent = "// ========== Cursor Hook 注入开始 ==========`n" + $hookContent + "`n// ========== Cursor Hook 注入结束 ==========`n`n" + $mainContent
        }
    }
    
    # 写入修改后的内容
    Set-Content -Path $MainJsPath -Value $newContent -Encoding UTF8 -NoNewline

    return $true
}

# 关闭 Cursor 进程
function Stop-CursorProcess {
    $cursorProcesses = Get-Process -Name "Cursor*" -ErrorAction SilentlyContinue

    if ($cursorProcesses) {
        Write-Log "发现 Cursor 进程正在运行,正在关闭..."
        $cursorProcesses | Stop-Process -Force
        Start-Sleep -Seconds 2
        Write-Log "Cursor 进程已关闭"
    }
}

# 主函数
function Main {
    Write-Host ""
    Write-Host "$BLUE========================================$NC"
    Write-Host "$BLUE   Cursor Hook 注入工具 (Windows)      $NC"
    Write-Host "$BLUE========================================$NC"
    Write-Host ""

    # 获取 Cursor main.js 路径
    $mainJsPath = Get-CursorPath
    if (-not $mainJsPath) {
        Write-Log "未找到 Cursor 安装路径" "ERROR"
        Write-Log "请确保 Cursor 已正确安装" "ERROR"
        exit 1
    }
    Write-Log "找到 Cursor main.js: $mainJsPath"

    # 回滚模式
    if ($Rollback) {
        Write-Log "执行回滚操作..."
        Stop-CursorProcess
        if (Restore-MainJs -MainJsPath $mainJsPath) {
            Write-Log "回滚成功!" "INFO"
        } else {
            Write-Log "回滚失败!" "ERROR"
            exit 1
        }
        exit 0
    }

    # 检查是否已注入
    if ((Test-AlreadyInjected -MainJsPath $mainJsPath) -and -not $Force) {
        Write-Log "Hook 已经注入,无需重复操作" "WARN"
        Write-Log "如需强制重新注入,请使用 -Force 参数" "INFO"
        exit 0
    }

    # 获取 Hook 脚本路径
    $hookScriptPath = Get-HookScriptPath
    if (-not $hookScriptPath) {
        Write-Log "未找到 cursor_hook.js 文件" "ERROR"
        Write-Log "请确保 cursor_hook.js 与此脚本在同一目录" "ERROR"
        exit 1
    }
    Write-Log "找到 Hook 脚本: $hookScriptPath"

    # 关闭 Cursor 进程
    Stop-CursorProcess

    # 备份原始文件
    Write-Log "正在备份原始文件..."
    $backupPath = Backup-MainJs -MainJsPath $mainJsPath

    # 注入 Hook 代码
    Write-Log "正在注入 Hook 代码..."
    try {
        if (Inject-Hook -MainJsPath $mainJsPath -HookScriptPath $hookScriptPath) {
            Write-Log "Hook 注入成功!" "INFO"
        } else {
            Write-Log "Hook 注入失败!" "ERROR"
            exit 1
        }
    } catch {
        Write-Log "注入过程中发生错误: $_" "ERROR"
        Write-Log "正在回滚..." "WARN"
        Restore-MainJs -MainJsPath $mainJsPath
        exit 1
    }

    Write-Host ""
    Write-Host "$GREEN========================================$NC"
    Write-Host "$GREEN   ✅ Hook 注入完成!                   $NC"
    Write-Host "$GREEN========================================$NC"
    Write-Host ""
    Write-Log "现在可以启动 Cursor 了"
    Write-Log "ID 配置文件位置: $env:USERPROFILE\.cursor_ids.json"
    Write-Host ""
    Write-Host "$YELLOW提示:$NC"
    Write-Host "  - 如需回滚,请运行: .\inject_hook_win.ps1 -Rollback"
    Write-Host "  - 如需强制重新注入,请运行: .\inject_hook_win.ps1 -Force"
    Write-Host "  - 如需启用调试日志,请运行: .\inject_hook_win.ps1 -Debug"
    Write-Host ""
}

# 执行主函数
Main



================================================
FILE: scripts/run/cursor_linux_id_modifier.sh
================================================
#!/bin/bash

# 设置错误处理
set -e

# 定义日志文件路径
LOG_FILE="/tmp/cursor_linux_id_modifier.log"

# 初始化日志文件
initialize_log() {
    echo "========== Cursor ID 修改工具日志开始 $(date) ==========" > "$LOG_FILE"
    chmod 644 "$LOG_FILE"
}

# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color

# 显式禁用时,关闭 TTY UI(resize/clear/Logo),避免部分环境乱码/花屏
if [ -n "${CURSOR_NO_TTY_UI:-}" ]; then
    CURSOR_NO_TTY_UI=1
fi

# UI/颜色开关:遵循 NO_COLOR 标准,并支持 CURSOR_NO_TTY_UI(禁用花哨 TTY UI)
if [ -n "${NO_COLOR:-}" ] || [ -n "${CURSOR_NO_COLOR:-}" ] || [ -n "${CURSOR_NO_TTY_UI:-}" ]; then
    RED=''
    GREEN=''
    YELLOW=''
    BLUE=''
    NC=''
fi

# 启动时尝试调整终端窗口大小为 120x40(列x行);不支持/失败时静默忽略,避免影响脚本主流程
try_resize_terminal_window() {
    local target_cols=120
    local target_rows=40

    # 可通过 CURSOR_NO_TTY_UI 显式禁用所有终端控制输出(避免部分环境乱码/花屏)
    if [ -n "${CURSOR_NO_TTY_UI:-}" ]; then
        return 0
    fi

    # 仅在交互终端中尝试,避免输出被重定向时出现乱码
    if [ ! -t 1 ]; then
        return 0
    fi

    case "${TERM:-}" in
        ""|dumb)
            return 0
            ;;
    esac

    # 终端类型检测:仅对常见 xterm 体系终端尝试窗口调整(GNOME Terminal/Konsole/xterm/Terminator 等通常为 xterm*)
    case "${TERM:-}" in
        xterm*|screen*|tmux*|rxvt*|alacritty*|kitty*|foot*|wezterm*)
            ;;
        *)
            return 0
            ;;
    esac

    # 优先通过 xterm 窗口控制序列调整;在 tmux/screen 下需要 passthrough 包装
    if [ -n "${TMUX:-}" ]; then
        printf '\033Ptmux;\033\033[8;%d;%dt\033\\' "$target_rows" "$target_cols" 2>/dev/null || true
    elif [ -n "${STY:-}" ]; then
        printf '\033P\033[8;%d;%dt\033\\' "$target_rows" "$target_cols" 2>/dev/null || true
    else
        printf '\033[8;%d;%dt' "$target_rows" "$target_cols" 2>/dev/null || true
    fi

    return 0
}

# 日志函数 - 同时输出到终端和日志文件
log_info() {
    echo -e "${GREEN}[INFO]${NC} $1"
    echo "[INFO] $(date '+%Y-%m-%d %H:%M:%S') $1" >> "$LOG_FILE"
}

log_warn() {
    echo -e "${YELLOW}[WARN]${NC} $1"
    echo "[WARN] $(date '+%Y-%m-%d %H:%M:%S') $1" >> "$LOG_FILE"
}

log_error() {
    echo -e "${RED}[ERROR]${NC} $1"
    echo "[ERROR] $(date '+%Y-%m-%d %H:%M:%S') $1" >> "$LOG_FILE"
}

log_debug() {
    echo -e "${BLUE}[DEBUG]${NC} $1"
    echo "[DEBUG] $(date '+%Y-%m-%d %H:%M:%S') $1" >> "$LOG_FILE"
}

# 记录命令输出到日志文件
log_cmd_output() {
    local cmd="$1"
    local msg="$2"
    echo "[CMD] $(date '+%Y-%m-%d %H:%M:%S') 执行命令: $cmd" >> "$LOG_FILE"
    echo "[CMD] $msg:" >> "$LOG_FILE"
    eval "$cmd" 2>&1 | tee -a "$LOG_FILE"
    echo "" >> "$LOG_FILE"
}

# sed -i 兼容封装:优先原地编辑;不支持/失败时回退到临时文件替换,提升跨发行版兼容性
sed_inplace() {
    local expr="$1"
    local file="$2"

    # GNU sed / BusyBox sed:通常支持 sed -i
    if sed -i "$expr" "$file" 2>/dev/null; then
        return 0
    fi

    # BSD sed:需要提供 -i '' 形式(少数环境可能出现)
    if sed -i '' "$expr" "$file" 2>/dev/null; then
        return 0
    fi

    # 最后兜底:临时文件替换(避免不同 sed 的 -i 语义差异)
    local temp_file
    temp_file=$(mktemp) || return 1
    if sed "$expr" "$file" > "$temp_file"; then
        cat "$temp_file" > "$file"
        rm -f "$temp_file"
        return 0
    fi
    rm -f "$temp_file"
    return 1
}

# 路径解析兼容:优先 realpath;缺失时回退到 readlink -f / python3 / cd+pwd(避免命令缺失触发 set -e)
resolve_path() {
    local target="$1"

    if command -v realpath >/dev/null 2>&1; then
        realpath "$target" 2>/dev/null && return 0
    fi

    if command -v readlink >/dev/null 2>&1; then
        readlink -f "$target" 2>/dev/null && return 0
    fi

    if command -v python3 >/dev/null 2>&1; then
        python3 -c 'import os,sys; print(os.path.realpath(sys.argv[1]))' "$target" 2>/dev/null && return 0
    fi

    # 最后兜底:不解析符号链接,仅尽量返回绝对路径
    if [ -d "$target" ]; then
        (cd "$target" 2>/dev/null && pwd -P) && return 0
    fi
    local dir
    dir=$(dirname "$target")
    (cd "$dir" 2>/dev/null && printf "%s/%s\n" "$(pwd -P)" "$(basename "$target")") && return 0

    echo "$target"
    return 0
}

# 获取当前用户
get_current_user() {
    # sudo 场景:优先以 SUDO_USER 作为目标用户(Cursor 通常运行在该用户下)
    if [ "$EUID" -eq 0 ] && [ -n "${SUDO_USER:-}" ]; then
        echo "$SUDO_USER"
        return 0
    fi

    # 普通/直跑 root 场景:使用当前有效用户
    if command -v id >/dev/null 2>&1; then
        id -un 2>/dev/null && return 0
    fi
    echo "${USER:-}"
}

# 获取指定用户的 Home 目录(兼容 sudo/root/容器等场景)
get_user_home_dir() {
    local user="$1"
    local home=""

    if command -v getent >/dev/null 2>&1; then
        home=$(getent passwd "$user" 2>/dev/null | awk -F: '{print $6}' | head -n 1)
    fi
    if [ -z "$home" ] && [ -f /etc/passwd ]; then
        home=$(awk -F: -v u="$user" '$1==u {print $6; exit}' /etc/passwd 2>/dev/null)
    fi
    if [ -z "$home" ]; then
        home=$(eval echo "~$user" 2>/dev/null)
    fi

    # 兜底:无法解析时使用当前环境 HOME
    if [ -z "$home" ] || [[ "$home" == "~"* ]]; then
        home="${HOME:-}"
    fi

    echo "$home"
}

# 获取指定用户的主组(chown 需要 user:group;不同发行版 id 参数/输出可能存在差异)
get_user_primary_group() {
    local user="$1"
    local group=""
    local gid=""

    # 优先:直接获取主组名(最简洁)
    if command -v id >/dev/null 2>&1; then
        group=$(id -gn "$user" 2>/dev/null | tr -d '\r\n') || true
        if [ -n "$group" ]; then
            echo "$group"
            return 0
        fi

        # 回退:先取 gid,再映射为组名(映射失败则直接返回 gid,chown 同样可用)
        gid=$(id -g "$user" 2>/dev/null | tr -d '\r\n') || true
    fi

    if [ -n "$gid" ]; then
        if command -v getent >/dev/null 2>&1; then
            group=$(getent group "$gid" 2>/dev/null | awk -F: '{print $1}' | head -n 1) || true
        fi
        if [ -z "$group" ] && [ -f /etc/group ]; then
            group=$(awk -F: -v g="$gid" '$3==g {print $1; exit}' /etc/group 2>/dev/null) || true
        fi

        if [ -n "$group" ]; then
            echo "$group"
            return 0
        fi

        echo "$gid"
        return 0
    fi

    # 最后兜底:返回用户本身(少数系统允许 user:user)
    echo "$user"
    return 0
}

CURRENT_USER=$(get_current_user)
if [ -z "$CURRENT_USER" ]; then
    log_error "无法获取用户名"
    exit 1
fi

# 🎯 统一“目标用户/目标 Home”:后续所有 Cursor 用户数据路径均基于该 Home
TARGET_HOME=$(get_user_home_dir "$CURRENT_USER")
if [ -z "$TARGET_HOME" ]; then
    log_error "无法解析目标用户 Home 目录: $CURRENT_USER"
    exit 1
fi
log_info "目标用户: $CURRENT_USER"
log_info "目标用户 Home: $TARGET_HOME"

# 🎯 统一“目标用户主组”:chown 时不再依赖 id -g -n 的兼容性
CURRENT_GROUP=$(get_user_primary_group "$CURRENT_USER")
if [ -z "$CURRENT_GROUP" ]; then
    CURRENT_GROUP="$CURRENT_USER"
    log_warn "无法解析目标用户主组,已回退为: $CURRENT_GROUP(后续 chown 可能失败)"
else
    log_info "目标用户主组: $CURRENT_GROUP"
fi

# 定义Linux下的Cursor路径
CURSOR_CONFIG_DIR="$TARGET_HOME/.config/Cursor"
STORAGE_FILE="$CURSOR_CONFIG_DIR/User/globalStorage/storage.json"
BACKUP_DIR="$CURSOR_CONFIG_DIR/User/globalStorage/backups"

# 共享ID(用于配置与JS注入保持一致)
CURSOR_ID_MACHINE_ID=""
CURSOR_ID_MACHINE_GUID=""
CURSOR_ID_MAC_MACHINE_ID=""
CURSOR_ID_DEVICE_ID=""
CURSOR_ID_SQM_ID=""
CURSOR_ID_FIRST_SESSION_DATE=""
CURSOR_ID_SESSION_ID=""
CURSOR_ID_MAC_ADDRESS="00:11:22:33:44:55"

# --- 新增:安装相关变量 ---
APPIMAGE_SEARCH_DIR="/opt/CursorInstall" # AppImage 搜索目录,可按需修改
APPIMAGE_PATTERN="Cursor-*.AppImage"     # AppImage 文件名模式
INSTALL_DIR="/opt/Cursor"                # Cursor 最终安装目录
ICON_PATH="/usr/share/icons/cursor.png"
DESKTOP_FILE="/usr/share/applications/cursor-cursor.desktop"
# --- 结束:安装相关变量 ---

# 可能的Cursor二进制路径 - 添加了标准安装路径
CURSOR_BIN_PATHS=(
    "/usr/bin/cursor"
    "/usr/local/bin/cursor"
    "$INSTALL_DIR/cursor"               # 添加标准安装路径
    "$TARGET_HOME/.local/bin/cursor"
    "/snap/bin/cursor"
)

# 找到Cursor安装路径
find_cursor_path() {
    log_info "查找Cursor安装路径..."
    
    for path in "${CURSOR_BIN_PATHS[@]}"; do
        if [ -f "$path" ] && [ -x "$path" ]; then # 确保文件存在且可执行
            log_info "找到Cursor安装路径: $path"
            CURSOR_PATH="$path"
            return 0
        fi
    done

    # 尝试通过which命令定位
    if command -v cursor &> /dev/null; then
        # 兼容修复:部分发行版没有 which;command -v 已可直接返回路径
        CURSOR_PATH=$(command -v cursor)
        log_info "通过 command -v 找到 Cursor: $CURSOR_PATH"
        return 0
    fi
    
    # 尝试查找可能的安装路径 (限制搜索范围和类型)
    # 兼容修复:find 的 -executable 在 BusyBox 等环境可能不可用,且 find 报错返回非0会触发 set -e;这里统一兜底处理
    local cursor_paths=""

    # 优先:使用 -executable(若受支持)
    cursor_paths=$(find /usr /opt "$TARGET_HOME/.local" -type f -name "cursor" -executable 2>/dev/null || true)

    # 回退:不依赖 -executable,改用 shell 过滤可执行
    if [ -z "$cursor_paths" ]; then
        cursor_paths=$(find /usr /opt "$TARGET_HOME/.local" -type f -name "cursor" 2>/dev/null || true)
        cursor_paths=$(echo "$cursor_paths" | while IFS= read -r p; do [ -n "$p" ] && [ -x "$p" ] && echo "$p"; done)
    fi

    # 额外兜底:标准安装路径优先
    if [ -x "$INSTALL_DIR/cursor" ]; then
        cursor_paths="$INSTALL_DIR/cursor"$'\n'"$cursor_paths"
    fi
    if [ -n "$cursor_paths" ]; then
        # 优先选择标准安装路径
        local standard_path=$(echo "$cursor_paths" | grep "$INSTALL_DIR/cursor" | head -1)
        if [ -n "$standard_path" ]; then
            CURSOR_PATH="$standard_path"
        else
            CURSOR_PATH=$(echo "$cursor_paths" | head -1)
        fi
        log_info "通过查找找到Cursor: $CURSOR_PATH"
        return 0
    fi
    
    log_warn "未找到Cursor可执行文件"
    return 1
}

# 查找并定位Cursor资源文件目录
find_cursor_resources() {
    log_info "查找Cursor资源目录..."
    
    # 可能的资源目录路径 - 添加了标准安装目录
    local resource_paths=(
        "$INSTALL_DIR" # 添加标准安装路径
        "/usr/lib/cursor"
        "/usr/share/cursor"
        "$TARGET_HOME/.local/share/cursor"
    )
    
    for path in "${resource_paths[@]}"; do
        if [ -d "$path/resources" ]; then # 检查是否存在 resources 子目录
            log_info "找到Cursor资源目录: $path"
            CURSOR_RESOURCES="$path"
            return 0
        fi
         if [ -d "$path/app" ]; then # 有些版本可能直接是 app 目录
             log_info "找到Cursor资源目录 (app): $path"
             CURSOR_RESOURCES="$path"
             return 0
         fi
    done
    
    # 如果有CURSOR_PATH,尝试从它推断
    if [ -n "$CURSOR_PATH" ]; then
        local base_dir=$(dirname "$CURSOR_PATH")
        # 检查常见的相对路径
        if [ -d "$base_dir/resources" ]; then
            CURSOR_RESOURCES="$base_dir"
            log_info "通过二进制路径找到资源目录: $CURSOR_RESOURCES"
            return 0
        elif [ -d "$base_dir/../resources" ]; then # 例如在 bin 目录内
            CURSOR_RESOURCES=$(resolve_path "$base_dir/..")
            log_info "通过二进制路径找到资源目录: $CURSOR_RESOURCES"
            return 0
        elif [ -d "$base_dir/../lib/cursor/resources" ]; then # 另一种常见结构
            CURSOR_RESOURCES=$(resolve_path "$base_dir/../lib/cursor")
            log_info "通过二进制路径找到资源目录: $CURSOR_RESOURCES"
            return 0
        fi
    fi
    
    log_warn "未找到Cursor资源目录"
    return 1
}

# 检查权限
check_permissions() {
    if [ "$EUID" -ne 0 ]; then
        log_error "请使用 sudo 运行此脚本 (安装和修改系统文件需要权限)"
        echo "示例: sudo $0"
        exit 1
    fi
}

# --- 新增/重构:从本地 AppImage 安装 Cursor ---
install_cursor_appimage() {
    log_info "开始尝试从本地 AppImage 安装 Cursor..."
    local found_appimage_path=""

    # 确保搜索目录存在
    mkdir -p "$APPIMAGE_SEARCH_DIR"

    # 查找 AppImage 文件
    find_appimage() {
        # 兼容修复:find 参数在不同实现中可能有差异,且 find 非0 会触发 set -e;这里统一兜底为成功返回
        found_appimage_path=$(find "$APPIMAGE_SEARCH_DIR" -maxdepth 1 -name "$APPIMAGE_PATTERN" -print -quit 2>/dev/null || true)
        if [ -z "$found_appimage_path" ]; then
            return 1
        else
            return 0
        fi
    }

    if ! find_appimage; then
        log_warn "在 '$APPIMAGE_SEARCH_DIR' 目录下未找到 '$APPIMAGE_PATTERN' 文件。"
        # --- 新增:添加文件名格式提醒 ---
        log_info "请确保 AppImage 文件名格式类似: Cursor-版本号-架构.AppImage (例如: Cursor-1.0.6-aarch64.AppImage 或 Cursor-x.y.z-x86_64.AppImage)"
        # --- 结束:添加文件名格式提醒 ---
        # 等待用户放置文件
        read -p $"请将 Cursor AppImage 文件放入 '$APPIMAGE_SEARCH_DIR' 目录,然后按 Enter 键继续..."

        # 再次查找
        if ! find_appimage; then
            log_error "在 '$APPIMAGE_SEARCH_DIR' 中仍然找不到 '$APPIMAGE_PATTERN' 文件。安装中止。"
            return 1
        fi
    fi

    log_info "找到 AppImage 文件: $found_appimage_path"
    local appimage_filename=$(basename "$found_appimage_path")

    # 进入搜索目录操作,避免路径问题
    local current_dir=$(pwd)
    cd "$APPIMAGE_SEARCH_DIR" || { log_error "无法进入目录: $APPIMAGE_SEARCH_DIR"; return 1; }

    log_info "设置 '$appimage_filename' 可执行权限..."
    chmod +x "$appimage_filename" || {
        log_error "设置可执行权限失败: $appimage_filename"
        cd "$current_dir"
        return 1
    }

    log_info "解压 AppImage 文件 '$appimage_filename'..."
    # 创建临时解压目录
    local extract_dir="squashfs-root"
    rm -rf "$extract_dir" # 清理旧的解压目录(如果存在)
    
    # 执行解压,将输出重定向避免干扰
    if ./"$appimage_filename" --appimage-extract > /dev/null; then
        log_info "AppImage 解压成功到 '$extract_dir'"
    else
        log_error "解压 AppImage 失败: $appimage_filename"
        rm -rf "$extract_dir" # 清理失败的解压
        cd "$current_dir"
        return 1
    fi

    # 检查解压后的预期目录结构
    local cursor_source_dir=""
    if [ -d "$extract_dir/usr/share/cursor" ]; then
       cursor_source_dir="$extract_dir/usr/share/cursor"
    elif [ -d "$extract_dir" ]; then # 有些 AppImage 可能直接在根目录
       # 进一步检查是否存在关键文件/目录
       if [ -f "$extract_dir/cursor" ] && [ -d "$extract_dir/resources" ]; then
           cursor_source_dir="$extract_dir"
       fi
    fi

    if [ -z "$cursor_source_dir" ]; then
        log_error "解压后的目录 '$extract_dir' 中未找到预期的 Cursor 文件结构 (例如 'usr/share/cursor' 或直接包含 'cursor' 和 'resources')。"
        rm -rf "$extract_dir"
        cd "$current_dir"
        return 1
    fi
     log_info "找到 Cursor 源文件在: $cursor_source_dir"


    log_info "安装 Cursor 到 '$INSTALL_DIR'..."
    # 如果安装目录已存在,先删除 (确保全新安装)
    if [ -d "$INSTALL_DIR" ]; then
        log_warn "发现已存在的安装目录 '$INSTALL_DIR',将先移除..."
        rm -rf "$INSTALL_DIR" || { log_error "移除旧安装目录失败: $INSTALL_DIR"; cd "$current_dir"; return 1; }
    fi
    
    # 创建安装目录的父目录(如果需要)并设置权限
    mkdir -p "$(dirname "$INSTALL_DIR")"
    
    # 移动解压后的内容到安装目录
    if mv "$cursor_source_dir" "$INSTALL_DIR"; then
        log_info "成功将文件移动到 '$INSTALL_DIR'"
        # 确保安装目录及其内容归属当前用户(如果需要)
        chown -R "$CURRENT_USER":"$CURRENT_GROUP" "$INSTALL_DIR" || log_warn "设置 '$INSTALL_DIR' 文件所有权失败,可能需要手动调整"
        chmod -R u+rwX,go+rX,go-w "$INSTALL_DIR" || log_warn "设置 '$INSTALL_DIR' 文件权限失败,可能需要手动调整"
    else
        log_error "移动文件到安装目录 '$INSTALL_DIR' 失败"
        rm -rf "$extract_dir" # 确保清理
        rm -rf "$INSTALL_DIR" # 清理部分移动的文件
        cd "$current_dir"
        return 1
    fi

    # 处理图标和桌面快捷方式 (从脚本执行的原始目录查找)
    cd "$current_dir" # 返回原始目录查找图标等文件

    local icon_source="./cursor.png"
    local desktop_source="./cursor-cursor.desktop"

    if [ -f "$icon_source" ]; then
        log_info "安装图标..."
        mkdir -p "$(dirname "$ICON_PATH")"
        cp "$icon_source" "$ICON_PATH" || log_warn "无法复制图标文件 '$icon_source' 到 '$ICON_PATH'"
        chmod 644 "$ICON_PATH" || log_warn "设置图标文件权限失败: $ICON_PATH"
    else
        log_warn "图标文件 '$icon_source' 在脚本当前目录不存在,跳过图标安装。"
        log_warn "请将 'cursor.png' 文件放置在脚本目录 '$current_dir' 下并重新运行安装(如果需要图标)。"
    fi

    if [ -f "$desktop_source" ]; then
        log_info "安装桌面快捷方式..."
         mkdir -p "$(dirname "$DESKTOP_FILE")"
        cp "$desktop_source" "$DESKTOP_FILE" || log_warn "无法创建桌面快捷方式 '$desktop_source' 到 '$DESKTOP_FILE'"
        chmod 644 "$DESKTOP_FILE" || log_warn "设置桌面文件权限失败: $DESKTOP_FILE"

        # 更新桌面数据库
        log_info "更新桌面数据库..."
        update-desktop-database "$(dirname "$DESKTOP_FILE")" &> /dev/null || log_warn "无法更新桌面数据库,快捷方式可能不会立即显示"
    else
        log_warn "桌面文件 '$desktop_source' 在脚本当前目录不存在,跳过快捷方式安装。"
         log_warn "请将 'cursor-cursor.desktop' 文件放置在脚本目录 '$current_dir' 下并重新运行安装(如果需要快捷方式)。"
    fi

    # 创建符号链接到 /usr/local/bin
    log_info "创建命令行启动链接..."
    ln -sf "$INSTALL_DIR/cursor" /usr/local/bin/cursor || log_warn "无法创建命令行链接 '/usr/local/bin/cursor'"

    # 清理临时文件
    log_info "清理临时文件..."
    cd "$APPIMAGE_SEARCH_DIR" # 返回搜索目录清理
    rm -rf "$extract_dir"
    log_info "正在删除原始 AppImage 文件: $found_appimage_path"
    rm -f "$appimage_filename" # 删除 AppImage 文件

    cd "$current_dir" # 确保返回最终目录

    log_info "Cursor 安装成功!安装目录: $INSTALL_DIR"
    return 0
}
# --- 结束:安装函数 ---

# 检查并关闭 Cursor 进程

# 获取 Cursor 相关进程 PID(兼容 pgrep/ps 多种实现)
get_cursor_pids() {
    local self_pid="$$"
    local pids=""

    # 优先使用 pgrep(更稳定):仅按进程名匹配,避免误匹配到脚本命令行(例如 sudo bash ...cursor_linux_id_modifier.sh)
    if command -v pgrep >/dev/null 2>&1; then
        pids=$(pgrep -i "cursor" 2>/dev/null || true)
        if [ -z "$pids" ]; then
            pids=$(pgrep "cursor" 2>/dev/null || true)
        fi
        if [ -z "$pids" ]; then
            pids=$(pgrep "Cursor" 2>/dev/null || true)
        fi

        if [ -n "$pids" ]; then
            echo "$pids" | awk -v self="$self_pid" '$1 ~ /^[0-9]+$/ && $1 != self {print $1}' | sort -u
            return 0
        fi
    fi

    # 回退:兼容不同 ps 实现(BusyBox 可能不支持 aux / -ef)
    if ps aux >/dev/null 2>&1; then
        ps aux 2>/dev/null \
            | grep -i '[c]ursor' \
            | grep -v "cursor_linux_id_modifier.sh" \
            | awk '{print $2}' \
            | awk -v self="$self_pid" '$1 ~ /^[0-9]+$/ && $1 != self {print $1}' \
            | sort -u
        return 0
    fi

    if ps -ef >/dev/null 2>&1; then
        ps -ef 2>/dev/null \
            | grep -i '[c]ursor' \
            | grep -v "cursor_linux_id_modifier.sh" \
            | awk '{print $2}' \
            | awk -v self="$self_pid" '$1 ~ /^[0-9]+$/ && $1 != self {print $1}' \
            | sort -u
        return 0
    fi

    ps 2>/dev/null \
        | grep -i '[c]ursor' \
        | grep -v "cursor_linux_id_modifier.sh" \
        | awk '{print $1}' \
        | awk -v self="$self_pid" '$1 ~ /^[0-9]+$/ && $1 != self {print $1}' \
        | sort -u
    return 0
}

# 打印 Cursor 相关进程详情(用于排障;不依赖固定列结构)
print_cursor_process_details() {
    log_debug "正在获取 Cursor 进程详细信息:"

    if ps aux >/dev/null 2>&1; then
        ps aux 2>/dev/null | grep -i '[c]ursor' | grep -v "cursor_linux_id_modifier.sh" || true
        return 0
    fi

    if ps -ef >/dev/null 2>&1; then
        ps -ef 2>/dev/null | grep -i '[c]ursor' | grep -v "cursor_linux_id_modifier.sh" || true
        return 0
    fi

    ps 2>/dev/null | grep -i '[c]ursor' | grep -v "cursor_linux_id_modifier.sh" || true
    return 0
}

check_and_kill_cursor() {
    log_info "检查 Cursor 进程..."
    
    local attempt=1
    local max_attempts=5
    
    while [ $attempt -le $max_attempts ]; do
        # 跨发行版兼容:优先 pgrep,其次兼容 ps aux/ps -ef/ps 的 PID 列差异
        local cursor_pids_raw
        cursor_pids_raw=$(get_cursor_pids || true)
        # 将换行分隔的 PID 列表转换为空格分隔,便于传给 kill(避免依赖 xargs)
        CURSOR_PIDS=$(echo "$cursor_pids_raw" | tr '\n' ' ' | sed 's/[[:space:]][[:space:]]*/ /g; s/^ //; s/ $//' || true)
        
        if [ -z "$CURSOR_PIDS" ]; then
            log_info "未发现运行中的 Cursor 进程"
            return 0
        fi
        
        log_warn "发现 Cursor 进程正在运行: $CURSOR_PIDS"
        print_cursor_process_details
        
        log_warn "尝试关闭 Cursor 进程..."
        
        if [ $attempt -eq $max_attempts ]; then
            log_warn "尝试强制终止进程..."
            kill -9 $CURSOR_PIDS 2>/dev/null || true
        else
            kill $CURSOR_PIDS 2>/dev/null || true
        fi
        
        sleep 1
        
        # 再次检查进程是否还在运行
        if [ -z "$(get_cursor_pids | head -n 1)" ]; then
            log_info "Cursor 进程已成功关闭"
            return 0
        fi
        
        log_warn "等待进程关闭,尝试 $attempt/$max_attempts..."
        ((attempt++))
    done
    
    log_error "在 $max_attempts 次尝试后仍无法关闭 Cursor 进程"
    print_cursor_process_details
    log_error "请手动关闭进程后重试"
    exit 1
}

# 备份配置文件
backup_config() {
    if [ ! -f "$STORAGE_FILE" ]; then
        log_warn "配置文件 '$STORAGE_FILE' 不存在,跳过备份"
        return 0
    fi
    
    mkdir -p "$BACKUP_DIR"
    local backup_file="$BACKUP_DIR/storage.json.backup_$(date +%Y%m%d_%H%M%S)"
    
    if cp "$STORAGE_FILE" "$backup_file"; then
        chmod 644 "$backup_file"
        # 确保备份文件归属正确用户
        chown "$CURRENT_USER":"$CURRENT_GROUP" "$backup_file" || log_warn "设置备份文件所有权失败: $backup_file"
        log_info "配置已备份到: $backup_file"
    else
        log_error "备份失败: $STORAGE_FILE"
        exit 1
    fi
    return 0 # 明确返回成功
}

# 生成随机 ID
generate_hex_bytes() {
    local bytes="$1"

    # 优先使用 openssl
    if command -v openssl >/dev/null 2>&1; then
        openssl rand -hex "$bytes"
        return 0
    fi

    # 兜底:/dev/urandom + od(多数发行版可用)
    if [ -r /dev/urandom ] && command -v od >/dev/null 2>&1; then
        # 使用更通用的 od 参数写法,兼容更多发行版实现
        od -An -N "$bytes" -t x1 /dev/urandom | tr -d ' \n'
        return 0
    fi

    # 最后兜底:如果 python3 可用
    if command -v python3 >/dev/null 2>&1; then
        python3 -c 'import os, sys; print(os.urandom(int(sys.argv[1])).hex())' "$bytes"
        return 0
    fi

    log_error "缺少 openssl/od/python3,无法生成随机数(bytes=$bytes)"
    return 1
}

generate_random_id() {
    # 生成32字节(64个十六进制字符)的随机数
    generate_hex_bytes 32
}

# 生成随机 UUID
generate_uuid() {
    # 在Linux上使用uuidgen生成UUID
    if command -v uuidgen &> /dev/null; then
        uuidgen | tr '[:upper:]' '[:lower:]'
    else
        # 备选方案:使用/proc/sys/kernel/random/uuid
        if [ -f /proc/sys/kernel/random/uuid ]; then
            cat /proc/sys/kernel/random/uuid
        else
            # 最后备选方案:使用随机 16 bytes 并格式化(避免 sed 捕获组超 9 的兼容性问题)
            local hex
            hex=$(generate_hex_bytes 16) || return 1
            echo "${hex:0:8}-${hex:8:4}-${hex:12:4}-${hex:16:4}-${hex:20:12}"
        fi
    fi
}

# 规范化 machineId(确保为十六进制字符串)
normalize_machine_id() {
    local raw="$1"
    local cleaned
    cleaned=$(echo "$raw" | tr -d '-' | tr '[:upper:]' '[:lower:]')
    if [[ "$cleaned" =~ ^[0-9a-f]{32,}$ ]]; then
        echo "$cleaned"
        return 0
    fi
    return 1
}

# 从现有配置读取ID(用于JS注入保持一致)
load_ids_from_storage() {
    if [ ! -f "$STORAGE_FILE" ]; then
        return 1
    fi

    if ! command -v python3 >/dev/null 2>&1; then
        log_warn "未检测到 python3,无法从现有配置读取 ID"
        return 1
    fi

    local output
    output=$(python3 - "$STORAGE_FILE" <<'PY'
import json, sys
path = sys.argv[1]
with open(path, "r", encoding="utf-8") as f:
    data = json.load(f)

def pick(keys):
    for k in keys:
        v = data.get(k)
        if isinstance(v, str) and v:
            return v
    return ""

items = {
    "machineId": pick(["telemetry.machineId", "machineId"]),
    "macMachineId": pick(["telemetry.macMachineId"]),
    "devDeviceId": pick(["telemetry.devDeviceId", "deviceId"]),
    "sqmId": pick(["telemetry.sqmId"]),
    "firstSessionDate": pick(["telemetry.firstSessionDate"]),
}

for k, v in items.items():
    print(f"{k}={v}")
PY
)
    if [ $? -ne 0 ] || [ -z "$output" ]; then
        return 1
    fi

    while IFS='=' read -r key value; do
        case "$key" in
            machineId) CURSOR_ID_MACHINE_ID="$value" ;;
            macMachineId) CURSOR_ID_MAC_MACHINE_ID="$value" ;;
            devDeviceId) CURSOR_ID_DEVICE_ID="$value" ;;
            sqmId) CURSOR_ID_SQM_ID="$value" ;;
            firstSessionDate) CURSOR_ID_FIRST_SESSION_DATE="$value" ;;
        esac
    done <<< "$output"

    if [ -n "$CURSOR_ID_MACHINE_ID" ]; then
        local normalized
        if normalized=$(normalize_machine_id "$CURSOR_ID_MACHINE_ID"); then
            if [ "$normalized" != "$CURSOR_ID_MACHINE_ID" ]; then
                log_warn "machineId 非标准格式,JS 注入将使用去除连字符后的值"
            fi
            CURSOR_ID_MACHINE_ID="$normalized"
        else
            log_warn "machineId 无法识别为十六进制,JS 注入将改用新值"
            CURSOR_ID_MACHINE_ID=""
        fi
    fi

    CURSOR_ID_SESSION_ID=$(generate_uuid)
    CURSOR_ID_MAC_ADDRESS="${CURSOR_ID_MAC_ADDRESS:-00:11:22:33:44:55}"

    if [ -n "$CURSOR_ID_MACHINE_ID" ] && [ -n "$CURSOR_ID_MAC_MACHINE_ID" ] && [ -n "$CURSOR_ID_DEVICE_ID" ] && [ -n "$CURSOR_ID_SQM_ID" ]; then
        return 0
    fi
    return 1
}

# 仅用于JS注入的ID生成(不写配置)
generate_ids_for_js_only() {
    CURSOR_ID_MACHINE_ID=$(generate_random_id)
    CURSOR_ID_MACHINE_GUID=$(generate_uuid)
    CURSOR_ID_MAC_MACHINE_ID=$(generate_random_id)
    CURSOR_ID_DEVICE_ID=$(generate_uuid)
    CURSOR_ID_SQM_ID="{$(generate_uuid | tr '[:lower:]' '[:upper:]')}"
    CURSOR_ID_FIRST_SESSION_DATE=$(date -u +"%Y-%m-%dT%H:%M:%S.000Z")
    CURSOR_ID_SESSION_ID=$(generate_uuid)
    CURSOR_ID_MAC_ADDRESS="${CURSOR_ID_MAC_ADDRESS:-00:11:22:33:44:55}"
}

# 修改现有文件
modify_or_add_config() {
    local key="$1"
    local value="$2"
    local file="$3"
    
    if [ ! -f "$file" ]; then
        log_error "配置文件不存在: $file"
        return 1
    fi
    
    # 确保文件对当前执行用户(root)可写
    chmod u+w "$file" || {
        log_error "无法修改文件权限(写): $file"
        return 1
    }
    
    # 创建临时文件
    local temp_file=$(mktemp)
    
    # 检查key是否存在
    if grep -q "\"$key\":[[:space:]]*\"[^\"]*\"" "$file"; then
        # key存在,执行替换 (更精确的匹配)
        sed "s/\\(\"$key\"\\):[[:space:]]*\"[^\"]*\"/\\1: \"$value\"/" "$file" > "$temp_file" || {
            log_error "修改配置失败 (替换): $key in $file"
            rm -f "$temp_file"
            chmod u-w "$file" # 恢复权限
            return 1
        }
         log_debug "已替换 key '$key' 在文件 '$file' 中"
    elif grep -q "}" "$file"; then
         # key不存在, 在最后一个 '}' 前添加新的key-value对
         # 注意:这种方式比较脆弱,如果 JSON 格式不标准或最后一行不是 '}' 会失败
         # 🔧 兼容修复:不依赖 GNU sed 的 \n 替换扩展;同时避免在 `}` 独占一行时生成无效 JSON
         if tail -n 1 "$file" | grep -Eq '^[[:space:]]*}[[:space:]]*$'; then
             # 多行 JSON:在最后一个 `}` 前插入新行,并为上一条属性补上逗号
             awk -v key="$key" -v value="$value" '
             { lines[NR] = $0 }
             END {
                 brace = 0
                 for (i = NR; i >= 1; i--) {
                     if (lines[i] ~ /^[[:space:]]*}[[:space:]]*$/) { brace = i; break }
                 }
                 if (brace == 0) { exit 2 }

                 prev = 0
                 for (i = brace - 1; i >= 1; i--) {
                     if (lines[i] !~ /^[[:space:]]*$/) { prev = i; break }
                 }
                 if (prev > 0) {
                     line = lines[prev]
                     sub(/[[:space:]]*$/, "", line)
                     if (line !~ /{$/ && line !~ /,$/) {
                         lines[prev] = line ","
                     } else {
                         lines[prev] = line
                     }
                 }

                 insert_line = "    \"" key "\": \"" value "\""
                 for (i = 1; i <= NR; i++) {
                     if (i == brace) { print insert_line }
                     print lines[i]
                 }
             }
             ' "$file" > "$temp_file" || {
                 log_error "添加配置失败 (注入): $key to $file"
                 rm -f "$temp_file"
                 chmod u-w "$file" # 恢复权限
                 return 1
             }
         else
             # 单行 JSON:直接在末尾 `}` 前插入键值(避免依赖 sed 的 \\n 扩展)
             sed "s/}[[:space:]]*$/,\"$key\": \"$value\"}/" "$file" > "$temp_file" || {
                 log_error "添加配置失败 (注入): $key to $file"
                 rm -f "$temp_file"
                 chmod u-w "$file" # 恢复权限
                 return 1
             }
         fi
         log_debug "已添加 key '$key' 到文件 '$file' 中"
    else
         log_error "无法确定如何添加配置: $key to $file (文件结构可能不标准)"
         rm -f "$temp_file"
         chmod u-w "$file" # 恢复权限
         return 1
    fi

    # 检查临时文件是否有效
    if [ ! -s "$temp_file" ]; then
        log_error "修改或添加配置后生成的临时文件为空: $key in $file"
        rm -f "$temp_file"
        chmod u-w "$file" # 恢复权限
        return 1
    fi
    
    # 使用 cat 替换原文件内容
    cat "$temp_file" > "$file" || {
        log_error "无法写入更新后的配置到文件: $file"
        rm -f "$temp_file"
        # 尝试恢复权限(如果失败也无大碍)
        chmod u-w "$file" || true
        return 1
    }
    
    rm -f "$temp_file"
    
    # 设置所有者和基础权限(root执行时目标文件是用户家目录下的)
    chown "$CURRENT_USER":"$CURRENT_GROUP" "$file" || log_warn "设置文件所有权失败: $file"
    chmod 644 "$file" || log_warn "设置文件权限失败: $file" # 用户读写,组和其他读
    
    return 0
}

# 生成新的配置
generate_new_config() {
    echo
    log_warn "机器码重置选项"
    
    # 使用菜单选择函数询问用户是否重置机器码
    set +e
    # 默认选择“重置”,满足“默认应全部处理”的需求
    select_menu_option "是否需要重置机器码? (默认:重置并同步修改配置文件):" "不重置 - 仅修改js文件即可|重置 - 同时修改配置文件和机器码" 1
    reset_choice=$?
    set -e
    
    # 记录日志以便调试
    echo "[INPUT_DEBUG] 机器码重置选项选择: $reset_choice" >> "$LOG_FILE"
    
    # 确保配置文件目录存在
    mkdir -p "$(dirname "$STORAGE_FILE")"
    chown "$CURRENT_USER":"$CURRENT_GROUP" "$(dirname "$STORAGE_FILE")" || log_warn "设置配置目录所有权失败: $(dirname "$STORAGE_FILE")"
    chmod 755 "$(dirname "$STORAGE_FILE")" || log_warn "设置配置目录权限失败: $(dirname "$STORAGE_FILE")"

    # 处理用户选择 - 索引0对应"不重置"选项,索引1对应"重置"选项
    if [ "$reset_choice" = "1" ]; then
        log_info "您选择了重置机器码"
        
        # 检查配置文件是否存在
        if [ -f "$STORAGE_FILE" ]; then
            log_info "发现已有配置文件: $STORAGE_FILE"
            
            # 备份现有配置
            if ! backup_config; then # 如果备份失败,不继续修改
                 log_error "配置文件备份失败,中止机器码重置。"
                 return 1 # 返回错误状态
            fi
            
            # 生成并设置新的设备ID
            local new_device_id=$(generate_uuid)
            local new_machine_id=$(generate_random_id)
            # 🔧 新增: serviceMachineId (用于 storage.serviceMachineId)
            local new_service_machine_id=$(generate_uuid)
            # 🔧 新增: firstSessionDate (重置首次会话日期)
            local new_first_session_date=$(date -u +"%Y-%m-%dT%H:%M:%S.000Z")
            # 🔧 新增: macMachineId 和 sqmId
            local new_mac_machine_id=$(generate_random_id)
            local new_sqm_id="{$(generate_uuid | tr '[:lower:]' '[:upper:]')}"

            CURSOR_ID_MACHINE_ID="$new_machine_id"
            CURSOR_ID_MAC_MACHINE_ID="$new_mac_machine_id"
            CURSOR_ID_DEVICE_ID="$new_device_id"
            CURSOR_ID_SQM_ID="$new_sqm_id"
            CURSOR_ID_FIRST_SESSION_DATE="$new_first_session_date"
            CURSOR_ID_SESSION_ID=$(generate_uuid)
            CURSOR_ID_MAC_ADDRESS="${CURSOR_ID_MAC_ADDRESS:-00:11:22:33:44:55}"

            log_info "正在设置新的设备和机器ID..."
            log_debug "新设备ID: $new_device_id"
            log_debug "新机器ID: $new_machine_id"
            log_debug "新serviceMachineId: $new_service_machine_id"
            log_debug "新firstSessionDate: $new_first_session_date"

            # 修改配置文件
            # 🔧 修复: 添加 storage.serviceMachineId, telemetry.firstSessionDate, telemetry.macMachineId, telemetry.sqmId
            local config_success=true
            modify_or_add_config "deviceId" "$new_device_id" "$STORAGE_FILE" || config_success=false
            modify_or_add_config "machineId" "$new_machine_id" "$STORAGE_FILE" || config_success=false
            modify_or_add_config "telemetry.machineId" "$new_machine_id" "$STORAGE_FILE" || config_success=false
            modify_or_add_config "telemetry.macMachineId" "$new_mac_machine_id" "$STORAGE_FILE" || config_success=false
            modify_or_add_config "telemetry.devDeviceId" "$new_device_id" "$STORAGE_FILE" || config_success=false
            modify_or_add_config "telemetry.sqmId" "$new_sqm_id" "$STORAGE_FILE" || config_success=false
            modify_or_add_config "storage.serviceMachineId" "$new_service_machine_id" "$STORAGE_FILE" || config_success=false
            modify_or_add_config "telemetry.firstSessionDate" "$new_first_session_date" "$STORAGE_FILE" || config_success=false

            if [ "$config_success" = true ]; then
                log_info "配置文件中的所有标识符修改成功"
                log_info "📋 [详情] 已更新以下标识符:"
                echo "   🔹 deviceId: ${new_device_id:0:16}..."
                echo "   🔹 machineId: ${new_machine_id:0:16}..."
                echo "   🔹 macMachineId: ${new_mac_machine_id:0:16}..."
                echo "   🔹 sqmId: $new_sqm_id"
                echo "   🔹 serviceMachineId: $new_service_machine_id"
                echo "   🔹 firstSessionDate: $new_first_session_date"

                # 🔧 新增: 修改 machineid 文件
                log_info "🔧 [machineid] 正在修改 machineid 文件..."
                local machineid_file_path="$CURSOR_CONFIG_DIR/machineid"
                if [ -f "$machineid_file_path" ]; then
                    # 备份原始 machineid 文件
                    local machineid_backup="$BACKUP_DIR/machineid.backup_$(date +%Y%m%d_%H%M%S)"
                    cp "$machineid_file_path" "$machineid_backup" 2>/dev/null && \
                        log_info "💾 [备份] machineid 文件已备份: $machineid_backup"
                fi
                # 写入新的 serviceMachineId 到 machineid 文件
                if echo -n "$new_service_machine_id" > "$machineid_file_path" 2>/dev/null; then
                    log_info "✅ [machineid] machineid 文件修改成功: $new_service_machine_id"
                    # 设置 machineid 文件为只读
                    chmod 444 "$machineid_file_path" 2>/dev/null && \
                        log_info "🔒 [保护] machineid 文件已设置为只读"
                else
                    log_warn "⚠️  [machineid] machineid 文件修改失败"
                    log_info "💡 [提示] 可手动修改文件: $machineid_file_path"
                fi

                # 🔧 新增: 修改 .updaterId 文件(更新器设备标识符)
                log_info "🔧 [updaterId] 正在修改 .updaterId 文件..."
                local updater_id_file_path="$CURSOR_CONFIG_DIR/.updaterId"
                if [ -f "$updater_id_file_path" ]; then
                    # 备份原始 .updaterId 文件
                    local updater_id_backup="$BACKUP_DIR/.updaterId.backup_$(date +%Y%m%d_%H%M%S)"
                    cp "$updater_id_file_path" "$updater_id_backup" 2>/dev/null && \
                        log_info "💾 [备份] .updaterId 文件已备份: $updater_id_backup"
                fi
                # 生成新的 updaterId(UUID格式)
                local new_updater_id=$(generate_uuid)
                if echo -n "$new_updater_id" > "$updater_id_file_path" 2>/dev/null; then
                    log_info "✅ [updaterId] .updaterId 文件修改成功: $new_updater_id"
                    # 设置 .updaterId 文件为只读
                    chmod 444 "$updater_id_file_path" 2>/dev/null && \
                        log_info "🔒 [保护] .updaterId 文件已设置为只读"
                else
                    log_warn "⚠️  [updaterId] .updaterId 文件修改失败"
                    log_info "💡 [提示] 可手动修改文件: $updater_id_file_path"
                fi
            else
                log_error "配置文件中的部分标识符修改失败"
                # 注意:即使失败,备份仍在,但配置文件可能已部分修改
                return 1 # 返回错误状态
            fi
        else
            log_warn "未找到配置文件 '$STORAGE_FILE',无法重置机器码。如果这是首次安装,这是正常的。"
            # 即使文件不存在,也认为此步骤(不执行)是"成功"的,允许继续
        fi
    else
        log_info "您选择了不重置机器码,将仅修改js文件"
        
        # 检查配置文件是否存在并备份(如果存在)
        if [ -f "$STORAGE_FILE" ]; then
            log_info "发现已有配置文件: $STORAGE_FILE"
            if ! backup_config; then
                 log_error "配置文件备份失败,中止操作。"
                 return 1 # 返回错误状态
            fi
            if load_ids_from_storage; then
                log_info "已从现有配置读取 ID,JS 注入将保持一致"
            else
                log_warn "无法从现有配置读取 ID,JS 注入将使用新生成的 ID(不会修改配置)"
                generate_ids_for_js_only
            fi
        else
            log_warn "未找到配置文件 '$STORAGE_FILE',跳过备份。"
            log_warn "无法读取现有ID,JS 注入将使用新生成的 ID(不会修改配置)"
            generate_ids_for_js_only
        fi
    fi
    
    echo
    log_info "配置处理完成"
    return 0 # 明确返回成功
}

# 查找Cursor的JS文件
find_cursor_js_files() {
    log_info "查找Cursor的JS文件..."
    
    local js_files=()
    local found=false
    
    # 确保 CURSOR_RESOURCES 已设置
    if [ -z "$CURSOR_RESOURCES" ] || [ ! -d "$CURSOR_RESOURCES" ]; then
        log_error "Cursor 资源目录未找到或无效 ($CURSOR_RESOURCES),无法查找 JS 文件。"
        return 1
    fi

    log_debug "在资源目录中搜索JS文件: $CURSOR_RESOURCES"
    
    # 在资源目录中递归搜索特定JS文件
    # 注意:这些模式可能需要根据 Cursor 版本更新
    local js_patterns=(
        "resources/app/out/vs/workbench/api/node/extensionHostProcess.js"
        "resources/app/out/main.js"
        "resources/app/out/vs/code/electron-utility/sharedProcess/sharedProcessMain.js"
        "resources/app/out/vs/code/node/cliProcessMain.js"
        # 添加其他可能的路径模式
        "app/out/vs/workbench/api/node/extensionHostProcess.js" # 如果资源目录是 app 的父目录
        "app/out/main.js"
        "app/out/vs/code/electron-utility/sharedProcess/sharedProcessMain.js"
        "app/out/vs/code/node/cliProcessMain.js"
    )
    
    for pattern in "${js_patterns[@]}"; do
        # 使用 find 在 CURSOR_RESOURCES 下查找完整路径
        # 兼容修复:find 遇到错误返回非0可能触发 set -e,这里统一兜底为成功返回
        local files=$(find "$CURSOR_RESOURCES" -path "*/$pattern" -type f 2>/dev/null || true)
        if [ -n "$files" ]; then
            while IFS= read -r file; do
                # 检查文件是否已添加
                if [[ ! " ${js_files[@]} " =~ " ${file} " ]]; then
                    log_info "找到JS文件: $file"
                    js_files+=("$file")
                    found=true
                fi
            done <<< "$files"
        fi
    done
    
    # 如果还没找到,尝试更通用的搜索(可能误报)
    if [ "$found" = false ]; then
        log_warn "在标准路径模式中未找到JS文件,尝试在资源目录 '$CURSOR_RESOURCES' 中进行更广泛的搜索..."
        # 查找包含特定关键字的 JS 文件
        local files=$(find "$CURSOR_RESOURCES" -name "*.js" -type f -exec grep -lE 'IOPlatformUUID|x-cursor-checksum|getMachineId' {} \; 2>/dev/null || true)
        if [ -n "$files" ]; then
            while IFS= read -r file; do
                 if [[ ! " ${js_files[@]} " =~ " ${file} " ]]; then
                     log_info "通过关键字找到可能的JS文件: $file"
                     js_files+=("$file")
                     found=true
                 fi
            done <<< "$files"
        else
             log_warn "在资源目录 '$CURSOR_RESOURCES' 中通过关键字也未能找到 JS 文件。"
        fi
    fi

    if [ "$found" = false ]; then
        log_error "在资源目录 '$CURSOR_RESOURCES' 中未找到任何可修改的JS文件。"
        log_error "请检查 Cursor 安装是否完整,或脚本中的 JS 路径模式是否需要更新。"
        return 1
    fi
    
    # 去重(理论上上面的检查已经处理,但以防万一)
    IFS=" " read -r -a CURSOR_JS_FILES <<< "$(echo "${js_files[@]}" | tr ' ' '\n' | sort -u | tr '\n' ' ')"
    
    log_info "找到 ${#CURSOR_JS_FILES[@]} 个唯一的JS文件需要处理。"
    return 0
}

# 修改Cursor的JS文件
# 🔧 修改Cursor内核JS文件实现设备识别绕过(增强版三重方案)
# 方案A: someValue占位符替换 - 稳定锚点,不依赖混淆后的函数名
# 方案B: b6 定点重写 - 机器码源函数直接返回固定值
# 方案C: Loader Stub + 外置 Hook - 主/共享进程仅加载外置 Hook 文件
modify_cursor_js_files() {
    log_info "🔧 [内核修改] 开始修改Cursor内核JS文件实现设备识别绕过..."
    log_info "💡 [方案] 使用增强版三重方案:占位符替换 + b6 定点重写 + Loader Stub + 外置 Hook"

    # 先查找需要修改的JS文件
    if ! find_cursor_js_files; then
        return 1
    fi

    if [ ${#CURSOR_JS_FILES[@]} -eq 0 ]; then
        log_error "JS 文件列表为空,无法继续修改。"
        return 1
    fi

    # 生成或复用设备标识符(优先使用配置中读取的值)
    local machine_id="${CURSOR_ID_MACHINE_ID:-}"
    local machine_guid="${CURSOR_ID_MACHINE_GUID:-}"
    local device_id="${CURSOR_ID_DEVICE_ID:-}"
    local mac_machine_id="${CURSOR_ID_MAC_MACHINE_ID:-}"
    local sqm_id="${CURSOR_ID_SQM_ID:-}"
    local session_id="${CURSOR_ID_SESSION_ID:-}"
    local first_session_date="${CURSOR_ID_FIRST_SESSION_DATE:-}"
    local mac_address="${CURSOR_ID_MAC_ADDRESS:-00:11:22:33:44:55}"
    local ids_missing=false

    if [ -z "$machine_id" ]; then
        machine_id=$(generate_random_id)
        ids_missing=true
    fi
    if [ -z "$machine_guid" ]; then
        machine_guid=$(generate_uuid)
        ids_missing=true
    fi
    if [ -z "$device_id" ]; then
        device_id=$(generate_uuid)
        ids_missing=true
    fi
    if [ -z "$mac_machine_id" ]; then
        mac_machine_id=$(generate_random_id)
        ids_missing=true
    fi
    if [ -z "$sqm_id" ]; then
        sqm_id="{$(generate_uuid | tr '[:lower:]' '[:upper:]')}"
        ids_missing=true
    fi
    if [ -z "$session_id" ]; then
        session_id=$(generate_uuid)
        ids_missing=true
    fi
    if [ -z "$first_session_date" ]; then
        first_session_date=$(date -u +"%Y-%m-%dT%H:%M:%S.000Z")
        ids_missing=true
    fi

    if [ "$ids_missing" = true ]; then
        log_warn "部分 ID 未从配置获取,已生成新值用于 JS 注入"
    else
        log_info "已使用配置中的设备标识符进行 JS 注入"
    fi

    CURSOR_ID_MACHINE_ID="$machine_id"
    CURSOR_ID_MACHINE_GUID="$machine_guid"
    CURSOR_ID_DEVICE_ID="$device_id"
    CURSOR_ID_MAC_MACHINE_ID="$mac_machine_id"
    CURSOR_ID_SQM_ID="$sqm_id"
    CURSOR_ID_SESSION_ID="$session_id"
    CURSOR_ID_FIRST_SESSION_DATE="$first_session_date"
    CURSOR_ID_MAC_ADDRESS="$mac_address"

    log_info "🔑 [准备] 设备标识符已就绪"
    log_info "   machineId: ${machine_id:0:16}..."
    log_info "   machineGuid: ${machine_guid:0:16}..."
    log_info "   deviceId: ${device_id:0:16}..."
    log_info "   macMachineId: ${mac_machine_id:0:16}..."
    log_info "   sqmId: $sqm_id"

    # 每次执行都删除旧配置并重新生成,确保获得新的设备标识符
    local ids_config_path="$TARGET_HOME/.cursor_ids.json"
    if [ -f "$ids_config_path" ]; then
        rm -f "$ids_config_path"
        log_info "🗑️  [清理] 已删除旧的 ID 配置文件"
    fi
    cat > "$ids_config_path" << EOF
{
  "machineId": "$machine_id",
  "machineGuid": "$machine_guid",
  "macMachineId": "$mac_machine_id",
  "devDeviceId": "$device_id",
  "sqmId": "$sqm_id",
  "macAddress": "$mac_address",
  "sessionId": "$session_id",
  "firstSessionDate": "$first_session_date",
  "createdAt": "$first_session_date"
}
EOF
    chown "$CURRENT_USER":"$CURRENT_GROUP" "$ids_config_path" 2>/dev/null || true
    log_info "💾 [保存] 新的 ID 配置已保存到: $ids_config_path"

    # 部署外置 Hook 文件(供 Loader Stub 加载,支持多域名备用下载)
    local hook_target_path="$TARGET_HOME/.cursor_hook.js"
    local script_dir
    script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
    local hook_source_path="$script_dir/../hook/cursor_hook.js"
    local hook_download_urls=(
        "https://wget.la/https://raw.githubusercontent.com/yuaotian/go-cursor-help/refs/heads/master/scripts/hook/cursor_hook.js"
        "https://down.npee.cn/?https://raw.githubusercontent.com/yuaotian/go-cursor-help/refs/heads/master/scripts/hook/cursor_hook.js"
        "https://xget.xi-xu.me/gh/yuaotian/go-cursor-help/refs/heads/master/scripts/hook/cursor_hook.js"
        "https://gh-proxy.com/https://raw.githubusercontent.com/yuaotian/go-cursor-help/refs/heads/master/scripts/hook/cursor_hook.js"
        "https://gh.chjina.com/https://raw.githubusercontent.com/yuaotian/go-cursor-help/refs/heads/master/scripts/hook/cursor_hook.js"
    )
    # 支持通过环境变量覆盖下载节点(逗号分隔)
    if [ -n "$CURSOR_HOOK_DOWNLOAD_URLS" ]; then
        IFS=',' read -r -a hook_download_urls <<< "$CURSOR_HOOK_DOWNLOAD_URLS"
        log_info "ℹ️  [Hook] 检测到自定义下载节点列表,将优先使用"
    fi

    if [ -f "$hook_source_path" ]; then
        if cp "$hook_source_path" "$hook_target_path"; then
            chown "$CURRENT_USER":"$CURRENT_GROUP" "$hook_target_path" 2>/dev/null || true
            log_info "✅ [Hook] 外置 Hook 已部署: $hook_target_path"
        else
            log_warn "⚠️  [Hook] 本地 Hook 复制失败,尝试在线下载..."
        fi
    fi

    if [ ! -f "$hook_target_path" ]; then
        log_info "ℹ️  [Hook] 正在下载外置 Hook,用于设备标识拦截..."
        local hook_downloaded=false
        local total_urls=${#hook_download_urls[@]}
        if [ "$total_urls" -eq 0 ]; then
            log_warn "⚠️  [Hook] 下载节点列表为空,跳过在线下载"
        elif command -v curl >/dev/null 2>&1; then
            local index=0
            for url in "${hook_download_urls[@]}"; do
                index=$((index + 1))
                log_info "⏳ [Hook] ($index/$total_urls) 当前下载节点: $url"

                # 兼容修复:部分 curl 版本可能不支持 --progress-bar,失败时回退为基础参数
                if curl -fL --progress-bar "$url" -o "$hook_target_path"; then
                    chown "$CURRENT_USER":"$CURRENT_GROUP" "$hook_target_path" 2>/dev/null || true
                    log_info "✅ [Hook] 外置 Hook 已在线下载: $hook_target_path"
                    hook_downloaded=true
                    break
                fi

                rm -f "$hook_target_path"
                log_warn "⚠️  [Hook] curl 下载失败,尝试回退参数重试: $url"
                if curl -fL "$url" -o "$hook_target_path"; then
                    chown "$CURRENT_USER":"$CURRENT_GROUP" "$hook_target_path" 2>/dev/null || true
                    log_info "✅ [Hook] 外置 Hook 已在线下载: $hook_target_path"
                    hook_downloaded=true
                    break
                fi

                rm -f "$hook_target_path"
                log_warn "⚠️  [Hook] 外置 Hook 下载失败: $url"
            done
        elif command -v wget >/dev/null 2>&1; then
            local index=0
            for url in "${hook_download_urls[@]}"; do
                index=$((index + 1))
                log_info "⏳ [Hook] ($index/$total_urls) 当前下载节点: $url"

                # 兼容修复:BusyBox/精简版 wget 可能不支持 --progress=bar:force,失败时回退为基础参数
                if wget --progress=bar:force -O "$hook_target_path" "$url"; then
                    chown "$CURRENT_USER":"$CURRENT_GROUP" "$hook_target_path" 2>/dev/null || true
                    log_info "✅ [Hook] 外置 Hook 已在线下载: $hook_target_path"
                    hook_downloaded=true
                    break
                fi

                rm -f "$hook_target_path"
                log_warn "⚠️  [Hook] wget 下载失败,尝试回退参数重试: $url"
                if wget -O "$hook_target_path" "$url"; then
                    chown "$CURRENT_USER":"$CURRENT_GROUP" "$hook_target_path" 2>/dev/null || true
                    log_info "✅ [Hook] 外置 Hook 已在线下载: $hook_target_path"
                    hook_downloaded=true
                    break
                fi

                rm -f "$hook_target_path"
                log_warn "⚠️  [Hook] 外置 Hook 下载失败: $url"
            done
        else
            log_warn "⚠️  [Hook] 未检测到 curl/wget,无法在线下载 Hook"
        fi
        if [ "$hook_downloaded" != true ] && [ ! -f "$hook_target_path" ]; then
            log_warn "⚠️  [Hook] 外置 Hook 全部下载失败"
        fi
    fi

    local modified_count=0
    local file_modification_status=()

    # 处理每个文件:创建原始备份或从原始备份恢复
    for file in "${CURSOR_JS_FILES[@]}"; do
        log_info "📝 [处理] 正在处理: $(basename "$file")"

        if [ ! -f "$file" ]; then
            log_error "文件不存在: $file,跳过处理。"
            file_modification_status+=("'$(basename "$file")': Not Found")
            continue
        fi

        # 创建备份目录
        local backup_dir="$(dirname "$file")/backups"
        mkdir -p "$backup_dir" 2>/dev/null || true

        local file_name=$(basename "$file")
        local original_backup="$backup_dir/$file_name.original"

        # 如果原始备份不存在,先创建
        if [ ! -f "$original_backup" ]; then
            # 检查当前文件是否已被修改过
            if grep -q "__cursor_patched__" "$file" 2>/dev/null; then
                log_warn "⚠️  [警告] 文件已被修改但无原始备份,将使用当前版本作为基础"
            fi
            cp "$file" "$original_backup"
            chown "$CURRENT_USER":"$CURRENT_GROUP" "$original_backup" 2>/dev/null || true
            chmod 444 "$original_backup" 2>/dev/null || true
            log_info "✅ [备份] 原始备份创建成功: $file_name"
        else
            # 从原始备份恢复,确保每次都是干净的注入
            log_info "🔄 [恢复] 从原始备份恢复: $file_name"
            cp "$original_backup" "$file"
        fi

        # 创建时间戳备份(记录每次修改前的状态)
        local backup_file="$backup_dir/$file_name.backup_$(date +%Y%m%d_%H%M%S)"
        if ! cp "$file" "$backup_file"; then
            log_error "无法创建文件备份: $file"
            file_modification_status+=("'$(basename "$file")': Backup Failed")
            continue
        fi
        chown "$CURRENT_USER":"$CURRENT_GROUP" "$backup_file" 2>/dev/null || true
        chmod 444 "$backup_file" 2>/dev/null || true

        chmod u+w "$file" || {
            log_error "无法修改文件权限(写): $file"
            file_modification_status+=("'$(basename "$file")': Permission Error")
            continue
        }

        local replaced=false

        # ========== 方法A: someValue占位符替换(稳定锚点) ==========
        # 重要说明:
        # 当前 Cursor 的 main.js 中占位符通常是以字符串字面量形式出现,例如:
        #   this.machineId="someValue.machineId"
        # 如果直接把 someValue.machineId 替换成 "\"<真实值>\"",会形成 ""<真实值>"" 导致 JS 语法错误。
        # 因此这里优先替换完整的字符串字面量(包含外层引号),再兜底替换不带引号的占位符。
        if grep -q 'someValue\.machineId' "$file"; then
            sed_inplace "s/\"someValue\.machineId\"/\"${machine_id}\"/g" "$file"
            sed_inplace "s/'someValue\.machineId'/\"${machine_id}\"/g" "$file"
            sed_inplace "s/someValue\.machineId/\"${machine_id}\"/g" "$file"
            log_info "   ✓ [方案A] 替换 someValue.machineId"
            replaced=true
        fi

        if grep -q 'someValue\.macMachineId' "$file"; then
            sed_inplace "s/\"someValue\.macMachineId\"/\"${mac_machine_id}\"/g" "$file"
            sed_inplace "s/'someValue\.macMachineId'/\"${mac_machine_id}\"/g" "$file"
            sed_inplace "s/someValue\.macMachineId/\"${mac_machine_id}\"/g" "$file"
            log_info "   ✓ [方案A] 替换 someValue.macMachineId"
            replaced=true
        fi

        if grep -q 'someValue\.devDeviceId' "$file"; then
            sed_inplace "s/\"someValue\.devDeviceId\"/\"${device_id}\"/g" "$file"
            sed_inplace "s/'someValue\.devDeviceId'/\"${device_id}\"/g" "$file"
            sed_inplace "s/someValue\.devDeviceId/\"${device_id}\"/g" "$file"
            log_info "   ✓ [方案A] 替换 someValue.devDeviceId"
            replaced=true
        fi

        if grep -q 'someValue\.sqmId' "$file"; then
            sed_inplace "s/\"someValue\.sqmId\"/\"${sqm_id}\"/g" "$file"
            sed_inplace "s/'someValue\.sqmId'/\"${sqm_id}\"/g" "$file"
            sed_inplace "s/someValue\.sqmId/\"${sqm_id}\"/g" "$file"
            log_info "   ✓ [方案A] 替换 someValue.sqmId"
            replaced=true
        fi

        if grep -q 'someValue\.sessionId' "$file"; then
            sed_inplace "s/\"someValue\.sessionId\"/\"${session_id}\"/g" "$file"
            sed_inplace "s/'someValue\.sessionId'/\"${session_id}\"/g" "$file"
            sed_inplace "s/someValue\.sessionId/\"${session_id}\"/g" "$file"
            log_info "   ✓ [方案A] 替换 someValue.sessionId"
            replaced=true
        fi

        if grep -q 'someValue\.firstSessionDate' "$file"; then
            sed_inplace "s/\"someValue\.firstSessionDate\"/\"${first_session_date}\"/g" "$file"
            sed_inplace "s/'someValue\.firstSessionDate'/\"${first_session_date}\"/g" "$file"
            sed_inplace "s/someValue\.firstSessionDate/\"${first_session_date}\"/g" "$file"
            log_info "   ✓ [方案A] 替换 someValue.firstSessionDate"
            replaced=true
        fi

        # ========== 方法B: b6 定点重写(机器码源函数,仅 main.js) ==========
        local b6_patched=false
        if [ "$(basename "$file")" = "main.js" ]; then
            if command -v python3 >/dev/null 2>&1; then
                local b6_result
                b6_result=$(python3 - "$file" "$machine_guid" "$machine_id" <<'PY'
# 🔧 修复:使用标准 4 空格缩进,避免 IndentationError
import re, sys

def diag(msg):
    print(f"[方案B][诊断] {msg}", file=sys.stderr)

path, machine_guid, machine_id = sys.argv[1], sys.argv[2], sys.argv[3]

with open(path, "r", encoding="utf-8") as f:
    data = f.read()

# ✅ 1+3 融合:限定 out-build/vs/base/node/id.js 模块内做特征匹配 + 花括号配对定位函数边界
marker = "out-build/vs/base/node/id.js"
marker_index = data.find(marker)
if marker_index < 0:
    print("NOT_FOUND")
    diag(f"未找到模块标记: {marker}")
    raise SystemExit(0)

window_end = min(len(data), marker_index + 200000)
window = data[marker_index:window_end]

def find_matching_brace(text, open_index, max_scan=20000):
    limit = min(len(text), open_index + max_scan)
    depth = 1
    in_single = in_double = in_template = False
    in_line_comment = in_block_comment = False
    escape = False
    i = open_index + 1
    while i < limit:
        ch = text[i]
        nxt = text[i + 1] if i + 1 < limit else ""

        if in_line_comment:
            if ch == "\n":
                in_line_comment = False
            i += 1
            continue
        if in_block_comment:
            if ch == "*" and nxt == "/":
                in_block_comment = False
                i += 2
                continue
            i += 1
            continue

        if in_single:
            if escape:
                escape = False
            elif ch == "\\":
                escape = True
            elif ch == "'":
                in_single = False
            i += 1
            continue
        if in_double:
            if escape:
                escape = False
            elif ch == "\\":
                escape = True
            elif ch == '"':
                in_double = False
            i += 1
            continue
        if in_template:
            if escape:
                escape = False
            elif ch == "\\":
                escape = True
            elif ch == "`":
                in_template = False
            i += 1
            continue

        if ch == "/" and nxt == "/":
            in_line_comment = True
            i += 2
            continue
        if ch == "/" and nxt == "*":
            in_block_comment = True
            i += 2
            continue

        if ch == "'":
            in_single = True
            i += 1
            continue
        if ch == '"':
            in_double = True
            i += 1
            continue
        if ch == "`":
            in_template = True
            i += 1
            continue

        if ch == "{":
            depth += 1
        elif ch == "}":
            depth -= 1
            if depth == 0:
                return i

        i += 1
    return None

# 🔧 修复:避免 raw string + 单引号 + ['"] 字符组导致的语法错误;同时修正正则转义,提升 b6 特征匹配命中率
hash_re = re.compile(r"""createHash\(["']sha256["']\)""")
sig_re = re.compile(r'^async function (\w+)\((\w+)\)')

hash_matches = list(hash_re.finditer(window))
diag(f"marker_index={marker_index} window_len={len(window)} sha256_createHash={len(hash_matches)}")

for idx, hm in enumerate(hash_matches, start=1):
    hash_pos = hm.start()
    func_start = window.rfind("async function", 0, hash_pos)
    if func_start < 0:
        if idx <= 3:
            diag(f"候选#{idx}: 未找到 async function 起点")
        continue

    open_brace = window.find("{", func_start)
    if open_brace < 0:
        if idx <= 3:
            diag(f"候选#{idx}: 未找到函数起始花括号")
        continue

    end_brace = find_matching_brace(window, open_brace, max_scan=20000)
    if end_brace is None:
        if idx <= 3:
            diag(f"候选#{idx}: 花括号配对失败(扫描上限内未闭合)")
        continue

    func_text = window[func_start:end_brace + 1]
    if len(func_text) > 8000:
        if idx <= 3:
            diag(f"候选#{idx}: 函数体过长 len={len(func_text)},已跳过")
        continue

    sm = sig_re.match(func_text)
    if not sm:
        if idx <= 3:
            diag(f"候选#{idx}: 未解析到函数签名(async function name(param))")
        continue
    name, param = sm.group(1), sm.group(2)

    # 特征校验:sha256 + hex digest + return param ? raw : hash
    has_digest = re.search(r"""\.digest\(["']hex["']\)""", func_text) is not None
    has_return = re.search(r'return\s+' + re.escape(param) + r'\?\w+:\w+\}', func_text) is not None
    if idx <= 3:
        diag(f"候选#{idx}: {name}({param}) len={len(func_text)} digest={has_digest} return={has_return}")
    if not has_digest:
        continue
    if not has_return:
        continue

    replacement = f'async function {name}({param}){{return {param}?"{machine_guid}":"{machine_id}";}}'
    abs_start = marker_index + func_start
    abs_end = marker_index + end_brace
    new_data = data[:abs_start] + replacement + data[abs_end + 1:]
    with open(path, "w", encoding="utf-8") as f:
        f.write(new_data)
    diag(f"命中并重写: {name}({param}) len={len(func_text)}")
    print("PATCHED")
    break
else:
    diag("未找到满足特征的候选函数")
    print("NOT_FOUND")
PY
                 )
                if [ "$b6_result" = "PATCHED" ]; then
                    log_info "   ✓ [方案B] 已重写 b6 特征函数"
                    b6_patched=true
                else
                    log_warn "⚠️  [方案B] 未定位到 b6 特征函数"
                fi
            else
                log_warn "⚠️  [方案B] 未检测到 python3,跳过 b6 定点重写"
            fi
        fi

        # ========== 方法C: Loader Stub 注入 ==========
        local inject_code='// ========== Cursor Hook Loader 开始 ==========
;(async function(){/*__cursor_patched__*/
"use strict";
if(globalThis.__cursor_hook_loaded__)return;
globalThis.__cursor_hook_loaded__=true;

try{
    // 兼容 ESM/CJS:避免使用 import.meta(仅 ESM 支持),统一用动态 import 加载 Hook
    var fsMod=await import("fs");
    var pathMod=await import("path");
    var osMod=await import("os");
    var urlMod=await import("url");

    var fs=fsMod&&(fsMod.default||fsMod);
    var path=pathMod&&(pathMod.default||pathMod);
    var os=osMod&&(osMod.default||osMod);
    var url=urlMod&&(urlMod.default||urlMod);

    if(fs&&path&&os&&url&&typeof url.pathToFileURL==="function"){
        var hookPath=path.join(os.homedir(), ".cursor_hook.js");
        if(typeof fs.existsSync==="function"&&fs.existsSync(hookPath)){
            await import(url.pathToFileURL(hookPath).href);
        }
    }
}catch(e){
    // 失败静默,避免影响启动
}
})();
// ========== Cursor Hook Loader 结束 ==========

'

        # 在版权声明后注入代码
        local temp_file=$(mktemp)
        if grep -q '\*/' "$file"; then
            awk -v inject="$inject_code" '
            /\*\// && !injected {
                print
                print ""
                print inject
                injected = 1
                next
            }
            { print }
            ' "$file" > "$temp_file"
            log_info "   ✓ [方案C] Loader Stub 已注入(版权声明后)"
        else
            echo "$inject_code" > "$temp_file"
            cat "$file" >> "$temp_file"
            log_info "   ✓ [方案C] Loader Stub 已注入(文件开头)"
        fi

        if mv "$temp_file" "$file"; then
            local summary="Hook加载器"
            if [ "$replaced" = true ]; then
                summary="someValue替换 + $summary"
            fi
            if [ "$b6_patched" = true ]; then
                summary="b6定点重写 + $summary"
            fi
            log_info "✅ [成功] 增强版方案修改成功($summary)"
            ((modified_count++))
            file_modification_status+=("'$(basename "$file")': Success")

            chmod u-w,go-w "$file" 2>/dev/null || true
            chown "$CURRENT_USER":"$CURRENT_GROUP" "$file" 2>/dev/null || true
        else
            log_error "Hook注入失败 (无法移动临时文件)"
            rm -f "$temp_file"
            file_modification_status+=("'$(basename "$file")': Inject Failed")
            cp "$original_backup" "$file" 2>/dev/null || true
        fi

    done

    log_info "📊 [统计] JS 文件处理状态汇总:"
    for status in "${file_modification_status[@]}"; do
        log_info "   - $status"
    done

    if [ "$modified_count" -eq 0 ]; then
        log_error "❌ [失败] 未能成功修改任何JS文件。"
        return 1
    fi

    log_info "🎉 [完成] 成功修改 $modified_count 个JS文件"
    log_info "💡 [说明] 使用增强版三重方案:"
    log_info "   • 方案A: someValue占位符替换(稳定锚点,跨版本兼容)"
    log_info "   • 方案B: b6 定点重写(机器码源函数)"
    log_info "   • 方案C: Loader Stub + 外置 Hook(cursor_hook.js)"
    log_info "📁 [配置] ID 配置文件: $ids_config_path"
    return 0
}

# 禁用自动更新
disable_auto_update() {
    log_info "正在尝试禁用 Cursor 自动更新..."
    
    # 查找可能的更新配置文件
    local update_configs=()
    # 用户配置目录下的
    if [ -d "$CURSOR_CONFIG_DIR" ]; then
        update_configs+=("$CURSOR_CONFIG_DIR/update-config.json")
        update_configs+=("$CURSOR_CONFIG_DIR/settings.json") # 有些设置可能在这里
    fi
    # 安装目录下的 (如果资源目录确定)
    if [ -n "$CURSOR_RESOURCES" ] && [ -d "$CURSOR_RESOURCES" ]; then
        update_configs+=("$CURSOR_RESOURCES/resources/app-update.yml")
         update_configs+=("$CURSOR_RESOURCES/app-update.yml") # 可能的位置
    fi
     # 标准安装目录下的
     if [ -d "$INSTALL_DIR" ]; then
          update_configs+=("$INSTALL_DIR/resources/app-update.yml")
          update_configs+=("$INSTALL_DIR/app-update.yml")
     fi
     # $TARGET_HOME/.local/share
     update_configs+=("$TARGET_HOME/.local/share/cursor/update-config.json")


    local disabled_count=0
    
    # 处理 JSON 配置文件
    local json_config_pattern='update-config.json|settings.json'
    for config in "${update_configs[@]}"; do
       if [[ "$config" =~ $json_config_pattern ]] && [ -f "$config" ]; then
           log_info "找到可能的更新配置文件: $config"
           
           # 备份
           cp "$config" "${config}.bak_$(date +%Y%m%d%H%M%S)" 2>/dev/null
           
            # 尝试修改 JSON (如果存在且是 settings.json)
            if [[ "$config" == *settings.json ]]; then
                # 🔧 兼容修复:复用 modify_or_add_config 统一处理替换/注入,避免 sed -i 与 \n 扩展差异
                if modify_or_add_config "update.mode" "none" "$config"; then
                    ((disabled_count++))
                    log_info "已尝试在 '$config' 中设置 'update.mode' 为 'none'"
                else
                    log_warn "修改 settings.json 中的 update.mode 失败: $config"
                fi
            elif [[ "$config" == *update-config.json ]]; then
                 # 直接覆盖 update-config.json
                 echo '{"autoCheck": false, "autoDownload": false}' > "$config"
                 chown "$CURRENT_USER":"$CURRENT_GROUP" "$config" || log_warn "设置所有权失败: $config"
                chmod 644 "$config" || log_warn "设置权限失败: $config"
                ((disabled_count++))
                log_info "已覆盖更新配置文件: $config"
            fi
       fi
    done

    # 处理 YAML 配置文件
     local yml_config_pattern='app-update.yml'
     for config in "${update_configs[@]}"; do
        if [[ "$config" =~ $yml_config_pattern ]] && [ -f "$config" ]; then
            log_info "找到可能的更新配置文件: $config"
            # 备份
            cp "$config" "${config}.bak_$(date +%Y%m%d%H%M%S)" 2>/dev/null
            # 清空或修改内容 (简单起见,直接清空或写入禁用标记)
             echo "# Automatic updates disabled by script $(date)" > "$config"
             # echo "provider: generic" > "$config" # 或者尝试修改 provider
             # echo "url: http://127.0.0.1" >> "$config"
             chmod 444 "$config" # 设置为只读
             ((disabled_count++))
             log_info "已修改/清空更新配置文件: $config"
        fi
     done

    # 尝试查找updater可执行文件并禁用(重命名或移除权限)
    local updater_paths=()
     if [ -n "$CURSOR_RESOURCES" ] && [ -d "$CURSOR_RESOURCES" ]; then
        # 兼容修复:不强依赖 find -executable,且兜底避免 find 非0 触发 set -e
        updater_paths+=($(find "$CURSOR_RESOURCES" -name "updater" -type f 2>/dev/null || true))
        updater_paths+=($(find "$CURSOR_RESOURCES" -name "CursorUpdater" -type f 2>/dev/null || true)) # macOS 风格?
     fi
       if [ -d "$INSTALL_DIR" ]; then
          updater_paths+=($(find "$INSTALL_DIR" -name "updater" -type f 2>/dev/null || true))
          updater_paths+=($(find "$INSTALL_DIR" -name "CursorUpdater" -type f 2>/dev/null || true))
       fi
       updater_paths+=("$CURSOR_CONFIG_DIR/updater") # 旧位置?

    for updater in "${updater_paths[@]}"; do
        if [ -f "$updater" ] && [ -x "$updater" ]; then
            log_info "找到更新程序: $updater"
            local bak_updater="${updater}.bak_$(date +%Y%m%d%H%M%S)"
            if mv "$updater" "$bak_updater"; then
                 log_info "已重命名更新程序为: $bak_updater"
                 ((disabled_count++))
            else
                 log_warn "重命名更新程序失败: $updater,尝试移除执行权限..."
                 if chmod a-x "$updater"; then
                      log_info "已移除更新程序执行权限: $updater"
                      ((disabled_count++))
                 else
                     log_error "无法禁用更新程序: $updater"
                 fi
            fi
        # elif [ -d "$updater" ]; then # 如果是目录,尝试禁用
        #     log_info "找到更新程序目录: $updater"
        #     touch "${updater}.disabled_by_script"
        #     log_info "已标记禁用更新程序目录: $updater"
        #     ((disabled_count++))
        fi
    done
    
    if [ "$disabled_count" -eq 0 ]; then
        log_warn "未能找到或禁用任何已知的自动更新机制。"
        log_warn "如果 Cursor 仍然自动更新,可能需要手动查找并禁用相关文件或设置。"
    else
        log_info "成功禁用或尝试禁用了 $disabled_count 个自动更新相关的文件/程序。"
    fi
     return 0 # 即使没找到,也认为函数执行成功
}

# 新增:通用菜单选择函数
select_menu_option() {
    local prompt="$1"
    IFS='|' read -ra options <<< "$2"
    local default_index=${3:-0}
    local selected_index=$default_index
    local key_input
    local cursor_up=$'\e[A' # 更标准的 ANSI 码
    local cursor_down=$'\e[B'
    local cursor_up_alt=$'\eOA' # 兼容应用光标模式
    local cursor_down_alt=$'\eOB'
    local enter_key=$'\n'
    # 兼容管道执行场景:stdin 非 TTY 时改用 /dev/tty 读取
    local input_fd=0
    local input_fd_opened=0

    if [ -t 0 ]; then
        input_fd=0
    elif [ -r /dev/tty ]; then
        exec 3</dev/tty
        input_fd=3
        input_fd_opened=1
    else
        # 无可用 TTY,直接使用默认选项返回
        echo -e "$prompt ${GREEN}${options[$selected_index]}${NC}"
        return $selected_index
    fi

    # 隐藏光标
    tput civis
    # 清除可能存在的旧菜单行 (假设菜单最多 N 行)
    local num_options=${#options[@]}
    for ((i=0; i<num_options+1; i++)); do echo -e "\033[K"; done # 清除行
     tput cuu $((num_options + 1)) # 光标移回顶部


    # 显示提示信息
    echo -e "$prompt"
    
    # 绘制菜单函数
    draw_menu() {
        # 光标移到菜单开始行下方一行
        tput cud 1 
        for i in "${!options[@]}"; do
             tput el # 清除当前行
            if [ $i -eq $selected_index ]; then
                echo -e " ${GREEN}►${NC} ${options[$i]}"
            else
                echo -e "   ${options[$i]}"
            fi
        done
         # 将光标移回提示行下方
        tput cuu "$num_options"
    }
    
    # 第一次显示菜单
    draw_menu

    # 循环处理键盘输入
    while true; do
        # 读取按键 (使用 -sn1 或 -sn3 取决于系统对箭头键的处理)
        # -N 1 读取单个字符,可能需要多次读取箭头键
        # -N 3 一次读取3个字符,通常用于箭头键
        read -rsn1 -u "$input_fd" key_press_1 # 读取第一个字符
         if [[ "$key_press_1" == $'\e' ]]; then # 如果是 ESC,读取后续字符
             read -rsn2 -u "$input_fd" key_press_2 # 读取 '[' 和 A/B
             key_input="$key_press_1$key_press_2"
         elif [[ "$key_press_1" == "" ]]; then # 如果是 Enter
             key_input=$enter_key
         else
             key_input="$key_press_1" # 其他按键
         fi

        # 检测按键
        case "$key_input" in
            # 上箭头键
            "$cursor_up"|"$cursor_up_alt")
                if [ $selected_index -gt 0 ]; then
                    ((selected_index--))
                    draw_menu
                fi
                ;;
            # 下箭头键
            "$cursor_down"|"$cursor_down_alt")
                if [ $selected_index -lt $((${#options[@]}-1)) ]; then
                    ((selected_index++))
                    draw_menu
                fi
                ;;
            # 数字键选择(1..N),避免方向键不可用
            [1-9])
                if [ "$key_input" -ge 1 ] && [ "$key_input" -le "$num_options" ]; then
                    selected_index=$((key_input - 1))
                    draw_menu
                fi
                ;;
            # Enter键
            "$enter_key")
                 # 清除菜单区域
                 tput cud 1 # 下移一行开始清除
                 for i in "${!options[@]}"; do tput el; tput cud 1; done
                 tput cuu $((num_options + 1)) # 移回提示行
                 tput el # 清除提示行本身
                 echo -e "$prompt ${GREEN}${options[$selected_index]}${NC}" # 显示最终选择

                 # 恢复光标
                 tput cnorm
                 # 关闭 /dev/tty 句柄,避免资源占用
                 if [ "$input_fd_opened" -eq 1 ]; then
                     exec 3<&-
                 fi
                 # 返回选择的索引
                 return $selected_index
                ;;
             *)
                 # 忽略其他按键
                 ;;
        esac
    done
}

# 新增 Cursor 初始化清理函数
cursor_initialize_cleanup() {
    log_info "正在执行 Cursor 初始化清理..."
    # CURSOR_CONFIG_DIR 在脚本全局已定义: $TARGET_HOME/.config/Cursor
    local USER_CONFIG_BASE_PATH="$CURSOR_CONFIG_DIR/User"

    log_debug "用户配置基础路径: $USER_CONFIG_BASE_PATH"

    local files_to_delete=(
        "$USER_CONFIG_BASE_PATH/globalStorage/state.vscdb"
        "$USER_CONFIG_BASE_PATH/globalStorage/state.vscdb.backup"
    )
    
    local folder_to_clean_contents="$USER_CONFIG_BASE_PATH/History"
    local folder_to_delete_completely="$USER_CONFIG_BASE_PATH/workspaceStorage"

    # 删除指定文件
    for file_path in "${files_to_delete[@]}"; do
        log_debug "检查文件: $file_path"
        if [ -f "$file_path" ]; then
            if rm -f "$file_path"; then
                log_info "已删除文件: $file_path"
            else
                log_error "删除文件 $file_path 失败"
            fi
        else
            log_warn "文件不存在,跳过删除: $file_path"
        fi
    done

    # 清空指定文件夹内容
    log_debug "检查待清空文件夹: $folder_to_clean_contents"
    if [ -d "$folder_to_clean_contents" ]; then
        if find "$folder_to_clean_contents" -mindepth 1 -delete; then
            log_info "已清空文件夹内容: $folder_to_clean_contents"
        else
            if [ -z "$(ls -A "$folder_to_clean_contents")" ]; then
                 log_info "文件夹 $folder_to_clean_contents 现在为空。"
            else
                 log_error "清空文件夹 $folder_to_clean_contents 内容失败 (部分或全部)。请检查权限或手动删除。"
            fi
        fi
    else
        log_warn "文件夹不存在,跳过清空: $folder_to_clean_contents"
    fi

    # 删除指定文件夹及其内容
    log_debug "检查待删除文件夹: $folder_to_delete_completely"
    if [ -d "$folder_to_delete_completely" ]; then
        if rm -rf "$folder_to_delete_completely"; then
            log_info "已删除文件夹: $folder_to_delete_completely"
        else
            log_error "删除文件夹 $folder_to_delete_completely 失败"
        fi
    else
        log_warn "文件夹不存在,跳过删除: $folder_to_delete_completely"
    fi

    log_info "Cursor 初始化清理完成。"
}

# 主函数
main() {
    # 在显示菜单/流程说明前调整终端窗口大小;不支持则静默忽略
    if [ -z "${CURSOR_NO_TTY_UI:-}" ]; then
        try_resize_terminal_window
    fi

    # 初始化日志文件
    initialize_log
    log_info "脚本启动..."
    log_info "运行用户: $CURRENT_USER (脚本以 EUID=$EUID 运行)"

    # 检查权限 (必须在脚本早期)
    check_permissions # 需要 root 权限进行安装和修改系统文件

    # 记录系统信息
    log_info "系统信息: $(uname -a)"
    log_cmd_output "lsb_release -a 2>/dev/null || cat /etc/*release 2>/dev/null || cat /etc/issue" "系统版本信息"
    
    if [ -z "${CURSOR_NO_TTY_UI:-}" ]; then
        clear
        # 显示 Logo
        echo -e "
        ██████╗██╗   ██╗██████╗ ███████╗ ██████╗ ██████╗ 
       ██╔════╝██║   ██║██╔══██╗██╔════╝██╔═══██╗██╔══██╗
       ██║     ██║   ██║██████╔╝███████╗██║   ██║██████╔╝
       ██║     ██║   ██║██╔══██╗╚════██║██║   ██║██╔══██╗
       ╚██████╗╚██████╔╝██║  ██║███████║╚██████╔╝██║  ██║
        ╚═════╝ ╚═════╝ ╚═╝  ╚═╝╚══════╝ ╚═════╝ ╚═╝  ╚═╝
        "
        echo -e "${BLUE}=====================================================${NC}"
        echo -e "${GREEN}         Cursor Linux 启动与修改工具(免费)            ${NC}"
        echo -e "${YELLOW}        关注公众号【煎饼果子卷AI】     ${NC}"
        echo -e "${YELLOW}  一起交流更多Cursor技巧和AI知识(脚本免费、关注公众号加群有更多技巧和大佬)  ${NC}"
        echo -e "${BLUE}=====================================================${NC}"
        echo
        echo -e "${YELLOW}⚡  [小小广告] Cursor官网正规成品号:Unlimited ♾️ ¥1050 | 7天周卡 $100 ¥210 | 7天周卡 $500 ¥1050 | 7天周卡 $1000 ¥2450 | 全部7天质保 | ,WeChat:JavaRookie666  ${NC}"
        echo
        echo -e "${YELLOW}[提示]${NC} 本工具旨在修改 Cursor 以解决可能的启动问题或设备限制。"
        echo -e "${YELLOW}[提示]${NC} 它将优先修改 JS 文件,并可选择重置设备ID和禁用自动更新。"
        echo -e "${YELLOW}[提示]${NC} 如果未找到 Cursor,将尝试从 '$APPIMAGE_SEARCH_DIR' 目录安装。"
        echo
    fi

    # 查找 Cursor 路径
    if ! find_cursor_path; then
        log_warn "系统中未找到现有的 Cursor 安装。"
        set +e
        select_menu_option "是否尝试从 '$APPIMAGE_SEARCH_DIR' 目录中的 AppImage 文件安装 Cursor?" "是,安装 Cursor|否,退出脚本" 0
        install_choice=$?
        set -e
        
        if [ "$install_choice" -eq 0 ]; then
            if ! install_cursor_appimage; then
                log_error "Cursor 安装失败,请检查上面的日志。脚本将退出。"
                exit 1
            fi
            # 安装成功后,重新查找路径
            if ! find_cursor_path || ! find_cursor_resources; then
                 log_error "安装后仍然无法找到 Cursor 的可执行文件或资源目录。请检查 '$INSTALL_DIR' 和 '/usr/local/bin/cursor'。脚本退出。"
                 exit 1
            fi
            log_info "Cursor 安装成功,继续执行修改步骤..."
        else
            log_info "用户选择不安装 Cursor,脚本退出。"
            exit 0
        fi
    else
        # 如果找到了 Cursor,也要确保找到资源目录
        if ! find_cursor_resources; then
            log_error "找到了 Cursor 可执行文件 ($CURSOR_PATH),但未能定位资源目录。"
            log_error "无法继续修改 JS 文件。请检查 Cursor 安装是否完整。脚本退出。"
            exit 1
        fi
        log_info "发现已安装的 Cursor ($CURSOR_PATH),资源目录 ($CURSOR_RESOURCES)。"
    fi

    # 到这里,Cursor 应该已安装并且路径已知

    # 检查并关闭Cursor进程
    if ! check_and_kill_cursor; then
         # check_and_kill_cursor 内部会记录错误并退出,但以防万一
         exit 1
    fi
    
    # 执行 Cursor 初始化清理
    # cursor_initialize_cleanup

    # 备份并处理配置文件 (机器码重置选项)
    if ! generate_new_config; then
         log_error "处理配置文件时出错,脚本中止。"
         # 此处可能需要考虑是否回滚JS修改(如果已执行)?目前不回滚。
         exit 1
    fi
    
    # 修改JS文件
    log_info "正在修改 Cursor JS 文件..."
    if ! modify_cursor_js_files; then
        log_error "JS 文件修改过程中发生错误。"
        log_warn "配置文件可能已被修改,但 JS 文件修改失败。"
        log_warn "如果重启后 Cursor 行为异常或仍有问题,请检查日志并考虑手动恢复备份或重新运行脚本。"
        # 决定是否继续执行禁用更新?通常建议继续
        # exit 1 # 或者选择退出
    else
        log_info "JS 文件修改成功!"
    fi
    
    # 禁用自动更新
    if ! disable_auto_update; then
        # disable_auto_update 内部会记录警告,不视为致命错误
        log_warn "尝试禁用自动更新时遇到问题(详见日志),但脚本将继续。"
    fi
    
    log_info "所有修改步骤已完成!"
    log_info "请启动 Cursor 以应用更改。"
    
    # 显示最后的提示信息
    echo
    echo -e "${GREEN}=====================================================${NC}"
    echo -e "${YELLOW}  请关注公众号【煎饼果子卷AI】获取更多技巧和交流 ${NC}"
    echo -e "${YELLOW}⚡   [小小广告] Cursor官网正规成品号:Unlimited ♾️ ¥1050 | 7天周卡 $100 ¥210 | 7天周卡 $500 ¥1050 | 7天周卡 $1000 ¥2450 | 全部7天质保 | ,WeChat:JavaRookie666  ${NC}"
    echo -e "${GREEN}=====================================================${NC}"
    echo
    
    # 记录脚本完成信息
    log_info "脚本执行完成"
    echo "========== Cursor ID 修改工具日志结束 $(date) ==========" >> "$LOG_FILE"
    
    # 显示日志文件位置
    echo
    log_info "详细日志已保存到: $LOG_FILE"
    echo "如遇问题请将此日志文件提供给开发者以协助排查"
    echo
}

# 执行主函数
main

exit 0 # 确保最后返回成功状态码


================================================
FILE: scripts/run/cursor_mac_id_modifier.sh
================================================
#!/bin/bash

# ========================================
# Cursor macOS 机器码修改脚本
# ========================================
#
# 🔧 权限修复增强:
# - 集成用户提供的核心权限修复命令
# - 特别处理logs目录权限问题
# - 解决EACCES: permission denied错误
# - 确保Cursor能正常启动
#
# 🚨 如果遇到权限错误,脚本会自动执行:
# - sudo chown -R "$TARGET_USER" "$TARGET_HOME/Library/Application Support/Cursor"
# - sudo chown -R "$TARGET_USER" "$TARGET_HOME/.cursor"
# - chmod -R u+rwX "$TARGET_HOME/Library/Application Support/Cursor"
# - chmod -R u+rwX "$TARGET_HOME/.cursor"
#
# ========================================

# 设置错误处理
set -e

# 定义日志文件路径
LOG_FILE="/tmp/cursor_free_trial_reset.log"

# 初始化日志文件
initialize_log() {
    echo "========== Cursor Free Trial Reset Tool Log Start $(date) ==========" > "$LOG_FILE"
    chmod 644 "$LOG_FILE"
}

# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color

# 启动时尝试调整终端窗口大小为 120x40(列x行);不支持/失败时静默忽略,避免影响脚本主流程
try_resize_terminal_window() {
    local target_cols=120
    local target_rows=40

    # 仅在交互终端中尝试,避免输出被重定向时出现乱码
    if [ ! -t 1 ]; then
        return 0
    fi

    case "${TERM:-}" in
        ""|dumb)
            return 0
            ;;
    esac

    # 终端类型检测:仅对常见 xterm 体系终端尝试窗口调整(Terminal.app/iTerm2 以及常见终端通常为 xterm*)
    case "${TERM:-}" in
        xterm*|screen*|tmux*|rxvt*|alacritty*|kitty*|foot*|wezterm*)
            ;;
        *)
            return 0
            ;;
    esac

    # 优先通过 xterm 窗口控制序列调整;在 tmux/screen 下需要 passthrough 包装
    if [ -n "${TMUX:-}" ]; then
        printf '\033Ptmux;\033\033[8;%d;%dt\033\\' "$target_rows" "$target_cols" 2>/dev/null || true
    elif [ -n "${STY:-}" ]; then
        printf '\033P\033[8;%d;%dt\033\\' "$target_rows" "$target_cols" 2>/dev/null || true
    else
        printf '\033[8;%d;%dt' "$target_rows" "$target_cols" 2>/dev/null || true
    fi

    return 0
}

# 日志函数 - 同时输出到终端和日志文件
log_info() {
    echo -e "${GREEN}[INFO]${NC} $1"
    echo "[INFO] $(date '+%Y-%m-%d %H:%M:%S') $1" >> "$LOG_FILE"
}

log_warn() {
    echo -e "${YELLOW}[WARN]${NC} $1"
    echo "[WARN] $(date '+%Y-%m-%d %H:%M:%S') $1" >> "$LOG_FILE"
}

log_error() {
    echo -e "${RED}[ERROR]${NC} $1"
    echo "[ERROR] $(date '+%Y-%m-%d %H:%M:%S') $1" >> "$LOG_FILE"
}

log_debug() {
    echo -e "${BLUE}[DEBUG]${NC} $1"
    echo "[DEBUG] $(date '+%Y-%m-%d %H:%M:%S') $1" >> "$LOG_FILE"
}

# 记录命令输出到日志文件
log_cmd_output() {
    local cmd="$1"
    local msg="$2"
    echo "[CMD] $(date '+%Y-%m-%d %H:%M:%S') 执行命令: $cmd" >> "$LOG_FILE"
    echo "[CMD] $msg:" >> "$LOG_FILE"
    eval "$cmd" 2>&1 | tee -a "$LOG_FILE"
    echo "" >> "$LOG_FILE"
}

# 生成指定字节长度的十六进制串(2*bytes 个字符),优先 openssl,缺失时使用 python3 兜底
generate_hex_bytes() {
    local bytes="$1"
    if command -v openssl >/dev/null 2>&1; then
        openssl rand -hex "$bytes"
        return 0
    fi
    # mac 脚本已要求 python3,可作为兜底
    python3 -c 'import os, sys; print(os.urandom(int(sys.argv[1])).hex())' "$bytes"
}

# 生成随机 UUID(小写),优先 uuidgen,缺失时使用 python3 兜底
generate_uuid() {
    if command -v uuidgen >/dev/null 2>&1; then
        uuidgen | tr '[:upper:]' '[:lower:]'
        return 0
    fi
    # mac 脚本已要求 python3,可作为兜底
    python3 -c 'import uuid; print(str(uuid.uuid4()))'
}

# 🚀 新增 Cursor 防掉试用Pro删除文件夹功能
remove_cursor_trial_folders() {
    echo
    log_info "🎯 [核心功能] 正在执行 Cursor 防掉试用Pro删除文件夹..."
    log_info "📋 [说明] 此功能将删除指定的Cursor相关文件夹以重置试用状态"
    echo

    # 定义需要删除的文件夹路径
    local folders_to_delete=(
        "$TARGET_HOME/Library/Application Support/Cursor"
        "$TARGET_HOME/.cursor"
    )

    log_info "📂 [检测] 将检查以下文件夹:"
    for folder in "${folders_to_delete[@]}"; do
        echo "   📁 $folder"
    done
    echo

    local deleted_count=0
    local skipped_count=0
    local error_count=0

    # 删除指定文件夹
    for folder in "${folders_to_delete[@]}"; do
        log_debug "🔍 [检查] 检查文件夹: $folder"

        if [ -d "$folder" ]; then
            log_warn "⚠️  [警告] 发现文件夹存在,正在删除..."
            if rm -rf "$folder"; then
                log_info "✅ [成功] 已删除文件夹: $folder"
                ((deleted_count++))
            else
                log_error "❌ [错误] 删除文件夹失败: $folder"
                ((error_count++))
            fi
        else
            log_warn "⏭️  [跳过] 文件夹不存在: $folder"
            ((skipped_count++))
        fi
        echo
    done

    # 🔧 重要:删除文件夹后立即执行权限修复
    log_info "🔧 [权限修复] 删除文件夹后立即执行权限修复..."
    echo

    # 调用统一的权限修复函数
    ensure_cursor_directory_permissions

    # 显示操作统计
    log_info "📊 [统计] 操作完成统计:"
    echo "   ✅ 成功删除: $deleted_count 个文件夹"
    echo "   ⏭️  跳过处理: $skipped_count 个文件夹"
    echo "   ❌ 删除失败: $error_count 个文件夹"
    echo

    if [ $deleted_count -gt 0 ]; then
        log_info "🎉 [完成] Cursor 防掉试用Pro文件夹删除完成!"
    else
        log_warn "🤔 [提示] 未找到需要删除的文件夹,可能已经清理过了"
    fi
    echo
}

# 🔄 重启Cursor并等待配置文件生成
restart_cursor_and_wait() {
    echo
    log_info "🔄 [重启] 正在重启Cursor以重新生成配置文件..."

    if [ -z "$CURSOR_PROCESS_PATH" ]; then
        log_error "❌ [错误] 未找到Cursor进程信息,无法重启"
        return 1
    fi

    log_info "📍 [路径] 使用路径: $CURSOR_PROCESS_PATH"

    if [ ! -f "$CURSOR_PROCESS_PATH" ]; then
        log_error "❌ [错误] Cursor可执行文件不存在: $CURSOR_PROCESS_PATH"
        return 1
    fi

    # 🔧 启动前权限修复
    log_info "🔧 [启动前权限] 执行启动前权限修复..."
    ensure_cursor_directory_permissions

    # 启动Cursor
    log_info "🚀 [启动] 正在启动Cursor..."
    "$CURSOR_PROCESS_PATH" > /dev/null 2>&1 &
    CURSOR_PID=$!

    log_info "⏳ [等待] 等待15秒让Cursor完全启动并生成配置文件..."
    sleep 15

    # 检查配置文件是否生成
    local config_path="$TARGET_HOME/Library/Application Support/Cursor/User/globalStorage/storage.json"
    local max_wait=30
    local waited=0

    while [ ! -f "$config_path" ] && [ $waited -lt $max_wait ]; do
        log_info "⏳ [等待] 等待配置文件生成... ($waited/$max_wait 秒)"
        sleep 1
        waited=$((waited + 1))
    done

    if [ -f "$config_path" ]; then
        log_info "✅ [成功] 配置文件已生成: $config_path"

        # 🛡️ 关键修复:配置文件生成后立即确保权限正确
        ensure_cursor_directory_permissions
    else
        log_warn "⚠️  [警告] 配置文件未在预期时间内生成,继续执行..."

        # 即使配置文件未生成,也要确保目录权限正确
        ensure_cursor_directory_permissions
    fi

    # 强制关闭Cursor
    log_info "🔄 [关闭] 正在关闭Cursor以进行配置修改..."
    if [ -n "${CURSOR_PID:-}" ]; then
        kill "$CURSOR_PID" 2>/dev/null || true
        # 🔧 回收后台进程,避免某些环境输出 “Terminated: 15 ...” 的噪音
        wait "$CURSOR_PID" 2>/dev/null || true
    fi

    # 确保所有Cursor进程都关闭
    pkill -f "Cursor" 2>/dev/null || true

    log_info "✅ [完成] Cursor重启流程完成"
    return 0
}

# 🔍 检查Cursor环境
test_cursor_environment() {
    local mode=${1:-"FULL"}

    echo
    log_info "🔍 [环境检查] 正在检查Cursor环境..."

    local config_path="$TARGET_HOME/Library/Application Support/Cursor/User/globalStorage/storage.json"
    local cursor_app_data="$TARGET_HOME/Library/Application Support/Cursor"
    local cursor_app_path="/Applications/Cursor.app"
    local issues=()

    # 检查Python3环境(macOS版本需要)
    if ! command -v python3 >/dev/null 2>&1; then
        issues+=("Python3环境不可用,macOS版本需要Python3来处理JSON配置文件")
        log_warn "⚠️  [警告] 未找到Python3,请安装Python3: brew install python3"
    else
        log_info "✅ [检查] Python3环境可用: $(python3 --version)"
    fi

    # 检查配置文件
    if [ ! -f "$config_path" ]; then
        issues+=("配置文件不存在: $config_path")
    else
        # 验证JSON格式
        # 🔧 修复:避免把路径直接拼进 Python 源码字符串(路径包含引号等特殊字符时会导致语法错误)
        if python3 -c 'import json, sys; json.load(open(sys.argv[1], "r", encoding="utf-8"))' "$config_path" 2>/dev/null; then
            log_info "✅ [检查] 配置文件格式正确"
        else
            issues+=("配置文件格式错误或损坏")
        fi
    fi

    # 检查Cursor目录结构
    if [ ! -d "$cursor_app_data" ]; then
        issues+=("Cursor应用数据目录不存在: $cursor_app_data")
    fi

    # 检查Cursor应用安装
    if [ ! -d "$cursor_app_path" ]; then
        issues+=("未找到Cursor应用安装: $cursor_app_path")
    else
        log_info "✅ [检查] 找到Cursor应用: $cursor_app_path"
    fi

    # 检查目录权限
    if [ -d "$cursor_app_data" ] && [ ! -w "$cursor_app_data" ]; then
        issues+=("Cursor应用数据目录无写入权限: $cursor_app_data")
    fi

    # 返回检查结果
    if [ ${#issues[@]} -eq 0 ]; then
        log_info "✅ [环境检查] 所有检查通过"
        return 0
    else
        log_error "❌ [环境检查] 发现 ${#issues[@]} 个问题:"
        for issue in "${issues[@]}"; do
            echo -e "${RED}  • $issue${NC}"
        done
        return 1
    fi
}

# 🚀 启动Cursor生成配置文件
start_cursor_to_generate_config() {
    log_info "🚀 [启动] 正在尝试启动Cursor生成配置文件..."

    local cursor_app_path="/Applications/Cursor.app"
    local cursor_executable="$cursor_app_path/Contents/MacOS/Cursor"

    if [ ! -f "$cursor_executable" ]; then
        log_error "❌ [错误] 未找到Cursor可执行文件: $cursor_executable"
        return 1
    fi

    log_info "📍 [路径] 使用Cursor路径: $cursor_executable"

    # 🚀 启动前权限修复
    ensure_cursor_directory_permissions

    # 启动Cursor
    "$cursor_executable" > /dev/null 2>&1 &
    local cursor_pid=$!
    log_info "🚀 [启动] Cursor已启动,PID: $cursor_pid"

    log_info "⏳ [等待] 请等待Cursor完全加载(约30秒)..."
    log_info "💡 [提示] 您可以在Cursor完全加载后手动关闭它"

    # 等待配置文件生成
    local config_path="$TARGET_HOME/Library/Application Support/Cursor/User/globalStorage/storage.json"
    local max_wait=60
    local waited=0

    while [ ! -f "$config_path" ] && [ $waited -lt $max_wait ]; do
        sleep 2
        waited=$((waited + 2))
        if [ $((waited % 10)) -eq 0 ]; then
            log_info "⏳ [等待] 等待配置文件生成... ($waited/$max_wait 秒)"
        fi
    done

    if [ -f "$config_path" ]; then
        log_info "✅ [成功] 配置文件已生成!"
        log_info "💡 [提示] 现在可以关闭Cursor并重新运行脚本"
        return 0
    else
        log_warn "⚠️  [超时] 配置文件未在预期时间内生成"
        log_info "💡 [建议] 请手动操作Cursor(如创建新文件)以触发配置生成"
        return 1
    fi
}

# 🛡️ 统一权限修复函数(优化版本)
ensure_cursor_directory_permissions() {
    log_info "🛡️ [权限修复] 执行核心权限修复命令..."

    # ⚠️ 关键:不要用 $(whoami) 当作目标用户!在 sudo 场景下 whoami= root,会把用户目录 chown 成 root,导致 Cursor 启动 EACCES
    local target_user="${TARGET_USER:-${SUDO_USER:-$USER}}"
    local cursor_support_dir="$TARGET_HOME/Library/Application Support/Cursor"
    local cursor_home_dir="$TARGET_HOME/.cursor"

    # 确保目录存在
    mkdir -p "$cursor_support_dir" 2>/dev/null || true
    mkdir -p "$cursor_home_dir/extensions" 2>/dev/null || true

    # 🔧 执行用户验证有效的4个核心权限修复命令
    log_info "🔧 [修复] 执行4个核心权限修复命令..."

    # 命令1: sudo chown -R <真实用户> ~/Library/"Application Support"/Cursor
    if sudo chown -R "$target_user" "$cursor_support_dir" 2>/dev/null; then
        log_info "✅ [1/4] sudo chown Application Support/Cursor 成功"
    else
        log_warn "⚠️  [1/4] sudo chown Application Support/Cursor 失败"
    fi

    # 命令2: sudo chown -R <真实用户> ~/.cursor
    if sudo chown -R "$target_user" "$cursor_home_dir" 2>/dev/null; then
        log_info "✅ [2/4] sudo chown .cursor 成功"
    else
        log_warn "⚠️  [2/4] sudo chown .cursor 失败"
    fi

    # 命令3: chmod -R u+rwX ~/Library/"Application Support"/Cursor
    # - X:仅对目录(或原本有可执行位的文件)补 x,避免破坏文件权限
    if chmod -R u+rwX "$cursor_support_dir" 2>/dev/null; then
        log_info "✅ [3/4] chmod Application Support/Cursor 成功"
    else
        log_warn "⚠️  [3/4] chmod Application Support/Cursor 失败"
    fi

    # 命令4: chmod -R u+rwX ~/.cursor (修复整个目录,不仅仅是extensions子目录)
    if chmod -R u+rwX "$cursor_home_dir" 2>/dev/null; then
        log_info "✅ [4/4] chmod .cursor 成功"
    else
        log_warn "⚠️  [4/4] chmod .cursor 失败"
    fi

    log_info "✅ [完成] 核心权限修复命令执行完成"
    return 0
}

#  关键权限修复函数(简化版本)
fix_cursor_permissions_
Download .txt
gitextract_anthe1ep/

├── .github/
│   └── workflows/
│       └── auto-tag-release.yml
├── .gitignore
├── LICENSE
├── README.md
├── README_CN.md
├── README_JP.md
└── scripts/
    ├── hook/
    │   ├── cursor_hook.js
    │   ├── inject_hook_unix.sh
    │   └── inject_hook_win.ps1
    └── run/
        ├── cursor_linux_id_modifier.sh
        ├── cursor_mac_id_modifier.sh
        └── cursor_win_id_modifier.ps1
Download .txt
SYMBOL INDEX (11 symbols across 1 files)

FILE: scripts/hook/cursor_hook.js
  function hookChildProcess (line 257) | function hookChildProcess(cp) {
  function hookOs (line 315) | function hookOs(os) {
  function normalizeFilePath (line 347) | function normalizeFilePath(filePath) {
  function previewValue (line 375) | function previewValue(value) {
  function coerceContentToUtf8Text (line 385) | function coerceContentToUtf8Text(content) {
  function isStorageJsonPath (line 416) | function isStorageJsonPath(filePath) {
  function protectStorageJson (line 424) | function protectStorageJson(content, filePath) {
  function hookFs (line 508) | function hookFs(fsModule) {
  function hookCrypto (line 693) | function hookCrypto(crypto) {
  function hookDeviceId (line 750) | function hookDeviceId(deviceIdModule) {
  function hookWindowsRegistry (line 764) | function hookWindowsRegistry(registryModule) {
Condensed preview — 12 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (399K chars).
[
  {
    "path": ".github/workflows/auto-tag-release.yml",
    "chars": 8372,
    "preview": "# This workflow requires Ubuntu 22.04 or 24.04\n\nname: Auto Tag & Release\n\non:\n  push:\n    branches:\n      - master\n     "
  },
  {
    "path": ".gitignore",
    "chars": 408,
    "preview": "# Compiled binary\n/cursor-id-modifier\n/cursor-id-modifier.exe\n\n# Build output directories\nbin/\ndist/\n\n# Go specific\ngo.s"
  },
  {
    "path": "LICENSE",
    "chars": 1063,
    "preview": "MIT License\n\nCopyright (c) 2024 dacrab\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof "
  },
  {
    "path": "README.md",
    "chars": 16853,
    "preview": "# 🚀 Cursor Free Trial Reset Tool\n\n<div align=\"center\">\n\n[![Release](https://img.shields.io/github/v/release/yuaotian/go-"
  },
  {
    "path": "README_CN.md",
    "chars": 13112,
    "preview": "# 🚀 Cursor 免费试用重置工具\n\n<div align=\"center\">\n\n[![Release](https://img.shields.io/github/v/release/yuaotian/go-cursor-help?s"
  },
  {
    "path": "README_JP.md",
    "chars": 19186,
    "preview": "# 🚀 Cursor 無料試用リセットツール\n\n<div align=\"center\">\n\n[![Release](https://img.shields.io/github/v/release/yuaotian/go-cursor-hel"
  },
  {
    "path": "scripts/hook/cursor_hook.js",
    "chars": 41414,
    "preview": "/**\n * Cursor 设备标识符 Hook 模块\n * \n * 🎯 功能:从底层拦截所有设备标识符的生成,实现一劳永逸的机器码修改\n * \n * 🔧 Hook 点:\n * 1. child_process.execSync - 拦截 "
  },
  {
    "path": "scripts/hook/inject_hook_unix.sh",
    "chars": 5810,
    "preview": "#!/bin/bash\n\n# ========================================\n# Cursor Hook 注入脚本 (macOS/Linux)\n# ============================="
  },
  {
    "path": "scripts/hook/inject_hook_win.ps1",
    "chars": 7466,
    "preview": "# ========================================\n# Cursor Hook 注入脚本 (Windows)\n# ========================================\n#\n# 🎯"
  },
  {
    "path": "scripts/run/cursor_linux_id_modifier.sh",
    "chars": 73509,
    "preview": "#!/bin/bash\n\n# 设置错误处理\nset -e\n\n# 定义日志文件路径\nLOG_FILE=\"/tmp/cursor_linux_id_modifier.log\"\n\n# 初始化日志文件\ninitialize_log() {\n    "
  },
  {
    "path": "scripts/run/cursor_mac_id_modifier.sh",
    "chars": 95931,
    "preview": "#!/bin/bash\n\n# ========================================\n# Cursor macOS 机器码修改脚本\n# ======================================="
  },
  {
    "path": "scripts/run/cursor_win_id_modifier.ps1",
    "chars": 94955,
    "preview": "# 设置输出编码为 UTF-8\n$OutputEncoding = [System.Text.Encoding]::UTF8\n[Console]::OutputEncoding = [System.Text.Encoding]::UTF8\n"
  }
]

About this extraction

This page contains the full source code of the yuaotian/go-cursor-help GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 12 files (369.2 KB), approximately 119.6k tokens, and a symbol index with 11 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!