pi-better-harness 0.15.0 → 0.15.2
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 +8 -6
- package/extensions/minimal-output/hook.ts +24 -207
- package/extensions/minimal-output/index.ts +5 -12
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -63,16 +63,18 @@ need interactive confirmation. Full policy: [pi-better-sandbox](https://github.c
|
|
|
63
63
|
## Minimal Tool Output
|
|
64
64
|
|
|
65
65
|
The bundled harness also provides `/tool-output minimal`, `/tool-output normal`,
|
|
66
|
-
and `/tool-output` (toggle). Minimal mode
|
|
67
|
-
|
|
66
|
+
and `/tool-output` (toggle). Minimal mode hides tool blocks entirely, including
|
|
67
|
+
running calls, headers, results, images, summary rows, and tool spacers. Built-in,
|
|
68
68
|
extension, and MCP calls are included. Execution, sandboxing, and agent-facing
|
|
69
|
-
payloads are unchanged. Ctrl+O
|
|
70
|
-
|
|
69
|
+
payloads are unchanged. Ctrl+O reveals the original tool blocks; Ctrl+O again
|
|
70
|
+
hides them. `/tool-output normal` restores ordinary rendering. Error results
|
|
71
|
+
are also hidden in minimal mode and remain available when revealed.
|
|
71
72
|
|
|
72
73
|
Normal mode is the default. The preference is saved in the current session,
|
|
73
74
|
including resume/reload. This is a version-sensitive internal TUI adapter,
|
|
74
|
-
tested with Pi 0.82.1
|
|
75
|
-
ordinary output enabled. Print/RPC output and
|
|
75
|
+
tested with Pi 0.82.1, 0.99.1, and the bundled Pi 1.0.0 CLI; incompatible APIs
|
|
76
|
+
produce a warning and leave ordinary output enabled. Print/RPC output and
|
|
77
|
+
exported transcripts are unchanged.
|
|
76
78
|
|
|
77
79
|
The standalone-package installer does not install this bundled extension.
|
|
78
80
|
Load the bundled harness or run it directly from a checkout:
|
|
@@ -7,10 +7,7 @@ interface ToolComponent {
|
|
|
7
7
|
expanded: boolean;
|
|
8
8
|
showImages: boolean;
|
|
9
9
|
resultRendererComponent?: unknown;
|
|
10
|
-
|
|
11
|
-
toolCallId?: string;
|
|
12
|
-
result?: { isError?: boolean };
|
|
13
|
-
ui: { requestRender(): void; children?: ChatContainer[] };
|
|
10
|
+
ui: { requestRender(): void };
|
|
14
11
|
invalidate(): void;
|
|
15
12
|
setExpanded(expanded: boolean): void;
|
|
16
13
|
render(width: number): string[];
|
|
@@ -23,43 +20,21 @@ interface ToolPrototype {
|
|
|
23
20
|
getTextOutput: Method;
|
|
24
21
|
setExpanded: Method;
|
|
25
22
|
invalidate: Method;
|
|
23
|
+
render: ToolComponent["render"];
|
|
26
24
|
[HOOK]?: HookState;
|
|
27
25
|
}
|
|
28
|
-
interface ChatContainer {
|
|
29
|
-
children: unknown[];
|
|
30
|
-
render: (width: number) => string[];
|
|
31
|
-
mouseLayout?: { width: number; children: Array<{ component: unknown; height: number }> };
|
|
32
|
-
[CHAT]?: { original: (width: number) => string[]; wrapper: (width: number) => string[] };
|
|
33
|
-
}
|
|
34
|
-
interface ContainerPrototype {
|
|
35
|
-
addChild: (child: unknown, ...rest: unknown[]) => unknown;
|
|
36
|
-
render: (width: number) => string[];
|
|
37
|
-
[ADD]?: { original: ContainerPrototype["addChild"]; wrapper: ContainerPrototype["addChild"] };
|
|
38
|
-
}
|
|
39
26
|
interface HookState {
|
|
40
27
|
enabled: boolean;
|
|
41
28
|
owners: number;
|
|
42
|
-
foldsTurns: boolean;
|
|
43
|
-
closeRuns(): void;
|
|
44
29
|
redraw(collapse?: boolean): void;
|
|
45
30
|
restore(): void;
|
|
46
|
-
installContainer(prototype: ContainerPrototype): void;
|
|
47
31
|
}
|
|
48
32
|
export interface MinimalOutputHook {
|
|
49
33
|
setEnabled(enabled: boolean): void;
|
|
50
34
|
dispose(): void;
|
|
51
|
-
readonly foldsTurns: boolean;
|
|
52
|
-
}
|
|
53
|
-
interface FoldSummary {
|
|
54
|
-
render(width: number): string[];
|
|
55
|
-
invalidate(): void;
|
|
56
|
-
handleMouse(event: { type?: string; button?: string }): { handled: true } | undefined;
|
|
57
|
-
setTools(tools: ToolComponent[]): void;
|
|
58
35
|
}
|
|
59
36
|
|
|
60
37
|
const HOOK = Symbol.for("pi-better-harness.minimal-output-hook");
|
|
61
|
-
const CHAT = Symbol.for("pi-better-harness.minimal-output-chat");
|
|
62
|
-
const ADD = Symbol.for("pi-better-harness.minimal-output-add-child");
|
|
63
38
|
const emptyResult = () => ({ render: () => [] as string[], invalidate() {} });
|
|
64
39
|
|
|
65
40
|
function hostRequire(): NodeRequire {
|
|
@@ -74,32 +49,26 @@ function hostRequire(): NodeRequire {
|
|
|
74
49
|
return require;
|
|
75
50
|
}
|
|
76
51
|
|
|
52
|
+
/** Bundled CLI classes are distinct from the SDK's unbundled deep imports. */
|
|
53
|
+
function bundledHostEntry(entry: string): string | undefined {
|
|
54
|
+
if (!process.argv[1]) return undefined;
|
|
55
|
+
try {
|
|
56
|
+
const directory = dirname(realpathSync(process.argv[1]));
|
|
57
|
+
if (directory === join(dirname(entry), "bundle")) return join(directory, "index.js");
|
|
58
|
+
} catch { /* An embedded host may not have a filesystem launcher. */ }
|
|
59
|
+
return undefined;
|
|
60
|
+
}
|
|
61
|
+
|
|
77
62
|
/** Resolve the running host's SDK, not a second SDK bundled beside the extension. */
|
|
78
63
|
export async function loadToolPrototype(): Promise<ToolPrototype> {
|
|
79
64
|
const entry = sdkEntry(hostRequire());
|
|
80
|
-
const
|
|
65
|
+
const bundle = bundledHostEntry(entry);
|
|
66
|
+
const path = bundle ?? join(dirname(entry), "modes/interactive/components/tool-execution.js");
|
|
81
67
|
const module = await import(pathToFileURL(path).href);
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
/** Chat rows are Container children. Patch that host class, not a second copy. */
|
|
86
|
-
export async function loadContainerPrototype(): Promise<ContainerPrototype> {
|
|
87
|
-
const entry = sdkEntry(hostRequire());
|
|
88
|
-
const tuiPath = createRequire(entry).resolve("@earendil-works/pi-tui");
|
|
89
|
-
const tui = await import(pathToFileURL(tuiPath).href);
|
|
90
|
-
const prototype = tui.Container?.prototype;
|
|
91
|
-
if (typeof prototype?.addChild !== "function" || typeof prototype?.render !== "function") {
|
|
92
|
-
throw new Error("Pi's chat container API is incompatible: missing Container.addChild. Turn folding is unavailable.");
|
|
68
|
+
if (!module.ToolExecutionComponent?.prototype) {
|
|
69
|
+
throw new Error("Pi's runtime does not expose its tool display class. Normal output remains enabled.");
|
|
93
70
|
}
|
|
94
|
-
return prototype;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
export async function loadMutedText(): Promise<(text: string) => string> {
|
|
98
|
-
const entry = sdkEntry(hostRequire());
|
|
99
|
-
const theme = await import(pathToFileURL(join(dirname(entry), "modes/interactive/theme/theme.js")).href);
|
|
100
|
-
return (text) => {
|
|
101
|
-
try { return theme.theme.fg("muted", text); } catch { return text; }
|
|
102
|
-
};
|
|
71
|
+
return module.ToolExecutionComponent.prototype;
|
|
103
72
|
}
|
|
104
73
|
|
|
105
74
|
// Pi's ESM-only export cannot be resolved with require.resolve on older SDKs.
|
|
@@ -115,38 +84,9 @@ function sdkEntry(require: ReturnType<typeof createRequire>): string {
|
|
|
115
84
|
throw new Error("Could not locate the running Pi SDK. Normal output remains enabled.");
|
|
116
85
|
}
|
|
117
86
|
|
|
118
|
-
function hasModelText(component: unknown): boolean {
|
|
119
|
-
const content = (component as { lastMessage?: { content?: unknown } } | null)?.lastMessage?.content;
|
|
120
|
-
if (!Array.isArray(content)) return false;
|
|
121
|
-
return content.some((block) => block?.type === "text" && typeof block.text === "string" && block.text.trim().length > 0);
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
function formatRun(tools: ToolComponent[], open: boolean): string {
|
|
125
|
-
const counts = new Map<string, number>();
|
|
126
|
-
let errors = 0;
|
|
127
|
-
for (const tool of tools) {
|
|
128
|
-
const name = tool.toolName || "tool";
|
|
129
|
-
counts.set(name, (counts.get(name) ?? 0) + 1);
|
|
130
|
-
if (tool.result?.isError) errors += 1;
|
|
131
|
-
}
|
|
132
|
-
const names = [...counts].map(([name, count]) => count > 1 ? `${name} ×${count}` : name);
|
|
133
|
-
const noun = tools.length === 1 ? "tool" : "tools";
|
|
134
|
-
const error = errors === 0 ? "" : errors === 1 ? " · 1 error" : ` · ${errors} errors`;
|
|
135
|
-
return `${open ? "▾" : "▸"} ${tools.length} ${noun}${error} · ${names.join(", ")}`;
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
function clip(text: string, width: number): string {
|
|
139
|
-
if (width <= 0 || text.length <= width) return text;
|
|
140
|
-
return width === 1 ? "…" : `${text.slice(0, width - 1)}…`;
|
|
141
|
-
}
|
|
142
|
-
|
|
143
87
|
/** Internal TUI adapter: no tools are replaced and no result content is changed. */
|
|
144
|
-
export function installMinimalOutputHook(
|
|
145
|
-
|
|
146
|
-
containerPrototype?: ContainerPrototype,
|
|
147
|
-
muted: (text: string) => string = (text) => text,
|
|
148
|
-
): MinimalOutputHook {
|
|
149
|
-
for (const name of ["updateDisplay", "getResultRenderer", "getTextOutput", "setExpanded", "invalidate"] as const) {
|
|
88
|
+
export function installMinimalOutputHook(prototype: ToolPrototype): MinimalOutputHook {
|
|
89
|
+
for (const name of ["updateDisplay", "getResultRenderer", "getTextOutput", "setExpanded", "invalidate", "render"] as const) {
|
|
150
90
|
if (typeof prototype[name] !== "function") {
|
|
151
91
|
throw new Error(`Pi's tool display API is incompatible: missing ${name}. Normal output remains enabled.`);
|
|
152
92
|
}
|
|
@@ -157,158 +97,35 @@ export function installMinimalOutputHook(
|
|
|
157
97
|
updateDisplay: prototype.updateDisplay,
|
|
158
98
|
getResultRenderer: prototype.getResultRenderer,
|
|
159
99
|
getTextOutput: prototype.getTextOutput,
|
|
100
|
+
render: prototype.render,
|
|
160
101
|
};
|
|
161
102
|
const seen = new WeakSet<ToolComponent>();
|
|
162
103
|
const components = new Set<WeakRef<ToolComponent>>();
|
|
163
|
-
const chats = new Set<WeakRef<ChatContainer>>();
|
|
164
|
-
const summaries = new WeakMap<ToolComponent, FoldSummary>();
|
|
165
|
-
const openedAt = new WeakMap<ToolComponent, number>();
|
|
166
|
-
let generation = 0;
|
|
167
|
-
let containerHooked = false;
|
|
168
|
-
let installedContainer: ContainerPrototype | undefined;
|
|
169
|
-
const isOpen = (tool: ToolComponent) => openedAt.get(tool) === generation;
|
|
170
|
-
const laterModelText = (children: unknown[], index: number) => {
|
|
171
|
-
for (let i = index; i < children.length; i++) {
|
|
172
|
-
if (hasModelText(children[i])) return true;
|
|
173
|
-
}
|
|
174
|
-
return false;
|
|
175
|
-
};
|
|
176
|
-
const attachFromTool = (tool: ToolComponent) => {
|
|
177
|
-
for (const child of tool.ui?.children ?? []) {
|
|
178
|
-
if (child?.children?.includes(tool)) wrapChat(child);
|
|
179
|
-
}
|
|
180
|
-
};
|
|
181
|
-
const wrapChat = (container: ChatContainer) => {
|
|
182
|
-
if (!container || seen.has(container as unknown as ToolComponent) || container[CHAT] || typeof container.render !== "function") return;
|
|
183
|
-
const original = container.render;
|
|
184
|
-
const wrapper = function (this: ChatContainer, width: number) {
|
|
185
|
-
if (!current.enabled || !Array.isArray(this.children) || !needsFold(this.children)) return original.call(this, width);
|
|
186
|
-
const lines: string[] = [];
|
|
187
|
-
const mouseChildren: Array<{ component: unknown; height: number }> = [];
|
|
188
|
-
const push = (component: { render(width: number): string[] }) => {
|
|
189
|
-
const childLines = component.render(width) ?? [];
|
|
190
|
-
mouseChildren.push({ component, height: childLines.length });
|
|
191
|
-
lines.push(...childLines);
|
|
192
|
-
};
|
|
193
|
-
let index = 0;
|
|
194
|
-
while (index < this.children.length) {
|
|
195
|
-
const child = this.children[index];
|
|
196
|
-
if (!seen.has(child as ToolComponent)) {
|
|
197
|
-
push(child as { render(width: number): string[] });
|
|
198
|
-
index += 1;
|
|
199
|
-
continue;
|
|
200
|
-
}
|
|
201
|
-
let end = index;
|
|
202
|
-
while (end < this.children.length && seen.has(this.children[end] as ToolComponent)) end += 1;
|
|
203
|
-
const tools = this.children.slice(index, end) as ToolComponent[];
|
|
204
|
-
const closed = laterModelText(this.children, end) && tools.every((tool) => !tool.expanded);
|
|
205
|
-
if (!closed) {
|
|
206
|
-
for (const tool of tools) push(tool);
|
|
207
|
-
} else {
|
|
208
|
-
const open = isOpen(tools[0]!);
|
|
209
|
-
let summary = summaries.get(tools[0]!);
|
|
210
|
-
if (!summary) {
|
|
211
|
-
summary = createSummary(tools[0]!);
|
|
212
|
-
summaries.set(tools[0]!, summary);
|
|
213
|
-
}
|
|
214
|
-
summary.setTools(tools);
|
|
215
|
-
push(summary);
|
|
216
|
-
if (open) for (const tool of tools) push(tool);
|
|
217
|
-
}
|
|
218
|
-
index = end;
|
|
219
|
-
}
|
|
220
|
-
this.mouseLayout = { width, children: mouseChildren };
|
|
221
|
-
return lines;
|
|
222
|
-
};
|
|
223
|
-
container[CHAT] = { original, wrapper };
|
|
224
|
-
container.render = wrapper;
|
|
225
|
-
chats.add(new WeakRef(container));
|
|
226
|
-
};
|
|
227
|
-
const createSummary = (anchor: ToolComponent): FoldSummary => {
|
|
228
|
-
let tools = [anchor];
|
|
229
|
-
return {
|
|
230
|
-
setTools(next) { tools = next; },
|
|
231
|
-
invalidate() {},
|
|
232
|
-
render(width) {
|
|
233
|
-
return ["", muted(clip(formatRun(tools, isOpen(anchor)), width))];
|
|
234
|
-
},
|
|
235
|
-
handleMouse(event) {
|
|
236
|
-
if (event.type !== "click" || (event.button && event.button !== "left")) return undefined;
|
|
237
|
-
if (isOpen(anchor)) openedAt.delete(anchor);
|
|
238
|
-
else openedAt.set(anchor, generation);
|
|
239
|
-
anchor.ui.requestRender();
|
|
240
|
-
return { handled: true };
|
|
241
|
-
},
|
|
242
|
-
};
|
|
243
|
-
};
|
|
244
|
-
const needsFold = (children: unknown[]) => {
|
|
245
|
-
let index = 0;
|
|
246
|
-
while (index < children.length) {
|
|
247
|
-
if (!seen.has(children[index] as ToolComponent)) { index += 1; continue; }
|
|
248
|
-
let end = index;
|
|
249
|
-
while (end < children.length && seen.has(children[end] as ToolComponent)) end += 1;
|
|
250
|
-
const tools = children.slice(index, end) as ToolComponent[];
|
|
251
|
-
if (laterModelText(children, end) && tools.every((tool) => !tool.expanded)) return true;
|
|
252
|
-
index = end;
|
|
253
|
-
}
|
|
254
|
-
return false;
|
|
255
|
-
};
|
|
256
104
|
state = {
|
|
257
105
|
enabled: false,
|
|
258
106
|
owners: 0,
|
|
259
|
-
foldsTurns: false,
|
|
260
|
-
closeRuns() { generation += 1; },
|
|
261
107
|
redraw(collapse = false) {
|
|
262
108
|
for (const reference of components) {
|
|
263
109
|
const component = reference.deref();
|
|
264
110
|
if (!component) { components.delete(reference); continue; }
|
|
265
111
|
if (collapse) component.setExpanded(false);
|
|
266
112
|
else component.invalidate();
|
|
267
|
-
attachFromTool(component);
|
|
268
113
|
component.ui.requestRender();
|
|
269
114
|
}
|
|
270
115
|
},
|
|
271
|
-
installContainer(next) {
|
|
272
|
-
if (containerHooked) return;
|
|
273
|
-
if (typeof next.addChild !== "function") {
|
|
274
|
-
throw new Error("Pi's chat container API is incompatible: missing Container.addChild. Turn folding is unavailable.");
|
|
275
|
-
}
|
|
276
|
-
const original = next[ADD]?.original ?? next.addChild;
|
|
277
|
-
const wrapper: ContainerPrototype["addChild"] = function (this: ChatContainer, child, ...rest) {
|
|
278
|
-
const result = original.call(this, child, ...rest);
|
|
279
|
-
if (seen.has(child as ToolComponent)) wrapChat(this);
|
|
280
|
-
return result;
|
|
281
|
-
};
|
|
282
|
-
next.addChild = wrapper;
|
|
283
|
-
next[ADD] = { original, wrapper };
|
|
284
|
-
containerHooked = true;
|
|
285
|
-
installedContainer = next;
|
|
286
|
-
state!.foldsTurns = true;
|
|
287
|
-
},
|
|
288
116
|
restore() {
|
|
289
117
|
for (const name of Object.keys(originals) as Array<keyof typeof originals>) {
|
|
290
118
|
// Do not remove another extension's subsequently installed wrapper.
|
|
291
|
-
if (prototype[name] === wrappers[name]) prototype[name]
|
|
119
|
+
if (prototype[name] === wrappers[name]) Object.assign(prototype, { [name]: originals[name] });
|
|
292
120
|
}
|
|
293
121
|
delete prototype[HOOK];
|
|
294
122
|
components.clear();
|
|
295
|
-
if (installedContainer && installedContainer[ADD]?.wrapper === installedContainer.addChild) {
|
|
296
|
-
installedContainer.addChild = installedContainer[ADD].original;
|
|
297
|
-
delete installedContainer[ADD];
|
|
298
|
-
}
|
|
299
|
-
for (const reference of chats) {
|
|
300
|
-
const container = reference.deref();
|
|
301
|
-
if (container?.[CHAT] && container.render === container[CHAT].wrapper) container.render = container[CHAT].original;
|
|
302
|
-
if (container) delete container[CHAT];
|
|
303
|
-
}
|
|
304
|
-
chats.clear();
|
|
305
123
|
},
|
|
306
124
|
};
|
|
307
125
|
const current = state;
|
|
308
126
|
const wrappers = {
|
|
309
127
|
updateDisplay(this: ToolComponent, ...args: unknown[]) {
|
|
310
128
|
if (!seen.has(this)) { seen.add(this); components.add(new WeakRef(this)); }
|
|
311
|
-
attachFromTool(this);
|
|
312
129
|
if (!current.enabled || this.expanded) return originals.updateDisplay.apply(this, args);
|
|
313
130
|
const showImages = this.showImages;
|
|
314
131
|
const lastRenderer = this.resultRendererComponent;
|
|
@@ -327,20 +144,20 @@ export function installMinimalOutputHook(
|
|
|
327
144
|
getTextOutput(this: ToolComponent, ...args: unknown[]) {
|
|
328
145
|
return current.enabled && !this.expanded ? "" : originals.getTextOutput.apply(this, args);
|
|
329
146
|
},
|
|
147
|
+
render(this: ToolComponent, width: number): string[] {
|
|
148
|
+
return current.enabled && !this.expanded ? [] : originals.render.call(this, width);
|
|
149
|
+
},
|
|
330
150
|
};
|
|
331
151
|
Object.assign(prototype, wrappers);
|
|
332
152
|
prototype[HOOK] = state;
|
|
333
153
|
}
|
|
334
154
|
const current = state;
|
|
335
|
-
if (containerPrototype) current.installContainer(containerPrototype);
|
|
336
155
|
current.owners += 1;
|
|
337
156
|
let disposed = false;
|
|
338
157
|
return {
|
|
339
|
-
foldsTurns: current.foldsTurns,
|
|
340
158
|
setEnabled(enabled) {
|
|
341
159
|
if (disposed) return;
|
|
342
160
|
current.enabled = enabled;
|
|
343
|
-
if (enabled) current.closeRuns();
|
|
344
161
|
current.redraw(enabled);
|
|
345
162
|
},
|
|
346
163
|
dispose() {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
2
|
-
import { installMinimalOutputHook,
|
|
2
|
+
import { installMinimalOutputHook, loadToolPrototype, type MinimalOutputHook } from "./hook.ts";
|
|
3
3
|
|
|
4
4
|
const ENTRY = "pi-better-harness-tool-output";
|
|
5
5
|
|
|
@@ -24,12 +24,7 @@ export default function minimalOutputExtension(pi: ExtensionAPI): void {
|
|
|
24
24
|
}
|
|
25
25
|
if (hook) return true;
|
|
26
26
|
try {
|
|
27
|
-
|
|
28
|
-
loadToolPrototype(),
|
|
29
|
-
loadContainerPrototype().catch(() => undefined),
|
|
30
|
-
loadMutedText().catch(() => undefined),
|
|
31
|
-
]);
|
|
32
|
-
hook = installMinimalOutputHook(toolPrototype, containerPrototype, muted);
|
|
27
|
+
hook = installMinimalOutputHook(await loadToolPrototype());
|
|
33
28
|
return true;
|
|
34
29
|
} catch (error) {
|
|
35
30
|
ctx.ui.notify(`Minimal tool output is unavailable: ${error instanceof Error ? error.message : String(error)}`, "warning");
|
|
@@ -61,11 +56,11 @@ export default function minimalOutputExtension(pi: ExtensionAPI): void {
|
|
|
61
56
|
});
|
|
62
57
|
|
|
63
58
|
pi.registerCommand("tool-output", {
|
|
64
|
-
description: "[minimal|normal] —
|
|
59
|
+
description: "[minimal|normal] — Hide tool blocks entirely, or restore normal output. No argument toggles. Display only.",
|
|
65
60
|
getArgumentCompletions: (argumentPrefix) => {
|
|
66
61
|
const prefix = argumentPrefix.trimStart().toLowerCase();
|
|
67
62
|
const matches = [
|
|
68
|
-
{ value: "minimal", label: "minimal", description: "
|
|
63
|
+
{ value: "minimal", label: "minimal", description: "Hide all tool blocks, including running tools" },
|
|
69
64
|
{ value: "normal", label: "normal", description: "Restore ordinary tool output" },
|
|
70
65
|
].filter((option) => option.value.startsWith(prefix));
|
|
71
66
|
return matches.length > 0 ? matches : null;
|
|
@@ -83,9 +78,7 @@ export default function minimalOutputExtension(pi: ExtensionAPI): void {
|
|
|
83
78
|
pi.appendEntry(ENTRY, { version: 1, enabled });
|
|
84
79
|
status(ctx);
|
|
85
80
|
ctx.ui.notify(enabled
|
|
86
|
-
?
|
|
87
|
-
? "Minimal tool output on. Finished tool runs fold after the next model text. Ctrl+O reveals them; click a folded run when the terminal supports it."
|
|
88
|
-
: "Minimal tool output on, but turn folding is unavailable in this Pi version. Ctrl+O reveals results."
|
|
81
|
+
? "Minimal tool output on. Tool blocks are hidden. Ctrl+O reveals them."
|
|
89
82
|
: "Normal tool output restored.", "info");
|
|
90
83
|
},
|
|
91
84
|
});
|
package/package.json
CHANGED