The response has been limited to 50k tokens of the smallest files in the repo. You can remove this limitation by removing the max tokens filter.
├── .github
    └── workflows
    │   └── auto-tag-release.yml
├── .gitignore
├── .goreleaser.yml
├── LICENSE
├── README.md
├── README_CN.md
├── README_JP.md
├── cmd
    └── cursor-id-modifier
    │   └── main.go
├── go.mod
├── go.sum
├── img
    ├── alipay.png
    ├── alipay_scan_pay.jpg
    ├── etc.png
    ├── pwsh_1.png
    ├── pwsh_2.png
    ├── qun-10.jpg
    ├── qun-12.png
    ├── qun-14.jpg
    ├── qun-15.jpg
    ├── qun-8.png
    ├── qun11.jpg
    ├── qun13.png
    ├── qun9.png
    ├── run_success.png
    ├── wx_group.jpg
    ├── wx_group6.jpg
    ├── wx_group7.jpg
    ├── wx_me.png
    ├── wx_public.jpg
    ├── wx_public_2.png
    ├── wx_zsm.jpg
    ├── wx_zsm2.png
    └── zanzhu
    │   └── twillot.png
├── internal
    ├── config
    │   └── config.go
    ├── lang
    │   └── lang.go
    ├── process
    │   └── manager.go
    └── ui
    │   ├── display.go
    │   ├── logo.go
    │   └── spinner.go
├── pkg
    └── idgen
    │   └── generator.go
├── process_cursor_links.py
└── scripts
    ├── build_all.bat
    ├── build_all.sh
    ├── cursor_id_modifier.pot
    ├── cursor_id_modifier.py
    ├── git-actions.sh
    ├── install.ps1
    ├── install.sh
    └── run
        ├── cursor_linux_id_modifier.sh
        ├── cursor_mac_free_trial_reset.sh
        ├── cursor_mac_id_modifier.sh
        ├── cursor_win_id_modifier.ps1
        └── cursor_win_id_modifier_old.ps1


/.github/workflows/auto-tag-release.yml:
--------------------------------------------------------------------------------
  1 | # This workflow requires Ubuntu 22.04 or 24.04
  2 | 
  3 | name: Auto Tag & Release
  4 | 
  5 | on:
  6 |   push:
  7 |     branches:
  8 |       - master
  9 |       - main
 10 |     tags:
 11 |       - "v*"
 12 |     paths-ignore:
 13 |       - "**.md"
 14 |       - "LICENSE"
 15 |       - ".gitignore"
 16 |   workflow_call: {}
 17 | 
 18 | permissions:
 19 |   contents: write
 20 |   packages: write
 21 |   actions: write
 22 | 
 23 | jobs:
 24 |   pre_job:
 25 |     runs-on: ubuntu-22.04
 26 |     outputs:
 27 |       should_skip: ${{ steps.skip_check.outputs.should_skip }}
 28 |     steps:
 29 |       - id: skip_check
 30 |         uses: fkirc/skip-duplicate-actions@v5.3.0
 31 |         with:
 32 |           cancel_others: "true"
 33 |           concurrent_skipping: "same_content"
 34 | 
 35 |   auto-tag-release:
 36 |     needs: pre_job
 37 |     if: |
 38 |       needs.pre_job.outputs.should_skip != 'true' ||
 39 |       startsWith(github.ref, 'refs/tags/v')
 40 |     runs-on: ubuntu-22.04
 41 |     timeout-minutes: 15
 42 |     outputs:
 43 |       version: ${{ steps.get_latest_tag.outputs.version }}
 44 |     concurrency:
 45 |       group: ${{ github.workflow }}-${{ github.ref }}
 46 |       cancel-in-progress: true
 47 | 
 48 |     steps:
 49 |       - name: Checkout
 50 |         uses: actions/checkout@v3
 51 |         with:
 52 |           fetch-depth: 0
 53 |           lfs: true
 54 |           submodules: recursive
 55 | 
 56 |       - name: Setup Go
 57 |         uses: actions/setup-go@v3
 58 |         with:
 59 |           go-version: "1.21"
 60 |           check-latest: true
 61 |           cache: true
 62 | 
 63 |       - name: Cache
 64 |         uses: actions/cache@v3
 65 |         with:
 66 |           path: |
 67 |             ~/.cache/go-build
 68 |             ~/go/pkg/mod
 69 |             ~/.cache/git
 70 |           key: ${{ runner.os }}-build-${{ hashFiles('**/go.sum') }}
 71 |           restore-keys: |
 72 |             ${{ runner.os }}-build-
 73 |             ${{ runner.os }}-
 74 | 
 75 |       # 只在非tag推送时执行自动打tag
 76 |       - name: Get latest tag
 77 |         if: ${{ !startsWith(github.ref, 'refs/tags/v') }}
 78 |         id: get_latest_tag
 79 |         run: |
 80 |           set -euo pipefail
 81 |           git fetch --tags --force || {
 82 |             echo "::error::Failed to fetch tags"
 83 |             exit 1
 84 |           }
 85 |           latest_tag=$(git tag -l 'v*' --sort=-v:refname | head -n 1)
 86 |           if [ -z "$latest_tag" ]; then
 87 |             new_version="v0.1.0"
 88 |           else
 89 |             major=$(echo $latest_tag | cut -d. -f1)
 90 |             minor=$(echo $latest_tag | cut -d. -f2)
 91 |             patch=$(echo $latest_tag | cut -d. -f3)
 92 |             new_patch=$((patch + 1))
 93 |             new_version="$major.$minor.$new_patch"
 94 |           fi
 95 |           echo "version=$new_version" >> "$GITHUB_OUTPUT"
 96 |           echo "Generated version: $new_version"
 97 | 
 98 |       - name: Validate version
 99 |         if: ${{ !startsWith(github.ref, 'refs/tags/v') }}
