# dsh-file-explorer [English](README.md) | 中文 DSH Web 的文件浏览器。页面边缘有一个浮动「文件」按钮,点击打开左侧抽屉(工作区文件树),点文件在右侧浮出可拖拽/缩放的预览框。点击会话区"生成的文件"芯片或工具行文件链接,会自动在预览框中打开对应文件,而非跳到系统默认应用。 ## 截图 | 浅色 | 深色 | | ---- | ---- | | ![文件浏览器(浅色主题)](./assets/dsh-file-explorer_light.png) | ![文件浏览器(深色主题)](./assets/dsh-file-explorer_dark.png) | ## 功能 1. **浮动入口**:页面左侧边缘固定一个「文件」按钮。它默认收起为小巧低调的把手,刻意不引人注目、不干扰主工作区;悬停或点击时展开,即可开关文件浏览器抽屉。 2. **左抽屉**:左侧全高抽屉(fixed),标题栏带关闭按钮,内含工作区文件树。 3. **文件浏览**:懒加载目录树,跟随当前会话的工作区根目录,切换会话时自动刷新;单行设置栏整合了可展开的搜索框(按名称或路径即时过滤已加载条目)、排序菜单(按名称 / 大小 / 修改时间,升序或降序)、显示隐藏开关、刷新与新建文件 / 新建文件夹按钮。 4. **悬浮预览框**:点文件在右侧浮出可拖拽/缩放/最小化/关闭的预览框。 5. **文件预览**:内置文本(源码)、Markdown(渲染 + 源码切换 + 行内编辑)、图片(data URL,含 SVG)、CSV(只读表格)、二进制(hexdump)预览。 6. **可扩展预览**:通过 `fileExplorer` 服务按扩展名注册预览器,未注册的扩展名按其检测到的类型回退到内置预览(文本→纯文本、图片→图片、二进制→十六进制);更高优先级的注册可**覆盖**该扩展名的内置预览。新增蛋白质结构(`.cif`/`.pdb` → Mol*)、序列等预览器无需改动核心。 7. **打开方式…**:当多个查看器插件都能渲染同一文件时,可在行「···」菜单中按文件选择查看器(自动 / 文本 / 十六进制 / 已安装的查看器),或在预览面板标题栏即时切换。选择仅本次生效,普通「打开」仍按优先级解析。 8. **浏览器打开**:点击 `.pdf` / `.html` / `.htm` / `.xhtml` / `.json` 文件直接在新浏览器标签页用浏览器原生渲染打开;HTML 页面可加载同目录资源(CSS/JS/图片/字体)。 9. **行操作菜单**:hover 某一行末尾出现「···」菜单。文件行提供「打开」(或「打开方式…」)与复制绝对/相对路径;文件与目录行都提供重命名、移动、复制、删除,目录行另增「新建文件 / 新建文件夹」。抽屉标题栏的「+ 新建」按钮可在工作区根目录创建文件或文件夹。 10. **快捷键**:`Ctrl/Cmd+Shift+E` 开关文件浏览器抽屉。 ## 按文件类型的预览行为 文件的打开方式取决于其扩展名及其被检测到的内容类型(文本 / 二进制): | 类型 | 扩展名 | 默认行为 | | ---- | ------ | -------- | | 源码文本 | `.ts` `.tsx` `.js` `.jsx` `.css` `.py` `.yaml` `.yml` `.sh` `.go` `.rs` `.xml` `.sql` `.txt` … | 源码预览;大文件分页流式加载 | | Markdown | `.md` `.mdx` | 渲染后的 HTML,可切换源码并行内编辑 | | 图片 | `.png` `.jpg` `.jpeg` `.gif` `.webp` `.svg` | 图片预览(data URL) | | CSV | `.csv` | 只读表格(首行为表头) | | PDF | `.pdf` | 浏览器原生阅读器,新标签页 | | HTML | `.html` `.htm` `.xhtml` | 浏览器原生渲染,新标签页 | | JSON | `.json` | 浏览器原生查看,新标签页 | | 二进制 / 未注册 | — | 十六进制转储(`hexdump -C` 风格,读取前 `maxBinaryBytes` 字节) | 文本与二进制由 NUL 字节扫描判别,图片按扩展名识别;零字节文件按空文本处理(可编辑),仅当扩展名为图片时才显示状态提示;超过大小上限的文件显示「文件过大」(文本改为分页而非报错)。任何文件还可在其「···」行菜单中强制「以文本打开」或「以二进制打开」,从而跳过上表的默认行为。 ### 覆盖内置预览器 内置预览器以优先级 `0` 注册。由于注册按最高优先级优先解析,扩展可以为特定扩展名替换任意内置预览——例如更丰富的 Markdown 或 CSV 渲染器——而无需改动核心。`registerViewer({ id, label, exts, component, priority })` 注册具名查看器;`registerPreview(ext, component, priority)` 是更轻量的匿名形式。 ## 安装 从 git 仓库安装(推荐): ```sh dsh plugin --profile web add github:wolfsonliu/dsh-file-explorer dsh web ``` 或从本地目录安装: ```sh git clone https://github.com/wolfsonliu/dsh-file-explorer cd dsh-file-explorer npm install npm run build dsh plugin --profile web add . dsh web ``` ### 可选预览插件 安装额外的预览器以获得更丰富的文件预览体验: ```sh # 基于 CodeMirror 6 的代码预览,支持语法高亮与编辑 dsh plugin --profile web add github:wolfsonliu/dsh-file-explorer-preview-code # 基于 Mol* 的分子结构预览(.cif / .pdb) dsh plugin --profile web add github:wolfsonliu/dsh-file-explorer-preview-molstar # 基于 SeqViz 的序列查看器(FASTA / GenBank / JBEI / SnapGene / SBOL) dsh plugin --profile web add github:wolfsonliu/dsh-file-explorer-preview-sequence ``` ## 配置 组合包默认启用以下配置: ```yaml - insert: - id: file-explorer name: '@dsh-external/dsh-file-explorer' config: maxTextBytes: 2097152 maxImageBytes: 10485760 maxBinaryBytes: 65536 maxRawBytes: 104857600 ``` | 配置项 | 默认值 | 说明 | | ---------------- | -----: | -------------------------------------- | | `maxTextBytes` | 2 MiB | 可预览的单个文本文件大小上限 | | `maxImageBytes` | 10 MiB | 可预览的单个图片大小上限 | | `maxBinaryBytes` | 64 KiB | 二进制文件 hexdump 读取的字节数上限 | | `maxRawBytes` | 100 MiB | `raw` 动作 / `readRawFile` 单次读取上限(非总大小) | | `showHidden` | false | 列出点开头(隐藏)文件的基础策略;头部"眼睛"开关按请求覆盖(取或) | | `inlineCsp` | none | 可选:静态路由 inline html/xhtml/svg 响应的 Content-Security-Policy | ## 数据层 宿主半部通过 `ctx.webServer.register()` 注册一个 `/file-explorer/api` 精确路由,动作(`action` 查询参数): - `list`:列出一级目录(目录在前、按名称排序),返回 `BrowserEntry[]`。 - `preview`:读取单个文件,返回判别式 `FilePreview`(`text` / `text-large` / `image` / `empty` / `binary` / `too-large`)。 - `pdf`:以内联方式流式返回 `.pdf` 文件(`Content-Type: application/pdf`),由浏览器原生阅读器在新标签页渲染。 - `resolve-path`:解析工作区相对路径为绝对路径与父路径。 - `write`:把 UTF-8 文本写入工作区文件(POST body `{ path, content }`),返回保存的相对路径。 所有路径经 `inside(root, input)` 工作区包含校验(含 `realpath` 符号链接解析),越界路径一律拒绝。文本/二进制通过 NUL 字节扫描判别,图片按扩展名映射 MIME 并返回 data URL。二进制预览返回前 `maxBinaryBytes` 字节的 base64(附带 `truncated` 标志),用于 `hexdump -C` 风格的十六进制转储。 宿主还注册了一条 `kind: 'prefix'` 路由 `/file-explorer/files//<相对路径…>`,以浏览器原生内容类型(`text/html`、`text/css`、`image/*`、`application/pdf`、字体、音视频,未知类型回退 `application/octet-stream`)流式返回工作区文件;支持 `Range`,目录回退其 `index.html`,并始终携带 `x-content-type-options: nosniff` 与 `cache-control: no-store`。`.pdf`/`.html`/`.htm`/`.xhtml` 即在新标签页打开该 URL。 ## Model Experience 本插件为纯 UI 表面,**不产生任何会话事件、不改动会话日志**,对模型不可见。宿主半部仅读取文件内容用于浏览器预览,与 agent 工具执行互不影响。 ## Known Limitations and Deferred Work - **轻量文本编辑**:内置编辑覆盖 Markdown 以及未被扩展预览认领的任何文本文件(行内编辑/保存,切换文件或关闭面板时自动保存);全文件类型的富 CodeMirror 编辑(语法高亮、行号)仍需 `preview-code` 扩展。 - **单文件预览**:无多标签页、无行内 diff。 - **自动刷新采用防抖轮询**:抽屉打开且标签页可见时,目录树每约 3 秒及窗口获得焦点时重新拉取其已加载目录;没有服务器推送(`fs.watch`)通道。 - **文件链接拦截为 best-effort**:依赖 DSH 会话区的 CSS 类名(`_fileLink`、`data-produced-files-row`),上游 UI 结构调整时需同步选择器。 - **大文件**:超大文本文件分页流式加载(超过 `maxTextBytes` 后经 `readRawFile` 分页预览);图片读取受 `maxImageBytes` 上限约束,二进制 hexdump 只读取前 `maxBinaryBytes` 字节。 - **隐藏文件默认不显示**:以点开头的文件/目录默认不列出,点击头部"眼睛"开关即可显示;组合包配置 `showHidden: true` 表示始终显示(取或语义)。 - **搜索为纯客户端**:树顶搜索框只匹配已加载(已展开)的条目,位于未展开目录中的文件不会命中;当前没有服务端递归搜索。 ## 开发扩展 `dsh-file-explorer` 通过 cordis 服务 `fileExplorer` 暴露注册入口:`registerViewer`、`registerPreview`、`registerFileAction`、`writeFile` 和 `readRawFile`。领域专家可把扩展做成独立插件(命名 `@dsh-external/dsh-file-explorer-preview-`),无需改动核心。 完整指南请参阅 **[开发 dsh-file-explorer 扩展](docs/developing-extensions.zh.md)**([English](docs/developing-extensions.md))——契约、路由、用 `readRawFile` 处理大文件/二进制、用 `writeFile` 编辑、打包、国际化,以及参考实现。 快速骨架: ```typescript import type { FileExplorerService } from '@dsh-external/dsh-file-explorer/client' export const inject = ['fileExplorer'] export function apply(ctx: { fileExplorer: FileExplorerService effect(cb: () => (() => void), label?: string): void }): void { ctx.effect(() => ctx.fileExplorer.registerViewer({ id: 'cif-viewer', // unique; 'auto' | 'text' | 'binary' are reserved label: 'My CIF Preview', // shown in the "Open with…" list exts: ['cif'], component: CifPreview, priority: 10, })) } ``` ## 扩展 `dsh-file-explorer` 通过 `fileExplorer` 服务支持扩展。已有的扩展: | 扩展 | 说明 | 仓库 | | ---- | ---- | ---- | | `dsh-file-explorer-preview-code` | 基于 CodeMirror 6 的代码预览与编辑 | [wolfsonliu/dsh-file-explorer-preview-code](https://github.com/wolfsonliu/dsh-file-explorer-preview-code) | | `dsh-file-explorer-preview-molstar` | 基于 Mol* 的分子结构预览(`.cif` / `.pdb`) | [wolfsonliu/dsh-file-explorer-preview-molstar](https://github.com/wolfsonliu/dsh-file-explorer-preview-molstar) | | `dsh-file-explorer-preview-sequence` | 基于 SeqViz 的序列查看器预览(FASTA / GenBank / JBEI / SnapGene / SBOL) | [wolfsonliu/dsh-file-explorer-preview-sequence](https://github.com/wolfsonliu/dsh-file-explorer-preview-sequence) | 欢迎增加更多扩展——参照 [开发扩展](docs/developing-extensions.zh.md) 自行开发即可。 ## 开发 ```sh npm install npm run check # tsc 类型检查 npm test # vitest 单元测试 npm run build # tsc + tsdown(宿主 ESM + 客户端 CJS bundle) ``` ## 参考 - [dsh-side-panel](https://github.com/ccq1/dsh-side-panel) — 一个 DSH Web 侧边栏插件,本项目的宿主路由与文件链接拦截借鉴了它的架构。 - [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) — 本插件所扩展的 DSH 框架。 ## 许可 [MIT](LICENSE)