dsh-plugin-debugging
让 DSH agent 自检自修它身处的运行时
Let your DSH agent inspect and fix its own runtime
<!-- SLSA 徽章能不能挂,判据见 docs/PUBLISHING.md(对具体版本查 attestations 端点;别凭印象挂)。 -->
各版本改动 → Releases
简体中文 · English
你改了个东西,发现没生效?在 DSH 里,这通常有三种原因:
- 配置:每次修改都会被重新读取,改完就生效。前提是
profile里已挂载hmr;没有hmr时,一切改动退化为需要重启。 - 宿主代码:进程只在启动时加载一次,改了必须重启。
- 前端资源:浏览器按指纹换资源,改完需要热重载或刷新。
这个插件让 agent(智能体)自己判断你遇到的是哪一种,并给出下一步。
它做什么
装上之后,agent 多了一组工具和一份 skill(技能)文档,skill 按需加载,用斜杠命令调用。
工具
只读 —— 它们不改变宿主上的任何状态。
| 工具 | 参数 | 做什么 | Web | Desktop |
|---|---|---|---|---|
dsh_list_instances |
port |
列出本机正在运行的 DSH 宿主。只有未认证的 GET / 返回完全相同的 DSH 响应体时,才认定为 DSH。“探不到”和“不是 DSH”分开报告。 |
✓ | ✓ |
dsh_check_auth |
host、port |
区分“没在运行”和“没通过认证”。 | ✓ | ✓ |
dsh_diagnose_plugin_load |
package、port、dshHome |
查一个插件到底加载没有:bundle 归属、挂载形态、loader 树,并区分实测证据和推断证据。 |
✓ | ✓ |
dsh_check_effect_mode |
change:config / bundle-added / host-code / client-code,alreadyInDependencies、dshHome |
判断一个改动是实时生效、需要重启,还是热重载。在正在运行的 profile 上实际探测。 |
✓ | ✗ |
dsh_dump_config |
profile、dshHome |
展示一个 profile 最终解析成什么:组合树,以及解释它的诊断信息。 |
✓ | ✗ |
dsh_sign_cookie |
host、port、maxAgeDays、dshHome |
签一个浏览器会话 cookie,让脚本或命令行客户端访问你自己的 DSH 实例。 |
✓ | ✓ |
会改变状态 —— 前两个会替换代码,或者结束你正在排障的那个宿主。
| 工具 | 参数 | 做什么 | Web | Desktop |
|---|---|---|---|---|
dsh_hot_reload |
entryId / module / serverName 三者取其一,外加 dryRun |
把一个已挂载的 entry 替换成磁盘上的最新代码,不重启;失败自动回滚。 |
✓ | ✓ |
dsh_restart |
reason,delayMs、dryRun、force |
当改动确实需要重启时,重启当前宿主。默认关闭。 | ✓ | ✗ |
行的顺序就是使用顺序,所以两张表只按一条线分开:是否改变状态。最后一列是按载体的可用性,原因见平台支持。
三个容易踩的坑:
dsh_check_auth的401不代表会话过期。 不带cookie的请求永远得到401,所以auth probe的401只证明服务在运行且要求认证。要区分“会话还有效”和“authority不对”,只能用浏览器打开那个host:port。同一端口重启后旧cookie仍然有效;端口变了才会401。dsh_hot_reload可能留下泄漏。 框架未跟踪的资源(比如timer或socket)在swap后会静默泄漏。dsh_restart的行为见下文专节。
背后的 skill 文档
skill 文档在 skills/dsh-plugin-debugging/SKILL.md,里面写了安装方式、凭证获取、进程识别和隔离实例的完整推理。
工具只是加速器;如果工具输出和这份 skill 文档冲突,以 skill 文档为准。
安装
通过插件页安装:
进入 插件 页,点右上角 添加插件,填入 dsh-plugin-debugging,安装。
通过 npm 安装:
dsh plugin --profile web add dsh-plugin-debugging
从源码安装:
git clone https://github.com/dsh-plugin-lab/dsh-plugin-debugging.git
cd dsh-plugin-debugging
pnpm install && pnpm run build
dsh plugin --profile web add "$PWD"
注意事项:
- 不要跳过
pnpm install:如果用link:安装,依赖来自仓库本身;跳过这一步,插件会显示未运行,并报ERR_MODULE_NOT_FOUND。 - 重启生效:安装后需要重启
dsh --profile web。 link:与dsh.bundle是两件事:link:只决定改源码要不要重装;patch层是否应用,取决于包是否声明了dsh.bundle。
环境要求:
Node >= 20,以及 DSH 版本满足 package.json 中的范围。
维护规则:
profile 的 dependency 和 bundle list 由 dsh plugin add 管理,不要手改。不要在 $DSH_HOME 下创建包,也不要在 profile 目录里跑包管理器。
安全与边界
除 dsh_restart 外,这些工具不会重启进程、不会改写 profile、不会写入宿主数据。这条规则由测试保证:只要有写操作指向宿主数据路径(profiles / sessions / storages / logs / cache / attachments / backups / integrations / mcp / settings.yaml / .credentials.yaml …),或者把 DSH_HOME 本身当作目标,pnpm run test 就会失败。
唯一的写入例外是本插件自己的命名空间 $DSH_HOME/<包名>/:只允许 $DSH_HOME 下第一层目录名恰好等于包名,再往下的路径不受限制。
各自会碰什么:
- 只读,不发请求:
dsh_check_effect_mode、dsh_diagnose_plugin_load、dsh_dump_config。只读实例已有的文件,不产生凭据。 - 只读,会发 HTTP:
dsh_check_auth连接你指定的host:port;dsh_list_instances只探测 loopback 端口。两者都不发凭据。 - 只动运行中的模块树:
dsh_hot_reload,不杀进程。 - 读本地签名密钥:
dsh_sign_cookie,为你自己的实例签一个cookie。不发请求,cookie的值刻意不返回。 - 结束宿主:
dsh_restart,这里唯一不可逆的动作。
dsh_restart
dsh_restart 是唯一不可逆的动作:它会让宿主退出,也就是你正在排障的那个。它默认关闭,跑起来要连过三道门槛:
- 四道检查:是否陷入重启循环、是否有其他会话或作业在忙、
bundle表是否可读、启动命令能否确定。force只能覆盖“会话在忙”这一道,另外三道绕不过。 - 一道独立的审批检查:先读取审批策略,只有策略是
ask时才询问。never表示提示已关闭,在never下询问必然被拒,所以必须先读策略再决定是否询问。 - 写
marker前的独立检查:本插件自己的命名空间不在默认文件沙箱内,所以这次写入会显式使用danger-full-access。
三道的结果都会写进工具输出。 dryRun 会跑完所有门槛,但不写任何东西。
> [!IMPORTANT]
> 仅在 Windows 上,且宿主由 Web 进程拉起时可用。 桌面端里它在写任何东西之前就拒绝:从托盘退出再启动即可。
重启后会发生什么:
- 新宿主读取
marker,重新唤醒之前列出的每一个会话,并在每个会话里留一条说明。 - 这条说明是一份回顾,不是「请继续」:什么时候请求的重启、宿主停了多久、
marker最后怎么了。 - 你写的
reason只出现在你发起重启的那个会话里;其他会话拿到同样的回顾,但看不到它。
平台支持
按端口识别监听进程在设计上跨平台;目前只在 Windows 上做过真机实测。具体行为:
- 找不到可用命令时:报告“无法检查”,而不是“没有监听者”。这两个结论正好相反。
- 弱兜底命令:可能发现“有人在监听”,但说不出是哪个进程;这种情况记为“未识别”,而不是报告“没有监听者”。
其余能力与平台无关。dsh_restart 需要 Windows,并且宿主由 Web 进程拉起 —— 桌面端里宿主是 Electron 壳的子进程,插件侧没有能重启那个壳的通道。如果你能在 Linux 或 macOS 上试一次真机重启,欢迎到 #44 说一声 —— 那个缺口正是这个 issue 留着的原因。
配置
字段
这些字段用于配置 profile 组合中的本插件。其中 enableRestart 在 插件 页的本插件卡片上也有一个开关。
| 字段 | 默认 | 含义 |
|---|---|---|
enableRestart |
false |
是否允许运行 dsh_restart。立即生效,无需重启宿主。 |
dshHome |
$DSH_HOME 或 /.dsh |
实例存放 profiles、日志和凭据的目录。 |
profile |
$DSH_PROFILE 或默认 profile |
工具要检查哪个 profile。 |
port |
0 |
要探测的宿主端口;0 表示自动寻找监听端口。 |
timeoutMs |
60000 |
快速操作的超时预算:读文件、运行命令,或发一次 HTTP 探测。 |
schemaDumpTimeoutMs |
240000 |
运行 --dump-config-schema 的超时预算(实测 10.2–15.7 秒;高负载 32 秒)。 |
这两个预算怎么算出来的,以及为什么传输层必须先于宿主的工具时限超时 → docs/ARCHITECTURE.md §5.1。
调试另一个实例
什么时候需要它: 你正在调试一个实例,但证据在另一个上 —— 另一个 profile,或另一个 DSH_HOME。
哪些工具收 dshHome: dsh_dump_config、dsh_check_effect_mode、dsh_diagnose_plugin_load、dsh_sign_cookie。路径解析和它启动的 dsh 子进程都会使用你传入的 home;输出会写明实际读取的是哪一个(dshHomeSource: tool-argument)。参数传入的值绝不会被悄悄写成配置默认值。
哪些不收,为什么:
dsh_check_auth:它回答的是某个host:port的认证状态,本身已经有host/port。dsh_list_instances:它只做发现,能给出的只是一个host:port。dsh_hot_reload:它替换的是当前进程内存里的模块,无法跨到另一个实例。dsh_restart:它杀掉的就是自己所在的宿主,不存在可以指向的“另一个实例”。
一个坑: 发现类工具只能给出 host:port,无法推导出对应的 DSH_HOME;所以 dshHome 需要你自己传。相应地,dsh_diagnose_plugin_load 会把答案分成两部分:磁盘证据来自你传入的 home,loader 树部分只反映当前进程。
许可证
MIT。
贡献
问题与需求请走仓库 Issues。
维护者文档地图 → AGENTS.md。