@doist/todoist-ai 5.2.0 → 6.1.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 (71) hide show
  1. package/README.md +6 -0
  2. package/dist/index.d.ts +272 -901
  3. package/dist/index.d.ts.map +1 -1
  4. package/dist/index.js +2 -2
  5. package/dist/main.js +1 -1
  6. package/dist/mcp-helpers.d.ts +7 -1
  7. package/dist/mcp-helpers.d.ts.map +1 -1
  8. package/dist/mcp-server-BhXFK7dP.js +3220 -0
  9. package/dist/mcp-server.d.ts.map +1 -1
  10. package/dist/todoist-tool.d.ts +6 -0
  11. package/dist/todoist-tool.d.ts.map +1 -1
  12. package/dist/tools/add-comments.d.ts +9 -82
  13. package/dist/tools/add-comments.d.ts.map +1 -1
  14. package/dist/tools/add-projects.d.ts +11 -73
  15. package/dist/tools/add-projects.d.ts.map +1 -1
  16. package/dist/tools/add-sections.d.ts +2 -14
  17. package/dist/tools/add-sections.d.ts.map +1 -1
  18. package/dist/tools/add-tasks.d.ts +24 -76
  19. package/dist/tools/add-tasks.d.ts.map +1 -1
  20. package/dist/tools/complete-tasks.d.ts +3 -11
  21. package/dist/tools/complete-tasks.d.ts.map +1 -1
  22. package/dist/tools/delete-object.d.ts +15 -11
  23. package/dist/tools/delete-object.d.ts.map +1 -1
  24. package/dist/tools/fetch.d.ts.map +1 -1
  25. package/dist/tools/find-activity.d.ts +25 -31
  26. package/dist/tools/find-activity.d.ts.map +1 -1
  27. package/dist/tools/find-comments.d.ts +9 -74
  28. package/dist/tools/find-comments.d.ts.map +1 -1
  29. package/dist/tools/find-completed-tasks.d.ts +28 -53
  30. package/dist/tools/find-completed-tasks.d.ts.map +1 -1
  31. package/dist/tools/find-project-collaborators.d.ts +2 -18
  32. package/dist/tools/find-project-collaborators.d.ts.map +1 -1
  33. package/dist/tools/find-projects.d.ts +3 -21
  34. package/dist/tools/find-projects.d.ts.map +1 -1
  35. package/dist/tools/find-sections.d.ts +1 -7
  36. package/dist/tools/find-sections.d.ts.map +1 -1
  37. package/dist/tools/find-tasks-by-date.d.ts +34 -54
  38. package/dist/tools/find-tasks-by-date.d.ts.map +1 -1
  39. package/dist/tools/find-tasks-by-date.resource.d.ts +28 -0
  40. package/dist/tools/find-tasks-by-date.resource.d.ts.map +1 -0
  41. package/dist/tools/find-tasks.d.ts +31 -55
  42. package/dist/tools/find-tasks.d.ts.map +1 -1
  43. package/dist/tools/get-overview.d.ts +8 -15
  44. package/dist/tools/get-overview.d.ts.map +1 -1
  45. package/dist/tools/manage-assignments.d.ts +9 -27
  46. package/dist/tools/manage-assignments.d.ts.map +1 -1
  47. package/dist/tools/search.d.ts +1 -9
  48. package/dist/tools/search.d.ts.map +1 -1
  49. package/dist/tools/update-comments.d.ts +10 -85
  50. package/dist/tools/update-comments.d.ts.map +1 -1
  51. package/dist/tools/update-projects.d.ts +12 -80
  52. package/dist/tools/update-projects.d.ts.map +1 -1
  53. package/dist/tools/update-sections.d.ts +4 -16
  54. package/dist/tools/update-sections.d.ts.map +1 -1
  55. package/dist/tools/update-tasks.d.ts +25 -87
  56. package/dist/tools/update-tasks.d.ts.map +1 -1
  57. package/dist/tools/user-info.d.ts +6 -2
  58. package/dist/tools/user-info.d.ts.map +1 -1
  59. package/dist/utils/labels.d.ts +5 -2
  60. package/dist/utils/labels.d.ts.map +1 -1
  61. package/dist/utils/output-schemas.d.ts +20 -176
  62. package/dist/utils/output-schemas.d.ts.map +1 -1
  63. package/dist/utils/priorities.d.ts +6 -1
  64. package/dist/utils/priorities.d.ts.map +1 -1
  65. package/dist/utils/widget-loader.d.ts +7 -0
  66. package/dist/utils/widget-loader.d.ts.map +1 -0
  67. package/package.json +21 -11
  68. package/scripts/inline-widget-builder.ts +87 -0
  69. package/scripts/inline-widgets-vite-plugin.ts +134 -0
  70. package/scripts/validate-schemas.ts +66 -65
  71. package/dist/mcp-server-D0ROki3I.js +0 -3171
