fix: 原版 DSH 壳上 dsh-ui 围栏静默不渲染(inputTriggers 硬注入门控) - #10
Conversation
taekchef
left a comment
There was a problem hiding this comment.
@linshule 这个根因抓得很准,修复方向我们完全认可——inputTriggers 不该当硬激活门禁,否则原版壳上整个渲染器都不启动。CI 两个 Node 版本全绿,我们本地也跑了全套(270 passed / 102 skipped)✅
在合之前只提一个请求改动(很小):
/panel 注册请从「apply 时查一次 ctx.get」改成 cordis 可选订阅,避免服务到场顺序竞态。
原因:slots/sessions 与 inputTriggers 往往是不同 bundle 并发提供,apply() 跑起来的那一刻 ctx.get('inputTriggers') 可能是 undefined——这样带该服务的宿主也会把 /panel 静默禁用。我们用最小 cordis 实验验证过:同批注册时两种顺序下 ctx.get 都可能 miss,而 ctx.inject 可选订阅在任意顺序下都能正确注册。
建议这样写(主体逻辑不用动):
export const inject = ['slots', 'sessions']
export function apply(ctx: Context): () => void {
// ……既有 slots / toolview / dock 注册不变……
ctx.inject(['inputTriggers'], (scope) => {
const slash = scope.get('inputTriggers') as InputTriggerServiceContract | undefined
if (slash === undefined) return
scope.effect(() => slash.registerSource(
createPanelSlashSource((sessionId, instruction) => sendPanelInstruction(ctx, sessionId, instruction)),
), 'genui: /panel')
})
}ctx.inject 的回调本身就是一个小插件 fiber:服务来了才激活、随 fiber 卸载自动 dispose,不需要再往外层 disposers 里塞。这样「没服务→照常渲染、/panel 不注册」「有服务→/panel 一定能注册」两边都不丢。
另外 main 刚合了 #14(issue #13 修复),麻烦顺手 rebase 一下 main(CHANGELOG / lib/client.js / dom-fence 测试有冲突),并保持 lib/client.js 重建提交。
改完这两点我们立刻合,辛苦啦 🙏
client 入口硬注入声明把 inputTriggers 当成激活前置,但 cordis 的 inject
是硬激活门控:原版 DSH 壳没有任何插件提供该服务 → fiber 永久 waiting、
apply() 永不执行 → 渲染器整体未启动,围栏保持代码块、控制台零报错。
apply() 体内早已用 ctx.get('inputTriggers') 可选降级(缺失仅禁用 /panel
并告警),硬注入声明与可选用法自相矛盾。修复:从硬注入列表移除
inputTriggers,保留可选查询路径;带该服务的宿主行为不变。
- src/client/index.tsx: inject 列表 + 原因注释
- tests/dom-fence.spec.tsx: 注入回归钉同步更新
- lib/client.js: 重建产物
- CHANGELOG.md: 变更记录
评审反馈:slots/sessions 与 inputTriggers 往往由不同 bundle 并发提供,
apply() 运行时一次性 ctx.get('inputTriggers') 可能 miss —— 带该服务的
宿主也会静默禁掉 /panel。改用 cordis 可选订阅:
ctx.inject(['inputTriggers'], (scope) => { … })
服务任意到场顺序都能注册 /panel;缺失时仅不注册,渲染不受影响;
订阅 fiber 卸载时自动 dispose,无需塞进外层 disposers。
- src/client/index.tsx: /panel 注册 + 注释更新
- lib/client.js: 重建产物
- CHANGELOG.md: 注入修复条目同步描述订阅方式
c3ff436 to
a5d4f4d
Compare
|
收到,两点都已按要求完成 ✅ 1. 按建议改成了
2. 两个分支均已 rebase 到最新 main
lib/client.js 已按各分支状态重建提交(tsc + tsdown 通过)。说明:两个 PR 都重建了 lib,合入顺序为 #10 → #11 时,第二个的 lib/client.js 合并可能需要最终重建一次(如需我可以在 #10 合入后立刻给 #11 重推)。 本地验证:jsdom 端到端(真实 shell MarkdownText + DOM 通道)在无 |
问题
在原版 DSH(0.1.0-rc.6)shell 上,所有
dsh-ui围栏渲染为普通代码块,控制台零报错(与 issue #6 的"静默失败"模式一致,但场景不同:不是 DOM 表面发现失败,而是整个 client 从未激活)。根因
client 入口的硬注入声明:
cordis 的
inject是硬激活门控:声明的服务必须全部被提供,fiber 才会激活。而原版 DSH shell 没有任何插件提供inputTriggers服务(全量扫描 boot graph 确认:仅 vision-toolkit 以ctx.inject(['inputTriggers'], …)可选订阅它,且其硬注入列表['slots','locale','remote','conversation','sessions']全部可用)。于是 genui 的 fiber 永久停在 waiting、
apply()永不执行、渲染器整体未启动 —— 围栏保持代码块,且无任何日志。矛盾点:
apply()体内早已把inputTriggers当作可选项处理:硬注入声明与可选用法自相矛盾 —— 声明写错位置导致可选降级代码永远到不了。
修复
把
inputTriggers从硬注入列表移除,保留ctx.get()可选查询路径:/panel命令禁用并告警一次(行为与apply()内现有降级逻辑一致)inputTriggers的宿主:ctx.get('inputTriggers')仍能取到服务,/panel命令照常注册 —— 行为零变化变更文件
src/client/index.tsxtests/dom-fence.spec.tsxinputTriggers,与硬门控语义冲突)lib/client.jsCHANGELOG.md验证
tsc -p tsconfig.json+tsdown均通过inputTriggers服务、DOM 通道路径):围栏被发现并水合成组件 —— callout、chart(柱状图,含柱高/标签/数值)渲染正确;inputTriggers缺失告警恰好一次;apply()无异常dom-fence.spec.tsx(27)全绿含更新后的回归钉,plugin-genui.spec.ts(7)全绿;其余失败均为环境限制(install-script 依赖chmod、skill-md 依赖宿主源码树 yaml 版本),与本次变更无关 —— 完整 370 项在 CI(Linux + DSH 源码 checkout)上运行复现与对照
dsh-ui围栏的消息即可ctx.inject()可选订阅 + 硬注入只声明必需服务)