pi-tui-status-beautifier 1.3.2 → 1.4.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.
@@ -22,6 +22,7 @@ export interface CustomStyleConfig {
22
22
  separator?: string;
23
23
  brackets?: [string, string];
24
24
  inverse?: boolean;
25
+ padName?: boolean;
25
26
  glyphs?: {
26
27
  success?: string;
27
28
  warning?: string;
@@ -31,21 +32,52 @@ export interface CustomStyleConfig {
31
32
  }
32
33
 
33
34
  const BUILTIN_PRESETS: Record<string, CustomStyleConfig> = {
34
- minimal: {
35
+ stream: {
35
36
  separator: " ❯ ",
36
37
  },
37
- glass: {
38
- prefix: "▕ ",
39
- suffix: " ▏",
38
+ powerline: {
39
+ brackets: ["‹", "›"],
40
+ separator: " ",
41
+ glyphs: {
42
+ success: "◆",
43
+ warning: "◌",
44
+ error: "▲",
45
+ accent: "◈",
46
+ },
47
+ },
48
+ matrix: {
49
+ brackets: ["⦗", "⦘"],
40
50
  separator: " ",
51
+ glyphs: {
52
+ success: "✦",
53
+ warning: "◍",
54
+ error: "✖",
55
+ accent: "✧",
56
+ },
41
57
  },
42
58
  glow: {
43
59
  brackets: ["[", "]"],
44
60
  inverse: true,
45
61
  },
62
+ // Backward-compatible aliases
63
+ minimal: {
64
+ separator: " ❯ ",
65
+ padName: true,
66
+ },
67
+ glass: {
68
+ brackets: ["‹", "›"],
69
+ separator: " ",
70
+ glyphs: {
71
+ success: "◆",
72
+ warning: "◌",
73
+ error: "▲",
74
+ accent: "◈",
75
+ },
76
+ },
46
77
  };
47
78
 
48
- const VALID_STYLES = ["minimal", "glass", "glow", "custom", "off"] as const;
79
+ const VALID_STYLES = ["stream", "powerline", "matrix", "glow", "minimal", "glass", "custom", "off"] as const;
80
+ const OFF_STYLES = new Set(["off", "default", "none", "raw", "vanilla", "disable", "disabled"]);
49
81
 
50
82
  // Store original statuses to allow dynamic redrawing on configuration changes.
51
83
  const originalStatuses = new Map<string, string | undefined>();
@@ -92,8 +124,12 @@ export function loadConfig(cwd: string = process.cwd()): {
92
124
  const data = JSON.parse(fs.readFileSync(globalPath, "utf-8"));
93
125
  if (data.beautifier) {
94
126
  if (typeof data.beautifier.style === "string") {
95
- const s = data.beautifier.style;
96
- if ((VALID_STYLES as readonly string[]).includes(s)) resolvedStyle = s;
127
+ const s = data.beautifier.style.toLowerCase().trim();
128
+ if (OFF_STYLES.has(s)) {
129
+ resolvedStyle = "off";
130
+ } else if ((VALID_STYLES as readonly string[]).includes(s)) {
131
+ resolvedStyle = s;
132
+ }
97
133
  }
98
134
  if (data.beautifier.custom && typeof data.beautifier.custom === "object") {
99
135
  resolvedCustom = data.beautifier.custom;
@@ -109,8 +145,12 @@ export function loadConfig(cwd: string = process.cwd()): {
109
145
  if (data.beautifier) {
110
146
  hasLocalConfig = true;
111
147
  if (typeof data.beautifier.style === "string") {
112
- const s = data.beautifier.style;
113
- if ((VALID_STYLES as readonly string[]).includes(s)) resolvedStyle = s;
148
+ const s = data.beautifier.style.toLowerCase().trim();
149
+ if (OFF_STYLES.has(s)) {
150
+ resolvedStyle = "off";
151
+ } else if ((VALID_STYLES as readonly string[]).includes(s)) {
152
+ resolvedStyle = s;
153
+ }
114
154
  }
115
155
  if (data.beautifier.custom && typeof data.beautifier.custom === "object") {
116
156
  resolvedCustom = { ...(resolvedCustom || {}), ...data.beautifier.custom };
@@ -138,7 +178,7 @@ export function beautifyStatus(
138
178
  customCfg?: CustomStyleConfig
139
179
  ): string | undefined {
140
180
  if (originalVal === undefined) return undefined;
141
- if (style === "off") return originalVal;
181
+ if (style === "off" || OFF_STYLES.has((style || "").toLowerCase().trim())) return originalVal;
142
182
 
143
183
  try {
144
184
  const hasAnsi = originalVal.includes("\u001B") || originalVal.includes("\u009B");
@@ -150,7 +190,7 @@ export function beautifyStatus(
150
190
  return originalVal;
151
191
  }
152
192
 
153
- // 1. Get display name
193
+ // 1. Get display name (compact natural width by default to save precious terminal columns)
154
194
  let name = key.toLowerCase();
155
195
  if (COMMON_NAMES[name]) {
156
196
  name = COMMON_NAMES[name];
@@ -164,7 +204,14 @@ export function beautifyStatus(
164
204
  name = COMMON_NAMES[name];
165
205
  }
166
206
  }
167
- const visualName = padToVisualWidth(sliceToVisualWidth(name, 10), 10);
207
+ const preset =
208
+ style === "custom"
209
+ ? (customCfg || customStyleConfig || {})
210
+ : (BUILTIN_PRESETS[style] || BUILTIN_PRESETS.stream);
211
+
212
+ const visualName = preset.padName === true
213
+ ? padToVisualWidth(sliceToVisualWidth(name, 10), 10)
214
+ : name;
168
215
 
169
216
  // 2. Extract metrics/progress details safely (e.g. (2) or fraction 2/5 or count)
170
217
  let details: string | undefined;
@@ -234,11 +281,6 @@ export function beautifyStatus(
234
281
  }
235
282
 
236
283
  // 4. Determine state glyph & indicator
237
- const preset =
238
- style === "custom"
239
- ? (customCfg || customStyleConfig || {})
240
- : (BUILTIN_PRESETS[style] || BUILTIN_PRESETS.minimal);
241
-
242
284
  const glyphMap = preset.glyphs || {};
243
285
  let glyph =
244
286
  glyphMap[state] ||
@@ -522,11 +564,12 @@ export default function (pi: ExtensionAPI) {
522
564
  }
523
565
 
524
566
  const styleOptions = [
525
- "custom - [AI Prompt Recipe] Let your agent generate or tailor your own style",
526
- "minimal - Clean chevron indicator (e.g. name ❯ ●)",
527
- "glass - Framed capsule badge (e.g. ▕ name ● ▏)",
528
- "glow - High-contrast inverse pill (e.g. name [ ● ])",
529
- "off - Pass through raw status output",
567
+ "stream - Clean chevron stream (e.g. name ❯ ● ready)",
568
+ "powerline - Angled brackets & diamonds (e.g. name ‹◆ ready›)",
569
+ "matrix - Dot-matrix brackets & stars (e.g. name ⦗✦ ready⦘)",
570
+ "glow - High-contrast inverse pill (e.g. name [ ● ready ])",
571
+ "custom - [AI Prompt Recipe] Let your agent tailor your bespoke style",
572
+ "off - Revert to native Pi status bar & clean settings",
530
573
  ];
531
574
 
532
575
  const choice = await ctx.ui.select(`Choose status style (Current: ${currentStyle}):`, styleOptions);
@@ -535,24 +578,61 @@ export default function (pi: ExtensionAPI) {
535
578
 
536
579
  const styleKey = choice.split(" ")[0].trim();
537
580
 
581
+ if (styleKey === "off") {
582
+ currentStyle = "off";
583
+ customStyleConfig = undefined;
584
+ lastRenderedStatus.clear();
585
+
586
+ // Restore all raw original statuses immediately
587
+ for (const [key, val] of originalStatuses.entries()) {
588
+ ctx.ui.setStatus(key, val);
589
+ }
590
+
591
+ // Zero-trace physical cleanup: completely prune the `beautifier` key from settings.json!
592
+ const { targetSettingsPath } = loadConfig(ctx.cwd || process.cwd());
593
+ try {
594
+ if (fs.existsSync(targetSettingsPath)) {
595
+ const data = fs.readFileSync(targetSettingsPath, "utf-8");
596
+ const config = JSON.parse(data);
597
+ if (config.beautifier) {
598
+ delete config.beautifier;
599
+ const tempSettings = `${targetSettingsPath}.tmp.${process.pid}.${Date.now()}`;
600
+ fs.writeFileSync(tempSettings, JSON.stringify(config, null, 2), "utf-8");
601
+ fs.renameSync(tempSettings, targetSettingsPath);
602
+ }
603
+ }
604
+ } catch (_e) {
605
+ // Silently ignore disk write errors
606
+ }
607
+
608
+ ctx.ui.notify("Reverted to native Pi status bar. Cleaned up settings.json.", "info");
609
+ return;
610
+ }
611
+
538
612
  if (styleKey === "custom") {
539
613
  const promptRecipe = [
540
614
  "You are acting as my Pi TUI Status Bar designer for `pi-tui-status-beautifier`.",
541
- "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.",
542
- "2. Once I select or describe my aesthetic, save the configuration directly into `./.pi/settings.json` (or `~/.pi/agent/settings.json`) under `beautifier`:",
615
+ "1. In my primary language, call `ask_user_question` with ASCII visual preview mockups showing ONLY realistic extension statuses (e.g. `chrome`, `toolflow`, `plan`):",
616
+ " - Powerline: chrome ‹◆ ready› | toolflow ‹◈ 2/5›",
617
+ " - Matrix: chrome ⦗✦ ready⦘ | toolflow ⦗◍ 2/5⦘",
618
+ " - Stream: chrome ❯ ● ready | toolflow ❯ ◐ 2/5",
619
+ " - Glow: chrome [ ● ready ] | toolflow [ ◐ 2/5 ]",
620
+ " (Do NOT include git branch or model name in mockups).",
621
+ "2. If I describe or pick a style, write the configuration into `./.pi/settings.json` (or `~/.pi/agent/settings.json`) under `beautifier`:",
543
622
  " {",
544
623
  ' "beautifier": {',
545
624
  ' "style": "custom",',
546
625
  ' "custom": {',
547
626
  ' "separator": " » ",',
548
627
  ' "brackets": ["«", "»"],',
549
- ' "prefix": "✦ ",',
628
+ ' "prefix": "",',
550
629
  ' "suffix": "",',
551
630
  ' "glyphs": { "success": "✦", "warning": "◇", "error": "✖", "accent": "✧" }',
552
631
  " }",
553
632
  " }",
554
633
  " }",
555
- "Do NOT crawl filesystem or edit extension source code files."
634
+ "3. If I say revert, restore, default, off, or cancel, DELETE the `beautifier` key from `settings.json` and exit quietly without asking more questions.",
635
+ "4. Do NOT search filesystem or edit extension source files."
556
636
  ].join("\n");
557
637
 
558
638
  if (typeof (ctx.ui as any).setEditorText === "function") {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-tui-status-beautifier",
3
- "version": "1.3.2",
3
+ "version": "1.4.0",
4
4
  "description": "Minimalist status bar formatter & AI-customizable layout engine for Pi TUI.",
5
5
  "main": "extensions/tui-status-beautifier.ts",
6
6
  "keywords": [