From 786eb2877f7161b82a645f975d728547a6aa4fe4 Mon Sep 17 00:00:00 2001 From: Mika Kuns Date: Fri, 26 Jun 2026 10:42:04 +0200 Subject: [PATCH] feat(ui): highlight user chat messages + opt-in interrupt (stop) button MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit LogKindForegroundConverter drives the log message foreground via a local binding (beats the dim local value), so user messages render in the accent color instead of vanishing into the transcript. Adds a small stop (Icon.Stop) button next to Send in both composers (SessionTerminalView + WorkConsole) wired to InterruptInteractiveCommand → InterruptInteractiveSessionAsync. Adds session.composer.interrupt (en/de). --- src/ClaudeDo.App/App.axaml | 1 + src/ClaudeDo.Localization/locales/de.json | 3 +- src/ClaudeDo.Localization/locales/en.json | 3 +- .../Converters/LogKindForegroundConverter.cs | 43 +++++++++++++++++++ src/ClaudeDo.Ui/Design/IslandStyles.axaml | 3 ++ .../Islands/TaskMonitorViewModel.cs | 7 +++ .../Views/Islands/Detail/WorkConsole.axaml | 12 ++++-- .../Views/Islands/SessionTerminalView.axaml | 11 ++++- .../Islands/SessionTerminalView.axaml.cs | 3 ++ .../MissionControl/MonitorPaneView.axaml | 1 + .../ViewModels/TaskMonitorViewModelTests.cs | 14 ++++++ 11 files changed, 94 insertions(+), 7 deletions(-) create mode 100644 src/ClaudeDo.Ui/Converters/LogKindForegroundConverter.cs diff --git a/src/ClaudeDo.App/App.axaml b/src/ClaudeDo.App/App.axaml index dd4a14d..aea3954 100644 --- a/src/ClaudeDo.App/App.axaml +++ b/src/ClaudeDo.App/App.axaml @@ -21,6 +21,7 @@ + diff --git a/src/ClaudeDo.Localization/locales/de.json b/src/ClaudeDo.Localization/locales/de.json index a9671f3..3381a55 100644 --- a/src/ClaudeDo.Localization/locales/de.json +++ b/src/ClaudeDo.Localization/locales/de.json @@ -235,7 +235,8 @@ "composer": { "placeholder": "Nachricht an die Sitzung…", "send": "Senden", - "stop": "Sitzung beenden" + "stop": "Sitzung beenden", + "interrupt": "Aktuellen Zug unterbrechen" } }, "missionControl": { diff --git a/src/ClaudeDo.Localization/locales/en.json b/src/ClaudeDo.Localization/locales/en.json index 0115698..82afbc4 100644 --- a/src/ClaudeDo.Localization/locales/en.json +++ b/src/ClaudeDo.Localization/locales/en.json @@ -235,7 +235,8 @@ "composer": { "placeholder": "Message the session…", "send": "Send", - "stop": "Stop session" + "stop": "Stop session", + "interrupt": "Interrupt current turn" } }, "missionControl": { diff --git a/src/ClaudeDo.Ui/Converters/LogKindForegroundConverter.cs b/src/ClaudeDo.Ui/Converters/LogKindForegroundConverter.cs new file mode 100644 index 0000000..3546100 --- /dev/null +++ b/src/ClaudeDo.Ui/Converters/LogKindForegroundConverter.cs @@ -0,0 +1,43 @@ +using System.Globalization; +using Avalonia; +using Avalonia.Data.Converters; +using Avalonia.Media; +using Avalonia.Styling; +using ClaudeDo.Ui.ViewModels.Islands; + +namespace ClaudeDo.Ui.Converters; + +public sealed class LogKindForegroundConverter : IValueConverter +{ + private static IBrush? Resolve(string key) + { + if (Application.Current is { } app && + app.Resources.TryGetResource(key, app.ActualThemeVariant, out var res) && + res is IBrush brush) + { + return brush; + } + return null; + } + + public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture) + { + var key = value is LogKind kind ? kind switch + { + LogKind.Sys => "TextMuteBrush", + LogKind.Tool => "SageBrush", + LogKind.Claude => "TextBrush", + LogKind.Stdout => "TextDimBrush", + LogKind.Stderr => "BloodBrush", + LogKind.Done => "MossBrightBrush", + LogKind.Msg => "TextDimBrush", + LogKind.User => "AccentBrush", + _ => "TextDimBrush", + } : "TextDimBrush"; + + return Resolve(key) ?? AvaloniaProperty.UnsetValue; + } + + public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture) => + throw new NotSupportedException(); +} diff --git a/src/ClaudeDo.Ui/Design/IslandStyles.axaml b/src/ClaudeDo.Ui/Design/IslandStyles.axaml index 194be8c..5d39140 100644 --- a/src/ClaudeDo.Ui/Design/IslandStyles.axaml +++ b/src/ClaudeDo.Ui/Design/IslandStyles.axaml @@ -84,6 +84,9 @@ M6.4 4.6 L12 10.2 L17.6 4.6 L19.4 6.4 L13.8 12 L19.4 17.6 L17.6 19.4 L12 13.8 L6.4 19.4 L4.6 17.6 L10.2 12 L4.6 6.4 Z + + M4 4 H20 V20 H4 Z + M4 12l5 5 11-11 diff --git a/src/ClaudeDo.Ui/ViewModels/Islands/TaskMonitorViewModel.cs b/src/ClaudeDo.Ui/ViewModels/Islands/TaskMonitorViewModel.cs index 9074d89..872b4d7 100644 --- a/src/ClaudeDo.Ui/ViewModels/Islands/TaskMonitorViewModel.cs +++ b/src/ClaudeDo.Ui/ViewModels/Islands/TaskMonitorViewModel.cs @@ -203,6 +203,13 @@ public sealed partial class TaskMonitorViewModel : ViewModelBase, IDisposable await _worker.StopInteractiveSessionAsync(_subscribedTaskId); } + [RelayCommand] + private async System.Threading.Tasks.Task InterruptInteractive() + { + if (!string.IsNullOrEmpty(_subscribedTaskId) && IsInteractiveLive) + await _worker.InterruptInteractiveSessionAsync(_subscribedTaskId); + } + private void ClearPendingQuestion() { PendingQuestionId = null; diff --git a/src/ClaudeDo.Ui/Views/Islands/Detail/WorkConsole.axaml b/src/ClaudeDo.Ui/Views/Islands/Detail/WorkConsole.axaml index 1a91f03..e89c096 100644 --- a/src/ClaudeDo.Ui/Views/Islands/Detail/WorkConsole.axaml +++ b/src/ClaudeDo.Ui/Views/Islands/Detail/WorkConsole.axaml @@ -267,7 +267,7 @@ only while an interactive session is running for this task. --> - + +