dsh-ssh-tui 0.8.0 → 0.8.2-rc.1
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/CHANGELOG.md +150 -0
- package/README.en.md +74 -8
- package/README.md +451 -577
- package/docs/display-mode.md +122 -0
- package/docs/release-notes-0.7.4.md +91 -0
- package/docs/release-notes-0.8.0.md +56 -0
- package/docs/release-notes-0.8.1.md +79 -0
- package/docs/release-notes-0.8.2-rc.1.md +159 -0
- package/docs/remote-ops.md +51 -0
- package/docs/terminals.md +53 -0
- package/docs/windows.md +13 -0
- package/lib/approval-state.js +148 -0
- package/lib/approval-state.js.map +1 -0
- package/lib/attach.js +4 -4
- package/lib/attach.js.map +1 -1
- package/lib/auth-failure.js +74 -0
- package/lib/auth-failure.js.map +1 -1
- package/lib/color-depth.js +26 -0
- package/lib/color-depth.js.map +1 -1
- package/lib/commands.js +2 -0
- package/lib/commands.js.map +1 -1
- package/lib/copy-text.js +30 -8
- package/lib/copy-text.js.map +1 -1
- package/lib/dialogs.js +124 -0
- package/lib/dialogs.js.map +1 -1
- package/lib/display-mode.js +147 -0
- package/lib/display-mode.js.map +1 -0
- package/lib/display-sock.js +490 -35
- package/lib/display-sock.js.map +1 -1
- package/lib/footer-accents.js +28 -0
- package/lib/footer-accents.js.map +1 -0
- package/lib/footer-budget.js +328 -0
- package/lib/footer-budget.js.map +1 -0
- package/lib/footer-format.js +433 -0
- package/lib/footer-format.js.map +1 -0
- package/lib/footer-layout.js +407 -0
- package/lib/footer-layout.js.map +1 -0
- package/lib/footer-meters.js +185 -0
- package/lib/footer-meters.js.map +1 -0
- package/lib/footer.js +19 -561
- package/lib/footer.js.map +1 -1
- package/lib/glyph-measure.js +92 -0
- package/lib/glyph-measure.js.map +1 -0
- package/lib/i18n/en.js +83 -7
- package/lib/i18n/en.js.map +1 -1
- package/lib/i18n/zh.js +85 -7
- package/lib/i18n/zh.js.map +1 -1
- package/lib/index.js +73 -5
- package/lib/index.js.map +1 -1
- package/lib/paint.js +75 -17
- package/lib/paint.js.map +1 -1
- package/lib/picker.js +14 -13
- package/lib/picker.js.map +1 -1
- package/lib/plan-projection.js +291 -0
- package/lib/plan-projection.js.map +1 -0
- package/lib/plan.js +61 -11
- package/lib/plan.js.map +1 -1
- package/lib/platform.js +96 -0
- package/lib/platform.js.map +1 -1
- package/lib/question-state.js +83 -0
- package/lib/question-state.js.map +1 -0
- package/lib/representation.js +283 -0
- package/lib/representation.js.map +1 -0
- package/lib/screen.js +105 -0
- package/lib/screen.js.map +1 -0
- package/lib/selection.js +5 -3
- package/lib/selection.js.map +1 -1
- package/lib/session-blank.js +81 -0
- package/lib/session-blank.js.map +1 -0
- package/lib/session-list.js +102 -81
- package/lib/session-list.js.map +1 -1
- package/lib/startup.js +56 -0
- package/lib/startup.js.map +1 -1
- package/lib/stats.js +101 -3
- package/lib/stats.js.map +1 -1
- package/lib/subagent-model.js +8 -7
- package/lib/subagent-model.js.map +1 -1
- package/lib/term-text.js +436 -69
- package/lib/term-text.js.map +1 -1
- package/lib/terminal-input.js +132 -10
- package/lib/terminal-input.js.map +1 -1
- package/lib/theme.js +335 -0
- package/lib/theme.js.map +1 -0
- package/lib/throughput.js +305 -0
- package/lib/throughput.js.map +1 -0
- package/lib/tool-present.js +67 -15
- package/lib/tool-present.js.map +1 -1
- package/lib/tui.js +4186 -1133
- package/lib/tui.js.map +1 -1
- package/lib/types/approval-state.d.ts +75 -0
- package/lib/types/attach.d.ts +6 -2
- package/lib/types/auth-failure.d.ts +55 -0
- package/lib/types/color-depth.d.ts +21 -0
- package/lib/types/commands.d.ts +6 -0
- package/lib/types/copy-text.d.ts +18 -1
- package/lib/types/dialogs.d.ts +147 -1
- package/lib/types/display-mode.d.ts +99 -0
- package/lib/types/display-sock.d.ts +90 -0
- package/lib/types/footer-accents.d.ts +22 -0
- package/lib/types/footer-budget.d.ts +204 -0
- package/lib/types/footer-format.d.ts +221 -0
- package/lib/types/footer-layout.d.ts +292 -0
- package/lib/types/footer-meters.d.ts +151 -0
- package/lib/types/footer.d.ts +19 -269
- package/lib/types/glyph-measure.d.ts +41 -0
- package/lib/types/index.d.ts +13 -0
- package/lib/types/paint.d.ts +48 -0
- package/lib/types/plan-projection.d.ts +162 -0
- package/lib/types/plan.d.ts +18 -2
- package/lib/types/platform.d.ts +83 -0
- package/lib/types/question-state.d.ts +96 -0
- package/lib/types/representation.d.ts +498 -0
- package/lib/types/screen.d.ts +126 -0
- package/lib/types/session-blank.d.ts +51 -0
- package/lib/types/session-list.d.ts +34 -0
- package/lib/types/startup.d.ts +30 -0
- package/lib/types/stats.d.ts +64 -1
- package/lib/types/subagent-model.d.ts +7 -6
- package/lib/types/term-text.d.ts +100 -24
- package/lib/types/terminal-input.d.ts +37 -0
- package/lib/types/theme.d.ts +109 -0
- package/lib/types/throughput.d.ts +163 -0
- package/lib/types/tool-present.d.ts +43 -2
- package/lib/types/transcript-types.d.ts +63 -2
- package/lib/types/tui.d.ts +960 -12
- package/package.json +73 -67
package/README.md
CHANGED
|
@@ -5,701 +5,575 @@
|
|
|
5
5
|
[](https://github.com/cyjyyd/dsh-ssh-tui/actions/workflows/ci.yml)
|
|
6
6
|
[](https://dshfind.com/zh/plugins/cyjyyd/dsh-ssh-tui?ref=badge)
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
不需要浏览器。**SSH 掉线时,正在跑的回合留在 Host 里,重连用同一条命令接回,会话不丢。**
|
|
8
|
+
**A resilient terminal frontend for DeepSeek Harness.**
|
|
10
9
|
|
|
11
|
-
|
|
10
|
+
纯 ANSI · 增量重绘 · SSH 断线重接 · Windows / ConPTY · Host-aware activation · 无需浏览器
|
|
12
11
|
|
|
13
|
-
|
|
14
|
-
本机桌面终端若更在意主题和布局,也可以继续用你已经习惯的界面。
|
|
12
|
+
**连接可以断,终端可以换,Harness 可以升级;正在工作的会话不应该因此变得脆弱。**
|
|
15
13
|
|
|
16
|
-
|
|
14
|
+
English: [README.en.md](README.en.md)
|
|
17
15
|
|
|
18
|
-
|
|
19
|
-
- **官方 `dsh-ssh`(0.1.6 起)**:本机跑 Harness、远端跑文件和进程,要预装 helper。人已经 SSH 在那台机器上时用本插件;两者可以叠用,不是替代。
|
|
20
|
-
- **其它终端皮肤**(`dsh-TUI` 等):本机漂亮终端,比主题和布局。本插件比的是弱网下的增量重绘、掉线后 Host 留下、纯文本行模式。
|
|
16
|
+
---
|
|
21
17
|
|
|
22
|
-
|
|
18
|
+
## 30 秒开始
|
|
23
19
|
|
|
24
|
-
|
|
20
|
+
需要 Node.js ≥ 22.19 和 DeepSeek Harness CLI。
|
|
25
21
|
|
|
26
|
-
|
|
22
|
+
```bash
|
|
23
|
+
npm i -g @deepseek-ai/dsh
|
|
24
|
+
dsh plugin --profile tui add dsh-ssh-tui@latest
|
|
25
|
+
dsh --profile tui
|
|
26
|
+
```
|
|
27
27
|
|
|
28
|
-
|
|
28
|
+
恢复旧会话:
|
|
29
29
|
|
|
30
|
-
|
|
30
|
+
```bash
|
|
31
|
+
dsh --profile tui --resume
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
更新:
|
|
31
35
|
|
|
32
36
|
```bash
|
|
33
37
|
dsh plugin --profile tui add dsh-ssh-tui@latest
|
|
34
|
-
dsh --profile tui
|
|
35
38
|
```
|
|
36
39
|
|
|
37
|
-
|
|
40
|
+
> `dsh plugin` 由 profile 内的 pnpm 管理依赖。更新时请显式带 `@latest`,否则已有 lockfile 可能继续沿用旧版本。
|
|
38
41
|
|
|
39
|
-
|
|
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 起不再支持**。
|
|
42
|
+
Windows 用户见 [Windows 指南](docs/windows.md)。
|
|
43
43
|
|
|
44
|
-
|
|
44
|
+
---
|
|
45
45
|
|
|
46
|
-
##
|
|
46
|
+
## 为什么会有这个 TUI
|
|
47
47
|
|
|
48
|
-
|
|
48
|
+
DeepSeek Harness 已经有 Web、headless 和不断扩展的插件生态。
|
|
49
49
|
|
|
50
|
-
|
|
50
|
+
`dsh-ssh-tui` 不试图把浏览器搬进终端。
|
|
51
51
|
|
|
52
|
-
|
|
52
|
+
它解决另一类问题:
|
|
53
53
|
|
|
54
|
-
|
|
55
|
-
下:思考默认折叠、`edit` 整行红/绿 diff、两个子代理各自一张卡、计划条钉在输入框上方。
|
|
56
|
-
|
|
57
|
-
单独看:[headless stdout](docs/screenshots/headless.png) · [dsh-ssh-tui](docs/screenshots/workspace.png)
|
|
58
|
-
|
|
59
|
-
## 弱网 SSH 上过程还在
|
|
60
|
-
|
|
61
|
-
同一条任务,按 **2 kB/s** 限速回放真实增量绘制(88×30,一帧一次 `stdout.write`)。官方 headless 这条链路上只会在全部结束后突然打出最终 Markdown;这里思考、`edit` diff、子代理卡和计划条是随着字节到达逐步出现的。
|
|
62
|
-
|
|
63
|
-

|
|
64
|
-
|
|
65
|
-
协议(可复现,不靠模型估):`npm run screenshots:slow` → `docs/screenshots/slow-link.json`。这次回放 14 次绘制、约 **18.0 KB**,在 2 kB/s 上大约 **8.8 s** 画完。数字是这条固定事件序的 stdout 字节账。
|
|
66
|
-
|
|
67
|
-
## 功能一览
|
|
68
|
-
|
|
69
|
-
- 纯终端渲染,无需浏览器/鼠标/重量级终端框架,适合慢速或远程 SSH;
|
|
70
|
-
- 模型思考流默认折叠,显示 `▸ 思考中 ⠹ · N 字 · Ns` 动画;结束后折叠为
|
|
71
|
-
`▸ 已思考 · N 行`,可单独展开;思考过程中也能实时展开/收起查看原文;
|
|
72
|
-
- 工作区支持 markdown 渲染:多级标题(H1 放大/下划线、H2 下划线、H3 着色)、
|
|
73
|
-
粗体、斜体、行内代码、代码块、列表、引用与链接;模型最终回复以普通白色显示,行内 `**粗体**` 用更亮的粗体区分;
|
|
74
|
-
- 系统提示词 / `system-reminder` / `AGENTS.md` 等注入折叠为「提示词注入:系统预设 AGENTS.MD」卡片,默认收起,Enter 展开看全文;
|
|
75
|
-
- 工具调用卡片化:标题默认色,状态球绿/黄/红表示成功/运行中/失败(成功不再跟 `[ok]` 重复;失败仍标 `[error]`);
|
|
76
|
-
连续读/编辑同一路径会叠成一张卡(`×N` + 累计字数/行数,编辑 diff 跟随追加,合并时翻牌动画);
|
|
77
|
-
shell 命令浅灰、路径 cyan;编辑工具 git 风格 diff(`-` 暗红底 / `+` 暗绿底 /
|
|
78
|
-
文件统计),头部带 git 红绿增删行数(如 ` -13 +24`),默认收起,Enter 展开;
|
|
79
|
-
正文超出窗口时单独全览(Esc 返回);JSON 参数与结果自动转可读内容;
|
|
80
|
-
- 转录区滚动回看(`PgUp`/`PgDn`、鼠标滚轮),点击思考/工具标题行直接展开收起;
|
|
81
|
-
- 输入框下方两行底栏:第一行链路芯片 + 按宽度丢组的会话数字(轮次、入/出 token、速度);
|
|
82
|
-
第二行只留一个活动词(运行中 / 工具 N / 子代理 N / 压缩中…),身份收到右侧(含 `目录:srv`;点击打印完整工作目录);
|
|
83
|
-
身份里始终带 `sub:<子代理模型>`(如 `sub:grok-4.5(xhigh)`):`/submodel` 选模型、`/subeffort` 选档位(带括号后缀);
|
|
84
|
-
子代理跟随主模型时它就是身份行的暗色;只有 `/submodel` 钉到**别的提供商**才变色并补上 `提供商/` 前缀
|
|
85
|
-
(如 `sub:xai/grok-4.5`)——完整路由在顶栏与 `/status`;
|
|
86
|
-
- 恢复旧会话会切到该会话记录的工作目录;新建会话用启动时的当前目录;
|
|
87
|
-
- 历史会话启动选择器:`dsh --profile tui --resume`(或 `resume`)先选会话再进入;
|
|
88
|
-
- 终端窗口标题栏:运行中旋转图标 + `运行中 · 工具 N`,完成后 `✓ 已完成`,并响
|
|
89
|
-
一声终端铃(`DSH_TUI_NO_BELL=1` 关闭);
|
|
90
|
-
- 审批、`ask_user_question`、计划模式、子代理进度、`/mode` 模式切换、`/model` 模型切换、
|
|
91
|
-
`/disconnect` 断线策略等完整支持;
|
|
92
|
-
- `/approval auto` 自动审批模式(Codex 式):读类/构建/测试、工作区 `edit`/`write`/`read` 自动放行;
|
|
93
|
-
`rm -rf`、`sudo`、`curl|sh`、`git push --force`、敏感路径只读等危险命令自动**拒绝**,并把原因
|
|
94
|
-
回给模型由其自行调整;`npm publish`、解释器 `-c`/`-e` 等未识别形状交给**子代理模型 AI 复核**
|
|
95
|
-
(用户消息 + args/reason/sandbox,英文界面走英文审核员;`authorization=yes` 才放行);
|
|
96
|
-
仍未可判定时接入才询问、断开时自动拒绝——配合 `/disconnect continue` 断线后回合不停摆;
|
|
97
|
-
`/approval status` 另报本轮 AI 复核次数;
|
|
98
|
-
- 每个子代理都是独立可折叠卡片,默认收起,运行中带旋转动画;多个子代理互不混排;
|
|
99
|
-
- 进入计划模式、待审计划、提问用户都会显示对应卡片和底部提示,而不是只塞进系统消息。
|
|
100
|
-
- 工作区底部有 Codex 式「处理中」动画卡:思考里第一个闭合的 `**加粗**` 作为 shimmer
|
|
101
|
-
标题(还没出现就保持「处理中」),运行中的工具摘要在 `└` 下自动折行(最多 3 行,末行
|
|
102
|
-
加省略号),带计时和 Esc 中断;回复开始流式输出时自动让位。
|
|
103
|
-
|
|
104
|
-
- 0.7 起:模型回复可**拖选自由复制**(按住鼠标拖过一段,走 OSC 52 写回本机剪贴板;按住 Shift 拖选
|
|
105
|
-
结果相同;工具卡仍是点击展开)。回复也是**可选中卡片**:空输入 `↑` 落到最新的一条回复或卡片(`▶` 标记,
|
|
106
|
-
走屏幕顺序;`Alt+4` 直接选中最新回复),
|
|
107
|
-
`/copy` 复制的是选中的那一条(原文,不是折行后的屏幕文本),`Enter` 打开全文;
|
|
108
|
-
SSH 会话里复制落到本机终端,不再误报「本终端不接收 OSC 52」;
|
|
109
|
-
底栏收敛成一条带优先级的芯片带(先丢文字后丢组,`⚠` 可点击打开 `/doctor`);**额度条常驻**并标注窗口
|
|
110
|
-
(`5Hr`/`1Wk`/`1Mo`,默认显示最小窗口,未取到时显示 `?%` 并每 15 秒重试);`/mode` 分组显示并可用 `/` 过滤;
|
|
111
|
-
极简视图逐文件列 `+/-`;工具 diff 为**行级**、只高亮变化字符、≥100 列时并排显示;
|
|
112
|
-
`DSH_TUI_LINE_MODE=1` 纯行模式(屏幕阅读器 / `tee`);`ssh-tui.keys` 可改键位(冲突会明确拒绝);
|
|
113
|
-
`DSH_TUI_COLOR_DEPTH` 指定色深(truecolor / 256 / 8 / none)。
|
|
114
|
-
|
|
115
|
-
## 环境要求
|
|
116
|
-
|
|
117
|
-
- Node.js ≥ 22.19
|
|
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 未发布,无法本地装包验证)
|
|
119
|
-
- pnpm(`dsh plugin` 通过 pnpm 管理 profile 依赖)
|
|
120
|
-
- 支持 ANSI 的终端(推荐 SSH 直连;Windows 用 PowerShell / Windows Terminal)
|
|
121
|
-
- Windows:安装、排障与 `/doctor` 的读法见 [docs/windows.md](docs/windows.md)。Host 与显示端之间的本地通道使用命名管道
|
|
122
|
-
`\\.\pipe\dsh-tui-<DSH_HOME 摘要 8 位>-<会话名>-<会话摘要 8 位>`(Windows 只能监听命名管道,
|
|
123
|
-
不能监听 `.sock` 文件;名字里同时带 DSH_HOME 与会话 id 的摘要,所以不同 home、不同会话都不会撞名,
|
|
124
|
-
结束进程即自动回收)。Host 的 stderr 记录在 `%USERPROFILE%\.dsh\tui-socks\<会话名>-<摘要>.err`,
|
|
125
|
-
会话锁仍在 `%USERPROFILE%\.dsh\tui-locks\`。
|
|
126
|
-
|
|
127
|
-
## 部署指南
|
|
128
|
-
|
|
129
|
-
推荐安装就是文首那条 `dsh plugin --profile tui add dsh-ssh-tui@latest`。CLI 会从 npm 拉包、写入 profile 依赖,并把本插件加入 `dsh.profile.bundles`(因为包内声明了 `dsh.bundle`)。
|
|
130
|
-
|
|
131
|
-
可选:把 SuperGrok 订阅接进 dsh(独立插件,不依赖本 TUI):
|
|
54
|
+
### 连接不可靠
|
|
132
55
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
56
|
+
SSH 会断、笔记本会合盖、网络会切换、跳板机会超时。
|
|
57
|
+
|
|
58
|
+
正在运行的回合不应该因为显示终端消失,就和整个 Harness Host 一起死亡。
|
|
59
|
+
|
|
60
|
+
`dsh-ssh-tui` 将 **Host 与显示端分离**:
|
|
61
|
+
|
|
62
|
+
```text
|
|
63
|
+
Harness session
|
|
64
|
+
│
|
|
65
|
+
▼
|
|
66
|
+
TUI Host
|
|
67
|
+
│
|
|
68
|
+
├── 当前 SSH / terminal
|
|
69
|
+
│
|
|
70
|
+
└── 断线后重新 attach
|
|
136
71
|
```
|
|
137
72
|
|
|
138
|
-
|
|
73
|
+
忙碌中的 Host 可以在显示端离开后继续存在;重新连接后,同一条命令即可接回。
|
|
139
74
|
|
|
140
|
-
|
|
141
|
-
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
### 终端环境并不统一
|
|
78
|
+
|
|
79
|
+
Linux PTY、Windows ConPTY、SSH、旧控制台、不同 OSC / mouse / clipboard 能力,并不是同一种终端。
|
|
80
|
+
|
|
81
|
+
本项目不会假定:
|
|
82
|
+
|
|
83
|
+
```text
|
|
84
|
+
process.stdin/stdout == terminal == display == host
|
|
142
85
|
```
|
|
143
86
|
|
|
144
|
-
|
|
87
|
+
而是显式区分:
|
|
88
|
+
|
|
89
|
+
```text
|
|
90
|
+
Harness Host
|
|
91
|
+
↓
|
|
92
|
+
Display Transport
|
|
93
|
+
↓
|
|
94
|
+
Terminal Capability
|
|
95
|
+
```
|
|
145
96
|
|
|
146
|
-
|
|
97
|
+
TTY 是一种能力,不是宿主存在的前提。
|
|
147
98
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
99
|
+
这也是为什么在没有真实终端的 Host 中,插件应该**安全地不激活**,而不是让宿主一起崩掉。
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
### Harness 本身仍在快速变化
|
|
104
|
+
|
|
105
|
+
本项目把 **兼容性当成功能维护,而不是发版后顺便测试**。
|
|
106
|
+
|
|
107
|
+
当前声明窗口:
|
|
108
|
+
|
|
109
|
+
| DeepSeek Harness | 状态 |
|
|
110
|
+
|---|---|
|
|
111
|
+
| `0.1.7-rc.1` / `0.1.7-rc.2` | ✅ 支持 |
|
|
112
|
+
| `0.2.0-rc.1` / `0.2.0-rc.2` | ✅ 支持 |
|
|
113
|
+
| `0.1.5` 及更早 | ❌ 自 `dsh-ssh-tui 0.8.0` 起不再支持 |
|
|
114
|
+
|
|
115
|
+
声明范围:
|
|
116
|
+
|
|
117
|
+
```text
|
|
118
|
+
>=0.1.7-rc.1 <0.1.8
|
|
119
|
+
|| >=0.2.0-rc.1 <0.2.1
|
|
151
120
|
```
|
|
152
121
|
|
|
153
|
-
|
|
122
|
+
发布前会针对支持线重新安装依赖并运行类型检查、测试和真实终端探针。
|
|
123
|
+
|
|
124
|
+
不是:
|
|
125
|
+
|
|
126
|
+
> “安装没有报错,所以应该能用。”
|
|
154
127
|
|
|
155
|
-
|
|
156
|
-
当成挂断:放下显示器并 flush 日志。**空闲断线不保活**(Host 退出,下次从日志
|
|
157
|
-
`--resume`);模型思考 / 回复 / 工具 / 子代理等忙碌状态则 **Host 留下**。
|
|
158
|
-
重新 SSH 后同一条命令会优先接入那个进程(选择器标「可接入」),不要再开第二份 Host:
|
|
128
|
+
而是尽量回答:
|
|
159
129
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
130
|
+
> **“这个 Harness 版本、这个 Host、这个终端路径,我们实际验证过什么?”**
|
|
131
|
+
|
|
132
|
+
---
|
|
133
|
+
|
|
134
|
+
## 同一个 Harness,终端里看到完整过程
|
|
135
|
+
|
|
136
|
+
官方 headless 很适合一次性任务:
|
|
164
137
|
|
|
165
138
|
```bash
|
|
166
|
-
dsh --profile
|
|
167
|
-
dsh --profile tui --resume <session-id> # 有活进程则接入,否则从日志恢复
|
|
139
|
+
dsh --profile headless "..."
|
|
168
140
|
```
|
|
169
141
|
|
|
170
|
-
|
|
171
|
-
后面跟的是 Host 的 pid。被标成「已占用」时 `--resume <session-id>` 会被拒绝而不是把对方踢掉——
|
|
172
|
-
要接管就在**选择器里**选中它,再按 `y` / Enter 确认(那个窗口随即退出)。
|
|
142
|
+
它完成任务后将最终回复写到 stdout。
|
|
173
143
|
|
|
174
|
-
|
|
175
|
-
那个窗口的 launcher 仍然连着显示通道,锁里写的还是 `attached`。所以 Host 会反过来向**终端本身**要答案
|
|
176
|
-
(经 relay 做一次光标往返,见 `scripts/tui-cut-probe.mjs`):终端答不上来就说明那个窗口已经没了,
|
|
177
|
-
选择器直接标「可接入」,一键接入;`--resume <session-id>` 也直接接入。
|
|
178
|
-
只有终端确认还活着时才需要上面的接管确认。这个判断在**首帧之前**完成,所以列表不会先显示「已占用」
|
|
179
|
-
再改口。
|
|
144
|
+
如果你需要持续观察思考、工具、diff、子代理、计划和审批,则可以进入 TUI。
|
|
180
145
|
|
|
181
|
-
|
|
182
|
-
`$DSH_HOME/tui-locks/`,显示通道在 `$DSH_HOME/tui-socks/`。进程死后残留锁会在
|
|
183
|
-
下次启动时核对 pid,已死则自动从日志接管。调试可设 `DSH_TUI_NO_SESSION_LOCK=1`。
|
|
146
|
+
下面是同一个任务:
|
|
184
147
|
|
|
185
|
-
|
|
186
|
-
旧窗口退出,不会两个窗口互相抢显示。
|
|
148
|
+

|
|
187
149
|
|
|
188
|
-
|
|
189
|
-
整屏重绘的时间算成链路);每次重问前等链路安静**一整个应答窗口**(350ms,超时后放宽到
|
|
190
|
-
800ms),这样「上一个请求的回复」必然已经落地并被丢掉;采样取中位数,并丢掉比中位数快 4
|
|
191
|
-
倍以上的(那是别人请求的回复,相对判定所以 `ssh localhost` 的 2ms 链路照样算得出来)。
|
|
192
|
-
代价是每次接入多约 0.4–0.6 秒探测时间,换来的是 50ms 链路不再出现 2ms / 1900ms 的跳变。
|
|
150
|
+
在 TUI 中:
|
|
193
151
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
152
|
+
- reasoning 可折叠、可实时展开;
|
|
153
|
+
- 工具调用以卡片呈现;
|
|
154
|
+
- edit 显示 git 风格 diff;
|
|
155
|
+
- 子代理独立显示;
|
|
156
|
+
- plan / approval / ask-user 直接进入交互界面;
|
|
157
|
+
- 模型输出持续流式显示,而不是等整个任务结束。
|
|
198
158
|
|
|
199
|
-
|
|
200
|
-
处理前再过滤一次;连 Host 启动那几百毫秒里敲的键也会被暂存、接入后补发,不再被丢掉。
|
|
201
|
-
`DSH_TUI_DEBUG=1` 时会打印每次采样与丢弃原因。
|
|
159
|
+
---
|
|
202
160
|
|
|
203
|
-
|
|
204
|
-
`ssh-tui.disconnect: continue`(也可用 `DSH_TUI_DISCONNECT=continue`)则不取消,
|
|
205
|
-
Host 在后台跑完这一轮;审批和提问等接上后再弹。空闲断线直接退出,不占后台。
|
|
206
|
-
留下的 Host 持有该会话的内核写锁(`session.lock`),而 Web 端打开同一会话时正是被这把锁挡下的
|
|
207
|
-
(`resume failed for session … is already owned by an active write handle`)。所以它**跑完留下来的那一轮后最多再等 1 分钟**
|
|
208
|
-
(`DSH_TUI_IDLE_EXIT_MS`,或 settings.yaml 的 `ssh-tui.idleExit`,毫秒;设 `0`/`off` 恢复旧行为)
|
|
161
|
+
## 为弱网而设计
|
|
209
162
|
|
|
210
|
-
|
|
211
|
-
冲突或未知的名字**不会静默生效**:启动时提示,且该键保持默认或变成无操作。
|
|
212
|
-
纯行模式:`DSH_TUI_LINE_MODE=1`(或 `ssh-tui.lineMode: true`)——不画帧,逐事件追加纯文本行,
|
|
213
|
-
适合屏幕阅读器、`tee` 与录屏;代价是全屏交互(鼠标拖选、卡片展开、`/find` 高亮)不可用。
|
|
214
|
-
就自行退出并让出锁:这段时间够原窗口重连接入,之后 `--resume` 重新打开已落盘的日志。
|
|
215
|
-
完全没有显示器且一直空闲的兜底仍由 `DSH_TUI_DETACHED_IDLE_MS`(默认 6 小时)负责。可选:用 tmux 包一层。
|
|
216
|
-
常驻与接管的可复制配方(tmux / screen / systemd --user / 长任务)见 [`docs/remote-ops.md`](docs/remote-ops.md);重连后转录里的「已重连 N 次 · 断开 Xs」与「离开 …」两行的语义也在那里。
|
|
163
|
+
TUI 使用纯 ANSI 和增量重绘,不依赖浏览器或重量级远程 UI。
|
|
217
164
|
|
|
218
|
-
|
|
165
|
+
下面是在 **2 kB/s** 限速下回放真实绘制事件:
|
|
219
166
|
|
|
220
|
-
|
|
167
|
+

|
|
221
168
|
|
|
222
|
-
|
|
169
|
+
该样例可以直接复现:
|
|
223
170
|
|
|
224
171
|
```bash
|
|
225
|
-
|
|
226
|
-
cd dsh-ssh-tui
|
|
227
|
-
node scripts/install.mjs # 默认安装到 tui profile(bash scripts/install.sh 等价)
|
|
172
|
+
npm run screenshots:slow
|
|
228
173
|
```
|
|
229
174
|
|
|
230
|
-
|
|
231
|
-
「装不上先看什么」和 `/doctor` 的读法见 [docs/windows.md](docs/windows.md)。
|
|
232
|
-
|
|
233
|
-
安装到其它 profile(例如自定义 `work` profile):
|
|
175
|
+
对应数据保存在:
|
|
234
176
|
|
|
235
|
-
```
|
|
236
|
-
|
|
177
|
+
```text
|
|
178
|
+
docs/screenshots/slow-link.json
|
|
237
179
|
```
|
|
238
180
|
|
|
239
|
-
|
|
240
|
-
把插件链接进 profile,自动把 `dsh-ssh-tui` 加入该 profile 的 `dsh.profile.bundles`,
|
|
241
|
-
最后把 `/mode` 需要的 preset 名单行写进该 profile 的 `cordis.patch.yml`(见下节)。
|
|
181
|
+
目标不是做一个网络 benchmark。
|
|
242
182
|
|
|
243
|
-
|
|
183
|
+
目标是确保:
|
|
244
184
|
|
|
245
|
-
|
|
246
|
-
而 DSH STORE 只接受「附加式、插件自有 id、不出现 `@deepseek-ai/*` 名字」的 Bundle Patch,
|
|
247
|
-
所以插件自己的 patch 不能挂载官方行 —— 名单行归 profile 的用户层。名单不只是
|
|
248
|
-
`/mode` 的菜单:`ask_user_question`、`present`、PTC 的呈现层、`subagent` 的模型选择
|
|
249
|
-
这些工具行都由 preset 提供,缺席时它们都不在 Agent 的工具目录里。
|
|
185
|
+
> **链路越差,界面可以降级;任务本身不能跟着失去可用性。**
|
|
250
186
|
|
|
251
|
-
|
|
187
|
+
---
|
|
252
188
|
|
|
253
|
-
|
|
254
|
-
「现在更新」走的是 `dsh plugin add`,不会执行仓库脚本,所以这是最通用的一条。
|
|
255
|
-
2. 仓库安装:`node scripts/profile-rows.mjs [profile]`(默认 `tui`;
|
|
256
|
-
`bash scripts/ensure-profile-rows.sh` 是它的薄封装,两者等价)。
|
|
257
|
-
3. 手动在该 profile 的 `$DSH_HOME/profiles/<profile>/cordis.patch.yml` 里加入:
|
|
189
|
+
## 核心能力
|
|
258
190
|
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
191
|
+
### Terminal-native workspace
|
|
192
|
+
|
|
193
|
+
- 纯 ANSI 渲染;
|
|
194
|
+
- Markdown、标题、列表、引用、代码块;
|
|
195
|
+
- 工具卡片与 git 风格 diff;
|
|
196
|
+
- reasoning 折叠与实时查看;
|
|
197
|
+
- plan / approval / ask-user-question;
|
|
198
|
+
- 子代理独立状态卡;
|
|
199
|
+
- 状态行按一眼扫读的顺序回答五个问题:链路健康、正在做什么、tok/s、额度余量、上下文占用(宽度不够时按优先级逐项收敛,窄屏更简洁而不是更拥挤);轮数 / 步数 / 模型时间 / 工具时间 / 缓存命中移出常驻行,仍可在 `/status` 与 `/diag` 查看;
|
|
200
|
+
- `/model`、`/mode`、`/submodel` 等 Harness 能力直接进入终端。
|
|
201
|
+
|
|
202
|
+
### Session continuity
|
|
203
|
+
|
|
204
|
+
- `--resume` 历史会话选择;
|
|
205
|
+
- SSH / terminal 断开后重新 attach;
|
|
206
|
+
- 一个 session 只允许一个写 Host;
|
|
207
|
+
- 新窗口接管时旧显示端有明确退出语义;
|
|
208
|
+
- Host 异常退出后可以从 Harness 日志恢复。
|
|
209
|
+
|
|
210
|
+
### Terminal capability handling
|
|
211
|
+
|
|
212
|
+
- truecolor / 256 / 8 / no-color;
|
|
213
|
+
- Windows Terminal / ConPTY;
|
|
214
|
+
- OSC 52 clipboard 能力判断;
|
|
215
|
+
- mouse / hyperlink / terminal title 能力控制;
|
|
216
|
+
- UTF-8 不可用时 ASCII fallback;
|
|
217
|
+
- `DSH_TUI_LINE_MODE=1` 纯行模式,可用于 `tee`、日志和屏幕阅读器。
|
|
218
|
+
|
|
219
|
+
### Safety and diagnostics
|
|
266
220
|
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
221
|
+
- `/doctor`:检查 profile、依赖和 Harness 组合;
|
|
222
|
+
- `/diag`:检查当前 Host、显示通道和 terminal capability;
|
|
223
|
+
- `/approval auto`:自动处理明确安全或明确危险的操作;
|
|
224
|
+
- 无法确定的动作仍回到用户审批;
|
|
225
|
+
- Host / terminal 不满足运行条件时尽量 fail-safe,而不是破坏宿主。
|
|
272
226
|
|
|
273
|
-
|
|
274
|
-
`/mode` 会打印补丁路径和 `/mode fix` 修复入口,`node scripts/verify.mjs`(`scripts/verify.sh` 等价)也会给出提示。
|
|
275
|
-
另外,preset 的 scope 身份按模块实例判定:一个 dsh 安装树里若存在两份
|
|
276
|
-
`@deepseek-ai/dsh-scope`(npm 嵌套安装的 checkout 可能如此),名单挂载会以
|
|
277
|
-
`refusing to compose an unscoped context` 失败;全局安装(`npm i -g`)不受影响。
|
|
227
|
+
---
|
|
278
228
|
|
|
279
|
-
|
|
229
|
+
## SSH 断了之后
|
|
230
|
+
|
|
231
|
+
如果只是空闲状态断开,Host 会退出,之后从持久化会话恢复即可。
|
|
232
|
+
|
|
233
|
+
如果模型正在:
|
|
234
|
+
|
|
235
|
+
- reasoning;
|
|
236
|
+
- 回复;
|
|
237
|
+
- 调工具;
|
|
238
|
+
- 运行子代理;
|
|
239
|
+
|
|
240
|
+
TUI 可以保留 Host,并允许重新接入。
|
|
280
241
|
|
|
281
242
|
```bash
|
|
282
|
-
|
|
283
|
-
npm install --no-audit --no-fund
|
|
284
|
-
npm run build
|
|
285
|
-
dsh plugin --profile tui add "link:$(pwd)"
|
|
243
|
+
dsh --profile tui --resume
|
|
286
244
|
```
|
|
287
245
|
|
|
288
|
-
|
|
246
|
+
或者指定会话:
|
|
289
247
|
|
|
290
|
-
```
|
|
291
|
-
|
|
292
|
-
node scripts/install.mjs # 装依赖、构建、链接进 tui profile、挂上 /mode 需要的行
|
|
293
|
-
node scripts/verify.mjs # 检查组合是否生效
|
|
248
|
+
```bash
|
|
249
|
+
dsh --profile tui --resume <session-id>
|
|
294
250
|
```
|
|
295
251
|
|
|
296
|
-
|
|
252
|
+
默认策略下,断线会避免无人值守地继续执行需要用户交互的工作。
|
|
297
253
|
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
dsh plugin --profile tui add "link:$((Get-Location).Path)"
|
|
254
|
+
如果明确希望当前回合在 SSH 断开后继续:
|
|
255
|
+
|
|
256
|
+
```text
|
|
257
|
+
/disconnect continue
|
|
303
258
|
```
|
|
304
259
|
|
|
305
|
-
|
|
260
|
+
重新连接后再 attach 即可。
|
|
306
261
|
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
262
|
+
完整生命周期、锁、接管、链路探测与 idle-exit 规则:
|
|
263
|
+
|
|
264
|
+
[Remote Operations](docs/remote-ops.md)
|
|
265
|
+
|
|
266
|
+
---
|
|
267
|
+
|
|
268
|
+
## Windows
|
|
269
|
+
|
|
270
|
+
Windows 不是“顺便能跑”的平台。
|
|
271
|
+
|
|
272
|
+
本项目对 Windows 单独处理:
|
|
273
|
+
|
|
274
|
+
- ConPTY 输入与终端能力;
|
|
275
|
+
- Host / display 生命周期;
|
|
276
|
+
- Windows Terminal 与传统控制台差异;
|
|
277
|
+
- UTF-8 / ASCII fallback;
|
|
278
|
+
- named pipe display transport;
|
|
279
|
+
- terminal close / reconnect;
|
|
280
|
+
- Windows CI 与真实终端探针。
|
|
281
|
+
|
|
282
|
+
安装方式与 Linux 相同:
|
|
283
|
+
|
|
284
|
+
```powershell
|
|
285
|
+
npm i -g @deepseek-ai/dsh
|
|
286
|
+
dsh plugin --profile tui add dsh-ssh-tui@latest
|
|
287
|
+
dsh --profile tui
|
|
311
288
|
```
|
|
312
289
|
|
|
313
|
-
|
|
290
|
+
完整说明:
|
|
314
291
|
|
|
315
|
-
|
|
292
|
+
[在 Windows 上使用](docs/windows.md)
|
|
316
293
|
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
294
|
+
---
|
|
295
|
+
|
|
296
|
+
## 官方 Harness Desktop
|
|
297
|
+
|
|
298
|
+
> ⚠ **不要把本插件加进 Desktop(或 `web`)profile。** 这不是"装了没用",是**会让应用崩**:
|
|
299
|
+
> Desktop 的宿主命令行走的是 web app 的语法(它传 `--no-open`),而命令行在 dsh 里没有仲裁——profile 里每个 app
|
|
300
|
+
> 都会用**自己的**语法解析同一份 argv,遇到不认识的旗标直接退出进程。0.8.2 起本插件的 startup 行会在识别到
|
|
301
|
+
> "这条命令行不属于我"(Desktop 启动器,或 web app 已接管)时**不认领**它;0.8.1 及更早则会以
|
|
302
|
+
> `error: unknown option '--no-open'` 让宿主退出 1,应用随即报 `dsh desktop host exited with 1` 并崩。
|
|
303
|
+
> 万一已经加进去了:从 `profiles\desktop\cordis.patch.yml` 里删掉 `ssh-tui-startup` / `ssh-tui` /
|
|
304
|
+
> `ssh-tui-routes` / `ssh-tui-subagent` 四行(或从备份恢复该文件),应用立刻恢复。
|
|
305
|
+
|
|
306
|
+
官方 Desktop 是 GUI 应用,本身**不需要这个 TUI**。
|
|
307
|
+
|
|
308
|
+
Desktop 内部的 Harness Host 和真正的 console runtime 也不是一回事。
|
|
309
|
+
|
|
310
|
+
当前 Desktop 启动链没有为终端插件提供真实 TTY,因此:
|
|
311
|
+
|
|
312
|
+
```text
|
|
313
|
+
Desktop Host
|
|
314
|
+
│
|
|
315
|
+
├── Harness services
|
|
316
|
+
│
|
|
317
|
+
└── no real terminal
|
|
320
318
|
```
|
|
321
319
|
|
|
322
|
-
|
|
323
|
-
`preset/routing-suite` 复制到 `$DSH_HOME/.agent-presets/routing-suite`,
|
|
324
|
-
这样 TUI 的 `/mode` 菜单才能选择“智能路由模式”。该插件需要 `webServer`
|
|
325
|
-
服务,脚本会在 profile 的 `cordis.patch.yml` 中挂载一个仅监听
|
|
326
|
-
`127.0.0.1` 随机端口的 `dsh-host-webserver`,不会对外开放端口。
|
|
320
|
+
在这种环境中,`dsh-ssh-tui` 会识别缺少 terminal capability,并保持惰性:
|
|
327
321
|
|
|
328
|
-
|
|
322
|
+
- 不创建显示 Host;
|
|
323
|
+
- 不获取 TUI session lock;
|
|
324
|
+
- 不挂终端相关 timer;
|
|
325
|
+
- 不启动 update check;
|
|
326
|
+
- 不应该因为插件无法绘制 TUI 而让 Desktop Host 一起失败。
|
|
327
|
+
|
|
328
|
+
如果你希望使用终端界面,请安装真正的 CLI,并从真实终端启动:
|
|
329
329
|
|
|
330
330
|
```bash
|
|
331
|
-
|
|
332
|
-
dsh --profile tui
|
|
333
|
-
dsh --profile tui resume # 同上(选择器)
|
|
334
|
-
dsh --profile tui --resume <session-id> # 直接恢复指定会话
|
|
335
|
-
dsh --profile tui resume <session-id> # 等价写法
|
|
336
|
-
dsh --profile tui --new # 显式新建会话(默认即新建,供脚本使用)
|
|
337
|
-
dsh --profile tui --model deepseek-v4-flash
|
|
338
|
-
dsh --profile tui --provider <id>
|
|
339
|
-
dsh --profile tui --no-color
|
|
331
|
+
npm i -g @deepseek-ai/dsh
|
|
332
|
+
dsh --profile tui
|
|
340
333
|
```
|
|
341
334
|
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
## 交互与快捷键
|
|
345
|
-
|
|
346
|
-
| 键 | 作用 |
|
|
347
|
-
| --- | --- |
|
|
348
|
-
| `Enter` | 发送;运行中则插入指示;空输入且已选中卡片时展开/收起,选中的是回复则打开全文(`Esc` 返回)。工具正文超出窗口也单独全览 |
|
|
349
|
-
| `1..9` / `Enter` | 回答 `ask_user_question` 提问:`1..9` 直接选,`Enter` 取当前高亮项(默认第一项),`Esc` 才取消 |
|
|
350
|
-
| `↑` / `↓` | 空输入且会话里已有卡片时:在当前屏幕顺序的最新一条(**回复或卡片**)开始往上走,标记 `▶` 只出现在选中的那一条;没有卡片时(纯问答、或刚 `/clear`)仍是有输入时的历史召回——那种会话用 `Alt+4` 或 `Ctrl+N`/`Ctrl+P` 选回复。有输入:历史(↓ 越过最新一条会回到当前草稿) |
|
|
351
|
-
| `Ctrl+R` | 展开最新一条卡片;已选中时全部展开或全部收起(选中的回复不会被抢走焦点,打开覆盖层时该键交给覆盖层) |
|
|
352
|
-
| `Ctrl+T` | 折叠输入框(只影响显示) |
|
|
353
|
-
| `Alt+1` / `2` / `3` / `4` | 跳到最新思考 / 计划 / 子代理 / 回复(回复会被选中,可直接 `/copy`) |
|
|
354
|
-
| `/find [类] 关键字` | 搜索并跳到该条完整消息(反色高亮),命中的那条同时成为选中项。类:`思考` `计划` `子代理` `回复` `提示词`。`Ctrl+/` 或 `Alt+/` 打开 |
|
|
355
|
-
| `Ctrl+G` / `Alt+N` | 下一条搜索结果;`Alt+P` 上一条 |
|
|
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;**拖过回复**按屏幕所见复制(不含选中标记 `▶`) |
|
|
359
|
-
| `PgUp` / `PgDn`、滚轮 | 转录回看 |
|
|
360
|
-
| `Esc` | 取消选择 → 回底部 → 取消当前轮次 |
|
|
361
|
-
| `Ctrl+C` | 中断当前轮次;空闲连按两次退出 |
|
|
362
|
-
| `Ctrl+D` | 退出 |
|
|
363
|
-
| `Ctrl+L` | 重绘整个画面 |
|
|
364
|
-
|
|
365
|
-
`/mode` 切换官方 preset:标准 (`standard`)、PTC (`ptc`;dsh 0.1.1 上仍是 `code`)、极简 (`minimal`)、创造 (`cordis`),以及本地安装的其它模式(如 `routing-suite`)。
|
|
366
|
-
官方 preset 的名字跟 `/language` 走(中文下显示“标准模式 / 极简模式 / PTC 模式 / 创造模式”,
|
|
367
|
-
英文下显示 Standard / Minimal / PTC / Cordis);`$DSH_HOME/.agent-presets` 里自己写的
|
|
368
|
-
preset 保留它 `preset.yml` 里的名字不翻译。`/mode <id|名字>` 直接切,比如
|
|
369
|
-
`/mode minimal`、`/mode 极简模式`;当前会话已经跑过一轮时只记住选择,下次启动生效。
|
|
370
|
-
名单没挂载时启动会打一行提示,`/mode` 会打印 profile 补丁路径和 `/mode fix` 修复入口(见「`/mode` 的 preset 名单」)。
|
|
371
|
-
|
|
372
|
-
斜杠命令:`/help`、`/find`、`/copy`、`/model`、`/effort`、`/provider`、`/language`(`/lang`)、`/view`、`/disconnect`、`/approval`(`auto` / `off` / `status`)、`/submodel`、`/subeffort`、`/mode`、
|
|
373
|
-
`/status`、`/diag`、`/subagents`、`/usage`(`/balance`、`/quota` 同义)、`/setup`、`/clear`,
|
|
374
|
-
界面语言:`/language` 打开选择器,或 `/language zh` / `/language en` 直接切。优先 `DSH_TUI_LANG`,其次 `$DSH_HOME/settings.yaml` 的 `ssh-tui.language`,再跟 `LANG`/`LC_MESSAGES`。未知和 `C` locale 默认中文。
|
|
375
|
-
工作区视图:`/view` 在 **详细**(默认,看见思考和单条工具)和 **极简** 之间切换,写入
|
|
376
|
-
`ssh-tui.view`。极简对齐 Codex:藏思考,按「回复 → 已调用 N 个工具 → 已编辑 N 个文件 →
|
|
377
|
-
下一段回复」交错绘制;合并卡头部带 git 红绿增删行数(`-13 +24`),Enter 展开条目(编辑
|
|
378
|
-
展开后画 diff),状态球只有全失败才红;进行中的计划仍钉在输入框上方。这和 `/mode`
|
|
379
|
-
(agent preset)不是一回事。
|
|
380
|
-
以及 harness 自带命令(`/goal`、`/plan`、`/compact` 等)。底栏第二行(身份行)在剩余额度
|
|
381
|
-
后面用 1 列 Braille 圆环显示当前模型窗口占用(来自 DSH `contextPressure`,与提供商无关),
|
|
382
|
-
绿 / 黄 / 红对应正常 / 80% / 95%。占用到约 80%/95% 会提示;空闲且占用到约 72% 时
|
|
383
|
-
自动跑 `/compact`,避免等回合中途再压才撞窗。
|
|
384
|
-
`/compact` 进行中会显示「压缩上下文」卡片和底栏转圈,结束时写出回收的 token 数。
|
|
385
|
-
模型请求失败会显示重试进度;会话标题由模型生成后写到窗口标题。harness 命令若声明
|
|
386
|
-
支持图片附件,会在命令列表和补全提示中标注“可附图”。
|
|
387
|
-
|
|
388
|
-
`/model` 只换**当前提供商**的模型和思考强度。已经在 SuperGrok 时,直接选
|
|
389
|
-
`grok-4.6` / `grok-4.5`(`grok-4.6` 含 `xhigh`)。要换 DeepSeek / OpenCode /
|
|
390
|
-
其它路由用 `/provider`:先选提供商,再选模型,**下一步请求生效,不用重启**。
|
|
391
|
-
每个提供商上次的模型和思考强度会分开记住。`/setup` 只新增或更新当前这条
|
|
392
|
-
API Key 提供商,不会冲掉其它路由。SuperGrok / X Premium 走本机 OAuth,不需要填 Key。
|
|
393
|
-
|
|
394
|
-
**一个网关就是一个提供商。** `llm-pi-ai` 把线路协议记在 provider 上(一条 route 只能
|
|
395
|
-
一种协议),所以目录跨协议的网关在 `settings.yaml` 里本来会拆成 `command-code` /
|
|
396
|
-
`command-code-completions` / `command-code-messages` 这样的兄弟行。`/provider`、
|
|
397
|
-
`/model`、`/submodel` 把它们**当成一家**列出:模型列表取各行并集,选中后自动落到
|
|
398
|
-
真正能发该协议的那一行(依据网关自己公布的 `supported_endpoints`;公布不了就沿用
|
|
399
|
-
它已经配置在的那行),而记住你上次选择的键是网关注 id——所以下次打开仍然只有一行。
|
|
400
|
-
Command Code 与 OpenCode Go 都是这种网关。
|
|
401
|
-
|
|
402
|
-
子代理默认跟随父会话的提供方,并尽量选同一家的轻量模型:按父会话所选模型名
|
|
403
|
-
近似匹配,`flash` 结尾的优先——DeepSeek 用 `deepseek-v4-flash`,xAI 用
|
|
404
|
-
`grok-4.5`。`/model` 或 `/provider` 换提供商(OAuth / API Key 都一样)时会
|
|
405
|
-
**自动落盘**子代理模型(不弹窗;想手动改再用 `/submodel`):
|
|
406
|
-
|
|
407
|
-
- `/submodel [model-id]`:打开子代理模型选择器;带参数时直接指定模型;
|
|
408
|
-
- `/subeffort`:选择子代理思考强度,或恢复为“跟随提供商默认”;
|
|
409
|
-
- `/subagents`:列出活动子代理;`/subagents kill <session-id> [更多 id...]`
|
|
410
|
-
可释放指定的 continuable 子代理(harness 0.1.1 新增的定向回收能力)。
|
|
411
|
-
|
|
412
|
-
中断的流式输出会保留已生成的部分,并显示 `⚠ 已中断` 标记;团队协作类会话事件
|
|
413
|
-
(`team/*`)也会以系统消息形式显示在转录区。
|
|
414
|
-
|
|
415
|
-
子代理不再把子会话内容平铺进主转录:每个子代理一张卡片,默认折叠,只显示
|
|
416
|
-
`子代理 spawn [id] 运行中 · Ns · 最近活动`。`Enter` / 鼠标点击展开该子代理自己的
|
|
417
|
-
用户消息、工具调用和结果;没有选中卡片时 `Ctrl+R` 展开最新一条,选中后才全部展开/收起。运行中的卡片带旋转
|
|
418
|
-
动画,状态栏和窗口标题显示 `⠋ 子代理 N`。
|
|
419
|
-
|
|
420
|
-
计划条只钉**最新一条未完成的计划**。同一轮次里模型再开新计划时,旧计划归档进
|
|
421
|
-
工作区随转录上滚,底栏换成新计划。任务全部完成后计划条会说「计划任务已全部完成」,
|
|
422
|
-
不再误报「计划模式已关闭」。一轮结束时若待办仍是进行中/待处理,计划条改成「本轮未收尾」并停止转圈,
|
|
423
|
-
同时自动追问模型补一次 `todo_write`(同一列表只问一次,不改会话里的旧状态)。
|
|
424
|
-
打开 `/` 命令选单或批准/提问对话框时,计划条让出底栏。
|
|
425
|
-
`exit_plan_mode` 按 markdown 渲染。`ask_user_question` 仍弹对话框,并留下折叠的
|
|
426
|
-
`提问用户` 卡片。`/goal` 是折叠的 `目标` 卡片。`/find 思考 padAnsi` 或 `Alt+1..4`
|
|
427
|
-
可跳到对应类别的最新卡片。
|
|
428
|
-
|
|
429
|
-
`/usage`(`/balance` 同义,旧名 `/quota` 仍可用)按**当前提供商**查额度或余额:
|
|
430
|
-
|
|
431
|
-
- **DeepSeek 官方**:`GET {baseURL}/user/balance`(文档接口),显示可用/赠送/充值余额;
|
|
432
|
-
- **OpenAI Completions 兼容网关**:按配置的 base URL 探测 `/user/balance`、`/dashboard/billing/credit_grants` 等;
|
|
433
|
-
- **SuperGrok**:`GET cli-chat-proxy.grok.com/v1/billing`,显示本周剩余%;
|
|
434
|
-
- **OpenCode Go**:官方 `/v1/usage`,滚动 5 小时 / 本周 / 本月剩余%;
|
|
435
|
-
- **Command Code**:官方 `/alpha/billing/credits`,滚动 5 小时 / 本周剩余% + 月度额度余额(USD);
|
|
436
|
-
- **OpenCode Zen**:按量计费、没有固定额度,提示到 `https://opencode.ai/zen`。
|
|
437
|
-
|
|
438
|
-
OpenCode Go / Command Code / SuperGrok 启动和运行中都静默查询,底栏显示套餐名 + 剩余条 + 百分比;窄屏先丢掉套餐名,只留条和百分比。DeepSeek 官方和可查询的 OpenAI 兼容网关把剩余余额画进底栏(`余额 86.42 CNY`)。跨过 50% / 25% / 10% / 5% 才往工作区打 ⚠。`/usage` 或 `/balance` 仍打印完整结果。查询默认每 **10 步**一次;小时窗口接近阈值时改 4 步。
|
|
439
|
-
|
|
440
|
-
## 配置
|
|
441
|
-
|
|
442
|
-
### 模型默认值(`$DSH_HOME/settings.yaml`)
|
|
443
|
-
|
|
444
|
-
```yaml
|
|
445
|
-
agent-default-model:
|
|
446
|
-
provider: opencode-go
|
|
447
|
-
model: deepseek-v4-pro
|
|
448
|
-
reasoningEffort: max
|
|
449
|
-
agent-presets:
|
|
450
|
-
default: standard
|
|
451
|
-
ssh-tui-subagent:
|
|
452
|
-
model: deepseek-v4-flash
|
|
453
|
-
# provider 可省略:省略时子代理跟随父会话提供方
|
|
454
|
-
# reasoningEffort 可省略:省略时跟随提供商/模型默认
|
|
455
|
-
ssh-tui:
|
|
456
|
-
language: zh # 或 en;/language 写入这里。DSH_TUI_LANG 优先
|
|
457
|
-
view: detailed # 或 compact;/view 写入这里
|
|
458
|
-
```
|
|
335
|
+
Desktop / no-TTY Host 的诊断与上游问题记录:
|
|
459
336
|
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
每个提供商上次的模型和思考强度记在 `ssh-tui-routes` 里,切回 SuperGrok / 官方 / Go 时会预填。
|
|
463
|
-
`/setup` 只更新当前这条提供商(模型列表会合并),不会删掉其它路由的 Key 和模型。
|
|
337
|
+
- [Desktop compatibility](docs/desktop.md)
|
|
338
|
+
- [Upstream desktop report](docs/upstream-desktop-report.md)
|
|
464
339
|
|
|
465
|
-
|
|
340
|
+
> Desktop-safe 不等于“把 TUI 嵌进 Desktop GUI”。
|
|
341
|
+
> 前者是 Host compatibility;后者需要宿主提供合适的 display transport。
|
|
466
342
|
|
|
467
|
-
|
|
468
|
-
加上子代理那条——包括钉死到别的提供商的情况)会单独记在 `tui-session-routes.json` 里,
|
|
469
|
-
`--resume` 时**自动按记录恢复**,并在转录区打一行说明:
|
|
343
|
+
---
|
|
470
344
|
|
|
345
|
+
## Host、Display、Terminal
|
|
346
|
+
|
|
347
|
+
项目目前遵循一个简单原则:
|
|
348
|
+
|
|
349
|
+
```text
|
|
350
|
+
┌──────────────┐
|
|
351
|
+
│ Harness Host │
|
|
352
|
+
└──────┬───────┘
|
|
353
|
+
│
|
|
354
|
+
session / events
|
|
355
|
+
│
|
|
356
|
+
┌──────▼───────┐
|
|
357
|
+
│ TUI Host │
|
|
358
|
+
└──────┬───────┘
|
|
359
|
+
│
|
|
360
|
+
display transport
|
|
361
|
+
│
|
|
362
|
+
┌───────────┴───────────┐
|
|
363
|
+
▼ ▼
|
|
364
|
+
real TTY / SSH stdio relay
|
|
365
|
+
│
|
|
366
|
+
▼
|
|
367
|
+
terminal capability
|
|
471
368
|
```
|
|
472
|
-
已按本会话记录恢复路由:xai/grok-4.6 (xhigh) · 子代理 deepseek-official/deepseek-v4-flash
|
|
473
|
-
```
|
|
474
369
|
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
向导会尽量自动填好上下文窗口:先读端点 `/models` 的容量字段,查不到再按模型名
|
|
504
|
-
去内置 pi-ai 目录匹配(会剥离提供商写进模型名的思考档位后缀 `-high` / `-low` /
|
|
505
|
-
`-thinking`,以及 `vendor/` 前缀、`:free` 标签、日期戳),命中后逐模型写入
|
|
506
|
-
`contextWindow`。只有仍有模型查不到容量时,才多出一个「路由默认上下文窗口」步骤,
|
|
507
|
-
并把推导值预填好(取本路由已探明窗口的最小值,避免超声明)——直接回车采用,也可
|
|
508
|
-
输入其它数字;全部命中时该步骤自动跳过,不需要任何输入。保存的是路由级
|
|
509
|
-
`defaultContextWindow`,之后用 `/model` 新加的模型会继承它;而且 `/model` 追加
|
|
510
|
-
模型时本身也会先查一遍目录,命中就直接写入该模型的 `contextWindow`。
|
|
511
|
-
|
|
512
|
-
### profile 用户层
|
|
513
|
-
|
|
514
|
-
每个 profile 的 `cordis.patch.yml` 是用户覆盖层,可覆盖插件 patch 的任何行;
|
|
515
|
-
`--patch <file>` 可临时叠加。
|
|
516
|
-
|
|
517
|
-
## 验证
|
|
370
|
+
这带来几个约束:
|
|
371
|
+
|
|
372
|
+
1. **Host 的生命周期不应由某一个显示窗口决定。**
|
|
373
|
+
2. **没有 TTY 不等于 Harness Host 不合法。**
|
|
374
|
+
3. **终端能力必须检测或明确声明,不能凭平台名称猜。**
|
|
375
|
+
4. **掉线、resize、terminal close 都是正常生命周期事件,而不是异常世界。**
|
|
376
|
+
5. **兼容性需要可测试,而不是依赖“在作者机器上能跑”。**
|
|
377
|
+
|
|
378
|
+
维护者侧的生命周期与平台设计:
|
|
379
|
+
|
|
380
|
+
- [Platform notes](docs/platform.md)
|
|
381
|
+
- [Terminal capability matrix](docs/terminals.md)
|
|
382
|
+
|
|
383
|
+
---
|
|
384
|
+
|
|
385
|
+
## 适合谁
|
|
386
|
+
|
|
387
|
+
推荐使用 `dsh-ssh-tui`,如果你经常:
|
|
388
|
+
|
|
389
|
+
- SSH 到服务器上写代码;
|
|
390
|
+
- 通过公司跳板机工作;
|
|
391
|
+
- 使用远程开发机 / 测试机;
|
|
392
|
+
- 网络延迟高或连接偶尔中断;
|
|
393
|
+
- 需要 Windows Terminal / ConPTY;
|
|
394
|
+
- 希望 Harness 更新后仍有明确兼容边界;
|
|
395
|
+
- 更在意 session continuity 和终端可靠性,而不是浏览器级视觉能力。
|
|
396
|
+
|
|
397
|
+
如果只跑一次任务并获取最终文本:
|
|
518
398
|
|
|
519
399
|
```bash
|
|
520
|
-
|
|
521
|
-
npm test # 单元 + 集成(含屏幕网格护栏、重连接管、选择器首帧)
|
|
522
|
-
python3 scripts/pty-acceptance.py # 真 PTY:模拟 40ms SSH 链路 + 滞留的光标回复
|
|
523
|
-
node scripts/tui-probe.mjs # 真 PTY:真 dsh --profile tui 走一遍启动/缩放//diag/打字//exit
|
|
400
|
+
dsh --profile headless "..."
|
|
524
401
|
```
|
|
525
402
|
|
|
526
|
-
|
|
403
|
+
通常更加简单。
|
|
404
|
+
|
|
405
|
+
如果需要浏览器富交互,则继续使用 Harness Web / Desktop。
|
|
406
|
+
|
|
407
|
+
它们解决的是不同问题。
|
|
408
|
+
|
|
409
|
+
---
|
|
410
|
+
|
|
411
|
+
## 常用命令
|
|
527
412
|
|
|
528
413
|
```bash
|
|
529
|
-
|
|
530
|
-
dsh --profile tui
|
|
414
|
+
# 启动
|
|
415
|
+
dsh --profile tui
|
|
416
|
+
|
|
417
|
+
# 恢复 / 接入会话
|
|
418
|
+
dsh --profile tui --resume
|
|
419
|
+
|
|
420
|
+
# 更新
|
|
421
|
+
dsh plugin --profile tui add dsh-ssh-tui@latest
|
|
422
|
+
|
|
423
|
+
# 卸载
|
|
424
|
+
dsh plugin --profile tui remove dsh-ssh-tui
|
|
531
425
|
```
|
|
532
426
|
|
|
533
|
-
|
|
534
|
-
`CSI 6n`,并且有两条「上一个 launcher 发出、仍在路上」的滞留回复(一条已在队列里,一条
|
|
535
|
-
落在探测窗口中间),按键在探测还没结束时就敲下去。脚本检查输入是否原样(且只送一次)
|
|
536
|
-
送达 Host、测得的 RTT 是否接近模拟值、屏幕上有没有被回显的 `^[[17;1R`。第一个参数可改
|
|
537
|
-
模拟延迟(秒):`python3 scripts/pty-acceptance.py 0.12`。
|
|
427
|
+
TUI 内:
|
|
538
428
|
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
429
|
+
```text
|
|
430
|
+
/doctor
|
|
431
|
+
/diag
|
|
432
|
+
/model
|
|
433
|
+
/mode
|
|
434
|
+
/submodel
|
|
435
|
+
/status
|
|
436
|
+
/disconnect
|
|
437
|
+
/approval
|
|
438
|
+
```
|
|
544
439
|
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
440
|
+
---
|
|
441
|
+
|
|
442
|
+
## 排障
|
|
443
|
+
|
|
444
|
+
优先运行:
|
|
445
|
+
|
|
446
|
+
```text
|
|
447
|
+
/doctor
|
|
550
448
|
```
|
|
551
449
|
|
|
552
|
-
|
|
553
|
-
那种布局会让 Host 持有真实会话的写锁却对用户的选择器不可见(2026-09-11 事故形态)。
|
|
450
|
+
检查 profile / Harness / plugin 组合。
|
|
554
451
|
|
|
555
|
-
|
|
452
|
+
当前会话、Host、显示端或 terminal capability 有问题:
|
|
556
453
|
|
|
557
|
-
```
|
|
558
|
-
|
|
559
|
-
node scripts/uninstall.mjs work # 指定 profile
|
|
454
|
+
```text
|
|
455
|
+
/diag
|
|
560
456
|
```
|
|
561
457
|
|
|
562
|
-
|
|
458
|
+
Windows:
|
|
563
459
|
|
|
564
|
-
|
|
460
|
+
[docs/windows.md](docs/windows.md)
|
|
565
461
|
|
|
566
|
-
|
|
567
|
-
- `.gitignore` 已排除 `node_modules/`、`lib/`、`.env*`、`*.key`、`session*.jsonl*`、
|
|
568
|
-
`sessions/`、日志与临时文件;
|
|
569
|
-
- 上传前请自查:`find . -type f | grep -Ei 'credential|\.env|\.key|session'`;
|
|
570
|
-
- 插件本身不收集、不上传任何数据;会话日志仅按需读写于本机 `$DSH_HOME`;
|
|
571
|
-
- 首次配置可能会在 shell rc(`.bashrc` / `.zshrc` 等)写入 `env.sh` 引用以便启动环境覆盖生效;
|
|
572
|
-
若不希望改动 rc,可设置 `DSH_TUI_NO_RC_HOOK=1` 跳过。
|
|
462
|
+
SSH、掉线、Host 生命周期:
|
|
573
463
|
|
|
574
|
-
|
|
464
|
+
[docs/remote-ops.md](docs/remote-ops.md)
|
|
575
465
|
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
466
|
+
Desktop:
|
|
467
|
+
|
|
468
|
+
[docs/desktop.md](docs/desktop.md)
|
|
469
|
+
|
|
470
|
+
终端能力:
|
|
471
|
+
|
|
472
|
+
[docs/terminals.md](docs/terminals.md)
|
|
473
|
+
|
|
474
|
+
底层平台设计:
|
|
475
|
+
|
|
476
|
+
[docs/platform.md](docs/platform.md)
|
|
477
|
+
|
|
478
|
+
提交 issue 时,建议同时附上 `/doctor` 与 `/diag` 输出。
|
|
479
|
+
|
|
480
|
+
---
|
|
481
|
+
|
|
482
|
+
## 可选:SuperGrok / X Premium
|
|
483
|
+
|
|
484
|
+
如果已经有 SuperGrok / X Premium,可以使用独立插件:
|
|
485
|
+
|
|
486
|
+
[dsh-llm-xai-oauth](https://github.com/cyjyyd/dsh-llm-xai-oauth)
|
|
487
|
+
|
|
488
|
+
安装到当前 TUI profile:
|
|
489
|
+
|
|
490
|
+
```bash
|
|
491
|
+
dsh plugin --profile tui add dsh-llm-xai-oauth@latest
|
|
598
492
|
```
|
|
599
493
|
|
|
494
|
+
它和本 TUI 独立:headless、Web 或其它 profile 也可以使用。
|
|
495
|
+
|
|
496
|
+
---
|
|
497
|
+
|
|
498
|
+
## Development
|
|
499
|
+
|
|
600
500
|
```bash
|
|
501
|
+
git clone https://github.com/cyjyyd/dsh-ssh-tui.git
|
|
502
|
+
cd dsh-ssh-tui
|
|
503
|
+
|
|
601
504
|
npm install
|
|
602
|
-
npm run typecheck
|
|
603
505
|
npm run build
|
|
506
|
+
npm test
|
|
507
|
+
```
|
|
508
|
+
|
|
509
|
+
两条不跑"有没有坏"、而跑"有没有守住"的命令:
|
|
510
|
+
|
|
511
|
+
```bash
|
|
512
|
+
npm run freeze # B2 冻结:八条不变量 + 七条退役路径(unclassified / live source rows / …)
|
|
513
|
+
npm run bench # 性能基线:流式 / 等待 / 报告翻页 / 菜单移动 / 向导打字,并断言都不整屏重画
|
|
604
514
|
```
|
|
605
515
|
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
-
|
|
644
|
-
|
|
645
|
-
-
|
|
646
|
-
|
|
647
|
-
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
在 POSIX 上是 `0600`/`0700`,在 Windows 上是**只授权当前用户**的 ACL(`icacls` 去掉继承)。
|
|
667
|
-
`DSH_HOME` 放在共享目录时这一点尤其重要。
|
|
668
|
-
|
|
669
|
-
### 状态栏与额度
|
|
670
|
-
|
|
671
|
-
- **额度条显示 `░░░░░░░░ ?%`**:**还没拿到读数**(接口慢或不通),不是 0%。TUI 每 15 秒重试一次,拿到后自动替换成
|
|
672
|
-
真实数值与窗口;一直不变成数值时用 `/quota` 看具体报错。
|
|
673
|
-
- **没有额度条**:只有 SuperGrok / OpenCode Go / Command Code 有额度;DeepSeek 显示的是余额行,Zen 是计量制。
|
|
674
|
-
- **`5Hr` / `1Wk` / `1Mo` 是什么**:该数值所属的额度窗口。默认显示**最小窗口**(5 小时 → 周 → 月),
|
|
675
|
-
`/quota` 列出全部窗口、剩余比例与重置时间。告警仍按"最紧的那个窗口"触发。
|
|
676
|
-
- **状态栏模型名没有提供商前缀**:状态行只显示模型名(`provider/model` 会截断成模型名),完整路由在顶栏与 `/status`;
|
|
677
|
-
`sub:` 子代理同样只显示模型名;只有钉到别的提供商时才补 `提供商/` 前缀并变色。
|
|
678
|
-
- **看不到子代理模型 / 想换子代理**:`/submodel` 选模型、`/subeffort` 选思考档位,`/status` 查看当前值。
|
|
679
|
-
- **没有 `tok/s`**:该轮没有可统计的模型 token;只有首字耗时时显示 `首字 1.2s`。
|
|
680
|
-
- **底栏一直显示「压缩中」,`/compact` 还说已有压缩在进行**:Host 在压缩过程中退出,日志里只剩
|
|
681
|
-
`compaction/start` 没有 `end`,恢复会话时那张卡片会一直停在"运行中"。重新启动(`--resume` 同一会话)
|
|
682
|
-
即可:重放会把这类没有结束事件的压缩结算成「压缩被中断」,底栏随之恢复,`/compact` 也能再用。
|
|
683
|
-
升级到 0.7.2 之前遇到时,重启同样有效(旧卡片不会写回日志)。
|
|
684
|
-
- **计划条只提醒一次"补待办"**:有意如此——一条待办列表只问一次,避免每轮结束都开一个新回合。
|
|
685
|
-
想再次触发,先把列表全部标成完成,再新开一列待办。
|
|
686
|
-
|
|
687
|
-
### 断线与代理
|
|
688
|
-
|
|
689
|
-
- **SSH 断了会怎样**:空闲则落盘后退出;忙碌(思考 / 回复 / 工具 / 子代理)默认取消当轮、保留 Host,
|
|
690
|
-
回来 `dsh --profile tui --resume` 接入;`/disconnect continue` 则让它在后台跑完当前轮。**不要**再开第二个 Host。
|
|
691
|
-
- **重连后多出一行提示、闪出 `^[[17;1R` 之类的字符、链路芯片变空心**:升级到最新版;自动重试期间保持 raw 模式
|
|
692
|
-
并丢弃排队字节,这些字符不会再被回显。
|
|
693
|
-
- **模型请求要走公司 / 本机代理**:给 dsh 进程加 `--use-env-proxy`(不要用 `NODE_OPTIONS`),并用 `NO_PROXY`
|
|
694
|
-
按域名分流——国内直连更快的域名放进去,本地 / 内网地址务必保留在列表里。做法与回退见
|
|
695
|
-
[docs/remote-ops.md §4.7](docs/remote-ops.md)。
|
|
696
|
-
|
|
697
|
-
### 排障入口
|
|
698
|
-
|
|
699
|
-
- **要给支持者一份可读的排障信息**:在会话里敲 **`/diag`**(只读本地信息、不外传):版本、平台、会话 id、
|
|
700
|
-
`DSH_HOME`、显示通道与可连接性、Host 的 pid / 锁状态、链路 RTT、日志格式与大小,最后是**判定链**
|
|
701
|
-
(例如"会接入后台 Host(pid N),不要另起第二个窗口")。部署组合问题用 **`/doctor`**。报 issue 时贴这两段即可。
|
|
516
|
+
真实终端、断线与平台行为由额外 probe 覆盖。
|
|
517
|
+
|
|
518
|
+
项目的目标不是让模拟测试代替终端,而是让:
|
|
519
|
+
|
|
520
|
+
```text
|
|
521
|
+
unit / contract tests
|
|
522
|
+
+
|
|
523
|
+
real terminal probes
|
|
524
|
+
+
|
|
525
|
+
cross-platform CI
|
|
526
|
+
```
|
|
527
|
+
|
|
528
|
+
共同定义“支持”。
|
|
529
|
+
|
|
530
|
+
---
|
|
531
|
+
|
|
532
|
+
## Documentation
|
|
533
|
+
|
|
534
|
+
| 文档 | 内容 |
|
|
535
|
+
|---|---|
|
|
536
|
+
| [windows.md](docs/windows.md) | Windows 安装、终端与排障 |
|
|
537
|
+
| [remote-ops.md](docs/remote-ops.md) | SSH、断线、attach、Host 生命周期 |
|
|
538
|
+
| [desktop.md](docs/desktop.md) | 官方 Harness Desktop / no-TTY Host |
|
|
539
|
+
| [platform.md](docs/platform.md) | 平台生命周期设计与维护者约束 |
|
|
540
|
+
| [release.md](docs/release.md) | 发版流程(硬性规则)与发布前人工门槛 |
|
|
541
|
+
| [terminals.md](docs/terminals.md) | Terminal capability 与兼容矩阵 |
|
|
542
|
+
| [upstream-desktop-report.md](docs/upstream-desktop-report.md) | 可复现的上游 Desktop 问题记录 |
|
|
543
|
+
|
|
544
|
+
---
|
|
545
|
+
|
|
546
|
+
## Project philosophy
|
|
547
|
+
|
|
548
|
+
这个项目最初是为 SSH、跳板机和弱网环境做的。
|
|
549
|
+
|
|
550
|
+
这些环境迫使它很早就面对一些桌面应用容易忽略的问题:
|
|
551
|
+
|
|
552
|
+
- 如果窗口消失,谁拥有 session?
|
|
553
|
+
- 如果网络断了,正在运行的任务怎么办?
|
|
554
|
+
- 如果没有 TTY,插件应该怎么退出?
|
|
555
|
+
- 如果 Windows 和 POSIX 的进程生命周期不同,谁负责 Host?
|
|
556
|
+
- 如果终端说自己支持某种能力,但实际上不支持,谁承担后果?
|
|
557
|
+
- 如果 Harness 明天换一个 Host,UI 是否必须全部重写?
|
|
558
|
+
|
|
559
|
+
因此现在更准确的定义不是:
|
|
560
|
+
|
|
561
|
+
> 一个 SSH 专用 TUI。
|
|
562
|
+
|
|
563
|
+
而是:
|
|
564
|
+
|
|
565
|
+
> **一个把 SSH 当作最严苛真实环境之一来设计的 DeepSeek Harness terminal frontend。**
|
|
566
|
+
|
|
567
|
+
SSH-first.
|
|
568
|
+
|
|
569
|
+
Host-aware.
|
|
570
|
+
|
|
571
|
+
Reconnectable.
|
|
572
|
+
|
|
573
|
+
Compatibility-tested.
|
|
574
|
+
|
|
575
|
+
---
|
|
702
576
|
|
|
703
577
|
## License
|
|
704
578
|
|
|
705
|
-
MIT
|
|
579
|
+
MIT
|