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:
@@ -194,6 +194,9 @@ public interface IWorkerClient : INotifyPropertyChanged
|
||||
Task<(bool Ok, string? Error)> SetWorktreeStateAsync(string taskId, WorktreeState newState);
|
||||
Task<ForceRemoveResultDto?> ForceRemoveWorktreeAsync(string taskId);
|
||||
|
||||
Task<ClaudeBinDto?> GetClaudeBinAsync();
|
||||
Task<ClaudeBinDto?> SetClaudeBinAsync(string? value);
|
||||
|
||||
Task<OnlineInboxStateDto?> GetOnlineInboxStateAsync();
|
||||
Task SetOnlineInboxConfigAsync(OnlineInboxConfigInputDto input);
|
||||
Task SetOnlineInboxAuthAsync(string refreshToken);
|
||||
|
||||
@@ -664,6 +664,12 @@ public partial class WorkerClient : ObservableObject, IAsyncDisposable, IWorkerC
|
||||
await InvokeTimedAsync("QueuePlanningSubtasksAsync", () => _hub.InvokeAsync("QueuePlanningSubtasksAsync", parentTaskId, ct));
|
||||
}
|
||||
|
||||
public Task<ClaudeBinDto?> GetClaudeBinAsync()
|
||||
=> TryInvokeAsync<ClaudeBinDto>("GetClaudeBin");
|
||||
|
||||
public Task<ClaudeBinDto?> SetClaudeBinAsync(string? value)
|
||||
=> TryInvokeAsync<ClaudeBinDto>("SetClaudeBin", value);
|
||||
|
||||
public Task<OnlineInboxStateDto?> GetOnlineInboxStateAsync()
|
||||
=> TryInvokeAsync<OnlineInboxStateDto>("GetOnlineInboxState");
|
||||
|
||||
|
||||
@@ -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))]
|
||||
|
||||
Reference in New Issue
Block a user