twenty-3rd/dsh-skill-switch ↗★ 1
dsh-skill-switch
项目级Skill开关与状态管理面板 适合需要按项目快速屏蔽/启用Skill并排查有效性错误的用户。
同名套件的其他儲存庫
安裝
npx -p @deepseek-ai/dsh dsh plugin --profile web add github:twenty-3rd/dsh-skill-switch說明文件
閱讀完整 README ↗使用说明
三步:打开任一会话 → 点视图标签条里的「Skill 开关」→ 用行内开关切换。 面板按会话 cwd 所属的项目生效;切换立刻写盘,变化在下一个模型轮次生效, 不需要重启。
界面
会话视图标签条里多出第三个标签(对话 / 轨迹 / Skill 开关;若装了 dsh-skills-manager,它排在 Skills 管理器之后)。面板由三部分组成:
- 左侧筛选 chip:全部 / 已屏蔽(各自带计数),外加名字+描述搜索。
- 卡片左侧:名字、来源徽标、有效/错误徽标、描述,以及一行事实 (判定失败的是 A/B/C 哪一条、frontmatter 缺什么、名字取自目录名、副本数量、 名字不合法无法开关等)。
- 卡片右侧:一个纯 CSS 开关键(点一下就是一次切换)+ 「操作」下拉菜单。
- 操作菜单:「补齐 frontmatter」(仅 frontmatter 有问题的项)与 「删除(全部副本)」;两者都有二次确认,且会把将受影响的文件路径一条条列出来。
界面语言:面板文案跟随 DSH 的界面语言,内置中文 / English 两套字典(键值一一对应)。
切换入口是 设置 → 通用 → Language(dsh-client-locale 提供的那一行);切换即时生效、
不用刷新页面,「Skill 开关」标签文字也会一起变。面板自身没有独立的语言开关。
点开一行 → 详情(只读)
点卡片左侧的事实区(名字 / 描述)进入详情页,「返回列表」回到列表(筛选与搜索词保留)。 开关键与「操作」按钮不在事实区里,点它们不会跳走(名字不合法、不能写开关的行也照样能看详情)。
详情只做"把列表里被折叠掉的事实摊开":列表每行只显示胜出副本(rank 最小者), 同名 skill 散在共享根 / DSH 根 / 库根里时,详情是唯一能看到另外几处的地方——包括 每处副本各自的 frontmatter 问题(同一个名字在不同根里状态可能不同)、会不会被 DSH 实际加载、能不能删。它不带任何写动作(屏蔽 / 删除 / 补齐仍在列表里)。
顶部不再显示项目绝对路径、开关目录与 mode:那是内部实现细节,用户无法据此
行动(开关目录的语义仍在「恢复本项全部」的二次确认里说明)。
功能一:项目级屏蔽
开关放在项目自己的 .dsh/skill-switches/ 里,随仓库走、随项目生效:
/.dsh/skill-switches/
├── mode # 可选:第一行 "deny"(默认)或 "allow"
├── off/ # deny 模式:这些 skill 被隐藏
└── on/ # allow 模式:只有这些 skill 可见
- 项目级:同一个 host 进程里,A 项目关掉的 skill 在 B 项目照常可见。
- 会话内生效:变化在会话的下一个轮次自动反映到 skill 目录——
dsh-tool-skill每轮agent/pre-step用{cwd: session.header.cwd}调snapshot,digest 变化 即重写系统提示里的目录,无需重启。 - 彻底隐藏:被关掉的 skill 不仅从目录消失,
skill工具按名加载也会被拦截。
面板里的"屏蔽/启用"在两种模式下语义一致(是否隐藏):
| 模式 | 屏蔽 | 恢复 |
|---|---|---|
deny(默认) | 建 off/ | 删 off/ |
allow | 删 on/ | 建 on/ |
两种情况下都会顺手清掉另一侧的同名残留,避免手工切换模式后语义漂移。
面板右上角的「恢复本项全部」清空 off/ 与 on/;如果项目当前是 allow
(白名单)模式,它会同时移除 mode 文件——只清 on/ 会让白名单变成空集,
等于把整个 skill 目录清空,与"恢复默认可见性"正好相反。确认框里会写明这一点。
仍然可以完全不用界面,直接建文件(与 v1 完全一致):
cd
mkdir -p .dsh/skill-switches/off
echo "这个项目用不到" > .dsh/skill-switches/off/ai-supply-chain-bottleneck-hunter
touch .dsh/skill-switches/off/api-design.md # .md 后缀也认
rm -rf .dsh/skill-switches # 全部恢复
功能二:全局删除
「删除(全部副本)」会把该名字在每一处已知根里的副本都删掉:
| 根 | 来源 id | 是否可删 |
|---|---|---|
/.dsh/skills | project-dsh | ✅ |
/.agents/skills | project-agents | ✅ |
customSkillDirs | custom | ✅ |
$DSH_HOME/skills(~/.dsh/skills) | user-dsh | ✅ |
$DSH_AGENTS_HOME/skills(~/.agents/skills) | user-agents | ✅(可用 allowSharedRootWrites: false 变只读) |
$DSH_BUNDLED_SKILL_DIR | bundled | ❌ 随宿主应用分发,删了会破坏安装 |
$DSH_HOME/skill-library | library | ✅(dsh-skills-manager 的规范副本) |
| 其它 provider 注册的虚拟 skill | runtime / 任意 | ❌ 磁盘上没有可删的东西 |
范围要说清楚:本插件扫描的根由"当前会话 cwd 的项目根 + 用户级/共享/内置/库"
组成,所以别的项目的项目级副本(/.dsh/skills)不在扫描范围内——
面板上按的是「删除(全部副本)」而不是「删除(全局)」,确认框里也会写明这一点。
要在别的项目里也消失,去那个项目的会话里再删一次(或直接删那个目录)。
安全边界:
- 路径全部由服务端扫描推导,客户端只能传名字;每个待删路径都要通过
"严格位于所属根之内、且不是根本身"的校验,越界直接
403 forbidden。 - 一次删除里单点失败不会拖垮其它副本;全部副本都不存在时报
404。 - 请求里的
cwd只在宿主确实认识该 session、且它的 cwd 还没 hydrate 时才被 当作兜底;sessionId 不认识时一律用宿主进程 cwd。否则任何调用方都能拿一个不存在的 sessionId 加任意绝对路径,让写入/删除发生在别处。 - 方法派发走
Object.hasOwn:constructor/toString这类原型成员会被当成 "未知方法"返回 404,不会命中原型链。 /skill-switch的 error.message 一律是面向机器的英文(wire 层);面板按 wire code 出本地化文案,所以中文界面不会混进英文细节、英文界面也不会混进中文。- 删除成功后会顺手清掉本项目里该名字的开关文件,避免"删了再装回来还带着旧屏蔽"。
配置
在 profile 的 cordis.patch.yml 里按 id 覆盖:
- id: skill-switch
config:
switchesDir: .dsh/skill-switches # 相对项目根的开关目录
defaultMode: deny # deny | allow
cacheTtlMs: 1000 # 状态缓存兜底时长(mtime 指纹命中则即时失效)
forceRefreshOnGet: true # get() 拦截路径是否绕过缓存
dshHome: '' # 默认 resolveDshHome()($DSH_HOME 或 ~/.dsh)
agentsHome: '' # 默认 $DSH_AGENTS_HOME 或 ~/.agents
customSkillDirs: [] # 额外 skill 根(同官方 provider 的 custom 层)
bundledSkillDir: '' # 默认 $DSH_BUNDLED_SKILL_DIR
allowSharedRootWrites: true # false = ~/.agents/skills 只读(不动 Claude Code 的共享根)
配置
在 profile 的 cordis.patch.yml 里按 id 覆盖:
- id: skill-switch
config:
switchesDir: .dsh/skill-switches # 相对项目根的开关目录
defaultMode: deny # deny | allow
cacheTtlMs: 1000 # 状态缓存兜底时长(mtime 指纹命中则即时失效)
forceRefreshOnGet: true # get() 拦截路径是否绕过缓存
dshHome: '' # 默认 resolveDshHome()($DSH_HOME 或 ~/.dsh)
agentsHome: '' # 默认 $DSH_AGENTS_HOME 或 ~/.agents
customSkillDirs: [] # 额外 skill 根(同官方 provider 的 custom 层)
bundledSkillDir: '' # 默认 $DSH_BUNDLED_SKILL_DIR
allowSharedRootWrites: true # false = ~/.agents/skills 只读(不动 Claude Code 的共享根)