@@ -2,6 +2,10 @@
|
|||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Fixed final bash tool cards to avoid rendering duplicate full-output truncation paths ([#4819](https://github.com/earendil-works/pi/issues/4819)).
|
||||||
|
|
||||||
## [0.75.4] - 2026-05-20
|
## [0.75.4] - 2026-05-20
|
||||||
|
|
||||||
### New Features
|
### New Features
|
||||||
|
|||||||
@@ -200,7 +200,15 @@ function rebuildBashResultRenderComponent(
|
|||||||
const state = component.state;
|
const state = component.state;
|
||||||
component.clear();
|
component.clear();
|
||||||
|
|
||||||
const output = getTextOutput(result as any, showImages).trim();
|
let output = getTextOutput(result as any, showImages).trim();
|
||||||
|
const truncation = result.details?.truncation;
|
||||||
|
const fullOutputPath = result.details?.fullOutputPath;
|
||||||
|
if (!options.isPartial && truncation?.truncated && fullOutputPath && output.endsWith("]")) {
|
||||||
|
const footerStart = output.lastIndexOf("\n\n[");
|
||||||
|
if (footerStart !== -1 && output.slice(footerStart).includes(fullOutputPath)) {
|
||||||
|
output = output.slice(0, footerStart).trimEnd();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (output) {
|
if (output) {
|
||||||
const styledOutput = output
|
const styledOutput = output
|
||||||
@@ -236,8 +244,6 @@ function rebuildBashResultRenderComponent(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const truncation = result.details?.truncation;
|
|
||||||
const fullOutputPath = result.details?.fullOutputPath;
|
|
||||||
if (truncation?.truncated || fullOutputPath) {
|
if (truncation?.truncated || fullOutputPath) {
|
||||||
const warnings: string[] = [];
|
const warnings: string[] = [];
|
||||||
if (fullOutputPath) {
|
if (fullOutputPath) {
|
||||||
|
|||||||
@@ -123,6 +123,43 @@ describe("ToolExecutionComponent parity", () => {
|
|||||||
await promise;
|
await promise;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("bash renderer does not duplicate final full output truncation details", async () => {
|
||||||
|
const operations: BashOperations = {
|
||||||
|
exec: async (_command, _cwd, { onData }) => {
|
||||||
|
for (let i = 1; i <= 4000; i++) {
|
||||||
|
onData(Buffer.from(`line-${String(i).padStart(4, "0")}\n`));
|
||||||
|
}
|
||||||
|
return { exitCode: 0 };
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const tool = createBashToolDefinition(process.cwd(), { operations });
|
||||||
|
const result = await tool.execute(
|
||||||
|
"tool-bash-1b",
|
||||||
|
{ command: "generate output" },
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
{} as never,
|
||||||
|
);
|
||||||
|
const component = new ToolExecutionComponent(
|
||||||
|
"bash",
|
||||||
|
"tool-bash-1b",
|
||||||
|
{ command: "generate output" },
|
||||||
|
{},
|
||||||
|
tool,
|
||||||
|
createFakeTui(),
|
||||||
|
process.cwd(),
|
||||||
|
);
|
||||||
|
component.setExpanded(true);
|
||||||
|
component.updateResult({ ...result, isError: false }, false);
|
||||||
|
|
||||||
|
const rendered = stripAnsi(component.render(200).join("\n"));
|
||||||
|
expect(rendered.match(/Full output:/g)?.length ?? 0).toBe(1);
|
||||||
|
expect(rendered).toMatch(/line-4000[^\n]*\n[^\S\n]*\n \[Full output:/);
|
||||||
|
expect(rendered).not.toMatch(/line-4000[^\n]*\n[^\S\n]*\n[^\S\n]*\n \[Full output:/);
|
||||||
|
expect(rendered).toContain("Truncated: showing 2000 of 4001 lines");
|
||||||
|
expect(rendered).not.toContain("[Showing lines 2002-4001 of 4001. Full output:");
|
||||||
|
});
|
||||||
|
|
||||||
test("does not duplicate built-in headers when passed the active built-in definition", () => {
|
test("does not duplicate built-in headers when passed the active built-in definition", () => {
|
||||||
const component = new ToolExecutionComponent(
|
const component = new ToolExecutionComponent(
|
||||||
"read",
|
"read",
|
||||||
|
|||||||
Reference in New Issue
Block a user