pi-zentui 0.15.1 → 0.17.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/README.md +281 -128
- package/extensions/zentui/config.ts +1147 -377
- 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 +193 -88
- package/extensions/zentui/format.ts +10 -2
- package/extensions/zentui/index.ts +721 -196
- package/extensions/zentui/minimalist-editor.ts +417 -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 +953 -773
- package/extensions/zentui/state.ts +27 -2
- package/extensions/zentui/style.ts +29 -0
- package/extensions/zentui/telemetry.ts +82 -0
- package/extensions/zentui/ui.ts +624 -75
- 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
|
|
|
@@ -21,21 +24,58 @@ Zentui brings two popular aesthetics to Pi:
|
|
|
21
24
|
- `on branch` — git branch with icon
|
|
22
25
|
- `[!?↑]` — git status indicators (modified, untracked, ahead/behind, stashed, etc.)
|
|
23
26
|
- `via v5.5.0` — runtime detection with version and Starship-style Nerd Font runtime/language modules
|
|
24
|
-
- Optional segments (off by default):
|
|
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 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`, `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,29 +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
|
-
|
|
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
|
+
}
|
|
182
325
|
},
|
|
183
|
-
"
|
|
184
|
-
"
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
326
|
+
"layout": {
|
|
327
|
+
"fixedEditor": {
|
|
328
|
+
"enabled": false,
|
|
329
|
+
"mouseScroll": true,
|
|
330
|
+
"copyNotice": true
|
|
331
|
+
}
|
|
189
332
|
},
|
|
190
333
|
"icons": {
|
|
191
334
|
"mode": "auto",
|
|
@@ -241,101 +384,67 @@ Default config values — copy this and change any value you want:
|
|
|
241
384
|
"editorThinkingMedium": "thinkingMedium",
|
|
242
385
|
"editorThinkingHigh": "thinkingHigh",
|
|
243
386
|
"editorThinkingXhigh": "thinkingXhigh"
|
|
244
|
-
},
|
|
245
|
-
"colorSources": {
|
|
246
|
-
"starship": "theme",
|
|
247
|
-
"editor": "theme",
|
|
248
|
-
"userMessages": "theme"
|
|
249
|
-
},
|
|
250
|
-
"features": {
|
|
251
|
-
"editor": true,
|
|
252
|
-
"statusLine": true,
|
|
253
|
-
"copyFriendly": false,
|
|
254
|
-
"viewportIndicators": true
|
|
255
|
-
},
|
|
256
|
-
"footerSegments": {
|
|
257
|
-
"cwd": true,
|
|
258
|
-
"sessionName": true,
|
|
259
|
-
"gitBranch": true,
|
|
260
|
-
"gitStatus": true,
|
|
261
|
-
"gitCounts": false,
|
|
262
|
-
"runtime": true,
|
|
263
|
-
"context": true,
|
|
264
|
-
"tokens": true,
|
|
265
|
-
"cost": true,
|
|
266
|
-
"sessionDuration": false,
|
|
267
|
-
"username": false,
|
|
268
|
-
"time": false,
|
|
269
|
-
"os": false,
|
|
270
|
-
"packageVersion": false,
|
|
271
|
-
"gitCommit": false,
|
|
272
|
-
"gitMetrics": false
|
|
273
|
-
},
|
|
274
|
-
"gitCommit": {
|
|
275
|
-
"hashLength": 7,
|
|
276
|
-
"onlyDetached": true,
|
|
277
|
-
"showTag": true
|
|
278
|
-
},
|
|
279
|
-
"gitMetrics": {
|
|
280
|
-
"onlyNonzero": true,
|
|
281
|
-
"ignoreSubmodules": false
|
|
282
|
-
},
|
|
283
|
-
"extensionStatuses": {
|
|
284
|
-
"defaultPlacement": "right",
|
|
285
|
-
"placements": {},
|
|
286
|
-
"colorModes": {}
|
|
287
|
-
},
|
|
288
|
-
"fixedEditor": {
|
|
289
|
-
"enabled": false,
|
|
290
|
-
"mouseScroll": true,
|
|
291
|
-
"copyNotice": true
|
|
292
387
|
}
|
|
293
388
|
}
|
|
294
389
|
```
|
|
295
390
|
|
|
296
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`.
|
|
297
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`.
|
|
298
|
-
- `
|
|
299
|
-
- `
|
|
300
|
-
- `
|
|
301
|
-
- `
|
|
302
|
-
- `
|
|
303
|
-
-
|
|
304
|
-
-
|
|
305
|
-
-
|
|
306
|
-
-
|
|
307
|
-
-
|
|
308
|
-
- `
|
|
309
|
-
- `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`.
|
|
310
|
-
- `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.
|
|
311
|
-
- `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.
|
|
312
|
-
- `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.
|
|
313
|
-
- `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.
|
|
314
|
-
- `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.
|
|
315
|
-
- `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.
|
|
316
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`.
|
|
317
|
-
- `editorAccent` styles
|
|
318
|
-
- `editorPrompt` styles the copy-friendly
|
|
319
|
-
- `editorBorder` styles the
|
|
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 `─`.
|
|
320
408
|
- `editorModel`, `editorProvider`, and `editorThinking*` style the editor metadata. `editorThinking` applies to every non-`off` thinking level unless a level-specific key is set.
|
|
321
409
|
|
|
322
|
-
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.
|
|
323
421
|
|
|
324
422
|
## Editor Metadata Format
|
|
325
423
|
|
|
326
|
-
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:
|
|
327
425
|
|
|
328
426
|
```json
|
|
329
427
|
{
|
|
330
|
-
"
|
|
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
|
+
}
|
|
331
440
|
}
|
|
332
441
|
```
|
|
333
442
|
|
|
334
|
-
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.
|
|
335
444
|
|
|
336
445
|
| Token | Renders |
|
|
337
446
|
| --------------- | --------------------------------------------------------------------------------------------- |
|
|
338
|
-
| `$model` | label selected by `
|
|
447
|
+
| `$model` | label selected by `components.editor.modelLabel` (`id`, or name with ID fallback) |
|
|
339
448
|
| `$model_id` | active Pi model ID |
|
|
340
449
|
| `$model_name` | active Pi model display name; empty when no name is set |
|
|
341
450
|
| `$provider` | provider label using Zentui's existing formatting |
|
|
@@ -348,13 +457,21 @@ Missing, non-string, or empty values use the default `$model $provider( $think
|
|
|
348
457
|
|
|
349
458
|
## Footer Format Template
|
|
350
459
|
|
|
351
|
-
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.
|
|
352
461
|
|
|
353
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`.
|
|
354
463
|
|
|
355
464
|
```json
|
|
356
465
|
{
|
|
357
|
-
"
|
|
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
|
+
}
|
|
358
475
|
}
|
|
359
476
|
```
|
|
360
477
|
|
|
@@ -362,10 +479,20 @@ Center the branch between directory and cost:
|
|
|
362
479
|
|
|
363
480
|
```json
|
|
364
481
|
{
|
|
365
|
-
"
|
|
482
|
+
"components": {
|
|
483
|
+
"footer": {
|
|
484
|
+
"styles": {
|
|
485
|
+
"starship": {
|
|
486
|
+
"format": "$cwd $fill $git_branch $fill $cost"
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
}
|
|
366
491
|
}
|
|
367
492
|
```
|
|
368
493
|
|
|
494
|
+
The released flat `footerFormat` and `footerSegments` keys remain accepted only as legacy migration inputs.
|
|
495
|
+
|
|
369
496
|
### Variables
|
|
370
497
|
|
|
371
498
|
| Token | Aliases | Renders |
|
|
@@ -381,16 +508,22 @@ Center the branch between directory and cost:
|
|
|
381
508
|
| `$git_added` | | added line count (`+N`) |
|
|
382
509
|
| `$git_deleted` | | deleted line count (`−N`) |
|
|
383
510
|
| `$runtime` | | runtime icon + version |
|
|
511
|
+
| `$model` | | selected model label (`components.footer.modelLabel`) |
|
|
512
|
+
| `$provider` | | formatted provider label |
|
|
384
513
|
| `$package` | | project package version, `is <glyph> <version>` (manifest-derived) |
|
|
385
514
|
| `$package_version` | | raw project package version (no icon) |
|
|
386
515
|
| `$session_duration` | `$duration` | session running time |
|
|
387
516
|
| `$username` | | `user@host` |
|
|
388
517
|
| `$os` | | operating-system icon |
|
|
389
518
|
| `$time` | | current time `HH:MM` |
|
|
390
|
-
| `$context` | | context usage (text and/or gauge
|
|
391
|
-
| `$tokens` | | input/output
|
|
519
|
+
| `$context` | | context usage (text and/or gauge; finite percentages use one decimal) |
|
|
520
|
+
| `$tokens` | | input/output counts and existing cache-hit percentage |
|
|
521
|
+
| `$cache_read` | | cache-read total (`R1.2k`); empty at zero or when unavailable |
|
|
522
|
+
| `$cache_write` | | cache-write total (`W300`); empty at zero or when unavailable |
|
|
392
523
|
| `$cost` | | session cost |
|
|
393
|
-
| `$
|
|
524
|
+
| `$subscription` | | `(sub)` in subscription mode; otherwise empty |
|
|
525
|
+
| `$auto_compaction` | | `(auto)` when automatic compaction is enabled; otherwise empty |
|
|
526
|
+
| `$sep` | `$separator` | themed `\|` using `colors.separator` |
|
|
394
527
|
| `$fill` | — | special: splits zones |
|
|
395
528
|
|
|
396
529
|
### `$fill` behavior
|
|
@@ -405,13 +538,18 @@ Center the branch between directory and cost:
|
|
|
405
538
|
- Literal text (`on branch`, `using`, `\|`, spaces) is rendered verbatim — you control all spacing.
|
|
406
539
|
- Each variable renders its core value only (no `on`/`via` prefixes); add those words as literal text.
|
|
407
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.
|
|
408
|
-
- `$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.
|
|
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.
|
|
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.
|
|
544
|
+
- Auto-compaction settings refresh on the next normal footer synchronization event. Unsupported Pi capabilities or settings-read errors safely omit optional markers.
|
|
409
545
|
- Unknown `$variables` render empty.
|
|
410
546
|
- Set or clear at runtime: `/zentui format "<template>"` and `/zentui format clear`.
|
|
411
547
|
|
|
412
548
|
## Fixed editor (experimental, opt-in)
|
|
413
549
|
|
|
414
|
-
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.
|
|
415
553
|
|
|
416
554
|
### How to enable
|
|
417
555
|
|
|
@@ -423,8 +561,10 @@ Or in `~/.pi/agent/zentui.json`:
|
|
|
423
561
|
|
|
424
562
|
```json
|
|
425
563
|
{
|
|
426
|
-
"
|
|
427
|
-
"
|
|
564
|
+
"layout": {
|
|
565
|
+
"fixedEditor": {
|
|
566
|
+
"enabled": true
|
|
567
|
+
}
|
|
428
568
|
}
|
|
429
569
|
}
|
|
430
570
|
```
|
|
@@ -433,19 +573,27 @@ Or in `~/.pi/agent/zentui.json`:
|
|
|
433
573
|
|
|
434
574
|
| Key | Action |
|
|
435
575
|
| --- | ------ |
|
|
436
|
-
| `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 |
|
|
437
577
|
| `Ctrl+Shift+↑` / `Ctrl+Shift+↓` | Scroll transcript up/down (Kitty protocol variants supported) |
|
|
438
578
|
| `Enter` | Jump to bottom (and submit message) |
|
|
439
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
|
+
|
|
440
586
|
### Mouse scroll (default on)
|
|
441
587
|
|
|
442
|
-
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:
|
|
443
589
|
|
|
444
590
|
```json
|
|
445
591
|
{
|
|
446
|
-
"
|
|
447
|
-
"
|
|
448
|
-
|
|
592
|
+
"layout": {
|
|
593
|
+
"fixedEditor": {
|
|
594
|
+
"enabled": true,
|
|
595
|
+
"mouseScroll": false
|
|
596
|
+
}
|
|
449
597
|
}
|
|
450
598
|
}
|
|
451
599
|
```
|
|
@@ -457,8 +605,13 @@ Mouse wheel scrolling is enabled by default when the fixed editor is on. Disable
|
|
|
457
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.
|
|
458
606
|
- **Alternate screen**: Uses the terminal's alternate screen buffer. Native scrollback history is not accessible while the fixed editor is active.
|
|
459
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.
|
|
460
609
|
- If your terminal is stuck after a crash, run `reset` or restart the terminal.
|
|
461
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
|
+
|
|
462
615
|
## Requirements
|
|
463
616
|
|
|
464
617
|
- [Pi](https://pi.dev) coding agent 0.80.3 or newer
|