Full sidebar workbench with file rendering and editing, terminal, Git, and subagents; third-party plugins can register new tabs.
Install
# from npm (prebuilt)
dsh plugin --profile web add dsh-better-sidebar
# from GitHub (first run asks for allowBuilds approval — follow the hint, retry)
dsh plugin --profile web add github:omdsh-dev/DSH-better-sidebar
Any plugin you install runs third-party code with your own permissions — it can read your files, use your credentials, and reach the network, and tool approvals don’t sandbox it. GitHub-sourced plugins also run build scripts at install time — pnpm blocks those until you allow them, so an install can stop with ERR_PNPM_GIT_DEP_PREPARE_NOT_ALLOWED or ERR_PNPM_IGNORED_BUILDS; dsh prints the exact key to add under allowBuilds in your profile’s pnpm-workspace.yaml, and the install works on the next run. Allowing a build is a trust decision: only install sources you trust, and pin a commit (github:owner/repo#sha).
README
[!IMPORTANT] Built on DSH's native sidebar API (since v0.19.0): the right column is DSH's own sidebar — the plugin registers every tab type as a native tab (no right panel of its own anymore) and keeps only its self-drawn bottom workbench and the
ctx.betterSidebarservice open to every plugin.Since v0.21.1 the host support floor is DSH
0.1.7-rc.1+(peer floor^0.1.7-rc.1; v0.22.0 is npm'slatest). DSH 0.1.7 ships a complete document preview of its own, so the plugin hands every read-only preview (spreadsheets / PDF / images / Office) back to the built-in and keeps only Markdown / HTML and the editable code editor. Hosts on 0.1.6-alpha.2 or earlier should pindsh-better-sidebar@0.19.1— the DSH-to-plugin version table is in Installation.
📑 Contents
- ✨ Features
- 🚀 Installation
- 🖼️ Feature Tour
- 💬 Community
- 🆕 Recent Updates
- ⌨️ Keyboard Shortcuts
- 🔌 Service API
- 🛠️ Development & Build
- 🔐 Security · ⚠️ Known Limitations · 🖥️ Platform Support
- 🌐 Plugin Ecosystem · 🤝 Contributing · 👥 Contributors · 🔗 Friends
✨ Features
What this plugin adds on top of DSH's stock sidebar:
- ✏️ Editable editor: the host's document preview is read-only → the plugin keeps an editable CodeMirror editor (save, syntax highlighting, preview toggle); Markdown / HTML also render through the plugin's own pipeline (Mermaid diagrams with safe rendering + click-to-zoom, README-level inline HTML, floating table of contents, sandboxed HTML preview)
- 🗂️ Enhanced file tree: takes over the built-in Files page — lazy-loading tree, expanded directories watched live and auto-refreshed, symlink awareness, global filename search, drag-and-drop upload, hover
@fileto drop a reference into the input box - 🌿 Changes (no Git panel in the stock sidebar): two lenses in one tab — Git (diff / history / stage·commit·revert) and This Session (every file the model touched) — with a unified diff renderer (intra-line character highlights, syntax coloring, secret redaction)
- 🧩 Background Tasks (absent upstream): agent topology preview + background task list (exit codes / live output / force-kill)
- 💬 Side Chat (absent upstream, beta): Codex-style side threads — inheriting the full parent context, running independently, promotable to a top-level session
- 🖥️ Bottom workbench (absent upstream): the right column belongs to DSH's native right sidebar; the plugin adds its own bottom workbench (drag-to-split panes, per-session persistence) that coexists with the native bar
- 📂 Model-driven sidebar opens (opt-in): the
sidebar_opentool lets the model actively open files / folders / web pages in the sidebar - 🔌 Service API:
ctx.betterSidebaris open to every plugin (registerTab/registerFileViewer); the built-in 5 tabs + 3 viewers go through the same API, and 28+ ecosystem plugins already build on it (see "🌐 Plugin Ecosystem") - ⚡ On-demand loading: ~325KB core at startup, editor / Mermaid / third-language dictionaries load on demand · 🌏 i18n follows DSH's language · 🔁 Session isolation persists layout per session
🚀 Installation
Prerequisites: DSH installed (dsh web boots), Node.js ≥ 20, pnpm ≥ 10.
Supported DSH versions:
📌 Channel and support line:
v0.22.0is the stable release (npmlatest) and targets DSH 0.1.7-rc.1+ only. Pin the DSH version exactly:npm i -g @deepseek-ai/dsh@0.1.7-rc.1(rc.1 rides npm'snextdist-tag). Hosts on DSH 0.1.6-alpha.2 or earlier should pindsh-better-sidebar@0.19.1— 0.1.7's breakage (the settings-service rewrite, the icon-export renames, session format v3→v4) is large enough that this version ships no compatibility layer.
🧭 Pick the plugin version that matches your DSH:
Your DSH Install command Version / peer declared 0.1.7-rc.1+ (including a later 0.1.7 stable) dsh plugin --profile web add dsh-better-sidebar@latest0.22.0, ^0.1.7-rc.10.1.7-alpha.1 / 0.1.7-alpha.2 nothing to install — move DSH to rc.1 first, then run the row above: npm i -g @deepseek-ai/dsh@0.1.7-rc.1— 0.1.6-alpha.2 and earlier, 0.1.5-rc.*(including the 0.1.5-rc.3 that is npm'slatest)dsh plugin --profile web add dsh-better-sidebar@0.19.10.19.1, ^0.1.5-rc.10.1.5-alpha.2dsh plugin --profile web add dsh-better-sidebar@0.19.0-alpha.1^0.1.5-alpha.20.1.2-rc.*dsh plugin --profile web add dsh-better-sidebar@0.18.1^0.1.2-rc.10.1.2-alpha.2dsh plugin --profile web add dsh-better-sidebar@0.18.0-alpha.0^0.1.2-alpha.20.1.0-rc.8/0.1.1dsh plugin --profile web add dsh-better-sidebar@0.17.1^0.1.0-rc.8Swap
webfor your own profile name. Older versions are pinned exactly (@0.19.1, not@latest), becauselatestmoves forward with each new stable cut; conversely, do not install 0.19.1 on a 0.1.7 alpha — it would simply break.
dsh plugin --profile web add dsh-better-sidebar@latest
The plugin depends on no package that needs a build script (the terminal and
node-ptywent back to DSH wholesale), so installing is one step; once installed you can enable / disable it on DSH's own Plugins page.
Then hard-refresh the browser (Cmd/Ctrl+Shift+R) to see the sidebar (DSH hot-reloads client changes; only host-half updates need a restart).
Or let DSH install it for you — paste this prompt into any DSH session:
Install the dsh-better-sidebar plugin (a sidebar workbench for DSH):
1. Run: dsh plugin --profile web add dsh-better-sidebar@latest (`latest` is the current stable)
2. When done, remind me to hard-refresh the browser (Cmd/Ctrl+Shift+R)
If anything fails, check the troubleshooting table in the README at https://github.com/omdsh-dev/DSH-better-sidebar
Option 3: one-shot script — from a clone of this repo, run bash scripts/install.sh (macOS / Linux / Windows Git Bash; native Windows uses install.ps1; -h for options) — it installs and registers the bundle in one go (including idempotent cleanup of an old manual mount row).
dsh plugin --profile web add dsh-better-sidebar@latest
or bump the version in ~/.dsh/profiles/web/package.json to the matching npm version ("^0.22.0") and run pnpm install. Then hard-refresh the browser (Cmd/Ctrl+Shift+R) — client changes do not need a DSH restart.
| Symptom | Cause & fix |
|---|---|
Ignored build scripts |
pnpm 11 blocked a transitive dependency's build script. Run pnpm approve-builds (no --all) in the profile directory (~/.dsh/profiles/web) and follow its prompts — the plugin itself has no build-script dependency (node-pty left with the terminal). |
minimum release age / version < 24h |
The release is younger than 24 hours. Wait, or re-run once (pnpm auto-adds minimumReleaseAgeExclude). |
| "profile directory not found" | Run dsh web once so it initializes ~/.dsh/profiles/web. |
| Two sidebars on the page | Double-mount. Old hand-written line: ~/.dsh/profiles/web/cordis.patch.yml still has - insert: ... better-sidebar ... — delete it (a same-id duplicate mount makes the loader fail loudly with duplicate loader entry id). When an aggregate bundle (e.g. @linxin666/dsh-web-ui-all) mounts this package under a different id, the plugin's own bundle patch backs off automatically since 0.13.x (it detects an already-enabled mount of the same package name and does not mount itself) — no manual fix needed; if it still double-mounts, make sure the aggregate bundle precedes dsh-better-sidebar in dsh.profile.bundles. |
| Where did my settings go after upgrading? | DSH 0.1.7 removed the registrable settings namespace: preferences now live on this plugin's mount row in the profile (entry id better-sidebar by default), not in ~/.dsh/settings.yaml. On first boot the plugin imports the dsh-better-sidebar section of the old settings.yaml (renamed settings.yaml.imported by the host) exactly once — only fields the current schema still declares, and only while that row has no user values yet, so it never overwrites values set after the upgrade. |
| Terminal unusable / shell fails to start | The terminal comes from DSH's own ui-sidebar-terminal (this plugin no longer ships a terminal or node-pty, and has no terminal settings). Consult DSH's own docs for problems; if the error mentions build scripts, see the row above. |
dsh: command not found |
Install DSH first, or run npx -y --package @deepseek-ai/dsh dsh plugin --profile web add dsh-better-sidebar@latest. |
To debug local changes or track the dev branch, point the dependency at a local clone and build it yourself:
1. git clone https://github.com/omdsh-dev/DSH-better-sidebar.git ~/Code/DSH-better-sidebar
cd ~/Code/DSH-better-sidebar && pnpm install && pnpm build
2. In ~/.dsh/profiles/web/package.json dependencies write "dsh-better-sidebar": "link:<absolute path of the clone>"
3. Append this mount line to ~/.dsh/profiles/web/cordis.patch.yml (this row's `config` IS this plugin's settings form: the deployment limits `readLimit` / `mediaLimit` / `uploadLimit` / `listLimit` plus the user-preference fields — that is what the settings page writes; omit it and every field falls back to its schema default):
- insert:
- id: better-sidebar
name: 'dsh-better-sidebar'
config:
readLimit: 524288
4. Run pnpm install in ~/.dsh/profiles/web
5. Restart DSH and hard-refresh
Update: git pull && pnpm install && pnpm build → just hard-refresh the browser (client changes hot-reload; only host-half changes need a DSH restart). To switch back to the npm channel, restore the matching npm version ("^0.22.0") and re-run pnpm install.
Prerequisite: DSH with plugin-registry integrated (dsh registry available). Enabling both channels double-mounts (the Node half loads twice, the page gets two sidebars).
git clone https://github.com/omdsh-dev/DSH-better-sidebar.git && cd DSH-better-sidebar
pnpm install && pnpm build
node scripts/package-registry.mjs # assemble the registry/ staging (manifest + artifacts + README, not committed)
dsh registry install ./registry # install (disabled by default)
dsh registry enable dsh-external/dsh-better-sidebar
Update: git pull && pnpm install && pnpm build → node scripts/package-registry.mjs → dsh registry uninstall/install/enable. Remove the other channel's mount before switching.
🖼️ Feature Tour
Below are real UI screenshots (two per row; click to zoom).
🗂️ File Workbench: ExplorerTwo explorer modes: embedded in the file preview / standalone file tree. Lazy-loading directory tree whose expanded directories the host watches per directory and re-lists on change, symlinks classified by target kind (directory links expand, dangling links flagged), global filename search, file/folder upload buttons plus drag-drop upload, context menu (open in new tab / open to the side / copy paths), and a hover @file button that references a file straight into the composer. |
📝 Inline Preview: Markdown · HTMLThe Markdown preview renders Mermaid diagrams (strict-mode safe rendering + a second sanitize pass; click a diagram for a zoom modal with wheel-zoom and drag-pan), README-level inline HTML (badge walls <div align=center>, <details> blocks nesting markdown, inline tags in table cells — DOMPurify-sanitized, <script> stripped, local media rewritten to the session media route) and a floating table of contents (appears with ≥3 headings, smooth-scroll jumping, auto-expanding folded blocks); HTML uses the plugin's own sandboxed preview with the two escape hatches the host does not have (htmlViewerNoSandbox / htmlViewerDefaultUnsafe). Images / PDF / spreadsheets / Office are no longer a plugin capability — the host's own document preview renders those formats. |
| 🖥️ CodeMirror editorAn editable text / code editor (save, syntax highlighting, preview toggle) — the host's own document preview is read-only, which is exactly why the plugin keeps its catch-all viewer. | 🖼️ Images / PDF / spreadsheets / Office (provided by DSH)These read-only formats render in DSH's own ui-sidebar-documentpreview: host-side Office→PDF conversion, worker-backed spreadsheet tables, image / PDF zoom viewports, and per-directory auto-refresh. The plugin deleted its own image / pdf / download-fallback viewers and no longer claims those extensions. |
💻 Terminal (provided by DSH)The right-Sidebar terminal is provided by DSH's own ui-sidebar-terminal: shell picker, double-click rename, reconnect, restore after reload, theme and contrast following. The plugin no longer ships xterm + node-pty.⚠️ Model-side caveat: the plugin's own 8 terminal_* tools (off by default) were the model's only cross-call persistent terminal; the upstream equivalent @deepseek-ai/dsh-tool-terminal is not mounted by any shipped bundle, so if you need that capability, add a tool-terminal row to your profile's cordis.patch.yml yourself. |
🌿 Changes: Git lens + This-Session lensTwo lenses on "what changed?": the Git lens keeps the full source-control surface (stage / unstage / commit (Ctrl+Enter) / revert, history, worktree and child-repo selectors); the This Session lens folds the session event log live, recording every file the model read / wrote / edited (grouped by file, kind-filtered, op-count badge). Clicking any change previews it in the draggable bottom pane with the unified diff — del red / add green / mod-blue pairing + intra-line character highlights + syntax coloring + context folding — or expands into a VSCode-style dedicated diff tab (same rendering stack). |
🌐 External-link takeover (browser view provided by DSH)Web tabs are DSH's own ui-sidebar-browser (multiple tabs / back-forward-reload / address bar / sandboxed iframe), mounted only in the desktop profile since 0.1.7 — the Web profile has no such kind. The plugin keeps the half the host does not provide: it takes over only links a tab type explicitly claims through urlTarget (Ctrl/Cmd-clicks always pass through) and lets everything else through to the host (whose linkOpening user setting decides where prose links go); the three protocol-routing settings are gone, and a claim whose target type is unavailable at open time falls back to window.open. |
🧩 Tasks: Agent Topology + Background JobsLive subagent-tree topology (run states, batched live previews) plus the background-jobs list (exit codes / live output / force-kill); new subagents / jobs can auto-activate the Tasks page, expanding the sidebar on wide viewports without forcing narrow full-screen drawers open (configurable). |
| 💬 Side Chat (beta)Codex-style side threads: one independent tab per conversation; the thread inherits the parent's full context (including the in-progress turn, honestly frozen as "interrupted") and runs independently without polluting the main session; follow-ups survive restarts; one click promotes the thread to a top-level session. | 🖥️ DSH's native right sidebar + plugin bottom workbenchThe right column is DSH's own sidebar: the plugin registers every tab type as a native tab (including taking over the built-in Files page), so clicking a file in the chat lands there directly — formats the host's own document preview already covers are rendered by the host, and the plugin claims only Markdown / HTML / editable code; the plugin's own bottom panel can stay open alongside it — drag a tab to a pane edge to split, to the middle to merge, drag the top edge to resize; the toggle lives in the session header. |
⚙️ Declarative SettingsThe "Side card" section in DSH settings: one small card per tab / viewer with an independent toggle (highlighted enabled state + brand switch); secondary settings open from the "Feature settings" strip at the card bottom (switch / text / number / select rows); plugin-owned settings persist under pluginSettings, while the whole preference set lives on this plugin's mount row in the profile (since DSH 0.1.7 settings are addressed by Loader entry id). |
📱 MobileOn narrow screens (<768px) the panels become a full-width drawer: bottom-panel tabs merge into the sidebar once, with touch-friendly dragging. |
💬 Community
WeChat / QQ group QR codes will live here. After uploading the QR images (drag them into any issue/comment to get a user-attachments link), replace src below and uncomment:
🆕 Recent Updates
Supported DSH versions: · full release history on the Releases page
v0.22.0
📦 Stable release (npm
latest): the support line is unchanged — DSH 0.1.7-rc.1+ only (peer floor^0.1.7-rc.1, CI pins@deepseek-ai/dsh@0.1.7-rc.1), so v0.21.1 users can upgrade straight away. Hosts on DSH 0.1.6-alpha.2 or earlier keep pinning v0.19.1.
- 🧩 The Tasks page is now a workflow graph (the primary view): the session tree renders as layered nodes joined by bezier edges — drag to pan, wheel-zoom to the cursor, fit to the content box, a control cluster bottom-right (graph/tree toggle + fold switch + zoom + fit); the classic indented tree is kept (keyboard-navigable) and both modes share one view model, so fold state and team enrichment never drift apart.
- 🃏 Two-segment node cards: the top segment is the kind badge (main agent / subagent / teammate / workflow / completed aggregate) + phase badge + name + meta; the bottom bar is the state dot + state word + the same merged activity line the main agent shows (concurrent tools grouped and counted, with the running call's detail — wording from the host's
chatnamespace) + a fold button on finished nodes; a running bar is swept across its whole width (disabled underprefers-reduced-motion). 8px-rounded, hierarchy carried by a faint top-segment tint only, the session you are on wearing a heavier accent border. - 🔀 Workflow runs enter the graph: runs folded from
tool-workflow/*events (the same events the official panel folds) hang under their origin agent, with member agents re-parented below and boxed per phase with matching badges; members with no catalog row are synthesized from the run's own data, so a finished run still shows who took part. - 🗂 Folding split into two groups that say what they hold:
✓ N completed(including failures, called out asN failed) andN idle(teammates that finished a turn and can be called back at any moment) are two separate rows; the manual fold button always works, the automatic rule only sweeps idle members once there are 3 or more, and an aggregate's name line reads "first two names ++N". - 🪟 Two persistent floating windows (extracted into a reusable
FloatingWindow): background-job output and the shared task's detail/edit surface — draggable, resizable from every edge, a self-scrolling body, dismissed only by the close button or Escape (no outside click / blur / anchor observer); the task window hands its spare height to the description, so enlarging it gives the content room, and the action row is pinned to the bottom. - 👥 Agent Teams board (experimental layer): members enrich their nodes and an always-visible strip lists the roster and shared tasks; the state machine follows the host (pending → claim → in progress → complete → reopen) with reassign / edit / two-step delete, and stale CAS revisions get their own notice; member activity is overlaid from
subagents.live'srunningflag. - 🔄 Background jobs now read the host's client
ctx.jobs(a pushed roster plus a non-consuming output stream andkill): the plugin deleted its ownjobs.list/jobs.output/jobs.killroutes and the event-replay mirror, never touching the model'sjob_outputcursor; output streams in a persistent floating window with tail-follow, and the drawer auto-collapses at 8+ agents. - 🛠 DSH 0.1.7 data-plane rewrite: upstream deleted the three
agentTeams.remoteView-style Remote methods → team reads moved to the Lead Session'sagentTeamSession projection (push-based; theteams.viewroute and its 5-second poll are gone); the two write routes stay, with rejections moved from a result union to a thrownTeamErrorand a stale revision mapped to a 409team-conflict. The bug this fixed in the wild: on 0.1.7 the team strip never rendered at all (the route answeredremoteView is not a function, and the page degraded silently). - 🐛 Four defects caught on a real host, all green in unit tests: the per-node fold button did nothing (blocked by the automatic rule's guards); an idle card never drew a fold button; claiming a task mislabelled it "blocked"; and "complete" on a queued task always failed (a claim comes first).
- 🎨 Narrow panes and mobile settings: card and row metrics re-tuned for the native right sidebar's narrow width; the settings page gained a Mobile group — on a narrow viewport (≤768px) the Tasks page no longer auto-opens and defaults to the tree view.
v0.21.1
📦 Stable release (npm
latest): supports DSH 0.1.7-rc.1+ only (peer floor^0.1.7-rc.1, CI pins@deepseek-ai/dsh@0.1.7-rc.1). Hosts on DSH 0.1.6-alpha.2 or earlier should stay on v0.19.1 — 0.1.7 moves three hard contracts (the settings service, the icon named exports and the session format) and this version writes no runtime compatibility layer. ⚠️ The previous v0.20.0 was never published to npm: its terminal / browser handover ships here too, so npm goes straight from 0.19.1 to this version.
- 🗂️ Read-only file previews handed to DSH's document preview: DSH 0.1.7's
ui-sidebar-documentpreviewships its own spreadsheet / PDF / image / Office rendering (host-side Office→PDF conversion, worker-backed spreadsheet tables, image / PDF zoom, per-directory auto-refresh), so the plugin deleted itsimage/pdf/binary-downloadviewers and refuses those extensions ineditor.canOpen—xlsx xls csv tsv fods pdf png jpg jpeg gif webp svg bmp ico doc docx ppt pptx— handing the address back to the host. rc.1 takes nine of them back:xlsb/xlt/xltx/xltm/ots/dot/dotx/avif/odshave no host renderer at all (opening one only said "preview is not available"), yet before the handover they reached the plugin's download pane — a regression we introduced ourselves in the previous version. The plugin'scodecatch-all claims them again.fodsstays handed over (the host shows that flat XML as plain text, which beats a download pane). — handing the file address back to the host. Three things the host does not have stay in the plugin: Markdown (its own renderer), HTML (its own sandboxed preview plus thehtmlViewerNoSandbox/htmlViewerDefaultUnsafesafety switches), and the editable text / code editor (the built-in ones are read-only previews); unknown binaries (.zip/.wasm) still land on the code editor's download pane after the binary check, so nothing regresses. - 🔗 External-link takeover narrowed: the three protocol-routing external-link settings are gone (with their keys in all 20 locale dictionaries). The plugin now takes over only links a tab type explicitly claims through
urlTargetand lets everything else through for the host to route (DSH 0.1.7 adds the user settinglinkOpening, deciding whether prose links open in the sidebar or a new tab); when nothing claims a link it does not preventDefault; a successful claim whose target type is unavailable at open time falls back towindow.open(url, '_blank', 'noopener,noreferrer')— which also fixes a real regression from the previous version: http links inside plugin-drawn markdown (Side Chat transcripts / editor previews / diff panes) did nothing when clicked. Separately, the host'sbrowserkind is no longer mounted in the Web profile (0.1.7 mounts it in the desktop profile only). - ⚙️ Settings surface rewritten + preferences imported automatically: DSH 0.1.7 removed the registrable settings namespace in favour of looking a form up by the plugin Loader row's entry id (
SettingsForms: onlydescribe/update/replace/mutate/configureremain). Plugin preferences therefore live in the profile's cordis patch document (i.e. this plugin's mount row), not in~/.dsh/settings.yaml; the schema comes from the plugin module's exportedConfig(this version merges the user preferences intoConfigand marks every preference fieldmeta.volatile = true— that single flag is the entire "settings apply live, without remounting the plugin" mechanism). Your settings are not lost: on first boot the plugin imports thedsh-better-sidebarsection of the oldsettings.yaml/settings.yaml.importedonce (only while that row still has no user values, and only fields the current schema still declares). The entry id is discovered at runtime (this bundle defaults tobetter-sidebar; an aggregate bundle mounts it under a different id) and never hardcoded. - 🔄 Live-refreshing file tree: the plugin takes over the built-in Files page, so the host's own per-directory watch cannot cover that tree — this version adds
/sidebar/ws/fs-watch: the client reports the directories it has expanded, the host watches exactly those withfs.watch(150ms debounce, a 64-handle cap per connection, paths going through the same workspace fence asfs.tree), and a change re-lists just that level; collapsing unsubscribes. Before this, the tree stayed stale until a manual refresh. - 🐛 Session following fixed: the plugin used to read a non-existent
SessionListState.currentfield (its own type mirror invented it, so the compiler never complained), which meant per-session persistence was never actually bound and the narrow-viewport park gate was always false. It now uses DSH 0.1.7'sctx.sidebarRight.mounted(set only when the column really switches to another session). - 🖥️ The model-side cost is unchanged: the plugin's own 8
terminal_*tools (off by default) were already removed in the previous version, and the upstream equivalent@deepseek-ai/dsh-tool-terminalis still not mounted by any shipped bundle — add atool-terminalrow to your profile'scordis.patch.ymlwhen you need a persistent terminal (otherwise the model only has one-shotbash/pwsh). - 📐 Baseline: every
@deepseek-ai/dsh-*pins0.1.7-rc.1, with the@deepseek-ai/cordispeer floor at^4.0.3;ui-primitivesrenamed its whole family of named icon exports (Icon<Name><14|16>→Icon<Name>Regular/Medium, 26 named imports adapted); session format v3→v4 (the Side Chat boundary injection now usesplugin:dsh-better-sidebar, and tool-result messages use the top-levelrole: 'tool'shape, with parsers accepting both old and new shapes for historical logs).
📜 Earlier versions: full release history in CHANGELOG_EN.md (v0.20.0 → v0.12.3) and on GitHub Releases.
⌨️ Keyboard Shortcuts
| Action | Keys |
|---|---|
| Save edits | Ctrl/Cmd + S |
| Git commit | Ctrl + Enter |
| Close tab | Middle mouse button |
| Tab context menu (right-click) | Close / Close Other Tabs / Close Tabs to the Left / Close Tabs to the Right (current pane) |
| Split / merge panes | Drag tab to pane edge / middle |
| Reference file to input | Hover the @file button at end of line |
| Copy file path | Right-click row → copy relative/absolute path |
🔌 Service API
Since v0.4.0 the plugin exposes the ctx.betterSidebar service — other plugins can register sidebar pages and file viewers (the 5 built-in tabs + 3 viewers register through the same service). v0.12.1 completed the base capabilities (complete type exports, capability detection, state subscription, tab badges, lifecycle callbacks, targeted open, plugin-owned settings, etc.).
Full integration docs (complete fields, matching algorithm, HMR pitfalls, declarative settings, version detection, the native-sidebar surface and the skinning contract): docs/external-plugin-guide.md; repository rules (hard constraints / CI / release) live in AGENTS.md.
➕ Add Plugins (recommended plugin catalog)
The dashed cards at the end of the "Sidebar content" / "File viewers" grids in the "Side Cards" settings section open the Add tab plugins / Add preview plugins modals: each declares its open extension point, offers a "Browse more plugins on GitHub" button (the GitHub topic dsh-better-sidebar), and lists the recommended catalog (name / repo / description / install script) — "Open" jumps to the repo, "Copy" writes the install command to the clipboard.
Curating a new plugin: append a PluginEntry to src/client/plugins-tabs.ts (tab registrations) or src/client/plugins-viewers.ts (file-previewer registrations) and tag your repo with the dsh-better-sidebar topic; data integrity is guarded by tests/plugin-list.spec.ts.
🛠️ Development & Build
pnpm install # @deepseek-ai/* devDependencies resolve (baseline 0.1.7-rc.1, alpha dist-tag) — no token needed
pnpm typecheck # tsc --noEmit
pnpm lint # eslint . (flat config: js + typescript-eslint + react-hooks recommended)
pnpm build # → lib/index.js + lib/invariant.js + lib/client.js + lib/client-registry.js + lib/types
pnpm test # vitest (includes manifest consistency guard; build first)
pnpm watch # tsdown --watch
Make thin wrappers (make help lists every target; package.json stays the single source of truth):
make check # aggregate gate: typecheck → build → test → check:consumer-types (mirrors CI)
make mount # real-mount smoke: build + pack → install Chromium → pnpm test:mount
make clean # remove lib/, *.tgz, playwright-report/, test-results/
pnpm check:consumer-types: the consumer-facing declaration-surface guard — type-checks the built lib/types from a browser-only consumer's perspective (no @types/node, skipLibCheck: false); run pnpm build first.
Architecture: a single npm package with host/client halves — host (src/index.ts): /sidebar/api/* JSON API, /sidebar/file media route, /sidebar/html preview route, /sidebar/upload upload route, and two WebSockets (/sidebar/ws/agent-opens for model-driven opens, /sidebar/ws/fs-watch for the file tree's directory watch; fs / git / preview are all session-scoped behind a trust fence); client (src/client/index.tsx): portal sidebar + views + link takeover; state persisted per session in localStorage. Organized per DSH official conventions (no default export, dual client bundles); no dependency on npm / checkout at runtime (@deepseek-ai/* provided by the web profile).
🔐 Security
- Routes protected by a Host-header trust fence (same as
/api);fs.writeis atomic; media/preview routes only serve files inside the session cwd (unlessworkspaceFenceis turned off in settings); git only shells out to the CLI and never sets identity - HTML preview content renders in an opaque-origin sandboxed iframe (no
allow-same-origin/allow-top-navigation,no-referrer, all permission policies disabled); the/sidebar/htmlroute carries a CSPsandbox+ size/path bounds - The settings page can disable the HTML preview's sandbox per feature (
htmlViewerNoSandbox/htmlViewerDefaultUnsafe, off by default, with a warning) — when off, content shares the origin with the UI; only recommended for fully trusted content. The web tab's sandbox is no longer this plugin's surface: the browser view comes from the host (desktop profile); see DSH's own docs for its sandbox and navigation policy
⚠️ Known Limitations
- Git has no push/pull/fetch; Markdown previews provide a manual refresh button with confirmation before discarding unsaved edits; the file tree only watches expanded directories (collapsed folders are unsubscribed, and there is no recursive whole-workspace scan); tool inline file-open buttons cannot be intercepted
- Which read-only previews exist is the host's call: spreadsheets / PDF / images / Office go to DSH's own
ui-sidebar-documentpreview, while the plugin renders only Markdown / HTML and the editable text buffer; the host implementation (rendering details, zoom, refresh timing) follows the DSH version - The browser view exists only in the desktop profile: the Web profile has no host
browserkind and the plugin no longer ships a browser tab, so web tabs are desktop-only; login state / third-party cookies /X-Frame-Optionslimits follow the host implementation - HTML preview renders the saved file (not unsaved drafts)
- No bottom panel on mobile (<768px): on narrow screens its tabs merge into the right sidebar once (after migrating back to desktop they stay in the right sidebar); the desktop bottom panel is only available on wide viewports. Without a selected session, tapping the subdued toggle shows the select-session message; with a selected session, it opens the full-width drawer
🖥️ Platform Support
Windows / Linux / macOS (macOS validated daily; the rest covered by unit tests). The plugin carries no native dependencies (the terminal and node-pty went back to DSH wholesale), so building needs only Node + pnpm, with no compiler toolchain.
🌐 Plugin Ecosystem
The ctx.betterSidebar service opens two extension points to every plugin: registerTab (sidebar pages) and registerFileViewer (file previewers). The 5 built-in tabs + 3 viewers register through the exact same API — fully equal capabilities.
import type {} from 'dsh-better-sidebar' // triggers the ctx.betterSidebar type merge
export const inject = ['betterSidebar']
export function apply(ctx: Context) {
ctx.effect(() => ctx.betterSidebar.registerTab({
id: 'my-plugin:db', title: 'Database', component: ({ scope }) => <DbView sessionId={scope.sessionId} />,
}))
ctx.effect(() => ctx.betterSidebar.registerFileViewer({
id: 'my-plugin:csv', exts: ['csv'], fetchStrategy: 'custom',
load: async (path, scope) => parseCsv(await fetchText(scope, path)),
component: ({ customData }) => <CsvGrid rows={customData} />,
}))
}
The GitHub topic dsh-better-sidebar already hosts 28+ ecosystem plugins (and growing):
📑 Tab Plugins (sidebar pages)
| Plugin | ⭐ | Description |
|---|---|---|
| ChenRuoT/dsh-sidebar-qa | Selection-based side Q&A — Codex-style side questions / Claude Code /btw |
|
| fuhefei/dsh-sentinel | Condition-driven wakeup: file / command / HTTP / process / webhook watches that wake the agent; dock + sidebar branch + global dashboard | |
| Fisfzy/ego-browser | Agent browser: a local browsing tab (@dsh-external/ego-browser, auto-registers the sidebar page when better-sidebar is present, floating-bubble fallback otherwise) |
|
| jiuge2467/dsh-studio | Full-stack enhancement workbench: multi-source MCP visual debugging hub, visual thinking engine | |
| Iwctwbh/dsh-flowglass | Flowglass: live session flowgraph (messages / tool groups / subagent branches) | |
| FeatherHunter/dsh-mattpocock-skills-deck | Game-like mission system for mattpocock/skills: fog-of-war map + task bar | |
| GULI-lab/DSH-element-source | Click any UI element on your dev page to jump to its Vue / React / Svelte / Angular source, straight into the chat | |
| Lzh3070/dsh-file-review-tab | File-change review tab: line-level red/green diffs + undo + chat-line deep links | |
| yq04/dsh-git-remotes | Git remotes tab: branches / upstream / ahead-behind, fetch with prune, ff-only pull, confirm-before-push | |
| ztyhehe/dsh-better-sidebar-svn | SVN source-control tab: status / diff / log / commit / update / revert / conflict resolution — symmetric to the built-in Git panel | |
| Melody-max114/dsh-excel-panel | Excel editing: xlsx preview/edit, live formula evaluation, merged cells, save back to the original file | |
| v587d/dsh-anysearch-refs | AnySearch results as sidebar cards: query, source snippets, highlighted keywords | |
| mlosun/dsh-docs-panel | Global docs panel: portable Markdown notes, readable from any workspace | |
| lnyuqian/dsh-skill-sidebar | Skills panel: scans local skill directories, one-click invocation copy, pinning | |
| g-yixuan/dsh-sidenote | Codex-style side chat + selection annotations (a thin consumer plugin) | |
| thirsty5034/dsh-ssh-tunnel | Multi-host SSH tunnels + SSH manager tab | |
| thirsty5034/dsh-git-forge | GitHub / Gitea accounts, project grants and push policy | |
| YesSanSan/dsh-conversation-outline | Conversation outline tab: per-turn structure, quick jump, one-line LLM titles | |
| Wulabalabo/dsh-sidebar-Explorer-Plus | File-manager tab: upload / move / delete / rename / new folder (write operations) | |
| yq04/dsh-turn-review | Turn review: review agent changes turn by turn | |
| Ghz114514/dsh-refpics | Pinterest-style reference-image search: masonry wall, sidebar board, downloads, save-to-Eagle | |
| yzlin499/dsh-yzlin499-easy-plugins | A handy utility bundle for a bare-bones DSH | |
| dong-victor/dsh-better-sidebar-starter | Run-configurations tab: IDEA-style Run/Debug configs (npm / springboot / python / custom) — one-click launch, history, WebSocket live logs (ANSI colors), parallel instances, cross-platform process-tree kill | |
| [baosfeng/ |
…
Links
More in this category
zhu1090093659/dsh-web#packages/dsh-task-board★ 8076
Task board for the dsh web GUI: a sidebar multi-column kanban whose cards run in real DSH agent sessions and can also be scheduled with cron expressions, executed host-side even with the browser closed.
zhu1090093659/dsh-web#packages/dsh-web-all★ 8076
Plugin and skin collection for the DSH Web UI: task board, Git graph, right-side panel, remote mobile UI, pet, live token stats, and a skin center.
ccch1mneyyy/dsh-TUI★ 3661
Claude Code-style full-screen terminal UI: pixel-whale header, live status line, and streaming thought expansion.
MeteorNOX/DeepSeek-Balance-Whale-Widget★ 3277
A fixed-corner whale widget for the DSH web GUI — balance, today's usage and per-turn cost with peak/off-peak pricing, editable balance-alert and daily-budget bubbles, a module-based custom bubble queue with A/B weighted choices and random lines or images, 30+ vendor templates (OpenAI, OpenRouter, Kimi, SiliconFlow, Ark, Zhipu, MiniMax and more) with per-model balance and subscription quota, plus task-end sound, imported audio, custom roles and a resource manager. Local-only, no telemetry.
Devin-AXIS/deepseek-design#deepseek-idesign★ 1628
Visual design studio for websites, app prototypes, posters, cards, reports, and magazines, with templates, direct element editing, selection-aware AI draft handoff, and export.
Devin-AXIS/deepseek-design#deepseek-ivideo★ 1628
Visual video studio with an editable timeline, animation and media controls, 27 templates, whole-video and selection-aware AI draft handoff, validation, preview, and export.
Community comments
Comments are public GitHub Discussions. Loading them connects to GitHub and Giscus; a GitHub account is required to post.