From ad79b9bcabfafeed7a30f869065e406d45915846 Mon Sep 17 00:00:00 2001 From: yiliang114 <1204183885@qq.com> Date: Sat, 6 Dec 2025 21:45:51 +0800 Subject: [PATCH] refactor(vscode-ide-companion): restructure tool call components Restructure tool call components with dedicated container implementations - Move tool call components to done subdirectory - Implement specialized ToolCallContainer for each tool type - Update component routing in ToolCallRouter - Add isFirst/isLast props for better layout control - Improve shared types and layout components --- .../{ => done}/Edit/EditToolCall.tsx | 59 ++++++++++++++----- .../toolcalls/{ => done}/Execute/Execute.css | 2 +- .../toolcalls/{ => done}/Execute/Execute.tsx | 41 +++++++++++-- .../{ => done}/Read/ReadToolCall.tsx | 41 +++++++++++-- .../{ => done}/Search/SearchToolCall.tsx | 36 +++++++++-- .../webview/components/toolcalls/index.tsx | 14 +++-- .../toolcalls/shared/LayoutComponents.tsx | 2 +- .../components/toolcalls/shared/types.ts | 2 + .../components/toolcalls/shared/utils.ts | 8 ++- 9 files changed, 165 insertions(+), 40 deletions(-) rename packages/vscode-ide-companion/src/webview/components/toolcalls/{ => done}/Edit/EditToolCall.tsx (76%) rename packages/vscode-ide-companion/src/webview/components/toolcalls/{ => done}/Execute/Execute.css (99%) rename packages/vscode-ide-companion/src/webview/components/toolcalls/{ => done}/Execute/Execute.tsx (78%) rename packages/vscode-ide-companion/src/webview/components/toolcalls/{ => done}/Read/ReadToolCall.tsx (75%) rename packages/vscode-ide-companion/src/webview/components/toolcalls/{ => done}/Search/SearchToolCall.tsx (75%) diff --git a/packages/vscode-ide-companion/src/webview/components/toolcalls/Edit/EditToolCall.tsx b/packages/vscode-ide-companion/src/webview/components/toolcalls/done/Edit/EditToolCall.tsx similarity index 76% rename from packages/vscode-ide-companion/src/webview/components/toolcalls/Edit/EditToolCall.tsx rename to packages/vscode-ide-companion/src/webview/components/toolcalls/done/Edit/EditToolCall.tsx index 543bc745..14bb5503 100644 --- a/packages/vscode-ide-companion/src/webview/components/toolcalls/Edit/EditToolCall.tsx +++ b/packages/vscode-ide-companion/src/webview/components/toolcalls/done/Edit/EditToolCall.tsx @@ -7,15 +7,42 @@ */ import { useEffect, useCallback, useMemo } from 'react'; -import type { BaseToolCallProps } from '../shared/types.js'; -import { ToolCallContainer } from '../shared/LayoutComponents.js'; +import type { BaseToolCallProps } from '../../shared/types.js'; import { groupContent, mapToolStatusToContainerStatus, -} from '../shared/utils.js'; -import { useVSCode } from '../../../hooks/useVSCode.js'; -import { FileLink } from '../../ui/FileLink.js'; -import { handleOpenDiff } from '../../../utils/diffUtils.js'; +} from '../../shared/utils.js'; +import { FileLink } from '../../../ui/FileLink.js'; +import type { ToolCallContainerProps } from '../../shared/LayoutComponents.js'; +import { useVSCode } from '../../../../hooks/useVSCode.js'; +import { handleOpenDiff } from '../../../../utils/diffUtils.js'; + +export const ToolCallContainer: React.FC = ({ + label, + status = 'success', + children, + toolCallId: _toolCallId, + labelSuffix, + className: _className, +}) => ( +
+
+
+ + {label} + + + {labelSuffix} + +
+ {children && ( +
{children}
+ )} +
+
+); /** * Calculate diff summary (added/removed lines) @@ -58,9 +85,6 @@ export const EditToolCall: React.FC = ({ toolCall }) => { [vscode], ); - // Extract filename from path - const getFileName = (path: string): string => path.split('/').pop() || path; - // Automatically trigger openDiff when diff content is detected // Only trigger once per tool call by checking toolCallId useEffect(() => { @@ -88,10 +112,9 @@ export const EditToolCall: React.FC = ({ toolCall }) => { // Error case: show error if (errors.length > 0) { const path = diffs[0]?.path || locations?.[0]?.path || ''; - const fileName = path ? getFileName(path) : ''; return ( = ({ toolCall }) => { {/* IMPORTANT: Always include min-w-0/max-w-full on inner wrappers to prevent overflow. */}
-
+
{/* Align the inline Edit label styling with shared toolcall label: larger + bold */} Edit @@ -137,7 +160,7 @@ export const EditToolCall: React.FC = ({ toolCall }) => { )}
-
+
{summary}
@@ -148,13 +171,19 @@ export const EditToolCall: React.FC = ({ toolCall }) => { // Success case without diff: show file in compact format if (locations && locations.length > 0) { - const fileName = getFileName(locations[0].path); const containerStatus = mapToolStatusToContainerStatus(toolCall.status); return ( + } >
diff --git a/packages/vscode-ide-companion/src/webview/components/toolcalls/Execute/Execute.css b/packages/vscode-ide-companion/src/webview/components/toolcalls/done/Execute/Execute.css similarity index 99% rename from packages/vscode-ide-companion/src/webview/components/toolcalls/Execute/Execute.css rename to packages/vscode-ide-companion/src/webview/components/toolcalls/done/Execute/Execute.css index 891b5701..97a561c5 100644 --- a/packages/vscode-ide-companion/src/webview/components/toolcalls/Execute/Execute.css +++ b/packages/vscode-ide-companion/src/webview/components/toolcalls/done/Execute/Execute.css @@ -99,4 +99,4 @@ /* Error content styling */ .execute-toolcall-error-content { color: #c74e39; -} \ No newline at end of file +} diff --git a/packages/vscode-ide-companion/src/webview/components/toolcalls/Execute/Execute.tsx b/packages/vscode-ide-companion/src/webview/components/toolcalls/done/Execute/Execute.tsx similarity index 78% rename from packages/vscode-ide-companion/src/webview/components/toolcalls/Execute/Execute.tsx rename to packages/vscode-ide-companion/src/webview/components/toolcalls/done/Execute/Execute.tsx index 1bb0637b..64e02ca7 100644 --- a/packages/vscode-ide-companion/src/webview/components/toolcalls/Execute/Execute.tsx +++ b/packages/vscode-ide-companion/src/webview/components/toolcalls/done/Execute/Execute.tsx @@ -7,10 +7,37 @@ */ import type React from 'react'; -import type { BaseToolCallProps } from '../shared/types.js'; -import { ToolCallContainer } from '../shared/LayoutComponents.js'; -import { safeTitle, groupContent } from '../shared/utils.js'; +import type { BaseToolCallProps } from '../../shared/types.js'; +import { safeTitle, groupContent } from '../../shared/utils.js'; import './Execute.css'; +import type { ToolCallContainerProps } from '../../shared/LayoutComponents.js'; + +export const ToolCallContainer: React.FC = ({ + label, + status = 'success', + children, + toolCallId: _toolCallId, + labelSuffix, + className: _className, +}) => ( +
+
+
+ + {label} + + + {labelSuffix} + +
+ {children && ( +
{children}
+ )} +
+
+); /** * Specialized component for Execute tool calls @@ -18,7 +45,9 @@ import './Execute.css'; */ export const ExecuteToolCall: React.FC = ({ toolCall }) => { const { title, content, rawInput, toolCallId } = toolCall; - const commandText = safeTitle(title); + const commandText = safeTitle( + (rawInput as Record)?.description || title, + ); // Group content by type const { textOutputs, errors } = groupContent(content); @@ -26,8 +55,8 @@ export const ExecuteToolCall: React.FC = ({ toolCall }) => { // Extract command from rawInput if available let inputCommand = commandText; if (rawInput && typeof rawInput === 'object') { - const inputObj = rawInput as { command?: string }; - inputCommand = inputObj.command || commandText; + const inputObj = rawInput as Record; + inputCommand = (inputObj.command as string | undefined) || commandText; } else if (typeof rawInput === 'string') { inputCommand = rawInput; } diff --git a/packages/vscode-ide-companion/src/webview/components/toolcalls/Read/ReadToolCall.tsx b/packages/vscode-ide-companion/src/webview/components/toolcalls/done/Read/ReadToolCall.tsx similarity index 75% rename from packages/vscode-ide-companion/src/webview/components/toolcalls/Read/ReadToolCall.tsx rename to packages/vscode-ide-companion/src/webview/components/toolcalls/done/Read/ReadToolCall.tsx index 56a6aafd..b1344623 100644 --- a/packages/vscode-ide-companion/src/webview/components/toolcalls/Read/ReadToolCall.tsx +++ b/packages/vscode-ide-companion/src/webview/components/toolcalls/done/Read/ReadToolCall.tsx @@ -8,15 +8,44 @@ import type React from 'react'; import { useCallback, useEffect, useMemo } from 'react'; -import type { BaseToolCallProps } from '../shared/types.js'; -import { ToolCallContainer } from '../shared/LayoutComponents.js'; +import type { BaseToolCallProps } from '../../shared/types.js'; import { groupContent, mapToolStatusToContainerStatus, -} from '../shared/utils.js'; -import { FileLink } from '../../ui/FileLink.js'; -import { useVSCode } from '../../../hooks/useVSCode.js'; -import { handleOpenDiff } from '../../../utils/diffUtils.js'; +} from '../../shared/utils.js'; +import { FileLink } from '../../../ui/FileLink.js'; +import { useVSCode } from '../../../../hooks/useVSCode.js'; +import { handleOpenDiff } from '../../../../utils/diffUtils.js'; +import type { ToolCallContainerProps } from '../../shared/LayoutComponents.js'; + +export const ToolCallContainer: React.FC = ({ + label, + status = 'success', + children, + toolCallId: _toolCallId, + labelSuffix, + className: _className, +}) => ( +
+
+
+ + {label} + + + {labelSuffix} + +
+ {children && ( +
+ {children} +
+ )} +
+
+); /** * Specialized component for Read tool calls diff --git a/packages/vscode-ide-companion/src/webview/components/toolcalls/Search/SearchToolCall.tsx b/packages/vscode-ide-companion/src/webview/components/toolcalls/done/Search/SearchToolCall.tsx similarity index 75% rename from packages/vscode-ide-companion/src/webview/components/toolcalls/Search/SearchToolCall.tsx rename to packages/vscode-ide-companion/src/webview/components/toolcalls/done/Search/SearchToolCall.tsx index b9fe6f35..2440127b 100644 --- a/packages/vscode-ide-companion/src/webview/components/toolcalls/Search/SearchToolCall.tsx +++ b/packages/vscode-ide-companion/src/webview/components/toolcalls/done/Search/SearchToolCall.tsx @@ -7,18 +7,46 @@ */ import type React from 'react'; -import type { BaseToolCallProps } from '../shared/types.js'; +import type { BaseToolCallProps } from '../../shared/types.js'; import { - ToolCallContainer, ToolCallCard, ToolCallRow, LocationsList, -} from '../shared/LayoutComponents.js'; +} from '../../shared/LayoutComponents.js'; import { safeTitle, groupContent, mapToolStatusToContainerStatus, -} from '../shared/utils.js'; +} from '../../shared/utils.js'; + +import type { ToolCallContainerProps } from '../../shared/LayoutComponents.js'; + +export const ToolCallContainer: React.FC = ({ + label, + status = 'success', + children, + toolCallId: _toolCallId, + labelSuffix, + className: _className, +}) => ( +
+
+
+ + {label} + + + {labelSuffix} + +
+ {children && ( +
{children}
+ )} +
+
+); /** * Specialized component for Search tool calls diff --git a/packages/vscode-ide-companion/src/webview/components/toolcalls/index.tsx b/packages/vscode-ide-companion/src/webview/components/toolcalls/index.tsx index 37350a20..11020a7a 100644 --- a/packages/vscode-ide-companion/src/webview/components/toolcalls/index.tsx +++ b/packages/vscode-ide-companion/src/webview/components/toolcalls/index.tsx @@ -10,14 +10,14 @@ import type React from 'react'; import type { BaseToolCallProps } from './shared/types.js'; import { shouldShowToolCall } from './shared/utils.js'; import { GenericToolCall } from './GenericToolCall.js'; -import { ReadToolCall } from './Read/ReadToolCall.js'; +import { ReadToolCall } from './done/Read/ReadToolCall.js'; import { WriteToolCall } from './Write/WriteToolCall.js'; -import { EditToolCall } from './Edit/EditToolCall.js'; +import { EditToolCall } from './done/Edit/EditToolCall.js'; import { ExecuteToolCall as BashExecuteToolCall } from './Bash/Bash.js'; -import { ExecuteToolCall } from './Execute/Execute.js'; +import { ExecuteToolCall } from './done/Execute/Execute.js'; import { UpdatedPlanToolCall } from './UpdatedPlan/UpdatedPlanToolCall.js'; import { ExecuteNodeToolCall } from './ExecuteNode/ExecuteNodeToolCall.js'; -import { SearchToolCall } from './Search/SearchToolCall.js'; +import { SearchToolCall } from './done/Search/SearchToolCall.js'; import { ThinkToolCall } from './Think/ThinkToolCall.js'; /** @@ -92,7 +92,9 @@ export const getToolCallComponent = ( /** * Main tool call component that routes to specialized implementations */ -export const ToolCallRouter: React.FC = ({ toolCall }) => { +export const ToolCallRouter: React.FC< + BaseToolCallProps & { isFirst?: boolean; isLast?: boolean } +> = ({ toolCall, isFirst, isLast }) => { // Check if we should show this tool call (hide internal ones) if (!shouldShowToolCall(toolCall.kind)) { return null; @@ -102,7 +104,7 @@ export const ToolCallRouter: React.FC = ({ toolCall }) => { const Component = getToolCallComponent(toolCall.kind, toolCall); // Render the specialized component - return ; + return ; }; // Re-export types for convenience diff --git a/packages/vscode-ide-companion/src/webview/components/toolcalls/shared/LayoutComponents.tsx b/packages/vscode-ide-companion/src/webview/components/toolcalls/shared/LayoutComponents.tsx index d4668287..153ed8f1 100644 --- a/packages/vscode-ide-companion/src/webview/components/toolcalls/shared/LayoutComponents.tsx +++ b/packages/vscode-ide-companion/src/webview/components/toolcalls/shared/LayoutComponents.tsx @@ -14,7 +14,7 @@ import './LayoutComponents.css'; /** * Props for ToolCallContainer - Claude Code style layout */ -interface ToolCallContainerProps { +export interface ToolCallContainerProps { /** Operation label (e.g., "Read", "Write", "Search") */ label: string; /** Status for bullet color: 'success' | 'error' | 'warning' | 'loading' | 'default' */ diff --git a/packages/vscode-ide-companion/src/webview/components/toolcalls/shared/types.ts b/packages/vscode-ide-companion/src/webview/components/toolcalls/shared/types.ts index d0866d21..57d3c700 100644 --- a/packages/vscode-ide-companion/src/webview/components/toolcalls/shared/types.ts +++ b/packages/vscode-ide-companion/src/webview/components/toolcalls/shared/types.ts @@ -56,6 +56,8 @@ export interface ToolCallData { */ export interface BaseToolCallProps { toolCall: ToolCallData; + isFirst?: boolean; + isLast?: boolean; } /** diff --git a/packages/vscode-ide-companion/src/webview/components/toolcalls/shared/utils.ts b/packages/vscode-ide-companion/src/webview/components/toolcalls/shared/utils.ts index 92ebf5df..4f43eb8d 100644 --- a/packages/vscode-ide-companion/src/webview/components/toolcalls/shared/utils.ts +++ b/packages/vscode-ide-companion/src/webview/components/toolcalls/shared/utils.ts @@ -20,7 +20,13 @@ export const formatValue = (value: unknown): string => { return ''; } if (typeof value === 'string') { - return value; + // TODO: 尝试从 string 取出 Output 部分 + try { + value = (JSON.parse(value) as { output?: unknown }).output ?? value; + } catch (_error) { + // ignore JSON parse errors + } + return value as string; } // Handle Error objects specially if (value instanceof Error) {