dsh-neotui 0.1.30 → 0.2.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 ADDED
@@ -0,0 +1,48 @@
1
+ # Changelog
2
+
3
+ ## 0.2.1 — 2026-08-16
4
+
5
+ ### Fixed
6
+
7
+ - AskUser 问题始终显示“输入自己的回答”和常驻输入栏。
8
+ - “跳过此问题”改为真实、可导航的列表项,不再使用重复的底部按钮。
9
+ - 自定义回答支持左右键、Home、End、Backspace、Delete 和光标位置插入。
10
+ - 鼠标只在选项实际文字区域内生效,同行空白区域不再误提交。
11
+ - 自定义输入栏固定在自定义回答项下一行,跳过项固定在输入栏下方。
12
+
13
+ ## 0.2.0 — 2026-08-16
14
+
15
+ ### Added
16
+
17
+ - Yazi 风格三栏文件选择器和工作区目录选择器。
18
+ - 路径编辑、目录筛选、隐藏项切换、内容型文件识别和 Nerd Font 图标。
19
+ - Kitty 图片附件、附件管理器和等比例图片预览。
20
+ - 会话树筛选和跨会话模糊定位。
21
+ - Ctrl+Space 控制面板中的快捷键、命令、设置和插件页面。
22
+ - 可校验、可恢复默认的快捷键覆盖配置。
23
+ - 插件清单筛选。
24
+ - Goal、Queue / Steering、后台任务、Subagent 和附件状态界面。
25
+
26
+ ### Changed
27
+
28
+ - Buffer 改为严格模态:点击外部不再隐式关闭。
29
+ - 历史分页不再受渲染层固定消息数量上限影响。
30
+ - 输入附件只显示在固定附件栏,不再写入消息文本。
31
+ - 工具和思考块交互、会话跳转与状态栏信息统一为 Nvim 风格操作。
32
+ - README 重构为安装、交互、快捷键、命令、配置和限制的完整指南。
33
+
34
+ ### Fixed
35
+
36
+ - 历史向上分页递归与 viewport 锚点。
37
+ - bracketed paste 和图片粘贴路由。
38
+ - Kitty 图片传输、placement、清理、返回和 framebuffer 重绘。
39
+ - 文件选择器 Space 多选、返回定位、居中滚动、筛选固定和路径展开。
40
+ - 附件管理器 `dd` 删除。
41
+ - 宽字符覆盖和附件图标 cell 宽度。
42
+ - PTY 退出、鼠标控制序列和 Kitty keyboard 尾部解析。
43
+
44
+ ### Known limitations
45
+
46
+ - 当前 Host prompt 内容协议只接受文本和图片,不支持通用文件块。
47
+ - 快捷键覆盖已安全持久化,但部分旧 handler 尚未完全迁移到动态 dispatch。
48
+ - 图片体验取决于 Kitty graphics 兼容终端及其 cell 几何信息。
package/README.md CHANGED
@@ -1,166 +1,266 @@
1
- # dsh-neotui — 鼠标驱动 Neo-TUI 客户端
1
+ # dsh-neotui
2
2
 
3
- DeepSeek Harness 的终端客户端(B 档范围,按 `../dsh-tui-design.md`)。纯 Node 标准库,零依赖。
3
+ `dsh-neotui` 是 DeepSeek Harness 的终端客户端:以 Vim/Nvim 风格的 NORMAL / INSERT 模式、Yazi 风格文件选择器和鼠标交互,访问与 WebUI 相同的 Host 会话、工具、审批、任务和设置能力。
4
4
 
5
- ## 安装(推荐:从 npm 装成 profile)
5
+ 本仓库发布两个 npm 包:
6
+
7
+ | 包 | 用途 |
8
+ |---|---|
9
+ | `dsh-neotui` | TUI 客户端、核心界面和 `dsh-neotui` 命令 |
10
+ | `dsh-neotui-app` | 将 TUI、API gateway 和 Host 服务装配成 DSH profile 的 bundle |
11
+
12
+ ## 0.2.0 亮点
13
+
14
+ - 三栏 Yazi 风格文件与工作区选择器:路径编辑、模糊筛选、隐藏项、Nerd Font 图标和 Kitty 图片预览;
15
+ - 图片附件栏、附件管理器、`dd` 删除和等比例 Kitty 预览;
16
+ - 会话树筛选、跨会话模糊定位和稳定的历史分页;
17
+ - NORMAL / INSERT 模式与可编辑的快捷键目录;
18
+ - 独立的命令、设置和插件目录,插件支持即时筛选;
19
+ - Queue / Steering、Goal、TODO、Plan Review、后台任务和 Subagent 状态;
20
+ - grapheme-aware framebuffer、CJK/组合字符、Kitty keyboard、SGR mouse、OSC 8/52。
21
+
22
+ 完整变化见 [`CHANGELOG.md`](CHANGELOG.md)。
23
+
24
+ ## 安装与启动
25
+
26
+ ### 独立 DSH profile
27
+
28
+ ```bash
29
+ dsh plugin --profile dsh-neotui add dsh-neotui-app
30
+ dsh --profile dsh-neotui
31
+ ```
32
+
33
+ 常用参数:
6
34
 
