pi-better-harness 0.26.0 → 0.26.1
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
|
@@ -76,7 +76,10 @@ stays quieter than conversation text. Tool rows are indented two columns past
|
|
|
76
76
|
the assistant text padding. Long
|
|
77
77
|
headers are truncated to the terminal width; result bodies,
|
|
78
78
|
images, boxes, and tool spacers are hidden. Built-in, extension, and MCP calls
|
|
79
|
-
are included.
|
|
79
|
+
are included. Tools without a custom call renderer use a generic icon and a
|
|
80
|
+
compact argument hint. Compaction summaries also collapse to one quiet row with
|
|
81
|
+
the pre-compaction token count; Ctrl+O reveals their original summary.
|
|
82
|
+
Execution, sandboxing, and agent-facing payloads are unchanged.
|
|
80
83
|
When a foreground run ends, each consecutive block of tool calls folds further
|
|
81
84
|
into one disclosure row showing the call count and any failures. Only the failure
|
|
82
85
|
count uses the error color; the disclosure and total stay muted. Assistant text
|
|
@@ -34,6 +34,14 @@ interface TranscriptComponent extends Component {
|
|
|
34
34
|
lastMessage?: { content: { type: string; text?: string; thinking?: string }[]; stopReason?: string };
|
|
35
35
|
}
|
|
36
36
|
interface ToolGroup { members: ToolComponent[]; open: boolean; expanded: number }
|
|
37
|
+
interface CompactionComponent extends Component {
|
|
38
|
+
expanded: boolean;
|
|
39
|
+
message: { tokensBefore: number };
|
|
40
|
+
setExpanded(expanded: boolean): void;
|
|
41
|
+
}
|
|
42
|
+
interface CompactionPrototype {
|
|
43
|
+
render: CompactionComponent["render"];
|
|
44
|
+
}
|
|
37
45
|
|
|
38
46
|
type Method = (this: ToolComponent, ...args: unknown[]) => unknown;
|
|
39
47
|
interface ToolMouseEvent { type: string; button: string; x: number; y: number; screenX: number; screenY: number; width: number; shift?: boolean; alt?: boolean; ctrl?: boolean }
|
|
@@ -129,7 +137,7 @@ function harnessCallDetail(name: string, input: unknown): string | undefined {
|
|
|
129
137
|
function compactCall(component: ToolComponent, width: number, theme?: Theme, indent = 3): string[] {
|
|
130
138
|
if (width <= 0) return [];
|
|
131
139
|
// Render the call alone at a wider width so terminal wrapping becomes truncation.
|
|
132
|
-
const header = component.callRendererComponent?.render(Math.max(4096, width + 1))
|
|
140
|
+
const header = Boolean(component.getCallRenderer?.()) && component.callRendererComponent?.render(Math.max(4096, width + 1))
|
|
133
141
|
.map((line) => stripVTControlCharacters(line).trim())
|
|
134
142
|
.find((line) => line.length > 0);
|
|
135
143
|
let text = header;
|
|
@@ -211,6 +219,16 @@ export async function loadToolPrototype(): Promise<ToolPrototype> {
|
|
|
211
219
|
return module.ToolExecutionComponent.prototype;
|
|
212
220
|
}
|
|
213
221
|
|
|
222
|
+
export async function loadCompactionPrototype(): Promise<CompactionPrototype> {
|
|
223
|
+
const entry = sdkEntry(hostRequire());
|
|
224
|
+
const path = bundledHostEntry(entry) ?? join(dirname(entry), "modes/interactive/components/compaction-summary-message.js");
|
|
225
|
+
const module = await import(pathToFileURL(path).href);
|
|
226
|
+
if (!module.CompactionSummaryMessageComponent?.prototype) {
|
|
227
|
+
throw new Error("Pi's runtime does not expose its compaction display class.");
|
|
228
|
+
}
|
|
229
|
+
return module.CompactionSummaryMessageComponent.prototype;
|
|
230
|
+
}
|
|
231
|
+
|
|
214
232
|
// Pi's ESM-only export cannot be resolved with require.resolve on older SDKs.
|
|
215
233
|
function sdkEntry(require: ReturnType<typeof createRequire>): string {
|
|
216
234
|
for (const directory of require.resolve.paths("@earendil-works/pi-coding-agent") ?? []) {
|
|
@@ -225,7 +243,7 @@ function sdkEntry(require: ReturnType<typeof createRequire>): string {
|
|
|
225
243
|
}
|
|
226
244
|
|
|
227
245
|
/** Internal TUI adapter: no tools are replaced and no result content is changed. */
|
|
228
|
-
export function installMinimalOutputHook(prototype: ToolPrototype, getTheme?: () => Theme): MinimalOutputHook {
|
|
246
|
+
export function installMinimalOutputHook(prototype: ToolPrototype, getTheme?: () => Theme, compactionPrototype?: CompactionPrototype): MinimalOutputHook {
|
|
229
247
|
for (const name of ["updateDisplay", "getResultRenderer", "getTextOutput", "setExpanded", "invalidate", "render"] as const) {
|
|
230
248
|
if (typeof prototype[name] !== "function") {
|
|
231
249
|
throw new Error(`Pi's tool display API is incompatible: missing ${name}. Normal output remains enabled.`);
|
|
@@ -359,6 +377,38 @@ export function installMinimalOutputHook(prototype: ToolPrototype, getTheme?: ()
|
|
|
359
377
|
},
|
|
360
378
|
};
|
|
361
379
|
const current = state;
|
|
380
|
+
const compactions = new Set<WeakRef<CompactionComponent>>();
|
|
381
|
+
const seenCompactions = new WeakSet<CompactionComponent>();
|
|
382
|
+
if (compactionPrototype) {
|
|
383
|
+
const originalRender = compactionPrototype.render;
|
|
384
|
+
const render = function(this: CompactionComponent, width: number): string[] {
|
|
385
|
+
if (!seenCompactions.has(this)) { seenCompactions.add(this); compactions.add(new WeakRef(this)); }
|
|
386
|
+
if (!current.enabled || this.expanded) return originalRender.call(this, width);
|
|
387
|
+
const detail = `from ${this.message.tokensBefore.toLocaleString()} tokens`;
|
|
388
|
+
const theme = getTheme?.();
|
|
389
|
+
const text = theme
|
|
390
|
+
? ` ${theme.fg("muted", "\u25c7")} ${theme.fg("muted", "Compaction")} ${theme.fg("dim", detail)}`
|
|
391
|
+
: ` \u25c7 Compaction ${detail}`;
|
|
392
|
+
return width > 0 ? [truncateToWidth(`${" ".repeat(Math.min(3, width - 1))}${text}`, width)] : [];
|
|
393
|
+
};
|
|
394
|
+
compactionPrototype.render = render;
|
|
395
|
+
const redraw = current.redraw;
|
|
396
|
+
current.redraw = function(collapse) {
|
|
397
|
+
for (const reference of compactions) {
|
|
398
|
+
const component = reference.deref();
|
|
399
|
+
if (!component) { compactions.delete(reference); continue; }
|
|
400
|
+
if (collapse) component.setExpanded(false);
|
|
401
|
+
else component.invalidate();
|
|
402
|
+
}
|
|
403
|
+
redraw.call(this, collapse);
|
|
404
|
+
};
|
|
405
|
+
const restore = current.restore;
|
|
406
|
+
current.restore = function() {
|
|
407
|
+
if (compactionPrototype.render === render) compactionPrototype.render = originalRender;
|
|
408
|
+
compactions.clear();
|
|
409
|
+
restore.call(this);
|
|
410
|
+
};
|
|
411
|
+
}
|
|
362
412
|
const wrappers = {
|
|
363
413
|
updateDisplay(this: ToolComponent, ...args: unknown[]) {
|
|
364
414
|
if (typeof this.ui.handleViewportInput === "function" && !inputWrappers.has(this.ui)) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
2
|
-
import { installMinimalOutputHook, loadToolPrototype, type MinimalOutputHook } from "./hook.ts";
|
|
2
|
+
import { installMinimalOutputHook, loadToolPrototype, loadCompactionPrototype, type MinimalOutputHook } from "./hook.ts";
|
|
3
3
|
import type { SettingsControl } from "../settings/registry.ts";
|
|
4
4
|
import { readHarnessSetting, updateHarnessSetting } from "../shared-harness-settings.ts";
|
|
5
5
|
|
|
@@ -37,7 +37,7 @@ export default function minimalOutputExtension(pi: ExtensionAPI): void {
|
|
|
37
37
|
}
|
|
38
38
|
if (hook) return true;
|
|
39
39
|
try {
|
|
40
|
-
hook = installMinimalOutputHook(await loadToolPrototype(), () => ctx.ui.theme);
|
|
40
|
+
hook = installMinimalOutputHook(await loadToolPrototype(), () => ctx.ui.theme, await loadCompactionPrototype());
|
|
41
41
|
return true;
|
|
42
42
|
} catch (error) {
|
|
43
43
|
ctx.ui.notify(`Minimal tool output is unavailable: ${error instanceof Error ? error.message : String(error)}`, "warning");
|
package/package.json
CHANGED