"use client"; import { memo } from "react"; import { IconCheck, IconX, IconTerminal } from "@tabler/icons-react"; import { GridSpinner } from "@/components/grid-spinner"; import { transformPathsInText } from "@/lib/utils"; import type { Message } from "@/lib/types/http"; import { ExpandableRow } from "./expandable-row"; import { useExpandState } from "./use-expand-state"; type ShellExecOutput = { exit_code?: number; stdout?: string; stderr?: string; }; type ShellExecPayload = { command?: string; work_dir?: string; output?: ShellExecOutput; }; type ToolExecuteMetadata = { tool_call_id?: string; status?: "pending" | "running" | "complete" | "error"; normalized?: { shell_exec?: ShellExecPayload }; }; type ToolExecuteMessageProps = { comment: Message; worktreePath?: string; }; function ExecuteStatusIcon({ status, exitCode, }: { status: string | undefined; exitCode: number | undefined; }) { if (status === "complete") { return exitCode === 0 ? ( ) : ( ); } if (status === "error") return ; if (status === "running") return ; return null; } type ExecuteOutputProps = { displayCommand: string; displayWorkDir: string | null; workDir: string | undefined; output: ShellExecOutput | undefined; }; function ExecuteOutputContent({ displayCommand, displayWorkDir, workDir, output, }: ExecuteOutputProps) { return (
        {displayCommand}
      
{displayWorkDir && (
cwd:{" "} {displayWorkDir}
)} {output?.stdout && (
          {output.stdout}
        
)} {output?.stderr && (
          {output.stderr}
        
)}
); } function isExecuteSuccess( status: ToolExecuteMetadata["status"], output: ShellExecOutput | undefined, ): boolean { if (status !== "complete") return false; return output?.exit_code === 0 || output?.exit_code === undefined; } function parseExecuteMetadata(comment: Message) { const metadata = comment.metadata as ToolExecuteMetadata | undefined; const status = metadata?.status; const shellExec = metadata?.normalized?.shell_exec; const output = shellExec?.output; const workDir = shellExec?.work_dir; const isSuccess = isExecuteSuccess(status, output); return { status, output, workDir, isSuccess }; } function CommandHeader({ displayCommand }: { displayCommand: string }) { return ( {displayCommand} ); } export const ToolExecuteMessage = memo(function ToolExecuteMessage({ comment, worktreePath, }: ToolExecuteMessageProps) { const { status, output, workDir, isSuccess } = parseExecuteMetadata(comment); const autoExpanded = status === "running"; const { isExpanded, handleToggle } = useExpandState(status, autoExpanded); const displayCommand = transformPathsInText(comment.content, worktreePath); const displayWorkDir = workDir ? transformPathsInText(workDir, worktreePath) : null; return ( } header={
{!isSuccess && ( )}
} hasExpandableContent isExpanded={isExpanded} onToggle={handleToggle} >
); });