편집자 노트

Web 终端

A terminal dock merged into the DSH web GUI: hideable, split-screen with the chat column when visible, and integrable with terminal-designed TUI plugins.

이것은 DeepSeek Harness(DSH) 플러그인입니다. 이 사이트는 GitHub README, 설치 정보, 유지보수 상태, 공개 보안 시그널을 모아 보여줍니다.

업스트림에서 중국어 README를 제공하지 않아 저장소 원본 내용을 표시합니다.

dsh-web-terminal

A terminal dock merged into the DSH web GUI: hideable, split-screen with the chat column when visible, and integrable with terminal-designed TUI plugins.

┌─────────────────────────────┐
│  session header  [ 终端 ⇧ ] │  ← toggle button (conversation.session.header.actions)
├─────────────────────────────┤
│  conversation (chat)        │  ← stays mounted & stateful
│  ────────────────────────   │  ← drag handle (resize)
│  [Shell] [Panel] ×│  ← dock tab bar
│  xterm.js terminal / TUI    │  ← full-emulation ConPTY
└─────────────────────────────┘
  • Hide / show: header button or `Ctrl+`` — the dock, the xterm instance and the PTY session all survive the toggle (nothing is torn down; VS Code style).
  • Split-screen: the dock is absolutely docked into the bottom band of the center column; the chat keeps its own scrollport above; height is draggable (120–900 px) and persisted in localStorage (dsh.webTerminal.v1).
  • TUI integration: any terminal-designed TUI runs unchanged inside the PTY (vim, htop, tianshu-tui, …), plus an extension API so plugins can register their own views.

Install

dsh plugin --profile web add link:D:\Deepseek Harness\dsh-web-terminal
# restart the web GUI, then use the header toggle or Ctrl+`

The plugin mounts via cordis.patch.yml (bundle patch layer, dsh-ssh pattern): host half = lib/index.js (node-pty PTY + WebSocket bridge + registry service), browser half = lib/client.js (the dock).

Architecture

PieceFileNotes
Plugin entry (host)src/index.tswebServer inject, routes + webTerminal service under ctx.effect
Routes + WS terminalsrc/routes.tsloopback fence, WebSocketServer({noServer:true}), 1MB/512KB backpressure
PTY layersrc/pty.tsnode-pty direct (^1.1.0, prebuilt win32-x64 ConPTY), TERM/COLORTERM env, powershell.exe default
Shared protocolsrc/protocol.tsframe types + WT_API paths + clamps
TUI registrysrc/tui-registry.tswebTerminal.registerView(def) extension seam
Client entrysrc/client/index.tsdock mount, header toggle slot, `Ctrl+``
Dock UIsrc/client/dock.tsxxterm + FitAddon, tabs, drag resize, TUI channel
TUI channelsrc/client/tui-channel.tswindow CustomEvent channel
Demo adaptersrc/examples/*one dom view (demo:panel, proves the CustomEvent channel)

Wire protocol (/api/dsh-web-terminal/*, loopback-fenced)

server→client: {type:'ready',view,cols,rows} | {type:'output',data}
               | {type:'title',title?} | {type:'exit',code,error?}
client→server: {type:'input',data} | {type:'resize',cols,rows}

TUI plugin integration API

Host side — any DSH plugin registers a view inside its own ctx.effect:

const webTerminal = ctx.get('webTerminal')
ctx.effect(() => webTerminal?.registerView({
  id: 'my-plugin:my-tui',        // namespaced 'pluginId:viewId'
  label: 'My TUI',
  order: 10,
  spawn: ({ cols, rows, env }) => ({
    command: 'npx',
    args: ['--yes', 'my-tui'],
    shell: true,                 // run through the default Windows shell
    env: { ...env, MY_FLAG: '1' },
  }),
}), 'my-plugin: tui view')

Client side — the browser half of the same plugin:

import { dispatchRegister, dispatchUnregister, onTuiEvent, TUI_EVENTS } from 'dsh-web-terminal/client'

ctx.effect(() => {
  dispatchRegister({ id: 'my-plugin:my-tui', label: 'My TUI', kind: 'pty' })
  return () => dispatchUnregister('my-plugin:my-tui')
}, 'my-plugin: tui client')

Events: adapter→dock register / unregister; dock→adapter ready (re-register, self-heal), activate ({id,container} — dom views render here), deactivate, view-state ({id,state:'running'|'exit'|'error',code?,error?}).

Security

  • Every route + the WS upgrade carry the loopback-only fence (remoteAddress ∈ {127.0.0.1, ::1, ::ffff:127.0.0.1}, Host localhost, sec-fetch-site and Origin checks) — LAN-exposed dsh web deployments must not serve these.
  • Client frames are strictly validated; only input/resize are accepted, cols/rows clamped.
  • The PTY is killed on socket close/error, tab close, dock unmount, and plugin dispose (ctx.effect disposer); no fs access from the browser.

Windows caveats

  • node-pty never sets TERM from the name option on Windows — the plugin sets TERM=xterm-256color/COLORTERM=truecolor explicitly in the env.
  • kill(signal) throws on Windows — bare kill() only; Ctrl+C is \u0003.
  • Default shell: powershell.exe (pwsh if installed, cmd.exe last resort). cmd.exe may need chcp 65001 for UTF-8 TUI output.
  • ConPTY emits CRLF natively — the bridge never converts EOL (convertEol:false).

Build

pnpm install        # node-pty ^1.1.0 prebuilt win32-x64 — no compiler needed
pnpm build          # tsc typecheck + tsdown → lib/index.js + lib/client.js
REPOSITORY SIGNALS

보안 및 설치 증거

이 점수는 공개 저장소 메타데이터와 이 사이트에 등록된 설치 증거에만 기반하며, 코드 보안 감사와 다릅니다.

출처 추적 가능

공개 플러그인 카탈로그에서 왔으며, 공개 GitHub 저장소로 연결됩니다.

라이선스

GitHub 메타데이터에서 라이선스가 감지되지 않았습니다.

유지보수 활동

최근 180일 내 코드 업데이트가 있습니다.

설치 증거

재현 가능한 정확한 설치 메타데이터가 아직 등록되지 않았습니다. 저장소 설명에 따라 직접 확인하세요.

설치 라이프사이클 스크립트

검사한 패키지 메타데이터에 설치 라이프사이클 스크립트가 선언되지 않았습니다.

주의 사항missing-license