中文EN

dsh-cookie-cleaner

toolsnpmMIT

桌面客户端的赛博端粒不老药:解决启动报 `desktop welcome: Web authentication failed`(HTTP 431)的现象——Electron 随机端口启动,`dsh-auth-*` 登录 cookie 随端口越积越多(70 余条、单条约 229 B),启动请求头撑爆 Node 默认 16 KB 上限,客户端直接起不来。两味药:脚本化清理器——报告并清理 cookie 库(Chromium SQLite)里残留的登录凭据,显式、离线、保留 `.bak` 副本,`--expired-only` 可收窄范围;设置面 patch 功能——经由 profile 的 `c

下载量 / Downloads
469

安装

dsh plugin --profile web add dsh-cookie-cleaner

沙箱测试

这个插件还没测过。提交测试 →

README

dsh-cookie-cleaner

清理 DSH(DeepSeek Harness)桌面客户端 cookie 库里堆积的本地登录凭据 cookie(dsh-auth-*),

解决的现象是启动报 desktop welcome: Web authentication failed(HTTP 431,约 70 次随机端口启动后必现,见下文因果链),

并把「为什么只能在客户端关闭时清理」讲清楚——不用每次再去问一遍 AI。

输出支持 9 种语言(zh / en / ja / ko / fr / de / it / ru / es),跟随系统 locale。

它是什么 / 为什么长这样

桌面客户端每次启动都会在 Electron 的 cookie 库里留下一条

dsh-auth-<base64url(sha256(host:port))>。名字按 host:port 哈希,端口一变就多一条,

各带 30 天有效期,于是历史记录长期堆积。

这些记录不影响登录,也不涉及账号凭据:

  • 主窗口的 HTTP/WS 请求走内存态凭据(宿主换发后由桌面层直接注入请求头),不经 cookie jar;
  • 鉴权只按当前 authority 派生的那一个名字取值,其余同名前缀条目本就永远读不到;
  • 每次启动都会用 launch token 重新换发。

关键约束(Windows 与 Linux 实测过 busy 与权限两种形态):这个库在客户端运行期间常常被 Chromium 占着打不开,

而宿主插件跑在 Electron 的纯 Node 模式子进程里,拿不到 session.cookies。所以:

清理动作不可能由「插件在启动时」完成——它只能发生在客户端已完全退出的时间窗里,
而那个时刻宿主插件本身并不存在。因此本仓库把执行体做成包内独立脚本,
插件半只做只读播报和命令指引,永不写库。
但读数不是这样:面板与命令面会先尝试只读打开(readOnly),打开成功就给实时值
(条数 / 请求头字节 / 占用百分比 / 距 431 还剩多少),打不开才明说读不到。
两者不拿同一个结论互相绑死:读不到之时的 busy 分支仍然保留,但不再当成必然。

堆积的根源是「每次启动一个随机端口」,而上游已有三份独立报告钉到同一条因果链

(#11366、

#11410、

#11650,约 70 次启动后必现 HTTP 431)。

它们给出的两条用户侧规避里,调小 connection.cookieMaxAgeDays 是面板「修复」真正写的那一项;

固定 webserver.port 属于启动行为面,只保留在命令面(面板不提供端口控件)。

完整关联见该章的

[为什么要固定端口](#为什么要固定端口上游三条-discussion-是同一条因果链)。

各平台的库位置与退出方式

平台 · cookie 库默认位置 · 完全退出客户端的方式

Windows · %APPDATA%\@deepseek-ai\dsh-desktop\Network\Cookies · 托盘图标 → 退出;确认任务管理器里没有 DeepSeek Harness

macOS · ~/Library/Application Support/@deepseek-ai/dsh-desktop/Network/Cookies · Cmd+Q 或菜单 → Quit;Dock 图标消失不等于已退出,用 ps aux \ · grep -i deepseek 确认

Linux · ~/.config/@deepseek-ai/dsh-desktop/Network/Cookies(XDG_CONFIG_HOME 优先) · 关闭主窗口后用 pgrep -af 'DeepSeek Harness\ · dsh-desktop' 确认没有残留

更早的 Chromium 布局把库直接放在 <userData>/Cookies(不带 Network/),工具两种都会试。

位置不对时用 --db=<完整路径>,或设 DSH_USER_DATA / DSH_COOKIE_DB 环境变量。

flatpak / snap 安装的客户端路径在常规位置之外,通常需要 --db 手动指。

运行期读数:借宿主自己已打开的句柄(仅 Windows)

客户端在跑时,Network\Cookies 被 Chromium 以不给共享读的方式开着。本机实测:

fs.openSync('r')、copyFileSync、DatabaseSync(readOnly)、?immutable=1 全部失败(EBUSY /

ERR_SQLITE_ERROR)。但目标进程自己手里就有一个可用句柄,于是读数阶梯是:

普通只读打开 → 成功就是实时值
           → busy 且是 win32 → 借句柄快照(NtQuerySystemInformation 枚举 → OpenProcess → DuplicateHandle → ReadFile)
                          → 还是不成 → 诚实地说读不到(绝不把“没读到”洗成 0 条)

边界与代价,全部写清楚:

  • 只读:不写、不改共享模式、只关自己 dup 出来的那份句柄;
  • 仅 Windows:非 win32 直接走 busy 档(不尝试任何原生调用);
  • 快照不是实时:借来的结果带 snapshot:true,面板单独一句「快照读数(借宿主句柄,非实时)」;
  • 只在宿主进程内有效:目标进程靠“与自身同一镜像名 + 父进程”识别,所以插件在桌面端里能命中;

独立跑 CLI 时镜像名不同,会诚实回到 busy(要数字就关客户端再跑);

  • 有预算:每个 PID 只 OpenProcess 一次、命中即返、默认上限 2 万次尝试 / 1200ms,超了就报

scan-budget;同一库 60 秒内复用上次快照结果,失败也至少隔 5 秒再试;

  • 不新增依赖:复用宿主自带的 koffi(扫安装位置解析,可用 DSH_KOFFI_PATH 指定),

找不到就当能力不存在,不报错不阻断其他功能。

安装

# 作为 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 失败(被占用 / 无权限 / 找不到 / 参数非法)。

Windows

# 1) 先退出客户端(托盘 → 退出),确认没有残留进程
Get-Process | Where-Object { $_.ProcessName -match 'DeepSeek|dsh' }

# 2) 试跑再实删
dsh-cookie-cleaner --clean --dry-run
dsh-cookie-cleaner --clean

macOS

# 1) Cmd+Q 退出后确认
ps aux | grep -i '[D]eepSeek Harness'

# 2) 试跑再实删
dsh-cookie-cleaner --clean --dry-run
dsh-cookie-cleaner --clean

# 没装全局命令时:
node ~/.dsh/profiles/desktop/node_modules/dsh-cookie-cleaner/src/cli.js --clean

Linux

# 1) 关闭主窗口后确认
pgrep -af 'DeepSeek Harness|dsh-desktop'

# 2) 试跑再实删
dsh-cookie-cleaner --clean --dry-run
dsh-cookie-cleaner --clean

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

成功输出长这样

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.

安全设计

  • 独占写锁即闸门——BEGIN IMMEDIATE 拿不到就拒绝执行并给出对应档位的处置文案;
  • 失败归因不猜错误码:实测 node:sqlite 在 POSIX 权限不足时只报

unable to open database file(不给 EACCES),所以工具自己探文件——

不存在 / 读不了 / 属于别人 / 被占用,四档各说各话,不会一律让你「去关客户端」;

  • 写盘前先拷 .bak-<时间戳>,主库副本失败即整单放弃(全有或全无);

-wal/-shm/-journal sidecar 一并带走(POSIX 用 WAL,只拷主文件是个残副本),

但 sidecar 拷不上只记为跳过,不拦停清理;

  • 删除语句只由 host_key 白名单 + 名称前缀构成,两者都过字符校验,时间戳走 BigInt 绑定参数;
  • 表结构自检:库里没有 cookies 表或缺关键列,一律拒绝,绝不对未知库执行写语句。

Node ≥ 22.19(用到 node:sqlite;Electron 44 内置的 Node 24 亦可)。

Node 22 上会有一条 ExperimentalWarning: SQLite,可用 node --no-warnings 消掉。

语言

优先级:--lang > DSH_COOKIE_LANG / DSH_LANG > LC_ALL / LC_MESSAGES / LANG > 系统 locale > zh。

LANG=C.UTF-8 / POSIX 这类中性 locale 判为英文(Linux 上很常见,不该给你看中文)。

认不出的语言落 zh,不会因此报错。插件侧同一套字典,可用设置项 lang 钉住。

插件面

  • 命令 /cookie-cleaner [status|clean]:只读。输出当前统计 + 可直接复制执行的清理命令。
  • 命令 `/cookie-clea

…(truncated)

以上内容来自 npm 上的 README,我们只做格式化,不改内容。

版本

npm 上共发布:8,最后更新 2026-11-06

链接

GitHub · Homepage · npm

同类插件