dsh-deepseek-web-login 0.6.11 → 0.6.13

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
@@ -2,6 +2,61 @@
2
2
 
3
3
  本项目遵循大致语义化版本;日期为本地时间。
4
4
 
5
+ ## 0.6.13 — 2026-09-30
6
+
7
+ **账号列表加「邮箱 / 手机号」标志。**
8
+
9
+ 用户要求:"给每个账号后面加个(邮箱)(手机号)等这样的标志呗"(多号并存时列表里只有一串脱敏
10
+ 标识,看不出这号是用什么注册的)。
11
+
12
+ 判据 `identifierKindOf()`(纯函数,`accounts.ts`):
13
+
14
+ 1. 记录里带了显式 `email` / `mobile_number` 字段 ⇒ 直接用(最准)。
15
+ 2. 老记录只有服务端给的脱敏 `display` ⇒ 按形态判:含 `@` = 邮箱;数字形态 = 手机号。
16
+ ⚠️ 门槛不能按"至少 6 位数字"—— 脱敏串 `183******78` 去掉星号**只剩 5 位**数字,
17
+ 第一版就是这么判错的(被自己的用例抓出来)。最终判据:「带掩码星号且 ≥5 位数字」
18
+ 或「纯数字且 ≥7 位」。
19
+ 3. 判不出来就是 `unknown`,界面**不显示**标志(不瞎猜)。
20
+
21
+ 判据在**主机侧**算好(`/accounts` 的 `identifierKind`),客户端只负责画 —— 免得两边各写一套。
22
+ 另加一枚中性色徽章样式(不占用红/黄/绿这些状态色)。
23
+
24
+ 已知边界:服务端只给**一个** `display`(`pickUserDisplay` 优先邮箱),所以"邮箱和手机都绑了"的
25
+ 账号会被标成邮箱 —— 手上没有足够信息区分时,如实只标能确定的那个。
26
+
27
+ 用例:`check-accounts` +6 条(显式字段优先 / 邮箱形态 / 手机号形态 / 判不出就不猜 / 短数字不算手机号 /
28
+ 标志文字);`check-accounts-view` +1 条端到端(夹具就是真实的"脱敏手机号 + 邮箱"两种形态)。
29
+
30
+ ## 0.6.12 — 2026-09-30
31
+
32
+ **按 DSH 会话(窗口)分槽:一个窗口一个网页端会话 + 一条链。**
33
+
34
+ 用户要求「每个窗口各用自己那个网页端会话,而不是占用之前的窗口」。上一版我判断"做不到"是
35
+ **查错了地方** —— 我看的是宿主日志里的 `request/header` 事件(那里只有 config / adapterDefaults / tools),
36
+ 而适配器实际收到的 `GenerateOptions` 里**有 `sessionId`**。宿主内核
37
+ (`@deepseek-ai/dsh-llm` 的 `types.d.ts`,npm 上公开)原文:
38
+
39
+ ```ts
40
+ /** Session identity stamped by the loop for listener routing. Adapters ignore
41
+ * it; replay uses it to keep concurrent parent and child cursors independent. */
42
+ sessionId?: Branded<'SessionId'>;
43
+ ```
44
+
45
+ 改动:
46
+
47
+ 1. `adapter.ts` 把 `options.sessionId` 透传成 `dshSessionId`。
48
+ 2. `webapi.ts` 的复用槽与投喂链从**全局单槽**改成**按 `账号 + DSH 会话` 分槽的 Map**
49
+ (`slotKeyFor`):窗口 A 与窗口 B 各拿一个网页端会话、各挂一条链,**切回来还复用自己那条**。
50
+ 3. 上限 `MAX_CONVERSATION_SLOTS = 6`:超过就淘汰**最久没用**的那条(连同它的网页端会话一起删),
51
+ 免得开过的窗口越多、服务端残留的会话越多。
52
+ 4. 拿不到 `sessionId` 时(老宿主 / 手工构造的请求)退化成共用一个 `(unknown)` 槽,行为与以前一致。
53
+ 5. 面板「立即清理」相应改成清**所有**窗口的会话(`clearLiveSession` 返回列表);
54
+ `GET /context-mode` 的 `chain` 多回一个 `slots`(当前养着几条会话)。
55
+
56
+ 用例:`check-session-reuse` 新增两条(换窗口各用各的 / 切回复用自己那条 / 无身份时退化);
57
+ 原有"换账号"那条按新设计改了断言 —— **意图不变、时机变了**(槽不再被覆盖,于是改成
58
+ "退役时每个会话必须由它自己那个账号的回调回收")。`check-bundle` 的链式接线守卫同步到新写法。
59
+
5
60
  ## 0.6.11 — 2026-09-30
