feat(claude-do): „Claude Help Me"-Button: Claude-Session zur Setup-Fehlersuch

Der Button, der aus „Problem erkannt" ein „Problem gelöst" macht: startet eine interaktive Claude-Session, die dem Nutzer beim Einrichten hilft.

## Warum externes Terminal
Der ConPTY-Stack (`PtyTerminalSession`, `ConPtyPaneView`) liegt in `ClaudeDo.Ui` und ist Avalonia — der Installer ist WPF und referenziert nur Data/Releases/Localization. Beim Fresh Install sind `app\`/`worker\` außerdem noch n

ClaudeDo-Task: 4e196058-38a3-404f-9862-4cb0e90195da
This commit is contained in:
mika kuns
2026-08-06 08:25:36 +02:00
parent b3a8373c70
commit 09e0772673
16 changed files with 630 additions and 35 deletions
@@ -90,10 +90,18 @@
</StackPanel>
<!-- Footer -->
<StackPanel Grid.Row="3" Orientation="Horizontal" HorizontalAlignment="Right" Margin="0,12,0,0">
<!-- Reserved space: a "Claude Help Me" button lands here in a follow-up task. -->
<Button Content="{loc:Tr installer.systemCheck.recheck}"
Command="{Binding RunChecksCommand}"/>
<StackPanel Grid.Row="3" Margin="0,12,0,0">
<TextBlock Text="{Binding ClaudeHelpError}" FontSize="12" TextWrapping="Wrap"
Foreground="{StaticResource ErrorBrush}" Margin="0,0,0,8"
Visibility="{Binding ClaudeHelpError, Converter={StaticResource NullToCollapsedConverter}}"/>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
<Button Content="{loc:Tr installer.systemCheck.claudeHelp.button}"
ToolTip="{Binding ClaudeHelpTooltip}"
Command="{Binding StartClaudeHelpCommand}"
Margin="0,0,8,0"/>
<Button Content="{loc:Tr installer.systemCheck.recheck}"
Command="{Binding RunChecksCommand}"/>
</StackPanel>
</StackPanel>
</Grid>
</UserControl>
@@ -51,8 +51,10 @@ public partial class SystemCheckPageViewModel : ObservableObject, IInstallerPage
{
private readonly InstallContext _context;
private readonly Func<EnvironmentCheckService> _checkServiceFactory;
private readonly ClaudeHelpLauncher _claudeHelpLauncher;
private SystemCheckPageView? _view;
private bool _hasStarted;
private EnvironmentCheckReport? _lastReport;
public string Title => TrExtension.Localizer?["installer.systemCheck.title"] ?? "System Check";
public string Icon => "";
@@ -67,13 +69,40 @@ public partial class SystemCheckPageViewModel : ObservableObject, IInstallerPage
[ObservableProperty] private bool _hasRun;
[ObservableProperty] private bool _hasBlockingError;
[ObservableProperty] private string _summary = string.Empty;
[ObservableProperty] private string? _claudeHelpError;
public bool BlocksNavigation => IsRunning || HasBlockingError;
public SystemCheckPageViewModel(InstallContext context, Func<EnvironmentCheckService> checkServiceFactory)
public bool ClaudeCliOk =>
_lastReport?.Results.FirstOrDefault(r => r.Id == ClaudeCliCheck.CheckId)?.Status == CheckStatus.Ok;
public bool ClaudeAuthFailed =>
_lastReport?.Results.FirstOrDefault(r => r.Id == ClaudeAuthCheck.CheckId)?.Status == CheckStatus.Failed;
public bool CanStartClaudeHelp => ClaudeCliOk && !ClaudeAuthFailed;
public string ClaudeHelpTooltip
{
get
{
var loc = TrExtension.Localizer;
if (!ClaudeCliOk)
return loc?["installer.systemCheck.claudeHelp.tooltip.cliMissing"] ?? "The Claude CLI was not found.";
if (ClaudeAuthFailed)
return loc?["installer.systemCheck.claudeHelp.tooltip.notLoggedIn"] ?? "Claude is not logged in.";
return loc?["installer.systemCheck.claudeHelp.tooltip.ready"]
?? "Start an interactive Claude session to help troubleshoot your setup.";
}
}
public SystemCheckPageViewModel(
InstallContext context,
Func<EnvironmentCheckService> checkServiceFactory,
ClaudeHelpLauncher claudeHelpLauncher)
{
_context = context;
_checkServiceFactory = checkServiceFactory;
_claudeHelpLauncher = claudeHelpLauncher;
}
partial void OnIsRunningChanged(bool value)
@@ -115,9 +144,14 @@ public partial class SystemCheckPageViewModel : ObservableObject, IInstallerPage
foreach (var result in report.Results)
Rows.Add(new CheckRowViewModel(result));
_lastReport = report;
HasBlockingError = report.HasBlockingError;
Summary = BuildSummary(report);
HasRun = true;
OnPropertyChanged(nameof(CanStartClaudeHelp));
OnPropertyChanged(nameof(ClaudeHelpTooltip));
StartClaudeHelpCommand.NotifyCanExecuteChanged();
}
finally
{
@@ -127,6 +161,20 @@ public partial class SystemCheckPageViewModel : ObservableObject, IInstallerPage
private bool CanRunChecks() => !IsRunning;
[RelayCommand(CanExecute = nameof(CanStartClaudeHelp))]
private async Task StartClaudeHelpAsync()
{
if (_lastReport is null) return;
ClaudeHelpError = null;
var result = await _claudeHelpLauncher.LaunchAsync(_lastReport, _context, CancellationToken.None);
if (!result.Success)
{
ClaudeHelpError = TrExtension.Localizer?.Get("installer.systemCheck.claudeHelp.error", result.ErrorMessage ?? "")
?? $"Could not start the Claude session: {result.ErrorMessage}";
}
}
private static string BuildSummary(EnvironmentCheckReport report)
{
var loc = TrExtension.Localizer;