@doist/todoist-ai 4.4.0 → 4.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. package/dist/index.d.ts +168 -35
  2. package/dist/index.d.ts.map +1 -1
  3. package/dist/index.js +24 -16
  4. package/dist/mcp-helpers.d.ts.map +1 -1
  5. package/dist/mcp-helpers.js +1 -1
  6. package/dist/mcp-server.d.ts.map +1 -1
  7. package/dist/mcp-server.js +78 -17
  8. package/dist/tool-helpers.d.ts +4 -0
  9. package/dist/tool-helpers.d.ts.map +1 -1
  10. package/dist/tool-helpers.js +2 -0
  11. package/dist/tools/__tests__/add-projects.test.js +1 -1
  12. package/dist/tools/__tests__/add-sections.test.js +1 -1
  13. package/dist/tools/__tests__/add-tasks.test.js +182 -13
  14. package/dist/tools/__tests__/assignment-integration.test.d.ts +2 -0
  15. package/dist/tools/__tests__/assignment-integration.test.d.ts.map +1 -0
  16. package/dist/tools/__tests__/assignment-integration.test.js +415 -0
  17. package/dist/tools/__tests__/find-projects.test.js +1 -1
  18. package/dist/tools/__tests__/find-sections.test.js +1 -1
  19. package/dist/tools/__tests__/find-tasks-by-date.test.js +1 -1
  20. package/dist/tools/__tests__/find-tasks.test.js +3 -3
  21. package/dist/tools/__tests__/get-overview.test.js +1 -1
  22. package/dist/tools/__tests__/update-tasks.test.js +82 -6
  23. package/dist/tools/__tests__/user-info.test.js +1 -1
  24. package/dist/tools/add-comments.d.ts +3 -3
  25. package/dist/tools/add-comments.d.ts.map +1 -1
  26. package/dist/tools/add-comments.js +1 -1
  27. package/dist/tools/add-projects.d.ts.map +1 -1
  28. package/dist/tools/add-projects.js +1 -1
  29. package/dist/tools/add-sections.d.ts.map +1 -1
  30. package/dist/tools/add-sections.js +1 -1
  31. package/dist/tools/add-tasks.d.ts +17 -7
  32. package/dist/tools/add-tasks.d.ts.map +1 -1
  33. package/dist/tools/add-tasks.js +51 -4
  34. package/dist/tools/find-comments.d.ts +2 -2
  35. package/dist/tools/find-completed-tasks.d.ts +4 -2
  36. package/dist/tools/find-completed-tasks.d.ts.map +1 -1
  37. package/dist/tools/find-completed-tasks.js +2 -2
  38. package/dist/tools/find-project-collaborators.d.ts +64 -0
  39. package/dist/tools/find-project-collaborators.d.ts.map +1 -0
  40. package/dist/tools/find-project-collaborators.js +151 -0
  41. package/dist/tools/find-tasks-by-date.d.ts +2 -0
  42. package/dist/tools/find-tasks-by-date.d.ts.map +1 -1
  43. package/dist/tools/find-tasks-by-date.js +2 -2
  44. package/dist/tools/find-tasks.d.ts +7 -2
  45. package/dist/tools/find-tasks.d.ts.map +1 -1
  46. package/dist/tools/find-tasks.js +128 -33
  47. package/dist/tools/get-overview.d.ts +2 -2
  48. package/dist/tools/get-overview.d.ts.map +1 -1
  49. package/dist/tools/get-overview.js +1 -1
  50. package/dist/tools/manage-assignments.d.ts +52 -0
  51. package/dist/tools/manage-assignments.d.ts.map +1 -0
  52. package/dist/tools/manage-assignments.js +337 -0
  53. package/dist/tools/update-comments.d.ts.map +1 -1
  54. package/dist/tools/update-comments.js +1 -1
  55. package/dist/tools/update-sections.d.ts.map +1 -1
  56. package/dist/tools/update-sections.js +1 -1
  57. package/dist/tools/update-tasks.d.ts +17 -7
  58. package/dist/tools/update-tasks.d.ts.map +1 -1
  59. package/dist/tools/update-tasks.js +40 -10
  60. package/dist/utils/assignment-validator.d.ts +69 -0
  61. package/dist/utils/assignment-validator.d.ts.map +1 -0
  62. package/dist/utils/assignment-validator.js +253 -0
  63. package/dist/utils/duration-parser.d.ts +2 -2
  64. package/dist/utils/duration-parser.d.ts.map +1 -1
  65. package/dist/utils/priorities.d.ts +8 -0
  66. package/dist/utils/priorities.d.ts.map +1 -0
  67. package/dist/utils/priorities.js +15 -0
  68. package/dist/utils/response-builders.d.ts +2 -2
  69. package/dist/utils/response-builders.d.ts.map +1 -1
  70. package/dist/utils/response-builders.js +8 -1
  71. package/dist/utils/test-helpers.d.ts +2 -0
  72. package/dist/utils/test-helpers.d.ts.map +1 -1
  73. package/dist/utils/test-helpers.js +2 -0
  74. package/dist/utils/tool-names.d.ts +2 -0
  75. package/dist/utils/tool-names.d.ts.map +1 -1
  76. package/dist/utils/tool-names.js +3 -0
  77. package/dist/utils/user-resolver.d.ts +39 -0
  78. package/dist/utils/user-resolver.d.ts.map +1 -0
  79. package/dist/utils/user-resolver.js +179 -0
  80. package/package.json +6 -6
