问题概述
在 dsh-better-sidebar@0.19.x 下,@wxg-prc-cpg/browser-skill-dsh-plugin@0.2.1 的客户端部分会在第一次 SidebarStore.setSession() 时抛异常,导致 better-sidebar 的整个底部工作台崩溃。用户实际看到的是由 better-sidebar 根错误边界渲染出来的、具有误导性的文案:
dsh-better-sidebar: Cannot read properties of undefined (reading 'kind')
环境
@deepseek-ai/dsh@0.1.5-rc.1(Windows 11,Node 24)
@wxg-prc-cpg/browser-skill-dsh-plugin@0.2.1(当前最新)
dsh-better-sidebar@0.19.1(当前最新)
- BrowserSkill CLI
bsk 0.2.1,浏览器已连接
复现步骤
- 在 DSH web profile 中安装
dsh-better-sidebar@0.19.1 与 @wxg-prc-cpg/browser-skill-dsh-plugin@0.2.1。
- 启动
dsh web,打开任意会话(侧边栏 store 在会话激活时 hydrate)。
- 底部侧边栏面板出现红色错误条:
dsh-better-sidebar: Cannot read properties of undefined (reading 'kind')。
根因
lib/client.cjs(源码位于 packages/dsh-plugin-browserskill/src/client/...):
function* leafNodes(node) {
if (node.kind === "leaf") { // <-- 这里的 node 是 undefined
yield node;
return;
}
for (const child of node.children) yield* leafNodes(child);
}
/** 是否已经有一个本插件的标签页打开在任一侧边栏工作台里 */
function observationTabOpen(state) {
if (state === void 0) return false;
for (const root of [state.splits, state.bottomSplits])
for (const leaf of leafNodes(root)) /* ... */ ;
return false;
}
state.splits 这个字段已经不存在了。dsh-better-sidebar@0.19.0 把右侧栏交给了 DSH 0.1.5 的原生右侧边栏,它自己的 SidebarState 现在只保留 bottomSplits:
// dsh-better-sidebar src/client/state.ts (0.19.1)
export interface SidebarState {
activePane: string | null;
// ...
/** 底部工作台的分栏树 */
bottomSplits: SplitNode;
// `splits`(旧版右侧栏分栏树)已被移除
}
于是这次遍历从一个 undefined 开始,leafNodes(undefined) 直接读取 undefined.kind 就炸了。
同一个函数里还有第二处过期假设:state.panelOpen 在同一版本中已改名为 state.bottomOpen,导致「面板被关闭后再自动打开」这一分支永远不会触发。
真实堆栈
浏览器控制台抓到的堆栈如下:
TypeError: Cannot read properties of undefined (reading 'kind')
at leafNodes (@wxg-prc-cpg/browser-skill-dsh-plugin/client.js)
at leafNodes.next (<anonymous>)
at observationTabOpen (…)
at evaluate (…)
at SidebarStore.notify (dsh-better-sidebar/lib/client.js)
at SidebarStore.setSession (dsh-better-sidebar/lib/client.js)
at <better-sidebar Sidebar useEffect: store.setSession(current)>
这个异常之所以会冒进 better-sidebar 的 React 树,是因为 registerObservationSidebar() 调用了 store.subscribe(evaluate),而 SidebarStore.notify() 是在 setSession() 内部同步执行订阅者的,此时 React 恰好在提交 better-sidebar 自己的 effect。因此它被 better-sidebar 的根 RenderBoundary 捕获,而不是被本插件自己的错误边界捕获。
修复建议
给分栏树遍历加空值保护,并在生态迁移期同时兼容两种字段名:
function* leafNodes(node) {
if (node === undefined || node === null) return;
if (node.kind === "leaf") {
yield node;
return;
}
for (const child of node.children) yield* leafNodes(child);
}
function observationTabOpen(state) {
if (state === undefined) return false;
for (const root of [state.splits, state.bottomSplits]) {
if (root === undefined || root === null) continue;
for (const leaf of leafNodes(root))
if (leaf.tabs.some((tab) => tab.type === "browserskill:observation")) return true;
}
return false;
}
以及:
// 原来是:state.panelOpen === false
if (previousVisible === 0 && count > 0 && open && (state.bottomOpen ?? state.panelOpen) === false) …
长期来看,在 better-sidebar >= 0.19 上可以直接去掉 state.splits(或对状态结构做特性检测),因为已经不存在右侧分栏树需要扫描了。
验证方式
我在本地用上面两处保护改了 lib/client.cjs,再用无头 Chrome 加载页面:打补丁前,控制台在页面加载后约 1 秒内必现该报错;打补丁后控制台干净,工作台正常渲染。
问题概述
在
dsh-better-sidebar@0.19.x下,@wxg-prc-cpg/browser-skill-dsh-plugin@0.2.1的客户端部分会在第一次SidebarStore.setSession()时抛异常,导致 better-sidebar 的整个底部工作台崩溃。用户实际看到的是由 better-sidebar 根错误边界渲染出来的、具有误导性的文案:环境
@deepseek-ai/dsh@0.1.5-rc.1(Windows 11,Node 24)@wxg-prc-cpg/browser-skill-dsh-plugin@0.2.1(当前最新)dsh-better-sidebar@0.19.1(当前最新)bsk 0.2.1,浏览器已连接复现步骤
dsh-better-sidebar@0.19.1与@wxg-prc-cpg/browser-skill-dsh-plugin@0.2.1。dsh web,打开任意会话(侧边栏 store 在会话激活时 hydrate)。dsh-better-sidebar: Cannot read properties of undefined (reading 'kind')。根因
lib/client.cjs(源码位于packages/dsh-plugin-browserskill/src/client/...):state.splits这个字段已经不存在了。dsh-better-sidebar@0.19.0把右侧栏交给了 DSH 0.1.5 的原生右侧边栏,它自己的SidebarState现在只保留bottomSplits:于是这次遍历从一个
undefined开始,leafNodes(undefined)直接读取undefined.kind就炸了。同一个函数里还有第二处过期假设:
state.panelOpen在同一版本中已改名为state.bottomOpen,导致「面板被关闭后再自动打开」这一分支永远不会触发。真实堆栈
浏览器控制台抓到的堆栈如下:
这个异常之所以会冒进 better-sidebar 的 React 树,是因为
registerObservationSidebar()调用了store.subscribe(evaluate),而SidebarStore.notify()是在setSession()内部同步执行订阅者的,此时 React 恰好在提交 better-sidebar 自己的 effect。因此它被 better-sidebar 的根RenderBoundary捕获,而不是被本插件自己的错误边界捕获。修复建议
给分栏树遍历加空值保护,并在生态迁移期同时兼容两种字段名:
以及:
长期来看,在 better-sidebar >= 0.19 上可以直接去掉
state.splits(或对状态结构做特性检测),因为已经不存在右侧分栏树需要扫描了。验证方式
我在本地用上面两处保护改了
lib/client.cjs,再用无头 Chrome 加载页面:打补丁前,控制台在页面加载后约 1 秒内必现该报错;打补丁后控制台干净,工作台正常渲染。