Menghuan1918 d1cdca3324 terminal: keep the pty alive while its tab is open, whatever the view does
The close frame was sent on every unmount, so switching conversations (or
refreshing) killed the shell even though the tab was still open; coming
back spawned a fresh terminal. Now the unmount close frame only fires when
the tab is truly gone (checked against the per-session store state), so a
bare unmount hands the process to the host's reconnect grace and the next
connect reattaches the SAME shell with its transcript. Closing a tab
releases the quota immediately: the socket-open path keeps the close
frame, and a new pty.close API covers the socket-down (reconnect loop)
case that previously left a 30s zombie holding the quota.

The host also records the spawn cwd and respawns when a reconnect carries
a different authoritative cwd — the page-load hydrate race can attach the
real session cwd after the first connect fell back to the process cwd, and
a shell in the wrong directory must not linger.
2026-08-08 17:24:08 +08:00
2026-08-08 00:04:01 +08:00
2026-08-08 16:23:36 +08:00

dsh-better-sidebar

DeepSeek Harness Web GUI 的 VSCode 风格右侧侧边栏插件:文件资源管理器、文件编辑/预览、交互式终端、Git 面板,按会话(conversation)记忆与隔离。样式完全复用 --dsw-* 主题变量与 @deepseek-ai/dsh-client-ui-primitives,观感与 GUI 原生一致。

image image

功能

文件资源管理器(Explorer)

  • 懒加载目录树,根目录 = 当前会话工作目录(cwd)
  • 目录优先排序、隐藏文件(点开头)变暗显示、每层 1000 项上限
  • 点击文件在侧边栏打开编辑器;刷新按钮重载

文件编辑与预览(Editor)

  • CodeMirror 6 编辑器:自动换行 + 按扩展名语法高亮(js/ts/jsx/tsx、json、python、html、css、xml、yaml、sql、java、c/c++、rust、go、php、shell、toml、nginx、dockerfile、properties…),one-dark 深色主题
  • 脏点标记 + Ctrl/Cmd+S 保存(原子写入);512KB 截断横幅、二进制文件提示
  • 图片直接预览(媒体路由);Markdown 支持 预览/编辑 切换——预览实时渲染未保存草稿,切换不丢编辑状态
  • 编辑器/终端/资源管理器在切换 Tab 时不卸载:终端保持连接与回滚,编辑器保留草稿

终端(Terminal)

  • xterm.js + node-pty(真实 shell),每会话最多 3 个;进程跨页面刷新存活(断线自动重连 + 转录回放)
  • 关闭 Tab 立即释放配额;连续失败后停止重连并显示原因与重试按钮

Git 面板

  • status(暂存/未暂存分组)、按文件 diff(HEAD vs 工作区/暂存区)、stage/unstage(单个与全部)、commit、分支切换、提交历史——基础集

VSCode 式分栏工作台

  • 拖 Tab 到分栏边缘(左/右/上/下 25% 区)即拆分新分栏,拖到中间合并;拖到另一个 Tab 上则插入其前
  • 分隔线拖拽调整比例;面板宽度从左侧缘拖拽
  • 面板折叠滑出隐藏,右缘展开按钮常驻;全屏展开按钮(还原为内容区一半)

Tab 栏

  • Tab 最大宽度 160px、横向滚动;+ 按钮紧贴最右 Tab(溢出时吸附右缘)
  • + 菜单新建 Tab(Explorer / Git / 终端,终端受 3 个上限约束);中键点击关闭 Tab
  • 空分栏不再显示空提示,而是可打开类型卡片(点击即开)

会话隔离与拦截

  • 侧边栏布局/分栏/Tab/目录展开按会话持久化(localStorage),切换会话即切换整套状态
  • 侧边栏占用布局(挤窄对话列而非悬浮遮挡,动画过渡);宽度永不超过视口,陈旧状态自动净化
  • 拦截对话"产出文件"行:点击改为在侧边栏打开,而不是系统默认程序

从源码安装

