Models & Providers

dsh-plugin-desk

Amouren7/dsh-plugin-desk · ★ 1

Amouren7

DeepSeek Harness 插件管家:在「设置 → 插件」新增标签页,用人话说明每个插件是做什么的,提供一键停用/启用(热生效)与安全卸载;同一页的「技能」分段盘点所有技能、标明唯一可用的触发方式,并给出两个真开关(模型自动加载 / 斜杠命令)。

README body is shown in Chinese.

License
MIT
Added
2026-10-30
Maintenance
active
Install kind
github
Manifest details
Manifest status
Declared
Manifest path
package.json#dsh
Manifest checked
2026-10-30T09:38:32.860Z
Lifecycle scripts
None found

Static manifest checks report declarations only; they are not compatibility or security review.

安装

dsh plugin --profile web add 'github:Amouren7/dsh-plugin-desk#92f1ec4e6e57001a2139902d62679efc55c32234'

GitHub 源码安装:首次需按提示配置 allowBuilds 构建授权后重试

For install and environment setup, plus plugin development tutorials, see DSH community docs ↗

README

Source README · body: zh · Read Chinese README

Table of contents
  1. 四个痛点
  2. 插件管理
  3. 功能
  4. 1. 用人话说明每个插件的作用
  5. 2. 来源徽章
  6. 3. 一键停用 / 启用
  7. 4. 安全卸载
  8. 5. 噪声过滤
  9. 技能管理
  10. 1. 每个技能标明「唯一可用的触发方式」
  11. 2. 两个真开关
  12. 3. 清理线索
  13. 4. 来源与升级对象
  14. 5. 没有「自动升级」按钮
  15. 安装
  16. 兼容性
  17. 自检与测试
  18. 已验证(全部为实测结果)
  19. 实现说明
  20. 权限与数据
  21. HTTP 接口
  22. 卸载本插件
  23. License

用人话看懂每个插件和技能是做什么的,一键停用/启用,安全卸载。

DeepSeek Harness 的「设置 → 插件」页是一份只读清单:它列出模块名,却不告诉你这个插件到底干什么用;想关掉一个插件,只能去手改 cordis.patch.yml。技能那边更糟 —— 装了 57 个技能,其中 14 个模型根本看不到,只能靠记住 /handoff 这类命令来用。

这个插件在同一个「插件」页里加一个插件管家标签页,分「插件」「技能」两段,补上这些事。

四个痛点

痛点 官方界面 插件管家
看不懂插件是做什么的 只显示英文模块名 中文名 + 一句话说明 + 来源徽章
关不掉 / 卸不掉插件 纯只读,「已启用」只是个标签 一键停用/启用(热生效)+ 卸载
不知道技能怎么用 模型目录与 / 菜单互不可见 每个技能标明唯一可用的触发方式
不知道技能怎么关 没有开关,只能手改 SKILL.md 两个真开关(模型自动加载 / / 命令),热生效

插件管理

功能

1. 用人话说明每个插件的作用

按质量优先级取说明:dshhub.summary → package.json 的 description → README.md 首段(自动剥离 Markdown / HTML、按语义边界截断)。

实测覆盖率(本机 168 个已安装包):dshhub 仅 1 个包使用,description 覆盖 164 个 —— 所以 description 才是主力,dshhub 是锦上添花。

2. 来源徽章

徽章 判定依据
官方 包名在 @deepseek-ai/ 命名空间下
社区 lockfile 里是普通 semver 版本号
GitHub 直装 lockfile specifier 为 github:owner/repo#tag
本地链接 specifier 为 file: / link:

判定读 pnpm-lock.yaml 的 importers 段,不看目录类型 —— 本环境用 nodeLinker: hoisted,真实目录并不代表来自 registry。

3. 一键停用 / 启用

走 Cordis 官方的 entry 更新通道 Entry.update({ disabled }):停用时 loader 会 await _dispose(fiber),该插件的工具、路由、监听立即注销;启用时重新 init() 装配。热生效,不需要重启。

选择会记在 ~/.dsh/plugin-manager.json,每次启动自动重放,所以重启后仍然保持你选的状态。

