Merge branch 'claudedo/16172942c1424a67a0499e01cefb7d60'

This commit is contained in:
mika kuns
2026-08-10 15:08:51 +02:00
19 changed files with 1295 additions and 24 deletions
@@ -34,6 +34,11 @@ public sealed partial class TaskRowViewModel : ViewModelBase
[ObservableProperty] private bool _parentFinalized;
[ObservableProperty] private bool _parentInView = true;
[ObservableProperty] private int _roadblockCount;
// Only meaningful when Status=Failed; stamped by TaskRunner.MarkFailed. "unknown" for a
// Failed task that predates this field. Null on every other status.
[ObservableProperty] private string? _failureReason;
[ObservableProperty] private int? _failureTurnsUsed;
[ObservableProperty] private int? _failureMaxTurns;
[ObservableProperty] private bool _isRefining;
// Manual = a reminder only the user can do. Every "hand this to Claude" affordance is hidden
// and automation skips it; opening a hand-driven ConPTY session stays allowed.
@@ -128,15 +133,33 @@ public sealed partial class TaskRowViewModel : ViewModelBase
? "1 roadblock reported during the run — see details"
: $"{RoadblockCount} roadblocks reported during the run — see details";
// True for every Failed task, even one that predates this field — FailureReasonLabel then
// falls back to "unknown" instead of leaving the tooltip blank.
public bool HasFailureReason => Status == TaskStatus.Failed;
public string FailureReasonLabel => FailureReason switch
{
"max_turns" => Loc.T("vm.failureReason.maxTurns"),
"timeout" => Loc.T("vm.failureReason.timeout"),
"cancelled" => Loc.T("vm.failureReason.cancelled"),
"error" => Loc.T("vm.failureReason.error"),
_ => Loc.T("vm.failureReason.unknown"),
};
// max_turns gets the actionable detail (turns used/configured) since that's the one case
// where the fix is "raise maxTurns and continue_task", not "reset and re-run".
public string? FailureReasonTooltip => !HasFailureReason ? null
: FailureReason == "max_turns" && FailureTurnsUsed is { } used && FailureMaxTurns is { } max
? Loc.T("vm.failureReasonTooltip.maxTurns", used, max)
: FailureReasonLabel;
// Drives the status chip tooltip: an open interactive session takes priority (it's tappable),
// otherwise a Failed task's reason, otherwise no tooltip.
public string? StatusChipTooltip
=> HasInteractiveSession ? Loc.T("tasks.interactiveChipTip") : FailureReasonTooltip;
public string DiffAdditionsText => $"+{DiffAdditions}";
public string DiffDeletionsText => $"{DiffDeletions}";
public string StepsText => Loc.T("vm.taskRow.stepsText", StepsCompleted, StepsCount);
// Null on a plain status chip so no tooltip shows there — the chip is only actionable
// while a session is open.
public string? InteractiveChipTooltip
=> HasInteractiveSession ? Loc.T("tasks.interactiveChipTip") : null;
public string StatusLabel
=> HasInteractiveSession ? Loc.T("vm.taskStatus.interactive")
: IsParked ? Loc.T("vm.taskStatus.parked") : Status switch
@@ -183,6 +206,9 @@ public sealed partial class TaskRowViewModel : ViewModelBase
OnPropertyChanged(nameof(IsParked));
OnPropertyChanged(nameof(IsQueued));
OnPropertyChanged(nameof(IsWaiting));
OnPropertyChanged(nameof(HasFailureReason));
OnPropertyChanged(nameof(FailureReasonTooltip));
OnPropertyChanged(nameof(StatusChipTooltip));
OnPropertyChanged(nameof(IsDraft));
OnPropertyChanged(nameof(IsPlanned));
OnPropertyChanged(nameof(CanOpenPlanningSession));
@@ -249,10 +275,21 @@ public sealed partial class TaskRowViewModel : ViewModelBase
OnPropertyChanged(nameof(StatusChipClass));
OnPropertyChanged(nameof(StatusLabel));
OnPropertyChanged(nameof(ShowStatusChip));
OnPropertyChanged(nameof(InteractiveChipTooltip));
OnPropertyChanged(nameof(StatusChipTooltip));
OnPropertyChanged(nameof(CanSendToQueue));
}
partial void OnFailureReasonChanged(string? value)
{
OnPropertyChanged(nameof(HasFailureReason));
OnPropertyChanged(nameof(FailureReasonLabel));
OnPropertyChanged(nameof(FailureReasonTooltip));
OnPropertyChanged(nameof(StatusChipTooltip));
}
partial void OnFailureTurnsUsedChanged(int? value) => OnPropertyChanged(nameof(FailureReasonTooltip));
partial void OnFailureMaxTurnsChanged(int? value) => OnPropertyChanged(nameof(FailureReasonTooltip));
partial void OnHasQueuedSubtasksChanged(bool value)
{
OnPropertyChanged(nameof(CanRemoveFromQueue));
@@ -332,6 +369,9 @@ public sealed partial class TaskRowViewModel : ViewModelBase
CreatedBy = t.CreatedBy;
BlockedByTaskId = t.BlockedByTaskId;
RoadblockCount = t.RoadblockCount;
FailureReason = t.FailureReason;
FailureTurnsUsed = t.FailureTurnsUsed;
FailureMaxTurns = t.FailureMaxTurns;
}
// Best-effort parse of diff stat strings like "+12 -3" or "12 additions, 3 deletions".