import { useContext, useState, useEffect } from 'react'; import { Play, Square, AlertCircle, CheckCircle, Clock, Cog, ArrowLeft, } from 'lucide-react'; import { TaskAttemptDataContext } from '@/components/context/taskDetailsContext.ts'; import { executionProcessesApi } from '@/lib/api.ts'; import { ProfileVariantBadge } from '@/components/common/ProfileVariantBadge.tsx'; import ProcessLogsViewer from './ProcessLogsViewer'; import type { ExecutionProcessStatus, ExecutionProcess } from 'shared/types'; import { useProcessSelection } from '@/contexts/ProcessSelectionContext'; function ProcessesTab() { const { attemptData, setAttemptData } = useContext(TaskAttemptDataContext); const { selectedProcessId, setSelectedProcessId } = useProcessSelection(); const [loadingProcessId, setLoadingProcessId] = useState(null); const getStatusIcon = (status: ExecutionProcessStatus) => { switch (status) { case 'running': return ; case 'completed': return ; case 'failed': return ; case 'killed': return ; default: return ; } }; const getStatusColor = (status: ExecutionProcessStatus) => { switch (status) { case 'running': return 'bg-blue-50 border-blue-200 text-blue-800'; case 'completed': return 'bg-green-50 border-green-200 text-green-800'; case 'failed': return 'bg-red-50 border-red-200 text-red-800'; case 'killed': return 'bg-gray-50 border-gray-200 text-gray-800'; default: return 'bg-gray-50 border-gray-200 text-gray-800'; } }; const formatDate = (dateString: string) => { const date = new Date(dateString); return date.toLocaleString(); }; const fetchProcessDetails = async (processId: string) => { try { setLoadingProcessId(processId); const result = await executionProcessesApi.getDetails(processId); if (result !== undefined) { setAttemptData((prev) => ({ ...prev, runningProcessDetails: { ...prev.runningProcessDetails, [processId]: result, }, })); } } catch (err) { console.error('Failed to fetch process details:', err); } finally { setLoadingProcessId(null); } }; // Automatically fetch process details when selectedProcessId changes useEffect(() => { if ( selectedProcessId && !attemptData.runningProcessDetails[selectedProcessId] ) { fetchProcessDetails(selectedProcessId); } }, [selectedProcessId, attemptData.runningProcessDetails]); const handleProcessClick = async (process: ExecutionProcess) => { setSelectedProcessId(process.id); // If we don't have details for this process, fetch them if (!attemptData.runningProcessDetails[process.id]) { await fetchProcessDetails(process.id); } }; const selectedProcess = selectedProcessId ? attemptData.runningProcessDetails[selectedProcessId] : null; if (!attemptData.processes || attemptData.processes.length === 0) { return (

No execution processes found for this attempt.

); } return (
{!selectedProcessId ? (
{attemptData.processes.map((process) => (
handleProcessClick(process)} >
{getStatusIcon(process.status)}

{process.run_reason}

Process ID: {process.id}

{

Profile:{' '} {process.executor_action.typ.type === 'CodingAgentInitialRequest' || process.executor_action.typ.type === 'CodingAgentFollowUpRequest' ? ( ) : null}

}
{process.status} {process.exit_code !== null && (

Exit: {process.exit_code.toString()}

)}
Started: {formatDate(process.started_at)} {process.completed_at && ( Completed: {formatDate(process.completed_at)} )}
Process ID: {process.id}
))}
) : (

Process Details

{selectedProcess ? ( ) : loadingProcessId === selectedProcessId ? (

Loading process details...

) : (

Failed to load process details. Please try again.

)}
)}
); } export default ProcessesTab;