@erlin-ai/pi-footer-wrap 0.1.1 → 0.2.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/CHANGELOG.md +15 -0
- package/lib/footer.ts +7 -4
- package/package.json +1 -1
- package/src/index.ts +22 -0
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,21 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [0.2.0] - 2026-10-02
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- Virtual models now show their routed physical model in the footer, e.g.
|
|
13
|
+
`auto → group/auto-glm-5-3-flash`, mirroring pi 0.99.x default footer
|
|
14
|
+
behavior. Read from session entries; same-model turns show no arrow.
|
|
15
|
+
|
|
16
|
+
### Fixed
|
|
17
|
+
|
|
18
|
+
- `layoutStats` called `String(wrapTextWithAnsi(...))`, but pi-tui returns
|
|
19
|
+
`string[]`; `String()` re-joined the wrapped pieces into one line, so an
|
|
20
|
+
over-wide stats line rendered unsplit and crashed pi's TUI with
|
|
21
|
+
`rendered line exceeds terminal width`.
|
|
22
|
+
|
|
8
23
|
## [0.1.0] - 2026-09-20
|
|
9
24
|
|
|
10
25
|
### Added
|
package/lib/footer.ts
CHANGED
|
@@ -155,10 +155,13 @@ export function layoutStats(
|
|
|
155
155
|
if (lw + minPad + rw <= width) {
|
|
156
156
|
return [left + " ".repeat(width - lw - rw) + right];
|
|
157
157
|
}
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
158
|
+
// wrapTextWithAnsi returns string[] (pi-tui utils.d.ts) — never String() it:
|
|
159
|
+
// Array→String joins with "," and can yield one over-wide line (crash).
|
|
160
|
+
const wrap = (s: string): string[] => {
|
|
161
|
+
if (visibleWidth(s) <= width) return [s];
|
|
162
|
+
const wrapped = wrapTextWithAnsi(s, width);
|
|
163
|
+
return Array.isArray(wrapped) ? wrapped : String(wrapped).split("\n");
|
|
164
|
+
};
|
|
162
165
|
if (lw <= width || rw <= width) {
|
|
163
166
|
const leftLines = lw <= width ? [left] : wrap(left);
|
|
164
167
|
const rightLines =
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@erlin-ai/pi-footer-wrap",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Adaptive-wrapping footer for the pi coding agent: takes over the default footer and wraps extension statuses across lines instead of truncating them. No data is dropped.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|
package/src/index.ts
CHANGED
|
@@ -25,6 +25,20 @@ function wrapToLines(text: string, width: number): string[] {
|
|
|
25
25
|
return Array.isArray(wrapped) ? wrapped : String(wrapped).split("\n");
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
+
/** Physical model id of the latest assistant response (what a virtual model routed to). */
|
|
29
|
+
function latestRoutedModel(ctx: any): string | undefined {
|
|
30
|
+
try {
|
|
31
|
+
const entries = ctx.sessionManager?.getEntries?.() ?? [];
|
|
32
|
+
for (let i = entries.length - 1; i >= 0; i--) {
|
|
33
|
+
const msg = entries[i]?.message;
|
|
34
|
+
if (msg?.role === "assistant" && msg.model) return String(msg.model);
|
|
35
|
+
}
|
|
36
|
+
} catch {
|
|
37
|
+
// best-effort
|
|
38
|
+
}
|
|
39
|
+
return undefined;
|
|
40
|
+
}
|
|
41
|
+
|
|
28
42
|
export default function (pi: any) {
|
|
29
43
|
let enabled = true;
|
|
30
44
|
|
|
@@ -69,6 +83,14 @@ export default function (pi: any) {
|
|
|
69
83
|
right =
|
|
70
84
|
level === "off" ? `${right} • thinking off` : `${right} • ${level}`;
|
|
71
85
|
}
|
|
86
|
+
// A virtual model routes each request; show where the latest response went
|
|
87
|
+
// (mirrors pi 0.99.x default footer, footer.js:207-211). ExtensionContext
|
|
88
|
+
// doesn't expose session.routedModel, so read the latest assistant message's
|
|
89
|
+
// physical model from session entries.
|
|
90
|
+
const routed = latestRoutedModel(ctx);
|
|
91
|
+
if (routed && routed !== model?.id) {
|
|
92
|
+
right += ` → ${routed}`;
|
|
93
|
+
}
|
|
72
94
|
if ((footerData?.getAvailableProviderCount?.() ?? 1) > 1 && model) {
|
|
73
95
|
right = `(${model.provider}) ${right}`;
|
|
74
96
|
}
|