rinco-pi-hud 1.0.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -12,17 +12,18 @@
12
12
 
13
13
  </div>
14
14
 
15
- Rinco Pi HUD provides a rich, real-time status footer for Pi TUI sessions. It displays project state, Git metrics, runtime versions, session activity, model usage, token costs, and more — all in a configurable three-line or single-line layout. Pi loads the TypeScript extension directly, so no build step is required (`tsconfig.json` sets `noEmit: true` and is used only for `npm run typecheck`).
15
+ Rinco Pi HUD provides a rich, real-time status footer for Pi TUI sessions. It displays project state, Git metrics, runtime versions, session activity, model usage, token costs, and more — all in a responsive four-group or customizable single-line layout. Pi loads the TypeScript extension directly, so no build step is required (`tsconfig.json` sets `noEmit: true` and is used only for `npm run typecheck`).
16
16
 
17
17
  ## Features
18
18
 
19
- - **Project state** — Working directory, Git branch, commit, tag, status, diff metrics, and runtime versions.
20
- - **Session activity** — Model, provider, context usage, tokens, cache, session cost, turn count, and thinking level.
21
- - **Tool and agent activity** — Native tool completion counts, running tools, active agent runs, skills, and MCP server status.
19
+ - **Project state** — Working directory, Git branch, commit, tag, status, operation state, diff metrics, and runtime versions.
20
+ - **Session activity** — Model, provider, context usage, independently controlled input/output tokens, cache, session cost, turn count, and thinking level.
21
+ - **Tool and agent activity** — Independent controls for running tools, completed tool counts, active agents, idle state, skills, and MCP server status.
22
22
  - **Model quota** — Automatic Codex weekly quota or Token Switch balance display by model provider.
23
23
  - **Git awareness** — Branches, detached HEAD, tags, ahead/behind, stash, merge/rebase conflicts, and dirty state.
24
24
  - **Runtime detection** — Node, Python, Go, Rust, Java, and 60+ other runtimes with package version parsing.
25
- - **Configurable layout** — Three-line categorized layout by default, or fully customizable single-line templates.
25
+ - **Configurable layout** — Responsive Project, Session, Activity, and Usage groups by default, or fully customizable single-line templates.
26
+ - **Granular status controls** — Toggle Git operation state, tool runtime/counts, active/idle agents, and input/output tokens separately from `/zentui`.
26
27
  - **Extension statuses** — Reads third-party extension statuses and places them by configurable position and color mode.
27
28
  - **Safe fallback** — Graceful timeout and error handling; no stale data after session shutdown.
28
29
 
@@ -82,24 +83,24 @@ The HUD footer is enabled by default. Run `/zentui` to open the interactive sett
82
83
 
83
84
  | Path | Purpose |
84
85
  | --- | --- |
85
- | [`extensions/hud/index.ts`](extensions/hud/index.ts) | Extension lifecycle and side-effect orchestration |
86
- | [`extensions/hud/config/`](extensions/hud/config/config.ts) | Configuration model, normalization, and persistence |
87
- | [`extensions/hud/footer/`](extensions/hud/footer/index.ts) | Footer rendering, categorized layout, and template parsing |
86
+ | [`extensions/hud/index.ts`](extensions/hud/index.ts) | Composition root for controllers, shared state, and UI installation |
87
+ | [`extensions/hud/config/`](extensions/hud/config/config.ts) | Configuration model, normalization, migration, and persistence |
88
+ | [`extensions/hud/footer/`](extensions/hud/footer/index.ts) | Footer rendering, semantic grouping, responsive layout, and template parsing |
88
89
  | [`extensions/hud/segments/`](extensions/hud/segments/) | State collectors: Git, runtime, MCP, skills, projects, etc. |
89
90
  | [`extensions/hud/telemetry/`](extensions/hud/telemetry/format.ts) | Usage formatting, token switch, and Codex subscription client |
90
- | [`extensions/hud/session/`](extensions/hud/session/) | Session lifecycle, context, and live context overlay |
91
- | [`extensions/hud/state/`](extensions/hud/state/) | Aggregated state, telemetry, and project refresh |
92
- | [`extensions/hud/commands/`](extensions/hud/commands/settings.ts) | `/zentui` command and interactive TUI settings |
91
+ | [`extensions/hud/session/`](extensions/hud/session/) | Pi event registration, session lifecycle, and live context overlay |
92
+ | [`extensions/hud/state/`](extensions/hud/state/) | Aggregated state, telemetry reducer, and project refresh controller |
93
+ | [`extensions/hud/commands/`](extensions/hud/commands/settings.ts) | `/zentui` settings UI and configuration controller |
93
94
  | [`extensions/hud/ui/`](extensions/hud/ui/) | Icons and terminal style utilities |
94
95
  | [`docs/footer.md`](docs/footer.md) | Complete footer configuration reference |