100 |         run: |
101 |           set -euo pipefail
102 |           new_tag="${{ steps.get_latest_tag.outputs.version }}"
103 |           echo "Validating version: $new_tag"
104 |           if [[ ! $new_tag =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
105 |             echo "::error::Invalid version format: $new_tag"
106 |             exit 1
107 |           fi
108 |           major=$(echo $new_tag | cut -d. -f1 | tr -d 'v')
109 |           minor=$(echo $new_tag | cut -d. -f2)
110 |           patch=$(echo $new_tag | cut -d. -f3)
111 |           if [[ $major -gt 99 || $minor -gt 99 || $patch -gt 999 ]]; then
112 |             echo "::error::Version numbers out of valid range"
113 |             exit 1
114 |           fi
115 |           echo "Version validation passed"
116 | 
117 |       - name: Create new tag
118 |         if: ${{ !startsWith(github.ref, 'refs/tags/v') }}
119 |         env:
120 |           GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
121 |         run: |
122 |           new_tag=${{ steps.get_latest_tag.outputs.version }}
123 |           git config --global user.name 'github-actions[bot]'
124 |           git config --global user.email 'github-actions[bot]@users.noreply.github.com'
125 |           git tag -a $new_tag -m "Release $new_tag"
126 |           git push origin $new_tag
127 | 
128 |       # 在 Run GoReleaser 之前添加配置检查步骤
129 |       - name: Check GoReleaser config
130 |         run: |
131 |           if [ ! -f ".goreleaser.yml" ] && [ ! -f ".goreleaser.yaml" ]; then
132 |             echo "::error::GoReleaser configuration file not found"
133 |             exit 1
134 |           fi
135 | 
136 |       # 添加依赖检查步骤
137 |       - name: Check Dependencies
138 |         run: |
139 |           go mod verify
140 |           go mod download
141 |           # 如果使用 vendor 模式,则执行以下命令
142 |           if [ -d "vendor" ]; then
143 |             go mod vendor
144 |           fi
145 | 
146 |       # 添加构建环境准备步骤
147 |       - name: Prepare Build Environment
148 |         run: |
149 |           echo "Building version: ${VERSION:-development}"
150 |           echo "GOOS=${GOOS:-$(go env GOOS)}" >> $GITHUB_ENV
151 |           echo "GOARCH=${GOARCH:-$(go env GOARCH)}" >> $GITHUB_ENV
152 |           echo "GO111MODULE=on" >> $GITHUB_ENV
153 | 
154 |       # 添加清理步骤
155 |       - name: Cleanup workspace
156 |         run: |
157 |           rm -rf /tmp/go/
158 |           rm -rf .cache/
159 |           rm -rf dist/
160 |           git clean -fdx
161 |           git status
162 | 
163 |       # 修改 GoReleaser 步骤
164 |       - name: Run GoReleaser
165 |         if: ${{ startsWith(github.ref, 'refs/tags/v') || (success() && steps.get_latest_tag.outputs.version != '') }}
166 |         uses: goreleaser/goreleaser-action@v3
167 |         with:
168 |           distribution: goreleaser
169 |           version: latest
170 |           args: release --clean --timeout 60m
171 |         env:
172 |           GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
173 |           VERSION: ${{ steps.get_latest_tag.outputs.version }}
174 |           CGO_ENABLED: 0
175 |           GOPATH: /tmp/go
176 |           GOROOT: ${{ env.GOROOT }}
177 |           GOCACHE: /tmp/.cache/go-build
178 |           GOMODCACHE: /tmp/go/pkg/mod
179 |           GORELEASER_DEBUG: 1
180 |           GORELEASER_CURRENT_TAG: ${{ steps.get_latest_tag.outputs.version }}
181 |           # 添加额外的构建信息
182 |           BUILD_TIME: ${{ steps.get_latest_tag.outputs.version }}
183 |           BUILD_COMMIT: ${{ github.sha }}
184 | 
185 |       # 优化 vendor 同步步骤
186 |       - name: Sync vendor directory
187 |         run: |
188 |           echo "Syncing vendor directory..."
189 |           go mod tidy
190 |           go mod vendor
191 |           go mod verify
192 |           # 验证 vendor 目录
193 |           if [ -d "vendor" ]; then
194 |             echo "Verifying vendor directory..."
195 |             go mod verify
196 |             # 检查是否有未跟踪的文件
197 |             if [ -n "$(git status --porcelain vendor/)" ]; then
198 |               echo "Warning: Vendor directory has uncommitted changes"
199 |               git status vendor/
200 |             fi
201 |           fi
202 | 
203 |       # 添加错误检查步骤
204 |       - name: Check GoReleaser Output
205 |         if: failure()
206 |         run: |
207 |           echo "::group::GoReleaser Debug Info"
208 |           cat dist/artifacts.json || true
209 |           echo "::endgroup::"
210 | 
211 |           echo "::group::GoReleaser Config"
212 |           cat .goreleaser.yml
213 |           echo "::endgroup::"
214 | 
215 |           echo "::group::Environment Info"
216 |           go version
217 |           go env
218 |           echo "::endgroup::"
219 | 
220 |       - name: Set Release Version
221 |         if: startsWith(github.ref, 'refs/tags/v')
222 |         run: |
223 |           echo "VERSION=${GITHUB_REF#refs/tags/}" >> $GITHUB_ENV
224 | 
225 |       # 改进验证步骤
226 |       - name: Verify Release
227 |         if: ${{ startsWith(github.ref, 'refs/tags/v') || (success() && steps.get_latest_tag.outputs.version != '') }}
228 |         run: |
229 |           echo "Verifying release artifacts..."
230 |           if [ ! -d "dist" ]; then
231 |             echo "::error::Release artifacts not found"
232 |             exit 1
233 |           fi
234 |           # 验证生成的二进制文件
235 |           for file in dist/cursor-id-modifier_*; do
236 |             if [ -f "$file" ]; then
237 |               echo "Verifying: $file"
238 |               if [[ "$file" == *.exe ]]; then
239 |                 # Windows 二进制文件检查
240 |                 if ! [ -x "$file" ]; then
241 |                   echo "::error::$file is not executable"
242 |                   exit 1
243 |                 fi
244 |               else
245 |                 # Unix 二进制文件检查
246 |                 if ! [ -x "$file" ]; then
247 |                   echo "::error::$file is not executable"
248 |                   exit 1
249 |                 fi
250 |               fi
251 |             fi
252 |           done
253 | 
254 |       - name: Notify on failure
255 |         if: failure()
256 |         run: |
257 |           echo "::error::Release process failed"
258 | 
259 |       # 修改构建摘要步骤
260 |       - name: Build Summary
261 |         if: always()
262 |         run: |
263 |           echo "## Build Summary" >> $GITHUB_STEP_SUMMARY
264 |           echo "- Go Version: $(go version)" >> $GITHUB_STEP_SUMMARY
265 |           echo "- Release Version: ${VERSION:-N/A}" >> $GITHUB_STEP_SUMMARY
266 |           echo "- GPG Signing: Disabled" >> $GITHUB_STEP_SUMMARY
267 |           echo "- Build Status: ${{ job.status }}" >> $GITHUB_STEP_SUMMARY
268 | 
269 |           if [ -d "dist" ]; then
270 |             echo "### Generated Artifacts" >> $GITHUB_STEP_SUMMARY
271 |             ls -lh dist/ | awk '{print "- "$9" ("$5")"}' >> $GITHUB_STEP_SUMMARY
272 |           fi
273 | 


--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
 1 | # Compiled binary
 2 | /cursor-id-modifier
 3 | /cursor-id-modifier.exe
 4 | 
 5 | # Build output directories
 6 | bin/
 7 | dist/
 8 | 
 9 | # Go specific
10 | go.sum
11 | go/
12 | .cache/
13 | 
14 | # IDE and editor files
15 | .vscode/
16 | .idea/
17 | *.swp
18 | *.swo
19 | 
20 | # OS specific
21 | .DS_Store
22 | Thumbs.db
23 | 
24 | # Build and release artifacts
25 | releases/
26 | *.syso
27 | *.exe
28 | *.exe~
29 | *.dll
30 | *.so
31 | *.dylib
32 | 
33 | # Test files
34 | *.test
35 | *.out
36 | coverage.txt
37 | 
38 | # Temporary files
39 | *.tmp
40 | *~
41 | *.bak
42 | *.log
43 | 
44 | .cunzhi*/


--------------------------------------------------------------------------------
/.goreleaser.yml:
--------------------------------------------------------------------------------
 1 | version: 2
 2 | 
 3 | before:
 4 |   hooks:
 5 |     - go mod tidy
 6 |     - go mod vendor
 7 |     - go mod verify
 8 | 
 9 | builds:
10 |   - id: cursor-id-modifier
11 |     main: ./cmd/cursor-id-modifier/main.go
12 |     binary: cursor-id-modifier
13 |     env:
14 |       - CGO_ENABLED=0
15 |       - GO111MODULE=on
16 |     goos:
17 |       - linux
18 |       - windows
19 |       - darwin
20 |     goarch:
21 |       - amd64
22 |       - arm64
23 |       - "386"
24 |     ignore:
25 |       - goos: darwin
26 |         goarch: "386"
27 |     ldflags:
28 |       - -s -w
29 |       - -X 'main.version={{.Version}}'
30 |       - -X 'main.commit={{.ShortCommit}}'
31 |       - -X 'main.date={{.CommitDate}}'
32 |       - -X 'main.builtBy=goreleaser'
33 |     flags:
34 |       - -trimpath
35 |     mod_timestamp: '{{ .CommitTimestamp }}'
36 | 
37 | archives:
38 |   - id: binary
39 |     format: binary
40 |     name_template: >-
41 |       {{- .ProjectName }}_
42 |       {{- .Version }}_
43 |       {{- .Os }}_
44 |       {{- if eq .Arch "amd64" }}x86_64
45 |       {{- else if eq .Arch "386" }}i386
46 |       {{- else }}{{ .Arch }}{{ end }}
47 |     builds:
48 |       - cursor-id-modifier
49 |     allow_different_binary_count: true
50 |     files:
51 |       - none*
52 | 
53 | checksum:
54 |   name_template: 'checksums.txt'
55 |   algorithm: sha256
56 | 
57 | release:
58 |   draft: true
59 |   prerelease: auto
60 |   mode: replace
61 |   header: |
62 |     ## Release {{.Tag}} ({{.Date}})
63 |     
64 |     See [CHANGELOG.md](CHANGELOG.md) for details.
65 |   footer: |
66 |     **Full Changelog**: https://github.com/owner/repo/compare/{{ .PreviousTag }}...{{ .Tag }}
67 |   extra_files:
68 |     - glob: 'LICENSE*'
69 |     - glob: 'README*'
70 |     - glob: 'CHANGELOG*'
71 | 
72 | changelog:
73 |   sort: asc
74 |   use: github
75 |   filters:
76 |     exclude:
77 |       - '^docs:'
78 |       - '^test:'
79 |       - '^ci:'
80 |       - Merge pull request
81 |       - Merge branch
82 |   groups:
83 |     - title: Features
84 |       regexp: "^.*feat[(\\w)]*:+.*
quot;
85 |       order: 0
86 |     - title: 'Bug fixes'
87 |       regexp: "^.*fix[(\\w)]*:+.*
quot;
88 |       order: 1
89 |     - title: Others
90 |       order: 999
91 | 
92 | project_name: cursor-id-modifier
93 | 


--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
 1 | MIT License
 2 | 
 3 | Copyright (c) 2024 dacrab
 4 | 
 5 | Permission is hereby granted, free of charge, to any person obtaining a copy
 6 | of this software and associated documentation files (the "Software"), to deal
 7 | in the Software without restriction, including without limitation the rights
 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 | 
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 | 
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE. 


--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
  1 | # 🚀 Cursor Free Trial Reset Tool
  2 | 
  3 | <div align="center">
  4 | 
  5 | [![Release](https://img.shields.io/github/v/release/yuaotian/go-cursor-help?style=flat-square&logo=github&color=blue)](https://github.com/yuaotian/go-cursor-help/releases/latest)
  6 | [![License](https://img.shields.io/badge/license-MIT-blue.svg?style=flat-square&logo=bookstack)](https://github.com/yuaotian/go-cursor-help/blob/master/LICENSE)
  7 | [![Stars](https://img.shields.io/github/stars/yuaotian/go-cursor-help?style=flat-square&logo=github)](https://github.com/yuaotian/go-cursor-help/stargazers)
  8 | 
  9 | [🌟 English](README.md) | [🌏 中文](README_CN.md) | [🌏 日本語](README_JP.md)
 10 | 
 11 | <img src="https://ai-cursor.com/wp-content/uploads/2024/09/logo-cursor-ai-png.webp" alt="Cursor Logo" width="120"/>
 12 | 
 13 | 
 14 | 
 15 | </div>
 16 | 
 17 | > ⚠️ **IMPORTANT NOTICE**
 18 | > 
 19 | > This tool currently supports:
 20 | > - ✅ Windows: Latest 1.0.x versions (Supported)
 21 | > - ✅ Mac/Linux: Latest 1.0.x versions (Supported, feedback welcome)
 22 | >
 23 | > Please check your Cursor version before using this tool.
 24 | 
 25 | <details open>
 26 | <summary><b>📦 Version History & Downloads</b></summary>
 27 | 
 28 | <div class="version-card" style="background: linear-gradient(135deg, #6e8efb, #a777e3); border-radius: 8px; padding: 15px; margin: 10px 0; color: white;">
 29 | 
 30 | ### 🌟 Latest Versions
 31 | 
 32 | [View Full Version History]([CursorHistoryDown.md](https://github.com/oslook/cursor-ai-downloads?tab=readme-ov-file))
 33 | 
 34 | </div>
 35 | 
 36 | 
 37 | 
 38 | </details>
 39 | 
 40 | ⚠️ **General Solutions for Cursor**
 41 | > 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`)
 42 | > Go to the Cursor official website to delete your current account
 43 | > Steps: User avatar -> Setting -> Advanced▼ in the bottom left -> Delete Account
 44 | >
 45 | > 2.  Run the machine code refresh script, see the script address below, available in China
 46 | > 
 47 | > 3.  Re-register an account, log in, and open Cursor to resume normal use.
 48 | >
 49 | > 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).
 50 | 
 51 | 
 52 | ---
 53 | 
 54 | ⚠️ **MAC Address Modification Warning**
 55 | > 
 56 | > For Mac users: This script includes a MAC address modification feature that will:
 57 | > - Modify your network interface's MAC address
 58 | > - Backup original MAC addresses before modification
 59 | > - This modification may temporarily affect network connectivity
 60 | > - You can skip this step when prompted during execution
 61 | >
 62 | 
 63 | <details >
 64 | <summary><b>🔒 Disable Auto-Update Feature</b></summary>
 65 | 
 66 | > To prevent Cursor from automatically updating to unsupported new versions, you can choose to disable the auto-update feature.
 67 | 
 68 | #### Method 1: Using Built-in Script (Recommended)
 69 | 
 70 | When running the reset tool, the script will ask if you want to disable auto-updates:
 71 | ```text
 72 | [Question] Do you want to disable Cursor auto-update feature?
 73 | 0) No - Keep default settings (Press Enter)
 74 | 1) Yes - Disable auto-update
 75 | ```
 76 | 
 77 | Select `1` to automatically complete the disable operation.
 78 | 
 79 | #### Method 2: Manual Disable
 80 | 
 81 | **Windows:**
 82 | 1. Close all Cursor processes
 83 | 2. Delete directory: `%LOCALAPPDATA%\cursor-updater`
 84 | 3. Create a file with the same name (without extension) in the same location
 85 | 
 86 | **macOS:**
 87 | ```bash
 88 | # NOTE: As tested, this method only works for version 0.45.11 and below.
 89 | # Close Cursor
 90 | pkill -f "Cursor"
 91 | # Replacing app-update.yml with a blank/read-only file
 92 | cd /Applications/Cursor.app/Contents/Resources
 93 | mv app-update.yml app-update.yml.bak
 94 | touch app-update.yml
 95 | chmod 444 app-update.yml
 96 | 
 97 | # Go to Settings -> Application -> Update, set Mode to none.
 98 | # This must be done to prevent Cursor from checking for updates.
 99 | 
100 | # NOTE: The cursor-updater modification method may no longer be effective
101 | # In any case, remove update directory and create blocking file
102 | rm -rf ~/Library/Application\ Support/Caches/cursor-updater
103 | touch ~/Library/Application\ Support/Caches/cursor-updater
104 | ```
105 | 
106 | **Linux:**
107 | ```bash
108 | # Close Cursor
109 | pkill -f "Cursor"
110 | # Remove update directory and create blocking file
111 | rm -rf ~/.config/cursor-updater
112 | touch ~/.config/cursor-updater
113 | ```
114 | 
115 | > ⚠️ **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.
116 | 
117 | 
118 | </details>
119 | 
120 | ---
121 | 
122 | ### 📝 Description
123 | 
124 | > When you encounter any of these messages:
125 | 
126 | #### Issue 1: Trial Account Limit <p align="right"><a href="#issue1"><img src="https://img.shields.io/badge/Move%20to%20Solution-Blue?style=plastic" alt="Back To Top"></a></p>
127 | 
128 | ```text
129 | Too many free trial accounts used on this machine.
130 | Please upgrade to pro. We have this limit in place
131 | to prevent abuse. Please let us know if you believe
132 | this is a mistake.
133 | ```
134 | 
135 | #### Issue 2: API Key Limitation <p align="right"><a href="#issue2"><img src="https://img.shields.io/badge/Move%20to%20Solution-green?style=plastic" alt="Back To Top"></a></p>
136 | 
137 | ```text
138 | [New Issue]
139 | 
140 | Composer relies on custom models that cannot be billed to an API key.
141 | Please disable API keys and use a Pro or Business subscription.
142 | Request ID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
143 | ```
144 | 
145 | #### Issue 3: Trial Request Limit
146 | 
147 | > This indicates you've reached the usage limit during the VIP free trial period:
148 | 
149 | ```text
150 | You've reached your trial request limit.
151 | ```
152 | 
153 | #### Issue 4: Claude 3.7 High Load <p align="right"><a href="#issue4"><img src="https://img.shields.io/badge/Move%20to%20Solution-purple?style=plastic" alt="Back To Top"></a></p>
154 | 
155 | ```text
156 | High Load 
157 | We're experiencing high demand for Claude 3.7 Sonnet right now. Please upgrade to Pro, or switch to the
158 | 'default' model, Claude 3.5 sonnet, another model, or try again in a few moments.
159 | ```
160 | 
161 | <br>
162 | 
163 | <p id="issue2"></p>
164 | 
165 | #### Solution : Uninstall Cursor Completely And Reinstall (API key Issue)
166 | 
167 | 1. Download [Geek.exe Uninstaller[Free]](https://geekuninstaller.com/download)
168 | 2. Uninstall Cursor app completely
169 | 3. Re-Install Cursor app
170 | 4. Continue to Solution 1
171 | 
172 | <br>
173 | 
174 | <p id="issue1"></p>
175 | 
176 | > Temporary Solution:
177 | 
178 | #### Solution 1: Quick Reset (Recommended)
179 | 
180 | 1. Close Cursor application
181 | 2. Run the machine code reset script (see installation instructions below)
182 | 3. Reopen Cursor to continue using
183 | 
184 | #### Solution 2: Account Switch
185 | 
186 | 1. File -> Cursor Settings -> Sign Out
187 | 2. Close Cursor
188 | 3. Run the machine code reset script
189 | 4. Login with a new account
190 | 
191 | #### Solution 3: Network Optimization
192 | 
193 | If the above solutions don't work, try:
194 | 
195 | - Switch to low-latency nodes (Recommended regions: Japan, Singapore, US, Hong Kong)
196 | - Ensure network stability
197 | - Clear browser cache and retry
198 | 
199 | #### Solution 4: Claude 3.7 Access Issue (High Load)
200 | 
201 | 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:
202 | 
203 | 1. Switch to a new account created with Gmail, possibly connecting through a different IP address
204 | 2. Try accessing during off-peak hours (typically 5-10 AM or 3-7 PM when restrictions are often lighter)
205 | 3. Consider upgrading to Pro for guaranteed access
206 | 4. Use Claude 3.5 Sonnet as a fallback option
207 | 
208 | > Note: These access patterns may change as Cursor adjusts their resource allocation policies.
209 | 
210 | ### 💻 System Support
211 | 
212 | <table>
213 | <tr>
214 | <td>
215 | 
216 | **Windows** ✅
217 | 
218 | - x64 (64-bit)
219 | - x86 (32-bit)
220 | 
221 | </td>
222 | <td>
223 | 
224 | **macOS** ✅
225 | 
226 | - Intel (x64)
227 | - Apple Silicon (M1/M2)
228 | 
229 | </td>
230 | <td>
231 | 
232 | **Linux** ✅
233 | 
234 | - x64 (64-bit)
235 | - x86 (32-bit)
236 | - ARM64
237 | 
238 | </td>
239 | </tr>
240 | </table>
241 | 
242 | 
243 | 
244 | ### 🚀 One-Click Solution
245 | 
246 | <details open>
247 | <summary><b>Global Users</b></summary>
248 | 
249 | **macOS**
250 | 
251 | ```bash
252 | # Method two
253 | 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
254 | ```
255 | 
256 | **Linux**
257 | 
258 | ```bash
259 | curl -fsSL https://raw.githubusercontent.com/yuaotian/go-cursor-help/refs/heads/master/scripts/run/cursor_linux_id_modifier.sh | sudo bash 
260 | ```
261 | 
262 | > **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.
263 | 
264 | **Windows**
265 | 
266 | ```powershell
267 | irm https://raw.githubusercontent.com/yuaotian/go-cursor-help/refs/heads/master/scripts/run/cursor_win_id_modifier.ps1 | iex
268 | ```
269 | 
270 | **Windows (Enhanced Version)**
271 | 
272 | ```powershell
273 | irm https://raw.githubusercontent.com/yuaotian/go-cursor-help/refs/heads/master/scripts/run/cursor_win_id_modifier_new.ps1 | iex
274 | ```
275 | > Enhanced Cursor machine code modifier with dual-mode operation and trial reset functionality
276 | 
277 | <div align="center">
278 | <img src="img/run_success.png" alt="Run Success" width="600"/>
279 | </div>
280 | 
281 | </details>
282 | 
283 | <details open>
284 | <summary><b>China Users (Recommended)</b></summary>
285 | 
286 | **macOS**
287 | 
288 | ```bash
289 | 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
290 | ```
291 | 
292 | **Linux**
293 | 
294 | ```bash
295 | 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
296 | ```
297 | 
298 | **Windows**
299 | 
300 | ```powershell
301 | 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
302 | ```
303 | 
304 | **Windows (Enhanced Version)**
305 | 
306 | ```powershell
307 | 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
308 | ```
309 | > Enhanced Cursor machine code modifier with dual-mode operation and trial reset functionality
310 | 
311 | </details>
312 | 
313 | <details open>
314 | <summary><b>Windows Terminal Run and Configuration</b></summary>
315 | 
316 | #### How to Open Administrator Terminal in Windows:
317 | 
318 | ##### Method 1: Using Win + X Shortcut
319 | ```md
320 | 1. Press Win + X key combination
321 | 2. Select one of these options from the menu:
322 |    - "Windows PowerShell (Administrator)"
323 |    - "Windows Terminal (Administrator)"
324 |    - "Terminal (Administrator)"
325 |    (Options may vary depending on Windows version)
326 | ```
327 | 
328 | ##### Method 2: Using Win + R Run Command
329 | ```md
330 | 1. Press Win + R key combination
331 | 2. Type powershell or pwsh in the Run dialog
332 | 3. Press Ctrl + Shift + Enter to run as administrator
333 |    or type in the opened window: Start-Process pwsh -Verb RunAs
334 | 4. Enter the reset script in the administrator terminal:
335 | 
336 | 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
337 | ```
338 | 
339 | For the enhanced version:
340 | ```powershell
341 | 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
342 | ```
343 | 
344 | ##### Method 3: Using Search
345 | >![Search PowerShell](img/pwsh_1.png)
346 | >
347 | >Type pwsh in the search box, right-click and select "Run as administrator"
348 | >![Run as Administrator](img/pwsh_2.png)
349 | 
350 | Enter the reset script in the administrator terminal:
351 | ```powershell
352 | 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
353 | ```
354 | 
355 | For the enhanced version:
356 | ```powershell
357 | 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
358 | ```
359 | 
360 | ### 🔧 PowerShell Installation Guide 
361 | 
362 | If PowerShell is not installed on your system, you can install it using one of these methods:
363 | 
364 | #### Method 1: Install via Winget (Recommended)
365 | 
366 | 1. Open Command Prompt or PowerShell
367 | 2. Run the following command:
368 | ```powershell
369 | winget install --id Microsoft.PowerShell --source winget
370 | ```
371 | 
372 | #### Method 2: Manual Installation
373 | 
374 | 1. Download the installer for your system:
375 |    - [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)
376 |    - [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)
377 |    - [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)
378 | 
379 | 2. Double-click the downloaded installer and follow the installation prompts
380 | 
381 | > 💡 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)
382 | 
383 | </details>
384 | 
385 | #### Windows 安装特性:
386 | 
387 | - 🔍 Automatically detects and uses PowerShell 7 if available
388 | - 🛡️ Requests administrator privileges via UAC prompt
389 | - 📝 Falls back to Windows PowerShell if PS7 isn't found
390 | - 💡 Provides manual instructions if elevation fails
391 | 
392 | That's it! The script will:
393 | 
394 | 1. ✨ Install the tool automatically
395 | 2. 🔄 Reset your Cursor trial immediately
396 | 
397 | ### 📦 Manual Installation
398 | 
399 | > Download the appropriate file for your system from [releases](https://github.com/yuaotian/go-cursor-help/releases/latest)
400 | 
401 | <details>
402 | <summary>Windows Packages</summary>
403 | 
404 | - 64-bit: `cursor-id-modifier_windows_x64.exe`
405 | - 32-bit: `cursor-id-modifier_windows_x86.exe`
406 | </details>
407 | 
408 | <details>
409 | <summary>macOS Packages</summary>
410 | 
411 | - Intel: `cursor-id-modifier_darwin_x64_intel`
412 | - M1/M2: `cursor-id-modifier_darwin_arm64_apple_silicon`
413 | </details>
414 | 
415 | <details>
416 | <summary>Linux Packages</summary>
417 | 
418 | - 64-bit: `cursor-id-modifier_linux_x64`
419 | - 32-bit: `cursor-id-modifier_linux_x86`
420 | - ARM64: `cursor-id-modifier_linux_arm64`
421 | </details>
422 | 
423 | ### 🔧 Technical Details
424 | 
425 | <details>
426 | <summary><b>Configuration Files</b></summary>
427 | 
428 | The program modifies Cursor's `storage.json` config file located at:
429 | 
430 | - Windows: `%APPDATA%\Cursor\User\globalStorage\storage.json`
431 | - macOS: `~/Library/Application Support/Cursor/User/globalStorage/storage.json`
432 | - Linux: `~/.config/Cursor/User/globalStorage/storage.json`
433 | </details>
434 | 
435 | <details>
436 | <summary><b>Modified Fields</b></summary>
437 | 
438 | The tool generates new unique identifiers for:
439 | 
440 | - `telemetry.machineId`
441 | - `telemetry.macMachineId`
442 | - `telemetry.devDeviceId`
443 | - `telemetry.sqmId`
444 | </details>
445 | 
446 | <details>
447 | <summary><b>Manual Auto-Update Disable</b></summary>
448 | 
449 | Windows users can manually disable the auto-update feature:
450 | 
451 | 1. Close all Cursor processes
452 | 2. Delete directory: `C:\Users\username\AppData\Local\cursor-updater`
453 | 3. Create a file with the same name: `cursor-updater` (without extension)
454 | 
455 | macOS/Linux users can try to locate similar `cursor-updater` directory in their system and perform the same operation.
456 | 
457 | </details>
458 | 
459 | <details>
460 | <summary><b>Safety Features</b></summary>
461 | 
462 | - ✅ Safe process termination
463 | - ✅ Atomic file operations
464 | - ✅ Error handling and recovery
465 | </details>
466 | 
467 | <details>
468 | <summary><b>Registry Modification Notice</b></summary>
469 | 
470 | > ⚠️ **Important: This tool modifies the Windows Registry**
471 | 
472 | #### Modified Registry
473 | - Path: `Computer\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography`
474 | - Key: `MachineGuid`
475 | 
476 | #### Potential Impact
477 | Modifying this registry key may affect:
478 | - Windows system's unique device identification
479 | - Device recognition and authorization status of certain software
480 | - System features based on hardware identification
481 | 
482 | #### Safety Measures
483 | 1. Automatic Backup
484 |    - Original value is automatically backed up before modification
485 |    - Backup location: `%APPDATA%\Cursor\User\globalStorage\backups`
486 |    - Backup file format: `MachineGuid.backup_YYYYMMDD_HHMMSS`
487 | 
488 | 2. Manual Recovery Steps
489 |    - Open Registry Editor (regedit)
490 |    - Navigate to: `Computer\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography`
491 |    - Right-click on `MachineGuid`
492 |    - Select "Modify"
493 |    - Paste the value from backup file
494 | 
495 | #### Important Notes
496 | - Verify backup file existence before modification
497 | - Use backup file to restore original value if needed
498 | - Administrator privileges required for registry modification
499 | </details>
500 | 
501 | ---
502 | 
503 | ### 📚 Recommended Reading
504 | 
505 | - [Cursor Issues Collection and Solutions](https://mp.weixin.qq.com/s/pnJrH7Ifx4WZvseeP1fcEA)
506 | - [AI Universal Development Assistant Prompt Guide](https://mp.weixin.qq.com/s/PRPz-qVkFJSgkuEKkTdzwg)
507 | 
508 | ---
509 | 
510 | ## 💬 Feedback & Suggestions
511 | 
512 | 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:
513 | 
514 | - 🐛 **Bug Reports**: Found any issues? Let us know!
515 | - 💡 **Feature Suggestions**: Have ideas for improvements?
516 | - ⭐ **Success Stories**: Share how the tool helped you!
517 | - 🔧 **Technical Feedback**: Performance, compatibility, or usability insights
518 | 
519 | Your feedback helps us improve the tool for everyone. Feel free to open an issue or contribute to the project!
520 | 
521 | ---
522 | 
523 | ##  Support
524 | 
525 | <div align="center">
526 | <b>If you find this helpful, consider buying me a spicy gluten snack (Latiao) as appreciation~ 💁☕️</b>
527 | <table>
528 | <tr>
529 | 
530 | <td align="center">
531 | <b>微信赞赏</b><br>
532 | <img src="img/wx_zsm2.png" width="500" alt="微信赞赏码"><br>
533 | <small>要到饭咧?啊咧?啊咧?不给也没事~ 请随意打赏</small>
534 | </td>
535 | <td align="center">
536 | <b>支付宝赞赏</b><br>
537 | <img src="img/alipay.png" width="500" alt="支付宝赞赏码"><br>
538 | <small>如果觉得有帮助,来包辣条犒劳一下吧~</small>
539 | </td>
540 | <td align="center">
541 | <b>Alipay</b><br>
542 | <img src="img/alipay_scan_pay.jpg" width="500" alt="Alipay"><br>
543 | <em>1 Latiao = 1 AI thought cycle</em>
544 | </td>
545 | <td align="center">
546 | <b>WeChat</b><br>
547 | <img src="img/qun-15.jpg" width="500" alt="WeChat"><br>
548 | <em>二维码7天内(7月14日前)有效,过期请加微信</em>
549 | </td>
550 | <!-- <td align="center">
551 | <b>ETC</b><br>
552 | <img src="img/etc.png" width="100" alt="ETC Address"><br>
553 | ETC: 0xa2745f4CD5d32310AC01694ABDB28bA32D125a6b
554 | </td>
555 | <td align="center"> -->
556 | </td>
557 | </tr>
558 | </table>
559 | </div>
560 | 
561 | ---
562 | 
563 | ## ⭐ Project Stats
564 | 
565 | <div align="center">
566 | 
567 | [![Star History Chart](https://api.star-history.com/svg?repos=yuaotian/go-cursor-help&type=Date)](https://star-history.com/#yuaotian/go-cursor-help&Date)
568 | 
569 | ![Repobeats analytics image](https://repobeats.axiom.co/api/embed/ddaa9df9a94b0029ec3fad399e1c1c4e75755477.svg "Repobeats analytics image")
570 | 
571 | </div>
572 | 
573 | ## 📄 License
574 | 
575 | <details>
576 | <summary><b>MIT License</b></summary>
577 | 
578 | Copyright (c) 2024
579 | 
580 | Permission is hereby granted, free of charge, to any person obtaining a copy
581 | of this software and associated documentation files (the "Software"), to deal
582 | in the Software without restriction, including without limitation the rights
583 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
584 | copies of the Software, and to permit persons to whom the Software is
585 | furnished to do so, subject to the following conditions:
586 | 
587 | The above copyright notice and this permission notice shall be included in all
588 | copies or substantial portions of the Software.
589 | 
590 | </details>
591 | 
592 | 


--------------------------------------------------------------------------------
/README_CN.md:
--------------------------------------------------------------------------------
  1 | # 🚀 Cursor 免费试用重置工具
  2 | 
  3 | <div align="center">
  4 | 
  5 | [![Release](https://img.shields.io/github/v/release/yuaotian/go-cursor-help?style=flat-square&logo=github&color=blue)](https://github.com/yuaotian/go-cursor-help/releases/latest)
  6 | [![License](https://img.shields.io/badge/license-MIT-blue.svg?style=flat-square&logo=bookstack)](https://github.com/yuaotian/go-cursor-help/blob/master/LICENSE)
  7 | [![Stars](https://img.shields.io/github/stars/yuaotian/go-cursor-help?style=flat-square&logo=github)](https://github.com/yuaotian/go-cursor-help/stargazers)
  8 | 
  9 | [🌟 English](README.md) | [🌏 中文](README_CN.md) | [🌏 日本語](README_JP.md)
 10 | 
 11 | <img src="https://ai-cursor.com/wp-content/uploads/2024/09/logo-cursor-ai-png.webp" alt="Cursor Logo" width="120"/>
 12 | 
 13 | 
 14 |  
 15 | > ⚠️ **重要提示**
 16 | > 
 17 | > 本工具当前支持版本:
 18 | > - ✅ Windows: 最新的 1.0.x 版本(已支持)
 19 | > - ✅ Mac/Linux: 最新的 1.0.x 版本(已支持,欢迎测试并反馈问题)
 20 |  
 21 | > 使用前请确认您的 Cursor 版本。
 22 | 
 23 | <details open>
 24 | <summary><b>📦 版本历史与下载</b></summary>
 25 | 
 26 | <div class="version-card" style="background: linear-gradient(135deg, #6e8efb, #a777e3); border-radius: 8px; padding: 15px; margin: 10px 0; color: white;">
 27 | 
 28 | 
 29 | [查看完整版本历史]([CursorHistoryDown.md](https://github.com/oslook/cursor-ai-downloads?tab=readme-ov-file))
 30 | 
 31 | </div>
 32 | 
 33 | 
 34 | </details>
 35 | 
 36 | ⚠️ **Cursor通用解决方案**
 37 | > 1.  关闭Cursor、退出账号、官网Setting删除账号(刷新节点IP:日本、新加坡、 美国、香港,低延迟为主不一定需要但是有条件就换,Windows用户建议刷新DNS缓存:`ipconfig /flushdns`)
 38 | > 前往Cursor官网删除当前账号
 39 | > 步骤:用户头像->Setting-左下角Advanced▼->Delete Account
 40 | >
 41 | > 2.  刷新机器码脚本,看下面脚本地址,国内可用
 42 | > 
 43 | > 3.  重新注册账号、登录、打开Cursor,即可恢复正常使用。
 44 | >
 45 | > 4.  备用方案:如果步骤 [**3**] 后仍不可用,或者遇到注册账号失败、无法删除账号等问题,这通常意味着您的浏览器被目标网站识别或限制(风控)。此时,请尝试更换浏览器,例如:Edge、Google Chrome、Firefox。(或者,可以尝试使用能够修改或随机化浏览器指纹信息的浏览器)。
 46 | 
 47 | 
 48 | 关注大佬公众号:煎饼果子卷AI
 49 | 
 50 | 
 51 | ---
 52 | 
 53 | > ⚠️ **MAC地址修改警告**
 54 | > 
 55 | > Mac用户请注意: 本脚本包含MAC地址修改功能,将会:
 56 | > - 修改您的网络接口MAC地址
 57 | > - 在修改前备份原始MAC地址
 58 | > - 此修改可能会暂时影响网络连接
 59 | > - 执行过程中可以选择跳过此步骤
 60 | 
 61 | ---
 62 | 
 63 | ### 📝 问题描述
 64 | 
 65 | > 当您遇到以下任何消息时:
 66 | 
 67 | #### 问题 1: 试用账号限制 <p align="right"><a href="#solution1"><img src="https://img.shields.io/badge/跳转到解决方案-Blue?style=plastic" alt="跳转到顶部"></a></p>
 68 | 
 69 | ```text
 70 | Too many free trial accounts used on this machine.
 71 | Please upgrade to pro. We have this limit in place
 72 | to prevent abuse. Please let us know if you believe
 73 | this is a mistake.
 74 | ```
 75 | 
 76 | #### 问题 2: API密钥限制 <p align="right"><a href="#solution2"><img src="https://img.shields.io/badge/跳转到解决方案-green?style=plastic" alt="跳转到顶部"></a></p>
 77 | 
 78 | ```text
 79 | [New Issue]
 80 | 
 81 | Composer relies on custom models that cannot be billed to an API key.
 82 | Please disable API keys and use a Pro or Business subscription.
 83 | Request ID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
 84 | ```
 85 | 
 86 | #### 问题 3: 试用请求限制
 87 | 
 88 | > 这表明您在VIP免费试用期间已达到使用限制:
 89 | 
 90 | ```text
 91 | You've reached your trial request limit.
 92 | ```
 93 | 
 94 | #### 问题 4: Claude 3.7 高负载 (High Load)  <p align="right"><a href="#solution4"><img src="https://img.shields.io/badge/跳转到解决方案-purple?style=plastic" alt="跳转到顶部"></a></p>
 95 | 
 96 | ```text
 97 | High Load 
 98 | We're experiencing high demand for Claude 3.7 Sonnet right now. Please upgrade to Pro, or switch to the
 99 | 'default' model, Claude 3.5 sonnet, another model, or try again in a few moments.
100 | ```
101 | 
102 | <br>
103 | 
104 | <p id="solution2"></p>
105 | 
106 | #### 解决方案:完全卸载Cursor并重新安装(API密钥问题)
107 | 
108 | 1. 下载 [Geek.exe 卸载工具[免费]](https://geekuninstaller.com/download)
109 | 2. 完全卸载Cursor应用
110 | 3. 重新安装Cursor应用
111 | 4. 继续执行解决方案1
112 | 
113 | <br>
114 | 
115 | <p id="solution1"></p>
116 | 
117 | > 临时解决方案:
118 | 
119 | #### 解决方案 1: 快速重置(推荐)
120 | 
121 | 1. 关闭Cursor应用
122 | 2. 运行机器码重置脚本(见下方安装说明)
123 | 3. 重新打开Cursor继续使用
124 | 
125 | #### 解决方案 2: 切换账号
126 | 
127 | 1. 文件 -> Cursor设置 -> 退出登录
128 | 2. 关闭Cursor
129 | 3. 运行机器码重置脚本
130 | 4. 使用新账号登录
131 | 
132 | #### 解决方案 3: 网络优化
133 | 
134 | 如果上述解决方案不起作用,请尝试:
135 | 
136 | - 切换到低延迟节点(推荐区域:日本、新加坡、美国、香港)
137 | - 确保网络稳定性
138 | - 清除浏览器缓存并重试
139 | 
140 | <p id="solution4"></p>
141 | 
142 | #### 解决方案 4: Claude 3.7 访问问题(High Load )
143 | 
144 | 如果您看到Claude 3.7 Sonnet的"High Load"(高负载)消息,这表明Cursor在一天中某些时段限制免费试用账号使用3.7模型。请尝试:
145 | 
146 | 1. 使用Gmail邮箱创建新账号,可能需要通过不同IP地址连接
147 | 2. 尝试在非高峰时段访问(通常在早上5-10点或下午3-7点之间限制较少)
148 | 3. 考虑升级到Pro版本获取保证访问权限
149 | 4. 使用Claude 3.5 Sonnet作为备选方案
150 | 
151 | > 注意:随着Cursor调整资源分配策略,这些访问模式可能会发生变化。
152 | 
153 | ### 🚀 系统支持
154 | 
155 | <table>
156 | <tr>
157 | <td>
158 | 
159 | **Windows** ✅
160 | 
161 | - x64 & x86
162 | 
163 | </td>
164 | <td>
165 | 
166 | **macOS** ✅
167 | 
168 | - Intel & M-series
169 | 
170 | </td>
171 | <td>
172 | 
173 | **Linux** ✅
174 | 
175 | - x64 & ARM64
176 | 
177 | </td>
178 | </tr>
179 | </table>
180 | 
181 | 
182 | 
183 | ### 🚀 一键解决方案
184 | 
185 | <details open>
186 | <summary><b>国内用户(推荐)</b></summary>
187 | 
188 | **macOS**
189 | 
190 | ```bash
191 | 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
192 | ```
193 | 
194 | **Linux**
195 | 
196 | ```bash
197 | 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
198 | ```
199 | 
200 | > **Linux 用户请注意:** 该脚本通过检查常用路径(`/usr/bin`, `/usr/local/bin`, `$HOME/.local/bin`, `/opt/cursor`, `/snap/bin`)、使用 `which cursor` 命令以及在 `/usr`、`/opt` 和 `$HOME/.local` 目录内搜索,来尝试定位您的 Cursor 安装。如果 Cursor 安装在其他位置或通过这些方法无法找到,脚本可能会失败。请确保可以通过这些标准位置或方法之一访问到 Cursor。
201 | 
202 | **Windows**
203 | 
204 | ```powershell
205 | 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
206 | ```
207 | 
208 | **Windows (增强版)**
209 | 
210 | ```powershell
211 | 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
212 | ```
213 | > 增强版Cursor机器码修改工具,支持双模式操作和试用重置功能
214 | <div align="center">
215 | <img src="img/run_success.png" alt="运行成功" width="600"/>
216 | </div>
217 | 
218 | </details>
219 | <details open>
220 | <summary><b>Windows 管理员终端运行和手动安装</b></summary>
221 | 
222 | #### Windows 系统打开管理员终端的方法:
223 | 
224 | ##### 方法一:使用 Win + X 快捷键
225 | ```md
226 | 1. 按下 Win + X 组合键
227 | 2. 在弹出的菜单中选择以下任一选项:
228 |    - "Windows PowerShell (管理员)"
229 |    - "Windows Terminal (管理员)" 
230 |    - "终端(管理员)"
231 |    (具体选项因Windows版本而异)
232 | ```
233 | 
234 | ##### 方法二:使用 Win + R 运行命令
235 | ```md
236 | 1. 按下 Win + R 组合键
237 | 2. 在运行框中输入 powershell 或 pwsh
238 | 3. 按 Ctrl + Shift + Enter 以管理员身份运行
239 |    或在打开的窗口中输入: Start-Process pwsh -Verb RunAs
240 | 4. 在管理员终端中输入以下重置脚本:
241 | 
242 | 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
243 | ```
244 | 
245 | 增强版脚本:
246 | ```powershell
247 | 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
248 | ```
249 | 
250 | ##### 方法三:通过搜索启动
251 | >![搜索 PowerShell](img/pwsh_1.png)
252 | >
253 | >在搜索框中输入 pwsh,右键选择"以管理员身份运行"
254 | >![管理员运行](img/pwsh_2.png)
255 | 
256 | 在管理员终端中输入重置脚本:
257 | ```powershell
258 | 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
259 | ```
260 | 
261 | 增强版脚本:
262 | ```powershell
263 | 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
264 | ```
265 | 
266 | ### 🔧 PowerShell 安装指南
267 | 
268 | 如果您的系统没有安装 PowerShell,可以通过以下方法安装:
269 | 
270 | #### 方法一:使用 Winget 安装(推荐)
271 | 
272 | 1. 打开命令提示符或 PowerShell
273 | 2. 运行以下命令:
274 | ```powershell
275 | winget install --id Microsoft.PowerShell --source winget
276 | ```
277 | 
278 | #### 方法二:手动下载安装
279 | 
280 | 1. 下载对应系统的安装包:
281 |    - [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位系统)
282 |    - [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位系统)
283 |    - [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系统)
284 | 
285 | 2. 双击下载的安装包,按提示完成安装
286 | 
287 | > 💡 如果仍然遇到问题,可以参考 [Microsoft 官方安装指南](https://learn.microsoft.com/zh-cn/powershell/scripting/install/installing-powershell-on-windows)
288 | 
289 | </details>
290 | 
291 | #### Windows 安装特性:
292 | 
293 | - 🔍 自动检测并使用 PowerShell 7(如果可用)
294 | - 🛡️ 通过 UAC 提示请求管理员权限
295 | - 📝 如果没有 PS7 则使用 Windows PowerShell
296 | - 💡 如果提权失败会提供手动说明
297 | 
298 | 完成后,脚本将:
299 | 
300 | 1. ✨ 自动安装工具
301 | 2. 🔄 立即重置 Cursor 试用期
302 | 
303 | ### 📦 手动安装
304 | 
305 | > 从 [releases](https://github.com/yuaotian/go-cursor-help/releases/latest) 下载适合您系统的文件
306 | 
307 | <details>
308 | <summary>Windows 安装包</summary>
309 | 
310 | - 64 位: `cursor-id-modifier_windows_x64.exe`
311 | - 32 位: `cursor-id-modifier_windows_x86.exe`
312 | </details>
313 | 
314 | <details>
315 | <summary>macOS 安装包</summary>
316 | 
317 | - Intel: `cursor-id-modifier_darwin_x64_intel`
318 | - M1/M2: `cursor-id-modifier_darwin_arm64_apple_silicon`
319 | </details>
320 | 
321 | <details>
322 | <summary>Linux 安装包</summary>
323 | 
324 | - 64 位: `cursor-id-modifier_linux_x64`
325 | - 32 位: `cursor-id-modifier_linux_x86`
326 | - ARM64: `cursor-id-modifier_linux_arm64`
327 | </details>
328 | 
329 | ### 🔧 技术细节
330 | 
331 | <details>
332 | <summary><b>注册表修改说明</b></summary>
333 | 
334 | > ⚠️ **重要提示:本工具会修改系统注册表**
335 | 
336 | #### 修改内容
337 | - 路径:`计算机\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography`
338 | - 项目:`MachineGuid`
339 | 
340 | #### 潜在影响
341 | 修改此注册表项可能会影响:
342 | - Windows 系统对设备的唯一标识
343 | - 某些软件的设备识别和授权状态
344 | - 基于硬件标识的系统功能
345 | 
346 | #### 安全措施
347 | 1. 自动备份
348 |    - 每次修改前会自动备份原始值
349 |    - 备份保存在:`%APPDATA%\Cursor\User\globalStorage\backups`
350 |    - 备份文件格式:`MachineGuid.backup_YYYYMMDD_HHMMSS`
351 | 
352 | 2. 手动恢复方法
353 |    - 打开注册表编辑器(regedit)
354 |    - 定位到:`计算机\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography`
355 |    - 右键点击 `MachineGuid`
356 |    - 选择"修改"
357 |    - 粘贴备份文件中的值
358 | 
359 | #### 注意事项
360 | - 建议在修改前先确认备份文件的存在
361 | - 如遇问题可通过备份文件恢复原始值
362 | - 必须以管理员权限运行才能修改注册表
363 | </details>
364 | 
365 | <details>
366 | <summary><b>配置文件</b></summary>
367 | 
368 | 程序修改 Cursor 的`storage.json`配置文件,位于:
369 | 
370 | - Windows: `%APPDATA%\Cursor\User\globalStorage\`
371 | - macOS: `~/Library/Application Support/Cursor/User/globalStorage/`
372 | - Linux: `~/.config/Cursor/User/globalStorage/`
373 | </details>
374 | 
375 | <details>
376 | <summary><b>修改字段</b></summary>
377 | 
378 | 工具会生成新的唯一标识符:
379 | 
380 | - `telemetry.machineId`
381 | - `telemetry.macMachineId`
382 | - `telemetry.devDeviceId`
383 | - `telemetry.sqmId`
384 | </details>
385 | 
386 | <details>
387 | <summary><b>手动禁用自动更新</b></summary>
388 | 
389 | Windows 用户可以手动禁用自动更新功能:
390 | 
391 | 1. 关闭所有 Cursor 进程
392 | 2. 删除目录:`C:\Users\用户名\AppData\Local\cursor-updater`
393 | 3. 创建同名文件:`cursor-updater`(不带扩展名)
394 | 
395 | Linux用户可以尝试在系统中找到类似的`cursor-updater`目录进行相同操作。
396 | 
397 | MacOS用户按照以下步骤操作:
398 | 
399 | ```bash
400 | # 注意:经测试,此方法仅适用于0.45.11及以下版本,不支持0.46.*版本
401 | # 关闭所有 Cursor 进程
402 | pkill -f "Cursor"
403 | 
404 | # 备份app-update.yml并创建空的只读文件代替原文件
405 | cd /Applications/Cursor.app/Contents/Resources
406 | mv app-update.yml app-update.yml.bak
407 | touch app-update.yml
408 | chmod 444 app-update.yml
409 | 
410 | # 打开Cursor设置,将更新模式设置为"无",该步骤必须执行,否则Cursor依然会自动检查更新
411 | # 步骤:Settings -> Application -> Update, 将Mode设置为none
412 | 
413 | # 注意: cursor-updater修改方法可能已失效。但为了以防万一,还是删除更新目录并创建阻止文件
414 | rm -rf ~/Library/Application\ Support/Caches/cursor-updater
415 | touch ~/Library/Application\ Support/Caches/cursor-updater
416 | ```
417 | </details>
418 | 
419 | <details>
420 | <summary><b>安全特性</b></summary>
421 | 
422 | - ✅ 安全的进程终止
423 | - ✅ 原子文件操作
424 | - ✅ 错误处理和恢复
425 | </details>
426 | 
427 | <details>
428 | <summary><b>重置 Cursor 免费试用</b></summary>
429 | 
430 | ### 使用 `cursor_free_trial_reset.sh` 脚本
431 | 
432 | #### macOS
433 | 
434 | ```bash
435 | 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
436 | ```
437 | 
438 | #### Linux
439 | 
440 | ```bash
441 | curl -fsSL https://raw.githubusercontent.com/yuaotian/go-cursor-help/refs/heads/master/scripts/run/cursor_free_trial_reset.sh | sudo bash
442 | ```
443 | 
444 | #### Windows
445 | 
446 | ```powershell
447 | irm https://raw.githubusercontent.com/yuaotian/go-cursor-help/refs/heads/master/scripts/run/cursor_free_trial_reset.sh | iex
448 | ```
449 | 
450 | </details>
451 | 
452 | ## 联系方式
453 | 
454 | <div align="center">
455 | <table>
456 | <tr>
457 | <td align="center">
458 | <b>个人微信</b><br>
459 | <img src="img/wx_me.png" width="250" alt="作者微信"><br>
460 | <b>微信:JavaRookie666</b>
461 | </td>
462 | <td align="center">
463 | <b>微信交流群</b><br>
464 | <img src="img/qun-15.jpg" width="500" alt="WeChat"><br>
465 | <small>二维码7天内(7月14日前)有效,过期请加微信</small>
466 | </td>
467 | <td align="center">
468 | <b>公众号</b><br>
469 | <img src="img/wx_public_2.png" width="250" alt="微信公众号"><br>
470 | <small>获取更多AI开发资源</small>
471 | </td>
472 | <td align="center">
473 | <b>微信赞赏</b><br>
474 | <img src="img/wx_zsm2.png" width="500" alt="微信赞赏码"><br>
475 | <small>要到饭咧?啊咧?啊咧?不给也没事~ 请随意打赏</small>
476 | </td>
477 | <td align="center">
478 | <b>支付宝赞赏</b><br>
479 | <img src="img/alipay.png" width="500" alt="支付宝赞赏码"><br>
480 | <small>如果觉得有帮助,来包辣条犒劳一下吧~</small>
481 | </td>
482 | </tr>
483 | </table>
484 | </div>
485 | 
486 | ---
487 | 
488 | ### 📚 推荐阅读
489 | 
490 | - [Cursor 异常问题收集和解决方案](https://mp.weixin.qq.com/s/pnJrH7Ifx4WZvseeP1fcEA)
491 | - [AI 通用开发助手提示词指南](https://mp.weixin.qq.com/s/PRPz-qVkFJSgkuEKkTdzwg)
492 | 
493 | ---
494 | 
495 | ## 💬 反馈与建议
496 | 
497 | 我们非常重视您对新增强脚本的反馈!如果您已经尝试了 `cursor_win_id_modifier_new.ps1` 脚本,请分享您的使用体验:
498 | 
499 | - 🐛 **错误报告**:发现任何问题?请告诉我们!
500 | - 💡 **功能建议**:有改进想法?
501 | - ⭐ **成功案例**:分享工具如何帮助到您!
502 | - 🔧 **技术反馈**:性能、兼容性或易用性方面的见解
503 | 
504 | 您的反馈帮助我们为所有人改进工具。欢迎提交issue或为项目做出贡献!
505 | 
506 | ---
507 | 
508 | ## ⭐ 项目统计
509 | 
510 | <div align="center">
511 | 
512 | [![Star History Chart](https://api.star-history.com/svg?repos=yuaotian/go-cursor-help&type=Date)](https://star-history.com/#yuaotian/go-cursor-help&Date)
513 | 
514 | ![Repobeats analytics image](https://repobeats.axiom.co/api/embed/ddaa9df9a94b0029ec3fad399e1c1c4e75755477.svg "Repobeats analytics image")
515 | 
516 | </div>
517 | 
518 | ## 📄 许可证
519 | 
520 | <details>
521 | <summary><b>MIT 许可证</b></summary>
522 | 
523 | Copyright (c) 2024
524 | 
525 | Permission is hereby granted, free of charge, to any person obtaining a copy
526 | of this software and associated documentation files (the "Software"), to deal
527 | in the Software without restriction, including without limitation the rights
528 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
529 | copies of the Software, and to permit persons to whom the Software is
530 | furnished to do so, subject to the following conditions:
531 | 
532 | The above copyright notice and this permission notice shall be included in all
533 | copies or substantial portions of the Software.
534 | 
535 | </details>
536 | 


--------------------------------------------------------------------------------
/README_JP.md:
--------------------------------------------------------------------------------
  1 | # 🚀 Cursor 無料試用リセットツール
  2 | 
  3 | <div align="center">
  4 | 
  5 | [![Release](https://img.shields.io/github/v/release/yuaotian/go-cursor-help?style=flat-square&logo=github&color=blue)](https://github.com/yuaotian/go-cursor-help/releases/latest)
  6 | [![License](https://img.shields.io/badge/license-MIT-blue.svg?style=flat-square&logo=bookstack)](https://github.com/yuaotian/go-cursor-help/blob/master/LICENSE)
  7 | [![Stars](https://img.shields.io/github/stars/yuaotian/go-cursor-help?style=flat-square&logo=github)](https://github.com/yuaotian/go-cursor-help/stargazers)
  8 | 
  9 | [🌟 English](README.md) | [🌏 中文](README_CN.md) | [🌏 日本語](README_JP.md)
 10 | 
 11 | <img src="https://ai-cursor.com/wp-content/uploads/2024/09/logo-cursor-ai-png.webp" alt="Cursor Logo" width="120"/>
 12 | 
 13 | 
 14 | 
 15 | </div>
 16 | 
 17 | > ⚠️ **重要なお知らせ**
 18 | > 
 19 | > このツールは現在以下のバージョンをサポートしています:
 20 | > - ✅ Windows: 最新の1.0.xバージョン(サポート済み)
 21 | > - ✅ Mac/Linux: 最新の1.0.xバージョン(サポート済み、フィードバック歓迎)
 22 | >
 23 | > このツールを使用する前に、Cursorのバージョンを確認してください。
 24 | 
 25 | <details open>
 26 | <summary><b>📦 バージョン履歴とダウンロード</b></summary>
 27 | 
 28 | <div class="version-card" style="background: linear-gradient(135deg, #6e8efb, #a777e3); border-radius: 8px; padding: 15px; margin: 10px 0; color: white;">
 29 | 
 30 | ### 🌟 最新バージョン
 31 | 
 32 | [完全なバージョン履歴を見る]([CursorHistoryDown.md](https://github.com/oslook/cursor-ai-downloads?tab=readme-ov-file))
 33 | 
 34 | </div>
 35 | 
 36 | </details>
 37 | 
 38 | ⚠️ **Cursorの一般的な解決策**
 39 | > 1.  Cursorを閉じ、アカウントからログアウトし、公式サイトの設定からアカウントを削除します(IPノードを更新:日本、シンガポール、アメリカ、香港など、低遅延を優先。必須ではありませんが条件が整えば変更してください。Windowsユーザーの場合はDNSキャッシュの更新をお勧めします:`ipconfig /flushdns`)
 40 | > Cursor公式サイトで現在のアカウントを削除します
 41 | > 手順:ユーザーアイコン->設定->左下のAdvanced▼->Delete Account
 42 | >
 43 | > 2.  マシンコードリセットスクリプトを実行します。下記のスクリプトアドレスを参照してください。
 44 | > 
 45 | > 3.  アカウントを再登録し、ログインして、Cursorを開くと、正常に使用できるようになります。
 46 | >
 47 | > 4.  代替案:ステップ[**3**]の後でもまだ使用できない場合、またはアカウント登録に失敗したり、アカウントを削除できないなどの問題が発生した場合、これは通常、ブラウザがターゲットサイトに識別または制限されている(リスク管理)ことを意味します。この場合、Edge、Google Chrome、Firefoxなど別のブラウザを試してみてください(または、ブラウザのフィンガープリント情報を変更またはランダム化できるブラウザの使用を検討してください)。
 48 | 
 49 | 
 50 | ---
 51 | 
 52 | ⚠️ **MACアドレス変更警告**
 53 | > 
 54 | > Macユーザーの皆様へ: このスクリプトにはMACアドレス変更機能が含まれています。以下の操作が行われます:
 55 | > - ネットワークインターフェースのMACアドレスを変更します
 56 | > - 変更前に元のMACアドレスをバックアップします
 57 | > - この変更により一時的にネットワーク接続が影響を受ける可能性があります
 58 | > - 実行中にこのステップをスキップすることができます
 59 | >
 60 | 
 61 | <details >
 62 | <summary><b>🔒 自動更新機能の無効化</b></summary>
 63 | 
 64 | > Cursorがサポートされていない新しいバージョンに自動的に更新されるのを防ぐために、自動更新機能を無効にすることができます。
 65 | 
 66 | #### 方法1: 組み込みスクリプトを使用する(推奨)
 67 | 
 68 | リセットツールを実行するとき、スクリプトは自動更新を無効にするかどうかを尋ねます:
 69 | ```text
 70 | [質問] Cursorの自動更新機能を無効にしますか?
 71 | 0) いいえ - デフォルト設定を維持(Enterキーを押す)
 72 | 1) はい - 自動更新を無効にする
 73 | ```
 74 | 
 75 | `1`を選択して無効化操作を自動的に完了します。
 76 | 
 77 | #### 方法2: 手動で無効化
 78 | 
 79 | **Windows:**
 80 | 1. すべてのCursorプロセスを閉じます
 81 | 2. ディレクトリを削除します: `%LOCALAPPDATA%\cursor-updater`
 82 | 3. 同じ名前のファイルを作成します(拡張子なし)
 83 | 
 84 | **macOS:**
 85 | ```bash
 86 | # 注意: テスト済みでは、この方法はバージョン0.45.11およびそれ以前のバージョンでのみ機能します。
 87 | # Cursorを閉じます
 88 | pkill -f "Cursor"
 89 | # app-update.ymlを空の読み取り専用ファイルに置き換えます
 90 | cd /Applications/Cursor.app/Contents/Resources
 91 | mv app-update.yml app-update.yml.bak
 92 | touch app-update.yml
 93 | chmod 444 app-update.yml
 94 | 
 95 | # 設定 -> アプリケーション -> 更新、モードをnoneに設定します。
 96 | # これを行わないと、Cursorは更新をチェックし続けます。
 97 | 
 98 | # 注意: cursor-updaterの変更方法はもはや有効ではないかもしれません
 99 | # いずれにせよ、更新ディレクトリを削除し、ブロックファイルを作成します
100 | rm -rf ~/Library/Application\ Support/Caches/cursor-updater
101 | touch ~/Library/Application\ Support/Caches/cursor-updater
102 | ```
103 | 
104 | **Linux:**
105 | ```bash
106 | # Cursorを閉じます
107 | pkill -f "Cursor"
108 | # 更新ディレクトリを削除し、ブロックファイルを作成します
109 | rm -rf ~/.config/cursor-updater
110 | touch ~/.config/cursor-updater
111 | ```
112 | 
113 | > ⚠️ **注意:** 自動更新を無効にした後、新しいバージョンを手動でダウンロードしてインストールする必要があります。新しいバージョンが互換性があることを確認した後に更新することをお勧めします。
114 | 
115 | </details>
116 | 
117 | ---
118 | 
119 | ### 📝 説明
120 | 
121 | > これらのメッセージのいずれかに遭遇した場合:
122 | 
123 | #### 問題1: 試用アカウント制限 <p align="right"><a href="#issue1"><img src="https://img.shields.io/badge/Move%20to%20Solution-Blue?style=plastic" alt="Back To Top"></a></p>
124 | 
125 | ```text
126 | Too many free trial accounts used on this machine.
127 | Please upgrade to pro. We have this limit in place
128 | to prevent abuse. Please let us know if you believe
129 | this is a mistake.
130 | ```
131 | 
132 | #### 問題2: APIキー制限 <p align="right"><a href="#issue2"><img src="https://img.shields.io/badge/Move%20to%20Solution-green?style=plastic" alt="Back To Top"></a></p>
133 | 
134 | ```text
135 | [New Issue]
136 | 
137 | Composer relies on custom models that cannot be billed to an API key.
138 | Please disable API keys and use a Pro or Business subscription.
139 | Request ID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
140 | ```
141 | 
142 | #### 問題3: 試用リクエスト制限
143 | 
144 | > これは、VIP無料試用期間中に使用制限に達したことを示しています:
145 | 
146 | ```text
147 | You've reached your trial request limit.
148 | ```
149 | 
150 | #### 問題4: Claude 3.7 高負荷 <p align="right"><a href="#issue4"><img src="https://img.shields.io/badge/Move%20to%20Solution-purple?style=plastic" alt="Back To Top"></a></p>
151 | 
152 | ```text
153 | High Load 
154 | We're experiencing high demand for Claude 3.7 Sonnet right now. Please upgrade to Pro, or switch to the
155 | 'default' model, Claude 3.5 sonnet, another model, or try again in a few moments.
156 | ```
157 | 
158 | <br>
159 | 
160 | <p id="issue2"></p>
161 | 
162 | #### 解決策 : Cursorを完全にアンインストールして再インストールする(APIキーの問題)
163 | 
164 | 1. [Geek.exeアンインストーラー[無料]](https://geekuninstaller.com/download)をダウンロードします
165 | 2. Cursorアプリを完全にアンインストールします
166 | 3. Cursorアプリを再インストールします
167 | 4. 解決策1を続行します
168 | 
169 | <br>
170 | 
171 | <p id="issue1"></p>
172 | 
173 | > 一時的な解決策:
174 | 
175 | #### 解決策1: クイックリセット(推奨)
176 | 
177 | 1. Cursorアプリケーションを閉じます
178 | 2. マシンコードリセットスクリプトを実行します(以下のインストール手順を参照)
179 | 3. Cursorを再度開いて使用を続けます
180 | 
181 | #### 解決策2: アカウントの切り替え
182 | 
183 | 1. ファイル -> Cursor設定 -> サインアウト
184 | 2. Cursorを閉じます
185 | 3. マシンコードリセットスクリプトを実行します
186 | 4. 新しいアカウントでログインします
187 | 
188 | #### 解決策3: ネットワークの最適化
189 | 
190 | 上記の解決策が機能しない場合は、次のことを試してください:
191 | 
192 | - 低遅延ノードに切り替えます(推奨地域:日本、シンガポール、米国、香港)
193 | - ネットワークの安定性を確保します
194 | - ブラウザのキャッシュをクリアして再試行します
195 | 
196 | #### 解決策4: Claude 3.7 アクセス問題(高負荷)
197 | 
198 | Claude 3.7 Sonnetの"High Load"メッセージが表示された場合、これはCursorが特定の時間帯に無料試用アカウントの3.7モデルの使用を制限していることを示しています。次のことを試してください:
199 | 
200 | 1. Gmailで作成した新しいアカウントに切り替えます。異なるIPアドレスを使用して接続することをお勧めします
201 | 2. 非ピーク時間帯にアクセスを試みます(通常、5-10 AMまたは3-7 PMの間に制限が少ないです)
202 | 3. Proにアップグレードしてアクセスを保証します
203 | 4. Claude 3.5 Sonnetを代替オプションとして使用します
204 | 
205 | > 注意: Cursorがリソース配分ポリシーを調整するにつれて、これらのアクセスパターンは変更される可能性があります。
206 | 
207 | ### 💻 システムサポート
208 | 
209 | <table>
210 | <tr>
211 | <td>
212 | 
213 | **Windows** ✅
214 | 
215 | - x64 (64ビット)
216 | - x86 (32ビット)
217 | 
218 | </td>
219 | <td>
220 | 
221 | **macOS** ✅
222 | 
223 | - Intel (x64)
224 | - Apple Silicon (M1/M2)
225 | 
226 | </td>
227 | <td>
228 | 
229 | **Linux** ✅
230 | 
231 | - x64 (64ビット)
232 | - x86 (32ビット)
233 | - ARM64
234 | 
235 | </td>
236 | </tr>
237 | </table>
238 | 
239 | 
240 | 
241 | ### 🚀 ワンクリックソリューション
242 | 
243 | <details open>
244 | <summary><b>グローバルユーザー</b></summary>
245 | 
246 | **macOS**
247 | 
248 | ```bash
249 | # 方法2
250 | 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
251 | ```
252 | 
253 | **Linux**
254 | 
255 | ```bash
256 | curl -fsSL https://raw.githubusercontent.com/yuaotian/go-cursor-help/refs/heads/master/scripts/run/cursor_linux_id_modifier.sh | sudo bash 
257 | ```
258 | 
259 | **Windows**
260 | 
261 | ```powershell
262 | irm https://raw.githubusercontent.com/yuaotian/go-cursor-help/refs/heads/master/scripts/run/cursor_win_id_modifier.ps1 | iex
263 | ```
264 | 
265 | **Windows (強化版)**
266 | 
267 | ```powershell
268 | irm https://raw.githubusercontent.com/yuaotian/go-cursor-help/refs/heads/master/scripts/run/cursor_win_id_modifier_new.ps1 | iex
269 | ```
270 | > デュアルモード操作とトライアルリセット機能を備えた強化版Cursorマシンコード修正ツール
271 | 
272 | <div align="center">
273 | <img src="img/run_success.png" alt="Run Success" width="600"/>
274 | </div>
275 | 
276 | </details>
277 | 
278 | <details open>
279 | <summary><b>中国ユーザー(推奨)</b></summary>
280 | 
281 | **macOS**
282 | 
283 | ```bash
284 | 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
285 | ```
286 | 
287 | **Linux**
288 | 
289 | ```bash
290 | 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
291 | ```
292 | 
293 | > **Linuxユーザーへの注意:** スクリプトは、一般的なパス(`/usr/bin`, `/usr/local/bin`, `$HOME/.local/bin`, `/opt/cursor`, `/snap/bin`)の確認、`which cursor` コマンドの使用、および `/usr`、`/opt`、`$HOME/.local` ディレクトリ内の検索によって、Cursor のインストールを見つけようとします。Cursorが他の場所にインストールされているか、これらの方法で見つからない場合、スクリプトは失敗する可能性があります。これらの標準的な場所または方法のいずれかを通じてCursorにアクセスできることを確認してください。
294 | 
295 | **Windows**
296 | 
297 | ```powershell
298 | 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
299 | ```
300 | 
301 | **Windows (強化版)**
302 | 
303 | ```powershell
304 | 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
305 | ```
306 | > デュアルモード操作とトライアルリセット機能を備えた強化版Cursorマシンコード修正ツール
307 | 
308 | </details>
309 | 
310 | <details open>
311 | <summary><b>Windowsターミナルの実行と構成</b></summary>
312 | 
313 | #### Windowsで管理者ターミナルを開く方法:
314 | 
315 | ##### 方法1: Win + Xショートカットを使用する
316 | ```md
317 | 1. Win + Xキーの組み合わせを押します
318 | 2. メニューから次のオプションのいずれかを選択します:
319 |    - "Windows PowerShell (管理者)"
320 |    - "Windows Terminal (管理者)"
321 |    - "ターミナル (管理者)"
322 |    (Windowsのバージョンによってオプションが異なる場合があります)
323 | ```
324 | 
325 | ##### 方法2: Win + R実行コマンドを使用する
326 | ```md
327 | 1. Win + Rキーの組み合わせを押します
328 | 2. 実行ダイアログにpowershellまたはpwshと入力します
329 | 3. Ctrl + Shift + Enterを押して管理者として実行します
330 |    または開いたウィンドウに次のように入力します: Start-Process pwsh -Verb RunAs
331 | 4. 管理者ターミナルにリセットスクリプトを入力します:
332 | 
333 | 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
334 | ```
335 | 
336 | 強化版スクリプト:
337 | ```powershell
338 | 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
339 | ```
340 | 
341 | ##### 方法3: 検索を使用する
342 | >![PowerShellを検索](img/pwsh_1.png)
343 | >
344 | >検索ボックスにpwshと入力し、右クリックして「管理者として実行」を選択します
345 | >![管理者として実行](img/pwsh_2.png)
346 | 
347 | 管理者ターミナルにリセットスクリプトを入力します:
348 | ```powershell
349 | 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
350 | ```
351 | 
352 | 強化版スクリプト:
353 | ```powershell
354 | 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
355 | ```
356 | 
357 | ### 🔧 PowerShellインストールガイド
358 | 
359 | システムにPowerShellがインストールされていない場合は、次の方法でインストールできます:
360 | 
361 | #### 方法1: Wingetを使用してインストール(推奨)
362 | 
363 | 1. コマンドプロンプトまたはPowerShellを開きます
364 | 2. 次のコマンドを実行します:
365 | ```powershell
366 | winget install --id Microsoft.PowerShell --source winget
367 | ```
368 | 
369 | #### 方法2: 手動でインストール
370 | 
371 | 1. システムに適したインストーラーをダウンロードします:
372 |    - [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ビットシステム用)
373 |    - [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ビットシステム用)
374 |    - [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システム用)
375 | 
376 | 2. ダウンロードしたインストーラーをダブルクリックし、インストールの指示に従います
377 | 
378 | > 💡 問題が発生した場合は、[Microsoft公式インストールガイド](https://learn.microsoft.com/ja-jp/powershell/scripting/install/installing-powershell-on-windows)を参照してください
379 | 
380 | </details>
381 | 
382 | #### Windowsインストール機能:
383 | 
384 | - 🔍 PowerShell 7が利用可能な場合は自動的に検出して使用します
385 | - 🛡️ UACプロンプトを介して管理者権限を要求します
386 | - 📝 PS7が見つからない場合はWindows PowerShellにフォールバックします
387 | - 💡 権限昇格に失敗した場合は手動の指示を提供します
388 | 
389 | これで完了です!スクリプトは次のことを行います:
390 | 
391 | 1. ✨ ツールを自動的にインストールします
392 | 2. 🔄 Cursorの試用期間を即座にリセットします
393 | 
394 | ### 📦 手動インストール
395 | 
396 | > [リリース](https://github.com/yuaotian/go-cursor-help/releases/latest)からシステムに適したファイルをダウンロードします
397 | 
398 | <details>
399 | <summary>Windowsパッケージ</summary>
400 | 
401 | - 64ビット: `cursor-id-modifier_windows_x64.exe`
402 | - 32ビット: `cursor-id-modifier_windows_x86.exe`
403 | </details>
404 | 
405 | <details>
406 | <summary>macOSパッケージ</summary>
407 | 
408 | - Intel: `cursor-id-modifier_darwin_x64_intel`
409 | - M1/M2: `cursor-id-modifier_darwin_arm64_apple_silicon`
410 | </details>
411 | 
412 | <details>
413 | <summary>Linuxパッケージ</summary>
414 | 
415 | - 64ビット: `cursor-id-modifier_linux_x64`
416 | - 32ビット: `cursor-id-modifier_linux_x86`
417 | - ARM64: `cursor-id-modifier_linux_arm64`
418 | </details>
419 | 
420 | ### 🔧 技術的詳細
421 | 
422 | <details>
423 | <summary><b>構成ファイル</b></summary>
424 | 
425 | プログラムはCursorの`storage.json`構成ファイルを変更します。場所は次のとおりです:
426 | 
427 | - Windows: `%APPDATA%\Cursor\User\globalStorage\storage.json`
428 | - macOS: `~/Library/Application Support/Cursor/User/globalStorage/storage.json`
429 | - Linux: `~/.config/Cursor/User/globalStorage/storage.json`
430 | </details>
431 | 
432 | <details>
433 | <summary><b>変更されたフィールド</b></summary>
434 | 
435 | ツールは次の新しい一意の識別子を生成します:
436 | 
437 | - `telemetry.machineId`
438 | - `telemetry.macMachineId`
439 | - `telemetry.devDeviceId`
440 | - `telemetry.sqmId`
441 | </details>
442 | 
443 | <details>
444 | <summary><b>手動自動更新無効化</b></summary>
445 | 
446 | Windowsユーザーは自動更新機能を手動で無効にすることができます:
447 | 
448 | 1. すべてのCursorプロセスを閉じます
449 | 2. ディレクトリを削除します: `C:\Users\username\AppData\Local\cursor-updater`
450 | 3. 同じ名前のファイルを作成します: `cursor-updater`(拡張子なし)
451 | 
452 | macOS/Linuxユーザーはシステム内で同様の`cursor-updater`ディレクトリを見つけて同じ操作を行うことができます。
453 | 
454 | </details>
455 | 
456 | <details>
457 | <summary><b>安全機能</b></summary>
458 | 
459 | - ✅ 安全なプロセス終了
460 | - ✅ アトミックファイル操作
461 | - ✅ エラーハンドリングとリカバリ
462 | </details>
463 | 
464 | <details>
465 | <summary><b>レジストリ変更通知</b></summary>
466 | 
467 | > ⚠️ **重要: このツールはWindowsレジストリを変更します**
468 | 
469 | #### 変更されたレジストリ
470 | - パス: `コンピュータ\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography`
471 | - キー: `MachineGuid`
472 | 
473 | #### 潜在的な影響
474 | このレジストリキーを変更すると、次のことに影響を与える可能性があります:
475 | - Windowsシステムの一意のデバイス識別
476 | - 特定のソフトウェアのデバイス認識と認証状態
477 | - ハードウェア識別に基づくシステム機能
478 | 
479 | #### 安全対策
480 | 1. 自動バックアップ
481 |    - 変更前に元の値が自動的にバックアップされます
482 |    - バックアップ場所: `%APPDATA%\Cursor\User\globalStorage\backups`
483 |    - バックアップファイル形式: `MachineGuid.backup_YYYYMMDD_HHMMSS`
484 | 
485 | 2. 手動復元手順
486 |    - レジストリエディタ(regedit)を開きます
487 |    - 次の場所に移動します: `コンピュータ\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography`
488 |    - `MachineGuid`を右クリックします
489 |    - 「修正」を選択します
490 |    - バックアップファイルの値を貼り付けます
491 | 
492 | #### 重要な注意事項
493 | - 変更前にバックアップファイルの存在を確認します
494 | - 必要に応じてバックアップファイルを使用して元の値を復元します
495 | - レジストリの変更には管理者権限が必要です
496 | </details>
497 | 
498 | ---
499 | 
500 | ### 📚 推奨読書
501 | 
502 | - [Cursorの問題収集と解決策](https://mp.weixin.qq.com/s/pnJrH7Ifx4WZvseeP1fcEA)
503 | - [AIユニバーサル開発アシスタントプロンプトガイド](https://mp.weixin.qq.com/s/PRPz-qVkFJSgkuEKkTdzwg)
504 | 
505 | ---
506 | 
507 | ##  サポート
508 | 
509 | <div align="center">
510 | <b>このツールが役立つと感じた場合、スパイシーグルテンのおやつ(Latiao)を買っていただけると嬉しいです~ 💁☕️</b>
511 | <table>
512 | <tr>
513 | 
514 | <td align="center">
515 | <b>WeChat Pay</b><br>
516 | <img src="img/wx_zsm2.png" width="500" alt="WeChat Pay"><br>
517 | <small>要到饭咧?啊咧?啊咧?不给也没事~ 请随意打赏</small>
518 | </td>
519 | <td align="center">
520 | <b>Alipay</b><br>
521 | <img src="img/alipay.png" width="500" alt="Alipay"><br>
522 | <small>如果觉得有帮助,来包辣条犒劳一下吧~</small>
523 | </td>
524 | <td align="center">
525 | <b>Alipay</b><br>
526 | <img src="img/alipay_scan_pay.jpg" width="500" alt="Alipay"><br>
527 | <em>1 Latiao = 1 AI thought cycle</em>
528 | </td>
529 | <td align="center">
530 | <b>WeChat</b><br>
531 | <img src="img/qun-15.jpg" width="500" alt="WeChat"><br>
532 | <em>二维码7天内(7月14日前)有效,过期请加微信</em>
533 | </td>
534 | <!-- <td align="center">
535 | <b>ETC</b><br>
536 | <img src="img/etc.png" width="100" alt="ETC Address"><br>
537 | ETC: 0xa2745f4CD5d32310AC01694ABDB28bA32D125a6b
538 | </td>
539 | <td align="center"> -->
540 | </td>
541 | </tr>
542 | </table>
543 | </div>
544 | 
545 | ---
546 | 
547 | ## 💬 フィードバック&提案
548 | 
549 | 新しい強化スクリプトに関するフィードバックをお待ちしています!`cursor_win_id_modifier_new.ps1` スクリプトをお試しいただいた方は、ぜひご体験をお聞かせください:
550 | 
551 | - 🐛 **バグレポート**:問題を発見されましたか?お知らせください!
552 | - 💡 **機能提案**:改善のアイデアはありますか?
553 | - ⭐ **成功事例**:ツールがどのようにお役に立ったかお聞かせください!
554 | - 🔧 **技術的フィードバック**:パフォーマンス、互換性、使いやすさに関するご意見
555 | 
556 | 皆様のフィードバックは、すべてのユーザーのためにツールを改善するのに役立ちます。お気軽にissueを開いたり、プロジェクトに貢献してください!
557 | 
558 | ---
559 | 
560 | ## ⭐ プロジェクト統計
561 | 
562 | <div align="center">
563 | 
564 | [![Star History Chart](https://api.star-history.com/svg?repos=yuaotian/go-cursor-help&type=Date)](https://star-history.com/#yuaotian/go-cursor-help&Date)
565 | 
566 | ![Repobeats analytics image](https://repobeats.axiom.co/api/embed/ddaa9df9a94b0029ec3fad399e1c1c4e75755477.svg "Repobeats analytics image")
567 | 
568 | </div>
569 | 
570 | ## 📄 ライセンス
571 | 
572 | <details>
573 | <summary><b>MITライセンス</b></summary>
574 | 
575 | Copyright (c) 2024
576 | 
577 | Permission is hereby granted, free of charge, to any person obtaining a copy
578 | of this software and associated documentation files (the "Software"), to deal
579 | in the Software without restriction, including without limitation the rights
580 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
581 | copies of the Software, and to permit persons to whom the Software is
582 | furnished to do so, subject to the following conditions:
583 | 
584 | The above copyright notice and this permission notice shall be included in all
585 | copies or substantial portions of the Software.
586 | 
587 | </details>
588 | 


--------------------------------------------------------------------------------
/cmd/cursor-id-modifier/main.go:
--------------------------------------------------------------------------------
  1 | package main
  2 | 
  3 | import (
  4 | 	"bufio"
  5 | 	"flag"
  6 | 	"fmt"
  7 | 	"os"
  8 | 	"os/exec"
  9 | 	"os/user"
 10 | 	"runtime"
 11 | 	"runtime/debug"
 12 | 	"strings"
 13 | 
 14 | 	"github.com/sirupsen/logrus"
 15 | 
 16 | 	"github.com/yuaotian/go-cursor-help/internal/config"
 17 | 	"github.com/yuaotian/go-cursor-help/internal/lang"
 18 | 	"github.com/yuaotian/go-cursor-help/internal/process"
 19 | 	"github.com/yuaotian/go-cursor-help/internal/ui"
 20 | 	"github.com/yuaotian/go-cursor-help/pkg/idgen"
 21 | )
 22 | 
 23 | // Global variables
 24 | var (
 25 | 	version     = "dev"
 26 | 	setReadOnly = flag.Bool("r", false, "set storage.json to read-only mode")
 27 | 	showVersion = flag.Bool("v", false, "show version information")
 28 | 	log         = logrus.New()
 29 | )
 30 | 
 31 | func main() {
 32 | 	// Place defer at the beginning of main to ensure it can catch panics from all subsequent function calls
 33 | 	defer func() {
 34 | 		if r := recover(); r != nil {
 35 | 			log.Errorf("Panic recovered: %v\n", r)
 36 | 			debug.PrintStack()
 37 | 			waitExit()
 38 | 		}
 39 | 	}()
 40 | 
 41 | 	handleFlags()
 42 | 	setupLogger()
 43 | 
 44 | 	username := getCurrentUser()
 45 | 	log.Debug("Running as user:", username)
 46 | 
 47 | 	// Initialize components
 48 | 	display := ui.NewDisplay(nil)
 49 | 	configManager := initConfigManager(username)
 50 | 	generator := idgen.NewGenerator()
 51 | 	processManager := process.NewManager(nil, log)
 52 | 
 53 | 	// Check and handle privileges
 54 | 	if err := handlePrivileges(display); err != nil {
 55 | 		return
 56 | 	}
 57 | 
 58 | 	// Setup display
 59 | 	setupDisplay(display)
 60 | 
 61 | 	text := lang.GetText()
 62 | 
 63 | 	// Handle Cursor processes
 64 | 	if err := handleCursorProcesses(display, processManager); err != nil {
 65 | 		return
 66 | 	}
 67 | 
 68 | 	// Handle configuration
 69 | 	oldConfig := readExistingConfig(display, configManager, text)
 70 | 	newConfig := generateNewConfig(display, generator, oldConfig, text)
 71 | 
 72 | 	if err := saveConfiguration(display, configManager, newConfig); err != nil {
 73 | 		return
 74 | 	}
 75 | 
 76 | 	// Show completion messages
 77 | 	showCompletionMessages(display)
 78 | 
 79 | 	if os.Getenv("AUTOMATED_MODE") != "1" {
 80 | 		waitExit()
 81 | 	}
 82 | }
 83 | 
 84 | func handleFlags() {
 85 | 	flag.Parse()
 86 | 	if *showVersion {
 87 | 		fmt.Printf("Cursor ID Modifier v%s\n", version)
 88 | 		os.Exit(0)
 89 | 	}
 90 | }
 91 | 
 92 | func setupLogger() {
 93 | 	log.SetFormatter(&logrus.TextFormatter{
 94 | 		FullTimestamp:          true,
 95 | 		DisableLevelTruncation: true,
 96 | 		PadLevelText:           true,
 97 | 	})
 98 | 	log.SetLevel(logrus.InfoLevel)
 99 | }
100 | 
101 | func getCurrentUser() string {
102 | 	if username := os.Getenv("SUDO_USER"); username != "" {
103 | 		return username
104 | 	}
105 | 
106 | 	user, err := user.Current()
107 | 	if err != nil {
108 | 		log.Fatal(err)
109 | 	}
110 | 	return user.Username
111 | }
112 | 
113 | func initConfigManager(username string) *config.Manager {
114 | 	configManager, err := config.NewManager(username)
115 | 	if err != nil {
116 | 		log.Fatal(err)
117 | 	}
118 | 	return configManager
119 | }
120 | 
121 | func handlePrivileges(display *ui.Display) error {
122 | 	isAdmin, err := checkAdminPrivileges()
123 | 	if err != nil {
124 | 		log.Error(err)
125 | 		waitExit()
126 | 		return err
127 | 	}
128 | 
129 | 	if !isAdmin {
130 | 		if runtime.GOOS == "windows" {
131 | 			return handleWindowsPrivileges(display)
132 | 		}
133 | 		display.ShowPrivilegeError(
134 | 			lang.GetText().PrivilegeError,
135 | 			lang.GetText().RunWithSudo,
136 | 			lang.GetText().SudoExample,
137 | 		)
138 | 		waitExit()
139 | 		return fmt.Errorf("insufficient privileges")
140 | 	}
141 | 	return nil
142 | }
143 | 
144 | func handleWindowsPrivileges(display *ui.Display) error {
145 | 	message := "\nRequesting administrator privileges..."
146 | 	if lang.GetCurrentLanguage() == lang.CN {
147 | 		message = "\n请求管理员权限..."
148 | 	}
149 | 	fmt.Println(message)
150 | 
151 | 	if err := selfElevate(); err != nil {
152 | 		log.Error(err)
153 | 		display.ShowPrivilegeError(
154 | 			lang.GetText().PrivilegeError,
155 | 			lang.GetText().RunAsAdmin,
156 | 			lang.GetText().RunWithSudo,
157 | 			lang.GetText().SudoExample,
158 | 		)
159 | 		waitExit()
160 | 		return err
161 | 	}
162 | 	return nil
163 | }
164 | 
165 | func setupDisplay(display *ui.Display) {
166 | 	if err := display.ClearScreen(); err != nil {
167 | 		log.Warn("Failed to clear screen:", err)
168 | 	}
169 | 	display.ShowLogo()
170 | 	fmt.Println()
171 | }
172 | 
173 | func handleCursorProcesses(display *ui.Display, processManager *process.Manager) error {
174 | 	if os.Getenv("AUTOMATED_MODE") == "1" {
175 | 		log.Debug("Running in automated mode, skipping Cursor process closing")
176 | 		return nil
177 | 	}
178 | 
179 | 	display.ShowProgress("Closing Cursor...")
180 | 	log.Debug("Attempting to close Cursor processes")
181 | 
182 | 	if err := processManager.KillCursorProcesses(); err != nil {
183 | 		log.Error("Failed to close Cursor:", err)
184 | 		display.StopProgress()
185 | 		display.ShowError("Failed to close Cursor. Please close it manually and try again.")
186 | 		waitExit()
187 | 		return err
188 | 	}
189 | 
190 | 	if processManager.IsCursorRunning() {
191 | 		log.Error("Cursor processes still detected after closing")
192 | 		display.StopProgress()
193 | 		display.ShowError("Failed to close Cursor completely. Please close it manually and try again.")
194 | 		waitExit()
195 | 		return fmt.Errorf("cursor still running")
196 | 	}
197 | 
198 | 	log.Debug("Successfully closed all Cursor processes")
199 | 	display.StopProgress()
200 | 	fmt.Println()
201 | 	return nil
202 | }
203 | 
204 | func readExistingConfig(display *ui.Display, configManager *config.Manager, text lang.TextResource) *config.StorageConfig {
205 | 	fmt.Println()
206 | 	display.ShowProgress(text.ReadingConfig)
207 | 	oldConfig, err := configManager.ReadConfig()
208 | 	if err != nil {
209 | 		log.Warn("Failed to read existing config:", err)
210 | 		oldConfig = nil
211 | 	}
212 | 	display.StopProgress()
213 | 	fmt.Println()
214 | 	return oldConfig
215 | }
216 | 
217 | func generateNewConfig(display *ui.Display, generator *idgen.Generator, oldConfig *config.StorageConfig, text lang.TextResource) *config.StorageConfig {
218 | 	display.ShowProgress(text.GeneratingIds)
219 | 	newConfig := &config.StorageConfig{}
220 | 
221 | 	if machineID, err := generator.GenerateMachineID(); err != nil {
222 | 		log.Fatal("Failed to generate machine ID:", err)
223 | 	} else {
224 | 		newConfig.TelemetryMachineId = machineID
225 | 	}
226 | 
227 | 	if macMachineID, err := generator.GenerateMacMachineID(); err != nil {
228 | 		log.Fatal("Failed to generate MAC machine ID:", err)
229 | 	} else {
230 | 		newConfig.TelemetryMacMachineId = macMachineID
231 | 	}
232 | 
233 | 	if deviceID, err := generator.GenerateDeviceID(); err != nil {
234 | 		log.Fatal("Failed to generate device ID:", err)
235 | 	} else {
236 | 		newConfig.TelemetryDevDeviceId = deviceID
237 | 	}
238 | 
239 | 	if oldConfig != nil && oldConfig.TelemetrySqmId != "" {
240 | 		newConfig.TelemetrySqmId = oldConfig.TelemetrySqmId
241 | 	} else if sqmID, err := generator.GenerateSQMID(); err != nil {
242 | 		log.Fatal("Failed to generate SQM ID:", err)
243 | 	} else {
244 | 		newConfig.TelemetrySqmId = sqmID
245 | 	}
246 | 
247 | 	display.StopProgress()
248 | 	fmt.Println()
249 | 	return newConfig
250 | }
251 | 
252 | func saveConfiguration(display *ui.Display, configManager *config.Manager, newConfig *config.StorageConfig) error {
253 | 	display.ShowProgress("Saving configuration...")
254 | 	if err := configManager.SaveConfig(newConfig, *setReadOnly); err != nil {
255 | 		log.Error(err)
256 | 		waitExit()
257 | 		return err
258 | 	}
259 | 	display.StopProgress()
260 | 	fmt.Println()
261 | 	return nil
262 | }
263 | 
264 | func showCompletionMessages(display *ui.Display) {
265 | 	display.ShowSuccess(lang.GetText().SuccessMessage, lang.GetText().RestartMessage)
266 | 	fmt.Println()
267 | 
268 | 	message := "Operation completed!"
269 | 	if lang.GetCurrentLanguage() == lang.CN {
270 | 		message = "操作完成!"
271 | 	}
272 | 	display.ShowInfo(message)
273 | }
274 | 
275 | func waitExit() {
276 | 	fmt.Print(lang.GetText().PressEnterToExit)
277 | 	os.Stdout.Sync()
278 | 	bufio.NewReader(os.Stdin).ReadString('\n')
279 | }
280 | 
281 | func checkAdminPrivileges() (bool, error) {
282 | 	switch runtime.GOOS {
283 | 	case "windows":
284 | 		cmd := exec.Command("net", "session")
285 | 		return cmd.Run() == nil, nil
286 | 
287 | 	case "darwin", "linux":
288 | 		currentUser, err := user.Current()
289 | 		if err != nil {
290 | 			return false, fmt.Errorf("failed to get current user: %w", err)
291 | 		}
292 | 		return currentUser.Uid == "0", nil
293 | 
294 | 	default:
295 | 		return false, fmt.Errorf("unsupported operating system: %s", runtime.GOOS)
296 | 	}
297 | }
298 | 
299 | func selfElevate() error {
300 | 	os.Setenv("AUTOMATED_MODE", "1")
301 | 
302 | 	switch runtime.GOOS {
303 | 	case "windows":
304 | 		verb := "runas"
305 | 		exe, _ := os.Executable()
306 | 		cwd, _ := os.Getwd()
307 | 		args := strings.Join(os.Args[1:], " ")
308 | 
309 | 		cmd := exec.Command("cmd", "/C", "start", verb, exe, args)
310 | 		cmd.Dir = cwd
311 | 		return cmd.Run()
312 | 
313 | 	case "darwin", "linux":
314 | 		exe, err := os.Executable()
315 | 		if err != nil {
316 | 			return err
317 | 		}
318 | 
319 | 		cmd := exec.Command("sudo", append([]string{exe}, os.Args[1:]...)...)
320 | 		cmd.Stdin = os.Stdin
321 | 		cmd.Stdout = os.Stdout
322 | 		cmd.Stderr = os.Stderr
323 | 		return cmd.Run()
324 | 
325 | 	default:
326 | 		return fmt.Errorf("unsupported operating system: %s", runtime.GOOS)
327 | 	}
328 | }
329 | 


--------------------------------------------------------------------------------
/go.mod:
--------------------------------------------------------------------------------
 1 | module github.com/yuaotian/go-cursor-help
 2 | 
 3 | go 1.21
 4 | 
 5 | require (
 6 | 	github.com/fatih/color v1.15.0
 7 | 	github.com/sirupsen/logrus v1.9.3
 8 | )
 9 | 
10 | require (
11 | 	github.com/mattn/go-colorable v0.1.13 // indirect
12 | 	github.com/mattn/go-isatty v0.0.17 // indirect
13 | 	github.com/stretchr/testify v1.10.0 // indirect
14 | 	golang.org/x/sys v0.13.0 // indirect
15 | )
16 | 


--------------------------------------------------------------------------------
/go.sum:
--------------------------------------------------------------------------------
 1 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 2 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
 3 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 4 | github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs=
 5 | github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw=
 6 | github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
 7 | github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
 8 | github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
 9 | github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng=
10 | github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
11 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
12 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
13 | github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
14 | github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
15 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
16 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
17 | github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
18 | github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
19 | golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
20 | golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
21 | golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
22 | golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
23 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
24 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
25 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
26 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
27 | 


--------------------------------------------------------------------------------
/img/alipay.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yuaotian/go-cursor-help/3504d0e5e262319e3d63fdbad93a2ed0d28f89ac/img/alipay.png


--------------------------------------------------------------------------------
/img/alipay_scan_pay.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yuaotian/go-cursor-help/3504d0e5e262319e3d63fdbad93a2ed0d28f89ac/img/alipay_scan_pay.jpg


--------------------------------------------------------------------------------
/img/etc.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yuaotian/go-cursor-help/3504d0e5e262319e3d63fdbad93a2ed0d28f89ac/img/etc.png


--------------------------------------------------------------------------------
/img/pwsh_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yuaotian/go-cursor-help/3504d0e5e262319e3d63fdbad93a2ed0d28f89ac/img/pwsh_1.png


--------------------------------------------------------------------------------
/img/pwsh_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yuaotian/go-cursor-help/3504d0e5e262319e3d63fdbad93a2ed0d28f89ac/img/pwsh_2.png


--------------------------------------------------------------------------------
/img/qun-10.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yuaotian/go-cursor-help/3504d0e5e262319e3d63fdbad93a2ed0d28f89ac/img/qun-10.jpg


--------------------------------------------------------------------------------
/img/qun-12.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yuaotian/go-cursor-help/3504d0e5e262319e3d63fdbad93a2ed0d28f89ac/img/qun-12.png


--------------------------------------------------------------------------------
/img/qun-14.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yuaotian/go-cursor-help/3504d0e5e262319e3d63fdbad93a2ed0d28f89ac/img/qun-14.jpg


--------------------------------------------------------------------------------
/img/qun-15.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yuaotian/go-cursor-help/3504d0e5e262319e3d63fdbad93a2ed0d28f89ac/img/qun-15.jpg


--------------------------------------------------------------------------------
/img/qun-8.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yuaotian/go-cursor-help/3504d0e5e262319e3d63fdbad93a2ed0d28f89ac/img/qun-8.png


--------------------------------------------------------------------------------
/img/qun11.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yuaotian/go-cursor-help/3504d0e5e262319e3d63fdbad93a2ed0d28f89ac/img/qun11.jpg


--------------------------------------------------------------------------------
/img/qun13.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yuaotian/go-cursor-help/3504d0e5e262319e3d63fdbad93a2ed0d28f89ac/img/qun13.png


--------------------------------------------------------------------------------
/img/qun9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yuaotian/go-cursor-help/3504d0e5e262319e3d63fdbad93a2ed0d28f89ac/img/qun9.png


--------------------------------------------------------------------------------
/img/run_success.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yuaotian/go-cursor-help/3504d0e5e262319e3d63fdbad93a2ed0d28f89ac/img/run_success.png


--------------------------------------------------------------------------------
/img/wx_group.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yuaotian/go-cursor-help/3504d0e5e262319e3d63fdbad93a2ed0d28f89ac/img/wx_group.jpg


--------------------------------------------------------------------------------
/img/wx_group6.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yuaotian/go-cursor-help/3504d0e5e262319e3d63fdbad93a2ed0d28f89ac/img/wx_group6.jpg


--------------------------------------------------------------------------------
/img/wx_group7.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yuaotian/go-cursor-help/3504d0e5e262319e3d63fdbad93a2ed0d28f89ac/img/wx_group7.jpg


--------------------------------------------------------------------------------
/img/wx_me.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yuaotian/go-cursor-help/3504d0e5e262319e3d63fdbad93a2ed0d28f89ac/img/wx_me.png


--------------------------------------------------------------------------------
/img/wx_public.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yuaotian/go-cursor-help/3504d0e5e262319e3d63fdbad93a2ed0d28f89ac/img/wx_public.jpg


--------------------------------------------------------------------------------
/img/wx_public_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yuaotian/go-cursor-help/3504d0e5e262319e3d63fdbad93a2ed0d28f89ac/img/wx_public_2.png


--------------------------------------------------------------------------------
/img/wx_zsm.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yuaotian/go-cursor-help/3504d0e5e262319e3d63fdbad93a2ed0d28f89ac/img/wx_zsm.jpg


--------------------------------------------------------------------------------
/img/wx_zsm2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yuaotian/go-cursor-help/3504d0e5e262319e3d63fdbad93a2ed0d28f89ac/img/wx_zsm2.png


--------------------------------------------------------------------------------
/img/zanzhu/twillot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yuaotian/go-cursor-help/3504d0e5e262319e3d63fdbad93a2ed0d28f89ac/img/zanzhu/twillot.png


--------------------------------------------------------------------------------
/internal/config/config.go:
--------------------------------------------------------------------------------
  1 | package config
  2 | 
  3 | import (
  4 | 	"encoding/json"
  5 | 	"fmt"
  6 | 	"os"
  7 | 	"path/filepath"
  8 | 	"runtime"
  9 | 	"sync"
 10 | 	"time"
 11 | )
 12 | 
 13 | // StorageConfig represents the storage configuration
 14 | type StorageConfig struct {
 15 | 	TelemetryMacMachineId string `json:"telemetry.macMachineId"`
 16 | 	TelemetryMachineId    string `json:"telemetry.machineId"`
 17 | 	TelemetryDevDeviceId  string `json:"telemetry.devDeviceId"`
 18 | 	TelemetrySqmId        string `json:"telemetry.sqmId"`
 19 | 	LastModified          string `json:"lastModified"`
 20 | 	Version               string `json:"version"`
 21 | }
 22 | 
 23 | // Manager handles configuration operations
 24 | type Manager struct {
 25 | 	configPath string
 26 | 	mu         sync.RWMutex
 27 | }
 28 | 
 29 | // NewManager creates a new configuration manager
 30 | func NewManager(username string) (*Manager, error) {
 31 | 	configPath, err := getConfigPath(username)
 32 | 	if err != nil {
 33 | 		return nil, fmt.Errorf("failed to get config path: %w", err)
 34 | 	}
 35 | 	return &Manager{configPath: configPath}, nil
 36 | }
 37 | 
 38 | // ReadConfig reads the existing configuration
 39 | func (m *Manager) ReadConfig() (*StorageConfig, error) {
 40 | 	m.mu.RLock()
 41 | 	defer m.mu.RUnlock()
 42 | 
 43 | 	data, err := os.ReadFile(m.configPath)
 44 | 	if err != nil {
 45 | 		if os.IsNotExist(err) {
 46 | 			return nil, nil
 47 | 		}
 48 | 		return nil, fmt.Errorf("failed to read config file: %w", err)
 49 | 	}
 50 | 
 51 | 	var config StorageConfig
 52 | 	if err := json.Unmarshal(data, &config); err != nil {
 53 | 		return nil, fmt.Errorf("failed to parse config file: %w", err)
 54 | 	}
 55 | 
 56 | 	return &config, nil
 57 | }
 58 | 
 59 | // SaveConfig saves the configuration
 60 | func (m *Manager) SaveConfig(config *StorageConfig, readOnly bool) error {
 61 | 	m.mu.Lock()
 62 | 	defer m.mu.Unlock()
 63 | 
 64 | 	// Ensure parent directories exist
 65 | 	if err := os.MkdirAll(filepath.Dir(m.configPath), 0755); err != nil {
 66 | 		return fmt.Errorf("failed to create config directory: %w", err)
 67 | 	}
 68 | 
 69 | 	// Prepare updated configuration
 70 | 	updatedConfig := m.prepareUpdatedConfig(config)
 71 | 
 72 | 	// Write configuration
 73 | 	if err := m.writeConfigFile(updatedConfig, readOnly); err != nil {
 74 | 		return err
 75 | 	}
 76 | 
 77 | 	return nil
 78 | }
 79 | 
 80 | // prepareUpdatedConfig merges existing config with updates
 81 | func (m *Manager) prepareUpdatedConfig(config *StorageConfig) map[string]interface{} {
 82 | 	// Read existing config
 83 | 	originalFile := make(map[string]interface{})
 84 | 	if data, err := os.ReadFile(m.configPath); err == nil {
 85 | 		json.Unmarshal(data, &originalFile)
 86 | 	}
 87 | 
 88 | 	// Update fields
 89 | 	originalFile["telemetry.sqmId"] = config.TelemetrySqmId
 90 | 	originalFile["telemetry.macMachineId"] = config.TelemetryMacMachineId
 91 | 	originalFile["telemetry.machineId"] = config.TelemetryMachineId
 92 | 	originalFile["telemetry.devDeviceId"] = config.TelemetryDevDeviceId
 93 | 	originalFile["lastModified"] = time.Now().UTC().Format(time.RFC3339)
 94 | 	// originalFile["version"] = "1.0.1"
 95 | 
 96 | 	return originalFile
 97 | }
 98 | 
 99 | // writeConfigFile handles the atomic write of the config file
100 | func (m *Manager) writeConfigFile(config map[string]interface{}, readOnly bool) error {
101 | 	// Marshal with indentation
102 | 	content, err := json.MarshalIndent(config, "", "    ")
103 | 	if err != nil {
104 | 		return fmt.Errorf("failed to marshal config: %w", err)
105 | 	}
106 | 
107 | 	// Write to temporary file
108 | 	tmpPath := m.configPath + ".tmp"
109 | 	if err := os.WriteFile(tmpPath, content, 0666); err != nil {
110 | 		return fmt.Errorf("failed to write temporary file: %w", err)
111 | 	}
112 | 
113 | 	// Set final permissions
114 | 	fileMode := os.FileMode(0666)
115 | 	if readOnly {
116 | 		fileMode = 0444
117 | 	}
118 | 
119 | 	if err := os.Chmod(tmpPath, fileMode); err != nil {
120 | 		os.Remove(tmpPath)
121 | 		return fmt.Errorf("failed to set temporary file permissions: %w", err)
122 | 	}
123 | 
124 | 	// Atomic rename
125 | 	if err := os.Rename(tmpPath, m.configPath); err != nil {
126 | 		os.Remove(tmpPath)
127 | 		return fmt.Errorf("failed to rename file: %w", err)
128 | 	}
129 | 
130 | 	// Sync directory
131 | 	if dir, err := os.Open(filepath.Dir(m.configPath)); err == nil {
132 | 		defer dir.Close()
133 | 		dir.Sync()
134 | 	}
135 | 
136 | 	return nil
137 | }
138 | 
139 | // getConfigPath returns the path to the configuration file
140 | func getConfigPath(username string) (string, error) {
141 | 	var configDir string
142 | 	switch runtime.GOOS {
143 | 	case "windows":
144 | 		configDir = filepath.Join(os.Getenv("APPDATA"), "Cursor", "User", "globalStorage")
145 | 	case "darwin":
146 | 		configDir = filepath.Join("/Users", username, "Library", "Application Support", "Cursor", "User", "globalStorage")
147 | 	case "linux":
148 | 		configDir = filepath.Join("/home", username, ".config", "Cursor", "User", "globalStorage")
149 | 	default:
150 | 		return "", fmt.Errorf("unsupported operating system: %s", runtime.GOOS)
151 | 	}
152 | 	return filepath.Join(configDir, "storage.json"), nil
153 | }
154 | 


--------------------------------------------------------------------------------
/internal/lang/lang.go:
--------------------------------------------------------------------------------
  1 | package lang
  2 | 
  3 | import (
  4 | 	"os"
  5 | 	"os/exec"
  6 | 	"strings"
  7 | 	"sync"
  8 | )
  9 | 
 10 | // Language represents a supported language code
 11 | type Language string
 12 | 
 13 | const (
 14 | 	// CN represents Chinese language
 15 | 	CN Language = "cn"
 16 | 	// EN represents English language
 17 | 	EN Language = "en"
 18 | )
 19 | 
 20 | // TextResource contains all translatable text resources
 21 | type TextResource struct {
 22 | 	// Success messages
 23 | 	SuccessMessage string
 24 | 	RestartMessage string
 25 | 
 26 | 	// Progress messages
 27 | 	ReadingConfig     string
 28 | 	GeneratingIds     string
 29 | 	CheckingProcesses string
 30 | 	ClosingProcesses  string
 31 | 	ProcessesClosed   string
 32 | 	PleaseWait        string
 33 | 
 34 | 	// Error messages
 35 | 	ErrorPrefix    string
 36 | 	PrivilegeError string
 37 | 
 38 | 	// Instructions
 39 | 	RunAsAdmin         string
 40 | 	RunWithSudo        string
 41 | 	SudoExample        string
 42 | 	PressEnterToExit   string
 43 | 	SetReadOnlyMessage string
 44 | 
 45 | 	// Info messages
 46 | 	ConfigLocation string
 47 | }
 48 | 
 49 | var (
 50 | 	currentLanguage     Language
 51 | 	currentLanguageOnce sync.Once
 52 | 	languageMutex       sync.RWMutex
 53 | )
 54 | 
 55 | // GetCurrentLanguage returns the current language, detecting it if not already set
 56 | func GetCurrentLanguage() Language {
 57 | 	currentLanguageOnce.Do(func() {
 58 | 		currentLanguage = detectLanguage()
 59 | 	})
 60 | 
 61 | 	languageMutex.RLock()
 62 | 	defer languageMutex.RUnlock()
 63 | 	return currentLanguage
 64 | }
 65 | 
 66 | // SetLanguage sets the current language
 67 | func SetLanguage(lang Language) {
 68 | 	languageMutex.Lock()
 69 | 	defer languageMutex.Unlock()
 70 | 	currentLanguage = lang
 71 | }
 72 | 
 73 | // GetText returns the TextResource for the current language
 74 | func GetText() TextResource {
 75 | 	return texts[GetCurrentLanguage()]
 76 | }
 77 | 
 78 | // detectLanguage detects the system language
 79 | func detectLanguage() Language {
 80 | 	// Check environment variables first
 81 | 	if isChineseEnvVar() {
 82 | 		return CN
 83 | 	}
 84 | 
 85 | 	// Then check OS-specific locale
 86 | 	if isWindows() {
 87 | 		if isWindowsChineseLocale() {
 88 | 			return CN
 89 | 		}
 90 | 	} else if isUnixChineseLocale() {
 91 | 		return CN
 92 | 	}
 93 | 
 94 | 	return EN
 95 | }
 96 | 
 97 | func isChineseEnvVar() bool {
 98 | 	for _, envVar := range []string{"LANG", "LANGUAGE", "LC_ALL"} {
 99 | 		if lang := os.Getenv(envVar); lang != "" && strings.Contains(strings.ToLower(lang), "zh") {
100 | 			return true
101 | 		}
102 | 	}
103 | 	return false
104 | }
105 | 
106 | func isWindows() bool {
107 | 	return os.Getenv("OS") == "Windows_NT"
108 | }
109 | 
110 | func isWindowsChineseLocale() bool {
111 | 	// Check Windows UI culture
112 | 	cmd := exec.Command("powershell", "-Command",
113 | 		"[System.Globalization.CultureInfo]::CurrentUICulture.Name")
114 | 	output, err := cmd.Output()
115 | 	if err == nil && strings.HasPrefix(strings.ToLower(strings.TrimSpace(string(output))), "zh") {
116 | 		return true
117 | 	}
118 | 
119 | 	// Check Windows locale
120 | 	cmd = exec.Command("wmic", "os", "get", "locale")
121 | 	output, err = cmd.Output()
122 | 	return err == nil && strings.Contains(string(output), "2052")
123 | }
124 | 
125 | func isUnixChineseLocale() bool {
126 | 	cmd := exec.Command("locale")
127 | 	output, err := cmd.Output()
128 | 	return err == nil && strings.Contains(strings.ToLower(string(output)), "zh_cn")
129 | }
130 | 
131 | // texts contains all translations
132 | var texts = map[Language]TextResource{
133 | 	CN: {
134 | 		// Success messages
135 | 		SuccessMessage: "[√] 配置文件已成功更新!",
136 | 		RestartMessage: "[!] 请手动重启 Cursor 以使更新生效",
137 | 
138 | 		// Progress messages
139 | 		ReadingConfig:     "正在读取配置文件...",
140 | 		GeneratingIds:     "正在生成新的标识符...",
141 | 		CheckingProcesses: "正在检查运行中的 Cursor 实例...",
142 | 		ClosingProcesses:  "正在关闭 Cursor 实例...",
143 | 		ProcessesClosed:   "所有 Cursor 实例已关闭",
144 | 		PleaseWait:        "请稍候...",
145 | 
146 | 		// Error messages
147 | 		ErrorPrefix:    "程序发生严重错误: %v",
148 | 		PrivilegeError: "\n[!] 错误:需要管理员权限",
149 | 
150 | 		// Instructions
151 | 		RunAsAdmin:         "请右键点击程序,选择「以管理员身份运行」",
152 | 		RunWithSudo:        "请使用 sudo 命令运行此程序",
153 | 		SudoExample:        "示例: sudo %s",
154 | 		PressEnterToExit:   "\n按回车键退出程序...",
155 | 		SetReadOnlyMessage: "设置 storage.json 为只读模式, 这将导致 workspace 记录信息丢失等问题",
156 | 
157 | 		// Info messages
158 | 		ConfigLocation: "配置文件位置:",
159 | 	},
160 | 	EN: {
161 | 		// Success messages
162 | 		SuccessMessage: "[√] Configuration file updated successfully!",
163 | 		RestartMessage: "[!] Please restart Cursor manually for changes to take effect",
164 | 
165 | 		// Progress messages
166 | 		ReadingConfig:     "Reading configuration file...",
167 | 		GeneratingIds:     "Generating new identifiers...",
168 | 		CheckingProcesses: "Checking for running Cursor instances...",
169 | 		ClosingProcesses:  "Closing Cursor instances...",
170 | 		ProcessesClosed:   "All Cursor instances have been closed",
171 | 		PleaseWait:        "Please wait...",
172 | 
173 | 		// Error messages
174 | 		ErrorPrefix:    "Program encountered a serious error: %v",
175 | 		PrivilegeError: "\n[!] Error: Administrator privileges required",
176 | 
177 | 		// Instructions
178 | 		RunAsAdmin:         "Please right-click and select 'Run as Administrator'",
179 | 		RunWithSudo:        "Please run this program with sudo",
180 | 		SudoExample:        "Example: sudo %s",
181 | 		PressEnterToExit:   "\nPress Enter to exit...",
182 | 		SetReadOnlyMessage: "Set storage.json to read-only mode, which will cause issues such as lost workspace records",
183 | 
184 | 		// Info messages
185 | 		ConfigLocation: "Config file location:",
186 | 	},
187 | }
188 | 


--------------------------------------------------------------------------------
/internal/process/manager.go:
--------------------------------------------------------------------------------
  1 | package process
  2 | 
  3 | import (
  4 | 	"fmt"
  5 | 	"os/exec"
  6 | 	"runtime"
  7 | 	"strings"
  8 | 	"time"
  9 | 
 10 | 	"github.com/sirupsen/logrus"
 11 | )
 12 | 
 13 | // Config holds process manager configuration
 14 | type Config struct {
 15 | 	MaxAttempts     int           // Maximum number of attempts to kill processes
 16 | 	RetryDelay      time.Duration // Delay between retry attempts
 17 | 	ProcessPatterns []string      // Process names to look for
 18 | }
 19 | 
 20 | // DefaultConfig returns the default configuration
 21 | func DefaultConfig() *Config {
 22 | 	return &Config{
 23 | 		MaxAttempts: 3,
 24 | 		RetryDelay:  2 * time.Second,
 25 | 		ProcessPatterns: []string{
 26 | 			"Cursor.exe", // Windows executable
 27 | 			"Cursor ",    // Linux/macOS executable with space
 28 | 			"cursor ",    // Linux/macOS executable lowercase with space
 29 | 			"cursor",     // Linux/macOS executable lowercase
 30 | 			"Cursor",     // Linux/macOS executable
 31 | 			"*cursor*",   // Any process containing cursor
 32 | 			"*Cursor*",   // Any process containing Cursor
 33 | 		},
 34 | 	}
 35 | }
 36 | 
 37 | // Manager handles process-related operations
 38 | type Manager struct {
 39 | 	config *Config
 40 | 	log    *logrus.Logger
 41 | }
 42 | 
 43 | // NewManager creates a new process manager with optional config and logger
 44 | func NewManager(config *Config, log *logrus.Logger) *Manager {
 45 | 	if config == nil {
 46 | 		config = DefaultConfig()
 47 | 	}
 48 | 	if log == nil {
 49 | 		log = logrus.New()
 50 | 	}
 51 | 	return &Manager{
 52 | 		config: config,
 53 | 		log:    log,
 54 | 	}
 55 | }
 56 | 
 57 | // IsCursorRunning checks if any Cursor process is currently running
 58 | func (m *Manager) IsCursorRunning() bool {
 59 | 	processes, err := m.getCursorProcesses()
 60 | 	if err != nil {
 61 | 		m.log.Warn("Failed to get Cursor processes:", err)
 62 | 		return false
 63 | 	}
 64 | 	return len(processes) > 0
 65 | }
 66 | 
 67 | // KillCursorProcesses attempts to kill all running Cursor processes
 68 | func (m *Manager) KillCursorProcesses() error {
 69 | 	for attempt := 1; attempt <= m.config.MaxAttempts; attempt++ {
 70 | 		processes, err := m.getCursorProcesses()
 71 | 		if err != nil {
 72 | 			return fmt.Errorf("failed to get processes: %w", err)
 73 | 		}
 74 | 
 75 | 		if len(processes) == 0 {
 76 | 			return nil
 77 | 		}
 78 | 
 79 | 		// Try graceful shutdown first on Windows
 80 | 		if runtime.GOOS == "windows" {
 81 | 			for _, pid := range processes {
 82 | 				exec.Command("taskkill", "/PID", pid).Run()
 83 | 				time.Sleep(500 * time.Millisecond)
 84 | 			}
 85 | 		}
 86 | 
 87 | 		// Force kill remaining processes
 88 | 		remainingProcesses, _ := m.getCursorProcesses()
 89 | 		for _, pid := range remainingProcesses {
 90 | 			m.killProcess(pid)
 91 | 		}
 92 | 
 93 | 		time.Sleep(m.config.RetryDelay)
 94 | 
 95 | 		if processes, _ := m.getCursorProcesses(); len(processes) == 0 {
 96 | 			return nil
 97 | 		}
 98 | 	}
 99 | 
100 | 	return nil
101 | }
102 | 
103 | // getCursorProcesses returns PIDs of running Cursor processes
104 | func (m *Manager) getCursorProcesses() ([]string, error) {
105 | 	cmd := m.getProcessListCommand()
106 | 	if cmd == nil {
107 | 		return nil, fmt.Errorf("unsupported operating system: %s", runtime.GOOS)
108 | 	}
109 | 
110 | 	output, err := cmd.Output()
111 | 	if err != nil {
112 | 		return nil, fmt.Errorf("failed to execute command: %w", err)
113 | 	}
114 | 
115 | 	return m.parseProcessList(string(output)), nil
116 | }
117 | 
118 | // getProcessListCommand returns the appropriate command to list processes based on OS
119 | func (m *Manager) getProcessListCommand() *exec.Cmd {
120 | 	switch runtime.GOOS {
121 | 	case "windows":
122 | 		return exec.Command("tasklist", "/FO", "CSV", "/NH")
123 | 	case "darwin":
124 | 		return exec.Command("ps", "-ax")
125 | 	case "linux":
126 | 		return exec.Command("ps", "-A")
127 | 	default:
128 | 		return nil
129 | 	}
130 | }
131 | 
132 | // parseProcessList extracts Cursor process PIDs from process list output
133 | func (m *Manager) parseProcessList(output string) []string {
134 | 	var processes []string
135 | 	for _, line := range strings.Split(output, "\n") {
136 | 		lowerLine := strings.ToLower(line)
137 | 
138 | 		if m.isOwnProcess(lowerLine) {
139 | 			continue
140 | 		}
141 | 
142 | 		if pid := m.findCursorProcess(line, lowerLine); pid != "" {
143 | 			processes = append(processes, pid)
144 | 		}
145 | 	}
146 | 	return processes
147 | }
148 | 
149 | // isOwnProcess checks if the process belongs to this application
150 | func (m *Manager) isOwnProcess(line string) bool {
151 | 	return strings.Contains(line, "cursor-id-modifier") ||
152 | 		strings.Contains(line, "cursor-helper")
153 | }
154 | 
155 | // findCursorProcess checks if a process line matches Cursor patterns and returns its PID
156 | func (m *Manager) findCursorProcess(line, lowerLine string) string {
157 | 	for _, pattern := range m.config.ProcessPatterns {
158 | 		if m.matchPattern(lowerLine, strings.ToLower(pattern)) {
159 | 			return m.extractPID(line)
160 | 		}
161 | 	}
162 | 	return ""
163 | }
164 | 
165 | // matchPattern checks if a line matches a pattern, supporting wildcards
166 | func (m *Manager) matchPattern(line, pattern string) bool {
167 | 	switch {
168 | 	case strings.HasPrefix(pattern, "*") && strings.HasSuffix(pattern, "*"):
169 | 		search := pattern[1 : len(pattern)-1]
170 | 		return strings.Contains(line, search)
171 | 	case strings.HasPrefix(pattern, "*"):
172 | 		return strings.HasSuffix(line, pattern[1:])
173 | 	case strings.HasSuffix(pattern, "*"):
174 | 		return strings.HasPrefix(line, pattern[:len(pattern)-1])
175 | 	default:
176 | 		return line == pattern
177 | 	}
178 | }
179 | 
180 | // extractPID extracts process ID from a process list line based on OS format
181 | func (m *Manager) extractPID(line string) string {
182 | 	switch runtime.GOOS {
183 | 	case "windows":
184 | 		parts := strings.Split(line, ",")
185 | 		if len(parts) >= 2 {
186 | 			return strings.Trim(parts[1], "\"")
187 | 		}
188 | 	case "darwin", "linux":
189 | 		parts := strings.Fields(line)
190 | 		if len(parts) >= 1 {
191 | 			return parts[0]
192 | 		}
193 | 	}
194 | 	return ""
195 | }
196 | 
197 | // killProcess forcefully terminates a process by PID
198 | func (m *Manager) killProcess(pid string) error {
199 | 	cmd := m.getKillCommand(pid)
200 | 	if cmd == nil {
201 | 		return fmt.Errorf("unsupported operating system: %s", runtime.GOOS)
202 | 	}
203 | 	return cmd.Run()
204 | }
205 | 
206 | // getKillCommand returns the appropriate command to kill a process based on OS
207 | func (m *Manager) getKillCommand(pid string) *exec.Cmd {
208 | 	switch runtime.GOOS {
209 | 	case "windows":
210 | 		return exec.Command("taskkill", "/F", "/PID", pid)
211 | 	case "darwin", "linux":
212 | 		return exec.Command("kill", "-9", pid)
213 | 	default:
214 | 		return nil
215 | 	}
216 | }
217 | 


--------------------------------------------------------------------------------
/internal/ui/display.go:
--------------------------------------------------------------------------------
 1 | package ui
 2 | 
 3 | import (
 4 | 	"fmt"
 5 | 	"os"
 6 | 	"os/exec"
 7 | 	"runtime"
 8 | 	"strings"
 9 | 
10 | 	"github.com/fatih/color"
11 | )
12 | 
13 | // Display handles UI operations for terminal output
14 | type Display struct {
15 | 	spinner *Spinner
16 | }
17 | 
18 | // NewDisplay creates a new display instance with an optional spinner
19 | func NewDisplay(spinner *Spinner) *Display {
20 | 	if spinner == nil {
21 | 		spinner = NewSpinner(nil)
22 | 	}
23 | 	return &Display{spinner: spinner}
24 | }
25 | 
26 | // Terminal Operations
27 | 
28 | // ClearScreen clears the terminal screen based on OS
29 | func (d *Display) ClearScreen() error {
30 | 	var cmd *exec.Cmd
31 | 	switch runtime.GOOS {
32 | 	case "windows":
33 | 		cmd = exec.Command("cmd", "/c", "cls")
34 | 	default:
35 | 		cmd = exec.Command("clear")
36 | 	}
37 | 	cmd.Stdout = os.Stdout
38 | 	return cmd.Run()
39 | }
40 | 
41 | // Progress Indicator
42 | 
43 | // ShowProgress displays a progress message with a spinner
44 | func (d *Display) ShowProgress(message string) {
45 | 	d.spinner.SetMessage(message)
46 | 	d.spinner.Start()
47 | }
48 | 
49 | // StopProgress stops the progress spinner
50 | func (d *Display) StopProgress() {
51 | 	d.spinner.Stop()
52 | }
53 | 
54 | // Message Display
55 | 
56 | // ShowSuccess displays success messages in green
57 | func (d *Display) ShowSuccess(messages ...string) {
58 | 	green := color.New(color.FgGreen)
59 | 	for _, msg := range messages {
60 | 		green.Println(msg)
61 | 	}
62 | }
63 | 
64 | // ShowInfo displays an info message in cyan
65 | func (d *Display) ShowInfo(message string) {
66 | 	cyan := color.New(color.FgCyan)
67 | 	cyan.Println(message)
68 | }
69 | 
70 | // ShowError displays an error message in red
71 | func (d *Display) ShowError(message string) {
72 | 	red := color.New(color.FgRed)
73 | 	red.Println(message)
74 | }
75 | 
76 | // ShowPrivilegeError displays privilege error messages with instructions
77 | func (d *Display) ShowPrivilegeError(messages ...string) {
78 | 	red := color.New(color.FgRed, color.Bold)
79 | 	yellow := color.New(color.FgYellow)
80 | 
81 | 	// Main error message
82 | 	red.Println(messages[0])
83 | 	fmt.Println()
84 | 
85 | 	// Additional instructions
86 | 	for _, msg := range messages[1:] {
87 | 		if strings.Contains(msg, "%s") {
88 | 			exe, _ := os.Executable()
89 | 			yellow.Printf(msg+"\n", exe)
90 | 		} else {
91 | 			yellow.Println(msg)
92 | 		}
93 | 	}
94 | }
95 | 


--------------------------------------------------------------------------------
/internal/ui/logo.go:
--------------------------------------------------------------------------------
 1 | package ui
 2 | 
 3 | import (
 4 | 	"github.com/fatih/color"
 5 | )
 6 | 
 7 | const cyberpunkLogo = `
 8 |    ██████╗██╗   ██╗██████╗ ███████╗ ██████╗ ██████╗ 
 9 |   ██╔════╝██║   ██║██╔══██╗██╔════╝██╔═══██╗██╔══██╗
10 |   ██║     ██║   ██║██████╔╝███████╗██║   ██║██████╔╝
11 |   ██║     ██║   ██║██╔══██╗╚════██║██║   ██║██╔══██╗
12 |   ╚██████╗╚██████╔╝██║  ██║███████║╚██████╔╝██║  ██║
13 |    ╚═════╝ ╚═════╝ ╚═╝  ╚═╝╚══════╝ ╚═════╝ ╚═╝  ╚═╝
14 | `
15 | 
16 | // ShowLogo displays the application logo
17 | func (d *Display) ShowLogo() {
18 | 	cyan := color.New(color.FgCyan, color.Bold)
19 | 	cyan.Println(cyberpunkLogo)
20 | }
21 | 


--------------------------------------------------------------------------------
/internal/ui/spinner.go:
--------------------------------------------------------------------------------
  1 | package ui
  2 | 
  3 | import (
  4 | 	"fmt"
  5 | 	"sync"
  6 | 	"time"
  7 | 
  8 | 	"github.com/fatih/color"
  9 | )
 10 | 
 11 | // SpinnerConfig defines spinner configuration
 12 | type SpinnerConfig struct {
 13 | 	Frames []string        // Animation frames for the spinner
 14 | 	Delay  time.Duration   // Delay between frame updates
 15 | }
 16 | 
 17 | // DefaultSpinnerConfig returns the default spinner configuration
 18 | func DefaultSpinnerConfig() *SpinnerConfig {
 19 | 	return &SpinnerConfig{
 20 | 		Frames: []string{"⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"},
 21 | 		Delay:  100 * time.Millisecond,
 22 | 	}
 23 | }
 24 | 
 25 | // Spinner represents a progress spinner
 26 | type Spinner struct {
 27 | 	config  *SpinnerConfig
 28 | 	message string
 29 | 	current int
 30 | 	active  bool
 31 | 	stopCh  chan struct{}
 32 | 	mu      sync.RWMutex
 33 | }
 34 | 
 35 | // NewSpinner creates a new spinner with the given configuration
 36 | func NewSpinner(config *SpinnerConfig) *Spinner {
 37 | 	if config == nil {
 38 | 		config = DefaultSpinnerConfig()
 39 | 	}
 40 | 	return &Spinner{
 41 | 		config: config,
 42 | 		stopCh: make(chan struct{}),
 43 | 	}
 44 | }
 45 | 
 46 | // State management
 47 | 
 48 | // SetMessage sets the spinner message
 49 | func (s *Spinner) SetMessage(message string) {
 50 | 	s.mu.Lock()
 51 | 	defer s.mu.Unlock()
 52 | 	s.message = message
 53 | }
 54 | 
 55 | // IsActive returns whether the spinner is currently active
 56 | func (s *Spinner) IsActive() bool {
 57 | 	s.mu.RLock()
 58 | 	defer s.mu.RUnlock()
 59 | 	return s.active
 60 | }
 61 | 
 62 | // Control methods
 63 | 
 64 | // Start begins the spinner animation
 65 | func (s *Spinner) Start() {
 66 | 	s.mu.Lock()
 67 | 	if s.active {
 68 | 		s.mu.Unlock()
 69 | 		return
 70 | 	}
 71 | 	s.active = true
 72 | 	s.mu.Unlock()
 73 | 
 74 | 	go s.run()
 75 | }
 76 | 
 77 | // Stop halts the spinner animation
 78 | func (s *Spinner) Stop() {
 79 | 	s.mu.Lock()
 80 | 	defer s.mu.Unlock()
 81 | 
 82 | 	if !s.active {
 83 | 		return
 84 | 	}
 85 | 
 86 | 	s.active = false
 87 | 	close(s.stopCh)
 88 | 	s.stopCh = make(chan struct{})
 89 | 	fmt.Print("\r") // Clear the spinner line
 90 | }
 91 | 
 92 | // Internal methods
 93 | 
 94 | func (s *Spinner) run() {
 95 | 	ticker := time.NewTicker(s.config.Delay)
 96 | 	defer ticker.Stop()
 97 | 
 98 | 	cyan := color.New(color.FgCyan, color.Bold)
 99 | 	message := s.message
100 | 
101 | 	// Print initial state
102 | 	fmt.Printf("\r %s %s", cyan.Sprint(s.config.Frames[0]), message)
103 | 
104 | 	for {
105 | 		select {
106 | 		case <-s.stopCh:
107 | 			return
108 | 		case <-ticker.C:
109 | 			s.mu.RLock()
110 | 			if !s.active {
111 | 				s.mu.RUnlock()
112 | 				return
113 | 			}
114 | 			frame := s.config.Frames[s.current%len(s.config.Frames)]
115 | 			s.current++
116 | 			s.mu.RUnlock()
117 | 
118 | 			fmt.Printf("\r %s", cyan.Sprint(frame))
119 | 			fmt.Printf("\033[%dG%s", 4, message) // Move cursor and print message
120 | 		}
121 | 	}
122 | }
123 | 


--------------------------------------------------------------------------------
/pkg/idgen/generator.go:
--------------------------------------------------------------------------------
  1 | package idgen
  2 | 
  3 | import (
  4 | 	"crypto/rand"
  5 | 	"encoding/hex"
  6 | 	"fmt"
  7 | 	"sync"
  8 | )
  9 | 
 10 | // Generator handles secure ID generation for machines and devices
 11 | type Generator struct {
 12 | 	bufferPool sync.Pool
 13 | }
 14 | 
 15 | // NewGenerator creates a new ID generator
 16 | func NewGenerator() *Generator {
 17 | 	return &Generator{
 18 | 		bufferPool: sync.Pool{
 19 | 			New: func() interface{} {
 20 | 				return make([]byte, 64)
 21 | 			},
 22 | 		},
 23 | 	}
 24 | }
 25 | 
 26 | // Constants for ID generation
 27 | const (
 28 | 	machineIDPrefix = "auth0|user_"
 29 | 	uuidFormat      = "%s-%s-%s-%s-%s"
 30 | )
 31 | 
 32 | // generateRandomHex generates a random hex string of specified length
 33 | func (g *Generator) generateRandomHex(length int) (string, error) {
 34 | 	buffer := g.bufferPool.Get().([]byte)
 35 | 	defer g.bufferPool.Put(buffer)
 36 | 
 37 | 	if _, err := rand.Read(buffer[:length]); err != nil {
 38 | 		return "", fmt.Errorf("failed to generate random bytes: %w", err)
 39 | 	}
 40 | 	return hex.EncodeToString(buffer[:length]), nil
 41 | }
 42 | 
 43 | // GenerateMachineID generates a new machine ID with auth0|user_ prefix
 44 | func (g *Generator) GenerateMachineID() (string, error) {
 45 | 	randomPart, err := g.generateRandomHex(32) // 生成64字符的十六进制
 46 | 	if err != nil {
 47 | 		return "", err
 48 | 	}
 49 | 
 50 | 	return fmt.Sprintf("%x%s", []byte(machineIDPrefix), randomPart), nil
 51 | }
 52 | 
 53 | // GenerateMacMachineID generates a new 64-byte MAC machine ID
 54 | func (g *Generator) GenerateMacMachineID() (string, error) {
 55 | 	return g.generateRandomHex(32) // 生成64字符的十六进制
 56 | }
 57 | 
 58 | // GenerateDeviceID generates a new device ID in UUID format
 59 | func (g *Generator) GenerateDeviceID() (string, error) {
 60 | 	id, err := g.generateRandomHex(16)
 61 | 	if err != nil {
 62 | 		return "", err
 63 | 	}
 64 | 	return fmt.Sprintf(uuidFormat,
 65 | 		id[0:8], id[8:12], id[12:16], id[16:20], id[20:32]), nil
 66 | }
 67 | 
 68 | // GenerateSQMID generates a new SQM ID in UUID format (with braces)
 69 | func (g *Generator) GenerateSQMID() (string, error) {
 70 | 	id, err := g.GenerateDeviceID()
 71 | 	if err != nil {
 72 | 		return "", err
 73 | 	}
 74 | 	return fmt.Sprintf("{%s}", id), nil
 75 | }
 76 | 
 77 | // ValidateID validates the format of various ID types
 78 | func (g *Generator) ValidateID(id string, idType string) bool {
 79 | 	switch idType {
 80 | 	case "machineID", "macMachineID":
 81 | 		return len(id) == 64 && isHexString(id)
 82 | 	case "deviceID":
 83 | 		return isValidUUID(id)
 84 | 	case "sqmID":
 85 | 		if len(id) < 2 || id[0] != '{' || id[len(id)-1] != '}' {
 86 | 			return false
 87 | 		}
 88 | 		return isValidUUID(id[1 : len(id)-1])
 89 | 	default:
 90 | 		return false
 91 | 	}
 92 | }
 93 | 
 94 | // Helper functions
 95 | func isHexString(s string) bool {
 96 | 	_, err := hex.DecodeString(s)
 97 | 	return err == nil
 98 | }
 99 | 
100 | func isValidUUID(uuid string) bool {
101 | 	if len(uuid) != 36 {
102 | 		return false
103 | 	}
104 | 	for i, r := range uuid {
105 | 		if i == 8 || i == 13 || i == 18 || i == 23 {
106 | 			if r != '-' {
107 | 				return false
108 | 			}
109 | 			continue
110 | 		}
111 | 		if !((r >= '0' && r <= '9') || (r >= 'a' && r <= 'f') || (r >= 'A' && r <= 'F')) {
112 | 			return false
113 | 		}
114 | 	}
115 | 	return true
116 | }
117 | 


--------------------------------------------------------------------------------
/process_cursor_links.py:
--------------------------------------------------------------------------------
  1 | import csv
  2 | from dataclasses import dataclass
  3 | from typing import List
  4 | import json
  5 | 
  6 | @dataclass
  7 | class CursorVersion:
  8 |     version: str
  9 |     build_id: str
 10 |     
 11 |     def get_download_links(self) -> dict:
 12 |         base_url = f"https://downloader.cursor.sh/builds/{self.build_id}"
 13 |         return {
 14 |             "windows": {
 15 |                 "x64": f"{base_url}/windows/nsis/x64",
 16 |                 "arm64": f"{base_url}/windows/nsis/arm64"
 17 |             },
 18 |             "mac": {
 19 |                 "universal": f"{base_url}/mac/installer/universal",
 20 |                 "arm64": f"{base_url}/mac/installer/arm64",
 21 |                 "x64": f"{base_url}/mac/installer/x64"
 22 |             },
 23 |             "linux": {
 24 |                 "x64": f"{base_url}/linux/appImage/x64"
 25 |             }
 26 |         }
 27 | 
 28 | def parse_versions(data: str) -> List[CursorVersion]:
 29 |     versions = []
 30 |     for line in data.strip().split('\n'):
 31 |         if not line:
 32 |             continue
 33 |         version, build_id = line.strip().split(',')
 34 |         versions.append(CursorVersion(version, build_id))
 35 |     return versions
 36 | 
 37 | def generate_markdown(versions: List[CursorVersion]) -> str:
 38 |     md = """# 🖥️ Windows
 39 | 
 40 | ## x64
 41 | <details>
 42 | <summary style="font-size:1.2em">📦 Windows x64 安装包</summary>
 43 | 
 44 | | 版本 | 下载链接 |
 45 | |------|----------|
 46 | """
 47 |     
 48 |     # Windows x64
 49 |     for version in versions:
 50 |         links = version.get_download_links()
 51 |         md += f"| {version.version} | [下载]({links['windows']['x64']}) |\n"
 52 |     
 53 |     md += """
 54 | </details>
 55 | 
 56 | ## ARM64 
 57 | <details>
 58 | <summary style="font-size:1.2em">📱 Windows ARM64 安装包</summary>
 59 | 
 60 | | 版本 | 下载链接 |
 61 | |------|----------|
 62 | """
 63 |     
 64 |     # Windows ARM64
 65 |     for version in versions:
 66 |         links = version.get_download_links()
 67 |         md += f"| {version.version} | [下载]({links['windows']['arm64']}) |\n"
 68 |     
 69 |     md += """
 70 | </details>
 71 | 
 72 | # 🍎 macOS
 73 | 
 74 | ## Universal
 75 | <details>
 76 | <summary style="font-size:1.2em">🎯 macOS Universal 安装包</summary>
 77 | 
 78 | | 版本 | 下载链接 |
 79 | |------|----------|
 80 | """
 81 |     
 82 |     # macOS Universal
 83 |     for version in versions:
 84 |         links = version.get_download_links()
 85 |         md += f"| {version.version} | [下载]({links['mac']['universal']}) |\n"
 86 |     
 87 |     md += """
 88 | </details>
 89 | 
 90 | ## ARM64
 91 | <details>
 92 | <summary style="font-size:1.2em">💪 macOS ARM64 安装包</summary>
 93 | 
 94 | | 版本 | 下载链接 |
 95 | |------|----------|
 96 | """
 97 |     
 98 |     # macOS ARM64
 99 |     for version in versions:
100 |         links = version.get_download_links()
101 |         md += f"| {version.version} | [下载]({links['mac']['arm64']}) |\n"
102 |     
103 |     md += """
104 | </details>
105 | 
106 | ## Intel
107 | <details>
108 | <summary style="font-size:1.2em">💻 macOS Intel 安装包</summary>
109 | 
110 | | 版本 | 下载链接 |
111 | |------|----------|
112 | """
113 |     
114 |     # macOS Intel
115 |     for version in versions:
116 |         links = version.get_download_links()
117 |         md += f"| {version.version} | [下载]({links['mac']['x64']}) |\n"
118 |     
119 |     md += """
120 | </details>
121 | 
122 | # 🐧 Linux
123 | 
124 | ## x64
125 | <details>
126 | <summary style="font-size:1.2em">🎮 Linux x64 AppImage</summary>
127 | 
128 | | 版本 | 下载链接 |
129 | |------|----------|
130 | """
131 |     
132 |     # Linux x64
133 |     for version in versions:
134 |         links = version.get_download_links()
135 |         md += f"| {version.version} | [下载]({links['linux']['x64']}) |\n"
136 |     
137 |     md += """
138 | </details>
139 | 
140 | <style>
141 | details {
142 |     margin: 1em 0;
143 |     padding: 0.5em 1em;
144 |     background: #f8f9fa;
145 |     border-radius: 8px;
146 |     box-shadow: 0 2px 4px rgba(0,0,0,0.1);
147 | }
148 | 
149 | summary {
150 |     cursor: pointer;
151 |     font-weight: bold;
152 |     margin: -0.5em -1em;
153 |     padding: 0.5em 1em;
154 | }
155 | 
156 | summary:hover {
157 |     background: #f1f3f5;
158 | }
159 | 
160 | table {
161 |     width: 100%;
162 |     border-collapse: collapse;
163 |     margin-top: 1em;
164 | }
165 | 
166 | th, td {
167 |     padding: 0.5em;
168 |     text-align: left;
169 |     border-bottom: 1px solid #dee2e6;
170 | }
171 | 
172 | tr:hover {
173 |     background: #f1f3f5;
174 | }
175 | 
176 | a {
177 |     color: #0366d6;
178 |     text-decoration: none;
179 | }
180 | 
181 | a:hover {
182 |     text-decoration: underline;
183 | }
184 | </style>
185 | """
186 |     return md
187 | 
188 | def main():
189 |     # 示例数据
190 |     data = """
191 | 0.45.11,250207y6nbaw5qc
192 | 0.45.10,250205buadkzpea
193 | 0.45.9,250202tgstl42dt
194 | 0.45.8,250201b44xw1x2k
195 | 0.45.7,250130nr6eorv84
196 | 0.45.6,25013021lv9say3
197 | 0.45.5,250128loaeyulq8
198 | 0.45.4,250126vgr3vztvj
199 | 0.45.3,250124b0rcj0qql
200 | 0.45.2,250123mhituoa6o
201 | 0.45.1,2501213ljml5byg
202 | 0.45.0,250120dh9ezx9pg
203 | 0.44.11,250103fqxdt5u9z
204 | 0.44.10,250102ys80vtnud
205 | 0.44.9,2412268nc6pfzgo
206 | 0.44.8,241222ooktny8mh
207 | 0.44.7,2412219nhracv01
208 | 0.44.6,2412214pmryneua
209 | 0.44.5,241220s3ux0e1tv
210 | 0.44.4,241219117fcvexy
211 | 0.44.3,241218sybfbogmq
212 | 0.44.2,241218ntls52u8v
213 | 0.44.0,2412187f9v0nffu
214 | 0.43.6,241206z7j6me2e2
215 | 0.43.5,241127pdg4cnbu2
216 | 0.43.4,241126w13goyvrs
217 | 0.43.3,2411246yqzx1jmm
218 | 0.43.1,241124gsiwb66nc
219 | 0.42.5,24111460bf2loz1
220 | 0.42.4,2410291z3bdg1dy
221 | 0.42.3,241016kxu9umuir
222 | 0.42.2,2410127mj66lvaq
223 | 0.42.1,241011i66p9fuvm
224 | 0.42.0,241009fij7nohn5
225 | 0.41.3,240925fkhcqg263
226 | 0.41.2,240921llnho65ov
227 | 0.41.1,2409189xe3envg5
228 | 0.40.4,2409052yfcjagw2
229 | 0.40.3,240829epqamqp7h
230 | 0.40.2,240828c021k3aib
231 | 0.40.1,2408245thnycuzj
232 | 0.40.0,24082202sreugb2
233 | 0.39.6,240819ih4ta2fye
234 | 0.39.5,240814y9rhzmu7h
235 | 0.39.4,240810elmeg3seq
236 | 0.39.3,2408092hoyaxt9m
237 | 0.39.2,240808phaxh4b5r
238 | 0.39.1,240807g919tr4ly
239 | 0.39.0,240802cdixtv9a6
240 | 0.38.1,240725f0ti25os7
241 | 0.38.0,240723790oxe4a2
242 | 0.37.1,240714yrr3gmv3k
243 | 0.36.2,2407077n6pzboby
244 | 0.36.1,240706uekt2eaft
245 | 0.36.0,240703xqkjv5aqa
246 | 0.35.1,240621pc2f7rl8a
247 | 0.35.0,240608cv11mfsjl
248 | 0.34.6,240606kgzq24cfb
249 | 0.34.6,240605r495newcf
250 | 0.34.5,240602rq6xovt3a
251 | 0.34.4,2406014h0rgjghe
252 | 0.34.3,240529baisuyd2e
253 | 0.34.2,240528whh1qyo9h
254 | 0.34.1,24052838ygfselt
255 | 0.34.0,240527xus72jmkj
256 | 0.33.4,240511kb8wt1tms
257 | 0.33.3,2405103lx8342ta
258 | 0.33.2,240510dwmw395qe
259 | 0.33.1,2405039a9h2fqc9
260 | 0.33.0,240503hyjsnhazo
261 | 0.32.8,240428d499o6zja
262 | 0.32.7,240427w5guozr0l
263 | 0.32.2,240417ab4wag7sx
264 | 0.32.1,2404152czor73fk
265 | 0.32.0,240412ugli06ue0
266 | 0.31.3,240402rq154jw46
267 | 0.31.1,240402pkwfm2ps6
268 | 0.31.0,2404018j7z0xv2g
269 | 0.30.5,240327tmd2ozdc7
270 | 0.30.4,240325dezy8ziab
271 | 0.30.3,2403229gtuhto9g
272 | 0.30.2,240322gzqjm3p0d
273 | 0.30.1,2403212w1ejubt8
274 | 0.30.0,240320tpx86e7hk
275 | 0.29.1,2403027twmz0d1t
276 | 0.29.0,240301kpqvacw2h
277 | 0.28.1,240226tstim4evd
278 | 0.28.0,240224g2d7jazcq
279 | 0.27.4,240219qdbagglqz
280 | 0.27.3,240218dxhc6y8os
281 | 0.27.2,240216kkzl9nhxi
282 | 0.27.1,240215l4ooehnyl
283 | 0.27.0,240215at6ewkd59
284 | 0.26.2,240212o6r9qxtcg
285 | 0.26.1,2402107t904hing
286 | 0.26.0,240210k8is5xr6v
287 | 0.25.3,240207aacboj1k8
288 | 0.25.2,240206p3708uc9z
289 | 0.25.1,2402033t030rprh
290 | 0.25.0,240203kh86t91q8
291 | 0.24.4,240129iecm3e33w
292 | 0.24.3,2401289dx79qsc0
293 | 0.24.1,240127cad17436d
294 | 0.24.0,240126wp9irhmza
295 | 0.23.9,240124dsmraeml3
296 | 0.23.8,240123fnn1hj1fg
297 | 0.23.7,240123xsfe7ywcv
298 | 0.23.6,240121m1740elox
299 | 0.23.5,2401215utj6tx6q
300 | 0.23.4,240121f4qy6ba2y
301 | 0.23.3,2401201und3ytom
302 | 0.23.2,240120an2k2hf1i
303 | 0.23.1,240119fgzxwudn9
304 | 0.22.2,24011721vsch1l1
305 | 0.22.1,2401083eyk8kmzc
306 | 0.22.0,240107qk62kvva3
307 | 0.21.1,231230h0vi6srww
308 | 0.21.0,231229ezidnxiu3
309 | 0.20.2,231219aksf83aad
310 | 0.20.1,231218ywfaxax09
311 | 0.20.0,231216nsyfew5j1
312 | 0.19.1,2312156z2ric57n
313 | 0.19.0,231214per9qal2p
314 | 0.18.8,2312098ffjr3ign
315 | 0.18.7,23120880aolip2i
316 | 0.18.6,231207ueqazwde8
317 | 0.18.5,231206jzy2n2sbi
318 | 0.18.4,2312033zjv5fqai
319 | 0.18.3,231203k2vnkxq2m
320 | 0.18.1,23120176kaer07t
321 | 0.17.0,231127p7iyxn8rg
322 | 0.16.0,231116rek2xuq6a
323 | 0.15.5,231115a5mv63u9f
324 | 0.15.4,23111469e1i3xyi
325 | 0.15.3,231113b0yv3uqem
326 | 0.15.2,231113ah0kuf3pf
327 | 0.15.1,231111yanyyovap
328 | 0.15.0,231110mdkomczmw
329 | 0.14.1,231109xitrgihlk
330 | 0.14.0,231102m6tuamwbx
331 | 0.13.4,231029rso7pso8l
332 | 0.13.3,231025uihnjkh9v
333 | 0.13.2,231024w4iv7xlm6
334 | 0.13.1,231022f3j0ubckv
335 | 0.13.0,231022ptw6i4j42
336 | 0.12.3,231008c5ursm0oj"""
337 |     
338 |     versions = parse_versions(data)
339 |     
340 |     # 生成 Markdown 文件
341 |     markdown_content = generate_markdown(versions)
342 |     with open('Cursor历史.md', 'w', encoding='utf-8') as f:
343 |         f.write(markdown_content)
344 |     
345 |     # 创建结果数据结构
346 |     result = {
347 |         "versions": []
348 |     }
349 |     
350 |     # 处理每个版本
351 |     for version in versions:
352 |         version_info = {
353 |             "version": version.version,
354 |             "build_id": version.build_id,
355 |             "downloads": version.get_download_links()
356 |         }
357 |         result["versions"].append(version_info)
358 |     
359 |     # 保存为JSON文件
360 |     with open('cursor_downloads.json', 'w', encoding='utf-8') as f:
361 |         json.dump(result, f, indent=2, ensure_ascii=False)
362 |     
363 |     # 同时生成CSV格式的下载链接
364 |     with open('cursor_downloads.csv', 'w', newline='', encoding='utf-8') as f:
365 |         writer = csv.writer(f)
366 |         writer.writerow(['Version', 'Platform', 'Architecture', 'Download URL'])
367 |         
368 |         for version in versions:
369 |             links = version.get_download_links()
370 |             for platform, archs in links.items():
371 |                 for arch, url in archs.items():
372 |                     writer.writerow([version.version, platform, arch, url])
373 | 
374 | if __name__ == "__main__":
375 |     main() 


--------------------------------------------------------------------------------
/scripts/build_all.bat:
--------------------------------------------------------------------------------
 1 | @echo off
 2 | setlocal EnableDelayedExpansion
 3 | 
 4 | :: Build optimization flags
 5 | set "OPTIMIZATION_FLAGS=-trimpath -ldflags=\"-s -w\""
 6 | set "BUILD_JOBS=4"
 7 | 
 8 | :: Messages / 消息
 9 | set "EN_MESSAGES[0]=Starting build process for version"
10 | set "EN_MESSAGES[1]=Using optimization flags:"
11 | set "EN_MESSAGES[2]=Cleaning old builds..."
12 | set "EN_MESSAGES[3]=Cleanup completed"
13 | set "EN_MESSAGES[4]=Starting builds for all platforms..."
14 | set "EN_MESSAGES[5]=Building for"
15 | set "EN_MESSAGES[6]=Build successful:"
16 | set "EN_MESSAGES[7]=All builds completed!"
17 | 
18 | :: Colors
19 | set "GREEN=[32m"
20 | set "RED=[31m"
21 | set "RESET=[0m"
22 | 
23 | :: Cleanup function
24 | :cleanup
25 | if exist "..\bin" (
26 |     rd /s /q "..\bin"
27 |     echo %GREEN%!EN_MESSAGES[3]!%RESET%
28 | )
29 | mkdir "..\bin" 2>nul
30 | 
31 | :: Build function with optimizations
32 | :build
33 | set "os=%~1"
34 | set "arch=%~2"
35 | set "ext="
36 | if "%os%"=="windows" set "ext=.exe"
37 | 
38 | echo %GREEN%!EN_MESSAGES[5]! %os%/%arch%%RESET%
39 | 
40 | set "CGO_ENABLED=0"
41 | set "GOOS=%os%"
42 | set "GOARCH=%arch%"
43 | 
44 | 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"
45 | exit /b 0
46 | 
47 | :: Main execution
48 | echo %GREEN%!EN_MESSAGES[0]!%RESET%
49 | echo %GREEN%!EN_MESSAGES[1]! %OPTIMIZATION_FLAGS%%RESET%
50 | 
51 | call :cleanup
52 | 
53 | echo %GREEN%!EN_MESSAGES[4]!%RESET%
54 | 
55 | :: Start builds in parallel
56 | set "pending=0"
57 | for %%o in (windows linux darwin) do (
58 |     for %%a in (amd64 386) do (
59 |         call :build %%o %%a
60 |         set /a "pending+=1"
61 |         if !pending! geq %BUILD_JOBS% (
62 |             timeout /t 1 /nobreak >nul
63 |             set "pending=0"
64 |         )
65 |     )
66 | )
67 | 
68 | :: Wait for all builds to complete
69 | :wait_builds
70 | timeout /t 2 /nobreak >nul
71 | tasklist /fi "IMAGENAME eq go.exe" 2>nul | find "go.exe" >nul
72 | if not errorlevel 1 goto wait_builds
73 | 
74 | echo %GREEN%!EN_MESSAGES[7]!%RESET%


--------------------------------------------------------------------------------
/scripts/build_all.sh:
--------------------------------------------------------------------------------
  1 | #!/bin/bash
  2 | 
  3 | # 设置颜色代码 / Set color codes
  4 | GREEN='\033[0;32m'
  5 | RED='\033[0;31m'
  6 | NC='\033[0m' # No Color / 无颜色
  7 | 
  8 | # Build optimization flags
  9 | OPTIMIZATION_FLAGS="-trimpath -ldflags=\"-s -w\""
 10 | PARALLEL_JOBS=$(nproc || echo "4")  # Get number of CPU cores or default to 4
 11 | 
 12 | # Messages / 消息
 13 | EN_MESSAGES=(
 14 |     "Starting build process for version"
 15 |     "Cleaning old builds..."
 16 |     "Creating bin directory..."
 17 |     "Failed to create bin directory"
 18 |     "Building for"
 19 |     "Successfully built:"
 20 |     "Failed to build for"
 21 |     "Build Summary:"
 22 |     "Successful builds:"
 23 |     "Failed builds:"
 24 |     "Generated files:"
 25 | )
 26 | 
 27 | CN_MESSAGES=(
 28 |     "开始构建版本"
 29 |     "正在清理旧的构建文件..."
 30 |     "正在创建bin目录..."
 31 |     "创建bin目录失败"
 32 |     "正在构建"
 33 |     "构建成功:"
 34 |     "构建失败:"
 35 |     "构建摘要:"
 36 |     "成功构建数:"
 37 |     "失败构建数:"
 38 |     "生成的文件:"
 39 |     "构建过程被中断"
 40 |     "错误:"
 41 | )
 42 | 
 43 | # 版本信息 / Version info
 44 | VERSION="1.0.0"
 45 | 
 46 | # Detect system language / 检测系统语言
 47 | detect_language() {
 48 |     if [[ $(locale | grep "LANG=zh_CN") ]]; then
 49 |         echo "cn"
 50 |     else
 51 |         echo "en"
 52 |     fi
 53 | }
 54 | 
 55 | # Get message based on language / 根据语言获取消息
 56 | get_message() {
 57 |     local index=$1
 58 |     local lang=$(detect_language)
 59 |     
 60 |     if [[ "$lang" == "cn" ]]; then
 61 |         echo "${CN_MESSAGES[$index]}"
 62 |     else
 63 |         echo "${EN_MESSAGES[$index]}"
 64 |     fi
 65 | }
 66 | 
 67 | # 错误处理函数 / Error handling function
 68 | handle_error() {
 69 |     echo -e "${RED}$(get_message 12) $1${NC}"
 70 |     exit 1
 71 | }
 72 | 
 73 | # 清理函数 / Cleanup function
 74 | cleanup() {
 75 |     if [ -d "../bin" ]; then
 76 |         rm -rf ../bin
 77 |         echo -e "${GREEN}$(get_message 1)${NC}"
 78 |     fi
 79 | }
 80 | 
 81 | # Build function with optimizations
 82 | build() {
 83 |     local os=$1
 84 |     local arch=$2
 85 |     local ext=""
 86 |     [ "$os" = "windows" ] && ext=".exe"
 87 |     
 88 |     echo -e "${GREEN}$(get_message 4) $os/$arch${NC}"
 89 |     
 90 |     GOOS=$os GOARCH=$arch CGO_ENABLED=0 go build \
 91 |         -trimpath \
 92 |         -ldflags="-s -w" \
 93 |         -o "../bin/$os/$arch/cursor-id-modifier$ext" \
 94 |         -a -installsuffix cgo \
 95 |         -mod=readonly \
 96 |         ../cmd/cursor-id-modifier &
 97 | }
 98 | 
 99 | # Parallel build execution
100 | build_all() {
101 |     local builds=0
102 |     local max_parallel=$PARALLEL_JOBS
103 |     
104 |     # Define build targets
105 |     declare -A targets=(
106 |         ["linux/amd64"]=1
107 |         ["linux/386"]=1
108 |         ["linux/arm64"]=1
109 |         ["windows/amd64"]=1
110 |         ["windows/386"]=1
111 |         ["darwin/amd64"]=1
112 |         ["darwin/arm64"]=1
113 |     )
114 |     
115 |     for target in "${!targets[@]}"; do
116 |         IFS='/' read -r os arch <<< "$target"
117 |         build "$os" "$arch"
118 |         
119 |         ((builds++))
120 |         
121 |         if ((builds >= max_parallel)); then
122 |             wait
123 |             builds=0
124 |         fi
125 |     done
126 |     
127 |     # Wait for remaining builds
128 |     wait
129 | }
130 | 
131 | # Main execution
132 | main() {
133 |     cleanup
134 |     mkdir -p ../bin || { echo -e "${RED}$(get_message 3)${NC}"; exit 1; }
135 |     build_all
136 |     echo -e "${GREEN}Build completed successfully${NC}"
137 | }
138 | 
139 | # 捕获错误信号 / Catch error signals
140 | trap 'echo -e "\n${RED}$(get_message 11)${NC}"; exit 1' INT TERM
141 | 
142 | # 执行主函数 / Execute main function
143 | main


--------------------------------------------------------------------------------
/scripts/cursor_id_modifier.pot:
--------------------------------------------------------------------------------
  1 | msgid ""
  2 | msgstr ""
  3 | "Project-Id-Version: cursor_id_modifier\n"
  4 | "POT-Creation-Date: 2025-04-25 12:00+0000\n"
  5 | "PO-Revision-Date: 2025-04-25 12:00+0000\n"
  6 | "Language-Team: None\n"
  7 | "MIME-Version: 1.0\n"
  8 | "Content-Type: text/plain; charset=UTF-8\n"
  9 | "Content-Transfer-Encoding: 8bit\n"
 10 | 
 11 | msgid "Error: No translation file found for domain 'cursor_id_modifier' in {}/zh_CN/LC_MESSAGES/"
 12 | msgstr ""
 13 | 
 14 | msgid "========== Cursor ID modification tool log start {} =========="
 15 | msgstr ""
 16 | 
 17 | msgid "[INFO] {} {}"
 18 | msgstr ""
 19 | 
 20 | msgid "[WARN] {} {}"
 21 | msgstr ""
 22 | 
 23 | msgid "[ERROR] {} {}"
 24 | msgstr ""
 25 | 
 26 | msgid "[DEBUG] {} {}"
 27 | msgstr ""
 28 | 
 29 | msgid "[CMD] {} Executing command: {}"
 30 | msgstr ""
 31 | 
 32 | msgid "[CMD] {}:"
 33 | msgstr ""
 34 | 
 35 | msgid "Unable to get username"
 36 | msgstr ""
 37 | 
 38 | msgid "Finding Cursor installation path..."
 39 | msgstr ""
 40 | 
 41 | msgid "Found Cursor installation path: {}"
 42 | msgstr ""
 43 | 
 44 | msgid "Found Cursor via which: {}"
 45 | msgstr ""
 46 | 
 47 | msgid "Cursor executable not found, will try using config directory"
 48 | msgstr ""
 49 | 
 50 | msgid "Found Cursor via search: {}"
 51 | msgstr ""
 52 | 
 53 | msgid "Finding Cursor resource directory..."
 54 | msgstr ""
 55 | 
 56 | msgid "Found Cursor resource directory: {}"
 57 | msgstr ""
 58 | 
 59 | msgid "Found resource directory via binary path: {}"
 60 | msgstr ""
 61 | 
 62 | msgid "Cursor resource directory not found"
 63 | msgstr ""
 64 | 
 65 | msgid "Please run this script with sudo"
 66 | msgstr ""
 67 | 
 68 | msgid "Example: sudo {}"
 69 | msgstr ""
 70 | 
 71 | msgid "Checking Cursor processes..."
 72 | msgstr ""
 73 | 
 74 | msgid "Getting process details for {}:"
 75 | msgstr ""
 76 | 
 77 | msgid "No running Cursor processes found"
 78 | msgstr ""
 79 | 
 80 | msgid "Found running Cursor processes"
 81 | msgstr ""
 82 | 
 83 | msgid "Attempting to terminate Cursor processes..."
 84 | msgstr ""
 85 | 
 86 | msgid "Attempting to forcefully terminate processes..."
 87 | msgstr ""
 88 | 
 89 | msgid "Waiting for processes to terminate, attempt {}/{}..."
 90 | msgstr ""
 91 | 
 92 | msgid "Cursor processes successfully terminated"
 93 | msgstr ""
 94 | 
 95 | msgid "Unable to terminate Cursor processes after {} attempts"
 96 | msgstr ""
 97 | 
 98 | msgid "Please manually terminate the processes and try again"
 99 | msgstr ""
100 | 
101 | msgid "Configuration file does not exist, skipping backup"
102 | msgstr ""
103 | 
104 | msgid "Configuration backed up to: {}"
105 | msgstr ""
106 | 
107 | msgid "Backup failed"
108 | msgstr ""
109 | 
110 | msgid "File does not exist: {}"
111 | msgstr ""
112 | 
113 | msgid "Unable to modify file permissions: {}"
114 | msgstr ""
115 | 
116 | msgid "Generated temporary file is empty"
117 | msgstr ""
118 | 
119 | msgid "Unable to write to file: {}"
120 | msgstr ""
121 | 
122 | msgid "Machine code reset options"
123 | msgstr ""
124 | 
125 | msgid "Do you need to reset the machine code? (Usually, modifying JS files is sufficient):"
126 | msgstr ""
127 | 
128 | msgid "Don't reset - only modify JS files"
129 | msgstr ""
130 | 
131 | msgid "Reset - modify both config file and machine code"
132 | msgstr ""
133 | 
134 | msgid "[INPUT_DEBUG] Machine code reset option selected: {}"
135 | msgstr ""
136 | 
137 | msgid "You chose to reset the machine code"
138 | msgstr ""
139 | 
140 | msgid "Found existing configuration file: {}"
141 | msgstr ""
142 | 
143 | msgid "Setting new device and machine IDs..."
144 | msgstr ""
145 | 
146 | msgid "New device ID: {}"
147 | msgstr ""
148 | 
149 | msgid "New machine ID: {}"
150 | msgstr ""
151 | 
152 | msgid "Configuration file modified successfully"
153 | msgstr ""
154 | 
155 | msgid "Configuration file modification failed"
156 | msgstr ""
157 | 
158 | msgid "Configuration file not found, this is normal, skipping ID modification"
159 | msgstr ""
160 | 
161 | msgid "You chose not to reset the machine code, will only modify JS files"
162 | msgstr ""
163 | 
164 | msgid "Configuration processing completed"
165 | msgstr ""
166 | 
167 | msgid "Finding Cursor's JS files..."
168 | msgstr ""
169 | 
170 | msgid "Searching for JS files in resource directory: {}"
171 | msgstr ""
172 | 
173 | msgid "Found JS file: {}"
174 | msgstr ""
175 | 
176 | msgid "No JS files found in resource directory, trying other directories..."
177 | msgstr ""
178 | 
179 | msgid "Searching directory: {}"
180 | msgstr ""
181 | 
182 | msgid "No modifiable JS files found"
183 | msgstr ""
184 | 
185 | msgid "Found {} JS files to modify"
186 | msgstr ""
187 | 
188 | msgid "Starting to modify Cursor's JS files..."
189 | msgstr ""
190 | 
191 | msgid "Unable to find modifiable JS files"
192 | msgstr ""
193 | 
194 | msgid "Processing file: {}"
195 | msgstr ""
196 | 
197 | msgid "Unable to create backup for file: {}"
198 | msgstr ""
199 | 
200 | msgid "Found x-cursor-checksum setting code"
201 | msgstr ""
202 | 
203 | msgid "Successfully modified x-cursor-checksum setting code"
204 | msgstr ""
205 | 
206 | msgid "Failed to modify x-cursor-checksum setting code"
207 | msgstr ""
208 | 
209 | msgid "Found IOPlatformUUID keyword"
210 | msgstr ""
211 | 
212 | msgid "Successfully injected randomUUID call into a$ function"
213 | msgstr ""
214 | 
215 | msgid "Failed to modify a$ function"
216 | msgstr ""
217 | 
218 | msgid "Successfully injected randomUUID call into v5 function"
219 | msgstr ""
220 | 
221 | msgid "Failed to modify v5 function"
222 | msgstr ""
223 | 
224 | msgid "Completed universal modification"
225 | msgstr ""
226 | 
227 | msgid "File already contains custom injection code, skipping modification"
228 | msgstr ""
229 | 
230 | msgid "Completed most universal injection"
231 | msgstr ""
232 | 
233 | msgid "File has already been modified, skipping modification"
234 | msgstr ""
235 | 
236 | msgid "Failed to modify any JS files"
237 | msgstr ""
238 | 
239 | msgid "Successfully modified {} JS files"
240 | msgstr ""
241 | 
242 | msgid "Disabling Cursor auto-update..."
243 | msgstr ""
244 | 
245 | msgid "Found update configuration file: {}"
246 | msgstr ""
247 | 
248 | msgid "Disabled update configuration file: {}"
249 | msgstr ""
250 | 
251 | msgid "Found updater: {}"
252 | msgstr ""
253 | 
254 | msgid "Disabled updater: {}"
255 | msgstr ""
256 | 
257 | msgid "No update configuration files or updaters found"
258 | msgstr ""
259 | 
260 | msgid "Successfully disabled auto-update"
261 | msgstr ""
262 | 
263 | msgid "You selected: {}"
264 | msgstr ""
265 | 
266 | msgid "This script only supports Linux systems"
267 | msgstr ""
268 | 
269 | msgid "Script started..."
270 | msgstr ""
271 | 
272 | msgid "System information: {}"
273 | msgstr ""
274 | 
275 | msgid "Current user: {}"
276 | msgstr ""
277 | 
278 | msgid "System version information"
279 | msgstr ""
280 | 
281 | msgid "Cursor Linux startup tool"
282 | msgstr ""
283 | 
284 | msgid "Important notice"
285 | msgstr ""
286 | 
287 | msgid "This tool prioritizes modifying JS files, which is safer and more reliable"
288 | msgstr ""
289 | 
290 | msgid "Modifying Cursor JS files..."
291 | msgstr ""
292 | 
293 | msgid "JS files modified successfully!"
294 | msgstr ""
295 | 
296 | msgid "JS file modification failed, but configuration file modification may have succeeded"
297 | msgstr ""
298 | 
299 | msgid "If Cursor still indicates the device is disabled after restarting, please rerun this script"
300 | msgstr ""
301 | 
302 | msgid "Please restart Cursor to apply the new configuration"
303 | msgstr ""
304 | 
305 | 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)"
306 | msgstr ""
307 | 
308 | msgid "Script execution completed"
309 | msgstr ""
310 | 
311 | msgid "========== Cursor ID modification tool log end {} =========="
312 | msgstr ""
313 | 
314 | msgid "Detailed log saved to: {}"
315 | msgstr ""
316 | 
317 | msgid "If you encounter issues, please provide this log file to the developer for troubleshooting"
318 | msgstr ""
319 | 


--------------------------------------------------------------------------------
/scripts/git-actions.sh:
--------------------------------------------------------------------------------
 1 | #!/bin/bash
 2 | REPO_DIR="$PWD"
 3 | LOCALES_DIR="$REPO_DIR/locales"
 4 | msginit -i cursor_id_modifier.pot -o $LOCALES_DIR/en_US/LC_MESSAGES/cursor_id_modifier.po -l en_US
 5 | for lang in en_US zh_CN; do
 6 |     cd $LOCALES_DIR/$lang/LC_MESSAGES
 7 |     msgfmt -o cursor_id_modifier.mo cursor_id_modifier.po
 8 | done
 9 | 
10 | 


--------------------------------------------------------------------------------
/scripts/install.ps1:
--------------------------------------------------------------------------------
  1 | # Check for admin rights and handle elevation
  2 | $isAdmin = ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")
  3 | if (-NOT $isAdmin) {
  4 |     # Detect PowerShell version and path
  5 |     $pwshPath = if (Get-Command "pwsh" -ErrorAction SilentlyContinue) {
  6 |         (Get-Command "pwsh").Source  # PowerShell 7+
  7 |     } elseif (Test-Path "$env:ProgramFiles\PowerShell\7\pwsh.exe") {
  8 |         "$env:ProgramFiles\PowerShell\7\pwsh.exe"
  9 |     } else {
 10 |         "powershell.exe"  # Windows PowerShell
 11 |     }
 12 |     
 13 |     try {
 14 |         Write-Host "`nRequesting administrator privileges..." -ForegroundColor Cyan
 15 |         $scriptPath = $MyInvocation.MyCommand.Path
 16 |         $argList = "-NoProfile -ExecutionPolicy Bypass -File `"$scriptPath`""
 17 |         Start-Process -FilePath $pwshPath -Verb RunAs -ArgumentList $argList -Wait
 18 |         exit
 19 |     }
 20 |     catch {
 21 |         Write-Host "`nError: Administrator privileges required" -ForegroundColor Red
 22 |         Write-Host "Please run this script from an Administrator PowerShell window" -ForegroundColor Yellow
 23 |         Write-Host "`nTo do this:" -ForegroundColor Cyan
 24 |         Write-Host "1. Press Win + X" -ForegroundColor White
 25 |         Write-Host "2. Click 'Windows Terminal (Admin)' or 'PowerShell (Admin)'" -ForegroundColor White
 26 |         Write-Host "3. Run the installation command again" -ForegroundColor White
 27 |         Write-Host "`nPress enter to exit..."
 28 |         $null = $Host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown')
 29 |         exit 1
 30 |     }
 31 | }
 32 | 
 33 | # Set TLS to 1.2
 34 | [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
 35 | 
 36 | # Create temporary directory
 37 | $TmpDir = Join-Path $env:TEMP ([System.Guid]::NewGuid().ToString())
 38 | New-Item -ItemType Directory -Path $TmpDir | Out-Null
 39 | 
 40 | # Cleanup function
 41 | function Cleanup {
 42 |     if (Test-Path $TmpDir) {
 43 |         Remove-Item -Recurse -Force $TmpDir
 44 |     }
 45 | }
 46 | 
 47 | # Error handler
 48 | trap {
 49 |     Write-Host "Error: $_" -ForegroundColor Red
 50 |     Cleanup
 51 |     Write-Host "Press enter to exit..."
 52 |     $null = $Host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown')
 53 |     exit 1
 54 | }
 55 | 
 56 | # Detect system architecture
 57 | function Get-SystemArch {
 58 |     if ([Environment]::Is64BitOperatingSystem) {
 59 |         return "x86_64"
 60 |     } else {
 61 |         return "i386"
 62 |     }
 63 | }
 64 | 
 65 | # Download with progress
 66 | function Get-FileWithProgress {
 67 |     param (
 68 |         [string]$Url,
 69 |         [string]$OutputFile
 70 |     )
 71 |     
 72 |     try {
 73 |         $webClient = New-Object System.Net.WebClient
 74 |         $webClient.Headers.Add("User-Agent", "PowerShell Script")
 75 |         
 76 |         $webClient.DownloadFile($Url, $OutputFile)
 77 |         return $true
 78 |     }
 79 |     catch {
 80 |         Write-Host "Failed to download: $_" -ForegroundColor Red
 81 |         return $false
 82 |     }
 83 | }
 84 | 
 85 | # Main installation function
 86 | function Install-CursorModifier {
 87 |     Write-Host "Starting installation..." -ForegroundColor Cyan
 88 |     
 89 |     # Detect architecture
 90 |     $arch = Get-SystemArch
 91 |     Write-Host "Detected architecture: $arch" -ForegroundColor Green
 92 |     
 93 |     # Set installation directory
 94 |     $InstallDir = "$env:ProgramFiles\CursorModifier"
 95 |     if (!(Test-Path $InstallDir)) {
 96 |         New-Item -ItemType Directory -Path $InstallDir | Out-Null
 97 |     }
 98 |     
 99 |     # Get latest release
100 |     try {
101 |         $latestRelease = Invoke-RestMethod -Uri "https://api.github.com/repos/yuaotian/go-cursor-help/releases/latest"
102 |         Write-Host "Found latest release: $($latestRelease.tag_name)" -ForegroundColor Cyan
103 |         
104 |         # Look for Windows binary with our architecture
105 |         $version = $latestRelease.tag_name.TrimStart('v')
106 |         Write-Host "Version: $version" -ForegroundColor Cyan
107 |         $possibleNames = @(
108 |             "cursor-id-modifier_${version}_windows_x86_64.exe",
109 |             "cursor-id-modifier_${version}_windows_$($arch).exe"
110 |         )
111 |         
112 |         $asset = $null
113 |         foreach ($name in $possibleNames) {
114 |             Write-Host "Checking for asset: $name" -ForegroundColor Cyan
115 |             $asset = $latestRelease.assets | Where-Object { $_.name -eq $name }
116 |             if ($asset) {
117 |                 Write-Host "Found matching asset: $($asset.name)" -ForegroundColor Green
118 |                 break
119 |             }
120 |         }
121 |         
122 |         if (!$asset) {
123 |             Write-Host "`nAvailable assets:" -ForegroundColor Yellow
124 |             $latestRelease.assets | ForEach-Object { Write-Host "- $($_.name)" }
125 |             throw "Could not find appropriate Windows binary for $arch architecture"
126 |         }
127 |         
128 |         $downloadUrl = $asset.browser_download_url
129 |     }
130 |     catch {
131 |         Write-Host "Failed to get latest release: $_" -ForegroundColor Red
132 |         exit 1
133 |     }
134 |     
135 |     # Download binary
136 |     Write-Host "`nDownloading latest release..." -ForegroundColor Cyan
137 |     $binaryPath = Join-Path $TmpDir "cursor-id-modifier.exe"
138 |     
139 |     if (!(Get-FileWithProgress -Url $downloadUrl -OutputFile $binaryPath)) {
140 |         exit 1
141 |     }
142 |     
143 |     # Install binary
144 |     Write-Host "Installing..." -ForegroundColor Cyan
145 |     try {
146 |         Copy-Item -Path $binaryPath -Destination "$InstallDir\cursor-id-modifier.exe" -Force
147 |         
148 |         # Add to PATH if not already present
149 |         $currentPath = [Environment]::GetEnvironmentVariable("Path", "Machine")
150 |         if ($currentPath -notlike "*$InstallDir*") {
151 |             [Environment]::SetEnvironmentVariable("Path", "$currentPath;$InstallDir", "Machine")
152 |         }
153 |     }
154 |     catch {
155 |         Write-Host "Failed to install: $_" -ForegroundColor Red
156 |         exit 1
157 |     }
158 |     
159 |     Write-Host "Installation completed successfully!" -ForegroundColor Green
160 |     Write-Host "Running cursor-id-modifier..." -ForegroundColor Cyan
161 |     
162 |     # Run the program
163 |     try {
164 |         & "$InstallDir\cursor-id-modifier.exe"
165 |         if ($LASTEXITCODE -ne 0) {
166 |             Write-Host "Failed to run cursor-id-modifier" -ForegroundColor Red
167 |             exit 1
168 |         }
169 |     }
170 |     catch {
171 |         Write-Host "Failed to run cursor-id-modifier: $_" -ForegroundColor Red
172 |         exit 1
173 |     }
174 | }
175 | 
176 | # Run installation
177 | try {
178 |     Install-CursorModifier
179 | }
180 | catch {
181 |     Write-Host "Installation failed: $_" -ForegroundColor Red
182 |     Cleanup
183 |     Write-Host "Press enter to exit..."
184 |     $null = $Host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown')
185 |     exit 1
186 | }
187 | finally {
188 |     Cleanup
189 |     if ($LASTEXITCODE -ne 0) {
190 |         Write-Host "Press enter to exit..." -ForegroundColor Green
191 |         $null = $Host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown')
192 |     }
193 | }


--------------------------------------------------------------------------------
/scripts/install.sh:
--------------------------------------------------------------------------------
  1 | #!/bin/bash
  2 | 
  3 | set -e
  4 | 
  5 | # Colors for output
  6 | RED='\033[0;31m'
  7 | GREEN='\033[0;32m'
  8 | BLUE='\033[0;36m'
  9 | YELLOW='\033[0;33m'
 10 | NC='\033[0m'
 11 | 
 12 | # Temporary directory for downloads
 13 | TMP_DIR=$(mktemp -d)
 14 | trap 'rm -rf "$TMP_DIR"' EXIT
 15 | 
 16 | # Check for required commands
 17 | check_requirements() {
 18 |     if ! command -v curl >/dev/null 2>&1; then
 19 |         echo -e "${RED}Error: curl is required${NC}"
 20 |         exit 1
 21 |     fi
 22 | }
 23 | 
 24 | # Detect system information
 25 | detect_system() {
 26 |     local os arch suffix
 27 | 
 28 |     case "$(uname -s)" in
 29 |         Linux*)  os="linux";;
 30 |         Darwin*) os="darwin";;
 31 |         *)       echo -e "${RED}Unsupported OS${NC}"; exit 1;;
 32 |     esac
 33 | 
 34 |     case "$(uname -m)" in
 35 |         x86_64)  
 36 |             arch="x86_64"
 37 |             ;;
 38 |         aarch64|arm64) 
 39 |             arch="arm64"
 40 |             ;;
 41 |         i386|i686)
 42 |             arch="i386"
 43 |             ;;
 44 |         *)       echo -e "${RED}Unsupported architecture${NC}"; exit 1;;
 45 |     esac
 46 | 
 47 |     echo "$os $arch"
 48 | }
 49 | 
 50 | # Download with progress
 51 | download() {
 52 |     local url="$1"
 53 |     local output="$2"
 54 |     curl -#L "$url" -o "$output"
 55 | }
 56 | 
 57 | # Check and create installation directory
 58 | setup_install_dir() {
 59 |     local install_dir="$1"
 60 |     
 61 |     if [ ! -d "$install_dir" ]; then
 62 |         mkdir -p "$install_dir" || {
 63 |             echo -e "${RED}Failed to create installation directory${NC}"
 64 |             exit 1
 65 |         }
 66 |     fi
 67 | }
 68 | 
 69 | # Main installation function
 70 | main() {
 71 |     check_requirements
 72 |     
 73 |     echo -e "${BLUE}Starting installation...${NC}"
 74 |     
 75 |     # Detect system
 76 |     read -r OS ARCH SUFFIX <<< "$(detect_system)"
 77 |     echo -e "${GREEN}Detected: $OS $ARCH${NC}"
 78 |     
 79 |     # Set installation directory
 80 |     INSTALL_DIR="/usr/local/bin"
 81 |     
 82 |     # Setup installation directory
 83 |     setup_install_dir "$INSTALL_DIR"
 84 |     
 85 |     # Get latest release info
 86 |     echo -e "${BLUE}Fetching latest release information...${NC}"
 87 |     LATEST_URL="https://api.github.com/repos/yuaotian/go-cursor-help/releases/latest"
 88 |     
 89 |     # Get latest version and remove 'v' prefix
 90 |     VERSION=$(curl -s "$LATEST_URL" | grep "tag_name" | cut -d'"' -f4 | sed 's/^v//')
 91 |     
 92 |     # Construct binary name
 93 |     BINARY_NAME="cursor-id-modifier_${VERSION}_${OS}_${ARCH}"
 94 |     echo -e "${BLUE}Looking for asset: $BINARY_NAME${NC}"
 95 |     
 96 |     # Get download URL directly
 97 |     DOWNLOAD_URL=$(curl -s "$LATEST_URL" | grep -o "\"browser_download_url\": \"[^\"]*${BINARY_NAME}[^\"]*\"" | cut -d'"' -f4)
 98 |     
 99 |     if [ -z "$DOWNLOAD_URL" ]; then
100 |         echo -e "${RED}Error: Could not find appropriate binary for $OS $ARCH${NC}"
101 |         echo -e "${YELLOW}Available assets:${NC}"
102 |         curl -s "$LATEST_URL" | grep "browser_download_url" | cut -d'"' -f4
103 |         exit 1
104 |     fi
105 |     
106 |     echo -e "${GREEN}Found matching asset: $BINARY_NAME${NC}"
107 |     echo -e "${BLUE}Downloading from: $DOWNLOAD_URL${NC}"
108 |     
109 |     download "$DOWNLOAD_URL" "$TMP_DIR/cursor-id-modifier"
110 |     
111 |     # Install binary
112 |     echo -e "${BLUE}Installing...${NC}"
113 |     chmod +x "$TMP_DIR/cursor-id-modifier"
114 |     sudo mv "$TMP_DIR/cursor-id-modifier" "$INSTALL_DIR/"
115 |     
116 |     echo -e "${GREEN}Installation completed successfully!${NC}"
117 |     echo -e "${BLUE}Running cursor-id-modifier...${NC}"
118 |     
119 |     # Run the program with sudo, preserving environment variables
120 |     export AUTOMATED_MODE=1
121 |     if ! sudo -E cursor-id-modifier; then
122 |         echo -e "${RED}Failed to run cursor-id-modifier${NC}"
123 |         exit 1
124 |     fi
125 | }
126 | 
127 | main
128 | 


