pi-tui-footer 1.2.3 → 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/README.md CHANGED
@@ -17,7 +17,7 @@ pi install git:github.com/onenora/pi-tui-footer
17
17
  固定版本:
18
18
 
19
19
  ```bash
20
- pi install git:github.com/onenora/pi-tui-footer@v1.2.3
20
+ pi install git:github.com/onenora/pi-tui-footer@v1.2.4
21
21
  ```
22
22
 
23
23
  更新:
@@ -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
- const piTuiPath = join(agentDir, "pi-tui.json");
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 {
@@ -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
- return detectNerdFont() ? "nerd" : "ascii";
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) === "ascii") return RUNTIME_ASCII_SYMBOLS[name] ?? name;
238
+ if (resolveIconMode(mode) !== "nerd") return RUNTIME_ASCII_SYMBOLS[name] ?? name;
189
239
  return RUNTIME_SYMBOLS[name] ?? "";
190
240
  }
@@ -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.9, MIT, by OldSun, https://github.com/OldSuns/pi-open-tui)
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, type FooterHandle } from "./footer.ts";
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: FooterHandle | undefined;
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?.cleanup();
186
+ cleanupFooter?.();
187
187
  editor?.cleanup();
188
188
  cleanupHeader = undefined;
189
189
  cleanupFooter = undefined;
@@ -4,11 +4,11 @@
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.9, MIT, by
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
  *
11
- * Re-registers the built-in tools (read, write, edit, grep, find, ls)
11
+ * Re-registers the built-in tools (read, write, edit, bash, grep, find, ls)
12
12
  * with `renderShell: "self"` and wraps each tool call / result in a frame
13
13
  * drawn with Unicode rounded-corner characters (╭ ╮ ╰ ╯ ─ │).
14
14
  *
@@ -26,6 +26,7 @@
26
26
 
27
27
  import type { ExtensionAPI, ToolDefinition } from "@earendil-works/pi-coding-agent";
28
28
  import {
29
+ createBashToolDefinition,
29
30
  createEditToolDefinition,
30
31
  createFindToolDefinition,
31
32
  createGrepToolDefinition,
@@ -228,7 +229,7 @@ function wrapBuiltin(def: ToolDef) {
228
229
  }
229
230
 
230
231
  /**
231
- * Register the 6 built-in file tools, either with rounded frames
232
+ * Register the 7 built-in file/bash tools, either with rounded frames
232
233
  * (`enabled`) or with their plain stock definitions (`!enabled`, restores
233
234
  * original rendering). Registration refreshes the active tool set in the
234
235
  * current session, so toggling the setting takes effect immediately.
@@ -238,6 +239,7 @@ export function registerRoundedTools(pi: ExtensionAPI, enabled: boolean, cwd: st
238
239
  createReadToolDefinition(cwd),
239
240
  createWriteToolDefinition(cwd),
240
241
  createEditToolDefinition(cwd),
242
+ createBashToolDefinition(cwd),
241
243
  createGrepToolDefinition(cwd),
242
244
  createFindToolDefinition(cwd),
243
245
  createLsToolDefinition(cwd),
@@ -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
- const commandDef = {
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
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-tui-footer",
3
- "version": "1.2.3",
3
+ "version": "1.2.5",
4
4
  "description": "pi extension: TUI footer/header with git status, telemetry, rounded tools, editor and settings enhancements",
5
5
  "type": "module",
6
6
  "keywords": [