twenty-3rd/dsh-skill-switch ↗★ 1

dsh-skill-switch

DSH web plugin: project-level skill switches with a panel — one-click block/unblock per project, global skill deletion, a valid/error verdict per skill (in registry + model-invocable + user-invocable, with the failing condition shown), and a read-only detail view listing every on-disk root location of a skill. 项目级 skill 开关 + 全局删除 + 有效/错误判定 + 每处根位置详情面板。 适合需要按项目快速屏蔽/启用Skill并排查有效性错误的用户。

패키지
dsh-skill-switch
호환성
미검증
Harness peer 범위
>=0.1.7-rc.2 <0.3.0
Cordis peer 범위
^4.0.1
버전
0.4.0
라이선스
MIT
최근 업데이트
2026. 10. 7.

같은 패키지 이름의 다른 저장소

설치

$npx -p @deepseek-ai/dsh dsh plugin --profile web add github:twenty-3rd/dsh-skill-switch

使用说明

三步:打开任一会话 → 点视图标签条里的「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/skillsproject-dsh✅
/.agents/skillsproject-agents✅
customSkillDirscustom✅
$DSH_HOME/skills(~/.dsh/skills)user-dsh✅
$DSH_AGENTS_HOME/skills(~/.agents/skills)user-agents✅(可用 allowSharedRootWrites: false 变只读)
$DSH_BUNDLED_SKILL_DIRbundled❌ 随宿主应用分发,删了会破坏安装
$DSH_HOME/skill-librarylibrary✅(dsh-skills-manager 的规范副本)
其它 provider 注册的虚拟 skillruntime / 任意❌ 磁盘上没有可删的东西

范围要说清楚:本插件扫描的根由"当前会话 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 的共享根)