pi 终端 UI 演进实录:从 @earendil-works/pi-tui 变更日志看差分渲染、备用屏 TUI 与键盘协议的完整实现脉络
pi 项目的终端交互层由 packages/tui 中的 @earendil-works/pi-tui 包承载:这是一个带差分渲染(differential rendering)与同步输出(CSI 2026)的最小化终端 UI 框架,也是上层 coding-agent CLI 的全部界面基础。本文以 packages/tui/CHANGELOG.md 为主体,完整梳理该包从 0.29.0(2025-12-25)到 0.84.4(2026-08-28)的版本演进,并结合 packages/tui/src 的源码与 packages/tui/package.json 配置,还原每一项关键变更背后的 API 形态、默认值与实现位置,帮助你既能读懂变更日志的每条记录,也能定位到对应的源码进行二次开发。
一、包概览与运行前提
从 packages/tui/package.json 可以确认当前发布状态:
- 包名
@earendil-works/pi-tui,当前版本0.84.4,MIT 许可,type: module,入口dist/index.js; engines.node为>=22.19.0——这是 0.75.0 版本(2026-05-17)作为破坏性变更提出的最低 Node.js 要求,使用该包需要以此版本为前提;- 运行时依赖只有两个:
marked@18.0.5(Markdown 解析,0.79.5 版本升级至此版本)与get-east-asian-width@1.6.0(东亚字符宽度计算,支撑 CJK/宽字符排版); - 开发依赖
@xterm/headless(VirtualTerminal测试用)与chalk(示例主题着色); - 包内附带
native/win32与native/darwin两套预编译原生模块(prebuilds/**/*.node、C 源码与构建脚本),用于 Windows VT 输入修饰键检测等场景。0.75.5 版本(2026-05-23)把原先可选的koffi依赖替换为这个极小的 vendored native helper,显著减小安装体积同时保留 Shift+Tab 等按键处理;0.84.0 还修复了 npm 包遗漏 Darwin/Windows 原生模块重建所需源码与构建脚本的问题。 - 测试方式为
node --test test/*.test.ts(见 package.json 的test脚本),演示程序为 packages/tui/test/chat-simple.ts,可用npx tsx test/chat-simple.ts运行。
框架的整体能力在 packages/tui/README.md 中概括为:可互换的渲染器(TuiMainScreen / TuiAltScreen)、仅重绘变化行的差分渲染、CSI 2026 同步输出防闪烁、Bracketed Paste(超过 10 行的粘贴生成 [paste #1 +50 lines] 标记)、组件化接口(render(width) 返回行数组)、主题支持、内联图片(Kitty/iTerm2 图形协议)、文件路径与斜杠命令自动补全。变更日志中的绝大多数条目,都是围绕这些核心能力展开的迭代。
二、版本时间线:从按键解析工具到全屏 TUI 框架
变更日志共覆盖约 9.5 周内的 100+ 个版本号。按主题聚类后,演进脉络可分为六个阶段:
| 阶段 | 版本区间 | 时间 | 核心主题 |
|---|---|---|---|
| 1 | 0.29.0 → 0.37.8 | 2025-12-25 ~ 2026-01-07 | 按键检测体系重构(matchesKey 取代 isXxx())、Kitty 键盘协议与按键释放事件、粘贴文件路径自动补空格 |
| 2 | 0.38.0 → 0.49.3 | 2026-01-08 ~ 2026-01-22 | 组件生态成型:EditorComponent 接口、StdinBuffer 批量输入拆分、Overlay 合成与 CSS 式定位、IME 硬件光标、kill ring/undo、fuzzy 匹配、OSC 8 超链接 |
| 3 | 0.50.0 → 0.62.0 | 2026-01-26 ~ 2026-03-23 | 编辑体验打磨:全局键位管理器(破坏性变更)、16ms 帧预算渲染调度、OSC 52/OSC 11 终端查询、CJK/宽字符换行与宽度计算 |
| 4 | 0.63.0 → 0.74.x | 2026-03-27 ~ 2026-05-07 | 多终端兼容性攻坚:Kitty 协议协商、tmux/Zellij 下 modifyOtherKeys 回退、WezTerm/iTerm2 图片放置、Node.js 22.19 门槛 |
| 5 | 0.75.x → 0.83.0 | 2026-05-17 ~ 2026-07-29 | 平台与工具链收敛:vendored 原生模块替代 koffi、PI_TUI_WRITE_LOG 目录模式、宽字符宽度修正 |
| 6 | 0.84.0 → 0.84.4 | 2026-08-06 ~ 2026-08-28 | 备用屏全屏 TUI 大版本:TuiAltScreen 布局/滚动/搜索/选择/滚动条,以及 LaTeX 终端渲染、能力检测的环境与程序化覆盖 |
其中值得完整保留记录的破坏性变更有三处(变更日志中以 Breaking Changes 小节标出):
- 0.33.0(2026-01-04):删除全部
isXxx()按键检测函数(isEnter()、isEscape()、isCtrlC()等),统一改用matchesKey(data, keyId)(如matchesKey(data, "ctrl+c")、"shift+enter"、"alt+left")。这影响所有使用ctx.ui.custom()处理键盘输入的钩子与自定义工具。同期引入Editor.insertTextAtCursor(text)与EditorKeybindingsManager。 - 0.47.0(2026-01-16):
Editor构造函数改为必须接收TUI作为第一个参数:new Editor(tui, theme),以启用内容超过终端高度时的自动垂直滚动(最大高度为终端的 30%,最少 5 行);新增Focusable接口、CURSOR_MARKER常量与isFocusable()类型守卫,用于 IME 候选窗定位。 - 0.61.0(2026-03-20):用单一全局键位管理器替换原“仅编辑器”的键位存储,键位 id 全部加命名空间。完整映射关系如下(
keybindings.json保持向后兼容,每个定义会把新内部 id 映射回原公开配置键):
| 旧 id | 新 id |
|---|---|
cursorUp / cursorDown / cursorLeft / cursorRight |
tui.editor.cursorUp / cursorDown / cursorLeft / cursorRight |
cursorWordLeft / cursorWordRight |
tui.editor.cursorWordLeft / cursorWordRight |
cursorLineStart / cursorLineEnd |
tui.editor.cursorLineStart / cursorLineEnd |
jumpForward / jumpBackward |
tui.editor.jumpForward / jumpBackward |
pageUp / pageDown |
tui.editor.pageUp / pageDown |
deleteCharBackward / deleteCharForward |
tui.editor.deleteCharBackward / deleteCharForward |
deleteWordBackward / deleteWordForward |
tui.editor.deleteWordBackward / deleteWordForward |
deleteToLineStart / deleteToLineEnd |
tui.editor.deleteToLineStart / deleteToLineEnd |
yank / yankPop / undo |
tui.editor.yank / yankPop / undo |
newLine |
tui.input.newLine |
submit / tab / copy |
tui.input.submit / tab / copy |
selectUp / selectDown |
tui.select.up / down |
selectPageUp / selectPageDown |
tui.select.pageUp / pageDown |
selectConfirm / selectCancel |
tui.select.confirm / cancel |
应用侧扩展方式为:通过 TypeScript 声明合并扩展 interface Keybindings,用 TUI 与应用两套定义创建一个管理器,再 setKeybindings(...) 安装。该版本同时修复了用户自定义键位无法遮蔽同键默认绑定的问题。
4. 0.75.0(2026-05-17):最低 Node.js 版本提升至 22.19.0。
三、双渲染器架构:主屏与备用屏
0.84.0(2026-08-06)是变更日志中体量最大的一个版本,它把“备用屏全屏 TUI”推为一等公民。结合源码可以确认其结构:
- 共享
TuiMode类型,主屏/备用屏渲染器各自带mode判别值(对应 packages/tui/src/tui-main-screen.ts 与 packages/tui/src/tui-alt-screen.ts 中的TuiMainScreen、TuiAltScreen两个类,TuiAltScreen的mode为"fullscreen",并实现ViewportTUI接口,可经isViewportTUI()类型守卫判断); - 接口兼容的两种渲染器,应用自持滚动(issue #7304):
TuiMainScreen写入主终端缓冲区、保留终端 scrollback;TuiAltScreen在备用缓冲区维护固定高度视口,退出时恢复主缓冲区并打印完整最终文档; - TUI 生命周期与渲染状态交接 API,支持在不重放主屏内容的情况下替换渲染器;
- 备用屏布局系统:
VStack、HStack与嵌套ScrollView,支持受限尺寸分配、sticky 区域、指针目标化滚动(栈条目支持basis、grow、shrink、minSize、maxSize与响应式visible回调;0.84.0 的 Fixed 条目还记录了“嵌套栈布局忽略子组件最小尺寸”的修复); - 拖选跨屏外滚动视图内容时的边缘自动滚动;比例滚动条(鼠标拖拽、Home/End 文档导航、
auto瞬态模式与预留最右列的always模式,模式可运行时切换); - 视口分页滚动与 OSC 133 语义提示符导航;与垂直光标移动解耦的、可配置的上一/下一提示符历史动作;
- 备用屏渲染器上的堆叠瞬态通知(issue #7361)。
TuiAltScreen 的构造参数在 packages/tui/src/tui-alt-screen.ts 中定义为 TuiAltScreenOptions,变更日志与源码可互相印证其默认值:
export interface TuiAltScreenOptions {
wheelScrollLines?: number; // 每次滚轮事件滚动的逻辑行数(默认 1,0.84.0 从 3 调细)
mouse?: boolean; // 是否捕获鼠标事件(默认 true)
searchMatchStyle?: (text: string) => string; // 非当前搜索命中的样式(默认下划线)
searchCurrentMatchStyle?: (text: string) => string; // 当前命中样式(默认加粗+反色)
openUrl?: (url: string) => void; // 主键点击激活 OSC 8 超链接的回调
onRightClickPaste?: () => void; // 右击粘贴(目前仅在 Windows 启用)
copyOnSelect?: boolean; // 鼠标释放时自动复制选区(默认 true)
copySelection?: (text: string) => Promise<boolean>; // 自定义剪贴板写入,返回 false 会闪错误提示
}
源码中的默认实现(tui-alt-screen.ts):wheelScrollLines = max(1, floor(options.wheelScrollLines ?? 1))、mouse ?? true、searchMatchStyle 默认 \x1b[4m...\x1b[24m(下划线)、searchCurrentMatchStyle 默认 \x1b[1;7m...\x1b[22;27m(加粗反色)、copyOnSelect ?? true。0.84.4 进一步为 copyOnSelect 提供了 getCopyOnSelect()/setCopyOnSelect() 运行时切换,以及 hasActiveSelection()、copyActiveSelectionToClipboard() 等程序化检测/复制当前全屏选区的辅助 API(issue #7720)。
主屏一侧的渲染策略在 packages/tui/src/tui-main-screen.ts 中可直接读到:宽度变化总是全量重渲染(换行结果变化);高度变化通常也全量重渲染,但检测到 Termux 会话时跳过(避免软键盘显隐触发整屏历史重放);常规更新则通过逐行比较找到首末变化行做增量重绘;整个更新被包在 \x1b[?2026h/\x1b[?2026l(synchronized output)之间保证原子刷新。0.84.4 还修复了“图片密集输出超过 V8 字符串长度上限导致主屏渲染崩溃”的问题(issue #8028)。
四、全屏键位体系:从 unbound 动作到可绑定快捷键
0.84.x 连续两个版本为备用屏视口引入了新的“无默认按键”(unbound)动作,供宿主应用自行绑定,这在 packages/tui/src/keybindings.ts 的 TUI_KEYBINDINGS 中都有对应条目:
- 0.84.1:
tui.altScreen.halfPageUp/tui.altScreen.halfPageDown(半屏滚动); - 0.84.2:
tui.altScreen.lineUp/tui.altScreen.lineDown(单行滚动,issue #7903,贡献者 @midastruth)。
连同既有条目,当前备用屏键位空间包括:pageUp/pageDown、previousPrompt/nextPrompt(OSC 133 语义提示符跳转)、search(默认 ctrl+shift+f,见 keybindings.ts)、searchNext(Enter/Ctrl+G)、searchPrevious(Shift+Enter/Ctrl+Shift+G)、searchClose(Escape)、top(默认 home)、bottom(默认 end)。其中增量搜索是 0.84.2 加入的:对主滚动视图内容做可配置样式的匹配高亮,并修复了“手动滚动时搜索位置弹回当前命中”“碎片化 SGR 鼠标输入泄漏进搜索框”两个问题。
0.84.1 还为全屏选择体验补全了编辑器式语义:双击按词/空白选择、粒度感知的拖拽选择、三击按段落选择(issue #7725/#7733,@volsa)。0.84.4 的 Fixed 条目进一步修正了“全屏双击选词在 / 和 - 处错误切分路径与 kebab-case 标识符”(issue #7746)。
键盘协议协商是这条时间线里反复出现的主题,可以按版本回溯其收敛过程:
- 0.37.6(2026-01-06):支持 Kitty 键盘协议 flag 2 的按键释放事件,导出
isKeyRelease(data)、isKeyRepeat(data)与KeyEventType类型; - 0.46.0:Kitty 协议终端下非拉丁键盘布局(俄语、乌克兰语等)的 Ctrl 组合键可正常工作;
- 0.56.3:Kitty 协议不可用时回退到 xterm
modifyOtherKeys模式 2,使 tmux 内的 Shift+Enter/Ctrl+Enter 可用; - 0.60.0:修复 tmux 下
modifyOtherKeys对 Backspace/Escape/Space 的匹配,并按 Windows Terminal 与旧式终端区分处理裸\x08退格歧义; - 0.70.3/0.70.1:Kitty CSI-u + 原始字符叠加导致的重复字符(意大利语布局)、括号粘贴内 CSI-u Ctrl+字母解码问题;
- 0.77.0:键盘协议协商忽略错配或延迟的终端响应,避免误判 Kitty 协议(@mitsuhiko 贡献);
- 0.79.0:Shift+Enter 的 Kitty 协议回退从“超时驱动”改为“响应驱动”,消除间歇性失效(issue #5188)。
与之配套的 SSH 高延迟修复在 0.84.2:经 SSH 传输时被拆成多段的 Alt+Enter 曾被误判为 Escape。修复引入 PI_TUI_ESC_TIMEOUT 环境变量且该超时仅作用于“孤立 Escape 输入”。其实现见 packages/tui/src/terminal.ts:
const DEFAULT_ESCAPE_TIMEOUT_MS = 10;
const DEFAULT_SSH_ESCAPE_TIMEOUT_MS = 100;
export function resolveEscapeTimeoutMs(env: NodeJS.ProcessEnv = process.env): number {
const configured = Number(env.PI_TUI_ESC_TIMEOUT);
if (Number.isFinite(configured) && configured > 0) {
return configured;
}
if (env.SSH_CONNECTION || env.SSH_TTY) {
return DEFAULT_SSH_ESCAPE_TIMEOUT_MS;
}
return DEFAULT_ESCAPE_TIMEOUT_MS;
}
即:显式配置 > 0 时生效;否则检测到 SSH_CONNECTION/SSH_TTY 时放宽到 100ms;本地默认 10ms。
五、编辑器与输入:粘贴、撤销、IME
变更日志中 Editor/Input 组件的迭代密度最高,按主题归并:
- 粘贴标记(paste marker):大段粘贴(>10 行)折叠为
[paste #1 +50 lines]标记。围绕标记的记账逻辑历经多轮修复——0.58.0 将标记视为不可分割的原子段(换行/光标导航不拆散标记);0.80.4 修复标记删除或终端状态清空后的陈旧粘贴状态(issue #6397);0.81.0 修复“删除粘贴标记时撤销注册表损坏”,撤销会连同文本一起恢复粘贴注册表、标记重编号按 id 升序平移注册表条目,提交后的提示词不再残留字面[paste #N ...]文本(issue #6844)。另有 0.29.0 的“粘贴文件路径后自动补空格”(拖拽 macOS 截图场景,@mitsuhiko 贡献)、0.79.0 的“历史导航返回时恢复当前草稿”、0.50.8 的垂直导航 sticky column(优先列恢复)、0.50.6 的“在首/末视觉行按 Up/Down 跳到行首/行尾”、0.50.4 的Ctrl+B/Ctrl+F词导航与Ctrl+]/Ctrl+Alt+]字符跳转。 - kill ring 与 undo:0.49.0 引入 Emacs 式 kill ring(
Ctrl+K删到行尾、Ctrl+Y粘回、Alt+Y弹栈,配合Ctrl+-undo,连续词字符合并为单一 undo 单元,fish 风格);0.52.8 将同样的能力(含Ctrl+Zundo)带到Input组件;Ctrl+D删词前向在 0.50.2 加入。 - IME 硬件光标:0.47.0 起
Editor/Input实现Focusable,TUI 扫描渲染输出中的CURSOR_MARKER(零宽 APC 转义)并把硬件光标定位到该处,供终端的 IME 候选窗定位;0.48.0 起硬件光标默认隐藏(PI_HARDWARE_CURSOR=1开启,取代旧的PI_NO_HARDWARE_CURSOR=1语义),0.49.0 提供showHardwareCursorgetter/setter;0.79.1 修复斜杠命令补全弹出时 IME 光标错位(issue #5283)。 - 宽字符/CJK:0.58.0 一族修复集中处理了 CJK 全角字符下的
Input横向滚动(按视觉列宽严格切分,防溢出与崩溃)、wordWrapLine在宽字符恰好落在换行边界时的溢出、制表符归一化为空格(setText()/粘贴路径);0.74.1 修复泰语 Sara Am/老挝 AM 元音的渲染伪影;0.79.1/0.79.2 修复混排拉丁与 CJK 文本的换行空隙问题(按 grapheme 边界断行)。 - 其他:0.51.4 修复输入滚动切碎 emoji 序列;0.50.2 新增
autocompleteMaxVisible选项(含 getter/setter)控制补全下拉高度;0.50.2 修复带空格路径的引号补全;0.81.0 修复终端关闭时先清除软件光标再恢复硬件光标,避免双光标伪影(issue #6790)。
六、Markdown 与 LaTeX 渲染演进
Markdown 组件的迭代在变更日志中留下了清晰轨迹,解析底座为 marked(0.79.5 固定到 18.0.5,与 package.json 一致):
- 流式渲染:0.79.9 修复流式输出中“部分闭合的代码栅栏导致代码块收缩/闪烁”(issue #5846,@xl0)——这对 agent 流式输出场景至关重要;
- 表格:0.50.2 引入正确的行分隔线与最小列宽(issue #997);0.84.3 修复换行表格内链接的颜色泄漏到边框与相邻单元格(含引用块内表格,issue #8335);
- 引用块:0.56.1 隔离 blockquote 样式防泄漏;0.56.0 修复嵌套列表内容丢失(按块级 token 渲染子节点);0.63.0 修复内联链接后 blockquote 文字色断链;
- 列表:0.44.0 修复代码块打断列表连续性导致所有项显示“1.”;0.74.1 修复任务列表复选框;0.79.2 修复松散列表项之间的空行分隔;0.80.2 保留无序列表源标记,孤立的
+不再渲染成-;0.76.0 提供可选渲染器选项保留有序列表源标记(issue #5013),0.80.3 提供保留源反斜杠转义的选项(issue #6105); - 样式一致性:0.43.0 起每行渲染后重置 ANSI 样式防跨行泄漏;0.62.0 修复标题内联代码后标题样式丢失、H1 下划线样式泄漏到行尾填充(0.65.0);0.67.4 起删除线要求严格
~~text~~双波浪号且非空白边界; - LaTeX:0.84.0 新增“终端友好的 Unicode LaTeX 渲染”——覆盖行内/行间公式、分式、上下标、常用符号、对齐方程、cases 与矩阵;0.84.1 修复关系符/乘号/命名算子的间距,并支持叠分式矩阵、算子极限、相邻矩阵的组合;0.84.2 修复“跨行换行的必填参数被解析为空”(issue #7760)与“控制空格被换行拆开导致整个表达式回退为原始源码”。对应实现为 packages/tui/src/latex.ts 中的
LatexParser与导出的renderLatex(见 packages/tui/src/index.ts)。
七、终端能力检测与内联图片
能力检测(capability detection)与图片协议是 0.84.4 的另一条主线,其源码位于 packages/tui/src/terminal-image.ts(导出 detectCapabilities、setCapabilities、setCapabilityOverrides、resetCapabilitiesCache、hyperlink、Kitty/iTerm2 编解码等,见 index.ts):
- 0.84.4(Added):为 OSC 8 超链接、内联图片协议、truecolor 能力增加环境变量与程序化覆盖入口(issue #8665)。这与导出列表中新增的
setCapabilityOverrides()对应,用于在 CI、嵌入式终端或测试中强制指定能力; - OSC 8 超链接:0.67.6 引入——终端声明支持时为 Markdown 链接渲染可点击超链接,并收紧
detectCapabilities():未知终端默认hyperlinks: false,tmux/screen(含嵌套会话)下强制关闭,防止终端静默吞掉 OSC 8 序列导致 URL 消失;0.70.0 修复换行链接的 BEL 终止符丢失(OAuth 登录 URL 每一行都可点击);0.76.0 使 Windows Terminal 启用 OSC 8、JetBrains 终端启用 truecolor 但禁用 OSC 8(issue #4923/#5037);0.78.0 修复 tmux 透传(客户端支持时,@mpazik 贡献);0.84.0 修复截断宽度后 OSC 8 未闭合(issue #7657); - 图片协议:Kitty 图形协议(Kitty/Ghostty/WezTerm)与 iTerm2 内联图片。典型修复包括:0.74.1 视口高度小于渲染图片时的放置(issue #4461)、0.73.1 图片 id 由终端分配并将解析值限制到合法范围、cmux 终端禁用内联图片、0.79.4 WezTerm 全量重绘回退下的内联图片(issue #5618/#4415)、0.79.7 Warp 终端检测(@dodiego 贡献)、0.84.0 修复 iTerm2 图片 payload 缺失 xterm.js 图片插件所需的尺寸元数据(issue #7612)、备用屏重绘时重复发送 Kitty 图片数据与越界重叠 sticky 区域等;
- 备用屏图片兼容性(README 与变更日志一致):
TuiAltScreen支持 Kitty 协议终端下的内联图片与视口裁剪;iTerm2 协议无法删除既有放置或裁剪源,因此TuiAltScreen在 iTerm2 下将图片组件渲染为文本占位,TuiMainScreen则正常渲染 iTerm2 图片; - OSC 9;4 进度指示:0.69.0 在
Terminal接口新增setProgress(active: boolean);0.70.0 以周期性更新保活,避免 Ghostty 在长任务中清除指示器(issue #3610);0.84.0 修复清除时输出完整 OSC 9;4 序列(issue #7581); - 终端外观查询:0.79.4 支持 OSC 11 背景色查询(issue #5385);0.79.7 增加颜色方案查询/通知 API(
TUI.queryTerminalColorScheme()、Tui.onTerminalColorSchemeChange()、TUI.setTerminalColorSchemeNotifications(),issue #5874),0.84.0 修复批量颜色方案报告被解析成单条畸形响应的问题(issue #7550)。
八、性能与渲染调度的关键节点
变更日志中的性能条目可归纳为四个里程碑:
- 0.42.5(2026-01-11):差分渲染只重绘变化行,减少闪烁(issue #617);
- 0.31.0(2026-01-02):
visibleWidth()重写为基于 grapheme 的宽度计算,Bun 上约 10 倍、Node 上约 15% 提速(@nathyong 贡献);同版本修复 ZWJ emoji(彩虹旗、家庭序列)被拆分为多字符的宽度错误; - 0.65.2(2026-04-06):流式高负载输出下把
requestRender()合并到 16ms 帧预算,同时保留requestRender(true)的立即渲染语义。配套地,0.67.0 为测试套件新增VirtualTerminal.waitForRender()辅助,等待 16ms 节流渲染管线稳定后再断言视口状态; - 0.84.2(2026-08-14):备用屏每帧分配开销降低约 9-18 倍——把整宽布局行作为直接行引用绘制,而非每帧都通过 ANSI/grapheme 分段重新合成每个可见行。
此外还有若干“防栈溢出/防崩溃”的底层修复,体现对超长内容的防御:0.67.0 Container.render() 用循环 push 替换 Array.push(...spread),避免长会话触发 V8 参数上限(issue #2651);0.78.0 修复超长换行行的 ANSI 换行栈溢出(issue #5185);0.62.0 truncateToWidth() 对超大字符串采用流式截断并保持 SGR 样式安全闭合(issue #2447);0.84.4 修复图片密集输出超过 V8 字符串长度上限时主屏渲染崩溃(issue #8028)。
输入侧,0.38.0 引入 StdinBuffer(改编自 OpenTUI,MIT 许可)把 SSH 批处理到达的 stdin 拆分为独立按键序列,解决按键丢失;0.52.12 提供 Terminal.drainInput() 在退出前排空 stdin(最长 1s),防止 Kitty 按键释放事件经慢速 SSH 泄漏到父 shell(issue #1204)。
九、调试环境变量速查
变更日志中沉淀了一组调试/行为开关,均可在源码中核实:
| 环境变量 | 作用 | 默认值 | 源码位置 |
|---|---|---|---|
PI_TUI_WRITE_LOG |
捕获写入 stdout 的原始 ANSI 流;值为文件路径时直接写入该文件,值为已存在目录时按实例生成唯一文件 tui-<时间戳>-<pid>.log(0.63.0 起支持目录,issue #2508,@mrexodia) |
未设置则不记录 | terminal.ts |
PI_DEBUG_REDRAW=1 |
记录全量重绘触发原因到 <logDirectory>/pi-debug.log |
关闭 | tui-main-screen.ts |
PI_HARDWARE_CURSOR=1 |
显示硬件光标(默认隐藏,保留软件光标渲染,0.48.0 起) | 关闭 | tui.ts |
PI_CLEAR_ON_SHRINK=1 |
内容收缩时清屏重绘(0.51.1 起默认关闭,也可用 setClearOnShrink(true) 打开) |
关闭 | tui.ts、tui-main-screen.ts |
PI_TUI_ESC_TIMEOUT |
孤立 Escape 的重组等待毫秒数,用于高延迟/SSH 终端 | 本地 10ms,SSH 会话 100ms | terminal.ts |
相关但属于 coding-agent 层的目录配置也可在日志中找到呼应:0.82.0 修复了调试/崩溃日志总是写到 ~/.pi/agent 的问题,现在会使用已配置的 TUI 日志目录(包括 PI_CODING_AGENT_DIR 指定的位置,issue #6958)。
十、其他值得记录的 API 增量
变更日志中还有不少单点但实用的 API 变化,按版本列出以便检索:
- 0.34.1:键位系统支持 32 个符号键(
SymbolKey类型、Key.backtick、Key.comma等),matchesKey()/parseKey()同步更新; - 0.34.0:
Editor.getExpandedText()返回粘贴标记展开后的真实内容; - 0.37.6/0.37.8:
Component.wantsKeyRelease属性(默认 false)选择接收按键释放事件; - 0.38.0:
EditorComponent接口(自定义编辑器实现入口); - 0.43.0:
fuzzyFilter()/fuzzyMatch()工具,斜杠命令补全由前缀匹配升级为模糊匹配(0.73.0 又让精确匹配在排序上优先); - 0.45.6:
OverlayOptions的 CSS 式定位/尺寸(width/maxHeight/row/col支持数字或"50%"百分比串、minWidth、anchor、offsetX/Y、margin)、visible响应式回调、showOverlay()返回OverlayHandle(hide/setHidden/isHidden),0.57.0 再补nonCapturing非捕获模式与focus()/unfocus()/isFocused()(overlay 合成顺序改为按焦点排序,聚焦者在上); - 0.49.0:
showHardwareCursorgetter/setter; - 0.49.3:
MarkdownTheme.codeBlockIndent(默认 2 空格); - 0.50.0:
PI_TUI_WRITE_LOG首次引入、TUI.fullRedraws只读属性; - 0.52.8:
EditorComponent.pasteToEditor()程序化粘贴; - 0.52.10:
TUI.addInputListener/removeInputListener,允许在组件处理前拦截、转换或消费原始输入; - 0.54.1:koffi 改为动态 require,避免 bun 把全部 18 个平台
.node文件(约 74MB)打进每个编译产物; - 0.58.2:
SelectListLayoutOptions可配置主列尺寸与自定义主标签截断钩子; - 0.60.0:tmux 下
modifyOtherKeys的 Backspace/Escape/Space 修复; - 0.68.0:
LoaderIndicatorOptions与Loader.setIndicator(),支持动画/静态/隐藏三种加载指示(issue #3413); - 0.69.0:
Terminal.setProgress(active)(OSC 9;4);AutocompleteProvider.shouldTriggerFileCompletion?()让扩展包装器获得通用堆叠补全,#成为与@并列的自然补全触发符(issue #2983); - 0.71.0:
ProcessTerminal在回退 80x24 前先读取COLUMNS/LINES(issue #4004); - 0.79.1:
AutocompleteProvider.triggerCharacters,编辑器补全可按 provider 定义的 token 前缀自然触发(issue #4703); - 0.79.4:OSC 11 背景色查询;0.79.7:
sliceByColumn(ANSI 感知的水平列切片)导出; - 0.80.0:
Ctrl+J成为与Shift+Enter并列的默认换行键; - 0.83.0:长图片回退路径在窄终端中溢出、家目录路径缩写、终端支持超链接时绝对路径可点击(issue #7262)。
十一、如何验证与深入阅读
本包为只读仓库,验证方式如下(均从 monorepo 根目录执行,工作目录为 packages/tui):
# 从 monorepo 根安装依赖
npm install
# 类型检查(根目录脚本)
npm run check
# 运行 TUI 包的单元测试(node --test 驱动,含 VirtualTerminal 差分渲染断言)
node --test --test-reporter=dot test/*.test.ts
# 交互式演示:Markdown 消息 + 加载指示 + 自动补全编辑器
npx tsx test/chat-simple.ts
# 抓取原始 ANSI 流用于调试
PI_TUI_WRITE_LOG=/tmp/tui-ansi.log npx tsx test/chat-simple.ts
建议的源码阅读路线(均由变更日志条目反向定位):
- 渲染核心:packages/tui/src/tui.ts(
TUI/Container/Focusable/OverlayHandle等共享类型与基类)、tui-main-screen.ts(三种主屏渲染策略与 16ms 节流)、tui-alt-screen.ts(视口滚动、选择、搜索、滚动条); - 布局:v-stack.ts、h-stack.ts、scroll-view.ts;
- 输入链路:terminal.ts(
ProcessTerminal、Kitty 协议协商、ESC 超时)、stdin-buffer.ts、keys.ts(Key/matchesKey/parseKey/decodeKittyPrintable)、keybindings.ts(命名空间化键位与tui.altScreen.*动作); - 能力与图片:terminal-image.ts、terminal-colors.ts;
- 富文本:markdown.ts(含
StrictStrikethroughTokenizer)、latex.ts。
十二、小结
从 packages/tui/CHANGELOG.md 的九个半月迭代史可以看到一条清晰的主线:pi-tui 从“按键解析 + 组件渲染”的底层工具,逐步长成具备双渲染器(主屏/备用屏)、应用自持滚动视口、模糊搜索、鼠标选择复制、LaTeX/Markdown 富文本与多终端能力协商的完整 TUI 框架。变更日志中每条记录都能在 packages/tui/src 中找到对应实现——从 TuiAltScreenOptions 的默认值、resolveEscapeTimeoutMs() 的 SSH 分支,到 TUI_KEYBINDINGS 中的 tui.altScreen.* 动作表——这使得该文档不仅是发布说明,更是一份可溯源的 API 演进索引。升级该包时,建议重点核对 0.33.0、0.47.0、0.61.0、0.75.0 四个破坏性变更点的迁移要求,以及你所在终端环境(tmux、WezTerm、iTerm2、Windows Terminal)对应的能力检测修复版本。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0627
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00