pi-tui-footer 1.2.1 → 1.2.3

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.0
20
+ pi install git:github.com/onenora/pi-tui-footer@v1.2.3
21
21
  ```
22
22
 
23
23
  更新:
@@ -4,7 +4,7 @@ import {
4
4
  type ExtensionContext,
5
5
  type KeybindingsManager,
6
6
  } from "@earendil-works/pi-coding-agent";
7
- import type { EditorTheme, TUI } from "@earendil-works/pi-tui";
7
+ import type { EditorTheme, TuiMouseEvent, TuiMouseEventResult, TUI } from "@earendil-works/pi-tui";
8
8
  import { CURSOR_MARKER, truncateToWidth, visibleWidth } from "@earendil-works/pi-tui";
9
9
  import type { CursorStyle } from "./config.ts";
10
10
  import {
@@ -24,6 +24,8 @@ const CURSOR_STYLE_SEQUENCES: Partial<Record<CursorStyle, string>> = {
24
24
  underline: "\x1b[4 q",
25
25
  };
26
26
  const DEFAULT_CURSOR_STYLE_SEQUENCE = "\x1b[0 q";
27
+ const EDITOR_FRAME_LEFT_INSET = 2;
28
+ const EDITOR_FRAME_HORIZONTAL_CHROME = EDITOR_FRAME_LEFT_INSET * 2;
27
29
 
28
30
  interface WorkingStatusIndicator {
29
31
  renderInBorder(width: number): string;
@@ -221,6 +223,16 @@ export class OpenTuiEditor extends CustomEditor {
221
223
  super.setPaddingX(0);
222
224
  }
223
225
 
226
+ override handleMouse(event: TuiMouseEvent): TuiMouseEventResult | undefined {
227
+ if (event.width < EDITOR_FRAME_HORIZONTAL_CHROME) return super.handleMouse(event);
228
+
229
+ return super.handleMouse({
230
+ ...event,
231
+ x: event.x - EDITOR_FRAME_LEFT_INSET,
232
+ width: event.width - EDITOR_FRAME_HORIZONTAL_CHROME,
233
+ });
234
+ }
235
+
224
236
  setWorkingStatusIndicator(indicator: WorkingStatusIndicator | undefined): void {
225
237
  this.embeddedWorkingStatusIndicator = indicator;
226
238
  this.tui.requestRender();
@@ -262,12 +274,12 @@ export class OpenTuiEditor extends CustomEditor {
262
274
  }
263
275
 
264
276
  render(width: number): string[] {
265
- if (width < 4) return this.renderBase(width);
277
+ if (width < EDITOR_FRAME_HORIZONTAL_CHROME) return this.renderBase(width);
266
278
 
267
279
  const rail = this.getRail();
268
280
  const borderPaint = this.getBorder;
269
281
  // ponytail: 1-char rail + 1-char gap on each side = 4 chars of chrome.
270
- const innerWidth = Math.max(0, width - 4);
282
+ const innerWidth = Math.max(0, width - EDITOR_FRAME_HORIZONTAL_CHROME);
271
283
  const baseLines = this.renderBase(innerWidth);
272
284
  const bottomIdx = findBottomBorderIndex(baseLines);
273
285
 
@@ -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.8, MIT, by OldSun, https://github.com/OldSuns/pi-open-tui)
7
+ * - pi-open-tui (v0.3.9, 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:
@@ -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.8, MIT, by
7
+ * (based on https://github.com/OldSuns/pi-open-tui v0.3.9, 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, bash, grep, find, ls)
11
+ * Re-registers the built-in tools (read, write, edit, 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,7 +26,6 @@
26
26
 
27
27
  import type { ExtensionAPI, ToolDefinition } from "@earendil-works/pi-coding-agent";
28
28
  import {
29
- createBashToolDefinition,
30
29
  createEditToolDefinition,
31
30
  createFindToolDefinition,
32
31
  createGrepToolDefinition,
@@ -229,7 +228,7 @@ function wrapBuiltin(def: ToolDef) {
229
228
  }
230
229
 
231
230
  /**
232
- * Register the 7 built-in file/bash tools, either with rounded frames
231
+ * Register the 6 built-in file tools, either with rounded frames
233
232
  * (`enabled`) or with their plain stock definitions (`!enabled`, restores
234
233
  * original rendering). Registration refreshes the active tool set in the
235
234
  * current session, so toggling the setting takes effect immediately.
@@ -239,7 +238,6 @@ export function registerRoundedTools(pi: ExtensionAPI, enabled: boolean, cwd: st
239
238
  createReadToolDefinition(cwd),
240
239
  createWriteToolDefinition(cwd),
241
240
  createEditToolDefinition(cwd),
242
- createBashToolDefinition(cwd),
243
241
  createGrepToolDefinition(cwd),
244
242
  createFindToolDefinition(cwd),
245
243
  createLsToolDefinition(cwd),
@@ -43,23 +43,28 @@ export function truncateBranch(branch: string, maxLen: number): string {
43
43
  }
44
44
 
45
45
  export function truncatePath(path: string, maxLen: number): string {
46
- if (path.length <= maxLen) return path;
46
+ // `maxLen` is a terminal-column budget, so every comparison here must use
47
+ // display width. Comparing String.length let wide (CJK) paths stay wider than
48
+ // the budget: for a basename of 4 characters but 8 columns, `truncatePath`
49
+ // returned it unchanged, so fitSegmentsByPriority's `while (totalW() > maxW)`
50
+ // loop never made progress and livelocked the renderer at 100% CPU.
51
+ if (visibleWidth(path) <= maxLen) return path;
47
52
  if (maxLen <= 3) return "...".slice(0, maxLen);
48
53
  const sepChar = path.includes("/") ? "/" : "\\";
49
54
  const parts = path.split(/[\\/]/);
50
- if (parts.length <= 2) return path.slice(0, maxLen - 3) + "...";
55
+ if (parts.length <= 2) return truncateToWidth(path, maxLen, "...");
51
56
  // Keep first segment (e.g. ~) and as many trailing segments as fit.
52
57
  const tail: string[] = [];
53
58
  let tailLen = 0;
54
59
  for (let i = parts.length - 1; i >= 1; i--) {
55
60
  const seg = parts[i]!;
56
- if (tailLen + seg.length + 4 > maxLen) break;
61
+ if (tailLen + visibleWidth(seg) + 4 > maxLen) break;
57
62
  tail.unshift(seg);
58
- tailLen += seg.length + 1;
63
+ tailLen += visibleWidth(seg) + 1;
59
64
  }
60
65
  const head = parts[0]!;
61
66
  const result = `${head}${sepChar}...${sepChar}${tail.join(sepChar)}`;
62
- return result.length > maxLen ? result.slice(0, maxLen - 3) + "..." : result;
67
+ return visibleWidth(result) > maxLen ? truncateToWidth(result, maxLen, "...") : result;
63
68
  }
64
69
 
65
70
  export function finiteOrZero(value: unknown): number {
@@ -158,7 +163,25 @@ export function fitSegmentsByPriority(
158
163
  if (totalW() <= maxW) break;
159
164
  }
160
165
  }
166
+ // A segment whose `truncate` cannot actually shrink would otherwise spin here
167
+ // forever and block the render timer. Require each pass to make progress, and
168
+ // drop the worst segment when it does not, so layout always terminates.
169
+ let lastTotal = Infinity;
161
170
  while (totalW() > maxW) {
171
+ const nowTotal = totalW();
172
+ if (nowTotal >= lastTotal) {
173
+ let worst = -1;
174
+ for (let i = 0; i < items.length; i++) {
175
+ if (items[i].text !== "" && (worst === -1 || items[i].priority < items[worst].priority)) {
176
+ worst = i;
177
+ }
178
+ }
179
+ if (worst === -1) break;
180
+ items[worst].text = "";
181
+ items[worst].w = 0;
182
+ continue;
183
+ }
184
+ lastTotal = nowTotal;
162
185
  let target = -1;
163
186
  for (let i = 0; i < items.length; i++) {
164
187
  if (items[i].text !== "" && (target === -1 || items[i].priority < items[target].priority)) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-tui-footer",
3
- "version": "1.2.1",
3
+ "version": "1.2.3",
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": [