feat: 新增 extraTools 配置接管其他工具卡片 - #5
Conversation
better-er
left a comment
There was a problem hiding this comment.
PR #5 审阅:feat: 新增 extraTools 配置接管其他工具卡片
审阅对象 #5,base main,head 3dcb057,8 文件 +460/−110。工作区已重新 fetch,本地 HEAD 与 PR head 一致。
事实核对
- 构建与类型:
pnpm typecheck通过,pnpm build通过,产出lib/index.js、lib/index.d.ts、lib/client.js、lib/client.js.map;pnpm install --frozen-lockfile通过,锁文件与 package.json 一致。线上 CI 同名检查 typecheck · build 为 pass。仓库无单测。 - 远端工具参数名:dsh-remote-file-system 的
edit_remote用file_path/old_string/new_string,write_remote用file_path/content,与DEFAULT_SPEC完全一致,所以cordis.patch.yml默认只写name是成立的。 - settings 通道:宿主
ctx.settings.installSection(owner, ns, schema, entry, hooks)与 dsh-settings 的签名一致,setSource/onChange为必填,传空实现能通过类型检查。客户端settingsScope.bind({ namespace }).getSnapshot().value与subscribe与 dsh-client-ui-settings 的SettingsScope契约一致,当前 DSH 0.1.5-rc.1 里服务名确实叫settingsScope,没有webUiSettings别名。 - CI 与发布:单一 Node 26.3.1、四项产物校验、release 的前置已发布守卫与
npm publish --provenance都与 CICD.md 的模板对齐。README 的 profile 覆盖示例符合 patch 按 id 替换整段 config 的语义,省略name与 dsh-web-app 的真实覆盖写法一致。 - 其余改动与描述相符,未发现别的失实。
修改要求
1. 必修:配置变化时的「整批重建」没有真正注销旧注册,二次 sync 会抛错
现实现拿 ctx.effect 包住 slots.inject,再用 disposeExtra 重跑,但这条链路上没有任何 disposer 被真正收集:
slots.register的契约是返回注销函数,内部实现为ctx.effect(() => this._register(...)),靠回调返回的 disposer 注销。客户端把slots.register(...)放在块体箭头里且不 return,回调返回 undefined。slots.inject同样返回注销函数,内部用ctx.effect(callback)包住用户回调;用户回调不返回 disposer,这个 effect 就收集不到任何东西。- cordis 的
Fiber.effect只收集 effect body 返回的 disposer,嵌套的ctx.effect各自挂在 fiber 的_disposables上,父 effect 的 disposer 不会连带注销它们。 SlotCore.register对 keyed 槽位遇到同 key 同 priority 会直接抛keyed slot "..." already has an entry for key "...",而这里 priority 固定为 -1。
于是 settings 第二次变化时 sync 会重新注册同一批 key 并抛错,README 里「settings 变化会让浏览器端重建这批 key 的注册」不成立。首次加载通常只发生一次有效 sync,实机验证很容易漏掉;但本插件把命名空间注册进了 Host,插件设置页可以改 extraTools,或 settings 镜像重建时就会命中。
修正方向,每条工具单独 inject 并让回调表达式返回 disposer,同时接住 slots.inject 自己返回的注销函数:
const disposers: Array<() => void> = []
for (const name of names) {
disposers.push(slots.inject('tool.call.toolview', () =>
slots.register({ name: 'tool.call.toolview', key: name, priority: -1 }, DiffCard)))
}
disposeExtra = () => { for (const dispose of disposers.reverse()) dispose() }2. 建议:SlotsService 子集接口的返回类型写错
inject(name, register): void 与 register(options, component): void 实际都返回 () => void。当前写法把返回值抹掉,既掩盖了问题 1,也让正确修法过不了类型检查,应改成 () => void。
3. 建议:extraTools 里的同名条目会当场抛错
names 未去重,同一份配置里出现两个同名条目时,同一轮 sync 就会对同 key 同 priority 注册两次并抛错。建议在收集 names 时按名字去重。
4. 小问题:订阅退订与 effect 时机
scope.subscribe(sync) 返回的退订函数没有保存,sync 里用 ctx.effect 包 slots.inject 也不能连带注销 inject 控制器。按问题 1 的修法直接收集 slots.inject 的 disposer 即可,subscribe 的退订也建议一并保存,在 settingsScope 卸载时调用。
结论
CI 与文档核对全部通过,主功能方向正确,但配置热更新的注销逻辑存在实打实的缺陷,建议按第 1 条修完再合。
本 PR 给 dsh-edit-diff 加上
extraTools配置,让它在edit与write之外也能接管其他工具的卡片,并默认接管 dsh-remote-file-system 的edit_remote与write_remote;顺带按 CICD.md 整理 CI。背景
dsh-edit-diff 此前只注册
tool.call.toolview的edit与write两个 key,参数名与判断逻辑都写死在代码里。远程文件工具的参数名与原生完全一致,但 key 没注册,卡片只能落回通用形式。浏览器半身拿不到 cordis 配置:
__DSH_BOOT__的 entry 结构里没有 config 字段,客户端内核创建插件 entry 时只传包名,所以cordis.patch.yml里写给插件的配置只有 host 半身能看见。双半插件传配置的官方通道是 settings 命名空间。具体改动
host 端
src/index.tsConfigschema 与ExtraTool类型,注册 settings 命名空间dsh-edit-diff。ctx.settings.installSection()把 entry 配置注册为 base 层,用户分节覆盖其上;没有挂载 settings provider 时退回 entry 值。@deepseek-ai/schemastery,与@deepseek-ai/cordis、@deepseek-ai/dsh-settings一起进 peerDependencies。client 端
src/client.tsKeySpec与extraSpecs,把原来写死的name === 'edit' || name === 'write'改成按工具名取参数名。edit与write使用默认参数名file_path、old_string、new_string、content,extraTools条目可逐项覆盖。ctx.inject(['settingsScope'], ...)绑定命名空间,配置变化时整批重建这批 key 的注册;settingsScope 缺失时内置两张卡片照常工作。配置
cordis.patch.yml默认接管edit_remote与write_remote,参数名与原生一致只写名字。cordis.patch.yml里按 id 覆盖extraTools。文档与 CI
.github/workflows/ci.yml去掉 master 触发与 node 22/26 矩阵,改为单一 Node 26.3.1,产物校验按双半身加 dts 的形态写。.github/workflows/release.yml补上已发布版本守卫、environment: release、npm publish --provenance,与 CICD.md 的模板对齐。package.json补engines: >=26.3.1,版本提到0.4.0。验证
pnpm typecheck通过,pnpm build通过。Configschema 能把extraTools解析出来。edit_remote与write_remote的卡片显示为去重 diff。影响面
edit_remote与write_remote两个 key;没装 dsh-remote-file-system 时这两个 key 无人认领,不渲染,无影响。edit与write的渲染路径不变,settingsScope 缺失时照常工作。@deepseek-ai/schemastery,另两个是类型依赖。0.4.0;发版时 release 工作流按 tag 比对,同号则不产生回写提交。