feat(settings): claude_bin im Dateien-Tab setzbar, mit Auflösungs-Check

Bisher nur per Hand in worker.config.json. Neuer Abschnitt CLAUDE CLI mit
eigenem Save-Button (die Datei gehoert dem Worker, nicht app_settings) und einer
Zeile, wohin der Wert per ExecutableResolver tatsaechlich aufloest — 'nicht im
PATH gefunden' war bisher erst am fehlgeschlagenen Run zu sehen. WorkerConfig ist
DI-Singleton und ClaudeProcess loest pro Spawn auf, also greift die Aenderung ab
dem naechsten Run ohne Neustart.

SaveOnlineInbox/SaveClaudeBin teilen jetzt ein SaveKey(), damit beide dieselbe
read-modify-write-Semantik haben (alle anderen Keys bleiben unberuehrt).
Die zugehoerigen Locale-Keys sind im vorigen Commit mitgelaufen.
This commit is contained in:
mika kuns
2026-08-27 10:39:25 +02:00
parent 31d53b0033
commit 13b81cac68
9 changed files with 124 additions and 1 deletions
@@ -12,6 +12,12 @@ public sealed partial class FilesSettingsTabViewModel : ViewModelBase
private readonly IWorkerClient _worker;
public OperationStatus RestoreOp { get; } = new();
public OperationStatus ClaudeBinOp { get; } = new();
// worker.config.json's claude_bin: a command name or a full path to the CLI. Saved on its own
// (not with the modal's Save button) because the worker owns the file, not app_settings.
[ObservableProperty] private string _claudeBin = "";
[ObservableProperty] private string _claudeBinResolvedHint = "";
[ObservableProperty] private string _statusMessage = "";
[ObservableProperty] private bool _hasCustomizedPrompts;
@@ -37,6 +43,34 @@ public sealed partial class FilesSettingsTabViewModel : ViewModelBase
};
}
public async Task LoadClaudeBinAsync()
{
var dto = await _worker.GetClaudeBinAsync();
if (dto is null) return;
ClaudeBin = dto.Value;
ApplyResolvedHint(dto);
}
[RelayCommand]
private async Task SaveClaudeBin()
{
StatusMessage = "";
using var op = ClaudeBinOp.Begin(Loc.T("ops.claudeBin.saving"));
var dto = await _worker.SetClaudeBinAsync(ClaudeBin);
if (dto is null)
{
StatusMessage = Loc.T("vm.filesTab.workerOffline");
return;
}
ClaudeBin = dto.Value;
ApplyResolvedHint(dto);
}
private void ApplyResolvedHint(ClaudeBinDto dto) =>
ClaudeBinResolvedHint = dto.ResolvedPath is null
? Loc.T("settings.files.claudeBinUnresolved")
: Loc.T("settings.files.claudeBinResolved", dto.ResolvedPath);
private bool CanRestoreDefaultAgents() => !RestoreOp.IsRunning;
[RelayCommand(CanExecute = nameof(CanRestoreDefaultAgents))]