6
61
 
7
62
  **清理策略按投喂模式分开:链式模式不自动清理、改为手动;链式下也不再按轮数轮换会话。**
package/lib/client.js CHANGED
@@ -377,6 +377,8 @@ font-size:13px;line-height:1.6;color:var(--fg);max-width:760px;padding:2px 0 12p
377
377
  .dsw-badge.on{color:var(--ok);background:rgba(26,159,90,.15);background:var(--ok-weak)}
378
378
  .dsw-badge.off{color:var(--warn);background:rgba(200,140,20,.16);background:var(--warn-weak)}
379
379
  .dsw-badge.err{color:var(--err);background:rgba(217,48,37,.15);background:var(--err-weak)}
380
+ /* 中性信息标志(邮箱 / 手机号):不属于状态,别用红黄绿去干扰状态色 */
381
+ .dsw-badge.kind{color:var(--fg);background:var(--code-bg);opacity:.85}
380
382
  /* 按钮:hover 不再整体调 opacity —— 那会把文字一起变淡,看着像被禁用了。
381
383
  改成背景微调 + 按下时 1px 位移(物理感);focus-visible 补上键盘可达性。 */
382
384
  .dsw-btn{font:inherit;font-size:12px;font-weight:500;line-height:1.5;padding:6px 13px;
@@ -963,6 +965,8 @@ background:var(--bg2);white-space:pre-wrap;font-size:12px}
963
965
  const main = el("div", "dsw-account-main");
964
966
  const title = el("div", "dsw-account-title");
965
967
  title.append(el("span", void 0, item.title || item.id));
968
+ if (item.identifierKind === "email") title.append(el("span", "dsw-badge kind", "邮箱"));
969
+ else if (item.identifierKind === "mobile") title.append(el("span", "dsw-badge kind", "手机号"));
966
970
  if (item.isActive) title.append(el("span", "dsw-badge on", "✅ 当前"));
967
971
  if (item.unverified) title.append(el("span", "dsw-badge off", "❔ 未校验"));
968
972
  if (item.limit && Number.isFinite(item.limit.untilMs) && item.limit.untilMs > Date.now()) title.append(el("span", "dsw-badge off", `⏳ 受限至 ${shortTime(item.limit.untilMs)}`));
@@ -1767,7 +1771,8 @@ background:var(--bg2);white-space:pre-wrap;font-size:12px}
1767
1771
  method: "POST",
1768
1772
  body: "{}"
1769
1773
  }).then((result) => {
1770
- cleanupNowHint.textContent = result?.cleared ? `已退出会话 ${String(result.cleared).slice(0, 8)}…,队列剩 ${result?.pending ?? 0} 个;下一轮会重新当链首(全量发一次)` : `没有在用会话;队列剩 ${result?.pending ?? 0} 个`;
1774
+ const n = Number(result?.cleared ?? 0);
1775
+ cleanupNowHint.textContent = n ? `已退出 ${n} 个网页端会话,队列剩 ${result?.pending ?? 0} 个;下一轮会重新当链首(全量发一次)` : `没有在用会话;队列剩 ${result?.pending ?? 0} 个`;
1771
1776
  }).catch((error) => {
1772
1777
  cleanupNowHint.textContent = `清理失败:${error?.message ?? error}`;
1773
1778
  }).finally(() => {