@doist/todoist-ai 4.1.0 → 4.5.1

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 (97) hide show
  1. package/dist/index.d.ts +405 -50
  2. package/dist/index.d.ts.map +1 -1
  3. package/dist/index.js +26 -16
  4. package/dist/mcp-helpers.d.ts.map +1 -1
  5. package/dist/mcp-helpers.js +1 -1
  6. package/dist/mcp-server.d.ts.map +1 -1
  7. package/dist/mcp-server.js +80 -17
  8. package/dist/tool-helpers.d.ts +4 -0
  9. package/dist/tool-helpers.d.ts.map +1 -1
  10. package/dist/tool-helpers.js +2 -0
  11. package/dist/tools/__tests__/add-projects.test.js +1 -1
  12. package/dist/tools/__tests__/add-sections.test.js +1 -1
  13. package/dist/tools/__tests__/add-tasks.test.js +52 -13
  14. package/dist/tools/__tests__/assignment-integration.test.d.ts +2 -0
  15. package/dist/tools/__tests__/assignment-integration.test.d.ts.map +1 -0
  16. package/dist/tools/__tests__/assignment-integration.test.js +415 -0
  17. package/dist/tools/__tests__/find-completed-tasks.test.js +136 -2
  18. package/dist/tools/__tests__/find-projects.test.js +1 -1
  19. package/dist/tools/__tests__/find-sections.test.js +1 -1
  20. package/dist/tools/__tests__/find-tasks-by-date.test.js +122 -3
  21. package/dist/tools/__tests__/find-tasks.test.js +258 -11
  22. package/dist/tools/__tests__/get-overview.test.js +1 -1
  23. package/dist/tools/__tests__/update-sections.test.js +1 -0
  24. package/dist/tools/__tests__/update-tasks.test.js +6 -6
  25. package/dist/tools/__tests__/user-info.test.d.ts +2 -0
  26. package/dist/tools/__tests__/user-info.test.d.ts.map +1 -0
  27. package/dist/tools/__tests__/user-info.test.js +139 -0
  28. package/dist/tools/add-comments.d.ts +28 -5
  29. package/dist/tools/add-comments.d.ts.map +1 -1
  30. package/dist/tools/add-comments.js +1 -1
  31. package/dist/tools/add-projects.d.ts +46 -2
  32. package/dist/tools/add-projects.d.ts.map +1 -1
  33. package/dist/tools/add-projects.js +1 -1
  34. package/dist/tools/add-sections.d.ts +14 -2
  35. package/dist/tools/add-sections.d.ts.map +1 -1
  36. package/dist/tools/add-sections.js +1 -1
  37. package/dist/tools/add-tasks.d.ts +16 -10
  38. package/dist/tools/add-tasks.d.ts.map +1 -1
  39. package/dist/tools/add-tasks.js +49 -3
  40. package/dist/tools/find-comments.d.ts +27 -4
  41. package/dist/tools/find-comments.d.ts.map +1 -1
  42. package/dist/tools/find-completed-tasks.d.ts +12 -4
  43. package/dist/tools/find-completed-tasks.d.ts.map +1 -1
  44. package/dist/tools/find-completed-tasks.js +20 -4
  45. package/dist/tools/find-project-collaborators.d.ts +64 -0
  46. package/dist/tools/find-project-collaborators.d.ts.map +1 -0
  47. package/dist/tools/find-project-collaborators.js +151 -0
  48. package/dist/tools/find-tasks-by-date.d.ts +8 -0
  49. package/dist/tools/find-tasks-by-date.d.ts.map +1 -1
  50. package/dist/tools/find-tasks-by-date.js +19 -2
  51. package/dist/tools/find-tasks.d.ts +13 -2
  52. package/dist/tools/find-tasks.d.ts.map +1 -1
  53. package/dist/tools/find-tasks.js +172 -23
  54. package/dist/tools/get-overview.d.ts +2 -2
  55. package/dist/tools/get-overview.d.ts.map +1 -1
  56. package/dist/tools/get-overview.js +1 -1
  57. package/dist/tools/manage-assignments.d.ts +52 -0
  58. package/dist/tools/manage-assignments.d.ts.map +1 -0
  59. package/dist/tools/manage-assignments.js +337 -0
  60. package/dist/tools/update-comments.d.ts +25 -2
  61. package/dist/tools/update-comments.d.ts.map +1 -1
  62. package/dist/tools/update-comments.js +1 -1
  63. package/dist/tools/update-projects.d.ts +46 -2
  64. package/dist/tools/update-projects.d.ts.map +1 -1
  65. package/dist/tools/update-sections.d.ts +14 -2
  66. package/dist/tools/update-sections.d.ts.map +1 -1
  67. package/dist/tools/update-sections.js +1 -1
  68. package/dist/tools/update-tasks.d.ts +16 -10
  69. package/dist/tools/update-tasks.d.ts.map +1 -1
  70. package/dist/tools/update-tasks.js +32 -9
  71. package/dist/tools/user-info.d.ts +44 -0
  72. package/dist/tools/user-info.d.ts.map +1 -0
  73. package/dist/tools/user-info.js +142 -0
  74. package/dist/utils/assignment-validator.d.ts +69 -0
  75. package/dist/utils/assignment-validator.d.ts.map +1 -0
  76. package/dist/utils/assignment-validator.js +253 -0
  77. package/dist/utils/duration-parser.d.ts +2 -2
  78. package/dist/utils/duration-parser.d.ts.map +1 -1
  79. package/dist/utils/labels.d.ts +10 -0
  80. package/dist/utils/labels.d.ts.map +1 -0
  81. package/dist/utils/labels.js +18 -0
  82. package/dist/utils/priorities.d.ts +8 -0
  83. package/dist/utils/priorities.d.ts.map +1 -0
  84. package/dist/utils/priorities.js +15 -0
  85. package/dist/utils/response-builders.d.ts +2 -2
  86. package/dist/utils/response-builders.d.ts.map +1 -1
  87. package/dist/utils/response-builders.js +8 -1
  88. package/dist/utils/test-helpers.d.ts +2 -0
  89. package/dist/utils/test-helpers.d.ts.map +1 -1
  90. package/dist/utils/test-helpers.js +3 -0
  91. package/dist/utils/tool-names.d.ts +3 -0
  92. package/dist/utils/tool-names.d.ts.map +1 -1
  93. package/dist/utils/tool-names.js +4 -0
  94. package/dist/utils/user-resolver.d.ts +39 -0
  95. package/dist/utils/user-resolver.d.ts.map +1 -0
  96. package/dist/utils/user-resolver.js +179 -0
  97. package/package.json +7 -7
