UI-Enhance
August 21, 2026 · View on GitHub
浏览器端(client bundle)增强插件,为 DeepSeek Harness Web 界面增量添加官方没有的交互能力。 原则:只做增量,不覆盖/替换官方渲染器。
功能现状
| 能力 | 状态 | 说明 |
|---|---|---|
| ② 会话状态面板 | ✅ 已验证 | 会话头部显示 🟢运行中/⚪空闲 + 当前工具名 + 排队计数 |
| ④ 打开 IDE | ✅ 已验证 | 会话头部右上角连体按钮「⧉ 打开」,▾ 菜单只显示本机已装 IDE(VS Code/Cursor/Windsurf/Trae 动态检测) |
| ③ 工具调用可视化 (A1) | ✅ 已验证 | 头部 🔧N 徽标点击展开统计面板:总数/成功/失败/均耗 + 工具分布条 + 最近调用流水(真实耗时) |
| 项目文件树 | ✅ 已验证 | 右上角最右「⋮☰」按钮,右侧浅色融入式文件树:递归目录 + git 状态徽标;可拖拽调宽(220-520);双击文件在 IDE 中打开;头部路径显示+复制(./ 开头最多三行、选中高亮);底部 git 汇总(分支/↑领先/N 处变更/最近提交);fs.watch+SSE 实时刷新(文件增删/git 提交即时更新);跟随当前会话的工作区(session→workspace 反查,切会话即切目录) |
| 布局与精简 | ✅ 已验证 | 头部顺序:状态→统计→IDE→文件树(最右);隐藏官方「Session log 下载」(同 id + priority -100 覆盖) |
| ① 消息渲染增强 | ⏸ 暂缓 | 官方已完善(markdown/代码块复制/思考行/操作条),等具体需求 |
架构图
┌──────────────────────────────────────────────────────────┐
│ plugins/ui-enhance(npm 包,同时是 DSH 插件条目) │
│ package.json: dsh.client.platform=web + exports["./client"] │
├──────────────────────────────────────────────────────────┤
│ 构建: tsdown → lib/client.js(closure-factory) │
│ tsc → lib/index.js (Node 宿主半身) │
│ 部署: install-plugins.mjs(构建→自检→pnpm file:→验证) │
├──────────────────────────────────────────────────────────┤
│ Node 半身 (lib/index.js) │
│ inject: ['webServer', 'workspaceRegistry'] │
│ ├─ ctx.webServer.register('/api/ui-enhance/...') │
│ │ ├─ POST /open-in-editor {editor} → IDE 命令映射 │
│ │ ├─ GET /editors → 检测本机已装 IDE │
│ │ ├─ GET /tree?dir= → 文件树 + git 汇总(分支/计数/提交) │
│ │ └─ GET /events → SSE 实时推送(fs.watch→changed) │
│ └─ workspaceRegistry.list() → 取工作区路径 │
│ │
│ Client 半身 (lib/client.js) │
│ inject: ['slots', 'locale'] │
│ apply(ctx) → ctx.slots.inject('conversation.session. │
│ header.utilities', ...) │
│ ├─ SessionStatusPanel(② 状态面板) │
│ │ useSession 快照 → running/tool/queue │
│ ├─ ToolCallStats(③ 工具统计,A1) │
│ │ 快照 nodes → 次数/分布/耗时 │
│ ├─ FileTreePanel(项目文件树) │
│ │ ⋮☰ 开关 + 右抽屉(可拖拽) + 路径复制 + git 徽标 │
│ │ fetch('/api/.../tree?dir=&session=') + 双击 open │
│ │ session 跟随:slot 注入 sessionId → 会话所属工作区 │
│ └─ OpenInEditorButton(④ 多IDE按钮) │
│ ▾菜单选 IDE + fetch('/api/ui-enhance/open-in-editor')│
└──────────────────────────────────────────────────────────┘
技术要点
- client bundle 形态:DSH 要求 client bundle 是
window.__ModuleLoader__.load({id, factory})closure-factory(tsdownbanner/footer包装,产物 git 忽略、安装时构建) - external:react 全家桶 +
@deepseek-ai/*走宿主模块表(deps.neverBundle/alwaysBundle) - slot 选择:
conversation.session.header.utilities是 list 型 slot(非 keyed), 与官方/dsh-webui 通过id区分,无冲突 - 禁止触碰:
conversation.chat.node是 keyed slot,官方已占用assistant-step/tool-call/user等 key——自定义 UI 不在此注册 - client→host 通道:Node 半身注册
webServerHTTP 路由,client 用fetch('/api/...')调用(dsh-webui 同款范式);实时推送用 SSE(/api/ui-enhance/events长连接 + fs.watch)
开发/部署/验收
# 部署(构建 + Node 自检 + 安装到 profile + 验证)
node scripts/install-plugins.mjs
# 单独自检 Node 半身
node scripts/check-plugin.mjs plugins/ui-enhance/lib/index.js
# 重启 DSH 使 Node 路由生效(前端刷新即可拉新 bundle)
# 验收:会话头部 → 状态面板 + 🔧统计 + ⋮☰文件树 + ⧉IDE(顺序:状态→统计→IDE→文件树最右)
# POST /api/ui-enhance/open-in-editor → {"ok":true,...}
# GET /api/ui-enhance/tree?dir= → 文件树 + git 汇总
# 实时刷新:面板打开时创建/删除临时文件 → 条目即时增删(fs.watch+SSE)
事故教训(inject 门禁)
现象:Node 半身源码里访问 ctx.webServer,但未在 inject 声明,
DSH 启动时 cordis 抛 cannot get property "webServer" without inject 直接崩。
根因:cordis(DSH 宿主框架)强制「访问服务必须在插件的 inject 导出里声明」。
这是运行时校验,--dump-config 和旧版自检(stub ctx 直接展开服务)都拦不住。
制度修复(已落地):
scripts/check-plugin.mjs:stub ctx 改为 Proxy 模拟真实 cordis 注入门禁—— 访问未在inject声明的服务即抛与 DSH 完全一致的报错;ctx.get()(内置查找) 放行不误伤scripts/install-plugins.mjs:client 包安装链路在构建后对lib/index.js跑 Node 半身 自检,未通过则跳过安装(DSH 不会因此起不来)- 插件代码要求:凡访问
ctx.<服务>必须同步加进export const inject = [...]