refactor: extract interfaces to Interfaces folders and consolidate filters

Move interface declarations into per-area Interfaces/ subfolders, merge the
small task-list filter classes into StatusFilter/SmartFlagFilter, and simplify
related services, converters and hub DTO handling.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
mika kuns
2026-05-30 15:41:10 +02:00
parent 77100b6b3b
commit 41da124a31
42 changed files with 306 additions and 532 deletions

View File

@@ -111,6 +111,22 @@ public sealed class WorkerHub : Microsoft.AspNetCore.SignalR.Hub
_state = state;
}
// Maps the two exceptions service methods throw into client-facing HubExceptions:
// KeyNotFoundException -> notFoundMessage, InvalidOperationException -> its own message.
private static async Task HubGuard(Func<Task> action, string notFoundMessage = "task not found")
{
try { await action(); }
catch (KeyNotFoundException) { throw new HubException(notFoundMessage); }
catch (InvalidOperationException ex) { throw new HubException(ex.Message); }
}
private static async Task<T> HubGuard<T>(Func<Task<T>> action, string notFoundMessage = "task not found")
{
try { return await action(); }
catch (KeyNotFoundException) { throw new HubException(notFoundMessage); }
catch (InvalidOperationException ex) { throw new HubException(ex.Message); }
}
public async Task QueuePlanningSubtasksAsync(string parentTaskId)
{
try
@@ -157,37 +173,11 @@ public sealed class WorkerHub : Microsoft.AspNetCore.SignalR.Hub
}
}
public async Task<string> ContinueTask(string taskId, string followUpPrompt)
{
try
{
return await _queue.ContinueTask(taskId, followUpPrompt);
}
catch (InvalidOperationException ex)
{
throw new HubException(ex.Message);
}
catch (KeyNotFoundException)
{
throw new HubException("task not found");
}
}
public Task<string> ContinueTask(string taskId, string followUpPrompt)
=> HubGuard(() => _queue.ContinueTask(taskId, followUpPrompt));
public async Task ResetTask(string taskId)
{
try
{
await _resetService.ResetAsync(taskId, CancellationToken.None);
}
catch (InvalidOperationException ex)
{
throw new HubException(ex.Message);
}
catch (KeyNotFoundException)
{
throw new HubException("task not found");
}
}
public Task ResetTask(string taskId)
=> HubGuard(() => _resetService.ResetAsync(taskId, CancellationToken.None));
public bool CancelTask(string taskId) => _queue.CancelTask(taskId);
@@ -285,10 +275,9 @@ public sealed class WorkerHub : Microsoft.AspNetCore.SignalR.Hub
return new ForceRemoveResultDto(result.Removed, result.Reason);
}
public async Task<MergeResultDto> MergeTask(
public Task<MergeResultDto> MergeTask(
string taskId, string targetBranch, bool removeWorktree, string commitMessage)
{
try
=> HubGuard(async () =>
{
var r = await _mergeService.MergeAsync(
taskId,
@@ -297,33 +286,14 @@ public sealed class WorkerHub : Microsoft.AspNetCore.SignalR.Hub
string.IsNullOrWhiteSpace(commitMessage) ? "Merge task" : commitMessage,
CancellationToken.None);
return new MergeResultDto(r.Status, r.ConflictFiles, r.ErrorMessage);
}
catch (KeyNotFoundException)
{
throw new HubException("task not found");
}
catch (InvalidOperationException ex)
{
throw new HubException(ex.Message);
}
}
});
public async Task<MergeTargetsDto> GetMergeTargets(string taskId)
{
try
public Task<MergeTargetsDto> GetMergeTargets(string taskId)
=> HubGuard(async () =>
{
var t = await _mergeService.GetTargetsAsync(taskId, CancellationToken.None);
return new MergeTargetsDto(t.DefaultBranch, t.LocalBranches);
}
catch (KeyNotFoundException)
{
throw new HubException("task not found");
}
catch (InvalidOperationException ex)
{
throw new HubException(ex.Message);
}
}
});
public async Task UpdateList(UpdateListDto dto)
{
@@ -345,9 +315,9 @@ public sealed class WorkerHub : Microsoft.AspNetCore.SignalR.Hub
using var ctx = _dbFactory.CreateDbContext();
var repo = new ListRepository(ctx);
var model = Nullify(dto.Model);
var systemPrompt = Nullify(dto.SystemPrompt);
var agentPath = Nullify(dto.AgentPath);
var model = dto.Model.NullIfBlank();
var systemPrompt = dto.SystemPrompt.NullIfBlank();
var agentPath = dto.AgentPath.NullIfBlank();
if (model is null && systemPrompt is null && agentPath is null)
{
@@ -394,9 +364,9 @@ public sealed class WorkerHub : Microsoft.AspNetCore.SignalR.Hub
var repo = new TaskRepository(ctx);
await repo.UpdateAgentSettingsAsync(
dto.TaskId,
Nullify(dto.Model),
Nullify(dto.SystemPrompt),
Nullify(dto.AgentPath));
dto.Model.NullIfBlank(),
dto.SystemPrompt.NullIfBlank(),
dto.AgentPath.NullIfBlank());
await _broadcaster.TaskUpdated(dto.TaskId);
}
@@ -449,21 +419,16 @@ public sealed class WorkerHub : Microsoft.AspNetCore.SignalR.Hub
public Task<int> GetPendingDraftCountAsync(string taskId)
=> _planning.GetPendingDraftCountAsync(taskId, Context.ConnectionAborted);
public async Task<IReadOnlyList<SubtaskDiffDto>> GetPlanningAggregate(string planningTaskId)
{
try
public Task<IReadOnlyList<SubtaskDiffDto>> GetPlanningAggregate(string planningTaskId)
=> HubGuard<IReadOnlyList<SubtaskDiffDto>>(async () =>
{
var diffs = await _planningAggregator.GetAggregatedDiffAsync(planningTaskId, CancellationToken.None);
return diffs.Select(d => new SubtaskDiffDto(
d.SubtaskId, d.Title, d.BranchName, d.BaseCommit, d.HeadCommit, d.DiffStat, d.UnifiedDiff)).ToList();
}
catch (KeyNotFoundException) { throw new HubException("planning task not found"); }
catch (InvalidOperationException ex) { throw new HubException(ex.Message); }
}
}, "planning task not found");
public async Task<CombinedDiffResultDto> BuildPlanningIntegrationBranch(string planningTaskId, string targetBranch)
{
try
public Task<CombinedDiffResultDto> BuildPlanningIntegrationBranch(string planningTaskId, string targetBranch)
=> HubGuard(async () =>
{
var result = await _planningAggregator.BuildIntegrationBranchAsync(
planningTaskId, targetBranch ?? "", CancellationToken.None);
@@ -475,17 +440,11 @@ public sealed class WorkerHub : Microsoft.AspNetCore.SignalR.Hub
false, null, null, f.Value.FirstConflictSubtaskId, f.Value.ConflictedFiles),
_ => throw new InvalidOperationException("unknown result type"),
};
}
catch (KeyNotFoundException) { throw new HubException("planning task not found"); }
catch (InvalidOperationException ex) { throw new HubException(ex.Message); }
}
}, "planning task not found");
public async Task MergeAllPlanning(string planningTaskId, string targetBranch)
{
try { await _planningMergeOrchestrator.StartAsync(planningTaskId, targetBranch ?? "", CancellationToken.None); }
catch (KeyNotFoundException) { throw new HubException("planning task not found"); }
catch (InvalidOperationException ex) { throw new HubException(ex.Message); }
}
public Task MergeAllPlanning(string planningTaskId, string targetBranch)
=> HubGuard(() => _planningMergeOrchestrator.StartAsync(planningTaskId, targetBranch ?? "", CancellationToken.None),
"planning task not found");
public async Task ContinuePlanningMerge(string planningTaskId)
{
@@ -537,6 +496,4 @@ public sealed class WorkerHub : Microsoft.AspNetCore.SignalR.Hub
await new PrimeScheduleRepository(ctx).DeleteAsync(id);
_primeSignal.Signal();
}
private static string? Nullify(string? s) => string.IsNullOrWhiteSpace(s) ? null : s;
}