zjuatri/dsh-terminal-plugin

dsh-terminal-plugin

VS Code–style PTY terminal panel for the DeepSeek Harness Web UI, with tabs, reconnectable sessions, and xterm.js.

Uncategorizedconptydeepseek-harnessdeepseek-harness-plugin

dsh-terminal-plugin

English | 中文

A VS Code-style bottom terminal panel for the DeepSeek Harness (DSH) Web GUI.

  • Press `Ctrl+`` to show or hide the panel.
  • Run multiple terminal tabs; press `Ctrl+Shift+`` to create a new one.
  • Uses a real PTY, so colours, cursor control, the alternate screen, and interactive programs such as vim, python, and top work as expected.
  • Occupies only the central conversation area and never squeezes either sidebar.
  • URLs and file paths in the output open with Ctrl/Cmd + click.
  • Right-click follows the VS Code habit: copies when there is a selection, pastes when there is not.
  • Terminal sessions survive page refreshes and replay recent output after reconnecting.

This is an interactive terminal for the person using the web page. It is separate from DSH agent persistent terminals exposed as ctx.terminals.

Requirements

  • Node.js 20 or later
  • @deepseek-ai/dsh with the Web profile, installed or runnable through npx
  • PowerShell 7 on Windows (recommended; Windows PowerShell is used as a fallback)

ws is installed as a package dependency. Building also requires linking peer dependencies from the DSH profile.

Install and build

Run the following from the repository root:

npm run link-deps  # once: link dependencies from the DSH profile
npm run vendor     # once: download and copy xterm.js assets
npm run build      # build the host, client, and static assets
npm test           # run the test suite

This repository contains only the plugin; it does not provide the dsh command. First confirm that the DSH CLI is available:

npx @deepseek-ai/dsh --help

Use the DSH CLI to add the package to the Web profile and mount the bundled cordis.patch.yml:

npx @deepseek-ai/dsh plugin --profile web add /path/to/dsh-terminal-plugin
npx @deepseek-ai/dsh plugin --profile web add git+https://github.com/zjuatri/dsh-terminal-plugin.git

If @deepseek-ai/dsh is installed globally, replace npx @deepseek-ai/dsh at the start of each command with dsh.

For a local checkout that needs to be mounted manually, add the following entry to the Web profile's cordis.patch.yml:

- insert:
    - id: dsh-terminal-plugin
      name: "file:///absolute/path/to/dsh-terminal-plugin/lib/index.js"

Restart dsh web after installing or changing the host-side plugin. A browser refresh is sufficient for client-only UI changes.

Usage

  1. Open the DSH Web GUI, then click the terminal button in the composer toolbar or press `Ctrl+``.
  2. The first open automatically creates a terminal. Use the + button in the panel toolbar to add tabs.
  3. New terminals use the workspace associated with the current session as their working directory. If that cannot be determined, they fall back to the DSH process working directory.
  4. By default, closing the final tab immediately creates a replacement so the visible panel is never empty. Hide the panel with `Ctrl+`` when it is not needed.

Terminal sessions run in the DSH host process. Refreshing the browser, a brief network interruption, or hiding and reopening the panel does not stop running commands.

Links in the output are underlined and show a pointer cursor. Hold Ctrl (Cmd on macOS) and click to open one, matching the VS Code integrated terminal:

DetectedExampleOpens as
URL with a schemehttp://localhost:3000, https://example.com/a?b=1a new tab
Bare localhost addresslocalhost:5173/app (how dev servers usually print it)http:// is added, then a new tab
Absolute file pathD:\repo\src\index.ts:12:3, /home/u/app/main.js:7a file:// address (the line and column are left for the editor)

For safety only http, https, and ftp are opened; javascript:, data:, and file: are never opened, because terminal output is untrusted content and must not become a code-execution entry point. Relative paths such as ./a.ts are not treated as links either, since there is no base directory to resolve them against.

Hovering a link shows the underline, a pointer cursor, and a “Ctrl+click to open …” hint. A plain click without the modifier opens nothing and never leaks through to the terminal selection. Link hit areas are computed in terminal columns, so wide characters (CJK) that occupy two cells do not shift the link sideways.

Right-click: copy when there is a selection, paste when there is not

Right-clicks inside the terminal are handled by the plugin, matching the VS Code integrated terminal (the browser's own context menu does not appear):

State when right-clickedBehavior
Something is selectedCopy it to the system clipboard and clear the selection
Nothing is selectedRead the clipboard and paste it into the terminal (newlines converted per terminal semantics)

Pasting goes through xterm's paste path, so bracketed paste and friends behave exactly as with Ctrl+V. If the browser denies clipboard access (for example outside a secure context) it fails silently: no error, no damaged terminal.

Configuration

The following options are commonly useful:

OptionDefaultDescription
mountPrefix/dsh-terminalHTTP and WebSocket path prefix for the plugin
shellPathauto-detectedAbsolute path to the interactive shell
shellArgsauto-selectedShell start-up arguments
cwdcurrent workspaceWorking directory for new terminals; supports the {cwd} placeholder
env{}Additional environment variables
rows / cols24 / 80Initial terminal dimensions
scrollbackBytes262144Output bytes retained for reconnect replay
idleCloseAfterMs0Time without attachments before closing; 0 disables automatic closing
maxTerminals20Maximum simultaneous terminal sessions

See src/config.ts for the complete configuration definition.

Security

A terminal is equivalent to a shell opened by the user on the host machine, so only trusted users should have access. Its HTTP and WebSocket requests reuse DSH Web's Host/Origin checks and Cookie authentication. In the uncommon environments where that capability is unavailable, only loopback requests are accepted.

Do not expose the plugin endpoint to untrusted networks or bypass DSH authentication.

Known limitations

  • Resizing the panel does not resize an already-running PTY; a newly created terminal uses the current dimensions.
  • Input is shared when the same terminal is open in multiple browser connections, so the intended use is single-user.
  • Only the most recent scrollbackBytes of output is replayed; older output cannot be restored.
  • A long URL that the terminal wraps is not joined across lines: each segment is matched on its own, so only the part that is a valid URL by itself can be clicked.

Development

Source files are in src/; build artifacts are in lib/. Before committing, run:

npm run build
npm test

The project is licensed under MIT. Bundled xterm.js and its add-on are also MIT licensed; see vendor/README.md.