1import React, { useState } from "react";
2import { LLMContent } from "../types";
3
4interface ChangeDirToolProps {
5 // For tool_use (pending state)
6 toolInput?: unknown; // { path: string }
7 isRunning?: boolean;
8
9 // For tool_result (completed state)
10 toolResult?: LLMContent[];
11 hasError?: boolean;
12 executionTime?: string;
13}
14
15function ChangeDirTool({
16 toolInput,
17 isRunning,
18 toolResult,
19 hasError,
20 executionTime,
21}: ChangeDirToolProps) {
22 const [isExpanded, setIsExpanded] = useState(false);
23
24 // Extract path from toolInput
25 const path =
26 typeof toolInput === "object" &&
27 toolInput !== null &&
28 "path" in toolInput &&
29 typeof (toolInput as { path: unknown }).path === "string"
30 ? (toolInput as { path: string }).path
31 : "";
32
33 // Get result text
34 const resultText =
35 toolResult
36 ?.map((r) => r.Text)
37 .filter(Boolean)
38 .join("") || "";
39
40 const isComplete = !isRunning && toolResult !== undefined;
41
42 return (
43 <div className="tool" data-testid={isComplete ? "tool-call-completed" : "tool-call-running"}>
44 <div className="tool-header" onClick={() => setIsExpanded(!isExpanded)}>
45 <div className="tool-summary">
46 <span className={`tool-emoji ${isRunning ? "running" : ""}`}>📂</span>
47 <span className="tool-command">cd {path || "..."}</span>
48 {isComplete && hasError && <span className="tool-error">✗</span>}
49 {isComplete && !hasError && <span className="tool-success">✓</span>}
50 </div>
51 <button
52 className="tool-toggle"
53 aria-label={isExpanded ? "Collapse" : "Expand"}
54 aria-expanded={isExpanded}
55 >
56 <svg
57 width="12"
58 height="12"
59 viewBox="0 0 12 12"
60 fill="none"
61 xmlns="http://www.w3.org/2000/svg"
62 style={{
63 transform: isExpanded ? "rotate(90deg)" : "rotate(0deg)",
64 transition: "transform 0.2s",
65 }}
66 >
67 <path
68 d="M4.5 3L7.5 6L4.5 9"
69 stroke="currentColor"
70 strokeWidth="1.5"
71 strokeLinecap="round"
72 strokeLinejoin="round"
73 />
74 </svg>
75 </button>
76 </div>
77
78 {isExpanded && (
79 <div className="tool-details">
80 <div className="tool-section">
81 <div className="tool-label">
82 Path:
83 {executionTime && <span className="tool-time">{executionTime}</span>}
84 </div>
85 <div className={`tool-code ${hasError ? "error" : ""}`}>{path || "(no path)"}</div>
86 </div>
87 {isComplete && (
88 <div className="tool-section">
89 <div className="tool-label">Result:</div>
90 <div className={`tool-code ${hasError ? "error" : ""}`}>
91 {resultText || "(no output)"}
92 </div>
93 </div>
94 )}
95 </div>
96 )}
97 </div>
98 );
99}
100
101export default ChangeDirTool;