dsh-cookie-cleaner:清理桌面客户端 cookie 库里堆积的 dsh-auth-*

前言

DSH(DeepSeek Harness)桌面客户端用久了,可能在启动时报一句有点吓人的错:desktop welcome: Web authentication failed。重装客户端也没用。这个错的根因不在账号,而在本地 cookie 库:每次启动宿主都挑一个随机端口,认证 cookie 的名字里包含 host:port,端口一变就多一条,条目越积越多,最终挤爆 HTTP 请求头上限,服务端返回 431,客户端把它归因成认证失败。

下面介绍的插件 dsh-cookie-cleaner(维护者 drscrewdriver,分类 admin-security)就是用来处理这件事的:它能只读播报本地 dsh-auth-* 条目的堆积情况,并在客户端完全退出后用一个独立命令把它们清掉。和”每次问一遍 AI 怎么清”相比,它把因果链、各平台库位置、安全边界都固化在工具里了。

这是什么

一句话定位:一个 DSH 插件 + 一个随包分发的独立清理命令,目标是解决桌面客户端「约 70 次随机端口启动后必现 HTTP 431」的启动失败问题。

  • 维护者:drscrewdriver
  • 版本:0.2.1(来自 package.json)
  • 许可证:MIT
  • 运行环境:Node ≥ 22.19(用到 node:sqlite;Electron 44 内置的 Node 24 亦可)

插件本身永不写库:清理动作只能发生在客户端已完全退出的时间窗里,而那个时刻宿主插件自己并不存在。所以插件半只做只读播报和命令指引,真正的执行体是包里的 src/cli.js。两者分开设计,这是理解它用法的前提。

核心功能

先说一条设计上的取舍:读数和清理是两条独立的路径。面板与命令面会先尝试只读打开 cookie 库(readOnly),打开成功就给实时值——条数、请求头占用字节、占用百分比、距 431 还剩多少;打不开才明说”读不到”,不会把”没读到”洗成”0 条”。清理则是必须等到客户端退出后由独立脚本执行。

具体能力有四块:

  1. 运行时读数。客户端在跑时,Windows 下可以借宿主进程自己已打开的句柄做快照读数(仅 Windows,非 win32 直接走 busy 档);借来的结果带 snapshot:true,面板会单独标注”非实时”。快照有预算限制:每个 PID 只 OpenProcess 一次,默认上限 2 万次尝试 / 1200ms,超了报 scan-budget。
  2. 只读播报命令 /cookie-cleaner(status 或 clean),输出当前统计,并给出可直接复制执行的清理命令。
  3. profile patch 体检与修复 /cookie-cleaner patch(check / fix / revert / plan),用机器判定代替人工检查 profile 的 cordis.patch.yml 是否写对,并提供一键修复(写前经 Config schema 校验,失败自动回滚)。
  4. 独立清理 CLI,支持全删、仅删已过期、dry-run 三种模式,写盘前先备份,删除语句只由 host_key 白名单 + 名称前缀构成。

清理时安全上做了这几件事,值得单独列出来:

  • 写盘前先拷 .bak-<时间戳>,主库副本失败即整单放弃(全有或全无);
  • -wal / -shm / -journal sidecar 一并带走,sidecar 拷不上只记为跳过;
  • 拿不到 BEGIN IMMEDIATE 独占写锁就拒绝执行并给出对应档位的处置文案;
  • 库里没有 cookies 表或缺关键列一律拒绝,绝不对未知库执行写语句。

这些 cookie 不影响登录、也不涉及账号凭据:主窗口请求走内存态凭据不经 cookie jar,每次启动都用 launch token 重新换发。删掉的只是本地历史残留。

安装

作为 DSH 插件安装,同时把清理工具全局装好:

# 作为 DSH 插件(提供 /cookie-cleaner 只读播报)
dsh --profile desktop plugin add dsh-cookie-cleaner

# 清理工具随包分发;装完即可用 profile 里的别名,或全局安装后直接敲命令
npm i -g dsh-cookie-cleaner

需要注意一点:desktop profile 由客户端自己管理,命令行 dsh plugin add 可能被拒,报 profile "desktop" is managed exclusively by the Electron application。那种情况下在客户端的插件管理界面里装即可。清理脚本本身是独立的,全局 npm 安装或 node <包目录>/src/cli.js 都能跑,不依赖宿主装载。

装进 profile 后的别名路径:

# Windows
%USERPROFILE%\.dsh\profiles\desktop\node_modules\.bin\dsh-cookie-cleaner.cmd
# macOS / Linux
~/.dsh/profiles/desktop/node_modules/.bin/dsh-cookie-cleaner

典型用法

清理动作的两步顺序是固定的:先确认客户端已完全退出,再跑清理。先看通用参数:

dsh-cookie-cleaner                        查看现状:库在哪、多少条 dsh-auth-*、多少已过期
dsh-cookie-cleaner --clean                删除回环域(127.0.0.1/localhost/[::1])下全部 dsh-auth-*
dsh-cookie-cleaner --clean --expired-only 保守档:只删已过期的
dsh-cookie-cleaner --clean --dry-run      只看会删几条,不写盘
dsh-cookie-cleaner --db=<完整路径>         手动指定 cookie 库
dsh-cookie-cleaner --lang=de              指定输出语言(缺省跟随系统 locale)

