从官方 CDN 里扒出 TRAE (TraeCode) 历史版本安装包

起因

新版本升级上去之后不好用,想回退到上一个版本,结果发现 TRAE 官网只提供最新版下载,更新日志里只有版本号,没有任何历史安装包入口。

于是就有了下面这一次「从更新日志倒推到安装包直链」的折腾。最终把 3.5.97 ~ 3.5.104 这一批(更新日志 2026-09-20 那条 "TraeCode v3.5.97 ~ 3.5.104 版本正式发布")挖出来了,记录一下完整思路。

结论先行

版本 构建号 上传时间
3.5.103 2.3.87602 2026-09-20
3.5.104 2.3.88407 2026-09-22

macOS(Apple Silicon):

ruby 复制代码
https://lf-cdn.trae.ai/obj/trae-ai-sg/pkg/app/releases/stable/2.3.88407/darwin/TraeCode-darwin-arm64.dmg

macOS(Intel):

ruby 复制代码
https://lf-cdn.trae.ai/obj/trae-ai-sg/pkg/app/releases/stable/2.3.88407/darwin/TraeCode-darwin-x64.dmg

Windows x64:

ruby 复制代码
https://lf-cdn.trae.ai/obj/trae-ai-sg/pkg/app/releases/stable/2.3.88407/win32/TraeCode-Setup-x64.exe

Linux x64:

ruby 复制代码
https://lf-cdn.trae.ai/obj/trae-ai-sg/pkg/app/releases/stable/2.3.88407/linux/TraeCode-linux-x64.tar.gz

3.5.103 把路径里的 2.3.88407 换成 2.3.87602 即可,文件名不变。

一、先摸清「下载链路」

官网页面的下载按钮是 JS 动态渲染的,直接抓 HTML 拿不到链接,所以要顺着它调的接口找。

抓官网 www.trae.ai/download 的网络请求,会发现一个很关键的接口:

bash 复制代码
https://icube-normal.trae.ai/icube/api/v1/native/version/trae/latest

它直接返回当前各产品线的安装包地址,结构大致是:

json 复制代码
{
  "data": {
    "manifest": { "darwin": { "versions": [ { "url": "...stable/2.3.91093/darwin/TRAE-darwin-arm64.dmg", "version": "3.6.2" } ] } },
    "solo": { "...": "TraeWork" },
    "tob": { "win32": { "download": [ { "x64": "...stable/2.3.68993/win32/TraeCode-Setup-x64.exe" } ] } }
  }
}

两个信息点:

  1. 安装包放在 .../pkg/app/releases/stable/ 下,路径中间那串 2.3.91093 是构建号;
  2. 接口只给「最新版」,历史构建得自己找,但路径规律已经到手了。

另外 tob 那条就是企业版 / TraeCode 线,包名前缀是 TraeCode-。

二、URL 规律

ruby 复制代码
https://lf-cdn.trae.ai/obj/trae-ai-sg/pkg/app/releases/stable/<构建号>/<平台>/<文件名>
  • 平台目录:darwin / win32 / linux
  • 文件名前缀区分产品线:
    • TRAE-* → 国际版 TRAE IDE
    • TraeCode-* → 企业版 / TraeCode
    • Trae_CN-* → 国内个人版
    • TRAE_Work_CN-* → TRAE Work 国内版
  • macOS 是 -darwin-arm64.dmg / -darwin-x64.dmg,Windows 是 -Setup-x64.exe
  • 每个构建目录里只放一条产品线的包

镜像域名换掉就行,路径一致:

  • 国内:https://lf-cdn.trae.com.cn/obj/trae-com-cn/...
  • 美国:https://lf-cdn.trae.ai/obj/trae-ai-us/...
  • 美国静态:https://lf-static.traecdn.us/obj/trae-ai-tx/...

三、核心难点:构建号 ≠ 版本号

界面显示的 3.5.104 和路径里的 2.3.88407 没有任何直接换算关系。也就是说,即使把路径规律摸清楚了,你还是不知道「3.5.97 ~ 3.5.104」对应哪个构建号。

常规做法是暴力遍历:从最新构建号往下递减,HEAD 请求探测哪些目录存在。但这样只能拿到一串「存在的构建号」,依然不知道每个构建对应什么版本------除非把几百 MB 的安装包整个下下来,挂载 DMG 看 Info.plist。每个候选都下几百 MB,显然不现实。

破局点:用 HTTP Range 只下几 KB,读出包内版本号