--------------------------------------------------------------------------------
/scripts/run/cursor_mac_free_trial_reset.sh:
--------------------------------------------------------------------------------
   1 | #!/bin/bash
   2 | 
   3 | # 设置错误处理
   4 | set -e
   5 | 
   6 | # 定义日志文件路径
   7 | LOG_FILE="/tmp/cursor_free_trial_reset.log"
   8 | 
   9 | # 初始化日志文件
  10 | initialize_log() {
  11 |     echo "========== Cursor Free Trial Reset Tool Log Start $(date) ==========" > "$LOG_FILE"
  12 |     chmod 644 "$LOG_FILE"
  13 | }
  14 | 
  15 | # 颜色定义
  16 | RED='\033[0;31m'
  17 | GREEN='\033[0;32m'
  18 | YELLOW='\033[1;33m'
  19 | BLUE='\033[0;34m'
  20 | NC='\033[0m' # No Color
  21 | 
  22 | # 日志函数 - 同时输出到终端和日志文件
  23 | log_info() {
  24 |     echo -e "${GREEN}[INFO]${NC} $1"
  25 |     echo "[INFO] $(date '+%Y-%m-%d %H:%M:%S') $1" >> "$LOG_FILE"
  26 | }
  27 | 
  28 | log_warn() {
  29 |     echo -e "${YELLOW}[WARN]${NC} $1"
  30 |     echo "[WARN] $(date '+%Y-%m-%d %H:%M:%S') $1" >> "$LOG_FILE"
  31 | }
  32 | 
  33 | log_error() {
  34 |     echo -e "${RED}[ERROR]${NC} $1"
  35 |     echo "[ERROR] $(date '+%Y-%m-%d %H:%M:%S') $1" >> "$LOG_FILE"
  36 | }
  37 | 
  38 | log_debug() {
  39 |     echo -e "${BLUE}[DEBUG]${NC} $1"
  40 |     echo "[DEBUG] $(date '+%Y-%m-%d %H:%M:%S') $1" >> "$LOG_FILE"
  41 | }
  42 | 
  43 | # 记录命令输出到日志文件
  44 | log_cmd_output() {
  45 |     local cmd="$1"
  46 |     local msg="$2"
  47 |     echo "[CMD] $(date '+%Y-%m-%d %H:%M:%S') 执行命令: $cmd" >> "$LOG_FILE"
  48 |     echo "[CMD] $msg:" >> "$LOG_FILE"
  49 |     eval "$cmd" 2>&1 | tee -a "$LOG_FILE"
  50 |     echo "" >> "$LOG_FILE"
  51 | }
  52 | 
  53 | # 获取当前用户
  54 | get_current_user() {
  55 |     if [ "$EUID" -eq 0 ]; then
  56 |         echo "$SUDO_USER"
  57 |     else
  58 |         echo "$USER"
  59 |     fi
  60 | }
  61 | 
  62 | CURRENT_USER=$(get_current_user)
  63 | if [ -z "$CURRENT_USER" ]; then
  64 |     log_error "无法获取用户名"
  65 |     exit 1
  66 | fi
  67 | 
  68 | # 定义配置文件路径
  69 | STORAGE_FILE="$HOME/Library/Application Support/Cursor/User/globalStorage/storage.json"
  70 | BACKUP_DIR="$HOME/Library/Application Support/Cursor/User/globalStorage/backups"
  71 | 
  72 | # 定义 Cursor 应用程序路径
  73 | CURSOR_APP_PATH="/Applications/Cursor.app"
  74 | 
  75 | # 🚀 新增 Cursor 防掉试用Pro删除文件夹功能
  76 | remove_cursor_trial_folders() {
  77 |     echo
  78 |     log_info "🎯 [核心功能] 正在执行 Cursor 防掉试用Pro删除文件夹..."
  79 |     log_info "📋 [说明] 此功能将删除指定的Cursor相关文件夹以重置试用状态"
  80 |     echo
  81 | 
  82 |     # 定义需要删除的文件夹路径
  83 |     local folders_to_delete=(
  84 |         "$HOME/Library/Application Support/Cursor"
  85 |         "$HOME/.cursor"
  86 |     )
  87 | 
  88 |     log_info "📂 [检测] 将检查以下文件夹:"
  89 |     for folder in "${folders_to_delete[@]}"; do
  90 |         echo "   📁 $folder"
  91 |     done
  92 |     echo
  93 | 
  94 |     local deleted_count=0
  95 |     local skipped_count=0
  96 |     local error_count=0
  97 | 
  98 |     # 删除指定文件夹
  99 |     for folder in "${folders_to_delete[@]}"; do
 100 |         log_debug "🔍 [检查] 检查文件夹: $folder"
 101 | 
 102 |         if [ -d "$folder" ]; then
 103 |             log_warn "⚠️  [警告] 发现文件夹存在,正在删除..."
 104 |             if rm -rf "$folder"; then
 105 |                 log_info "✅ [成功] 已删除文件夹: $folder"
 106 |                 ((deleted_count++))
 107 |             else
 108 |                 log_error "❌ [错误] 删除文件夹失败: $folder"
 109 |                 ((error_count++))
 110 |             fi
 111 |         else
 112 |             log_warn "⏭️  [跳过] 文件夹不存在: $folder"
 113 |             ((skipped_count++))
 114 |         fi
 115 |         echo
 116 |     done
 117 | 
 118 |     # 🔧 重要:深度修复权限问题
 119 |     log_info "🔧 [深度修复] 正在进行全面的权限修复..."
 120 |     local cursor_support_dir="$HOME/Library/Application Support/Cursor"
 121 |     local cursor_home_dir="$HOME/.cursor"
 122 | 
 123 |     # 创建完整的目录结构(包括Cursor可能需要的所有子目录)
 124 |     local directories=(
 125 |         "$cursor_support_dir"
 126 |         "$cursor_support_dir/User"
 127 |         "$cursor_support_dir/User/globalStorage"
 128 |         "$cursor_support_dir/User/workspaceStorage"
 129 |         "$cursor_support_dir/User/History"
 130 |         "$cursor_support_dir/logs"
 131 |         "$cursor_support_dir/CachedData"
 132 |         "$cursor_support_dir/CachedExtensions"
 133 |         "$cursor_support_dir/CachedExtensionVSIXs"
 134 |         "$cursor_home_dir"
 135 |         "$cursor_home_dir/extensions"
 136 |     )
 137 | 
 138 |     log_info "📁 [创建] 创建完整的目录结构..."
 139 |     for dir in "${directories[@]}"; do
 140 |         if mkdir -p "$dir" 2>/dev/null; then
 141 |             log_debug "✅ 创建目录: $dir"
 142 |         else
 143 |             log_warn "⚠️  创建目录失败: $dir"
 144 |         fi
 145 |     done
 146 | 
 147 |     # 设置递归权限(确保所有子目录都有正确权限)
 148 |     log_info "🔐 [权限] 设置递归权限..."
 149 |     chmod -R 755 "$cursor_support_dir" 2>/dev/null || true
 150 |     chmod -R 755 "$cursor_home_dir" 2>/dev/null || true
 151 | 
 152 |     # 特别处理:确保当前用户拥有这些目录
 153 |     log_info "👤 [所有权] 确保目录所有权正确..."
 154 |     chown -R "$(whoami)" "$cursor_support_dir" 2>/dev/null || true
 155 |     chown -R "$(whoami)" "$cursor_home_dir" 2>/dev/null || true
 156 | 
 157 |     # 验证权限设置
 158 |     log_info "🔍 [验证] 验证权限设置..."
 159 |     if [ -w "$cursor_support_dir" ] && [ -w "$cursor_home_dir" ]; then
 160 |         log_info "✅ [成功] 权限验证通过"
 161 |     else
 162 |         log_warn "⚠️  [警告] 权限验证失败,可能仍存在问题"
 163 |     fi
 164 | 
 165 |     # 🔍 权限诊断
 166 |     log_info "🔍 [诊断] 执行权限诊断..."
 167 |     echo "   📁 目录权限检查:"
 168 |     for dir in "${directories[@]}"; do
 169 |         if [ -d "$dir" ]; then
 170 |             local perms=$(ls -ld "$dir" | awk '{print $1, $3, $4}')
 171 |             echo "     ✅ $dir: $perms"
 172 |         else
 173 |             echo "     ❌ $dir: 不存在"
 174 |         fi
 175 |     done
 176 | 
 177 |     # 🔍 权限诊断
 178 |     log_info "🔍 [诊断] 执行权限诊断..."
 179 |     echo "   📁 目录权限检查:"
 180 |     for dir in "${directories[@]}"; do
 181 |         if [ -d "$dir" ]; then
 182 |             local perms=$(ls -ld "$dir" | awk '{print $1, $3, $4}')
 183 |             echo "     ✅ $dir: $perms"
 184 |         else
 185 |             echo "     ❌ $dir: 不存在"
 186 |         fi
 187 |     done
 188 | 
 189 |     log_info "✅ [完成] 深度权限修复完成"
 190 |     echo
 191 | 
 192 |     # 显示操作统计
 193 |     log_info "📊 [统计] 操作完成统计:"
 194 |     echo "   ✅ 成功删除: $deleted_count 个文件夹"
 195 |     echo "   ⏭️  跳过处理: $skipped_count 个文件夹"
 196 |     echo "   ❌ 删除失败: $error_count 个文件夹"
 197 |     echo
 198 | 
 199 |     if [ $deleted_count -gt 0 ]; then
 200 |         log_info "🎉 [完成] Cursor 防掉试用Pro文件夹删除完成!"
 201 |     else
 202 |         log_warn "🤔 [提示] 未找到需要删除的文件夹,可能已经清理过了"
 203 |     fi
 204 |     echo
 205 | }
 206 | 
 207 | # 🔄 重启Cursor并等待配置文件生成
 208 | restart_cursor_and_wait() {
 209 |     echo
 210 |     log_info "🔄 [重启] 正在重启Cursor以重新生成配置文件..."
 211 | 
 212 |     if [ -z "$CURSOR_PROCESS_PATH" ]; then
 213 |         log_error "❌ [错误] 未找到Cursor进程信息,无法重启"
 214 |         return 1
 215 |     fi
 216 | 
 217 |     log_info "📍 [路径] 使用路径: $CURSOR_PROCESS_PATH"
 218 | 
 219 |     if [ ! -f "$CURSOR_PROCESS_PATH" ]; then
 220 |         log_error "❌ [错误] Cursor可执行文件不存在: $CURSOR_PROCESS_PATH"
 221 |         return 1
 222 |     fi
 223 | 
 224 |     # 🔧 启动前最后一次权限确认
 225 |     log_info "🔧 [最终权限] 启动前最后一次权限确认..."
 226 |     local cursor_support_dir="$HOME/Library/Application Support/Cursor"
 227 |     local cursor_home_dir="$HOME/.cursor"
 228 | 
 229 |     # 再次确认完整目录结构存在
 230 |     local directories=(
 231 |         "$cursor_support_dir"
 232 |         "$cursor_support_dir/User"
 233 |         "$cursor_support_dir/User/globalStorage"
 234 |         "$cursor_support_dir/logs"
 235 |         "$cursor_support_dir/CachedData"
 236 |         "$cursor_home_dir"
 237 |         "$cursor_home_dir/extensions"
 238 |     )
 239 | 
 240 |     for dir in "${directories[@]}"; do
 241 |         mkdir -p "$dir" 2>/dev/null || true
 242 |     done
 243 | 
 244 |     # 设置强制权限
 245 |     chmod -R 755 "$cursor_support_dir" 2>/dev/null || true
 246 |     chmod -R 755 "$cursor_home_dir" 2>/dev/null || true
 247 |     chown -R "$(whoami)" "$cursor_support_dir" 2>/dev/null || true
 248 |     chown -R "$(whoami)" "$cursor_home_dir" 2>/dev/null || true
 249 | 
 250 |     # 启动Cursor
 251 |     log_info "🚀 [启动] 正在启动Cursor..."
 252 |     "$CURSOR_PROCESS_PATH" > /dev/null 2>&1 &
 253 |     CURSOR_PID=$!
 254 | 
 255 |     log_info "⏳ [等待] 等待15秒让Cursor完全启动并生成配置文件..."
 256 |     sleep 15
 257 | 
 258 |     # 检查配置文件是否生成
 259 |     local config_path="$HOME/Library/Application Support/Cursor/User/globalStorage/storage.json"
 260 |     local max_wait=30
 261 |     local waited=0
 262 | 
 263 |     while [ ! -f "$config_path" ] && [ $waited -lt $max_wait ]; do
 264 |         log_info "⏳ [等待] 等待配置文件生成... ($waited/$max_wait 秒)"
 265 |         sleep 1
 266 |         waited=$((waited + 1))
 267 |     done
 268 | 
 269 |     if [ -f "$config_path" ]; then
 270 |         log_info "✅ [成功] 配置文件已生成: $config_path"
 271 |     else
 272 |         log_warn "⚠️  [警告] 配置文件未在预期时间内生成,继续执行..."
 273 |     fi
 274 | 
 275 |     # 强制关闭Cursor
 276 |     log_info "🔄 [关闭] 正在关闭Cursor以进行配置修改..."
 277 |     if [ ! -z "$CURSOR_PID" ]; then
 278 |         kill $CURSOR_PID 2>/dev/null || true
 279 |     fi
 280 | 
 281 |     # 确保所有Cursor进程都关闭
 282 |     pkill -f "Cursor" 2>/dev/null || true
 283 | 
 284 |     log_info "✅ [完成] Cursor重启流程完成"
 285 |     return 0
 286 | }
 287 | 
 288 | # 🛠️ 修改机器码配置
 289 | modify_machine_code_config() {
 290 |     echo
 291 |     log_info "🛠️  [配置] 正在修改机器码配置..."
 292 | 
 293 |     local config_path="$HOME/Library/Application Support/Cursor/User/globalStorage/storage.json"
 294 | 
 295 |     if [ ! -f "$config_path" ]; then
 296 |         log_error "❌ [错误] 配置文件不存在: $config_path"
 297 |         log_info "💡 [提示] 请手动启动Cursor一次,然后重新运行此脚本"
 298 |         return 1
 299 |     fi
 300 | 
 301 |     # 生成新的ID
 302 |     local MAC_MACHINE_ID=$(uuidgen | tr '[:upper:]' '[:lower:]')
 303 |     local UUID=$(uuidgen | tr '[:upper:]' '[:lower:]')
 304 |     local MACHINE_ID="auth0|user_$(openssl rand -hex 32)"
 305 |     local SQM_ID="{$(uuidgen | tr '[:lower:]' '[:upper:]')}"
 306 | 
 307 |     log_info "🔧 [生成] 已生成新的设备标识符"
 308 | 
 309 |     # 备份原始配置
 310 |     local backup_dir="$HOME/Library/Application Support/Cursor/User/globalStorage/backups"
 311 |     mkdir -p "$backup_dir"
 312 | 
 313 |     local backup_name="storage.json.backup_$(date +%Y%m%d_%H%M%S)"
 314 |     cp "$config_path" "$backup_dir/$backup_name"
 315 |     log_info "💾 [备份] 已备份原配置: $backup_name"
 316 | 
 317 |     # 使用Python修改JSON配置(更可靠)
 318 |     python3 -c "
 319 | import json
 320 | import sys
 321 | 
 322 | try:
 323 |     with open('$config_path', 'r', encoding='utf-8') as f:
 324 |         config = json.load(f)
 325 | 
 326 |     config['telemetry.machineId'] = '$MACHINE_ID'
 327 |     config['telemetry.macMachineId'] = '$MAC_MACHINE_ID'
 328 |     config['telemetry.devDeviceId'] = '$UUID'
 329 |     config['telemetry.sqmId'] = '$SQM_ID'
 330 | 
 331 |     with open('$config_path', 'w', encoding='utf-8') as f:
 332 |         json.dump(config, f, indent=2, ensure_ascii=False)
 333 | 
 334 |     print('SUCCESS')
 335 | except Exception as e:
 336 |     print(f'ERROR: {e}')
 337 |     sys.exit(1)
 338 | " 2>/dev/null
 339 | 
 340 |     if [ $? -eq 0 ]; then
 341 |         log_info "✅ [成功] 机器码配置修改完成"
 342 |         log_info "📋 [详情] 已更新以下标识符:"
 343 |         echo "   🔹 machineId: ${MACHINE_ID:0:20}..."
 344 |         echo "   🔹 macMachineId: $MAC_MACHINE_ID"
 345 |         echo "   🔹 devDeviceId: $UUID"
 346 |         echo "   🔹 sqmId: $SQM_ID"
 347 |         return 0
 348 |     else
 349 |         log_error "❌ [错误] 修改配置失败"
 350 |         return 1
 351 |     fi
 352 | }
 353 | 
 354 | # 检查权限
 355 | check_permissions() {
 356 |     if [ "$EUID" -ne 0 ]; then
 357 |         log_error "请使用 sudo 运行此脚本"
 358 |         echo "示例: sudo $0"
 359 |         exit 1
 360 |     fi
 361 | }
 362 | 
 363 | # 检查并关闭 Cursor 进程(保存进程信息)
 364 | check_and_kill_cursor() {
 365 |     log_info "🔍 [检查] 检查 Cursor 进程..."
 366 | 
 367 |     local attempt=1
 368 |     local max_attempts=5
 369 | 
 370 |     # 💾 保存Cursor进程路径
 371 |     CURSOR_PROCESS_PATH="/Applications/Cursor.app/Contents/MacOS/Cursor"
 372 | 
 373 |     # 函数:获取进程详细信息
 374 |     get_process_details() {
 375 |         local process_name="$1"
 376 |         log_debug "正在获取 $process_name 进程详细信息:"
 377 |         ps aux | grep -i "/Applications/Cursor.app" | grep -v grep
 378 |     }
 379 | 
 380 |     while [ $attempt -le $max_attempts ]; do
 381 |         # 使用更精确的匹配来获取 Cursor 进程
 382 |         CURSOR_PIDS=$(ps aux | grep -i "/Applications/Cursor.app" | grep -v grep | awk '{print $2}')
 383 | 
 384 |         if [ -z "$CURSOR_PIDS" ]; then
 385 |             log_info "💡 [提示] 未发现运行中的 Cursor 进程"
 386 |             # 确认Cursor应用路径存在
 387 |             if [ -f "$CURSOR_PROCESS_PATH" ]; then
 388 |                 log_info "💾 [保存] 已保存Cursor路径: $CURSOR_PROCESS_PATH"
 389 |             else
 390 |                 log_warn "⚠️  [警告] 未找到Cursor应用,请确认已安装"
 391 |             fi
 392 |             return 0
 393 |         fi
 394 | 
 395 |         log_warn "⚠️  [警告] 发现 Cursor 进程正在运行"
 396 |         # 💾 保存进程信息
 397 |         log_info "💾 [保存] 已保存Cursor路径: $CURSOR_PROCESS_PATH"
 398 |         get_process_details "cursor"
 399 | 
 400 |         log_warn "🔄 [操作] 尝试关闭 Cursor 进程..."
 401 | 
 402 |         if [ $attempt -eq $max_attempts ]; then
 403 |             log_warn "💥 [强制] 尝试强制终止进程..."
 404 |             kill -9 $CURSOR_PIDS 2>/dev/null || true
 405 |         else
 406 |             kill $CURSOR_PIDS 2>/dev/null || true
 407 |         fi
 408 | 
 409 |         sleep 1
 410 | 
 411 |         # 同样使用更精确的匹配来检查进程是否还在运行
 412 |         if ! ps aux | grep -i "/Applications/Cursor.app" | grep -v grep > /dev/null; then
 413 |             log_info "✅ [成功] Cursor 进程已成功关闭"
 414 |             return 0
 415 |         fi
 416 | 
 417 |         log_warn "⏳ [等待] 等待进程关闭,尝试 $attempt/$max_attempts..."
 418 |         ((attempt++))
 419 |     done
 420 | 
 421 |     log_error "❌ [错误] 在 $max_attempts 次尝试后仍无法关闭 Cursor 进程"
 422 |     get_process_details "cursor"
 423 |     log_error "💥 [错误] 请手动关闭进程后重试"
 424 |     exit 1
 425 | }
 426 | 
 427 | # 备份配置文件
 428 | backup_config() {
 429 |     if [ ! -f "$STORAGE_FILE" ]; then
 430 |         log_warn "配置文件不存在,跳过备份"
 431 |         return 0
 432 |     fi
 433 |     
 434 |     mkdir -p "$BACKUP_DIR"
 435 |     local backup_file="$BACKUP_DIR/storage.json.backup_$(date +%Y%m%d_%H%M%S)"
 436 |     
 437 |     if cp "$STORAGE_FILE" "$backup_file"; then
 438 |         chmod 644 "$backup_file"
 439 |         chown "$CURRENT_USER" "$backup_file"
 440 |         log_info "配置已备份到: $backup_file"
 441 |     else
 442 |         log_error "备份失败"
 443 |         exit 1
 444 |     fi
 445 | }
 446 | 
 447 | # 生成随机 ID
 448 | generate_random_id() {
 449 |     # 生成32字节(64个十六进制字符)的随机数
 450 |     openssl rand -hex 32
 451 | }
 452 | 
 453 | # 生成随机 UUID
 454 | generate_uuid() {
 455 |     uuidgen | tr '[:upper:]' '[:lower:]'
 456 | }
 457 | 
 458 | # 修改现有文件
 459 | modify_or_add_config() {
 460 |     local key="$1"
 461 |     local value="$2"
 462 |     local file="$3"
 463 |     
 464 |     if [ ! -f "$file" ]; then
 465 |         log_error "文件不存在: $file"
 466 |         return 1
 467 |     fi
 468 |     
 469 |     # 确保文件可写
 470 |     chmod 644 "$file" || {
 471 |         log_error "无法修改文件权限: $file"
 472 |         return 1
 473 |     }
 474 |     
 475 |     # 创建临时文件
 476 |     local temp_file=$(mktemp)
 477 |     
 478 |     # 检查key是否存在
 479 |     if grep -q "\"$key\":" "$file"; then
 480 |         # key存在,执行替换
 481 |         sed "s/\"$key\":[[:space:]]*\"[^\"]*\"/\"$key\": \"$value\"/" "$file" > "$temp_file" || {
 482 |             log_error "修改配置失败: $key"
 483 |             rm -f "$temp_file"
 484 |             return 1
 485 |         }
 486 |     else
 487 |         # key不存在,添加新的key-value对
 488 |         sed "s/}$/,\n    \"$key\": \"$value\"\n}/" "$file" > "$temp_file" || {
 489 |             log_error "添加配置失败: $key"
 490 |             rm -f "$temp_file"
 491 |             return 1
 492 |         }
 493 |     fi
 494 |     
 495 |     # 检查临时文件是否为空
 496 |     if [ ! -s "$temp_file" ]; then
 497 |         log_error "生成的临时文件为空"
 498 |         rm -f "$temp_file"
 499 |         return 1
 500 |     fi
 501 |     
 502 |     # 使用 cat 替换原文件内容
 503 |     cat "$temp_file" > "$file" || {
 504 |         log_error "无法写入文件: $file"
 505 |         rm -f "$temp_file"
 506 |         return 1
 507 |     }
 508 |     
 509 |     rm -f "$temp_file"
 510 |     
 511 |     # 恢复文件权限
 512 |     chmod 444 "$file"
 513 |     
 514 |     return 0
 515 | }
 516 | 
 517 | # 生成新的配置
 518 | generate_new_config() {
 519 |     echo
 520 |     log_warn "机器码处理"
 521 |     
 522 |     # 默认不重置机器码
 523 |     reset_choice=0
 524 |     
 525 |     # 记录日志以便调试
 526 |     echo "[INPUT_DEBUG] 机器码重置选项: 不重置 (默认)" >> "$LOG_FILE"
 527 |     
 528 |     # 处理 - 默认为不重置
 529 |     log_info "默认不重置机器码,将仅修改js文件"
 530 |     
 531 |     # 确保配置文件目录存在
 532 |     if [ -f "$STORAGE_FILE" ]; then
 533 |         log_info "发现已有配置文件: $STORAGE_FILE"
 534 |         
 535 |         # 备份现有配置(以防万一)
 536 |         backup_config
 537 |     else
 538 |         log_warn "未找到配置文件,这是正常的,脚本将跳过ID修改"
 539 |     fi
 540 |     
 541 |     echo
 542 |     log_info "配置处理完成"
 543 | }
 544 | 
 545 | # 清理 Cursor 之前的修改
 546 | clean_cursor_app() {
 547 |     log_info "尝试清理 Cursor 之前的修改..."
 548 |     
 549 |     # 如果存在备份,直接恢复备份
 550 |     local latest_backup=""
 551 |     
 552 |     # 查找最新的备份
 553 |     latest_backup=$(find /tmp -name "Cursor.app.backup_*" -type d -print 2>/dev/null | sort -r | head -1)
 554 |     
 555 |     if [ -n "$latest_backup" ] && [ -d "$latest_backup" ]; then
 556 |         log_info "找到现有备份: $latest_backup"
 557 |         log_info "正在恢复原始版本..."
 558 |         
 559 |         # 停止 Cursor 进程
 560 |         check_and_kill_cursor
 561 |         
 562 |         # 恢复备份
 563 |         sudo rm -rf "$CURSOR_APP_PATH"
 564 |         sudo cp -R "$latest_backup" "$CURSOR_APP_PATH"
 565 |         sudo chown -R "$CURRENT_USER:staff" "$CURSOR_APP_PATH"
 566 |         sudo chmod -R 755 "$CURSOR_APP_PATH"
 567 |         
 568 |         log_info "已恢复原始版本"
 569 |         return 0
 570 |     else
 571 |         log_warn "未找到现有备份,尝试重新安装 Cursor..."
 572 |         echo "您可以从 https://cursor.sh 下载并重新安装 Cursor"
 573 |         echo "或者继续执行此脚本,将尝试修复现有安装"
 574 |         
 575 |         # 可以在这里添加重新下载和安装的逻辑
 576 |         return 1
 577 |     fi
 578 | }
 579 | 
 580 | # 修改 Cursor 主程序文件(安全模式)
 581 | modify_cursor_app_files() {
 582 |     log_info "正在安全修改 Cursor 主程序文件..."
 583 |     log_info "详细日志将记录到: $LOG_FILE"
 584 |     
 585 |     # 先清理之前的修改
 586 |     clean_cursor_app
 587 |     
 588 |     # 验证应用是否存在
 589 |     if [ ! -d "$CURSOR_APP_PATH" ]; then
 590 |         log_error "未找到 Cursor.app,请确认安装路径: $CURSOR_APP_PATH"
 591 |         return 1
 592 |     fi
 593 | 
 594 |     # 定义目标文件 - 将extensionHostProcess.js放在最前面优先处理
 595 |     local target_files=(
 596 |         "${CURSOR_APP_PATH}/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js"
 597 |         "${CURSOR_APP_PATH}/Contents/Resources/app/out/main.js"
 598 |         "${CURSOR_APP_PATH}/Contents/Resources/app/out/vs/code/node/cliProcessMain.js"
 599 |     )
 600 |     
 601 |     # 检查文件是否存在并且是否已修改
 602 |     local need_modification=false
 603 |     local missing_files=false
 604 |     
 605 |     log_debug "检查目标文件..."
 606 |     for file in "${target_files[@]}"; do
 607 |         if [ ! -f "$file" ]; then
 608 |             log_warn "文件不存在: ${file/$CURSOR_APP_PATH\//}"
 609 |             echo "[FILE_CHECK] 文件不存在: $file" >> "$LOG_FILE"
 610 |             missing_files=true
 611 |             continue
 612 |         fi
 613 |         
 614 |         echo "[FILE_CHECK] 文件存在: $file ($(wc -c < "$file") 字节)" >> "$LOG_FILE"
 615 |         
 616 |         if ! grep -q "return crypto.randomUUID()" "$file" 2>/dev/null; then
 617 |             log_info "文件需要修改: ${file/$CURSOR_APP_PATH\//}"
 618 |             grep -n "IOPlatformUUID" "$file" | head -3 >> "$LOG_FILE" || echo "[FILE_CHECK] 未找到 IOPlatformUUID" >> "$LOG_FILE"
 619 |             need_modification=true
 620 |             break
 621 |         else
 622 |             log_info "文件已修改: ${file/$CURSOR_APP_PATH\//}"
 623 |         fi
 624 |     done
 625 |     
 626 |     # 如果所有文件都已修改或不存在,则退出
 627 |     if [ "$missing_files" = true ]; then
 628 |         log_error "部分目标文件不存在,请确认 Cursor 安装是否完整"
 629 |         return 1
 630 |     fi
 631 |     
 632 |     if [ "$need_modification" = false ]; then
 633 |         log_info "所有目标文件已经被修改过,无需重复操作"
 634 |         return 0
 635 |     fi
 636 | 
 637 |     # 创建临时工作目录
 638 |     local timestamp=$(date +%Y%m%d_%H%M%S)
 639 |     local temp_dir="/tmp/cursor_reset_${timestamp}"
 640 |     local temp_app="${temp_dir}/Cursor.app"
 641 |     local backup_app="/tmp/Cursor.app.backup_${timestamp}"
 642 |     
 643 |     log_debug "创建临时目录: $temp_dir"
 644 |     echo "[TEMP_DIR] 创建临时目录: $temp_dir" >> "$LOG_FILE"
 645 |     
 646 |     # 清理可能存在的旧临时目录
 647 |     if [ -d "$temp_dir" ]; then
 648 |         log_info "清理已存在的临时目录..."
 649 |         rm -rf "$temp_dir"
 650 |     fi
 651 |     
 652 |     # 创建新的临时目录
 653 |     mkdir -p "$temp_dir" || {
 654 |         log_error "无法创建临时目录: $temp_dir"
 655 |         echo "[ERROR] 无法创建临时目录: $temp_dir" >> "$LOG_FILE"
 656 |         return 1
 657 |     }
 658 | 
 659 |     # 备份原应用
 660 |     log_info "备份原应用..."
 661 |     echo "[BACKUP] 开始备份: $CURSOR_APP_PATH -> $backup_app" >> "$LOG_FILE"
 662 |     
 663 |     cp -R "$CURSOR_APP_PATH" "$backup_app" || {
 664 |         log_error "无法创建应用备份"
 665 |         echo "[ERROR] 备份失败: $CURSOR_APP_PATH -> $backup_app" >> "$LOG_FILE"
 666 |         rm -rf "$temp_dir"
 667 |         return 1
 668 |     }
 669 |     
 670 |     echo "[BACKUP] 备份完成" >> "$LOG_FILE"
 671 | 
 672 |     # 复制应用到临时目录
 673 |     log_info "创建临时工作副本..."
 674 |     echo "[COPY] 开始复制: $CURSOR_APP_PATH -> $temp_dir" >> "$LOG_FILE"
 675 |     
 676 |     cp -R "$CURSOR_APP_PATH" "$temp_dir" || {
 677 |         log_error "无法复制应用到临时目录"
 678 |         echo "[ERROR] 复制失败: $CURSOR_APP_PATH -> $temp_dir" >> "$LOG_FILE"
 679 |         rm -rf "$temp_dir" "$backup_app"
 680 |         return 1
 681 |     }
 682 |     
 683 |     echo "[COPY] 复制完成" >> "$LOG_FILE"
 684 | 
 685 |     # 确保临时目录的权限正确
 686 |     chown -R "$CURRENT_USER:staff" "$temp_dir"
 687 |     chmod -R 755 "$temp_dir"
 688 | 
 689 |     # 移除签名(增强兼容性)
 690 |     log_info "移除应用签名..."
 691 |     echo "[CODESIGN] 移除签名: $temp_app" >> "$LOG_FILE"
 692 |     
 693 |     codesign --remove-signature "$temp_app" 2>> "$LOG_FILE" || {
 694 |         log_warn "移除应用签名失败"
 695 |         echo "[WARN] 移除签名失败: $temp_app" >> "$LOG_FILE"
 696 |     }
 697 | 
 698 |     # 移除所有相关组件的签名
 699 |     local components=(
 700 |         "$temp_app/Contents/Frameworks/Cursor Helper.app"
 701 |         "$temp_app/Contents/Frameworks/Cursor Helper (GPU).app"
 702 |         "$temp_app/Contents/Frameworks/Cursor Helper (Plugin).app"
 703 |         "$temp_app/Contents/Frameworks/Cursor Helper (Renderer).app"
 704 |     )
 705 | 
 706 |     for component in "${components[@]}"; do
 707 |         if [ -e "$component" ]; then
 708 |             log_info "正在移除签名: $component"
 709 |             codesign --remove-signature "$component" || {
 710 |                 log_warn "移除组件签名失败: $component"
 711 |             }
 712 |         fi
 713 |     done
 714 |     
 715 |     # 修改目标文件 - 优先处理js文件
 716 |     local modified_count=0
 717 |     local files=(
 718 |         "${temp_app}/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js"
 719 |         "${temp_app}/Contents/Resources/app/out/main.js"
 720 |         "${temp_app}/Contents/Resources/app/out/vs/code/node/cliProcessMain.js"
 721 |     )
 722 |     
 723 |     for file in "${files[@]}"; do
 724 |         if [ ! -f "$file" ]; then
 725 |             log_warn "文件不存在: ${file/$temp_dir\//}"
 726 |             continue
 727 |         fi
 728 |         
 729 |         log_debug "处理文件: ${file/$temp_dir\//}"
 730 |         echo "[PROCESS] 开始处理文件: $file" >> "$LOG_FILE"
 731 |         echo "[PROCESS] 文件大小: $(wc -c < "$file") 字节" >> "$LOG_FILE"
 732 |         
 733 |         # 输出文件部分内容到日志
 734 |         echo "[FILE_CONTENT] 文件头部 100 行:" >> "$LOG_FILE"
 735 |         head -100 "$file" 2>/dev/null | grep -v "^
quot; | head -50 >> "$LOG_FILE"
 736 |         echo "[FILE_CONTENT] ..." >> "$LOG_FILE"
 737 |         
 738 |         # 创建文件备份
 739 |         cp "$file" "${file}.bak" || {
 740 |             log_error "无法创建文件备份: ${file/$temp_dir\//}"
 741 |             echo "[ERROR] 无法创建文件备份: $file" >> "$LOG_FILE"
 742 |             continue
 743 |         }
 744 | 
 745 |         # 使用 sed 替换而不是字符串操作
 746 |         if [[ "$file" == *"extensionHostProcess.js"* ]]; then
 747 |             log_debug "处理 extensionHostProcess.js 文件..."
 748 |             echo "[PROCESS_DETAIL] 开始处理 extensionHostProcess.js 文件" >> "$LOG_FILE"
 749 |             
 750 |             # 检查是否包含目标代码
 751 |             if grep -q 'i.header.set("x-cursor-checksum' "$file"; then
 752 |                 log_debug "找到 x-cursor-checksum 设置代码"
 753 |                 echo "[FOUND] 找到 x-cursor-checksum 设置代码" >> "$LOG_FILE"
 754 |                 
 755 |                 # 记录匹配的行到日志
 756 |                 grep -n 'i.header.set("x-cursor-checksum' "$file" >> "$LOG_FILE"
 757 |                 
 758 |                 # 执行特定的替换
 759 |                 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
 760 |                     log_info "成功修改 x-cursor-checksum 设置代码"
 761 |                     echo "[SUCCESS] 成功完成 x-cursor-checksum 设置代码替换" >> "$LOG_FILE"
 762 |                     # 记录修改后的行
 763 |                     grep -n 'i.header.set("x-cursor-checksum' "$file" >> "$LOG_FILE"
 764 |                     ((modified_count++))
 765 |                     log_info "成功修改文件: ${file/$temp_dir\//}"
 766 |                 else
 767 |                     log_error "修改 x-cursor-checksum 设置代码失败"
 768 |                     echo "[ERROR] 替换 x-cursor-checksum 设置代码失败" >> "$LOG_FILE"
 769 |                     cp "${file}.bak" "$file"
 770 |                 fi
 771 |             else
 772 |                 log_warn "未找到 x-cursor-checksum 设置代码"
 773 |                 echo "[FILE_CHECK] 未找到 x-cursor-checksum 设置代码" >> "$LOG_FILE"
 774 |                 
 775 |                 # 记录文件部分内容到日志以便排查
 776 |                 echo "[FILE_CONTENT] 文件中包含 'header.set' 的行:" >> "$LOG_FILE"
 777 |                 grep -n "header.set" "$file" | head -20 >> "$LOG_FILE"
 778 |                 
 779 |                 echo "[FILE_CONTENT] 文件中包含 'checksum' 的行:" >> "$LOG_FILE"
 780 |                 grep -n "checksum" "$file" | head -20 >> "$LOG_FILE"
 781 |             fi
 782 |             
 783 |             echo "[PROCESS_DETAIL] 完成处理 extensionHostProcess.js 文件" >> "$LOG_FILE"
 784 |         elif grep -q "IOPlatformUUID" "$file"; then
 785 |             log_debug "找到 IOPlatformUUID 关键字"
 786 |             echo "[FOUND] 找到 IOPlatformUUID 关键字" >> "$LOG_FILE"
 787 |             grep -n "IOPlatformUUID" "$file" | head -5 >> "$LOG_FILE"
 788 |             
 789 |             # 定位 IOPlatformUUID 相关函数
 790 |             if grep -q "function a\
quot; "$file"; then
 791 |                 # 检查是否已经修改过
 792 |                 if grep -q "return crypto.randomUUID()" "$file"; then
 793 |                     log_info "文件已经包含 randomUUID 调用,跳过修改"
 794 |                     ((modified_count++))
 795 |                     continue
 796 |                 fi
 797 |                 
 798 |                 # 针对 main.js 中发现的代码结构进行修改
 799 |                 if sed -i.tmp 's/function a\$(t){switch/function a\$(t){return crypto.randomUUID(); switch/' "$file"; then
 800 |                     log_debug "成功注入 randomUUID 调用到 a\$ 函数"
 801 |                     ((modified_count++))
 802 |                     log_info "成功修改文件: ${file/$temp_dir\//}"
 803 |                 else
 804 |                     log_error "修改 a\$ 函数失败"
 805 |                     cp "${file}.bak" "$file"
 806 |                 fi
 807 |             elif grep -q "async function v5" "$file"; then
 808 |                 # 检查是否已经修改过
 809 |                 if grep -q "return crypto.randomUUID()" "$file"; then
 810 |                     log_info "文件已经包含 randomUUID 调用,跳过修改"
 811 |                     ((modified_count++))
 812 |                     continue
 813 |                 fi
 814 |                 
 815 |                 # 替代方法 - 修改 v5 函数
 816 |                 if sed -i.tmp 's/async function v5(t){let e=/async function v5(t){return crypto.randomUUID(); let e=/' "$file"; then
 817 |                     log_debug "成功注入 randomUUID 调用到 v5 函数"
 818 |                     ((modified_count++))
 819 |                     log_info "成功修改文件: ${file/$temp_dir\//}"
 820 |                 else
 821 |                     log_error "修改 v5 函数失败"
 822 |                     cp "${file}.bak" "$file"
 823 |                 fi
 824 |             else
 825 |                 # 检查是否已经注入了自定义代码
 826 |                 if grep -q "// Cursor ID 修改工具注入" "$file"; then
 827 |                     log_info "文件已经包含自定义注入代码,跳过修改"
 828 |                     ((modified_count++))
 829 |                     continue
 830 |                 fi
 831 |                 
 832 |                 # 使用更通用的注入方法
 833 |                 log_warn "未找到具体函数,尝试使用通用修改方法"
 834 |                 inject_code="
 835 | // Cursor ID 修改工具注入 - $(date +%Y%m%d%H%M%S)
 836 | // 随机设备ID生成器注入 - $(date +%s)
 837 | const randomDeviceId_$(date +%s) = () => {
 838 |     try {
 839 |         return require('crypto').randomUUID();
 840 |     } catch (e) {
 841 |         return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => {
 842 |             const r = Math.random() * 16 | 0;
 843 |             return (c === 'x' ? r : (r & 0x3 | 0x8)).toString(16);
 844 |         });
 845 |     }
 846 | };
 847 | "
 848 |                 # 将代码注入到文件开头
 849 |                 echo "$inject_code" > "${file}.new"
 850 |                 cat "$file" >> "${file}.new"
 851 |                 mv "${file}.new" "$file"
 852 |                 
 853 |                 # 替换调用点
 854 |                 sed -i.tmp 's/await v5(!1)/randomDeviceId_'"$(date +%s)"'()/g' "$file"
 855 |                 sed -i.tmp 's/a\$(t)/randomDeviceId_'"$(date +%s)"'()/g' "$file"
 856 |                 
 857 |                 log_debug "完成通用修改"
 858 |                 ((modified_count++))
 859 |                 log_info "使用通用方法成功修改文件: ${file/$temp_dir\//}"
 860 |             fi
 861 |         else
 862 |             # 未找到 IOPlatformUUID,可能是文件结构变化
 863 |             log_warn "未找到 IOPlatformUUID,尝试替代方法"
 864 |             
 865 |             # 检查是否已经注入或修改过
 866 |             if grep -q "return crypto.randomUUID()" "$file" || grep -q "// Cursor ID 修改工具注入" "$file"; then
 867 |                 log_info "文件已经被修改过,跳过修改"
 868 |                 ((modified_count++))
 869 |                 continue
 870 |             fi
 871 |             
 872 |             # 尝试找其他关键函数如 getMachineId 或 getDeviceId
 873 |             if grep -q "function t\$()" "$file" || grep -q "async function y5" "$file"; then
 874 |                 log_debug "找到设备ID相关函数"
 875 |                 
 876 |                 # 修改 MAC 地址获取函数
 877 |                 if grep -q "function t\$()" "$file"; then
 878 |                     sed -i.tmp 's/function t\$(){/function t\$(){return "00:00:00:00:00:00";/' "$file"
 879 |                     log_debug "修改 MAC 地址获取函数成功"
 880 |                 fi
 881 |                 
 882 |                 # 修改设备ID获取函数
 883 |                 if grep -q "async function y5" "$file"; then
 884 |                     sed -i.tmp 's/async function y5(t){/async function y5(t){return crypto.randomUUID();/' "$file"
 885 |                     log_debug "修改设备ID获取函数成功"
 886 |                 fi
 887 |                 
 888 |                 ((modified_count++))
 889 |                 log_info "使用替代方法成功修改文件: ${file/$temp_dir\//}"
 890 |             else
 891 |                 # 最后尝试的通用方法 - 在文件顶部插入重写函数定义
 892 |                 log_warn "未找到任何已知函数,使用最通用的方法"
 893 |                 
 894 |                 inject_universal_code="
 895 | // Cursor ID 修改工具注入 - $(date +%Y%m%d%H%M%S)
 896 | // 全局拦截设备标识符 - $(date +%s)
 897 | const originalRequire_$(date +%s) = require;
 898 | require = function(module) {
 899 |     const result = originalRequire_$(date +%s)(module);
 900 |     if (module === 'crypto' && result.randomUUID) {
 901 |         const originalRandomUUID_$(date +%s) = result.randomUUID;
 902 |         result.randomUUID = function() {
 903 |             return '${new_uuid}';
 904 |         };
 905 |     }
 906 |     return result;
 907 | };
 908 | 
 909 | // 覆盖所有可能的系统ID获取函数
 910 | global.getMachineId = function() { return '${machine_id}'; };
 911 | global.getDeviceId = function() { return '${device_id}'; };
 912 | global.macMachineId = '${mac_machine_id}';
 913 | "
 914 |                 # 将代码注入到文件开头
 915 |                 local new_uuid=$(uuidgen | tr '[:upper:]' '[:lower:]')
 916 |                 local machine_id="auth0|user_$(openssl rand -hex 16)"
 917 |                 local device_id=$(uuidgen | tr '[:upper:]' '[:lower:]')
 918 |                 local mac_machine_id=$(openssl rand -hex 32)
 919 |                 
 920 |                 inject_universal_code=${inject_universal_code//\$\{new_uuid\}/$new_uuid}
 921 |                 inject_universal_code=${inject_universal_code//\$\{machine_id\}/$machine_id}
 922 |                 inject_universal_code=${inject_universal_code//\$\{device_id\}/$device_id}
 923 |                 inject_universal_code=${inject_universal_code//\$\{mac_machine_id\}/$mac_machine_id}
 924 |                 
 925 |                 echo "$inject_universal_code" > "${file}.new"
 926 |                 cat "$file" >> "${file}.new"
 927 |                 mv "${file}.new" "$file"
 928 |                 
 929 |                 log_debug "完成通用覆盖"
 930 |                 ((modified_count++))
 931 |                 log_info "使用最通用方法成功修改文件: ${file/$temp_dir\//}"
 932 |             fi
 933 |         fi
 934 |         
 935 |         # 添加在关键操作后记录日志
 936 |         echo "[MODIFIED] 文件修改后内容:" >> "$LOG_FILE"
 937 |         grep -n "return crypto.randomUUID()" "$file" | head -3 >> "$LOG_FILE"
 938 |         
 939 |         # 清理临时文件
 940 |         rm -f "${file}.tmp" "${file}.bak"
 941 |         echo "[PROCESS] 文件处理完成: $file" >> "$LOG_FILE"
 942 |     done
 943 |     
 944 |     if [ "$modified_count" -eq 0 ]; then
 945 |         log_error "未能成功修改任何文件"
 946 |         rm -rf "$temp_dir"
 947 |         return 1
 948 |     fi
 949 |     
 950 |     # 重新签名应用(增加重试机制)
 951 |     local max_retry=3
 952 |     local retry_count=0
 953 |     local sign_success=false
 954 |     
 955 |     while [ $retry_count -lt $max_retry ]; do
 956 |         ((retry_count++))
 957 |         log_info "尝试签名 (第 $retry_count 次)..."
 958 |         
 959 |         # 使用更详细的签名参数
 960 |         if codesign --sign - --force --deep --preserve-metadata=entitlements,identifier,flags "$temp_app" 2>&1 | tee /tmp/codesign.log; then
 961 |             # 验证签名
 962 |             if codesign --verify -vvvv "$temp_app" 2>/dev/null; then
 963 |                 sign_success=true
 964 |                 log_info "应用签名验证通过"
 965 |                 break
 966 |             else
 967 |                 log_warn "签名验证失败,错误日志:"
 968 |                 cat /tmp/codesign.log
 969 |             fi
 970 |         else
 971 |             log_warn "签名失败,错误日志:"
 972 |             cat /tmp/codesign.log
 973 |         fi
 974 |         
 975 |         sleep 1
 976 |     done
 977 | 
 978 |     if ! $sign_success; then
 979 |         log_error "经过 $max_retry 次尝试仍无法完成签名"
 980 |         log_error "请手动执行以下命令完成签名:"
 981 |         echo -e "${BLUE}sudo codesign --sign - --force --deep '${temp_app}'${NC}"
 982 |         echo -e "${YELLOW}操作完成后,请手动将应用复制到原路径:${NC}"
 983 |         echo -e "${BLUE}sudo cp -R '${temp_app}' '/Applications/'${NC}"
 984 |         log_info "临时文件保留在:${temp_dir}"
 985 |         return 1
 986 |     fi
 987 | 
 988 |     # 替换原应用
 989 |     log_info "安装修改版应用..."
 990 |     if ! sudo rm -rf "$CURSOR_APP_PATH" || ! sudo cp -R "$temp_app" "/Applications/"; then
 991 |         log_error "应用替换失败,正在恢复..."
 992 |         sudo rm -rf "$CURSOR_APP_PATH"
 993 |         sudo cp -R "$backup_app" "$CURSOR_APP_PATH"
 994 |         rm -rf "$temp_dir" "$backup_app"
 995 |         return 1
 996 |     fi
 997 |     
 998 |     # 清理临时文件
 999 |     rm -rf "$temp_dir" "$backup_app"
1000 |     
1001 |     # 设置权限
1002 |     sudo chown -R "$CURRENT_USER:staff" "$CURSOR_APP_PATH"
1003 |     sudo chmod -R 755 "$CURSOR_APP_PATH"
1004 |     
1005 |     log_info "Cursor 主程序文件修改完成!原版备份在: ${backup_app/$HOME/\~}"
1006 |     return 0
1007 | }
1008 | 
1009 | # 显示文件树结构
1010 | show_file_tree() {
1011 |     local base_dir=$(dirname "$STORAGE_FILE")
1012 |     echo
1013 |     log_info "文件结构:"
1014 |     echo -e "${BLUE}$base_dir${NC}"
1015 |     echo "├── globalStorage"
1016 |     echo "│   ├── storage.json (已修改)"
1017 |     echo "│   └── backups"
1018 |     
1019 |     # 列出备份文件
1020 |     if [ -d "$BACKUP_DIR" ]; then
1021 |         local backup_files=("$BACKUP_DIR"/*)
1022 |         if [ ${#backup_files[@]} -gt 0 ]; then
1023 |             for file in "${backup_files[@]}"; do
1024 |                 if [ -f "$file" ]; then
1025 |                     echo "│       └── $(basename "$file")"
1026 |                 fi
1027 |             done
1028 |         else
1029 |             echo "│       └── (空)"
1030 |         fi
1031 |     fi
1032 |     echo
1033 | }
1034 | 
1035 | # 显示公众号信息
1036 | show_follow_info() {
1037 |     echo
1038 |     echo -e "${GREEN}================================${NC}"
1039 |     echo -e "${YELLOW}  关注公众号【煎饼果子卷AI】一起交流更多Cursor技巧和AI知识(脚本免费、关注公众号加群有更多技巧和大佬) ${NC}"
1040 |     echo -e "${GREEN}================================${NC}"
1041 |     echo
1042 | }
1043 | 
1044 | # 禁用自动更新
1045 | disable_auto_update() {
1046 |     local updater_path="$HOME/Library/Application Support/Caches/cursor-updater"
1047 |     local app_update_yml="/Applications/Cursor.app/Contents/Resources/app-update.yml"
1048 |     
1049 |     echo
1050 |     log_info "正在禁用 Cursor 自动更新..."
1051 |     
1052 |     # 备份并清空 app-update.yml
1053 |     if [ -f "$app_update_yml" ]; then
1054 |         log_info "备份并修改 app-update.yml..."
1055 |         if ! sudo cp "$app_update_yml" "${app_update_yml}.bak" 2>/dev/null; then
1056 |             log_warn "备份 app-update.yml 失败,继续执行..."
1057 |         fi
1058 |         
1059 |         if sudo bash -c "echo '' > \"$app_update_yml\"" && \
1060 |            sudo chmod 444 "$app_update_yml"; then
1061 |             log_info "成功禁用 app-update.yml"
1062 |         else
1063 |             log_error "修改 app-update.yml 失败,请手动执行以下命令:"
1064 |             echo -e "${BLUE}sudo cp \"$app_update_yml\" \"${app_update_yml}.bak\"${NC}"
1065 |             echo -e "${BLUE}sudo bash -c 'echo \"\" > \"$app_update_yml\"'${NC}"
1066 |             echo -e "${BLUE}sudo chmod 444 \"$app_update_yml\"${NC}"
1067 |         fi
1068 |     else
1069 |         log_warn "未找到 app-update.yml 文件"
1070 |     fi
1071 |     
1072 |     # 同时也处理 cursor-updater
1073 |     log_info "处理 cursor-updater..."
1074 |     if sudo rm -rf "$updater_path" && \
1075 |        sudo touch "$updater_path" && \
1076 |        sudo chmod 444 "$updater_path"; then
1077 |         log_info "成功禁用 cursor-updater"
1078 |     else
1079 |         log_error "禁用 cursor-updater 失败,请手动执行以下命令:"
1080 |         echo -e "${BLUE}sudo rm -rf \"$updater_path\" && sudo touch \"$updater_path\" && sudo chmod 444 \"$updater_path\"${NC}"
1081 |     fi
1082 |     
1083 |     echo
1084 |     log_info "验证方法:"
1085 |     echo "1. 运行命令:ls -l \"$updater_path\""
1086 |     echo "   确认文件权限显示为:r--r--r--"
1087 |     echo "2. 运行命令:ls -l \"$app_update_yml\""
1088 |     echo "   确认文件权限显示为:r--r--r--"
1089 |     echo
1090 |     log_info "完成后请重启 Cursor"
1091 | }
1092 | 
1093 | # 新增恢复功能选项
1094 | restore_feature() {
1095 |     # 检查备份目录是否存在
1096 |     if [ ! -d "$BACKUP_DIR" ]; then
1097 |         log_warn "备份目录不存在"
1098 |         return 1
1099 |     fi
1100 | 
1101 |     # 使用 find 命令获取备份文件列表并存储到数组
1102 |     backup_files=()
1103 |     while IFS= read -r file; do
1104 |         [ -f "$file" ] && backup_files+=("$file")
1105 |     done < <(find "$BACKUP_DIR" -name "*.backup_*" -type f 2>/dev/null | sort)
1106 |     
1107 |     # 检查是否找到备份文件
1108 |     if [ ${#backup_files[@]} -eq 0 ]; then
1109 |         log_warn "未找到任何备份文件"
1110 |         return 1
1111 |     fi
1112 |     
1113 |     echo
1114 |     log_info "可用的备份文件:"
1115 |     
1116 |     # 构建菜单选项字符串
1117 |     menu_options="退出 - 不恢复任何文件"
1118 |     for i in "${!backup_files[@]}"; do
1119 |         menu_options="$menu_options|$(basename "${backup_files[$i]}")"
1120 |     done
1121 |     
1122 |     # 使用菜单选择函数
1123 |     select_menu_option "请使用上下箭头选择要恢复的备份文件,按Enter确认:" "$menu_options" 0
1124 |     choice=$?
1125 |     
1126 |     # 处理用户输入
1127 |     if [ "$choice" = "0" ]; then
1128 |         log_info "跳过恢复操作"
1129 |         return 0
1130 |     fi
1131 |     
1132 |     # 获取选择的备份文件 (减1是因为第一个选项是"退出")
1133 |     local selected_backup="${backup_files[$((choice-1))]}"
1134 |     
1135 |     # 验证文件存在性和可读性
1136 |     if [ ! -f "$selected_backup" ] || [ ! -r "$selected_backup" ]; then
1137 |         log_error "无法访问选择的备份文件"
1138 |         return 1
1139 |     fi
1140 |     
1141 |     # 尝试恢复配置
1142 |     if cp "$selected_backup" "$STORAGE_FILE"; then
1143 |         chmod 644 "$STORAGE_FILE"
1144 |         chown "$CURRENT_USER" "$STORAGE_FILE"
1145 |         log_info "已从备份文件恢复配置: $(basename "$selected_backup")"
1146 |         return 0
1147 |     else
1148 |         log_error "恢复配置失败"
1149 |         return 1
1150 |     fi
1151 | }
1152 | 
1153 | # 解决"应用已损坏,无法打开"问题
1154 | fix_damaged_app() {
1155 |     log_info "正在修复"应用已损坏"问题..."
1156 |     
1157 |     # 检查Cursor应用是否存在
1158 |     if [ ! -d "$CURSOR_APP_PATH" ]; then
1159 |         log_error "未找到Cursor应用: $CURSOR_APP_PATH"
1160 |         return 1
1161 |     fi
1162 |     
1163 |     log_info "尝试移除隔离属性..."
1164 |     if sudo xattr -rd com.apple.quarantine "$CURSOR_APP_PATH" 2>/dev/null; then
1165 |         log_info "成功移除隔离属性"
1166 |     else
1167 |         log_warn "移除隔离属性失败,尝试其他方法..."
1168 |     fi
1169 |     
1170 |     log_info "尝试重新签名应用..."
1171 |     if sudo codesign --force --deep --sign - "$CURSOR_APP_PATH" 2>/dev/null; then
1172 |         log_info "应用重新签名成功"
1173 |     else
1174 |         log_warn "应用重新签名失败"
1175 |     fi
1176 |     
1177 |     echo
1178 |     log_info "修复完成!请尝试重新打开Cursor应用"
1179 |     echo
1180 |     echo -e "${YELLOW}如果仍然无法打开,您可以尝试以下方法:${NC}"
1181 |     echo "1. 在系统偏好设置->安全性与隐私中,点击"仍要打开"按钮"
1182 |     echo "2. 暂时关闭Gatekeeper(不建议): sudo spctl --master-disable"
1183 |     echo "3. 重新下载安装Cursor应用"
1184 |     echo
1185 |     echo -e "${BLUE}参考链接: https://sysin.org/blog/macos-if-crashes-when-opening/${NC}"
1186 |     
1187 |     return 0
1188 | }
1189 | 
1190 | # 新增:通用菜单选择函数
1191 | # 参数: 
1192 | # $1 - 提示信息
1193 | # $2 - 选项数组,格式为 "选项1|选项2|选项3"
1194 | # $3 - 默认选项索引 (从0开始)
1195 | # 返回: 选中的选项索引 (从0开始)
1196 | select_menu_option() {
1197 |     local prompt="$1"
1198 |     IFS='|' read -ra options <<< "$2"
1199 |     local default_index=${3:-0}
1200 |     local selected_index=$default_index
1201 |     local key_input
1202 |     local cursor_up='\033[A'
1203 |     local cursor_down='\033[B'
1204 |     local enter_key=
#39;\n'
1205 |     
1206 |     # 保存光标位置
1207 |     tput sc
1208 |     
1209 |     # 显示提示信息
1210 |     echo -e "$prompt"
1211 |     
1212 |     # 第一次显示菜单
1213 |     for i in "${!options[@]}"; do
1214 |         if [ $i -eq $selected_index ]; then
1215 |             echo -e " ${GREEN}►${NC} ${options[$i]}"
1216 |         else
1217 |             echo -e "   ${options[$i]}"
1218 |         fi
1219 |     done
1220 |     
1221 |     # 循环处理键盘输入
1222 |     while true; do
1223 |         # 读取单个按键
1224 |         read -rsn3 key_input
1225 |         
1226 |         # 检测按键
1227 |         case "$key_input" in
1228 |             # 上箭头键
1229 |             
#39;\033[A')
1230 |                 if [ $selected_index -gt 0 ]; then
1231 |                     ((selected_index--))
1232 |                 fi
1233 |                 ;;
1234 |             # 下箭头键
1235 |             
#39;\033[B')
1236 |                 if [ $selected_index -lt $((${#options[@]}-1)) ]; then
1237 |                     ((selected_index++))
1238 |                 fi
1239 |                 ;;
1240 |             # Enter键
1241 |             "")
1242 |                 echo # 换行
1243 |                 log_info "您选择了: ${options[$selected_index]}"
1244 |                 return $selected_index
1245 |                 ;;
1246 |         esac
1247 |         
1248 |         # 恢复光标位置
1249 |         tput rc
1250 |         
1251 |         # 重新显示菜单
1252 |         for i in "${!options[@]}"; do
1253 |             if [ $i -eq $selected_index ]; then
1254 |                 echo -e " ${GREEN}►${NC} ${options[$i]}"
1255 |             else
1256 |                 echo -e "   ${options[$i]}"
1257 |             fi
1258 |         done
1259 |     done
1260 | }
1261 | 
1262 | # 主函数
1263 | main() {
1264 |     
1265 |     # 初始化日志文件
1266 |     initialize_log
1267 |     log_info "脚本启动..."
1268 |     
1269 |     # 记录系统信息
1270 |     log_info "系统信息: $(uname -a)"
1271 |     log_info "当前用户: $CURRENT_USER"
1272 |     log_cmd_output "sw_vers" "macOS 版本信息"
1273 |     log_cmd_output "which codesign" "codesign 路径"
1274 |     log_cmd_output "ls -la \"$CURSOR_APP_PATH\"" "Cursor 应用信息"
1275 |     
1276 |     # 新增环境检查
1277 |     if [[ $(uname) != "Darwin" ]]; then
1278 |         log_error "本脚本仅支持 macOS 系统"
1279 |         exit 1
1280 |     fi
1281 |     
1282 |     clear
1283 |     # 显示 Logo
1284 |     echo -e "
1285 |     ██████╗██╗   ██╗██████╗ ███████╗ ██████╗ ██████╗ 
1286 |    ██╔════╝██║   ██║██╔══██╗██╔════╝██╔═══██╗██╔══██╗
1287 |    ██║     ██║   ██║██████╔╝███████╗██║   ██║██████╔╝
1288 |    ██║     ██║   ██║██╔══██╗╚════██║██║   ██║██╔══██╗
1289 |    ╚██████╗╚██████╔╝██║  ██║███████║╚██████╔╝██║  ██║
1290 |     ╚═════╝ ╚═════╝ ╚═╝  ╚═╝╚══════╝ ╚═════╝ ╚═╝  ╚═╝
1291 |     "
1292 |     echo -e "${BLUE}================================${NC}"
1293 |     echo -e "${GREEN}🚀   Cursor 防掉试用Pro删除工具          ${NC}"
1294 |     echo -e "${YELLOW}📱  关注公众号【煎饼果子卷AI】     ${NC}"
1295 |     echo -e "${YELLOW}🤝  一起交流更多Cursor技巧和AI知识(脚本免费、关注公众号加群有更多技巧和大佬)  ${NC}"
1296 |     echo -e "${BLUE}================================${NC}"
1297 |     echo
1298 |     echo -e "${YELLOW}💡 [重要提示]${NC} 本工具采用分阶段执行策略,既能彻底清理又能修改机器码"
1299 |     echo -e "${YELLOW}💡 [重要提示]${NC} 本工具免费,如果对您有帮助,请关注公众号【煎饼果子卷AI】"
1300 |     echo
1301 | 
1302 |     # 📋 执行流程说明
1303 |     echo
1304 |     echo -e "${GREEN}📋 [执行流程]${NC} 本脚本将按以下步骤执行:"
1305 |     echo -e "${BLUE}  1️⃣  检测并关闭Cursor进程${NC}"
1306 |     echo -e "${BLUE}  2️⃣  保存Cursor程序路径信息${NC}"
1307 |     echo -e "${BLUE}  3️⃣  删除指定的Cursor试用相关文件夹${NC}"
1308 |     echo -e "${BLUE}      📁 ~/Library/Application Support/Cursor${NC}"
1309 |     echo -e "${BLUE}      📁 ~/.cursor${NC}"
1310 |     echo -e "${BLUE}  3.5️⃣ 预创建必要目录结构,避免权限问题${NC}"
1311 |     echo -e "${BLUE}  4️⃣  重新启动Cursor让其生成新的配置文件${NC}"
1312 |     echo -e "${BLUE}  5️⃣  等待配置文件生成完成(最多45秒)${NC}"
1313 |     echo -e "${BLUE}  6️⃣  关闭Cursor进程${NC}"
1314 |     echo -e "${BLUE}  7️⃣  修改新生成的机器码配置文件${NC}"
1315 |     echo -e "${BLUE}  8️⃣  显示操作完成统计信息${NC}"
1316 |     echo
1317 |     echo -e "${YELLOW}⚠️  [注意事项]${NC}"
1318 |     echo -e "${YELLOW}  • 脚本执行过程中请勿手动操作Cursor${NC}"
1319 |     echo -e "${YELLOW}  • 建议在执行前关闭所有Cursor窗口${NC}"
1320 |     echo -e "${YELLOW}  • 执行完成后需要重新启动Cursor${NC}"
1321 |     echo -e "${YELLOW}  • 原配置文件会自动备份到backups文件夹${NC}"
1322 |     echo -e "${YELLOW}  • 需要Python3环境来处理JSON配置文件${NC}"
1323 |     echo
1324 | 
1325 |     # 🤔 用户确认
1326 |     echo -e "${GREEN}🤔 [确认]${NC} 请确认您已了解上述执行流程"
1327 |     read -p "是否继续执行?(输入 y 或 yes 继续,其他任意键退出): " confirmation
1328 |     if [[ ! "$confirmation" =~ ^(y|yes)$ ]]; then
1329 |         echo -e "${YELLOW}👋 [退出]${NC} 用户取消执行,脚本退出"
1330 |         exit 0
1331 |     fi
1332 |     echo -e "${GREEN}✅ [确认]${NC} 用户确认继续执行"
1333 |     echo
1334 | 
1335 |     # 🚀 执行主要功能
1336 |     check_permissions
1337 |     check_and_kill_cursor
1338 | 
1339 |     # 🚨 重要警告提示
1340 |     echo
1341 |     echo -e "${RED}🚨 [重要警告]${NC} ============================================"
1342 |     log_warn "⚠️  [风控提醒] Cursor 风控机制非常严格!"
1343 |     log_warn "⚠️  [必须删除] 必须完全删除指定文件夹,不能有任何残留设置"
1344 |     log_warn "⚠️  [防掉试用] 只有彻底清理才能有效防止掉试用Pro状态"
1345 |     echo -e "${RED}🚨 [重要警告]${NC} ============================================"
1346 |     echo
1347 | 
1348 |     # 🎯 执行 Cursor 防掉试用Pro删除文件夹功能
1349 |     log_info "🚀 [开始] 开始执行核心功能..."
1350 |     remove_cursor_trial_folders
1351 | 
1352 |     # 🔄 重启Cursor让其重新生成配置文件
1353 |     restart_cursor_and_wait
1354 | 
1355 |     # 🛠️ 修改机器码配置
1356 |     modify_machine_code_config
1357 |     
1358 |     # 🎉 显示操作完成信息
1359 |     echo
1360 |     log_info "🎉 [完成] Cursor 防掉试用Pro删除操作已完成!"
1361 |     echo
1362 | 
1363 |     # 📱 显示公众号信息
1364 |     echo -e "${GREEN}================================${NC}"
1365 |     echo -e "${YELLOW}📱  关注公众号【煎饼果子卷AI】一起交流更多Cursor技巧和AI知识(脚本免费、关注公众号加群有更多技巧和大佬)  ${NC}"
1366 |     echo -e "${GREEN}================================${NC}"
1367 |     echo
1368 |     log_info "🚀 [提示] 现在可以重新启动 Cursor 尝试使用了!"
1369 |     echo
1370 | 
1371 |     # 🚫 以下功能已暂时屏蔽
1372 |     log_warn "⚠️  [提示] 以下功能已暂时屏蔽:"
1373 |     log_info "📋 [说明] - 自动更新禁用功能"
1374 |     log_info "📋 [说明] - 应用修复功能"
1375 |     log_info "📋 [说明] 如需恢复这些功能,请联系开发者"
1376 |     echo
1377 | 
1378 |     # 🎉 脚本执行完成
1379 |     log_info "🎉 [完成] 所有操作已完成!"
1380 |     echo
1381 |     log_info "💡 [提示] 如果需要恢复机器码修改功能,请联系开发者"
1382 |     log_warn "⚠️  [注意] 重启 Cursor 后生效"
1383 |     echo
1384 |     log_info "🚀 [下一步] 现在可以启动 Cursor 尝试使用了!"
1385 |     echo
1386 | 
1387 |     # 记录脚本完成信息
1388 |     log_info "📝 [日志] 脚本执行完成"
1389 |     echo "========== Cursor 防掉试用Pro删除工具日志结束 $(date) ==========" >> "$LOG_FILE"
1390 | 
1391 |     # 显示日志文件位置
1392 |     echo
1393 |     log_info "📄 [日志] 详细日志已保存到: $LOG_FILE"
1394 |     echo "如遇问题请将此日志文件提供给开发者以协助排查"
1395 |     echo
1396 | }
1397 | 
1398 | # 执行主函数
1399 | main
1400 | 
1401 | 


--------------------------------------------------------------------------------
/scripts/run/cursor_win_id_modifier_old.ps1:
--------------------------------------------------------------------------------
  1 | # 设置输出编码为 UTF-8
  2 | $OutputEncoding = [System.Text.Encoding]::UTF8
  3 | [Console]::OutputEncoding = [System.Text.Encoding]::UTF8
  4 | 
  5 | # 颜色定义
  6 | $RED = "`e[31m"
  7 | $GREEN = "`e[32m"
  8 | $YELLOW = "`e[33m"
  9 | $BLUE = "`e[34m"
 10 | $NC = "`e[0m"
 11 | 
 12 | # 配置文件路径
 13 | $STORAGE_FILE = "$env:APPDATA\Cursor\User\globalStorage\storage.json"
 14 | $BACKUP_DIR = "$env:APPDATA\Cursor\User\globalStorage\backups"
 15 | 
 16 | # 新增 Cursor 初始化函数
 17 | function Cursor-初始化 {
 18 |     Write-Host "$GREEN[信息]$NC 正在执行 Cursor 初始化清理..."
 19 |     $BASE_PATH = "$env:APPDATA\Cursor\User"
 20 | 
 21 |     $filesToDelete = @(
 22 |         (Join-Path -Path $BASE_PATH -ChildPath "globalStorage\\state.vscdb"),
 23 |         (Join-Path -Path $BASE_PATH -ChildPath "globalStorage\\state.vscdb.backup")
 24 |     )
 25 |     
 26 |     $folderToCleanContents = Join-Path -Path $BASE_PATH -ChildPath "History"
 27 |     $folderToDeleteCompletely = Join-Path -Path $BASE_PATH -ChildPath "workspaceStorage"
 28 | 
 29 |     Write-Host "$BLUE[调试]$NC 基础路径: $BASE_PATH"
 30 | 
 31 |     # 删除指定文件
 32 |     foreach ($file in $filesToDelete) {
 33 |         Write-Host "$BLUE[调试]$NC 检查文件: $file"
 34 |         if (Test-Path $file) {
 35 |             try {
 36 |                 Remove-Item -Path $file -Force -ErrorAction Stop
 37 |                 Write-Host "$GREEN[成功]$NC 已删除文件: $file"
 38 |             }
 39 |             catch {
 40 |                 Write-Host "$RED[错误]$NC 删除文件 $file 失败: $($_.Exception.Message)"
 41 |             }
 42 |         } else {
 43 |             Write-Host "$YELLOW[警告]$NC 文件不存在,跳过删除: $file"
 44 |         }
 45 |     }
 46 | 
 47 |     # 清空指定文件夹内容
 48 |     Write-Host "$BLUE[调试]$NC 检查待清空文件夹: $folderToCleanContents"
 49 |     if (Test-Path $folderToCleanContents) {
 50 |         try {
 51 |             # 获取子项进行删除,以避免删除 History 文件夹本身
 52 |             Get-ChildItem -Path $folderToCleanContents -Recurse | Remove-Item -Recurse -Force -ErrorAction Stop
 53 |             Write-Host "$GREEN[成功]$NC 已清空文件夹内容: $folderToCleanContents"
 54 |         }
 55 |         catch {
 56 |             Write-Host "$RED[错误]$NC 清空文件夹 $folderToCleanContents 内容失败: $($_.Exception.Message)"
 57 |         }
 58 |     } else {
 59 |         Write-Host "$YELLOW[警告]$NC 文件夹不存在,跳过清空: $folderToCleanContents"
 60 |     }
 61 | 
 62 |     # 删除指定文件夹及其内容
 63 |     Write-Host "$BLUE[调试]$NC 检查待删除文件夹: $folderToDeleteCompletely"
 64 |     if (Test-Path $folderToDeleteCompletely) {
 65 |         try {
 66 |             Remove-Item -Path $folderToDeleteCompletely -Recurse -Force -ErrorAction Stop
 67 |             Write-Host "$GREEN[成功]$NC 已删除文件夹: $folderToDeleteCompletely"
 68 |         }
 69 |         catch {
 70 |             Write-Host "$RED[错误]$NC 删除文件夹 $folderToDeleteCompletely 失败: $($_.Exception.Message)"
 71 |         }
 72 |     } else {
 73 |         Write-Host "$YELLOW[警告]$NC 文件夹不存在,跳过删除: $folderToDeleteCompletely"
 74 |     }
 75 | 
 76 |     Write-Host "$GREEN[信息]$NC Cursor 初始化清理完成。"
 77 |     Write-Host "" # 添加空行以改善输出格式
 78 | }
 79 | 
 80 | # 检查管理员权限
 81 | function Test-Administrator {
 82 |     $user = [Security.Principal.WindowsIdentity]::GetCurrent()
 83 |     $principal = New-Object Security.Principal.WindowsPrincipal($user)
 84 |     return $principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
 85 | }
 86 | 
 87 | if (-not (Test-Administrator)) {
 88 |     Write-Host "$RED[错误]$NC 请以管理员身份运行此脚本"
 89 |     Write-Host "请右键点击脚本,选择'以管理员身份运行'"
 90 |     Read-Host "按回车键退出"
 91 |     exit 1
 92 | }
 93 | 
 94 | # 显示 Logo
 95 | Clear-Host
 96 | Write-Host @"
 97 | 
 98 |     ██████╗██╗   ██╗██████╗ ███████╗ ██████╗ ██████╗ 
 99 |    ██╔════╝██║   ██║██╔══██╗██╔════╝██╔═══██╗██╔══██╗
100 |    ██║     ██║   ██║██████╔╝███████╗██║   ██║██████╔╝
101 |    ██║     ██║   ██║██╔══██╗╚════██║██║   ██║██╔══██╗
102 |    ╚██████╗╚██████╔╝██║  ██║███████║╚██████╔╝██║  ██║
103 |     ╚═════╝ ╚═════╝ ╚═╝  ╚═╝╚══════╝ ╚═════╝ ╚═╝  ╚═╝
104 | 
105 | "@
106 | Write-Host "$BLUE================================$NC"
107 | Write-Host "$GREEN   Cursor 设备ID 修改工具          $NC"
108 | Write-Host "$YELLOW  关注公众号【煎饼果子卷AI】 $NC"
109 | Write-Host "$YELLOW  一起交流更多Cursor技巧和AI知识(脚本免费、关注公众号加群有更多技巧和大佬)  $NC"
110 | Write-Host "$YELLOW  [重要提示] 本工具免费,如果对您有帮助,请关注公众号【煎饼果子卷AI】  $NC"
111 | Write-Host ""
112 | Write-Host "$YELLOW   [小小广告]  出售CursorPro教育号一年质保三个月,有需要找我(86),WeChat:JavaRookie666  $NC"
113 | Write-Host "$BLUE================================$NC"
114 | 
115 | # 获取并显示 Cursor 版本
116 | function Get-CursorVersion {
117 |     try {
118 |         # 主要检测路径
119 |         $packagePath = "$env:LOCALAPPDATA\\Programs\\cursor\\resources\\app\\package.json"
120 |         
121 |         if (Test-Path $packagePath) {
122 |             $packageJson = Get-Content $packagePath -Raw | ConvertFrom-Json
123 |             if ($packageJson.version) {
124 |                 Write-Host "$GREEN[信息]$NC 当前安装的 Cursor 版本: v$($packageJson.version)"
125 |                 return $packageJson.version
126 |             }
127 |         }
128 | 
129 |         # 备用路径检测
130 |         $altPath = "$env:LOCALAPPDATA\\cursor\\resources\\app\\package.json"
131 |         if (Test-Path $altPath) {
132 |             $packageJson = Get-Content $altPath -Raw | ConvertFrom-Json
133 |             if ($packageJson.version) {
134 |                 Write-Host "$GREEN[信息]$NC 当前安装的 Cursor 版本: v$($packageJson.version)"
135 |                 return $packageJson.version
136 |             }
137 |         }
138 | 
139 |         Write-Host "$YELLOW[警告]$NC 无法检测到 Cursor 版本"
140 |         Write-Host "$YELLOW[提示]$NC 请确保 Cursor 已正确安装"
141 |         return $null
142 |     }
143 |     catch {
144 |         Write-Host "$RED[错误]$NC 获取 Cursor 版本失败: $_"
145 |         return $null
146 |     }
147 | }
148 | 
149 | # 获取并显示版本信息
150 | $cursorVersion = Get-CursorVersion
151 | Write-Host ""
152 | 
153 | Write-Host "$YELLOW[重要提示]$NC 最新的 1.0.x (以支持)"
154 | Write-Host ""
155 | 
156 | # 检查并关闭 Cursor 进程
157 | Write-Host "$GREEN[信息]$NC 检查 Cursor 进程..."
158 | 
159 | function Get-ProcessDetails {
160 |     param($processName)
161 |     Write-Host "$BLUE[调试]$NC 正在获取 $processName 进程详细信息:"
162 |     Get-WmiObject Win32_Process -Filter "name='$processName'" | 
163 |         Select-Object ProcessId, ExecutablePath, CommandLine | 
164 |         Format-List
165 | }
166 | 
167 | # 定义最大重试次数和等待时间
168 | $MAX_RETRIES = 5
169 | $WAIT_TIME = 1
170 | 
171 | # 处理进程关闭
172 | function Close-CursorProcess {
173 |     param($processName)
174 |     
175 |     $process = Get-Process -Name $processName -ErrorAction SilentlyContinue
176 |     if ($process) {
177 |         Write-Host "$YELLOW[警告]$NC 发现 $processName 正在运行"
178 |         Get-ProcessDetails $processName
179 |         
180 |         Write-Host "$YELLOW[警告]$NC 尝试关闭 $processName..."
181 |         Stop-Process -Name $processName -Force
182 |         
183 |         $retryCount = 0
184 |         while ($retryCount -lt $MAX_RETRIES) {
185 |             $process = Get-Process -Name $processName -ErrorAction SilentlyContinue
186 |             if (-not $process) { break }
187 |             
188 |             $retryCount++
189 |             if ($retryCount -ge $MAX_RETRIES) {
190 |                 Write-Host "$RED[错误]$NC 在 $MAX_RETRIES 次尝试后仍无法关闭 $processName"
191 |                 Get-ProcessDetails $processName
192 |                 Write-Host "$RED[错误]$NC 请手动关闭进程后重试"
193 |                 Read-Host "按回车键退出"
194 |                 exit 1
195 |             }
196 |             Write-Host "$YELLOW[警告]$NC 等待进程关闭,尝试 $retryCount/$MAX_RETRIES..."
197 |             Start-Sleep -Seconds $WAIT_TIME
198 |         }
199 |         Write-Host "$GREEN[信息]$NC $processName 已成功关闭"
200 |     }
201 | }
202 | 
203 | # 关闭所有 Cursor 进程
204 | Close-CursorProcess "Cursor"
205 | Close-CursorProcess "cursor"
206 | 
207 | # 执行 Cursor 初始化清理
208 | # Cursor-初始化
209 | 
210 | # 创建备份目录
211 | if (-not (Test-Path $BACKUP_DIR)) {
212 |     New-Item -ItemType Directory -Path $BACKUP_DIR | Out-Null
213 | }
214 | 
215 | # 备份现有配置
216 | if (Test-Path $STORAGE_FILE) {
217 |     Write-Host "$GREEN[信息]$NC 正在备份配置文件..."
218 |     $backupName = "storage.json.backup_$(Get-Date -Format 'yyyyMMdd_HHmmss')"
219 |     Copy-Item $STORAGE_FILE "$BACKUP_DIR\$backupName"
220 | }
221 | 
222 | # 生成新的 ID
223 | Write-Host "$GREEN[信息]$NC 正在生成新的 ID..."
224 | 
225 | # 在颜色定义后添加此函数
226 | function Get-RandomHex {
227 |     param (
228 |         [int]$length
229 |     )
230 |     
231 |     $bytes = New-Object byte[] ($length)
232 |     $rng = [System.Security.Cryptography.RNGCryptoServiceProvider]::new()
233 |     $rng.GetBytes($bytes)
234 |     $hexString = [System.BitConverter]::ToString($bytes) -replace '-',''
235 |     $rng.Dispose()
236 |     return $hexString
237 | }
238 | 
239 | # 改进 ID 生成函数
240 | function New-StandardMachineId {
241 |     $template = "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx"
242 |     $result = $template -replace '[xy]', {
243 |         param($match)
244 |         $r = [Random]::new().Next(16)
245 |         $v = if ($match.Value -eq "x") { $r } else { ($r -band 0x3) -bor 0x8 }
246 |         return $v.ToString("x")
247 |     }
248 |     return $result
249 | }
250 | 
251 | # 在生成 ID 时使用新函数
252 | $MAC_MACHINE_ID = New-StandardMachineId
253 | $UUID = [System.Guid]::NewGuid().ToString()
254 | # 将 auth0|user_ 转换为字节数组的十六进制
255 | $prefixBytes = [System.Text.Encoding]::UTF8.GetBytes("auth0|user_")
256 | $prefixHex = -join ($prefixBytes | ForEach-Object { '{0:x2}' -f $_ })
257 | # 生成32字节(64个十六进制字符)的随机数作为 machineId 的随机部分
258 | $randomPart = Get-RandomHex -length 32
259 | $MACHINE_ID = "$prefixHex$randomPart"
260 | $SQM_ID = "{$([System.Guid]::NewGuid().ToString().ToUpper())}"
261 | 
262 | # 在Update-MachineGuid函数前添加权限检查
263 | if (-NOT ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")) {
264 |     Write-Host "$RED[错误]$NC 请使用管理员权限运行此脚本"
265 |     Start-Process powershell "-NoProfile -ExecutionPolicy Bypass -File `"$PSCommandPath`"" -Verb RunAs
266 |     exit
267 | }
268 | 
269 | function Update-MachineGuid {
270 |     try {
271 |         # 检查注册表路径是否存在,不存在则创建
272 |         $registryPath = "HKLM:\SOFTWARE\Microsoft\Cryptography"
273 |         if (-not (Test-Path $registryPath)) {
274 |             Write-Host "$YELLOW[警告]$NC 注册表路径不存在: $registryPath,正在创建..."
275 |             New-Item -Path $registryPath -Force | Out-Null
276 |             Write-Host "$GREEN[信息]$NC 注册表路径创建成功"
277 |         }
278 | 
279 |         # 获取当前的 MachineGuid,如果不存在则使用空字符串作为默认值
280 |         $originalGuid = ""
281 |         try {
282 |             $currentGuid = Get-ItemProperty -Path $registryPath -Name MachineGuid -ErrorAction SilentlyContinue
283 |             if ($currentGuid) {
284 |                 $originalGuid = $currentGuid.MachineGuid
285 |                 Write-Host "$GREEN[信息]$NC 当前注册表值:"
286 |                 Write-Host "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography" 
287 |                 Write-Host "    MachineGuid    REG_SZ    $originalGuid"
288 |             } else {
289 |                 Write-Host "$YELLOW[警告]$NC MachineGuid 值不存在,将创建新值"
290 |             }
291 |         } catch {
292 |             Write-Host "$YELLOW[警告]$NC 获取 MachineGuid 失败: $($_.Exception.Message)"
293 |         }
294 | 
295 |         # 创建备份目录(如果不存在)
296 |         if (-not (Test-Path $BACKUP_DIR)) {
297 |             New-Item -ItemType Directory -Path $BACKUP_DIR -Force | Out-Null
298 |         }
299 | 
300 |         # 创建备份文件(仅当原始值存在时)
301 |         if ($originalGuid) {
302 |             $backupFile = "$BACKUP_DIR\MachineGuid_$(Get-Date -Format 'yyyyMMdd_HHmmss').reg"
303 |             $backupResult = Start-Process "reg.exe" -ArgumentList "export", "`"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography`"", "`"$backupFile`"" -NoNewWindow -Wait -PassThru
304 |             
305 |             if ($backupResult.ExitCode -eq 0) {
306 |                 Write-Host "$GREEN[信息]$NC 注册表项已备份到:$backupFile"
307 |             } else {
308 |                 Write-Host "$YELLOW[警告]$NC 备份创建失败,继续执行..."
309 |             }
310 |         }
311 | 
312 |         # 生成新GUID
313 |         $newGuid = [System.Guid]::NewGuid().ToString()
314 | 
315 |         # 更新或创建注册表值
316 |         Set-ItemProperty -Path $registryPath -Name MachineGuid -Value $newGuid -Force -ErrorAction Stop
317 |         
318 |         # 验证更新
319 |         $verifyGuid = (Get-ItemProperty -Path $registryPath -Name MachineGuid -ErrorAction Stop).MachineGuid
320 |         if ($verifyGuid -ne $newGuid) {
321 |             throw "注册表验证失败:更新后的值 ($verifyGuid) 与预期值 ($newGuid) 不匹配"
322 |         }
323 | 
324 |         Write-Host "$GREEN[信息]$NC 注册表更新成功:"
325 |         Write-Host "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography"
326 |         Write-Host "    MachineGuid    REG_SZ    $newGuid"
327 |         return $true
328 |     }
329 |     catch {
330 |         Write-Host "$RED[错误]$NC 注册表操作失败:$($_.Exception.Message)"
331 |         
332 |         # 尝试恢复备份(如果存在)
333 |         if (($backupFile -ne $null) -and (Test-Path $backupFile)) {
334 |             Write-Host "$YELLOW[恢复]$NC 正在从备份恢复..."
335 |             $restoreResult = Start-Process "reg.exe" -ArgumentList "import", "`"$backupFile`"" -NoNewWindow -Wait -PassThru
336 |             
337 |             if ($restoreResult.ExitCode -eq 0) {
338 |                 Write-Host "$GREEN[恢复成功]$NC 已还原原始注册表值"
339 |             } else {
340 |                 Write-Host "$RED[错误]$NC 恢复失败,请手动导入备份文件:$backupFile"
341 |             }
342 |         } else {
343 |             Write-Host "$YELLOW[警告]$NC 未找到备份文件或备份创建失败,无法自动恢复"
344 |         }
345 |         return $false
346 |     }
347 | }
348 | 
349 | # 创建或更新配置文件
350 | Write-Host "$GREEN[信息]$NC 正在更新配置..."
351 | 
352 | try {
353 |     # 检查配置文件是否存在
354 |     if (-not (Test-Path $STORAGE_FILE)) {
355 |         Write-Host "$RED[错误]$NC 未找到配置文件: $STORAGE_FILE"
356 |         Write-Host "$YELLOW[提示]$NC 请先安装并运行一次 Cursor 后再使用此脚本"
357 |         Read-Host "按回车键退出"
358 |         exit 1
359 |     }
360 | 
361 |     # 读取现有配置文件
362 |     try {
363 |         $originalContent = Get-Content $STORAGE_FILE -Raw -Encoding UTF8
364 |         
365 |         # 将 JSON 字符串转换为 PowerShell 对象
366 |         $config = $originalContent | ConvertFrom-Json 
367 | 
368 |         # 备份当前值
369 |         $oldValues = @{
370 |             'machineId' = $config.'telemetry.machineId'
371 |             'macMachineId' = $config.'telemetry.macMachineId'
372 |             'devDeviceId' = $config.'telemetry.devDeviceId'
373 |             'sqmId' = $config.'telemetry.sqmId'
374 |         }
375 | 
376 |         # 更新特定的值
377 |         $config.'telemetry.machineId' = $MACHINE_ID
378 |         $config.'telemetry.macMachineId' = $MAC_MACHINE_ID
379 |         $config.'telemetry.devDeviceId' = $UUID
380 |         $config.'telemetry.sqmId' = $SQM_ID
381 | 
382 |         # 将更新后的对象转换回 JSON 并保存
383 |         $updatedJson = $config | ConvertTo-Json -Depth 10
384 |         [System.IO.File]::WriteAllText(
385 |             [System.IO.Path]::GetFullPath($STORAGE_FILE), 
386 |             $updatedJson, 
387 |             [System.Text.Encoding]::UTF8
388 |         )
389 |         Write-Host "$GREEN[信息]$NC 成功更新配置文件"
390 |     } catch {
391 |         # 如果出错,尝试恢复原始内容
392 |         if ($originalContent) {
393 |             [System.IO.File]::WriteAllText(
394 |                 [System.IO.Path]::GetFullPath($STORAGE_FILE), 
395 |                 $originalContent, 
396 |                 [System.Text.Encoding]::UTF8
397 |             )
398 |         }
399 |         throw "处理 JSON 失败: $_"
400 |     }
401 |     # 直接执行更新 MachineGuid,不再询问
402 |     Update-MachineGuid
403 |     # 显示结果
404 |     Write-Host ""
405 |     Write-Host "$GREEN[信息]$NC 已更新配置:"
406 |     Write-Host "$BLUE[调试]$NC machineId: $MACHINE_ID"
407 |     Write-Host "$BLUE[调试]$NC macMachineId: $MAC_MACHINE_ID"
408 |     Write-Host "$BLUE[调试]$NC devDeviceId: $UUID"
409 |     Write-Host "$BLUE[调试]$NC sqmId: $SQM_ID"
410 | 
411 |     # 显示文件树结构
412 |     Write-Host ""
413 |     Write-Host "$GREEN[信息]$NC 文件结构:"
414 |     Write-Host "$BLUE$env:APPDATA\Cursor\User$NC"
415 |     Write-Host "├── globalStorage"
416 |     Write-Host "│   ├── storage.json (已修改)"
417 |     Write-Host "│   └── backups"
418 | 
419 |     # 列出备份文件
420 |     $backupFiles = Get-ChildItem "$BACKUP_DIR\*" -ErrorAction SilentlyContinue
421 |     if ($backupFiles) {
422 |         foreach ($file in $backupFiles) {
423 |             Write-Host "│       └── $($file.Name)"
424 |         }
425 |     } else {
426 |         Write-Host "│       └── (空)"
427 |     }
428 | 
429 |     # 显示公众号信息
430 |     Write-Host ""
431 |     Write-Host "$GREEN================================$NC"
432 |     Write-Host "$YELLOW  关注公众号【煎饼果子卷AI】一起交流更多Cursor技巧和AI知识(脚本免费、关注公众号加群有更多技巧和大佬)  $NC"
433 |     Write-Host "$GREEN================================$NC"
434 |     Write-Host ""
435 |     Write-Host "$GREEN[信息]$NC 请重启 Cursor 以应用新的配置"
436 |     Write-Host ""
437 | 
438 |     # 询问是否要禁用自动更新
439 |     Write-Host ""
440 |     Write-Host "$YELLOW[询问]$NC 是否要禁用 Cursor 自动更新功能?"
441 |     Write-Host "0) 否 - 保持默认设置 (按回车键)"
442 |     Write-Host "1) 是 - 禁用自动更新"
443 |     $choice = Read-Host "请输入选项 (0)"
444 | 
445 |     if ($choice -eq "1") {
446 |         Write-Host ""
447 |         Write-Host "$GREEN[信息]$NC 正在处理自动更新..."
448 |         $updaterPath = "$env:LOCALAPPDATA\cursor-updater"
449 | 
450 |         # 定义手动设置教程
451 |         function Show-ManualGuide {
452 |             Write-Host ""
453 |             Write-Host "$YELLOW[警告]$NC 自动设置失败,请尝试手动操作:"
454 |             Write-Host "$YELLOW手动禁用更新步骤:$NC"
455 |             Write-Host "1. 以管理员身份打开 PowerShell"
456 |             Write-Host "2. 复制粘贴以下命令:"
457 |             Write-Host "$BLUE命令1 - 删除现有目录(如果存在):$NC"
458 |             Write-Host "Remove-Item -Path `"$updaterPath`" -Force -Recurse -ErrorAction SilentlyContinue"
459 |             Write-Host ""
460 |             Write-Host "$BLUE命令2 - 创建阻止文件:$NC"
461 |             Write-Host "New-Item -Path `"$updaterPath`" -ItemType File -Force | Out-Null"
462 |             Write-Host ""
463 |             Write-Host "$BLUE命令3 - 设置只读属性:$NC"
464 |             Write-Host "Set-ItemProperty -Path `"$updaterPath`" -Name IsReadOnly -Value `$true"
465 |             Write-Host ""
466 |             Write-Host "$BLUE命令4 - 设置权限(可选):$NC"
467 |             Write-Host "icacls `"$updaterPath`" /inheritance:r /grant:r `"`$($env:USERNAME):(R)`""
468 |             Write-Host ""
469 |             Write-Host "$YELLOW验证方法:$NC"
470 |             Write-Host "1. 运行命令:Get-ItemProperty `"$updaterPath`""
471 |             Write-Host "2. 确认 IsReadOnly 属性为 True"
472 |             Write-Host "3. 运行命令:icacls `"$updaterPath`""
473 |             Write-Host "4. 确认只有读取权限"
474 |             Write-Host ""
475 |             Write-Host "$YELLOW[提示]$NC 完成后请重启 Cursor"
476 |         }
477 | 
478 |         try {
479 |             # 检查cursor-updater是否存在
480 |             if (Test-Path $updaterPath) {
481 |                 # 如果是文件,说明已经创建了阻止更新
482 |                 if ((Get-Item $updaterPath) -is [System.IO.FileInfo]) {
483 |                     Write-Host "$GREEN[信息]$NC 已创建阻止更新文件,无需再次阻止"
484 |                     return
485 |                 }
486 |                 # 如果是目录,尝试删除
487 |                 else {
488 |                     try {
489 |                         Remove-Item -Path $updaterPath -Force -Recurse -ErrorAction Stop
490 |                         Write-Host "$GREEN[信息]$NC 成功删除 cursor-updater 目录"
491 |                     }
492 |                     catch {
493 |                         Write-Host "$RED[错误]$NC 删除 cursor-updater 目录失败"
494 |                         Show-ManualGuide
495 |                         return
496 |                     }
497 |                 }
498 |             }
499 | 
500 |             # 创建阻止文件
501 |             try {
502 |                 New-Item -Path $updaterPath -ItemType File -Force -ErrorAction Stop | Out-Null
503 |                 Write-Host "$GREEN[信息]$NC 成功创建阻止文件"
504 |             }
505 |             catch {
506 |                 Write-Host "$RED[错误]$NC 创建阻止文件失败"
507 |                 Show-ManualGuide
508 |                 return
509 |             }
510 | 
511 |             # 设置文件权限
512 |             try {
513 |                 # 设置只读属性
514 |                 Set-ItemProperty -Path $updaterPath -Name IsReadOnly -Value $true -ErrorAction Stop
515 |                 
516 |                 # 使用 icacls 设置权限
517 |                 $result = Start-Process "icacls.exe" -ArgumentList "`"$updaterPath`" /inheritance:r /grant:r `"$($env:USERNAME):(R)`"" -Wait -NoNewWindow -PassThru
518 |                 if ($result.ExitCode -ne 0) {
519 |                     throw "icacls 命令失败"
520 |                 }
521 |                 
522 |                 Write-Host "$GREEN[信息]$NC 成功设置文件权限"
523 |             }
524 |             catch {
525 |                 Write-Host "$RED[错误]$NC 设置文件权限失败"
526 |                 Show-ManualGuide
527 |                 return
528 |             }
529 | 
530 |             # 验证设置
531 |             try {
532 |                 $fileInfo = Get-ItemProperty $updaterPath
533 |                 if (-not $fileInfo.IsReadOnly) {
534 |                     Write-Host "$RED[错误]$NC 验证失败:文件权限设置可能未生效"
535 |                     Show-ManualGuide
536 |                     return
537 |                 }
538 |             }
539 |             catch {
540 |                 Write-Host "$RED[错误]$NC 验证设置失败"
541 |                 Show-ManualGuide
542 |                 return
543 |             }
544 | 
545 |             Write-Host "$GREEN[信息]$NC 成功禁用自动更新"
546 |         }
547 |         catch {
548 |             Write-Host "$RED[错误]$NC 发生未知错误: $_"
549 |             Show-ManualGuide
550 |         }
551 |     }
552 |     else {
553 |         Write-Host "$GREEN[信息]$NC 保持默认设置,不进行更改"
554 |     }
555 | 
556 |     # 保留有效的注册表更新
557 |     Update-MachineGuid
558 | 
559 | } catch {
560 |     Write-Host "$RED[错误]$NC 主要操作失败: $_"
561 |     Write-Host "$YELLOW[尝试]$NC 使用备选方法..."
562 |     
563 |     try {
564 |         # 备选方法:使用 Add-Content
565 |         $tempFile = [System.IO.Path]::GetTempFileName()
566 |         $config | ConvertTo-Json | Set-Content -Path $tempFile -Encoding UTF8
567 |         Copy-Item -Path $tempFile -Destination $STORAGE_FILE -Force
568 |         Remove-Item -Path $tempFile
569 |         Write-Host "$GREEN[信息]$NC 使用备选方法成功写入配置"
570 |     } catch {
571 |         Write-Host "$RED[错误]$NC 所有尝试都失败了"
572 |         Write-Host "错误详情: $_"
573 |         Write-Host "目标文件: $STORAGE_FILE"
574 |         Write-Host "请确保您有足够的权限访问该文件"
575 |         Read-Host "按回车键退出"
576 |         exit 1
577 |     }
578 | }
579 | 
580 | Write-Host ""
581 | Read-Host "按回车键退出"
582 | exit 0
583 | 
584 | # 在文件写入部分修改
585 | function Write-ConfigFile {
586 |     param($config, $filePath)
587 |     
588 |     try {
589 |         # 使用 UTF8 无 BOM 编码
590 |         $utf8NoBom = New-Object System.Text.UTF8Encoding $false
591 |         $jsonContent = $config | ConvertTo-Json -Depth 10
592 |         
593 |         # 统一使用 LF 换行符
594 |         $jsonContent = $jsonContent.Replace("`r`n", "`n")
595 |         
596 |         [System.IO.File]::WriteAllText(
597 |             [System.IO.Path]::GetFullPath($filePath),
598 |             $jsonContent,
599 |             $utf8NoBom
600 |         )
601 |         
602 |         Write-Host "$GREEN[信息]$NC 成功写入配置文件(UTF8 无 BOM)"
603 |     }
604 |     catch {
605 |         throw "写入配置文件失败: $_"
606 |     }
607 | } 


--------------------------------------------------------------------------------