@doist/todoist-ai 4.16.0 → 4.16.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 (167) hide show
  1. package/dist/filter-helpers.d.ts +1 -1
  2. package/dist/index.d.ts +175 -175
  3. package/dist/index.js +61 -81
  4. package/dist/main.js +15 -23
  5. package/dist/mcp-helpers.d.ts +4 -4
  6. package/dist/mcp-server-6tm7Rhyz.js +2840 -0
  7. package/dist/todoist-tool.d.ts +2 -2
  8. package/dist/tool-helpers.d.ts +1 -1
  9. package/dist/tools/add-comments.d.ts +1 -1
  10. package/dist/tools/add-comments.d.ts.map +1 -1
  11. package/dist/tools/add-projects.d.ts +4 -4
  12. package/dist/tools/add-projects.d.ts.map +1 -1
  13. package/dist/tools/add-sections.d.ts +1 -1
  14. package/dist/tools/add-sections.d.ts.map +1 -1
  15. package/dist/tools/add-tasks.d.ts +4 -4
  16. package/dist/tools/add-tasks.d.ts.map +1 -1
  17. package/dist/tools/complete-tasks.d.ts +1 -1
  18. package/dist/tools/complete-tasks.d.ts.map +1 -1
  19. package/dist/tools/delete-object.d.ts +3 -3
  20. package/dist/tools/delete-object.d.ts.map +1 -1
  21. package/dist/tools/fetch.d.ts +1 -1
  22. package/dist/tools/find-activity.d.ts +5 -5
  23. package/dist/tools/find-activity.d.ts.map +1 -1
  24. package/dist/tools/find-comments.d.ts +2 -2
  25. package/dist/tools/find-comments.d.ts.map +1 -1
  26. package/dist/tools/find-completed-tasks.d.ts +3 -3
  27. package/dist/tools/find-completed-tasks.d.ts.map +1 -1
  28. package/dist/tools/find-project-collaborators.d.ts +2 -2
  29. package/dist/tools/find-projects.d.ts +1 -1
  30. package/dist/tools/find-projects.d.ts.map +1 -1
  31. package/dist/tools/find-sections.d.ts +1 -1
  32. package/dist/tools/find-sections.d.ts.map +1 -1
  33. package/dist/tools/find-tasks-by-date.d.ts +1 -1
  34. package/dist/tools/find-tasks-by-date.d.ts.map +1 -1
  35. package/dist/tools/find-tasks.d.ts +3 -3
  36. package/dist/tools/find-tasks.d.ts.map +1 -1
  37. package/dist/tools/get-overview.d.ts +1 -1
  38. package/dist/tools/manage-assignments.d.ts +1 -1
  39. package/dist/tools/search.d.ts +1 -1
  40. package/dist/tools/update-comments.d.ts +4 -4
  41. package/dist/tools/update-comments.d.ts.map +1 -1
  42. package/dist/tools/update-projects.d.ts +1 -1
  43. package/dist/tools/update-projects.d.ts.map +1 -1
  44. package/dist/tools/update-sections.d.ts +4 -4
  45. package/dist/tools/update-sections.d.ts.map +1 -1
  46. package/dist/tools/update-tasks.d.ts +7 -7
  47. package/dist/tools/update-tasks.d.ts.map +1 -1
  48. package/dist/tools/user-info.d.ts +1 -1
  49. package/dist/utils/assignment-validator.d.ts +2 -2
  50. package/dist/utils/response-builders.d.ts +1 -3
  51. package/dist/utils/response-builders.d.ts.map +1 -1
  52. package/dist/utils/test-helpers.d.ts +1 -1
  53. package/dist/utils/user-resolver.d.ts +1 -1
  54. package/package.json +10 -8
  55. package/dist/filter-helpers.js +0 -79
  56. package/dist/mcp-helpers.js +0 -71
  57. package/dist/mcp-server.js +0 -142
  58. package/dist/todoist-tool.js +0 -1
  59. package/dist/tool-helpers.js +0 -125
  60. package/dist/tool-helpers.test.d.ts +0 -2
  61. package/dist/tool-helpers.test.d.ts.map +0 -1
  62. package/dist/tool-helpers.test.js +0 -223
  63. package/dist/tools/__tests__/add-comments.test.d.ts +0 -2
  64. package/dist/tools/__tests__/add-comments.test.d.ts.map +0 -1
  65. package/dist/tools/__tests__/add-comments.test.js +0 -241
  66. package/dist/tools/__tests__/add-projects.test.d.ts +0 -2
  67. package/dist/tools/__tests__/add-projects.test.d.ts.map +0 -1
  68. package/dist/tools/__tests__/add-projects.test.js +0 -174
  69. package/dist/tools/__tests__/add-sections.test.d.ts +0 -2
  70. package/dist/tools/__tests__/add-sections.test.d.ts.map +0 -1
  71. package/dist/tools/__tests__/add-sections.test.js +0 -185
  72. package/dist/tools/__tests__/add-tasks.test.d.ts +0 -2
  73. package/dist/tools/__tests__/add-tasks.test.d.ts.map +0 -1
  74. package/dist/tools/__tests__/add-tasks.test.js +0 -606
  75. package/dist/tools/__tests__/assignment-integration.test.d.ts +0 -2
  76. package/dist/tools/__tests__/assignment-integration.test.d.ts.map +0 -1
  77. package/dist/tools/__tests__/assignment-integration.test.js +0 -428
  78. package/dist/tools/__tests__/complete-tasks.test.d.ts +0 -2
  79. package/dist/tools/__tests__/complete-tasks.test.d.ts.map +0 -1
  80. package/dist/tools/__tests__/complete-tasks.test.js +0 -206
  81. package/dist/tools/__tests__/delete-object.test.d.ts +0 -2
  82. package/dist/tools/__tests__/delete-object.test.d.ts.map +0 -1
  83. package/dist/tools/__tests__/delete-object.test.js +0 -110
  84. package/dist/tools/__tests__/fetch.test.d.ts +0 -2
  85. package/dist/tools/__tests__/fetch.test.d.ts.map +0 -1
  86. package/dist/tools/__tests__/fetch.test.js +0 -279
  87. package/dist/tools/__tests__/find-activity.test.d.ts +0 -2
  88. package/dist/tools/__tests__/find-activity.test.d.ts.map +0 -1
  89. package/dist/tools/__tests__/find-activity.test.js +0 -229
  90. package/dist/tools/__tests__/find-comments.test.d.ts +0 -2
  91. package/dist/tools/__tests__/find-comments.test.d.ts.map +0 -1
  92. package/dist/tools/__tests__/find-comments.test.js +0 -236
  93. package/dist/tools/__tests__/find-completed-tasks.test.d.ts +0 -2
  94. package/dist/tools/__tests__/find-completed-tasks.test.d.ts.map +0 -1
  95. package/dist/tools/__tests__/find-completed-tasks.test.js +0 -423
  96. package/dist/tools/__tests__/find-projects.test.d.ts +0 -2
  97. package/dist/tools/__tests__/find-projects.test.d.ts.map +0 -1
  98. package/dist/tools/__tests__/find-projects.test.js +0 -154
  99. package/dist/tools/__tests__/find-sections.test.d.ts +0 -2
  100. package/dist/tools/__tests__/find-sections.test.d.ts.map +0 -1
  101. package/dist/tools/__tests__/find-sections.test.js +0 -313
  102. package/dist/tools/__tests__/find-tasks-by-date.test.d.ts +0 -2
  103. package/dist/tools/__tests__/find-tasks-by-date.test.d.ts.map +0 -1
  104. package/dist/tools/__tests__/find-tasks-by-date.test.js +0 -528
  105. package/dist/tools/__tests__/find-tasks.test.d.ts +0 -2
  106. package/dist/tools/__tests__/find-tasks.test.d.ts.map +0 -1
  107. package/dist/tools/__tests__/find-tasks.test.js +0 -771
  108. package/dist/tools/__tests__/get-overview.test.d.ts +0 -2
  109. package/dist/tools/__tests__/get-overview.test.d.ts.map +0 -1
  110. package/dist/tools/__tests__/get-overview.test.js +0 -225
  111. package/dist/tools/__tests__/search.test.d.ts +0 -2
  112. package/dist/tools/__tests__/search.test.d.ts.map +0 -1
  113. package/dist/tools/__tests__/search.test.js +0 -206
  114. package/dist/tools/__tests__/update-comments.test.d.ts +0 -2
  115. package/dist/tools/__tests__/update-comments.test.d.ts.map +0 -1
  116. package/dist/tools/__tests__/update-comments.test.js +0 -294
  117. package/dist/tools/__tests__/update-projects.test.d.ts +0 -2
  118. package/dist/tools/__tests__/update-projects.test.d.ts.map +0 -1
  119. package/dist/tools/__tests__/update-projects.test.js +0 -217
  120. package/dist/tools/__tests__/update-sections.test.d.ts +0 -2
  121. package/dist/tools/__tests__/update-sections.test.d.ts.map +0 -1
  122. package/dist/tools/__tests__/update-sections.test.js +0 -169
  123. package/dist/tools/__tests__/update-tasks.test.d.ts +0 -2
  124. package/dist/tools/__tests__/update-tasks.test.d.ts.map +0 -1
  125. package/dist/tools/__tests__/update-tasks.test.js +0 -788
  126. package/dist/tools/__tests__/user-info.test.d.ts +0 -2
  127. package/dist/tools/__tests__/user-info.test.d.ts.map +0 -1
  128. package/dist/tools/__tests__/user-info.test.js +0 -139
  129. package/dist/tools/add-comments.js +0 -89
  130. package/dist/tools/add-projects.js +0 -63
  131. package/dist/tools/add-sections.js +0 -74
  132. package/dist/tools/add-tasks.js +0 -169
  133. package/dist/tools/complete-tasks.js +0 -68
  134. package/dist/tools/delete-object.js +0 -79
  135. package/dist/tools/fetch.js +0 -102
  136. package/dist/tools/find-activity.js +0 -221
  137. package/dist/tools/find-comments.js +0 -148
  138. package/dist/tools/find-completed-tasks.js +0 -168
  139. package/dist/tools/find-project-collaborators.js +0 -151
  140. package/dist/tools/find-projects.js +0 -101
  141. package/dist/tools/find-sections.js +0 -101
  142. package/dist/tools/find-tasks-by-date.js +0 -198
  143. package/dist/tools/find-tasks.js +0 -329
  144. package/dist/tools/get-overview.js +0 -249
  145. package/dist/tools/manage-assignments.js +0 -337
  146. package/dist/tools/search.js +0 -65
  147. package/dist/tools/update-comments.js +0 -82
  148. package/dist/tools/update-projects.js +0 -84
  149. package/dist/tools/update-sections.js +0 -70
  150. package/dist/tools/update-tasks.js +0 -179
  151. package/dist/tools/user-info.js +0 -142
  152. package/dist/utils/assignment-validator.js +0 -253
  153. package/dist/utils/constants.js +0 -45
  154. package/dist/utils/duration-parser.js +0 -96
  155. package/dist/utils/duration-parser.test.d.ts +0 -2
  156. package/dist/utils/duration-parser.test.d.ts.map +0 -1
  157. package/dist/utils/duration-parser.test.js +0 -147
  158. package/dist/utils/labels.js +0 -18
  159. package/dist/utils/priorities.js +0 -20
  160. package/dist/utils/response-builders.js +0 -210
  161. package/dist/utils/sanitize-data.js +0 -37
  162. package/dist/utils/sanitize-data.test.d.ts +0 -2
  163. package/dist/utils/sanitize-data.test.d.ts.map +0 -1
  164. package/dist/utils/sanitize-data.test.js +0 -93
  165. package/dist/utils/test-helpers.js +0 -237
  166. package/dist/utils/tool-names.js +0 -40
  167. package/dist/utils/user-resolver.js +0 -179
