dsh-connect-trae 3.7.0 → 3.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,266 @@
1
1
  # Changelog
2
2
 
3
+ ## 3.9.1 (2026-10-18)
4
+
5
+ > **3.9.0 从未发布到 npm**(发版时卡在 OTP 认证),本版本是同一套账号池功能加上 tag 之后
6
+ > 的十三处修正与重排。功能面见下面的 3.9.0 段;这里只列 3.9.0 tag 之后的改动。
7
+
8
+ ### 新增
9
+
10
+ - **测试请求体积**(`regions.<面板>.pool.probeInputTokens`,默认 `0`):测速时向上游发多少
11
+ 文本。`0` 是**一个词的最小探针**,其余选项 1 万 / 2 万 / 3 万 / 5 万 / 10 万 token。默认
12
+ 保持最小而不是「像真实对话」——填多少就扣多少积分,插件没有证据说明 Trae 在小请求上会
13
+ 误判,就不该让默认值替你花钱。老 Host 不认识这个字段时,卡片**不渲染这一行**(否则保存
14
+ 必然读回失败)。
15
+ - **读余额前按需刷新 token**:单个账号的凭证过期后,读它的余额/签到/探针会先刷新一次
16
+ (同一账号并发只刷一次,失败时不重试而是返回旧凭证让上游如实 401)。此前只有「当前
17
+ 绑定」的账号会被刷新,池里其他账号过期后余额永远是空的;现在读不到余额的行会明确标
18
+ 「登录已失效」,而不是只显示一个 `—`。
19
+
20
+ ### 修复
21
+
22
+ - **「本机今日已签到」是设备级事实,不是账号级**:Trae 的每日签到绑在 `x-device-id` 上,
23
+ 同一台机器第二次签到必被 9095 拒。此前按账号记账,于是池表里第二个账号照样给一个「签到」
24
+ 按钮——点了注定失败。现在任一账号当日已领即视为整台机器已用:其余行的按钮禁用、状态写
25
+ 「本设备今日已用」,「一键签到所有账号」同样禁用并说明「一台设备一天一次」。
26
+ - **无签到面板的行列数错位**:表格换成四列时,行里仍渲染五个格子,动作按钮被挤到第二行。
27
+ - **绑定下拉里列出幽灵账号**:设置里存着、本机已无登录的账号没有凭证,选中后什么都不会
28
+ 发生;现在从「手动选择计费账号」里剔除(仍留在成员表里可移除)。
29
+ - **刷新失败改为五分钟退避**:被吊销的账号每轮轮询都触发两次注定失败的上游刷新。
30
+ - **`tokenExpired` 只在真的读不到余额时上报**:不再出现「登录已失效」与有效余额并排。
31
+ - **药丸开关只作用于设置行**:它曾被写成全局 `.dsm-trae-switch input`,导致面板 tab 里的
32
+ 开关也长成药丸;配色也改用能分清明暗的令牌(此前取到的 `brand-primary` 在浅色主题里近黑)。
33
+
34
+ ### 变更(卡片外观)
35
+
36
+ - **池区块按参考卡片重排**:顶部只留动作行(一键签到 / 一键测试 / 重新检测),成员表自成
37
+ 一张卡(卡头装「已选 N / M」+ 全选 / 清空),每格都是「主行 + 灰副行」,账号管理控件放进
38
+ 虚线工具区,保存行移出设置盒并与「鼓励一下」同排。不再有第二张账号表重复同样的名字、
39
+ 积分和签到状态。
40
+ - **一套尺度**:内边距 14 / 10,圆角 14(面)、10(面内的盒)、999(药丸),字阶 10–14,
41
+ 区块用分隔线而不是再套一层框,同一行各格首行对齐。
42
+ - **成员状态写成字**:「已在池中」/「未入池」不再只靠勾选框表达;勾选框的 label 只包 input,
43
+ 点账号名不会改计费对象。
44
+
45
+ ### 测试
46
+
47
+ - 全仓 **841** 例通过(3.9.0 tag 时为 809)。新增:`tests/card-shot.spec.tsx`(用真实组件
48
+ 渲染成静态页 + 几何审计 + Chrome headless 截图,`CARD_SHOT=1` 才跑,CI 零副作用)、
49
+ 尺度守卫(间距变量、圆角白名单)、设备级签到的三条断言(含反向验证:改回按账号即失败)。
50
+
51
+ ## 3.9.0 (2026-10-18)
52
+
53
+ > **账号池:多账号不再只是「列出来让你手点」。** 本机读完几个账号之后,可以打开一个
54
+ > **按规则自动选号、请求失败自动换号**的池(默认关闭)。此前多账号的全部能力止步于
55
+ > 「卡片把还有额度的账号列出来,你自己点一下切过去」——额度耗尽发生在一次对话中途时,
56
+ > 你只会看到一条失败,然后回去点按钮、再重发。这个版本把「谁付钱」变成一条可以委托给
57
+ > 插件的规则,同时**不偷偷替你换计费对象**:池默认关闭,打开它本身就是一次显式选择。
58
+
59
+ ### 新增
60
+
61
+ - **账号池(逐面板,默认关闭)**:`enabled` / `targetModelId` / `memberAccountIds` 三个字段
62
+ 落在 `regions.<面板>.pool`。名单是**显式 opt-in**(默认空,空名单意味着「谁都不服务」,
63
+ 而不是「全员」)。
64
+
65
+ | 规则 | 为什么是这个顺序 |
66
+ | --- | --- |
67
+ | 先排除不可用 | `credential-rejected` / `plan-gated` / `not-found` 永久出池(这三种都不是「等一会儿就好」);`rate-limited` / `out-of-credit` / `unavailable` / `failed` 在重试时间后回池;`model-busy` 用 2 分钟短时钟 |
68
+ | 再优先快到期 | 同样是额度,先花掉 3 天内会过期的那部分,否则它过期后等于没拿到 |
69
+ | 然后比可用额度、token 新鲜度 | 额度高者先;同额度取 token 更新者 |
70
+ | 最后按账号 id 兜底 | 排序必须是**全序**,否则卡片与路由器会在两行之间来回抖 |
71
+
72
+ - **失败换号(真实请求路径)**:一次请求最多试 3 个账号。只有**账号级**失败才换号
73
+ (`authentication` / `hard_credit` / `soft_rate` / `server`);`not_found` / `client`
74
+ 不换——模型 id 写错换号只会把同一个错误烧两遍,还会冤枉一个没机会服务的账号。换号
75
+ 仍然失败时,错误消息尾部会带一句**为什么没有别的账号能接**(全部试过 / 剩余全被排除
76
+ + 原因),而不是只留一个裸的上游错误。
77
+ - **实盘失败落盘**:换号过程中学到的结论以 `live-request` 探针写进
78
+ `$DSH_HOME/.trae-pool.<面板>.json`(0o600、原子写、永不抛错、**不存任何凭证**),
79
+ 卡片能分辨「批量测出来的」与「真实流量告诉我的」。
80
+ - **卡片上的池区块**:成员表(草稿勾选框、状态点、当前计费徽标、在池标记、排除原因、
81
+ **通用积分**列并标注 Work 不可花、探针结论 + 相对时间 + 模型作用域、签到列只在支持的
82
+ 面板出现、行内测速/移除)、幽灵成员(设置里存着但本机已无登录,仍渲染成可移除的行)、
83
+ 「全部签到」与「全部测速」(NDJSON **逐行**返回,跑一个显示一个)、目标模型选择
84
+ (`''` = 自动挑免费模型;已下架的模型单独成一个选项并给「切回自动」按钮)、保存/放弃
85
+ 草稿与未保存徽标、活动日志。
86
+ - **三条路由**:`POST /plugins/dsh-connect-trae/pool?action=checkin|test|remove`
87
+ (`test` 走 `application/x-ndjson`)。守卫:仅 POST(405)、仅环回来源(403)、池不可用
88
+ (503)、`action` 必须可解析(400)、`accountId` 必须是 24 位十六进制(400,且**在任何
89
+ 写入或上游调用之前**校验——这个 id 会进文件名与凭证查找)、空池 409 区分 `no-members`
90
+ 与 `no-live-members`、签到不支持的面板 409 `checkin-unsupported`(**在花掉一次只能失败
91
+ 的请求之前**)。
92
+
93
+ ### 修复
94
+
95
+ - **`checkinSupported` 按面板判定**:只有国内版有个人签到活动(国际版与企业版网关直接
96
+ 404)。此前没有任何地方表达这件事,卡片只能靠「请求失败」来发现。
97
+ - **`toCredits` 补 `endpoint`**:Trae 的额度分 General(SOLO 聊天实际扣的)与 Work(够不到)
98
+ 两个桶。池的排序与卡片显示统一用 **General**,此前只能拿到两桶之和——一个 Work 余额很
99
+ 大、General 已空的账号会排在一个真能服务的账号前面。
100
+
101
+ ### 测试
102
+
103
+ - 新增 **5 个文件 / 112 例**:`tests/account-pool.spec.ts`(56:排序全分支、出池规则、
104
+ 冷却时钟、`billableMembers`、`resolveTargetModel` 的 stale 不给 id、批处理串行与流式、
105
+ 9095 中止整批、落盘合并规则、`parseUpstreamResetAt` 无时区一律 undefined)、
106
+ `tests/account-pool-store.spec.ts`(20:往返/合并/按面板隔离/坏 JSON/版本不符/读时修补/
107
+ 文件不含凭证/池文档组装与幽灵成员)、`tests/account-pool-route.spec.ts`(14:五种拒绝、
108
+ 坏 id 时上游调用次数为 0、NDJSON 三行、409 两种空池、签到不支持时零次 claim)、
109
+ `tests/account-pool-failover.spec.ts`(12:轮转压倒绑定、清空恢复绑定、**refresh 落在被
110
+ 轮转的账号上**、企业店拒绝个人轮转、shim 只在账号级失败换号、三次上限 + shortfall 文本、
111
+ 池 hook 抛异常仍正常作答)、`tests/card-pool.spec.tsx`(10:草稿勾选→写 `regions`、
112
+ 放弃还原、stale 目标、签到列按能力隐藏、NDJSON 增量渲染、幽灵成员可移除、**以及「区块里
113
+ 每个 class 都真有样式规则」**——这条守卫此前只覆盖输入框读数,池区块曾在零 CSS 的情况下
114
+ 通过全部行为断言)。
115
+ - 全仓 **823** 例通过(3.8.1 为 711)。
116
+
117
+ ## 3.8.1 (2026-10-18)
118
+
119
+ > **signed-out 不再吞掉账号列表。** 2026-10-18 的现场报告是「本地突然刷不出账号了」:
120
+ > 绑定的账号 access token 过期、refresh 被上游 401,这本身是要重登的凭据问题;真正致命的是
121
+ > 卡片在 `signed-out` 状态下把整张账号表藏起来、只留一行状态——明明列表里还有一个可用账号,
122
+ > 屏幕上却一个都看不见,而唯一能自救的那一下点击(改绑另一个账号)在界面上不存在。
123
+ > 本版修复这条恢复路径。3.8.0 从未发布到 npm,所以本版即「3.8.0 全部内容 + 本修复」。
124
+
125
+ ### 修复
126
+
127
+ - **账号面板 signed-out 时仍列出账号名册**(`src/client/TraeUsageCard.tsx`):渲染门控从
128
+ `status !== 'signed-in' || accounts.length === 0` 改为 `status !== 'error' && accounts.length > 0`。
129
+ Host 在「有名册但绑定的账号用不了」时回的就是 `signed-out` + 原因 + 名册——三者同一条响应,
130
+ 此前名册被状态丢弃。改绑完成后原因仍单独显示在表格下方一行,不再连带吞掉账号行。
131
+
132
+ ### 测试
133
+
134
+ - 新增 1 例(`tests/card-accounts-table.spec.tsx`):断言 signed-out 时原因可见、表头与两行都渲染、
135
+ 已绑定行标为当前且不重复给按钮、**另一行的绑定按钮点击后确实写入 `accounts.cn`**。
136
+ 变异验证:把门控还原成 `=== 'signed-in'`,恰好只有这一例变红。
137
+ - 全仓 **711** 例通过(710 + 1)。
138
+
139
+ ## 3.8.0 (2026-10-18)
140
+
141
+ > **本版未发布到 npm**(tag `v3.8.0` 与 GitHub Release 已建、不可移动;发布被 npm 2FA 的
142
+ > PUT 401 挡住)。其全部内容随 3.8.1 一起上线,以下保留原文。
143
+
144
+ > **国内区多了一个面板:企业版。** 同一张 CN 凭据若属于 `tob_online` 租户,会被两个网关
145
+ > 同时服务——消费池扣个人积分,租户池扣企业额度。同一模型、两种付费方,所以「谁付钱」
146
+ > 必须由你选,不能由插件猜。同时修好 `config_name` 大小写导致的 `4001`,以及企业网关
147
+ > 用 HTTP 200 + `event:error` 拒绝时被当成「这轮助手什么都没说」的问题。
148
+
149
+ ### 新增
150
+
151
+ - **卡片新增「企业版」面板**:供应商开关从「按区域」改为「按面板」,国内版、企业版、
152
+ 国际版三者并列,各有**独立开关、独立账号绑定、独立模型选择**。
153
+
154
+ | 面板 | provider | 默认开关 |
155
+ |---|---|---|
156
+ | 国内版 | `trae` | 开 |
157
+ | 企业版 | `trae-enterprise` | **关**(原来两个面板的用户不受影响) |
158
+ | 国际版 | `trae-global` | 开 |
159
+
160
+ 关掉企业版不会影响国内版;两个 CN 池的模型选择也不再互相覆盖。企业版默认关闭,
161
+ 因为纯个人账号用不了企业池——默认放开等于给所有人塞一条一用就失败的 provider。
162
+
163
+ - **`trae-enterprise`(显示名「Trae 企业版」)**:现在 `cn` 区并列发布两个 provider:
164
+
165
+ | provider | 计费池 | 说明 |
166
+ |---|---|---|
167
+ | `trae` | 消费 SOLO | 行为与此前完全一致,永不碰企业网关 |
168
+ | `trae-enterprise` | 企业租户 | **不回落**,失败如实报错 |
169
+
170
+ `TRAE_PROVIDER_IDS` 描述每个区发布哪些 id,`routeOfTraeProvider` 把 id 映射到计费池;
171
+ **路由在构建 provider 的客户端时固定**,不存在「按调用猜一次」。shim 为每个 provider
172
+ 提供一条 bearer 路由并按 bearer 分派,未知 token 直接 401,不会退回第一条路由。
173
+
174
+ ### 修复
175
+
176
+ - **计费账号与卡片显示可能不是同一个(本版最重要的一个)**:`accounts()` 从**已经为展示
177
+ 过滤过**的列表推导 `selected`,而 `current()` 从**全量**登录里解析真正计费的凭据。
178
+ 开着 `hideTenantAccounts` 且企业号排序在前时,两者分歧——卡片高亮个人号,聊天扣企业池,
179
+ 而卡片里的 `rescanAccounts` 还会把这个错误绑定**存下来**。现在 `inUse` 拆成两个入参:
180
+ 显式绑定走全量(展示过滤不得缩小「用户选的号」的查找范围),无绑定时默认值走过滤后列表
181
+ (隐藏企业号是计费决定,不是展示细节);`current()` 与 `accounts()` 传同一对参数,
182
+ 结构上不可能再分歧,正在计费的账号也永不会被从列表里隐藏。
183
+
184
+ - **`deepseek-v4.1-flash` 等模型报 `4001`(`param is invalid`)**:网关的 `config_name`
185
+ **区分大小写**,而 Remote 目录给的是小写、网关只认 `DeepSeek-V4.1-Flash`。三处一起修:
186
+
187
+ 1. `modelConfig` 补上 `wireConfigName`。DSH 设置通道用它重建文档,未声明的字段会在
188
+ **每次保存时被丢掉**——映射一丢,该模型就要等到下一次发现才能用。
189
+ 2. `fetchModels` 改为从**客户端所钉的那条网关**读名录。两个池的名录不同
190
+ (`DeepSeek-V4.1-Flash` 只有企业池列),原本钉在企业池的客户端去读消费池名录,
191
+ 永远发现不了自己池的独占模型。
192
+ 3. `TraeSoloBridge` 查表改为大小写不敏感,映射都落空时退回目录行自己的 id。
193
+
194
+ - **企业网关的拒绝形态**:它是 **HTTP 200**,但首帧是 `event:error`(`code 4001`)。
195
+ 现在会被转成真正的客户端错误,正常流则逐字节重放给调用方——否则拒绝会表现成
196
+ 「这一轮助手什么都没说」。
197
+
198
+ - **企业网关要求每次调用带 `session_id`**,而消费网关会拒绝带它的请求体,所以只在该路由上加。
199
+
200
+ ### 自测
201
+
202
+ - 企业版相关新增 **38** 项(`enterprise-provider` 17、`card-enterprise-panel` 9、auth 租户
203
+ 作用域 4、web-status 过滤 3、catalog 费率 1、solo-bridge 错误码 1……详见 PR 描述第 3 节)。
204
+ 覆盖按 bearer 分派、`session_id` 只在该路由、200/`event:error` 识别、流原样透传、
205
+ 名录按路由读取、大小写映射与 schema 往返、租户账号作用域、4222 可读等。
206
+ - 计费一致性新增 2 例:`accounts()` 里 `selected` 的那一行必须就是 `current()` 计费的那个账号;
207
+ 被隐藏的账号正在计费时仍须留在列表里。两例在修复前均变红(`expected 'tenant-user' to be 'personal-user'`)。
208
+ - 用真实 `tob_online` 帐号实测:企业路由返回 PONG、带 `session_id`、个人 `consumed_amount` 不变。
209
+ - 全仓 **710** 例通过,双 tsconfig 类型检查通过。
210
+
211
+ ## 3.7.1 (2026-10-18)
212
+
213
+ > **对齐 DSH 0.2.1-rc.2,并把发布后核验收敛为一条命令。** 宿主 rc.1 → rc.2 对本插件消费的
214
+ > API 是**零变化**(逐字节核对确认),所以本版没有行为改动——它做的是两件事:把开发树钉到
215
+ > 用户实际运行的那份宿主上,以及让「npm 上的包是否等于 tag 指向的源码」不再依赖手工核对。
216
+
217
+ ### 变更
218
+
219
+ - **对齐宿主 DSH 0.2.1-rc.2**:13 个 `@deepseek-ai/dsh-*` devDependency 从 `0.2.1-rc.1`
220
+ 推进到 `0.2.1-rc.2`。`cordis` / `schemastery` / `pi-ai`(仍 `1.1.0`)均未变。
221
+ - **peer 范围无需改动**:`0.2.1-rc.2` 对 `>=0.1.7-rc.1 <0.3.0-0` 已判通过(实测)。
222
+
223
+ ### 新增
224
+
225
+ - **`pnpm run verify:release`**(`scripts/verify-release.mjs`):把 RELEASING.md 第 8 步
226
+ 从手工核验变成一条命令,21 项检查一次做完 —— tag 版本、tag 之后的提交、工作树状态、registry 收录、
227
+ `latest` 指向、**发布包每一个文件**与 tag 逐字节比对、`lib/` 由 tag 源码重建后比对。
228
+ 退出码即结论:`0` 一致 / `1` 不一致 / `2` 前置条件不满足。
229
+
230
+ > 手工版本的三个已知盲点被闭合:核对清单只写了 8 个文件而发布包有 15 个
231
+ > (`icons/`、`docs/assets/`、`scripts/verify-windows.mjs` 从未被核对);
232
+ > 拿本地 `lib/` 当基准会掩盖「构建自未提交工作树」;`git show` 默认按 UTF-8 解码,
233
+ > 把 PNG 当文本会得到假的不一致 —— 本脚本第一版就踩了这个坑,三个图片文件全部误报。
234
+
235
+ ### 文档
236
+
237
+ - RELEASING.md 第 8 步改为脚本优先,手工等价步骤保留在折叠区并注明其局限。
238
+ - **新增 `docs/PENDING_CHANGELOG.md` 暂存机制**:`CHANGELOG.md` 是随包文件,在已发布的 tag
239
+ 之后改动它会让 `verify:release` 正确地报「tag 之后改动了发布内容」。未发布版本的条目因此
240
+ 暂存在 `docs/`(`docs/*.md` 不进包),发版时并入 CHANGELOG 再删除。RELEASING.md 第 3 步
241
+ 已加入对应指引。
242
+
243
+ ### 测试
244
+
245
+ - `tests/dsh-peer-range.spec.ts` 的 `MUST_ADMIT` 补入 `0.2.1-rc.1` / `0.2.1-rc.2` / `0.2.1`。
246
+ 此前这份「必须放行的版本」清单里**没有当前正在使用的版本**——范围若被误收窄到
247
+ 当前宿主之外,测试仍会全绿。变异验证:把上界改到 `<0.2.1-rc.2` → 对应用例立刻变红。
248
+ - 新增 7 例(`tests/verify-release.spec.ts`),用 PATH 上的假 `npm`/`tar` 提供受控发布包,
249
+ 子进程跑**真脚本**:一致→0、篡改→1、多出文件→1、无 tag→2、未发布→2、二进制逐字节比对、
250
+ tag 之后有提交仍→0。
251
+ - **变异验证**:把 `git show` 改回 UTF-8 解码 → 2 例变红;让比对恒返回「一致」→ 1 例变红。
252
+ - 全仓 **670** 例通过。
253
+
254
+ ### 已核对确认无变化
255
+
256
+ - 逐字节比对插件消费的宿主包(`.d.ts` 与 `lib/*.js`)——`dsh-llm`、`dsh-llm-pi-ai`、
257
+ `dsh-settings`、`dsh-host-webserver`、`dsh-atomic-write`、`dsh-home-paths`、
258
+ `dsh-attachment`、`dsh-client-ui-renderer`,以及 `dsh-app-boot` 的 peer 门禁:**全部相同**。
259
+ - pi-ai 仍为 `1.1.0`,`openai-completions.js` 与 `utils/transcript.js` 未变,
260
+ 上一轮的双向适配结论原样成立。
261
+ - 线上请求体探针在真实 rc.2 栈上复跑,结果与 rc.1 一致。
262
+
263
+
3
264
  ## 3.7.0 (2026-10-17)
