# dsh-ui-web

> 为 DSH Web GUI 复刻 AionUi 右侧面板：Explorer 文件树与 Git 变更、Preview 多格式预览、按项目隔离的面板宽度持久化。

## Metadata

- Author: [@CAPTAIN1275](https://github.com/CAPTAIN1275)
- Repo: <https://github.com/CAPTAIN1275/dsh-ui-web.git>
- GitHub: [CAPTAIN1275/dsh-ui-web](https://github.com/CAPTAIN1275/dsh-ui-web)
- Stars: 34
- Language: TypeScript
- License: [Apache-2.0](https://spdx.org/licenses/Apache-2.0.html)
- Topics: `dsh-plugin`, `dsh-plugin-market`, `dsh-plugins`
- Forks: 2
- Open Issues: 0
- Last push: 2026-08-16T18:08:27.000Z
- Added: 2026-08-20T00:00:00.000Z

## Install

```bash
dsh plugin --profile web add github:CAPTAIN1275/dsh-ui-web/packages/dsh-aionui-panel
```

## Wiki

## 一句话定位
dsh-aionui-panel 是 DSH Web GUI 聊天区右侧的两块面板：Explorer 提供文件树、按文件名搜索、Git 变更的 stage / unstage / discard；Preview 提供 markdown / 代码 / 文档 / 图片 / PDF 等 10+ 格式的多 tab 预览，并支持面板宽度按项目隔离持久化。它把 AionUi 的右侧面板（Apache-2.0 参考实现）按官方 SDK 重新实现，数据源走宿主进程托管的真实文件系统与真实 git 仓库。

## 核心能力
- Explorer 文件树：点击文件在 Preview 打开，整行点击展开/折叠文件夹，顶部按文件名搜索（150ms 防抖、跳过 .git 与 node_modules、命中上限 200 条、扫描上限 20,000 项）。
- 拖拽文件到聊天输入框：文件树行可拖到输入框松手，相对路径插入当前草稿光标处；拖拽过程中输入框上方出现高亮提示条。
- Git 变更面板：读取真实 git status（porcelain v1 -z）并支持 stage / unstage / discard；untracked 走删除、tracked 走 restore、批量放弃弹确认。
- Preview 多 tab 预览：markdown / html / code / diff / csv / pdf / word / excel / ppt / 图片 / 文本 / url；支持源码/预览切换、分屏编辑（比例持久化）、保存（mtime 冲突检测）、下载、刷新、dirty 点、中键关闭、右键批量关闭（dirty 确认）、tab 溢出渐变指示器。
- 面板宽度可拖拽调整（rAF 帧合并）：Explorer 默认 260px / 范围 220~500px；Preview 默认 480px / 范围 340~1200px；双击把手复位默认宽度；两级钳位保证聊天区 >= 360px；折叠 = 宽度缩 0 但组件保持挂载，树展开态与预览 tab 不丢失。
- 偏好按项目隔离持久化：localStorage 键名沿用 AionUi（`chat-workspace-width-px`、`chat-preview-width-px`、`preview-panel-split-ratio`、`project-panel-collapse:<root>`、`explorer-ui:<root>`、`scm-ui:<root>`、`preview-ui:<root>`），LRU 上限 12 个 scope，非法值经范围校验后回退默认。

## 技术实现
- **语言**: TypeScript（ESM；host 与 browser 半区分层编译）
- **关键依赖**: `@deepseek-ai/cordis`（host 半区插件运行时）、`@deepseek-ai/dsh-host-webserver` 与 `@deepseek-ai/dsh-subprocess`（宿主 HTTP 路由与 git 子进程管理）、`@deepseek-ai/dsh-client-runtime` / `@deepseek-ai/dsh-client-locale` / `@deepseek-ai/dsh-client-ui-conversation`（browser 半区注入）、`react ^18.2.0`（UI 渲染）
- **架构模式**: Cordis 双半区插件 — `src/index.ts` 是 host 半区（Node 进程：fs/git 服务 + `/aionui-panel/*` 路由 + systemPrompt 公告），`src/client/index.ts` 是 browser 半区（Web GUI 侧：状态核心 + 拖拽引擎 + DOM 布局控制器 + React 组件），`src/core/types.ts` 是两侧共享的纯类型；`cordis.patch.yml` 把插件行插入 web profile 名单，`package.json#dsh.client` 声明浏览器注入与 `platform: "web"`。
- **入口文件**: `src/index.ts`（host 半区入口）、`src/client/index.ts`（browser 半区入口）、`src/host/routes.ts`（`/aionui-panel/*` 路由层，含 JSON content-type CSRF 拦截与 SSE 变更流）、`src/host/gate.ts`（workspace gate）、`src/host/fs-service.ts` / `src/host/git-service.ts`（fs / git 数据服务）

## 适用场景
在 DSH Web GUI 里开项目会话、想让 LLM 直接看到/改真实仓库文件的用户：聊天时让 agent 读 `.ts` 看 `.yaml`，或人工点开几个文件对照草稿。如果你已经在 `dsh web` 上跑 DSH、但觉得"只能打字给 agent"不够直观、希望有 VS Code 那种右侧项目浏览器感，这一插件就是补这一块的。

## 前置依赖与兼容性
| 依赖 | 最低版本 | 说明 |
|---|---|---|
| DSH 运行时 | >=0.1.0-rc.6 | `peerDependencies` 锁定 `@deepseek-ai/dsh-*` 为 `^0.1.0-rc.6`，含 `dsh-client-locale` / `dsh-client-runtime` / `dsh-client-ui-conversation` / `dsh-client-ui-slots` / `dsh-host-webserver` / `dsh-subprocess` / `dsh-system-prompt` / `dsh-workspace`（package.json:33-43） |
| 客户端运行 profile | web | `cordis.patch.yml` 把插件行插入 web profile 名册，`package.json#dsh.client.platform` 也为 `web`；headless profile 下浏览器半区不加载（cordis.patch.yml:11-13、package.json:20-32） |
| React | ^18.2.0 | browser 半区依赖，UI 组件基于 React 18 渲染（package.json:42） |
| Node.js | 未声明 | 仓库根 `package.json` 与本包 `package.json` 均无 `engines` 字段；构建/测试依赖 `tsdown@0.22.2`、`vitest@4.1.8`、`typescript@~5.7.2` |
| 平台 | 跨平台（macOS / Windows / Linux） | 仅依赖 Node 标准库（`node:fs` / `node:http` / `node:path` / `node:fs/promises`）；host 半区路径处理在 win32 上做大小写无关、分隔符无关的规范化（src/host/gate.ts:1-46） |
| 原生模块 | 无 | 没有 koffi / node-pty / `node:sqlite` 等原生绑定；git 通过 `@deepseek-ai/dsh-subprocess` 管理的子进程调用（src/host/git-service.ts:34-79） |

## 安装方式
```bash
dsh plugin --profile web add github:CAPTAIN1275/dsh-ui-web/packages/dsh-aionui-panel
```

安装后重启 `dsh web`，打开一个有工作目录的项目会话即可看到聊天区右侧的"预览"与"文件/变更"面板。

## 配置项
本插件无需 DSH 侧配置（无 cordis Schema 或 `ctx.config` 暴露项）。浏览器侧的"用户偏好"——面板宽度、折叠态、Preview 分屏比例、tab 顺序——由本插件自己写到 localStorage，按 project root 隔离，无需用户手工配置。

## 常见问题

**Q: 这个插件装上后能看到什么？**

A: 在 `dsh web` 打开的项目会话中，聊天区右侧会多出两块面板：Explorer（文件树 + Git 变更 tab）与 Preview（多 tab 文件预览）。文件树中的文件可拖到聊天输入框松手，把相对路径插入草稿光标处，agent 会按需读取该文件，无需手敲路径。

**Q: 文件预览支持哪些格式？**

A: markdown、html、code、diff、csv、pdf、word、excel、ppt、图片、文本、url 共 10+ 种格式。支持源码/预览切换、分屏编辑（比例持久化）、保存（mtime 冲突检测）、下载、刷新、dirty 点、中键关闭、右键批量关闭（dirty 确认）、tab 溢出渐变指示器。

**Q: 必须用 DSH Web GUI（profile=web）才能看到面板吗？**

A: 是。`cordis.patch.yml` 把插件行插入 web profile 名单，`dsh.client.platform` 字段也为 web；CLI/headless profile 下浏览器半区不会加载，所以这两块面板只在 DSH Web GUI 里出现。

**Q: 数据来源是真实文件系统还是 mock？**

A: 真实。宿主进程经 `/aionui-panel/*` HTTP 路由提供目录列举、文件读写、文件名搜索、git status / diff / stage / unstage / discard；递归 fs.watch 与每 2 秒一次的 git 轮询组成 SSE 变更流，文件树与 Git 状态实时刷新。

**Q: 工作区路径不在已注册 workspace 里会被怎么处理？**

A: 直接拒绝。所有请求的 project root 都过 workspace gate：realpath 规范化后必须落在 host 工作区注册表返回的某个 workspace 内或其子目录；越界返回稳定错误码 `path-outside-root`。同时路由层强制 JSON content-type 校验，拦截无 CORS 预检的表单 CSRF。

**Q: 我没装 git 二进制能用吗？**

A: 文件树和预览完全可用。host 半区做一次 git 可用性探测；探测失败则打日志并下发 `gitUnavailable` 事件，SCM tab 进入友好的"未安装 git"状态而不再每 2 秒重试 spawn。

**Q: 面板宽度、折叠状态会保存吗？**

A: 按项目隔离保存到 localStorage，键名沿用 AionUi 命名（`chat-workspace-width-px`、`chat-preview-width-px`、`preview-panel-split-ratio`、`project-panel-collapse:<root>`、`explorer-ui:<root>`、`scm-ui:<root>`、`preview-ui:<root>`），LRU 上限 12 个 scope，超出最久未用被淘汰。

**Q: Agent 会知道这个面板的存在吗？**

A: 会。host 半区通过 systemPrompt section（order=210）向所有 agent 公告本插件能力、限制与协作方式；用户提到"右侧面板 / 预览面板 / 文件树 / 变更面板"时模型即知道对应本插件。

**Q: 出现 bug 时如何排查？**

A: 浏览器侧任何 DOM/runtime 接线失败只 `console.error` 不会抛，确保 web shell 不被插件拖崩；打开开发者工具 Console 过滤 `dsh-aionui-panel` 即可看到失败原因。

## 上手难度
入门 — 装好插件、重启 `dsh web`、打开项目会话即可看到面板，所有交互都有即时可视反馈；不需要写配置或调用任何 API。

## 已知问题与限制
- host 半区文本读取单 tab 上限 80,000 字符，图片读取 data URL 上限 8 MB，超出即被截断（src/host/fs-service.ts:18-21）。
- 文件名搜索命中上限 200 条、扫描上限 20,000 项，且固定跳过 `.git` 与 `node_modules`；命中超过上限会以 `truncated` 标记返回（src/host/fs-service.ts:22-28）。
- git 可用性探测仅一次：探测失败后 SCM tab 进入"未安装 git"状态并停止重试，但文件系统监听与 Preview 仍正常（src/host/routes.ts:101-138）。
- 非文件树拖拽场景（如直接拖 OS 资源管理器文件到 DSH Web）仍由 DSH Web 自身的图片 drop handler 处理，本插件只接管文件树行到聊天输入框的内部拖拽（src/client/drag/file-drag.ts:7-12）。
- 用户开启系统 `prefers-reduced-motion` 后全局禁用面板过渡动画，包括拖拽边的瞬时切换（README.md:50）。
- 文件树固定隐藏 `.git` 目录（`src/host/fs-service.ts:27-28`），如需查看 `.git` 内部文件请改用终端或 `dsh-ssh` 类插件。

---

This document is auto-generated by [deepseek-plugin.org](https://deepseek-plugin.org). HTML page: [dsh-ui-web](https://deepseek-plugin.org/plugins/CAPTAIN1275/dsh-ui-web/packages/dsh-aionui-panel)
Wiki generated by AI (model: `MiniMax-M3`)
