@xzzpig/pi-tidy 0.0.0-stage → 0.1.0
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 +1104 -0
- package/FORK-CHANGELOG.md +31 -0
- package/LICENSE +21 -0
- package/README.md +416 -2
- package/fork/defaults.ts +77 -0
- package/fork/index.ts +2 -0
- package/fork/install.ts +58 -0
- package/fork/thinking-row.ts +221 -0
- package/package.json +68 -3
- package/src/clean-copy.ts +313 -0
- package/src/clipboard.ts +29 -0
- package/src/config.ts +292 -0
- package/src/draw/frame-draw.ts +307 -0
- package/src/draw/icons.ts +2014 -0
- package/src/draw/paint.ts +57 -0
- package/src/frame.ts +20 -0
- package/src/hover.ts +185 -0
- package/src/index.ts +322 -0
- package/src/live.ts +91 -0
- package/src/messages/bash-mode-frame.ts +112 -0
- package/src/messages/error-lines.ts +331 -0
- package/src/messages/extension-notice.ts +204 -0
- package/src/messages/hex-swatches.ts +245 -0
- package/src/messages/message-frame.ts +515 -0
- package/src/messages/user-message.ts +207 -0
- package/src/theme-access.ts +26 -0
- package/src/tools/background-jobs.ts +617 -0
- package/src/tools/bash-highlight.ts +330 -0
- package/src/tools/codemode-body.ts +602 -0
- package/src/tools/result-preview.ts +56 -0
- package/src/tools/split-diff.ts +606 -0
- package/src/tools/tool-frame.ts +1019 -0
- package/src/tools/tool-group-view.ts +1160 -0
- package/src/tools/tool-groups.ts +706 -0
- package/src/tools/tool-lines.ts +621 -0
- package/src/tools/write-preview.ts +81 -0
- package/src/turns/code-blocks.ts +273 -0
- package/src/turns/turn-lifecycle.ts +43 -0
- package/src/turns/turn-state.ts +257 -0
- package/src/turns/turn-view.ts +504 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,1104 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
What changed in each released version of pi-tidy (published as
|
|
4
|
+
`@andy8647/pi-toolbox` up to 0.4.1). Versions follow
|
|
5
|
+
[semantic versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
|
+
|
|
7
|
+
## [0.9.6] - 2026-11-13
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
|
|
11
|
+
**An `edit` another extension registers keeps its file and its diff.** aft's hashline mode (`edit_mode: "hashline"`) takes
|
|
12
|
+
`{ patch }` instead of `{ path }` and brings renderers of its own, so the box showed no path chip, no file-type icon and no
|
|
13
|
+
panes: it stacked the tool's own `edited … (+a/-d)` row under a border that repeated the path. The file now comes from the
|
|
14
|
+
result's `details.files` and the diff from `details.diff` when the call carries neither — the same shape pi's own edit
|
|
15
|
+
result uses — and a relative path is resolved against the working directory, so the chip copies all of it. pi's own
|
|
16
|
+
`edit` is unchanged: its preview still wins while the edit streams, and a preview error still keeps pi's rendering.
|
|
17
|
+
|
|
18
|
+
**A `/reload` with new settings reaches every box and message.** The render caches named the options they read, field by
|
|
19
|
+
field, so an option no cache listed could leave the old frame on screen — 0.9.4's split diff ignoring a theme switch was
|
|
20
|
+
that bug. Each cache now records one revision that every option change bumps, so a setting added later needs nothing
|
|
21
|
+
remembered.
|
|
22
|
+
|
|
23
|
+
## [0.9.5] - 2026-11-09
|
|
24
|
+
|
|
25
|
+
### Added
|
|
26
|
+
|
|
27
|
+
**A color in a message gets a swatch.** A reply or your own message that names a color now shows a `●` painted in it:
|
|
28
|
+
`#7f849c`, `#f00` and `#7f849c80` for hex, `rgb(127, 132, 156)` / `rgba(…)` and `hsl(240, 10%, 15%)` / `hsla(…)`
|
|
29
|
+
for the CSS functions, commas or spaces between the parts. Alpha is ignored because there is nothing to blend against,
|
|
30
|
+
and named colors (`red`, `tomato`) are not matched at all: they are ordinary words in prose. Fenced code blocks,
|
|
31
|
+
inline code and thinking keep their text, so a shell comment that happens to look like a color stays a comment.
|
|
32
|
+
`tidy.hexSwatches: false` leaves the markdown to pi.
|
|
33
|
+
|
|
34
|
+
**A shell's `-c` script is highlighted as the script it is.** `bash -c 'set -e` plus five more lines used to arrive as
|
|
35
|
+
one string token: every row the same green, and no way to read the commands. A quoted argument after `-c` (or a
|
|
36
|
+
combined form like `-lc`) is now tokenized as shell code, three levels of nesting deep, with the quotes still read as
|
|
37
|
+
strings. Heredocs, double-quoted payloads and `grep -c 'x'` keep the plain string treatment.
|
|
38
|
+
|
|
39
|
+
**Words the grammar cannot name take a colour of their own.** Arguments, paths, globs, filenames and the value of
|
|
40
|
+
`VAR=value` / `--flag=value` were passed through uncoloured, so a path-heavy row was a wall of the terminal's default
|
|
41
|
+
foreground. They take `toolOutput`: readable, and clearly not the grey a comment gets.
|
|
42
|
+
|
|
43
|
+
## [0.9.4] - 2026-11-09
|
|
44
|
+
|
|
45
|
+
### Added
|
|
46
|
+
|
|
47
|
+
**A framed user message can stop short of the full width.** `userMessageMaxWidth` takes `"auto"` (the default, the
|
|
48
|
+
whole width), a fraction of it (`0.7`) or a column count (`88`). The text wraps earlier and the frame hugs the narrower
|
|
49
|
+
column, so a long prompt keeps the chat-bubble shape under `userMessageAlign: "right"` instead of spanning the screen.
|
|
50
|
+
The label still gets room to draw itself, so a cap narrower than the icon and time is widened to fit them. The rail and
|
|
51
|
+
the rules are full-width by design and ignore it.
|
|
52
|
+
|
|
53
|
+
### Fixed
|
|
54
|
+
|
|
55
|
+
**Split diffs now follow the theme's appearance.** Light themes get pale row backgrounds and stronger word highlights;
|
|
56
|
+
dark themes and older hosts keep their existing colours. No new setting is needed. Existing edit diffs also refresh
|
|
57
|
+
on theme switches and reloads, even when the added-text colour stays the same.
|
|
58
|
+
|
|
59
|
+
Thanks to @s5unty for the split diff fix, the `appearance` read and the instance-keyed cache included (#73), and to
|
|
60
|
+
@cheney12138 for proposing `userMessageMaxWidth` and the three value forms it takes (#58).
|
|
61
|
+
|
|
62
|
+
## [0.9.3] - 2026-11-08
|
|
63
|
+
|
|
64
|
+
### Added
|
|
65
|
+
|
|
66
|
+
**A message an extension draws itself now wears the transcript's frame.** `frameMessages` framed compaction, branch, skill and
|
|
67
|
+
pi's own custom boxes, but a custom message whose renderer returns a component was left exactly as the extension drew it —
|
|
68
|
+
on a default pi-subagents install, a full-width slab in `customMessageBg` sitting between two framed runs. The rows are still
|
|
69
|
+
the extension's, since nothing here can know where a label belongs inside them; the chrome is Tidy's. The frame, the kind's
|
|
70
|
+
color, the fill stripped, the blank edges trimmed, and clicks mapped back through the border to the component that drew the
|
|
71
|
+
row, so its own click still opens it.
|
|
72
|
+
|
|
73
|
+
pi-subagents' notices are drawn from the message rather than from its renderer: the border says who it is about and how it
|
|
74
|
+
went (`╭─ wiki-verifier failed ──╮`, `╭─ worker needs attention ──╮`) in that status's own color — green for a
|
|
75
|
+
completion, red for a failure, yellow for a stall — the message's own text is the body with the title line it repeats taken
|
|
76
|
+
out, one row of it shows until a click, and the plugin's `(ctrl+o to expand)` is gone because the row is already a header.
|
|
77
|
+
The label is read from `details`: `runs[]` on a completion notice, `event` on a control notice, and the same fields on the
|
|
78
|
+
other twelve types wherever they exist, so a notice that names nobody is still drawn, with the glyph alone.
|
|
79
|
+
Session entries (`reply sent to …`) keep their extension's styling: they render through `CustomEntryComponent`, which pi does
|
|
80
|
+
not export, and the entry renderer registry answers whichever extension registered first.
|
|
81
|
+
|
|
82
|
+
### Fixed
|
|
83
|
+
|
|
84
|
+
**A background job's notifications no longer break the transcript.** `hideJobNotifications` has been on by default since
|
|
85
|
+
0.4.1, but it only applied with `collapseTurns: "off"`. 0.8.0 made turn folding the default, so from then on every
|
|
86
|
+
`[process] "ticker" matched stdout: READY` came back as a block of its own, between runs, on a default install.
|
|
87
|
+
|
|
88
|
+
The blocks are still not drawn. The part a job's row cannot hold is the matched log line; the row only carries the
|
|
89
|
+
pattern. That line is kept per job and drawn as a row under it, inside the group the job belongs to: `· matched stdout:
|
|
90
|
+
tick 5`, at most three, with `· +N earlier` above them, and only while the group is open. A folded turn says how many
|
|
91
|
+
arrived (`▸ … · 2 matched`), because the rows carrying them are inside it. The model still receives every message, and a
|
|
92
|
+
watcher that ticks every second costs a folded transcript nothing.
|
|
93
|
+
|
|
94
|
+
`hideJobNotifications: false` keeps the blocks and draws no rows, rather than reporting the same match twice. A
|
|
95
|
+
notification whose job has no row to absorb it keeps its own block, so nothing is lost: another session, a row not
|
|
96
|
+
rendered again after a `/reload`, a pinned call, `groupTools: false`, pi-processes not loaded.
|
|
97
|
+
|
|
98
|
+
## [0.9.2] - 2026-11-07
|
|
99
|
+
|
|
100
|
+
### Added
|
|
101
|
+
|
|
102
|
+
**A file box's path is one click away.** A `write` or `edit` box's top border carries a copy chip after the path
|
|
103
|
+
(`╭─ src/app.ts ────╮`): click it for `~/…/app.ts` on the clipboard, and the chip shows a tick for a moment. Under the
|
|
104
|
+
pointer it lights up and the pointer becomes a hand, like the code block chip. `icons: false` draws the word `copy`
|
|
105
|
+
instead, and a box too narrow for the chip keeps its plain border.
|
|
106
|
+
|
|
107
|
+
### Fixed
|
|
108
|
+
|
|
109
|
+
**Selecting a path on a box's border copied nothing.** A frame's top border was taken for chrome and dropped whole,
|
|
110
|
+
so a drag along the `write` or `edit` border produced an empty selection: no hint, and `ctrl+x` silently did nothing
|
|
111
|
+
because pi treats an empty selection as no selection. A top border's label now stays when it names a file, with the
|
|
112
|
+
corner, the padding rules, the title's icons and the chip taken off; a reply's `model 14:06` label is still chrome.
|
|
113
|
+
|
|
114
|
+
**The code block chip's hit range was one cell left of it on a framed reply** — the frame's padding was not counted,
|
|
115
|
+
which the four-cell word `copy` hid. It is measured on the drawn row now.
|
|
116
|
+
|
|
117
|
+
**A reply with no frame had a chip nothing answered.** `presentTurn` returns early when a message has no turn header
|
|
118
|
+
and no reply frame, and that return came before the layout and the mouse handler were installed: with
|
|
119
|
+
`finalReplyStyle: "off"`, and on every reply while it streams, the chip was painted and a click did nothing, hover included.
|
|
120
|
+
The early return now only takes the messages that have no hit target, so a reply without chrome keeps its fast path and a
|
|
121
|
+
reply with a chip gets the handler it needs. Thanks to @indesperate for the report and for the trace: the early return
|
|
122
|
+
was exactly where they said it was, and the three bugs it hid were found in the code they pointed at.
|
|
123
|
+
|
|
124
|
+
**A block on an open turn's rail had no joint and no chip.** The rules were matched after the rail went on, and a railed
|
|
125
|
+
row's `│` never equals a rule's own text, so the block kept a plain border and its chip was dead. The rules are measured
|
|
126
|
+
before the rail now: a block on the rail joins it (`├─ fish ────`) and its chip copies like any other.
|
|
127
|
+
|
|
128
|
+
**One block could stop every later chip in the reply, and a repeated block could copy the wrong one.** A rule was
|
|
129
|
+
recognised by the cells it was drawn with, so a block inside a quote or a list item (drawn narrower, with a `│` or a
|
|
130
|
+
`1.` in front) never matched, and no later block was matched either. On pi 1.5 a block pi has already drawn is reused
|
|
131
|
+
without `renderToken` running, so the blocks tidy knew about and the blocks on the rows drifted apart: with two identical
|
|
132
|
+
blocks and a third, the second chip copied the third block's text. The rules are matched by their shape and the blocks
|
|
133
|
+
are read from Markdown's tokens now. A rule too narrow for its label draws no chip and no longer gets an invisible hit
|
|
134
|
+
target on its last cell.
|
|
135
|
+
|
|
136
|
+
### Changed
|
|
137
|
+
|
|
138
|
+
**The copy chips are glyphs**: `` (md-content_copy) at rest and `` (fa-check) after a copy, instead of `copy` and
|
|
139
|
+
`copied`. They take one cell instead of four, so the rule around them is three cells longer. `icons: false` keeps the
|
|
140
|
+
words.
|
|
141
|
+
|
|
142
|
+
## [0.9.1] - 2026-11-06
|
|
143
|
+
|
|
144
|
+
### Added
|
|
145
|
+
|
|
146
|
+
**A reply's fenced code blocks are drawn as a section** (`tidy.codeBlocks`). The two fence rows become rules that
|
|
147
|
+
join the reply's frame or rail (`├─ fish copy ────┤`), with the language on the opening one and a chip beside it:
|
|
148
|
+
clicking it puts the block's own text on the clipboard, and the chip reads `copied` for a moment. Under the pointer the chip
|
|
149
|
+
lights up and the pointer becomes a hand, the same hover the folded rows use. The code rows stay
|
|
150
|
+
as pi drew them. A `diff` block goes side by side instead, under the same `splitDiff` switch and `splitDiffMinWidth`
|
|
151
|
+
as an edit's diff, and keeps the unified form on a row too narrow for two panes. A language highlight.js has no
|
|
152
|
+
grammar for gets the closest one that exists: `fish` is read as a shell, and `.env` and TOML as INI, where pi alone
|
|
153
|
+
paints them one flat colour. `tidy.codeBlocks: false` leaves pi's own fences. A pi whose Markdown draws its code
|
|
154
|
+
blocks itself (no `renderToken` to hook) is unaffected, and tidy says so once at session start.
|
|
155
|
+
|
|
156
|
+
**The run summary's counts wear kind glyphs, and its LLM time wears the provider's.** Folded, every `kind×N` and
|
|
157
|
+
the `LLM` timing get a Nerd Font glyph in front: the tool kind's own, and for the timing the same provider glyph
|
|
158
|
+
the reply's border draws, so both lines name the same vendor. `tidy.icons: false` turns them off. A row too narrow
|
|
159
|
+
to hold them drops the glyphs whole and falls back to plain `bash×8 · read×3`: no count is ever truncated to make
|
|
160
|
+
room for an icon.
|
|
161
|
+
|
|
162
|
+
**`codemode` has a kind glyph of its own** (`fa-code`) instead of the generic wrench.
|
|
163
|
+
|
|
164
|
+
## [0.9.0] - 2026-11-05
|
|
165
|
+
|
|
166
|
+
### Added
|
|
167
|
+
|
|
168
|
+
**`tidy.messageTimeFormat` sets how a message's time reads**, in user messages and the final reply's border (#59): `auto`,
|
|
169
|
+
or a pattern such as `"M月D日 HH:mm:ss"`.
|
|
170
|
+
|
|
171
|
+
**`tidy.messageHeaderStyle: "split"` sets a rule between who a message is from and its time** (#59):
|
|
172
|
+
`╭── model ── 13:09 ───╮`, in user messages and the final reply's border. The default stays `inline`.
|
|
173
|
+
|
|
174
|
+
**The final reply and user messages can have rules without side borders** (#56). `tidy.finalReplyStyle` and
|
|
175
|
+
`tidy.userMessageStyle` both take `"rules"`: a rule above and below and nothing beside the text, so a terminal's own
|
|
176
|
+
selection copies it clean too.
|
|
177
|
+
|
|
178
|
+
**`tidy.finalReplyStyle` replaces `frameFinalReply`**, which keeps working, and also takes `"rail"`: the rules plus a `│` in
|
|
179
|
+
front of the text, like a rail user message.
|
|
180
|
+
|
|
181
|
+
**`tidy.messageBorderColors.assistant` colors the final reply** (#59): its frame and an opened run's rail and marker, as a
|
|
182
|
+
theme color name or `#rrggbb`. The default stays `accent`.
|
|
183
|
+
|
|
184
|
+
### Fixed
|
|
185
|
+
|
|
186
|
+
**`bashResultLines` no longer depends on `highlightBash`.** With highlighting off, the setting was ignored and collapsed
|
|
187
|
+
bash boxes showed pi's 5 lines. They now follow the setting, whose default is 1. If you had highlighting off and want the
|
|
188
|
+
5 lines back, set `tidy.bashResultLines: 5`.
|
|
189
|
+
|
|
190
|
+
**`thinkingColor` accepts `#rrggbb`, as documented.** A hex value made every thinking row disappear.
|
|
191
|
+
|
|
192
|
+
### Changed
|
|
193
|
+
|
|
194
|
+
**The configuration reference is grouped by what each key affects**, and every key now says when it applies. It also
|
|
195
|
+
records two limits that were not written down: `diffLines` only works while an edit's diff is drawn as two panes, and
|
|
196
|
+
`hideJobNotifications` only works with `collapseTurns: "off"`.
|
|
197
|
+
|
|
198
|
+
## [0.8.1] - 2026-11-05
|
|
199
|
+
|
|
200
|
+
### Added
|
|
201
|
+
|
|
202
|
+
**Copies leave the frames behind.** Text selected in pi's fullscreen mode now reaches the clipboard without tidy's
|
|
203
|
+
frames, corners and rail glyphs, on select and with the copy key, with or without pi-starline (#56). A terminal's own
|
|
204
|
+
selection (shift or option and drag) never reaches tidy, so it still brings them along. If you relied on the old copies,
|
|
205
|
+
`tidy.cleanCopy: false` turns this off. Until pi-starline's next release, its copy key still handles the selections it
|
|
206
|
+
recognises, and its hint counts characters its own way.
|
|
207
|
+
|
|
208
|
+
**A rail message carries its icon and time in the top rule.** With `userMessageStyle: "rail"`, the user icon moves out of
|
|
209
|
+
the text into the top rule, next to the time the frame style already showed. `userMessageAlign: "right"` moves that label to
|
|
210
|
+
the right end of the rule; the rail and the text stay left. The text also sits one cell closer to the rail: a cell of pi's
|
|
211
|
+
padding that was meant to come off never did.
|
|
212
|
+
|
|
213
|
+
**`tidy.userMessageTime: false` hides a user message's time**, in both styles. The final reply's border keeps its own.
|
|
214
|
+
|
|
215
|
+
### Fixed
|
|
216
|
+
|
|
217
|
+
**An opened run draws fast again.** 0.8.0 slowed down an opened run by 40-90%: settled thinking rows were rebuilt on
|
|
218
|
+
every frame. They are reused now, which takes 20-46% off a frame in that state at 1,500 components. The render benchmark
|
|
219
|
+
now measures opened runs, which is how this got through.
|
|
220
|
+
|
|
221
|
+
**A short message's frame has room around its label.** The box was exactly as wide as the icon and time in its top
|
|
222
|
+
border, leaving a stub of border on each side (#49). It is now four cells wider.
|
|
223
|
+
|
|
224
|
+
### Changed
|
|
225
|
+
|
|
226
|
+
**The startup list may name `pi-tidy/src`.** The sources moved under `src/`. Nothing else changes for you.
|
|
227
|
+
|
|
228
|
+
## [0.8.0] - 2026-11-04
|
|
229
|
+
|
|
230
|
+
**A run now folds by default.** When a run ends, its process folds to one `▸ took …` line above a framed final reply.
|
|
231
|
+
This changes what you see on update unless your settings already name these keys. To go back:
|
|
232
|
+
|
|
233
|
+
```json
|
|
234
|
+
{ "tidy": { "collapseTurns": "off", "frameFinalReply": false } }
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
### Changed
|
|
238
|
+
|
|
239
|
+
**An opened run hangs on a rail.** The summary's marker moves to the first column, and a rail runs down from it into the
|
|
240
|
+
final reply's left border, in the reply's colour. Groups sit one cell in, boxes two. A box from `alwaysShowTools` joins
|
|
241
|
+
the rail of a group that is open right above or below it. The summary drops its call counts while opened, because the
|
|
242
|
+
group headers carry them.
|
|
243
|
+
|
|
244
|
+
**A group's rows are easier to scan.** The `✓` or `✗` follows the tool's name, so tool icons and the thinking brain share
|
|
245
|
+
a column. Thinking text is dim and runs up to the metrics column. bash commands are highlighted (`highlightBash`), and a
|
|
246
|
+
leading `cd` shows only its last directory (`cd …/pi-tidy && rg x`); the opened box keeps the full command.
|
|
247
|
+
|
|
248
|
+
**Rows say what happened.** A bash call that printed nothing says `no output`, and reading an image says `image`, where it
|
|
249
|
+
said `1 line`.
|
|
250
|
+
|
|
251
|
+
### Added
|
|
252
|
+
|
|
253
|
+
**`toolRowLines`.** Set it to `2` and a call that does not fit its row goes on to a second one: the rest of a long command,
|
|
254
|
+
or the next line of a multi-line one with `(+N lines)`. Calls that fit keep one row. The default stays `1`.
|
|
255
|
+
|
|
256
|
+
### Fixed
|
|
257
|
+
|
|
258
|
+
**Opening an always-shown box no longer throws thinking out of its group.** Opening a `write` or `edit` box moved its
|
|
259
|
+
step's thinking out of the group and took one off the `N thoughts` count.
|
|
260
|
+
|
|
261
|
+
**A failed run keeps its failure in view when it folds.** A run that ended in an error with no text folded the error away,
|
|
262
|
+
and only the summary's `error` was left.
|
|
263
|
+
|
|
264
|
+
**The hover band reaches the end of a clipped row.** It used to stop at the `…`.
|
|
265
|
+
|
|
266
|
+
**The metrics columns follow a result that lands late.** They were only measured again when a call joined the group.
|
|
267
|
+
|
|
268
|
+
**An opened row keeps its columns.** Opening a call moved its row one cell right, and opening a thought moved it two.
|
|
269
|
+
|
|
270
|
+
## [0.7.3] - 2026-11-03
|
|
271
|
+
|
|
272
|
+
### Fixed
|
|
273
|
+
|
|
274
|
+
**One reply, one group.** The first reply after pi started could show two `▾` headers, with some of its calls
|
|
275
|
+
under the second. Folding then kept both headers, in reverse order. A reply is one group again, whichever extensions
|
|
276
|
+
restyle your messages.
|
|
277
|
+
|
|
278
|
+
**Thinking stays under its group's header.** With `groupOpen: true`, a step's `thinking` row could sit above the
|
|
279
|
+
group's summary line instead of inside the group.
|
|
280
|
+
|
|
281
|
+
**An empty step no longer starts a new group** (#50, by dreanzy).
|
|
282
|
+
|
|
283
|
+
**Failed requests are framed, once.** A request that fails for good now shows its `Error: …` in the same
|
|
284
|
+
`╭─ error ─╮` box as other errors (#45). When pi retries, the attempts share one box that counts them
|
|
285
|
+
(`error ×3`), and pi's "Retry failed after N attempts" takes its place when it gives up. An error after part of
|
|
286
|
+
the reply, and an abort with Esc, stay as pi drew them. `tidy.dedupeErrors: false` turns all of this off.
|
|
287
|
+
|
|
288
|
+
### Changed
|
|
289
|
+
|
|
290
|
+
**pi can show you this changelog.** tidy now ships its changelog, so pi 1.5 can list what changed after an update.
|
|
291
|
+
pi starts showing it from the next update on.
|
|
292
|
+
|
|
293
|
+
## [0.7.2] - 2026-11-02
|
|
294
|
+
|
|
295
|
+
### Added
|
|
296
|
+
|
|
297
|
+
**A failed request is one framed row, not one row per retry.** pi reports its own errors — a failed request, an
|
|
298
|
+
extension that threw — by appending a plain row per attempt: `Error: 429: {"message":…}` three times for one
|
|
299
|
+
failure, provider body included, with no frame. tidy now keeps the first row of a repeated error, puts `×N` in its
|
|
300
|
+
border (`╭─ error ×3 ─────╮`) and hides the repeats, so one failure reads as one line. The surviving row is the only
|
|
301
|
+
record that a turn failed, so it stays; warnings and notes are not touched. `tidy.dedupeErrors: false` restores pi's
|
|
302
|
+
behaviour.
|
|
303
|
+
|
|
304
|
+
### Changed
|
|
305
|
+
|
|
306
|
+
**A summary box's label sits in the border, not on its own row.** Compaction, branch and expanded skill boxes
|
|
307
|
+
draw the `[compaction]` / `[branch]` / `[skill]` label on a row of its own; a custom message draws `[type]` the
|
|
308
|
+
same way. That row is a title, so it now goes into the top border next to the kind icon — `╭─ [branch] ───╮`
|
|
309
|
+
— and the blank row that separated it from the body goes with it. A collapsed skill box keeps its label inline:
|
|
310
|
+
there it shares the row with the skill's name. User messages are never touched: their first row is the user's
|
|
311
|
+
own text, which may well be a bare `[word]`.
|
|
312
|
+
|
|
313
|
+
## [0.7.1] - 2026-11-01
|
|
314
|
+
|
|
315
|
+
A rendering release: nothing changes on screen, the frame costs a fraction of what it did.
|
|
316
|
+
|
|
317
|
+
### Changed
|
|
318
|
+
|
|
319
|
+
**A row is measured before it is truncated.** pi-tui's `truncateToWidth` segments the whole string whether or not
|
|
320
|
+
anything is cut — 17 µs for a styled 100-cell row against 90 ns for `visibleWidth` — and every drawn row went through
|
|
321
|
+
it. Rows that already fit now skip it entirely; at 500 components with every tool output open that was 78% of the
|
|
322
|
+
frame. Measured on the benchmark fixture with every tool output open: 5.5 ms → 0.8 ms at 500 components, 21.2 ms →
|
|
323
|
+
2.6 ms at 1500.
|
|
324
|
+
|
|
325
|
+
**A settled tool's rows are drawn once.** An opened call rebuilt its body rows every frame — concatenation, trim and a
|
|
326
|
+
format per row — from a box that had not changed. They are now cached and rebuilt when the group, the pointer, the
|
|
327
|
+
tool's own result or the box under it moves. An active run, a partial call, a background job or a scheduled reveal all
|
|
328
|
+
still draw fresh, so streaming is unchanged.
|
|
329
|
+
|
|
330
|
+
**A turn summary is built once per turn, not once per frame.** Folding a run is now the cheapest state to render
|
|
331
|
+
instead of the most expensive: 3.8 ms → 0.53 ms per frame at 1500 components, where the summary used to iterate the
|
|
332
|
+
turn's messages and tools four times per turn per frame. It is rebuilt when the turn moves or a second passes.
|
|
333
|
+
|
|
334
|
+
### Added
|
|
335
|
+
|
|
336
|
+
**The render benchmark folds runs, and reports on the pull request.** `pnpm bench` now measures three states — tool
|
|
337
|
+
outputs closed, runs folded, tool outputs open — because turn folding is a different path, not a smaller version of
|
|
338
|
+
the other two. CI rewrites a single comment on the PR with the table, found by a marker in its body so every run
|
|
339
|
+
patches it rather than stacking a new one. Pull requests from forks skip that step, and a base older than 0.7.0
|
|
340
|
+
reports the PR's own numbers for the state it cannot render.
|
|
341
|
+
|
|
342
|
+
## [0.7.0] - 2026-11-01
|
|
343
|
+
|
|
344
|
+
### Experimental (opt-in)
|
|
345
|
+
|
|
346
|
+
Turn folding and final-reply framing are experimental and disabled by default. Updating does not enable
|
|
347
|
+
them. To try both, merge these keys into the `tidy` object in `~/.pi/agent/settings.json`:
|
|
348
|
+
|
|
349
|
+
```json
|
|
350
|
+
{
|
|
351
|
+
"tidy": {
|
|
352
|
+
"collapseTurns": "afterRun",
|
|
353
|
+
"frameFinalReply": true
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
The two keys work independently. Use `collapseTurns: "live"` to fold while the run is still active.
|
|
359
|
+
To disable them, restore `collapseTurns: "off"` and `frameFinalReply: false`. Restart Pi after upgrading
|
|
360
|
+
to load the new rendering patches.
|
|
361
|
+
|
|
362
|
+
**A run can fold to one summary.** `tidy.collapseTurns` takes `off` (default), `afterRun` or `live`. One run
|
|
363
|
+
follows steering, retries and automatic continuations until pi settles. Its summary sits at the top of the turn
|
|
364
|
+
and reads wall time, the main model's request time, the union of top-level tool time, per-tool call counts and
|
|
365
|
+
failure counts; failures stay named inline. Click it, or use `/tidy turn [N|last]`, to open the process; the row
|
|
366
|
+
stays in place and folds it again, with the pointer band and hand. `ctrl+o` still controls tool outputs and their
|
|
367
|
+
turn. Metadata is saved outside model context and restored on the active branch; older turns show `—` for the
|
|
368
|
+
timings they never recorded.
|
|
369
|
+
|
|
370
|
+
**Frame the final reply.** `tidy.frameFinalReply: true` frames only the settled final text, full width,
|
|
371
|
+
with that message's model and a dim italic `HH:MM` (`MM-DD` for older messages). It can be enabled without
|
|
372
|
+
turn folding.
|
|
373
|
+
|
|
374
|
+
### Added
|
|
375
|
+
|
|
376
|
+
**User frames carry a clock and can align right.** The clock appears next to the user icon. Set
|
|
377
|
+
`tidy.userMessageAlign: "right"` for right alignment; it defaults to `"left"` and requires
|
|
378
|
+
`tidy.userMessageStyle: "frame"` with `tidy.frameMessages: true` (both defaults).
|
|
379
|
+
|
|
380
|
+
**File tools put their title in the border.** read/edit/write boxes carry the kind icon and path in the top
|
|
381
|
+
border; the body starts with the result or diff. `write` no longer leaves a gap under its title.
|
|
382
|
+
|
|
383
|
+
### Fixed
|
|
384
|
+
|
|
385
|
+
- A framed `codemode` box puts its summary row in the top border, where read/edit/write put their path
|
|
386
|
+
(`╭─ ✓ codemode bash×1 read×4 0.1s ─╮`), and the body starts with the script's fold row. It was the one box
|
|
387
|
+
whose title stayed inside the frame.
|
|
388
|
+
- The final reply's border names the model that answered, not the provider (`╭─ 🐳 deepseek-v4-pro 14:03 ─╮`). The
|
|
389
|
+
provider keeps the glyph. A model id too long for the border is clipped with `…` instead of dropping the whole
|
|
390
|
+
label.
|
|
391
|
+
- Folded turns preserve tool group boundaries, so thinking counts and rows stay with their own groups after
|
|
392
|
+
restoring or expanding a turn, including groups split by `alwaysShowTools`.
|
|
393
|
+
- Hovering a turn summary no longer highlights the first tool group header too, or vice versa.
|
|
394
|
+
- OSC 133 zone markers stay outside the final frame. A zone that started after the left border made Ghostty
|
|
395
|
+
cache the row and paint the first answer line blank; selection then exposed stale copies of it.
|
|
396
|
+
- The final frame contains only the answer; the final message's thinking is not drawn inside it.
|
|
397
|
+
- A group's `N thoughts` no longer over-counts when a streaming step turns into a boundary: the run
|
|
398
|
+
counted as a carrier is given back when its text arrives. Thanks to @ncuiigai for reporting the mismatch
|
|
399
|
+
and tracing its cause ([#39](https://github.com/Andy8647/pi-tidy/issues/39)).
|
|
400
|
+
- A pinned, expanded edit no longer leaves pi's bare `Thinking...` above its box.
|
|
401
|
+
- Deepseek uses the whale emoji; Nerd Fonts has no brand glyph for it.
|
|
402
|
+
|
|
403
|
+
## [0.6.3] - 2026-10-31
|
|
404
|
+
|
|
405
|
+
### Added
|
|
406
|
+
|
|
407
|
+
**Tool groups can start open.** Set `tidy.groupOpen: true` to start each new group with its `▾` header
|
|
408
|
+
and one row per call, without opening the calls' full outputs. The default is `false`, so existing
|
|
409
|
+
setups stay unchanged. Clicking the header or using `ctrl+o`'s collapse-all keeps the group folded;
|
|
410
|
+
the setting only decides its initial state. Changes apply to new groups after `/reload`, and fold
|
|
411
|
+
state is not persisted across session restores. Thanks to @dreanzy for the proposal and implementation
|
|
412
|
+
([#37](https://github.com/Andy8647/pi-tidy/pull/37)).
|
|
413
|
+
|
|
414
|
+
## [0.6.2] - 2026-10-30
|
|
415
|
+
|
|
416
|
+
### Fixed
|
|
417
|
+
|
|
418
|
+
**A script's call whose arguments wrap reads as its summary, not as raw JSON.** Inside an open `codemode` box pi
|
|
419
|
+
writes each call's arguments as compact JSON, and wraps a row longer than the box onto the rows below it. tidy glued
|
|
420
|
+
those rows back together to find the arguments and put the summary in their place, but pi's box pads each row out to
|
|
421
|
+
its width, indents the next one and drops the space it broke at, so the glued text never matched the arguments and
|
|
422
|
+
the row kept pi's JSON, clipped with `…`. Below about 200 columns that was every `write` and `edit` and any long
|
|
423
|
+
`bash` command. The rows are now glued back with the one space pi dropped, and matched with spaces let through, so
|
|
424
|
+
the row shows the path or the command like the others, and its duration lines up with theirs again. A row that does
|
|
425
|
+
get clipped keeps its duration's colour: the clip used to take the colour with the arguments and leave the duration
|
|
426
|
+
white.
|
|
427
|
+
|
|
428
|
+
## [0.6.1] - 2026-10-30
|
|
429
|
+
|
|
430
|
+
### Changed
|
|
431
|
+
|
|
432
|
+
**A row you can click shows a hand.** The band that lights a clickable row under the pointer now comes with the
|
|
433
|
+
pointer shape to match: tidy asks the terminal for a hand (OSC 22) while a row is lit and for the arrow again when
|
|
434
|
+
none is, and puts the arrow back before pi leaves the alt screen. Ghostty, kitty, foot and WezTerm draw it; other
|
|
435
|
+
terminals ignore the sequence.
|
|
436
|
+
|
|
437
|
+
**A `codemode` box reads as its call list with grouping off, too**
|
|
438
|
+
([#27](https://github.com/Andy8647/pi-tidy/issues/27)). 0.6.0 built the call list into the group: with
|
|
439
|
+
`groupTools: false` the box was still pi's own — ten lines of script, the last eight calls, the head of the output
|
|
440
|
+
and a `Took` row. Now it is the same list in a frame of its own: the row a group would show for the call
|
|
441
|
+
(`✓ codemode bash×3 read×1 1 failed · 0.1s`) as its title, every call the script made, and the script and the
|
|
442
|
+
output folded to one row each that open on click and light up under the pointer. `ctrl+o`, or a click anywhere
|
|
443
|
+
else in the box, opens both. The list is drawn from a second, expanded rendering of pi's own renderer, so nothing
|
|
444
|
+
is cut short and pi's box is left as it was. The same goes for a grouped session with `codemode` in
|
|
445
|
+
`alwaysShowTools`. Each box keeps its list until something in it changes: 0.6.0 re-decorated every framed
|
|
446
|
+
`codemode` box on every frame, which on a session of 300 scripts cost about 38 ms a frame; it is under 2 ms now.
|
|
447
|
+
Thanks to @indesperate for asking for the call list in the first place and for noticing it was missing with
|
|
448
|
+
grouping off.
|
|
449
|
+
|
|
450
|
+
**Thinking is tidy's row with grouping off, too.** The thinking row was wired into grouping, so with
|
|
451
|
+
`groupTools: false` every step left pi's bare `Thinking...` floating over its box. The row has nothing to do with
|
|
452
|
+
folding calls: with grouping off each step's thinking is now the same `thinking` row a message that writes text
|
|
453
|
+
gets inside a group — the brain, one line of what it thought, a click to open it in its box — and the step loses
|
|
454
|
+
pi's padding rows the way it does with grouping on.
|
|
455
|
+
|
|
456
|
+
**An open thinking box carries its label in the border.** Opening a message's thinking used to keep the
|
|
457
|
+
` thinking Now demo…` row above the box, repeating the box's first words. The row now folds into the box's
|
|
458
|
+
top border, `╭─ thinking ───╮`, so the open box is one row shorter and still says what it holds; a click
|
|
459
|
+
anywhere on it, the border included, folds it back into the row.
|
|
460
|
+
|
|
461
|
+
### Fixed
|
|
462
|
+
|
|
463
|
+
**bash's `Command exited with code N` trailer comes off a failed call inside a script.** 0.6.0 said so, but
|
|
464
|
+
it only matched the row without pi's box around it: drawn for real, the row is one cell further in, and the
|
|
465
|
+
trailer stayed, two blank rows above it.
|
|
466
|
+
|
|
467
|
+
**Long sessions scroll smoothly again.** pi's fullscreen mode draws the whole transcript on every frame — every
|
|
468
|
+
wheel tick, every streamed token, every hover change — and three things tidy draws were rebuilt from scratch each
|
|
469
|
+
time. Edit boxes were the worst: the side-by-side diff had a cache with room for one diff, so with more than one
|
|
470
|
+
edit in the transcript each box pushed out the one before it, and every frame re-parsed and re-highlighted every
|
|
471
|
+
diff in the history. The lag grew with the number of edits, which is why only long sessions felt it. On a
|
|
472
|
+
1,500-message session with 121 edits a scroll frame took about 50 ms (pi on its own: under 1 ms); it takes about
|
|
473
|
+
1.4 ms now. The diff is kept per box, and so are each group's summary line and each message's thinking rows, each
|
|
474
|
+
rebuilt only when what it shows changes. Nothing looks different.
|
|
475
|
+
|
|
476
|
+
**…and with every box open, too.** With `ctrl+o`'s expand-all on, each opened call's rows went through a
|
|
477
|
+
trailing-whitespace regex that is quadratic on a padded row (the padding is followed by a colour reset, so it
|
|
478
|
+
never sits at the end), and the same session took about 250 ms a frame. It is about 24 ms now, with nothing
|
|
479
|
+
looking different.
|
|
480
|
+
|
|
481
|
+
## [0.6.0] - 2026-10-30
|
|
482
|
+
|
|
483
|
+
### Changed
|
|
484
|
+
|
|
485
|
+
**A `codemode` row says what its script ran.** Nested tool calls never become tool rows of their own, so the
|
|
486
|
+
folded row used to show only the script's first line. It counts them now: `codemode bash×3 read×1 0.1s`, growing
|
|
487
|
+
while the script runs, with a red `1 failed` when a call inside the script failed and the script caught it and
|
|
488
|
+
still succeeded.
|
|
489
|
+
|
|
490
|
+
**Inside the box, the nested calls read like tidy's rows.** pi draws them with the arguments as compact JSON;
|
|
491
|
+
they now carry the same kind icon as the outer rows, and the arguments become the same one-line summary
|
|
492
|
+
(`pwd`, `src/app.ts`, `(+12 lines)` for a multi-line one), read back from `result.details.calls`: JSON when the
|
|
493
|
+
200-character clip survived it, the surviving key when it did not, pi's own text when neither works. bash's
|
|
494
|
+
`Command exited with code N` trailer is dropped from a nested failure, where the error above it already says
|
|
495
|
+
what happened.
|
|
496
|
+
|
|
497
|
+
**The body opens as a call list.** Inside a group, a `codemode` box no longer dumps the script and the output:
|
|
498
|
+
the script folds to `▸ script · 13 lines` and the output to `▸ output · 4 items`, each opening in place on
|
|
499
|
+
click (and lighting up under the pointer, like every other row), with a dim rule between the sections and a
|
|
500
|
+
rail of its own down the body. The call rows take a name column and a duration column, and a nested
|
|
501
|
+
`process start` hangs inside the body with them. A script that called nothing folds the same way, using the
|
|
502
|
+
output's first marker (`==> text N/M <==`, `<console_output>`, `Script error:`) as the boundary. Nothing wraps
|
|
503
|
+
onto a second row: an argument that does not fit is clipped, and the duration is the part that never gives way.
|
|
504
|
+
pi's `Took` row is gone, since the row above the body carries the time. The output stays one block: a script
|
|
505
|
+
builds its `text()` items from whatever it computed, so an item can be a filtered, merged summary of several
|
|
506
|
+
calls and nothing ties it back to the call that fed it.
|
|
507
|
+
|
|
508
|
+
**`bash` takes the md-console glyph.** `fa-terminal` is missing from some monospace Nerd Fonts and drew as a
|
|
509
|
+
blank; `\u{f018d}` renders wherever the rest of the set does. The file-type map's `bash` entry was still on
|
|
510
|
+
codicons' terminal glyph, so shell files and the `bash` tool now agree.
|
|
511
|
+
|
|
512
|
+
**Group rows share a name column.** A call's arguments used to start wherever its name ended, so a list of
|
|
513
|
+
`bash` and `read` and `process` rows had a ragged left edge. The name is padded to the widest one in the group
|
|
514
|
+
(capped at 14 cells, so one long MCP name cannot push everything out of reach), and a thinking row's label
|
|
515
|
+
pads the same way so its text starts in that column too.
|
|
516
|
+
|
|
517
|
+
### Fixed
|
|
518
|
+
|
|
519
|
+
**No blank row above a framed message box.** pi inserts a `Spacer(1)` before a user message and before the
|
|
520
|
+
compaction, branch and skill boxes, and the frame added an empty row of its own on top of it: the box floated
|
|
521
|
+
one row below the transcript, and for the summary boxes that turned pi's filled padding row into a second blank
|
|
522
|
+
one. The top border is the first row now, for all four (the user message's `OSC 133` zone marker moved with it).
|
|
523
|
+
Custom messages keep the spacer, because pi puts no spacer in front of those and it is the only separation they
|
|
524
|
+
have.
|
|
525
|
+
|
|
526
|
+
**A click on message text lands where it is drawn** ([#30](https://github.com/Andy8647/pi-tidy/pull/30), by
|
|
527
|
+
@s5unty). Trimming the message edges and restyling a thinking run changed the layout, but the mouse regions
|
|
528
|
+
kept using the untrimmed one: an interactive Markdown element such as pi-code-render's `[COPY]` had a click
|
|
529
|
+
target a few rows off, and a click outside a thinking run was swallowed instead of reaching the Markdown, which
|
|
530
|
+
left raw code unfoldeable. Rendering and hit testing now go through the same component tree, with one
|
|
531
|
+
coordinate transform for the trimmed rows.
|
|
532
|
+
|
|
533
|
+
## [0.5.0] - 2026-10-30
|
|
534
|
+
|
|
535
|
+
### Changed
|
|
536
|
+
|
|
537
|
+
**User messages are tidy's now, in a frame that hugs them.** pi-starline used to restyle user messages, tied to its
|
|
538
|
+
editor switch: turning Starline's input box off sent the transcript's prompts back to pi's filled block. They are
|
|
539
|
+
tidy's to draw now, independently of Starline, and by default (`userMessageStyle: "frame"`) in tidy's rounded frame,
|
|
540
|
+
as wide as the text plus its inset — a one-word prompt gets a small box, a long one stops at the screen's width —
|
|
541
|
+
with the user icon set into the top border (`╭─ ───╮`), so the text starts clean and copies without it. The
|
|
542
|
+
border is `messageBorderColors.user`.
|
|
543
|
+
|
|
544
|
+
`"rail"` keeps the look pi-starline drew: a full-width rule above and below, an accent `│` and (with `icons`) the
|
|
545
|
+
user icon in front of the text, later rows hanging under it; `userMessagePaddingY` and `userMessageColors` (`rail`,
|
|
546
|
+
`rule`; theme names or `#rrggbb`) tune it. `"off"` leaves pi's look. Both styles render pi's own Markdown child, so
|
|
547
|
+
markdown transformers keep working. `frameUserMessages` is no longer read: `true` asked for what is now the default.
|
|
548
|
+
pi-starline 0.9 drops its own version; with an older pi-starline, Starline's still draws on top.
|
|
549
|
+
|
|
550
|
+
**Your own `!` commands get a frame, marked as yours.** pi drew `!` / `!!` runs between two full-width `bashMode`
|
|
551
|
+
rules, which read like the agent's bash box without its frame. Under `frameMessages` they now get tidy's rounded frame
|
|
552
|
+
with the user icon, the `!` or `!!` that was typed in place of `$`, and the user messages' color — the agent's bash
|
|
553
|
+
box changes color with its state, this one does not, and pi's own `Running...` / `(exit N)` / `(cancelled)` rows report
|
|
554
|
+
the outcome. `!!` stays dim. The 20-row preview and `ctrl+o` are pi's, unchanged.
|
|
555
|
+
|
|
556
|
+
## [0.4.14] - 2026-10-28
|
|
557
|
+
|
|
558
|
+
### Fixed
|
|
559
|
+
|
|
560
|
+
**Background jobs started through codemode are tracked too.** Nested `process start` calls now keep
|
|
561
|
+
independent status rows under their calling tool, including multiple processes started by one script.
|
|
562
|
+
Completion and log-match notifications fold into those rows instead of appearing separately. A script
|
|
563
|
+
failure does not discard jobs it already started, and saved associations survive session restoration.
|
|
564
|
+
Direct starts and processes without a corresponding row keep their existing behaviour.
|
|
565
|
+
|
|
566
|
+
**Each nested process has its own hover and expand target.** Clicking a process no longer expands
|
|
567
|
+
codemode. It opens that process's command, working directory and the last 20 output lines; expanded
|
|
568
|
+
logs update as output arrives. Closing one process leaves its siblings and the script unchanged.
|
|
569
|
+
The group header and collapse-all close child details too. Unavailable logs are reported explicitly,
|
|
570
|
+
and process output is stripped of terminal control sequences before display.
|
|
571
|
+
|
|
572
|
+
## [0.4.13] - 2026-10-27
|
|
573
|
+
|
|
574
|
+
### Fixed
|
|
575
|
+
|
|
576
|
+
**The group header keeps its click when a thinking run above it is expanded.** `installCarrierMouse` answered an
|
|
577
|
+
expanded run before it looked at which row was hit, and the summary line is drawn by the same component, so
|
|
578
|
+
clicking `▾ 3 calls` folded the run instead of shutting the group: the header stayed `▾` and the reasoning
|
|
579
|
+
disappeared. The fold now only answers on the run's own rows.
|
|
580
|
+
|
|
581
|
+
## [0.4.11] - 2026-10-24
|
|
582
|
+
|
|
583
|
+
### Fixed
|
|
584
|
+
|
|
585
|
+
**A user message keeps its own padding while tools are folded.** Grouping trims the blank rows pi pads every
|
|
586
|
+
message with, so a folded group sits against the line above it. A user message is not one of those: it is a
|
|
587
|
+
filled box whose first and last rows are padding *with a background fill*, not empty rows, and the trim
|
|
588
|
+
stripped them as well — the highlighted bubble hugged its text on both sides and the `▸ 2 calls` header
|
|
589
|
+
pressed against it. The boundary wrapper gained an `untrimmed` branch, and the messages that are pi's own
|
|
590
|
+
padded boxes (user, plus custom in the same shape) take it. Assistant steps keep their edges compacted
|
|
591
|
+
around a group, which is what the compacting was for.
|
|
592
|
+
|
|
593
|
+
No setting was added: keeping the padding is now the only behaviour, because the tight version was a
|
|
594
|
+
mistake for messages rather than a preference.
|
|
595
|
+
|
|
596
|
+
Reported by @bumaociyuan (#17) and @frostime (#19); the fix is @bumaociyuan's `untrimmed` change from #18.
|
|
597
|
+
|
|
598
|
+
**Settings are read from the native home directory.** Before `PI_CODING_AGENT_DIR`, the fallback was
|
|
599
|
+
`${HOME}/.pi/agent` with `/tmp` behind it, so a Windows session without `HOME` looked in `/tmp/.pi/agent` and
|
|
600
|
+
silently ran on defaults. It asks `os.homedir()` now, which is right on Windows too.
|
|
601
|
+
|
|
602
|
+
## [0.4.10] - 2026-10-23
|
|
603
|
+
|
|
604
|
+
### Fixed
|
|
605
|
+
|
|
606
|
+
**A multi-line argument no longer paints the rows below it off by a line.** A row is one string in the lines
|
|
607
|
+
array the renderer hands back, and the summary took a call's `command` apart at its first newline but passed
|
|
608
|
+
every other argument through whole. So a tool whose first string argument is a script
|
|
609
|
+
(`chrome-devtools_evaluate_script`'s `function`, most MCP tools) returned a "row" with real newlines in it:
|
|
610
|
+
the terminal drew four physical rows where pi's frame counted one, and every row below painted off by the
|
|
611
|
+
difference. What you saw was the last few lines of a script sitting in the middle of the transcript, with
|
|
612
|
+
`Working` wedged between them and the durations stranded on their own rows.
|
|
613
|
+
|
|
614
|
+
Every argument now goes through the same rule: first line, then `(+N lines)` for the rest, trimmed. That is
|
|
615
|
+
also what the collapsed row has always claimed, so a script now reads as `evaluate_script () => { (+3 lines)`.
|
|
616
|
+
|
|
617
|
+
## [0.4.9] - 2026-10-23
|
|
618
|
+
|
|
619
|
+
### Fixed
|
|
620
|
+
|
|
621
|
+
**A thinking row no longer takes the whole message with it.** An assistant step streams as a carrier and
|
|
622
|
+
becomes the group boundary when its text arrives, and the click handler installed while it was a carrier
|
|
623
|
+
stayed on the component: it answered "this is my row" for every `y`, and consumed the click. So on any
|
|
624
|
+
message that had streamed its thinking, clicking the text (a fenced code block included) opened the
|
|
625
|
+
reasoning instead of reaching what was under the pointer. The handler now records the rows it actually
|
|
626
|
+
drew each frame and hands everything else back to the handler it replaced.
|
|
627
|
+
|
|
628
|
+
**One row under a thinking row no longer toggles it.** pi places its own regions on the untrimmed
|
|
629
|
+
layout, and the padding rows this extension trims away move every row by one, so a click on the first
|
|
630
|
+
line below a run landed on pi's hidden label. The runs are ours once restyled — the click table covers
|
|
631
|
+
every one of them, open or shut — so a click that misses them all now falls through instead.
|
|
632
|
+
|
|
633
|
+
## [0.4.8] - 2026-10-23
|
|
634
|
+
|
|
635
|
+
### Added
|
|
636
|
+
|
|
637
|
+
**Thinking is a row inside the group, and it stays live while it arrives.** A model step that only
|
|
638
|
+
thinks and calls a tool used to vanish when you opened a group: its `Thinking...` label was hidden, so
|
|
639
|
+
the transcript showed the call but nothing about the reasoning behind it. Now that step is a `thinking`
|
|
640
|
+
line under the `│` gutter — a brain, the word, then one line of what the model actually thought, above
|
|
641
|
+
the call it belongs to and in transcript order, at one consistent height whether the group is folded or
|
|
642
|
+
open. The summary line counts the runs (`▾ 5 calls · bash×3 · 🧠 4 thoughts · 1 failed · 1.3s`),
|
|
643
|
+
which while folded is the only sign the reply did any thinking at all.
|
|
644
|
+
|
|
645
|
+
- While a run is still arriving, the group keeps one line beneath the summary: a sliding window over the
|
|
646
|
+
*tail* of that thinking, so the newest words are what you see and the row takes the full width. It
|
|
647
|
+
moves on a 300ms tick rather than per frame — pi repaints ~30x/s, and a window recomputed on every
|
|
648
|
+
paint slides a cell per token, which read as flicker — and the cut lands on a word break. The summary
|
|
649
|
+
says `◐ thinking` while it runs and goes back to `N thoughts` once it stops; the row itself does not
|
|
650
|
+
animate. A message's thinking **outside** a group (the label above its text, or a turn that has not
|
|
651
|
+
called a tool yet) is live on the same terms, except that it has no summary above it, so the row wears
|
|
652
|
+
the spinner itself.
|
|
653
|
+
- Live means three things at once: an agent run is open (`agent_start` … `agent_end`/`agent_settled`,
|
|
654
|
+
tracked in a live slot so `/reload` reaches the patches), the message is still streaming, and its text
|
|
655
|
+
grew inside the last 1.5 seconds. Growth is the signal that cannot lie — a run that stops sending
|
|
656
|
+
tokens goes quiet on its own — and a repaint is scheduled for the moment the window lapses, because by
|
|
657
|
+
then pi may have nothing left to paint. A restored session never looks live: a component that arrives
|
|
658
|
+
with its text already finished did not grow in front of us.
|
|
659
|
+
- A click on the row opens that step's thinking: pi renders its own text, untruncated, inside the same
|
|
660
|
+
rounded box a tool result gets — the border uses the new `thinkingColor` (default `warning`). Another
|
|
661
|
+
click folds it back. pi's `thinkingVisibilityOverrides` is the switch behind it, so pi's own click and
|
|
662
|
+
ours cannot disagree about what is open. A message that is nothing but thinking toggles on any click,
|
|
663
|
+
and the hit map is shifted with the rows when padding is trimmed — pi's own region measures the
|
|
664
|
+
untrimmed layout.
|
|
665
|
+
- A message with both thinking **and** text is the group boundary, and its `Thinking...` label used to
|
|
666
|
+
float above the text as bare italic. It now wears the same row — same colour, same format, same
|
|
667
|
+
preview — right where pi draws it, above the text. Its run is **not** added to the group's count: the
|
|
668
|
+
group lists only the runs it folded, and counting one that renders above the text would promise a row
|
|
669
|
+
that opening the group cannot show.
|
|
670
|
+
- The summary line of an open group is carried by the leading thinking row when there is one — a carrier
|
|
671
|
+
renders *before* its own call, so the header would otherwise land under it. Folded, the first call
|
|
672
|
+
still carries the line, which keeps the group's first frame from being blank.
|
|
673
|
+
- pi's `hideThinkingBlock` setting is deliberately ignored: the row is the same whether the setting is
|
|
674
|
+
on or off, and a click is the one way to read the text. One behaviour, not two.
|
|
675
|
+
- The brain is `nf-md-brain`, **U+F09D1** — not the emoji 🧠, which is in no monospace Nerd Font and
|
|
676
|
+
falls back to a two-cell colour glyph that breaks the row it sits in. The preview is capped at **56
|
|
677
|
+
cells**: filling the row turned a glance into a paragraph wedged between the calls.
|
|
678
|
+
|
|
679
|
+
### Changed
|
|
680
|
+
|
|
681
|
+
**An opened call keeps its row.** It used to *become* a box: the row vanished and a framed block took
|
|
682
|
+
its place, which made a group hard to follow — the thing you clicked disappeared. Inside the group the
|
|
683
|
+
rail already says what belongs to what, so a box there was a frame inside a frame. Now the row stays
|
|
684
|
+
where it is (the anchor never moves), takes a tick off the rail (`├─`) and its output hangs underneath —
|
|
685
|
+
without repeating the command, which the row already spells out. Boxes are kept where they earn their
|
|
686
|
+
keep: an `edit`/`write` call (never folded into a group), and a message's own thinking outside one —
|
|
687
|
+
where the expanded run now keeps its `thinking` title above the box.
|
|
688
|
+
|
|
689
|
+
**The metrics sit in columns.** `1 line` / `12 lines` and `2.0s` / `0.1s` used to start wherever the
|
|
690
|
+
arguments happened to end, so a group read as a ragged block of numbers. The note and the duration are
|
|
691
|
+
now padded to the group's widest of each and the whole tail is right-aligned, so every row ends on the
|
|
692
|
+
same cell.
|
|
693
|
+
|
|
694
|
+
**No padding rows left anywhere in the transcript.** The gaps were not the box's spacer but pi's own
|
|
695
|
+
message padding: a user message draws a blank row above and below its text, and an assistant text
|
|
696
|
+
message starts with a `Spacer`. Every message block is now trimmed at both edges — a reply sits directly
|
|
697
|
+
under the prompt, and a group line directly under the text that introduced it. The OSC 133 zone markers
|
|
698
|
+
that ride on those dropped rows move onto the rows that survive, so shell integration (prompt placement,
|
|
699
|
+
`Ctrl+Shift+Up`) is unaffected.
|
|
700
|
+
|
|
701
|
+
### Fixed
|
|
702
|
+
|
|
703
|
+
**A tool row now spends the terminal's width on the command.** The argument column was a fixed 60 cells
|
|
704
|
+
and the row was cut at the right edge afterwards, which meant on a narrow terminal the
|
|
705
|
+
`51 lines · 1.6s` went first and a chopped command stayed behind — and on a wide one the command was
|
|
706
|
+
still cut at cell 60 with 80 cells of row left empty. The row now measures what it has: the arguments
|
|
707
|
+
fill the space left after the tail, the `(+12 lines)` marker is dropped before the command is shortened,
|
|
708
|
+
and the tail only gives way when there is no room for both.
|
|
709
|
+
|
|
710
|
+
**A grouped box no longer opens with a blank row.** pi puts a blank line between a call and its output;
|
|
711
|
+
under the gutter that read as a hole between the row and the box. Inside a group the blank is dropped
|
|
712
|
+
and the click geometry follows it. The split-diff body lost its own blank row under the `↳ diff +N -M`
|
|
713
|
+
summary too: a 20-row diff box was spending three of them on air.
|
|
714
|
+
|
|
715
|
+
## [0.4.7] - 2026-10-21
|
|
716
|
+
|
|
717
|
+
### Changed
|
|
718
|
+
|
|
719
|
+
**The copy no longer says "Claude Code-style".** The comparison set the wrong expectations and invited
|
|
720
|
+
the wrong argument: the parts that carry this extension — split diffs with word-level emphasis,
|
|
721
|
+
failures pinned at level 1 while the rest of the group is folded, live background-job rows, the
|
|
722
|
+
per-tool never-fold list — do not exist there. The README, the npm description and the cover now say
|
|
723
|
+
what the extension does instead of what it resembles. `claude-code` stays a search keyword, because
|
|
724
|
+
that is what people type when they want this interaction.
|
|
725
|
+
|
|
726
|
+
The cover also shows the split edit diff (`old │ new`) rather than the old stacked one, at 16:9.
|
|
727
|
+
|
|
728
|
+
## [0.4.6] - 2026-10-20
|
|
729
|
+
|
|
730
|
+
### Fixed
|
|
731
|
+
|
|
732
|
+
**Tidy no longer registers any tools, so sandbox extensions can load alongside it.** Registering a
|
|
733
|
+
tool under a built-in name is a hard failure in pi (`Tool "write" conflicts with
|
|
734
|
+
…/pi-tidy/index.ts`), and Tidy did it for `bash` (to highlight the command row) and, since 0.4.4, for
|
|
735
|
+
`write` (to make the preview height a setting). Any extension that legitimately owns those tools — a
|
|
736
|
+
sandbox such as pi-playpen, which must wrap execution or lose its enforcement — could therefore not
|
|
737
|
+
be installed at the same time. Both now travel as a `pi.registerToolRenderer()` resolver: the
|
|
738
|
+
installed tool keeps execution, schema, shell and result renderer, and `next()` hands Tidy the
|
|
739
|
+
downstream renderers so the call row can be replaced and the collapsed preview budget lowered on top
|
|
740
|
+
of whatever it returned.
|
|
741
|
+
|
|
742
|
+
- `bash`: the command row is still syntax highlighted and still folds to one line while collapsed,
|
|
743
|
+
and `bashResultLines` still caps the output preview. The `startedAt`/`endedAt` state pi's own
|
|
744
|
+
result renderer reads for its `Took 1.2s` footer is still maintained (we own the call renderer, so
|
|
745
|
+
nobody else would). `highlightBash: false` leaves bash completely untouched.
|
|
746
|
+
- `write`: unchanged behaviour, now on top of whichever result renderer is downstream instead of
|
|
747
|
+
pi's built-in one.
|
|
748
|
+
- `pi ≥ 1.3` is required for those two features. On an older pi they are skipped and a single warning
|
|
749
|
+
names what is unavailable, and only when the setting was actually changed away from pi's own
|
|
750
|
+
default — someone who never touched `writeLines` is not lectured.
|
|
751
|
+
|
|
752
|
+
Thanks to @s5unty for the diagnosis, the constraint that made the alternative (asking a sandbox
|
|
753
|
+
extension to stand down) unacceptable, and the write half in #8.
|
|
754
|
+
|
|
755
|
+
## [0.4.5] - 2026-10-20
|
|
756
|
+
|
|
757
|
+
### Added
|
|
758
|
+
|
|
759
|
+
**`diffLines`: the edit box's height is a setting.** pi's edit renderer draws the entire diff, collapsed
|
|
760
|
+
or not — a large edit owns the screen no matter what `alwaysShowTools` says. The collapsed box now
|
|
761
|
+
draws at most `diffLines` rows (default 20), windowed at the *first changed line* with a third of the
|
|
762
|
+
budget of context above it, and closes with `… (N more lines, M total, ctrl+o to expand)`. Cutting at
|
|
763
|
+
the top of the diff would hide the change itself on a large file, which is why the window follows the
|
|
764
|
+
first change instead. `ctrl+o` draws all of it; `0` keeps just the `↳ diff +N -M` summary.
|
|
765
|
+
|
|
766
|
+
**Hover on folded rows.** Pointing at a group summary line turns `▸` into `▶` and tints the row;
|
|
767
|
+
pointing at a call row in an open group lights that row and shows a `›` at its end. The whole row is
|
|
768
|
+
the click target, so the whole row lights up. Nothing is consumed — pi still receives the packet and
|
|
769
|
+
drag-selection across rows behaves exactly as before — and the band is dropped the moment the pointer
|
|
770
|
+
leaves, via a wrapper over the alt screen's mouse handler. Only available with 1003 all-motion
|
|
771
|
+
tracking, which pi enables outside tmux/screen; inside a multiplexer the rows simply never light up.
|
|
772
|
+
|
|
773
|
+
### Changed
|
|
774
|
+
|
|
775
|
+
**Failures stopped shouting, and stopped taking up room.** A folded group used to hang one red row
|
|
776
|
+
per failed call under its summary. In a 50-call reply with two failures that is a three-line "folded"
|
|
777
|
+
group — the fold accomplishes nothing — and three reds (`1 failed`, `✗`, `exit 1`) described one probe.
|
|
778
|
+
Now level 0 is one line again: the summary carries `2 failed` in red — the colour is the signal, no
|
|
779
|
+
cross beside it — and the failed rows wait in level 1 with the rest. Open the group and each failed row shows its own `✗` (the count goes `muted`,
|
|
780
|
+
so red appears once at either level), its note in `muted` (`exit 1` is data, not an alarm), and — for a
|
|
781
|
+
failure that printed nothing at all (`sed` on a directory, a `test`, anything that only exits
|
|
782
|
+
non-zero) — a whole row dropped to `dim` while keeping the red glyph. A timeout or an abort counts as
|
|
783
|
+
something to read and keeps full contrast. The expanded box's red border is unchanged.
|
|
784
|
+
|
|
785
|
+
## [0.4.4] - 2026-10-20
|
|
786
|
+
|
|
787
|
+
### Added
|
|
788
|
+
|
|
789
|
+
**Side-by-side edit diffs.** An edit's diff is now two panes, `old │ new`, with line numbers on both
|
|
790
|
+
sides, a coloured bar and a tinted row for every changed line, and the changed words emphasised
|
|
791
|
+
inside the line. pi hands its edit renderer a unified diff string, so the panes are re-derived from
|
|
792
|
+
that string (the rendered lines are not reversible) and the row tint is mixed from the theme's diff
|
|
793
|
+
colours — it follows whatever theme is active. Removed and added blocks pair row by row, so a
|
|
794
|
+
replaced block reads as before/after instead of two stacked runs. Below `splitDiffMinWidth` (72 by
|
|
795
|
+
default) the box keeps pi's unified diff; `splitDiff: false` turns it off entirely.
|
|
796
|
+
|
|
797
|
+
The frame keeps the tinted rows' background fill and strips every other one, so the box stays
|
|
798
|
+
transparent everywhere else.
|
|
799
|
+
|
|
800
|
+
**`writeLines`: the write preview's height is a setting.** pi's write box hard-codes ten lines of the
|
|
801
|
+
written file while collapsed. The tool is re-registered (the same way bash already was) with a
|
|
802
|
+
configurable budget: `"writeLines": 10` is pi's number, `0` keeps just the header until `ctrl+o`.
|
|
803
|
+
`alwaysShowTools` remains the switch for whether edits and writes show their own box or fold into
|
|
804
|
+
the group — `[]` folds both.
|
|
805
|
+
|
|
806
|
+
## [0.4.3] - 2026-10-19
|
|
807
|
+
|
|
808
|
+
### Changed
|
|
809
|
+
|
|
810
|
+
**A cover image, a demo video and screenshots.** The README opens with a cover
|
|
811
|
+
and links a 40-second demo; `pi.image` and `pi.video` give the
|
|
812
|
+
[pi package gallery](https://pi.dev/packages) a preview instead of a line of
|
|
813
|
+
text. The media live in `assets/` on GitHub and stay out of the npm tarball.
|
|
814
|
+
|
|
815
|
+
## [0.4.2] - 2026-10-19
|
|
816
|
+
|
|
817
|
+
### Changed
|
|
818
|
+
|
|
819
|
+
**Renamed to pi-tidy.** `@andy8647/pi-toolbox` said nothing about what the
|
|
820
|
+
package does and sat under a personal scope; it is now the unscoped `pi-tidy`,
|
|
821
|
+
and the repository is `Andy8647/pi-tidy` (GitHub redirects the old URLs). Swap
|
|
822
|
+
the package with `pi remove npm:@andy8647/pi-toolbox && pi install npm:pi-tidy`.
|
|
823
|
+
Settings move to a `"tidy"` key; the `"toolbox"` key is still read, so existing
|
|
824
|
+
configs keep working. The old package is deprecated with a pointer here.
|
|
825
|
+
|
|
826
|
+
**Peer dependencies are `*` again**, as pi asks of extensions. 0.4.0 set them to
|
|
827
|
+
`>=1.1.0`, but npm treats a peer conflict as an error for the whole install, so
|
|
828
|
+
one mismatched range can block every package in pi's directory — an older pi
|
|
829
|
+
now gets a warning at session start instead.
|
|
830
|
+
|
|
831
|
+
## [0.4.1] - 2026-10-19
|
|
832
|
+
|
|
833
|
+
### Added
|
|
834
|
+
|
|
835
|
+
**Background jobs on the row that started them.** A `process start` call
|
|
836
|
+
(pi-processes) finishes in milliseconds while the process it started runs on, so
|
|
837
|
+
the row used to say `✓ … 0.0s` and the process's life showed up as separate
|
|
838
|
+
`[process] …` messages further down. The row now tracks the process:
|
|
839
|
+
`◐ process ticker running 12s · READY matched`, changing in place to
|
|
840
|
+
`✓ … exited 0 · 20s`, `✗ … exit 1 · 3s` or `⊘ … killed SIGTERM · 3s`. A running or
|
|
841
|
+
failed job keeps its row under a folded summary, which spins and counts them
|
|
842
|
+
(`▸ 5 calls · … · ◐ 1 running`); failed jobs count toward `N failed`.
|
|
843
|
+
|
|
844
|
+
The job's notification messages are no longer drawn once its row shows them —
|
|
845
|
+
pi-processes still delivers them to the model, toolbox only skips drawing them;
|
|
846
|
+
a job without a row (one started from `/ps`) keeps its messages. A reloaded
|
|
847
|
+
session is rebuilt from those persisted messages, and a job pi-processes no
|
|
848
|
+
longer knows (a session from an earlier pi) reads `not running` instead of
|
|
849
|
+
spinning forever. The spinner turns once a second for a job's first five
|
|
850
|
+
minutes, then stands still and the clock ticks once a minute, so a dev server
|
|
851
|
+
left running for hours doesn't repaint the transcript every second.
|
|
852
|
+
|
|
853
|
+
This is an adapter: pi has no notion of background jobs, so `background-jobs.ts`
|
|
854
|
+
has a small provider interface and pi-processes (its `processes:*` event
|
|
855
|
+
protocol and `ad-process:notification` messages) is the first provider. If that
|
|
856
|
+
protocol changes, rows simply go back to plain tool rows. New options
|
|
857
|
+
`backgroundJobs` and `hideJobNotifications` (both default `true`).
|
|
858
|
+
|
|
859
|
+
### Fixed
|
|
860
|
+
|
|
861
|
+
**A quick call flashed a row under the summary.** A folded group shows the row
|
|
862
|
+
of a call that is still running — so a call that ran for 40 ms popped out under
|
|
863
|
+
`▸ 4 calls` and folded back a frame later, and a `process start` stopped within
|
|
864
|
+
a second did the same. A running call (or job) now gets its row, and its
|
|
865
|
+
`running …` mention in the summary, after one second; long commands still
|
|
866
|
+
surface, quick ones never move. Likewise a step still streaming its thinking in
|
|
867
|
+
the middle of a group no longer flashes `Thinking...` under the summary before
|
|
868
|
+
its tool call arrives; at the start of a turn, with nothing folded yet, the label
|
|
869
|
+
still shows.
|
|
870
|
+
|
|
871
|
+
The README's "No mouse handling" section described a design removed long ago
|
|
872
|
+
and contradicted the click support; it's rewritten, along with the broken
|
|
873
|
+
screenshot placeholder and a duplicate border-color bullet.
|
|
874
|
+
|
|
875
|
+
## [0.4.0] - 2026-10-19
|
|
876
|
+
|
|
877
|
+
### Added
|
|
878
|
+
|
|
879
|
+
**Grouped tool calls: one line per assistant segment, three levels deep.** A reply
|
|
880
|
+
that ran six tools used to cost six boxes; it now costs one line —
|
|
881
|
+
`▸ 6 calls · bash×4 read×2 · 1.2s` — with the per-tool icons toolbox already
|
|
882
|
+
uses for call rows. Clicking the line turns it into a `▾` header with exactly one
|
|
883
|
+
row per call under a `│` gutter
|
|
884
|
+
(`│ ✓ bash cd ~ && python3 - <<'PY' (+26 lines) 0.1s`); clicking a row opens that
|
|
885
|
+
call's full box (still on the gutter, so it's clear which group it belongs to),
|
|
886
|
+
clicking the box folds it back into its row, and clicking the `▾` header folds the
|
|
887
|
+
whole group — boxes included — back to its summary line.
|
|
888
|
+
|
|
889
|
+
Edits and writes never fold. Their diff is the thing you want to see, so they keep
|
|
890
|
+
pi's own box and end the group before them; the calls after an edit start a new
|
|
891
|
+
group, which keeps the transcript in order. New `alwaysShowTools` option (default
|
|
892
|
+
`["edit", "write"]`, `[]` folds everything).
|
|
893
|
+
|
|
894
|
+
A group is everything between two boundaries: a user message, or an assistant
|
|
895
|
+
message with visible text. The text always renders, so a reply that drifts is
|
|
896
|
+
still visible, and each segment keeps its own summary. pi gives every model step
|
|
897
|
+
its own assistant message, and a step that only calls a tool has no text — those
|
|
898
|
+
steps don't split the group, and their `Thinking...` label folds away with it,
|
|
899
|
+
reappearing next to that call's box when you open it. The running tool keeps its
|
|
900
|
+
own row under the summary so a long command doesn't look frozen.
|
|
901
|
+
|
|
902
|
+
Running and failed calls keep their own row under a folded summary — a failure
|
|
903
|
+
should never hide inside `▸ 6 calls` — and the summary counts them
|
|
904
|
+
(`▸ 6 calls · … · 1 failed · 1.2s`). Clicking any row opens that call's box,
|
|
905
|
+
including those two under a folded summary. Every row also says what the call
|
|
906
|
+
produced, Claude Code style: `12 lines`, `3 matches`, `no files`, `exit 1` for the
|
|
907
|
+
built-in tools (truncated output reports the original total); other tools get no
|
|
908
|
+
note rather than a guessed one.
|
|
909
|
+
|
|
910
|
+
`ctrl+o` expands every box (thinking included, like pi's native transcript), and
|
|
911
|
+
pressing it again folds every group back to its summary line; pi's own click on a
|
|
912
|
+
full box folds just that box. Membership is derived at render time from transcript
|
|
913
|
+
order, so groups survive a session reload without persisting anything. New
|
|
914
|
+
`groupTools` option (default `true`).
|
|
915
|
+
|
|
916
|
+
### Changed
|
|
917
|
+
|
|
918
|
+
**Requires pi ≥ 1.1.0** (peer dependencies were `*`). Component mouse events
|
|
919
|
+
arrived in 0.86 and tool durations in 1.1.0; on anything older the groups can't
|
|
920
|
+
be opened and the summary has no times. The dev dependencies moved from 0.82 to
|
|
921
|
+
1.3, so the tests now run pi's real click dispatch instead of a stand-in — the
|
|
922
|
+
stand-in is how a `button: "left"` vs `0` mismatch went unnoticed.
|
|
923
|
+
|
|
924
|
+
**Settings apply on `/reload`.** The prototype patches are installed once per
|
|
925
|
+
process, and used to keep the options of the first load; a reload's new settings
|
|
926
|
+
(including `enabled: false` and `frameMessages: false`) were silently dropped.
|
|
927
|
+
The patches now read their options from a global slot each load updates.
|
|
928
|
+
|
|
929
|
+
**Bash call rows collapse to one line by default.** The call row rendered the
|
|
930
|
+
command verbatim, so a heredoc (`python3 - <<'PY'` plus forty lines of body) or a
|
|
931
|
+
long `&&` chain filled the box before the command had even run, pushing every
|
|
932
|
+
previous tool call off screen. The collapsed row now shows the first line only,
|
|
933
|
+
cut at 100 characters (pi's own `COLLAPSED_ARGS_CHARS`, so bash folds like every
|
|
934
|
+
other tool), followed by `(+N more lines, ctrl+o to expand)`. `ctrl+o` still
|
|
935
|
+
gives the whole command back.
|
|
936
|
+
|
|
937
|
+
**Collapsed result previews shrank to one line too.** pi's bash renderer caps the
|
|
938
|
+
collapsed output at a hard-coded `BASH_PREVIEW_LINES = 5` with no setting, so even
|
|
939
|
+
a one-line command cost five output rows. The collapsed view now keeps a single
|
|
940
|
+
row and `ctrl+o` still brings back all of it. New `bashResultLines` option (default
|
|
941
|
+
`1`, `0` hides output until expanded) — applied by lowering the budget on the
|
|
942
|
+
`VisualLinePreview` pi built, so timers, truncation warnings and image fallbacks
|
|
943
|
+
stay pi's own.
|
|
944
|
+
|
|
945
|
+
`frame.ts` is split by job (`frame-draw.ts`, `tool-frame.ts`, `tool-group-view.ts`,
|
|
946
|
+
`message-frame.ts`); it keeps re-exporting the same API.
|
|
947
|
+
|
|
948
|
+
### Fixed
|
|
949
|
+
|
|
950
|
+
**Clicking a framed box toggled the wrong row — or nothing at all.** pi maps a
|
|
951
|
+
click on a box through its own unframed layout, and for `renderShell: "self"`
|
|
952
|
+
tools (edit, and MCP tools via pi-mcp-adapter) through a height that only pi's
|
|
953
|
+
own render records; toolbox replaces that render, so those clicks were always
|
|
954
|
+
dropped. Clicks are now translated through the frame's geometry into the source
|
|
955
|
+
component's coordinates and reach pi's own toggle.
|
|
956
|
+
|
|
957
|
+
`formatBashCallHighlighted(args, theme, options?)` takes the new third argument
|
|
958
|
+
(`{ expanded, maxChars, hint }`); omitting it renders the full command, so
|
|
959
|
+
existing callers are unaffected. `collapseBashCommand` is exported for tests.
|
|
960
|
+
|
|
961
|
+
## [0.3.3] - 2026-10-05
|
|
962
|
+
|
|
963
|
+
### Fixed
|
|
964
|
+
|
|
965
|
+
**A running tool box no longer freezes on a stale frame.** The frame cache
|
|
966
|
+
keyed on `(line count, first line, last line)`; tool boxes are bordered by
|
|
967
|
+
constant frame and padding rows, so any change confined to the middle left the
|
|
968
|
+
key untouched. A `sleep 580` bash call kept showing `Elapsed 0.0s` until
|
|
969
|
+
something else — a click expanding the box — invalidated the cache. The same
|
|
970
|
+
hole hid streaming output that stayed on the same number of lines. The cache
|
|
971
|
+
now compares the lines it framed, which costs a pointer comparison per row
|
|
972
|
+
while `Box`/`Text` hand back their cached arrays. The message and container box
|
|
973
|
+
caches, which shared the fingerprint helper, were made sound the same way.
|
|
974
|
+
|
|
975
|
+
Also: framing no longer writes into the line array `Text` returns from its
|
|
976
|
+
cache (`content[0] = row` on an untrimmed array duplicated the kind icon on the
|
|
977
|
+
next render).
|
|
978
|
+
|
|
979
|
+
## [0.3.2] - 2026-09-22
|
|
980
|
+
|
|
981
|
+
### Removed
|
|
982
|
+
|
|
983
|
+
**The `collapseAnchor` option and its `(ctrl+o to collapse)` row are gone.**
|
|
984
|
+
The row existed because, before Pi 0.86.0, the only way to close one expanded
|
|
985
|
+
box was `ctrl+o` collapsing every box at once. Pi now toggles a single tool
|
|
986
|
+
box (and compaction/branch/skill message boxes) on a click anywhere in its
|
|
987
|
+
content, so the anchor row is redundant. A `toolbox.collapseAnchor` key in
|
|
988
|
+
`settings.json` is ignored.
|
|
989
|
+
|
|
990
|
+
## [0.3.1] - 2026-09-20
|
|
991
|
+
|
|
992
|
+
### Fixed
|
|
993
|
+
|
|
994
|
+
**File icon placement for home-relative paths.** pi's `renderToolPath`
|
|
995
|
+
shortens `$HOME` to `~` in the display text, so an edit on
|
|
996
|
+
`~/.pi/agent/settings.json` never contained the raw args path — the icon
|
|
997
|
+
fell back into the prefix (`✏️{} edit ~/.pi/...`) instead of sitting in
|
|
998
|
+
front of the path. The matcher now tries both the raw and the `~`-shortened
|
|
999
|
+
form.
|
|
1000
|
+
|
|
1001
|
+
### Added
|
|
1002
|
+
|
|
1003
|
+
**File icons render in their brand colors, with full-set coverage.** The
|
|
1004
|
+
icon map now contains the complete nvim-web-devicons set — 736 extensions
|
|
1005
|
+
and 1172 special filenames — each with its brand color applied as a
|
|
1006
|
+
truecolor escape (TypeScript blue, Rust orange, Go cyan, ...), like lazyvim
|
|
1007
|
+
and yazi. Unknown extensions fall back to an uncolored generic file icon.
|
|
1008
|
+
Tool-kind icons (FA glyphs) intentionally stay uncolored; they follow the
|
|
1009
|
+
call row.
|
|
1010
|
+
|
|
1011
|
+
### Changed
|
|
1012
|
+
|
|
1013
|
+
**The call row drops the tool-name word for file tools.** With the kind
|
|
1014
|
+
icon in front, ` edit ~/x.ts` reads choppier than
|
|
1015
|
+
` ~/x.ts` — the word is redundant, so read/edit/write rows are
|
|
1016
|
+
just `kind icon + file icon + path`. Rows that don't start with the tool
|
|
1017
|
+
name are left untouched.
|
|
1018
|
+
|
|
1019
|
+
## [0.3.0] - 2026-09-19
|
|
1020
|
+
|
|
1021
|
+
### Added
|
|
1022
|
+
|
|
1023
|
+
**Message boxes get the same rounded transparent frame as tool boxes, each
|
|
1024
|
+
kind in its own border color.** User messages, compaction and branch
|
|
1025
|
+
summaries, skill invocations, and extension custom messages previously kept
|
|
1026
|
+
pi's default filled-background bars, since they never go through
|
|
1027
|
+
`ToolExecutionComponent`. Their components are now patched the same way.
|
|
1028
|
+
User messages keep their OSC 133 zone markers, and custom messages rendered
|
|
1029
|
+
by an extension-provided renderer are left untouched — the renderer owns its
|
|
1030
|
+
styling.
|
|
1031
|
+
|
|
1032
|
+
**Tool boxes can take per-tool border colors and Nerd Font icons.** A
|
|
1033
|
+
successful box uses its tool's configured color instead of green (pending
|
|
1034
|
+
stays grey, errors stay red, unlisted tools take the theme accent), and every
|
|
1035
|
+
box's call row leads with a kind icon — file tools put the target file's
|
|
1036
|
+
nvim-web-devicons glyph right in front of the path (`write /tmp/x.ts`
|
|
1037
|
+
renders ` write /tmp/x.ts`).
|
|
1038
|
+
|
|
1039
|
+
New settings under `toolbox`: `frameMessages` (default `true`) toggles the
|
|
1040
|
+
message frames; `frameUserMessages` (default `false`) opts user messages in
|
|
1041
|
+
— they are skipped by default because pi-starline patches the same
|
|
1042
|
+
prototype, and two render patches on one prototype fight over the output;
|
|
1043
|
+
`icons` (default `true`, requires a Nerd Font) toggles the icons;
|
|
1044
|
+
`toolColors` maps tool names to success border colors (replaces defaults
|
|
1045
|
+
when set); `messageBorderColors` picks a border color per message
|
|
1046
|
+
kind — `user` (`toolTitle`), `compaction` (`customMessageLabel`), `branch`
|
|
1047
|
+
(`mdCode`), `skill` (`accent`), `custom` (`warning`). Values are theme fg
|
|
1048
|
+
color names, so they follow the active theme; tool boxes keep their
|
|
1049
|
+
status-driven grey/green/red.
|
|
1050
|
+
|
|
1051
|
+
## [0.2.3] - 2026-09-18
|
|
1052
|
+
|
|
1053
|
+
### Fixed
|
|
1054
|
+
|
|
1055
|
+
**Bash syntax highlighting can no longer freeze the whole interface.** A `#`
|
|
1056
|
+
that was neither at the start of a word nor inside quotes — `fill:#242f60`,
|
|
1057
|
+
`a#b`, `url#frag` — was treated as a word break that no branch handled. The
|
|
1058
|
+
scanner stopped advancing and pushed empty strings until the process ran out of
|
|
1059
|
+
memory. Because the call row is re-rendered on every tool-argument delta, a
|
|
1060
|
+
streaming command containing one of these deadlocked the TUI: 100% CPU, no
|
|
1061
|
+
repaint, `ctrl+c` unresponsive, and the session file stopped updating. The
|
|
1062
|
+
process could not recover on its own and survived closing the terminal tab.
|
|
1063
|
+
|
|
1064
|
+
Bare `\r` and other non-space whitespace (`\u00a0`, `\v`, `\f`) reached the same
|
|
1065
|
+
dead end, because they are word breaks too.
|
|
1066
|
+
|
|
1067
|
+
The tokenizer now keeps a mid-word `#` inside the word, and the scanner can
|
|
1068
|
+
never loop without consuming a character — an unhandled break character is
|
|
1069
|
+
emitted as plain text instead of spinning. `test/bash-highlight.test.ts` covers
|
|
1070
|
+
the reported shapes, a heredoc with a hex colour, and 400 randomized inputs
|
|
1071
|
+
containing `#`, `\r` and non-ASCII spaces; every case asserts termination (a hang
|
|
1072
|
+
is detected by a worker deadline) and that no character is dropped.
|
|
1073
|
+
|
|
1074
|
+
## [0.2.2] - 2026-08-10
|
|
1075
|
+
|
|
1076
|
+
### Added
|
|
1077
|
+
|
|
1078
|
+
**A collapse anchor row inside expanded tool boxes.** When a tool box is
|
|
1079
|
+
expanded, the frame now ends with a `(ctrl+o to collapse)` row. With
|
|
1080
|
+
[pi-starline](https://github.com/Andy8647/pi-starline) installed the row is
|
|
1081
|
+
clickable (click it to collapse the box again); without Starline it reads as
|
|
1082
|
+
an ordinary keyboard hint — `ctrl+o` really does collapse the box in Pi.
|
|
1083
|
+
Set `toolbox.collapseAnchor: false` to opt out of the row entirely.
|
|
1084
|
+
|
|
1085
|
+
The anchor row is painted by Starline's `expandHintAction` matching it, so
|
|
1086
|
+
neither extension needs to know about the other.
|
|
1087
|
+
|
|
1088
|
+
## [0.2.1] - 2026-07-26
|
|
1089
|
+
|
|
1090
|
+
### Changed
|
|
1091
|
+
|
|
1092
|
+
- Tool boxes stand down when another extension owns the mouse; clicking to
|
|
1093
|
+
expand a box is now opt-in rather than the default.
|
|
1094
|
+
|
|
1095
|
+
## [0.2.0] - 2026-07-26
|
|
1096
|
+
|
|
1097
|
+
### Added
|
|
1098
|
+
|
|
1099
|
+
- Rounded, status-aware tool box frames with bash highlighting.
|
|
1100
|
+
- Click a tool box's border to expand just that box.
|
|
1101
|
+
|
|
1102
|
+
### Removed
|
|
1103
|
+
|
|
1104
|
+
- The fixed-editor-era click-to-expand that required Starline's compositor.
|