# DSH 文件工作台插件（Vue 3 + Vite）

> 🌐 简体中文 | [English](README.md)

在 DSH 会话视图的**右侧面板**内提供三个能力，共用同一个工作区根：

- 🗂 **文件工作台**（tab kind `workbench`）：Win11 资源管理器风格的文件管理器
- 📝 **文件编辑器**（tab kind `vscode`）：CodeMirror 多标签代码编辑器 + 项目树
- ▶ **终端**：node-pty（ConPTY）常驻 shell，**全局单例**，跨面板常驻不重建

在此之上还有：**Git / SVN 管理面板**、把文件作为官方 `@路径` 引用送进会话输入框、
后台任务面板、用子代理处理选中文件。

文件**查看**统一改道到 **DSH 右侧原生查看器**（Markdown / 代码高亮 / 图片 / PDF / HTML / 纯文本）；
需要就地编辑时用文件编辑器，或在列表右键「编辑」打开内置记事本。

## 面板与入口

| 面板 | tab kind | guide 入口 | 说明 |
| --- | --- | --- | --- |
| 文件工作台 | `workbench` | order 100 | 右侧栏 guide 区点击打开，首次自动定位当前会话工作区目录 |
| 文件编辑器 | `vscode` | order 101 | 同上，排在文件工作台下方 |
| 终端 | — | — | 工具栏终端按钮，或在目录右键「在终端打开」 |

> 入口只有右侧栏 guide 卡与标签，不再有输入框按钮 / 顶部抽屉。

## 功能一览

### 🗂 文件工作台（资源管理器）

- **单窗口 Win11 树**：主页 / 图库 / 此电脑盘符 / 回收站 / 收藏 / 会话文件；
  可拖拽分隔条（默认 3:7），命令栏 + 状态栏，目录优先 + 大小写不敏感排序。
- **盘符真实卷标**：读取系统卷标显示为 `卷标 (C:)`，无卷标回退本地化的「本地磁盘 (C:)」。
- **视图档位**：超大 / 大 / 中 / 小图标、列表、详情、内容、平铺共 8 档；
  详情视图列宽可拖拽；可切换是否显示扩展名。
- **搜索**：聚焦当前目录递归检索文件名与内容，支持区分大小写 / 正则、虚拟滚动；
  支持对内容命中做跨文件批量替换。
- **CRUD**：新建文件 / 目录、重命名、删除（带确认）、复制 / 剪切 / 粘贴、
  鼠标拉框多选、批量操作、外部拖拽上传、压缩 / 解压。
- **回收站**：与文件列表共用同一套 UI（8 档视图 / 排序 / 多选 / 拉框一致），
  操作换成 还原 / 永久删除 / 清空回收站。
- **Git 徽标**：文件状态（`?` / `A` / `M` / `D`）徽标 + 右键 Git 操作。
- **记事本**：右键「编辑」打开内置文本编辑器（另存 / 剪贴板 / 未保存二次确认）。
- **后台任务**：上传、压缩等长任务在后台任务面板显示进度与结果，可查历史归档。
- **子代理**：右键「用子代理处理」，就选中文件 / 目录发起官方子代理会话。
- **导航**：后退 / 前进 / 上级 / 回到会话目录、面包屑地址栏、收藏、会话触碰文件（SSE 实时）。

### 📝 文件编辑器

- **项目树**：展开状态与滚动位置持久化；单击选中、双击打开；右键
  新建文件 / 文件夹、重命名、删除、刷新、添加到会话。
- **多标签编辑**：CodeMirror 6，语言按扩展名**动态加载**（TS/JS/JSON/HTML/CSS/Markdown/YAML/XML/
  Python/SQL/Java/C++/Rust/Go/PHP，以及 C#/shell/Ruby 等 legacy 模式；无匹配回退纯文本）。
- **标签栏右键菜单**：关闭 / 保存并关闭 / 关闭其他 / 关闭右侧标签页 / 关闭全部。
- **编辑器右键**：格式化内容、保存；`Ctrl+S` 保存；未保存关闭时二次确认；只读文件有明确标识。
- **打开文件夹**：两栏选择器（左栏「我的电脑 + 快捷方式」，右栏对应文件夹），
  支持**双击下钻、单击选中**，另可新建文件夹或直接输入路径。
- 与文件工作台**共用同一个全局终端**。

### ▶ 终端

