dsh-skill-console
已验证dsh-skill-console · v0.1.1 · MIT · Web 界面
DeepSeek Harness 技能控制台:在 Web GUI 里浏览全部本地技能、一键启用/停用、删除到可恢复回收站,以及从本地路径或 GitHub 仓库导入技能。
安装
dsh plugin add dsh-skill-console 用 dsh --profile default --dump-config 确认 layer 已生效 —— 参见安装指南。
源码
标签
作者
说明文档
dsh-skill-console
English | 中文
DeepSeek Harness 的技能管理插件。 在 Web GUI 的「设置 → 技能」里浏览全部本地技能、一键启用停用、删除到可恢复的回收站、从本地目录或 GitHub 仓库导入——不用再手动去命令行里搬文件。

为什么要有这个
dsh 的技能注册表在设计上就是只读的:provider 只负责 list() 和 get(),官方接口里没有任何写入路径。对一个注册表来说这是对的,但代价是每天都会遇到的操作——「这个先关一阵」「这个不用了删掉」「把那个仓库里的技能拿过来」——全都得回到终端手动改文件。
这个插件把这块补上,全程只用官方 SDK:不改 dsh 源码,不打补丁,不引入影子状态。
功能
| 浏览 | 全部本地技能,按发现来源分组(项目 / 自定义 / 用户 / 内置 / 运行时),支持搜索和启用状态筛选 |
| 启用 / 停用 | 一键切换。靠重命名技能的 SKILL.md 实现,重启后依然有效,且与磁盘状态始终一致 |
| 删除 | 移入各根目录下的 .trash,可恢复,另有单独的「彻底删除」 |
| 加载 | 技能页上的文件夹选择:直接选目录,勾选里面扫出来的技能,装上 |
| 导入 | 扫描本地目录或 GitHub 仓库,勾选后装进任一用户级根目录 |
| 诊断 | 列出那些永远进不了技能目录的文件,并说明原因 |
| 详情 | 渲染 SKILL.md 正文(标题、加粗、代码、表格),并显示 whenToUse、路径和附带文件 |
环境要求
- Node
^22.19.0 || >=24.0.0 - DeepSeek Harness,SDK
0.1.x(rc.7 及以上)
安装
从 npm 安装
包发布之后:
dsh plugin --profile web add dsh-skill-console
重启 dsh web,打开「设置 → 技能」。
从源码安装
git clone https://github.com/wendaokeliu-sys/dsh-skill-console.git
cd dsh-skill-console
pnpm install
pnpm build
npm link
dsh plugin --profile web add dsh-skill-console
免构建直接放置
编译产物没有任何运行时依赖,除了你 profile 本来就有的 dsh SDK——js-yaml 在构建期已经打进 bundle。所以把编译好的包直接放到 dsh 能解析到的位置就行:
<dsh home>/profiles/node_modules/dsh-skill-console/
package.json
lib/index.js
lib/client.js
然后往 profile 的 cordis.patch.yml(<dsh home>/profiles/<profile>/cordis.patch.yml)里加一行:
- insert:
- id: skill-console
name: 'dsh-skill-console'
<dsh home> 在 macOS / Linux 上是 ~/.dsh,Windows 上是 C:\Users\<你>\.dsh,也可能是 DSH_HOME 指向的位置。
注意:手工放进
node_modules的目录,可能被这个 profile 后续的pnpm install清掉。这条路适合试用,不适合长期安装。
开发模式
直接挂源码,不用打包:
dsh web --patch ./cordis.patch.yml
使用
全部功能在设置 → 技能一个页面上:技能列表、一个【加载技能】按钮、一个搜索框。其他东西不常驻——诊断提示条和回收站只在里面有内容时才出现。
列表
技能按发现来源分组:
| 来源 | 目录 |
|---|---|
project-dsh |
<项目>/.dsh/skills |
project-agents |
<项目>/.agents/skills |
custom |
customSkillDirs 指定的目录 |
user-dsh |
<dsh home>/skills |
user-agents |
~/.agents/skills |
bundled |
随包分发的技能 |
- 加载技能是唯一的添加入口,本机文件夹和 GitHub 仓库都走它。
- 左边的开关控制启用停用。项目级、内置和运行时技能的开关是灰的——它们在这里只读(见安全边界)。
- 点技能名打开详情:正文、
whenToUse、绝对路径、以及这个技能包里附带的资源文件。 - 删除二次确认后移入回收站。
- 右侧两个小圆点是调用策略:绿色 = 模型可调用,蓝色 = 用户可调用,灰色 = 关闭。
- 搜索框匹配名称和描述;旁边的分段控件按启用状态筛选。
回收站
删除会把技能移进回收站,只要里面还有东西,列表下方就会出现一个回收站区块。恢复把技能搬回原位——如果原来的位置已经被同名新技能占了,它会拒绝而不是覆盖。彻底删除不可逆。
加载技能
一个按钮,两种来源。
本机文件夹会打开系统的目录选择框。选一个目录,里面所有能导入的技能就列出来给你勾选安装。没有原生选择框的主机(多为远程部署)会退回成手填绝对路径。
GitHub 仓库支持 owner/repo、owner/repo@分支、普通 URL,以及带子目录的浏览地址(https://github.com/owner/repo/tree/main/skills)。
两种来源都是同一套流程:选目标根目录 → 扫描 → 勾选 → 导入所选。目标里已存在同名技能的候选项会被标出来并且默认不勾选;想覆盖就勾上覆盖同名技能。
GitHub 匿名调用 API 每小时 60 次,扫大仓库容易用完。启动 dsh 之前设一下 GITHUB_TOKEN(或 GH_TOKEN)可以提高配额:
GITHUB_TOKEN=ghp_xxx dsh web
诊断
当用户级目录里有文件永远进不了技能目录时,列表上方会出现一条提示,告诉你有几个、分别为什么:缺 description、名字不是 kebab-case、SKILL.md 里的 name 和目录名对不上、文件读不了,或者描述太短。没有提示条就说明一切正常。
配置
配置存在 dsh 自己的 settings 服务里,命名空间是 dsh-skill-console:
| 字段 | 默认 | 作用 |
|---|---|---|
enabled |
true |
总开关。关掉后 provider 卸载、写接口返回 503,目录接口仍可读 |
announceToAgent |
true |
往 system prompt 里加一段说明,让 agent 知道有这个插件、能做什么 |
allowNetworkImport |
true |
是否允许仓库导入 |
实现原理
启用停用不引入影子状态
官方 filesystem provider 只认两种发现形状:目录包的 <name>/SKILL.md,和扁平文件 <name>.md。停用就是把文件改名成 SKILL.md.disabled——文件还在原地,provider 扫不到,状态自然跨重启保持。GUI 之所以还能列出被停用的技能,是因为本插件自己扫盘时把 .disabled 文件也收进来并打上标记。
好处是不需要侧车状态文件。你手动改名、用 git 回滚、把目录同步到另一台机器,插件报告的永远是磁盘上的真实情况,不可能出现「配置说启用了、文件却不在」的错位。
删除
删除是 rename 到 <root>/.trash/<名字>-<时间戳>。.trash 是点开头的,官方 provider 本来就跳过点开头的条目,所以被删的技能对所有消费者天然不可见,不需要额外记账。恢复时从回收站条目的名字里读回原路径。
目录视图从哪来
dsh web app 里,宿主层的 skill-filesystem 行是故意关掉的——agent preset 各自往自己的 scope 层挂 provider。直接查全局层会是空的,所以本插件往那一层注册了一个自己的只读 provider,专供管理视图使用。
agent 会话不受影响:preset 层比全局层更近,同名技能永远是 preset 自己的 provider 胜出。
安全边界
- 只有用户级技能可写——
<dsh home>/skills和~/.agents/skills。项目级、内置和运行时技能只读展示,控件禁用。每次写入在执行任何 syscall 之前先过一道根目录检查。项目级技能属于它所在的仓库,应该跟着 git 走,不该被 GUI 悄悄改掉。 - 接口只走回环。 远端地址必须是 loopback 字面量,
Host头必须指向 loopback,跨站请求一律拒绝。就算你把dsh web绑到0.0.0.0,局域网里的人也够不到这些接口。 - 导入有硬上限。 目录深度、候选数量、单文件大小、单包文件数都设了上限。把导入器指向一个巨大的 monorepo 只会慢,不会失控。
- 仓库导入可以整个关掉,通过
allowNetworkImport。
开发
pnpm install
pnpm typecheck # tsc --noEmit
pnpm test # 44 个测试
pnpm build # 类型声明 + 两个 bundle
src/
protocol.ts 宿主端和浏览器端共享的线上类型 + 路由表
skillfs.ts 所有碰文件的操作:扫描、frontmatter 解析、启停、回收站
import.ts 导入来源(本地目录 / GitHub 仓库)以及落盘
provider.ts 注册进 ctx.skills 全局层的只读 provider
routes.ts /api/skill-console 路由族及其请求闸门
index.ts 宿主端 apply:settings、provider、routes、system prompt
client/
api.ts 路由的类型化客户端
locales.ts 中英文案(locale 服务强制双语对齐)
index.tsx 浏览器端 apply:注册 settings.section 槽位
panel/ 控制台页面
测试覆盖:按官方 provider 语义解析 frontmatter、写入闸门、停用 → 删除 → 恢复 → 彻底删除的完整生命周期、仓库地址解析、本地导入落盘,以及在真实 HTTP 服务器上跑的整套路由测试(含回环闸门和总开关)。
常见问题
「技能」分区没出现。 看 dsh web 的启动日志里有没有 skill-console 的报错,以及浏览器控制台里有没有 dsh-skill-console 加载失败。最常见的原因是包名从 profile 里解析不到——确认 <dsh home>/profiles/node_modules/dsh-skill-console 存在,或者 npm link 确实成功了。
装的技能找不到。 打开诊断页。如果那里也没列出来,多半是文件层级太深了——发现过程不递归,技能必须是技能根目录的直接子项。
导入报 403。 GitHub 限流,设 GITHUB_TOKEN。
开关提示「只读」。 那个技能在项目级或内置根目录里。去它所在的地方改,或者先复制一份到用户级根目录。
贡献
欢迎提 issue 和 PR,见 CONTRIBUTING.md。