pi-zentui 0.16.0 → 0.17.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/README.md +270 -129
- package/extensions/zentui/config.ts +1126 -384
- package/extensions/zentui/editor-metadata-format.ts +6 -6
- package/extensions/zentui/extension-status.ts +8 -7
- package/extensions/zentui/fixed-editor/cluster.ts +55 -66
- package/extensions/zentui/fixed-editor/compositor.ts +448 -338
- package/extensions/zentui/fixed-editor/editor-layout.ts +227 -0
- package/extensions/zentui/fixed-editor/index.ts +29 -20
- package/extensions/zentui/fixed-editor/layout.ts +144 -0
- package/extensions/zentui/fixed-editor/pi-compat.ts +21 -9
- package/extensions/zentui/fixed-editor/terminal-modes.ts +27 -7
- package/extensions/zentui/fixed-editor/types.ts +21 -0
- package/extensions/zentui/footer.ts +134 -85
- package/extensions/zentui/index.ts +723 -206
- package/extensions/zentui/minimalist-editor.ts +420 -0
- package/extensions/zentui/package-version.ts +4 -3
- package/extensions/zentui/project-refresh.ts +22 -11
- package/extensions/zentui/prototype-patch-registry.ts +63 -11
- package/extensions/zentui/selector-border.ts +16 -6
- package/extensions/zentui/settings-command.ts +951 -804
- package/extensions/zentui/state.ts +11 -2
- package/extensions/zentui/style.ts +29 -0
- package/extensions/zentui/ui.ts +608 -66
- package/extensions/zentui/user-message-osc.ts +248 -0
- package/extensions/zentui/user-message-styles.ts +215 -0
- package/extensions/zentui/user-message.ts +74 -127
- package/package.json +4 -2
package/README.md
CHANGED
|
@@ -8,10 +8,13 @@ A Starship-inspired statusline and Opencode-style TUI for [Pi](https://pi.dev).
|
|
|
8
8
|
|
|
9
9
|
## What is this?
|
|
10
10
|
|
|
11
|
-
Zentui
|
|
11
|
+
Zentui styles three major Pi surfaces independently:
|
|
12
12
|
|
|
13
|
-
- **
|
|
14
|
-
- **
|
|
13
|
+
- **Editor** — selectable opencode, low-rail opencode, and minimalist input frames inspired by [Opencode](https://github.com/opencode-ai/opencode)
|
|
14
|
+
- **User messages** — selectable framed, framed copy-friendly, compact, and labeled transcript messages
|
|
15
|
+
- **[Starship](https://starship.rs/) footer** — current directory, Git, runtime, context, tokens, cost, and other configurable segments
|
|
16
|
+
|
|
17
|
+
Editor, User messages, and selector borders use an `enabled` field. Footer uses one `style`: `native`, `starship`, or `hidden`. **Appearance** (selector borders and icons) and **Layout** (the fixed-editor experiment) remain supporting configuration domains.
|
|
15
18
|
|
|
16
19
|
## Features
|
|
17
20
|
|
|
@@ -24,18 +27,55 @@ Zentui brings two popular aesthetics to Pi:
|
|
|
24
27
|
- Optional segments (off by default): selected model/provider, `user@host`, current time, OS icon, session duration, and the **project package version** (e.g. `package.json` → `0.6.0`) — distinct from the runtime segment, which shows the installed toolchain
|
|
25
28
|
- Right side shows context usage, token counts, and cost
|
|
26
29
|
- Built-in footer segments can be shown or hidden individually from `/zentui`
|
|
27
|
-
- Fully custom Starship-style layout via
|
|
30
|
+
- Fully custom Starship-style layout via the `components.footer.styles.starship.format` template string — see [Footer Format Template](#footer-format-template)
|
|
28
31
|
- Third-party Pi extension statuses from `ctx.ui.setStatus()` can be shown on the left,
|
|
29
32
|
middle, or right side, or hidden per status key from `/zentui`
|
|
30
33
|
|
|
31
34
|
### Editor (Opencode-inspired)
|
|
32
35
|
|
|
33
|
-
-
|
|
34
|
-
-
|
|
35
|
-
-
|
|
36
|
-
-
|
|
37
|
-
-
|
|
38
|
-
-
|
|
36
|
+
- `opencode` (default) keeps an accent rail on every interior row
|
|
37
|
+
- `opencode-copy-friendly` (**Opencode (copy-friendly)** in `/zentui`) preserves the low-rail rendering for clean terminal selection
|
|
38
|
+
- `minimalist` moves session name, cost, model, thinking, context, Git, configurable path, Bash state, and turn duration into a rounded frame
|
|
39
|
+
- The selected model label and provider appear inside both Opencode editor variants; the model ID is used by default, while `components.editor.modelLabel: "name"` uses the display name with ID fallback.
|
|
40
|
+
- Opencode autocomplete rows retain Pi's original unframed trailing layout; Minimalist keeps autocomplete inside its rounded frame
|
|
41
|
+
- Configurable model, provider, thinking-level, accent, and border colors
|
|
42
|
+
- **Fixed editor** (experimental, opt-in): pin the editor cluster at the bottom of the terminal while the transcript scrolls above, independently of selected editor and Footer modes
|
|
43
|
+
|
|
44
|
+
Editor previews:
|
|
45
|
+
|
|
46
|
+
```text
|
|
47
|
+
opencode opencode-copy-friendly minimalist
|
|
48
|
+
──────────────────── ──────────────────── ╭─ session ── model ╮
|
|
49
|
+
│
|
|
50
|
+
│ prompt › prompt │ prompt │
|
|
51
|
+
│
|
|
52
|
+
│ metadata metadata ╰─ git ───── path ──╯
|
|
53
|
+
──────────────────── ────────────────────
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### User messages
|
|
57
|
+
|
|
58
|
+
- `framed` (default) preserves the full-width bordered prompt box with an accent rail
|
|
59
|
+
- `framed-copy-friendly` (**Framed (copy-friendly)** in `/zentui`) keeps the full-width horizontal borders and blank spacer rows, removes the copied accent rail, and retains a one-cell leading gutter before body text.
|
|
60
|
+
- `compact` uses only an accent rail, with no border or padding rows
|
|
61
|
+
- `labeled` uses a rounded box with the fixed label `User`
|
|
62
|
+
- Disabling User-message styling delegates byte-for-byte to Pi's native renderer; native is not a style ID
|
|
63
|
+
- No custom `plain` message style is provided
|
|
64
|
+
|
|
65
|
+
```text
|
|
66
|
+
framed framed-copy-friendly
|
|
67
|
+
──────────────────── ────────────────────
|
|
68
|
+
│
|
|
69
|
+
│ Message Message
|
|
70
|
+
│
|
|
71
|
+
──────────────────── ────────────────────
|
|
72
|
+
|
|
73
|
+
compact labeled
|
|
74
|
+
│ Message ╭─ User ───────────╮
|
|
75
|
+
│ Continued │ Message │
|
|
76
|
+
│ Continued │
|
|
77
|
+
╰──────────────────╯
|
|
78
|
+
```
|
|
39
79
|
|
|
40
80
|
### Git Status Icons
|
|
41
81
|
|
|
@@ -130,16 +170,20 @@ pi install git:github.com/lmilojevicc/pi-zentui
|
|
|
130
170
|
|
|
131
171
|
User config lives at `~/.pi/agent/zentui.json`. The file is optional: missing or invalid known values fall back to Zentui defaults, unknown keys are ignored at runtime, and `/zentui` can patch color-source settings, UI feature toggles, built-in footer segment visibility, and active third-party status placements.
|
|
132
172
|
|
|
133
|
-
The interactive `/zentui` menu is split into exactly
|
|
173
|
+
The interactive `/zentui` menu is split into exactly eight component-oriented sections, in this order. Use `Tab` and `Shift+Tab` to switch sections:
|
|
174
|
+
|
|
175
|
+
1. **Appearance** — selector-border enablement, style, and colors; icon mode.
|
|
176
|
+
2. **Editor** — editor enablement, style, colors, model label, border behavior, viewport indicators, and settings for the selected editor style.
|
|
177
|
+
3. **User messages** — message enablement, `framed | framed-copy-friendly | compact | labeled` style selection (including **Framed (copy-friendly)**), and colors.
|
|
178
|
+
4. **Layout** — fixed-editor enablement, mouse scrolling, and copy notices.
|
|
179
|
+
5. **Footer** — `Native | Starship | Hidden` style selection. Starship additionally shows colors, model label, responsive layout, separator, context style, and path display.
|
|
180
|
+
6. **Segments** — visibility toggles for non-Git Starship segments.
|
|
181
|
+
7. **Git** — Starship Git segment and probe controls.
|
|
182
|
+
8. **Extensions** — Starship extension-status placement and color controls for active keys.
|
|
134
183
|
|
|
135
|
-
|
|
136
|
-
2. **Editor** — editor enabled (`features.editor`); editor border color mode (`editorBorderColorMode`); editor model label (`editorModelLabel`); copy-friendly mode (`features.copyFriendly`); viewport indicators (`features.viewportIndicators`); fixed editor (`fixedEditor.enabled`); and, while fixed editor is enabled, mouse scroll (`fixedEditor.mouseScroll`) and copy notice (`fixedEditor.copyNotice`).
|
|
137
|
-
3. **Footer** — status line enabled (`features.statusLine`); responsive footer (`responsiveFooter`); compact footer rows (`compactFooterMaxLines`); context style (`contextStyle`); path display (`pathDisplay.mode`); path depth (`pathDisplay.depth`).
|
|
138
|
-
4. **Segments** — visibility toggles for every non-Git built-in segment under `footerSegments`: `cwd`, `sessionName`, `runtime`, `modelInfo`, `context`, `tokens`, `cost`, `sessionDuration`, `username`, `time`, `os`, and `packageVersion`.
|
|
139
|
-
5. **Git** — Git branch visibility (`footerSegments.gitBranch`); branch length (`gitBranch.maxLength`); Git status visibility (`footerSegments.gitStatus`); Git counts visibility (`footerSegments.gitCounts`); Git commit visibility (`footerSegments.gitCommit`); commit-only-detached (`gitCommit.onlyDetached`); exact-match tag (`gitCommit.showTag`); Git metrics visibility (`footerSegments.gitMetrics`); hide zero metrics (`gitMetrics.onlyNonzero`); ignore submodules (`gitMetrics.ignoreSubmodules`).
|
|
140
|
-
6. **Extensions** — default placement (`extensionStatuses.defaultPlacement`) first, followed by placement (`extensionStatuses.placements[key]`) and color (`extensionStatuses.colorModes[key]`) controls for currently active status keys.
|
|
184
|
+
Editor and User messages retain independent enablement and style configuration. Footer's single style selects Pi's built-in Footer (`Native`), Zentui's Starship Footer, or an owned zero-row Footer (`Hidden`). Color and model-label rows update only their owning component.
|
|
141
185
|
|
|
142
|
-
Free-form values such as custom formats, raw colors/styles, numeric values outside the shown presets, and inactive extension keys remain JSON-only.
|
|
186
|
+
Starship-specific Footer rows are shown only while Starship is selected. The **Segments**, **Git**, and **Extensions** sections remain available for preconfiguration under every Footer style. Free-form values such as custom formats, Opencode metadata format, raw colors/styles, numeric values outside the shown presets, and inactive extension keys remain JSON-only.
|
|
143
187
|
|
|
144
188
|
Useful slash-command shortcuts:
|
|
145
189
|
|
|
@@ -149,10 +193,13 @@ Useful slash-command shortcuts:
|
|
|
149
193
|
/zentui statusline enable
|
|
150
194
|
/zentui statusline disable
|
|
151
195
|
/zentui editor toggle
|
|
196
|
+
/zentui messages enable
|
|
197
|
+
/zentui messages disable
|
|
198
|
+
/zentui messages toggle
|
|
152
199
|
/zentui statusline toggle
|
|
153
|
-
/zentui
|
|
154
|
-
/zentui
|
|
155
|
-
/zentui
|
|
200
|
+
/zentui messages
|
|
201
|
+
/zentui user-messages
|
|
202
|
+
/zentui layout
|
|
156
203
|
/zentui viewport-indicators enable
|
|
157
204
|
/zentui viewport-indicators disable
|
|
158
205
|
/zentui viewport-indicators toggle
|
|
@@ -163,30 +210,125 @@ Useful slash-command shortcuts:
|
|
|
163
210
|
/zentui format clear
|
|
164
211
|
```
|
|
165
212
|
|
|
213
|
+
`footer`, `statusline`, `status`, and `status line` are aliases: enable selects Starship, disable selects Native, and toggle selects Native only from Starship (Native or Hidden toggle to Starship).
|
|
214
|
+
|
|
166
215
|
Default config values — copy this and change any value you want:
|
|
167
216
|
|
|
168
217
|
```json
|
|
169
218
|
{
|
|
170
219
|
"projectRefreshIntervalMs": 30000,
|
|
171
|
-
"
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
220
|
+
"components": {
|
|
221
|
+
"editor": {
|
|
222
|
+
"enabled": true,
|
|
223
|
+
"style": "opencode",
|
|
224
|
+
"colorSource": "theme",
|
|
225
|
+
"borderColorMode": "static",
|
|
226
|
+
"modelLabel": "id",
|
|
227
|
+
"viewportIndicators": true,
|
|
228
|
+
"styles": {
|
|
229
|
+
"opencode": {
|
|
230
|
+
"metadataFormat": "$model $provider( $thinking)"
|
|
231
|
+
},
|
|
232
|
+
"opencode-copy-friendly": {
|
|
233
|
+
"metadataFormat": "$model $provider( $thinking)"
|
|
234
|
+
},
|
|
235
|
+
"minimalist": {
|
|
236
|
+
"pathDisplay": "compact",
|
|
237
|
+
"contextFormat": "percent",
|
|
238
|
+
"contextGauge": false,
|
|
239
|
+
"showSessionName": true,
|
|
240
|
+
"showTimer": true,
|
|
241
|
+
"showCost": true,
|
|
242
|
+
"showGit": true,
|
|
243
|
+
"contextThresholds": {
|
|
244
|
+
"warning": 70,
|
|
245
|
+
"error": 90
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
},
|
|
250
|
+
"userMessages": {
|
|
251
|
+
"enabled": true,
|
|
252
|
+
"style": "framed",
|
|
253
|
+
"colorSource": "theme",
|
|
254
|
+
"styles": {
|
|
255
|
+
"framed": {},
|
|
256
|
+
"framed-copy-friendly": {},
|
|
257
|
+
"compact": {},
|
|
258
|
+
"labeled": {}
|
|
259
|
+
}
|
|
260
|
+
},
|
|
261
|
+
"selectorBorders": {
|
|
262
|
+
"enabled": true,
|
|
263
|
+
"style": "zentui",
|
|
264
|
+
"colorSource": "theme"
|
|
265
|
+
},
|
|
266
|
+
"footer": {
|
|
267
|
+
"style": "starship",
|
|
268
|
+
"colorSource": "theme",
|
|
269
|
+
"modelLabel": "id",
|
|
270
|
+
"styles": {
|
|
271
|
+
"starship": {
|
|
272
|
+
"format": "",
|
|
273
|
+
"responsive": true,
|
|
274
|
+
"compactFormat": "$cwd$wrap(in $session_name)$wrap(on $git_branch) $git_status$wrap$context$wrap_sep$tokens",
|
|
275
|
+
"compactMaxLines": 2,
|
|
276
|
+
"separator": "pipe",
|
|
277
|
+
"contextStyle": "text",
|
|
278
|
+
"contextThresholds": {
|
|
279
|
+
"warning": 70,
|
|
280
|
+
"error": 90
|
|
281
|
+
},
|
|
282
|
+
"pathDisplay": {
|
|
283
|
+
"mode": "basename",
|
|
284
|
+
"depth": 0
|
|
285
|
+
},
|
|
286
|
+
"segments": {
|
|
287
|
+
"cwd": true,
|
|
288
|
+
"sessionName": true,
|
|
289
|
+
"gitBranch": true,
|
|
290
|
+
"gitStatus": true,
|
|
291
|
+
"gitCounts": false,
|
|
292
|
+
"runtime": true,
|
|
293
|
+
"modelInfo": false,
|
|
294
|
+
"context": true,
|
|
295
|
+
"tokens": true,
|
|
296
|
+
"cost": true,
|
|
297
|
+
"sessionDuration": false,
|
|
298
|
+
"username": false,
|
|
299
|
+
"time": false,
|
|
300
|
+
"os": false,
|
|
301
|
+
"packageVersion": false,
|
|
302
|
+
"gitCommit": false,
|
|
303
|
+
"gitMetrics": false
|
|
304
|
+
},
|
|
305
|
+
"gitBranch": {
|
|
306
|
+
"maxLength": "full"
|
|
307
|
+
},
|
|
308
|
+
"gitCommit": {
|
|
309
|
+
"hashLength": 7,
|
|
310
|
+
"onlyDetached": true,
|
|
311
|
+
"showTag": true
|
|
312
|
+
},
|
|
313
|
+
"gitMetrics": {
|
|
314
|
+
"onlyNonzero": true,
|
|
315
|
+
"ignoreSubmodules": false
|
|
316
|
+
},
|
|
317
|
+
"extensionStatuses": {
|
|
318
|
+
"defaultPlacement": "right",
|
|
319
|
+
"placements": {},
|
|
320
|
+
"colorModes": {}
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
}
|
|
183
325
|
},
|
|
184
|
-
"
|
|
185
|
-
"
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
326
|
+
"layout": {
|
|
327
|
+
"fixedEditor": {
|
|
328
|
+
"enabled": false,
|
|
329
|
+
"mouseScroll": true,
|
|
330
|
+
"copyNotice": true
|
|
331
|
+
}
|
|
190
332
|
},
|
|
191
333
|
"icons": {
|
|
192
334
|
"mode": "auto",
|
|
@@ -242,103 +384,67 @@ Default config values — copy this and change any value you want:
|
|
|
242
384
|
"editorThinkingMedium": "thinkingMedium",
|
|
243
385
|
"editorThinkingHigh": "thinkingHigh",
|
|
244
386
|
"editorThinkingXhigh": "thinkingXhigh"
|
|
245
|
-
},
|
|
246
|
-
"colorSources": {
|
|
247
|
-
"starship": "theme",
|
|
248
|
-
"editor": "theme",
|
|
249
|
-
"userMessages": "theme"
|
|
250
|
-
},
|
|
251
|
-
"features": {
|
|
252
|
-
"editor": true,
|
|
253
|
-
"statusLine": true,
|
|
254
|
-
"copyFriendly": false,
|
|
255
|
-
"viewportIndicators": true
|
|
256
|
-
},
|
|
257
|
-
"footerSegments": {
|
|
258
|
-
"cwd": true,
|
|
259
|
-
"sessionName": true,
|
|
260
|
-
"gitBranch": true,
|
|
261
|
-
"gitStatus": true,
|
|
262
|
-
"gitCounts": false,
|
|
263
|
-
"runtime": true,
|
|
264
|
-
"modelInfo": false,
|
|
265
|
-
"context": true,
|
|
266
|
-
"tokens": true,
|
|
267
|
-
"cost": true,
|
|
268
|
-
"sessionDuration": false,
|
|
269
|
-
"username": false,
|
|
270
|
-
"time": false,
|
|
271
|
-
"os": false,
|
|
272
|
-
"packageVersion": false,
|
|
273
|
-
"gitCommit": false,
|
|
274
|
-
"gitMetrics": false
|
|
275
|
-
},
|
|
276
|
-
"gitCommit": {
|
|
277
|
-
"hashLength": 7,
|
|
278
|
-
"onlyDetached": true,
|
|
279
|
-
"showTag": true
|
|
280
|
-
},
|
|
281
|
-
"gitMetrics": {
|
|
282
|
-
"onlyNonzero": true,
|
|
283
|
-
"ignoreSubmodules": false
|
|
284
|
-
},
|
|
285
|
-
"extensionStatuses": {
|
|
286
|
-
"defaultPlacement": "right",
|
|
287
|
-
"placements": {},
|
|
288
|
-
"colorModes": {}
|
|
289
|
-
},
|
|
290
|
-
"fixedEditor": {
|
|
291
|
-
"enabled": false,
|
|
292
|
-
"mouseScroll": true,
|
|
293
|
-
"copyNotice": true
|
|
294
387
|
}
|
|
295
388
|
}
|
|
296
389
|
```
|
|
297
390
|
|
|
298
391
|
- Style values can be Starship/terminal strings (`bold purple`, `fg:202`, `#89b` / `#89b4fa`, `bg:blue fg:bright-green`) or Pi theme tokens (`accent`, `borderMuted`, `thinkingHigh`). Short `#rgb` hex values expand to `#rrggbb`.
|
|
299
392
|
- `projectRefreshIntervalMs`: project status polling interval; `0` disables polling. Values `1..4999` clamp up to `5000` (minimum 5s); invalid/non-finite values fall back to `30000`.
|
|
300
|
-
- `
|
|
301
|
-
- `
|
|
302
|
-
- `
|
|
303
|
-
- `
|
|
304
|
-
- `
|
|
305
|
-
-
|
|
306
|
-
-
|
|
307
|
-
-
|
|
308
|
-
-
|
|
309
|
-
- `
|
|
310
|
-
- `
|
|
311
|
-
- `footerSegments`: show or hide individual built-in footer segments (`cwd`, `sessionName`, `gitBranch`, `gitStatus`, `gitCounts`, `gitCommit`, `gitMetrics`, `runtime`, `modelInfo`, `packageVersion`, `sessionDuration`, `username`, `time`, `os`, `context`, `tokens`, `cost`). `modelInfo` is off by default and shows the selected model plus the provider unless the model label already contains it. Toggle non-Git segments from **Segments** and Git segments from **Git** in `/zentui`.
|
|
312
|
-
- `footerFormat`: optional Starship-style template string that fully controls the footer layout. When set, it overrides `footerSegments`. See [Footer Format Template](#footer-format-template) below. The `/zentui` **Footer** tab configures responsive behavior, compact rows, context style, and path display mode/depth; **Appearance** configures separator and icon mode; **Git** configures branch length; set or clear custom formats with `/zentui format`.
|
|
313
|
-
- `responsiveFooter`: enabled by default. Zentui keeps the current aligned one-row footer while every settings-resolved left/middle/right zone fits without layout truncation. Otherwise it tries two complete left-aligned rows, preferring `left` / `middle right` and then `left middle` / `right`. Only when neither split fits does it use `compactFooterFormat`. Set `false` to restore the legacy one-row fitting behavior. Selection uses measured terminal-cell width, not fixed device breakpoints.
|
|
314
|
-
- `compactFooterFormat`: JSON-only template used by the compact stage. The default keeps cwd, session name, git branch/status, context, and abbreviated token/cache metrics. A top-level `$wrap` is an automatic wrap opportunity: one space on the same row or no space at a row break. `$wrap_sep` is the same kind of boundary but renders the styled ` | ` divider only when its adjacent chunks share a row. Nested uses of either boundary remain empty variables. `$fill` is ignored. A standalone `$extensions` chunk inserts active non-`off` extension statuses in left/middle/right placement order; embedded uses render empty. Custom `footerFormat` values use this built-in compact fallback unless this key is also customized.
|
|
315
|
-
- `compactFooterMaxLines`: `1`, `2`, `3`, or `"unlimited"` (default `2`). Finite limits crop remaining chunks with exactly one trailing `…`. Compact cwd always uses basename mode; cwd/session/branch chunks target half the available row width before final ANSI-aware clamping. `/zentui` exposes the responsive toggle and row limit, while compact format editing remains JSON-only. Pi supplies footer width but no supported viewport-height budget, so `"unlimited"` is explicit.
|
|
316
|
-
- `gitCommit`: Starship [`git_commit`](https://starship.rs/config/#git-commit)-style options for the `gitCommit` footer segment. `hashLength` (default `7`, clamped to `4`–`40`) controls the short-hash display length. `onlyDetached` (default `true`) shows the hash mainly on detached HEAD. `showTag` (default `true`) appends an exact-match tag (`git describe --tags --exact-match HEAD`). The tag probe piggybacks on the existing git refresh — it only runs when both the segment and `showTag` are on, and misses/failures degrade silently.
|
|
317
|
-
- `gitMetrics`: Starship [`git_metrics`](https://starship.rs/config/#git-metrics)-style options for the `gitMetrics` footer segment. Uses `git diff HEAD --numstat` (staged + unstaged combined — the Starship “total dirty” view) to show aggregate `+added −deleted` line counts. `onlyNonzero` (default `true`) omits each zero component independently and hides the segment entirely at `0/0`. `ignoreSubmodules` (default `false`) adds `--ignore-submodules=all`. The numstat diff piggybacks on the existing git refresh and uses a hard 2s timeout; a metrics-only failure degrades silently without discarding fresh branch/status data. On very large monorepos the diff may lag or be omitted on timeout.
|
|
318
|
-
- `extensionStatuses`: controls third-party statuses published by other Pi extensions through `ctx.ui.setStatus()`. `defaultPlacement` and each `placements` value can be `off`, `left`, `middle`, or `right`. The **Extensions** tab in `/zentui` lists only statuses that are currently active. `defaultPlacement` applies only when a status key has no entry in `placements`; keyed overrides always win.
|
|
393
|
+
- `components.editor`: owns editor enablement, `opencode | opencode-copy-friendly | minimalist` style selection, color source, border mode, model label, viewport indicators, and all three editor-style configurations.
|
|
394
|
+
- `components.userMessages`: owns message enablement, `framed | framed-copy-friendly | compact | labeled` style selection, and color source. `framed-copy-friendly` remains Zentui-rendered; disabling the component delegates to Pi's native renderer.
|
|
395
|
+
- `components.selectorBorders`: owns selector-border enablement, the fixed `zentui` style, and its color source.
|
|
396
|
+
- `components.footer`: owns `native | starship | hidden` style selection, Footer color source, Footer model label, and every Starship option under `styles.starship` (formats, segments, context thresholds, path, Git, and extension statuses). Native restores Pi's built-in Footer; Hidden installs an empty component with zero rows.
|
|
397
|
+
- `layout.fixedEditor`: owns fixed-layout enablement, mouse scrolling, and copy notices. Layout activation depends on Pi compatibility inspection, not on Zentui editor/Footer style.
|
|
398
|
+
- Editor and Footer `modelLabel` values are independent and have separate controls in the **Editor** and **Footer** sections.
|
|
399
|
+
- Selector borders support only `zentui`; set their owning `enabled` field to `false` for native Pi behavior.
|
|
400
|
+
- Flat released keys such as `editorStyle`, `features`, `footerFormat`, and `fixedEditor` remain accepted as migration input. `components.footer.enabled` and `features.statusLine` migrate to Starship or Native when no valid Footer style is present; Hidden projects `features.statusLine: false`. Canonical `components` and `layout` paths are the primary JSON interface, and component saves materialize canonical snapshots.
|
|
401
|
+
- Explicit unsupported future component style IDs are preserved unchanged on disk but fail open at runtime: Editor, User-message, and selector-border customization stay disabled, while Footer behavior is Native. Missing, empty, or malformed style values continue normal default and legacy migration behavior.
|
|
402
|
+
- The flat properties returned by `mergeConfig`, `loadConfig`, and save helpers are deprecated compatibility output and will remain available until at least the next major release. This output deprecation is separate from accepted legacy flat JSON input.
|
|
403
|
+
- `polished` and `polished-copy-friendly` remain read-only migration aliases for `opencode` and `opencode-copy-friendly`. Legacy `features.copyFriendly` and the old nested Editor/message `copyFriendly` fields are read-only migration inputs: message copy-friendly `true` selects `framed-copy-friendly` rather than disabling custom rendering. Explicit Editor or User-message style saves remove only the corresponding obsolete nested flag; raw released feature keys, unknown fields, and unknown style data remain preserved as user-owned migration data.
|
|
319
404
|
- The shown `editor*` values match the default `theme` source. Omit those keys to keep Zentui's source-aware defaults when switching between `theme` and `terminal`.
|
|
320
|
-
- `editorAccent` styles
|
|
321
|
-
- `editorPrompt` styles the copy-friendly
|
|
322
|
-
- `editorBorder` styles
|
|
405
|
+
- `editorAccent` styles Editor and User-message accent rails and the labeled message label.
|
|
406
|
+
- `editorPrompt` styles the `opencode-copy-friendly` Editor prompt glyph. Omit it to use `editorAccent`, then the default accent fallback.
|
|
407
|
+
- `editorBorder` styles the `framed` and `framed-copy-friendly` previous-message top/bottom borders and the active editor in static border color mode; the border glyph stays `─`.
|
|
323
408
|
- `editorModel`, `editorProvider`, and `editorThinking*` style the editor metadata. `editorThinking` applies to every non-`off` thinking level unless a level-specific key is set.
|
|
324
409
|
|
|
325
|
-
Tip:
|
|
410
|
+
Tip: with `opencode-copy-friendly`, setting Pi's `editorPaddingX` to `1` in `~/.pi/agent/settings.json` keeps a small left gutter without copying a rail glyph.
|
|
411
|
+
|
|
412
|
+
## Minimalist editor style
|
|
413
|
+
|
|
414
|
+
Set `components.editor.style` to `minimalist` or select it from the `/zentui` **Editor** tab. The rounded frame shows viewport counts, Bash state, the current/completed turn duration, and the explicit Pi session name at top left; cost, model, thinking level, and context usage at top right; viewport count plus Git branch/status at bottom left; and the configured path at bottom right. Unnamed sessions add no placeholder. Autocomplete stays inside the frame when Pi's existing editor output can be split safely. Unknown third-party editor layouts fail open without decoration.
|
|
415
|
+
|
|
416
|
+
The Minimalist editor is inspired by [pi-custom-input](https://github.com/VinhLe1410/pi-custom-input), with an independent implementation in Zentui.
|
|
417
|
+
|
|
418
|
+
While `minimalist` is selected, the `/zentui` **Editor** area shows its focused controls without repeating the style name on every row. Path examples are `src` (`compact`), `zentui/src` (`project`), and `~/Projects/zentui/src` (`full`). Context can render as `11%`, `11%/372k`, or—with the gauge enabled and enough room—`[█░░░░] 11%/372k`. The gauge shortens or disappears before the context text at narrow widths. Session name, timer, cost, and Git can be hidden independently; model, thinking, and context remain structurally stable.
|
|
419
|
+
|
|
420
|
+
Footer visibility is controlled by `components.footer.style`: use `starship`, `native`, or `hidden`. Minimalist editor decoration and the Starship Footer may be shown together, including at narrow widths or after decoration fallback. Minimalist style does not remove Pi's header; the experimental fixed-editor layout remains separate.
|
|
326
421
|
|
|
327
422
|
## Editor Metadata Format
|
|
328
423
|
|
|
329
|
-
Set `
|
|
424
|
+
Set `metadataFormat` under either opencode style in `~/.pi/agent/zentui.json` to customize that style's metadata row. The two variants retain independent values:
|
|
330
425
|
|
|
331
426
|
```json
|
|
332
427
|
{
|
|
333
|
-
"
|
|
428
|
+
"components": {
|
|
429
|
+
"editor": {
|
|
430
|
+
"styles": {
|
|
431
|
+
"opencode": {
|
|
432
|
+
"metadataFormat": "$model_name ($model_id)( · $provider)( · $thinking)( · $session_name)"
|
|
433
|
+
},
|
|
434
|
+
"opencode-copy-friendly": {
|
|
435
|
+
"metadataFormat": "$model( · $provider)"
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
}
|
|
334
440
|
}
|
|
335
441
|
```
|
|
336
442
|
|
|
337
|
-
The syntax follows the
|
|
443
|
+
The syntax follows the Footer Format Template conventions: `$variable` and `${variable}` references, literal text and spaces, and conditional groups `( ... )` that disappear when all variables inside are empty. Unknown variables and `$fill` render empty; `$fill` never creates an editor layout zone because the right side remains reserved for structural Vim status.
|
|
338
444
|
|
|
339
445
|
| Token | Renders |
|
|
340
446
|
| --------------- | --------------------------------------------------------------------------------------------- |
|
|
341
|
-
| `$model` | label selected by `
|
|
447
|
+
| `$model` | label selected by `components.editor.modelLabel` (`id`, or name with ID fallback) |
|
|
342
448
|
| `$model_id` | active Pi model ID |
|
|
343
449
|
| `$model_name` | active Pi model display name; empty when no name is set |
|
|
344
450
|
| `$provider` | provider label using Zentui's existing formatting |
|
|
@@ -351,13 +457,21 @@ Missing, non-string, or empty values use the default `$model $provider( $think
|
|
|
351
457
|
|
|
352
458
|
## Footer Format Template
|
|
353
459
|
|
|
354
|
-
For full control, set a Starship-style
|
|
460
|
+
For full control, set `components.footer.styles.starship.format` to a Starship-style template string. It supports `$variable` and `${variable}` tokens, a special `$fill` token that splits the line into left and right zones, and conditional groups `( ... )` that drop entirely when every nested variable is empty. When set, it overrides `components.footer.styles.starship.segments`; when empty or omitted, the segment layout above is used.
|
|
355
461
|
|
|
356
462
|
A second `$fill` creates a **centered middle zone** — content between the two fills is true-centered (`floor((gap - middle) / 2)`), just like third-party statuses placed `middle`.
|
|
357
463
|
|
|
358
464
|
```json
|
|
359
465
|
{
|
|
360
|
-
"
|
|
466
|
+
"components": {
|
|
467
|
+
"footer": {
|
|
468
|
+
"styles": {
|
|
469
|
+
"starship": {
|
|
470
|
+
"format": "$os $username $cwd($sep$session_name)( on $git_branch)( $git_status)( via $runtime)$fill($context)($sep$tokens)($sep$cost)($sep$time)"
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
}
|
|
361
475
|
}
|
|
362
476
|
```
|
|
363
477
|
|
|
@@ -365,10 +479,20 @@ Center the branch between directory and cost:
|
|
|
365
479
|
|
|
366
480
|
```json
|
|
367
481
|
{
|
|
368
|
-
"
|
|
482
|
+
"components": {
|
|
483
|
+
"footer": {
|
|
484
|
+
"styles": {
|
|
485
|
+
"starship": {
|
|
486
|
+
"format": "$cwd $fill $git_branch $fill $cost"
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
}
|
|
369
491
|
}
|
|
370
492
|
```
|
|
371
493
|
|
|
494
|
+
The released flat `footerFormat` and `footerSegments` keys remain accepted only as legacy migration inputs.
|
|
495
|
+
|
|
372
496
|
### Variables
|
|
373
497
|
|
|
374
498
|
| Token | Aliases | Renders |
|
|
@@ -384,7 +508,7 @@ Center the branch between directory and cost:
|
|
|
384
508
|
| `$git_added` | | added line count (`+N`) |
|
|
385
509
|
| `$git_deleted` | | deleted line count (`−N`) |
|
|
386
510
|
| `$runtime` | | runtime icon + version |
|
|
387
|
-
| `$model` | | selected model label (`
|
|
511
|
+
| `$model` | | selected model label (`components.footer.modelLabel`) |
|
|
388
512
|
| `$provider` | | formatted provider label |
|
|
389
513
|
| `$package` | | project package version, `is <glyph> <version>` (manifest-derived) |
|
|
390
514
|
| `$package_version` | | raw project package version (no icon) |
|
|
@@ -414,16 +538,18 @@ Center the branch between directory and cost:
|
|
|
414
538
|
- Literal text (`on branch`, `using`, `\|`, spaces) is rendered verbatim — you control all spacing.
|
|
415
539
|
- Each variable renders its core value only (no `on`/`via` prefixes); add those words as literal text.
|
|
416
540
|
- Conditional groups: wrap optional pieces in parentheses, e.g. `$cwd( on $git_branch)($git_status)$fill($context)`. If every `$var` inside a group is empty, the whole group (including its literals) is dropped.
|
|
417
|
-
- `$session_name` is available whenever `
|
|
541
|
+
- `$session_name` is available whenever `components.footer.styles.starship.format` is set, independently of `components.footer.styles.starship.segments.sessionName`; use a conditional group such as `($sep$session_name)` so unnamed sessions leave no separator.
|
|
418
542
|
- The built-in wide footer appends cache totals to the token segment, `(sub)` to cost, and `(auto)` to context when available. Custom formats keep `$tokens`, `$cost`, and `$context` backward-compatible and include telemetry only through the atomic variables above.
|
|
419
|
-
- `DEFAULT_COMPACT_FOOTER_FORMAT` omits model/provider and atomic telemetry. Add their variables explicitly to `
|
|
543
|
+
- `DEFAULT_COMPACT_FOOTER_FORMAT` omits model/provider and atomic telemetry. Add their variables explicitly to `components.footer.styles.starship.compactFormat` to opt in at narrow widths. The flat `compactFooterFormat` key is a legacy migration input.
|
|
420
544
|
- Auto-compaction settings refresh on the next normal footer synchronization event. Unsupported Pi capabilities or settings-read errors safely omit optional markers.
|
|
421
545
|
- Unknown `$variables` render empty.
|
|
422
546
|
- Set or clear at runtime: `/zentui format "<template>"` and `/zentui format clear`.
|
|
423
547
|
|
|
424
548
|
## Fixed editor (experimental, opt-in)
|
|
425
549
|
|
|
426
|
-
The fixed
|
|
550
|
+
The fixed layout pins Pi's usable editor cluster at the bottom of the terminal while the transcript scrolls above. It can activate independently of Zentui editor and Footer style; Pi compatibility inspection decides whether it is safe. Hidden contributes zero rows and no spacer. A live Footer style change tears down the compositor, replaces the Footer, and reprobes the new component; reprobe failure leaves ordinary rendering active.
|
|
551
|
+
|
|
552
|
+
At constrained heights, Zentui reserves one transcript row, keeps a complete Zentui editor frame and cursor, then prioritizes active autocomplete, Footer, below-editor widget, above-editor widget, and status. Editor content crops around the cursor; known autocomplete content crops around its selected item. Native and third-party editors are treated as opaque and are either pinned intact or rendered through Pi's normal layout. If the terminal later grows, fixed layout returns automatically without reinstalling the compositor.
|
|
427
553
|
|
|
428
554
|
### How to enable
|
|
429
555
|
|
|
@@ -435,8 +561,10 @@ Or in `~/.pi/agent/zentui.json`:
|
|
|
435
561
|
|
|
436
562
|
```json
|
|
437
563
|
{
|
|
438
|
-
"
|
|
439
|
-
"
|
|
564
|
+
"layout": {
|
|
565
|
+
"fixedEditor": {
|
|
566
|
+
"enabled": true
|
|
567
|
+
}
|
|
440
568
|
}
|
|
441
569
|
}
|
|
442
570
|
```
|
|
@@ -445,19 +573,27 @@ Or in `~/.pi/agent/zentui.json`:
|
|
|
445
573
|
|
|
446
574
|
| Key | Action |
|
|
447
575
|
| --- | ------ |
|
|
448
|
-
| `PageUp` / `PageDown` | Scroll transcript one viewport up/down |
|
|
576
|
+
| `PageUp` / `PageDown` | Scroll transcript one viewport up/down; consumed at either boundary while transcript scrolling exists |
|
|
449
577
|
| `Ctrl+Shift+↑` / `Ctrl+Shift+↓` | Scroll transcript up/down (Kitty protocol variants supported) |
|
|
450
578
|
| `Enter` | Jump to bottom (and submit message) |
|
|
451
579
|
|
|
580
|
+
PageUp/PageDown propagate to Pi when there is no transcript scroll range, while normal-flow fallback is active, or while an overlay owns input.
|
|
581
|
+
|
|
582
|
+
### Graceful cleanup
|
|
583
|
+
|
|
584
|
+
Live disable restores the full scroll region, mouse modes, alternate-scroll behavior, autowrap, cursor visibility, and primary screen before Pi repaints its normal layout. Pi lifecycle shutdown (`/quit`, Ctrl+C, Ctrl+D, SIGHUP, and SIGTERM) performs the same reset without a late repaint into the caller's shell. Cleanup after `SIGKILL`, a fatal crash that prevents Pi's shutdown callback, terminal disconnect, or failure of both terminal writers cannot be guaranteed.
|
|
585
|
+
|
|
452
586
|
### Mouse scroll (default on)
|
|
453
587
|
|
|
454
|
-
Mouse wheel scrolling is enabled by default when the fixed editor is on. Disable it
|
|
588
|
+
Mouse wheel scrolling is enabled by default when the fixed editor is on. Disable it from the `/zentui` **Layout** section or:
|
|
455
589
|
|
|
456
590
|
```json
|
|
457
591
|
{
|
|
458
|
-
"
|
|
459
|
-
"
|
|
460
|
-
|
|
592
|
+
"layout": {
|
|
593
|
+
"fixedEditor": {
|
|
594
|
+
"enabled": true,
|
|
595
|
+
"mouseScroll": false
|
|
596
|
+
}
|
|
461
597
|
}
|
|
462
598
|
}
|
|
463
599
|
```
|
|
@@ -469,8 +605,13 @@ Mouse wheel scrolling is enabled by default when the fixed editor is on. Disable
|
|
|
469
605
|
- **Incompatible with** `pi-powerline-footer`, `@tifan/pi-fixed-editor`, and `pi-sticky-input`. These packages patch the same Pi TUI internals; only one rendering owner can be active at a time.
|
|
470
606
|
- **Alternate screen**: Uses the terminal's alternate screen buffer. Native scrollback history is not accessible while the fixed editor is active.
|
|
471
607
|
- **Pi version fragility**: Patches internal TUI methods (`doRender`, `render`, `terminal.write`, `terminal.rows`) that may change across Pi versions. If the TUI layout is unsupported, Zentui falls back to normal rendering with a console warning.
|
|
608
|
+
- Pi has no Footer getter or Footer-change event. Zentui observes normal third-party takeover through Pi's custom-component disposal callback and will not restore Native afterward. Direct internal mutation, a future Pi version that stops disposing replaced components, and automatic fixed-layout reprobe after third-party replacement cannot be detected.
|
|
472
609
|
- If your terminal is stuck after a crash, run `reset` or restart the terminal.
|
|
473
610
|
|
|
611
|
+
## Acknowledgments
|
|
612
|
+
|
|
613
|
+
The minimalist frame's information hierarchy was inspired by [VinhLe1410/pi-custom-input](https://github.com/VinhLe1410/pi-custom-input) and is integrated with Zentui's existing editor, state, configuration, and compatibility layers.
|
|
614
|
+
|
|
474
615
|
## Requirements
|
|
475
616
|
|
|
476
617
|
- [Pi](https://pi.dev) coding agent 0.80.3 or newer
|