dsh-plugin-showcase
v0.2.0
Published
DeepSeek Harness starter companion: a health-check tool, a destructive-command gate, a slash command, a settings card and a right-sidebar guide — plus a self-hosted market index.
Maintainers
Readme
dsh-plugin-showcase
一个 DeepSeek Harness(DSH) 的新人首装搭档:用一句话说明它所在的这台 DSH 主机 是什么状况,同时把八个插件能力面一次性用满,因此整块接口面可以在一个小包里读完。
版本 0.2.0。v1 的能力面一个都没退化(showcase_inspect、/showcase on|off、
拦截门、三处 slot、locale、icon、patch 全部保持),v2 增加了体检、两个命令分支、
面板里的三步引导,以及随包分发的自托管市场索引。
| 能力面 | 位置(v0.2.0) |
| --- | --- |
| 工具 showcase_inspect | lib/index.js:600,注册在 :638 |
| 工具 showcase_doctor | lib/index.js:619,注册在 :639 |
| 钩子 tools/pre-execute | lib/index.js:641(拦截门),模式表 :21–:38 |
| 斜杠命令 /showcase | lib/index.js:652 |
| 设置卡片 | lib/client.js:531(settings.section,id showcase) |
| 右侧栏面板 | 面板体 lib/client.js:551,tab 类型 :539 |
| 国际化 | lib/client.js:13(19 键)、locale/en.json、locale/zh.json |
| 市场索引 | market/index.json(在 files 白名单里随包发布) |
| 测试 | tests/host.test.mjs、tests/client.test.mjs |
行号对应 v0.2.0。全程零构建:只有原生 ESM JavaScript,没有第三方运行时依赖,也没有
任何 @deepseek-ai import。
安装与卸载
本机使用的 profile:C:\Users\baba\.dsh\profiles\web。
方式一:从市场安装(正常路径)
- 把 0.2.0 发布到 npm(流程见
PUBLISH.md),包内索引就能在https://cdn.jsdelivr.net/npm/dsh-plugin-showcase@latest/market/index.json取到。 - 打开 DSH → 设置 → 市场/发现页,把这个 URL 添加为索引源。宿主服务
pluginMarket维护这份indexes列表,它的初始值是空数组:发现页不搜索 npm,所以没配索引之前什么都不会出现。 - 搜索
dsh-plugin-showcase→ 安装。包会装进 profile,并把它在dsh.bundle里 对应的条目追加进dsh.profile.bundles,层随即生效。
索引随包分发,所以从 0.2.0 起才有:0.1.0 发布时包里没有 market/,它没有索引。
0.2.0 及以后的版本,上面那条 CDN 地址直接就能取到索引——不需要本机服务,也没有任何
进程要你养着。
不想等索引,也可以直接按 registry 名安装:
dsh plugin --profile web add dsh-plugin-showcase方式二:从 checkout 安装(官方命令)
dsh plugin --profile web add <本目录路径>本机 PATH 上没有全局 dsh,所以同一个命令改从检出调用:
node "C:\Users\baba\Desktop\deepseek-harness\apps\cli\lib\bin.js" plugin --profile web add "C:\Users\baba\Desktop\DSH工作区\plugins\dsh-plugin-showcase"卸载:... plugin --profile web remove dsh-plugin-showcase。
方式三:本机实际使用的手动等价物
三处改动,不跑安装:
C:\Users\baba\.dsh\profiles\web\package.json的dependencies加一行"dsh-plugin-showcase": "link:C:/Users/baba/Desktop/DSH工作区/plugins/dsh-plugin-showcase";- 同一个文件的
dsh.profile.bundles末尾追加"dsh-plugin-showcase"; - 建一个目录 junction,让 Node 能解析这个包名:
C:\Users\baba\.dsh\profiles\web\node_modules\dsh-plugin-showcase→C:\Users\baba\Desktop\DSH工作区\plugins\dsh-plugin-showcase(本机实测为<JUNCTION>重解析点;重建命令cmd /c mklink /J <链接> <目标>)。
为什么本机不用安装命令。 它会在 profile 内跑一次安装,而这次安装会重新解析整棵树。
这个 profile 里已经装着十一个第三方插件(dsh-cost-meter、dsh-better-sidebar、
dsh-chat-import、dsh-context、dsh-memgas、dsh-wallpaper-bg、@linxin666/*、
@liustack/*、@tt-a1i/archify-dsh)。上面三处改动正是链接安装后的最终状态,但没有那次
可能改写这十一个插件版本的解析过程。
不启动、只验证层(以下为实测输出):
node "C:\Users\baba\Desktop\deepseek-harness\apps\cli\lib\bin.js" --profile web --dump-config
# ...
# == dsh-plugin-showcase
# - id: showcase
# name: dsh-plugin-showcaseDSH 的 HMR 监视 profile 的 package.json(只看 bundles 数组)与 profile 的 patch
文件,因此追加条目会在不重启宿主进程的情况下重新组合;浏览器那一半需要刷新一次页面。
撤销同样只是把这三处改回去。
体检(0.2.0 新增)
showcase_doctor 无参数,返回一份 HealthReport:
{
generatedAt: "ISO", pluginVersion: "0.2.0",
dshVersion: "0.2.1-rc.2", // string | null
summary: { ok, warn, fail, unknown }, // 整数,与下面 checks 的统计恒等
checks: [{ id, title, status, detail, hint }] // hint: string | null
}两种问法:
- 工具:跑一次
showcase_doctor(showcase_inspect仍然返回 v1 那份巡检快照) - 命令:
/showcase doctor—— 同一段文本直接回在对话里
渲染文本首行是 DSH 体检报告 <generatedAt>,随后每条 check 一行
[OK|WARN|FAIL|?] <title> — <detail>,有下一步时再缩进一行 ↳ <hint>,末行是
合计: ok N / warn N / fail N / unknown N。
六项 check(按顺序):
| id | 看什么 | ok / warn / fail / unknown |
| --- | --- | --- |
| engine.dsh | 运行中的 DSH 版本(读 <profile>/node_modules/@deepseek-ai/dsh-app-boot/package.json)与 engines.dsh 比对 | ok = 满足范围,fail = 不满足(hint 提示升级),warn = 未声明 engines.dsh,unknown = 版本读不到或范围无法离线解析 |
| workspace.cwd | workingDirectory | ok = 有目录,warn = 取不到 |
| model.default | agentDefaultModel | ok = provider/model,unknown = 无该服务 |
| plugin.gate | 本插件的拦截门 | ok = 开启,warn = 关闭(hint: /showcase on) |
| plugin.locale | settings.describe() 里的界面语言偏好 | ok = 有值,unknown = 读不到 |
| market.index | pluginMarket.listIndexes() 的索引列表 | ok = 每个源都可用,warn = 一条都没配或部分不可用,unknown = 没有市场服务 |
任何一条 check 内部抛错都不会让整次体检失败。 只有它自己那行退化成 unknown,
detail 写成 检查异常: <message> 并带 hint,其余五项判决保持不变,合计仍然是六项。
命令
| 输入 | 回答 |
| --- | --- |
| /showcase | v1 那份巡检报告文本 |
| /showcase on / off | showcase 拦截门: 已开启 / 已关闭 |
| /showcase doctor | 体检报告文本(与工具同一份渲染) |
| /showcase about | 一行:版本、两个工具、命令分支、拦截门状态、DSH 版本 |
| 其它 | /showcase [on|off|doctor|about] |
输入先 trim 再转小写,所以 ON 有效,Dr. Who 得到用法那一行。
拦截门
默认开启。当一次工具调用的 command、cmd、script 或 code 参数(不区分大小写)
命中下列任一模式时拒绝执行:
rm -rf /、rm -rf ~- fork 炸弹:
:(){:|:&;}、:(){ :|:& };:、.(){ :|:& };:、bomb(){ bomb|bomb& };bomb del /f /s /q c:\、format c:- 处在命令位置上的
shutdown/shutdown.exe词(前面可以带sudo、doas或pkexec),例如shutdown /s /t 0、sudo shutdown -h now
把空格抹掉的写法(例如 rm -rf /tmp),或把空格换成制表符,同样拦得住。拒绝理由固定为
showcase: 拒绝执行破坏性命令;其余一律调用 next() 放行。这四个参数键之外的文本不
参与匹配;钩子内部出故障也照样 next() —— 插件 bug 绝不能阻塞工具调用。
设置卡与面板
设置卡片 —— 设置里的导航行 功能展示 / Showcase(id showcase,order 90):
标题与说明、体检提示、一行可复制的 /showcase doctor、刷新与"打开巡检面板"按钮、带
v0.2.0 与拦截门状态的页脚、三条能力行,最后是快照或降级文案。
右侧栏面板 —— tab 类型 id showcase-panel、kind showcase、标题
巡检面板 / Showcase panel,面板体挂在同一个 key 上。打开它有两个入口:左侧栏底部
Settings 旁边的 ◎ 按钮,以及设置卡上的按钮,两者最终都走
sidebarRight.openTab('showcase')。这个 tab 类型没有声明 guide 条目,所以它不会出现
在右侧栏的引导页里。
面板一打开就是三步引导:1)跑一次体检 —— 把 /showcase doctor 作为可复制文本交给你;
2)打开设置卡;3)了解拦截门 —— 给出 /showcase on|off 的可复制文本。每一步都有自己
的复制按钮,按下后标签变成 已复制 / Copied,约 1.6 秒后回退。页脚显示 v0.2.0,
取不到快照时再加上降级那一行。
国际化
19 个运行期键,en 与 zh 各一份,都是真翻译而不是照抄:
v1 的八个 title subtitle panelTitle panelEmpty gateOn gateOff
openPanel refresh,加 v2 的 welcome stepDoctorTitle stepDoctorBody
stepSettingsTitle stepSettingsBody stepGateTitle stepGateBody copyHint
copied doctorHint aboutBody。
语言解析顺序是 ctx.locale → navigator.language → en;没有 locale 服务的宿主照样
渲染真实文案。
市场索引(随包自托管)
v0.2.0 起索引跟包一起走:market/index.json(format 1,收录本插件),并在
package.json 的 files 白名单里,所以它在发布出去的 tarball 里。对外地址:
https://cdn.jsdelivr.net/npm/dsh-plugin-showcase@latest/market/index.json在发现页把它添加为索引源,就不用任何本地服务器也能装。
开发期本机用过的那套临时服务仍在 http://127.0.0.1:8791 上监听(它的索引在
/index.json 回答 200)。它已经不再需要:把发现页的索引源换成上面那条 CDN 地址
即可,之后那套本地服务可以停掉。
市场元数据仍然来自 locale/en.json(锚点)与 locale/zh.json,所以插件页会显示本地化
标题与描述,配上 icon.svg。
诚实的限制清单
- client 侧仍然拿不到宿主实时数据,零构建约束下也拿不到。 官方 remote API 路线需要
typert 装饰器、代码生成步骤和第三方依赖——这三条与"原生 ESM、不构建、不加依赖"逐条
冲突。
lib/client.js会去探测几种可能的形状(remote.showcase、ctx.showcase), 失败即降级为null。所以设置卡与面板显示的是静态能力行加降级文案,不是实时快照; 也正因如此,首启引导只能把/showcase doctor文本交给你,而不是替你去调用宿主。 sidebar.footer.action座位不投影label。 侧栏外壳只以{ wide }渲染这个 座位,可见文本由组件自己画(◎,标签通过aria-label承载)。那个labelthunk 是合法的SlotLabel也没写错,只是这个座位没有壳去读它。- 390px 左右的表现由宿主决定,不由插件决定。 实测容器宽度低于 320px 时座位才改为
堆叠,且每个盒子都是
min-width: 0加overflow-x: hidden,被压窄时只会让行变短、 不会撑出横向滚动条。但右列宽度是 DSH 自己钳制的:插件既不能把面板做得比宿主允许的 更窄,也不能更宽,而 390px 以下的情况只是通过容器实测走到的,没有在真实窄视口里验证。 - 没有真实浏览器的视觉回归 —— 测试覆盖事实,不覆盖像素。 client 侧证据来自 Node 桩
测试:
react被换成最小的createElement/useState/useEffect/useRef替身, 所以断言的是元素树与文本(19 键双语、三条引导标题、点击后的"已复制"、降级文案)。 既没有截图基线,也没有像素比对。
二次开发指引
- 加一个工具。 照抄
inspectTool(lib/index.js:600)或doctorTool(:619) 那种原始 JSON-SchemaToolDefinition形状,用ctx.effect(() => ctx.tools.register(<tool>), 'showcase: <name>')注册 (:638/:639)。output必须带{ schema, render }。 - 加一项 check。 在
buildHealthReport(lib/index.js:511)的数组里加一行runCheck('<id>', '<标题>', () => …),保持这层包裹(抛错才会退化成unknown); 只有形状真的变了才动buildHealthSchema。 - 加一个新 slot。 在
apply()(lib/client.js:525)里照抄slots.inject(<slot>, () => slots.register({ name, … }, 组件))这个形状:settings.section在:531、sidebar.right.pane.tab在:551、sidebar.footer.action在:559。右侧栏 tab 必须两半都注册——面板体的 key 要等于 通过sidebarRightTabs注册的类型 id。 - 加一条运行期文案。 同时加进
dict.en与dict.zh(lib/client.js:13),并把tests/helpers/client-harness.mjs里的DICT_KEYS一起扩展,双语用例才会继续守住它。
测试
npm install # 只做一次,需要访问 registry(devDependency: vitest)
npm test # 之后完全离线,一条命令跑完整个套件两个文件共 98 个用例,不写死任何机器路径——所有路径都由 import.meta.url 推导,夹具
(一个工作区、一个双版本 DSH profile)是每次运行现建的临时目录。
tests/host.test.mjs(66 个):模块形状、四处注册的ctx.effect生命周期、两个工具 的参数与output契约(返回值用各自声明的 schema 反向校验)、快照形状与""/null降级、git 分支发现、八条破坏性模式外加抹空格写法与参数键范围、关机类命令的词边界、 钩子内部抛错仍放行、拦截门开关、HealthReport 形状与"不出现undefined"、summary 与 checks 恒等、六项 check 各自的 ok/warn/unknown/fail 分支、单条 check 抛错只降级自己、 报告渲染版式,以及命令的五种输入。tests/client.test.mjs(32 个):lazy-CJS 登记、factory 导出(含VERSION)、恰好三个 座位、tab 类型与面板体 key 一致且服务晚到也能补注册、侧栏按钮的打开路径、19 个双语键、 三条引导标题、语言解析(含没有 locale 服务的宿主)、fetchSnapshot的各级降级、 有数据与无数据两种渲染、首启引导、点击复制后变"已复制"、刷新点击。
运行器:vitest 3(已声明的 devDependency)。
