DeepSeek Harness Plugin Hub

发布与管理完整 Harness Profiles,发现适合你的插件。

探索

插件目录环境预设文档中心动态

社区

发布插件联系我们报告问题

相关链接

Plugin Hub GitHubDeepSeek Harness 官方项目系统状态隐私说明
© 2026 DeepSeek Harness Plugin HubPowered byPaxTech

独立、非官方社区项目,与 DeepSeek 官方无隶属、授权或背书关系。

Mini Skin — DeepSeek Harness 插件(DSH Plugin)
DeepSeek Harness Plugin Hub
ProfilesPlugins分类动态文档登录管理 Profiles
ProfilesPlugins分类动态文档登录
← Plugins
M

dsh-mini-skin

Mini Skin

仅使用样式表的 DSH 皮肤:背景图、调色板变量、方形 UI 约定和字体,全部集中在一个设置区段中。不使用观察器,不修改 DOM。

插件会安装到这里;不确定时保持 web。

npx -y @deepseek-ai/dsh plugin --profile web add github:Firefly-Star/dsh-mini-skin#4209a9289f4c683a226a66385c931d4632c99d1a
README兼容性版本

兼容性与来源证明

Mini Skin 以 dsh-mini-skin 发布,当前版本为 0.3.1。Plugin Hub 会校验它的 manifest,并保存精确安装来源,便于复现安装结果。

DSH 兼容范围
*
运行环境
web
发布来源
github
Registry 更新时间
2026/10/9

版本

0.3.1stable
2026/10/9
0.3.0stable
2026/10/9
0.2.0stable
2026/10/8

相关插件

正在加载相关插件…

最新版
0.3.1
DSH
*
HMR
重启进程
Tree shaking
未声明可安全裁剪
解包体积
未提供
文件数
未提供
Surface
web
许可证
MIT
发布源
github
GitHub
★ 0
周下载
0
最近提交
2026/10/10
查看源码 ↗
README Badge

点击下方 Badge 复制 Markdown,粘贴到 README 即可。

这是你的 Plugin?认领权益 · 优先安全扫描

验证 package.json 声明的 GitHub 仓库,即可管理这个公开页面。认领后,Hub 会优先安排当前版本的安全扫描,并在通过后公开展示结果。

认领这个 Plugin →
报告问题

相关插件

继续浏览 ui-customization 分类下经过校验的插件。

Web App@deepseek-ai/dsh-web-appdsh 浏览器界面捆绑包:位于 dsh-base 之上的 Web 补丁层,加上运行时粘合插件(提供前端 dist、Web 界面提示符、bash 运行时变量和 URL 行)Experimental Agent Team Web Profile@deepseek-ai/dsh-experimental-agent-team-web-profile用于 Agent Teams Remote 和 UI 插件的实验性 Web 配置层Ab Chartdsh-ab-chart带有绘制其调用的浏览器卡片的图表渲染工具,封装在一个可发布的插件包中Whale Widgetdsh-whale-widgetDSH Web 界面右下角的 DeepSeek 余额小鲸鱼挂件:余额/今日已用/峰谷定价、自定义泡泡点击序列(文本/余额/今日/峰谷/图片/随机语句与并列加权选择)、逐行样式与字体、悬浮快捷编辑、音效与每轮消耗、自定义角色/动图/音效、吸附与翻转自定义

README

dsh-mini-skin

一个只注入样式表的 DSH 皮肤插件,带一个自包含的皮肤库。所有开关集中在 设置 → 自定义皮肤 一个分区里。

运行时成本刻意压到最低:0 个 MutationObserver、1 个一次性监听(DOMContentLoaded)、只依赖宿主的稳定钩子(data-slot=*)。图片数据一律留在样式表里,切换素材只改一个 body 属性;行内变量只存极小值(rgba 颜色、字体栈、px 偏移、blob URL)。


安装

# GitHub(推荐:一行装,不需要 npm 账号)
dsh plugin --profile web add 'github:Firefly-Star/dsh-mini-skin'

