@diegopetrucci/pi-quiet-tools 0.1.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/README.md +63 -0
- package/index.ts +384 -0
- package/package.json +28 -0
package/README.md
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# quiet-tools
|
|
2
|
+
|
|
3
|
+
A pi extension that makes collapsed built-in tool rows much quieter in the TUI.
|
|
4
|
+
|
|
5
|
+
When enabled, collapsed tool output renders as one output line plus an inline hidden-line count and `Ctrl+O` expand hint. Expanding with `Ctrl+O` still shows pi's full rendered output.
|
|
6
|
+
|
|
7
|
+
`quiet-tools` only changes the visual renderer. It does not truncate, summarize, or rewrite the actual tool results sent to the model.
|
|
8
|
+
|
|
9
|
+
## Covered tools
|
|
10
|
+
|
|
11
|
+
- `bash`
|
|
12
|
+
- `read`
|
|
13
|
+
- `grep`
|
|
14
|
+
- `find`
|
|
15
|
+
- `ls`
|
|
16
|
+
- `edit`
|
|
17
|
+
- `write`
|
|
18
|
+
|
|
19
|
+
For `edit` and `write`, the collapsed call preview is also shortened so large diffs or file contents do not fill the TUI. Expanding restores pi's normal renderer.
|
|
20
|
+
|
|
21
|
+
## Commands
|
|
22
|
+
|
|
23
|
+
```text
|
|
24
|
+
/quiet-tools status
|
|
25
|
+
/quiet-tools off
|
|
26
|
+
/quiet-tools on
|
|
27
|
+
/quiet-tools toggle
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
The extension starts enabled by default. Disabling is temporary for the current extension runtime/session; after `/reload`, `/new`, `/resume`, or `/fork`, it starts enabled again.
|
|
31
|
+
|
|
32
|
+
## Install
|
|
33
|
+
|
|
34
|
+
### Standalone npm package
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
pi install npm:@diegopetrucci/pi-quiet-tools
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### Collection package
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
pi install npm:@diegopetrucci/pi-extensions
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### GitHub package
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
pi install git:github.com/diegopetrucci/pi-extensions
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Then reload pi:
|
|
53
|
+
|
|
54
|
+
```text
|
|
55
|
+
/reload
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Notes
|
|
59
|
+
|
|
60
|
+
- This extension overrides pi's built-in tool definitions so it can customize only their TUI renderers.
|
|
61
|
+
- It reuses pi's built-in implementations and preserves `shellPath`, `shellCommandPrefix`, and image autoresize settings when they are available from settings files.
|
|
62
|
+
- If another extension also overrides built-in tool execution, pi's extension load order determines which override wins.
|
|
63
|
+
- It affects assistant-invoked tool rows. User `!`/`!!` bash commands are rendered by a separate pi component and keep pi's default preview behavior.
|
package/index.ts
ADDED
|
@@ -0,0 +1,384 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createBashToolDefinition,
|
|
3
|
+
createEditToolDefinition,
|
|
4
|
+
createFindToolDefinition,
|
|
5
|
+
createGrepToolDefinition,
|
|
6
|
+
createLsToolDefinition,
|
|
7
|
+
createReadToolDefinition,
|
|
8
|
+
createWriteToolDefinition,
|
|
9
|
+
DEFAULT_MAX_BYTES,
|
|
10
|
+
DEFAULT_MAX_LINES,
|
|
11
|
+
formatSize,
|
|
12
|
+
keyHint,
|
|
13
|
+
SettingsManager,
|
|
14
|
+
type ExtensionAPI,
|
|
15
|
+
type ToolDefinition as PiToolDefinition,
|
|
16
|
+
type ToolsOptions,
|
|
17
|
+
} from "@earendil-works/pi-coding-agent";
|
|
18
|
+
import { Box, Container, Text, truncateToWidth } from "@earendil-works/pi-tui";
|
|
19
|
+
|
|
20
|
+
const COLLAPSED_PREVIEW_LINES = 1;
|
|
21
|
+
const QUIET_CALL_TOOL_NAMES = new Set(["edit", "write"]);
|
|
22
|
+
|
|
23
|
+
type ToolDefinition = PiToolDefinition<any, any, any>;
|
|
24
|
+
type ToolRenderCall = NonNullable<ToolDefinition["renderCall"]>;
|
|
25
|
+
type ToolRenderResult = NonNullable<ToolDefinition["renderResult"]>;
|
|
26
|
+
type ToolRenderCallParams = Parameters<ToolRenderCall>;
|
|
27
|
+
type ToolRenderResultParams = Parameters<ToolRenderResult>;
|
|
28
|
+
type RenderTheme = ToolRenderResultParams[2];
|
|
29
|
+
type ToolRenderContext = ToolRenderResultParams[3];
|
|
30
|
+
|
|
31
|
+
type TimerRenderState = {
|
|
32
|
+
startedAt?: number;
|
|
33
|
+
endedAt?: number;
|
|
34
|
+
interval?: ReturnType<typeof setInterval>;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
type TruncationLike = {
|
|
38
|
+
truncated?: boolean;
|
|
39
|
+
truncatedBy?: "lines" | "bytes";
|
|
40
|
+
firstLineExceedsLimit?: boolean;
|
|
41
|
+
outputLines?: number;
|
|
42
|
+
totalLines?: number;
|
|
43
|
+
maxBytes?: number;
|
|
44
|
+
maxLines?: number;
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
class QuietResultRenderComponent extends Container {}
|
|
48
|
+
|
|
49
|
+
function sanitizePreviewText(text: string): string {
|
|
50
|
+
return text
|
|
51
|
+
.replace(/\x1b\][^\x07]*(?:\x07|\x1b\\)/g, "")
|
|
52
|
+
.replace(/\x1b\[[0-?]*[ -/]*[@-~]/g, "")
|
|
53
|
+
.replace(/[\x00-\x08\x0B-\x1F\x7F]/g, "");
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function getTextOutput(result: ToolRenderResultParams[0]): string {
|
|
57
|
+
return sanitizePreviewText(
|
|
58
|
+
result.content
|
|
59
|
+
.filter((content) => content.type === "text")
|
|
60
|
+
.map((content) => content.text ?? "")
|
|
61
|
+
.join("\n")
|
|
62
|
+
.trim(),
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function visibleLength(text: string): number {
|
|
67
|
+
return text.replace(/\x1b\[[0-?]*[ -/]*[@-~]/g, "").length;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function plural(count: number, singular: string): string {
|
|
71
|
+
return `${count} ${singular}${count === 1 ? "" : "s"}`;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function formatDuration(ms: number): string {
|
|
75
|
+
return `${(ms / 1000).toFixed(1)}s`;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function renderCollapsedLine(line: string, hiddenLines: number, theme: RenderTheme, width: number): string {
|
|
79
|
+
if (width <= 0) return "";
|
|
80
|
+
|
|
81
|
+
const styledLine = theme.fg("toolOutput", line);
|
|
82
|
+
if (hiddenLines <= 0) {
|
|
83
|
+
return truncateToWidth(styledLine, width, "...");
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const hint = theme.fg(
|
|
87
|
+
"muted",
|
|
88
|
+
` ... ${plural(hiddenLines, "more line")} (${keyHint("app.tools.expand", "to expand")})`,
|
|
89
|
+
);
|
|
90
|
+
const hintWidth = visibleLength(hint);
|
|
91
|
+
if (hintWidth + 8 > width) {
|
|
92
|
+
return truncateToWidth(`${styledLine}${hint}`, width, "...");
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return `${truncateToWidth(styledLine, width - hintWidth, "...")}${hint}`;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function formatLimitWarning(label: string, count: unknown): string | undefined {
|
|
99
|
+
return typeof count === "number" ? `${count} ${label} limit` : undefined;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function getTruncationWarnings(result: ToolRenderResultParams[0]): string[] {
|
|
103
|
+
const details = result.details as
|
|
104
|
+
| {
|
|
105
|
+
truncation?: TruncationLike;
|
|
106
|
+
fullOutputPath?: string;
|
|
107
|
+
matchLimitReached?: number;
|
|
108
|
+
resultLimitReached?: number;
|
|
109
|
+
entryLimitReached?: number;
|
|
110
|
+
linesTruncated?: boolean;
|
|
111
|
+
}
|
|
112
|
+
| undefined;
|
|
113
|
+
const truncation = details?.truncation;
|
|
114
|
+
const warnings: string[] = [];
|
|
115
|
+
|
|
116
|
+
if (details?.fullOutputPath) {
|
|
117
|
+
warnings.push(`Full output: ${details.fullOutputPath}`);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
if (truncation?.truncated) {
|
|
121
|
+
if (truncation.firstLineExceedsLimit) {
|
|
122
|
+
warnings.push(`First line exceeds ${formatSize(truncation.maxBytes ?? DEFAULT_MAX_BYTES)} limit`);
|
|
123
|
+
} else if (truncation.truncatedBy === "lines") {
|
|
124
|
+
warnings.push(
|
|
125
|
+
`Truncated: showing ${truncation.outputLines ?? "some"} of ${truncation.totalLines ?? "?"} lines (${truncation.maxLines ?? DEFAULT_MAX_LINES} line limit)`,
|
|
126
|
+
);
|
|
127
|
+
} else {
|
|
128
|
+
warnings.push(
|
|
129
|
+
`Truncated: ${truncation.outputLines ?? "some"} lines shown (${formatSize(truncation.maxBytes ?? DEFAULT_MAX_BYTES)} limit)`,
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const matchLimitWarning = formatLimitWarning("matches", details?.matchLimitReached);
|
|
135
|
+
if (matchLimitWarning) warnings.push(matchLimitWarning);
|
|
136
|
+
|
|
137
|
+
const resultLimitWarning = formatLimitWarning("results", details?.resultLimitReached);
|
|
138
|
+
if (resultLimitWarning) warnings.push(resultLimitWarning);
|
|
139
|
+
|
|
140
|
+
const entryLimitWarning = formatLimitWarning("entries", details?.entryLimitReached);
|
|
141
|
+
if (entryLimitWarning) warnings.push(entryLimitWarning);
|
|
142
|
+
|
|
143
|
+
if (details?.linesTruncated) warnings.push("Some lines truncated");
|
|
144
|
+
|
|
145
|
+
return warnings;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function syncElapsedTimer(options: ToolRenderResultParams[1], context: ToolRenderContext): TimerRenderState {
|
|
149
|
+
const state = context.state as TimerRenderState;
|
|
150
|
+
|
|
151
|
+
if (state.startedAt !== undefined && options.isPartial && !state.interval) {
|
|
152
|
+
state.interval = setInterval(() => context.invalidate(), 1000);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
if (!options.isPartial || context.isError) {
|
|
156
|
+
state.endedAt ??= Date.now();
|
|
157
|
+
if (state.interval) {
|
|
158
|
+
clearInterval(state.interval);
|
|
159
|
+
state.interval = undefined;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
return state;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
function renderQuietCollapsedResult(
|
|
167
|
+
result: ToolRenderResultParams[0],
|
|
168
|
+
options: ToolRenderResultParams[1],
|
|
169
|
+
theme: RenderTheme,
|
|
170
|
+
context: ToolRenderContext,
|
|
171
|
+
): Container {
|
|
172
|
+
const state = syncElapsedTimer(options, context);
|
|
173
|
+
const component = context.lastComponent instanceof QuietResultRenderComponent
|
|
174
|
+
? context.lastComponent
|
|
175
|
+
: new QuietResultRenderComponent();
|
|
176
|
+
component.clear();
|
|
177
|
+
|
|
178
|
+
const output = getTextOutput(result);
|
|
179
|
+
const outputLines = output ? output.split("\n") : [];
|
|
180
|
+
|
|
181
|
+
if (outputLines.length > 0) {
|
|
182
|
+
const firstLine = outputLines[0] ?? "";
|
|
183
|
+
const hiddenLines = Math.max(0, outputLines.length - COLLAPSED_PREVIEW_LINES);
|
|
184
|
+
component.addChild({
|
|
185
|
+
render: (width) => [renderCollapsedLine(firstLine, hiddenLines, theme, width)],
|
|
186
|
+
invalidate: () => undefined,
|
|
187
|
+
});
|
|
188
|
+
} else if (options.isPartial) {
|
|
189
|
+
component.addChild(new Text(theme.fg("muted", "Running..."), 0, 0));
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
const warnings = getTruncationWarnings(result);
|
|
193
|
+
if (warnings.length > 0) {
|
|
194
|
+
component.addChild(new Text(theme.fg("warning", `[${warnings.join(". ")}]`), 0, 0));
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
if (state.startedAt !== undefined && options.isPartial) {
|
|
198
|
+
component.addChild(new Text(theme.fg("muted", `Elapsed ${formatDuration(Date.now() - state.startedAt)}`), 0, 0));
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
component.invalidate();
|
|
202
|
+
return component;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
function getPathArg(args: unknown): string | undefined {
|
|
206
|
+
if (!args || typeof args !== "object") return undefined;
|
|
207
|
+
const values = args as { path?: unknown; file_path?: unknown };
|
|
208
|
+
return typeof values.file_path === "string"
|
|
209
|
+
? values.file_path
|
|
210
|
+
: typeof values.path === "string"
|
|
211
|
+
? values.path
|
|
212
|
+
: undefined;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
function formatQuietEditCall(args: unknown, theme: ToolRenderCallParams[1]): string {
|
|
216
|
+
const path = getPathArg(args);
|
|
217
|
+
const edits = args && typeof args === "object" && Array.isArray((args as { edits?: unknown }).edits)
|
|
218
|
+
? (args as { edits: unknown[] }).edits.length
|
|
219
|
+
: undefined;
|
|
220
|
+
const editSummary = typeof edits === "number" && edits > 0 ? `${plural(edits, "edit block")} hidden` : "preview hidden";
|
|
221
|
+
return `${theme.fg("toolTitle", theme.bold("edit"))} ${theme.fg("accent", path ?? "...")}${theme.fg(
|
|
222
|
+
"muted",
|
|
223
|
+
` ... ${editSummary} (${keyHint("app.tools.expand", "to expand")})`,
|
|
224
|
+
)}`;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
function formatQuietWriteCall(args: unknown, theme: ToolRenderCallParams[1]): string {
|
|
228
|
+
const path = getPathArg(args);
|
|
229
|
+
const content = args && typeof args === "object" ? (args as { content?: unknown }).content : undefined;
|
|
230
|
+
const contentSummary = typeof content === "string"
|
|
231
|
+
? `${plural(content.split("\n").length, "line")}, ${formatSize(Buffer.byteLength(content, "utf8"))} hidden`
|
|
232
|
+
: "content hidden";
|
|
233
|
+
return `${theme.fg("toolTitle", theme.bold("write"))} ${theme.fg("accent", path ?? "...")}${theme.fg(
|
|
234
|
+
"muted",
|
|
235
|
+
` ... ${contentSummary} (${keyHint("app.tools.expand", "to expand")})`,
|
|
236
|
+
)}`;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
function renderQuietCall(
|
|
240
|
+
toolName: string,
|
|
241
|
+
base: ToolDefinition,
|
|
242
|
+
args: ToolRenderCallParams[0],
|
|
243
|
+
theme: ToolRenderCallParams[1],
|
|
244
|
+
context: ToolRenderCallParams[2],
|
|
245
|
+
) {
|
|
246
|
+
if (context.expanded || !QUIET_CALL_TOOL_NAMES.has(toolName)) {
|
|
247
|
+
return base.renderCall?.(args, theme, context) ?? new Text(theme.fg("toolTitle", theme.bold(toolName)), 0, 0);
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
if (toolName === "edit") {
|
|
251
|
+
const component = context.lastComponent instanceof Box ? context.lastComponent : new Box(1, 1);
|
|
252
|
+
const bgColor = context.isError
|
|
253
|
+
? "toolErrorBg"
|
|
254
|
+
: context.executionStarted && !context.isPartial
|
|
255
|
+
? "toolSuccessBg"
|
|
256
|
+
: "toolPendingBg";
|
|
257
|
+
component.setBgFn((text) => theme.bg(bgColor, text));
|
|
258
|
+
component.clear();
|
|
259
|
+
component.addChild(new Text(formatQuietEditCall(args, theme), 0, 0));
|
|
260
|
+
component.invalidate();
|
|
261
|
+
return component;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
const text = context.lastComponent instanceof Text ? context.lastComponent : new Text("", 0, 0);
|
|
265
|
+
text.setText(formatQuietWriteCall(args, theme));
|
|
266
|
+
return text;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
function createQuietToolDefinition(base: ToolDefinition): ToolDefinition {
|
|
270
|
+
const baseRenderResult = base.renderResult;
|
|
271
|
+
|
|
272
|
+
return {
|
|
273
|
+
...base,
|
|
274
|
+
renderCall(args, theme, context) {
|
|
275
|
+
return renderQuietCall(base.name, base, args, theme, context);
|
|
276
|
+
},
|
|
277
|
+
renderResult(result, options, theme, context) {
|
|
278
|
+
if (options.expanded && baseRenderResult) {
|
|
279
|
+
const delegateContext = context.lastComponent instanceof QuietResultRenderComponent
|
|
280
|
+
? { ...context, lastComponent: undefined }
|
|
281
|
+
: context;
|
|
282
|
+
return baseRenderResult(result, options, theme, delegateContext);
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
return renderQuietCollapsedResult(result, options, theme, context);
|
|
286
|
+
},
|
|
287
|
+
};
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
function createBaseToolOptions(cwd: string): ToolsOptions | undefined {
|
|
291
|
+
try {
|
|
292
|
+
const settings = SettingsManager.create(cwd);
|
|
293
|
+
return {
|
|
294
|
+
read: { autoResizeImages: settings.getImageAutoResize() },
|
|
295
|
+
bash: {
|
|
296
|
+
commandPrefix: settings.getShellCommandPrefix(),
|
|
297
|
+
shellPath: settings.getShellPath(),
|
|
298
|
+
},
|
|
299
|
+
};
|
|
300
|
+
} catch {
|
|
301
|
+
return undefined;
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
function createBaseToolDefinitions(cwd: string): ToolDefinition[] {
|
|
306
|
+
const options = createBaseToolOptions(cwd);
|
|
307
|
+
return [
|
|
308
|
+
createReadToolDefinition(cwd, options?.read),
|
|
309
|
+
createBashToolDefinition(cwd, options?.bash),
|
|
310
|
+
createEditToolDefinition(cwd, options?.edit),
|
|
311
|
+
createWriteToolDefinition(cwd, options?.write),
|
|
312
|
+
createGrepToolDefinition(cwd, options?.grep),
|
|
313
|
+
createFindToolDefinition(cwd, options?.find),
|
|
314
|
+
createLsToolDefinition(cwd, options?.ls),
|
|
315
|
+
] as ToolDefinition[];
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
function createQuietToolDefinitions(cwd: string, enabled: boolean): ToolDefinition[] {
|
|
319
|
+
const baseDefinitions = createBaseToolDefinitions(cwd);
|
|
320
|
+
return enabled ? baseDefinitions.map(createQuietToolDefinition) : baseDefinitions;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
export default function quietToolsExtension(pi: ExtensionAPI) {
|
|
324
|
+
let enabled = true;
|
|
325
|
+
|
|
326
|
+
function registerTools(cwd: string): void {
|
|
327
|
+
for (const tool of createQuietToolDefinitions(cwd, enabled)) {
|
|
328
|
+
pi.registerTool(tool);
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
pi.on("session_start", async (_event, ctx) => {
|
|
333
|
+
registerTools(ctx.cwd);
|
|
334
|
+
});
|
|
335
|
+
|
|
336
|
+
pi.registerCommand("quiet-tools", {
|
|
337
|
+
description: "Toggle compact collapsed previews for built-in tool rows",
|
|
338
|
+
getArgumentCompletions: (prefix) => {
|
|
339
|
+
const commands = ["on", "off", "toggle", "status"];
|
|
340
|
+
const query = prefix.trim().toLowerCase();
|
|
341
|
+
const matches = commands.filter((command) => command.startsWith(query));
|
|
342
|
+
return matches.length > 0 ? matches.map((value) => ({ value, label: value })) : null;
|
|
343
|
+
},
|
|
344
|
+
handler: async (args, ctx) => {
|
|
345
|
+
const action = args.trim().toLowerCase() || "toggle";
|
|
346
|
+
|
|
347
|
+
if (action === "on" || action === "enable") {
|
|
348
|
+
enabled = true;
|
|
349
|
+
registerTools(ctx.cwd);
|
|
350
|
+
ctx.ui.notify("Quiet tool previews enabled: collapsed built-in tool rows show one-line output.", "info");
|
|
351
|
+
return;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
if (action === "off" || action === "disable") {
|
|
355
|
+
enabled = false;
|
|
356
|
+
registerTools(ctx.cwd);
|
|
357
|
+
ctx.ui.notify("Quiet tool previews disabled: restored pi's standard built-in tool renderers.", "info");
|
|
358
|
+
return;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
if (action === "toggle") {
|
|
362
|
+
enabled = !enabled;
|
|
363
|
+
registerTools(ctx.cwd);
|
|
364
|
+
ctx.ui.notify(
|
|
365
|
+
enabled
|
|
366
|
+
? "Quiet tool previews enabled: collapsed built-in tool rows show one-line output."
|
|
367
|
+
: "Quiet tool previews disabled: restored pi's standard built-in tool renderers.",
|
|
368
|
+
"info",
|
|
369
|
+
);
|
|
370
|
+
return;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
if (action === "status") {
|
|
374
|
+
ctx.ui.notify(
|
|
375
|
+
`Quiet tool previews are ${enabled ? "enabled" : "disabled"}. Collapsed preview lines: ${enabled ? COLLAPSED_PREVIEW_LINES : "pi default"}. Model-visible tool results are unchanged.`,
|
|
376
|
+
"info",
|
|
377
|
+
);
|
|
378
|
+
return;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
ctx.ui.notify("Usage: /quiet-tools on | off | toggle | status", "warning");
|
|
382
|
+
},
|
|
383
|
+
});
|
|
384
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@diegopetrucci/pi-quiet-tools",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "A pi extension that visually compacts collapsed built-in tool output in the TUI without changing tool results sent to the model.",
|
|
5
|
+
"keywords": ["pi-package", "pi", "tools", "terminal", "tui"],
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/diegopetrucci/pi-extensions.git",
|
|
10
|
+
"directory": "extensions/quiet-tools"
|
|
11
|
+
},
|
|
12
|
+
"files": [
|
|
13
|
+
"index.ts",
|
|
14
|
+
"README.md"
|
|
15
|
+
],
|
|
16
|
+
"publishConfig": {
|
|
17
|
+
"access": "public"
|
|
18
|
+
},
|
|
19
|
+
"pi": {
|
|
20
|
+
"extensions": [
|
|
21
|
+
"index.ts"
|
|
22
|
+
]
|
|
23
|
+
},
|
|
24
|
+
"peerDependencies": {
|
|
25
|
+
"@earendil-works/pi-coding-agent": "*",
|
|
26
|
+
"@earendil-works/pi-tui": "*"
|
|
27
|
+
}
|
|
28
|
+
}
|