dsh-web-panel
Claude Code-style native DeepSeek Harness sidebar for VS Code: self-written chat UI (no iframe) reusing the existing dsh web service — workspace-synced sessions, sandbox-permission/model/reasoning pickers, context ring. / VS Code 里的 Claude Code 风格 DeepSeek Harness 原生侧边栏:自写聊天 UI(无 iframe),复用现有 dsh web 服务;工作区会话同步、沙箱权限/模型/推理档选择、上下文占用环。
- Stars
- 1
- Language
- JavaScript
- Created
- Aug 14, 2026
- Updated
- Sep 18, 2026
Introduction
DSH Web Panel
A Claude Code-style native DSH sidebar for VS Code: a self-written native
front-end (no iframe) that reuses your existing dsh web service
(127.0.0.1:3080 by default) and ~/.dsh — no second gateway, no server changes.
Unofficial community extension. Not affiliated with DeepSeek.
Harness compatibility: 0.6.0 speaks the 0.1.6 wire (Typert API Gateway: cookie-authenticated
/api/<ns>/<method>, oneremote.muxWebSocket, durable events plus process-local assistant frames). For DeepSeek Harness 0.1.0–0.1.5 use release 0.5.0; the two wires are not interchangeable.
- Entry points (same as Claude Code): the DeepSeek Harness icon (DeepSeek
blue) in the top-right auxiliary bar — click to summon the chat panel; the
status-bar DSH item shows server state and toggles the panel;
Ctrl+Alt+D. - Sessions: current-workspace sessions only — create / switch / archive / rename / fork; the context meter shows real server-side token data.
- Model & preset: model + reasoning-effort pickers; preset switching is blank-session-only (locked once the conversation starts — a server constraint).
- Capabilities: streaming replies, stop, tool cards / approval cards / todos /
timeline, image attachments (vision),
/compact, Markdown + code blocks. - Protocol: 0.1.6 Typert gateway —
POST /api/<ns>/<method>with named args, a browser-session cookie minted from the launch token, and one/api/remote.muxsocket carrying every stream (session follow, workspace baseline,$events) — see docs/protocol.md.
Install
From a released .vsix:
code --install-extension dsh-webview-0.6.0.vsix
Or build it yourself (run in the repo root):
npx @vscode/vsce package
pwsh -File test\fix-vsix.ps1 # repairs vsce's UTF-8 mangling of package.json
code --install-extension dsh-webview-0.6.0.vsix
⚠️ Known issue: on some Windows environments
vsce packagere-encodes the Chinese text inpackage.jsonas GBK mojibake and can even break the JSON. Always runtest\fix-vsix.ps1after packaging.
Zero-config launch
On startup the extension probes dshWeb.port (default 3080) and attaches if a
dsh instance responds. Otherwise it starts one, trying in order:
dshWeb.command → dshWeb.checkout → dsh on PATH → npx @deepseek-ai/dsh.
The server runs with cwd = the first workspace folder and DSH_HOME pinned
to ~/.dsh (identical to attach — never isolated).
Settings
| Setting | Default | Meaning |
|---|---|---|
dshWeb.port | 3080 | Port to attach to or start on |
dshWeb.attachExisting | true | Reuse a running instance instead of starting a new one |
dshWeb.spawnIfMissing | true | Start a server when none is running |
dshWeb.checkout | "" (auto) | Optional checkout path (launches apps/cli/lib/bin.js) |
dshWeb.command | "" | Full command override, e.g. pnpm dsh |
dshWeb.extraArgs | [] | Extra arguments, e.g. --trusted-host |
dshWeb.attachWaitSeconds | 30 | Seconds to wait for a launcher before starting a server of our own |
dshWeb.takeoverAfterSeconds | 45 | Seconds an attached server may stay silent before we take the port over |
dshWeb.nodeMaxOldSpaceMb | 8192 | --max-old-space-size for the node we launch (0 = Node's default) |
dshWeb.nodeArgs | [] | Extra flags for the node executable itself (checkout launcher) |
dshWeb.followWorkspace | true | Restart self-started server when the first folder changes |
dshWeb.stopOnExit | true | Stop a self-started server when VS Code exits |
Troubleshooting: Output → DSH (logs connection and protocol traffic).
Troubleshooting: missing top-right icon / persistent "Chat" tab
Two independent root causes, both fixed by the bundled one-click fix-dsh.cmd:
Cause 1: the extension scan cache points at a deleted old-version folder
VS Code caches its extension scan in .vscode\extensions\extensions.json. If a new
version is installed by deleting the old folder, VS Code still looks for the old path
at startup → ENOENT → the extension is marked broken and the new version in the same
folder is never discovered (hence no icon).
Fix: test\fix-cache.js — rewrites the cache entry to the new path, drops the
profile-level scan caches (forcing a full rescan), and repairs the placeholder icon
path. Backups are created automatically.
Cause 2: auxiliary-bar container icons / Chat tab persistence live in global storage
VS Code 1.136 stores auxiliary-bar container icons (title-bar / right-edge strip) in
global storage workbench.auxiliarybar.pinnedPanels; the Chat tab's persistence
lives there too. Patching only the per-workspace state is ineffective, and edits made
while VS Code is running get overwritten on exit.
Fix: test\fix-state.js — removes Chat from the global pinned list, registers
dsh-aux, hides the Chat view across all workspace DBs, and backs up every
state.vscdb (.bak-dsh); idempotent.
Usage
- Fully exit VS Code (all windows, including minimized);
- Double-click
fix-dsh.cmdon the Desktop (it refuses to run while VS Code is open); - Reopen VS Code → the blue harness icon appears top-right, Chat is gone.
Development
node test/respond-wire-verify.js # permission/question answer wire shape (14 checks, headless)
node test/approval-card-verify.js # approval card rendering + dedup (12 checks, jsdom)
node test/real-launch-verify.js # spawns the real dsh web server through the launch chain
node test/spawn-verify.js # launch-chain (checkout / dsh CLI / npx) checks
approval-card-verify.js runs the real webview/app.js in jsdom and drives it
uith the same host messages the extension sends. It pins the field-name contract
behind the duplicate-card bug: session-log events carry the approval id as
data.id, while server-request frames carry it as approvalId; reading only the
latter makes the id undefined, so the log card and the replayed frame render as
two identical cards and approval/decided never settles either. It needs jsdom,
so point DSH_CHECKOUT_NODE_MODULES at a checkout that has one, e.g.
$env:DSH_CHECKOUT_NODE_MODULES = '<checkout>\node_modules'.
respond-wire-verify.js is the regression guard for the sidebar's permission
buttons: it stands up a fake dsh gateway, activates the extension against it,
pushes an approval/* and a question/* frame into the sidebar webview, and
asserts the POST /api/respond envelope. The gateway routes client-responses by
the echoed rpcId and then validates the payload against
approvalResponsePayloadSchema / questionResponsePayloadSchema, both of which
require sessionId; a wrong shape is rejected with {accepted:false} and
surfaces to the user as server rejected response to undefined.
License
MIT — see LICENSE.