# pi-pretty-tui

[English](./README.md) | 简体中文

为 [Pi coding agent](https://pi.dev/) 打造美观、精致的 TUI 体验。

## 功能特性

- **可折叠的活动时间线：** 不再让大量独立调用填满对话。思考、工具和普通 `info` 通知会进入同一条按真实时间排序的活动流；工作进行时显示为 `Running(...)`，结束后变为低调的 `Done(...)`。父级合并统计顶层与嵌套工具调用总数，并单独显示思考数量；展开后可查看所有有序成员，成员摘要在展开嵌套详情后仍然保留。思考与工具地位相同：没有调用任何工具的那一轮同样会有自己的 `Running(1 thought)` / `Done(1 thought)` 父行，思考作为其子级，内容不会被丢弃。
- **可持久化的回答 footer：** 整轮 Agent 工作真正 settled 后（包括工具、自动重试和 compaction），最终回答底部会显示一条低调的灰色分隔线，工作时长与 fullscreen 模式下的 `[Copy]` 控件都嵌在线中。`[Copy]` 只复制最终可见回答，不包含 thought、工具、状态或 footer；reload 和 session tree 切换后仍会保留。
- **实时工作计时：** 三种模式下，耗时显示在输入框顶部边框的 `Working` 右侧，颜色与边框一致。它与完成 footer 共用 Agent 整轮工作的计时起点和时长格式，包含自动重试，工作真正结束后消失；窄输入框放不下时会隐藏计时。clean 模式下，`Running` 父节点圆点约每 800 ms 在输入框当前边框色和 `dim` 间切换；`Running` 文字使用相同边框色，工具圆点保持稳定，整轮结束后停止闪烁。展开后的 `Done` 标题和圆点使用主题的 `success` 色，折叠摘要的圆点、标题与内容统一使用 `dim`。
- **临时 UI 状态：** 编辑器上方的一行只显示 Pi 直接产生的 UI 操作反馈，例如 Thinking 或工具输出可见性变化。新状态会替换旧状态，并在十秒后自动消失，不进入 transcript 或 session。
- **按需查看有效信息：** 针对不同工具设计的摘要，会简洁呈现路径、命令、结果、diff、文件预览和实时 shell 输出，同时保留查看原始完整内容的能力。
- **统一、精致的视觉体验：** 用户消息使用主题标题色（`mdHeading`，默认暖黄/琥珀色）的圆角边框，与蓝色 `mdLink` 思考区分。full 和 compact 使用带底色、铺满宽度的 `User` 面板，与 Assistant 卡片一致；clean 保留透明、右对齐、自适应宽度的气泡，长消息在终端宽度的 75% 处换行，不显示 `User` 标注。配合圆角输入框、主题感知配色、层级清晰的 Markdown 标题、更清爽的列表，以及带语法高亮的圆角代码块，让整个 TUI 更协调。在 fullscreen 模式下，每个围栏代码块还带有符合原生体验的 `[Copy]` 控件。

clean 中，Pi 内置的 `read`、`bash`、`edit`、`write`、`grep`、`find` 和 `ls` 工具使用专门设计的紧凑视图；compact 折叠时显示简短摘要，展开后与 full 共用原生详情卡片。没有嵌套调用的第三方工具会自动获得统一的紧凑行，单独展开时继续使用原生 renderer，但会移除与整体冲突的终端背景色。用户与 steer 消息、compaction 摘要、可见 assistant 正文、warning、error、aborted/length 响应，以及注册了专用 renderer 的 displayed custom message 都会形成硬分组边界。同时不会影响 Pi 原有的光标、输入法、自动补全和工具执行行为；fullscreen 鼠标交互增强见下文。

## 安装

```sh
pi install npm:pi-pretty-tui
```

安装后重启 Pi，或运行 `/reload`。

Pi 可能会提示内置工具被覆盖。这是正常现象：pi-pretty-tui 会重新注册 Pi 的内置工具，并将实际执行委托给原始实现，只修改它们的 TUI 渲染方式。

## 使用工具调用

点击 `Running(...)` 或 `Done(...)` 行，可以保留父级并展开其下方的工具、已完成的 `● thought` 和扩展更新。点击单个工具或思考子项可在保留摘要的同时展开嵌套详情。每棵展开的树末尾都有 `└─ [↑ Collapse]`，无需滚回父级即可只折叠当前分组；再次点击父级也可以折叠。clean 模式下，`Ctrl+O` 只提示使用这些局部展开入口，不会展开或收起内容；full 和 compact 模式保留 Pi 原生的工具输出全局展开行为。第三方替换的 `grep`、`find`（如 FFF）也使用紧凑的树节点，展开子项时仍可查看原生详情。紧凑工具名使用 `text` 加粗，参数使用 `muted`，运行中工具圆点使用 `dim`，成功/失败圆点保留对应主题色。思考圆点使用 `mdLink`，标题使用 `text` 加粗，详情正文使用 `muted`。工具名称会原样使用定义中的 `label`，没有 `label` 时回退到原始 `name`；pi-pretty-tui 不再重命名或转换大小写。

clean 和 compact 中，扩展调用 `ctx.ui.notify(message, "info")`（或省略 type）使用相同展示：clean 加入当前 thought/tool 活动组，compact 独立显示。warning 和 error 保持独立，使用 `⚠` 和 `✕` 并形成硬边界；工具失败归属于对应工具详情。full 将 info、warning、error 的投递委托给 Pi 原始方法，保留其文案、每次独立出现及状态行为。

在 clean 模式下，Pi 原生的 cache miss 提示以黄色 `⚠` 子节点加入产生该次缓存未命中的 assistant 消息所属的 thought/tool 活动组，随组折叠与展开，并且不会打断后续工具调用。如果该消息没有关联的工作（例如只输出正文的最终回答），提示保持独立。是否显示提示，以及 token 数、成本、模型切换和空闲时长等文案仍由 Pi 决定；接管的是 `addCacheMissNotice()` 入口，不匹配文本。历史提示在重建时重新推导，不额外写入会话记录。full 和 compact 使用相同的警告展示，独立显示，不包裹活动组。

clean 和 compact 下，没有自有 renderer 的 displayed custom message 使用统一、accent 配色的 `◇` Markdown 显示：当前存在 thought/tool 工作时加入当前组，否则独立显示，并保留 session 持久化。注册了 renderer 的消息完全保留插件原生显示并形成硬边界。full 同样保留 custom message 的原生展示。所有判断只依据 Pi 的通知 type 和 renderer 是否存在，不识别扩展名称、custom message 名称，也不根据文本内容推断语义。

clean 和 compact 中，Pi 内部直接调用 `showStatus()` 产生的反馈属于临时 UI 状态：它只显示在编辑器上方，新状态替换旧状态，并由十秒 timer 自动清除；它不会进入 transcript 或活动时间线，reload 时也会清除。在 clean 模式下，`Ctrl+T` 和 `Ctrl+O` 都只显示点击对应节点的简短提示，不改变内容可见性或 Pi 的 Thinking 设置。在 full 和 compact 模式下，两者保留 Pi 的原生行为。full 也保留原生 `showStatus()` 投递，不使用十秒 timer 删除 transcript 中的状态反馈。

即使同一消息的后续更新才加入思考，可见 assistant 正文也保持在活动树之外；重复更新不会关闭后续独立的工具活动组。

`read` 行范围标签正确处理数字字符串及省略/null 参数，不再拼接出错误行号；无效范围值不显示范围标签。展开的 `edit` diff 使用固定宽度、右对齐的左侧行号栏，`+`/`-` 独占一列；长代码续行与正文列对齐，保留代码缩进及主题 diff 配色。

## 错误展示

clean 和 compact 模式下，独立错误保留原始标题和完整内容，以紧凑的 `✕ Error · 原因` 展示。来源类型、标题及完整内容完全一致的相邻错误合为一条可见行，并使用暗色 `×2` / `×3` 标识次数。其他 transcript 组件会打断计数；包含思考、工具或可见回答的错误不参与合并。合并仅影响 UI，不删除或修改会话记录及原始消息组件。长错误完整换行，不增加预览截断；full 保留原生 assistant 错误文案及每次独立出现，不将它们合并为重复计数。

## Codemode 与嵌套工具

clean 和 compact 模式共用嵌套工具展示。通过 Pi 嵌套执行 API 调用其他工具的工具保留自己的父节点；clean 模式先展开活动组，compact 模式直接显示独立的父子调用树，不包裹活动组。两者都会显示各内部调用的状态、紧凑参数、耗时和结果摘要；点击某个内部调用，可以独立展开其参数和文本结果；点击展开后的正文可收起该调用，脚本和脚本输出正文也可点击收起各自区块。工具统一使用 `●` 圆点：运行中为主题暗色，成功与失败分别为主题成功色与错误色；工具名使用正文色加粗。`[Script]` 和 `[Script output]` 分别控制脚本与汇总输出；嵌套父工具标题仅用于展示，点击不会展开或折叠详情。各区块或子调用通过自己的入口独立展开/收起，`Ctrl+O` 在 clean 模式下只显示提示。扩展仍可通过 Pi 的 `setToolsExpanded()` API 全局控制，之后也可局部展开/收起；再次调用全局 API 会重置局部状态。并行调用按照启动顺序排列，不会随完成顺序跳动。即使脚本捕获错误后成功，失败的子调用仍会明确标记。

活动组摘要合并统计顶层与嵌套调用：一个父调用加三个内部调用显示为 `4 tool calls`，父调用本身也计一次；父工具节点仍保留子调用数量和树结构。内部调用不会变成不存在的顶层 transcript 成员，也不会挤掉树尾折叠按钮。归属依据 Pi 的 `parentToolCallId`，不依赖工具名或 JavaScript 源码解析，因此其他嵌套调用工具也适用。这需要支持嵌套执行事件的 Pi（0.99.0 及以后）；旧版本保持原有显示。full 在工具卡片内使用 codemode 自己的原生 renderer，不额外追加 pretty-tui 快照中保存的子调用详情；可见信息、展开折叠及快捷键行为跟随 Pi。clean 和 compact 共用嵌套执行状态、历史快照、状态处理与子项局部展开逻辑；全局展开操作会重置它们的局部覆盖。

子工具的文本结果和 edit diff 会存入隐藏的、仅用于 UI 的 session 条目，支持 reload 和会话分支恢复。每个父调用最多保留 256 个子调用，每项参数最多 4,096 字符，每项文本结果最多 8,192 字符，参数和结果合计最多 131,072 字符；截断会明确提示。每项展开预览还设有 200 行上限，嵌套树最多展示父调用以下八层。没有快照的旧会话会明确显示仅保留调用记录。目前子结果使用通用文本视图，不调用各第三方工具的 renderer，也不在快照中保存图片；父工具自身的媒体结果与原生 renderer 仍可在 full 模式查看。

这些 UI 条目不会修改脚本输出或模型收到的工具结果，但**会保存脚本可能未打印的子工具文本**，因此请将 session 文件视为可能含有敏感信息。常见凭证参数键会被遮盖，工具输出则不保证已清除所有敏感内容。

## 设置与渲染模式

运行 `/pretty-tui` 可打开扩展设置。`Enabled` 开关会持久化控制 pi-pretty-tui 是否安装渲染补丁和内置工具 renderer。修改后会自动调用 Pi 官方的 reload 流程，无需手动执行 `/reload`。也可以直接使用 `/pretty-tui enable` 和 `/pretty-tui disable`。禁用期间设置命令仍然可用，Pi 会恢复原生渲染。

三种模式保留输入框工作计时、回答 footer 和复制增强；clean/compact 使用临时状态反馈，full 保留原生状态投递。clean 将 `● thought` 放在活动组内。compact 使用独立思考卡片，默认折叠并预览第一行思考内容（超宽时以省略号截断为一行），标题显示 `▸`，点击标题展开 Markdown 详情后显示 `▾`。full 保留原生思考段、与正文的原始顺序、Markdown transform 和逐段点击，并为每个思考段加上左上角带名称的边框。full 中思考默认展开，不因已有 compact/原生隐藏设置而初始折叠；手动收起及后续 `Ctrl+T` 可见性切换继续生效。

full 以原生 Pi 的信息和行为为准，统一使用带主题底色的面板。User、Assistant、思考和工具面板的底色从对应边框的主题色派生。深色主题保留色相并显著降低亮度和饱和度，蓝、紫、绿、红边框对应同色系深底色，Assistant 中性边框对应深灰底色；浅色主题使用同色系浅底色，保证原生深色文字可读。标题、边框和底边耗时保留语义配色，颜色转换使用缓存并跟随主题及终端色彩模式变化。原生内容中的前景语法/diff 配色继续保留，ANSI reset 后会恢复面板底色，图片协议行保持原样。

full 和 compact 面板左右各保留一个字符的外侧留白，极窄终端取消；留白保持终端背景，统一应用于 User、Assistant、思考和工具面板。

每个工具只有一张占满剩余宽度的面板：调用在上，原生可见结果在下，中间以 `Output` 分隔线区分。不再使用独立结果卡片、连接线或结果缩进；无可见结果时不添加输出占位。去掉边缘布局空白，保留内部空行与图片占位；不同工具之间保留两行留白。User 面板铺满宽度，左上角显示 `User`；相邻正文块合并为默认展开的 Assistant 卡片；思考默认展开，保留局部及原生可见性控制。

内置工具使用 Pi 官方 renderer，保留预览、截断/展开入口及错误详情。full 模式的 bash 命令额外使用 Pi 的 shell 语法高亮，区分变量、字符串、关键字和注释，并按命令与语法配色缓存；原生 `$` 提示符、命令原文、超时标注和结果输出保持不变。shell/codemode 原生 `Took`/`Elapsed` 保留在底边框且与边框同色；窄面板放不下时保留原生正文计时。第三方 renderer、媒体数据和原生鼠标交互继续保留。clean 保留活动分组与透明用户气泡。compact 共用面板底色、边框配色、留白及 User/Assistant 卡片，工具默认只显示参数和结果摘要，独立工具卡片标题用 `▸` 表示折叠、`▾` 表示展开，点击标题切换详情，`Ctrl+O` 保留原生全局展开。User/Assistant 和仅用于展示的嵌套父工具标题不添加折叠箭头。独立工具展开后与 full 共用原生 renderer 和卡片投影，包括命令高亮、输出分界及原生耗时，不再带 compact 的树状连接线和结果缩进；嵌套工具保留脚本、输出和子项的局部展开。Pi 提供最终耗时时，compact 在边框显示 `Took`，缺失时不猜测。极窄终端省略边框但保留面板底色。

扩展支持三种可持久化的渲染模式：`clean`（默认）、`compact` 和 `full`。可交互选择，也可以直接使用 `/pretty-tui clean`、`/pretty-tui compact`、`/pretty-tui full` 和 `/pretty-tui status`。设置会保存到 `~/.pi/agent/pretty-tui.json`，或 `PI_CODING_AGENT_DIR` 指定目录中的对应位置。

| 模式 | 第三方工具 | codemode 等嵌套调用工具 |
|---|---|---|
| `clean` | 活动组中的紧凑摘要，展开查看原生详情 | 活动组内的嵌套树，各区块局部展开 |
| `compact` | 独立紧凑面板，点击标题查看原生详情 | 卡片内的独立父子树，脚本、输出及子项按需展开 |
| `full` | 原生内容与交互，外加标题卡片 | 标题卡片内的原生 codemode 内容与展开控件，不额外添加快照详情 |

full 和 compact 保留 Pi 原生的 `Ctrl+O` 全局展开，之后仍可局部控制共享展示中的各子项；这两种模式不生成 clean 的 `Running/Done` 活动组外壳。

fullscreen 模式下，活动树/工具交互行与复制入口允许同一行左右最多两个终端字符格的鼠标抖动；更大偏移或跨行移动仍按拖动处理。普通文本选择、链接和 Pi 的双击/三击行为保持不变。

compact 和 full 中，压缩摘要使用主题配色的 `compaction ▸/▾` 卡片，保留原始 token 数、快捷键提示和完整摘要；点击标题/正文或使用原生 `Ctrl+O` 切换展开。压缩费用提示仍独立显示，clean 保留 Pi 原生压缩消息样式。

## 复制用户消息

fullscreen 模式下，左键点击用户气泡的正文或边框，可复制完整原始文本，保留 Markdown、缩进和换行，不包含气泡边框。已有链接和代码块 `[Copy]` 控件保留优先级；拖动选择文本不会触发整条复制。复制使用 Pi 原生剪贴板路径及反馈，只复制文本，不复制图片附件。regular 模式保留终端自身的鼠标选择与复制行为。

## 复制代码块

代码块的圆角与线条使用 `borderMuted`，语言标签、`[Copy]` 和代码正文保持原有配色。

在 fullscreen TUI 模式下，用户消息与助手回复中的 Markdown 围栏代码块会在顶部边框显示可点击的 `[Copy]` 控件：

```sh
pi --tui-mode fullscreen
```

点击后只复制代码内容，不包含圆角边框；复制会通过 Pi 原生的 fullscreen 剪贴板路径完成，并显示与直接框选文本相同的临时 `Copied!` 或 `Copy failed` 提示。regular TUI 模式下，终端会保留鼠标输入用于文本选择和滚动，因此该控件会被隐藏。

## 开发

修改渲染状态或 transcript 分组前，请运行仓库内的回归测试：

```sh
npm install
npm test
```

测试覆盖实时与历史恢复的活动时间线、自动重试与终止状态、用户/steer/compaction/原生 renderer 边界、十秒 UI 状态替换、reload 与 shutdown 时的旧 timer 与状态清理、独立严重级别样式、内置与第三方工具、可展开思考、并行工具完成归属、孤立 tool call、重复摘要防护、可持久化的工作时长与仅回答复制控件、自适应用户聊天气泡、原型补丁的完整恢复，以及 fullscreen 代码块复制的点击区域。GitHub Actions 会在每次 push 和 pull request 时运行相同检查。

## 兼容性说明

当前开发与回归测试基线为 **Pi 1.3.0**。用户气泡已适配该版本直接使用 Markdown 的布局，full/compact 使用带底色、铺满宽度的 User 面板，clean 使用透明、按内容自适应的气泡。嵌套执行需要 Pi 0.99.0 及以后；这是功能要求，不代表每个旧版都经过测试。

工具渲染使用 Pi 的公开扩展 API。活动工具状态通过 Pi 导出的交互组件跟随其内置执行状态变化；clean 模式的 thought 详情使用活动时间线自身的展开状态，full 和 compact 模式则保留 Pi 内置的 Thinking 可见性控制。由于 Pi 目前没有为这些展示细节提供公开渲染钩子，自适应的原生用户消息气泡、原生输入编辑器圆角、无序列表标记和围栏代码块增强需要使用可安全重载的运行时补丁。Markdown 增强仅在渲染主 transcript 中的用户消息和助手回复时启用；扩展 overlay 创建的 Markdown 保持 Pi 原生布局。Markdown 解析、语法高亮和终端语义区域仍由 Pi 处理。

本扩展不会修改 Pi 源文件。运行时补丁会在会话关闭时移除，但未来的 Pi 版本可能需要本扩展同步适配。

## 卸载

```sh
pi remove npm:pi-pretty-tui
```

然后重启 Pi。

## 许可证

MIT
