npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

dsh-files-pane

v1.0.1

Published

In-browser files pane for the DSH Web GUI: a Session View tab that browses the host's files and reads them in place

Readme

dsh-files-pane

An in-browser files pane for the DeepSeek Harness Web GUI: a Session View tab (对话 / 轨迹 / 文件) that browses the host's files and reads them in place — instead of handing a path to a native desktop opener, which a headless host cannot honour.

在 DSH 网页面板里内置一个「文件」视图标签:左侧两栏目录导航,右侧阅读文件内容。不改动主窗体, 复用聊天窗自己的 Markdown 与代码渲染,点击会话里的任意文件即在其中打开。

Why it exists

dsh web runs on the machine that holds the files; the browser usually does not. Clicking a file reference in a conversation calls remote.session.openWorkspacePath, which on a headless host spawns xdg-open into nothing. This plugin intercepts that one call and renders the file in the page instead.

Features

  • Files as a Session View tab — a third tab beside Chat and Trajectory, full width, one view at a time. No floating window, no sidebar takeover.
  • Click-through from the conversation — tool cards, @path mentions and produced-file chips open here, and the tab is selected for you.
  • The chat window's own renderers — Markdown goes through the shipped MarkdownText, code through the shipped shiki CodeBlock, so both look exactly like the conversation.
  • Relative images in Markdown — ![](./img/x.png) is read from the host and rendered beside the Markdown text (MarkdownText itself only renders http(s) images).
  • Two-column navigation — a parent column (siblings, directories only, current one highlighted) beside the current directory, so hopping sideways never needs a trip up.
  • Editable path — click the bold name in the header, type a path, press Enter. ~ is expanded; a file path lands on its content, a directory path on its listing.
  • Reading-oriented chrome — one merged header row (ancestor path + pinned current name, fish-style ~ and shortening only when the row would overflow), a collapse toggle that puts the listing away entirely (remembered across reloads), and loading feedback that never blanks the pane it replaces.
  • Text is capped at 400 KB per file, images at 4 MB; binary files are announced rather than dumped.

Install

The package is plain ESM with a hand-written browser bundle: no build step, no dependencies.

From a checkout — clone it, then mount it as one row in your profile's patch layer (~/.dsh/profiles/<profile>/cordis.patch.yml):

git clone https://github.com/liooil/dsh-files-pane ~/.dsh/plugins/dsh-files-pane
- insert:
    - id: files-pane
      name: '/home/<you>/.dsh/plugins/dsh-files-pane/lib/index.js'

The loader accepts a path-like entry name, and dsh-client-modules walks up from it to this package's package.json for the dsh.client declaration and the ./client bundle. The bundle is then served at /plugins/dsh-files-pane/client.js.

As a package — the repo declares a dsh.bundle manifest (cordis.patch.yml), so a published copy mounts by name instead:

dsh plugin add dsh-files-pane

⚠️ Use one of the two. Mounting the same package from two sources at once fails the client module scan (resolves from multiple active Loader sources), so remove the local-path row before installing the package (or vice versa).

Changing the plugin set (including this first mount) takes effect on the next dsh start:

systemctl --user restart dsh     # or however your host is supervised

Layout

| Path | Half | Owns | | --- | --- | --- | | lib/index.js | Host (Node) | Two same-origin POST routes, /dsh-files-pane/list and /dsh-files-pane/read, reading the filesystem through the deployment's own fs service. | | client/client.js | Browser | The View tab, the header action, the file-open interception, and all presentation. | | package.json | — | The dsh.bundle manifest (installable), the dsh.client declaration (platform: web), and the ./client export the module scanner reads. | | cordis.patch.yml | — | The bundle patch that mounts this package by name when it is installed as a package. |

The browser half is a hand-written bundle in the client module-table format (window.__ModuleLoader__.load({id, factory})) — the same shape the shipped client packages ship — so it can require("react") and require("@deepseek-ai/dsh-client-ui-primitives") directly.

Two seams worth knowing

Both are reached through Cordis services and both degrade safely, but both are internal enough to deserve a note:

  • Opening the tab. The active View is not owned by a service: the session header and body both read it from the conversation.session slot store (actions.setView). Selecting this tab programmatically therefore goes uiSession.adapter.resolve(sessionId) → slots.resolveStore(entry.store, binding) → store.actions.setView('files'), which is the same cached per-session instance the header reads. If a future release renames either hop, the failure is logged and the plugin falls back to manual tab switching.
  • Taking over the file opener. remote.session.openWorkspacePath is replaced on the Remote namespace service (saved descriptor, restored on unload) and answers with the Remote envelope {ok, value} the caller expects. This is what makes a click in the conversation land here.

The two host routes sit outside /api (no gateway involved), so they carry their own guard: POST only, plus an Origin/Host same-origin check.

Development

There is no build step: edit client/client.js and reload.

  • Browser half only — ask the host to re-hash the bundle in place, then refresh the page:

    ctx.get('clientModules').rebuilt('dsh-files-pane')

    (A tiny Cordis plugin calling this is enough; a page refresh then fetches the new revision.)

  • Host half or package.json — restart dsh.

The client HMR driver only helps while pnpm run dev:web is rebuilding bundles from a checkout; this package is served from its own directory, so the two steps above are the whole loop.

License

MIT — see LICENSE.