mirror of
https://github.com/claude-code-best/claude-code.git
synced 2026-06-18 14:25:51 +00:00
130 lines
4.0 KiB
TypeScript
130 lines
4.0 KiB
TypeScript
import React from 'react'
|
|
import { removeSandboxViolationTags } from 'src/utils/sandbox/sandbox-ui-utils.js'
|
|
import { KeyboardShortcutHint } from '@anthropic/ink'
|
|
import { MessageResponse } from '../../components/MessageResponse.js'
|
|
import { OutputLine } from '../../components/shell/OutputLine.js'
|
|
import { ShellTimeDisplay } from '../../components/shell/ShellTimeDisplay.js'
|
|
import { Box, Text } from '@anthropic/ink'
|
|
import type { Out as BashOut } from './BashTool.js'
|
|
|
|
type Props = {
|
|
content: Omit<BashOut, 'interrupted'>
|
|
verbose: boolean
|
|
timeoutMs?: number
|
|
}
|
|
|
|
// Pattern to match "Shell cwd was reset to <path>" message
|
|
// Use (?:^|\n) to match either start of string or after a newline
|
|
const SHELL_CWD_RESET_PATTERN = /(?:^|\n)(Shell cwd was reset to .+)$/
|
|
|
|
/**
|
|
* Extracts sandbox violations from stderr if present
|
|
* Returns both the cleaned stderr and the violations content
|
|
*/
|
|
function extractSandboxViolations(stderr: string): {
|
|
cleanedStderr: string
|
|
} {
|
|
const violationsMatch = stderr.match(
|
|
/<sandbox_violations>([\s\S]*?)<\/sandbox_violations>/,
|
|
)
|
|
|
|
if (!violationsMatch) {
|
|
return { cleanedStderr: stderr }
|
|
}
|
|
|
|
// Remove the sandbox violations section from stderr
|
|
const cleanedStderr = removeSandboxViolationTags(stderr).trim()
|
|
|
|
return {
|
|
cleanedStderr,
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Extracts the "Shell cwd was reset" warning message from stderr
|
|
* Returns the cleaned stderr and the warning message separately
|
|
*/
|
|
function extractCwdResetWarning(stderr: string): {
|
|
cleanedStderr: string
|
|
cwdResetWarning: string | null
|
|
} {
|
|
const match = stderr.match(SHELL_CWD_RESET_PATTERN)
|
|
if (!match) {
|
|
return { cleanedStderr: stderr, cwdResetWarning: null }
|
|
}
|
|
|
|
// Extract the warning message from capture group 1
|
|
const cwdResetWarning = match[1] ?? null
|
|
// Remove the warning from stderr (replace the full match)
|
|
const cleanedStderr = stderr.replace(SHELL_CWD_RESET_PATTERN, '').trim()
|
|
|
|
return { cleanedStderr, cwdResetWarning }
|
|
}
|
|
|
|
export default function BashToolResultMessage({
|
|
content: {
|
|
stdout = '',
|
|
stderr: stdErrWithViolations = '',
|
|
isImage,
|
|
returnCodeInterpretation,
|
|
noOutputExpected,
|
|
backgroundTaskId,
|
|
},
|
|
verbose,
|
|
timeoutMs,
|
|
}: Props): React.ReactNode {
|
|
// Extract sandbox violations from stderr as it feels cleaner on the UI
|
|
// We want the model to see the violations, so it can explain what went wrong, and the
|
|
// user can access them in the violation logs
|
|
const { cleanedStderr: stderrWithoutViolations } =
|
|
extractSandboxViolations(stdErrWithViolations)
|
|
|
|
// Extract "Shell cwd was reset" warning to render it with warning color instead of error
|
|
const { cleanedStderr: stderr, cwdResetWarning } = extractCwdResetWarning(
|
|
stderrWithoutViolations,
|
|
)
|
|
|
|
// If this is an image, we don't want to truncate it in the UI
|
|
if (isImage) {
|
|
return (
|
|
<MessageResponse height={1}>
|
|
<Text dimColor>[Image data detected and sent to Claude]</Text>
|
|
</MessageResponse>
|
|
)
|
|
}
|
|
|
|
return (
|
|
<Box flexDirection="column">
|
|
{stdout !== '' ? <OutputLine content={stdout} verbose={verbose} /> : null}
|
|
{stderr.trim() !== '' ? (
|
|
<OutputLine content={stderr} verbose={verbose} isError />
|
|
) : null}
|
|
{cwdResetWarning ? (
|
|
<MessageResponse>
|
|
<Text dimColor>{cwdResetWarning}</Text>
|
|
</MessageResponse>
|
|
) : null}
|
|
{stdout === '' && stderr.trim() === '' && !cwdResetWarning ? (
|
|
<MessageResponse height={1}>
|
|
<Text dimColor>
|
|
{backgroundTaskId ? (
|
|
<>
|
|
Running in the background{' '}
|
|
<KeyboardShortcutHint shortcut="↓" action="manage" parens />
|
|
</>
|
|
) : (
|
|
returnCodeInterpretation ||
|
|
(noOutputExpected ? 'Done' : '(No output)')
|
|
)}
|
|
</Text>
|
|
</MessageResponse>
|
|
) : null}
|
|
{timeoutMs && (
|
|
<MessageResponse>
|
|
<ShellTimeDisplay timeoutMs={timeoutMs} />
|
|
</MessageResponse>
|
|
)}
|
|
</Box>
|
|
)
|
|
}
|