科研技能中心 for DeepSeek Harness:技能目录、分类、按会话启用门控,以及用户可调用的…
30.5/100
综合分
1
GitHub 星标
—
npm 周下载
—/5
用户评分
数据截至 2026/10/13 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。
安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add kee0012/dsh-science-skill该包不可直接 npm 安装,改从 GitHub 源安装(明细见下方安装检查)
状态速览
判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态信任档位:待复验
是什么
dsh 原生插件 · skill
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
活跃:最近一次提交在 22 天前
档位由哪些信号合成
本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。
社区实装还没有人打卡 · 装过的第一个就是你
安全扫描自动 · 静态分析源码v2.7.0🔵 扫描:含敏感能力尚无人工评估展开查看扫描说明与证据 ↓
安全扫描自动 · 静态分析源码
v2.7.0静态扫描发现插件具备触达本地系统的能力:执行外部命令、读写/删除本地文件、读取剪贴板或密钥类环境变量(至少其一)。这是能力清单,不是危险判定——具体能力项与证据见下方,安装前请自行判断是否需要。
读写/删除本地文件发起外部网络请求
查看扫描证据(共 110 处,展示前 79 条)
- 读取本地文件lib/index.js:240
if (!existsSync(gatePath)) { - 读取本地文件lib/index.js:245
const entries = JSON.parse(readFileSync(gatePath, 'utf8'))?.pinned ?? {} - 写入本地文件lib/index.js:261
mkdirSync(dirname(gatePath), { recursive: true }) - 写入本地文件lib/index.js:262
writeFileSync(gatePath, JSON.stringify({ pinned: on }, null, 2) + '\n') - 读取本地文件lib/index.js:401
return JSON.parse(readFileSync(join(paths.dataDir, `${id}.json`), 'utf8')) - 读取本地文件lib/index.js:442
text = readFileSync(file, 'utf8') - 读取本地文件lib/index.js:492
const record = JSON.parse(readFileSync(dataPath, 'utf8')) - 写入本地文件lib/index.js:506
writeFileSync(dataPath, JSON.stringify(record, null, 2) + '\n') - 读取本地文件lib/index.js:579
files = readdirSync(paths.dataDir) - 写入本地文件lib/index.js:766
writeFileSync(filePath, JSON.stringify(record, null, 2) + '\n') - 发起网络请求lib/client.js:225
await fetch(`${API_BASE}/skill-gate/session`, { - 发起网络请求lib/client.js:250
const data = await (await fetch(`${API_BASE}/skill-gate/state`, { cache: "no-store" })).json(); - 发起网络请求lib/client.js:264
const data = await (await fetch(`${API_BASE}/skill-gate/pin`, { - 发起网络请求lib/client.js:493
return await (await fetch(url, { - 发起网络请求lib/client.js:771
const data = await (await fetch(`${API_BASE}/skills/import`, { - 发起网络请求lib/client.js:834
const res = await fetch(`${API_BASE}/skills/refresh`, { - 读取本地文件lib/lib/catalog-runtime.mjs:40
if (!existsSync(dataDir)) return { ok: false, error: 'no catalog data dir' } - 读取本地文件lib/lib/catalog-runtime.mjs:42
let hasSchema = existsSync(join(catalogDir, 'schema.json')) - 读取本地文件lib/lib/catalog-runtime.mjs:43
if (!hasSchema && typeof bundledSchema === 'string' && existsSync(bundledSchema)) { - 读取本地文件lib/lib/catalog-runtime.mjs:47
writeFileSync(join(catalogDir, 'schema.json'), readFileSync(bundledSchema, 'utf8')) - 写入本地文件lib/lib/catalog-runtime.mjs:47
writeFileSync(join(catalogDir, 'schema.json'), readFileSync(bundledSchema, 'utf8')) - 读取本地文件lib/lib/catalog-runtime.mjs:57
for (const f of readdirSync(dataDir).filter((x) => x.endsWith('.json')).sort()) { - 读取本地文件lib/lib/catalog-runtime.mjs:59
try { record = JSON.parse(readFileSync(join(dataDir, f), 'utf8')) } catch { errors.push(`${f}: unparsable`); continue } - 写入本地文件lib/lib/catalog-runtime.mjs:103
writeFileSync(indexOut, JSON.stringify(index, null, 2) + '\n') - 读取本地文件lib/lib/categories-runtime.mjs:330
return JSON.parse(readFileSync(path, 'utf8').replace(/^ FEFF/, '')) - 读取本地文件lib/lib/categories-runtime.mjs:340
if (!existsSync(path)) return [] - 写入本地文件lib/lib/categories-runtime.mjs:359
mkdirSync(dirname(path), { recursive: true }) - 写入本地文件lib/lib/categories-runtime.mjs:367
writeFileSync(path, `${JSON.stringify(stored, null, 2)}\n`, 'utf8') - 读取本地文件lib/lib/categories-runtime.mjs:394
if (existsSync(legacyPath)) { - 删除本地文件lib/lib/categories-runtime.mjs:412
rmSync(legacyPath, { force: true }) - 读取本地文件lib/lib/import-settings.mjs:56
if (!existsSync(path)) return { defaultSkillDir: '' } - 读取本地文件lib/lib/import-settings.mjs:58
const parsed = JSON.parse(readFileSync(path, 'utf8').replace(/^ FEFF/, '')) - 写入本地文件lib/lib/import-settings.mjs:76
mkdirSync(dirname(path), { recursive: true }) - 写入本地文件lib/lib/import-settings.mjs:77
writeFileSync(path, JSON.stringify({ defaultSkillDir }, null, 2) + '\n') - 读取本地文件lib/lib/skill-naming.mjs:69
if (!existsSync(path)) return undefined - 读取本地文件lib/lib/skill-naming.mjs:72
text = readFileSync(path, 'utf8') - 读取本地文件lib/lib/skill-naming.mjs:234
text = readFileSync(join(root, '.credentials.yaml'), 'utf8') - 发起网络请求lib/lib/skill-naming.mjs:394
const response = await fetch(`${route.baseURL.replace(/ +$/u, '')}/chat/completions`, { - 读取本地文件lib/lib/skills-runtime.mjs:104
if (!existsSync(skillMd)) return { ok: false, error: '目录中没有 SKILL.md' } - 读取本地文件lib/lib/skills-runtime.mjs:106
try { md = readFileSync(skillMd, 'utf8') } catch { return { ok: false, error: 'SKILL.md 无法读取' } } - 删除本地文件递归lib/lib/skills-runtime.mjs:183
rmSync(staging, { recursive: true, force: true }) - 删除本地文件递归lib/lib/skills-runtime.mjs:190
rmSync(staging, { recursive: true, force: true }) - 读取本地文件lib/lib/skills-runtime.mjs:197
const finalExists = existsSync(finalTarget) - 读取本地文件lib/lib/skills-runtime.mjs:205
const adoptedExists = adoptedPath !== undefined && existsSync(adoptedPath) - 删除本地文件递归lib/lib/skills-runtime.mjs:207
rmSync(staging, { recursive: true, force: true }) - 写入本地文件lib/lib/skills-runtime.mjs:212
mkdirSync(installRoot, { recursive: true }) - 删除本地文件递归lib/lib/skills-runtime.mjs:213
rmSync(finalTarget, { recursive: true, force: true }) - 删除本地文件递归lib/lib/skills-runtime.mjs:214
if (adoptedPath !== undefined && adoptedPath !== finalTarget) rmSync(adoptedPath, { recursive: true, force: true }) - 写入本地文件lib/lib/skills-runtime.mjs:224
renameSync(staging, finalTarget) - 删除本地文件递归lib/lib/skills-runtime.mjs:229
rmSync(staging, { recursive: true, force: true }) - 写入本地文件lib/lib/skills-runtime.mjs:253
mkdirSync(dataDir, { recursive: true }) - 写入本地文件lib/lib/skills-runtime.mjs:254
writeFileSync(join(dataDir, `${finalId}.json`), JSON.stringify(record, null, 2) + '\n') - 读取本地文件lib/lib/skills-runtime.mjs:302
entries = readdirSync(dir, { withFileTypes: true }) - 读取本地文件lib/lib/skills-runtime.mjs:349
if (!existsSync(dataPath)) return undefined - 写入本地文件lib/lib/skills-runtime.mjs:390
mkdirSync(installRoot, { recursive: true }) - 写入本地文件lib/lib/skills-runtime.mjs:461
writeFileSync(dataPath, JSON.stringify(record, null, 2) + '\n') - 读取本地文件lib/lib/skill-acceptance.mjs:97
entries = readdirSync(dir, { withFileTypes: true }).map((entry) => entry.name) - 读取本地文件lib/lib/skill-acceptance.mjs:110
return { path, text: readFileSync(path, 'utf8').replace(/^ FEFF/, '') } - 读取本地文件lib/lib/skill-acceptance.mjs:211
entries = readdirSync(skillsDir, { withFileTypes: true }) - 读取本地文件lib/lib/skill-provider.mjs:95
entries = readdirSync(dir, { withFileTypes: true }) - 读取本地文件lib/root.mjs:79
return existsSync(bundledSchema) ? bundledSchema : undefined - 读取本地文件lib/lib/skill-frontmatter.mjs:217
return repairFrontmatterText(readFileSync(path, 'utf8')) - 读取本地文件lib/lib/skill-frontmatter.mjs:320
let body = readFileSync(path, 'utf8') - 写入本地文件lib/lib/skill-frontmatter.mjs:345
writeFileSync(temporary, body, 'utf8') - 写入本地文件lib/lib/skill-frontmatter.mjs:346
renameSync(temporary, path) - 写入本地文件lib/lib/skill-frontmatter.mjs:360
writeFileSync(temporary, plan.after, 'utf8') - 写入本地文件lib/lib/skill-frontmatter.mjs:361
renameSync(temporary, path) - 读取本地文件lib/lib/skills-migrate.mjs:31
if (statSync(pathA).size !== statSync(pathB).size) return false - 读取本地文件lib/lib/skills-migrate.mjs:32
return readFileSync(pathA, 'utf8') === readFileSync(pathB, 'utf8') - 读取本地文件lib/lib/skills-migrate.mjs:41
if (!existsSync(path)) return undefined - 读取本地文件lib/lib/skills-migrate.mjs:43
return JSON.parse(readFileSync(path, 'utf8').replace(/^ FEFF/, '')) - 读取本地文件lib/lib/skills-migrate.mjs:62
if (!existsSync(skillsDir)) return { renamed: [], conflicts: [] } - 读取本地文件lib/lib/skills-migrate.mjs:65
for (const entry of readdirSync(skillsDir, { withFileTypes: true })) { - 删除本地文件递归lib/lib/skills-migrate.mjs:77
rmSync(join(skillsDir, entry.name), { recursive: true, force: true }) - 删除本地文件lib/lib/skills-migrate.mjs:79
if (existsSync(staleRecord)) rmSync(staleRecord, { force: true }) - 写入本地文件lib/lib/skills-migrate.mjs:87
renameSync(join(skillsDir, entry.name), target) - 写入本地文件lib/lib/skills-migrate.mjs:97
mkdirSync(dataDir, { recursive: true }) - 写入本地文件lib/lib/skills-migrate.mjs:102
writeFileSync(join(dataDir, verdict.name + '.json'), JSON.stringify(moved, null, 2) + '\n', 'utf8') - 删除本地文件lib/lib/skills-migrate.mjs:104
rmSync(join(dataDir, entry.name + '.json'), { force: true })
扫描于 2026/11/1(0 天前) · 范围 入口闭包 + 发布文件清单 · 来源 GitHub 仓库
静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。
依赖的 DSH / Cordis 模块
@deepseek-ai/cordis@deepseek-ai/dsh-api-gateway@deepseek-ai/dsh-api-session-controller@deepseek-ai/dsh-client-locale@deepseek-ai/dsh-client-ui-conversation@deepseek-ai/dsh-client-ui-input-trigger@deepseek-ai/dsh-client-ui-renderer@deepseek-ai/dsh-client-ui-settings@deepseek-ai/dsh-client-ui-sidebar@deepseek-ai/dsh-client-ui-slots给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个
功能亮点
- 技能目录与分类
- 按会话启用门控
- 用户调用技能栏
README
由 DeepSeek 最新模型翻译生成dsh-science-skill
科研技能中心:把散落在磁盘上的技能,变成 DSH 里一面可浏览、可分类、可一键调用的技能墙。
这是一个 DeepSeek Harness 插件,不依赖 Science Agent。装上之后你会得到:技能设置面板、分类标签栏、卡片式技能墙、搜索、卡片内直接改分类、开关、导入与刷新,以及用 /命令 调用技能的能力。
功能特性
左侧栏入口与技能墙
- 侧栏注册一个「技能」入口,点开在本区展开技能墙:顶部是分类标签栏(分类多了会自动排到下一行),下面按 4 列铺开卡片。
- 卡片上有三个彼此独立的目标:点卡片正文打开该技能的详情弹窗;点右上角「召唤」才把它的 /命令 引用插入当前会话的输入框(不新建会话);点右下角带 ▾ 的分类标签能直接把技能换到别的分类,改完立即重排,设置面板里的同一个技能同步。
- 技能墙用官方 sidebar.panellist 一行入口 + main 一个面板实现。
技能详情与「试试这样用」
- 详情弹窗自上而下是:分类图标、中文名、/命令、「去试试」(等同召唤)、一句简介,然后是「试试这样用」——几条中文示例提问,点任意一条就把这句话插入当前会话的输入框,不会覆盖你后续的编辑。
- 最下面是「技能详情」:该技能 SKILL.md 的原文,等宽、限高、可滚动。
展开完整文档(README 剩余 1 节)
dsh-science-skill
科研技能中心:把散落在磁盘上的技能,变成 DSH 里一面可浏览、可分类、可一键调用的技能墙。
这是一个 DeepSeek Harness 插件,不依赖 Science Agent。装上之后你会得到:技能设置面板、分类标签栏、卡片式技能墙、搜索、卡片内直接改分类、开关、导入与刷新,以及用 /命令 调用技能的能力。
功能特性
左侧栏入口与技能墙
- 侧栏注册一个「技能」入口,点开在本区展开技能墙:顶部是分类标签栏(分类多了会自动排到下一行),下面按 4 列铺开卡片。
- 卡片上有三个彼此独立的目标:点卡片正文打开该技能的详情弹窗;点右上角「召唤」才把它的 /命令 引用插入当前会话的输入框(不新建会话);点右下角带 ▾ 的分类标签能直接把技能换到别的分类,改完立即重排,设置面板里的同一个技能同步。
- 技能墙用官方 sidebar.panellist 一行入口 + main 一个面板实现。
技能详情与「试试这样用」
- 详情弹窗自上而下是:分类图标、中文名、/命令、「去试试」(等同召唤)、一句简介,然后是「试试这样用」——几条中文示例提问,点任意一条就把这句话插入当前会话的输入框,不会覆盖你后续的编辑。
- 最下面是「技能详情」:该技能 SKILL.md 的原文,等宽、限高、可滚动。
- 中文名、中文简介、分类与示例由你在 DSH 里的默认对话模型在同一次调用里一并生成,不需要给插件单独配模型;模型偶尔没给出示例时只降级为空数组,中文名与分类照常保留。
分类管理与开关
- 分类可创建、改名、删除、排序、恢复默认,并可按名称推荐图标。
- 每个技能可单独开关,开关状态持久化在数据根下。
导入与刷新
- 导入技能目录、校验一个目录能否导入、刷新重新扫描,都在设置面板里完成。
- 重复导入直接覆盖:被替换的旧文件夹直接删除,不再保留任何备份——你选中的那个文件夹就是要用的版本;你在面板里改过的中文名、分类与示例留在记录上,SKILL.md 换成新的。
- 2.0.5 之前的版本会把被替换的文件夹留成 .<id>.old-<时间戳> 备份。旧备份一旦被发现,工具条上会出现「清理旧版本(N)」按钮;点一下就把这些残留删除。重新导入同一个技能时,它自己的旧备份也会顺带清掉。
- 桌面版与 dsh web 都可用。
安装
插件托管在 GitHub(kee0012/dsh-science-skill,未发布到 npm),DSH 支持以 git 依赖方式直接安装:
从 GitHub 安装(推荐,日常使用;拉取默认分支最新提交)
dsh plugin --profile desktop add github:kee0012/dsh-science-skill
安装后需要重启 DSH,新的服务端代码与 client bundle 才会生效。
使用
导入技能
1. 打开 设置 → Science Skill,在「技能默认目录」里指定一个目录(只接受绝对路径,留空=未设置)。
2. 点「+ 添加目录」选择要导入的技能文件夹,确认分类即可。指定了默认目录时,导入的技能一律装到那里;未指定则回落到数据根下的 skills。
3. 技能已经躺在目录里但没被登记?点「刷新」重新扫描:插件会把它们登记进目录记录,并为从未命名过的技能生成中文名、中文简介与示例。
技能目录要求
- 每个技能是一个子目录,内含 SKILL.md。
- SKILL.md 的 frontmatter 必须有 name: 与 description:;name 要能当 kebab-case 标识用(小写字母、数字、单连字符)。
- 子目录名可以随便起,不要求等于 name——不合规的目录名用 frontmatter 的 name 当记录标识,插件不重命名、不移动你的文件夹。
调用技能
- 在技能墙上点卡片的「召唤」,或打开详情弹窗点「去试试」,该技能的 /命令 引用就会被插入当前会话的输入框,回车发送即可。
- 也可以直接在输入框里敲 / 加技能标识调用。
技能目录规则与数据存放
技能根如何解析
- 只加载你在「技能默认目录」里设定的那一个目录,可以用 skillDirs 配置追加额外的根。
- 未设定时回落到 <dataRoot>/skills,以及 $DSH_AGENTS_HOME(缺省 ~/.agents)下的 skills。
- 插件同时以提供者身份接入内核技能注册表,把暴露的目录限定为你选定的那一个,因此面板上显示的技能就是模型能加载的技能;内核没有这个注册表时插件照常工作,只是退化为「仅面板可见」。
登记规则
- 目录名本身合规时,直接用它当记录标识(/命令 另按 frontmatter 的 name 走)。
- 目录名不合规(带大写、空格、点、中文)时,用 frontmatter 的 name 当记录标识,并记住真实文件夹名。
- 两个文件夹声明了同一个 name 时,先扫到的收录,后一个跳过并说明「技能标识已被占用」。
- 点号开头的子目录视为导入残留,一律忽略;既没有合规目录名、SKILL.md 里也没有合规 name 的文件夹会被跳过并给出原因。
- 不再被扫描的旧记录会被排除出索引,但记录文件保留——把默认目录指回去就回来了。
不动你的文件
- 登记只写数据根下的记录,不复制、不修改、不删除技能目录里的任何东西;已有记录也原样保留(只增不改)。
数据放在哪里
数据根按顺序解析:插件配置的 dataRoot(相对路径按 process.cwd() 解析)→ $DSH_HOME → ~/.dsh。数据根下会用到:
| 路径 | 作用 |
| catalog/data/<id>.json | 每个技能一条元数据(中文名、简介、分类、命令、示例提问) |
| catalog/index.json | 聚合索引,面板读它 |
| catalog/categories.json | 分类表,数组顺序就是面板顺序 |
| catalog/schema.json | 记录结构校验;缺失时从插件自带 schema 播种一次 |
| skill-gate.json | 全局技能开关({"pinned": {"<name>": true}}) |
| skill-import.json | 技能默认目录({"defaultSkillDir": "<绝对路径>"},空串=未设置) |
配置
- id: science-skill
name: dsh-science-skill
config:
enabled: true # false 时不注册任何路由 dataRoot: '' # 缺省走 $DSH_HOME
skillDirs: [] # 追加的技能根(相对路径按 dataRoot 解析)
naming: true # 导入技能时用默认模型起中文名;关掉则只做规则推断
HTTP 接口
全部挂在 /api/dsh-science-skill 下。读接口返回 JSON,写接口收 JSON body。
| 方法 | 路径 | 作用 |
| GET | /skills | 技能列表(含中文名、简介、分类、/命令、示例提问) |
| GET | /skills/detail?id= | 单个技能的展示字段 + 示例 + SKILL.md 原文(上限 20000 字符,超出带 truncated;id 非法 400、不存在 404) |
| POST | /skills/refresh | 重新扫描:登记新技能、重建索引,并为「从未命名或没有示例」的技能启动回填(3 条并发) |
| GET | /import-settings | 技能默认目录(未设置时为空串) |
| POST | /import-settings | 设/清技能默认目录:{defaultSkillDir}(只接受绝对路径或空串) |
| GET | /skills/validate?path= | 校验一个技能目录能不能导入 |
| POST | /skills/import | 导入技能目录:{path, overwrite?, category?};不带 overwrite 时同名技能返回 400 already exists,应答含 overwritten 与「已覆盖更新」文案 |
| POST | /skills/update | 改展示信息与分类:{id, displayName?, displaySummary?, category?} |
| POST | /skills/delete | 删除技能(internal 共享包拒绝删除) |
| GET | /categories | 分类表 |
| GET | /categories/suggest?label= | 按名称推荐图标 |
| POST | /categories/create|rename|delete|reorder|restore | 分类增删改序与恢复默认 |
| GET | /catalog | 聚合索引原文 |
| GET | /skill-gate/state?sessionId= | 该会话的激活集合与全局开关 |
| POST | /skill-gate/pin | 改全局开关:{name, enabled} |
| POST | /skill-gate/session | 推某会话的激活集合:{sessionId, names[]} |
兼容性
- 需要 DSH ^0.2.0-rc.1:宿主半边只依赖 ctx.webServer,客户端半边使用官方插槽与 slots / sessions / conversation / remote / locale / inputTriggers 服务。
- 零运行时 npm 依赖,离线机器也能装起来。
- 可选:内核提供 skillGate 挂点时,面板里的开关会真正影响模型可见的技能目录;没有该挂点时插件照常工作,开关只记录状态。
已知限制
- 技能最终能否被模型加载,仍由 DSH 内核决定。同名技能存在多个来源时,按内核的优先级规则胜负,面板上显示的不一定是最终生效的那一份。
- 插件只读写数据根,不接管技能发现,也不 patch 内核。
反馈与贡献
问题、建议与 Pull Request 都欢迎:Issues。
许可证
MIT预览分享卡片长什么样 ↓
分享 · DeepSeek Harness Hub
kee0012/dsh-science-skill
科研技能中心 for DeepSeek Harness:技能目录、分类、按会话启用门控,以及用户可调用的…
相关插件 · 技能 / 提示词
人设统管ZiChuanLan/agent-purge
一份系统提示词,喂给多个 coding…
★ 931已汉化DSH
73.8
人物画像蒸馏titanwings/distilly
Distilly — 把他们的思考方式提炼成可复用的技能,供任何智能体或机器人使用。原名 Colleague Skill(原同事 Skill)。
★ 25,659已汉化DSH
71.3
推理工作空间套件Tiger3807861189/J-Space-Cognition-Suite
J-Space 是面向复杂推理、大型仓库工程、子代理协作与授权安全分析的推理时工作空间和控制套件。
★ 2,957已汉化DSH
70.5
两阶段工具锚定预设xiaobright/dsh-anchored-standard
实验性 DeepSeek Harness agent preset…
★ 3,742已汉化DSH
70.1
智能体工作流编排nrslib/takt
不再日夜盯着 AI 编码智能体。
★ 1,402已汉化DSH
70
Agent 运行时手册Electricitysheep/dsh-handbook
DeepSeek Harness dsh 从 0 到 1 深度手册:安装/插件开发/性能调优/实测案例/同模型多…
★ 827已汉化DSH
68.7