feat(mcp/external): add DeleteTask
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -219,6 +219,18 @@ public sealed class ExternalMcpService
|
|||||||
return cancelled;
|
return cancelled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[McpServerTool, Description("Delete a task. Refuses if the task is currently Running — cancel it first.")]
|
||||||
|
public async Task DeleteTask(string taskId, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var task = await _tasks.GetByIdAsync(taskId, cancellationToken)
|
||||||
|
?? throw new InvalidOperationException($"Task {taskId} not found.");
|
||||||
|
if (task.Status == TaskStatus.Running)
|
||||||
|
throw new InvalidOperationException("Cannot delete a running task. Cancel it first.");
|
||||||
|
|
||||||
|
await _tasks.DeleteAsync(taskId, cancellationToken);
|
||||||
|
await _broadcaster.TaskUpdated(taskId);
|
||||||
|
}
|
||||||
|
|
||||||
[McpServerTool, Description("List all known tags. Useful for discovering existing tag names (including 'agent' which marks tasks for auto-execution) before tagging.")]
|
[McpServerTool, Description("List all known tags. Useful for discovering existing tag names (including 'agent' which marks tasks for auto-execution) before tagging.")]
|
||||||
public async Task<IReadOnlyList<TagDto>> ListTags(CancellationToken cancellationToken)
|
public async Task<IReadOnlyList<TagDto>> ListTags(CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -225,4 +225,40 @@ public sealed class ExternalMcpServiceTests : IDisposable
|
|||||||
await Assert.ThrowsAsync<InvalidOperationException>(() =>
|
await Assert.ThrowsAsync<InvalidOperationException>(() =>
|
||||||
sut.UpdateTask("does-not-exist", "x", null, null, null, CancellationToken.None));
|
sut.UpdateTask("does-not-exist", "x", null, null, null, CancellationToken.None));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task DeleteTask_RemovesTaskAndTagJoins()
|
||||||
|
{
|
||||||
|
var listId = await SeedListAsync();
|
||||||
|
var task = await SeedTaskAsync(listId);
|
||||||
|
await _tasks.SetTagsAsync(task.Id, new[] { "agent" });
|
||||||
|
var queue = CreateQueue();
|
||||||
|
var sut = BuildSut(queue);
|
||||||
|
|
||||||
|
await sut.DeleteTask(task.Id, CancellationToken.None);
|
||||||
|
|
||||||
|
Assert.Null(await _tasks.GetByIdAsync(task.Id));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task DeleteTask_OnRunning_Throws()
|
||||||
|
{
|
||||||
|
var listId = await SeedListAsync();
|
||||||
|
var task = await SeedTaskAsync(listId, status: TaskStatus.Running);
|
||||||
|
var queue = CreateQueue();
|
||||||
|
var sut = BuildSut(queue);
|
||||||
|
|
||||||
|
await Assert.ThrowsAsync<InvalidOperationException>(() =>
|
||||||
|
sut.DeleteTask(task.Id, CancellationToken.None));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task DeleteTask_NotFound_Throws()
|
||||||
|
{
|
||||||
|
var queue = CreateQueue();
|
||||||
|
var sut = BuildSut(queue);
|
||||||
|
|
||||||
|
await Assert.ThrowsAsync<InvalidOperationException>(() =>
|
||||||
|
sut.DeleteTask("does-not-exist", CancellationToken.None));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user