95
96
  | [`docs/CONTRIBUTING.md`](docs/CONTRIBUTING.md) | Local development, testing guidance, and pull request checklist |
96
- | [`tests/`](tests/) | Vitest test suite (34+ tests across 6 files) |
97
+ | [`tests/`](tests/) | Vitest test suite (41 tests across 8 files) |
97
98
 
98
99
  ## Customization
99
100
 
100
101
  ### Layout
101
102
 
102
- The default three-line layout groups project, session, and usage information. Set `footerFormat` to a template string for a single-line layout:
103
+ The default layout groups Project, Session, Activity, and Usage information. Long groups wrap at complete segment boundaries with aligned continuation lines. Set `footerFormat` to a template string for a single-line layout:
103
104
 
104
105
  ```text
105
106
  /zentui format "$cwd( $git_branch)$fill($context)( $tokens)( $cost)"
@@ -109,13 +110,16 @@ Template variables use `$name` or `${name}` syntax. See the [footer reference](d
109
110
 
110
111
  ### Segments
111
112
 
112
- Enable or disable individual status segments via `/zentui`:
113
+ Open `/zentui`, then select **Built-in segments** to enable or disable individual statuses. Fine-grained controls include:
113
114
 
114
- ```text
115
- /zentui statusline enable
116
- /zentui statusline disable
117
- /zentui statusline toggle
118
- ```
115
+ | Group | Independently controlled statuses |
116
+ | --- | --- |
117
+ | Project | Git status, Git operation state (`MERGING`, `REBASING`, etc.), commit, metrics, runtime, package, OS, and user |
118
+ | Session | Model, thinking level, turn count, and duration |
119
+ | Activity | Running tools, completed tool counts, active agents, `Agent idle`, skills, and MCP |
120
+ | Usage | Context, input tokens, output tokens, cache details/hit rate, cost, quota, and time |
121
+
122
+ Existing configs using the former aggregate `tokens`, `toolActivity`, or `agentActivity` switches are migrated automatically. The whole footer can still be controlled with `/zentui statusline enable|disable|toggle`.
119
123
 
120
124
  ### Extension statuses
121
125
 
@@ -48,7 +48,9 @@ Tests live in `tests/`:
48
48
 
49
49
  - `zentui-status.test.ts` — Config counts, MCP status parsing, and extension status helpers.
50
50
  - `codex-usage.test.ts` — Codex payload normalization and model-specific quota formatting.
51
- - `footer-layout.test.ts` — Categorized three-line layout and narrow-width budget.
51
+ - `footer-layout.test.ts` — Four-group categorized layout, segment wrapping, and narrow-width budget.
52
+ - `footer-groups.test.ts` — Semantic Project, Session, Activity, and Usage segment ordering.
53
+ - `footer-segment-controls.test.ts` — Independent status controls and legacy-config migration.
52
54
  - `model-switch-statusline.test.ts` — Model switch statusline integration.
53
55
  - `model-usage-refresh.test.ts` — Model usage refresh integration.
54
56
  - `token-switch-usage.test.ts` — Token Switch balance formatting.
@@ -78,24 +80,36 @@ Do not add ignore rules, skip tests, or weaken types merely to bypass a check.
78
80
 
79
81
  The HUD extension is organized into functional modules under `extensions/hud/`:
80
82
 
81
- - **`index.ts`** — Lifecycle and side-effect orchestration.
83
+ - **`index.ts`** — Composition root for controllers, shared state, and UI installation.
84
+ - **`commands/`** — `/zentui` presentation and its configuration-persistence controller.
82
85
  - **`config/`** — Configuration model, normalization, and persistence.
83
- - **`footer/`** — Footer rendering, categorized layout, and template parsing.
86
+ - **`footer/`** — Footer rendering, semantic group construction, responsive layout, and templates.
84
87
  - **`segments/`** — State collectors: Git, runtime, MCP, skills, projects, etc.
88
+ - **`session/`** — Pi event registration, lifecycle generations, and live-context throttling.
89
+ - **`state/`** — Shared footer state, telemetry reducer, and project-refresh controller.
85
90
  - **`telemetry/`** — Usage formatting, token switch, and Codex subscription client.
86
- - **`session/`** — Session lifecycle, context, and live context overlay.
87
- - **`state/`** — Aggregated state, telemetry, and project refresh.
88
- - **`commands/`** — `/zentui` command and interactive TUI settings.
89
91
  - **`ui/`** — Icons and terminal style utilities.
90
92
 
91
93
  Key conventions:
92
94
 
93
- - Keep event listeners and side-effects in `index.ts`; do not read files or spawn processes in `render()`.
95
+ - Keep composition in `index.ts`, Pi event listeners in `session/event-handlers.ts`, and avoid file reads or subprocesses in `render()`.
94
96
  - Async results check session generation before applying.
95
97
  - Timers should be cleaned up on shutdown and `unref()` where possible.
96
98
  - State collectors return explicit `ok` / `error` / `not found` semantics.
97
99
  - Use `visibleWidth()` and `truncateToWidth()` for terminal width calculations.
98
100
 
101
+ ## Releases
102
+
103
+ npm releases use GitHub Trusted Publishing through `.github/workflows/publish.yml`; no `NPM_TOKEN` repository secret is required. The workflow has narrowly scoped `id-token: write` permission, verifies the package, and publishes with provenance.
104
+
105
+ 1. Update the same version in `package.json` and `package-lock.json`.
106
+ 2. Commit and push the release changes to `main`.
107
+ 3. Create an annotated tag that exactly matches the package version, for example `git tag -a v1.1.0 -m "v1.1.0"`.
108
+ 4. Push the tag with `git push origin v1.1.0`.
109
+ 5. Confirm the **Publish npm package** workflow succeeds and verify the version on npm.
110
+
111
+ The tag/version guard fails the workflow before publication if they do not match.
112
+
99
113
  ## Pull request checklist
100
114
 
101
115
  Before opening a pull request, confirm that:
@@ -12,17 +12,18 @@
12
12
 
13
13
  </div>
14
14
 
15
- Rinco Pi HUD 为 Pi TUI 会话提供丰富的实时状态脚注,可显示项目状态、Git 指标、运行时版本、会话活动、模型用量、Token 费用等信息,支持可配置的三行或单行布局。Pi 可直接加载 TypeScript 扩展,无需构建步骤(`tsconfig.json` 设置了 `noEmit: true`,仅用于 `npm run typecheck` 类型检查)。
15
+ Rinco Pi HUD 为 Pi TUI 会话提供丰富的实时状态脚注,可显示项目状态、Git 指标、运行时版本、会话活动、模型用量、Token 费用等信息,支持响应式四分组布局或可定制的单行布局。Pi 可直接加载 TypeScript 扩展,无需构建步骤(`tsconfig.json` 设置了 `noEmit: true`,仅用于 `npm run typecheck` 类型检查)。
16
16
 
17
17
  ## 功能
18
18
 
19
- - **Project state**:当前目录、Git 分支、Commit、Tag、工作区状态、差异指标和运行时版本。
20
- - **Session activity**:模型、Provider、Context 用量、Token、缓存、会话费用、轮次和 Thinking 等级。
21
- - **Tool and agent activity**:Native Tool 完成次数、正在运行的 Tool、活跃 Agent 数、Skill 和 MCP Server 状态。
19
+ - **Project state**:当前目录、Git 分支、Commit、Tag、工作区状态、Git 操作状态、差异指标和运行时版本。
20
+ - **Session activity**:模型、Provider、Context 用量、可独立控制的输入/输出 Token、缓存、会话费用、轮次和 Thinking 等级。
21
+ - **Tool and agent activity**:可分别控制正在运行的 Tool、已完成 Tool 计数、活跃 Agent、空闲状态、Skill 和 MCP Server 状态。
22
22
  - **Model quota**:根据当前模型自动切换 Codex 周限额或 Token Switch 余额。
23
23
  - **Git awareness**:分支、Detached HEAD、Tag、Ahead/Behind、Stash、合并冲突和脏状态。
24
24
  - **Runtime detection**:支持 Node、Python、Go、Rust、Java 等 60+ 运行时,并解析项目清单版本。
25
- - **Configurable layout**:默认三行分类布局,或完全自定义的单行模板。
25
+ - **Configurable layout**:默认使用响应式 Project、Session、Activity、Usage 四分组布局,或完全自定义的单行模板。
26
+ - **Granular status controls**:可在 `/zentui` 中分别控制 Git 操作状态、Tool 运行状态/计数、Agent 活跃/空闲状态及输入/输出 Token。
26
27
  - **Extension statuses**:读取第三方扩展发布的状态,按配置的位置和颜色模式显示。
27
28
  - **Safe fallback**:超时和错误处理优雅,会话关闭后不留过期数据。
28
29
 
@@ -82,24 +83,24 @@ HUD 脚注默认启用。运行 `/zentui` 打开交互式设置。
82
83
 
83
84
  | 路径 | 说明 |
84
85
  | --- | --- |
85
- | [`extensions/hud/index.ts`](../extensions/hud/index.ts) | 扩展生命周期与副作用编排 |
86
- | [`extensions/hud/config/`](../extensions/hud/config/config.ts) | 配置模型、归一化与持久化 |
87
- | [`extensions/hud/footer/`](../extensions/hud/footer/index.ts) | 脚注渲染、分类布局与模板解析 |
86
+ | [`extensions/hud/index.ts`](../extensions/hud/index.ts) | Controller、共享状态与 UI 安装的组合入口 |
87
+ | [`extensions/hud/config/`](../extensions/hud/config/config.ts) | 配置模型、归一化、迁移与持久化 |
88
+ | [`extensions/hud/footer/`](../extensions/hud/footer/index.ts) | 脚注渲染、语义分组、响应式布局与模板解析 |
88
89
  | [`extensions/hud/segments/`](../extensions/hud/segments/) | 状态采集器:Git、运行时、MCP、Skill、项目等 |
89
90
  | [`extensions/hud/telemetry/`](../extensions/hud/telemetry/format.ts) | 用量格式化、Token Switch 与 Codex 订阅客户端 |
90
- | [`extensions/hud/session/`](../extensions/hud/session/) | 会话生命周期、上下文与实时上下文覆盖 |
91
- | [`extensions/hud/state/`](../extensions/hud/state/) | 聚合状态、遥测与项目刷新 |
92
- | [`extensions/hud/commands/`](../extensions/hud/commands/settings.ts) | `/zentui` 命令与交互式 TUI 设置 |
91
+ | [`extensions/hud/session/`](../extensions/hud/session/) | Pi 事件注册、会话生命周期与实时 Context 覆盖 |
92
+ | [`extensions/hud/state/`](../extensions/hud/state/) | 聚合状态、Telemetry Reducer 与项目刷新 Controller |
93
+ | [`extensions/hud/commands/`](../extensions/hud/commands/settings.ts) | `/zentui` 设置界面与配置 Controller |
93
94
  | [`extensions/hud/ui/`](../extensions/hud/ui/) | 图标与终端样式工具 |
94
95
  | [`docs/footer.md`](footer.md) | 完整脚注配置参考 |
95
96
  | [`docs/CONTRIBUTING.md`](CONTRIBUTING.md) | 本地开发、测试规范和 PR 检查清单 |
96
- | [`tests/`](../tests/) | Vitest 测试套件(34+ 测试用例,6 个文件) |
97
+ | [`tests/`](../tests/) | Vitest 测试套件(41 个测试用例,8 个文件) |
97
98
 
98
99
  ## 定制
99
100
 
100
101
  ### 布局
101
102
 
102
- 默认三行布局将项目、会话和用量信息分组显示。设置 `footerFormat` 模板字符串可切换为单行布局:
103
+ 默认布局将信息分为 Project、Session、Activity 和 Usage 四组;超长分组会在完整状态项边界处换行,并保持续行对齐。设置 `footerFormat` 模板字符串可切换为单行布局:
103
104
 
104
105
  ```text
