不重启也能清掉卡顿的 DeepSeek Harness 工作台:就地重建界面、替换插件代码,运行中的回合、排队消息和未发送草稿都保留。
44.9/100
综合分
30
GitHub 星标
—
npm 周下载
—/5
用户评分
数据截至 2026/10/31 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。
安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add dsh-unlagnpm 源 · dsh-unlag 的发布者账号已校验与本仓库一致
状态速览
判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态信任档位:已验证
是什么
dsh 原生插件 · tool
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
活跃:最近一次提交在 1 天前
档位由哪些信号合成
本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。
社区实装还没有人打卡 · 装过的第一个就是你
安装兼容性检查✓ 自动检查通过展开查看检查明细 ↓
以下结论由程序自动检查 npm 包、engines 声明与入口文件得出,未做人工实机验证——能装不等于用着没问题。
✓npm 包dsh-unlag @ 1.14.9
✓Node 引擎未声明 engines.node
✓dsh CLI 依赖未声明 dsh 版本约束
✓入口文件main/exports/bin 已声明
验证方式:npm registry 存在性 + package.json 静态校验 · 最后检查 2026/10/29 08:40:26
安全扫描自动 · 静态分析源码v2.7.0🔵 扫描:含敏感能力尚无人工评估展开查看扫描说明与证据 ↓
安全扫描自动 · 静态分析源码
v2.7.0静态扫描发现插件具备触达本地系统的能力:执行外部命令、读写/删除本地文件、读取剪贴板或密钥类环境变量(至少其一)。这是能力清单,不是危险判定——具体能力项与证据见下方,安装前请自行判断是否需要。
读写/删除本地文件发起外部网络请求
查看扫描证据(共 25 处,展示前 17 条)
- 读取本地文件index.js:69
const raw = readFileSync(new URL('./package.json', import.meta.url), 'utf8') - 读取本地文件index.js:82
return statSync(new URL('./index.js', import.meta.url)).mtime.toISOString() - 写入本地文件index.js:356
mkdirSync(target.slice(0, cut), { recursive: true }) - 写入本地文件index.js:402
renameSync(target, `${target}.1`) - 读取本地文件index.js:450
names = readdirSync(dir, { withFileTypes: true }) - 读取本地文件index.js:465
const stat = statSync(path) - 读取本地文件index.js:486
return readFileSync(fd, 'utf8') - 读取本地文件index.js:511
if (existsSync(path)) roots.push(path) - 写入本地文件index.js:3702
mkdirSync(join(stateHome(), '.dsh'), { recursive: true }) - 写入本地文件index.js:3705
writeFileSync(temporary, body) - 写入本地文件index.js:3706
renameSync(temporary, SWITCH_PATH) - 发起网络请求client.js:234
const response = await withTimeout(fetch(`${HOST_BASE}/state`, { cache: 'no-store', credentials: 'same-origin' })); - 发起网络请求client.js:252
const response = await withTimeout(fetch(`${HOST_BASE}/state`, { cache: 'no-store', credentials: 'same-origin' })); - 发起网络请求client.js:282
void fetch(`${HOST_BASE}/boot`, { - 发起网络请求client.js:377
fetch(`${HOST_BASE}/report?${query}`, { - 发起网络请求client.js:400
const response = await withTimeout(fetch(`${HOST_BASE}/reload?requestId=${encodeURIComponent(requestId)}`, { - 发起网络请求client.js:467
response = await withTimeout(fetch(`${HOST_BASE}/verify`, {
扫描于 2026/10/31(0 天前) · 范围 入口闭包 + 全包扫描 · 来源 npm 发布包
静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。
给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个
最近更新
在 GitHub 查看全部 →v1.14.142026-10-29
开关保存按点击排队发出,晚到的旧回答不回写;保存进行中按下刷新会先等这份保存(≤4 秒)落地再读开关,这一按看到的就是屏幕上那个开关。证据:node scripts/test.mjs 66 个文件 1453 项全绿;ui-copy-lint / zh-lint / style-lint 0 error。
v1.14.132026-10-29
· 1.14.13
· 一次按压只认一个基线(上一次评审的第一条):一次按压在排队前先记住「开始那一刻在跑的插件」,之后的重试、补问只改变问什么,不改变判什么;最终结论永远和这份基线比。于是「这一按停掉的插件」一定记为 newlyFailed,「这一按之前就停着的」只进 carriedEntries/preexistingInactive——同一次按压不会因为多问了一次就把别人的旧账算成自己的失败,也不会把真实损失说成没事。
· 取消落在应用之前就真的不动(第二条):页面的路由在响应发出前连接断开、助手的调用被停,都能穿过队列到达「问应用之前」这一道;被停的一次直接中止,不重试、不写失败、不写条目记忆,答 cancelled/rebuild: unknown,/state.operation 记 cancelled,日志写 a press was stopped before it reached the app; nothing was replaced。已经问过应用的更新不受等待被停影响,仍按真实结果记账;已经发出「还在应用」的响应不算断开,页面在等就照常跑完。
· 同一个名字只答它那一次更新(第三条):页面给一次按压起的名字在更新结束时写进那份记录(中途加入的也算它这一次),两次更新之后重问最早的名字,答的仍是它那一次、带那次自己的 operationId;重问任何旧名字都不会再触发新的更新。
· 证据:新增 test/press-final.test.mjs(24 项)、test/press-retry-baseline.test.mjs(11 项)、test/press-cancel.test.mjs(14 项)、test/press-old-id.test.mjs(10 项);node scripts/test.mjs 66 个文件、1447 项全绿(EXIT 0);node --check index.js client.js ok;ui-copy-lint 0 error(8 warn 与基线同)、zh-lint 0 error、style-lint 通过。本版不改按钮外观、不新增开关或刷新模式,rebuild 在仍有停掉条目时依旧拒绝报 safe。
v1.14.122026-10-29
· 1.14.12
· 第一次按就成功(#3 现场,本机日志 2026-10-29T06:24:49Z):上一版的「再问一次」只在「这一按停掉的条目」被读到时才触发。本机实测的那次拒绝里,停掉的是这一按之前就已经停着的插件(adb (dsh-mobile-use),它自己导入时抛 JsonSchemaError: unsupported schema 里的 type 数组),不是这一按降下来的,于是条目清单里找不到它、重问没有发生,这一按答「插件更新没完成」;同一个人 5 秒后再按一次就答 done。现在改成:只要应用拒绝了这批条目(不是排队冲突那类),就先等一小会儿再问一次,第二次按现在的运行状态判。日志写 the update was rejected; asked once more on the set that runs now;如果第二次问的时候确实读到这一按停掉的条目,仍写原来的 this update left an entry stopped (…); asked once more without it,并按「去掉它」的清单问。
· 等一小会儿再读条目状态:Loader 在拒绝之后过一会儿才写下新的条目状态,紧挨着异常读到的可能还是「运行中」,按那份清单重问会重演同一个失败。等待时间默认 250 ms,DSH_UNLAG_RETRY_MS 可改(上限 2000 ms),定时器 unref,不拖住宿主退出。
· 仍然只重问一次:retriedOnce 不变,第二问还失败就走原来的失败路径并照常写日志,永不进入循环。
· 测试:新增 test/press-retry-stale.test.mjs(4 项:拒绝但不是这一按造成的 → 答 done、该插件记在 carriedEntries、应用恰好被问两次、日志写明第二次)与 test/press-retry-fails.test.mjs(3 项:一直拒绝 → 答 failed、只问两次、日志可见);test/agent-tool.test.mjs、test/button.test.mjs 里钉住「应用被问了几次」的断言按新合同改成两次。
· 证据:node scripts/test.mjs 63 个文件、1410 项全绿;node --check 两入口 ok;zh-lint、ui-copy-lint 0 error,style-lint 通过。本版不改按钮外观、不新增开关或刷新模式。
数据来自仓库的 GitHub Release,可能与插件实际版本不一致。
README
由 DeepSeek 最新模型翻译生成dsh-unlag(解除卡顿)
DSH 桌面端自己的刷新按钮。
开发插件要重启,可手里还有任务在跑?刷新一下!
开久了页面越来越卡?刷新一下!
一个按钮解决桌面端这些烦恼,正在进行的会话不受影响。窗口右上角点一下:插件代码原地换掉,卡顿的界面重建一次,宿主自己的轮次、子代理、终端进程继续跑完。
只在桌面 App 的窗口里出现:浏览器直接打开同一个地址时没有这个按钮,本插件不做网页版。
两个日常场景
| 情况 | 按一下 |
| 改了界面类插件,手里还有任务在跑 | 插件当场换掉,宿主自己的任务继续跑完 |
| 界面越用越卡 | 直接恢复流畅,会话、队列、草稿都还在 |
以前两种都得关掉 App 再来。现在不用,也不用挑空闲时间——马上换,不等。
边界说清楚:宿主自己的轮次、子代理、终端进程不受影响;被换掉的那个插件如果自己负责某个正在跑的任务(例如 agent-loop),这个任务会随实例结束。主脚本以外的资源不能配对时,会保留当前页面并说明原因,不会硬重建。
装
dsh plugin install dsh-unlag
安装后由 DSH 完成首次加载,之后的更新都走按钮。
用
点右上角那个按钮。
展开完整文档(README 剩余 1 节)
dsh-unlag(解除卡顿)
DSH 桌面端自己的刷新按钮。
开发插件要重启,可手里还有任务在跑?刷新一下!
开久了页面越来越卡?刷新一下!
一个按钮解决桌面端这些烦恼,正在进行的会话不受影响。窗口右上角点一下:插件代码原地换掉,卡顿的界面重建一次,宿主自己的轮次、子代理、终端进程继续跑完。
只在桌面 App 的窗口里出现:浏览器直接打开同一个地址时没有这个按钮,本插件不做网页版。
两个日常场景
| 情况 | 按一下 |
| 改了界面类插件,手里还有任务在跑 | 插件当场换掉,宿主自己的任务继续跑完 |
| 界面越用越卡 | 直接恢复流畅,会话、队列、草稿都还在 |
以前两种都得关掉 App 再来。现在不用,也不用挑空闲时间——马上换,不等。
边界说清楚:宿主自己的轮次、子代理、终端进程不受影响;被换掉的那个插件如果自己负责某个正在跑的任务(例如 agent-loop),这个任务会随实例结束。主脚本以外的资源不能配对时,会保留当前页面并说明原因,不会硬重建。
装
dsh plugin install dsh-unlag
安装后由 DSH 完成首次加载,之后的更新都走按钮。
用
点右上角那个按钮。右键菜单有三行,另有一项在配置里:
- 按下刷新时换掉插件代码(默认开)
- 按下刷新时重建界面(默认开)
- Agent 可以自己刷新(默认关)
前两行都开=先换代码再重建;只开一个=另一项完全不动;都不开=点击无反应。最后一行只决定谁能按,不改变按下去做什么。
「改完文件自动刷新」不是菜单行,是配置项(默认关),开了也不用按按钮。
页面自己缺插件时会主动说一句:应用在两次启动之间换过插件代码,新开的页面按启动时那份冻结清单去要脚本会答 404,那个插件就没加载,屏幕上原本什么都不会说。现在页面启动后读一次开机时记下的应答,只有应用明确答「这个地址没了」时,才在按钮旁说「缺插件,重启应用后恢复」——不用按任何东西。读不到、读不全或清单太长时保持安静。这句话不是某次刷新的结论,所以不会到点消失,按下一次后由新的结果接替。
插件换过之后,页面按旧版本号要的懒加载分块,只要这个文件还在就按它现在的版本答:文件还在、只是编号变了,不该算缺插件,也不该让人只剩重启。文件真没了才拒绝并点名是哪个文件。
谁能让它刷新
默认只有人:自动刷新关着,Agent 入口也关着,本插件不装任何文件监视,本插件自己永远不会去换代码。
右键按钮里打开「Agent 可以自己刷新」后,会话里的 Agent 可以自己按这个按钮(工具名 unlag_refresh),复用按钮那套判定与拦截,但只换宿主侧的插件代码:页面不会重开,也不会替你按下按钮;内容没保存、插件没恢复时照样停住并说明原因。关着时 Agent 调它会被告知先打开开关,不会偷偷刷新。
这不等于 App 自己也不会换:宿主自带的插件热更新有自己的开关和监视,装了开发插件、开着那边的自动应用时,改文件仍可能由宿主应用;本插件开关关掉只是本插件不发起。
不会丢什么
- 正在跑的轮次、子代理、终端进程:宿主进程不重启,会话记录和排队消息都留着。被换掉的插件实例会先关掉:如果某个正在跑的任务由那个插件自己负责(例如 agent-loop),这个任务会随实例结束;宿主自己的轮次不受影响。
- 界面重建会重新进入同一个地址:屏幕上正在显示的内容重新载入一次,会话记录还在。
- 排队消息:排在宿主里,重建文档不影响它。
- 输入草稿:重建前先提交焦点里的内容,文字草稿由 App 自己存下来,回到同一会话还在。
- 附件:草稿里的附件只存在当前页面里,文字草稿会存下来,附件不会。草稿里确实还有没发出去的附件时,按钮会停住并说明先发出去;消息发出后留在记录里的图片不算草稿,不会挡住刷新。
- 有未保存改动、开着弹窗、或下个页面要用的模块读不全:拦下并提示,提示里写明卡在哪一项,宁可不刷。
- 原来就起不来的插件不挡换代码,但也算不算「可以重建」:启动以来就没跑过的插件只记日志;上一次更新打坏、还没恢复的必要插件,会在结果里点名,并且下一次按也不会被当成已修好。
- 四个开关读不到时不硬刷:提示稍后再试,日志记下是哪一步没读到,绝不谎称代码已是最新。
- 旧页面记着的启动清单分组变了(装过/卸过插件):按插件逐个补齐再交给新页面,不会因为清单 404 把 App 带走。
- 从不自己重启或退出 App。
管不到(它会拦下并说明,不会硬来):
- 改动替插件加原生能力、改服务声明或权限:这类改动不在一次点击的范围里。
- 独立进程和进程级的东西:宠物窗口自己的配置、DSH 自身升级、原生依赖变化。
- 万一新页面还是起不来:App 会进入错误恢复(退出,或请你停用第三方插件)。本插件不替你选,也不会自己重启或退出 App。
依据的官方约定
- 页面启动时,宿主把插件清单写成 window.__DSH_BOOT__;脚本地址形如 /plugins/??<包>/client.js&rev=<修订>,修订由文件的修改时间、变更时间、大小决定(docs/subsystems/client-modules.md)。
- 宿主对未知、被改过、过期的修订返回 404,不会拿别的字节顶上,也不会让单页应用的回退把 HTML 当脚本发出去(同上)。
- 插件代码重建、但入口没重启时,宿主用 rebuilt() 发布新修订,页面按新地址只换掉那一个插件(同上)。
- 页面只应用自己启动时那一版宿主的清单;宿主换了版本,页面要重新载入才能跟上(同上,Host release changes)。
本插件只做这些约定允许的事:换代码走宿主的插件重载入口,重建走一次页面载入。唯一的差异在下一节。
与官方约定的差异
官方的插件资源路由对未知修订返回 404。本插件对旧页面记着的旧修订返回当前内容:桌面版在窗口启动时固定了启动清单,页面按旧修订请求脚本是常态,返回 404 会让新页面起不来、App 直接退出。这是本插件的兼容措施,不是官方行为。右键按钮里的开关只决定按下去做什么(换插件代码/重建页面/自动刷新/允许 Agent 按),关掉开关不会停掉这套兼容措施。
同一原因下的第二种情况:启动清单里记着的插件在配置里已经被关掉或删掉了,官方路由对那一行只会 404。本插件改为返回一段空脚本,让这一行不再 404;那个插件因此不会被加载,页面是否能起来仍取决于其余启动行和官方启动流程。日志会写明哪个插件被留下,/dsh-unlag/verify 的结论里也带 leftOut 字段。
排错
- 日志:~/.dsh/unlag-reload.log,换代码/跳过/被拦各一行,含原因。
- 演练:npm run smoke 不按按钮,只按当前启动清单,把下一个文档要加载的字节在沙箱里跑一遍,看每个插件是否都注册(rehearsal.ok),并当场核对三件事:写死的旧版本号仍然拿得到现在的字节(shim.staleRev),按下前会做的那个判断此刻是否放行(pressPath),以及那个判断本身会不会误拒(verify.sound 应为 ok、verify.broken 应为 blocked、verify.refuses 与 verify.accepts 为 true)——它证明的是「启动清单里的每个插件都注册了、每个分块都取得到、按钮此刻真的可按、拦住的是坏清单」,不换任何代码;演练里的 Loader 只收集注册的 ID,不执行插件的 factory、import 与 apply,所以它不等于整机刷新已经安全。
- 同一支脚本还现场核对路由的守门规则(contract):读路由只认读,写路由缺 x-dsh-unlag 头或来自别的源一律 403,未知路径 404。它用的是和页面一样的请求,所以这条规则在运行中的 App 上是否还在,一眼可见。
- 状态:GET /dsh-unlag/state → {"version":"<当前版本>","code":"<index.js 写入时间>","plugins":true,"page":true,"shim":{...},"served":{"status":"served|missing|unknown","entries":<当前插件图行数>,"id":"dsh-unlag"}}。code 用来分清「版本号没刷」和「旧代码真的还在跑」;served 用来分清「按钮没出现」是插件图里没这一行(missing)、还是图还没就绪(unknown)。
- 重建后的日志带起页面代次:interface rebuilt; the page runs the plugins as served now (page <rev>),据此判断新文档加载的是新脚本还是旧脚本。
- 按钮不出现且 served 是 missing:先看 profile 的 package.json 里 dsh.profile.bundles 还列不列着 dsh-unlag。宿主装别的插件时会按 dependencies 重算这份有序清单,手装或软链进来的条目可能被一并丢掉,加回去、重启即可。装清单失败与插件本身无关,已提上游:<https://github.com/deepseek-ai/deepseek-harness/discussions/11383>。
- 装不上、报 ECONNREFUSED 或 UND_ERR_CONNECT_TIMEOUT:先看 ~/.npmrc 里的代理是否在跑,代理没起时换镜像直连也能装。
每类说法对应的测试与现场输出整理在 EVIDENCE.md,含还没证到的两件事。
与官方文档的对照
判定按下后能不能重建,依赖的是 Client Modules 的读接口和它自己公布的路由规则。逐条核对的是 App 内随包发布的文档 .research/asar-dsh/dsh-client-modules/README.zh.md(15968 B,sha256 前缀 33cee13e7b61a151)。
| 官方规则(该文档行) | 这里的做法 | 为什么 |
| 未知资源或 revision 返回 404(80) | 冻结的启动清单里的行,旧 revision 照样给现在的字节;表里已经没有的插件仍然 404 | 桌面壳从启动时读到的清单重启文档,任何一行 404 都会让壳以退出码 1 结束,正在跑的会话随之死掉。只在「这一行确实还在表里」时接管,别的 404 原样放行 |
| 启动图与批次 URL 是应用目录相对形式(80) | 校验时按同样形式(plugins/??…&rev=…)读,相对路径补前导 / 后再取 | 与文档一致,避免把文档相对形式当绝对路径 |
| 每个阶段在 URL 超过 3 KiB 前分区(80) | 一行超过 8 KiB 就拒检(blocked/list) | 官方既然在 3 KiB 前分区,真实启动行就短于 3 KiB(这台机器实测最长 2834 B),8 KiB 只挡伪造清单,不会误拒正常行 |
| revision 由 mtime/ctime/大小派生,不哈希内容(80、136) | 只用官方读接口拿到的 revision,不自己算版本;比对的是正文里注册的插件 id | 哈希会引入一套自己的代际,和官方的 404 规则打架 |
| bundle 内容变更只能通过 rebuilt() 进入图(78) | 不调用 rebuilt() | 调了会让运行中的页面就地换模块,草稿和正在跑的任务受影响;这里只换宿主侧代码,页面由人来按按钮重开 |
| 图更新在同一个 Loader 上串行执行(90) | 重建走宿主自己的插件重载,不自己改 Loader | 自己改会和官方协调逻辑冲突,这是不能碰的那层 |
改完后让运行中的 App 用上
不用重启 App,也不用重启页面:换掉 index.js 后让插件的记录重载一次即可。
1. 改版本号,并 touch index.js client.js。只改版本号是不够的:插件的装载按文件时间判断要不要重新读,时间没变就还是旧代码在跑,/state 里会看到版本号没变(或变了但 code 是旧的)。
2. 在插件列表里把本插件关掉再打开。这两步之后 ~/.dsh/unlag-reload.log 会出现一行新的 dsh-unlag <版本>。
3. 等约 20 秒,读 GET /dsh-unlag/state:version 是新版本、code 是刚才 index.js 的写入时间,才算真的换上了。
4. npm run smoke 对着运行中的 App 复核一遍(见下一节)。
5. 发布用 ./scripts/release.sh,它发完会回查 registry 是否真的列出版本。npm view 读的是 CDN 缓存,发布成功后的一两分钟里可能还显示上一版;npm view 与 registry 不一致时,以版本号文档(https://registry.npmjs.org/dsh-unlag/<版本>)是否 200 为准。
页面那一半(按钮点击后的重建)不在这一步里:那是按钮本人的事,只有人能按。
测试
npm test
对着正在运行的 App 走一遍真实判定(页面半、宿主半都是线上代码,用的是 App 现在渲染的启动清单;只回答「能不能刷」,绝不按按钮),并核对路由契约:读接口 200、写方法 405、不带页面头的按键路由 403:
npm run smoke
没有 App 在监听时打印 skip 并退出 0。预览分享卡片长什么样 ↓
分享 · DeepSeek Harness Hub
regrevia/dsh-unlag
不重启也能清掉卡顿的 DeepSeek Harness 工作台:就地重建界面、替换插件代码,运行中的回合、排队消息和未发送草稿都保留。
相关插件 · 工具 / 效率
破甲管控台kingcharleslzy-ai/dsh-purge
dsh-purge Community · DeepSeek Harness 社区维护版:宿主兼容、状态诊断、提示词管理、更新与本机备份回滚。基于小杨 / YuJunZhiXue 的 dsh-purge。
★ 3,801已汉化DeepSeek 客户端
74.5
网文长卷lingfengQAQ/webnovel-writer
基于 Claude Code 的长篇网文辅助创作系统,解决 AI 写作中的「遗忘」和「幻觉」问题,支持 200…
★ 7,636已汉化DSH
72.2
多智能体协作HKUDS/AutoSwarm
AutoSwarm: Unify Your Agents. Unify Your Context (Codex · Claude Code · DeepSeek Harness · Muse · Grok · WorkBuddy· nanobot · and more)
★ 2,082已汉化DSH
71.7
Vox 拼贴视频生成Alisa0808/vox-director
🎬 Vox Director拼贴动效导演
★ 2,129已汉化DSH
71.4
Agent 演化引擎Q00/ouroboros
智能体 OS:智能体自己变聪明,我们只守住底线:面试准入、分阶段评估、带预算的进化循环。MCP 服务器,14 种运行时:Claude Code、Codex CLI、Gemini CLI、OpenCode、Copilot、Kiro 等。
★ 6,292已汉化DSH
71.3
智能体运行框架路由HarnessRouter/harnessrouter
智能体运行框架的统一接口。
★ 3,800已汉化DSH
71.2