feat/planning-sessions-worker #7
@@ -267,6 +267,23 @@ public sealed class TaskRepository
|
|||||||
return child;
|
return child;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task UpdatePlanningTaskAsync(
|
||||||
|
string taskId,
|
||||||
|
string? title,
|
||||||
|
string? description,
|
||||||
|
CancellationToken ct = default)
|
||||||
|
{
|
||||||
|
var entity = await _context.Tasks.AsNoTracking().FirstOrDefaultAsync(t => t.Id == taskId, ct)
|
||||||
|
?? throw new InvalidOperationException("Planning task not found.");
|
||||||
|
if (title is not null) entity.Title = title;
|
||||||
|
if (description is not null) entity.Description = description;
|
||||||
|
await _context.Tasks
|
||||||
|
.Where(t => t.Id == taskId)
|
||||||
|
.ExecuteUpdateAsync(s => s
|
||||||
|
.SetProperty(t => t.Title, entity.Title)
|
||||||
|
.SetProperty(t => t.Description, entity.Description), ct);
|
||||||
|
}
|
||||||
|
|
||||||
public async Task<TaskEntity?> SetPlanningStartedAsync(
|
public async Task<TaskEntity?> SetPlanningStartedAsync(
|
||||||
string taskId,
|
string taskId,
|
||||||
string sessionToken,
|
string sessionToken,
|
||||||
|
|||||||
@@ -82,4 +82,19 @@ public sealed class PlanningMcpService
|
|||||||
|
|
||||||
await _tasks.DeleteAsync(taskId, cancellationToken);
|
await _tasks.DeleteAsync(taskId, cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task UpdatePlanningTask(
|
||||||
|
PlanningMcpContext ctx,
|
||||||
|
string? title,
|
||||||
|
string? description,
|
||||||
|
CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
await _tasks.UpdatePlanningTaskAsync(ctx.ParentTaskId, title, description, cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<int> Finalize(
|
||||||
|
PlanningMcpContext ctx,
|
||||||
|
bool queueAgentTasks,
|
||||||
|
CancellationToken cancellationToken)
|
||||||
|
=> _tasks.FinalizePlanningAsync(ctx.ParentTaskId, queueAgentTasks, cancellationToken);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -104,4 +104,31 @@ public sealed class PlanningMcpServiceTests : IDisposable
|
|||||||
|
|
||||||
Assert.Null(await _tasks.GetByIdAsync(c.Id));
|
Assert.Null(await _tasks.GetByIdAsync(c.Id));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task UpdatePlanningTask_SetsTitleAndDescription()
|
||||||
|
{
|
||||||
|
var parent = await SeedPlanningParentAsync();
|
||||||
|
|
||||||
|
await _sut.UpdatePlanningTask(Ctx(parent.Id), "new title", "new desc", CancellationToken.None);
|
||||||
|
|
||||||
|
var loaded = await _tasks.GetByIdAsync(parent.Id);
|
||||||
|
Assert.Equal("new title", loaded!.Title);
|
||||||
|
Assert.Equal("new desc", loaded.Description);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Finalize_PromotesDraftsAndInvalidatesToken()
|
||||||
|
{
|
||||||
|
var parent = await SeedPlanningParentAsync();
|
||||||
|
await _tasks.CreateChildAsync(parent.Id, "c1", null, null, null);
|
||||||
|
await _tasks.CreateChildAsync(parent.Id, "c2", null, null, null);
|
||||||
|
|
||||||
|
var count = await _sut.Finalize(Ctx(parent.Id), true, CancellationToken.None);
|
||||||
|
|
||||||
|
Assert.Equal(2, count);
|
||||||
|
var loaded = await _tasks.GetByIdAsync(parent.Id);
|
||||||
|
Assert.Equal(TaskStatus.Planned, loaded!.Status);
|
||||||
|
Assert.Null(loaded.PlanningSessionToken);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user