# Workspace File Explorer (fexp) [English](README.en.md) · [中文](README.md) ![GitHub Release](https://img.shields.io/github/v/release/ShanHaiFish/fexp-file-explorer) ![License](https://img.shields.io/github/license/ShanHaiFish/fexp-file-explorer) ![GitHub Stars](https://img.shields.io/github/stars/ShanHaiFish/fexp-file-explorer) [![Docs](https://img.shields.io/badge/docs-GitHub%20Pages-2ea44f)](https://shanhaifish.github.io/fexp-file-explorer/) A dynamic Cordis plugin for DSH (DeepSeek Harness) that browses workspace directories and files from the left sidebar. Two entry points — the "File Explorer" pill at the top of the sidebar and the "Open Directory" button in the session header — slide out a 320px panel that locates the current workspace directory. Click a directory to enter it, click a file to preview its text content. The toolbar can open the current directory in the system file explorer with one click, and file references can be appended to the chat input while previewing. **Since v1.5.0 this is a static bundle plugin loaded automatically from the profile layer stack** — install once, and it activates on every DSH startup with no manual `define`/`run` needed. ## Features - **Dual entry points** (SVG vector icons; colors use theme CSS variables, so text stays readable on light, dark, and any custom theme): - "File Explorer" pill button at the top of the sidebar, right of the "Workspaces" title (shown when the sidebar is wide; auto-hidden while the "Search sessions" box is expanded so it never covers the search input, v1.5.1) - "Open Directory" button in the session header bar - **Browse panel** (slides out from either entry, 320px, overlays the left area): - Automatically locates the **current workspace directory** (current session `cwd`); re-locates automatically when you switch workspaces, while re-opening in the same workspace keeps your last position - Directories first, then files (with sizes); click a directory to enter, click a file to preview - Breadcrumb navigation at any level; toolbar: current workspace / root / up one level / refresh / **open in system file explorer** - File preview: text content (256KB default limit, 1MB max), with clear messages for binary or oversized files - Preview header: file name / size / **[Add to chat]** / close preview - **Open in system file explorer**: one click opens the current directory in the OS file manager (DSH native open-path RPC, `Invoke-Item` on Windows; **v1.6.1** adapts to the newer `session/openWorkspacePath` Typert Remote endpoint, falling back to the legacy `host.openPath` / `workspaces.openPath` when unreachable) - **Add to chat (v1.6.0)**: appends a DSH **@ file-command reference** to the input draft (without overwriting existing content; multiple files add space-separated): files under the session cwd use the relative form (`@client/client.js`), files outside keep the absolute path, and paths with spaces follow the official quoted grammar (`@"path with spaces"`); the input box shows only a short reference, and DSH's native `FILE_REFERENCE_PROMPT` makes the model treat @-prefixed paths as explicitly referenced files to read via the `read` tool - **Icons (v1.4.0)**: Google Material Icons official library (fonts.google.com/icons, Apache 2.0), solid fill style stays crisp at small sizes, consistent with Chrome/Android first-party visuals ## Screenshots | | | | | --- | --- | --- | | ![fexp screenshot 1](assets/screenshot-1.png) | ![fexp screenshot 2](assets/screenshot-2.png) | ![fexp screenshot 3](assets/screenshot-3.png) | ## Quick Start ```sh # Install (static bundle, recommended; published to npm) dsh plugin --profile web add fexp-file-explorer ``` For local development or unpublished copies use `file:` pointing at this repository (the path must NOT contain spaces): ```sh dsh plugin --profile web add file:/path/to/fexp-file-explorer ``` Restart `dsh web` and the plugin activates automatically: the "File Explorer" pill appears at the top of the sidebar and the "Open Directory" button appears in the session header. No manual `define`/`run` required. ## Usage 1. **Open the panel**: click "File Explorer" in the sidebar or "Open Directory" in the session header; the 320px panel slides out from the left, locating the current workspace directory; 2. **Browse**: click a directory to enter it; use the toolbar "up one level / root / refresh" or jump to any level via the breadcrumbs; 3. **Preview files**: click a file to preview its text content at the bottom of the panel (256KB default limit); 4. **Add to chat**: while previewing, click "Add to chat" to append a DSH @ file reference (`@relative-path` / `@"path with spaces"`) to the input draft, then edit and send; 5. **Open in system file explorer**: the rightmost toolbar button opens the current directory in the OS file manager (`Invoke-Item` on Windows). ## Repository Contents | Path | Description | | --- | --- | | `package.json` + `cordis.patch.yml` + `lib/` + `client/` | **Static bundle** (recommended): auto-loaded on DSH startup after `dsh plugin add` | | `host-source.js` + `client-source.js` | Dynamic-plugin fallback form: for profiles without bundle support | | `manifest.json` | Plugin metadata + restore parameters (plugin/name/purpose/version) | | `LICENSE` | MIT License | | `assets/` | UI screenshots (screenshot-1~3.png) | | `AGENTS.md` | Agent collaboration conventions (rebuild flow / change workflow / coding conventions / versioning) | | `README.md` / `README.en.md` | 中文 / English docs | ## Two Forms | | Static bundle (v1.5.0, recommended) | Dynamic plugin (fallback) | | --- | --- | --- | | Loading | `dsh plugin add` installs into the profile layer stack; auto-loaded on DSH startup | Must be re-registered with `cordis_define` + `cordis_run` after every DSH restart | | Code | `lib/index.js` (Host) + `client/client.js` (Client) | `host-source.js` + `client-source.js` | | When to use | Normal profiles (web, etc.) | Profiles without bundle support | Dynamic fallback steps: 1. Have an agent read `host-source.js` and `client-source.js`; 2. `cordis_define`: `plugin: { kind: "new", idPrefix: "fexp" }`, `name`/`purpose` from `manifest.json` (purpose includes the `CAPABILITIES: fs, rpc` declaration), `code.host`/`code.client` as the full contents of the two source files; 3. `cordis_run` to activate; success when the panel appears. > The dynamic form does not survive DSH restarts and must be reloaded; the static bundle form has no such limitation. ## Technical Notes - **Host half**: the static bundle form lives in `lib/index.js` and mounts three JSON routes via `webServer` (`/fexp/default-root`, `/fexp/list-dir`, `/fexp/read-file`) on top of the DSH `fs` service (resolve/listDir/stat/readText) and `sandboxPolicy.workspaceRoot`; the dynamic fallback in `host-source.js` exposes the same three methods as Package-private RPCs via `harness.handle`. - **Client half**: uses only additive slots (`shell.overlay`, `conversation.session.header.actions`, `conversation.input.dock`, `sidebar.footer.action`) and never replaces built-in UI; plain JS + `React.createElement`, no JSX/TS. The static form registers via `window.__ModuleLoader__.load`, replaces `host.call` with fetches to same-origin routes, and replaces `styles.insert` with a self-managed `