pi-tui-footer 1.2.4 → 1.2.5
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/config.ts
CHANGED
|
@@ -61,8 +61,6 @@ export interface OpenTuiConfig {
|
|
|
61
61
|
thinkingPeek: ThinkingPeekConfig;
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
-
export type PiTuiConfig = OpenTuiConfig;
|
|
65
|
-
|
|
66
64
|
export const DEFAULT_CONFIG: OpenTuiConfig = {
|
|
67
65
|
enabled: true,
|
|
68
66
|
roundedTools: true,
|
|
@@ -105,11 +103,7 @@ export const DEFAULT_CONFIG: OpenTuiConfig = {
|
|
|
105
103
|
|
|
106
104
|
export function getConfigPath(): string {
|
|
107
105
|
const agentDir = getAgentDir();
|
|
108
|
-
|
|
109
|
-
const openTuiPath = join(agentDir, "open-tui.json");
|
|
110
|
-
if (existsSync(piTuiPath)) return piTuiPath;
|
|
111
|
-
if (existsSync(openTuiPath)) return openTuiPath;
|
|
112
|
-
return piTuiPath;
|
|
106
|
+
return join(agentDir, "pi-tui.json");
|
|
113
107
|
}
|
|
114
108
|
|
|
115
109
|
function normalizeThinkingPeekLines(value: unknown): ThinkingPeekLines {
|
package/extensions/icons.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export type IconMode = "auto" | "nerd" | "ascii";
|
|
1
|
+
export type IconMode = "auto" | "nerd" | "unicode" | "ascii";
|
|
2
2
|
|
|
3
3
|
export interface IconGlyphs {
|
|
4
4
|
cwd: string;
|
|
@@ -94,6 +94,47 @@ const ASCII_GLYPHS: IconGlyphs = {
|
|
|
94
94
|
deleted: "x",
|
|
95
95
|
};
|
|
96
96
|
|
|
97
|
+
// Portable Unicode icon set for terminals without a Nerd Font. Keeps the
|
|
98
|
+
// footer icon-like instead of dropping to letters: emoji glyphs (folder,
|
|
99
|
+
// branch, laptop, bulb, floppy, plug, hourglass, bolt) render through the
|
|
100
|
+
// client terminal's emoji fallback at 2 columns, which matches
|
|
101
|
+
// pi-tui's visibleWidth for RGI emoji; the remaining symbols are
|
|
102
|
+
// single-width and covered by DejaVu Sans Mono, JetBrains Mono, Noto Sans
|
|
103
|
+
// Mono and Liberation Mono. Glyph choices are easy to adjust per slot.
|
|
104
|
+
const UNICODE_GLYPHS: IconGlyphs = {
|
|
105
|
+
cwd: "📁",
|
|
106
|
+
host: "⌂",
|
|
107
|
+
session: "🔖",
|
|
108
|
+
git: "🌿",
|
|
109
|
+
working: "◷",
|
|
110
|
+
done: "✓",
|
|
111
|
+
context: "≡",
|
|
112
|
+
model: "💻",
|
|
113
|
+
thinking: "💡",
|
|
114
|
+
input: "↑",
|
|
115
|
+
output: "↓",
|
|
116
|
+
cacheHit: "💾",
|
|
117
|
+
cost: "$",
|
|
118
|
+
speed: "⚡",
|
|
119
|
+
latency: "⌛",
|
|
120
|
+
stall: "⚠",
|
|
121
|
+
extensions: "🔌",
|
|
122
|
+
ahead: "↑",
|
|
123
|
+
behind: "↓",
|
|
124
|
+
diverged: "↕",
|
|
125
|
+
conflicted: "=",
|
|
126
|
+
stashed: "$",
|
|
127
|
+
modified: "!",
|
|
128
|
+
staged: "+",
|
|
129
|
+
untracked: "?",
|
|
130
|
+
renamed: "→",
|
|
131
|
+
deleted: "✗",
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
function isSshSession(): boolean {
|
|
135
|
+
return Boolean(process.env.SSH_TTY || process.env.SSH_CONNECTION);
|
|
136
|
+
}
|
|
137
|
+
|
|
97
138
|
export function detectNerdFont(): boolean {
|
|
98
139
|
// TTY and locale checks are the only reliable signals available here. The
|
|
99
140
|
// terminal emulator owns font selection, so auto mode is optimistic once
|
|
@@ -103,14 +144,23 @@ export function detectNerdFont(): boolean {
|
|
|
103
144
|
return locale === undefined || /utf-?8/i.test(locale);
|
|
104
145
|
}
|
|
105
146
|
|
|
106
|
-
export function resolveIconMode(mode: IconMode): "nerd" | "ascii" {
|
|
147
|
+
export function resolveIconMode(mode: IconMode): "nerd" | "unicode" | "ascii" {
|
|
107
148
|
if (mode === "nerd") return "nerd";
|
|
108
149
|
if (mode === "ascii") return "ascii";
|
|
109
|
-
|
|
150
|
+
if (mode === "unicode") return "unicode";
|
|
151
|
+
if (!detectNerdFont()) return "ascii";
|
|
152
|
+
// Auto cannot know whether the terminal that renders this session ships a
|
|
153
|
+
// Nerd Font (see #38). Local terminals usually do; SSH clients usually do
|
|
154
|
+
// not, because the font lives on the client device, so portable Unicode
|
|
155
|
+
// symbols are the safer default there. Terminals that do have a Nerd Font
|
|
156
|
+
// can opt back in with an explicit icons.mode of "nerd".
|
|
157
|
+
if (isSshSession()) return "unicode";
|
|
158
|
+
return "nerd";
|
|
110
159
|
}
|
|
111
160
|
|
|
112
161
|
export function resolveGlyphs(mode: IconMode): IconGlyphs {
|
|
113
162
|
const resolved = resolveIconMode(mode);
|
|
163
|
+
if (resolved === "unicode") return UNICODE_GLYPHS;
|
|
114
164
|
return resolved === "nerd" ? NERD_GLYPHS : ASCII_GLYPHS;
|
|
115
165
|
}
|
|
116
166
|
|
|
@@ -185,6 +235,6 @@ const RUNTIME_ASCII_SYMBOLS: Record<string, string> = {
|
|
|
185
235
|
};
|
|
186
236
|
|
|
187
237
|
export function runtimeSymbol(name: string, mode: IconMode): string {
|
|
188
|
-
if (resolveIconMode(mode)
|
|
238
|
+
if (resolveIconMode(mode) !== "nerd") return RUNTIME_ASCII_SYMBOLS[name] ?? name;
|
|
189
239
|
return RUNTIME_SYMBOLS[name] ?? "";
|
|
190
240
|
}
|
package/extensions/index.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* thinking peek preview, rounded tool frames, and turn telemetry.
|
|
5
5
|
*
|
|
6
6
|
* Integrated from:
|
|
7
|
-
* - pi-open-tui (v0.3.
|
|
7
|
+
* - pi-open-tui (v0.3.10, MIT, by OldSun, https://github.com/OldSuns/pi-open-tui)
|
|
8
8
|
* - pi-rounded-tools (v0.1.3, MIT, by OrionPax, https://github.com/orionpax1997/pi-rounded-tools)
|
|
9
9
|
*
|
|
10
10
|
* Security audit notes:
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
import type { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
18
18
|
import { type OpenTuiConfig, DEFAULT_CONFIG, ensureConfigExists, loadConfig, saveConfig } from "./config.ts";
|
|
19
19
|
import { installEditor } from "./editor.ts";
|
|
20
|
-
import { installFooter
|
|
20
|
+
import { installFooter } from "./footer.ts";
|
|
21
21
|
import { installHeader } from "./header.ts";
|
|
22
22
|
import { emptyGitStatus, readGitStatus } from "./git.ts";
|
|
23
23
|
import { readRuntimeInfo } from "./runtime.ts";
|
|
@@ -71,7 +71,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
71
71
|
let requestFooterRender: (() => void) | undefined;
|
|
72
72
|
let workingTimer: ReturnType<typeof setInterval> | undefined;
|
|
73
73
|
let cleanupHeader: (() => void) | undefined;
|
|
74
|
-
let cleanupFooter:
|
|
74
|
+
let cleanupFooter: (() => void) | undefined;
|
|
75
75
|
let editor: ReturnType<typeof installEditor> | undefined;
|
|
76
76
|
let pendingUiChange: PendingUiChange | undefined;
|
|
77
77
|
|
|
@@ -164,7 +164,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
164
164
|
},
|
|
165
165
|
},
|
|
166
166
|
);
|
|
167
|
-
cleanupFooter = footer;
|
|
167
|
+
cleanupFooter = footer.cleanup;
|
|
168
168
|
editor = installEditor(
|
|
169
169
|
pi,
|
|
170
170
|
ctx,
|
|
@@ -183,7 +183,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
183
183
|
if (!isTuiContext(ctx)) return;
|
|
184
184
|
if (active) {
|
|
185
185
|
cleanupHeader?.();
|
|
186
|
-
cleanupFooter?.
|
|
186
|
+
cleanupFooter?.();
|
|
187
187
|
editor?.cleanup();
|
|
188
188
|
cleanupHeader = undefined;
|
|
189
189
|
cleanupFooter = undefined;
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Merged 2026-08 from the standalone local extension rounded-tools.ts (a
|
|
5
5
|
* localized copy of npm:pi-rounded-tools@0.1.3, MIT, by OrionPax,
|
|
6
6
|
* https://github.com/orionpax1997/pi-rounded-tools), integrated into pi-tui
|
|
7
|
-
* (based on https://github.com/OldSuns/pi-open-tui v0.3.
|
|
7
|
+
* (based on https://github.com/OldSuns/pi-open-tui v0.3.10, MIT, by
|
|
8
8
|
* OldSun) and gated behind `roundedTools` in pi-tui config
|
|
9
9
|
* (~/.pi/agent/pi-tui.json, default on).
|
|
10
10
|
*
|
|
@@ -65,7 +65,7 @@ const COPY = {
|
|
|
65
65
|
wheelLines: (count: number) => `${count} ${count === 1 ? "line" : "lines"} / notch`,
|
|
66
66
|
wheelPrompt: (count: number) => `Wheel scroll lines per notch, 1-10 (current: ${count}). Enter: apply · Esc: cancel`,
|
|
67
67
|
cursorStyles: { block: "Block", bar: "Bar", underline: "Underline" },
|
|
68
|
-
icons: { auto: "Auto", nerd: "Nerd", ascii: "ASCII" },
|
|
68
|
+
icons: { auto: "Auto", nerd: "Nerd", unicode: "Unicode", ascii: "ASCII" },
|
|
69
69
|
},
|
|
70
70
|
},
|
|
71
71
|
zh: {
|
|
@@ -106,7 +106,7 @@ const COPY = {
|
|
|
106
106
|
wheelLines: (count: number) => `每格 ${count} 行`,
|
|
107
107
|
wheelPrompt: (count: number) => `滚轮每格滚动行数(当前 ${count},范围 1-10),输入后 Enter 应用 · Esc 取消`,
|
|
108
108
|
cursorStyles: { block: "块", bar: "竖线", underline: "下划线" },
|
|
109
|
-
icons: { auto: "自动", nerd: "Nerd", ascii: "ASCII" },
|
|
109
|
+
icons: { auto: "自动", nerd: "Nerd", unicode: "Unicode", ascii: "ASCII" },
|
|
110
110
|
},
|
|
111
111
|
},
|
|
112
112
|
} as const;
|
|
@@ -129,7 +129,7 @@ function toggleSetting(config: OpenTuiConfig, key: keyof OpenTuiConfig["footerSe
|
|
|
129
129
|
}
|
|
130
130
|
|
|
131
131
|
function cycleIconMode(config: OpenTuiConfig): OpenTuiConfig {
|
|
132
|
-
const order: IconMode[] = ["auto", "nerd", "ascii"];
|
|
132
|
+
const order: IconMode[] = ["auto", "nerd", "unicode", "ascii"];
|
|
133
133
|
const currentIdx = order.indexOf(config.icons.mode);
|
|
134
134
|
const next = order[(currentIdx + 1) % order.length]!;
|
|
135
135
|
return { ...config, icons: { mode: next } };
|
|
@@ -183,7 +183,6 @@ function buildFeaturesItems(config: OpenTuiConfig, copy: SettingsCopy): SettingI
|
|
|
183
183
|
return [
|
|
184
184
|
{ id: "enabled", label: copy.labels.enabled, currentValue: flag(config.enabled) },
|
|
185
185
|
{ id: "roundedTools", label: copy.labels.roundedTools, currentValue: flag(config.roundedTools) },
|
|
186
|
-
{ id: "inlineFooter", label: copy.labels.inlineFooter, currentValue: flag(config.inlineFooter) },
|
|
187
186
|
{ id: "settingsLanguage", label: copy.labels.language, currentValue: copy.values.languages[config.settingsLanguage] },
|
|
188
187
|
{
|
|
189
188
|
id: "wheelScrollLines",
|
|
@@ -191,6 +190,7 @@ function buildFeaturesItems(config: OpenTuiConfig, copy: SettingsCopy): SettingI
|
|
|
191
190
|
currentValue: copy.values.wheelLines(config.fullscreen.wheelScrollLines),
|
|
192
191
|
},
|
|
193
192
|
{ id: "thinkingPeek", label: copy.labels.thinkingPeek, currentValue: formatThinkingPeekLines(config.thinkingPeek.lines, copy) },
|
|
193
|
+
{ id: "inlineFooter", label: copy.labels.inlineFooter, currentValue: flag(config.inlineFooter) },
|
|
194
194
|
];
|
|
195
195
|
}
|
|
196
196
|
|
|
@@ -484,7 +484,7 @@ export function registerSettingsCommand(
|
|
|
484
484
|
onOverlayClosed?: () => void;
|
|
485
485
|
},
|
|
486
486
|
): void {
|
|
487
|
-
|
|
487
|
+
pi.registerCommand("pi-tui", {
|
|
488
488
|
description: "Open the Pi TUI settings UI",
|
|
489
489
|
handler: async (_args: string, ctx: ExtensionContext) => {
|
|
490
490
|
if (!ctx.hasUI) return;
|
|
@@ -509,7 +509,5 @@ export function registerSettingsCommand(
|
|
|
509
509
|
// cannot strand the overlay without keyboard input.
|
|
510
510
|
hooks.onOverlayClosed?.();
|
|
511
511
|
},
|
|
512
|
-
};
|
|
513
|
-
pi.registerCommand("pi-tui", commandDef);
|
|
514
|
-
pi.registerCommand("open-tui", commandDef);
|
|
512
|
+
});
|
|
515
513
|
}
|