Skip to content

Commit 0d86d57

Browse files
Merge PR matt1398#168: fix renderer memory leak from unbounded expansion state
Integrates psypeal/claude-devtools#168 into fork with conflict resolution: - ipcChannels.ts: kept both PR's session:refresh and upstream's search API channels - linkedTool/index.ts: added BashToolViewer export from PR - sessionDetailSlice.ts: merged PR's expansion state clearing with upstream's slimDetail optimization Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2 parents 34b0aad + 106665c commit 0d86d57

10 files changed

Lines changed: 560 additions & 7 deletions

File tree

src/renderer/components/chat/items/LinkedToolItem.tsx

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import {
1414
getToolContextTokens,
1515
getToolStatus,
1616
getToolSummary,
17+
hasBashContent,
1718
hasEditContent,
1819
hasReadContent,
1920
hasSkillInstructions,
@@ -31,6 +32,7 @@ import { Wrench } from 'lucide-react';
3132
import { BaseItem, StatusDot } from './BaseItem';
3233
import { formatDuration } from './baseItemHelpers';
3334
import {
35+
BashToolViewer,
3436
DefaultToolViewer,
3537
EditToolViewer,
3638
ReadToolViewer,
@@ -39,6 +41,7 @@ import {
3941
WriteToolViewer,
4042
} from './linkedTool';
4143

44+
import type { StepVariant } from '@renderer/constants/stepVariants';
4245
import type { LinkedToolItem as LinkedToolItemType } from '@renderer/types/groups';
4346

4447
interface LinkedToolItemProps {
@@ -139,7 +142,12 @@ export const LinkedToolItem: React.FC<LinkedToolItemProps> = React.memo(function
139142
const useWriteViewer =
140143
linkedTool.name === 'Write' && hasWriteContent(linkedTool) && !linkedTool.result?.isError;
141144
const useSkillViewer = linkedTool.name === 'Skill' && hasSkillInstructions(linkedTool);
142-
const useDefaultViewer = !useReadViewer && !useEditViewer && !useWriteViewer && !useSkillViewer;
145+
const useBashViewer = linkedTool.name === 'Bash' && hasBashContent(linkedTool);
146+
const useDefaultViewer =
147+
!useReadViewer && !useEditViewer && !useWriteViewer && !useSkillViewer && !useBashViewer;
148+
149+
// Determine step variant for colored borders/icons
150+
const toolVariant: StepVariant = status === 'error' ? 'tool-error' : 'tool';
143151

144152
// Check if we should show error display for Read/Write tools
145153
const showReadError = linkedTool.name === 'Read' && linkedTool.result?.isError;
@@ -164,6 +172,7 @@ export const LinkedToolItem: React.FC<LinkedToolItemProps> = React.memo(function
164172
highlightClasses={highlightClasses}
165173
highlightStyle={highlightStyle}
166174
notificationDotColor={notificationDotColor}
175+
variant={toolVariant}
167176
>
168177
{/* Read tool with CodeBlockViewer */}
169178
{useReadViewer && <ReadToolViewer linkedTool={linkedTool} />}
@@ -177,6 +186,9 @@ export const LinkedToolItem: React.FC<LinkedToolItemProps> = React.memo(function
177186
{/* Skill tool with instructions */}
178187
{useSkillViewer && <SkillToolViewer linkedTool={linkedTool} />}
179188

189+
{/* Bash tool with syntax-highlighted command */}
190+
{useBashViewer && <BashToolViewer linkedTool={linkedTool} status={status} />}
191+
180192
{/* Default rendering for other tools */}
181193
{useDefaultViewer && <DefaultToolViewer linkedTool={linkedTool} status={status} />}
182194

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/**
2+
* BashToolViewer
3+
*
4+
* Renders Bash tool calls with syntax-highlighted command input
5+
* via CodeBlockViewer and collapsible output section.
6+
*/
7+
8+
import React from 'react';
9+
10+
import { CodeBlockViewer } from '@renderer/components/chat/viewers';
11+
12+
import { type ItemStatus } from '../BaseItem';
13+
14+
import { CollapsibleOutputSection } from './CollapsibleOutputSection';
15+
import { renderOutput } from './renderHelpers';
16+
17+
import type { LinkedToolItem } from '@renderer/types/groups';
18+
19+
interface BashToolViewerProps {
20+
linkedTool: LinkedToolItem;
21+
status: ItemStatus;
22+
}
23+
24+
export const BashToolViewer: React.FC<BashToolViewerProps> = ({ linkedTool, status }) => {
25+
const command = linkedTool.input.command as string;
26+
const description = linkedTool.input.description as string | undefined;
27+
28+
// Use the description (truncated) as the file name label, or fallback to "bash"
29+
const fileName = description
30+
? description.length > 60
31+
? description.slice(0, 57) + '...'
32+
: description
33+
: 'bash';
34+
35+
return (
36+
<>
37+
{/* Input Section — Syntax-highlighted command */}
38+
<CodeBlockViewer
39+
fileName={fileName}
40+
content={command}
41+
language="bash"
42+
/>
43+
44+
{/* Output Section — Collapsible */}
45+
{!linkedTool.isOrphaned && linkedTool.result && (
46+
<CollapsibleOutputSection status={status}>
47+
{renderOutput(linkedTool.result.content)}
48+
</CollapsibleOutputSection>
49+
)}
50+
</>
51+
);
52+
};

src/renderer/components/chat/items/linkedTool/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
* Exports all specialized tool viewer components.
55
*/
66

7+
export { BashToolViewer } from './BashToolViewer';
78
export { CollapsibleOutputSection } from './CollapsibleOutputSection';
89
export { DefaultToolViewer } from './DefaultToolViewer';
910
export { EditToolViewer } from './EditToolViewer';

0 commit comments

Comments
 (0)