DSH Plugin Store
Back to home

gxinxing

deepseek-harness-tui

Terminal-native interactive TUI for DeepSeek Harness (dsh) — built with Ink, React for terminals

Stars
5
Language
JavaScript
Created
Aug 13, 2026
Updated
Aug 13, 2026
UITools
GitHub repo

Introduction

deepseek-harness-tui

An interactive terminal chat for DeepSeek Harness — terminal-native style, built with Ink (React for terminals).

Give it a TokenDance key and a dsh install; run dsh --profile tui and you get a zero-chrome terminal chat with DeepSeek models: bottom-anchored transcript, tool calls folded into cells, thinking folding, and a theme that adapts to your terminal via OSC 11. It's a thin, readable plugin (~800 lines of UI) — not a re-implementation of the harness.

English · 简体中文

GitHub stars License DeepSeek Harness

deepseek-harness-tui running in a terminal

Install

Requires Node.js ≥ 20 and the DeepSeek Harness CLI:

npm install -g @deepseek-ai/dsh        # the harness (no Homebrew tap yet)
git clone https://github.com/gxinxing/deepseek-harness-tui
cd deepseek-harness-tui && pnpm install

Wire the plugin bundle into the tui profile (one-time):

dsh plugin --profile tui add @deepseek-ai/dsh-headless
dsh plugin --profile tui add /path/to/deepseek-harness-tui

Use

export TOKENDANCE_API_KEY=sk-...   # or add it to ~/.dsh/.credentials.yaml (0600)
dsh --profile tui                  # open the TUI

In the TUI: ctrl + t folds the thinking trace, esc interrupts the running turn, /help shows all keys and commands.

What it does

  • Terminal-native UI, not a re-skinned echo. The transcript is the surface — no boxes, no chrome. The DeepSeek brand banner (ANSI Shadow logo, gradient) greets you only on the empty state; model · cwd live in a dim footer.
  • Tool calls fold into cells. ⠋ Running <cmd> while active → ✓ <cmd> • 1.2s (or on error), with output merged into the cell, dimmed, and truncated head + tail (… +N lines). No interleaved wall of raw output.
  • Theme derived from your terminal. OSC 11 probes the real background: message tints and code chips are blended from it (12% white over dark, 4% black over light) — never hardcoded hex. Force a theme with DSH_TUI_BG=#ffffff for testing.
  • Thinking you can fold. ctrl + t toggles the reasoning trace; esc aborts the turn at any time via agent.cancel({ kind: 'user' }).
  • Markdown that keeps its shape. Headers keep their #, fenced blocks keep their fences, inline code gets a subtle chip — and CJK/emoji wrap at correct character widths with an aligned gutter.
  • A live viewport. The transcript is bottom-anchored; the tail is always visible. Busy state shows a braille spinner + compact elapsed timer (Working 5s).

Learn more

Model routing (TokenDance)

The profile patch (cordis.patch.yml) routes llm-deepseek through the TokenDance gateway:

llm-deepseek:
  apiKeyEnv: TOKENDANCE_API_KEY
  baseURL: https://tokendance.space/gateway/v1

The provider is registered in ~/.dsh/settings.yaml (llm-pi-ai.providers.tokendance): OpenAI-compatible endpoint, thinkingFormat: deepseek, models deepseek-v4-flash (default) and deepseek-v4-pro. Switch models by editing the provider's models list or overriding llm-deepseek.model in your profile patch.

Prerequisite fix (one-time, per dsh install). TokenDance streams subsequent tool-call deltas with empty name/id; the stock @deepseek-ai/dsh-llm-deepseek adapter overwrites the first frame's call id with "" and the harness loops on unknown tool "". Apply the guard in node_modules/@deepseek-ai/dsh-llm-deepseek/lib/index.js:

- if (call.id !== void 0) block.callId = call.id
+ if (call.id) block.callId = call.id
- ... if (call.function?.name !== void 0) ...
+ ... if (call.function?.name) ...

Applied 2026-08-13 on this machine. The edit lives in the global dsh install and is lost on dsh upgrade — re-apply after upgrading (worth an upstream PR).

Self-inspection · Self-repair · Self-update loop

This project ships a complete automated quality gate — inspect → repair → update — closed loop:

┌──────────────┐    ┌──────────────┐    ┌──────────────┐
│  Local dev   │    │  Pre-commit  │    │  CI / PR     │
│  pnpm check  │───▶│  lint-staged │───▶│  ci.yml      │
│  (one-shot)  │    │  (git commit)│    │  (GitHub)    │
└──────────────┘    └──────────────┘    └──────────────┘
      ▲                                       │
      │                                       ▼
      │                            ┌──────────────────────┐
      │                            │  lint + format:check  │
      │                            │  + test (Node 20/22)  │
      │                            └──────────────────────┘
      │                                       │
      ▼                                       ▼
┌──────────────────────────────────────────────────────────┐
│          deps.yml  (auto-scan every Mon 06:00 UTC)        │
│  Update found → auto PR → review & merge → closed loop   │
└──────────────────────────────────────────────────────────┘

Local inspection

pnpm check        # all-in-one: lint → format:check → test
pnpm lint         # code quality (ESLint)
pnpm format:check # style gate (Prettier)
pnpm test         # unit tests (Node built-in runner, 57 cases)

Local self-repair

pnpm lint:fix     # auto-fix all fixable ESLint issues
pnpm format       # auto-format all source files

On every git commit (husky + lint-staged):

  • staged *.js files → prettier --write + eslint --fix before the commit lands
  • committed code is always clean — no manual pnpm format needed

Dependency self-update

pnpm deps:check   # scan all deps for available upgrades (grouped + audit)
pnpm deps:update  # bump package.json to latest compatible + pnpm install

GitHub Actions auto-runs (.github/workflows/deps.yml):

  • Every Monday 06:00 UTC
  • Creates a deps/auto-update-YYYYMMDD branch + PR when updates exist
  • Manual trigger available from the GitHub Actions tab

CI gate (.github/workflows/ci.yml)

TriggerJobMatrix
push / pull_request to maininspectNode 20 + Node 22
lint
format:check
test (57 cases)
coverage uploadNode 22 only

Any stage failure blocks the merge — main is always green.

Contributing

Issues and PRs are welcome. Good first tasks: upstream the two runtime patches (TokenDance tool-call guard, grep permission-error tolerance), add a screenshot for light themes, or port the welcome banner to other model providers. See INTEGRATION-NOTES.md before touching the event bridge.

License

MIT. An independent community project, not affiliated with DeepSeek or TokenDance.