From 91a72f92169995db3a0660073e225c1203efbc6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=85=8E=E9=A5=BC=E6=9E=9C=E5=AD=90=E5=8D=B7=E9=B2=A8?= =?UTF-8?q?=E9=B1=BC=E8=BE=A3=E6=A4=92?= Date: Sun, 21 Dec 2025 21:22:28 +0800 Subject: [PATCH] =?UTF-8?q?fix(cursor):=20=E4=BC=98=E5=8C=96=20ID=20?= =?UTF-8?q?=E6=9B=BF=E6=8D=A2=E9=80=BB=E8=BE=91=E4=B8=8E=20ESM=20=E5=85=BC?= =?UTF-8?q?=E5=AE=B9=E6=80=A7=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 修复了 Cursor 各平台脚本中 ID 占位符的替换方式,避免因双重引号导致的 JavaScript 语法错误。同时增强对 ESM 模块系统的兼容处理,确保在纯 ESM 环境下 也能正确获取 `require` 方法以完成模块 hook。此外,统一各平台脚本的处理逻辑, 提升代码一致性与可维护性。 --- scripts/run/cursor_linux_id_modifier.sh | 34 ++++++++- scripts/run/cursor_mac_id_modifier.sh | 58 +++++++++++++-- scripts/run/cursor_win_id_modifier.ps1 | 99 +++++++++++++++---------- 3 files changed, 140 insertions(+), 51 deletions(-) diff --git a/scripts/run/cursor_linux_id_modifier.sh b/scripts/run/cursor_linux_id_modifier.sh index 97dee3b..c78c266 100755 --- a/scripts/run/cursor_linux_id_modifier.sh +++ b/scripts/run/cursor_linux_id_modifier.sh @@ -826,37 +826,54 @@ EOF local replaced=false # ========== 方法A: someValue占位符替换(稳定锚点) ========== + # 重要说明: + # 当前 Cursor 的 main.js 中占位符通常是以字符串字面量形式出现,例如: + # this.machineId="someValue.machineId" + # 如果直接把 someValue.machineId 替换成 "\"<真实值>\"",会形成 ""<真实值>"" 导致 JS 语法错误。 + # 因此这里优先替换完整的字符串字面量(包含外层引号),再兜底替换不带引号的占位符。 if grep -q 'someValue\.machineId' "$file"; then + sed -i "s/\"someValue\.machineId\"/\"${machine_id}\"/g" "$file" + sed -i "s/'someValue\.machineId'/\"${machine_id}\"/g" "$file" sed -i "s/someValue\.machineId/\"${machine_id}\"/g" "$file" log_info " ✓ [方案A] 替换 someValue.machineId" replaced=true fi if grep -q 'someValue\.macMachineId' "$file"; then + sed -i "s/\"someValue\.macMachineId\"/\"${mac_machine_id}\"/g" "$file" + sed -i "s/'someValue\.macMachineId'/\"${mac_machine_id}\"/g" "$file" sed -i "s/someValue\.macMachineId/\"${mac_machine_id}\"/g" "$file" log_info " ✓ [方案A] 替换 someValue.macMachineId" replaced=true fi if grep -q 'someValue\.devDeviceId' "$file"; then + sed -i "s/\"someValue\.devDeviceId\"/\"${device_id}\"/g" "$file" + sed -i "s/'someValue\.devDeviceId'/\"${device_id}\"/g" "$file" sed -i "s/someValue\.devDeviceId/\"${device_id}\"/g" "$file" log_info " ✓ [方案A] 替换 someValue.devDeviceId" replaced=true fi if grep -q 'someValue\.sqmId' "$file"; then + sed -i "s/\"someValue\.sqmId\"/\"${sqm_id}\"/g" "$file" + sed -i "s/'someValue\.sqmId'/\"${sqm_id}\"/g" "$file" sed -i "s/someValue\.sqmId/\"${sqm_id}\"/g" "$file" log_info " ✓ [方案A] 替换 someValue.sqmId" replaced=true fi if grep -q 'someValue\.sessionId' "$file"; then + sed -i "s/\"someValue\.sessionId\"/\"${session_id}\"/g" "$file" + sed -i "s/'someValue\.sessionId'/\"${session_id}\"/g" "$file" sed -i "s/someValue\.sessionId/\"${session_id}\"/g" "$file" log_info " ✓ [方案A] 替换 someValue.sessionId" replaced=true fi if grep -q 'someValue\.firstSessionDate' "$file"; then + sed -i "s/\"someValue\.firstSessionDate\"/\"${first_session_date}\"/g" "$file" + sed -i "s/'someValue\.firstSessionDate'/\"${first_session_date}\"/g" "$file" sed -i "s/someValue\.firstSessionDate/\"${first_session_date}\"/g" "$file" log_info " ✓ [方案A] 替换 someValue.firstSessionDate" replaced=true @@ -864,9 +881,22 @@ EOF # ========== 方法B: 增强版深度 Hook 注入 ========== local inject_code='// ========== Cursor Hook 注入开始 ========== -;(function(){/*__cursor_patched__*/ +;(async function(){/*__cursor_patched__*/ "use strict"; if(globalThis.__cursor_patched__)return; + +// 兼容 ESM:确保可用的 require(部分版本 main.js 可能是纯 ESM,不保证存在 require) +var __require__=typeof require==="function"?require:null; +if(!__require__){ + try{ + var __m__=await import("module"); + __require__=__m__.createRequire(import.meta.url); + }catch(e){ + // 无法获得 require 时直接退出,避免影响主进程启动 + return; + } +} + globalThis.__cursor_patched__=true; var __ids__={ @@ -879,7 +909,7 @@ var __ids__={ globalThis.__cursor_ids__=__ids__; -var Module=require("module"); +var Module=__require__("module"); var _origReq=Module.prototype.require; var _hooked=new Map(); diff --git a/scripts/run/cursor_mac_id_modifier.sh b/scripts/run/cursor_mac_id_modifier.sh index 11d0932..98c71dc 100644 --- a/scripts/run/cursor_mac_id_modifier.sh +++ b/scripts/run/cursor_mac_id_modifier.sh @@ -1623,40 +1623,69 @@ EOF log_info "📝 [处理] 正在处理: ${file/$CURSOR_APP_PATH\//}" # ========== 方法A: someValue占位符替换(稳定锚点) ========== + # 重要说明: + # 当前 Cursor 的 main.js 中占位符通常是以字符串字面量形式出现,例如: + # this.machineId="someValue.machineId" + # 如果直接把 someValue.machineId 替换成 "\"<真实值>\"",会形成 ""<真实值>"" 导致 JS 语法错误。 + # 因此这里优先替换完整的字符串字面量(包含外层引号),再兜底替换不带引号的占位符。 local replaced=false if grep -q 'someValue\.machineId' "$file"; then - sed -i.tmp "s/someValue\.machineId/\"${machine_id}\"/g" "$file" + sed -i.tmp \ + -e "s/\"someValue\.machineId\"/\"${machine_id}\"/g" \ + -e "s/'someValue\.machineId'/\"${machine_id}\"/g" \ + -e "s/someValue\.machineId/\"${machine_id}\"/g" \ + "$file" log_info " ✓ [方案A] 替换 someValue.machineId" replaced=true fi if grep -q 'someValue\.macMachineId' "$file"; then - sed -i.tmp "s/someValue\.macMachineId/\"${mac_machine_id}\"/g" "$file" + sed -i.tmp \ + -e "s/\"someValue\.macMachineId\"/\"${mac_machine_id}\"/g" \ + -e "s/'someValue\.macMachineId'/\"${mac_machine_id}\"/g" \ + -e "s/someValue\.macMachineId/\"${mac_machine_id}\"/g" \ + "$file" log_info " ✓ [方案A] 替换 someValue.macMachineId" replaced=true fi if grep -q 'someValue\.devDeviceId' "$file"; then - sed -i.tmp "s/someValue\.devDeviceId/\"${device_id}\"/g" "$file" + sed -i.tmp \ + -e "s/\"someValue\.devDeviceId\"/\"${device_id}\"/g" \ + -e "s/'someValue\.devDeviceId'/\"${device_id}\"/g" \ + -e "s/someValue\.devDeviceId/\"${device_id}\"/g" \ + "$file" log_info " ✓ [方案A] 替换 someValue.devDeviceId" replaced=true fi if grep -q 'someValue\.sqmId' "$file"; then - sed -i.tmp "s/someValue\.sqmId/\"${sqm_id}\"/g" "$file" + sed -i.tmp \ + -e "s/\"someValue\.sqmId\"/\"${sqm_id}\"/g" \ + -e "s/'someValue\.sqmId'/\"${sqm_id}\"/g" \ + -e "s/someValue\.sqmId/\"${sqm_id}\"/g" \ + "$file" log_info " ✓ [方案A] 替换 someValue.sqmId" replaced=true fi if grep -q 'someValue\.sessionId' "$file"; then - sed -i.tmp "s/someValue\.sessionId/\"${session_id}\"/g" "$file" + sed -i.tmp \ + -e "s/\"someValue\.sessionId\"/\"${session_id}\"/g" \ + -e "s/'someValue\.sessionId'/\"${session_id}\"/g" \ + -e "s/someValue\.sessionId/\"${session_id}\"/g" \ + "$file" log_info " ✓ [方案A] 替换 someValue.sessionId" replaced=true fi if grep -q 'someValue\.firstSessionDate' "$file"; then - sed -i.tmp "s/someValue\.firstSessionDate/\"${first_session_date}\"/g" "$file" + sed -i.tmp \ + -e "s/\"someValue\.firstSessionDate\"/\"${first_session_date}\"/g" \ + -e "s/'someValue\.firstSessionDate'/\"${first_session_date}\"/g" \ + -e "s/someValue\.firstSessionDate/\"${first_session_date}\"/g" \ + "$file" log_info " ✓ [方案A] 替换 someValue.firstSessionDate" replaced=true fi @@ -1664,9 +1693,22 @@ EOF # ========== 方法B: 增强版深度 Hook 注入 ========== # 创建注入代码 local inject_code='// ========== Cursor Hook 注入开始 ========== -;(function(){/*__cursor_patched__*/ +;(async function(){/*__cursor_patched__*/ "use strict"; if(globalThis.__cursor_patched__)return; + +// 兼容 ESM:确保可用的 require(部分版本 main.js 可能是纯 ESM,不保证存在 require) +var __require__=typeof require==="function"?require:null; +if(!__require__){ + try{ + var __m__=await import("module"); + __require__=__m__.createRequire(import.meta.url); + }catch(e){ + // 无法获得 require 时直接退出,避免影响主进程启动 + return; + } +} + globalThis.__cursor_patched__=true; var __ids__={ @@ -1679,7 +1721,7 @@ var __ids__={ globalThis.__cursor_ids__=__ids__; -var Module=require("module"); +var Module=__require__("module"); var _origReq=Module.prototype.require; var _hooked=new Map(); diff --git a/scripts/run/cursor_win_id_modifier.ps1 b/scripts/run/cursor_win_id_modifier.ps1 index d4f24bb..01920b8 100644 --- a/scripts/run/cursor_win_id_modifier.ps1 +++ b/scripts/run/cursor_win_id_modifier.ps1 @@ -1,4 +1,4 @@ -# 设置输出编码为 UTF-8 +# 设置输出编码为 UTF-8 $OutputEncoding = [System.Text.Encoding]::UTF8 [Console]::OutputEncoding = [System.Text.Encoding]::UTF8 @@ -178,48 +178,52 @@ function Modify-CursorJSFiles { # ========== 方法A: someValue占位符替换(稳定锚点) ========== # 这些字符串是固定的占位符,不会被混淆器修改,跨版本稳定 + # 重要说明: + # 当前 Cursor 的 main.js 中占位符通常是以字符串字面量形式出现,例如: + # this.machineId="someValue.machineId" + # 如果直接把 someValue.machineId 替换成 "\"<真实值>\"",会形成 ""<真实值>"" 导致 JS 语法错误(Invalid token)。 + # 因此这里优先替换完整的字符串字面量(包含外层引号),并使用 JSON 字符串字面量确保转义安全。 - # 替换 someValue.machineId - if ($content -match 'someValue\.machineId') { - $content = $content -replace 'someValue\.machineId', "`"$machineId`"" - Write-Host " $GREEN✓$NC [方案A] 替换 someValue.machineId" - $replaced = $true - } - - # 替换 someValue.macMachineId - if ($content -match 'someValue\.macMachineId') { - $content = $content -replace 'someValue\.macMachineId', "`"$macMachineId`"" - Write-Host " $GREEN✓$NC [方案A] 替换 someValue.macMachineId" - $replaced = $true - } - - # 替换 someValue.devDeviceId - if ($content -match 'someValue\.devDeviceId') { - $content = $content -replace 'someValue\.devDeviceId', "`"$deviceId`"" - Write-Host " $GREEN✓$NC [方案A] 替换 someValue.devDeviceId" - $replaced = $true - } + # 🔧 新增: firstSessionDate(重置首次会话日期) + $firstSessionDateValue = (Get-Date).ToString("yyyy-MM-ddTHH:mm:ss.fffZ") - # 替换 someValue.sqmId - if ($content -match 'someValue\.sqmId') { - $content = $content -replace 'someValue\.sqmId', "`"$sqmId`"" - Write-Host " $GREEN✓$NC [方案A] 替换 someValue.sqmId" - $replaced = $true - } + $placeholders = @( + @{ Name = 'someValue.machineId'; Value = [string]$machineId }, + @{ Name = 'someValue.macMachineId'; Value = [string]$macMachineId }, + @{ Name = 'someValue.devDeviceId'; Value = [string]$deviceId }, + @{ Name = 'someValue.sqmId'; Value = [string]$sqmId }, + @{ Name = 'someValue.sessionId'; Value = [string]$sessionId }, + @{ Name = 'someValue.firstSessionDate'; Value = [string]$firstSessionDateValue } + ) + + foreach ($ph in $placeholders) { + $name = $ph.Name + $jsonValue = ($ph.Value | ConvertTo-Json -Compress) # 生成带双引号的 JSON 字符串字面量 + + $changed = $false + + # 优先替换带引号的占位符字面量,避免出现 ""abc"" 破坏语法 + $doubleLiteral = '"' + $name + '"' + if ($content.Contains($doubleLiteral)) { + $content = $content.Replace($doubleLiteral, $jsonValue) + $changed = $true + } + $singleLiteral = "'" + $name + "'" + if ($content.Contains($singleLiteral)) { + $content = $content.Replace($singleLiteral, $jsonValue) + $changed = $true + } - # 替换 someValue.sessionId(新增锚点) - if ($content -match 'someValue\.sessionId') { - $content = $content -replace 'someValue\.sessionId', "`"$sessionId`"" - Write-Host " $GREEN✓$NC [方案A] 替换 someValue.sessionId" - $replaced = $true - } + # 兜底:如果占位符以非字符串字面量形式出现,则替换为 JSON 字符串字面量(自带引号) + if (-not $changed -and $content.Contains($name)) { + $content = $content.Replace($name, $jsonValue) + $changed = $true + } - # 🔧 新增: 替换 someValue.firstSessionDate - $firstSessionDateValue = (Get-Date).ToString("yyyy-MM-ddTHH:mm:ss.fffZ") - if ($content -match 'someValue\.firstSessionDate') { - $content = $content -replace 'someValue\.firstSessionDate', $firstSessionDateValue - Write-Host " $GREEN✓$NC [方案A] 替换 someValue.firstSessionDate" - $replaced = $true + if ($changed) { + Write-Host " $GREEN✓$NC [方案A] 替换 $name" + $replaced = $true + } } # ========== 方法B: 增强版深度 Hook 注入 ========== @@ -234,9 +238,22 @@ function Modify-CursorJSFiles { $injectCode = @" // ========== Cursor Hook 注入开始 ========== -;(function(){/*__cursor_patched__*/ +;(async function(){/*__cursor_patched__*/ 'use strict'; if(globalThis.__cursor_patched__)return; + +// 兼容 ESM:确保可用的 require(部分版本 main.js 可能是纯 ESM,不保证存在 require) +var __require__=typeof require==='function'?require:null; +if(!__require__){ + try{ + var __m__=await import('module'); + __require__=__m__.createRequire(import.meta.url); + }catch(e){ + // 无法获得 require 时直接退出,避免影响主进程启动 + return; + } +} + globalThis.__cursor_patched__=true; // 固定的设备标识符 @@ -252,7 +269,7 @@ var __ids__={ globalThis.__cursor_ids__=__ids__; // Hook Module.prototype.require -var Module=require('module'); +var Module=__require__('module'); var _origReq=Module.prototype.require; var _hooked=new Map();