前言¶
DSH 的理念是「一切皆插件」,插件以當前 dsh 進程的權限運行,能改 host 裏的東西。對桌面版用戶來說,比較磨人的一類故障是:使用過程中重啓若干次後,DSH 必然起不來,彈窗報 desktop welcome: Web authentication failed,並建議重裝或禁用插件。手動刪掉 Cookie 庫能救回來,但重啓幾十次又會出現同樣的問題。soyorinhhh/dsh-cookie-doctor 就是針對這個故障的插件:清理堆積的 dsh-auth-* cookie,並從根上阻止它們再次堆積。它由 soyorinhhh 維護,分類是 admin-security,GitHub 上 1 個 star。
下面按「是什麼、爲什麼有用、怎麼裝、怎麼用、需要注意什麼」介紹。
這是什麼¶
一句話定位:DSH 桌面版「Web authentication failed」崩潰治理插件。它的目標不是幫你繞過問題,而是把根因找出來並止住。
| 項 | 內容 |
|---|---|
| 插件名稱 | dsh-cookie-doctor |
| 維護者 | soyorinhhh |
| 分類 | admin-security |
| 版本 | 0.1.0(見 package.json) |
| 許可證 | MIT |
| 運行要求 | Node >= 22.13.0 |
| 源碼 | https://github.com/soyorinhhh/dsh-cookie-doctor |
| 目錄頁 | https://www.skillhub.cn/plugins/soyorinhhh/dsh-cookie-doctor |
插件掛載在 host 進程裏,接管 dsh-host-webserver 創建的 http.Server。它不改 DSH 的鑑權邏輯,也不改端口、不碰 host 頭;cookie 名照舊按 host:port 哈希,插件只是把這個 session 用不到的歷史 cookie 一條條作廢。
問題根因¶
sessions cookie 的名字裏帶了端口,而 cookie 本身不按端口隔離。@deepseek-ai/dsh-client-connection 裏是這麼算 cookie 名的:
const COOKIE_PREFIX = "dsh-auth-";
/** Canonical request authority used as the cookie name and signed audience. */
function cookieName(authority) {
return COOKIE_PREFIX + encodeBase64Url(createHash("sha256").update(authority).digest());
}
而 authority 來自請求頭裏的 host:
function requestAuthority(headers) {
const host = header(headers, "host"); // "127.0.0.1:54321"
...
return new URL(`http://${host}`).host;
}
桌面版每次啓動都隨機換端口,於是:
- 每次啓動都算出一個新的 cookie 名(
dsh-auth-+ host:端口 的哈希); - Chromium 存 cookie 不看端口,這些 cookie 全都堆在
127.0.0.1這同一個域下; - shell 的 welcome backend 會把庫裏該域下的所有 cookie 拼成一個
Cookie頭髮出去:
async () => (await session.defaultSession.cookies.get({ url: ready.url }))
.map((cookie) => `${cookie.name}=${cookie.value}`).join("; ")
- 每條這種 cookie 大約 220~260 字節,攢到 70 條出頭就頂到 Node 默認的
maxHeaderSize(16384 字節); - Node 的 HTTP 解析器在進入業務代碼之前就直接返回 431,Electron 那邊看到的就是認證失敗。
README 給出的實測(test/simulate.mjs 場景 A)是:第 73 次啓動時請求頭 16423 字節,返回 431。README 還提到,截至 0.2.1-rc.3 官方仍未修復。
插件做了什麼¶
三個動作:
| 動作 | 作用 |
|---|---|
server.maxHeaderSize = 256KB |
把天花板抬到約 1000 條 cookie,已經攢了 70+ 條的機器也能立刻啓動 |
每條請求都算一遍「本輪該有的 cookie 名」,把其它 dsh-auth-* 用 Set-Cookie: …=; Max-Age=0 過期掉 |
Chromium 自己清理,庫裏永遠只剩 1 條,不再堆積 |
統計寫進 ~/.dsh/cookie-doctor/report.json |
能直接看到到底有沒有生效 |
過期指令走的是同一條 Chromium 網絡棧,所以和當初寫下它們的通道完全一致。README 裏的實測結果:
| 場景 | 結果 |
|---|---|
| A. 不裝插件 | 第 73 次啓動 431 崩潰 |
| B. 裝插件,從零開始 90 次啓動 | Cookie 頭恆爲 223 字節 / 1 條 |
| C. 裝插件,機器已攢 76 條(請求頭 17098 字節,已超默認上限) | 不崩,第一次請求就自愈到 1 條 |
另外,README 記錄了這個插件在真實 DSH host 裏跑過:dsh --profile ctest --port 18099 起來後,帶 20000 字節 Cookie 頭髮請求,返回 401 而不是 431,響應裏帶上了過期指令。
插件對 apply() 做了整體 try/catch:即使初始化異常也只會打一行警告,不會讓 host 啓動失敗。
安裝¶
README 裏的安裝方式不是 dsh plugin add,而是倉庫自帶的安裝腳本:
node scripts/install.mjs # 裝進 ~/.dsh/profiles/desktop
node scripts/install.mjs --dry-run # 先看它要幹什麼
腳本做的事(不需要聯網、不需要 pnpm):
~/.dsh/plugins/dsh-cookie-doctor→ 指向本倉庫(Windows 用 junction,不用管理員權限)<profile>/node_modules/dsh-cookie-doctor→ 指向上面的目錄,讓 Node 能解析到- 在 profile 的
package.json里加上dependencies和dsh.profile.bundles(改之前自動備份)
裝完重啓 DeepSeek Harness。控制台會打印一行:
[cookie-doctor] 已接管 host HTTP 通道:maxHeaderSize 16384 → 262144,過期策略 開啓
卸載:
node scripts/install.mjs --uninstall
按 README 的說法,插件的 bundle patch 路徑是 ./cordis.patch.yml,配置項寫在這個文件(或 profile 層覆寫)裏。
已經起不來了怎麼辦¶
插件只能在 host 起來之後才跑;當請求頭已經超過 16KB 時 host 根本收不到請求,所以已經病發的機器得先在外面清一次:
# 1. 完全退出 DeepSeek Harness(連托盤一起退)
node scripts/diagnose.mjs --dry-run # 先體檢:會看到 dsh-auth-* 有幾十條
node scripts/repair.mjs --dry-run # 看會刪多少
node scripts/repair.mjs # 真刪,自動備份原庫
# 2. 重新啓動 DSH
repair.mjs 只刪 dsh-auth-* 那些行,別的 cookie 一條不動。刪之前會自動生成 Cookies.bak-<時間戳>。
如果連 DSH 都啓動不了、只想手動來,README 給出的等價做法是刪掉:
%APPDATA%\@deepseek-ai\dsh-desktop\Network\Cookies
以及同目錄的 Cookies-journal。效果等價,但會連別的 cookie 一起清掉。
體檢腳本¶
node scripts/diagnose.mjs # 看當前堆了多少、會不會炸
node scripts/diagnose.mjs --json # 機器可讀
README 給出的輸出示例:
cookie 庫:C:\Users\me\AppData\Roaming\@deepseek-ai\dsh-desktop\Network\Cookies
cookie 總數:80(其中 dsh-auth-* 80 條,其它 0 條)
127.0.0.1 → 80 條,拼成請求頭約 20400 字節
dsh-auth-Ab3x…
…
🔴 已經炸了:請求頭超過 16KB,啓動必定報 Web authentication failed
Node 默認請求頭上限 16384 字節,當前最壞 20400 字節
需要注意:DSH 運行中 cookie 庫被 Chromium 獨佔鎖定,體檢和修復都要先完全退出 DSH。只想看一眼的話,可以先複製一份庫文件,再用 --db <副本> 分析。
配置¶
改 cordis.patch.yml 裏的 config(或 profile 層覆寫):
| 鍵 | 默認 | 說明 |
|---|---|---|
maxHeaderBytes |
262144 |
抬到多少。0 = 不動默認值(不推薦,默認值就是那個坑) |
purgeStale |
true |
是否過期掉歷史 cookie |
maxPurgePerResponse |
200 |
一條響應最多帶多少條過期指令 |
warnAuthCookies |
8 |
超過這麼多條就警告一次 |
reportPath |
$DSH_HOME/cookie-doctor/report.json |
統計落盤位置 |
quiet |
false |
關掉日誌 |
測試¶
README 提供了兩個可以自己跑的測試:
node test/simulate.mjs # 復現故障 + 驗證修復(含病發機器自愈)
node test/repair.test.mjs # 體檢/修復腳本,用 Chromium 同結構的 cookie 庫跑
test/simulate.mjs 的實測輸出:
### A. 不裝插件(復現線上故障)
首次:請求頭 223 字節,庫中 1 條
末次:請求頭 16423 字節,庫中 73 條
❌ 第 73 次啓動失敗:auth=303 welcome=431
### B. 裝插件(從零開始)
峯值請求頭 223 字節 / 庫中 1 條,90 次啓動全程正常
### C. 裝插件 + 已攢 76 條(病發機器)
首次:請求頭 17098 字節 → 自愈到 1 條,全程正常
幾種取捨¶
- 抬高
maxHeaderSize有沒有副作用? README 的解釋是:host 只監聽迴環地址,抬高上限只是讓「頭部異常大」的請求不至於被解析器直接掐掉;真正的訪問控制仍然由/api的 loopback + Origin 圍欄負責。不想要可以設maxHeaderBytes: 0。 - 爲什麼不乾脆把 cookie 名改成不帶端口? 那樣
authority就失去了端口綁定(isAuthenticated會校驗payload.authority === authority),等於放寬鑑權語義;而且改的是 DSH 自己的代碼,插件做不到、也不該越界。所以插件選擇「保留語義,只清理垃圾」。
適用場景與注意¶
適合:
- 用 DSH 桌面版,遇到過重啓後報
desktop welcome: Web authentication failed,手動刪 Cookie 庫能救但會復發的人。 - 想先看清楚自己機器上
dsh-auth-*堆了多少條再決定要不要改配置的人。 - 不想重裝 DSH、不想禁用插件的人。
需要注意:
- 插件以當前 dsh 進程的權限運行,並在 host 進程裏接管 HTTP server。安裝前應檢查源碼與許可證(MIT)。
- 插件是第三方個人維護的,README 裏明確寫了「100% vibe coding,來源自 DeepSeek V4.1 Flash Harness 端」。要在自己的環境裏驗證一下,別直接當作官方修復。
- 病發的機器需要先在外面執行
repair.mjs,插件本身只能阻止後續堆積。 - DSH 運行期間 cookie 庫被鎖定,體檢和修復前必須完全退出 DSH(包括托盤)。
小結¶
這個插件的價值在於把一個只能靠刪文件解決的偶發崩潰,變成兩步可復現的操作:先 diagnose.mjs 看清當前堆了多少,再裝插件(或先 repair.mjs 清一次)阻止復發。它不碰鑑權語義,所以風險面比較明確。
- 目錄頁:https://www.skillhub.cn/plugins/soyorinhhh/dsh-cookie-doctor
- 源碼:https://github.com/soyorinhhh/dsh-cookie-doctor
注:DSH 社區目錄是獨立站點,與 DeepSeek / 幻方無官方從屬關係。