import React, { useState, useEffect } from 'react'; import { Terminal, CheckCircle, AlertTriangle, CircleDashed, Clock, Loader2, ArrowRight, TerminalIcon, Power, StopCircle } from 'lucide-react'; import { ToolViewProps } from '../types'; import { formatTimestamp, getToolTitle, normalizeContentToString } from '../utils'; import { cn } from '@/lib/utils'; import { useTheme } from 'next-themes'; import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; import { Badge } from '@/components/ui/badge'; import { Progress } from '@/components/ui/progress'; import { ScrollArea } from "@/components/ui/scroll-area"; import { extractCommandData } from './_utils'; export function TerminateCommandToolView({ name = 'terminate-command', assistantContent, toolContent, assistantTimestamp, toolTimestamp, isSuccess = true, isStreaming = false, }: ToolViewProps) { const { resolvedTheme } = useTheme(); const isDarkTheme = resolvedTheme === 'dark'; const [progress, setProgress] = useState(0); const [showFullOutput, setShowFullOutput] = useState(true); const { sessionName, output, actualIsSuccess, actualToolTimestamp, actualAssistantTimestamp } = extractCommandData( assistantContent, toolContent, isSuccess, toolTimestamp, assistantTimestamp ); const rawSessionName = React.useMemo(() => { if (sessionName) return sessionName; if (!assistantContent) return null; const contentStr = normalizeContentToString(assistantContent); if (!contentStr) return null; try { const parsed = JSON.parse(contentStr); if (parsed.content) { const sessionMatch = parsed.content.match( /]*session_name=["']([^"']+)["'][^>]*>/, ); if (sessionMatch) { return sessionMatch[1].trim(); } } } catch (e) { const sessionMatch = contentStr.match( /]*session_name=["']([^"']+)["'][^>]*>/, ); if (sessionMatch) { return sessionMatch[1].trim(); } } return null; }, [assistantContent, sessionName]); const finalSessionName = rawSessionName?.trim() || sessionName; const toolTitle = getToolTitle(name) || 'Terminate Session'; const terminationSuccess = React.useMemo(() => { if (!output) return false; const outputLower = output.toLowerCase(); if (outputLower.includes('does not exist')) return false; if (outputLower.includes('terminated') || outputLower.includes('killed')) return true; if (typeof toolContent === 'string') { const toolResultMatch = toolContent.match(/ToolResult\(success=(true|false)/i); if (toolResultMatch) { return toolResultMatch[1].toLowerCase() === 'true'; } } return actualIsSuccess; }, [output, actualIsSuccess, toolContent]); useEffect(() => { if (isStreaming) { const timer = setInterval(() => { setProgress((prevProgress) => { if (prevProgress >= 95) { clearInterval(timer); return prevProgress; } return prevProgress + 5; }); }, 300); return () => clearInterval(timer); } else { setProgress(100); } }, [isStreaming]); const formattedOutput = React.useMemo(() => { if (!output) return []; let processedOutput = output; try { if (typeof output === 'string' && (output.trim().startsWith('{') || output.trim().startsWith('{'))) { const parsed = JSON.parse(output); if (parsed && typeof parsed === 'object' && parsed.output) { processedOutput = parsed.output; } } } catch (e) { } processedOutput = String(processedOutput); processedOutput = processedOutput.replace(/\\\\/g, '\\'); processedOutput = processedOutput .replace(/\\n/g, '\n') .replace(/\\t/g, '\t') .replace(/\\"/g, '"') .replace(/\\'/g, "'"); processedOutput = processedOutput.replace(/\\u([0-9a-fA-F]{4})/g, (_match, group) => { return String.fromCharCode(parseInt(group, 16)); }); return processedOutput.split('\n'); }, [output]); const hasMoreLines = formattedOutput.length > 10; const previewLines = formattedOutput.slice(0, 10); const linesToShow = showFullOutput ? formattedOutput : previewLines; return (
{toolTitle}
{!isStreaming && ( {terminationSuccess ? ( ) : ( )} {terminationSuccess ? 'Session terminated' : 'Termination failed'} )}
{isStreaming ? (

Terminating session

{finalSessionName || 'Processing termination...'}

{progress}%

) : finalSessionName ? (
Session
{finalSessionName}
{output && (

Result

{terminationSuccess ? 'Success' : 'Failed'}
Termination output
{!terminationSuccess && ( Error )}
                        {linesToShow.map((line, index) => (
                          
{line || ' '}
))} {!showFullOutput && hasMoreLines && (
+ {formattedOutput.length - 10} more lines
)}
)} {!output && !isStreaming && (

No output received

)}
) : (

No Session Found

No session name was detected. Please provide a valid session to terminate.

)}
{!isStreaming && finalSessionName && ( Terminate )}
{actualToolTimestamp && !isStreaming ? formatTimestamp(actualToolTimestamp) : actualAssistantTimestamp ? formatTimestamp(actualAssistantTimestamp) : ''}
); }