@@ -1,3171 +0,0 @@
1
- import { getTaskUrl as me, getProjectUrl as fe, TodoistApi as Ae } from "@doist/todoist-api-typescript";
2
- import { McpServer as Ue } from "@modelcontextprotocol/sdk/server/mcp.js";
3
- import F, { z as s } from "zod";
4
- import { addDays as be, formatISO as Pe } from "date-fns";
5
- function X(e) {
6
- if (e == null)
7
- return e;
8
- if (Array.isArray(e))
9
- return e.map((t) => X(t));
10
- if (typeof e == "object") {
11
- const t = {};
12
- for (const [o, n] of Object.entries(e))
13
- if (n !== null) {
14
- const r = X(n);
15
- if (r !== null && typeof r == "object" && !Array.isArray(r) && Object.keys(r).length === 0)
16
- continue;
17
- t[o] = r;
18
- }
19
- return t;
20
- }
21
- return e;
22
- }
23
- const Ee = process.env.USE_STRUCTURED_CONTENT === "true" || process.env.NODE_ENV === "test";
24
- function Oe({
25
- textContent: e,
26
- structuredContent: t
27
- }) {
28
- const o = X(t), n = {};
29
- if (e && (n.content = [{ type: "text", text: e }]), t && (n.structuredContent = o), !Ee && t) {
30
- const r = JSON.stringify(o);
31
- n.content || (n.content = []), n.content.push({
32
- type: "text",
33
- mimeType: "application/json",
34
- text: r
35
- });
36
- }
37
- return n;
38
- }
39
- function _e(e) {
40
- return {
41
- content: [{ type: "text", text: e }],
42
- isError: !0
43
- };
44
- }
45
- function Ne(e) {
46
- switch (e) {
47
- case "readonly":
48
- return { readOnlyHint: !0, destructiveHint: !1 };
49
- case "additive":
50
- return { readOnlyHint: !1, destructiveHint: !1 };
51
- case "mutating":
52
- return { readOnlyHint: !1, destructiveHint: !0 };
53
- }
54
- }
55
- function I(e, t, o) {
56
- const n = async (r, i) => {
57
- try {
58
- const { textContent: c, structuredContent: a } = await e.execute(
59
- r,
60
- o
61
- );
62
- return Oe({ textContent: c, structuredContent: a });
63
- } catch (c) {
64
- console.error(`Error executing tool ${e.name}:`, { args: r, error: c });
65
- const a = c instanceof Error ? c.message : "An unknown error occurred";
66
- return _e(a);
67
- }
68
- };
69
- t.registerTool(
70
- e.name,
71
- {
72
- description: e.description,
73
- inputSchema: e.parameters,
74
- outputSchema: e.outputSchema,
75
- annotations: Ne(e.mutability)
76
- },
77
- n
78
- );
79
- }
80
- const S = {
81
- /** Default limit for task listings */
82
- TASKS_DEFAULT: 10,
83
- /** Maximum limit for task search and list operations */
84
- TASKS_MAX: 100,
85
- /** Default limit for completed tasks */
86
- COMPLETED_TASKS_DEFAULT: 50,
87
- /** Maximum limit for completed tasks */
88
- COMPLETED_TASKS_MAX: 200,
89
- /** Default limit for project listings */
90
- PROJECTS_DEFAULT: 50,
91
- /** Maximum limit for project listings */
92
- PROJECTS_MAX: 200,
93
- /** Maximum limit for section listings */
94
- SECTIONS_MAX: 200,
95
- /** Batch size for fetching all tasks in a project */
96
- TASKS_BATCH_SIZE: 50,
97
- /** Default limit for comment listings */
98
- COMMENTS_DEFAULT: 10,
99
- /** Maximum limit for comment search and list operations */
100
- COMMENTS_MAX: 10,
101
- /** Default limit for activity log listings */
102
- ACTIVITY_DEFAULT: 20,
103
- /** Maximum limit for activity log search and list operations */
104
- ACTIVITY_MAX: 100
105
- }, G = {
106
- /** Maximum number of failures to show in detailed error messages */
107
- MAX_FAILURES_SHOWN: 3
108
- };
109
- class U extends Error {
110
- constructor(t, o) {
111
- super(`Invalid duration format "${t}": ${o}`), this.name = "DurationParseError";
112
- }
113
- }
114
- function ge(e) {
115
- if (!e || typeof e != "string")
116
- throw new U(e, "Duration must be a non-empty string");
117
- const t = e.trim().toLowerCase().replace(/\s+/g, "");
118
- if (!t)
119
- throw new U(e, "Duration must be a non-empty string");
120
- const o = t.match(/^(?:(\d+(?:\.\d+)?)h)?(?:(\d+(?:\.\d+)?)m)?$/);
121
- if (!o || !o[1] && !o[2])
122
- throw new U(e, 'Use format like "2h", "30m", "2h30m", or "1.5h"');
123
- let n = 0;
124
- const [, r, i] = o;
125
- if (r) {
126
- const c = Number.parseFloat(r);
127
- if (Number.isNaN(c) || c < 0)
128
- throw new U(e, "Hours must be a positive number");
129
- n += c * 60;
130
- }
131
- if (i) {
132
- const c = Number.parseFloat(i);
133
- if (Number.isNaN(c) || c < 0)
134
- throw new U(e, "Minutes must be a positive number");
135
- if (c % 1 !== 0)
136
- throw new U(
137
- e,
138
- "Minutes must be a whole number (use decimal hours instead)"
139
- );
140
- n += c;
141
- }
142
- if (n = Math.round(n), n === 0)
143
- throw new U(e, "Duration must be greater than 0 minutes");
144
- if (n > 1440)
145
- throw new U(e, "Duration cannot exceed 24 hours (1440 minutes)");
146
- return { minutes: n };
147
- }
148
- function Me(e) {
149
- if (e <= 0) return "0m";
150
- const t = Math.floor(e / 60), o = e % 60;
151
- return t === 0 ? `${o}m` : o === 0 ? `${t}h` : `${t}h${o}m`;
152
- }
153
- const Fe = ["p1", "p2", "p3", "p4"], Q = s.enum(Fe, {
154
- description: "Task priority: p1 (highest), p2 (high), p3 (medium), p4 (lowest/default)"
155
- });
156
- function Te(e) {
157
- return { p1: 4, p2: 3, p3: 2, p4: 1 }[e];
158
- }
159
- function Re(e) {
160
- return { 4: "p1", 3: "p2", 2: "p3", 1: "p4" }[e];
161
- }
162
- const A = /* @__PURE__ */ new Map(), R = /* @__PURE__ */ new Map(), q = 300 * 1e3;
163
- class Le {
164
- /**
165
- * Resolve a user name or ID to a user ID by looking up collaborators across all shared projects.
166
- * Supports exact name matches, partial matches, and email matches.
167
- */
168
- async resolveUser(t, o) {
169
- if (!o || o.trim().length === 0)
170
- return null;
171
- const n = o.trim(), r = A.get(n);
172
- if (r && Date.now() - r.timestamp < q)
173
- return r.result;
174
- if (/^[0-9]+$/.test(n) || /^[a-f0-9-]{8,}$/i.test(n) && n.includes("-") || /^[a-z0-9_]{6,}$/i.test(n) && !/^[a-z]+[\s-]/.test(n) && /[0-9_]/.test(n)) {
175
- const i = { userId: n, displayName: n, email: n };
176
- return A.set(n, { result: i, timestamp: Date.now() }), i;
177
- }
178
- try {
179
- const i = await this.getAllCollaborators(t);
180
- if (i.length === 0)
181
- return A.set(n, { result: null, timestamp: Date.now() }), null;
182
- const c = o.toLowerCase().trim();
183
- let a = i.find((l) => l.name.toLowerCase() === c);
184
- if (a) {
185
- const l = { userId: a.id, displayName: a.name, email: a.email };
186
- return A.set(n, { result: l, timestamp: Date.now() }), l;
187
- }
188
- if (a = i.find((l) => l.email.toLowerCase() === c), a) {
189
- const l = { userId: a.id, displayName: a.name, email: a.email };
190
- return A.set(n, { result: l, timestamp: Date.now() }), l;
191
- }
192
- if (a = i.find((l) => l.name.toLowerCase().includes(c)), a) {
193
- const l = { userId: a.id, displayName: a.name, email: a.email };
194
- return A.set(n, { result: l, timestamp: Date.now() }), l;
195
- }
196
- if (a = i.find((l) => l.email.toLowerCase().includes(c)), a) {
197
- const l = { userId: a.id, displayName: a.name, email: a.email };
198
- return A.set(n, { result: l, timestamp: Date.now() }), l;
199
- }
200
- const d = null;
201
- return A.set(n, { result: d, timestamp: Date.now() }), d;
202
- } catch {
203
- return A.set(n, { result: null, timestamp: Date.now() }), null;
204
- }
205
- }
206
- /**
207
- * Validate that a user is a collaborator on a specific project
208
- */
209
- async validateProjectCollaborator(t, o, n) {
210
- try {
211
- return (await this.getProjectCollaborators(t, o)).some((i) => i.id === n);
212
- } catch {
213
- return !1;
214
- }
215
- }
216
- /**
217
- * Get collaborators for a specific project
218
- */
219
- async getProjectCollaborators(t, o) {
220
- const n = `project_${o}`, r = R.get(n);
221
- if (r && Date.now() - r.timestamp < q)
222
- return r.result;
223
- try {
224
- const i = await t.getProjectCollaborators(o), a = (Array.isArray(i) ? i : i.results || []).filter((d) => d?.id && d.name && d.email);
225
- return R.set(n, {
226
- result: a,
227
- timestamp: Date.now()
228
- }), a;
229
- } catch {
230
- return [];
231
- }
232
- }
233
- /**
234
- * Get all collaborators from all shared projects
235
- */
236
- async getAllCollaborators(t) {
237
- const o = "all_collaborators", n = R.get(o);
238
- if (n && Date.now() - n.timestamp < q)
239
- return n.result;
240
- try {
241
- const { results: r } = await t.getProjects({}), i = r.filter((u) => u.isShared);
242
- if (i.length === 0) {
243
- const u = [];
244
- return R.set(o, { result: u, timestamp: Date.now() }), u;
245
- }
246
- const c = [], a = /* @__PURE__ */ new Set(), d = i.map(
247
- (u) => this.getProjectCollaborators(t, u.id)
248
- ), l = await Promise.allSettled(d);
249
- for (const u of l)
250
- if (u.status === "fulfilled")
251
- for (const p of u.value)
252
- p && !a.has(p.id) && (c.push(p), a.add(p.id));
253
- return R.set(o, {
254
- result: c,
255
- timestamp: Date.now()
256
- }), c;
257
- } catch {
258
- return [];
259
- }
260
- }
261
- /**
262
- * Clear all caches - useful for testing
263
- */
264
- clearCache() {
265
- A.clear(), R.clear();
266
- }
267
- }
268
- const _ = new Le();
269
- async function We(e, t) {
270
- return _.resolveUser(e, t);
271
- }
272
- const ye = ["assigned", "unassignedOrMe", "all"];
273
- async function ee(e, t) {
274
- if (!t)
275
- return;
276
- const o = await We(e, t);
277
- if (!o)
278
- throw new Error(
279
- `Could not find user: "${t}". Make sure the user is a collaborator on a shared project.`
280
- );
281
- return { userId: o.userId, email: o.email };
282
- }
283
- function H(e, t) {
284
- return t.length === 0 ? e : e.length === 0 ? t : `${e} & ${t}`;
285
- }
286
- function Be({
287
- resolvedAssigneeId: e,
288
- assigneeEmail: t,
289
- responsibleUserFiltering: o = "unassignedOrMe"
290
- }) {
291
- return e && t ? `assigned to: ${t}` : o === "unassignedOrMe" ? "!assigned to: others" : o === "assigned" ? "assigned to: others" : "";
292
- }
293
- function de({
294
- tasks: e,
295
- resolvedAssigneeId: t,
296
- currentUserId: o,
297
- responsibleUserFiltering: n = "unassignedOrMe"
298
- }) {
299
- return t ? e.filter((r) => r.responsibleUid === t) : n === "unassignedOrMe" ? e.filter((r) => !r.responsibleUid || r.responsibleUid === o) : e;
300
- }
301
- function W(e) {
302
- return "inboxProject" in e;
303
- }
304
- async function Ie(e) {
305
- const { apiMethod: t, args: o, limit: n = 100 } = e, r = [];
306
- let i = null;
307
- do {
308
- const c = await t({
309
- ...o,
310
- cursor: i,
311
- limit: n
312
- });
313
- r.push(...c.results), i = c.nextCursor ?? null;
314
- } while (i !== null);
315
- return r;
316
- }
317
- async function ke(e) {
318
- return Ie({
319
- apiMethod: (t) => e.getProjects(t),
320
- limit: S.PROJECTS_MAX
321
- });
322
- }
323
- async function ze(e, t) {
324
- return Ie({
325
- apiMethod: (o) => e.getSections(o),
326
- args: t ? { projectId: t } : {},
327
- limit: S.SECTIONS_MAX
328
- });
329
- }
330
- function Ye(e, t, o, n) {
331
- const r = [t, o, n].filter(Boolean);
332
- if (r.length > 1)
333
- throw new Error(
334
- `Task ${e}: Only one of projectId, sectionId, or parentId can be specified at a time. The Todoist API requires exactly one destination for move operations.`
335
- );
336
- if (r.length === 0)
337
- throw new Error(
338
- `Task ${e}: At least one of projectId, sectionId, or parentId must be provided for move operations.`
339
- );
340
- if (t) return { projectId: t };
341
- if (o) return { sectionId: o };
342
- if (n) return { parentId: n };
343
- throw new Error("Unexpected error: No valid move parameter found");
344
- }
345
- function O(e) {
346
- return {
347
- id: e.id,
348
- content: e.content,
349
- description: e.description,
350
- dueDate: e.due?.date,
351
- recurring: e.due?.isRecurring && e.due.string ? e.due.string : !1,
352
- deadlineDate: e.deadline?.date,
353
- priority: Re(e.priority) ?? "p4",
354
- projectId: e.projectId,
355
- sectionId: e.sectionId ?? void 0,
356
- parentId: e.parentId ?? void 0,
357
- labels: e.labels,
358
- duration: e.duration ? Me(e.duration.amount) : void 0,
359
- responsibleUid: e.responsibleUid ?? void 0,
360
- assignedByUid: e.assignedByUid ?? void 0,
361
- checked: e.checked,
362
- completedAt: e.completedAt ?? void 0
363
- };
364
- }
365
- function we(e) {
366
- return {
367
- id: e.id,
368
- name: e.name,
369
- color: e.color,
370
- isFavorite: e.isFavorite,
371
- isShared: e.isShared,
372
- parentId: W(e) ? e.parentId ?? void 0 : void 0,
373
- inboxProject: W(e) ? e.inboxProject ?? !1 : !1,
374
- viewStyle: e.viewStyle
375
- };
376
- }
377
- function te(e) {
378
- return {
379
- id: e.id,
380
- taskId: e.taskId ?? void 0,
381
- projectId: e.projectId ?? void 0,
382
- content: e.content,
383
- postedAt: e.postedAt,
384
- postedUid: e.postedUid ?? void 0,
385
- fileAttachment: e.fileAttachment ? {
386
- resourceType: e.fileAttachment.resourceType,
387
- fileName: e.fileAttachment.fileName ?? void 0,
388
- fileSize: e.fileAttachment.fileSize ?? void 0,
389
- fileType: e.fileAttachment.fileType ?? void 0,
390
- fileUrl: e.fileAttachment.fileUrl ?? void 0,
391
- fileDuration: e.fileAttachment.fileDuration ?? void 0,
392
- uploadState: e.fileAttachment.uploadState ?? void 0,
393
- url: e.fileAttachment.url ?? void 0,
394
- title: e.fileAttachment.title ?? void 0,
395
- image: e.fileAttachment.image ?? void 0,
396
- imageWidth: e.fileAttachment.imageWidth ?? void 0,
397
- imageHeight: e.fileAttachment.imageHeight ?? void 0
398
- } : void 0
399
- };
400
- }
401
- function He(e) {
402
- return {
403
- id: e.id ?? void 0,
404
- objectType: e.objectType,
405
- objectId: e.objectId,
406
- eventType: e.eventType,
407
- eventDate: e.eventDate,
408
- parentProjectId: e.parentProjectId ?? void 0,
409
- parentItemId: e.parentItemId ?? void 0,
410
- initiatorId: e.initiatorId ?? void 0,
411
- extraData: e.extraData ?? void 0
412
- };
413
- }
414
- const Ke = F.object({
415
- httpStatusCode: F.number(),
416
- responseData: F.object({
417
- error: F.string(),
418
- errorCode: F.number(),
419
- errorTag: F.string()
420
- })
421
- });
422
- async function se({
423
- client: e,
424
- query: t,
425
- limit: o,
426
- cursor: n
427
- }) {
428
- try {
429
- const { results: r, nextCursor: i } = await e.getTasksByFilter({ query: t, cursor: n, limit: o });
430
- return { tasks: r.map(O), nextCursor: i };
431
- } catch (r) {
432
- const i = Ke.safeParse(r);
433
- if (!i.success)
434
- throw r;
435
- const { responseData: c } = i.data;
436
- throw c.errorTag === "INVALID_SEARCH_QUERY" ? new Error(`Invalid filter query: ${t}`) : new Error(
437
- `${c.error} (tag: ${c.errorTag}, code: ${c.errorCode})`
438
- );
439
- }
440
- }
441
- const B = s.object({
442
- id: s.string().describe("The unique ID of the task."),
443
- content: s.string().describe("The task title/content."),
444
- description: s.string().describe("The task description."),
445
- dueDate: s.string().optional().describe("The due date of the task (ISO 8601 format)."),
446
- recurring: s.union([s.boolean(), s.string()]).describe("Whether the task is recurring, or the recurrence string."),
447
- deadlineDate: s.string().optional().describe("The deadline date of the task (ISO 8601 format)."),
448
- priority: Q.describe(
449
- "The priority level: p1 (highest), p2 (high), p3 (medium), p4 (lowest)."
450
- ),
451
- projectId: s.string().describe("The ID of the project this task belongs to."),
452
- sectionId: s.string().optional().describe("The ID of the section this task belongs to."),
453
- parentId: s.string().optional().describe("The ID of the parent task (for subtasks)."),
454
- labels: s.array(s.string()).optional().describe("The labels attached to this task."),
455
- duration: s.string().optional().describe('The duration of the task (e.g., "2h30m").'),
456
- responsibleUid: s.string().optional().describe("The UID of the user responsible for this task."),
457
- isUncompletable: s.boolean().optional().describe("Whether the task is uncompletable (organizational header)."),
458
- assignedByUid: s.string().optional().describe("The UID of the user who assigned this task."),
459
- checked: s.boolean().describe("Whether the task is checked/completed."),
460
- completedAt: s.string().optional().describe("When the task was completed (ISO 8601 format).")
461
- }), oe = s.object({
462
- id: s.string().describe("The unique ID of the project."),
463
- name: s.string().describe("The name of the project."),
464
- color: s.string().describe("The color of the project."),
465
- isFavorite: s.boolean().describe("Whether the project is marked as favorite."),
466
- isShared: s.boolean().describe("Whether the project is shared."),
467
- parentId: s.string().optional().describe("The ID of the parent project (for sub-projects)."),
468
- inboxProject: s.boolean().describe("Whether this is the inbox project."),
469
- viewStyle: s.string().describe("The view style of the project (list, board, calendar).")
470
- }), ne = s.object({
471
- id: s.string().describe("The unique ID of the section."),
472
- name: s.string().describe("The name of the section.")
473
- }), Ve = s.object({
474
- resourceType: s.string().describe("The type of resource (file, url, image, etc)."),
475
- fileName: s.string().optional().describe("The name of the file."),
476
- fileSize: s.number().optional().describe("The size of the file in bytes."),
477
- fileType: s.string().optional().describe("The MIME type of the file."),
478
- fileUrl: s.string().optional().describe("The URL to access the file."),
479
- fileDuration: s.number().optional().describe("The duration in milliseconds (for audio/video files)."),
480
- uploadState: s.enum(["pending", "completed"]).optional().describe("The upload state of the file."),
481
- url: s.string().optional().describe("The URL for link/url resource types."),
482
- title: s.string().optional().describe("The title for link/url resource types."),
483
- image: s.string().optional().describe("The image URL for image resource types."),
484
- imageWidth: s.number().optional().describe("The width of the image in pixels."),
485
- imageHeight: s.number().optional().describe("The height of the image in pixels.")
486
- }), re = s.object({
487
- id: s.string().describe("The unique ID of the comment."),
488
- taskId: s.string().optional().describe("The ID of the task this comment belongs to."),
489
- projectId: s.string().optional().describe("The ID of the project this comment belongs to."),
490
- content: s.string().describe("The content of the comment."),
491
- postedAt: s.string().describe("When the comment was posted (ISO 8601 format)."),
492
- postedUid: s.string().optional().describe("The UID of the user who posted this comment."),
493
- fileAttachment: Ve.optional().describe("File attachment information, if any.")
494
- }), Ge = s.object({
495
- id: s.string().optional().describe("The unique ID of the activity event."),
496
- objectType: s.string().describe("The type of object this event relates to (task, project, etc)."),
497
- objectId: s.string().describe("The ID of the object this event relates to."),
498
- eventType: s.string().describe("The type of event (added, updated, deleted, completed, etc)."),
499
- eventDate: s.string().describe("When the event occurred (ISO 8601 format)."),
500
- parentProjectId: s.string().optional().describe("The ID of the parent project."),
501
- parentItemId: s.string().optional().describe("The ID of the parent item."),
502
- initiatorId: s.string().optional().describe("The ID of the user who initiated this event."),
503
- extraData: s.record(s.unknown()).optional().describe("Additional event data.")
504
- }), qe = s.object({
505
- id: s.string().describe("The unique ID of the user."),
506
- name: s.string().describe("The full name of the user."),
507
- email: s.string().describe("The email address of the user.")
508
- }), Je = s.object({
509
- item: s.string().describe("The item that failed (usually an ID or identifier)."),
510
- error: s.string().describe("The error message."),
511
- code: s.string().optional().describe("The error code, if available.")
512
- }), g = {
513
- // Task management tools
514
- ADD_TASKS: "add-tasks",
515
- COMPLETE_TASKS: "complete-tasks",
516
- UPDATE_TASKS: "update-tasks",
517
- FIND_TASKS: "find-tasks",
518
- FIND_TASKS_BY_DATE: "find-tasks-by-date",
519
- FIND_COMPLETED_TASKS: "find-completed-tasks",
520
- // Project management tools
521
- ADD_PROJECTS: "add-projects",
522
- UPDATE_PROJECTS: "update-projects",
523
- FIND_PROJECTS: "find-projects",
524
- // Section management tools
525
- ADD_SECTIONS: "add-sections",
526
- UPDATE_SECTIONS: "update-sections",
527
- FIND_SECTIONS: "find-sections",
528
- // Comment management tools
529
- ADD_COMMENTS: "add-comments",
530
- UPDATE_COMMENTS: "update-comments",
531
- FIND_COMMENTS: "find-comments",
532
- // Assignment and collaboration tools
533
- FIND_PROJECT_COLLABORATORS: "find-project-collaborators",
534
- MANAGE_ASSIGNMENTS: "manage-assignments",
535
- // Activity and audit tools
536
- FIND_ACTIVITY: "find-activity",
537
- // General tools
538
- GET_OVERVIEW: "get-overview",
539
- DELETE_OBJECT: "delete-object",
540
- USER_INFO: "user-info",
541
- // OpenAI MCP tools
542
- SEARCH: "search",
543
- FETCH: "fetch"
544
- }, Xe = s.object({
545
- taskId: s.string().optional().describe("The ID of the task to comment on."),
546
- projectId: s.string().optional().describe(
547
- 'The ID of the project to comment on. Project ID should be an ID string, or the text "inbox", for inbox tasks.'
548
- ),
549
- content: s.string().min(1).describe("The content of the comment.")
550
- }), Ze = {
551
- comments: s.array(Xe).min(1).describe("The array of comments to add.")
552
- }, Qe = {
553
- comments: s.array(re).describe("The created comments."),
554
- totalCount: s.number().describe("The total number of comments created."),
555
- addedCommentIds: s.array(s.string()).describe("The IDs of the added comments.")
556
- }, et = {
557
- name: g.ADD_COMMENTS,
558
- description: "Add multiple comments to tasks or projects. Each comment must specify either taskId or projectId.",
559
- parameters: Ze,
560
- outputSchema: Qe,
561
- mutability: "additive",
562
- async execute(e, t) {
563
- const { comments: o } = e;
564
- for (const [l, u] of o.entries()) {
565
- if (!u.taskId && !u.projectId)
566
- throw new Error(
567
- `Comment ${l + 1}: Either taskId or projectId must be provided.`
568
- );
569
- if (u.taskId && u.projectId)
570
- throw new Error(
571
- `Comment ${l + 1}: Cannot provide both taskId and projectId. Choose one.`
572
- );
573
- }
574
- const r = o.some((l) => l.projectId === "inbox") ? await t.getUser() : null, i = o.map(async ({ content: l, taskId: u, projectId: p }) => {
575
- const b = p === "inbox" && r ? r.inboxProjectId : p;
576
- return await t.addComment({
577
- content: l,
578
- ...u ? { taskId: u } : { projectId: b }
579
- });
580
- }), a = (await Promise.all(i)).map(te);
581
- return {
582
- textContent: tt({ comments: a }),
583
- structuredContent: {
584
- comments: a,
585
- totalCount: a.length,
586
- addedCommentIds: a.map((l) => l.id)
587
- }
588
- };
589
- }
590
- };
591
- function tt({ comments: e }) {
592
- const t = e.filter((i) => i.taskId).length, o = e.filter((i) => i.projectId).length, n = [];
593
- if (t > 0) {
594
- const i = t > 1 ? "comments" : "comment";
595
- n.push(`${t} task ${i}`);
596
- }
597
- if (o > 0) {
598
- const i = o > 1 ? "comments" : "comment";
599
- n.push(`${o} project ${i}`);
600
- }
601
- return n.length > 0 ? `Added ${n.join(" and ")}` : "No comments added";
602
- }
603
- const st = s.object({
604
- name: s.string().min(1).describe("The name of the project."),
605
- parentId: s.string().optional().describe("The ID of the parent project. If provided, creates this as a sub-project."),
606
- isFavorite: s.boolean().optional().describe("Whether the project is a favorite. Defaults to false."),
607
- viewStyle: s.enum(["list", "board", "calendar"]).optional().describe('The project view style. Defaults to "list".')
608
- }), ot = {
609
- projects: s.array(st).min(1).describe("The array of projects to add.")
610
- }, nt = {
611
- projects: s.array(oe).describe("The created projects."),
612
- totalCount: s.number().describe("The total number of projects created.")
613
- }, rt = {
614
- name: g.ADD_PROJECTS,
615
- description: "Add one or more new projects.",
616
- parameters: ot,
617
- outputSchema: nt,
618
- mutability: "additive",
619
- async execute({ projects: e }, t) {
620
- const o = await Promise.all(e.map((i) => t.addProject(i))), n = it({ projects: o }), r = o.map((i) => ({
621
- ...i,
622
- parentId: "parentId" in i ? i.parentId ?? void 0 : void 0,
623
- inboxProject: "inboxProject" in i ? i.inboxProject : !1
624
- }));
625
- return {
626
- textContent: n,
627
- structuredContent: {
628
- projects: r,
629
- totalCount: r.length
630
- }
631
- };
632
- }
633
- };
634
- function it({ projects: e }) {
635
- const t = e.length, o = e.map((r) => `• ${r.name} (id=${r.id})`).join(`
636
- `);
637
- return `Added ${t} project${t === 1 ? "" : "s"}:
638
- ${o}`;
639
- }
640
- const at = s.object({
641
- name: s.string().min(1).describe("The name of the section."),
642
- projectId: s.string().min(1).describe(
643
- 'The ID of the project to add the section to. Project ID should be an ID string, or the text "inbox", for inbox tasks.'
644
- )
645
- }), ct = {
646
- sections: s.array(at).min(1).describe("The array of sections to add.")
647
- }, dt = {
648
- sections: s.array(ne).describe("The created sections."),
649
- totalCount: s.number().describe("The total number of sections created.")
650
- }, lt = {
651
- name: g.ADD_SECTIONS,
652
- description: "Add one or more new sections to projects.",
653
- parameters: ct,
654
- outputSchema: dt,
655
- mutability: "additive",
656
- async execute({ sections: e }, t) {
657
- const n = e.some((a) => a.projectId === "inbox") ? await t.getUser() : null, r = e.map((a) => ({
658
- ...a,
659
- projectId: a.projectId === "inbox" && n ? n.inboxProjectId : a.projectId
660
- })), i = await Promise.all(
661
- r.map((a) => t.addSection(a))
662
- );
663
- return {
664
- textContent: ut({ sections: i }),
665
- structuredContent: {
666
- sections: i,
667
- totalCount: i.length
668
- }
669
- };
670
- }
671
- };
672
- function ut({ sections: e }) {
673
- const t = e.length, o = e.map((r) => `• ${r.name} (id=${r.id}, projectId=${r.projectId})`).join(`
674
- `);
675
- return `Added ${t} section${t === 1 ? "" : "s"}:
676
- ${o}`;
677
- }
678
- const L = {
679
- USER_NOT_FOUND: "USER_NOT_FOUND",
680
- USER_NOT_COLLABORATOR: "USER_NOT_COLLABORATOR",
681
- PROJECT_NOT_SHARED: "PROJECT_NOT_SHARED",
682
- TASK_NOT_ACCESSIBLE: "TASK_NOT_ACCESSIBLE",
683
- PERMISSION_DENIED: "PERMISSION_DENIED",
684
- PROJECT_NOT_FOUND: "PROJECT_NOT_FOUND",
685
- TASK_NOT_FOUND: "TASK_NOT_FOUND"
686
- };
687
- class pt {
688
- /**
689
- * Validate a single assignment operation
690
- */
691
- async validateAssignment(t, o) {
692
- const { taskId: n, projectId: r, responsibleUid: i } = o, c = await _.resolveUser(t, i);
693
- if (!c)
694
- return {
695
- isValid: !1,
696
- taskId: n,
697
- projectId: r,
698
- error: {
699
- type: L.USER_NOT_FOUND,
700
- message: `User "${i}" not found`,
701
- suggestions: [
702
- "Check the spelling of the user name or email",
703
- "Ensure the user is a collaborator on at least one shared project",
704
- "Try using the user's full email address"
705
- ]
706
- }
707
- };
708
- try {
709
- const a = await t.getProject(r);
710
- if (!a.isShared)
711
- return {
712
- isValid: !1,
713
- taskId: n,
714
- projectId: r,
715
- resolvedUser: c,
716
- error: {
717
- type: L.PROJECT_NOT_SHARED,
718
- message: `Project "${a.name}" is not shared`,
719
- suggestions: [
720
- "Share the project with collaborators before assigning tasks",
721
- "Only shared projects support task assignments"
722
- ]
723
- }
724
- };
725
- if (!await _.validateProjectCollaborator(
726
- t,
727
- r,
728
- c.userId
729
- ))
730
- return {
731
- isValid: !1,
732
- taskId: n,
733
- projectId: r,
734
- resolvedUser: c,
735
- error: {
736
- type: L.USER_NOT_COLLABORATOR,
737
- message: `User "${c.displayName}" is not a collaborator on project "${a.name}"`,
738
- suggestions: [
739
- "Invite the user to collaborate on this project first",
740
- "Check if the user has been removed from the project",
741
- "Verify you have permission to see project collaborators"
742
- ]
743
- }
744
- };
745
- if (n)
746
- try {
747
- await t.getTask(n);
748
- } catch {
749
- return {
750
- isValid: !1,
751
- taskId: n,
752
- projectId: r,
753
- resolvedUser: c,
754
- error: {
755
- type: L.TASK_NOT_FOUND,
756
- message: `Task "${n}" not found or not accessible`,
757
- suggestions: [
758
- "Verify the task ID is correct",
759
- "Check if the task has been deleted",
760
- "Ensure you have access to the task"
761
- ]
762
- }
763
- };
764
- }
765
- return {
766
- isValid: !0,
767
- taskId: n,
768
- projectId: r,
769
- resolvedUser: c
770
- };
771
- } catch {
772
- return {
773
- isValid: !1,
774
- taskId: n,
775
- projectId: r,
776
- resolvedUser: c,
777
- error: {
778
- type: L.PERMISSION_DENIED,
779
- message: "Permission denied or API error occurred",
780
- suggestions: [
781
- "Check your API permissions",
782
- "Verify you have access to the project",
783
- "Try again later if this is a temporary API issue"
784
- ]
785
- }
786
- };
787
- }
788
- }
789
- /**
790
- * Validate multiple assignment operations in bulk
791
- */
792
- async validateBulkAssignment(t, o) {
793
- const n = o.map(
794
- (r) => this.validateAssignment(t, r)
795
- );
796
- return Promise.all(n);
797
- }
798
- /**
799
- * Validate assignment for task creation (no taskId required)
800
- */
801
- async validateTaskCreationAssignment(t, o, n) {
802
- return this.validateAssignment(t, {
803
- projectId: o,
804
- responsibleUid: n
805
- });
806
- }
807
- /**
808
- * Validate assignment for task update
809
- */
810
- async validateTaskUpdateAssignment(t, o, n) {
811
- if (n === null)
812
- return {
813
- isValid: !0,
814
- taskId: o
815
- };
816
- try {
817
- const r = await t.getTask(o);
818
- return this.validateAssignment(t, {
819
- taskId: o,
820
- projectId: r.projectId,
821
- responsibleUid: n
822
- });
823
- } catch {
824
- return {
825
- isValid: !1,
826
- taskId: o,
827
- error: {
828
- type: L.TASK_NOT_FOUND,
829
- message: `Task "${o}" not found or not accessible`,
830
- suggestions: [
831
- "Verify the task ID is correct",
832
- "Check if the task has been deleted",
833
- "Ensure you have access to the task"
834
- ]
835
- }
836
- };
837
- }
838
- }
839
- /**
840
- * Get detailed assignment eligibility information for troubleshooting
841
- */
842
- async getAssignmentEligibility(t, o, n, r) {
843
- const i = [];
844
- let c = !1, a;
845
- try {
846
- a = await t.getProject(o);
847
- } catch {
848
- return {
849
- canAssign: !1,
850
- projectInfo: {
851
- name: "Unknown",
852
- isShared: !1,
853
- collaboratorCount: 0
854
- },
855
- recommendations: ["Project not found or not accessible"]
856
- };
857
- }
858
- const d = await _.getProjectCollaborators(t, o), l = {
859
- name: a.name,
860
- isShared: a.isShared,
861
- collaboratorCount: d.length
862
- };
863
- if (!a.isShared)
864
- return i.push("Share this project to enable task assignments"), { canAssign: !1, projectInfo: l, recommendations: i };
865
- const u = await _.resolveUser(t, n);
866
- if (!u)
867
- return i.push("User not found - check spelling or invite to a shared project"), { canAssign: !1, projectInfo: l, recommendations: i };
868
- const p = d.some((y) => y.id === u.userId), b = {
869
- resolvedName: u.displayName,
870
- isCollaborator: p
871
- };
872
- if (!p)
873
- return i.push(
874
- `Invite ${u.displayName} to collaborate on project "${a.name}"`
875
- ), { canAssign: !1, projectInfo: l, userInfo: b, recommendations: i };
876
- let m;
877
- if (r && r.length > 0) {
878
- let y = 0, k = 0;
879
- for (const w of r)
880
- try {
881
- await t.getTask(w), y++;
882
- } catch {
883
- k++;
884
- }
885
- m = { accessibleTasks: y, inaccessibleTasks: k }, k > 0 && i.push(`${k} task(s) are not accessible`);
886
- }
887
- return c = !0, i.push(`Ready to assign tasks to ${u.displayName}`), {
888
- canAssign: c,
889
- projectInfo: l,
890
- userInfo: b,
891
- taskInfo: m,
892
- recommendations: i
893
- };
894
- }
895
- }
896
- const ie = new pt();
897
- function ht(e = /* @__PURE__ */ new Date()) {
898
- return e.toISOString().split("T")[0] ?? "";
899
- }
900
- function je(e, t, o = {}) {
901
- const { context: n, showDetails: r = !1 } = o, i = t.length, c = [], d = `${e} ${i} ${i === 1 ? "task" : "tasks"}${n ? ` ${n}` : ""}.`;
902
- c.push(d);
903
- const l = 5;
904
- if (r || i <= l) {
905
- const u = K(t, l);
906
- if (u.length > 0) {
907
- const p = i > l ? `, +${i - l} more` : "";
908
- c.push(`Tasks:
909
- ${u}${p}.`);
910
- }
911
- }
912
- return c.join(`
913
- `);
914
- }
915
- function mt(e) {
916
- const { action: t, success: o, total: n, successItems: r, failures: i } = e, c = [], a = `${t}: ${o}/${n} successful.`;
917
- if (c.push(a), r?.length && r.length <= 5 && c.push(`Completed:
918
- ${r.map((d) => ` ${d}`).join(`
919
- `)}.`), i?.length) {
920
- const d = i.length, l = `Failed (${d}):
921
- ${i.slice(0, G.MAX_FAILURES_SHOWN).map((u) => ` ${u.item} (Error: ${u.error}${u.code ? ` [${u.code}]` : ""})`).join(
922
- `
923
- `
924
- )}${d > G.MAX_FAILURES_SHOWN ? `, +${d - G.MAX_FAILURES_SHOWN} more` : ""}.`;
925
- c.push(l);
926
- }
927
- return c.join(`
928
- `);
929
- }
930
- function ft(e) {
931
- const t = e.content || e.title || "Untitled", o = e.dueDate ? ` • due ${e.dueDate}` : "", n = e.priority ? ` • ${e.priority.toUpperCase()}` : "", r = e.projectName ? ` • ${e.projectName}` : "", i = e.id ? ` • id=${e.id}` : "";
932
- return ` ${t}${o}${n}${r}${i}`;
933
- }
934
- function bt(e) {
935
- const t = e.inboxProject ? " • Inbox" : "", o = e.isFavorite ? " • ⭐" : "", n = e.isShared ? " • Shared" : "", r = e.viewStyle && e.viewStyle !== "list" ? ` • ${e.viewStyle}` : "", i = ` • id=${e.id}`;
936
- return ` ${e.name}${t}${o}${n}${r}${i}`;
937
- }
938
- function K(e, t = 5) {
939
- const n = e.slice(0, t).map(ft).join(`
940
- `);
941
- if (e.length > t) {
942
- const r = e.length - t;
943
- return `${n}
944
- ... and ${r} more task${r === 1 ? "" : "s"}`;
945
- }
946
- return n;
947
- }
948
- function N({
949
- subject: e,
950
- count: t,
951
- limit: o,
952
- nextCursor: n,
953
- filterHints: r,
954
- previewLines: i,
955
- zeroReasonHints: c,
956
- nextSteps: a
957
- }) {
958
- const d = [], l = `${e}: ${t}${typeof o == "number" ? ` (limit ${o})` : ""}${n ? ", more available" : ""}.`;
959
- return d.push(l), r?.length && d.push(`Filter: ${r.join("; ")}.`), i?.length && d.push(`Preview:
960
- ${i}`), !t && c?.length && d.push(`No results. ${c.join("; ")}.`), (a?.length || n) && d.push(ve(a || [], n)), d.join(`
961
- `);
962
- }
963
- function ve(e, t) {
964
- const o = [...e];
965
- return t && o.push(`Pass cursor '${t}' to fetch more results.`), `${o.length === 1 ? "Possible suggested next step:" : "Possible suggested next steps:"}
966
- ${o.map((r) => `- ${r}`).join(`
967
- `)}`;
968
- }
969
- const gt = s.object({
970
- content: s.string().min(1).describe(
971
- 'The task name/title. Should be concise and actionable (e.g., "Review PR #123", "Call dentist"). For longer content, use the description field instead. Supports Markdown.'
972
- ),
973
- description: s.string().optional().describe(
974
- "Additional details, notes, or context for the task. Use this for longer content rather than putting it in the task name. Supports Markdown."
975
- ),
976
- priority: Q.optional().describe(
977
- "The priority of the task: p1 (highest), p2 (high), p3 (medium), p4 (lowest/default)."
978
- ),
979
- dueString: s.string().optional().describe("The due date for the task, in natural language."),
980
- deadlineDate: s.string().optional().describe(
981
- 'The deadline date for the task in ISO 8601 format (YYYY-MM-DD, e.g., "2025-12-31"). Deadlines are immovable constraints shown with a different indicator than due dates.'
982
- ),
983
- duration: s.string().optional().describe(
984
- 'The duration of the task. Use format: "2h" (hours), "90m" (minutes), "2h30m" (combined), or "1.5h" (decimal hours). Max 24h.'
985
- ),
986
- labels: s.array(s.string()).optional().describe("The labels to attach to the task."),
987
- projectId: s.string().optional().describe(
988
- 'The project ID to add this task to. Project ID should be an ID string, or the text "inbox", for inbox tasks.'
989
- ),
990
- sectionId: s.string().optional().describe("The section ID to add this task to."),
991
- parentId: s.string().optional().describe("The parent task ID (for subtasks)."),
992
- responsibleUser: s.string().optional().describe(
993
- "Assign task to this user. Can be a user ID, name, or email address. User must be a collaborator on the target project."
994
- ),
995
- isUncompletable: s.boolean().optional().describe(
996
- "Whether this task should be uncompletable (organizational header). Tasks with isUncompletable: true appear as organizational headers and cannot be completed."
997
- )
998
- }), Tt = {
999
- tasks: s.array(gt).min(1).describe("The array of tasks to add.")
1000
- }, yt = {
1001
- tasks: s.array(B).describe("The created tasks."),
1002
- totalCount: s.number().describe("The total number of tasks created.")
1003
- }, It = {
1004
- name: g.ADD_TASKS,
1005
- description: "Add one or more tasks to a project, section, or parent. Supports assignment to project collaborators.",
1006
- parameters: Tt,
1007
- outputSchema: yt,
1008
- mutability: "additive",
1009
- async execute({ tasks: e }, t) {
1010
- const o = e.map((c) => kt(c, t)), r = (await Promise.all(o)).map(O);
1011
- return {
1012
- textContent: wt({
1013
- tasks: r,
1014
- args: { tasks: e }
1015
- }),
1016
- structuredContent: {
1017
- tasks: r,
1018
- totalCount: r.length
1019
- }
1020
- };
1021
- }
1022
- };
1023
- async function kt(e, t) {
1024
- const {
1025
- duration: o,
1026
- projectId: n,
1027
- sectionId: r,
1028
- parentId: i,
1029
- responsibleUser: c,
1030
- priority: a,
1031
- labels: d,
1032
- deadlineDate: l,
1033
- ...u
1034
- } = e;
1035
- let p = n;
1036
- n === "inbox" && (p = (await t.getUser()).inboxProjectId);
1037
- let b = {
1038
- ...u,
1039
- projectId: p,
1040
- sectionId: r,
1041
- parentId: i,
1042
- labels: d,
1043
- deadlineDate: l
1044
- };
1045
- if (a && (b.priority = Te(a)), c && !p && !r && !i)
1046
- throw new Error(
1047
- `Task "${e.content}": Cannot assign tasks without specifying project context. Please specify a projectId, sectionId, or parentId.`
1048
- );
1049
- if (o)
1050
- try {
1051
- const { minutes: m } = ge(o);
1052
- b = {
1053
- ...b,
1054
- duration: m,
1055
- durationUnit: "minute"
1056
- };
1057
- } catch (m) {
1058
- throw m instanceof U ? new Error(`Task "${e.content}": ${m.message}`) : m;
1059
- }
1060
- if (c) {
1061
- let m = p;
1062
- if (!m && i)
1063
- try {
1064
- m = (await t.getTask(i)).projectId;
1065
- } catch {
1066
- throw new Error(`Task "${e.content}": Parent task "${i}" not found`);
1067
- }
1068
- else if (!m && r)
1069
- throw new Error(
1070
- `Task "${e.content}": When assigning tasks to sections, please also specify projectId`
1071
- );
1072
- if (!m)
1073
- throw new Error(
1074
- `Task "${e.content}": Cannot determine target project for assignment validation`
1075
- );
1076
- const y = await ie.validateTaskCreationAssignment(
1077
- t,
1078
- m,
1079
- c
1080
- );
1081
- if (!y.isValid) {
1082
- const k = y.error?.message || "Assignment validation failed", w = y.error?.suggestions?.join(". ") || "";
1083
- throw new Error(
1084
- `Task "${e.content}": ${k}${w ? `. ${w}` : ""}`
1085
- );
1086
- }
1087
- b.assigneeId = y.resolvedUser?.userId;
1088
- }
1089
- return await t.addTask(b);
1090
- }
1091
- function wt({
1092
- tasks: e,
1093
- args: t
1094
- }) {
1095
- const o = /* @__PURE__ */ new Set();
1096
- for (const r of t.tasks)
1097
- r.projectId ? o.add("projects") : r.sectionId ? o.add("sections") : r.parentId ? o.add("subtasks") : o.add("inbox");
1098
- let n = "";
1099
- if (o.size === 1) {
1100
- const r = Array.from(o)[0];
1101
- n = r === "inbox" ? "" : `to ${r}`;
1102
- } else o.size > 1 && (n = "to multiple contexts");
1103
- return je("Added", e, {
1104
- context: n,
1105
- showDetails: !0
1106
- });
1107
- }
1108
- const jt = {
1109
- ids: s.array(s.string().min(1)).min(1).describe("The IDs of the tasks to complete.")
1110
- }, vt = {
1111
- completed: s.array(s.string()).describe("The IDs of successfully completed tasks."),
1112
- failures: s.array(Je).describe("Failed task completions with error details."),
1113
- totalRequested: s.number().describe("The total number of tasks requested to complete."),
1114
- successCount: s.number().describe("The number of successfully completed tasks."),
1115
- failureCount: s.number().describe("The number of failed task completions.")
1116
- }, Ct = {
1117
- name: g.COMPLETE_TASKS,
1118
- description: "Complete one or more tasks by their IDs.",
1119
- parameters: jt,
1120
- outputSchema: vt,
1121
- mutability: "mutating",
1122
- async execute(e, t) {
1123
- const o = [], n = [];
1124
- for (const i of e.ids)
1125
- try {
1126
- await t.closeTask(i), o.push(i);
1127
- } catch (c) {
1128
- const a = c instanceof Error ? c.message : "Unknown error";
1129
- n.push({
1130
- item: i,
1131
- error: a
1132
- });
1133
- }
1134
- return {
1135
- textContent: St({
1136
- completed: o,
1137
- failures: n,
1138
- args: e
1139
- }),
1140
- structuredContent: {
1141
- completed: o,
1142
- failures: n,
1143
- totalRequested: e.ids.length,
1144
- successCount: o.length,
1145
- failureCount: n.length
1146
- }
1147
- };
1148
- }
1149
- };
1150
- function St({
1151
- completed: e,
1152
- failures: t,
1153
- args: o
1154
- }) {
1155
- return mt({
1156
- action: "Completed tasks",
1157
- success: e.length,
1158
- total: o.ids.length,
1159
- successItems: e,
1160
- failures: t
1161
- });
1162
- }
1163
- const $t = {
1164
- type: s.enum(["project", "section", "task", "comment"]).describe("The type of entity to delete."),
1165
- id: s.string().min(1).describe("The ID of the entity to delete.")
1166
- }, Dt = {
1167
- deletedEntity: s.object({
1168
- type: s.enum(["project", "section", "task", "comment"]).describe("The type of deleted entity."),
1169
- id: s.string().describe("The ID of the deleted entity.")
1170
- }).describe("Information about the deleted entity."),
1171
- success: s.boolean().describe("Whether the deletion was successful.")
1172
- }, xt = {
1173
- name: g.DELETE_OBJECT,
1174
- description: "Delete a project, section, task, or comment by its ID.",
1175
- parameters: $t,
1176
- outputSchema: Dt,
1177
- mutability: "mutating",
1178
- async execute(e, t) {
1179
- switch (e.type) {
1180
- case "project":
1181
- await t.deleteProject(e.id);
1182
- break;
1183
- case "section":
1184
- await t.deleteSection(e.id);
1185
- break;
1186
- case "task":
1187
- await t.deleteTask(e.id);
1188
- break;
1189
- case "comment":
1190
- await t.deleteComment(e.id);
1191
- break;
1192
- }
1193
- return {
1194
- textContent: `Deleted ${e.type}: id=${e.id}`,
1195
- structuredContent: {
1196
- deletedEntity: { type: e.type, id: e.id },
1197
- success: !0
1198
- }
1199
- };
1200
- }
1201
- }, At = {
1202
- id: s.string().min(1).describe(
1203
- 'A unique identifier for the document in the format "task:{id}" or "project:{id}".'
1204
- )
1205
- }, Ut = {
1206
- id: s.string().describe("The ID of the fetched document."),
1207
- title: s.string().describe("The title of the document."),
1208
- text: s.string().describe("The text content of the document."),
1209
- url: s.string().describe("The URL of the document."),
1210
- metadata: s.record(s.unknown()).optional().describe("Additional metadata about the document.")
1211
- }, Pt = {
1212
- name: g.FETCH,
1213
- description: 'Fetch the full contents of a task or project by its ID. The ID should be in the format "task:{id}" or "project:{id}".',
1214
- parameters: At,
1215
- outputSchema: Ut,
1216
- mutability: "readonly",
1217
- async execute(e, t) {
1218
- const { id: o } = e, [n, r] = o.split(":", 2);
1219
- if (!r || n !== "task" && n !== "project")
1220
- throw new Error(
1221
- 'Invalid ID format. Expected "task:{id}" or "project:{id}". Example: "task:8485093748" or "project:6cfCcrrCFg2xP94Q"'
1222
- );
1223
- let i;
1224
- if (n === "task") {
1225
- const c = await t.getTask(r), a = O(c), d = [a.content];
1226
- a.description && d.push(`
1227
-
1228
- Description: ${a.description}`), a.dueDate && d.push(`
1229
- Due: ${a.dueDate}`), a.labels.length > 0 && d.push(`
1230
- Labels: ${a.labels.join(", ")}`), i = {
1231
- id: `task:${a.id}`,
1232
- title: a.content,
1233
- text: d.join(""),
1234
- url: me(a.id),
1235
- metadata: {
1236
- priority: a.priority,
1237
- projectId: a.projectId,
1238
- sectionId: a.sectionId,
1239
- parentId: a.parentId,
1240
- recurring: a.recurring,
1241
- duration: a.duration,
1242
- responsibleUid: a.responsibleUid,
1243
- assignedByUid: a.assignedByUid,
1244
- checked: a.checked,
1245
- completedAt: a.completedAt
1246
- }
1247
- };
1248
- } else {
1249
- const c = await t.getProject(r), a = we(c), d = [a.name];
1250
- a.isShared && d.push(`
1251
-
1252
- Shared project`), a.isFavorite && d.push(`
1253
- Favorite: Yes`), i = {
1254
- id: `project:${a.id}`,
1255
- title: a.name,
1256
- text: d.join(""),
1257
- url: fe(a.id),
1258
- metadata: {
1259
- color: a.color,
1260
- isFavorite: a.isFavorite,
1261
- isShared: a.isShared,
1262
- parentId: a.parentId,
1263
- inboxProject: a.inboxProject,
1264
- viewStyle: a.viewStyle
1265
- }
1266
- };
1267
- }
1268
- return { textContent: JSON.stringify(i) };
1269
- }
1270
- }, Et = {
1271
- objectType: s.enum(["task", "project", "comment"]).optional().describe("Type of object to filter by."),
1272
- objectId: s.string().optional().describe("Filter by specific object ID (task, project, or comment)."),
1273
- eventType: s.enum([
1274
- "added",
1275
- "updated",
1276
- "deleted",
1277
- "completed",
1278
- "uncompleted",
1279
- "archived",
1280
- "unarchived",
1281
- "shared",
1282
- "left"
1283
- ]).optional().describe("Type of event to filter by."),
1284
- projectId: s.string().optional().describe("Filter events by parent project ID."),
1285
- taskId: s.string().optional().describe("Filter events by parent task ID (for subtask events)."),
1286
- initiatorId: s.string().optional().describe("Filter by the user ID who initiated the event."),
1287
- limit: s.number().int().min(1).max(S.ACTIVITY_MAX).default(S.ACTIVITY_DEFAULT).describe("Maximum number of activity events to return."),
1288
- cursor: s.string().optional().describe("Pagination cursor for retrieving the next page of results.")
1289
- }, Ot = {
1290
- events: s.array(Ge).describe("The activity events."),
1291
- nextCursor: s.string().optional().describe("Cursor for the next page of results."),
1292
- totalCount: s.number().describe("The total number of events in this page."),
1293
- hasMore: s.boolean().describe("Whether there are more results available."),
1294
- appliedFilters: s.record(s.unknown()).describe("The filters that were applied to the search.")
1295
- }, _t = {
1296
- name: g.FIND_ACTIVITY,
1297
- description: "Retrieve recent activity logs to monitor and audit changes in Todoist. Shows events from all users by default (use initiatorId to filter by specific user). Track task completions, updates, deletions, project changes, and more with flexible filtering. Note: Date-based filtering is not supported by the Todoist API.",
1298
- parameters: Et,
1299
- outputSchema: Ot,
1300
- mutability: "readonly",
1301
- async execute(e, t) {
1302
- const { objectType: o, objectId: n, eventType: r, projectId: i, taskId: c, initiatorId: a, limit: d, cursor: l } = e, u = {
1303
- limit: d,
1304
- cursor: l ?? null
1305
- };
1306
- o && (u.objectType = o), n && n !== "remove" && (u.objectId = n), r && (u.eventType = r), i && (u.parentProjectId = i), c && (u.parentItemId = c), a && (u.initiatorId = a);
1307
- const { results: p, nextCursor: b } = await t.getActivityLogs(u), m = p.map(He);
1308
- return {
1309
- textContent: Nt({ events: m, args: e, nextCursor: b }),
1310
- structuredContent: {
1311
- events: m,
1312
- nextCursor: b ?? void 0,
1313
- totalCount: m.length,
1314
- hasMore: !!b,
1315
- appliedFilters: e
1316
- }
1317
- };
1318
- }
1319
- };
1320
- function Nt({
1321
- events: e,
1322
- args: t,
1323
- nextCursor: o
1324
- }) {
1325
- let n = "Activity events";
1326
- const r = [];
1327
- if (t.eventType && r.push(`${t.eventType}`), t.objectType) {
1328
- const a = t.objectType === "task" ? "tasks" : `${t.objectType}s`;
1329
- r.push(a);
1330
- }
1331
- r.length > 0 && (n = `Activity: ${r.join(" ")}`);
1332
- const i = [];
1333
- t.objectId && i.push(`object ID: ${t.objectId}`), t.projectId && i.push(`project: ${t.projectId}`), t.taskId && i.push(`task: ${t.taskId}`), t.initiatorId && i.push(`initiator: ${t.initiatorId}`);
1334
- const c = [];
1335
- return e.length === 0 && (c.push("No activity events match the specified filters"), c.push("Note: Activity logs only show recent events"), t.eventType && c.push(`Try removing the eventType filter (${t.eventType})`), t.objectType && c.push(`Try removing the objectType filter (${t.objectType})`), (t.objectId || t.projectId || t.taskId) && c.push("Verify the object ID is correct")), N({
1336
- subject: n,
1337
- count: e.length,
1338
- limit: t.limit,
1339
- nextCursor: o ?? void 0,
1340
- filterHints: i,
1341
- previewLines: Mt(e, Math.min(e.length, t.limit)),
1342
- zeroReasonHints: c
1343
- });
1344
- }
1345
- function Mt(e, t = 10) {
1346
- const n = e.slice(0, t).map(Ft).join(`
1347
- `);
1348
- if (e.length > t) {
1349
- const r = e.length - t;
1350
- return `${n}
1351
- ... and ${r} more event${r === 1 ? "" : "s"}`;
1352
- }
1353
- return n;
1354
- }
1355
- function Ft(e) {
1356
- const t = Rt(e.eventDate), o = `${e.eventType} ${e.objectType}`;
1357
- let n = "";
1358
- if (e.extraData) {
1359
- const a = e.extraData.content || e.extraData.name || e.extraData.last_content;
1360
- a && typeof a == "string" && (n = ` • "${a.length > 50 ? `${a.substring(0, 47)}...` : a}"`);
1361
- }
1362
- const r = e.objectId ? ` • id=${e.objectId}` : "", i = e.initiatorId ? ` • by=${e.initiatorId}` : " • system", c = e.parentProjectId ? ` • project=${e.parentProjectId}` : "";
1363
- return ` [${t}] ${o}${n}${r}${i}${c}`;
1364
- }
1365
- function Rt(e) {
1366
- try {
1367
- const t = new Date(e), o = t.toLocaleDateString("en-US", { month: "short", timeZone: "UTC" }), n = t.toLocaleDateString("en-US", { day: "numeric", timeZone: "UTC" }), r = t.toLocaleTimeString("en-US", {
1368
- hour: "2-digit",
1369
- minute: "2-digit",
1370
- hour12: !1,
1371
- timeZone: "UTC"
1372
- });
1373
- return `${o} ${n}, ${r}`;
1374
- } catch {
1375
- return e;
1376
- }
1377
- }
1378
- const Lt = {
1379
- taskId: s.string().optional().describe("Find comments for a specific task."),
1380
- projectId: s.string().optional().describe(
1381
- 'Find comments for a specific project. Project ID should be an ID string, or the text "inbox", for inbox tasks.'
1382
- ),
1383
- commentId: s.string().optional().describe("Get a specific comment by ID."),
1384
- cursor: s.string().optional().describe("Pagination cursor for retrieving more results."),
1385
- limit: s.number().int().min(1).max(S.COMMENTS_MAX).optional().describe("Maximum number of comments to return")
1386
- }, Wt = {
1387
- comments: s.array(re).describe("The found comments."),
1388
- nextCursor: s.string().optional().describe("Cursor for the next page of results."),
1389
- totalCount: s.number().describe("The total number of comments in this page.")
1390
- }, Bt = {
1391
- name: g.FIND_COMMENTS,
1392
- description: "Find comments by task, project, or get a specific comment by ID. Exactly one of taskId, projectId, or commentId must be provided.",
1393
- parameters: Lt,
1394
- outputSchema: Wt,
1395
- mutability: "readonly",
1396
- async execute(e, t) {
1397
- const o = [e.taskId, e.projectId, e.commentId].filter(Boolean);
1398
- if (o.length === 0)
1399
- throw new Error("Must provide exactly one of: taskId, projectId, or commentId.");
1400
- if (o.length > 1)
1401
- throw new Error(
1402
- "Cannot provide multiple search parameters. Choose one of: taskId, projectId, or commentId."
1403
- );
1404
- const n = e.projectId === "inbox" ? (await t.getUser()).inboxProjectId : e.projectId;
1405
- let r = !1, i = null, c;
1406
- if (e.commentId)
1407
- c = [await t.getComment(e.commentId)];
1408
- else if (e.taskId) {
1409
- const l = await t.getComments({
1410
- taskId: e.taskId,
1411
- cursor: e.cursor || null,
1412
- limit: e.limit || S.COMMENTS_DEFAULT
1413
- });
1414
- c = l.results, r = l.nextCursor !== null, i = l.nextCursor;
1415
- } else if (n) {
1416
- const l = await t.getComments({
1417
- projectId: n,
1418
- cursor: e.cursor || null,
1419
- limit: e.limit || S.COMMENTS_DEFAULT
1420
- });
1421
- c = l.results, r = l.nextCursor !== null, i = l.nextCursor;
1422
- } else
1423
- throw new Error("Invalid state: no search parameter provided");
1424
- const a = c.map(te);
1425
- return {
1426
- textContent: zt({
1427
- comments: a,
1428
- searchType: e.commentId ? "single" : e.taskId ? "task" : "project",
1429
- searchId: e.commentId || e.taskId || e.projectId || "",
1430
- hasMore: r,
1431
- nextCursor: i
1432
- }),
1433
- structuredContent: {
1434
- comments: a,
1435
- searchType: e.commentId ? "single" : e.taskId ? "task" : "project",
1436
- searchId: e.commentId || e.taskId || e.projectId || "",
1437
- hasMore: r,
1438
- nextCursor: i ?? void 0,
1439
- totalCount: a.length
1440
- }
1441
- };
1442
- }
1443
- };
1444
- function zt({
1445
- comments: e,
1446
- searchType: t,
1447
- searchId: o,
1448
- hasMore: n,
1449
- nextCursor: r
1450
- }) {
1451
- if (e.length === 0)
1452
- return `No comments found for ${t}${t !== "single" ? ` ${o}` : ""}`;
1453
- let i;
1454
- if (t === "single") {
1455
- const c = e[0];
1456
- if (!c)
1457
- return "Comment not found";
1458
- i = `Found comment${c.fileAttachment !== void 0 ? ` • Has attachment: ${c.fileAttachment?.fileName || "file"}` : ""} • id=${c.id}`;
1459
- } else {
1460
- const c = e.filter((l) => l.fileAttachment !== void 0).length, a = c > 0 ? ` (${c} with attachments)` : "", d = e.length === 1 ? "comment" : "comments";
1461
- i = `Found ${e.length} ${d} for ${t} ${o}${a}`, n && (i += " • More available");
1462
- }
1463
- if (r) {
1464
- const c = ve([], r);
1465
- return `${i}
1466
- ${c}`;
1467
- }
1468
- return i;
1469
- }
1470
- const Yt = ["and", "or"], ae = {
1471
- labels: s.string().array().optional().describe("The labels to filter the tasks by"),
1472
- labelsOperator: s.enum(Yt).optional().describe(
1473
- 'The operator to use when filtering by labels. This will dictate whether a task has all labels, or some of them. Default is "or".'
1474
- )
1475
- };
1476
- function ce(e = [], t = "or") {
1477
- if (e.length === 0) return "";
1478
- const o = t === "and" ? " & " : " | ";
1479
- return `(${e.map((i) => i.startsWith("@") ? i : `@${i}`).join(` ${o} `)})`;
1480
- }
1481
- const Ht = {
1482
- getBy: s.enum(["completion", "due"]).default("completion").describe(
1483
- 'The method to use to get the tasks: "completion" to get tasks by completion date (ie, when the task was actually completed), "due" to get tasks by due date (ie, when the task was due to be completed by).'
1484
- ),
1485
- since: s.string().date().regex(/^\d{4}-\d{2}-\d{2}$/).describe("The start date to get the tasks for. Format: YYYY-MM-DD."),
1486
- until: s.string().date().regex(/^\d{4}-\d{2}-\d{2}$/).describe("The start date to get the tasks for. Format: YYYY-MM-DD."),
1487
- workspaceId: s.string().optional().describe("The ID of the workspace to get the tasks for."),
1488
- projectId: s.string().optional().describe(
1489
- 'The ID of the project to get the tasks for. Project ID should be an ID string, or the text "inbox", for inbox tasks.'
1490
- ),
1491
- sectionId: s.string().optional().describe("The ID of the section to get the tasks for."),
1492
- parentId: s.string().optional().describe("The ID of the parent task to get the tasks for."),
1493
- responsibleUser: s.string().optional().describe(
1494
- "Find tasks assigned to this user. Can be a user ID, name, or email address. Defaults to all collaborators when omitted."
1495
- ),
1496
- limit: s.number().int().min(1).max(S.COMPLETED_TASKS_MAX).default(S.COMPLETED_TASKS_DEFAULT).describe("The maximum number of tasks to return."),
1497
- cursor: s.string().optional().describe(
1498
- "The cursor to get the next page of tasks (cursor is obtained from the previous call to this tool, with the same parameters)."
1499
- ),
1500
- ...ae
1501
- }, Kt = {
1502
- tasks: s.array(B).describe("The found completed tasks."),
1503
- nextCursor: s.string().optional().describe("Cursor for the next page of results."),
1504
- totalCount: s.number().describe("The total number of tasks in this page."),
1505
- hasMore: s.boolean().describe("Whether there are more results available."),
1506
- appliedFilters: s.record(s.unknown()).describe("The filters that were applied to the search.")
1507
- }, Vt = {
1508
- name: g.FIND_COMPLETED_TASKS,
1509
- description: "Get completed tasks (includes all collaborators by default—use responsibleUser to narrow).",
1510
- parameters: Ht,
1511
- outputSchema: Kt,
1512
- mutability: "readonly",
1513
- async execute(e, t) {
1514
- const { getBy: o, labels: n, labelsOperator: r, since: i, until: c, responsibleUser: a, projectId: d, ...l } = e, u = await ee(t, a), p = u?.email;
1515
- let m = ce(n, r);
1516
- u && p && (m = H(m, `assigned to: ${p}`));
1517
- const y = await t.getUser(), k = y.tzInfo?.gmtString || "+00:00", w = d === "inbox" ? y.inboxProjectId : d, D = `${i}T00:00:00${k}`, P = `${c}T23:59:59${k}`, h = new Date(D).toISOString(), T = new Date(P).toISOString(), { items: C, nextCursor: v } = o === "completion" ? await t.getCompletedTasksByCompletionDate({
1518
- ...l,
1519
- projectId: w,
1520
- since: h,
1521
- until: T,
1522
- ...m ? { filterQuery: m, filterLang: "en" } : {}
1523
- }) : await t.getCompletedTasksByDueDate({
1524
- ...l,
1525
- projectId: w,
1526
- since: h,
1527
- until: T,
1528
- ...m ? { filterQuery: m, filterLang: "en" } : {}
1529
- }), f = C.map(O);
1530
- return {
1531
- textContent: Gt({
1532
- tasks: f,
1533
- args: e,
1534
- nextCursor: v,
1535
- assigneeEmail: p
1536
- }),
1537
- structuredContent: {
1538
- tasks: f,
1539
- nextCursor: v ?? void 0,
1540
- totalCount: f.length,
1541
- hasMore: !!v,
1542
- appliedFilters: e
1543
- }
1544
- };
1545
- }
1546
- };
1547
- function Gt({
1548
- tasks: e,
1549
- args: t,
1550
- nextCursor: o,
1551
- assigneeEmail: n
1552
- }) {
1553
- const r = t.getBy === "completion" ? "completed" : "due", i = `Completed tasks (by ${r} date)`, c = [];
1554
- if (c.push(`${r} date: ${t.since} to ${t.until}`), t.projectId && c.push(`project: ${t.projectId}`), t.sectionId && c.push(`section: ${t.sectionId}`), t.parentId && c.push(`parent: ${t.parentId}`), t.workspaceId && c.push(`workspace: ${t.workspaceId}`), t.labels && t.labels.length > 0) {
1555
- const d = t.labels.map((l) => `@${l}`).join(t.labelsOperator === "and" ? " & " : " | ");
1556
- c.push(`labels: ${d}`);
1557
- }
1558
- if (t.responsibleUser) {
1559
- const d = n || t.responsibleUser;
1560
- c.push(`assigned to: ${d}`);
1561
- }
1562
- const a = [];
1563
- return e.length === 0 && (a.push("No tasks completed in this date range"), a.push("Try expanding the date range"), (t.projectId || t.sectionId || t.parentId) && a.push("Try removing project/section/parent filters"), t.getBy === "due" && a.push('Try switching to "completion" date instead')), N({
1564
- subject: i,
1565
- count: e.length,
1566
- limit: t.limit,
1567
- nextCursor: o ?? void 0,
1568
- filterHints: c,
1569
- previewLines: K(e, Math.min(e.length, t.limit)),
1570
- zeroReasonHints: a
1571
- });
1572
- }
1573
- const { FIND_PROJECTS: qt, ADD_TASKS: Ce, UPDATE_TASKS: Se } = g, Jt = {
1574
- projectId: s.string().min(1).describe("The ID of the project to search for collaborators in."),
1575
- searchTerm: s.string().optional().describe(
1576
- "Search for a collaborator by name or email (partial and case insensitive match). If omitted, all collaborators in the project are returned."
1577
- )
1578
- }, Xt = {
1579
- collaborators: s.array(qe).describe("The found collaborators."),
1580
- projectInfo: s.object({
1581
- id: s.string().describe("The project ID."),
1582
- name: s.string().describe("The project name."),
1583
- isShared: s.boolean().describe("Whether the project is shared.")
1584
- }).optional().describe("Information about the project."),
1585
- totalCount: s.number().describe("The total number of collaborators found."),
1586
- totalAvailable: s.number().optional().describe("The total number of available collaborators in the project."),
1587
- appliedFilters: s.record(s.unknown()).describe("The filters that were applied to the search.")
1588
- }, Zt = {
1589
- name: g.FIND_PROJECT_COLLABORATORS,
1590
- description: "Search for collaborators by name or other criteria in a project.",
1591
- parameters: Jt,
1592
- outputSchema: Xt,
1593
- mutability: "readonly",
1594
- async execute(e, t) {
1595
- const { projectId: o, searchTerm: n } = e;
1596
- let r = o, i;
1597
- try {
1598
- if (i = await t.getProject(o), !i)
1599
- throw new Error(`Project with ID "${o}" not found or not accessible`);
1600
- if (r = i.name, !i.isShared)
1601
- return {
1602
- textContent: `Project "${r}" is not shared and has no collaborators.
1603
-
1604
- **Next steps:**
1605
- • Share the project to enable collaboration
1606
- • Use ${Ce} and ${Se} for assignment features once shared`,
1607
- structuredContent: {
1608
- collaborators: [],
1609
- projectInfo: {
1610
- id: o,
1611
- name: r,
1612
- isShared: !1
1613
- },
1614
- totalCount: 0,
1615
- appliedFilters: e
1616
- }
1617
- };
1618
- } catch (l) {
1619
- throw new Error(
1620
- `Failed to access project "${o}": ${l instanceof Error ? l.message : "Unknown error"}`
1621
- );
1622
- }
1623
- const c = await _.getProjectCollaborators(t, o);
1624
- if (c.length === 0)
1625
- return {
1626
- textContent: `Project "${r}" has no collaborators or collaborator data is not accessible.
1627
-
1628
- **Next steps:**
1629
- • Check project sharing settings
1630
- • Ensure you have permission to view collaborators
1631
- • Try refreshing or re-sharing the project`,
1632
- structuredContent: {
1633
- collaborators: [],
1634
- projectInfo: {
1635
- id: o,
1636
- name: r,
1637
- isShared: !0
1638
- },
1639
- totalCount: 0,
1640
- appliedFilters: e
1641
- }
1642
- };
1643
- let a = c;
1644
- if (n) {
1645
- const l = n.toLowerCase().trim();
1646
- a = c.filter(
1647
- (u) => u.name.toLowerCase().includes(l) || u.email.toLowerCase().includes(l)
1648
- );
1649
- }
1650
- return {
1651
- textContent: Qt({
1652
- collaborators: a,
1653
- projectName: r,
1654
- searchTerm: n,
1655
- totalAvailable: c.length
1656
- }),
1657
- structuredContent: {
1658
- collaborators: a,
1659
- projectInfo: {
1660
- id: o,
1661
- name: r,
1662
- isShared: !0
1663
- },
1664
- totalCount: a.length,
1665
- totalAvailable: c.length,
1666
- appliedFilters: e
1667
- }
1668
- };
1669
- }
1670
- };
1671
- function Qt({
1672
- collaborators: e,
1673
- projectName: t,
1674
- searchTerm: o,
1675
- totalAvailable: n
1676
- }) {
1677
- const r = o ? `Project collaborators matching "${o}"` : "Project collaborators", i = [];
1678
- o && i.push(`matching "${o}"`), i.push(`in project "${t}"`);
1679
- let c = [];
1680
- e.length > 0 && (c = e.slice(0, 10).map((l) => {
1681
- const u = l.name || "Unknown Name", p = l.email || "No email";
1682
- return `• ${u} (${p}) - ID: ${l.id}`;
1683
- }), e.length > 10 && c.push(`... and ${e.length - 10} more`));
1684
- const a = [];
1685
- e.length === 0 && (o ? (a.push(`No collaborators match "${o}"`), a.push("Try a broader search term or check spelling"), n > 0 && a.push(`${n} collaborators available without filter`)) : (a.push("Project has no collaborators"), a.push("Share the project to add collaborators")));
1686
- const d = [];
1687
- return e.length > 0 ? (d.push(`Use ${Ce} with responsibleUser to assign new tasks`), d.push(`Use ${Se} with responsibleUser to reassign existing tasks`), d.push("Use collaborator names, emails, or IDs for assignments")) : (d.push(`Use ${qt} to find other projects`), o && n > 0 && d.push("Try searching without filters to see all collaborators")), N({
1688
- subject: r,
1689
- count: e.length,
1690
- filterHints: i,
1691
- previewLines: c.join(`
1692
- `),
1693
- zeroReasonHints: a,
1694
- nextSteps: d
1695
- });
1696
- }
1697
- const { ADD_PROJECTS: es } = g, ts = {
1698
- search: s.string().optional().describe(
1699
- "Search for a project by name (partial and case insensitive match). If omitted, all projects are returned."
1700
- ),
1701
- limit: s.number().int().min(1).max(S.PROJECTS_MAX).default(S.PROJECTS_DEFAULT).describe("The maximum number of projects to return."),
1702
- cursor: s.string().optional().describe(
1703
- "The cursor to get the next page of projects (cursor is obtained from the previous call to this tool, with the same parameters)."
1704
- )
1705
- }, ss = {
1706
- projects: s.array(oe).describe("The found projects."),
1707
- nextCursor: s.string().optional().describe("Cursor for the next page of results."),
1708
- totalCount: s.number().describe("The total number of projects in this page."),
1709
- hasMore: s.boolean().describe("Whether there are more results available."),
1710
- appliedFilters: s.record(s.unknown()).describe("The filters that were applied to the search.")
1711
- }, os = {
1712
- name: g.FIND_PROJECTS,
1713
- description: "List all projects or search for projects by name. When searching, all matching projects are returned (pagination is ignored). When not searching, projects are returned with pagination.",
1714
- parameters: ts,
1715
- outputSchema: ss,
1716
- mutability: "readonly",
1717
- async execute(e, t) {
1718
- let o, n = null;
1719
- if (e.search)
1720
- o = await ke(t), n = null;
1721
- else {
1722
- const a = await t.getProjects({
1723
- limit: e.limit,
1724
- cursor: e.cursor ?? null
1725
- });
1726
- o = a.results, n = a.nextCursor;
1727
- }
1728
- const r = e.search ? e.search.toLowerCase() : void 0, c = (r ? o.filter((a) => a.name.toLowerCase().includes(r)) : o).map(we);
1729
- return {
1730
- textContent: ns({ projects: c, args: e, nextCursor: n }),
1731
- structuredContent: {
1732
- projects: c,
1733
- nextCursor: n ?? void 0,
1734
- totalCount: c.length,
1735
- hasMore: !!n,
1736
- appliedFilters: e
1737
- }
1738
- };
1739
- }
1740
- };
1741
- function ns({
1742
- projects: e,
1743
- args: t,
1744
- nextCursor: o
1745
- }) {
1746
- const n = t.search ? `All projects matching "${t.search}"` : "Projects", r = [];
1747
- t.search && r.push(`search: "${t.search}"`);
1748
- const i = 10, a = e.slice(0, i).map(bt).join(`
1749
- `), d = e.length - i, l = d > 0 ? `${a}
1750
- …and ${d} more` : a, u = [];
1751
- return e.length === 0 && (t.search ? (u.push("Try broader search terms"), u.push("Check spelling"), u.push("Remove search to see all projects")) : (u.push("No projects created yet"), u.push(`Use ${es} to create a project`))), N({
1752
- subject: n,
1753
- count: e.length,
1754
- limit: t.limit,
1755
- nextCursor: o ?? void 0,
1756
- filterHints: r,
1757
- previewLines: l,
1758
- zeroReasonHints: u
1759
- });
1760
- }
1761
- const { ADD_SECTIONS: rs } = g, is = {
1762
- projectId: s.string().min(1).describe(
1763
- 'The ID of the project to search sections in. Project ID should be an ID string, or the text "inbox", for inbox tasks.'
1764
- ),
1765
- search: s.string().optional().describe(
1766
- "Search for a section by name (partial and case insensitive match). If omitted, all sections in the project are returned."
1767
- )
1768
- }, as = {
1769
- sections: s.array(ne).describe("The found sections."),
1770
- totalCount: s.number().describe("The total number of sections found."),
1771
- appliedFilters: s.record(s.unknown()).describe("The filters that were applied to the search.")
1772
- }, cs = {
1773
- name: g.FIND_SECTIONS,
1774
- description: "Search for sections by name or other criteria in a project. When searching, all sections in the project are fetched to ensure complete results.",
1775
- parameters: is,
1776
- outputSchema: as,
1777
- mutability: "readonly",
1778
- async execute(e, t) {
1779
- const o = e.projectId === "inbox" ? (await t.getUser()).inboxProjectId : e.projectId;
1780
- let n;
1781
- e.search ? n = await ze(t, o) : n = (await t.getSections({
1782
- projectId: o
1783
- })).results;
1784
- const r = e.search ? e.search.toLowerCase() : void 0, c = (r ? n.filter((d) => d.name.toLowerCase().includes(r)) : n).map(({ id: d, name: l }) => ({ id: d, name: l }));
1785
- return {
1786
- textContent: ds({
1787
- sections: c,
1788
- projectId: e.projectId,
1789
- search: e.search
1790
- }),
1791
- structuredContent: {
1792
- sections: c,
1793
- totalCount: c.length,
1794
- appliedFilters: e
1795
- }
1796
- };
1797
- }
1798
- };
1799
- function ds({
1800
- sections: e,
1801
- projectId: t,
1802
- search: o
1803
- }) {
1804
- const n = [];
1805
- o ? (n.push("Try broader search terms"), n.push("Check spelling"), n.push("Remove search to see all sections")) : (n.push("Project has no sections yet"), n.push(`Use ${rs} to create sections`));
1806
- const r = o ? `Sections in project ${t} matching "${o}"` : `Sections in project ${t}`, i = e.length > 0 ? e.map((c) => ` ${c.name} • id=${c.id}`).join(`
1807
- `) : void 0;
1808
- return N({
1809
- subject: r,
1810
- count: e.length,
1811
- previewLines: i,
1812
- zeroReasonHints: n
1813
- });
1814
- }
1815
- const { FIND_COMPLETED_TASKS: le, ADD_TASKS: ue } = g, ls = {
1816
- searchText: s.string().optional().describe("The text to search for in tasks."),
1817
- projectId: s.string().optional().describe(
1818
- 'Find tasks in this project. Project ID should be an ID string, or the text "inbox", for inbox tasks.'
1819
- ),
1820
- sectionId: s.string().optional().describe("Find tasks in this section."),
1821
- parentId: s.string().optional().describe("Find subtasks of this parent task."),
1822
- responsibleUser: s.string().optional().describe("Find tasks assigned to this user. Can be a user ID, name, or email address."),
1823
- responsibleUserFiltering: s.enum(ye).optional().describe(
1824
- 'How to filter by responsible user when responsibleUser is not provided. "assigned" = only tasks assigned to others; "unassignedOrMe" = only unassigned tasks or tasks assigned to me; "all" = all tasks regardless of assignment. Default value will be `unassignedOrMe`.'
1825
- ),
1826
- limit: s.number().int().min(1).max(S.TASKS_MAX).default(S.TASKS_DEFAULT).describe("The maximum number of tasks to return."),
1827
- cursor: s.string().optional().describe(
1828
- "The cursor to get the next page of tasks (cursor is obtained from the previous call to this tool, with the same parameters)."
1829
- ),
1830
- ...ae
1831
- }, us = {
1832
- tasks: s.array(B).describe("The found tasks."),
1833
- nextCursor: s.string().optional().describe("Cursor for the next page of results."),
1834
- totalCount: s.number().describe("The total number of tasks in this page."),
1835
- hasMore: s.boolean().describe("Whether there are more results available."),
1836
- appliedFilters: s.record(s.unknown()).describe("The filters that were applied to the search.")
1837
- }, ps = {
1838
- name: g.FIND_TASKS,
1839
- description: "Find tasks by text search, or by project/section/parent container/responsible user. At least one filter must be provided.",
1840
- parameters: ls,
1841
- outputSchema: us,
1842
- mutability: "readonly",
1843
- async execute(e, t) {
1844
- const {
1845
- searchText: o,
1846
- projectId: n,
1847
- sectionId: r,
1848
- parentId: i,
1849
- responsibleUser: c,
1850
- responsibleUserFiltering: a,
1851
- limit: d,
1852
- cursor: l,
1853
- labels: u,
1854
- labelsOperator: p
1855
- } = e, b = await t.getUser(), m = u && u.length > 0;
1856
- if (!o && !n && !r && !i && !c && !m)
1857
- throw new Error(
1858
- "At least one filter must be provided: searchText, projectId, sectionId, parentId, responsibleUser, or labels"
1859
- );
1860
- const y = await ee(t, c), k = y?.userId, w = y?.email;
1861
- if (n || r || i) {
1862
- const f = {
1863
- limit: d,
1864
- cursor: l ?? null
1865
- };
1866
- n && (f.projectId = n === "inbox" ? b.inboxProjectId : n), r && (f.sectionId = r), i && (f.parentId = i);
1867
- const { results: j, nextCursor: $ } = await t.getTasks(f), x = j.map(O);
1868
- let E = o ? x.filter(
1869
- (M) => M.content.toLowerCase().includes(o.toLowerCase()) || M.description?.toLowerCase().includes(o.toLowerCase())
1870
- ) : x;
1871
- return E = de({
1872
- tasks: E,
1873
- resolvedAssigneeId: k,
1874
- currentUserId: b.id,
1875
- responsibleUserFiltering: a
1876
- }), u && u.length > 0 && (E = p === "and" ? E.filter(
1877
- (M) => u.every((V) => M.labels.includes(V))
1878
- ) : E.filter(
1879
- (M) => u.some((V) => M.labels.includes(V))
1880
- )), {
1881
- textContent: J({
1882
- tasks: E,
1883
- args: e,
1884
- nextCursor: $,
1885
- isContainerSearch: !0,
1886
- assigneeEmail: w
1887
- }),
1888
- structuredContent: {
1889
- tasks: E,
1890
- nextCursor: $ ?? void 0,
1891
- totalCount: E.length,
1892
- hasMore: !!$,
1893
- appliedFilters: e
1894
- }
1895
- };
1896
- }
1897
- if (k && !o && !m) {
1898
- const { results: f, nextCursor: j } = await t.getTasksByFilter({
1899
- query: `assigned to: ${w}`,
1900
- lang: "en",
1901
- limit: d,
1902
- cursor: l ?? null
1903
- }), $ = f.map(O);
1904
- return {
1905
- textContent: J({
1906
- tasks: $,
1907
- args: e,
1908
- nextCursor: j,
1909
- isContainerSearch: !1,
1910
- assigneeEmail: w
1911
- }),
1912
- structuredContent: {
1913
- tasks: $,
1914
- nextCursor: j ?? void 0,
1915
- totalCount: $.length,
1916
- hasMore: !!j,
1917
- appliedFilters: e
1918
- }
1919
- };
1920
- }
1921
- let D = "";
1922
- o && (D = `search: ${o}`);
1923
- const P = ce(u, p);
1924
- D = H(D, P);
1925
- const { tasks: h, nextCursor: T } = await se({
1926
- client: t,
1927
- query: D,
1928
- cursor: e.cursor,
1929
- limit: e.limit
1930
- }), C = de({
1931
- tasks: h,
1932
- resolvedAssigneeId: k,
1933
- currentUserId: b.id,
1934
- responsibleUserFiltering: a
1935
- });
1936
- return {
1937
- textContent: J({
1938
- tasks: C,
1939
- args: e,
1940
- nextCursor: T,
1941
- isContainerSearch: !1,
1942
- assigneeEmail: w
1943
- }),
1944
- structuredContent: {
1945
- tasks: C,
1946
- nextCursor: T ?? void 0,
1947
- totalCount: h.length,
1948
- hasMore: !!T,
1949
- appliedFilters: e
1950
- }
1951
- };
1952
- }
1953
- };
1954
- function hs(e) {
1955
- if (e.projectId) {
1956
- const t = [
1957
- e.searchText ? "No tasks in project match search" : "Project has no tasks yet"
1958
- ];
1959
- return e.searchText || t.push(`Use ${ue} to create tasks`), t;
1960
- }
1961
- if (e.sectionId) {
1962
- const t = [e.searchText ? "No tasks in section match search" : "Section is empty"];
1963
- return e.searchText || t.push("Tasks may be in other sections of the project"), t;
1964
- }
1965
- if (e.parentId) {
1966
- const t = [e.searchText ? "No subtasks match search" : "No subtasks created yet"];
1967
- return e.searchText || t.push(`Use ${ue} with parentId to add subtasks`), t;
1968
- }
1969
- return [];
1970
- }
1971
- function J({
1972
- tasks: e,
1973
- args: t,
1974
- nextCursor: o,
1975
- isContainerSearch: n,
1976
- assigneeEmail: r
1977
- }) {
1978
- let i = "Tasks";
1979
- const c = [], a = [];
1980
- if (n) {
1981
- if (t.projectId ? (i = "Tasks in project", c.push(`in project ${t.projectId}`)) : t.sectionId ? (i = "Tasks in section", c.push(`in section ${t.sectionId}`)) : t.parentId ? (i = "Subtasks", c.push(`subtasks of ${t.parentId}`)) : i = "Tasks", t.searchText && (i += ` matching "${t.searchText}"`, c.push(`containing "${t.searchText}"`)), t.responsibleUser) {
1982
- const d = r || t.responsibleUser;
1983
- i += ` assigned to ${d}`, c.push(`assigned to ${d}`);
1984
- }
1985
- if (t.labels && t.labels.length > 0) {
1986
- const d = t.labels.map((l) => `@${l}`).join(t.labelsOperator === "and" ? " & " : " | ");
1987
- c.push(`labels: ${d}`);
1988
- }
1989
- e.length === 0 && a.push(...hs(t));
1990
- } else {
1991
- const d = r || t.responsibleUser, l = [];
1992
- if (t.searchText && l.push(`"${t.searchText}"`), t.responsibleUser && l.push(`assigned to ${d}`), t.labels && t.labels.length > 0) {
1993
- const u = t.labels.map((p) => `@${p}`).join(t.labelsOperator === "and" ? " & " : " | ");
1994
- l.push(`with labels: ${u}`);
1995
- }
1996
- if (t.searchText ? (i = `Search results for ${l.join(" ")}`, c.push(`matching "${t.searchText}"`)) : t.responsibleUser && (!t.labels || t.labels.length === 0) ? i = `Tasks assigned to ${d}` : t.labels && t.labels.length > 0 && !t.responsibleUser ? i = `Tasks with labels: ${t.labels.map((p) => `@${p}`).join(t.labelsOperator === "and" ? " & " : " | ")}` : i = `Tasks ${l.join(" ")}`, t.responsibleUser && c.push(`assigned to ${d}`), t.labels && t.labels.length > 0) {
1997
- const u = t.labels.map((p) => `@${p}`).join(t.labelsOperator === "and" ? " & " : " | ");
1998
- c.push(`labels: ${u}`);
1999
- }
2000
- if (e.length === 0) {
2001
- if (t.responsibleUser) {
2002
- const u = r || t.responsibleUser;
2003
- a.push(`No tasks assigned to ${u}`), a.push("Check if the user name is correct"), a.push(`Check completed tasks with ${le}`);
2004
- }
2005
- t.searchText && (a.push("Try broader search terms"), a.push("Verify spelling and try partial words"), t.responsibleUser || a.push(`Check completed tasks with ${le}`));
2006
- }
2007
- }
2008
- return N({
2009
- subject: i,
2010
- count: e.length,
2011
- limit: t.limit,
2012
- nextCursor: o ?? void 0,
2013
- filterHints: c,
2014
- previewLines: K(e, Math.min(e.length, t.limit)),
2015
- zeroReasonHints: a
2016
- });
2017
- }
2018
- const ms = {
2019
- startDate: s.string().regex(/^(\d{4}-\d{2}-\d{2}|today)$/).optional().describe("The start date to get the tasks for. Format: YYYY-MM-DD or 'today'."),
2020
- overdueOption: s.enum(["overdue-only", "include-overdue", "exclude-overdue"]).optional().describe(
2021
- "How to handle overdue tasks. 'overdue-only' to get only overdue tasks, 'include-overdue' to include overdue tasks along with tasks for the specified date(s), and 'exclude-overdue' to exclude overdue tasks. Default is 'include-overdue'."
2022
- ),
2023
- daysCount: s.number().int().min(1).max(30).default(1).describe(
2024
- "The number of days to get the tasks for, starting from the start date. Default is 1 which means only tasks for the start date."
2025
- ),
2026
- limit: s.number().int().min(1).max(S.TASKS_MAX).default(S.TASKS_DEFAULT).describe("The maximum number of tasks to return."),
2027
- cursor: s.string().optional().describe(
2028
- "The cursor to get the next page of tasks (cursor is obtained from the previous call to this tool, with the same parameters)."
2029
- ),
2030
- responsibleUser: s.string().optional().describe("Find tasks assigned to this user. Can be a user ID, name, or email address."),
2031
- responsibleUserFiltering: s.enum(ye).optional().describe(
2032
- 'How to filter by responsible user when responsibleUser is not provided. "assigned" = only tasks assigned to others; "unassignedOrMe" = only unassigned tasks or tasks assigned to me; "all" = all tasks regardless of assignment. Default is "unassignedOrMe".'
2033
- ),
2034
- ...ae
2035
- }, fs = {
2036
- tasks: s.array(B).describe("The found tasks."),
2037
- nextCursor: s.string().optional().describe("Cursor for the next page of results."),
2038
- totalCount: s.number().describe("The total number of tasks in this page."),
2039
- hasMore: s.boolean().describe("Whether there are more results available."),
2040
- appliedFilters: s.record(s.unknown()).describe("The filters that were applied to the search.")
2041
- }, bs = {
2042
- name: g.FIND_TASKS_BY_DATE,
2043
- description: "Get tasks by date range. Use startDate 'today' to get today's tasks including overdue items, or provide a specific date/date range.",
2044
- parameters: ms,
2045
- outputSchema: fs,
2046
- mutability: "readonly",
2047
- async execute(e, t) {
2048
- if (!e.startDate && e.overdueOption !== "overdue-only")
2049
- throw new Error(
2050
- "Either startDate must be provided or overdueOption must be set to overdue-only"
2051
- );
2052
- const o = await ee(t, e.responsibleUser), n = o?.userId, r = o?.email;
2053
- let i = "";
2054
- if (e.overdueOption === "overdue-only")
2055
- i = "overdue";
2056
- else if (e.startDate === "today")
2057
- i = e.overdueOption === "exclude-overdue" ? "today" : "(today | overdue)";
2058
- else if (e.startDate) {
2059
- const p = e.startDate, b = be(p, e.daysCount), m = Pe(b, { representation: "date" });
2060
- i = `(due after: ${p} | due: ${p}) & due before: ${m}`;
2061
- }
2062
- const c = ce(e.labels, e.labelsOperator);
2063
- c.length > 0 && (i = H(i, `(${c})`));
2064
- const a = Be({
2065
- resolvedAssigneeId: n,
2066
- assigneeEmail: r,
2067
- responsibleUserFiltering: e.responsibleUserFiltering
2068
- });
2069
- i = H(i, a);
2070
- const { tasks: d, nextCursor: l } = await se({
2071
- client: t,
2072
- query: i,
2073
- cursor: e.cursor,
2074
- limit: e.limit
2075
- });
2076
- return {
2077
- textContent: gs({ tasks: d, args: e, nextCursor: l, assigneeEmail: r }),
2078
- structuredContent: {
2079
- tasks: d,
2080
- nextCursor: l ?? void 0,
2081
- totalCount: d.length,
2082
- hasMore: !!l,
2083
- appliedFilters: e
2084
- }
2085
- };
2086
- }
2087
- };
2088
- function gs({
2089
- tasks: e,
2090
- args: t,
2091
- nextCursor: o,
2092
- assigneeEmail: n
2093
- }) {
2094
- const r = [];
2095
- if (t.overdueOption === "overdue-only")
2096
- r.push("overdue tasks only");
2097
- else if (t.startDate === "today") {
2098
- const a = t.overdueOption === "exclude-overdue" ? "" : " + overdue tasks";
2099
- r.push(
2100
- `today${a}${t.daysCount > 1 ? ` + ${t.daysCount - 1} more days` : ""}`
2101
- );
2102
- } else if (t.startDate) {
2103
- const a = t.daysCount > 1 ? ` to ${ht(be(t.startDate, t.daysCount))}` : "";
2104
- r.push(`${t.startDate}${a}`);
2105
- }
2106
- if (t.labels && t.labels.length > 0) {
2107
- const a = t.labels.map((d) => `@${d}`).join(t.labelsOperator === "and" ? " & " : " | ");
2108
- r.push(`labels: ${a}`);
2109
- }
2110
- if (t.responsibleUser) {
2111
- const a = n || t.responsibleUser;
2112
- r.push(`assigned to: ${a}`);
2113
- }
2114
- let i = "";
2115
- if (t.overdueOption === "overdue-only" ? i = "Overdue tasks" : t.startDate === "today" ? i = t.overdueOption === "exclude-overdue" ? "Today's tasks" : "Today's tasks + overdue" : t.startDate ? i = `Tasks for ${t.startDate}` : i = "Tasks", t.responsibleUser) {
2116
- const a = n || t.responsibleUser;
2117
- i += ` assigned to ${a}`;
2118
- }
2119
- const c = [];
2120
- if (e.length === 0)
2121
- if (t.overdueOption === "overdue-only")
2122
- c.push("Great job! No overdue tasks");
2123
- else if (t.startDate === "today") {
2124
- const a = t.overdueOption === "exclude-overdue" ? "" : " or overdue";
2125
- c.push(`Great job! No tasks for today${a}`);
2126
- } else
2127
- c.push("Expand date range with larger 'daysCount'"), c.push("Check today's tasks with startDate='today'");
2128
- return N({
2129
- subject: i,
2130
- count: e.length,
2131
- limit: t.limit,
2132
- nextCursor: o ?? void 0,
2133
- filterHints: r,
2134
- previewLines: K(e, Math.min(e.length, t.limit)),
2135
- zeroReasonHints: c
2136
- });
2137
- }
2138
- const Ts = {
2139
- projectId: s.string().min(1).optional().describe(
2140
- "Optional project ID. If provided, shows detailed overview of that project. If omitted, shows overview of all projects."
2141
- )
2142
- }, ys = {
2143
- type: s.enum(["account_overview", "project_overview"]).describe("The type of overview returned."),
2144
- totalProjects: s.number().optional().describe("Total number of projects (account overview only)."),
2145
- totalTasks: s.number().optional().describe("Total number of tasks."),
2146
- totalSections: s.number().optional().describe("Total number of sections (project overview only)."),
2147
- tasksWithoutSection: s.number().optional().describe("Number of tasks not in any section (project overview only)."),
2148
- projectInfo: s.object({
2149
- id: s.string(),
2150
- name: s.string(),
2151
- isShared: s.boolean(),
2152
- isFavorite: s.boolean()
2153
- }).optional().describe("Project information (project overview only)."),
2154
- // Additional fields that exist in structured outputs
2155
- hasNestedProjects: s.boolean().optional().describe("Whether account has nested projects (account overview only)."),
2156
- inbox: s.any().optional().describe("Inbox information (account overview only)."),
2157
- projects: s.array(s.any()).optional().describe("List of projects (account overview only)."),
2158
- project: s.any().optional().describe("Project details (project overview only)."),
2159
- sections: s.array(s.any()).optional().describe("List of sections (project overview only)."),
2160
- tasks: s.array(s.any()).optional().describe("List of tasks (project overview only)."),
2161
- stats: s.any().optional().describe("Statistics object (project overview only).")
2162
- };
2163
- function Is(e) {
2164
- const t = {};
2165
- for (const r of e)
2166
- t[r.id] = {
2167
- ...r,
2168
- children: [],
2169
- childOrder: r.childOrder ?? 0
2170
- };
2171
- const o = [];
2172
- for (const r of e) {
2173
- const i = t[r.id];
2174
- if (i)
2175
- if (W(r) && r.parentId) {
2176
- const c = t[r.parentId];
2177
- c ? c.children.push(i) : o.push(i);
2178
- } else
2179
- o.push(i);
2180
- }
2181
- function n(r) {
2182
- r.sort((i, c) => i.childOrder - c.childOrder);
2183
- for (const i of r)
2184
- n(i.children);
2185
- }
2186
- return n(o), o;
2187
- }
2188
- async function ks(e, t) {
2189
- const o = {};
2190
- return await Promise.all(
2191
- t.map(async (n) => {
2192
- const { results: r } = await e.getSections({ projectId: n });
2193
- o[n] = r;
2194
- })
2195
- ), o;
2196
- }
2197
- function $e(e, t, o = "") {
2198
- const n = [];
2199
- n.push(`${o}- Project: ${e.name} (id=${e.id})`);
2200
- const r = t[e.id] || [];
2201
- for (const i of r)
2202
- n.push(`${o} - Section: ${i.name} (id=${i.id})`);
2203
- for (const i of e.children)
2204
- n.push(...$e(i, t, `${o} `));
2205
- return n;
2206
- }
2207
- function pe(e) {
2208
- const t = {};
2209
- for (const n of e)
2210
- t[n.id] = { ...n, children: [] };
2211
- const o = [];
2212
- for (const n of e) {
2213
- const r = t[n.id];
2214
- if (!r) continue;
2215
- if (!n.parentId) {
2216
- o.push(r);
2217
- continue;
2218
- }
2219
- const i = t[n.parentId];
2220
- i ? i.children.push(r) : o.push(r);
2221
- }
2222
- return o;
2223
- }
2224
- function Z(e, t = "") {
2225
- const o = [];
2226
- for (const n of e) {
2227
- const r = `id=${n.id}`, i = n.dueDate ? `; due=${n.dueDate}` : "", c = `; content=${n.content}`;
2228
- o.push(`${t}- ${r}${i}${c}`), n.children.length > 0 && o.push(...Z(n.children, `${t} `));
2229
- }
2230
- return o;
2231
- }
2232
- function De(e, t) {
2233
- return {
2234
- id: e.id,
2235
- name: e.name,
2236
- parentId: W(e) ? e.parentId ?? null : null,
2237
- sections: t[e.id] || [],
2238
- children: e.children.map((o) => De(o, t))
2239
- };
2240
- }
2241
- async function ws(e, t) {
2242
- let o = [], n;
2243
- do {
2244
- const { results: r, nextCursor: i } = await e.getTasks({
2245
- projectId: t,
2246
- limit: S.TASKS_BATCH_SIZE,
2247
- cursor: n ?? void 0
2248
- });
2249
- o = o.concat(r.map(O)), n = i ?? void 0;
2250
- } while (n);
2251
- return o;
2252
- }
2253
- async function js(e, t) {
2254
- const { results: o } = await e.getSections({ projectId: t });
2255
- return o;
2256
- }
2257
- async function vs(e) {
2258
- const { results: t } = await e.getProjects({}), o = t.find((p) => W(p) && p.inboxProject === !0), n = t.filter((p) => !W(p) || p.inboxProject !== !0), r = Is(n), i = t.map((p) => p.id), c = await ks(e, i), a = ["# Personal Projects", ""];
2259
- if (o) {
2260
- a.push(`- Inbox Project: ${o.name} (id=${o.id})`);
2261
- for (const p of c[o.id] || [])
2262
- a.push(` - Section: ${p.name} (id=${p.id})`);
2263
- }
2264
- if (r.length)
2265
- for (const p of r)
2266
- a.push(...$e(p, c));
2267
- else
2268
- a.push("_No projects found._");
2269
- a.push("");
2270
- const d = r.some((p) => p.children.length > 0);
2271
- d && a.push(
2272
- "_Note: Indentation indicates that a project is a sub-project of the one above it. This allows for organizing projects hierarchically, with parent projects containing related sub-projects._",
2273
- ""
2274
- );
2275
- const l = a.join(`
2276
- `), u = {
2277
- type: "account_overview",
2278
- inbox: o ? {
2279
- id: o.id,
2280
- name: o.name,
2281
- sections: c[o.id] || []
2282
- } : null,
2283
- projects: r.map(
2284
- (p) => De(p, c)
2285
- ),
2286
- totalProjects: t.length,
2287
- totalSections: i.reduce(
2288
- (p, b) => p + (c[b]?.length || 0),
2289
- 0
2290
- ),
2291
- hasNestedProjects: d
2292
- };
2293
- return { textContent: l, structuredContent: u };
2294
- }
2295
- async function Cs(e, t) {
2296
- const o = await e.getProject(t), n = await js(e, t), r = await ws(e, t), i = {};
2297
- for (const u of n)
2298
- i[u.id] = [];
2299
- const c = [];
2300
- for (const u of r)
2301
- (u.sectionId ? i[u.sectionId] ?? c : c).push(u);
2302
- const a = [`# ${o.name}`];
2303
- if (c.length > 0) {
2304
- a.push("");
2305
- const u = pe(c);
2306
- a.push(...Z(u));
2307
- }
2308
- for (const u of n) {
2309
- a.push(""), a.push(`## ${u.name}`);
2310
- const p = i[u.id];
2311
- if (!p?.length)
2312
- continue;
2313
- const b = pe(p);
2314
- a.push(...Z(b));
2315
- }
2316
- const d = a.join(`
2317
- `), l = {
2318
- type: "project_overview",
2319
- project: {
2320
- id: o.id,
2321
- name: o.name
2322
- },
2323
- sections: n,
2324
- tasks: r.map((u) => ({
2325
- ...u,
2326
- children: []
2327
- // Tasks already include hierarchical info via parentId
2328
- })),
2329
- stats: {
2330
- totalTasks: r.length,
2331
- totalSections: n.length,
2332
- tasksWithoutSection: c.length
2333
- }
2334
- };
2335
- return { textContent: d, structuredContent: l };
2336
- }
2337
- const Ss = {
2338
- name: g.GET_OVERVIEW,
2339
- description: "Get a Markdown overview. If no projectId is provided, shows all projects with hierarchy and sections (useful for navigation). If projectId is provided, shows detailed overview of that specific project including all tasks grouped by sections.",
2340
- parameters: Ts,
2341
- outputSchema: ys,
2342
- mutability: "readonly",
2343
- async execute(e, t) {
2344
- const o = e.projectId ? await Cs(t, e.projectId) : await vs(t);
2345
- return {
2346
- textContent: o.textContent,
2347
- structuredContent: o.structuredContent
2348
- };
2349
- }
2350
- }, { FIND_TASKS: $s, FIND_PROJECT_COLLABORATORS: he, UPDATE_TASKS: Ds } = g, xs = 50, As = {
2351
- operation: s.enum(["assign", "unassign", "reassign"]).describe("The assignment operation to perform."),
2352
- taskIds: s.array(s.string()).min(1).max(xs).describe("The IDs of the tasks to operate on (max 50)."),
2353
- responsibleUser: s.string().optional().describe(
2354
- "The user to assign tasks to. Can be user ID, name, or email. Required for assign and reassign operations."
2355
- ),
2356
- fromAssigneeUser: s.string().optional().describe(
2357
- "For reassign operations: the current assignee to reassign from. Can be user ID, name, or email. Optional - if not provided, reassigns from any current assignee."
2358
- ),
2359
- dryRun: s.boolean().optional().default(!1).describe("If true, validates operations without executing them.")
2360
- }, Us = {
2361
- results: s.array(
2362
- s.object({
2363
- taskId: s.string().describe("The ID of the task."),
2364
- success: s.boolean().describe("Whether the operation was successful."),
2365
- error: s.string().optional().describe("Error message if the operation failed."),
2366
- originalAssigneeId: s.string().optional().describe("The original assignee ID before the operation."),
2367
- newAssigneeId: s.string().optional().describe("The new assignee ID after the operation.")
2368
- })
2369
- ).describe("Results of the assignment operations."),
2370
- summary: s.object({
2371
- total: s.number().describe("Total number of tasks processed."),
2372
- succeeded: s.number().describe("Number of successful operations."),
2373
- failed: s.number().describe("Number of failed operations."),
2374
- dryRun: s.boolean().describe("Whether this was a dry run.")
2375
- }).optional().describe("Summary of the operation.")
2376
- }, Ps = {
2377
- name: g.MANAGE_ASSIGNMENTS,
2378
- description: "Bulk assignment operations for multiple tasks. Supports assign, unassign, and reassign operations with atomic rollback on failures.",
2379
- parameters: As,
2380
- outputSchema: Us,
2381
- mutability: "mutating",
2382
- async execute(e, t) {
2383
- const { operation: o, taskIds: n, responsibleUser: r, fromAssigneeUser: i, dryRun: c } = e;
2384
- if ((o === "assign" || o === "reassign") && !r)
2385
- throw new Error(`${o} operation requires responsibleUser parameter`);
2386
- const a = await Promise.allSettled(
2387
- n.map(async (h) => {
2388
- try {
2389
- return await t.getTask(h);
2390
- } catch {
2391
- throw new Error(`Task ${h} not found or not accessible`);
2392
- }
2393
- })
2394
- ), d = [], l = [];
2395
- for (let h = 0; h < a.length; h++) {
2396
- const T = a[h];
2397
- T && T.status === "fulfilled" ? d.push(T.value) : T && T.status === "rejected" ? l.push({
2398
- taskId: n[h] || "invalid-task-id",
2399
- success: !1,
2400
- error: T.reason?.message || "Task not accessible"
2401
- }) : l.push({
2402
- taskId: n[h] || "invalid-task-id",
2403
- success: !1,
2404
- error: "Task not accessible"
2405
- });
2406
- }
2407
- if (d.length === 0)
2408
- return {
2409
- textContent: z({
2410
- operation: o,
2411
- results: l,
2412
- dryRun: c
2413
- }),
2414
- structuredContent: {
2415
- operation: o,
2416
- results: l,
2417
- totalRequested: n.length,
2418
- successful: 0,
2419
- failed: l.length,
2420
- dryRun: c
2421
- }
2422
- };
2423
- let u;
2424
- o === "reassign" && i && (u = (await _.resolveUser(t, i))?.userId || i);
2425
- const p = [];
2426
- for (const h of d)
2427
- o === "reassign" && u && h.responsibleUid !== u || p.push({
2428
- taskId: h.id,
2429
- projectId: h.projectId,
2430
- responsibleUid: r || ""
2431
- // Will be validated appropriately
2432
- });
2433
- if (o === "unassign") {
2434
- if (c) {
2435
- const f = d.map(($) => ({
2436
- taskId: $.id,
2437
- success: !0,
2438
- originalAssigneeId: $.responsibleUid ?? void 0,
2439
- newAssigneeId: void 0
2440
- }));
2441
- return {
2442
- textContent: z({
2443
- operation: o,
2444
- results: f,
2445
- dryRun: !0
2446
- }),
2447
- structuredContent: {
2448
- operation: o,
2449
- results: f,
2450
- totalRequested: n.length,
2451
- successful: f.length,
2452
- failed: l.length,
2453
- dryRun: !0
2454
- }
2455
- };
2456
- }
2457
- const h = d.map(async (f) => {
2458
- try {
2459
- return await t.updateTask(f.id, { assigneeId: null }), {
2460
- taskId: f.id,
2461
- success: !0,
2462
- originalAssigneeId: f.responsibleUid ?? void 0,
2463
- newAssigneeId: void 0
2464
- };
2465
- } catch (j) {
2466
- return {
2467
- taskId: f.id,
2468
- success: !1,
2469
- error: j instanceof Error ? j.message : "Update failed",
2470
- originalAssigneeId: f.responsibleUid ?? void 0
2471
- };
2472
- }
2473
- }), T = await Promise.all(h), C = [...T, ...l];
2474
- return {
2475
- textContent: z({
2476
- operation: o,
2477
- results: C,
2478
- dryRun: !1
2479
- }),
2480
- structuredContent: {
2481
- operation: o,
2482
- results: C,
2483
- totalRequested: n.length,
2484
- successful: T.filter((f) => f.success).length,
2485
- failed: C.filter((f) => !f.success).length,
2486
- dryRun: !1
2487
- }
2488
- };
2489
- }
2490
- const b = await ie.validateBulkAssignment(
2491
- t,
2492
- p
2493
- ), m = [], y = [];
2494
- for (let h = 0; h < p.length; h++) {
2495
- const T = p[h], C = b[h];
2496
- T && C && C.isValid ? m.push({ assignment: T, validation: C }) : T?.taskId && y.push({
2497
- taskId: T.taskId,
2498
- success: !1,
2499
- error: C?.error?.message || "Validation failed"
2500
- });
2501
- }
2502
- async function k(h, T) {
2503
- const C = h.filter(
2504
- (f) => f.assignment != null && f.validation != null
2505
- );
2506
- if (!T)
2507
- return C.map(({ assignment: f, validation: j }) => {
2508
- const $ = d.find((x) => x.id === f.taskId);
2509
- if (!f.taskId || !j.resolvedUser?.userId)
2510
- throw new Error(
2511
- "Invalid assignment or validation data - this should not happen"
2512
- );
2513
- return {
2514
- taskId: f.taskId,
2515
- success: !0,
2516
- originalAssigneeId: $?.responsibleUid ?? void 0,
2517
- newAssigneeId: j.resolvedUser.userId
2518
- };
2519
- });
2520
- const v = C.map(
2521
- async ({ assignment: f, validation: j }) => {
2522
- const $ = d.find((x) => x.id === f.taskId);
2523
- if (!f.taskId || !j.resolvedUser?.userId)
2524
- return {
2525
- taskId: f.taskId || "unknown-task",
2526
- success: !1,
2527
- error: "Invalid assignment data - missing task ID or resolved user",
2528
- originalAssigneeId: $?.responsibleUid ?? void 0
2529
- };
2530
- try {
2531
- return await t.updateTask(f.taskId, {
2532
- assigneeId: j.resolvedUser.userId
2533
- }), {
2534
- taskId: f.taskId,
2535
- success: !0,
2536
- originalAssigneeId: $?.responsibleUid ?? void 0,
2537
- newAssigneeId: j.resolvedUser.userId
2538
- };
2539
- } catch (x) {
2540
- return {
2541
- taskId: f.taskId,
2542
- success: !1,
2543
- error: x instanceof Error ? x.message : "Update failed",
2544
- originalAssigneeId: $?.responsibleUid ?? void 0
2545
- };
2546
- }
2547
- }
2548
- );
2549
- return Promise.all(v);
2550
- }
2551
- const w = await k(m, !c), D = [...w, ...y, ...l];
2552
- return {
2553
- textContent: z({
2554
- operation: o,
2555
- results: D,
2556
- dryRun: c
2557
- }),
2558
- structuredContent: {
2559
- operation: o,
2560
- results: D,
2561
- totalRequested: n.length,
2562
- successful: w.filter((h) => h.success).length,
2563
- failed: D.filter((h) => !h.success).length,
2564
- dryRun: c
2565
- }
2566
- };
2567
- }
2568
- };
2569
- function z({
2570
- operation: e,
2571
- results: t,
2572
- dryRun: o
2573
- }) {
2574
- const n = t.filter((d) => d.success), r = t.filter((d) => !d.success), i = o ? "would be" : "were", c = {
2575
- assign: "assigned",
2576
- unassign: "unassigned",
2577
- reassign: "reassigned"
2578
- }[e];
2579
- let a = `**${o ? "Dry Run: " : ""}Bulk ${e} operation**
2580
-
2581
- `;
2582
- if (n.length > 0) {
2583
- a += `**${n.length} task${n.length === 1 ? "" : "s"} ${i} successfully ${c}**
2584
- `;
2585
- const d = n.slice(0, 5);
2586
- for (const l of d) {
2587
- let u = "";
2588
- e === "unassign" ? u = " (unassigned from previous assignee)" : l.newAssigneeId && (u = ` → ${l.newAssigneeId}`), a += ` • Task ${l.taskId}${u}
2589
- `;
2590
- }
2591
- n.length > 5 && (a += ` • ... and ${n.length - 5} more
2592
- `), a += `
2593
- `;
2594
- }
2595
- if (r.length > 0) {
2596
- a += `**${r.length} task${r.length === 1 ? "" : "s"} failed**
2597
- `;
2598
- const d = r.slice(0, 5);
2599
- for (const l of d)
2600
- a += ` • Task ${l.taskId}: ${l.error}
2601
- `;
2602
- r.length > 5 && (a += ` • ... and ${r.length - 5} more failures
2603
- `), a += `
2604
- `;
2605
- }
2606
- return !o && n.length > 0 ? (a += `**Next steps:**
2607
- `, a += `• Use ${$s} with responsibleUser to see ${e === "unassign" ? "unassigned" : "newly assigned"} tasks
2608
- `, a += `• Use ${Ds} for individual assignment changes
2609
- `, r.length > 0 && (a += `• Check failed tasks and use ${he} to verify collaborator access
2610
- `)) : o ? (a += `**To execute:**
2611
- `, a += `• Remove dryRun parameter and run again to execute changes
2612
- `, n.length > 0 && (a += `• ${n.length} task${n.length === 1 ? "" : "s"} ready for ${e} operation
2613
- `), r.length > 0 && (a += `• Fix ${r.length} validation error${r.length === 1 ? "" : "s"} before executing
2614
- `)) : n.length === 0 && (a += `**Suggestions:**
2615
- `, a += `• Use ${he} to find valid assignees
2616
- `, a += `• Check task IDs and assignee permissions
2617
- `, a += `• Use dryRun=true to validate before executing
2618
- `), a;
2619
- }
2620
- const Es = {
2621
- query: s.string().min(1).describe("The search query string to find tasks and projects.")
2622
- }, Os = {
2623
- results: s.array(
2624
- s.object({
2625
- id: s.string().describe("The ID of the result."),
2626
- title: s.string().describe("The title of the result."),
2627
- url: s.string().describe("The URL of the result.")
2628
- })
2629
- ).describe("The search results."),
2630
- totalCount: s.number().describe("Total number of results found.")
2631
- }, _s = {
2632
- name: g.SEARCH,
2633
- description: "Search across tasks and projects in Todoist. Returns a list of relevant results with IDs, titles, and URLs.",
2634
- parameters: Es,
2635
- outputSchema: Os,
2636
- mutability: "readonly",
2637
- async execute(e, t) {
2638
- const { query: o } = e, [n, r] = await Promise.all([
2639
- se({
2640
- client: t,
2641
- query: `search: ${o}`,
2642
- limit: S.TASKS_MAX,
2643
- cursor: void 0
2644
- }),
2645
- ke(t)
2646
- ]), i = o.toLowerCase(), c = r.filter(
2647
- (d) => d.name.toLowerCase().includes(i)
2648
- ), a = [];
2649
- for (const d of n.tasks)
2650
- a.push({
2651
- id: `task:${d.id}`,
2652
- title: d.content,
2653
- url: me(d.id)
2654
- });
2655
- for (const d of c)
2656
- a.push({
2657
- id: `project:${d.id}`,
2658
- title: d.name,
2659
- url: fe(d.id)
2660
- });
2661
- return {
2662
- textContent: JSON.stringify({ results: a }),
2663
- structuredContent: { results: a, totalCount: a.length }
2664
- };
2665
- }
2666
- }, Ns = s.object({
2667
- id: s.string().min(1).describe("The ID of the comment to update."),
2668
- content: s.string().min(1).describe("The new content for the comment.")
2669
- }), Ms = {
2670
- comments: s.array(Ns).min(1).describe("The comments to update.")
2671
- }, Fs = {
2672
- comments: s.array(re).describe("The updated comments."),
2673
- totalCount: s.number().describe("The total number of comments updated."),
2674
- updatedCommentIds: s.array(s.string()).describe("The IDs of the updated comments."),
2675
- appliedOperations: s.object({
2676
- updateCount: s.number().describe("The number of comments updated.")
2677
- }).describe("Summary of operations performed.")
2678
- }, Rs = {
2679
- name: g.UPDATE_COMMENTS,
2680
- description: "Update multiple existing comments with new content.",
2681
- parameters: Ms,
2682
- outputSchema: Fs,
2683
- mutability: "mutating",
2684
- async execute(e, t) {
2685
- const { comments: o } = e, n = o.map(async (a) => await t.updateComment(a.id, { content: a.content })), i = (await Promise.all(n)).map(te);
2686
- return {
2687
- textContent: Ls({
2688
- comments: i
2689
- }),
2690
- structuredContent: {
2691
- comments: i,
2692
- totalCount: i.length,
2693
- updatedCommentIds: i.map((a) => a.id),
2694
- appliedOperations: {
2695
- updateCount: i.length
2696
- }
2697
- }
2698
- };
2699
- }
2700
- };
2701
- function Ls({ comments: e }) {
2702
- const t = e.filter((i) => i.taskId).length, o = e.filter((i) => i.projectId).length, n = [];
2703
- if (t > 0) {
2704
- const i = t > 1 ? "comments" : "comment";
2705
- n.push(`${t} task ${i}`);
2706
- }
2707
- if (o > 0) {
2708
- const i = o > 1 ? "comments" : "comment";
2709
- n.push(`${o} project ${i}`);
2710
- }
2711
- return n.length > 0 ? `Updated ${n.join(" and ")}` : "No comments updated";
2712
- }
2713
- const Ws = s.object({
2714
- id: s.string().min(1).describe("The ID of the project to update."),
2715
- name: s.string().min(1).optional().describe("The new name of the project."),
2716
- isFavorite: s.boolean().optional().describe("Whether the project is a favorite."),
2717
- viewStyle: s.enum(["list", "board", "calendar"]).optional().describe("The project view style.")
2718
- }), Bs = {
2719
- projects: s.array(Ws).min(1).describe("The projects to update.")
2720
- }, zs = {
2721
- projects: s.array(oe).describe("The updated projects."),
2722
- totalCount: s.number().describe("The total number of projects updated."),
2723
- updatedProjectIds: s.array(s.string()).describe("The IDs of the updated projects."),
2724
- appliedOperations: s.object({
2725
- updateCount: s.number().describe("The number of projects actually updated."),
2726
- skippedCount: s.number().describe("The number of projects skipped (no changes).")
2727
- }).describe("Summary of operations performed.")
2728
- }, Ys = {
2729
- name: g.UPDATE_PROJECTS,
2730
- description: "Update multiple existing projects with new values.",
2731
- parameters: Bs,
2732
- outputSchema: zs,
2733
- mutability: "mutating",
2734
- async execute(e, t) {
2735
- const { projects: o } = e, n = o.map(async (c) => {
2736
- if (!Ks(c))
2737
- return;
2738
- const { id: a, ...d } = c;
2739
- return await t.updateProject(a, d);
2740
- }), r = (await Promise.all(n)).filter(
2741
- (c) => c !== void 0
2742
- ).map((c) => ({
2743
- ...c,
2744
- parentId: "parentId" in c ? c.parentId ?? void 0 : void 0,
2745
- inboxProject: "inboxProject" in c ? c.inboxProject : !1
2746
- }));
2747
- return {
2748
- textContent: Hs({
2749
- projects: r,
2750
- args: e
2751
- }),
2752
- structuredContent: {
2753
- projects: r,
2754
- totalCount: r.length,
2755
- updatedProjectIds: r.map((c) => c.id),
2756
- appliedOperations: {
2757
- updateCount: r.length,
2758
- skippedCount: o.length - r.length
2759
- }
2760
- }
2761
- };
2762
- }
2763
- };
2764
- function Hs({
2765
- projects: e,
2766
- args: t
2767
- }) {
2768
- const o = t.projects.length, n = e.length, r = o - n, i = e.length, c = e.map((d) => `• ${d.name} (id=${d.id})`).join(`
2769
- `);
2770
- let a = `Updated ${i} project${i === 1 ? "" : "s"}`;
2771
- return r > 0 && (a += ` (${r} skipped - no changes)`), i > 0 && (a += `:
2772
- ${c}`), a;
2773
- }
2774
- function Ks({ id: e, ...t }) {
2775
- return Object.keys(t).length > 0;
2776
- }
2777
- const Vs = s.object({
2778
- id: s.string().min(1).describe("The ID of the section to update."),
2779
- name: s.string().min(1).describe("The new name of the section.")
2780
- }), Gs = {
2781
- sections: s.array(Vs).min(1).describe("The sections to update.")
2782
- }, qs = {
2783
- sections: s.array(ne).describe("The updated sections."),
2784
- totalCount: s.number().describe("The total number of sections updated."),
2785
- updatedSectionIds: s.array(s.string()).describe("The IDs of the updated sections.")
2786
- }, Js = {
2787
- name: g.UPDATE_SECTIONS,
2788
- description: "Update multiple existing sections with new values.",
2789
- parameters: Gs,
2790
- outputSchema: qs,
2791
- mutability: "mutating",
2792
- async execute({ sections: e }, t) {
2793
- const o = await Promise.all(
2794
- e.map((r) => t.updateSection(r.id, { name: r.name }))
2795
- );
2796
- return {
2797
- textContent: Xs({
2798
- sections: o
2799
- }),
2800
- structuredContent: {
2801
- sections: o,
2802
- totalCount: o.length,
2803
- updatedSectionIds: o.map((r) => r.id)
2804
- }
2805
- };
2806
- }
2807
- };
2808
- function Xs({ sections: e }) {
2809
- const t = e.length, o = e.map((r) => `• ${r.name} (id=${r.id}, projectId=${r.projectId})`).join(`
2810
- `);
2811
- return `Updated ${t} section${t === 1 ? "" : "s"}:
2812
- ${o}`;
2813
- }
2814
- const Zs = s.object({
2815
- id: s.string().min(1).describe("The ID of the task to update."),
2816
- content: s.string().optional().describe(
2817
- 'The new task name/title. Should be concise and actionable (e.g., "Review PR #123", "Call dentist"). For longer content, use the description field instead. Supports Markdown.'
2818
- ),
2819
- description: s.string().optional().describe(
2820
- "New additional details, notes, or context for the task. Use this for longer content rather than putting it in the task name. Supports Markdown."
2821
- ),
2822
- projectId: s.string().optional().describe(
2823
- 'The new project ID for the task. Project ID should be an ID string, or the text "inbox", for inbox tasks.'
2824
- ),
2825
- sectionId: s.string().optional().describe("The new section ID for the task."),
2826
- parentId: s.string().optional().describe("The new parent task ID (for subtasks)."),
2827
- order: s.number().optional().describe("The new order of the task within its parent/section."),
2828
- priority: Q.optional().describe(
2829
- "The new priority of the task: p1 (highest), p2 (high), p3 (medium), p4 (lowest/default)."
2830
- ),
2831
- dueString: s.string().optional().describe("The new due date for the task, in natural language (e.g., 'tomorrow at 5pm')."),
2832
- deadlineDate: s.string().optional().describe(
2833
- 'The new deadline date for the task in ISO 8601 format (YYYY-MM-DD, e.g., "2025-12-31"). Deadlines are immovable constraints shown with a different indicator than due dates. Use "remove" to clear the deadline.'
2834
- ),
2835
- duration: s.string().optional().describe(
2836
- 'The duration of the task. Use format: "2h" (hours), "90m" (minutes), "2h30m" (combined), or "1.5h" (decimal hours). Max 24h.'
2837
- ),
2838
- responsibleUser: s.string().optional().describe(
2839
- 'Change task assignment. Use "unassign" to remove assignment. Can be user ID, name, or email. User must be a project collaborator.'
2840
- ),
2841
- labels: s.array(s.string()).optional().describe("The new labels for the task. Replaces all existing labels."),
2842
- isUncompletable: s.boolean().optional().describe(
2843
- "Whether this task should be uncompletable (organizational header). Tasks with isUncompletable: true appear as organizational headers and cannot be completed."
2844
- )
2845
- }), Qs = {
2846
- tasks: s.array(Zs).min(1).describe("The tasks to update.")
2847
- }, eo = {
2848
- tasks: s.array(B).describe("The updated tasks."),
2849
- totalCount: s.number().describe("The total number of tasks updated."),
2850
- updatedTaskIds: s.array(s.string()).describe("The IDs of the updated tasks."),
2851
- appliedOperations: s.object({
2852
- updateCount: s.number().describe("The number of tasks actually updated."),
2853
- skippedCount: s.number().describe("The number of tasks skipped (no changes).")
2854
- }).describe("Summary of operations performed.")
2855
- }, to = {
2856
- name: g.UPDATE_TASKS,
2857
- description: "Update existing tasks including content, dates, priorities, and assignments.",
2858
- parameters: Qs,
2859
- outputSchema: eo,
2860
- mutability: "mutating",
2861
- async execute(e, t) {
2862
- const { tasks: o } = e, n = o.map(async (a) => {
2863
- if (!oo(a))
2864
- return;
2865
- const {
2866
- id: d,
2867
- projectId: l,
2868
- sectionId: u,
2869
- parentId: p,
2870
- duration: b,
2871
- responsibleUser: m,
2872
- priority: y,
2873
- labels: k,
2874
- deadlineDate: w,
2875
- ...D
2876
- } = a;
2877
- let P = l;
2878
- l === "inbox" && (P = (await t.getUser()).inboxProjectId);
2879
- let h = {
2880
- ...D,
2881
- ...k !== void 0 && { labels: k }
2882
- };
2883
- if (y && (h.priority = Te(y)), w !== void 0 && (w === null || w === "remove" ? h = { ...h, deadlineDate: null } : h = { ...h, deadlineDate: w }), b)
2884
- try {
2885
- const { minutes: v } = ge(b);
2886
- h = {
2887
- ...h,
2888
- duration: v,
2889
- durationUnit: "minute"
2890
- };
2891
- } catch (v) {
2892
- throw v instanceof U ? new Error(`Task ${d}: ${v.message}`) : v;
2893
- }
2894
- if (m !== void 0)
2895
- if (m === null || m === "unassign")
2896
- h = { ...h, assigneeId: null };
2897
- else {
2898
- const v = await ie.validateTaskUpdateAssignment(
2899
- t,
2900
- d,
2901
- m
2902
- );
2903
- if (!v.isValid) {
2904
- const f = v.error?.message || "Assignment validation failed", j = v.error?.suggestions?.join(". ") || "";
2905
- throw new Error(
2906
- `Task ${d}: ${f}${j ? `. ${j}` : ""}`
2907
- );
2908
- }
2909
- h = { ...h, assigneeId: v.resolvedUser?.userId };
2910
- }
2911
- if (!P && !u && !p)
2912
- return await t.updateTask(d, h);
2913
- const T = Ye(d, P, u, p), C = await t.moveTask(d, T);
2914
- return Object.keys(h).length > 0 ? await t.updateTask(d, h) : C;
2915
- }), r = (await Promise.all(n)).filter(
2916
- (a) => a !== void 0
2917
- ), i = r.map(O);
2918
- return {
2919
- textContent: so({
2920
- tasks: i,
2921
- args: e
2922
- }),
2923
- structuredContent: {
2924
- tasks: i,
2925
- totalCount: i.length,
2926
- updatedTaskIds: r.map((a) => a.id),
2927
- appliedOperations: {
2928
- updateCount: i.length,
2929
- skippedCount: o.length - i.length
2930
- }
2931
- }
2932
- };
2933
- }
2934
- };
2935
- function so({
2936
- tasks: e,
2937
- args: t
2938
- }) {
2939
- const o = t.tasks.length, n = e.length, r = o - n;
2940
- let i = "";
2941
- return r > 0 && (i = ` (${r} skipped - no changes)`), je("Updated", e, {
2942
- context: i,
2943
- showDetails: e.length <= 5
2944
- });
2945
- }
2946
- function oo({ id: e, ...t }) {
2947
- return Object.keys(t).length > 0;
2948
- }
2949
- const no = {}, ro = {
2950
- type: s.literal("user_info").describe("The type of the response."),
2951
- userId: s.string().describe("The user ID."),
2952
- fullName: s.string().describe("The full name of the user."),
2953
- timezone: s.string().describe("The timezone of the user."),
2954
- currentLocalTime: s.string().describe("The current local time of the user."),
2955
- startDay: s.number().describe("The start day of the week (1 = Monday, 7 = Sunday)."),
2956
- startDayName: s.string().describe("The name of the start day."),
2957
- weekStartDate: s.string().describe("The start date of the current week (YYYY-MM-DD)."),
2958
- weekEndDate: s.string().describe("The end date of the current week (YYYY-MM-DD)."),
2959
- currentWeekNumber: s.number().describe("The current week number of the year."),
2960
- completedToday: s.number().describe("The number of tasks completed today."),
2961
- dailyGoal: s.number().describe("The daily goal for task completions."),
2962
- weeklyGoal: s.number().describe("The weekly goal for task completions."),
2963
- email: s.string().describe("The email address of the user."),
2964
- plan: s.enum(["Todoist Free", "Todoist Pro", "Todoist Business"]).describe("The user plan.")
2965
- };
2966
- function io(e) {
2967
- return e.businessAccountId ? "Todoist Business" : e.isPremium ? "Todoist Pro" : "Todoist Free";
2968
- }
2969
- function ao(e, t) {
2970
- const n = ((e.getDay() || 7) - t + 7) % 7, r = new Date(e);
2971
- return r.setDate(e.getDate() - n), r;
2972
- }
2973
- function co(e) {
2974
- const t = new Date(e);
2975
- return t.setDate(e.getDate() + 6), t;
2976
- }
2977
- function lo(e) {
2978
- const t = new Date(e.getFullYear(), 0, 1), o = (e.getTime() - t.getTime()) / 864e5;
2979
- return Math.ceil((o + t.getDay() + 1) / 7);
2980
- }
2981
- function uo(e) {
2982
- return ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"][e === 7 ? 0 : e] ?? "Unknown";
2983
- }
2984
- function Y(e) {
2985
- return e.toISOString().split("T")[0] ?? "";
2986
- }
2987
- function po(e) {
2988
- try {
2989
- return new Intl.DateTimeFormat("en-US", { timeZone: e }), !0;
2990
- } catch {
2991
- return !1;
2992
- }
2993
- }
2994
- function xe(e) {
2995
- return po(e) ? e : "UTC";
2996
- }
2997
- function ho(e, t) {
2998
- const o = xe(t);
2999
- return e.toLocaleString("en-US", {
3000
- timeZone: o,
3001
- year: "numeric",
3002
- month: "2-digit",
3003
- day: "2-digit",
3004
- hour: "2-digit",
3005
- minute: "2-digit",
3006
- second: "2-digit",
3007
- hour12: !1
3008
- });
3009
- }
3010
- async function mo(e) {
3011
- const t = await e.getUser(), o = t.tzInfo?.timezone ?? "UTC", n = xe(o), r = /* @__PURE__ */ new Date(), i = ho(r, n), c = t.startDay ?? 1, a = uo(c), d = io(t), l = new Date(r.toLocaleString("en-US", { timeZone: n })), u = ao(l, c), p = co(u), b = lo(l), y = [
3012
- "# User Information",
3013
- "",
3014
- `**User ID:** ${t.id}`,
3015
- `**Full Name:** ${t.fullName}`,
3016
- `**Email:** ${t.email}`,
3017
- `**Timezone:** ${n}`,
3018
- `**Current Local Time:** ${i}`,
3019
- "",
3020
- "## Week Settings",
3021
- `**Week Start Day:** ${a} (${c})`,
3022
- `**Current Week:** Week ${b}`,
3023
- `**Week Start Date:** ${Y(u)}`,
3024
- `**Week End Date:** ${Y(p)}`,
3025
- "",
3026
- "## Daily Progress",
3027
- `**Completed Today:** ${t.completedToday}`,
3028
- `**Daily Goal:** ${t.dailyGoal}`,
3029
- `**Weekly Goal:** ${t.weeklyGoal}`,
3030
- "",
3031
- "## Account Info",
3032
- `**Plan:** ${d}`
3033
- ].join(`
3034
- `), k = {
3035
- type: "user_info",
3036
- userId: t.id,
3037
- fullName: t.fullName,
3038
- timezone: n,
3039
- currentLocalTime: i,
3040
- startDay: c,
3041
- startDayName: a,
3042
- weekStartDate: Y(u),
3043
- weekEndDate: Y(p),
3044
- currentWeekNumber: b,
3045
- completedToday: t.completedToday,
3046
- dailyGoal: t.dailyGoal,
3047
- weeklyGoal: t.weeklyGoal,
3048
- email: t.email,
3049
- plan: d
3050
- };
3051
- return { textContent: y, structuredContent: k };
3052
- }
3053
- const fo = {
3054
- name: g.USER_INFO,
3055
- description: "Get comprehensive user information including user ID, full name, email, timezone with current local time, week start day preferences, current week dates, daily/weekly goal progress, and user plan (Free/Pro/Business).",
3056
- parameters: no,
3057
- outputSchema: ro,
3058
- mutability: "readonly",
3059
- async execute(e, t) {
3060
- const o = await mo(t);
3061
- return {
3062
- textContent: o.textContent,
3063
- structuredContent: o.structuredContent
3064
- };
3065
- }
3066
- }, bo = `
3067
- ## Todoist Task and Project Management Tools
3068
-
3069
- You have access to comprehensive Todoist management tools for personal productivity and team collaboration. Use these tools to help users manage tasks, projects, sections, comments, and assignments effectively.
3070
-
3071
- ### Core Capabilities:
3072
- - Create, update, complete, and search tasks with rich metadata (priorities, due dates, durations, assignments)
3073
- - Manage projects and sections with flexible organization
3074
- - Handle comments and collaboration features
3075
- - Bulk assignment operations for team workflows
3076
- - Get overviews and insights about workload and progress
3077
-
3078
- ### Tool Usage Guidelines:
3079
-
3080
- **Task Management:**
3081
- - **add-tasks**: Create tasks with content, description, priority (p1=highest, p2=high, p3=medium, p4=lowest/default), dueString (natural language like "tomorrow", "next Friday", "2024-12-25"), deadlineDate (ISO 8601 format like "2025-12-31" for immovable constraints), duration (formats like "2h", "90m", "2h30m"), and assignments to project collaborators
3082
- - **update-tasks**: Modify existing tasks - get task IDs from search results first, only include fields that need changes. Supports deadlineDate (ISO 8601 format like "2025-12-31") updates and removals (use "remove" to clear)
3083
- - **complete-tasks**: Mark tasks as done using task IDs
3084
- - **find-tasks**: Search by text, project/section/parent container, responsible user, or labels. Requires at least one search parameter
3085
- - **find-tasks-by-date**: Get tasks by date range (startDate: YYYY-MM-DD or 'today' which includes overdue tasks) or specific day counts
3086
- - **find-completed-tasks**: View completed tasks by completion date or original due date (returns all collaborators unless filtered)
3087
-
3088
- **Project & Organization:**
3089
- - **add-projects/update-projects/find-projects**: Manage project lifecycle with names, favorites, and view styles (list/board/calendar)
3090
- - **add-sections/update-sections/find-sections**: Organize tasks within projects using sections
3091
- - **get-overview**: Get comprehensive Markdown overview of entire account or specific project with task hierarchies
3092
-
3093
- **Collaboration & Comments:**
3094
- - **add-comments/update-comments/find-comments**: Manage task and project discussions
3095
- - **find-project-collaborators**: Find team members by name or email for assignments
3096
- - **manage-assignments**: Bulk assign/unassign/reassign up to 50 tasks with atomic operations and dry-run validation
3097
-
3098
- **Activity & Audit:**
3099
- - **find-activity**: Retrieve recent activity logs to monitor and audit changes. Shows events from all users by default; use initiatorId to filter by specific user. Filter by object type (task/project/comment), event type (added/updated/deleted/completed/uncompleted/archived/unarchived/shared/left), and specific objects (objectId, projectId, taskId). Useful for tracking who did what and when. Note: Date-based filtering is not supported.
3100
-
3101
- **General Operations:**
3102
- - **delete-object**: Remove projects, sections, tasks, or comments by type and ID
3103
- - **user-info**: Get user details including timezone, goals, and plan information
3104
-
3105
- ### Best Practices:
3106
-
3107
- 1. **Task Creation**: Write clear, actionable task titles. Use natural language for due dates ("tomorrow", "next Monday"). Set appropriate priorities and include detailed descriptions when needed.
3108
-
3109
- 2. **Search Strategy**: Use specific search queries combining multiple filters for precise results. When searching for tasks, start with broader queries and narrow down as needed.
3110
-
3111
- 3. **Assignments**: Always validate project collaborators exist before assigning tasks. Use find-project-collaborators to verify user access.
3112
-
3113
- 4. **Bulk Operations**: When working with multiple items, prefer bulk tools (complete-tasks, manage-assignments) over individual operations for better performance.
3114
-
3115
- 5. **Date Handling**: All dates respect user timezone settings. Use 'today' keyword for dynamic date filtering (includes overdue tasks).
3116
-
3117
- 6. **Labels**: Use label filtering with AND/OR operators for advanced task organization. Most search tools support labels parameter.
3118
-
3119
- 7. **Pagination**: Large result sets use cursor-based pagination. Use limit parameter to control result size (default varies by tool).
3120
-
3121
- 8. **Error Handling**: All tools provide detailed error messages and next-step suggestions. Pay attention to validation feedback for corrective actions.
3122
-
3123
- ### Common Workflows:
3124
-
3125
- - **Daily Planning**: Use find-tasks-by-date with 'today' and get-overview for project status
3126
- - **Team Assignment**: find-project-collaborators → add-tasks with responsibleUser → manage-assignments for bulk changes
3127
- - **Task Search**: find-tasks with multiple filters → update-tasks or complete-tasks based on results
3128
- - **Project Organization**: add-projects → add-sections → add-tasks with projectId and sectionId
3129
- - **Progress Reviews**: find-completed-tasks with date ranges → get-overview for project summaries
3130
- - **Activity Auditing**: find-activity with event/object filters to track changes, monitor team activity, or investigate specific actions
3131
-
3132
- Always provide clear, actionable task titles and descriptions. Use the overview tools to give users context about their workload and project status.
3133
- `;
3134
- function wo({ todoistApiKey: e, baseUrl: t }) {
3135
- const o = new Ue(
3136
- { name: "todoist-mcp-server", version: "0.1.0" },
3137
- {
3138
- capabilities: {
3139
- tools: { listChanged: !0 }
3140
- },
3141
- instructions: bo
3142
- }
3143
- ), n = new Ae(e, { baseUrl: t });
3144
- return I(It, o, n), I(Ct, o, n), I(to, o, n), I(ps, o, n), I(bs, o, n), I(Vt, o, n), I(rt, o, n), I(Ys, o, n), I(os, o, n), I(lt, o, n), I(Js, o, n), I(cs, o, n), I(et, o, n), I(Bt, o, n), I(Rs, o, n), I(_t, o, n), I(Ss, o, n), I(xt, o, n), I(fo, o, n), I(Zt, o, n), I(Ps, o, n), I(_s, o, n), I(Pt, o, n), o;
3145
- }
3146
- export {
3147
- Zt as a,
3148
- Ss as b,
3149
- _t as c,
3150
- xt as d,
3151
- Bt as e,
3152
- Pt as f,
3153
- wo as g,
3154
- Rs as h,
3155
- et as i,
3156
- cs as j,
3157
- Js as k,
3158
- lt as l,
3159
- Ps as m,
3160
- os as n,
3161
- Ys as o,
3162
- rt as p,
3163
- Vt as q,
3164
- bs as r,
3165
- _s as s,
3166
- ps as t,
3167
- fo as u,
3168
- to as v,
3169
- Ct as w,
3170
- It as x
3171
- };