每个构建目录里除了 .dmg / .exe,还有一份 darwin/*.zip(macOS 免安装包)。而 zip 的格式决定了:

  1. 文件尾部有 EOCD 记录,里面写着中央目录的偏移和大小;
  2. 中央目录里列出所有条目的文件名、偏移、压缩方式、压缩后大小;
  3. 条目数据可以单独按偏移取。

所以只要:

  1. 取最后 ~80 KB,找到 EOCD,读出中央目录位置;
  2. 取中央目录那一段(几十 KB),定位到 Trae.app/Contents/Info.plist;
  3. 按偏移取该条目几十 KB 的 deflate 数据,解压后读 CFBundleShortVersionString。

整个流程只需要几 KB 流量,就能确知某个构建号背后的真实版本号。探测成本从「几百 MB」降到「几 KB」,整件事就可行了。

核心代码(Python 标准库 + curl 即可):

python 复制代码
def read_version(zip_url):
    size = content_length(zip_url)
    tail = rng(zip_url, size - 80000, size - 1)
    i = tail.rfind(b"PK\x05\x06")            # EOCD
    cd_size, cd_off = struct.unpack("<II", tail[i + 12:i + 20])
    cd = rng(zip_url, cd_off, cd_off + cd_size - 1)

    # 解析中央目录,找到 Trae.app/Contents/Info.plist
    ...
    raw = rng(zip_url, data_off, data_off + comp - 1)
    data = zlib.decompress(raw, -15) if method == 8 else raw
    return re.search(r"<key>CFBundleShortVersionString</key>\s*<string>([^<]+)</string>", data)

四、实测结果

把 69000 ~ 95000 这一段全部扫了一遍(HEAD 探测 + 上面的 Range 读版本),企业版 / TraeCode 线公开的构建是:

版本号 构建号 上传时间 对应更新日志
3.5.87 2.3.68993 2026-08-12 3.5.84 ~ 3.5.92 那批
3.5.91 2.3.73738 2026-08-20 同上
3.5.103 2.3.87602 2026-09-20 3.5.97 ~ 3.5.104 那批
3.5.104 2.3.88407 2026-09-22 同上
3.6.0 2.3.88717 / 88917 / 89047 / 89097 / 89127 - 合并后的新版 TRAE
3.6.2 2.3.91093 2026-10 初 当前最新

注意 3.5.103 的上传时间 2026-09-20 13:25 GMT,和更新日志那条日期完全对上,可以确认就是同一批发布。

另外更新日志虽然写的是「3.5.97 ~ 3.5.104」,但公开 CDN 上只有 3.5.103 / 3.5.104 两个构建,中间的 3.5.97 ~ 3.5.102 没有对外发布的安装包。

验证方式:下载后挂载 DMG,读 Trae.app/Contents/Info.plist 确认版本号,并检查代码签名主体是否与现行版本一致(都是 Developer ID Application: SPRING (SG) PTE. LTD. (79M8227NKH)),确认是官方包。

五、几个坑

  1. 并发别开太高。一开始用 50+ 并发跑 Range 请求,被 Akamai 挡了,返回的是一个 HTML 错误页而不是 404 或 403,脚本会误判。降到 20 ~ 24 并发就稳定了。
  2. 探测用 HEAD 而不是带 Range 的 GET。HEAD 便宜,不容易触发源站,实测 6000 个探测点 2 分多钟跑完。
  3. 偶发 000(连接失败)。网络抖动导致,不是包不存在,脚本里要做重试,Range 请求要校验返回长度是否等于请求长度。
  4. 构建目录不通用 。一个构建目录只放一条产品线的包,不要拿 TRAE-* 的名字去试 TraeCode 的构建号。
  5. 第三方资料大多停更。网上能找到的整理(GitHub issue、Gitee 归档仓库)基本只覆盖到几个月前,而且大多只给构建号不给版本号,最新的还是得自己扫。

六、装了老版本,怎么防止又被自动升级

  1. 装完之后先断网再打开 Trae;
  2. 设置里搜「更新」,把 Update: Mode 改成 manual,取消勾选 Update: Show Release Notes:
json 复制代码
{
  "update.mode": "manual",
  "update.showReleaseNotes": false
}
  1. 更彻底一点,在 hosts 里屏蔽更新域名(要下载新包时再把这几行注释掉):
css 复制代码
0.0.0.0 icube-normal.trae.ai
0.0.0.0 lf-cdn.trae.ai
0.0.0.0 api.trae.ai

注意 hosts 拦截之后,官网和 CDN 也一起下不了包了,需要先注释掉再下载。

七、一点总结

整个思路其实就是三步:

  1. 找接口:官网页面是动态渲染的,抓它调的接口,拿到「最新版」的完整下载地址,反推出 URL 规律;
  2. 降成本:暴力遍历只能拿到构建号,用 zip 中央目录 + HTTP Range 只取几 KB,就能把「构建号 → 版本号」的映射补上;
  3. 做映射:扫描 + 读版本 + 和更新日志的日期对齐,确认哪一批对应哪个构建。

这套方法不限于 TRAE,凡是「electron 应用 + 对象存储分发 + 只有最新版入口」的软件基本都能套用,关键就是找到那个可以被 Range 请求精确切片的容器格式(zip / dmg / exe 里的元数据)。

希望官方以后能把历史版本入口做出来,就不用这么折腾了 🙃

相关推荐
tianyuanwo1 小时前
Python 属性查找陷阱:从 `AttributeError: ‘X‘ object has no attribute ‘_children‘` 说起
python
程序猿阿森1 小时前
混合精度详解:FP16 vs BF16,Loss Scaling 与 PyTorch 实战
人工智能·pytorch·python
benchmark_cc1 小时前
A股、港股、美股日K如何拼接?处理不同交易日造成的时间轴错位
大数据·python·pandas·量化交易·股票数据·quantdash
龙腾-虎跃1 小时前
AI-Vue3-python-flask-Blog 全栈博客项目深度解析:从零搭建你的 AI 博客
人工智能·python·flask
余槐i1 小时前
无慢查询 RT 却飙升:cProfile 定位 FastAPI 事件循环阻塞
后端·python·性能优化·fastapi·asyncio
Xiu Yan2 小时前
Python 数据分析:数据分析步骤
开发语言·python·数据分析
vilya2 小时前
把 Python 塞进 APK:Chaquopy 打包实践
android·python
黑妹天下第一乖2 小时前
小智改造实战解读-用kokoro-onnx替换云端 TTS 的完整记录
大数据·开发语言·人工智能·python·交互
papaofdoudou2 小时前
从抽象群到可计算的矩阵:S₃ 的表示论与共轭视角
python·决策树·矩阵