7
35
  ```bash
8
- npm i -g pnpm # 首次需要 pnpm(dsh plugin 通过它安装)
9
- dsh plugin --profile dsh-neotui add dsh-neotui-app # 装 bundle,自动加入 profile 层栈
10
- dsh --profile dsh-neotui # 启动
36
+ dsh --profile dsh-neotui --session <session-id>
37
+ dsh --profile dsh-neotui --cwd ~/work
38
+ dsh --profile dsh-neotui --host 127.0.0.1 --port 3981
11
39
  ```
12
40
 
13
- ## 本地开发(从源码跑)
41
+ 出于安全原因,`--host 0.0.0.0` 会被拒绝。能够执行工具的 Host 不应直接暴露到不受信任的网络。
14
42
 
15
- 克隆后先自链核心包(app bundle 通过包名 `dsh-neotui` 引核心,Node 会从真实路径向上找 `node_modules`):
43
+ ### 连接已有 Web Host
16
44
 
17
45
  ```bash
18
- ln -sfn .. node_modules/dsh-neotui # 仓库根自链,让 app/src 能 import "dsh-neotui"
46
+ dsh --profile dsh-neotui --attach 3080
19
47
  ```
20
48
 
21
- 然后把 profile 的两条软链指到本仓库(`~/.dsh/profiles/node_modules/`):
49
+ 也可以直接运行客户端:
22
50
 
23
51
  ```bash
24
- ln -sfn "$(pwd)" ~/.dsh/profiles/node_modules/dsh-neotui
25
- ln -sfn "$(pwd)/app" ~/.dsh/profiles/node_modules/dsh-neotui-app
52
+ node bin/dsh-tui.js
53
+ node bin/dsh-tui.js --base http://127.0.0.1:3080
26
54
  ```
27
55
 
28
- 启动(本地开发 profile `~/.dsh/profiles/dsh-neotui`):
56
+ 默认连接 `http://127.0.0.1:3080`;可通过 `--base`、`DSH_URL` 或 `DSH_WEB_URL` 覆盖。`--attach` 不会启动或替换 WebUI。
57
+
58
+ ## 从源码运行
59
+
60
+ ```text
61
+ .
62
+ ├── app/ dsh-neotui-app bundle
63
+ ├── bin/dsh-tui.js 客户端入口
64
+ ├── src/ TUI 核心
65
+ └── test/ 单元、终端协议与 PTY 测试
66
+ ```
67
+
68
+ 使用本地 profile:
29
69
 
30
70
  ```bash
71
+ mkdir -p ~/.dsh/profiles/node_modules
72
+ ln -sfn "$(pwd)" ~/.dsh/profiles/node_modules/dsh-neotui
73
+ ln -sfn "$(pwd)/app" ~/.dsh/profiles/node_modules/dsh-neotui-app
31
74
  dsh --profile dsh-neotui
32
- dsh --profile dsh-neotui --session <id>
33
- dsh --profile dsh-neotui --cwd ~/work
34
- dsh --profile dsh-neotui --port 3981
35
- dsh --profile dsh-neotui --attach 3080 # 共存调试:连已运行的 web 宿主(存储隔离,不碰 $DSH_HOME)
75
+ ```
76
+
77
+ 只调试客户端时,保证目标 Host 已运行即可:
36
78
 
37
- node bin/dsh-tui.js # 纯客户端模式:连接已运行的 web 宿主(默认 3080)
38
- node bin/dsh-tui.js --base http://host:port
79
+ ```bash
80
+ node bin/dsh-tui.js --base http://127.0.0.1:3080
39
81
  ```
40
82
 
41
- **共存调试**:web UI 和 TUI 同时跑用 `--attach`——TUI 直连 web 宿主的 API(两边实时互见对方消息),自身的内嵌宿主存储重定向到 `/tmp/dsh-neotui-attach`,绝不写共享的 `$DSH_HOME`。纯客户端 `node bin/dsh-tui.js --attach 3080` 同理。
83
+ ## 交互模型
42
84
 