@@ -1,606 +0,0 @@
1
- import { jest } from '@jest/globals';
2
- import { createMockTask, createMockUser, extractStructuredContent, extractTextContent, TEST_IDS, TODAY, } from '../../utils/test-helpers.js';
3
- import { ToolNames } from '../../utils/tool-names.js';
4
- import { addTasks } from '../add-tasks.js';
5
- // Mock the Todoist API
6
- const mockTodoistApi = {
7
- addTask: jest.fn(),
8
- getUser: jest.fn(),
9
- };
10
- const { ADD_TASKS, GET_OVERVIEW } = ToolNames;
11
- describe(`${ADD_TASKS} tool`, () => {
12
- beforeEach(() => {
13
- jest.clearAllMocks();
14
- });
15
- describe('adding multiple tasks', () => {
16
- it('should add multiple tasks and return mapped results', async () => {
17
- // Mock API responses extracted from recordings (Task type)
18
- const mockApiResponse1 = createMockTask({
19
- id: '8485093748',
20
- content: 'First task content',
21
- url: 'https://todoist.com/showTask?id=8485093748',
22
- addedAt: '2025-08-13T22:09:56.123456Z',
23
- });
24
- const mockApiResponse2 = createMockTask({
25
- id: '8485093749',
26
- content: 'Second task content',
27
- description: 'Task description',
28
- labels: ['work', 'urgent'],
29
- childOrder: 2,
30
- priority: 2,
31
- url: 'https://todoist.com/showTask?id=8485093749',
32
- addedAt: '2025-08-13T22:09:57.123456Z',
33
- due: {
34
- date: '2025-08-15',
35
- isRecurring: false,
36
- lang: 'en',
37
- string: 'Aug 15',
38
- timezone: null,
39
- },
40
- });
41
- mockTodoistApi.addTask
42
- .mockResolvedValueOnce(mockApiResponse1)
43
- .mockResolvedValueOnce(mockApiResponse2);
44
- const result = await addTasks.execute({
45
- tasks: [
46
- {
47
- content: 'First task content',
48
- projectId: '6cfCcrrCFg2xP94Q',
49
- },
50
- {
51
- content: 'Second task content',
52
- description: 'Task description',
53
- priority: 'p2',
54
- dueString: 'Aug 15',
55
- projectId: '6cfCcrrCFg2xP94Q',
56
- },
57
- ],
58
- }, mockTodoistApi);
59
- // Verify API was called correctly for each task
60
- expect(mockTodoistApi.addTask).toHaveBeenCalledTimes(2);
61
- expect(mockTodoistApi.addTask).toHaveBeenNthCalledWith(1, {
62
- content: 'First task content',
63
- projectId: '6cfCcrrCFg2xP94Q',
64
- sectionId: undefined,
65
- parentId: undefined,
66
- });
67
- expect(mockTodoistApi.addTask).toHaveBeenNthCalledWith(2, {
68
- content: 'Second task content',
69
- description: 'Task description',
70
- priority: 3,
71
- dueString: 'Aug 15',
72
- projectId: '6cfCcrrCFg2xP94Q',
73
- sectionId: undefined,
74
- parentId: undefined,
75
- });
76
- // Verify result is a concise summary
77
- expect(extractTextContent(result)).toMatchSnapshot();
78
- // Verify structured content
79
- const structuredContent = extractStructuredContent(result);
80
- expect(structuredContent.tasks).toHaveLength(2);
81
- expect(structuredContent).toEqual(expect.objectContaining({
82
- totalCount: 2,
83
- tasks: expect.arrayContaining([
84
- expect.objectContaining({ id: '8485093748' }),
85
- expect.objectContaining({ id: '8485093749' }),
86
- ]),
87
- }));
88
- });
89
- it('should handle tasks with section and parent IDs', async () => {
90
- const mockApiResponse = createMockTask({
91
- id: '8485093750',
92
- content: 'Subtask content',
93
- description: 'Subtask description',
94
- priority: 3,
95
- sectionId: 'section-123',
96
- parentId: 'parent-task-456',
97
- url: 'https://todoist.com/showTask?id=8485093750',
98
- addedAt: '2025-08-13T22:09:58.123456Z',
99
- });
100
- mockTodoistApi.addTask.mockResolvedValue(mockApiResponse);
101
- const result = await addTasks.execute({
102
- tasks: [
103
- {
104
- content: 'Subtask content',
105
- description: 'Subtask description',
106
- priority: 'p3',
107
- projectId: '6cfCcrrCFg2xP94Q',
108
- sectionId: 'section-123',
109
- parentId: 'parent-task-456',
110
- },
111
- ],
112
- }, mockTodoistApi);
113
- expect(mockTodoistApi.addTask).toHaveBeenCalledWith({
114
- content: 'Subtask content',
115
- description: 'Subtask description',
116
- priority: 2,
117
- projectId: '6cfCcrrCFg2xP94Q',
118
- sectionId: 'section-123',
119
- parentId: 'parent-task-456',
120
- });
121
- // Verify result is a concise summary
122
- expect(extractTextContent(result)).toMatchSnapshot();
123
- // Verify structured content
124
- const structuredContent = extractStructuredContent(result);
125
- expect(structuredContent).toEqual(expect.objectContaining({
126
- totalCount: 1,
127
- tasks: expect.arrayContaining([expect.objectContaining({ id: '8485093750' })]),
128
- }));
129
- });
130
- it('should add tasks with duration', async () => {
131
- const mockApiResponse1 = createMockTask({
132
- id: '8485093752',
133
- content: 'Task with 2 hour duration',
134
- duration: { amount: 120, unit: 'minute' },
135
- url: 'https://todoist.com/showTask?id=8485093752',
136
- addedAt: '2025-08-13T22:09:56.123456Z',
137
- });
138
- const mockApiResponse2 = createMockTask({
139
- id: '8485093753',
140
- content: 'Task with 45 minute duration',
141
- duration: { amount: 45, unit: 'minute' },
142
- url: 'https://todoist.com/showTask?id=8485093753',
143
- addedAt: '2025-08-13T22:09:57.123456Z',
144
- });
145
- mockTodoistApi.addTask
146
- .mockResolvedValueOnce(mockApiResponse1)
147
- .mockResolvedValueOnce(mockApiResponse2);
148
- const result = await addTasks.execute({
149
- tasks: [
150
- {
151
- content: 'Task with 2 hour duration',
152
- duration: '2h',
153
- projectId: '6cfCcrrCFg2xP94Q',
154
- },
155
- {
156
- content: 'Task with 45 minute duration',
157
- duration: '45m',
158
- projectId: '6cfCcrrCFg2xP94Q',
159
- },
160
- ],
161
- }, mockTodoistApi);
162
- // Verify API was called with parsed duration
163
- expect(mockTodoistApi.addTask).toHaveBeenNthCalledWith(1, {
164
- content: 'Task with 2 hour duration',
165
- projectId: '6cfCcrrCFg2xP94Q',
166
- sectionId: undefined,
167
- parentId: undefined,
168
- duration: 120,
169
- durationUnit: 'minute',
170
- });
171
- expect(mockTodoistApi.addTask).toHaveBeenNthCalledWith(2, {
172
- content: 'Task with 45 minute duration',
173
- projectId: '6cfCcrrCFg2xP94Q',
174
- sectionId: undefined,
175
- parentId: undefined,
176
- duration: 45,
177
- durationUnit: 'minute',
178
- });
179
- // Verify result is a concise summary
180
- expect(extractTextContent(result)).toMatchSnapshot();
181
- // Verify structured content
182
- const structuredContent = extractStructuredContent(result);
183
- expect(structuredContent.tasks).toHaveLength(2);
184
- expect(structuredContent).toEqual(expect.objectContaining({
185
- totalCount: 2,
186
- tasks: expect.arrayContaining([
187
- expect.objectContaining({ id: '8485093752' }),
188
- expect.objectContaining({ id: '8485093753' }),
189
- ]),
190
- }));
191
- });
192
- it('should handle various duration formats', async () => {
193
- const mockApiResponse = createMockTask({
194
- id: '8485093754',
195
- content: 'Task with combined duration',
196
- duration: { amount: 150, unit: 'minute' },
197
- url: 'https://todoist.com/showTask?id=8485093754',
198
- addedAt: '2025-08-13T22:09:56.123456Z',
199
- });
200
- mockTodoistApi.addTask.mockResolvedValue(mockApiResponse);
201
- // Test different duration formats
202
- const testCases = [
203
- { input: '2h30m', expectedMinutes: 150 },
204
- { input: '1.5h', expectedMinutes: 90 },
205
- { input: ' 90m ', expectedMinutes: 90 },
206
- { input: '2H30M', expectedMinutes: 150 },
207
- ];
208
- for (const testCase of testCases) {
209
- mockTodoistApi.addTask.mockClear();
210
- await addTasks.execute({
211
- tasks: [
212
- {
213
- content: 'Test task',
214
- duration: testCase.input,
215
- projectId: '6cfCcrrCFg2xP94Q',
216
- },
217
- ],
218
- }, mockTodoistApi);
219
- expect(mockTodoistApi.addTask).toHaveBeenCalledWith(expect.objectContaining({
220
- duration: testCase.expectedMinutes,
221
- durationUnit: 'minute',
222
- }));
223
- }
224
- });
225
- it('should add task with deadline', async () => {
226
- const mockApiResponse = createMockTask({
227
- id: '8485093756',
228
- content: 'Task with deadline',
229
- deadline: {
230
- date: '2025-12-31',
231
- lang: 'en',
232
- },
233
- url: 'https://todoist.com/showTask?id=8485093756',
234
- addedAt: '2025-08-13T22:09:56.123456Z',
235
- });
236
- mockTodoistApi.addTask.mockResolvedValue(mockApiResponse);
237
- const result = await addTasks.execute({
238
- tasks: [
239
- {
240
- content: 'Task with deadline',
241
- projectId: '6cfCcrrCFg2xP94Q',
242
- deadlineDate: '2025-12-31',
243
- },
244
- ],
245
- }, mockTodoistApi);
246
- // Verify API was called with deadline
247
- expect(mockTodoistApi.addTask).toHaveBeenCalledWith({
248
- content: 'Task with deadline',
249
- projectId: '6cfCcrrCFg2xP94Q',
250
- sectionId: undefined,
251
- parentId: undefined,
252
- deadlineDate: '2025-12-31',
253
- });
254
- // Verify result is a concise summary
255
- expect(extractTextContent(result)).toMatchSnapshot();
256
- // Verify structured content includes deadline
257
- const structuredContent = extractStructuredContent(result);
258
- expect(structuredContent.tasks).toHaveLength(1);
259
- expect(structuredContent).toEqual(expect.objectContaining({
260
- totalCount: 1,
261
- tasks: expect.arrayContaining([
262
- expect.objectContaining({
263
- id: '8485093756',
264
- deadlineDate: '2025-12-31',
265
- }),
266
- ]),
267
- }));
268
- });
269
- it('should add task with labels', async () => {
270
- const mockApiResponse = createMockTask({
271
- id: '8485093755',
272
- content: 'Task with labels',
273
- labels: ['urgent', 'work'],
274
- url: 'https://todoist.com/showTask?id=8485093755',
275
- addedAt: '2025-08-13T22:09:56.123456Z',
276
- });
277
- mockTodoistApi.addTask.mockResolvedValue(mockApiResponse);
278
- const result = await addTasks.execute({
279
- tasks: [
280
- {
281
- content: 'Task with labels',
282
- labels: ['urgent', 'work'],
283
- projectId: '6cfCcrrCFg2xP94Q',
284
- },
285
- ],
286
- }, mockTodoistApi);
287
- expect(mockTodoistApi.addTask).toHaveBeenCalledWith({
288
- content: 'Task with labels',
289
- labels: ['urgent', 'work'],
290
- projectId: '6cfCcrrCFg2xP94Q',
291
- sectionId: undefined,
292
- parentId: undefined,
293
- });
294
- // Verify structured content includes labels
295
- const structuredContent = extractStructuredContent(result);
296
- expect(structuredContent.tasks).toHaveLength(1);
297
- expect(structuredContent.tasks).toEqual(expect.arrayContaining([expect.objectContaining({ labels: ['urgent', 'work'] })]));
298
- });
299
- it('should add task with empty labels array', async () => {
300
- const mockApiResponse = createMockTask({
301
- id: '8485093756',
302
- content: 'Task with empty labels',
303
- labels: [],
304
- url: 'https://todoist.com/showTask?id=8485093756',
305
- addedAt: '2025-08-13T22:09:56.123456Z',
306
- });
307
- mockTodoistApi.addTask.mockResolvedValue(mockApiResponse);
308
- await addTasks.execute({
309
- tasks: [
310
- {
311
- content: 'Task with empty labels',
312
- labels: [],
313
- projectId: '6cfCcrrCFg2xP94Q',
314
- },
315
- ],
316
- }, mockTodoistApi);
317
- expect(mockTodoistApi.addTask).toHaveBeenCalledWith({
318
- content: 'Task with empty labels',
319
- labels: [],
320
- projectId: '6cfCcrrCFg2xP94Q',
321
- sectionId: undefined,
322
- parentId: undefined,
323
- });
324
- });
325
- it('should add task without labels field', async () => {
326
- const mockApiResponse = createMockTask({
327
- id: '8485093757',
328
- content: 'Task without labels',
329
- url: 'https://todoist.com/showTask?id=8485093757',
330
- addedAt: '2025-08-13T22:09:56.123456Z',
331
- });
332
- mockTodoistApi.addTask.mockResolvedValue(mockApiResponse);
333
- await addTasks.execute({
334
- tasks: [
335
- {
336
- content: 'Task without labels',
337
- projectId: '6cfCcrrCFg2xP94Q',
338
- },
339
- ],
340
- }, mockTodoistApi);
341
- expect(mockTodoistApi.addTask).toHaveBeenCalledWith({
342
- content: 'Task without labels',
343
- labels: undefined,
344
- projectId: '6cfCcrrCFg2xP94Q',
345
- sectionId: undefined,
346
- parentId: undefined,
347
- });
348
- });
349
- it('should add multiple tasks with different label configurations', async () => {
350
- const mockApiResponse1 = createMockTask({
351
- id: '8485093758',
352
- content: 'Task with labels',
353
- labels: ['personal'],
354
- });
355
- const mockApiResponse2 = createMockTask({
356
- id: '8485093759',
357
- content: 'Task without labels',
358
- });
359
- const mockApiResponse3 = createMockTask({
360
- id: '8485093760',
361
- content: 'Task with multiple labels',
362
- labels: ['work', 'urgent', 'review'],
363
- });
364
- mockTodoistApi.addTask
365
- .mockResolvedValueOnce(mockApiResponse1)
366
- .mockResolvedValueOnce(mockApiResponse2)
367
- .mockResolvedValueOnce(mockApiResponse3);
368
- await addTasks.execute({
369
- tasks: [
370
- {
371
- content: 'Task with labels',
372
- labels: ['personal'],
373
- projectId: '6cfCcrrCFg2xP94Q',
374
- },
375
- {
376
- content: 'Task without labels',
377
- projectId: '6cfCcrrCFg2xP94Q',
378
- },
379
- {
380
- content: 'Task with multiple labels',
381
- labels: ['work', 'urgent', 'review'],
382
- projectId: '6cfCcrrCFg2xP94Q',
383
- },
384
- ],
385
- }, mockTodoistApi);
386
- expect(mockTodoistApi.addTask).toHaveBeenCalledTimes(3);
387
- expect(mockTodoistApi.addTask).toHaveBeenNthCalledWith(1, expect.objectContaining({
388
- labels: ['personal'],
389
- }));
390
- expect(mockTodoistApi.addTask).toHaveBeenNthCalledWith(2, expect.objectContaining({
391
- labels: undefined,
392
- }));
393
- expect(mockTodoistApi.addTask).toHaveBeenNthCalledWith(3, expect.objectContaining({
394
- labels: ['work', 'urgent', 'review'],
395
- }));
396
- });
397
- });
398
- describe('error handling', () => {
399
- it('should throw error for invalid duration format', async () => {
400
- await expect(addTasks.execute({
401
- tasks: [
402
- {
403
- content: 'Task with invalid duration',
404
- duration: 'invalid',
405
- projectId: '6cfCcrrCFg2xP94Q',
406
- },
407
- ],
408
- }, mockTodoistApi)).rejects.toThrow('Task "Task with invalid duration": Invalid duration format "invalid"');
409
- });
410
- it('should throw error for duration exceeding 24 hours', async () => {
411
- await expect(addTasks.execute({
412
- tasks: [
413
- {
414
- content: 'Task with too long duration',
415
- duration: '25h',
416
- projectId: '6cfCcrrCFg2xP94Q',
417
- },
418
- ],
419
- }, mockTodoistApi)).rejects.toThrow('Task "Task with too long duration": Invalid duration format "25h": Duration cannot exceed 24 hours (1440 minutes)');
420
- });
421
- it('should propagate API errors', async () => {
422
- const apiError = new Error('API Error: Task content is required');
423
- mockTodoistApi.addTask.mockRejectedValue(apiError);
424
- await expect(addTasks.execute({ tasks: [{ content: '', projectId: '6cfCcrrCFg2xP94Q' }] }, mockTodoistApi)).rejects.toThrow(apiError.message);
425
- });
426
- it('should handle partial failures when adding multiple tasks', async () => {
427
- const mockApiResponse = createMockTask({
428
- id: '8485093751',
429
- content: 'First task content',
430
- url: 'https://todoist.com/showTask?id=8485093751',
431
- addedAt: '2025-08-13T22:09:59.123456Z',
432
- });
433
- const apiError = new Error('API Error: Second task failed');
434
- mockTodoistApi.addTask
435
- .mockResolvedValueOnce(mockApiResponse)
436
- .mockRejectedValueOnce(apiError);
437
- await expect(addTasks.execute({
438
- tasks: [
439
- { content: 'First task content', projectId: '6cfCcrrCFg2xP94Q' },
440
- { content: 'Second task content', projectId: '6cfCcrrCFg2xP94Q' },
441
- ],
442
- }, mockTodoistApi)).rejects.toThrow('API Error: Second task failed');
443
- // Verify first task was attempted
444
- expect(mockTodoistApi.addTask).toHaveBeenCalledTimes(2);
445
- });
446
- });
447
- describe('next steps logic', () => {
448
- it('should suggest find-tasks-by-date for today when hasToday is true', async () => {
449
- // Clear any leftover mocks from previous tests
450
- mockTodoistApi.addTask.mockClear();
451
- const mockApiResponse = createMockTask({
452
- id: '8485093755',
453
- content: 'Task due today',
454
- url: 'https://todoist.com/showTask?id=8485093755',
455
- addedAt: '2025-08-13T22:09:56.123456Z',
456
- due: {
457
- date: TODAY,
458
- isRecurring: false,
459
- lang: 'en',
460
- string: 'today',
461
- timezone: null,
462
- },
463
- });
464
- mockTodoistApi.addTask.mockResolvedValue(mockApiResponse);
465
- const result = await addTasks.execute({
466
- tasks: [
467
- {
468
- content: 'Task due today',
469
- dueString: 'today',
470
- projectId: '6cfCcrrCFg2xP94Q',
471
- },
472
- ],
473
- }, mockTodoistApi);
474
- const textContent = extractTextContent(result);
475
- expect(textContent).toMatchSnapshot();
476
- expect(textContent).toContain(`Use ${GET_OVERVIEW} to see your updated project organization`);
477
- });
478
- it('should suggest overview tool when no hasToday context', async () => {
479
- // Clear any leftover mocks from previous tests
480
- mockTodoistApi.addTask.mockClear();
481
- const mockApiResponse = createMockTask({
482
- id: '8485093756',
483
- content: 'Regular task',
484
- url: 'https://todoist.com/showTask?id=8485093756',
485
- addedAt: '2025-08-13T22:09:56.123456Z',
486
- });
487
- mockTodoistApi.addTask.mockResolvedValue(mockApiResponse);
488
- const result = await addTasks.execute({
489
- tasks: [{ content: 'Regular task', projectId: '6cfCcrrCFg2xP94Q' }],
490
- }, mockTodoistApi);
491
- const textContent = extractTextContent(result);
492
- expect(textContent).toMatchSnapshot();
493
- expect(textContent).toContain(`Use ${GET_OVERVIEW} to see your updated project organization`);
494
- });
495
- });
496
- describe('tasks without project context', () => {
497
- it('should allow creating tasks with only content (goes to Inbox)', async () => {
498
- const mockApiResponse = createMockTask({
499
- id: '8485093758',
500
- content: 'Simple inbox task',
501
- url: 'https://todoist.com/showTask?id=8485093758',
502
- addedAt: '2025-08-13T22:09:56.123456Z',
503
- });
504
- mockTodoistApi.addTask.mockResolvedValue(mockApiResponse);
505
- const result = await addTasks.execute({
506
- tasks: [
507
- {
508
- content: 'Simple inbox task',
509
- },
510
- ],
511
- }, mockTodoistApi);
512
- expect(mockTodoistApi.addTask).toHaveBeenCalledWith({
513
- content: 'Simple inbox task',
514
- labels: undefined,
515
- projectId: undefined,
516
- sectionId: undefined,
517
- parentId: undefined,
518
- });
519
- const textContent = extractTextContent(result);
520
- expect(textContent).toContain('Added 1 task');
521
- expect(textContent).toContain('Simple inbox task');
522
- });
523
- it('should prevent assignment without project context', async () => {
524
- await expect(addTasks.execute({
525
- tasks: [
526
- {
527
- content: 'Task with assignment but no project',
528
- responsibleUser: 'user@example.com',
529
- },
530
- ],
531
- }, mockTodoistApi)).rejects.toThrow('Task "Task with assignment but no project": Cannot assign tasks without specifying project context. Please specify a projectId, sectionId, or parentId.');
532
- });
533
- });
534
- describe('inbox project ID resolution', () => {
535
- it('should resolve "inbox" to actual inbox project ID', async () => {
536
- const mockUser = createMockUser({
537
- inboxProjectId: TEST_IDS.PROJECT_INBOX,
538
- });
539
- const mockApiResponse = createMockTask({
540
- id: '8485093760',
541
- content: 'Task for inbox',
542
- projectId: TEST_IDS.PROJECT_INBOX,
543
- url: 'https://todoist.com/showTask?id=8485093760',
544
- addedAt: '2025-08-13T22:09:56.123456Z',
545
- });
546
- // Mock the API calls
547
- mockTodoistApi.getUser.mockResolvedValue(mockUser);
548
- mockTodoistApi.addTask.mockResolvedValue(mockApiResponse);
549
- const result = await addTasks.execute({
550
- tasks: [
551
- {
552
- content: 'Task for inbox',
553
- projectId: 'inbox',
554
- },
555
- ],
556
- }, mockTodoistApi);
557
- // Verify getUser was called to resolve inbox
558
- expect(mockTodoistApi.getUser).toHaveBeenCalledTimes(1);
559
- // Verify addTask was called with resolved inbox project ID
560
- expect(mockTodoistApi.addTask).toHaveBeenCalledWith({
561
- content: 'Task for inbox',
562
- projectId: TEST_IDS.PROJECT_INBOX,
563
- sectionId: undefined,
564
- parentId: undefined,
565
- labels: undefined,
566
- });
567
- // Verify result contains the task
568
- const structuredContent = extractStructuredContent(result);
569
- expect(structuredContent.totalCount).toBe(1);
570
- expect(structuredContent.tasks).toEqual(expect.arrayContaining([
571
- expect.objectContaining({
572
- id: '8485093760',
573
- projectId: TEST_IDS.PROJECT_INBOX,
574
- }),
575
- ]));
576
- });
577
- it('should not call getUser when projectId is not "inbox"', async () => {
578
- const mockApiResponse = createMockTask({
579
- id: '8485093761',
580
- content: 'Regular task',
581
- projectId: '6cfCcrrCFg2xP94Q',
582
- url: 'https://todoist.com/showTask?id=8485093761',
583
- addedAt: '2025-08-13T22:09:56.123456Z',
584
- });
585
- mockTodoistApi.addTask.mockResolvedValue(mockApiResponse);
586
- await addTasks.execute({
587
- tasks: [
588
- {
589
- content: 'Regular task',
590
- projectId: '6cfCcrrCFg2xP94Q',
591
- },
592
- ],
593
- }, mockTodoistApi);
594
- // Verify getUser was NOT called for regular project ID
595
- expect(mockTodoistApi.getUser).not.toHaveBeenCalled();
596
- // Verify addTask was called with original project ID
597
- expect(mockTodoistApi.addTask).toHaveBeenCalledWith({
598
- content: 'Regular task',
599
- projectId: '6cfCcrrCFg2xP94Q',
600
- sectionId: undefined,
601
- parentId: undefined,
602
- labels: undefined,
603
- });
604
- });
605
- });
606
- });
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=assignment-integration.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"assignment-integration.test.d.ts","sourceRoot":"","sources":["../../../src/tools/__tests__/assignment-integration.test.ts"],"names":[],"mappings":""}