diff --git a/go.mod b/go.mod index 31dbc86..1cc5f01 100644 --- a/go.mod +++ b/go.mod @@ -13,7 +13,7 @@ require ( github.com/modelcontextprotocol/go-sdk v1.6.1 github.com/teamwork/desksdkgo v1.0.1 github.com/teamwork/spacessdkgo v0.0.0-20260518181558-a6af69d00abb - github.com/teamwork/twapi-go-sdk v1.20.3 + github.com/teamwork/twapi-go-sdk v1.20.4 ) require ( diff --git a/go.sum b/go.sum index 75f14ae..b39afeb 100644 --- a/go.sum +++ b/go.sum @@ -184,8 +184,8 @@ github.com/teamwork/desksdkgo v1.0.1 h1:Mi5D1pnGfL5JwD7s7g7OyHml7Y9jsak5MNJaotJt github.com/teamwork/desksdkgo v1.0.1/go.mod h1:Mgvw83q8iqHr7Sm9xV1iI/T89o3ObaPU3ChMJheRzwA= github.com/teamwork/spacessdkgo v0.0.0-20260518181558-a6af69d00abb h1:bQluDjySZeC5etnWgjk4WFRy0PvzGDw8XEBd4JJYWCQ= github.com/teamwork/spacessdkgo v0.0.0-20260518181558-a6af69d00abb/go.mod h1:jfE0RLsZuk/3Glzs5bJ95pNb92emV7uXZYgoGSLQ76I= -github.com/teamwork/twapi-go-sdk v1.20.3 h1:W4V2adgnrdCqdAupUgm1ElurmFpaND8fOUI/SuH2gBU= -github.com/teamwork/twapi-go-sdk v1.20.3/go.mod h1:uj6BNtyyKtggfeY3whzn8bLWuhP1twhghjWD6z3h3F4= +github.com/teamwork/twapi-go-sdk v1.20.4 h1:W5ycV6GDDc/SlNkMopIrX1/QeReV6PeqFUBuLqsDuDk= +github.com/teamwork/twapi-go-sdk v1.20.4/go.mod h1:uj6BNtyyKtggfeY3whzn8bLWuhP1twhghjWD6z3h3F4= github.com/tinylib/msgp v1.6.3 h1:bCSxiTz386UTgyT1i0MSCvdbWjVW+8sG3PjkGsZQt4s= github.com/tinylib/msgp v1.6.3/go.mod h1:RSp0LW9oSxFut3KzESt5Voq4GVWyS+PSulT77roAqEA= github.com/tklauser/go-sysconf v0.3.16 h1:frioLaCQSsF5Cy1jgRBrzr6t502KIIwQ0MArYICU0nA= diff --git a/internal/twprojects/tasks.go b/internal/twprojects/tasks.go index 60ae922..dc04661 100644 --- a/internal/twprojects/tasks.go +++ b/internal/twprojects/tasks.go @@ -755,6 +755,15 @@ func TaskList(engine *twapi.Engine) toolsets.ToolWrapper { {Type: "null"}, }, }, + "show_completed": { + Description: "If true, include completed tasks and tasks belonging to completed tasklists; " + + "both excluded by default.", + AnyOf: []*jsonschema.Schema{ + {Type: "boolean"}, + {Type: "null"}, + }, + Default: []byte(`false`), + }, "only_unassigned": { Description: "If true, only return tasks that have no assignee.", AnyOf: []*jsonschema.Schema{ @@ -786,6 +795,7 @@ func TaskList(engine *twapi.Engine) toolsets.ToolWrapper { return helpers.NewToolResultTextError("failed to decode request: %s", err.Error()), nil } verbose := true + var showCompleted *bool err := helpers.ParamGroup(arguments, helpers.OptionalNumericParam(&taskListRequest.Path.TasklistID, "tasklist_id"), helpers.OptionalNumericParam(&taskListRequest.Path.ProjectID, "project_id"), @@ -804,6 +814,7 @@ func TaskList(engine *twapi.Engine) toolsets.ToolWrapper { helpers.OptionalTimePointerParam(&taskListRequest.Filters.CompletedBefore, "completed_before"), helpers.OptionalDatePointerParam(&taskListRequest.Filters.DueAfter, "due_after"), helpers.OptionalDatePointerParam(&taskListRequest.Filters.DueBefore, "due_before"), + helpers.OptionalPointerParam(&showCompleted, "show_completed"), helpers.OptionalPointerParam(&taskListRequest.Filters.OnlyUnassigned, "only_unassigned"), helpers.OptionalPointerParam(&taskListRequest.Filters.OnlyUnplanned, "only_unplanned"), helpers.OptionalParam(&verbose, "verbose"), @@ -811,6 +822,13 @@ func TaskList(engine *twapi.Engine) toolsets.ToolWrapper { if err != nil { return helpers.NewToolResultTextError("invalid parameters: %s", err.Error()), nil } + if showCompleted != nil { + // A single flag drives both SDK filters: completed tasks are hidden by + // default, and so are tasks living inside a completed tasklist. Callers + // asking to see completed work expect both. + taskListRequest.Filters.IncludeCompletedTasks = showCompleted + taskListRequest.Filters.IncludeTasksFromCompletedTasklists = showCompleted + } if verbose { // Include custom fields and values in task list response for richer // context, as they are commonly used in Teamwork projects and provide diff --git a/internal/twprojects/tasks_test.go b/internal/twprojects/tasks_test.go index a35f857..ad80aad 100644 --- a/internal/twprojects/tasks_test.go +++ b/internal/twprojects/tasks_test.go @@ -189,6 +189,7 @@ func TestTaskList(t *testing.T) { "completed_before": "2023-10-31T23:59:59Z", "due_after": "2023-10-01", "due_before": "2023-10-31", + "show_completed": true, "only_unassigned": true, "only_unplanned": true, "page": float64(1), @@ -213,6 +214,7 @@ func TestTaskListByTasklist(t *testing.T) { "completed_before": "2023-10-31T23:59:59Z", "due_after": "2023-10-01", "due_before": "2023-10-31", + "show_completed": true, "only_unassigned": true, "only_unplanned": true, "page": float64(1), @@ -237,6 +239,7 @@ func TestTaskListByProject(t *testing.T) { "completed_before": "2023-10-31T23:59:59Z", "due_after": "2023-10-01", "due_before": "2023-10-31", + "show_completed": true, "only_unassigned": true, "only_unplanned": true, "page": float64(1),