43
- ## 结构
85
+ ### NORMAL / INSERT
44
86
 
45
- ```
46
- tui/ TUI 核心(src/) + 独立入口(bin/) + 测试(test/)
47
- tui/app/ dsh-neotui-app bundle:cordis.patch.yml + tui-startup/tui-runtime 插件
48
- (~/.dsh/profiles/ntui 通过 profiles/node_modules 软链解析它)
49
- ```
87
+ - `NORMAL`:单字符用于导航和操作;
88
+ - `INSERT`:键盘输入交给消息编辑器;
89
+ - `i` 或点击输入框进入 INSERT;
90
+ - `Esc` 离开 INSERT;
91
+ - INSERT 中 `Esc` 不会中断当前回合;
92
+ - NORMAL 中 `Esc` 会中断正在运行的回合,否则返回上一级;
93
+ - NORMAL 中连续两次 `Ctrl+C` 退出,INSERT 中 `Ctrl+C` 清空输入。
94
+
95
+ 底栏始终显示当前模式。按 `Ctrl+Space` 打开快捷键、命令、设置和插件目录。
96
+
97
+ ### 输入与附件
98
+
99
+ | 模式 | 按键 | 功能 |
100
+ |---|---|---|
101
+ | INSERT | `Enter` | 发送 |
102
+ | INSERT | `Shift+Enter` / `Ctrl+J` | 换行 |
103
+ | INSERT | `Ctrl+L` | 展开/折叠输入栏 |
104
+ | INSERT | `↑` / `↓` | 在首尾行浏览输入历史 |
105
+ | INSERT | `Ctrl+Shift+C` | 复制输入框选区 |
106
+ | INSERT | `Ctrl+O` | 打开文件选择器 |
107
+ | NORMAL | `Ctrl+O` | 打开附件管理器 |
108
+
109
+ 文件选择器支持:
110
+
111
+ | 按键 | 功能 |
112
+ |---|---|
113
+ | `↑` / `↓` | 移动光标 |
114
+ | `←` / `→` | 返回上级 / 进入目录 |
115
+ | `Space` | 选择或取消文件 |
116
+ | `Enter` | 确认上传 |
117
+ | `/` | 筛选当前目录 |
118
+ | `Ctrl+/` | 清除筛选并退出筛选模式 |
119
+ | `Ctrl+F` | 编辑路径,支持 `~`、`$HOME` 和环境变量 |
120
+ | `Ctrl+.` | 显示/隐藏隐藏项 |
121
+ | `Esc` | 关闭 |
122
+
123
+ 附件管理器支持 `Enter` 预览、`Shift+Enter` 或双击用默认程序打开、`dd` 删除。当前 Host 内容协议只接受文本和图片;普通文件不会被伪装成可发送附件。
124
+
125
+ Kitty graphics 可用时,图片在文件选择器和附件预览中等比例显示;否则回退到 MIME、尺寸和文件大小信息。
50
126
 
51
- ## 操作
127
+ ### Queue / Steering
52
128
 
