Bundle
fexp-file-explorer
DSH 静态 bundle 插件:在左侧工作区浏览目录与文件。双入口(文件浏览/打开目录)、320px 浏览面板、文件预览、一键打开系统资源管理器、文件引用添加到聊天。A static-bundle DSH plugin: workspace file explorer in the left sidebar.
- Source
- ShanHaiFish
- License
- MIT
- Updated
- Updated 7 days ago
Readme
# 左侧文件浏览器 (fexp)
[English](README.en.md) · [中文](README.md)



[](https://shanhaifish.github.io/fexp-file-explorer/)
DSH(DeepSeek Harness)动态 Cordis 插件:在左侧工作区浏览目录与文件。双入口(侧栏顶部「文件浏览」胶囊 + 会话标题栏「打开目录」按钮)→ 320px 滑出面板,自动定位当前工作区目录,点击目录进入、点击文件预览文本内容;工具栏可一键在系统资源管理器中打开当前目录,预览时可把文件引用添加到聊天输入框。
**v1.5.0 起为静态 bundle 插件,随 profile 层栈自动加载**——安装一次,每次启动 DSH 即自动生效,不再需要手动 define/run。**v1.6.0 已发布到 npm**,`dsh plugin --profile web add fexp-file-explorer` 直接安装。
## 功能特性
- **双入口**(SVG 矢量图标, 颜色全部使用主题 CSS 变量, 深浅色及任意主题下文字与背景都保持对比):
- 侧栏顶部「工作区」标题行右侧的「文件浏览」胶囊按钮(宽栏时显示;
工作区「搜索会话」搜索框展开时自动隐藏, 避免遮挡搜索框, v1.5.1)
- 会话标题栏「打开目录」按钮
- **浏览面板**(点击任意入口滑出, 320px, 覆盖左侧区域):
- 自动定位到**当前工作区目录**(当前会话 cwd); 切换工作区后面板自动重新定位,
同一工作区重开保留上次浏览位置
- 目录在前、文件在后, 文件显示大小; 点击目录进入、点击文件预览
- 面包屑任意层级跳转; 工具栏: 当前工作区 / 回到根目录 / 上一级 / 刷新 / **在系统资源管理器中打开**
- 文件预览: 文本内容(默认 256KB 上限, 最大 1MB), 二进制/超限有明确提示
- 预览头部: 文件名 / 大小 / **[添加到聊天]** / 关闭预览
- **在系统资源管理器中打开**: 一键用系统资源管理器打开当前浏览的目录
(DSH 原生 `host.openPath`, Windows 走 `Invoke-Item`; 直连原生 API
`POST /api/host.openPath`, 避免被拦截型第三方插件把调用改道到文件编辑器)
— **v1.6.1**: 适配新版 DSH 的 `session/openWorkspacePath` Typert Remote 端点
(先试新端点, 不可达时回退旧 `host.openPath` 与 `workspaces.openPath`)
- **添加到聊天(v1.6.0)**: 预览文件时把 DSH **@ 文件命令引用**追加到聊天输入框草稿
(不覆盖已有内容), 可连续添加多个文件(空格分隔): 工作区 cwd 内的文件用
相对路径(`@client/client.js` 形式), 工作区外保留绝对路径, 含空格路径按官方
语法加引号(`@"path with spaces"`); 输入框只显示短引用, DSH 原生 @ 语义
让模型明白这是你显式引用的文件, 需要内容时它会用 read 工具读取
- **图标(v1.4.0)**: Google Material Icons 官方库(fonts.google.com/icons,
Apache 2.0 许可), 实心填充风格小尺寸下依然清晰, 与 Chrome/Android 大厂视觉一致
## 界面预览
| | | |
| --- | --- | --- |
|  |  |  |
## 快速开始
```sh
# 安装(静态 bundle, 推荐; 已发布到 npm)
dsh plugin --profile web add fexp-file-explorer
```
直接从源码安装(本地开发或未发布时, 注意路径不能含空格):
```sh
dsh plugin --profile web add file:/path/to/fexp-file-explorer
```
重启 `dsh web` 后插件即自动生效:侧栏顶部出现「文件浏览」胶囊按钮,会话标题栏出现「打开目录」按钮,无需手动 define/run。
## 使用说明
1. **打开面板**: 点击侧栏「文件浏览」或会话标题栏「打开目录」, 320px 面板从左侧滑出, 自动定位到当前工作区目录;
2. **浏览**: 点击目录进入下一级, 用工具栏「上一级 / 回到根目录 / 刷新」导航, 或点面包屑任意层级跳转;
3. **预览文件**: 点击文件在面板底部预览文本内容(默认 256KB 上限);
4. **添加到聊天**: 预览时点击「添加到聊天」, DSH @ 文件引用(`@相对路径` / `@"带空格路径"`)追加到输入框草稿, 编辑后发送;
5. **在系统资源管理器中打开**: 工具栏最右侧按钮, 一键打开当前浏览的目录(Windows 走 `Invoke-Item`)。
## 仓库内容
| 路径 | 说明 |
| --- | --- |
| `package.json` + `cordis.patch.yml` + `lib/` + `client/` | **静态 bundle**(推荐):`dsh plugin add` 安装后随 DSH 启动自动加载 |
| `host-source.js` + `client-source.js` | 动态插件回退形态:无 bundle 能力的 profile 按下方流程加载 |
| `manifest.json` | 插件元数据 + 恢复定义参数(plugin/name/purpose/version) |
| `LICENSE` | MIT 许可证 |
| `assets/` | 界面预览截图(screenshot-1~3.png) |
| `AGENTS.md` | 代理协作约定(重建流程/修改工作流/编码约定/版本管理) |
| `README.md` / `README.en.md` | 中文 / English 文档 |
## 双形态说明
| | 静态 bundle(v1.5.0, 推荐) | 动态插件(回退) |
| --- | --- | --- |
| 加载方式 | `dsh plugin add` 装进 profile 层栈, 随 DSH 启动自动加载 | 每次 DSH 重启后需 `cordis_define` + `cordis_run` 手动注册 |
| 代码位置 | `lib/index.js`(Host) + `client/client.js`(Client) | `host-source.js` + `client-source.js` |
| 适用场景 | 正常 profile(web 等) | 无 bundle 能力的 profile |
动态回退形态步骤:
1. 让 agent 读取 `host-source.js` 与 `client-source.js`;
2. `cordis_define`:`plugin: { kind:"new", idPrefix:"fexp" }`,name/purpose 取
`manifest.json`(purpose 含 `CAPABILITIES: fs, rpc` 声明),`code.host` /
`code.client` 取两个源码文件的完整内容;
3. `cordis_run` 激活;面板出现即成功。
> 动态形态不跨 DSH 进程存续,重启后需重新加载;静态 bundle 形态无此限制。
## 技术要点
- **Host 半区**: 静态 bundle 形态在 `lib/index.js`,经 `webServer` 挂三个 JSON
路由(`/fexp/default-root` / `/fexp/list-dir` / `/fexp/read-file`), 底层使用
DSH 的 `fs` 服务(resolve/listDir/stat/readText) 与 `sandboxPolicy.workspaceRoot`;
动态回退形态在 `host-source.js`,通过 `harness.handle` 暴露同名三个 RPC。
- **Client 半区**: 全部使用增量插槽(`shell.overlay`、
`conversation.session.header.actions`、`conversation.input.dock`、
`sidebar.footer.action`), 不替换任何内置 UI; 纯 JS + `React.createElement`,
无 JSX/TS; 静态形态经 `window.__ModuleLoader__.load` 注册,
`host.call` → fetch 同源路由, `styles.insert` → 自建 `<style>` 标签。
- **竞态修复(v1.0.0)**: `useStore` 订阅后立即自愈同步当前状态, 避免"探针写入
早于订阅导致更新丢失"的启动时序竞态; `sidebarWide` 默认 `true`, 探针异常时
顶部按钮仍可见。
- **打开资源管理器(v1.1.0/1.5.2)**: 路径直接交 DSH 原生 `host.openPath`
(Windows 走 `Invoke-Item`)。v1.5.2 起改为直连原生 API
(`POST /api/host.openPath`, 官方 client-request 信封协议, 同源)——
安装了 `dsh-better-sidebar` 等拦截型插件时会 monkey-patch
`workspaces.openPath`, 把「打开目录」改道成「在侧边栏编辑器打开文件」,
对目录报 `"…" is a directory`; 直连原生 API 绕过被 patch 的通道,
无 fetch 环境/网络层失败时回退 `workspaces.openPath`; 不新增 Host RPC,
无 spawn/外部网络能力。
- **添加到聊天(v1.2.0~v1.6.0)**: 会话作用域插槽 `conversation.input.dock` 内的隐藏桥
组件捕获标准包 `inputActions`(setDraft) 与 `useInput`(草稿订阅), 面板
「添加到聊天」调用 `setDraft(现有草稿 + 引用)`; 这是内置 UI 写输入框的
同一官方通道, 纯 Client 能力, 无新 Host RPC。v1.6.0 起插入的引用改为 DSH
@ 文件命令语法(与官方 file-reference 的 `formatFileMention` 一致):
工作区内相对路径、工作区外绝对路径、含空格加 `@"…"` 引号; DSH 系统提示的
`FILE_REFERENCE_PROMPT`(Paths prefixed with @ are files explicitly referenced
by the user; use the read tool when contents are needed) 让模型按 @ 前缀
理解并读取引用文件, 不再需要拼长 Markdown 链接。
- **工作区绑定(v1.2.2)**: 面板加载 effect 原以 `path === null` 为守卫, 之前浏览过
后关闭再打开(或切换工作区)不会重新加载, 导致「文件浏览」展示上一个工作区的
旧目录; 新增 `boundWs` 绑定状态, 打开面板/工作区切换时若 `boundWs !== 当前
wsPath` 即重新绑定并加载当前工作区目录, 同一工作区重开保留上次浏览位置;
双入口统一走 `openPanelFor`, 工具栏「当前工作区目录」走 `bindWorkspace`。
- **主题对比度(v1.2.3)**: 入口按钮(「文件浏览」/「打开目录」)原用内联硬编码颜色
(文字 `#e8edf3` 近白), 浅色主题下看不清; 改为 CSS 类 `.fexp-entry-btn` /
`.fexp-entry-btn-active`, 颜色全部走主题 CSS 变量(`label-primary` 文字、
`bg-layer-1/2` 背景、`border-l2` 边框、`brand-primary` 激活态), 深浅色及
任意主题自动适配, 附 hover 反馈。
- **图标库(v1.4.0)**: Google Material Icons 官方库 path, 实心填充渲染
(`fill="currentColor"`, 无 stroke), 默认尺寸 16px; 前版(v1.3.0)的 Lucide
线性图标已取代。
- **搜索框避让(v1.5.1)**: 「文件浏览」入口按钮固定定位在「工作区」标题行,
工作区「搜索会话」搜索框展开时正好被按钮遮挡; `TopToggle` 用
`MutationObserver` 监听搜索按钮 `aria-expanded` 状态(展开时该按钮带
`aria-expanded="true"` 且下一个兄弟元素为 `input[type=text]`, 与同样带
`aria-expanded` 的会话行/分组折叠按钮可区分), 搜索框展开期间隐藏入口
按钮, 收起后自动恢复; Host 无改动。
## 安全与边界
- **能力声明**: `CAPABILITIES: fs, rpc`——仅文件系统访问(host 的 `fs` 服务)
与常规 RPC; 无网络请求、无 spawn/进程、无凭据访问。
- **安全审查**: WARN 级(v1.5.2 起 38/300, 此前历版本持平 33/300); 审查引擎为
`plugin_security_review` / `plugin_security_audit`(见
[dsh-plugin-security-review](https://github.com/ShanHaiFish/dsh-plugin-security-review))。
- **已知限制**: 文件预览默认 256KB 上限(最大 1MB), 超限明确报错 `FS_TOO_LARGE`,
需在对话中让助手读取; 静态 bundle 随 profile 加载, 动态回退形态不跨 DSH
进程存续, 重启后需重建。
## 版本历史
| 版本 | 说明 |
| --- | --- |
| v1.6.1 | 修复「在系统资源管理器中打开」在 DSH 版本升级后失效:新版 DSH(0.1.3+) 把该 Host RPC 从 `host.openPath` 重构为 Typert Remote 端点 `session/openWorkspacePath`(官方 client 走 `ctx.remote.session.openWorkspacePath({ path })`,实际 `POST /api/session/openWorkspacePath`,payload 以 `{ args: { request } }` 包装);旧端点已不存在(404),回退通道 `workspaces.openPath` 也已从新版 client 移除。`nativeOpenPath` 改为先试新端点,收到明确业务错误直接抛出;端点不可达(404/网络/非 JSON)才回退旧端点与 `workspaces.openPath`(若存在);安全审查持平 WARN(38/300) |
| v1.6.0 | 「添加到聊天」改插 DSH @ 文件命令引用: 不再拼 `[文件名](绝对路径)` 长文本, 改为插入官方语法 `@相对路径`(工作区内)/`@绝对路径`(工作区外)/`@"带空格路径"`(含空格时); DSH 原生 FILE_REFERENCE_PROMPT 让模型按 @ 前缀理解并 read 读取; 连续添加多个以空格分隔; 输入框只显示短引用; 纯 Client 能力, 安全审查持平 WARN(38/300) |
| v1.5.3 | 精简「打开资源管理器」按钮 hover 文字: 「在系统资源管理器中打开当前目录」(14 字) → 「打开资源管理器」(6 字), 与工具栏其他按钮 4~6 字风格一致; 纯文字改动无逻辑变化; 安全审查持平 WARN(38/300) |
| v1.5.2 | 修复「在系统资源管理器中打开」被拦截型插件干扰: 装有 `dsh-better-sidebar`(默认拦截 `workspaces.openPath`)时, 该插件把调用改道为「在侧边栏编辑器打开文件」, 对目录报 `"<path>" is a directory`; `openInExplorer` 改为优先直连 DSH 原生 `host.openPath`(官方信封协议, `POST /api/host.openPath`, 同源, 无新增 Host RPC/外部网络), 绕过被 patch 的通道; 无 fetch 环境或网络层失败时回退原通道, 信封内业务错误如实报告; 工具栏按钮不再依赖 `workspaces` 存在; 安全审查 WARN(38/300) |
| v1.5.1 | 修复「文件浏览」按钮遮挡工作区「搜索会话」搜索框: 点击工作区顶部搜索图标展开搜索框时, 固定定位的入口按钮正好叠在搜索框上挡住输入; TopToggle 用 MutationObserver 监听搜索按钮 aria-expanded 状态(搜索按钮展开时带 aria-expanded="true" 且下一个兄弟元素为 input[type=text], 与会话行/分组折叠按钮可区分), 搜索框展开期间隐藏入口按钮、收起后自动恢复; Host 无改动, 纯 Client 能力, 安全审查持平 WARN(33/300) |
| v1.5.0 | 静态 bundle 化: `package.json`(dsh.bundle.patch + dsh.client.platform)+ `cordis.patch.yml` + `lib/index.js`(webServer 挂三个 JSON 路由)+ `client/client.js`(__ModuleLoader__ 注册, host.call→fetch, styles→自建标签); 随 profile 层栈自动加载, 无需重启后手动 define/run; 动态形态源码保留为回退; 安全审查持平 WARN(33/300) |
| v1.4.0 | 图标整体改用 Google Material Icons 官方库(Apache 2.0): 实心填充风格小尺寸下清晰, 符合 Chrome/Android 大厂标准; 关闭面板=keyboard_double_arrow_left(« 与 VS Code 一致)、工作区=workspaces、根目录=home、上一级=arrow_upward、刷新=refresh、资源管理器=folder_open、关闭预览=close; svgIcon 改 fill=currentColor, 默认尺寸 14→16px; Host 无改动, 安全审查持平 WARN(33/300) |
| v1.3.0 | 图标改用 Lucide 官方图标库(lucide.dev, ISC 许可): 关闭面板=panel-left-close、当前工作区=briefcase、根目录=house、上一级=folder-up、刷新=refresh-cw、资源管理器打开=folder-open、关闭预览=x, 语义更直观(已被 v1.4.0 的 Material Icons 取代); Host 无改动 |
| v1.2.3 | 修复「文件浏览」「打开目录」按钮浅色主题下文字看不清: 入口按钮改为 CSS 类并全部使用主题 CSS 变量(`label-primary` 文字 / `bg-layer-1/2` 背景 / `brand-primary` 激活态), 深浅色及任意主题自动适配保证对比, 补充 hover 反馈; Host 无改动 |
| v1.2.2 | 修复「文件浏览」打开面板定位到上一个工作区目录: 面板加载 effect 的 `path===null` 守卫导致切换工作区后不重载; 新增 `boundWs` 工作区绑定, 打开面板/切换工作区时自动重定位到当前工作区目录, 双入口统一走 `openPanelFor`; Host 无改动 |
| v1.2.1 | 修复「已添加」状态不合理: 按钮保持「添加到聊天」常显可用, 支持连续多次添加文件 |
| v1.2.0 | 新增预览区「添加到聊天」按钮: 经 `conversation.input.dock` 隐藏桥捕获标准包 `inputActions/useInput`, 把文件引用追加到输入框草稿, 用户编辑后发送; 纯 Client 能力, 安全审查持平 WARN(33/300) |
| v1.1.0 | 新增「在系统资源管理器中打开」工具栏按钮: Client 走 DSH 原生 `host.openPath`(Windows `Invoke-Item`) 打开当前浏览目录; 无新增 Host RPC/能力, 安全审查持平 WARN(33/300) |
| v1.0.0 | 最终形态: 顶部「文件浏览」+ 标题栏「打开目录」双入口; 内联样式深色适配; 启动竞态修复(订阅自愈 + 默认宽栏) |
| (pkg-1~pkg-7) | 演进过程: 侧栏底部按钮 → 顶部浮层 → 标签胶囊 → 内联样式可见性修复 → 移除底部按钮与诊断条 |
## 维护
- **提交约定**: Conventional Commits, 中文描述(`feat:` 新功能 / `fix:` 缺陷修复 /
`docs:` 文档 / `refactor:` 重构 / `chore:` 杂项), 源码 / manifest / README
三件套保持一致。
- **代理协作**: 修改前先读 `AGENTS.md`; 重建插件与修改工作流详见该文件。
- **发布**: 功能迭代后打 tag(`vX.Y.Z`)并 `gh release create` 发布; 文档页由
GitHub Pages 自动构建(https://shanhaifish.github.io/fexp-file-explorer/)。
Install
dsh plugin --profile web add github:ShanHaiFish/fexp-file-explorer#225a99acc96205471b6996afbe53aec108e86754
Profile: web
With the hub plugin installed, ask your agent to install it by name — it resolves the same plan shown here.
dsh plugin --profile web add github:stvlynn/dsh.fish#path:packages/dsh-plugin-hub
install fexp-file-explorer from the hub