rinco-pi-hud 1.6.0 → 1.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +25 -23
- package/assets/readme/hero.svg +1 -1
- package/assets/readme/responsive.svg +4 -5
- package/docs/CONTRIBUTING.md +3 -2
- package/docs/README.zh-CN.md +25 -23
- package/docs/footer.md +36 -24
- package/docs/upstream-zentui.md +3 -3
- package/extensions/hud/commands/settings-controller.ts +2 -2
- package/extensions/hud/commands/settings.ts +12 -18
- package/extensions/hud/config/config-counts.ts +0 -3
- package/extensions/hud/config/normalize.ts +1 -3
- package/extensions/hud/config/persist.ts +2 -4
- package/extensions/hud/config/schema.ts +0 -6
- package/extensions/hud/footer/groups.ts +2 -6
- package/extensions/hud/footer/index.ts +10 -8
- package/extensions/hud/footer/render-labels.ts +3 -14
- package/extensions/hud/index.ts +2 -0
- package/extensions/hud/segments/mcp-status.ts +23 -26
- package/extensions/hud/session/event-handlers.ts +0 -8
- package/extensions/hud/session/footer-clock.ts +2 -1
- package/extensions/hud/state/index.ts +0 -1
- package/extensions/hud/state/telemetry.ts +2 -44
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -26,7 +26,7 @@ Requires Pi **1.3.0 or newer within the 1.x release line**. Development and CI d
|
|
|
26
26
|
pi install npm:rinco-pi-hud
|
|
27
27
|
```
|
|
28
28
|
|
|
29
|
-
Restart Pi afterwards, or run `/reload`. The footer is enabled by default and `/
|
|
29
|
+
Restart Pi afterwards, or run `/reload`. The footer is enabled by default and `/hud` opens the settings UI.
|
|
30
30
|
|
|
31
31
|
From GitHub, or from a local checkout:
|
|
32
32
|
|
|
@@ -44,32 +44,32 @@ pi install "$PWD"
|
|
|
44
44
|
> Pi extensions run with your user permissions. Review the source before installing any third-party extension.
|
|
45
45
|
|
|
46
46
|
> [!NOTE]
|
|
47
|
-
> Truecolor and 256-color terminals are supported; explicit RGB colors use Pi's terminal-capability-aware encoder. The screenshot above renders with ASCII icon mode; `/
|
|
47
|
+
> Truecolor and 256-color terminals are supported; explicit RGB colors use Pi's terminal-capability-aware encoder. The screenshot above renders with ASCII icon mode; `/hud` switches between the `auto`, `nerd`, and `ascii` glyph sets.
|
|
48
48
|
|
|
49
49
|
## Commands
|
|
50
50
|
|
|
51
51
|
| Command | Effect |
|
|
52
52
|
| --- | --- |
|
|
53
|
-
| `/
|
|
54
|
-
| `/
|
|
55
|
-
| `/
|
|
56
|
-
| `/
|
|
57
|
-
| `/
|
|
58
|
-
| `/
|
|
59
|
-
| `/
|
|
53
|
+
| `/hud` | Settings UI: rows, segments, separator, icons, colors, templates |
|
|
54
|
+
| `/hud statusline enable\|disable\|toggle` | Show or hide the whole footer |
|
|
55
|
+
| `/hud row project\|session\|activity\|usage <enable\|disable\|toggle>` | Turn one row on or off |
|
|
56
|
+
| `/hud format "<template>"` | Replace the four rows with a single-line template |
|
|
57
|
+
| `/hud compact-format "<template>"` | Opt into a wrapped template below 80 columns; `clear` removes it |
|
|
58
|
+
| `/hud footer hud\|hidden\|native` | Four-group/template HUD, statuses only, or Pi’s native footer |
|
|
59
|
+
| `/hud layout\|segments\|extensions` | Open a settings section directly |
|
|
60
60
|
| `/codex-status` | Print Codex subscription usage and rate-limit windows |
|
|
61
61
|
| `/usage-refresh` | Refresh the model usage or balance shown in the footer |
|
|
62
62
|
|
|
63
63
|
## What it shows
|
|
64
64
|
|
|
65
|
-
| Row | Segments, each with its own switch under **Built-in segments** in `/
|
|
65
|
+
| Row | Segments, each with its own switch under **Built-in segments** in `/hud` |
|
|
66
66
|
| --- | --- |
|
|
67
67
|
| **Project** | directory, git branch, commit and tag, working-tree status, operation state (`MERGING`, `REBASING`, …), diff metrics, runtime, package version, OS, user |
|
|
68
|
-
| **Session** | session name, provider and model, thinking level, turn count, duration |
|
|
69
|
-
| **Activity** | running tools, completed tool counts,
|
|
70
|
-
| **Usage** | context window with a gauge, input and output tokens, cache read/write volume and hit rate, cost, model quota
|
|
68
|
+
| **Session** | session name, provider and model, thinking level, turn count, duration, clock |
|
|
69
|
+
| **Activity** | running tools, completed tool counts, skills, MCP servers |
|
|
70
|
+
| **Usage** | context window with a gauge, input and output tokens, cache read/write volume and hit rate, cost, model quota |
|
|
71
71
|
|
|
72
|
-
Rows are toggled with `/
|
|
72
|
+
Rows are toggled with `/hud row usage disable`; the segments inside them have individual switches in the same UI. Existing configs that used the former aggregate `tokens` or `toolActivity` switches are migrated automatically.
|
|
73
73
|
|
|
74
74
|
### Model quota
|
|
75
75
|
|
|
@@ -92,16 +92,18 @@ Groups wrap only at segment boundaries. A continuation line realigns under the s
|
|
|
92
92
|
Set a template for a single-line footer instead of the four groups:
|
|
93
93
|
|
|
94
94
|
```text
|
|
95
|
-
/
|
|
95
|
+
/hud format "$cwd( $git_branch)$fill($context)( $tokens)( $cost)"
|
|
96
96
|
```
|
|
97
97
|
|
|
98
|
-
Variables accept `$name` or `${name}`. The [footer reference](docs/footer.md) lists all of them, along with the aliases (`$directory`, `$status`, `$codex`, …). Run `/
|
|
98
|
+
Variables accept `$name` or `${name}`. The [footer reference](docs/footer.md) lists all of them, along with the aliases (`$directory`, `$status`, `$codex`, …). Run `/hud format` with no argument, or `/hud format clear`, to go back to the four groups.
|
|
99
99
|
|
|
100
100
|
## Configuration
|
|
101
101
|
|
|
102
|
-
|
|
102
|
+
The HUD uses `/hud`; `/zentui` is reserved for the original Zentui package. There is no legacy command alias. See [Using with Zentui](docs/footer.md#using-with-the-original-zentui) for component separation.
|
|
103
103
|
|
|
104
|
-
|
|
104
|
+
`/hud` writes to `~/.pi/agent/rinco-pi-hud.json` and applies changes immediately. It covers the separator style, icon mode (`nerd`, `ascii`, or `auto`), footer colors (Pi theme tokens or terminal palette styles), context rendering (text, gauge, or both), the project refresh interval, and third-party extension statuses with their own placement and color mode.
|
|
105
|
+
|
|
106
|
+
Footer colors follow the active Pi theme by default, including theme switches and automatic light/dark changes. In `/hud`, **Footer colors → theme** enables this behavior; **terminal** keeps the original Sakura RGB palette. Explicit custom colors (hex, indexed, or `fg:`/`bg:` styles) remain fixed in either mode. Remove those entries from `colors` to restore automatic theme colors.
|
|
105
107
|
|
|
106
108
|
Footer features are adapted from Zentui **0.32.0**, without installing its editor, messages, working line, tool display, or OMP adapter. New opt-in features include repository-relative paths, `$join_sep`, compact templates, extension-published values, safe status hyperlinks, PR/CI metadata, and average token rate. Defaults and existing configurations remain unchanged. See [docs/upstream-zentui.md](docs/upstream-zentui.md) for the exact snapshot and integration boundaries, and [docs/footer.md](docs/footer.md) for configuration and examples.
|
|
107
109
|
|
|
@@ -116,11 +118,11 @@ Footer features are adapted from Zentui **0.32.0**, without installing its edito
|
|
|
116
118
|
| [`extensions/hud/telemetry/`](extensions/hud/telemetry/format.ts) | Usage formatting, provider balance probes, and the Codex subscription client |
|
|
117
119
|
| [`extensions/hud/session/`](extensions/hud/session/) | Pi event registration, session lifecycle, and live context overlay |
|
|
118
120
|
| [`extensions/hud/state/`](extensions/hud/state/) | Aggregated state, telemetry reducer, and project refresh controller |
|
|
119
|
-
| [`extensions/hud/commands/`](extensions/hud/commands/settings.ts) | `/
|
|
121
|
+
| [`extensions/hud/commands/`](extensions/hud/commands/settings.ts) | `/hud` settings UI and configuration controller |
|
|
120
122
|
| [`extensions/hud/ui/`](extensions/hud/ui/) | Icons and terminal style utilities |
|
|
121
123
|
| [`docs/footer.md`](docs/footer.md) | Complete footer configuration reference |
|
|
122
124
|
| [`docs/CONTRIBUTING.md`](docs/CONTRIBUTING.md) | Local development, testing guidance, and pull request checklist |
|
|
123
|
-
| [`tests/`](tests/) | Vitest suite: footer layout, telemetry, provider balances, MCP
|
|
125
|
+
| [`tests/`](tests/) | Vitest suite: footer layout, telemetry, provider balances, MCP runtime tool counts |
|
|
124
126
|
|
|
125
127
|
## Development
|
|
126
128
|
|
|
@@ -155,19 +157,19 @@ Confirm Pi is running in TUI mode rather than headless, JSON, or print mode. The
|
|
|
155
157
|
<details>
|
|
156
158
|
<summary>The layout looks wrong in a narrow terminal</summary>
|
|
157
159
|
|
|
158
|
-
The footer measures the terminal and wraps at segment boundaries, so narrow windows show fewer segments per line. Set a `footerFormat` template, or disable low-priority segments in `/
|
|
160
|
+
The footer measures the terminal and wraps at segment boundaries, so narrow windows show fewer segments per line. Set a `footerFormat` template, or disable low-priority segments in `/hud`.
|
|
159
161
|
</details>
|
|
160
162
|
|
|
161
163
|
<details>
|
|
162
164
|
<summary>Colors look incorrect</summary>
|
|
163
165
|
|
|
164
|
-
The default palette follows the active Pi theme. If the footer still uses fixed colors, select **Footer colors → theme** in `/
|
|
166
|
+
The default palette follows the active Pi theme. If the footer still uses fixed colors, select **Footer colors → theme** in `/hud` and remove explicit color overrides from `~/.pi/agent/rinco-pi-hud.json`. Third-party statuses set to `original` retain their own colors. Truecolor and 256-color output follow Pi's detected terminal capabilities.
|
|
165
167
|
</details>
|
|
166
168
|
|
|
167
169
|
<details>
|
|
168
170
|
<summary>Icons are missing or misaligned</summary>
|
|
169
171
|
|
|
170
|
-
Unicode and Nerd Font glyphs vary between terminals and fonts. Install a Nerd Font, or switch to ASCII icons in `/
|
|
172
|
+
Unicode and Nerd Font glyphs vary between terminals and fonts. Install a Nerd Font, or switch to ASCII icons in `/hud`.
|
|
171
173
|
</details>
|
|
172
174
|
|
|
173
175
|
## License
|
package/assets/readme/hero.svg
CHANGED
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
|
|
16
16
|
<text x="80" y="260" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, 'Liberation Mono', monospace" font-size="20" xml:space="preserve"><tspan> </tspan><tspan fill="#f2a7c6" font-weight="700">Project</tspan><tspan> </tspan><tspan fill="#716879"> › </tspan><tspan fill="#f2a7c6" font-weight="700">rinco-pi-hud</tspan><tspan fill="#716879"> › </tspan><tspan>on </tspan><tspan fill="#c7b8f5" font-weight="700">*</tspan><tspan> </tspan><tspan fill="#c7b8f5" font-weight="700">main</tspan><tspan fill="#716879"> › </tspan><tspan fill="#9fd3f2">via</tspan><tspan> </tspan><tspan fill="#AEE5C5" font-weight="700">node v24.18.0</tspan><tspan fill="#716879"> › </tspan><tspan fill="#f7eef8">linux</tspan></text>
|
|
17
17
|
<text x="80" y="290" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, 'Liberation Mono', monospace" font-size="20" xml:space="preserve"><tspan> </tspan><tspan fill="#9fd3f2">Session</tspan><tspan> </tspan><tspan fill="#716879"> › </tspan><tspan fill="#9fd3f2">deepseek/deepseek-flash</tspan><tspan fill="#716879"> › </tspan><tspan fill="#efc3e6">Thinking level: max</tspan><tspan fill="#716879"> › </tspan><tspan fill="#efc3e6">Turn 3</tspan></text>
|
|
18
|
-
<text x="80" y="320" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, 'Liberation Mono', monospace" font-size="20" xml:space="preserve"><tspan> </tspan><tspan fill="#efc3e6">Activity</tspan><tspan fill="#716879"> › </tspan><tspan fill="#aee5c5">Tool read × 30 write × 7 edit × 13 bash × 76</tspan
|
|
18
|
+
<text x="80" y="320" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, 'Liberation Mono', monospace" font-size="20" xml:space="preserve"><tspan> </tspan><tspan fill="#efc3e6">Activity</tspan><tspan fill="#716879"> › </tspan><tspan fill="#aee5c5">Tool read × 30 write × 7 edit × 13 bash × 76</tspan></text>
|
|
19
19
|
<text x="80" y="350" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, 'Liberation Mono', monospace" font-size="20" xml:space="preserve"><tspan> </tspan><tspan fill="#aee5c5">Usage</tspan><tspan> </tspan><tspan fill="#716879"> › </tspan><tspan fill="#aee5c5">[##--------] 17%/1.0M</tspan><tspan fill="#716879"> › </tspan><tspan fill="#a99bae">↑ 177k</tspan><tspan fill="#716879"> › </tspan><tspan fill="#a99bae">↓ 74k</tspan><tspan fill="#716879"> › </tspan><tspan fill="#a99bae">R 10M</tspan><tspan> </tspan><tspan fill="#aee5c5">CH 99.8%</tspan><tspan fill="#716879"> › </tspan><tspan fill="#aee5c5" font-weight="700">$ 0.204</tspan></text>
|
|
20
20
|
</g>
|
|
21
21
|
</svg>
|
|
@@ -14,14 +14,14 @@
|
|
|
14
14
|
<line x1="194" y1="160" x2="194" y2="334" stroke="#716879" stroke-dasharray="3 5" opacity="0.55"/>
|
|
15
15
|
<text x="80" y="190" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, 'Liberation Mono', monospace" font-size="20" xml:space="preserve"><tspan> </tspan><tspan fill="#f2a7c6" font-weight="700">Project</tspan><tspan> </tspan><tspan fill="#716879"> › </tspan><tspan fill="#f2a7c6" font-weight="700">rinco-pi-hud</tspan><tspan fill="#716879"> › </tspan><tspan>on </tspan><tspan fill="#c7b8f5" font-weight="700">*</tspan><tspan> </tspan><tspan fill="#c7b8f5" font-weight="700">main</tspan><tspan fill="#716879"> › </tspan><tspan fill="#9fd3f2">via</tspan><tspan> </tspan><tspan fill="#AEE5C5" font-weight="700">node v24.18.0</tspan><tspan fill="#716879"> › </tspan><tspan fill="#f7eef8">linux</tspan></text>
|
|
16
16
|
<text x="80" y="220" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, 'Liberation Mono', monospace" font-size="20" xml:space="preserve"><tspan> </tspan><tspan fill="#9fd3f2">Session</tspan><tspan> </tspan><tspan fill="#716879"> › </tspan><tspan fill="#9fd3f2">deepseek/deepseek-flash</tspan><tspan fill="#716879"> › </tspan><tspan fill="#efc3e6">Thinking level: max</tspan><tspan fill="#716879"> › </tspan><tspan fill="#efc3e6">Turn 3</tspan></text>
|
|
17
|
-
<text x="80" y="250" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, 'Liberation Mono', monospace" font-size="20" xml:space="preserve"><tspan> </tspan><tspan fill="#efc3e6">Activity</tspan><tspan fill="#716879"> › </tspan><tspan fill="#aee5c5">Tool read × 30 write × 7 edit × 13 bash × 76</tspan
|
|
17
|
+
<text x="80" y="250" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, 'Liberation Mono', monospace" font-size="20" xml:space="preserve"><tspan> </tspan><tspan fill="#efc3e6">Activity</tspan><tspan fill="#716879"> › </tspan><tspan fill="#aee5c5">Tool read × 30 write × 7 edit × 13 bash × 76</tspan></text>
|
|
18
18
|
<text x="80" y="280" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, 'Liberation Mono', monospace" font-size="20" xml:space="preserve"><tspan> </tspan><tspan fill="#aee5c5">Usage</tspan><tspan> </tspan><tspan fill="#716879"> › </tspan><tspan fill="#aee5c5">[##--------] 17%/1.0M</tspan><tspan fill="#716879"> › </tspan><tspan fill="#a99bae">↑ 177k</tspan><tspan fill="#716879"> › </tspan><tspan fill="#a99bae">↓ 74k</tspan><tspan fill="#716879"> › </tspan><tspan fill="#a99bae">R 10M</tspan><tspan> </tspan><tspan fill="#aee5c5">CH 99.8%</tspan></text>
|
|
19
19
|
<text x="80" y="310" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, 'Liberation Mono', monospace" font-size="20" xml:space="preserve"><tspan> </tspan><tspan fill="#716879"> › </tspan><tspan fill="#aee5c5" font-weight="700">$ 0.204</tspan></text>
|
|
20
20
|
</g>
|
|
21
21
|
<g id="panel-56">
|
|
22
22
|
<rect x="56" y="368" width="1088" height="298" rx="14" fill="#16131F" stroke="#2C2640"/>
|
|
23
23
|
<text x="80" y="391" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, 'Liberation Mono', monospace" font-size="18" fill="#A99BAE">render(56)</text>
|
|
24
|
-
<text x="1120" y="391" text-anchor="end" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, 'Liberation Mono', monospace" font-size="18" fill="#A99BAE">
|
|
24
|
+
<text x="1120" y="391" text-anchor="end" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, 'Liberation Mono', monospace" font-size="18" fill="#A99BAE">7 rows · continuations align</text>
|
|
25
25
|
<line x1="56" y1="402" x2="1144" y2="402" stroke="#2C2640"/>
|
|
26
26
|
<line x1="194" y1="402" x2="194" y2="666" stroke="#716879" stroke-dasharray="3 5" opacity="0.55"/>
|
|
27
27
|
<text x="80" y="432" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, 'Liberation Mono', monospace" font-size="20" xml:space="preserve"><tspan> </tspan><tspan fill="#f2a7c6" font-weight="700">Project</tspan><tspan> </tspan><tspan fill="#716879"> › </tspan><tspan fill="#f2a7c6" font-weight="700">rinco-pi-hud</tspan><tspan fill="#716879"> › </tspan><tspan>on </tspan><tspan fill="#c7b8f5" font-weight="700">*</tspan><tspan> </tspan><tspan fill="#c7b8f5" font-weight="700">main</tspan></text>
|
|
@@ -29,8 +29,7 @@
|
|
|
29
29
|
<text x="80" y="492" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, 'Liberation Mono', monospace" font-size="20" xml:space="preserve"><tspan> </tspan><tspan fill="#9fd3f2">Session</tspan><tspan> </tspan><tspan fill="#716879"> › </tspan><tspan fill="#9fd3f2">deepseek/deepseek-flash</tspan></text>
|
|
30
30
|
<text x="80" y="522" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, 'Liberation Mono', monospace" font-size="20" xml:space="preserve"><tspan> </tspan><tspan fill="#716879"> › </tspan><tspan fill="#efc3e6">Thinking level: max</tspan><tspan fill="#716879"> › </tspan><tspan fill="#efc3e6">Turn 3</tspan></text>
|
|
31
31
|
<text x="80" y="552" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, 'Liberation Mono', monospace" font-size="20" xml:space="preserve"><tspan> </tspan><tspan fill="#efc3e6">Activity</tspan><tspan fill="#716879"> › </tspan><tspan fill="#aee5c5">Tool read × 30 write × 7 edit × 13 bash × </tspan><tspan>…</tspan></text>
|
|
32
|
-
<text x="80" y="582" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, 'Liberation Mono', monospace" font-size="20" xml:space="preserve"><tspan>
|
|
33
|
-
<text x="80" y="612" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, 'Liberation Mono', monospace" font-size="20" xml:space="preserve"><tspan>
|
|
34
|
-
<text x="80" y="642" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, 'Liberation Mono', monospace" font-size="20" xml:space="preserve"><tspan> </tspan><tspan fill="#716879"> › </tspan><tspan fill="#a99bae">R 10M</tspan><tspan> </tspan><tspan fill="#aee5c5">CH 99.8%</tspan><tspan fill="#716879"> › </tspan><tspan fill="#aee5c5" font-weight="700">$ 0.204</tspan></text>
|
|
32
|
+
<text x="80" y="582" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, 'Liberation Mono', monospace" font-size="20" xml:space="preserve"><tspan> </tspan><tspan fill="#aee5c5">Usage</tspan><tspan> </tspan><tspan fill="#716879"> › </tspan><tspan fill="#aee5c5">[##--------] 17%/1.0M</tspan><tspan fill="#716879"> › </tspan><tspan fill="#a99bae">↑ 177k</tspan><tspan fill="#716879"> › </tspan><tspan fill="#a99bae">↓ 74k</tspan></text>
|
|
33
|
+
<text x="80" y="612" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, 'Liberation Mono', monospace" font-size="20" xml:space="preserve"><tspan> </tspan><tspan fill="#716879"> › </tspan><tspan fill="#a99bae">R 10M</tspan><tspan> </tspan><tspan fill="#aee5c5">CH 99.8%</tspan><tspan fill="#716879"> › </tspan><tspan fill="#aee5c5" font-weight="700">$ 0.204</tspan></text>
|
|
35
34
|
</g>
|
|
36
35
|
</svg>
|
package/docs/CONTRIBUTING.md
CHANGED
|
@@ -50,7 +50,8 @@ npm run pack:check
|
|
|
50
50
|
|
|
51
51
|
Tests live in `tests/`:
|
|
52
52
|
|
|
53
|
-
- `zentui-status.test.ts` — Config counts,
|
|
53
|
+
- `zentui-status.test.ts` — Config counts, telemetry, and skill activity.
|
|
54
|
+
- `mcp-status.test.ts` — Pi runtime MCP namespaces, exposure filtering, and dynamic tool changes.
|
|
54
55
|
- `mcp-footer.test.ts` — MCP count rendering, segment controls, custom formats, and legacy third-party statuses.
|
|
55
56
|
- `codex-usage.test.ts` — Codex payload normalization and model-specific quota formatting.
|
|
56
57
|
- `footer-layout.test.ts` — Four-group categorized layout, segment wrapping, and narrow-width budget.
|
|
@@ -103,7 +104,7 @@ Follow the configured conventions:
|
|
|
103
104
|
The HUD extension is organized into functional modules under `extensions/hud/`:
|
|
104
105
|
|
|
105
106
|
- **`index.ts`** — Composition root for controllers, shared state, and UI installation.
|
|
106
|
-
- **`commands/`** — `/
|
|
107
|
+
- **`commands/`** — `/hud` presentation and its configuration-persistence controller.
|
|
107
108
|
- **`config/`** — Configuration model, normalization, and persistence.
|
|
108
109
|
- **`footer/`** — Footer rendering, semantic group construction, responsive layout, and templates.
|
|
109
110
|
- **`segments/`** — State collectors: Git, runtime, MCP, skills, projects, etc.
|
package/docs/README.zh-CN.md
CHANGED
|
@@ -26,7 +26,7 @@ Rinco Pi HUD 用四组实时状态替换 Pi 的脚注行,不需要的部分都
|
|
|
26
26
|
pi install npm:rinco-pi-hud
|
|
27
27
|
```
|
|
28
28
|
|
|
29
|
-
装完重启 Pi,或执行 `/reload`。脚注默认启用,`/
|
|
29
|
+
装完重启 Pi,或执行 `/reload`。脚注默认启用,`/hud` 打开设置界面。
|
|
30
30
|
|
|
31
31
|
从 GitHub 或本地目录安装:
|
|
32
32
|
|
|
@@ -44,32 +44,32 @@ pi install "$PWD"
|
|
|
44
44
|
> Pi 扩展以当前用户权限运行。安装任何第三方扩展前,请先审查其源码。
|
|
45
45
|
|
|
46
46
|
> [!NOTE]
|
|
47
|
-
> 支持 Truecolor 和 256 色终端;显式 RGB 颜色通过 Pi 的终端能力适配接口输出。上图用的是 ASCII 图标模式,`/
|
|
47
|
+
> 支持 Truecolor 和 256 色终端;显式 RGB 颜色通过 Pi 的终端能力适配接口输出。上图用的是 ASCII 图标模式,`/hud` 可以在 `auto`、`nerd`、`ascii` 三套符号之间切换。
|
|
48
48
|
|
|
49
49
|
## 命令
|
|
50
50
|
|
|
51
51
|
| 命令 | 作用 |
|
|
52
52
|
| --- | --- |
|
|
53
|
-
| `/
|
|
54
|
-
| `/
|
|
55
|
-
| `/
|
|
56
|
-
| `/
|
|
57
|
-
| `/
|
|
58
|
-
| `/
|
|
59
|
-
| `/
|
|
53
|
+
| `/hud` | 设置界面:行、状态段、分隔符、图标、颜色、模板 |
|
|
54
|
+
| `/hud statusline enable\|disable\|toggle` | 显示或隐藏整个脚注 |
|
|
55
|
+
| `/hud row project\|session\|activity\|usage <enable\|disable\|toggle>` | 开关某一行 |
|
|
56
|
+
| `/hud format "<template>"` | 用单行模板替换四行布局 |
|
|
57
|
+
| `/hud compact-format "<template>"` | 设置低于 80 列时使用的换行模板;`clear` 清除 |
|
|
58
|
+
| `/hud footer hud\|hidden\|native` | HUD、仅第三方状态、恢复 Pi 原生脚注 |
|
|
59
|
+
| `/hud layout\|segments\|extensions` | 直接打开对应设置页 |
|
|
60
60
|
| `/codex-status` | 打印 Codex 订阅用量与限额窗口 |
|
|
61
61
|
| `/usage-refresh` | 立即刷新脚注上的模型用量或余额 |
|
|
62
62
|
|
|
63
63
|
## 显示什么
|
|
64
64
|
|
|
65
|
-
| 行 | 状态段。每段在 `/
|
|
65
|
+
| 行 | 状态段。每段在 `/hud` 的 **Built-in segments** 里都有独立开关 |
|
|
66
66
|
| --- | --- |
|
|
67
67
|
| **Project** | 目录、Git 分支、Commit 与 Tag、工作区状态、Git 操作状态(`MERGING`、`REBASING` 等)、差异指标、运行时、包版本、OS、用户 |
|
|
68
|
-
| **Session** | 会话名称、Provider 与模型、Thinking
|
|
69
|
-
| **Activity** | 正在运行的 Tool、已完成 Tool
|
|
70
|
-
| **Usage** | Context 窗口与进度条、输入/输出 Token
|
|
68
|
+
| **Session** | 会话名称、Provider 与模型、Thinking 等级、轮次、会话时长、时间 |
|
|
69
|
+
| **Activity** | 正在运行的 Tool、已完成 Tool 计数、Skill、MCP Server |
|
|
70
|
+
| **Usage** | Context 窗口与进度条、输入/输出 Token、缓存读写量与命中率、费用、模型限额 |
|
|
71
71
|
|
|
72
|
-
行用 `/
|
|
72
|
+
行用 `/hud row usage disable` 开关;行内每个状态段在同一界面里各有开关。使用旧版聚合开关 `tokens`、`toolActivity` 的配置会自动迁移。
|
|
73
73
|
|
|
74
74
|
### 模型限额
|
|
75
75
|
|
|
@@ -92,16 +92,18 @@ Usage 行跟随当前模型的 Provider:
|
|
|
92
92
|
想换成单行脚注,设置模板即可:
|
|
93
93
|
|
|
94
94
|
```text
|
|
95
|
-
/
|
|
95
|
+
/hud format "$cwd( $git_branch)$fill($context)( $tokens)( $cost)"
|
|
96
96
|
```
|
|
97
97
|
|
|
98
|
-
变量可以写成 `$name` 或 `${name}`。[脚注参考](footer.md)列出了全部变量和别名(`$directory`、`$status`、`$codex` 等)。不带参数的 `/
|
|
98
|
+
变量可以写成 `$name` 或 `${name}`。[脚注参考](footer.md)列出了全部变量和别名(`$directory`、`$status`、`$codex` 等)。不带参数的 `/hud format`(或 `/hud format clear`)恢复四行分组布局。
|
|
99
99
|
|
|
100
100
|
## 配置
|
|
101
101
|
|
|
102
|
-
`/zentui`
|
|
102
|
+
本项目使用 `/hud`,把 `/zentui` 留给原版 Zentui,不保留旧命令别名。配置文件和现有设置不变。与原版搭配时,请将 Zentui 的 Footer 设为 Native,让本项目继续管理 HUD;详见[共存说明](footer.md#using-with-the-original-zentui)。
|
|
103
103
|
|
|
104
|
-
|
|
104
|
+
`/hud` 把配置写入 `~/.pi/agent/rinco-pi-hud.json`,改动立即生效。可配置分隔符样式、图标模式(`nerd`、`ascii`、`auto`)、脚注配色(Pi 主题色或终端调色板样式)、Context 渲染方式(文本、进度条或两者)、项目刷新间隔,以及第三方扩展状态的位置与颜色模式。
|
|
105
|
+
|
|
106
|
+
脚注默认自动跟随当前 Pi 主题,包括手动切换主题和自动明暗切换。在 `/hud` 中选择 **Footer colors → theme** 启用跟随,选择 **terminal** 则保留原有 Sakura RGB 配色。显式自定义颜色(十六进制、索引色或 `fg:`/`bg:` 样式)在两种模式下都会保留;删除 `colors` 中的相应配置即可恢复自动配色。
|
|
105
107
|
|
|
106
108
|
已适配 Zentui **0.32.0** 的 Footer 新功能:仓库相对路径、`$join_sep` 条件分隔符、窄屏模板、扩展发布的自定义值、安全状态超链接,以及按需启用的 PR/CI 与平均 Token 速率。默认四行 HUD、原有配置及余额查询保持不变;不接管编辑器、消息、工作进度行或工具展示,也不引入 OMP 适配。同步快照和边界见[上游集成记录](upstream-zentui.md),配置示例和完整变量参考见 [docs/footer.md](footer.md)。
|
|
107
109
|
|
|
@@ -116,11 +118,11 @@ Usage 行跟随当前模型的 Provider:
|
|
|
116
118
|
| [`extensions/hud/telemetry/`](../extensions/hud/telemetry/format.ts) | 用量格式化、各家余额探测与 Codex 订阅客户端 |
|
|
117
119
|
| [`extensions/hud/session/`](../extensions/hud/session/) | Pi 事件注册、会话生命周期与实时 Context 覆盖 |
|
|
118
120
|
| [`extensions/hud/state/`](../extensions/hud/state/) | 聚合状态、Telemetry Reducer 与项目刷新 Controller |
|
|
119
|
-
| [`extensions/hud/commands/`](../extensions/hud/commands/settings.ts) | `/
|
|
121
|
+
| [`extensions/hud/commands/`](../extensions/hud/commands/settings.ts) | `/hud` 设置界面与配置 Controller |
|
|
120
122
|
| [`extensions/hud/ui/`](../extensions/hud/ui/) | 图标与终端样式工具 |
|
|
121
123
|
| [`docs/footer.md`](footer.md) | 完整脚注配置参考 |
|
|
122
124
|
| [`docs/CONTRIBUTING.md`](CONTRIBUTING.md) | 本地开发、测试规范和 PR 检查清单 |
|
|
123
|
-
| [`tests/`](../tests/) | Vitest 测试套件:脚注布局、遥测、各家余额与 MCP
|
|
125
|
+
| [`tests/`](../tests/) | Vitest 测试套件:脚注布局、遥测、各家余额与 MCP 运行时工具计数 |
|
|
124
126
|
|
|
125
127
|
## 开发
|
|
126
128
|
|
|
@@ -155,19 +157,19 @@ npx tsx assets/readme/source/build-assets.mts /tmp/footer.json
|
|
|
155
157
|
<details>
|
|
156
158
|
<summary>窄终端里布局看起来不对</summary>
|
|
157
159
|
|
|
158
|
-
脚注会测量终端宽度,只在状态段边界换行,所以窗口越窄,每行容纳的状态段越少。可以设置 `footerFormat` 模板,或在 `/
|
|
160
|
+
脚注会测量终端宽度,只在状态段边界换行,所以窗口越窄,每行容纳的状态段越少。可以设置 `footerFormat` 模板,或在 `/hud` 中关闭低优先级状态段。
|
|
159
161
|
</details>
|
|
160
162
|
|
|
161
163
|
<details>
|
|
162
164
|
<summary>颜色显示异常</summary>
|
|
163
165
|
|
|
164
|
-
默认配色自动跟随当前 Pi 主题。如果脚注仍使用固定颜色,请在 `/
|
|
166
|
+
默认配色自动跟随当前 Pi 主题。如果脚注仍使用固定颜色,请在 `/hud` 中选择 **Footer colors → theme**,并删除 `~/.pi/agent/rinco-pi-hud.json` 中的显式颜色覆盖。设为 `original` 的第三方扩展状态会保留自己的颜色。Truecolor 与 256 色输出仍按 Pi 检测到的终端能力选择。
|
|
165
167
|
</details>
|
|
166
168
|
|
|
167
169
|
<details>
|
|
168
170
|
<summary>图标缺失或错位</summary>
|
|
169
171
|
|
|
170
|
-
Unicode 与 Nerd Font 符号的显示效果因终端和字体而异。建议安装 Nerd Font,或在 `/
|
|
172
|
+
Unicode 与 Nerd Font 符号的显示效果因终端和字体而异。建议安装 Nerd Font,或在 `/hud` 中切换到 ASCII 图标。
|
|
171
173
|
</details>
|
|
172
174
|
|
|
173
175
|
## 许可证
|
package/docs/footer.md
CHANGED
|
@@ -7,33 +7,49 @@ When `footerFormat` is empty, the HUD displays four semantic groups:
|
|
|
7
7
|
```text
|
|
8
8
|
Project · pi-sakura · main · 24.18
|
|
9
9
|
Session · gpt-5.3 · Thinking level: high · Turn 8
|
|
10
|
-
Activity ·
|
|
10
|
+
Activity · Tool read × 4 · Skill 2/3 · MCP 2
|
|
11
11
|
Usage · 35%/200k · ↑ 4.2k · ↓ 1.1k · $ 0.030
|
|
12
12
|
```
|
|
13
13
|
|
|
14
|
-
The MCP segment
|
|
14
|
+
The MCP segment uses Pi's public `pi.getAllTools()` API to count unique MCP namespaces with non-hidden registered tools, including direct, codemode, and deferred exposure. It includes file-configured and dynamically registered servers without reading `mcp.json`, resolving credentials, or creating connections. Hidden tools left behind after disabling or removing a server do not count. The value is read on each footer render (including normal project refreshes); zero hides the segment. This is a runtime tool-availability count, not a connection-health or configured-server count: resource-only servers and servers with no exposed tools are omitted, and a disconnected server may retain registered tools. Use Pi's `/mcp` for full connection status. `pi.getMcpServers()` is not used because it only lists extension registrations, not all configured servers. Legacy adapter footer statuses remain ordinary third-party statuses.
|
|
15
15
|
|
|
16
16
|
The category column is sized from visible text so every separator aligns. When a row exceeds the terminal width, complete status segments move to an indented continuation line. Only a single segment that is wider than the available content area is truncated. Third-party extension statuses appear on the Activity group in configured `left`, `middle`, then `right` order.
|
|
17
17
|
|
|
18
18
|
Control each default-layout row independently:
|
|
19
19
|
|
|
20
20
|
```text
|
|
21
|
-
/
|
|
22
|
-
/
|
|
23
|
-
/
|
|
24
|
-
/
|
|
21
|
+
/hud row project enable
|
|
22
|
+
/hud row session disable
|
|
23
|
+
/hud row activity toggle
|
|
24
|
+
/hud row usage toggle
|
|
25
25
|
```
|
|
26
26
|
|
|
27
|
-
The command shape is `/
|
|
27
|
+
The command shape is `/hud row <project|session|activity|usage> <enable|disable|toggle>`. Values persist under `footerRows`; all four default to `true`. Row switches apply only to the default layout and do not alter a custom single-line `footerFormat`.
|
|
28
|
+
|
|
29
|
+
## Using with the original Zentui
|
|
30
|
+
|
|
31
|
+
This package registers `/hud`, not `/zentui`. The original Zentui keeps `/zentui`;
|
|
32
|
+
the HUD has no legacy alias and still uses `rinco-pi-hud.json`.
|
|
33
|
+
|
|
34
|
+
To use Zentui's User messages, Working line, or Tool display alongside the HUD,
|
|
35
|
+
set Zentui's `components.footer.style` to `"native"` in
|
|
36
|
+
`~/.pi/agent/zentui.json`. Native releases Zentui's Footer ownership without
|
|
37
|
+
removing another extension's footer. Keep this package's status line enabled.
|
|
38
|
+
Do not select Zentui Starship or Hidden while expecting the HUD to remain in control.
|
|
39
|
+
|
|
40
|
+
Zentui components are independent. Disable its Editor, Thinking and selector borders
|
|
41
|
+
unless wanted. With its Editor disabled, use Working line placement `"above"` rather
|
|
42
|
+
than the editor-border placement. Tool display custom/MCP overrides and replacement
|
|
43
|
+
of Bash renderers require separate consent; installing the package does not authorize them.
|
|
28
44
|
|
|
29
45
|
## Footer modes
|
|
30
46
|
|
|
31
|
-
- `/
|
|
32
|
-
- `/
|
|
33
|
-
- `/
|
|
47
|
+
- `/hud footer hud`: enable the normal four groups or configured templates.
|
|
48
|
+
- `/hud footer hidden`: show only allowed third-party statuses, no row when none exist.
|
|
49
|
+
- `/hud footer native`: release ownership to Pi; saved HUD choices remain unchanged.
|
|
34
50
|
|
|
35
51
|
Hidden and HUD share the existing per-key `extensionStatuses` placement/color policy.
|
|
36
|
-
Native is Pi-owned and does not apply this policy. `/
|
|
52
|
+
Native is Pi-owned and does not apply this policy. `/hud layout`, `segments`, and
|
|
37
53
|
`extensions` open the corresponding settings tabs directly.
|
|
38
54
|
|
|
39
55
|
## Repository paths
|
|
@@ -54,7 +70,7 @@ abbreviation; a stale root is never used to produce a relative path.
|
|
|
54
70
|
|
|
55
71
|
By default, `colorSources.starship` is `"theme"`. Built-in footer colors use semantic Pi theme tokens such as `accent`, `muted`, `success`, `warning`, and `error`; runtime labels also use the active theme. Switching themes, including automatic light/dark switching, recolors the footer without reloading the extension. This applies to both the default rows and custom templates.
|
|
56
72
|
|
|
57
|
-
To enable theme colors in an existing configuration, use **Footer colors → theme** in `/
|
|
73
|
+
To enable theme colors in an existing configuration, use **Footer colors → theme** in `/hud`, or set:
|
|
58
74
|
|
|
59
75
|
```json
|
|
60
76
|
{
|
|
@@ -91,30 +107,28 @@ Entries you explicitly set under `colors` override the selected defaults. Semant
|
|
|
91
107
|
| `sessionDuration` | off | Session | Current session duration |
|
|
92
108
|
| `runningTools` | on | Activity | Currently running native tools and elapsed time |
|
|
93
109
|
| `toolCounts` | on | Activity | Cumulative completed native-tool counts |
|
|
94
|
-
| `activeAgents` | on | Activity | Active primary agent runs |
|
|
95
|
-
| `agentIdle` | on | Activity | `Agent idle` when no primary agent run is active |
|
|
96
110
|
| `skills` | on | Activity | Active/available skills count, e.g. `Skill 1/3` |
|
|
97
|
-
| `mcp` | on | Activity |
|
|
111
|
+
| `mcp` | on | Activity | MCP namespaces with exposed runtime tools, e.g. `MCP 2` |
|
|
98
112
|
| `context` | on | Usage | Context percentage, window size, and/or gauge |
|
|
99
113
|
| `inputTokens` | on | Usage | Cumulative input tokens |
|
|
100
114
|
| `outputTokens` | on | Usage | Cumulative output tokens |
|
|
101
115
|
| `cacheDetails` | on | Usage | Cache read/write tokens and latest hit rate |
|
|
102
116
|
| `cost` | on | Usage | Cumulative session cost |
|
|
103
117
|
| `codexUsage` | on | Usage | Codex weekly quota remaining |
|
|
104
|
-
| `time` | off |
|
|
118
|
+
| `time` | off | Session | Current time `HH:MM`, after session duration |
|
|
105
119
|
|
|
106
120
|
## Template syntax
|
|
107
121
|
|
|
108
122
|
Set a custom template:
|
|
109
123
|
|
|
110
124
|
```text
|
|
111
|
-
/
|
|
125
|
+
/hud format "$os $cwd( $git_branch)$fill($context)( $tokens)( $cost)"
|
|
112
126
|
```
|
|
113
127
|
|
|
114
128
|
Clear it:
|
|
115
129
|
|
|
116
130
|
```text
|
|
117
|
-
/
|
|
131
|
+
/hud format clear
|
|
118
132
|
```
|
|
119
133
|
|
|
120
134
|
### Variables
|
|
@@ -169,10 +183,9 @@ the separator already owns spacing. Templates without it retain their previous b
|
|
|
169
183
|
| `$skills` | Active/available skills, e.g. `Skill 1/3` |
|
|
170
184
|
| `$active_skills` | Active skills count only |
|
|
171
185
|
| `$extensions` | Installed Pi packages count |
|
|
172
|
-
| `$mcp` |
|
|
186
|
+
| `$mcp` | MCP namespace count from Pi's exposed runtime tools |
|
|
173
187
|
| `$tool_counts` | Native tool completion counts |
|
|
174
188
|
| `$running_tools` | Recently running tools |
|
|
175
|
-
| `$active_agents` | Active primary agent runs |
|
|
176
189
|
| `$subscription` | Optional `(sub)` when Pi reports OAuth subscription use (also kimi-coding) |
|
|
177
190
|
| `$auto_compaction` | Optional `(auto)` when public, trust-aware Pi settings report automatic compaction |
|
|
178
191
|
| `$pr_number` / `$pr_url` | Current open GitHub PR number / plain HTTPS URL, qualified against local HEAD |
|
|
@@ -199,7 +212,6 @@ $codex_quota → $codex_usage
|
|
|
199
212
|
$turn_count → $turn
|
|
200
213
|
$codex → $codex_usage
|
|
201
214
|
$tools → $tool_counts
|
|
202
|
-
$agents → $active_agents
|
|
203
215
|
$separator → $sep
|
|
204
216
|
```
|
|
205
217
|
|
|
@@ -208,7 +220,7 @@ $separator → $sep
|
|
|
208
220
|
Set a separate narrow layout (used below 80 terminal columns):
|
|
209
221
|
|
|
210
222
|
```text
|
|
211
|
-
/
|
|
223
|
+
/hud compact-format "$cwd$wrap(on $git_branch)$fill$context$wrap_sep$tokens$wrap_sep$extension_statuses"
|
|
212
224
|
```
|
|
213
225
|
|
|
214
226
|
`$wrap` starts an independently packable chunk with a space boundary.
|
|
@@ -220,7 +232,7 @@ template order and are right-aligned. Nested/additional fills do not create extr
|
|
|
220
232
|
|
|
221
233
|
`compactFooterMaxLines` defaults to 2 (range 1–8), and omitted/truncated chunks use `…`.
|
|
222
234
|
Layout → Responsive compact controls `responsiveFooter`; an empty compact format is inert.
|
|
223
|
-
Use `/
|
|
235
|
+
Use `/hud compact-format clear` to return to the existing layout at every width.
|
|
224
236
|
Custom templates and wide templates are otherwise unchanged; arbitrary narrow layouts cannot keep every field.
|
|
225
237
|
|
|
226
238
|
## Custom extension values
|
|
@@ -279,7 +291,7 @@ Unsafe protocols, title, clipboard, cursor controls and embedded line breaks are
|
|
|
279
291
|
links and styles are closed before adjacent content. Zentui mode strips publisher styling/links.
|
|
280
292
|
|
|
281
293
|
```text
|
|
282
|
-
/
|
|
294
|
+
/hud format "$cwd( · PR #$pr_number)( · $ci)$fill($token_rate)"
|
|
283
295
|
```
|
|
284
296
|
|
|
285
297
|
PR/CI collection is opt-in through template references and requires installed/authenticated
|
package/docs/upstream-zentui.md
CHANGED
|
@@ -25,8 +25,8 @@ No extra runtime dependency is installed. Pi 1.3–1.x remains supported.
|
|
|
25
25
|
| Passive live metadata | Template-opt-in `$pr_number`, `$pr_url`, `$ci`, `$token_rate` |
|
|
26
26
|
| Atomic telemetry | `$cache_read` and `$cache_write` already existed; add optional `$subscription` / `$auto_compaction` |
|
|
27
27
|
| Thinking variable | `$thinkingLevel` aliases the existing `$thinking` |
|
|
28
|
-
| Status-only / native mode | `/
|
|
29
|
-
| Direct settings access | `/
|
|
28
|
+
| Status-only / native mode | `/hud footer hidden` keeps permitted statuses; `native` releases Footer ownership |
|
|
29
|
+
| Direct settings access | `/hud layout`, `segments`, `extensions` |
|
|
30
30
|
|
|
31
31
|
## Deliberate differences
|
|
32
32
|
|
|
@@ -36,7 +36,7 @@ No extra runtime dependency is installed. Pi 1.3–1.x remains supported.
|
|
|
36
36
|
- Keep the independent, flat `~/.pi/agent/rinco-pi-hud.json` schema. Upstream
|
|
37
37
|
`components.footer.styles.starship` objects are not automatically imported.
|
|
38
38
|
- Keep existing theme defaults, legacy configuration migration, and all HUD counters, skills,
|
|
39
|
-
MCP
|
|
39
|
+
MCP runtime tool counts, model/provider labels, live context and usage totals.
|
|
40
40
|
- Keep the existing Codex quota client and DeepSeek / Token Switch balance probes.
|
|
41
41
|
`$codex_quota` is a compatibility alias for `$codex_usage`, not a new collector.
|
|
42
42
|
Upstream's separate official-OpenAI response-header quota collector is not installed.
|
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
saveSeparatorPatch,
|
|
16
16
|
saveUiFeaturesPatch,
|
|
17
17
|
} from "../config/config.js";
|
|
18
|
-
import {
|
|
18
|
+
import { registerHudSettingsCommand } from "./settings.js";
|
|
19
19
|
|
|
20
20
|
interface SettingsControllerDeps {
|
|
21
21
|
getConfig: () => PolishedTuiConfig;
|
|
@@ -32,7 +32,7 @@ export function registerSettingsController(pi: ExtensionAPI, deps: SettingsContr
|
|
|
32
32
|
deps.setConfig(config);
|
|
33
33
|
};
|
|
34
34
|
|
|
35
|
-
|
|
35
|
+
registerHudSettingsCommand(pi, {
|
|
36
36
|
getConfig: deps.getConfig,
|
|
37
37
|
setColorSources(patch) {
|
|
38
38
|
updateConfig(saveColorSourcesPatch(patch));
|
|
@@ -102,7 +102,7 @@ const featureSettingLabels: Record<FeatureSettingId, string> = {
|
|
|
102
102
|
};
|
|
103
103
|
|
|
104
104
|
const featureSettingDescriptions: Record<FeatureSettingId, string> = {
|
|
105
|
-
statusLine: "Enable or disable
|
|
105
|
+
statusLine: "Enable or disable Rinco HUD's custom footer/status line.",
|
|
106
106
|
};
|
|
107
107
|
|
|
108
108
|
const footerRowLabels: Record<keyof FooterRowsConfig, string> = {
|
|
@@ -132,10 +132,8 @@ const footerSegmentSettingLabels: Record<FooterSegmentSettingId, string> = {
|
|
|
132
132
|
sessionDuration: "Session duration",
|
|
133
133
|
runningTools: "Running tools",
|
|
134
134
|
toolCounts: "Completed tool counts",
|
|
135
|
-
activeAgents: "Active agents",
|
|
136
|
-
agentIdle: "Agent idle status",
|
|
137
135
|
skills: "Skill activity",
|
|
138
|
-
mcp: "MCP
|
|
136
|
+
mcp: "MCP runtime servers",
|
|
139
137
|
context: "Context usage",
|
|
140
138
|
inputTokens: "Input tokens",
|
|
141
139
|
outputTokens: "Output tokens",
|
|
@@ -154,7 +152,7 @@ const footerSegmentSettingDescriptions: Record<FooterSegmentSettingId, string> =
|
|
|
154
152
|
"Show numeric ahead/behind and stash counts (requires the Git status segment to be enabled).",
|
|
155
153
|
sessionDuration: "Show session running time on the session row.",
|
|
156
154
|
username: "Show user@hostname on the project row.",
|
|
157
|
-
time: "Show the current time (HH:MM) on the
|
|
155
|
+
time: "Show the current time (HH:MM) after duration on the session row.",
|
|
158
156
|
os: "Show an operating-system icon on the project row.",
|
|
159
157
|
runtime: "Show or hide the detected runtime/language on the project row.",
|
|
160
158
|
context: "Show or hide context usage on the usage row.",
|
|
@@ -175,11 +173,9 @@ const footerSegmentSettingDescriptions: Record<FooterSegmentSettingId, string> =
|
|
|
175
173
|
codexUsage: "Show OpenAI Codex subscription rate limits on the usage row when available.",
|
|
176
174
|
configCounts: "Show instruction-file and installed Pi package counts on the project row.",
|
|
177
175
|
skills: "Show active/available Pi skill counts on the activity row.",
|
|
178
|
-
mcp: "Show
|
|
176
|
+
mcp: "Show MCP servers with exposed runtime tools reported by Pi.",
|
|
179
177
|
runningTools: "Show currently running native tools and their elapsed time.",
|
|
180
178
|
toolCounts: "Show cumulative completed native-tool counts.",
|
|
181
|
-
activeAgents: "Show active main agent runs on the activity row (not subagent count).",
|
|
182
|
-
agentIdle: "Show Agent idle when no main agent run is active.",
|
|
183
179
|
};
|
|
184
180
|
|
|
185
181
|
const directCommandSuggestions = [
|
|
@@ -257,9 +253,7 @@ function isFooterSegmentSettingId(value: string): value is FooterSegmentSettingI
|
|
|
257
253
|
value === "skills" ||
|
|
258
254
|
value === "mcp" ||
|
|
259
255
|
value === "runningTools" ||
|
|
260
|
-
value === "toolCounts"
|
|
261
|
-
value === "activeAgents" ||
|
|
262
|
-
value === "agentIdle"
|
|
256
|
+
value === "toolCounts"
|
|
263
257
|
);
|
|
264
258
|
}
|
|
265
259
|
|
|
@@ -333,7 +327,7 @@ function footerSegmentPatch(
|
|
|
333
327
|
}
|
|
334
328
|
|
|
335
329
|
function usageText(): string {
|
|
336
|
-
return 'Usage: /
|
|
330
|
+
return 'Usage: /hud statusline [enable|disable|toggle], /hud row [project|session|activity|usage] [enable|disable|toggle], or /hud format "<template>", /hud compact-format "<template>"|clear, /hud footer hud|hidden|native, /hud layout|extensions|segments';
|
|
337
331
|
}
|
|
338
332
|
|
|
339
333
|
function isFooterRow(value: string): value is keyof FooterRowsConfig {
|
|
@@ -602,9 +596,9 @@ function withSectionFooter(lines: string[], theme: ExtensionContext["ui"]["theme
|
|
|
602
596
|
return next;
|
|
603
597
|
}
|
|
604
598
|
|
|
605
|
-
export function
|
|
606
|
-
pi.registerCommand("
|
|
607
|
-
description: "Configure
|
|
599
|
+
export function registerHudSettingsCommand(pi: ExtensionAPI, deps: SettingsCommandDeps): void {
|
|
600
|
+
pi.registerCommand("hud", {
|
|
601
|
+
description: "Configure Rinco HUD",
|
|
608
602
|
getArgumentCompletions: argumentCompletions,
|
|
609
603
|
handler: async (_args, ctx) => {
|
|
610
604
|
const args = typeof _args === "string" ? _args : "";
|
|
@@ -673,7 +667,7 @@ export function registerZentuiSettingsCommand(pi: ExtensionAPI, deps: SettingsCo
|
|
|
673
667
|
}
|
|
674
668
|
} catch (error) {
|
|
675
669
|
const message = error instanceof Error ? error.message : String(error);
|
|
676
|
-
if (ctx.hasUI) ctx.ui.notify(`Could not update
|
|
670
|
+
if (ctx.hasUI) ctx.ui.notify(`Could not update HUD settings: ${message}`, "error");
|
|
677
671
|
}
|
|
678
672
|
return;
|
|
679
673
|
}
|
|
@@ -691,7 +685,7 @@ export function registerZentuiSettingsCommand(pi: ExtensionAPI, deps: SettingsCo
|
|
|
691
685
|
}
|
|
692
686
|
} catch (error) {
|
|
693
687
|
const message = error instanceof Error ? error.message : String(error);
|
|
694
|
-
if (ctx.hasUI) ctx.ui.notify(`Could not update
|
|
688
|
+
if (ctx.hasUI) ctx.ui.notify(`Could not update HUD settings: ${message}`, "error");
|
|
695
689
|
}
|
|
696
690
|
return;
|
|
697
691
|
}
|
|
@@ -859,7 +853,7 @@ export function registerZentuiSettingsCommand(pi: ExtensionAPI, deps: SettingsCo
|
|
|
859
853
|
settingsList = makeSettingsList();
|
|
860
854
|
tui.requestRender();
|
|
861
855
|
const message = error instanceof Error ? error.message : String(error);
|
|
862
|
-
ctx.ui.notify(`Could not update
|
|
856
|
+
ctx.ui.notify(`Could not update HUD settings: ${message}`, "error");
|
|
863
857
|
}
|
|
864
858
|
},
|
|
865
859
|
() => done(undefined),
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { createRequire } from "node:module";
|
|
2
2
|
import { readFileSync, statSync } from "node:fs";
|
|
3
3
|
import { isAbsolute, join } from "node:path";
|
|
4
|
-
import { countConfiguredMcpServers } from "../segments/mcp-status.js";
|
|
5
4
|
|
|
6
5
|
export interface ConfigCounts {
|
|
7
6
|
instructionFiles: {
|
|
@@ -10,7 +9,6 @@ export interface ConfigCounts {
|
|
|
10
9
|
total: number;
|
|
11
10
|
};
|
|
12
11
|
packages: number;
|
|
13
|
-
mcpServers: number;
|
|
14
12
|
}
|
|
15
13
|
|
|
16
14
|
export interface ConfigCountOptions {
|
|
@@ -84,7 +82,6 @@ export function countConfigEntries(cwd: string, options: ConfigCountOptions = {}
|
|
|
84
82
|
total: agentsMd + claudeMd,
|
|
85
83
|
},
|
|
86
84
|
packages: countPackages(agentDir),
|
|
87
|
-
mcpServers: countConfiguredMcpServers(cwd, agentDir),
|
|
88
85
|
};
|
|
89
86
|
}
|
|
90
87
|
|
|
@@ -166,7 +166,7 @@ function footerSegmentValue(
|
|
|
166
166
|
function footerSegmentValueWithLegacy(
|
|
167
167
|
record: Record<string, unknown>,
|
|
168
168
|
key: keyof FooterSegmentsConfig,
|
|
169
|
-
legacyKey: "tokens" | "toolActivity"
|
|
169
|
+
legacyKey: "tokens" | "toolActivity",
|
|
170
170
|
): boolean {
|
|
171
171
|
const value = record[key];
|
|
172
172
|
if (typeof value === "boolean") return value;
|
|
@@ -268,8 +268,6 @@ function normalizeFooterSegments(record: Record<string, unknown>): FooterSegment
|
|
|
268
268
|
mcp: footerSegmentValue(record, "mcp"),
|
|
269
269
|
runningTools: footerSegmentValueWithLegacy(record, "runningTools", "toolActivity"),
|
|
270
270
|
toolCounts: footerSegmentValueWithLegacy(record, "toolCounts", "toolActivity"),
|
|
271
|
-
activeAgents: footerSegmentValueWithLegacy(record, "activeAgents", "agentActivity"),
|
|
272
|
-
agentIdle: footerSegmentValueWithLegacy(record, "agentIdle", "agentActivity"),
|
|
273
271
|
};
|
|
274
272
|
}
|
|
275
273
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* `save*Patch` functions: validate a partial settings patch, merge it into
|
|
3
3
|
* the on-disk config record via `mutateConfig`, and return the freshly
|
|
4
4
|
* merged `PolishedTuiConfig`. Each function only accepts fields/values that
|
|
5
|
-
* pass the corresponding type guard, so callers (e.g. the `/
|
|
5
|
+
* pass the corresponding type guard, so callers (e.g. the `/hud` settings
|
|
6
6
|
* UI) cannot write malformed values into the config file.
|
|
7
7
|
*/
|
|
8
8
|
import { normalizeIconMode } from "../ui/icons.js";
|
|
@@ -75,9 +75,7 @@ function isFooterSegmentKey(value: string): value is keyof FooterSegmentsConfig
|
|
|
75
75
|
value === "skills" ||
|
|
76
76
|
value === "mcp" ||
|
|
77
77
|
value === "runningTools" ||
|
|
78
|
-
value === "toolCounts"
|
|
79
|
-
value === "activeAgents" ||
|
|
80
|
-
value === "agentIdle"
|
|
78
|
+
value === "toolCounts"
|
|
81
79
|
);
|
|
82
80
|
}
|
|
83
81
|
|
|
@@ -79,8 +79,6 @@ export type FooterSegmentsConfig = {
|
|
|
79
79
|
mcp: boolean;
|
|
80
80
|
runningTools: boolean;
|
|
81
81
|
toolCounts: boolean;
|
|
82
|
-
activeAgents: boolean;
|
|
83
|
-
agentIdle: boolean;
|
|
84
82
|
};
|
|
85
83
|
|
|
86
84
|
export type ExtensionStatusPlacement = "off" | "left" | "middle" | "right";
|
|
@@ -206,7 +204,6 @@ export const FOOTER_FORMAT_VARIABLES = [
|
|
|
206
204
|
"mcp",
|
|
207
205
|
"tool_counts",
|
|
208
206
|
"running_tools",
|
|
209
|
-
"active_agents",
|
|
210
207
|
"sep",
|
|
211
208
|
"join_sep",
|
|
212
209
|
"extension_statuses",
|
|
@@ -237,7 +234,6 @@ export const FOOTER_FORMAT_ALIASES: Record<string, string> = {
|
|
|
237
234
|
turn_count: "turn",
|
|
238
235
|
codex: "codex_usage",
|
|
239
236
|
tools: "tool_counts",
|
|
240
|
-
agents: "active_agents",
|
|
241
237
|
separator: "sep",
|
|
242
238
|
};
|
|
243
239
|
|
|
@@ -349,8 +345,6 @@ export const defaultConfig: PolishedTuiConfig = {
|
|
|
349
345
|
mcp: true,
|
|
350
346
|
runningTools: true,
|
|
351
347
|
toolCounts: true,
|
|
352
|
-
activeAgents: true,
|
|
353
|
-
agentIdle: true,
|
|
354
348
|
},
|
|
355
349
|
gitCommit: {
|
|
356
350
|
hashLength: 7,
|
|
@@ -20,14 +20,13 @@ export interface SessionFooterSegments {
|
|
|
20
20
|
thinking: string;
|
|
21
21
|
turn: string;
|
|
22
22
|
duration: string;
|
|
23
|
+
time: string;
|
|
23
24
|
}
|
|
24
25
|
|
|
25
26
|
export interface ActivityFooterSegments {
|
|
26
27
|
category: string;
|
|
27
28
|
runningTools: string;
|
|
28
29
|
toolCounts: string;
|
|
29
|
-
activeAgents: string;
|
|
30
|
-
agentIdle: string;
|
|
31
30
|
skills: string;
|
|
32
31
|
mcp: string;
|
|
33
32
|
extensions: readonly string[];
|
|
@@ -41,7 +40,6 @@ export interface UsageFooterSegments {
|
|
|
41
40
|
cache: string;
|
|
42
41
|
cost: string;
|
|
43
42
|
quota: string;
|
|
44
|
-
time: string;
|
|
45
43
|
}
|
|
46
44
|
|
|
47
45
|
export interface CategorizedFooterGroupInput {
|
|
@@ -79,13 +77,12 @@ export function buildCategorizedFooterGroups(
|
|
|
79
77
|
input.session.thinking,
|
|
80
78
|
input.session.turn,
|
|
81
79
|
input.session.duration,
|
|
80
|
+
input.session.time,
|
|
82
81
|
]),
|
|
83
82
|
activity: compact([
|
|
84
83
|
input.activity.category,
|
|
85
84
|
input.activity.runningTools,
|
|
86
85
|
input.activity.toolCounts,
|
|
87
|
-
input.activity.activeAgents,
|
|
88
|
-
input.activity.agentIdle,
|
|
89
86
|
input.activity.skills,
|
|
90
87
|
input.activity.mcp,
|
|
91
88
|
...input.activity.extensions,
|
|
@@ -98,7 +95,6 @@ export function buildCategorizedFooterGroups(
|
|
|
98
95
|
input.usage.cache,
|
|
99
96
|
input.usage.cost,
|
|
100
97
|
input.usage.quota,
|
|
101
|
-
input.usage.time,
|
|
102
98
|
]),
|
|
103
99
|
};
|
|
104
100
|
}
|
|
@@ -53,6 +53,7 @@ export function installFooter(
|
|
|
53
53
|
scheduleProjectRefresh: (ctx: ExtensionContext) => void;
|
|
54
54
|
setExtensionStatusesGetter?: (fn: (() => ReadonlyMap<string, string>) | undefined) => void;
|
|
55
55
|
getLiveContext?: () => LiveContextOverride | undefined;
|
|
56
|
+
getMcpServerCount?: () => number;
|
|
56
57
|
getCustomValues?: () => ReadonlyMap<string, string>;
|
|
57
58
|
getTemplateValues?: () => ReadonlyMap<string, string>;
|
|
58
59
|
setOwnership?: (owned: boolean) => void;
|
|
@@ -200,9 +201,14 @@ export function installFooter(
|
|
|
200
201
|
mcpLabel,
|
|
201
202
|
toolCountsLabel,
|
|
202
203
|
runningToolsLabel,
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
204
|
+
} = buildTelemetryLabels(
|
|
205
|
+
ctx,
|
|
206
|
+
state,
|
|
207
|
+
config,
|
|
208
|
+
theme,
|
|
209
|
+
colorSource,
|
|
210
|
+
hooks.getMcpServerCount?.() ?? 0,
|
|
211
|
+
);
|
|
206
212
|
const rawCustomValues = hooks.getCustomValues?.() ?? new Map<string, string>();
|
|
207
213
|
const customValues = new Map<string, string>();
|
|
208
214
|
for (const [alias, key] of Object.entries(config.footerVariables)) {
|
|
@@ -391,8 +397,6 @@ export function installFooter(
|
|
|
391
397
|
return toolCountsLabel;
|
|
392
398
|
case "running_tools":
|
|
393
399
|
return runningToolsLabel;
|
|
394
|
-
case "active_agents":
|
|
395
|
-
return activeAgentsLabel || agentIdleLabel;
|
|
396
400
|
case "subscription":
|
|
397
401
|
case "auto_compaction":
|
|
398
402
|
case "pr_number":
|
|
@@ -589,13 +593,12 @@ export function installFooter(
|
|
|
589
593
|
thinking: config.footerSegments.thinking ? thinkingLabel : "",
|
|
590
594
|
turn: config.footerSegments.turnCount ? turnLabel : "",
|
|
591
595
|
duration: sessionDurationSegment,
|
|
596
|
+
time: timeSegment,
|
|
592
597
|
},
|
|
593
598
|
activity: {
|
|
594
599
|
category: activityCategoryLabel,
|
|
595
600
|
runningTools: config.footerSegments.runningTools ? runningToolsLabel : "",
|
|
596
601
|
toolCounts: config.footerSegments.toolCounts ? toolCountsLabel : "",
|
|
597
|
-
activeAgents: config.footerSegments.activeAgents ? activeAgentsLabel : "",
|
|
598
|
-
agentIdle: config.footerSegments.agentIdle ? agentIdleLabel : "",
|
|
599
602
|
skills: config.footerSegments.skills ? skillsLabel : "",
|
|
600
603
|
mcp: config.footerSegments.mcp ? mcpLabel : "",
|
|
601
604
|
extensions: [...extensionLeft, ...extensionMiddle, ...extensionRight],
|
|
@@ -612,7 +615,6 @@ export function installFooter(
|
|
|
612
615
|
? renderStyleForSource(theme, colorSource, config.colors.cost, state.costLabel)
|
|
613
616
|
: "",
|
|
614
617
|
quota: config.footerSegments.codexUsage ? codexUsageLabel : "",
|
|
615
|
-
time: timeSegment,
|
|
616
618
|
},
|
|
617
619
|
});
|
|
618
620
|
const contents = composeCategorizedFooterRows(
|
|
@@ -151,18 +151,17 @@ export type TelemetryLabels = {
|
|
|
151
151
|
mcpLabel: string;
|
|
152
152
|
toolCountsLabel: string;
|
|
153
153
|
runningToolsLabel: string;
|
|
154
|
-
activeAgentsLabel: string;
|
|
155
|
-
agentIdleLabel: string;
|
|
156
154
|
};
|
|
157
155
|
|
|
158
156
|
/** Build every session/activity/usage-row telemetry label (model, thinking level,
|
|
159
|
-
* turn count, cache/tool
|
|
157
|
+
* turn count, cache/tool counters, skills, MCP, Codex usage, …). */
|
|
160
158
|
export function buildTelemetryLabels(
|
|
161
159
|
ctx: Pick<ExtensionContext, "model">,
|
|
162
160
|
state: FooterState,
|
|
163
161
|
config: PolishedTuiConfig,
|
|
164
162
|
theme: ThemeLike,
|
|
165
163
|
colorSource: ColorSource,
|
|
164
|
+
mcpServerCount = 0,
|
|
166
165
|
): TelemetryLabels {
|
|
167
166
|
const statusStyle = (style: string, text: string) =>
|
|
168
167
|
text ? renderStyleForSource(theme, colorSource, style, text) : "";
|
|
@@ -266,9 +265,7 @@ export function buildTelemetryLabels(
|
|
|
266
265
|
const configCountsLabel = [instructionFilesLabel, extensionsLabel].filter(Boolean).join(" ");
|
|
267
266
|
|
|
268
267
|
const mcpLabel =
|
|
269
|
-
|
|
270
|
-
? statusStyle(config.colors.gitStatus, `MCP ${state.configCounts.mcpServers}`)
|
|
271
|
-
: "";
|
|
268
|
+
mcpServerCount > 0 ? statusStyle(config.colors.gitStatus, `MCP ${mcpServerCount}`) : "";
|
|
272
269
|
|
|
273
270
|
const telemetryStats = getTelemetryStats(state.telemetry);
|
|
274
271
|
const toolCountsText = Object.entries(telemetryStats.completedToolCounts)
|
|
@@ -286,12 +283,6 @@ export function buildTelemetryLabels(
|
|
|
286
283
|
})
|
|
287
284
|
.join(" ");
|
|
288
285
|
const runningToolsLabel = statusStyle(config.colors.contextWarning, runningToolsText);
|
|
289
|
-
const activeAgentsLabel =
|
|
290
|
-
telemetryStats.activeAgentRuns > 0
|
|
291
|
-
? statusStyle(config.colors.extensionStatus, `Agent × ${telemetryStats.activeAgentRuns}`)
|
|
292
|
-
: "";
|
|
293
|
-
const agentIdleLabel =
|
|
294
|
-
telemetryStats.activeAgentRuns === 0 ? statusStyle(config.colors.muted, "Agent idle") : "";
|
|
295
286
|
|
|
296
287
|
return {
|
|
297
288
|
projectCategoryLabel,
|
|
@@ -322,7 +313,5 @@ export function buildTelemetryLabels(
|
|
|
322
313
|
mcpLabel,
|
|
323
314
|
toolCountsLabel,
|
|
324
315
|
runningToolsLabel,
|
|
325
|
-
activeAgentsLabel,
|
|
326
|
-
agentIdleLabel,
|
|
327
316
|
};
|
|
328
317
|
}
|
package/extensions/hud/index.ts
CHANGED
|
@@ -9,6 +9,7 @@ import { CustomVariables } from "./segments/custom-variables.js";
|
|
|
9
9
|
import { createLiveMetadata } from "./segments/live-metadata.js";
|
|
10
10
|
import { FooterTelemetryController } from "./telemetry/optional.js";
|
|
11
11
|
import { emptyGitStatus } from "./segments/git.js";
|
|
12
|
+
import { getMcpServerCount } from "./segments/mcp-status.js";
|
|
12
13
|
import { LiveContextController } from "./session/live-context.js";
|
|
13
14
|
import { createProjectStateController } from "./state/project-controller.js";
|
|
14
15
|
import { isLiveExtensionContext } from "./session/context.js";
|
|
@@ -200,6 +201,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
200
201
|
getActiveExtensionStatuses = fn ?? (() => new Map());
|
|
201
202
|
},
|
|
202
203
|
getLiveContext: () => liveContext.get(),
|
|
204
|
+
getMcpServerCount: () => getMcpServerCount(pi),
|
|
203
205
|
getCustomValues: () => customVariables.snapshot(),
|
|
204
206
|
getTemplateValues: () => new Map([...templateValues, ...metadata.values()]),
|
|
205
207
|
setOwnership(owned) {
|
|
@@ -1,31 +1,28 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { join } from "node:path";
|
|
1
|
+
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
3
2
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
3
|
+
/** Count MCP namespaces with exposed runtime tools, not configuration entries or connections.
|
|
4
|
+
* Pi owns configuration, trust, credentials, and connections. getMcpServers() only lists
|
|
5
|
+
* extension registrations, whereas getAllTools() includes tools from file-configured servers
|
|
6
|
+
* and extensions, including codemode/deferred tools absent from the active tool set.
|
|
7
|
+
* Hidden tools remain registered after a server is disabled or removed, so exclude them.
|
|
8
|
+
* Resource-only servers cannot be identified through this public API and are not counted.
|
|
9
|
+
*/
|
|
10
|
+
export function getMcpServerCount(pi: Pick<ExtensionAPI, "getAllTools">): number {
|
|
11
11
|
try {
|
|
12
|
-
const
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
12
|
+
const namespaces = new Set<string>();
|
|
13
|
+
for (const tool of pi.getAllTools()) {
|
|
14
|
+
const namespace = tool.namespace?.name;
|
|
15
|
+
if (
|
|
16
|
+
tool.exposure !== "hidden" &&
|
|
17
|
+
namespace &&
|
|
18
|
+
/^mcp__[A-Za-z0-9_]+$/.test(namespace) &&
|
|
19
|
+
tool.name.startsWith(`${namespace}__`)
|
|
20
|
+
) {
|
|
21
|
+
namespaces.add(namespace);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
return namespaces.size;
|
|
19
25
|
} catch {
|
|
20
|
-
return
|
|
26
|
+
return 0;
|
|
21
27
|
}
|
|
22
28
|
}
|
|
23
|
-
|
|
24
|
-
/** Count file-configured server entries, including disabled ones, without resolving secrets
|
|
25
|
-
* or starting connections. Project entries override global entries with the same name.
|
|
26
|
-
* This is not a connection count or a validation of individual server settings. */
|
|
27
|
-
export function countConfiguredMcpServers(cwd: string, agentDir: string): number {
|
|
28
|
-
const globalNames = agentDir ? readServerNames(join(agentDir, "mcp.json")) : [];
|
|
29
|
-
const projectNames = readServerNames(join(cwd, ".pi", "mcp.json"));
|
|
30
|
-
return new Set([...globalNames, ...projectNames]).size;
|
|
31
|
-
}
|
|
@@ -79,18 +79,10 @@ export function registerSessionEventHandlers(
|
|
|
79
79
|
|
|
80
80
|
pi.on("agent_start", (event, ctx) => {
|
|
81
81
|
deps.liveContext.clear();
|
|
82
|
-
deps.state.telemetry = updateTelemetryState(deps.state.telemetry, {
|
|
83
|
-
type: "agent-start",
|
|
84
|
-
at: Date.now(),
|
|
85
|
-
});
|
|
86
82
|
syncInteractiveState(event, ctx);
|
|
87
83
|
});
|
|
88
84
|
pi.on("agent_end", (event, ctx) => {
|
|
89
85
|
deps.liveContext.clear();
|
|
90
|
-
deps.state.telemetry = updateTelemetryState(deps.state.telemetry, {
|
|
91
|
-
type: "agent-end",
|
|
92
|
-
at: Date.now(),
|
|
93
|
-
});
|
|
94
86
|
syncInteractiveAndProjectState(event, ctx);
|
|
95
87
|
});
|
|
96
88
|
pi.on("model_select", (event, ctx) => {
|
|
@@ -18,7 +18,8 @@ export function footerClockNeeds(
|
|
|
18
18
|
const defaultLayout = !config.footerFormat;
|
|
19
19
|
return {
|
|
20
20
|
wallClock:
|
|
21
|
-
names.has("time") ||
|
|
21
|
+
names.has("time") ||
|
|
22
|
+
(defaultLayout && config.footerRows.session && config.footerSegments.time),
|
|
22
23
|
duration:
|
|
23
24
|
names.has("session_duration") ||
|
|
24
25
|
(defaultLayout && config.footerRows.session && config.footerSegments.sessionDuration),
|
|
@@ -4,7 +4,6 @@ export const TRACKED_TOOL_NAMES = ["read", "write", "edit", "bash", "grep", "ls"
|
|
|
4
4
|
|
|
5
5
|
export type TrackedToolName = (typeof TRACKED_TOOL_NAMES)[number];
|
|
6
6
|
export type ToolStatus = "running" | "completed" | "error";
|
|
7
|
-
export type AgentRunStatus = "running" | "completed";
|
|
8
7
|
|
|
9
8
|
export interface ToolRecord {
|
|
10
9
|
toolCallId: string;
|
|
@@ -15,19 +14,12 @@ export interface ToolRecord {
|
|
|
15
14
|
endTime?: number;
|
|
16
15
|
}
|
|
17
16
|
|
|
18
|
-
export interface AgentRunRecord {
|
|
19
|
-
status: AgentRunStatus;
|
|
20
|
-
startTime: number;
|
|
21
|
-
endTime?: number;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
17
|
export interface TelemetryState {
|
|
25
18
|
sessionName: string | undefined;
|
|
26
19
|
turnIndex: number;
|
|
27
20
|
thinkingLevel: string;
|
|
28
21
|
modelSupportsReasoning: boolean;
|
|
29
22
|
tools: readonly ToolRecord[];
|
|
30
|
-
agentRuns: readonly AgentRunRecord[];
|
|
31
23
|
}
|
|
32
24
|
|
|
33
25
|
export interface TelemetryInitialValues {
|
|
@@ -47,21 +39,16 @@ export type TelemetryUpdate =
|
|
|
47
39
|
args?: Record<string, unknown> | null;
|
|
48
40
|
at: number;
|
|
49
41
|
}
|
|
50
|
-
| { type: "tool-result"; toolCallId: string; isError: boolean; at: number }
|
|
51
|
-
| { type: "agent-start"; at: number }
|
|
52
|
-
| { type: "agent-end"; at: number };
|
|
42
|
+
| { type: "tool-result"; toolCallId: string; isError: boolean; at: number };
|
|
53
43
|
|
|
54
44
|
export interface TelemetryStats {
|
|
55
45
|
completedToolCounts: Record<TrackedToolName, number>;
|
|
56
46
|
recentRunningTools: readonly ToolRecord[];
|
|
57
|
-
activeAgentRuns: number;
|
|
58
47
|
}
|
|
59
48
|
|
|
60
49
|
const trackedToolNames = new Set<string>(TRACKED_TOOL_NAMES);
|
|
61
50
|
const TOOL_HISTORY_LIMIT = 500;
|
|
62
51
|
const TOOL_HISTORY_RETAINED = 400;
|
|
63
|
-
const AGENT_HISTORY_LIMIT = 500;
|
|
64
|
-
const AGENT_HISTORY_RETAINED = 400;
|
|
65
52
|
const MAX_EXTERNAL_TEXT_LENGTH = 2048;
|
|
66
53
|
const thinkingLevels = new Set(["off", "minimal", "low", "medium", "high", "xhigh", "max"]);
|
|
67
54
|
|
|
@@ -87,7 +74,6 @@ export function createTelemetryState(initial: TelemetryInitialValues = {}): Tele
|
|
|
87
74
|
thinkingLevel: normalizeThinkingLevel(initial.thinkingLevel),
|
|
88
75
|
modelSupportsReasoning: initial.modelSupportsReasoning ?? false,
|
|
89
76
|
tools: [],
|
|
90
|
-
agentRuns: [],
|
|
91
77
|
};
|
|
92
78
|
}
|
|
93
79
|
|
|
@@ -193,21 +179,6 @@ function finishTool(
|
|
|
193
179
|
return { ...state, tools };
|
|
194
180
|
}
|
|
195
181
|
|
|
196
|
-
function finishLatestAgentRun(state: TelemetryState, at: number): TelemetryState {
|
|
197
|
-
let matchIndex = -1;
|
|
198
|
-
for (let index = state.agentRuns.length - 1; index >= 0; index -= 1) {
|
|
199
|
-
if (state.agentRuns[index]?.status === "running") {
|
|
200
|
-
matchIndex = index;
|
|
201
|
-
break;
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
if (matchIndex < 0) return state;
|
|
205
|
-
|
|
206
|
-
const agentRuns = [...state.agentRuns];
|
|
207
|
-
agentRuns[matchIndex] = { ...agentRuns[matchIndex]!, status: "completed", endTime: at };
|
|
208
|
-
return { ...state, agentRuns };
|
|
209
|
-
}
|
|
210
|
-
|
|
211
182
|
export function updateTelemetryState(
|
|
212
183
|
state: TelemetryState,
|
|
213
184
|
update: TelemetryUpdate,
|
|
@@ -221,15 +192,6 @@ export function updateTelemetryState(
|
|
|
221
192
|
return addTool(state, update);
|
|
222
193
|
case "tool-result":
|
|
223
194
|
return finishTool(state, update);
|
|
224
|
-
case "agent-start": {
|
|
225
|
-
let agentRuns = [...state.agentRuns, { status: "running" as const, startTime: update.at }];
|
|
226
|
-
if (agentRuns.length > AGENT_HISTORY_LIMIT) {
|
|
227
|
-
agentRuns = agentRuns.slice(-AGENT_HISTORY_RETAINED);
|
|
228
|
-
}
|
|
229
|
-
return { ...state, agentRuns };
|
|
230
|
-
}
|
|
231
|
-
case "agent-end":
|
|
232
|
-
return finishLatestAgentRun(state, update.at);
|
|
233
195
|
}
|
|
234
196
|
}
|
|
235
197
|
|
|
@@ -254,12 +216,8 @@ export function getTelemetryStats(state: TelemetryState): TelemetryStats {
|
|
|
254
216
|
.filter((tool) => tool.status === "running")
|
|
255
217
|
.slice(-2)
|
|
256
218
|
.map((tool) => ({ ...tool }));
|
|
257
|
-
const activeAgentRuns = state.agentRuns.reduce(
|
|
258
|
-
(count, run) => count + (run.status === "running" ? 1 : 0),
|
|
259
|
-
0,
|
|
260
|
-
);
|
|
261
219
|
|
|
262
|
-
return { completedToolCounts, recentRunningTools
|
|
220
|
+
return { completedToolCounts, recentRunningTools };
|
|
263
221
|
}
|
|
264
222
|
|
|
265
223
|
export const createTelemetry = createTelemetryState;
|