53
- | 鼠标 | 键盘等价 |
129
+ 模型运行时,Enter 的策略由 `busyEnter` 决定:
130
+
131
+ - `queue`:加入下一回合队列;
132
+ - `steer`:追加到当前回合。
133
+
134
+ `Ctrl+Y` 切换策略,`Ctrl+U` 打开队列。队列面板使用 `e` 编辑、`s` steering、`d` 删除、`Esc` 关闭。
135
+
136
+ ## 快捷键
137
+
138
+ 以下是默认绑定。控制面板中的快捷键页以 `MODE / KEY / FUNCTION` 三列显示,并允许编辑用户覆盖;配置写入 `$DSH_HOME/tui-config.json`。
139
+
140
+ | 模式 | 按键 | 功能 |
141
+ |---|---|---|
142
+ | ALL | `Ctrl+Space` / `F7` | 控制面板 |
143
+ | NORMAL | `/` | 筛选会话树;`Ctrl+/` 退出 |
144
+ | NORMAL | `Ctrl+F` | 跨会话模糊定位 |
145
+ | NORMAL | `Ctrl+B` | 显示/隐藏侧栏 |
146
+ | NORMAL | `Ctrl+M` | 模型与思考强度 |
147
+ | NORMAL | `F8` / `F9` | 权限策略 / Agent 模式 |
148
+ | NORMAL | `Ctrl+W` | 工作区 |
149
+ | NORMAL | `Ctrl+Shift+W` | 添加工作区 |
150
+ | NORMAL | `Ctrl+T` | 轨迹视图 |
151
+ | NORMAL | `Shift+Tab` | 对话/轨迹切换 |
152
+ | NORMAL | `Ctrl+E` | 按 step 快速跳转 |
153
+ | NORMAL | `Ctrl+J` | 后台任务与 Subagent |
154
+ | NORMAL | `Ctrl+U` | 消息队列 |
155
+ | NORMAL | `Ctrl+G` | Goal / TODO |
156
+ | NORMAL | `Ctrl+S` | Settings |
157
+ | NORMAL | `Ctrl+A` | Subagent |
158
+ | NORMAL | `Ctrl+K` | Skills |
159
+ | ALL | `Ctrl+Q` | 退出 |
160
+ | NORMAL | `t` / `b` | 展开/折叠思考块 / 工具块 |
161
+ | NORMAL | `g g` / `G` | 对话顶部 / 底部 |
162
+ | NORMAL | `[` / `]` | 上一个 / 下一个提问终点 |
163
+ | NORMAL | `PgUp` / `PgDn` | 翻页;到顶时加载更早历史 |
164
+
165
+ 快捷键目录中:`Enter` 编辑当前 JSON 配置项,`Shift+Tab` 在 NORMAL / INSERT / ALL 间轮换,`Alt+Enter` 恢复默认。保存前会校验 JSON、模式和按键字段;错误文本会保留以便继续修改。
166
+
167
+ ## Slash 命令
168
+
169
+ 输入 `/` 后使用 `Tab`、`↑`、`↓` 补全。TUI 本地命令包括:
170
+
171
+ | 命令 | 功能 |
54
172
  |---|---|
