Skip to content

dsh-plugin-showcase

Verified

dsh-plugin-showcase · v0.2.0 · MIT · Web UI

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.

Install

dsh plugin add dsh-plugin-showcase

Confirm the layer applied with dsh --profile default --dump-config — see the install guide.

Source

Published to npm without a public repository. Inspect the package contents before installing.

Tags

Creators

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。

方式一:从市场安装(正常路径)

  1. 把 0.2.0 发布到 npm(流程见 PUBLISH.md),包内索引就能在 https://cdn.jsdelivr.net/npm/dsh-plugin-showcase@latest/market/index.json 取到。
  2. 打开 DSH → 设置 → 市场/发现页,把这个 URL 添加为索引源。宿主服务 pluginMarket 维护这份 indexes 列表,它的初始值是空数组:发现页不搜索 npm,所以没配索引之前什么都不会出现。
  3. 搜索 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。

方式三:本机实际使用的手动等价物

三处改动,不跑安装:

  1. C:\Users\baba\.dsh\profiles\web\package.json 的 dependencies 加一行 "dsh-plugin-showcase": "link:C:/Users/baba/Desktop/DSH工作区/plugins/dsh-plugin-showcase";
  2. 同一个文件的 dsh.profile.bundles 末尾追加 "dsh-plugin-showcase";
  3. 建一个目录 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-showcase

DSH 的 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

输入先 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。

诚实的限制清单

  1. client 侧仍然拿不到宿主实时数据,零构建约束下也拿不到。 官方 remote API 路线需要 typert 装饰器、代码生成步骤和第三方依赖——这三条与"原生 ESM、不构建、不加依赖"逐条 冲突。lib/client.js 会去探测几种可能的形状(remote.showcase、ctx.showcase), 失败即降级为 null。所以设置卡与面板显示的是静态能力行加降级文案,不是实时快照; 也正因如此,首启引导只能把 /showcase doctor 文本交给你,而不是替你去调用宿主。
  2. sidebar.footer.action 座位不投影 label。 侧栏外壳只以 { wide } 渲染这个 座位,可见文本由组件自己画(◎,标签通过 aria-label 承载)。那个 label thunk 是合法的 SlotLabel 也没写错,只是这个座位没有壳去读它。
  3. 390px 左右的表现由宿主决定,不由插件决定。 实测容器宽度低于 320px 时座位才改为 堆叠,且每个盒子都是 min-width: 0 加 overflow-x: hidden,被压窄时只会让行变短、 不会撑出横向滚动条。但右列宽度是 DSH 自己钳制的:插件既不能把面板做得比宿主允许的 更窄,也不能更宽,而 390px 以下的情况只是通过容器实测走到的,没有在真实窄视口里验证。
  4. 没有真实浏览器的视觉回归 —— 测试覆盖事实,不覆盖像素。 client 侧证据来自 Node 桩 测试:react 被换成最小的 createElement/useState/useEffect/useRef 替身, 所以断言的是元素树与文本(19 键双语、三条引导标题、点击后的"已复制"、降级文案)。 既没有截图基线,也没有像素比对。

二次开发指引

  • 加一个工具。 照抄 inspectTool(lib/index.js:600)或 doctorTool(:619) 那种原始 JSON-Schema ToolDefinition 形状,用 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)。