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