01 · 需求分析
本篇回答三个问题:为什么要做这个 fork、要解决什么、做到什么程度算完成。
每条需求都给出「现象 / 根因(含证据)/ 需求 / 验收标准 / 状态」,便于回溯与验收。
证据中的提交号均在本仓库 main 或 sync/v0.24.1 上。
一、背景
DSH(DeepSeek Harness)宿主自身提供会话、任务、模型与一个原生右侧栏(ctx.sidebarRight /
sidebarRightTabs)。上游 dsh-better-sidebar 在此基础上提供了一套「侧边栏工作台」:
文件树与编辑器、文件变动、任务、侧边对话、终端、浏览器,并把
ctx.betterSidebar 服务开放给其他插件注册标签页与文件预览器。
本 fork 的定位:不重复造工作台,而是在其之上补齐宿主与上游都没有的那一层——
「信息层」:这个会话的智能体拓扑、所属应用、以及会话画像。同时,在 fork 过程中暴露出
若干与 DSH 桌面壳(Electron 壳)交互的边界缺陷,一并作为需求纳入。
二、核心需求
R1 — 侧边栏只应存在一套
| 项 |
内容 |
| 现象 |
窗口里同时出现两套右侧边栏与两套开合按钮(一套自绘浮窗控件、一套 DSH 原生) |
| 根因 |
fork 基线 v0.18.0 时,插件自绘右侧面板与开关(toggleCluster);DSH 0.1.5 起宿主自己也提供原生右侧栏,二者并存 |
| 需求 |
右侧内容全部改为注册进 DSH 原生右侧栏;插件不再自绘右侧面板 |
| 验收标准 |
① 产物中 toggleCluster 引用数为 0;② 右列只有宿主那一个展开控件;③ 每个 tab 类型与 tab 体都经由原生注册路径(src/client/native/)出现 |
| 状态 |
✅ 已完成(基线升级到上游 v0.19.1:5a7e213 → 合并 e5d34ac;产物核对 toggleCluster = 0) |
R2 — 补齐「信息层」标签页
| 项 |
内容 |
| 现象 |
宿主有会话树、上游有工作台,但没有「这个会话的智能体拓扑 / 应用 / 画像」这一层信息 |
| 根因 |
上游聚焦文件工作台,信息层属于使用方(本 fork)的业务诉求 |
| 需求 |
提供三个信息层标签页:apes:agents(智能体)、apes:apps(应用)、apes:profile(画像),按 DSH 标准 TabDescriptor 注册 |
| 验收标准 |
① 三个 tab 进入原生 guide(带图标、可开合分栏);② order 取 60/65/70,与原生 10–50 不冲突;③ 单实例(single);④ 文案走 i18n(zh/en 双语齐全) |
| 状态 |
✅ 已完成(src/client/apes/,随基线同步进 v0.19.1 与 v0.24.1 两条线) |
R2.1(收敛) — 最初的 apes:tasks 已移除:它与原生会话树信息重叠,属重复建设。当前信息层为三 tab。
R3 — HTML 预览必须能在桌面壳里显示(且不牺牲沙箱)
| 项 |
内容 |
| 现象 |
预览 HTML 文件时 iframe 只显示一行 forbidden(DSH Desktop 扩展模式) |
| 根因 |
三层因果:① 桌面壳给所有路由套一层围栏,扩展模式下 ordinaryBrowserEnabled 恒为 false,不带 Electron 注入的 x-dsh-desktop-renderer 头一律 403;② 该头只发给 mainFrame 与同源子框架;③ 预览 iframe 的 sandbox 令牌不含 allow-same-origin,请求时源为 null → 拿不到头 → 403。与本次基线升级无关(v0.18.0 起行为一致) |
| 需求 |
在保持不透明源沙箱边界的前提下让预览可用 |
| 验收标准 |
① 沙箱态下自包含 HTML(含内联脚本/样式)完整可见;② sandbox 令牌一个字符不变(不加 allow-same-origin);③ 解锁态下多文件 HTML 的相对资源也能加载;④ 取文档失败时仍能把路由的错误答复透出,而不是白屏 |
| 状态 |
✅ 已完成(4c242ac:主框架 fetch 取文档 → srcDoc 交付,见 03-功能说明) |
R4 — 插件面板不得盖住宿主与其他插件的弹窗
| 项 |
内容 |
| 现象 |
打开「社区插件市场」(宿主自带的 dsh-community-market)时,弹窗左下角被本插件的文件面板切掉 |
| 根因 |
桌面壳给上游 #root 打标 data-dsh-desktop-content-viewport 并施加 isolation: isolate——#root 成为层叠上下文,宿主的 overlay 层(.dshDesktopOverlay,z-index: 1000)就在其中;而插件的面板宿主挂在 document.body(在该上下文之外)且是带 z-index: 25 的定位元素,于是整块画在其上,宿主 overlay 的 1000 根本没参与竞争 |
| 需求 |
遵守宿主的层叠契约:在 app 内容之上、在宿主 overlay 层之下 |
| 验收标准 |
① 插件市场弹窗完整盖住本插件面板;② 本插件面板仍在对话内容之上;③ 非桌面壳部署(纯网页)行为不变 |
| 状态 |
✅ 已完成(4422001:宿主挂载点改为 #root[data-dsh-desktop-content-viewport],无标记时回退 document.body) |
R5 — 可运维:版本线可预期、升级可回滚
| 项 |
内容 |
| 现象 |
跟随上游新版本时,插件可能静默失效(不报错、不加载、无日志),排查成本高 |
| 根因 |
宿主启动时的兼容性预检 semver.satisfies(host, peerRange, { includePrerelease: true }):caret 范围跨 minor 必为 false → 整行禁用 |
| 需求 |
① 同时维护两条互相独立的版本线(旧宿主线 / 新宿主线),各自钉住可用的上游基线与 peer 范围;② 每次升级都有可回滚锚点(分支 + tag);③ 文档写清「哪条线配哪个宿主」 |
| 验收标准 |
① main(1.2.0 / 上游 v0.19.1 / peer ^0.1.5-rc.1)与 sync/v0.24.1(1.3.0 / 上游 v0.24.1 / peer ^0.2.0-rc.1)均可独立构建并通过门禁;② 远端有 backup/* 分支与 apes-v* tag 作为锚点;③ 部署指南给出选线决策 |
| 状态 |
✅ 已完成(见 05-运维手册) |
三、非目标(scope lock)
| 不做 |
原因 |
| 新增上游之外的工作台面板(文件 / 终端 / 浏览器) |
属上游与宿主职责;本 fork 只用它们,不重造 |
| 团队 / 房间 / 多智能体协作面板 |
属宿主 dsh-background-agents 一类能力的职责 |
为「能用」而放宽沙箱(例如给预览 iframe 加 allow-same-origin) |
安全底线:不拿安全边界换便利(R3 明确要求保住不透明源) |
| 直接 merge 上游提交 |
冲突面大、易引入无关变更;改用测量式 re-base(见 07-开发与测试) |
四、约束条件
- 安全边界不可降级:HTML 预览与浏览器类内容一律在不透明源沙箱中渲染;新增能力不得要求放宽它。
- KISS / DRY:一处逻辑只写一遍(例如两处 HTML 预览共用
HtmlPreviewFrame)。
- 双语:所有面向用户的文案必须同时有
zh 与 en(本次会话新增文案遵循此约定)。
- 可回滚:任何升级前先留分支/tag 锚点,改动都能一条命令回退。
- 不污染运行环境:不把未验证的新线同步进正在使用的 DSH profile。
五、需求 → 实现 → 锚点
| 需求 |
主要实现位置 |
关键提交 |
| R1 单一侧边栏 |
src/client/native/(原生侧边栏适配层) |
5a7e213 / e5d34ac |
| R2 信息层三 tab |
src/client/apes/(tabs.tsx / icons.tsx / locales.ts) |
随 5a7e213、e5bbef1 同步 |
| R3 HTML 预览 |
src/client/HtmlPreviewFrame.tsx + src/client/html-preview.ts |
4c242ac |
| R4 层叠契约 |
src/client/desktop-env.ts(panelHostParent)+ src/client/index.tsx |
4422001 |
| R5 版本线可运维 |
分支 main / sync/v0.24.1、tag apes-v1.1.0-pre-sync、apes-v1.2.0 |
4422001 / e5bbef1 |