pi-pretty-tui 0.1.1 → 0.1.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 +3 -1
- package/extensions/index.ts +133 -23
- package/package.json +10 -2
package/README.md
CHANGED
|
@@ -9,6 +9,8 @@ A visual refinement extension for the [Pi coding agent](https://pi.dev/). It pro
|
|
|
9
9
|
- Compact `Read`, `Bash`, `Edit`, `Write`, `Grep`, `Find`, and `List` calls
|
|
10
10
|
- Gray running, green success, and red failure indicators
|
|
11
11
|
- Concise result summaries with expandable output
|
|
12
|
+
- Native-style `Write` previews: first 10 lines when collapsed, full content when expanded
|
|
13
|
+
- Live `Bash` output: latest 5 lines when collapsed, all available output when expanded
|
|
12
14
|
- Colored `+added` and `-removed` edit statistics and diffs
|
|
13
15
|
- Correct hanging indentation for long paths and wrapped tool output
|
|
14
16
|
- Bullet (`•`) markers for unordered Markdown lists
|
|
@@ -25,7 +27,7 @@ Pi may warn that built-in tools are being overridden. This is expected: pi-prett
|
|
|
25
27
|
|
|
26
28
|
## Expand tool output
|
|
27
29
|
|
|
28
|
-
|
|
30
|
+
Press `Ctrl+O` (Pi's default `app.tools.expand` keybinding) to show or hide detailed output, edit diffs, and complete `Write` content.
|
|
29
31
|
|
|
30
32
|
## Compatibility notice
|
|
31
33
|
|
package/extensions/index.ts
CHANGED
|
@@ -101,20 +101,53 @@ export default function prettyTui(pi: ExtensionAPI) {
|
|
|
101
101
|
context.state.compactToolStatus = status;
|
|
102
102
|
};
|
|
103
103
|
|
|
104
|
+
const callRow = (theme: any, name: string, detail: string, state: any): DisplayRow => ({
|
|
105
|
+
prefix: () => {
|
|
106
|
+
const status = (state.compactToolStatus ?? "running") as ToolStatus;
|
|
107
|
+
const color = status === "success" ? "success" : status === "error" ? "error" : "dim";
|
|
108
|
+
return theme.fg(color, "● ");
|
|
109
|
+
},
|
|
110
|
+
continuation: " ",
|
|
111
|
+
content:
|
|
112
|
+
theme.fg("accent", theme.bold(name)) +
|
|
113
|
+
theme.fg("dim", "(") +
|
|
114
|
+
theme.fg("text", detail) +
|
|
115
|
+
theme.fg("dim", ")"),
|
|
116
|
+
});
|
|
117
|
+
|
|
104
118
|
const call = (theme: any, name: string, detail: string, state: any) =>
|
|
105
|
-
block([
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
119
|
+
block([callRow(theme, name, detail, state)]);
|
|
120
|
+
|
|
121
|
+
const writeCall = (theme: any, path: string, content: string, expanded: boolean, state: any) => {
|
|
122
|
+
const lines = content.replace(/\t/g, " ").split("\n");
|
|
123
|
+
while (lines.length > 0 && lines[lines.length - 1] === "") lines.pop();
|
|
124
|
+
|
|
125
|
+
const total = lines.length;
|
|
126
|
+
const shown = lines.slice(0, expanded ? total : 10);
|
|
127
|
+
const remaining = total - shown.length;
|
|
128
|
+
const rows: DisplayRow[] = [
|
|
129
|
+
callRow(theme, "Write", `${path} · ${total} ${total === 1 ? "line" : "lines"}`, state),
|
|
130
|
+
];
|
|
131
|
+
|
|
132
|
+
for (let index = 0; index < shown.length; index++) {
|
|
133
|
+
const isLast = index === shown.length - 1 && remaining === 0;
|
|
134
|
+
rows.push({
|
|
135
|
+
prefix: theme.fg("dim", isLast ? " └ " : " │ "),
|
|
136
|
+
continuation: theme.fg("dim", " │ "),
|
|
137
|
+
content: theme.fg("toolOutput", shown[index] || " "),
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
if (remaining > 0) {
|
|
142
|
+
rows.push({
|
|
143
|
+
prefix: theme.fg("muted", " └ "),
|
|
144
|
+
continuation: " ",
|
|
145
|
+
content: theme.fg("muted", `… ${remaining} more ${remaining === 1 ? "line" : "lines"}`),
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
return block(rows);
|
|
150
|
+
};
|
|
118
151
|
|
|
119
152
|
const result = (
|
|
120
153
|
theme: any,
|
|
@@ -161,6 +194,72 @@ export default function prettyTui(pi: ExtensionAPI) {
|
|
|
161
194
|
return result(theme, label);
|
|
162
195
|
};
|
|
163
196
|
|
|
197
|
+
const terminalOutputLines = (output: string): string[] => {
|
|
198
|
+
const lines: string[] = [];
|
|
199
|
+
let current = "";
|
|
200
|
+
|
|
201
|
+
for (let index = 0; index < output.length; index++) {
|
|
202
|
+
const char = output[index];
|
|
203
|
+
if (char === "\r") {
|
|
204
|
+
if (output[index + 1] === "\n") {
|
|
205
|
+
lines.push(current);
|
|
206
|
+
current = "";
|
|
207
|
+
index++;
|
|
208
|
+
} else {
|
|
209
|
+
// A bare carriage return redraws the current terminal line. Progress
|
|
210
|
+
// bars such as tqdm use this to update in place.
|
|
211
|
+
current = "";
|
|
212
|
+
}
|
|
213
|
+
} else if (char === "\n") {
|
|
214
|
+
lines.push(current);
|
|
215
|
+
current = "";
|
|
216
|
+
} else {
|
|
217
|
+
current += char;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
if (current) lines.push(current);
|
|
222
|
+
return lines;
|
|
223
|
+
};
|
|
224
|
+
|
|
225
|
+
const bashResult = (
|
|
226
|
+
context: any,
|
|
227
|
+
theme: any,
|
|
228
|
+
summary: string,
|
|
229
|
+
output: string,
|
|
230
|
+
expanded: boolean,
|
|
231
|
+
status: ToolStatus,
|
|
232
|
+
): Component => {
|
|
233
|
+
setStatus(context, status);
|
|
234
|
+
const lines = terminalOutputLines(output);
|
|
235
|
+
const shown = expanded ? lines : lines.slice(-5);
|
|
236
|
+
const omitted = lines.length - shown.length;
|
|
237
|
+
const rows: DisplayRow[] = [{
|
|
238
|
+
prefix: theme.fg("dim", "└ "),
|
|
239
|
+
continuation: " ",
|
|
240
|
+
content: theme.fg(status === "error" ? "error" : "toolOutput", summary),
|
|
241
|
+
}];
|
|
242
|
+
|
|
243
|
+
if (omitted > 0) {
|
|
244
|
+
rows.push({
|
|
245
|
+
prefix: theme.fg("muted", " │ "),
|
|
246
|
+
continuation: theme.fg("muted", " │ "),
|
|
247
|
+
content: theme.fg("muted", `… ${omitted} earlier ${omitted === 1 ? "line" : "lines"}`),
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
for (let index = 0; index < shown.length; index++) {
|
|
252
|
+
const isLast = index === shown.length - 1;
|
|
253
|
+
rows.push({
|
|
254
|
+
prefix: theme.fg("dim", isLast ? " └ " : " │ "),
|
|
255
|
+
continuation: theme.fg("dim", " │ "),
|
|
256
|
+
content: theme.fg("toolOutput", shown[index] || " "),
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
return block(rows);
|
|
261
|
+
};
|
|
262
|
+
|
|
164
263
|
const completeStatus = (context: any, output: string): boolean => {
|
|
165
264
|
const failed = isError(context, output);
|
|
166
265
|
setStatus(context, failed ? "error" : "success");
|
|
@@ -200,20 +299,31 @@ export default function prettyTui(pi: ExtensionAPI) {
|
|
|
200
299
|
...bash,
|
|
201
300
|
renderShell: "self",
|
|
202
301
|
renderCall(args: any, theme: any, context: any) {
|
|
203
|
-
const command =
|
|
302
|
+
const command = typeof args.command === "string" ? args.command : "";
|
|
204
303
|
return call(theme, "Bash", command, context.state);
|
|
205
304
|
},
|
|
206
305
|
renderResult(toolResult: any, options: any, theme: any, context: any) {
|
|
207
|
-
if (options.isPartial) return partialResult(context, theme, "Running…");
|
|
208
306
|
const output = textContent(toolResult);
|
|
209
|
-
|
|
210
|
-
|
|
307
|
+
if (options.isPartial) {
|
|
308
|
+
return bashResult(context, theme, "Running…", output, options.expanded, "running");
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
const failed = isError(context, output);
|
|
312
|
+
const outputLines = terminalOutputLines(output);
|
|
313
|
+
const lineCount = outputLines.filter((line) => line.length > 0).length;
|
|
211
314
|
const summary = failed
|
|
212
|
-
?
|
|
213
|
-
:
|
|
214
|
-
? `Done · ${
|
|
315
|
+
? outputLines[0] || "Command failed"
|
|
316
|
+
: outputLines.length > 0
|
|
317
|
+
? `Done · ${lineCount} output ${lineCount === 1 ? "line" : "lines"}`
|
|
215
318
|
: "Done";
|
|
216
|
-
return
|
|
319
|
+
return bashResult(
|
|
320
|
+
context,
|
|
321
|
+
theme,
|
|
322
|
+
summary,
|
|
323
|
+
output,
|
|
324
|
+
options.expanded,
|
|
325
|
+
failed ? "error" : "success",
|
|
326
|
+
);
|
|
217
327
|
},
|
|
218
328
|
} as any);
|
|
219
329
|
|
|
@@ -261,8 +371,8 @@ export default function prettyTui(pi: ExtensionAPI) {
|
|
|
261
371
|
...write,
|
|
262
372
|
renderShell: "self",
|
|
263
373
|
renderCall(args: any, theme: any, context: any) {
|
|
264
|
-
const content =
|
|
265
|
-
return
|
|
374
|
+
const content = typeof args.content === "string" ? args.content : "";
|
|
375
|
+
return writeCall(theme, String(args.path ?? ""), content, context.expanded, context.state);
|
|
266
376
|
},
|
|
267
377
|
renderResult(toolResult: any, options: any, theme: any, context: any) {
|
|
268
378
|
if (options.isPartial) return partialResult(context, theme, "Writing…");
|
package/package.json
CHANGED
|
@@ -1,10 +1,18 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-pretty-tui",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"description": "Polished tool calls and list rendering for the Pi coding agent TUI",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Kainan Yang <ykn0309@whu.edu.cn>",
|
|
7
7
|
"type": "module",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/ykn0309/pi-pretty-tui.git"
|
|
11
|
+
},
|
|
12
|
+
"homepage": "https://github.com/ykn0309/pi-pretty-tui#readme",
|
|
13
|
+
"bugs": {
|
|
14
|
+
"url": "https://github.com/ykn0309/pi-pretty-tui/issues"
|
|
15
|
+
},
|
|
8
16
|
"keywords": [
|
|
9
17
|
"pi-package",
|
|
10
18
|
"pi-extension",
|
|
@@ -32,6 +40,6 @@
|
|
|
32
40
|
"extensions": [
|
|
33
41
|
"./extensions/index.ts"
|
|
34
42
|
],
|
|
35
|
-
"image": "https://unpkg.com/pi-pretty-tui@0.1.
|
|
43
|
+
"image": "https://unpkg.com/pi-pretty-tui@0.1.3/assets/screenshot.png"
|
|
36
44
|
}
|
|
37
45
|
}
|