@@ -2,15 +2,20 @@ import { z } from 'zod';
2
2
  import { getToolOutput } from '../mcp-helpers.js';
3
3
  import { getTasksByFilter, mapTask } from '../tool-helpers.js';
4
4
  import { ApiLimits } from '../utils/constants.js';
5
- import { LabelsSchema, generateLabelsFilter } from '../utils/labels.js';
5
+ import { generateLabelsFilter, LabelsSchema } from '../utils/labels.js';
6
6
  import { generateTaskNextSteps, getDateString, previewTasks, summarizeList, } from '../utils/response-builders.js';
7
7
  import { ToolNames } from '../utils/tool-names.js';
8
+ import { resolveUserNameToId } from '../utils/user-resolver.js';
8
9
  const { FIND_COMPLETED_TASKS, ADD_TASKS } = ToolNames;
9
10
  const ArgsSchema = {
10
11
  searchText: z.string().optional().describe('The text to search for in tasks.'),
11
12
  projectId: z.string().optional().describe('Find tasks in this project.'),
12
13
  sectionId: z.string().optional().describe('Find tasks in this section.'),
13
14
  parentId: z.string().optional().describe('Find subtasks of this parent task.'),
15
+ responsibleUser: z
16
+ .string()
17
+ .optional()
18
+ .describe('Find tasks assigned to this user. Can be a user ID, name, or email address.'),
14
19
  limit: z
15
20
  .number()
16
21
  .int()
@@ -26,14 +31,32 @@ const ArgsSchema = {
26
31
  };
27
32
  const findTasks = {
28
33
  name: ToolNames.FIND_TASKS,
29
- description: 'Find tasks by text search, or by project/section/parent container. At least one filter must be provided.',
34
+ description: 'Find tasks by text search, or by project/section/parent container/responsible user. At least one filter must be provided.',
30
35
  parameters: ArgsSchema,
31
36
  async execute(args, client) {
32
- const { searchText, projectId, sectionId, parentId, limit, cursor, labels, labelsOperator, } = args;
37
+ const { searchText, projectId, sectionId, parentId, responsibleUser, limit, cursor, labels, labelsOperator, } = args;
33
38
  // Validate at least one filter is provided
34
39
  const hasLabels = labels && labels.length > 0;
35
- if (!searchText && !projectId && !sectionId && !parentId && !hasLabels) {
36
- throw new Error('At least one filter must be provided: searchText, projectId, sectionId, parentId, or labels');
40
+ if (!searchText &&
41
+ !projectId &&
42
+ !sectionId &&
43
+ !parentId &&
44
+ !responsibleUser &&
45
+ !hasLabels) {
46
+ throw new Error('At least one filter must be provided: searchText, projectId, sectionId, parentId, responsibleUser, or labels');
47
+ }
48
+ // Resolve assignee name to user ID if provided
49
+ let resolvedAssigneeId = responsibleUser;
50
+ let assigneeDisplayName;
51
+ if (responsibleUser) {
52
+ const resolved = await resolveUserNameToId(client, responsibleUser);
53
+ if (resolved) {
54
+ resolvedAssigneeId = resolved.userId;
55
+ assigneeDisplayName = resolved.displayName;
56
+ }
57
+ else {
58
+ throw new Error(`Could not find user: "${responsibleUser}". Make sure the user is a collaborator on a shared project.`);
59
+ }
37
60
  }
38
61
  // If using container-based filtering, use direct API
39
62
  if (projectId || sectionId || parentId) {
@@ -49,36 +72,68 @@ const findTasks = {
49
72
  taskParams.parentId = parentId;
50
73
  const { results, nextCursor } = await client.getTasks(taskParams);
51
74
  const mappedTasks = results.map(mapTask);
52
- // If also has searchText, filter the results
53
- let finalTasks = searchText
75
+ // Apply search text filter
76
+ let filteredTasks = searchText
54
77
  ? mappedTasks.filter((task) => task.content.toLowerCase().includes(searchText.toLowerCase()) ||
55
78
  task.description?.toLowerCase().includes(searchText.toLowerCase()))
56
79
  : mappedTasks;
57
- // If labels have also been provided, filter the results for those
80
+ // Apply responsibleUid filter
81
+ if (resolvedAssigneeId) {
82
+ filteredTasks = filteredTasks.filter((task) => task.responsibleUid === resolvedAssigneeId);
83
+ }
84
+ // Apply label filter
58
85
  if (labels && labels.length > 0) {
59
- finalTasks =
86
+ filteredTasks =
60
87
  labelsOperator === 'and'
61
- ? finalTasks.filter((task) => labels.every((label) => task.labels.includes(label)))
62
- : finalTasks.filter((task) => labels.some((label) => task.labels.includes(label)));
88
+ ? filteredTasks.filter((task) => labels.every((label) => task.labels.includes(label)))
89
+ : filteredTasks.filter((task) => labels.some((label) => task.labels.includes(label)));
63
90
  }
64
91
  const textContent = generateTextContent({
65
- tasks: finalTasks,
92
+ tasks: filteredTasks,
66
93
  args,
67
94
  nextCursor,
68
95
  isContainerSearch: true,
96
+ assigneeDisplayName,
69
97
  });
70
98
  return getToolOutput({
71
99
  textContent,
72
100
  structuredContent: {
73
- tasks: finalTasks,
101
+ tasks: filteredTasks,
74
102
  nextCursor,
75
- totalCount: finalTasks.length,
103
+ totalCount: filteredTasks.length,
76
104
  hasMore: Boolean(nextCursor),
77
105
  appliedFilters: args,
78
106
  },
79
107
  });
80
108
  }
81
- // Handle search text and/or labels using filter query
109
+ // If only responsibleUid is provided (without containers), use assignee filter
110
+ if (resolvedAssigneeId && !searchText && !hasLabels) {
111
+ const tasks = await client.getTasksByFilter({
112
+ query: `assigned to: ${assigneeDisplayName}`,
113
+ lang: 'en',
114
+ limit,
115
+ cursor: cursor ?? null,
116
+ });
117
+ const mappedTasks = tasks.results.map(mapTask);
118
+ const textContent = generateTextContent({
119
+ tasks: mappedTasks,
120
+ args,
121
+ nextCursor: tasks.nextCursor,
122
+ isContainerSearch: false,
123
+ assigneeDisplayName,
124
+ });
125
+ return getToolOutput({
126
+ textContent,
127
+ structuredContent: {
128
+ tasks: mappedTasks,
129
+ nextCursor: tasks.nextCursor,
130
+ totalCount: mappedTasks.length,
131
+ hasMore: Boolean(tasks.nextCursor),
132
+ appliedFilters: args,
133
+ },
134
+ });
135
+ }
136
+ // Handle search text and/or labels using filter query (responsibleUid filtering done client-side)
82
137
  let query = '';
83
138
  // Add search text component
84
139
  if (searchText) {
@@ -101,18 +156,24 @@ const findTasks = {
101
156
  cursor: args.cursor,
102
157
  limit: args.limit,
103
158
  });
159
+ // Always filter by responsibleUid client-side (API doesn't reliably support responsibleUid filtering)
160
+ let tasks = result.tasks;
161
+ if (resolvedAssigneeId) {
162
+ tasks = result.tasks.filter((task) => task.responsibleUid === resolvedAssigneeId);
163
+ }
104
164
  const textContent = generateTextContent({
105
- tasks: result.tasks,
165
+ tasks,
106
166
  args,
107
167
  nextCursor: result.nextCursor,
108
168
  isContainerSearch: false,
169
+ assigneeDisplayName,
109
170
  });
110
171
  return getToolOutput({
111
172
  textContent,
112
173
  structuredContent: {
113
- tasks: result.tasks,
174
+ tasks,
114
175
  nextCursor: result.nextCursor,
115
- totalCount: result.tasks.length,
176
+ totalCount: tasks.length,
116
177
  hasMore: Boolean(result.nextCursor),
117
178
  appliedFilters: args,
118
179
  },
@@ -145,9 +206,9 @@ function getContainerZeroReasonHints(args) {
145
206
  }
146
207
  return [];
147
208
  }
148
- function generateTextContent({ tasks, args, nextCursor, isContainerSearch, }) {
209
+ function generateTextContent({ tasks, args, nextCursor, isContainerSearch, assigneeDisplayName, }) {
149
210
  // Generate subject and filter descriptions based on search type
150
- let subject;
211
+ let subject = 'Tasks';
151
212
  const filterHints = [];
152
213
  const zeroReasonHints = [];
153
214
  if (isContainerSearch) {
@@ -172,6 +233,12 @@ function generateTextContent({ tasks, args, nextCursor, isContainerSearch, }) {
172
233
  subject += ` matching "${args.searchText}"`;
173
234
  filterHints.push(`containing "${args.searchText}"`);
174
235
  }
236
+ // Add responsibleUid filter if present
237
+ if (args.responsibleUser) {
238
+ const displayName = assigneeDisplayName || args.responsibleUser;
239
+ subject += ` assigned to ${displayName}`;
240
+ filterHints.push(`assigned to ${displayName}`);
241
+ }
175
242
  // Add label filter information
176
243
  if (args.labels && args.labels.length > 0) {
177
244
  const labelText = args.labels
@@ -185,34 +252,62 @@ function generateTextContent({ tasks, args, nextCursor, isContainerSearch, }) {
185
252
  }
186
253
  }
187
254
  else {
188
- // Text-only search or labels-only search
255
+ // Text, responsibleUid, or labels search
256
+ const displayName = assigneeDisplayName || args.responsibleUser;
257
+ // Build subject based on filters
258
+ const subjectParts = [];
259
+ if (args.searchText) {
260
+ subjectParts.push(`"${args.searchText}"`);
261
+ }
262
+ if (args.responsibleUser) {
263
+ subjectParts.push(`assigned to ${displayName}`);
264
+ }
265
+ if (args.labels && args.labels.length > 0) {
266
+ const labelText = args.labels
267
+ .map((label) => `@${label}`)
268
+ .join(args.labelsOperator === 'and' ? ' & ' : ' | ');
269
+ subjectParts.push(`with labels: ${labelText}`);
270
+ }
189
271
  if (args.searchText) {
190
- subject = `Search results for "${args.searchText}"`;
272
+ subject = `Search results for ${subjectParts.join(' ')}`;
191
273
  filterHints.push(`matching "${args.searchText}"`);
192
274
  }
193
- else if (args.labels && args.labels.length > 0) {
194
- // Labels-only search
275
+ else if (args.responsibleUser && (!args.labels || args.labels.length === 0)) {
276
+ subject = `Tasks assigned to ${displayName}`;
277
+ }
278
+ else if (args.labels && args.labels.length > 0 && !args.responsibleUser) {
195
279
  const labelText = args.labels
196
280
  .map((label) => `@${label}`)
197
281
  .join(args.labelsOperator === 'and' ? ' & ' : ' | ');
198
282
  subject = `Tasks with labels: ${labelText}`;
199
- filterHints.push(`labels: ${labelText}`);
200
283
  }
201
284
  else {
202
- // Fallback (shouldn't happen given validation)
203
- subject = 'Tasks';
285
+ subject = `Tasks ${subjectParts.join(' ')}`;
204
286
  }
205
- // Add label filter information for text search with labels
206
- if (args.searchText && args.labels && args.labels.length > 0) {
287
+ // Add filter hints
288
+ if (args.responsibleUser) {
289
+ filterHints.push(`assigned to ${displayName}`);
290
+ }
291
+ if (args.labels && args.labels.length > 0) {
207
292
  const labelText = args.labels
208
293
  .map((label) => `@${label}`)
209
294
  .join(args.labelsOperator === 'and' ? ' & ' : ' | ');
210
295
  filterHints.push(`labels: ${labelText}`);
211
296
  }
212
297
  if (tasks.length === 0) {
213
- zeroReasonHints.push('Try broader search terms');
214
- zeroReasonHints.push(`Check completed tasks with ${FIND_COMPLETED_TASKS}`);
215
- zeroReasonHints.push('Verify spelling and try partial words');
298
+ if (args.responsibleUser) {
299
+ const displayName = assigneeDisplayName || args.responsibleUser;
300
+ zeroReasonHints.push(`No tasks assigned to ${displayName}`);
301
+ zeroReasonHints.push('Check if the user name is correct');
302
+ zeroReasonHints.push(`Check completed tasks with ${FIND_COMPLETED_TASKS}`);
303
+ }
304
+ if (args.searchText) {
305
+ zeroReasonHints.push('Try broader search terms');
306
+ zeroReasonHints.push('Verify spelling and try partial words');
307
+ if (!args.responsibleUser) {
308
+ zeroReasonHints.push(`Check completed tasks with ${FIND_COMPLETED_TASKS}`);
309
+ }
310
+ }
216
311
  }
217
312
  }
218
313
  // Generate contextual next steps
@@ -228,7 +323,7 @@ function generateTextContent({ tasks, args, nextCursor, isContainerSearch, }) {
228
323
  limit: args.limit,
229
324
  nextCursor: nextCursor ?? undefined,
230
325
  filterHints,
231
- previewLines: previewTasks(tasks),
326
+ previewLines: previewTasks(tasks, Math.min(tasks.length, args.limit)),
232
327
  zeroReasonHints,
233
328
  nextSteps,
234
329
  });
@@ -20,7 +20,7 @@ type AccountOverviewStructured = Record<string, unknown> & {
20
20
  totalSections: number;
21
21
  hasNestedProjects: boolean;
22
22
  };
23
- interface ProjectOverviewStructured extends Record<string, unknown> {
23
+ type ProjectOverviewStructured = Record<string, unknown> & {
24
24
  type: 'project_overview';
25
25
  project: {
26
26
  id: string;
@@ -35,7 +35,7 @@ interface ProjectOverviewStructured extends Record<string, unknown> {
35
35
  totalSections: number;
36
36
  tasksWithoutSection: number;
37
37
  };
38
- }
38
+ };
39
39
  declare const getOverview: {
40
40
  name: "get-overview";
41
41
  description: string;
@@ -1 +1 @@
1
- {"version":3,"file":"get-overview.d.ts","sourceRoot":"","sources":["../../src/tools/get-overview.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAA;AACxE,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAGvB,OAAO,EAAmC,OAAO,EAAE,MAAM,oBAAoB,CAAA;AAgI7E,KAAK,gBAAgB,GAAG;IACpB,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;IACvB,QAAQ,EAAE,OAAO,EAAE,CAAA;IACnB,QAAQ,EAAE,gBAAgB,EAAE,CAAA;CAC/B,CAAA;AAED,KAAK,yBAAyB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG;IACvD,IAAI,EAAE,kBAAkB,CAAA;IACxB,KAAK,EAAE;QACH,EAAE,EAAE,MAAM,CAAA;QACV,IAAI,EAAE,MAAM,CAAA;QACZ,QAAQ,EAAE,OAAO,EAAE,CAAA;KACtB,GAAG,IAAI,CAAA;IACR,QAAQ,EAAE,gBAAgB,EAAE,CAAA;IAC5B,aAAa,EAAE,MAAM,CAAA;IACrB,aAAa,EAAE,MAAM,CAAA;IACrB,iBAAiB,EAAE,OAAO,CAAA;CAC7B,CAAA;AAED,UAAU,yBAA0B,SAAQ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAC/D,IAAI,EAAE,kBAAkB,CAAA;IACxB,OAAO,EAAE;QACL,EAAE,EAAE,MAAM,CAAA;QACV,IAAI,EAAE,MAAM,CAAA;KACf,CAAA;IACD,QAAQ,EAAE,OAAO,EAAE,CAAA;IACnB,KAAK,EAAE,KAAK,CAAC,UAAU,CAAC,OAAO,OAAO,CAAC,GAAG;QAAE,QAAQ,EAAE,KAAK,EAAE,CAAA;KAAE,CAAC,CAAA;IAChE,KAAK,EAAE;QACH,UAAU,EAAE,MAAM,CAAA;QAClB,aAAa,EAAE,MAAM,CAAA;QACrB,mBAAmB,EAAE,MAAM,CAAA;KAC9B,CAAA;CACJ;AA6JD,QAAA,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;CAeyB,CAAA;AAE1C,OAAO,EAAE,WAAW,EAAE,KAAK,yBAAyB,EAAE,KAAK,yBAAyB,EAAE,CAAA"}
1
+ {"version":3,"file":"get-overview.d.ts","sourceRoot":"","sources":["../../src/tools/get-overview.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAA;AACxE,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAGvB,OAAO,EAAqB,OAAO,EAAgB,MAAM,oBAAoB,CAAA;AAgI7E,KAAK,gBAAgB,GAAG;IACpB,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;IACvB,QAAQ,EAAE,OAAO,EAAE,CAAA;IACnB,QAAQ,EAAE,gBAAgB,EAAE,CAAA;CAC/B,CAAA;AAED,KAAK,yBAAyB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG;IACvD,IAAI,EAAE,kBAAkB,CAAA;IACxB,KAAK,EAAE;QACH,EAAE,EAAE,MAAM,CAAA;QACV,IAAI,EAAE,MAAM,CAAA;QACZ,QAAQ,EAAE,OAAO,EAAE,CAAA;KACtB,GAAG,IAAI,CAAA;IACR,QAAQ,EAAE,gBAAgB,EAAE,CAAA;IAC5B,aAAa,EAAE,MAAM,CAAA;IACrB,aAAa,EAAE,MAAM,CAAA;IACrB,iBAAiB,EAAE,OAAO,CAAA;CAC7B,CAAA;AAED,KAAK,yBAAyB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG;IACvD,IAAI,EAAE,kBAAkB,CAAA;IACxB,OAAO,EAAE;QACL,EAAE,EAAE,MAAM,CAAA;QACV,IAAI,EAAE,MAAM,CAAA;KACf,CAAA;IACD,QAAQ,EAAE,OAAO,EAAE,CAAA;IACnB,KAAK,EAAE,KAAK,CAAC,UAAU,CAAC,OAAO,OAAO,CAAC,GAAG;QAAE,QAAQ,EAAE,KAAK,EAAE,CAAA;KAAE,CAAC,CAAA;IAChE,KAAK,EAAE;QACH,UAAU,EAAE,MAAM,CAAA;QAClB,aAAa,EAAE,MAAM,CAAA;QACrB,mBAAmB,EAAE,MAAM,CAAA;KAC9B,CAAA;CACJ,CAAA;AA6JD,QAAA,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;CAeyB,CAAA;AAE1C,OAAO,EAAE,WAAW,EAAE,KAAK,yBAAyB,EAAE,KAAK,yBAAyB,EAAE,CAAA"}
@@ -115,7 +115,7 @@ function buildProjectStructure(project, sectionsByProject) {
115
115
  }
116
116
  async function getAllTasksForProject(client, projectId) {
117
117
  let allTasks = [];
118
- let cursor = undefined;
118
+ let cursor;
119
119
  do {
120
120
  const { results, nextCursor } = await client.getTasks({
121
121
  projectId,
@@ -0,0 +1,52 @@
1
+ import { z } from 'zod';
2
+ export type OperationResult = {
3
+ taskId: string;
4
+ success: boolean;
5
+ error?: string;
6
+ originalAssigneeId?: string | null;
7
+ newAssigneeId?: string | null;
8
+ };
9
+ declare const manageAssignments: {
10
+ name: "manage-assignments";
11
+ description: string;
12
+ parameters: {
13
+ operation: z.ZodEnum<["assign", "unassign", "reassign"]>;
14
+ taskIds: z.ZodArray<z.ZodString, "many">;
15
+ responsibleUser: z.ZodOptional<z.ZodString>;
16
+ fromAssigneeUser: z.ZodOptional<z.ZodString>;
17
+ dryRun: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
18
+ };
19
+ execute(args: {
20
+ operation: "assign" | "unassign" | "reassign";
21
+ taskIds: string[];
22
+ dryRun: boolean;
23
+ responsibleUser?: string | undefined;
24
+ fromAssigneeUser?: string | undefined;
25
+ }, client: import("@doist/todoist-api-typescript").TodoistApi): Promise<{
26
+ content: {
27
+ type: "text";
28
+ text: string;
29
+ }[];
30
+ structuredContent: {
31
+ operation: "assign" | "unassign" | "reassign";
32
+ results: OperationResult[];
33
+ totalRequested: number;
34
+ successful: number;
35
+ failed: number;
36
+ dryRun: boolean;
37
+ };
38
+ } | {
39
+ content: ({
40
+ type: "text";
41
+ text: string;
42
+ mimeType?: undefined;
43
+ } | {
44
+ type: "text";
45
+ mimeType: string;
46
+ text: string;
47
+ })[];
48
+ structuredContent?: undefined;
49
+ }>;
50
+ };
51
+ export { manageAssignments };
52
+ //# sourceMappingURL=manage-assignments.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manage-assignments.d.ts","sourceRoot":"","sources":["../../src/tools/manage-assignments.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AA4CvB,MAAM,MAAM,eAAe,GAAG;IAC1B,MAAM,EAAE,MAAM,CAAA;IACd,OAAO,EAAE,OAAO,CAAA;IAChB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,kBAAkB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAClC,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAChC,CAAA;AAED,QAAA,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAoRmB,CAAA;AAuF1C,OAAO,EAAE,iBAAiB,EAAE,CAAA"}