+
;
+ return
;
case 'tool_result':
return
;
@@ -456,16 +508,27 @@ const TOOL_CONFIG = {
getSummary: (input) => input.task_id?.substring(0, 8) || 'task',
},
Skill: {
- icon: Play,
+ icon: Zap,
color: 'purple',
- label: 'Using skill',
+ label: 'Launching skill',
getSummary: (input) => input.skill || 'skill',
},
SlashCommand: {
- icon: Terminal,
+ icon: Command,
color: 'cyan',
label: 'Running command',
- getSummary: (input) => input.command || 'command',
+ getSummary: (input) => input.command?.split(' ')[0] || 'command',
+ },
+ AskUserQuestion: {
+ icon: HelpCircle,
+ color: 'yellow',
+ label: 'Asking question',
+ getSummary: (input) => {
+ const questions = input.questions || [];
+ if (questions.length === 1) return questions[0].header || 'question';
+ return `${questions.length} questions`;
+ },
+ isInteractive: true,
},
ExitPlanMode: {
icon: ClipboardList,
@@ -541,8 +604,10 @@ const COLOR_CLASSES = {
// Note: PlanApprovalCard removed - ExitPlanMode approval now handled via PermissionDialog modal
-const ToolUseCard = memo(function ToolUseCard({ tool, input, result }) {
+const ToolUseCard = memo(function ToolUseCard({ tool, input, result, onSendMessage }) {
const [showResult, setShowResult] = useState(false);
+ const [selectedOptions, setSelectedOptions] = useState({});
+ const [customInput, setCustomInput] = useState('');
const config = TOOL_CONFIG[tool] || {
icon: Terminal,
@@ -864,6 +929,187 @@ const ToolUseCard = memo(function ToolUseCard({ tool, input, result }) {
);
}
+ if (tool === 'Skill') {
+ return (
+
+ );
+ }
+
+ if (tool === 'SlashCommand') {
+ return (
+
+
+
+ {input.command}
+
+
+ );
+ }
+
+ if (tool === 'AskUserQuestion') {
+ const questions = input.questions || [];
+ // Only consider it "answered" if there's a successful result (not an error)
+ const hasResult = result && !result.isError;
+
+ // Handle option selection
+ const handleOptionClick = (qIdx, optIdx, isMulti) => {
+ if (hasResult) return; // Already answered
+ setSelectedOptions(prev => {
+ const key = `q${qIdx}`;
+ if (isMulti) {
+ const current = prev[key] || [];
+ if (current.includes(optIdx)) {
+ return { ...prev, [key]: current.filter(i => i !== optIdx) };
+ }
+ return { ...prev, [key]: [...current, optIdx] };
+ }
+ return { ...prev, [key]: [optIdx] };
+ });
+ };
+
+ // Submit selected answers or custom input
+ const handleSubmit = () => {
+ if (!onSendMessage || hasResult) return;
+
+ // If custom input is provided, use that
+ if (customInput.trim()) {
+ onSendMessage(customInput.trim());
+ return;
+ }
+
+ // Otherwise use selected options
+ const answers = questions.map((q, qIdx) => {
+ const selected = selectedOptions[`q${qIdx}`] || [];
+ const labels = selected.map(idx => q.options[idx]?.label).filter(Boolean);
+ return labels.join(', ') || '';
+ }).filter(Boolean);
+
+ if (answers.length > 0) {
+ onSendMessage(answers.join('\n'));
+ }
+ };
+
+ const isOptionSelected = (qIdx, optIdx) => {
+ return (selectedOptions[`q${qIdx}`] || []).includes(optIdx);
+ };
+
+ const hasSelection = Object.values(selectedOptions).some(arr => arr.length > 0);
+ const canSubmit = hasSelection || customInput.trim();
+
+ return (
+
+ {questions.map((q, qIdx) => (
+
+ {/* Question header */}
+
+
+ {q.header}
+
+ {q.multiSelect && (
+ (select multiple)
+ )}
+
+
+ {/* Question text */}
+
{q.question}
+
+ {/* Options as grid for better layout */}
+
+ {q.options?.map((opt, optIdx) => {
+ const isSelected = isOptionSelected(qIdx, optIdx);
+ return (
+
+ );
+ })}
+
+
+ ))}
+
+ {/* Custom input + Submit section */}
+ {!hasResult && onSendMessage && (
+
+ {/* Custom input field */}
+
+
+ setCustomInput(e.target.value)}
+ placeholder="Enter your own answer..."
+ minRows={2}
+ maxRows={6}
+ className="w-full px-3 py-2 bg-dark-800 border border-dark-700 rounded-lg text-sm text-dark-200
+ placeholder-dark-500 resize-none
+ focus:outline-none focus:border-yellow-500/50 focus:ring-1 focus:ring-yellow-500/20
+ transition-all duration-200"
+ />
+
+
+ {/* Submit button */}
+
+
+ )}
+
+ {hasResult && (
+
+
+ Response submitted
+
+ )}
+
+ );
+ }
+
// Default JSON view
return (
+
{/* Header */}
{/* Icon */}
@@ -902,8 +1153,8 @@ const ToolUseCard = memo(function ToolUseCard({ tool, input, result }) {
•
{summary}
- {/* Result badge */}
- {resultData && (
+ {/* Result badge - hide for interactive tools since they handle their own state */}
+ {resultData && !isInteractiveTool && (
<>
•
@@ -920,13 +1171,13 @@ const ToolUseCard = memo(function ToolUseCard({ tool, input, result }) {
- {/* Content - always visible with max height and scroll */}
-
+ {/* Content - interactive tools get full height, others are capped */}
+
{renderSpecialInput()}
- {/* Collapsible Result Section */}
- {resultData && (
+ {/* Collapsible Result Section - hide for interactive tools */}
+ {resultData && !isInteractiveTool && (