refactor: address code smells (run-dir helper, App DI injection)

- TaskRunner: extract worktree-vs-sandbox selection into
  PrepareRunDirectoryAsync so RunAsync reads linearly (a small helper, not
  a Strategy pattern — overkill for a two-way branch).
- App: drop the public static ServiceProvider locator; inject the provider
  via constructor through AppBuilder.Configure(() => new App(services)).
  Parameterless ctor + BuildAvaloniaApp() retained for the XAML designer.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
mika kuns
2026-06-04 11:33:10 +02:00
parent 72a86fc173
commit 3756b81817
4 changed files with 50 additions and 29 deletions

View File

@@ -64,29 +64,14 @@ public sealed class TaskRunner
}
// Determine working directory: worktree or sandbox.
WorktreeContext? wtCtx = null;
string runDir;
if (list.WorkingDir is not null)
var prep = await PrepareRunDirectoryAsync(task, list, ct);
if (prep.FailureReason is not null)
{
try
{
wtCtx = await _wtManager.CreateAsync(task, list, ct);
await _broadcaster.WorkerLog($"Created worktree for \"{task.Title}\"", WorkerLogLevel.Info, DateTime.UtcNow);
runDir = wtCtx.WorktreePath;
}
catch (Exception ex)
{
_logger.LogError(ex, "Failed to create worktree for task {TaskId}", task.Id);
await MarkFailed(task.Id, task.Title, slot, $"Worktree creation failed: {ex.Message}");
return;
}
}
else
{
runDir = Path.Combine(_cfg.SandboxRoot, task.Id);
Directory.CreateDirectory(runDir);
await MarkFailed(task.Id, task.Title, slot, prep.FailureReason);
return;
}
var wtCtx = prep.WtCtx;
var runDir = prep.RunDir!;
var resolvedConfig = await ResolveConfigAsync(task, listConfig, null, ct);
@@ -216,6 +201,30 @@ public sealed class TaskRunner
await _broadcaster.TaskUpdated(taskId);
}
private readonly record struct RunDirResult(string? RunDir, WorktreeContext? WtCtx, string? FailureReason);
private async Task<RunDirResult> PrepareRunDirectoryAsync(TaskEntity task, ListEntity list, CancellationToken ct)
{
if (list.WorkingDir is not null)
{
try
{
var wtCtx = await _wtManager.CreateAsync(task, list, ct);
await _broadcaster.WorkerLog($"Created worktree for \"{task.Title}\"", WorkerLogLevel.Info, DateTime.UtcNow);
return new RunDirResult(wtCtx.WorktreePath, wtCtx, null);
}
catch (Exception ex)
{
_logger.LogError(ex, "Failed to create worktree for task {TaskId}", task.Id);
return new RunDirResult(null, null, $"Worktree creation failed: {ex.Message}");
}
}
var sandboxDir = Path.Combine(_cfg.SandboxRoot, task.Id);
Directory.CreateDirectory(sandboxDir);
return new RunDirResult(sandboxDir, null, null);
}
private async Task<RunResult> RunOnceAsync(
string taskId, string taskTitle, string slot, string runDir, ClaudeRunConfig config,
int runNumber, bool isRetry, string prompt, CancellationToken ct)