feat(hub): expose worktree overview, state mutation, force-remove

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
mika kuns
2026-05-19 09:37:29 +02:00
parent b095a29f97
commit 046da0fd81

View File

@@ -29,6 +29,21 @@ public record AppSettingsDto(
public record WorktreeCleanupDto(int Removed); public record WorktreeCleanupDto(int Removed);
public record WorktreeResetDto(int Removed, int TasksAffected, bool Blocked, int RunningTasks); public record WorktreeResetDto(int Removed, int TasksAffected, bool Blocked, int RunningTasks);
public record WorktreeOverviewDto(
string TaskId,
string TaskTitle,
ClaudeDo.Data.Models.TaskStatus TaskStatus,
string ListId,
string ListName,
string Path,
string BranchName,
WorktreeState State,
string? DiffStat,
DateTime CreatedAt,
bool PathExistsOnDisk);
public record ForceRemoveResultDto(bool Removed, string? Reason);
public record MergeResultDto(string Status, IReadOnlyList<string> ConflictFiles, string? ErrorMessage); public record MergeResultDto(string Status, IReadOnlyList<string> ConflictFiles, string? ErrorMessage);
public record MergeTargetsDto(string DefaultBranch, IReadOnlyList<string> LocalBranches); public record MergeTargetsDto(string DefaultBranch, IReadOnlyList<string> LocalBranches);
public record UpdateListDto(string Id, string Name, string? WorkingDir, string DefaultCommitType); public record UpdateListDto(string Id, string Name, string? WorkingDir, string DefaultCommitType);
@@ -220,9 +235,9 @@ public sealed class WorkerHub : Microsoft.AspNetCore.SignalR.Hub
}); });
} }
public async Task<WorktreeCleanupDto> CleanupFinishedWorktrees() public async Task<WorktreeCleanupDto> CleanupFinishedWorktrees(string? listId = null)
{ {
var result = await _wtMaintenance.CleanupFinishedAsync(); var result = await _wtMaintenance.CleanupFinishedAsync(listId, Context.ConnectionAborted);
return new WorktreeCleanupDto(result.Removed); return new WorktreeCleanupDto(result.Removed);
} }
@@ -232,6 +247,33 @@ public sealed class WorkerHub : Microsoft.AspNetCore.SignalR.Hub
return new WorktreeResetDto(result.Removed, result.TasksAffected, result.Blocked, result.RunningTasks); return new WorktreeResetDto(result.Removed, result.TasksAffected, result.Blocked, result.RunningTasks);
} }
public async Task<List<WorktreeOverviewDto>> GetWorktreesOverview(string? listId)
{
var rows = await _wtMaintenance.GetOverviewAsync(listId, Context.ConnectionAborted);
return rows.Select(r => new WorktreeOverviewDto(
r.TaskId, r.TaskTitle, r.TaskStatus, r.ListId, r.ListName,
r.Path, r.BranchName, r.State, r.DiffStat, r.CreatedAt, r.PathExistsOnDisk)).ToList();
}
public async Task<bool> SetWorktreeState(string taskId, WorktreeState newState)
{
using var ctx = _dbFactory.CreateDbContext();
var repo = new WorktreeRepository(ctx);
var existing = await repo.GetByTaskIdAsync(taskId, Context.ConnectionAborted);
if (existing is null) throw new HubException("worktree not found");
await repo.SetStateAsync(taskId, newState, Context.ConnectionAborted);
await _broadcaster.WorktreeUpdated(taskId);
return true;
}
public async Task<ForceRemoveResultDto> ForceRemoveWorktree(string taskId)
{
var result = await _wtMaintenance.ForceRemoveAsync(taskId, Context.ConnectionAborted);
if (result.Removed)
await _broadcaster.WorktreeUpdated(taskId);
return new ForceRemoveResultDto(result.Removed, result.Reason);
}
public async Task<MergeResultDto> MergeTask( public async Task<MergeResultDto> MergeTask(
string taskId, string targetBranch, bool removeWorktree, string commitMessage) string taskId, string targetBranch, bool removeWorktree, string commitMessage)
{ {