Skip to content
dsh.fish
Bundle

dsh-file-panel

DeepSeek Harness plugin: a right-side panel that lists files the agent created or downloaded, with inline preview and "reveal in folder".

Source
yu2025-luo
stars
3 stars
License
MIT
Updated
Updated 4 days ago

Readme

# dsh-file-panel

[![CI](https://github.com/yu2025-luo/dsh-file-panel/actions/workflows/ci.yml/badge.svg)](https://github.com/yu2025-luo/dsh-file-panel/actions/workflows/ci.yml) [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)

A plugin for [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) (`dsh` web GUI) that watches what the agent creates and downloads during a session, and shows it in a **right-side popup panel** β€” like the file viewer in Codex.

When a file or image is written to disk during a session, the panel pops up automatically on the right. Every row lets you:

- πŸ‘ **Preview** β€” images render inline; text files show their first 256 KB; other types show metadata.
- πŸ“‚ **Show in folder** β€” opens the OS file manager with the file selected (`explorer.exe /select` on Windows, `open -R` on macOS, `xdg-open` on Linux).
- β†— **Open** β€” opens the file with the OS default application (via the harness's built-in `host.openPath` RPC).
- πŸ“‹ **Copy path** β€” copies the absolute path to the clipboard.

Also ships a **workspace folder** shortcut at the bottom of the panel.

[δΈ­ζ–‡θ―΄ζ˜Ž](README.zh.md)

## Screenshots

![Session files panel](screenshots/panel-session-files.png)

*The right-docked session files panel: every row previews, opens, reveals, or copies its path; the bottom button opens the session's working directory. The panel is fully draggable (grab the header) and resizable from its left and bottom edges, with scrollbars appearing when it gets narrow.*

## Installation

Requires DeepSeek Harness `dsh` CLI (npm package `@deepseek-ai/dsh`) and pnpm.

### From a local checkout

```sh
cd dsh-file-panel
npm install          # installs esbuild (dev-only)
npm run build        # produces lib/index.js + lib/client.js (committed)

# register in the web profile (link: tracks your checkout live)
dsh plugin --profile web add link:.
```

### From GitHub

```sh
dsh plugin --profile web add github:yu2025-luo/dsh-file-panel
```

The built artifacts are committed, so no build step runs during install.

### Activate

Restart the `dsh web` server (plugin sets take effect on restart), then refresh
`http://127.0.0.1:3080`. That's it β€” no configuration required.

Remove with:

```sh
dsh plugin --profile web remove dsh-file-panel
```

## Usage

| Gesture | Result |
| --- | --- |
| Agent creates/downloads a file | Panel pops up automatically (newest files carry a `NEW` chip) |
| Click a row | Inline preview (image / text / metadata) |
| Row hover actions | Preview, open, show in folder, copy path |
| πŸ”” bell | Toggle auto-pop for new files |
| `–` / `Γ—` | Collapse to a floating launcher button (with new-file badge) or hide |
| Bottom "open workspace folder" | Opens the session's working directory |

Panel state (open/collapsed) and the auto-pop preference persist in
`localStorage`. The auto-pop baseline is per session: files that already
existed when the panel first saw the session do not re-trigger a popup.

## How it works

One npm package with two halves, registered as a single loader row
(`cordis.patch.yml` β†’ row `file-panel`):

```
Host half (src/index.js)                     Browser half (src/client.jsx)
────────────────────────                     ──────────────────────────────
ctx.on('fs/observed')          ──┐
  write/edit tools report        β”‚            shell.overlay slot entry:
  files (precise, attributed     β”‚            a right-docked floating panel
  to the session)                β”œβ”€β”€β–Ά FileTracker (per-session lists,
recursive fs.watch per           β”‚      ignore rules, caps, fence)
  session working directory       β”‚                β”‚
  (catches shell downloads:    β”€β”€β”˜                β–Ό
  curl, Invoke-WebRequest, …)          RPC channel /file-panel
                                        authority: 'loopback'
                                        list Β· readText Β· readImage
                                        reveal Β· describe
                                                  β–²
                                                  β”‚ poll every 1.5 s
                                        client: ctx.connection.rpc.call()
                                        open file: built-in api.host.openPath
```

The client half registers into the shipped `shell.overlay` slot (additive,
frame-wide floating layer), reads the current session through the standard
`useSessions` prop, and polls the plugin's own loopback-only RPC channel.
The channel is registered with `ctx.connection.rpc.handle`, the sanctioned
static-package RPC seam.

### Security

- The `/file-panel` channel is registered with `authority: 'loopback'`, so
  only pages served from `127.0.0.1` can call it. When the GUI is accessed
  over the network (`--trusted-host`), the panel shows a notice and stays
  inactive.
- Every read/reveal endpoint only accepts absolute paths that the tracker
  has actually seen (a tool write or a watcher event under a watched working
  directory) β€” the RPC can never be used as a generic file-read/reveal
  primitive.

## Project layout

```
src/
  index.js      host half: tracker wiring + /file-panel RPC endpoints
  tracker.js    pure-Node file tracker (fs/observed ingestion, recursive
                watcher with debounce, ignore rules, caps, RPC fence)
  client.jsx    browser half: the right-side panel UI (React, JSX)
build.mjs       esbuild build for both halves
cordis.patch.yml  the bundle patch inserting the loader row
tests/          node:test unit + host-half smoke tests
lib/            built artifacts (committed, so installs need no build step)
```

## Development

```sh
npm install
npm run build   # rebuild lib/index.js and lib/client.js
npm test        # node --test
```

For a fast client-side iteration loop after changing `src/client.jsx`:

```sh
npm run build
```

then hard-refresh the GUI page (`lib/client.js` is served with
`cache-control: no-cache`; plugin *sets* only change on restart, but bundle
*content* re-hashes per request β€” see `dsh-client-modules`). During active
UI development you can also run `pnpm run dev:web` from the harness checkout
to rebuild client bundles on change.

## Compatibility

Built against the public seams of `@deepseek-ai/dsh` `0.1.0-rc.x`:

- host: `ctx.connection.rpc.handle` / `ctx.on('fs/observed')`
- client: `shell.overlay` slot, `useSessions` standard prop,
  `ctx.connection.rpc.call`, `ctx.locale`

DeepSeek Harness is pre-release: those seams may move. If the panel stops
working after a `dsh` upgrade, check the pinned version in
`package.json` and re-run the build.

## Known limitations

- The recursive watcher uses `fs.watch({ recursive: true })` (Node β‰₯ 20).
  On platforms where that is unavailable, the panel still tracks everything
  the harness `write`/`edit` tools produce, but shell-side downloads may be
  missed.
- The panel is process-local: it starts empty after a restart (it only
  records files it actually observed; it does not scan history).
- `node_modules`, `.git`, and temporary-file noise are ignored by design.
- `reveal` on headless Linux reports `canReveal: false` and hides the
  button (no desktop to open).

## Publishing to GitHub / npm

1. Create a GitHub repo and push (the repo is already a git repository with
   a `v0.1.4` tag):

   ```sh
   git remote add origin https://github.com/yu2025-luo/dsh-file-panel.git
   git push -u origin main --tags
   ```

2. Add the [`dsh-plugin` topic](https://github.com/topics/dsh-plugin) on the
   repo page (About β†’ gear icon β†’ Topics) together with
   `deepseek-harness`, `dsh`, `deepseek`, and `file-preview`. The repo then
   appears on the public plugin topic page automatically.
3. Users install with
   `dsh plugin --profile web add github:yu2025-luo/dsh-file-panel#v0.1.4`.
4. Optionally publish to npm (`npm publish`) β€” then install with
   `dsh plugin --profile web add dsh-file-panel`.

Community catalogs that sync from the `dsh-plugin` topic:
[Oh-My-DSH](https://github.com/like-study1/Oh-My-DSH) (auto-synced) and
[awesome-deepseek-harness](https://github.com/0xsline/awesome-deepseek-harness)
(PR-based).

Remember to bump the version and re-run `npm run build` before releasing.

## License

[MIT](LICENSE)

Install

dsh plugin --profile web add github:yu2025-luo/dsh-file-panel

Profile: web

  • This package builds from source on install. pnpm will ask you to allow its build script β€” that is permission to run the package’s code on your machine, outside the agent sandbox. Only allow sources you trust.
  • This source has no pinned commit, so a later push upstream changes what installs. Prefer pinning a commit.
Source