DobyChao/dsh-workspace-enhancement0

dsh-workspace-enhancement

Unified SSH remote-execution plugin for DeepSeek Harness — ProxyJump chain, SFTP filesystem, subprocess and PTY over ssh2

包名
dsh-workspace-enhancement
版本
0.1.3
许可证
MIT
最近更新
2026年9月12日

安装

$npx -p @deepseek-ai/dsh dsh plugin --profile web add github:DobyChao/dsh-workspace-enhancement

dsh-workspace-enhancement

English | 中文

npm version license node version dsh-plugin

A DeepSeek Harness workspace-enhancement plugin — local and remote (SSH) workspaces managed in one place. A session can hold multiple workspaces (a main cwd plus a thin declaration list of side directories); machines, TOFU host keys and keychain passwords all live in your local ~/.dsh. Built on ssh2.

Features

FeatureDescription
Remote workspacesctx.subprocess + ctx.fs transparent remote providers: one SSH chain (multi-hop) runs bash / files / PTY / directory browsing with no code changes on the tools
Multi-workspace sessionsThe「⊕ 工作区」button in the session header: attach one or more side workspaces (local dirs or remote machine dirs) as a thin declaration list (mount/unmount + label; the permission tiers were retired with ADR-0019); the model is told about them and can operate them directly
Add-workspace flowConnection sidebar (saved machines, ~/.ssh/config aliases, local) + directory browser (breadcrumbs, native chooser, new folder); remote "Connect & open" creates the session straight on the server
Machine settings pageMachine CRUD / test / set-current / forget host key; OS-keychain passwords; TOFU host keys (accept-new default)
Session awarenessRemote marker + online tri-state + reconnect in the sidebar; per-session prompt injection states the remote / side-workspace context
Cross-server executionsw_exec(server, command) runs a command on a named server (a registry id like c1, or the temporary id of sw_connect save:false; defaults to the session's machine) — the target OS is probed once per connection and reported (bash -c on POSIX, pwsh -Command on win32); on Windows hosts a bash tool is registered for remote-Linux workspaces
Remote approval gateOptional per-machine gate (AUDIT-6 / ADR-0020, default off): every shell-shaped remote command and every remote terminal asks the platform approval service before it runs — human asks you each time, ai auto-grants a short read-only whitelist (pwd, ls, git status, …) and asks for the rest; every ask/reject pair lands in the session's audit log
Model toolssw_status, sw_connect (save:false = temporary), sw_pick_workspace, sw_exec (cross-server execution)
Runtime localizationUI copy, the per-session remote-context prompt, sw_* tool descriptions/errors AND protocol-data validation/routing errors follow the settings-page Language option (zh/en); the UI defaults to the browser language, so a Chinese browser stays Chinese. Only bad-request: protocol-layer diagnostics (machine-readable contract) stay English

How it works

flowchart LR
    subgraph local["Your machine"]
        agent["agent loop
orchestration · memory · LLM calls"] --> seam["this plugin
ctx.subprocess · ctx.fs"]
    end
    subgraph remote["Remote host"]
        run["bash · files · PTY (terminal)"]
    end
    seam -- "one SSH connection (multi-hop jumps)" --> run

No DSH install on the remote: the model orchestrates locally, commands run remotely, results come back into context.

Design notes (implementation facts, not user features):

  • Registry & routing: remote-workspaces/machines.json is the single source of truth; ssh:/// (and the local dsw-routes placeholder tree) route every operation to the right machine; ~/.ssh/config aliases are recognized.
  • Security: TOFU host keys (accept-new / verify / off), per-machine OS keychain (DPAPI / security / secret-tool), credentials redacted in error messages. Remote commands run with the remote OS account's permissions — the local sandbox does not apply to them; the per-machine approval gate can be enabled (default off, ADR-0020).
  • Side workspaces are a thin declaration list (ADR-0019): a side root only declares "this session can operate on this directory directly" (mount/unmount + label) — there are no fs/exec permission tiers, because any absolute path on the same machine is already reachable from a remote session and per-root tiers never fenced shells. Remote side roots still participate in routing (an absolute path under a remote side root goes to that machine even when the session cwd is local); real isolation lives in the per-session sandbox/mode (local) and the operator's trust boundary.
  • sw_exec semantics: the command always runs on a named serverserver takes a registry id or the temporary sw_connect save:false id and defaults to the session's machine (a local session without a server errors). The target OS is probed once per connection (uname -scmd /c verunknown) and reported in the first output line; POSIX/unknown runs bash -c, win32 runs pwsh -Command. The spawn goes through the same mixed provider, so machine routing applies unchanged. run_in_background mirrors the official bash tool (job id returned immediately, no timeout; requires ctx.jobs and errors honestly when absent); sandbox_permissions/escalation is intentionally unsupported (deployment policy only).
  • win32 bash seam: on a Windows host the plugin registers the bash tool itself (the official bash executor is not composed there, so the name is free) — a remote-Linux session runs bash -c on the server, a local Windows session gets a clear error instead of silently degrading; POSIX hosts never register it (the official bash tool owns the name).
  • Remote approval gate (ADR-0020, AUDIT-6): one gate on the mixed subprocess seam's remote branch — bash -c / pwsh -Command-shaped spawns and remote terminals ask ctx.approval before any SSH activity (machine mode remoteApproval: 'off' | 'human' | 'ai' in machines.json, default 'off' so upgrades change nothing). In 'ai' mode a prepend waterfall answerer auto-grants only a reviewable read-only whitelist — everything else, and any classifier failure, goes to the human answerer (fail closed: never policy and missing answerers are deterministic denials). Honest boundaries: the SFTP write path is NOT gated (writing a script + bash script.sh bypasses the shape gate — the structural answer is the planned remote sandbox runner, REQ-I9); the plugin's own fixed probes and sw_connect save:false temporary connections are not gated; local sessions are unaffected. UX-1's remote-full permission preset snippet keeps its canonical home in ADR-0015 (apply it by hand in cordis.patch.yml).

Install

# from npm (v0.1.0+)
dsh plugin --profile web add dsh-workspace-enhancement
# from source: npm run build first (host loads lib/)
dsh plugin --profile web add 

First install with DSH's supply-chain pnpm: native build scripts are blocked by default — allow them once per profile in pnpm-workspace.yaml (unstrict allowBuilds): ssh2, cpu-features, koffi, node-pty, dsh-subprocess-local — then run dsh plugin --profile web install. Without it the first add exits non-zero (ERR_PNPM_IGNORED_BUILDS) and the bundle is not appended.

Compatibility

Which plugin version to install depends on the DSH host family you run — check it with dsh --version (and the family under your DSH install, e.g. /@deepseek-ai/):

Your DSH hostInstallNotes
0.1.5 line (0.1.5-rc.1, 0.1.5-rc.2, …)0.1.4 or newerThe only supported family (peers are ^0.1.5-rc.1). The browser channel rides the official shared /api transport (/api/dsw/), so no standalone /dsw route is needed
0.1.2-rc.1 family (0.1.2, 0.1.3 releases)0.1.3 — the last release of that lineNo longer supported (retired 2026-09-11). That line moved the Connection seam — connection.rpc.handle can no longer register a channel — so no fix is backported to it
any other / older lineNever supported

Host and plugin must move together. The 0.1.4 line speaks /api/dsw/* while 0.1.3 and earlier speak /dsw/*, and 0.1.3 has no readByteRange. Mixing them leaves the connection / directory UI without a data channel (the host still boots, the UI silently cannot load machines or browse). Upgrading DSH means upgrading this plugin in the same step; the full window and the upstream drift log are in docs/compatibility.md.

Roadmap

Current status and remaining milestones: docs/ROADMAP.md. The single backlog lives in docs/backlog.md; the generated state snapshot is docs/status.md.

Development

Start with AGENTS.md (rules, commands, red lines). Then:

DocWhat it answers
docs/backlog.mdwhat is planned, in progress, blocked, done
docs/status.mdversion, HEAD, backlog roll-up (generated by npm run status)
docs/architecture.mdhow the plugin is built and wired
docs/decisions/why it is built that way (ADRs)
docs/testing.mdtest layers, how to run them, sandbox limits
docs/compatibility.mdhost version support window and upstream drift tracking
docs/rounds/what each development round delivered and how it was verified

One gate for everything: npm run check (static constraints + typecheck + unit tests + build + pack smoke) — the same command CI runs.

References

  • dsh-ssh: remote execution engine — ctx.subprocess / ctx.fs providers, jump chains, PTY, directory-picker seam, session.route placeholder.
  • dsh-remote: workspace helper — machines registry, TOFU, OS keychain, web UI and settings page.

License

MIT