dsh-compass
English | 中文
⚠️ Warning: the published npm release of dsh cannot show this panel — a source build can. The last npm release of DeepSeek Harness predates the web slot system the panel renders through. Upstream
master(≥47f9438, verified) ships the slot system, module loader, andshell.overlayseat, and hosts this package directly — build the official repo from source and install there. The fork keeps the same panel in-box. See Requirements.
A single-package DeepSeek Harness plugin adding a right-side context-and-files panel to the Web GUI: directory browsing with git status badges, live injected-context documents with a compaction history stream, a framed read-only git commit graph with working-tree status, panel-file drag into the conversation (image intake for vision models), and a session-log download action.
The package is one bundle, one loader row: the host half mounts the local git backend (/git/*), the plugin-owned directory routes (/dir/*), and the /export command as child plugins; the browser half registers the panel into shell.overlay and the download action into the panel's header utilities.
⚠️ Requirements
The panel renders through the web slot system (window.__ModuleLoader__, the frozen module table, and the shell.overlay seat in ui-layout). Hosts divide into three tiers, verified 2026-08:
- Upstream
master, source build — works.https://github.com/deepseek-ai/deepseek-harnessat47f9438contains the slot system, thedsh.clientmanifest handling, and theshell.overlayrender site; this package's externals all resolve and the panel mounts. Build the repo from source (below) — the npm release is older than these commits. - The fork — works, panel in-box. Its default
webprofile ships the same panel; installing this package there is for running the standalone artifact. - Published npm release — does not work. The last npm release predates the slot system; an install that passes every check while the GUI shows no panel is the expected symptom. Wait for the next upstream release that ships it.
Confirm the mounting surface on your host:
dsh --profile web --dump-config
On the fork the output must contain the ui-context-files, git, directory-routes, and session-log-download rows. On an upstream source build the panel needs no upstream rows of its own — check instead that the served page's boot manifest carries the modules row (packages/client/modules, the __ModuleLoader__ provider).
Screenshots
Files tab — lazy directory tree with directories-first order, basename filter, git working-tree status badges, and per-row open/copy actions:

Git tab — framed working-tree block and commit tree: branch position, uncommitted files, lanes, ref badges, lazy commit expansion, and a refresh control. Workspace rows and commit files open their diff in the centered pop-out, colored by line role:

Context tab — injected-context documents split into the live window and the compaction history stream, with search over both; the view re-projects live and pulls the complete history out-of-band on activation (up to 1,000 messages, the conversation window untouched), so both sections hold the complete log:

Directories first — symlinked directories sort with the directories group:

Panel-file drag — file rows drag their absolute path into the conversation. On fork builds the composer's native intake consumes the drag (image files attach their content directly on vision models). On every other host — including upstream source builds, whose composer does not know the drag MIME yet — the package's own window-level intake takes the drop and appends the path sentence to the draft, which the agent can still act on with its tools. The intake yields to a composer that claims the drag, so both hosts keep exactly one intake:

Main-track compatibility
The package carries every capability surface it needs, so it installs on any dsh build whose web composition includes the slot system (in upstream master since the slot-system commit; the last npm release predates it):
- directory listing and text reads go through the package's own bounded browser (
/dir/*reads the filesystem directly — nodirectoryPicker.readText, no browse backend requirement, works even when the profile composes a native chooser); - the git seam and its local backend ship inside the package (
ctx.subprocess+ctx.webServercome from the base composition); - the conversation reserve uses the package's own
--dsh-compass-widthvariable and a CSS:has()rule against the shell's stable[data-shell-overlay]hook — no fork CSS required (the fork's in-box rule reads a different variable, so no composition double-pads).
Security and performance
Security. Every host route this package registers is loopback-only and refuses to load on a non-loopback webserver host. Request bodies are capped at 64 KiB and must be application/json; every path must be fully qualified, so a wire value never resolves against the host working directory. Reads fail closed: oversized images refuse whole (file-too-large, plus the composed attachment per-file limit as 413), image formats come from magic bytes rather than filename extensions, git hashes are format-validated so no option can ride the hash slot, workspace-diff paths must stay inside the repository, and a git call outside a repository answers not-a-repository. The panel is read-only: git commands never write, dropped images are never copied into the workspace, and file content crosses the wire only through the bounded read routes.
Performance. The context tab's document stream is signature-gated, so the panel re-projects and re-renders only when the injected documents actually change, not per stream batch. Complete history arrives through /dir/injected-docs, which filters the durable log server-side and sends text blocks only; on a session with 181k events this replaced roughly 120 MB of history-page JSON per activation with a single KB-scale response. Every listing and read is bounded (maxEntries, maxTextBytes, maxImageBytes, git maxOutputBytes and maxCommits), every fetch rides an AbortSignal that cancels with the caller, and the per-session fetch markers prune with the session list, so nothing accumulates per departed session.
Install
On an upstream source build, first build the official repo and use its CLI (verified with master at 47f9438):
git clone https://github.com/deepseek-ai/deepseek-harness.git
cd deepseek-harness
git checkout 47f9438
pnpm install && pnpm run build
pnpm dsh --profile web --port 3080 # the stock web profile boots the web GUI
Then, with any host that passed the requirements check, install from this repository with a pinned commit:
dsh plugin --profile web add github:Happy2Git/dsh-compass#<commit-sha>
Git installs build from source through the package's prepare script (transpile-only, no dev context). pnpm ≥10 blocks the build until allowed; on the first failed add, copy the exact key pnpm printed into the profile's pnpm-workspace.yaml:
allowBuilds:
dsh-compass: true
Then re-run the same add. Do not build inside node_modules by hand: a failed add never registers the layer, and a hand build does not register it either. That allowance is permission to execute this package's code at install time — pin a commit so a later push cannot silently change what runs.
Verify the install:
~/.dsh/profiles/web/package.jsonlistsdsh-compassin bothdependenciesanddsh.profile.bundles(a missing bundles entry means theadddid not succeed; re-rundsh plugin --profile web installto register it);~/.dsh/profiles/web/node_modules/dsh-compass/lib/containsindex.jsandclient.js(built byprepare).
On an upstream source build nothing else is needed: the package's own bundle patch disables the stock session-log-download row (its /export command would collide with this package's, and this package ships the command plus its own download button and dialog; the ZIP endpoint itself belongs to ApiProxy and stays).
The fork's default web profile ships the same panel in-box. To use this package instead, disable the in-box panel rows in the profile's own cordis.patch.yml (session-log-download is already handled by the package's own patch):
- id: ui-context-files
disabled: true
- id: git
disabled: true
- id: directory-routes
disabled: true
Restart dsh web, refresh the page, and check: curl -X POST http://127.0.0.1:<port>/dir/list -H 'content-type: application/json' -d '{"path":"<any dir>"}' answers JSON (host half mounted), the browser console has no __ModuleLoader__ error, and the panel is on the right.
Local checkouts install without any build permission:
dsh plugin --profile web add ./dsh-compass
Uninstall
dsh plugin --profile web remove dsh-compass
This runs pnpm remove and drops the package from the layer list; it works even when the profile fails to boot. On the fork, delete the three disabled: true rows added above to restore the in-box panel; on an upstream build the package-patched session-log-download row restores itself.
When the panel still does not appear
- Official npm release of dsh. Expected, not an install failure. The published release has no slot system, so the panel cannot render; uninstall as above, and either build upstream
masterfrom source (see Install) or wait for the next upstream release. ERR_MODULE_NOT_FOUNDat boot. Thepreparebuild was blocked or skipped; apply theallowBuildsstep and re-run theadd.- Boot fails with
command "export" is already registered. The composition still mounts the stocksession-log-downloadrow and the plugin's patch did not land after it. Ensuredsh-compasssits indsh.profile.bundles(pluginaddappends it after the stock bundles) and that the profile'snode_modules/dsh-compass/cordis.patch.ymlcontains thesession-log-downloaddisable. - Host routes answer but no panel in the GUI. The host build lacks the slot system; re-check the requirements.
Building
pnpm build (also the prepare script) runs tsdown only — the shipped entry points transpile from src/ with no type checking, so a git install builds self-contained. Type safety is owned where the sources originate: these sources are typechecked under the fork's strict aggregate before extraction, and the bundled tsconfig.json maps the @deepseek-ai/dsh-* types to a sibling ../deepseek-harness checkout for editor support.
Roadmap
The package is published and installable; here is where it goes next. Star or watch the repo to follow along.
- English UI locale. The panel copy is Chinese today; add an English dictionary behind the locale service.
- Exact-path git output. The git backend parses
--name-status/--numstatwith default quoting; switch to-zNUL-terminated output so paths with quotes or tabs display exactly. - Rename-aware file list. Show a rename as one row instead of a delete + add pair.
- Drag-to-attach on upstream. Upstream's composer does not know the panel drag MIME, so the package's own intake degrades to the path sentence; an upstream ui-conversation PR adopting the MIME would restore image attach on source builds.
- dsh-terminal. The terminal TUI is packaged the same way and stays local until its feature set grows.
License
MIT. Copyright (c) 2026 DeepSeek.
No comments yet. Be the first to write one.