dsh-connect-trae 2.0.6 → 2.1.0
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 +15 -0
- package/README.en.md +6 -3
- package/README.md +6 -3
- package/lib/client.js +115 -0
- package/lib/index.d.ts +102 -5
- package/lib/index.js +128 -23
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 2.1.0 (2026-09-24)
|
|
4
|
+
|
|
5
|
+
### Features
|
|
6
|
+
|
|
7
|
+
- **新增「每日签到领取」**(对齐 `dsh-connect-workbuddy` 的签到能力):
|
|
8
|
+
- **交互**:国内版卡片在积分面板下方多一行签到:显示每日奖励(基础 + 额外,本机实测 `150 + 50`)与一个「立即领取」按钮;领取中显示「领取中…」,当日已领取显示「今日已领取」并禁用。国际版没有签到活动,因此**不显示该行**。
|
|
9
|
+
- **这是插件里唯一的写操作**,也是唯一会改变账号状态的调用(`POST /trae/api/v2/ug/checkin_credits/claim`);其余查询全部只读。README 顶部与特性列表都按此措辞改写,不再把整个用量面板称为「只读」。
|
|
10
|
+
- **根因级发现:缺 `x-device-id` 会被静默拒绝**。同一份 Authorization,只加这一个头,结果从「HTTP 200 + 业务码 `9004`(The submitted order parameters are incorrect)」变成「`code: 0`,奖励到账」——**HTTP 状态始终是 200**,只看状态码会把它误判为成功。设备号取自本机 `iCubeAuthInfo://icube-dc:<id>`,即 `identity.ts` 里聊天通道同源的那个 `deviceId`(官方客户端在 `main.js` 的 `fb(headers)` 里给每个 ug 请求都补上它)。`deviceId` 由 `index.ts` 惰性注入;读不到时降级为不发该头——**只影响领取,不影响状态查询**(状态接口两种情况下都正常返回)。
|
|
11
|
+
- **领取前的守卫比上游更强**:路由 `POST /plugins/dsh-connect-trae/checkin` 仅接受 POST、仅接受回环来源、仅服务 `cn` 区域,并且**先读状态**——已领取(`checked_in` 或 `did_checked_in` 任一为真)就直接返回 `alreadyCheckedIn` 且**根本不发领取请求**;活动关闭答 409。国际版直接答 404 并说明原因,而不是把上游的 HTML 404 当成网络故障抛给用户。
|
|
12
|
+
- **已实测上游按北京自然日幂等**:重复领取仍回 `code: 0`,而权益总额(`total=1600, consumed=390.8`)逐字节不变,**不会重复发放**。插件仍然自行守卫——「不会重复发放」是上游的行为,不是插件可以依赖的保证。
|
|
13
|
+
- **业务拒绝不当成故障**:`claimed: false` + 原始业务码与 message 原样回给卡片并显示出来,而不是包成 500。否则用户只会看到「领取失败」,而丢掉唯一能解释原因的 `9004`。
|
|
14
|
+
- **对齐官方客户端的状态判定**:`checked_in` 与 `did_checked_in` 是**两个独立字段**,官方在「今日已领取」上同时看后者(即使状态读回 `checked_in: false` 也保持按钮禁用)。插件在**卡片与路由两侧都**按同一规则判定,`extra_credits` 也一并展示,避免把当天实际到账的 200 说成 150。
|
|
15
|
+
- 卡片新增 8 条真实点击测试(`tests/card-checkin.spec.tsx`,渲染**真组件**、`fireEvent.click` 真按钮、断言真发出去的请求),`usage.spec.ts` 补 6 条、`web-status.spec.ts` 补 7 条,共 21 条新测试(全仓 261 → 282)。做过**变异验证**:去掉路由的 `did_checked_in` 守卫 → 2 条失败;去掉卡片的同款判定 → 1 条失败;把卡片的 `POST` 改成 `GET` → 1 条失败;删掉「已领取则不发请求」的守卫 → 2 条失败。
|
|
16
|
+
- 取证与接口契约:`docs/USAGE_API_RESEARCH.md` 新增「每日签到领取」一节(含决定性请求头对照表、幂等性实测表、区域限制与官方字段语义)。
|
|
17
|
+
|
|
3
18
|
## 2.0.6 (2026-09-22)
|
|
4
19
|
|
|
5
20
|
### Features
|
package/README.en.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
<h1 align="center">dsh-connect-trae</h1>
|
|
6
6
|
|
|
7
|
-
<p align="center"><b>Connect locally signed-in Trae models to DeepSeek Harness with local DSH tools and
|
|
7
|
+
<p align="center"><b>Connect locally signed-in Trae models to DeepSeek Harness with local DSH tools, a credits overview, and daily check-in claiming.</b></p>
|
|
8
8
|
|
|
9
9
|
<p align="center">
|
|
10
10
|
<a href="README.md">中文</a> ·
|
|
@@ -24,7 +24,9 @@
|
|
|
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
|
|
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.
|
|
28
|
+
|
|
29
|
+
> Apart from the daily check-in claim, every query this plugin makes is read-only and consumes nothing; the claim only happens when you click the button.
|
|
28
30
|
|
|
29
31
|
## Features
|
|
30
32
|
|
|
@@ -37,6 +39,7 @@ A [DeepSeek Harness (DSH)](https://github.com/deepseek-ai/deepseek-harness) bund
|
|
|
37
39
|
- **Region-isolated directories and selections** — CN and international each keep their own model directory, enabled picks, image opt-ins, and context budgets, and each provider reads only its own slot.
|
|
38
40
|
- **Account switching** — refreshes the token list and lets users select an account without storing tokens in DSH settings.
|
|
39
41
|
- **Read-only usage and model management** — Work/general credits on CN accounts, subscription/trial status on international ones; enable Trae models freely. Read-only queries consume nothing.
|
|
42
|
+
- **Daily check-in claiming** — a one-click claim on the CN card (the button shows the daily reward, and reads "Claimed today" and disables itself once done). This is the plugin's **only** operation that changes account state, and it runs only when you click. The international side has no check-in activity, so no button is shown there.
|
|
40
43
|
- **Secure loopback shim** — one random port + in-process random secret per region; the real Trae token is never handed to pi-ai.
|
|
41
44
|
|
|
42
45
|
## How it works
|
|
@@ -54,7 +57,7 @@ DSH PiAiAdapter (one stack per provider)
|
|
|
54
57
|
|
|
55
58
|
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**.
|
|
56
59
|
|
|
57
|
-
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). 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).
|
|
60
|
+
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). 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).
|
|
58
61
|
|
|
59
62
|
> See `docs/IMPLEMENTATION_PLAN.md`, `docs/SOLO_ROUTE_DECISION.md`, `docs/USAGE_API_RESEARCH.md`.
|
|
60
63
|
|
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
<h1 align="center">dsh-connect-trae</h1>
|
|
6
6
|
|
|
7
|
-
<p align="center"><b>把本机登录的 Trae 模型接入 DeepSeek Harness
|
|
7
|
+
<p align="center"><b>把本机登录的 Trae 模型接入 DeepSeek Harness,并提供用量/积分概览与每日签到领取。</b></p>
|
|
8
8
|
|
|
9
9
|
<p align="center">
|
|
10
10
|
<a href="README.en.md">English</a> ·
|
|
@@ -24,7 +24,9 @@
|
|
|
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
|
|
27
|
+
一个独立的 [DeepSeek Harness (DSH)](https://github.com/deepseek-ai/deepseek-harness) bundle 插件。它把本机已登录的 Trae 账号(**国内版与国际版均支持**)接到 DSH 的模型选择器:模型负责生成结构化工具调用,`bash` / `read` / `write` / `edit` 等工具由 DSH 本地执行;同时提供用量概览(国内版 Work/通用积分、国际版订阅状态)、每日签到领取与模型管理界面。**国内版与国际版是两个并行的供应商(`trae` / `trae-global`),可同时使用**;插件设置卡片以 tab 区分两者,方便统一管理。
|
|
28
|
+
|
|
29
|
+
> 除每日签到领取外,插件的所有查询都是只读的、不消耗额度;签到领取也只在你点击按钮时才发生。
|
|
28
30
|
|
|
29
31
|
## 功能特性
|
|
30
32
|
|
|
@@ -37,6 +39,7 @@
|
|
|
37
39
|
- **目录与勾选按区域隔离** —— 国内版与国际版各一套模型目录、勾选、图片开关与上下文预算,两个供应商各自读各自的槽位。
|
|
38
40
|
- **多账号切换** —— 支持重新读取 Token 列表并选择账号;Token 不写入 DSH 设置。
|
|
39
41
|
- **只读用量与模型管理** —— 国内版查看 Work 积分与通用积分,国际版查看订阅/试用状态;刷新/启用 Trae 模型;只读查询不消耗额度。
|
|
42
|
+
- **每日签到领取** —— 国内版卡片上一键领取当日签到积分(按钮显示每日奖励,已领取则显示「今日已领取」并禁用);这是插件里**唯一会改变账号状态**的操作,由你主动点击触发。国际版没有签到活动,因此不显示该按钮。
|
|
40
43
|
- **安全 loopback shim** —— 每区域一个随机端口 + 进程内随机 secret,真实 Trae token 不交给 pi-ai。
|
|
41
44
|
|
|
42
45
|
## 工作原理
|
|
@@ -54,7 +57,7 @@ DSH PiAiAdapter(每个 provider 一套)
|
|
|
54
57
|
|
|
55
58
|
国内版与国际版各持一套完整的运行时栈——凭据 store、模型 catalog、wire 映射、上游客户端、回环 shim、adapter——按凭证自带的区域声明隔离可见账号,所以**两个区域的账号可以同时在线、同时被不同会话使用**。
|
|
56
59
|
|
|
57
|
-
用量概览走 `https://api.trae.cn/trae/api/v2/pay/*` 与 `/trae/api/v2/ug/*`
|
|
60
|
+
用量概览走 `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` 作为迁移来源保留读取)。
|
|
58
61
|
|
|
59
62
|
> 详见 `docs/IMPLEMENTATION_PLAN.md`、`docs/SOLO_ROUTE_DECISION.md`、`docs/USAGE_API_RESEARCH.md`。
|
|
60
63
|
|
package/lib/client.js
CHANGED
|
@@ -14,6 +14,11 @@ window.__ModuleLoader__.load({
|
|
|
14
14
|
const TRAE_MODELS_REFRESH_PATH = "/plugins/dsh-connect-trae/models/refresh";
|
|
15
15
|
/** Plugin-owned local account rescan endpoint. */
|
|
16
16
|
const TRAE_ACCOUNTS_REFRESH_PATH = "/plugins/dsh-connect-trae/accounts/refresh";
|
|
17
|
+
/**
|
|
18
|
+
* Plugin-owned daily check-in claim endpoint. POST, loopback-only, and the only
|
|
19
|
+
* route in this plugin that changes upstream account state.
|
|
20
|
+
*/
|
|
21
|
+
const TRAE_CHECKIN_PATH = "/plugins/dsh-connect-trae/checkin";
|
|
17
22
|
/** Query parameter naming the region a card request addresses. */
|
|
18
23
|
const TRAE_REGION_PARAM = "region";
|
|
19
24
|
/** Every region, in card tab order. */
|
|
@@ -209,6 +214,11 @@ window.__ModuleLoader__.load({
|
|
|
209
214
|
.dsm-trae-searched-list code{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:11px;line-height:16px;color:var(--dsw-alias-label-secondary,#b8b8b8);word-break:break-all}
|
|
210
215
|
.dsm-trae-searched-reason{color:var(--dsw-alias-label-tertiary,#999);font-size:11px}
|
|
211
216
|
.dsm-trae-usage-cheer:focus-visible{outline:2px solid var(--dsw-alias-brand-primary,#5686fe);outline-offset:2px}
|
|
217
|
+
.dsm-trae-checkin{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:12px 16px;border:1px solid var(--dsw-alias-border-l2,#3a3d45);border-radius:14px;background:var(--dsw-alias-bg-layer-2,#24262c)}
|
|
218
|
+
.dsm-trae-checkin-copy{display:flex;flex-direction:column;gap:2px;min-width:0}
|
|
219
|
+
.dsm-trae-checkin-label{color:var(--dsw-alias-label-primary,#e6e6e6);font-size:13px;line-height:18px;font-weight:600}
|
|
220
|
+
.dsm-trae-checkin-hint{color:var(--dsw-alias-label-tertiary,#9aa0a8);font-size:12px;line-height:17px}
|
|
221
|
+
.dsm-trae-checkin-button{flex:none}
|
|
212
222
|
`;
|
|
213
223
|
//#endregion
|
|
214
224
|
//#region src/client/TraeUsageCard.tsx
|
|
@@ -286,6 +296,14 @@ window.__ModuleLoader__.load({
|
|
|
286
296
|
const [switchingAccount, setSwitchingAccount] = (0, react.useState)(false);
|
|
287
297
|
/** Region whose on/off checkbox write is in flight, so its box can't race. */
|
|
288
298
|
const [togglingRegion, setTogglingRegion] = (0, react.useState)(void 0);
|
|
299
|
+
/**
|
|
300
|
+
* Whether a check-in claim is in flight. A single flag rather than a
|
|
301
|
+
* per-region map: the claim exists only on the CN tab, and one shared flag
|
|
302
|
+
* keeps a tab switch from stranding a second concurrent claim.
|
|
303
|
+
*/
|
|
304
|
+
const [claiming, setClaiming] = (0, react.useState)(false);
|
|
305
|
+
/** Last claim refusal, shown until the next successful refresh. */
|
|
306
|
+
const [claimError, setClaimError] = (0, react.useState)(void 0);
|
|
289
307
|
const mounted = (0, react.useRef)(true);
|
|
290
308
|
(0, react.useEffect)(() => {
|
|
291
309
|
mounted.current = true;
|
|
@@ -354,6 +372,14 @@ window.__ModuleLoader__.load({
|
|
|
354
372
|
status: "signed-out",
|
|
355
373
|
accounts: []
|
|
356
374
|
};
|
|
375
|
+
/**
|
|
376
|
+
* Drop a claim refusal when the tab changes. The error belongs to the region
|
|
377
|
+
* it came from — carrying it onto the other tab would attribute an
|
|
378
|
+
* international account's problem to the CN one (or the reverse).
|
|
379
|
+
*/
|
|
380
|
+
(0, react.useEffect)(() => {
|
|
381
|
+
setClaimError(void 0);
|
|
382
|
+
}, [activeRegion]);
|
|
357
383
|
(0, react.useEffect)(() => {
|
|
358
384
|
if (!open || !activeRegionOn || status.status !== "signed-in") return;
|
|
359
385
|
const controller = new AbortController();
|
|
@@ -407,6 +433,38 @@ window.__ModuleLoader__.load({
|
|
|
407
433
|
}
|
|
408
434
|
};
|
|
409
435
|
/**
|
|
436
|
+
* Claim today's check-in reward for the active tab's region.
|
|
437
|
+
*
|
|
438
|
+
* The Host route owns every guard that matters — POST only, loopback origin
|
|
439
|
+
* only, CN only, and a status read before the claim — because a browser-side
|
|
440
|
+
* check is not a guard. The button's own `disabled` is therefore a courtesy
|
|
441
|
+
* (it stops an obviously pointless click), not the protection.
|
|
442
|
+
*
|
|
443
|
+
* A refusal is not thrown away: the route answers `claimed: false` with the
|
|
444
|
+
* upstream's business code and message, and the card shows it. The upstream
|
|
445
|
+
* also reports success for an already-claimed day, so `alreadyCheckedIn`
|
|
446
|
+
* refreshes the state without pretending a new reward landed.
|
|
447
|
+
*/
|
|
448
|
+
const claimCheckin = async () => {
|
|
449
|
+
setClaiming(true);
|
|
450
|
+
setClaimError(void 0);
|
|
451
|
+
try {
|
|
452
|
+
const response = await fetch(withTraeRegion(TRAE_CHECKIN_PATH, activeRegion), {
|
|
453
|
+
method: "POST",
|
|
454
|
+
headers: { accept: "application/json" },
|
|
455
|
+
credentials: "same-origin"
|
|
456
|
+
});
|
|
457
|
+
const body = await response.json().catch(() => void 0);
|
|
458
|
+
if (!response.ok) throw new Error(body?.error ?? `HTTP ${response.status}`);
|
|
459
|
+
if (body?.claimed === false && body.alreadyCheckedIn !== true) throw new Error(body.message === void 0 || body.message === "" ? t("row.checkinRefused", { code: String(body.code ?? "") }) : `${t("row.checkinRefused", { code: String(body.code ?? "") })}: ${body.message}`);
|
|
460
|
+
await refreshUsage(activeRegion);
|
|
461
|
+
} catch (error) {
|
|
462
|
+
if (mounted.current) setClaimError(error instanceof Error ? error.message : t("row.requestFailed"));
|
|
463
|
+
} finally {
|
|
464
|
+
if (mounted.current) setClaiming(false);
|
|
465
|
+
}
|
|
466
|
+
};
|
|
467
|
+
/**
|
|
410
468
|
* Switch one region's provider off or on (issue #11). The write carries the
|
|
411
469
|
* region's whole slot through untouched — only `enabled` changes — so the
|
|
412
470
|
* user's directory, model picks, image opt-ins and budgets survive a
|
|
@@ -787,6 +845,45 @@ window.__ModuleLoader__.load({
|
|
|
787
845
|
className: "dsm-trae-usage-error",
|
|
788
846
|
children: t("row.creditsError", { message: status.creditsError })
|
|
789
847
|
}),
|
|
848
|
+
status.checkin === void 0 ? null : (() => {
|
|
849
|
+
const done = status.checkin.checkedIn || status.checkin.didCheckedIn;
|
|
850
|
+
const reward = formatNumber(status.checkin.credits);
|
|
851
|
+
const bonus = status.checkin.extraCredits === void 0 ? "" : ` + ${formatNumber(status.checkin.extraCredits)}`;
|
|
852
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
853
|
+
className: "dsm-trae-checkin",
|
|
854
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
855
|
+
className: "dsm-trae-checkin-copy",
|
|
856
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
857
|
+
className: "dsm-trae-checkin-label",
|
|
858
|
+
children: t("row.checkinLabel")
|
|
859
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
860
|
+
className: "dsm-trae-checkin-hint",
|
|
861
|
+
children: [t("row.checkinReward", { reward: `${reward}${bonus}` }), done ? ` · ${t("row.checkinDoneHint")}` : ""]
|
|
862
|
+
})]
|
|
863
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
864
|
+
type: "button",
|
|
865
|
+
className: "dsm-btn dsm-btn-primary dsm-trae-checkin-button",
|
|
866
|
+
disabled: !status.checkin.enabled || done || claiming,
|
|
867
|
+
onClick: () => {
|
|
868
|
+
claimCheckin();
|
|
869
|
+
},
|
|
870
|
+
children: claiming ? t("row.checkinClaiming") : done ? t("row.checkinClaimed") : t("row.checkinClaim")
|
|
871
|
+
})]
|
|
872
|
+
});
|
|
873
|
+
})(),
|
|
874
|
+
status.checkin !== void 0 && !status.checkin.enabled ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
875
|
+
className: "dsm-trae-usage-error",
|
|
876
|
+
children: t("row.checkinDisabled")
|
|
877
|
+
}) : null,
|
|
878
|
+
status.checkinError === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
879
|
+
className: "dsm-trae-usage-error",
|
|
880
|
+
children: t("row.checkinError", { message: status.checkinError })
|
|
881
|
+
}),
|
|
882
|
+
claimError === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
883
|
+
className: "dsm-trae-usage-error",
|
|
884
|
+
role: "alert",
|
|
885
|
+
children: t("row.checkinError", { message: claimError })
|
|
886
|
+
}),
|
|
790
887
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
791
888
|
className: "dsm-trae-models",
|
|
792
889
|
"aria-label": t("row.modelsTitle"),
|
|
@@ -995,6 +1092,15 @@ window.__ModuleLoader__.load({
|
|
|
995
1092
|
"row.creditsConsumedLabel": "Consumed",
|
|
996
1093
|
"row.creditsTotalLabel": "Total",
|
|
997
1094
|
"row.creditsError": "Usage unavailable: {message}",
|
|
1095
|
+
"row.checkinLabel": "Daily check-in",
|
|
1096
|
+
"row.checkinReward": "{reward} credits per day",
|
|
1097
|
+
"row.checkinClaim": "Claim today",
|
|
1098
|
+
"row.checkinClaiming": "Claiming…",
|
|
1099
|
+
"row.checkinClaimed": "Claimed today",
|
|
1100
|
+
"row.checkinDoneHint": "come back tomorrow",
|
|
1101
|
+
"row.checkinRefused": "Trae refused the check-in (code {code})",
|
|
1102
|
+
"row.checkinError": "Check-in failed: {message}",
|
|
1103
|
+
"row.checkinDisabled": "This account has no check-in activity available.",
|
|
998
1104
|
"row.regionCn": "CN",
|
|
999
1105
|
"row.regionAi": "International",
|
|
1000
1106
|
"row.subscriptionLabel": "Subscription",
|
|
@@ -1063,6 +1169,15 @@ window.__ModuleLoader__.load({
|
|
|
1063
1169
|
"row.creditsConsumedLabel": "消耗",
|
|
1064
1170
|
"row.creditsTotalLabel": "合计",
|
|
1065
1171
|
"row.creditsError": "用量查询失败:{message}",
|
|
1172
|
+
"row.checkinLabel": "每日签到",
|
|
1173
|
+
"row.checkinReward": "每日 {reward} 积分",
|
|
1174
|
+
"row.checkinClaim": "立即领取",
|
|
1175
|
+
"row.checkinClaiming": "领取中…",
|
|
1176
|
+
"row.checkinClaimed": "今日已领取",
|
|
1177
|
+
"row.checkinDoneHint": "明天再来",
|
|
1178
|
+
"row.checkinRefused": "Trae 拒绝了本次签到(业务码 {code})",
|
|
1179
|
+
"row.checkinError": "签到失败:{message}",
|
|
1180
|
+
"row.checkinDisabled": "该账号当前没有可用的签到活动。",
|
|
1066
1181
|
"row.regionCn": "国内版",
|
|
1067
1182
|
"row.regionAi": "国际版",
|
|
1068
1183
|
"row.subscriptionLabel": "订阅状态",
|
package/lib/index.d.ts
CHANGED
|
@@ -1156,6 +1156,21 @@ declare class TraeDelegatingUpstreamClient implements TraeUpstreamClient {
|
|
|
1156
1156
|
declare const TRAE_PAY_BASE = "https://api.trae.cn";
|
|
1157
1157
|
interface TraeUsageOptions {
|
|
1158
1158
|
credential(): Promise<TraeCredential | undefined>;
|
|
1159
|
+
/**
|
|
1160
|
+
* Device identity of the credential's own installation, sent as
|
|
1161
|
+
* `x-device-id` on the check-in routes.
|
|
1162
|
+
*
|
|
1163
|
+
* The claim endpoint is the one WRITE in this client, and it is guarded
|
|
1164
|
+
* server-side by that header: with the same Authorization but no
|
|
1165
|
+
* `x-device-id`, the upstream answers HTTP 200 with business code `9004`
|
|
1166
|
+
* ("The submitted order parameters are incorrect") and grants nothing —
|
|
1167
|
+
* verified 2026-09-24 against a live CN account, where adding the header
|
|
1168
|
+
* flipped the same request to `code: 0` and the daily reward landed. The
|
|
1169
|
+
* official client sends it on every check-in call
|
|
1170
|
+
* (`main.js`'s `fb(headers)` sets `x-device-id` from `guaranteedDeviceId`).
|
|
1171
|
+
* Absent, the client still reads status; only the claim refuses.
|
|
1172
|
+
*/
|
|
1173
|
+
deviceId?(): Promise<string | undefined>;
|
|
1159
1174
|
fetchImpl?: typeof fetch;
|
|
1160
1175
|
baseUrl?: string;
|
|
1161
1176
|
timeoutMs?: number;
|
|
@@ -1209,8 +1224,27 @@ interface TraeUsageSnapshot {
|
|
|
1209
1224
|
}
|
|
1210
1225
|
interface TraeCheckinStatus {
|
|
1211
1226
|
checkedIn: boolean;
|
|
1227
|
+
/** Reward for one check-in, as reported by the upstream (`credits`). */
|
|
1212
1228
|
credits: number;
|
|
1213
1229
|
enabled: boolean;
|
|
1230
|
+
/**
|
|
1231
|
+
* Whether today's reward was claimed in a previous session. The upstream
|
|
1232
|
+
* reports `did_checked_in` separately from `checked_in`: the app uses the
|
|
1233
|
+
* former to keep the claim button disabled for the rest of the Beijing day
|
|
1234
|
+
* even when the status read happens to report `checked_in: false`.
|
|
1235
|
+
*/
|
|
1236
|
+
didCheckedIn: boolean;
|
|
1237
|
+
/** Bonus credit granted on top of the base reward, when the upstream reports one. */
|
|
1238
|
+
extraCredits?: number;
|
|
1239
|
+
}
|
|
1240
|
+
/** Result of claiming today's check-in reward. */
|
|
1241
|
+
interface TraeCheckinClaim {
|
|
1242
|
+
/** Whether the upstream accepted the claim (`code === 0`). */
|
|
1243
|
+
claimed: boolean;
|
|
1244
|
+
/** Business code from the answer; `0` on success. */
|
|
1245
|
+
code: number;
|
|
1246
|
+
/** Upstream message, verbatim but truncated — never token material. */
|
|
1247
|
+
message: string;
|
|
1214
1248
|
}
|
|
1215
1249
|
interface TraeActivityRule {
|
|
1216
1250
|
activityId: string;
|
|
@@ -1226,8 +1260,11 @@ interface TraeUsageView {
|
|
|
1226
1260
|
activities: TraeActivityRule[];
|
|
1227
1261
|
}
|
|
1228
1262
|
/**
|
|
1229
|
-
* A
|
|
1230
|
-
*
|
|
1263
|
+
* A client for the verified Trae usage/credits endpoints.
|
|
1264
|
+
*
|
|
1265
|
+
* Every method is read-only except {@link TraeUsageClient.claimCheckin}, which
|
|
1266
|
+
* claims the daily check-in reward — the one deliberate mutation, requested by
|
|
1267
|
+
* the user from the card and guarded before it is sent.
|
|
1231
1268
|
*/
|
|
1232
1269
|
declare class TraeUsageClient {
|
|
1233
1270
|
private readonly options;
|
|
@@ -1243,6 +1280,13 @@ declare class TraeUsageClient {
|
|
|
1243
1280
|
* international region its own verified pay gateway.
|
|
1244
1281
|
*/
|
|
1245
1282
|
private payBase;
|
|
1283
|
+
/**
|
|
1284
|
+
* Device id for the check-in routes, or undefined when the machine's
|
|
1285
|
+
* installation identity cannot be read. Best-effort on purpose: a missing
|
|
1286
|
+
* identity must not break the read-only status query, which the upstream
|
|
1287
|
+
* answers with or without the header.
|
|
1288
|
+
*/
|
|
1289
|
+
private deviceIdHeader;
|
|
1246
1290
|
private authedHeaders;
|
|
1247
1291
|
private post;
|
|
1248
1292
|
/**
|
|
@@ -1260,8 +1304,26 @@ declare class TraeUsageClient {
|
|
|
1260
1304
|
private requireCnRegion;
|
|
1261
1305
|
/** Total entitlements / credits and per-pack breakdown. */
|
|
1262
1306
|
snapshot(signal?: AbortSignal): Promise<TraeUsageSnapshot>;
|
|
1263
|
-
/**
|
|
1307
|
+
/**
|
|
1308
|
+
* Daily check-in status. Read-only, and answered with or without the device
|
|
1309
|
+
* header — the claim is what needs it.
|
|
1310
|
+
*/
|
|
1264
1311
|
checkinStatus(signal?: AbortSignal): Promise<TraeCheckinStatus>;
|
|
1312
|
+
/**
|
|
1313
|
+
* Claim today's check-in reward. The ONLY state-changing call in this client.
|
|
1314
|
+
*
|
|
1315
|
+
* The upstream is idempotent per Beijing day (verified 2026-09-24: repeating
|
|
1316
|
+
* the call on an already-claimed day answers `code: 0` while the entitlement
|
|
1317
|
+
* total stays byte-identical), so a double click cannot double-grant. The
|
|
1318
|
+
* card and its route still guard, because "cannot double-grant" is a property
|
|
1319
|
+
* of the upstream we verify rather than one we rely on.
|
|
1320
|
+
*
|
|
1321
|
+
* A business refusal arrives as HTTP 200 with a non-zero `code` — most often
|
|
1322
|
+
* `9004` when the request carries no `x-device-id`. That is reported as
|
|
1323
|
+
* `claimed: false` rather than thrown, so the caller can tell "the upstream
|
|
1324
|
+
* refused this" apart from "the request never arrived".
|
|
1325
|
+
*/
|
|
1326
|
+
claimCheckin(signal?: AbortSignal): Promise<TraeCheckinClaim>;
|
|
1265
1327
|
/** Rewards / activity rules. */
|
|
1266
1328
|
activities(signal?: AbortSignal): Promise<TraeActivityRule[]>;
|
|
1267
1329
|
/** Convenience: snapshot + check-in + activities in one call (best-effort, non-fatal on missing). */
|
|
@@ -1271,6 +1333,11 @@ declare class TraeUsageClient {
|
|
|
1271
1333
|
//#region src/status-paths.d.ts
|
|
1272
1334
|
/** Plugin-owned usage endpoint consumed by its browser half. */
|
|
1273
1335
|
declare const TRAE_USAGE_PATH = "/plugins/dsh-connect-trae/usage";
|
|
1336
|
+
/**
|
|
1337
|
+
* Plugin-owned daily check-in claim endpoint. POST, loopback-only, and the only
|
|
1338
|
+
* route in this plugin that changes upstream account state.
|
|
1339
|
+
*/
|
|
1340
|
+
declare const TRAE_CHECKIN_PATH = "/plugins/dsh-connect-trae/checkin";
|
|
1274
1341
|
/** Query parameter naming the region a card request addresses. */
|
|
1275
1342
|
declare const TRAE_REGION_PARAM = "region";
|
|
1276
1343
|
/** Every region, in card tab order. */
|
|
@@ -1316,10 +1383,32 @@ interface TraeWebModel {
|
|
|
1316
1383
|
};
|
|
1317
1384
|
maxContextWindow?: number;
|
|
1318
1385
|
}
|
|
1319
|
-
/**
|
|
1386
|
+
/**
|
|
1387
|
+
* Daily check-in state rendered below the credit stats.
|
|
1388
|
+
*
|
|
1389
|
+
* `didCheckedIn` is not redundant with `checkedIn`: the upstream reports them
|
|
1390
|
+
* separately, and the official client keeps the claim button disabled for the
|
|
1391
|
+
* rest of the Beijing day off `did_checked_in` even when a status read comes
|
|
1392
|
+
* back `checked_in: false`. The card mirrors that rule so a stale-looking
|
|
1393
|
+
* status cannot invite a pointless second claim.
|
|
1394
|
+
*/
|
|
1320
1395
|
interface TraeWebCheckin {
|
|
1321
1396
|
checkedIn: boolean;
|
|
1397
|
+
didCheckedIn: boolean;
|
|
1322
1398
|
credits: number;
|
|
1399
|
+
enabled: boolean;
|
|
1400
|
+
extraCredits?: number;
|
|
1401
|
+
}
|
|
1402
|
+
/** The claim route's answer, so the card can report a business refusal verbatim. */
|
|
1403
|
+
interface TraeWebCheckinClaim {
|
|
1404
|
+
/** False when the upstream answered a non-zero business code (e.g. 9004). */
|
|
1405
|
+
claimed: boolean;
|
|
1406
|
+
/** True when today was already claimed, so nothing was sent upstream. */
|
|
1407
|
+
alreadyCheckedIn: boolean;
|
|
1408
|
+
code?: number;
|
|
1409
|
+
message?: string;
|
|
1410
|
+
/** The refreshed check-in state, present whenever the claim path ran. */
|
|
1411
|
+
checkin?: TraeWebCheckin;
|
|
1323
1412
|
}
|
|
1324
1413
|
/** One reward activity rule (name + work/general credits when present). */
|
|
1325
1414
|
interface TraeWebActivity {
|
|
@@ -1425,6 +1514,14 @@ type TraeWebUsage = {
|
|
|
1425
1514
|
};
|
|
1426
1515
|
credits?: TraeWebCredits;
|
|
1427
1516
|
creditsError?: string;
|
|
1517
|
+
/**
|
|
1518
|
+
* Daily check-in state (CN only). Absent on the international region,
|
|
1519
|
+
* whose check-in surface does not exist — probed 2026-09-24: the
|
|
1520
|
+
* `/trae/api/v2/ug/*` family answers 404 on every ai gateway, so the card
|
|
1521
|
+
* shows no claim button there rather than a button that cannot work.
|
|
1522
|
+
*/
|
|
1523
|
+
checkin?: TraeWebCheckin;
|
|
1524
|
+
checkinError?: string;
|
|
1428
1525
|
/** Subscription status of an international account (region ai only). */
|
|
1429
1526
|
payStatus?: TraeWebPayStatus;
|
|
1430
1527
|
payStatusError?: string;
|
|
@@ -1561,4 +1658,4 @@ declare function regionEnabled(config: Config, region: TraeRegion): boolean;
|
|
|
1561
1658
|
declare const Config: z<Config>;
|
|
1562
1659
|
declare function apply(ctx: Context, config: Config): void;
|
|
1563
1660
|
//#endregion
|
|
1564
|
-
export { Config, FALLBACK_TRAE_MODELS, FALLBACK_TRAE_MODELS_AI, REGION_GATEWAYS, type RawChatDelta, type RawChatMessage, type RawChatTool, SseDecoder, type SseEvent, TRAE_AI_PROVIDER, TRAE_CN_AGENT_TASK_PATH, TRAE_CN_TITLE_PATH, TRAE_MODEL_DETAIL_FUNCTIONS, TRAE_MODEL_DETAIL_PATH, TRAE_PAY_BASE, TRAE_PROVIDER, TRAE_PROVIDERS, TRAE_PROVIDER_DISPLAY_NAMES, TRAE_RAW_CHAT_V1_PATH, TRAE_RAW_CHAT_V2_PATH, TRAE_REASONING_EFFORTS, TRAE_REGIONS, TRAE_REGION_PARAM, TRAE_SETTINGS_NS, TRAE_SOLO_CHAT_PATH, TRAE_SOLO_FUNCTION, TRAE_SOLO_MODELS_PATH, TRAE_SOLO_REMOTE_BASE, TRAE_STREAM_IDLE_TIMEOUT_MS, TRAE_USAGE_PATH, TRAE_VERSION_CODE_FALLBACK, type TraeActivityRule, type TraeAdapter, type TraeCachedModelConfig, TraeCatalog, type TraeChatResult, type TraeCheckinStatus, type TraeContextBudget, type TraeCredential, TraeCredentialStore, TraeDelegatingUpstreamClient, type TraeDiscoveredModel, type TraeDiscoveredReasoning, type TraeEdition, TraeFallbackUpstreamClient, type TraeFallbackUpstreamOptions, type TraeFusionRawChatEnvelope, TraeGatedUpstreamClient, type TraeGatedUpstreamOptions, type TraeIdentity, type TraeInputModality, type TraeModelDetailRequest, type TraeModelInfo, type TraeObservedModelConfig, TraeRawCapabilityController, type TraeRawCapabilityControllerOptions, type TraeRawCapabilitySnapshot, TraeRawCapabilityState, type TraeRawChatBehaviorConfig, type TraeRawChatCapability, type TraeRawChatClientOptions, type TraeRawChatConfig, type TraeRawChatFailureReason, type TraeRawChatRuntimeConfig, TraeRawChatUpstreamClient, type TraeRawDiagnostic, type TraeRawDiagnosticState, type TraeRawGateway, type TraeRawGatewayOptions, type TraeRawResolverResult, type TraeReasoningCapability, type TraeReasoningEffort, type TraeRefreshDevice, type TraeRegion, type TraeRegionGateways, TraeRegionState, type TraeShim, TraeSoloBridge, type TraeSoloClientOptions, TraeSoloRemoteCatalogClient, type TraeSoloRemoteCatalogOptions, TraeSoloUpstreamClient, type TraeStorageCandidate, type TraeStreamEvent, type TraeUpstreamClient, TraeUsageClient, type TraeUsageOptions, type TraeUsagePack, type TraeUsageRouteOptions, type TraeUsageSnapshot, type TraeUsageSummary, type TraeUsageView, type TraeWebActivity, type TraeWebCheckin, type TraeWebCredits, type TraeWebUsage, type TraeWireModel, UnconfiguredTraeUpstreamClient, apply, applyContextBudgets, applyImageSelection, applyReasoningEffort, bridgeTraeSoloStream, buildTraeAgentTaskBody, buildTraeCnHeaders, buildTraeFusionRawChatEnvelope, buildTraeModelDetailRequest, buildTraeRawChatDraft, buildTraeRawChatRuntimeConfig, classifyTraeRawChatFailure, createTraeAdapter, createTraeRawGateway, createTraeShim, decodeRawChatChunk, decodeTraeEvent, decryptTraeStorageValue, deriveCatalog, discoveredCatalog, fallbackModelsFor, hashTraeRawChatArg, identityHeaders, inject, legacyTraeOwnAuthPath, mergeTraeModelSources, name, nextRegionEnabled, nextRegionSlots, normalizeTraeCredential, normalizeTraeVersionCode, parseObservedModelConfig, parseReasoningCapability, parseTraeAuthValue, parseTraeCachedModel, parseTraeModelExtraConfigLogLine, parseTraeRawChatBehaviorConfig, parseTraeRemoteModel, parseTraeStorageDocument, pickTraeStorageIdentity, prepareSoloBody, probeTraeRawChatCapability, rawCapabilityDiagnostic, rawCapabilityFingerprint, readTraeCachedModel, readTraeCliIdentity, readTraeIdentity, refreshTraeCredential, regionEnabled, regionEnabledOf, regionOfCredential, regionOfEdition, regionOfHost, regionOfTraeProvider, regionOfTraeStatusUrl, regionOfUserRegion, regionStateOf, registerTraeUsageRoute, resolveTraeIdentity, resolveTraeRawRuntime, sanitizeCatalog, traeEndpoint, traeInputModalities, traeModelDisplayName, traeOwnAuthPath, traeRawChatExtraInfo, traeStorageCandidates, traeWebUsage, withTraeRegion };
|
|
1661
|
+
export { Config, FALLBACK_TRAE_MODELS, FALLBACK_TRAE_MODELS_AI, REGION_GATEWAYS, type RawChatDelta, type RawChatMessage, type RawChatTool, SseDecoder, type SseEvent, TRAE_AI_PROVIDER, TRAE_CHECKIN_PATH, TRAE_CN_AGENT_TASK_PATH, TRAE_CN_TITLE_PATH, TRAE_MODEL_DETAIL_FUNCTIONS, TRAE_MODEL_DETAIL_PATH, TRAE_PAY_BASE, TRAE_PROVIDER, TRAE_PROVIDERS, TRAE_PROVIDER_DISPLAY_NAMES, TRAE_RAW_CHAT_V1_PATH, TRAE_RAW_CHAT_V2_PATH, TRAE_REASONING_EFFORTS, TRAE_REGIONS, TRAE_REGION_PARAM, TRAE_SETTINGS_NS, TRAE_SOLO_CHAT_PATH, TRAE_SOLO_FUNCTION, TRAE_SOLO_MODELS_PATH, TRAE_SOLO_REMOTE_BASE, TRAE_STREAM_IDLE_TIMEOUT_MS, TRAE_USAGE_PATH, TRAE_VERSION_CODE_FALLBACK, type TraeActivityRule, type TraeAdapter, type TraeCachedModelConfig, TraeCatalog, type TraeChatResult, type TraeCheckinClaim, type TraeCheckinStatus, type TraeContextBudget, type TraeCredential, TraeCredentialStore, TraeDelegatingUpstreamClient, type TraeDiscoveredModel, type TraeDiscoveredReasoning, type TraeEdition, TraeFallbackUpstreamClient, type TraeFallbackUpstreamOptions, type TraeFusionRawChatEnvelope, TraeGatedUpstreamClient, type TraeGatedUpstreamOptions, type TraeIdentity, type TraeInputModality, type TraeModelDetailRequest, type TraeModelInfo, type TraeObservedModelConfig, TraeRawCapabilityController, type TraeRawCapabilityControllerOptions, type TraeRawCapabilitySnapshot, TraeRawCapabilityState, type TraeRawChatBehaviorConfig, type TraeRawChatCapability, type TraeRawChatClientOptions, type TraeRawChatConfig, type TraeRawChatFailureReason, type TraeRawChatRuntimeConfig, TraeRawChatUpstreamClient, type TraeRawDiagnostic, type TraeRawDiagnosticState, type TraeRawGateway, type TraeRawGatewayOptions, type TraeRawResolverResult, type TraeReasoningCapability, type TraeReasoningEffort, type TraeRefreshDevice, type TraeRegion, type TraeRegionGateways, TraeRegionState, type TraeShim, TraeSoloBridge, type TraeSoloClientOptions, TraeSoloRemoteCatalogClient, type TraeSoloRemoteCatalogOptions, TraeSoloUpstreamClient, type TraeStorageCandidate, type TraeStreamEvent, type TraeUpstreamClient, TraeUsageClient, type TraeUsageOptions, type TraeUsagePack, type TraeUsageRouteOptions, type TraeUsageSnapshot, type TraeUsageSummary, type TraeUsageView, type TraeWebActivity, type TraeWebCheckin, type TraeWebCheckinClaim, type TraeWebCredits, type TraeWebUsage, type TraeWireModel, UnconfiguredTraeUpstreamClient, apply, applyContextBudgets, applyImageSelection, applyReasoningEffort, bridgeTraeSoloStream, buildTraeAgentTaskBody, buildTraeCnHeaders, buildTraeFusionRawChatEnvelope, buildTraeModelDetailRequest, buildTraeRawChatDraft, buildTraeRawChatRuntimeConfig, classifyTraeRawChatFailure, createTraeAdapter, createTraeRawGateway, createTraeShim, decodeRawChatChunk, decodeTraeEvent, decryptTraeStorageValue, deriveCatalog, discoveredCatalog, fallbackModelsFor, hashTraeRawChatArg, identityHeaders, inject, legacyTraeOwnAuthPath, mergeTraeModelSources, name, nextRegionEnabled, nextRegionSlots, normalizeTraeCredential, normalizeTraeVersionCode, parseObservedModelConfig, parseReasoningCapability, parseTraeAuthValue, parseTraeCachedModel, parseTraeModelExtraConfigLogLine, parseTraeRawChatBehaviorConfig, parseTraeRemoteModel, parseTraeStorageDocument, pickTraeStorageIdentity, prepareSoloBody, probeTraeRawChatCapability, rawCapabilityDiagnostic, rawCapabilityFingerprint, readTraeCachedModel, readTraeCliIdentity, readTraeIdentity, refreshTraeCredential, regionEnabled, regionEnabledOf, regionOfCredential, regionOfEdition, regionOfHost, regionOfTraeProvider, regionOfTraeStatusUrl, regionOfUserRegion, regionStateOf, registerTraeUsageRoute, resolveTraeIdentity, resolveTraeRawRuntime, sanitizeCatalog, traeEndpoint, traeInputModalities, traeModelDisplayName, traeOwnAuthPath, traeRawChatExtraInfo, traeStorageCandidates, traeWebUsage, withTraeRegion };
|
package/lib/index.js
CHANGED
|
@@ -3043,8 +3043,11 @@ function parseUsageSnapshot(payload) {
|
|
|
3043
3043
|
};
|
|
3044
3044
|
}
|
|
3045
3045
|
/**
|
|
3046
|
-
* A
|
|
3047
|
-
*
|
|
3046
|
+
* A client for the verified Trae usage/credits endpoints.
|
|
3047
|
+
*
|
|
3048
|
+
* Every method is read-only except {@link TraeUsageClient.claimCheckin}, which
|
|
3049
|
+
* claims the daily check-in reward — the one deliberate mutation, requested by
|
|
3050
|
+
* the user from the card and guarded before it is sent.
|
|
3048
3051
|
*/
|
|
3049
3052
|
var TraeUsageClient = class {
|
|
3050
3053
|
options;
|
|
@@ -3070,6 +3073,20 @@ var TraeUsageClient = class {
|
|
|
3070
3073
|
async payBase() {
|
|
3071
3074
|
return this.baseUrl ?? REGION_GATEWAYS[await this.currentRegion()].pay;
|
|
3072
3075
|
}
|
|
3076
|
+
/**
|
|
3077
|
+
* Device id for the check-in routes, or undefined when the machine's
|
|
3078
|
+
* installation identity cannot be read. Best-effort on purpose: a missing
|
|
3079
|
+
* identity must not break the read-only status query, which the upstream
|
|
3080
|
+
* answers with or without the header.
|
|
3081
|
+
*/
|
|
3082
|
+
async deviceIdHeader() {
|
|
3083
|
+
try {
|
|
3084
|
+
const deviceId = await this.options.deviceId?.();
|
|
3085
|
+
return deviceId === void 0 || deviceId === "" ? {} : { "x-device-id": deviceId };
|
|
3086
|
+
} catch {
|
|
3087
|
+
return {};
|
|
3088
|
+
}
|
|
3089
|
+
}
|
|
3073
3090
|
async authedHeaders() {
|
|
3074
3091
|
const credential = await this.options.credential();
|
|
3075
3092
|
if (credential === void 0 || credential.accessToken === "") throw new Error("Trae credential is not available; cannot query usage");
|
|
@@ -3082,8 +3099,11 @@ var TraeUsageClient = class {
|
|
|
3082
3099
|
"Referer": `${origin}/`
|
|
3083
3100
|
};
|
|
3084
3101
|
}
|
|
3085
|
-
async post(path, data, signal) {
|
|
3086
|
-
const headers =
|
|
3102
|
+
async post(path, data, signal, extraHeaders = {}) {
|
|
3103
|
+
const headers = {
|
|
3104
|
+
...await this.authedHeaders(),
|
|
3105
|
+
...extraHeaders
|
|
3106
|
+
};
|
|
3087
3107
|
const response = await this.fetchImpl(`${await this.payBase()}${path}`, {
|
|
3088
3108
|
method: "POST",
|
|
3089
3109
|
headers,
|
|
@@ -3137,14 +3157,46 @@ var TraeUsageClient = class {
|
|
|
3137
3157
|
await this.requireCnRegion("usage snapshot");
|
|
3138
3158
|
return parseUsageSnapshot(await this.post("/trae/api/v2/pay/web_user_ent_usage", { require_usage: true }, signal));
|
|
3139
3159
|
}
|
|
3140
|
-
/**
|
|
3160
|
+
/**
|
|
3161
|
+
* Daily check-in status. Read-only, and answered with or without the device
|
|
3162
|
+
* header — the claim is what needs it.
|
|
3163
|
+
*/
|
|
3141
3164
|
async checkinStatus(signal) {
|
|
3142
3165
|
await this.requireCnRegion("check-in status");
|
|
3143
|
-
const
|
|
3166
|
+
const headers = await this.deviceIdHeader();
|
|
3167
|
+
const payload = await this.post("/trae/api/v2/ug/checkin_credits/status", {}, signal, headers);
|
|
3168
|
+
const extraCredits = asNumber(payload["extra_credits"]);
|
|
3144
3169
|
return {
|
|
3145
3170
|
checkedIn: payload["checked_in"] === true,
|
|
3146
3171
|
credits: asNumber(payload["credits"]) ?? 0,
|
|
3147
|
-
enabled: payload["enable"] !== false
|
|
3172
|
+
enabled: payload["enable"] !== false,
|
|
3173
|
+
didCheckedIn: payload["did_checked_in"] === true,
|
|
3174
|
+
...extraCredits === void 0 || extraCredits <= 0 ? {} : { extraCredits }
|
|
3175
|
+
};
|
|
3176
|
+
}
|
|
3177
|
+
/**
|
|
3178
|
+
* Claim today's check-in reward. The ONLY state-changing call in this client.
|
|
3179
|
+
*
|
|
3180
|
+
* The upstream is idempotent per Beijing day (verified 2026-09-24: repeating
|
|
3181
|
+
* the call on an already-claimed day answers `code: 0` while the entitlement
|
|
3182
|
+
* total stays byte-identical), so a double click cannot double-grant. The
|
|
3183
|
+
* card and its route still guard, because "cannot double-grant" is a property
|
|
3184
|
+
* of the upstream we verify rather than one we rely on.
|
|
3185
|
+
*
|
|
3186
|
+
* A business refusal arrives as HTTP 200 with a non-zero `code` — most often
|
|
3187
|
+
* `9004` when the request carries no `x-device-id`. That is reported as
|
|
3188
|
+
* `claimed: false` rather than thrown, so the caller can tell "the upstream
|
|
3189
|
+
* refused this" apart from "the request never arrived".
|
|
3190
|
+
*/
|
|
3191
|
+
async claimCheckin(signal) {
|
|
3192
|
+
await this.requireCnRegion("check-in claim");
|
|
3193
|
+
const headers = await this.deviceIdHeader();
|
|
3194
|
+
const payload = await this.post("/trae/api/v2/ug/checkin_credits/claim", {}, signal, headers);
|
|
3195
|
+
const code = asNumber(payload["code"]) ?? 0;
|
|
3196
|
+
return {
|
|
3197
|
+
claimed: code === 0,
|
|
3198
|
+
code,
|
|
3199
|
+
message: typeof payload["message"] === "string" ? payload["message"].slice(0, 200) : ""
|
|
3148
3200
|
};
|
|
3149
3201
|
}
|
|
3150
3202
|
/** Rewards / activity rules. */
|
|
@@ -3189,6 +3241,11 @@ const TRAE_USAGE_PATH = "/plugins/dsh-connect-trae/usage";
|
|
|
3189
3241
|
const TRAE_MODELS_REFRESH_PATH = "/plugins/dsh-connect-trae/models/refresh";
|
|
3190
3242
|
/** Plugin-owned local account rescan endpoint. */
|
|
3191
3243
|
const TRAE_ACCOUNTS_REFRESH_PATH = "/plugins/dsh-connect-trae/accounts/refresh";
|
|
3244
|
+
/**
|
|
3245
|
+
* Plugin-owned daily check-in claim endpoint. POST, loopback-only, and the only
|
|
3246
|
+
* route in this plugin that changes upstream account state.
|
|
3247
|
+
*/
|
|
3248
|
+
const TRAE_CHECKIN_PATH = "/plugins/dsh-connect-trae/checkin";
|
|
3192
3249
|
/** Query parameter naming the region a card request addresses. */
|
|
3193
3250
|
const TRAE_REGION_PARAM = "region";
|
|
3194
3251
|
/** Every region, in card tab order. */
|
|
@@ -3323,6 +3380,16 @@ function toCredits(snapshot) {
|
|
|
3323
3380
|
accounts
|
|
3324
3381
|
};
|
|
3325
3382
|
}
|
|
3383
|
+
/** Map the check-in answer to the card's compact document. */
|
|
3384
|
+
function toCheckin(status) {
|
|
3385
|
+
return {
|
|
3386
|
+
checkedIn: status.checkedIn,
|
|
3387
|
+
didCheckedIn: status.didCheckedIn,
|
|
3388
|
+
credits: status.credits,
|
|
3389
|
+
enabled: status.enabled,
|
|
3390
|
+
...status.extraCredits === void 0 ? {} : { extraCredits: status.extraCredits }
|
|
3391
|
+
};
|
|
3392
|
+
}
|
|
3326
3393
|
/**
|
|
3327
3394
|
* Assemble one region's card document. `region` is the tab the card is on; the
|
|
3328
3395
|
* region-scoped store already answers with only that region's accounts, so the
|
|
@@ -3389,20 +3456,13 @@ async function traeWebUsage(deps, region) {
|
|
|
3389
3456
|
payStatusError: safeMessage(error)
|
|
3390
3457
|
};
|
|
3391
3458
|
}
|
|
3392
|
-
|
|
3393
|
-
|
|
3394
|
-
|
|
3395
|
-
|
|
3396
|
-
|
|
3397
|
-
|
|
3398
|
-
|
|
3399
|
-
} catch (error) {
|
|
3400
|
-
return {
|
|
3401
|
-
status: "signed-in",
|
|
3402
|
-
...account,
|
|
3403
|
-
creditsError: safeMessage(error)
|
|
3404
|
-
};
|
|
3405
|
-
}
|
|
3459
|
+
const [snapshotResult, checkinResult] = await Promise.allSettled([client.snapshot(), client.checkinStatus()]);
|
|
3460
|
+
return {
|
|
3461
|
+
status: "signed-in",
|
|
3462
|
+
...account,
|
|
3463
|
+
...snapshotResult.status === "fulfilled" ? { credits: toCredits(snapshotResult.value) } : { creditsError: safeMessage(snapshotResult.reason) },
|
|
3464
|
+
...checkinResult.status === "fulfilled" ? { checkin: toCheckin(checkinResult.value) } : { checkinError: safeMessage(checkinResult.reason) }
|
|
3465
|
+
};
|
|
3406
3466
|
}
|
|
3407
3467
|
/**
|
|
3408
3468
|
* The region a request addresses, or a 400 answer. Absent parameter means the
|
|
@@ -3471,7 +3531,49 @@ function registerTraeUsageRoute(ctx, deps) {
|
|
|
3471
3531
|
}
|
|
3472
3532
|
}
|
|
3473
3533
|
});
|
|
3534
|
+
/**
|
|
3535
|
+
* Daily check-in claim — the ONLY route in this plugin that mutates
|
|
3536
|
+
* upstream account state, so it is guarded more tightly than its siblings:
|
|
3537
|
+
* POST only, loopback origin only, and the status read runs FIRST so an
|
|
3538
|
+
* already-claimed day never reaches the upstream claim at all. The upstream
|
|
3539
|
+
* is idempotent per Beijing day anyway (verified 2026-09-24: a repeat claim
|
|
3540
|
+
* answers `code: 0` with the entitlement total unchanged), but relying on
|
|
3541
|
+
* that for correctness would put the guard in someone else's hands.
|
|
3542
|
+
*/
|
|
3543
|
+
const disposeCheckin = ctx.webServer.register({
|
|
3544
|
+
kind: "exact",
|
|
3545
|
+
path: TRAE_CHECKIN_PATH,
|
|
3546
|
+
handler: async (req, res) => {
|
|
3547
|
+
if (req.method !== "POST") return json(res, 405, { error: "method not allowed" });
|
|
3548
|
+
if (!loopbackOrigin(req)) return json(res, 403, { error: "origin-not-trusted" });
|
|
3549
|
+
const region = requestRegion(req, res);
|
|
3550
|
+
if (region === void 0) return;
|
|
3551
|
+
if (region !== "cn") return json(res, 404, { error: "check-in is not available for the international region" });
|
|
3552
|
+
try {
|
|
3553
|
+
const client = deps.client(region);
|
|
3554
|
+
const current = await client.checkinStatus();
|
|
3555
|
+
if (!current.enabled) return json(res, 409, { error: "check-in is not enabled for this account" });
|
|
3556
|
+
if (current.checkedIn || current.didCheckedIn) return json(res, 200, {
|
|
3557
|
+
claimed: false,
|
|
3558
|
+
alreadyCheckedIn: true,
|
|
3559
|
+
checkin: toCheckin(current)
|
|
3560
|
+
});
|
|
3561
|
+
const claim = await client.claimCheckin();
|
|
3562
|
+
const checkin = await client.checkinStatus();
|
|
3563
|
+
json(res, 200, {
|
|
3564
|
+
claimed: claim.claimed,
|
|
3565
|
+
alreadyCheckedIn: false,
|
|
3566
|
+
code: claim.code,
|
|
3567
|
+
message: claim.message,
|
|
3568
|
+
checkin: toCheckin(checkin)
|
|
3569
|
+
});
|
|
3570
|
+
} catch (error) {
|
|
3571
|
+
json(res, 500, { error: safeMessage(error) });
|
|
3572
|
+
}
|
|
3573
|
+
}
|
|
3574
|
+
});
|
|
3474
3575
|
return () => {
|
|
3576
|
+
disposeCheckin();
|
|
3475
3577
|
disposeRefresh();
|
|
3476
3578
|
disposeAccounts();
|
|
3477
3579
|
disposeUsage();
|
|
@@ -3866,7 +3968,10 @@ function apply(ctx, config) {
|
|
|
3866
3968
|
catalog,
|
|
3867
3969
|
shim,
|
|
3868
3970
|
delegating,
|
|
3869
|
-
usageClient: new TraeUsageClient({
|
|
3971
|
+
usageClient: new TraeUsageClient({
|
|
3972
|
+
credential: () => store.resolve(),
|
|
3973
|
+
deviceId: async () => (await identity()).deviceId
|
|
3974
|
+
}),
|
|
3870
3975
|
discoverModels: async (signal) => {
|
|
3871
3976
|
const merged = mergeTraeModelSources(await withDirectoryRetry(() => remoteCatalog.fetchModels(signal)), await solo.fetchModels(signal));
|
|
3872
3977
|
wire.callableKeys.clear();
|
|
@@ -4048,4 +4153,4 @@ function apply(ctx, config) {
|
|
|
4048
4153
|
});
|
|
4049
4154
|
}
|
|
4050
4155
|
//#endregion
|
|
4051
|
-
export { Config, FALLBACK_TRAE_MODELS, FALLBACK_TRAE_MODELS_AI, REGION_GATEWAYS, SseDecoder, TRAE_AI_PROVIDER, TRAE_CN_AGENT_TASK_PATH, TRAE_CN_TITLE_PATH, TRAE_MODEL_DETAIL_FUNCTIONS, TRAE_MODEL_DETAIL_PATH, TRAE_PAY_BASE, TRAE_PROVIDER, TRAE_PROVIDERS, TRAE_PROVIDER_DISPLAY_NAMES, TRAE_RAW_CHAT_V1_PATH, TRAE_RAW_CHAT_V2_PATH, TRAE_REASONING_EFFORTS, TRAE_REGIONS, TRAE_REGION_PARAM, TRAE_SETTINGS_NS, TRAE_SOLO_CHAT_PATH, TRAE_SOLO_FUNCTION, TRAE_SOLO_MODELS_PATH, TRAE_SOLO_REMOTE_BASE, TRAE_STREAM_IDLE_TIMEOUT_MS, TRAE_USAGE_PATH, TRAE_VERSION_CODE_FALLBACK, TraeCatalog, TraeCredentialStore, TraeDelegatingUpstreamClient, TraeFallbackUpstreamClient, TraeGatedUpstreamClient, TraeRawCapabilityController, TraeRawCapabilityState, TraeRawChatUpstreamClient, TraeSoloBridge, TraeSoloRemoteCatalogClient, TraeSoloUpstreamClient, TraeUsageClient, UnconfiguredTraeUpstreamClient, apply, applyContextBudgets, applyImageSelection, applyReasoningEffort, bridgeTraeSoloStream, buildTraeAgentTaskBody, buildTraeCnHeaders, buildTraeFusionRawChatEnvelope, buildTraeModelDetailRequest, buildTraeRawChatDraft, buildTraeRawChatRuntimeConfig, classifyTraeRawChatFailure, createTraeAdapter, createTraeRawGateway, createTraeShim, decodeRawChatChunk, decodeTraeEvent, decryptTraeStorageValue, deriveCatalog, discoveredCatalog, fallbackModelsFor, hashTraeRawChatArg, identityHeaders, inject, legacyTraeOwnAuthPath, mergeTraeModelSources, name, nextRegionEnabled, nextRegionSlots, normalizeTraeCredential, normalizeTraeVersionCode, parseObservedModelConfig, parseReasoningCapability, parseTraeAuthValue, parseTraeCachedModel, parseTraeModelExtraConfigLogLine, parseTraeRawChatBehaviorConfig, parseTraeRemoteModel, parseTraeStorageDocument, pickTraeStorageIdentity, prepareSoloBody, probeTraeRawChatCapability, rawCapabilityDiagnostic, rawCapabilityFingerprint, readTraeCachedModel, readTraeCliIdentity, readTraeIdentity, refreshTraeCredential, regionEnabled, regionEnabledOf, regionOfCredential, regionOfEdition, regionOfHost, regionOfTraeProvider, regionOfTraeStatusUrl, regionOfUserRegion, regionStateOf, registerTraeUsageRoute, resolveTraeIdentity, resolveTraeRawRuntime, sanitizeCatalog, traeEndpoint, traeInputModalities, traeModelDisplayName, traeOwnAuthPath, traeRawChatExtraInfo, traeStorageCandidates, traeWebUsage, withTraeRegion };
|
|
4156
|
+
export { Config, FALLBACK_TRAE_MODELS, FALLBACK_TRAE_MODELS_AI, REGION_GATEWAYS, SseDecoder, TRAE_AI_PROVIDER, TRAE_CHECKIN_PATH, TRAE_CN_AGENT_TASK_PATH, TRAE_CN_TITLE_PATH, TRAE_MODEL_DETAIL_FUNCTIONS, TRAE_MODEL_DETAIL_PATH, TRAE_PAY_BASE, TRAE_PROVIDER, TRAE_PROVIDERS, TRAE_PROVIDER_DISPLAY_NAMES, TRAE_RAW_CHAT_V1_PATH, TRAE_RAW_CHAT_V2_PATH, TRAE_REASONING_EFFORTS, TRAE_REGIONS, TRAE_REGION_PARAM, TRAE_SETTINGS_NS, TRAE_SOLO_CHAT_PATH, TRAE_SOLO_FUNCTION, TRAE_SOLO_MODELS_PATH, TRAE_SOLO_REMOTE_BASE, TRAE_STREAM_IDLE_TIMEOUT_MS, TRAE_USAGE_PATH, TRAE_VERSION_CODE_FALLBACK, TraeCatalog, TraeCredentialStore, TraeDelegatingUpstreamClient, TraeFallbackUpstreamClient, TraeGatedUpstreamClient, TraeRawCapabilityController, TraeRawCapabilityState, TraeRawChatUpstreamClient, TraeSoloBridge, TraeSoloRemoteCatalogClient, TraeSoloUpstreamClient, TraeUsageClient, UnconfiguredTraeUpstreamClient, apply, applyContextBudgets, applyImageSelection, applyReasoningEffort, bridgeTraeSoloStream, buildTraeAgentTaskBody, buildTraeCnHeaders, buildTraeFusionRawChatEnvelope, buildTraeModelDetailRequest, buildTraeRawChatDraft, buildTraeRawChatRuntimeConfig, classifyTraeRawChatFailure, createTraeAdapter, createTraeRawGateway, createTraeShim, decodeRawChatChunk, decodeTraeEvent, decryptTraeStorageValue, deriveCatalog, discoveredCatalog, fallbackModelsFor, hashTraeRawChatArg, identityHeaders, inject, legacyTraeOwnAuthPath, mergeTraeModelSources, name, nextRegionEnabled, nextRegionSlots, normalizeTraeCredential, normalizeTraeVersionCode, parseObservedModelConfig, parseReasoningCapability, parseTraeAuthValue, parseTraeCachedModel, parseTraeModelExtraConfigLogLine, parseTraeRawChatBehaviorConfig, parseTraeRemoteModel, parseTraeStorageDocument, pickTraeStorageIdentity, prepareSoloBody, probeTraeRawChatCapability, rawCapabilityDiagnostic, rawCapabilityFingerprint, readTraeCachedModel, readTraeCliIdentity, readTraeIdentity, refreshTraeCredential, regionEnabled, regionEnabledOf, regionOfCredential, regionOfEdition, regionOfHost, regionOfTraeProvider, regionOfTraeStatusUrl, regionOfUserRegion, regionStateOf, registerTraeUsageRoute, resolveTraeIdentity, resolveTraeRawRuntime, sanitizeCatalog, traeEndpoint, traeInputModalities, traeModelDisplayName, traeOwnAuthPath, traeRawChatExtraInfo, traeStorageCandidates, traeWebUsage, withTraeRegion };
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-connect-trae",
|
|
3
3
|
"displayName": "DSH Connect Trae",
|
|
4
|
-
"description": "Connect locally signed-in Trae models to DeepSeek Harness,
|
|
5
|
-
"version": "2.0
|
|
4
|
+
"description": "Connect locally signed-in Trae models to DeepSeek Harness, with a usage/credits summary and daily check-in claiming.",
|
|
5
|
+
"version": "2.1.0",
|
|
6
6
|
"author": "dingminhua",
|
|
7
7
|
"copyright": "Copyright (c) 2026 LaoDing",
|
|
8
8
|
"license": "MIT",
|