mirror of
https://github.com/claude-code-best/claude-code.git
synced 2026-06-21 15:55:50 +00:00
style: 完成所有文件的lint
This commit is contained in:
@@ -1,41 +1,36 @@
|
||||
import type { ToolUseBlockParam } from '@anthropic-ai/sdk/resources/index.mjs'
|
||||
import React, { useMemo } from 'react'
|
||||
import { useTerminalSize } from 'src/hooks/useTerminalSize.js'
|
||||
import type { ThemeName } from 'src/utils/theme.js'
|
||||
import type { Command } from '../../commands.js'
|
||||
import { BLACK_CIRCLE } from '../../constants/figures.js'
|
||||
import { Box, Text, stringWidth, useTheme } from '@anthropic/ink'
|
||||
import { useAppStateMaybeOutsideOfProvider } from '../../state/AppState.js'
|
||||
import {
|
||||
findToolByName,
|
||||
type Tool,
|
||||
type ToolProgressData,
|
||||
type Tools,
|
||||
} from '../../Tool.js'
|
||||
import type { ProgressMessage } from '../../types/message.js'
|
||||
import { useIsClassifierChecking } from '../../utils/classifierApprovalsHook.js'
|
||||
import { logError } from '../../utils/log.js'
|
||||
import type { buildMessageLookups } from '../../utils/messages.js'
|
||||
import { MessageResponse } from '../MessageResponse.js'
|
||||
import { useSelectedMessageBg } from '../messageActions.js'
|
||||
import { SentryErrorBoundary } from '../SentryErrorBoundary.js'
|
||||
import { ToolUseLoader } from '../ToolUseLoader.js'
|
||||
import { HookProgressMessage } from './HookProgressMessage.js'
|
||||
import type { ToolUseBlockParam } from '@anthropic-ai/sdk/resources/index.mjs';
|
||||
import React, { useMemo } from 'react';
|
||||
import { useTerminalSize } from 'src/hooks/useTerminalSize.js';
|
||||
import type { ThemeName } from 'src/utils/theme.js';
|
||||
import type { Command } from '../../commands.js';
|
||||
import { BLACK_CIRCLE } from '../../constants/figures.js';
|
||||
import { Box, Text, stringWidth, useTheme } from '@anthropic/ink';
|
||||
import { useAppStateMaybeOutsideOfProvider } from '../../state/AppState.js';
|
||||
import { findToolByName, type Tool, type ToolProgressData, type Tools } from '../../Tool.js';
|
||||
import type { ProgressMessage } from '../../types/message.js';
|
||||
import { useIsClassifierChecking } from '../../utils/classifierApprovalsHook.js';
|
||||
import { logError } from '../../utils/log.js';
|
||||
import type { buildMessageLookups } from '../../utils/messages.js';
|
||||
import { MessageResponse } from '../MessageResponse.js';
|
||||
import { useSelectedMessageBg } from '../messageActions.js';
|
||||
import { SentryErrorBoundary } from '../SentryErrorBoundary.js';
|
||||
import { ToolUseLoader } from '../ToolUseLoader.js';
|
||||
import { HookProgressMessage } from './HookProgressMessage.js';
|
||||
|
||||
type Props = {
|
||||
param: ToolUseBlockParam
|
||||
addMargin: boolean
|
||||
tools: Tools
|
||||
commands: Command[]
|
||||
verbose: boolean
|
||||
inProgressToolUseIDs: Set<string>
|
||||
progressMessagesForMessage: ProgressMessage[]
|
||||
shouldAnimate: boolean
|
||||
shouldShowDot: boolean
|
||||
inProgressToolCallCount?: number
|
||||
lookups: ReturnType<typeof buildMessageLookups>
|
||||
isTranscriptMode?: boolean
|
||||
}
|
||||
param: ToolUseBlockParam;
|
||||
addMargin: boolean;
|
||||
tools: Tools;
|
||||
commands: Command[];
|
||||
verbose: boolean;
|
||||
inProgressToolUseIDs: Set<string>;
|
||||
progressMessagesForMessage: ProgressMessage[];
|
||||
shouldAnimate: boolean;
|
||||
shouldShowDot: boolean;
|
||||
inProgressToolCallCount?: number;
|
||||
lookups: ReturnType<typeof buildMessageLookups>;
|
||||
isTranscriptMode?: boolean;
|
||||
};
|
||||
|
||||
export function AssistantToolUseMessage({
|
||||
param,
|
||||
@@ -51,29 +46,21 @@ export function AssistantToolUseMessage({
|
||||
lookups,
|
||||
isTranscriptMode,
|
||||
}: Props): React.ReactNode {
|
||||
const terminalSize = useTerminalSize()
|
||||
const [theme] = useTheme()
|
||||
const bg = useSelectedMessageBg()
|
||||
const pendingWorkerRequest = useAppStateMaybeOutsideOfProvider(
|
||||
state => state.pendingWorkerRequest,
|
||||
)
|
||||
const isClassifierCheckingRaw = useIsClassifierChecking(param.id)
|
||||
const permissionMode = useAppStateMaybeOutsideOfProvider(
|
||||
state => state.toolPermissionContext.mode,
|
||||
)
|
||||
const terminalSize = useTerminalSize();
|
||||
const [theme] = useTheme();
|
||||
const bg = useSelectedMessageBg();
|
||||
const pendingWorkerRequest = useAppStateMaybeOutsideOfProvider(state => state.pendingWorkerRequest);
|
||||
const isClassifierCheckingRaw = useIsClassifierChecking(param.id);
|
||||
const permissionMode = useAppStateMaybeOutsideOfProvider(state => state.toolPermissionContext.mode);
|
||||
// strippedDangerousRules is set by stripDangerousPermissionsForAutoMode
|
||||
// (even to {}) whenever auto is active, and cleared by restoreDangerousPermissions
|
||||
// on deactivation — a reliable proxy for isAutoModeActive() during plan.
|
||||
// prePlanMode would be stale after transitionPlanAutoMode deactivates mid-plan.
|
||||
const hasStrippedRules = useAppStateMaybeOutsideOfProvider(
|
||||
state => !!state.toolPermissionContext.strippedDangerousRules,
|
||||
)
|
||||
const isAutoClassifier =
|
||||
permissionMode === 'auto' || (permissionMode === 'plan' && hasStrippedRules)
|
||||
const isClassifierChecking =
|
||||
process.env.USER_TYPE === 'ant' &&
|
||||
isClassifierCheckingRaw &&
|
||||
permissionMode !== 'auto'
|
||||
);
|
||||
const isAutoClassifier = permissionMode === 'auto' || (permissionMode === 'plan' && hasStrippedRules);
|
||||
const isClassifierChecking = process.env.USER_TYPE === 'ant' && isClassifierCheckingRaw && permissionMode !== 'auto';
|
||||
|
||||
// Memoize on param identity (stable — from the persisted message object).
|
||||
// Zod safeParse allocates per call, and some tools' userFacingName()
|
||||
@@ -81,47 +68,34 @@ export function AssistantToolUseMessage({
|
||||
// this, ~50 bash messages × shell-quote-per-render pushed transition
|
||||
// render past the shimmer tick → abort → infinite retry (#21605).
|
||||
const parsed = useMemo(() => {
|
||||
if (!tools) return null
|
||||
const tool = findToolByName(tools, param.name)
|
||||
if (!tool) return null
|
||||
const input = tool.inputSchema.safeParse(param.input)
|
||||
const data = input.success ? input.data : undefined
|
||||
if (!tools) return null;
|
||||
const tool = findToolByName(tools, param.name);
|
||||
if (!tool) return null;
|
||||
const input = tool.inputSchema.safeParse(param.input);
|
||||
const data = input.success ? input.data : undefined;
|
||||
return {
|
||||
tool,
|
||||
input,
|
||||
userFacingToolName: tool.userFacingName(data),
|
||||
userFacingToolNameBackgroundColor:
|
||||
tool.userFacingNameBackgroundColor?.(data),
|
||||
userFacingToolNameBackgroundColor: tool.userFacingNameBackgroundColor?.(data),
|
||||
isTransparentWrapper: tool.isTransparentWrapper?.() ?? false,
|
||||
}
|
||||
}, [tools, param])
|
||||
};
|
||||
}, [tools, param]);
|
||||
|
||||
if (!parsed) {
|
||||
// Guard against undefined tools (required prop) or unknown tool name
|
||||
logError(
|
||||
new Error(
|
||||
tools
|
||||
? `Tool ${param.name} not found`
|
||||
: `Tools array is undefined for tool ${param.name}`,
|
||||
),
|
||||
)
|
||||
return null
|
||||
logError(new Error(tools ? `Tool ${param.name} not found` : `Tools array is undefined for tool ${param.name}`));
|
||||
return null;
|
||||
}
|
||||
|
||||
const {
|
||||
tool,
|
||||
input,
|
||||
userFacingToolName,
|
||||
userFacingToolNameBackgroundColor,
|
||||
isTransparentWrapper,
|
||||
} = parsed
|
||||
const { tool, input, userFacingToolName, userFacingToolNameBackgroundColor, isTransparentWrapper } = parsed;
|
||||
|
||||
const isResolved = lookups.resolvedToolUseIDs.has(param.id)
|
||||
const isQueued = !inProgressToolUseIDs.has(param.id) && !isResolved
|
||||
const isWaitingForPermission = pendingWorkerRequest?.toolUseId === param.id
|
||||
const isResolved = lookups.resolvedToolUseIDs.has(param.id);
|
||||
const isQueued = !inProgressToolUseIDs.has(param.id) && !isResolved;
|
||||
const isWaitingForPermission = pendingWorkerRequest?.toolUseId === param.id;
|
||||
|
||||
if (isTransparentWrapper) {
|
||||
if (isQueued || isResolved) return null
|
||||
if (isQueued || isResolved) return null;
|
||||
return (
|
||||
<Box flexDirection="column" width="100%" backgroundColor={bg}>
|
||||
{renderToolUseProgressMessage(
|
||||
@@ -134,18 +108,18 @@ export function AssistantToolUseMessage({
|
||||
terminalSize,
|
||||
)}
|
||||
</Box>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if (userFacingToolName === '') {
|
||||
return null
|
||||
return null;
|
||||
}
|
||||
|
||||
const renderedToolUseMessage = input.success
|
||||
? renderToolUseMessage(tool, input.data, { theme, verbose, commands })
|
||||
: null
|
||||
: null;
|
||||
if (renderedToolUseMessage === null) {
|
||||
return null
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
@@ -157,11 +131,7 @@ export function AssistantToolUseMessage({
|
||||
backgroundColor={bg}
|
||||
>
|
||||
<Box flexDirection="column">
|
||||
<Box
|
||||
flexDirection="row"
|
||||
flexWrap="nowrap"
|
||||
minWidth={stringWidth(userFacingToolName) + (shouldShowDot ? 2 : 0)}
|
||||
>
|
||||
<Box flexDirection="row" flexWrap="nowrap" minWidth={stringWidth(userFacingToolName) + (shouldShowDot ? 2 : 0)}>
|
||||
{shouldShowDot &&
|
||||
(isQueued ? (
|
||||
<Box minWidth={2}>
|
||||
@@ -182,9 +152,7 @@ export function AssistantToolUseMessage({
|
||||
bold
|
||||
wrap="truncate-end"
|
||||
backgroundColor={userFacingToolNameBackgroundColor}
|
||||
color={
|
||||
userFacingToolNameBackgroundColor ? 'inverseText' : undefined
|
||||
}
|
||||
color={userFacingToolNameBackgroundColor ? 'inverseText' : undefined}
|
||||
>
|
||||
{userFacingToolName}
|
||||
</Text>
|
||||
@@ -195,18 +163,14 @@ export function AssistantToolUseMessage({
|
||||
</Box>
|
||||
)}
|
||||
{/* Render tool-specific tags (timeout, model, resume ID, etc.) */}
|
||||
{input.success &&
|
||||
tool.renderToolUseTag &&
|
||||
tool.renderToolUseTag(input.data)}
|
||||
{input.success && tool.renderToolUseTag && tool.renderToolUseTag(input.data)}
|
||||
</Box>
|
||||
{!isResolved &&
|
||||
!isQueued &&
|
||||
(isClassifierChecking ? (
|
||||
<MessageResponse height={1}>
|
||||
<Text dimColor>
|
||||
{isAutoClassifier
|
||||
? 'Auto classifier checking\u2026'
|
||||
: 'Bash classifier checking\u2026'}
|
||||
{isAutoClassifier ? 'Auto classifier checking\u2026' : 'Bash classifier checking\u2026'}
|
||||
</Text>
|
||||
</MessageResponse>
|
||||
) : isWaitingForPermission ? (
|
||||
@@ -231,29 +195,23 @@ export function AssistantToolUseMessage({
|
||||
{!isResolved && isQueued && renderToolUseQueuedMessage(tool)}
|
||||
</Box>
|
||||
</Box>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
function renderToolUseMessage(
|
||||
tool: Tool,
|
||||
input: unknown,
|
||||
{
|
||||
theme,
|
||||
verbose,
|
||||
commands,
|
||||
}: { theme: ThemeName; verbose: boolean; commands: Command[] },
|
||||
{ theme, verbose, commands }: { theme: ThemeName; verbose: boolean; commands: Command[] },
|
||||
): React.ReactNode {
|
||||
try {
|
||||
const parsed = tool.inputSchema.safeParse(input)
|
||||
const parsed = tool.inputSchema.safeParse(input);
|
||||
if (!parsed.success) {
|
||||
return ''
|
||||
return '';
|
||||
}
|
||||
return tool.renderToolUseMessage(parsed.data, { theme, verbose, commands })
|
||||
return tool.renderToolUseMessage(parsed.data, { theme, verbose, commands });
|
||||
} catch (error) {
|
||||
logError(
|
||||
new Error(`Error rendering tool use message for ${tool.name}: ${error}`),
|
||||
)
|
||||
return ''
|
||||
logError(new Error(`Error rendering tool use message for ${tool.name}: ${error}`));
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -268,16 +226,15 @@ function renderToolUseProgressMessage(
|
||||
inProgressToolCallCount,
|
||||
isTranscriptMode,
|
||||
}: {
|
||||
verbose: boolean
|
||||
inProgressToolCallCount?: number
|
||||
isTranscriptMode?: boolean
|
||||
verbose: boolean;
|
||||
inProgressToolCallCount?: number;
|
||||
isTranscriptMode?: boolean;
|
||||
},
|
||||
terminalSize: { columns: number; rows: number },
|
||||
): React.ReactNode {
|
||||
const toolProgressMessages = progressMessagesForMessage.filter(
|
||||
(msg): msg is ProgressMessage<ToolProgressData> =>
|
||||
(msg.data as Record<string, unknown>).type !== 'hook_progress',
|
||||
)
|
||||
(msg): msg is ProgressMessage<ToolProgressData> => (msg.data as Record<string, unknown>).type !== 'hook_progress',
|
||||
);
|
||||
try {
|
||||
const toolMessages =
|
||||
tool.renderToolUseProgressMessage?.(toolProgressMessages, {
|
||||
@@ -286,7 +243,7 @@ function renderToolUseProgressMessage(
|
||||
terminalSize,
|
||||
inProgressToolCallCount: inProgressToolCallCount ?? 1,
|
||||
isTranscriptMode,
|
||||
}) ?? null
|
||||
}) ?? null;
|
||||
return (
|
||||
<>
|
||||
<SentryErrorBoundary>
|
||||
@@ -300,26 +257,18 @@ function renderToolUseProgressMessage(
|
||||
</SentryErrorBoundary>
|
||||
{toolMessages}
|
||||
</>
|
||||
)
|
||||
);
|
||||
} catch (error) {
|
||||
logError(
|
||||
new Error(
|
||||
`Error rendering tool use progress message for ${tool.name}: ${error}`,
|
||||
),
|
||||
)
|
||||
return null
|
||||
logError(new Error(`Error rendering tool use progress message for ${tool.name}: ${error}`));
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function renderToolUseQueuedMessage(tool: Tool): React.ReactNode {
|
||||
try {
|
||||
return tool.renderToolUseQueuedMessage?.()
|
||||
return tool.renderToolUseQueuedMessage?.();
|
||||
} catch (error) {
|
||||
logError(
|
||||
new Error(
|
||||
`Error rendering tool use queued message for ${tool.name}: ${error}`,
|
||||
),
|
||||
)
|
||||
return null
|
||||
logError(new Error(`Error rendering tool use queued message for ${tool.name}: ${error}`));
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user