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

@@ -1,3 +1,4 @@
using System;
using Avalonia;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Markup.Xaml;
@@ -10,7 +11,12 @@ namespace ClaudeDo.App;
public partial class App : Application
{
public static ServiceProvider Services { get; set; } = null!;
private readonly IServiceProvider? _services;
// Parameterless ctor is required by the XAML previewer / designer.
public App() { }
public App(IServiceProvider services) => _services = services;
public override void Initialize()
{
@@ -21,16 +27,19 @@ public partial class App : Application
{
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
{
var services = _services
?? throw new InvalidOperationException("App was constructed without a service provider.");
FocusClearing.Install();
desktop.MainWindow = new MainWindow
{
DataContext = Services.GetRequiredService<IslandsShellViewModel>(),
DataContext = services.GetRequiredService<IslandsShellViewModel>(),
};
// Kick off the SignalR retry loop — reconnects indefinitely if the worker
// is not up yet, or goes down and comes back.
_ = Services.GetRequiredService<WorkerClient>().StartAsync();
_ = services.GetRequiredService<WorkerClient>().StartAsync();
}
base.OnFrameworkInitializationCompleted();

View File

@@ -35,7 +35,6 @@ sealed class Program
SetCurrentProcessExplicitAppUserModelID("ClaudeDo.App");
var services = BuildServices();
App.Services = services;
using (var scope = services.CreateScope())
{
@@ -45,7 +44,7 @@ sealed class Program
try
{
BuildAvaloniaApp()
ConfigureAppBuilder(AppBuilder.Configure(() => new App(services)))
.StartWithClassicDesktopLifetime(args);
}
finally
@@ -58,8 +57,12 @@ sealed class Program
}
}
// Parameterless entry point required by the XAML previewer / designer.
public static AppBuilder BuildAvaloniaApp()
=> AppBuilder.Configure<App>()
=> ConfigureAppBuilder(AppBuilder.Configure<App>());
private static AppBuilder ConfigureAppBuilder(AppBuilder builder)
=> builder
.UsePlatformDetect()
#if DEBUG
.WithDeveloperTools()