4
265
 
5
266
  > **对齐 DSH 0.2.1-rc.1。** 宿主把 `@earendil-works/pi-ai` 从 `^0.85.1` 抬到 `^1.1.0`,
package/README.en.md CHANGED
@@ -24,7 +24,7 @@
24
24
  <a href="https://dshfind.com/plugins/dingminhua/dsh-connect-trae"><img src="https://dshfind.com/api/badge/dingminhua/dsh-connect-trae" alt="dshfind plugin"></a>
25
25
  </p>
26
26
 
27
- A [DeepSeek Harness (DSH)](https://github.com/deepseek-ai/deepseek-harness) bundle plugin that connects locally signed-in Trae models (**both CN and international installs**) to the DSH model picker. Trae generates structured tool calls while DSH executes its own local tools, with a usage overview (Work/general credits on CN, subscription status on international), daily check-in claiming, and a model-management panel. **The CN and international sides are two parallel providers (`trae` / `trae-global`) that can be used at the same time**; the settings card separates them with tabs for convenient management.
27
+ A [DeepSeek Harness (DSH)](https://github.com/deepseek-ai/deepseek-harness) bundle plugin that connects locally signed-in Trae models (**CN, enterprise, and international installs**) to the DSH model picker. Trae generates structured tool calls while DSH executes its own local tools, with a usage overview (Work/general credits on CN, tenant allowance on enterprise, subscription status on international), daily check-in claiming, and a model-management panel. **The CN, enterprise, and international sides are three parallel providers (`trae` / `trae-enterprise` / `trae-global`) that can be used at the same time**; the settings card separates them with tabs for convenient management.
28
28
 
29
29
  **Runs on macOS, Windows, and Linux**: CI runs the full typecheck / test / build matrix on `ubuntu-latest` and `windows-latest`, and Windows gets purpose-built handling for directory probing, app version headers, and lock behavior — see [Windows notes](#windows-notes).
30
30
 
@@ -32,9 +32,10 @@ A [DeepSeek Harness (DSH)](https://github.com/deepseek-ai/deepseek-harness) bund
32
32
 
33
33
  ## Features
34
34
 
35
- - **Dual parallel providers** — the CN side registers as the `trae` provider (e.g. `DeepSeek-V4-Flash`, `DeepSeek-V4-Pro`), the international side as `trae-global` (the Gemini/GPT/MiniMax roster), and **both rosters appear in the DSH model picker simultaneously**: different sessions can each pick a side without interfering.
36
- - **Either side can be switched off** — each tab carries its own checkbox (both checked by default): unchecking **withdraws that provider from the DSH model picker entirely** (not merely hiding the tab) and stops all of its requests; checking it again restores it with the account, directory, picks, and context budgets intact. If you never use the international side, just uncheck it.
37
- - **Tabbed settings card** — the card's top carries a "Domestic / Global" tab bar; each tab holds its own account picker, usage overview, and model management. Account, directory, selection, and unsaved drafts are fully isolated per tab — switching accounts or refreshing models on one tab never touches the other side's runtime catalog or sessions.
35
+ - **Three parallel providers** — the CN side registers as the `trae` provider (e.g. `DeepSeek-V4-Flash`, `DeepSeek-V4-Pro`), the enterprise side as `trae-enterprise`, and the international side as `trae-global` (the Gemini/GPT/MiniMax roster); **all three rosters appear in the DSH model picker simultaneously**: different sessions can each pick a side without interfering.
36
+ - **Enterprise is a separate billing channel, not an alias for CN** — the same CN credential, when it belongs to a `tob_online` tenant, is served by **two** gateways: the consumer pool (billed against personal credits) and the tenant pool (billed against the enterprise allowance). Same model, two payers, so **you** choose who pays; the plugin never guesses. `trae` never touches the enterprise gateway, and `trae-enterprise` **never falls back** — a refusal is reported as a refusal instead of quietly re-running on personal credits. Enterprise is **off by default**: a personal-only account cannot use the tenant pool, so shipping it enabled would mean handing everyone a provider that fails on first use.
37
+ - **Any panel can be switched off on its own** — each tab carries its own checkbox (CN and international checked by default, enterprise not): unchecking **withdraws that provider from the DSH model picker entirely** (not merely hiding the tab) and stops all of its requests; checking it again restores it with the account, directory, picks, and context budgets intact. If you never use the international side, just uncheck it.
38
+ - **Tabbed settings card** — the card's top carries a "Domestic / Enterprise / Global" tab bar; each tab holds its own account picker, usage overview, and model management. Account, directory, selection, and unsaved drafts are fully isolated per tab — switching accounts or refreshing models on one tab never touches the other side's runtime catalog or sessions. CN and enterprise share one CN credential pool but keep **separate account bindings and model picks**: the two rosters differ (`DeepSeek-V4.1-Flash` is listed only on the enterprise pool), so picks never overwrite each other.
38
39
  - **Multiplier in the model name** — model names show the credit multiplier in Trae's own menu format (e.g. `GLM-5.2 · x0.79`), updated with each directory refresh.
39
40
  - **DSH local tool loop** — gets pending structured `tool_calls` from Trae `llm_utils_chat`, lets DSH execute its own local tools, then returns tool results to the model.
40
41
  - **Dual-region detection (CN / international)** — detects local sign-ins across Trae CN, TRAE SOLO CN, Trae, and TRAE SOLO installs. The region is derived from the credential's own `userRegion` claim (host suffix and edition label as fallbacks), with no manual switch.
@@ -51,7 +52,7 @@ A [DeepSeek Harness (DSH)](https://github.com/deepseek-ai/deepseek-harness) bund
51
52
 
52
53
  <img src="docs/assets/dsh-connect-trae-composer-credits.png" width="536" alt="Trae credits panel: a table of accounts with their general balance, and the composer readout below" />
53
54
 
54
- **Where that readout sits is a choice** (learned from the sibling `dsh-connect-workbuddy` issue #62). The default is the **composer toolbar** (the position described above); if another plugin occupies it and the readout does not appear, move it **below the input box** — the row carrying the round / step / token statistics, where the readout is APPENDED after the shipped figures rather than replacing them. The seat is set **per region** (CN and international are stored separately), in the card's settings block next to the "show credits in the composer row" checkbox. Why a second seat exists at all: the composer toolbar is a **shared list slot** that the shell's own controls and every other plugin register into, and a shared slot **cannot promise that every occupant is visible** — the report behind that issue is a readout that vanished entirely once a third-party plugin was installed (this plugin has been squeezed out of a shared row once before too, down to a clipped "Tr" at the sidebar foot).
55
+ **Where that readout sits is a choice** (learned from the sibling `dsh-connect-workbuddy` issue #62). The default is the **composer toolbar** (the position described above); if another plugin occupies it and the readout does not appear, move it **below the input box** — the row carrying the round / step / token statistics, where the readout is APPENDED after the shipped figures rather than replacing them. The seat is set **per panel** (all three are stored separately), in the card's settings block next to the "show credits in the composer row" checkbox. Why a second seat exists at all: the composer toolbar is a **shared list slot** that the shell's own controls and every other plugin register into, and a shared slot **cannot promise that every occupant is visible** — the report behind that issue is a readout that vanished entirely once a third-party plugin was installed (this plugin has been squeezed out of a shared row once before too, down to a clipped "Tr" at the sidebar foot).
55
56
 
56
57
  - **Secure loopback shim** — one random port + in-process random secret per region; the real Trae token is never handed to pi-ai.
57
58
 
@@ -62,13 +63,18 @@ DSH PiAiAdapter (one stack per provider)
62
63
  -> secure loopback shim (one random port + in-process random secret per region)
63
64
  -> TraeSoloBridge
64
65
  -> CN: https://trae-api-cn.mchost.guru/api/agent/v3/llm_utils_chat
66
+ -> Enterprise: https://console.enterprise.trae.cn/api/agent/v3/llm_utils_chat
65
67
  -> Global: https://coresg-normal.trae.ai/api/agent/v3/llm_utils_chat
66
68
  -> Trae SSE / pending function_call
67
69
  -> OpenAI SSE tool_calls
68
70
  -> DSH executes local tools and returns their results
69
71
  ```
70
72
 
71
- The CN and international sides each own a complete runtime stack — credential store, model catalog, wire map, upstream clients, loopback shim, adapter — with visibility filtered by the credential's own region claim, so **both regions' accounts can be signed in and used by different sessions at the same time**.
73
+ Each panel owns a complete runtime stack — credential store, model catalog, wire map, upstream clients, loopback shim, adapter — with visibility filtered by the credential's own region claim, so **accounts from several regions can be signed in and used by different sessions at the same time**.
74
+
75
+ **A panel is not a region.** `cn` and `ai` happen to line up with the two regions, but the enterprise pool shares the `cn` credentials while billing a different account and serving a different roster — it needs its own switch, its own account binding, and its own model picks. That is exactly what a "panel" is. Keeping panel and region as two concepts lets `enterprise` ride the same settings pipeline with no change to the stored shape: it is just another slot in the `regions` map.
76
+
77
+ The CN region therefore publishes two providers side by side, and **the route is fixed when the provider's client is built** — there is no "guess once per call". The shim exposes one bearer route per provider and dispatches by bearer; an unknown token gets a 401 rather than falling back to the first route. The enterprise gateway requires a `session_id` on every call while the consumer gateway rejects a body carrying one, so it is added only on that route.
72
78
 
73
79
  Usage overview hits the read-only `https://api.trae.cn/trae/api/v2/pay/*` and `/trae/api/v2/ug/*` endpoints (international accounts read their own gateway's subscription status); the daily check-in claim is the one write among them, going to `POST /trae/api/v2/ug/checkin_credits/claim` with this installation's device id (`x-device-id`, the same identity the chat path sends). That device id is also what Trae keys the "one check-in per device per day" rule on, so switching accounts does not reset the day's slot. Refreshed tokens are kept per region in `$DSH_HOME/.trae-auth.cn.json` and `$DSH_HOME/.trae-auth.ai.json` (two simultaneously signed-in accounts never overwrite each other; the legacy single file `.trae-auth.json` is still read as a migration source).
74
80
 
@@ -138,7 +144,7 @@ Restart the DSH process after install/update/uninstall.
138
144
  ## DSH version compatibility
139
145
 
140
146
  **Requires DSH 0.1.7-rc.1 and up** (since 2.3.0 the plugin no longer targets hosts older than 0.1.7; the peer dependency ranges are narrowed accordingly).
141
- **The peer upper bound is `<0.3.0-0`, so both the 0.1.7 and the 0.2 line are supported (including 0.2.1-rc.1, verified).**
147
+ **The peer upper bound is `<0.3.0-0`, so both the 0.1.7 and the 0.2 line are supported (including 0.2.1-rc.2, verified).**
142
148
 
143
149
  ### Both pi-ai context generations are supported (since 3.4.2)
144
150
 
@@ -161,15 +167,15 @@ The boundary is **0.86**: `dist/utils/transcript.js`, `normalizeContext`, the es
161
167
 
162
168
  The 0.2.0 line breaks **no** contract this plugin consumes — a symbol-by-symbol check confirmed every API it imports is unchanged ([full 0.2.0-rc.1 impact check](https://github.com/dingminhua/dsh-connect-trae/blob/main/docs/DSH_0.2.0_RC1_IMPACT_CHECK.md)). But since 0.1.7 DSH enforces a **bundle-level peer gate**: a bundle whose peers are unsatisfied is skipped **whole**, with one line on stderr and nothing in the UI — the plugin simply disappears.
163
169
 
164
- ### DSH 0.2.1-rc.1 (pi-ai 1.1.0) sync
170
+ ### DSH 0.2.1 line (pi-ai 1.1.0) sync
165
171
 
166
- The `0.2.1-rc.1` host moved `@earendil-works/pi-ai` from `^0.85.1` to **`^1.1.0`** — the only change on the 0.2 line with real behavioural impact. Three conclusions:
172
+ The `0.2.1-rc.1` host moved `@earendil-works/pi-ai` from `^0.85.1` to **`^1.1.0`** (unchanged through `0.2.1-rc.2`) — the only change on the 0.2 line with real behavioural impact. Three conclusions:
167
173
 
168
174
  1. **The request body did not regress (measured, not inferred).** The 1.1.0 api reads the prompt **only** from a transcript system message and never touches top-level `systemPrompt` / `tools`, while `dsh-llm-pi-ai`'s `piContext()` still emits the legacy envelope. The bidirectional adapter this plugin has shipped since 3.4.2 covers exactly that: feeding the real host envelope through real `1.1.0` with a local SSE capture yields `roles: ["system","user"]`, an intact system text and `tools: 1`; **without the adapter it degenerates to `roles: ["user"]`, system `null`, `tools: 0`** — with no error. That contrast is pinned as a wire-level matrix in `tests/pi-ai-context.spec.ts`.
169
175
  2. **Types were fixed.** 1.1.0 changed `ProviderStreams`' second parameter to a **branded** `TranscriptContext` (a `unique symbol` only `normalizeContext()` can produce). The adapter casts once at that single boundary (`withContextAdaptation` in `src/adapter.ts`) and documents why the brand cannot be obtained honestly there.
170
- 3. **The peer range needed no change.** DSH evaluates with `semver.satisfies(runtime, range, { includePrerelease: true })` and checks only the `@deepseek-ai/dsh*` namespace, so `>=0.1.7-rc.1 <0.3.0-0` already admits `0.2.1-rc.1` (verified). Note the prerelease cliff only exists under **default** options — it is not this plugin's situation.
176
+ 3. **The peer range needed no change.** DSH evaluates with `semver.satisfies(runtime, range, { includePrerelease: true })` and checks only the `@deepseek-ai/dsh*` namespace, so `>=0.1.7-rc.1 <0.3.0-0` already admits both `0.2.1-rc.1` and `0.2.1-rc.2` (verified). Note the prerelease cliff only exists under **default** options — it is not this plugin's situation.
171
177
 
172
- The dev tree pins `@earendil-works/pi-ai` at exactly **1.1.0** (the version the host actually bundles) rather than `^1.1.0`, so local typecheck and tests run against the same contract users do; the `schemastery` override moved to `3.18.5` (`dsh-llm-pi-ai@0.2.1-rc.1` declares `~3.18.5`).
178
+ The dev tree pins `@earendil-works/pi-ai` at exactly **1.1.0** (the version the host actually bundles) rather than `^1.1.0`, so local typecheck and tests run against the same contract users do; the `schemastery` override moved to `3.18.5` (`dsh-llm-pi-ai@0.2.1-rc.2` declares `~3.18.5`).
173
179
 
174
180
 
175
181
  ### Why the upper bound is not `<0.2.0`
package/README.md CHANGED
@@ -24,7 +24,7 @@
24
24
  <a href="https://dshfind.com/plugins/dingminhua/dsh-connect-trae"><img src="https://dshfind.com/api/badge/dingminhua/dsh-connect-trae" alt="dshfind plugin"></a>
25
25
  </p>
26
26
 
27
- 一个独立的 [DeepSeek Harness (DSH)](https://github.com/deepseek-ai/deepseek-harness) bundle 插件。它把本机已登录的 Trae 账号(**国内版与国际版均支持**)接到 DSH 的模型选择器:模型负责生成结构化工具调用,`bash` / `read` / `write` / `edit` 等工具由 DSH 本地执行;同时提供用量概览(国内版 Work/通用积分、国际版订阅状态)、每日签到领取与模型管理界面。**国内版与国际版是两个并行的供应商(`trae` / `trae-global`),可同时使用**;插件设置卡片以 tab 区分两者,方便统一管理。
27
+ 一个独立的 [DeepSeek Harness (DSH)](https://github.com/deepseek-ai/deepseek-harness) bundle 插件。它把本机已登录的 Trae 账号(**国内版、企业版与国际版均支持**)接到 DSH 的模型选择器:模型负责生成结构化工具调用,`bash` / `read` / `write` / `edit` 等工具由 DSH 本地执行;同时提供用量概览(国内版 Work/通用积分、企业版租户额度、国际版订阅状态)、每日签到领取与模型管理界面。**国内版、企业版与国际版是三个并行的供应商(`trae` / `trae-enterprise` / `trae-global`),可同时使用**;插件设置卡片以 tab 区分三者,方便统一管理。
28
28
 
29
29
  **支持 macOS、Windows 与 Linux**:CI 在 `ubuntu-latest` 与 `windows-latest` 上跑完整 typecheck / 测试 / 构建;Windows 侧的目录探测、应用版本头与锁行为均有针对性处理,详见 [Windows 说明](#windows-说明)。
30
30
 
@@ -32,28 +32,33 @@
32
32
 
33
33
  ## 功能特性
34
34
 
35
- - **双供应商并行接入** —— 国内版注册为 DSH 的 `trae` provider(`DeepSeek-V4-Flash`、`DeepSeek-V4-Pro` 等),国际版注册为 `trae-global`(Gemini / GPT / MiniMax 阵容),**两边模型同时出现在 DSH 模型选择器里**:不同会话可以各选一边,互不干扰。
36
- - **可单独关闭任一版本** —— 两个 tab 各带一个勾选(默认都勾选):取消勾选即把该版本的供应商**整个从 DSH 模型选择器撤掉**(不是只藏起 tab),并且不再发起任何请求;重新勾选即恢复,账号、目录、勾选与上下文预算全部保留。用不到国际版就把国际版关掉即可。
37
- - **插件卡片 tab 切换** —— 设置卡片顶部为「国内版 / 国际版」两个 tab,各含独立的账号选择、用量概览与模型管理;每个 tab 的账号、目录、勾选与未保存草稿完全隔离——在一个 tab 里切账号或刷新模型,不会触碰另一边的运行时目录与会话。
35
+ - **三供应商并行接入** —— 国内版注册为 DSH 的 `trae` provider(`DeepSeek-V4-Flash`、`DeepSeek-V4-Pro` 等),企业版注册为 `trae-enterprise`,国际版注册为 `trae-global`(Gemini / GPT / MiniMax 阵容),**三边模型同时出现在 DSH 模型选择器里**:不同会话可以各选一边,互不干扰。
36
+ - **企业版是独立计费通道,不是国内版的别名** —— 同一张 CN 凭据若属于 `tob_online` 租户,会被**两个**网关同时服务:消费池(扣个人积分)与租户池(扣企业额度)。同一模型、两种付费方,所以「谁付钱」由你显式选,插件不替你猜。`trae` 永不碰企业网关;`trae-enterprise` **不回落**,被拒绝就如实报错,不会悄悄改用个人额度重跑。企业版**默认关闭**——纯个人账号用不了企业池,默认放开等于塞一条一用就失败的 provider。
37
+ - **可单独关闭任一面板** —— 三个 tab 各带一个勾选(国内版与国际版默认勾选,企业版默认不勾):取消勾选即把该面板的供应商**整个从 DSH 模型选择器撤掉**(不是只藏起 tab),并且不再发起任何请求;重新勾选即恢复,账号、目录、勾选与上下文预算全部保留。用不到国际版就把国际版关掉即可。
38
+ - **插件卡片 tab 切换** —— 设置卡片顶部为「国内版 / 企业版 / 国际版」三个 tab,各含独立的账号选择、用量概览与模型管理;每个 tab 的账号、目录、勾选与未保存草稿完全隔离——在一个 tab 里切账号或刷新模型,不会触碰另一边的运行时目录与会话。国内版与企业版共用同一份 CN 凭据池,但**各有各的账号绑定与模型勾选**:两个池的名录并不相同(`DeepSeek-V4.1-Flash` 只有企业池列),所以勾选互不覆盖。
39
+ - **账号池:自动选号 + 失败换号(默认关闭)** —— 本机读完几个账号后,「该用谁的额度」可以交给插件按规则排序:**先排除不可用的**(凭据被拒、套餐不覆盖、账号已不存在、限流未到重试时间、额度耗尽),再在可用账号里**优先快到期的那点额度**(与其放着过期,不如先花掉),最后才比总额、token 新鲜度,并以账号 id 兜底成**全序**(同样的输入永远得到同样的顺序,不会在两行之间来回抖)。三个面板**各有各的池**:国内版与企业版共用同一份 CN 凭据,但企业版只挑租户账号、国内版不会漂到租户号上。开着池时,发请求前先按上面的顺序选中一个账号,并且**真实请求失败会换下一个账号重试(最多 3 个)**——只有账号级失败才换(`401` 凭据被拒、额度耗尽、限流、上游 5xx);模型 id 写错、请求本身不合法**不换号**,因为那不是账号的问题,换号只会把同一个错误烧两遍、还冤枉一个没机会服务的账号。换号失败的真相会写进池的探针记录,下一次排序直接把它排到后面,而每一次结论都能在卡片上看到:`可用` / `限流` / `额度耗尽` / `凭据被拒` / `套餐不覆盖` / `上游不提供` / `本次未测出`,以及「什么时候可以重试」。**关掉池就回到严格绑定**,不会有任何残留 override。卡片里的「全部测速」会把每个成员按目标模型各测一次,结果**边跑边显示**(一行一个答案,不等整批跑完),并落盘成下次排序的依据。
40
+
41
+ > 池是**显式选择**:默认关闭。它不会替你在没打开池的情况下换账号——「换账号等于换人计费」,所以这件事只能由你点头。池打开后卡片会明确写出**当前是谁在付费**(Host 报告的是「下一个真正发送请求的账号」,不是保存的那个绑定)。
42
+
38
43
  - **倍率内嵌模型名** —— 模型名称按 Trae 自身菜单的格式显示积分倍率(如 `GLM-5.2 · x0.79`),倍率随目录刷新更新。
39
44
  - **DSH 本地工具循环** —— 通过 Trae `llm_utils_chat` 获取待执行的结构化 `tool_calls`,交由 DSH 自带的本地工具执行,再将工具结果回传模型。
40
45
  - **国内国际双区域自动识别** —— 自动发现 Trae CN / TRAE SOLO CN / Trae / TRAE SOLO 四个本地安装的登录账号;区域由凭证自带的 `userRegion` 声明自动判定(host 后缀与 edition 标签兜底),无需手动指定。
41
- - **目录与勾选按区域隔离** —— 国内版与国际版各一套模型目录、勾选、图片开关与上下文预算,两个供应商各自读各自的槽位。
46
+ - **目录与勾选按面板隔离** —— 三个面板各一套模型目录、勾选、图片开关与上下文预算,各自读各自的槽位。名录从**该面板所钉的那条网关**读取——原本钉在企业池的客户端去读消费池名录,会永远发现不了自己池的独占模型。
42
47
  - **识图能力跟随 Trae 自身的标注** —— Trae 把某个模型标为 `multimodal` 时,插件直接按多模态对外声明,无需你在卡片上逐一手勾(issue #16)。判据是「**你手动勾选的 ∪ Trae 标注多模态的**」:Trae 明确标 `false` 或未标注的模型保持纯文本,你可以照旧手动为它们打开图片输入。卡片上被自动开启的那一行显示为已勾选且只读,并说明原因。详见下方「图片输入(识图)」。
43
- - **多账号切换** —— 支持重新读取 Token 列表并选择账号;Token 不写入 DSH 设置。**你的选择会被记住并长期生效**:插件不会因为某个账号额度用尽、或检测到另一个可用账号就自作主张替你切换(换账号意味着换人计费)。所以当绑定的账号额度耗尽时,卡片会**明确告诉你**,并把本机其他还有额度的账号连同其可用积分数列出来,由你一键切换——而不是让面板一直空着、也不自动把你切走。「刷新账号与 Token」每次都会回报结果(找到几个账号、当前仍绑定谁),不会再「点了没反应」。下拉里显示的是产品名(`Trae` / `TRAE SOLO` / 国际版),便于分辨凭据来自哪个安装。
48
+ - **多账号切换** —— 支持重新读取 Token 列表并选择账号;Token 不写入 DSH 设置。**你的选择会被记住并长期生效**:插件不会因为某个账号额度用尽、或检测到另一个可用账号就自作主张替你切换(换账号意味着换人计费)——唯一的例外是你**亲自打开**的账号池(见下一条),那是一个显式选择,而不是插件的自作主张。所以当绑定的账号额度耗尽时,卡片会**明确告诉你**,并把本机其他还有额度的账号连同其可用积分数列出来,由你一键切换——而不是让面板一直空着、也不自动把你切走。「刷新账号与 Token」每次都会回报结果(找到几个账号、当前仍绑定谁),不会再「点了没反应」。下拉里显示的是产品名(`Trae` / `TRAE SOLO` / 国际版),便于分辨凭据来自哪个安装。
44
49
  - **跟随 Trae 当前登录的账号** —— 你在 Trae 桌面端**退出并换登录**后,卡片会检测到「插件绑定的账号」与「Trae 现在登录的账号」不一致,并给出一行提示与**一键切换**(复用账号下拉的同一次写入,不引入第二条切换路径)。想让插件**自动跟随**,可打开设置卡片里的「跟随 Trae 当前登录的账号」开关:此后每次配置生效都会把 `accounts.<region>` 重绑到 App 当前登录的账号。**该开关默认关闭**——已有配置保持原来的严格绑定,自动换绑意味着换人计费,必须由你主动勾选;未勾选时上面那行提示就是你的手动通道。(issue #29)
45
- - **账号导入 / 导出** —— 不用再为了用第二个账号而把凭据手工写进默认路径、顶掉上一个。在卡片账号区的「导入 / 导出账号」里:**导出**勾选若干账号下载一份 JSON;**导入**选择文件后先看**脱敏预览**(只显示账号标识与「是否有 Token」,不含凭据本身)再勾选导入。文件格式与同族 `dsh-connect-workbuddy` **互通**,两边导出的文件可以互相导入。导入按账号去重(同一账号再导入即覆盖更新),**认不出所属区域或因缺 Token 的记录会被跳过并计数**——国内版与国际版是两条并行计费通道,跨区导入会导致跨区计费,所以这里只认同能**正向识别**的区域。导出文件里是**有效 Token,请当作密码保管**。(issue #37)
50
+ - **账号导入 / 导出** —— 不用再为了用第二个账号而把凭据手工写进默认路径、顶掉上一个。在卡片账号区的「导入 / 导出账号」里:**导出**勾选若干账号下载一份 JSON;**导入**选择文件后先看**脱敏预览**(只显示账号标识与「是否有 Token」,不含凭据本身)再勾选导入。文件格式与同族 `dsh-connect-workbuddy` **互通**,两边导出的文件可以互相导入。导入按账号去重(同一账号再导入即覆盖更新),**认不出所属区域或因缺 Token 的记录会被跳过并计数**——国内版与国际版是两条并行计费通道,跨区导入会导致跨区计费,所以这里只认同能**正向识别**的区域(企业版共用 CN 凭据池,不构成第三条导入通道)。导出文件里是**有效 Token,请当作密码保管**。(issue #37)
46
51
  - **只读用量与模型管理** —— 国内版查看 Work 积分与通用积分,国际版查看订阅/试用状态;刷新/启用 Trae 模型;只读查询不消耗额度。
47
52
  - **积分临近到期会提醒** —— 剩余额度只回答「还有多少」,回答不了「**哪一笔先到期**」;提醒条按到期紧迫程度逐级加重(**7 天 → 24 小时 → 已过期**),写明金额、套餐数和最早到期时间,避免只盯总额时悄悄丢掉最先到期的额度。国内版在用量页与输入框积分面板两处都显示(国际版是订阅制,没有逐包到期数据)。
48
53
  - **一键测试启用模型** —— 给**已启用**的每个模型发一条最小消息(一句 `ping`、不带工具),逐个告诉你能不能真的应答:**可用** / **需要更高档位**(Trae `1005`,你的套餐不覆盖)/ **上游不提供**(`4001`,SOLO 通道没有这个模型)/ **被限流**(`4011`,Trae 限了这条通道)/ **登录凭据被拒** / **本次未测出**。最后一项是一等公民:超时、断连、代理、5xx **一律不算「不可用」**——只有上游明确的拒绝才算负面结论。**这是插件里唯一消耗额度的操作**(签到改变的是账号状态,不消耗),只在你点击时运行,结果只留在当前会话里不写入设置。
49
54
  > `4011` 是**限流**不是「模型不可用」(issue #33 实测):它额度耗尽走的是另一个码 `4008`,所以「额度还有很多却报 4011」两句话可以同时成立。被限流的模型**等你一会儿再试**即可,不要删。
50
55
  - **一键测试所有模型** —— 同一套探测,作用于当前 region 的**全部可见模型**(不限于已启用的)。想知道「没启用的那些到底还能不能用」时用它——比如套餐降级后,或 Trae 调整了模型阵容之后。
51
- - **每日签到领取(逐账号)** —— 国内版**每个账号行各有一个签到按钮**,当日奖励直接写在按钮上(`签到 +150`);该账号当天已领显示「已领取」并禁用,**本机今日名额已被别的账号用掉**时显示「本机已签」并禁用——如实区分「这个账号领了」和「这台设备领过了」,绝不把后者说成「已领取」。这是插件里**唯一会改变账号状态**的操作,由你主动点击触发;一次点击只针对该行账号、只发一次请求,**刻意没有「一键全签」**——Trae 的签到按「**每台设备每天一次**」计(换账号不会重置当天名额),批量只会酿成一排假失败。国际版没有签到活动,因此不显示该按钮。
56
+ - **每日签到领取(逐账号)** —— 国内版**每个账号行各有一个签到按钮**,当日奖励直接写在按钮上(`签到 +150`);该账号当天已领显示「已领取」并禁用,**本机今日名额已被别的账号用掉**时显示「本机已签」并禁用——如实区分「这个账号领了」和「这台设备领过了」,绝不把后者说成「已领取」。这是插件里**唯一会改变账号状态**的操作,由你主动点击触发;一次点击只针对该行账号、只发一次请求。Trae 的签到按「**每台设备每天一次**」计(换账号不会重置当天名额),所以逐账号签到始终是主路径。账号池里另有一个「全部签到」,它**不是**把同一件事盲目重复:一旦上游回 `9095`(本机今日已领),整批立刻停止并把剩余账号如实标成「本机已签」,产出的是真相而不是一排假失败。国际版没有签到活动,因此不显示该按钮。
52
57
  - **输入框读数** —— 在输入框工具栏(「专家」与模型选择器之间)显示一块可点击读数,5 分钟自动刷新。**两个区域都显示,但显示的东西不同,这是数据决定的**:国内版是积分制,显示「Trae CN · <通用积分>」;国际版是订阅制,它的用量文档里根本没有积分字段,所以显示「Trae 国际版 · <套餐>」(如 `Pro` / `Free`)。**整块可点击**,弹出浮层显示一张**表格**:本区域**每个账号一行**,国内版列**通用积分**、国际版列**套餐**,**点行即可切换账号**(写入与卡片相同的 `accounts` 字段、合并时不丢掉另一个区域的选择),并把手动刷新按钮放在浮层里。**只在当前会话选中的模型属于本插件时出现**——选其它供应商的模型时整块不渲染。这样两个连接器插件不会争同一个位置(侧边栏底部是共享的根级行,输入框工具栏是按会话、按供应商的)。
53
58
 
54
59
  <img src="docs/assets/dsh-connect-trae-composer-credits.png" width="536" alt="Trae credits panel: a table of accounts with their general balance, and the composer readout below" />
55
60
 
56
- **读数显示在哪里可以选**(学自同族 `dsh-connect-workbuddy` issue #62)。默认在**输入框工具栏**(即上面说的位置);如果那里被别的插件占了、读数不显示,改成**输入框下方**——那是「轮次 / 步数 / token」统计所在的那一行,读数是**追加**在官方统计之后,不会顶掉它们。位置**按区域分别设置**(国内版与国际版各存各的),在卡片「设置」区紧挨「在输入框工具栏显示积分读数」那个勾选框。之所以要有第二个位置:输入框工具栏是**共享的 list 插槽**,外壳自己的控件和其他插件都注册在那里,而共享插槽**无法保证每个占用者都可见**——同族的报告者装了第三方插件后读数就整个消失了(本插件早年放在侧边栏底部时也被挤成过一个「Tr」的残片)。
61
+ **读数显示在哪里可以选**(学自同族 `dsh-connect-workbuddy` issue #62)。默认在**输入框工具栏**(即上面说的位置);如果那里被别的插件占了、读数不显示,改成**输入框下方**——那是「轮次 / 步数 / token」统计所在的那一行,读数是**追加**在官方统计之后,不会顶掉它们。位置**按面板分别设置**(三个面板各存各的),在卡片「设置」区紧挨「在输入框工具栏显示积分读数」那个勾选框。之所以要有第二个位置:输入框工具栏是**共享的 list 插槽**,外壳自己的控件和其他插件都注册在那里,而共享插槽**无法保证每个占用者都可见**——同族的报告者装了第三方插件后读数就整个消失了(本插件早年放在侧边栏底部时也被挤成过一个「Tr」的残片)。
57
62
 
58
63
  - **安全 loopback shim** —— 每区域一个随机端口 + 进程内随机 secret,真实 Trae token 不交给 pi-ai。
59
64
 
@@ -64,13 +69,18 @@ DSH PiAiAdapter(每个 provider 一套)
64
69
  -> 安全 loopback shim(每区域一个随机端口 + 进程内随机 secret)
65
70
  -> TraeSoloBridge
66
71
  -> 国内版 https://trae-api-cn.mchost.guru/api/agent/v3/llm_utils_chat
72
+ -> 企业版 https://console.enterprise.trae.cn/api/agent/v3/llm_utils_chat
67
73
  -> 国际版 https://coresg-normal.trae.ai/api/agent/v3/llm_utils_chat
68
74
  -> Trae SSE / pending function_call
69
75
  -> OpenAI SSE tool_calls
70
76
  -> DSH 本地执行工具并回传结果
71
77
  ```
72
78
 
73
- 国内版与国际版各持一套完整的运行时栈——凭据 store、模型 catalog、wire 映射、上游客户端、回环 shim、adapter——按凭证自带的区域声明隔离可见账号,所以**两个区域的账号可以同时在线、同时被不同会话使用**。
79
+ 每个面板各持一套完整的运行时栈——凭据 store、模型 catalog、wire 映射、上游客户端、回环 shim、adapter——按凭证自带的区域声明隔离可见账号,所以**多个区域的账号可以同时在线、同时被不同会话使用**。
80
+
81
+ **面板不是区域。** `cn` 与 `ai` 恰好与两个区域一一对应,但企业池共用 `cn` 凭据却计费到另一个账户、供另一份名录,它需要自己的开关、自己的账号绑定与自己的模型选择——那正是「面板」这个概念。把面板与区域分成两个概念,`enterprise` 就能用同一套设置管道处理,存储形状不变:它只是 `regions` 映射里的又一个槽位。
82
+
83
+ 国内区因此并列发布两个 provider,**路由在构建 provider 的客户端时固定**,不存在「按调用猜一次」:shim 为每个 provider 提供一条 bearer 路由并按 bearer 分派,未知 token 直接 401,不会退回第一条路由。企业网关要求每次调用带 `session_id`,而消费网关会拒绝带它的请求体,所以只在该路由上加。
74
84
 
75
85
  用量概览走 `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` 作为迁移来源保留读取)。
76
86
 
@@ -96,7 +106,7 @@ DSH PiAiAdapter(每个 provider 一套)
96
106
 
97
107
  ## 模型覆盖范围
98
108
 
99
- 插件提供的是 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-*` 等),国内版与国际版均走这条通道。
109
+ 插件提供的是 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` 只有企业池列),所以两边勾选互不覆盖。
100
110
 
101
111
  以下 3 个模型目前来自 **TraeCode(Trae IDE)通道**,尚未开放到 SOLO 通道:
102
112
 
@@ -150,7 +160,7 @@ npm install dsh-connect-trae
150
160
  ## DSH 版本兼容
151
161
 
152
162
  **要求 DSH 0.1.7-rc.1 及以上**(2.3.0 起不再支持 0.1.7 之前的宿主;peer 依赖范围已按此收窄)。
153
- **peer 上界为 `<0.3.0-0`:0.1.7 与 0.2 两条线均受支持(含 0.2.1-rc.1,已实测)。**
163
+ **peer 上界为 `<0.3.0-0`:0.1.7 与 0.2 两条线均受支持(含 0.2.1-rc.2,已实测)。**
154
164
 
155
165
  ### 同时支持 pi-ai 的两代上下文(3.4.2 起)
156
166
 
@@ -182,9 +192,9 @@ DSH 自己横跨 `@earendil-works/pi-ai` 的两代,而**本插件解析到哪
182
192
  0.2.0 线对本插件**没有契约破坏**——逐符号核对确认插件消费的 API 全部未变([完整的 0.2.0-rc.1 影响面核对](https://github.com/dingminhua/dsh-connect-trae/blob/main/docs/DSH_0.2.0_RC1_IMPACT_CHECK.md))。但 0.1.7 起 DSH 有一道**bundle 级 peer 门禁**:
183
193
  peer 范围不满足的 bundle 会被**整体跳过**,只往 stderr 写一行,界面上表现为「插件凭空消失」。
184
194
 
185
- ### DSH 0.2.1-rc.1(pi-ai 1.1.0)同步结论
195
+ ### DSH 0.2.1 线(pi-ai 1.1.0)同步结论
186
196
 
187
- 宿主 `0.2.1-rc.1` 把 `@earendil-works/pi-ai` 从 `^0.85.1` 抬到了 **`^1.1.0`**,这是 0.2 线里
197
+ 宿主 `0.2.1-rc.1` 把 `@earendil-works/pi-ai` 从 `^0.85.1` 抬到了 **`^1.1.0`**(`0.2.1-rc.2` 保持不变),这是 0.2 线里
188
198
  唯一有实际行为影响的变化。三项结论:
189
199
 
190
200
  1. **请求体没有丢东西(已实测)**。1.1.0 的 api **只**读 transcript 里的 system 消息,
@@ -197,13 +207,13 @@ peer 范围不满足的 bundle 会被**整体跳过**,只往 stderr 写一行
197
207
  `TranscriptContext`,只有 `normalizeContext()` 能产出。适配层在这条边界上做一次显式转型
198
208
  (`src/adapter.ts` 的 `withContextAdaptation`),并在两处调用点写明为何品牌在此处不可诚实获得。
199
209
  3. **peer 范围无需改动**。DSH 用 `semver.satisfies(runtime, range, { includePrerelease: true })`
200
- 求值,且只校验 `@deepseek-ai/dsh*` 命名空间,因此 `>=0.1.7-rc.1 <0.3.0-0` 对 `0.2.1-rc.1` 已判通过
210
+ 求值,且只校验 `@deepseek-ai/dsh*` 命名空间,因此 `>=0.1.7-rc.1 <0.3.0-0` 对 `0.2.1-rc.1` / `0.2.1-rc.2` 均已判通过
201
211
  (已实测)。**注意**:预发布悬崖只在**默认选项**下成立——那是 `dsh-connect-workbuddy` 侧
202
212
  调研文档所描述的困境,本插件不适用。
203
213
 
204
214
  开发树的 `@earendil-works/pi-ai` 钉在 **1.1.0**(宿主实际随包的版本)而非 `^1.1.0`,
205
215
  使本地 typecheck 与测试跑在与用户完全一致的契约上;`schemastery` 的 override 同步抬到
206
- `3.18.5`(`dsh-llm-pi-ai@0.2.1-rc.1` 声明 `~3.18.5`)。
216
+ `3.18.5`(`dsh-llm-pi-ai@0.2.1-rc.2` 声明 `~3.18.5`)。
207
217
 
208
218
 
209
219
  ### peer 上界为什么不写 `<0.2.0`