105
106
  /zentui format "$cwd( $git_branch)$fill($context)( $tokens)( $cost)"
@@ -109,13 +110,16 @@ HUD 脚注默认启用。运行 `/zentui` 打开交互式设置。
109
110
 
110
111
  ### 状态段
111
112
 
112
- 通过 `/zentui` 启用或禁用单个状态段:
113
+ 运行 `/zentui` 并进入 **Built-in segments**,即可启用或禁用单个状态:
113
114
 
114
- ```text
115
- /zentui statusline enable
116
- /zentui statusline disable
117
- /zentui statusline toggle
118
- ```
115
+ | 分组 | 可独立控制的状态 |
116
+ | --- | --- |
117
+ | Project | Git 状态、Git 操作状态(`MERGING`、`REBASING` 等)、Commit、差异指标、运行时、包版本、OS 和用户 |
118
+ | Session | 模型、Thinking 等级、轮次和会话时长 |
119
+ | Activity | 正在运行的 Tool、已完成 Tool 计数、活跃 Agent、`Agent idle`、Skill 和 MCP |
120
+ | Usage | Context、输入 Token、输出 Token、缓存详情/命中率、费用、限额和时间 |
121
+
122
+ 使用旧版聚合开关 `tokens`、`toolActivity` 或 `agentActivity` 的配置会自动迁移。仍可通过 `/zentui statusline enable|disable|toggle` 控制整个脚注。
119
123
 
