feat(interactive): worker launch-spec for embedded ConPTY sessions

Adds InteractiveLaunchSpecService + GetInteractiveLaunchSpec hub method that
prepares a task worktree (session-skills seeding, run env) and returns a
LaunchSpec {cwd,exe,args,env} for a UI-hosted ConPTY terminal. Reuses
ISessionSkillSeeder, TaskRunner.UnionSkillNames, and WindowsTerminalLauncher
resume-arg/resolve logic. Guards mirror ResumeTaskInTerminal; a never-run task
yields a fresh-start spec instead of an error.
This commit is contained in:
mika kuns
2026-07-23 16:47:15 +02:00
parent d91ad2d635
commit 1245e75902
11 changed files with 408 additions and 3 deletions
+15 -1
View File
@@ -130,6 +130,7 @@ public sealed class WorkerHub : Microsoft.AspNetCore.SignalR.Hub
private readonly InteractiveSessionService _interactive;
private readonly LogRingBuffer? _logBuffer;
private readonly ISessionSkillRegistry _skillRegistry;
private readonly IInteractiveLaunchSpecService? _interactiveLaunchSpec;
public WorkerHub(
QueueService queue,
@@ -157,7 +158,8 @@ public sealed class WorkerHub : Microsoft.AspNetCore.SignalR.Hub
Runner.PendingQuestionRegistry pendingQuestions,
InteractiveSessionService interactive,
ISessionSkillRegistry skillRegistry,
LogRingBuffer? logBuffer = null)
LogRingBuffer? logBuffer = null,
IInteractiveLaunchSpecService? interactiveLaunchSpec = null)
{
_queue = queue;
_waker = waker;
@@ -185,6 +187,7 @@ public sealed class WorkerHub : Microsoft.AspNetCore.SignalR.Hub
_interactive = interactive;
_skillRegistry = skillRegistry;
_logBuffer = logBuffer;
_interactiveLaunchSpec = interactiveLaunchSpec;
}
// Persistence boundary for the session_skills JSON-array columns (task/list/global).
@@ -657,6 +660,17 @@ public sealed class WorkerHub : Microsoft.AspNetCore.SignalR.Hub
}
});
// Builds the launch spec an embedded ConPTY terminal (UI process) needs to open an
// interactive Claude session in a task's worktree -- same worktree prep as an
// autonomous run (session-skills seeding, run env vars), --resume if the task has a
// persisted session or a fresh-start spec otherwise. Guards mirror ResumeTaskInTerminal.
public Task<LaunchSpec> GetInteractiveLaunchSpec(string taskId) => HubGuard(() =>
{
if (_interactiveLaunchSpec is null)
throw new InvalidOperationException("Interactive launch spec service is not configured.");
return _interactiveLaunchSpec.BuildForTaskAsync(taskId, Context.ConnectionAborted);
});
public Task SendInteractiveMessage(string taskId, string text) =>
_interactive.SendAsync(taskId, text, Context.ConnectionAborted);