pi-tui-status-beautifier 1.2.1 → 1.3.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.
|
@@ -13,7 +13,36 @@ const COMMON_NAMES: Record<string, string> = {
|
|
|
13
13
|
"wechat-assistant": "wechat",
|
|
14
14
|
};
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
export interface CustomStyleConfig {
|
|
17
|
+
prefix?: string;
|
|
18
|
+
suffix?: string;
|
|
19
|
+
separator?: string;
|
|
20
|
+
brackets?: [string, string];
|
|
21
|
+
inverse?: boolean;
|
|
22
|
+
glyphs?: {
|
|
23
|
+
success?: string;
|
|
24
|
+
warning?: string;
|
|
25
|
+
error?: string;
|
|
26
|
+
accent?: string;
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const BUILTIN_PRESETS: Record<string, CustomStyleConfig> = {
|
|
31
|
+
minimal: {
|
|
32
|
+
separator: " ❯ "
|
|
33
|
+
},
|
|
34
|
+
glass: {
|
|
35
|
+
prefix: "▕ ",
|
|
36
|
+
suffix: " ▏",
|
|
37
|
+
separator: " "
|
|
38
|
+
},
|
|
39
|
+
glow: {
|
|
40
|
+
brackets: ["[", "]"],
|
|
41
|
+
inverse: true
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
const VALID_STYLES = ["minimal", "glass", "glow", "custom", "off"] as const;
|
|
17
46
|
|
|
18
47
|
// Store original statuses to allow dynamic redrawing on configuration changes.
|
|
19
48
|
const originalStatuses = new Map<string, string | undefined>();
|
|
@@ -39,6 +68,7 @@ const home = process.env.HOME || process.env.USERPROFILE || "";
|
|
|
39
68
|
const settingsPath = path.join(home, ".pi/agent/settings.json");
|
|
40
69
|
|
|
41
70
|
let currentStyle = "minimal";
|
|
71
|
+
let customStyleConfig: CustomStyleConfig | undefined;
|
|
42
72
|
|
|
43
73
|
try {
|
|
44
74
|
if (fs.existsSync(settingsPath)) {
|
|
@@ -48,6 +78,9 @@ try {
|
|
|
48
78
|
const saved = config.beautifier.style;
|
|
49
79
|
currentStyle = (VALID_STYLES as readonly string[]).includes(saved) ? saved : "minimal";
|
|
50
80
|
}
|
|
81
|
+
if (config.beautifier?.custom && typeof config.beautifier.custom === "object") {
|
|
82
|
+
customStyleConfig = config.beautifier.custom;
|
|
83
|
+
}
|
|
51
84
|
}
|
|
52
85
|
} catch (_e) {
|
|
53
86
|
// Graceful fallback to default in case of JSON parse or read errors
|
|
@@ -58,7 +91,8 @@ export function beautifyStatus(
|
|
|
58
91
|
key: string,
|
|
59
92
|
originalVal: string | undefined,
|
|
60
93
|
theme: any,
|
|
61
|
-
style: string
|
|
94
|
+
style: string,
|
|
95
|
+
customCfg?: CustomStyleConfig
|
|
62
96
|
): string | undefined {
|
|
63
97
|
if (originalVal === undefined) return undefined;
|
|
64
98
|
if (style === "off") return originalVal;
|
|
@@ -138,38 +172,53 @@ export function beautifyStatus(
|
|
|
138
172
|
state = name === "plan" ? "accent" : "success";
|
|
139
173
|
}
|
|
140
174
|
|
|
141
|
-
// 4.
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
175
|
+
// 4. Determine state glyph & indicator
|
|
176
|
+
const preset =
|
|
177
|
+
style === "custom"
|
|
178
|
+
? (customCfg || customStyleConfig || {})
|
|
179
|
+
: (BUILTIN_PRESETS[style] || BUILTIN_PRESETS.minimal);
|
|
180
|
+
|
|
181
|
+
const glyphMap = preset.glyphs || {};
|
|
182
|
+
let glyph =
|
|
183
|
+
glyphMap[state] ||
|
|
184
|
+
(state === "warning" ? "◌" : state === "error" ? "▲" : state === "accent" ? "◆" : "●");
|
|
145
185
|
|
|
146
186
|
const hasThemeFg = theme && typeof theme.fg === "function";
|
|
147
|
-
const
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
default: {
|
|
167
|
-
const separator = hasThemeFg ? theme.fg("dim", " ❯ ") : " ❯ ";
|
|
168
|
-
const dimmedName = hasThemeFg ? theme.fg("muted", visualName) : visualName;
|
|
169
|
-
const detailStr = details ? ` (${details})` : "";
|
|
170
|
-
return `${dimmedName}${separator}${coloredIndicator}${detailStr}`;
|
|
171
|
-
}
|
|
187
|
+
const coloredGlyph = hasThemeFg ? theme.fg(state, glyph) : glyph;
|
|
188
|
+
const dimmedName = hasThemeFg ? theme.fg("muted", visualName) : visualName;
|
|
189
|
+
|
|
190
|
+
const openBracket = preset.brackets?.[0] ?? "";
|
|
191
|
+
const closeBracket = preset.brackets?.[1] ?? "";
|
|
192
|
+
const prefix = preset.prefix ?? "";
|
|
193
|
+
const suffix = preset.suffix ?? "";
|
|
194
|
+
const sep = preset.separator ?? (preset.brackets ? " " : " ❯ ");
|
|
195
|
+
|
|
196
|
+
// Inverse pill badge (glow preset)
|
|
197
|
+
if (preset.inverse && theme && typeof theme.inverse === "function") {
|
|
198
|
+
const pillContent = ` ${glyph}${details ? ` ${details}` : ""} `;
|
|
199
|
+
const coloredBadge = hasThemeFg ? theme.inverse(theme.fg(state, pillContent)) : `[${pillContent}]`;
|
|
200
|
+
return `${prefix}${dimmedName} ${coloredBadge}${suffix}`;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
let badge = coloredGlyph;
|
|
204
|
+
if (details) {
|
|
205
|
+
badge = `${coloredGlyph} ${details}`;
|
|
172
206
|
}
|
|
207
|
+
if (openBracket && closeBracket) {
|
|
208
|
+
const styledOpen = hasThemeFg ? theme.fg("dim", openBracket) : openBracket;
|
|
209
|
+
const styledClose = hasThemeFg ? theme.fg("dim", closeBracket) : closeBracket;
|
|
210
|
+
badge = `${styledOpen}${badge}${styledClose}`;
|
|
211
|
+
} else if (details && !preset.brackets) {
|
|
212
|
+
const detailStr = hasThemeFg ? theme.fg("dim", ` (${details})`) : ` (${details})`;
|
|
213
|
+
badge = `${coloredGlyph}${detailStr}`;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
const styledSep =
|
|
217
|
+
hasThemeFg && (sep.includes("│") || sep.includes("⁝") || sep.includes("❯"))
|
|
218
|
+
? theme.fg("dim", sep)
|
|
219
|
+
: sep;
|
|
220
|
+
|
|
221
|
+
return `${prefix}${dimmedName}${styledSep}${badge}${suffix}`;
|
|
173
222
|
} catch (_error) {
|
|
174
223
|
return originalVal;
|
|
175
224
|
}
|
|
@@ -329,15 +378,15 @@ export default function (pi: ExtensionAPI) {
|
|
|
329
378
|
|
|
330
379
|
if (styleKey === "custom") {
|
|
331
380
|
const promptRecipe = [
|
|
332
|
-
"You are acting as my Pi TUI Status Bar designer
|
|
333
|
-
"1.
|
|
334
|
-
"2.
|
|
335
|
-
"
|
|
381
|
+
"You are acting as my Pi TUI Status Bar designer for `pi-tui-status-beautifier`.",
|
|
382
|
+
"1. In my primary language, call `ask_user_question` with ASCII visual preview mockups (e.g. Cyber Powerline ‹●›, Nordic Minimalist │ ◈, Capsule Pill [●], Tokyo Night » ✦) to consult my visual taste.",
|
|
383
|
+
"2. Once I select or describe my aesthetic, save the configuration directly into `settings.json` under `beautifier.style = 'custom'` and `beautifier.custom = { separator, brackets, glyphs, prefix, suffix }`.",
|
|
384
|
+
"Do NOT edit any extension source code files."
|
|
336
385
|
].join("\n");
|
|
337
386
|
|
|
338
387
|
if (typeof (ctx.ui as any).setEditorText === "function") {
|
|
339
388
|
(ctx.ui as any).setEditorText(promptRecipe);
|
|
340
|
-
ctx.ui.notify("Press Enter to let your agent consult your style preference
|
|
389
|
+
ctx.ui.notify("Press Enter to let your agent consult your style preference with visual previews!", "info");
|
|
341
390
|
} else {
|
|
342
391
|
ctx.ui.notify(promptRecipe, "info");
|
|
343
392
|
}
|
|
@@ -349,14 +398,13 @@ export default function (pi: ExtensionAPI) {
|
|
|
349
398
|
lastRenderedStatus.clear();
|
|
350
399
|
ctx.ui.notify(`TUI status style changed to: ${styleKey}`, "info");
|
|
351
400
|
|
|
352
|
-
for (const [key, val] of originalStatuses.entries()) {
|
|
353
|
-
ctx.ui.setStatus(key, val);
|
|
354
|
-
}
|
|
355
|
-
|
|
356
401
|
try {
|
|
357
402
|
if (fs.existsSync(settingsPath)) {
|
|
358
403
|
const data = fs.readFileSync(settingsPath, "utf-8");
|
|
359
404
|
const config = JSON.parse(data);
|
|
405
|
+
if (config.beautifier?.custom && typeof config.beautifier.custom === "object") {
|
|
406
|
+
customStyleConfig = config.beautifier.custom;
|
|
407
|
+
}
|
|
360
408
|
if (!config.beautifier) config.beautifier = {};
|
|
361
409
|
config.beautifier.style = styleKey;
|
|
362
410
|
const tempSettings = `${settingsPath}.tmp.${process.pid}.${Date.now()}`;
|
|
@@ -366,6 +414,10 @@ export default function (pi: ExtensionAPI) {
|
|
|
366
414
|
} catch (_e) {
|
|
367
415
|
// Silently ignore disk write errors
|
|
368
416
|
}
|
|
417
|
+
|
|
418
|
+
for (const [key, val] of originalStatuses.entries()) {
|
|
419
|
+
ctx.ui.setStatus(key, val);
|
|
420
|
+
}
|
|
369
421
|
}
|
|
370
422
|
},
|
|
371
423
|
});
|
package/package.json
CHANGED