pi-zentui 0.27.1 → 0.29.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 +27 -4
- package/docs/configuration.md +274 -14
- package/docs/footer-format.md +85 -0
- package/extensions/zentui/codex-quota.ts +3 -1
- package/extensions/zentui/config.ts +208 -11
- package/extensions/zentui/custom-variable-demand.ts +61 -0
- package/extensions/zentui/custom-variable-format.ts +79 -0
- package/extensions/zentui/custom-variables.ts +152 -0
- package/extensions/zentui/editor-metadata-format.ts +51 -2
- package/extensions/zentui/editor-mouse.ts +1 -12
- package/extensions/zentui/extension-status-controller.ts +3 -2
- package/extensions/zentui/footer-format.ts +13 -3
- package/extensions/zentui/footer-text.ts +1 -1
- package/extensions/zentui/footer.ts +132 -22
- package/extensions/zentui/host-template-values.ts +28 -0
- package/extensions/zentui/index.ts +339 -236
- package/extensions/zentui/minimalist-editor.ts +347 -9
- package/extensions/zentui/minimalist-settings.ts +118 -0
- package/extensions/zentui/minimalist-template.ts +176 -0
- package/extensions/zentui/omp-editor-frame.ts +148 -0
- package/extensions/zentui/omp-statusline.ts +569 -0
- package/extensions/zentui/omp-template-lookups.ts +533 -0
- package/extensions/zentui/omp-template-metrics.ts +91 -0
- package/extensions/zentui/omp-template-modes.ts +323 -0
- package/extensions/zentui/omp-ui.ts +210 -0
- package/extensions/zentui/project-demand.ts +6 -3
- package/extensions/zentui/selector-border.ts +31 -26
- package/extensions/zentui/settings-command.ts +142 -34
- package/extensions/zentui/settings-keys.ts +1 -1
- package/extensions/zentui/settings-list-selection.ts +1 -18
- package/extensions/zentui/state.ts +9 -6
- package/extensions/zentui/thinking-experimental.ts +4 -15
- package/extensions/zentui/ui.ts +267 -96
- package/extensions/zentui/user-message-styles.ts +18 -11
- package/extensions/zentui/user-message.ts +38 -2
- package/extensions/zentui/working-line.ts +51 -19
- package/omp.ts +153 -0
- package/package.json +40 -5
- package/extensions/zentui/accent-rail-layout-patch.ts +0 -457
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<h1 align="center">Zentui</h1>
|
|
2
2
|
|
|
3
|
-
<p align="center">A modular terminal UI for <a href="https://pi.dev">Pi</a>.</p>
|
|
3
|
+
<p align="center">A modular terminal UI for <a href="https://pi.dev">Pi</a> and <a href="https://omp.sh">Oh My Pi</a>.</p>
|
|
4
4
|
|
|
5
5
|
<p align="center">
|
|
6
6
|
<a href="https://www.npmjs.com/package/pi-zentui"><img alt="npm version" src="https://shieldcn.dev/npm/pi-zentui.svg?variant=outline" /></a>
|
|
@@ -89,6 +89,29 @@ pi install npm:pi-zentui
|
|
|
89
89
|
pi install git:github.com/lmilojevicc/pi-zentui
|
|
90
90
|
```
|
|
91
91
|
|
|
92
|
+
### Oh My Pi
|
|
93
|
+
|
|
94
|
+
Requires OMP **18.4.10 or newer**. From this checkout:
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
# Try without changing installed plugins
|
|
98
|
+
npm run omp:dev
|
|
99
|
+
|
|
100
|
+
# Persistently link the development checkout
|
|
101
|
+
npm run omp:install-local
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
OMP loads `omp.ts` through the package's `omp.extensions` manifest; Pi keeps its existing entrypoint. Configuration is separate: `~/.omp/agent/zentui.json` by default, or the active OMP profile's agent directory.
|
|
105
|
+
|
|
106
|
+
The OMP port is deliberately a small skin: **Editor, User messages, and Statusline only**. `/zentui` has those three sections; Working, thinking, selectors, and summaries remain OMP-owned. Pi keeps the full Zentui component set. Saved choices for unsupported OMP surfaces are not rewritten.
|
|
107
|
+
|
|
108
|
+
Opencode and Minimalist metadata include OMP's supported `fast`/`ultrafast` mode. Existing custom templates are unchanged; add `$fast_mode` explicitly where wanted. Statusline supports the same token independently.
|
|
109
|
+
|
|
110
|
+
OMP also exposes opt-in [template data](./docs/configuration.md#omp-template-data) for session ID, PR number/URL, subagent count, token rate, active processing time, hostname, provider quota, Vim/OMP modes, and collaboration/stream state. Use the same named variables in Opencode metadata, Minimalist slots, or Starship wide/compact formats. Defaults are unchanged; `$usage_quota` explicitly opts into OMP's usage-report API, which may refresh authenticated reports.
|
|
111
|
+
|
|
112
|
+
**Statusline → Starship** replaces OMP's native status content rather than adding another line. **Hidden** suppresses native main status content and shows only permitted extension statuses; **Native** restores OMP's own line. This works with Zentui Editor enabled or disabled. OMP's inert `setFooter()` API is adapted through guarded, session-scoped native renderer decoration; native settings and other sessions/previews are left alone. All built-in composer layouts are supported; unfamiliar frame/message shapes fail open. See [OMP compatibility](./docs/configuration.md#oh-my-pi-compatibility).
|
|
113
|
+
|
|
114
|
+
|
|
92
115
|
## Configure
|
|
93
116
|
|
|
94
117
|
Run `/zentui` inside Pi to configure Appearance, Editor, User messages, Thinking (Experimental), Working line, Footer, and Extension statuses. With Starship selected, Footer contains **Segments →** and **Git →** child pages. Use `Tab` and `Shift+Tab` to switch sections; compact help follows your configured selection keys. Every section has a direct route (for example, `/zentui footer`). `/zentui segments` and `/zentui git` open Footer child pages when Starship is active; under Native or Hidden they open Footer with a requires-Starship explanation. `/zentui extensions` always opens independent default/per-key status visibility, without changing Footer style or saved Starship placement/color preferences. The configured cancel key returns from a child to Footer; at the top level it closes settings. Extension statuses are published keyed Footer statuses, not extension management or Working line integrations. Inactive options retain their saved preferences. Most changes apply live. Active Streaming can switch live to Rail or Tree, and Rail and Tree can switch live between each other. Entering Streaming from a structural mode, first enable, and re-enable after a live disable require restarting Pi. Configuration is saved to:
|
|
@@ -162,13 +185,13 @@ Useful shortcuts:
|
|
|
162
185
|
/zentui format clear
|
|
163
186
|
```
|
|
164
187
|
|
|
165
|
-
**Thinking (Experimental)** uses one private `AssistantMessageComponent` renderer for Rail, Tree, and Streaming, tested against exact Pi versions 0.
|
|
188
|
+
**Thinking (Experimental)** uses one private `AssistantMessageComponent` renderer for Rail, Tree, and Streaming, tested against exact Pi versions 0.85.0 and 0.87.1. It is disabled by default and may break after Pi updates. Zentui installs an enabled startup mode before transcript restoration. A healthy installed controller lets active Streaming switch live to Rail or Tree, and lets Rail and Tree switch live between each other, without reinstalling its patch. Entering Streaming from Rail or Tree saves the choice but keeps the active structural mode until restart. Disabling live restores native thinking and releases Streaming resources. First enable and re-enable after a live disable are also restart-gated. Mode changes while disabled only preconfigure the next enable. Startup failures, missing constructors, incompatible private child layouts, parser limits, theme/render/width errors, and displaced patch ownership fail open to complete native thinking. If cleanup throws while leaving Streaming, disabling still restores native thinking and a structural selection still becomes active; the successful change warns that Streaming is unavailable for the rest of the session.
|
|
166
189
|
|
|
167
190
|
Rail shows every parsed label in each native contiguous thinking run (`│ Label`, with only the open final phase shown as `│ • Label`). Tree independently shows the latest five labels in each run (`├─ · Label`, settled `└─ · Label`, open `└─ • Label`); it never aggregates across intervening text or tool blocks. Rail and Tree follow Pi's thinking visibility. Complete strict SGR styling is stripped before parsing; every other terminal control and unsafe or unstructured content keeps the complete run native. Labels are rendered by fresh host-shaped Pi Markdown instances before cropping, so emphasis, code, links, HTML, LaTeX, custom transforms, and native `thinkingText` styling remain host-controlled. Every label occupies one terminal row: ANSI/OSC/grapheme-aware cropping adds `…` only when needed. Native horizontal padding stays external. Connectors are styled directly with the current theme's `accent` callback on every render, so custom themes control them independently. Hidden native thinking remains hidden and keeps Pi's native hidden label.
|
|
168
191
|
|
|
169
192
|
Streaming retains Pi's host-rendered final five rows under `Thinking 7.1s`, folds completed reasoning under `Thought` or current-session `Thought for 12.3s`, and owns the configured thinking-toggle binding (Ctrl+T by default) only when started in Streaming. Its input listener and timer are acquired only for an enabled Streaming session start; startup acquisition failure uses native thinking and marks Streaming unavailable. Restored completions cannot recover a duration because Pi does not persist the thinking-end timestamp. Expand/refold and lifecycle tracking are bounded to 256 retained assistant components; evicted entries are first restored natively. All modes restore/dispose on shutdown. Thinking (Experimental) never writes the Working line and does not change its existing **Thinking time** option, working text, Footer, Editor, statuses, or model behavior.
|
|
170
193
|
|
|
171
|
-
Pi 0.84 also provides a native fullscreen TUI with a sticky editor and Footer.
|
|
194
|
+
Pi 0.84 also provides a native fullscreen TUI with a sticky editor and Footer. Both tested versions are covered by a fullscreen live-transition PTY smoke in addition to the standard matrix. Zentui does not enable fullscreen automatically; select it from Pi's `/settings`, set `"tuiMode": "fullscreen"` in Pi settings, or launch Pi with `--tui-mode fullscreen`.
|
|
172
195
|
|
|
173
196
|
**Codex quota (opt-in):** Show remaining 5-hour/weekly quota for `openai-codex` through independent Editor and Starship Footer settings, both off by default. See [configuration and private-endpoint limitations](./docs/configuration.md#codex-account-quota), including `$codex_quota` for custom templates.
|
|
174
197
|
|
|
@@ -176,7 +199,7 @@ Minimalist can also show the latest assistant prompt's cache hit rate in its top
|
|
|
176
199
|
|
|
177
200
|
## Requirements
|
|
178
201
|
|
|
179
|
-
- [Pi](https://pi.dev) coding agent 0.
|
|
202
|
+
- [Pi](https://pi.dev) coding agent 0.85.0 or newer
|
|
180
203
|
- A [Nerd Font](https://www.nerdfonts.com/) for Nerd icons; Auto falls back to ASCII when no supported terminal signal is present
|
|
181
204
|
|
|
182
205
|
## Development
|
package/docs/configuration.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
[Back to README](../README.md) · [Footer format template](./footer-format.md)
|
|
4
4
|
|
|
5
|
-
Zentui reads optional user configuration from `~/.pi/agent/zentui.json
|
|
5
|
+
Zentui reads optional user configuration from `~/.pi/agent/zentui.json` in Pi, or `~/.omp/agent/zentui.json` in Oh My Pi. The active host/profile agent-directory override is respected. Missing or invalid known values fall back to defaults. Unknown fields are ignored at runtime but preserved on disk by component save operations where they are user-owned migration or future-style data.
|
|
6
6
|
|
|
7
7
|
## Refresh and cache freshness
|
|
8
8
|
|
|
@@ -201,11 +201,11 @@ Reference only—not a starter file. Prefer the minimal overrides above. Optiona
|
|
|
201
201
|
"viewportIndicators": true,
|
|
202
202
|
"styles": {
|
|
203
203
|
"opencode": {
|
|
204
|
-
"metadataFormat": "$model $provider( $thinking)( $codex_quota)",
|
|
204
|
+
"metadataFormat": "$model $provider( $thinking)( $fast_mode)( $codex_quota)",
|
|
205
205
|
"completionMenu": "palette"
|
|
206
206
|
},
|
|
207
207
|
"opencode-copy-friendly": {
|
|
208
|
-
"metadataFormat": "$model $provider( $thinking)( $codex_quota)",
|
|
208
|
+
"metadataFormat": "$model $provider( $thinking)( $fast_mode)( $codex_quota)",
|
|
209
209
|
"completionMenu": "palette"
|
|
210
210
|
},
|
|
211
211
|
"accent-rail": {
|
|
@@ -422,7 +422,7 @@ Reference only—not a starter file. Prefer the minimal overrides above. Optiona
|
|
|
422
422
|
- Editor `modelLabel` uses `id` by default; `name` uses the display name with ID fallback. Footer has an independent `modelLabel` control.
|
|
423
423
|
- `components.userMessages` owns User-message enablement, `framed | framed-copy-friendly | compact | labeled` style selection, and color source. Disabling it delegates byte-for-byte to Pi's native renderer.
|
|
424
424
|
- `components.thinkingSteps` independently owns opt-in **Thinking (Experimental)** display. It defaults to `{ "enabled": false, "mode": "tree" }`; canonical modes are `rail | tree | streaming`. The former persisted `streaming-experimental` value is accepted only as a migration alias and is normalized to `streaming` on save.
|
|
425
|
-
- All three modes decorate Pi's private host renderer and are tested on exact Pi versions 0.
|
|
425
|
+
- All three modes decorate Pi's private host renderer and are tested on exact Pi versions 0.85.0 and 0.87.1. Active Streaming can switch live to Rail or Tree, and Rail and Tree can switch live between each other. Entering Streaming from a structural mode, first enable, and re-enable after live disable require restart; live disable restores native thinking. Disabled mode changes only preconfigure.
|
|
426
426
|
- `components.workingLine.enabled` is the sole Working-line ownership switch. Thinking (Experimental) never enables, configures, or owns the Working line and leaves the existing **Thinking time** option unchanged.
|
|
427
427
|
- `components.workingLine.placement` (`above | border`) selects the default floating row or the Minimalist/Opencode top border. Accent Rail supports only Above. Disabled, native, unavailable, or unsafe/narrow editors and Pi versions without working-row visibility control fall back to Above without changing saved choices. Legacy `input` normalizes to `above`; the prompt remains available for typing.
|
|
428
428
|
- `components.selectorBorders` owns selector-border enablement, fixed `zentui` style, and color source. Disable it for native Pi behavior.
|
|
@@ -456,7 +456,7 @@ This example enables only Editor quota, without changing any component's style o
|
|
|
456
456
|
|
|
457
457
|
**Custom templates remain authoritative.** Saved nonempty formats, including copies of old defaults, are never rewritten or augmented outside the template. Add `( $codex_quota)` to either Opencode variant's `metadataFormat`, `($sep$codex_quota)` to a Footer wide `format`, or `$wrap_sep($codex_quota)` to `compactFormat`. Tokens remain empty when the corresponding quota toggle is off or the provider is ineligible. Unlike ordinary Footer `segments` flags, quota consent cannot be bypassed by a template.
|
|
458
458
|
|
|
459
|
-
**Compatibility and privacy:** Zentui uses Pi's public active-model metadata, `modelRegistry.getProvider("openai-codex")`, and `getProviderAuth("openai-codex")`, available on
|
|
459
|
+
**Compatibility and privacy:** Zentui uses Pi's public active-model metadata, `modelRegistry.getProvider("openai-codex")`, and `getProviderAuth("openai-codex")`, available on supported Pi 0.85.0 and 0.87.1. Hosts without safe model/provider routing metadata do not collect or display quota; unavailable auth shows placeholders. There is no fallback to private storage or older credential APIs; the Pi minimum is 0.85.0. Auth is sent only to `https://chatgpt.com/backend-api/wham/usage`, with redirects rejected. JWT decoding is limited to the account-routing claim and is not identity verification. An opaque credential change invalidates cached data conservatively.
|
|
460
460
|
|
|
461
461
|
The endpoint is undocumented and may change or reject some plans. Its path and seconds-based window field are corroborated by [OpenAI's Codex client](https://github.com/openai/codex/blob/rust-v0.98.0/codex-rs/backend-client/src/client.rs); this is not a public API guarantee. Automated verification uses synthetic responses, not a live account. No reset times, countdowns, alerts, or quota history are provided.
|
|
462
462
|
|
|
@@ -524,11 +524,7 @@ Set `components.editor.style` to `accent-rail` or select **Accent Rail** in `/ze
|
|
|
524
524
|
|
|
525
525
|
Known autocomplete rows retain Pi's native text, descriptions, and scrolling on the same full-width surface. The selected native `→` becomes the configured rail without replacing Pi's selected-text color. Ambiguous third-party editor layouts fail open using already-rendered native rows.
|
|
526
526
|
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
Set `ZENTUI_DEBUG=1` when launching Pi to log the workaround diagnostic without adding normal UI noise. Maintainers can probe an explicitly installed compatible host with `ZENTUI_TEST_GLOBAL_PI=/path/to/pi npx vitest run test/accent-rail-layout-patch.test.ts -t "explicitly selected"`.
|
|
530
|
-
|
|
531
|
-
`transparent` defaults to `false`. Set it to `true` or select **Transparent** in `/zentui` to remove only Zentui-owned input and autocomplete backgrounds while preserving geometry, rail/text colors, and native autocomplete backgrounds. The rail and gap are rendered decoration, not underlying prompt text; terminal drag or rectangular selection can still include them.
|
|
527
|
+
`transparent` defaults to `false`. In `/zentui editor`, select **Editor style → Accent Rail**, then **Editor background → transparent** directly below it. Choose **filled** to restore Zentui's background. The control changes only `components.editor.styles.accent-rail.transparent`, removing Zentui-owned input and autocomplete backgrounds while preserving geometry, rail/text colors, and native selection backgrounds. It is also available as a saved preference while Editor is disabled. The rail and gap are rendered decoration, not underlying prompt text; terminal drag or rectangular selection can still include them.
|
|
532
528
|
|
|
533
529
|
### Minimalist
|
|
534
530
|
|
|
@@ -538,6 +534,132 @@ Path examples are `src` (`compact`), `zentui/src` (`project`), and `~/Projects/z
|
|
|
538
534
|
|
|
539
535
|
Autocomplete stays inside the frame when Pi output can be split safely. Unknown third-party layouts fail open. Footer visibility remains independently controlled by `components.footer.style`; Minimalist does not remove Pi's header.
|
|
540
536
|
|
|
537
|
+
### Minimalist metadata templates and custom values
|
|
538
|
+
|
|
539
|
+
Minimalist has six independently configurable border slots under
|
|
540
|
+
`components.editor.styles.minimalist.formats`: `topLeft`, `topMiddle`,
|
|
541
|
+
`topRight`, `bottomLeft`, `bottomMiddle`, and `bottomRight`. Missing slots keep
|
|
542
|
+
Zentui's generated layout; an empty string hides that slot's configurable
|
|
543
|
+
metadata. No extra rows are added. Use **Editor → Metadata templates** in
|
|
544
|
+
`/zentui` to edit a slot or **Reset / inherit** to delete its override.
|
|
545
|
+
|
|
546
|
+
Templates use the existing `$variable`, `${variable}`, literal text, and
|
|
547
|
+
conditional `( ... )` grammar. Layout is selected by the six slot names, not
|
|
548
|
+
`$fill`. Viewport counts, Bash mode, and an embedded Working line remain
|
|
549
|
+
operational indicators outside the templates. Explicit templates may show
|
|
550
|
+
metadata whose ordinary visibility toggle is off, but can never bypass Editor
|
|
551
|
+
Codex quota consent. Nothing is appended outside an explicit template.
|
|
552
|
+
|
|
553
|
+
Custom values are published by other extensions. Give them simple local names
|
|
554
|
+
with `variables`, then reference those names in any slot:
|
|
555
|
+
|
|
556
|
+
```json
|
|
557
|
+
{
|
|
558
|
+
"components": {
|
|
559
|
+
"editor": {
|
|
560
|
+
"style": "minimalist",
|
|
561
|
+
"styles": {
|
|
562
|
+
"minimalist": {
|
|
563
|
+
"variables": { "claude_quota": "@scope/usage:quota" },
|
|
564
|
+
"formats": {
|
|
565
|
+
"topMiddle": "$claude_quota",
|
|
566
|
+
"bottomMiddle": "$session_name"
|
|
567
|
+
},
|
|
568
|
+
"extensionColorMode": "original"
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
```
|
|
575
|
+
|
|
576
|
+
**Editor → Custom variable aliases** edits the name-to-publisher-key JSON or
|
|
577
|
+
resets the aliases. Names use letters, digits, and underscores, start with a
|
|
578
|
+
letter or underscore, and cannot replace built-in/structural variables or
|
|
579
|
+
prototype names. At most 16 aliases are accepted; keys are nonempty, at most
|
|
580
|
+
64 UTF-16 code units, and contain no whitespace or terminal controls. Reset
|
|
581
|
+
removes only the edited overrides. Unrelated owners/styles and unknown raw
|
|
582
|
+
configuration remain untouched. These settings never enable Footer or Working
|
|
583
|
+
line.
|
|
584
|
+
|
|
585
|
+
Built-ins are `$model`, `$model_id`, `$model_name`, `$provider`, `$thinking`,
|
|
586
|
+
`$fast_mode`, `$session_name`, `$turn_duration`, `$cost`, `$context`, `$cache_hit`,
|
|
587
|
+
`$codex_quota`, `$cwd`, `$git_branch`, `$git_status`, `$tokens`, `$input_tokens`,
|
|
588
|
+
and `$output_tokens`. `$turn_duration` is current/completed interaction time,
|
|
589
|
+
not total session duration. Existing path, context, separator and color
|
|
590
|
+
preferences still apply. `$sep` (alias `$separator`) uses the configured
|
|
591
|
+
Minimalist dash/dot separator. Prefer optional groups such as
|
|
592
|
+
`$model($sep$thinking)` to avoid separators around empty values.
|
|
593
|
+
|
|
594
|
+
OMP additionally supports the [host template data](#omp-template-data) built-ins
|
|
595
|
+
in all six slots and both Opencode metadata formats. These are separate from
|
|
596
|
+
publisher aliases and are not included in `$extensions`.
|
|
597
|
+
|
|
598
|
+
`$extensions` aggregates published custom values in deterministic key order.
|
|
599
|
+
The generated top-right layout includes it after cost; setting an explicit
|
|
600
|
+
slot lets you move or omit it. Values referenced through an alias anywhere in
|
|
601
|
+
the six effective templates are excluded from the aggregate, avoiding an
|
|
602
|
+
automatic duplicate. This is distinct from Footer's existing extension-status
|
|
603
|
+
integration. Custom values do not automatically consume `ctx.ui.setStatus()`.
|
|
604
|
+
|
|
605
|
+
Centers are terminal-centered and clamped between side labels; they disappear
|
|
606
|
+
whole when they cannot fit. Custom values yield whole before built-in side
|
|
607
|
+
metadata at narrow widths, rather than clipping quotas or activity labels.
|
|
608
|
+
Large aggregates yield as one unit. Literal separators are template-owned;
|
|
609
|
+
use conditional groups around optional values. Width cannot guarantee that
|
|
610
|
+
all configured metadata is visible.
|
|
611
|
+
|
|
612
|
+
**Custom value colors** offers Original (default) and Zentui. Original retains
|
|
613
|
+
safe SGR and HTTP(S) links from the publisher, with closing resets so styles
|
|
614
|
+
cannot leak into borders. Zentui strips publisher styling and applies the
|
|
615
|
+
Editor color source and extension-status fallback style. Newlines and other
|
|
616
|
+
terminal controls are sanitized; no publisher callbacks or commands run while
|
|
617
|
+
rendering.
|
|
618
|
+
|
|
619
|
+
#### Custom-value publisher protocol v1
|
|
620
|
+
|
|
621
|
+
The versioned event-bus protocol publishes data, not a location. Probe before
|
|
622
|
+
each refresh and keep the extension's normal fallback when inactive:
|
|
623
|
+
|
|
624
|
+
```typescript
|
|
625
|
+
const key = "@scope/usage:quota";
|
|
626
|
+
const capability = { supported: false, active: false, key };
|
|
627
|
+
pi.events.emit("zentui:variable-capability", capability);
|
|
628
|
+
|
|
629
|
+
if (capability.active) {
|
|
630
|
+
pi.events.emit("zentui:variable", { key, text: "CC $459/1200" });
|
|
631
|
+
ctx.ui.setStatus(key, undefined); // remove this publisher's own fallback
|
|
632
|
+
} else {
|
|
633
|
+
ctx.ui.setStatus(key, "CC $459/1200");
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
// Remove a value on publisher shutdown or when no longer applicable.
|
|
637
|
+
pi.events.emit("zentui:variable", { key, text: undefined });
|
|
638
|
+
```
|
|
639
|
+
|
|
640
|
+
Zentui adds `version: 1` and `supported: true` to a mutable probe. Optional
|
|
641
|
+
`key` tests demand for that particular publication; without it, `active`
|
|
642
|
+
reports whether any custom value is demanded. Active requires the current TUI
|
|
643
|
+
session and either an owned, enabled, safely decorated Minimalist/Opencode
|
|
644
|
+
editor with a referencing alias or aggregate, or an owned Starship Footer with
|
|
645
|
+
a referencing alias in its wide or responsive compact template. Availability
|
|
646
|
+
is the union of independently owned consumers: disabling Editor never drops a
|
|
647
|
+
value still demanded by Footer. It is not a guarantee of visibility at the
|
|
648
|
+
current width. Startup probes may precede the first safe
|
|
649
|
+
editor render: probe again on the publisher's next refresh. This protocol
|
|
650
|
+
adds no Zentui poller and no capability-change notification.
|
|
651
|
+
|
|
652
|
+
Use stable package-qualified keys. The namespace is global by convention;
|
|
653
|
+
collisions are last-update-wins, and either publisher can remove a shared key.
|
|
654
|
+
At most 16 unique values are retained, with keys up to 64 and raw text up to
|
|
655
|
+
256 UTF-16 code units. Malformed/over-limit updates are ignored; existing
|
|
656
|
+
keys can still update at capacity. Empty text also removes. Positive updates
|
|
657
|
+
while inactive are ignored. Session replacement, shutdown, disable, loss of
|
|
658
|
+
ownership, or loss of template demand drops inactive values; publishers must
|
|
659
|
+
republish after reactivation. Publishers own their refresh resources, data
|
|
660
|
+
freshness, and stale markers. Zentui neither fetches account data nor persists
|
|
661
|
+
these values. Working-line protocol v1 remains unchanged.
|
|
662
|
+
|
|
541
663
|
### Opencode completion menu
|
|
542
664
|
|
|
543
665
|
Both Opencode variants default to `completionMenu: "palette"` and can be configured independently. The transparent palette keeps captured native rows and embedded backgrounds, removes only a recognized selected `→` while preserving native emphasis, omits a narrowly recognized trailing count row such as `(1/47)`, fills available width without adding a background, and adds a bottom separator plus `↑↓ Navigate Enter Use Esc Close`.
|
|
@@ -584,6 +706,7 @@ The configured right zone and Pi's operational right status are right-aligned to
|
|
|
584
706
|
| `$model_name` | display name; empty when unset |
|
|
585
707
|
| `$provider` | formatted provider label |
|
|
586
708
|
| `$thinking` | current level; empty when `off` |
|
|
709
|
+
| `$fast_mode` | OMP's supported `fast` or `ultrafast` selection; empty when off, unsupported, or running Pi |
|
|
587
710
|
| `$session_name` | current Pi session name; empty when unnamed |
|
|
588
711
|
| `$context` | compact current context usage and window, for example `26.8%/272k` |
|
|
589
712
|
| `$tokens` | cumulative session input/output tokens only, for example `↑76k ↓1.6k` |
|
|
@@ -592,9 +715,51 @@ The configured right zone and Pi's operational right status are right-aligned to
|
|
|
592
715
|
|
|
593
716
|
`$context` uses Pi's current context snapshot and the live assistant context override, refreshing on the existing 250 ms streaming render cadence. `$tokens` and `$cache_hit` use authoritative persisted session snapshots, so they update at normal session synchronization boundaries rather than estimating in-progress totals. These variables are independent of Footer visibility, style, color source, and configuration.
|
|
594
717
|
|
|
718
|
+
### Custom values in Opencode metadata
|
|
719
|
+
|
|
720
|
+
Both Opencode styles can reference the same event-bus values used by Minimalist.
|
|
721
|
+
Each style has independent `variables` and `extensionColorMode` settings:
|
|
722
|
+
|
|
723
|
+
```json
|
|
724
|
+
{
|
|
725
|
+
"components": {
|
|
726
|
+
"editor": {
|
|
727
|
+
"styles": {
|
|
728
|
+
"opencode": {
|
|
729
|
+
"variables": { "quota": "@scope/usage:quota" },
|
|
730
|
+
"metadataFormat": "$model( · $quota)$fill($session_name)",
|
|
731
|
+
"extensionColorMode": "original"
|
|
732
|
+
},
|
|
733
|
+
"opencode-copy-friendly": {
|
|
734
|
+
"variables": { "quota": "@scope/usage:quota" },
|
|
735
|
+
"metadataFormat": "$model$fill($quota)"
|
|
736
|
+
}
|
|
737
|
+
}
|
|
738
|
+
}
|
|
739
|
+
}
|
|
740
|
+
}
|
|
741
|
+
```
|
|
742
|
+
|
|
743
|
+
Aliases and these formats are JSON-only for Opencode; Minimalist's settings
|
|
744
|
+
controls still edit only Minimalist. Missing color mode means Original; Zentui
|
|
745
|
+
uses Editor's color source and the historical extension-status fallback style.
|
|
746
|
+
Custom values yield whole before built-in metadata when the row cannot fit.
|
|
747
|
+
No value is automatically appended to an explicit format. Enabling/disabling
|
|
748
|
+
Editor or changing a format never changes Footer choices.
|
|
749
|
+
|
|
750
|
+
Starship independently supports aliases under
|
|
751
|
+
`components.footer.styles.starship.variables` and Original/Zentui under
|
|
752
|
+
`extensionColorMode`; both wide `format` and responsive `compactFormat` can
|
|
753
|
+
reference them. See [custom Footer values](./footer-format.md#custom-extension-values).
|
|
754
|
+
Native/Hidden Footer and existing `setStatus` placement/color choices are
|
|
755
|
+
unchanged. Footer's compact `$extensions` continues to mean Pi's keyed extension
|
|
756
|
+
statuses, not this new variable registry. Removing an alias/format reference
|
|
757
|
+
releases only that consumer's demand; values survive while any other owned
|
|
758
|
+
consumer still references them.
|
|
759
|
+
|
|
595
760
|
Model variables use Editor `colors.model` (legacy `editorModel`), provider uses `colors.provider` (legacy `editorProvider`), and thinking uses the matching Editor level style. Literal text, session name, and usage metadata use the neutral editor-border theme style. ANSI/VT sequences, controls, and line-breaking whitespace are sanitized without collapsing ordinary spaces.
|
|
596
761
|
|
|
597
|
-
Missing, non-string, or empty values use `$model $provider( $thinking)( $codex_quota)`, with identical spacing while
|
|
762
|
+
Missing, non-string, or empty values use `$model $provider( $thinking)( $fast_mode)( $codex_quota)`, with identical Pi spacing while the optional values are empty. OMP's current per-family service tier is checked against the active model's capabilities each render, so `/fast` and model changes do not leave stale indicators. Saved nonempty templates are not rewritten; add `( · $fast_mode)` explicitly to opt in. A non-empty format that resolves to no metadata preserves the normal blank spacer and metadata rows. This option is JSON-only; `/zentui format` controls the Footer.
|
|
598
763
|
|
|
599
764
|
## User-message styles
|
|
600
765
|
|
|
@@ -624,7 +789,7 @@ Only an actually open thinking phase uses `•`; a text/tool transition or resto
|
|
|
624
789
|
|
|
625
790
|
Streaming keeps the reviewed host-rendered behavior: while open it shows the latest five rendered terminal rows beneath `Thinking 7.1s`; completion folds under `Thought` or current-session `Thought for Ns`. Restored entries have no duration because Pi does not persist a reliable thinking-end timestamp. Only a session started in active Streaming owns its validated configured `app.thinking.toggle` binding and one-second timer. Ctrl+T expands/refolds native reasoning. Startup resource failures and private-shape/render failures use complete native thinking. A cleanup callback that throws while leaving Streaming is contained: Rail or Tree remains active, while Streaming becomes unavailable for that session. Component and timing tracking are bounded to 256; evicted entries are restored natively first.
|
|
626
791
|
|
|
627
|
-
The exact all-mode private matrix covers Pi 0.
|
|
792
|
+
The exact all-mode private matrix covers Pi 0.85.0 and 0.87.1 under dark, light, and current themes, narrow/wide widths and resize; both versions also have fullscreen live-transition PTY coverage. Thinking (Experimental) never owns or writes the Working line, including its unchanged **Thinking time** option, and does not own Footer, Editor, widgets, statuses, or model behavior.
|
|
628
793
|
|
|
629
794
|
## Working line
|
|
630
795
|
|
|
@@ -645,7 +810,9 @@ Classic and KITT move color across message and segments. **Animate spinner color
|
|
|
645
810
|
|
|
646
811
|
Both speeds accept `30..1000` ms. Classic/KITT combine both cadences through one Pi Loader interval; exact cycles are used within 1024-frame/512-KiB limits. Pathological custom pairs use a bounded evenly distributed schedule with at most half a spinner-cycle and half a text-step rounding. Legacy `intervalMs` is accepted only as migration input for `spinnerIntervalMs` when the canonical field is absent.
|
|
647
812
|
|
|
648
|
-
Content reserves the complete Tokens label and active extension segments first, then Message, Thought, Elapsed, and Tool allocation, while preserving visual order **Message · Tool · Elapsed · Thought · Tokens · Extensions** within the 80-column Loader-row contract. Active thought starts as `thinking 0s`; completed positive thought becomes `thought for Ns`. Rebuilds preserve spinner and visible color phase.
|
|
813
|
+
Content reserves the complete Tokens label and active extension segments first, then Message, Thought, Elapsed, and Tool allocation, while preserving visual order **Message · Tool · Elapsed · Thought · Tokens · Extensions** within the 80-column Loader-row contract. Active thought starts as `thinking 0s`; completed positive thought becomes `thought for Ns`. Rebuilds preserve spinner and visible color phase.
|
|
814
|
+
|
|
815
|
+
Pi's working-row APIs are global and unkeyed. While owning the row, Zentui reasserts its blank message on owned refreshes/reconciles (even with unchanged frames) and before a Border fallback reveals the Above row. A later external message write or reset can still win until the next such boundary; native spinner ticks alone do not repair it, and there is no added polling. Separate multiline widgets are unaffected; extensions sharing the working-message slot should use keyed segments below instead.
|
|
649
816
|
|
|
650
817
|
### Working-line extension integration
|
|
651
818
|
|
|
@@ -774,7 +941,100 @@ Pi 0.84 adds a native fullscreen TUI with sticky Editor and Footer plus an indep
|
|
|
774
941
|
}
|
|
775
942
|
```
|
|
776
943
|
|
|
777
|
-
Save this in Pi's `~/.pi/agent/settings.json`, select fullscreen in Pi's `/settings`, or use `--tui-mode fullscreen`. Zentui does not enable it automatically. Pi owns layout and scrolling while Zentui supplies configured components. Pi 0.
|
|
944
|
+
Save this in Pi's `~/.pi/agent/settings.json`, select fullscreen in Pi's `/settings`, or use `--tui-mode fullscreen`. Zentui does not enable it automatically. Pi owns layout and scrolling while Zentui supplies configured components. Zentui requires Pi 0.85.0 or newer.
|
|
945
|
+
|
|
946
|
+
## Oh My Pi compatibility
|
|
947
|
+
|
|
948
|
+
OMP 18.4.10+ uses `omp.ts` as a deliberately focused skin for **Editor, User messages, and Statusline only**. `/zentui` defaults to Editor and cycles through those three sections; `/zentui statusline` opens the canonical Footer owner. Footer-local Segments/Git controls and three-owner presets remain available. Working, thinking, selectors, turn summaries, and all-owner migration remain OMP-owned; their saved values are ignored by the focused runtime without being rewritten. Pi's full component set is unchanged.
|
|
949
|
+
|
|
950
|
+
`npm run omp:dev` launches with only this extension; `npm run omp:install-local` links the checkout with `omp plugin link`. OMP remaps shared Pi package imports to its own host modules, avoiding duplicate runtime classes/theme state.
|
|
951
|
+
|
|
952
|
+
| Surface | OMP behavior |
|
|
953
|
+
| --- | --- |
|
|
954
|
+
| Editor | All Zentui styles support OMP's built-in Box, Band, Claude, Pi, Borderless, Rule, Field, and Rail layouts, preserving multiline input, cursor markers, shell submission, and autocomplete. Public composer row capture leaves native input layout/preferences unchanged. Unknown/ambiguous chrome fails open; decorated mouse geometry is not guessed. |
|
|
955
|
+
| Fast mode | `$fast_mode` is `fast` for supported priority service and `ultrafast` for supported OpenAI ultrafast service. Other families' preferences, off/default/flex tiers, and unsupported models render empty. This reports the selected supported tier, not a latency guarantee. |
|
|
956
|
+
| User messages | Normal Markdown messages support Zentui styles. Native image, badge, synthetic, and unfamiliar message surfaces remain native. |
|
|
957
|
+
| Statusline | Starship replaces the native lower status slot and suppresses native attached status content; there is no persistent footer widget or duplicate main line. Hidden suppresses main status content and retains only permitted extension statuses; Native delegates exact native behavior. Editor enablement is independent. |
|
|
958
|
+
|
|
959
|
+
OMP's `setFooter()` is inert, so the adapter decorates exported native status renderers and restores only its own methods. Scope is established by matching session identity and mounted public `editor.composerFacts` identity. Verified ownership survives temporary dialog unmounting, but editor replacement, detached containers, session changes, and foreign method displacement release it; native startup/preview and other sessions remain untouched. The guarded runtime `session` field is the private compatibility boundary—changed/uninspectable shapes fail open to native. Native preferences/status maps are not rewritten. Extension statuses are recorded from successful public publications starting at extension initialization, including earlier `session_start` handlers; publications predating observation cannot be recovered. In TSP terminals, custom status is plain semantic composer text rather than ANSI frame/color parity; host-owned model-picker action/icon chrome remains native.
|
|
960
|
+
|
|
961
|
+
OMP has no public editor-factory getter. Zentui observes public setter descriptors across handler scopes and preserves expanded drafts for its observed editors. Initial replacement is OMP's normal last-writer-wins behavior: an opaque pre-existing editor factory cannot be recovered or wrapped. Once a later setter is observed, cleanup restores only Zentui-owned state. Handler-local dialog cancellation remains scoped to the invoking command.
|
|
962
|
+
|
|
963
|
+
### OMP template data
|
|
964
|
+
|
|
965
|
+
The following explicit Zentui names are available in Opencode/copy-friendly
|
|
966
|
+
`metadataFormat`, all Minimalist slots, and Starship `format`/`compactFormat`.
|
|
967
|
+
OMP segment IDs are not automatically template variables. These names are
|
|
968
|
+
reserved built-ins, not custom publisher aliases; `$extensions` is unchanged.
|
|
969
|
+
Pi and unavailable OMP capabilities render these host values empty.
|
|
970
|
+
|
|
971
|
+
| Variable | Data and distinctions |
|
|
972
|
+
| --- | --- |
|
|
973
|
+
| `$session_id` | Current session's full ID, not its human-readable `$session_name`. |
|
|
974
|
+
| `$pr_number`, `$pr_url` | Current non-default branch's GitHub PR number and safe plain HTTPS URL. |
|
|
975
|
+
| `$subagent_count` | Native active subagent badge count; background Bash/Eval jobs are not subagents. A known zero renders `0`. |
|
|
976
|
+
| `$token_rate` | Output tokens/second, for example `42.5 tok/s`. Uses OMP's last-assistant average; observed live Vibe workers add the current streaming main rate, not an idle previous reply. Unknown timings remain empty. |
|
|
977
|
+
| `$active_time` | Native accumulated active-processing time, including the open interval and excluding idle time, for example `1m 5s`. Not wall-clock `$session_duration` or current/completed `$turn_duration`; a known zero renders `0s`. |
|
|
978
|
+
| `$hostname` | Machine hostname without the username. |
|
|
979
|
+
| `$usage_quota` | Proven current-provider/model/account quota windows, for example `5 Hour: 80% left`. Distinct from independently consented `$codex_quota`. |
|
|
980
|
+
| `$collaboration` | Native role and participant count, for example `host · 3 participants`; participants include the host. |
|
|
981
|
+
| `$stream_state` | Native publisher state and remote viewer count. `live · 0 viewers` is active; no publisher renders empty. |
|
|
982
|
+
| `$vim_mode` | Current native editor `insert`, `normal`, `visual`, or `visual-line` state. Disabled Vim renders empty. |
|
|
983
|
+
| `$plan_mode`, `$goal_mode` | `Plan`/`Goal`, or `Plan paused`/`Goal paused` when the native paused state is known. |
|
|
984
|
+
| `$prewalk_mode` | `Prewalk` while the attached session has a Prewalk target. |
|
|
985
|
+
| `$vibe_mode` | `Vibe` while enabled. |
|
|
986
|
+
| `$loop_mode` | `Loop waiting`, `Loop running`, or `Loop paused`; no loop renders empty. |
|
|
987
|
+
|
|
988
|
+
Defaults and saved templates are never augmented. Add only the desired variables,
|
|
989
|
+
with optional groups around labels:
|
|
990
|
+
|
|
991
|
+
```json
|
|
992
|
+
{
|
|
993
|
+
"components": {
|
|
994
|
+
"editor": {
|
|
995
|
+
"styles": {
|
|
996
|
+
"opencode": {
|
|
997
|
+
"metadataFormat": "$model( · $session_id)( · PR #$pr_number)( · $subagent_count agents)( · $active_time)( · $token_rate)( · $vim_mode)"
|
|
998
|
+
}
|
|
999
|
+
}
|
|
1000
|
+
},
|
|
1001
|
+
"footer": {
|
|
1002
|
+
"styles": {
|
|
1003
|
+
"starship": {
|
|
1004
|
+
"format": "$cwd( · PR #$pr_number)( · $plan_mode)( · $goal_mode)( · $loop_mode)$fill$context",
|
|
1005
|
+
"compactFormat": "$cwd$wrap(PR #$pr_number)$wrap($active_time)$wrap($token_rate)"
|
|
1006
|
+
}
|
|
1007
|
+
}
|
|
1008
|
+
}
|
|
1009
|
+
}
|
|
1010
|
+
}
|
|
1011
|
+
```
|
|
1012
|
+
|
|
1013
|
+
PR data requires a matching GitHub remote, `gh`, and read access. Read-only lookups
|
|
1014
|
+
capture and recheck repository/branch identity, cache for up to 30 seconds, and
|
|
1015
|
+
invalidate on native project/branch changes. No PR, default/detached branches,
|
|
1016
|
+
unavailable tooling, or lookup failure renders empty rather than a placeholder.
|
|
1017
|
+
|
|
1018
|
+
**`$usage_quota` is opt-in by explicit template reference.** It uses the current
|
|
1019
|
+
native session's public usage-report API and declared public account-routing
|
|
1020
|
+
capability, never credentials/keys or private native quota caches. OMP may refresh
|
|
1021
|
+
authenticated reports from its configured providers on a cache miss. Successful
|
|
1022
|
+
snapshots are cached for up to five minutes, shortened by window resets; there
|
|
1023
|
+
is no additional polling timer or default request. Missing identity, ambiguous
|
|
1024
|
+
accounts, mismatched provider/model scopes, failures, and expired windows omit
|
|
1025
|
+
the affected data. A real zero remaining quota stays visible. The Editor and
|
|
1026
|
+
Footer's `$codex_quota` toggles remain separate and are not changed.
|
|
1027
|
+
|
|
1028
|
+
Session ID/hostname use public context/OS data. Other fields require a verified
|
|
1029
|
+
native component/session/editor association even when Footer is Native or Hidden.
|
|
1030
|
+
Current public Vim/session getters take precedence where supported; native
|
|
1031
|
+
Plan/Goal/Vibe pause flags, Loop, collaboration, stream state, and worker-rate
|
|
1032
|
+
callbacks are observed only after successful public publications. Publications
|
|
1033
|
+
predating observation cannot be recovered from private fields. Plan/Goal/Vibe
|
|
1034
|
+
snapshots reset with session identity; native UI-global states stay local to
|
|
1035
|
+
their component across focus changes. Locked or displaced setters disable
|
|
1036
|
+
observation, and disposal restores only still-owned descriptors. All rendered
|
|
1037
|
+
text follows the consuming component's sanitization and local colors.
|
|
778
1038
|
|
|
779
1039
|
## Compatibility and migration
|
|
780
1040
|
|
package/docs/footer-format.md
CHANGED
|
@@ -53,6 +53,9 @@ Show model, provider, and active thinking level in the Footer:
|
|
|
53
53
|
|
|
54
54
|
Add `$model $provider( $thinkingLevel)` to `components.footer.styles.starship.compactFormat` separately to keep these details in compact layouts. Defaults and the built-in Model info segment are unchanged.
|
|
55
55
|
|
|
56
|
+
In OMP, include the independent fast-mode token with `/zentui format "$model $provider( $thinkingLevel)( · $fast_mode)"`. Add it to `compactFormat` separately if needed. `$fast_mode` uses the active model's service-tier family and OMP's model capability checks, not another provider family's saved priority preference.
|
|
57
|
+
|
|
58
|
+
|
|
56
59
|
To keep metadata on the right, set both templates independently:
|
|
57
60
|
|
|
58
61
|
```json
|
|
@@ -93,6 +96,7 @@ The released flat `footerFormat` and `footerSegments` keys remain accepted only
|
|
|
93
96
|
| `$model` | | selected Footer model label |
|
|
94
97
|
| `$provider` | | formatted provider label |
|
|
95
98
|
| `$thinkingLevel` | | current thinking level; empty when unavailable or `off` |
|
|
99
|
+
| `$fast_mode` | | OMP's supported `fast` or `ultrafast` selection; empty when off, unsupported, or running Pi |
|
|
96
100
|
| `$package` | | project package version as `is <glyph> <version>` |
|
|
97
101
|
| `$package_version` | | raw project package version |
|
|
98
102
|
| `$session_duration` | `$duration` | session running time |
|
|
@@ -112,6 +116,36 @@ The released flat `footerFormat` and `footerSegments` keys remain accepted only
|
|
|
112
116
|
|
|
113
117
|
Each variable renders its core value without prose prefixes such as `on` or `via`; add those words as literals.
|
|
114
118
|
|
|
119
|
+
### OMP host data
|
|
120
|
+
|
|
121
|
+
OMP also supplies `$session_id`, `$pr_number`, `$pr_url`, `$subagent_count`,
|
|
122
|
+
`$token_rate`, `$active_time`, `$hostname`, `$usage_quota`, `$collaboration`,
|
|
123
|
+
`$stream_state`, `$vim_mode`, `$plan_mode`, `$prewalk_mode`, `$goal_mode`,
|
|
124
|
+
`$vibe_mode`, and `$loop_mode`. These explicit built-ins also work in Opencode
|
|
125
|
+
metadata and Minimalist slots; they are not aliases for OMP's segment IDs or
|
|
126
|
+
third-party `$extensions`. Pi and unsupported/inactive capabilities render empty.
|
|
127
|
+
See the [data/source reference](./configuration.md#omp-template-data).
|
|
128
|
+
|
|
129
|
+
For example:
|
|
130
|
+
|
|
131
|
+
```json
|
|
132
|
+
{
|
|
133
|
+
"format": "$cwd( · PR #$pr_number)( · $plan_mode)( · $loop_mode)$fill$context( · $active_time)( · $token_rate)",
|
|
134
|
+
"compactFormat": "$cwd$wrap(PR #$pr_number)$wrap($active_time)$wrap($token_rate)"
|
|
135
|
+
}
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
Keep `$session_id` separate from the session name and `$active_time` separate
|
|
139
|
+
from wall-clock `$session_duration`. Optional groups hide unavailable fields,
|
|
140
|
+
including missing PR/rate/quotas, without leaving their labels behind.
|
|
141
|
+
`$pr_url` is safe plain HTTPS text, not an injected terminal hyperlink.
|
|
142
|
+
|
|
143
|
+
Referencing `$usage_quota` explicitly opts into OMP's public usage-report API,
|
|
144
|
+
which may refresh authenticated reports from configured providers. Snapshots
|
|
145
|
+
are demand-driven and cached for up to five minutes, subject to window resets
|
|
146
|
+
and current provider/model/account scope. Defaults make no new requests; this
|
|
147
|
+
does not enable or configure the independent `$codex_quota` consent toggle.
|
|
148
|
+
|
|
115
149
|
### `$codex_quota` consent and freshness
|
|
116
150
|
|
|
117
151
|
Set `components.footer.codexQuota: true` and select Starship to opt in. The built-in wide layout and shipped compact default include quota conditionally. Saved custom formats are unchanged; add `($sep$codex_quota)` to `format` and `$wrap_sep($codex_quota)` to `compactFormat` where desired. Templates without the token never have quota appended outside them.
|
|
@@ -158,6 +192,57 @@ Example:
|
|
|
158
192
|
|
|
159
193
|
These tokens are structural in compact mode: `$wrap` and `$wrap_sep` render no text themselves, and `$extensions` is empty when no third-party status is active.
|
|
160
194
|
|
|
195
|
+
## Custom extension values
|
|
196
|
+
|
|
197
|
+
Publishers can provide named text through `zentui:variable` protocol v1, without
|
|
198
|
+
owning or wrapping Footer. Map stable publisher keys to simple local names under
|
|
199
|
+
`components.footer.styles.starship.variables`, then reference the names in either
|
|
200
|
+
template:
|
|
201
|
+
|
|
202
|
+
```json
|
|
203
|
+
{
|
|
204
|
+
"components": {
|
|
205
|
+
"footer": {
|
|
206
|
+
"styles": {
|
|
207
|
+
"starship": {
|
|
208
|
+
"variables": { "quota": "@scope/usage:quota" },
|
|
209
|
+
"extensionColorMode": "original",
|
|
210
|
+
"format": "$cwd$fill($quota)($sep$cost)",
|
|
211
|
+
"compactFormat": "$cwd$fill($quota)$wrap_sep$tokens"
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
These JSON-only aliases cannot replace built-in variables, aliases such as
|
|
220
|
+
`branch`, structural tokens, or prototype names. Missing values are empty;
|
|
221
|
+
conditional groups remove associated optional text. No custom value is appended
|
|
222
|
+
outside an explicit template. A compact-only reference creates demand only
|
|
223
|
+
while responsive mode is enabled. Native and Hidden never acquire this registry
|
|
224
|
+
on behalf of Footer, and configuring aliases does not select Starship or enable
|
|
225
|
+
Editor.
|
|
226
|
+
|
|
227
|
+
Original is the default color mode and preserves permitted publisher SGR and
|
|
228
|
+
HTTP(S) hyperlinks. Zentui strips incoming styling and uses Footer's own
|
|
229
|
+
`colors.extensionStatus` role and color source. These choices are independent of
|
|
230
|
+
Editor and of the existing `extensionStatuses.colorModes` preferences.
|
|
231
|
+
|
|
232
|
+
Values are kept whole through wide alignment, reflow, and compact packing.
|
|
233
|
+
When a value would be partially cropped or split, Footer recomposes without it
|
|
234
|
+
instead of showing misleading partial quotas or labels. Width fitting uses safe
|
|
235
|
+
internal probes that are restored before terminal output. Built-in narrow-width
|
|
236
|
+
behavior remains unchanged, and template literals still own their spacing.
|
|
237
|
+
|
|
238
|
+
The compact `$extensions` token above its existing configuration section
|
|
239
|
+
continues to expand `ctx.ui.setStatus()` statuses; it is **not** an aggregate of
|
|
240
|
+
new custom values. A publisher can use `setStatus()` as its own fallback when
|
|
241
|
+
capability is inactive, and must remove only its own fallback when active to
|
|
242
|
+
avoid duplicate output. See [publisher protocol](./configuration.md#custom-value-publisher-protocol-v1)
|
|
243
|
+
for capability, bounds, session lifecycle, and ownership rules. Disabling one
|
|
244
|
+
surface does not evict a value still consumed by another owned surface.
|
|
245
|
+
|
|
161
246
|
## `$fill` behavior
|
|
162
247
|
|
|
163
248
|
In the wide template:
|
|
@@ -3,6 +3,7 @@ import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
|
3
3
|
import type { ZentuiConfig } from "./config";
|
|
4
4
|
import { sanitizeEditorMetadataText } from "./editor-metadata-format";
|
|
5
5
|
import { collectFooterFormatReferences, parseFooterFormat } from "./footer-format";
|
|
6
|
+
import { minimalistTemplateReferences } from "./minimalist-template";
|
|
6
7
|
|
|
7
8
|
const INTERVAL = 60_000;
|
|
8
9
|
const TIMEOUT = 10_000;
|
|
@@ -45,8 +46,9 @@ export function parseCodexQuota(value: unknown): CodexQuota | undefined {
|
|
|
45
46
|
export function editorWantsCodexQuota(config: ZentuiConfig): boolean {
|
|
46
47
|
const editor = config.components.editor;
|
|
47
48
|
if (!editor.enabled || !editor.codexQuota) return false;
|
|
49
|
+
if (editor.style === "minimalist")
|
|
50
|
+
return minimalistTemplateReferences(editor.styles.minimalist).has("codex_quota");
|
|
48
51
|
return (
|
|
49
|
-
editor.style === "minimalist" ||
|
|
50
52
|
editor.style === "accent-rail" ||
|
|
51
53
|
collectFooterFormatReferences(
|
|
52
54
|
parseFooterFormat(sanitizeEditorMetadataText(editor.styles[editor.style].metadataFormat)),
|