feat(worker): accept #123 task numbers as MCP tool input

TaskIdResolver resolves a #123/bare-123 taskId parameter to its GUID
before any lookup, across every External/ MCP tool that takes a task
id, including the batch tools' id arrays (via delegation to the
already-resolving single-entity methods) and update_task's
dependsOnTaskId (empty string still passes through unchanged as the
clear-link sentinel). An unknown number throws a clear error instead
of a silent null. McpToolDocs.TaskNumberHint tells the agent to refer
to tasks as #<number> when reporting to the user, added to the
description of get_task, list_tasks, add_task, update_task_status and
review_task.
This commit is contained in:
mika kuns
2026-08-11 13:10:49 +02:00
parent 9660a29da4
commit 2a3133efad
14 changed files with 298 additions and 7 deletions
@@ -229,6 +229,41 @@ public sealed class ExternalMcpServiceTests : IDisposable
Assert.Equal(task.Number, dto.Number);
}
[Fact]
public async Task GetTask_ByHashNumber_ResolvesToTask()
{
var listId = await SeedListAsync();
var task = await SeedTaskAsync(listId);
var sut = BuildSut(CreateQueue());
var dto = await sut.GetTask($"#{task.Number}", CancellationToken.None);
Assert.Equal(task.Id, dto.Id);
}
[Fact]
public async Task GetTask_ByBareNumber_ResolvesToTask()
{
var listId = await SeedListAsync();
var task = await SeedTaskAsync(listId);
var sut = BuildSut(CreateQueue());
var dto = await sut.GetTask(task.Number.ToString(), CancellationToken.None);
Assert.Equal(task.Id, dto.Id);
}
[Fact]
public async Task GetTask_UnknownNumber_ThrowsWithNumberInMessage()
{
var sut = BuildSut(CreateQueue());
var ex = await Assert.ThrowsAsync<InvalidOperationException>(() =>
sut.GetTask("#999999", CancellationToken.None));
Assert.Contains("999999", ex.Message);
}
[Fact]
public async Task GetTask_ReturnsFullDtoIncludingDescription()
{