Skills Plugins MCP Prompt Model 导航 博客 资讯 我的中心
工具与能力 #deepseek-harness#deepseek-harness-plugin#dsh#dsh-plugin#node-pty#plugin

dsh-terminal

Workspace-aware web terminal plugin for the DeepSeek Harness (dsh). Runs a streaming PTY terminal at /terminal and embeds a split-pane terminal dock powered by xterm.js.

emircanerkul @emircanerkul ⬇ 2 ★ 0 main

安装

dsh plugin --profile web add github:emircanerkul/dsh-terminal
下载安装清单

需要可复现安装时,可在仓库后追加 #commit 固定提交。

Workspace-aware web terminal plugin for the DeepSeek Harness (dsh). Runs a streaming PTY terminal at /terminal and embeds a split-pane terminal dock powered by xterm.js.

该插件未提供要点说明,请参考仓库 README。

deepseek-harnessdeepseek-harness-plugindshdsh-pluginnode-ptyplugin
  1. 安装并启动 DeepSeek Harness:npx @deepseek-ai/dsh web
  2. 在终端执行上面的安装命令(CLI 会解析插件并核验来源)
  3. 用 dsh plugins list 确认已安装,必要时重启 Harness 生效

插件以当前 dsh 进程的权限运行,安装时可能执行代码。请先通读仓库源码与许可证,确认无破坏性命令与越权访问;本站只做索引,不对第三方插件安全性作担保。

代码仓库github.com/emircanerkul/dsh-terminal
许可证MIT
主要语言main
下载量2
GitHub 星标0
最近推送2026-08-20
收录日期2026-09-19
分类工具与能力

事实信息来自公开插件目录快照(2026-10-01),介绍文案由本站再加工。

以下为插件仓库 README 全文(原始内容,由公开目录抓取整理)。

# dsh-terminal

Workspace-aware web terminal plugin for the [DeepSeek Harness](https://github.com/deepseek-ai) (dsh).
Loaded as a **host plugin** by the `web` profile: it serves a terminal page at
`/terminal` (streaming PTY output over SSE, keystrokes via POST) and embeds a
**split-pane terminal dock** into the chat column so you can run `nvim`/`lazygit`
on the workspace you're working in without leaving the page.

## Demo

A quick tour of the workspace-aware terminal dock.

[图片: dsh-terminal demo]

## What makes it "workspace-aware"

- **One PTY per workspace root**, kept alive across SSE disconnects — switching
  conversations preserves each workspace's terminal and scrollback.
- Sessions are bounded by an LRU cap (default 8) **and** an idle reaper, so
  never-again-visited terminals are eventually freed.
- The dock targets whatever chat is *active* by asking the server for its
  authoritative workspace root (validated against the real workspace registry).

## Installation

Install directly from the GitHub repository:

```sh
dsh plugin --profile web add github:emircanerkul/dsh-terminal
dsh web
```

Or clone it locally and install from the local directory:

```sh
git clone https://github.com/emircanerkul/dsh-terminal.git
cd dsh-terminal
npm install
npm run check
dsh plugin --profile web add .
dsh web
```

## Loading

The web profile mounts this plugin through a patch layer and resolves it as a
**package by name** (so DSH's runtime client-plugin discovery can find its
`dsh.client` half — the Settings → Plugins card). In `cordis.patch.yml`:

```yaml
- insert:
    - id: terminal
      name: 'dsh-terminal'
```

with `dsh-terminal` linked into the profile's shared install so both the
loader and the client-modules scanner resolve it:

```sh
ln -s /absolute/path/to/dshterm ~/.dsh/profiles/node_modules/dsh-terminal
```

The plugin declares a client half in `package.json` (`dsh.client` +
`exports["./client"]`, implemented in `client.js`) that contributes a
Settings → Plugins card; the host serves the config through
`GET/POST /terminal/shortcuts` and keeps it in a small file store
(`~/.dsh-terminal/shortcuts.json`), so the plugin stays self-contained and
never waits on the shared settings service. See `src/index.js` for the
plugin row (`inject: ['webServer', 'sandboxPolicy']`).

## Layout

```
terminal.mjs        entry point (re-exports src/index.js — the mounted path)
src/               host-side server code
  index.js         plugin assembly + teardown, idle-reaper timer
  constants.js     limits, MIME table, asset manifest, path roots, knobs
  palette.js       the single fixed terminal palette (no theme switcher)
  pty.js           single node-pty accessor
  sessions.js      PTY lifecycle manager (LRU + idle reaper)
  http.js          body reader / static server / JSON-text response helpers
  workspace.js     workspace-root resolution helpers
  auth.js          page-token mint + ?token= check helpers
  page.js          /terminal page HTML builder
  routes/          all HTTP routes + the chat-column embed tap (split by area)
    index.js         installRoutes() wiring + shared route helpers
    terminal.js      /terminal, /stream, /input, /resize, /kill
    api.js           /bin, /workspace, /debug, /sessions
    assets.js        /terminal/assets/*
    embed-tap.js     chat-column embed injection
web/               browser-side assets served at /terminal/assets/*
  embed.js         the chat-column SPLIT-PANE dock (client LRU of iframes)
  terminal/        terminal page bootstrap + vendored xterm
  fonts/           Nerd Font used for nvim/lazygit PUA icons
test/              unit tests (TerminalSessions) + a module smoke harness
```

## Config / static-asset map

`src/constants.js` holds the knob values (`MAX_SESSIONS`, `MAX_CLIENTS_PER_SESSION`,
`IDLE_MS`, `REAPER_MS`, `MAX_INPUT_BYTES`, `MAX_RESIZE_BYTES`) and the `ASSETS`
manifest that maps public `/terminal/assets/` URLs to files under `web/`.

## HTTP surface (authed = `?token=` from the /terminal page)

| Method | Path               | Purpose                                             |
|--------|--------------------|-----------------------------------------------------|
| GET    | `/terminal`         | the terminal page (mints the auth token)            |
| GET    | `/terminal/stream`  | SSE: PTY output for the workspace                   |
| POST   | `/terminal/input`   | keystrokes into the PTY                             |
| POST   | `/terminal/resize`  | resize the PTY                                      |
| GET    | `/terminal/bin`     | is a command (lazygit/nvim) on PATH?                |
| GET    | `/terminal/proc`     | the executable currently occupying this workspace's terminal (or null) |
| GET    | `/terminal/debug`   | last embed-reported detection diagnostic            |
| GET    | `/terminal/workspace`| authoritative active workspace root + list          |
| GET    | `/terminal/sessions`| live per-workspace PTY debug listing                |
| GET    | `/terminal/shortcuts`| effective dock hotkeys (Settings → Plugins → Terminal) |
| POST   | `/terminal/kill`    | kill one workspace's terminal                       |
| GET    | `/terminal/assets/*`| static files (embed, bootstrap, xterm, fonts)       |

## Keyboard shortcuts

The dock registers global shortcuts that fire whatever has focus — chat, sidebar,
or the terminal itself (the config is relayed into the terminal page, which
captures matching combos before xterm/lazygit see them and asks the dock to act):

| Action            | Default        | Notes                                        |
|-------------------|----------------|----------------------------------------------|
| Toggle dock       | `Ctrl+\``        | restores the last size/position (persisted)  |
| Toggle popup mode | `Ctrl+Shift+\`` | open/close the full-screen floating modal    |
| Open lazygit      | `Ctrl+Shift+G`  | → `lazygit`, only at an idle shell prompt    |
| Open nvim         | `Ctrl+Shift+E`  | → `nvim .`, only at an idle shell prompt     |

Toggling back open restores the previous size and split because those are
persisted per workspace. The launchers first ask `/terminal/proc`, which scans
*this workspace's* PTY process tree for **any** non-shell program (lazygit, nvim,
vim, htop, …). If one is running — whatever it is — the shortcut does NOT type the
new command; instead it shows a short toast telling you to close the running app
first (`Ctrl+C` / `:q`). So pressing `Ctrl+Shift+E` while lazygit is up won't type
`nvim .` over it — it toasts "running lazygit — close it first". A lazygit in
another workspace or a separate terminal never counts: each `/terminal/proc` call
walks only the active workspace's PTY.

