From 134b9fb598b513e48043a1f866700f51dc6e9e66 Mon Sep 17 00:00:00 2001 From: Mika Kuns Date: Tue, 23 Jun 2026 08:41:03 +0200 Subject: [PATCH] fix(ui): surface interactive/planning launch errors in footer --- src/ClaudeDo.Localization/locales/de.json | 10 +++++++++- src/ClaudeDo.Localization/locales/en.json | 10 +++++++++- .../ViewModels/Islands/TasksIslandViewModel.cs | 5 +++-- src/ClaudeDo.Ui/ViewModels/IslandsShellViewModel.cs | 12 ++++++++++++ 4 files changed, 33 insertions(+), 4 deletions(-) diff --git a/src/ClaudeDo.Localization/locales/de.json b/src/ClaudeDo.Localization/locales/de.json index cf35ead..4a02803 100644 --- a/src/ClaudeDo.Localization/locales/de.json +++ b/src/ClaudeDo.Localization/locales/de.json @@ -88,6 +88,14 @@ "inheritedFromGlobal": "geerbt · Global", "overrideBadge": "überschrieben", "resetToInherited": "Auf geerbt zurücksetzen" + }, + "agentEditor": { + "model": "Modell", + "maxTurns": "Max. Durchläufe", + "systemPrompt": "System-Prompt (angehängt)", + "promptPrepended": "Wird automatisch vorangestellt:", + "agentFile": "Agent-Datei", + "browse": "Durchsuchen..." } }, "tasks": { @@ -464,7 +472,7 @@ "taskStatus": { "idle": "Leerlauf", "queued": "In Warteschlange", "running": "Läuft", "waitingForReview": "Wartet auf Prüfung", "waitingForChildren": "Wartet auf Verbesserungen", "done": "Fertig", "failed": "Fehlgeschlagen", "cancelled": "Abgebrochen", "parked": "Geparkt" }, "planningBadge": { "active": "PLANUNG", "finalized": "GEPLANT" }, "taskRow": { "createdPrefix": "Erstellt {0}", "stepsText": "{0}/{1} Schritte" }, - "tasksIsland": { "completedHeader": "ABGESCHLOSSEN", "completedHeaderCount": "ABGESCHLOSSEN · {0}" }, + "tasksIsland": { "completedHeader": "ABGESCHLOSSEN", "completedHeaderCount": "ABGESCHLOSSEN · {0}", "runInteractiveFailed": "Interaktiv ausführen fehlgeschlagen: {0}", "planningOpenFailed": "Planungssitzung konnte nicht geöffnet werden: {0}" }, "diff": { "loadFailed": "Diff konnte nicht geladen werden: {0}", "noChanges": "Keine Änderungen anzuzeigen.", "unavailable": "Diff nicht mehr verfügbar — Commit-Bereich unvollständig." }, "planningDiff": { "hubError": "Kombinierte Vorschau konnte nicht erstellt werden (Hub-Fehler).", "conflict": "Kombinierte Vorschau nicht möglich: Teilaufgabe {0} steht im Konflikt mit einer früheren Teilaufgabe ({1} Dateien)." }, "merge": { "commitMessage": "Merge-Aufgabe: {0}", "workerOfflineBranches": "Worker offline — Branches können nicht aufgelistet werden.", "loadBranchesFailed": "Branches konnten nicht geladen werden: {0}", "merged": "Zusammengeführt.", "conflict": "Merge-Konflikt — Ziel-Branch wiederhergestellt. Manuell oder über Fortsetzen lösen, dann erneut versuchen.", "blocked": "Blockiert: {0}", "unknownStatus": "Unbekannter Status: {0}", "mergeFailed": "Merge fehlgeschlagen: {0}" }, diff --git a/src/ClaudeDo.Localization/locales/en.json b/src/ClaudeDo.Localization/locales/en.json index 1786344..6acf54f 100644 --- a/src/ClaudeDo.Localization/locales/en.json +++ b/src/ClaudeDo.Localization/locales/en.json @@ -88,6 +88,14 @@ "inheritedFromGlobal": "inherited · Global", "overrideBadge": "override", "resetToInherited": "Reset to inherited" + }, + "agentEditor": { + "model": "Model", + "maxTurns": "Max turns", + "systemPrompt": "System prompt (appended)", + "promptPrepended": "Prepended automatically:", + "agentFile": "Agent file", + "browse": "Browse..." } }, "tasks": { @@ -464,7 +472,7 @@ "taskStatus": { "idle": "Idle", "queued": "Queued", "running": "Running", "waitingForReview": "Waiting for Review", "waitingForChildren": "Waiting for Improvements", "done": "Done", "failed": "Failed", "cancelled": "Cancelled", "parked": "Parked" }, "planningBadge": { "active": "PLANNING", "finalized": "PLANNED" }, "taskRow": { "createdPrefix": "Created {0}", "stepsText": "{0}/{1} steps" }, - "tasksIsland": { "completedHeader": "COMPLETED", "completedHeaderCount": "COMPLETED · {0}" }, + "tasksIsland": { "completedHeader": "COMPLETED", "completedHeaderCount": "COMPLETED · {0}", "runInteractiveFailed": "Run interactively failed: {0}", "planningOpenFailed": "Couldn't open planning session: {0}" }, "diff": { "loadFailed": "Failed to load diff: {0}", "noChanges": "No changes to show.", "unavailable": "Diff no longer available — commit range incomplete." }, "planningDiff": { "hubError": "Could not build combined preview (hub error).", "conflict": "Cannot build combined preview: subtask {0} conflicts with an earlier subtask ({1} files)." }, "merge": { "commitMessage": "Merge task: {0}", "workerOfflineBranches": "Worker offline — cannot list branches.", "loadBranchesFailed": "Failed to load branches: {0}", "merged": "Merged.", "conflict": "Merge conflict — target branch restored. Resolve manually or via Continue, then retry.", "blocked": "Blocked: {0}", "unknownStatus": "Unknown status: {0}", "mergeFailed": "Merge failed: {0}" }, diff --git a/src/ClaudeDo.Ui/ViewModels/Islands/TasksIslandViewModel.cs b/src/ClaudeDo.Ui/ViewModels/Islands/TasksIslandViewModel.cs index 0b877d3..e7c7fde 100644 --- a/src/ClaudeDo.Ui/ViewModels/Islands/TasksIslandViewModel.cs +++ b/src/ClaudeDo.Ui/ViewModels/Islands/TasksIslandViewModel.cs @@ -28,6 +28,7 @@ public sealed partial class TasksIslandViewModel : ViewModelBase, IDisposable public event EventHandler? TasksChanged; public event Action? NotesRequested; public event Action? PrepRequested; + public event Action? ErrorReported; public void RequestFocusAddTask() => FocusAddTaskRequested?.Invoke(this, EventArgs.Empty); [RelayCommand] @@ -770,7 +771,7 @@ public sealed partial class TasksIslandViewModel : ViewModelBase, IDisposable if (row.Status != TaskStatus.Idle || row.PlanningPhase != PlanningPhase.None) return; ForegroundHelper.AllowAny(); try { await _worker!.StartPlanningSessionAsync(row.Id); } - catch { } + catch (Exception ex) { ErrorReported?.Invoke(Loc.T("vm.tasksIsland.planningOpenFailed", ex.Message)); } } [RelayCommand] @@ -779,7 +780,7 @@ public sealed partial class TasksIslandViewModel : ViewModelBase, IDisposable if (row is null || _worker is null) return; ForegroundHelper.AllowAny(); try { await _worker.OpenInteractiveTerminalAsync(row.Id); } - catch { } + catch (Exception ex) { ErrorReported?.Invoke(Loc.T("vm.tasksIsland.runInteractiveFailed", ex.Message)); } } [RelayCommand] diff --git a/src/ClaudeDo.Ui/ViewModels/IslandsShellViewModel.cs b/src/ClaudeDo.Ui/ViewModels/IslandsShellViewModel.cs index a11a6b6..c97d891 100644 --- a/src/ClaudeDo.Ui/ViewModels/IslandsShellViewModel.cs +++ b/src/ClaudeDo.Ui/ViewModels/IslandsShellViewModel.cs @@ -125,6 +125,17 @@ public sealed partial class IslandsShellViewModel : ViewModelBase, IDisposable WorkerLogText = null; } + // Surfaces a UI-originated failure in the footer status strip (same line as the + // worker log), color-coded as an error and auto-cleared by _clearTimer. + public void FlashFooterError(string message) + { + WorkerLogText = $"{DateTime.Now:HH:mm} · {message}"; + WorkerLogLevel = WorkerLogLevel.Error; + IsWorkerLogVisible = true; + _clearTimer.Stop(); + _clearTimer.Start(); + } + private void OnPrimeFired(PrimeFiredEvent evt) { var when = evt.FiredAt.LocalDateTime.ToString("HH:mm"); @@ -181,6 +192,7 @@ public sealed partial class IslandsShellViewModel : ViewModelBase, IDisposable Tasks.SelectionChanged += (_, _) => Details.Bind(Tasks.SelectedTask); Tasks.NotesRequested += () => Details.ShowNotes(); Tasks.PrepRequested += () => Details.ShowPrep(); + Tasks.ErrorReported += FlashFooterError; Tasks.TasksChanged += (_, _) => _ = Lists.RefreshCountsAsync(); Tasks.OpenListSettingsRequested += (_, _) => {