用 /rst 一条命令重启 DSH:由进程外启动器关掉当前进程并拉起新的,重启完成后把回执写回你发起重启的那条会话。仅支持 Windows 10/11(依赖 tasklist/taskkill)。
安装
# npm 包(预构建)
dsh plugin --profile web add dsh-rst
# GitHub 源码(首次需按提示配置 allowBuilds 构建授权后重试)
dsh plugin --profile web add github:JingYu-er/dsh-rst
装任何插件都等于在你的机器上跑第三方代码,权限和你本人一样大——能读你的文件、用你的凭据、访问网络,工具审批管不到它。GitHub 来源的插件还会在安装时执行构建脚本——pnpm 默认拦截,所以安装可能停在 ERR_PNPM_GIT_DEP_PREPARE_NOT_ALLOWED 或 ERR_PNPM_IGNORED_BUILDS;dsh 会打印出需要添加的确切键名,把它加进该 profile 的 pnpm-workspace.yaml 的 allowBuilds 下,重跑一次即可装上。放行构建本身就是一次信任判断:请只安装可信来源,并尽量锁定 commit(github:owner/repo#sha)。
README
一条
/rst重启 DSH,并让重启后的 DSH 回到你这条会话里补一张回执。
English: README_EN.md · 安装 · 界面预览 · 快速开始 · 时序 · 安全边界 · 重启后的回执 · 日志与排障 · 已知限制
这是什么
dsh-rst 给 DSH 加一条给人用的斜杠命令 /rst:在会话里敲一下,DSH 自己重启,重启完成后在原来那条会话里追加一张回执卡片,告诉你「回来了,用时几秒,新 Host PID 多少」。
它不做的事:不接管进程管理、不替你切换模型或配置、不碰你的对话内容(除了那张回执卡片)。它是用户命令,不是模型工具——模型不能调用它。桌面版和 CLI 模式下都可用。
界面预览
在会话里敲 /rst 之后:

命令卡片显示重启器 PID、日志路径和预计耗时;几秒后同一条会话追加回执:「已重启完成:DSH 已经带着新配置回到这个会话(用时 X 秒,新 Host PID N)」。
为什么需要这个插件
手动重启 DSH 本身不难,难的是它一天要发生很多次:装完或更新插件要重启才生效,改一行插件代码要看效果,切了配置要确认是否吃上,一轮实验跑完想清空状态——每次都是「关掉应用 → 等它退干净 → 双击图标 → 重新打开刚才那个会话 → 回忆刚才在调什么」。动作不长,但重复几十遍之后,消耗的是注意力,不是那几秒。
/rst 把这一串压成一条命令:
- 装插件、改插件、切配置之后不用再手动走流程。 在会话里敲
/rst,几秒后同一个会话里出现一张回执:「已重启完成(用时 X 秒,新 Host PID N)」,新 Host 加载的就是你刚装/刚改的东西。调试插件时这个循环一天能跑几十次,这是它最值钱的地方。 - 结果回到你正在说话的地方。 回执落在原会话里,上下文不丢,不用靠记忆拼「我刚才在验证哪个改动」。
- 人在外面也能重启。 配合
@xmanrui/dsh-im等远程控制插件,手机上发一条/rst就能远程重启(走消息兜底通道);GUI 卡住、远程桌面没连上、你不在电脑前时最有用。
为什么必须有一个进程外的启动器(技术说明)
重启分三步:关掉当前 Host → 等它的 Web 端口释放 → 用同样的参数把同一个 exe 拉起来。这三步不能由 Host 自己完成:
- 命令卡片在 Host 里执行,Host 一退出就断在半路。 没有人能保证「等端口释放 → 重新拉起」被走完,所以必须有一个不在 DSH 进程树里的进程去做这件事。
- 不能靠
process.send或 preload 往回要状态。 Host 和 Electron 主进程是两个进程,要重启就只能在外部动手。 - 反向路径不存在。 没有「重启完成」的通知通道——回执只能由重启后的新 Host 自己发。
于是职责被拆成三块:插件只负责「收命令、写交接文件、发回执」,重启交给一个 detached 的纯 Node 启动器(relaunch.cjs),回执靠重启后的新 Host 读 pending.json 补发。
安装
从 npm 安装(推荐)
dsh plugin --profile desktop add dsh-rst
从 GitHub 直装
dsh plugin --profile desktop add github:JingYu-er/dsh-rst#main
装完重启一次 DSH(让 bundle 层生效)。是否就绪这样确认:
/rst --dry-run
它会打印重启计划(父进程 / 宿主 PID、要拉起的 exe、Web 端口、日志路径)而不动任何进程。
本地开发可以挂 link:
dsh plugin --profile desktop add link:D:\path\to\dsh-rst
改完代码不用手动重启——下次 /rst 拉起的 Host 加载的就是新代码(插件是自举的)。
快速开始
| 用法 | 行为 |
|---|---|
/rst |
重启 DSH,并在回复里给出启动器 PID 与日志路径 |
/rst --dry-run |
只打印重启计划,不杀、不拉 |
时序
你:/rst
│
├─ 插件(Host 进程)立刻回一张命令卡片「正在重启」
│ └─ 写 %LOCALAPPDATA%\dsh-rst\pending.json
│ (sessionId / startedAt / shellPid / hostPid)
│
├─ 用 process.execPath + ELECTRON_RUN_AS_NODE=1 spawn relaunch.cjs(detached)
│ └─ 启动器:等 2 s → 安全闸校验 → 优雅关 Host(5 s 宽限)→ 等宿主退出
│ → 等 Web 端口与 bili 引擎端口释放(最多 30 s)→ 拉起同一个 exe → 写 restart-<ts>.log
│
└─ 新 Host 起来,DSH 恢复原会话
└─ 插件轮询 sessions.get(sessionId)(每 500 ms,最多 180 s)
└─ 会话变成 live → 追加回执(command/run + command/done)
→ 删除 pending.json
安全边界
重启意味着要杀进程,所以边界写得比较死:
- 安全闸:杀之前
tasklist一次,确认目标 PID 的映像名与计划里记录的 exe 映像名一致(大小写不敏感)。名字对不上就 abort——只写日志,一个进程都不杀。 - 只杀 PID,不带
/T:不按名字群杀,也不顺手带走子进程(Vite、构建工具、你的终端都不在重启范围里)。 - 每一步都有账:start / gate / wait / kill / spawn / abort 全写进
restart-<ts>.log;abort 时命令结果里会如实写「已中止:shell 不是 …」。 - 不做假成功:拉不起来就是 failed 并给出日志路径,不静默、不假装。
--dry-run零副作用:只打印计划,不碰进程、不写 pending.json。
重启后的回执
回执是跨重启的一次交接:
/rst触发时写pending.json(会话 id、启动时间、各 PID)。- 新 Host 里插件在
apply完成后轮询sessions.get(sessionId),每 500 ms 一次,最多 180 s。 - 会话恢复成 live 的那一轮成功,就往原会话追加两条事件:
command/run:命令卡片(namerst,source为 user)command/done:kindsuccess,文本「已重启完成:DSH 已经带着新配置回到这个会话(用时 X 秒,新 Host PID N)。」
- 写成功后删除
pending.json;超时就只记日志。
只写命令卡片,不写 assistant / message,不插合成回合。 这是踩过坑的结论:早期版本为了「让回复出现在对话里」,往会话日志里缝 assistant 事件、往当前 turn 里塞一条消息,结果会话上下文当场解析失败(turns 乱、parseFail 非 0、帧被丢弃)。会话日志是 DSH 的持久化格式,能被它自己解析是硬约束;命令卡片是官方支持的写入面,回执就走这条。
回执超时不等于重启失败:如果 180 s 内你一直没打开那条会话,pending 会留着,下次启动再补一次(日志里如实记 timeout)。
状态文件与日志
全部在 %LOCALAPPDATA%\dsh-rst\:
| 文件 | 内容 |
|---|---|
loaded.log |
插件被 Host 加载(pid、electron 版本、commands 服务是否可用) |
invocations.log |
每次触发记录(命令或消息、会话、上下文) |
host-trace.log |
Host 侧痕迹;用来区分「命令没进来」还是「启动器没起来」 |
announce.log |
回执轮询明细:start / attempt / appended / timeout |
pending.json |
待补发的回执(拿到才算完,成功即删) |
restart-<ts>.log |
单次重启的启动器逐步日志 |
实现细节
| 项 | 桌面模式 | CLI 模式 |
|---|---|---|
| 判定 | process.versions.electron 存在且 process.send 是函数 |
其余情况 |
| 关掉谁 | taskkill /PID <Electron 主进程>(先优雅,5 s 没走再强制) |
由启动器 process.exit(0) |
| 拉起谁 | 同一个 exe,环境里去掉 ELECTRON_RUN_AS_NODE |
同一个 node + 同样的 argv |
| 等端口 | 从 DSH_WEB_URL 解析 Web 端口 + bili 引擎端口,最多等 30 s |
只等 bili 引擎端口 |
| 失败形态 | 命令卡片显示启动器 PID 与日志路径 | 同左 |
启动器参数:--shell --host --exe --workdir --log --delay --grace --enginewait [--port] [--waitports] [--exeargs],默认 delay=2000ms(给命令卡片落日志的时间)、grace=5000ms(优雅关机的宽限)、enginewait=30000ms(等 bili 引擎等被占端口释放的上限)。--waitports 是要等的端口列表(逗号分隔),会与 --port 合并去重。拉起失败会重试,最多 3 次,每次拉起后 1 s 检查是否还活着。
环境变量:DSH_WEB_URL(解析 Web 端口)、LOCALAPPDATA(状态目录,缺省回退 TEMP / 用户目录)。
消息兜底:远程控制插件(如 @xmanrui/dsh-im)把消息送进来时,/rst 会以普通消息出现;插件全局监听 session/event,命中 ^/rst(\s|$) 且 5 s 防抖后走同一套流程。
兼容性与已知限制
- 进程枚举与关停依赖
tasklist/taskkill:目前只支持 Windows 10/11。 - 只覆盖桌面版与 CLI 模式;TUI 模式没有 Web 端口,拉起后不再等端口。
- 回执需要 180 s 内那条会话被恢复成 live;超时只写日志,会话里不会有任何提示。
- 重启会打断正在跑的回合,长回合里别
/rst。 - 命令名固定
rst,与其他插件撞名时先改名再装。 pending.json超时后不自动清理:下次启动会再试,如果那个会话早已不存在,日志里会多几行 timeout(无害)。
更新日志
- 0.3.0:
/rst现在等 bili 引擎端口释放后再拉起(最多 30 s),避免新实例先起、旧引擎还在 flush 的竞态;优雅关机宽限 2 s → 5 s;--exeargs终于真的传给新实例。 - 更早版本见 git 历史。
排错
- 输入
/rst没有补全 → 插件没加载。看loaded.log有没有新行,profile 的package.json里是否同时有 link 依赖和bundles列表项。 - 命令报「找不到重启器脚本」 → 包不完整:发布时
files里漏了relaunch.cjs。 - 应用没回来 → 看
restart-<ts>.log停在哪一步。abort: shell … is not …说明安全闸拦下了(父进程不是 DSH)。 - 回执没来 →
announce.log只有 start/attempt:会话没恢复成 live。把那条会话打开,最多等 180 s;或下次启动时补发。 - 会话日志报 dropped frames / parseFail → 不该再出现:回执只写命令卡片,不缝 assistant 消息。
目录结构
dsh-rst/
├── index.js 插件入口:name / apply / 命令注册 / 回执交接
├── relaunch.cjs 启动器(纯 Node,被 detached 拉起,脱离 DSH 进程树)
├── relaunch.ps1 早期 PowerShell 版启动器(已弃用,保留作参考)
├── cordis.patch.yml bundle 层声明:把插件挂进 loader 树
├── package.json
├── README.md / README_EN.md
└── LICENSE
开发
index.js 是唯一的宿主侧入口;relaunch.cjs 不依赖 DSH 运行时,只用 Node 标准库,方便单独调试。
改完直接 /rst 验证即可——被拉起的新 Host 会加载工作区里的新代码。动手前建议先 /rst --dry-run 看一眼计划,确认你准备杀的是对的进程。
许可证
链接
同类插件
DayuanJiang/next-ai-draw-io#dsh-plugin★ 36802
dsh 的 draw.io 绘图插件:通过 next-ai-drawio MCP 服务器作图,点回复里的链接在右侧栏打开实时预览,可以手动修改图,AI 的每次修改都是可以恢复的版本。需 Node.js 18+,首次使用由 npx 下载 MCP 服务器。
Tencent/WeKnora#dsh-weknora★ 36302
把 WeKnora 知识库接入 dsh 的四个只读工具:列出知识库、混合检索原文片段、按顺序还原单篇文档,以及直接取用 WeKnora 自己带引用的 RAG 或 ReAct agent 回答(含可续聊的 session id)。
superdesigndev/treg★ 7042
给 Agent 的工具目录:按「要做的事」检索约 2,600 个外部接口(SEO 与 SERP、外链、社交、人物与公司信息补全、广告库、抓取),查看参数与单次调用价格后直接调用,凭据由服务端注入。附带技能,MCP 行在未设置 TREG_TOKEN 前保持禁用。
T-Auto/dsh-ops★ 5074
为 Windows 的 DSH 提供 bash、PowerShell 7 及 Rust 高性能工具,减少 token 消耗。
sixtysevenlf/dsh-blender-plugin★ 1575
让 DSH agent 通过直连 TCP 通道驱动本地 Blender,提供 15 个工具:视口帧、自定义视角渲染、Python 执行、无头与作业卸载、事务回滚,以及 34 个 family / 228 个 op 的规划层。
TencentCloudBase/CloudBase-AI-Toolkit#dsh-plugin★ 1155
把腾讯云 CloudBase 后端接入 DeepSeek Harness——在对话里搭好并部署全栈应用,查询结果渲染为表格卡片(分页、排序、导出 CSV),部署后可预览真实域名,并提供 CloudBase MCP 工具集(`mcp__cloudbase__*`),登录走 device-code 流程。
社区评论
评论公开保存在 GitHub Discussions。加载评论会连接 GitHub 和 Giscus;发表内容需要 GitHub 账号。