Shortcuts are **layout-independent**: each matches `event.key` *or*
`event.code` (the physical key, and multiple codes are accepted). On US the key
left of `1` is `Backquote`; on a UK/ISO ("British PC") layout that key reports
`IntlBackslash` (yielding `key="0"` under Ctrl), so the toggle matches both, so `Ctrl+` `` ` ``
toggles the dock there too. `mod` is one of `ctrl` | `meta` | `alt` | `any`; note
`Cmd+` `` ` `` is the OS "cycle windows" shortcut on macOS, so a `meta` default
would never reach the page — `ctrl` is the safe cross-platform default. Each
binding is set by `key` (character), `code` (physical key; several codes may be
given), or both. Toggle/modal accept both the US `Backquote` and the UK/ISO
`IntlBackslash` physical codes.

**Configure bindings from Settings → Plugins → Terminal.** The Settings card
reads the current bindings from `GET /terminal/shortcuts` and saves them via
`POST /terminal/shortcuts`; the host persists them to
`~/.dsh-terminal/shortcuts.json`. The dock fetches the effective config from
`GET /terminal/shortcuts` on every page load and merges it over the defaults in
`web/embed.js` (no localStorage override path any more). `web/embed.js` is
loaded fresh per page, so after saving in the settings panel a plain browser
refresh picks the new bindings up.

## Development

```sh
npm run check   # syntax-check every source + web asset
npm test        # unit tests for PTY lifecycle (TerminalSessions)
node test/smoke.mjs  # mount the plugin against a mock ctx (wiring smoke test)
```

**Reload behaviour (important):**
- `web/embed.js` is injected as a tiny loader that pulls `/terminal/assets/embed.js`
  fresh from disk on every page load — **embed edits go live on a plain browser refresh**.
- `web/terminal/boot.js` is read **once at module load** and baked into the
  `/terminal` page, so **boot.js edits require a web-profile restart**.
- Server-side edits under `src/**` also require a web-profile restart.
- The Settings → Plugins → Terminal card comes from the `dsh.client` half, so
  it appears only after a web-profile restart realigns loader entry names and
  the browser loads the new client bundle (refresh the page too). From then on,
  saved bindings go live in the dock on a refresh.

## Sponsor

  [图片: Erklab]

Sponsored by [erklab](https://erklab.com) — Architected with production-grade systems using AI-driven velocity and human-centered precision.

数据来源:公开的 DeepSeek Harness 插件目录与各插件 GitHub 仓库。本站为独立第三方目录,与 DeepSeek、幻方(High-Flyer)及插件作者均无隶属或背书关系。

每日精选 Skill 推荐,免费送到你邮箱

输入邮箱,每天接收一个精选 AI Agent 技能推荐。完全免费,持续更新。

提交后我们会发送一封确认邮件,点击邮件里的链接才会开始收信。

完全免费,取消任意时间。我们不会发送垃圾邮件。