feat(mission-control): Handler-Run per Knopf abbrechen

Ein "Abandon run"-Knopf an Handler-Panes fragt HandlerRoundState.Get(handlerTaskId)
nach den noch offenen (Queued/Running) Tasks des Laufs, bestaetigt mit Anzahl,
cancelt jeden ueber den bestehenden CancelTaskAsync-Pfad und schliesst danach die
Session -- ein Schritt statt Tile schliessen + Queue separat abbrechen. Ohne
offene Tasks (oder ohne Round-Eintrag) schliesst die Aktion direkt, ohne Dialog.
Nur an den beiden Handler-Panes sichtbar (IsListHandler), normale Task-/Ad-hoc-
Panes bleiben unveraendert.
This commit is contained in:
mika kuns
2026-09-02 22:39:12 +02:00
parent b298594a2c
commit bd5aa265d1
13 changed files with 417 additions and 5 deletions
@@ -18,6 +18,12 @@ public sealed partial class ConPtyPaneViewModel : ViewModelBase, IDisposable
// Only a task-based pane can be submitted for review (an ad-hoc directory session has no task).
public bool IsTaskBased => TaskId is not null;
/// <summary>Set by the host for a list-handler run ("Let Claude handle it" / "Let Claude merge
/// the reviews") pane -- shows the "Abandon run" action. Plain mutable property, not
/// <see cref="ObservableProperty"/>: the host sets it once right after construction, before the
/// pane is added to the visible collection, so no change notification is needed.</summary>
public bool IsListHandler { get; set; }
[ObservableProperty] private string _displayTitle;
[ObservableProperty] private InteractiveTerminalViewModel _terminal = new();
@@ -26,6 +32,10 @@ public sealed partial class ConPtyPaneViewModel : ViewModelBase, IDisposable
/// flight, so a rapid double-click can't race two submissions for the same task.</summary>
[ObservableProperty] private bool _isSubmitPending;
/// <summary>Set by the host while an abandon-run round trip (query open tasks, confirm,
/// cancel each, close pane) is in flight, so a rapid double-click can't race two runs.</summary>
[ObservableProperty] private bool _isAbandonPending;
/// <summary>Raised when the terminal failed to start — the host surfaces this via the footer error strip.</summary>
public event Action<string>? ErrorReported;
@@ -36,6 +46,12 @@ public sealed partial class ConPtyPaneViewModel : ViewModelBase, IDisposable
/// commits the worktree and moves the task to WaitingForReview.</summary>
public event Action<string>? SubmitForReviewRequested;
/// <summary>Raised when the user abandons a list-handler run (<see cref="IsListHandler"/>
/// only): the host looks up this round's still-open tasks, confirms with the user (naming the
/// count), cancels them, then closes this pane -- one action instead of closing the tile and
/// separately cancelling the queue.</summary>
public event Action<string>? AbandonRunRequested;
/// <summary>Raised with <c>(taskId, exitCode)</c> when a task-based session that had been running
/// dies non-zero. The host reports it to the worker, which decides whether this was a list
/// handler killed by the usage limit and worth reopening. Ad-hoc panes never raise it — there is
@@ -141,6 +157,16 @@ public sealed partial class ConPtyPaneViewModel : ViewModelBase, IDisposable
partial void OnIsSubmitPendingChanged(bool value) => SubmitForReviewCommand.NotifyCanExecuteChanged();
private bool CanAbandonRun() => IsListHandler && !IsAbandonPending;
[RelayCommand(CanExecute = nameof(CanAbandonRun))]
private void AbandonRun()
{
if (TaskId is { } id) AbandonRunRequested?.Invoke(id);
}
partial void OnIsAbandonPendingChanged(bool value) => AbandonRunCommand.NotifyCanExecuteChanged();
// A launch failure permanently occupies the TaskId dedupe slot unless the user can retry —
// re-opening the same task would otherwise just re-focus a dead tile.
private bool CanRetry() => Terminal.HasExited && Terminal.StartError is not null;