@@ -0,0 +1,139 @@
1
+ import { jest } from '@jest/globals';
2
+ import { extractStructuredContent, extractTextContent, TEST_ERRORS, } from '../../utils/test-helpers.js';
3
+ import { ToolNames } from '../../utils/tool-names.js';
4
+ import { userInfo } from '../user-info.js';
5
+ // Mock the Todoist API
6
+ const mockTodoistApi = {
7
+ getUser: jest.fn(),
8
+ };
9
+ const { USER_INFO } = ToolNames;
10
+ // Helper function to create a mock user with default values that can be overridden
11
+ function createMockUser(overrides = {}) {
12
+ return {
13
+ id: '123',
14
+ fullName: 'Test User',
15
+ email: 'test@example.com',
16
+ isPremium: true,
17
+ completedToday: 12,
18
+ dailyGoal: 10,
19
+ weeklyGoal: 100,
20
+ startDay: 1, // Monday
21
+ tzInfo: {
22
+ timezone: 'Europe/Madrid',
23
+ gmtString: '+02:00',
24
+ hours: 2,
25
+ minutes: 0,
26
+ isDst: 1,
27
+ },
28
+ lang: 'en',
29
+ avatarBig: 'https://example.com/avatar.jpg',
30
+ avatarMedium: null,
31
+ avatarS640: null,
32
+ avatarSmall: null,
33
+ karma: 86394.0,
34
+ karmaTrend: 'up',
35
+ nextWeek: 1,
36
+ weekendStartDay: 6,
37
+ timeFormat: 0,
38
+ dateFormat: 0,
39
+ daysOff: [6, 7],
40
+ businessAccountId: null,
41
+ completedCount: 102920,
42
+ inboxProjectId: '6PVw8cMf7m8fWwRp',
43
+ startPage: 'overdue',
44
+ ...overrides,
45
+ };
46
+ }
47
+ describe(`${USER_INFO} tool`, () => {
48
+ beforeEach(() => {
49
+ jest.clearAllMocks();
50
+ });
51
+ it('should generate user info with all required fields', async () => {
52
+ const mockUser = createMockUser();
53
+ mockTodoistApi.getUser.mockResolvedValue(mockUser);
54
+ const result = await userInfo.execute({}, mockTodoistApi);
55
+ expect(mockTodoistApi.getUser).toHaveBeenCalledWith();
56
+ // Test text content contains expected information
57
+ const textContent = extractTextContent(result);
58
+ expect(textContent).toContain('User ID:** 123');
59
+ expect(textContent).toContain('Test User');
60
+ expect(textContent).toContain('test@example.com');
61
+ expect(textContent).toContain('Europe/Madrid');
62
+ expect(textContent).toContain('Monday (1)');
63
+ expect(textContent).toContain('Completed Today:** 12');
64
+ expect(textContent).toContain('Plan:** Todoist Pro');
65
+ // Test structured content
66
+ const structuredContent = extractStructuredContent(result);
67
+ expect(structuredContent).toEqual(expect.objectContaining({
68
+ type: 'user_info',
69
+ userId: '123',
70
+ fullName: 'Test User',
71
+ email: 'test@example.com',
72
+ timezone: 'Europe/Madrid',
73
+ startDay: 1,
74
+ startDayName: 'Monday',
75
+ completedToday: 12,
76
+ dailyGoal: 10,
77
+ weeklyGoal: 100,
78
+ plan: 'Todoist Pro',
79
+ currentLocalTime: expect.any(String),
80
+ weekStartDate: expect.any(String),
81
+ weekEndDate: expect.any(String),
82
+ currentWeekNumber: expect.any(Number),
83
+ }));
84
+ // Verify date formats
85
+ expect(structuredContent.weekStartDate).toMatch(/^\d{4}-\d{2}-\d{2}$/);
86
+ expect(structuredContent.weekEndDate).toMatch(/^\d{4}-\d{2}-\d{2}$/);
87
+ expect(structuredContent.currentLocalTime).toMatch(/^\d{2}\/\d{2}\/\d{4}, \d{2}:\d{2}:\d{2}$/);
88
+ });
89
+ it('should handle missing timezone info', async () => {
90
+ const mockUser = createMockUser({
91
+ isPremium: false,
92
+ tzInfo: {
93
+ timezone: 'UTC',
94
+ gmtString: '+00:00',
95
+ hours: 0,
96
+ minutes: 0,
97
+ isDst: 0,
98
+ },
99
+ });
100
+ mockTodoistApi.getUser.mockResolvedValue(mockUser);
101
+ const result = await userInfo.execute({}, mockTodoistApi);
102
+ const textContent = extractTextContent(result);
103
+ expect(textContent).toContain('UTC'); // Should default to UTC
104
+ expect(textContent).toContain('Monday (1)'); // Should default to Monday
105
+ expect(textContent).toContain('Plan:** Todoist Free');
106
+ const structuredContent = extractStructuredContent(result);
107
+ expect(structuredContent.timezone).toBe('UTC');
108
+ expect(structuredContent.startDay).toBe(1);
109
+ expect(structuredContent.startDayName).toBe('Monday');
110
+ expect(structuredContent.plan).toBe('Todoist Free');
111
+ });
112
+ it('should handle invalid timezone and fallback to UTC', async () => {
113
+ const mockUser = createMockUser({
114
+ startDay: 2, // Tuesday
115
+ tzInfo: {
116
+ timezone: 'Invalid/Timezone',
117
+ gmtString: '+05:30',
118
+ hours: 5,
119
+ minutes: 30,
120
+ isDst: 0,
121
+ },
122
+ });
123
+ mockTodoistApi.getUser.mockResolvedValue(mockUser);
124
+ const result = await userInfo.execute({}, mockTodoistApi);
125
+ const textContent = extractTextContent(result);
126
+ expect(textContent).toContain('UTC'); // Should fallback to UTC
127
+ expect(textContent).toContain('Tuesday (2)');
128
+ const structuredContent = extractStructuredContent(result);
129
+ expect(structuredContent.timezone).toBe('UTC'); // Should be UTC, not the invalid timezone
130
+ expect(structuredContent.startDay).toBe(2);
131
+ expect(structuredContent.startDayName).toBe('Tuesday');
132
+ expect(structuredContent.currentLocalTime).toMatch(/^\d{2}\/\d{2}\/\d{4}, \d{2}:\d{2}:\d{2}$/);
133
+ });
134
+ it('should propagate API errors', async () => {
135
+ const apiError = new Error(TEST_ERRORS.API_UNAUTHORIZED);
136
+ mockTodoistApi.getUser.mockRejectedValue(apiError);
137
+ await expect(userInfo.execute({}, mockTodoistApi)).rejects.toThrow(TEST_ERRORS.API_UNAUTHORIZED);
138
+ });
139
+ });
@@ -1,4 +1,3 @@
1
- import type { Comment } from '@doist/todoist-api-typescript';
2
1
  import { z } from 'zod';