# 本地目录(link:改文件即时生效,开发用)
dsh plugin --profile web add '<绝对路径>\mini-skin'

# tarball(复制安装,工作区目录不再是运行依赖)
npm pack --pack-destination .
dsh plugin --profile web add '<绝对路径>\dsh-mini-skin-0.3.0.tgz'

本插件未发布到 npm(npm 上没有 dsh-mini-skin):请用上面的 GitHub 或 tarball 方式安装。从 GitHub/tarball 安装是复制安装——本地源码的改动不会再影响已装版本。

重启语义:客户端半边(lib/client.js)热更新即可;节点半边(lib/index.js)改动必须重启 DSH。皮肤库路由只在重启后存在。


功能

三种皮肤状态

状态含义
官方皮肤宿主原样:本插件的样式表、body 属性、行内变量全部撤下(插件本体仍在,设置分区照旧可用)。它自己也是一份皮肤包 —— 见下
皮肤库里的皮肤<DSH_HOME>/mini-skins/ 里的 .json 包,名字取自包内 name
自定义当前设置的指纹与应用皮肤时记下的指纹不符(即你改过任何一项)

官方皮肤是一份包文件,不是代码里的常量。 它就是库里的 official.json:深色→暗色场景、浅色→亮色场景、侧栏→maid-atelier 立绘,主内容不透明度 52 / 侧栏 100,素材按名字引用(dark-hero / maid-left …),所以只有 1.7 KB、不带图片字节。插件在每次读取皮肤库列表时检查它是否还在,缺了就补一份(判据是包名,所以你自己另存或改名的那份不会被覆盖)。你在面板里选「官方皮肤」时,客户端是真的去读这个文件来推导配置 —— 「宿主原样」这层语义(撤下插件的一切)仍然是渲染规则,配置本身已经全部外置。

official.json 不单独出现在「正在使用」的下拉里,因为那一项就是它。

四套预设:主题 × 状态

主内容背景图 / 不透明度、侧栏背景图 / 不透明度 / 水平 / 垂直位置 按四个组合各存一份:dark:idle / dark:work / light:idle / light:work。

生效组合 = 当前主题 × 当前状态(是否正在工作);主题事件与状态变化都会重放设置。

工作状态怎么检测:宿主只在 DOM 上暴露状态(没有服务、没有事件),所以每 0.4 秒读一次 DOM。判据按可靠性排序:

  1. [data-chat-running] —— 会话级的"整轮在跑"标记(chat 视图的 RunningStatus,源码注释写明 mount only while the Session is running)。它覆盖整轮:思考、流式输出、执行工具、压缩上下文……只要这一轮没结束就在。这是首选判据。
  2. [data-state='running'] —— 单个节点(推理行 / 工具卡 / 命令卡)自己还在流式时的标记,会被 settle 掉,只作兜底。
  3. [data-composer-input][data-phase] —— 只有"提交中 / 裁决中"两个瞬时相位,同样只作兜底,不代表整轮在跑。

教训:只用了 2) 和 3) 的版本把"执行工具 / 纯深度思考"误判成空闲——那两个相位在这两种时刻都不成立。

原皮肤为此挂了整个 body 的 MutationObserver;本插件改用一个定时器(每轮一两次 querySelector)—— 代价是切换最多延迟 0.4 秒,收益是保住 0 观察器。

面板顶部的「正在编辑」是四选一:切换它会调用宿主的 theme.setTheme() 把界面主题真的切过去、并临时把预览状态切到空闲或工作,所以你改什么就能立刻看到什么;关掉面板后交还给自动检测。在某一套里改任何值也会先确保该套生效。

背景图(勾选式)

主内容
  [x] 有背景图
  |-- 背景图     本地文件… / (禁用项)内置素材:亮色场景(来自皮肤)
  |   已选择本地文件:xxx.webp        <- 勾了没选时显示「尚未选择图片。」
  |   不透明度   ----o----  [52] %
  [ ] 有背景图   -> 素材 / 不透明度 / 位置全部隐藏,该模式素材设为「无」
