feat(installer): add WPF installer/configurator project

Standalone WPF app (ClaudeDo.Installer) that handles full installation
and ongoing configuration of ClaudeDo. Two modes: wizard for first run,
tabbed settings panel for subsequent launches. Page-based extensibility
via IInstallerPage interface — adding new config sections requires only
one new class.

Install pipeline: dotnet publish, deploy binaries, write configs, init
DB (via SchemaInitializer from ClaudeDo.Data), register Windows Service,
create shortcuts. Dark theme matching the Avalonia app (forest teal accent).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
CubeGameLP
2026-04-14 21:01:03 +02:00
parent 2479bb6ea1
commit 78831b2263
47 changed files with 2351 additions and 0 deletions

View File

@@ -0,0 +1,79 @@
using System.Windows;
using ClaudeDo.Installer.Core;
using ClaudeDo.Installer.Pages.InstallPage;
using ClaudeDo.Installer.Pages.PathsPage;
using ClaudeDo.Installer.Pages.ServicePage;
using ClaudeDo.Installer.Pages.UiSettingsPage;
using ClaudeDo.Installer.Pages.WelcomePage;
using ClaudeDo.Installer.Steps;
using ClaudeDo.Installer.Views;
using Microsoft.Extensions.DependencyInjection;
namespace ClaudeDo.Installer;
public partial class App : Application
{
private ServiceProvider? _services;
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
var mode = ModeDetector.Detect();
_services = BuildServices();
Window mainWindow = mode switch
{
InstallerMode.Wizard => new WizardWindow
{
DataContext = _services.GetRequiredService<WizardViewModel>()
},
InstallerMode.Settings => new SettingsWindow
{
DataContext = _services.GetRequiredService<SettingsViewModel>()
},
_ => throw new InvalidOperationException($"Unknown installer mode: {mode}")
};
DarkTitleBar.Apply(mainWindow);
mainWindow.Show();
}
protected override void OnExit(ExitEventArgs e)
{
_services?.Dispose();
base.OnExit(e);
}
private static ServiceProvider BuildServices()
{
var sc = new ServiceCollection();
// Core
sc.AddSingleton<InstallContext>();
sc.AddSingleton<PageResolver>();
sc.AddSingleton<InstallerService>();
// Pages
sc.AddSingleton<IInstallerPage, WelcomePageViewModel>();
sc.AddSingleton<IInstallerPage, PathsPageViewModel>();
sc.AddSingleton<IInstallerPage, ServicePageViewModel>();
sc.AddSingleton<IInstallerPage, UiSettingsPageViewModel>();
sc.AddSingleton<IInstallerPage, InstallPageViewModel>();
// Steps (registration order = execution order)
sc.AddSingleton<IInstallStep, PublishAppStep>();
sc.AddSingleton<IInstallStep, PublishWorkerStep>();
sc.AddSingleton<IInstallStep, DeployBinariesStep>();
sc.AddSingleton<IInstallStep, WriteConfigStep>();
sc.AddSingleton<IInstallStep, InitDatabaseStep>();
sc.AddSingleton<IInstallStep, RegisterServiceStep>();
sc.AddSingleton<IInstallStep, CreateShortcutsStep>();
// ViewModels
sc.AddSingleton<WizardViewModel>();
sc.AddSingleton<SettingsViewModel>();
return sc.BuildServiceProvider();
}
}