退出码:0 成功;1 失败(被占用 / 无权限 / 找不到 / 参数非法)。建议先 dry-run 再实删。

各平台先退出客户端的方式不同,cookie 库默认位置也不同:

# Windows:托盘 → 退出;确认没有残留进程
Get-Process | Where-Object { $_.ProcessName -match 'DeepSeek|dsh' }
# 库位置:%APPDATA%\@deepseek-ai\dsh-desktop\Network\Cookies

dsh-cookie-cleaner --clean --dry-run
dsh-cookie-cleaner --clean
# macOS:Cmd+Q;Dock 图标消失不等于已退出
ps aux | grep -i '[D]eepSeek Harness'
# 库位置:~/Library/Application Support/@deepseek-ai/dsh-desktop/Network/Cookies

dsh-cookie-cleaner --clean --dry-run
dsh-cookie-cleaner --clean
# Linux:关闭主窗口后确认
pgrep -af 'DeepSeek Harness|dsh-desktop'
# 库位置:~/.config/@deepseek-ai/dsh-desktop/Network/Cookies(XDG_CONFIG_HOME 优先)

dsh-cookie-cleaner --clean --dry-run
dsh-cookie-cleaner --clean

# 只删已过期的:
dsh-cookie-cleaner --clean --expired-only

macOS 上没装全局命令时,直接跑包内脚本:

node ~/.dsh/profiles/desktop/node_modules/dsh-cookie-cleaner/src/cli.js --clean

成功输出长这样,删除条数、库体积变化、备份位置都在里面:

Deleted 3 dsh-auth-* entries (all)
  Database: ~/.config/@deepseek-ai/dsh-desktop/Network/Cookies  20480 B → 8192 B
  Backup: ~/.config/@deepseek-ai/dsh-desktop/Network/Cookies.bak-20261104-061512 (incl. -wal, -shm)
  Account credentials, sessions and plugin configuration were not touched; the local cookie is re-issued on next start.

关于堆积的根因:宿主每次启动用随机端口(apps/desktop-host/src/index.ts 里 host 启动参数是 --port 0),而认证 cookie 名是 dsh-auth- + base64url(sha256(authority)),http 下 authority 取 url.host(含端口);RFC 6265 里 cookie 不按端口隔离,于是 127.0.0.1 下所有历史端口的条目都会被一并发送。单条约 229 B,Node 默认 --max-http-header-size 16384,16384 / 229 ≈ 71.5,即约 70 次启动后必然失败。上游已有三份独立 discussion 报告钉到同一条因果链(#11366、#11410、#11650)。调小 connection.cookieMaxAgeDays(缩短 cookie 寿命)是面板「修复」真正写的那一项;固定 webserver.port 属于启动行为面,只保留在命令面。

适用场景与注意

适合的人:使用 DSH 桌面客户端的开发者,尤其是装了 rc.2 以后版本、曾出现过 desktop welcome: Web authentication failed 的用户;以及想从源头减少堆积、愿意改 profile 的 profile 维护者。插件侧提供设置项 userDataRoot、expiredOnly、lang、guardDays、guardMode,浏览器卡片在设置页顶级节「Cookie 清理器」与插件页配置卡各一处,提供体检 / 修复 / 回滚三个按钮。输出支持 9 种语言,跟随系统 locale(LANG=C.UTF-8 / POSIX 这类中性 locale 判为英文),认不出的语言落 zh。

几点注意:

  • 插件以当前 dsh 进程权限运行,清理动作要求客户端已完全退出,否则将被占用拒绝执行(bundled 的 Windows 借句柄快照只读能力不在此列,且仅 Windows)。
  • 社区目录站是独立站点,与 DeepSeek / 幻方无官方从属关系,本插件是第三方维护的。安装前建议检查源码与许可证(MIT),确认与你的环境兼容。
  • CLI 的体检功能在离线档只看得到文件层,运行态与 bundle 层的对比需要客户端起来后由面板或 /cookie-cleaner patch check 来查;CLI 一律不写 profile,写配置只有宿主侧那条带校验与回滚的路径。
  • Linux 用户注意 LANG=C.UTF-8 等中性 locale 会得到英文输出,需要中文就显式传 --lang=zh。

小结

这个插件的价值不在于”多了一个清理脚本”,而在于它把一个很难自查的问题(随机端口导致 cookie 名随端口变化、越积越多、最终 431)做了定位、量化和安全的清理,同时不碰账号凭据、会话和插件配置。对已经踩到 431 的用户来说,先 dry-run 再实删是一条成本很低的验证路径。

目录页:https://www.skillhub.cn/plugins/drscrewdriver/dsh-cookie-cleaner
GitHub:https://github.com/drscrewdriver/dsh-cookie-cleaner

羽毛球分组比赛记分
小程序二维码

欢迎使用《羽毛球分组比赛记分》微信小程序

小夜