侧栏  同一套(含水平 / 垂直位置)
  • 勾选 = 该模式素材为 file;取消 = none。存储与皮肤包格式与选择无关。
  • 素材只支持本地图片(系统文件选择器,图片本体存 IndexedDB)。不支持远程 URL:custom 分支仅作为旧设置的兼容兜底保留。
  • 内置素材(场景 / 立绘)不能在这里挑选——它们属于"皮肤"这一层;下拉里只以禁用项出现,告诉你"现在是什么、来自哪"。

其它

  • 方形契约(可关):按钮、输入框、卡片、弹窗圆角归零
  • 字体:界面字体(覆盖宿主的 --dsw-font-family)+ 侧栏字体(只作用于侧栏列)
  • 品牌字标:DSH 方框字标 / 宿主原样
  • LINK ACTIVE 标签开关

皮肤库(插件自己的目录)

节点半边把 <DSH_HOME>/mini-skins/ 通过一条同源路由暴露给浏览器半边:

GET                  -> { dir, skins: [{ file, name, savedAt, bytes, ok, error }] }
GET  ?file=<名字>     -> 该包的完整 JSON
POST { pack }        -> 写进库(重名自动加时间戳后缀)
DELETE ?file=<名字>   -> 删除
  • 只处理目录里直接的 *.json;请求只能点名文件,不能给路径(basename + 白名单正则双重校验)。
  • 解析不了的文件不隐藏,在下拉里标灰并给出原因(JSON 解析失败 / format 不符 / 读取失败:<code>)。
  • 官方皮肤包固定落到 official.json:客户端按文件名引用它,否则"按包名自动命名"会为中文名再写一份、库里出现两个官方皮肤。
  • 列表里的 official.json 被客户端过滤掉(下拉里那一项就是它)。
  • 导出 = 两件事都做:下载 <名称>-<日期>.json 并且存入皮肤库(状态行分别报告两边结果)。
  • 导入:系统文件选择器读一个 .json,图片写回本机存储后立即套用。
  • 当前皮肤的那个包被删或改名时,客户端启动会按包名在库里找同名的一份接手,让活动皮肤认得回来。

包格式(自包含)

{
  "format": "dsh-mini-skin-pack",
  "version": 3,
  "name": "我的皮肤",
  "savedAt": "2026-...",
  "shared": { "square": true, "brandMark": "dsh", "linkChip": true, "uiFont": "system", "sidebarFont": "inherit", "packName": "我的皮肤" },
  "modes": {
    "dark:idle":  { "canvasImage": "dark-hero", "canvasOpacity": 90, "sidebarImage": "maid-left", "sidebarOpacity": 100, "sidebarOffsetX": 0, "sidebarOffsetY": 0 },
    "dark:work":  { "canvasImage": "dark-active", "canvasOpacity": 90, "sidebarImage": "maid-left", "sidebarOpacity": 100, "sidebarOffsetX": 0, "sidebarOffsetY": 0 },
    "light:idle": { "canvasImage": "light-hero", "canvasOpacity": 65, "sidebarImage": "maid-left", "sidebarOpacity": 100, "sidebarOffsetX": 0, "sidebarOffsetY": 0 },
    "light:work": { "canvasImage": "light-active", "canvasOpacity": 65, "sidebarImage": "maid-left", "sidebarOpacity": 100, "sidebarOffsetX": 0, "sidebarOffsetY": 0 }
  },
  "images": { "sidebar:dark:idle": "data:image/webp;base64,..." }
}
  • 四套预设键:dark:idle / dark:work / light:idle / light:work;v2 的 dark / light 仍能导入(映射到该主题的两套)。
  • 内置素材按名字引用(dark-hero / light-hero / maid-left ...),不重复打包 -> 纯内置配置的包只有几 KB(skins/official.json 1.7 KB 就是这么来的)。
  • 本地图片的字节内嵌进 images(键为 区域:模式:状态)-> 换台机器导入即用,不需要原文件。
  • activeSkin(皮肤库身份)不进包:由导入方在导入后决定。
  • 因此"自包含"是结构上的保证:只涉及本地图片,没有跨域 / 失效链接的可能。

