import { useState, useEffect, useCallback } from "react"; import { FileCode, ChevronDown, ChevronRight, ChevronLeft, AlertCircle, GitCommit, WrapText, Maximize2 } from "lucide-react"; import type { MergeDetails, Column } from "@fusion/core"; import { getErrorMessage } from "@fusion/core"; import { fetchTaskDiff, type TaskDiff, } from "../api"; import { highlightDiff } from "../utils/highlightDiff"; import { ChangesDiffModal } from "./ChangesDiffModal"; import "./TaskDiffShared.css"; import "./TaskChangesTab.css"; interface TaskChangesTabProps { taskId: string; worktree?: string; projectId?: string; column?: Column; mergeDetails?: MergeDetails; /** * Files modified by the task during execution, captured from the worktree. * Used as a last-resort fallback when the live worktree diff is empty or the * recorded `mergeDetails.commitSha` resolves to an empty git commit (which * can happen when the merger stores a per-branch SHA that gets collapsed * into a different squash on main). * * Done-task sources of truth: * - Authoritative landed diff: `/api/tasks/:id/diff` lineage union. * - Fallback views keep a consistent `N file(s) changed` headline. * - Provenance is disclosed in `task-changes-state-hint` text. */ modifiedFiles?: string[]; } function getStatusLabel(status: "added" | "modified" | "deleted" | "unknown"): string { switch (status) { case "added": return "A"; case "deleted": return "D"; case "modified": return "M"; default: return "?"; } } function renderModifiedFilesFallback( fileList: string[], isDone: boolean, mergeDetails?: MergeDetails, source: "landed" | "execution" = "execution", ) { return (
{mergeDetails.commitSha.slice(0, 7)}
{fileList.length} file{fileList.length === 1 ? "" : "s"} changed.
{isDone // FN-4647: done-task fallback must explicitly describe executor-captured scope. ? source === "landed" ? "These are files captured from the merged commit metadata. The lineage-backed diff is unavailable for this task." : "These are files captured from the worktree during execution. They may differ from the files that actually landed on main. The lineage-backed diff is unavailable for this task." : "The live worktree diff is empty. Showing the last file paths captured during execution — patches unavailable."}No worktree available for this task.
Changes will be shown once the task is in progress.Detailed file changes unavailable.
{hasSummary ? `Final commit summary: ${summaryFiles ?? 0} file${(summaryFiles ?? 0) === 1 ? "" : "s"} changed, +${summaryAdditions ?? 0} additions, -${summaryDeletions ?? 0} deletions. Counts only the recorded merge/squash commit, not the full task lineage.` : "No merge commit was recorded for this task."}No files modified.
{isDone ? "No file changes were recorded in the merge commit." : "The agent did not modify any files during execution."}{mergeDetails.commitSha.slice(0, 7)}
{highlightDiff(file.patch)}