Merge claudedo/28d494e791e842fc966eb8691181e6da
This commit is contained in:
@@ -424,6 +424,8 @@ public sealed partial class DetailsIslandViewModel : ViewModelBase, IDisposable
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (_subscribedTask is not null)
|
||||
_subscribedTask.PropertyChanged -= OnBoundTaskPropertyChanged;
|
||||
Monitor.PropertyChanged -= OnMonitorPropertyChanged;
|
||||
Monitor.Dispose();
|
||||
Loc.LanguageChanged -= _langChangedHandler;
|
||||
@@ -908,14 +910,33 @@ public sealed partial class DetailsIslandViewModel : ViewModelBase, IDisposable
|
||||
Merge.SyncWorktree(WorktreePath, WorktreeBaseCommit, WorktreeHeadCommit,
|
||||
WorktreeStateLabel, _listWorkingDir);
|
||||
|
||||
// Tracks whichever row we last subscribed to, so a later Task switch can unsubscribe the old
|
||||
// one cleanly even though the generated OnTaskChanged only hands us the new value.
|
||||
private TaskRowViewModel? _subscribedTask;
|
||||
|
||||
partial void OnTaskChanged(TaskRowViewModel? value)
|
||||
{
|
||||
if (_subscribedTask is not null)
|
||||
_subscribedTask.PropertyChanged -= OnBoundTaskPropertyChanged;
|
||||
_subscribedTask = value;
|
||||
if (value is not null)
|
||||
value.PropertyChanged += OnBoundTaskPropertyChanged;
|
||||
|
||||
ReviewDiffViewed = false;
|
||||
Merge.SyncTaskContext(Task?.Id, Task?.Title, Task?.IsPlanningParent == true);
|
||||
NotifySessionSections();
|
||||
OnPropertyChanged(nameof(CanAcceptDrop));
|
||||
}
|
||||
|
||||
// The bound row's HasInteractiveSession can flip from outside (Mission Control opening/closing
|
||||
// a ConPTY pane) without Task itself changing, so ResetAndRetryCommand needs its own listener
|
||||
// to stay in sync with the gate in CanResetAndRetry.
|
||||
private void OnBoundTaskPropertyChanged(object? sender, System.ComponentModel.PropertyChangedEventArgs e)
|
||||
{
|
||||
if (e.PropertyName == nameof(TaskRowViewModel.HasInteractiveSession))
|
||||
ResetAndRetryCommand.NotifyCanExecuteChanged();
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private void CloseDetails() => CloseDetail?.Invoke();
|
||||
|
||||
@@ -1149,8 +1170,11 @@ public sealed partial class DetailsIslandViewModel : ViewModelBase, IDisposable
|
||||
catch { /* offline */ }
|
||||
}
|
||||
|
||||
// Reset & Retry discards the branch/uncommitted work and queues an autonomous run into the
|
||||
// same worktree — must stay off while the user is hand-editing it in an interactive ConPTY
|
||||
// pane, same reasoning as TaskRowViewModel.CanSendToQueue.
|
||||
private bool CanResetAndRetry() =>
|
||||
Task != null && _worker.IsConnected && ShowResetAndRetry;
|
||||
Task != null && _worker.IsConnected && ShowResetAndRetry && !Task.HasInteractiveSession;
|
||||
|
||||
// Set once the user opens the diff/combined-diff for the current review. Reset on
|
||||
// task switch and on every state change (a new run means a new diff to read), so
|
||||
|
||||
@@ -837,6 +837,19 @@ public sealed partial class TasksIslandViewModel : ViewModelBase, IDisposable
|
||||
// A finalized planning parent queues its plan (children sequentially), not itself.
|
||||
if (row.CanQueuePlan)
|
||||
{
|
||||
// The hub's QueuePlanningSubtasksAsync queues every Idle child unconditionally — it has
|
||||
// no notion of a UI-hosted ConPTY session. Block the whole plan if any child has one open,
|
||||
// otherwise that child's worktree would get an autonomous run racing the user's own edits.
|
||||
var interactiveChildren = Items
|
||||
.Where(r => r.ParentTaskId == row.Id && r.HasInteractiveSession)
|
||||
.Select(r => r.Title)
|
||||
.ToList();
|
||||
if (interactiveChildren.Count > 0)
|
||||
{
|
||||
ErrorReported?.Invoke(Loc.T(
|
||||
"vm.tasksIsland.queuePlanBlockedInteractive", string.Join(", ", interactiveChildren)));
|
||||
return;
|
||||
}
|
||||
await QueuePlanningSubtasksAsync(row);
|
||||
return;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user