dsh-xdpool 2.5.1 → 2.6.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 CHANGED
@@ -1,6 +1,96 @@
1
1
  # Changelog
2
2
  本项目的所有重要变更都会记录在此文件。
3
3
  版本号遵循 [语义化版本](https://semver.org/lang/zh-CN/)。
4
+ ## 2.6.0 — 一次收掉 2.5.1 之后的全部改动
5
+
6
+ > 本版把 2.5.2 到 2.5.6 的五个小版本合并发布。内容分四块:**群反馈的五处界面问题**、**八项借鉴来的功能**、**CodeArts 403 那四个缺陷**、以及**路由与看板的一次结构升级**。另外收掉了我自己在修补过程中引入的三处错误(lane 选择极性反转、两套 tsconfig 判据不一、`source` 变量在死区被读取)。
7
+
8
+ ### 一、群里反馈的五处
9
+
10
+ **「重启后模型选择变成 1/14」——不是丢了,是名册短了**
11
+
12
+ 保存的选择一直完好。真正发生的是目录刷新那一次网关只回了 14 个模型,用户存的 5 个里只有 1 个在其中,界面只显示 `已启用 1 / 14`,看起来就像被重置。现在多一行 `另有 N 个已保存的模型当前未提供`,悬停列出具体 id —— 两个数字都对,不一致本身就是信息,以前这条信息不可见。
13
+
14
+ **「点了咋没起作用,实际都续在后面」——面板改成手风琴**
15
+
16
+ 账号列表是一账号一行、模型列表是一模型一卡,两个同时展开会把第二个顶到屏外。现在同一张卡内一次只开一个面板,跨卡仍然独立。模型列表也默认只显示已启用的行,其余收进 `显示其余 N 个`。
17
+
18
+ **「OpenCode Free 关不掉,应该默认关闭」**
19
+
20
+ 免密 lane(`free:` 模型)原本无条件注册,而聚合总开关管不到它 —— 它压根不是聚合 provider,所以没有任何 UI 能关。新增 `freeLane` 开关,**默认关**;关闭时 `current()` 返回空,`allRows()` 保留花名册给需要解释它的页面。这样「关掉」是选择,不是抹除。
21
+
22
+ **「移出账号后又被加回来」/「账号使用方式只有 WorkBuddy 有」**
23
+
24
+ 忽略名单的持久化与扫描闸门补齐;「账号使用方式」扩展为可作用于第三方渠道的多 Key 分配(见第二节)。
25
+
26
+ ### 二、八项借鉴来的功能
27
+
28
+ **A. 同模型多线路优先** —— 限流时正确动作通常是**换线路拿同一个模型**,而不是换模型(换模型会改上下文窗口、工具调用、文风)。注册表里 86 个模型 id 挂在 2 家以上,`siblingRoutes` 从目录推导出来。
29
+
30
+ **B. 熔断 + 探测复活** —— 登录被拒后的冷却时长是猜的,两头都容易错。现在每轮运行对坐冷账号做一次廉价鉴权读,**只有探测成功才解除**,失败则冷却原样留着 —— 否则探测频率会改变账号被关多久。
31
+
32
+ **C. 签到先读状态** —— 领取接口幂等,旧代码靠「故意触发错误再翻译成成功」工作。改成先 GET 状态,常见情况连写请求都不发。状态读失败时回落旧行为。
33
+
34
+ **D. 兜底模型表不再带价格** —— 几个月前抓的倍率会让人按错数字做预算,`multiplier: 0` 还会点亮「免费」徽章让结束的促销继续宣称免费。促销徽章一并删掉;`undefined` 才是诚实的。
35
+
36
+ **E. 凭据文件收成仅本人可读** —— 每个密文原本走裸 `writeFile`,POSIX 上通常是 `0644`(同机其他用户可读,而里面是明文 token)。权限在写临时文件时打上,原子重命名带过去。Windows 的缺口写在注释里而非藏起来。
37
+
38
+ **F. 自动化逐条状态** —— `detail` 是自由文本,所以「0 条已领」在三种情况下长得一样。现在每个任务给出 `已领/早已领过/暂不可领/失败`,卡片渲染成四枚状态标签。
39
+
40
+ **G. 自定义 OpenAI 兼容端点** —— 一个注册表位置 `custom_openai`,**baseUrl 与模型列表都为空**:vLLM、LiteLLM、one-api、自建网关都行。不给默认 URL,因为猜一个会把请求发到用户没选过的地方。
41
+
42
+ **H. 自动化够到以前够不到的任务** —— deeplink 里没有 `expertId` 时按标题去市场查(多个匹配就拒绝,召唤错专家照样 0 分);账号资格从「global 一律不做」改成**按 job 分级**,签到会跑 global。
43
+
44
+ ### 三、CodeArts 403:四个缺陷
45
+
46
+ 网友的报告带了完整对照实验。四个都修了:
47
+
48
+ 1. **真因是 User-Agent** —— `attributionHeaders()` 盖上宿主 bot UA,snap-access 网关对它直接回 `403 TM.00000001`。同凭证、同 body、同接口:bot UA→403,不设 UA→200,IDE 形状的 UA→200。现在请求显式设自己的 UA,其余 attribution 头保留。
49
+ 2. **403 被归成 `AUTH`** —— 网关所有 IAM 拒绝实测都是 401 `APIG.0301`;唯一的 403 是 WAF 判定。卡片把 `AUTH` 渲染成「API 密钥无效」,于是一个请求头问题被报成凭据问题。现在 403 按 body 判。
50
+ 3. **鉴权失败不换号** —— 原分支只 `refresh()` 当前账号,池里两个账号时一个被拒就整平台失败。现在也轮询,每个账号只试一次。
51
+ 4. **报错丢掉上游 body** —— 原来只剩 `HTTP 403`。现在附上 `errorDetail`(截 200 字)。
52
+
53
+ 范围是刻意的:`401 || 403 → AUTH` 在 pack 里出现 11 次、分属 6 个适配器,而对多数厂商 403 确实是凭据问题。只有 CodeArts 实测过,所以只改它那两处,测试断言其余 9 处不变。
54
+
55
+ ### 四、路由与看板的结构升级
56
+
57
+ **路由改成两级(平台 → 模型)**
58
+
59
+ 一条链现在是 `platforms: [{ owner, models[] }]`,界面就是它的样子:折叠态每平台一枚胶囊(`1. TRAE(字节)· 1`),展开态每平台一张卡(上移/下移/移除 + 卡内模型列表 + 只列本平台模型的下拉)。
60
+
61
+ 这里有个必须处理的陷阱:**分组对交错链是有损的**。`hy3 → opencode/x → glm-5.3` 按 owner 分组后两个池模型并到一起,顺序被改 —— 也就是路由优先级被改了。所以草稿同时持有 `flat`(服务端给的原始序列)和 `platforms`,**只有真正编辑了平台结构才重算 `flat`**。打开一条链直接保存,顺序一个字节都不变。
62
+
63
+ **路由能选到扫码登录渠道**
64
+
65
+ 之前候选只来自本插件自己的两个目录(池名册 + 聚合注册表),而扫码登录渠道是宿主注册的 provider,两个都没有 —— 所以只有一行。现在接上宿主渠道,成员 id 形式 `<channel>:<model>`,执行走 shim 本来就有第五条 lane。`host` 与 `aggregate` 严格分开(凭据、错误词汇、代码路径都不同)。
66
+
67
+ **看板认得渠道了**
68
+
69
+ `UsageCall` 原本只有 `region`(cn/global),而这是池专有属性,所以每行都写「国内版」。现在 `channel` 进了 `UsageCall` **并进了两个聚合表的分组键** —— 同一模型 id 可挂多家,混成一行会把一家 token 记到另一家头上。三张表首列都改成渠道。
70
+
71
+ **聚合渠道支持多把 Key**
72
+
73
+ `ProviderSetting.apiKeys` + `distribution`;`appendApiKey` 是**指令**而非存储字段(读取路由从不回显 Key,只报 `keyCount`,所以浏览器发整份列表只能用占位符拼,会把看不见的 Key 冲掉)。轮转只对「这把 Key 的问题」重试(429/401),400/404/402/5xx 换 Key 只会倍增等待。策略控件**只在 `keyCount > 1` 时出现** —— 一把 Key 时它是个只有一个选项的开关。
74
+
75
+ ### 五、我引入并修掉的三处
76
+
77
+ **lane 选择极性反转** —— `laneAllowedIds` 返回白名单,而调用点当黑名单用,于是勾 3/16 露出的是另外 13 个。这段代码从 2.5.0 起就是反的,只因当时 lane 没有发布选择(`allow === undefined` 短路)而一直没显形。修正为对着名册取补集。
78
+
79
+ **两套 tsconfig 判据不一** —— host 没开 `exactOptionalPropertyTypes`,client 开了,且 TypeScript 会顺 import 把 host 文件拉进 client 程序,于是同一文件「一套配置绿、另一套红」。现在两边都开,9 处一并修好(其中 3 处顺带暴露了真实的重复计算)。
80
+
81
+ **`source` 在死区被读取** —— 上一版给 10 个调用点一刀切加 `, source`,但 5 个适配器的名册变量叫 `all`,另有 1 个声明在调用之后。thunk 只延后一次调用、不延后一行,所以那一处改成了局部换序。改写脚本改为逐行扫描 + 每步断言。
82
+
83
+ ### 六、其它
84
+
85
+ - 看板数字列的表头与数据对齐(`.dsm-xdpool-table th` 优先级高于 `.dsm-xdpool-num`,表头一直左对齐)
86
+ - 链成员有了 180 秒自己的超时(调用方 signal 只覆盖「用户取消」,不覆盖「供应商攥着连接不放」)
87
+ - `REASON_STATUS` 表:cooling/session_dead/reserve/disabled/empty 各有状态码,不再一律 401
88
+ - 过期不再显示成「长期有效」,单位降到小时/分钟
89
+ - 渠道池 `provider.status` 加 30 秒缓存(一次请求数 13 个渠道的账号,成本是十三个的和)
90
+ - 交流群弹窗改成双码(微信机器人 + QQ 群),README 顶部同步;README 下载徽章改读新包实时统计
91
+ - 链的每次跳过记录 `成员 → 原因 (状态码)`,全败时把整条轨迹写进错误消息
92
+ - 按渠道分组的下拉、同模型线路按钮在两级结构落地后移除(分组已结构化,再套一层 optgroup 是把卡片说过的话再说一遍)
93
+
4
94
  ## 2.5.1 — 六张 issue、一个交流群入口,外加拿掉 billion-context
5
95
 
6
96
  > 2.5.0 之后收到的反馈集中在两类:**看得见却点不动的界面**(链不显示、单选互顶、卡片空白),和**说错话的报错**(额度已用尽、密钥无效、为预留让你调低预留)。这一版把这两类都按「根因 + 可复现断言」的方式收掉,同时按你的要求移除了 billion-context 那一页,并在「点Star」旁边加了「交流群」。
@@ -69,6 +159,78 @@ Refs #95 #96 #98 #99 #101 #102。
69
159
 
70
160
  ## 附:CodeArts 的输出上限是上限,不是默认值(细节,已并入 2.5.1)
71
161
 
162
+ ## 2.5.0 — 十张 issue 一起收:失效账号、第三条指纹、CodeArts 上限、保存回滚、侧栏开关
163
+
164
+ > #68 到 #83 攒了十来张单子,其中三张(#72/#73/#74)是同一类毛病:代码把一个「没数据」和「数据是空」当成了同一件事。这批按这个线索统一收拾,另外把社区两个 PR 收了进来。
165
+
166
+ ### 最要紧的三条
167
+
168
+ | 症状 | 真实原因 |
169
+ | --- | --- |
170
+ | 一个失效账号吃掉整次请求的 8 次重试,最后报「API 密钥无效」 | 以「刷新拿到了新 token」判定账号仍可用。有一类账号 refresh 长期有效、chat 恒回 403,判死条件因此恒假 |
171
+ | buddy 某一轮被中断后,之后每一轮都失败(`a message has empty content`) | 中断留下的 assistant 消息只有 reasoning、没有正文,序列化时空字符串被原样发到 wire,国内网关 400/11151 且不在重试集合里 |
172
+ | zcode 全部模型勾选后,每次重启又变回全禁用 | 用户全开时黑名单是空对象,与「从未选过」无法区分,启动补静音据此又把它们全关一遍 |
173
+
174
+ ### #68 失效账号耗尽重试预算
175
+
176
+ 池车道以「刷新成功」当「账号可用」。对 refresh 长期有效而业务侧恒 403 的账号,`recovered` 与 `accessToken !== before` 恒真 ⇒ 永不 `penalizeCredentialDead` ⇒ `available()` 不排除 ⇒ `priority` 下 `acquire()` 一直返回同一个 ⇒ 8 次预算全花在它身上。
177
+
178
+ 改法:单次请求内只允许该账号换一次票(`refreshedThisRequest`),第二次仍报 `session_dead` 就直接判死并轮到下一个账号。压缩重试路径同步。取「第二次」而不是把惩罚提到刷新之前,是为了仍给真正过期的 token 一次机会。
179
+
180
+ ### #70 侧栏入口开关
181
+
182
+ 新增 `sidebarRow` 配置(默认开)。**只**控制左侧栏那一行:设置页的 XD Pool 卡片始终注册,模型池不受影响 —— 关掉入口不能把开关本身也锁在门外。开关写在卡片里,`apply()` 与卡片读同一份设置镜像,因此两边不会给出不同答案;宿主发布了变更通知的平台上无需重启。
183
+
184
+ ### #72 订阅包余额虚高 30 倍
185
+
186
+ `fetchCredits` 只把 `CapacityType === 4` 当月包,而实际有三种:`1`=一次性包、`2`=**周期订阅包**(12 期 × 4000,`CapacityRemain` 是整期剩余、`CycleCapacityRemain` 才是当期剩余)、`4`=月包。`type=2` 落进「一次性」分支,整期额度被当余额。三账号实测:官方 3,399.8 / 插件 102,396 → 修复后 3,366;另两个只有月包的账号(3,049 / 2,771)不变,所以长期没被发现。
187
+
188
+ `expiresAtMs` 对 `type=2` 取 `DeductionEndTime`,**不能用 `CycleEndTime`** —— 它每月都到,会让「会过期」天天报警。空包只在一次性包时丢弃,月包当期耗尽要留着显示「0/500 · 下月回满」。
189
+
190
+ Refs #72。
191
+
192
+ ### #73 中断回合留下的空 assistant 消息
193
+
194
+ `serializeMessages2` 出口加 `isBlankWireMessage` / `dropBlankWireMessages`,`serializeMessages4` 同步。三点取舍都用真实请求验证过:`user` 空消息不动(两网关都容忍);不伪造占位内容(会污染模型看到的对话);**有 `tool_calls` 的 assistant 消息绝不删**(它是 tool 结果的配对锚点,删了造孤儿)。
195
+
196
+ 实测矩阵(国内):空 assistant 400/11151;空 system 同样 400/11151;空 user 200;`content:null` + `tool_calls` 200;删掉空 assistant 后正常 SSE。国际网关对全部形态都 200,所以故障面目前只在 buddy 车道。
197
+
198
+ Refs #73。
199
+
200
+ ### #74 全开渠道每次重启被重新禁用
201
+
202
+ `setModelDisabled` 打开模型时是**删键**而不是写 `false`,于是「用户全开」与「从未选择」在磁盘上是同一个空对象。新增持久标记 `selectionTouched`:四个用户入口(`setModelDisabled` / `setModelsDisabled` / `clearModelsDisabled` / `clearDisabledModels`)都置位,启动补静音只在标记缺失时执行,且自身写黑名单时传 `{ mark: false }` 不置位。
203
+
204
+ 影响面是「所有模型都打开」的渠道,目录越小越必然(zcode 2 个、gemini/minimax/raccoon 同理);部分启用的渠道免疫,这解释了为什么只有 zcode 反复被报。
205
+
206
+ Refs #74。
207
+
208
+ ### #75 保存模型选择后界面回滚 30 秒
209
+
210
+ `saveModels` 收尾是 `setDraftFor(region, undefined)`,而它的语义是「退回池子最后报告的状态」,那份状态靠 30 秒轮询刷新 —— 于是保存后卡片画的是**保存前**的清单,用户在这 30 秒里再点一次保存,写入的就是回滚后的旧清单。另外 `settingsScope.set` 被声明成 `Promise<void>`,把宿主 revision 冲突时返回的 `false` 丢掉了,被拒绝也提示「已保存」。
211
+
212
+ 改法:先 `refresh(region)` 再清草稿(重读失败则保留草稿);`set` 返回类型放宽到 `boolean | void`,`=== false` 时保留草稿、报「设置已在别处被修改」、不显示已保存。
213
+
214
+ Refs #75。
215
+
216
+ ### #82 RPC 桥惰性解析
217
+
218
+ 2.4.6 的 CHANGELOG 声称这条已修,但发布产物里 `installPackRpc` 仍只捕获一次。现已改为每次 `callPack` 前 `if (packRpcBridge === undefined) packRpcBridge = resolvePackRpcBridge()`:`connection` 就绪晚于 `apply()` 时,桥不会再永久为空、退化成裸 `fetch('/api/channel-pack')` 吃 401 而让账号池整片空白。
219
+
220
+ Refs #82。
221
+
222
+ ### 同批合并的社区 PR
223
+
224
+ - **#81([@jmglsi](https://github.com/jmglsi))** 第三条内容指纹:`Relative paths resolve from the workspace root` → `are resolved against the workspace root`。用陈述句的过去分词形式,语义、长度、换行位置都不变,被网关字符串表收录的子串消失。
225
+ - **#84([@Refeain](https://github.com/Refeain))** CodeArts 输出上限见下节。
226
+
227
+ ### #69 / #71 尚未定性
228
+
229
+ `#69 CodeArts 提示密钥无效` 只有一句话。它至少有两条来源:本条 `InferHub.4001.200`(SSE 帧里的 200,不是 4xx)与真正的 401/403。前者已随 #83 修掉;后者需要失败时的原始响应才能确认。
230
+ `#71 kimi k3.1 pro 没有响应` 同样只有一句话,且目录里没有 `kimi-k3.1-pro` 这个 id(有 `kimi-k3-1`)。请在 issue 里补一下:是空回复、卡住不动、还是有报错文案。
231
+
232
+ ### 详情:CodeArts 的输出上限是上限,不是默认值
233
+
72
234
  > 华为这条链接 65536 能用、131072 就空流,代码里也一直写着这个数字。但它是 `options.maxTokens ?? 65536` —— 只兜底,不设界。
73
235
 
74
236
  ### 触发条件:宿主把别的 provider 的额度原样递过来
@@ -105,6 +267,7 @@ TRAE 与 Cline 早就这么做了(`clampTraeMaxTokens` / `clampClineMaxTokens`
105
267
  Refs #83, #69。
106
268
 
107
269
  ## 附:第三条内容指纹 —— 文件引用指引里的 “resolve from the workspace root”(细节,已并入 2.5.1)
270
+ ### 详情:第三条内容指纹:文件引用指引里的 “resolve from the workspace root”
108
271
 
109
272
  > 2.4.1/2.4.2 修好的两个指纹管了一周,10 月 28 日又整片 400/11128。这次被点名的不是产品名,而是一句普通说明。
110
273
 
@@ -125,6 +288,12 @@ DSH 在 agent 有 `read` 工具时会贡献一段文件引用指引,开头是
125
288
  ### 其他
126
289
  - 全套 79 文件 1028 用例(1026 通过 + 2 跳过)。
127
290
 
291
+ ### 验证
292
+
293
+ - 全套 **80 文件 / 1033 用例**(含 #81 的 5 例、#84 的 5 例、本批新增)
294
+ - `pack.js` 每次改动后 `node --check` 通过
295
+ - server `tsc` 0 错;client `tsc` 的 6 条是既存问题(`accounts.ts` / `context-budget.ts` / `free-upstream.ts` 的 Node 类型不匹配),改前改后数量一致
296
+
128
297
  ## 2.4.6 — 扫码账号每次打开都空白:一份数据卡在两个细节里
129
298
 
130
299
  > 2.4.4/2.4.5 之后侧栏能进、能滚了,但扫码过的渠道在账号池里经常整片空白,重开也一样。磁盘上账号是齐的(`state.json` 里 15 条),所以问题全在读取链。
package/README.en.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  <p align="center">
4
4
  <a href="https://www.npmjs.com/package/dsh-xdpool"><img src="https://img.shields.io/npm/v/dsh-xdpool?style=flat-square&label=npm&color=cb3837" alt="npm version"></a>
5
- <a href="https://www.npmjs.com/package/dsh-workbuddy-xdpool"><img src="https://img.shields.io/badge/downloads-9k%2Fmo%20%28prev%20name%29-cb3837?style=flat-square" alt="npm downloads under the previous name"></a>
5
+ <a href="https://www.npmjs.com/package/dsh-xdpool"><img src="https://img.shields.io/npm/dm/dsh-xdpool?style=flat-square&label=downloads&color=cb3837" alt="npm downloads"></a>
6
6
  <a href="LICENSE"><img src="https://img.shields.io/github/license/XDTrees/dsh-xdpool?style=flat-square" alt="MIT license"></a>
7
7
  <a href="https://github.com/XDTrees/dsh-xdpool/stargazers"><img src="https://img.shields.io/github/stars/XDTrees/dsh-xdpool?style=flat-square" alt="GitHub stars"></a>
8
8
  </p>
@@ -10,15 +10,20 @@
10
10
  ## Join the group
11
11
 
12
12
  <p align="center">
13
- <img src="assets/community-qr.png" width="300" alt="WeChat group code: XD community group">
13
+ <img src="assets/community-qr-wechat.jpg" width="240" alt="WeChat bot code: scan to add the bot, then send XD to be pulled into the group">
14
+ &nbsp;&nbsp;&nbsp;&nbsp;
15
+ <img src="assets/community-qr-qq.jpg" width="240" alt="QQ group code: scan it to join the XD community group">
14
16
  <br>
15
- <sub>Scan with WeChat to join the <b>XD community group</b>. The code is valid for 7 days; if it has expired, say so in <a href="https://github.com/XDTrees/dsh-xdpool/issues">issues</a> and it will be refreshed.</sub>
17
+ <b>Left: WeChat (bot)</b> — scanning only adds the bot. <b>Send “XD”</b> and it pulls you into the group; scanning alone does nothing.<br>
18
+ <b>Right: QQ group</b> — scan and you are in. Group number 1103463688.
16
19
  <br>
17
- <sub>The 交流群 button next to “Star” in the card's top-right corner opens this same code — no need to come back to the README.</sub>
20
+ <sub>Both groups are live; use whichever you prefer. If a code stops working, say so in <a href="https://github.com/XDTrees/dsh-xdpool/issues">issues</a> and it will be refreshed.</sub>
21
+ <br>
22
+ <sub>The 交流群 button next to “Star” in the card's top-right corner opens these same two codes — no need to come back to the README.</sub>
18
23
  </p>
19
24
 
20
25
  <p align="center">
21
- <sub>Download stats still come from the previous package name <code>dsh-workbuddy-xdpool</code> (8,976/month as of 2026-10-12 — every download before the rename; the live shields badge kept getting rate-limited by the npm upstream, hence the snapshot figure). The new <code>dsh-xdpool</code> package accumulates its own stats, and the badge switches back to live data later.</sub>
26
+ <sub>The downloads badge reads <code>dsh-xdpool</code>'s own live npm stats now, not the pre-rename snapshot.</sub>
22
27
  </p>
23
28
 
24
29
  English | [中文](./README.md)
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  <p align="center">
4
4
  <a href="https://www.npmjs.com/package/dsh-xdpool"><img src="https://img.shields.io/npm/v/dsh-xdpool?style=flat-square&label=npm&color=cb3837" alt="npm version"></a>
5
- <a href="https://www.npmjs.com/package/dsh-workbuddy-xdpool"><img src="https://img.shields.io/badge/downloads-9k%2F%E6%9C%88%20%28%E6%97%A7%E5%90%8D%29-cb3837?style=flat-square" alt="npm downloads under the previous name"></a>
5
+ <a href="https://www.npmjs.com/package/dsh-xdpool"><img src="https://img.shields.io/npm/dm/dsh-xdpool?style=flat-square&label=downloads&color=cb3837" alt="npm downloads"></a>
6
6
  <a href="LICENSE"><img src="https://img.shields.io/github/license/XDTrees/dsh-xdpool?style=flat-square" alt="MIT license"></a>
7
7
  <a href="https://github.com/XDTrees/dsh-xdpool/stargazers"><img src="https://img.shields.io/github/stars/XDTrees/dsh-xdpool?style=flat-square" alt="GitHub stars"></a>
8
8
  </p>
@@ -10,15 +10,20 @@
10
10
  ## 先加群
11
11
 
12
12
  <p align="center">
13
- <img src="assets/community-qr.png" width="300" alt="微信群二维码:XD 交流群">
13
+ <img src="assets/community-qr-wechat.jpg" width="240" alt="微信机器人二维码:扫码添加后发送 XD 拉你进群">
14
+ &nbsp;&nbsp;&nbsp;&nbsp;
15
+ <img src="assets/community-qr-qq.jpg" width="240" alt="QQ 群二维码:直接扫码加入 XD 交流群">
14
16
  <br>
15
- <sub>微信扫一扫加入 <b>XD 交流群</b>。二维码 7 天内有效;过期了在 <a href="https://github.com/XDTrees/dsh-xdpool/issues">issues</a> 说一声会换新。</sub>
17
+ <b>左:微信(机器人)</b> —— 扫码添加机器人后<b>发送「XD」</b>,它才会拉你进群;只扫码不加不发是不会有反应的。<br>
18
+ <b>右:QQ 群</b> —— 直接扫码即可加入,群号 1103463688。
16
19
  <br>
17
- <sub>卡片右上角「点Star」旁边的「交流群」按钮打开的也是这个码 —— 不用回头找 README。</sub>
20
+ <sub>两个群都在,哪个方便用哪个。二维码失效了在 <a href="https://github.com/XDTrees/dsh-xdpool/issues">issues</a> 说一声会换新。</sub>
21
+ <br>
22
+ <sub>卡片右上角「点Star」旁边的「交流群」按钮打开的是同样这两张码 —— 不用回头找 README。</sub>
18
23
  </p>
19
24
 
20
25
  <p align="center">
21
- <sub>下载量统计沿用旧包名 <code>dsh-workbuddy-xdpool</code>(截至 2026-10-12 为 8,976 次/月,改名前的全部下载;shields 的实时徽章常被 npm 上游限流,所以这里用了快照数字)。新包 <code>dsh-xdpool</code> 的统计会随时间累积,之后徽章会换回实时数据。</sub>
26
+ <sub>下载量徽章读的是 npm 上 <code>dsh-xdpool</code> 自己的实时统计,不再是改名前的快照。</sub>
22
27
  </p>
23
28
 
24
29
  [English](./README.en.md) | 中文
Binary file
Binary file