120
124
  ### 扩展状态
121
125
 
package/docs/footer.md CHANGED
@@ -2,46 +2,51 @@
2
2
 
3
3
  ## Default layout
4
4
 
5
- When `footerFormat` is empty, the HUD displays a three-line categorized layout:
5
+ When `footerFormat` is empty, the HUD displays four semantic groups:
6
6
 
7
7
  ```text
8
- ⌂ project · pi-sakura ·  main ·  24.18
9
- λ session · gpt-5.3 · high · ↺ 8 · ★ 2/3 · ⊕ 2/2
10
- ◉ usage · 35%/200k · ↑ 4.2k · ↓ 1.1k · $ 0.030
8
+ Project · pi-sakura ·  main ·  24.18
9
+ Session · gpt-5.3 · Thinking level: high · Turn 8
10
+ Activity · Agent idle · Skill 2/3 · MCP 2/2
11
+ Usage · 35%/200k · ↑ 4.2k · ↓ 1.1k · $ 0.030
11
12
  ```
12
13
 
13
- Each line independently computes visible width. Extension statuses are appended to the second line by placement (`left`, `middle`, `right`). When space is tight, lines are truncated at the end with an ellipsis.
14
+ 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.
14
15
 
15
16
  ## Built-in status segments
16
17
 