4. 安全卸载

  • 先快照 entry 的 options,再 loader.remove(),然后校验确实移除;若仍在,按快照 loader.create() 恢复原状。
  • 官方 @deepseek-ai/* 组件禁止卸载(卸载会破坏启动),UI 上按钮直接置灰,只允许停用。
  • 卸载后同样记入状态文件,重启不会自己装回来。

5. 噪声过滤

本机装了 168 个包,其中绝大多数是传递依赖,真正能管理的插件只有个位数。列表会自动剔除:

  • 非插件库(没有 dsh.bundle 的普通依赖)—— 实测过滤 154 个
  • 框架内部条目(cordis:include、node:* 等)—— 实测过滤 4 个

技能管理

插件管家页顶部有 插件 | 技能 分段控制。技能页复用同一套卡片语言。

1. 每个技能标明「唯一可用的触发方式」

技能的 invocation 策略有两个互相独立的维度,界面把它们翻译成一句人话:

模型自动加载 / 命令可用 界面直接告诉你
✓ ✓ 模型会自己调用;也可用 /name 手动唤起
✗ ✓ 模型看不到它 —— 只能用 /name 手动唤起
✓ ✗ 仅模型自动调用(/name 不可用)
✗ ✗ 已停用

第二行是本机 14 个技能的真实状态。它们在模型侧完全不存在,靠翻文件夹是发现不了的。

实测(本机 60 个技能):

模型看不到、只能用 / 唤起 = 14
两个开关都开的           = 46
来源:用户安装 57 / 插件提供 3

2. 两个真开关

不是「障眼法」:插件注册一个 rank 0 的影子 provider,把策略按需置 false。注册表按层合并、同层内 rank 升序取胜,而三个消费点都按策略过滤:

消费点 过滤 后果
tool-skill 模型目录 filter(isModelInvocable) 不进 <available_skills>
tool-skill 加载守卫 isModelInvocable skill 工具拒绝加载
session-controller 命令目录 filter(isUserInvocable) 不进 / 菜单

关键实现细节:这些技能住在 agent preset 作用域,不在全局层。而服务读取走 topology-sensitive 属性代理 —— ctx.skills(声明式注入)返回绑定到访问上下文的反射,ctx.get('skills') 读的是全局存储。插件必须为每个 preset createScope 并走该作用域的 .skills 反射注册,否则候选会被更近的层直接盖掉。这一步不需要修改任何预设文件(shipped 与用户预设一并覆盖)。

3. 清理线索

标记 实测数量 判定依据
目录内有不生效的 SKILL.md 40 加载器只认 <技能名>/SKILL.md,segments.length > 2 一律忽略
目录内混入非技能文件 2 根目录出现 package.json / package-lock.json 等
缺少描述 0 模型与命令菜单都无法判断用途

嵌套那份不只是冗余 —— 抽样确认它与生效那份内容不同(brainstorming 10047 vs 15456 字节)。

4. 来源与升级对象

从指令文件路径反解归属:

  • 路径含 node_modules/<pkg>/ → 「插件提供 · 升级对象 <pkg> v<version>」
  • 路径在 ~/.agents/skills/ 或 ~/.dsh/skills/ 下 → 「用户安装」

source 字段在本部署不可信:host 进程 cwd 是家目录,预设把用户根报成 project-agents。所以分类以路径为准。

5. 没有「自动升级」按钮

实测本机 57 个技能:0 个是 git 仓库、无清单、无安装元数据(~/.agents/plugins/marketplace.json 与技能无关,它只有一条指向不存在路径的条目)。通用自动升级路径不存在,因此不提供按钮 —— 只标注该升级什么。


安装

dsh plugin --profile web add "github:Amouren7/dsh-plugin-desk#v0.2.1"

装完重启 dsh web,然后打开 设置 → 插件 → 插件管家。

页面是懒加载的,浏览器可能缓存旧前端;若看不到新标签页,按 Ctrl+Shift+R 强制刷新。

暂未发布到 npm:dsh-plugin-manager / dsh-plugin-hub / dsh-plugin-console 三个相近名字均已被他人占用, 因此先用 GitHub 源码安装。本包名 dsh-plugin-desk 在 npm 上是可用的。

兼容性

项 值
DSH >=0.1.5-rc.1(依赖 0.1.5 的 settings.plugins.tab 插槽)
Node >=20
Profile web
实测环境 Windows 11 · DSH 0.1.5-rc.1 · Node 24.18.1

技能功能需要部署提供 skills 与 agentPresets 服务,以及可解析的 @deepseek-ai/dsh-scope;缺任一项时技能开关会如实拒绝并在界面说明原因,插件页其余功能不受影响。

@deepseek-ai/dsh-scope 从两个解析根依次尝试:profile 根(<DSH_HOME>/profiles/)与 DSH 自身的安装根。任一可用即可,因为预设作用域覆盖要靠它建立;两个都不可用时才会降级,且失败信息会列出实际找过的路径。

自检与测试

node scripts/selftest.mjs   # 离线复验插件元数据链路(不启动 loader)
npm test                    # 22 项单元测试:路由自愈 / 客户端错误硬化 / 技能派生 / 作用域解析 / apply 冒烟

技能功能的端到端实测记录见 tests/acceptance.md(含未验证项的如实标注)。

已验证(全部为实测结果)

界面(设置 → 插件 → 插件管家):

验证项 结果
标签页接入 与官方 插件配置/插件列表 并列出现,官方页面 data-slot-error 为空
插件卡片 5 张卡片,名称/说明/来源徽章/版本/状态齐全
噪声过滤 168 个已安装包 → 只保留 5 个真插件,过滤 154 个非插件依赖 + 4 个框架内部条目
分段控制 `插件
技能卡片 60 张,含作用、whenToUse、来源、指令文件路径、用法提示
技能开关 60/60 可开关;写入后赢得该名字的 provider 变成本插件
界面一键停用 点「停用」→ fiber 已 dispose,徽章变「已停用」,按钮变「启用」
界面一键启用 点「启用」→ fiber 重新装配完成,徽章回「运行中」
状态持久化 ~/.dsh/plugin-manager.json / ~/.dsh/plugin-desk-skills.json 落盘,启动时重放

系统级验证技能停用真的生效(由 harness 自身确认,非插件自证):

动作 本会话 <available_skills> 目录的变化
设 brainstorming 模型自动加载 = 关 brainstorming 消失
恢复默认 回来
设 grilling 模型自动加载 = 关 grilling 消失
恢复默认 回来

覆盖跨插件重载存活(开机即装,非懒装)。

宿主能力(HTTP 接口层):

验证项 结果
元数据解析 5 个插件全部解析出中文名与说明;来源判定 github/community/linked/official 全部正确
安全卸载 移除 → 校验确认 → 该插件路由端点随之失效(证明真 dispose)→ 记忆落盘
官方组件保护 @deepseek-ai/* 卸载被拒,只允许停用
技能盘点完整性 60 个技能;与独立文件系统扫描(57 个目录 / 14 个模型不可见)逐项吻合
预设作用域安装 连续三次读取 installed=[standard,ptc,minimal,cordis] 稳定不变
解析根回退 人为移除 profile 根的 @deepseek-ai/dsh-scope 后:旧代码 installed=[] 且报「不可解析」,新代码仍为 installed=[standard,ptc,minimal,cordis];恢复后无差异

实现说明

  • 零构建:lib/*.js 既是源码也是产物,没有打包步骤,改完直接生效。
  • 文件职责:lib/index.js 插件清单与 API;lib/skills.js 技能盘点、派生函数与覆盖 provider;lib/skill-overrides.js 可按预设单独装配的入口;lib/client.js 前端。
  • 宿主侧零依赖:只用 Node 内置模块。技能作用域需要 @deepseek-ai/dsh-scope 时动态解析并 import(不是静态依赖,保住装配可移植性),并依次尝试 profile 根与 DSH 安装根两个解析根。
  • 前端模块信封:lib/client.js 按 DSH 的 client-modules 约定包成惰性 CJS 工厂(window.__ModuleLoader__.load({ id, factory })),模块体在首次物化时才执行。
  • React 取自 shell 的冻结模块表:require('react') 即可,无需 import;但必须在模块作用域解析一次,放进组件体内会在渲染期炸掉整个 section。详见 docs/SLOT-CONTRACT.md。
  • 注册值是函数组件:SlotComponent<P> = (props) => ReactNode。返回 DOM 节点或 { render() } 对象会被 React 拒绝,并让官方插件页变成空白。
  • 持久化为什么不写 patch 层:bundle 装配会用自己的 id 组合出同名条目,patch 层的 disabled: 条目并不能可靠阻断它。因此状态由本插件自管,启动时重放。

权限与数据

项 说明
读取 profile 的 node_modules(仅 package.json / README.md)、pnpm-lock.yaml、运行中的 loader 条目、技能注册表、技能指令文件所在目录(判断清理标记)
写入 ~/.dsh/plugin-manager.json(插件停用/卸载记忆)、~/.dsh/plugin-desk-skills.json(技能开关覆盖)
网络 无
凭据 不读写

技能开关不修改任何 SKILL.md:状态由影子 provider 覆盖,删掉状态文件即完全复原。

HTTP 接口

界面之外,宿主能力也可直接调用:

方法 路径 说明
GET /dsh-plugin-desk/api/list 插件清单(含中文名、说明、来源、状态)
POST /dsh-plugin-desk/api/toggle { entryId, enabled } 热启停
POST /dsh-plugin-desk/api/uninstall { entryId } 安全卸载
GET /dsh-plugin-desk/api/skills 技能清单(含用法提示、来源、清理标记、presetInstall 诊断)
POST /dsh-plugin-desk/api/skills/toggle { name, model?, user? } 设置技能开关
POST /dsh-plugin-desk/api/skills/reset { name } 恢复该技能的默认策略

卸载本插件

dsh plugin --profile web remove dsh-plugin-desk

状态文件 ~/.dsh/plugin-manager.json 与 ~/.dsh/plugin-desk-skills.json 会保留;若不再需要,可自行删除。删除技能状态文件后,所有技能立即回到默认策略。

License

MIT