Orchestrates worktree discard, task reset to Manual, and SignalR broadcast. Includes integration tests (happy path + running-task rejection). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
69 lines
2.3 KiB
C#
69 lines
2.3 KiB
C#
using ClaudeDo.Data;
|
|
using ClaudeDo.Data.Models;
|
|
using ClaudeDo.Data.Repositories;
|
|
using ClaudeDo.Worker.Hub;
|
|
using ClaudeDo.Worker.Runner;
|
|
using Microsoft.EntityFrameworkCore;
|
|
using TaskStatus = ClaudeDo.Data.Models.TaskStatus;
|
|
|
|
namespace ClaudeDo.Worker.Services;
|
|
|
|
public sealed class TaskResetService
|
|
{
|
|
private readonly IDbContextFactory<ClaudeDoDbContext> _dbFactory;
|
|
private readonly WorktreeManager _wtManager;
|
|
private readonly HubBroadcaster _broadcaster;
|
|
private readonly ILogger<TaskResetService> _logger;
|
|
|
|
public TaskResetService(
|
|
IDbContextFactory<ClaudeDoDbContext> dbFactory,
|
|
WorktreeManager wtManager,
|
|
HubBroadcaster broadcaster,
|
|
ILogger<TaskResetService> logger)
|
|
{
|
|
_dbFactory = dbFactory;
|
|
_wtManager = wtManager;
|
|
_broadcaster = broadcaster;
|
|
_logger = logger;
|
|
}
|
|
|
|
public async Task ResetAsync(string taskId, CancellationToken ct)
|
|
{
|
|
TaskEntity task;
|
|
ListEntity list;
|
|
WorktreeEntity? wt;
|
|
|
|
using (var ctx = _dbFactory.CreateDbContext())
|
|
{
|
|
task = await new TaskRepository(ctx).GetByIdAsync(taskId, ct)
|
|
?? throw new KeyNotFoundException($"Task '{taskId}' not found.");
|
|
|
|
if (task.Status == TaskStatus.Running)
|
|
throw new InvalidOperationException("Cannot reset a running task. Cancel it first.");
|
|
|
|
list = await new ListRepository(ctx).GetByIdAsync(task.ListId, ct)
|
|
?? throw new InvalidOperationException("List not found.");
|
|
|
|
wt = await new WorktreeRepository(ctx).GetByTaskIdAsync(taskId, ct);
|
|
}
|
|
|
|
bool worktreeChanged = false;
|
|
if (wt is not null && wt.State == WorktreeState.Active && list.WorkingDir is not null)
|
|
{
|
|
await _wtManager.DiscardAsync(wt, list.WorkingDir, ct);
|
|
worktreeChanged = true;
|
|
}
|
|
|
|
using (var ctx = _dbFactory.CreateDbContext())
|
|
{
|
|
await new TaskRepository(ctx).ResetToManualAsync(taskId, ct);
|
|
}
|
|
|
|
await _broadcaster.TaskUpdated(taskId);
|
|
if (worktreeChanged)
|
|
await _broadcaster.WorktreeUpdated(taskId);
|
|
|
|
_logger.LogInformation("Reset task {TaskId} to Manual (worktree discarded: {Discarded})", taskId, worktreeChanged);
|
|
}
|
|
}
|