17
- | Key | Default | Line | Description |
18
+ | Key | Default | Group | Description |
18
19
  | --- | --- | --- | --- |
19
- | `os` | on | 1 | OS icon/text per platform |
20
- | `username` | off | 1 | `user@hostname` |
21
- | `cwd` | on | 1 | Current working directory |
22
- | `gitBranch` | on | 1 | Branch name or `HEAD` when detached |
23
- | `gitStatus` | on | 1 | Conflicts, staged, modified, untracked, stash, ahead/behind |
24
- | `gitCounts` | off | sub | Numeric counts for ahead/behind and stash |
25
- | `gitCommit` | off | 1 | Short commit hash and optional exact tag |
26
- | `gitMetrics` | off | 1 | Added/deleted lines from `git diff HEAD --numstat` |
27
- | `packageVersion` | off | 1 | Project manifest version |
28
- | `runtime` | on | 1 | Detected language/build system and tool version |
29
- | `configCounts` | off | 1 | Instruction files and installed Pi packages count |
30
- | `sessionName` | on | 2 | Current Pi session name |
31
- | `model` | on | 2 | Provider and model ID |
32
- | `thinking` | on | 2 | Thinking level when reasoning-capable |
33
- | `turnCount` | on | 2 | Current turn index |
34
- | `skills` | on | 2 | Active/available skills count, e.g. `★ 1/3` |
35
- | `mcp` | on | 2 | MCP connected/total servers |
36
- | `toolActivity` | on | 2 | Native tool completion count or recent running status |
37
- | `agentActivity` | on | 2 | Active primary agent runs |
38
- | `context` | on | 3 | Context percentage, window size, and/or gauge |
39
- | `tokens` | on | 3 | Input, output, cache token summary |
40
- | `cacheDetails` | on | 3 | Cumulative cache read/write tokens |
41
- | `cost` | on | 3 | Cumulative session cost |
42
- | `codexUsage` | on | 3 | Codex weekly quota remaining |
43
- | `sessionDuration` | off | 3 | Current session duration |
44
- | `time` | off | 3 | Current time `HH:MM` |
20
+ | `cwd` | on | Project | Current working directory |
21
+ | `gitBranch` | on | Project | Branch name or `HEAD` when detached |
22
+ | `gitStatus` | on | Project | Conflicts, staged, modified, untracked, stash, ahead/behind |
23
+ | `gitState` | on | Project | Git operation state such as `MERGING` or `REBASING` |
24
+ | `gitCounts` | off | Project | Numeric counts embedded in ahead/behind and stash status |
25
+ | `gitCommit` | off | Project | Short commit hash and optional exact tag |
26
+ | `gitMetrics` | off | Project | Added/deleted lines from `git diff HEAD --numstat` |
27
+ | `runtime` | on | Project | Detected language/build system and tool version |
28
+ | `packageVersion` | off | Project | Project manifest version |
29
+ | `configCounts` | off | Project | Instruction files and installed Pi packages count |
30
+ | `os` | on | Project | OS icon/text per platform |
31
+ | `username` | off | Project | `user@hostname` |
32
+ | `sessionName` | on | Session | Current Pi session name |
33
+ | `model` | on | Session | Provider and model ID |
34
+ | `thinking` | on | Session | Thinking level when reasoning-capable |
35
+ | `turnCount` | on | Session | Current turn index |
36
+ | `sessionDuration` | off | Session | Current session duration |
37
+ | `runningTools` | on | Activity | Currently running native tools and elapsed time |
38
+ | `toolCounts` | on | Activity | Cumulative completed native-tool counts |
39
+ | `activeAgents` | on | Activity | Active primary agent runs |
40
+ | `agentIdle` | on | Activity | `Agent idle` when no primary agent run is active |
41
+ | `skills` | on | Activity | Active/available skills count, e.g. `Skill 1/3` |
42
+ | `mcp` | on | Activity | MCP connected/total servers |
43
+ | `context` | on | Usage | Context percentage, window size, and/or gauge |
44
+ | `inputTokens` | on | Usage | Cumulative input tokens |
45
+ | `outputTokens` | on | Usage | Cumulative output tokens |
46
+ | `cacheDetails` | on | Usage | Cache read/write tokens and latest hit rate |
47
+ | `cost` | on | Usage | Cumulative session cost |
48
+ | `codexUsage` | on | Usage | Codex weekly quota remaining |
49
+ | `time` | off | Usage | Current time `HH:MM` |
45
50
 
