import { useState, useEffect, useCallback } from "react"; import { FileCode, ChevronDown, ChevronRight, AlertCircle } from "lucide-react"; import { fetchTaskDiff, type TaskDiff } from "../api"; interface TaskChangesTabProps { taskId: string; worktree?: string; } function getFileStatus(file: string, patch: string): "added" | "modified" | "deleted" | "unknown" { if (patch.includes("diff --git")) { if (patch.includes("new file mode")) return "added"; if (patch.includes("deleted file mode")) return "deleted"; return "modified"; } return "unknown"; } function getStatusColor(status: "added" | "modified" | "deleted" | "unknown"): string { switch (status) { case "added": return "#3fb950"; // green case "deleted": return "#f85149"; // red case "modified": return "#58a6ff"; // blue default: return "#8b949e"; // gray } } function formatFileSize(bytes: number): string { if (bytes < 1024) return `${bytes} B`; if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`; return `${(bytes / (1024 * 1024)).toFixed(1)} MB`; } export function TaskChangesTab({ taskId, worktree }: TaskChangesTabProps) { const [diffData, setDiffData] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const [expandedFiles, setExpandedFiles] = useState>(new Set()); const loadDiff = useCallback(async () => { if (!worktree) { setLoading(false); return; } try { setLoading(true); setError(null); const data = await fetchTaskDiff(taskId); setDiffData(data); // Auto-expand first file if there are files if (data.files.length > 0) { setExpandedFiles(new Set([data.files[0].path])); } } catch (err: any) { setError(err.message || "Failed to load diff"); } finally { setLoading(false); } }, [taskId, worktree]); useEffect(() => { loadDiff(); }, [loadDiff]); const toggleFile = (file: string) => { setExpandedFiles((prev) => { const next = new Set(prev); if (next.has(file)) { next.delete(file); } else { next.add(file); } return next; }); }; if (loading) { return (
Loading changes...
); } if (error) { return (
Error loading changes: {error}
); } if (!worktree) { return (

No worktree available for this task.

Changes will be shown once the task is in progress.
); } if (!diffData || diffData.files.length === 0) { return (

No files modified.

The agent did not modify any files during execution.
); } return (

Modified Files ({diffData.files.length})

{diffData.files.map((fileEntry) => { const { path, status, patch } = fileEntry; const isExpanded = expandedFiles.has(path); return (
{isExpanded && patch && (
                    {patch}
                  
)}
); })}
); }