55
- | 左键点击会话(工作区树内) | ↑↓ + Enter |
56
- | 点击/Enter/←→ 折叠工作区文件夹 | 右键「折叠全部/展开全部」 |
57
- | 隐藏/显示侧栏(nvim 式整体收起) | **Ctrl+B** |
58
- | 控制面板(三页) | **F7**/Ctrl+Space 打开(首页快捷键),**Ctrl+P** 直达命令页;**Tab** 翻页:快捷键 / 命令 / 设置 |
59
- | 设置次级页 | 在「设置」页内 **Shift+Tab** 翻次级页(常规 / 插件) |
60
- | 主页切换 | **Shift+Tab** 在对话 ↔ 轨迹之间切换;顶部标签页(对话/轨迹/工作区/设置/技能/子代理)可点击直达 |
61
- | 输入模式 | `i` 或点击进入,**Esc 退出**(nvim normal/insert);未聚焦时字母=快捷键,多字粘贴直接输入 |
62
- | 思考/工具折叠 | `t` 思考块展开折叠,`b` 工具块(bash 等)展开折叠;右键消息 →「展开 / 折叠」折叠单个输出块;正文文本块同样支持点击/右键折叠(▸/▾ + 「…共 N 字」尾注);展开的思考块渲染**全文**,不再截断 |
63
- | 右键菜单 | 菜单打开后**再次右键**任意位置:立即关闭当前菜单并在新位置打开新菜单(OS 式);左键点击菜单外仍是关闭 |
64
- | 对话 ↔ 轨迹转跳 | 对话里右键消息 →「转跳轨迹」定位到对应 step(自动展开+高亮);轨迹里右键 step →「转跳对话」回到该消息 |
65
- | 步骤快速转跳 | **Ctrl+E**:fzf 式过滤 step 列表(编号/耗时/工具/消息预览),回车定位到该 step 的轨迹窗口 |
66
- | 轨迹窗口导航 | 转跳后只显示 `step±20` 窗口;**PgUp/PgDn** 上下各加载 10 步,**Home/End** 跳到最早/最新 20 步,`r` 回最新 |
67
- | 后台任务 | **Ctrl+J** 后台任务面板(Enter/→/l 展开详情,←/h 折叠,q 关闭);状态栏只显示「N 个任务正在后台运行 · M已完成 (Ctrl+J 查看详情)」 |
68
- | 右键文件夹 → 新建会话(归属该工作区) | `n` |
69
- | 滚轮翻页 / 拖拽 | PgUp / PgDn / gg / G |
70
- | 点击展开思考块/工具卡 | — |
71
- | 点击输入框输入 | i / 直接打字 |
72
- | 滚轮到顶加载更早记录 | PgUp 到顶 |
73
- | | `/` 搜索会话,`n` 新建会话,Ctrl+B/N 切换焦点 |
74
- | | Ctrl+P 命令面板,Ctrl+M 模型,Ctrl+W 工作区,Ctrl+T 轨迹,Ctrl+J 任务,Ctrl+G 目标 |
75
- | — | Ctrl+S 设置(JSON 树编辑器,settings.mutate 保存),Ctrl+A 子代理(历史/发消息/中断) |
76
- | | Ctrl+K 技能列表(详情/复制名) |
77
- | — | 输入框 `@/路径/图.png` 附带图片发送(base64 image 内容部件) |
78
- | — | nvim 式按键:聊天聚焦时字母=快捷键(`t` 思考/`i` 输入/`g g` 顶/`G` 底/`/` 搜索),其余字母自动进输入栏 |
79
- | — | 命令面板「切换主题」:dark / light / gruvbox 实时切换 |
80
- | — | 会话右键菜单:打开/重命名/停止/复制 ID/分叉/导出日志 |
81
- | — | Ctrl+Q 退出 |
82
-
83
- ## 验证过的能力
84
-
85
- - 协议:unary RPC(POST `/api/<method>` 信封)+ WS 帧流(`/api/events.mux`)+ `/api/respond`(审批/提问应答)
86
- - 输入:SGR 鼠标(1000/1002/1003/1006)press/release/drag/wheel、修饰键、CJK、bracketed paste、kitty 键盘协议(24/24 单测通过)
87
- - 渲染:cell diff + truecolor、OSC 8 可点击链接、CJK 宽度、滚动缓冲 + 游标分页(beforeSeq)
88
- - 侧栏:web 同款「工作区(文件夹) → 会话(文件)」可折叠树(运行徽标、未分组兜底、右键菜单)
89
- - 降噪:焦点感知高亮(仅聚焦窗格显示选中态)、消息流无粗体标题(用户绿色 gutter、助手空白分隔)、链接无下划线、统一提示样式
90
- - 块式渲染(pi 风格):输出按块拆分,每块独立底色——思考 `THINKBG`(暗)、工具调用 `TOOLBG`(蓝调 `#1e1e2e`)、工具成功 `TOOLOK`(绿调 `#1e2e1e`)、工具失败 `TOOLERR`(红调 `#2e1e1e`)、正文 `CARD`、用户消息 `USERBG`(`#2d2d30`);⏳/✓/✗ 状态字形;块间留白;颜色随主题([pi 主题参考](https://github.com/earendil-works/pi/blob/main/packages/coding-agent/docs/themes.md))
91
- - 工具块**默认展开**(命令 JSON + 结果常显),点击折叠;思考块默认折叠,**`t` 键全局展开/折叠**(pi 式快捷键),点击单个思考块覆盖全局模式
92
- - 稳定性:宽字符贴右缘自动截断(防终端换行损坏)、渲染循环 try/catch 兜底(出错不再杀进程,日志+继续)
93
- - SGR 复位语义:样式分量回到默认值即显式复位(`\x1b[0m`),滚动后背景残留/蔓延彻底消除,块间空隙稳定露出终端背景
94
- - 输入光标:下划线式(不再反显白块);搜索模式独占输入(IME 多字文本进搜索框、结果实时刷新、退格/leader 可用)
95
- - leader 面板对鼠标 motion 免疫(仅点击关闭),搜索模式内 F7/Ctrl+Space 仍可呼出
96
- - 模型切换支持思考强度:选模型后有 Off/High/Max 二次选择(默认 High);插件清单页通过 Typert RPC(`pluginInventory/list`,HTTP POST + `{args}` 载荷)读真实 Loader 条目
97
- - 命令页显示真实 slash 命令(`commands/list`):/compact /export /feedback /goal /permission /plan,点选填入输入框
98
- - 布局:顶部标签页(对话/轨迹,面板以额外活动标签呈现)+ 侧栏「▣ 工作区」标题行
99
- - footer(powerline 风格,2–3 行):第 1 行身份(工作区/会话/运行态/🎯目标/✎计划/模型),第 2 行用量(ctx 条+%、入/出/缓存/共 token、⚙步/回合/首响),第 3 行任务(有 job 时)
100
- - 折叠块预览:bash 折叠后显示命令概要(view.title 或 command),思考折叠后显示前 3 行
101
- - 会话内搜索:**Ctrl+F** 模糊搜本会话消息/工具名,回车跳转
102
- - 轨迹详情:点击回合行弹窗(工具调用 + 耗时),`/` 过滤回合;**增量加载**(每页 20 回合逐页渲染,最近回合秒开,历史步骤按需翻页,不再阻塞等待全量历史)
103
- - 轨迹 详细/简略:每个 step 左键单击(▸/▾)或右键菜单第一项 →「展开(详细)/ 折叠(简略)」内联展开事件列表(仿对话页);跳转定位的 step 自动展开 + 高亮闪烁
104
- - 轨迹窗口模型:转跳只显示目标 step **±20 个相邻步骤**;PgUp/PgDn 按 10 步扩展窗口(按需向后翻页加载),Home 加载到最早 20 步,End 回到最新 20 步,窗口指示行显示「窗口 #N–#M(已加载 X) · step a–b」;窗口边界基于事件序号(seq)而非 step 编号——会话压缩后 step 编号会重新计数,seq 始终唯一
105
- - 工作区文件搜索:工作区面板内直接打字(`/`)模糊搜文件名,回车预览
106
- - 消息反馈:助手消息右键 👍/👎(`messageFeedback/put` Typert RPC,`{request:…}` 载荷),已评状态回显、可删除
107
- - 图片画廊:多图时 ←/→ 切换,标题显示 (N/M) + 尺寸
108
- - 会话内搜索高亮:Ctrl+F 跳转后匹配词高亮(黄底),Esc 清除
109
- - 轨迹逐事件详情:点击回合 → 事件列表 → 选事件看全文
110
- - 用户消息前缀:自己发的消息第一行直接显示内容并带 `用户名 > ` 前缀(默认取系统登录名);**设置页新增「TUI 界面」命名空间**,编辑 `userPrefix` 并 Ctrl+S 即时生效(持久化到 `$DSH_HOME/tui-config.json`);环境变量 `DSH_TUI_USER_PREFIX` 亦可覆盖
111
- - 块计时:流式块实时显示 `已经过 X秒/分/小时`,完成后冻结为 `已完成,耗时 X`(工具失败显示 `失败,耗时 X`);缺失 block-end 也不会出现永远走动的计时器
112
- - 块编号:think/tool/text 块头部标注所属 `(step N)`,与轨迹页的 step 编号对应,Ctrl+E 可据此快速转跳
113
- - 主题持久化:切主题写入 `$DSH_HOME/tui-theme.txt`(或 XDG config),重启保留
114
- - 输入模式标识:标签栏右侧 NORMAL/INSERT 指示,Esc 退出输入
115
- - 实时流:merge 修复(新回合不再覆盖旧回合)、活跃时 500ms 轮询、流式思考/工具自动展开
116
- - footer 增加完整工作路径 + 缓存命中率
117
- - 工作区右键「重命名工作区」(workspace.rename)
118
- - 轨迹回合行加用户消息预览、移除「按 Esc 返回」提示
119
- - 点击击穿修复:弹窗关闭时吞掉配对 release,不再误触下层会话
120
- - footer 离线态:断连时第 1 行显示 ⚠离线
121
- - 功能:会话列表/搜索/新建/重命名、流式对话(历史 + 轮询实时)、推理块折叠、工具卡(diff/通用卡)、审批/提问弹窗
122
- - 面板:命令面板(模糊筛选)、模型选择(真实目录)、工作区文件树(展开/预览)、轨迹视图(braille 三车道时间轴 + 回合统计表)、任务/目标弹窗
123
- - 设置:11 个命名空间通用 JSON 树编辑器(类型着色、布尔点击切换、标量编辑、pending 暂存、settings.mutate 保存、重启生效标记)
124
- - 子代理:列表(activity/mode)、历史日志、continuable 发消息、中断
125
- - 会话操作:分叉(session.fork)、日志导出(ZIP 落盘,已真机验证 1.5MB zip)
126
- - 主题:theme.js 三套调色板(dark/light/gruvbox),全 UI 经 live Proxy 读色,命令面板一键切换
127
- - 实时更新:mux 实时通道在本部署不工作(20s 探测仅 3 个 baseline 帧),改用 web 同款 resync 式轮询(1.2s,活跃时自适应),会话列表状态同步刷新
128
- - 渲染性能:节点级渲染缓存(仅流式尾节点重渲染),冷重建 50 节点 ~3ms,热重建命中缓存
129
- - 鼠标:滚动条点击跳转 + 拖拽 scrubbing、拖拽选区 + OSC 52 复制(nvim 式)、右键上下文菜单
130
- - 技能:skill.list 真实数据(⚡ 模型可调用徽标 + 描述/何时使用详情)
131
- - 图片输入:`@路径` 解析 → image 内容部件(15 项单测,解析/媒体类型/base64/容错全覆盖)
132
- - 图片:消息内 🖼 占位 → kitty 图形协议内联 / chafa 字符预览 / 外部查看器兜底
133
- - 状态栏:上下文压力 (ctx%)、token、目标 🎯、连接态、任务指示
173
+ | `/reload` | 重新绘制并载入界面状态 |
174
+ | `/restart` | 重启 TUI 并恢复会话 handoff |
175
+ | `/model` | 模型选择 |
176
+ | `/theme` | 切换主题 |
177
+ | `/permission` | 权限选择 |
178
+ | `/goal` | Goal 面板 |
179
+
180
+ Host 提供的 `/compact`、`/export`、`/feedback`、`/plan` 等命令会动态出现在命令页;实际清单以当前 Host `commands/list` 为准。
181
+
182
+ ## 面板与工具卡
183
+
184
+ TUI 支持:
185
+
186
+ - 工作区和分组会话树:新建、打开、重命名、移动、归档、删除和导出;
187
+ - terminal、read、search、web、diff generic presentation;
188
+ - `run_code` 嵌套子调用树;
189
+ - 工具审批、AskUser 单选/多选、Plan Review;
190
+ - Goal、TODO、后台任务和 Subagent;
191
+ - 独立插件清单及 `/` 筛选;
192
+ - dark、light、gruvbox 主题。
193
+
194
+ 所有 Buffer 都是模态的:点击外部只会吞掉事件,不会关闭 Buffer。退出必须使用界面明确提示的按键或操作。
195
+
196
+ ## 鼠标与终端能力
197
+
198
+ - 点击工作区、会话、标签、工具块和输入框;
199
+ - 拖动侧栏分隔线;
200
+ - 滚轮浏览对话、列表和弹窗;
201
+ - 输入框拖选并通过 OSC 52 复制;
202
+ - 右键消息、轨迹 step 和工作区树打开菜单;
203
+ - SGR mouse、bracketed paste、Kitty keyboard、OSC 8、OSC 52;
204
+ - ANSI truecolor 差量 framebuffer;
205
+ - CJK、组合字符和 ZWJ emoji grapheme-aware 渲染。
206
+
207
+ 不同终端、tmux SSH 环境对 Kitty graphics、keyboard、OSC 52 的支持不同。WezTerm 和 Kitty 是图片预览的推荐终端。
208
+
209
+ ## 配置
210
+
211
+ TUI 设置:
212
+
213
+ ```text
214
+ $DSH_HOME/tui-config.json
215
+ ```
216
+
217
+ 包含显示名、默认折叠状态、运行中 Enter 策略和快捷键覆盖。主题保存在:
218
+
219
+ ```text
220
+ $DSH_HOME/tui-theme.txt
221
+ ```
222
+
223
+ `DSH_TUI_USER_PREFIX` 可覆盖默认用户名。
134
224
 
135
225
  ## 测试
136
226
 
137
227
  ```bash
138
- node test/term.test.mjs # 输入解码器单测 (24 项)
139
- node test/image.test.mjs # 图片输入解析单测 (15 项)
140
- # 真机脚本(10 个):smoke live panels final settings edit theme skills select poll
141
- node bin/dsh-tui.js --script test/smoke.script --plain # 真机冒烟
142
- node bin/dsh-tui.js --script test/live.script --plain # 实时流验证
143
- node bin/dsh-tui.js --script test/panels.script --plain # 面板全流程
144
- node bin/dsh-tui.js --script test/final.script --plain # 目标/模型
228
+ npm test # 单元与协议测试
229
+ npm run test:pty # 真实 PTY 生命周期
230
+ npm run test:rc # 完整发布候选验证
145
231
  ```
146
232
 
147
- tty 端到端(raw 模式 + alt-screen):`script -qec "node bin/dsh-tui.js" /dev/null`
148
-
149
- 脚本语法:`wait <ms>` / `key <name>` / `text ...` / `mouse <kind> <btn> <x> <y>` / `frame <json>` / `quit`。
233
+ PTY 测试会验证 alternate screen、SGR mouse、界面渲染、退出恢复和常见运行时错误。需要可用的 DSH Host;Host 不可用时测试会明确输出 `SKIP`。
150
234
 
151
- ## 结构(TUI 核心)
235
+ 脚本化 smoke:
152
236
 
237
+ ```bash
238
+ node bin/dsh-tui.js --script test/smoke.script --plain
153
239
  ```
154
- src/text.js Unicode 宽度、braille、bars
155
- src/screen.js cell 帧缓冲 + ANSI diff 渲染
156
- src/term.js raw 模式、SGR/kitty 输入解码
157
- src/api.js RPC + WS + respond
158
- src/md.js Markdown 终端行(OSC 8 链接、轻量高亮)
159
- src/widgets.js List/ScrollView/Input/Popup/Menu/StatusBar
160
- src/views.js App + 会话列表 + ChatView + 审批弹窗
161
- bin/dsh-tui.js 入口(交互 / 脚本化测试台)
240
+
241
+ ## 当前限制
242
+
243
+ - TUI Host 必须使用兼容的事件、RPC 和内容块契约;
244
+ - 当前 Host 不支持通用二进制文件内容块,文件选择器只会发送图片;
245
+ - Kitty 图片效果受终端实现、cell 尺寸和复用器支持影响;
246
+ - 超长工具输出可能由 Host 截断,TUI 会显示工具提供的恢复位置;
247
+ - 快捷键覆盖配置已持久化并经过校验,部分旧 handler 仍使用内置 dispatch,后续版本会继续统一动态绑定。
248
+
249
+ ## 代码结构
250
+
251
+ ```text
252
+ src/api.js HTTP RPC、WebSocket 和 respond
253
+ src/term.js raw mode、鼠标、paste、Kitty keyboard
254
+ src/screen.js cell framebuffer 与 ANSI diff
255
+ src/text.js grapheme、显示宽度和截断
256
+ src/md.js Markdown、代码块和 OSC 8
257
+ src/widgets.js Input、Popup、ScrollView、Menu、StatusBar
258
+ src/views.js App、ChatView、会话树和主路由
259
+ src/panels.js Workspace、Trajectory、Queue、Jobs、Settings
260
+ src/file-picker.js 三栏文件/目录选择器与图片预览
261
+ app/ DSH bundle 与 Cordis patch
162
262
  ```
163
263
 
164
- ## 路线图(剩余 B 档模块)
264
+ ## 许可证
165
265
 
166
- 图片插件端到端验证(需真实附件)、kitty 图形协议实机验证(需 kitty/wezterm 终端)、TUI slot 契约三层(见设计文档 §2)、子代理完整流程验证(需真实子代理)、交付物/反馈面板(无对应投影数据)、locale 切换。
266
+ MIT
package/bin/dsh-tui.js CHANGED
@@ -20,6 +20,7 @@ const has = (name) => args.includes(name);
20
20
 
21
21
  const base = opt("--base", opt("--attach", process.env.DSH_URL || process.env.DSH_WEB_URL || "http://127.0.0.1:3080"));
22
22
  const log = (...a) => console.error("[dsh-tui]", ...a);
23
+ let activeTerm = null;
23
24
 
24
25
  async function main() {
25
26
  const script = opt("--script", null);
@@ -38,6 +39,7 @@ async function main() {
38
39
  onResize: (w, h) => app.resize(w, h),
39
40
  });
40
41
  app.term = term;
42
+ activeTerm = term;
41
43
  screen.resize(term.w, term.h);
42
44
  app.resize(term.w, term.h);
43
45
  term.start();
@@ -127,4 +129,8 @@ function dump(app, plain) {
127
129
  out.chunks.length = 0;
128
130
  }
129
131
 
130
- main().catch((e) => { log("fatal:", e); process.exit(1); });
132
+ main().catch((e) => {
133
+ log("fatal:", e);
134
+ try { activeTerm?.stop(); } catch {}
135
+ process.exit(1);
136
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-neotui",
3
- "version": "0.1.30",
3
+ "version": "0.2.1",
4
4
  "description": "Neo-TUI: mouse-driven terminal UI client for DeepSeek Harness (B-tier per dsh-tui-design.md)",
5
5
  "type": "module",
6
6
  "bin": {
@@ -14,11 +14,14 @@
14
14
  "bin",
15
15
  "src",
16
16
  "README.md",
17
+ "CHANGELOG.md",
17
18
  "LICENSE"
18
19
  ],
19
20
  "scripts": {
20
21
  "start": "node bin/dsh-tui.js",
21
- "test": "node test/scripted.mjs"
22
+ "test": "node --test test/*.test.mjs",
23
+ "test:pty": "python3 test/pty-crash.py",
24
+ "test:rc": "npm test && npm run test:pty"
22
25
  },
23
26
  "repository": {
24
27
  "type": "git",