feat(ui): interactive chat composer in the session terminal + work console
SessionTerminalView gains an opt-in composer (IsComposerVisible / ComposerText / SubmitCommand / ComposerPlaceholder styled props); Mission Control binds it to the monitor VM. Task detail's WorkConsole output tab gets a matching shell-prompt composer bound through Monitor.*, shown only while an interactive session is live. log-user lines render in the accent color. Adds session.composer.* (en/de).
This commit is contained in:
@@ -231,7 +231,12 @@
|
|||||||
"chipDone": "FERTIG",
|
"chipDone": "FERTIG",
|
||||||
"chipFailed": "FEHLGESCHLAGEN",
|
"chipFailed": "FEHLGESCHLAGEN",
|
||||||
"reviewContinueTip": "Dieses Feedback senden und die Aufgabe erneut ausführen",
|
"reviewContinueTip": "Dieses Feedback senden und die Aufgabe erneut ausführen",
|
||||||
"reviewResetTip": "Alle Änderungen verwerfen und die Aufgabe auf Leerlauf zurücksetzen"
|
"reviewResetTip": "Alle Änderungen verwerfen und die Aufgabe auf Leerlauf zurücksetzen",
|
||||||
|
"composer": {
|
||||||
|
"placeholder": "Nachricht an die Sitzung…",
|
||||||
|
"send": "Senden",
|
||||||
|
"stop": "Sitzung beenden"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"missionControl": {
|
"missionControl": {
|
||||||
"openInApp": "In App öffnen",
|
"openInApp": "In App öffnen",
|
||||||
|
|||||||
@@ -231,7 +231,12 @@
|
|||||||
"chipDone": "DONE",
|
"chipDone": "DONE",
|
||||||
"chipFailed": "FAILED",
|
"chipFailed": "FAILED",
|
||||||
"reviewContinueTip": "Send this feedback and re-run the task",
|
"reviewContinueTip": "Send this feedback and re-run the task",
|
||||||
"reviewResetTip": "Discard all changes and reset the task to Idle"
|
"reviewResetTip": "Discard all changes and reset the task to Idle",
|
||||||
|
"composer": {
|
||||||
|
"placeholder": "Message the session…",
|
||||||
|
"send": "Send",
|
||||||
|
"stop": "Stop session"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"missionControl": {
|
"missionControl": {
|
||||||
"openInApp": "Open in app",
|
"openInApp": "Open in app",
|
||||||
|
|||||||
@@ -528,6 +528,10 @@
|
|||||||
<Style Selector="Border.terminal TextBlock[Tag=log-msg]">
|
<Style Selector="Border.terminal TextBlock[Tag=log-msg]">
|
||||||
<Setter Property="Foreground" Value="{StaticResource TextDimBrush}" />
|
<Setter Property="Foreground" Value="{StaticResource TextDimBrush}" />
|
||||||
</Style>
|
</Style>
|
||||||
|
<!-- log-user: user's own messages in interactive sessions — accent color to stand out -->
|
||||||
|
<Style Selector="Border.terminal TextBlock[Tag=log-user]">
|
||||||
|
<Setter Property="Foreground" Value="{DynamicResource AccentBrush}" />
|
||||||
|
</Style>
|
||||||
|
|
||||||
<!-- ============================================================ -->
|
<!-- ============================================================ -->
|
||||||
<!-- TERMINAL HEADER -->
|
<!-- TERMINAL HEADER -->
|
||||||
|
|||||||
@@ -263,6 +263,36 @@
|
|||||||
Command="{Binding RejectReviewCommand}" />
|
Command="{Binding RejectReviewCommand}" />
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
|
<!-- Interactive composer — chat with a live in-app session; shell-prompt style,
|
||||||
|
only while an interactive session is running for this task. -->
|
||||||
|
<Grid DockPanel.Dock="Bottom"
|
||||||
|
IsVisible="{Binding Monitor.IsInteractiveLive}"
|
||||||
|
ColumnDefinitions="Auto,*,Auto"
|
||||||
|
Margin="12,2,12,8">
|
||||||
|
<TextBlock Grid.Column="0" Text="❯"
|
||||||
|
FontFamily="{StaticResource MonoFont}"
|
||||||
|
FontSize="{StaticResource FontSizeMono}"
|
||||||
|
Foreground="{DynamicResource AccentBrush}"
|
||||||
|
VerticalAlignment="Center" Margin="0,0,8,0" />
|
||||||
|
<TextBox Grid.Column="1"
|
||||||
|
Classes="review-prompt"
|
||||||
|
Text="{Binding Monitor.ComposerDraft, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
|
||||||
|
AcceptsReturn="False"
|
||||||
|
TextWrapping="Wrap"
|
||||||
|
MaxHeight="160"
|
||||||
|
PlaceholderText="{loc:Tr session.composer.placeholder}"
|
||||||
|
VerticalContentAlignment="Center"
|
||||||
|
FontFamily="{StaticResource MonoFont}"
|
||||||
|
FontSize="{StaticResource FontSizeMono}">
|
||||||
|
<TextBox.KeyBindings>
|
||||||
|
<KeyBinding Gesture="Enter" Command="{Binding Monitor.SubmitComposerCommand}" />
|
||||||
|
</TextBox.KeyBindings>
|
||||||
|
</TextBox>
|
||||||
|
<Button Grid.Column="2" Classes="prompt-action accent" Content="[Send]"
|
||||||
|
VerticalAlignment="Center" Margin="12,0,0,0"
|
||||||
|
Command="{Binding Monitor.SubmitComposerCommand}" />
|
||||||
|
</Grid>
|
||||||
|
|
||||||
<ScrollViewer Name="LogScroll"
|
<ScrollViewer Name="LogScroll"
|
||||||
VerticalScrollBarVisibility="Visible"
|
VerticalScrollBarVisibility="Visible"
|
||||||
AllowAutoHide="False"
|
AllowAutoHide="False"
|
||||||
|
|||||||
@@ -50,6 +50,29 @@
|
|||||||
</Border>
|
</Border>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
|
<!-- ── Composer bar ── -->
|
||||||
|
<Border DockPanel.Dock="Bottom"
|
||||||
|
IsVisible="{Binding #Root.IsComposerVisible}"
|
||||||
|
Background="{DynamicResource Surface2Brush}"
|
||||||
|
BorderBrush="{DynamicResource LineBrush}"
|
||||||
|
BorderThickness="0,1,0,0"
|
||||||
|
Padding="6,5">
|
||||||
|
<Grid ColumnDefinitions="*,Auto">
|
||||||
|
<TextBox Grid.Column="0"
|
||||||
|
Text="{Binding #Root.ComposerText, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
|
||||||
|
PlaceholderText="{Binding #Root.ComposerPlaceholder}"
|
||||||
|
AcceptsReturn="False">
|
||||||
|
<TextBox.KeyBindings>
|
||||||
|
<KeyBinding Gesture="Enter" Command="{Binding #Root.SubmitCommand}"/>
|
||||||
|
</TextBox.KeyBindings>
|
||||||
|
</TextBox>
|
||||||
|
<Button Grid.Column="1"
|
||||||
|
Margin="6,0,0,0"
|
||||||
|
Content="{loc:Tr session.composer.send}"
|
||||||
|
Command="{Binding #Root.SubmitCommand}"/>
|
||||||
|
</Grid>
|
||||||
|
</Border>
|
||||||
|
|
||||||
<!-- ── Log output ── -->
|
<!-- ── Log output ── -->
|
||||||
<ScrollViewer Name="LogScroll"
|
<ScrollViewer Name="LogScroll"
|
||||||
VerticalScrollBarVisibility="Visible"
|
VerticalScrollBarVisibility="Visible"
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Collections.Specialized;
|
using System.Collections.Specialized;
|
||||||
|
using System.Windows.Input;
|
||||||
using Avalonia;
|
using Avalonia;
|
||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
|
using Avalonia.Data;
|
||||||
|
|
||||||
namespace ClaudeDo.Ui.Views.Islands;
|
namespace ClaudeDo.Ui.Views.Islands;
|
||||||
|
|
||||||
@@ -17,12 +19,24 @@ public partial class SessionTerminalView : UserControl
|
|||||||
AvaloniaProperty.Register<SessionTerminalView, bool>(nameof(IsDone));
|
AvaloniaProperty.Register<SessionTerminalView, bool>(nameof(IsDone));
|
||||||
public static readonly StyledProperty<bool> IsFailedProperty =
|
public static readonly StyledProperty<bool> IsFailedProperty =
|
||||||
AvaloniaProperty.Register<SessionTerminalView, bool>(nameof(IsFailed));
|
AvaloniaProperty.Register<SessionTerminalView, bool>(nameof(IsFailed));
|
||||||
|
public static readonly StyledProperty<bool> IsComposerVisibleProperty =
|
||||||
|
AvaloniaProperty.Register<SessionTerminalView, bool>(nameof(IsComposerVisible), defaultValue: false);
|
||||||
|
public static readonly StyledProperty<string?> ComposerTextProperty =
|
||||||
|
AvaloniaProperty.Register<SessionTerminalView, string?>(nameof(ComposerText), defaultBindingMode: BindingMode.TwoWay);
|
||||||
|
public static readonly StyledProperty<ICommand?> SubmitCommandProperty =
|
||||||
|
AvaloniaProperty.Register<SessionTerminalView, ICommand?>(nameof(SubmitCommand));
|
||||||
|
public static readonly StyledProperty<string?> ComposerPlaceholderProperty =
|
||||||
|
AvaloniaProperty.Register<SessionTerminalView, string?>(nameof(ComposerPlaceholder));
|
||||||
|
|
||||||
public IEnumerable? Entries { get => GetValue(EntriesProperty); set => SetValue(EntriesProperty, value); }
|
public IEnumerable? Entries { get => GetValue(EntriesProperty); set => SetValue(EntriesProperty, value); }
|
||||||
public string? Label { get => GetValue(LabelProperty); set => SetValue(LabelProperty, value); }
|
public string? Label { get => GetValue(LabelProperty); set => SetValue(LabelProperty, value); }
|
||||||
public bool IsRunning { get => GetValue(IsRunningProperty); set => SetValue(IsRunningProperty, value); }
|
public bool IsRunning { get => GetValue(IsRunningProperty); set => SetValue(IsRunningProperty, value); }
|
||||||
public bool IsDone { get => GetValue(IsDoneProperty); set => SetValue(IsDoneProperty, value); }
|
public bool IsDone { get => GetValue(IsDoneProperty); set => SetValue(IsDoneProperty, value); }
|
||||||
public bool IsFailed { get => GetValue(IsFailedProperty); set => SetValue(IsFailedProperty, value); }
|
public bool IsFailed { get => GetValue(IsFailedProperty); set => SetValue(IsFailedProperty, value); }
|
||||||
|
public bool IsComposerVisible { get => GetValue(IsComposerVisibleProperty); set => SetValue(IsComposerVisibleProperty, value); }
|
||||||
|
public string? ComposerText { get => GetValue(ComposerTextProperty); set => SetValue(ComposerTextProperty, value); }
|
||||||
|
public ICommand? SubmitCommand { get => GetValue(SubmitCommandProperty); set => SetValue(SubmitCommandProperty, value); }
|
||||||
|
public string? ComposerPlaceholder { get => GetValue(ComposerPlaceholderProperty); set => SetValue(ComposerPlaceholderProperty, value); }
|
||||||
|
|
||||||
private INotifyCollectionChanged? _subscribedCollection;
|
private INotifyCollectionChanged? _subscribedCollection;
|
||||||
|
|
||||||
|
|||||||
@@ -107,7 +107,11 @@
|
|||||||
Label="{Binding DisplayTitle}"
|
Label="{Binding DisplayTitle}"
|
||||||
IsRunning="{Binding IsRunning}"
|
IsRunning="{Binding IsRunning}"
|
||||||
IsDone="{Binding IsDone}"
|
IsDone="{Binding IsDone}"
|
||||||
IsFailed="{Binding IsFailed}" />
|
IsFailed="{Binding IsFailed}"
|
||||||
|
IsComposerVisible="{Binding IsInteractiveLive}"
|
||||||
|
ComposerText="{Binding ComposerDraft, Mode=TwoWay}"
|
||||||
|
SubmitCommand="{Binding SubmitComposerCommand}"
|
||||||
|
ComposerPlaceholder="{loc:Tr session.composer.placeholder}" />
|
||||||
|
|
||||||
</DockPanel>
|
</DockPanel>
|
||||||
</Border>
|
</Border>
|
||||||
|
|||||||
Reference in New Issue
Block a user