docs: rewrite README — features first, then install-from-source
Restructured per the user's request: a full feature walkthrough (explorer, CodeMirror editor with preview/edit toggle, terminal, git, split workbench, tab bar, session isolation, interception) followed by step-by-step source installation (clone → pnpm install/build → web profile registration → restart). Corrected stale limitations (syntax highlighting now shipped; the sidebar squeezes the layout instead of floating).
This commit is contained in:
@@ -1,78 +1,123 @@
|
||||
# dsh-better-sidebar
|
||||
|
||||
A DeepSeek Harness web plugin providing a **VSCode-like right sidebar** with a
|
||||
file explorer, file editor/preview, an interactive terminal, and a source
|
||||
control panel — **isolated per conversation session**.
|
||||
DeepSeek Harness Web GUI 的 **VSCode 风格右侧侧边栏**插件:文件资源管理器、文件编辑/预览、交互式终端、Git 面板,**按会话(conversation)记忆与隔离**。样式完全复用 `--dsw-*` 主题变量与 `@deepseek-ai/dsh-client-ui-primitives`,观感与 GUI 原生一致。
|
||||
|
||||
- 右侧侧边栏(文件夹预览 / 文件编辑与预览 / 终端 / Git)——按会话记忆与隔离
|
||||
- Explorer: 懒加载目录树,根目录 = 当前会话工作目录
|
||||
- Editor: CodeMirror 文本编辑(自动换行 + 按扩展名语法高亮、脏点 + Ctrl/Cmd+S 保存)、图片查看;Markdown 支持预览/编辑切换(预览渲染未保存草稿)
|
||||
- Terminal: xterm.js + node-pty(每会话最多 3 个,进程跨刷新存活)
|
||||
- Git: status / diff / stage / commit / branch / history(基础集)
|
||||
- 分栏工作台: VSCode 式拖拽分栏(拖 Tab 到分栏边缘即左右/上下拆分,拖到中间合并)、
|
||||
分隔线拖拽、面板宽度拖拽;折叠后右缘展开按钮常驻
|
||||
- Tab 栏: 最大宽度 160px、横向滚动、`+` 紧贴最右 Tab(溢出时吸附右缘)、`+` 菜单新建 Tab;空分栏显示可打开类型卡片(点击即开);切换 Tab 不卸载内容(终端保持连接与回滚、编辑器保留未保存草稿)
|
||||
- 拦截: 对话"产出文件"行点击改为在侧边栏打开
|
||||
- 样式完全复用 `--dsw-*` 主题变量与 `@deepseek-ai/dsh-client-ui-primitives`
|
||||
## 功能
|
||||
|
||||
### 文件资源管理器(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. 克隆、安装、构建
|
||||
|
||||
```sh
|
||||
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` 加入:
|
||||
|
||||
```json
|
||||
"dsh-better-sidebar": "link:/绝对路径/DSH-better-sidebar"
|
||||
```
|
||||
|
||||
编辑 `~/.dsh/profiles/web/cordis.patch.yml`,追加插件行:
|
||||
|
||||
```yaml
|
||||
- insert:
|
||||
- id: better-sidebar
|
||||
name: 'dsh-better-sidebar'
|
||||
```
|
||||
|
||||
然后安装依赖:
|
||||
|
||||
```sh
|
||||
(cd ~/.dsh/profiles/web && pnpm install)
|
||||
```
|
||||
|
||||
### 3. 重启 GUI 并刷新页面
|
||||
|
||||
```sh
|
||||
pm2 restart dsh-web # 或你自己的 dsh web 启动方式
|
||||
```
|
||||
|
||||
浏览器**硬刷新**(Cmd/Ctrl+Shift+R)后,右侧出现侧边栏即安装成功。
|
||||
|
||||
### 更新
|
||||
|
||||
重新 `pnpm build`(host/client 双产物)→ `pm2 restart dsh-web` → 刷新页面;`link:` 引用无需重新 install。
|
||||
|
||||
## 开发
|
||||
|
||||
```sh
|
||||
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 包,双半结构(与 DSH monorepo 内 client 包同构):
|
||||
一个 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(`session.cwd` / fs / git / 终端 / 媒体路由一致);终端按 `${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>`):面板几何、分栏树、Tabs、树展开;读取时做结构校验(旧/损坏状态回退默认)并把宽度钳制到当前视口,防止陈旧全屏宽度压垮应用布局。
|
||||
- client bundle externals 仅模块表词条(react/cordis/ui-primitives 等),xterm 等全部内联。
|
||||
|
||||
## 安装(web profile)
|
||||
|
||||
```sh
|
||||
# 1. 构建
|
||||
pnpm install && pnpm build
|
||||
|
||||
# 2. 全局 web profile 引用
|
||||
# ~/.dsh/profiles/web/package.json dependencies:
|
||||
# "dsh-better-sidebar": "link:/Users/menghuan/Code/DSH-better-sidebar"
|
||||
# ~/.dsh/profiles/web/cordis.patch.yml 追加:
|
||||
# - id: better-sidebar
|
||||
# name: 'dsh-better-sidebar'
|
||||
|
||||
# 3. 安装依赖并重启 GUI
|
||||
(cd ~/.dsh/profiles/web && pnpm install)
|
||||
pm2 restart dsh-web # 或你的 dsh web 启动方式
|
||||
```
|
||||
|
||||
## 开发
|
||||
|
||||
```sh
|
||||
pnpm typecheck # tsc --noEmit
|
||||
pnpm test # vitest(单元 + 冒烟:真实 git/fs 交互)
|
||||
pnpm build # tsc + tsdown → lib/index.js + lib/client.js
|
||||
pnpm watch # tsdown --watch(client bundle 热重建)
|
||||
```
|
||||
|
||||
改完 host/client 后重新 `pnpm build`,再重启 `dsh-web` 生效。
|
||||
|
||||
## 依赖说明
|
||||
|
||||
- `node-pty` / `ws` / `xterm` / `@xterm/addon-fit` / `clsx`:npm 常规依赖(node-pty 使用随包预编译二进制,无源码编译)。
|
||||
- pnpm 会剥离 node-pty 预编译 `spawn-helper` 的可执行位(`posix_spawnp failed`);插件启动时自动恢复(
|
||||
`ensureSpawnHelper`,与 `@deepseek-ai/dsh-pty-local` 的 postinstall 同思路,对 link 安装也生效)。
|
||||
- `@deepseek-ai/*` 包仅以 `link:` 指向 `~/.dsh/source/current`(DSH 源码 checkout,构建产物已存在),仅用于类型;运行时只经模块表消费 `dsh-client-ui-primitives`。
|
||||
- 所有 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 身份。
|
||||
- 路由受 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(手动刷新)。
|
||||
- 工具行内的文件打开按钮(核心代码)不可拦截,仅"产出文件"行被接管。
|
||||
- 侧边栏为悬浮面板(核心 AppFrame 无右侧插件位),不修改核心布局。
|
||||
- Git 无 push/pull/fetch;无文件 watcher(手动刷新)
|
||||
- 工具行内的文件打开按钮(核心代码)不可拦截,仅"产出文件"行被接管
|
||||
- 终端 Tab 拖拽到另一分栏时会重挂载(shell 重开);切换 Tab 不会
|
||||
- 仅验证 macOS(node-pty 预编译二进制平台相关)
|
||||
|
||||
Reference in New Issue
Block a user