46
51
  ## Template syntax
47
52
 
@@ -100,7 +105,7 @@ Clear it:
100
105
  | `$instruction_files` | `AGENTS.md` + `CLAUDE.md` total |
101
106
  | `$agents_files` | `AGENTS.md` count |
102
107
  | `$claude_files` | `CLAUDE.md` count |
103
- | `$skills` | Active/available skills, e.g. `★ 1/3` |
108
+ | `$skills` | Active/available skills, e.g. `Skill 1/3` |
104
109
  | `$active_skills` | Active skills count only |
105
110
  | `$extensions` | Installed Pi packages count |
106
111
  | `$mcp` | MCP connected/total |
@@ -0,0 +1,74 @@
1
+ import type { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent";
2
+ import {
3
+ type PolishedTuiConfig,
4
+ saveColorSourcesPatch,
5
+ saveContextStylePatch,
6
+ saveExtensionStatusColorMode,
7
+ saveExtensionStatusPlacement,
8
+ saveFooterFormatPatch,
9
+ saveFooterSegmentsPatch,
10
+ saveGitBranchPatch,
11
+ saveIconsModePatch,
12
+ savePathDisplayPatch,
13
+ saveSeparatorPatch,
14
+ saveUiFeaturesPatch,
15
+ } from "../config/config.js";
16
+ import { registerZentuiSettingsCommand } from "./settings.js";
17
+
18
+ interface SettingsControllerDeps {
19
+ getConfig: () => PolishedTuiConfig;
20
+ setConfig: (config: PolishedTuiConfig) => void;
21
+ applyConfiguredUi: (ctx: ExtensionContext) => void;
22
+ restartSessionTimer: () => void;
23
+ getActiveExtensionStatuses: () => ReadonlyMap<string, string>;
24
+ requestRender: () => void;
25
+ }
26
+
27
+ /** Connect the settings UI to persistence without exposing patch mechanics to the extension root. */
28
+ export function registerSettingsController(pi: ExtensionAPI, deps: SettingsControllerDeps): void {
29
+ const updateConfig = (config: PolishedTuiConfig) => {
30
+ deps.setConfig(config);
31
+ };
32
+
33
+ registerZentuiSettingsCommand(pi, {
34
+ getConfig: deps.getConfig,
35
+ setColorSources(patch) {
36
+ updateConfig(saveColorSourcesPatch(patch));
37
+ },
38
+ setUiFeatures(patch, ctx) {
39
+ updateConfig(saveUiFeaturesPatch(patch));
40
+ deps.applyConfiguredUi(ctx);
41
+ },
42
+ setFooterSegments(patch) {
43
+ updateConfig(saveFooterSegmentsPatch(patch));
44
+ deps.restartSessionTimer();
45
+ },
46
+ setFooterFormat(value) {
47
+ updateConfig(saveFooterFormatPatch(value));
48
+ deps.restartSessionTimer();
49
+ },
50
+ setIconMode(mode) {
51
+ updateConfig(saveIconsModePatch(mode));
52
+ },
53
+ setContextStyle(style) {
54
+ updateConfig(saveContextStylePatch(style));
55
+ },
56
+ setSeparator(separator) {
57
+ updateConfig(saveSeparatorPatch(separator));
58
+ },
59
+ setPathDisplay(patch) {
60
+ updateConfig(savePathDisplayPatch(patch));
61
+ },
62
+ setGitBranch(patch) {
63
+ updateConfig(saveGitBranchPatch(patch));
64
+ },
65
+ getActiveExtensionStatuses: deps.getActiveExtensionStatuses,
66
+ setExtensionStatusPlacement(key, placement) {
67
+ updateConfig(saveExtensionStatusPlacement(key, placement));
68
+ },
69
+ setExtensionStatusColorMode(key, colorMode) {
70
+ updateConfig(saveExtensionStatusColorMode(key, colorMode));
71
+ },
72
+ requestRender: deps.requestRender,
73
+ });
74
+ }
@@ -113,44 +113,50 @@ const footerSegmentSettingLabels: Record<FooterSegmentSettingId, string> = {
113
113
  cwd: "Current directory",
114
114
  gitBranch: "Git branch",
115
115
  gitStatus: "Git status",
116
+ gitState: "Git operation state",
116
117
  gitCounts: "Git counts",
117
- sessionDuration: "Session duration",
118
- username: "Username@host",
119
- time: "Current time",
120
- os: "OS icon",
121
- runtime: "Runtime",
122
- context: "Context usage",
123
- tokens: "Token counts",
124
- cost: "Session cost",
125
- packageVersion: "Package version",
126
118
  gitCommit: "Git commit",
127
119
  gitMetrics: "Git line metrics",
120
+ runtime: "Runtime",
121
+ packageVersion: "Package version",
122
+ configCounts: "Config counts",
123
+ os: "OS icon",
124
+ username: "Username@host",
128
125
  sessionName: "Session name",
129
126
  model: "Model",
130
127
  thinking: "Thinking level",
131
128
  turnCount: "Turn count",
132
- cacheDetails: "Cache details",
133
- codexUsage: "Codex subscription",
134
- configCounts: "Config counts",
129
+ sessionDuration: "Session duration",
130
+ runningTools: "Running tools",
131
+ toolCounts: "Completed tool counts",
132
+ activeAgents: "Active agents",
133
+ agentIdle: "Agent idle status",
135
134
  skills: "Skill activity",
136
135
  mcp: "MCP connections",
137
- toolActivity: "Tool activity",
138
- agentActivity: "Agent run activity",
136
+ context: "Context usage",
137
+ inputTokens: "Input tokens",
138
+ outputTokens: "Output tokens",
139
+ cacheDetails: "Cache details",
140
+ cost: "Session cost",
141
+ codexUsage: "Codex subscription",
142
+ time: "Current time",
139
143
  };
140
144
 
141
145
  const footerSegmentSettingDescriptions: Record<FooterSegmentSettingId, string> = {
142
146
  cwd: "Show or hide the current working directory on the project row.",
143
147
  gitBranch: "Show or hide the git branch name on the project row.",
144
148
  gitStatus: "Show or hide git status icons and ahead/behind markers on the project row.",
149
+ gitState: "Show or hide Git operation states such as MERGING and REBASING.",
145
150
  gitCounts:
146
151
  "Show numeric ahead/behind and stash counts (requires the Git status segment to be enabled).",
147
- sessionDuration: "Show session running time on the usage row.",
152
+ sessionDuration: "Show session running time on the session row.",
148
153
  username: "Show user@hostname on the project row.",
149
154
  time: "Show the current time (HH:MM) on the usage row.",
150
155
  os: "Show an operating-system icon on the project row.",
151
156
  runtime: "Show or hide the detected runtime/language on the project row.",
152
157
  context: "Show or hide context usage on the usage row.",
153
- tokens: "Show or hide input/output token counts on the usage row.",
158
+ inputTokens: "Show or hide cumulative input tokens on the usage row.",
159
+ outputTokens: "Show or hide cumulative output tokens on the usage row.",
154
160
  cost: "Show or hide session cost on the usage row.",
155
161
  packageVersion:
156
162
  "Show the project’s own manifest version (package.json, Cargo.toml, pyproject.toml, …) on the project row. Distinct from the installed toolchain version.",
@@ -165,10 +171,12 @@ const footerSegmentSettingDescriptions: Record<FooterSegmentSettingId, string> =
165
171
  cacheDetails: "Show cumulative cache read/write token totals on the usage row.",
166
172
  codexUsage: "Show OpenAI Codex subscription rate limits on the usage row when available.",
167
173
  configCounts: "Show instruction-file and installed Pi package counts on the project row.",
168
- skills: "Show active/available Pi skill counts on the session row.",
169
- mcp: "Show parsed MCP connected/total server counts on the session row.",
170
- toolActivity: "Show completed or running native tools on the session row.",
171
- agentActivity: "Show active main agent runs on the session row (not subagent count).",
174
+ skills: "Show active/available Pi skill counts on the activity row.",
175
+ mcp: "Show parsed MCP connected/total server counts on the activity row.",
176
+ runningTools: "Show currently running native tools and their elapsed time.",
177
+ toolCounts: "Show cumulative completed native-tool counts.",
178
+ activeAgents: "Show active main agent runs on the activity row (not subagent count).",
179
+ agentIdle: "Show Agent idle when no main agent run is active.",
172
180
  };
173
181
 
174
182
  const directCommandSuggestions = [
@@ -209,11 +217,13 @@ function isFooterSegmentSettingId(value: string): value is FooterSegmentSettingI
209
217
  value === "cwd" ||
210
218
  value === "gitBranch" ||
211
219
  value === "gitStatus" ||
220
+ value === "gitState" ||
212
221
  value === "gitCounts" ||
213
222
  value === "sessionDuration" ||
214
223
  value === "runtime" ||
215
224
  value === "context" ||
216
- value === "tokens" ||
225
+ value === "inputTokens" ||
226
+ value === "outputTokens" ||
217
227
  value === "cost" ||
218
228
  value === "username" ||
219
229
  value === "time" ||
@@ -230,8 +240,10 @@ function isFooterSegmentSettingId(value: string): value is FooterSegmentSettingI
230
240
  value === "configCounts" ||
231
241
  value === "skills" ||
232
242
  value === "mcp" ||
233
- value === "toolActivity" ||
234
- value === "agentActivity"
243
+ value === "runningTools" ||
244
+ value === "toolCounts" ||
245
+ value === "activeAgents" ||
246
+ value === "agentIdle"
235
247
  );
236
248
  }
