pi-one-ui 0.9.0 → 0.9.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 +24 -1
- package/LICENSE +1 -1
- package/README.en.md +12 -10
- package/README.md +12 -10
- package/THIRD-PARTY-NOTICES.md +98 -0
- package/extensions/app/config/renderer.ts +1 -1
- package/extensions/app/config/shell.ts +5 -5
- package/extensions/app/runtime/tui-runtime.ts +6 -6
- package/extensions/app/settings/controller.ts +1 -1
- package/extensions/layouts/overlay/settings-panel.ts +9 -8
- package/extensions/layouts/overlay/settings-previews.ts +1 -1
- package/extensions/layouts/{context → transcript}/index.ts +8 -8
- package/extensions/layouts/{context → transcript}/renderer/compact-mode.ts +4 -4
- package/extensions/layouts/{context → transcript}/renderer/default-mode.ts +37 -7
- package/extensions/layouts/{context → transcript}/renderer/index.ts +8 -8
- package/extensions/layouts/{context → transcript}/renderer/mouse/interaction.ts +2 -2
- package/extensions/layouts/{context → transcript}/renderer/tool/message-display.ts +1 -1
- package/extensions/layouts/{context → transcript}/renderer/tool/names.ts +19 -2
- package/extensions/layouts/{context/renderer/context-refresh.ts → transcript/renderer/transcript-refresh.ts} +6 -6
- package/extensions/layouts/{context → transcript}/thinking/compact-thinking.ts +4 -4
- package/extensions/tools/component-tree.ts +1 -1
- package/package.json +3 -2
- /package/extensions/app/config/{context.ts → user-messages.ts} +0 -0
- /package/extensions/layouts/{context → transcript}/message/user-message-osc.ts +0 -0
- /package/extensions/layouts/{context → transcript}/message/user-message-styles.ts +0 -0
- /package/extensions/layouts/{context → transcript}/message/user-message.ts +0 -0
- /package/extensions/layouts/{context → transcript}/renderer/markdown-enhance.ts +0 -0
- /package/extensions/layouts/{context → transcript}/renderer/mouse/hover.ts +0 -0
- /package/extensions/layouts/{context → transcript}/renderer/mouse/layout.ts +0 -0
- /package/extensions/layouts/{context → transcript}/renderer/mouse/packets.ts +0 -0
- /package/extensions/layouts/{context → transcript}/renderer/mouse/scroll.ts +0 -0
- /package/extensions/layouts/{context → transcript}/renderer/tool/diff/ATTRIBUTION.md +0 -0
- /package/extensions/layouts/{context → transcript}/renderer/tool/diff/ansi-utils.ts +0 -0
- /package/extensions/layouts/{context → transcript}/renderer/tool/diff/diff-component.ts +0 -0
- /package/extensions/layouts/{context → transcript}/renderer/tool/diff/diff-edit-render.ts +0 -0
- /package/extensions/layouts/{context → transcript}/renderer/tool/diff/diff-header.ts +0 -0
- /package/extensions/layouts/{context → transcript}/renderer/tool/diff/diff-highlight.ts +0 -0
- /package/extensions/layouts/{context → transcript}/renderer/tool/diff/diff-inline.ts +0 -0
- /package/extensions/layouts/{context → transcript}/renderer/tool/diff/diff-layout.ts +0 -0
- /package/extensions/layouts/{context → transcript}/renderer/tool/diff/diff-limits.ts +0 -0
- /package/extensions/layouts/{context → transcript}/renderer/tool/diff/diff-palette.ts +0 -0
- /package/extensions/layouts/{context → transcript}/renderer/tool/diff/diff-parse.ts +0 -0
- /package/extensions/layouts/{context → transcript}/renderer/tool/diff/diff-presentation.ts +0 -0
- /package/extensions/layouts/{context → transcript}/renderer/tool/diff/diff-renderer.ts +0 -0
- /package/extensions/layouts/{context → transcript}/renderer/tool/diff/diff-text.ts +0 -0
- /package/extensions/layouts/{context → transcript}/renderer/tool/diff/diff-write-render.ts +0 -0
- /package/extensions/layouts/{context → transcript}/renderer/tool/diff/index.ts +0 -0
- /package/extensions/layouts/{context → transcript}/renderer/tool/diff/line-width-safety.ts +0 -0
- /package/extensions/layouts/{context → transcript}/renderer/tool/diff/shiki-highlight.ts +0 -0
- /package/extensions/layouts/{context → transcript}/renderer/tool/diff/write-execution.ts +0 -0
- /package/extensions/layouts/{context → transcript}/renderer/tool/grouping.ts +0 -0
- /package/extensions/layouts/{context → transcript}/renderer/tool/result.ts +0 -0
- /package/extensions/layouts/{context → transcript}/renderer/tool/show-more-hint.ts +0 -0
- /package/extensions/layouts/{context → transcript}/renderer/tool/toggle-render-cache.ts +0 -0
- /package/extensions/layouts/{context → transcript}/summary/core.ts +0 -0
- /package/extensions/layouts/{context → transcript}/summary/index.ts +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,22 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [0.9.1] - 2026-10-05
|
|
10
|
+
|
|
11
|
+
### Changed
|
|
12
|
+
|
|
13
|
+
- Rename the `/oneui` settings section from `Context` to `Transcript`. Names that refer to the model context window are unchanged: the `/context` command, the Context Inspector, the Footer `context` segment with `contextStyle` and `contextThresholds`, and the `context*` color keys. No configuration key, command, or stored value changes.
|
|
14
|
+
|
|
15
|
+
### Fixed
|
|
16
|
+
|
|
17
|
+
- Show the complete command on an expanded tool card while the tool call is still running. Ctrl+O and mouse expansion now wrap the full input against the viewport width instead of clipping it to `renderer.toolInputNameLength`, so long bash commands stay readable during execution; embedded line breaks in multi-line commands are preserved. Collapsed cards and settled cards keep the truncated title line, and settled cards still list the full input in the expanded `Input` section.
|
|
18
|
+
|
|
19
|
+
### Migration
|
|
20
|
+
|
|
21
|
+
- No configuration migration is required. Existing canonical v1 files and command names remain supported.
|
|
22
|
+
- The `/oneui` settings section previously labeled `Context` is now `Transcript`; the `/context` command and the Context Inspector keep their names. No configuration key or stored value changes.
|
|
23
|
+
- For an unpinned npm installation, run `pi update npm:pi-one-ui`; for an existing version pin, run `pi install npm:pi-one-ui@0.9.1`. Fully exit and restart Pi after updating the package.
|
|
24
|
+
|
|
9
25
|
## [0.9.0] - 2026-10-02
|
|
10
26
|
|
|
11
27
|
### Changed
|
|
@@ -23,6 +39,12 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
|
23
39
|
- The fullscreen "Back to bottom" button and its `Ctrl+End` binding are gone. Use the official `End` shortcut and the restyled end-of-transcript indicator instead.
|
|
24
40
|
- For an unpinned npm installation, run `pi update npm:pi-one-ui`; for an existing version pin, run `pi install npm:pi-one-ui@0.9.0`. Fully exit and restart Pi after updating the package.
|
|
25
41
|
|
|
42
|
+
### Release verification
|
|
43
|
+
|
|
44
|
+
- Release source: [`bd915d1`](https://github.com/kerolt/pi-one-ui/commit/bd915d1376486a2aa6c21626f645893e99e29791). [CI](https://github.com/kerolt/pi-one-ui/actions/runs/36949089996) and [Publish](https://github.com/kerolt/pi-one-ui/actions/runs/36949089612) completed successfully; local `npm run verify` passed 1,190 tests across 69 files, and `npm run pack:check` confirmed 124 package files.
|
|
45
|
+
- npm `latest` resolves to `0.9.0`, published `2026-10-02T01:05:39.420Z` with `gitHead` `bd915d1376486a2aa6c21626f645893e99e29791`, package SHA-1 `c354b2f6eafb4e2fe00c915ec43925d0304918dc`, integrity `sha512-uipQsMexnSRrB/7fNPNotgsjsHuHMRwLKtgRrp9EmmfoPaYJhtkrMZ+CPkBiXlHqt63sDfHVgcSvp/5rvA5GvQ==`, and a published provenance statement (SLSA v1).
|
|
46
|
+
- Real Pi fullscreen TUI probes were not run for this release (no TTY), so terminal, theme, and reload combinations still require manual verification.
|
|
47
|
+
|
|
26
48
|
## [0.8.0] - 2026-09-30
|
|
27
49
|
|
|
28
50
|
### Changed
|
|
@@ -223,7 +245,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
|
223
245
|
|
|
224
246
|
- Reduced rendering lag when expanding settled tool groups by reusing cached child output.
|
|
225
247
|
|
|
226
|
-
[Unreleased]: https://github.com/kerolt/pi-one-ui/compare/v0.9.
|
|
248
|
+
[Unreleased]: https://github.com/kerolt/pi-one-ui/compare/v0.9.1...HEAD
|
|
249
|
+
[0.9.1]: https://github.com/kerolt/pi-one-ui/compare/v0.9.0...v0.9.1
|
|
227
250
|
[0.9.0]: https://github.com/kerolt/pi-one-ui/compare/v0.8.0...v0.9.0
|
|
228
251
|
[0.8.0]: https://github.com/kerolt/pi-one-ui/compare/v0.7.2...v0.8.0
|
|
229
252
|
[0.7.2]: https://github.com/kerolt/pi-one-ui/compare/v0.7.1...v0.7.2
|
package/LICENSE
CHANGED
package/README.en.md
CHANGED
|
@@ -20,11 +20,11 @@ The result is a single installable and configurable Pi package that continues to
|
|
|
20
20
|
`pi-one-ui` organizes the Pi interface into a clean hierarchy:
|
|
21
21
|
|
|
22
22
|
```text
|
|
23
|
-
Header →
|
|
23
|
+
Header → Transcript → WorkingLine → Editor → Footer
|
|
24
24
|
```
|
|
25
25
|
|
|
26
26
|
- **Header**: Startup information, logo, and shortcut hints.
|
|
27
|
-
- **
|
|
27
|
+
- **Transcript**: Conversation content area, including user messages, assistant messages, thinking blocks, tool calls, diffs, Markdown, and turn summaries.
|
|
28
28
|
- **WorkingLine**: Working state indicator, spinner, token/thought/elapsed statistics, live output throughput, and turn summaries.
|
|
29
29
|
- **Editor**: Input editor, completion menu, metadata display, and the Minimalist style (with effortless toggle to Pi native).
|
|
30
30
|
- **Footer**: Current directory, Git status, runtime info, token/cost tracking, and extension statuses.
|
|
@@ -34,7 +34,7 @@ Header → Context → WorkingLine → Editor → Footer
|
|
|
34
34
|
|
|
35
35
|
| Feature | Description | Entry point |
|
|
36
36
|
| ---------------------- | ------------------------------------------------------------------------------------------- | ----------------- |
|
|
37
|
-
| Unified settings panel | Centrally manages settings for Header,
|
|
37
|
+
| Unified settings panel | Centrally manages settings for Header, Transcript, WorkingLine, Editor, Footer, and Features | `/oneui` |
|
|
38
38
|
| Context Inspector | Shows context usage and previews system prompt, memory, skills, tools, and message contents | `/context` |
|
|
39
39
|
| Session reference | Searches previous Pi sessions or subagents and injects their relevant context | `@` completion |
|
|
40
40
|
| Subagent autocomplete | Provides subagent name completion and delegation hints | `@` completion |
|
|
@@ -76,9 +76,11 @@ Then open the unified settings panel:
|
|
|
76
76
|
/oneui
|
|
77
77
|
```
|
|
78
78
|
|
|
79
|
-
### Upgrading to 0.9.
|
|
79
|
+
### Upgrading to 0.9.1
|
|
80
80
|
|
|
81
|
-
This release
|
|
81
|
+
This release fixes truncated commands on expanded tool cards: a pending card now wraps the complete command against the terminal width after Ctrl+O or a mouse click, preserving line breaks in multi-line commands, while collapsed cards and settled cards keep the truncated title line and settled cards continue to list the full input in the Input section. The `/oneui` settings section previously labeled `Context` is now `Transcript`; names that refer to the model context window stay unchanged (the `/context` command, the Context Inspector, the Footer `context` segment and `context*` color keys), and no configuration key, command, or stored value changes.
|
|
82
|
+
|
|
83
|
+
Users upgrading from 0.8.x also need the 0.9.0 migration: `renderer.scrollStepLines` is gone and wheel stepping is controlled by Pi's own `fullscreenWheelScrollLines` setting in `~/.pi/agent/settings.json` (an integer such as `3`, or `"auto"`), a leftover `scrollStepLines` key is ignored and preserved on save, and the fullscreen "Back to bottom" button with its `Ctrl+End` binding is removed in favor of the official `End` shortcut and indicator.
|
|
82
84
|
|
|
83
85
|
For an unpinned npm installation, run:
|
|
84
86
|
|
|
@@ -86,7 +88,7 @@ For an unpinned npm installation, run:
|
|
|
86
88
|
pi update npm:pi-one-ui
|
|
87
89
|
```
|
|
88
90
|
|
|
89
|
-
If your installation pins a version, run `pi install npm:pi-one-ui@0.9.
|
|
91
|
+
If your installation pins a version, run `pi install npm:pi-one-ui@0.9.1` to update the pin. Fully exit and restart Pi after updating the package.
|
|
90
92
|
|
|
91
93
|
## Configuration
|
|
92
94
|
|
|
@@ -165,9 +167,9 @@ To keep the configuration section clean and focused, in-depth options, template
|
|
|
165
167
|
| Upstream project | Capabilities incorporated into `pi-one-ui` | Reference baseline |
|
|
166
168
|
| --------------------------------------------------------------- | ------------------------------------------------------------------------------------------ | ------------------------- |
|
|
167
169
|
| [pi-zentui](https://github.com/lmilojevicc/pi-zentui) | Starship-style Footer, Editor layouts, and shell interaction capabilities | v0.21.0, commit `5341b38` |
|
|
168
|
-
| [pi-cc-extensions](https://github.com/minuque/pi-cc-extensions) | Claude Code-style
|
|
170
|
+
| [pi-cc-extensions](https://github.com/minuque/pi-cc-extensions) | Claude Code-style Transcript renderer, Tool/Diff rendering, Context Inspector, and references | v0.8.67, commit `dba37e5` |
|
|
169
171
|
|
|
170
|
-
Production code lives in `extensions/`. `pi-one-ui` has unified the composition entry point, configuration storage, lifecycle management, layout ownership, overlay orchestration, and input routing. The project now evolves independently and no longer tracks upstream changes directly.
|
|
172
|
+
Production code lives in `extensions/`. `pi-one-ui` has unified the composition entry point, configuration storage, lifecycle management, layout ownership, overlay orchestration, and input routing. The project now evolves independently and no longer tracks upstream changes directly. Copyright notices and the full MIT license texts for the two upstream projects and for the diff renderer source are collected in [THIRD-PARTY-NOTICES.md](./THIRD-PARTY-NOTICES.md).
|
|
171
173
|
|
|
172
174
|
See [ARCHITECTURE.md](./ARCHITECTURE.md) for detailed module boundaries, event flow, and ownership conventions.
|
|
173
175
|
|
|
@@ -245,7 +247,7 @@ See [ARCHITECTURE.md](./ARCHITECTURE.md) for module rules and real Pi TUI verifi
|
|
|
245
247
|
All tests run through Vitest and are organized into domain directories:
|
|
246
248
|
|
|
247
249
|
- `tests/config/`: canonical configuration, storage, and compatibility boundaries.
|
|
248
|
-
- `tests/
|
|
250
|
+
- `tests/transcript/`: Transcript content, tools, diffs, thinking, and mouse interaction.
|
|
249
251
|
- `tests/header/`, `tests/working-line/`, `tests/editor/`, and `tests/footer/`: Layout behavior and lifecycle coverage.
|
|
250
252
|
- `tests/runtime/`, `tests/overlay/`, and `tests/integration/`: runtime infrastructure, overlays, and the composed entry point.
|
|
251
253
|
- `tests/services/`: Git, runtime, project, session, and telemetry data.
|
|
@@ -297,4 +299,4 @@ GitHub issues and contributions are welcome. When submitting changes:
|
|
|
297
299
|
|
|
298
300
|
## License
|
|
299
301
|
|
|
300
|
-
This project is released under the [MIT License](./LICENSE).
|
|
302
|
+
This project is released under the [MIT License](./LICENSE). Copyright notices and full license texts for the incorporated third-party code are in [THIRD-PARTY-NOTICES.md](./THIRD-PARTY-NOTICES.md).
|
package/README.md
CHANGED
|
@@ -20,11 +20,11 @@
|
|
|
20
20
|
`pi-one-ui` 将 Pi 的交互界面划分为以下布局层级:
|
|
21
21
|
|
|
22
22
|
```text
|
|
23
|
-
Header →
|
|
23
|
+
Header → Transcript → WorkingLine → Editor → Footer
|
|
24
24
|
```
|
|
25
25
|
|
|
26
26
|
- **Header**:启动信息、Logo 和快捷键提示。
|
|
27
|
-
- **
|
|
27
|
+
- **Transcript**:对话内容区,包含用户消息、Assistant 消息、Thinking 思考过程、Tool 执行、Diff 对比、Markdown 及回合摘要。
|
|
28
28
|
- **WorkingLine**:工作状态指示、Spinner、Token/思考时长统计、实时吞吐速率及回合摘要。
|
|
29
29
|
- **Editor**:输入编辑器、补全建议、元数据展示及 Minimalist 极简样式(支持一键切换 Pi 原生)。
|
|
30
30
|
- **Footer**:工作目录、Git 状态、运行时信息、Token/费用统计及扩展状态等。
|
|
@@ -34,7 +34,7 @@ Header → Context → WorkingLine → Editor → Footer
|
|
|
34
34
|
|
|
35
35
|
| 功能 | 说明 | 入口 |
|
|
36
36
|
| --------------------- | ---------------------------------------------------------------------- | ----------------- |
|
|
37
|
-
| 统一设置面板 | 集中管理 Header、
|
|
37
|
+
| 统一设置面板 | 集中管理 Header、Transcript、WorkingLine、Editor、Footer 等组件及功能设置 | `/oneui` |
|
|
38
38
|
| Context Inspector | 查看上下文占用,并预览 System prompt、Memory、Skills、Tools 及消息内容 | `/context` |
|
|
39
39
|
| Session reference | 搜索并引用注入历史 Pi 会话或 Subagent 的有效上下文 | `@` 补全 |
|
|
40
40
|
| Subagent autocomplete | 提供 Subagent 名称补全与委派提示 | `@` 补全 |
|
|
@@ -76,9 +76,11 @@ pi install git:github.com/kerolt/pi-one-ui
|
|
|
76
76
|
/oneui
|
|
77
77
|
```
|
|
78
78
|
|
|
79
|
-
### 升级到 0.9.
|
|
79
|
+
### 升级到 0.9.1
|
|
80
80
|
|
|
81
|
-
|
|
81
|
+
本次修复了展开工具卡后命令仍被截断的问题:正在执行(pending)的工具卡在 Ctrl+O 或鼠标点击展开后,会按终端宽度折行展示完整命令,多行命令的内嵌换行会被保留;折叠态与已结束的卡继续使用截断标题,已结束的卡仍在 Input 段展示完整输入。`/oneui` 设置面板的 `Context` 分区更名为 `Transcript`,与模型上下文占用有关的名称保持不变(`/context` 命令、Context Inspector、Footer 的 `context` 段与 `context*` 颜色键),配置键、命令与已存数据都没有变化。
|
|
82
|
+
|
|
83
|
+
从 0.8.x 升级的用户还需要执行 0.9.0 的迁移:`renderer.scrollStepLines` 已移除,滚轮步进改由 Pi 官方设置 `fullscreenWheelScrollLines` 控制(`~/.pi/agent/settings.json` 中写入整数如 `3`,或 `"auto"`),配置文件里遗留的 `scrollStepLines` 键会被忽略并保留;fullscreen 的回到底部按钮与 `Ctrl+End` 绑定已移除,请使用官方 `End` 快捷键与指示条。
|
|
82
84
|
|
|
83
85
|
未固定版本的 npm 安装可执行:
|
|
84
86
|
|
|
@@ -86,7 +88,7 @@ pi install git:github.com/kerolt/pi-one-ui
|
|
|
86
88
|
pi update npm:pi-one-ui
|
|
87
89
|
```
|
|
88
90
|
|
|
89
|
-
若安装时固定了版本,执行 `pi install npm:pi-one-ui@0.9.
|
|
91
|
+
若安装时固定了版本,执行 `pi install npm:pi-one-ui@0.9.1` 更新版本指定。更新安装包后,完整退出并重启 Pi。
|
|
90
92
|
|
|
91
93
|
## 配置
|
|
92
94
|
|
|
@@ -167,9 +169,9 @@ pi update npm:pi-one-ui
|
|
|
167
169
|
| 上游项目 | 融入 `pi-one-ui` 的主要能力 | 参照 Baseline |
|
|
168
170
|
| --------------------------------------------------------------- | -------------------------------------------------------------------------- | ------------------------- |
|
|
169
171
|
| [pi-zentui](https://github.com/lmilojevicc/pi-zentui) | Starship 风格 Footer、Editor 基础布局与 Shell 交互能力 | v0.21.0,commit `5341b38` |
|
|
170
|
-
| [pi-cc-extensions](https://github.com/minuque/pi-cc-extensions) | Claude Code 风格
|
|
172
|
+
| [pi-cc-extensions](https://github.com/minuque/pi-cc-extensions) | Claude Code 风格 Transcript 渲染器、Tool/Diff 视图、Context Inspector 与会话引用 | v0.8.67,commit `dba37e5` |
|
|
171
173
|
|
|
172
|
-
融合后的生产代码位于 `extensions/`。`pi-one-ui` 在原始实现之上完成了入口统一、配置存储规范化、生命周期治理、Layout Ownership 收敛、Overlay
|
|
174
|
+
融合后的生产代码位于 `extensions/`。`pi-one-ui` 在原始实现之上完成了入口统一、配置存储规范化、生命周期治理、Layout Ownership 收敛、Overlay 统一调度与输入路由解耦,并持续独立演进。当前实现已完全独立于上游,不依赖也不自动同步上游分支。两个上游项目以及 Diff 渲染器来源的版权与 MIT 许可全文收录在 [THIRD-PARTY-NOTICES.md](./THIRD-PARTY-NOTICES.md)。
|
|
173
175
|
|
|
174
176
|
更详细的模块边界、事件流与 Ownership 约定参见 [ARCHITECTURE.md](./ARCHITECTURE.md)。
|
|
175
177
|
|
|
@@ -247,7 +249,7 @@ npm run pack:check
|
|
|
247
249
|
所有测试统一由 Vitest 执行,并按照功能领域组织在子目录中:
|
|
248
250
|
|
|
249
251
|
- `tests/config/`:canonical 配置、存储和兼容性边界。
|
|
250
|
-
- `tests/
|
|
252
|
+
- `tests/transcript/`:Transcript 内容区、Tool、Diff、Thinking 和鼠标交互。
|
|
251
253
|
- `tests/header/`、`tests/working-line/`、`tests/editor/`、`tests/footer/`:各 Layout 的行为和生命周期。
|
|
252
254
|
- `tests/runtime/`、`tests/overlay/`、`tests/integration/`:运行时基础设施、Overlay 和组合入口。
|
|
253
255
|
- `tests/services/`:Git、runtime、project、session 和 telemetry。
|
|
@@ -299,4 +301,4 @@ git push origin main --follow-tags
|
|
|
299
301
|
|
|
300
302
|
## 许可证
|
|
301
303
|
|
|
302
|
-
本项目基于 [MIT License](./LICENSE)
|
|
304
|
+
本项目基于 [MIT License](./LICENSE) 发布。整合进来的上游代码的版权与许可全文见 [THIRD-PARTY-NOTICES.md](./THIRD-PARTY-NOTICES.md)。
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# Third-Party Notices
|
|
2
|
+
|
|
3
|
+
`pi-one-ui` is distributed under the MIT License (see [LICENSE](./LICENSE)). Its
|
|
4
|
+
source code incorporates material from the open-source projects listed below.
|
|
5
|
+
Each upstream license text is reproduced in full, as required by the MIT
|
|
6
|
+
License.
|
|
7
|
+
|
|
8
|
+
## pi-zentui
|
|
9
|
+
|
|
10
|
+
Source: <https://github.com/lmilojevicc/pi-zentui> (baseline v0.21.0, commit
|
|
11
|
+
`5341b38`). Incorporated capabilities: Starship-style Footer, Editor base
|
|
12
|
+
layouts, and shell interaction.
|
|
13
|
+
|
|
14
|
+
Copyright (c) 2025-2026 Luka
|
|
15
|
+
|
|
16
|
+
```text
|
|
17
|
+
MIT License
|
|
18
|
+
|
|
19
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
20
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
21
|
+
in the Software without restriction, including without limitation the rights
|
|
22
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
23
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
24
|
+
furnished to do so, subject to the following conditions:
|
|
25
|
+
|
|
26
|
+
The above copyright notice and this permission notice shall be included in all
|
|
27
|
+
copies or substantial portions of the Software.
|
|
28
|
+
|
|
29
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
30
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
31
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
32
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
33
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
34
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
35
|
+
SOFTWARE.
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## pi-cc-extensions
|
|
39
|
+
|
|
40
|
+
Source: <https://github.com/minuque/pi-cc-extensions> (baseline v0.8.67, commit
|
|
41
|
+
`dba37e5`). Incorporated capabilities: Claude Code-style Transcript renderer,
|
|
42
|
+
Tool/Diff views, Context Inspector, and session references.
|
|
43
|
+
|
|
44
|
+
Copyright (c) 2026 minuque
|
|
45
|
+
|
|
46
|
+
```text
|
|
47
|
+
MIT License
|
|
48
|
+
|
|
49
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
50
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
51
|
+
in the Software without restriction, including without limitation the rights
|
|
52
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
53
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
54
|
+
furnished to do so, subject to the following conditions:
|
|
55
|
+
|
|
56
|
+
The above copyright notice and this permission notice shall be included in all
|
|
57
|
+
copies or substantial portions of the Software.
|
|
58
|
+
|
|
59
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
60
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
61
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
62
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
63
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
64
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
65
|
+
SOFTWARE.
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## pi-tool-display
|
|
69
|
+
|
|
70
|
+
Source: <https://github.com/MasuRii/pi-tool-display> (commit
|
|
71
|
+
`91cef7580078371f8dc49a8607222807ad6a424d`). Incorporated material: the rich
|
|
72
|
+
diff renderer under
|
|
73
|
+
`extensions/layouts/transcript/renderer/tool/diff/`. The same attribution is
|
|
74
|
+
repeated next to the adapted code in that directory's `ATTRIBUTION.md`.
|
|
75
|
+
|
|
76
|
+
Copyright (c) MasuRii and pi-tool-display contributors
|
|
77
|
+
|
|
78
|
+
```text
|
|
79
|
+
MIT License
|
|
80
|
+
|
|
81
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
82
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
83
|
+
in the Software without restriction, including without limitation the rights
|
|
84
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
85
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
86
|
+
furnished to do so, subject to the following conditions:
|
|
87
|
+
|
|
88
|
+
The above copyright notice and this permission notice shall be included in all
|
|
89
|
+
copies or substantial portions of the Software.
|
|
90
|
+
|
|
91
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
92
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
93
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
94
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
95
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
96
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
97
|
+
SOFTWARE.
|
|
98
|
+
```
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { CompactThinkingConfig } from "../../layouts/
|
|
1
|
+
import type { CompactThinkingConfig } from "../../layouts/transcript/thinking/compact-thinking.ts";
|
|
2
2
|
import { type ConfigRecord, configStore } from "./store.ts";
|
|
3
3
|
|
|
4
4
|
export type CompactStyleMode = "on" | "compact" | "off";
|
|
@@ -8,10 +8,6 @@ import {
|
|
|
8
8
|
resolveConfiguredIcons,
|
|
9
9
|
} from "../../shared/icons.ts";
|
|
10
10
|
import { isSupportedColorSpec } from "../../shared/style.ts";
|
|
11
|
-
import {
|
|
12
|
-
normalizeUserMessages,
|
|
13
|
-
type UserMessagesComponentConfig,
|
|
14
|
-
} from "./context.ts";
|
|
15
11
|
import {
|
|
16
12
|
defaultEditor,
|
|
17
13
|
type EditorBorderColorMode,
|
|
@@ -55,6 +51,10 @@ import {
|
|
|
55
51
|
configPath as defaultConfigPath,
|
|
56
52
|
mutateConfigFile,
|
|
57
53
|
} from "./store.ts";
|
|
54
|
+
import {
|
|
55
|
+
normalizeUserMessages,
|
|
56
|
+
type UserMessagesComponentConfig,
|
|
57
|
+
} from "./user-messages.ts";
|
|
58
58
|
import { booleanValue, overlayKnown, recordValue } from "./values.ts";
|
|
59
59
|
import {
|
|
60
60
|
defaultWorkingLine,
|
|
@@ -64,9 +64,9 @@ import {
|
|
|
64
64
|
} from "./working-line.ts";
|
|
65
65
|
|
|
66
66
|
export type { IconMode } from "../../shared/icons.ts";
|
|
67
|
-
export * from "./context.ts";
|
|
68
67
|
export * from "./editor.ts";
|
|
69
68
|
export * from "./footer.ts";
|
|
69
|
+
export * from "./user-messages.ts";
|
|
70
70
|
export * from "./working-line.ts";
|
|
71
71
|
export type ColorSpec = string;
|
|
72
72
|
/** 选择框边框样式:`one-ui` 是唯一实现,旧配置里的 `zentui` 按同一样式读取。 */
|
|
@@ -9,15 +9,15 @@ import contextInspector from "../../features/context-inspector/index.ts";
|
|
|
9
9
|
import effortCommand from "../../features/effort-command.ts";
|
|
10
10
|
import sessionReference from "../../features/session-reference/index.ts";
|
|
11
11
|
import subagentAutocomplete from "../../features/subagent-autocomplete.ts";
|
|
12
|
-
import registerContext, {
|
|
13
|
-
type ContextRuntimeController,
|
|
14
|
-
} from "../../layouts/context/index.ts";
|
|
15
12
|
import { EditorLayoutController } from "../../layouts/editor/index.ts";
|
|
16
13
|
import { FooterLayoutController } from "../../layouts/footer/index.ts";
|
|
17
14
|
import registerHeader, {
|
|
18
15
|
applyStartupHeader,
|
|
19
16
|
} from "../../layouts/header/index.ts";
|
|
20
17
|
import { SelectorController } from "../../layouts/overlay/selector-controller.ts";
|
|
18
|
+
import registerTranscript, {
|
|
19
|
+
type TranscriptRuntimeController,
|
|
20
|
+
} from "../../layouts/transcript/index.ts";
|
|
21
21
|
import { WorkingLineLayoutController } from "../../layouts/working-line/controller.ts";
|
|
22
22
|
import {
|
|
23
23
|
LEGACY_TURN_SUMMARY_ENTRY_TYPE,
|
|
@@ -61,7 +61,7 @@ export class TuiRuntime {
|
|
|
61
61
|
readonly input = new InputRouter();
|
|
62
62
|
private readonly coordinator: EventCoordinator;
|
|
63
63
|
private readonly coordinatedPi: ExtensionAPI;
|
|
64
|
-
private
|
|
64
|
+
private transcript: TranscriptRuntimeController | undefined;
|
|
65
65
|
private installed = false;
|
|
66
66
|
private currentContext: ExtensionContext | undefined;
|
|
67
67
|
|
|
@@ -92,7 +92,7 @@ export class TuiRuntime {
|
|
|
92
92
|
render: this.render,
|
|
93
93
|
settings: this.settings,
|
|
94
94
|
onConfigChanged: (previous, ctx) => {
|
|
95
|
-
this.
|
|
95
|
+
this.transcript?.applyConfig(ctx, previous);
|
|
96
96
|
if (previous.showStartupHeader !== config.showStartupHeader) {
|
|
97
97
|
applyStartupHeader(ctx);
|
|
98
98
|
}
|
|
@@ -101,7 +101,7 @@ export class TuiRuntime {
|
|
|
101
101
|
bindings.workingLineController.setSummaryWriterEnabled(false);
|
|
102
102
|
bindings.installEventHandlers(this.coordinator);
|
|
103
103
|
registerHeader(pi);
|
|
104
|
-
this.
|
|
104
|
+
this.transcript = registerTranscript(pi, {
|
|
105
105
|
getConfig: bindings.getConfig,
|
|
106
106
|
services: {
|
|
107
107
|
input: this.input,
|
|
@@ -23,7 +23,7 @@ import {
|
|
|
23
23
|
|
|
24
24
|
const SECTIONS = [
|
|
25
25
|
{ id: "header", label: "Header" },
|
|
26
|
-
{ id: "
|
|
26
|
+
{ id: "transcript", label: "Transcript" },
|
|
27
27
|
{ id: "workingLine", label: "WorkingLine" },
|
|
28
28
|
{ id: "editor", label: "Editor" },
|
|
29
29
|
{ id: "footer", label: "Footer" },
|
|
@@ -111,7 +111,7 @@ function itemsFor(
|
|
|
111
111
|
["starship", "native", "hidden"],
|
|
112
112
|
),
|
|
113
113
|
];
|
|
114
|
-
case "
|
|
114
|
+
case "transcript":
|
|
115
115
|
return [
|
|
116
116
|
toggle(
|
|
117
117
|
"userMessagesEnabled",
|
|
@@ -127,7 +127,7 @@ function itemsFor(
|
|
|
127
127
|
["framed", "framed-copy-friendly", "compact", "labeled"],
|
|
128
128
|
),
|
|
129
129
|
item(
|
|
130
|
-
"
|
|
130
|
+
"transcriptMode",
|
|
131
131
|
"Tool style",
|
|
132
132
|
"on = rich cards, compact = one summary per assistant message, off = native.",
|
|
133
133
|
config.mode,
|
|
@@ -212,10 +212,10 @@ function itemsFor(
|
|
|
212
212
|
`preset:${preset}`,
|
|
213
213
|
preset,
|
|
214
214
|
preset === "native"
|
|
215
|
-
? "Disable custom Editor, Footer, WorkingLine and
|
|
215
|
+
? "Disable custom Editor, Footer, WorkingLine and Transcript rendering."
|
|
216
216
|
: preset === "compact"
|
|
217
|
-
? "Enable Editor, Footer, WorkingLine and compact
|
|
218
|
-
: "Enable Editor, Footer, WorkingLine and rich
|
|
217
|
+
? "Enable Editor, Footer, WorkingLine and compact Transcript rendering."
|
|
218
|
+
: "Enable Editor, Footer, WorkingLine and rich Transcript rendering.",
|
|
219
219
|
"apply",
|
|
220
220
|
["apply"],
|
|
221
221
|
),
|
|
@@ -225,7 +225,8 @@ function itemsFor(
|
|
|
225
225
|
|
|
226
226
|
const descriptions: Record<SectionId, string> = {
|
|
227
227
|
header: "Header owns startup branding and startup guidance.",
|
|
228
|
-
|
|
228
|
+
transcript:
|
|
229
|
+
"Transcript owns messages, tool cards, diffs, thinking, and summaries.",
|
|
229
230
|
workingLine: "WorkingLine is the sole owner of Pi's unkeyed working row.",
|
|
230
231
|
editor: "Editor owns the input editor factory and its styles.",
|
|
231
232
|
footer: "Footer owns footer rendering and project status segments.",
|
|
@@ -317,7 +318,7 @@ export function createSettingsPanel(
|
|
|
317
318
|
(line) => ` ${line}`,
|
|
318
319
|
),
|
|
319
320
|
]
|
|
320
|
-
: section === "
|
|
321
|
+
: section === "transcript"
|
|
321
322
|
? [
|
|
322
323
|
"",
|
|
323
324
|
theme.fg("muted", " User message preview"),
|
|
@@ -2,9 +2,9 @@ import type { Theme } from "@earendil-works/pi-coding-agent";
|
|
|
2
2
|
import { truncateToWidth, visibleWidth } from "@earendil-works/pi-tui";
|
|
3
3
|
import type { PolishedTuiConfig } from "../../app/config/shell.ts";
|
|
4
4
|
import { safeThemeFg } from "../../shared/style.ts";
|
|
5
|
-
import { renderUserMessageStyle } from "../context/message/user-message-styles.ts";
|
|
6
5
|
import { sanitizeEditorMetadataText } from "../editor/editor-metadata-format.ts";
|
|
7
6
|
import { renderMinimalistFrame } from "../editor/minimalist-editor.ts";
|
|
7
|
+
import { renderUserMessageStyle } from "../transcript/message/user-message-styles.ts";
|
|
8
8
|
|
|
9
9
|
export const SETTINGS_PREVIEW_MAX_WIDTH = 72;
|
|
10
10
|
export const SETTINGS_PREVIEW_MAX_ROWS = 10;
|
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
type PolishedTuiConfig,
|
|
10
10
|
} from "../../app/config/shell.ts";
|
|
11
11
|
import { installUserMessageStyle } from "./message/user-message.ts";
|
|
12
|
-
import
|
|
12
|
+
import registerTranscriptRenderer, {
|
|
13
13
|
getCompactThinkingConfig,
|
|
14
14
|
type RendererExtensionOptions,
|
|
15
15
|
type RendererRuntimeController,
|
|
@@ -18,19 +18,19 @@ import markdownEnhance from "./renderer/markdown-enhance.ts";
|
|
|
18
18
|
import agentSummary from "./summary/index.ts";
|
|
19
19
|
import { installCompactThinking } from "./thinking/compact-thinking.ts";
|
|
20
20
|
|
|
21
|
-
export type
|
|
21
|
+
export type TranscriptRuntimeController = RendererRuntimeController & {
|
|
22
22
|
applyConfig(ctx: ExtensionContext, previous: Config): void;
|
|
23
23
|
};
|
|
24
|
-
export type
|
|
24
|
+
export type TranscriptExtensionOptions = {
|
|
25
25
|
readonly getConfig: () => PolishedTuiConfig;
|
|
26
26
|
readonly services?: RendererExtensionOptions["services"];
|
|
27
27
|
};
|
|
28
28
|
|
|
29
|
-
/**
|
|
30
|
-
export default function
|
|
29
|
+
/** Transcript 仅组织自身内容组件,Feature 的启用由 app 决定。 */
|
|
30
|
+
export default function registerTranscript(
|
|
31
31
|
pi: ExtensionAPI,
|
|
32
|
-
options:
|
|
33
|
-
):
|
|
32
|
+
options: TranscriptExtensionOptions,
|
|
33
|
+
): TranscriptRuntimeController {
|
|
34
34
|
let activeTheme: Theme | undefined;
|
|
35
35
|
let cleanupUserMessages: (() => void) | undefined;
|
|
36
36
|
const reconcile = (): void => {
|
|
@@ -53,7 +53,7 @@ export default function registerContext(
|
|
|
53
53
|
|
|
54
54
|
markdownEnhance(pi);
|
|
55
55
|
const thinking = installCompactThinking(pi, getCompactThinkingConfig());
|
|
56
|
-
const renderer =
|
|
56
|
+
const renderer = registerTranscriptRenderer(pi, undefined, thinking, {
|
|
57
57
|
services: options.services,
|
|
58
58
|
});
|
|
59
59
|
if (config.enableAgentSummary) {
|
|
@@ -47,7 +47,6 @@ import {
|
|
|
47
47
|
} from "../../../tools/patch-keys.ts";
|
|
48
48
|
import { toolLoadingIcon } from "../../../tools/tool-loading-icon.ts";
|
|
49
49
|
import { sanitizeToolResultText } from "../../../tools/tool-result-sanitize.ts";
|
|
50
|
-
import { refreshContextComponent } from "./context-refresh.ts";
|
|
51
50
|
import { isToolCallHovered } from "./mouse/hover.ts";
|
|
52
51
|
import {
|
|
53
52
|
countEditDiffStats,
|
|
@@ -64,6 +63,7 @@ import {
|
|
|
64
63
|
scheduleAnimation,
|
|
65
64
|
} from "./tool/result.ts";
|
|
66
65
|
import { showMoreHintText } from "./tool/show-more-hint.ts";
|
|
66
|
+
import { refreshTranscriptComponent } from "./transcript-refresh.ts";
|
|
67
67
|
|
|
68
68
|
/** compact 渲染层对 compact-thinking 的只读查询面(不建第二套计时器)。 */
|
|
69
69
|
export type CompactThinkingQuery = {
|
|
@@ -843,7 +843,7 @@ function collectMountedComponents(root: any): void {
|
|
|
843
843
|
}
|
|
844
844
|
});
|
|
845
845
|
// Replace tracking only after scanning components. The root often omits the
|
|
846
|
-
//
|
|
846
|
+
// transcript while a panel or custom UI is open,
|
|
847
847
|
// so clearing here would lose live updateContent/updateDisplay instances,
|
|
848
848
|
// and mode changes would require a /reload to rebuild them.
|
|
849
849
|
if (assistants.size > 0 || tools.size > 0) {
|
|
@@ -1425,7 +1425,7 @@ function refreshTrackedComponents(): void {
|
|
|
1425
1425
|
for (const component of [...trackedAssistantComponents]) {
|
|
1426
1426
|
try {
|
|
1427
1427
|
if (config.mode !== "compact") detachAssistantExpansion(component);
|
|
1428
|
-
|
|
1428
|
+
refreshTranscriptComponent(component);
|
|
1429
1429
|
} catch {
|
|
1430
1430
|
trackedAssistantComponents.delete(component);
|
|
1431
1431
|
}
|
|
@@ -1433,7 +1433,7 @@ function refreshTrackedComponents(): void {
|
|
|
1433
1433
|
for (const component of [...trackedToolComponents]) {
|
|
1434
1434
|
try {
|
|
1435
1435
|
// 共享实现负责 updateDisplay;invalidate 属于 compact-mode 的跟踪语义。
|
|
1436
|
-
|
|
1436
|
+
refreshTranscriptComponent(component);
|
|
1437
1437
|
component.invalidate?.();
|
|
1438
1438
|
} catch {
|
|
1439
1439
|
trackedToolComponents.delete(component);
|
|
@@ -5,7 +5,12 @@
|
|
|
5
5
|
* 生命周期对齐 compact-mode:installDefaultMode → hooks.shutdown。
|
|
6
6
|
*/
|
|
7
7
|
import { ToolExecutionComponent } from "@earendil-works/pi-coding-agent";
|
|
8
|
-
import {
|
|
8
|
+
import {
|
|
9
|
+
Text,
|
|
10
|
+
truncateToWidth,
|
|
11
|
+
visibleWidth,
|
|
12
|
+
wrapTextWithAnsi,
|
|
13
|
+
} from "@earendil-works/pi-tui";
|
|
9
14
|
import {
|
|
10
15
|
type CompactStyleMode,
|
|
11
16
|
config,
|
|
@@ -271,10 +276,18 @@ function createPolishedTool(
|
|
|
271
276
|
visualState === "success"
|
|
272
277
|
? `${BRIGHT_GREEN}${rawIcon}${ANSI_FG_RESET}`
|
|
273
278
|
: theme.fg(toolIconColor(context), rawIcon);
|
|
279
|
+
const summaryTitle =
|
|
280
|
+
label === toolName ? humanizeToolLabel(label) : label;
|
|
274
281
|
const summary = toolCallSummary(toolName, args, {
|
|
275
|
-
title:
|
|
282
|
+
title: summaryTitle,
|
|
276
283
|
variant: "default",
|
|
277
284
|
});
|
|
285
|
+
const expanded = Boolean(context?.expanded);
|
|
286
|
+
// 展开且仍在执行的卡展示完整命令;折叠卡与已结束的卡继续用截断摘要。
|
|
287
|
+
const fullCallText =
|
|
288
|
+
expanded && isPending
|
|
289
|
+
? `${toolCallSummary(toolName, args, { title: summaryTitle, variant: "default", fullInput: true }).main}${summary.detail}`
|
|
290
|
+
: "";
|
|
278
291
|
let writeStatsText = "";
|
|
279
292
|
let writeStatsStyled = "";
|
|
280
293
|
if (toolName === "write" && visualState === "success") {
|
|
@@ -293,23 +306,40 @@ function createPolishedTool(
|
|
|
293
306
|
const extraStyled = writeStatsStyled || theme.fg("dim", summary.detail);
|
|
294
307
|
let cachedWidth: number | undefined;
|
|
295
308
|
let cachedLine: string | undefined;
|
|
296
|
-
|
|
309
|
+
let cachedLines: string[] | undefined;
|
|
297
310
|
return {
|
|
298
311
|
render(width: number) {
|
|
299
|
-
if (
|
|
300
|
-
return
|
|
312
|
+
if (cachedLines !== undefined && cachedWidth === width)
|
|
313
|
+
return cachedLines;
|
|
301
314
|
const viewportWidth = toolViewportWidth(width);
|
|
302
315
|
// 展开态贴左(外层 Box 已 pad 1);折叠 self-shell 保留 1 格前导空格
|
|
303
316
|
const lead = expanded ? "" : " ";
|
|
317
|
+
cachedWidth = width;
|
|
318
|
+
if (fullCallText) {
|
|
319
|
+
// 完整文本按换行与视口宽度折行,续行对齐命令起始列
|
|
320
|
+
const prefix = `${lead}${icon} `;
|
|
321
|
+
const indent = " ".repeat(visibleWidth(prefix));
|
|
322
|
+
cachedLines = wrapTextWithAnsi(
|
|
323
|
+
fullCallText,
|
|
324
|
+
Math.max(1, viewportWidth - visibleWidth(prefix)),
|
|
325
|
+
).map((line, index) =>
|
|
326
|
+
truncateToWidth(
|
|
327
|
+
`${index === 0 ? prefix : indent}${theme.fg("toolTitle", line)}`,
|
|
328
|
+
viewportWidth,
|
|
329
|
+
"",
|
|
330
|
+
),
|
|
331
|
+
);
|
|
332
|
+
return cachedLines;
|
|
333
|
+
}
|
|
304
334
|
const callWidth = Math.max(
|
|
305
335
|
0,
|
|
306
336
|
viewportWidth - visibleWidth(icon) - 1 - (expanded ? 0 : 1),
|
|
307
337
|
);
|
|
308
338
|
const mainWidth = Math.max(0, callWidth - visibleWidth(extraText));
|
|
309
|
-
cachedWidth = width;
|
|
310
339
|
// 纯文本先截断再着色(省略号不带 ANSI);从头截断,与多 tool 一致
|
|
311
340
|
cachedLine = `${lead}${icon} ${theme.fg("toolTitle", headTruncateToWidth(summary.main, mainWidth))}${extraStyled}`;
|
|
312
|
-
|
|
341
|
+
cachedLines = [truncateToWidth(cachedLine, viewportWidth, "")];
|
|
342
|
+
return cachedLines;
|
|
313
343
|
},
|
|
314
344
|
invalidate() {},
|
|
315
345
|
};
|
|
@@ -62,7 +62,7 @@ import {
|
|
|
62
62
|
|
|
63
63
|
let compactModeHooks: CompactModeHooks | undefined;
|
|
64
64
|
|
|
65
|
-
function
|
|
65
|
+
function refreshCurrentTranscript(
|
|
66
66
|
ctx?: any,
|
|
67
67
|
toolGrouping?: ToolGroupingHooks,
|
|
68
68
|
render?: ToolMouseServices["render"],
|
|
@@ -104,15 +104,15 @@ function applyStyleMode(
|
|
|
104
104
|
tui.terminal?.write?.(TOOL_MOUSE_DISABLE);
|
|
105
105
|
}
|
|
106
106
|
} else if (mode === "compact") {
|
|
107
|
-
// Enter compact mode after collecting the current
|
|
107
|
+
// Enter compact mode after collecting the current transcript and syncing ownership.
|
|
108
108
|
syncCompactMode(ctx);
|
|
109
109
|
}
|
|
110
110
|
// Reshape immediately and once more after the panel/custom UI unmounts and
|
|
111
|
-
// the main
|
|
112
|
-
|
|
111
|
+
// the main transcript is mounted again.
|
|
112
|
+
refreshCurrentTranscript(ctx, toolGrouping, render);
|
|
113
113
|
scheduleSessionRender(() => {
|
|
114
114
|
if (mode === "compact") syncCompactMode(ctx);
|
|
115
|
-
|
|
115
|
+
refreshCurrentTranscript(ctx, toolGrouping, render);
|
|
116
116
|
});
|
|
117
117
|
ctx.ui.notify(`Claude Code style: ${mode}`, "info");
|
|
118
118
|
}
|
|
@@ -203,7 +203,7 @@ export default function (
|
|
|
203
203
|
// 配置(如 expandedPreviewMaxLines / excludeRenderers)变化可能改变
|
|
204
204
|
// 渲染结果:丢弃工具卡跨 toggle 缓存,下次 updateDisplay 重建。
|
|
205
205
|
installation?.toggleRenderCache.clear();
|
|
206
|
-
|
|
206
|
+
refreshCurrentTranscript(
|
|
207
207
|
ctx,
|
|
208
208
|
installation?.toolGrouping,
|
|
209
209
|
options.services?.render,
|
|
@@ -243,7 +243,7 @@ export default function (
|
|
|
243
243
|
hooks.toolGrouping.setTheme(ctx.ui.theme);
|
|
244
244
|
hooks.toggleRenderCache.setTheme(ctx.ui.theme);
|
|
245
245
|
setMessageDisplayTheme(ctx.ui.theme);
|
|
246
|
-
// Collect the resumed
|
|
246
|
+
// Collect the resumed transcript before syncing compact patches and expansion state.
|
|
247
247
|
syncCompactMode(ctx);
|
|
248
248
|
// compact-thinking 的 session_start 处理在本 handler 之后执行(在其之上再装
|
|
249
249
|
// 一层 updateContent);延迟再同步一次,保证 compact 补丁最终位于外层。
|
|
@@ -253,7 +253,7 @@ export default function (
|
|
|
253
253
|
|
|
254
254
|
pi.on("session_compact", async (event, ctx) => {
|
|
255
255
|
const hooks = ensureTuiInstallation(ctx);
|
|
256
|
-
// Compaction rebuilds the
|
|
256
|
+
// Compaction rebuilds the transcript without session_start. Rebind after
|
|
257
257
|
// other TUI extensions may have replaced the root input dispatcher.
|
|
258
258
|
if (ctx?.mode === "tui" && ctx?.hasUI)
|
|
259
259
|
installToolMouseInteraction(ctx, mouseOwner, options.services);
|
|
@@ -955,7 +955,7 @@ export function resetToolHoverState(): void {
|
|
|
955
955
|
}
|
|
956
956
|
|
|
957
957
|
/**
|
|
958
|
-
* Installs the
|
|
958
|
+
* Installs the transcript mouse route through the shared input router.
|
|
959
959
|
*
|
|
960
960
|
* @param ctx Active TUI extension context.
|
|
961
961
|
* @param owner Ownership token used to make teardown safe across reloads.
|
|
@@ -1037,7 +1037,7 @@ export function scheduleSessionRender(refresh?: () => void): void {
|
|
|
1037
1037
|
const tui = getToolMouseTui();
|
|
1038
1038
|
if (!tui || typeof tui.requestRender !== "function") return;
|
|
1039
1039
|
if (sessionRenderTimer) clearTimeout(sessionRenderTimer);
|
|
1040
|
-
// Restored
|
|
1040
|
+
// Restored transcript components are populated at different points for startup, reload,
|
|
1041
1041
|
// and session replacement. Repaint after session_start and the surrounding UI
|
|
1042
1042
|
// rebuild finish so messages are not left hidden until the next terminal input.
|
|
1043
1043
|
sessionRenderTimer = setTimeout(() => {
|
|
@@ -173,7 +173,7 @@ export function isMessageDisplayComponent(value: any): boolean {
|
|
|
173
173
|
}
|
|
174
174
|
|
|
175
175
|
/**
|
|
176
|
-
* Refreshes mounted
|
|
176
|
+
* Refreshes mounted transcript message components after a mode change.
|
|
177
177
|
*/
|
|
178
178
|
export function refreshMessageDisplays(root: any): void {
|
|
179
179
|
walkComponentTree(root, (value: any) => {
|
|
@@ -1,8 +1,21 @@
|
|
|
1
1
|
import { config } from "../../../../app/config/renderer.ts";
|
|
2
2
|
import { oneLine } from "../../../../tools/format.ts";
|
|
3
|
+
import { sanitizeToolResultText } from "../../../../tools/tool-result-sanitize.ts";
|
|
3
4
|
|
|
4
|
-
|
|
5
|
-
|
|
5
|
+
/** 展开输入与 `formatToolInputArgs` 共用同一个字符数上限。 */
|
|
6
|
+
const MAX_FULL_INPUT_CHARS = 8_000;
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* 输入摘要的文本处理。折叠摘要压成一行并按 toolInputNameLength 截断;
|
|
10
|
+
* fullInput 保留完整内容与换行,供展开卡展示完整命令使用。
|
|
11
|
+
*/
|
|
12
|
+
function clipSummaryInput(value: unknown, fullInput: boolean): string {
|
|
13
|
+
if (!fullInput) return oneLine(value, config.toolInputNameLength);
|
|
14
|
+
const raw = String(value ?? "");
|
|
15
|
+
const text = sanitizeToolResultText(raw, MAX_FULL_INPUT_CHARS)
|
|
16
|
+
.replace(/\t/g, " ")
|
|
17
|
+
.trim();
|
|
18
|
+
return raw.length > MAX_FULL_INPUT_CHARS ? `${text}…` : text;
|
|
6
19
|
}
|
|
7
20
|
|
|
8
21
|
/**
|
|
@@ -31,6 +44,8 @@ export type ToolCallSummaryOptions = {
|
|
|
31
44
|
title?: string;
|
|
32
45
|
/** 文案变体;缺省 "default"。 */
|
|
33
46
|
variant?: ToolCallSummaryVariant;
|
|
47
|
+
/** true 时返回未截断且保留换行的完整输入;缺省 false。 */
|
|
48
|
+
fullInput?: boolean;
|
|
34
49
|
};
|
|
35
50
|
|
|
36
51
|
/**
|
|
@@ -46,6 +61,8 @@ export function toolCallSummary(
|
|
|
46
61
|
): { main: string; detail: string } {
|
|
47
62
|
const title = opts.title ?? humanizeToolLabel(toolName);
|
|
48
63
|
const variant = opts.variant ?? "default";
|
|
64
|
+
const clip = (value: unknown) =>
|
|
65
|
+
clipSummaryInput(value, opts.fullInput === true);
|
|
49
66
|
if (!args || typeof args !== "object") return { main: title, detail: "" };
|
|
50
67
|
const name = toolName.toLowerCase();
|
|
51
68
|
const value = (fallback: string, ...keys: string[]) => {
|
|
@@ -11,22 +11,22 @@ import {
|
|
|
11
11
|
|
|
12
12
|
// pi-coding-agent 类型声明中 AssistantMessageComponent 仅能以 value 形式使用,
|
|
13
13
|
// updateContent/lastMessage 用结构化类型访问。
|
|
14
|
-
type
|
|
14
|
+
type TranscriptComponentInternals = {
|
|
15
15
|
lastMessage?: AssistantMessage;
|
|
16
16
|
updateContent(message: AssistantMessage): void;
|
|
17
17
|
invalidate?(): void;
|
|
18
18
|
};
|
|
19
19
|
|
|
20
20
|
/**
|
|
21
|
-
* Refreshes one constructed
|
|
21
|
+
* Refreshes one constructed transcript component.
|
|
22
22
|
*
|
|
23
23
|
* Assistant components receive their latest message, while tool components
|
|
24
24
|
* refresh their display so resumed content returns to the current shell.
|
|
25
25
|
*/
|
|
26
|
-
export function
|
|
26
|
+
export function refreshTranscriptComponent(value: unknown): boolean {
|
|
27
27
|
if (!value || typeof value !== "object") return false;
|
|
28
28
|
if (value instanceof AssistantMessageComponent) {
|
|
29
|
-
const self = value as unknown as
|
|
29
|
+
const self = value as unknown as TranscriptComponentInternals;
|
|
30
30
|
if (self.lastMessage) self.updateContent(self.lastMessage);
|
|
31
31
|
else self.invalidate?.();
|
|
32
32
|
return true;
|
|
@@ -65,13 +65,13 @@ function assertCompactModeOutermost(): void {
|
|
|
65
65
|
* This covers reload, resume and compaction paths where Pi rebuilds components
|
|
66
66
|
* before the renderer patches are installed.
|
|
67
67
|
*/
|
|
68
|
-
export function
|
|
68
|
+
export function refreshMountedTranscript(tui?: unknown): void {
|
|
69
69
|
if (!tui || typeof (tui as any).getMountedRoots !== "function") return;
|
|
70
70
|
// Fix patch order before refreshing so updateContent runs through the outer patch.
|
|
71
71
|
assertCompactModeOutermost();
|
|
72
72
|
walkComponentTree(tui, (value: any) => {
|
|
73
73
|
try {
|
|
74
|
-
|
|
74
|
+
refreshTranscriptComponent(value);
|
|
75
75
|
} catch {
|
|
76
76
|
// Isolate one component failure; a later tree rebuild can retry it.
|
|
77
77
|
}
|
|
@@ -33,8 +33,8 @@ import {
|
|
|
33
33
|
formatThoughtDuration,
|
|
34
34
|
styleCompactThinkingText,
|
|
35
35
|
} from "../renderer/compact-mode.ts";
|
|
36
|
-
import { refreshMountedContext } from "../renderer/context-refresh.ts";
|
|
37
36
|
import { isToolTuiFullscreen } from "../renderer/tool/show-more-hint.ts";
|
|
37
|
+
import { refreshMountedTranscript } from "../renderer/transcript-refresh.ts";
|
|
38
38
|
|
|
39
39
|
// 保持导出兼容:渲染函数已并入 renderer/compact-mode.ts,这里 re-export。
|
|
40
40
|
export {
|
|
@@ -1088,15 +1088,15 @@ function compactThinking(pi: ExtensionAPI) {
|
|
|
1088
1088
|
|
|
1089
1089
|
// pi 在 reload/resume 时先于 session_start 用原始原型重建聊天组件
|
|
1090
1090
|
// (rebuildChatFromMessages / renderCurrentSessionState)。由共享的
|
|
1091
|
-
//
|
|
1091
|
+
// refreshMountedTranscript 扫描挂载树重绘这些组件,恢复 compact 渲染、
|
|
1092
1092
|
// 持久化时长与工具调用显示。
|
|
1093
|
-
|
|
1093
|
+
refreshMountedTranscript(activeTui);
|
|
1094
1094
|
activeTui?.requestRender(true);
|
|
1095
1095
|
});
|
|
1096
1096
|
|
|
1097
1097
|
pi.on("session_tree", (_event, ctx) => {
|
|
1098
1098
|
restoreDurationEntries(ctx.sessionManager.getBranch(), completedDurations);
|
|
1099
|
-
|
|
1099
|
+
refreshMountedTranscript(activeTui);
|
|
1100
1100
|
activeTui?.requestRender(true);
|
|
1101
1101
|
});
|
|
1102
1102
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Shared recursive traversal for component trees.
|
|
3
3
|
*
|
|
4
4
|
* The implementation covers the children/getMountedRoots/seen traversal used by
|
|
5
|
-
*
|
|
5
|
+
* transcript rendering, grouping and mouse packet handling.
|
|
6
6
|
*
|
|
7
7
|
* The visitor runs once for every non-array object. Returning `false` stops
|
|
8
8
|
* traversal into that node's children and mounted roots.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-one-ui",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.1",
|
|
4
4
|
"description": "A single, customizable Pi UI package with layout-oriented Context and Shell rendering for Pi.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -25,7 +25,8 @@
|
|
|
25
25
|
"README.md",
|
|
26
26
|
"README.en.md",
|
|
27
27
|
"CHANGELOG.md",
|
|
28
|
-
"LICENSE"
|
|
28
|
+
"LICENSE",
|
|
29
|
+
"THIRD-PARTY-NOTICES.md"
|
|
29
30
|
],
|
|
30
31
|
"scripts": {
|
|
31
32
|
"format": "biome format --write extensions tests package.json tsconfig.json vitest.config.ts biome.json",
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|