前置条件

  • 已安装 DSH(dsh web 可运行),Node.js ≥ 20、pnpm ≥ 10
  • DSH 源码 checkout 位于 ~/.dsh/source/current(@deepseek-ai/* 类型依赖以 link: 指向它;若 checkout 在其他路径,修改 package.json 中对应的 link: 路径)

1. 克隆、安装、构建

git clone https://github.com/dsh-external/DSH-better-sidebar.git
cd DSH-better-sidebar
pnpm install
pnpm build        # 产物: lib/index.js (host) + lib/client.js (client)

2. 注册到 web profile

编辑 ~/.dsh/profiles/web/package.json,在 dependencies 加入:

"dsh-better-sidebar": "link:/绝对路径/DSH-better-sidebar"

编辑 ~/.dsh/profiles/web/cordis.patch.yml,追加插件行:

- insert:
    - id: better-sidebar
      name: 'dsh-better-sidebar'

然后安装依赖:

(cd ~/.dsh/profiles/web && pnpm install)

3. 重启 GUI 并刷新页面

pm2 restart dsh-web   # 或你自己的 dsh web 启动方式

浏览器硬刷新(Cmd/Ctrl+Shift+R)后,右侧出现侧边栏即安装成功。

更新

重新 pnpm build(host/client 双产物)→ pm2 restart dsh-web → 刷新页面;link: 引用无需重新 install。

开发

pnpm typecheck   # tsc --noEmit
pnpm test        # vitest(单元 + 冒烟:真实 git/fs/node-pty 交互)
pnpm build       # tsc + tsdown → lib/index.js + lib/client.js
pnpm watch       # tsdown --watch(client bundle 热重建)

架构

一个 npm 包,host/client 双半结构(与 DSH monorepo 内 client 包同构):

半 入口 职责
host src/index.ts → lib/index.js cordis 插件:/sidebar/api/* JSON API、/sidebar/file 媒体路由、/sidebar/ws/terminal WebSocket;fs / git / pty 服务
client src/client/index.tsx → lib/client.js 浏览器 bundle(__ModuleLoader__.load 闭包工厂):portal 侧边栏 + 各视图 + turnTail 拦截
  • 所有 API 携带 sessionId;cwd 权威值取自会话 header,会话未附加(页面加载竞态)时回退客户端摘要 cwd,再回退进程 cwd;终端按 ${sessionId}:${tabId} 键控
  • 路由与 /api 同款信任围栏(Host 头 loopback / connection.trustedHosts,src/trust-fence.ts,拷贝自 @deepseek-ai/dsh-client-connection,BSD-3-Clause)
  • client 状态按会话持久化到 localStorage(dsh-sidebar:v1:<sessionId>),读取时结构校验 + 宽度钳制视口
  • client bundle externals 仅模块表词条(react/cordis/ui-primitives 等),xterm/CodeMirror 等全部内联

安全边界

  • 路由受 Host 头信任围栏保护(与 /api 一致;0.0.0.0 部署时由 dsh web 启动器动态派生的 LAN IP 列表生效)
  • fs.write 仅文本写入、原子替换(临时文件 + rename);/sidebar/file 仅限会话 cwd 内的媒体文件
  • 提交/分支操作仅调用 git CLI,绝不设置 git 身份

已知限制(v1 非目标)

  • Git 无 push/pull/fetch;无文件 watcher(手动刷新)
  • 工具行内的文件打开按钮(核心代码)不可拦截,仅"产出文件"行被接管
  • 终端 Tab 拖拽到另一分栏时会重挂载(shell 重开);切换 Tab 不会
  • 仅验证 macOS(node-pty 预编译二进制平台相关)
S
Description
WorkBuddy/Tutti-style right sidebar enhancement for DeepSeek Harness: Tasks / Agents / Profile tabs, configurable display name (default apes--sidebar, preset feyOS). Built on dsh-better-sidebar.
Readme MIT
6.6 MiB
Languages
TypeScript 93.5%
CSS 4%
Shell 1.6%
JavaScript 0.5%
PowerShell 0.4%