dsh-connect-trae
Verifieddsh-connect-trae · v4.4.1 · MIT · Web UI
把本机登录的 Trae 模型接入 DeepSeek Harness:国内版与国际版双供应商并行,提供用量/积分概览与每日签到领取。
Install
dsh plugin add dsh-connect-trae Confirm the layer applied with dsh --profile default --dump-config — see the install guide.
Source
Tags
Readme
dsh-connect-trae
把本机登录的 Trae 模型接入 DeepSeek Harness,并提供用量/积分概览与每日签到领取。
English · 安装 · 工作原理 · 模型覆盖范围 · 更新日志 · 问题反馈
一个独立的 DeepSeek Harness (DSH) bundle 插件。它把本机已登录的 Trae 账号(国内版、企业版与国际版均支持)接到 DSH 的模型选择器:模型负责生成结构化工具调用,bash / read / write / edit 等工具由 DSH 本地执行;同时提供用量概览(国内版 Work/通用积分、企业版租户额度、国际版订阅状态)、每日签到领取与模型管理界面。国内版、企业版与国际版是三个并行的供应商(trae / trae-enterprise / trae-global),可同时使用;插件设置卡片以 tab 区分三者,方便统一管理。
支持 macOS、Windows 与 Linux:CI 在 ubuntu-latest 与 windows-latest 上跑完整 typecheck / 测试 / 构建;Windows 侧的目录探测、应用版本头与锁行为均有针对性处理,详见 Windows 说明。
除每日签到领取外,插件的所有查询都是只读的、不消耗额度;签到领取也只在你点击按钮时才发生。
功能特性
三供应商并行接入 —— 国内版注册为 DSH 的
traeprovider(DeepSeek-V4-Flash、DeepSeek-V4-Pro等),企业版注册为trae-enterprise,国际版注册为trae-global(Gemini / GPT / MiniMax 阵容),三边模型同时出现在 DSH 模型选择器里:不同会话可以各选一边,互不干扰。企业版是独立计费通道,不是国内版的别名 —— 同一张 CN 凭据若属于
tob_online租户,会被两个网关同时服务:消费池(扣个人积分)与租户池(扣企业额度)。同一模型、两种付费方,所以「谁付钱」由你显式选,插件不替你猜。trae永不碰企业网关;trae-enterprise不回落,被拒绝就如实报错,不会悄悄改用个人额度重跑。企业版默认关闭——纯个人账号用不了企业池,默认放开等于塞一条一用就失败的 provider。可单独关闭任一面板 —— 三个 tab 各带一个勾选(国内版与国际版默认勾选,企业版默认不勾):取消勾选即把该面板的供应商整个从 DSH 模型选择器撤掉(不是只藏起 tab),并且不再发起任何请求;重新勾选即恢复,账号、目录、勾选与上下文预算全部保留。用不到国际版就把国际版关掉即可。
插件卡片 tab 切换 —— 设置卡片顶部为「国内版 / 企业版 / 国际版」三个 tab,各含独立的账号选择、用量概览与模型管理;每个 tab 的账号、目录、勾选与未保存草稿完全隔离——在一个 tab 里切账号或刷新模型,不会触碰另一边的运行时目录与会话。国内版与企业版共用同一份 CN 凭据池,但各有各的账号绑定与模型勾选:两个池的名录并不相同(
DeepSeek-V4.1-Flash只有企业池列),所以勾选互不覆盖。卡片内再按「账号 / 模型 / 诊断」分栏(学自同族
dsh-connect-workbuddy)—— 上面那排地区是作用域(这张卡片讲的是哪个供应商),这一排是同一张卡片里的分栏:账号栏管「谁在服务、还剩多少、签到与账号池」,模型栏管「勾哪些模型、图片输入、上下文预算、保存」,诊断栏只读地列出面板名、供应商 id、服务账号、两种令牌到期时间、目录/已启用模型数、账号池与签到支持与否,以及本面板最近一次报错的原文。分栏的理由是提交语义不同:账号改动点一下即生效,模型改动是草稿、必须点「保存」——一列长页会把保存按钮放到离它要保存的东西三屏之外。切栏不重新拉取、不丢未保存的模型草稿、账号池日志也不重建;未登录时不出分栏,那一屏说明不会被看不见的 tab 藏起来。模型栏把所有模型一次性铺开,没有内层滚动条——不再是一个套在滚动页面里的小窗口,唯一滚动的就是卡片自己那一页。账号池:自动选号 + 失败换号(默认关闭) —— 本机读完几个账号后,「该用谁的额度」可以交给插件按规则排序:先排除不可用的(凭据被拒、套餐不覆盖、账号已不存在、限流未到重试时间、额度耗尽),再在可用账号里优先快到期的那点额度(与其放着过期,不如先花掉),最后才比总额、token 新鲜度,并以账号 id 兜底成全序(同样的输入永远得到同样的顺序,不会在两行之间来回抖)。三个面板各有各的池:国内版与企业版共用同一份 CN 凭据,但企业版只挑租户账号、国内版不会漂到租户号上。开着池时,发请求前先按上面的顺序选中一个账号,并且真实请求失败会换下一个账号重试(最多 3 个)——只有账号级失败才换(
401凭据被拒、额度耗尽、限流、上游 5xx);模型 id 写错、请求本身不合法不换号,因为那不是账号的问题,换号只会把同一个错误烧两遍、还冤枉一个没机会服务的账号。换号失败的真相会写进池的探针记录,下一次排序直接把它排到后面,而每一次结论都能在卡片上看到:可用/限流/额度耗尽/凭据被拒/套餐不覆盖/上游不提供/本次未测出,以及「什么时候可以重试」。关掉池就回到严格绑定,不会有任何残留 override。卡片里的「全部测速」会把每个成员按目标模型各测一次,结果边跑边显示(一行一个答案,不等整批跑完),并落盘成下次排序的依据。池是显式选择:默认关闭。它不会替你在没打开池的情况下换账号——「换账号等于换人计费」,所以这件事只能由你点头。池打开后卡片会明确写出当前是谁在付费(Host 报告的是「下一个真正发送请求的账号」,不是保存的那个绑定)。
倍率内嵌模型名 —— 模型名称按 Trae 自身菜单的格式显示积分倍率(如
GLM-5.2 · x0.79),倍率随目录刷新更新。活动优惠徽标 —— Trae 把促销规则发在目录里(
activity_discount:折扣比例、原价、闲时时段与时区),插件按当前时钟判定后,在模型名旁边画一枚胶囊:5 折/闲时 5 折/限时 5 折,悬停写明原价、现价与时段。判定放在渲染时刻而不是解析时刻,所以夜间折扣不会在第二天早上继续挂着;上游说「此刻没打折」就不画,不从倍率反推,也不给没有结束时间的活动编「限时」。这是纯提示:不改请求、不改计费,国际区(订阅制)没有这项数据因此不显示。详见 docs/PROMO_BADGE.md。DSH 本地工具循环 —— 通过 Trae
llm_utils_chat获取待执行的结构化tool_calls,交由 DSH 自带的本地工具执行,再将工具结果回传模型。国内国际双区域自动识别 —— 自动发现 Trae CN / TRAE SOLO CN / Trae / TRAE SOLO 四个本地安装的登录账号;区域由凭证自带的
userRegion声明自动判定(host 后缀与 edition 标签兜底),无需手动指定。目录与勾选按面板隔离 —— 三个面板各一套模型目录、勾选、图片开关与上下文预算,各自读各自的槽位。名录从该面板所钉的那条网关读取——原本钉在企业池的客户端去读消费池名录,会永远发现不了自己池的独占模型。
识图能力跟随 Trae 自身的标注 —— Trae 把某个模型标为
multimodal时,插件直接按多模态对外声明,无需你在卡片上逐一手勾(issue #16)。判据是「你手动勾选的 ∪ Trae 标注多模态的」:Trae 明确标false或未标注的模型保持纯文本,你可以照旧手动为它们打开图片输入。卡片上被自动开启的那一行显示为已勾选且只读,并说明原因。详见下方「图片输入(识图)」。多账号切换 —— 支持重新读取 Token 列表并选择账号;Token 不写入 DSH 设置。你的选择会被记住并长期生效:插件不会因为某个账号额度用尽、或检测到另一个可用账号就自作主张替你切换(换账号意味着换人计费)——唯一的例外是你亲自打开的账号池(见下一条),那是一个显式选择,而不是插件的自作主张。所以当绑定的账号额度耗尽时,卡片会明确告诉你,并把本机其他还有额度的账号连同其可用积分数列出来,由你一键切换——而不是让面板一直空着、也不自动把你切走。「刷新账号与 Token」每次都会回报结果(找到几个账号、当前仍绑定谁),不会再「点了没反应」。下拉里显示的是产品名(
Trae/TRAE SOLO/ 国际版),便于分辨凭据来自哪个安装。账号导入 / 导出 —— 不用再为了用第二个账号而把凭据手工写进默认路径、顶掉上一个。在卡片账号区的「导入 / 导出账号」里:导出勾选若干账号下载一份 JSON;导入选择文件后先看脱敏预览(只显示账号标识与「是否有 Token」,不含凭据本身)再勾选导入。文件格式与同族
dsh-connect-workbuddy互通,两边导出的文件可以互相导入。导入按账号去重(同一账号再导入即覆盖更新),认不出所属区域或因缺 Token 的记录会被跳过并计数——国内版与国际版是两条并行计费通道,跨区导入会导致跨区计费,所以这里只认同能正向识别的区域(企业版共用 CN 凭据池,不构成第三条导入通道)。导出文件里是有效 Token,请当作密码保管。(issue #37)只读用量与模型管理 —— 国内版查看 Work 积分与通用积分,国际版查看订阅/试用状态;刷新/启用 Trae 模型;只读查询不消耗额度。
积分临近到期会提醒 —— 剩余额度只回答「还有多少」,回答不了「哪一笔先到期」;提醒条按到期紧迫程度逐级加重(7 天 → 24 小时 → 已过期),写明金额、套餐数和最早到期时间,避免只盯总额时悄悄丢掉最先到期的额度。国内版在用量页与输入框积分面板两处都显示(国际版是订阅制,没有逐包到期数据)。
一键测试启用模型 —— 给已启用的每个模型发一条最小消息(一句
ping、不带工具),逐个告诉你能不能真的应答:可用 / 需要更高档位(Trae1005,你的套餐不覆盖)/ 上游不提供(4001,SOLO 通道没有这个模型)/ 被限流(4011,Trae 限了这条通道)/ 登录凭据被拒 / 本次未测出。最后一项是一等公民:超时、断连、代理、5xx 一律不算「不可用」——只有上游明确的拒绝才算负面结论。这是插件里唯一消耗额度的操作(签到改变的是账号状态,不消耗),只在你点击时运行,结果只留在当前会话里不写入设置。4011是限流不是「模型不可用」(issue #33 实测):它额度耗尽走的是另一个码4008,所以「额度还有很多却报 4011」两句话可以同时成立。被限流的模型等你一会儿再试即可,不要删。一键测试所有模型 —— 同一套探测,作用于当前 region 的全部可见模型(不限于已启用的)。想知道「没启用的那些到底还能不能用」时用它——比如套餐降级后,或 Trae 调整了模型阵容之后。
每日签到领取(逐账号) —— 国内版每个账号行各有一个签到按钮,当日奖励直接写在按钮上(
签到 +150);该账号当天已领显示「已领取」并禁用,本机今日名额已被别的账号用掉时显示「本机已签」并禁用——如实区分「这个账号领了」和「这台设备领过了」,绝不把后者说成「已领取」。这是插件里唯一会改变账号状态的操作,由你主动点击触发;一次点击只针对该行账号、只发一次请求。Trae 的签到按「每台设备每天一次」计(换账号不会重置当天名额),所以逐账号签到始终是主路径。账号池里另有一个「全部签到」,它不是把同一件事盲目重复:一旦上游回9095(本机今日已领),整批立刻停止并把剩余账号如实标成「本机已签」,产出的是真相而不是一排假失败。国际版没有签到活动,因此不显示该按钮。输入框读数 —— 在输入框工具栏(「专家」与模型选择器之间)显示一块可点击读数,5 分钟自动刷新。两个区域都显示,但显示的东西不同,这是数据决定的:国内版是积分制,显示「Trae CN · <通用积分>」;国际版是订阅制,它的用量文档里根本没有积分字段,所以显示「Trae 国际版 · <套餐>」(如
Pro/Free)。整块可点击,弹出浮层显示一张表格:本区域每个账号一行,国内版列通用积分、国际版列套餐,点行即可切换账号(写入与卡片相同的accounts字段、合并时不丢掉另一个区域的选择),并把手动刷新按钮放在浮层里。只在当前会话选中的模型属于本插件时出现——选其它供应商的模型时整块不渲染。这样两个连接器插件不会争同一个位置(侧边栏底部是共享的根级行,输入框工具栏是按会话、按供应商的)。
读数显示在哪里可以选(学自同族
dsh-connect-workbuddyissue #62)。默认在输入框工具栏(即上面说的位置);如果那里被别的插件占了、读数不显示,改成输入框下方——那是「轮次 / 步数 / token」统计所在的那一行,读数是追加在官方统计之后,不会顶掉它们。位置按面板分别设置(三个面板各存各的),在卡片「设置」区紧挨「在输入框工具栏显示积分读数」那个勾选框。之所以要有第二个位置:输入框工具栏是共享的 list 插槽,外壳自己的控件和其他插件都注册在那里,而共享插槽无法保证每个占用者都可见——同族的报告者装了第三方插件后读数就整个消失了(本插件早年放在侧边栏底部时也被挤成过一个「Tr」的残片)。安全 loopback shim —— 每区域一个随机端口 + 进程内随机 secret,真实 Trae token 不交给 pi-ai。
工作原理
DSH PiAiAdapter(每个 provider 一套)
-> 安全 loopback shim(每区域一个随机端口 + 进程内随机 secret)
-> TraeSoloBridge
-> 国内版 https://trae-api-cn.mchost.guru/api/agent/v3/llm_utils_chat
-> 企业版 https://console.enterprise.trae.cn/api/agent/v3/llm_utils_chat
-> 国际版 https://coresg-normal.trae.ai/api/agent/v3/llm_utils_chat
-> Trae SSE / pending function_call
-> OpenAI SSE tool_calls
-> DSH 本地执行工具并回传结果
每个面板各持一套完整的运行时栈——凭据 store、模型 catalog、wire 映射、上游客户端、回环 shim、adapter——按凭证自带的区域声明隔离可见账号,所以多个区域的账号可以同时在线、同时被不同会话使用。
面板不是区域。 cn 与 ai 恰好与两个区域一一对应,但企业池共用 cn 凭据却计费到另一个账户、供另一份名录,它需要自己的开关、自己的账号绑定与自己的模型选择——那正是「面板」这个概念。把面板与区域分成两个概念,enterprise 就能用同一套设置管道处理,存储形状不变:它只是 regions 映射里的又一个槽位。
国内区因此并列发布两个 provider,路由在构建 provider 的客户端时固定,不存在「按调用猜一次」:shim 为每个 provider 提供一条 bearer 路由并按 bearer 分派,未知 token 直接 401,不会退回第一条路由。企业网关要求每次调用带 session_id,而消费网关会拒绝带它的请求体,所以只在该路由上加。
用量概览走 https://api.trae.cn/trae/api/v2/pay/* 与 /trae/api/v2/ug/* 只读接口(国际账号走其自有网关的订阅状态端点);每日签到领取是其中唯一的写操作,走 POST /trae/api/v2/ug/checkin_credits/claim,需要携带本机安装的设备号(x-device-id,与聊天通道同源)。该设备号也正是签到「每台设备每天一次」的判定依据,所以换账号不会重置当天名额。刷新得到的 token 按区域存放在 $DSH_HOME/.trae-auth.cn.json 与 $DSH_HOME/.trae-auth.ai.json(两个账号同时在线互不覆盖;旧的单文件 .trae-auth.json 作为迁移来源保留读取)。
详见
docs/IMPLEMENTATION_PLAN.md、docs/SOLO_ROUTE_DECISION.md、docs/USAGE_API_RESEARCH.md。
图片输入(识图)
插件对外声明「这个模型是否接受图片」,DSH 据此决定附图是原样发出还是降级成文字描述。所以这条声明是硬开关,不是一个无关紧要的标记。
判据是两个来源的并集(issue #16):
| 来源 | 含义 |
|---|---|
Trae 目录自带的 multimodal 字段 |
Trae 自己对「这模型读不读图」的回答。Trae IDE 本体的附图按钮就是纯粹由这个字段驱动的,没有用户开关 |
你在卡片上手动勾选的 imageModelIds |
显式选择。即便 Trae 后来不再标注该模型,你的勾选也不会被撤掉 |
要点:
- 只有
multimodal === true才自动开启。 字段缺失(旧版本保存的目录、兜底目录)或明确false,都按纯文本处理——宁可不发,也不对一个能力不确定的模型谎报「支持图片」。 - 自动开启并不等于自动发图。 它只是让 DSH 允许你给该模型附图;图片始终由你在对话里自己贴,插件不会替你发送任何东西。
- 被自动开启的行在卡片上显示为已勾选且只读。 因为并集语义下取消勾选会被立刻重新加上,给它一个可点的框是在撒谎。目前不为单个模型提供「强制关闭」的出口;如果你需要这个开关,可以在 issue #16 下提出。
- 手动勾选对 Trae 标注
false(或未标注)的模型依然有效,这是为那些「上游没标但实际可用」的情况留的口子。
模型覆盖范围
插件提供的是 Trae SOLO 通道的模型(DeepSeek-V4-Flash-Official、DeepSeek-V4-Pro-Official、GLM-5.3、GLM-5.2、Kimi-K3、MiniMax-M3、Qwen3.8-Max、Doubao-Seed-* 等),三个面板均走这条通道。企业池另有一份名录(例如 DeepSeek-V4.1-Flash 只有企业池列),所以两边勾选互不覆盖。
以下 2 个模型目前来自 TraeCode(Trae IDE)通道,尚未开放到 SOLO 通道:
| 模型 |
|---|
kimi-k2.8-preview |
qwen3.8-flash |
它们会出现在模型列表里(Trae 的目录列出了它们),但插件侧暂时没有可调用它们的通道。选中后发送消息会得到一条明确的错误,例如:
Trae does not serve this model under the SOLO function the request used
(config_name rejected) · Trae code 4001 · upstream: We're sorry, the param is invalid…
即「上游不提供该模型」被如实说明,而不是静默失败或像网络故障。官方把它们开放到 SOLO 通道后,插件会自动可用(判据就是能不能拿到调用 id),无需升级插件。
同一条报错的另一种成因(3.5.1 已修,issue #38):
DeepSeek-V4四行曾报同样的 4001,但成因相反 —— 它们在上游名单里本来可以调用,只是 CN 区的 wire 把同一族列了三行且共享展示名,旧代码让最后一行 (元数据残缺的小写行deepseek-v4-flash)抢走了展示名键,桥接层据此把config_name改写成小写拼写, 上游拒收。判别方法:看这个模型在上游名单里有没有调用 id —— 有而报 4001,就是这一类。 3.5.1 起两张映射表都改为先到先得,不再发生改写,四行已实测恢复正常。
为什么现在会显示(2026-10-02 起的策略):此前这类「目录里有、但拿不到调用 id」的模型会被直接隐藏,理由是「放出来只会报错」。但可调用名单是按账号档位下发的——在免费账号上测不到,不等于付费账号用不了(issue #19 的报告人就是 Pro:他的账号能调用本机免费账号被门禁挡住的模型)。隐藏用户自己 Trae IDE 里有的模型,比让他看到一条明确的错误更糟,所以改为:全部呈现 + 如实报错。
deepseek-v4.1-flash曾在此列——docs/DS41_CALLABILITY.md(2026-09-15 取证)实测 8 个 SOLO function 全部返回4001 param is invalid。上游后来把它开放到了 SOLO 通道:当前实时目录里它带wireFunction: solo_work_remote,可正常调用(已实测刷新确认)。文档此前未同步,现已从表中移除。
glm-5.3-flash同样曾在此列,4.4.0 起已移除:上游后来开放了它,当前实时 wire 名单里它带wireFunction: solo_work_remote(实测)。目录侧那一行一直都在——它此前被列出来的原因是 Remote 目录列出了它而 wire 名单没有,于是既拿不到调用 id、也从未进入可调用名单; 4.4.0 修好了「wire 有而目录没有」与「目录问了但没问全」两处之后,它作为普通可调用模型出现。
注意区分:
GLM-5.3是支持的(走 SOLO 通道)。glm-5.3-flash现在也支持了—— 它与GLM-5.3始终是两个不同的模型,但前者已开放到 SOLO 通道。
如果你现在就要用这 3 个模型,请直接在 Trae IDE 本体中使用。
最大输出与上下文预算
模型卡上的「最大输出」来自 Trae get_detail_param 的 model_detail_list[].max_tokens —— 上游是发布这个值的(CN 实测 80/80 config 都带)。4.0.1 起它随目录合并一路带到卡片、/models/refresh 与 DSH 模型注册;此前合并层漏传了这个字段,整区模型全部显示空白(issue #42,诊断见 docs/ISSUE42_DIAGNOSIS.md)。仍然空白的行是诚实的:目录里有、但 SOLO 名单里没有对应 config 的模型(上面那 3 个 TraeCode 通道行)拿不到任何候选值,宁可空白也不编一个上限。这个值是元数据,插件不把它写进请求体(输出上限由 Trae 服务端决定)。
上下文窗口在 Trae 公布的默认(dev)档与 Max 档之间二选一,按面板逐模型存成 contextBudgets。想整区一次切换:模型管理区有「整区切到 Max」(给每个带 Max 档的行写入其 maxContextWindow,没有 Max 档的行不动)和「全部恢复默认上下文」(清空本区预算)两个按钮,作用在草稿上、按「保存」生效,与逐行单选落盘的结果完全一致(issue #42 附带需求——CN 有 18 个 Max 模型,以前要点 18 次)。
安装
推荐使用 DSH 插件命令安装 npm 已发布版本:
dsh plugin --profile desktop add dsh-connect-trae
或直接通过 npm 安装:
npm install dsh-connect-trae
安装、更新或卸载 bundle 后,需要重启对应的 DSH 进程。
DSH 版本兼容
要求 DSH 0.1.7-rc.1 及以上(2.3.0 起不再支持 0.1.7 之前的宿主;peer 依赖范围已按此收窄)。
peer 上界为 <0.3.0-0:0.1.7 与 0.2 两条线均受支持(含 0.2.1-rc.2,已实测)。
同时支持 pi-ai 的两代上下文(3.4.2 起)
DSH 自己横跨 @earendil-works/pi-ai 的两代,而本插件解析到哪一代由你的安装环境决定,
未必是宿主那一代——插件声明它是 peer,这是对的,但两代对「上下文长什么样」的定义不同:
| 旧代(≤0.85) | 新代(0.86+) | |
|---|---|---|
| 形状 | { systemPrompt, tools, messages } |
{ messages: [ {role:'system', content, toolsAdded}, … ] } |
| 系统提示 | 顶层 systemPrompt |
只挂在那条 system 消息上 |
| 工具声明 | 顶层 tools |
只挂在那条 system 消息的 toolsAdded 上 |
错配两个方向都会坏,所以 3.4.2 起插件会按自己解析到的那一代双向适配(issue #27):
- 新宿主 + 旧库:必崩——旧代的 token 估算没有
role === 'system'分支,会去迭代一个字符串并抛Cannot read properties of undefined (reading 'length')。这一步在请求构造之前,所以表现为 「任意模型都崩、耗时极短、usage 恒为 0」。 - 旧宿主 + 新库:不崩,但现代 api 只读那条 system 消息,顶层字段被静默忽略——系统提示与 全部工具声明丢失(模型永远不会产生 toolCall)。这类故障更隐蔽,同样已修。
代际判据是本插件自己解析到的那份包(读它的 manifest 版本;读不到时看包布局),
不是宿主版本——因为嵌套的旧副本会盖过宿主的新副本,反之亦然。启动时日志里会有一行
dsh-connect-trae: pi-ai <版本> (<代数>),legacy 表示你这份安装解析到了 ≤0.85 的旧代。
分界线是 0.86:dist/utils/transcript.js、normalizeContext、估算器的 system 分支、
以及「不再读顶层字段」这四件事同时出现在 0.86.0。按 0.87 划分会把 0.86.x 误判成旧代而错误折返,
反而丢掉提示与工具。
0.2.0 线对本插件没有契约破坏——逐符号核对确认插件消费的 API 全部未变(完整的 0.2.0-rc.1 影响面核对)。但 0.1.7 起 DSH 有一道bundle 级 peer 门禁: peer 范围不满足的 bundle 会被整体跳过,只往 stderr 写一行,界面上表现为「插件凭空消失」。
DSH 0.2.1 线(pi-ai 1.1.0)同步结论
宿主 0.2.1-rc.1 把 @earendil-works/pi-ai 从 ^0.85.1 抬到了 ^1.1.0(0.2.1-rc.2 保持不变),这是 0.2 线里
唯一有实际行为影响的变化。三项结论:
- 请求体没有丢东西(已实测)。1.1.0 的 api 只读 transcript 里的 system 消息,
顶层
systemPrompt/tools完全不再读取;而dsh-llm-pi-ai的piContext()仍然产出 旧版信封。本插件 3.4.2 起就有的双向适配正好覆盖这一点——把真实宿主信封喂进真实1.1.0+ 本地 SSE 捕获线上请求体,得到roles: ["system","user"]、system 文本完好、tools: 1;去掉适配则变成roles: ["user"]、systemnull、tools: 0(不报错)。 这条对照已固化为tests/pi-ai-context.spec.ts的线上请求体矩阵。 - 类型面补齐。1.1.0 把
ProviderStreams的第二参改成带unique symbol品牌标记的TranscriptContext,只有normalizeContext()能产出。适配层在这条边界上做一次显式转型 (src/adapter.ts的withContextAdaptation),并在两处调用点写明为何品牌在此处不可诚实获得。 - peer 范围无需改动。DSH 用
semver.satisfies(runtime, range, { includePrerelease: true })求值,且只校验@deepseek-ai/dsh*命名空间,因此>=0.1.7-rc.1 <0.3.0-0对0.2.1-rc.1/0.2.1-rc.2均已判通过 (已实测)。注意:预发布悬崖只在默认选项下成立——那是dsh-connect-workbuddy侧 调研文档所描述的困境,本插件不适用。
开发树的 @earendil-works/pi-ai 钉在 1.1.0(宿主实际随包的版本)而非 ^1.1.0,
使本地 typecheck 与测试跑在与用户完全一致的契约上;schemastery 的 override 同步抬到
3.18.5([email protected] 声明 ~3.18.5)。
peer 上界为什么不写 <0.2.0
2.3.1 曾写 <0.2.0-0,意图是「先不支持 0.2.0 正式版」。这个写法是错的:
SemVer 里 0.2.0-rc.1 < 0.2.0-0,于是它把整个 0.2.0 预发布线也一并排除,
用户装上第一个 0.2.0 预发布版后插件立即整体失效(2.3.1 的实际故障)。
| 写法 | 0.1.7 线 | 0.2.0 alpha/rc | 0.2.0 正式 | 0.3.0 |
|---|---|---|---|---|
>=0.1.7-rc.1 <0.2.0-0 ❌ |
✅ | ❌ | ❌ | ❌ |
>=0.1.7-rc.1 <0.2.0 |
✅ | ✅ | ❌ | ❌ |
>=0.1.7-rc.1 <0.3.0-0 ✅ |
✅ | ✅ | ✅ | ❌ |
tests/dsh-peer-range.spec.ts 钉住这条不变式:逐条断言每个 peer 范围必须放行
0.1.7 与 0.2 两条线、必须挡住 0.3 线,并禁止 <0.2.0-0 这种写法回归。
为什么需要专门的测试:范围写错时
tsc通过、全部单测通过、pnpm install通过、 CI 全绿——只有真实宿主会拒绝加载。这正是 2.3.1 一路绿着上线的原因。
0.1.7 把设置体系整体重建,插件按 0.1.7 的契约工作:
- 宿主端注册:
SettingsForms.configure({auto}, owner)(0.1.7 起installSection已删除),命名空间取宿主实际服务的 Loader 条目 id(ctx.fiber.entry?.options.id,回落到trae)——harness 按精确匹配查找 provider 的命名空间,写死trae会让 provider 被判「未配置」。 - 客户端设置面:
configForms(0.1.7 起settingsScope已移除)。inject只声明slots/locale,设置面用ctx.get()软探测——Cordis 的依赖闸门是硬闸,inject里任一服务在运行线上不存在,apply()就永远不会执行(这正是 2.2.0 及更早版本在 0.1.7 上卡在pending (waiting for service: settingsScope)的原因)。 - 配置卡片槽位:
plugins.bundle.config/plugins.row.config(settings.plugin.item已删除)。 - schema 可写声明:可写字段必须标
volatile()(asVolatile),否则写入被 0.1.7 的写入门直接拒绝;0.1.7 以{get(): T}活引用交付配置值,所有读取与合并路径都先解包(unwrapVolatile/unwrapVolatileDeep)。 - 折叠箭头用纯 CSS,不静态导入任何 primitives 图标——图标命名族随版本变动,静态导入不是稳定契约。
平台支持
| 平台 | 状态 | 说明 |
|---|---|---|
| macOS | ✅ 完全支持 | 开发与验证环境;目录名均经真机确认 |
| Windows | ✅ 支持 | CI 跑 windows-latest;账号目录、应用版本头、锁行为均有专门处理。已在一台真机(Windows 10.0.22621 + TRAE SOLO CN)通过验证,见下方 |
| Linux | ✅ 支持 | 含 WSL2 + Trae CLI 场景(issue #5);目录名按多候选探测 |
三个平台共享同一套逻辑:账号读取、解密、区域判定、签到与用量查询均与平台无关,平台差异只集中在路径解析(src/paths.ts)与设备指纹(src/identity.ts)两处。
Windows 说明
- 账号数据目录:插件读取
%APPDATA%\<目录名>\User\globalStorage\storage.json(与安装目录无关——Electron 系应用的用户数据固定放%APPDATA%,装到 D 盘也一样)。插件会并列探测多个目录拼写(Trae CN与trae-cn、TRAE SOLO CN与trae-solo-cn),命中任一即可;Windows 文件名不区分大小写,因此不会重复探测同一目录。 - 应用版本头:插件从安装目录
<LOCALAPPDATA>\Programs\<安装目录名>\resources\app\product.json读取appVersion(LOCALAPPDATA缺失时回退<home>\AppData\Local),随请求发送x-app-version/x-ide-version;读不到时这些头不发送,不影响登录与聊天。 - 设备指纹:
x-device-type发windows,x-os-version为Windows <版本>。机器 ID 取自数据目录的telemetry.machineId(或同目录machineid),该推导在 Windows 上成立。 - 文件锁:宿主
dsh-atomic-write原生处理 Windows 的独占创建语义(EPERM/EBUSY重试),无需插件侧适配。 - Raw Chat 探测(已知限制):
model-cache依赖sqlite3命令行,Windows 默认未安装,该探测会失败并安全回退。Raw Chat 默认关闭,不影响主流程。 - 权限位:写凭据副本时传
mode: 0o600/dirMode: 0o700,Windows 忽略 POSIX 权限位——不报错,属已知且无害。
真机验证结果(2026-09-26,Windows 10.0.22621 + TRAE SOLO CN)
node scripts/verify-windows.mjs 实测全部通过(退出码 0):
| 检查项 | 实测结果 |
|---|---|
| 目录探测 | 命中 %APPDATA%\TRAE SOLO CN\User\globalStorage\storage.json(其余候选为 missing) |
| 账号解析 | 解出 1 个账号,solo / cn 区域 |
x-device-type |
windows ✅ |
x-os-version |
Windows 10.0.22621 ✅ |
x-device-id |
16 位纯数字(来自数据目录,非兜底哈希)✅ |
x-app-version |
0.1.56,取自 %LOCALAPPDATA%\Programs\TRAE SOLO CN\resources\app\product.json ✅ |
这确认了什么:win32DirName 作依据是正确的——TRAE SOLO CN 这个拼写确实是 Windows 真机上的实际目录名,且 product.json 的安装路径推导与设备指纹各字段都成立。即「Windows 上插件读得到 Trae 登录」已由真机证据支持,不再是推断。
脚本之外的运行路径(同一台真机,2026-09-26)
上表四项只覆盖路径探测与设备指纹,不等于「整个插件在 Windows 上跑得通」。因此另外单独实测了插件的主流程(直接调用 lib/ 的导出,即产品代码本身):
| 运行路径 | 实测结果 |
|---|---|
TraeCredentialStore.resolve() |
✅ 返回凭据,host https://api.trae.cn,token 有效期正常解析 |
identityHeaders() 全部请求头 |
✅ 10 个头全部生成(x-device-id / x-machine-id / x-device-cpu / x-ide-version-code 等) |
| 用量查询(只读,不消耗积分) | ✅ 拿到 9 个积分包,总额 2050 / 已用 1522.85 |
| 模型目录拉取(只读) | ✅ 拉到 42 个模型 |
原子写 writeFileAtomic |
✅ 写入 + 回读一致 |
并发文件锁 withFileLock |
✅ 8 个并发写串行化正确,无丢失更新(Windows 独占创建语义由宿主处理,验证成立) |
SSE 解码 |
✅ 代码按 \r?\n 切分,CRLF 与分块均支持 |
也就是说:登录、身份、用量、模型目录、并发写入这些主流程在 Windows 上均实测可用。
已知限制(本机实测确认其行为):
model-cache依赖sqlite3命令行,本机未安装,实测抛ENOENT(spawn sqlite3 ENOENT),调用方.catch(() => undefined)正确兜底——不影响主流程,Raw Chat 默认关闭。该模块的目录拼写缺口已修复(同轮发现并修掉):它原先把
state.vscdb路径硬编码为Trae CN单一拼写,而paths.ts是多候选,且它自己重算了一遍目录而没复用traeStorageCandidates。在本机(真实目录名为TRAE SOLO CN)上,旧代码指向的...\Trae CN\...\state.vscdb根本不存在;只因sqlite3缺失、该调用必然失败并兜底,才把一个错误的路径藏在了另一个看似合理的错误(依赖缺失)后面。修法是让缓存路径从凭据路径推导——
state.vscdb与storage.json同在globalStorage,因而同一个候选目录既管登录也管缓存;raw-resolver现在把命中的候选传下去,多版本共存时不会读到另一个安装的模型表。真机复测:新代码正确选中%APPDATA%\TRAE SOLO CN\User\globalStorage\state.vscdb(存在),旧代码只找Trae CN(不存在)。
仍然未验证的部分:本机只装了 TRAE SOLO CN,因此
Trae CN/trae-cn这两个拼写仍未经真机确认——但它们在此机器上不存在只反映「本机没装这个版本」,不代表拼写有误。装了 Trae 中国版的 Windows 用户仍欢迎跑一次上面的命令回报。
安装 Trae 中国版或别的情形?一条命令即可回报:
node scripts/verify-windows.mjs—— 它用插件自身的构建产物列出在这台机器上探测的每条路径、能否解出账号、以及设备指纹,输出已脱敏(用户名替换为<user>,账号名与设备号只给长度),可直接贴进 issue。完整的验证步骤与结论判读见docs/WINDOWS_VERIFY_GUIDE.md;手工逐步排查见docs/WINDOWS_TOKEN_PROBE.md(只要目录名与 key 名,不要 token)。若目录名仍对不上,可用authFile+edition直接指定完整路径救急。
开发
pnpm install
pnpm run check # typecheck + test + build
本地开发用 link: 安装到 desktop profile(改码后重启 DSH Desktop 生效):
dsh plugin --profile desktop add /path/to/dsh-connect-trae
致谢
- Wang-JQ77/dsh-trae-api(MIT)— Trae 认证、会话和模型协议研究的参照实现。
第三方开源依赖
本项目参考的与 Trae 接入直接相关的开源项目,以及它们的许可证与合规说明,见 THIRD_PARTY_NOTICES.md。引入新的 Trae 相关外部依赖或复用其他项目代码时,请同步更新该文件并遵守对应许可证要求。
许可证
本项目采用 MIT 许可证,版权归属:Copyright (c) 2026 LaoDing。