- **ConPTY 常驻 shell**（node-pty）：真实控制台语义——退格逐字符删除、回车即时执行、
  全屏 TTY 程序与中文输出正常；`cmd` / `powershell` 可切换。
- **多标签**（上限 9），每个标签一个独立后端会话；会话跨面板关闭存活，重连即续传输出。
- **浮窗**：可拖动、右下角缩放、双击复位；最小化收进右下角 **dock 栏**（跨面板常驻，可还原）。
- **关闭即清理**：Windows 下以 `taskkill /T` 终结整棵进程树，避免 npm / python / node 孤儿残留。
- **搜索与显示**：Ctrl+F 搜索输出（区分大小写）、字号增减、清屏。
- **键位**：`Ctrl+C` 有选区时复制（无选区放行 SIGINT）、`Ctrl+V` 粘贴、`Ctrl+F` 搜索、`Ctrl±` / `Ctrl+0` 字号。
- **权限徽标**：显示当前终端是「管理员」还是「普通权限」，见下文[权限模型](#权限模型终端管理员模式)。
- **官方终端后端**：本机 shell 的进程层（PTY 创建 / 重连 / 清理）在宿主官方 `ctx.webTerminals`
  服务可用时委托给官方实现，不可用时自动回退插件自建后端；SSH 终端始终走插件自建 SSH 通道。

### 🌿 Git / SVN 管理面板

两个面板都可从文件工作台与文件编辑器中打开（右键 → 打开管理面板），均按左侧窄栏分区：

**Git**（7 个分区）

| 分区 | 能力 |
| --- | --- |
| 变更 | 暂存区 / 未暂存 / 未跟踪三组；行内暂存、取消暂存、忽略、还原；全部暂存；提交（含快捷提交） |
| 历史 | 提交图（全部 / 当前分支）+ 提交详情（hash / 作者 / 时间 / parents / refs / 文件清单 / 补丁）；`reset`（soft / mixed / hard）、`revert`、`cherry-pick` |
| 分支 | 新建并切换、重命名、本地与远程分支列表、切换、合并到当前、推送、删除、检出远程分支 |
| 标签 | 新建、拉取全部、发布 Release、查看、拉取远程标签、推送、删除 |
| 远程 | 新增、修改 URL、删除 |
| 贮藏 | 新建、查看、应用 / 删除 |
| 命令行 | 内置 git CLI，直接跑任意 git 子命令并显示输出 |

另有文件级 **diff 视图 / 文件历史 / blame**，以及分支上下游 `↑ahead ↓behind` 显示。

**SVN**（3 个分区：变更 / 日志 / 输出）

- 更新、清理、检出（URL + 目标目录）、加入版本控制、还原、解决冲突、提交（选中或全部）。
- 文件级 diff / blame；工作副本 URL 与仓库根展示。
- **忽略**走 `svn:ignore`（目录属性，作用在父目录，先读后幂等追加）。
- 未装 svn CLI 或当前目录不是工作副本时，给出明确提示与引导。

**右键菜单**统一由 `composables/domain/repoMenu.ts` 生成（单一来源），Git 提供
暂存 / 提交 / 差异 / 还原 / 忽略（写入仓库根 `.gitignore`），SVN 提供 打开管理面板 / 更新 /
加入版本控制 / 忽略。

### 🧩 外部视图注入（Activity Bar）

文件编辑器与文件工作台都支持**外部插件 / 脚本注册自定义视图**，经由一套框架无关的 Activity Bar
注册表实现——不要求 Vue/React，原生 JS 即可。完整作者文档见 [`docs/activity-bar-plugin.md`](docs/activity-bar-plugin.md)。

- **两个相互独立的注册表**，以 window 全局暴露：
  - 文件编辑器：`window.__dshFileWorkbenchVSCode__.activityBar.register(view)`
  - 文件工作台：`window.__dshFileWorkbenchWorkbench__.activityBar.register(view)`
- **契约**：每个视图是 `{ id, title, icon?, order?, mount(el, ctx), when? }`；`mount(el, ctx)`
  把 UI 渲染进 `el`，可返回清理函数（切走该视图 / 卸载时调用）。`ctx` 提供 `projectDir` / `theme`
  / `activeFile` getter、`onProjectChange` / `onThemeChange` / `onDidChangeActiveFile` 订阅，
  以及 `openFile` / `listOpenFiles` / `openDiff` / `toast`。
- **命令贡献点**（编辑器，apiVersion ≥ 2）：插件还能通过 `window.__dshFileWorkbenchVSCode__.commands`
  （`register` / `execute` / `unregister` / `list` / `has`）注册可被调用的动作——对标 VS Code 的
  `commands.registerCommand`。注册的命令在被按 id 触发前保持惰性，不会擅自改动编辑器行为。
- **状态栏项**（编辑器，apiVersion ≥ 2）：用 `window.__dshFileWorkbenchVSCode__.statusbar.register({ id, text, commandId, tooltip?, order?, when? })`
  把某个命令暴露成编辑器底部状态栏的可点击按钮，点击即以 `{ path, projectDir }` 上下文自动执行该命令 ——
  这是命令的内置触发面，无需自己找地方放按钮。
- **后台任务**（工作台，apiVersion ≥ 3）：用 `window.__dshFileWorkbenchWorkbench__.backgroundTasks`
  （`start(label, opts?) → { step, updateLabel, done, fail }`、`clearFinished`、`clearAll`）把工作台的
  任务面板当作通用进度登记处复用——插件登记的耗时任务会出现在同一个底部任务按钮里，含历史 / 归档。
  注入视图激活时，状态栏只置灰本地导航区（文件信息 / 视图切换），后台任务按钮仍可点击、可查看。
- **多语言标题**：`title` 可为普通字符串或按 locale 的对象（`{ zh, en }`），随页面语言解析。
- **位置与可见性**：工作台中注册的视图出现在回收站下方的「外部注入」导航分组，无任何注册时整组隐藏；
  当某个注入视图处于激活态时，顶部工具栏（WinMenuBar）与资源管理器的命令栏会被禁用（inert + 置灰），
  底部状态栏则只置灰本地导航区（文件信息 / 视图切换），保留后台任务按钮可点击、可查看。
- **幂等**：同 `id` 重复注册即覆盖（支持热更新），`unregister(id)` 干净移除；注册表在模块级，
  面板卸载再挂载不会丢注册。

### 🔗 会话联动

- **会话文件**：经 SSE 实时推送当前会话触碰过的文件，在导航树「会话文件」分组展示。
- **添加到会话**：把文件 / 目录作为 **DSH 官方结构化引用 chip**（`@路径`，`source: "reference"`）
  写入当前会话输入框草稿——不是拼纯文本。
- **打开改道**：会话里点文件（工具行路径、产物行、正文提及）会改道到本插件；
  工作台未挂载时自动回落到宿主原生行为。
- **跟随会话**：切换会话或会话工作目录变化时，工作区根自动跟随。

### 🎨 设置

允许操作工作区根之外的文件（root 开关）、显示隐藏文件、强调色、界面字号、字体族、
主题（跟随宿主 / 深色 / 浅色）、默认视图。

## 快捷键

全局：

| 按键  | 功能          |
| --- | ----------- |
| `?` | 打开快捷键帮助（全局） |

文件列表（焦点内）：

| 按键                     | 功能               |
| ---------------------- | ---------------- |
| `Ctrl/Cmd+A`           | 全选               |
| `Ctrl/Cmd+C / X / V`   | 复制 / 剪切 / 粘贴     |
| `Ctrl/Cmd+F`           | 聚焦筛选框            |
| `Ctrl+Shift+N`         | 新建文件夹            |
| `Delete` / `F2` / `F5` | 删除（确认）/ 重命名 / 刷新 |
| `Enter`                | 打开文件 / 进入目录      |
| `↑ ↓ Home End`         | 移动选中             |
| `Backspace` / `Alt+↑`  | 返回上级             |
| `Alt+← / →`            | 浏览历史后退 / 前进      |

文件编辑器与终端：

| 按键               | 位置    | 功能                       |
| ---------------- | ----- | ------------------------ |
| `Ctrl/Cmd+S`     | 编辑器   | 保存当前标签                   |
| 标签栏右键            | 编辑器   | 关闭 / 保存并关闭 / 关闭其他 / 关闭右侧 / 关闭全部 |
| `Ctrl+C`         | 终端    | 有选区时复制；无选区放行 `SIGINT`     |
| `Ctrl+V`         | 终端    | 粘贴                       |
| `Ctrl+F`         | 终端    | 搜索终端输出                   |
| `Ctrl±` / `Ctrl+0` | 终端    | 增大 / 减小 / 复位字号           |

## 项目结构

```
src/
  shared/
    types.ts             宿主 ↔ 客户端 ↔ Vue 共享类型
    locales.ts           中英文案字典（zh / en 两份都要同步改）
    session-files.ts     会话转写文件解析
  host/                  服务端（Cordis 插件）
    index.ts             apply：注册 /api/dsh-file-workbench 路由 + 静态资源 + 自更新
    updater.ts           启动后自更新
    fs/
      fs-tree.ts         列目录 / 排序 / 软链接 / containment 守卫
      fs-search.ts       递归搜索 + 跨文件替换
      fs-read.ts         打开 / 保存
      fs-zip.ts          压缩 / 解压
      fs-drives.ts       盘符与卷标（Win32_LogicalDisk，5 分钟 TTL 缓存）
      recycle.ts         系统回收站
    routes/
      routes.ts                资源分发表
      routes-fs.ts             文件系统（列表 / 搜索 / 读写 / 压缩 / 我的电脑）
      routes-git.ts            Git（status / diff / add / discard / log / branch / tag / remote / stash / 忽略）
      routes-svn.ts            SVN（info / status / run / 日志 / blame）
      routes-terminal.ts       终端：ConPTY 常驻 shell（SSE 流）+ 宿主提权探测 /term-env
      routes-recycle.ts        回收站
      routes-session-stream.ts 会话触碰文件 SSE
      routes-subagent.ts       子代理
      routes-task-archives.ts  后台任务归档
      routes-persist.ts        偏好持久化
      routes-util.ts           JSON 信封 / body 解析 / 静态资源 / 路径校验
    store/
      root-store.ts      工作区根
      workbench-store.ts prefs / favorites / layout 持久化
    subagent/subagent.ts 官方子代理会话
  client/                DSH 客户端桥接（TSX，注册进右侧栏，注入 Vue 产物 + 挂载）
    index.tsx            apply：注册两个右侧栏 tab、改道文件打开、注入 Vue 产物、引用通道
    RightPaneBridge.tsx  把 Vue 工作台 / 编辑器主体挂进右侧面板容器
    ComposerBridge.tsx   会话输入框引用座位（官方 `@路径` chip 写入）
    TabMenuBridge.tsx    右侧栏 tab 菜单追加项（新开编辑器 / 弹出浮窗）
    OfficialTerminalBridge.ts 官方终端桥：本机终端走宿主 ctx.webTerminals
    api.ts               「打开 tab」桥
  vue/                   Vue 3 + Vite 前端
    main.ts              入口：右侧面板挂载 + **全局终端常驻挂载**（挂 body）
    App.vue              文件工作台单窗口壳
    styles.css           全局主题变量与基础样式
    components/
      common/            WinMenuBar / NavPathBar / Icon / ContextMenu / ConfirmDialog / ShortcutHelpDialog
      business/explorer/ ExplorerPane（双栏 + 分隔条）、CommandBar、NavPane、FileListPane（列表 / 回收站）、
                         ThisPcPane、SearchPane、StatusBar、BgTaskPanel、TxtEditor
      business/vscode/   VSCodePane、ProjectTree、TabBar、CodeEditor、FolderPickerDialog、langResolver
      business/git/      GitPanel、GitDiffView、GitGraphList、SvnPanel、QuickCommit
      business/terminal/ TerminalHost（全局单例宿主）、TerminalDialog（浮窗 / 停靠）
      settings/          SettingsDialog
    composables/
      core/              useApi、settings、theme、i18n、dialog、fileTaskMeta
      domain/            git、gitGraph、svn、repoMenu（右键菜单单一来源）、terminalStore、
                         officialTerm（官方终端桥取用器）、driveName
      session/           sessionSse、tasks、listStatus
      ui/                icons、clipboard、dnd、virtual
    stores/              workbench、explorer、fileCommands、vscode、activityBar（外部视图注入注册表）
    types/               auto-imports.d.ts、components.d.ts
```

## 开发

前置：Node ≥ 20、npm（或 pnpm）。

| 命令                   | 作用                             |
| -------------------- | ------------------------------ |
| `npm run dev:vue`    | 单独跑 Vue 应用联调（自挂 `#app`，配合已运行的 host） |
| `npm run build:vue`  | 仅构建 Vue 产物（`dist/`）             |
| `npm run typecheck`  | `vue-tsc --noEmit`             |
| `npm run build`      | 完整构建：Vite(Vue) + esbuild(host/client) → `lib/` |
| `npm run build:dev`  | 同上，`--dev`                     |
| `npm run sync`       | 把 `lib/` 同步进 web profile        |
| `npm run deploy`     | `build:dev` + `sync`           |

API 基址默认 `/api/dsh-file-workbench`，可用环境变量 `VITE_API_BASE` 覆盖
（例如开发时指向 `http://localhost:xxxx/api/dsh-file-workbench`）。

**改动生效范围**（影响调试方式）：

- 只改 `src/vue/**`、`src/shared/locales.ts` → 构建 + 同步后**硬刷新浏览器**即可。
- 改了 `src/host/**` 或 `src/client/**`（例如新增路由）→ **必须重启 `dsh web`**。

## 安装到 DSH（web 档）

```bash
npm run build && npm run sync   # 构建并把产物同步进 web profile
```

装好后在 profile 里执行 `npm install`（让 cordis.patch.yml 生效），**重启 `dsh web`** 并硬刷新浏览器
（Cmd/Ctrl+Shift+R）。

> 若 `dsh web` 未内置本插件的挂载行，可在
> `~/.dsh/profiles/web/cordis.patch.yml` 追加：
>
> ```yaml
> - insert:
>     - id: dsh-file-workbench
>       name: 'dsh-file-workbench'
> ```

## 使用

1. 在 DSH 右侧栏的 guide 区点「文件工作台」或「文件编辑器」打开面板
   （首次会自动定位到当前会话的工作区目录）。
2. 工作台：左侧导航树选择位置；右侧列表双击文件夹进入、双击文件在 **DSH 右侧查看器**打开。
3. 编辑器：工具栏「打开文件夹」选定项目目录 → 项目树双击打开文件 → 多标签编写、`Ctrl+S` 保存。
4. 终端：工具栏终端按钮打开，最小化后收进右下角 dock 栏，点一下还原。
5. `?` 查看快捷键帮助。

## 权限模型（终端管理员模式）

终端 shell 由宿主以 **ConPTY** 派生，**子进程继承 `dsh web` 进程的令牌** ——
所以「终端里的命令有没有管理员权限」等于「`dsh web` 是不是以管理员启动」。

- **获得管理员终端**：以**管理员身份运行** `dsh web`（右键终端/快捷方式 →
  「以管理员身份运行」），面板内**所有**终端即拥有管理员权限。
- **徽标**：终端标签栏显示「管理员 / 普通权限」，鼠标悬停可看说明；点击给出获取指引。
  探测由 host 的 `GET /term-env` 提供（Windows 用 `whoami /groups` 的完整性级别 SID 判定，
  POSIX 用 `uid === 0`）。
- **为什么不能在插件内单开一个提权终端**：Windows 提权必须过 UAC，而走 ShellExecute / `runas`
  的提权进程**无法挂到 ConPTY 伪控制台**上，因此插件无法对单个终端提权；可行路径只有让宿主整体提权。
- 备选方案（当前未实现）：以 `sudo.exe` 做单命令级提权（需先启用 Windows sudo 且设为 inline 模式），
  或宿主注册高权限助手经命名管道桥接（引入自建提权通道，安全面较大）。

## 安全

- 所有读写路径先经根目录 containment 守卫（含符号链接解析后的再检查），拒绝越权与路径穿越。
- 工作区根之外默认只读；需在设置中开启 **root 开关**才允许写操作。
- 搜索对符号链接目录不下钻（循环安全），并对访问数与命中数设预算。
- 终端工作目录同样过保护路径校验；终止会话时清理整棵进程树。
- 持久化仅写 `{DSH_HOME|~/.dsh}/fileworkbench/` 白名单键（prefs / favorites / layout）。

## 依赖

- **Vue 3 + Vite**（前端）；**React**（DSH 右侧栏桥接，由宿主提供）；**esbuild**（host/client 构建）。
- `element-plus`（UI 组件）；`@xterm/xterm` + fit / search / web-links addon（终端渲染）。
- **CodeMirror 6**（编辑器：`@codemirror/*` 语言包按需动态加载）。
- `node-pty`（ConPTY 交互终端，原生模块，缺失时终端不可用）。
- `fflate`（压缩 / 解压）；`fzstd`（解压会话转写 zstd）。
- 复用 peer `@deepseek-ai/cordis`、`@deepseek-ai/dsh-host-webserver`。

## License

MIT
