pi-tui-status-beautifier 1.3.2 → 1.5.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/extensions/tui-status-beautifier.ts +225 -37
- package/package.json +1 -1
|
@@ -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
|
-
|
|
35
|
+
stream: {
|
|
35
36
|
separator: " ❯ ",
|
|
36
37
|
},
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
suffix: " ▏",
|
|
38
|
+
powerline: {
|
|
39
|
+
brackets: ["‹", "›"],
|
|
40
40
|
separator: " ",
|
|
41
|
+
glyphs: {
|
|
42
|
+
success: "◆",
|
|
43
|
+
warning: "◌",
|
|
44
|
+
error: "▲",
|
|
45
|
+
accent: "◈",
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
matrix: {
|
|
49
|
+
brackets: ["⦗", "⦘"],
|
|
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 = ["
|
|
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>();
|
|
@@ -67,6 +99,7 @@ const BRACKET_PATTERN = /\[(\d+)\]/;
|
|
|
67
99
|
const NUMBER_PATTERN = /\b(\d+)\b/;
|
|
68
100
|
|
|
69
101
|
let currentStyle = "minimal";
|
|
102
|
+
let fullFooterEnabled = false;
|
|
70
103
|
let customStyleConfig: CustomStyleConfig | undefined;
|
|
71
104
|
|
|
72
105
|
/**
|
|
@@ -75,6 +108,7 @@ let customStyleConfig: CustomStyleConfig | undefined;
|
|
|
75
108
|
*/
|
|
76
109
|
export function loadConfig(cwd: string = process.cwd()): {
|
|
77
110
|
style: string;
|
|
111
|
+
fullFooter: boolean;
|
|
78
112
|
custom?: CustomStyleConfig;
|
|
79
113
|
targetSettingsPath: string;
|
|
80
114
|
} {
|
|
@@ -83,6 +117,7 @@ export function loadConfig(cwd: string = process.cwd()): {
|
|
|
83
117
|
const localPath = path.join(cwd, ".pi/settings.json");
|
|
84
118
|
|
|
85
119
|
let resolvedStyle = "minimal";
|
|
120
|
+
let resolvedFullFooter = false;
|
|
86
121
|
let resolvedCustom: CustomStyleConfig | undefined;
|
|
87
122
|
let hasLocalConfig = false;
|
|
88
123
|
|
|
@@ -92,8 +127,15 @@ export function loadConfig(cwd: string = process.cwd()): {
|
|
|
92
127
|
const data = JSON.parse(fs.readFileSync(globalPath, "utf-8"));
|
|
93
128
|
if (data.beautifier) {
|
|
94
129
|
if (typeof data.beautifier.style === "string") {
|
|
95
|
-
const s = data.beautifier.style;
|
|
96
|
-
if (
|
|
130
|
+
const s = data.beautifier.style.toLowerCase().trim();
|
|
131
|
+
if (OFF_STYLES.has(s)) {
|
|
132
|
+
resolvedStyle = "off";
|
|
133
|
+
} else if ((VALID_STYLES as readonly string[]).includes(s)) {
|
|
134
|
+
resolvedStyle = s;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
if (typeof data.beautifier.fullFooter === "boolean") {
|
|
138
|
+
resolvedFullFooter = data.beautifier.fullFooter;
|
|
97
139
|
}
|
|
98
140
|
if (data.beautifier.custom && typeof data.beautifier.custom === "object") {
|
|
99
141
|
resolvedCustom = data.beautifier.custom;
|
|
@@ -109,8 +151,15 @@ export function loadConfig(cwd: string = process.cwd()): {
|
|
|
109
151
|
if (data.beautifier) {
|
|
110
152
|
hasLocalConfig = true;
|
|
111
153
|
if (typeof data.beautifier.style === "string") {
|
|
112
|
-
const s = data.beautifier.style;
|
|
113
|
-
if (
|
|
154
|
+
const s = data.beautifier.style.toLowerCase().trim();
|
|
155
|
+
if (OFF_STYLES.has(s)) {
|
|
156
|
+
resolvedStyle = "off";
|
|
157
|
+
} else if ((VALID_STYLES as readonly string[]).includes(s)) {
|
|
158
|
+
resolvedStyle = s;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
if (typeof data.beautifier.fullFooter === "boolean") {
|
|
162
|
+
resolvedFullFooter = data.beautifier.fullFooter;
|
|
114
163
|
}
|
|
115
164
|
if (data.beautifier.custom && typeof data.beautifier.custom === "object") {
|
|
116
165
|
resolvedCustom = { ...(resolvedCustom || {}), ...data.beautifier.custom };
|
|
@@ -120,11 +169,12 @@ export function loadConfig(cwd: string = process.cwd()): {
|
|
|
120
169
|
} catch (_) {}
|
|
121
170
|
|
|
122
171
|
currentStyle = resolvedStyle;
|
|
172
|
+
fullFooterEnabled = resolvedFullFooter;
|
|
123
173
|
customStyleConfig = resolvedCustom;
|
|
124
174
|
|
|
125
175
|
// Target path for atomic write: local project if exists or in project directory, otherwise global
|
|
126
176
|
const targetSettingsPath = hasLocalConfig || fs.existsSync(localPath) ? localPath : globalPath;
|
|
127
|
-
return { style: resolvedStyle, custom: resolvedCustom, targetSettingsPath };
|
|
177
|
+
return { style: resolvedStyle, fullFooter: resolvedFullFooter, custom: resolvedCustom, targetSettingsPath };
|
|
128
178
|
}
|
|
129
179
|
|
|
130
180
|
loadConfig();
|
|
@@ -138,7 +188,7 @@ export function beautifyStatus(
|
|
|
138
188
|
customCfg?: CustomStyleConfig
|
|
139
189
|
): string | undefined {
|
|
140
190
|
if (originalVal === undefined) return undefined;
|
|
141
|
-
if (style === "off") return originalVal;
|
|
191
|
+
if (style === "off" || OFF_STYLES.has((style || "").toLowerCase().trim())) return originalVal;
|
|
142
192
|
|
|
143
193
|
try {
|
|
144
194
|
const hasAnsi = originalVal.includes("\u001B") || originalVal.includes("\u009B");
|
|
@@ -150,7 +200,7 @@ export function beautifyStatus(
|
|
|
150
200
|
return originalVal;
|
|
151
201
|
}
|
|
152
202
|
|
|
153
|
-
// 1. Get display name
|
|
203
|
+
// 1. Get display name (compact natural width by default to save precious terminal columns)
|
|
154
204
|
let name = key.toLowerCase();
|
|
155
205
|
if (COMMON_NAMES[name]) {
|
|
156
206
|
name = COMMON_NAMES[name];
|
|
@@ -164,7 +214,14 @@ export function beautifyStatus(
|
|
|
164
214
|
name = COMMON_NAMES[name];
|
|
165
215
|
}
|
|
166
216
|
}
|
|
167
|
-
const
|
|
217
|
+
const preset =
|
|
218
|
+
style === "custom"
|
|
219
|
+
? (customCfg || customStyleConfig || {})
|
|
220
|
+
: (BUILTIN_PRESETS[style] || BUILTIN_PRESETS.stream);
|
|
221
|
+
|
|
222
|
+
const visualName = preset.padName === true
|
|
223
|
+
? padToVisualWidth(sliceToVisualWidth(name, 10), 10)
|
|
224
|
+
: name;
|
|
168
225
|
|
|
169
226
|
// 2. Extract metrics/progress details safely (e.g. (2) or fraction 2/5 or count)
|
|
170
227
|
let details: string | undefined;
|
|
@@ -234,11 +291,6 @@ export function beautifyStatus(
|
|
|
234
291
|
}
|
|
235
292
|
|
|
236
293
|
// 4. Determine state glyph & indicator
|
|
237
|
-
const preset =
|
|
238
|
-
style === "custom"
|
|
239
|
-
? (customCfg || customStyleConfig || {})
|
|
240
|
-
: (BUILTIN_PRESETS[style] || BUILTIN_PRESETS.minimal);
|
|
241
|
-
|
|
242
294
|
const glyphMap = preset.glyphs || {};
|
|
243
295
|
let glyph =
|
|
244
296
|
glyphMap[state] ||
|
|
@@ -424,26 +476,66 @@ export function renderBeautifiedFooter(
|
|
|
424
476
|
const modelName = ctx?.model?.name || ctx?.model?.id || "";
|
|
425
477
|
const styledModel = modelName ? (hasThemeFg ? theme.fg("muted", modelName) : modelName) : "";
|
|
426
478
|
|
|
427
|
-
// 3. Token metrics
|
|
428
|
-
let input = 0, output = 0;
|
|
429
|
-
|
|
479
|
+
// 3. Token metrics & context usage (full fidelity matching native Pi footer)
|
|
480
|
+
let input = 0, output = 0, cacheRead = 0, cacheWrite = 0, cost = 0;
|
|
481
|
+
let latestCacheHitRate: number | undefined;
|
|
482
|
+
|
|
483
|
+
if (ctx?.sessionManager?.getEntries) {
|
|
430
484
|
try {
|
|
431
|
-
for (const
|
|
432
|
-
if (
|
|
433
|
-
|
|
485
|
+
for (const entry of ctx.sessionManager.getEntries()) {
|
|
486
|
+
if (entry.type === "usage" && entry.usage) {
|
|
487
|
+
input += entry.usage.input || 0;
|
|
488
|
+
output += entry.usage.output || 0;
|
|
489
|
+
cacheRead += entry.usage.cacheRead || 0;
|
|
490
|
+
cacheWrite += entry.usage.cacheWrite || 0;
|
|
491
|
+
cost += entry.usage.cost?.total || 0;
|
|
492
|
+
} else if (entry.type === "message" && entry.message?.role === "assistant" && entry.message?.usage) {
|
|
493
|
+
const u = entry.message.usage;
|
|
434
494
|
input += u.input || 0;
|
|
435
495
|
output += u.output || 0;
|
|
496
|
+
cacheRead += u.cacheRead || 0;
|
|
497
|
+
cacheWrite += u.cacheWrite || 0;
|
|
498
|
+
cost += u.cost?.total || 0;
|
|
499
|
+
const promptTokens = (u.input || 0) + (u.cacheRead || 0) + (u.cacheWrite || 0);
|
|
500
|
+
if (promptTokens > 0 && u.cacheRead) {
|
|
501
|
+
latestCacheHitRate = (u.cacheRead / promptTokens) * 100;
|
|
502
|
+
}
|
|
436
503
|
}
|
|
437
504
|
}
|
|
438
505
|
} catch (_) {}
|
|
439
506
|
}
|
|
440
|
-
|
|
441
|
-
const
|
|
507
|
+
|
|
508
|
+
const fmt = (n: number) => {
|
|
509
|
+
if (n < 1000) return `${n}`;
|
|
510
|
+
if (n < 10000) return `${(n / 1000).toFixed(1)}k`;
|
|
511
|
+
if (n < 1000000) return `${Math.round(n / 1000)}k`;
|
|
512
|
+
if (n < 10000000) return `${(n / 1000000).toFixed(1)}M`;
|
|
513
|
+
return `${Math.round(n / 1000000)}M`;
|
|
514
|
+
};
|
|
515
|
+
|
|
516
|
+
const statParts: string[] = [];
|
|
517
|
+
if (input > 0) statParts.push(`↑${fmt(input)}`);
|
|
518
|
+
if (output > 0) statParts.push(`↓${fmt(output)}`);
|
|
519
|
+
if (cacheRead > 0) statParts.push(`R${fmt(cacheRead)}`);
|
|
520
|
+
if (latestCacheHitRate !== undefined) statParts.push(`CH${latestCacheHitRate.toFixed(1)}%`);
|
|
521
|
+
if (cost > 0) statParts.push(`$${cost.toFixed(3)}`);
|
|
522
|
+
|
|
523
|
+
const contextUsage = ctx?.getContextUsage?.();
|
|
524
|
+
const contextWindow = contextUsage?.contextWindow || ctx?.model?.contextWindow || 0;
|
|
525
|
+
if (contextUsage?.percent !== undefined && contextUsage?.percent !== null) {
|
|
526
|
+
statParts.push(`${contextUsage.percent.toFixed(1)}%/${fmt(contextWindow)} (auto)`);
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
const tokenStr = statParts.join(" ");
|
|
442
530
|
const styledTokens = tokenStr ? (hasThemeFg ? theme.fg("dim", tokenStr) : tokenStr) : "";
|
|
443
531
|
|
|
532
|
+
// Thinking level
|
|
533
|
+
const thinking = ctx?.thinkingLevel && ctx.thinkingLevel !== "off" ? ` • ${ctx.thinkingLevel}` : "";
|
|
534
|
+
const fullModelStr = styledModel ? `${styledModel}${hasThemeFg ? theme.fg("dim", thinking) : thinking}` : "";
|
|
535
|
+
|
|
444
536
|
// Left & right parts of Line 1
|
|
445
537
|
const leftText = styledBranch;
|
|
446
|
-
const rightParts = [styledTokens,
|
|
538
|
+
const rightParts = [styledTokens, fullModelStr].filter(Boolean);
|
|
447
539
|
const rightText = rightParts.join(styledSep);
|
|
448
540
|
|
|
449
541
|
const leftVis = getStringWidth(leftText);
|
|
@@ -492,7 +584,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
492
584
|
originalStatuses.clear();
|
|
493
585
|
lastRenderedStatus.clear();
|
|
494
586
|
|
|
495
|
-
// Hook setStatus for clean status badge formatting (
|
|
587
|
+
// 1. Hook setStatus for clean status badge formatting (always active unless style === "off")
|
|
496
588
|
const originalSetStatus = ctx.ui.setStatus;
|
|
497
589
|
if (originalSetStatus && !(originalSetStatus as any).__beautifierHooked) {
|
|
498
590
|
const wrapped = function (key: string, value: string | undefined) {
|
|
@@ -511,6 +603,28 @@ export default function (pi: ExtensionAPI) {
|
|
|
511
603
|
(wrapped as any).__beautifierHooked = true;
|
|
512
604
|
ctx.ui.setStatus = wrapped;
|
|
513
605
|
}
|
|
606
|
+
|
|
607
|
+
// 2. Hook setFooter ONLY if user explicitly opted in with fullFooter === true!
|
|
608
|
+
// By default fullFooter is FALSE: Pi's native top two lines remain 100% native and untouched!
|
|
609
|
+
if (fullFooterEnabled && currentStyle !== "off" && typeof (ctx.ui as any).setFooter === "function") {
|
|
610
|
+
(ctx.ui as any).setFooter((tui: any, theme: any, footerData: any) => {
|
|
611
|
+
const unsub =
|
|
612
|
+
typeof footerData?.onBranchChange === "function"
|
|
613
|
+
? footerData.onBranchChange(() => tui.requestRender())
|
|
614
|
+
: undefined;
|
|
615
|
+
|
|
616
|
+
return {
|
|
617
|
+
dispose: unsub,
|
|
618
|
+
invalidate() {},
|
|
619
|
+
render(width: number): string[] {
|
|
620
|
+
if (currentStyle === "off" || !fullFooterEnabled) return [];
|
|
621
|
+
return renderBeautifiedFooter(width, tui, theme, footerData, ctx, currentStyle, customStyleConfig);
|
|
622
|
+
},
|
|
623
|
+
};
|
|
624
|
+
});
|
|
625
|
+
} else if (typeof (ctx.ui as any).setFooter === "function") {
|
|
626
|
+
(ctx.ui as any).setFooter(undefined); // Restore native Pi footer
|
|
627
|
+
}
|
|
514
628
|
});
|
|
515
629
|
|
|
516
630
|
// Dynamic status bar style controller registry
|
|
@@ -522,11 +636,13 @@ export default function (pi: ExtensionAPI) {
|
|
|
522
636
|
}
|
|
523
637
|
|
|
524
638
|
const styleOptions = [
|
|
525
|
-
"
|
|
526
|
-
"
|
|
527
|
-
"
|
|
528
|
-
"glow
|
|
529
|
-
"
|
|
639
|
+
"stream - Clean chevron stream (e.g. name ❯ ● ready)",
|
|
640
|
+
"powerline - Angled brackets & diamonds (e.g. name ‹◆ ready›)",
|
|
641
|
+
"matrix - Dot-matrix brackets & stars (e.g. name ⦗✦ ready⦘)",
|
|
642
|
+
"glow - High-contrast inverse pill (e.g. name [ ● ready ])",
|
|
643
|
+
"custom - [AI Prompt Recipe] Let your agent tailor your bespoke style",
|
|
644
|
+
`footer - Toggle Full-Footer beautification (Git/Model/Tokens) [Currently: ${fullFooterEnabled ? "ON" : "OFF"}]`,
|
|
645
|
+
"off - Revert to native Pi status bar & clean settings",
|
|
530
646
|
];
|
|
531
647
|
|
|
532
648
|
const choice = await ctx.ui.select(`Choose status style (Current: ${currentStyle}):`, styleOptions);
|
|
@@ -535,24 +651,96 @@ export default function (pi: ExtensionAPI) {
|
|
|
535
651
|
|
|
536
652
|
const styleKey = choice.split(" ")[0].trim();
|
|
537
653
|
|
|
654
|
+
if (styleKey === "footer") {
|
|
655
|
+
fullFooterEnabled = !fullFooterEnabled;
|
|
656
|
+
const { targetSettingsPath } = loadConfig(ctx.cwd || process.cwd());
|
|
657
|
+
try {
|
|
658
|
+
if (fs.existsSync(targetSettingsPath)) {
|
|
659
|
+
const data = fs.readFileSync(targetSettingsPath, "utf-8");
|
|
660
|
+
const config = JSON.parse(data);
|
|
661
|
+
if (!config.beautifier) config.beautifier = {};
|
|
662
|
+
config.beautifier.fullFooter = fullFooterEnabled;
|
|
663
|
+
const tempSettings = `${targetSettingsPath}.tmp.${process.pid}.${Date.now()}`;
|
|
664
|
+
fs.writeFileSync(tempSettings, JSON.stringify(config, null, 2), "utf-8");
|
|
665
|
+
fs.renameSync(tempSettings, targetSettingsPath);
|
|
666
|
+
}
|
|
667
|
+
} catch (_) {}
|
|
668
|
+
|
|
669
|
+
if (fullFooterEnabled && currentStyle !== "off" && typeof (ctx.ui as any).setFooter === "function") {
|
|
670
|
+
(ctx.ui as any).setFooter((tui: any, theme: any, footerData: any) => {
|
|
671
|
+
const unsub = typeof footerData?.onBranchChange === "function" ? footerData.onBranchChange(() => tui.requestRender()) : undefined;
|
|
672
|
+
return {
|
|
673
|
+
dispose: unsub,
|
|
674
|
+
invalidate() {},
|
|
675
|
+
render(width: number): string[] {
|
|
676
|
+
if (currentStyle === "off" || !fullFooterEnabled) return [];
|
|
677
|
+
return renderBeautifiedFooter(width, tui, theme, footerData, ctx, currentStyle, customStyleConfig);
|
|
678
|
+
}
|
|
679
|
+
};
|
|
680
|
+
});
|
|
681
|
+
} else if (typeof (ctx.ui as any).setFooter === "function") {
|
|
682
|
+
(ctx.ui as any).setFooter(undefined);
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
ctx.ui.notify(`Full-footer beautification is now ${fullFooterEnabled ? "ENABLED" : "DISABLED (Native Pi Footer)"}`, "info");
|
|
686
|
+
return;
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
if (styleKey === "off") {
|
|
690
|
+
currentStyle = "off";
|
|
691
|
+
customStyleConfig = undefined;
|
|
692
|
+
lastRenderedStatus.clear();
|
|
693
|
+
|
|
694
|
+
// Restore all raw original statuses immediately
|
|
695
|
+
for (const [key, val] of originalStatuses.entries()) {
|
|
696
|
+
ctx.ui.setStatus(key, val);
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
// Zero-trace physical cleanup: completely prune the `beautifier` key from settings.json!
|
|
700
|
+
const { targetSettingsPath } = loadConfig(ctx.cwd || process.cwd());
|
|
701
|
+
try {
|
|
702
|
+
if (fs.existsSync(targetSettingsPath)) {
|
|
703
|
+
const data = fs.readFileSync(targetSettingsPath, "utf-8");
|
|
704
|
+
const config = JSON.parse(data);
|
|
705
|
+
if (config.beautifier) {
|
|
706
|
+
delete config.beautifier;
|
|
707
|
+
const tempSettings = `${targetSettingsPath}.tmp.${process.pid}.${Date.now()}`;
|
|
708
|
+
fs.writeFileSync(tempSettings, JSON.stringify(config, null, 2), "utf-8");
|
|
709
|
+
fs.renameSync(tempSettings, targetSettingsPath);
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
} catch (_e) {
|
|
713
|
+
// Silently ignore disk write errors
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
ctx.ui.notify("Reverted to native Pi status bar. Cleaned up settings.json.", "info");
|
|
717
|
+
return;
|
|
718
|
+
}
|
|
719
|
+
|
|
538
720
|
if (styleKey === "custom") {
|
|
539
721
|
const promptRecipe = [
|
|
540
722
|
"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.
|
|
542
|
-
"
|
|
723
|
+
"1. In my primary language, call `ask_user_question` with ASCII visual preview mockups showing ONLY realistic extension statuses (e.g. `chrome`, `toolflow`, `plan`):",
|
|
724
|
+
" - Powerline: chrome ‹◆ ready› | toolflow ‹◈ 2/5›",
|
|
725
|
+
" - Matrix: chrome ⦗✦ ready⦘ | toolflow ⦗◍ 2/5⦘",
|
|
726
|
+
" - Stream: chrome ❯ ● ready | toolflow ❯ ◐ 2/5",
|
|
727
|
+
" - Glow: chrome [ ● ready ] | toolflow [ ◐ 2/5 ]",
|
|
728
|
+
" (Do NOT include git branch or model name in mockups).",
|
|
729
|
+
"2. If I describe or pick a style, write the configuration into `./.pi/settings.json` (or `~/.pi/agent/settings.json`) under `beautifier`:",
|
|
543
730
|
" {",
|
|
544
731
|
' "beautifier": {',
|
|
545
732
|
' "style": "custom",',
|
|
546
733
|
' "custom": {',
|
|
547
734
|
' "separator": " » ",',
|
|
548
735
|
' "brackets": ["«", "»"],',
|
|
549
|
-
' "prefix": "
|
|
736
|
+
' "prefix": "",',
|
|
550
737
|
' "suffix": "",',
|
|
551
738
|
' "glyphs": { "success": "✦", "warning": "◇", "error": "✖", "accent": "✧" }',
|
|
552
739
|
" }",
|
|
553
740
|
" }",
|
|
554
741
|
" }",
|
|
555
|
-
"
|
|
742
|
+
"3. If I say revert, restore, default, off, or cancel, DELETE the `beautifier` key from `settings.json` and exit quietly without asking more questions.",
|
|
743
|
+
"4. Do NOT search filesystem or edit extension source files."
|
|
556
744
|
].join("\n");
|
|
557
745
|
|
|
558
746
|
if (typeof (ctx.ui as any).setEditorText === "function") {
|
package/package.json
CHANGED