dsh-ssh-tui 0.7.3 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.en.md +101 -27
- package/README.md +83 -27
- package/docs/remote-ops.md +80 -1
- package/docs/terminals.md +17 -4
- package/docs/windows.md +128 -0
- package/lib/attach.js +14 -1
- package/lib/attach.js.map +1 -1
- package/lib/auth-failure.js +92 -0
- package/lib/auth-failure.js.map +1 -0
- package/lib/commands.js +2 -0
- package/lib/commands.js.map +1 -1
- package/lib/copy-text.js +2 -0
- package/lib/copy-text.js.map +1 -1
- package/lib/diag.js +3 -0
- package/lib/diag.js.map +1 -1
- package/lib/dialogs.js.map +1 -1
- package/lib/display-sock.js +313 -2
- package/lib/display-sock.js.map +1 -1
- package/lib/dsh-compat.js +46 -0
- package/lib/dsh-compat.js.map +1 -1
- package/lib/i18n/en.js +49 -14
- package/lib/i18n/en.js.map +1 -1
- package/lib/i18n/index.js +5 -0
- package/lib/i18n/index.js.map +1 -1
- package/lib/i18n/zh.js +49 -14
- package/lib/i18n/zh.js.map +1 -1
- package/lib/index.js +76 -15
- package/lib/index.js.map +1 -1
- package/lib/line-mode.js +4 -0
- package/lib/line-mode.js.map +1 -1
- package/lib/paint.js +32 -1
- package/lib/paint.js.map +1 -1
- package/lib/picker.js +104 -15
- package/lib/picker.js.map +1 -1
- package/lib/plan.js +8 -0
- package/lib/plan.js.map +1 -1
- package/lib/platform.js +81 -0
- package/lib/platform.js.map +1 -1
- package/lib/preset-rows.js +54 -24
- package/lib/preset-rows.js.map +1 -1
- package/lib/question-wait.js +418 -0
- package/lib/question-wait.js.map +1 -0
- package/lib/selection.js +26 -8
- package/lib/selection.js.map +1 -1
- package/lib/term-text.js +79 -8
- package/lib/term-text.js.map +1 -1
- package/lib/terminal-input.js +13 -0
- package/lib/terminal-input.js.map +1 -1
- package/lib/tui.js +713 -51
- package/lib/tui.js.map +1 -1
- package/lib/types/attach.d.ts +8 -0
- package/lib/types/auth-failure.d.ts +48 -0
- package/lib/types/commands.d.ts +6 -0
- package/lib/types/diag.d.ts +2 -0
- package/lib/types/dialogs.d.ts +16 -0
- package/lib/types/display-sock.d.ts +78 -2
- package/lib/types/dsh-compat.d.ts +44 -12
- package/lib/types/i18n/index.d.ts +13 -3
- package/lib/types/index.d.ts +7 -0
- package/lib/types/paint.d.ts +21 -0
- package/lib/types/picker.d.ts +22 -0
- package/lib/types/platform.d.ts +22 -0
- package/lib/types/preset-rows.d.ts +18 -10
- package/lib/types/question-wait.d.ts +221 -0
- package/lib/types/selection.d.ts +12 -4
- package/lib/types/settings-subagent.d.ts +3 -3
- package/lib/types/subagent-model.d.ts +3 -3
- package/lib/types/term-text.d.ts +14 -0
- package/lib/types/terminal-input.d.ts +10 -0
- package/lib/types/transcript-types.d.ts +22 -0
- package/lib/types/tui.d.ts +149 -3
- package/lib/types/update-check.d.ts +19 -4
- package/lib/types/workspace-changes.d.ts +135 -0
- package/lib/update-check.js +25 -8
- package/lib/update-check.js.map +1 -1
- package/lib/workspace-changes.js +120 -0
- package/lib/workspace-changes.js.map +1 -0
- package/package.json +104 -69
package/README.en.md
CHANGED
|
@@ -6,7 +6,9 @@
|
|
|
6
6
|
[](https://dshfind.com/en/plugins/cyjyyd/dsh-ssh-tui?ref=badge)
|
|
7
7
|
|
|
8
8
|
A DeepSeek Harness terminal for jump hosts, headless servers, and high-latency
|
|
9
|
-
SSH. Plain ANSI and incremental redraws. No browser required.
|
|
9
|
+
SSH. Plain ANSI and incremental redraws. No browser required. **When the SSH
|
|
10
|
+
session drops mid-turn, the Host keeps the turn; reconnecting with the same
|
|
11
|
+
command attaches back to it, so the session is not lost.**
|
|
10
12
|
|
|
11
13
|
中文部署指南:[README.md](README.md)
|
|
12
14
|
|
|
@@ -14,6 +16,20 @@ If you mostly work over SSH — a jump host, a test box, a keyboard-only
|
|
|
14
16
|
session — start here. A local desktop terminal with themes and layout
|
|
15
17
|
you already like can stay as it is.
|
|
16
18
|
|
|
19
|
+
How this differs from what already exists:
|
|
20
|
+
|
|
21
|
+
- **Official headless**: the same task prints only its last reply to stdout; the
|
|
22
|
+
rest stays in the session log.
|
|
23
|
+
- **Official `dsh-ssh` (from 0.1.6)**: the Harness runs locally and files and
|
|
24
|
+
processes run remotely, which needs a helper installed ahead of time. Use this
|
|
25
|
+
plugin when you are already SSH'd onto the machine. The two stack; neither
|
|
26
|
+
replaces the other.
|
|
27
|
+
- **Other terminal skins** (`dsh-TUI` and the like): a good-looking local
|
|
28
|
+
terminal, competing on themes and layout. This plugin competes on incremental
|
|
29
|
+
redraws over a slow link, a Host that survives the drop, and a plain line mode.
|
|
30
|
+
|
|
31
|
+
How to get back in after a drop is under [After an SSH drop](#after-an-ssh-drop).
|
|
32
|
+
|
|
17
33
|
A SuperGrok / X Premium subscription goes through the standalone plugin
|
|
18
34
|
[dsh-llm-xai-oauth](https://github.com/cyjyyd/dsh-llm-xai-oauth) (headless, web, or this TUI). It reuses a local grok-bridge token; no xAI API key.
|
|
19
35
|
|
|
@@ -31,6 +47,8 @@ dsh --profile tui
|
|
|
31
47
|
Current `dsh` requires `--profile` (`dsh plugin add …` errors without it).
|
|
32
48
|
Swap `tui` for another profile name.
|
|
33
49
|
|
|
50
|
+
**On the 0.2.0-rc host line?** 0.8.0 is the release that supports it (older versions are refused by the launcher's version check), but it is published under `next` for now — `latest` is still 0.7.4 until 2026-10-01. Until then install with `dsh plugin --profile tui add dsh-ssh-tui@next`; on the 0.1.7-rc line `@latest` (0.7.4) is enough, and moving to 0.8.0 later costs nothing. **0.1.5 and older hosts are no longer supported as of 0.8.0.**
|
|
51
|
+
|
|
34
52
|
**Updates must use `@latest`.** `dsh plugin` forwards the rest of the line to
|
|
35
53
|
pnpm in the profile directory. A bare `add dsh-ssh-tui` keeps the version
|
|
36
54
|
already pinned in `pnpm-lock.yaml` (often 0.3.7). Do not put `--profile`
|
|
@@ -69,8 +87,12 @@ Reproducible, no model in the loop: `npm run screenshots:slow` writes
|
|
|
69
87
|
`docs/screenshots/slow-link.json`. This capture is 14 paints, about
|
|
70
88
|
**18.0 KB**, **8.8 s** at 2 kB/s. Byte ledger for this event sequence.
|
|
71
89
|
|
|
72
|
-
0.7 highlights: drag-select any part of a model reply to copy it (
|
|
73
|
-
clipboard; a tool card still expands on click
|
|
90
|
+
0.7 highlights: drag-select any part of a model reply to copy it (hold the button, or Shift;
|
|
91
|
+
OSC 52 into your local clipboard; a tool card still expands on click; an SSH session copies
|
|
92
|
+
into the local terminal and no longer warns that it cannot) · a reply is a selectable card too:
|
|
93
|
+
one `↑` on an empty input lands on the newest reply-or-card (marked `▶`, in screen order;
|
|
94
|
+
`Alt+4` selects the latest reply), `/copy` then takes that one as written rather than the
|
|
95
|
+
wrapped screen text, and `Enter` opens it full-screen · the footer is one priority-ordered chip
|
|
74
96
|
strip, and `⚠` opens `/doctor` · the quota bar is on screen from the first frame and names
|
|
75
97
|
its window (`5Hr`/`1Wk`/`1Mo`, smallest window by default, `?%` with a 15-second retry until
|
|
76
98
|
a reading arrives) · `/mode` groups presets and filters with `/` · the compact view names
|
|
@@ -82,8 +104,10 @@ pins the palette (truecolor / 256 / 8 / none).
|
|
|
82
104
|
## Requirements
|
|
83
105
|
|
|
84
106
|
- Node.js >= 22.19
|
|
85
|
-
- `@deepseek-ai/dsh` CLI: `npm i -g @deepseek-ai/dsh` (CI covers `0.1.5-rc.1` / `0.1.5-rc.3` / `0.1.7-rc.1`: `0.1.5-rc.1` runs typecheck and the unit suite, the other
|
|
107
|
+
- `@deepseek-ai/dsh` CLI: `npm i -g @deepseek-ai/dsh` (this repo develops on `0.1.7-rc.1`; CI covers `0.1.5-rc.1` / `0.1.5-rc.3` / `0.1.7-rc.1` / `0.1.7-rc.2`: `0.1.5-rc.1` runs typecheck and the unit suite, the other three add the real-PTY probes, and every non-default leg rewrites the manifest with `scripts/ci-pin-line.mjs` before installing from scratch. `0.1.5-alpha.1` / `0.1.5-alpha.2` / `0.1.3-alpha.2` share the same handle API + `agent/assistant-stream` shims as the 0.1.5-rc line. **`0.1.2-rc` and older are no longer supported** — if the install is refused, upgrade to `0.1.5-rc` or `0.1.7-rc` first. `0.1.3-alpha.1` exists only as a GitHub tag and was never published to npm)
|
|
86
108
|
- pnpm (used by `dsh plugin` to manage profile dependencies)
|
|
109
|
+
- an ANSI terminal (SSH directly, or PowerShell / Windows Terminal on Windows)
|
|
110
|
+
- **Windows**: install, troubleshooting and how to read `/doctor` are in [docs/windows.md](docs/windows.md)
|
|
87
111
|
|
|
88
112
|
## Install
|
|
89
113
|
|
|
@@ -114,7 +138,7 @@ dsh --profile headless "Reply with exactly: tui-install-ok. Do not use tools."
|
|
|
114
138
|
dsh --profile tui
|
|
115
139
|
```
|
|
116
140
|
|
|
117
|
-
From a checkout: `bash scripts/smoke-headless.sh
|
|
141
|
+
From a checkout: `node scripts/smoke-headless.mjs` (or `bash scripts/smoke-headless.sh`; prints an outcome summary, never a token).
|
|
118
142
|
|
|
119
143
|
### After an SSH drop
|
|
120
144
|
|
|
@@ -130,6 +154,22 @@ dsh --profile tui --resume # picker (live hosts first)
|
|
|
130
154
|
dsh --profile tui --resume <session-id> # attach if live, else resume the log
|
|
131
155
|
```
|
|
132
156
|
|
|
157
|
+
The picker gives every live session one of two words and the Host's pid:
|
|
158
|
+
**attachable** (one keystroke in) or **occupied** (another window has it). When it
|
|
159
|
+
says occupied, `--resume <session-id>` is refused rather than kicking that window:
|
|
160
|
+
take it over from the **picker** instead — select the row and confirm with `y` /
|
|
161
|
+
Enter, and the other window exits.
|
|
162
|
+
|
|
163
|
+
**A cut link does not block you.** When SSH dies the server usually does not
|
|
164
|
+
know yet: sshd waits for TCP keepalive (which can be hours), the launcher stays
|
|
165
|
+
connected to the display channel, and the lock still reads `attached`. So the
|
|
166
|
+
Host asks the **terminal itself** (a cursor round trip through the relay — see
|
|
167
|
+
`scripts/tui-cut-probe.mjs`). A terminal that cannot answer means that window is
|
|
168
|
+
gone, the picker says **attachable**, one keystroke attaches, and so does
|
|
169
|
+
`--resume <session-id>`. Only a terminal that confirms it is still there needs
|
|
170
|
+
the takeover question above — and that answer is resolved *before* the list is
|
|
171
|
+
painted, so a row never says occupied and then changes its mind.
|
|
172
|
+
|
|
133
173
|
A second Host on the same `sessionId` is refused (it would steal the jsonl
|
|
134
174
|
and approvals). Locks live under `$DSH_HOME/tui-locks/`; the display socket
|
|
135
175
|
under `$DSH_HOME/tui-socks/`. A leftover lock from a crash is stolen if the
|
|
@@ -155,8 +195,11 @@ New sessions inherit the directory you launched from. Resuming a session
|
|
|
155
195
|
`目录:srv` (last path segment); click it to print the full path.
|
|
156
196
|
|
|
157
197
|
On start, if npm has a newer `dsh-ssh-tui`, a first-launch picker offers
|
|
158
|
-
**Update now / Later / Skip this version**. Update now
|
|
159
|
-
`dsh plugin --profile tui add dsh-ssh-tui
|
|
198
|
+
**Update now / Later / Skip this version**. Update now installs the exact
|
|
199
|
+
version just looked up (`dsh plugin --profile tui add dsh-ssh-tui@<version>`),
|
|
200
|
+
not `@latest`: pnpm resolves `@latest` a second time, and a release still inside
|
|
201
|
+
its `minimumReleaseAge` window is then skipped silently — the install succeeds
|
|
202
|
+
and you are left on the old one. It asks you to restart afterwards.
|
|
160
203
|
Set `DSH_TUI_NO_UPDATE_CHECK=1` to skip. `/status` also shows the plugin version, the link chip, the quota window, and whether the subagent model is in the same family as the parent route.
|
|
161
204
|
|
|
162
205
|
From git:
|
|
@@ -164,9 +207,12 @@ From git:
|
|
|
164
207
|
```sh
|
|
165
208
|
git clone https://github.com/cyjyyd/dsh-ssh-tui.git
|
|
166
209
|
cd dsh-ssh-tui
|
|
167
|
-
|
|
210
|
+
node scripts/install.mjs # installs into the `tui` profile
|
|
168
211
|
```
|
|
169
212
|
|
|
213
|
+
`bash scripts/install.sh` is a thin wrapper around that script, so it does the
|
|
214
|
+
same thing where bash exists. On Windows run the Node form — there is no bash.
|
|
215
|
+
|
|
170
216
|
Or manually:
|
|
171
217
|
|
|
172
218
|
```sh
|
|
@@ -175,6 +221,14 @@ npm run build
|
|
|
175
221
|
dsh plugin --profile tui add "link:$(pwd)"
|
|
176
222
|
```
|
|
177
223
|
|
|
224
|
+
The PowerShell equivalent, since `$(pwd)` is a POSIX substitution:
|
|
225
|
+
|
|
226
|
+
```powershell
|
|
227
|
+
npm install --no-audit --no-fund
|
|
228
|
+
npm run build
|
|
229
|
+
dsh plugin --profile tui add "link:$((Get-Location).Path)"
|
|
230
|
+
```
|
|
231
|
+
|
|
178
232
|
### The preset roster `/mode` needs
|
|
179
233
|
|
|
180
234
|
A terminal profile built on `dsh-base` composes no preset roster (only the Web
|
|
@@ -191,8 +245,8 @@ Three ways to repair it (idempotent, pick one):
|
|
|
191
245
|
1. **In-app**: `/mode fix` writes the block below and tells you to restart.
|
|
192
246
|
This is the generic path — an npm install and the in-app "Update now" both go
|
|
193
247
|
through `dsh plugin add` and never run the repository scripts.
|
|
194
|
-
2. From a checkout: `
|
|
195
|
-
(default `tui`).
|
|
248
|
+
2. From a checkout: `node scripts/profile-rows.mjs [profile]`
|
|
249
|
+
(default `tui`; `bash scripts/ensure-profile-rows.sh` is the same command).
|
|
196
250
|
3. By hand, in `$DSH_HOME/profiles/<profile>/cordis.patch.yml`:
|
|
197
251
|
|
|
198
252
|
```yaml
|
|
@@ -213,7 +267,7 @@ this block lists the roster row twice, and the second mount fails with
|
|
|
213
267
|
|
|
214
268
|
Without the row, the TUI prints a boot line ("No agent-preset roster is
|
|
215
269
|
composed…"), `/mode` reports the patch path plus the `/mode fix` entry point,
|
|
216
|
-
and `scripts/verify.sh` says the same. Preset identity is per module instance,
|
|
270
|
+
and `node scripts/verify.mjs` (`scripts/verify.sh`) says the same. Preset identity is per module instance,
|
|
217
271
|
so a dsh install tree carrying two copies of `@deepseek-ai/dsh-scope` (an
|
|
218
272
|
npm-nested checkout can) fails the mount with `refusing to compose an unscoped
|
|
219
273
|
context`; a global `npm i -g` install is not affected.
|
|
@@ -221,7 +275,7 @@ context`; a global `npm i -g` install is not affected.
|
|
|
221
275
|
For the optional **智能路由模式 (routing-suite)** mode, also run:
|
|
222
276
|
|
|
223
277
|
```sh
|
|
224
|
-
|
|
278
|
+
node scripts/install-routing-suite.mjs
|
|
225
279
|
```
|
|
226
280
|
|
|
227
281
|
The script adds `dsh-routing-suite`, registers its preset for the `/mode`
|
|
@@ -238,8 +292,8 @@ dsh --profile tui
|
|
|
238
292
|
Verify and uninstall:
|
|
239
293
|
|
|
240
294
|
```sh
|
|
241
|
-
|
|
242
|
-
|
|
295
|
+
node scripts/verify.mjs
|
|
296
|
+
node scripts/uninstall.mjs
|
|
243
297
|
```
|
|
244
298
|
|
|
245
299
|
## First-launch setup
|
|
@@ -348,14 +402,15 @@ You can reopen the wizard at any time with:
|
|
|
348
402
|
|
|
349
403
|
| Key | Action |
|
|
350
404
|
| --- | --- |
|
|
351
|
-
| `Enter` | send; while running, steer; with empty input, toggle the selected card. Oversized tool bodies open a dedicated inspect view
|
|
405
|
+
| `Enter` | send; while running, steer; with empty input, toggle the selected card, or open the full view when the selected row is a reply (`Esc` returns). Oversized tool bodies open a dedicated inspect view too |
|
|
352
406
|
| `Tab` | complete the highlighted slash command |
|
|
353
|
-
| `↑` / `↓` | empty input
|
|
354
|
-
| `Ctrl+R` | expand the latest card; once
|
|
407
|
+
| `↑` / `↓` | empty input with cards in the session: walk up from the newest **reply or card** in screen order (the `▶` marker is only ever on the selected row); with no card at all (plain Q&A, or right after `/clear`) the key keeps its history meaning — select a reply there with `Alt+4` or `Ctrl+N`/`Ctrl+P`. Otherwise history (↓ past the newest item restores the live draft) |
|
|
408
|
+
| `Ctrl+R` | expand the latest card; once something is selected, expand or collapse all (a selected reply keeps its selection) |
|
|
355
409
|
| `Ctrl+T` | fold the input box (display-only) |
|
|
356
|
-
| `Alt+1` / `2` / `3` / `4` | jump to latest thinking / plan / subagent / reply |
|
|
357
|
-
| `/find [kind] query` | search and jump to the full matching message (`thinking` `plan` `subagent` `reply` `prompt` `tool`). `Ctrl+/` or `Alt+/` opens it |
|
|
358
|
-
| `/copy` | copy the
|
|
410
|
+
| `Alt+1` / `2` / `3` / `4` | jump to latest thinking / plan / subagent / reply (a reply is selected, ready for `/copy`) |
|
|
411
|
+
| `/find [kind] query` | search and jump to the full matching message (`thinking` `plan` `subagent` `reply` `prompt` `tool`), which is also selected. `Ctrl+/` or `Alt+/` opens it |
|
|
412
|
+
| `/copy` | copy the selected card or reply **as written** to the local clipboard (latest reply if none is selected; OSC 52). The selection survives, so pressing it twice copies the same thing. Inside a full view the copy key (`Ctrl+Shift+C`) takes **the body on screen** — a tool body, a changes diff, or the reply as written — and the overlay echoes the confirmation |
|
|
413
|
+
| `/retryauth [on\|off]` | auto-retry once when the *provider* rejects a request (HTTP 401/403 while a local credential is configured); off by default. The three-step diagnosis is in [`docs/remote-ops.md`](docs/remote-ops.md) §4.8 |
|
|
359
414
|
| `Ctrl+G` / `Alt+N` | next search hit; `Alt+P` previous |
|
|
360
415
|
| `Esc` | drop selection → scroll to bottom → cancel the running turn |
|
|
361
416
|
| `Ctrl+C` | cancel the running turn; press twice when idle to exit |
|
|
@@ -623,8 +678,11 @@ skips token chunks and lays out only the visible tail on the first paint.
|
|
|
623
678
|
|
|
624
679
|
Each paint is one `stdout.write` of dirty rows only, so a jump host or
|
|
625
680
|
corporate proxy does not see one SSH packet per line. Local ttys use 80 ms.
|
|
626
|
-
Over SSH the TUI probes CSI 6n
|
|
627
|
-
|
|
681
|
+
Over SSH the TUI probes CSI 6n and picks 80 / 160 / 250 / 400 ms from the
|
|
682
|
+
round-trip. It keeps measuring — 8 s after the attach, then every 20 s (a
|
|
683
|
+
measurement that moved is confirmed 5 s later) — and both the chip and the paint
|
|
684
|
+
tier follow the median of the last three, so a jittery entry cannot pin either
|
|
685
|
+
at the slowest tier. `DSH_TUI_PAINT_MS` always wins (40–1000). The stats line
|
|
628
686
|
starts with `SSH ●●●○ 90ms` (1 pip red, 2 yellow, 3+ green). The probe
|
|
629
687
|
does not write into the transcript.
|
|
630
688
|
|
|
@@ -639,13 +697,16 @@ Find your symptom; each answer is what to do, not a change log.
|
|
|
639
697
|
|
|
640
698
|
- **`dsh-ssh-tui: both stdin and stdout must be TTYs`** — start it from a real terminal or
|
|
641
699
|
SSH session; a pipe, CI, or `&` background job will not do.
|
|
700
|
+
- **Windows install, the scripts, and how to read `/doctor`** — [docs/windows.md](docs/windows.md)
|
|
701
|
+
has a 30-second install, a "what to check first when it will not start" table, and what the
|
|
702
|
+
`●` / `⚠` / `✖` marks in a `/doctor` report mean.
|
|
642
703
|
- **Windows: `host display socket did not appear`** — upgrade
|
|
643
704
|
(`dsh plugin --profile tui add dsh-ssh-tui@latest`); older builds waited 15 seconds and
|
|
644
705
|
timed out on the named pipe. If it still fails, attach `/diag` to an issue.
|
|
645
706
|
- **Windows: the in-app update reports `spawn dsh ENOENT`** — an older updater spawned a
|
|
646
|
-
bare `dsh`, which on Windows is a `dsh.cmd` shim. Run
|
|
647
|
-
|
|
648
|
-
from then on
|
|
707
|
+
bare `dsh`, which on Windows is a `dsh.cmd` shim. Run
|
|
708
|
+
`dsh plugin --profile tui add dsh-ssh-tui@latest` once from the command line; the in-app
|
|
709
|
+
update works from then on, and it installs the version it looked up rather than `@latest`.
|
|
649
710
|
- **pnpm refuses to run the build script of a git dependency** — add the key pnpm prints to
|
|
650
711
|
`allowBuilds` in the profile's `pnpm-workspace.yaml`, then reinstall.
|
|
651
712
|
- **After an upgrade `/mode` reports a missing service, or the preset tools vanish** — run
|
|
@@ -686,8 +747,17 @@ Find your symptom; each answer is what to do, not a change log.
|
|
|
686
747
|
painter asks for the narrow text form; a font without the glyph still makes the terminal
|
|
687
748
|
fall back to a wider colour emoji.
|
|
688
749
|
- **The screen cannot keep up on a slow link** — `DSH_TUI_PAINT_MS` sets the paint interval
|
|
689
|
-
(40–1000 ms: smaller is snappier and sends more); unset, it follows the round-trip
|
|
690
|
-
|
|
750
|
+
(40–1000 ms: smaller is snappier and sends more); unset, it follows the round-trip,
|
|
751
|
+
which is re-measured while the session runs (80 / 160 / 250 / 400 ms, median of the last
|
|
752
|
+
three) — see `scripts/tui-rtt-probe.mjs`.
|
|
753
|
+
- **The model “thinks, then says it is done”** — that is an **empty turn from upstream**: some
|
|
754
|
+
gateways map a Gemini/Claude thought part onto `reasoning_content` and then finish with
|
|
755
|
+
`finish_reason: stop` and no content at all, so the harness assembles a reply that is only
|
|
756
|
+
thinking and the turn legitimately ends. The TUI now says so in the transcript
|
|
757
|
+
(“upstream ended this turn after thinking only … it is not really done — press Enter or send
|
|
758
|
+
another message to continue”) instead of letting 完成 read as an answer. Measured on one
|
|
759
|
+
gateway (`google-ai-pro` / `gemini-3.8-flash-high`): about **29%** of turns, with the rest of
|
|
760
|
+
the same session replying normally.
|
|
691
761
|
- **Screen reader, or you want a log** — start with `DSH_TUI_LINE_MODE=1`: plain appended
|
|
692
762
|
lines, no cursor control, safe to `tee`.
|
|
693
763
|
- **Title bar or bell does nothing** — the terminal needs OSC 0 and BEL; `DSH_TUI_NO_BELL=1`
|
|
@@ -695,6 +765,10 @@ Find your symptom; each answer is what to do, not a change log.
|
|
|
695
765
|
- **Whole-row backgrounds are too loud on a dark terminal** — `DSH_TUI_COLOR_DEPTH=none`
|
|
696
766
|
drops them; diffs still read through `+`/`-`.
|
|
697
767
|
|
|
768
|
+
- **Box drawing and dots render as garbage** — the console code page is not UTF-8. The UI
|
|
769
|
+
redraws its chrome in ASCII automatically (rules as `-`, status dots as `*`, the warning as
|
|
770
|
+
`!`) and `/diag` says so on its terminal line; `chcp 65001` or Windows Terminal restores the
|
|
771
|
+
glyphs. `DSH_TUI_ASCII=1` forces ASCII, `=0` forces Unicode. See [docs/windows.md](docs/windows.md).
|
|
698
772
|
- **Terminal compatibility** — what each terminal is allowed and promised (Windows Terminal,
|
|
699
773
|
conhost, GNOME, XFCE, Konsole, xterm, tmux, screen, the Linux console) is tabulated in
|
|
700
774
|
[docs/terminals.md](docs/terminals.md); `/diag` prints the verdict it used, and
|
package/README.md
CHANGED
|
@@ -6,13 +6,21 @@
|
|
|
6
6
|
[](https://dshfind.com/zh/plugins/cyjyyd/dsh-ssh-tui?ref=badge)
|
|
7
7
|
|
|
8
8
|
给跳板机、无桌面服务器、高延迟 SSH 用的 DeepSeek Harness 终端。纯 ANSI、增量重绘,
|
|
9
|
-
|
|
9
|
+
不需要浏览器。**SSH 掉线时,正在跑的回合留在 Host 里,重连用同一条命令接回,会话不丢。**
|
|
10
10
|
|
|
11
11
|
English: [README.en.md](README.en.md)
|
|
12
12
|
|
|
13
13
|
如果你主要在 SSH 里写代码——公司跳板、测试机、只有键盘的会话——可以从这里开始。
|
|
14
14
|
本机桌面终端若更在意主题和布局,也可以继续用你已经习惯的界面。
|
|
15
15
|
|
|
16
|
+
和现成的东西不重叠:
|
|
17
|
+
|
|
18
|
+
- **官方 headless**:同一条任务只把最后一条回复打到 stdout,过程全在日志里。
|
|
19
|
+
- **官方 `dsh-ssh`(0.1.6 起)**:本机跑 Harness、远端跑文件和进程,要预装 helper。人已经 SSH 在那台机器上时用本插件;两者可以叠用,不是替代。
|
|
20
|
+
- **其它终端皮肤**(`dsh-TUI` 等):本机漂亮终端,比主题和布局。本插件比的是弱网下的增量重绘、掉线后 Host 留下、纯文本行模式。
|
|
21
|
+
|
|
22
|
+
掉线之后怎么接回来,见下面的[「SSH 断了之后」](#ssh-断了之后)。
|
|
23
|
+
|
|
16
24
|
已经在付 SuperGrok / X Premium 的话,用独立插件 [dsh-llm-xai-oauth](https://github.com/cyjyyd/dsh-llm-xai-oauth) 把订阅接进 dsh(headless / web / 本 TUI 都能用),复用本机 grok-bridge token,不需要 xAI API Key。
|
|
17
25
|
|
|
18
26
|
本插件已被 [dshfind 插件目录](https://dshfind.com/zh/plugins/cyjyyd/dsh-ssh-tui) 收录:
|
|
@@ -28,6 +36,11 @@ dsh --profile tui
|
|
|
28
36
|
|
|
29
37
|
当前 `dsh` 必须带 `--profile`(`dsh plugin add …` 会报缺选项)。装进别的 profile 把 `tui` 换成那个名字即可。
|
|
30
38
|
|
|
39
|
+
> **宿主已升到 0.2.0-rc 的用户请看这里**:0.8.0 支持 `0.2.0-rc` 线(旧版会因声明窗口不符被 launcher 拒绝),
|
|
40
|
+
> 但它目前只挂在 `next` 上——`latest` 仍是 0.7.4,2026-10-01 起才切到 0.8.0。这段时间请用
|
|
41
|
+
> `dsh plugin --profile tui add dsh-ssh-tui@next` 安装;还在 `0.1.7-rc` 线的话 `@latest`(0.7.4) 就够用,
|
|
42
|
+
> 等 0.8.0 上 `latest` 再升也不迟。**0.1.5 及更早的宿主从 0.8.0 起不再支持**。
|
|
43
|
+
|
|
31
44
|
**更新必须带 `@latest`。** `dsh plugin` 只是把后面的参数转给 profile 目录里的 pnpm。写成 `add dsh-ssh-tui`(没有版本)时,pnpm 会沿用 `pnpm-lock.yaml` 里已经钉死的版本(常见就是一直停在 0.3.7)。也不要把 `--profile` 写到 `add` 后面:`dsh plugin add --profile tui add dsh-ssh-tui` 不是合法用法。卸载:`dsh plugin --profile tui remove dsh-ssh-tui`。
|
|
32
45
|
|
|
33
46
|
## 官方 headless 和这个 TUI
|
|
@@ -88,7 +101,11 @@ dsh --profile tui
|
|
|
88
101
|
标题(还没出现就保持「处理中」),运行中的工具摘要在 `└` 下自动折行(最多 3 行,末行
|
|
89
102
|
加省略号),带计时和 Esc 中断;回复开始流式输出时自动让位。
|
|
90
103
|
|
|
91
|
-
- 0.7
|
|
104
|
+
- 0.7 起:模型回复可**拖选自由复制**(按住鼠标拖过一段,走 OSC 52 写回本机剪贴板;按住 Shift 拖选
|
|
105
|
+
结果相同;工具卡仍是点击展开)。回复也是**可选中卡片**:空输入 `↑` 落到最新的一条回复或卡片(`▶` 标记,
|
|
106
|
+
走屏幕顺序;`Alt+4` 直接选中最新回复),
|
|
107
|
+
`/copy` 复制的是选中的那一条(原文,不是折行后的屏幕文本),`Enter` 打开全文;
|
|
108
|
+
SSH 会话里复制落到本机终端,不再误报「本终端不接收 OSC 52」;
|
|
92
109
|
底栏收敛成一条带优先级的芯片带(先丢文字后丢组,`⚠` 可点击打开 `/doctor`);**额度条常驻**并标注窗口
|
|
93
110
|
(`5Hr`/`1Wk`/`1Mo`,默认显示最小窗口,未取到时显示 `?%` 并每 15 秒重试);`/mode` 分组显示并可用 `/` 过滤;
|
|
94
111
|
极简视图逐文件列 `+/-`;工具 diff 为**行级**、只高亮变化字符、≥100 列时并排显示;
|
|
@@ -98,10 +115,10 @@ dsh --profile tui
|
|
|
98
115
|
## 环境要求
|
|
99
116
|
|
|
100
117
|
- Node.js ≥ 22.19
|
|
101
|
-
- DeepSeek Harness CLI:`npm i -g @deepseek-ai/dsh
|
|
118
|
+
- DeepSeek Harness CLI:`npm i -g @deepseek-ai/dsh`(本仓库默认开发线是 `0.2.0-rc.1`,CI 覆盖 `0.1.7-rc.1` / `0.1.7-rc.2` / `0.2.0-rc.1` 三条 dsh 线加一条 Windows 腿:`0.1.7-rc.1` 跑 typecheck 与单元套件,另两条连真 PTY 探针一起跑;非默认腿由 `scripts/ci-pin-line.mjs` 改写 manifest 后从零安装。**`0.1.5` 及更早的线自 0.8.0 起不再支持**(`dshReleases` 里保留 `incompatible` 的明确表态,装不上请升到 `0.1.7-rc` 或 `0.2.0-rc`;`0.1.5` 那条线需要的是 `<0.1.6` 的旧代 API)。`0.1.3-alpha.1` 只在 GitHub 有 tag、npm 未发布,无法本地装包验证)
|
|
102
119
|
- pnpm(`dsh plugin` 通过 pnpm 管理 profile 依赖)
|
|
103
120
|
- 支持 ANSI 的终端(推荐 SSH 直连;Windows 用 PowerShell / Windows Terminal)
|
|
104
|
-
- Windows
|
|
121
|
+
- Windows:安装、排障与 `/doctor` 的读法见 [docs/windows.md](docs/windows.md)。Host 与显示端之间的本地通道使用命名管道
|
|
105
122
|
`\\.\pipe\dsh-tui-<DSH_HOME 摘要 8 位>-<会话名>-<会话摘要 8 位>`(Windows 只能监听命名管道,
|
|
106
123
|
不能监听 `.sock` 文件;名字里同时带 DSH_HOME 与会话 id 的摘要,所以不同 home、不同会话都不会撞名,
|
|
107
124
|
结束进程即自动回收)。Host 的 stderr 记录在 `%USERPROFILE%\.dsh\tui-socks\<会话名>-<摘要>.err`,
|
|
@@ -150,6 +167,17 @@ dsh --profile tui --resume # 选择器(活进程优先接入
|
|
|
150
167
|
dsh --profile tui --resume <session-id> # 有活进程则接入,否则从日志恢复
|
|
151
168
|
```
|
|
152
169
|
|
|
170
|
+
选择器里每个活着的会话只标两个词:**可接入**(一键接入)或**已占用**(别的窗口在用)。
|
|
171
|
+
后面跟的是 Host 的 pid。被标成「已占用」时 `--resume <session-id>` 会被拒绝而不是把对方踢掉——
|
|
172
|
+
要接管就在**选择器里**选中它,再按 `y` / Enter 确认(那个窗口随即退出)。
|
|
173
|
+
|
|
174
|
+
**断线残留不会挡住你**:SSH 被切断时服务端常常还不知道(sshd 要等 TCP keepalive 才发现,可能几小时),
|
|
175
|
+
那个窗口的 launcher 仍然连着显示通道,锁里写的还是 `attached`。所以 Host 会反过来向**终端本身**要答案
|
|
176
|
+
(经 relay 做一次光标往返,见 `scripts/tui-cut-probe.mjs`):终端答不上来就说明那个窗口已经没了,
|
|
177
|
+
选择器直接标「可接入」,一键接入;`--resume <session-id>` 也直接接入。
|
|
178
|
+
只有终端确认还活着时才需要上面的接管确认。这个判断在**首帧之前**完成,所以列表不会先显示「已占用」
|
|
179
|
+
再改口。
|
|
180
|
+
|
|
153
181
|
同一 `sessionId` 不能同时开第二份 Host(会抢 jsonl 和审批)。锁在
|
|
154
182
|
`$DSH_HOME/tui-locks/`,显示通道在 `$DSH_HOME/tui-socks/`。进程死后残留锁会在
|
|
155
183
|
下次启动时核对 pid,已死则自动从日志接管。调试可设 `DSH_TUI_NO_SESSION_LOCK=1`。
|
|
@@ -163,6 +191,11 @@ dsh --profile tui --resume <session-id> # 有活进程则接入,否则从
|
|
|
163
191
|
倍以上的(那是别人请求的回复,相对判定所以 `ssh localhost` 的 2ms 链路照样算得出来)。
|
|
164
192
|
代价是每次接入多约 0.4–0.6 秒探测时间,换来的是 50ms 链路不再出现 2ms / 1900ms 的跳变。
|
|
165
193
|
|
|
194
|
+
**链路会一直重测,不是只测一次**:接入 8 秒后补测一次,之后每 20 秒一次(变化超过 50ms 时
|
|
195
|
+
5 秒后再确认一次),footer 芯片与绘制档位取**最近三次的中位数**——单次抖动(或接入那一刻正好
|
|
196
|
+
在抖)不会把芯片和绘制预算钉在最慢一档,真正的变化两次就能定下来。终端完全不答 DSR 时退避到
|
|
197
|
+
10 分钟一次。见 `scripts/tui-rtt-probe.mjs`(CI 的 0.1.7 腿)。
|
|
198
|
+
|
|
166
199
|
这些回复也不可能再进输入框:relay 整条 stdin 管道常驻过滤(含跨 read 拆分的),Host 键
|
|
167
200
|
处理前再过滤一次;连 Host 启动那几百毫秒里敲的键也会被暂存、接入后补发,不再被丢掉。
|
|
168
201
|
`DSH_TUI_DEBUG=1` 时会打印每次采样与丢弃原因。
|
|
@@ -182,22 +215,25 @@ Host 在后台跑完这一轮;审批和提问等接上后再弹。空闲断线
|
|
|
182
215
|
完全没有显示器且一直空闲的兜底仍由 `DSH_TUI_DETACHED_IDLE_MS`(默认 6 小时)负责。可选:用 tmux 包一层。
|
|
183
216
|
常驻与接管的可复制配方(tmux / screen / systemd --user / 长任务)见 [`docs/remote-ops.md`](docs/remote-ops.md);重连后转录里的「已重连 N 次 · 断开 Xs」与「离开 …」两行的语义也在那里。
|
|
184
217
|
|
|
185
|
-
启动时若 npm 上有更新,会弹出选单(类似 Codex / Claude Code 首启):**现在更新 / 稍后 /
|
|
218
|
+
启动时若 npm 上有更新,会弹出选单(类似 Codex / Claude Code 首启):**现在更新 / 稍后 / 跳过此版本**。选「现在更新」安装的是刚才查到的那个版本号(`dsh plugin --profile tui add dsh-ssh-tui@<版本>`),不写 `@latest`:pnpm 对 `@latest` 会再解析一次,刚发布、还在 `minimumReleaseAge` 窗口里的版本会被静默跳过、装成旧的还显示成功。完成后提示退出再启动。`DSH_TUI_NO_UPDATE_CHECK=1` 可关掉。`/status` 里也能看到当前插件版本、链路芯片、额度窗口,以及子代理模型是否与父路由同族。
|
|
186
219
|
|
|
187
|
-
仓库内也可:`bash scripts/smoke-headless.sh
|
|
220
|
+
仓库内也可:`node scripts/smoke-headless.mjs`(`bash scripts/smoke-headless.sh` 等价;记录出口摘要,不打印 token)。
|
|
188
221
|
|
|
189
222
|
### 方式一:从 git clone 安装
|
|
190
223
|
|
|
191
224
|
```bash
|
|
192
225
|
git clone https://github.com/cyjyyd/dsh-ssh-tui.git
|
|
193
226
|
cd dsh-ssh-tui
|
|
194
|
-
|
|
227
|
+
node scripts/install.mjs # 默认安装到 tui profile(bash scripts/install.sh 等价)
|
|
195
228
|
```
|
|
196
229
|
|
|
230
|
+
Windows 没有 bash,用同一条 `node scripts/install.mjs`;完整的 Windows 步骤、
|
|
231
|
+
「装不上先看什么」和 `/doctor` 的读法见 [docs/windows.md](docs/windows.md)。
|
|
232
|
+
|
|
197
233
|
安装到其它 profile(例如自定义 `work` profile):
|
|
198
234
|
|
|
199
235
|
```bash
|
|
200
|
-
|
|
236
|
+
node scripts/install.mjs work
|
|
201
237
|
```
|
|
202
238
|
|
|
203
239
|
脚本会依次:安装依赖 → 构建 `lib/` → 通过 `dsh plugin --profile <name> add link:<repo>`
|
|
@@ -216,7 +252,8 @@ bash scripts/install.sh work
|
|
|
216
252
|
|
|
217
253
|
1. **运行中的应用内修复**:`/mode fix` 写入下面这段并提示重启。npm 安装和
|
|
218
254
|
「现在更新」走的是 `dsh plugin add`,不会执行仓库脚本,所以这是最通用的一条。
|
|
219
|
-
2. 仓库安装:`
|
|
255
|
+
2. 仓库安装:`node scripts/profile-rows.mjs [profile]`(默认 `tui`;
|
|
256
|
+
`bash scripts/ensure-profile-rows.sh` 是它的薄封装,两者等价)。
|
|
220
257
|
3. 手动在该 profile 的 `$DSH_HOME/profiles/<profile>/cordis.patch.yml` 里加入:
|
|
221
258
|
|
|
222
259
|
```yaml
|
|
@@ -234,7 +271,7 @@ profile(例如同时装了 `@deepseek-ai/dsh-web-app` 的 profile)。改完
|
|
|
234
271
|
会以 `service "agentPresets" has been registered` 失败),先把 profile 补丁里的这段删掉。
|
|
235
272
|
|
|
236
273
|
名单缺席时,TUI 启动会打一行提示(中文界面:「未挂载 agent-presets 名单…」),
|
|
237
|
-
`/mode` 会打印补丁路径和 `/mode fix` 修复入口,`scripts/verify.sh`
|
|
274
|
+
`/mode` 会打印补丁路径和 `/mode fix` 修复入口,`node scripts/verify.mjs`(`scripts/verify.sh` 等价)也会给出提示。
|
|
238
275
|
另外,preset 的 scope 身份按模块实例判定:一个 dsh 安装树里若存在两份
|
|
239
276
|
`@deepseek-ai/dsh-scope`(npm 嵌套安装的 checkout 可能如此),名单挂载会以
|
|
240
277
|
`refusing to compose an unscoped context` 失败;全局安装(`npm i -g`)不受影响。
|
|
@@ -248,7 +285,15 @@ npm run build
|
|
|
248
285
|
dsh plugin --profile tui add "link:$(pwd)"
|
|
249
286
|
```
|
|
250
287
|
|
|
251
|
-
Windows(PowerShell
|
|
288
|
+
Windows(PowerShell)不用 bash,直接跑 Node 脚本(`scripts/*.sh` 只是转去调用它们的薄封装):
|
|
289
|
+
|
|
290
|
+
```powershell
|
|
291
|
+
cd dsh-ssh-tui
|
|
292
|
+
node scripts/install.mjs # 装依赖、构建、链接进 tui profile、挂上 /mode 需要的行
|
|
293
|
+
node scripts/verify.mjs # 检查组合是否生效
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
不想用脚本时,三条命令等价:
|
|
252
297
|
|
|
253
298
|
```powershell
|
|
254
299
|
cd dsh-ssh-tui
|
|
@@ -261,8 +306,8 @@ dsh plugin --profile tui add "link:$((Get-Location).Path)"
|
|
|
261
306
|
|
|
262
307
|
```bash
|
|
263
308
|
dsh plugin --profile work add dsh-ssh-tui
|
|
264
|
-
#
|
|
265
|
-
|
|
309
|
+
# 或仓库脚本(bash scripts/install-npm.sh 等价)
|
|
310
|
+
node scripts/install-npm.mjs work
|
|
266
311
|
```
|
|
267
312
|
|
|
268
313
|
### 智能路由模式(dsh-routing-suite)
|
|
@@ -270,8 +315,8 @@ bash scripts/install-npm.sh work
|
|
|
270
315
|
需要“智能路由模式”时,安装 `dsh-routing-suite` 并注册其 preset:
|
|
271
316
|
|
|
272
317
|
```bash
|
|
273
|
-
|
|
274
|
-
|
|
318
|
+
node scripts/install-routing-suite.mjs # 默认 tui profile
|
|
319
|
+
node scripts/install-routing-suite.mjs work # 其它 profile(bash scripts/install-routing-suite.sh 等价)
|
|
275
320
|
```
|
|
276
321
|
|
|
277
322
|
脚本会执行 `dsh plugin --profile <name> add dsh-routing-suite`,并把包内的
|
|
@@ -300,16 +345,17 @@ dsh --profile tui --no-color
|
|
|
300
345
|
|
|
301
346
|
| 键 | 作用 |
|
|
302
347
|
| --- | --- |
|
|
303
|
-
| `Enter` |
|
|
348
|
+
| `Enter` | 发送;运行中则插入指示;空输入且已选中卡片时展开/收起,选中的是回复则打开全文(`Esc` 返回)。工具正文超出窗口也单独全览 |
|
|
304
349
|
| `1..9` / `Enter` | 回答 `ask_user_question` 提问:`1..9` 直接选,`Enter` 取当前高亮项(默认第一项),`Esc` 才取消 |
|
|
305
|
-
| `↑` / `↓` |
|
|
306
|
-
| `Ctrl+R` |
|
|
350
|
+
| `↑` / `↓` | 空输入且会话里已有卡片时:在当前屏幕顺序的最新一条(**回复或卡片**)开始往上走,标记 `▶` 只出现在选中的那一条;没有卡片时(纯问答、或刚 `/clear`)仍是有输入时的历史召回——那种会话用 `Alt+4` 或 `Ctrl+N`/`Ctrl+P` 选回复。有输入:历史(↓ 越过最新一条会回到当前草稿) |
|
|
351
|
+
| `Ctrl+R` | 展开最新一条卡片;已选中时全部展开或全部收起(选中的回复不会被抢走焦点,打开覆盖层时该键交给覆盖层) |
|
|
307
352
|
| `Ctrl+T` | 折叠输入框(只影响显示) |
|
|
308
|
-
| `Alt+1` / `2` / `3` / `4` | 跳到最新思考 / 计划 / 子代理 /
|
|
309
|
-
| `/find [类] 关键字` |
|
|
353
|
+
| `Alt+1` / `2` / `3` / `4` | 跳到最新思考 / 计划 / 子代理 / 回复(回复会被选中,可直接 `/copy`) |
|
|
354
|
+
| `/find [类] 关键字` | 搜索并跳到该条完整消息(反色高亮),命中的那条同时成为选中项。类:`思考` `计划` `子代理` `回复` `提示词`。`Ctrl+/` 或 `Alt+/` 打开 |
|
|
310
355
|
| `Ctrl+G` / `Alt+N` | 下一条搜索结果;`Alt+P` 上一条 |
|
|
311
|
-
| `/copy` |
|
|
312
|
-
|
|
|
356
|
+
| `/copy` | 把选中的卡片或回复按**原文**写入本机剪贴板(无选中则最近一条回复;支持 OSC 52 的终端/tmux)。复制后保留选中,连按两次拿到的是同一条。在「全文」覆盖层里按复制键(`Ctrl+Shift+C`)复制的是**屏幕上那份正文**——工具卡是工具全文、改动卡是那份 diff、回复是原文;覆盖层底部会回显「已复制 …(全文)」 |
|
|
357
|
+
| `/retryauth [on\|off]` | "提供商侧鉴权失败"(HTTP 401/403,且本机凭据已配)时要不要自动重试一次;默认关。判断口诀与排查三步见 [`docs/remote-ops.md`](docs/remote-ops.md) 4.8 |
|
|
358
|
+
| 鼠标左键 | 点击卡片标题展开/收起;点 markdown 链接则复制 URL;**拖过回复**按屏幕所见复制(不含选中标记 `▶`) |
|
|
313
359
|
| `PgUp` / `PgDn`、滚轮 | 转录回看 |
|
|
314
360
|
| `Esc` | 取消选择 → 回底部 → 取消当前轮次 |
|
|
315
361
|
| `Ctrl+C` | 中断当前轮次;空闲连按两次退出 |
|
|
@@ -471,7 +517,7 @@ DeepSeek 上、B 会话跑在 xAI 上;只记软件级默认值的话,resume
|
|
|
471
517
|
## 验证
|
|
472
518
|
|
|
473
519
|
```bash
|
|
474
|
-
|
|
520
|
+
node scripts/verify.mjs # 检查 profile 组合与 CLI 语法(bash scripts/verify.sh 等价)
|
|
475
521
|
npm test # 单元 + 集成(含屏幕网格护栏、重连接管、选择器首帧)
|
|
476
522
|
python3 scripts/pty-acceptance.py # 真 PTY:模拟 40ms SSH 链路 + 滞留的光标回复
|
|
477
523
|
node scripts/tui-probe.mjs # 真 PTY:真 dsh --profile tui 走一遍启动/缩放//diag/打字//exit
|
|
@@ -509,8 +555,8 @@ PROBE_HOME=$H node scripts/tui-probe.mjs --session <id> # 只读式驱动已
|
|
|
509
555
|
## 卸载
|
|
510
556
|
|
|
511
557
|
```bash
|
|
512
|
-
|
|
513
|
-
|
|
558
|
+
node scripts/uninstall.mjs # 默认 tui profile(bash scripts/uninstall.sh 等价)
|
|
559
|
+
node scripts/uninstall.mjs work # 指定 profile
|
|
514
560
|
```
|
|
515
561
|
|
|
516
562
|
卸载只移除 profile 中的插件依赖与 bundle 层,不会删除会话数据。
|
|
@@ -568,10 +614,12 @@ npm run build
|
|
|
568
614
|
### 启动与安装
|
|
569
615
|
|
|
570
616
|
- **`dsh-ssh-tui: both stdin and stdout must be TTYs`**:必须在真实终端 / SSH 会话里启动;管道、CI、`&` 后台都不行。
|
|
617
|
+
- **Windows 安装、脚本与 `/doctor` 的读法**:[docs/windows.md](docs/windows.md) 有 30 秒安装、
|
|
618
|
+
「装不上先看什么」的对照表,以及 `/doctor` 报告里 `●` / `⚠` / `✖` 各代表什么。
|
|
571
619
|
- **Windows 报 `host display socket did not appear`**:升级到最新版:
|
|
572
620
|
`dsh plugin --profile tui add dsh-ssh-tui@latest`。仍失败请附 `/diag` 输出提 issue。
|
|
573
621
|
- **Windows 上应用内更新报 `spawn dsh ENOENT`**:旧的更新器直接 `spawn dsh`,而 Windows 上装的是 `dsh.cmd` 垫片;
|
|
574
|
-
|
|
622
|
+
在命令行跑一次 `dsh plugin --profile tui add dsh-ssh-tui@latest`,之后应用内更新正常(它装的是查到的版本号,不再写 `@latest`)。
|
|
575
623
|
- **pnpm 拒绝 git 依赖的构建脚本**:把 pnpm 打印的 key 加进 profile 的 `pnpm-workspace.yaml` 的 `allowBuilds`,再重装。
|
|
576
624
|
- **升级后 `/mode` 报「服务不可用」、preset 工具消失**:敲 `/doctor`。它逐项判定部署组合(补丁能否解析、
|
|
577
625
|
名单与 code-runtime 是否组合、有没有行被挂载两次、dsh 版本是否在兼容表内、是否装着两份 `@deepseek-ai/dsh-scope`),
|
|
@@ -597,11 +645,19 @@ npm run build
|
|
|
597
645
|
- **中文 / emoji 挤压相邻字符**:换一款覆盖这些字形的等宽字体(如 Noto Sans Mono CJK)。程序按 2 格预算这些符号
|
|
598
646
|
并请求文本字形;字体缺字时终端会回退到彩色 emoji 字形,视觉上仍可能偏宽。
|
|
599
647
|
- **弱网下画面跟不上**:`DSH_TUI_PAINT_MS` 控制发画间隔(40–1000 ms,越小越快也越费流量);
|
|
600
|
-
|
|
648
|
+
不设时按测得的 RTT 自动取 80 / 160 / 250 / 400 ms;链路每 20 秒重测(刚变化过就 5 秒后再测一次),
|
|
649
|
+
取最近三次的中位数,所以接入那一刻的抖动不会把绘制档位钉在最慢一档。
|
|
650
|
+
- **模型“只思考一下就说完成”**:这是**上游返回了空回合**——有些网关把 Gemini/Claude 的 thought 部分映射成
|
|
651
|
+
`reasoning_content`,然后以 `finish_reason: stop` 收尾却没有任何正文,harness 如实组装成“只含思考的助手消息”,
|
|
652
|
+
回合就合法结束了。TUI 现在会显式写一行「上游只返回了思考…这不是真正的完成(finish_reason: stop);按 Enter 或再输入一句即可继续」,
|
|
653
|
+
不再让你以为它答完了。实测某网关(`google-ai-pro` / `gemini-3.8-flash-high`)约 **29%** 的回合如此(同会话其它回合正常)。
|
|
601
654
|
- **要给屏幕阅读器或日志用**:`DSH_TUI_LINE_MODE=1` 启动纯行模式——只追加纯文本行、不发光标控制,可直接 `tee` 存档。
|
|
602
655
|
- **标题栏 / 铃声不生效**:终端需支持 OSC 0 与 BEL;`DSH_TUI_NO_BELL=1` 可关闭铃声。
|
|
603
656
|
- **深色终端下整行底色太抢眼**:`DSH_TUI_COLOR_DEPTH=none` 去掉底色,diff 仍用 `+`/`-` 区分。
|
|
604
657
|
|
|
658
|
+
- **框线、圆点显示成乱码**:控制台代码页不是 UTF-8。界面会自动改画 ASCII(横线 `-`、状态点 `*`、
|
|
659
|
+
警告 `!`),`/diag` 的「终端」一行会注明;想要原字形就 `chcp 65001` 或改用 Windows Terminal。
|
|
660
|
+
`DSH_TUI_ASCII=1` 强制 ASCII,`=0` 强制 Unicode。详见 [docs/windows.md](docs/windows.md)。
|
|
605
661
|
- **终端兼容性**:每个终端允许发什么、承诺什么(Windows Terminal / conhost / GNOME / XFCE / Konsole /
|
|
606
662
|
xterm / tmux / screen / Linux 控制台)见 [docs/terminals.md](docs/terminals.md);
|
|
607
663
|
判定依据写在 `/diag` 的「终端」一行,判定错了用 `DSH_TUI_TERM_CAPS` 覆盖。
|