dsh-doctor
asdf17128
Find what your DeepSeek Harness (dsh) patches silently broke — dead patches, config fields dropped by whole-config repla…
PROJECT TOPICS
PROJECT README
Terminal + SFTP tabs in the DeepSeek Harness (dsh) web conversation view. Run commands on the harness host machine directly from the browser — green-on-black classic terminal look, persistent cwd, sudo password prompt, command history — and browse/transfer files over the same SSH connection with an SFTP tab.

对话 · 轨迹 · 终端 · SFTP ordering)subprocess servicecd works across commands (cd .., cd ~/x, relative paths, error messages for bad targets)sudo run with sudo -S; the panel masks the password field while sudo is waiting (type it at the bottom line and press Enter)The plugin ships as a dsh profile plugin. On the machine running dsh web:
# 1. Install the package into the web profile (git dependency; pnpm resolves it)
dsh plugin --profile web add <your-account>/dsh-terminal-panel
# 2. Register the plugin in the profile patch layer
cat >> ~/.dsh/profiles/web/cordis.patch.yml <<'EOF'
- insert:
- id: dsh-terminal-panel
name: 'dsh-terminal-panel'
config:
trustedHosts:
- myhost.tailXXXX.ts.net # optional: hosts allowed to drive the terminal
EOF
# 3. Restart the web app (adjust to how you run it)
systemctl --user restart dsh-web
Then hard-refresh (Ctrl+Shift+R) the dsh web page — the 终端 and SFTP tabs appear in the conversation view.
| Field | Type | Default | Description |
|---|---|---|---|
trustedHosts |
string[] |
[] |
Extra hostnames (besides loopback) allowed to call the terminal RPC. Required when the web UI is served through a reverse proxy / Tailscale Serve with a real hostname. |
sshTarget |
string |
'' |
SSH target for command execution, e.g. user@127.0.0.1 or user@my-server. Empty = run commands locally. |
sshIdentity |
string |
~/.ssh/dsh-terminal |
SSH identity file used for sshTarget. |
sshUser |
string |
'' |
SSH username when sshTarget holds a bare host. |
sshPassword |
string |
'' |
SSH password (delivered via SSH_ASKPASS, never through a pty prompt). Empty = key auth. |
Open the 设置 button in either tab (or the first-run setup panel when no
target is configured) and set host / username / password / key path — the
Terminal and SFTP tabs share this one login. Settings persist in
~/.local/share/dsh-terminal-panel/config.json and take effect on the next
command — no cordis.patch.yml edits or service restarts. The panel lists
the host's detected addresses (Tailscale IP first) for convenience, and a
one-click key initialisation for localhost targets.
The SFTP tab opens at the target user's home directory and offers:
Transfers run through the system sftp client in batch mode, reusing the
terminal's SSH credentials — password auth works without extra prompts
(SSH_ASKPASS), key auth is used automatically when configured. The transfer
cap is 64 MB per file (the payload crosses the HTTP layer as base64); for
larger files use scp/rsync from the terminal tab. In local mode
(sshTarget empty) the SFTP tab shows a hint pointing to the settings panel.
When dsh runs sandboxed (bwrap/user namespace — the default on Linux), the
process cannot setuid, so sudo is unusable in local mode. In SSH mode
the panel keeps one persistent ssh -t session (pseudo-tty) per terminal,
exactly like an SSH client:
cd and environment persist natively inside the session- insert:
- id: dsh-terminal-panel
name: 'dsh-terminal-panel'
config:
trustedHosts:
- myhost.tailXXXX.ts.net
sshTarget: user@127.0.0.1 # localhost: sudo works
# sshTarget: user@remote-host # or any SSH host
sshIdentity: /home/<user>/.ssh/dsh-terminal
Set up the identity once (one command, no password prompts afterwards):
ssh-keygen -t ed25519 -N "" -f ~/.ssh/dsh-terminal
# allow shell access (no port forwarding etc.):
echo "restrict,no-user-rc $(cat ~/.ssh/dsh-terminal.pub)" >> ~/.ssh/authorized_keys
# for a remote target, add the same line to the target's authorized_keys
In SSH mode a completion marker is emitted after each command so the panel knows when the remote command finished (it is stripped from the display). Commands reading stdin (e.g.
sudo -S) keep stdin open — type the password in the panel and press Enter; the input is masked.
⚠️ This plugin executes arbitrary commands on the harness host. Anyone who can reach the
/sxec/*endpoints can run commands as the target user.
trustedHosts (DNS-rebinding defence).basic_auth) when exposing it beyond localhost.config.json (0600) and delivered to ssh via SSH_ASKPASS; prefer key auth on shared machines.lib/index.js): a dsh plugin that registers a /sxec/* route family on the harness webserver (term-init, term-run, term-send, term-signal, term-reset, term-read, term-config, term-init-key, sftp-init, sftp-list, sftp-mkdir, sftp-rm, sftp-download, sftp-upload). Commands run either locally via node:child_process (bypassing the harness subprocess sandbox) or through a persistent ssh -t pty session when sshTarget is configured; output is ANSI-sanitised and buffered. SFTP operations spawn short-lived sftp -b - batch processes with the same credentials.lib/client.js): registers the 终端 and SFTP slots in conversation.view and talks to the host via same-origin fetch('/sxec/*') calls (no WebSocket, no extra ports). Both tabs share one settings panel and one theme.git clone <your-account>/dsh-terminal-panel
# edit lib/index.js (host) / lib/client.js (client), then:
systemctl --user restart dsh-web # host changes take effect immediately
# client changes need a hard refresh of the page
MIT
CLASSIFICATION EVIDENCE
系统优先读取 GitHub Topics,再与站内分类词典和词根规则比对。