dsh-deepseek-web-login 0.7.3 → 0.7.5
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 +83 -0
- package/lib/index.js +48 -5
- package/lib/index.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,89 @@
|
|
|
2
2
|
|
|
3
3
|
本项目大致遵循语义化版本;日期为本地时间。
|
|
4
4
|
|
|
5
|
+
## 0.7.5 — 2026-10-10
|
|
6
|
+
|
|
7
|
+
**修好 0.6.43 那个从未生效的修复:退出 DSH 会把持久化状态自己抹掉。**
|
|
8
|
+
|
|
9
|
+
### 根因
|
|
10
|
+
|
|
11
|
+
`disposeSessionReuse()` 是**卸载钩子**(`index.ts` 的 `ctx.effect(() => () => …)`),
|
|
12
|
+
它`clear()` 内存之后**紧接着 `persistResumeState()`** ⇒ **把空态写回了文件**。
|
|
13
|
+
|
|
14
|
+
⇒ **每次退出 DSH,`resume-state.json` 都被自己清空** ⇒ 下次启动 `restoreResumeState()` 读回空。
|
|
15
|
+
**0.6.43/0.7.1 的"重启后仍能续上同一会话"在真实使用下等于没生效。**
|
|
16
|
+
|
|
17
|
+
症状:同一对话线被迫建新会话 + 网页端出现「修改 / 重新生成」分叉(实测 27 万字符全量重发)。
|
|
18
|
+
|
|
19
|
+
### 修法
|
|
20
|
+
|
|
21
|
+
`persistResumeState(opts?: { persist?: boolean })` —— **退出 / 重置语义**的调用点传 `false`:
|
|
22
|
+
|
|
23
|
+
- `disposeSessionReuse()`(卸载钩子,最要紧)
|
|
24
|
+
- `resetSessionReuse()`
|
|
25
|
+
- `resetContextChain()`
|
|
26
|
+
|
|
27
|
+
其余 8 处调用点都是**真实增删改**(入栈、出栈、链更新、链删除、会话退役),**照旧落盘**。
|
|
28
|
+
|
|
29
|
+
### 为什么之前一直是绿的
|
|
30
|
+
|
|
31
|
+
- `check-resume-after-restart` 只测**「进程 → 进程」**,**不经过卸载钩子**;
|
|
32
|
+
- `check-bundle` 守的是"落盘点存在",**不守"落盘的内容对不对"**。
|
|
33
|
+
|
|
34
|
+
⚠️ **加了持久化就必须测「退出 → 启动」这个生命周期边界。**
|
|
35
|
+
|
|
36
|
+
### 新增守卫
|
|
37
|
+
|
|
38
|
+
`tests/check-persist-lifecycle.mjs`(3 条)—— 先用 `writeResumeStateForTest` 造出**非空**落盘态,
|
|
39
|
+
再调三个清空函数,断言**文件内容没被写空**。变异验证:三处改回 `persistResumeState()` ⇒ 三条一起红。
|
|
40
|
+
|
|
41
|
+
`check-bundle` 新增一条守**卸载钩子那个调用点真的存在**(断"没被调用")。
|
|
42
|
+
|
|
43
|
+
⚠️ 这条守卫的首版**恒真**:`slice().includes('disposeSessionReuse()')` 命中了同一段里那行
|
|
44
|
+
**注释**「① `disposeSessionReuse()` 把复用槽里的会话…」⇒ 删掉真实调用后仍为真。
|
|
45
|
+
⇒ 改成**按行判**(`line.trim() === 'disposeSessionReuse()'`)才抓住。
|
|
46
|
+
**这是「断言会被注释引用污染」的又一例,与 MEMORY纪律③同源。**
|
|
47
|
+
|
|
48
|
+
### 验证
|
|
49
|
+
|
|
50
|
+
`tsc` / build / 产物 / 新守卫 3 / 产物新增那条 / 外部审查 8 / `check-resume-after-restart` / 隔离 全过。
|
|
51
|
+
|
|
52
|
+
## 0.7.4 — 2026-10-10
|
|
53
|
+
|
|
54
|
+
**收窄 0.7.3 的 `--no-sandbox`:只给 headless 传输层,登录窗口保持 sandbox。**
|
|
55
|
+
|
|
56
|
+
### 0.7.3 的问题
|
|
57
|
+
|
|
58
|
+
`--no-sandbox` 被加进 `buildBrowserArgs()`,而那个函数**被两处共用**:
|
|
59
|
+
|
|
60
|
+
| 调用点 | 用途 | 该不该关 sandbox |
|
|
61
|
+
|---|---|---|
|
|
62
|
+
| `browser-login.ts:538` | **登录窗口**(可见真实浏览器,用户在里面手动输密码) | ❌ 不该 |
|
|
63
|
+
| `browser-transport.ts:193` | 请求代理(headless 后台,只请求 `about:blank`) | ✅ Linux/CI 需要 |
|
|
64
|
+
|
|
65
|
+
⇒ 0.7.3 **连登录窗口的 sandbox 也关了**。sandbox 是浏览器跑第三方网页代码时的进程隔离,
|
|
66
|
+
而登录窗口要加载 DeepSeek 真实页面 —— **那才是真正扩大攻击面**。
|
|
67
|
+
(0.7.3 的 CHANGELOG 写"攻击面不因此变大",**那句话不准确**,这里更正。)
|
|
68
|
+
|
|
69
|
+
### 现在
|
|
70
|
+
|
|
71
|
+
`--no-sandbox` 移到新函数 `transportExtraArgs()`,**只有 headless 传输层**调用它。
|
|
72
|
+
传输层不加载任何第三方页面、只发 HTTP ⇒ 关 sandbox 的收益(Linux/CI 可用)大于代价。
|
|
73
|
+
|
|
74
|
+
### 守卫
|
|
75
|
+
|
|
76
|
+
三条,缺一不可:
|
|
77
|
+
|
|
78
|
+
1. `transportExtraArgs()` 里**必须**有 `--no-sandbox`(否则 Linux/CI 起不来);
|
|
79
|
+
2. `buildBrowserArgs()` 里**必须没有**(登录窗口要用);
|
|
80
|
+
3. **传输层的 spawn 必须真的调用它** —— 前两条只断函数内容,断不了"调用点被删"。
|
|
81
|
+
|
|
82
|
+
三条都做过变异验证(挪位置 / 拿掉内容 / 删调用行,各自打红)。
|
|
83
|
+
|
|
84
|
+
### 验证
|
|
85
|
+
|
|
86
|
+
`tsc` / build / 产物 / 17 项登录 / 8 项新守卫 / 隔离 / `check-browser-transport`(真启浏览器)/ **67/67** 全过。
|
|
87
|
+
|
|
5
88
|
## 0.7.3 — 2026-10-10
|
|
6
89
|
|
|
7
90
|
**修好 Linux/CI 上浏览器起不来的问题**(0.7.2 只在 ubuntu-latest 上挂,macOS / Windows 同 commit 通过)。
|
package/lib/index.js
CHANGED
|
@@ -3991,10 +3991,32 @@ function buildBrowserArgs(profileDir, url) {
|
|
|
3991
3991
|
"--disable-sync",
|
|
3992
3992
|
"--no-service-autorun",
|
|
3993
3993
|
"--disable-background-mode",
|
|
3994
|
-
"--no-sandbox",
|
|
3995
3994
|
url
|
|
3996
3995
|
];
|
|
3997
3996
|
}
|
|
3997
|
+
/**
|
|
3998
|
+
* 只给 **headless 请求代理**追加的启动参数(0.7.3)。
|
|
3999
|
+
*
|
|
4000
|
+
* ## 为什么需要 `--no-sandbox`
|
|
4001
|
+
*
|
|
4002
|
+
* headless Chrome 在 Linux 上默认要 sandbox,而 Linux 上跑浏览器的人只有两种:
|
|
4003
|
+
* root(容器 / CI runner)或没有 user namespace 权限的普通用户 —— **两种都起不来**。
|
|
4004
|
+
* 症状伪装成「浏览器调试端口未就绪」(等满 25s 拿不到 `DevToolsActivePort`),
|
|
4005
|
+
* 看起来像超时、实际是启动失败 ⇒ **别去调大那个超时**,那只会掩盖真问题。
|
|
4006
|
+
*
|
|
4007
|
+
* ## 为什么只给传输层
|
|
4008
|
+
*
|
|
4009
|
+
* sandbox 是浏览器里跑第三方网页代码时的进程隔离。**登录窗口会加载 DeepSeek 的真实页面、
|
|
4010
|
+
* 用户还在里面手动输密码** —— 关掉它的 sandbox 才是真正扩大攻击面。
|
|
4011
|
+
* 传输层只请求 `about:blank` + 发 HTTP、**不加载任何第三方页面**,
|
|
4012
|
+
* 所以关掉它的 sandbox 换来的收益(Linux/CI 可用)大于代价。
|
|
4013
|
+
*
|
|
4014
|
+
* ⚠️ 若哪天登录窗口也要在 Linux 上跑,应在这里按 `headless` 判定,
|
|
4015
|
+
* **而不是把 flag 挪进 `buildBrowserArgs`**(那会连带关掉登录窗口的)。
|
|
4016
|
+
*/
|
|
4017
|
+
function transportExtraArgs() {
|
|
4018
|
+
return ["--no-sandbox"];
|
|
4019
|
+
}
|
|
3998
4020
|
/** 解析 `<profile>/DevToolsActivePort`:第一行是端口;容忍 CRLF 与附带内容。 */
|
|
3999
4021
|
function parseDevToolsActivePort(text) {
|
|
4000
4022
|
const first = String(text ?? "").split(/\r?\n/)[0]?.trim();
|
|
@@ -4677,6 +4699,7 @@ async function launchBrowserTransport() {
|
|
|
4677
4699
|
}
|
|
4678
4700
|
const child = spawn(browser.path, [
|
|
4679
4701
|
...buildBrowserArgs(PROFILE_DIR, "about:blank"),
|
|
4702
|
+
...transportExtraArgs(),
|
|
4680
4703
|
"--headless=new",
|
|
4681
4704
|
"--disable-gpu",
|
|
4682
4705
|
"--disable-dev-shm-usage",
|
|
@@ -6605,7 +6628,27 @@ function persistStatePath() {
|
|
|
6605
6628
|
return join(webLoginDir(), PERSIST_FILE);
|
|
6606
6629
|
}
|
|
6607
6630
|
/** 把当前内存状态写盘。**永不抛** —— 落盘失败不该让正常请求失败。 */
|
|
6608
|
-
|
|
6631
|
+
/**
|
|
6632
|
+
* 把当前内存状态写盘。**永不抛** —— 落盘失败不该让正常请求失败。
|
|
6633
|
+
*
|
|
6634
|
+
* 🔴 2026-10-10(0.7.5)`opts.persist: false`:**退出 / 重置语义**的调用点要用它。
|
|
6635
|
+
*
|
|
6636
|
+
* ## 为什么需要这个开关
|
|
6637
|
+
*
|
|
6638
|
+
* 0.6.43 给会话槽与链加了落盘,好让"重启后仍能续上同一会话"。但三个**清空**函数
|
|
6639
|
+
* (`resetContextChain` / `disposeSessionReuse` / `resetSessionReuse`)在 `clear()` 之后
|
|
6640
|
+
* **紧接着调persistResumeState()** ⇒ **把空态写回了文件**。
|
|
6641
|
+
*
|
|
6642
|
+
* 其中 `disposeSessionReuse()` 是**卸载钩子**(`index.ts` 的 `ctx.effect(() => () => …��`)
|
|
6643
|
+
* ⇒ **每次退出 DSH,持久化的状态都被自己抹掉** ⇒ 重启后 `restoreResumeState()` 读回空。
|
|
6644
|
+
* 症状:网页端同一对话线被迫建新会话 + 出现「修改 / 重新生成」分叉(实测 27 万字符全量重发)。
|
|
6645
|
+
*
|
|
6646
|
+
* 之所以长期没被发现:`check-resume-after-restart` 只测**「进程 → 进程」**,
|
|
6647
|
+
* **不经过卸载钩子**;`check-bundle` 守的是"落盘点存在",**不守"落盘的内容对不对"**。
|
|
6648
|
+
* ⚠️ **加了持久化就必须测「退出 → 启动」这个生命周期边界。**
|
|
6649
|
+
*/
|
|
6650
|
+
function persistResumeState(opts) {
|
|
6651
|
+
if (opts?.persist === false) return;
|
|
6609
6652
|
try {
|
|
6610
6653
|
const chains = [...contextChains.entries()].map(([key, s]) => ({
|
|
6611
6654
|
key,
|
|
@@ -6752,7 +6795,7 @@ function resetContextChain() {
|
|
|
6752
6795
|
contextChains.clear();
|
|
6753
6796
|
lastChainKey = void 0;
|
|
6754
6797
|
lastFeedReason = void 0;
|
|
6755
|
-
persistResumeState();
|
|
6798
|
+
persistResumeState({ persist: false });
|
|
6756
6799
|
}
|
|
6757
6800
|
/** 给状态页看:当前链式投喂是否真的在跑(没用链式就返回 undefined)。 */
|
|
6758
6801
|
function contextChainInfo() {
|
|
@@ -6888,7 +6931,7 @@ function disposeSessionReuse() {
|
|
|
6888
6931
|
reuseSlots.clear();
|
|
6889
6932
|
contextChains.clear();
|
|
6890
6933
|
lastChainKey = void 0;
|
|
6891
|
-
persistResumeState();
|
|
6934
|
+
persistResumeState({ persist: false });
|
|
6892
6935
|
sentRefIdsBySession.clear();
|
|
6893
6936
|
if (slots.length === 0) return void 0;
|
|
6894
6937
|
for (const slot of slots) try {
|
|
@@ -10912,7 +10955,7 @@ async function checkForUpdate(current, fetchImpl) {
|
|
|
10912
10955
|
* 兜底常量与 package.json 的一致性由 `tests/check-smoke.mjs` 守着,不会漂。
|
|
10913
10956
|
*/
|
|
10914
10957
|
/** 与 package.json 保持一致的兜底版本(由测试保证不会漂)。 */
|
|
10915
|
-
const FALLBACK_VERSION = "0.7.
|
|
10958
|
+
const FALLBACK_VERSION = "0.7.5";
|
|
10916
10959
|
let cached;
|
|
10917
10960
|
/** 本插件版本(如 `0.1.26`)。 */
|
|
10918
10961
|
function pluginVersion() {
|