dsh-plugin-dashboard
v0.1.9
Published
DSH third-party plugin version dashboard: a Web Settings tab listing installed plugins with current/latest versions (npm registry or git tags/HEAD) and one-click upgrade.
Maintainers
Readme
dsh-plugin-dashboard
DSH 插件管理面板,嵌入 dsh Web 设置:Settings → Plugins 新增「插件管理」tab,列出当前 profile 安装的第三方插件、各自已装版本与最新版本(npm registry 或 GitHub tags/HEAD),支持一键升级与卸载。
能力
- 版本清单:读当前 profile 的
package.json(dependencies +dsh.profile.bundles)、node_modules/*/package.json(已装版本)、pnpm-lock.yaml(github 安装解析到的 40 位 commit)。 - 最新版本:全部走 dsh 进程自带的 node 运行时(
fetch,零子进程)——npm 包查询 registry 的/<pkg>/latest(dist-taglatest,尊重npm_config_registry);github 安装(github:user/repo)查 GitHub REST API/tags+/commits/HEAD,取最高 semver tag(无 tag 用 HEAD);支持GITHUB_TOKEN环境变量提额;远端 4xx/不可达 → 该条目降级为「未知」并显示原因,不影响其它条目。 - 升级:preview 先展示 当前→目标 / 新 specifier / 可复制命令;应用时备份
package.json(.dshbak-*)、改写 specifier(npm 保 range 风格^/~;git 包 pin 到#<tag>或#<commit>)、经ctx.subprocess跑 dsh 原生命令dsh plugin --profile <name> add <pkg>@<版本>(bounded collect 输出),失败自动回滚。 - 全部更新:头部「全部更新」按钮先列出所有可升级插件(当前 → 目标)与跳过原因,确认后按顺序逐个执行
dsh plugin add;单个失败不回滚已完成的更新,结果逐条回报,完成后重启 dsh 生效。 - 禁用/启用:按 loader 树里该插件贡献的行(
options.name归属、带文件 id)向 profile 的cordis.patch.yml追加disabled: true的 id-targeted 补丁(patchReload: live的 profile 即时热生效,startup重启后生效)——不动dsh.profile.bundles/dependencies,包保持安装、dsh pluginreconcile 不会复读它;启用则整块移除(写入前备份.dshbak-*)。core 包拒绝禁用。 - 卸载:从
dependencies(ctx.subprocess跑dsh plugin --profile <name> remove <pkg>)与dsh.profile.bundles中一并移除;core 包(@deepseek-ai/*、@deepseek-harness-tui/*)拒绝卸载;未知包报错;同样带备份与失败回滚。 - stale 与并发:升级前对当前文件重新计算,counts 与 staged 不一致拒绝;升级/卸载串行执行。
- 安全护栏:只操作本 profile 的 package.json;core 卸载被硬拒绝;
pnpm install失败恢复原文件。
安装
作为 profile bundle 挂载。dsh plugin add 只是在 profile 目录跑 pnpm——运行中直接执行即可,无需先停止 dsh;装完重启 dsh 生效。
cd ~/.dsh/profiles/<你的 profile> # 例如 web
dsh plugin --profile <你的 profile> add dsh-plugin-dashboard从 npm 安装,lib/ 已随包发布,装完即可用,无需本地构建。dsh plugin add 会自动把包名加进 profile 的 dsh.profile.bundles;手动编辑时形如:
{
"dsh": {
"profile": {
"bundles": ["@deepseek-ai/dsh-base", "@deepseek-ai/dsh-web-app", "dsh-browser-tool", "dsh-plugin-dashboard"]
}
}
}重启 dsh,Web 设置 → Plugins 出现「插件管理」tab。验证:
dsh --profile <你的 profile> --dump-config | grep dsh-plugin-dashboard工作原理
- node 面(
exports "."):cordis 插件,注入 dsh 原生的webServer+subprocess服务——ctx.webServer.register挂prefix路由/plugins/dsh-plugin-dashboard/api(/list、/upgrade、/upgrade-all、/uninstall),零裸child_process:命令执行全部经ctx.subprocess.spawn(树级终止、bounded collect),版本查询用 node 运行时自带fetch(dsh 的 node,无额外进程)。dsh 进程的 cwd 就是 profile 目录,所有读写都针对它。 - 浏览器面(
exports "./client"):esbuild 打包成window.__ModuleLoader__.load({ id, factory })lazy-CJS factory(脚本scripts/build-client.mjs)。ModuleLoader 契约有三个硬约束:factory 只接收require且必须return module.exports(<script>环境无 module/exports,需在 factory 体内自声明var module = { exports: {} }; var exports = module.exports;);entry 导出需treeShaking: false防止export const inject被内联删除;模块必须真实export const inject(声明服务注入,运行时经此拿ctx.slots)。组件用React.createElement手写(零 JSX);react及@deepseek-ai/*全部 external,从平台模块表解析;dsh.client.inject元数据同时提供给 shell 的注入装配。 - client→host 通信:浏览器直接
fetch同源/plugins/dsh-plugin-dashboard/api/*——走ctx.webServer路由,不依赖 typert Remote 装配(那条路需要进 dsh 主仓库api/remotes静态登记)。
配置(均可选,环境变量优先)
| 环境变量 | 说明 |
| --- | --- |
| DSH_PLUGIN_DASHBOARD_PROFILE_DIR | 覆盖 profile 目录(默认 process.cwd(),即 dsh 运行的 profile) |
| DSH_PROFILES_ROOT | 仅供测试/独立调试时指定 profiles 根 |
行为细节与限制
- 卸载语义:
dependencies条目走pnpm remove(改 deps + lockfile + node_modules),随后从dsh.profile.bundles剔除同名挂载;仅挂载而未声明依赖的条目(如某些 host 包)只剔除 bundles。卸载/升级完成后都需要重启 dsh 生效,UI 会提示。 - 升级不会静默覆盖:staged preview 计数与 apply 时对 live 文件重算结果不一致 → 报 stale 让用户重新 preview;只是行号或无关内容变化但 counts 未变 → 跟随新内容应用(与 omp ast_edit 同一语义)。
- npm 最新版本以 dist-tag
latest为基准;本地npm配的 registry(如镜像)即查询源。 - git 包判定:以 lock 里解析的 commit 与远端 tag/HEAD commit 比较;安装当时无 tag 的仓库升级会 pin 到新 HEAD。
- core 保护:
@deepseek-ai/*、@deepseek-harness-tui/*不可卸载(防止拆掉 dsh-base 这类地基);tab 上也不显示卸载按钮。 - 运行中应用:升级/卸载在 dsh 运行中直接执行(改动 profile 的 package.json 与 node_modules),完成后需重启 dsh 加载新版本,UI 会提示。无需先停止 dsh——从 dsh 自己的 UI 里先停止反而会中断待执行的应用流程。- 禁用与卸载交互:卸载一个被禁用的插件会顺带清理其禁用块(避免下次启动对已不存在行的警告);禁用某插件后升级它没问题——若新版 patch 改了行 id,旧禁用块会在启动时对缺失行警告一次,重新禁用即可消除。
开发
npm run build # tsc(node 面)→ lib/ + esbuild(浏览器面)→ lib/client.cjs
npm run check # tsc --noEmit
bun test # 32 项:semver/profile/upgrade + host 插件路由全链路(fake webServer + pnpm shim)
npm run smoke # fixture 路由全链路 + client.cjs 形态 + 真实 web profile(容错)依赖安装注意:@deepseek-ai/* 类型包均声明为 devDependencies(peer 冲突时统一对齐到同一 rc 版本,见 package.json);esbuild 的 postinstall 被 npm 11 拦截时手动 node node_modules/esbuild/install.js。
与其它 dsh 设置项的边界
dsh 自带「Plugin list」(ui-settings-plugin-inventory,Loader 树只读清单)与「Plugin configuration」(ui-settings-plugins,settings namespace 配置编辑器)两个 tab;本面板补的是第三方包维度:版本对比、升级、卸载——三者互补,本包不改动它们。
许可
MIT © 画野 (mtaech)