数据与存储

位置内容
localStorage['dsh-mini-skin:settings:v1']设置 v2:{ version, dark{10 项}, light{10 项}, square, brandMark, linkChip, uiFont, sidebarFont, packName, activeSkin }
IndexedDB['dsh-mini-skin'].images本地图片本体,键为图片槽位 区域:模式:状态(canvas:dark:idle … character:light:work);读出来的 blob URL 按槽位惰性缓存,卸载时只回收缓存里实际存在的那些
<DSH_HOME>/mini-skins/*.json皮肤库

迁移:v1(扁平、无模式概念)会同时写进两套预设;更早的 dsh-mini-skin:art-opacity 单键也会被读取(先判键存在——Number(null) 是 0,曾经因此让全新安装的默认不透明度变成 0)。


文件

路径说明
lib/index.js节点半边:皮肤库目录 + /api/dsh/mini-skins 路由(ctx.inject(["webServer"], ...) + server.register)+ 官方皮肤包的持有与自愈
lib/client.js浏览器半边(提交型产物,约 473 KB,含 5 张内嵌图):样式表、生命周期、设置分区、皮肤库客户端
package.jsondsh.bundle.patch / dsh.client / exports(含 ./locale/*.json)/ files 白名单
cordis.patch.ymlbundle patch:插入插件行
locale/{zh,en}.json插件菜单的本地化名称与简介
assets/plugin-icon.svg插件图标(自绘,无第三方美术)
artwork/署名与许可
skins/official.json官方皮肤包(1.7 KB,纯内置素材引用):深色→暗色场景、浅色→亮色场景、侧栏→立绘
skins/orca-link.json虎鲸链路示例包(四态:深色 90% / 亮色 65% 主内容不透明度 + 8 张动图槽位)
skins/深海女仆.json深海女仆皮肤包:把 maid-atelier 的宫殿 + 双女仆合成成一张画布图 + Q 版小人(1.8 MB 自包含)
dev/anim/动画管线(图集切片、质心对齐、皮肤包生成、接缝校验):产出落在 $DSH_HOME/mini-skins,不写回本仓库,留作复现手段
dev/maid/深海女仆皮肤的构建侧:两个脚本 + 两张合成中间图 + 一份"哪些还原得了 / 哪些还原不了"的分析

皮肤包(skins/)

skins/ 下是可以直接放进 <DSH_HOME>/mini-skins/ 的皮肤包(一个包一个 json):

包说明
official.json官方皮肤。节点半边在库缺它时会补一份(按包名判断,不覆盖你改过的)
orca-link.json虎鲸链路:四态预设 + 8 张动图槽位内嵌
深海女仆.json深海女仆:合成场景 + Q 版小人,8 个槽位内嵌

三个包的素材都是内嵌 base64(mini-skin 不支持远程 URL),所以文件本身就有 1~2 MB。

重新生成「深海女仆」那个包(需要隔壁 dsh-deep-whale 仓库的素材,本仓库不分发那些原图):

cd dev\maid
python build-scene.py   # 宫殿 + 双女仆 -> scene-{dark,light}.webp(中间产物,留在这里)
python build-pack.py    # -> ..\..\skins\深海女仆.json

脚本从 <仓库根>/../dsh-deep-whale/maid-atelier/assets 找素材;换机器时用环境变量 MAID_ATELIER_ASSETS 指绝对路径。savedAt 每次构建都会变,要可复现的产物就设 MAID_SAVED_AT(固定成仓库里那份的值即可逐字节重现)。


开发

工厂源码在 dev/new-factory.txt,assemble.mjs 把它拼到 lib/client.js 的图片前缀之后。不要手改 lib/client.js 里那段工厂:它每次都会被覆盖。

node dev/assemble.mjs          # 拼接(保留 412 KB 图片前缀 + 内嵌 5 张图)
node --check mini-skin/lib/client.js   # 语法

验证(探针)

验证脚本通过 CDP 驱动一个隔离的无头 Chrome,对着一个探针 DSH 实例跑真实交互:

# 1) 探针实例(写 ~/.dsh,需要更宽权限)
dsh --profile web --no-open --port 0
# 2) 隔离 Chrome(需要命名管道权限)
chrome --headless=new --no-sandbox --remote-debugging-port=9335 --user-data-dir=<工作区>\_probe-chrome
# 3) 跑脚本
$env:DSH_PROBE_APP='http://127.0.0.1:<端口>/?token=<令牌>'; $env:DSH_PROBE_CDP='http://127.0.0.1:9335'
node dev/verify-chain4.mjs

脚本要点(踩过的坑都在里面):设置弹窗必须用真实鼠标事件(Input.dispatchMouseEvent)点击,.click() 无效;点击前要 scrollIntoView(面板会超出视口);用 <select> 的 value + change 合成事件驱动不了 React。

探针的硬限制:探针实例切不动宿主主题(「外观」那三个方块点了不生效),所以"切主题 -> 换预设"这条路必须由人在真实界面里验。


已验证 / 未验证(如实)

已在探针里实测通过:插件装载(样式表 + body 属性)、画布与侧栏背景层真实绘制、侧栏定位 0px 0px, 50% 100%、面板渲染(7 下拉 / 4 滑块 / 4 数字框 / 11 按钮)、按模式取预设一致(含侧栏垂直偏移)、导出包生成(格式 / 命名 / 入库)、控制台无异常。

已用无头 Chrome 实测(软件渲染):侧栏 268x268 下「无背景 / 静态图 / 空闲动图(6帧1.12s) / 工作动图(8帧0.66s) / 工作动图全屏」五档,帧距中位数均为 8.3ms(120Hz)、p95 8.4-8.5ms、最大不超过 18ms,Task% 差异全在 ±0.5% 噪声内(基线反而最高),Layout/Recalc 均为 0.00 —— 即动图代价在噪声之下。无头是软件渲染,真机 GPU 表现建议用 DevTools → Rendering → Frame Rendering Stats 复核。

只有静态核查:勾选式 UI、皮肤库路由的运行时行为、导入流程、v3 四套预设的迁移路径。

已在真实界面确认(用户实测,2026-10-09):

  • 面板改任何值不再被回退(bug 7)
  • 执行工具 / 纯深度思考时保持工作态(bug 8)
  • 深海女仆皮肤进出工作态不再闪(bug 12 + 13)—— 这一条最初两次修复都没治住,最后定位到"每个槽位各建一个 blob URL",按内容去重后才消失
  • 顶图不再把侧栏工作区列表挤掉(clamp(72px, 18vh, 上限))

仍未验证:「官方皮肤改为库里的 official.json」这条做了静态核查 + 一次真实路由的入库/读取往返(1787 字节、四套预设键正确、库列表里只剩官方与虎鲸链路两份),还没在界面上点过 —— 需要重启 DSH 让节点半边的新代码生效后再验一次。

探针 / 实测抓出并修掉的真 bug(留存记录):

  1. 行内样式写几百 KB 的 data URI -> 图不显示、换图无效(图片数据必须留在样式表)
  2. 蒙版 rgba() 当作 background-image 图层 -> 整条声明失效(必须是 linear-gradient())
  3. 缺失的旧键 Number(null) === 0 -> 全新安装默认不透明度为 0
  4. 外层脚本 const IMAGES 在 HMR 重复求值时抛 already been declared -> 整份插件失效(改为可重复求值的 window.__dshMiniSkinArt 赋值)
  5. 受控 <select> 的当前值不在选项里 -> 显示第一项("不要背景图"),再选它因"值没变"不触发
  6. 面板用 inject 捕获的对象快照初始化 -> 重新挂载后显示旧值(改为向插件取当前值)7. 面板改任何值都会被"重新读皮肤包"覆盖回去(过 0.几秒回退成当前皮肤的原配置)。根因:改值走的是 reapply(),而它为了"磁盘上更新过的包点了也能生效"会重新读包、把读回来的旧配置写回 settings 并落盘。修法:改值只走纯套用的 preview()(不落盘、不读包),reapply() 也改成只影响页面、绝不写回设置
  7. 工作状态误判:只用 [data-state='running'] + composer data-phase 时,执行工具 / 纯深度思考会被判成空闲(那两个相位在这两种时刻都不成立)。改为以会话级的 [data-chat-running] 为首选判据
  8. fileUrls 只预置了四个旧的两段键(canvas:dark…),而读写都用三段键(canvas:dark:idle)—— 对象上根本没有那些键,读到的是 undefined:行内出现 url("undefined") 让图不显示,undefined !== null 又让卸载时 revokeObjectURL(undefined) 抛异常、把整段清理中断。改为 Map + 惰性读取(读到才缓存,读不到就是"没有这张图")
  9. 「官方皮肤」以前把配置写死在代码里(一个 builtin 状态 + 一组默认常量),于是"官方"与"包"两套语义并存、面板里出现两个近义条目。改为:官方皮肤就是库里的 official.json,插件在读取列表时保证它存在(判据是包名,不覆盖用户改过的那份);面板里 official.json 不再单独出现
  10. 官方皮肤包入库时按包名生成文件名,中文名被净化成别的名字,客户端按 official.json 找不到它 → 库里出现两个官方皮肤。改为:官方包固定落到 official.json
  11. 切空闲/工作态时画面闪一下(四套预设指向同一张图也照样闪)。根因有两层:① 状态一变就重写整套设置,而图片是以 blob URL 写在 body 的行内自定义属性上的 —— 重写自定义属性会让 body 子树整体失效、那张 1920×1080 的背景重新解码,于是有一帧是空的;② 更要命的是导入时每个槽位各建了一个 blob URL,所以四套状态虽然存的是同一份字节,属性值却真的在 A → B 之间变,①的"值没变就不写"守卫拦不住。修法:按内容指纹(size + text)复用同一个 blob URL(同字节的图共用 URL,状态切换时值根本不变),再加"值没变就不写"的守卫。数值型变量照写,保证拖动滑块一定生效。这是插件级的修复:任何"多套状态共用一张图"的皮肤都会闪,而四套图确实不同的配置照样正常重放
  12. 去重之后才暴露的配套坑:artStore / artRevoke 原来无条件 revokeObjectURL,而一个 URL 现在会被多个槽位共用 —— 必须改成"没有别的槽位还引用它"才回收,否则会把某张图从活着的槽位底下抽走。另外 clearSettings 是直接 removeProperty(绕过了写入缓存),那里要把缓存一起清掉,否则下次激活时属性会被当成"重复"而永远不再出现

许可

本仓库的代码与美术分开许可,两套条款各自独立:

范围许可文件
代码:lib/index.js、lib/client.js 里的代码、package.json、cordis.patch.yml、locale/*、assets/*、skins/*/*.py、构建工具MITLICENSE
美术:artwork/ 下的图片资源、lib/client.js 内嵌的图片数据、dev/maid/scene-*.webp 合成图、skins/深海女仆.json 包内图片CC BY-NC-SA 4.0artwork/LICENSE-ARTWORK

署名链(必须随资源一起保留):

  • 场景图:orca-link —— 上善 -> Small-tailqwq,见 artwork/NOTICE
  • 立绘 / 宫殿 / Q 版小人:maid-atelier —— 上善 -> ZipZipPipe -> Small-tailqwq,见 artwork/NOTICE-maid-atelier

注意事项:

  • 美术是非商业许可:不得用于以商业优势或金钱报酬为主要目的的用途。
  • 立绘经降采样与重编码后随包分发,属改编作品,按相同方式共享条款继续以 CC BY-NC-SA 4.0 分发。
  • dev/maid/scene-*.webp、skins/深海女仆.json 包里的 base64 图片同样是改编作品: 分了它就要把上面的署名链与许可一起带走。该目录只放脚本与产物,不复制 maid-atelier 的原始素材文件。
  • 复制本插件的图片资源时,署名与许可必须一起带走。