diff --git a/.github/workflows/auto-tag-release.yml b/.github/workflows/auto-tag-release.yml
deleted file mode 100644
index ab9e5e5..0000000
--- a/.github/workflows/auto-tag-release.yml
+++ /dev/null
@@ -1,272 +0,0 @@
-# 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
diff --git a/.gitignore b/.gitignore
index 80d4dfa..37c65ae 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,16 +1,7 @@
-# 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/
@@ -23,17 +14,6 @@ Thumbs.db
# Build and release artifacts
releases/
-*.syso
-*.exe
-*.exe~
-*.dll
-*.so
-*.dylib
-
-# Test files
-*.test
-*.out
-coverage.txt
# Temporary files
*.tmp
diff --git a/.goreleaser.yml b/.goreleaser.yml
deleted file mode 100644
index 13c0b21..0000000
--- a/.goreleaser.yml
+++ /dev/null
@@ -1,92 +0,0 @@
-version: 2
-
-before:
- hooks:
- - go mod tidy
- - go mod vendor
- - go mod verify
-
-builds:
- - id: cursor-id-modifier
- main: ./cmd/cursor-id-modifier/main.go
- binary: cursor-id-modifier
- env:
- - CGO_ENABLED=0
- - GO111MODULE=on
- goos:
- - linux
- - windows
- - darwin
- goarch:
- - amd64
- - arm64
- - "386"
- ignore:
- - goos: darwin
- goarch: "386"
- ldflags:
- - -s -w
- - -X 'main.version={{.Version}}'
- - -X 'main.commit={{.ShortCommit}}'
- - -X 'main.date={{.CommitDate}}'
- - -X 'main.builtBy=goreleaser'
- flags:
- - -trimpath
- mod_timestamp: '{{ .CommitTimestamp }}'
-
-archives:
- - id: binary
- format: binary
- name_template: >-
- {{- .ProjectName }}_
- {{- .Version }}_
- {{- .Os }}_
- {{- if eq .Arch "amd64" }}x86_64
- {{- else if eq .Arch "386" }}i386
- {{- else }}{{ .Arch }}{{ end }}
- builds:
- - cursor-id-modifier
- allow_different_binary_count: true
- files:
- - none*
-
-checksum:
- name_template: 'checksums.txt'
- algorithm: sha256
-
-release:
- draft: true
- prerelease: auto
- mode: replace
- header: |
- ## Release {{.Tag}} ({{.Date}})
-
- See [CHANGELOG.md](CHANGELOG.md) for details.
- footer: |
- **Full Changelog**: https://github.com/owner/repo/compare/{{ .PreviousTag }}...{{ .Tag }}
- extra_files:
- - glob: 'LICENSE*'
- - glob: 'README*'
- - glob: 'CHANGELOG*'
-
-changelog:
- sort: asc
- use: github
- filters:
- exclude:
- - '^docs:'
- - '^test:'
- - '^ci:'
- - Merge pull request
- - Merge branch
- groups:
- - title: Features
- regexp: "^.*feat[(\\w)]*:+.*$"
- order: 0
- - title: 'Bug fixes'
- regexp: "^.*fix[(\\w)]*:+.*$"
- order: 1
- - title: Others
- order: 999
-
-project_name: cursor-id-modifier
diff --git a/LICENSE b/LICENSE
deleted file mode 100644
index 11eeb01..0000000
--- a/LICENSE
+++ /dev/null
@@ -1,21 +0,0 @@
-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.
\ No newline at end of file
diff --git a/README.md b/README.md
index 4da973c..3a35720 100644
--- a/README.md
+++ b/README.md
@@ -10,557 +10,356 @@
-
-
-
-
-> ⚠️ **IMPORTANT NOTICE**
->
-> This tool currently supports:
-> - ✅ Windows: Latest 1.0.x versions (Supported)
-> - ✅ Mac/Linux: Latest 1.0.x versions (Supported, feedback welcome)
->
-> Please check your Cursor version before using this tool.
-
-
-📦 Version History & Downloads
-
-
-
-### 🌟 Latest Versions
-
-[View Full Version History]([CursorHistoryDown.md](https://github.com/oslook/cursor-ai-downloads?tab=readme-ov-file))
-
-
-
-
-
-⚠️ **General Solutions for Cursor**
-> 1. Close Cursor, log out of your account, and delete your account in the official website Settings (refresh IP node: Japan, Singapore, USA, Hong Kong, prioritizing low latency - not necessarily required but change if conditions allow; Windows users are recommended to refresh DNS cache: `ipconfig /flushdns`)
-> Go to the Cursor official website to delete your current account
-> Steps: User avatar -> Setting -> Advanced▼ in the bottom left -> Delete Account
->
-> 2. Run the machine code refresh script, see the script address below, available in China
->
-> 3. Re-register an account, log in, and open Cursor to resume normal use.
->
-> 4. Alternative solution: If still unusable after step [**3**], or if you encounter problems such as account registration failure or inability to delete an account, this usually means your browser has been identified or restricted by the target website (risk control). In this case, try switching browsers, such as: Edge, Google Chrome, Firefox. (Or, consider using a browser that can modify or randomize browser fingerprint information).
-
-
---
-⚠️ **MAC Address Modification Warning**
->
-> For Mac users: This script includes a MAC address modification feature that will:
-> - Modify your network interface's MAC address
-> - Backup original MAC addresses before modification
-> - This modification may temporarily affect network connectivity
-> - You can skip this step when prompted during execution
->
-
-
-🔒 Disable Auto-Update Feature
+## 🎯 What This Tool Does
-> To prevent Cursor from automatically updating to unsupported new versions, you can choose to disable the auto-update feature.
+**Cursor Free Trial Reset Tool** helps you reset your Cursor AI editor trial by modifying device identifiers. When you see those annoying trial limit messages, this tool gives you a fresh start!
-#### Method 1: Using Built-in Script (Recommended)
+### 🚨 Common Issues This Fixes
-When running the reset tool, the script will ask if you want to disable auto-updates:
-```text
-[Question] Do you want to disable Cursor auto-update feature?
-0) No - Keep default settings (Press Enter)
-1) Yes - Disable auto-update
-```
-
-Select `1` to automatically complete the disable operation.
-
-#### Method 2: Manual Disable
-
-**Windows:**
-1. Close all Cursor processes
-2. Delete directory: `%LOCALAPPDATA%\cursor-updater`
-3. Create a file with the same name (without extension) in the same location
-
-**macOS:**
-```bash
-# NOTE: As tested, this method only works for version 0.45.11 and below.
-# Close Cursor
-pkill -f "Cursor"
-# Replacing app-update.yml with a blank/read-only file
-cd /Applications/Cursor.app/Contents/Resources
-mv app-update.yml app-update.yml.bak
-touch app-update.yml
-chmod 444 app-update.yml
-
-# Go to Settings -> Application -> Update, set Mode to none.
-# This must be done to prevent Cursor from checking for updates.
-
-# NOTE: The cursor-updater modification method may no longer be effective
-# In any case, remove update directory and create blocking file
-rm -rf ~/Library/Application\ Support/Caches/cursor-updater
-touch ~/Library/Application\ Support/Caches/cursor-updater
-```
+
+🔴 "Too many free trial accounts used on this machine"
-**Linux:**
-```bash
-# Close Cursor
-pkill -f "Cursor"
-# Remove update directory and create blocking file
-rm -rf ~/.config/cursor-updater
-touch ~/.config/cursor-updater
```
-
-> ⚠️ **Note:** After disabling auto-updates, you'll need to manually download and install new versions. It's recommended to update only after confirming the new version is compatible.
-
-
-
-
----
-
-### 📝 Description
-
-> When you encounter any of these messages:
-
-#### Issue 1: Trial Account Limit 
-
-```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.
```
-#### Issue 2: API Key Limitation 
+**✅ Solution:** Use our tool to reset your machine's device identifiers!
+
+
-```text
-[New Issue]
+
+🟡 "Composer relies on custom models..."
+```
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
```
-#### Issue 3: Trial Request Limit
+**✅ Solution:**
+1. Completely uninstall Cursor using [Geek Uninstaller](https://geekuninstaller.com/download)
+2. Reinstall Cursor
+3. Run our reset tool
-> This indicates you've reached the usage limit during the VIP free trial period:
-
-```text
-You've reached your trial request limit.
-```
+
-#### Issue 4: Claude 3.7 High Load

+
+🟣 "High Load" for Claude 3.7
-```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.
+```
+We're experiencing high demand for Claude 3.7 Sonnet right now.
+Please upgrade to Pro, or switch to the 'default' model...
```
-
-
-
-
-#### Solution : Uninstall Cursor Completely And Reinstall (API key Issue)
-
-1. Download [Geek.exe Uninstaller[Free]](https://geekuninstaller.com/download)
-2. Uninstall Cursor app completely
-3. Re-Install Cursor app
-4. Continue to Solution 1
-
-
-
-
-
-> Temporary Solution:
-
-#### Solution 1: Quick Reset (Recommended)
-
-1. Close Cursor application
-2. Run the machine code reset script (see installation instructions below)
-3. Reopen Cursor to continue using
-
-#### Solution 2: Account Switch
-
-1. File -> Cursor Settings -> Sign Out
-2. Close Cursor
-3. Run the machine code reset script
-4. Login with a new account
-
-#### Solution 3: Network Optimization
-
-If the above solutions don't work, try:
-
-- Switch to low-latency nodes (Recommended regions: Japan, Singapore, US, Hong Kong)
-- Ensure network stability
-- Clear browser cache and retry
-
-#### Solution 4: Claude 3.7 Access Issue (High Load)
-
-If you see the "High Load" message for Claude 3.7 Sonnet, this indicates Cursor is limiting free trial accounts from using the 3.7 model during certain times of the day. Try:
+**✅ Solution:** Reset your trial and try during off-peak hours (5-10 AM or 3-7 PM)
-1. Switch to a new account created with Gmail, possibly connecting through a different IP address
-2. Try accessing during off-peak hours (typically 5-10 AM or 3-7 PM when restrictions are often lighter)
-3. Consider upgrading to Pro for guaranteed access
-4. Use Claude 3.5 Sonnet as a fallback option
+
-> Note: These access patterns may change as Cursor adjusts their resource allocation policies.
+---
-### 💻 System Support
+## 🖥️ Platform Support
-
+
-
-
-**Windows** ✅
+ |
-- x64 (64-bit)
-- x86 (32-bit)
+### 🐧 **Linux**
+✅ All distributions
+✅ x64, x86, ARM64
+✅ Auto-detection
|
-
-
-**macOS** ✅
+ |
-- Intel (x64)
-- Apple Silicon (M1/M2)
+### 🍎 **macOS**
+✅ Intel & Apple Silicon
+✅ Permission auto-fix
+✅ Python3 integration
|
-
-
-**Linux** ✅
+ |
-- x64 (64-bit)
-- x86 (32-bit)
-- ARM64
+### 🪟 **Windows**
+✅ x64, x86, ARM64
+✅ Registry modification
+✅ PowerShell 7 ready
|
+---
+## ⚡ Quick Start (One-Click Solution)
-### 🚀 One-Click Solution
+### 🌍 Global Users
-Global Users
-
-**macOS**
+🐧 Linux
```bash
-# Method two
-curl -fsSL https://aizaozao.com/accelerate.php/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
+curl -fsSL https://raw.githubusercontent.com/yuaotian/go-cursor-help/refs/heads/master/scripts/run/cursor_linux_id_modifier.sh | sudo bash
```
-**Linux**
+
+
+
+🍎 macOS
```bash
-curl -fsSL https://raw.githubusercontent.com/yuaotian/go-cursor-help/refs/heads/master/scripts/run/cursor_linux_id_modifier.sh | sudo 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
```
-> **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
-**Windows**
+**Run in PowerShell as Administrator:**
```powershell
irm https://raw.githubusercontent.com/yuaotian/go-cursor-help/refs/heads/master/scripts/run/cursor_win_id_modifier.ps1 | iex
```
-**Windows (Enhanced Version)**
+
-```powershell
-irm https://raw.githubusercontent.com/yuaotian/go-cursor-help/refs/heads/master/scripts/run/cursor_win_id_modifier_new.ps1 | iex
-```
-> Enhanced Cursor machine code modifier with dual-mode operation and trial reset functionality
+### 🇨🇳 China Users (Accelerated)
-
-

-
+
+🐧 Linux
+
+```bash
+curl -fsSL https://aizaozao.com/accelerate.php/https://raw.githubusercontent.com/yuaotian/go-cursor-help/refs/heads/master/scripts/run/cursor_linux_id_modifier.sh | sudo bash
+```
-China Users (Recommended)
-
-**macOS**
+🍎 macOS
```bash
curl -fsSL https://aizaozao.com/accelerate.php/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://aizaozao.com/accelerate.php/https://raw.githubusercontent.com/yuaotian/go-cursor-help/refs/heads/master/scripts/run/cursor_linux_id_modifier.sh | sudo bash
-```
+
-**Windows**
+
+🪟 Windows
```powershell
irm https://aizaozao.com/accelerate.php/https://raw.githubusercontent.com/yuaotian/go-cursor-help/refs/heads/master/scripts/run/cursor_win_id_modifier.ps1 | iex
```
-**Windows (Enhanced Version)**
+
-```powershell
-irm https://aizaozao.com/accelerate.php/https://raw.githubusercontent.com/yuaotian/go-cursor-help/refs/heads/master/scripts/run/cursor_win_id_modifier_new.ps1 | iex
-```
-> Enhanced Cursor machine code modifier with dual-mode operation and trial reset functionality
+---
-
+## 🛠️ How to Run as Administrator
-
-Windows Terminal Run and Configuration
-
-#### 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)
-```
+### 🪟 Windows Methods
-##### 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:
+
+Method 1: Win + X Shortcut
-irm https://aizaozao.com/accelerate.php/https://raw.githubusercontent.com/yuaotian/go-cursor-help/refs/heads/master/scripts/run/cursor_win_id_modifier.ps1 | iex
-```
+1. Press `Win + X`
+2. Select "Windows PowerShell (Administrator)" or "Terminal (Administrator)"
+3. Paste the command above
-For the enhanced version:
-```powershell
-irm https://aizaozao.com/accelerate.php/https://raw.githubusercontent.com/yuaotian/go-cursor-help/refs/heads/master/scripts/run/cursor_win_id_modifier_new.ps1 | iex
-```
+
-##### Method 3: Using Search
->
->
->Type pwsh in the search box, right-click and select "Run as administrator"
->
+
+Method 2: Search Method
-Enter the reset script in the administrator terminal:
-```powershell
-irm https://aizaozao.com/accelerate.php/https://raw.githubusercontent.com/yuaotian/go-cursor-help/refs/heads/master/scripts/run/cursor_win_id_modifier.ps1 | iex
-```
+1. Search for "PowerShell" in Start Menu
+2. Right-click → "Run as administrator"
+3. Paste the command
-For the enhanced version:
-```powershell
-irm https://aizaozao.com/accelerate.php/https://raw.githubusercontent.com/yuaotian/go-cursor-help/refs/heads/master/scripts/run/cursor_win_id_modifier_new.ps1 | iex
-```
+
+
-### 🔧 PowerShell Installation Guide
+
-If PowerShell is not installed on your system, you can install it using one of these methods:
+
+Method 3: Win + R
-#### Method 1: Install via Winget (Recommended)
+1. Press `Win + R`
+2. Type `powershell`
+3. Press `Ctrl + Shift + Enter`
-1. Open Command Prompt or PowerShell
-2. Run the following command:
+
+
+### 🔧 PowerShell Installation (if needed)
+
+**Option 1: Using Winget**
```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)
+**Option 2: Manual Download**
+- [PowerShell 7.4.6 x64](https://github.com/PowerShell/PowerShell/releases/download/v7.4.6/PowerShell-7.4.6-win-x64.msi)
+- [PowerShell 7.4.6 x86](https://github.com/PowerShell/PowerShell/releases/download/v7.4.6/PowerShell-7.4.6-win-x86.msi)
+- [PowerShell 7.4.6 ARM64](https://github.com/PowerShell/PowerShell/releases/download/v7.4.6/PowerShell-7.4.6-win-arm64.msi)
-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)
+---
-
+## 🔧 Advanced Features
-#### Windows 安装特性:
+### 🔒 Auto-Update Disable
-- 🔍 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
+The script can automatically disable Cursor's auto-update feature to prevent version conflicts:
-That's it! The script will:
+**Windows:** Creates blocking file at `%LOCALAPPDATA%\cursor-updater`
+**macOS:** Modifies `app-update.yml` and creates blocking files
+**Linux:** Creates blocking file at `~/.config/cursor-updater`
-1. ✨ Install the tool automatically
-2. 🔄 Reset your Cursor trial immediately
+### 🛡️ Safety Features
-### 📦 Manual Installation
+- ✅ **Automatic Backups** - All original files are backed up before modification
+- ✅ **Process Management** - Safely stops and restarts Cursor processes
+- ✅ **Permission Handling** - Automatically fixes file permissions (macOS)
+- ✅ **Error Recovery** - Restores backups if something goes wrong
+- ✅ **Multi-Method Approach** - Uses multiple techniques for maximum compatibility
-> Download the appropriate file for your system from [releases](https://github.com/yuaotian/go-cursor-help/releases/latest)
+### 🔍 What Gets Modified
-Windows Packages
+Configuration Files
-- 64-bit: `cursor-id-modifier_windows_x64.exe`
-- 32-bit: `cursor-id-modifier_windows_x86.exe`
-
+**Location:**
+- Windows: `%APPDATA%\Cursor\User\globalStorage\storage.json`
+- macOS: `~/Library/Application Support/Cursor/User/globalStorage/storage.json`
+- Linux: `~/.config/Cursor/User/globalStorage/storage.json`
-
-macOS Packages
+**Modified Fields:**
+- `telemetry.machineId`
+- `telemetry.macMachineId`
+- `telemetry.devDeviceId`
+- `telemetry.sqmId`
-- Intel: `cursor-id-modifier_darwin_x64_intel`
-- M1/M2: `cursor-id-modifier_darwin_arm64_apple_silicon`
-Linux Packages
+JavaScript Files (Advanced)
-- 64-bit: `cursor-id-modifier_linux_x64`
-- 32-bit: `cursor-id-modifier_linux_x86`
-- ARM64: `cursor-id-modifier_linux_arm64`
-
+The tool injects code into Cursor's JavaScript files to override device ID functions:
+- `extensionHostProcess.js`
+- `main.js`
+- `cliProcessMain.js`
-### 🔧 Technical Details
+
-Configuration Files
+Windows Registry (Windows Only)
-The program modifies Cursor's `storage.json` config file located at:
+**Modified Registry:**
+- Path: `HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography`
+- Key: `MachineGuid`
+
+**⚠️ Important:** Original values are automatically backed up to `%APPDATA%\Cursor\User\globalStorage\backups`
-- Windows: `%APPDATA%\Cursor\User\globalStorage\storage.json`
-- macOS: `~/Library/Application Support/Cursor/User/globalStorage/storage.json`
-- Linux: `~/.config/Cursor/User/globalStorage/storage.json`
-
-Modified Fields
+---
-The tool generates new unique identifiers for:
+## 🎉 Success Screenshot
-- `telemetry.machineId`
-- `telemetry.macMachineId`
-- `telemetry.devDeviceId`
-- `telemetry.sqmId`
-
+
+

+
-
-Manual Auto-Update Disable
+---
-Windows users can manually disable the auto-update feature:
+## 🆘 Troubleshooting
-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)
+### ❓ Common Issues
-macOS/Linux users can try to locate similar `cursor-updater` directory in their system and perform the same operation.
+**Q: Script says "Permission denied"**
+A: Make sure you're running with `sudo` (Linux/macOS) or as Administrator (Windows)
-
+**Q: Cursor still shows trial limit**
+A: Try the full reset option and restart Cursor completely
-
-Safety Features
+**Q: Script can't find Cursor installation**
+A: Ensure Cursor is installed in standard locations or install from [cursor.sh](https://cursor.sh/)
-- ✅ Safe process termination
-- ✅ Atomic file operations
-- ✅ Error handling and recovery
-
+**Q: Python3 error on macOS**
+A: Install Python3 with `brew install python3`
-
-Registry Modification Notice
+### 🔄 General Solution Steps
-> ⚠️ **Important: This tool modifies the Windows Registry**
+1. **Close Cursor completely**
+2. **Delete account** from Cursor website (Settings → Advanced → Delete Account)
+3. **Run our reset tool**
+4. **Register new account**
+5. **Restart Cursor**
-#### 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
-
+## 💡 Pro Tips
+
+- 🌐 **Network Optimization:** Use low-latency nodes (Japan, Singapore, US, Hong Kong)
+- 🕐 **Timing:** Try accessing Claude 3.7 during off-peak hours
+- 🔄 **Browser Switching:** If account issues persist, try different browsers
+- 📱 **IP Refresh:** Consider refreshing your IP if possible
+- 🧹 **DNS Cache:** Windows users can run `ipconfig /flushdns`
---
-### 📚 Recommended Reading
+## 📚 Additional Resources
-- [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)
+- [Cursor Issues Collection & Solutions](https://mp.weixin.qq.com/s/pnJrH7Ifx4WZvseeP1fcEA)
+- [AI Development Assistant 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_new.ps1` script, please share your experience:
+## 💬 Feedback & Support
-- 🐛 **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
+Found this helpful? We'd love to hear from you!
-Your feedback helps us improve the tool for everyone. Feel free to open an issue or contribute to the project!
+- 🐛 **Bug Reports:** Open an issue on GitHub
+- 💡 **Feature Requests:** Share your ideas
+- ⭐ **Success Stories:** Tell us how it helped
+- 🔧 **Technical Feedback:** Performance insights welcome
---
-## Support
+## ☕ Support the Project
---
-## ⭐ Project Stats
+## 📊 Project Stats
@@ -570,12 +369,17 @@ ETC: 0xa2745f4CD5d32310AC01694ABDB28bA32D125a6b
+---
+
## 📄 License
MIT License
-Copyright (c) 2024
+```
+MIT License
+
+Copyright (c) 2025
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@@ -587,5 +391,23 @@ 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.
+```
+
+---
+
+
+
+**⭐ Star this repo if it helped you! ⭐**
+
+**Made with ❤️ for the Cursor community**
+
+
\ No newline at end of file
diff --git a/README_CN.md b/README_CN.md
index 80ee6e2..341825c 100644
--- a/README_CN.md
+++ b/README_CN.md
@@ -10,502 +10,366 @@
-
-
-> ⚠️ **重要提示**
->
-> 本工具当前支持版本:
-> - ✅ Windows: 最新的 1.0.x 版本(已支持)
-> - ✅ Mac/Linux: 最新的 1.0.x 版本(已支持,欢迎测试并反馈问题)
-
-> 使用前请确认您的 Cursor 版本。
-
-
-📦 版本历史与下载
-
-
-
-
-[查看完整版本历史]([CursorHistoryDown.md](https://github.com/oslook/cursor-ai-downloads?tab=readme-ov-file))
-
-
-
-
-⚠️ **Cursor通用解决方案**
-> 1. 关闭Cursor、退出账号、官网Setting删除账号(刷新节点IP:日本、新加坡、 美国、香港,低延迟为主不一定需要但是有条件就换,Windows用户建议刷新DNS缓存:`ipconfig /flushdns`)
-> 前往Cursor官网删除当前账号
-> 步骤:用户头像->Setting-左下角Advanced▼->Delete Account
->
-> 2. 刷新机器码脚本,看下面脚本地址,国内可用
->
-> 3. 重新注册账号、登录、打开Cursor,即可恢复正常使用。
->
-> 4. 备用方案:如果步骤 [**3**] 后仍不可用,或者遇到注册账号失败、无法删除账号等问题,这通常意味着您的浏览器被目标网站识别或限制(风控)。此时,请尝试更换浏览器,例如:Edge、Google Chrome、Firefox。(或者,可以尝试使用能够修改或随机化浏览器指纹信息的浏览器)。
-
-
-关注大佬公众号:煎饼果子卷AI
-
-
---
-> ⚠️ **MAC地址修改警告**
->
-> Mac用户请注意: 本脚本包含MAC地址修改功能,将会:
-> - 修改您的网络接口MAC地址
-> - 在修改前备份原始MAC地址
-> - 此修改可能会暂时影响网络连接
-> - 执行过程中可以选择跳过此步骤
-
----
+## 🎯 工具功能
-### 📝 问题描述
+**Cursor 免费试用重置工具** 通过修改设备标识符来重置您的 Cursor AI 编辑器试用期。当您看到那些烦人的试用限制消息时,这个工具能给您一个全新的开始!
-> 当您遇到以下任何消息时:
+### 🚨 常见问题解决
-#### 问题 1: 试用账号限制 
+
+🔴 "Too many free trial accounts used on this machine"
-```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密钥限制 
+**✅ 解决方案:** 使用我们的工具重置您机器的设备标识符!
-```text
-[New Issue]
+
+
+
+🟡 "Composer relies on custom models..."
+```
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免费试用期间已达到使用限制:
+**✅ 解决方案:**
+1. 使用 [Geek 卸载工具](https://geekuninstaller.com/download) 完全卸载 Cursor
+2. 重新安装 Cursor
+3. 运行我们的重置工具
-```text
-You've reached your trial request limit.
-```
+
-#### 问题 4: Claude 3.7 高负载 (High Load) 
+
+🟣 Claude 3.7 "High Load" 高负载
-```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.
+```
+We're experiencing high demand for Claude 3.7 Sonnet right now.
+Please upgrade to Pro, or switch to the 'default' model...
```
-
-
-
-
-#### 解决方案:完全卸载Cursor并重新安装(API密钥问题)
-
-1. 下载 [Geek.exe 卸载工具[免费]](https://geekuninstaller.com/download)
-2. 完全卸载Cursor应用
-3. 重新安装Cursor应用
-4. 继续执行解决方案1
-
-
-
-
-
-> 临时解决方案:
-
-#### 解决方案 1: 快速重置(推荐)
-
-1. 关闭Cursor应用
-2. 运行机器码重置脚本(见下方安装说明)
-3. 重新打开Cursor继续使用
-
-#### 解决方案 2: 切换账号
-
-1. 文件 -> Cursor设置 -> 退出登录
-2. 关闭Cursor
-3. 运行机器码重置脚本
-4. 使用新账号登录
-
-#### 解决方案 3: 网络优化
-
-如果上述解决方案不起作用,请尝试:
-
-- 切换到低延迟节点(推荐区域:日本、新加坡、美国、香港)
-- 确保网络稳定性
-- 清除浏览器缓存并重试
-
-
-
-#### 解决方案 4: Claude 3.7 访问问题(High Load )
-
-如果您看到Claude 3.7 Sonnet的"High Load"(高负载)消息,这表明Cursor在一天中某些时段限制免费试用账号使用3.7模型。请尝试:
+**✅ 解决方案:** 重置试用期并在非高峰时段尝试(早上5-10点或下午3-7点)
-1. 使用Gmail邮箱创建新账号,可能需要通过不同IP地址连接
-2. 尝试在非高峰时段访问(通常在早上5-10点或下午3-7点之间限制较少)
-3. 考虑升级到Pro版本获取保证访问权限
-4. 使用Claude 3.5 Sonnet作为备选方案
+
-> 注意:随着Cursor调整资源分配策略,这些访问模式可能会发生变化。
+---
-### 🚀 系统支持
+## 🖥️ 平台支持
-
+
-
-
-**Windows** ✅
+ |
-- x64 & x86
+### 🐧 **Linux**
+✅ 所有发行版
+✅ x64, x86, ARM64
+✅ 自动检测安装
|
-
-
-**macOS** ✅
+ |
-- Intel & M-series
+### 🍎 **macOS**
+✅ Intel & Apple Silicon
+✅ 权限自动修复
+✅ Python3 集成
|
-
-
-**Linux** ✅
+ |
-- x64 & ARM64
+### 🪟 **Windows**
+✅ x64, x86, ARM64
+✅ 注册表修改
+✅ PowerShell 7 就绪
|
+---
+## ⚡ 快速开始(一键解决方案)
-### 🚀 一键解决方案
+### 🇨🇳 国内用户(推荐,加速访问)
-国内用户(推荐)
-
-**macOS**
+🐧 Linux
```bash
-curl -fsSL https://aizaozao.com/accelerate.php/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
+curl -fsSL https://aizaozao.com/accelerate.php/https://raw.githubusercontent.com/yuaotian/go-cursor-help/refs/heads/master/scripts/run/cursor_linux_id_modifier.sh | sudo bash
```
-**Linux**
+
+
+
+🍎 macOS
```bash
-curl -fsSL https://aizaozao.com/accelerate.php/https://raw.githubusercontent.com/yuaotian/go-cursor-help/refs/heads/master/scripts/run/cursor_linux_id_modifier.sh | sudo bash
+curl -fsSL https://aizaozao.com/accelerate.php/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 用户请注意:** 该脚本通过检查常用路径(`/usr/bin`, `/usr/local/bin`, `$HOME/.local/bin`, `/opt/cursor`, `/snap/bin`)、使用 `which cursor` 命令以及在 `/usr`、`/opt` 和 `$HOME/.local` 目录内搜索,来尝试定位您的 Cursor 安装。如果 Cursor 安装在其他位置或通过这些方法无法找到,脚本可能会失败。请确保可以通过这些标准位置或方法之一访问到 Cursor。
+
+
+
+🪟 Windows
-**Windows**
+**在 PowerShell 管理员模式下运行:**
```powershell
irm https://aizaozao.com/accelerate.php/https://raw.githubusercontent.com/yuaotian/go-cursor-help/refs/heads/master/scripts/run/cursor_win_id_modifier.ps1 | iex
```
-**Windows (增强版)**
+
-```powershell
-irm https://aizaozao.com/accelerate.php/https://raw.githubusercontent.com/yuaotian/go-cursor-help/refs/heads/master/scripts/run/cursor_win_id_modifier_new.ps1 | iex
+### 🌍 海外用户
+
+
+🐧 Linux
+
+```bash
+curl -fsSL https://raw.githubusercontent.com/yuaotian/go-cursor-help/refs/heads/master/scripts/run/cursor_linux_id_modifier.sh | sudo bash
```
-> 增强版Cursor机器码修改工具,支持双模式操作和试用重置功能
-
-

-
-
-Windows 管理员终端运行和手动安装
-
-#### 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. 在管理员终端中输入以下重置脚本:
+
+🍎 macOS
-irm https://aizaozao.com/accelerate.php/https://raw.githubusercontent.com/yuaotian/go-cursor-help/refs/heads/master/scripts/run/cursor_win_id_modifier.ps1 | iex
+```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
```
-增强版脚本:
-```powershell
-irm https://aizaozao.com/accelerate.php/https://raw.githubusercontent.com/yuaotian/go-cursor-help/refs/heads/master/scripts/run/cursor_win_id_modifier_new.ps1 | iex
-```
+
-##### 方法三:通过搜索启动
->
->
->在搜索框中输入 pwsh,右键选择"以管理员身份运行"
->
+
+🪟 Windows
-在管理员终端中输入重置脚本:
```powershell
-irm https://aizaozao.com/accelerate.php/https://raw.githubusercontent.com/yuaotian/go-cursor-help/refs/heads/master/scripts/run/cursor_win_id_modifier.ps1 | iex
+irm https://raw.githubusercontent.com/yuaotian/go-cursor-help/refs/heads/master/scripts/run/cursor_win_id_modifier.ps1 | iex
```
-增强版脚本:
-```powershell
-irm https://aizaozao.com/accelerate.php/https://raw.githubusercontent.com/yuaotian/go-cursor-help/refs/heads/master/scripts/run/cursor_win_id_modifier_new.ps1 | iex
-```
+
+
+---
+
+## 🛠️ Windows 管理员权限运行方法
+
+### 🪟 Windows 操作方法
+
+
+方法一:Win + X 快捷键
-### 🔧 PowerShell 安装指南
+1. 按下 `Win + X` 组合键
+2. 选择 "Windows PowerShell (管理员)" 或 "终端(管理员)"
+3. 粘贴上面的命令
-如果您的系统没有安装 PowerShell,可以通过以下方法安装:
+
+
+
+方法二:搜索方法
+
+1. 在开始菜单搜索 "PowerShell"
+2. 右键点击 → "以管理员身份运行"
+3. 粘贴命令
+
+
+
+
+
+
+
+方法三:Win + R
+
+1. 按下 `Win + R`
+2. 输入 `powershell`
+3. 按 `Ctrl + Shift + Enter`
+
+
-#### 方法一:使用 Winget 安装(推荐)
+### 🔧 PowerShell 安装(如需要)
-1. 打开命令提示符或 PowerShell
-2. 运行以下命令:
+**选项1:使用 Winget**
```powershell
winget install --id Microsoft.PowerShell --source winget
```
-#### 方法二:手动下载安装
+**选项2:手动下载**
+- [PowerShell 7.4.6 x64](https://github.com/PowerShell/PowerShell/releases/download/v7.4.6/PowerShell-7.4.6-win-x64.msi)
+- [PowerShell 7.4.6 x86](https://github.com/PowerShell/PowerShell/releases/download/v7.4.6/PowerShell-7.4.6-win-x86.msi)
+- [PowerShell 7.4.6 ARM64](https://github.com/PowerShell/PowerShell/releases/download/v7.4.6/PowerShell-7.4.6-win-arm64.msi)
-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)
+### 🔒 自动更新禁用
-
+脚本可以自动禁用 Cursor 的自动更新功能以防止版本冲突:
-#### Windows 安装特性:
+**Windows:** 在 `%LOCALAPPDATA%\cursor-updater` 创建阻止文件
+**macOS:** 修改 `app-update.yml` 并创建阻止文件
+**Linux:** 在 `~/.config/cursor-updater` 创建阻止文件
-- 🔍 自动检测并使用 PowerShell 7(如果可用)
-- 🛡️ 通过 UAC 提示请求管理员权限
-- 📝 如果没有 PS7 则使用 Windows PowerShell
-- 💡 如果提权失败会提供手动说明
+### 🛡️ 安全特性
-完成后,脚本将:
+- ✅ **自动备份** - 修改前自动备份所有原始文件
+- ✅ **进程管理** - 安全停止和重启 Cursor 进程
+- ✅ **权限处理** - 自动修复文件权限(macOS)
+- ✅ **错误恢复** - 出错时自动恢复备份
+- ✅ **多方法兼容** - 使用多种技术确保最大兼容性
-1. ✨ 自动安装工具
-2. 🔄 立即重置 Cursor 试用期
+### 🔍 修改内容
-### 📦 手动安装
+
+配置文件
-> 从 [releases](https://github.com/yuaotian/go-cursor-help/releases/latest) 下载适合您系统的文件
+**位置:**
+- Windows: `%APPDATA%\Cursor\User\globalStorage\storage.json`
+- macOS: `~/Library/Application Support/Cursor/User/globalStorage/storage.json`
+- Linux: `~/.config/Cursor/User/globalStorage/storage.json`
-
-Windows 安装包
+**修改字段:**
+- `telemetry.machineId`
+- `telemetry.macMachineId`
+- `telemetry.devDeviceId`
+- `telemetry.sqmId`
-- 64 位: `cursor-id-modifier_windows_x64.exe`
-- 32 位: `cursor-id-modifier_windows_x86.exe`
-macOS 安装包
+JavaScript 文件(高级)
+
+工具会向 Cursor 的 JavaScript 文件注入代码以覆盖设备 ID 函数:
+- `extensionHostProcess.js`
+- `main.js`
+- `cliProcessMain.js`
-- Intel: `cursor-id-modifier_darwin_x64_intel`
-- M1/M2: `cursor-id-modifier_darwin_arm64_apple_silicon`
-Linux 安装包
+Windows 注册表(仅 Windows)
-- 64 位: `cursor-id-modifier_linux_x64`
-- 32 位: `cursor-id-modifier_linux_x86`
-- ARM64: `cursor-id-modifier_linux_arm64`
-
+**修改注册表:**
+- 路径: `HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography`
+- 键: `MachineGuid`
-### 🔧 技术细节
+**⚠️ 重要:** 原始值会自动备份到 `%APPDATA%\Cursor\User\globalStorage\backups`
-
-注册表修改说明
-
-> ⚠️ **重要提示:本工具会修改系统注册表**
-
-#### 修改内容
-- 路径:`计算机\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`
- - 选择"修改"
- - 粘贴备份文件中的值
-
-#### 注意事项
-- 建议在修改前先确认备份文件的存在
-- 如遇问题可通过备份文件恢复原始值
-- 必须以管理员权限运行才能修改注册表
-
-配置文件
+---
-程序修改 Cursor 的`storage.json`配置文件,位于:
+## 🎉 成功截图
-- Windows: `%APPDATA%\Cursor\User\globalStorage\`
-- macOS: `~/Library/Application Support/Cursor/User/globalStorage/`
-- Linux: `~/.config/Cursor/User/globalStorage/`
-
+
+

+
-
-修改字段
+---
-工具会生成新的唯一标识符:
+## 🆘 故障排除
-- `telemetry.machineId`
-- `telemetry.macMachineId`
-- `telemetry.devDeviceId`
-- `telemetry.sqmId`
-
+### ❓ 常见问题
-
-手动禁用自动更新
+**Q: 脚本提示 "Permission denied"**
+A: 确保使用 `sudo`(Linux/macOS)或管理员权限(Windows)运行
-Windows 用户可以手动禁用自动更新功能:
+**Q: Cursor 仍显示试用限制**
+A: 尝试完整重置选项并完全重启 Cursor
-1. 关闭所有 Cursor 进程
-2. 删除目录:`C:\Users\用户名\AppData\Local\cursor-updater`
-3. 创建同名文件:`cursor-updater`(不带扩展名)
+**Q: 脚本找不到 Cursor 安装**
+A: 确保 Cursor 安装在标准位置或从 [cursor.sh](https://cursor.sh/) 安装
-Linux用户可以尝试在系统中找到类似的`cursor-updater`目录进行相同操作。
+**Q: macOS 上的 Python3 错误**
+A: 使用 `brew install python3` 安装 Python3
-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
-```
-
+1. **完全关闭 Cursor**
+2. **删除账户** 从 Cursor 网站(设置 → 高级 → 删除账户)
+3. **运行我们的重置工具**
+4. **注册新账户**
+5. **重启 Cursor**
-
-安全特性
+---
-- ✅ 安全的进程终止
-- ✅ 原子文件操作
-- ✅ 错误处理和恢复
-
+## 💡 专业提示
-
-重置 Cursor 免费试用
+- 🌐 **网络优化:** 使用低延迟节点(日本、新加坡、美国、香港)
+- 🕐 **时机选择:** 在非高峰时段尝试访问 Claude 3.7
+- 🔄 **浏览器切换:** 如果账户问题持续,尝试不同浏览器
+- 📱 **IP 刷新:** 如可能考虑刷新您的 IP
+- 🧹 **DNS 缓存:** Windows 用户可运行 `ipconfig /flushdns`
-### 使用 `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
-```
+- [Cursor 异常问题收集和解决方案](https://mp.weixin.qq.com/s/pnJrH7Ifx4WZvseeP1fcEA)
+- [AI 通用开发助手提示词指南](https://mp.weixin.qq.com/s/PRPz-qVkFJSgkuEKkTdzwg)
-#### 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
-```
+- 🐛 **错误报告:** 在 GitHub 上开启 issue
+- 💡 **功能请求:** 分享您的想法
+- ⭐ **成功案例:** 告诉我们它如何帮助了您
+- 🔧 **技术反馈:** 欢迎性能见解
-
+---
-## 联系方式
+## ☕ 支持项目
-
----
-
-### 📚 推荐阅读
-- [Cursor 异常问题收集和解决方案](https://mp.weixin.qq.com/s/pnJrH7Ifx4WZvseeP1fcEA)
-- [AI 通用开发助手提示词指南](https://mp.weixin.qq.com/s/PRPz-qVkFJSgkuEKkTdzwg)
-
----
-
-## 💬 反馈与建议
-
-我们非常重视您对新增强脚本的反馈!如果您已经尝试了 `cursor_win_id_modifier_new.ps1` 脚本,请分享您的使用体验:
-
-- 🐛 **错误报告**:发现任何问题?请告诉我们!
-- 💡 **功能建议**:有改进想法?
-- ⭐ **成功案例**:分享工具如何帮助到您!
-- 🔧 **技术反馈**:性能、兼容性或易用性方面的见解
-
-您的反馈帮助我们为所有人改进工具。欢迎提交issue或为项目做出贡献!
+
---
-## ⭐ 项目统计
+## 📊 项目统计
@@ -515,12 +379,17 @@ irm https://raw.githubusercontent.com/yuaotian/go-cursor-help/refs/heads/master/
+---
+
## 📄 许可证
MIT 许可证
-Copyright (c) 2024
+```
+MIT License
+
+Copyright (c) 2025
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@@ -532,4 +401,23 @@ 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.
+```
+
+
+---
+
+
+
+**⭐ 如果这个项目帮到了您,请给个 Star! ⭐**
+
+**用 ❤️ 为 Cursor 社区制作**
+
+
\ No newline at end of file
diff --git a/README_JP.md b/README_JP.md
index 15e4416..d72f001 100644
--- a/README_JP.md
+++ b/README_JP.md
@@ -10,554 +10,356 @@
-
-
-
-
-> ⚠️ **重要なお知らせ**
->
-> このツールは現在以下のバージョンをサポートしています:
-> - ✅ Windows: 最新の1.0.xバージョン(サポート済み)
-> - ✅ Mac/Linux: 最新の1.0.xバージョン(サポート済み、フィードバック歓迎)
->
-> このツールを使用する前に、Cursorのバージョンを確認してください。
-
-
-📦 バージョン履歴とダウンロード
-
-
-
-### 🌟 最新バージョン
-
-[完全なバージョン履歴を見る]([CursorHistoryDown.md](https://github.com/oslook/cursor-ai-downloads?tab=readme-ov-file))
-
-
-
-⚠️ **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アドレスをバックアップします
-> - この変更により一時的にネットワーク接続が影響を受ける可能性があります
-> - 実行中にこのステップをスキップすることができます
->
-
-
-🔒 自動更新機能の無効化
-
-> Cursorがサポートされていない新しいバージョンに自動的に更新されるのを防ぐために、自動更新機能を無効にすることができます。
-
-#### 方法1: 組み込みスクリプトを使用する(推奨)
-
-リセットツールを実行するとき、スクリプトは自動更新を無効にするかどうかを尋ねます:
-```text
-[質問] Cursorの自動更新機能を無効にしますか?
-0) いいえ - デフォルト設定を維持(Enterキーを押す)
-1) はい - 自動更新を無効にする
-```
-
-`1`を選択して無効化操作を自動的に完了します。
+## 🎯 ツールの機能
-#### 方法2: 手動で無効化
+**Cursor 無料試用リセットツール** は、デバイス識別子を変更することで Cursor AI エディターの試用期間をリセットします。煩わしい試用制限メッセージが表示されたとき、このツールで新たなスタートを切ることができます!
-**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
-```
+
+🔴 "Too many free trial accounts used on this machine"
-**Linux:**
-```bash
-# Cursorを閉じます
-pkill -f "Cursor"
-# 更新ディレクトリを削除し、ブロックファイルを作成します
-rm -rf ~/.config/cursor-updater
-touch ~/.config/cursor-updater
```
-
-> ⚠️ **注意:** 自動更新を無効にした後、新しいバージョンを手動でダウンロードしてインストールする必要があります。新しいバージョンが互換性があることを確認した後に更新することをお勧めします。
-
-
-
----
-
-### 📝 説明
-
-> これらのメッセージのいずれかに遭遇した場合:
-
-#### 問題1: 試用アカウント制限 
-
-```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キー制限 
+**✅ 解決策:** 私たちのツールを使用してマシンのデバイス識別子をリセット!
-```text
-[New Issue]
+
+
+
+🟡 "Composer relies on custom models..."
+```
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無料試用期間中に使用制限に達したことを示しています:
+**✅ 解決策:**
+1. [Geek アンインストーラー](https://geekuninstaller.com/download) を使用して Cursor を完全にアンインストール
+2. Cursor を再インストール
+3. 私たちのリセットツールを実行
-```text
-You've reached your trial request limit.
-```
+
-#### 問題4: Claude 3.7 高負荷 
+
+🟣 Claude 3.7 "High Load" 高負荷
-```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.
+```
+We're experiencing high demand for Claude 3.7 Sonnet right now.
+Please upgrade to Pro, or switch to the 'default' model...
```
-
-
-
-
-#### 解決策 : Cursorを完全にアンインストールして再インストールする(APIキーの問題)
-
-1. [Geek.exeアンインストーラー[無料]](https://geekuninstaller.com/download)をダウンロードします
-2. Cursorアプリを完全にアンインストールします
-3. Cursorアプリを再インストールします
-4. 解決策1を続行します
-
-
-
-
-
-> 一時的な解決策:
-
-#### 解決策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モデルの使用を制限していることを示しています。次のことを試してください:
+**✅ 解決策:** 試用期間をリセットし、オフピーク時間(午前5-10時または午後3-7時)に試行
-1. Gmailで作成した新しいアカウントに切り替えます。異なるIPアドレスを使用して接続することをお勧めします
-2. 非ピーク時間帯にアクセスを試みます(通常、5-10 AMまたは3-7 PMの間に制限が少ないです)
-3. Proにアップグレードしてアクセスを保証します
-4. Claude 3.5 Sonnetを代替オプションとして使用します
+
-> 注意: Cursorがリソース配分ポリシーを調整するにつれて、これらのアクセスパターンは変更される可能性があります。
+---
-### 💻 システムサポート
+## 🖥️ プラットフォームサポート
-
+
-
-
-**Windows** ✅
+ |
-- x64 (64ビット)
-- x86 (32ビット)
+### 🐧 **Linux**
+✅ 全ディストリビューション
+✅ x64, x86, ARM64
+✅ 自動検出
|
-
-
-**macOS** ✅
+ |
-- Intel (x64)
-- Apple Silicon (M1/M2)
+### 🍎 **macOS**
+✅ Intel & Apple Silicon
+✅ 権限自動修復
+✅ Python3 統合
|
-
-
-**Linux** ✅
+ |
-- x64 (64ビット)
-- x86 (32ビット)
-- ARM64
+### 🪟 **Windows**
+✅ x64, x86, ARM64
+✅ レジストリ変更
+✅ PowerShell 7 対応
|
+---
+## ⚡ クイックスタート(ワンクリックソリューション)
-### 🚀 ワンクリックソリューション
+### 🌍 グローバルユーザー
-グローバルユーザー
-
-**macOS**
+🐧 Linux
```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
+curl -fsSL https://raw.githubusercontent.com/yuaotian/go-cursor-help/refs/heads/master/scripts/run/cursor_linux_id_modifier.sh | sudo bash
```
-**Linux**
+
+
+
+🍎 macOS
```bash
-curl -fsSL https://raw.githubusercontent.com/yuaotian/go-cursor-help/refs/heads/master/scripts/run/cursor_linux_id_modifier.sh | sudo 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
```
-**Windows**
+
-```powershell
-irm https://raw.githubusercontent.com/yuaotian/go-cursor-help/refs/heads/master/scripts/run/cursor_win_id_modifier.ps1 | iex
-```
+
+🪟 Windows
-**Windows (強化版)**
+**PowerShell を管理者として実行:**
```powershell
-irm https://raw.githubusercontent.com/yuaotian/go-cursor-help/refs/heads/master/scripts/run/cursor_win_id_modifier_new.ps1 | iex
+irm https://raw.githubusercontent.com/yuaotian/go-cursor-help/refs/heads/master/scripts/run/cursor_win_id_modifier.ps1 | iex
```
-> デュアルモード操作とトライアルリセット機能を備えた強化版Cursorマシンコード修正ツール
-
-
-

-
-
-中国ユーザー(推奨)
+### 🇨🇳 中国ユーザー(高速化)
-**macOS**
+
+🐧 Linux
```bash
-curl -fsSL https://aizaozao.com/accelerate.php/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
+curl -fsSL https://aizaozao.com/accelerate.php/https://raw.githubusercontent.com/yuaotian/go-cursor-help/refs/heads/master/scripts/run/cursor_linux_id_modifier.sh | sudo bash
```
-**Linux**
+
+
+
+🍎 macOS
```bash
-curl -fsSL https://aizaozao.com/accelerate.php/https://raw.githubusercontent.com/yuaotian/go-cursor-help/refs/heads/master/scripts/run/cursor_linux_id_modifier.sh | sudo bash
+curl -fsSL https://aizaozao.com/accelerate.php/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ユーザーへの注意:** スクリプトは、一般的なパス(`/usr/bin`, `/usr/local/bin`, `$HOME/.local/bin`, `/opt/cursor`, `/snap/bin`)の確認、`which cursor` コマンドの使用、および `/usr`、`/opt`、`$HOME/.local` ディレクトリ内の検索によって、Cursor のインストールを見つけようとします。Cursorが他の場所にインストールされているか、これらの方法で見つからない場合、スクリプトは失敗する可能性があります。これらの標準的な場所または方法のいずれかを通じてCursorにアクセスできることを確認してください。
+
-**Windows**
+
+🪟 Windows
```powershell
irm https://aizaozao.com/accelerate.php/https://raw.githubusercontent.com/yuaotian/go-cursor-help/refs/heads/master/scripts/run/cursor_win_id_modifier.ps1 | iex
```
-**Windows (強化版)**
+
-```powershell
-irm https://aizaozao.com/accelerate.php/https://raw.githubusercontent.com/yuaotian/go-cursor-help/refs/heads/master/scripts/run/cursor_win_id_modifier_new.ps1 | iex
-```
-> デュアルモード操作とトライアルリセット機能を備えた強化版Cursorマシンコード修正ツール
+---
-
+## 🛠️ 管理者として実行する方法
-
-Windowsターミナルの実行と構成
-
-#### Windowsで管理者ターミナルを開く方法:
-
-##### 方法1: Win + Xショートカットを使用する
-```md
-1. Win + Xキーの組み合わせを押します
-2. メニューから次のオプションのいずれかを選択します:
- - "Windows PowerShell (管理者)"
- - "Windows Terminal (管理者)"
- - "ターミナル (管理者)"
- (Windowsのバージョンによってオプションが異なる場合があります)
-```
+### 🪟 Windows の方法
-##### 方法2: Win + R実行コマンドを使用する
-```md
-1. Win + Rキーの組み合わせを押します
-2. 実行ダイアログにpowershellまたはpwshと入力します
-3. Ctrl + Shift + Enterを押して管理者として実行します
- または開いたウィンドウに次のように入力します: Start-Process pwsh -Verb RunAs
-4. 管理者ターミナルにリセットスクリプトを入力します:
+
+方法1: Win + X ショートカット
-irm https://aizaozao.com/accelerate.php/https://raw.githubusercontent.com/yuaotian/go-cursor-help/refs/heads/master/scripts/run/cursor_win_id_modifier.ps1 | iex
-```
+1. `Win + X` を押す
+2. "Windows PowerShell (管理者)" または "ターミナル (管理者)" を選択
+3. 上記のコマンドを貼り付け
-強化版スクリプト:
-```powershell
-irm https://aizaozao.com/accelerate.php/https://raw.githubusercontent.com/yuaotian/go-cursor-help/refs/heads/master/scripts/run/cursor_win_id_modifier_new.ps1 | iex
-```
+
-##### 方法3: 検索を使用する
->
->
->検索ボックスにpwshと入力し、右クリックして「管理者として実行」を選択します
->
+
+方法2: 検索方法
-管理者ターミナルにリセットスクリプトを入力します:
-```powershell
-irm https://aizaozao.com/accelerate.php/https://raw.githubusercontent.com/yuaotian/go-cursor-help/refs/heads/master/scripts/run/cursor_win_id_modifier.ps1 | iex
-```
+1. スタートメニューで "PowerShell" を検索
+2. 右クリック → "管理者として実行"
+3. コマンドを貼り付け
-強化版スクリプト:
-```powershell
-irm https://aizaozao.com/accelerate.php/https://raw.githubusercontent.com/yuaotian/go-cursor-help/refs/heads/master/scripts/run/cursor_win_id_modifier_new.ps1 | iex
-```
+
+
+
+
-### 🔧 PowerShellインストールガイド
+
+方法3: Win + R
+
+1. `Win + R` を押す
+2. `powershell` と入力
+3. `Ctrl + Shift + Enter` を押す
-システムにPowerShellがインストールされていない場合は、次の方法でインストールできます:
+
-#### 方法1: Wingetを使用してインストール(推奨)
+### 🔧 PowerShell インストール(必要な場合)
-1. コマンドプロンプトまたはPowerShellを開きます
-2. 次のコマンドを実行します:
+**オプション1: Winget を使用**
```powershell
winget install --id Microsoft.PowerShell --source winget
```
-#### 方法2: 手動でインストール
+**オプション2: 手動ダウンロード**
+- [PowerShell 7.4.6 x64](https://github.com/PowerShell/PowerShell/releases/download/v7.4.6/PowerShell-7.4.6-win-x64.msi)
+- [PowerShell 7.4.6 x86](https://github.com/PowerShell/PowerShell/releases/download/v7.4.6/PowerShell-7.4.6-win-x86.msi)
+- [PowerShell 7.4.6 ARM64](https://github.com/PowerShell/PowerShell/releases/download/v7.4.6/PowerShell-7.4.6-win-arm64.msi)
-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)を参照してください
+### 🔒 自動更新の無効化
-
+スクリプトは Cursor の自動更新機能を自動的に無効にしてバージョン競合を防ぎます:
-#### Windowsインストール機能:
+**Windows:** `%LOCALAPPDATA%\cursor-updater` にブロックファイルを作成
+**macOS:** `app-update.yml` を変更しブロックファイルを作成
+**Linux:** `~/.config/cursor-updater` にブロックファイルを作成
-- 🔍 PowerShell 7が利用可能な場合は自動的に検出して使用します
-- 🛡️ UACプロンプトを介して管理者権限を要求します
-- 📝 PS7が見つからない場合はWindows PowerShellにフォールバックします
-- 💡 権限昇格に失敗した場合は手動の指示を提供します
+### 🛡️ 安全機能
-これで完了です!スクリプトは次のことを行います:
+- ✅ **自動バックアップ** - 変更前に全ての元ファイルを自動バックアップ
+- ✅ **プロセス管理** - Cursor プロセスを安全に停止・再起動
+- ✅ **権限処理** - ファイル権限を自動修復(macOS)
+- ✅ **エラー回復** - 問題発生時に自動でバックアップを復元
+- ✅ **マルチメソッド対応** - 最大互換性のため複数の技術を使用
-1. ✨ ツールを自動的にインストールします
-2. 🔄 Cursorの試用期間を即座にリセットします
+### 🔍 変更内容
-### 📦 手動インストール
+
+設定ファイル
-> [リリース](https://github.com/yuaotian/go-cursor-help/releases/latest)からシステムに適したファイルをダウンロードします
+**場所:**
+- Windows: `%APPDATA%\Cursor\User\globalStorage\storage.json`
+- macOS: `~/Library/Application Support/Cursor/User/globalStorage/storage.json`
+- Linux: `~/.config/Cursor/User/globalStorage/storage.json`
-
-Windowsパッケージ
+**変更フィールド:**
+- `telemetry.machineId`
+- `telemetry.macMachineId`
+- `telemetry.devDeviceId`
+- `telemetry.sqmId`
-- 64ビット: `cursor-id-modifier_windows_x64.exe`
-- 32ビット: `cursor-id-modifier_windows_x86.exe`
-macOSパッケージ
+JavaScript ファイル(高度)
+
+ツールは Cursor の JavaScript ファイルにコードを注入してデバイス ID 関数を上書きします:
+- `extensionHostProcess.js`
+- `main.js`
+- `cliProcessMain.js`
-- Intel: `cursor-id-modifier_darwin_x64_intel`
-- M1/M2: `cursor-id-modifier_darwin_arm64_apple_silicon`
-Linuxパッケージ
+Windows レジストリ(Windows のみ)
+
+**変更レジストリ:**
+- パス: `HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography`
+- キー: `MachineGuid`
+
+**⚠️ 重要:** 元の値は `%APPDATA%\Cursor\User\globalStorage\backups` に自動バックアップされます
-- 64ビット: `cursor-id-modifier_linux_x64`
-- 32ビット: `cursor-id-modifier_linux_x86`
-- ARM64: `cursor-id-modifier_linux_arm64`
-### 🔧 技術的詳細
+---
-
-構成ファイル
+## 🎉 成功スクリーンショット
-プログラムは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`
-
+---
-
-変更されたフィールド
+## 🆘 トラブルシューティング
-ツールは次の新しい一意の識別子を生成します:
+### ❓ よくある問題
-- `telemetry.machineId`
-- `telemetry.macMachineId`
-- `telemetry.devDeviceId`
-- `telemetry.sqmId`
-
+**Q: スクリプトが "Permission denied" と表示される**
+A: `sudo`(Linux/macOS)または管理者権限(Windows)で実行していることを確認
-
-手動自動更新無効化
+**Q: Cursor がまだ試用制限を表示する**
+A: フルリセットオプションを試し、Cursor を完全に再起動
-Windowsユーザーは自動更新機能を手動で無効にすることができます:
+**Q: スクリプトが Cursor インストールを見つけられない**
+A: Cursor が標準的な場所にインストールされているか、[cursor.sh](https://cursor.sh/) からインストールしているか確認
-1. すべてのCursorプロセスを閉じます
-2. ディレクトリを削除します: `C:\Users\username\AppData\Local\cursor-updater`
-3. 同じ名前のファイルを作成します: `cursor-updater`(拡張子なし)
+**Q: macOS で Python3 エラー**
+A: `brew install python3` で Python3 をインストール
-macOS/Linuxユーザーはシステム内で同様の`cursor-updater`ディレクトリを見つけて同じ操作を行うことができます。
+### 🔄 一般的な解決手順
-
+1. **Cursor を完全に閉じる**
+2. **アカウントを削除** Cursor ウェブサイトから(設定 → 高度 → アカウント削除)
+3. **リセットツールを実行**
+4. **新しいアカウントを登録**
+5. **Cursor を再起動**
-
-安全機能
+---
-- ✅ 安全なプロセス終了
-- ✅ アトミックファイル操作
-- ✅ エラーハンドリングとリカバリ
-
+## 💡 プロのヒント
-
-レジストリ変更通知
+- 🌐 **ネットワーク最適化:** 低遅延ノードを使用(日本、シンガポール、米国、香港)
+- 🕐 **タイミング:** オフピーク時間に Claude 3.7 にアクセスを試行
+- 🔄 **ブラウザ切り替え:** アカウント問題が続く場合は異なるブラウザを試行
+- 📱 **IP リフレッシュ:** 可能であれば IP をリフレッシュすることを検討
+- 🧹 **DNS キャッシュ:** Windows ユーザーは `ipconfig /flushdns` を実行可能
-> ⚠️ **重要: このツールは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`を右クリックします
- - 「修正」を選択します
- - バックアップファイルの値を貼り付けます
-
-#### 重要な注意事項
-- 変更前にバックアップファイルの存在を確認します
-- 必要に応じてバックアップファイルを使用して元の値を復元します
-- レジストリの変更には管理者権限が必要です
-
+- [Cursor 問題収集と解決策](https://mp.weixin.qq.com/s/pnJrH7Ifx4WZvseeP1fcEA)
+- [AI 開発アシスタントガイド](https://mp.weixin.qq.com/s/PRPz-qVkFJSgkuEKkTdzwg)
---
-### 📚 推奨読書
+## 💬 フィードバック&サポート
+
+役に立ちましたか?ぜひお聞かせください!
-- [Cursorの問題収集と解決策](https://mp.weixin.qq.com/s/pnJrH7Ifx4WZvseeP1fcEA)
-- [AIユニバーサル開発アシスタントプロンプトガイド](https://mp.weixin.qq.com/s/PRPz-qVkFJSgkuEKkTdzwg)
+- 🐛 **バグレポート:** GitHub で issue を開く
+- 💡 **機能リクエスト:** アイデアを共有
+- ⭐ **成功事例:** どのように役立ったかお教えください
+- 🔧 **技術フィードバック:** パフォーマンスの洞察を歓迎
---
-## サポート
+## ☕ プロジェクトをサポート
-
----
-## 💬 フィードバック&提案
-
-新しい強化スクリプトに関するフィードバックをお待ちしています!`cursor_win_id_modifier_new.ps1` スクリプトをお試しいただいた方は、ぜひご体験をお聞かせください:
-
-- 🐛 **バグレポート**:問題を発見されましたか?お知らせください!
-- 💡 **機能提案**:改善のアイデアはありますか?
-- ⭐ **成功事例**:ツールがどのようにお役に立ったかお聞かせください!
-- 🔧 **技術的フィードバック**:パフォーマンス、互換性、使いやすさに関するご意見
-
-皆様のフィードバックは、すべてのユーザーのためにツールを改善するのに役立ちます。お気軽にissueを開いたり、プロジェクトに貢献してください!
+
---
-## ⭐ プロジェクト統計
+## 📊 プロジェクト統計
@@ -567,12 +369,17 @@ ETC: 0xa2745f4CD5d32310AC01694ABDB28bA32D125a6b
+---
+
## 📄 ライセンス
-MITライセンス
+MIT ライセンス
-Copyright (c) 2024
+```
+MIT License
+
+Copyright (c) 2025
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@@ -584,4 +391,23 @@ 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.
+```
+
+
+---
+
+
+
+**⭐ このプロジェクトが役に立ったら Star をください! ⭐**
+
+**Cursor コミュニティのために ❤️ で作成**
+
+
\ No newline at end of file
diff --git a/cmd/cursor-id-modifier/main.go b/cmd/cursor-id-modifier/main.go
deleted file mode 100644
index 4ff9e0e..0000000
--- a/cmd/cursor-id-modifier/main.go
+++ /dev/null
@@ -1,328 +0,0 @@
-package main
-
-import (
- "bufio"
- "flag"
- "fmt"
- "os"
- "os/exec"
- "os/user"
- "runtime"
- "runtime/debug"
- "strings"
-
- "github.com/sirupsen/logrus"
-
- "github.com/yuaotian/go-cursor-help/internal/config"
- "github.com/yuaotian/go-cursor-help/internal/lang"
- "github.com/yuaotian/go-cursor-help/internal/process"
- "github.com/yuaotian/go-cursor-help/internal/ui"
- "github.com/yuaotian/go-cursor-help/pkg/idgen"
-)
-
-// Global variables
-var (
- version = "dev"
- setReadOnly = flag.Bool("r", false, "set storage.json to read-only mode")
- showVersion = flag.Bool("v", false, "show version information")
- log = logrus.New()
-)
-
-func main() {
- // Place defer at the beginning of main to ensure it can catch panics from all subsequent function calls
- defer func() {
- if r := recover(); r != nil {
- log.Errorf("Panic recovered: %v\n", r)
- debug.PrintStack()
- waitExit()
- }
- }()
-
- handleFlags()
- setupLogger()
-
- username := getCurrentUser()
- log.Debug("Running as user:", username)
-
- // Initialize components
- display := ui.NewDisplay(nil)
- configManager := initConfigManager(username)
- generator := idgen.NewGenerator()
- processManager := process.NewManager(nil, log)
-
- // Check and handle privileges
- if err := handlePrivileges(display); err != nil {
- return
- }
-
- // Setup display
- setupDisplay(display)
-
- text := lang.GetText()
-
- // Handle Cursor processes
- if err := handleCursorProcesses(display, processManager); err != nil {
- return
- }
-
- // Handle configuration
- oldConfig := readExistingConfig(display, configManager, text)
- newConfig := generateNewConfig(display, generator, oldConfig, text)
-
- if err := saveConfiguration(display, configManager, newConfig); err != nil {
- return
- }
-
- // Show completion messages
- showCompletionMessages(display)
-
- if os.Getenv("AUTOMATED_MODE") != "1" {
- waitExit()
- }
-}
-
-func handleFlags() {
- flag.Parse()
- if *showVersion {
- fmt.Printf("Cursor ID Modifier v%s\n", version)
- os.Exit(0)
- }
-}
-
-func setupLogger() {
- log.SetFormatter(&logrus.TextFormatter{
- FullTimestamp: true,
- DisableLevelTruncation: true,
- PadLevelText: true,
- })
- log.SetLevel(logrus.InfoLevel)
-}
-
-func getCurrentUser() string {
- if username := os.Getenv("SUDO_USER"); username != "" {
- return username
- }
-
- user, err := user.Current()
- if err != nil {
- log.Fatal(err)
- }
- return user.Username
-}
-
-func initConfigManager(username string) *config.Manager {
- configManager, err := config.NewManager(username)
- if err != nil {
- log.Fatal(err)
- }
- return configManager
-}
-
-func handlePrivileges(display *ui.Display) error {
- isAdmin, err := checkAdminPrivileges()
- if err != nil {
- log.Error(err)
- waitExit()
- return err
- }
-
- if !isAdmin {
- if runtime.GOOS == "windows" {
- return handleWindowsPrivileges(display)
- }
- display.ShowPrivilegeError(
- lang.GetText().PrivilegeError,
- lang.GetText().RunWithSudo,
- lang.GetText().SudoExample,
- )
- waitExit()
- return fmt.Errorf("insufficient privileges")
- }
- return nil
-}
-
-func handleWindowsPrivileges(display *ui.Display) error {
- message := "\nRequesting administrator privileges..."
- if lang.GetCurrentLanguage() == lang.CN {
- message = "\n请求管理员权限..."
- }
- fmt.Println(message)
-
- if err := selfElevate(); err != nil {
- log.Error(err)
- display.ShowPrivilegeError(
- lang.GetText().PrivilegeError,
- lang.GetText().RunAsAdmin,
- lang.GetText().RunWithSudo,
- lang.GetText().SudoExample,
- )
- waitExit()
- return err
- }
- return nil
-}
-
-func setupDisplay(display *ui.Display) {
- if err := display.ClearScreen(); err != nil {
- log.Warn("Failed to clear screen:", err)
- }
- display.ShowLogo()
- fmt.Println()
-}
-
-func handleCursorProcesses(display *ui.Display, processManager *process.Manager) error {
- if os.Getenv("AUTOMATED_MODE") == "1" {
- log.Debug("Running in automated mode, skipping Cursor process closing")
- return nil
- }
-
- display.ShowProgress("Closing Cursor...")
- log.Debug("Attempting to close Cursor processes")
-
- if err := processManager.KillCursorProcesses(); err != nil {
- log.Error("Failed to close Cursor:", err)
- display.StopProgress()
- display.ShowError("Failed to close Cursor. Please close it manually and try again.")
- waitExit()
- return err
- }
-
- if processManager.IsCursorRunning() {
- log.Error("Cursor processes still detected after closing")
- display.StopProgress()
- display.ShowError("Failed to close Cursor completely. Please close it manually and try again.")
- waitExit()
- return fmt.Errorf("cursor still running")
- }
-
- log.Debug("Successfully closed all Cursor processes")
- display.StopProgress()
- fmt.Println()
- return nil
-}
-
-func readExistingConfig(display *ui.Display, configManager *config.Manager, text lang.TextResource) *config.StorageConfig {
- fmt.Println()
- display.ShowProgress(text.ReadingConfig)
- oldConfig, err := configManager.ReadConfig()
- if err != nil {
- log.Warn("Failed to read existing config:", err)
- oldConfig = nil
- }
- display.StopProgress()
- fmt.Println()
- return oldConfig
-}
-
-func generateNewConfig(display *ui.Display, generator *idgen.Generator, oldConfig *config.StorageConfig, text lang.TextResource) *config.StorageConfig {
- display.ShowProgress(text.GeneratingIds)
- newConfig := &config.StorageConfig{}
-
- if machineID, err := generator.GenerateMachineID(); err != nil {
- log.Fatal("Failed to generate machine ID:", err)
- } else {
- newConfig.TelemetryMachineId = machineID
- }
-
- if macMachineID, err := generator.GenerateMacMachineID(); err != nil {
- log.Fatal("Failed to generate MAC machine ID:", err)
- } else {
- newConfig.TelemetryMacMachineId = macMachineID
- }
-
- if deviceID, err := generator.GenerateDeviceID(); err != nil {
- log.Fatal("Failed to generate device ID:", err)
- } else {
- newConfig.TelemetryDevDeviceId = deviceID
- }
-
- if oldConfig != nil && oldConfig.TelemetrySqmId != "" {
- newConfig.TelemetrySqmId = oldConfig.TelemetrySqmId
- } else if sqmID, err := generator.GenerateSQMID(); err != nil {
- log.Fatal("Failed to generate SQM ID:", err)
- } else {
- newConfig.TelemetrySqmId = sqmID
- }
-
- display.StopProgress()
- fmt.Println()
- return newConfig
-}
-
-func saveConfiguration(display *ui.Display, configManager *config.Manager, newConfig *config.StorageConfig) error {
- display.ShowProgress("Saving configuration...")
- if err := configManager.SaveConfig(newConfig, *setReadOnly); err != nil {
- log.Error(err)
- waitExit()
- return err
- }
- display.StopProgress()
- fmt.Println()
- return nil
-}
-
-func showCompletionMessages(display *ui.Display) {
- display.ShowSuccess(lang.GetText().SuccessMessage, lang.GetText().RestartMessage)
- fmt.Println()
-
- message := "Operation completed!"
- if lang.GetCurrentLanguage() == lang.CN {
- message = "操作完成!"
- }
- display.ShowInfo(message)
-}
-
-func waitExit() {
- fmt.Print(lang.GetText().PressEnterToExit)
- os.Stdout.Sync()
- bufio.NewReader(os.Stdin).ReadString('\n')
-}
-
-func checkAdminPrivileges() (bool, error) {
- switch runtime.GOOS {
- case "windows":
- cmd := exec.Command("net", "session")
- return cmd.Run() == nil, nil
-
- case "darwin", "linux":
- currentUser, err := user.Current()
- if err != nil {
- return false, fmt.Errorf("failed to get current user: %w", err)
- }
- return currentUser.Uid == "0", nil
-
- default:
- return false, fmt.Errorf("unsupported operating system: %s", runtime.GOOS)
- }
-}
-
-func selfElevate() error {
- os.Setenv("AUTOMATED_MODE", "1")
-
- switch runtime.GOOS {
- case "windows":
- verb := "runas"
- exe, _ := os.Executable()
- cwd, _ := os.Getwd()
- args := strings.Join(os.Args[1:], " ")
-
- cmd := exec.Command("cmd", "/C", "start", verb, exe, args)
- cmd.Dir = cwd
- return cmd.Run()
-
- case "darwin", "linux":
- exe, err := os.Executable()
- if err != nil {
- return err
- }
-
- cmd := exec.Command("sudo", append([]string{exe}, os.Args[1:]...)...)
- cmd.Stdin = os.Stdin
- cmd.Stdout = os.Stdout
- cmd.Stderr = os.Stderr
- return cmd.Run()
-
- default:
- return fmt.Errorf("unsupported operating system: %s", runtime.GOOS)
- }
-}
diff --git a/go.mod b/go.mod
deleted file mode 100644
index 6bcebe3..0000000
--- a/go.mod
+++ /dev/null
@@ -1,15 +0,0 @@
-module github.com/yuaotian/go-cursor-help
-
-go 1.21
-
-require (
- github.com/fatih/color v1.15.0
- github.com/sirupsen/logrus v1.9.3
-)
-
-require (
- github.com/mattn/go-colorable v0.1.13 // indirect
- github.com/mattn/go-isatty v0.0.17 // indirect
- github.com/stretchr/testify v1.10.0 // indirect
- golang.org/x/sys v0.13.0 // indirect
-)
diff --git a/go.sum b/go.sum
deleted file mode 100644
index d930a66..0000000
--- a/go.sum
+++ /dev/null
@@ -1,26 +0,0 @@
-github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
-github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs=
-github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw=
-github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
-github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
-github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
-github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng=
-github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
-github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
-github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
-github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
-github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
-github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
-github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
-github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
-github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
-golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
-golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
-gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
-gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff --git a/img/qun-10.jpg b/img/qun-10.jpg
deleted file mode 100644
index 727e389..0000000
Binary files a/img/qun-10.jpg and /dev/null differ
diff --git a/img/qun-12.png b/img/qun-12.png
deleted file mode 100644
index ebfc610..0000000
Binary files a/img/qun-12.png and /dev/null differ
diff --git a/img/qun-14.jpg b/img/qun-14.jpg
deleted file mode 100644
index d139c25..0000000
Binary files a/img/qun-14.jpg and /dev/null differ
diff --git a/img/qun-8.png b/img/qun-8.png
deleted file mode 100644
index 33435ed..0000000
Binary files a/img/qun-8.png and /dev/null differ
diff --git a/img/qun11.jpg b/img/qun11.jpg
deleted file mode 100644
index 4cf169f..0000000
Binary files a/img/qun11.jpg and /dev/null differ
diff --git a/img/qun13.png b/img/qun13.png
deleted file mode 100644
index d30449d..0000000
Binary files a/img/qun13.png and /dev/null differ
diff --git a/img/qun9.png b/img/qun9.png
deleted file mode 100644
index 60499a8..0000000
Binary files a/img/qun9.png and /dev/null differ
diff --git a/img/wx_group.jpg b/img/wx_group.jpg
deleted file mode 100644
index 05e507f..0000000
Binary files a/img/wx_group.jpg and /dev/null differ
diff --git a/img/wx_group6.jpg b/img/wx_group6.jpg
deleted file mode 100644
index 0d907ba..0000000
Binary files a/img/wx_group6.jpg and /dev/null differ
diff --git a/img/wx_group7.jpg b/img/wx_group7.jpg
deleted file mode 100644
index 2a12f68..0000000
Binary files a/img/wx_group7.jpg and /dev/null differ
diff --git a/img/wx_public.jpg b/img/wx_public.jpg
deleted file mode 100644
index 2455fc5..0000000
Binary files a/img/wx_public.jpg and /dev/null differ
diff --git a/img/wx_zsm.jpg b/img/wx_zsm.jpg
deleted file mode 100644
index d4c9a45..0000000
Binary files a/img/wx_zsm.jpg and /dev/null differ
diff --git a/img/zanzhu/twillot.png b/img/zanzhu/twillot.png
deleted file mode 100644
index 459f601..0000000
Binary files a/img/zanzhu/twillot.png and /dev/null differ
diff --git a/internal/config/config.go b/internal/config/config.go
deleted file mode 100644
index 75b64df..0000000
--- a/internal/config/config.go
+++ /dev/null
@@ -1,153 +0,0 @@
-package config
-
-import (
- "encoding/json"
- "fmt"
- "os"
- "path/filepath"
- "runtime"
- "sync"
- "time"
-)
-
-// StorageConfig represents the storage configuration
-type StorageConfig struct {
- TelemetryMacMachineId string `json:"telemetry.macMachineId"`
- TelemetryMachineId string `json:"telemetry.machineId"`
- TelemetryDevDeviceId string `json:"telemetry.devDeviceId"`
- TelemetrySqmId string `json:"telemetry.sqmId"`
- LastModified string `json:"lastModified"`
- Version string `json:"version"`
-}
-
-// Manager handles configuration operations
-type Manager struct {
- configPath string
- mu sync.RWMutex
-}
-
-// NewManager creates a new configuration manager
-func NewManager(username string) (*Manager, error) {
- configPath, err := getConfigPath(username)
- if err != nil {
- return nil, fmt.Errorf("failed to get config path: %w", err)
- }
- return &Manager{configPath: configPath}, nil
-}
-
-// ReadConfig reads the existing configuration
-func (m *Manager) ReadConfig() (*StorageConfig, error) {
- m.mu.RLock()
- defer m.mu.RUnlock()
-
- data, err := os.ReadFile(m.configPath)
- if err != nil {
- if os.IsNotExist(err) {
- return nil, nil
- }
- return nil, fmt.Errorf("failed to read config file: %w", err)
- }
-
- var config StorageConfig
- if err := json.Unmarshal(data, &config); err != nil {
- return nil, fmt.Errorf("failed to parse config file: %w", err)
- }
-
- return &config, nil
-}
-
-// SaveConfig saves the configuration
-func (m *Manager) SaveConfig(config *StorageConfig, readOnly bool) error {
- m.mu.Lock()
- defer m.mu.Unlock()
-
- // Ensure parent directories exist
- if err := os.MkdirAll(filepath.Dir(m.configPath), 0755); err != nil {
- return fmt.Errorf("failed to create config directory: %w", err)
- }
-
- // Prepare updated configuration
- updatedConfig := m.prepareUpdatedConfig(config)
-
- // Write configuration
- if err := m.writeConfigFile(updatedConfig, readOnly); err != nil {
- return err
- }
-
- return nil
-}
-
-// prepareUpdatedConfig merges existing config with updates
-func (m *Manager) prepareUpdatedConfig(config *StorageConfig) map[string]interface{} {
- // Read existing config
- originalFile := make(map[string]interface{})
- if data, err := os.ReadFile(m.configPath); err == nil {
- json.Unmarshal(data, &originalFile)
- }
-
- // Update fields
- originalFile["telemetry.sqmId"] = config.TelemetrySqmId
- originalFile["telemetry.macMachineId"] = config.TelemetryMacMachineId
- originalFile["telemetry.machineId"] = config.TelemetryMachineId
- originalFile["telemetry.devDeviceId"] = config.TelemetryDevDeviceId
- originalFile["lastModified"] = time.Now().UTC().Format(time.RFC3339)
- // originalFile["version"] = "1.0.1"
-
- return originalFile
-}
-
-// writeConfigFile handles the atomic write of the config file
-func (m *Manager) writeConfigFile(config map[string]interface{}, readOnly bool) error {
- // Marshal with indentation
- content, err := json.MarshalIndent(config, "", " ")
- if err != nil {
- return fmt.Errorf("failed to marshal config: %w", err)
- }
-
- // Write to temporary file
- tmpPath := m.configPath + ".tmp"
- if err := os.WriteFile(tmpPath, content, 0666); err != nil {
- return fmt.Errorf("failed to write temporary file: %w", err)
- }
-
- // Set final permissions
- fileMode := os.FileMode(0666)
- if readOnly {
- fileMode = 0444
- }
-
- if err := os.Chmod(tmpPath, fileMode); err != nil {
- os.Remove(tmpPath)
- return fmt.Errorf("failed to set temporary file permissions: %w", err)
- }
-
- // Atomic rename
- if err := os.Rename(tmpPath, m.configPath); err != nil {
- os.Remove(tmpPath)
- return fmt.Errorf("failed to rename file: %w", err)
- }
-
- // Sync directory
- if dir, err := os.Open(filepath.Dir(m.configPath)); err == nil {
- defer dir.Close()
- dir.Sync()
- }
-
- return nil
-}
-
-// getConfigPath returns the path to the configuration file
-func getConfigPath(username string) (string, error) {
- var configDir string
- switch runtime.GOOS {
- case "windows":
- configDir = filepath.Join(os.Getenv("APPDATA"), "Cursor", "User", "globalStorage")
- case "darwin":
- configDir = filepath.Join("/Users", username, "Library", "Application Support", "Cursor", "User", "globalStorage")
- case "linux":
- configDir = filepath.Join("/home", username, ".config", "Cursor", "User", "globalStorage")
- default:
- return "", fmt.Errorf("unsupported operating system: %s", runtime.GOOS)
- }
- return filepath.Join(configDir, "storage.json"), nil
-}
diff --git a/internal/lang/lang.go b/internal/lang/lang.go
deleted file mode 100644
index 973fc24..0000000
--- a/internal/lang/lang.go
+++ /dev/null
@@ -1,187 +0,0 @@
-package lang
-
-import (
- "os"
- "os/exec"
- "strings"
- "sync"
-)
-
-// Language represents a supported language code
-type Language string
-
-const (
- // CN represents Chinese language
- CN Language = "cn"
- // EN represents English language
- EN Language = "en"
-)
-
-// TextResource contains all translatable text resources
-type TextResource struct {
- // Success messages
- SuccessMessage string
- RestartMessage string
-
- // Progress messages
- ReadingConfig string
- GeneratingIds string
- CheckingProcesses string
- ClosingProcesses string
- ProcessesClosed string
- PleaseWait string
-
- // Error messages
- ErrorPrefix string
- PrivilegeError string
-
- // Instructions
- RunAsAdmin string
- RunWithSudo string
- SudoExample string
- PressEnterToExit string
- SetReadOnlyMessage string
-
- // Info messages
- ConfigLocation string
-}
-
-var (
- currentLanguage Language
- currentLanguageOnce sync.Once
- languageMutex sync.RWMutex
-)
-
-// GetCurrentLanguage returns the current language, detecting it if not already set
-func GetCurrentLanguage() Language {
- currentLanguageOnce.Do(func() {
- currentLanguage = detectLanguage()
- })
-
- languageMutex.RLock()
- defer languageMutex.RUnlock()
- return currentLanguage
-}
-
-// SetLanguage sets the current language
-func SetLanguage(lang Language) {
- languageMutex.Lock()
- defer languageMutex.Unlock()
- currentLanguage = lang
-}
-
-// GetText returns the TextResource for the current language
-func GetText() TextResource {
- return texts[GetCurrentLanguage()]
-}
-
-// detectLanguage detects the system language
-func detectLanguage() Language {
- // Check environment variables first
- if isChineseEnvVar() {
- return CN
- }
-
- // Then check OS-specific locale
- if isWindows() {
- if isWindowsChineseLocale() {
- return CN
- }
- } else if isUnixChineseLocale() {
- return CN
- }
-
- return EN
-}
-
-func isChineseEnvVar() bool {
- for _, envVar := range []string{"LANG", "LANGUAGE", "LC_ALL"} {
- if lang := os.Getenv(envVar); lang != "" && strings.Contains(strings.ToLower(lang), "zh") {
- return true
- }
- }
- return false
-}
-
-func isWindows() bool {
- return os.Getenv("OS") == "Windows_NT"
-}
-
-func isWindowsChineseLocale() bool {
- // Check Windows UI culture
- cmd := exec.Command("powershell", "-Command",
- "[System.Globalization.CultureInfo]::CurrentUICulture.Name")
- output, err := cmd.Output()
- if err == nil && strings.HasPrefix(strings.ToLower(strings.TrimSpace(string(output))), "zh") {
- return true
- }
-
- // Check Windows locale
- cmd = exec.Command("wmic", "os", "get", "locale")
- output, err = cmd.Output()
- return err == nil && strings.Contains(string(output), "2052")
-}
-
-func isUnixChineseLocale() bool {
- cmd := exec.Command("locale")
- output, err := cmd.Output()
- return err == nil && strings.Contains(strings.ToLower(string(output)), "zh_cn")
-}
-
-// texts contains all translations
-var texts = map[Language]TextResource{
- CN: {
- // Success messages
- SuccessMessage: "[√] 配置文件已成功更新!",
- RestartMessage: "[!] 请手动重启 Cursor 以使更新生效",
-
- // Progress messages
- ReadingConfig: "正在读取配置文件...",
- GeneratingIds: "正在生成新的标识符...",
- CheckingProcesses: "正在检查运行中的 Cursor 实例...",
- ClosingProcesses: "正在关闭 Cursor 实例...",
- ProcessesClosed: "所有 Cursor 实例已关闭",
- PleaseWait: "请稍候...",
-
- // Error messages
- ErrorPrefix: "程序发生严重错误: %v",
- PrivilegeError: "\n[!] 错误:需要管理员权限",
-
- // Instructions
- RunAsAdmin: "请右键点击程序,选择「以管理员身份运行」",
- RunWithSudo: "请使用 sudo 命令运行此程序",
- SudoExample: "示例: sudo %s",
- PressEnterToExit: "\n按回车键退出程序...",
- SetReadOnlyMessage: "设置 storage.json 为只读模式, 这将导致 workspace 记录信息丢失等问题",
-
- // Info messages
- ConfigLocation: "配置文件位置:",
- },
- EN: {
- // Success messages
- SuccessMessage: "[√] Configuration file updated successfully!",
- RestartMessage: "[!] Please restart Cursor manually for changes to take effect",
-
- // Progress messages
- ReadingConfig: "Reading configuration file...",
- GeneratingIds: "Generating new identifiers...",
- CheckingProcesses: "Checking for running Cursor instances...",
- ClosingProcesses: "Closing Cursor instances...",
- ProcessesClosed: "All Cursor instances have been closed",
- PleaseWait: "Please wait...",
-
- // Error messages
- ErrorPrefix: "Program encountered a serious error: %v",
- PrivilegeError: "\n[!] Error: Administrator privileges required",
-
- // Instructions
- RunAsAdmin: "Please right-click and select 'Run as Administrator'",
- RunWithSudo: "Please run this program with sudo",
- SudoExample: "Example: sudo %s",
- PressEnterToExit: "\nPress Enter to exit...",
- SetReadOnlyMessage: "Set storage.json to read-only mode, which will cause issues such as lost workspace records",
-
- // Info messages
- ConfigLocation: "Config file location:",
- },
-}
diff --git a/internal/process/manager.go b/internal/process/manager.go
deleted file mode 100644
index f48ac20..0000000
--- a/internal/process/manager.go
+++ /dev/null
@@ -1,216 +0,0 @@
-package process
-
-import (
- "fmt"
- "os/exec"
- "runtime"
- "strings"
- "time"
-
- "github.com/sirupsen/logrus"
-)
-
-// Config holds process manager configuration
-type Config struct {
- MaxAttempts int // Maximum number of attempts to kill processes
- RetryDelay time.Duration // Delay between retry attempts
- ProcessPatterns []string // Process names to look for
-}
-
-// DefaultConfig returns the default configuration
-func DefaultConfig() *Config {
- return &Config{
- MaxAttempts: 3,
- RetryDelay: 2 * time.Second,
- ProcessPatterns: []string{
- "Cursor.exe", // Windows executable
- "Cursor ", // Linux/macOS executable with space
- "cursor ", // Linux/macOS executable lowercase with space
- "cursor", // Linux/macOS executable lowercase
- "Cursor", // Linux/macOS executable
- "*cursor*", // Any process containing cursor
- "*Cursor*", // Any process containing Cursor
- },
- }
-}
-
-// Manager handles process-related operations
-type Manager struct {
- config *Config
- log *logrus.Logger
-}
-
-// NewManager creates a new process manager with optional config and logger
-func NewManager(config *Config, log *logrus.Logger) *Manager {
- if config == nil {
- config = DefaultConfig()
- }
- if log == nil {
- log = logrus.New()
- }
- return &Manager{
- config: config,
- log: log,
- }
-}
-
-// IsCursorRunning checks if any Cursor process is currently running
-func (m *Manager) IsCursorRunning() bool {
- processes, err := m.getCursorProcesses()
- if err != nil {
- m.log.Warn("Failed to get Cursor processes:", err)
- return false
- }
- return len(processes) > 0
-}
-
-// KillCursorProcesses attempts to kill all running Cursor processes
-func (m *Manager) KillCursorProcesses() error {
- for attempt := 1; attempt <= m.config.MaxAttempts; attempt++ {
- processes, err := m.getCursorProcesses()
- if err != nil {
- return fmt.Errorf("failed to get processes: %w", err)
- }
-
- if len(processes) == 0 {
- return nil
- }
-
- // Try graceful shutdown first on Windows
- if runtime.GOOS == "windows" {
- for _, pid := range processes {
- exec.Command("taskkill", "/PID", pid).Run()
- time.Sleep(500 * time.Millisecond)
- }
- }
-
- // Force kill remaining processes
- remainingProcesses, _ := m.getCursorProcesses()
- for _, pid := range remainingProcesses {
- m.killProcess(pid)
- }
-
- time.Sleep(m.config.RetryDelay)
-
- if processes, _ := m.getCursorProcesses(); len(processes) == 0 {
- return nil
- }
- }
-
- return nil
-}
-
-// getCursorProcesses returns PIDs of running Cursor processes
-func (m *Manager) getCursorProcesses() ([]string, error) {
- cmd := m.getProcessListCommand()
- if cmd == nil {
- return nil, fmt.Errorf("unsupported operating system: %s", runtime.GOOS)
- }
-
- output, err := cmd.Output()
- if err != nil {
- return nil, fmt.Errorf("failed to execute command: %w", err)
- }
-
- return m.parseProcessList(string(output)), nil
-}
-
-// getProcessListCommand returns the appropriate command to list processes based on OS
-func (m *Manager) getProcessListCommand() *exec.Cmd {
- switch runtime.GOOS {
- case "windows":
- return exec.Command("tasklist", "/FO", "CSV", "/NH")
- case "darwin":
- return exec.Command("ps", "-ax")
- case "linux":
- return exec.Command("ps", "-A")
- default:
- return nil
- }
-}
-
-// parseProcessList extracts Cursor process PIDs from process list output
-func (m *Manager) parseProcessList(output string) []string {
- var processes []string
- for _, line := range strings.Split(output, "\n") {
- lowerLine := strings.ToLower(line)
-
- if m.isOwnProcess(lowerLine) {
- continue
- }
-
- if pid := m.findCursorProcess(line, lowerLine); pid != "" {
- processes = append(processes, pid)
- }
- }
- return processes
-}
-
-// isOwnProcess checks if the process belongs to this application
-func (m *Manager) isOwnProcess(line string) bool {
- return strings.Contains(line, "cursor-id-modifier") ||
- strings.Contains(line, "cursor-helper")
-}
-
-// findCursorProcess checks if a process line matches Cursor patterns and returns its PID
-func (m *Manager) findCursorProcess(line, lowerLine string) string {
- for _, pattern := range m.config.ProcessPatterns {
- if m.matchPattern(lowerLine, strings.ToLower(pattern)) {
- return m.extractPID(line)
- }
- }
- return ""
-}
-
-// matchPattern checks if a line matches a pattern, supporting wildcards
-func (m *Manager) matchPattern(line, pattern string) bool {
- switch {
- case strings.HasPrefix(pattern, "*") && strings.HasSuffix(pattern, "*"):
- search := pattern[1 : len(pattern)-1]
- return strings.Contains(line, search)
- case strings.HasPrefix(pattern, "*"):
- return strings.HasSuffix(line, pattern[1:])
- case strings.HasSuffix(pattern, "*"):
- return strings.HasPrefix(line, pattern[:len(pattern)-1])
- default:
- return line == pattern
- }
-}
-
-// extractPID extracts process ID from a process list line based on OS format
-func (m *Manager) extractPID(line string) string {
- switch runtime.GOOS {
- case "windows":
- parts := strings.Split(line, ",")
- if len(parts) >= 2 {
- return strings.Trim(parts[1], "\"")
- }
- case "darwin", "linux":
- parts := strings.Fields(line)
- if len(parts) >= 1 {
- return parts[0]
- }
- }
- return ""
-}
-
-// killProcess forcefully terminates a process by PID
-func (m *Manager) killProcess(pid string) error {
- cmd := m.getKillCommand(pid)
- if cmd == nil {
- return fmt.Errorf("unsupported operating system: %s", runtime.GOOS)
- }
- return cmd.Run()
-}
-
-// getKillCommand returns the appropriate command to kill a process based on OS
-func (m *Manager) getKillCommand(pid string) *exec.Cmd {
- switch runtime.GOOS {
- case "windows":
- return exec.Command("taskkill", "/F", "/PID", pid)
- case "darwin", "linux":
- return exec.Command("kill", "-9", pid)
- default:
- return nil
- }
-}
diff --git a/internal/ui/display.go b/internal/ui/display.go
deleted file mode 100644
index 32ed566..0000000
--- a/internal/ui/display.go
+++ /dev/null
@@ -1,94 +0,0 @@
-package ui
-
-import (
- "fmt"
- "os"
- "os/exec"
- "runtime"
- "strings"
-
- "github.com/fatih/color"
-)
-
-// Display handles UI operations for terminal output
-type Display struct {
- spinner *Spinner
-}
-
-// NewDisplay creates a new display instance with an optional spinner
-func NewDisplay(spinner *Spinner) *Display {
- if spinner == nil {
- spinner = NewSpinner(nil)
- }
- return &Display{spinner: spinner}
-}
-
-// Terminal Operations
-
-// ClearScreen clears the terminal screen based on OS
-func (d *Display) ClearScreen() error {
- var cmd *exec.Cmd
- switch runtime.GOOS {
- case "windows":
- cmd = exec.Command("cmd", "/c", "cls")
- default:
- cmd = exec.Command("clear")
- }
- cmd.Stdout = os.Stdout
- return cmd.Run()
-}
-
-// Progress Indicator
-
-// ShowProgress displays a progress message with a spinner
-func (d *Display) ShowProgress(message string) {
- d.spinner.SetMessage(message)
- d.spinner.Start()
-}
-
-// StopProgress stops the progress spinner
-func (d *Display) StopProgress() {
- d.spinner.Stop()
-}
-
-// Message Display
-
-// ShowSuccess displays success messages in green
-func (d *Display) ShowSuccess(messages ...string) {
- green := color.New(color.FgGreen)
- for _, msg := range messages {
- green.Println(msg)
- }
-}
-
-// ShowInfo displays an info message in cyan
-func (d *Display) ShowInfo(message string) {
- cyan := color.New(color.FgCyan)
- cyan.Println(message)
-}
-
-// ShowError displays an error message in red
-func (d *Display) ShowError(message string) {
- red := color.New(color.FgRed)
- red.Println(message)
-}
-
-// ShowPrivilegeError displays privilege error messages with instructions
-func (d *Display) ShowPrivilegeError(messages ...string) {
- red := color.New(color.FgRed, color.Bold)
- yellow := color.New(color.FgYellow)
-
- // Main error message
- red.Println(messages[0])
- fmt.Println()
-
- // Additional instructions
- for _, msg := range messages[1:] {
- if strings.Contains(msg, "%s") {
- exe, _ := os.Executable()
- yellow.Printf(msg+"\n", exe)
- } else {
- yellow.Println(msg)
- }
- }
-}
diff --git a/internal/ui/logo.go b/internal/ui/logo.go
deleted file mode 100644
index 564525a..0000000
--- a/internal/ui/logo.go
+++ /dev/null
@@ -1,20 +0,0 @@
-package ui
-
-import (
- "github.com/fatih/color"
-)
-
-const cyberpunkLogo = `
- ██████╗██╗ ██╗██████╗ ███████╗ ██████╗ ██████╗
- ██╔════╝██║ ██║██╔══██╗██╔════╝██╔═══██╗██╔══██╗
- ██║ ██║ ██║██████╔╝███████╗██║ ██║██████╔╝
- ██║ ██║ ██║██╔══██╗╚════██║██║ ██║██╔══██╗
- ╚██████╗╚██████╔╝██║ ██║███████║╚██████╔╝██║ ██║
- ╚═════╝ ╚═════╝ ╚═╝ ╚═╝╚══════╝ ╚═════╝ ╚═╝ ╚═╝
-`
-
-// ShowLogo displays the application logo
-func (d *Display) ShowLogo() {
- cyan := color.New(color.FgCyan, color.Bold)
- cyan.Println(cyberpunkLogo)
-}
diff --git a/internal/ui/spinner.go b/internal/ui/spinner.go
deleted file mode 100644
index 145f730..0000000
--- a/internal/ui/spinner.go
+++ /dev/null
@@ -1,122 +0,0 @@
-package ui
-
-import (
- "fmt"
- "sync"
- "time"
-
- "github.com/fatih/color"
-)
-
-// SpinnerConfig defines spinner configuration
-type SpinnerConfig struct {
- Frames []string // Animation frames for the spinner
- Delay time.Duration // Delay between frame updates
-}
-
-// DefaultSpinnerConfig returns the default spinner configuration
-func DefaultSpinnerConfig() *SpinnerConfig {
- return &SpinnerConfig{
- Frames: []string{"⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"},
- Delay: 100 * time.Millisecond,
- }
-}
-
-// Spinner represents a progress spinner
-type Spinner struct {
- config *SpinnerConfig
- message string
- current int
- active bool
- stopCh chan struct{}
- mu sync.RWMutex
-}
-
-// NewSpinner creates a new spinner with the given configuration
-func NewSpinner(config *SpinnerConfig) *Spinner {
- if config == nil {
- config = DefaultSpinnerConfig()
- }
- return &Spinner{
- config: config,
- stopCh: make(chan struct{}),
- }
-}
-
-// State management
-
-// SetMessage sets the spinner message
-func (s *Spinner) SetMessage(message string) {
- s.mu.Lock()
- defer s.mu.Unlock()
- s.message = message
-}
-
-// IsActive returns whether the spinner is currently active
-func (s *Spinner) IsActive() bool {
- s.mu.RLock()
- defer s.mu.RUnlock()
- return s.active
-}
-
-// Control methods
-
-// Start begins the spinner animation
-func (s *Spinner) Start() {
- s.mu.Lock()
- if s.active {
- s.mu.Unlock()
- return
- }
- s.active = true
- s.mu.Unlock()
-
- go s.run()
-}
-
-// Stop halts the spinner animation
-func (s *Spinner) Stop() {
- s.mu.Lock()
- defer s.mu.Unlock()
-
- if !s.active {
- return
- }
-
- s.active = false
- close(s.stopCh)
- s.stopCh = make(chan struct{})
- fmt.Print("\r") // Clear the spinner line
-}
-
-// Internal methods
-
-func (s *Spinner) run() {
- ticker := time.NewTicker(s.config.Delay)
- defer ticker.Stop()
-
- cyan := color.New(color.FgCyan, color.Bold)
- message := s.message
-
- // Print initial state
- fmt.Printf("\r %s %s", cyan.Sprint(s.config.Frames[0]), message)
-
- for {
- select {
- case <-s.stopCh:
- return
- case <-ticker.C:
- s.mu.RLock()
- if !s.active {
- s.mu.RUnlock()
- return
- }
- frame := s.config.Frames[s.current%len(s.config.Frames)]
- s.current++
- s.mu.RUnlock()
-
- fmt.Printf("\r %s", cyan.Sprint(frame))
- fmt.Printf("\033[%dG%s", 4, message) // Move cursor and print message
- }
- }
-}
diff --git a/pkg/idgen/generator.go b/pkg/idgen/generator.go
deleted file mode 100644
index 3061f74..0000000
--- a/pkg/idgen/generator.go
+++ /dev/null
@@ -1,116 +0,0 @@
-package idgen
-
-import (
- "crypto/rand"
- "encoding/hex"
- "fmt"
- "sync"
-)
-
-// Generator handles secure ID generation for machines and devices
-type Generator struct {
- bufferPool sync.Pool
-}
-
-// NewGenerator creates a new ID generator
-func NewGenerator() *Generator {
- return &Generator{
- bufferPool: sync.Pool{
- New: func() interface{} {
- return make([]byte, 64)
- },
- },
- }
-}
-
-// Constants for ID generation
-const (
- machineIDPrefix = "auth0|user_"
- uuidFormat = "%s-%s-%s-%s-%s"
-)
-
-// generateRandomHex generates a random hex string of specified length
-func (g *Generator) generateRandomHex(length int) (string, error) {
- buffer := g.bufferPool.Get().([]byte)
- defer g.bufferPool.Put(buffer)
-
- if _, err := rand.Read(buffer[:length]); err != nil {
- return "", fmt.Errorf("failed to generate random bytes: %w", err)
- }
- return hex.EncodeToString(buffer[:length]), nil
-}
-
-// GenerateMachineID generates a new machine ID with auth0|user_ prefix
-func (g *Generator) GenerateMachineID() (string, error) {
- randomPart, err := g.generateRandomHex(32) // 生成64字符的十六进制
- if err != nil {
- return "", err
- }
-
- return fmt.Sprintf("%x%s", []byte(machineIDPrefix), randomPart), nil
-}
-
-// GenerateMacMachineID generates a new 64-byte MAC machine ID
-func (g *Generator) GenerateMacMachineID() (string, error) {
- return g.generateRandomHex(32) // 生成64字符的十六进制
-}
-
-// GenerateDeviceID generates a new device ID in UUID format
-func (g *Generator) GenerateDeviceID() (string, error) {
- id, err := g.generateRandomHex(16)
- if err != nil {
- return "", err
- }
- return fmt.Sprintf(uuidFormat,
- id[0:8], id[8:12], id[12:16], id[16:20], id[20:32]), nil
-}
-
-// GenerateSQMID generates a new SQM ID in UUID format (with braces)
-func (g *Generator) GenerateSQMID() (string, error) {
- id, err := g.GenerateDeviceID()
- if err != nil {
- return "", err
- }
- return fmt.Sprintf("{%s}", id), nil
-}
-
-// ValidateID validates the format of various ID types
-func (g *Generator) ValidateID(id string, idType string) bool {
- switch idType {
- case "machineID", "macMachineID":
- return len(id) == 64 && isHexString(id)
- case "deviceID":
- return isValidUUID(id)
- case "sqmID":
- if len(id) < 2 || id[0] != '{' || id[len(id)-1] != '}' {
- return false
- }
- return isValidUUID(id[1 : len(id)-1])
- default:
- return false
- }
-}
-
-// Helper functions
-func isHexString(s string) bool {
- _, err := hex.DecodeString(s)
- return err == nil
-}
-
-func isValidUUID(uuid string) bool {
- if len(uuid) != 36 {
- return false
- }
- for i, r := range uuid {
- if i == 8 || i == 13 || i == 18 || i == 23 {
- if r != '-' {
- return false
- }
- continue
- }
- if !((r >= '0' && r <= '9') || (r >= 'a' && r <= 'f') || (r >= 'A' && r <= 'F')) {
- return false
- }
- }
- return true
-}
diff --git a/process_cursor_links.py b/process_cursor_links.py
deleted file mode 100644
index 2952064..0000000
--- a/process_cursor_links.py
+++ /dev/null
@@ -1,375 +0,0 @@
-import csv
-from dataclasses import dataclass
-from typing import List
-import json
-
-@dataclass
-class CursorVersion:
- version: str
- build_id: str
-
- def get_download_links(self) -> dict:
- base_url = f"https://downloader.cursor.sh/builds/{self.build_id}"
- return {
- "windows": {
- "x64": f"{base_url}/windows/nsis/x64",
- "arm64": f"{base_url}/windows/nsis/arm64"
- },
- "mac": {
- "universal": f"{base_url}/mac/installer/universal",
- "arm64": f"{base_url}/mac/installer/arm64",
- "x64": f"{base_url}/mac/installer/x64"
- },
- "linux": {
- "x64": f"{base_url}/linux/appImage/x64"
- }
- }
-
-def parse_versions(data: str) -> List[CursorVersion]:
- versions = []
- for line in data.strip().split('\n'):
- if not line:
- continue
- version, build_id = line.strip().split(',')
- versions.append(CursorVersion(version, build_id))
- return versions
-
-def generate_markdown(versions: List[CursorVersion]) -> str:
- md = """# 🖥️ Windows
-
-## x64
-
-📦 Windows x64 安装包
-
-| 版本 | 下载链接 |
-|------|----------|
-"""
-
- # Windows x64
- for version in versions:
- links = version.get_download_links()
- md += f"| {version.version} | [下载]({links['windows']['x64']}) |\n"
-
- md += """
-
-
-## ARM64
-
-📱 Windows ARM64 安装包
-
-| 版本 | 下载链接 |
-|------|----------|
-"""
-
- # Windows ARM64
- for version in versions:
- links = version.get_download_links()
- md += f"| {version.version} | [下载]({links['windows']['arm64']}) |\n"
-
- md += """
-
-
-# 🍎 macOS
-
-## Universal
-
-🎯 macOS Universal 安装包
-
-| 版本 | 下载链接 |
-|------|----------|
-"""
-
- # macOS Universal
- for version in versions:
- links = version.get_download_links()
- md += f"| {version.version} | [下载]({links['mac']['universal']}) |\n"
-
- md += """
-
-
-## ARM64
-
-💪 macOS ARM64 安装包
-
-| 版本 | 下载链接 |
-|------|----------|
-"""
-
- # macOS ARM64
- for version in versions:
- links = version.get_download_links()
- md += f"| {version.version} | [下载]({links['mac']['arm64']}) |\n"
-
- md += """
-
-
-## Intel
-
-💻 macOS Intel 安装包
-
-| 版本 | 下载链接 |
-|------|----------|
-"""
-
- # macOS Intel
- for version in versions:
- links = version.get_download_links()
- md += f"| {version.version} | [下载]({links['mac']['x64']}) |\n"
-
- md += """
-
-
-# 🐧 Linux
-
-## x64
-
-🎮 Linux x64 AppImage
-
-| 版本 | 下载链接 |
-|------|----------|
-"""
-
- # Linux x64
- for version in versions:
- links = version.get_download_links()
- md += f"| {version.version} | [下载]({links['linux']['x64']}) |\n"
-
- md += """
-
-
-
-"""
- return md
-
-def main():
- # 示例数据
- data = """
-0.45.11,250207y6nbaw5qc
-0.45.10,250205buadkzpea
-0.45.9,250202tgstl42dt
-0.45.8,250201b44xw1x2k
-0.45.7,250130nr6eorv84
-0.45.6,25013021lv9say3
-0.45.5,250128loaeyulq8
-0.45.4,250126vgr3vztvj
-0.45.3,250124b0rcj0qql
-0.45.2,250123mhituoa6o
-0.45.1,2501213ljml5byg
-0.45.0,250120dh9ezx9pg
-0.44.11,250103fqxdt5u9z
-0.44.10,250102ys80vtnud
-0.44.9,2412268nc6pfzgo
-0.44.8,241222ooktny8mh
-0.44.7,2412219nhracv01
-0.44.6,2412214pmryneua
-0.44.5,241220s3ux0e1tv
-0.44.4,241219117fcvexy
-0.44.3,241218sybfbogmq
-0.44.2,241218ntls52u8v
-0.44.0,2412187f9v0nffu
-0.43.6,241206z7j6me2e2
-0.43.5,241127pdg4cnbu2
-0.43.4,241126w13goyvrs
-0.43.3,2411246yqzx1jmm
-0.43.1,241124gsiwb66nc
-0.42.5,24111460bf2loz1
-0.42.4,2410291z3bdg1dy
-0.42.3,241016kxu9umuir
-0.42.2,2410127mj66lvaq
-0.42.1,241011i66p9fuvm
-0.42.0,241009fij7nohn5
-0.41.3,240925fkhcqg263
-0.41.2,240921llnho65ov
-0.41.1,2409189xe3envg5
-0.40.4,2409052yfcjagw2
-0.40.3,240829epqamqp7h
-0.40.2,240828c021k3aib
-0.40.1,2408245thnycuzj
-0.40.0,24082202sreugb2
-0.39.6,240819ih4ta2fye
-0.39.5,240814y9rhzmu7h
-0.39.4,240810elmeg3seq
-0.39.3,2408092hoyaxt9m
-0.39.2,240808phaxh4b5r
-0.39.1,240807g919tr4ly
-0.39.0,240802cdixtv9a6
-0.38.1,240725f0ti25os7
-0.38.0,240723790oxe4a2
-0.37.1,240714yrr3gmv3k
-0.36.2,2407077n6pzboby
-0.36.1,240706uekt2eaft
-0.36.0,240703xqkjv5aqa
-0.35.1,240621pc2f7rl8a
-0.35.0,240608cv11mfsjl
-0.34.6,240606kgzq24cfb
-0.34.6,240605r495newcf
-0.34.5,240602rq6xovt3a
-0.34.4,2406014h0rgjghe
-0.34.3,240529baisuyd2e
-0.34.2,240528whh1qyo9h
-0.34.1,24052838ygfselt
-0.34.0,240527xus72jmkj
-0.33.4,240511kb8wt1tms
-0.33.3,2405103lx8342ta
-0.33.2,240510dwmw395qe
-0.33.1,2405039a9h2fqc9
-0.33.0,240503hyjsnhazo
-0.32.8,240428d499o6zja
-0.32.7,240427w5guozr0l
-0.32.2,240417ab4wag7sx
-0.32.1,2404152czor73fk
-0.32.0,240412ugli06ue0
-0.31.3,240402rq154jw46
-0.31.1,240402pkwfm2ps6
-0.31.0,2404018j7z0xv2g
-0.30.5,240327tmd2ozdc7
-0.30.4,240325dezy8ziab
-0.30.3,2403229gtuhto9g
-0.30.2,240322gzqjm3p0d
-0.30.1,2403212w1ejubt8
-0.30.0,240320tpx86e7hk
-0.29.1,2403027twmz0d1t
-0.29.0,240301kpqvacw2h
-0.28.1,240226tstim4evd
-0.28.0,240224g2d7jazcq
-0.27.4,240219qdbagglqz
-0.27.3,240218dxhc6y8os
-0.27.2,240216kkzl9nhxi
-0.27.1,240215l4ooehnyl
-0.27.0,240215at6ewkd59
-0.26.2,240212o6r9qxtcg
-0.26.1,2402107t904hing
-0.26.0,240210k8is5xr6v
-0.25.3,240207aacboj1k8
-0.25.2,240206p3708uc9z
-0.25.1,2402033t030rprh
-0.25.0,240203kh86t91q8
-0.24.4,240129iecm3e33w
-0.24.3,2401289dx79qsc0
-0.24.1,240127cad17436d
-0.24.0,240126wp9irhmza
-0.23.9,240124dsmraeml3
-0.23.8,240123fnn1hj1fg
-0.23.7,240123xsfe7ywcv
-0.23.6,240121m1740elox
-0.23.5,2401215utj6tx6q
-0.23.4,240121f4qy6ba2y
-0.23.3,2401201und3ytom
-0.23.2,240120an2k2hf1i
-0.23.1,240119fgzxwudn9
-0.22.2,24011721vsch1l1
-0.22.1,2401083eyk8kmzc
-0.22.0,240107qk62kvva3
-0.21.1,231230h0vi6srww
-0.21.0,231229ezidnxiu3
-0.20.2,231219aksf83aad
-0.20.1,231218ywfaxax09
-0.20.0,231216nsyfew5j1
-0.19.1,2312156z2ric57n
-0.19.0,231214per9qal2p
-0.18.8,2312098ffjr3ign
-0.18.7,23120880aolip2i
-0.18.6,231207ueqazwde8
-0.18.5,231206jzy2n2sbi
-0.18.4,2312033zjv5fqai
-0.18.3,231203k2vnkxq2m
-0.18.1,23120176kaer07t
-0.17.0,231127p7iyxn8rg
-0.16.0,231116rek2xuq6a
-0.15.5,231115a5mv63u9f
-0.15.4,23111469e1i3xyi
-0.15.3,231113b0yv3uqem
-0.15.2,231113ah0kuf3pf
-0.15.1,231111yanyyovap
-0.15.0,231110mdkomczmw
-0.14.1,231109xitrgihlk
-0.14.0,231102m6tuamwbx
-0.13.4,231029rso7pso8l
-0.13.3,231025uihnjkh9v
-0.13.2,231024w4iv7xlm6
-0.13.1,231022f3j0ubckv
-0.13.0,231022ptw6i4j42
-0.12.3,231008c5ursm0oj"""
-
- versions = parse_versions(data)
-
- # 生成 Markdown 文件
- markdown_content = generate_markdown(versions)
- with open('Cursor历史.md', 'w', encoding='utf-8') as f:
- f.write(markdown_content)
-
- # 创建结果数据结构
- result = {
- "versions": []
- }
-
- # 处理每个版本
- for version in versions:
- version_info = {
- "version": version.version,
- "build_id": version.build_id,
- "downloads": version.get_download_links()
- }
- result["versions"].append(version_info)
-
- # 保存为JSON文件
- with open('cursor_downloads.json', 'w', encoding='utf-8') as f:
- json.dump(result, f, indent=2, ensure_ascii=False)
-
- # 同时生成CSV格式的下载链接
- with open('cursor_downloads.csv', 'w', newline='', encoding='utf-8') as f:
- writer = csv.writer(f)
- writer.writerow(['Version', 'Platform', 'Architecture', 'Download URL'])
-
- for version in versions:
- links = version.get_download_links()
- for platform, archs in links.items():
- for arch, url in archs.items():
- writer.writerow([version.version, platform, arch, url])
-
-if __name__ == "__main__":
- main()
\ No newline at end of file
diff --git a/scripts/build_all.bat b/scripts/build_all.bat
deleted file mode 100644
index e07e387..0000000
--- a/scripts/build_all.bat
+++ /dev/null
@@ -1,74 +0,0 @@
-@echo off
-setlocal EnableDelayedExpansion
-
-:: Build optimization flags
-set "OPTIMIZATION_FLAGS=-trimpath -ldflags=\"-s -w\""
-set "BUILD_JOBS=4"
-
-:: Messages / 消息
-set "EN_MESSAGES[0]=Starting build process for version"
-set "EN_MESSAGES[1]=Using optimization flags:"
-set "EN_MESSAGES[2]=Cleaning old builds..."
-set "EN_MESSAGES[3]=Cleanup completed"
-set "EN_MESSAGES[4]=Starting builds for all platforms..."
-set "EN_MESSAGES[5]=Building for"
-set "EN_MESSAGES[6]=Build successful:"
-set "EN_MESSAGES[7]=All builds completed!"
-
-:: Colors
-set "GREEN=[32m"
-set "RED=[31m"
-set "RESET=[0m"
-
-:: Cleanup function
-:cleanup
-if exist "..\bin" (
- rd /s /q "..\bin"
- echo %GREEN%!EN_MESSAGES[3]!%RESET%
-)
-mkdir "..\bin" 2>nul
-
-:: Build function with optimizations
-:build
-set "os=%~1"
-set "arch=%~2"
-set "ext="
-if "%os%"=="windows" set "ext=.exe"
-
-echo %GREEN%!EN_MESSAGES[5]! %os%/%arch%%RESET%
-
-set "CGO_ENABLED=0"
-set "GOOS=%os%"
-set "GOARCH=%arch%"
-
-start /b cmd /c "go build -trimpath -ldflags=\"-s -w\" -o ..\bin\%os%\%arch%\cursor-id-modifier%ext% -a -installsuffix cgo -mod=readonly ..\cmd\cursor-id-modifier"
-exit /b 0
-
-:: Main execution
-echo %GREEN%!EN_MESSAGES[0]!%RESET%
-echo %GREEN%!EN_MESSAGES[1]! %OPTIMIZATION_FLAGS%%RESET%
-
-call :cleanup
-
-echo %GREEN%!EN_MESSAGES[4]!%RESET%
-
-:: Start builds in parallel
-set "pending=0"
-for %%o in (windows linux darwin) do (
- for %%a in (amd64 386) do (
- call :build %%o %%a
- set /a "pending+=1"
- if !pending! geq %BUILD_JOBS% (
- timeout /t 1 /nobreak >nul
- set "pending=0"
- )
- )
-)
-
-:: Wait for all builds to complete
-:wait_builds
-timeout /t 2 /nobreak >nul
-tasklist /fi "IMAGENAME eq go.exe" 2>nul | find "go.exe" >nul
-if not errorlevel 1 goto wait_builds
-
-echo %GREEN%!EN_MESSAGES[7]!%RESET%
\ No newline at end of file
diff --git a/scripts/build_all.sh b/scripts/build_all.sh
deleted file mode 100755
index 7db5e7b..0000000
--- a/scripts/build_all.sh
+++ /dev/null
@@ -1,143 +0,0 @@
-#!/bin/bash
-
-# 设置颜色代码 / Set color codes
-GREEN='\033[0;32m'
-RED='\033[0;31m'
-NC='\033[0m' # No Color / 无颜色
-
-# Build optimization flags
-OPTIMIZATION_FLAGS="-trimpath -ldflags=\"-s -w\""
-PARALLEL_JOBS=$(nproc || echo "4") # Get number of CPU cores or default to 4
-
-# Messages / 消息
-EN_MESSAGES=(
- "Starting build process for version"
- "Cleaning old builds..."
- "Creating bin directory..."
- "Failed to create bin directory"
- "Building for"
- "Successfully built:"
- "Failed to build for"
- "Build Summary:"
- "Successful builds:"
- "Failed builds:"
- "Generated files:"
-)
-
-CN_MESSAGES=(
- "开始构建版本"
- "正在清理旧的构建文件..."
- "正在创建bin目录..."
- "创建bin目录失败"
- "正在构建"
- "构建成功:"
- "构建失败:"
- "构建摘要:"
- "成功构建数:"
- "失败构建数:"
- "生成的文件:"
- "构建过程被中断"
- "错误:"
-)
-
-# 版本信息 / Version info
-VERSION="1.0.0"
-
-# Detect system language / 检测系统语言
-detect_language() {
- if [[ $(locale | grep "LANG=zh_CN") ]]; then
- echo "cn"
- else
- echo "en"
- fi
-}
-
-# Get message based on language / 根据语言获取消息
-get_message() {
- local index=$1
- local lang=$(detect_language)
-
- if [[ "$lang" == "cn" ]]; then
- echo "${CN_MESSAGES[$index]}"
- else
- echo "${EN_MESSAGES[$index]}"
- fi
-}
-
-# 错误处理函数 / Error handling function
-handle_error() {
- echo -e "${RED}$(get_message 12) $1${NC}"
- exit 1
-}
-
-# 清理函数 / Cleanup function
-cleanup() {
- if [ -d "../bin" ]; then
- rm -rf ../bin
- echo -e "${GREEN}$(get_message 1)${NC}"
- fi
-}
-
-# Build function with optimizations
-build() {
- local os=$1
- local arch=$2
- local ext=""
- [ "$os" = "windows" ] && ext=".exe"
-
- echo -e "${GREEN}$(get_message 4) $os/$arch${NC}"
-
- GOOS=$os GOARCH=$arch CGO_ENABLED=0 go build \
- -trimpath \
- -ldflags="-s -w" \
- -o "../bin/$os/$arch/cursor-id-modifier$ext" \
- -a -installsuffix cgo \
- -mod=readonly \
- ../cmd/cursor-id-modifier &
-}
-
-# Parallel build execution
-build_all() {
- local builds=0
- local max_parallel=$PARALLEL_JOBS
-
- # Define build targets
- declare -A targets=(
- ["linux/amd64"]=1
- ["linux/386"]=1
- ["linux/arm64"]=1
- ["windows/amd64"]=1
- ["windows/386"]=1
- ["darwin/amd64"]=1
- ["darwin/arm64"]=1
- )
-
- for target in "${!targets[@]}"; do
- IFS='/' read -r os arch <<< "$target"
- build "$os" "$arch"
-
- ((builds++))
-
- if ((builds >= max_parallel)); then
- wait
- builds=0
- fi
- done
-
- # Wait for remaining builds
- wait
-}
-
-# Main execution
-main() {
- cleanup
- mkdir -p ../bin || { echo -e "${RED}$(get_message 3)${NC}"; exit 1; }
- build_all
- echo -e "${GREEN}Build completed successfully${NC}"
-}
-
-# 捕获错误信号 / Catch error signals
-trap 'echo -e "\n${RED}$(get_message 11)${NC}"; exit 1' INT TERM
-
-# 执行主函数 / Execute main function
-main
\ No newline at end of file
diff --git a/scripts/cursor_id_modifier.pot b/scripts/cursor_id_modifier.pot
deleted file mode 100644
index 54f4417..0000000
--- a/scripts/cursor_id_modifier.pot
+++ /dev/null
@@ -1,318 +0,0 @@
-msgid ""
-msgstr ""
-"Project-Id-Version: cursor_id_modifier\n"
-"POT-Creation-Date: 2025-04-25 12:00+0000\n"
-"PO-Revision-Date: 2025-04-25 12:00+0000\n"
-"Language-Team: None\n"
-"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=UTF-8\n"
-"Content-Transfer-Encoding: 8bit\n"
-
-msgid "Error: No translation file found for domain 'cursor_id_modifier' in {}/zh_CN/LC_MESSAGES/"
-msgstr ""
-
-msgid "========== Cursor ID modification tool log start {} =========="
-msgstr ""
-
-msgid "[INFO] {} {}"
-msgstr ""
-
-msgid "[WARN] {} {}"
-msgstr ""
-
-msgid "[ERROR] {} {}"
-msgstr ""
-
-msgid "[DEBUG] {} {}"
-msgstr ""
-
-msgid "[CMD] {} Executing command: {}"
-msgstr ""
-
-msgid "[CMD] {}:"
-msgstr ""
-
-msgid "Unable to get username"
-msgstr ""
-
-msgid "Finding Cursor installation path..."
-msgstr ""
-
-msgid "Found Cursor installation path: {}"
-msgstr ""
-
-msgid "Found Cursor via which: {}"
-msgstr ""
-
-msgid "Cursor executable not found, will try using config directory"
-msgstr ""
-
-msgid "Found Cursor via search: {}"
-msgstr ""
-
-msgid "Finding Cursor resource directory..."
-msgstr ""
-
-msgid "Found Cursor resource directory: {}"
-msgstr ""
-
-msgid "Found resource directory via binary path: {}"
-msgstr ""
-
-msgid "Cursor resource directory not found"
-msgstr ""
-
-msgid "Please run this script with sudo"
-msgstr ""
-
-msgid "Example: sudo {}"
-msgstr ""
-
-msgid "Checking Cursor processes..."
-msgstr ""
-
-msgid "Getting process details for {}:"
-msgstr ""
-
-msgid "No running Cursor processes found"
-msgstr ""
-
-msgid "Found running Cursor processes"
-msgstr ""
-
-msgid "Attempting to terminate Cursor processes..."
-msgstr ""
-
-msgid "Attempting to forcefully terminate processes..."
-msgstr ""
-
-msgid "Waiting for processes to terminate, attempt {}/{}..."
-msgstr ""
-
-msgid "Cursor processes successfully terminated"
-msgstr ""
-
-msgid "Unable to terminate Cursor processes after {} attempts"
-msgstr ""
-
-msgid "Please manually terminate the processes and try again"
-msgstr ""
-
-msgid "Configuration file does not exist, skipping backup"
-msgstr ""
-
-msgid "Configuration backed up to: {}"
-msgstr ""
-
-msgid "Backup failed"
-msgstr ""
-
-msgid "File does not exist: {}"
-msgstr ""
-
-msgid "Unable to modify file permissions: {}"
-msgstr ""
-
-msgid "Generated temporary file is empty"
-msgstr ""
-
-msgid "Unable to write to file: {}"
-msgstr ""
-
-msgid "Machine code reset options"
-msgstr ""
-
-msgid "Do you need to reset the machine code? (Usually, modifying JS files is sufficient):"
-msgstr ""
-
-msgid "Don't reset - only modify JS files"
-msgstr ""
-
-msgid "Reset - modify both config file and machine code"
-msgstr ""
-
-msgid "[INPUT_DEBUG] Machine code reset option selected: {}"
-msgstr ""
-
-msgid "You chose to reset the machine code"
-msgstr ""
-
-msgid "Found existing configuration file: {}"
-msgstr ""
-
-msgid "Setting new device and machine IDs..."
-msgstr ""
-
-msgid "New device ID: {}"
-msgstr ""
-
-msgid "New machine ID: {}"
-msgstr ""
-
-msgid "Configuration file modified successfully"
-msgstr ""
-
-msgid "Configuration file modification failed"
-msgstr ""
-
-msgid "Configuration file not found, this is normal, skipping ID modification"
-msgstr ""
-
-msgid "You chose not to reset the machine code, will only modify JS files"
-msgstr ""
-
-msgid "Configuration processing completed"
-msgstr ""
-
-msgid "Finding Cursor's JS files..."
-msgstr ""
-
-msgid "Searching for JS files in resource directory: {}"
-msgstr ""
-
-msgid "Found JS file: {}"
-msgstr ""
-
-msgid "No JS files found in resource directory, trying other directories..."
-msgstr ""
-
-msgid "Searching directory: {}"
-msgstr ""
-
-msgid "No modifiable JS files found"
-msgstr ""
-
-msgid "Found {} JS files to modify"
-msgstr ""
-
-msgid "Starting to modify Cursor's JS files..."
-msgstr ""
-
-msgid "Unable to find modifiable JS files"
-msgstr ""
-
-msgid "Processing file: {}"
-msgstr ""
-
-msgid "Unable to create backup for file: {}"
-msgstr ""
-
-msgid "Found x-cursor-checksum setting code"
-msgstr ""
-
-msgid "Successfully modified x-cursor-checksum setting code"
-msgstr ""
-
-msgid "Failed to modify x-cursor-checksum setting code"
-msgstr ""
-
-msgid "Found IOPlatformUUID keyword"
-msgstr ""
-
-msgid "Successfully injected randomUUID call into a$ function"
-msgstr ""
-
-msgid "Failed to modify a$ function"
-msgstr ""
-
-msgid "Successfully injected randomUUID call into v5 function"
-msgstr ""
-
-msgid "Failed to modify v5 function"
-msgstr ""
-
-msgid "Completed universal modification"
-msgstr ""
-
-msgid "File already contains custom injection code, skipping modification"
-msgstr ""
-
-msgid "Completed most universal injection"
-msgstr ""
-
-msgid "File has already been modified, skipping modification"
-msgstr ""
-
-msgid "Failed to modify any JS files"
-msgstr ""
-
-msgid "Successfully modified {} JS files"
-msgstr ""
-
-msgid "Disabling Cursor auto-update..."
-msgstr ""
-
-msgid "Found update configuration file: {}"
-msgstr ""
-
-msgid "Disabled update configuration file: {}"
-msgstr ""
-
-msgid "Found updater: {}"
-msgstr ""
-
-msgid "Disabled updater: {}"
-msgstr ""
-
-msgid "No update configuration files or updaters found"
-msgstr ""
-
-msgid "Successfully disabled auto-update"
-msgstr ""
-
-msgid "You selected: {}"
-msgstr ""
-
-msgid "This script only supports Linux systems"
-msgstr ""
-
-msgid "Script started..."
-msgstr ""
-
-msgid "System information: {}"
-msgstr ""
-
-msgid "Current user: {}"
-msgstr ""
-
-msgid "System version information"
-msgstr ""
-
-msgid "Cursor Linux startup tool"
-msgstr ""
-
-msgid "Important notice"
-msgstr ""
-
-msgid "This tool prioritizes modifying JS files, which is safer and more reliable"
-msgstr ""
-
-msgid "Modifying Cursor JS files..."
-msgstr ""
-
-msgid "JS files modified successfully!"
-msgstr ""
-
-msgid "JS file modification failed, but configuration file modification may have succeeded"
-msgstr ""
-
-msgid "If Cursor still indicates the device is disabled after restarting, please rerun this script"
-msgstr ""
-
-msgid "Please restart Cursor to apply the new configuration"
-msgstr ""
-
-msgid "Follow the WeChat public account [Pancake AI] to discuss more Cursor tips and AI knowledge (script is free, join the group via the public account for more tips and experts)"
-msgstr ""
-
-msgid "Script execution completed"
-msgstr ""
-
-msgid "========== Cursor ID modification tool log end {} =========="
-msgstr ""
-
-msgid "Detailed log saved to: {}"
-msgstr ""
-
-msgid "If you encounter issues, please provide this log file to the developer for troubleshooting"
-msgstr ""
diff --git a/scripts/cursor_id_modifier.py b/scripts/cursor_id_modifier.py
deleted file mode 100644
index aad0bc8..0000000
--- a/scripts/cursor_id_modifier.py
+++ /dev/null
@@ -1,1298 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
-AppImage instructions:
-mkdir -p ~/Downloads/Cursor
-cd ~/Downloads/Cursor
-cd Cursor && ./Cursor-1.0.5-x86_64.AppImage --appimage-extract
-mkdir -p ~/.local
-rsync -rt ~/Downloads/Cursor/squashfs-root/usr/ ~/.local
-# ^ copy the subfolders not usr itself, so the resulting executable should be ~/.local/bin/cursor
-"""
-import subprocess
-import os
-
-SCRIPTS_DIR = os.path.dirname(os.path.abspath(__file__))
-# repo_dir = os.path.dirname(SCRIPTS_DIR)
-repo_dir = SCRIPTS_DIR
-locales_dir = os.path.join(repo_dir, 'locales')
-t_domain = "cursor_id_modifier"
-
-def compile_messages():
- global _
- languages = ['en_US', 'zh_CN']
- for lang in languages:
- lang_dir = os.path.join(locales_dir, lang, 'LC_MESSAGES')
- if os.path.isdir(lang_dir):
- # Change the directory to the LC_MESSAGES folder
- os.chdir(lang_dir)
- # Run msgfmt command
- out_name = 'cursor_id_modifier.mo'
- subprocess.run(['msgfmt', '-o', out_name, 'cursor_id_modifier.po'], check=True)
- print(os.path.abspath(out_name))
- else:
- print(f"Directory not found: {lang_dir}")
-
-import sys
-import subprocess
-import datetime
-import tempfile
-import shutil
-import uuid
-import hashlib
-import re
-import getpass
-import time
-import select
-import tty
-import termios
-import signal
-import json
-from pathlib import Path
-import glob
-import pwd
-
-import gettext
-import random
-
-# 尝试导入netifaces,如果不可用则使用系统命令
-# Try to import netifaces, use system commands if not available
-try:
- import netifaces
- NETIFACES_AVAILABLE = True
-except ImportError:
- NETIFACES_AVAILABLE = False
- log_warn = lambda x: print(f"[WARN] {x}") # 临时日志函数
- log_warn("netifaces library not found, will use system commands for network operations")
-
-# 设置语言环境
-# Set language environment
-
-# lang = 'zh' if '--en' not in sys.argv else 'en'
-lang = 'en'
-
-assert os.path.isdir(locales_dir)
-# gettext.bindtextdomain(t_domain, localedir=locales_dir)
-if lang == 'zh':
- translation = gettext.translation(
- t_domain,
- localedir=locales_dir,
- languages=['en_US', 'zh_CN'],
- )
-else:
- translation = gettext.NullTranslations()
-translation.install()
-_ = translation.gettext
-
-# 设置错误处理
-# Set error handling
-def set_error_handling():
- global _
- # 在 Python 中,我们使用 try/except 来处理错误,而不是 bash 的 set -e
- # In Python, we use try/except to handle errors instead of bash's set -e
- pass
-
-set_error_handling()
-
-# 定义日志文件路径
-# Define log file path
-LOG_FILE = "/tmp/cursor_linux_id_modifier.log"
-
-# 初始化日志文件
-# Initialize log file
-def initialize_log():
- with open(LOG_FILE, 'w') as f:
- f.write(_("========== Cursor ID modification tool log start {} ==========").format(datetime.datetime.now()) + "\n")
- os.chmod(LOG_FILE, 0o644)
-
-# 颜色定义
-# Color definitions
-RED = '\033[0;31m'
-GREEN = '\033[0;32m'
-YELLOW = '\033[1;33m'
-BLUE = '\033[0;34m'
-NC = '\033[0m' # No Color
-
-# 日志函数 - 同时输出到终端和日志文件
-# Log functions - output to terminal and log file simultaneously
-def log_info(message):
- global _
- print(f"{GREEN}[INFO]{NC} {_(message)}")
- with open(LOG_FILE, 'a') as f:
- f.write(_("[INFO] {} {}").format(datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'), _(message)) + "\n")
-
-def log_warn(message):
- global _
- print(f"{YELLOW}[WARN]{NC} {_(message)}")
- with open(LOG_FILE, 'a') as f:
- f.write(_("[WARN] {} {}").format(datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'), _(message)) + "\n")
-
-def log_error(message):
- global _
- print(f"{RED}[ERROR]{NC} {_(message)}")
- with open(LOG_FILE, 'a') as f:
- f.write(_("[ERROR] {} {}").format(datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'), _(message)) + "\n")
-
-def log_debug(message):
- global _
- print(f"{BLUE}[DEBUG]{NC} {_(message)}")
- with open(LOG_FILE, 'a') as f:
- f.write(_("[DEBUG] {} {}").format(datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'), _(message)) + "\n")
-
-# 记录命令输出到日志文件
-# Log command output to log file
-def log_cmd_output(cmd, msg):
- global _
- with open(LOG_FILE, 'a') as f:
- f.write(_("[CMD] {} Executing command: {}").format(datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'), cmd) + "\n")
- f.write(_("[CMD] {}:").format(_(msg)) + "\n")
- process = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True)
- with open(LOG_FILE, 'a') as f:
- for line in process.stdout:
- print(line, end='')
- f.write(line)
- process.wait()
- with open(LOG_FILE, 'a') as f:
- f.write("\n")
-
-# 获取当前用户
-# Get current user
-def get_current_user():
- global _
- if os.geteuid() == 0:
- return os.environ.get('SUDO_USER', '')
- return getpass.getuser()
-
-CURRENT_USER = get_current_user()
-if not CURRENT_USER:
- log_error(_("Unable to get username"))
- sys.exit(1)
-
-# 定义Linux下的Cursor路径
-# Define Cursor paths on Linux
-CURSOR_CONFIG_DIR = os.path.expanduser("~/.config/Cursor")
-STORAGE_FILE = os.path.join(CURSOR_CONFIG_DIR, "User/globalStorage/storage.json")
-BACKUP_DIR = os.path.join(CURSOR_CONFIG_DIR, "User/globalStorage/backups")
-
-# 可能的Cursor二进制路径
-# Possible Cursor binary paths
-CURSOR_BIN_PATHS = [
- "/usr/bin/cursor",
- "/usr/local/bin/cursor",
- os.path.expanduser("~/.local/bin/cursor"),
- "/opt/cursor/cursor",
- "/snap/bin/cursor",
-]
-
-# 找到Cursor安装路径
-# Find Cursor installation path
-def find_cursor_path():
- global _
- log_info(_("Finding Cursor installation path..."))
-
- for path in CURSOR_BIN_PATHS:
- if os.path.isfile(path):
- log_info(_("Found Cursor installation path: {}").format(path))
- os.environ['CURSOR_PATH'] = path
- return True
-
- # 尝试通过which命令定位
- # Try locating via which command
- try:
- result = subprocess.run(['which', 'cursor'], capture_output=True, text=True)
- if result.returncode == 0:
- os.environ['CURSOR_PATH'] = result.stdout.strip()
- log_info(_("Found Cursor via which: {}").format(os.environ['CURSOR_PATH']))
- return True
- except subprocess.CalledProcessError:
- pass
-
- # 尝试查找可能的安装路径
- # Try finding possible installation paths
- search_dirs = ['/usr', '/opt', os.path.expanduser('~/.local')]
- for dir in search_dirs:
- try:
- for root, _1, files in os.walk(dir):
- if 'cursor' in files:
- path = os.path.join(root, 'cursor')
- if os.access(path, os.X_OK):
- os.environ['CURSOR_PATH'] = path
- log_info(_("Found Cursor via search: {}").format(os.environ['CURSOR_PATH']))
- return True
- except PermissionError:
- continue
- log_warn(_("Cursor executable not found, will try using config directory"))
- return False
-
-# 查找并定位Cursor资源文件目录
-# Find and locate Cursor resource directory
-def find_cursor_resources():
- global _
- log_info(_("Finding Cursor resource directory..."))
-
- # 可能的资源目录路径
- # Possible resource directory paths
- resource_paths = [
- "/usr/lib/cursor",
- "/usr/share/cursor",
- "/opt/cursor",
- os.path.expanduser("~/.local/share/cursor"),
- ]
-
- for path in resource_paths:
- if os.path.isdir(path):
- log_info(_("Found Cursor resource directory: {}").format(path))
- os.environ['CURSOR_RESOURCES'] = path
- return True
-
- # 如果有CURSOR_PATH,尝试从它推断
- # If CURSOR_PATH exists, try to infer from it
- if os.environ.get('CURSOR_PATH'):
- base_dir = os.path.dirname(os.environ['CURSOR_PATH'])
- resource_dir = os.path.join(base_dir, 'resources')
- if os.path.isdir(resource_dir):
- os.environ['CURSOR_RESOURCES'] = resource_dir
- log_info(_("Found resource directory via binary path: {}").format(os.environ['CURSOR_RESOURCES']))
- return True
-
- log_warn(_("Cursor resource directory not found"))
- return False
-
-# 检查权限
-# Check permissions
-def check_permissions():
- global _
- if os.geteuid() != 0:
- log_error(_("Please run this script with sudo"))
- print(_("Example: sudo {}").format(sys.argv[0]))
- sys.exit(1)
-
-# 检查并关闭 Cursor 进程
-# Check and kill Cursor processes
-def check_and_kill_cursor():
- global _
- log_info(_("Checking Cursor processes..."))
-
- attempt = 1
- max_attempts = 5
-
- # 函数:获取进程详细信息
- # Function: Get process details
- def get_process_details(process_name):
- log_debug(_("Getting process details for {}:").format(process_name))
- try:
- result = subprocess.run(
- 'ps aux | grep -i "cursor" | grep -v grep | grep -v "cursor_id_modifier.py"',
- shell=True, capture_output=True, text=True
- )
- print(result.stdout)
- except subprocess.CalledProcessError:
- pass
-
- while attempt <= max_attempts:
- # 使用更精确的匹配来获取 Cursor 进程,排除当前脚本和grep进程
- # Use more precise matching to get Cursor processes, excluding current script and grep
- try:
- result = subprocess.run(
- 'ps aux | grep -i "cursor" | grep -v "grep" | grep -v "cursor_id_modifier.py" | awk \'{print $2}\'',
- shell=True, capture_output=True, text=True
- )
- CURSOR_PIDS = result.stdout.strip().split('\n')
- CURSOR_PIDS = [pid for pid in CURSOR_PIDS if pid]
- except subprocess.CalledProcessError:
- CURSOR_PIDS = []
-
- if not CURSOR_PIDS:
- log_info(_("No running Cursor processes found"))
- return True
-
- log_warn(_("Found running Cursor processes"))
- get_process_details("cursor")
-
- log_warn(_("Attempting to terminate Cursor processes..."))
-
- for pid in CURSOR_PIDS:
- try:
- if attempt == max_attempts:
- log_warn(_("Attempting to forcefully terminate processes..."))
- os.kill(int(pid), signal.SIGKILL)
- else:
- os.kill(int(pid), signal.SIGTERM)
- except (OSError, ValueError):
- continue
-
- time.sleep(1)
-
- # 再次检查进程是否还在运行
- # Check again if processes are still running
- try:
- result = subprocess.run(
- 'ps aux | grep -i "cursor" | grep -v "grep" | grep -v "cursor_id_modifier.py"',
- shell=True, capture_output=True, text=True
- )
- if not result.stdout.strip():
- log_info(_("Cursor processes successfully terminated"))
- return True
- except subprocess.CalledProcessError:
- log_info(_("Cursor processes successfully terminated"))
- return True
-
- log_warn(_("Waiting for processes to terminate, attempt {}/{}...").format(attempt, max_attempts))
- attempt += 1
-
- log_error(_("Unable to terminate Cursor processes after {} attempts").format(max_attempts))
- get_process_details("cursor")
- log_error(_("Please manually terminate the processes and try again"))
- sys.exit(1)
-
-# 备份配置文件
-# Backup configuration file
-def backup_config():
- global _
- if not os.path.isfile(STORAGE_FILE):
- log_warn(_("Configuration file does not exist, skipping backup"))
- return True
-
- os.makedirs(BACKUP_DIR, exist_ok=True)
- backup_file = os.path.join(BACKUP_DIR, "storage.json.backup_{}".format(datetime.datetime.now().strftime('%Y%m%d_%H%M%S')))
-
- try:
- shutil.copy(STORAGE_FILE, backup_file)
- os.chmod(backup_file, 0o644)
- os.chown(backup_file, pwd.getpwnam(CURRENT_USER).pw_uid, -1)
- log_info(_("Configuration backed up to: {}").format(backup_file))
- except (OSError, shutil.Error):
- log_error(_("Backup failed"))
- sys.exit(1)
-
-# 生成随机 ID
-# Generate random ID
-def generate_random_id():
- global _
- # 生成32字节(64个十六进制字符)的随机数
- # Generate 32 bytes (64 hexadecimal characters) of random data
- return hashlib.sha256(os.urandom(32)).hexdigest()
-
-# 生成随机 UUID
-# Generate random UUID
-def generate_uuid():
- global _
- # 在Linux上使用uuid模块生成UUID
- # Use uuid module to generate UUID on Linux
- try:
- return str(uuid.uuid1()).lower()
- except Exception:
- # 备选方案:生成类似UUID的字符串
- # Fallback: Generate UUID-like string
- rand_bytes = os.urandom(16)
- rand_hex = rand_bytes.hex()
- return f"{rand_hex[:8]}-{rand_hex[8:12]}-{rand_hex[12:16]}-{rand_hex[16:20]}-{rand_hex[20:]}"
-
-# 修改现有文件
-# Modify or add to configuration file
-def modify_or_add_config(key, value, file):
- global _
- if not os.path.isfile(file):
- log_error(_("File does not exist: {}").format(file))
- return False
-
- # 确保文件可写
- # Ensure file is writable
- try:
- os.chmod(file, 0o644)
- except OSError:
- log_error(_("Unable to modify file permissions: {}").format(file))
- return False
-
- # 创建临时文件
- # Create temporary file
- with tempfile.NamedTemporaryFile(mode='w', delete=False) as temp_file:
- temp_path = temp_file.name
-
- # 读取原始文件
- # Read original file
- with open(file, 'r') as f:
- content = f.read()
-
- # 检查key是否存在
- # Check if key exists
- if f'"{key}":' in content:
- # key存在,执行替换
- # Key exists, perform replacement
- pattern = f'"{key}":\\s*"[^"]*"'
- replacement = f'"{key}": "{value}"'
- new_content = re.sub(pattern, replacement, content)
- else:
- # key不存在,添加新的key-value对
- # Key does not exist, add new key-value pair
- new_content = content.rstrip('}\n') + f',\n "{key}": "{value}"\n}}'
-
- # 写入临时文件
- # Write to temporary file
- with open(temp_path, 'w') as f:
- f.write(new_content)
-
- # 检查临时文件是否为空
- # Check if temporary file is empty
- if os.path.getsize(temp_path) == 0:
- log_error(_("Generated temporary file is empty"))
- os.unlink(temp_path)
- return False
-
- # 替换原文件
- # Replace original file
- try:
- shutil.move(temp_path, file)
- except OSError:
- log_error(_("Unable to write to file: {}").format(file))
- os.unlink(temp_path)
- return False
-
- # 恢复文件权限
- # Restore file permissions
- os.chmod(file, 0o444)
- return True
-
-# 生成新的配置
-# Generate new configuration
-def generate_new_config():
- global _
- print()
- log_warn(_("Machine code reset options"))
-
- # 使用菜单选择函数询问用户是否重置机器码
- # Use menu selection function to ask user whether to reset machine code
- reset_choice = select_menu_option(
- _("Do you need to reset the machine code? (Usually, modifying JS files is sufficient):"),
- [_("Don't reset - only modify JS files"), _("Reset - modify both config file and machine code")],
- 0
- )
-
- # 记录日志以便调试
- # Log for debugging
- with open(LOG_FILE, 'a') as f:
- f.write(_("[INPUT_DEBUG] Machine code reset option selected: {}").format(reset_choice) + "\n")
-
- # 处理用户选择
- # Handle user selection
- if reset_choice == 1:
- log_info(_("You chose to reset the machine code"))
-
- # 确保配置文件目录存在
- # Ensure configuration file directory exists
- if os.path.isfile(STORAGE_FILE):
- log_info(_("Found existing configuration file: {}").format(STORAGE_FILE))
-
- # 备份现有配置
- # Backup existing configuration
- backup_config()
-
- # 生成并设置新的设备ID
- # Generate and set new device ID
- new_device_id = generate_uuid()
- new_machine_id = "auth0|user_{}".format(hashlib.sha256(os.urandom(16)).hexdigest()[:32])
-
- log_info(_("Setting new device and machine IDs..."))
- log_debug(_("New device ID: {}").format(new_device_id))
- log_debug(_("New machine ID: {}").format(new_machine_id))
-
- # 修改配置文件
- # Modify configuration file
- if (modify_or_add_config("deviceId", new_device_id, STORAGE_FILE) and
- modify_or_add_config("machineId", new_machine_id, STORAGE_FILE)):
- log_info(_("Configuration file modified successfully"))
- else:
- log_error(_("Configuration file modification failed"))
- else:
- log_warn(_("Configuration file not found, this is normal, skipping ID modification"))
- else:
- log_info(_("You chose not to reset the machine code, will only modify JS files"))
-
- # 确保配置文件目录存在
- # Ensure configuration file directory exists
- if os.path.isfile(STORAGE_FILE):
- log_info(_("Found existing configuration file: {}").format(STORAGE_FILE))
-
- # 备份现有配置
- # Backup existing configuration
- backup_config()
- else:
- log_warn(_("Configuration file not found, this is normal, skipping ID modification"))
-
- print()
- log_info(_("Configuration processing completed"))
-
-# 查找Cursor的JS文件
-# Find Cursor's JS files
-def find_cursor_js_files():
- global _
- log_info(_("Finding Cursor's JS files..."))
-
- js_files = []
- found = False
-
- # 如果找到了资源目录,在资源目录中搜索
- # If resource directory is found, search in it
- if os.environ.get('CURSOR_RESOURCES'):
- log_debug(_("Searching for JS files in resource directory: {}").format(os.environ['CURSOR_RESOURCES']))
-
- # 在资源目录中递归搜索特定JS文件
- # Recursively search for specific JS files in resource directory
- js_patterns = [
- "*/extensionHostProcess.js",
- "*/main.js",
- "*/cliProcessMain.js",
- "*/app/out/vs/workbench/api/node/extensionHostProcess.js",
- "*/app/out/main.js",
- "*/app/out/vs/code/node/cliProcessMain.js",
- ]
-
- for pattern in js_patterns:
- try:
- files = glob.glob(os.path.join(os.environ['CURSOR_RESOURCES'], pattern), recursive=True)
- for file in files:
- log_info(_("Found JS file: {}").format(file))
- js_files.append(file)
- found = True
- except Exception:
- continue
-
- # 如果还没找到,尝试在/usr和$HOME目录下搜索
- # If not found, try searching in /usr and $HOME directories
- if not found:
- log_warn(_("No JS files found in resource directory, trying other directories..."))
-
- search_dirs = [
- "/usr/lib/cursor",
- "/usr/share/cursor",
- "/opt/cursor",
- os.path.expanduser("~/.config/Cursor"),
- os.path.expanduser("~/.local/share/cursor"),
- ]
-
- for dir in search_dirs:
- if os.path.isdir(dir):
- log_debug(_("Searching directory: {}").format(dir))
- try:
- for root, _1, files in os.walk(dir):
- for file in files:
- if file.endswith('.js'):
- file_path = os.path.join(root, file)
- with open(file_path, 'r', errors='ignore') as f:
- content = f.read()
- if "IOPlatformUUID" in content or "x-cursor-checksum" in content:
- log_info(_("Found JS file: {}").format(file_path))
- js_files.append(file_path)
- found = True
- except Exception:
- continue
-
- if not found:
- log_error(_("No modifiable JS files found"))
- return False, []
-
- # 保存找到的文件列表到环境变量
- # Save found files to environment variable
- os.environ['CURSOR_JS_FILES'] = json.dumps(js_files)
- log_info(_("Found {} JS files to modify").format(len(js_files)))
- return True, js_files
-
-# 修改Cursor的JS文件
-# Modify Cursor's JS files
-def modify_cursor_js_files():
- global _
- log_info(_("Starting to modify Cursor's JS files..."))
-
- # 先查找需要修改的JS文件
- # First find JS files to modify
- success, js_files = find_cursor_js_files()
- if not success:
- log_error(_("Unable to find modifiable JS files"))
- return False
-
- modified_count = 0
-
- for file in js_files:
- log_info(_("Processing file: {}").format(file))
-
- # 创建文件备份
- # Create file backup
- backup_file = f"{file}.backup_{datetime.datetime.now().strftime('%Y%m%d%H%M%S')}"
- try:
- shutil.copy(file, backup_file)
- except OSError:
- log_error(_("Unable to create backup for file: {}").format(file))
- continue
-
- # 确保文件可写
- # Ensure file is writable
- try:
- os.chmod(file, 0o644)
- except OSError:
- log_error(_("Unable to modify file permissions: {}").format(file))
- continue
-
- # 读取文件内容
- # Read file content
- with open(file, 'r', errors='ignore') as f:
- content = f.read()
-
- # 检查文件内容并进行相应修改
- # Check file content and make appropriate modifications
- if 'i.header.set("x-cursor-checksum' in content:
- log_debug(_("Found x-cursor-checksum setting code"))
- new_content = content.replace(
- 'i.header.set("x-cursor-checksum",e===void 0?`${p}${t}`:`${p}${t}/${e}`)',
- 'i.header.set("x-cursor-checksum",e===void 0?`${p}${t}`:`${p}${t}/${p}`)'
- )
- if new_content != content:
- with open(file, 'w') as f:
- f.write(new_content)
- log_info(_("Successfully modified x-cursor-checksum setting code"))
- modified_count += 1
- else:
- log_error(_("Failed to modify x-cursor-checksum setting code"))
- shutil.copy(backup_file, file)
- elif "IOPlatformUUID" in content:
- log_debug(_("Found IOPlatformUUID keyword"))
- if "function a$" in content and "return crypto.randomUUID()" not in content:
- new_content = content.replace(
- "function a$(t){switch",
- "function a$(t){return crypto.randomUUID(); switch"
- )
- if new_content != content:
- with open(file, 'w') as f:
- f.write(new_content)
- log_debug(_("Successfully injected randomUUID call into a$ function"))
- modified_count += 1
- else:
- log_error(_("Failed to modify a$ function"))
- shutil.copy(backup_file, file)
- elif "async function v5" in content and "return crypto.randomUUID()" not in content:
- new_content = content.replace(
- "async function v5(t){let e=",
- "async function v5(t){return crypto.randomUUID(); let e="
- )
- if new_content != content:
- with open(file, 'w') as f:
- f.write(new_content)
- log_debug(_("Successfully injected randomUUID call into v5 function"))
- modified_count += 1
- else:
- log_error(_("Failed to modify v5 function"))
- shutil.copy(backup_file, file)
- else:
- # 通用注入方法
- # Universal injection method
- if "// Cursor ID 修改工具注入" not in content:
- timestamp = datetime.datetime.now().strftime('%s')
- datetime_s = datetime.datetime.now().strftime('%Y%m%d%H%M%S')
- inject_code = f"""
-// Cursor ID 修改工具注入 - {datetime_s}
-// 随机设备ID生成器注入 - {timestamp}
-const randomDeviceId_{timestamp} = () => {{
- try {{
- return require('crypto').randomUUID();
- }} catch (e) {{
- return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => {{
- const r = Math.random() * 16 | 0;
- return (c === 'x' ? r : (r & 0x3 | 0x8)).toString(16);
- }});
- }}
-}};
-"""
- # NOTE: double {{ or }} is literal, so code matches:
- old_bash_inject_code = """
-// Cursor ID 修改工具注入 - $(date +%Y%m%d%H%M%S)
-// 随机设备ID生成器注入 - $(date +%s)
-const randomDeviceId_$(date +%s) = () => {
- try {
- return require('crypto').randomUUID();
- } catch (e) {
- return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => {
- const r = Math.random() * 16 | 0;
- return (c === 'x' ? r : (r & 0x3 | 0x8)).toString(16);
- });
- }
-};
-"""
- new_content = inject_code + content
- new_content = new_content.replace(f"await v5(!1)", f"randomDeviceId_{timestamp}()")
- new_content = new_content.replace(f"a$(t)", f"randomDeviceId_{timestamp}()")
- with open(file, 'w') as f:
- f.write(new_content)
- log_debug(_("Completed universal modification"))
- modified_count += 1
- else:
- log_info(_("File already contains custom injection code, skipping modification"))
- else:
- # 未找到关键字,尝试通用方法
- # No keywords found, try universal method
- if "return crypto.randomUUID()" not in content and "// Cursor ID 修改工具注入" not in content:
- if "function t$()" in content or "async function y5" in content:
- new_content = content
- if "function t$()" in new_content:
- new_content = new_content.replace(
- "function t$(){",
- 'function t$(){return "00:00:00:00:00:00";'
- )
- if "async function y5" in new_content:
- new_content = new_content.replace(
- "async function y5(t){",
- "async function y5(t){return crypto.randomUUID();"
- )
- if new_content != content:
- with open(file, 'w') as f:
- f.write(new_content)
- modified_count += 1
- else:
- # 最通用的注入方法
- # Most universal injection method
- new_uuid = generate_uuid()
- machine_id = f"auth0|user_{hashlib.sha256(os.urandom(16)).hexdigest()[:32]}"
- device_id = generate_uuid()
- mac_machine_id = hashlib.sha256(os.urandom(32)).hexdigest()
- timestamp = datetime.datetime.now().strftime('%s')
- datetime_s = datetime.datetime.now().strftime('%Y%m%d%H%M%S')
- inject_universal_code = f"""
-// Cursor ID 修改工具注入 - {datetime_s}
-// 全局拦截设备标识符 - {timestamp}
-const originalRequire_{timestamp} = require;
-require = function(module) {{
- const result = originalRequire_{timestamp}(module);
- if (module === 'crypto' && result.randomUUID) {{
- const originalRandomUUID_{timestamp} = result.randomUUID;
- result.randomUUID = function() {{
- return '{new_uuid}';
- }};
- }}
- return result;
-}};
-
-// 覆盖所有可能的系统ID获取函数
-global.getMachineId = function() {{ return '{machine_id}'; }};
-global.getDeviceId = function() {{ return '{device_id}'; }};
-global.macMachineId = '{mac_machine_id}';
-"""
- # NOTE: Double {{ or }} is literal, so matches:
- old_bash_inject_code = """
-// Cursor ID 修改工具注入 - $(date +%Y%m%d%H%M%S)
-// 全局拦截设备标识符 - $(date +%s)
-const originalRequire_$(date +%s) = require;
-require = function(module) {
- const result = originalRequire_$(date +%s)(module);
- if (module === 'crypto' && result.randomUUID) {
- const originalRandomUUID_$(date +%s) = result.randomUUID;
- result.randomUUID = function() {
- return '$new_uuid';
- };
- }
- return result;
-};
-
-// 覆盖所有可能的系统ID获取函数
-global.getMachineId = function() { return '$machine_id'; };
-global.getDeviceId = function() { return '$device_id'; };
-global.macMachineId = '$mac_machine_id';
-"""
- new_content = inject_universal_code + content
- with open(file, 'w') as f:
- f.write(new_content)
- log_debug(_("Completed most universal injection"))
- modified_count += 1
- else:
- log_info(_("File has already been modified, skipping modification"))
-
- # 恢复文件权限
- # Restore file permissions
- os.chmod(file, 0o444)
-
- if modified_count == 0:
- log_error(_("Failed to modify any JS files"))
- return False
-
- log_info(_("Successfully modified {} JS files").format(modified_count))
- return True
-
-# 获取网络接口列表
-# Get network interface list
-def get_network_interfaces():
- global _
- if NETIFACES_AVAILABLE:
- try:
- # 使用netifaces库
- # Use netifaces library
- interfaces = netifaces.interfaces()
- # 过滤掉回环接口
- # Filter out loopback interfaces
- return [iface for iface in interfaces if not iface.startswith('lo')]
- except Exception:
- pass
-
- # 如果netifaces不可用或失败,使用系统命令
- # If netifaces is not available or failed, use system commands
- try:
- result = subprocess.run(['ip', 'link', 'show'], capture_output=True, text=True)
- interfaces = []
- for line in result.stdout.split('\n'):
- if ': ' in line and 'state' in line.lower():
- iface_name = line.split(': ')[1].split('@')[0]
- if not iface_name.startswith('lo'):
- interfaces.append(iface_name)
- return interfaces
- except subprocess.CalledProcessError:
- # 最后的备选方案
- # Last fallback option
- try:
- result = subprocess.run(['ls', '/sys/class/net/'], capture_output=True, text=True)
- interfaces = result.stdout.strip().split('\n')
- return [iface for iface in interfaces if not iface.startswith('lo')]
- except subprocess.CalledProcessError:
- log_error(_("Unable to get network interface list"))
- return []
-
-# 生成随机MAC地址
-# Generate random MAC address
-def generate_random_mac():
- global _
- # 生成随机MAC地址,确保第一个字节的最低位为0(单播地址)
- # Generate random MAC address, ensure the lowest bit of first byte is 0 (unicast address)
- mac = [0x00, 0x16, 0x3e,
- random.randint(0x00, 0x7f),
- random.randint(0x00, 0xff),
- random.randint(0x00, 0xff)]
- return ':'.join(map(lambda x: "%02x" % x, mac))
-
-# 获取当前MAC地址
-# Get current MAC address
-def get_current_mac(interface):
- global _
- if NETIFACES_AVAILABLE:
- try:
- # 使用netifaces库
- # Use netifaces library
- addrs = netifaces.ifaddresses(interface)
- if netifaces.AF_LINK in addrs:
- return addrs[netifaces.AF_LINK][0]['addr']
- except Exception:
- pass
-
- # 使用系统命令获取MAC地址
- # Use system command to get MAC address
- try:
- result = subprocess.run(['cat', f'/sys/class/net/{interface}/address'],
- capture_output=True, text=True)
- if result.returncode == 0:
- return result.stdout.strip()
- except subprocess.CalledProcessError:
- pass
-
- # 备选方案:使用ip命令
- # Fallback: use ip command
- try:
- result = subprocess.run(['ip', 'link', 'show', interface],
- capture_output=True, text=True)
- for line in result.stdout.split('\n'):
- if 'link/ether' in line:
- return line.split()[1]
- except subprocess.CalledProcessError:
- pass
-
- return None
-
-# 修改MAC地址
-# Modify MAC address
-def modify_mac_address():
- global _
- log_info(_("Starting MAC address modification..."))
-
- # 获取网络接口列表
- # Get network interface list
- interfaces = get_network_interfaces()
- if not interfaces:
- log_error(_("No network interfaces found"))
- return False
-
- log_info(_("Found network interfaces: {}").format(', '.join(interfaces)))
-
- # 选择要修改的接口(通常选择第一个非回环接口)
- # Select interface to modify (usually the first non-loopback interface)
- target_interface = None
- for iface in interfaces:
- # 优先选择以太网接口
- # Prefer ethernet interfaces
- if any(prefix in iface.lower() for prefix in ['eth', 'enp', 'ens', 'enx']):
- target_interface = iface
- break
-
- # 如果没有找到以太网接口,选择第一个可用接口
- # If no ethernet interface found, select first available interface
- if not target_interface and interfaces:
- target_interface = interfaces[0]
-
- if not target_interface:
- log_error(_("No suitable network interface found"))
- return False
-
- log_info(_("Selected network interface: {}").format(target_interface))
-
- # 获取当前MAC地址
- # Get current MAC address
- current_mac = get_current_mac(target_interface)
- if current_mac:
- log_info(_("Current MAC address: {}").format(current_mac))
-
- # 备份当前MAC地址
- # Backup current MAC address
- backup_file = os.path.join(BACKUP_DIR, f"original_mac_{target_interface}.txt")
- try:
- os.makedirs(BACKUP_DIR, exist_ok=True)
- with open(backup_file, 'w') as f:
- f.write(f"{target_interface}:{current_mac}\n")
- log_info(_("Original MAC address backed up to: {}").format(backup_file))
- except OSError:
- log_warn(_("Failed to backup original MAC address"))
- else:
- log_warn(_("Unable to get current MAC address"))
-
- # 生成新的MAC地址
- # Generate new MAC address
- new_mac = generate_random_mac()
- log_info(_("Generated new MAC address: {}").format(new_mac))
-
- # 修改MAC地址
- # Modify MAC address
- success = False
-
- # 方法1:使用ip命令
- # Method 1: Use ip command
- try:
- log_debug(_("Attempting to modify MAC address using ip command..."))
-
- # 先关闭接口
- # First bring down the interface
- subprocess.run(['ip', 'link', 'set', 'dev', target_interface, 'down'],
- check=True, capture_output=True)
-
- # 修改MAC地址
- # Modify MAC address
- subprocess.run(['ip', 'link', 'set', 'dev', target_interface, 'address', new_mac],
- check=True, capture_output=True)
-
- # 重新启用接口
- # Bring up the interface
- subprocess.run(['ip', 'link', 'set', 'dev', target_interface, 'up'],
- check=True, capture_output=True)
-
- success = True
- log_info(_("Successfully modified MAC address using ip command"))
-
- except subprocess.CalledProcessError as e:
- log_warn(_("Failed to modify MAC address using ip command: {}").format(str(e)))
-
- # 方法2:使用ifconfig命令(备选方案)
- # Method 2: Use ifconfig command (fallback)
- if not success:
- try:
- log_debug(_("Attempting to modify MAC address using ifconfig command..."))
-
- # 先关闭接口
- # First bring down the interface
- subprocess.run(['ifconfig', target_interface, 'down'],
- check=True, capture_output=True)
-
- # 修改MAC地址
- # Modify MAC address
- subprocess.run(['ifconfig', target_interface, 'hw', 'ether', new_mac],
- check=True, capture_output=True)
-
- # 重新启用接口
- # Bring up the interface
- subprocess.run(['ifconfig', target_interface, 'up'],
- check=True, capture_output=True)
-
- success = True
- log_info(_("Successfully modified MAC address using ifconfig command"))
-
- except subprocess.CalledProcessError as e:
- log_warn(_("Failed to modify MAC address using ifconfig command: {}").format(str(e)))
-
- # 验证MAC地址修改
- # Verify MAC address modification
- if success:
- time.sleep(2) # 等待网络接口稳定
- # Wait for network interface to stabilize
-
- new_current_mac = get_current_mac(target_interface)
- if new_current_mac and new_current_mac.lower() == new_mac.lower():
- log_info(_("MAC address modification verified successfully"))
- log_info(_("New MAC address: {}").format(new_current_mac))
-
- # 保存新MAC地址信息
- # Save new MAC address information
- new_mac_file = os.path.join(BACKUP_DIR, f"new_mac_{target_interface}.txt")
- try:
- with open(new_mac_file, 'w') as f:
- f.write(f"{target_interface}:{new_current_mac}\n")
- f.write(f"Modified at: {datetime.datetime.now()}\n")
- log_info(_("New MAC address information saved to: {}").format(new_mac_file))
- except OSError:
- log_warn(_("Failed to save new MAC address information"))
-
- return True
- else:
- log_error(_("MAC address modification verification failed"))
- log_error(_("Expected: {}, Actual: {}").format(new_mac, new_current_mac))
- return False
- else:
- log_error(_("All MAC address modification methods failed"))
- log_error(_("Please check if you have sufficient permissions or try running with sudo"))
- return False
-
-# 禁用自动更新
-# Disable auto-update
-def disable_auto_update():
- global _
- log_info(_("Disabling Cursor auto-update..."))
-
- # 查找可能的更新配置文件
- # Find possible update configuration files
- update_configs = [
- os.path.join(CURSOR_CONFIG_DIR, "update-config.json"),
- os.path.expanduser("~/.local/share/cursor/update-config.json"),
- "/opt/cursor/resources/app-update.yml",
- ]
-
- disabled = False
-
- for config in update_configs:
- if os.path.isfile(config):
- log_info(_("Found update configuration file: {}").format(config))
- try:
- shutil.copy(config, f"{config}.bak")
- with open(config, 'w') as f:
- json.dump({"autoCheck": False, "autoDownload": False}, f)
- os.chmod(config, 0o444)
- log_info(_("Disabled update configuration file: {}").format(config))
- disabled = True
- except (OSError, shutil.Error):
- continue
-
- # 尝试查找updater可执行文件并禁用
- # Try to find and disable updater executable
- updater_paths = [
- os.path.join(CURSOR_CONFIG_DIR, "updater"),
- "/opt/cursor/updater",
- "/usr/lib/cursor/updater",
- ]
-
- for updater in updater_paths:
- if os.path.exists(updater):
- log_info(_("Found updater: {}").format(updater))
- try:
- if os.path.isfile(updater):
- shutil.move(updater, f"{updater}.bak")
- else:
- Path(f"{updater}.disabled").touch()
- log_info(_("Disabled updater: {}").format(updater))
- disabled = True
- except (OSError, shutil.Error):
- continue
-
- if not disabled:
- log_warn(_("No update configuration files or updaters found"))
- else:
- log_info(_("Successfully disabled auto-update"))
-
-# 新增:通用菜单选择函数
-# New: Universal menu selection function
-def select_menu_option(prompt, options, default_index=0):
- global _
- # 保存终端设置
- # Save terminal settings
- old_settings = termios.tcgetattr(sys.stdin)
- selected_index = default_index
-
- try:
- # 设置终端为非缓冲模式
- # Set terminal to non-buffered mode
- tty.setcbreak(sys.stdin.fileno())
-
- # 显示提示信息
- # Display prompt
- print(_(prompt))
-
- # 第一次显示菜单
- # Display menu initially
- for i, option in enumerate(options):
- if i == selected_index:
- print(f" {GREEN}►{NC} {_(option)}")
- else:
- print(f" {_(option)}")
-
- while True:
- # 读取键盘输入
- # Read keyboard input
- rlist, _1, _2 = select.select([sys.stdin], [], [], 0.1)
- if rlist:
- key = sys.stdin.read(1)
- # 上箭头键
- # Up arrow key
- if key == '\033':
- next_char = sys.stdin.read(2)
- if next_char == '[A' and selected_index > 0:
- selected_index -= 1
- # 下箭头键
- # Down arrow key
- elif next_char == '[B' and selected_index < len(options) - 1:
- selected_index += 1
- # Enter键
- # Enter key
- elif key == '\n':
- print()
- log_info(_("You selected: {}").format(options[selected_index]))
- return selected_index
-
- # 清除当前菜单
- # Clear current menu
- sys.stdout.write('\033[{}A\033[J'.format(len(options) + 1))
- sys.stdout.flush()
-
- # 重新显示提示和菜单
- # Redisplay prompt and menu
- print(_(prompt))
- for i, option in enumerate(options):
- if i == selected_index:
- print(f" {GREEN}►{NC} {_(option)}")
- else:
- print(f" {_(option)}")
- sys.stdout.flush()
-
- finally:
- # 恢复终端设置
- # Restore terminal settings
- termios.tcsetattr(sys.stdin, termios.TCSADRAIN, old_settings)
-
-# 主函数
-# Main function
-def main():
- global _
- # 检查系统环境
- # Check system environment
- if sys.platform != "linux":
- log_error(_("This script only supports Linux systems"))
- sys.exit(1)
-
- # 初始化日志文件
- # Initialize log file
- initialize_log()
- log_info(_("Script started..."))
-
- # 记录系统信息
- # Log system information
- log_info(_("System information: {}").format(subprocess.getoutput("uname -a")))
- log_info(_("Current user: {}").format(CURRENT_USER))
- log_cmd_output(
- "lsb_release -a 2>/dev/null || cat /etc/*release 2>/dev/null || cat /etc/issue",
- _("System version information")
- )
-
- # 清除终端
- # Clear terminal
- os.system('clear')
-
- # 显示 Logo
- # Display Logo
- print("""
- ██████╗██╗ ██╗██████╗ ███████╗ ██████╗ ██████╗
- ██╔════╝██║ ██║██╔══██╗██╔════╝██╔═══██╗██╔══██╗
- ██║ ██║ ██║██████╔╝███████╗██║ ██║██████╔╝
- ██║ ██║ ██║██╔══██╗╚════██║██║ ██║██╔══██╗
- ╚██████╗╚██████╔╝██║ ██║███████║╚██████╔╝██║ ██║
- ╚═════╝ ╚═════╝ ╚═╝ ╚═╝╚══════╝ ╚═════╝ ╚═╝ ╚═╝
- """)
- print(f"{BLUE}================================{NC}")
- print(f"{GREEN} {_('Cursor Linux startup tool')} {NC}")
- print(f"{BLUE}================================{NC}")
- print()
- print(f"{YELLOW}[{_('Important notice')}] {NC} {_('This tool prioritizes modifying JS files, which is safer and more reliable')}")
- print()
-
- # 执行主要功能
- # Execute main functions
- check_permissions()
- find_cursor_path()
- find_cursor_resources()
- check_and_kill_cursor()
- backup_config()
- generate_new_config()
-
- # 修改JS文件
- # Modify JS files
- log_info(_("Modifying Cursor JS files..."))
- js_success = modify_cursor_js_files()
- if js_success:
- log_info(_("JS files modified successfully!"))
- else:
- log_warn(_("JS file modification failed, but configuration file modification may have succeeded"))
- log_warn(_("If Cursor still indicates the device is disabled after restarting, please rerun this script"))
-
- # 修改MAC地址
- # Modify MAC address
- log_info(_("Modifying system MAC address..."))
- mac_success = modify_mac_address()
- if mac_success:
- log_info(_("MAC address modified successfully!"))
- else:
- log_warn(_("MAC address modification failed"))
- log_warn(_("This may affect the effectiveness of device identification bypass"))
-
- # 禁用自动更新
- # Disable auto-update
- disable_auto_update()
-
- # 显示修改结果总结
- # Display modification result summary
- print()
- print(f"{GREEN}================================{NC}")
- print(f"{BLUE} {_('Modification Results Summary')} {NC}")
- print(f"{GREEN}================================{NC}")
-
- if js_success:
- print(f"{GREEN}✓{NC} {_('JS files modification: SUCCESS')}")
- else:
- print(f"{RED}✗{NC} {_('JS files modification: FAILED')}")
-
- if mac_success:
- print(f"{GREEN}✓{NC} {_('MAC address modification: SUCCESS')}")
- else:
- print(f"{RED}✗{NC} {_('MAC address modification: FAILED')}")
-
- print(f"{GREEN}================================{NC}")
- print()
-
- log_info(_("Please restart Cursor to apply the new configuration"))
-
- # 显示最后的提示信息
- # Display final prompt
- print()
- print(f"{GREEN}================================{NC}")
- print(f"{YELLOW} {_('Follow the WeChat public account [Pancake AI] to discuss more Cursor tips and AI knowledge (script is free, join the group via the public account for more tips and experts)')} {NC}")
- print("WeChat account: [煎饼果子卷AI]")
- print(f"{GREEN}================================{NC}")
- print()
-
- # 记录脚本完成信息
- # Log script completion information
- log_info(_("Script execution completed"))
- with open(LOG_FILE, 'a') as f:
- f.write(_("========== Cursor ID modification tool log end {} ==========").format(datetime.datetime.now()) + "\n")
-
- # 显示日志文件位置
- # Display log file location
- print()
- log_info(_("Detailed log saved to: {}").format(LOG_FILE))
- print(_("If you encounter issues, please provide this log file to the developer for troubleshooting"))
- print()
-
-if __name__ == "__main__":
- main()
\ No newline at end of file
diff --git a/scripts/git-actions.sh b/scripts/git-actions.sh
deleted file mode 100755
index 632e312..0000000
--- a/scripts/git-actions.sh
+++ /dev/null
@@ -1,9 +0,0 @@
-#!/bin/bash
-REPO_DIR="$PWD"
-LOCALES_DIR="$REPO_DIR/locales"
-msginit -i cursor_id_modifier.pot -o $LOCALES_DIR/en_US/LC_MESSAGES/cursor_id_modifier.po -l en_US
-for lang in en_US zh_CN; do
- cd $LOCALES_DIR/$lang/LC_MESSAGES
- msgfmt -o cursor_id_modifier.mo cursor_id_modifier.po
-done
-
diff --git a/scripts/install.ps1 b/scripts/install.ps1
deleted file mode 100644
index b30350b..0000000
--- a/scripts/install.ps1
+++ /dev/null
@@ -1,193 +0,0 @@
-# Check for admin rights and handle elevation
-$isAdmin = ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")
-if (-NOT $isAdmin) {
- # Detect PowerShell version and path
- $pwshPath = if (Get-Command "pwsh" -ErrorAction SilentlyContinue) {
- (Get-Command "pwsh").Source # PowerShell 7+
- } elseif (Test-Path "$env:ProgramFiles\PowerShell\7\pwsh.exe") {
- "$env:ProgramFiles\PowerShell\7\pwsh.exe"
- } else {
- "powershell.exe" # Windows PowerShell
- }
-
- try {
- Write-Host "`nRequesting administrator privileges..." -ForegroundColor Cyan
- $scriptPath = $MyInvocation.MyCommand.Path
- $argList = "-NoProfile -ExecutionPolicy Bypass -File `"$scriptPath`""
- Start-Process -FilePath $pwshPath -Verb RunAs -ArgumentList $argList -Wait
- exit
- }
- catch {
- Write-Host "`nError: Administrator privileges required" -ForegroundColor Red
- Write-Host "Please run this script from an Administrator PowerShell window" -ForegroundColor Yellow
- Write-Host "`nTo do this:" -ForegroundColor Cyan
- Write-Host "1. Press Win + X" -ForegroundColor White
- Write-Host "2. Click 'Windows Terminal (Admin)' or 'PowerShell (Admin)'" -ForegroundColor White
- Write-Host "3. Run the installation command again" -ForegroundColor White
- Write-Host "`nPress enter to exit..."
- $null = $Host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown')
- exit 1
- }
-}
-
-# Set TLS to 1.2
-[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
-
-# Create temporary directory
-$TmpDir = Join-Path $env:TEMP ([System.Guid]::NewGuid().ToString())
-New-Item -ItemType Directory -Path $TmpDir | Out-Null
-
-# Cleanup function
-function Cleanup {
- if (Test-Path $TmpDir) {
- Remove-Item -Recurse -Force $TmpDir
- }
-}
-
-# Error handler
-trap {
- Write-Host "Error: $_" -ForegroundColor Red
- Cleanup
- Write-Host "Press enter to exit..."
- $null = $Host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown')
- exit 1
-}
-
-# Detect system architecture
-function Get-SystemArch {
- if ([Environment]::Is64BitOperatingSystem) {
- return "x86_64"
- } else {
- return "i386"
- }
-}
-
-# Download with progress
-function Get-FileWithProgress {
- param (
- [string]$Url,
- [string]$OutputFile
- )
-
- try {
- $webClient = New-Object System.Net.WebClient
- $webClient.Headers.Add("User-Agent", "PowerShell Script")
-
- $webClient.DownloadFile($Url, $OutputFile)
- return $true
- }
- catch {
- Write-Host "Failed to download: $_" -ForegroundColor Red
- return $false
- }
-}
-
-# Main installation function
-function Install-CursorModifier {
- Write-Host "Starting installation..." -ForegroundColor Cyan
-
- # Detect architecture
- $arch = Get-SystemArch
- Write-Host "Detected architecture: $arch" -ForegroundColor Green
-
- # Set installation directory
- $InstallDir = "$env:ProgramFiles\CursorModifier"
- if (!(Test-Path $InstallDir)) {
- New-Item -ItemType Directory -Path $InstallDir | Out-Null
- }
-
- # Get latest release
- try {
- $latestRelease = Invoke-RestMethod -Uri "https://api.github.com/repos/yuaotian/go-cursor-help/releases/latest"
- Write-Host "Found latest release: $($latestRelease.tag_name)" -ForegroundColor Cyan
-
- # Look for Windows binary with our architecture
- $version = $latestRelease.tag_name.TrimStart('v')
- Write-Host "Version: $version" -ForegroundColor Cyan
- $possibleNames = @(
- "cursor-id-modifier_${version}_windows_x86_64.exe",
- "cursor-id-modifier_${version}_windows_$($arch).exe"
- )
-
- $asset = $null
- foreach ($name in $possibleNames) {
- Write-Host "Checking for asset: $name" -ForegroundColor Cyan
- $asset = $latestRelease.assets | Where-Object { $_.name -eq $name }
- if ($asset) {
- Write-Host "Found matching asset: $($asset.name)" -ForegroundColor Green
- break
- }
- }
-
- if (!$asset) {
- Write-Host "`nAvailable assets:" -ForegroundColor Yellow
- $latestRelease.assets | ForEach-Object { Write-Host "- $($_.name)" }
- throw "Could not find appropriate Windows binary for $arch architecture"
- }
-
- $downloadUrl = $asset.browser_download_url
- }
- catch {
- Write-Host "Failed to get latest release: $_" -ForegroundColor Red
- exit 1
- }
-
- # Download binary
- Write-Host "`nDownloading latest release..." -ForegroundColor Cyan
- $binaryPath = Join-Path $TmpDir "cursor-id-modifier.exe"
-
- if (!(Get-FileWithProgress -Url $downloadUrl -OutputFile $binaryPath)) {
- exit 1
- }
-
- # Install binary
- Write-Host "Installing..." -ForegroundColor Cyan
- try {
- Copy-Item -Path $binaryPath -Destination "$InstallDir\cursor-id-modifier.exe" -Force
-
- # Add to PATH if not already present
- $currentPath = [Environment]::GetEnvironmentVariable("Path", "Machine")
- if ($currentPath -notlike "*$InstallDir*") {
- [Environment]::SetEnvironmentVariable("Path", "$currentPath;$InstallDir", "Machine")
- }
- }
- catch {
- Write-Host "Failed to install: $_" -ForegroundColor Red
- exit 1
- }
-
- Write-Host "Installation completed successfully!" -ForegroundColor Green
- Write-Host "Running cursor-id-modifier..." -ForegroundColor Cyan
-
- # Run the program
- try {
- & "$InstallDir\cursor-id-modifier.exe"
- if ($LASTEXITCODE -ne 0) {
- Write-Host "Failed to run cursor-id-modifier" -ForegroundColor Red
- exit 1
- }
- }
- catch {
- Write-Host "Failed to run cursor-id-modifier: $_" -ForegroundColor Red
- exit 1
- }
-}
-
-# Run installation
-try {
- Install-CursorModifier
-}
-catch {
- Write-Host "Installation failed: $_" -ForegroundColor Red
- Cleanup
- Write-Host "Press enter to exit..."
- $null = $Host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown')
- exit 1
-}
-finally {
- Cleanup
- if ($LASTEXITCODE -ne 0) {
- Write-Host "Press enter to exit..." -ForegroundColor Green
- $null = $Host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown')
- }
-}
\ No newline at end of file
diff --git a/scripts/install.sh b/scripts/install.sh
deleted file mode 100755
index adc7881..0000000
--- a/scripts/install.sh
+++ /dev/null
@@ -1,127 +0,0 @@
-#!/bin/bash
-
-set -e
-
-# Colors for output
-RED='\033[0;31m'
-GREEN='\033[0;32m'
-BLUE='\033[0;36m'
-YELLOW='\033[0;33m'
-NC='\033[0m'
-
-# Temporary directory for downloads
-TMP_DIR=$(mktemp -d)
-trap 'rm -rf "$TMP_DIR"' EXIT
-
-# Check for required commands
-check_requirements() {
- if ! command -v curl >/dev/null 2>&1; then
- echo -e "${RED}Error: curl is required${NC}"
- exit 1
- fi
-}
-
-# Detect system information
-detect_system() {
- local os arch suffix
-
- case "$(uname -s)" in
- Linux*) os="linux";;
- Darwin*) os="darwin";;
- *) echo -e "${RED}Unsupported OS${NC}"; exit 1;;
- esac
-
- case "$(uname -m)" in
- x86_64)
- arch="x86_64"
- ;;
- aarch64|arm64)
- arch="arm64"
- ;;
- i386|i686)
- arch="i386"
- ;;
- *) echo -e "${RED}Unsupported architecture${NC}"; exit 1;;
- esac
-
- echo "$os $arch"
-}
-
-# Download with progress
-download() {
- local url="$1"
- local output="$2"
- curl -#L "$url" -o "$output"
-}
-
-# Check and create installation directory
-setup_install_dir() {
- local install_dir="$1"
-
- if [ ! -d "$install_dir" ]; then
- mkdir -p "$install_dir" || {
- echo -e "${RED}Failed to create installation directory${NC}"
- exit 1
- }
- fi
-}
-
-# Main installation function
-main() {
- check_requirements
-
- echo -e "${BLUE}Starting installation...${NC}"
-
- # Detect system
- read -r OS ARCH SUFFIX <<< "$(detect_system)"
- echo -e "${GREEN}Detected: $OS $ARCH${NC}"
-
- # Set installation directory
- INSTALL_DIR="/usr/local/bin"
-
- # Setup installation directory
- setup_install_dir "$INSTALL_DIR"
-
- # Get latest release info
- echo -e "${BLUE}Fetching latest release information...${NC}"
- LATEST_URL="https://api.github.com/repos/yuaotian/go-cursor-help/releases/latest"
-
- # Get latest version and remove 'v' prefix
- VERSION=$(curl -s "$LATEST_URL" | grep "tag_name" | cut -d'"' -f4 | sed 's/^v//')
-
- # Construct binary name
- BINARY_NAME="cursor-id-modifier_${VERSION}_${OS}_${ARCH}"
- echo -e "${BLUE}Looking for asset: $BINARY_NAME${NC}"
-
- # Get download URL directly
- DOWNLOAD_URL=$(curl -s "$LATEST_URL" | grep -o "\"browser_download_url\": \"[^\"]*${BINARY_NAME}[^\"]*\"" | cut -d'"' -f4)
-
- if [ -z "$DOWNLOAD_URL" ]; then
- echo -e "${RED}Error: Could not find appropriate binary for $OS $ARCH${NC}"
- echo -e "${YELLOW}Available assets:${NC}"
- curl -s "$LATEST_URL" | grep "browser_download_url" | cut -d'"' -f4
- exit 1
- fi
-
- echo -e "${GREEN}Found matching asset: $BINARY_NAME${NC}"
- echo -e "${BLUE}Downloading from: $DOWNLOAD_URL${NC}"
-
- download "$DOWNLOAD_URL" "$TMP_DIR/cursor-id-modifier"
-
- # Install binary
- echo -e "${BLUE}Installing...${NC}"
- chmod +x "$TMP_DIR/cursor-id-modifier"
- sudo mv "$TMP_DIR/cursor-id-modifier" "$INSTALL_DIR/"
-
- echo -e "${GREEN}Installation completed successfully!${NC}"
- echo -e "${BLUE}Running cursor-id-modifier...${NC}"
-
- # Run the program with sudo, preserving environment variables
- export AUTOMATED_MODE=1
- if ! sudo -E cursor-id-modifier; then
- echo -e "${RED}Failed to run cursor-id-modifier${NC}"
- exit 1
- fi
-}
-
-main
diff --git a/scripts/run/cursor_linux_id_modifier.sh b/scripts/run/cursor_linux_id_modifier.sh
index 2ba6938..6be1c89 100755
--- a/scripts/run/cursor_linux_id_modifier.sh
+++ b/scripts/run/cursor_linux_id_modifier.sh
@@ -1,397 +1,200 @@
#!/bin/bash
-# 设置错误处理
-set -e
+# ========================================
+# 🐧 Cursor Linux ID Modifier Script 🚀
+# ========================================
+# Purpose: Reset Cursor trial by modifying device identifiers
+# Platform: Linux (all distributions)
+# Requirements: sudo privileges, Cursor installed
+# ========================================
-# 定义日志文件路径
-LOG_FILE="/tmp/cursor_linux_id_modifier.log"
+set -e
-# 初始化日志文件
-initialize_log() {
- echo "========== Cursor ID 修改工具日志开始 $(date) ==========" > "$LOG_FILE"
+# ========================================
+# CONFIGURATION
+# ========================================
+
+readonly SCRIPT_NAME="Cursor Linux ID Modifier"
+readonly LOG_FILE="/tmp/cursor_linux_id_modifier.log"
+readonly CURSOR_CONFIG_DIR="$HOME/.config/Cursor"
+readonly STORAGE_FILE="$CURSOR_CONFIG_DIR/User/globalStorage/storage.json"
+readonly BACKUP_DIR="$CURSOR_CONFIG_DIR/User/globalStorage/backups"
+
+# Colors for output
+readonly RED='\033[0;31m'
+readonly GREEN='\033[0;32m'
+readonly YELLOW='\033[1;33m'
+readonly BLUE='\033[0;34m'
+readonly NC='\033[0m'
+
+# ========================================
+# UTILITY FUNCTIONS
+# ========================================
+
+# Initialize logging
+init_log() {
+ echo "========== $SCRIPT_NAME 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
-
-# 日志函数 - 同时输出到终端和日志文件
+# Logging functions with emojis
log_info() {
- echo -e "${GREEN}[INFO]${NC} $1"
+ 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 -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 -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 -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"
-}
-
-# 获取当前用户
+# Get current user (handle sudo)
get_current_user() {
if [ "$EUID" -eq 0 ]; then
- echo "$SUDO_USER"
+ echo "${SUDO_USER:-$USER}"
else
echo "$USER"
fi
}
-CURRENT_USER=$(get_current_user)
-if [ -z "$CURRENT_USER" ]; then
- log_error "无法获取用户名"
- exit 1
-fi
-
-# 定义Linux下的Cursor路径
-CURSOR_CONFIG_DIR="$HOME/.config/Cursor"
-STORAGE_FILE="$CURSOR_CONFIG_DIR/User/globalStorage/storage.json"
-BACKUP_DIR="$CURSOR_CONFIG_DIR/User/globalStorage/backups"
+# Generate random UUID
+generate_uuid() {
+ if command -v uuidgen &> /dev/null; then
+ uuidgen | tr '[:upper:]' '[:lower:]'
+ elif [ -f /proc/sys/kernel/random/uuid ]; then
+ cat /proc/sys/kernel/random/uuid
+ else
+ openssl rand -hex 16 | sed 's/\(..\)\(..\)\(..\)\(..\)\(..\)\(..\)\(..\)\(..\)/\1\2\3\4-\5\6-\7\8-\9\10-\11\12\13\14\15\16/'
+ fi
+}
-# --- 新增:安装相关变量 ---
-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"
-# --- 结束:安装相关变量 ---
+# Generate random hex string
+generate_random_hex() {
+ local length=${1:-32}
+ openssl rand -hex $((length / 2))
+}
-# 可能的Cursor二进制路径 - 添加了标准安装路径
-CURSOR_BIN_PATHS=(
- "/usr/bin/cursor"
- "/usr/local/bin/cursor"
- "$INSTALL_DIR/cursor" # 添加标准安装路径
- "$HOME/.local/bin/cursor"
- "/snap/bin/cursor"
-)
+# ========================================
+# CURSOR DETECTION
+# ========================================
-# 找到Cursor安装路径
-find_cursor_path() {
- log_info "查找Cursor安装路径..."
+# Find Cursor installation
+find_cursor_installation() {
+ log_info "🔍 Searching for Cursor installation..."
- for path in "${CURSOR_BIN_PATHS[@]}"; do
- if [ -f "$path" ] && [ -x "$path" ]; then # 确保文件存在且可执行
- log_info "找到Cursor安装路径: $path"
- CURSOR_PATH="$path"
+ local cursor_paths=(
+ "/usr/bin/cursor"
+ "/usr/local/bin/cursor"
+ "/opt/Cursor/cursor"
+ "$HOME/.local/bin/cursor"
+ "/snap/bin/cursor"
+ )
+
+ # Check predefined paths
+ for path in "${cursor_paths[@]}"; do
+ if [ -f "$path" ] && [ -x "$path" ]; then
+ log_info "🎯 Found Cursor at: $path"
+ echo "$path"
return 0
fi
done
-
- # 尝试通过which命令定位
+
+ # Try which command
if command -v cursor &> /dev/null; then
- CURSOR_PATH=$(which cursor)
- log_info "通过which找到Cursor: $CURSOR_PATH"
+ local cursor_path=$(which cursor)
+ log_info "🎯 Found Cursor via which: $cursor_path"
+ echo "$cursor_path"
return 0
fi
- # 尝试查找可能的安装路径 (限制搜索范围和类型)
- local cursor_paths=$(find /usr /opt $HOME/.local -path "$INSTALL_DIR/cursor" -o -name "cursor" -type f -executable 2>/dev/null)
- 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"
+ # Search in common directories
+ local found_path=$(find /usr /opt "$HOME/.local" -name "cursor" -type f -executable 2>/dev/null | head -1)
+ if [ -n "$found_path" ]; then
+ log_info "🎯 Found Cursor via search: $found_path"
+ echo "$found_path"
return 0
fi
- log_warn "未找到Cursor可执行文件"
+ log_error "❌ Cursor installation not found"
return 1
}
-# 查找并定位Cursor资源文件目录
+# Find Cursor resources directory
find_cursor_resources() {
- log_info "查找Cursor资源目录..."
+ log_info "Searching for Cursor resources..."
- # 可能的资源目录路径 - 添加了标准安装目录
local resource_paths=(
- "$INSTALL_DIR" # 添加标准安装路径
+ "/opt/Cursor"
"/usr/lib/cursor"
"/usr/share/cursor"
"$HOME/.local/share/cursor"
)
for path in "${resource_paths[@]}"; do
- if [ -d "$path/resources" ]; then # 检查是否存在 resources 子目录
- log_info "找到Cursor资源目录: $path"
- CURSOR_RESOURCES="$path"
+ if [ -d "$path/resources" ] || [ -d "$path/app" ]; then
+ log_info "Found Cursor resources at: $path"
+ echo "$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=$(realpath "$base_dir/..")
- log_info "通过二进制路径找到资源目录: $CURSOR_RESOURCES"
- return 0
- elif [ -d "$base_dir/../lib/cursor/resources" ]; then # 另一种常见结构
- CURSOR_RESOURCES=$(realpath "$base_dir/../lib/cursor")
- log_info "通过二进制路径找到资源目录: $CURSOR_RESOURCES"
- return 0
- fi
- fi
-
- log_warn "未找到Cursor资源目录"
+ log_error "Cursor resources not found"
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() {
- found_appimage_path=$(find "$APPIMAGE_SEARCH_DIR" -maxdepth 1 -name "$APPIMAGE_PATTERN" -print -quit)
- 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":"$(id -g -n "$CURRENT_USER")" "$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" # 返回原始目录查找图标等文件
+# ========================================
+# PROCESS MANAGEMENT
+# ========================================
- 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 进程
-check_and_kill_cursor() {
- log_info "检查 Cursor 进程..."
+# Stop all Cursor processes
+stop_cursor_processes() {
+ log_info "Stopping Cursor processes..."
- local attempt=1
local max_attempts=5
-
- # 函数:获取进程详细信息
- get_process_details() {
- local process_name="$1"
- log_debug "正在获取 $process_name 进程详细信息:"
- ps aux | grep -i "cursor" | grep -v grep | grep -v "cursor_linux_id_modifier.sh"
- }
+ local attempt=1
while [ $attempt -le $max_attempts ]; do
- # 使用更精确的匹配来获取 Cursor 进程,排除当前脚本和grep进程
- CURSOR_PIDS=$(ps aux | grep -i "cursor" | grep -v "grep" | grep -v "cursor_linux_id_modifier.sh" | awk '{print $2}' || true)
+ local cursor_pids=$(pgrep -i cursor | grep -v $$ || true)
- if [ -z "$CURSOR_PIDS" ]; then
- log_info "未发现运行中的 Cursor 进程"
+ if [ -z "$cursor_pids" ]; then
+ log_info "All Cursor processes stopped"
return 0
fi
- log_warn "发现 Cursor 进程正在运行"
- get_process_details "cursor"
-
- log_warn "尝试关闭 Cursor 进程..."
+ log_warn "Found running Cursor processes, stopping... (attempt $attempt/$max_attempts)"
if [ $attempt -eq $max_attempts ]; then
- log_warn "尝试强制终止进程..."
- kill -9 $CURSOR_PIDS 2>/dev/null || true
+ kill -9 $cursor_pids 2>/dev/null || true
else
- kill $CURSOR_PIDS 2>/dev/null || true
- fi
-
- sleep 1
-
- # 再次检查进程是否还在运行,排除当前脚本和grep进程
- if ! ps aux | grep -i "cursor" | grep -v "grep" | grep -v "cursor_linux_id_modifier.sh" > /dev/null; then
- log_info "Cursor 进程已成功关闭"
- return 0
+ kill $cursor_pids 2>/dev/null || true
fi
- log_warn "等待进程关闭,尝试 $attempt/$max_attempts..."
+ sleep 2
((attempt++))
done
- log_error "在 $max_attempts 次尝试后仍无法关闭 Cursor 进程"
- get_process_details "cursor"
- log_error "请手动关闭进程后重试"
- exit 1
+ log_error "Failed to stop all Cursor processes"
+ return 1
}
-# 备份配置文件
+# ========================================
+# CONFIGURATION MANAGEMENT
+# ========================================
+
+# Create backup of configuration
backup_config() {
if [ ! -f "$STORAGE_FILE" ]; then
- log_warn "配置文件 '$STORAGE_FILE' 不存在,跳过备份"
+ log_warn "Configuration file not found, skipping backup"
return 0
fi
@@ -400,877 +203,303 @@ backup_config() {
if cp "$STORAGE_FILE" "$backup_file"; then
chmod 644 "$backup_file"
- # 确保备份文件归属正确用户
- chown "$CURRENT_USER":"$(id -g -n "$CURRENT_USER")" "$backup_file" || log_warn "设置备份文件所有权失败: $backup_file"
- log_info "配置已备份到: $backup_file"
- else
- log_error "备份失败: $STORAGE_FILE"
- exit 1
- fi
- return 0 # 明确返回成功
-}
-
-# 生成随机 ID
-generate_random_id() {
- # 生成32字节(64个十六进制字符)的随机数
- openssl rand -hex 32
-}
-
-# 生成随机 UUID
-generate_uuid() {
- # 在Linux上使用uuidgen生成UUID
- if command -v uuidgen &> /dev/null; then
- uuidgen | tr '[:upper:]' '[:lower:]'
+ chown "$(get_current_user):$(id -g -n "$(get_current_user)")" "$backup_file" 2>/dev/null || true
+ log_info "Configuration backed up to: $(basename "$backup_file")"
+ return 0
else
- # 备选方案:使用/proc/sys/kernel/random/uuid
- if [ -f /proc/sys/kernel/random/uuid ]; then
- cat /proc/sys/kernel/random/uuid
- else
- # 最后备选方案:使用openssl生成
- openssl rand -hex 16 | sed 's/\\(..\\)\\(..\\)\\(..\\)\\(..\\)\\(..\\)\\(..\\)\\(..\\)\\(..\\)/\\1\\2\\3\\4-\\5\\6-\\7\\8-\\9\\10-\\11\\12\\13\\14\\15\\16/'
- fi
+ log_error "Failed to backup configuration"
+ return 1
fi
}
-# 修改现有文件
-modify_or_add_config() {
+# Modify configuration file
+modify_config() {
local key="$1"
local value="$2"
local file="$3"
if [ ! -f "$file" ]; then
- log_error "配置文件不存在: $file"
+ log_error "Configuration file not found: $file"
return 1
fi
- # 确保文件对当前执行用户(root)可写
- chmod u+w "$file" || {
- log_error "无法修改文件权限(写): $file"
- return 1
- }
-
- # 创建临时文件
+ # Create temporary file
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 格式不标准或最后一行不是 '}' 会失败
- sed '$ s/}/,\n "'$key'\": "'$value'\"\n}/' "$file" > "$temp_file" || {
- log_error "添加配置失败 (注入): $key to $file"
- rm -f "$temp_file"
- chmod u-w "$file" # 恢复权限
- return 1
- }
- log_debug "已添加 key '$key' 到文件 '$file' 中"
+ # Update or add key-value pair
+ if grep -q "\"$key\":" "$file"; then
+ sed "s/\"$key\":[[:space:]]*\"[^\"]*\"/\"$key\": \"$value\"/" "$file" > "$temp_file"
+ log_debug "Updated existing key: $key"
else
- log_error "无法确定如何添加配置: $key to $file (文件结构可能不标准)"
- rm -f "$temp_file"
- chmod u-w "$file" # 恢复权限
- return 1
+ sed '$ s/}/,\n "'$key'": "'$value'"\n}/' "$file" > "$temp_file"
+ log_debug "Added new key: $key"
fi
-
- # 检查临时文件是否有效
+
+ # Verify temporary file
if [ ! -s "$temp_file" ]; then
- log_error "修改或添加配置后生成的临时文件为空: $key in $file"
+ log_error "Failed to modify configuration"
rm -f "$temp_file"
- chmod u-w "$file" # 恢复权限
return 1
fi
- # 使用 cat 替换原文件内容
- cat "$temp_file" > "$file" || {
- log_error "无法写入更新后的配置到文件: $file"
+ # Replace original file
+ if cat "$temp_file" > "$file"; then
+ rm -f "$temp_file"
+ chown "$(get_current_user):$(id -g -n "$(get_current_user)")" "$file" 2>/dev/null || true
+ chmod 644 "$file" 2>/dev/null || true
+ return 0
+ else
+ log_error "Failed to write configuration"
rm -f "$temp_file"
- # 尝试恢复权限(如果失败也无大碍)
- chmod u-w "$file" || true
return 1
- }
-
- rm -f "$temp_file"
-
- # 设置所有者和基础权限(root执行时目标文件是用户家目录下的)
- chown "$CURRENT_USER":"$(id -g -n "$CURRENT_USER")" "$file" || log_warn "设置文件所有权失败: $file"
- chmod 644 "$file" || log_warn "设置文件权限失败: $file" # 用户读写,组和其他读
-
- return 0
+ fi
}
-# 生成新的配置
+# Generate new configuration
generate_new_config() {
- echo
- log_warn "机器码重置选项"
-
- # 使用菜单选择函数询问用户是否重置机器码
- select_menu_option "是否需要重置机器码? (通常情况下,只修改js文件即可):" "不重置 - 仅修改js文件即可|重置 - 同时修改配置文件和机器码" 0
- reset_choice=$?
+ log_info "Generating new device identifiers..."
- # 记录日志以便调试
- echo "[INPUT_DEBUG] 机器码重置选项选择: $reset_choice" >> "$LOG_FILE"
-
- # 确保配置文件目录存在
+ # Ensure config directory exists
mkdir -p "$(dirname "$STORAGE_FILE")"
- chown "$CURRENT_USER":"$(id -g -n "$CURRENT_USER")" "$(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 "您选择了重置机器码"
+ chown "$(get_current_user):$(id -g -n "$(get_current_user)")" "$(dirname "$STORAGE_FILE")" 2>/dev/null || true
+
+ if [ -f "$STORAGE_FILE" ]; then
+ log_info "Found existing configuration file"
+ backup_config || return 1
- # 检查配置文件是否存在
- 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_uuid) # 使用 UUID 作为 Machine ID 更常见
-
- log_info "正在设置新的设备和机器ID..."
- log_debug "新设备ID: $new_device_id"
- log_debug "新机器ID: $new_machine_id"
-
- # 修改配置文件
- if modify_or_add_config "deviceId" "$new_device_id" "$STORAGE_FILE" && \
- modify_or_add_config "machineId" "$new_machine_id" "$STORAGE_FILE"; then
- log_info "配置文件中的 deviceId 和 machineId 修改成功"
- else
- log_error "配置文件中的 deviceId 或 machineId 修改失败"
- # 注意:即使失败,备份仍在,但配置文件可能已部分修改
- return 1 # 返回错误状态
- fi
- else
- log_warn "未找到配置文件 '$STORAGE_FILE',无法重置机器码。如果这是首次安装,这是正常的。"
- # 即使文件不存在,也认为此步骤(不执行)是"成功"的,允许继续
- fi
- else
- log_info "您选择了不重置机器码,将仅修改js文件"
+ # Generate new IDs
+ local new_device_id=$(generate_uuid)
+ local new_machine_id=$(generate_uuid)
+
+ log_info "Updating device identifiers..."
- # 检查配置文件是否存在并备份(如果存在)
- if [ -f "$STORAGE_FILE" ]; then
- log_info "发现已有配置文件: $STORAGE_FILE"
- if ! backup_config; then
- log_error "配置文件备份失败,中止操作。"
- return 1 # 返回错误状态
- fi
+ if modify_config "telemetry.deviceId" "$new_device_id" "$STORAGE_FILE" && \
+ modify_config "telemetry.machineId" "$new_machine_id" "$STORAGE_FILE"; then
+ log_info "Configuration updated successfully"
+ return 0
else
- log_warn "未找到配置文件 '$STORAGE_FILE',跳过备份。"
+ log_error "Failed to update configuration"
+ return 1
fi
+ else
+ log_warn "Configuration file not found: $STORAGE_FILE"
+ log_info "This is normal for first-time installations"
+ return 0
fi
-
- echo
- log_info "配置处理完成"
- return 0 # 明确返回成功
}
-# 查找Cursor的JS文件
+# ========================================
+# JAVASCRIPT MODIFICATION
+# ========================================
+
+# Find Cursor JS files
find_cursor_js_files() {
- log_info "查找Cursor的JS文件..."
+ log_info "Searching for Cursor JS files..."
- local js_files=()
- local found=false
-
- # 确保 CURSOR_RESOURCES 已设置
- if [ -z "$CURSOR_RESOURCES" ] || [ ! -d "$CURSOR_RESOURCES" ]; then
- log_error "Cursor 资源目录未找到或无效 ($CURSOR_RESOURCES),无法查找 JS 文件。"
+ local resources_dir
+ if ! resources_dir=$(find_cursor_resources); then
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/node/cliProcessMain.js"
- # 添加其他可能的路径模式
- "app/out/vs/workbench/api/node/extensionHostProcess.js" # 如果资源目录是 app 的父目录
+ "app/out/vs/workbench/api/node/extensionHostProcess.js"
"app/out/main.js"
"app/out/vs/code/node/cliProcessMain.js"
)
+ local js_files=()
for pattern in "${js_patterns[@]}"; do
- # 使用 find 在 CURSOR_RESOURCES 下查找完整路径
- local files=$(find "$CURSOR_RESOURCES" -path "*/$pattern" -type f 2>/dev/null)
+ local files=$(find "$resources_dir" -path "*/$pattern" -type f 2>/dev/null)
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
+ js_files+=("$file")
+ log_info "Found JS file: $file"
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)
- 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 路径模式是否需要更新。"
+ if [ ${#js_files[@]} -eq 0 ]; then
+ log_error "No JS files found for modification"
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文件需要处理。"
+ printf '%s\n' "${js_files[@]}"
return 0
}
-# 修改Cursor的JS文件
+# Modify Cursor JS files
modify_cursor_js_files() {
- log_info "开始修改Cursor的JS文件..."
+ log_info "Modifying Cursor JS files..."
- # 先查找需要修改的JS文件
- if ! find_cursor_js_files; then
- # find_cursor_js_files 内部会打印错误日志
+ local js_files
+ if ! js_files=($(find_cursor_js_files)); then
return 1
fi
- if [ ${#CURSOR_JS_FILES[@]} -eq 0 ]; then
- log_error "JS 文件列表为空,无法继续修改。"
- return 1
- fi
-
local modified_count=0
- local file_modification_status=() # 记录每个文件的修改状态
-
- for file in "${CURSOR_JS_FILES[@]}"; do
- log_info "处理文件: $file"
+ local new_uuid=$(generate_uuid)
+ local machine_id=$(generate_uuid)
+ local device_id=$(generate_uuid)
+ local mac_machine_id=$(generate_random_hex 64)
+
+ for file in "${js_files[@]}"; do
+ log_info "Processing: $(basename "$file")"
if [ ! -f "$file" ]; then
- log_error "文件不存在: $file,跳过处理。"
- file_modification_status+=("'$file': Not Found")
+ log_warn "File not found: $file"
continue
fi
-
- # 创建文件备份
+
+ # Create backup
local backup_file="${file}.backup_$(date +%Y%m%d_%H%M%S)"
if ! cp "$file" "$backup_file"; then
- log_error "无法创建文件备份: $file"
- file_modification_status+=("'$file': Backup Failed")
+ log_error "Failed to backup: $file"
continue
fi
- chown "$CURRENT_USER":"$(id -g -n "$CURRENT_USER")" "$backup_file" || log_warn "设置备份文件所有权失败: $backup_file"
- chmod 444 "$backup_file" || log_warn "设置备份文件权限失败: $backup_file"
-
-
- # 确保文件对当前执行用户(root)可写
- chmod u+w "$file" || {
- log_error "无法修改文件权限(写): $file"
- file_modification_status+=("'$file': Permission Error (Write)")
- # 尝试恢复备份(如果可能)
- cp "$backup_file" "$file" 2>/dev/null || true
- continue
- }
-
- local modification_applied=false
-
- # --- 开始尝试各种修改模式 ---
- # 模式1:精确修改 x-cursor-checksum (最常见的目标之一)
- if grep -q 'i.header.set("x-cursor-checksum' "$file"; then
- log_debug "找到 x-cursor-checksum 设置代码,尝试修改..."
- # 使用更健壮的 sed,处理不同的空格和变量名可能性
- if sed -i -E 's/(i|[\w$]+)\.header\.set\("x-cursor-checksum",\s*e\s*===\s*void 0\s*\?\s*`\$\{p\}(\$\{t\})`\s*:\s*`\$\{p\}\2\/(\$\{e\})`/i.header.set("x-cursor-checksum",e===void 0?`${p}${t}`:`${p}${t}\/${p}`)/' "$file"; then
- # 验证修改是否真的发生 (避免 sed 没匹配但返回0)
- if ! grep -q 'i.header.set("x-cursor-checksum",e===void 0?`${p}${t}`:`${p}${t}\/${e}`)' "$file"; then
- log_info "成功修改 x-cursor-checksum 设置代码"
- modification_applied=true
- else
- log_warn "sed 命令执行成功,但似乎未修改 x-cursor-checksum (可能模式不匹配当前版本)"
- fi
- else
- log_error "修改 x-cursor-checksum 设置代码失败 (sed 命令执行错误)"
- fi
- fi
-
- # 模式2:注入 randomUUID 到特定函数 (如果模式1未应用)
- if [ "$modification_applied" = false ] && grep -q "IOPlatformUUID" "$file"; then
- log_debug "未修改 checksum 或未找到,尝试注入 randomUUID..."
- # 尝试注入 a$ 函数
- if grep -q "function a\$(" "$file" && ! grep -q "return crypto.randomUUID()" "$file"; then
- if sed -i 's/function a\$(t){switch/function a\$(t){try { return require("crypto").randomUUID(); } catch(e){} switch/' "$file"; then
- # 验证修改
- if grep -q "return require(\"crypto\").randomUUID()" "$file"; then
- log_info "成功注入 randomUUID 调用到 a\$ 函数"
- modification_applied=true
- else
- log_warn "sed 注入 a$ 失败(可能模式不匹配)"
- fi
- else
- log_error "修改 a\$ 函数失败 (sed 命令执行错误)"
- fi
- # 尝试注入 v5 函数 (如果 a$ 没成功)
- elif [ "$modification_applied" = false ] && grep -q "async function v5(" "$file" && ! grep -q "return crypto.randomUUID()" "$file"; then
- if sed -i 's/async function v5(t){let e=/async function v5(t){try { return require("crypto").randomUUID(); } catch(e){} let e=/' "$file"; then
- # 验证修改
- if grep -q "return require(\"crypto\").randomUUID()" "$file"; then
- log_info "成功注入 randomUUID 调用到 v5 函数"
- modification_applied=true
- else
- log_warn "sed 注入 v5 失败(可能模式不匹配)"
- fi
- else
- log_error "修改 v5 函数失败 (sed 命令执行错误)"
- fi
- fi
+ # Check if already modified
+ if grep -q "Cursor ID Modifier" "$file"; then
+ log_info "File already modified: $(basename "$file")"
+ rm -f "$backup_file"
+ ((modified_count++))
+ continue
fi
-
- # 模式3:通用注入 (如果上述模式都未应用,并且没有标记)
- if [ "$modification_applied" = false ] && ! grep -q "// Cursor ID Modifier Injection" "$file"; then
- log_debug "特定修改模式未生效或不适用,尝试通用注入..."
- # 生成唯一标识符以避免冲突
- local timestamp=$(date +%s)
- local new_uuid=$(generate_uuid)
- local machine_id=$(generate_uuid) # 使用 UUID
- local device_id=$(generate_uuid)
- local mac_machine_id=$(openssl rand -hex 32) # 伪造 MAC 相关 ID
-
- # 创建注入代码块
- local inject_universal_code="
-// Cursor ID Modifier Injection - $timestamp
-const originalRequire_$timestamp = typeof require === 'function' ? require : null;
-if (originalRequire_$timestamp) {
+
+ # Create injection code
+ local inject_code="
+// Cursor ID Modifier Injection - $(date)
+const originalRequire = typeof require === 'function' ? require : null;
+if (originalRequire) {
require = function(module) {
try {
- const result = originalRequire_$timestamp(module);
+ const result = originalRequire(module);
if (module === 'crypto' && result && result.randomUUID) {
- const originalRandomUUID_$timestamp = result.randomUUID;
result.randomUUID = function() { return '$new_uuid'; };
- console.log('Cursor Modifier: Patched crypto.randomUUID');
- }
- if (module === 'os' && result && result.networkInterfaces) {
- const originalNI_$timestamp = result.networkInterfaces;
- result.networkInterfaces = function() { return { lo: [{ address: '127.0.0.1', netmask: '255.0.0.0', family: 'IPv4', mac: '00:00:00:00:00:00', internal: true, cidr: '127.0.0.1/8' }]}; };
- console.log('Cursor Modifier: Patched os.networkInterfaces');
}
return result;
} catch (e) {
- console.error('Cursor Modifier: Error in require patch for module:', module, e);
- // 如果原始 require 失败,可能需要返回一个空对象或抛出异常
- // 尝试调用原始 require,即使它可能已在 try 块中失败
- try { return originalRequire_$timestamp(module); } catch (innerE) { return {}; }
+ return originalRequire(module);
}
};
-} else { console.warn('Cursor Modifier: Original require not found.'); }
+}
-// Override potential global functions or properties if they exist
+// Override global functions
try { if (typeof global !== 'undefined' && global.getMachineId) global.getMachineId = function() { return '$machine_id'; }; } catch(e){}
try { if (typeof global !== 'undefined' && global.getDeviceId) global.getDeviceId = function() { return '$device_id'; }; } catch(e){}
-try { if (typeof global !== 'undefined' && global.macMachineId) global.macMachineId = '$mac_machine_id'; } catch(e){}
try { if (typeof process !== 'undefined' && process.env) process.env.VSCODE_MACHINE_ID = '$machine_id'; } catch(e){}
-console.log('Cursor Modifier: Universal patches applied (UUID: $new_uuid)');
-// End Cursor ID Modifier Injection - $timestamp
+console.log('Cursor ID Modifier: Patches applied');
+// End Cursor ID Modifier Injection
"
- # 将变量替换进代码
- inject_universal_code=${inject_universal_code//\$new_uuid/$new_uuid}
- inject_universal_code=${inject_universal_code//\$machine_id/$machine_id}
- inject_universal_code=${inject_universal_code//\$device_id/$device_id}
- inject_universal_code=${inject_universal_code//\$mac_machine_id/$mac_machine_id}
- inject_universal_code=${inject_universal_code//\$timestamp/$timestamp} # 确保时间戳替换
-
- # 将代码注入到文件开头
- local temp_inject_file=$(mktemp)
- echo "$inject_universal_code" > "$temp_inject_file"
- cat "$file" >> "$temp_inject_file"
-
- if mv "$temp_inject_file" "$file"; then
- log_info "完成通用注入修改"
- modification_applied=true
- else
- log_error "通用注入失败 (无法移动临时文件)"
- rm -f "$temp_inject_file" # 清理注入文件
- fi
- elif [ "$modification_applied" = false ]; then
- log_info "文件 '$file' 似乎已被修改过 (包含注入标记),跳过通用注入。"
- # 即使未应用新修改,也认为"成功"处理(避免恢复备份)
- modification_applied=true # 标记为已处理,防止恢复备份
- fi
-
- # --- 结束修改尝试 ---
-
- # 根据修改结果处理
- if [ "$modification_applied" = true ]; then
+
+ # Inject code at beginning of file
+ local temp_file=$(mktemp)
+ echo "$inject_code" > "$temp_file"
+ cat "$file" >> "$temp_file"
+
+ if mv "$temp_file" "$file"; then
+ log_info "Successfully modified: $(basename "$file")"
+ chown "$(get_current_user):$(id -g -n "$(get_current_user)")" "$file" 2>/dev/null || true
+ chmod 644 "$file" 2>/dev/null || true
+ rm -f "$backup_file"
((modified_count++))
- file_modification_status+=("'$file': Success")
- # 恢复文件权限为只读
- chmod u-w,go-w "$file" || log_warn "设置文件只读权限失败: $file"
- # 设置文件所有者
- chown "$CURRENT_USER":"$(id -g -n "$CURRENT_USER")" "$file" || log_warn "设置 JS 文件所有权失败: $file"
else
- log_error "未能成功应用任何修改到文件: $file"
- file_modification_status+=("'$file': Failed")
- # 恢复备份
- log_info "正在从备份恢复文件: $file"
- if cp "$backup_file" "$file"; then
- chmod u-w,go-w "$file" || log_warn "恢复备份后设置只读权限失败: $file"
- chown "$CURRENT_USER":"$(id -g -n "$CURRENT_USER")" "$file" || log_warn "恢复备份后设置所有权失败: $file"
- else
- log_error "从备份恢复文件失败: $file"
- # 文件可能处于不确定状态
- fi
- fi
-
- # 清理备份文件
- rm -f "$backup_file"
-
- 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文件。"
- 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
- # $HOME/.local/share
- update_configs+=("$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
- # 尝试添加或修改 "update.mode": "none"
- if grep -q '"update.mode"' "$config"; then
- sed -i 's/"update.mode":[[:space:]]*"[^"]*"/"update.mode": "none"/' "$config" || log_warn "修改 settings.json 中的 update.mode 失败"
- elif grep -q "}" "$config"; then # 尝试注入
- sed -i '$ s/}/,\n "update.mode": "none"\n}/' "$config" || log_warn "注入 update.mode 到 settings.json 失败"
- else
- log_warn "无法修改 settings.json 以禁用更新(结构未知)"
- fi
- # 确保权限正确
- chown "$CURRENT_USER":"$(id -g -n "$CURRENT_USER")" "$config" || log_warn "设置所有权失败: $config"
- chmod 644 "$config" || log_warn "设置权限失败: $config"
- ((disabled_count++))
- log_info "已尝试在 '$config' 中设置 'update.mode' 为 'none'"
- elif [[ "$config" == *update-config.json ]]; then
- # 直接覆盖 update-config.json
- echo '{"autoCheck": false, "autoDownload": false}' > "$config"
- chown "$CURRENT_USER":"$(id -g -n "$CURRENT_USER")" "$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
- updater_paths+=($(find "$CURSOR_RESOURCES" -name "updater" -type f -executable 2>/dev/null))
- updater_paths+=($(find "$CURSOR_RESOURCES" -name "CursorUpdater" -type f -executable 2>/dev/null)) # macOS 风格?
- fi
- if [ -d "$INSTALL_DIR" ]; then
- updater_paths+=($(find "$INSTALL_DIR" -name "updater" -type f -executable 2>/dev/null))
- updater_paths+=($(find "$INSTALL_DIR" -name "CursorUpdater" -type f -executable 2>/dev/null))
- fi
- updater_paths+=("$HOME/.config/Cursor/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++))
+ log_error "Failed to modify: $file"
+ cp "$backup_file" "$file" 2>/dev/null || true
+ rm -f "$temp_file" "$backup_file"
fi
done
- if [ "$disabled_count" -eq 0 ]; then
- log_warn "未能找到或禁用任何已知的自动更新机制。"
- log_warn "如果 Cursor 仍然自动更新,可能需要手动查找并禁用相关文件或设置。"
+ if [ "$modified_count" -gt 0 ]; then
+ log_info "Successfully modified $modified_count JS files"
+ return 0
else
- log_info "成功禁用或尝试禁用了 $disabled_count 个自动更新相关的文件/程序。"
+ log_error "Failed to modify any JS files"
+ return 1
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 enter_key=$'\n'
+# ========================================
+# MAIN EXECUTION
+# ========================================
- # 隐藏光标
- tput civis
- # 清除可能存在的旧菜单行 (假设菜单最多 N 行)
- local num_options=${#options[@]}
- for ((i=0; i/dev/null; then
+ log_error "Cursor installation not found"
+ log_info "Please install Cursor first: https://cursor.sh/"
+ exit 1
fi
-
- log_info "Cursor 初始化清理完成。"
+
+ log_info "Prerequisites check passed"
}
-# 主函数
+# Main function
main() {
- # 初始化日志文件
- 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" "系统版本信息"
-
- clear
- # 显示 Logo
- echo -e "
+ echo"
██████╗██╗ ██╗██████╗ ███████╗ ██████╗ ██████╗
- ██╔════╝██║ ██║██╔══██╗██╔════╝██╔═══██╗██╔══██╗
- ██║ ██║ ██║██████╔╝███████╗██║ ██║██████╔╝
- ██║ ██║ ██║██╔══██╗╚════██║██║ ██║██╔══██╗
- ╚██████╗╚██████╔╝██║ ██║███████║╚██████╔╝██║ ██║
- ╚═════╝ ╚═════╝ ╚═╝ ╚═╝╚══════╝ ╚═════╝ ╚═╝ ╚═╝
- "
- 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 "${GREEN} [小小广告] 出售CursorPro教育号一年质保三个月,有需要找我(86),WeChat:JavaRookie666 ${NC}"
+ ██╔════╝██║ ██║██╔══██╗██╔════╝██╔═══██╗██╔══██╗
+ ██║ ██║ ██║██████╔╝███████╗██║ ██║██████╔╝
+ ██║ ██║ ██║██╔══██╗╚════██║██║ ██║██╔══██╗
+ ╚██████╗╚██████╔╝██║ ██║███████║╚██████╔╝██║ ██║
+ ╚═════╝ ╚═════╝ ╚═╝ ╚═╝╚══════╝ ╚═════╝ ╚═╝ ╚═╝"
echo
- echo -e "${YELLOW}[提示]${NC} 本工具旨在修改 Cursor 以解决可能的启动问题或设备限制。"
- echo -e "${YELLOW}[提示]${NC} 它将优先修改 JS 文件,并可选择重置设备ID和禁用自动更新。"
- echo -e "${YELLOW}[提示]${NC} 如果未找到 Cursor,将尝试从 '$APPIMAGE_SEARCH_DIR' 目录安装。"
+ echo "========================================="
+ echo " 🐧 $SCRIPT_NAME"
+ echo "========================================="
echo
-
- # 查找 Cursor 路径
- if ! find_cursor_path; then
- log_warn "系统中未找到现有的 Cursor 安装。"
- select_menu_option "是否尝试从 '$APPIMAGE_SEARCH_DIR' 目录中的 AppImage 文件安装 Cursor?" "是,安装 Cursor|否,退出脚本" 0
- install_choice=$?
-
- 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
+
+ init_log
+ check_prerequisites
+
+ log_info "🚀 Starting Cursor ID modification process..."
+
+ # Stop Cursor processes
+ if ! stop_cursor_processes; then
+ log_error "Failed to stop Cursor processes"
+ exit 1
fi
- # 执行 Cursor 初始化清理
- # cursor_initialize_cleanup
-
- # 备份并处理配置文件 (机器码重置选项)
+ # Generate new configuration
if ! generate_new_config; then
- log_error "处理配置文件时出错,脚本中止。"
- # 此处可能需要考虑是否回滚JS修改(如果已执行)?目前不回滚。
- exit 1
+ log_error "Failed to generate new configuration"
+ exit 1
fi
- # 修改JS文件
- log_info "正在修改 Cursor JS 文件..."
+ # Modify JS files
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 "尝试禁用自动更新时遇到问题(详见日志),但脚本将继续。"
+ log_error "Failed to modify JS files"
+ exit 1
fi
- log_info "所有修改步骤已完成!"
- log_info "请启动 Cursor 以应用更改。"
-
- # 显示最后的提示信息
echo
- echo -e "${GREEN}=====================================================${NC}"
- echo -e "${YELLOW} 请关注公众号【煎饼果子卷AI】获取更多技巧和交流 ${NC}"
- echo -e "${GREEN}=====================================================${NC}"
+ echo "╔══════════════════════════════════════════════════════════════════════════════╗"
+ echo "║ ║"
+ echo "║ 🎉 SUCCESS! CURSOR ID MODIFICATION COMPLETED! 🎉 ║"
+ echo "║ ║"
+ echo "║ ✅ Device identifiers have been reset ║"
+ echo "║ ✅ JavaScript patches applied ║"
+ echo "║ ✅ Configuration files updated ║"
+ echo "║ ║"
+ echo "║ 🚀 You can now restart Cursor to use the reset trial! ║"
+ echo "║ ║"
+ echo "╚══════════════════════════════════════════════════════════════════════════════╝"
echo
-
- # 记录脚本完成信息
- log_info "脚本执行完成"
- echo "========== Cursor ID 修改工具日志结束 $(date) ==========" >> "$LOG_FILE"
-
- # 显示日志文件位置
- echo
- log_info "详细日志已保存到: $LOG_FILE"
- echo "如遇问题请将此日志文件提供给开发者以协助排查"
+ log_info "📄 Log file saved to: $LOG_FILE"
echo
}
-# 执行主函数
-main
-
-exit 0 # 确保最后返回成功状态码
+# Execute main function
+main "$@"
\ No newline at end of file
diff --git a/scripts/run/cursor_mac_free_trial_reset.sh b/scripts/run/cursor_mac_free_trial_reset.sh
deleted file mode 100644
index 13f2a5b..0000000
--- a/scripts/run/cursor_mac_free_trial_reset.sh
+++ /dev/null
@@ -1,1401 +0,0 @@
-#!/bin/bash
-
-# 设置错误处理
-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
-
-# 日志函数 - 同时输出到终端和日志文件
-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"
-}
-
-# 获取当前用户
-get_current_user() {
- if [ "$EUID" -eq 0 ]; then
- echo "$SUDO_USER"
- else
- echo "$USER"
- fi
-}
-
-CURRENT_USER=$(get_current_user)
-if [ -z "$CURRENT_USER" ]; then
- log_error "无法获取用户名"
- exit 1
-fi
-
-# 定义配置文件路径
-STORAGE_FILE="$HOME/Library/Application Support/Cursor/User/globalStorage/storage.json"
-BACKUP_DIR="$HOME/Library/Application Support/Cursor/User/globalStorage/backups"
-
-# 定义 Cursor 应用程序路径
-CURSOR_APP_PATH="/Applications/Cursor.app"
-
-# 🚀 新增 Cursor 防掉试用Pro删除文件夹功能
-remove_cursor_trial_folders() {
- echo
- log_info "🎯 [核心功能] 正在执行 Cursor 防掉试用Pro删除文件夹..."
- log_info "📋 [说明] 此功能将删除指定的Cursor相关文件夹以重置试用状态"
- echo
-
- # 定义需要删除的文件夹路径
- local folders_to_delete=(
- "$HOME/Library/Application Support/Cursor"
- "$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 "🔧 [深度修复] 正在进行全面的权限修复..."
- local cursor_support_dir="$HOME/Library/Application Support/Cursor"
- local cursor_home_dir="$HOME/.cursor"
-
- # 创建完整的目录结构(包括Cursor可能需要的所有子目录)
- local directories=(
- "$cursor_support_dir"
- "$cursor_support_dir/User"
- "$cursor_support_dir/User/globalStorage"
- "$cursor_support_dir/User/workspaceStorage"
- "$cursor_support_dir/User/History"
- "$cursor_support_dir/logs"
- "$cursor_support_dir/CachedData"
- "$cursor_support_dir/CachedExtensions"
- "$cursor_support_dir/CachedExtensionVSIXs"
- "$cursor_home_dir"
- "$cursor_home_dir/extensions"
- )
-
- log_info "📁 [创建] 创建完整的目录结构..."
- for dir in "${directories[@]}"; do
- if mkdir -p "$dir" 2>/dev/null; then
- log_debug "✅ 创建目录: $dir"
- else
- log_warn "⚠️ 创建目录失败: $dir"
- fi
- done
-
- # 设置递归权限(确保所有子目录都有正确权限)
- log_info "🔐 [权限] 设置递归权限..."
- chmod -R 755 "$cursor_support_dir" 2>/dev/null || true
- chmod -R 755 "$cursor_home_dir" 2>/dev/null || true
-
- # 特别处理:确保当前用户拥有这些目录
- log_info "👤 [所有权] 确保目录所有权正确..."
- chown -R "$(whoami)" "$cursor_support_dir" 2>/dev/null || true
- chown -R "$(whoami)" "$cursor_home_dir" 2>/dev/null || true
-
- # 验证权限设置
- log_info "🔍 [验证] 验证权限设置..."
- if [ -w "$cursor_support_dir" ] && [ -w "$cursor_home_dir" ]; then
- log_info "✅ [成功] 权限验证通过"
- else
- log_warn "⚠️ [警告] 权限验证失败,可能仍存在问题"
- fi
-
- # 🔍 权限诊断
- log_info "🔍 [诊断] 执行权限诊断..."
- echo " 📁 目录权限检查:"
- for dir in "${directories[@]}"; do
- if [ -d "$dir" ]; then
- local perms=$(ls -ld "$dir" | awk '{print $1, $3, $4}')
- echo " ✅ $dir: $perms"
- else
- echo " ❌ $dir: 不存在"
- fi
- done
-
- # 🔍 权限诊断
- log_info "🔍 [诊断] 执行权限诊断..."
- echo " 📁 目录权限检查:"
- for dir in "${directories[@]}"; do
- if [ -d "$dir" ]; then
- local perms=$(ls -ld "$dir" | awk '{print $1, $3, $4}')
- echo " ✅ $dir: $perms"
- else
- echo " ❌ $dir: 不存在"
- fi
- done
-
- log_info "✅ [完成] 深度权限修复完成"
- echo
-
- # 显示操作统计
- 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 "🔧 [最终权限] 启动前最后一次权限确认..."
- local cursor_support_dir="$HOME/Library/Application Support/Cursor"
- local cursor_home_dir="$HOME/.cursor"
-
- # 再次确认完整目录结构存在
- local directories=(
- "$cursor_support_dir"
- "$cursor_support_dir/User"
- "$cursor_support_dir/User/globalStorage"
- "$cursor_support_dir/logs"
- "$cursor_support_dir/CachedData"
- "$cursor_home_dir"
- "$cursor_home_dir/extensions"
- )
-
- for dir in "${directories[@]}"; do
- mkdir -p "$dir" 2>/dev/null || true
- done
-
- # 设置强制权限
- chmod -R 755 "$cursor_support_dir" 2>/dev/null || true
- chmod -R 755 "$cursor_home_dir" 2>/dev/null || true
- chown -R "$(whoami)" "$cursor_support_dir" 2>/dev/null || true
- chown -R "$(whoami)" "$cursor_home_dir" 2>/dev/null || true
-
- # 启动Cursor
- log_info "🚀 [启动] 正在启动Cursor..."
- "$CURSOR_PROCESS_PATH" > /dev/null 2>&1 &
- CURSOR_PID=$!
-
- log_info "⏳ [等待] 等待15秒让Cursor完全启动并生成配置文件..."
- sleep 15
-
- # 检查配置文件是否生成
- local config_path="$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"
- else
- log_warn "⚠️ [警告] 配置文件未在预期时间内生成,继续执行..."
- fi
-
- # 强制关闭Cursor
- log_info "🔄 [关闭] 正在关闭Cursor以进行配置修改..."
- if [ ! -z "$CURSOR_PID" ]; then
- kill $CURSOR_PID 2>/dev/null || true
- fi
-
- # 确保所有Cursor进程都关闭
- pkill -f "Cursor" 2>/dev/null || true
-
- log_info "✅ [完成] Cursor重启流程完成"
- return 0
-}
-
-# 🛠️ 修改机器码配置
-modify_machine_code_config() {
- echo
- log_info "🛠️ [配置] 正在修改机器码配置..."
-
- local config_path="$HOME/Library/Application Support/Cursor/User/globalStorage/storage.json"
-
- if [ ! -f "$config_path" ]; then
- log_error "❌ [错误] 配置文件不存在: $config_path"
- log_info "💡 [提示] 请手动启动Cursor一次,然后重新运行此脚本"
- return 1
- fi
-
- # 生成新的ID
- local MAC_MACHINE_ID=$(uuidgen | tr '[:upper:]' '[:lower:]')
- local UUID=$(uuidgen | tr '[:upper:]' '[:lower:]')
- local MACHINE_ID="auth0|user_$(openssl rand -hex 32)"
- local SQM_ID="{$(uuidgen | tr '[:lower:]' '[:upper:]')}"
-
- log_info "🔧 [生成] 已生成新的设备标识符"
-
- # 备份原始配置
- local backup_dir="$HOME/Library/Application Support/Cursor/User/globalStorage/backups"
- mkdir -p "$backup_dir"
-
- local backup_name="storage.json.backup_$(date +%Y%m%d_%H%M%S)"
- cp "$config_path" "$backup_dir/$backup_name"
- log_info "💾 [备份] 已备份原配置: $backup_name"
-
- # 使用Python修改JSON配置(更可靠)
- python3 -c "
-import json
-import sys
-
-try:
- with open('$config_path', 'r', encoding='utf-8') as f:
- config = json.load(f)
-
- config['telemetry.machineId'] = '$MACHINE_ID'
- config['telemetry.macMachineId'] = '$MAC_MACHINE_ID'
- config['telemetry.devDeviceId'] = '$UUID'
- config['telemetry.sqmId'] = '$SQM_ID'
-
- with open('$config_path', 'w', encoding='utf-8') as f:
- json.dump(config, f, indent=2, ensure_ascii=False)
-
- print('SUCCESS')
-except Exception as e:
- print(f'ERROR: {e}')
- sys.exit(1)
-" 2>/dev/null
-
- if [ $? -eq 0 ]; then
- log_info "✅ [成功] 机器码配置修改完成"
- log_info "📋 [详情] 已更新以下标识符:"
- echo " 🔹 machineId: ${MACHINE_ID:0:20}..."
- echo " 🔹 macMachineId: $MAC_MACHINE_ID"
- echo " 🔹 devDeviceId: $UUID"
- echo " 🔹 sqmId: $SQM_ID"
- return 0
- else
- log_error "❌ [错误] 修改配置失败"
- return 1
- fi
-}
-
-# 检查权限
-check_permissions() {
- if [ "$EUID" -ne 0 ]; then
- log_error "请使用 sudo 运行此脚本"
- echo "示例: sudo $0"
- exit 1
- fi
-}
-
-# 检查并关闭 Cursor 进程(保存进程信息)
-check_and_kill_cursor() {
- log_info "🔍 [检查] 检查 Cursor 进程..."
-
- local attempt=1
- local max_attempts=5
-
- # 💾 保存Cursor进程路径
- CURSOR_PROCESS_PATH="/Applications/Cursor.app/Contents/MacOS/Cursor"
-
- # 函数:获取进程详细信息
- get_process_details() {
- local process_name="$1"
- log_debug "正在获取 $process_name 进程详细信息:"
- ps aux | grep -i "/Applications/Cursor.app" | grep -v grep
- }
-
- while [ $attempt -le $max_attempts ]; do
- # 使用更精确的匹配来获取 Cursor 进程
- CURSOR_PIDS=$(ps aux | grep -i "/Applications/Cursor.app" | grep -v grep | awk '{print $2}')
-
- if [ -z "$CURSOR_PIDS" ]; then
- log_info "💡 [提示] 未发现运行中的 Cursor 进程"
- # 确认Cursor应用路径存在
- if [ -f "$CURSOR_PROCESS_PATH" ]; then
- log_info "💾 [保存] 已保存Cursor路径: $CURSOR_PROCESS_PATH"
- else
- log_warn "⚠️ [警告] 未找到Cursor应用,请确认已安装"
- fi
- return 0
- fi
-
- log_warn "⚠️ [警告] 发现 Cursor 进程正在运行"
- # 💾 保存进程信息
- log_info "💾 [保存] 已保存Cursor路径: $CURSOR_PROCESS_PATH"
- get_process_details "cursor"
-
- 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 ! ps aux | grep -i "/Applications/Cursor.app" | grep -v grep > /dev/null; then
- log_info "✅ [成功] Cursor 进程已成功关闭"
- return 0
- fi
-
- log_warn "⏳ [等待] 等待进程关闭,尝试 $attempt/$max_attempts..."
- ((attempt++))
- done
-
- log_error "❌ [错误] 在 $max_attempts 次尝试后仍无法关闭 Cursor 进程"
- get_process_details "cursor"
- log_error "💥 [错误] 请手动关闭进程后重试"
- exit 1
-}
-
-# 备份配置文件
-backup_config() {
- if [ ! -f "$STORAGE_FILE" ]; then
- log_warn "配置文件不存在,跳过备份"
- 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" "$backup_file"
- log_info "配置已备份到: $backup_file"
- else
- log_error "备份失败"
- exit 1
- fi
-}
-
-# 生成随机 ID
-generate_random_id() {
- # 生成32字节(64个十六进制字符)的随机数
- openssl rand -hex 32
-}
-
-# 生成随机 UUID
-generate_uuid() {
- uuidgen | tr '[:upper:]' '[:lower:]'
-}
-
-# 修改现有文件
-modify_or_add_config() {
- local key="$1"
- local value="$2"
- local file="$3"
-
- if [ ! -f "$file" ]; then
- log_error "文件不存在: $file"
- return 1
- fi
-
- # 确保文件可写
- chmod 644 "$file" || {
- log_error "无法修改文件权限: $file"
- return 1
- }
-
- # 创建临时文件
- local temp_file=$(mktemp)
-
- # 检查key是否存在
- if grep -q "\"$key\":" "$file"; then
- # key存在,执行替换
- sed "s/\"$key\":[[:space:]]*\"[^\"]*\"/\"$key\": \"$value\"/" "$file" > "$temp_file" || {
- log_error "修改配置失败: $key"
- rm -f "$temp_file"
- return 1
- }
- else
- # key不存在,添加新的key-value对
- sed "s/}$/,\n \"$key\": \"$value\"\n}/" "$file" > "$temp_file" || {
- log_error "添加配置失败: $key"
- rm -f "$temp_file"
- return 1
- }
- fi
-
- # 检查临时文件是否为空
- if [ ! -s "$temp_file" ]; then
- log_error "生成的临时文件为空"
- rm -f "$temp_file"
- return 1
- fi
-
- # 使用 cat 替换原文件内容
- cat "$temp_file" > "$file" || {
- log_error "无法写入文件: $file"
- rm -f "$temp_file"
- return 1
- }
-
- rm -f "$temp_file"
-
- # 恢复文件权限
- chmod 444 "$file"
-
- return 0
-}
-
-# 生成新的配置
-generate_new_config() {
- echo
- log_warn "机器码处理"
-
- # 默认不重置机器码
- reset_choice=0
-
- # 记录日志以便调试
- echo "[INPUT_DEBUG] 机器码重置选项: 不重置 (默认)" >> "$LOG_FILE"
-
- # 处理 - 默认为不重置
- log_info "默认不重置机器码,将仅修改js文件"
-
- # 确保配置文件目录存在
- if [ -f "$STORAGE_FILE" ]; then
- log_info "发现已有配置文件: $STORAGE_FILE"
-
- # 备份现有配置(以防万一)
- backup_config
- else
- log_warn "未找到配置文件,这是正常的,脚本将跳过ID修改"
- fi
-
- echo
- log_info "配置处理完成"
-}
-
-# 清理 Cursor 之前的修改
-clean_cursor_app() {
- log_info "尝试清理 Cursor 之前的修改..."
-
- # 如果存在备份,直接恢复备份
- local latest_backup=""
-
- # 查找最新的备份
- latest_backup=$(find /tmp -name "Cursor.app.backup_*" -type d -print 2>/dev/null | sort -r | head -1)
-
- if [ -n "$latest_backup" ] && [ -d "$latest_backup" ]; then
- log_info "找到现有备份: $latest_backup"
- log_info "正在恢复原始版本..."
-
- # 停止 Cursor 进程
- check_and_kill_cursor
-
- # 恢复备份
- sudo rm -rf "$CURSOR_APP_PATH"
- sudo cp -R "$latest_backup" "$CURSOR_APP_PATH"
- sudo chown -R "$CURRENT_USER:staff" "$CURSOR_APP_PATH"
- sudo chmod -R 755 "$CURSOR_APP_PATH"
-
- log_info "已恢复原始版本"
- return 0
- else
- log_warn "未找到现有备份,尝试重新安装 Cursor..."
- echo "您可以从 https://cursor.sh 下载并重新安装 Cursor"
- echo "或者继续执行此脚本,将尝试修复现有安装"
-
- # 可以在这里添加重新下载和安装的逻辑
- return 1
- fi
-}
-
-# 修改 Cursor 主程序文件(安全模式)
-modify_cursor_app_files() {
- log_info "正在安全修改 Cursor 主程序文件..."
- log_info "详细日志将记录到: $LOG_FILE"
-
- # 先清理之前的修改
- clean_cursor_app
-
- # 验证应用是否存在
- if [ ! -d "$CURSOR_APP_PATH" ]; then
- log_error "未找到 Cursor.app,请确认安装路径: $CURSOR_APP_PATH"
- return 1
- fi
-
- # 定义目标文件 - 将extensionHostProcess.js放在最前面优先处理
- local target_files=(
- "${CURSOR_APP_PATH}/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js"
- "${CURSOR_APP_PATH}/Contents/Resources/app/out/main.js"
- "${CURSOR_APP_PATH}/Contents/Resources/app/out/vs/code/node/cliProcessMain.js"
- )
-
- # 检查文件是否存在并且是否已修改
- local need_modification=false
- local missing_files=false
-
- log_debug "检查目标文件..."
- for file in "${target_files[@]}"; do
- if [ ! -f "$file" ]; then
- log_warn "文件不存在: ${file/$CURSOR_APP_PATH\//}"
- echo "[FILE_CHECK] 文件不存在: $file" >> "$LOG_FILE"
- missing_files=true
- continue
- fi
-
- echo "[FILE_CHECK] 文件存在: $file ($(wc -c < "$file") 字节)" >> "$LOG_FILE"
-
- if ! grep -q "return crypto.randomUUID()" "$file" 2>/dev/null; then
- log_info "文件需要修改: ${file/$CURSOR_APP_PATH\//}"
- grep -n "IOPlatformUUID" "$file" | head -3 >> "$LOG_FILE" || echo "[FILE_CHECK] 未找到 IOPlatformUUID" >> "$LOG_FILE"
- need_modification=true
- break
- else
- log_info "文件已修改: ${file/$CURSOR_APP_PATH\//}"
- fi
- done
-
- # 如果所有文件都已修改或不存在,则退出
- if [ "$missing_files" = true ]; then
- log_error "部分目标文件不存在,请确认 Cursor 安装是否完整"
- return 1
- fi
-
- if [ "$need_modification" = false ]; then
- log_info "所有目标文件已经被修改过,无需重复操作"
- return 0
- fi
-
- # 创建临时工作目录
- local timestamp=$(date +%Y%m%d_%H%M%S)
- local temp_dir="/tmp/cursor_reset_${timestamp}"
- local temp_app="${temp_dir}/Cursor.app"
- local backup_app="/tmp/Cursor.app.backup_${timestamp}"
-
- log_debug "创建临时目录: $temp_dir"
- echo "[TEMP_DIR] 创建临时目录: $temp_dir" >> "$LOG_FILE"
-
- # 清理可能存在的旧临时目录
- if [ -d "$temp_dir" ]; then
- log_info "清理已存在的临时目录..."
- rm -rf "$temp_dir"
- fi
-
- # 创建新的临时目录
- mkdir -p "$temp_dir" || {
- log_error "无法创建临时目录: $temp_dir"
- echo "[ERROR] 无法创建临时目录: $temp_dir" >> "$LOG_FILE"
- return 1
- }
-
- # 备份原应用
- log_info "备份原应用..."
- echo "[BACKUP] 开始备份: $CURSOR_APP_PATH -> $backup_app" >> "$LOG_FILE"
-
- cp -R "$CURSOR_APP_PATH" "$backup_app" || {
- log_error "无法创建应用备份"
- echo "[ERROR] 备份失败: $CURSOR_APP_PATH -> $backup_app" >> "$LOG_FILE"
- rm -rf "$temp_dir"
- return 1
- }
-
- echo "[BACKUP] 备份完成" >> "$LOG_FILE"
-
- # 复制应用到临时目录
- log_info "创建临时工作副本..."
- echo "[COPY] 开始复制: $CURSOR_APP_PATH -> $temp_dir" >> "$LOG_FILE"
-
- cp -R "$CURSOR_APP_PATH" "$temp_dir" || {
- log_error "无法复制应用到临时目录"
- echo "[ERROR] 复制失败: $CURSOR_APP_PATH -> $temp_dir" >> "$LOG_FILE"
- rm -rf "$temp_dir" "$backup_app"
- return 1
- }
-
- echo "[COPY] 复制完成" >> "$LOG_FILE"
-
- # 确保临时目录的权限正确
- chown -R "$CURRENT_USER:staff" "$temp_dir"
- chmod -R 755 "$temp_dir"
-
- # 移除签名(增强兼容性)
- log_info "移除应用签名..."
- echo "[CODESIGN] 移除签名: $temp_app" >> "$LOG_FILE"
-
- codesign --remove-signature "$temp_app" 2>> "$LOG_FILE" || {
- log_warn "移除应用签名失败"
- echo "[WARN] 移除签名失败: $temp_app" >> "$LOG_FILE"
- }
-
- # 移除所有相关组件的签名
- local components=(
- "$temp_app/Contents/Frameworks/Cursor Helper.app"
- "$temp_app/Contents/Frameworks/Cursor Helper (GPU).app"
- "$temp_app/Contents/Frameworks/Cursor Helper (Plugin).app"
- "$temp_app/Contents/Frameworks/Cursor Helper (Renderer).app"
- )
-
- for component in "${components[@]}"; do
- if [ -e "$component" ]; then
- log_info "正在移除签名: $component"
- codesign --remove-signature "$component" || {
- log_warn "移除组件签名失败: $component"
- }
- fi
- done
-
- # 修改目标文件 - 优先处理js文件
- local modified_count=0
- local files=(
- "${temp_app}/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js"
- "${temp_app}/Contents/Resources/app/out/main.js"
- "${temp_app}/Contents/Resources/app/out/vs/code/node/cliProcessMain.js"
- )
-
- for file in "${files[@]}"; do
- if [ ! -f "$file" ]; then
- log_warn "文件不存在: ${file/$temp_dir\//}"
- continue
- fi
-
- log_debug "处理文件: ${file/$temp_dir\//}"
- echo "[PROCESS] 开始处理文件: $file" >> "$LOG_FILE"
- echo "[PROCESS] 文件大小: $(wc -c < "$file") 字节" >> "$LOG_FILE"
-
- # 输出文件部分内容到日志
- echo "[FILE_CONTENT] 文件头部 100 行:" >> "$LOG_FILE"
- head -100 "$file" 2>/dev/null | grep -v "^$" | head -50 >> "$LOG_FILE"
- echo "[FILE_CONTENT] ..." >> "$LOG_FILE"
-
- # 创建文件备份
- cp "$file" "${file}.bak" || {
- log_error "无法创建文件备份: ${file/$temp_dir\//}"
- echo "[ERROR] 无法创建文件备份: $file" >> "$LOG_FILE"
- continue
- }
-
- # 使用 sed 替换而不是字符串操作
- if [[ "$file" == *"extensionHostProcess.js"* ]]; then
- log_debug "处理 extensionHostProcess.js 文件..."
- echo "[PROCESS_DETAIL] 开始处理 extensionHostProcess.js 文件" >> "$LOG_FILE"
-
- # 检查是否包含目标代码
- if grep -q 'i.header.set("x-cursor-checksum' "$file"; then
- log_debug "找到 x-cursor-checksum 设置代码"
- echo "[FOUND] 找到 x-cursor-checksum 设置代码" >> "$LOG_FILE"
-
- # 记录匹配的行到日志
- grep -n 'i.header.set("x-cursor-checksum' "$file" >> "$LOG_FILE"
-
- # 执行特定的替换
- if sed -i.tmp 's/i\.header\.set("x-cursor-checksum",e===void 0?`${p}${t}`:`${p}${t}\/${e}`)/i.header.set("x-cursor-checksum",e===void 0?`${p}${t}`:`${p}${t}\/${p}`)/' "$file"; then
- log_info "成功修改 x-cursor-checksum 设置代码"
- echo "[SUCCESS] 成功完成 x-cursor-checksum 设置代码替换" >> "$LOG_FILE"
- # 记录修改后的行
- grep -n 'i.header.set("x-cursor-checksum' "$file" >> "$LOG_FILE"
- ((modified_count++))
- log_info "成功修改文件: ${file/$temp_dir\//}"
- else
- log_error "修改 x-cursor-checksum 设置代码失败"
- echo "[ERROR] 替换 x-cursor-checksum 设置代码失败" >> "$LOG_FILE"
- cp "${file}.bak" "$file"
- fi
- else
- log_warn "未找到 x-cursor-checksum 设置代码"
- echo "[FILE_CHECK] 未找到 x-cursor-checksum 设置代码" >> "$LOG_FILE"
-
- # 记录文件部分内容到日志以便排查
- echo "[FILE_CONTENT] 文件中包含 'header.set' 的行:" >> "$LOG_FILE"
- grep -n "header.set" "$file" | head -20 >> "$LOG_FILE"
-
- echo "[FILE_CONTENT] 文件中包含 'checksum' 的行:" >> "$LOG_FILE"
- grep -n "checksum" "$file" | head -20 >> "$LOG_FILE"
- fi
-
- echo "[PROCESS_DETAIL] 完成处理 extensionHostProcess.js 文件" >> "$LOG_FILE"
- elif grep -q "IOPlatformUUID" "$file"; then
- log_debug "找到 IOPlatformUUID 关键字"
- echo "[FOUND] 找到 IOPlatformUUID 关键字" >> "$LOG_FILE"
- grep -n "IOPlatformUUID" "$file" | head -5 >> "$LOG_FILE"
-
- # 定位 IOPlatformUUID 相关函数
- if grep -q "function a\$" "$file"; then
- # 检查是否已经修改过
- if grep -q "return crypto.randomUUID()" "$file"; then
- log_info "文件已经包含 randomUUID 调用,跳过修改"
- ((modified_count++))
- continue
- fi
-
- # 针对 main.js 中发现的代码结构进行修改
- if sed -i.tmp 's/function a\$(t){switch/function a\$(t){return crypto.randomUUID(); switch/' "$file"; then
- log_debug "成功注入 randomUUID 调用到 a\$ 函数"
- ((modified_count++))
- log_info "成功修改文件: ${file/$temp_dir\//}"
- else
- log_error "修改 a\$ 函数失败"
- cp "${file}.bak" "$file"
- fi
- elif grep -q "async function v5" "$file"; then
- # 检查是否已经修改过
- if grep -q "return crypto.randomUUID()" "$file"; then
- log_info "文件已经包含 randomUUID 调用,跳过修改"
- ((modified_count++))
- continue
- fi
-
- # 替代方法 - 修改 v5 函数
- if sed -i.tmp 's/async function v5(t){let e=/async function v5(t){return crypto.randomUUID(); let e=/' "$file"; then
- log_debug "成功注入 randomUUID 调用到 v5 函数"
- ((modified_count++))
- log_info "成功修改文件: ${file/$temp_dir\//}"
- else
- log_error "修改 v5 函数失败"
- cp "${file}.bak" "$file"
- fi
- else
- # 检查是否已经注入了自定义代码
- if grep -q "// Cursor ID 修改工具注入" "$file"; then
- log_info "文件已经包含自定义注入代码,跳过修改"
- ((modified_count++))
- continue
- fi
-
- # 使用更通用的注入方法
- log_warn "未找到具体函数,尝试使用通用修改方法"
- inject_code="
-// Cursor ID 修改工具注入 - $(date +%Y%m%d%H%M%S)
-// 随机设备ID生成器注入 - $(date +%s)
-const randomDeviceId_$(date +%s) = () => {
- try {
- return require('crypto').randomUUID();
- } catch (e) {
- return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => {
- const r = Math.random() * 16 | 0;
- return (c === 'x' ? r : (r & 0x3 | 0x8)).toString(16);
- });
- }
-};
-"
- # 将代码注入到文件开头
- echo "$inject_code" > "${file}.new"
- cat "$file" >> "${file}.new"
- mv "${file}.new" "$file"
-
- # 替换调用点
- sed -i.tmp 's/await v5(!1)/randomDeviceId_'"$(date +%s)"'()/g' "$file"
- sed -i.tmp 's/a\$(t)/randomDeviceId_'"$(date +%s)"'()/g' "$file"
-
- log_debug "完成通用修改"
- ((modified_count++))
- log_info "使用通用方法成功修改文件: ${file/$temp_dir\//}"
- fi
- else
- # 未找到 IOPlatformUUID,可能是文件结构变化
- log_warn "未找到 IOPlatformUUID,尝试替代方法"
-
- # 检查是否已经注入或修改过
- if grep -q "return crypto.randomUUID()" "$file" || grep -q "// Cursor ID 修改工具注入" "$file"; then
- log_info "文件已经被修改过,跳过修改"
- ((modified_count++))
- continue
- fi
-
- # 尝试找其他关键函数如 getMachineId 或 getDeviceId
- if grep -q "function t\$()" "$file" || grep -q "async function y5" "$file"; then
- log_debug "找到设备ID相关函数"
-
- # 修改 MAC 地址获取函数
- if grep -q "function t\$()" "$file"; then
- sed -i.tmp 's/function t\$(){/function t\$(){return "00:00:00:00:00:00";/' "$file"
- log_debug "修改 MAC 地址获取函数成功"
- fi
-
- # 修改设备ID获取函数
- if grep -q "async function y5" "$file"; then
- sed -i.tmp 's/async function y5(t){/async function y5(t){return crypto.randomUUID();/' "$file"
- log_debug "修改设备ID获取函数成功"
- fi
-
- ((modified_count++))
- log_info "使用替代方法成功修改文件: ${file/$temp_dir\//}"
- else
- # 最后尝试的通用方法 - 在文件顶部插入重写函数定义
- log_warn "未找到任何已知函数,使用最通用的方法"
-
- inject_universal_code="
-// Cursor ID 修改工具注入 - $(date +%Y%m%d%H%M%S)
-// 全局拦截设备标识符 - $(date +%s)
-const originalRequire_$(date +%s) = require;
-require = function(module) {
- const result = originalRequire_$(date +%s)(module);
- if (module === 'crypto' && result.randomUUID) {
- const originalRandomUUID_$(date +%s) = result.randomUUID;
- result.randomUUID = function() {
- return '${new_uuid}';
- };
- }
- return result;
-};
-
-// 覆盖所有可能的系统ID获取函数
-global.getMachineId = function() { return '${machine_id}'; };
-global.getDeviceId = function() { return '${device_id}'; };
-global.macMachineId = '${mac_machine_id}';
-"
- # 将代码注入到文件开头
- local new_uuid=$(uuidgen | tr '[:upper:]' '[:lower:]')
- local machine_id="auth0|user_$(openssl rand -hex 16)"
- local device_id=$(uuidgen | tr '[:upper:]' '[:lower:]')
- local mac_machine_id=$(openssl rand -hex 32)
-
- inject_universal_code=${inject_universal_code//\$\{new_uuid\}/$new_uuid}
- inject_universal_code=${inject_universal_code//\$\{machine_id\}/$machine_id}
- inject_universal_code=${inject_universal_code//\$\{device_id\}/$device_id}
- inject_universal_code=${inject_universal_code//\$\{mac_machine_id\}/$mac_machine_id}
-
- echo "$inject_universal_code" > "${file}.new"
- cat "$file" >> "${file}.new"
- mv "${file}.new" "$file"
-
- log_debug "完成通用覆盖"
- ((modified_count++))
- log_info "使用最通用方法成功修改文件: ${file/$temp_dir\//}"
- fi
- fi
-
- # 添加在关键操作后记录日志
- echo "[MODIFIED] 文件修改后内容:" >> "$LOG_FILE"
- grep -n "return crypto.randomUUID()" "$file" | head -3 >> "$LOG_FILE"
-
- # 清理临时文件
- rm -f "${file}.tmp" "${file}.bak"
- echo "[PROCESS] 文件处理完成: $file" >> "$LOG_FILE"
- done
-
- if [ "$modified_count" -eq 0 ]; then
- log_error "未能成功修改任何文件"
- rm -rf "$temp_dir"
- return 1
- fi
-
- # 重新签名应用(增加重试机制)
- local max_retry=3
- local retry_count=0
- local sign_success=false
-
- while [ $retry_count -lt $max_retry ]; do
- ((retry_count++))
- log_info "尝试签名 (第 $retry_count 次)..."
-
- # 使用更详细的签名参数
- if codesign --sign - --force --deep --preserve-metadata=entitlements,identifier,flags "$temp_app" 2>&1 | tee /tmp/codesign.log; then
- # 验证签名
- if codesign --verify -vvvv "$temp_app" 2>/dev/null; then
- sign_success=true
- log_info "应用签名验证通过"
- break
- else
- log_warn "签名验证失败,错误日志:"
- cat /tmp/codesign.log
- fi
- else
- log_warn "签名失败,错误日志:"
- cat /tmp/codesign.log
- fi
-
- sleep 1
- done
-
- if ! $sign_success; then
- log_error "经过 $max_retry 次尝试仍无法完成签名"
- log_error "请手动执行以下命令完成签名:"
- echo -e "${BLUE}sudo codesign --sign - --force --deep '${temp_app}'${NC}"
- echo -e "${YELLOW}操作完成后,请手动将应用复制到原路径:${NC}"
- echo -e "${BLUE}sudo cp -R '${temp_app}' '/Applications/'${NC}"
- log_info "临时文件保留在:${temp_dir}"
- return 1
- fi
-
- # 替换原应用
- log_info "安装修改版应用..."
- if ! sudo rm -rf "$CURSOR_APP_PATH" || ! sudo cp -R "$temp_app" "/Applications/"; then
- log_error "应用替换失败,正在恢复..."
- sudo rm -rf "$CURSOR_APP_PATH"
- sudo cp -R "$backup_app" "$CURSOR_APP_PATH"
- rm -rf "$temp_dir" "$backup_app"
- return 1
- fi
-
- # 清理临时文件
- rm -rf "$temp_dir" "$backup_app"
-
- # 设置权限
- sudo chown -R "$CURRENT_USER:staff" "$CURSOR_APP_PATH"
- sudo chmod -R 755 "$CURSOR_APP_PATH"
-
- log_info "Cursor 主程序文件修改完成!原版备份在: ${backup_app/$HOME/\~}"
- return 0
-}
-
-# 显示文件树结构
-show_file_tree() {
- local base_dir=$(dirname "$STORAGE_FILE")
- echo
- log_info "文件结构:"
- echo -e "${BLUE}$base_dir${NC}"
- echo "├── globalStorage"
- echo "│ ├── storage.json (已修改)"
- echo "│ └── backups"
-
- # 列出备份文件
- if [ -d "$BACKUP_DIR" ]; then
- local backup_files=("$BACKUP_DIR"/*)
- if [ ${#backup_files[@]} -gt 0 ]; then
- for file in "${backup_files[@]}"; do
- if [ -f "$file" ]; then
- echo "│ └── $(basename "$file")"
- fi
- done
- else
- echo "│ └── (空)"
- fi
- fi
- echo
-}
-
-# 显示公众号信息
-show_follow_info() {
- echo
- echo -e "${GREEN}================================${NC}"
- echo -e "${YELLOW} 关注公众号【煎饼果子卷AI】一起交流更多Cursor技巧和AI知识(脚本免费、关注公众号加群有更多技巧和大佬) ${NC}"
- echo -e "${GREEN}================================${NC}"
- echo
-}
-
-# 禁用自动更新
-disable_auto_update() {
- local updater_path="$HOME/Library/Application Support/Caches/cursor-updater"
- local app_update_yml="/Applications/Cursor.app/Contents/Resources/app-update.yml"
-
- echo
- log_info "正在禁用 Cursor 自动更新..."
-
- # 备份并清空 app-update.yml
- if [ -f "$app_update_yml" ]; then
- log_info "备份并修改 app-update.yml..."
- if ! sudo cp "$app_update_yml" "${app_update_yml}.bak" 2>/dev/null; then
- log_warn "备份 app-update.yml 失败,继续执行..."
- fi
-
- if sudo bash -c "echo '' > \"$app_update_yml\"" && \
- sudo chmod 444 "$app_update_yml"; then
- log_info "成功禁用 app-update.yml"
- else
- log_error "修改 app-update.yml 失败,请手动执行以下命令:"
- echo -e "${BLUE}sudo cp \"$app_update_yml\" \"${app_update_yml}.bak\"${NC}"
- echo -e "${BLUE}sudo bash -c 'echo \"\" > \"$app_update_yml\"'${NC}"
- echo -e "${BLUE}sudo chmod 444 \"$app_update_yml\"${NC}"
- fi
- else
- log_warn "未找到 app-update.yml 文件"
- fi
-
- # 同时也处理 cursor-updater
- log_info "处理 cursor-updater..."
- if sudo rm -rf "$updater_path" && \
- sudo touch "$updater_path" && \
- sudo chmod 444 "$updater_path"; then
- log_info "成功禁用 cursor-updater"
- else
- log_error "禁用 cursor-updater 失败,请手动执行以下命令:"
- echo -e "${BLUE}sudo rm -rf \"$updater_path\" && sudo touch \"$updater_path\" && sudo chmod 444 \"$updater_path\"${NC}"
- fi
-
- echo
- log_info "验证方法:"
- echo "1. 运行命令:ls -l \"$updater_path\""
- echo " 确认文件权限显示为:r--r--r--"
- echo "2. 运行命令:ls -l \"$app_update_yml\""
- echo " 确认文件权限显示为:r--r--r--"
- echo
- log_info "完成后请重启 Cursor"
-}
-
-# 新增恢复功能选项
-restore_feature() {
- # 检查备份目录是否存在
- if [ ! -d "$BACKUP_DIR" ]; then
- log_warn "备份目录不存在"
- return 1
- fi
-
- # 使用 find 命令获取备份文件列表并存储到数组
- backup_files=()
- while IFS= read -r file; do
- [ -f "$file" ] && backup_files+=("$file")
- done < <(find "$BACKUP_DIR" -name "*.backup_*" -type f 2>/dev/null | sort)
-
- # 检查是否找到备份文件
- if [ ${#backup_files[@]} -eq 0 ]; then
- log_warn "未找到任何备份文件"
- return 1
- fi
-
- echo
- log_info "可用的备份文件:"
-
- # 构建菜单选项字符串
- menu_options="退出 - 不恢复任何文件"
- for i in "${!backup_files[@]}"; do
- menu_options="$menu_options|$(basename "${backup_files[$i]}")"
- done
-
- # 使用菜单选择函数
- select_menu_option "请使用上下箭头选择要恢复的备份文件,按Enter确认:" "$menu_options" 0
- choice=$?
-
- # 处理用户输入
- if [ "$choice" = "0" ]; then
- log_info "跳过恢复操作"
- return 0
- fi
-
- # 获取选择的备份文件 (减1是因为第一个选项是"退出")
- local selected_backup="${backup_files[$((choice-1))]}"
-
- # 验证文件存在性和可读性
- if [ ! -f "$selected_backup" ] || [ ! -r "$selected_backup" ]; then
- log_error "无法访问选择的备份文件"
- return 1
- fi
-
- # 尝试恢复配置
- if cp "$selected_backup" "$STORAGE_FILE"; then
- chmod 644 "$STORAGE_FILE"
- chown "$CURRENT_USER" "$STORAGE_FILE"
- log_info "已从备份文件恢复配置: $(basename "$selected_backup")"
- return 0
- else
- log_error "恢复配置失败"
- return 1
- fi
-}
-
-# 解决"应用已损坏,无法打开"问题
-fix_damaged_app() {
- log_info "正在修复"应用已损坏"问题..."
-
- # 检查Cursor应用是否存在
- if [ ! -d "$CURSOR_APP_PATH" ]; then
- log_error "未找到Cursor应用: $CURSOR_APP_PATH"
- return 1
- fi
-
- log_info "尝试移除隔离属性..."
- if sudo find "$CURSOR_APP_PATH" -print0 \
- | xargs -0 sudo xattr -d com.apple.quarantine 2>/dev/null
- log_info "成功移除隔离属性"
- else
- log_warn "移除隔离属性失败,尝试其他方法..."
- fi
-
- log_info "尝试重新签名应用..."
- if sudo codesign --force --deep --sign - "$CURSOR_APP_PATH" 2>/dev/null; then
- log_info "应用重新签名成功"
- else
- log_warn "应用重新签名失败"
- fi
-
- echo
- log_info "修复完成!请尝试重新打开Cursor应用"
- echo
- echo -e "${YELLOW}如果仍然无法打开,您可以尝试以下方法:${NC}"
- echo "1. 在系统偏好设置->安全性与隐私中,点击"仍要打开"按钮"
- echo "2. 暂时关闭Gatekeeper(不建议): sudo spctl --master-disable"
- echo "3. 重新下载安装Cursor应用"
- echo
- echo -e "${BLUE}参考链接: https://sysin.org/blog/macos-if-crashes-when-opening/${NC}"
-
- return 0
-}
-
-# 新增:通用菜单选择函数
-# 参数:
-# $1 - 提示信息
-# $2 - 选项数组,格式为 "选项1|选项2|选项3"
-# $3 - 默认选项索引 (从0开始)
-# 返回: 选中的选项索引 (从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='\033[A'
- local cursor_down='\033[B'
- local enter_key=$'\n'
-
- # 保存光标位置
- tput sc
-
- # 显示提示信息
- echo -e "$prompt"
-
- # 第一次显示菜单
- for i in "${!options[@]}"; do
- if [ $i -eq $selected_index ]; then
- echo -e " ${GREEN}►${NC} ${options[$i]}"
- else
- echo -e " ${options[$i]}"
- fi
- done
-
- # 循环处理键盘输入
- while true; do
- # 读取单个按键
- read -rsn3 key_input
-
- # 检测按键
- case "$key_input" in
- # 上箭头键
- $'\033[A')
- if [ $selected_index -gt 0 ]; then
- ((selected_index--))
- fi
- ;;
- # 下箭头键
- $'\033[B')
- if [ $selected_index -lt $((${#options[@]}-1)) ]; then
- ((selected_index++))
- fi
- ;;
- # Enter键
- "")
- echo # 换行
- log_info "您选择了: ${options[$selected_index]}"
- return $selected_index
- ;;
- esac
-
- # 恢复光标位置
- tput rc
-
- # 重新显示菜单
- for i in "${!options[@]}"; do
- if [ $i -eq $selected_index ]; then
- echo -e " ${GREEN}►${NC} ${options[$i]}"
- else
- echo -e " ${options[$i]}"
- fi
- done
- done
-}
-
-# 主函数
-main() {
-
- # 初始化日志文件
- initialize_log
- log_info "脚本启动..."
-
- # 记录系统信息
- log_info "系统信息: $(uname -a)"
- log_info "当前用户: $CURRENT_USER"
- log_cmd_output "sw_vers" "macOS 版本信息"
- log_cmd_output "which codesign" "codesign 路径"
- log_cmd_output "ls -la \"$CURSOR_APP_PATH\"" "Cursor 应用信息"
-
- # 新增环境检查
- if [[ $(uname) != "Darwin" ]]; then
- log_error "本脚本仅支持 macOS 系统"
- exit 1
- fi
-
- clear
- # 显示 Logo
- echo -e "
- ██████╗██╗ ██╗██████╗ ███████╗ ██████╗ ██████╗
- ██╔════╝██║ ██║██╔══██╗██╔════╝██╔═══██╗██╔══██╗
- ██║ ██║ ██║██████╔╝███████╗██║ ██║██████╔╝
- ██║ ██║ ██║██╔══██╗╚════██║██║ ██║██╔══██╗
- ╚██████╗╚██████╔╝██║ ██║███████║╚██████╔╝██║ ██║
- ╚═════╝ ╚═════╝ ╚═╝ ╚═╝╚══════╝ ╚═════╝ ╚═╝ ╚═╝
- "
- echo -e "${BLUE}================================${NC}"
- echo -e "${GREEN}🚀 Cursor 防掉试用Pro删除工具 ${NC}"
- echo -e "${YELLOW}📱 关注公众号【煎饼果子卷AI】 ${NC}"
- echo -e "${YELLOW}🤝 一起交流更多Cursor技巧和AI知识(脚本免费、关注公众号加群有更多技巧和大佬) ${NC}"
- echo -e "${BLUE}================================${NC}"
- echo
- echo -e "${YELLOW}💡 [重要提示]${NC} 本工具采用分阶段执行策略,既能彻底清理又能修改机器码"
- echo -e "${YELLOW}💡 [重要提示]${NC} 本工具免费,如果对您有帮助,请关注公众号【煎饼果子卷AI】"
- echo
-
- # 📋 执行流程说明
- echo
- echo -e "${GREEN}📋 [执行流程]${NC} 本脚本将按以下步骤执行:"
- echo -e "${BLUE} 1️⃣ 检测并关闭Cursor进程${NC}"
- echo -e "${BLUE} 2️⃣ 保存Cursor程序路径信息${NC}"
- echo -e "${BLUE} 3️⃣ 删除指定的Cursor试用相关文件夹${NC}"
- echo -e "${BLUE} 📁 ~/Library/Application Support/Cursor${NC}"
- echo -e "${BLUE} 📁 ~/.cursor${NC}"
- echo -e "${BLUE} 3.5️⃣ 预创建必要目录结构,避免权限问题${NC}"
- echo -e "${BLUE} 4️⃣ 重新启动Cursor让其生成新的配置文件${NC}"
- echo -e "${BLUE} 5️⃣ 等待配置文件生成完成(最多45秒)${NC}"
- echo -e "${BLUE} 6️⃣ 关闭Cursor进程${NC}"
- echo -e "${BLUE} 7️⃣ 修改新生成的机器码配置文件${NC}"
- echo -e "${BLUE} 8️⃣ 显示操作完成统计信息${NC}"
- echo
- echo -e "${YELLOW}⚠️ [注意事项]${NC}"
- echo -e "${YELLOW} • 脚本执行过程中请勿手动操作Cursor${NC}"
- echo -e "${YELLOW} • 建议在执行前关闭所有Cursor窗口${NC}"
- echo -e "${YELLOW} • 执行完成后需要重新启动Cursor${NC}"
- echo -e "${YELLOW} • 原配置文件会自动备份到backups文件夹${NC}"
- echo -e "${YELLOW} • 需要Python3环境来处理JSON配置文件${NC}"
- echo
-
- # 🤔 用户确认
- echo -e "${GREEN}🤔 [确认]${NC} 请确认您已了解上述执行流程"
- read -p "是否继续执行?(输入 y 或 yes 继续,其他任意键退出): " confirmation
- if [[ ! "$confirmation" =~ ^(y|yes)$ ]]; then
- echo -e "${YELLOW}👋 [退出]${NC} 用户取消执行,脚本退出"
- exit 0
- fi
- echo -e "${GREEN}✅ [确认]${NC} 用户确认继续执行"
- echo
-
- # 🚀 执行主要功能
- check_permissions
- check_and_kill_cursor
-
- # 🚨 重要警告提示
- echo
- echo -e "${RED}🚨 [重要警告]${NC} ============================================"
- log_warn "⚠️ [风控提醒] Cursor 风控机制非常严格!"
- log_warn "⚠️ [必须删除] 必须完全删除指定文件夹,不能有任何残留设置"
- log_warn "⚠️ [防掉试用] 只有彻底清理才能有效防止掉试用Pro状态"
- echo -e "${RED}🚨 [重要警告]${NC} ============================================"
- echo
-
- # 🎯 执行 Cursor 防掉试用Pro删除文件夹功能
- log_info "🚀 [开始] 开始执行核心功能..."
- remove_cursor_trial_folders
-
- # 🔄 重启Cursor让其重新生成配置文件
- restart_cursor_and_wait
-
- # 🛠️ 修改机器码配置
- modify_machine_code_config
-
- # 🎉 显示操作完成信息
- echo
- log_info "🎉 [完成] Cursor 防掉试用Pro删除操作已完成!"
- echo
-
- # 📱 显示公众号信息
- echo -e "${GREEN}================================${NC}"
- echo -e "${YELLOW}📱 关注公众号【煎饼果子卷AI】一起交流更多Cursor技巧和AI知识(脚本免费、关注公众号加群有更多技巧和大佬) ${NC}"
- echo -e "${GREEN}================================${NC}"
- echo
- log_info "🚀 [提示] 现在可以重新启动 Cursor 尝试使用了!"
- echo
-
- # 🚫 以下功能已暂时屏蔽
- log_warn "⚠️ [提示] 以下功能已暂时屏蔽:"
- log_info "📋 [说明] - 自动更新禁用功能"
- log_info "📋 [说明] - 应用修复功能"
- log_info "📋 [说明] 如需恢复这些功能,请联系开发者"
- echo
-
- # 🎉 脚本执行完成
- log_info "🎉 [完成] 所有操作已完成!"
- echo
- log_info "💡 [提示] 如果需要恢复机器码修改功能,请联系开发者"
- log_warn "⚠️ [注意] 重启 Cursor 后生效"
- echo
- log_info "🚀 [下一步] 现在可以启动 Cursor 尝试使用了!"
- echo
-
- # 记录脚本完成信息
- log_info "📝 [日志] 脚本执行完成"
- echo "========== Cursor 防掉试用Pro删除工具日志结束 $(date) ==========" >> "$LOG_FILE"
-
- # 显示日志文件位置
- echo
- log_info "📄 [日志] 详细日志已保存到: $LOG_FILE"
- echo "如遇问题请将此日志文件提供给开发者以协助排查"
- echo
-}
-
-# 执行主函数
-main
-
diff --git a/scripts/run/cursor_mac_id_modifier.sh b/scripts/run/cursor_mac_id_modifier.sh
index bf2bf24..49cd0d5 100644
--- a/scripts/run/cursor_mac_id_modifier.sh
+++ b/scripts/run/cursor_mac_id_modifier.sh
@@ -1,488 +1,752 @@
#!/bin/bash
# ========================================
-# Cursor macOS 机器码修改脚本 (增强权限修复版)
+# 🍎 Cursor macOS ID Modifier Script 🚀
# ========================================
-#
-# 🔧 权限修复增强:
-# - 集成用户提供的核心权限修复命令
-# - 特别处理logs目录权限问题
-# - 解决EACCES: permission denied错误
-# - 确保Cursor能正常启动
-#
-# 🚨 如果遇到权限错误,脚本会自动执行:
-# - sudo chown -R $(whoami) ~/Library/"Application Support"/Cursor
-# - sudo chown -R $(whoami) ~/.cursor
-# - chmod -R u+w ~/Library/"Application Support"/Cursor
-# - chmod -R u+w ~/.cursor/extensions
-#
+# Purpose: Reset Cursor trial by modifying device identifiers
+# Platform: macOS (Intel & Apple Silicon)
+# Requirements: sudo privileges, Cursor installed
# ========================================
-# 设置错误处理
set -e
-# 定义日志文件路径
-LOG_FILE="/tmp/cursor_free_trial_reset.log"
+# ========================================
+# CONFIGURATION
+# ========================================
+
+readonly SCRIPT_NAME="Cursor macOS ID Modifier"
+readonly LOG_FILE="/tmp/cursor_mac_id_modifier.log"
+readonly CURSOR_CONFIG_DIR="$HOME/Library/Application Support/Cursor"
+readonly STORAGE_FILE="$CURSOR_CONFIG_DIR/User/globalStorage/storage.json"
+readonly BACKUP_DIR="$CURSOR_CONFIG_DIR/User/globalStorage/backups"
+readonly CURSOR_APP_PATH="/Applications/Cursor.app"
+
+# Colors for output
+readonly RED='\033[0;31m'
+readonly GREEN='\033[0;32m'
+readonly YELLOW='\033[1;33m'
+readonly BLUE='\033[0;34m'
+readonly NC='\033[0m'
-# 初始化日志文件
-initialize_log() {
- echo "========== Cursor Free Trial Reset Tool Log Start $(date) ==========" > "$LOG_FILE"
+# ========================================
+# UTILITY FUNCTIONS
+# ========================================
+
+# Initialize logging
+init_log() {
+ echo "========== $SCRIPT_NAME 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
-
-# 日志函数 - 同时输出到终端和日志文件
+# Logging functions with emojis
log_info() {
- echo -e "${GREEN}[INFO]${NC} $1"
+ 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 -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 -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 -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"
+# Generate UUID
+generate_uuid() {
+ uuidgen | tr '[:upper:]' '[:lower:]'
}
-# 🚀 新增 Cursor 防掉试用Pro删除文件夹功能
-remove_cursor_trial_folders() {
- echo
- log_info "🎯 [核心功能] 正在执行 Cursor 防掉试用Pro删除文件夹..."
- log_info "📋 [说明] 此功能将删除指定的Cursor相关文件夹以重置试用状态"
- echo
+# Generate random hex string
+generate_random_hex() {
+ local length=${1:-32}
+ openssl rand -hex $((length / 2))
+}
- # 定义需要删除的文件夹路径
- local folders_to_delete=(
- "$HOME/Library/Application Support/Cursor"
- "$HOME/.cursor"
- )
+# ========================================
+# PERMISSION MANAGEMENT
+# ========================================
- log_info "📂 [检测] 将检查以下文件夹:"
- for folder in "${folders_to_delete[@]}"; do
- echo " 📁 $folder"
- done
- echo
+# Fix Cursor directory permissions
+fix_cursor_permissions() {
+ log_info "Fixing Cursor directory permissions..."
+
+ local cursor_support_dir="$HOME/Library/Application Support/Cursor"
+ local cursor_home_dir="$HOME/.cursor"
+
+ # Ensure directories exist
+ mkdir -p "$cursor_support_dir" 2>/dev/null || true
+ mkdir -p "$cursor_home_dir/extensions" 2>/dev/null || true
+
+ # Fix ownership and permissions
+ if sudo chown -R "$(whoami)" "$cursor_support_dir" 2>/dev/null; then
+ log_info "Fixed ownership for Application Support/Cursor"
+ else
+ log_warn "Failed to fix ownership for Application Support/Cursor"
+ fi
+
+ if sudo chown -R "$(whoami)" "$cursor_home_dir" 2>/dev/null; then
+ log_info "Fixed ownership for .cursor"
+ else
+ log_warn "Failed to fix ownership for .cursor"
+ fi
+
+ if chmod -R u+w "$cursor_support_dir" 2>/dev/null; then
+ log_info "Fixed permissions for Application Support/Cursor"
+ else
+ log_warn "Failed to fix permissions for Application Support/Cursor"
+ fi
+
+ if chmod -R u+w "$cursor_home_dir/extensions" 2>/dev/null; then
+ log_info "Fixed permissions for .cursor/extensions"
+ else
+ log_warn "Failed to fix permissions for .cursor/extensions"
+ fi
+
+ log_info "Permission fix completed"
+}
- local deleted_count=0
- local skipped_count=0
- local error_count=0
+# ===========
+EMENT
+# ==================
- # 删除指定文件夹
- 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++))
+stop_cursor_
+ log_info "Stopping Cursor
+
+ local max_attempts=5
+ local attempt=1
+
+s ]; do
+ local cursor_pids=$(pgrep -i
+
+
+ log_info "All Cursor processes stopped"
+ n 0
fi
- echo
- done
-
- # 🔧 重要:删除文件夹后立即执行权限修复
- log_info "� [权限修复] 删除文件夹后立即执行权限修复..."
- echo
-
- # 调用统一的权限修复函数
- ensure_cursor_directory_permissions
+
+mpts)"
+
+ if [ $attempt -eq $hen
+ e
+ else
- # 显示操作统计
- log_info "📊 [统计] 操作完成统计:"
- echo " ✅ 成功删除: $deleted_count 个文件夹"
- echo " ⏭️ 跳过处理: $skipped_count 个文件夹"
- echo " ❌ 删除失败: $error_count 个文件夹"
- echo
+ fi
+
+ sleep 2
+ ttempt++))
- if [ $deleted_count -gt 0 ]; then
- log_info "🎉 [完成] Cursor 防掉试用Pro文件夹删除完成!"
- else
- log_warn "🤔 [提示] 未找到需要删除的文件夹,可能已经清理过了"
- fi
- echo
+
+s"
+ return 1
}
-# 🔄 重启Cursor并等待配置文件生成
-restart_cursor_and_wait() {
- echo
- log_info "🔄 [重启] 正在重启Cursor以重新生成配置文件..."
+# ===========
+GEMENT
+# ================
- if [ -z "$CURSOR_PROCESS_PATH" ]; then
- log_error "❌ [错误] 未找到Cursor进程信息,无法重启"
- return 1
- fi
+# Remove Cursor trial folders
+ {
+ log_info "s..."
+
+ local folders_to_delete=(
+ "$HOME/Li/Cursor"
- log_info "📍 [路径] 使用路径: $CURSOR_PROCESS_PATH"
+ )
+
+nt=0
+ local skippe
+
+ for folder in "${]}"; do
+ log_debug older"
+
+ if [ -d "$folder" ]; then
+ log_warn "Found folder, removing: $folder"
+ if ; then
+ log_info "Succ"
+ )
- if [ ! -f "$CURSOR_PROCESS_PATH" ]; then
- log_error "❌ [错误] Cursor可执行文件不存在: $CURSOR_PROCESS_PATH"
- return 1
- fi
+ log_error "Failed
+ fi
+ else
+ log_info "Folder not flder"
+ ((skipped_count++))
+ i
+ done
+
+ log_info "Folder removal ced_count"
+
+ # al
- # 🔧 启动前权限修复
- log_info "🔧 [启动前权限] 执行启动前权限修复..."
- ensure_cursor_directory_permissions
+
+ return 0
+}
- # 启动Cursor
- log_info "🚀 [启动] 正在启动Cursor..."
- "$CURSOR_PROCESS_PATH" > /dev/null 2>&1 &
- CURSOR_PID=$!
+# =======
- log_info "⏳ [等待] 等待15秒让Cursor完全启动并生成配置文件..."
- sleep 15
+# =========================
- # 检查配置文件是否生成
- local config_path="$HOME/Library/Application Support/Cursor/User/globalStorage/storage.json"
- local max_wait=30
+ config
+start_cursor_for_config() {
+ log_info
+
+"
+
+ if [ ! -f "$cursor_exec" ]; then
+ log_error "Cursor ele"
+eturn 1
+ fi
+
+rting
+ fix_cursor_permissions
+
+ # Start Cursor
+ "$cursor_execut1 &
+
+ log_info "Cursor startedid"
+
+ # Wait for config file generation
+ local config_path="$STORAGE_FILE"
+ locat=60
local waited=0
-
- while [ ! -f "$config_path" ] && [ $waited -lt $max_wait ]; do
- log_info "⏳ [等待] 等待配置文件生成... ($waited/$max_wait 秒)"
- sleep 1
- waited=$((waited + 1))
+
+.."
+ while [ do
+ sleep 2
+ waited=$((waited + 2))
+ en
+ log_innds)"
+ fi
done
-
+
if [ -f "$config_path" ]; then
- log_info "✅ [成功] 配置文件已生成: $config_path"
-
- # 🛡️ 关键修复:配置文件生成后立即确保权限正确
- ensure_cursor_directory_permissions
+ loy"
+ ation
+missions
+ return 0
else
- log_warn "⚠️ [警告] 配置文件未在预期时间内生成,继续执行..."
+ log_warn "Configuration file not generated wi
+ rn 1
+fi
+}
- # 即使配置文件未生成,也要确保目录权限正确
- ensure_cursor_directory_permissions
- fi
+# ========================================
+# CONFIGT
+# ========================================
- # 强制关闭Cursor
- log_info "🔄 [关闭] 正在关闭Cursor以进行配置修改..."
- if [ ! -z "$CURSOR_PID" ]; then
- kill $CURSOR_PID 2>/dev/null || true
+e
+check_python3() {
+ if ! command -v python3 >/dev/null 2>&1; then
+ log_error "Python3 is required but not found"
+
+n 1
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="$HOME/Library/Application Support/Cursor/User/globalStorage/storage.json"
- local cursor_app_data="$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"
+# Backupfiguration
+backup_config() {
+ if [ ! -f "$STORAGE_FILE" ]; then
+ log_warn "Configuration file not fo backup"
+ retu
+ fi
+
+ IR"
+%S)"
+
+ if cp "$STORAGE_FILE" "$backup_n
+ chmod 644 "$backup_file"
+"
+ return 0
else
- log_info "✅ [检查] Python3环境可用: $(python3 --version)"
+ion"
+ return 1
fi
+}
- # 检查配置文件
+ion
+modify_machine_code_config() {
+..."
+
+ if ! check_python3; then
+ 1
+ fi
+
+ local config_path="_FILE"
+
+s
if [ ! -f "$config_path" ]; then
- issues+=("配置文件不存在: $config_path")
- else
- # 验证JSON格式
- if python3 -c "import json; json.load(open('$config_path'))" 2>/dev/null; then
- log_info "✅ [检查] 配置文件格式正确"
+ log_error "Configuration file not f
+"
+
+ if start_cursor_for_config; then
+ log_info
else
- issues+=("配置文件格式错误或损坏")
+"
+ return 1
fi
fi
+
+ # Verify JSON format
+ if ! p
+
+turn 1
+ fi
+
+ log_info "Configuration file format is val"
+
+ # Baion
+ if ! backup_config; then
+ return 1
+ fi
+
+ s
+uid)
+ local UUID=$(gen
+ local MACHINE_ID="auth0|user_$(gene)"
+ local SQM_ID="{$(uuidgen | tr '[:lo"
+
+ log_info "Generated new device identifiers"
+
+ython
+ local py"
+import json
+import sys
- # 检查Cursor目录结构
- if [ ! -d "$cursor_app_data" ]; then
- issues+=("Cursor应用数据目录不存在: $cursor_app_data")
- fi
+try:
+ with open('$config_path', 'r', enc8') as f:
+d(f)
- # 检查Cursor应用安装
- if [ ! -d "$cursor_app_path" ]; then
- issues+=("未找到Cursor应用安装: $cursor_app_path")
- else
- log_info "✅ [检查] 找到Cursor应用: $cursor_app_path"
- fi
+ # Update properties
+ properties_to_update = {
+ ID',
+ 'telemetry.macMachineId': '$MAC_MACHINE_ID',
+ ID',
+QM_ID'
+ }
- # 检查目录权限
- if [ -d "$cursor_app_data" ] && [ ! -w "$cursor_app_data" ]; then
- issues+=("Cursor应用数据目录无写入权限: $cursor_app_data")
- fi
+ for key, value in properties_to_update.items():
+ alue
- # 返回检查结果
- if [ ${#issues[@]} -eq 0 ]; then
- log_info "✅ [环境检查] 所有检查通过"
+ wi
+se)
+
+ print('SUCCESS')
+except Exception as e:
+ prin
+ sys.exit(1)
+" 2>&1
+
+ if echo "$python_result" | grep -q "SUCC
+ log_info "Configuration updated successfully"
+
+ ssions
+ chmod 644 "$config_path" 2>/dev/null || true
+ sions
+
+ log_info "Machine code conpleted"
+ log_"
+
+INE_ID"
+ echo " •D"
+ echo " • sqmId: $SQM_ID"
+
return 0
- else
- log_error "❌ [环境检查] 发现 ${#issues[@]} 个问题:"
- for issue in "${issues[@]}"; do
- echo -e "${RED} • $issue${NC}"
- done
+
+tion"
+ log_debug "Pytho"
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"
+CUTION
- if [ ! -f "$cursor_executable" ]; then
- log_error "❌ [错误] 未找到Cursor可执行文件: $cursor_executable"
- return 1
- fi
- log_info "📍 [路径] 使用Cursor路径: $cursor_executable"
+ites
+check_prerequisite{
+ log_info "Checking prerequ.."
+
+nstalled
+ if [hen
+ log_error "Cursor applicationH"
+sh/"
+ exit 1
+i
+
+ # Check Python3
+ if ! check_python3; then
+ exit 1
+ fi
+
+ log_info "Prerequisites check passed"
+}
- # 🚀 启动前权限修复
- ensure_cursor_directory_permissions
+# Show menu
+show_menu() {
+ echo
+ echo "Please select an option:"
+ echo "1.ed)"
- # 启动Cursor
- "$cursor_executable" > /dev/null 2>&1 &
- local cursor_pid=$!
- log_info "🚀 [启动] Cursor已启动,PID: $cursor_pid"
+ echo "3. Resy"
+ echo "4. Exit"
+ echo
+}
- log_info "⏳ [等待] 请等待Cursor完全加载(约30秒)..."
- log_info "💡 [提示] 您可以在Cursor完全加载后手动关闭它"
+# Main function
+main() {
+ echo "===="
+E"
+ echo "======"
+ eco
+
+ init_log
+ check_prerequisites
+
+ while true; do
+ show_menu
+ read -p " choice
+
+ case $choice in
+ 1)
+ log_
+
+ esses
+ l_folders
+
+ if modify_machine_code_config; then
+ echo
+====="
+ log_info "Full reset completed successfully!"
+ log_inf"
+ log_inal"
+ break
+ else
+ log_error "Machine code modifiled"
+ it 1
+ fi
+ ;;
+ 2)
+ .."
+
+_processes
+
+ if modify_machine_code_chen
+
+ ="
+ log_info "Machine code modification completed!"
+ log_info "========================
+ log_info "You can now restart Cursor"
+ break
+ else
+ log_error "Machin"
- # 等待配置文件生成
- local config_path="$HOME/Library/Application Support/Cursor/User/globalStorage/storage.json"
- local max_wait=60
- local waited=0
+ fi
- 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
+ 3)
+ log_info "Starting trial folder reset only..."
+
+ stop_cursor_processes
+ lders
+
+
+ log_info "========================================"
+ log_info "Trial folder reset com!"
+======="
+ log_info "You can nowrsor"
+ break
+ ;;
+ 4)
+ "
+ 0
+
+ *)
+ log_warn "Invalid choice. Please en"
+ ;;
+ esac
done
+
+ echo
+ log_inLE"
+ echo
+}
- if [ -f "$config_path" ]; then
- log_info "✅ [成功] 配置文件已生成!"
- log_info "💡 [提示] 现在可以关闭Cursor并重新运行脚本"
- return 0
- else
- log_warn "⚠️ [超时] 配置文件未在预期时间内生成"
- log_info "💡 [建议] 请手动操作Cursor(如创建新文件)以触发配置生成"
- return 1
- fi
+# Exec
+" "$@ainmlo
+g_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"
+}
+
+# Generate UUID
+generate_uuid() {
+ uuidgen | tr '[:upper:]' '[:lower:]'
+}
+
+# Generate random hex string
+generate_random_hex() {
+ local length=${1:-32}
+ openssl rand -hex $((length / 2))
}
-# 🛡️ 统一权限修复函数(优化版本)
-ensure_cursor_directory_permissions() {
- log_info "🛡️ [权限修复] 执行核心权限修复命令..."
+# ========================================
+# PERMISSION MANAGEMENT
+# ========================================
+# Fix Cursor directory permissions
+fix_cursor_permissions() {
+ log_info "Fixing Cursor directory permissions..."
+
local cursor_support_dir="$HOME/Library/Application Support/Cursor"
local cursor_home_dir="$HOME/.cursor"
-
- # 确保目录存在
+
+ # Ensure directories exist
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 $(whoami) ~/Library/"Application Support"/Cursor
+
+ # Fix ownership and permissions
if sudo chown -R "$(whoami)" "$cursor_support_dir" 2>/dev/null; then
- log_info "✅ [1/4] sudo chown Application Support/Cursor 成功"
+ log_info "Fixed ownership for Application Support/Cursor"
else
- log_warn "⚠️ [1/4] sudo chown Application Support/Cursor 失败"
+ log_warn "Failed to fix ownership for Application Support/Cursor"
fi
-
- # 命令2: sudo chown -R $(whoami) ~/.cursor
+
if sudo chown -R "$(whoami)" "$cursor_home_dir" 2>/dev/null; then
- log_info "✅ [2/4] sudo chown .cursor 成功"
+ log_info "Fixed ownership for .cursor"
else
- log_warn "⚠️ [2/4] sudo chown .cursor 失败"
+ log_warn "Failed to fix ownership for .cursor"
fi
-
- # 命令3: chmod -R u+w ~/Library/"Application Support"/Cursor
+
if chmod -R u+w "$cursor_support_dir" 2>/dev/null; then
- log_info "✅ [3/4] chmod Application Support/Cursor 成功"
+ log_info "Fixed permissions for Application Support/Cursor"
else
- log_warn "⚠️ [3/4] chmod Application Support/Cursor 失败"
+ log_warn "Failed to fix permissions for Application Support/Cursor"
fi
-
- # 命令4: chmod -R u+w ~/.cursor/extensions
+
if chmod -R u+w "$cursor_home_dir/extensions" 2>/dev/null; then
- log_info "✅ [4/4] chmod .cursor/extensions 成功"
+ log_info "Fixed permissions for .cursor/extensions"
else
- log_warn "⚠️ [4/4] chmod .cursor/extensions 失败"
+ log_warn "Failed to fix permissions for .cursor/extensions"
fi
-
- log_info "✅ [完成] 核心权限修复命令执行完成"
- return 0
+
+ log_info "Permission fix completed"
}
-# 关键权限修复函数(简化版本)
-fix_cursor_permissions_critical() {
- log_info "🚨 [关键权限修复] 执行权限修复..."
- ensure_cursor_directory_permissions
-}
+# ========================================
+# PROCESS MANAGEMENT
+# ========================================
-# 🚀 Cursor启动前权限确保(简化版本)
-ensure_cursor_startup_permissions() {
- log_info "🚀 [启动前权限] 执行权限修复..."
- ensure_cursor_directory_permissions
+# Stop all Cursor processes
+stop_cursor_processes() {
+ log_info "Stopping Cursor processes..."
+
+ local max_attempts=5
+ local attempt=1
+
+ while [ $attempt -le $max_attempts ]; do
+ local cursor_pids=$(pgrep -i cursor 2>/dev/null || true)
+
+ if [ -z "$cursor_pids" ]; then
+ log_info "All Cursor processes stopped"
+ return 0
+ fi
+
+ log_warn "Found running Cursor processes, stopping... (attempt $attempt/$max_attempts)"
+
+ if [ $attempt -eq $max_attempts ]; then
+ pkill -9 -i cursor 2>/dev/null || true
+ else
+ pkill -i cursor 2>/dev/null || true
+ fi
+
+ sleep 2
+ ((attempt++))
+ done
+
+ log_error "Failed to stop all Cursor processes"
+ return 1
}
+# ========================================
+# FOLDER MANAGEMENT
+# ========================================
-
-
-
-# 🛠️ 修改机器码配置(增强版)
-modify_machine_code_config() {
- local mode=${1:-"FULL"}
-
- echo
- log_info "🛠️ [配置] 正在修改机器码配置..."
-
- local config_path="$HOME/Library/Application Support/Cursor/User/globalStorage/storage.json"
-
- # 增强的配置文件检查
- if [ ! -f "$config_path" ]; then
- log_error "❌ [错误] 配置文件不存在: $config_path"
- echo
- log_info "💡 [解决方案] 请尝试以下步骤:"
- echo -e "${BLUE} 1️⃣ 手动启动Cursor应用程序${NC}"
- echo -e "${BLUE} 2️⃣ 等待Cursor完全加载(约30秒)${NC}"
- echo -e "${BLUE} 3️⃣ 关闭Cursor应用程序${NC}"
- echo -e "${BLUE} 4️⃣ 重新运行此脚本${NC}"
- echo
- log_warn "⚠️ [备选方案] 如果问题持续:"
- echo -e "${BLUE} • 选择脚本的'重置环境+修改机器码'选项${NC}"
- echo -e "${BLUE} • 该选项会自动生成配置文件${NC}"
- echo
-
- # 提供用户选择
- read -p "是否现在尝试启动Cursor生成配置文件?(y/n): " user_choice
- if [[ "$user_choice" =~ ^(y|yes)$ ]]; then
- log_info "🚀 [尝试] 正在尝试启动Cursor..."
- if start_cursor_to_generate_config; then
- return 0
+# Remove Cursor trial folders
+remove_cursor_trial_folders() {
+ log_info "Removing Cursor trial folders..."
+
+ local folders_to_delete=(
+ "$HOME/Library/Application Support/Cursor"
+ "$HOME/.cursor"
+ )
+
+ local deleted_count=0
+ local skipped_count=0
+
+ for folder in "${folders_to_delete[@]}"; do
+ log_debug "Checking folder: $folder"
+
+ if [ -d "$folder" ]; then
+ log_warn "Found folder, removing: $folder"
+ if rm -rf "$folder"; then
+ log_info "Successfully removed: $folder"
+ ((deleted_count++))
+ else
+ log_error "Failed to remove: $folder"
fi
+ else
+ log_info "Folder not found (skipping): $folder"
+ ((skipped_count++))
fi
+ done
+
+ log_info "Folder removal completed - Deleted: $deleted_count, Skipped: $skipped_count"
+
+ # Fix permissions after folder removal
+ fix_cursor_permissions
+
+ return 0
+}
- return 1
- fi
+# ========================================
+# CURSOR MANAGEMENT
+# ========================================
- # 验证配置文件格式并显示结构
- log_info "🔍 [验证] 检查配置文件格式..."
- if ! python3 -c "import json; json.load(open('$config_path'))" 2>/dev/null; then
- log_error "❌ [错误] 配置文件格式错误或损坏"
- log_info "💡 [建议] 配置文件可能已损坏,建议选择'重置环境+修改机器码'选项"
+# Start Cursor to generate config
+start_cursor_for_config() {
+ log_info "Starting Cursor to generate configuration..."
+
+ local cursor_executable="$CURSOR_APP_PATH/Contents/MacOS/Cursor"
+
+ if [ ! -f "$cursor_executable" ]; then
+ log_error "Cursor executable not found: $cursor_executable"
return 1
fi
- log_info "✅ [验证] 配置文件格式正确"
-
- # 显示当前配置文件中的相关属性
- log_info "📋 [当前配置] 检查现有的遥测属性:"
- python3 -c "
-import json
-try:
- with open('$config_path', 'r', encoding='utf-8') as f:
- config = json.load(f)
-
- properties = ['telemetry.machineId', 'telemetry.macMachineId', 'telemetry.devDeviceId', 'telemetry.sqmId']
- for prop in properties:
- if prop in config:
- value = config[prop]
- display_value = value[:20] + '...' if len(value) > 20 else value
- print(f' ✓ {prop} = {display_value}')
- else:
- print(f' - {prop} (不存在,将创建)')
-except Exception as e:
- print(f'Error reading config: {e}')
-"
- echo
-
- # 显示操作进度
- log_info "⏳ [进度] 1/5 - 生成新的设备标识符..."
-
- # 生成新的ID
- local MAC_MACHINE_ID=$(uuidgen | tr '[:upper:]' '[:lower:]')
- local UUID=$(uuidgen | tr '[:upper:]' '[:lower:]')
- local MACHINE_ID="auth0|user_$(openssl rand -hex 32)"
- local SQM_ID="{$(uuidgen | tr '[:lower:]' '[:upper:]')}"
-
- log_info "✅ [进度] 1/5 - 设备标识符生成完成"
+
+ # Fix permissions before starting
+ fix_cursor_permissions
+
+ # Start Cursor
+ "$cursor_executable" > /dev/null 2>&1 &
+ local cursor_pid=$!
+ log_info "Cursor started with PID: $cursor_pid"
+
+ # Wait for config file generation
+ local config_path="$STORAGE_FILE"
+ local max_wait=60
+ local waited=0
+
+ log_info "Waiting for configuration file generation..."
+ while [ ! -f "$config_path" ] && [ $waited -lt $max_wait ]; do
+ sleep 2
+ waited=$((waited + 2))
+ if [ $((waited % 10)) -eq 0 ]; then
+ log_info "Still waiting... ($waited/$max_wait seconds)"
+ fi
+ done
+
+ if [ -f "$config_path" ]; then
+ log_info "Configuration file generated successfully"
+ # Fix permissions after generation
+ fix_cursor_permissions
+ return 0
+ else
+ log_warn "Configuration file not generated within timeout"
+ return 1
+ fi
+}
- log_info "⏳ [进度] 2/5 - 创建备份目录..."
+# ========================================
+# CONFIGURATION MANAGEMENT
+# ========================================
- # 备份原始配置(增强版)
- local backup_dir="$HOME/Library/Application Support/Cursor/User/globalStorage/backups"
- if ! mkdir -p "$backup_dir"; then
- log_error "❌ [错误] 无法创建备份目录: $backup_dir"
+# Check if Python3 is available
+check_python3() {
+ if ! command -v python3 >/dev/null 2>&1; then
+ log_error "Python3 is required but not found"
+ log_info "Please install Python3: brew install python3"
return 1
fi
+ return 0
+}
- local backup_name="storage.json.backup_$(date +%Y%m%d_%H%M%S)"
- local backup_path="$backup_dir/$backup_name"
-
- log_info "⏳ [进度] 3/5 - 备份原始配置..."
- if ! cp "$config_path" "$backup_path"; then
- log_error "❌ [错误] 备份配置文件失败"
+# Backup configuration
+backup_config() {
+ if [ ! -f "$STORAGE_FILE" ]; then
+ log_warn "Configuration file not found, skipping backup"
+ 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"
+ log_info "Configuration backed up to: $(basename "$backup_file")"
+ return 0
+ else
+ log_error "Failed to backup configuration"
return 1
fi
+}
- # 验证备份是否成功
- if [ -f "$backup_path" ]; then
- local backup_size=$(wc -c < "$backup_path")
- local original_size=$(wc -c < "$config_path")
- if [ "$backup_size" -eq "$original_size" ]; then
- log_info "✅ [进度] 3/5 - 配置备份成功: $backup_name"
+# Modify machine code configuration
+modify_machine_code_config() {
+ log_info "Modifying machine code configuration..."
+
+ if ! check_python3; then
+ return 1
+ fi
+
+ local config_path="$STORAGE_FILE"
+
+ # Check if config file exists
+ if [ ! -f "$config_path" ]; then
+ log_error "Configuration file not found: $config_path"
+ log_info "Attempting to generate configuration file..."
+
+ if start_cursor_for_config; then
+ log_info "Configuration file generated, continuing..."
else
- log_warn "⚠️ [警告] 备份文件大小不匹配,但继续执行"
+ log_error "Failed to generate configuration file"
+ return 1
fi
- else
- log_error "❌ [错误] 备份文件创建失败"
+ fi
+
+ # Verify JSON format
+ if ! python3 -c "import json; json.load(open('$config_path'))" 2>/dev/null; then
+ log_error "Configuration file format is invalid"
return 1
fi
-
- log_info "⏳ [进度] 4/5 - 更新配置文件..."
-
- # 使用Python修改JSON配置(更可靠,安全方式)
+
+ log_info "Configuration file format is valid"
+
+ # Backup original configuration
+ if ! backup_config; then
+ return 1
+ fi
+
+ # Generate new IDs
+ local MAC_MACHINE_ID=$(generate_uuid)
+ local UUID=$(generate_uuid)
+ local MACHINE_ID="auth0|user_$(generate_random_hex 64)"
+ local SQM_ID="{$(uuidgen | tr '[:lower:]' '[:upper:]')}"
+
+ log_info "Generated new device identifiers"
+
+ # Update configuration using Python
local python_result=$(python3 -c "
import json
import sys
@@ -491,7 +755,7 @@ try:
with open('$config_path', 'r', encoding='utf-8') as f:
config = json.load(f)
- # 安全更新配置,确保属性存在
+ # Update properties
properties_to_update = {
'telemetry.machineId': '$MACHINE_ID',
'telemetry.macMachineId': '$MAC_MACHINE_ID',
@@ -500,10 +764,6 @@ try:
}
for key, value in properties_to_update.items():
- if key in config:
- print(f' ✓ 更新属性: {key}')
- else:
- print(f' + 添加属性: {key}')
config[key] = value
with open('$config_path', 'w', encoding='utf-8') as f:
@@ -515,2391 +775,155 @@ except Exception as e:
sys.exit(1)
" 2>&1)
- # 🔧 关键修复:正确解析Python执行结果
- local python_exit_code=$?
- local python_success=false
-
- # 检查Python脚本是否成功执行
- if [ $python_exit_code -eq 0 ]; then
- # 检查输出中是否包含SUCCESS标记(忽略其他输出)
- if echo "$python_result" | grep -q "SUCCESS"; then
- python_success=true
- log_info "✅ [Python] 配置修改执行成功"
- else
- log_warn "⚠️ [Python] 执行成功但未找到SUCCESS标记"
- log_info "💡 [调试] Python完整输出:"
- echo "$python_result"
- fi
- else
- log_error "❌ [Python] 脚本执行失败,退出码: $python_exit_code"
- log_info "💡 [调试] Python完整输出:"
- echo "$python_result"
- fi
-
- if [ "$python_success" = true ]; then
- log_info "⏳ [进度] 5/5 - 验证修改结果..."
-
- # 🔒 关键修复:在验证前确保文件权限正确
+ if echo "$python_result" | grep -q "SUCCESS"; then
+ log_info "Configuration updated successfully"
+
+ # Set proper permissions
chmod 644 "$config_path" 2>/dev/null || true
-
- # 验证修改是否成功
- local verification_result=$(python3 -c "
-import json
-try:
- with open('$config_path', 'r', encoding='utf-8') as f:
- config = json.load(f)
-
- properties_to_check = {
- 'telemetry.machineId': '$MACHINE_ID',
- 'telemetry.macMachineId': '$MAC_MACHINE_ID',
- 'telemetry.devDeviceId': '$UUID',
- 'telemetry.sqmId': '$SQM_ID'
- }
-
- verification_passed = True
- for key, expected_value in properties_to_check.items():
- actual_value = config.get(key)
- if actual_value == expected_value:
- print(f'✓ {key}: 验证通过')
- else:
- print(f'✗ {key}: 验证失败 (期望: {expected_value}, 实际: {actual_value})')
- verification_passed = False
-
- if verification_passed:
- print('VERIFICATION_SUCCESS')
- else:
- print('VERIFICATION_FAILED')
-except Exception as e:
- print(f'VERIFICATION_ERROR: {e}')
-" 2>&1)
-
- # 检查验证结果(忽略其他输出,只关注最终结果)
- if echo "$verification_result" | grep -q "VERIFICATION_SUCCESS"; then
- log_info "✅ [进度] 5/5 - 修改验证成功"
-
- # 🔐 关键修复:设置配置文件为只读保护
- if chmod 444 "$config_path" 2>/dev/null; then
- log_info "🔐 [保护] 配置文件已设置为只读保护"
- else
- log_warn "⚠️ [警告] 无法设置配置文件只读保护"
- fi
-
- # 🛡️ 关键修复:执行权限修复
- ensure_cursor_directory_permissions
-
- echo
- log_info "🎉 [成功] 机器码配置修改完成!"
- log_info "📋 [详情] 已更新以下标识符:"
- echo " 🔹 machineId: ${MACHINE_ID:0:20}..."
- echo " 🔹 macMachineId: $MAC_MACHINE_ID"
- echo " 🔹 devDeviceId: $UUID"
- echo " 🔹 sqmId: $SQM_ID"
- echo
- log_info "💾 [备份] 原配置已备份至: $backup_name"
- return 0
- else
- log_error "❌ [错误] 修改验证失败"
- log_info "💡 [验证详情]:"
- echo "$verification_result"
- log_info "🔄 [恢复] 正在恢复备份并修复权限..."
-
- # 恢复备份并确保权限正确
- if cp "$backup_path" "$config_path"; then
- chmod 644 "$config_path" 2>/dev/null || true
- ensure_cursor_directory_permissions
- log_info "✅ [恢复] 已恢复原始配置并修复权限"
- else
- log_error "❌ [错误] 恢复备份失败"
- fi
- return 1
- fi
- else
- log_error "❌ [错误] 修改配置失败"
- log_info "💡 [调试信息] Python执行详情:"
- echo "$python_result"
-
- # 尝试恢复备份并修复权限
- if [ -f "$backup_path" ]; then
- log_info "🔄 [恢复] 正在恢复备份配置并修复权限..."
- if cp "$backup_path" "$config_path"; then
- chmod 644 "$config_path" 2>/dev/null || true
- ensure_cursor_directory_permissions
- log_info "✅ [恢复] 已恢复原始配置并修复权限"
- else
- log_error "❌ [错误] 恢复备份失败"
- fi
- fi
-
- return 1
- fi
-}
-
-
-
-# 获取当前用户
-get_current_user() {
- if [ "$EUID" -eq 0 ]; then
- echo "$SUDO_USER"
- else
- echo "$USER"
- fi
-}
-
-CURRENT_USER=$(get_current_user)
-if [ -z "$CURRENT_USER" ]; then
- log_error "无法获取用户名"
- exit 1
-fi
-
-# 定义配置文件路径
-STORAGE_FILE="$HOME/Library/Application Support/Cursor/User/globalStorage/storage.json"
-BACKUP_DIR="$HOME/Library/Application Support/Cursor/User/globalStorage/backups"
-
-# 定义 Cursor 应用程序路径
-CURSOR_APP_PATH="/Applications/Cursor.app"
-
-# 新增:判断接口类型是否为Wi-Fi
-is_wifi_interface() {
- local interface_name="$1"
- # 通过networksetup判断接口类型
- networksetup -listallhardwareports | \
- awk -v dev="$interface_name" 'BEGIN{found=0} /Hardware Port: Wi-Fi/{found=1} /Device:/{if(found && $2==dev){exit 0}else{found=0}}' && return 0 || return 1
-}
-
-# 🎯 增强的MAC地址生成和验证(集成randommac.sh特性)
-generate_local_unicast_mac() {
- # 第一字节:LAA+单播(低两位10),其余随机
- local first_byte=$(( (RANDOM & 0xFC) | 0x02 ))
- local mac=$(printf '%02x:%02x:%02x:%02x:%02x:%02x' \
- $first_byte $((RANDOM%256)) $((RANDOM%256)) $((RANDOM%256)) $((RANDOM%256)) $((RANDOM%256)))
- echo "$mac"
-}
-
-# 🔍 MAC地址验证函数(基于randommac.sh)
-validate_mac_address() {
- local mac="$1"
- local regex="^([0-9A-Fa-f]{2}[:]){5}([0-9A-Fa-f]{2})$"
-
- if [[ $mac =~ $regex ]]; then
- return 0
- else
- return 1
- fi
-}
-
-
-
-# 🔄 增强的WiFi断开和重连机制
-manage_wifi_connection() {
- local action="$1" # disconnect 或 reconnect
- local interface_name="$2"
-
- if ! is_wifi_interface "$interface_name"; then
- log_info "📡 [跳过] 接口 '$interface_name' 不是WiFi,跳过WiFi管理"
- return 0
- fi
-
- case "$action" in
- "disconnect")
- log_info "📡 [WiFi] 断开WiFi连接但保持适配器开启..."
-
- # 方法1: 使用airport工具断开
- if command -v /System/Library/PrivateFrameworks/Apple80211.framework/Versions/Current/Resources/airport >/dev/null 2>&1; then
- sudo /System/Library/PrivateFrameworks/Apple80211.framework/Versions/Current/Resources/airport -z 2>>"$LOG_FILE"
- log_info "✅ [WiFi] 使用airport工具断开WiFi连接"
- else
- # 方法2: 使用networksetup断开
- local wifi_service=$(networksetup -listallhardwareports | grep -A1 "Device: $interface_name" | grep "Hardware Port:" | cut -d: -f2 | xargs)
- if [ -n "$wifi_service" ]; then
- networksetup -setairportpower "$interface_name" off 2>>"$LOG_FILE"
- sleep 2
- networksetup -setairportpower "$interface_name" on 2>>"$LOG_FILE"
- log_info "✅ [WiFi] 使用networksetup重置WiFi适配器"
- else
- log_warn "⚠️ [WiFi] 无法找到WiFi服务,跳过断开"
- fi
- fi
-
- sleep 3
- ;;
-
- "reconnect")
- log_info "📡 [WiFi] 重新连接WiFi..."
-
- # 触发网络硬件重新检测
- sudo networksetup -detectnewhardware 2>>"$LOG_FILE"
-
- # 等待网络重新连接
- log_info "⏳ [WiFi] 等待WiFi重新连接..."
- local wait_count=0
- local max_wait=30
-
- while [ $wait_count -lt $max_wait ]; do
- if ping -c 1 8.8.8.8 >/dev/null 2>&1; then
- log_info "✅ [WiFi] 网络连接已恢复"
- return 0
- fi
- sleep 2
- wait_count=$((wait_count + 2))
-
- if [ $((wait_count % 10)) -eq 0 ]; then
- log_info "⏳ [WiFi] 等待网络连接... ($wait_count/$max_wait 秒)"
- fi
- done
-
- log_warn "⚠️ [WiFi] 网络连接未在预期时间内恢复,但继续执行"
- ;;
-
- *)
- log_error "❌ [错误] 无效的WiFi管理操作: $action"
- return 1
- ;;
- esac
-}
-
-# 🛠️ 增强的第三方工具MAC地址修改
-try_third_party_mac_tool() {
- local interface_name="$1"
- local random_mac="$2"
- local success=false
- local tool_used=""
-
- log_info "🛠️ [第三方] 尝试使用第三方工具修改MAC地址"
-
- # 🔍 检测可用的第三方工具
- local available_tools=()
- if command -v macchanger >/dev/null 2>&1; then
- available_tools+=("macchanger")
- fi
- if command -v spoof-mac >/dev/null 2>&1; then
- available_tools+=("spoof-mac")
- fi
-
- if [ ${#available_tools[@]} -eq 0 ]; then
- log_warn "⚠️ [警告] 未检测到可用的第三方MAC地址修改工具"
- log_info "💡 [建议] 可以安装以下工具:"
- echo " • brew install spoof-mac"
- echo " • brew install macchanger"
- return 1
- fi
-
- log_info "🔍 [检测] 发现可用工具: ${available_tools[*]}"
-
- # 🎯 优先使用macchanger
- if [[ " ${available_tools[*]} " =~ " macchanger " ]]; then
- log_info "🔧 [macchanger] 尝试使用macchanger修改接口 '$interface_name' 的MAC地址..."
-
- # 先关闭接口
- sudo ifconfig "$interface_name" down 2>>"$LOG_FILE"
- sleep 2
-
- if sudo macchanger -m "$random_mac" "$interface_name" >>"$LOG_FILE" 2>&1; then
- success=true
- tool_used="macchanger"
- log_info "✅ [成功] macchanger修改成功"
- else
- log_warn "⚠️ [失败] macchanger修改失败"
- fi
-
- # 重新启用接口
- sudo ifconfig "$interface_name" up 2>>"$LOG_FILE"
- sleep 2
- fi
-
- # 🎯 如果macchanger失败,尝试spoof-mac
- if ! $success && [[ " ${available_tools[*]} " =~ " spoof-mac " ]]; then
- log_info "🔧 [spoof-mac] 尝试使用spoof-mac修改接口 '$interface_name' 的MAC地址..."
-
- if sudo spoof-mac set "$random_mac" "$interface_name" >>"$LOG_FILE" 2>&1; then
- success=true
- tool_used="spoof-mac"
- log_info "✅ [成功] spoof-mac修改成功"
- else
- log_warn "⚠️ [失败] spoof-mac修改失败"
- fi
- fi
-
- if $success; then
- log_info "🎉 [成功] 第三方工具 ($tool_used) 修改MAC地址成功"
+ fix_cursor_permissions
+
+ log_info "Machine code configuration completed"
+ log_info "Updated identifiers:"
+ echo " • machineId: ${MACHINE_ID:0:20}..."
+ echo " • macMachineId: $MAC_MACHINE_ID"
+ echo " • devDeviceId: $UUID"
+ echo " • sqmId: $SQM_ID"
+
return 0
else
- log_error "❌ [失败] 所有第三方工具都修改失败"
+ log_error "Failed to update configuration"
+ log_debug "Python output: $python_result"
return 1
fi
}
-# 🔍 增强的macOS环境检测和兼容性评估
-detect_macos_environment() {
- local macos_version=$(sw_vers -productVersion)
- local macos_major=$(echo "$macos_version" | cut -d. -f1)
- local macos_minor=$(echo "$macos_version" | cut -d. -f2)
- local hardware_type=""
-
- # 检测硬件类型
- if [[ $(uname -m) == "arm64" ]]; then
- hardware_type="Apple Silicon"
- else
- hardware_type="Intel"
- fi
-
- log_info "🔍 [环境] 系统环境检测: macOS $macos_version ($hardware_type)"
-
- # 检查SIP状态
- local sip_status=$(csrutil status 2>/dev/null | grep -o "enabled\|disabled" || echo "unknown")
- log_info "🔒 [SIP] 系统完整性保护状态: $sip_status"
-
- # 设置环境变量
- export MACOS_VERSION="$macos_version"
- export MACOS_MAJOR="$macos_major"
- export MACOS_MINOR="$macos_minor"
- export HARDWARE_TYPE="$hardware_type"
- export SIP_STATUS="$sip_status"
-
- # 🎯 增强的兼容性检查
- local compatibility_level="FULL"
- local compatibility_issues=()
-
- # 检查macOS版本兼容性
- if [[ $macos_major -ge 14 ]]; then
- compatibility_issues+=("macOS $macos_major+ 对MAC地址修改有严格限制")
- compatibility_level="LIMITED"
- elif [[ $macos_major -ge 12 ]]; then
- compatibility_issues+=("macOS $macos_major 可能对MAC地址修改有部分限制")
- compatibility_level="PARTIAL"
- fi
-
- # 检查硬件兼容性
- if [[ "$hardware_type" == "Apple Silicon" ]]; then
- compatibility_issues+=("Apple Silicon硬件对MAC地址修改有硬件级限制")
- if [[ "$compatibility_level" == "FULL" ]]; then
- compatibility_level="PARTIAL"
- else
- compatibility_level="MINIMAL"
- fi
- fi
+# ========================================
+# MAIN EXECUTION
+# ========================================
- # 检查SIP影响
- if [[ "$sip_status" == "enabled" ]]; then
- compatibility_issues+=("系统完整性保护(SIP)可能阻止某些修改方法")
+# Check prerequisites
+check_prerequisites() {
+ log_info "Checking prerequisites..."
+
+ # Check if Cursor is installed
+ if [ ! -d "$CURSOR_APP_PATH" ]; then
+ log_error "Cursor application not found at: $CURSOR_APP_PATH"
+ log_info "Please install Cursor first: https://cursor.sh/"
+ exit 1
fi
-
- # 设置兼容性级别
- export MAC_COMPATIBILITY_LEVEL="$compatibility_level"
-
- # 显示兼容性评估结果
- case "$compatibility_level" in
- "FULL")
- log_info "✅ [兼容性] 完全兼容 - 支持所有MAC地址修改方法"
- ;;
- "PARTIAL")
- log_warn "⚠️ [兼容性] 部分兼容 - 某些方法可能失败"
- ;;
- "LIMITED")
- log_warn "⚠️ [兼容性] 有限兼容 - 大多数方法可能失败"
- ;;
- "MINIMAL")
- log_error "❌ [兼容性] 最小兼容 - MAC地址修改可能完全失败"
- ;;
- esac
-
- if [ ${#compatibility_issues[@]} -gt 0 ]; then
- log_info "📋 [兼容性问题]:"
- for issue in "${compatibility_issues[@]}"; do
- echo " • $issue"
- done
+
+ # Check Python3
+ if ! check_python3; then
+ exit 1
fi
-
- # 返回兼容性状态
- case "$compatibility_level" in
- "FULL"|"PARTIAL") return 0 ;;
- *) return 1 ;;
- esac
+
+ log_info "Prerequisites check passed"
}
-# 🚀 增强的MAC地址修改函数,支持智能方法选择
-_change_mac_for_one_interface() {
- local interface_name="$1"
-
- if [ -z "$interface_name" ]; then
- log_error "❌ [错误] _change_mac_for_one_interface: 未提供接口名称"
- return 1
- fi
-
- log_info "🚀 [开始] 开始处理接口: $interface_name"
- echo
-
- # 🔍 环境检测和兼容性评估
- detect_macos_environment
- local env_compatible=$?
- local compatibility_level="$MAC_COMPATIBILITY_LEVEL"
-
- # 📡 获取当前MAC地址
- local current_mac=$(ifconfig "$interface_name" | awk '/ether/{print $2}')
- if [ -z "$current_mac" ]; then
- log_warn "⚠️ [警告] 无法获取接口 '$interface_name' 的当前MAC地址,可能已禁用或不存在"
- return 1
- else
- log_info "📍 [当前] 接口 '$interface_name' 当前MAC地址: $current_mac"
- fi
-
- # 🎯 自动生成新MAC地址
- local random_mac=$(generate_local_unicast_mac)
- log_info "🎲 [生成] 为接口 '$interface_name' 生成新MAC地址: $random_mac"
-
- # 📋 显示修改计划
+# Show menu
+show_menu() {
echo
- log_info "📋 [计划] MAC地址修改计划:"
- echo " 🔹 接口: $interface_name"
- echo " 🔹 当前MAC: $current_mac"
- echo " 🔹 目标MAC: $random_mac"
- echo " 🔹 兼容性: $compatibility_level"
+ echo "🎯 Please select an option:"
echo
-
- # 🔄 WiFi预处理
- manage_wifi_connection "disconnect" "$interface_name"
-
- # 🛠️ 执行MAC地址修改(多方法尝试)
- local mac_change_success=false
- local method_used=""
- local methods_tried=()
-
- # 📊 根据兼容性级别选择方法顺序
- local method_order=()
- case "$compatibility_level" in
- "FULL")
- method_order=("ifconfig" "third-party" "networksetup")
- ;;
- "PARTIAL")
- method_order=("third-party" "ifconfig" "networksetup")
- ;;
- "LIMITED"|"MINIMAL")
- method_order=("third-party" "networksetup" "ifconfig")
- ;;
- esac
-
- log_info "🛠️ [方法] 将按以下顺序尝试修改方法: ${method_order[*]}"
+ echo " 1️⃣ 🔥 Reset trial folders + Modify machine code (Recommended)"
+ echo " 2️⃣ ⚙️ Modify machine code only"
+ echo " 3️⃣ 🗂️ Reset trial folders only"
+ echo " 4️⃣ 🚪 Exit"
echo
+}
- # 🔄 逐个尝试修改方法
- for method in "${method_order[@]}"; do
- log_info "🔧 [尝试] 正在尝试 $method 方法..."
- methods_tried+=("$method")
-
- case "$method" in
- "ifconfig")
- if _try_ifconfig_method "$interface_name" "$random_mac"; then
- mac_change_success=true
- method_used="ifconfig"
- break
- fi
- ;;
- "third-party")
- if try_third_party_mac_tool "$interface_name" "$random_mac"; then
- mac_change_success=true
- method_used="third-party"
+# Main function
+main() {
+ echo"
+ ██████╗██╗ ██╗██████╗ ███████╗ ██████╗ ██████╗
+ ██╔════╝██║ ██║██╔══██╗██╔════╝██╔═══██╗██╔══██╗
+ ██║ ██║ ██║██████╔╝███████╗██║ ██║██████╔╝
+ ██║ ██║ ██║██╔══██╗╚════██║██║ ██║██╔══██╗
+ ╚██████╗╚██████╔╝██║ ██║███████║╚██████╔╝██║ ██║
+ ╚═════╝ ╚═════╝ ╚═╝ ╚═╝╚══════╝ ╚═════╝ ╚═╝ ╚═╝"
+ echo
+ echo "========================================="
+ echo " 🍎 $SCRIPT_NAME"
+ echo "========================================="
+ echo
+
+ init_log
+ check_prerequisites
+
+ while true; do
+ show_menu
+ read -p "Enter your choice (1-4): " choice
+
+ case $choice in
+ 1)
+ log_info "Starting full reset (folders + machine code)..."
+
+ stop_cursor_processes
+ remove_cursor_trial_folders
+
+ if modify_machine_code_config; then
+ echo
+ echo "╔══════════════════════════════════════════════════════════════════════════════╗"
+ echo "║ ║"
+ echo "║ 🎉 SUCCESS! FULL RESET COMPLETED! 🎉 ║"
+ echo "║ ║"
+ echo "║ ✅ Trial folders removed ║"
+ echo "║ ✅ Machine code configuration updated ║"
+ echo "║ ✅ Permissions fixed ║"
+ echo "║ ║"
+ echo "║ 🚀 You can now restart Cursor to use the reset trial! ║"
+ echo "║ ║"
+ echo "╚══════════════════════════════════════════════════════════════════════════════╝"
break
+ else
+ log_error "Machine code modification failed"
+ exit 1
fi
;;
- "networksetup")
- if _try_networksetup_method "$interface_name" "$random_mac"; then
- mac_change_success=true
- method_used="networksetup"
+ 2)
+ log_info "Starting machine code modification only..."
+
+ stop_cursor_processes
+
+ if modify_machine_code_config; then
+ echo
+ log_info "========================================="
+ log_info "Machine code modification completed!"
+ log_info "========================================="
+ log_info "You can now restart Cursor"
break
+ else
+ log_error "Machine code modification failed"
+ exit 1
fi
;;
- esac
-
- log_warn "⚠️ [失败] $method 方法失败,尝试下一个方法..."
- sleep 2
- done
-
- # 🔍 验证修改结果
- if [[ $mac_change_success == true ]]; then
- log_info "🔍 [验证] 验证MAC地址修改结果..."
- sleep 3 # 等待系统更新
-
- local final_mac_check=$(ifconfig "$interface_name" | awk '/ether/{print $2}')
- log_info "📍 [检查] 接口 '$interface_name' 最终MAC地址: $final_mac_check"
-
- if [ "$final_mac_check" == "$random_mac" ]; then
- echo
- log_info "🎉 [成功] MAC地址修改成功!"
- echo " ✅ 使用方法: $method_used"
- echo " ✅ 接口: $interface_name"
- echo " ✅ 原MAC: $current_mac"
- echo " ✅ 新MAC: $final_mac_check"
-
- # 🔄 WiFi后处理
- manage_wifi_connection "reconnect" "$interface_name"
-
- return 0
- else
- log_warn "⚠️ [验证失败] MAC地址可能未生效或已被系统重置"
- log_info "💡 [提示] 期望: $random_mac, 实际: $final_mac_check"
- mac_change_success=false
- fi
- fi
-
- # ❌ 失败处理和用户选择
- if [[ $mac_change_success == false ]]; then
- echo
- log_error "❌ [失败] 所有MAC地址修改方法都失败了"
- log_info "📋 [尝试过的方法]: ${methods_tried[*]}"
-
- # 🔄 WiFi恢复
- manage_wifi_connection "reconnect" "$interface_name"
-
- # 📊 显示故障排除信息
- _show_troubleshooting_info "$interface_name"
-
- # 🎯 提供用户选择
- echo
- echo -e "${BLUE}💡 [说明]${NC} MAC地址修改失败,您可以选择:"
- echo -e "${BLUE}💡 [备注]${NC} 如果所有接口都失败,脚本会自动尝试JS内核修改方案"
- echo
-
- # 简化的用户选择
- echo "请选择操作:"
- echo " 1. 重试本接口"
- echo " 2. 跳过本接口"
- echo " 3. 退出脚本"
-
- read -p "请输入选择 (1-3): " choice
-
- case "$choice" in
- 1)
- log_info "🔄 [重试] 用户选择重试本接口"
- _change_mac_for_one_interface "$interface_name"
- ;;
- 2)
- log_info "⏭️ [跳过] 用户选择跳过本接口"
- return 1
- ;;
3)
- log_info "🚪 [退出] 用户选择退出脚本"
- exit 1
+ log_info "Starting trial folder reset only..."
+
+ stop_cursor_processes
+ remove_cursor_trial_folders
+
+ echo
+ log_info "========================================="
+ log_info "Trial folder reset completed!"
+ log_info "========================================="
+ log_info "You can now restart Cursor"
+ break
+ ;;
+ 4)
+ log_info "Exiting..."
+ exit 0
;;
*)
- log_info "⏭️ [默认] 无效选择,跳过本接口"
- return 1
+ log_warn "Invalid choice. Please enter 1-4."
;;
esac
- return 1
- fi
+ done
+
+ echo
+ log_info "Log file: $LOG_FILE"
+ echo
}
-# 🔧 增强的传统ifconfig方法(集成WiFi管理)
-_try_ifconfig_method() {
- local interface_name="$1"
- local random_mac="$2"
-
- log_info "🔧 [ifconfig] 使用传统ifconfig方法修改MAC地址"
-
- # 🔄 WiFi特殊处理已在主函数中处理,这里只需要基本的接口操作
- log_info "📡 [接口] 临时禁用接口 '$interface_name' 以修改MAC地址..."
- if ! sudo ifconfig "$interface_name" down 2>>"$LOG_FILE"; then
- log_error "❌ [错误] 禁用接口 '$interface_name' 失败"
- return 1
- fi
-
- log_info "⏳ [等待] 等待接口完全关闭..."
- sleep 3
-
- # 🎯 尝试修改MAC地址
- log_info "🎯 [修改] 设置新MAC地址: $random_mac"
- if sudo ifconfig "$interface_name" ether "$random_mac" 2>>"$LOG_FILE"; then
- log_info "✅ [成功] MAC地址设置命令执行成功"
-
- # 重新启用接口
- log_info "🔄 [启用] 重新启用接口..."
- if sudo ifconfig "$interface_name" up 2>>"$LOG_FILE"; then
- log_info "✅ [成功] 接口重新启用成功"
- sleep 2
- return 0
- else
- log_error "❌ [错误] 重新启用接口失败"
- return 1
- fi
- else
- log_error "❌ [错误] ifconfig ether 命令失败"
- log_info "🔄 [恢复] 尝试重新启用接口..."
- sudo ifconfig "$interface_name" up 2>/dev/null || true
- return 1
- fi
-}
-
-# 🌐 增强的networksetup方法(适用于受限环境)
-_try_networksetup_method() {
- local interface_name="$1"
- local random_mac="$2"
-
- log_info "🌐 [networksetup] 尝试使用系统网络偏好设置方法"
-
- # 🔍 获取硬件端口名称
- local hardware_port=$(networksetup -listallhardwareports | grep -A1 "Device: $interface_name" | grep "Hardware Port:" | cut -d: -f2 | xargs)
-
- if [ -z "$hardware_port" ]; then
- log_warn "⚠️ [警告] 无法找到接口 $interface_name 对应的硬件端口"
- log_info "📋 [调试] 可用硬件端口列表:"
- networksetup -listallhardwareports | grep -E "(Hardware Port|Device)" | head -10
- return 1
- fi
-
- log_info "🔍 [发现] 找到硬件端口: '$hardware_port' (设备: $interface_name)"
-
- # 🎯 尝试多种networksetup方法
- local methods_tried=()
-
- # 方法1: 尝试重置网络服务
- log_info "🔧 [方法1] 尝试重置网络服务..."
- methods_tried+=("reset-service")
- if sudo networksetup -setnetworkserviceenabled "$hardware_port" off 2>>"$LOG_FILE"; then
- sleep 2
- if sudo networksetup -setnetworkserviceenabled "$hardware_port" on 2>>"$LOG_FILE"; then
- log_info "✅ [成功] 网络服务重置成功"
- sleep 2
-
- # 检测硬件变化
- sudo networksetup -detectnewhardware 2>>"$LOG_FILE"
- sleep 3
-
- # 验证是否有效果
- local new_mac=$(ifconfig "$interface_name" | awk '/ether/{print $2}')
- if [ "$new_mac" != "$(ifconfig "$interface_name" | awk '/ether/{print $2}')" ]; then
- log_info "✅ [成功] networksetup方法可能有效"
- return 0
- fi
- fi
- fi
-
- # 方法2: 尝试手动配置
- log_info "🔧 [方法2] 尝试手动网络配置..."
- methods_tried+=("manual-config")
-
- # 获取当前配置
- local current_config=$(networksetup -getinfo "$hardware_port" 2>/dev/null)
- if [ -n "$current_config" ]; then
- log_info "📋 [当前配置] $hardware_port 的网络配置:"
- echo "$current_config" | head -5
-
- # 尝试重新应用配置以触发MAC地址更新
- if echo "$current_config" | grep -q "DHCP"; then
- log_info "🔄 [DHCP] 重新应用DHCP配置..."
- if sudo networksetup -setdhcp "$hardware_port" 2>>"$LOG_FILE"; then
- log_info "✅ [成功] DHCP配置重新应用成功"
- sleep 3
- sudo networksetup -detectnewhardware 2>>"$LOG_FILE"
- return 0
- fi
- fi
- fi
-
- # 方法3: 强制硬件重新检测
- log_info "🔧 [方法3] 强制硬件重新检测..."
- methods_tried+=("hardware-detect")
-
- if sudo networksetup -detectnewhardware 2>>"$LOG_FILE"; then
- log_info "✅ [成功] 硬件重新检测完成"
- sleep 3
- return 0
- fi
-
- # 所有方法都失败
- log_error "❌ [失败] networksetup所有方法都失败"
- log_info "📋 [尝试过的方法]: ${methods_tried[*]}"
- log_warn "⚠️ [说明] networksetup方法在当前macOS版本中可能不支持直接MAC地址修改"
-
- return 1
-}
-
-# 📊 增强的故障排除信息显示
-_show_troubleshooting_info() {
- local interface_name="$1"
-
- echo
- echo -e "${YELLOW}╔══════════════════════════════════════════════════════════════╗${NC}"
- echo -e "${YELLOW}║ MAC地址修改故障排除信息 ║${NC}"
- echo -e "${YELLOW}╚══════════════════════════════════════════════════════════════╝${NC}"
- echo
-
- # 🔍 系统信息
- echo -e "${BLUE}🔍 系统环境信息:${NC}"
- echo " 📱 macOS版本: $MACOS_VERSION"
- echo " 💻 硬件类型: $HARDWARE_TYPE"
- echo " 🔒 SIP状态: $SIP_STATUS"
- echo " 🌐 接口名称: $interface_name"
- echo " 📊 兼容性级别: ${MAC_COMPATIBILITY_LEVEL:-未知}"
-
- # 显示接口详细信息
- local interface_info=$(ifconfig "$interface_name" 2>/dev/null | head -3)
- if [ -n "$interface_info" ]; then
- echo " 📡 接口状态:"
- echo "$interface_info" | sed 's/^/ /'
- fi
- echo
-
- # ⚠️ 问题分析
- echo -e "${BLUE}⚠️ 可能的问题原因:${NC}"
- local issues_found=false
-
- if [[ "$HARDWARE_TYPE" == "Apple Silicon" ]] && [[ $MACOS_MAJOR -ge 12 ]]; then
- echo " ❌ Apple Silicon Mac在macOS 12+版本中有硬件级MAC地址修改限制"
- echo " ❌ 网络驱动程序可能完全禁止MAC地址修改"
- issues_found=true
- fi
-
- if [[ $MACOS_MAJOR -ge 14 ]]; then
- echo " ❌ macOS Sonoma (14+) 对MAC地址修改有严格的系统级限制"
- issues_found=true
- elif [[ $MACOS_MAJOR -ge 12 ]]; then
- echo " ⚠️ macOS Monterey+ 对MAC地址修改有部分限制"
- issues_found=true
- fi
-
- if [[ "$SIP_STATUS" == "enabled" ]]; then
- echo " ⚠️ 系统完整性保护(SIP)可能阻止某些MAC地址修改方法"
- issues_found=true
- fi
-
- if ! $issues_found; then
- echo " ❓ 网络接口可能不支持MAC地址修改"
- echo " ❓ 权限不足或其他系统安全策略限制"
- fi
- echo
-
- # 💡 解决方案
- echo -e "${BLUE}💡 建议的解决方案:${NC}"
- echo
- echo -e "${GREEN} 🛠️ 方案1: 安装第三方工具${NC}"
- echo " brew install spoof-mac"
- echo " brew install macchanger"
- echo " # 这些工具可能使用不同的底层方法"
- echo
-
- if [[ "$HARDWARE_TYPE" == "Apple Silicon" ]] || [[ $MACOS_MAJOR -ge 14 ]]; then
- echo -e "${GREEN} 🔧 方案2: 使用Cursor JS内核修改 (推荐)${NC}"
- echo " # 本脚本会自动尝试JS内核修改方案"
- echo " # 直接修改Cursor内核文件绕过系统MAC检测"
- echo
- fi
-
- echo -e "${GREEN} 🌐 方案3: 网络层解决方案${NC}"
- echo " • 使用虚拟机运行需要MAC地址修改的应用"
- echo " • 配置路由器级别的MAC地址过滤绕过"
- echo " • 使用VPN或代理服务"
- echo
-
- if [[ "$SIP_STATUS" == "enabled" ]]; then
- echo -e "${YELLOW} ⚠️ 方案4: 临时禁用SIP (高风险,不推荐)${NC}"
- echo " 1. 重启进入恢复模式 (Command+R)"
- echo " 2. 打开终端运行: csrutil disable"
- echo " 3. 重启后尝试修改MAC地址"
- echo " 4. 完成后重新启用: csrutil enable"
- echo " ⚠️ 警告: 禁用SIP会降低系统安全性"
- echo
- fi
-
- # 🔧 技术细节
- echo -e "${BLUE}🔧 技术细节和错误分析:${NC}"
- echo " 📋 常见错误信息:"
- echo " • ifconfig: ioctl (SIOCAIFADDR): Can't assign requested address"
- echo " • Operation not permitted"
- echo " • Device or resource busy"
- echo
- echo " 🔍 错误含义:"
- echo " • 系统内核拒绝了MAC地址修改请求"
- echo " • 硬件驱动程序不允许MAC地址更改"
- echo " • 安全策略阻止了网络接口修改"
- echo
-
- if [[ "$HARDWARE_TYPE" == "Apple Silicon" ]]; then
- echo " 🍎 Apple Silicon特殊说明:"
- echo " • 硬件级别的安全限制,无法通过软件绕过"
- echo " • 网络芯片固件可能锁定了MAC地址"
- echo " • 建议使用应用层解决方案(如JS内核修改)"
- echo
- fi
-
- echo -e "${BLUE}📞 获取更多帮助:${NC}"
- echo " • 查看系统日志: sudo dmesg | grep -i network"
- echo " • 检查网络接口: networksetup -listallhardwareports"
- echo " • 测试权限: sudo ifconfig $interface_name"
- echo
-}
-
-# 检查权限
-check_permissions() {
- if [ "$EUID" -ne 0 ]; then
- log_error "请使用 sudo 运行此脚本"
- echo "示例: sudo $0"
- exit 1
- fi
-}
-
-# 检查并关闭 Cursor 进程(保存进程信息)
-check_and_kill_cursor() {
- log_info "🔍 [检查] 检查 Cursor 进程..."
-
- local attempt=1
- local max_attempts=5
-
- # 💾 保存Cursor进程路径
- CURSOR_PROCESS_PATH="/Applications/Cursor.app/Contents/MacOS/Cursor"
-
- # 函数:获取进程详细信息
- get_process_details() {
- local process_name="$1"
- log_debug "正在获取 $process_name 进程详细信息:"
- ps aux | grep -i "/Applications/Cursor.app" | grep -v grep
- }
-
- while [ $attempt -le $max_attempts ]; do
- # 使用更精确的匹配来获取 Cursor 进程
- CURSOR_PIDS=$(ps aux | grep -i "/Applications/Cursor.app" | grep -v grep | awk '{print $2}')
-
- if [ -z "$CURSOR_PIDS" ]; then
- log_info "💡 [提示] 未发现运行中的 Cursor 进程"
- # 确认Cursor应用路径存在
- if [ -f "$CURSOR_PROCESS_PATH" ]; then
- log_info "💾 [保存] 已保存Cursor路径: $CURSOR_PROCESS_PATH"
- else
- log_warn "⚠️ [警告] 未找到Cursor应用,请确认已安装"
- fi
- return 0
- fi
-
- log_warn "⚠️ [警告] 发现 Cursor 进程正在运行"
- # 💾 保存进程信息
- log_info "💾 [保存] 已保存Cursor路径: $CURSOR_PROCESS_PATH"
- get_process_details "cursor"
-
- 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 3
-
- # 同样使用更精确的匹配来检查进程是否还在运行
- if ! ps aux | grep -i "/Applications/Cursor.app" | grep -v grep > /dev/null; then
- log_info "✅ [成功] Cursor 进程已成功关闭"
- return 0
- fi
-
- log_warn "⏳ [等待] 等待进程关闭,尝试 $attempt/$max_attempts..."
- ((attempt++))
- done
-
- log_error "❌ [错误] 在 $max_attempts 次尝试后仍无法关闭 Cursor 进程"
- get_process_details "cursor"
- log_error "💥 [错误] 请手动关闭进程后重试"
- exit 1
-}
-
-# 备份配置文件
-backup_config() {
- if [ ! -f "$STORAGE_FILE" ]; then
- log_warn "配置文件不存在,跳过备份"
- 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" "$backup_file"
- log_info "配置已备份到: $backup_file"
- else
- log_error "备份失败"
- exit 1
- fi
-}
-
-# 🔧 修改Cursor内核JS文件实现设备识别绕过(新增核心功能)
-modify_cursor_js_files() {
- log_info "🔧 [内核修改] 开始修改Cursor内核JS文件实现设备识别绕过..."
- echo
-
- # 检查Cursor应用是否存在
- if [ ! -d "$CURSOR_APP_PATH" ]; then
- log_error "❌ [错误] 未找到Cursor应用: $CURSOR_APP_PATH"
- return 1
- fi
-
- # 生成新的设备标识符
- local new_uuid=$(uuidgen | tr '[:upper:]' '[:lower:]')
- local machine_id="auth0|user_$(openssl rand -hex 16)"
- local device_id=$(uuidgen | tr '[:upper:]' '[:lower:]')
- local mac_machine_id=$(openssl rand -hex 32)
-
- log_info "🔑 [生成] 已生成新的设备标识符"
-
- # 目标JS文件列表
- local js_files=(
- "$CURSOR_APP_PATH/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js"
- "$CURSOR_APP_PATH/Contents/Resources/app/out/main.js"
- "$CURSOR_APP_PATH/Contents/Resources/app/out/vs/code/node/cliProcessMain.js"
- )
-
- local modified_count=0
- local need_modification=false
-
- # 检查是否需要修改
- log_info "🔍 [检查] 检查JS文件修改状态..."
- for file in "${js_files[@]}"; do
- if [ ! -f "$file" ]; then
- log_warn "⚠️ [警告] 文件不存在: ${file/$CURSOR_APP_PATH\//}"
- continue
- fi
-
- if ! grep -q "return crypto.randomUUID()" "$file" 2>/dev/null; then
- log_info "📝 [需要] 文件需要修改: ${file/$CURSOR_APP_PATH\//}"
- need_modification=true
- break
- else
- log_info "✅ [已修改] 文件已修改: ${file/$CURSOR_APP_PATH\//}"
- fi
- done
-
- if [ "$need_modification" = false ]; then
- log_info "✅ [跳过] 所有JS文件已经被修改过,无需重复操作"
- return 0
- fi
-
- # 关闭Cursor进程
- log_info "🔄 [关闭] 关闭Cursor进程以进行文件修改..."
- check_and_kill_cursor
-
- # 创建备份
- local timestamp=$(date +%Y%m%d_%H%M%S)
- local backup_app="/tmp/Cursor.app.backup_js_${timestamp}"
-
- log_info "💾 [备份] 创建Cursor应用备份..."
- if ! cp -R "$CURSOR_APP_PATH" "$backup_app"; then
- log_error "❌ [错误] 创建备份失败"
- return 1
- fi
-
- log_info "✅ [备份] 备份创建成功: $backup_app"
-
- # 修改JS文件
- log_info "🔧 [修改] 开始修改JS文件..."
-
- for file in "${js_files[@]}"; do
- if [ ! -f "$file" ]; then
- log_warn "⚠️ [跳过] 文件不存在: ${file/$CURSOR_APP_PATH\//}"
- continue
- fi
-
- log_info "📝 [处理] 正在处理: ${file/$CURSOR_APP_PATH\//}"
-
- # 检查是否已经修改过
- if grep -q "return crypto.randomUUID()" "$file" || grep -q "// Cursor ID 修改工具注入" "$file"; then
- log_info "✅ [跳过] 文件已经被修改过"
- ((modified_count++))
- continue
- fi
-
- # 方法1: 查找IOPlatformUUID相关函数
- if grep -q "IOPlatformUUID" "$file"; then
- log_info "🔍 [发现] 找到IOPlatformUUID关键字"
-
- # 针对不同的函数模式进行修改
- if grep -q "function a\$" "$file"; then
- if sed -i.tmp 's/function a\$(t){switch/function a\$(t){return crypto.randomUUID(); switch/' "$file"; then
- log_info "✅ [成功] 修改a$函数成功"
- ((modified_count++))
- continue
- fi
- fi
-
- # 通用注入方法 - ES模块兼容版本
- local inject_code="
-// Cursor ID 修改工具注入 - $(date) - ES模块兼容版本
-import crypto from 'crypto';
-
-// 保存原始函数引用
-const originalRandomUUID_$(date +%s) = crypto.randomUUID;
-
-// 重写crypto.randomUUID方法
-crypto.randomUUID = function() {
- return '${new_uuid}';
-};
-
-// 覆盖所有可能的系统ID获取函数 - ES模块兼容版本
-globalThis.getMachineId = function() { return '${machine_id}'; };
-globalThis.getDeviceId = function() { return '${device_id}'; };
-globalThis.macMachineId = '${mac_machine_id}';
-
-// 确保在不同环境下都能访问
-if (typeof window !== 'undefined') {
- window.getMachineId = globalThis.getMachineId;
- window.getDeviceId = globalThis.getDeviceId;
- window.macMachineId = globalThis.macMachineId;
-}
-
-// 确保模块顶层执行
-console.log('Cursor设备标识符已成功劫持 - ES模块版本 煎饼果子(86) 关注公众号【煎饼果子卷AI】一起交流更多Cursor技巧和AI知识(脚本免费、关注公众号加群有更多技巧和大佬)');
-"
-
- # 替换变量
- inject_code=${inject_code//\$\{new_uuid\}/$new_uuid}
- inject_code=${inject_code//\$\{machine_id\}/$machine_id}
- inject_code=${inject_code//\$\{device_id\}/$device_id}
- inject_code=${inject_code//\$\{mac_machine_id\}/$mac_machine_id}
-
- # 注入代码到文件开头
- echo "$inject_code" > "${file}.new"
- cat "$file" >> "${file}.new"
- mv "${file}.new" "$file"
-
- log_info "✅ [成功] 通用注入方法修改成功"
- ((modified_count++))
-
- # 方法2: 查找其他设备ID相关函数
- elif grep -q "function t\$()" "$file" || grep -q "async function y5" "$file"; then
- log_info "🔍 [发现] 找到设备ID相关函数"
-
- # 修改MAC地址获取函数
- if grep -q "function t\$()" "$file"; then
- sed -i.tmp 's/function t\$(){/function t\$(){return "00:00:00:00:00:00";/' "$file"
- log_info "✅ [成功] 修改MAC地址获取函数"
- fi
-
- # 修改设备ID获取函数
- if grep -q "async function y5" "$file"; then
- sed -i.tmp 's/async function y5(t){/async function y5(t){return crypto.randomUUID();/' "$file"
- log_info "✅ [成功] 修改设备ID获取函数"
- fi
-
- ((modified_count++))
- else
- log_warn "⚠️ [警告] 未找到已知的设备ID函数模式,跳过此文件"
- fi
- done
-
- if [ $modified_count -gt 0 ]; then
- log_info "🎉 [完成] 成功修改 $modified_count 个JS文件"
- log_info "💾 [备份] 原始文件备份位置: $backup_app"
- return 0
- else
- log_error "❌ [失败] 没有成功修改任何文件"
- return 1
- fi
-}
-
-# 增强的系统MAC地址修改函数,支持多种兼容性检测和修改方法
-change_system_mac_address() {
- log_info "开始尝试修改所有活动的 Wi-Fi/Ethernet 接口的系统 MAC 地址..."
- echo
-
- # 环境兼容性预检查
- detect_macos_environment
- local env_compatible=$?
-
- if [[ $env_compatible -ne 0 ]]; then
- echo -e "${YELLOW}⚠️ [兼容性警告]${NC} 检测到可能存在MAC地址修改限制的环境:"
- echo -e "${YELLOW} • macOS版本: $MACOS_VERSION${NC}"
- echo -e "${YELLOW} • 硬件类型: $HARDWARE_TYPE${NC}"
- echo -e "${YELLOW} • SIP状态: $SIP_STATUS${NC}"
- echo
- echo -e "${BLUE}💡 [建议]${NC} 在此环境中,传统的ifconfig方法可能失败。"
- echo -e "${BLUE} 脚本将自动尝试多种兼容性方法,包括第三方工具。${NC}"
- echo
-
- # 检查第三方工具可用性
- local tools_available=false
- if command -v spoof-mac >/dev/null 2>&1; then
- echo -e "${GREEN}✅ 检测到 spoof-mac 工具${NC}"
- tools_available=true
- fi
- if command -v macchanger >/dev/null 2>&1; then
- echo -e "${GREEN}✅ 检测到 macchanger 工具${NC}"
- tools_available=true
- fi
-
- if [[ $tools_available == false ]]; then
- echo -e "${YELLOW}⚠️ 未检测到第三方MAC修改工具${NC}"
- echo -e "${BLUE}💡 建议安装: brew install spoof-mac 或 brew install macchanger${NC}"
- echo
-
- # 🔧 Apple Silicon智能替代方案
- if [[ "$HARDWARE_TYPE" == "Apple Silicon" ]]; then
- echo -e "${BLUE}🔧 [智能方案]${NC} 检测到Apple Silicon环境,MAC地址修改受硬件限制"
- echo -e "${BLUE}💡 [自动切换]${NC} 将自动使用JS内核修改实现更直接的设备识别绕过"
- echo
-
- log_info "🔄 [智能切换] 自动切换到JS内核修改方案..."
- if modify_cursor_js_files; then
- log_info "✅ [成功] JS内核修改完成,已实现设备识别绕过"
- log_info "💡 [说明] 此方案比MAC地址修改更直接有效,完美适配Apple Silicon"
- return 0
- else
- log_warn "⚠️ [警告] JS内核修改失败,将继续尝试MAC地址修改"
- fi
- fi
-
- # 非Apple Silicon环境或JS修改失败时,询问是否继续MAC地址修改
- read -p "是否继续尝试MAC地址修改?(y/n): " continue_choice
- if [[ ! "$continue_choice" =~ ^(y|yes)$ ]]; then
- log_info "用户选择跳过MAC地址修改"
- return 1
- fi
- fi
- fi
-
- echo -e "${YELLOW}[警告]${NC} 即将尝试修改您所有活动的 Wi-Fi 或以太网接口的 MAC 地址。"
- echo -e "${YELLOW}[警告]${NC} 此更改是 ${RED}临时${NC} 的,将在您重启 Mac 后恢复为原始地址。"
- echo -e "${YELLOW}[警告]${NC} 修改 MAC 地址可能会导致临时的网络中断或连接问题。"
- echo -e "${YELLOW}[警告]${NC} 请确保您了解相关风险。此操作主要影响本地网络识别,而非互联网身份。"
- echo
-
- local active_interfaces=()
- local potential_interfaces=()
- local default_route_interface=""
-
- # 0. 尝试获取默认路由接口,作为后备
- log_info "尝试通过路由表获取默认网络接口 (用于后备)..."
- default_route_interface=$(route get default | grep 'interface:' | awk '{print $2}')
- if [ -n "$default_route_interface" ]; then
- log_info "检测到默认路由接口 (后备): $default_route_interface"
- else
- log_warn "未能通过路由表获取默认接口 (后备)。"
- fi
-
- # 1. 获取所有 Wi-Fi 和 Ethernet 接口名称
- log_info "正在检测 Wi-Fi 和 Ethernet 接口..."
- while IFS= read -r line; do
- if [[ $line == "Hardware Port: Wi-Fi" || $line == "Hardware Port: Ethernet" ]]; then
- read -r dev_line # 读取下一行 Device: enX
- device=$(echo "$dev_line" | awk '{print $2}')
- if [ -n "$device" ]; then
- log_debug "检测到潜在接口: $device ($line)"
- potential_interfaces+=("$device")
- fi
- fi
- done < <(networksetup -listallhardwareports)
-
- if [ ${#potential_interfaces[@]} -eq 0 ]; then
- log_warn "未能通过 networksetup 检测到任何 Wi-Fi 或 Ethernet 接口。"
- # 检查是否有路由表接口作为后备
- if [ -n "$default_route_interface" ]; then
- log_warn "将使用路由表检测到的接口 '$default_route_interface' 作为后备。"
- potential_interfaces+=("$default_route_interface")
- else
- log_warn "路由表也未能提供后备接口。"
- # 在此情况下,potential_interfaces 仍为空,后续逻辑会处理
- fi
- fi
-
- # 2. 检查哪些接口是活动的
- log_info "正在检查接口活动状态..."
- for interface_name in "${potential_interfaces[@]}"; do
- log_debug "检查接口 '$interface_name' 状态..."
- if ifconfig "$interface_name" 2>/dev/null | grep -q "status: active"; then
- log_info "发现活动接口: $interface_name"
- active_interfaces+=("$interface_name")
- else
- log_debug "接口 '$interface_name' 非活动或不存在。"
- fi
- done
-
- # 3. 检查是否找到活动接口
- if [ ${#active_interfaces[@]} -eq 0 ]; then
- log_warn "未找到任何活动的 Wi-Fi 或 Ethernet 接口可供修改 MAC 地址。"
- echo -e "${YELLOW}未找到活动的 Wi-Fi 或 Ethernet 接口。跳过 MAC 地址修改。${NC}"
- return 1 # 返回错误码,表示没有接口被修改
- fi
-
- log_info "将尝试为以下活动接口修改 MAC 地址: ${active_interfaces[*]}"
- echo
-
- # 4. 🚀 循环处理找到的活动接口(增强版)
- local overall_success=true
- local successful_interfaces=()
- local failed_interfaces=()
-
- echo -e "${BLUE}🚀 [开始] 开始处理 ${#active_interfaces[@]} 个活动接口...${NC}"
- echo
-
- # 处理每个接口
- for i in "${!active_interfaces[@]}"; do
- local interface_name="${active_interfaces[$i]}"
- local interface_num=$((i + 1))
-
- echo -e "${YELLOW}╔══════════════════════════════════════════════════════════════╗${NC}"
- echo -e "${YELLOW}║ 处理接口 $interface_num/${#active_interfaces[@]}: $interface_name ║${NC}"
- echo -e "${YELLOW}╚══════════════════════════════════════════════════════════════╝${NC}"
- echo
-
- if _change_mac_for_one_interface "$interface_name"; then
- log_info "✅ [成功] 接口 '$interface_name' MAC地址修改成功"
- successful_interfaces+=("$interface_name")
- else
- log_warn "⚠️ [失败] 接口 '$interface_name' MAC地址修改失败"
- failed_interfaces+=("$interface_name")
- overall_success=false
- fi
-
- echo
- echo -e "${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
- echo
- done
-
- # 📊 显示处理结果统计
- echo -e "${BLUE}📊 [统计] MAC地址修改结果统计:${NC}"
- echo " ✅ 成功: ${#successful_interfaces[@]} 个接口"
- if [ ${#successful_interfaces[@]} -gt 0 ]; then
- for interface in "${successful_interfaces[@]}"; do
- echo " • $interface"
- done
- fi
- echo " ❌ 失败: ${#failed_interfaces[@]} 个接口"
- if [ ${#failed_interfaces[@]} -gt 0 ]; then
- for interface in "${failed_interfaces[@]}"; do
- echo " • $interface"
- done
- fi
- echo
-
- log_info "📋 [完成] 所有活动接口的MAC地址修改尝试完成"
-
- if $overall_success; then
- return 0 # 所有尝试都成功
- else
- # 🔧 MAC地址修改失败时自动切换到JS内核修改
- echo
- log_warn "⚠️ [警告] MAC地址修改失败或部分失败"
- log_info "🔧 [智能切换] 自动切换到JS内核修改方案..."
- log_info "💡 [说明] JS内核修改直接修改Cursor设备检测逻辑,绕过效果更好"
-
- if modify_cursor_js_files; then
- log_info "✅ [成功] JS内核修改完成,已实现设备识别绕过"
- log_info "💡 [结果] 虽然MAC地址修改失败,但JS内核修改提供了更直接的解决方案"
- return 0
- else
- log_error "❌ [失败] JS内核修改也失败了"
- log_error "💥 [严重] 所有设备识别绕过方案都失败了"
- return 1
- fi
- fi
-}
-
-
-
-
-# 修改现有文件
-modify_or_add_config() {
- local key="$1"
- local value="$2"
- local file="$3"
-
- if [ ! -f "$file" ]; then
- log_error "文件不存在: $file"
- return 1
- fi
-
- # 确保文件可写
- chmod 644 "$file" || {
- log_error "无法修改文件权限: $file"
- return 1
- }
-
- # 创建临时文件
- local temp_file=$(mktemp)
-
- # 检查key是否存在
- if grep -q "\"$key\":" "$file"; then
- # key存在,执行替换
- sed "s/\"$key\":[[:space:]]*\"[^\"]*\"/\"$key\": \"$value\"/" "$file" > "$temp_file" || {
- log_error "修改配置失败: $key"
- rm -f "$temp_file"
- return 1
- }
- else
- # key不存在,添加新的key-value对
- sed "s/}$/,\n \"$key\": \"$value\"\n}/" "$file" > "$temp_file" || {
- log_error "添加配置失败: $key"
- rm -f "$temp_file"
- return 1
- }
- fi
-
- # 检查临时文件是否为空
- if [ ! -s "$temp_file" ]; then
- log_error "生成的临时文件为空"
- rm -f "$temp_file"
- return 1
- fi
-
- # 使用 cat 替换原文件内容
- cat "$temp_file" > "$file" || {
- log_error "无法写入文件: $file"
- rm -f "$temp_file"
- return 1
- }
-
- rm -f "$temp_file"
-
- # 恢复文件权限
- chmod 444 "$file"
-
- return 0
-}
-
-# 清理 Cursor 之前的修改
-clean_cursor_app() {
- log_info "尝试清理 Cursor 之前的修改..."
-
- # 如果存在备份,直接恢复备份
- local latest_backup=""
-
- # 查找最新的备份
- latest_backup=$(find /tmp -name "Cursor.app.backup_*" -type d -print 2>/dev/null | sort -r | head -1)
-
- if [ -n "$latest_backup" ] && [ -d "$latest_backup" ]; then
- log_info "找到现有备份: $latest_backup"
- log_info "正在恢复原始版本..."
-
- # 停止 Cursor 进程
- check_and_kill_cursor
-
- # 恢复备份
- sudo rm -rf "$CURSOR_APP_PATH"
- sudo cp -R "$latest_backup" "$CURSOR_APP_PATH"
- sudo chown -R "$CURRENT_USER:staff" "$CURSOR_APP_PATH"
- sudo chmod -R 755 "$CURSOR_APP_PATH"
-
- log_info "已恢复原始版本"
- return 0
- else
- log_warn "未找到现有备份,尝试重新安装 Cursor..."
- echo "您可以从 https://cursor.sh 下载并重新安装 Cursor"
- echo "或者继续执行此脚本,将尝试修复现有安装"
-
- # 可以在这里添加重新下载和安装的逻辑
- return 1
- fi
-}
-
-# 修改 Cursor 主程序文件(安全模式)
-modify_cursor_app_files() {
- log_info "正在安全修改 Cursor 主程序文件..."
- log_info "详细日志将记录到: $LOG_FILE"
-
- # 先清理之前的修改
- clean_cursor_app
-
- # 验证应用是否存在
- if [ ! -d "$CURSOR_APP_PATH" ]; then
- log_error "未找到 Cursor.app,请确认安装路径: $CURSOR_APP_PATH"
- return 1
- fi
-
- # 定义目标文件 - 将extensionHostProcess.js放在最前面优先处理
- local target_files=(
- "${CURSOR_APP_PATH}/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js"
- "${CURSOR_APP_PATH}/Contents/Resources/app/out/main.js"
- "${CURSOR_APP_PATH}/Contents/Resources/app/out/vs/code/node/cliProcessMain.js"
- )
-
- # 检查文件是否存在并且是否已修改
- local need_modification=false
- local missing_files=false
-
- log_debug "检查目标文件..."
- for file in "${target_files[@]}"; do
- if [ ! -f "$file" ]; then
- log_warn "文件不存在: ${file/$CURSOR_APP_PATH\//}"
- echo "[FILE_CHECK] 文件不存在: $file" >> "$LOG_FILE"
- missing_files=true
- continue
- fi
-
- echo "[FILE_CHECK] 文件存在: $file ($(wc -c < "$file") 字节)" >> "$LOG_FILE"
-
- if ! grep -q "return crypto.randomUUID()" "$file" 2>/dev/null; then
- log_info "文件需要修改: ${file/$CURSOR_APP_PATH\//}"
- grep -n "IOPlatformUUID" "$file" | head -3 >> "$LOG_FILE" || echo "[FILE_CHECK] 未找到 IOPlatformUUID" >> "$LOG_FILE"
- need_modification=true
- break
- else
- log_info "文件已修改: ${file/$CURSOR_APP_PATH\//}"
- fi
- done
-
- # 如果所有文件都已修改或不存在,则退出
- if [ "$missing_files" = true ]; then
- log_error "部分目标文件不存在,请确认 Cursor 安装是否完整"
- return 1
- fi
-
- if [ "$need_modification" = false ]; then
- log_info "所有目标文件已经被修改过,无需重复操作"
- return 0
- fi
-
- # 创建临时工作目录
- local timestamp=$(date +%Y%m%d_%H%M%S)
- local temp_dir="/tmp/cursor_reset_${timestamp}"
- local temp_app="${temp_dir}/Cursor.app"
- local backup_app="/tmp/Cursor.app.backup_${timestamp}"
-
- log_debug "创建临时目录: $temp_dir"
- echo "[TEMP_DIR] 创建临时目录: $temp_dir" >> "$LOG_FILE"
-
- # 清理可能存在的旧临时目录
- if [ -d "$temp_dir" ]; then
- log_info "清理已存在的临时目录..."
- rm -rf "$temp_dir"
- fi
-
- # 创建新的临时目录
- mkdir -p "$temp_dir" || {
- log_error "无法创建临时目录: $temp_dir"
- echo "[ERROR] 无法创建临时目录: $temp_dir" >> "$LOG_FILE"
- return 1
- }
-
- # 备份原应用
- log_info "备份原应用..."
- echo "[BACKUP] 开始备份: $CURSOR_APP_PATH -> $backup_app" >> "$LOG_FILE"
-
- cp -R "$CURSOR_APP_PATH" "$backup_app" || {
- log_error "无法创建应用备份"
- echo "[ERROR] 备份失败: $CURSOR_APP_PATH -> $backup_app" >> "$LOG_FILE"
- rm -rf "$temp_dir"
- return 1
- }
-
- echo "[BACKUP] 备份完成" >> "$LOG_FILE"
-
- # 复制应用到临时目录
- log_info "创建临时工作副本..."
- echo "[COPY] 开始复制: $CURSOR_APP_PATH -> $temp_dir" >> "$LOG_FILE"
-
- cp -R "$CURSOR_APP_PATH" "$temp_dir" || {
- log_error "无法复制应用到临时目录"
- echo "[ERROR] 复制失败: $CURSOR_APP_PATH -> $temp_dir" >> "$LOG_FILE"
- rm -rf "$temp_dir" "$backup_app"
- return 1
- }
-
- echo "[COPY] 复制完成" >> "$LOG_FILE"
-
- # 确保临时目录的权限正确
- chown -R "$CURRENT_USER:staff" "$temp_dir"
- chmod -R 755 "$temp_dir"
-
- # 移除签名(增强兼容性)
- log_info "移除应用签名..."
- echo "[CODESIGN] 移除签名: $temp_app" >> "$LOG_FILE"
-
- codesign --remove-signature "$temp_app" 2>> "$LOG_FILE" || {
- log_warn "移除应用签名失败"
- echo "[WARN] 移除签名失败: $temp_app" >> "$LOG_FILE"
- }
-
- # 移除所有相关组件的签名
- local components=(
- "$temp_app/Contents/Frameworks/Cursor Helper.app"
- "$temp_app/Contents/Frameworks/Cursor Helper (GPU).app"
- "$temp_app/Contents/Frameworks/Cursor Helper (Plugin).app"
- "$temp_app/Contents/Frameworks/Cursor Helper (Renderer).app"
- )
-
- for component in "${components[@]}"; do
- if [ -e "$component" ]; then
- log_info "正在移除签名: $component"
- codesign --remove-signature "$component" || {
- log_warn "移除组件签名失败: $component"
- }
- fi
- done
-
- # 修改目标文件 - 优先处理js文件
- local modified_count=0
- local files=(
- "${temp_app}/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js"
- "${temp_app}/Contents/Resources/app/out/main.js"
- "${temp_app}/Contents/Resources/app/out/vs/code/node/cliProcessMain.js"
- )
-
- for file in "${files[@]}"; do
- if [ ! -f "$file" ]; then
- log_warn "文件不存在: ${file/$temp_dir\//}"
- continue
- fi
-
- log_debug "处理文件: ${file/$temp_dir\//}"
- echo "[PROCESS] 开始处理文件: $file" >> "$LOG_FILE"
- echo "[PROCESS] 文件大小: $(wc -c < "$file") 字节" >> "$LOG_FILE"
-
- # 输出文件部分内容到日志
- echo "[FILE_CONTENT] 文件头部 100 行:" >> "$LOG_FILE"
- head -100 "$file" 2>/dev/null | grep -v "^$" | head -50 >> "$LOG_FILE"
- echo "[FILE_CONTENT] ..." >> "$LOG_FILE"
-
- # 创建文件备份
- cp "$file" "${file}.bak" || {
- log_error "无法创建文件备份: ${file/$temp_dir\//}"
- echo "[ERROR] 无法创建文件备份: $file" >> "$LOG_FILE"
- continue
- }
-
- # 使用 sed 替换而不是字符串操作
- if [[ "$file" == *"extensionHostProcess.js"* ]]; then
- log_debug "处理 extensionHostProcess.js 文件..."
- echo "[PROCESS_DETAIL] 开始处理 extensionHostProcess.js 文件" >> "$LOG_FILE"
-
- # 检查是否包含目标代码
- if grep -q 'i.header.set("x-cursor-checksum' "$file"; then
- log_debug "找到 x-cursor-checksum 设置代码"
- echo "[FOUND] 找到 x-cursor-checksum 设置代码" >> "$LOG_FILE"
-
- # 记录匹配的行到日志
- grep -n 'i.header.set("x-cursor-checksum' "$file" >> "$LOG_FILE"
-
- # 执行特定的替换
- if sed -i.tmp 's/i\.header\.set("x-cursor-checksum",e===void 0?`${p}${t}`:`${p}${t}\/${e}`)/i.header.set("x-cursor-checksum",e===void 0?`${p}${t}`:`${p}${t}\/${p}`)/' "$file"; then
- log_info "成功修改 x-cursor-checksum 设置代码"
- echo "[SUCCESS] 成功完成 x-cursor-checksum 设置代码替换" >> "$LOG_FILE"
- # 记录修改后的行
- grep -n 'i.header.set("x-cursor-checksum' "$file" >> "$LOG_FILE"
- ((modified_count++))
- log_info "成功修改文件: ${file/$temp_dir\//}"
- else
- log_error "修改 x-cursor-checksum 设置代码失败"
- cp "${file}.bak" "$file"
- fi
- else
- log_warn "未找到 x-cursor-checksum 设置代码"
- echo "[FILE_CHECK] 未找到 x-cursor-checksum 设置代码" >> "$LOG_FILE"
-
- # 记录文件部分内容到日志以便排查
- echo "[FILE_CONTENT] 文件中包含 'header.set' 的行:" >> "$LOG_FILE"
- grep -n "header.set" "$file" | head -20 >> "$LOG_FILE"
-
- echo "[FILE_CONTENT] 文件中包含 'checksum' 的行:" >> "$LOG_FILE"
- grep -n "checksum" "$file" | head -20 >> "$LOG_FILE"
- fi
-
- echo "[PROCESS_DETAIL] 完成处理 extensionHostProcess.js 文件" >> "$LOG_FILE"
- elif grep -q "IOPlatformUUID" "$file"; then
- log_debug "找到 IOPlatformUUID 关键字"
- echo "[FOUND] 找到 IOPlatformUUID 关键字" >> "$LOG_FILE"
- grep -n "IOPlatformUUID" "$file" | head -5 >> "$LOG_FILE"
-
- # 定位 IOPlatformUUID 相关函数
- if grep -q "function a\$" "$file"; then
- # 检查是否已经修改过
- if grep -q "return crypto.randomUUID()" "$file"; then
- log_info "文件已经包含 randomUUID 调用,跳过修改"
- ((modified_count++))
- continue
- fi
-
- # 针对 main.js 中发现的代码结构进行修改
- if sed -i.tmp 's/function a\$(t){switch/function a\$(t){return crypto.randomUUID(); switch/' "$file"; then
- log_debug "成功注入 randomUUID 调用到 a\$ 函数"
- ((modified_count++))
- log_info "成功修改文件: ${file/$temp_dir\//}"
- else
- log_error "修改 a\$ 函数失败"
- cp "${file}.bak" "$file"
- fi
- elif grep -q "async function v5" "$file"; then
- # 检查是否已经修改过
- if grep -q "return crypto.randomUUID()" "$file"; then
- log_info "文件已经包含 randomUUID 调用,跳过修改"
- ((modified_count++))
- continue
- fi
-
- # 替代方法 - 修改 v5 函数
- if sed -i.tmp 's/async function v5(t){let e=/async function v5(t){return crypto.randomUUID(); let e=/' "$file"; then
- log_debug "成功注入 randomUUID 调用到 v5 函数"
- ((modified_count++))
- log_info "成功修改文件: ${file/$temp_dir\//}"
- else
- log_error "修改 v5 函数失败"
- cp "${file}.bak" "$file"
- fi
- else
- # 检查是否已经注入了自定义代码
- if grep -q "// Cursor ID 修改工具注入" "$file"; then
- log_info "文件已经包含自定义注入代码,跳过修改"
- ((modified_count++))
- continue
- fi
-
- # 新增检查:检查是否已存在 randomDeviceId_ 时间戳模式
- if grep -q "const randomDeviceId_[0-9]\\{10,\\}" "$file"; then
- log_info "文件已经包含 randomDeviceId_ 模式,跳过通用注入"
- echo "[FOUND] 文件已包含 randomDeviceId_ 模式,跳过通用注入: $file" >> "$LOG_FILE"
- ((modified_count++)) # 计为已修改,防止后续尝试其他方法
- continue
- fi
-
- # 使用更通用的注入方法
- log_warn "未找到具体函数,尝试使用通用修改方法"
- inject_code="
-// Cursor ID 修改工具注入 - $(date +%Y%m%d%H%M%S) - ES模块兼容版本
-// 随机设备ID生成器注入 - $(date +%s)
-import crypto from 'crypto';
-
-const randomDeviceId_$(date +%s) = () => {
- try {
- return crypto.randomUUID();
- } catch (e) {
- return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => {
- const r = Math.random() * 16 | 0;
- return (c === 'x' ? r : (r & 0x3 | 0x8)).toString(16);
- });
- }
-};
-"
- # 将代码注入到文件开头
- echo "$inject_code" > "${file}.new"
- cat "$file" >> "${file}.new"
- mv "${file}.new" "$file"
-
- # 替换调用点
- sed -i.tmp 's/await v5(!1)/randomDeviceId_'"$(date +%s)"'()/g' "$file"
- sed -i.tmp 's/a\$(t)/randomDeviceId_'"$(date +%s)"'()/g' "$file"
-
- log_debug "完成通用修改"
- ((modified_count++))
- log_info "使用通用方法成功修改文件: ${file/$temp_dir\//}"
- fi
- else
- # 未找到 IOPlatformUUID,可能是文件结构变化
- log_warn "未找到 IOPlatformUUID,尝试替代方法"
-
- # 检查是否已经注入或修改过
- if grep -q "return crypto.randomUUID()" "$file" || grep -q "// Cursor ID 修改工具注入" "$file"; then
- log_info "文件已经被修改过,跳过修改"
- ((modified_count++))
- continue
- fi
-
- # 尝试找其他关键函数如 getMachineId 或 getDeviceId
- if grep -q "function t\$()" "$file" || grep -q "async function y5" "$file"; then
- log_debug "找到设备ID相关函数"
-
- # 修改 MAC 地址获取函数
- if grep -q "function t\$()" "$file"; then
- sed -i.tmp 's/function t\$(){/function t\$(){return "00:00:00:00:00:00";/' "$file"
- log_debug "修改 MAC 地址获取函数成功"
- fi
-
- # 修改设备ID获取函数
- if grep -q "async function y5" "$file"; then
- sed -i.tmp 's/async function y5(t){/async function y5(t){return crypto.randomUUID();/' "$file"
- log_debug "修改设备ID获取函数成功"
- fi
-
- ((modified_count++))
- log_info "使用替代方法成功修改文件: ${file/$temp_dir\//}"
- else
- # 最后尝试的通用方法 - 在文件顶部插入重写函数定义
- log_warn "未找到任何已知函数,使用最通用的方法"
-
- inject_universal_code="
-// Cursor ID 修改工具注入 - $(date +%Y%m%d%H%M%S) - ES模块兼容版本
-// 全局拦截设备标识符 - $(date +%s)
-import crypto from 'crypto';
-
-// 保存原始函数引用
-const originalRandomUUID_$(date +%s) = crypto.randomUUID;
-
-// 重写crypto.randomUUID方法
-crypto.randomUUID = function() {
- return '${new_uuid}';
-};
-
-// 覆盖所有可能的系统ID获取函数 - 使用globalThis
-globalThis.getMachineId = function() { return '${machine_id}'; };
-globalThis.getDeviceId = function() { return '${device_id}'; };
-globalThis.macMachineId = '${mac_machine_id}';
-
-// 确保在不同环境下都能访问
-if (typeof window !== 'undefined') {
- window.getMachineId = globalThis.getMachineId;
- window.getDeviceId = globalThis.getDeviceId;
- window.macMachineId = globalThis.macMachineId;
-}
-
-// 确保模块顶层执行
-console.log('Cursor全局设备标识符拦截已激活 - ES模块版本');
-"
- # 将代码注入到文件开头
- local new_uuid=$(uuidgen | tr '[:upper:]' '[:lower:]')
- local machine_id="auth0|user_$(openssl rand -hex 16)"
- local device_id=$(uuidgen | tr '[:upper:]' '[:lower:]')
- local mac_machine_id=$(openssl rand -hex 32)
-
- inject_universal_code=${inject_universal_code//\$\{new_uuid\}/$new_uuid}
- inject_universal_code=${inject_universal_code//\$\{machine_id\}/$machine_id}
- inject_universal_code=${inject_universal_code//\$\{device_id\}/$device_id}
- inject_universal_code=${inject_universal_code//\$\{mac_machine_id\}/$mac_machine_id}
-
- echo "$inject_universal_code" > "${file}.new"
- cat "$file" >> "${file}.new"
- mv "${file}.new" "$file"
-
- log_debug "完成通用覆盖"
- ((modified_count++))
- log_info "使用最通用方法成功修改文件: ${file/$temp_dir\//}"
- fi
- fi
-
- # 添加在关键操作后记录日志
- echo "[MODIFIED] 文件修改后内容:" >> "$LOG_FILE"
- grep -n "return crypto.randomUUID()" "$file" | head -3 >> "$LOG_FILE"
-
- # 清理临时文件
- rm -f "${file}.tmp" "${file}.bak"
- echo "[PROCESS] 文件处理完成: $file" >> "$LOG_FILE"
- done
-
- if [ "$modified_count" -eq 0 ]; then
- log_error "未能成功修改任何文件"
- rm -rf "$temp_dir"
- return 1
- fi
-
- # 重新签名应用(增加重试机制)
- local max_retry=3
- local retry_count=0
- local sign_success=false
-
- while [ $retry_count -lt $max_retry ]; do
- ((retry_count++))
- log_info "尝试签名 (第 $retry_count 次)..."
-
- # 使用更详细的签名参数
- if codesign --sign - --force --deep --preserve-metadata=entitlements,identifier,flags "$temp_app" 2>&1 | tee /tmp/codesign.log; then
- # 验证签名
- if codesign --verify -vvvv "$temp_app" 2>/dev/null; then
- sign_success=true
- log_info "应用签名验证通过"
- break
- else
- log_warn "签名验证失败,错误日志:"
- cat /tmp/codesign.log
- fi
- else
- log_warn "签名失败,错误日志:"
- cat /tmp/codesign.log
- fi
-
- sleep 3
- done
-
- if ! $sign_success; then
- log_error "经过 $max_retry 次尝试仍无法完成签名"
- log_error "请手动执行以下命令完成签名:"
- echo -e "${BLUE}sudo codesign --sign - --force --deep '${temp_app}'${NC}"
- echo -e "${YELLOW}操作完成后,请手动将应用复制到原路径:${NC}"
- echo -e "${BLUE}sudo cp -R '${temp_app}' '/Applications/'${NC}"
- log_info "临时文件保留在:${temp_dir}"
- return 1
- fi
-
- # 替换原应用
- log_info "安装修改版应用..."
- if ! sudo rm -rf "$CURSOR_APP_PATH" || ! sudo cp -R "$temp_app" "/Applications/"; then
- log_error "应用替换失败,正在恢复..."
- sudo rm -rf "$CURSOR_APP_PATH"
- sudo cp -R "$backup_app" "$CURSOR_APP_PATH"
- rm -rf "$temp_dir" "$backup_app"
- return 1
- fi
-
- # 清理临时文件
- rm -rf "$temp_dir" "$backup_app"
-
- # 设置权限
- sudo chown -R "$CURRENT_USER:staff" "$CURSOR_APP_PATH"
- sudo chmod -R 755 "$CURSOR_APP_PATH"
-
- log_info "Cursor 主程序文件修改完成!原版备份在: ${backup_app/$HOME/\~}"
- return 0
-}
-
-# 显示文件树结构
-show_file_tree() {
- local base_dir=$(dirname "$STORAGE_FILE")
- echo
- log_info "文件结构:"
- echo -e "${BLUE}$base_dir${NC}"
- echo "├── globalStorage"
- echo "│ ├── storage.json (已修改)"
- echo "│ └── backups"
-
- # 列出备份文件
- if [ -d "$BACKUP_DIR" ]; then
- local backup_files=("$BACKUP_DIR"/*)
- if [ ${#backup_files[@]} -gt 0 ]; then
- for file in "${backup_files[@]}"; do
- if [ -f "$file" ]; then
- echo "│ └── $(basename "$file")"
- fi
- done
- else
- echo "│ └── (空)"
- fi
- fi
- echo
-}
-
-# 显示公众号信息
-show_follow_info() {
- echo
- echo -e "${GREEN}================================${NC}"
- echo -e "${YELLOW} 关注公众号【煎饼果子卷AI】一起交流更多Cursor技巧和AI知识(脚本免费、关注公众号加群有更多技巧和大佬) ${NC}"
- echo -e "${GREEN}================================${NC}"
- echo
-}
-
-# 禁用自动更新
-disable_auto_update() {
- local updater_path="$HOME/Library/Application Support/Caches/cursor-updater"
- local app_update_yml="/Applications/Cursor.app/Contents/Resources/app-update.yml"
-
- echo
- log_info "正在禁用 Cursor 自动更新..."
-
- # 备份并清空 app-update.yml
- if [ -f "$app_update_yml" ]; then
- log_info "备份并修改 app-update.yml..."
- if ! sudo cp "$app_update_yml" "${app_update_yml}.bak" 2>/dev/null; then
- log_warn "备份 app-update.yml 失败,继续执行..."
- fi
-
- if sudo bash -c "echo '' > \"$app_update_yml\"" && \
- sudo chmod 444 "$app_update_yml"; then
- log_info "成功禁用 app-update.yml"
- else
- log_error "修改 app-update.yml 失败,请手动执行以下命令:"
- echo -e "${BLUE}sudo cp \"$app_update_yml\" \"${app_update_yml}.bak\"${NC}"
- echo -e "${BLUE}sudo bash -c 'echo \"\" > \"$app_update_yml\"'${NC}"
- echo -e "${BLUE}sudo chmod 444 \"$app_update_yml\"${NC}"
- fi
- else
- log_warn "未找到 app-update.yml 文件"
- fi
-
- # 同时也处理 cursor-updater
- log_info "处理 cursor-updater..."
- if sudo rm -rf "$updater_path" && \
- sudo touch "$updater_path" && \
- sudo chmod 444 "$updater_path"; then
- log_info "成功禁用 cursor-updater"
- else
- log_error "禁用 cursor-updater 失败,请手动执行以下命令:"
- echo -e "${BLUE}sudo rm -rf \"$updater_path\" && sudo touch \"$updater_path\" && sudo chmod 444 \"$updater_path\"${NC}"
- fi
-
- echo
- log_info "验证方法:"
- echo "1. 运行命令:ls -l \"$updater_path\""
- echo " 确认文件权限显示为:r--r--r--"
- echo "2. 运行命令:ls -l \"$app_update_yml\""
- echo " 确认文件权限显示为:r--r--r--"
- echo
- log_info "完成后请重启 Cursor"
-}
-
-# 新增恢复功能选项
-restore_feature() {
- # 检查备份目录是否存在
- if [ ! -d "$BACKUP_DIR" ]; then
- log_warn "备份目录不存在"
- return 1
- fi
-
- # 使用 find 命令获取备份文件列表并存储到数组
- backup_files=()
- while IFS= read -r file; do
- [ -f "$file" ] && backup_files+=("$file")
- done < <(find "$BACKUP_DIR" -name "*.backup_*" -type f 2>/dev/null | sort)
-
- # 检查是否找到备份文件
- if [ ${#backup_files[@]} -eq 0 ]; then
- log_warn "未找到任何备份文件"
- return 1
- fi
-
- echo
- log_info "可用的备份文件:"
-
- # 构建菜单选项字符串
- menu_options="退出 - 不恢复任何文件"
- for i in "${!backup_files[@]}"; do
- menu_options="$menu_options|$(basename "${backup_files[$i]}")"
- done
-
- # 使用菜单选择函数
- select_menu_option "请使用上下箭头选择要恢复的备份文件,按Enter确认:" "$menu_options" 0
- choice=$?
-
- # 处理用户输入
- if [ "$choice" = "0" ]; then
- log_info "跳过恢复操作"
- return 0
- fi
-
- # 获取选择的备份文件 (减1是因为第一个选项是"退出")
- local selected_backup="${backup_files[$((choice-1))]}"
-
- # 验证文件存在性和可读性
- if [ ! -f "$selected_backup" ] || [ ! -r "$selected_backup" ]; then
- log_error "无法访问选择的备份文件"
- return 1
- fi
-
- # 尝试恢复配置
- if cp "$selected_backup" "$STORAGE_FILE"; then
- chmod 644 "$STORAGE_FILE"
- chown "$CURRENT_USER" "$STORAGE_FILE"
- log_info "已从备份文件恢复配置: $(basename "$selected_backup")"
- return 0
- else
- log_error "恢复配置失败"
- return 1
- fi
-}
-
-# 解决"应用已损坏,无法打开"问题
-fix_damaged_app() {
- log_info "正在修复"应用已损坏"问题..."
-
- # 检查Cursor应用是否存在
- if [ ! -d "$CURSOR_APP_PATH" ]; then
- log_error "未找到Cursor应用: $CURSOR_APP_PATH"
- return 1
- fi
-
- log_info "尝试移除隔离属性..."
- if sudo find "$CURSOR_APP_PATH" -print0 \
- | xargs -0 sudo xattr -d com.apple.quarantine 2>/dev/null
- then
- log_info "成功移除隔离属性"
- else
- log_warn "移除隔离属性失败,尝试其他方法..."
- fi
-
- log_info "尝试重新签名应用..."
- if sudo codesign --force --deep --sign - "$CURSOR_APP_PATH" 2>/dev/null; then
- log_info "应用重新签名成功"
- else
- log_warn "应用重新签名失败"
- fi
-
- echo
- log_info "修复完成!请尝试重新打开Cursor应用"
- echo
- echo -e "${YELLOW}如果仍然无法打开,您可以尝试以下方法:${NC}"
- echo "1. 在系统偏好设置->安全性与隐私中,点击"仍要打开"按钮"
- echo "2. 暂时关闭Gatekeeper(不建议): sudo spctl --master-disable"
- echo "3. 重新下载安装Cursor应用"
- echo
- echo -e "${BLUE} 参考链接: https://sysin.org/blog/macos-if-crashes-when-opening/ ${NC}"
-
- return 0
-}
-
-# 新增:通用菜单选择函数
-# 参数:
-# $1 - 提示信息
-# $2 - 选项数组,格式为 "选项1|选项2|选项3"
-# $3 - 默认选项索引 (从0开始)
-# 返回: 选中的选项索引 (从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='\033[A'
- local cursor_down='\033[B'
- local enter_key=$'\n'
-
- # 保存光标位置
- tput sc
-
- # 显示提示信息
- echo -e "$prompt"
-
- # 第一次显示菜单
- for i in "${!options[@]}"; do
- if [ $i -eq $selected_index ]; then
- echo -e " ${GREEN}►${NC} ${options[$i]}"
- else
- echo -e " ${options[$i]}"
- fi
- done
-
- # 循环处理键盘输入
- while true; do
- # 读取单个按键
- read -rsn3 key_input
-
- # 检测按键
- case "$key_input" in
- # 上箭头键
- $'\033[A')
- if [ $selected_index -gt 0 ]; then
- ((selected_index--))
- fi
- ;;
- # 下箭头键
- $'\033[B')
- if [ $selected_index -lt $((${#options[@]}-1)) ]; then
- ((selected_index++))
- fi
- ;;
- # Enter键
- "")
- echo # 换行
- log_info "您选择了: ${options[$selected_index]}"
- return $selected_index
- ;;
- esac
-
- # 恢复光标位置
- tput rc
-
- # 重新显示菜单
- for i in "${!options[@]}"; do
- if [ $i -eq $selected_index ]; then
- echo -e " ${GREEN}►${NC} ${options[$i]}"
- else
- echo -e " ${options[$i]}"
- fi
- done
- done
-}
-
-# 主函数
-main() {
-
- # 初始化日志文件
- initialize_log
- log_info "脚本启动..."
-
- # 🚀 启动时权限修复(解决EACCES错误)
- log_info "🚀 [启动时权限] 执行启动时权限修复..."
- ensure_cursor_directory_permissions
-
- # 记录系统信息
- log_info "系统信息: $(uname -a)"
- log_info "当前用户: $CURRENT_USER"
- log_cmd_output "sw_vers" "macOS 版本信息"
- log_cmd_output "which codesign" "codesign 路径"
- log_cmd_output "ls -ld "$CURSOR_APP_PATH"" "Cursor 应用信息"
-
- # 新增环境检查
- if [[ $(uname) != "Darwin" ]]; then
- log_error "本脚本仅支持 macOS 系统"
- exit 1
- fi
-
- clear
- # 显示 Logo
- echo -e "
- ██████╗██╗ ██╗██████╗ ███████╗ ██████╗ ██████╗
- ██╔════╝██║ ██║██╔══██╗██╔════╝██╔═══██╗██╔══██╗
- ██║ ██║ ██║██████╔╝███████╗██║ ██║██████╔╝
- ██║ ██║ ██║██╔══██╗╚════██║██║ ██║██╔══██╗
- ╚██████╗╚██████╔╝██║ ██║███████║╚██████╔╝██║ ██║
- ╚═════╝ ╚═════╝ ╚═╝ ╚═╝╚══════╝ ╚═════╝ ╚═╝ ╚═╝
- "
- echo -e "${BLUE}================================${NC}"
- echo -e "${GREEN}🚀 Cursor 防掉试用Pro删除工具 ${NC}"
- echo -e "${YELLOW}📱 关注公众号【煎饼果子卷AI】 ${NC}"
- echo -e "${YELLOW}🤝 一起交流更多Cursor技巧和AI知识(脚本免费、关注公众号加群有更多技巧和大佬) ${NC}"
- echo -e "${BLUE}================================${NC}"
- echo
- echo -e "${YELLOW}💰 [小小广告] 出售CursorPro教育号一年质保三个月,有需要找我(86),WeChat:JavaRookie666 ${NC}"
- echo
- echo -e "${YELLOW}💡 [重要提示]${NC} 本工具采用分阶段执行策略,既能彻底清理又能修改机器码。"
- echo -e "${YELLOW}💡 [重要提示]${NC} 本工具免费,如果对您有帮助,请关注公众号【煎饼果子卷AI】"
- echo
- echo
-
- # 🎯 用户选择菜单
- echo
- echo -e "${GREEN}🎯 [选择模式]${NC} 请选择您要执行的操作:"
- echo
- echo -e "${BLUE} 1️⃣ 仅修改机器码${NC}"
- echo -e "${YELLOW} • 仅执行机器码修改功能${NC}"
- echo -e "${YELLOW} • 跳过文件夹删除/环境重置步骤${NC}"
- echo -e "${YELLOW} • 保留现有Cursor配置和数据${NC}"
- echo
- echo -e "${BLUE} 2️⃣ 重置环境+修改机器码${NC}"
- echo -e "${RED} • 执行完全环境重置(删除Cursor文件夹)${NC}"
- echo -e "${RED} • ⚠️ 配置将丢失,请注意备份${NC}"
- echo -e "${YELLOW} • 按照机器代码修改${NC}"
- echo -e "${YELLOW} • 这相当于当前的完整脚本行为${NC}"
- echo
-
- # 获取用户选择
- while true; do
- read -p "请输入选择 (1 或 2): " user_choice
- if [ "$user_choice" = "1" ]; then
- echo -e "${GREEN}✅ [选择]${NC} 您选择了:仅修改机器码"
- execute_mode="MODIFY_ONLY"
- break
- elif [ "$user_choice" = "2" ]; then
- echo -e "${GREEN}✅ [选择]${NC} 您选择了:重置环境+修改机器码"
- echo -e "${RED}⚠️ [重要警告]${NC} 此操作将删除所有Cursor配置文件!"
- read -p "确认执行完全重置?(输入 yes 确认,其他任意键取消): " confirm_reset
- if [ "$confirm_reset" = "yes" ]; then
- execute_mode="RESET_AND_MODIFY"
- break
- else
- echo -e "${YELLOW}👋 [取消]${NC} 用户取消重置操作"
- continue
- fi
- else
- echo -e "${RED}❌ [错误]${NC} 无效选择,请输入 1 或 2"
- fi
- done
-
- echo
-
- # 📋 根据选择显示执行流程说明
- if [ "$execute_mode" = "MODIFY_ONLY" ]; then
- echo -e "${GREEN}📋 [执行流程]${NC} 仅修改机器码模式将按以下步骤执行:"
- echo -e "${BLUE} 1️⃣ 检测Cursor配置文件${NC}"
- echo -e "${BLUE} 2️⃣ 备份现有配置文件${NC}"
- echo -e "${BLUE} 3️⃣ 修改机器码配置${NC}"
- echo -e "${BLUE} 4️⃣ 显示操作完成信息${NC}"
- echo
- echo -e "${YELLOW}⚠️ [注意事项]${NC}"
- echo -e "${YELLOW} • 不会删除任何文件夹或重置环境${NC}"
- echo -e "${YELLOW} • 保留所有现有配置和数据${NC}"
- echo -e "${YELLOW} • 原配置文件会自动备份${NC}"
- echo -e "${YELLOW} • 需要Python3环境来处理JSON配置文件${NC}"
- else
- echo -e "${GREEN}📋 [执行流程]${NC} 重置环境+修改机器码模式将按以下步骤执行:"
- echo -e "${BLUE} 1️⃣ 检测并关闭Cursor进程${NC}"
- echo -e "${BLUE} 2️⃣ 保存Cursor程序路径信息${NC}"
- echo -e "${BLUE} 3️⃣ 删除指定的Cursor试用相关文件夹${NC}"
- echo -e "${BLUE} 📁 ~/Library/Application Support/Cursor${NC}"
- echo -e "${BLUE} 📁 ~/.cursor${NC}"
- echo -e "${BLUE} 3.5️⃣ 预创建必要目录结构,避免权限问题${NC}"
- echo -e "${BLUE} 4️⃣ 重新启动Cursor让其生成新的配置文件${NC}"
- echo -e "${BLUE} 5️⃣ 等待配置文件生成完成(最多45秒)${NC}"
- echo -e "${BLUE} 6️⃣ 关闭Cursor进程${NC}"
- echo -e "${BLUE} 7️⃣ 修改新生成的机器码配置文件${NC}"
- echo -e "${BLUE} 8️⃣ 智能设备识别绕过(MAC地址修改或JS内核修改)${NC}"
- echo -e "${BLUE} 9️⃣ 禁用自动更新${NC}"
- echo -e "${BLUE} 🔟 显示操作完成统计信息${NC}"
- echo
- echo -e "${YELLOW}⚠️ [注意事项]${NC}"
- echo -e "${YELLOW} • 脚本执行过程中请勿手动操作Cursor${NC}"
- echo -e "${YELLOW} • 建议在执行前关闭所有Cursor窗口${NC}"
- echo -e "${YELLOW} • 执行完成后需要重新启动Cursor${NC}"
- echo -e "${YELLOW} • 原配置文件会自动备份到backups文件夹${NC}"
- echo -e "${YELLOW} • 需要Python3环境来处理JSON配置文件${NC}"
- echo -e "${YELLOW} • MAC地址修改是临时的,重启后恢复${NC}"
- fi
- echo
-
- # 🤔 用户确认
- echo -e "${GREEN}🤔 [确认]${NC} 请确认您已了解上述执行流程"
- read -p "是否继续执行?(输入 y 或 yes 继续,其他任意键退出): " confirmation
- if [[ ! "$confirmation" =~ ^(y|yes)$ ]]; then
- echo -e "${YELLOW}👋 [退出]${NC} 用户取消执行,脚本退出"
- exit 0
- fi
- echo -e "${GREEN}✅ [确认]${NC} 用户确认继续执行"
- echo
-
- # 🚀 根据用户选择执行相应功能
- if [ "$execute_mode" = "MODIFY_ONLY" ]; then
- log_info "🚀 [开始] 开始执行仅修改机器码功能..."
-
- # 先进行环境检查
- if ! test_cursor_environment "MODIFY_ONLY"; then
- echo
- log_error "❌ [环境检查失败] 无法继续执行"
- echo
- log_info "💡 [建议] 请选择以下操作:"
- echo -e "${BLUE} 1️⃣ 选择'重置环境+修改机器码'选项(推荐)${NC}"
- echo -e "${BLUE} 2️⃣ 手动启动Cursor一次,然后重新运行脚本${NC}"
- echo -e "${BLUE} 3️⃣ 检查Cursor是否正确安装${NC}"
- echo -e "${BLUE} 4️⃣ 安装Python3: brew install python3${NC}"
- echo
- read -p "按回车键退出..."
- exit 1
- fi
-
- # 执行机器码修改
- if modify_machine_code_config "MODIFY_ONLY"; then
- echo
- log_info "🎉 [完成] 机器码修改完成!"
- log_info "💡 [提示] 现在可以启动Cursor使用新的机器码配置"
- else
- echo
- log_error "❌ [失败] 机器码修改失败!"
- log_info "💡 [建议] 请尝试'重置环境+修改机器码'选项"
- fi
-
- # 🔧 智能设备识别绕过(MAC地址修改或JS内核修改)
- echo
- log_info "🔧 [设备识别] 开始智能设备识别绕过..."
- log_info "💡 [说明] 将根据系统环境自动选择最佳方案(MAC地址修改或JS内核修改)"
-
- if change_system_mac_address; then
- log_info "✅ [成功] 设备识别绕过完成(使用MAC地址修改)"
- else
- log_warn "⚠️ [警告] 设备识别绕过失败或部分失败"
- log_info "💡 [提示] 但可能已通过JS内核修改实现了绕过效果"
- fi
-
- # 🚫 禁用自动更新(仅修改模式也需要)
- echo
- log_info "🚫 [禁用更新] 正在禁用Cursor自动更新..."
- disable_auto_update
-
- # 🛡️ 关键修复:仅修改模式的权限修复
- echo
- log_info "🛡️ [权限修复] 执行仅修改模式的权限修复..."
- log_info "💡 [说明] 确保Cursor应用能够正常启动,无权限错误"
- ensure_cursor_directory_permissions
-
- # 🔧 关键修复:修复应用签名问题(防止"应用已损坏"错误)
- echo
- log_info "🔧 [应用修复] 正在修复Cursor应用签名问题..."
- log_info "💡 [说明] 防止出现'应用已损坏,无法打开'的错误"
-
- if fix_damaged_app; then
- log_info "✅ [应用修复] Cursor应用签名修复成功"
- else
- log_warn "⚠️ [应用修复] 应用签名修复失败,可能需要手动处理"
- log_info "💡 [建议] 如果Cursor无法启动,请在系统偏好设置中允许打开"
- fi
- else
- # 完整的重置环境+修改机器码流程
- log_info "🚀 [开始] 开始执行重置环境+修改机器码功能..."
-
- # 🚀 执行主要功能
- check_permissions
- check_and_kill_cursor
-
- # 🚨 重要警告提示
- echo
- echo -e "${RED}🚨 [重要警告]${NC} ============================================"
- log_warn "⚠️ [风控提醒] Cursor 风控机制非常严格!"
- log_warn "⚠️ [必须删除] 必须完全删除指定文件夹,不能有任何残留设置"
- log_warn "⚠️ [防掉试用] 只有彻底清理才能有效防止掉试用Pro状态"
- echo -e "${RED}🚨 [重要警告]${NC} ============================================"
- echo
-
- # 🎯 执行 Cursor 防掉试用Pro删除文件夹功能
- log_info "🚀 [开始] 开始执行核心功能..."
- remove_cursor_trial_folders
-
- # 🔄 重启Cursor让其重新生成配置文件
- restart_cursor_and_wait
-
- # 🛠️ 修改机器码配置
- modify_machine_code_config
-
- # 🔧 智能设备识别绕过(MAC地址修改或JS内核修改)
- echo
- log_info "🔧 [设备识别] 开始智能设备识别绕过..."
- log_info "💡 [说明] 将根据系统环境自动选择最佳方案(MAC地址修改或JS内核修改)"
-
- if change_system_mac_address; then
- log_info "✅ [成功] 设备识别绕过完成(使用MAC地址修改)"
- else
- log_warn "⚠️ [警告] 设备识别绕过失败或部分失败"
- log_info "💡 [提示] 但可能已通过JS内核修改实现了绕过效果"
- fi
-
- # 🔧 关键修复:修复应用签名问题(防止"应用已损坏"错误)
- echo
- log_info "🔧 [应用修复] 正在修复Cursor应用签名问题..."
- log_info "💡 [说明] 防止出现'应用已损坏,无法打开'的错误"
-
- if fix_damaged_app; then
- log_info "✅ [应用修复] Cursor应用签名修复成功"
- else
- log_warn "⚠️ [应用修复] 应用签名修复失败,可能需要手动处理"
- log_info "💡 [建议] 如果Cursor无法启动,请在系统偏好设置中允许打开"
- fi
- fi
-
- # 🚫 禁用自动更新
- echo
- log_info "🚫 [禁用更新] 正在禁用Cursor自动更新..."
- disable_auto_update
-
- # 🎉 显示操作完成信息
- echo
- log_info "🎉 [完成] Cursor 防掉试用Pro删除操作已完成!"
- echo
-
- # 📱 显示公众号信息
- echo -e "${GREEN}================================${NC}"
- echo -e "${YELLOW}📱 关注公众号【煎饼果子卷AI】一起交流更多Cursor技巧和AI知识(脚本免费、关注公众号加群有更多技巧和大佬) ${NC}"
- echo -e "${GREEN}================================${NC}"
- echo
- log_info "🚀 [提示] 现在可以重新启动 Cursor 尝试使用了!"
- echo
-
- # 🎉 显示修改结果总结
- echo
- echo -e "${GREEN}================================${NC}"
- echo -e "${BLUE} 🎯 修改结果总结 ${NC}"
- echo -e "${GREEN}================================${NC}"
- echo -e "${GREEN}✅ JSON配置文件修改: 完成${NC}"
- echo -e "${GREEN}✅ MAC地址修改: 完成${NC}"
- echo -e "${GREEN}✅ 自动更新禁用: 完成${NC}"
- echo -e "${GREEN}================================${NC}"
- echo
-
- # 🛡️ 脚本完成前最终权限修复
- echo
- log_info "🛡️ [最终权限修复] 执行脚本完成前的最终权限修复..."
- ensure_cursor_directory_permissions
-
- # 🎉 脚本执行完成
- log_info "🎉 [完成] 所有操作已完成!"
- echo
- log_info "💡 [重要提示] 完整的Cursor破解流程已执行:"
- echo -e "${BLUE} ✅ 机器码配置文件修改${NC}"
- echo -e "${BLUE} ✅ 系统MAC地址修改${NC}"
- echo -e "${BLUE} ✅ 自动更新功能禁用${NC}"
- echo -e "${BLUE} ✅ 权限修复和验证${NC}"
- echo
- log_warn "⚠️ [注意] 重启 Cursor 后生效"
- echo
- log_info "🚀 [下一步] 现在可以启动 Cursor 尝试使用了!"
- echo
-
- # 记录脚本完成信息
- log_info "📝 [日志] 脚本执行完成"
- echo "========== Cursor 防掉试用Pro删除工具日志结束 $(date) ==========" >> "$LOG_FILE"
-
- # 显示日志文件位置
- echo
- log_info "📄 [日志] 详细日志已保存到: $LOG_FILE"
- echo "如遇问题请将此日志文件提供给开发者以协助排查"
- echo
-}
-
-# 执行主函数
-main
-
+# Execute main function
+main "$@"
\ No newline at end of file
diff --git a/scripts/run/cursor_mac_id_modifier_new.sh b/scripts/run/cursor_mac_id_modifier_new.sh
deleted file mode 100644
index 6eaff20..0000000
--- a/scripts/run/cursor_mac_id_modifier_new.sh
+++ /dev/null
@@ -1,688 +0,0 @@
-#!/bin/bash
-
-# ========================================
-# Cursor macOS 机器码修改脚本 (重构精简版)
-# ========================================
-#
-# 🎯 重构目标:
-# - 简化脚本复杂度,从3158行压缩到约900行
-# - 自动化权限修复,解决EACCES权限错误
-# - 减少用户交互步骤,提升执行效率
-# - 保持所有原有功能完整性
-#
-# 🚀 执行流程说明:
-# 1. 环境检测和权限预修复
-# 2. 用户选择执行模式(仅修改 vs 完整重置)
-# 3. 自动执行所有必要步骤
-# 4. 智能设备识别绕过(MAC地址或JS内核修改)
-# 5. 自动权限修复和验证
-#
-# ========================================
-
-set -e
-
-# ==================== 核心配置 ====================
-LOG_FILE="/tmp/cursor_reset_$(date +%Y%m%d_%H%M%S).log"
-CURSOR_APP_PATH="/Applications/Cursor.app"
-STORAGE_FILE="$HOME/Library/Application Support/Cursor/User/globalStorage/storage.json"
-BACKUP_DIR="$HOME/Library/Application Support/Cursor/User/globalStorage/backups"
-
-# 颜色定义
-RED='\033[0;31m'
-GREEN='\033[0;32m'
-YELLOW='\033[1;33m'
-BLUE='\033[0;34m'
-NC='\033[0m'
-
-# ==================== 统一工具函数 ====================
-
-# 初始化日志
-init_log() {
- echo "========== Cursor重构脚本执行日志 $(date) ==========" > "$LOG_FILE"
- chmod 644 "$LOG_FILE"
-}
-
-# 精简日志函数
-log() {
- local level="$1"
- local msg="$2"
- local color=""
-
- case "$level" in
- "INFO") color="$GREEN" ;;
- "WARN") color="$YELLOW" ;;
- "ERROR") color="$RED" ;;
- *) color="$BLUE" ;;
- esac
-
- echo -e "${color}[$level]${NC} $msg"
- echo "[$level] $(date '+%H:%M:%S') $msg" >> "$LOG_FILE"
-}
-
-# 统一权限管理器 - 解决所有权限问题
-fix_permissions() {
- log "INFO" "🔧 执行统一权限修复..."
-
- local cursor_support="$HOME/Library/Application Support/Cursor"
- local cursor_home="$HOME/.cursor"
-
- # 创建必要目录结构
- local dirs=(
- "$cursor_support"
- "$cursor_support/User"
- "$cursor_support/User/globalStorage"
- "$cursor_support/logs"
- "$cursor_support/CachedData"
- "$cursor_home"
- "$cursor_home/extensions"
- )
-
- for dir in "${dirs[@]}"; do
- mkdir -p "$dir" 2>/dev/null || true
- done
-
- # 执行核心权限修复命令
- if sudo chown -R "$(whoami)" "$cursor_support" 2>/dev/null && \
- sudo chown -R "$(whoami)" "$cursor_home" 2>/dev/null && \
- chmod -R u+w "$cursor_support" 2>/dev/null && \
- chmod -R u+w "$cursor_home/extensions" 2>/dev/null; then
- log "INFO" "✅ 权限修复成功"
- return 0
- else
- log "ERROR" "❌ 权限修复失败"
- return 1
- fi
-}
-
-# 环境检测器
-detect_environment() {
- log "INFO" "🔍 检测系统环境..."
-
- # 检测macOS版本和硬件
- MACOS_VERSION=$(sw_vers -productVersion)
- HARDWARE_TYPE=$(uname -m)
-
- if [[ "$HARDWARE_TYPE" == "arm64" ]]; then
- HARDWARE_TYPE="Apple Silicon"
- else
- HARDWARE_TYPE="Intel"
- fi
-
- # 检测兼容性
- local macos_major=$(echo "$MACOS_VERSION" | cut -d. -f1)
- if [[ $macos_major -ge 14 ]] || [[ "$HARDWARE_TYPE" == "Apple Silicon" ]]; then
- MAC_COMPATIBLE=false
- log "WARN" "⚠️ 检测到MAC地址修改受限环境: macOS $MACOS_VERSION ($HARDWARE_TYPE)"
- else
- MAC_COMPATIBLE=true
- log "INFO" "✅ 环境兼容性检查通过"
- fi
-
- # 检查Python3
- if ! command -v python3 >/dev/null 2>&1; then
- log "ERROR" "❌ 未找到Python3,请安装: brew install python3"
- return 1
- fi
-
- # 检查Cursor应用
- if [ ! -d "$CURSOR_APP_PATH" ]; then
- log "ERROR" "❌ 未找到Cursor应用: $CURSOR_APP_PATH"
- return 1
- fi
-
- log "INFO" "✅ 环境检测完成: macOS $MACOS_VERSION ($HARDWARE_TYPE)"
- return 0
-}
-
-# 进程管理器
-manage_cursor_process() {
- local action="$1" # kill 或 start
-
- case "$action" in
- "kill")
- log "INFO" "🔄 关闭Cursor进程..."
- pkill -f "Cursor" 2>/dev/null || true
- sleep 2
-
- # 验证是否关闭
- if pgrep -f "Cursor" >/dev/null; then
- pkill -9 -f "Cursor" 2>/dev/null || true
- sleep 2
- fi
- log "INFO" "✅ Cursor进程已关闭"
- ;;
- "start")
- log "INFO" "🚀 启动Cursor..."
- "$CURSOR_APP_PATH/Contents/MacOS/Cursor" > /dev/null 2>&1 &
- sleep 15
- log "INFO" "✅ Cursor已启动"
- ;;
- esac
-}
-
-# 错误处理器
-handle_error() {
- local error_msg="$1"
- local recovery_action="$2"
-
- log "ERROR" "❌ 错误: $error_msg"
-
- if [ -n "$recovery_action" ]; then
- log "INFO" "🔄 尝试恢复: $recovery_action"
- eval "$recovery_action"
- fi
-
- log "INFO" "💡 如需帮助,请查看日志: $LOG_FILE"
-}
-
-# ==================== 功能模块 ====================
-
-# 机器码修改器
-modify_machine_code() {
- log "INFO" "🛠️ 开始修改机器码配置..."
-
- # 检查配置文件
- if [ ! -f "$STORAGE_FILE" ]; then
- log "ERROR" "❌ 配置文件不存在,请先启动Cursor生成配置"
- return 1
- fi
-
- # 创建备份
- mkdir -p "$BACKUP_DIR"
- local backup_file="$BACKUP_DIR/storage.json.backup_$(date +%Y%m%d_%H%M%S)"
- cp "$STORAGE_FILE" "$backup_file" || {
- log "ERROR" "❌ 备份失败"
- return 1
- }
-
- # 生成新ID
- local machine_id="auth0|user_$(openssl rand -hex 16)"
- local mac_machine_id=$(uuidgen | tr '[:upper:]' '[:lower:]')
- local device_id=$(uuidgen | tr '[:upper:]' '[:lower:]')
- local sqm_id="{$(uuidgen | tr '[:lower:]' '[:upper:]')}"
-
- # 修改配置文件
- local python_result=$(python3 -c "
-import json
-import sys
-
-try:
- with open('$STORAGE_FILE', 'r', encoding='utf-8') as f:
- config = json.load(f)
-
- config['telemetry.machineId'] = '$machine_id'
- config['telemetry.macMachineId'] = '$mac_machine_id'
- config['telemetry.devDeviceId'] = '$device_id'
- config['telemetry.sqmId'] = '$sqm_id'
-
- with open('$STORAGE_FILE', 'w', encoding='utf-8') as f:
- json.dump(config, f, indent=2, ensure_ascii=False)
-
- print('SUCCESS')
-except Exception as e:
- print(f'ERROR: {e}')
- sys.exit(1)
-" 2>&1)
-
- if echo "$python_result" | grep -q "SUCCESS"; then
- # 设置只读保护
- chmod 444 "$STORAGE_FILE" 2>/dev/null || true
- log "INFO" "✅ 机器码修改成功"
- log "INFO" "💾 备份保存至: $(basename "$backup_file")"
- return 0
- else
- log "ERROR" "❌ 机器码修改失败: $python_result"
- cp "$backup_file" "$STORAGE_FILE" 2>/dev/null || true
- return 1
- fi
-}
-
-# 智能设备绕过器 - 根据环境自动选择最佳方案
-bypass_device_detection() {
- log "INFO" "🔧 开始智能设备识别绕过..."
-
- # 根据环境兼容性选择方案
- if [ "$MAC_COMPATIBLE" = false ]; then
- log "INFO" "💡 检测到MAC地址修改受限,使用JS内核修改方案"
- return modify_js_kernel
- else
- log "INFO" "💡 尝试MAC地址修改方案"
- if modify_mac_address; then
- return 0
- else
- log "WARN" "⚠️ MAC地址修改失败,切换到JS内核修改"
- return modify_js_kernel
- fi
- fi
-}
-
-# MAC地址修改器(简化版)
-modify_mac_address() {
- log "INFO" "🌐 开始MAC地址修改..."
-
- # 获取活动网络接口
- local interfaces=()
- while IFS= read -r line; do
- if [[ $line == "Hardware Port: Wi-Fi" || $line == "Hardware Port: Ethernet" ]]; then
- read -r dev_line
- local device=$(echo "$dev_line" | awk '{print $2}')
- if [ -n "$device" ] && ifconfig "$device" 2>/dev/null | grep -q "status: active"; then
- interfaces+=("$device")
- fi
- fi
- done < <(networksetup -listallhardwareports)
-
- if [ ${#interfaces[@]} -eq 0 ]; then
- log "WARN" "⚠️ 未找到活动网络接口"
- return 1
- fi
-
- local success_count=0
- for interface in "${interfaces[@]}"; do
- log "INFO" "🔧 处理接口: $interface"
-
- # 生成新MAC地址
- local new_mac=$(printf '%02x:%02x:%02x:%02x:%02x:%02x' \
- $(( (RANDOM & 0xFC) | 0x02 )) $((RANDOM%256)) $((RANDOM%256)) \
- $((RANDOM%256)) $((RANDOM%256)) $((RANDOM%256)))
-
- # 尝试修改MAC地址
- if sudo ifconfig "$interface" down 2>/dev/null && \
- sleep 2 && \
- sudo ifconfig "$interface" ether "$new_mac" 2>/dev/null && \
- sudo ifconfig "$interface" up 2>/dev/null; then
- log "INFO" "✅ 接口 $interface MAC地址修改成功: $new_mac"
- ((success_count++))
- else
- log "WARN" "⚠️ 接口 $interface MAC地址修改失败"
- fi
- sleep 2
- done
-
- if [ $success_count -gt 0 ]; then
- log "INFO" "✅ MAC地址修改完成 ($success_count/${#interfaces[@]} 成功)"
- return 0
- else
- return 1
- fi
-}
-
-# JS内核修改器(简化版)
-modify_js_kernel() {
- log "INFO" "🔧 开始JS内核修改..."
-
- # 关闭Cursor
- manage_cursor_process "kill"
-
- # 目标JS文件
- local js_files=(
- "$CURSOR_APP_PATH/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js"
- "$CURSOR_APP_PATH/Contents/Resources/app/out/main.js"
- )
-
- # 检查是否需要修改
- local need_modify=false
- for file in "${js_files[@]}"; do
- if [ -f "$file" ] && ! grep -q "return crypto.randomUUID()" "$file" 2>/dev/null; then
- need_modify=true
- break
- fi
- done
-
- if [ "$need_modify" = false ]; then
- log "INFO" "✅ JS文件已修改,跳过"
- return 0
- fi
-
- # 创建备份
- local backup_app="/tmp/Cursor.app.backup_$(date +%Y%m%d_%H%M%S)"
- cp -R "$CURSOR_APP_PATH" "$backup_app" || {
- log "ERROR" "❌ 创建备份失败"
- return 1
- fi
-
- # 生成设备ID
- local new_uuid=$(uuidgen | tr '[:upper:]' '[:lower:]')
- local machine_id="auth0|user_$(openssl rand -hex 16)"
-
- # 修改JS文件
- local modified_count=0
- for file in "${js_files[@]}"; do
- if [ ! -f "$file" ]; then
- continue
- fi
-
- log "INFO" "📝 处理文件: $(basename "$file")"
-
- # 创建注入代码
- local inject_code="
-// Cursor设备标识符劫持 - $(date +%Y%m%d%H%M%S)
-import crypto from 'crypto';
-const originalRandomUUID = crypto.randomUUID;
-crypto.randomUUID = function() { return '$new_uuid'; };
-globalThis.getMachineId = function() { return '$machine_id'; };
-console.log('Cursor设备标识符已劫持');
-"
-
- # 注入代码
- echo "$inject_code" > "${file}.new"
- cat "$file" >> "${file}.new"
- mv "${file}.new" "$file"
-
- ((modified_count++))
- log "INFO" "✅ 文件修改成功: $(basename "$file")"
- done
-
- if [ $modified_count -gt 0 ]; then
- # 重新签名
- if codesign --sign - --force --deep "$CURSOR_APP_PATH" 2>/dev/null; then
- log "INFO" "✅ JS内核修改完成 ($modified_count 个文件)"
- return 0
- else
- log "WARN" "⚠️ 签名失败,但修改已完成"
- return 0
- fi
- else
- log "ERROR" "❌ 未修改任何文件"
- return 1
- fi
-}
-
-# 环境重置器
-reset_environment() {
- log "INFO" "🗑️ 开始环境重置..."
-
- # 关闭Cursor
- manage_cursor_process "kill"
-
- # 删除目标文件夹
- local folders=(
- "$HOME/Library/Application Support/Cursor"
- "$HOME/.cursor"
- )
-
- local deleted_count=0
- for folder in "${folders[@]}"; do
- if [ -d "$folder" ]; then
- if rm -rf "$folder"; then
- log "INFO" "✅ 已删除: $folder"
- ((deleted_count++))
- else
- log "ERROR" "❌ 删除失败: $folder"
- fi
- fi
- done
-
- # 修复权限
- fix_permissions
-
- log "INFO" "✅ 环境重置完成 (删除 $deleted_count 个文件夹)"
- return 0
-}
-
-# 禁用自动更新
-disable_auto_update() {
- log "INFO" "🚫 禁用自动更新..."
-
- local app_update_yml="$CURSOR_APP_PATH/Contents/Resources/app-update.yml"
- local updater_path="$HOME/Library/Application Support/Caches/cursor-updater"
-
- # 禁用app-update.yml
- if [ -f "$app_update_yml" ]; then
- sudo cp "$app_update_yml" "${app_update_yml}.bak" 2>/dev/null || true
- sudo bash -c "echo '' > \"$app_update_yml\"" 2>/dev/null || true
- sudo chmod 444 "$app_update_yml" 2>/dev/null || true
- fi
-
- # 禁用cursor-updater
- sudo rm -rf "$updater_path" 2>/dev/null || true
- sudo touch "$updater_path" 2>/dev/null || true
- sudo chmod 444 "$updater_path" 2>/dev/null || true
-
- log "INFO" "✅ 自动更新已禁用"
-}
-
-# 修复应用签名问题
-fix_app_signature() {
- log "INFO" "🔧 修复应用签名..."
-
- # 移除隔离属性
- sudo find "$CURSOR_APP_PATH" -print0 2>/dev/null | \
- xargs -0 sudo xattr -d com.apple.quarantine 2>/dev/null || true
-
- # 重新签名
- sudo codesign --force --deep --sign - "$CURSOR_APP_PATH" 2>/dev/null || true
-
- log "INFO" "✅ 应用签名修复完成"
-}
-
-# ==================== 主执行流程 ====================
-
-# 快速模式 - 仅修改机器码
-quick_mode() {
- log "INFO" "🚀 执行快速模式(仅修改机器码)..."
-
- # 检查环境
- if ! detect_environment; then
- handle_error "环境检测失败" "exit 1"
- return 1
- fi
-
- # 预修复权限
- fix_permissions
-
- # 修改机器码
- if ! modify_machine_code; then
- handle_error "机器码修改失败" "exit 1"
- return 1
- fi
-
- # 设备绕过
- bypass_device_detection || log "WARN" "⚠️ 设备绕过失败,但机器码修改已完成"
-
- # 禁用更新
- disable_auto_update
-
- # 修复签名
- fix_app_signature
-
- # 最终权限修复
- fix_permissions
-
- log "INFO" "🎉 快速模式执行完成!"
- return 0
-}
-
-# 完整模式 - 重置环境+修改机器码
-full_mode() {
- log "INFO" "🚀 执行完整模式(重置环境+修改机器码)..."
-
- # 检查环境
- if ! detect_environment; then
- handle_error "环境检测失败" "exit 1"
- return 1
- fi
-
- # 环境重置
- if ! reset_environment; then
- handle_error "环境重置失败" "exit 1"
- return 1
- fi
-
- # 启动Cursor生成配置
- manage_cursor_process "start"
-
- # 等待配置文件生成
- local config_wait=0
- while [ ! -f "$STORAGE_FILE" ] && [ $config_wait -lt 30 ]; do
- sleep 2
- ((config_wait += 2))
- log "INFO" "⏳ 等待配置文件生成... ($config_wait/30秒)"
- done
-
- # 关闭Cursor
- manage_cursor_process "kill"
-
- # 修改机器码
- if ! modify_machine_code; then
- handle_error "机器码修改失败" "exit 1"
- return 1
- fi
-
- # 设备绕过
- bypass_device_detection || log "WARN" "⚠️ 设备绕过失败,但机器码修改已完成"
-
- # 禁用更新
- disable_auto_update
-
- # 修复签名
- fix_app_signature
-
- # 最终权限修复
- fix_permissions
-
- log "INFO" "🎉 完整模式执行完成!"
- return 0
-}
-
-# ==================== 用户界面 ====================
-
-# 显示Logo和信息
-show_header() {
- clear
- echo -e "
- ██████╗██╗ ██╗██████╗ ███████╗ ██████╗ ██████╗
- ██╔════╝██║ ██║██╔══██╗██╔════╝██╔═══██╗██╔══██╗
- ██║ ██║ ██║██████╔╝███████╗██║ ██║██████╔╝
- ██║ ██║ ██║██╔══██╗╚════██║██║ ██║██╔══██╗
- ╚██████╗╚██████╔╝██║ ██║███████║╚██████╔╝██║ ██║
- ╚═════╝ ╚═════╝ ╚═╝ ╚═╝╚══════╝ ╚═════╝ ╚═╝ ╚═╝
- "
- echo -e "${BLUE}================================${NC}"
- echo -e "${GREEN}🚀 Cursor 机器码修改工具 (重构版) ${NC}"
- echo -e "${YELLOW}📱 关注公众号【煎饼果子卷AI】 ${NC}"
- echo -e "${BLUE}================================${NC}"
- echo
- echo -e "${YELLOW}💡 [免费工具]${NC} 如果对您有帮助,请关注公众号支持开发者"
- echo
-}
-
-# 用户选择菜单
-user_menu() {
- echo -e "${GREEN}🎯 [选择模式]${NC} 请选择执行模式:"
- echo
- echo -e "${BLUE} 1️⃣ 快速模式 - 仅修改机器码${NC}"
- echo -e "${YELLOW} • 保留现有配置和数据${NC}"
- echo -e "${YELLOW} • 执行时间约30秒${NC}"
- echo -e "${YELLOW} • 自动权限修复${NC}"
- echo
- echo -e "${BLUE} 2️⃣ 完整模式 - 重置环境+修改机器码${NC}"
- echo -e "${RED} • 删除所有Cursor配置(请备份)${NC}"
- echo -e "${YELLOW} • 执行时间约90秒${NC}"
- echo -e "${YELLOW} • 彻底重置试用状态${NC}"
- echo
-
- while true; do
- read -p "请输入选择 (1 或 2): " choice
- case "$choice" in
- 1)
- log "INFO" "✅ 用户选择:快速模式"
- return 1
- ;;
- 2)
- echo -e "${RED}⚠️ [警告]${NC} 完整模式将删除所有Cursor配置!"
- read -p "确认执行?(输入 yes 确认): " confirm
- if [ "$confirm" = "yes" ]; then
- log "INFO" "✅ 用户选择:完整模式"
- return 2
- else
- echo -e "${YELLOW}👋 [取消]${NC} 请重新选择"
- continue
- fi
- ;;
- *)
- echo -e "${RED}❌ [错误]${NC} 无效选择,请输入 1 或 2"
- ;;
- esac
- done
-}
-
-# 显示完成信息
-show_completion() {
- echo
- echo -e "${GREEN}================================${NC}"
- echo -e "${BLUE} 🎯 执行完成总结 ${NC}"
- echo -e "${GREEN}================================${NC}"
- echo -e "${GREEN}✅ 机器码配置: 已修改${NC}"
- echo -e "${GREEN}✅ 设备识别绕过: 已完成${NC}"
- echo -e "${GREEN}✅ 自动更新: 已禁用${NC}"
- echo -e "${GREEN}✅ 权限修复: 已完成${NC}"
- echo -e "${GREEN}✅ 应用签名: 已修复${NC}"
- echo -e "${GREEN}================================${NC}"
- echo
- echo -e "${YELLOW}📱 关注公众号【煎饼果子卷AI】获取更多Cursor技巧${NC}"
- echo
- echo -e "${BLUE}🚀 [下一步]${NC} 现在可以启动Cursor使用了!"
- echo -e "${BLUE}📄 [日志]${NC} 详细日志保存在: $LOG_FILE"
- echo
-}
-
-# ==================== 主函数 ====================
-
-main() {
- # 检查权限
- if [ "$EUID" -ne 0 ]; then
- echo -e "${RED}❌ [错误]${NC} 请使用 sudo 运行此脚本"
- echo "示例: sudo $0"
- exit 1
- fi
-
- # 检查macOS
- if [[ $(uname) != "Darwin" ]]; then
- echo -e "${RED}❌ [错误]${NC} 本脚本仅支持 macOS 系统"
- exit 1
- fi
-
- # 初始化
- init_log
- log "INFO" "🚀 Cursor重构脚本启动..."
-
- # 预修复权限
- fix_permissions
-
- # 显示界面
- show_header
-
- # 用户选择
- user_menu
- local mode=$?
-
- echo
- log "INFO" "🚀 开始执行,请稍候..."
- echo
-
- # 执行对应模式
- case $mode in
- 1)
- if quick_mode; then
- show_completion
- exit 0
- else
- log "ERROR" "❌ 快速模式执行失败"
- exit 1
- fi
- ;;
- 2)
- if full_mode; then
- show_completion
- exit 0
- else
- log "ERROR" "❌ 完整模式执行失败"
- exit 1
- fi
- ;;
- esac
-}
-
-# 执行主函数
-main "$@"
diff --git a/scripts/run/cursor_win_id_modifier.ps1 b/scripts/run/cursor_win_id_modifier.ps1
index 6b27639..98a0572 100644
--- a/scripts/run/cursor_win_id_modifier.ps1
+++ b/scripts/run/cursor_win_id_modifier.ps1
@@ -1,21 +1,58 @@
-# 设置输出编码为 UTF-8
+# ========================================
+# 🪟 Cursor Windows ID Modifier Script 🚀
+# ========================================
+# Purpose: Reset Cursor trial by modifying device identifiers
+# Platform: Windows (x64, x86, ARM64)
+# Requirements: Administrator privileges, Cursor installed
+# ========================================
+
+# Set output encoding to UTF-8
$OutputEncoding = [System.Text.Encoding]::UTF8
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
-# 颜色定义
+# ========================================
+# CONFIGURATION
+# ========================================
+
+$SCRIPT_NAME = "Cursor Windows ID Modifier"
+$STORAGE_FILE = "$env:APPDATA\Cursor\User\globalStorage\storage.json"
+$BACKUP_DIR = "$env:APPDATA\Cursor\User\globalStorage\backups"
+
+# Colors for output
$RED = "`e[31m"
$GREEN = "`e[32m"
$YELLOW = "`e[33m"
$BLUE = "`e[34m"
$NC = "`e[0m"
-# 配置文件路径
-$STORAGE_FILE = "$env:APPDATA\Cursor\User\globalStorage\storage.json"
-$BACKUP_DIR = "$env:APPDATA\Cursor\User\globalStorage\backups"
+# ========================================
+# UTILITY FUNCTIONS
+# ========================================
+
+# Logging functions with emojis
+function Write-Info {
+ param([string]$Message)
+ Write-Host "$GREEN✅ [INFO]$NC $Message"
+}
-# PowerShell原生方法生成随机字符串
+function Write-Warn {
+ param([string]$Message)
+ Write-Host "$YELLOW⚠️ [WARN]$NC $Message"
+}
+
+function Write-Error {
+ param([string]$Message)
+ Write-Host "$RED❌ [ERROR]$NC $Message"
+}
+
+function Write-Debug {
+ param([string]$Message)
+ Write-Host "$BLUE🔍 [DEBUG]$NC $Message"
+}
+
+# Generate random string
function Generate-RandomString {
- param([int]$Length)
+ param([int]$Length = 32)
$chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
$result = ""
for ($i = 0; $i -lt $Length; $i++) {
@@ -24,88 +61,407 @@ function Generate-RandomString {
return $result
}
-# 修改Cursor内核JS文件实现设备识别绕过(从macOS版本移植)
-function Modify-CursorJSFiles {
- Write-Host ""
- Write-Host "$BLUE🔧 [内核修改]$NC 开始修改Cursor内核JS文件实现设备识别绕过..."
- Write-Host ""
+# Generate UUID
+function Generate-UUID {
+ return [System.Guid]::NewGuid().ToString().ToLower()
+}
+
+# ========================================
+# CURSOR DETECTION
+# ========================================
+
+# Find Cursor installation
+function Find-CursorInstallation {
+ Write-Info "🔍 Searching for Cursor installation..."
+
+ $cursorPaths = @(
+ "$env:LOCALAPPDATA\Programs\cursor\Cursor.exe",
+ "$env:PROGRAMFILES\Cursor\Cursor.exe",
+ "$env:PROGRAMFILES(X86)\Cursor\Cursor.exe"
+ )
+
+ foreach ($path in $cursorPaths) {
+ if (Test-Path $path) {
+ Write-Info "🎯 Found Cursor at: $path"
+ return $path
+ }
+ }
+
+ Write-Error "Cursor installation not found"
+ return $null
+}
- # Windows版Cursor应用路径
- $cursorAppPath = "${env:LOCALAPPDATA}\Programs\Cursor"
+# Find Cursor resources directory
+function Find-CursorResources {
+ Write-Info "Searching for Cursor resources..."
+
+ $cursorAppPath = "$env:LOCALAPPDATA\Programs\Cursor"
if (-not (Test-Path $cursorAppPath)) {
- # 尝试其他可能的安装路径
$alternatePaths = @(
- "${env:ProgramFiles}\Cursor",
- "${env:ProgramFiles(x86)}\Cursor",
- "${env:USERPROFILE}\AppData\Local\Programs\Cursor"
+ "$env:PROGRAMFILES\Cursor",
+ "$env:PROGRAMFILES(X86)\Cursor"
)
-
+
foreach ($path in $alternatePaths) {
if (Test-Path $path) {
$cursorAppPath = $path
break
}
}
+ }
+
+ if (Test-Path $cursorAppPath) {
+ Write-Info "Found Cursor resources at: $cursorAppPath"
+ return $cursorAppPath
+ }
+
+ Write-Error "Cursor resources not found"
+ return $null
+}
+
+# ========================================
+# PROCESS MANAGEMENT
+# ========================================
+
+# Stop all Cursor processes
+function Stop-AllCursorProcesses {
+ param(
+ [int]$MaxRetries = 3,
+ [int]$WaitSeconds = 5
+ )
+
+ Write-Info "🔄 Stopg Cursursor processes..."
+
+ $cursorProcessNames = @("Cursor", "cursor", "Cursor Helper", "CursorUpdater")
+
+ for ($retry = 1; $retry -le $MaxRetries; $retry++) {
+ Write-Debug "Process check attempt $retry/$MaxRetries"
+
+ $foundProcesses = @()
+ foreach ($processName in $cursorProcessNames) {
+ $processes = Get-Process -Name $processName -ErrorAction SilentlyContinue
+ if ($processes) {
+ $foundProcesses += $processes
+ Write-Warn "Found process: $processName (PID: $($processes.Id -join ', '))"
+ }
+ }
+
+ if ($foundProcesses.Count -eq 0) {
+ Write-Info "All Cursor processes stopped"
+ return $true
+ }
+
+ Write-Info "Stopping $($foundProcesses.Count) Cursor processes..."
+
+ # Try graceful shutdown first
+ foreach ($process in $foundProcesses) {
+ try {
+ $process.CloseMainWindow() | Out-Null
+ } catch {
+ Write-Debug "Graceful shutdown failed for: $($process.ProcessName)"
+ }
+ }
+
+ Start-Sleep -Seconds 3
+
+ # Force terminate remaining processes
+ foreach ($processName in $cursorProcessNames) {
+ $processes = Get-Process -Name $processName -ErrorAction SilentlyContinue
+ if ($processes) {
+ foreach ($process in $processes) {
+ try {
+ Stop-Process -Id $process.Id -Force
+ Write-Debug "Force terminated: $($process.ProcessName) (PID: $($process.Id))"
+ } catch {
+ Write-Warn "Failed to terminate: $($process.ProcessName)"
+ }
+ }
+ }
+ }
+
+ if ($retry -lt $MaxRetries) {
+ Write-Info "Waiting $WaitSeconds seconds before retry..."
+ Start-Sleep -Seconds $WaitSeconds
+ }
+ }
+
+ Write-Error "Failed to stop all Cursor processes after $MaxRetries attempts"
+ return $false
+}
+
+# ========================================
+# FOLDER MANAGEMENT
+# ========================================
+
+# Remove Cursor trial folders
+function Remove-CursorTrialFolders {
+ Write-Info "Removing Cursor trial folders..."
+
+ $foldersToDelete = @(
+ "$env:USERPROFILE\.cursor",
+ "$env:APPDATA\Cursor",
+ "C:\Users\Administrator\.cursor",
+ "C:\Users\Administrator\AppData\Roaming\Cursor"
+ )
+
+ $deletedCount = 0
+ $skippedCount = 0
+ $errorCount = 0
+
+ foreach ($folder in $foldersToDelete) {
+ Write-Debug "Checking folder: $folder"
+
+ if (Test-Path $folder) {
+ try {
+ Write-Warn "Found folder, removing: $folder"
+ Remove-Item -Path $folder -Recurse -Force -ErrorAction Stop
+ Write-Info "Successfully removed: $folder"
+ $deletedCount++
+ }
+ catch {
+ Write-Error "Failed to remove folder: $folder - $($_.Exception.Message)"
+ $errorCount++
+ }
+ } else {
+ Write-Info "Folder not found (skipping): $folder"
+ $skippedCount++
+ }
+ }
+
+ Write-Info "Folder removal completed - Deleted: $deletedCount, Skipped: $skippedCount, Errors: $errorCount"
+
+ # Pre-create necessary directory structure
+ $cursorAppData = "$env:APPDATA\Cursor"
+ $cursorUserProfile = "$env:USERPROFILE\.cursor"
+
+ try {
+ if (-not (Test-Path $cursorAppData)) {
+ New-Item -ItemType Directory -Path $cursorAppData -Force | Out-Null
+ }
+ if (-not (Test-Path $cursorUserProfile)) {
+ New-Item -ItemType Directory -Path $cursorUserProfile -Force | Out-Null
+ }
+ Write-Info "Directory structure pre-created successfully"
+ } catch {
+ Write-Warn "Failed to pre-create directories: $($_.Exception.Message)"
+ }
+
+ return ($errorCount -eq 0)
+}
- if (-not (Test-Path $cursorAppPath)) {
- Write-Host "$RED❌ [错误]$NC 未找到Cursor应用安装路径"
- Write-Host "$YELLOW💡 [提示]$NC 请确认Cursor已正确安装"
+# ========================================
+# CURSOR MANAGEMENT
+# ========================================
+
+# Start Cursor to generate config
+function Start-CursorForConfig {
+ Write-Info "Starting Cursor to generate configuration..."
+
+ $cursorPath = Find-CursorInstallation
+ if (-not $cursorPath) {
+ return $false
+ }
+
+ try {
+ Write-Info "Starting Cursor at: $cursorPath"
+ $process = Start-Process -FilePath $cursorPath -PassThru -WindowStyle Hidden
+
+ Write-Info "Waiting for configuration file generation..."
+ $configPath = $STORAGE_FILE
+ $maxWait = 60
+ $waited = 0
+
+ while (-not (Test-Path $configPath) -and $waited -lt $maxWait) {
+ Start-Sleep -Seconds 2
+ $waited += 2
+ if ($waited % 10 -eq 0) {
+ Write-Info "Still waiting... ($waited/$maxWait seconds)"
+ }
+ }
+
+ if (Test-Path $configPath) {
+ Write-Info "Configuration file generated successfully"
+
+ # Wait a bit more to ensure file is fully written
+ Start-Sleep -Seconds 5
+
+ # Stop Cursor
+ if ($process -and -not $process.HasExited) {
+ $process.Kill()
+ $process.WaitForExit(5000)
+ }
+
+ # Ensure all processes are stopped
+ Stop-AllCursorProcesses | Out-Null
+
+ return $true
+ } else {
+ Write-Warn "Configuration file not generated within timeout"
return $false
}
+ } catch {
+ Write-Error "Failed to start Cursor: $($_.Exception.Message)"
+ return $false
}
+}
- Write-Host "$GREEN✅ [发现]$NC 找到Cursor安装路径: $cursorAppPath"
+# ========================================
+# CONFIGURATION MANAGEMENT
+# ========================================
- # 生成新的设备标识符
- $newUuid = [System.Guid]::NewGuid().ToString().ToLower()
- $machineId = "auth0|user_$(Generate-RandomString -Length 32)"
- $deviceId = [System.Guid]::NewGuid().ToString().ToLower()
- $macMachineId = Generate-RandomString -Length 64
+# Backup configuration
+function Backup-Config {
+ if (-not (Test-Path $STORAGE_FILE)) {
+ Write-Warn "Configuration file not found, skipping backup"
+ return $true
+ }
+
+ if (-not (Test-Path $BACKUP_DIR)) {
+ New-Item -ItemType Directory -Path $BACKUP_DIR -Force | Out-Null
+ }
+
+ $backupName = "storage.json.backup_$(Get-Date -Format 'yyyyMMdd_HHmmss')"
+ $backupPath = "$BACKUP_DIR\$backupName"
+
+ try {
+ Copy-Item $STORAGE_FILE $backupPath -ErrorAction Stop
+ Write-Info "Configuration backed up to: $backupName"
+ return $true
+ } catch {
+ Write-Error "Failed to backup configuration: $($_.Exception.Message)"
+ return $false
+ }
+}
+
+# Modify machine code configuration
+function Modify-MachineCodeConfig {
+ Write-Info "Modifying machine code configuration..."
+
+ $configPath = $STORAGE_FILE
+
+ # Check if config file exists
+ if (-not (Test-Path $configPath)) {
+ Write-Error "Configuration file not found: $configPath"
+ Write-Info "Attempting to generate configuration file..."
+
+ if (Start-CursorForConfig) {
+ Write-Info "Configuration file generated, continuing..."
+ } else {
+ Write-Error "Failed to generate configuration file"
+ return $false
+ }
+ }
+
+ # Verify JSON format
+ try {
+ $originalContent = Get-Content $configPath -Raw -Encoding UTF8 -ErrorAction Stop
+ $config = $originalContent | ConvertFrom-Json -ErrorAction Stop
+ Write-Info "Configuration file format is valid"
+ } catch {
+ Write-Error "Configuration file format is invalid: $($_.Exception.Message)"
+ return $false
+ }
+
+ # Backup original configuration
+ if (-not (Backup-Config)) {
+ return $false
+ }
+
+ # Generate new IDs
+ $MAC_MACHINE_ID = Generate-UUID
+ $UUID = Generate-UUID
+ $MACHINE_ID = "auth0|user_$(Generate-RandomString -Length 64)"
+ $SQM_ID = "{$(([System.Guid]::NewGuid()).ToString().ToUpper())}"
+
+ Write-Info "Generated new device identifiers"
+
+ try {
+ # Update configuration
+ $config.'telemetry.machineId' = $MACHINE_ID
+ $config.'telemetry.macMachineId' = $MAC_MACHINE_ID
+ $config.'telemetry.devDeviceId' = $UUID
+ $config.'telemetry.sqmId' = $SQM_ID
+
+ # Write updated configuration
+ $config | ConvertTo-Json -Depth 10 | Set-Content -Path $configPath -Encoding UTF8 -NoNewline
+
+ Write-Info "Configuration updated successfully"
+ Write-Info "Updated identifiers:"
+ Write-Host " • machineId: $($MACHINE_ID.Substring(0, [Math]::Min(20, $MACHINE_ID.Length)))..."
+ Write-Host " • macMachineId: $MAC_MACHINE_ID"
+ Write-Host " • devDeviceId: $UUID"
+ Write-Host " • sqmId: $SQM_ID"
+
+ return $true
+ } catch {
+ Write-Error "Failed to update configuration: $($_.Exception.Message)"
+ return $false
+ }
+}
- Write-Host "$GREEN🔑 [生成]$NC 已生成新的设备标识符"
+# ========================================
+# JAVASCRIPT MODIFICATION
+# ========================================
- # 目标JS文件列表(Windows路径)
+# Modify Cursor JS files
+function Modify-CursorJSFiles {
+ Write-Info "Modifying Cursor JS files..."
+
+ $cursorAppPath = Find-CursorResources
+ if (-not $cursorAppPath) {
+ return $false
+ }
+
+ # Target JS files
$jsFiles = @(
"$cursorAppPath\resources\app\out\vs\workbench\api\node\extensionHostProcess.js",
"$cursorAppPath\resources\app\out\main.js",
"$cursorAppPath\resources\app\out\vs\code\node\cliProcessMain.js"
)
-
+
$modifiedCount = 0
$needModification = $false
-
- # 检查是否需要修改
- Write-Host "$BLUE🔍 [检查]$NC 检查JS文件修改状态..."
+
+ # Check if modification is needed
foreach ($file in $jsFiles) {
if (-not (Test-Path $file)) {
- Write-Host "$YELLOW⚠️ [警告]$NC 文件不存在: $(Split-Path $file -Leaf)"
+ Write-Warn "File not found: $(Split-Path $file -Leaf)"
continue
}
-
+
$content = Get-Content $file -Raw -ErrorAction SilentlyContinue
- if ($content -and $content -notmatch "return crypto\.randomUUID\(\)") {
- Write-Host "$BLUE📝 [需要]$NC 文件需要修改: $(Split-Path $file -Leaf)"
+ if ($content -and $content -notmatch "Cursor ID Modifier") {
+ Write-Debug "File needs modification: $(Split-Path $file -Leaf)"
$needModification = $true
break
} else {
- Write-Host "$GREEN✅ [已修改]$NC 文件已修改: $(Split-Path $file -Leaf)"
+ Write-Info "File already modified: $(Split-Path $file -Leaf)"
}
}
-
+
if (-not $needModification) {
- Write-Host "$GREEN✅ [跳过]$NC 所有JS文件已经被修改过,无需重复操作"
+ Write-Info "All JS files already modified, skipping"
return $true
}
-
- # 关闭Cursor进程
- Write-Host "$BLUE🔄 [关闭]$NC 关闭Cursor进程以进行文件修改..."
- Stop-AllCursorProcesses -MaxRetries 3 -WaitSeconds 3 | Out-Null
-
- # 创建备份
+
+ # Stop Cursor processes
+ if (-not (Stop-AllCursorProcesses -MaxRetries 3 -WaitSeconds 3)) {
+ Write-Error "Failed to stop Cursor processes"
+ return $false
+ }
+
+ # Generate new identifiers
+ $newUuid = Generate-UUID
+ $machineId = "auth0|user_$(Generate-RandomString -Length 32)"
+ $deviceId = Generate-UUID
+ $macMachineId = Generate-RandomString -Length 64
+
+ Write-Info "Generated new device identifiers for JS injection"
+
+ # Create backup
$timestamp = Get-Date -Format "yyyyMMdd_HHmmss"
$backupPath = "$env:TEMP\Cursor_JS_Backup_$timestamp"
-
- Write-Host "$BLUE💾 [备份]$NC 创建Cursor JS文件备份..."
+
try {
New-Item -ItemType Directory -Path $backupPath -Force | Out-Null
foreach ($file in $jsFiles) {
@@ -114,1566 +470,296 @@ function Modify-CursorJSFiles {
Copy-Item $file "$backupPath\$fileName" -Force
}
}
- Write-Host "$GREEN✅ [备份]$NC 备份创建成功: $backupPath"
+ Write-Info "JS files backed up to: $backupPath"
} catch {
- Write-Host "$RED❌ [错误]$NC 创建备份失败: $($_.Exception.Message)"
+ Write-Error "Failed to create backup: $($_.Exception.Message)"
return $false
}
-
- # 修改JS文件
- Write-Host "$BLUE🔧 [修改]$NC 开始修改JS文件..."
-
+
+ # Modify JS files
foreach ($file in $jsFiles) {
if (-not (Test-Path $file)) {
- Write-Host "$YELLOW⚠️ [跳过]$NC 文件不存在: $(Split-Path $file -Leaf)"
+ Write-Warn "File not found: $(Split-Path $file -Leaf)"
continue
}
-
- Write-Host "$BLUE📝 [处理]$NC 正在处理: $(Split-Path $file -Leaf)"
-
+
+ Write-Info "Processing: $(Split-Path $file -Leaf)"
+
try {
$content = Get-Content $file -Raw -Encoding UTF8
-
- # 检查是否已经修改过
- if ($content -match "return crypto\.randomUUID\(\)" -or $content -match "// Cursor ID 修改工具注入") {
- Write-Host "$GREEN✅ [跳过]$NC 文件已经被修改过"
+
+ # Check if already modified
+ if ($content -match "Cursor ID Modifier") {
+ Write-Info "File already modified: $(Split-Path $file -Leaf)"
$modifiedCount++
continue
}
-
- # ES模块兼容的JavaScript注入代码
- $timestampVar = [DateTimeOffset]::Now.ToUnixTimeSeconds()
+
+ # Create injection code
$injectCode = @"
-// Cursor ID 修改工具注入 - $(Get-Date) - ES模块兼容版本
-import crypto from 'crypto';
-
-// 保存原始函数引用
-const originalRandomUUID_${timestampVar} = crypto.randomUUID;
-
-// 重写crypto.randomUUID方法
-crypto.randomUUID = function() {
- return '${newUuid}';
-};
-
-// 覆盖所有可能的系统ID获取函数 - ES模块兼容版本
-globalThis.getMachineId = function() { return '${machineId}'; };
-globalThis.getDeviceId = function() { return '${deviceId}'; };
-globalThis.macMachineId = '${macMachineId}';
-
-// 确保在不同环境下都能访问
-if (typeof window !== 'undefined') {
- window.getMachineId = globalThis.getMachineId;
- window.getDeviceId = globalThis.getDeviceId;
- window.macMachineId = globalThis.macMachineId;
+// Cursor ID Modifier Injection - $(Get-Date)
+const originalRequire = typeof require === 'function' ? require : null;
+if (originalRequire) {
+ require = function(module) {
+ try {
+ const result = originalRequire(module);
+ if (module === 'crypto' && result && result.randomUUID) {
+ result.randomUUID = function() { return '$newUuid'; };
+ }
+ return result;
+ } catch (e) {
+ return originalRequire(module);
+ }
+ };
}
-// 确保模块顶层执行
-console.log('Cursor设备标识符已成功劫持 - ES模块版本 煎饼果子(86) 关注公众号【煎饼果子卷AI】一起交流更多Cursor技巧和AI知识(脚本免费、关注公众号加群有更多技巧和大佬)');
+// Override global functions
+try { if (typeof global !== 'undefined' && global.getMachineId) global.getMachineId = function() { return '$machineId'; }; } catch(e){}
+try { if (typeof global !== 'undefined' && global.getDeviceId) global.getDeviceId = function() { return '$deviceId'; }; } catch(e){}
+try { if (typeof process !== 'undefined' && process.env) process.env.VSCODE_MACHINE_ID = '$machineId'; } catch(e){}
-"@
-
- # 方法1: 查找IOPlatformUUID相关函数
- if ($content -match "IOPlatformUUID") {
- Write-Host "$BLUE🔍 [发现]$NC 找到IOPlatformUUID关键字"
-
- # 针对不同的函数模式进行修改
- if ($content -match "function a\$") {
- $content = $content -replace "function a\$\(t\)\{switch", "function a`$(t){return crypto.randomUUID(); switch"
- Write-Host "$GREEN✅ [成功]$NC 修改a`$函数成功"
- $modifiedCount++
- continue
- }
+console.log('Cursor ID Modifier: Patches applied');
+// End Cursor ID Modifier Injection
- # 通用注入方法
- $content = $injectCode + $content
- Write-Host "$GREEN✅ [成功]$NC 通用注入方法修改成功"
- $modifiedCount++
- }
- # 方法2: 查找其他设备ID相关函数
- elseif ($content -match "function t\$\(\)" -or $content -match "async function y5") {
- Write-Host "$BLUE🔍 [发现]$NC 找到设备ID相关函数"
-
- # 修改MAC地址获取函数
- if ($content -match "function t\$\(\)") {
- $content = $content -replace "function t\$\(\)\{", "function t`$(){return `"00:00:00:00:00:00`";"
- Write-Host "$GREEN✅ [成功]$NC 修改MAC地址获取函数"
- }
-
- # 修改设备ID获取函数
- if ($content -match "async function y5") {
- $content = $content -replace "async function y5\(t\)\{", "async function y5(t){return crypto.randomUUID();"
- Write-Host "$GREEN✅ [成功]$NC 修改设备ID获取函数"
- }
-
- $modifiedCount++
- }
- else {
- Write-Host "$YELLOW⚠️ [警告]$NC 未找到已知的设备ID函数模式,使用通用注入"
- $content = $injectCode + $content
- $modifiedCount++
- }
-
- # 写入修改后的内容
- Set-Content -Path $file -Value $content -Encoding UTF8 -NoNewline
- Write-Host "$GREEN✅ [完成]$NC 文件修改完成: $(Split-Path $file -Leaf)"
-
- } catch {
- Write-Host "$RED❌ [错误]$NC 修改文件失败: $($_.Exception.Message)"
- # 尝试从备份恢复
- $fileName = Split-Path $file -Leaf
- $backupFile = "$backupPath\$fileName"
- if (Test-Path $backupFile) {
- Copy-Item $backupFile $file -Force
- Write-Host "$YELLOW🔄 [恢复]$NC 已从备份恢复文件"
+"@
+
+ # Inject code at beginning
+ $content = $injectCode + $content
+
+ # Write modified content
+ Set-Content -Path $file -Value $content -Encoding UTF8 -NoNewline
+ Write-Info "Successfully modified: $(Split-Path $file -Leaf)"
+ $modifiedCount++
+
+ } catch {
+ Write-Error "Failed to modify file: $($_.Exception.Message)"
+ # Try to restore from backup
+ $fileName = Split-Path $file -Leaf
+ $backupFile = "$backupPath\$fileName"
+ if (Test-Path $backupFile) {
+ Copy-Item $backupFile $file -Force
+ Write-Info "Restored from backup: $(Split-Path $file -Leaf)"
}
}
}
-
+
if ($modifiedCount -gt 0) {
- Write-Host ""
- Write-Host "$GREEN🎉 [完成]$NC 成功修改 $modifiedCount 个JS文件"
- Write-Host "$BLUE💾 [备份]$NC 原始文件备份位置: $backupPath"
- Write-Host "$BLUE💡 [说明]$NC JavaScript注入功能已启用,实现设备识别绕过"
+ Write-Info "Successfully modified $modifiedCount JS files"
+ Write-Info "Backup location: $backupPath"
return $true
} else {
- Write-Host "$RED❌ [失败]$NC 没有成功修改任何文件"
- return $false
- }
-}
-
-
-# 🚀 新增 Cursor 防掉试用Pro删除文件夹功能
-function Remove-CursorTrialFolders {
- Write-Host ""
- Write-Host "$GREEN🎯 [核心功能]$NC 正在执行 Cursor 防掉试用Pro删除文件夹..."
- Write-Host "$BLUE📋 [说明]$NC 此功能将删除指定的Cursor相关文件夹以重置试用状态"
- Write-Host ""
-
- # 定义需要删除的文件夹路径
- $foldersToDelete = @()
-
- # Windows Administrator 用户路径
- $adminPaths = @(
- "C:\Users\Administrator\.cursor",
- "C:\Users\Administrator\AppData\Roaming\Cursor"
- )
-
- # 当前用户路径
- $currentUserPaths = @(
- "$env:USERPROFILE\.cursor",
- "$env:APPDATA\Cursor"
- )
-
- # 合并所有路径
- $foldersToDelete += $adminPaths
- $foldersToDelete += $currentUserPaths
-
- Write-Host "$BLUE📂 [检测]$NC 将检查以下文件夹:"
- foreach ($folder in $foldersToDelete) {
- Write-Host " 📁 $folder"
- }
- Write-Host ""
-
- $deletedCount = 0
- $skippedCount = 0
- $errorCount = 0
-
- # 删除指定文件夹
- foreach ($folder in $foldersToDelete) {
- Write-Host "$BLUE🔍 [检查]$NC 检查文件夹: $folder"
-
- if (Test-Path $folder) {
- try {
- Write-Host "$YELLOW⚠️ [警告]$NC 发现文件夹存在,正在删除..."
- Remove-Item -Path $folder -Recurse -Force -ErrorAction Stop
- Write-Host "$GREEN✅ [成功]$NC 已删除文件夹: $folder"
- $deletedCount++
- }
- catch {
- Write-Host "$RED❌ [错误]$NC 删除文件夹失败: $folder"
- Write-Host "$RED💥 [详情]$NC 错误信息: $($_.Exception.Message)"
- $errorCount++
- }
- } else {
- Write-Host "$YELLOW⏭️ [跳过]$NC 文件夹不存在: $folder"
- $skippedCount++
- }
- Write-Host ""
- }
-
- # 显示操作统计
- Write-Host "$GREEN📊 [统计]$NC 操作完成统计:"
- Write-Host " ✅ 成功删除: $deletedCount 个文件夹"
- Write-Host " ⏭️ 跳过处理: $skippedCount 个文件夹"
- Write-Host " ❌ 删除失败: $errorCount 个文件夹"
- Write-Host ""
-
- if ($deletedCount -gt 0) {
- Write-Host "$GREEN🎉 [完成]$NC Cursor 防掉试用Pro文件夹删除完成!"
-
- # 🔧 预创建必要的目录结构,避免权限问题
- Write-Host "$BLUE🔧 [修复]$NC 预创建必要的目录结构以避免权限问题..."
-
- $cursorAppData = "$env:APPDATA\Cursor"
- $cursorLocalAppData = "$env:LOCALAPPDATA\cursor"
- $cursorUserProfile = "$env:USERPROFILE\.cursor"
-
- # 创建主要目录
- try {
- if (-not (Test-Path $cursorAppData)) {
- New-Item -ItemType Directory -Path $cursorAppData -Force | Out-Null
- }
- if (-not (Test-Path $cursorUserProfile)) {
- New-Item -ItemType Directory -Path $cursorUserProfile -Force | Out-Null
- }
- Write-Host "$GREEN✅ [完成]$NC 目录结构预创建完成"
- } catch {
- Write-Host "$YELLOW⚠️ [警告]$NC 预创建目录时出现问题: $($_.Exception.Message)"
- }
- } else {
- Write-Host "$YELLOW🤔 [提示]$NC 未找到需要删除的文件夹,可能已经清理过了"
- }
- Write-Host ""
-}
-
-# 🔄 重启Cursor并等待配置文件生成
-function Restart-CursorAndWait {
- Write-Host ""
- Write-Host "$GREEN🔄 [重启]$NC 正在重启Cursor以重新生成配置文件..."
-
- if (-not $global:CursorProcessInfo) {
- Write-Host "$RED❌ [错误]$NC 未找到Cursor进程信息,无法重启"
- return $false
- }
-
- $cursorPath = $global:CursorProcessInfo.Path
-
- # 修复:确保路径是字符串类型
- if ($cursorPath -is [array]) {
- $cursorPath = $cursorPath[0]
- }
-
- # 验证路径不为空
- if ([string]::IsNullOrEmpty($cursorPath)) {
- Write-Host "$RED❌ [错误]$NC Cursor路径为空"
- return $false
- }
-
- Write-Host "$BLUE📍 [路径]$NC 使用路径: $cursorPath"
-
- if (-not (Test-Path $cursorPath)) {
- Write-Host "$RED❌ [错误]$NC Cursor可执行文件不存在: $cursorPath"
-
- # 尝试使用备用路径
- $backupPaths = @(
- "$env:LOCALAPPDATA\Programs\cursor\Cursor.exe",
- "$env:PROGRAMFILES\Cursor\Cursor.exe",
- "$env:PROGRAMFILES(X86)\Cursor\Cursor.exe"
- )
-
- $foundPath = $null
- foreach ($backupPath in $backupPaths) {
- if (Test-Path $backupPath) {
- $foundPath = $backupPath
- Write-Host "$GREEN💡 [发现]$NC 使用备用路径: $foundPath"
- break
- }
- }
-
- if (-not $foundPath) {
- Write-Host "$RED❌ [错误]$NC 无法找到有效的Cursor可执行文件"
- return $false
- }
-
- $cursorPath = $foundPath
- }
-
- try {
- Write-Host "$GREEN🚀 [启动]$NC 正在启动Cursor..."
- $process = Start-Process -FilePath $cursorPath -PassThru -WindowStyle Hidden
-
- Write-Host "$YELLOW⏳ [等待]$NC 等待20秒让Cursor完全启动并生成配置文件..."
- Start-Sleep -Seconds 20
-
- # 检查配置文件是否生成
- $configPath = "$env:APPDATA\Cursor\User\globalStorage\storage.json"
- $maxWait = 45
- $waited = 0
-
- while (-not (Test-Path $configPath) -and $waited -lt $maxWait) {
- Write-Host "$YELLOW⏳ [等待]$NC 等待配置文件生成... ($waited/$maxWait 秒)"
- Start-Sleep -Seconds 1
- $waited++
- }
-
- if (Test-Path $configPath) {
- Write-Host "$GREEN✅ [成功]$NC 配置文件已生成: $configPath"
-
- # 额外等待确保文件完全写入
- Write-Host "$YELLOW⏳ [等待]$NC 等待5秒确保配置文件完全写入..."
- Start-Sleep -Seconds 5
- } else {
- Write-Host "$YELLOW⚠️ [警告]$NC 配置文件未在预期时间内生成"
- Write-Host "$BLUE💡 [提示]$NC 可能需要手动启动Cursor一次来生成配置文件"
- }
-
- # 强制关闭Cursor
- Write-Host "$YELLOW🔄 [关闭]$NC 正在关闭Cursor以进行配置修改..."
- if ($process -and -not $process.HasExited) {
- $process.Kill()
- $process.WaitForExit(5000)
- }
-
- # 确保所有Cursor进程都关闭
- Get-Process -Name "Cursor" -ErrorAction SilentlyContinue | Stop-Process -Force
- Get-Process -Name "cursor" -ErrorAction SilentlyContinue | Stop-Process -Force
-
- Write-Host "$GREEN✅ [完成]$NC Cursor重启流程完成"
- return $true
-
- } catch {
- Write-Host "$RED❌ [错误]$NC 重启Cursor失败: $($_.Exception.Message)"
- Write-Host "$BLUE💡 [调试]$NC 错误详情: $($_.Exception.GetType().FullName)"
- return $false
- }
-}
-
-# 🔒 强制关闭所有Cursor进程(增强版)
-function Stop-AllCursorProcesses {
- param(
- [int]$MaxRetries = 3,
- [int]$WaitSeconds = 5
- )
-
- Write-Host "$BLUE🔒 [进程检查]$NC 正在检查并关闭所有Cursor相关进程..."
-
- # 定义所有可能的Cursor进程名称
- $cursorProcessNames = @(
- "Cursor",
- "cursor",
- "Cursor Helper",
- "Cursor Helper (GPU)",
- "Cursor Helper (Plugin)",
- "Cursor Helper (Renderer)",
- "CursorUpdater"
- )
-
- for ($retry = 1; $retry -le $MaxRetries; $retry++) {
- Write-Host "$BLUE🔍 [检查]$NC 第 $retry/$MaxRetries 次进程检查..."
-
- $foundProcesses = @()
- foreach ($processName in $cursorProcessNames) {
- $processes = Get-Process -Name $processName -ErrorAction SilentlyContinue
- if ($processes) {
- $foundProcesses += $processes
- Write-Host "$YELLOW⚠️ [发现]$NC 进程: $processName (PID: $($processes.Id -join ', '))"
- }
- }
-
- if ($foundProcesses.Count -eq 0) {
- Write-Host "$GREEN✅ [成功]$NC 所有Cursor进程已关闭"
- return $true
- }
-
- Write-Host "$YELLOW🔄 [关闭]$NC 正在关闭 $($foundProcesses.Count) 个Cursor进程..."
-
- # 先尝试优雅关闭
- foreach ($process in $foundProcesses) {
- try {
- $process.CloseMainWindow() | Out-Null
- Write-Host "$BLUE • 优雅关闭: $($process.ProcessName) (PID: $($process.Id))$NC"
- } catch {
- Write-Host "$YELLOW • 优雅关闭失败: $($process.ProcessName)$NC"
- }
- }
-
- Start-Sleep -Seconds 3
-
- # 强制终止仍在运行的进程
- foreach ($processName in $cursorProcessNames) {
- $processes = Get-Process -Name $processName -ErrorAction SilentlyContinue
- if ($processes) {
- foreach ($process in $processes) {
- try {
- Stop-Process -Id $process.Id -Force
- Write-Host "$RED • 强制终止: $($process.ProcessName) (PID: $($process.Id))$NC"
- } catch {
- Write-Host "$RED • 强制终止失败: $($process.ProcessName)$NC"
- }
- }
- }
- }
-
- if ($retry -lt $MaxRetries) {
- Write-Host "$YELLOW⏳ [等待]$NC 等待 $WaitSeconds 秒后重新检查..."
- Start-Sleep -Seconds $WaitSeconds
- }
- }
-
- Write-Host "$RED❌ [失败]$NC 经过 $MaxRetries 次尝试仍有Cursor进程在运行"
- return $false
-}
-
-# 🔐 检查文件权限和锁定状态
-function Test-FileAccessibility {
- param(
- [string]$FilePath
- )
-
- Write-Host "$BLUE🔐 [权限检查]$NC 检查文件访问权限: $(Split-Path $FilePath -Leaf)"
-
- if (-not (Test-Path $FilePath)) {
- Write-Host "$RED❌ [错误]$NC 文件不存在"
- return $false
- }
-
- # 检查文件是否被锁定
- try {
- $fileStream = [System.IO.File]::Open($FilePath, 'Open', 'ReadWrite', 'None')
- $fileStream.Close()
- Write-Host "$GREEN✅ [权限]$NC 文件可读写,无锁定"
- return $true
- } catch [System.IO.IOException] {
- Write-Host "$RED❌ [锁定]$NC 文件被其他进程锁定: $($_.Exception.Message)"
- return $false
- } catch [System.UnauthorizedAccessException] {
- Write-Host "$YELLOW⚠️ [权限]$NC 文件权限受限,尝试修改权限..."
-
- # 尝试修改文件权限
- try {
- $file = Get-Item $FilePath
- if ($file.IsReadOnly) {
- $file.IsReadOnly = $false
- Write-Host "$GREEN✅ [修复]$NC 已移除只读属性"
- }
-
- # 再次测试
- $fileStream = [System.IO.File]::Open($FilePath, 'Open', 'ReadWrite', 'None')
- $fileStream.Close()
- Write-Host "$GREEN✅ [权限]$NC 权限修复成功"
- return $true
- } catch {
- Write-Host "$RED❌ [权限]$NC 无法修复权限: $($_.Exception.Message)"
- return $false
- }
- } catch {
- Write-Host "$RED❌ [错误]$NC 未知错误: $($_.Exception.Message)"
+ Write-Error "Failed to modify any JS files"
return $false
}
}
-# 🧹 Cursor 初始化清理功能(从旧版本移植)
-function Invoke-CursorInitialization {
- Write-Host ""
- Write-Host "$GREEN🧹 [初始化]$NC 正在执行 Cursor 初始化清理..."
- $BASE_PATH = "$env:APPDATA\Cursor\User"
-
- $filesToDelete = @(
- (Join-Path -Path $BASE_PATH -ChildPath "globalStorage\state.vscdb"),
- (Join-Path -Path $BASE_PATH -ChildPath "globalStorage\state.vscdb.backup")
- )
-
- $folderToCleanContents = Join-Path -Path $BASE_PATH -ChildPath "History"
- $folderToDeleteCompletely = Join-Path -Path $BASE_PATH -ChildPath "workspaceStorage"
-
- Write-Host "$BLUE🔍 [调试]$NC 基础路径: $BASE_PATH"
-
- # 删除指定文件
- foreach ($file in $filesToDelete) {
- Write-Host "$BLUE🔍 [检查]$NC 检查文件: $file"
- if (Test-Path $file) {
- try {
- Remove-Item -Path $file -Force -ErrorAction Stop
- Write-Host "$GREEN✅ [成功]$NC 已删除文件: $file"
- }
- catch {
- Write-Host "$RED❌ [错误]$NC 删除文件 $file 失败: $($_.Exception.Message)"
- }
- } else {
- Write-Host "$YELLOW⚠️ [跳过]$NC 文件不存在,跳过删除: $file"
- }
- }
-
- # 清空指定文件夹内容
- Write-Host "$BLUE🔍 [检查]$NC 检查待清空文件夹: $folderToCleanContents"
- if (Test-Path $folderToCleanContents) {
- try {
- Get-ChildItem -Path $folderToCleanContents -Recurse | Remove-Item -Force -Recurse -ErrorAction Stop
- Write-Host "$GREEN✅ [成功]$NC 已清空文件夹内容: $folderToCleanContents"
- }
- catch {
- Write-Host "$RED❌ [错误]$NC 清空文件夹 $folderToCleanContents 失败: $($_.Exception.Message)"
- }
- } else {
- Write-Host "$YELLOW⚠️ [跳过]$NC 文件夹不存在,跳过清空: $folderToCleanContents"
- }
-
- # 完全删除指定文件夹
- Write-Host "$BLUE🔍 [检查]$NC 检查待删除文件夹: $folderToDeleteCompletely"
- if (Test-Path $folderToDeleteCompletely) {
- try {
- Remove-Item -Path $folderToDeleteCompletely -Recurse -Force -ErrorAction Stop
- Write-Host "$GREEN✅ [成功]$NC 已删除文件夹: $folderToDeleteCompletely"
- }
- catch {
- Write-Host "$RED❌ [错误]$NC 删除文件夹 $folderToDeleteCompletely 失败: $($_.Exception.Message)"
- }
- } else {
- Write-Host "$YELLOW⚠️ [跳过]$NC 文件夹不存在,跳过删除: $folderToDeleteCompletely"
- }
-
- Write-Host "$GREEN✅ [完成]$NC Cursor 初始化清理完成"
- Write-Host ""
-}
+# ========================================
+# REGISTRY MANAGEMENT
+# ========================================
-# 🔧 修改系统注册表 MachineGuid(从旧版本移植)
+# Update Windows MachineGuid
function Update-MachineGuid {
+ Write-Info "Updating Windows MachineGuid..."
+
try {
- Write-Host "$BLUE🔧 [注册表]$NC 正在修改系统注册表 MachineGuid..."
-
- # 检查注册表路径是否存在,不存在则创建
$registryPath = "HKLM:\SOFTWARE\Microsoft\Cryptography"
+
+ # Check if registry path exists
if (-not (Test-Path $registryPath)) {
- Write-Host "$YELLOW⚠️ [警告]$NC 注册表路径不存在: $registryPath,正在创建..."
+ Write-Warn "Registry path not found, creating: $registryPath"
New-Item -Path $registryPath -Force | Out-Null
- Write-Host "$GREEN✅ [信息]$NC 注册表路径创建成功"
}
-
- # 获取当前的 MachineGuid,如果不存在则使用空字符串作为默认值
+
+ # Get current GUID for backup
$originalGuid = ""
try {
$currentGuid = Get-ItemProperty -Path $registryPath -Name MachineGuid -ErrorAction SilentlyContinue
if ($currentGuid) {
$originalGuid = $currentGuid.MachineGuid
- Write-Host "$GREEN✅ [信息]$NC 当前注册表值:"
- Write-Host "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography"
- Write-Host " MachineGuid REG_SZ $originalGuid"
- } else {
- Write-Host "$YELLOW⚠️ [警告]$NC MachineGuid 值不存在,将创建新值"
+ Write-Info "Current MachineGuid: $originalGuid"
}
} catch {
- Write-Host "$YELLOW⚠️ [警告]$NC 读取注册表失败: $($_.Exception.Message)"
- Write-Host "$YELLOW⚠️ [警告]$NC 将尝试创建新的 MachineGuid 值"
+ Write-Warn "Could not read current MachineGuid"
}
-
- # 创建备份文件(仅当原始值存在时)
- $backupFile = $null
+
+ # Create backup if original exists
if ($originalGuid) {
+ if (-not (Test-Path $BACKUP_DIR)) {
+ New-Item -ItemType Directory -Path $BACKUP_DIR -Force | Out-Null
+ }
+
$backupFile = "$BACKUP_DIR\MachineGuid_$(Get-Date -Format 'yyyyMMdd_HHmmss').reg"
- Write-Host "$BLUE💾 [备份]$NC 正在备份注册表..."
- $backupResult = Start-Process "reg.exe" -ArgumentList "export", "`"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography`"", "`"$backupFile`"" -NoNewWindow -Wait -PassThru
-
- if ($backupResult.ExitCode -eq 0) {
- Write-Host "$GREEN✅ [备份]$NC 注册表项已备份到:$backupFile"
+ $exportResult = Start-Process "reg.exe" -ArgumentList "export", "`"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography`"", "`"$backupFile`"" -NoNewWindow -Wait -PassThru
+
+ if ($exportResult.ExitCode -eq 0) {
+ Write-Info "Registry backed up to: $(Split-Path $backupFile -Leaf)"
} else {
- Write-Host "$YELLOW⚠️ [警告]$NC 备份创建失败,继续执行..."
- $backupFile = $null
+ Write-Warn "Registry backup failed, continuing..."
}
}
-
- # 生成新GUID
+
+ # Generate new GUID
$newGuid = [System.Guid]::NewGuid().ToString()
- Write-Host "$BLUE🔄 [生成]$NC 新的 MachineGuid: $newGuid"
-
- # 更新或创建注册表值
+ Write-Info "New MachineGuid: $newGuid"
+
+ # Update registry
Set-ItemProperty -Path $registryPath -Name MachineGuid -Value $newGuid -Force -ErrorAction Stop
-
- # 验证更新
+
+ # Verify update
$verifyGuid = (Get-ItemProperty -Path $registryPath -Name MachineGuid -ErrorAction Stop).MachineGuid
- if ($verifyGuid -ne $newGuid) {
- throw "注册表验证失败:更新后的值 ($verifyGuid) 与预期值 ($newGuid) 不匹配"
- }
-
- Write-Host "$GREEN✅ [成功]$NC 注册表更新成功:"
- Write-Host "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography"
- Write-Host " MachineGuid REG_SZ $newGuid"
- return $true
- }
- catch {
- Write-Host "$RED❌ [错误]$NC 注册表操作失败:$($_.Exception.Message)"
-
- # 尝试恢复备份(如果存在)
- if ($backupFile -and (Test-Path $backupFile)) {
- Write-Host "$YELLOW🔄 [恢复]$NC 正在从备份恢复..."
- $restoreResult = Start-Process "reg.exe" -ArgumentList "import", "`"$backupFile`"" -NoNewWindow -Wait -PassThru
-
- if ($restoreResult.ExitCode -eq 0) {
- Write-Host "$GREEN✅ [恢复成功]$NC 已还原原始注册表值"
- } else {
- Write-Host "$RED❌ [错误]$NC 恢复失败,请手动导入备份文件:$backupFile"
- }
+ if ($verifyGuid -eq $newGuid) {
+ Write-Info "Registry updated successfully"
+ return $true
} else {
- Write-Host "$YELLOW⚠️ [警告]$NC 未找到备份文件或备份创建失败,无法自动恢复"
+ throw "Registry verification failed"
}
-
+ } catch {
+ Write-Error "Registry operation failed: $($_.Exception.Message)"
return $false
}
}
-# 检查配置文件和环境
-function Test-CursorEnvironment {
- param(
- [string]$Mode = "FULL"
- )
-
- Write-Host ""
- Write-Host "$BLUE🔍 [环境检查]$NC 正在检查Cursor环境..."
+# ========================================
+# MAIN EXECUTION
+# ========================================
- $configPath = "$env:APPDATA\Cursor\User\globalStorage\storage.json"
- $cursorAppData = "$env:APPDATA\Cursor"
- $issues = @()
-
- # 检查配置文件
- if (-not (Test-Path $configPath)) {
- $issues += "配置文件不存在: $configPath"
- } else {
- try {
- $content = Get-Content $configPath -Raw -Encoding UTF8 -ErrorAction Stop
- $config = $content | ConvertFrom-Json -ErrorAction Stop
- Write-Host "$GREEN✅ [检查]$NC 配置文件格式正确"
- } catch {
- $issues += "配置文件格式错误: $($_.Exception.Message)"
- }
- }
-
- # 检查Cursor目录结构
- if (-not (Test-Path $cursorAppData)) {
- $issues += "Cursor应用数据目录不存在: $cursorAppData"
- }
-
- # 检查Cursor安装
- $cursorPaths = @(
- "$env:LOCALAPPDATA\Programs\cursor\Cursor.exe",
- "$env:PROGRAMFILES\Cursor\Cursor.exe",
- "$env:PROGRAMFILES(X86)\Cursor\Cursor.exe"
- )
-
- $cursorFound = $false
- foreach ($path in $cursorPaths) {
- if (Test-Path $path) {
- Write-Host "$GREEN✅ [检查]$NC 找到Cursor安装: $path"
- $cursorFound = $true
- break
- }
- }
-
- if (-not $cursorFound) {
- $issues += "未找到Cursor安装,请确认Cursor已正确安装"
- }
-
- # 返回检查结果
- if ($issues.Count -eq 0) {
- Write-Host "$GREEN✅ [环境检查]$NC 所有检查通过"
- return @{ Success = $true; Issues = @() }
- } else {
- Write-Host "$RED❌ [环境检查]$NC 发现 $($issues.Count) 个问题:"
- foreach ($issue in $issues) {
- Write-Host "$RED • ${issue}$NC"
- }
- return @{ Success = $false; Issues = $issues }
- }
-}
-
-# �🛠️ 修改机器码配置(增强版)
-function Modify-MachineCodeConfig {
- param(
- [string]$Mode = "FULL"
- )
-
- Write-Host ""
- Write-Host "$GREEN🛠️ [配置]$NC 正在修改机器码配置..."
-
- $configPath = "$env:APPDATA\Cursor\User\globalStorage\storage.json"
-
- # 增强的配置文件检查
- if (-not (Test-Path $configPath)) {
- Write-Host "$RED❌ [错误]$NC 配置文件不存在: $configPath"
- Write-Host ""
- Write-Host "$YELLOW💡 [解决方案]$NC 请尝试以下步骤:"
- Write-Host "$BLUE 1️⃣ 手动启动Cursor应用程序$NC"
- Write-Host "$BLUE 2️⃣ 等待Cursor完全加载(约30秒)$NC"
- Write-Host "$BLUE 3️⃣ 关闭Cursor应用程序$NC"
- Write-Host "$BLUE 4️⃣ 重新运行此脚本$NC"
- Write-Host ""
- Write-Host "$YELLOW⚠️ [备选方案]$NC 如果问题持续:"
- Write-Host "$BLUE • 选择脚本的'重置环境+修改机器码'选项$NC"
- Write-Host "$BLUE • 该选项会自动生成配置文件$NC"
- Write-Host ""
-
- # 提供用户选择
- $userChoice = Read-Host "是否现在尝试启动Cursor生成配置文件?(y/n)"
- if ($userChoice -match "^(y|yes)$") {
- Write-Host "$BLUE🚀 [尝试]$NC 正在尝试启动Cursor..."
- return Start-CursorToGenerateConfig
- }
-
- return $false
- }
-
- # 在仅修改机器码模式下也要确保进程完全关闭
- if ($Mode -eq "MODIFY_ONLY") {
- Write-Host "$BLUE🔒 [安全检查]$NC 即使在仅修改模式下,也需要确保Cursor进程完全关闭"
- if (-not (Stop-AllCursorProcesses -MaxRetries 3 -WaitSeconds 3)) {
- Write-Host "$RED❌ [错误]$NC 无法关闭所有Cursor进程,修改可能失败"
- $userChoice = Read-Host "是否强制继续?(y/n)"
- if ($userChoice -notmatch "^(y|yes)$") {
- return $false
- }
- }
- }
-
- # 检查文件权限和锁定状态
- if (-not (Test-FileAccessibility -FilePath $configPath)) {
- Write-Host "$RED❌ [错误]$NC 无法访问配置文件,可能被锁定或权限不足"
- return $false
- }
-
- # 验证配置文件格式并显示结构
- try {
- Write-Host "$BLUE🔍 [验证]$NC 检查配置文件格式..."
- $originalContent = Get-Content $configPath -Raw -Encoding UTF8 -ErrorAction Stop
- $config = $originalContent | ConvertFrom-Json -ErrorAction Stop
- Write-Host "$GREEN✅ [验证]$NC 配置文件格式正确"
-
- # 显示当前配置文件中的相关属性
- Write-Host "$BLUE📋 [当前配置]$NC 检查现有的遥测属性:"
- $telemetryProperties = @('telemetry.machineId', 'telemetry.macMachineId', 'telemetry.devDeviceId', 'telemetry.sqmId')
- foreach ($prop in $telemetryProperties) {
- if ($config.PSObject.Properties[$prop]) {
- $value = $config.$prop
- $displayValue = if ($value.Length -gt 20) { "$($value.Substring(0,20))..." } else { $value }
- Write-Host "$GREEN ✓ ${prop}$NC = $displayValue"
- } else {
- Write-Host "$YELLOW - ${prop}$NC (不存在,将创建)"
- }
- }
- Write-Host ""
- } catch {
- Write-Host "$RED❌ [错误]$NC 配置文件格式错误: $($_.Exception.Message)"
- Write-Host "$YELLOW💡 [建议]$NC 配置文件可能已损坏,建议选择'重置环境+修改机器码'选项"
- return $false
- }
-
- # 实现原子性文件操作和重试机制
- $maxRetries = 3
- $retryCount = 0
-
- while ($retryCount -lt $maxRetries) {
- $retryCount++
- Write-Host ""
- Write-Host "$BLUE🔄 [尝试]$NC 第 $retryCount/$maxRetries 次修改尝试..."
-
- try {
- # 显示操作进度
- Write-Host "$BLUE⏳ [进度]$NC 1/6 - 生成新的设备标识符..."
-
- # 生成新的ID
- $MAC_MACHINE_ID = [System.Guid]::NewGuid().ToString()
- $UUID = [System.Guid]::NewGuid().ToString()
- $prefixBytes = [System.Text.Encoding]::UTF8.GetBytes("auth0|user_")
- $prefixHex = -join ($prefixBytes | ForEach-Object { '{0:x2}' -f $_ })
- $randomBytes = New-Object byte[] 32
- $rng = [System.Security.Cryptography.RNGCryptoServiceProvider]::new()
- $rng.GetBytes($randomBytes)
- $randomPart = [System.BitConverter]::ToString($randomBytes) -replace '-',''
- $rng.Dispose()
- $MACHINE_ID = "${prefixHex}${randomPart}"
- $SQM_ID = "{$([System.Guid]::NewGuid().ToString().ToUpper())}"
-
- Write-Host "$GREEN✅ [进度]$NC 1/6 - 设备标识符生成完成"
-
- Write-Host "$BLUE⏳ [进度]$NC 2/6 - 创建备份目录..."
-
- # 备份原始值(增强版)
- $backupDir = "$env:APPDATA\Cursor\User\globalStorage\backups"
- if (-not (Test-Path $backupDir)) {
- New-Item -ItemType Directory -Path $backupDir -Force -ErrorAction Stop | Out-Null
- }
-
- $backupName = "storage.json.backup_$(Get-Date -Format 'yyyyMMdd_HHmmss')_retry$retryCount"
- $backupPath = "$backupDir\$backupName"
-
- Write-Host "$BLUE⏳ [进度]$NC 3/6 - 备份原始配置..."
- Copy-Item $configPath $backupPath -ErrorAction Stop
-
- # 验证备份是否成功
- if (Test-Path $backupPath) {
- $backupSize = (Get-Item $backupPath).Length
- $originalSize = (Get-Item $configPath).Length
- if ($backupSize -eq $originalSize) {
- Write-Host "$GREEN✅ [进度]$NC 3/6 - 配置备份成功: $backupName"
- } else {
- Write-Host "$YELLOW⚠️ [警告]$NC 备份文件大小不匹配,但继续执行"
- }
- } else {
- throw "备份文件创建失败"
- }
-
- Write-Host "$BLUE⏳ [进度]$NC 4/6 - 读取原始配置到内存..."
-
- # 原子性操作:读取原始内容到内存
- $originalContent = Get-Content $configPath -Raw -Encoding UTF8 -ErrorAction Stop
- $config = $originalContent | ConvertFrom-Json -ErrorAction Stop
-
- Write-Host "$BLUE⏳ [进度]$NC 5/6 - 在内存中更新配置..."
-
- # 更新配置值(安全方式,确保属性存在)
- $propertiesToUpdate = @{
- 'telemetry.machineId' = $MACHINE_ID
- 'telemetry.macMachineId' = $MAC_MACHINE_ID
- 'telemetry.devDeviceId' = $UUID
- 'telemetry.sqmId' = $SQM_ID
- }
-
- foreach ($property in $propertiesToUpdate.GetEnumerator()) {
- $key = $property.Key
- $value = $property.Value
-
- # 使用 Add-Member 或直接赋值的安全方式
- if ($config.PSObject.Properties[$key]) {
- # 属性存在,直接更新
- $config.$key = $value
- Write-Host "$BLUE ✓ 更新属性: ${key}$NC"
- } else {
- # 属性不存在,添加新属性
- $config | Add-Member -MemberType NoteProperty -Name $key -Value $value -Force
- Write-Host "$BLUE + 添加属性: ${key}$NC"
- }
- }
-
- Write-Host "$BLUE⏳ [进度]$NC 6/6 - 原子性写入新配置文件..."
-
- # 原子性操作:删除原文件,写入新文件
- $tempPath = "$configPath.tmp"
- $updatedJson = $config | ConvertTo-Json -Depth 10
-
- # 写入临时文件
- [System.IO.File]::WriteAllText($tempPath, $updatedJson, [System.Text.Encoding]::UTF8)
-
- # 验证临时文件
- $tempContent = Get-Content $tempPath -Raw -Encoding UTF8
- $tempConfig = $tempContent | ConvertFrom-Json
-
- # 验证所有属性是否正确写入
- $tempVerificationPassed = $true
- foreach ($property in $propertiesToUpdate.GetEnumerator()) {
- $key = $property.Key
- $expectedValue = $property.Value
- $actualValue = $tempConfig.$key
-
- if ($actualValue -ne $expectedValue) {
- $tempVerificationPassed = $false
- Write-Host "$RED ✗ 临时文件验证失败: ${key}$NC"
- break
- }
- }
-
- if (-not $tempVerificationPassed) {
- Remove-Item $tempPath -Force -ErrorAction SilentlyContinue
- throw "临时文件验证失败"
- }
-
- # 原子性替换:删除原文件,重命名临时文件
- Remove-Item $configPath -Force
- Move-Item $tempPath $configPath
-
- # 设置文件为只读(可选)
- $file = Get-Item $configPath
- $file.IsReadOnly = $false # 保持可写,便于后续修改
-
- # 最终验证修改结果
- Write-Host "$BLUE🔍 [最终验证]$NC 验证新配置文件..."
-
- $verifyContent = Get-Content $configPath -Raw -Encoding UTF8
- $verifyConfig = $verifyContent | ConvertFrom-Json
-
- $verificationPassed = $true
- $verificationResults = @()
-
- # 安全验证每个属性
- foreach ($property in $propertiesToUpdate.GetEnumerator()) {
- $key = $property.Key
- $expectedValue = $property.Value
- $actualValue = $verifyConfig.$key
-
- if ($actualValue -eq $expectedValue) {
- $verificationResults += "✓ ${key}: 验证通过"
- } else {
- $verificationResults += "✗ ${key}: 验证失败 (期望: ${expectedValue}, 实际: ${actualValue})"
- $verificationPassed = $false
- }
- }
-
- # 显示验证结果
- Write-Host "$BLUE📋 [验证详情]$NC"
- foreach ($result in $verificationResults) {
- Write-Host " $result"
- }
-
- if ($verificationPassed) {
- Write-Host "$GREEN✅ [成功]$NC 第 $retryCount 次尝试修改成功!"
- Write-Host ""
- Write-Host "$GREEN🎉 [完成]$NC 机器码配置修改完成!"
- Write-Host "$BLUE📋 [详情]$NC 已更新以下标识符:"
- Write-Host " 🔹 machineId: $MACHINE_ID"
- Write-Host " 🔹 macMachineId: $MAC_MACHINE_ID"
- Write-Host " 🔹 devDeviceId: $UUID"
- Write-Host " 🔹 sqmId: $SQM_ID"
- Write-Host ""
- Write-Host "$GREEN💾 [备份]$NC 原配置已备份至: $backupName"
-
- # 🔒 添加配置文件保护机制
- Write-Host "$BLUE🔒 [保护]$NC 正在设置配置文件保护..."
- try {
- $configFile = Get-Item $configPath
- $configFile.IsReadOnly = $true
- Write-Host "$GREEN✅ [保护]$NC 配置文件已设置为只读,防止Cursor覆盖修改"
- Write-Host "$BLUE💡 [提示]$NC 文件路径: $configPath"
- } catch {
- Write-Host "$YELLOW⚠️ [保护]$NC 设置只读属性失败: $($_.Exception.Message)"
- Write-Host "$BLUE💡 [建议]$NC 可手动右键文件 → 属性 → 勾选'只读'"
- }
- Write-Host "$BLUE 🔒 [安全]$NC 建议重启Cursor以确保配置生效"
- return $true
- } else {
- Write-Host "$RED❌ [失败]$NC 第 $retryCount 次尝试验证失败"
- if ($retryCount -lt $maxRetries) {
- Write-Host "$BLUE🔄 [恢复]$NC 恢复备份,准备重试..."
- Copy-Item $backupPath $configPath -Force
- Start-Sleep -Seconds 2
- continue # 继续下一次重试
- } else {
- Write-Host "$RED❌ [最终失败]$NC 所有重试都失败,恢复原始配置"
- Copy-Item $backupPath $configPath -Force
- return $false
- }
- }
-
- } catch {
- Write-Host "$RED❌ [异常]$NC 第 $retryCount 次尝试出现异常: $($_.Exception.Message)"
- Write-Host "$BLUE💡 [调试信息]$NC 错误类型: $($_.Exception.GetType().FullName)"
-
- # 清理临时文件
- if (Test-Path "$configPath.tmp") {
- Remove-Item "$configPath.tmp" -Force -ErrorAction SilentlyContinue
- }
-
- if ($retryCount -lt $maxRetries) {
- Write-Host "$BLUE🔄 [恢复]$NC 恢复备份,准备重试..."
- if (Test-Path $backupPath) {
- Copy-Item $backupPath $configPath -Force
- }
- Start-Sleep -Seconds 3
- continue # 继续下一次重试
- } else {
- Write-Host "$RED❌ [最终失败]$NC 所有重试都失败"
- # 尝试恢复备份
- if (Test-Path $backupPath) {
- Write-Host "$BLUE🔄 [恢复]$NC 正在恢复备份配置..."
- try {
- Copy-Item $backupPath $configPath -Force
- Write-Host "$GREEN✅ [恢复]$NC 已恢复原始配置"
- } catch {
- Write-Host "$RED❌ [错误]$NC 恢复备份失败: $($_.Exception.Message)"
- }
- }
- return $false
- }
- }
- }
-
- # 如果到达这里,说明所有重试都失败了
- Write-Host "$RED❌ [最终失败]$NC 经过 $maxRetries 次尝试仍无法完成修改"
- return $false
-
-}
-
-# 启动Cursor生成配置文件
-function Start-CursorToGenerateConfig {
- Write-Host "$BLUE🚀 [启动]$NC 正在尝试启动Cursor生成配置文件..."
-
- # 查找Cursor可执行文件
- $cursorPaths = @(
- "$env:LOCALAPPDATA\Programs\cursor\Cursor.exe",
- "$env:PROGRAMFILES\Cursor\Cursor.exe",
- "$env:PROGRAMFILES(X86)\Cursor\Cursor.exe"
- )
-
- $cursorPath = $null
- foreach ($path in $cursorPaths) {
- if (Test-Path $path) {
- $cursorPath = $path
- break
- }
- }
-
- if (-not $cursorPath) {
- Write-Host "$RED❌ [错误]$NC 未找到Cursor安装,请确认Cursor已正确安装"
+# Check prerequisites
+function Test-Prerequisites {
+ Write-Info "Checking prerequisites..."
+
+ # Check if running as administrator
+ $currentPrincipal = New-Object Security.Principal.WindowsPrincipal([Security.Principal.WindowsIdentity]::GetCurrent())
+ if (-not $currentPrincipal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
+ Write-Error "This script requires administrator privileges"
+ Write-Info "Please run PowerShell as Administrator and try again"
return $false
}
-
- try {
- Write-Host "$BLUE📍 [路径]$NC 使用Cursor路径: $cursorPath"
-
- # 启动Cursor
- $process = Start-Process -FilePath $cursorPath -PassThru -WindowStyle Normal
- Write-Host "$GREEN🚀 [启动]$NC Cursor已启动,PID: $($process.Id)"
-
- Write-Host "$YELLOW⏳ [等待]$NC 请等待Cursor完全加载(约30秒)..."
- Write-Host "$BLUE💡 [提示]$NC 您可以在Cursor完全加载后手动关闭它"
-
- # 等待配置文件生成
- $configPath = "$env:APPDATA\Cursor\User\globalStorage\storage.json"
- $maxWait = 60
- $waited = 0
-
- while (-not (Test-Path $configPath) -and $waited -lt $maxWait) {
- Start-Sleep -Seconds 2
- $waited += 2
- if ($waited % 10 -eq 0) {
- Write-Host "$YELLOW⏳ [等待]$NC 等待配置文件生成... ($waited/$maxWait 秒)"
- }
- }
-
- if (Test-Path $configPath) {
- Write-Host "$GREEN✅ [成功]$NC 配置文件已生成!"
- Write-Host "$BLUE💡 [提示]$NC 现在可以关闭Cursor并重新运行脚本"
- return $true
- } else {
- Write-Host "$YELLOW⚠️ [超时]$NC 配置文件未在预期时间内生成"
- Write-Host "$BLUE💡 [建议]$NC 请手动操作Cursor(如创建新文件)以触发配置生成"
- return $false
- }
-
- } catch {
- Write-Host "$RED❌ [错误]$NC 启动Cursor失败: $($_.Exception.Message)"
+
+ # Check if Cursor is installed
+ if (-not (Find-CursorInstallation)) {
+ Write-Error "Cursor installation not found"
+ Write-Info "Please install Cursor first: https://cursor.sh/"
return $false
}
+
+ Write-Info "Prerequisites check passed"
+ return $true
}
-# 检查管理员权限
-function Test-Administrator {
- $user = [Security.Principal.WindowsIdentity]::GetCurrent()
- $principal = New-Object Security.Principal.WindowsPrincipal($user)
- return $principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
-}
-
-if (-not (Test-Administrator)) {
- Write-Host "$RED[错误]$NC 请以管理员身份运行此脚本"
- Write-Host "请右键点击脚本,选择'以管理员身份运行'"
- Read-Host "按回车键退出"
- exit 1
-}
-
-# 显示 Logo
-Clear-Host
-Write-Host @"
-
- ██████╗██╗ ██╗██████╗ ███████╗ ██████╗ ██████╗
- ██╔════╝██║ ██║██╔══██╗██╔════╝██╔═══██╗██╔══██╗
- ██║ ██║ ██║██████╔╝███████╗██║ ██║██████╔╝
- ██║ ██║ ██║██╔══██╗╚════██║██║ ██║██╔══██╗
- ╚██████╗╚██████╔╝██║ ██║███████║╚██████╔╝██║ ██║
- ╚═════╝ ╚═════╝ ╚═╝ ╚═╝╚══════╝ ╚═════╝ ╚═╝ ╚═╝
-
-"@
-Write-Host "$BLUE================================$NC"
-Write-Host "$GREEN🚀 Cursor 防掉试用Pro删除工具 $NC"
-Write-Host "$YELLOW📱 关注公众号【煎饼果子卷AI】 $NC"
-Write-Host "$YELLOW🤝 一起交流更多Cursor技巧和AI知识(脚本免费、关注公众号加群有更多技巧和大佬) $NC"
-Write-Host "$YELLOW💡 [重要提示] 本工具免费,如果对您有帮助,请关注公众号【煎饼果子卷AI】 $NC"
-Write-Host ""
-Write-Host "$YELLOW💰 [小小广告] 出售CursorPro教育号一年质保三个月,有需要找我(86),WeChat:JavaRookie666 $NC"
-Write-Host "$BLUE================================$NC"
-
-# 🎯 用户选择菜单
-Write-Host ""
-Write-Host "$GREEN🎯 [选择模式]$NC 请选择您要执行的操作:"
-Write-Host ""
-Write-Host "$BLUE 1️⃣ 仅修改机器码$NC"
-Write-Host "$YELLOW • 执行机器码修改功能$NC"
-Write-Host "$YELLOW • 执行注入破解JS代码到核心文件$NC"
-Write-Host "$YELLOW • 跳过文件夹删除/环境重置步骤$NC"
-Write-Host "$YELLOW • 保留现有Cursor配置和数据$NC"
-Write-Host ""
-Write-Host "$BLUE 2️⃣ 重置环境+修改机器码$NC"
-Write-Host "$RED • 执行完全环境重置(删除Cursor文件夹)$NC"
-Write-Host "$RED • ⚠️ 配置将丢失,请注意备份$NC"
-Write-Host "$YELLOW • 按照机器代码修改$NC"
-Write-Host "$YELLOW • 执行注入破解JS代码到核心文件$NC"
-Write-Host "$YELLOW • 这相当于当前的完整脚本行为$NC"
-Write-Host ""
-
-# 获取用户选择
-do {
- $userChoice = Read-Host "请输入选择 (1 或 2)"
- if ($userChoice -eq "1") {
- Write-Host "$GREEN✅ [选择]$NC 您选择了:仅修改机器码"
- $executeMode = "MODIFY_ONLY"
- break
- } elseif ($userChoice -eq "2") {
- Write-Host "$GREEN✅ [选择]$NC 您选择了:重置环境+修改机器码"
- Write-Host "$RED⚠️ [重要警告]$NC 此操作将删除所有Cursor配置文件!"
- $confirmReset = Read-Host "确认执行完全重置?(输入 yes 确认,其他任意键取消)"
- if ($confirmReset -eq "yes") {
- $executeMode = "RESET_AND_MODIFY"
- break
- } else {
- Write-Host "$YELLOW👋 [取消]$NC 用户取消重置操作"
- continue
- }
- } else {
- Write-Host "$RED❌ [错误]$NC 无效选择,请输入 1 或 2"
- }
-} while ($true)
-
-Write-Host ""
-
-# 📋 根据选择显示执行流程说明
-if ($executeMode -eq "MODIFY_ONLY") {
- Write-Host "$GREEN📋 [执行流程]$NC 仅修改机器码模式将按以下步骤执行:"
- Write-Host "$BLUE 1️⃣ 检测Cursor配置文件$NC"
- Write-Host "$BLUE 2️⃣ 备份现有配置文件$NC"
- Write-Host "$BLUE 3️⃣ 修改机器码配置$NC"
- Write-Host "$BLUE 4️⃣ 显示操作完成信息$NC"
+# Show menu
+function Show-Menu {
Write-Host ""
- Write-Host "$YELLOW⚠️ [注意事项]$NC"
- Write-Host "$YELLOW • 不会删除任何文件夹或重置环境$NC"
- Write-Host "$YELLOW • 保留所有现有配置和数据$NC"
- Write-Host "$YELLOW • 原配置文件会自动备份$NC"
-} else {
- Write-Host "$GREEN📋 [执行流程]$NC 重置环境+修改机器码模式将按以下步骤执行:"
- Write-Host "$BLUE 1️⃣ 检测并关闭Cursor进程$NC"
- Write-Host "$BLUE 2️⃣ 保存Cursor程序路径信息$NC"
- Write-Host "$BLUE 3️⃣ 删除指定的Cursor试用相关文件夹$NC"
- Write-Host "$BLUE 📁 C:\Users\Administrator\.cursor$NC"
- Write-Host "$BLUE 📁 C:\Users\Administrator\AppData\Roaming\Cursor$NC"
- Write-Host "$BLUE 📁 C:\Users\%USERNAME%\.cursor$NC"
- Write-Host "$BLUE 📁 C:\Users\%USERNAME%\AppData\Roaming\Cursor$NC"
- Write-Host "$BLUE 3.5️⃣ 预创建必要目录结构,避免权限问题$NC"
- Write-Host "$BLUE 4️⃣ 重新启动Cursor让其生成新的配置文件$NC"
- Write-Host "$BLUE 5️⃣ 等待配置文件生成完成(最多45秒)$NC"
- Write-Host "$BLUE 6️⃣ 关闭Cursor进程$NC"
- Write-Host "$BLUE 7️⃣ 修改新生成的机器码配置文件$NC"
- Write-Host "$BLUE 8️⃣ 显示操作完成统计信息$NC"
+ Write-Host "🎯 Please select an option:"
+ Write-Host ""
+ Write-Host " 1️⃣ 🔥 Full reset (Folders + Config + JS + Registry) [Recommended]"
+ Write-Host " 2️⃣ 🗂️ Reset trial folders only"
+ Write-Host " 3️⃣ ⚙️ Modify machine code configuration only"
+ Write-Host " 4️⃣ 📝 Modify JS files only"
+ Write-Host " 5️⃣ 🔧 Update registry only"
+ Write-Host " 6️⃣ 🚪 Exit"
Write-Host ""
- Write-Host "$YELLOW⚠️ [注意事项]$NC"
- Write-Host "$YELLOW • 脚本执行过程中请勿手动操作Cursor$NC"
- Write-Host "$YELLOW • 建议在执行前关闭所有Cursor窗口$NC"
- Write-Host "$YELLOW • 执行完成后需要重新启动Cursor$NC"
- Write-Host "$YELLOW • 原配置文件会自动备份到backups文件夹$NC"
-}
-Write-Host ""
-
-# 🤔 用户确认
-Write-Host "$GREEN🤔 [确认]$NC 请确认您已了解上述执行流程"
-$confirmation = Read-Host "是否继续执行?(输入 y 或 yes 继续,其他任意键退出)"
-if ($confirmation -notmatch "^(y|yes)$") {
- Write-Host "$YELLOW👋 [退出]$NC 用户取消执行,脚本退出"
- Read-Host "按回车键退出"
- exit 0
-}
-Write-Host "$GREEN✅ [确认]$NC 用户确认继续执行"
-Write-Host ""
-
-# 获取并显示 Cursor 版本
-function Get-CursorVersion {
- try {
- # 主要检测路径
- $packagePath = "$env:LOCALAPPDATA\\Programs\\cursor\\resources\\app\\package.json"
-
- if (Test-Path $packagePath) {
- $packageJson = Get-Content $packagePath -Raw | ConvertFrom-Json
- if ($packageJson.version) {
- Write-Host "$GREEN[信息]$NC 当前安装的 Cursor 版本: v$($packageJson.version)"
- return $packageJson.version
- }
- }
-
- # 备用路径检测
- $altPath = "$env:LOCALAPPDATA\\cursor\\resources\\app\\package.json"
- if (Test-Path $altPath) {
- $packageJson = Get-Content $altPath -Raw | ConvertFrom-Json
- if ($packageJson.version) {
- Write-Host "$GREEN[信息]$NC 当前安装的 Cursor 版本: v$($packageJson.version)"
- return $packageJson.version
- }
- }
-
- Write-Host "$YELLOW[警告]$NC 无法检测到 Cursor 版本"
- Write-Host "$YELLOW[提示]$NC 请确保 Cursor 已正确安装"
- return $null
- }
- catch {
- Write-Host "$RED[错误]$NC 获取 Cursor 版本失败: $_"
- return $null
- }
-}
-
-# 获取并显示版本信息
-$cursorVersion = Get-CursorVersion
-Write-Host ""
-
-Write-Host "$YELLOW💡 [重要提示]$NC 最新的 1.0.x 版本已支持"
-
-Write-Host ""
-
-# 🔍 检查并关闭 Cursor 进程
-Write-Host "$GREEN🔍 [检查]$NC 正在检查 Cursor 进程..."
-
-function Get-ProcessDetails {
- param($processName)
- Write-Host "$BLUE🔍 [调试]$NC 正在获取 $processName 进程详细信息:"
- Get-WmiObject Win32_Process -Filter "name='$processName'" |
- Select-Object ProcessId, ExecutablePath, CommandLine |
- Format-List
-}
-
-# 定义最大重试次数和等待时间
-$MAX_RETRIES = 5
-$WAIT_TIME = 1
-
-# 🔄 处理进程关闭并保存进程信息
-function Close-CursorProcessAndSaveInfo {
- param($processName)
-
- $global:CursorProcessInfo = $null
-
- $processes = Get-Process -Name $processName -ErrorAction SilentlyContinue
- if ($processes) {
- Write-Host "$YELLOW⚠️ [警告]$NC 发现 $processName 正在运行"
-
- # 💾 保存进程信息用于后续重启 - 修复:确保获取单个进程路径
- $firstProcess = if ($processes -is [array]) { $processes[0] } else { $processes }
- $processPath = $firstProcess.Path
-
- # 确保路径是字符串而不是数组
- if ($processPath -is [array]) {
- $processPath = $processPath[0]
- }
-
- $global:CursorProcessInfo = @{
- ProcessName = $firstProcess.ProcessName
- Path = $processPath
- StartTime = $firstProcess.StartTime
- }
- Write-Host "$GREEN💾 [保存]$NC 已保存进程信息: $($global:CursorProcessInfo.Path)"
-
- Get-ProcessDetails $processName
-
- Write-Host "$YELLOW🔄 [操作]$NC 尝试关闭 $processName..."
- Stop-Process -Name $processName -Force
-
- $retryCount = 0
- while ($retryCount -lt $MAX_RETRIES) {
- $process = Get-Process -Name $processName -ErrorAction SilentlyContinue
- if (-not $process) { break }
-
- $retryCount++
- if ($retryCount -ge $MAX_RETRIES) {
- Write-Host "$RED❌ [错误]$NC 在 $MAX_RETRIES 次尝试后仍无法关闭 $processName"
- Get-ProcessDetails $processName
- Write-Host "$RED💥 [错误]$NC 请手动关闭进程后重试"
- Read-Host "按回车键退出"
- exit 1
- }
- Write-Host "$YELLOW⏳ [等待]$NC 等待进程关闭,尝试 $retryCount/$MAX_RETRIES..."
- Start-Sleep -Seconds $WAIT_TIME
- }
- Write-Host "$GREEN✅ [成功]$NC $processName 已成功关闭"
- } else {
- Write-Host "$BLUE💡 [提示]$NC 未发现 $processName 进程运行"
- # 尝试找到Cursor的安装路径
- $cursorPaths = @(
- "$env:LOCALAPPDATA\Programs\cursor\Cursor.exe",
- "$env:PROGRAMFILES\Cursor\Cursor.exe",
- "$env:PROGRAMFILES(X86)\Cursor\Cursor.exe"
- )
-
- foreach ($path in $cursorPaths) {
- if (Test-Path $path) {
- $global:CursorProcessInfo = @{
- ProcessName = "Cursor"
- Path = $path
- StartTime = $null
- }
- Write-Host "$GREEN💾 [发现]$NC 找到Cursor安装路径: $path"
- break
- }
- }
-
- if (-not $global:CursorProcessInfo) {
- Write-Host "$YELLOW⚠️ [警告]$NC 未找到Cursor安装路径,将使用默认路径"
- $global:CursorProcessInfo = @{
- ProcessName = "Cursor"
- Path = "$env:LOCALAPPDATA\Programs\cursor\Cursor.exe"
- StartTime = $null
- }
- }
- }
-}
-
-# �️ 确保备份目录存在
-if (-not (Test-Path $BACKUP_DIR)) {
- try {
- New-Item -ItemType Directory -Path $BACKUP_DIR -Force | Out-Null
- Write-Host "$GREEN✅ [备份目录]$NC 备份目录创建成功: $BACKUP_DIR"
- } catch {
- Write-Host "$YELLOW⚠️ [警告]$NC 备份目录创建失败: $($_.Exception.Message)"
- }
}
-# �🚀 根据用户选择执行相应功能
-if ($executeMode -eq "MODIFY_ONLY") {
- Write-Host "$GREEN🚀 [开始]$NC 开始执行仅修改机器码功能..."
-
- # 先进行环境检查
- $envCheck = Test-CursorEnvironment -Mode "MODIFY_ONLY"
- if (-not $envCheck.Success) {
- Write-Host ""
- Write-Host "$RED❌ [环境检查失败]$NC 无法继续执行,发现以下问题:"
- foreach ($issue in $envCheck.Issues) {
- Write-Host "$RED • ${issue}$NC"
- }
- Write-Host ""
- Write-Host "$YELLOW💡 [建议]$NC 请选择以下操作:"
- Write-Host "$BLUE 1️⃣ 选择'重置环境+修改机器码'选项(推荐)$NC"
- Write-Host "$BLUE 2️⃣ 手动启动Cursor一次,然后重新运行脚本$NC"
- Write-Host "$BLUE 3️⃣ 检查Cursor是否正确安装$NC"
- Write-Host ""
- Read-Host "按回车键退出"
- exit 1
- }
-
- # 执行机器码修改
- $configSuccess = Modify-MachineCodeConfig -Mode "MODIFY_ONLY"
-
- if ($configSuccess) {
- Write-Host ""
- Write-Host "$GREEN🎉 [配置文件]$NC 机器码配置文件修改完成!"
-
- # 添加注册表修改
- Write-Host "$BLUE🔧 [注册表]$NC 正在修改系统注册表..."
- $registrySuccess = Update-MachineGuid
-
- # 🔧 新增:JavaScript注入功能(设备识别绕过增强)
- Write-Host ""
- Write-Host "$BLUE🔧 [设备识别绕过]$NC 正在执行JavaScript注入功能..."
- Write-Host "$BLUE💡 [说明]$NC 此功能将直接修改Cursor内核JS文件,实现更深层的设备识别绕过"
- $jsSuccess = Modify-CursorJSFiles
-
- if ($registrySuccess) {
- Write-Host "$GREEN✅ [注册表]$NC 系统注册表修改成功"
-
- if ($jsSuccess) {
- Write-Host "$GREEN✅ [JavaScript注入]$NC JavaScript注入功能执行成功"
- Write-Host ""
- Write-Host "$GREEN🎉 [完成]$NC 所有机器码修改完成(增强版)!"
- Write-Host "$BLUE📋 [详情]$NC 已完成以下修改:"
- Write-Host "$GREEN ✓ Cursor 配置文件 (storage.json)$NC"
- Write-Host "$GREEN ✓ 系统注册表 (MachineGuid)$NC"
- Write-Host "$GREEN ✓ JavaScript内核注入(设备识别绕过)$NC"
- } else {
- Write-Host "$YELLOW⚠️ [JavaScript注入]$NC JavaScript注入功能执行失败,但其他功能成功"
- Write-Host ""
- Write-Host "$GREEN🎉 [完成]$NC 所有机器码修改完成!"
- Write-Host "$BLUE📋 [详情]$NC 已完成以下修改:"
- Write-Host "$GREEN ✓ Cursor 配置文件 (storage.json)$NC"
- Write-Host "$GREEN ✓ 系统注册表 (MachineGuid)$NC"
- Write-Host "$YELLOW ⚠ JavaScript内核注入(部分失败)$NC"
- }
-
- # 🔒 添加配置文件保护机制
- Write-Host "$BLUE🔒 [保护]$NC 正在设置配置文件保护..."
- try {
- $configPath = "$env:APPDATA\Cursor\User\globalStorage\storage.json"
- $configFile = Get-Item $configPath
- $configFile.IsReadOnly = $true
- Write-Host "$GREEN✅ [保护]$NC 配置文件已设置为只读,防止Cursor覆盖修改"
- Write-Host "$BLUE💡 [提示]$NC 文件路径: $configPath"
- } catch {
- Write-Host "$YELLOW⚠️ [保护]$NC 设置只读属性失败: $($_.Exception.Message)"
- Write-Host "$BLUE💡 [建议]$NC 可手动右键文件 → 属性 → 勾选'只读'"
- }
- } else {
- Write-Host "$YELLOW⚠️ [注册表]$NC 注册表修改失败,但配置文件修改成功"
-
- if ($jsSuccess) {
- Write-Host "$GREEN✅ [JavaScript注入]$NC JavaScript注入功能执行成功"
- Write-Host ""
- Write-Host "$YELLOW🎉 [部分完成]$NC 配置文件和JavaScript注入完成,注册表修改失败"
- Write-Host "$BLUE💡 [建议]$NC 可能需要管理员权限来修改注册表"
- Write-Host "$BLUE📋 [详情]$NC 已完成以下修改:"
- Write-Host "$GREEN ✓ Cursor 配置文件 (storage.json)$NC"
- Write-Host "$YELLOW ⚠ 系统注册表 (MachineGuid) - 失败$NC"
- Write-Host "$GREEN ✓ JavaScript内核注入(设备识别绕过)$NC"
- } else {
- Write-Host "$YELLOW⚠️ [JavaScript注入]$NC JavaScript注入功能执行失败"
- Write-Host ""
- Write-Host "$YELLOW🎉 [部分完成]$NC 配置文件修改完成,注册表和JavaScript注入失败"
- Write-Host "$BLUE💡 [建议]$NC 可能需要管理员权限来修改注册表"
- }
-
- # 🔒 即使注册表修改失败,也要保护配置文件
- Write-Host "$BLUE🔒 [保护]$NC 正在设置配置文件保护..."
- try {
- $configPath = "$env:APPDATA\Cursor\User\globalStorage\storage.json"
- $configFile = Get-Item $configPath
- $configFile.IsReadOnly = $true
- Write-Host "$GREEN✅ [保护]$NC 配置文件已设置为只读,防止Cursor覆盖修改"
- Write-Host "$BLUE💡 [提示]$NC 文件路径: $configPath"
- } catch {
- Write-Host "$YELLOW⚠️ [保护]$NC 设置只读属性失败: $($_.Exception.Message)"
- Write-Host "$BLUE💡 [建议]$NC 可手动右键文件 → 属性 → 勾选'只读'"
- }
- }
-
- Write-Host "$BLUE💡 [提示]$NC 现在可以启动Cursor使用新的机器码配置"
- } else {
- Write-Host ""
- Write-Host "$RED❌ [失败]$NC 机器码修改失败!"
- Write-Host "$YELLOW💡 [建议]$NC 请尝试'重置环境+修改机器码'选项"
- }
-} else {
- # 完整的重置环境+修改机器码流程
- Write-Host "$GREEN🚀 [开始]$NC 开始执行重置环境+修改机器码功能..."
-
- # 🚀 关闭所有 Cursor 进程并保存信息
- Close-CursorProcessAndSaveInfo "Cursor"
- if (-not $global:CursorProcessInfo) {
- Close-CursorProcessAndSaveInfo "cursor"
- }
-
- # 🚨 重要警告提示
+# Main function
+function Main {
Write-Host ""
- Write-Host "$RED🚨 [重要警告]$NC ============================================"
- Write-Host "$YELLOW⚠️ [风控提醒]$NC Cursor 风控机制非常严格!"
- Write-Host "$YELLOW⚠️ [必须删除]$NC 必须完全删除指定文件夹,不能有任何残留设置"
- Write-Host "$YELLOW⚠️ [防掉试用]$NC 只有彻底清理才能有效防止掉试用Pro状态"
- Write-Host "$RED🚨 [重要警告]$NC ============================================"
+ Write-Host "██████╗██╗ ██╗██████╗ ███████╗ ██████╗ ██████╗ "
+ Write-Host "██╔════╝██║ ██║██╔══██╗██╔════╝██╔═══██╗██╔══██╗"
+ Write-Host "██║ ██║ ██║██████╔╝███████╗██║ ██║██████╔╝"
+ Write-Host "██║ ██║ ██║██╔══██╗╚════██║██║ ██║██╔══██╗"
+ Write-Host "╚██████╗╚██████╔╝██║ ██║███████║╚██████╔╝██║ ██║"
+ Write-Host " ╚═════╝ ╚═════╝ ╚═╝ ╚═╝╚══════╝ ╚═════╝ ╚═╝ ╚═╝"
+ Write-Host ""
+ Write-Host "========================================="
+ Write-Host " 🪟 $SCRIPT_NAME"
+ Write-Host "========================================="
Write-Host ""
-
- # 🎯 执行 Cursor 防掉试用Pro删除文件夹功能
- Write-Host "$GREEN🚀 [开始]$NC 开始执行核心功能..."
- Remove-CursorTrialFolders
-
-
-
- # 🔄 重启Cursor让其重新生成配置文件
- Restart-CursorAndWait
-
- # 🛠️ 修改机器码配置
- $configSuccess = Modify-MachineCodeConfig
- # 🧹 执行 Cursor 初始化清理
- Invoke-CursorInitialization
-
- if ($configSuccess) {
- Write-Host ""
- Write-Host "$GREEN🎉 [配置文件]$NC 机器码配置文件修改完成!"
-
- # 添加注册表修改
- Write-Host "$BLUE🔧 [注册表]$NC 正在修改系统注册表..."
- $registrySuccess = Update-MachineGuid
-
- # 🔧 新增:JavaScript注入功能(设备识别绕过增强)
- Write-Host ""
- Write-Host "$BLUE🔧 [设备识别绕过]$NC 正在执行JavaScript注入功能..."
- Write-Host "$BLUE💡 [说明]$NC 此功能将直接修改Cursor内核JS文件,实现更深层的设备识别绕过"
- $jsSuccess = Modify-CursorJSFiles
-
- if ($registrySuccess) {
- Write-Host "$GREEN✅ [注册表]$NC 系统注册表修改成功"
-
- if ($jsSuccess) {
- Write-Host "$GREEN✅ [JavaScript注入]$NC JavaScript注入功能执行成功"
- Write-Host ""
- Write-Host "$GREEN🎉 [完成]$NC 所有操作完成(增强版)!"
- Write-Host "$BLUE📋 [详情]$NC 已完成以下操作:"
- Write-Host "$GREEN ✓ 删除 Cursor 试用相关文件夹$NC"
- Write-Host "$GREEN ✓ Cursor 初始化清理$NC"
- Write-Host "$GREEN ✓ 重新生成配置文件$NC"
- Write-Host "$GREEN ✓ 修改机器码配置$NC"
- Write-Host "$GREEN ✓ 修改系统注册表$NC"
- Write-Host "$GREEN ✓ JavaScript内核注入(设备识别绕过)$NC"
- } else {
- Write-Host "$YELLOW⚠️ [JavaScript注入]$NC JavaScript注入功能执行失败,但其他功能成功"
- Write-Host ""
- Write-Host "$GREEN🎉 [完成]$NC 所有操作完成!"
- Write-Host "$BLUE📋 [详情]$NC 已完成以下操作:"
- Write-Host "$GREEN ✓ 删除 Cursor 试用相关文件夹$NC"
- Write-Host "$GREEN ✓ Cursor 初始化清理$NC"
- Write-Host "$GREEN ✓ 重新生成配置文件$NC"
- Write-Host "$GREEN ✓ 修改机器码配置$NC"
- Write-Host "$GREEN ✓ 修改系统注册表$NC"
- Write-Host "$YELLOW ⚠ JavaScript内核注入(部分失败)$NC"
- }
-
- # 🔒 添加配置文件保护机制
- Write-Host "$BLUE🔒 [保护]$NC 正在设置配置文件保护..."
- try {
- $configPath = "$env:APPDATA\Cursor\User\globalStorage\storage.json"
- $configFile = Get-Item $configPath
- $configFile.IsReadOnly = $true
- Write-Host "$GREEN✅ [保护]$NC 配置文件已设置为只读,防止Cursor覆盖修改"
- Write-Host "$BLUE💡 [提示]$NC 文件路径: $configPath"
- } catch {
- Write-Host "$YELLOW⚠️ [保护]$NC 设置只读属性失败: $($_.Exception.Message)"
- Write-Host "$BLUE💡 [建议]$NC 可手动右键文件 → 属性 → 勾选'只读'"
- }
- } else {
- Write-Host "$YELLOW⚠️ [注册表]$NC 注册表修改失败,但其他操作成功"
-
- if ($jsSuccess) {
- Write-Host "$GREEN✅ [JavaScript注入]$NC JavaScript注入功能执行成功"
- Write-Host ""
- Write-Host "$YELLOW🎉 [部分完成]$NC 大部分操作完成,注册表修改失败"
- Write-Host "$BLUE💡 [建议]$NC 可能需要管理员权限来修改注册表"
- Write-Host "$BLUE📋 [详情]$NC 已完成以下操作:"
- Write-Host "$GREEN ✓ 删除 Cursor 试用相关文件夹$NC"
- Write-Host "$GREEN ✓ Cursor 初始化清理$NC"
- Write-Host "$GREEN ✓ 重新生成配置文件$NC"
- Write-Host "$GREEN ✓ 修改机器码配置$NC"
- Write-Host "$YELLOW ⚠ 修改系统注册表 - 失败$NC"
- Write-Host "$GREEN ✓ JavaScript内核注入(设备识别绕过)$NC"
- } else {
- Write-Host "$YELLOW⚠️ [JavaScript注入]$NC JavaScript注入功能执行失败"
+ if (-not (Test-Prerequisites)) {
+ exit 1
+ }
+
+ while ($true) {
+ Show-Menu
+ $choice = Read-Host "Enter your choice (1-6)"
+
+ switch ($choice) {
+ 1 {
+ Write-Info "Starting full reset..."
+
+ $success = $true
+
+ if (-not (Stop-AllCursorProcesses)) {
+ $success = $false
+ }
+
+ if ($success -and -not (Remove-CursorTrialFolders)) {
+ Write-Warn "Folder removal had issues, but continuing..."
+ }
+
+ if ($success -and -not (Modify-MachineCodeConfig)) {
+ Write-Warn "Config modification failed, but continuing..."
+ }
+
+ if ($success -and -not (Modify-CursorJSFiles)) {
+ Write-Warn "JS modification failed, but continuing..."
+ }
+
+ if ($success -and -not (Update-MachineGuid)) {
+ Write-Warn "Registry update failed, but continuing..."
+ }
+
Write-Host ""
- Write-Host "$YELLOW🎉 [部分完成]$NC 大部分操作完成,注册表和JavaScript注入失败"
- Write-Host "$BLUE💡 [建议]$NC 可能需要管理员权限来修改注册表"
- }
-
- # 🔒 即使注册表修改失败,也要保护配置文件
- Write-Host "$BLUE🔒 [保护]$NC 正在设置配置文件保护..."
- try {
- $configPath = "$env:APPDATA\Cursor\User\globalStorage\storage.json"
- $configFile = Get-Item $configPath
- $configFile.IsReadOnly = $true
- Write-Host "$GREEN✅ [保护]$NC 配置文件已设置为只读,防止Cursor覆盖修改"
- Write-Host "$BLUE💡 [提示]$NC 文件路径: $configPath"
- } catch {
- Write-Host "$YELLOW⚠️ [保护]$NC 设置只读属性失败: $($_.Exception.Message)"
- Write-Host "$BLUE💡 [建议]$NC 可手动右键文件 → 属性 → 勾选'只读'"
+ Write-Host "╔══════════════════════════════════════════════════════════════════════════════╗"
+ Write-Host "║ ║"
+ Write-Host "║ 🎉 SUCCESS! FULL RESET COMPLETED! 🎉 ║"
+ Write-Host "║ ║"
+ Write-Host "║ ✅ Trial folders removed ║"
+ Write-Host "║ ✅ Machine code configuration updated ║"
+ Write-Host "║ ✅ JavaScript files patched ║"
+ Write-Host "║ ✅ Windows registry updated ║"
+ Write-Host "║ ║"
+ Write-Host "║ 🚀 You can now restart Cursor to use the reset trial! ║"
+ Write-Host "║ ║"
+ Write-Host "╚══════════════════════════════════════════════════════════════════════════════╝"
+ return
+ }
+ 2 {
+ Write-Info "Starting trial folder reset..."
+ Stop-AllCursorProcesses | Out-Null
+ Remove-CursorTrialFolders | Out-Null
+ Write-Info "Trial folder reset completed"
+ return
+ }
+ 3 {
+ Write-Info "Starting machine code configuration modification..."
+ Stop-AllCursorProcesses | Out-Null
+ Modify-MachineCodeConfig | Out-Null
+ Write-Info "Machine code configuration completed"
+ return
+ }
+ 4 {
+ Write-Info "Starting JS file modification..."
+ Modify-CursorJSFiles | Out-Null
+ Write-Info "JS file modification completed"
+ return
+ }
+ 5 {
+ Write-Info "Starting registry update..."
+ Update-MachineGuid | Out-Null
+ Write-Info "Registry update completed"
+ return
+ }
+ 6 {
+ Write-Info "Exiting..."
+ return
+ }
+ default {
+ Write-Warn "Invalid choice. Please enter 1-6."
}
}
- } else {
- Write-Host ""
- Write-Host "$RED❌ [失败]$NC 机器码配置修改失败!"
- Write-Host "$YELLOW💡 [建议]$NC 请检查错误信息并重试"
}
}
-
-# 📱 显示公众号信息
-Write-Host ""
-Write-Host "$GREEN================================$NC"
-Write-Host "$YELLOW📱 关注公众号【煎饼果子卷AI】一起交流更多Cursor技巧和AI知识(脚本免费、关注公众号加群有更多技巧和大佬) $NC"
-Write-Host "$GREEN================================$NC"
-Write-Host ""
-
-# 🎉 脚本执行完成
-Write-Host "$GREEN🎉 [脚本完成]$NC 感谢使用 Cursor 机器码修改工具!"
-Write-Host "$BLUE💡 [提示]$NC 如有问题请参考公众号或重新运行脚本"
-Write-Host ""
-Read-Host "按回车键退出"
-exit 0
+# Execute main function
+Main
\ No newline at end of file
diff --git a/scripts/run/cursor_win_id_modifier_old.ps1 b/scripts/run/cursor_win_id_modifier_old.ps1
deleted file mode 100644
index 278aca1..0000000
--- a/scripts/run/cursor_win_id_modifier_old.ps1
+++ /dev/null
@@ -1,607 +0,0 @@
-# 设置输出编码为 UTF-8
-$OutputEncoding = [System.Text.Encoding]::UTF8
-[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
-
-# 颜色定义
-$RED = "`e[31m"
-$GREEN = "`e[32m"
-$YELLOW = "`e[33m"
-$BLUE = "`e[34m"
-$NC = "`e[0m"
-
-# 配置文件路径
-$STORAGE_FILE = "$env:APPDATA\Cursor\User\globalStorage\storage.json"
-$BACKUP_DIR = "$env:APPDATA\Cursor\User\globalStorage\backups"
-
-# 新增 Cursor 初始化函数
-function Cursor-初始化 {
- Write-Host "$GREEN[信息]$NC 正在执行 Cursor 初始化清理..."
- $BASE_PATH = "$env:APPDATA\Cursor\User"
-
- $filesToDelete = @(
- (Join-Path -Path $BASE_PATH -ChildPath "globalStorage\\state.vscdb"),
- (Join-Path -Path $BASE_PATH -ChildPath "globalStorage\\state.vscdb.backup")
- )
-
- $folderToCleanContents = Join-Path -Path $BASE_PATH -ChildPath "History"
- $folderToDeleteCompletely = Join-Path -Path $BASE_PATH -ChildPath "workspaceStorage"
-
- Write-Host "$BLUE[调试]$NC 基础路径: $BASE_PATH"
-
- # 删除指定文件
- foreach ($file in $filesToDelete) {
- Write-Host "$BLUE[调试]$NC 检查文件: $file"
- if (Test-Path $file) {
- try {
- Remove-Item -Path $file -Force -ErrorAction Stop
- Write-Host "$GREEN[成功]$NC 已删除文件: $file"
- }
- catch {
- Write-Host "$RED[错误]$NC 删除文件 $file 失败: $($_.Exception.Message)"
- }
- } else {
- Write-Host "$YELLOW[警告]$NC 文件不存在,跳过删除: $file"
- }
- }
-
- # 清空指定文件夹内容
- Write-Host "$BLUE[调试]$NC 检查待清空文件夹: $folderToCleanContents"
- if (Test-Path $folderToCleanContents) {
- try {
- # 获取子项进行删除,以避免删除 History 文件夹本身
- Get-ChildItem -Path $folderToCleanContents -Recurse | Remove-Item -Recurse -Force -ErrorAction Stop
- Write-Host "$GREEN[成功]$NC 已清空文件夹内容: $folderToCleanContents"
- }
- catch {
- Write-Host "$RED[错误]$NC 清空文件夹 $folderToCleanContents 内容失败: $($_.Exception.Message)"
- }
- } else {
- Write-Host "$YELLOW[警告]$NC 文件夹不存在,跳过清空: $folderToCleanContents"
- }
-
- # 删除指定文件夹及其内容
- Write-Host "$BLUE[调试]$NC 检查待删除文件夹: $folderToDeleteCompletely"
- if (Test-Path $folderToDeleteCompletely) {
- try {
- Remove-Item -Path $folderToDeleteCompletely -Recurse -Force -ErrorAction Stop
- Write-Host "$GREEN[成功]$NC 已删除文件夹: $folderToDeleteCompletely"
- }
- catch {
- Write-Host "$RED[错误]$NC 删除文件夹 $folderToDeleteCompletely 失败: $($_.Exception.Message)"
- }
- } else {
- Write-Host "$YELLOW[警告]$NC 文件夹不存在,跳过删除: $folderToDeleteCompletely"
- }
-
- Write-Host "$GREEN[信息]$NC Cursor 初始化清理完成。"
- Write-Host "" # 添加空行以改善输出格式
-}
-
-# 检查管理员权限
-function Test-Administrator {
- $user = [Security.Principal.WindowsIdentity]::GetCurrent()
- $principal = New-Object Security.Principal.WindowsPrincipal($user)
- return $principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
-}
-
-if (-not (Test-Administrator)) {
- Write-Host "$RED[错误]$NC 请以管理员身份运行此脚本"
- Write-Host "请右键点击脚本,选择'以管理员身份运行'"
- Read-Host "按回车键退出"
- exit 1
-}
-
-# 显示 Logo
-Clear-Host
-Write-Host @"
-
- ██████╗██╗ ██╗██████╗ ███████╗ ██████╗ ██████╗
- ██╔════╝██║ ██║██╔══██╗██╔════╝██╔═══██╗██╔══██╗
- ██║ ██║ ██║██████╔╝███████╗██║ ██║██████╔╝
- ██║ ██║ ██║██╔══██╗╚════██║██║ ██║██╔══██╗
- ╚██████╗╚██████╔╝██║ ██║███████║╚██████╔╝██║ ██║
- ╚═════╝ ╚═════╝ ╚═╝ ╚═╝╚══════╝ ╚═════╝ ╚═╝ ╚═╝
-
-"@
-Write-Host "$BLUE================================$NC"
-Write-Host "$GREEN Cursor 设备ID 修改工具 $NC"
-Write-Host "$YELLOW 关注公众号【煎饼果子卷AI】 $NC"
-Write-Host "$YELLOW 一起交流更多Cursor技巧和AI知识(脚本免费、关注公众号加群有更多技巧和大佬) $NC"
-Write-Host "$YELLOW [重要提示] 本工具免费,如果对您有帮助,请关注公众号【煎饼果子卷AI】 $NC"
-Write-Host ""
-Write-Host "$YELLOW [小小广告] 出售CursorPro教育号一年质保三个月,有需要找我(86),WeChat:JavaRookie666 $NC"
-Write-Host "$BLUE================================$NC"
-
-# 获取并显示 Cursor 版本
-function Get-CursorVersion {
- try {
- # 主要检测路径
- $packagePath = "$env:LOCALAPPDATA\\Programs\\cursor\\resources\\app\\package.json"
-
- if (Test-Path $packagePath) {
- $packageJson = Get-Content $packagePath -Raw | ConvertFrom-Json
- if ($packageJson.version) {
- Write-Host "$GREEN[信息]$NC 当前安装的 Cursor 版本: v$($packageJson.version)"
- return $packageJson.version
- }
- }
-
- # 备用路径检测
- $altPath = "$env:LOCALAPPDATA\\cursor\\resources\\app\\package.json"
- if (Test-Path $altPath) {
- $packageJson = Get-Content $altPath -Raw | ConvertFrom-Json
- if ($packageJson.version) {
- Write-Host "$GREEN[信息]$NC 当前安装的 Cursor 版本: v$($packageJson.version)"
- return $packageJson.version
- }
- }
-
- Write-Host "$YELLOW[警告]$NC 无法检测到 Cursor 版本"
- Write-Host "$YELLOW[提示]$NC 请确保 Cursor 已正确安装"
- return $null
- }
- catch {
- Write-Host "$RED[错误]$NC 获取 Cursor 版本失败: $_"
- return $null
- }
-}
-
-# 获取并显示版本信息
-$cursorVersion = Get-CursorVersion
-Write-Host ""
-
-Write-Host "$YELLOW[重要提示]$NC 最新的 1.0.x (以支持)"
-Write-Host ""
-
-# 检查并关闭 Cursor 进程
-Write-Host "$GREEN[信息]$NC 检查 Cursor 进程..."
-
-function Get-ProcessDetails {
- param($processName)
- Write-Host "$BLUE[调试]$NC 正在获取 $processName 进程详细信息:"
- Get-WmiObject Win32_Process -Filter "name='$processName'" |
- Select-Object ProcessId, ExecutablePath, CommandLine |
- Format-List
-}
-
-# 定义最大重试次数和等待时间
-$MAX_RETRIES = 5
-$WAIT_TIME = 1
-
-# 处理进程关闭
-function Close-CursorProcess {
- param($processName)
-
- $process = Get-Process -Name $processName -ErrorAction SilentlyContinue
- if ($process) {
- Write-Host "$YELLOW[警告]$NC 发现 $processName 正在运行"
- Get-ProcessDetails $processName
-
- Write-Host "$YELLOW[警告]$NC 尝试关闭 $processName..."
- Stop-Process -Name $processName -Force
-
- $retryCount = 0
- while ($retryCount -lt $MAX_RETRIES) {
- $process = Get-Process -Name $processName -ErrorAction SilentlyContinue
- if (-not $process) { break }
-
- $retryCount++
- if ($retryCount -ge $MAX_RETRIES) {
- Write-Host "$RED[错误]$NC 在 $MAX_RETRIES 次尝试后仍无法关闭 $processName"
- Get-ProcessDetails $processName
- Write-Host "$RED[错误]$NC 请手动关闭进程后重试"
- Read-Host "按回车键退出"
- exit 1
- }
- Write-Host "$YELLOW[警告]$NC 等待进程关闭,尝试 $retryCount/$MAX_RETRIES..."
- Start-Sleep -Seconds $WAIT_TIME
- }
- Write-Host "$GREEN[信息]$NC $processName 已成功关闭"
- }
-}
-
-# 关闭所有 Cursor 进程
-Close-CursorProcess "Cursor"
-Close-CursorProcess "cursor"
-
-# 执行 Cursor 初始化清理
-# Cursor-初始化
-
-# 创建备份目录
-if (-not (Test-Path $BACKUP_DIR)) {
- New-Item -ItemType Directory -Path $BACKUP_DIR | Out-Null
-}
-
-# 备份现有配置
-if (Test-Path $STORAGE_FILE) {
- Write-Host "$GREEN[信息]$NC 正在备份配置文件..."
- $backupName = "storage.json.backup_$(Get-Date -Format 'yyyyMMdd_HHmmss')"
- Copy-Item $STORAGE_FILE "$BACKUP_DIR\$backupName"
-}
-
-# 生成新的 ID
-Write-Host "$GREEN[信息]$NC 正在生成新的 ID..."
-
-# 在颜色定义后添加此函数
-function Get-RandomHex {
- param (
- [int]$length
- )
-
- $bytes = New-Object byte[] ($length)
- $rng = [System.Security.Cryptography.RNGCryptoServiceProvider]::new()
- $rng.GetBytes($bytes)
- $hexString = [System.BitConverter]::ToString($bytes) -replace '-',''
- $rng.Dispose()
- return $hexString
-}
-
-# 改进 ID 生成函数
-function New-StandardMachineId {
- $template = "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx"
- $result = $template -replace '[xy]', {
- param($match)
- $r = [Random]::new().Next(16)
- $v = if ($match.Value -eq "x") { $r } else { ($r -band 0x3) -bor 0x8 }
- return $v.ToString("x")
- }
- return $result
-}
-
-# 在生成 ID 时使用新函数
-$MAC_MACHINE_ID = New-StandardMachineId
-$UUID = [System.Guid]::NewGuid().ToString()
-# 将 auth0|user_ 转换为字节数组的十六进制
-$prefixBytes = [System.Text.Encoding]::UTF8.GetBytes("auth0|user_")
-$prefixHex = -join ($prefixBytes | ForEach-Object { '{0:x2}' -f $_ })
-# 生成32字节(64个十六进制字符)的随机数作为 machineId 的随机部分
-$randomPart = Get-RandomHex -length 32
-$MACHINE_ID = "$prefixHex$randomPart"
-$SQM_ID = "{$([System.Guid]::NewGuid().ToString().ToUpper())}"
-
-# 在Update-MachineGuid函数前添加权限检查
-if (-NOT ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")) {
- Write-Host "$RED[错误]$NC 请使用管理员权限运行此脚本"
- Start-Process powershell "-NoProfile -ExecutionPolicy Bypass -File `"$PSCommandPath`"" -Verb RunAs
- exit
-}
-
-function Update-MachineGuid {
- try {
- # 检查注册表路径是否存在,不存在则创建
- $registryPath = "HKLM:\SOFTWARE\Microsoft\Cryptography"
- if (-not (Test-Path $registryPath)) {
- Write-Host "$YELLOW[警告]$NC 注册表路径不存在: $registryPath,正在创建..."
- New-Item -Path $registryPath -Force | Out-Null
- Write-Host "$GREEN[信息]$NC 注册表路径创建成功"
- }
-
- # 获取当前的 MachineGuid,如果不存在则使用空字符串作为默认值
- $originalGuid = ""
- try {
- $currentGuid = Get-ItemProperty -Path $registryPath -Name MachineGuid -ErrorAction SilentlyContinue
- if ($currentGuid) {
- $originalGuid = $currentGuid.MachineGuid
- Write-Host "$GREEN[信息]$NC 当前注册表值:"
- Write-Host "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography"
- Write-Host " MachineGuid REG_SZ $originalGuid"
- } else {
- Write-Host "$YELLOW[警告]$NC MachineGuid 值不存在,将创建新值"
- }
- } catch {
- Write-Host "$YELLOW[警告]$NC 获取 MachineGuid 失败: $($_.Exception.Message)"
- }
-
- # 创建备份目录(如果不存在)
- if (-not (Test-Path $BACKUP_DIR)) {
- New-Item -ItemType Directory -Path $BACKUP_DIR -Force | Out-Null
- }
-
- # 创建备份文件(仅当原始值存在时)
- if ($originalGuid) {
- $backupFile = "$BACKUP_DIR\MachineGuid_$(Get-Date -Format 'yyyyMMdd_HHmmss').reg"
- $backupResult = Start-Process "reg.exe" -ArgumentList "export", "`"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography`"", "`"$backupFile`"" -NoNewWindow -Wait -PassThru
-
- if ($backupResult.ExitCode -eq 0) {
- Write-Host "$GREEN[信息]$NC 注册表项已备份到:$backupFile"
- } else {
- Write-Host "$YELLOW[警告]$NC 备份创建失败,继续执行..."
- }
- }
-
- # 生成新GUID
- $newGuid = [System.Guid]::NewGuid().ToString()
-
- # 更新或创建注册表值
- Set-ItemProperty -Path $registryPath -Name MachineGuid -Value $newGuid -Force -ErrorAction Stop
-
- # 验证更新
- $verifyGuid = (Get-ItemProperty -Path $registryPath -Name MachineGuid -ErrorAction Stop).MachineGuid
- if ($verifyGuid -ne $newGuid) {
- throw "注册表验证失败:更新后的值 ($verifyGuid) 与预期值 ($newGuid) 不匹配"
- }
-
- Write-Host "$GREEN[信息]$NC 注册表更新成功:"
- Write-Host "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography"
- Write-Host " MachineGuid REG_SZ $newGuid"
- return $true
- }
- catch {
- Write-Host "$RED[错误]$NC 注册表操作失败:$($_.Exception.Message)"
-
- # 尝试恢复备份(如果存在)
- if (($backupFile -ne $null) -and (Test-Path $backupFile)) {
- Write-Host "$YELLOW[恢复]$NC 正在从备份恢复..."
- $restoreResult = Start-Process "reg.exe" -ArgumentList "import", "`"$backupFile`"" -NoNewWindow -Wait -PassThru
-
- if ($restoreResult.ExitCode -eq 0) {
- Write-Host "$GREEN[恢复成功]$NC 已还原原始注册表值"
- } else {
- Write-Host "$RED[错误]$NC 恢复失败,请手动导入备份文件:$backupFile"
- }
- } else {
- Write-Host "$YELLOW[警告]$NC 未找到备份文件或备份创建失败,无法自动恢复"
- }
- return $false
- }
-}
-
-# 创建或更新配置文件
-Write-Host "$GREEN[信息]$NC 正在更新配置..."
-
-try {
- # 检查配置文件是否存在
- if (-not (Test-Path $STORAGE_FILE)) {
- Write-Host "$RED[错误]$NC 未找到配置文件: $STORAGE_FILE"
- Write-Host "$YELLOW[提示]$NC 请先安装并运行一次 Cursor 后再使用此脚本"
- Read-Host "按回车键退出"
- exit 1
- }
-
- # 读取现有配置文件
- try {
- $originalContent = Get-Content $STORAGE_FILE -Raw -Encoding UTF8
-
- # 将 JSON 字符串转换为 PowerShell 对象
- $config = $originalContent | ConvertFrom-Json
-
- # 备份当前值
- $oldValues = @{
- 'machineId' = $config.'telemetry.machineId'
- 'macMachineId' = $config.'telemetry.macMachineId'
- 'devDeviceId' = $config.'telemetry.devDeviceId'
- 'sqmId' = $config.'telemetry.sqmId'
- }
-
- # 更新特定的值
- $config.'telemetry.machineId' = $MACHINE_ID
- $config.'telemetry.macMachineId' = $MAC_MACHINE_ID
- $config.'telemetry.devDeviceId' = $UUID
- $config.'telemetry.sqmId' = $SQM_ID
-
- # 将更新后的对象转换回 JSON 并保存
- $updatedJson = $config | ConvertTo-Json -Depth 10
- [System.IO.File]::WriteAllText(
- [System.IO.Path]::GetFullPath($STORAGE_FILE),
- $updatedJson,
- [System.Text.Encoding]::UTF8
- )
- Write-Host "$GREEN[信息]$NC 成功更新配置文件"
- } catch {
- # 如果出错,尝试恢复原始内容
- if ($originalContent) {
- [System.IO.File]::WriteAllText(
- [System.IO.Path]::GetFullPath($STORAGE_FILE),
- $originalContent,
- [System.Text.Encoding]::UTF8
- )
- }
- throw "处理 JSON 失败: $_"
- }
- # 直接执行更新 MachineGuid,不再询问
- Update-MachineGuid
- # 显示结果
- Write-Host ""
- Write-Host "$GREEN[信息]$NC 已更新配置:"
- Write-Host "$BLUE[调试]$NC machineId: $MACHINE_ID"
- Write-Host "$BLUE[调试]$NC macMachineId: $MAC_MACHINE_ID"
- Write-Host "$BLUE[调试]$NC devDeviceId: $UUID"
- Write-Host "$BLUE[调试]$NC sqmId: $SQM_ID"
-
- # 显示文件树结构
- Write-Host ""
- Write-Host "$GREEN[信息]$NC 文件结构:"
- Write-Host "$BLUE$env:APPDATA\Cursor\User$NC"
- Write-Host "├── globalStorage"
- Write-Host "│ ├── storage.json (已修改)"
- Write-Host "│ └── backups"
-
- # 列出备份文件
- $backupFiles = Get-ChildItem "$BACKUP_DIR\*" -ErrorAction SilentlyContinue
- if ($backupFiles) {
- foreach ($file in $backupFiles) {
- Write-Host "│ └── $($file.Name)"
- }
- } else {
- Write-Host "│ └── (空)"
- }
-
- # 显示公众号信息
- Write-Host ""
- Write-Host "$GREEN================================$NC"
- Write-Host "$YELLOW 关注公众号【煎饼果子卷AI】一起交流更多Cursor技巧和AI知识(脚本免费、关注公众号加群有更多技巧和大佬) $NC"
- Write-Host "$GREEN================================$NC"
- Write-Host ""
- Write-Host "$GREEN[信息]$NC 请重启 Cursor 以应用新的配置"
- Write-Host ""
-
- # 询问是否要禁用自动更新
- Write-Host ""
- Write-Host "$YELLOW[询问]$NC 是否要禁用 Cursor 自动更新功能?"
- Write-Host "0) 否 - 保持默认设置 (按回车键)"
- Write-Host "1) 是 - 禁用自动更新"
- $choice = Read-Host "请输入选项 (0)"
-
- if ($choice -eq "1") {
- Write-Host ""
- Write-Host "$GREEN[信息]$NC 正在处理自动更新..."
- $updaterPath = "$env:LOCALAPPDATA\cursor-updater"
-
- # 定义手动设置教程
- function Show-ManualGuide {
- Write-Host ""
- Write-Host "$YELLOW[警告]$NC 自动设置失败,请尝试手动操作:"
- Write-Host "$YELLOW手动禁用更新步骤:$NC"
- Write-Host "1. 以管理员身份打开 PowerShell"
- Write-Host "2. 复制粘贴以下命令:"
- Write-Host "$BLUE命令1 - 删除现有目录(如果存在):$NC"
- Write-Host "Remove-Item -Path `"$updaterPath`" -Force -Recurse -ErrorAction SilentlyContinue"
- Write-Host ""
- Write-Host "$BLUE命令2 - 创建阻止文件:$NC"
- Write-Host "New-Item -Path `"$updaterPath`" -ItemType File -Force | Out-Null"
- Write-Host ""
- Write-Host "$BLUE命令3 - 设置只读属性:$NC"
- Write-Host "Set-ItemProperty -Path `"$updaterPath`" -Name IsReadOnly -Value `$true"
- Write-Host ""
- Write-Host "$BLUE命令4 - 设置权限(可选):$NC"
- Write-Host "icacls `"$updaterPath`" /inheritance:r /grant:r `"`$($env:USERNAME):(R)`""
- Write-Host ""
- Write-Host "$YELLOW验证方法:$NC"
- Write-Host "1. 运行命令:Get-ItemProperty `"$updaterPath`""
- Write-Host "2. 确认 IsReadOnly 属性为 True"
- Write-Host "3. 运行命令:icacls `"$updaterPath`""
- Write-Host "4. 确认只有读取权限"
- Write-Host ""
- Write-Host "$YELLOW[提示]$NC 完成后请重启 Cursor"
- }
-
- try {
- # 检查cursor-updater是否存在
- if (Test-Path $updaterPath) {
- # 如果是文件,说明已经创建了阻止更新
- if ((Get-Item $updaterPath) -is [System.IO.FileInfo]) {
- Write-Host "$GREEN[信息]$NC 已创建阻止更新文件,无需再次阻止"
- return
- }
- # 如果是目录,尝试删除
- else {
- try {
- Remove-Item -Path $updaterPath -Force -Recurse -ErrorAction Stop
- Write-Host "$GREEN[信息]$NC 成功删除 cursor-updater 目录"
- }
- catch {
- Write-Host "$RED[错误]$NC 删除 cursor-updater 目录失败"
- Show-ManualGuide
- return
- }
- }
- }
-
- # 创建阻止文件
- try {
- New-Item -Path $updaterPath -ItemType File -Force -ErrorAction Stop | Out-Null
- Write-Host "$GREEN[信息]$NC 成功创建阻止文件"
- }
- catch {
- Write-Host "$RED[错误]$NC 创建阻止文件失败"
- Show-ManualGuide
- return
- }
-
- # 设置文件权限
- try {
- # 设置只读属性
- Set-ItemProperty -Path $updaterPath -Name IsReadOnly -Value $true -ErrorAction Stop
-
- # 使用 icacls 设置权限
- $result = Start-Process "icacls.exe" -ArgumentList "`"$updaterPath`" /inheritance:r /grant:r `"$($env:USERNAME):(R)`"" -Wait -NoNewWindow -PassThru
- if ($result.ExitCode -ne 0) {
- throw "icacls 命令失败"
- }
-
- Write-Host "$GREEN[信息]$NC 成功设置文件权限"
- }
- catch {
- Write-Host "$RED[错误]$NC 设置文件权限失败"
- Show-ManualGuide
- return
- }
-
- # 验证设置
- try {
- $fileInfo = Get-ItemProperty $updaterPath
- if (-not $fileInfo.IsReadOnly) {
- Write-Host "$RED[错误]$NC 验证失败:文件权限设置可能未生效"
- Show-ManualGuide
- return
- }
- }
- catch {
- Write-Host "$RED[错误]$NC 验证设置失败"
- Show-ManualGuide
- return
- }
-
- Write-Host "$GREEN[信息]$NC 成功禁用自动更新"
- }
- catch {
- Write-Host "$RED[错误]$NC 发生未知错误: $_"
- Show-ManualGuide
- }
- }
- else {
- Write-Host "$GREEN[信息]$NC 保持默认设置,不进行更改"
- }
-
- # 保留有效的注册表更新
- Update-MachineGuid
-
-} catch {
- Write-Host "$RED[错误]$NC 主要操作失败: $_"
- Write-Host "$YELLOW[尝试]$NC 使用备选方法..."
-
- try {
- # 备选方法:使用 Add-Content
- $tempFile = [System.IO.Path]::GetTempFileName()
- $config | ConvertTo-Json | Set-Content -Path $tempFile -Encoding UTF8
- Copy-Item -Path $tempFile -Destination $STORAGE_FILE -Force
- Remove-Item -Path $tempFile
- Write-Host "$GREEN[信息]$NC 使用备选方法成功写入配置"
- } catch {
- Write-Host "$RED[错误]$NC 所有尝试都失败了"
- Write-Host "错误详情: $_"
- Write-Host "目标文件: $STORAGE_FILE"
- Write-Host "请确保您有足够的权限访问该文件"
- Read-Host "按回车键退出"
- exit 1
- }
-}
-
-Write-Host ""
-Read-Host "按回车键退出"
-exit 0
-
-# 在文件写入部分修改
-function Write-ConfigFile {
- param($config, $filePath)
-
- try {
- # 使用 UTF8 无 BOM 编码
- $utf8NoBom = New-Object System.Text.UTF8Encoding $false
- $jsonContent = $config | ConvertTo-Json -Depth 10
-
- # 统一使用 LF 换行符
- $jsonContent = $jsonContent.Replace("`r`n", "`n")
-
- [System.IO.File]::WriteAllText(
- [System.IO.Path]::GetFullPath($filePath),
- $jsonContent,
- $utf8NoBom
- )
-
- Write-Host "$GREEN[信息]$NC 成功写入配置文件(UTF8 无 BOM)"
- }
- catch {
- throw "写入配置文件失败: $_"
- }
-}
\ No newline at end of file