Repository navigation
Releases: Max-Null/dsh-skill-mcp-center
Release list
v0.7.0
Added
插件包内的技能可以启停了(#1 的后半段)。它们没有可写的 SKILL.md,改名 / 移出目录 / 断链对安装内容都不生效(社区同类项目因此只能显示「内置只读」)。现在走 registry 的 rank 遮蔽:
- 停用:
ctx.skills.register()一个同名占位技能——runtime rank 250 赢过包内 provider ≈550 与 bundled 600,两个 invocation 都设为 false。技能仍在 catalog 里、仍可被面板列出,但模型与人都调不到它。 - 启用:调 disposer,恢复原本的 provider。
- 停用清单落在
$DSH_HOME/skill-mcp-center/disabled-skills.json并在启动后重放——registry 不提供「查看被遮蔽定义」的 API,不落盘就等于重启即失忆。 - 面板的
enabled只在「清单里有 且 占位注册成功」时为 false:同名冲突会让register()抛错,那时不能谎报禁用。
Changed
SkillView新增enabled;非磁盘技能(有路径但writable: false)也显示开关,走新增的setSkillEnabledRPC。- README 截图段补 Skill 标签页的插件技能启停。
v0.6.5
Fixed
- README 的 MCP 截图重拍:0.6.4 带的是整窗截图,把侧栏的会话标题一起框了进去;换成只含设置对话框的裁剪图(
[role="dialog"]的 boundingBox),内容不变。
v0.6.4
Fixed
- MCP 卡片的命令行不再渲染成
[object Object]:cordis.yml里的command/args可以是!!js表达式,options.config上保留为{ __jsExpr }节点、求值结果在fiber.config上(与pluginSkillRoots同一个坑)。listMcpServers原来照 options 读,playwright-headless这类条目就显示成[object Object] {"__jsExpr":"…"}。现在优先读fiber.config,非字符串值再归一成字符串。
Changed
- README 截图段补 MCP 标签页,含开关的效力边界说明与「本次运行已停用」的行内提示。
v0.6.3
Changed
- MCP 开关的效力边界写进界面:DSH 的
Loader.write()是空实现(cordis-plugin-loader@1.0.2的lib/index.js:715就是write() {},源码注释写明「root tree is in-memory; writes are no-ops」),所以面板的启停只对本次运行生效,重启后从cordis.patch.yml重新加载、恢复启用(#6)。MCP 视图顶部现在写明这一点,被面板关掉且属于本次运行的条目显示「本次运行已停用 · 重启恢复」。 listMcpServers新增sessionToggled:只有本运行内被面板改过开关的条目才为真。cordis.patch.yml里disabled: true的条目是持久禁用,不能被标成「重启恢复」——两种「关」要能区分开。
v0.6.2
Fixed
- 代码注册的 skill 不再把空路径发给
readSkill:ctx.skills.register()注册的条目(office 系列、browser-skill、diagnose-windows-sandbox-acl等)没有SKILL.md,listSkills对它们一律报path: ''。设置页此前无条件渲染「查看 SKILL.md」,点下去就是readSkill: path is required红字。现在这些条目不渲染该按钮,改为显示「无 SKILL.md」徽章,路径行也写同样的话,不再留一个空白让人以为加载失败。 - 运行时 skill 不再共用同一个展开/阅读身份:
expanded与mdPath都拿s.path当 key,而所有代码注册条目的path都是空串——点开一张卡,同组的卡全部跟着展开。新增skillKeyOf()给无文件条目一个\0runtime:<name>形式的稳定别名(NUL 不会出现在路径里,因此不会与真实路径相撞),磁盘条目仍以路径为身份。侧栏的 React key 一并改用它。
v0.6.0
新增
删除用户级 / 项目级技能。 设置页与侧栏的技能行都多了一个「删除」按钮,只出现在可写的技能上 —— ~/.dsh/skills、~/.agents/skills,以及当前工作区的 <cwd>/.agents/skills 与 <cwd>/.dsh/skills。插件技能与 DSH 官方内置技能(plugin: / bundled / dsh-official)保持只读,不出现该按钮。
点删除先弹确认,写明技能名与完整路径;确认后该技能从磁盘移除 —— 目录形态(<name>/SKILL.md)删整个目录,平铺形态(<name>.md)删那个文件。
不直接销毁:条目被移到 ~/.dsh/.skill-trash/,成功提示里给出具体位置,误删可手动移回去。
兼容性
新增一个 RPC 端点 deleteSkill({ path, cwd? });现有端点与请求信封不变。
删除面刻意窄于查看面:readSkill 接受插件与内置根,删除只接受用户级与项目级根,并且要求目标正好是某个允许根的直接子项 —— 根自身、技能内部的嵌套文件、名字相近的兄弟目录一律拒绝(skill-not-found)。
验证
pnpm typecheck / pnpm test(45 passed)/ pnpm build 三关全绿。
隔离 dev 实例端到端:
- RPC 层 —— 项目级
probe-skill列出(writable: true)→ 删除返回trashPath→ 列表归零 → 磁盘移除 → 回收目录里在;同一实例里指向插件技能的删除被拒(skill-not-found) - UI 层 —— 侧栏行内删除按钮渲染(19 个可写技能各一个,文案「删除技能」);真实点击后确认文案含 name + path、toast 报出回收路径、列表刷新
v0.5.4
修复
插件用 bundledSkillDir 注册的技能扫不到。 面板原先只认一种形态:拿 loader entry 的 name 当包名,去拼 <node_modules>/<包名>/skills。插件若把官方 @deepseek-ai/dsh-skill-filesystem 挂在自己的 id 下、用 bundledSkillDir 指向自带 skills/(活样本 dsh-plugin-zhihu-search),说明符就是另一个包名,拼出的路径不存在;而它的技能往往还在另一棵 node_modules 树里。
真正的判据比「拼错了包名」更深一层:bundledSkillDir 在 entry.options.config 里保留的是 !!js 表达式节点({ __jsExpr }),不是路径 —— Loader 只把求值后的副本交给 entry 的 fiber,存下来那份要留着让文件写回保住 !!js 写法。照 options 拼路径必然落空,且不报错(静默漏掉)。
修法:该配置从 fiber 读,两条声明都探,并对同一目录去重。
兼容性
无接口变更 —— listSkills() 的出入参、端点集合与请求信封均未改,只是发现来源多了一条。插件技能仍是只读展示(writable: false),未开放开关。
新增 12 条测试:10 条覆盖根发现(含「options 里的表达式节点不被当作路径采信」这一关键回归),2 条用真 cordis + 真 Loader 坐实 options/fiber 的形态差异 —— 后者会在上游改变该行为时变红。
验证
隔离 dev 实例做 A/B 对照:同样本、同环境,唯一变量是插件代码 —— 旧代码 29 个技能且看不到样本,新代码 30 个、样本出现(来源 plugin:bundled-probe-skill)。样本与 dsh-plugin-zhihu-search 同构,另插一条只报告 config 的 echo entry,用来把「bundle 已挂载但旧代码扫不到」与「bundle 压根没挂载」分开。
pnpm typecheck / pnpm test(35 passed)/ pnpm build 三关全绿。
v0.5.3
修复
-
Windows 下技能列表整体为空(issue #3)。
~/.dsh/skills下的条目是目录 junction 或符号链接时,scanSkillRoot()拿Dirent.isDirectory()当形态判据——而 Dirent 是 lstat 语义,junction 报isDirectory() === false/isSymbolicLink() === true,于是skillPathFor()返回 null,每个链接型技能在continue处被丢弃。技能本身完好可读,只是扫不到。判据改为分层:Dirent 能明确作答时直接采信(真目录走
isDirectory()、真文件走isFile()),只有链接与文件系统报DT_UNKNOWN的形态才跟随一次stat。真目录因此仍是零额外系统调用;断链在stat处失败即跳过,同根其它技能不受影响。这不是 Windows 专用分支——junction 与 POSIX 符号链接走同一条路。
兼容性
- 无接口变更:
listSkills()的出入参、端点集合与请求信封均未改,只是扫描判据放宽。 - 新增 5 条单测(真目录 /
.md文件 / 链接指向目录 / 断链 / 非技能条目),用真实目录链接、不 mock fs。做过反向验证——把判据退回旧写法后,与链接相关的 2 条立刻转红。
v0.5.2
本版本同时交付 0.5.1 与 0.5.2 —— 0.5.1 当时只发了 npm 包(未提交、未打 tag),其内容随本次提交一并入库,并在此补上说明。
修复
- web 环境下设置面板报「加载失败:transport failure for
/skill-mcp/listSkills:HTTP 405」(0.5.1)
根因在宿主侧:ctx.connection.rpc.handle()注册逻辑通道时会访问client-connection未声明的webServer注入,cordis 属性代理抛错后注册静默失败(DSH 源码形态特有;打包内核形态不受影响)。上游报告:deepseek-ai/deepseek-harness discussions #6880。
变更
- RPC transport 改为双路径自适应(0.5.1)
- 宿主提供
connection.fetch.register→ 注册POST /api/skill-mcp精确路由(只写 Connection 自己的路由表,不触碰owner.webServer); - 宿主只提供逻辑通道注册表(老打包内核)→ 自动回退
/skill-mcp; - 浏览器侧先试新路由,收到 404 才回退(新路由未注册时
/api/*是 404,根路径才是 405); connection服务改用ctx.inject(['connection'], cb)获取:它在插件apply时尚未就绪,且ctx.plugin(P)不等待依赖。
- 宿主提供
- 放宽
@deepseek-ai/dsh-*的版本范围(0.5.2)
peerDependencies与devDependencies中的dsh-client-connection、dsh-host-apiproxy、dsh-skill、dsh-tools由^0.1.1-rc.1改为>=0.1.1-rc.1 <0.3.0—— 保留下限、只放宽上界。
内核逐个检查插件peerDependencies里的每个@deepseek-ai/*声明,判据是标准 semver:semver.satisfies(runtimeVersion, requirement, { includePrerelease: true })。^0.1.1-rc.1展开为>=0.1.1-rc.1 <0.2.0-0,对0.2.0-rc.1判 false;判定失败的插件会被静默跳过 —— 不进 fiber graph,也不出现在「did not activate」列表里,用户侧只看到「插件装了却毫无反应」且没有任何日志可查。
兼容性
- 无 API 变更:端点集合、请求体、响应信封(
RpcResult)均未改。 - 面板端与宿主端需同版本升级(浏览器侧的传输策略随之切换)。
- 0.5.2 无运行时行为变更,仅依赖声明放宽;旧内核(0.1.7-rc.2)仍然满足。
测试
- 新增
tests/rpc-transport.test.ts(8 条):传输层选择、服务晚到时不抢先注册、路由派发、JSON 解析失败与引擎异常收敛为internal信封。 - 全量 18 条通过;
typecheck无错;build重新构建且产物哈希与构建前一致。
验证
- web(源码形态)实测:
POST /api/skill-mcp→ 200,面板恢复,控制台 0 errors。