pi-one-ui 0.7.2 → 0.8.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/CHANGELOG.md +28 -1
- package/README.en.md +5 -8
- package/README.md +6 -7
- package/extensions/app/config/footer.ts +21 -5
- package/extensions/app/config/renderer.ts +1 -1
- package/extensions/app/config/shell.ts +62 -60
- package/extensions/app/runtime/prototype-patch-registry.ts +13 -9
- package/extensions/app/runtime/tui-runtime.ts +19 -12
- package/extensions/app/settings/controller.ts +2 -2
- package/extensions/layouts/context/index.ts +2 -2
- package/extensions/layouts/context/message/user-message-osc.ts +1 -1
- package/extensions/layouts/context/message/user-message-styles.ts +9 -6
- package/extensions/layouts/context/message/user-message.ts +5 -5
- package/extensions/layouts/context/renderer/compact-mode.ts +2 -2
- package/extensions/layouts/context/renderer/default-mode.ts +10 -10
- package/extensions/layouts/context/renderer/index.ts +0 -1
- package/extensions/layouts/context/renderer/mouse/interaction.ts +5 -5
- package/extensions/layouts/context/renderer/mouse/scroll.ts +4 -4
- package/extensions/layouts/context/renderer/tool/diff/diff-edit-render.ts +1 -1
- package/extensions/layouts/context/renderer/tool/diff/index.ts +1 -1
- package/extensions/layouts/context/renderer/tool/grouping.ts +3 -3
- package/extensions/layouts/context/renderer/tool/message-display.ts +7 -7
- package/extensions/layouts/context/renderer/tool/result.ts +16 -16
- package/extensions/layouts/context/renderer/tool/toggle-render-cache.ts +9 -9
- package/extensions/layouts/editor/controller.ts +17 -17
- package/extensions/layouts/editor/editor-metadata-format.ts +5 -5
- package/extensions/layouts/editor/factory.ts +5 -5
- package/extensions/layouts/editor/minimalist-editor.ts +8 -8
- package/extensions/layouts/editor/ownership.ts +24 -20
- package/extensions/layouts/editor/ui.ts +10 -15
- package/extensions/layouts/footer/controller.ts +4 -4
- package/extensions/layouts/footer/data.ts +2 -2
- package/extensions/layouts/footer/extension-status.ts +4 -4
- package/extensions/layouts/footer/footer.ts +5 -2
- package/extensions/layouts/overlay/selector-border.ts +4 -4
- package/extensions/layouts/overlay/selector-controller.ts +1 -1
- package/extensions/layouts/overlay/settings-previews.ts +2 -2
- package/extensions/layouts/working-line/interaction-summary.ts +3 -1
- package/extensions/layouts/working-line/working-line.ts +4 -4
- package/extensions/services/package-data.ts +1 -1
- package/extensions/shared/style.ts +66 -56
- package/extensions/tools/patch-keys.ts +23 -23
- package/package.json +7 -7
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,26 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [0.8.0] - 2026-09-30
|
|
10
|
+
|
|
11
|
+
### Changed
|
|
12
|
+
|
|
13
|
+
- Require Pi `>= 0.99.0`: the Editor reads a theme's `cwd`, `editorModel`, and `editorBorder` keys from the palette shape Pi exposes since 0.99, and development, tests, and type checking target that version.
|
|
14
|
+
- Simplify color configuration: `colors.*` now accepts Pi official theme tokens defined in a theme file's `colors` field and explicit terminal colors; bare terminal color names are rejected, so write `fg:purple`, `fg:red`, a hex value, or a 256-color index for fixed terminal colors. Pi-one-ui custom keys such as `cwd`, `editorModel`, and `editorBorder` are documented as extensions that the shipped themes define. The reference is updated in both Chinese and English README.
|
|
15
|
+
- Rename the remaining persisted `zentui` values: `components.selectorBorders.style` is now `one-ui`, extension status `colorModes` are `themed` / `original`, and the working-line turn summary entry type is `one-ui-turn-summary`.
|
|
16
|
+
|
|
17
|
+
### Fixed
|
|
18
|
+
|
|
19
|
+
- Read Editor theme tokens from the palette field exposed by the running Pi version. Pi 0.99 renamed the theme palette map from `fgColors` to `fgAnsi` and added a resolved `colors` record, so the Editor model label, cwd label, and static border now pick up a theme's `editorModel` / `cwd` / `editorBorder` colors instead of falling back to `syntaxKeyword` / `syntaxFunction` / `borderMuted`.
|
|
20
|
+
|
|
21
|
+
### Migration
|
|
22
|
+
|
|
23
|
+
- Install Pi `>= 0.99.0` before updating this package. Earlier Pi releases keep working only through the previous package version.
|
|
24
|
+
- Replace bare terminal color names in `colors.*` with an explicit form: `purple` becomes `fg:purple`, `red` becomes `fg:red`, and fixed colors can also use hex or a 256-color index. Values that no longer validate are dropped at load and fall back to the built-in default, and the file itself is not rewritten.
|
|
25
|
+
- No manual edit is required for the renamed `zentui` values. The next configuration save rewrites `selectorBorders.style` and extension status color modes to the new names, and turn summaries written by older versions continue to render from history.
|
|
26
|
+
- After updating the package, fully exit and restart Pi instead of running `/reload`: the cross-reload patch coordination keys were renamed, so an in-place reload would leave the previous instance's marks unrecognized until the process restarts.
|
|
27
|
+
- For an unpinned npm installation, run `pi update npm:pi-one-ui`; for an existing version pin, run `pi install npm:pi-one-ui@0.8.0`.
|
|
28
|
+
|
|
9
29
|
## [0.7.2] - 2026-09-28
|
|
10
30
|
|
|
11
31
|
### Changed
|
|
@@ -21,6 +41,12 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
|
21
41
|
- No configuration migration is required. Existing canonical v1 files and command names remain supported.
|
|
22
42
|
- For an unpinned npm installation, run `pi update npm:pi-one-ui`; for an existing version pin, run `pi install npm:pi-one-ui@0.7.2`. Fully exit and restart Pi after updating the package.
|
|
23
43
|
|
|
44
|
+
### Release verification
|
|
45
|
+
|
|
46
|
+
- Release source: [`67ebac4`](https://github.com/kerolt/pi-one-ui/commit/67ebac41e1aeaaab51e11257de17134fb40ab63e). [CI](https://github.com/kerolt/pi-one-ui/actions/runs/36365224155) and [Publish](https://github.com/kerolt/pi-one-ui/actions/runs/36365227223) completed successfully; local and CI `npm run verify` passed 1,185 tests across 70 files, and `npm run pack:check` confirmed 124 package files.
|
|
47
|
+
- Real Pi regular/fullscreen TUI probes passed, covering settings, Context Inspector, Editor input and focus, presets, reload, session tree, compaction, session replacement, input listeners, and third-party Editor ownership. User-specific terminal, theme, and extension combinations still require manual verification.
|
|
48
|
+
- At publication, npm `latest` resolved to `0.7.2` with the matching release `gitHead` and package SHA-1 `730dc4a0e4713e26cef4ea3b0c83c122f8b83bc6`; the downloaded package file list and contents matched the release commit. The [provenance statement](https://registry.npmjs.org/-/npm/v1/attestations/pi-one-ui@0.7.2) was published at [Sigstore log index 2981051472](https://search.sigstore.dev/?logIndex=2981051472).
|
|
49
|
+
|
|
24
50
|
## [0.7.1] - 2026-09-21
|
|
25
51
|
|
|
26
52
|
### Changed
|
|
@@ -174,7 +200,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
|
174
200
|
|
|
175
201
|
- Reduced rendering lag when expanding settled tool groups by reusing cached child output.
|
|
176
202
|
|
|
177
|
-
[Unreleased]: https://github.com/kerolt/pi-one-ui/compare/v0.
|
|
203
|
+
[Unreleased]: https://github.com/kerolt/pi-one-ui/compare/v0.8.0...HEAD
|
|
204
|
+
[0.8.0]: https://github.com/kerolt/pi-one-ui/compare/v0.7.2...v0.8.0
|
|
178
205
|
[0.7.2]: https://github.com/kerolt/pi-one-ui/compare/v0.7.1...v0.7.2
|
|
179
206
|
[0.7.1]: https://github.com/kerolt/pi-one-ui/compare/v0.7.0...v0.7.1
|
|
180
207
|
[0.7.0]: https://github.com/kerolt/pi-one-ui/compare/v0.6.1...v0.7.0
|
package/README.en.md
CHANGED
|
@@ -50,7 +50,7 @@ Header → Context → WorkingLine → Editor → Footer
|
|
|
50
50
|
### Requirements
|
|
51
51
|
|
|
52
52
|
- Node.js `>=22.19.0`
|
|
53
|
-
- Pi and related runtime packages `>=0.
|
|
53
|
+
- Pi and related runtime packages `>=0.99.0`
|
|
54
54
|
|
|
55
55
|
### Install from npm
|
|
56
56
|
|
|
@@ -76,11 +76,9 @@ Then open the unified settings panel:
|
|
|
76
76
|
/oneui
|
|
77
77
|
```
|
|
78
78
|
|
|
79
|
-
### Upgrading to 0.
|
|
79
|
+
### Upgrading to 0.8.0
|
|
80
80
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
Existing canonical v1 configurations and commands remain compatible; no migration is required.
|
|
81
|
+
Pi `>= 0.99.0` is now required. The Editor model label, cwd label, and static border read a theme's `editorModel` / `cwd` / `editorBorder` keys through the palette shape the current Pi exposes; `colors.*` accepts Pi official theme tokens and explicit terminal colors only, so bare terminal color names such as `purple` must be written as `fg:purple`; and the legacy `zentui` values in `selectorBorders.style`, extension status `colorModes`, and the turn summary entry type use new names, with legacy values still read for compatibility.
|
|
84
82
|
|
|
85
83
|
For an unpinned npm installation, run:
|
|
86
84
|
|
|
@@ -88,7 +86,7 @@ For an unpinned npm installation, run:
|
|
|
88
86
|
pi update npm:pi-one-ui
|
|
89
87
|
```
|
|
90
88
|
|
|
91
|
-
If your installation pins a version, run `pi install npm:pi-one-ui@0.
|
|
89
|
+
If your installation pins a version, run `pi install npm:pi-one-ui@0.8.0` to update the pin. Fully exit and restart Pi after updating the package instead of running `/reload`: the cross-reload patch coordination keys were renamed, so an in-place reload would leave the previous instance's marks unrecognized.
|
|
92
90
|
|
|
93
91
|
## Configuration
|
|
94
92
|
|
|
@@ -157,8 +155,7 @@ To keep the configuration section clean and focused, in-depth options, template
|
|
|
157
155
|
- `margin`: distance from the terminal edges — either a single number for all sides, or an object with per-edge `top`/`right`/`bottom`/`left` values.
|
|
158
156
|
- Saved changes apply the next time `/oneui` opens; no `/reload` needed.
|
|
159
157
|
- **Color system & theme customization**: see [Editor Colors Reference (docs/editor-colors.md)](./docs/editor-colors.md)
|
|
160
|
-
-
|
|
161
|
-
- Full support for adaptive thinking-effort border colors (from Low to Max) and labels. The completion menu selection shares the editor frame color and follows the same chain.
|
|
158
|
+
- `colors.*` accepts official Pi theme tokens (from the theme file `colors` field), modifiers, and explicit terminal colors. Terminal color names must use prefixes such as `fg:purple` or `fg:red`; fixed colors can also use hex codes, 256-color indexes, or `fg:`/`bg:` prefixes. The token list and syntax are in [docs/editor-colors.md](<./docs/editor-colors.md#3-configuration-value-syntax>).
|
|
162
159
|
- **Migration from legacy versions**: Field cleanups from 0.5.x/0.6.0 (such as merging `opencode` into `minimalist`, or removing `colorSource`) are covered in [docs/configuration.md: Changes and Migration](./docs/configuration.md#6-变更与迁移).
|
|
163
160
|
|
|
164
161
|
## Upstream origins and project evolution
|
package/README.md
CHANGED
|
@@ -50,7 +50,7 @@ Header → Context → WorkingLine → Editor → Footer
|
|
|
50
50
|
### 环境要求
|
|
51
51
|
|
|
52
52
|
- Node.js `>=22.19.0`
|
|
53
|
-
- Pi 及其相关运行时包 `>=0.
|
|
53
|
+
- Pi 及其相关运行时包 `>=0.99.0`
|
|
54
54
|
|
|
55
55
|
### 从 npm 安装
|
|
56
56
|
|
|
@@ -76,11 +76,9 @@ pi install git:github.com/kerolt/pi-one-ui
|
|
|
76
76
|
/oneui
|
|
77
77
|
```
|
|
78
78
|
|
|
79
|
-
### 升级到 0.
|
|
79
|
+
### 升级到 0.8.0
|
|
80
80
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
现有 canonical v1 配置和命令保持兼容,无需迁移。
|
|
81
|
+
本次要求 Pi `>= 0.99.0`。Editor 的模型名、目录标签与 static 外框改为从当前 Pi 的调色板结构读取主题里的 `editorModel` / `cwd` / `editorBorder` 键;`colors.*` 收敛为 Pi 官方主题 token 与显式终端色两种写法,裸终端色名(如 `purple`)不再接受,需写成 `fg:purple`;`selectorBorders.style`、扩展状态 `colorModes` 与轮次摘要条目类型中的旧 `zentui` 值改为新名称,读取端仍兼容旧值。
|
|
84
82
|
|
|
85
83
|
未固定版本的 npm 安装可执行:
|
|
86
84
|
|
|
@@ -88,7 +86,7 @@ pi install git:github.com/kerolt/pi-one-ui
|
|
|
88
86
|
pi update npm:pi-one-ui
|
|
89
87
|
```
|
|
90
88
|
|
|
91
|
-
若安装时固定了版本,执行 `pi install npm:pi-one-ui@0.
|
|
89
|
+
若安装时固定了版本,执行 `pi install npm:pi-one-ui@0.8.0` 更新版本指定。更新安装包后,完整退出并重启 Pi,不要使用 `/reload`:跨 reload 的补丁协调键已改名,直接重载会让旧实例留下的标记无法被识别。
|
|
92
90
|
|
|
93
91
|
## 配置
|
|
94
92
|
|
|
@@ -157,7 +155,8 @@ pi update npm:pi-one-ui
|
|
|
157
155
|
- `margin`:距终端边缘的外边距,可以是四边统一数字,也可以是按 `top`/`right`/`bottom`/`left` 分别配置的对象。
|
|
158
156
|
- 修改保存后下次打开 `/oneui` 即生效,无需 `/reload`。
|
|
159
157
|
- **颜色体系与主题定制**:详见 [Editor 颜色配置说明 (docs/editor-colors.md)](./docs/editor-colors.md)
|
|
160
|
-
-
|
|
158
|
+
- `colors.*` 只接受 Pi 官方主题 token(主题文件 `colors` 字段里的官方颜色键)、修饰符和显式终端色;终端色名必须写成 `fg:purple`、`fg:red` 等形式,固定色彩也可以使用 Hex、256 色索引或 `fg:`/`bg:` 前缀。
|
|
159
|
+
- Editor 的 `cwd`、`editorModel`、`editorBorder` 是 pi-one-ui 自定义的扩展颜色键(主题文件 `colors` 可以写这些键),缺少时回落到 Pi 官方 theme token;`cc-dark` 和 `cc-light` 已支持这些键。
|
|
161
160
|
- 支持完整的 Thinking 思考档位(Low 至 Max)自适应边框与标签分级配色,补全下拉选中项与编辑器外框同色,跟随同一条颜色链。
|
|
162
161
|
- **历史版本迁移**:旧版升级带来的字段收敛(如 `opencode` 样式统一合并入 `minimalist`、`colorSource` 双模式移除等)参见 [docs/configuration.md 变更与迁移节](./docs/configuration.md#6-变更与迁移)。
|
|
163
162
|
|
|
@@ -20,7 +20,7 @@ export type GitMetricsConfig = {
|
|
|
20
20
|
ignoreSubmodules: boolean;
|
|
21
21
|
};
|
|
22
22
|
export type ExtensionStatusPlacement = "off" | "left" | "middle" | "right";
|
|
23
|
-
export type ExtensionStatusColorMode = "
|
|
23
|
+
export type ExtensionStatusColorMode = "themed" | "original";
|
|
24
24
|
export type ExtensionStatusesConfig = {
|
|
25
25
|
defaultPlacement: ExtensionStatusPlacement;
|
|
26
26
|
placements: Record<string, ExtensionStatusPlacement>;
|
|
@@ -185,7 +185,21 @@ export function isExtensionStatusPlacement(
|
|
|
185
185
|
export function isExtensionStatusColorMode(
|
|
186
186
|
value: unknown,
|
|
187
187
|
): value is ExtensionStatusColorMode {
|
|
188
|
-
return value === "
|
|
188
|
+
return value === "themed" || value === "original";
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Parses an extension status color mode. The historical `zentui` value is read
|
|
193
|
+
* as its `themed` replacement so existing configuration files keep working.
|
|
194
|
+
*
|
|
195
|
+
* @param value Raw configuration value.
|
|
196
|
+
* @returns The canonical color mode, or undefined when unsupported.
|
|
197
|
+
*/
|
|
198
|
+
export function parseExtensionStatusColorMode(
|
|
199
|
+
value: unknown,
|
|
200
|
+
): ExtensionStatusColorMode | undefined {
|
|
201
|
+
if (value === "zentui") return "themed";
|
|
202
|
+
return isExtensionStatusColorMode(value) ? value : undefined;
|
|
189
203
|
}
|
|
190
204
|
|
|
191
205
|
function thresholds(value: unknown): ContextThresholds {
|
|
@@ -279,9 +293,11 @@ export function normalizeFooter(value: unknown): FooterComponentConfig {
|
|
|
279
293
|
),
|
|
280
294
|
),
|
|
281
295
|
colorModes: Object.fromEntries(
|
|
282
|
-
Object.entries(recordValue(statuses.colorModes)).
|
|
283
|
-
(entry):
|
|
284
|
-
|
|
296
|
+
Object.entries(recordValue(statuses.colorModes)).flatMap(
|
|
297
|
+
(entry): Array<[string, ExtensionStatusColorMode]> => {
|
|
298
|
+
const mode = parseExtensionStatusColorMode(entry[1]);
|
|
299
|
+
return mode ? [[entry[0], mode]] : [];
|
|
300
|
+
},
|
|
285
301
|
),
|
|
286
302
|
),
|
|
287
303
|
},
|
|
@@ -35,7 +35,7 @@ export const DEFAULT_TOOL_DISPLAY_CONFIG: ToolDisplayConfig = {
|
|
|
35
35
|
/**
|
|
36
36
|
* Expanded tool/diff body cap. 40 ≈ one screen of content after title,
|
|
37
37
|
* Input section, editor, and status — keeps the TUI compact.
|
|
38
|
-
* Raise via /
|
|
38
|
+
* Raise via /oneui → Diff → Expanded max lines when reviewing large dumps.
|
|
39
39
|
*/
|
|
40
40
|
expandedPreviewMaxLines: 40,
|
|
41
41
|
};
|
|
@@ -44,6 +44,7 @@ import {
|
|
|
44
44
|
type PathDisplayConfig,
|
|
45
45
|
parseCompactFooterMaxLines,
|
|
46
46
|
parseContextStyle,
|
|
47
|
+
parseExtensionStatusColorMode,
|
|
47
48
|
parseSeparatorStyle,
|
|
48
49
|
type SeparatorStyle,
|
|
49
50
|
type StarshipFooterStyleConfig,
|
|
@@ -68,7 +69,8 @@ export * from "./editor.ts";
|
|
|
68
69
|
export * from "./footer.ts";
|
|
69
70
|
export * from "./working-line.ts";
|
|
70
71
|
export type ColorSpec = string;
|
|
71
|
-
|
|
72
|
+
/** 选择框边框样式:`one-ui` 是唯一实现,旧配置里的 `zentui` 按同一样式读取。 */
|
|
73
|
+
export type SelectorBorderStyle = "one-ui" | "zentui";
|
|
72
74
|
export type SelectorBordersComponentConfig = {
|
|
73
75
|
enabled: boolean;
|
|
74
76
|
style: SelectorBorderStyle;
|
|
@@ -127,44 +129,43 @@ export type PolishedTuiColors = {
|
|
|
127
129
|
workingLineMid?: ColorSpec;
|
|
128
130
|
workingLineHigh?: ColorSpec;
|
|
129
131
|
};
|
|
130
|
-
export type
|
|
132
|
+
export type PolishedTuiConfig = {
|
|
131
133
|
projectRefreshIntervalMs: number;
|
|
132
134
|
icons: ResolvedIcons;
|
|
133
135
|
colors: PolishedTuiColors;
|
|
134
136
|
components: ComponentsConfig;
|
|
135
137
|
};
|
|
136
|
-
export type PolishedTuiConfig = ZentuiConfig;
|
|
137
138
|
export const configPath = defaultConfigPath;
|
|
138
139
|
|
|
139
|
-
export const defaultConfig:
|
|
140
|
+
export const defaultConfig: PolishedTuiConfig = {
|
|
140
141
|
projectRefreshIntervalMs: 30_000,
|
|
141
142
|
icons: { mode: "auto", ...NERD_DEFAULT_ICONS },
|
|
142
143
|
colors: {
|
|
143
|
-
sessionName: "bold
|
|
144
|
-
gitBranch: "bold
|
|
145
|
-
gitStatus: "bold
|
|
146
|
-
contextNormal: "
|
|
147
|
-
contextWarning: "bold
|
|
148
|
-
contextError: "bold
|
|
149
|
-
tokens: "
|
|
150
|
-
cost: "bold
|
|
151
|
-
separator: "
|
|
144
|
+
sessionName: "bold success",
|
|
145
|
+
gitBranch: "bold syntaxKeyword",
|
|
146
|
+
gitStatus: "bold error",
|
|
147
|
+
contextNormal: "muted",
|
|
148
|
+
contextWarning: "bold warning",
|
|
149
|
+
contextError: "bold error",
|
|
150
|
+
tokens: "muted",
|
|
151
|
+
cost: "bold success",
|
|
152
|
+
separator: "muted",
|
|
152
153
|
runtimePrefix: "",
|
|
153
|
-
extensionStatus: "
|
|
154
|
-
sessionDuration: "
|
|
154
|
+
extensionStatus: "muted",
|
|
155
|
+
sessionDuration: "warning",
|
|
155
156
|
packageVersion: "208",
|
|
156
|
-
gitCommit: "bold
|
|
157
|
-
gitMetricsAdded: "bold
|
|
158
|
-
gitMetricsDeleted: "bold
|
|
159
|
-
username: "bold
|
|
160
|
-
time: "bold
|
|
161
|
-
os: "bold
|
|
157
|
+
gitCommit: "bold success",
|
|
158
|
+
gitMetricsAdded: "bold success",
|
|
159
|
+
gitMetricsDeleted: "bold error",
|
|
160
|
+
username: "bold warning",
|
|
161
|
+
time: "bold warning",
|
|
162
|
+
os: "bold text",
|
|
162
163
|
},
|
|
163
164
|
components: {
|
|
164
165
|
editor: defaultEditor,
|
|
165
166
|
userMessages: normalizeUserMessages(undefined),
|
|
166
167
|
workingLine: defaultWorkingLine,
|
|
167
|
-
selectorBorders: { enabled: true, style: "
|
|
168
|
+
selectorBorders: { enabled: true, style: "one-ui" },
|
|
168
169
|
footer: defaultFooter,
|
|
169
170
|
},
|
|
170
171
|
};
|
|
@@ -217,7 +218,7 @@ const knownComponentStyleIds: Record<
|
|
|
217
218
|
"compact",
|
|
218
219
|
"labeled",
|
|
219
220
|
]),
|
|
220
|
-
selectorBorders: new Set(["zentui"]),
|
|
221
|
+
selectorBorders: new Set(["one-ui", "zentui"]),
|
|
221
222
|
footer: new Set(["native", "starship", "hidden"]),
|
|
222
223
|
};
|
|
223
224
|
const retiredEditorStyleIds = new Set([
|
|
@@ -226,7 +227,7 @@ const retiredEditorStyleIds = new Set([
|
|
|
226
227
|
"accent-rail",
|
|
227
228
|
]);
|
|
228
229
|
const unsupportedComponentStyles = new WeakMap<
|
|
229
|
-
|
|
230
|
+
PolishedTuiConfig,
|
|
230
231
|
ReadonlySet<ComponentStyleOwner>
|
|
231
232
|
>();
|
|
232
233
|
const styleOwners = Object.keys(
|
|
@@ -247,7 +248,7 @@ function unsupportedSelectedStyleId(
|
|
|
247
248
|
}
|
|
248
249
|
|
|
249
250
|
export function hasUnsupportedComponentStyle(
|
|
250
|
-
config:
|
|
251
|
+
config: PolishedTuiConfig,
|
|
251
252
|
owner: ComponentStyleOwner,
|
|
252
253
|
): boolean {
|
|
253
254
|
return unsupportedComponentStyles.get(config)?.has(owner) ?? false;
|
|
@@ -262,19 +263,20 @@ function resolveComponents(value: unknown): ComponentsConfig {
|
|
|
262
263
|
workingLine: normalizeWorkingLine(source.workingLine),
|
|
263
264
|
selectorBorders: {
|
|
264
265
|
enabled: booleanValue(selector.enabled, true),
|
|
265
|
-
|
|
266
|
+
// 只有一种样式;旧配置里的 `zentui` 一律按 `one-ui` 读取。
|
|
267
|
+
style: "one-ui",
|
|
266
268
|
},
|
|
267
269
|
footer: normalizeFooter(source.footer),
|
|
268
270
|
};
|
|
269
271
|
}
|
|
270
272
|
|
|
271
273
|
/** 各配置领域在此组合,运行时仅使用 canonical 结构。 */
|
|
272
|
-
export function mergeConfig(parsed: unknown):
|
|
274
|
+
export function mergeConfig(parsed: unknown): PolishedTuiConfig {
|
|
273
275
|
const record = recordValue(parsed);
|
|
274
276
|
const icons = recordValue(record.icons);
|
|
275
277
|
const colors = recordValue(record.colors);
|
|
276
278
|
const interval = record.projectRefreshIntervalMs;
|
|
277
|
-
const config:
|
|
279
|
+
const config: PolishedTuiConfig = {
|
|
278
280
|
projectRefreshIntervalMs:
|
|
279
281
|
typeof interval === "number" && Number.isFinite(interval)
|
|
280
282
|
? Math.round(interval) <= 0
|
|
@@ -314,12 +316,12 @@ export function mergeConfig(parsed: unknown): ZentuiConfig {
|
|
|
314
316
|
return config;
|
|
315
317
|
}
|
|
316
318
|
|
|
317
|
-
export function loadConfig():
|
|
319
|
+
export function loadConfig(): PolishedTuiConfig {
|
|
318
320
|
return mergeConfig(configStore.read());
|
|
319
321
|
}
|
|
320
322
|
|
|
321
323
|
export function getExtensionStatusPlacement(
|
|
322
|
-
config:
|
|
324
|
+
config: PolishedTuiConfig,
|
|
323
325
|
key: string,
|
|
324
326
|
): ExtensionStatusPlacement {
|
|
325
327
|
const statuses = config.components.footer.styles.starship.extensionStatuses;
|
|
@@ -335,14 +337,14 @@ export function getExtensionStatusPlacement(
|
|
|
335
337
|
}
|
|
336
338
|
|
|
337
339
|
export function getExtensionStatusColorMode(
|
|
338
|
-
config:
|
|
340
|
+
config: PolishedTuiConfig,
|
|
339
341
|
key: string,
|
|
340
342
|
): ExtensionStatusColorMode {
|
|
341
343
|
const modes =
|
|
342
344
|
config.components.footer.styles.starship.extensionStatuses.colorModes;
|
|
343
345
|
return Object.hasOwn(modes, key) && isExtensionStatusColorMode(modes[key])
|
|
344
346
|
? modes[key]
|
|
345
|
-
: "
|
|
347
|
+
: "themed";
|
|
346
348
|
}
|
|
347
349
|
|
|
348
350
|
/** 纯配置修改可在一次 ConfigStore.update 中组合成 Preset。 */
|
|
@@ -371,7 +373,7 @@ export function mutateComponentsRecord(
|
|
|
371
373
|
function mutateConfig(
|
|
372
374
|
path: string,
|
|
373
375
|
update: (record: ConfigRecord) => void,
|
|
374
|
-
):
|
|
376
|
+
): PolishedTuiConfig {
|
|
375
377
|
const mutate = (record: ConfigRecord) => {
|
|
376
378
|
record.version = 1;
|
|
377
379
|
update(record);
|
|
@@ -387,7 +389,7 @@ function saveComponentsMutation(
|
|
|
387
389
|
update: (components: ComponentsConfig) => void,
|
|
388
390
|
path: string,
|
|
389
391
|
replacedStyle?: ComponentStyleOwner,
|
|
390
|
-
):
|
|
392
|
+
): PolishedTuiConfig {
|
|
391
393
|
return mutateConfig(path, (record) =>
|
|
392
394
|
mutateComponentsRecord(
|
|
393
395
|
record,
|
|
@@ -405,7 +407,7 @@ export function saveEditorComponentPatch(
|
|
|
405
407
|
>
|
|
406
408
|
>,
|
|
407
409
|
path = configPath,
|
|
408
|
-
):
|
|
410
|
+
): PolishedTuiConfig {
|
|
409
411
|
return saveComponentsMutation(
|
|
410
412
|
(components) => {
|
|
411
413
|
components.editor = overlayKnown(
|
|
@@ -420,7 +422,7 @@ export function saveEditorComponentPatch(
|
|
|
420
422
|
export function saveMinimalistEditorStylePatch(
|
|
421
423
|
patch: Partial<MinimalistEditorStyleConfig>,
|
|
422
424
|
path = configPath,
|
|
423
|
-
):
|
|
425
|
+
): PolishedTuiConfig {
|
|
424
426
|
return saveComponentsMutation((components) => {
|
|
425
427
|
components.editor.styles.minimalist = overlayKnown(
|
|
426
428
|
components.editor.styles.minimalist,
|
|
@@ -431,7 +433,7 @@ export function saveMinimalistEditorStylePatch(
|
|
|
431
433
|
export function saveUserMessagesComponentPatch(
|
|
432
434
|
patch: Partial<Pick<UserMessagesComponentConfig, "enabled" | "style">>,
|
|
433
435
|
path = configPath,
|
|
434
|
-
):
|
|
436
|
+
): PolishedTuiConfig {
|
|
435
437
|
return saveComponentsMutation(
|
|
436
438
|
(components) => {
|
|
437
439
|
components.userMessages = overlayKnown(
|
|
@@ -446,7 +448,7 @@ export function saveUserMessagesComponentPatch(
|
|
|
446
448
|
export function saveWorkingLineComponentPatch(
|
|
447
449
|
patch: WorkingLineComponentPatch,
|
|
448
450
|
path = configPath,
|
|
449
|
-
):
|
|
451
|
+
): PolishedTuiConfig {
|
|
450
452
|
return saveComponentsMutation((components) => {
|
|
451
453
|
components.workingLine = overlayKnown(
|
|
452
454
|
components.workingLine,
|
|
@@ -457,7 +459,7 @@ export function saveWorkingLineComponentPatch(
|
|
|
457
459
|
export function saveSelectorBordersComponentPatch(
|
|
458
460
|
patch: Partial<SelectorBordersComponentConfig>,
|
|
459
461
|
path = configPath,
|
|
460
|
-
):
|
|
462
|
+
): PolishedTuiConfig {
|
|
461
463
|
return saveComponentsMutation(
|
|
462
464
|
(components) => {
|
|
463
465
|
components.selectorBorders = overlayKnown(
|
|
@@ -472,7 +474,7 @@ export function saveSelectorBordersComponentPatch(
|
|
|
472
474
|
export function saveFooterComponentPatch(
|
|
473
475
|
patch: Partial<Pick<FooterComponentConfig, "style" | "modelLabel">>,
|
|
474
476
|
path = configPath,
|
|
475
|
-
):
|
|
477
|
+
): PolishedTuiConfig {
|
|
476
478
|
return saveComponentsMutation(
|
|
477
479
|
(components) => {
|
|
478
480
|
components.footer = overlayKnown(
|
|
@@ -506,7 +508,7 @@ export type StarshipFooterStylePatch = Partial<
|
|
|
506
508
|
export function saveStarshipFooterStylePatch(
|
|
507
509
|
patch: StarshipFooterStylePatch,
|
|
508
510
|
path = configPath,
|
|
509
|
-
):
|
|
511
|
+
): PolishedTuiConfig {
|
|
510
512
|
return saveComponentsMutation((components) => {
|
|
511
513
|
components.footer.styles.starship = overlayKnown(
|
|
512
514
|
components.footer.styles.starship,
|
|
@@ -517,7 +519,7 @@ export function saveStarshipFooterStylePatch(
|
|
|
517
519
|
export function saveUiFeaturesPatch(
|
|
518
520
|
patch: Partial<UiFeaturesConfig>,
|
|
519
521
|
path = configPath,
|
|
520
|
-
):
|
|
522
|
+
): PolishedTuiConfig {
|
|
521
523
|
return saveComponentsMutation(
|
|
522
524
|
(components) => {
|
|
523
525
|
if (typeof patch.editor === "boolean") {
|
|
@@ -539,7 +541,7 @@ export function saveUiFeaturesPatch(
|
|
|
539
541
|
export function saveFooterSegmentsPatch(
|
|
540
542
|
patch: Partial<FooterSegmentsConfig>,
|
|
541
543
|
path = configPath,
|
|
542
|
-
):
|
|
544
|
+
): PolishedTuiConfig {
|
|
543
545
|
const segments = Object.fromEntries(
|
|
544
546
|
Object.entries(patch).filter(
|
|
545
547
|
([key, value]) =>
|
|
@@ -551,7 +553,7 @@ export function saveFooterSegmentsPatch(
|
|
|
551
553
|
export function saveFooterFormatPatch(
|
|
552
554
|
value: string,
|
|
553
555
|
path = configPath,
|
|
554
|
-
):
|
|
556
|
+
): PolishedTuiConfig {
|
|
555
557
|
return saveStarshipFooterStylePatch(
|
|
556
558
|
{ format: typeof value === "string" ? value : "" },
|
|
557
559
|
path,
|
|
@@ -564,7 +566,7 @@ export function saveResponsiveFooterPatch(
|
|
|
564
566
|
compactFooterMaxLines?: CompactFooterMaxLines;
|
|
565
567
|
},
|
|
566
568
|
path = configPath,
|
|
567
|
-
):
|
|
569
|
+
): PolishedTuiConfig {
|
|
568
570
|
const canonical: Partial<StarshipFooterStyleConfig> = {};
|
|
569
571
|
if (typeof patch.responsiveFooter === "boolean") {
|
|
570
572
|
canonical.responsive = patch.responsiveFooter;
|
|
@@ -582,7 +584,7 @@ export function saveResponsiveFooterPatch(
|
|
|
582
584
|
export function saveIconsModePatch(
|
|
583
585
|
mode: IconMode,
|
|
584
586
|
path = configPath,
|
|
585
|
-
):
|
|
587
|
+
): PolishedTuiConfig {
|
|
586
588
|
return mutateConfig(path, (record) => {
|
|
587
589
|
record.icons = {
|
|
588
590
|
...recordValue(record.icons),
|
|
@@ -593,7 +595,7 @@ export function saveIconsModePatch(
|
|
|
593
595
|
export function saveContextStylePatch(
|
|
594
596
|
style: ContextStyle,
|
|
595
597
|
path = configPath,
|
|
596
|
-
):
|
|
598
|
+
): PolishedTuiConfig {
|
|
597
599
|
return saveStarshipFooterStylePatch(
|
|
598
600
|
{ contextStyle: parseContextStyle(style) },
|
|
599
601
|
path,
|
|
@@ -602,7 +604,7 @@ export function saveContextStylePatch(
|
|
|
602
604
|
export function saveSeparatorPatch(
|
|
603
605
|
separator: SeparatorStyle,
|
|
604
606
|
path = configPath,
|
|
605
|
-
):
|
|
607
|
+
): PolishedTuiConfig {
|
|
606
608
|
return saveStarshipFooterStylePatch(
|
|
607
609
|
{ separator: parseSeparatorStyle(separator) },
|
|
608
610
|
path,
|
|
@@ -611,7 +613,7 @@ export function saveSeparatorPatch(
|
|
|
611
613
|
export function saveContextThresholdsPatch(
|
|
612
614
|
patch: Partial<ContextThresholds>,
|
|
613
615
|
path = configPath,
|
|
614
|
-
):
|
|
616
|
+
): PolishedTuiConfig {
|
|
615
617
|
if (typeof patch.warning === "bigint" || typeof patch.error === "bigint") {
|
|
616
618
|
throw new TypeError("Context thresholds must be JSON-serializable numbers");
|
|
617
619
|
}
|
|
@@ -620,19 +622,19 @@ export function saveContextThresholdsPatch(
|
|
|
620
622
|
export function savePathDisplayPatch(
|
|
621
623
|
patch: Partial<PathDisplayConfig>,
|
|
622
624
|
path = configPath,
|
|
623
|
-
):
|
|
625
|
+
): PolishedTuiConfig {
|
|
624
626
|
return saveStarshipFooterStylePatch({ pathDisplay: patch }, path);
|
|
625
627
|
}
|
|
626
628
|
export function saveGitBranchPatch(
|
|
627
629
|
patch: Partial<GitBranchConfig>,
|
|
628
630
|
path = configPath,
|
|
629
|
-
):
|
|
631
|
+
): PolishedTuiConfig {
|
|
630
632
|
return saveStarshipFooterStylePatch({ gitBranch: patch }, path);
|
|
631
633
|
}
|
|
632
634
|
export function saveEditorModelLabel(
|
|
633
635
|
value: ModelLabelSource,
|
|
634
636
|
path = configPath,
|
|
635
|
-
):
|
|
637
|
+
): PolishedTuiConfig {
|
|
636
638
|
return saveComponentsMutation((components) => {
|
|
637
639
|
components.editor.modelLabel = parseEditorModelLabel(value);
|
|
638
640
|
components.footer.modelLabel = parseEditorModelLabel(value);
|
|
@@ -641,19 +643,19 @@ export function saveEditorModelLabel(
|
|
|
641
643
|
export function saveEditorStyle(
|
|
642
644
|
value: EditorStyle,
|
|
643
645
|
path = configPath,
|
|
644
|
-
):
|
|
646
|
+
): PolishedTuiConfig {
|
|
645
647
|
return saveEditorComponentPatch({ style: parseEditorStyle(value) }, path);
|
|
646
648
|
}
|
|
647
649
|
export function saveMinimalistPatch(
|
|
648
650
|
patch: Partial<MinimalistConfig>,
|
|
649
651
|
path = configPath,
|
|
650
|
-
):
|
|
652
|
+
): PolishedTuiConfig {
|
|
651
653
|
return saveMinimalistEditorStylePatch(patch, path);
|
|
652
654
|
}
|
|
653
655
|
export function saveEditorBorderColorMode(
|
|
654
656
|
value: EditorBorderColorMode,
|
|
655
657
|
path = configPath,
|
|
656
|
-
):
|
|
658
|
+
): PolishedTuiConfig {
|
|
657
659
|
return saveEditorComponentPatch(
|
|
658
660
|
{ borderColorMode: parseEditorBorderColorMode(value) },
|
|
659
661
|
path,
|
|
@@ -662,7 +664,7 @@ export function saveEditorBorderColorMode(
|
|
|
662
664
|
export function saveGitCommitPatch(
|
|
663
665
|
patch: Partial<Pick<GitCommitConfig, "onlyDetached" | "showTag">>,
|
|
664
666
|
path = configPath,
|
|
665
|
-
):
|
|
667
|
+
): PolishedTuiConfig {
|
|
666
668
|
const valid = Object.fromEntries(
|
|
667
669
|
Object.entries(patch).filter(
|
|
668
670
|
([key, value]) =>
|
|
@@ -675,7 +677,7 @@ export function saveGitCommitPatch(
|
|
|
675
677
|
export function saveGitMetricsPatch(
|
|
676
678
|
patch: Partial<GitMetricsConfig>,
|
|
677
679
|
path = configPath,
|
|
678
|
-
):
|
|
680
|
+
): PolishedTuiConfig {
|
|
679
681
|
const valid = Object.fromEntries(
|
|
680
682
|
Object.entries(patch).filter(
|
|
681
683
|
([key, value]) =>
|
|
@@ -688,7 +690,7 @@ export function saveGitMetricsPatch(
|
|
|
688
690
|
export function saveExtensionStatusDefaultPlacement(
|
|
689
691
|
placement: ExtensionStatusPlacement,
|
|
690
692
|
path = configPath,
|
|
691
|
-
):
|
|
693
|
+
): PolishedTuiConfig {
|
|
692
694
|
return saveComponentsMutation((components) => {
|
|
693
695
|
components.footer.styles.starship.extensionStatuses.defaultPlacement =
|
|
694
696
|
isExtensionStatusPlacement(placement) ? placement : "right";
|
|
@@ -698,7 +700,7 @@ export function saveExtensionStatusPlacement(
|
|
|
698
700
|
key: string,
|
|
699
701
|
placement: ExtensionStatusPlacement,
|
|
700
702
|
path = configPath,
|
|
701
|
-
):
|
|
703
|
+
): PolishedTuiConfig {
|
|
702
704
|
return saveComponentsMutation((components) => {
|
|
703
705
|
Object.defineProperty(
|
|
704
706
|
components.footer.styles.starship.extensionStatuses.placements,
|
|
@@ -716,7 +718,7 @@ export function saveExtensionStatusColorMode(
|
|
|
716
718
|
key: string,
|
|
717
719
|
colorMode: ExtensionStatusColorMode,
|
|
718
720
|
path = configPath,
|
|
719
|
-
):
|
|
721
|
+
): PolishedTuiConfig {
|
|
720
722
|
return saveComponentsMutation((components) => {
|
|
721
723
|
Object.defineProperty(
|
|
722
724
|
components.footer.styles.starship.extensionStatuses.colorModes,
|
|
@@ -1,5 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Global registry slot for prototype patches. The key is only shared by module
|
|
3
|
+
* instances of the same process, so it has to stay stable across `/reload`.
|
|
4
|
+
*/
|
|
5
|
+
export const POLISHED_PROTOTYPE_PATCH_REGISTRY = Symbol.for(
|
|
6
|
+
"pi-one-ui.prototype-patch-registry",
|
|
3
7
|
);
|
|
4
8
|
|
|
5
9
|
type PrototypePatchAdapter =
|
|
@@ -35,7 +39,7 @@ type PatchRegistry = Map<PrototypePatchAdapter, PatchRecord>;
|
|
|
35
39
|
type PatchTarget = Record<PropertyKey, unknown>;
|
|
36
40
|
|
|
37
41
|
function existingRegistry(target: PatchTarget): PatchRegistry | undefined {
|
|
38
|
-
const existing = target[
|
|
42
|
+
const existing = target[POLISHED_PROTOTYPE_PATCH_REGISTRY];
|
|
39
43
|
return existing instanceof Map ? (existing as PatchRegistry) : undefined;
|
|
40
44
|
}
|
|
41
45
|
|
|
@@ -43,7 +47,7 @@ function registryFor(target: PatchTarget): PatchRegistry {
|
|
|
43
47
|
const existing = existingRegistry(target);
|
|
44
48
|
if (existing) return existing;
|
|
45
49
|
const registry: PatchRegistry = new Map();
|
|
46
|
-
Object.defineProperty(target,
|
|
50
|
+
Object.defineProperty(target, POLISHED_PROTOTYPE_PATCH_REGISTRY, {
|
|
47
51
|
value: registry,
|
|
48
52
|
configurable: true,
|
|
49
53
|
});
|
|
@@ -100,7 +104,7 @@ function createCleanup(
|
|
|
100
104
|
if (current !== record) return;
|
|
101
105
|
restorePredecessor(target, record);
|
|
102
106
|
registry.delete(adapter);
|
|
103
|
-
if (registry.size === 0) delete target[
|
|
107
|
+
if (registry.size === 0) delete target[POLISHED_PROTOTYPE_PATCH_REGISTRY];
|
|
104
108
|
};
|
|
105
109
|
}
|
|
106
110
|
|
|
@@ -124,7 +128,7 @@ export function installPrototypePatch(
|
|
|
124
128
|
);
|
|
125
129
|
const predecessor = target[method];
|
|
126
130
|
if (typeof predecessor !== "function") {
|
|
127
|
-
if (registry.size === 0) delete target[
|
|
131
|
+
if (registry.size === 0) delete target[POLISHED_PROTOTYPE_PATCH_REGISTRY];
|
|
128
132
|
throw new TypeError(
|
|
129
133
|
`Cannot patch ${method}: predecessor is not a function`,
|
|
130
134
|
);
|
|
@@ -135,7 +139,7 @@ export function installPrototypePatch(
|
|
|
135
139
|
predecessorDescriptor,
|
|
136
140
|
wrapper: () => undefined,
|
|
137
141
|
};
|
|
138
|
-
const wrapper: PrototypeMethod = function
|
|
142
|
+
const wrapper: PrototypeMethod = function polishedPrototypeWrapper(
|
|
139
143
|
this: unknown,
|
|
140
144
|
...args: unknown[]
|
|
141
145
|
): unknown {
|
|
@@ -152,7 +156,7 @@ export function installPrototypePatch(
|
|
|
152
156
|
try {
|
|
153
157
|
installWrapper(target, nextRecord);
|
|
154
158
|
} catch (error) {
|
|
155
|
-
if (registry.size === 0) delete target[
|
|
159
|
+
if (registry.size === 0) delete target[POLISHED_PROTOTYPE_PATCH_REGISTRY];
|
|
156
160
|
throw error;
|
|
157
161
|
}
|
|
158
162
|
record = nextRecord;
|
|
@@ -179,5 +183,5 @@ export function removePrototypePatch(
|
|
|
179
183
|
deactivateRecord(record);
|
|
180
184
|
restorePredecessor(target, record);
|
|
181
185
|
registry.delete(adapter);
|
|
182
|
-
if (registry.size === 0) delete target[
|
|
186
|
+
if (registry.size === 0) delete target[POLISHED_PROTOTYPE_PATCH_REGISTRY];
|
|
183
187
|
}
|