feat(interactive): New session button for ad-hoc ConPTY sessions

Adds a 'New session' header button in Mission Control that opens a folder picker
and starts a task-less embedded ConPTY session in the chosen directory. ConPtyPaneViewModel
TaskId is now nullable (ad-hoc panes have no task and are never deduped) with a
CreateAdHoc factory; the view does the picking, the VM stays picker-agnostic.
This commit is contained in:
mika kuns
2026-07-23 16:47:15 +02:00
parent 9ab48d7094
commit 3feb08d9d9
7 changed files with 127 additions and 4 deletions
@@ -7,14 +7,15 @@ using ClaudeDo.Ui.Services;
namespace ClaudeDo.Ui.ViewModels.MissionControl;
/// <summary>
/// Command Center pane hosting an embedded ConPTY terminal for one task's interactive Claude
/// session (task-based only — no ad-hoc/free sessions yet). Distinct from the streamed-log
/// Command Center pane hosting an embedded ConPTY terminal for either one task's interactive
/// Claude session, or an ad-hoc/free session in a user-chosen directory (no task, <see cref="TaskId"/>
/// is null — ad-hoc panes are never deduped, unlike task-based ones). Distinct from the streamed-log
/// <see cref="ClaudeDo.Ui.ViewModels.Islands.TaskMonitorViewModel"/> pane; the two coexist until
/// the streaming interactive stack is removed.
/// </summary>
public sealed partial class ConPtyPaneViewModel : ViewModelBase, IMissionControlPane, IDisposable
{
public string TaskId { get; }
public string? TaskId { get; }
[ObservableProperty] private string _displayTitle;
@@ -26,7 +27,9 @@ public sealed partial class ConPtyPaneViewModel : ViewModelBase, IMissionControl
/// <summary>Set by the host (Mission Control) to remove this pane from its collection.</summary>
public Action<ConPtyPaneViewModel>? CloseRequested { get; set; }
public ConPtyPaneViewModel(string taskId, string displayTitle, TerminalLaunchDescriptor descriptor)
/// <summary>Task-based pane — dedup'd by <see cref="TaskId"/>. Pass null for an ad-hoc pane
/// (no task, never deduped); prefer <see cref="CreateAdHoc"/> at ad-hoc call sites.</summary>
public ConPtyPaneViewModel(string? taskId, string displayTitle, TerminalLaunchDescriptor descriptor)
{
TaskId = taskId;
_displayTitle = displayTitle;
@@ -34,6 +37,10 @@ public sealed partial class ConPtyPaneViewModel : ViewModelBase, IMissionControl
Terminal.Start(descriptor);
}
/// <summary>Ad-hoc pane — no task, no dedup.</summary>
public static ConPtyPaneViewModel CreateAdHoc(string displayTitle, TerminalLaunchDescriptor descriptor)
=> new(null, displayTitle, descriptor);
private void OnTerminalPropertyChanged(object? sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == nameof(InteractiveTerminalViewModel.StartError) && Terminal.StartError is { Length: > 0 } error)