3
2
  declare const addComments: {
4
3
  name: "add-comments";
@@ -10,19 +9,19 @@ declare const addComments: {
10
9
  content: z.ZodString;
11
10
  }, "strip", z.ZodTypeAny, {
12
11
  content: string;
13
- projectId?: string | undefined;
14
12
  taskId?: string | undefined;
13
+ projectId?: string | undefined;
15
14
  }, {
16
15
  content: string;
17
- projectId?: string | undefined;
18
16
  taskId?: string | undefined;
17
+ projectId?: string | undefined;
19
18
  }>, "many">;
20
19
  };
21
20
  execute(args: {
22
21
  comments: {
23
22
  content: string;
24
- projectId?: string | undefined;
25
23
  taskId?: string | undefined;
24
+ projectId?: string | undefined;
26
25
  }[];
27
26
  }, client: import("@doist/todoist-api-typescript").TodoistApi): Promise<{
28
27
  content: {
@@ -30,7 +29,31 @@ declare const addComments: {
30
29
  text: string;
31
30
  }[];
32
31
  structuredContent: {
33
- comments: Comment[];
32
+ comments: {
33
+ taskId: string | undefined;
34
+ id: string;
35
+ content: string;
36
+ postedAt: string;
37
+ fileAttachment: {
38
+ resourceType: string;
39
+ fileName?: string | null | undefined;
40
+ fileSize?: number | null | undefined;
41
+ fileType?: string | null | undefined;
42
+ fileUrl?: string | null | undefined;
43
+ fileDuration?: number | null | undefined;
44
+ uploadState?: "pending" | "completed" | null | undefined;
45
+ image?: string | null | undefined;
46
+ imageWidth?: number | null | undefined;
47
+ imageHeight?: number | null | undefined;
48
+ url?: string | null | undefined;
49
+ title?: string | null | undefined;
50
+ } | null;
51
+ postedUid: string;
52
+ uidsToNotify: string[] | null;
53
+ reactions: Record<string, string[]> | null;
54
+ isDeleted: boolean;
55
+ projectId?: string | undefined;
56
+ }[];
34
57
  totalCount: number;
35
58
  addedCommentIds: string[];
36
59
  };
@@ -1 +1 @@
1
- {"version":3,"file":"add-comments.d.ts","sourceRoot":"","sources":["../../src/tools/add-comments.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAkB,OAAO,EAAE,MAAM,+BAA+B,CAAA;AAC5E,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAkBvB,QAAA,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA0CyB,CAAA;AA6C1C,OAAO,EAAE,WAAW,EAAE,CAAA"}
1
+ {"version":3,"file":"add-comments.d.ts","sourceRoot":"","sources":["../../src/tools/add-comments.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAkBvB,QAAA,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4BAoFygV,CAAC;4BAA6C,CAAC;4BAA6C,CAAC;2BAA4C,CAAC;gCAAiD,CAAC;+BAAgD,CAAC;yBAA2D,CAAC;8BAA+C,CAAC;+BAAgD,CAAC;uBAAwC,CAAC;yBAA0C,CAAC;;;;;;;;;;;;;;;;;;;;;;;CA1C98V,CAAA;AAyC1C,OAAO,EAAE,WAAW,EAAE,CAAA"}
@@ -42,7 +42,7 @@ const addComments = {
42
42
  });
43
43
  },
44
44
  };
45
- function generateTextContent({ comments, }) {
45
+ function generateTextContent({ comments }) {
46
46
  // Group comments by entity type and count
47
47
  const taskComments = comments.filter((c) => c.taskId).length;
48
48
  const projectComments = comments.filter((c) => c.projectId).length;
@@ -1,4 +1,3 @@
1
- import type { PersonalProject, WorkspaceProject } from '@doist/todoist-api-typescript';
2
1
  import { z } from 'zod';
3
2
  declare const addProjects: {
4
3
  name: "add-projects";
@@ -30,7 +29,52 @@ declare const addProjects: {
30
29
  text: string;
31
30
  }[];
32
31
  structuredContent: {
33
- projects: (PersonalProject | WorkspaceProject)[];
32
+ projects: ({
33
+ url: string;
34
+ id: string;
35
+ canAssignTasks: boolean;
36
+ childOrder: number;
37
+ color: string;
38
+ createdAt: string | null;
39
+ isArchived: boolean;
40
+ isDeleted: boolean;
41
+ isFavorite: boolean;
42
+ isFrozen: boolean;
43
+ name: string;
44
+ updatedAt: string | null;
45
+ viewStyle: string;
46
+ defaultOrder: number;
47
+ description: string;
48
+ isCollapsed: boolean;
49
+ isShared: boolean;
50
+ parentId: string | null;
51
+ inboxProject: boolean;
52
+ } | {
53
+ url: string;
54
+ id: string;
55
+ canAssignTasks: boolean;
56
+ childOrder: number;
57
+ color: string;
58
+ createdAt: string | null;
59
+ isArchived: boolean;
60
+ isDeleted: boolean;
61
+ isFavorite: boolean;
62
+ isFrozen: boolean;
63
+ name: string;
64
+ updatedAt: string | null;
65
+ viewStyle: string;
66
+ defaultOrder: number;
67
+ description: string;
68
+ isCollapsed: boolean;
69
+ isShared: boolean;
70
+ collaboratorRoleDefault: string;
71
+ folderId: string | null;
72
+ isInviteOnly: boolean | null;
73
+ isLinkSharingEnabled: boolean;
74
+ role: string | null;
75
+ status: string;
76
+ workspaceId: string;
77
+ })[];
34
78
  totalCount: number;
35
79
  };
36
80
  } | {
@@ -1 +1 @@
1
- {"version":3,"file":"add-projects.d.ts","sourceRoot":"","sources":["../../src/tools/add-projects.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAA;AACtF,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAwBvB,QAAA,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAgByB,CAAA;AAmC1C,OAAO,EAAE,WAAW,EAAE,CAAA"}
1
+ {"version":3,"file":"add-projects.d.ts","sourceRoot":"","sources":["../../src/tools/add-projects.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAwBvB,QAAA,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAgByB,CAAA;AA+B1C,OAAO,EAAE,WAAW,EAAE,CAAA"}
@@ -33,7 +33,7 @@ const addProjects = {
33
33
  });
34
34
  },
35
35
  };
36
- function generateTextContent({ projects, }) {
36
+ function generateTextContent({ projects }) {
37
37
  const count = projects.length;
38
38
  const projectList = projects.map((project) => `• ${project.name} (id=${project.id})`).join('\n');
39
39
  const summary = `Added ${count} project${count === 1 ? '' : 's'}:\n${projectList}`;
@@ -1,4 +1,3 @@
1
- import type { Section } from '@doist/todoist-api-typescript';
2
1
  import { z } from 'zod';
3
2
  declare const addSections: {
4
3
  name: "add-sections";
@@ -26,7 +25,20 @@ declare const addSections: {
26
25
  text: string;
27
26
  }[];
28
27
  structuredContent: {
29
- sections: Section[];
28
+ sections: {
29
+ url: string;
30
+ id: string;
31
+ userId: string;
32
+ projectId: string;
33
+ addedAt: string;
34
+ updatedAt: string;
35
+ archivedAt: string | null;
36
+ name: string;
37
+ sectionOrder: number;
38
+ isArchived: boolean;
39
+ isDeleted: boolean;
40
+ isCollapsed: boolean;
41
+ }[];
30
42
  totalCount: number;
31
43
  };
32
44
  } | {
@@ -1 +1 @@
1
- {"version":3,"file":"add-sections.d.ts","sourceRoot":"","sources":["../../src/tools/add-sections.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,+BAA+B,CAAA;AAC5D,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAiBvB,QAAA,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAgByB,CAAA;AAiD1C,OAAO,EAAE,WAAW,EAAE,CAAA"}
1
+ {"version":3,"file":"add-sections.d.ts","sourceRoot":"","sources":["../../src/tools/add-sections.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAiBvB,QAAA,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAgByB,CAAA;AA6C1C,OAAO,EAAE,WAAW,EAAE,CAAA"}
@@ -26,7 +26,7 @@ const addSections = {
26
26
  });
27
27
  },
28
28
  };
29
- function generateTextContent({ sections, }) {
29
+ function generateTextContent({ sections }) {
30
30
  const count = sections.length;
31
31
  const sectionList = sections
32
32
  .map((section) => `• ${section.name} (id=${section.id}, projectId=${section.projectId})`)
@@ -7,42 +7,46 @@ declare const addTasks: {
7
7
  tasks: z.ZodArray<z.ZodObject<{
8
8
  content: z.ZodString;
9
9
  description: z.ZodOptional<z.ZodString>;
10
- priority: z.ZodOptional<z.ZodNumber>;
10
+ priority: z.ZodOptional<z.ZodEnum<["p1", "p2", "p3", "p4"]>>;
11
11
  dueString: z.ZodOptional<z.ZodString>;
12
12
  duration: z.ZodOptional<z.ZodString>;
13
13
  projectId: z.ZodOptional<z.ZodString>;
14
14
  sectionId: z.ZodOptional<z.ZodString>;
15
15
  parentId: z.ZodOptional<z.ZodString>;
16
+ responsibleUser: z.ZodOptional<z.ZodString>;
16
17
  }, "strip", z.ZodTypeAny, {
17
18
  content: string;
18
19
  description?: string | undefined;
19
- parentId?: string | undefined;
20
20
  projectId?: string | undefined;
21
+ parentId?: string | undefined;
21
22
  sectionId?: string | undefined;
22
- priority?: number | undefined;
23
- dueString?: string | undefined;
24
23
  duration?: string | undefined;
24
+ priority?: "p1" | "p2" | "p3" | "p4" | undefined;
25
+ dueString?: string | undefined;
26
+ responsibleUser?: string | undefined;
25
27
  }, {
26
28
  content: string;
27
29
  description?: string | undefined;
28
- parentId?: string | undefined;
29
30
  projectId?: string | undefined;
31
+ parentId?: string | undefined;
30
32
  sectionId?: string | undefined;
31
- priority?: number | undefined;
32
- dueString?: string | undefined;
33
33
  duration?: string | undefined;
34
+ priority?: "p1" | "p2" | "p3" | "p4" | undefined;
35
+ dueString?: string | undefined;
36
+ responsibleUser?: string | undefined;
34
37
  }>, "many">;
35
38
  };
36
39
  execute({ tasks }: {
37
40
  tasks: {
38
41
  content: string;
39
42
  description?: string | undefined;
40
- parentId?: string | undefined;
41
43
  projectId?: string | undefined;
44
+ parentId?: string | undefined;
42
45
  sectionId?: string | undefined;
43
- priority?: number | undefined;
44
- dueString?: string | undefined;
45
46
  duration?: string | undefined;
47
+ priority?: "p1" | "p2" | "p3" | "p4" | undefined;
48
+ dueString?: string | undefined;
49
+ responsibleUser?: string | undefined;
46
50
  }[];
47
51
  }, client: TodoistApi): Promise<{
48
52
  content: {
@@ -62,6 +66,8 @@ declare const addTasks: {
62
66
  parentId: string | null;
63
67
  labels: string[];
64
68
  duration: string | null;
69
+ responsibleUid: string | null;
70
+ assignedByUid: string | null;
65
71
  }[];
66
72
  totalCount: number;
67
73
  };
@@ -1 +1 @@
1
- {"version":3,"file":"add-tasks.d.ts","sourceRoot":"","sources":["../../src/tools/add-tasks.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAqB,UAAU,EAAE,MAAM,+BAA+B,CAAA;AAClF,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAgCvB,QAAA,MAAM,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAsB4B,CAAA;AA8D1C,OAAO,EAAE,QAAQ,EAAE,CAAA"}
1
+ {"version":3,"file":"add-tasks.d.ts","sourceRoot":"","sources":["../../src/tools/add-tasks.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAqB,UAAU,EAAE,MAAM,+BAA+B,CAAA;AAClF,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AA0CvB,QAAA,MAAM,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAuB4B,CAAA;AA+H1C,OAAO,EAAE,QAAQ,EAAE,CAAA"}
@@ -1,13 +1,15 @@
1
1
  import { z } from 'zod';
2
2
  import { getToolOutput } from '../mcp-helpers.js';
3
3
  import { mapTask } from '../tool-helpers.js';
4
+ import { assignmentValidator } from '../utils/assignment-validator.js';
4
5
  import { DurationParseError, parseDuration } from '../utils/duration-parser.js';
6
+ import { convertPriorityToNumber, PrioritySchema } from '../utils/priorities.js';
5
7
  import { generateTaskNextSteps, getDateString, summarizeTaskOperation, } from '../utils/response-builders.js';
6
8
  import { ToolNames } from '../utils/tool-names.js';
7
9
  const TaskSchema = z.object({
8
10
  content: z.string().min(1).describe('The content of the task to create.'),
9
11
  description: z.string().optional().describe('The description of the task.'),
10
- priority: z.number().int().min(1).max(4).optional().describe('The priority of the task (1-4).'),
12
+ priority: PrioritySchema.optional().describe('The priority of the task: p1 (highest), p2 (high), p3 (medium), p4 (lowest/default).'),
11
13
  dueString: z.string().optional().describe('The due date for the task, in natural language.'),
12
14
  duration: z
13
15
  .string()
@@ -16,13 +18,17 @@ const TaskSchema = z.object({
16
18
  projectId: z.string().optional().describe('The project ID to add this task to.'),
17
19
  sectionId: z.string().optional().describe('The section ID to add this task to.'),
18
20
  parentId: z.string().optional().describe('The parent task ID (for subtasks).'),
21
+ responsibleUser: z
22
+ .string()
23
+ .optional()
24
+ .describe('Assign task to this user. Can be a user ID, name, or email address. User must be a collaborator on the target project.'),
19
25
  });
20
26
  const ArgsSchema = {
21
27
  tasks: z.array(TaskSchema).min(1).describe('The array of tasks to add.'),
22
28
  };
23
29
  const addTasks = {
24
30
  name: ToolNames.ADD_TASKS,
25
- description: 'Add one or more tasks to a project, section, or parent.',
31
+ description: 'Add one or more tasks to a project, section, or parent. Supports assignment to project collaborators.',
26
32
  parameters: ArgsSchema,
27
33
  async execute({ tasks }, client) {
28
34
  const addTaskPromises = tasks.map((task) => processTask(task, client));
@@ -42,8 +48,16 @@ const addTasks = {
42
48
  },
43
49
  };
44
50
  async function processTask(task, client) {
45
- const { duration: durationStr, projectId, sectionId, parentId, ...otherTaskArgs } = task;
51
+ const { duration: durationStr, projectId, sectionId, parentId, responsibleUser, priority, ...otherTaskArgs } = task;
46
52
  let taskArgs = { ...otherTaskArgs, projectId, sectionId, parentId };
53
+ // Handle priority conversion if provided
54
+ if (priority) {
55
+ taskArgs.priority = convertPriorityToNumber(priority);
56
+ }
57
+ // Prevent assignment to tasks without sufficient project context
58
+ if (!projectId && !sectionId && !parentId) {
59
+ throw new Error(`Task "${task.content}": Cannot assign tasks without specifying project context. Please specify a projectId, sectionId, or parentId.`);
60
+ }
47
61
  // Parse duration if provided
48
62
  if (durationStr) {
49
63
  try {
@@ -61,6 +75,38 @@ async function processTask(task, client) {
61
75
  throw error;
62
76
  }
63
77
  }
78
+ // Handle assignment if provided
79
+ if (responsibleUser) {
80
+ // Resolve target project for validation
81
+ let targetProjectId = projectId;
82
+ if (!targetProjectId && parentId) {
83
+ // For subtasks, get project from parent task
84
+ try {
85
+ const parentTask = await client.getTask(parentId);
86
+ targetProjectId = parentTask.projectId;
87
+ }
88
+ catch (_error) {
89
+ throw new Error(`Task "${task.content}": Parent task "${parentId}" not found`);
90
+ }
91
+ }
92
+ else if (!targetProjectId && sectionId) {
93
+ // For section tasks, we need to find the project - this is a limitation
94
+ // For now, we'll require explicit projectId when using assignments with sections
95
+ throw new Error(`Task "${task.content}": When assigning tasks to sections, please also specify projectId`);
96
+ }
97
+ if (!targetProjectId) {
98
+ throw new Error(`Task "${task.content}": Cannot determine target project for assignment validation`);
99
+ }
100
+ // Validate assignment using comprehensive validator
101
+ const validation = await assignmentValidator.validateTaskCreationAssignment(client, targetProjectId, responsibleUser);
102
+ if (!validation.isValid) {
103
+ const errorMsg = validation.error?.message || 'Assignment validation failed';
104
+ const suggestions = validation.error?.suggestions?.join('. ') || '';
105
+ throw new Error(`Task "${task.content}": ${errorMsg}${suggestions ? `. ${suggestions}` : ''}`);
106
+ }
107
+ // Use the validated assignee ID
108
+ taskArgs.assigneeId = validation.resolvedUser?.userId;
109
+ }
64
110
  return await client.addTask(taskArgs);
65
111
  }
66
112
  function generateTextContent({ tasks, args, }) {
@@ -1,4 +1,3 @@
1
- import type { Comment } from '@doist/todoist-api-typescript';
2
1
  import { z } from 'zod';
3
2
  declare const findComments: {
4
3
  name: "find-comments";
@@ -11,10 +10,10 @@ declare const findComments: {
11
10
  limit: z.ZodOptional<z.ZodNumber>;
12
11
  };
13
12
  execute(args: {
14
- projectId?: string | undefined;
15
13
  limit?: number | undefined;
16
- cursor?: string | undefined;
17
14
  taskId?: string | undefined;
15
+ projectId?: string | undefined;
16
+ cursor?: string | undefined;
18
17
  commentId?: string | undefined;
19
18
  }, client: import("@doist/todoist-api-typescript").TodoistApi): Promise<{
20
19
  content: {
@@ -22,7 +21,31 @@ declare const findComments: {
22
21
  text: string;
23
22
  }[];
24
23
  structuredContent: {
25
- comments: Comment[];
24
+ comments: {
25
+ taskId: string | undefined;
26
+ id: string;
27
+ content: string;
28
+ postedAt: string;
29
+ fileAttachment: {
30
+ resourceType: string;
31
+ fileName?: string | null | undefined;
32
+ fileSize?: number | null | undefined;
33
+ fileType?: string | null | undefined;
34
+ fileUrl?: string | null | undefined;
35
+ fileDuration?: number | null | undefined;
36
+ uploadState?: "pending" | "completed" | null | undefined;
37
+ image?: string | null | undefined;
38
+ imageWidth?: number | null | undefined;
39
+ imageHeight?: number | null | undefined;
40
+ url?: string | null | undefined;
41
+ title?: string | null | undefined;
42
+ } | null;
43
+ postedUid: string;
44
+ uidsToNotify: string[] | null;
45
+ reactions: Record<string, string[]> | null;
46
+ isDeleted: boolean;
47
+ projectId?: string | undefined;
48
+ }[];
26
49
  searchType: string;
27
50
  searchId: string;
28
51
  hasMore: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"find-comments.d.ts","sourceRoot":"","sources":["../../src/tools/find-comments.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,+BAA+B,CAAA;AAC5D,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAuBvB,QAAA,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAsEwB,CAAA;AAoF1C,OAAO,EAAE,YAAY,EAAE,CAAA"}
1
+ {"version":3,"file":"find-comments.d.ts","sourceRoot":"","sources":["../../src/tools/find-comments.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAuBvB,QAAA,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4BA2J++P,CAAC;4BAA6C,CAAC;4BAA6C,CAAC;2BAA4C,CAAC;gCAAiD,CAAC;+BAAgD,CAAC;yBAA2D,CAAC;8BAA+C,CAAC;+BAAgD,CAAC;uBAAwC,CAAC;yBAA0C,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;CArFr7Q,CAAA;AAoF1C,OAAO,EAAE,YAAY,EAAE,CAAA"}
@@ -3,6 +3,8 @@ declare const findCompletedTasks: {
3
3
  name: "find-completed-tasks";
4
4
  description: string;
5
5
  parameters: {
6
+ labels: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
7
+ labelsOperator: z.ZodOptional<z.ZodEnum<["and", "or"]>>;
6
8
  getBy: z.ZodDefault<z.ZodEnum<["completion", "due"]>>;
7
9
  since: z.ZodString;
8
10
  until: z.ZodString;
@@ -15,14 +17,16 @@ declare const findCompletedTasks: {
15
17
  };
16
18
  execute(args: {
17
19
  limit: number;
18
- getBy: "completion" | "due";
20
+ getBy: "due" | "completion";
19
21
  since: string;
20
22
  until: string;
23
+ projectId?: string | undefined;
21
24
  parentId?: string | undefined;
22
25
  workspaceId?: string | undefined;
23
- projectId?: string | undefined;
24
26
  sectionId?: string | undefined;
27
+ labels?: string[] | undefined;
25
28
  cursor?: string | undefined;
29
+ labelsOperator?: "and" | "or" | undefined;
26
30
  }, client: import("@doist/todoist-api-typescript").TodoistApi): Promise<{
27
31
  content: {
28
32
  type: "text";
@@ -41,20 +45,24 @@ declare const findCompletedTasks: {
41
45
  parentId: string | null;
42
46
  labels: string[];
43
47
  duration: string | null;
48
+ responsibleUid: string | null;
49
+ assignedByUid: string | null;
44
50
  }[];
45
51
  nextCursor: string | null;
46
52
  totalCount: number;
47
53
  hasMore: boolean;
48
54
  appliedFilters: {
49
55
  limit: number;
50
- getBy: "completion" | "due";
56
+ getBy: "due" | "completion";
51
57
  since: string;
52
58
  until: string;
59
+ projectId?: string | undefined;
53
60
  parentId?: string | undefined;
54
61
  workspaceId?: string | undefined;
55
- projectId?: string | undefined;
56
62
  sectionId?: string | undefined;
63
+ labels?: string[] | undefined;
57
64
  cursor?: string | undefined;
65
+ labelsOperator?: "and" | "or" | undefined;
58
66
  };
59
67
  };
60
68
  } | {
@@ -1 +1 @@
1
- {"version":3,"file":"find-completed-tasks.d.ts","sourceRoot":"","sources":["../../src/tools/find-completed-tasks.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AA8CvB,QAAA,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6BkB,CAAA;AA2D1C,OAAO,EAAE,kBAAkB,EAAE,CAAA"}
1
+ {"version":3,"file":"find-completed-tasks.d.ts","sourceRoot":"","sources":["../../src/tools/find-completed-tasks.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAiDvB,QAAA,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAoCkB,CAAA;AAmE1C,OAAO,EAAE,kBAAkB,EAAE,CAAA"}