Cursor 突然找不到 Claude 模型?一招搞定!
最近几天,很多 Cursor 用户(尤其是 Team 账号)发现模型列表里突然少了一大半,Opus 5.5、Sonnet 5.5 等 Claude 模型全都不见了。
原因其实很简单:Cursor 桌面版请求时,默认把客户端身份标记成了 ide,导致官方后台直接隐藏了 Claude 系列。只要把身份“伪装”成 desktop 就能解决!
原作者写了一个 Python 脚本,只需三步就能一键修复。
🚀 极简解决步骤:
第一步:彻底关闭 Cursor
记得检查一下电脑右下角/右上角的系统托盘,确保完全退出程序。
第二步:运行修复脚本
下载作者的 apply.py 脚本,在终端(命令行)里运行:
点击查看 apply.py 脚本
#!/usr/bin/env python3
"""把 Cursor IDE 的模型目录身份从 glass/ide 改成 desktop。
desktop 和 cli 拿到的模型目录相同,包含 Opus / Sonnet。
glass 和 ide 的目录里没有 Claude。
只改两类位置:
1. header.set("x-cursor-client-type", <变量>??"ide")
改成 header.set("x-cursor-client-type","desktop")
2. clientIdentity:{clientType:"ide"}
改成 clientIdentity:{clientType:"desktop"}
不改 main.js 里登录用的 "x-cursor-client-type":"ide"。
用法:
先完全退出 Cursor,再执行。
python3 apply.py # 自动找安装目录,先预览
python3 apply.py --apply # 真正写入
python3 apply.py --apply /path/to/resources/app
sudo python3 apply.py --apply # Linux 系统目录需要 root
python3 apply.py --revert --apply
"""
from __future__ import annotations
import argparse
import re
import sys
from pathlib import Path
HEADER_RE = re.compile(
r'header\.set\("x-cursor-client-type",(?P<expr>[A-Za-z_$][\w$]*\?\?"ide"|\"desktop\")\)'
)
HEADER_NEW = 'header.set("x-cursor-client-type","desktop")'
IDENTITY_OLD = 'clientIdentity:{clientType:"ide"}'
IDENTITY_NEW = 'clientIdentity:{clientType:"desktop"}'
RELATIVE_FILES = [
"out/vs/workbench/workbench.glass.main.js",
"out/vs/workbench/workbench.desktop.main.js",
"out/vs/workbench/api/node/extensionHostProcess.js",
"out/vs/workbench/api/worker/extensionHostWorkerMain.js",
"extensions/cursor-agent-host/dist/main.js",
]
def candidate_apps() -> list[Path]:
home = Path.home()
found: list[Path] = []
roots = [
Path("/usr/share/cursor/resources/app"),
Path("/usr/lib/cursor/resources/app"),
Path("/opt/Cursor/resources/app"),
Path("/opt/cursor/resources/app"),
home / ".local/share/cursor/resources/app",
Path("/Applications/Cursor.app/Contents/Resources/app"),
home / "Applications/Cursor.app/Contents/Resources/app",
Path.home() / "AppData/Local/Programs/cursor/resources/app",
Path.home() / "AppData/Local/cursor/resources/app",
]
local = Path.home() / "AppData/Local"
if local.is_dir():
roots.append(local / "Programs/cursor/resources/app")
for root in roots:
if (root / "out/vs/workbench").is_dir():
found.append(root)
return found
def cache_dirs() -> list[Path]:
home = Path.home()
dirs = [
home / ".config/Cursor/CachedData",
home / "Library/Application Support/Cursor/CachedData",
home / "AppData/Roaming/Cursor/CachedData",
]
return [d for d in dirs if d.is_dir()]
def transform(text: str, revert: bool) -> tuple[str, list[str]]:
notes: list[str] = []
def header_sub(match: re.Match[str]) -> str:
expr = match.group("expr")
if revert:
if expr == '"desktop"':
notes.append("header desktop -> <var>??\"ide\" 无法自动还原变量名,跳过;请用 .bak 文件")
return match.group(0)
notes.append("header 已是原样")
return match.group(0)
if expr == '"desktop"':
notes.append("header 已经是 desktop")
return match.group(0)
notes.append(f"header {expr} -> \"desktop\"")
return HEADER_NEW
new_text, header_count = HEADER_RE.subn(header_sub, text)
if header_count == 0 and '??"ide"' in text:
notes.append('文件里还有 ??"ide",但没匹配到 header.set,需要手工看')
if revert:
count = new_text.count(IDENTITY_NEW)
if count:
new_text = new_text.replace(IDENTITY_NEW, IDENTITY_OLD)
notes.append(f"clientIdentity desktop -> ide x{count}")
elif IDENTITY_OLD in new_text:
notes.append("clientIdentity 已是 ide")
else:
count = new_text.count(IDENTITY_OLD)
if count:
new_text = new_text.replace(IDENTITY_OLD, IDENTITY_NEW)
notes.append(f"clientIdentity ide -> desktop x{count}")
elif IDENTITY_NEW in new_text:
notes.append("clientIdentity 已经是 desktop")
return new_text, notes
def backup(path: Path) -> Path:
bak = path.with_name(path.name + ".bak-before-desktop-identity")
if not bak.exists():
bak.write_bytes(path.read_bytes())
return bak
def clear_cache() -> None:
for cache in cache_dirs():
for child in cache.iterdir():
if child.is_dir():
for sub in child.rglob("*"):
if sub.is_file():
sub.unlink()
for sub in sorted(child.rglob("*"), reverse=True):
if sub.is_dir():
sub.rmdir()
child.rmdir()
print(f"cleared {child}")
def main() -> int:
parser = argparse.ArgumentParser()
parser.add_argument("app", nargs="?", help="Cursor 的 resources/app 目录")
parser.add_argument("--apply", action="store_true", help="写入文件。不加这个参数只预览")
parser.add_argument("--revert", action="store_true", help="用备份还原;没有备份时只能还原 clientIdentity")
parser.add_argument("--clear-cache", action="store_true", help="删掉 CachedData,避免沿用旧字节码")
args = parser.parse_args()
if args.app:
apps = [Path(args.app)]
else:
apps = candidate_apps()
if not apps:
print("没找到 Cursor 安装目录。请传入 resources/app 的路径。", file=sys.stderr)
return 1
for app in apps:
print(f"app {app}")
for rel in RELATIVE_FILES:
path = app / rel
if not path.is_file():
print(f" skip 缺少 {rel}")
continue
original = path.read_text(encoding="utf-8", errors="replace")
if args.revert:
bak = path.with_name(path.name + ".bak-before-desktop-identity")
if bak.is_file():
print(f" revert {rel} <- {bak.name}")
if args.apply:
path.write_bytes(bak.read_bytes())
continue
updated, notes = transform(original, revert=args.revert)
print(f" {rel}")
for note in notes:
print(f" {note}")
if updated == original:
continue
if not args.apply:
print(" 预览,未写入")
continue
bak = backup(path)
path.write_text(updated, encoding="utf-8")
print(f" 已写入,备份 {bak.name}")
if args.apply and args.clear_cache:
clear_cache()
elif args.apply:
print("下次启动前可以再跑一次并加上 --clear-cache,或者手动删掉 Cursor 的 CachedData。")
else:
print("这是预览。确认后加上 --apply。Linux 系统目录要加 sudo。")
return 0
if __name__ == "__main__":
raise SystemExit(main())
python3 apply.py --apply
(注:如果是 Linux 系统目录,前面加 sudo;Windows 如果没自动识别路径,可在命令后加上你的 resources/app 路径)
第三步:重新打开 Cursor
重启后,去模型列表看看,Opus 5.5 是不是已经回来了?
⚠️ 温馨提示:
- 会失效:每次 Cursor 官方更新后,这个修改会被覆盖。如果 Claude 又没了,重新跑一遍上面的脚本就行。
- 想还原:运行
python3 apply.py --revert --apply即可恢复原版。
如果你也遇到了同样的问题,赶紧去试试吧!
本文来自博客园,作者:流年灬似氺,转载请注明原文链接:https://www.cnblogs.com/lic0914/p/23469569

浙公网安备 33010602011771号