Merge branch 'claudedo/df0e925e1ff4419d8b7a45f8a184f6d0'

This commit is contained in:
mika kuns
2026-08-05 09:26:46 +02:00
21 changed files with 27 additions and 278 deletions
+2 -33
View File
@@ -639,42 +639,11 @@ public sealed class WorkerHub : Microsoft.AspNetCore.SignalR.Hub
return ctx;
}
// Picks up a task's Claude session in a real terminal window (--resume) so the user can
// drive it by hand. Only for tasks the worker isn't actively running, with a persisted
// session id and a live worktree.
public Task ResumeTaskInTerminal(string taskId) => HubGuard(async () =>
{
await using var ctx = await _dbFactory.CreateDbContextAsync();
var task = await new TaskRepository(ctx).GetByIdAsync(taskId, Context.ConnectionAborted)
?? throw new KeyNotFoundException();
if (task.Status is TaskStatus.Running or TaskStatus.Queued)
throw new InvalidOperationException("Can't pick up a running or queued task — interrupt it first.");
var run = await new TaskRunRepository(ctx).GetLatestByTaskIdAsync(taskId, Context.ConnectionAborted);
if (run?.SessionId is not { Length: > 0 } sessionId)
throw new InvalidOperationException("This task has no resumable Claude session yet.");
var worktree = await new WorktreeRepository(ctx).GetByTaskIdAsync(taskId, Context.ConnectionAborted);
if (worktree is null || worktree.State is not (WorktreeState.Active or WorktreeState.Kept))
throw new InvalidOperationException("This task has no active worktree to resume in.");
if (!Directory.Exists(worktree.Path))
throw new InvalidOperationException("The task's worktree directory no longer exists.");
try
{
await _launcher.LaunchResumeAsync(worktree.Path, sessionId, Context.ConnectionAborted);
}
catch (TerminalLaunchException ex)
{
throw new InvalidOperationException(ex.Message);
}
});
// 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.
// persisted session or a fresh-start spec otherwise. Guards: no running/queued task,
// and (once a worktree exists) it must be live on disk.
public Task<LaunchSpec> GetInteractiveLaunchSpec(string taskId) => HubGuard(() =>
{
if (_interactiveLaunchSpec is null)