From f49aaa39a32661b54c109ba002d24cbdf73f4ea3 Mon Sep 17 00:00:00 2001 From: soryu Date: Mon, 9 Mar 2026 17:20:52 +0000 Subject: feat: worktree diff/commit endpoints and frontend diff viewing (#88) * feat: soryu-co/soryu - makima: Fix worktree info failing when origin ref is missing * WIP: heartbeat checkpoint * WIP: heartbeat checkpoint * WIP: heartbeat checkpoint * feat: soryu-co/soryu - makima: Add worktree commit endpoint and diff endpoint for regular users * feat: soryu-co/soryu - makima: Add frontend diff viewing with clickable worktree files --- makima/frontend/src/components/mesh/TaskDetail.tsx | 41 ++++++++++++++++++++-- 1 file changed, 39 insertions(+), 2 deletions(-) (limited to 'makima/frontend/src/components/mesh/TaskDetail.tsx') diff --git a/makima/frontend/src/components/mesh/TaskDetail.tsx b/makima/frontend/src/components/mesh/TaskDetail.tsx index fdcc58b..00719e2 100644 --- a/makima/frontend/src/components/mesh/TaskDetail.tsx +++ b/makima/frontend/src/components/mesh/TaskDetail.tsx @@ -1,6 +1,6 @@ import { useState, useCallback, useMemo, useEffect } from "react"; import type { TaskWithSubtasks, TaskStatus, TaskSummary, CompletionAction, DaemonDirectory } from "../../lib/api"; -import { retryCompletionAction, getDaemonDirectories, cloneWorktree } from "../../lib/api"; +import { retryCompletionAction, getDaemonDirectories, cloneWorktree, getWorktreeDiff } from "../../lib/api"; import { SubtaskTree, SubtaskProgressBar, calculateTreeStats } from "./SubtaskTree"; import { OverlayDiffViewer } from "./OverlayDiffViewer"; import { PRPreview } from "./PRPreview"; @@ -136,6 +136,9 @@ export function TaskDetail({ ); const [showDiff, setShowDiff] = useState(false); const [showPRPreview, setShowPRPreview] = useState(false); + const [worktreeFileDiff, setWorktreeFileDiff] = useState(null); + const [worktreeFileDiffPath, setWorktreeFileDiffPath] = useState(null); + const [worktreeFileDiffLoading, setWorktreeFileDiffLoading] = useState(false); const [useTreeView, setUseTreeView] = useState(false); // Track which subtask is expanded for inline editing const [expandedSubtaskId, setExpandedSubtaskId] = useState(null); @@ -153,6 +156,22 @@ export function TaskDetail({ // Track branch modal state const [showBranchModal, setShowBranchModal] = useState(false); + // Handle clicking a file in the worktree panel to show its diff + const handleWorktreeFileClick = useCallback(async (filePath: string) => { + setWorktreeFileDiffLoading(true); + setWorktreeFileDiffPath(filePath); + setWorktreeFileDiff(null); + try { + const result = await getWorktreeDiff(task.id, filePath); + setWorktreeFileDiff(result.diff); + } catch (e) { + console.error("Failed to fetch worktree diff:", e); + setWorktreeFileDiff(""); + } finally { + setWorktreeFileDiffLoading(false); + } + }, [task.id]); + // Check if task is running const isTaskRunning = task.status === "running" || task.status === "initializing" || task.status === "starting"; // Check if task is in a terminal state (can be continued/reopened) @@ -897,7 +916,7 @@ export function TaskDetail({ {/* Worktree Files Panel - show changed files in the worktree */} {(task.status === "done" || task.status === "failed" || task.status === "merged" || task.status === "running") && ( - + )} {/* Patches List Panel - show exported patches for this task */} @@ -920,6 +939,24 @@ export function TaskDetail({ )} + {/* Worktree File Diff Modal */} + {(worktreeFileDiff !== null || worktreeFileDiffLoading) && ( +
+
+ { + setWorktreeFileDiff(null); + setWorktreeFileDiffPath(null); + setWorktreeFileDiffLoading(false); + }} + title={worktreeFileDiffPath ? `Diff: ${worktreeFileDiffPath}` : "File Diff"} + /> +
+
+ )} + {/* PR Preview Modal */} {showPRPreview && (
-- cgit v1.2.3