diff --git a/packages/cli/src/ui/components/messages/DenseToolMessage.test.tsx b/packages/cli/src/ui/components/messages/DenseToolMessage.test.tsx
index 30879b13b3..586ce89ab2 100644
--- a/packages/cli/src/ui/components/messages/DenseToolMessage.test.tsx
+++ b/packages/cli/src/ui/components/messages/DenseToolMessage.test.tsx
@@ -357,9 +357,8 @@ describe('DenseToolMessage', () => {
await waitUntilReady();
const output = lastFrame();
expect(output).toContain('→ Found 2 matches');
- // Matches are rendered in a secondary list for high-signal summaries
- expect(output).toContain('file1.ts:10: match 1');
- expect(output).toContain('file2.ts:20: match 2');
+ // Matches should no longer be rendered in dense mode to keep it compact
+ expect(output).not.toContain('file1.ts:10: match 1');
expect(output).toMatchSnapshot();
});
@@ -400,9 +399,8 @@ describe('DenseToolMessage', () => {
const output = lastFrame();
expect(output).toContain('Attempting to read files from **/*.ts');
expect(output).toContain('→ Read 3 file(s) (1 ignored)');
- expect(output).toContain('file1.ts');
- expect(output).toContain('file2.ts');
- expect(output).toContain('file3.ts');
+ // File lists should no longer be rendered in dense mode
+ expect(output).not.toContain('file1.ts');
expect(output).toMatchSnapshot();
});
@@ -477,6 +475,28 @@ describe('DenseToolMessage', () => {
expect(output).toMatchSnapshot();
});
+ it('truncates long description but preserves tool name (< 25 chars)', async () => {
+ const longDescription =
+ 'This is a very long description that should definitely be truncated because it exceeds the available terminal width and we want to see how it behaves.';
+ const toolName = 'tool-name-is-24-chars-!!'; // Exactly 24 chars
+ const { lastFrame, waitUntilReady } = await renderWithProviders(
+ ,
+ );
+ await waitUntilReady();
+ const output = lastFrame();
+
+ // Tool name should be fully present (it plus one space is exactly 25, fitting the maxWidth)
+ expect(output).toContain(toolName);
+ // Description should be present but truncated
+ expect(output).toContain('This is a');
+ expect(output).toMatchSnapshot();
+ });
+
describe('Toggleable Diff View (Alternate Buffer)', () => {
const diffResult: FileDiff = {
fileDiff: '@@ -1,1 +1,1 @@\n-old line\n+new line',
diff --git a/packages/cli/src/ui/components/messages/DenseToolMessage.tsx b/packages/cli/src/ui/components/messages/DenseToolMessage.tsx
index 6e81d07931..f5e4b31c66 100644
--- a/packages/cli/src/ui/components/messages/DenseToolMessage.tsx
+++ b/packages/cli/src/ui/components/messages/DenseToolMessage.tsx
@@ -72,27 +72,6 @@ const hasPayload = (res: unknown): res is PayloadResult => {
return typeof value === 'string';
};
-const RenderItemsList: React.FC<{
- items?: string[];
- maxVisible?: number;
-}> = ({ items, maxVisible = 20 }) => {
- if (!items || items.length === 0) return null;
- return (
-
- {items.slice(0, maxVisible).map((item, i) => (
-
- {item}
-
- ))}
- {items.length > maxVisible && (
-
- ... and {items.length - maxVisible} more
-
- )}
-
- );
-};
-
function getFileOpData(
diff: FileDiff,
status: CoreToolCallStatus,
@@ -188,8 +167,6 @@ function getFileOpData(
}
function getReadManyFilesData(result: ReadManyFilesResult): ViewParts {
- const items = result.files ?? [];
- const maxVisible = 10;
const includePatterns = result.include?.join(', ') ?? '';
const description = (
@@ -198,18 +175,12 @@ function getReadManyFilesData(result: ReadManyFilesResult): ViewParts {
);
const skippedCount = result.skipped?.length ?? 0;
- const summaryStr = `Read ${items.length} file(s)${
+ const summaryStr = `Read ${result.files.length} file(s)${
skippedCount > 0 ? ` (${skippedCount} ignored)` : ''
}`;
const summary = → {summaryStr};
- const hasItems = items.length > 0;
- const payload = hasItems ? (
-
- {hasItems && }
-
- ) : undefined;
- return { description, summary, payload };
+ return { description, summary, payload: undefined };
}
function getListDirectoryData(
@@ -258,20 +229,11 @@ function getGenericSuccessData(
);
} else if (isGrepResult(resultDisplay)) {
- summary = → {resultDisplay.summary};
- const matches = resultDisplay.matches;
- if (matches.length > 0) {
- payload = (
-
- `${m.filePath}:${m.lineNumber}: ${m.line.trim()}`,
- )}
- maxVisible={10}
- />
-
- );
- }
+ summary = (
+
+ → {resultDisplay.summary}
+
+ );
} else if (isTodoList(resultDisplay)) {
summary = (
@@ -488,15 +450,18 @@ export const DenseToolMessage: React.FC = (props) => {
return (
-
-
-
- {name}{' '}
-
-
-
- {description}
+
+
+
+
+ {name}{' '}
+
+
+
+ {description}
+
+
{summary && (
{
// TODO(24053): Usage of type guards makes this class too aware of internals
if (isFileDiff(res)) return true;
if (tool.confirmationDetails?.type === 'edit') return true;
- if (isGrepResult(res) && res.matches.length > 0) return true;
-
- // ReadManyFilesResult check (has 'include' and 'files')
- if (isListResult(res) && 'include' in res) {
- const includeProp = (res as { include?: unknown }).include;
- if (Array.isArray(includeProp) && res.files.length > 0) {
- return true;
- }
- }
// Generic summary/payload pattern
if (
diff --git a/packages/cli/src/ui/components/messages/__snapshots__/DenseToolMessage.test.tsx.snap b/packages/cli/src/ui/components/messages/__snapshots__/DenseToolMessage.test.tsx.snap
index d08b84c1a9..01bb88b00e 100644
--- a/packages/cli/src/ui/components/messages/__snapshots__/DenseToolMessage.test.tsx.snap
+++ b/packages/cli/src/ui/components/messages/__snapshots__/DenseToolMessage.test.tsx.snap
@@ -51,10 +51,6 @@ exports[`DenseToolMessage > renders correctly for Errored Edit tool 1`] = `
exports[`DenseToolMessage > renders correctly for ReadManyFiles results 1`] = `
" ✓ test-tool Attempting to read files from **/*.ts → Read 3 file(s) (1 ignored)
-
- file1.ts
- file2.ts
- file3.ts
"
`;
@@ -110,9 +106,6 @@ exports[`DenseToolMessage > renders correctly for file diff results with stats 1
exports[`DenseToolMessage > renders correctly for grep results 1`] = `
" ✓ test-tool Test description → Found 2 matches
-
- file1.ts:10: match 1
- file2.ts:20: match 2
"
`;
@@ -136,6 +129,12 @@ exports[`DenseToolMessage > renders generic output message for unknown object re
"
`;
+exports[`DenseToolMessage > truncates long description but preserves tool name (< 25 chars) 1`] = `
+" ✓ tool-name-is-24-chars-!! This is a very long description that should definitely be truncated …
+ → Success result
+"
+`;
+
exports[`DenseToolMessage > truncates long string results 1`] = `
" ✓ test-tool Test description
→ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA…
diff --git a/packages/core/src/tools/ls.test.ts b/packages/core/src/tools/ls.test.ts
index 372de8e8a6..e9a684719e 100644
--- a/packages/core/src/tools/ls.test.ts
+++ b/packages/core/src/tools/ls.test.ts
@@ -132,7 +132,7 @@ describe('LSTool', () => {
expect(result.llmContent).toContain('[DIR] subdir');
expect(result.llmContent).toContain('file1.txt');
expect(result.returnDisplay).toEqual({
- summary: 'Listed 2 item(s).',
+ summary: 'Found 2 item(s).',
files: ['[DIR] subdir', 'file1.txt'],
});
});
@@ -150,7 +150,7 @@ describe('LSTool', () => {
expect(result.llmContent).toContain('secondary-file.txt');
expect(result.returnDisplay).toEqual({
- summary: 'Listed 1 item(s).',
+ summary: 'Found 1 item(s).',
files: expect.any(Array),
});
});
@@ -178,7 +178,7 @@ describe('LSTool', () => {
expect(result.llmContent).toContain('file1.txt');
expect(result.llmContent).not.toContain('file2.log');
expect(result.returnDisplay).toEqual({
- summary: 'Listed 1 item(s).',
+ summary: 'Found 1 item(s).',
files: expect.any(Array),
});
});
@@ -195,7 +195,7 @@ describe('LSTool', () => {
expect(result.llmContent).not.toContain('file2.log');
// .git is always ignored by default.
expect(result.returnDisplay).toEqual(
- expect.objectContaining({ summary: 'Listed 2 item(s). (2 ignored)' }),
+ expect.objectContaining({ summary: 'Found 2 item(s). (2 ignored)' }),
);
});
@@ -212,7 +212,7 @@ describe('LSTool', () => {
expect(result.llmContent).toContain('file1.txt');
expect(result.llmContent).not.toContain('file2.log');
expect(result.returnDisplay).toEqual(
- expect.objectContaining({ summary: 'Listed 2 item(s). (1 ignored)' }),
+ expect.objectContaining({ summary: 'Found 2 item(s). (1 ignored)' }),
);
});
@@ -301,7 +301,7 @@ describe('LSTool', () => {
expect(result.llmContent).toContain('file1.txt');
expect(result.llmContent).not.toContain('problematic.txt');
expect(result.returnDisplay).toEqual({
- summary: 'Listed 1 item(s).',
+ summary: 'Found 1 item(s).',
files: expect.any(Array),
});
@@ -364,7 +364,7 @@ describe('LSTool', () => {
expect(result.llmContent).toContain('secondary-file.txt');
expect(result.returnDisplay).toEqual({
- summary: 'Listed 1 item(s).',
+ summary: 'Found 1 item(s).',
files: expect.any(Array),
});
});
diff --git a/packages/core/src/tools/ls.ts b/packages/core/src/tools/ls.ts
index b8e2e6a803..249a28372b 100644
--- a/packages/core/src/tools/ls.ts
+++ b/packages/core/src/tools/ls.ts
@@ -276,7 +276,7 @@ class LSToolInvocation extends BaseToolInvocation {
resultMessage = appendJitContext(resultMessage, jitContext);
}
- let displayMessage = `Listed ${entries.length} item(s).`;
+ let displayMessage = `Found ${entries.length} item(s).`;
if (ignoredCount > 0) {
displayMessage += ` (${ignoredCount} ignored)`;
}