fix(ui): keep ConPTY sessions alive across Mission Control layout rebuilds

TerminalView kills its child process on any logical-tree detach unless
BeginReparent() suppressed it, and RebuildOverviewGrid() detaches every
existing pane whenever one is added - so opening a second interactive
session killed the first. Focus-mode tab switches had the same defect.

PtyTerminalSession now puts the control in permanent reparent mode after
launch (teardown stays explicit via ConPtyPaneViewModel.Dispose -> Kill),
and the new ConPtyPaneHost reparents each pane's single long-lived view
across grid rebuilds and tab switches instead of letting the DataTemplate
instantiate a dead replacement.
This commit is contained in:
mika kuns
2026-08-06 12:43:55 +02:00
parent 0878bae19e
commit aac84e48b7
4 changed files with 73 additions and 1 deletions
@@ -1,11 +1,13 @@
using System;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Linq;
using Avalonia.Controls;
using Avalonia.Interactivity;
using Avalonia.Layout;
using Avalonia.Media;
using Avalonia.Platform.Storage;
using Avalonia.VisualTree;
using ClaudeDo.Ui.ViewModels;
namespace ClaudeDo.Ui.Views.MissionControl;
@@ -73,6 +75,18 @@ public partial class MissionControlView : UserControl
RebuildOverviewGrid();
else if (e.PropertyName == nameof(MissionControlViewModel.HasQueued))
UpdateQueueColumn();
else if (e.PropertyName == nameof(MissionControlViewModel.IsFocusMode))
// The now-visible layout's hosts must re-steal their pane views from the hidden
// one (see ConPtyPaneHost) — posted so it runs after the visibility change and
// the TabControl's content presenter have gone through a layout pass.
Avalonia.Threading.Dispatcher.UIThread.Post(ReclaimVisiblePaneHosts,
Avalonia.Threading.DispatcherPriority.Loaded);
}
private void ReclaimVisiblePaneHosts()
{
foreach (var host in this.GetVisualDescendants().OfType<ConPtyPaneHost>())
host.Reclaim();
}
// The queue column is Pixel-widthed (so the splitter can drag it) — when nothing is