统一管理专家库,在会话输入框旁一键切换挂载
29.9/100
综合分
0
GitHub 星标
—
npm 周下载
—/5
用户评分
数据截至 2026/10/19 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。
安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add Aliboder/dsh-expert-hub该包不可直接 npm 安装,改从 GitHub 源安装(明细见下方安装检查)
状态速览
判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态信任档位:待复验
是什么
dsh 原生插件 · market
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
活跃:最近一次提交在 17 天前
档位由哪些信号合成
本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。
社区实装还没有人打卡 · 装过的第一个就是你
安全扫描自动 · 静态分析源码v2.7.0🔵 扫描:含敏感能力尚无人工评估展开查看扫描说明与证据 ↓
安全扫描自动 · 静态分析源码
v2.7.0静态扫描发现插件具备触达本地系统的能力:执行外部命令、读写/删除本地文件、读取剪贴板或密钥类环境变量(至少其一)。这是能力清单,不是危险判定——具体能力项与证据见下方,安装前请自行判断是否需要。
读写/删除本地文件写入剪贴板(不计风险)发起外部网络请求
查看扫描证据(共 105 处,展示前 71 条)
- 发起网络请求client.js:1222
return fetch(path, init).then(function (response) { - 写入剪贴板client.js:4295
navigator.clipboard.writeText(template).then(markCopied, function () { - 读取本地文件src/paths.js:108
start = await realpath(resolve(cwd)) - 读取本地文件src/paths.js:109
if (!(await stat(start)).isDirectory()) return undefined - 读取本地文件src/paths.js:116
await lstat(join(current, '.git')) - 读取本地文件src/routes.js:205
const data = await readFile(file.path) - 读取本地文件src/selections.js:47
state = normalizeState(JSON.parse(await readFile(stateFile, 'utf8'))) - 写入本地文件src/selections.js:58
await mkdir(dirname(stateFile), { recursive: true }) - 写入本地文件src/selections.js:60
await writeFile(tmp, `${JSON.stringify(snapshot, null, 2)}\n`, { encoding: 'utf8', mode: 0o600 }) - 写入本地文件src/selections.js:61
await rename(tmp, stateFile) - 读取本地文件src/workbuddy.js:82
return JSON.parse(normalizeText(await readFile(path, 'utf8'))) - 读取本地文件src/workbuddy.js:91
return normalizeText(await readFile(path, 'utf8')) - 读取本地文件src/workbuddy.js:100
return (await stat(path)).isFile() - 读取本地文件src/workbuddy.js:110
entries = await readdir(dir, { withFileTypes: true }) - 读取本地文件src/workbuddy.js:415
entries = await readdir(root, { withFileTypes: true }) - 写入本地文件src/store.js:73
await mkdir(paths.expertsRoot, { recursive: true }) - 读取本地文件src/store.js:79
const parsed = JSON.parse(normalizeText(await readFile(join(dir, MANIFEST), 'utf8'))) - 读取本地文件src/store.js:91
if ((await stat(join(dir, name))).isFile()) return { path: join(dir, name), ext: `.${name.split('.').pop()}` } - 写入本地文件src/store.js:104
await mkdir(join(targetRoot, 'skills'), { recursive: true }) - 删除本地文件递归src/store.js:105
await rm(target, { recursive: true, force: true }) - 写入本地文件src/store.js:111
await mkdir(target, { recursive: true }) - 写入本地文件src/store.js:112
await writeFile(join(target, 'SKILL.md'), `${normalizeText(skill.content)}\n`, { - 读取本地文件src/store.js:136
exists = (await stat(dir)).isDirectory() - 删除本地文件递归src/store.js:149
await rm(staging, { recursive: true, force: true }) - 写入本地文件src/store.js:150
await mkdir(staging, { recursive: true }) - 写入本地文件src/store.js:153
await writeFile(join(staging, 'expert.yml'), serializeExpertYml(meta), { encoding: 'utf8', mode: 0o600 }) - 删除本地文件递归src/store.js:183
await rm(dir, { recursive: true, force: true }) - 删除本地文件递归src/store.js:187
await rm(staging, { recursive: true, force: true }).catch(() => {}) - 删除本地文件递归src/store.js:210
await rm(dir, { recursive: true, force: true }) - 读取本地文件src/store.js:218
return normalizeText(await readFile(path, 'utf8')) - 读取本地文件src/store.js:304
entries = await readdir(paths.expertsRoot, { withFileTypes: true }) - 读取本地文件src/store.js:402
sourceExists = (await stat(paths.sourceDir)).isDirectory() - 读取本地文件src/skill-sources.js:69
return (await stat(path)).isDirectory() - 读取本地文件src/skill-sources.js:78
return (await stat(path)).isFile() - 读取本地文件src/skill-sources.js:164
entries = await readdir(home, { withFileTypes: true }) - 读取本地文件src/skill-sources.js:186
entries = await readdir(configDir, { withFileTypes: true }) - 读取本地文件src/skill-sources.js:204
real = await realpath(dir) - 读取本地文件src/skill-sources.js:249
entries = await readdir(root.path, { withFileTypes: true }) - 写入本地文件src/author.js:156
await writeFile(temp, data, { mode: 0o600, ...options }) - 写入本地文件src/author.js:157
await rename(temp, filePath) - 删除本地文件src/author.js:161
await rm(temp, { force: true }).catch(() => {}) - 写入本地文件src/author.js:178
await mkdir(dir) - 读取本地文件src/author.js:192
entries = await readdir(dir, { withFileTypes: true }) - 删除本地文件src/author.js:200
await rm(join(dir, entry.name), { force: true }).catch(() => {}) - 读取本地文件src/author.js:258
await stat(absolute) - 写入本地文件src/author.js:293
await writeFile(join(dir, 'expert.yml'), serializeExpertYml(meta), { encoding: 'utf8', mode: 0o600 }) - 写入本地文件src/author.js:294
await writeFile(join(dir, 'role.md'), `${roleText}\n`, { encoding: 'utf8', mode: 0o600 }) - 写入本地文件src/author.js:296
await writeFile(join(dir, `avatar${avatar.ext}`), avatar.data, { mode: 0o600 }) - 删除本地文件递归src/author.js:310
await rm(dir, { recursive: true, force: true }).catch(() => {}) - 删除本地文件递归src/author.js:318
await rm(dir, { recursive: true, force: true }).catch(() => {}) - 读取本地文件src/author.js:364
const existing = await readdir(skillsDir, { withFileTypes: true }).catch(() => []) - 删除本地文件递归src/author.js:368
await rm(join(skillsDir, entry.name), { recursive: true, force: true }) - 读取本地文件src/author.js:380
const text = normalizeText(await readFile(file, 'utf8')) - 读取本地文件src/author.js:420
info = await stat(source) - 删除本地文件递归src/author.js:431
await rm(target, { recursive: true, force: true }) - 读取本地文件src/author.js:439
const content = await readFile(source, 'utf8') - 读取本地文件src/fingerprint.js:32
listed = await readdir(current, { withFileTypes: true }) - 读取本地文件src/fingerprint.js:45
const info = await stat(path) - 写入本地文件src/importers.js:316
await mkdir(base, { recursive: true }) - 删除本地文件递归src/importers.js:326
await rm(dir, { recursive: true, force: true }).catch(() => {}) - 删除本地文件递归src/importers.js:339
await rm(dir, { recursive: true, force: true }).catch(() => {}) - 删除本地文件递归src/importers.js:366
await rm(dir, { recursive: true, force: true }).catch(() => {}) - 写入本地文件src/importers.js:465
await mkdir(root, { recursive: true }) - 写入本地文件src/importers.js:529
await mkdir(entry.destination, { recursive: true }).catch((error) => { - 写入本地文件src/importers.js:570
await mkdir(dirname(entry.destination), { recursive: true }) - 写入本地文件src/importers.js:571
await writeFile(entry.destination, content, { mode: 0o600 }) - 写入本地文件src/importers.js:638
await mkdir(root, { recursive: true }) - 删除本地文件递归src/importers.js:834
await rm(dir, { recursive: true, force: true }).catch(() => {}) - 读取本地文件src/importers.js:857
info = await stat(absolute) - 读取本地文件src/importers.js:887
const bytes = await readFile(absolute) - 删除本地文件递归src/importers.js:934
await rm(dir, { recursive: true, force: true }).catch(() => {})
扫描于 2026/11/3(0 天前) · 范围 入口闭包 + 发布文件清单 · 来源 GitHub 仓库
静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。
给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个
DSH 专家中心:WorkBuddy 市场、AI 创建专家、详情即编辑、技能管理、按会话切换
README
由 DeepSeek 最新模型翻译生成DSH Expert Hub · 专家中心
把 WorkBuddy 专家、自建专家、网上导入的专家统一收进 DSH 的同一个专家库,在设置页里像应用商店一样浏览、导入、编辑,在会话输入框旁一键切换。
这是 DeepSeek Harness(DSH)的社区插件,不是 DeepSeek 官方产品。
它解决什么
旧版 WorkBuddy 专家插件只能「只读扫描 → 逐个安装 → 再去输入框旁选择」,看不到专家详情、不能新建、不能编辑、不能从网上导入。Expert Hub 重新实现了整条链路:
| 能力 | 说明 |
| WorkBuddy 专家市场 | 读取本机 WorkBuddy 已落盘的专家(.codebuddy-plugin/plugin.json + agents/.md),展示头像、职业、分类、技能,一键导入/更新/全部导入 |
| AI 创建专家 | 用自然语言描述你要的专家,AI 先读《DSH 专家创作规范》,再生成 role.md 与必要的技能并写入专家库 |
| AI 代为导入 | 把专家链接、网页内容或一段介绍直接发给 AI,由 AI 读取并整理成专家条目后写入;不再需要填网址、找下载链接 |
| 对话内管理 | 直接在会话里说「改一下某专家的提示词 / 加个技能 / 从目录导入技能 / 让我用某专家」,由 expert_manage 工具完成 |
展开完整文档(README 剩余 1 节)
DSH Expert Hub · 专家中心
把 WorkBuddy 专家、自建专家、网上导入的专家统一收进 DSH 的同一个专家库,在设置页里像应用商店一样浏览、导入、编辑,在会话输入框旁一键切换。
这是 DeepSeek Harness(DSH)的社区插件,不是 DeepSeek 官方产品。
它解决什么
旧版 WorkBuddy 专家插件只能「只读扫描 → 逐个安装 → 再去输入框旁选择」,看不到专家详情、不能新建、不能编辑、不能从网上导入。Expert Hub 重新实现了整条链路:
| 能力 | 说明 |
| WorkBuddy 专家市场 | 读取本机 WorkBuddy 已落盘的专家(.codebuddy-plugin/plugin.json + agents/.md),展示头像、职业、分类、技能,一键导入/更新/全部导入 |
| AI 创建专家 | 用自然语言描述你要的专家,AI 先读《DSH 专家创作规范》,再生成 role.md 与必要的技能并写入专家库 |
| AI 代为导入 | 把专家链接、网页内容或一段介绍直接发给 AI,由 AI 读取并整理成专家条目后写入;不再需要填网址、找下载链接 |
| 对话内管理 | 直接在会话里说「改一下某专家的提示词 / 加个技能 / 从目录导入技能 / 让我用某专家」,由 expert_manage 工具完成 |
| 详情即编辑 | 卡片只有「详情」一个入口;打开后头像、名称、职业、role.md、技能在同一页面编辑,点「保存修改」生效 |
| 迁移专家 | 详情页可把全局专家整体迁移到某个项目,或把项目专家迁回全局;也可在对话里让 agent 调用 expert_manage 的 migrate 完成 |
| 项目级 / 全局专家 | 全局专家在 ~/.dsh/experts;项目专家在 <项目根>/.dsh/experts(随仓库走)。项目页顶部从 DSH 已登记工作区中选择,失效目录禁用;已安装页可按「全部 / 全局 / 项目」筛选,卡片带范围徽章;会话胶囊里也分组展示 |
| 技能管理 | 技能卡片式列表,可新增/编辑/删除,也可从本机技能目录一键导入 |
| 删除与回收站 | 卡片可直接删除(软删除到回收站);回收站可恢复或永久删除 |
| 会话内切换 | 输入框旁的专家胶囊:头像 + 搜索 + 当前标记,按 2 列网格分组展示全局/项目专家,选中即挂载「角色提示词 + 全部 skills」;「不用专家」随时退出 |
| 选择可恢复 | 选择按会话持久化,DSH 重启或会话恢复后自动重新挂载 |
| 实时刷新 | 专家库或 WorkBuddy 来源变化时,打开的下拉/页面通过 SSE 自动更新 |
界面
| 专家中心(设置 → 专家中心) | WorkBuddy 市场 |
| 已安装 | 市场 |
| 专家档案(详情 + 编辑合并) | 会话输入框旁的专家胶囊 |
| 专家档案 | 胶囊 |
安装
桌面端(推荐):侧栏 插件 → 添加插件,输入 npm 包名 dsh-expert-hub,安装后重启桌面 App。
终端:
dsh plugin --profile web add dsh-expert-hub
也可以从源码目录安装(开发调试):
dsh plugin --profile web add D:\SystemFiles\Documents\Project\DSH\plugins\dsh-expert-hub
安装后重启宿主(bundles 只在启动时读取),浏览器强刷。
使用
专家中心(设置 → 专家中心)
- 已安装:专家卡片墙,支持搜索、分类筛选、排序;每张卡片可直接「详情」或「删除」(删除前二次确认,删除是软删除,移入回收站)。详情与编辑合并成「专家档案」页:头像、名称、职业、role.md 和技能都在一个页面里改,点「保存修改」生效;技能可增删改或从目录导入。
- 回收站:列出软删除的专家,可「恢复」或「永久删除」(永久删除需二次确认,删除后不可恢复)。
- WorkBuddy 市场:本机 WorkBuddy 里已「召唤」的专家。首次使用需在 WorkBuddy 专家中心点击「召唤」,专家落盘到 ~/.workbuddy/plugins/marketplaces/experts/plugins 后这里就能看到。
支持单个导入、批量导入、发现源更新后的「更新」。
- AI 添加:页面只保留「让 AI 帮我创建专家」一条路——描述需求,AI 按《DSH 专家创作规范》生成 role.md 与必要的技能并写入;不再有手动填表或本机路径导入。
AI 创建专家(推荐)
在任意会话里直接用自然语言描述即可:
创建一个「周报助手」:帮我整理零散工作记录,输出 Markdown 周报表格,语气简洁,再加一个“周报检查清单”技能。
AI 会先调用 expert_manage({action:'guide'}) 读取创作规范(身份 / 工作流程 / 输出格式 / 质量检查 / 边界;技能只在确有可复用流程时创建),再调用 expert_manage({action:'create'}) 写入;需要的话可以用 activate:true 立即在当前会话启用。
AI 代为导入(外部来源)
不需要再走「填网址 → 下载 → 解压 → 导入」的流程。在任意会话里直接把来源发给 AI 即可:
帮我导入这个专家:https://example.com/some-expert
把下面这段专家介绍整理成一位专家并导入: AI 的处理流程:
1. 读取:网页正文用 web_fetch 读取;专家压缩包、本机目录、单个 .md 交给插件读取;
2. 整理:归一成一位专家的完整条目——中文显示名、职业/称号、role.md 角色提示词(必要时附技能正文);
3. 写入:调用 expert_import({expert:{…}}) 写入 ~/.dsh/experts/<id>/,并给出来源记录;
4. 选用(可选):用户说「导入并直接用」时传 activate: true,立刻在当前会话启用。
来源里有多位专家时,AI 会先问你要导入哪几位,再逐个写入;已有的同名专家不会被覆盖,会自动改用 -2 后缀。
对话内管理专家
除了设置页,也可以直接让智能体改专家: text 列出专家库里有哪些专家看看「电脑管家」的角色提示词把「电脑管家」的职业改成“硬件工程师”,角色提示词里加上二手配件避坑给「像素君」加一个技能:设计评审清单,内容是……
从 D:\skills\my-skill 导入技能到「像素君」让我用「码小序」
对应模型工具 expert_manage,支持 list / get / create / update / add_skill / remove_skill / import_skill / use。
删除专家仍只在设置页操作,避免对话里误删。
需要用项目级专家时,让 AI 带 library="project",例如: text 给这个项目建一个「本仓库代码评审」专家,用项目级把当前项目的「接口约定」专家角色提示词补上错误码规范
项目根目录优先使用 DSH 工作区注册表里当前会话所属的 workspace;找不到时退回「最近的包含 .git 的祖先目录」,再退回当前工作目录。项目专家存于 <项目根>/.dsh/experts;全局专家仍存于 ~/.dsh/experts。
项目页顶部可以从所有已登记工作区里切换查看,目录失效的工作区会禁用。
会话内切换
输入框左侧的专家胶囊会显示当前专家头像与名字(未选择时显示「专家」)。点开后:
- 搜索已安装专家,点选即切换,当前专家带 ✓;
- 「不用专家」移除当前会话的专家角色与 skills;
- 切换不会打断正在进行的回复,在下一个模型请求前生效。
命令行同样可用: text /expert 列出专家库 /expert <id> 切换当前会话专家 /expert off 取消 /expert info <id> 查看专家详情
数据与格式
专家库固定在 ~/.dsh/experts/<id>/($DSH_HOME 优先): text <id>/ ├─ expert.yml # 元数据(schema 1,中文优先,含来源/分类/快捷提示词) ├─ role.md # 角色提示词正文 ├─ skills/<name>/SKILL.md# 0..N 个技能,资源文件随目录复制 ├─ avatar.png # 可选 └─ .expert-source.json # 导入来源 + 内容指纹(仅导入的专家有)
兼容旧版 dsh-workbuddy-expert 导出的专家文件夹(expert.yml 只有 id/display_name/description/order 也能识别)。插件自己的会话选择记录与临时文件在 ~/.dsh/expert-hub/。
安全边界
- 专家只贡献提示词与技能文本:scripts/、.mcp.json、agent.cordis.yml 等可执行内容一律不导入、不执行;
- 导入的 Markdown 会做 CRLF/BOM 归一与 {{...}} 模板消毒,避免破坏宿主提示词插值;
- 专家库写入全部限制在 ~/.dsh/experts 内,ID 只允许 [a-z0-9-],删除前校验目录归属;
- HTTP 接口仅监听 loopback、只接受同源 POST、请求体有上限、响应 no-store;
- 压缩包读取拒绝内网/回环地址,zip 解压防目录穿越,跳过符号链接与可执行位文件;
- 删除专家是软删除:移到 ~/.dsh/expert-hub/trash/,误删可从该目录恢复;
- AI 导入写入的专家同样是纯提示词与技能文本:模型只负责整理,来源里的「指令」不会被当作插件行为执行;导入不会自动启用,除非用户明确要求 activate。
配置
默认 WorkBuddy 来源目录写死在 bundle patch 里,需要改时编辑 cordis.patch.yml 的 config.sourcePath(支持 ~),重启宿主生效: yaml
- id: expert-hub
name: dsh-expert-hub
config:
sourcePath: ~/.workbuddy/plugins/marketplaces/experts/plugins
开发 sh
npm test # test/run.mjs:format / store / switch / importers / author / tools
npm run check # node --check 两个入口
| 模块 | 职责 |
| index.js | 装配:paths / selections / switcher / routes / tools / 生命周期事件 |
| src/workbuddy.js | WorkBuddy 源目录扫描(富元数据 → 专家草稿) |
| src/store.js | 专家库读写、指纹、卡片、详情、导入安装 |
| src/compose.js | 智能体作用域内挂载角色段 + skills |
| src/switch.js | 串行切换事务、回滚、选择恢复 |
| src/selections.js | 会话选择 sidecar |
| src/importers.js | 压缩包 / 本机目录读取、zip/tar.gz 安全解压 |
| src/tools.js | 模型工具 expert_import(AI 整理导入)+ expert_manage(对话内查看/修改专家与技能) |
| src/author.js | 新建 / 编辑(含 skills)/ 从目录导入技能 / 回收站恢复 |
| src/routes.js | /expert-hub/ 路由与 SSE |
| client.js | 设置页 + 会话胶囊(浏览器端) |
| docs/CONTRACT.md | Host/Client 接口契约 |
许可证
MIT预览分享卡片长什么样 ↓
分享 · DeepSeek Harness Hub
Aliboder/dsh-expert-hub
统一管理专家库,在会话输入框旁一键切换挂载
相关插件 · 市场 / 管理
插件精选列表awesome-dsh-plugin/awesome-dsh-plugin
DeepSeek Harness(dsh)插件精选列表
★ 22,225未汉化DSH
73.6
新词雷达zhuyansen/new-term-radar
new-term-radar新词雷达
★ 2,049已汉化MCP
72.8
插件生态导航0xsline/awesome-deepseek-harness
安装 贡献指南 DeepSeek Docs 公开插件目录 Issues
★ 1,188已汉化DSH
72.6
技能注册中心iflytek/skillhub
企业级开源智能体技能注册中心——发布、发现并管理组织内可复用的技能包。
★ 5,370已汉化DSH
71.9
插件市场目录imsai-sh/awesome-deepseek-harness-plugins
面向 DeepSeek Harnessdsh生态的社区插件目录,共收录 13941 个插件含 PR 收录与…
★ 355已汉化DSH
71.8
插件精选清单Anil-matcha/awesome-dsh-plugin
DeepSeek Harnessdsh精选指南——DeepSeek…
★ 1,013已汉化DSH
71.7
这是你的仓库?认领条目