237
249
 
@@ -155,6 +155,17 @@ function footerSegmentValue(
155
155
  return typeof value === "boolean" ? value : defaultConfig.footerSegments[key];
156
156
  }
157
157
 
158
+ function footerSegmentValueWithLegacy(
159
+ record: Record<string, unknown>,
160
+ key: keyof FooterSegmentsConfig,
161
+ legacyKey: "tokens" | "toolActivity" | "agentActivity",
162
+ ): boolean {
163
+ const value = record[key];
164
+ if (typeof value === "boolean") return value;
165
+ const legacyValue = record[legacyKey];
166
+ return typeof legacyValue === "boolean" ? legacyValue : defaultConfig.footerSegments[key];
167
+ }
168
+
158
169
  function definedColors(
159
170
  colors: Partial<Record<keyof PolishedTuiConfig["colors"], string | undefined>>,
160
171
  ): Partial<PolishedTuiConfig["colors"]> {
@@ -212,10 +223,13 @@ function normalizeFooterSegments(record: Record<string, unknown>): FooterSegment
212
223
  cwd: footerSegmentValue(record, "cwd"),
213
224
  gitBranch: footerSegmentValue(record, "gitBranch"),
214
225
  gitStatus: footerSegmentValue(record, "gitStatus"),
226
+ gitState: footerSegmentValue(record, "gitState"),
215
227
  gitCounts: footerSegmentValue(record, "gitCounts"),
216
228
  runtime: footerSegmentValue(record, "runtime"),
217
229
  context: footerSegmentValue(record, "context"),
218
- tokens: footerSegmentValue(record, "tokens"),
230
+ inputTokens: footerSegmentValueWithLegacy(record, "inputTokens", "tokens"),
231
+ outputTokens: footerSegmentValueWithLegacy(record, "outputTokens", "tokens"),
232
+ cacheDetails: footerSegmentValue(record, "cacheDetails"),
219
233
  cost: footerSegmentValue(record, "cost"),
220
234
  sessionDuration: footerSegmentValue(record, "sessionDuration"),
221
235
  username: footerSegmentValue(record, "username"),
@@ -228,13 +242,14 @@ function normalizeFooterSegments(record: Record<string, unknown>): FooterSegment
228
242
  model: footerSegmentValue(record, "model"),
229
243
  thinking: footerSegmentValue(record, "thinking"),
230
244
  turnCount: footerSegmentValue(record, "turnCount"),
231
- cacheDetails: footerSegmentValue(record, "cacheDetails"),
232
245
  codexUsage: footerSegmentValue(record, "codexUsage"),
233
246
  configCounts: footerSegmentValue(record, "configCounts"),
234
247
  skills: footerSegmentValue(record, "skills"),
235
248
  mcp: footerSegmentValue(record, "mcp"),
236
- toolActivity: footerSegmentValue(record, "toolActivity"),
237
- agentActivity: footerSegmentValue(record, "agentActivity"),
249
+ runningTools: footerSegmentValueWithLegacy(record, "runningTools", "toolActivity"),
250
+ toolCounts: footerSegmentValueWithLegacy(record, "toolCounts", "toolActivity"),
251
+ activeAgents: footerSegmentValueWithLegacy(record, "activeAgents", "agentActivity"),
252
+ agentIdle: footerSegmentValueWithLegacy(record, "agentIdle", "agentActivity"),
238
253
  };
239
254
  }
240
255
 
@@ -46,10 +46,12 @@ function isFooterSegmentKey(value: string): value is keyof FooterSegmentsConfig
46
46
  value === "cwd" ||
47
47
  value === "gitBranch" ||
48
48
  value === "gitStatus" ||
49
+ value === "gitState" ||
49
50
  value === "gitCounts" ||
50
51
  value === "runtime" ||
51
52
  value === "context" ||
52
- value === "tokens" ||
53
+ value === "inputTokens" ||
54
+ value === "outputTokens" ||
53
55
  value === "cost" ||
54
56
  value === "sessionDuration" ||
55
57
  value === "username" ||
@@ -67,8 +69,10 @@ function isFooterSegmentKey(value: string): value is keyof FooterSegmentsConfig
67
69
  value === "configCounts" ||
68
70
  value === "skills" ||
69
71
  value === "mcp" ||
70
- value === "toolActivity" ||
71
- value === "agentActivity"
72
+ value === "runningTools" ||
73
+ value === "toolCounts" ||
74
+ value === "activeAgents" ||
75
+ value === "agentIdle"
72
76
  );
73
77
  }
74
78