Back to home@bbboy31

dsh-terminal-tabs

Terminals view tab for DeepSeek Harness web UI — live background job count, streaming output, one-click kill

Stars
0
Language
JavaScript
Created
Aug 26, 2026
Updated
Aug 26, 2026
GitHub repo

Introduction

dsh-terminal-tabs

English | 中文

Turn the background commands your model starts into something visible and closable inside the DeepSeek Harness web UI: a Terminals view tab next to Chat / Trajectory whose label tracks how many background shells and subagents the current session has running (命令行1, 命令行×3). Open it for a management page — one row per running command with a Chinese purpose title, a collapsible one-line command body, start clock plus ticking duration, a live output pane, and a Close button that actually kills the process.

Features

  • Real view tab — registered through the official conversation.view seat, sibling of Chat / Trajectory; selection is managed by the framework.
  • Live label — the tab text re-resolves on every projection from the host-pushed jobsBySession mirror, scoped to whichever session you are viewing. Zero observation RPC.
  • Purpose titles — a local heuristic dictionary maps each command to a short Chinese phrase (cd → 打开文件夹 "Open folder", git status → 查看 Git 状态 "Git status", Start-Sleep → 等待 "Wait", npm run dev → 启动开发服务 "Start dev server"). Subagents show as 子代理任务 "Subagent task"; unknown commands fall back to 执行命令 "Run command" while the raw text stays fully visible.
  • Collapsible body — the command renders one ellipsised line; the chevron flips down/up and unwraps the full text.
  • Live output — expanding a row opens a dark scrollback fed by a private tee on the spawned process: newest ~10 lines auto-follow, wheel up browses history, returning to the bottom resumes following.
  • Timing — start wall-clock (HH:MM:SS) and elapsed time (秒 → 分秒 → 时分) tick every second.
  • One-click close — kills the job through the node half's HTTP route; the jobs registry ownership fence still applies, so cross-session requests are rejected.
  • Stable numbering — rows keep their number while open; re-entering the page renumbers compactly. Background subagents are included, marked with an indigo dot.

How live output works (boundaries)

The browser never touches the model's consuming cursor. The node half wraps ctx.shell.start() at the instance level: every successfully spawned process gets an internal pump (300 ms) that drains the pipe into a per-process ring buffer (48 KiB cap). The wrapper is the process's single consuming cursor; a model-side read returns everything accumulated since its previous read, byte-for-byte — only the cadence changes. Consequences:

  • Background jobs started before the wrapper mounted have no captured output ("(暂无输出)").
  • Persistent PTY terminal sessions (ctx.terminals) do not flow through this channel.
  • The wrapper understands the current ShellProcessRead shape ({ delta }); if that contract changes upstream, output display degrades to empty while close/kill keeps working.

Configuration (cordis.yml config row; all optional)

KeyDefaultMeaning
routePath/dsh-terminal-tabs/closeAbsolute pathname of the kill route
tailPath/dsh-terminal-tabs/tailAbsolute pathname of the output-tail route
includeKinds["bash","pwsh","subagent"]Job kinds shown in the UI

Install

dsh plugin --profile web add github:bbboy31/dsh-terminal-tabs

Pure-JavaScript dual-plane plugin (node half index.js, browser half client.js) — no build step. After installing, refresh the web page.

Uninstall

dsh plugin --profile web remove dsh-terminal-tabs

Or use 插件市场 → installed list → 卸载 (two-step confirm). Uninstalling removes the routes, tab, and stylesheet with the fiber — no residue.

Development note: the Loader caches imported modules by package name — editing the node half requires a package rename or a process restart to take effect; client-half edits apply on page refresh.

License

MIT