@doist/todoist-ai 4.14.5 → 4.15.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/README.md +16 -2
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/mcp-server.js +2 -2
- package/dist/tool-helpers.d.ts +2 -0
- package/dist/tool-helpers.d.ts.map +1 -1
- package/dist/tool-helpers.js +1 -0
- package/dist/tools/__tests__/add-tasks.test.js +44 -0
- package/dist/tools/__tests__/update-tasks.test.js +67 -0
- package/dist/tools/add-tasks.d.ts +5 -0
- package/dist/tools/add-tasks.d.ts.map +1 -1
- package/dist/tools/add-tasks.js +13 -2
- package/dist/tools/find-activity.js +1 -1
- package/dist/tools/find-completed-tasks.d.ts +1 -0
- package/dist/tools/find-completed-tasks.d.ts.map +1 -1
- package/dist/tools/find-tasks-by-date.d.ts +1 -0
- package/dist/tools/find-tasks-by-date.d.ts.map +1 -1
- package/dist/tools/find-tasks.d.ts +1 -0
- package/dist/tools/find-tasks.d.ts.map +1 -1
- package/dist/tools/find-tasks.js +8 -3
- package/dist/tools/update-tasks.d.ts +5 -0
- package/dist/tools/update-tasks.d.ts.map +1 -1
- package/dist/tools/update-tasks.js +16 -1
- package/dist/utils/test-helpers.d.ts +1 -0
- package/dist/utils/test-helpers.d.ts.map +1 -1
- package/dist/utils/test-helpers.js +1 -0
- package/package.json +14 -4
- package/scripts/validate-schemas.ts +280 -0
package/README.md
CHANGED
|
@@ -20,14 +20,28 @@ Here's an example using [Vercel's AI SDK](https://ai-sdk.dev/docs/ai-sdk-core/ge
|
|
|
20
20
|
|
|
21
21
|
```js
|
|
22
22
|
import { findTasksByDate, addTasks } from "@doist/todoist-ai";
|
|
23
|
+
import { TodoistApi } from "@doist/todoist-api-typescript";
|
|
23
24
|
import { streamText } from "ai";
|
|
24
25
|
|
|
26
|
+
// Create Todoist API client
|
|
27
|
+
const client = new TodoistApi(process.env.TODOIST_API_KEY);
|
|
28
|
+
|
|
29
|
+
// Helper to wrap tools with the client
|
|
30
|
+
function wrapTool(tool, todoistClient) {
|
|
31
|
+
return {
|
|
32
|
+
...tool,
|
|
33
|
+
execute(args) {
|
|
34
|
+
return tool.execute(args, todoistClient);
|
|
35
|
+
},
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
|
|
25
39
|
const result = streamText({
|
|
26
40
|
model: yourModel,
|
|
27
41
|
system: "You are a helpful Todoist assistant",
|
|
28
42
|
tools: {
|
|
29
|
-
findTasksByDate,
|
|
30
|
-
addTasks,
|
|
43
|
+
findTasksByDate: wrapTool(findTasksByDate, client),
|
|
44
|
+
addTasks: wrapTool(addTasks, client),
|
|
31
45
|
},
|
|
32
46
|
});
|
|
33
47
|
```
|
package/dist/index.d.ts
CHANGED
|
@@ -32,6 +32,7 @@ declare const tools: {
|
|
|
32
32
|
description: import("zod").ZodOptional<import("zod").ZodString>;
|
|
33
33
|
priority: import("zod").ZodOptional<import("zod").ZodEnum<["p1", "p2", "p3", "p4"]>>;
|
|
34
34
|
dueString: import("zod").ZodOptional<import("zod").ZodString>;
|
|
35
|
+
deadlineDate: import("zod").ZodOptional<import("zod").ZodString>;
|
|
35
36
|
duration: import("zod").ZodOptional<import("zod").ZodString>;
|
|
36
37
|
labels: import("zod").ZodOptional<import("zod").ZodArray<import("zod").ZodString, "many">>;
|
|
37
38
|
projectId: import("zod").ZodOptional<import("zod").ZodString>;
|
|
@@ -48,6 +49,7 @@ declare const tools: {
|
|
|
48
49
|
duration?: string | undefined;
|
|
49
50
|
priority?: "p1" | "p2" | "p3" | "p4" | undefined;
|
|
50
51
|
dueString?: string | undefined;
|
|
52
|
+
deadlineDate?: string | undefined;
|
|
51
53
|
responsibleUser?: string | undefined;
|
|
52
54
|
}, {
|
|
53
55
|
content: string;
|
|
@@ -59,6 +61,7 @@ declare const tools: {
|
|
|
59
61
|
duration?: string | undefined;
|
|
60
62
|
priority?: "p1" | "p2" | "p3" | "p4" | undefined;
|
|
61
63
|
dueString?: string | undefined;
|
|
64
|
+
deadlineDate?: string | undefined;
|
|
62
65
|
responsibleUser?: string | undefined;
|
|
63
66
|
}>, "many">;
|
|
64
67
|
};
|
|
@@ -73,6 +76,7 @@ declare const tools: {
|
|
|
73
76
|
duration?: string | undefined;
|
|
74
77
|
priority?: "p1" | "p2" | "p3" | "p4" | undefined;
|
|
75
78
|
dueString?: string | undefined;
|
|
79
|
+
deadlineDate?: string | undefined;
|
|
76
80
|
responsibleUser?: string | undefined;
|
|
77
81
|
}[];
|
|
78
82
|
}, client: import("@doist/todoist-api-typescript").TodoistApi): Promise<{
|
|
@@ -87,6 +91,7 @@ declare const tools: {
|
|
|
87
91
|
description: string;
|
|
88
92
|
dueDate: string | undefined;
|
|
89
93
|
recurring: string | boolean;
|
|
94
|
+
deadlineDate: string | undefined;
|
|
90
95
|
priority: number;
|
|
91
96
|
projectId: string;
|
|
92
97
|
sectionId: string | null;
|
|
@@ -164,6 +169,7 @@ declare const tools: {
|
|
|
164
169
|
order: import("zod").ZodOptional<import("zod").ZodNumber>;
|
|
165
170
|
priority: import("zod").ZodOptional<import("zod").ZodEnum<["p1", "p2", "p3", "p4"]>>;
|
|
166
171
|
dueString: import("zod").ZodOptional<import("zod").ZodString>;
|
|
172
|
+
deadlineDate: import("zod").ZodOptional<import("zod").ZodString>;
|
|
167
173
|
duration: import("zod").ZodOptional<import("zod").ZodString>;
|
|
168
174
|
responsibleUser: import("zod").ZodOptional<import("zod").ZodString>;
|
|
169
175
|
labels: import("zod").ZodOptional<import("zod").ZodArray<import("zod").ZodString, "many">>;
|
|
@@ -178,6 +184,7 @@ declare const tools: {
|
|
|
178
184
|
duration?: string | undefined;
|
|
179
185
|
priority?: "p1" | "p2" | "p3" | "p4" | undefined;
|
|
180
186
|
dueString?: string | undefined;
|
|
187
|
+
deadlineDate?: string | undefined;
|
|
181
188
|
responsibleUser?: string | undefined;
|
|
182
189
|
order?: number | undefined;
|
|
183
190
|
}, {
|
|
@@ -191,6 +198,7 @@ declare const tools: {
|
|
|
191
198
|
duration?: string | undefined;
|
|
192
199
|
priority?: "p1" | "p2" | "p3" | "p4" | undefined;
|
|
193
200
|
dueString?: string | undefined;
|
|
201
|
+
deadlineDate?: string | undefined;
|
|
194
202
|
responsibleUser?: string | undefined;
|
|
195
203
|
order?: number | undefined;
|
|
196
204
|
}>, "many">;
|
|
@@ -207,6 +215,7 @@ declare const tools: {
|
|
|
207
215
|
duration?: string | undefined;
|
|
208
216
|
priority?: "p1" | "p2" | "p3" | "p4" | undefined;
|
|
209
217
|
dueString?: string | undefined;
|
|
218
|
+
deadlineDate?: string | undefined;
|
|
210
219
|
responsibleUser?: string | undefined;
|
|
211
220
|
order?: number | undefined;
|
|
212
221
|
}[];
|
|
@@ -222,6 +231,7 @@ declare const tools: {
|
|
|
222
231
|
description: string;
|
|
223
232
|
dueDate: string | undefined;
|
|
224
233
|
recurring: string | boolean;
|
|
234
|
+
deadlineDate: string | undefined;
|
|
225
235
|
priority: number;
|
|
226
236
|
projectId: string;
|
|
227
237
|
sectionId: string | null;
|
|
@@ -291,6 +301,7 @@ declare const tools: {
|
|
|
291
301
|
description: string;
|
|
292
302
|
dueDate: string | undefined;
|
|
293
303
|
recurring: string | boolean;
|
|
304
|
+
deadlineDate: string | undefined;
|
|
294
305
|
priority: number;
|
|
295
306
|
projectId: string;
|
|
296
307
|
sectionId: string | null;
|
|
@@ -367,6 +378,7 @@ declare const tools: {
|
|
|
367
378
|
description: string;
|
|
368
379
|
dueDate: string | undefined;
|
|
369
380
|
recurring: string | boolean;
|
|
381
|
+
deadlineDate: string | undefined;
|
|
370
382
|
priority: number;
|
|
371
383
|
projectId: string;
|
|
372
384
|
sectionId: string | null;
|
|
@@ -448,6 +460,7 @@ declare const tools: {
|
|
|
448
460
|
description: string;
|
|
449
461
|
dueDate: string | undefined;
|
|
450
462
|
recurring: string | boolean;
|
|
463
|
+
deadlineDate: string | undefined;
|
|
451
464
|
priority: number;
|
|
452
465
|
projectId: string;
|
|
453
466
|
sectionId: string | null;
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAA;AAE9C,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAA;AAErD,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAA;AAErD,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAA;AAErD,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAA;AAC/C,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAA;AAEzD,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAA;AACvD,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAA;AAExC,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAA;AACvD,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAA;AACvD,OAAO,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAA;AAEpE,OAAO,EAAE,wBAAwB,EAAE,MAAM,uCAAuC,CAAA;AAChF,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAA;AACvD,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAA;AACvD,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAA;AACjD,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAA;AAC/D,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAA;AACrD,OAAO,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAA;AACjE,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAA;AAC1C,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAA;AAC3D,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAA;AAC3D,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAA;AAC3D,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAA;AACrD,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAA;AAE/C,QAAA,MAAM,KAAK
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/mcp-server.js
CHANGED
|
@@ -39,8 +39,8 @@ You have access to comprehensive Todoist management tools for personal productiv
|
|
|
39
39
|
### Tool Usage Guidelines:
|
|
40
40
|
|
|
41
41
|
**Task Management:**
|
|
42
|
-
- **add-tasks**: Create tasks with content, description, priority (p1=highest, p2=high, p3=medium, p4=lowest/default), dueString (natural language like "tomorrow", "next Friday", "2024-12-25"), duration (formats like "2h", "90m", "2h30m"), and assignments to project collaborators
|
|
43
|
-
- **update-tasks**: Modify existing tasks - get task IDs from search results first, only include fields that need changes
|
|
42
|
+
- **add-tasks**: Create tasks with content, description, priority (p1=highest, p2=high, p3=medium, p4=lowest/default), dueString (natural language like "tomorrow", "next Friday", "2024-12-25"), deadlineDate (ISO 8601 format like "2025-12-31" for immovable constraints), duration (formats like "2h", "90m", "2h30m"), and assignments to project collaborators
|
|
43
|
+
- **update-tasks**: Modify existing tasks - get task IDs from search results first, only include fields that need changes. Supports deadlineDate (ISO 8601 format like "2025-12-31") updates and removals (use "remove" to clear)
|
|
44
44
|
- **complete-tasks**: Mark tasks as done using task IDs
|
|
45
45
|
- **find-tasks**: Search by text, project/section/parent container, responsible user, or labels. Requires at least one search parameter
|
|
46
46
|
- **find-tasks-by-date**: Get tasks by date range (startDate: YYYY-MM-DD or 'today' which includes overdue tasks) or specific day counts
|
package/dist/tool-helpers.d.ts
CHANGED
|
@@ -24,6 +24,7 @@ declare function mapTask(task: Task): {
|
|
|
24
24
|
description: string;
|
|
25
25
|
dueDate: string | undefined;
|
|
26
26
|
recurring: string | boolean;
|
|
27
|
+
deadlineDate: string | undefined;
|
|
27
28
|
priority: number;
|
|
28
29
|
projectId: string;
|
|
29
30
|
sectionId: string | null;
|
|
@@ -78,6 +79,7 @@ declare function getTasksByFilter({ client, query, limit, cursor, }: {
|
|
|
78
79
|
description: string;
|
|
79
80
|
dueDate: string | undefined;
|
|
80
81
|
recurring: string | boolean;
|
|
82
|
+
deadlineDate: string | undefined;
|
|
81
83
|
priority: number;
|
|
82
84
|
projectId: string;
|
|
83
85
|
sectionId: string | null;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tool-helpers.d.ts","sourceRoot":"","sources":["../src/tool-helpers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACR,aAAa,EACb,YAAY,EACZ,eAAe,EACf,IAAI,EACJ,UAAU,EACV,gBAAgB,EACnB,MAAM,+BAA+B,CAAA;AAKtC,OAAO,EACH,aAAa,EACb,+BAA+B,EAC/B,4BAA4B,EAC5B,0BAA0B,EAC1B,KAAK,wBAAwB,EAC7B,sBAAsB,GACzB,MAAM,qBAAqB,CAAA;AAE5B,MAAM,MAAM,OAAO,GAAG,eAAe,GAAG,gBAAgB,CAAA;AAExD,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,IAAI,eAAe,CAE9E;AAED,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,IAAI,gBAAgB,CAEhF;AAED;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAC9B,MAAM,EAAE,MAAM,EACd,SAAS,CAAC,EAAE,MAAM,EAClB,SAAS,CAAC,EAAE,MAAM,EAClB,QAAQ,CAAC,EAAE,MAAM,GAClB,YAAY,CAsBd;AAED;;;;GAIG;AACH,iBAAS,OAAO,CAAC,IAAI,EAAE,IAAI
|
|
1
|
+
{"version":3,"file":"tool-helpers.d.ts","sourceRoot":"","sources":["../src/tool-helpers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACR,aAAa,EACb,YAAY,EACZ,eAAe,EACf,IAAI,EACJ,UAAU,EACV,gBAAgB,EACnB,MAAM,+BAA+B,CAAA;AAKtC,OAAO,EACH,aAAa,EACb,+BAA+B,EAC/B,4BAA4B,EAC5B,0BAA0B,EAC1B,KAAK,wBAAwB,EAC7B,sBAAsB,GACzB,MAAM,qBAAqB,CAAA;AAE5B,MAAM,MAAM,OAAO,GAAG,eAAe,GAAG,gBAAgB,CAAA;AAExD,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,IAAI,eAAe,CAE9E;AAED,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,IAAI,gBAAgB,CAEhF;AAED;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAC9B,MAAM,EAAE,MAAM,EACd,SAAS,CAAC,EAAE,MAAM,EAClB,SAAS,CAAC,EAAE,MAAM,EAClB,QAAQ,CAAC,EAAE,MAAM,GAClB,YAAY,CAsBd;AAED;;;;GAIG;AACH,iBAAS,OAAO,CAAC,IAAI,EAAE,IAAI;;;;;;;;;;;;;;;;;EAmB1B;AAED;;;;GAIG;AACH,iBAAS,UAAU,CAAC,OAAO,EAAE,OAAO;;;;;;;;;EAWnC;AAED;;;;GAIG;AACH,iBAAS,gBAAgB,CAAC,KAAK,EAAE,aAAa;;;;;;;;;;EAY7C;AAWD,iBAAe,gBAAgB,CAAC,EAC5B,MAAM,EACN,KAAK,EACL,KAAK,EACL,MAAM,GACT,EAAE;IACC,MAAM,EAAE,UAAU,CAAA;IAClB,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,MAAM,GAAG,SAAS,CAAA;IACzB,MAAM,EAAE,MAAM,GAAG,SAAS,CAAA;CAC7B;;;;;;;;;;;;;;;;;;;;GAkBA;AAED,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,UAAU,EAAE,OAAO,EAAE,CAAA"}
|
package/dist/tool-helpers.js
CHANGED
|
@@ -48,6 +48,7 @@ function mapTask(task) {
|
|
|
48
48
|
description: task.description,
|
|
49
49
|
dueDate: task.due?.date,
|
|
50
50
|
recurring: task.due?.isRecurring && task.due.string ? task.due.string : false,
|
|
51
|
+
deadlineDate: task.deadline?.date,
|
|
51
52
|
priority: task.priority,
|
|
52
53
|
projectId: task.projectId,
|
|
53
54
|
sectionId: task.sectionId,
|
|
@@ -221,6 +221,50 @@ describe(`${ADD_TASKS} tool`, () => {
|
|
|
221
221
|
}));
|
|
222
222
|
}
|
|
223
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
|
+
});
|
|
224
268
|
it('should add task with labels', async () => {
|
|
225
269
|
const mockApiResponse = createMockTask({
|
|
226
270
|
id: '8485093755',
|
|
@@ -339,6 +339,73 @@ describe(`${UPDATE_TASKS} tool`, () => {
|
|
|
339
339
|
expect(structuredContent.tasks).toHaveLength(1);
|
|
340
340
|
});
|
|
341
341
|
});
|
|
342
|
+
describe('updating deadlines', () => {
|
|
343
|
+
it('should update task deadline', async () => {
|
|
344
|
+
const mockApiResponse = createMockTask({
|
|
345
|
+
id: '8485093760',
|
|
346
|
+
content: 'Task with deadline',
|
|
347
|
+
deadline: {
|
|
348
|
+
date: '2025-12-31',
|
|
349
|
+
lang: 'en',
|
|
350
|
+
},
|
|
351
|
+
url: 'https://todoist.com/showTask?id=8485093760',
|
|
352
|
+
addedAt: '2025-08-13T22:09:56.123456Z',
|
|
353
|
+
});
|
|
354
|
+
mockTodoistApi.updateTask.mockResolvedValue(mockApiResponse);
|
|
355
|
+
const result = await updateTasks.execute({
|
|
356
|
+
tasks: [
|
|
357
|
+
{
|
|
358
|
+
id: '8485093760',
|
|
359
|
+
deadlineDate: '2025-12-31',
|
|
360
|
+
},
|
|
361
|
+
],
|
|
362
|
+
}, mockTodoistApi);
|
|
363
|
+
// Verify API was called with deadline
|
|
364
|
+
expect(mockTodoistApi.updateTask).toHaveBeenCalledWith('8485093760', {
|
|
365
|
+
deadlineDate: '2025-12-31',
|
|
366
|
+
});
|
|
367
|
+
// Verify result structure
|
|
368
|
+
const textContent = extractTextContent(result);
|
|
369
|
+
expect(textContent).toContain('Updated 1 task');
|
|
370
|
+
const structuredContent = extractStructuredContent(result);
|
|
371
|
+
expect(structuredContent).toEqual(expect.objectContaining({
|
|
372
|
+
tasks: expect.arrayContaining([
|
|
373
|
+
expect.objectContaining({
|
|
374
|
+
id: '8485093760',
|
|
375
|
+
deadlineDate: '2025-12-31',
|
|
376
|
+
}),
|
|
377
|
+
]),
|
|
378
|
+
}));
|
|
379
|
+
expect(structuredContent.tasks).toHaveLength(1);
|
|
380
|
+
});
|
|
381
|
+
it('should remove task deadline with "remove" string', async () => {
|
|
382
|
+
const mockApiResponse = createMockTask({
|
|
383
|
+
id: '8485093761',
|
|
384
|
+
content: 'Task without deadline',
|
|
385
|
+
deadline: null,
|
|
386
|
+
url: 'https://todoist.com/showTask?id=8485093761',
|
|
387
|
+
addedAt: '2025-08-13T22:09:56.123456Z',
|
|
388
|
+
});
|
|
389
|
+
mockTodoistApi.updateTask.mockResolvedValue(mockApiResponse);
|
|
390
|
+
const result = await updateTasks.execute({
|
|
391
|
+
tasks: [
|
|
392
|
+
{
|
|
393
|
+
id: '8485093761',
|
|
394
|
+
deadlineDate: 'remove',
|
|
395
|
+
},
|
|
396
|
+
],
|
|
397
|
+
}, mockTodoistApi);
|
|
398
|
+
// Verify API was called to remove deadline (converts "remove" to null)
|
|
399
|
+
expect(mockTodoistApi.updateTask).toHaveBeenCalledWith('8485093761', {
|
|
400
|
+
deadlineDate: null,
|
|
401
|
+
});
|
|
402
|
+
// Verify result structure
|
|
403
|
+
const textContent = extractTextContent(result);
|
|
404
|
+
expect(textContent).toContain('Updated 1 task');
|
|
405
|
+
const structuredContent = extractStructuredContent(result);
|
|
406
|
+
expect(structuredContent.tasks).toHaveLength(1);
|
|
407
|
+
});
|
|
408
|
+
});
|
|
342
409
|
describe('updating labels', () => {
|
|
343
410
|
it('should update task labels', async () => {
|
|
344
411
|
const mockApiResponse = createMockTask({
|
|
@@ -9,6 +9,7 @@ declare const addTasks: {
|
|
|
9
9
|
description: z.ZodOptional<z.ZodString>;
|
|
10
10
|
priority: z.ZodOptional<z.ZodEnum<["p1", "p2", "p3", "p4"]>>;
|
|
11
11
|
dueString: z.ZodOptional<z.ZodString>;
|
|
12
|
+
deadlineDate: z.ZodOptional<z.ZodString>;
|
|
12
13
|
duration: z.ZodOptional<z.ZodString>;
|
|
13
14
|
labels: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
14
15
|
projectId: z.ZodOptional<z.ZodString>;
|
|
@@ -25,6 +26,7 @@ declare const addTasks: {
|
|
|
25
26
|
duration?: string | undefined;
|
|
26
27
|
priority?: "p1" | "p2" | "p3" | "p4" | undefined;
|
|
27
28
|
dueString?: string | undefined;
|
|
29
|
+
deadlineDate?: string | undefined;
|
|
28
30
|
responsibleUser?: string | undefined;
|
|
29
31
|
}, {
|
|
30
32
|
content: string;
|
|
@@ -36,6 +38,7 @@ declare const addTasks: {
|
|
|
36
38
|
duration?: string | undefined;
|
|
37
39
|
priority?: "p1" | "p2" | "p3" | "p4" | undefined;
|
|
38
40
|
dueString?: string | undefined;
|
|
41
|
+
deadlineDate?: string | undefined;
|
|
39
42
|
responsibleUser?: string | undefined;
|
|
40
43
|
}>, "many">;
|
|
41
44
|
};
|
|
@@ -50,6 +53,7 @@ declare const addTasks: {
|
|
|
50
53
|
duration?: string | undefined;
|
|
51
54
|
priority?: "p1" | "p2" | "p3" | "p4" | undefined;
|
|
52
55
|
dueString?: string | undefined;
|
|
56
|
+
deadlineDate?: string | undefined;
|
|
53
57
|
responsibleUser?: string | undefined;
|
|
54
58
|
}[];
|
|
55
59
|
}, client: TodoistApi): Promise<{
|
|
@@ -64,6 +68,7 @@ declare const addTasks: {
|
|
|
64
68
|
description: string;
|
|
65
69
|
dueDate: string | undefined;
|
|
66
70
|
recurring: string | boolean;
|
|
71
|
+
deadlineDate: string | undefined;
|
|
67
72
|
priority: number;
|
|
68
73
|
projectId: string;
|
|
69
74
|
sectionId: string | null;
|
|
@@ -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;
|
|
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;AA2DvB,QAAA,MAAM,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAuB4B,CAAA;AAwI1C,OAAO,EAAE,QAAQ,EAAE,CAAA"}
|
package/dist/tools/add-tasks.js
CHANGED
|
@@ -17,6 +17,10 @@ const TaskSchema = z.object({
|
|
|
17
17
|
.describe('Additional details, notes, or context for the task. Use this for longer content rather than putting it in the task name. Supports Markdown.'),
|
|
18
18
|
priority: PrioritySchema.optional().describe('The priority of the task: p1 (highest), p2 (high), p3 (medium), p4 (lowest/default).'),
|
|
19
19
|
dueString: z.string().optional().describe('The due date for the task, in natural language.'),
|
|
20
|
+
deadlineDate: z
|
|
21
|
+
.string()
|
|
22
|
+
.optional()
|
|
23
|
+
.describe('The deadline date for the task in ISO 8601 format (YYYY-MM-DD, e.g., "2025-12-31"). Deadlines are immovable constraints shown with a different indicator than due dates.'),
|
|
20
24
|
duration: z
|
|
21
25
|
.string()
|
|
22
26
|
.optional()
|
|
@@ -55,8 +59,15 @@ const addTasks = {
|
|
|
55
59
|
},
|
|
56
60
|
};
|
|
57
61
|
async function processTask(task, client) {
|
|
58
|
-
const { duration: durationStr, projectId, sectionId, parentId, responsibleUser, priority, labels, ...otherTaskArgs } = task;
|
|
59
|
-
let taskArgs = {
|
|
62
|
+
const { duration: durationStr, projectId, sectionId, parentId, responsibleUser, priority, labels, deadlineDate, ...otherTaskArgs } = task;
|
|
63
|
+
let taskArgs = {
|
|
64
|
+
...otherTaskArgs,
|
|
65
|
+
projectId,
|
|
66
|
+
sectionId,
|
|
67
|
+
parentId,
|
|
68
|
+
labels,
|
|
69
|
+
deadlineDate,
|
|
70
|
+
};
|
|
60
71
|
// Handle priority conversion if provided
|
|
61
72
|
if (priority) {
|
|
62
73
|
taskArgs.priority = convertPriorityToNumber(priority);
|
|
@@ -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;AAwDvB,QAAA,MAAM,kBAAkB
|
|
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;AAwDvB,QAAA,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAmEkB,CAAA;AA2E1C,OAAO,EAAE,kBAAkB,EAAE,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"find-tasks-by-date.d.ts","sourceRoot":"","sources":["../../src/tools/find-tasks-by-date.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAmEvB,QAAA,MAAM,eAAe
|
|
1
|
+
{"version":3,"file":"find-tasks-by-date.d.ts","sourceRoot":"","sources":["../../src/tools/find-tasks-by-date.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAmEvB,QAAA,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2EqB,CAAA;AAsG1C,OAAO,EAAE,eAAe,EAAE,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"find-tasks.d.ts","sourceRoot":"","sources":["../../src/tools/find-tasks.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;
|
|
1
|
+
{"version":3,"file":"find-tasks.d.ts","sourceRoot":"","sources":["../../src/tools/find-tasks.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AA2DvB,QAAA,MAAM,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAwL2B,CAAA;AA2K1C,OAAO,EAAE,SAAS,EAAE,CAAA"}
|
package/dist/tools/find-tasks.js
CHANGED
|
@@ -9,7 +9,10 @@ import { ToolNames } from '../utils/tool-names.js';
|
|
|
9
9
|
const { FIND_COMPLETED_TASKS, ADD_TASKS } = ToolNames;
|
|
10
10
|
const ArgsSchema = {
|
|
11
11
|
searchText: z.string().optional().describe('The text to search for in tasks.'),
|
|
12
|
-
projectId: z
|
|
12
|
+
projectId: z
|
|
13
|
+
.string()
|
|
14
|
+
.optional()
|
|
15
|
+
.describe('Find tasks in this project. Project ID should be an ID string, or the text "inbox", for inbox tasks.'),
|
|
13
16
|
sectionId: z.string().optional().describe('Find tasks in this section.'),
|
|
14
17
|
parentId: z.string().optional().describe('Find subtasks of this parent task.'),
|
|
15
18
|
responsibleUser: z
|
|
@@ -60,8 +63,10 @@ const findTasks = {
|
|
|
60
63
|
limit,
|
|
61
64
|
cursor: cursor ?? null,
|
|
62
65
|
};
|
|
63
|
-
if (projectId)
|
|
64
|
-
taskParams.projectId =
|
|
66
|
+
if (projectId) {
|
|
67
|
+
taskParams.projectId =
|
|
68
|
+
projectId === 'inbox' ? todoistUser.inboxProjectId : projectId;
|
|
69
|
+
}
|
|
65
70
|
if (sectionId)
|
|
66
71
|
taskParams.sectionId = sectionId;
|
|
67
72
|
if (parentId)
|
|
@@ -13,6 +13,7 @@ declare const updateTasks: {
|
|
|
13
13
|
order: z.ZodOptional<z.ZodNumber>;
|
|
14
14
|
priority: z.ZodOptional<z.ZodEnum<["p1", "p2", "p3", "p4"]>>;
|
|
15
15
|
dueString: z.ZodOptional<z.ZodString>;
|
|
16
|
+
deadlineDate: z.ZodOptional<z.ZodString>;
|
|
16
17
|
duration: z.ZodOptional<z.ZodString>;
|
|
17
18
|
responsibleUser: z.ZodOptional<z.ZodString>;
|
|
18
19
|
labels: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
@@ -27,6 +28,7 @@ declare const updateTasks: {
|
|
|
27
28
|
duration?: string | undefined;
|
|
28
29
|
priority?: "p1" | "p2" | "p3" | "p4" | undefined;
|
|
29
30
|
dueString?: string | undefined;
|
|
31
|
+
deadlineDate?: string | undefined;
|
|
30
32
|
responsibleUser?: string | undefined;
|
|
31
33
|
order?: number | undefined;
|
|
32
34
|
}, {
|
|
@@ -40,6 +42,7 @@ declare const updateTasks: {
|
|
|
40
42
|
duration?: string | undefined;
|
|
41
43
|
priority?: "p1" | "p2" | "p3" | "p4" | undefined;
|
|
42
44
|
dueString?: string | undefined;
|
|
45
|
+
deadlineDate?: string | undefined;
|
|
43
46
|
responsibleUser?: string | undefined;
|
|
44
47
|
order?: number | undefined;
|
|
45
48
|
}>, "many">;
|
|
@@ -56,6 +59,7 @@ declare const updateTasks: {
|
|
|
56
59
|
duration?: string | undefined;
|
|
57
60
|
priority?: "p1" | "p2" | "p3" | "p4" | undefined;
|
|
58
61
|
dueString?: string | undefined;
|
|
62
|
+
deadlineDate?: string | undefined;
|
|
59
63
|
responsibleUser?: string | undefined;
|
|
60
64
|
order?: number | undefined;
|
|
61
65
|
}[];
|
|
@@ -71,6 +75,7 @@ declare const updateTasks: {
|
|
|
71
75
|
description: string;
|
|
72
76
|
dueDate: string | undefined;
|
|
73
77
|
recurring: string | boolean;
|
|
78
|
+
deadlineDate: string | undefined;
|
|
74
79
|
priority: number;
|
|
75
80
|
projectId: string;
|
|
76
81
|
sectionId: string | null;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"update-tasks.d.ts","sourceRoot":"","sources":["../../src/tools/update-tasks.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;
|
|
1
|
+
{"version":3,"file":"update-tasks.d.ts","sourceRoot":"","sources":["../../src/tools/update-tasks.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAmEvB,QAAA,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8HyB,CAAA;AAqC1C,OAAO,EAAE,WAAW,EAAE,CAAA"}
|
|
@@ -26,6 +26,10 @@ const TasksUpdateSchema = z.object({
|
|
|
26
26
|
.string()
|
|
27
27
|
.optional()
|
|
28
28
|
.describe("The new due date for the task, in natural language (e.g., 'tomorrow at 5pm')."),
|
|
29
|
+
deadlineDate: z
|
|
30
|
+
.string()
|
|
31
|
+
.optional()
|
|
32
|
+
.describe('The new deadline date for the task in ISO 8601 format (YYYY-MM-DD, e.g., "2025-12-31"). Deadlines are immovable constraints shown with a different indicator than due dates. Use "remove" to clear the deadline.'),
|
|
29
33
|
duration: z
|
|
30
34
|
.string()
|
|
31
35
|
.optional()
|
|
@@ -52,7 +56,7 @@ const updateTasks = {
|
|
|
52
56
|
if (!hasUpdatesToMake(task)) {
|
|
53
57
|
return undefined;
|
|
54
58
|
}
|
|
55
|
-
const { id, projectId, sectionId, parentId, duration: durationStr, responsibleUser, priority, labels, ...otherUpdateArgs } = task;
|
|
59
|
+
const { id, projectId, sectionId, parentId, duration: durationStr, responsibleUser, priority, labels, deadlineDate, ...otherUpdateArgs } = task;
|
|
56
60
|
let updateArgs = {
|
|
57
61
|
...otherUpdateArgs,
|
|
58
62
|
...(labels !== undefined && { labels }),
|
|
@@ -61,6 +65,17 @@ const updateTasks = {
|
|
|
61
65
|
if (priority) {
|
|
62
66
|
updateArgs.priority = convertPriorityToNumber(priority);
|
|
63
67
|
}
|
|
68
|
+
// Handle deadline changes if provided
|
|
69
|
+
if (deadlineDate !== undefined) {
|
|
70
|
+
if (deadlineDate === null || deadlineDate === 'remove') {
|
|
71
|
+
// Remove deadline - support both legacy null and new "remove" string
|
|
72
|
+
updateArgs = { ...updateArgs, deadlineDate: null };
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
// Set new deadline
|
|
76
|
+
updateArgs = { ...updateArgs, deadlineDate };
|
|
77
|
+
}
|
|
78
|
+
}
|
|
64
79
|
// Parse duration if provided
|
|
65
80
|
if (durationStr) {
|
|
66
81
|
try {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"test-helpers.d.ts","sourceRoot":"","sources":["../../src/utils/test-helpers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,eAAe,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,+BAA+B,CAAA;AAChG,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAA;AAE9C;;;GAGG;AACH,MAAM,MAAM,UAAU,GAAG;IACrB,EAAE,EAAE,MAAM,CAAA;IACV,OAAO,EAAE,MAAM,CAAA;IACf,WAAW,EAAE,MAAM,CAAA;IACnB,OAAO,EAAE,MAAM,GAAG,SAAS,CAAA;IAC3B,SAAS,EAAE,MAAM,GAAG,OAAO,CAAA;IAC3B,QAAQ,EAAE,MAAM,CAAA;IAChB,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;IACvB,MAAM,EAAE,MAAM,EAAE,CAAA;IAChB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;IACvB,cAAc,EAAE,MAAM,GAAG,IAAI,CAAA;IAC7B,aAAa,EAAE,MAAM,GAAG,IAAI,CAAA;IAC5B,OAAO,EAAE,OAAO,CAAA;IAChB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;CAC7B,CAAA;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,SAAS,GAAE,OAAO,CAAC,IAAI,CAAM,GAAG,IAAI,CA8BlE;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,SAAS,GAAE,OAAO,CAAC,OAAO,CAAM,GAAG,OAAO,CAgB3E;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,SAAS,GAAE,OAAO,CAAC,eAAe,CAAM,GAAG,eAAe,CAuB3F;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,CAAC,EACnC,OAAO,EAAE,CAAC,EAAE,EACZ,UAAU,GAAE,MAAM,GAAG,IAAW,GACjC;IACC,OAAO,EAAE,CAAC,EAAE,CAAA;IACZ,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;CAC5B,CAKA;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,SAAS,GAAE,OAAO,CAAC,UAAU,CAAM,GAAG,UAAU,
|
|
1
|
+
{"version":3,"file":"test-helpers.d.ts","sourceRoot":"","sources":["../../src/utils/test-helpers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,eAAe,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,+BAA+B,CAAA;AAChG,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAA;AAE9C;;;GAGG;AACH,MAAM,MAAM,UAAU,GAAG;IACrB,EAAE,EAAE,MAAM,CAAA;IACV,OAAO,EAAE,MAAM,CAAA;IACf,WAAW,EAAE,MAAM,CAAA;IACnB,OAAO,EAAE,MAAM,GAAG,SAAS,CAAA;IAC3B,SAAS,EAAE,MAAM,GAAG,OAAO,CAAA;IAC3B,YAAY,EAAE,MAAM,GAAG,SAAS,CAAA;IAChC,QAAQ,EAAE,MAAM,CAAA;IAChB,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;IACvB,MAAM,EAAE,MAAM,EAAE,CAAA;IAChB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;IACvB,cAAc,EAAE,MAAM,GAAG,IAAI,CAAA;IAC7B,aAAa,EAAE,MAAM,GAAG,IAAI,CAAA;IAC5B,OAAO,EAAE,OAAO,CAAA;IAChB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;CAC7B,CAAA;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,SAAS,GAAE,OAAO,CAAC,IAAI,CAAM,GAAG,IAAI,CA8BlE;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,SAAS,GAAE,OAAO,CAAC,OAAO,CAAM,GAAG,OAAO,CAgB3E;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,SAAS,GAAE,OAAO,CAAC,eAAe,CAAM,GAAG,eAAe,CAuB3F;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,CAAC,EACnC,OAAO,EAAE,CAAC,EAAE,EACZ,UAAU,GAAE,MAAM,GAAG,IAAW,GACjC;IACC,OAAO,EAAE,CAAC,EAAE,CAAA;IACZ,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;CAC5B,CAKA;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,SAAS,GAAE,OAAO,CAAC,UAAU,CAAM,GAAG,UAAU,CAoBhF;AAED;;GAEG;AACH,eAAO,MAAM,WAAW;;;;;CAKd,CAAA;AAEV;;GAEG;AACH,wBAAgB,eAAe,CAAC,CAAC,EAAE,CAAC,GAAG,OAAO,EAC1C,KAAK,EAAE,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,CAAC,CAAC;IAAC,QAAQ,CAAC,EAAE,CAAC,CAAA;CAAE,CAAC;UAAjC,MAAM;WAAS,CAAC;eAAa,CAAC;IAGtD;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,OAAO,GAAG,MAAM,CAqB9D;AAED;;;GAGG;AACH,wBAAgB,wBAAwB,CACpC,MAAM,EAAE,UAAU,CAAC,OAAO,aAAa,CAAC,GACzC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAuBzB;AAED;;GAEG;AACH,eAAO,MAAM,QAAQ;;;;;;;;;;CAUX,CAAA;AAEV;;;GAGG;AACH,eAAO,MAAM,KAAK,EAAG,YAAqB,CAAA;AAE1C;;;GAGG;AACH,wBAAgB,cAAc,CAAC,SAAS,GAAE,OAAO,CAAC,WAAW,CAAM,GAAG,WAAW,CAmChF"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@doist/todoist-ai",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.15.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -40,19 +40,20 @@
|
|
|
40
40
|
"lint:write": "biome lint --write",
|
|
41
41
|
"format:check": "biome format",
|
|
42
42
|
"format:write": "biome format --write",
|
|
43
|
-
"
|
|
43
|
+
"lint:schemas": "npm run build && npx tsc scripts/validate-schemas.ts --outDir dist/scripts --moduleResolution node --module ESNext --target es2021 --esModuleInterop --skipLibCheck --declaration false && node dist/scripts/validate-schemas.js",
|
|
44
|
+
"check": "biome check && npm run lint:schemas",
|
|
44
45
|
"check:fix": "biome check --fix --unsafe",
|
|
45
46
|
"prepare": "husky"
|
|
46
47
|
},
|
|
47
48
|
"dependencies": {
|
|
48
49
|
"@modelcontextprotocol/sdk": "^1.11.1",
|
|
49
50
|
"date-fns": "^4.1.0",
|
|
50
|
-
"@doist/todoist-api-typescript": "5.
|
|
51
|
+
"@doist/todoist-api-typescript": "5.9.0",
|
|
51
52
|
"dotenv": "^17.0.0",
|
|
52
53
|
"zod": "^3.25.7"
|
|
53
54
|
},
|
|
54
55
|
"devDependencies": {
|
|
55
|
-
"@biomejs/biome": "2.2
|
|
56
|
+
"@biomejs/biome": "2.3.2",
|
|
56
57
|
"@types/express": "^5.0.2",
|
|
57
58
|
"@types/jest": "30.0.0",
|
|
58
59
|
"@types/morgan": "^1.9.9",
|
|
@@ -71,6 +72,15 @@
|
|
|
71
72
|
"lint-staged": {
|
|
72
73
|
"*": [
|
|
73
74
|
"biome check --write --no-errors-on-unmatched --files-ignore-unknown=true"
|
|
75
|
+
],
|
|
76
|
+
"src/tools/*.ts": [
|
|
77
|
+
"npm run lint:schemas"
|
|
78
|
+
],
|
|
79
|
+
"src/index.ts": [
|
|
80
|
+
"npm run lint:schemas"
|
|
81
|
+
],
|
|
82
|
+
"scripts/validate-schemas.ts": [
|
|
83
|
+
"npm run lint:schemas"
|
|
74
84
|
]
|
|
75
85
|
}
|
|
76
86
|
}
|
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Schema Validation Script for Todoist AI MCP Server
|
|
5
|
+
*
|
|
6
|
+
* This script validates that all tool parameter schemas follow Gemini API compatibility rules.
|
|
7
|
+
* Specifically, it checks that no Zod string schemas use both .nullable() and .optional().
|
|
8
|
+
*
|
|
9
|
+
* This version imports the actual tools from the compiled index.js and validates their
|
|
10
|
+
* runtime Zod schemas for maximum accuracy.
|
|
11
|
+
*
|
|
12
|
+
* Usage:
|
|
13
|
+
* npm run build && node scripts/validate-schemas.js
|
|
14
|
+
* npm run build && node scripts/validate-schemas.js --verbose
|
|
15
|
+
* npm run build && node scripts/validate-schemas.js --json
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
import { z } from 'zod'
|
|
19
|
+
|
|
20
|
+
interface ValidationIssue {
|
|
21
|
+
toolName: string
|
|
22
|
+
parameterPath: string
|
|
23
|
+
issue: string
|
|
24
|
+
suggestion: string
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
interface ValidationResult {
|
|
28
|
+
success: boolean
|
|
29
|
+
issues: ValidationIssue[]
|
|
30
|
+
toolsChecked: number
|
|
31
|
+
parametersChecked: number
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Recursively walk a Zod schema and detect problematic patterns
|
|
36
|
+
*/
|
|
37
|
+
function walkZodSchema(
|
|
38
|
+
schema: z.ZodTypeAny,
|
|
39
|
+
path: string,
|
|
40
|
+
issues: ValidationIssue[],
|
|
41
|
+
toolName: string,
|
|
42
|
+
): void {
|
|
43
|
+
const typeName = schema._def.typeName
|
|
44
|
+
|
|
45
|
+
// Check for ZodOptional containing a ZodNullable ZodString
|
|
46
|
+
if (typeName === 'ZodOptional') {
|
|
47
|
+
const innerSchema = schema._def.innerType
|
|
48
|
+
if (innerSchema._def.typeName === 'ZodNullable') {
|
|
49
|
+
const nullableInner = innerSchema._def.innerType
|
|
50
|
+
if (nullableInner._def.typeName === 'ZodString') {
|
|
51
|
+
issues.push({
|
|
52
|
+
toolName,
|
|
53
|
+
parameterPath: path,
|
|
54
|
+
issue: 'GEMINI_API_INCOMPATIBLE: z.string().nullable().optional() pattern detected',
|
|
55
|
+
suggestion:
|
|
56
|
+
'REQUIRED FIX: Change "z.string().nullable().optional()" to "z.string().optional()" and use special strings like "remove" or "unassign" in description to handle clearing. This pattern causes HTTP 400 errors in Google Gemini API due to OpenAPI 3.1 nullable type incompatibility.',
|
|
57
|
+
})
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Check for ZodNullable containing a ZodOptional ZodString
|
|
63
|
+
if (typeName === 'ZodNullable') {
|
|
64
|
+
const innerSchema = schema._def.innerType
|
|
65
|
+
if (innerSchema._def.typeName === 'ZodOptional') {
|
|
66
|
+
const optionalInner = innerSchema._def.innerType
|
|
67
|
+
if (optionalInner._def.typeName === 'ZodString') {
|
|
68
|
+
issues.push({
|
|
69
|
+
toolName,
|
|
70
|
+
parameterPath: path,
|
|
71
|
+
issue: 'GEMINI_API_INCOMPATIBLE: z.string().optional().nullable() pattern detected',
|
|
72
|
+
suggestion:
|
|
73
|
+
'REQUIRED FIX: Change "z.string().optional().nullable()" to "z.string().optional()" and use special strings like "remove" or "unassign" in description to handle clearing. This pattern causes HTTP 400 errors in Google Gemini API due to OpenAPI 3.1 nullable type incompatibility.',
|
|
74
|
+
})
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Recursively check nested schemas
|
|
80
|
+
switch (typeName) {
|
|
81
|
+
case 'ZodObject': {
|
|
82
|
+
const shape = schema._def.shape()
|
|
83
|
+
for (const [key, value] of Object.entries(shape)) {
|
|
84
|
+
const newPath = path ? `${path}.${key}` : key
|
|
85
|
+
walkZodSchema(value as z.ZodTypeAny, newPath, issues, toolName)
|
|
86
|
+
}
|
|
87
|
+
break
|
|
88
|
+
}
|
|
89
|
+
case 'ZodArray':
|
|
90
|
+
walkZodSchema(schema._def.type, `${path}[]`, issues, toolName)
|
|
91
|
+
break
|
|
92
|
+
|
|
93
|
+
case 'ZodOptional':
|
|
94
|
+
case 'ZodNullable':
|
|
95
|
+
case 'ZodDefault':
|
|
96
|
+
walkZodSchema(schema._def.innerType, path, issues, toolName)
|
|
97
|
+
break
|
|
98
|
+
|
|
99
|
+
case 'ZodUnion':
|
|
100
|
+
case 'ZodDiscriminatedUnion': {
|
|
101
|
+
const options = schema._def.options || schema._def.discriminatedUnion
|
|
102
|
+
if (Array.isArray(options)) {
|
|
103
|
+
options.forEach((option: z.ZodTypeAny, index: number) => {
|
|
104
|
+
walkZodSchema(option, `${path}[union:${index}]`, issues, toolName)
|
|
105
|
+
})
|
|
106
|
+
}
|
|
107
|
+
break
|
|
108
|
+
}
|
|
109
|
+
case 'ZodIntersection':
|
|
110
|
+
walkZodSchema(schema._def.left, `${path}[left]`, issues, toolName)
|
|
111
|
+
walkZodSchema(schema._def.right, `${path}[right]`, issues, toolName)
|
|
112
|
+
break
|
|
113
|
+
|
|
114
|
+
case 'ZodRecord':
|
|
115
|
+
if (schema._def.valueType) {
|
|
116
|
+
walkZodSchema(schema._def.valueType, `${path}[value]`, issues, toolName)
|
|
117
|
+
}
|
|
118
|
+
break
|
|
119
|
+
|
|
120
|
+
case 'ZodTuple':
|
|
121
|
+
if (schema._def.items) {
|
|
122
|
+
schema._def.items.forEach((item: z.ZodTypeAny, index: number) => {
|
|
123
|
+
walkZodSchema(item, `${path}[${index}]`, issues, toolName)
|
|
124
|
+
})
|
|
125
|
+
}
|
|
126
|
+
break
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Validate a single tool's parameter schema
|
|
132
|
+
*/
|
|
133
|
+
// biome-ignore lint/suspicious/noExplicitAny: this is a tooling script
|
|
134
|
+
function validateToolSchema(tool: any): ValidationIssue[] {
|
|
135
|
+
const issues: ValidationIssue[] = []
|
|
136
|
+
const toolName = tool.name || 'unknown'
|
|
137
|
+
|
|
138
|
+
if (!tool.parameters) {
|
|
139
|
+
return issues
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
try {
|
|
143
|
+
const schema = z.object(tool.parameters)
|
|
144
|
+
walkZodSchema(schema, '', issues, toolName)
|
|
145
|
+
} catch (error) {
|
|
146
|
+
issues.push({
|
|
147
|
+
toolName,
|
|
148
|
+
parameterPath: 'root',
|
|
149
|
+
issue: `Failed to analyze schema: ${error}`,
|
|
150
|
+
suggestion: 'Check that the tool parameters are valid Zod schemas',
|
|
151
|
+
})
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
return issues
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Main validation function using runtime schema analysis
|
|
159
|
+
*/
|
|
160
|
+
async function validateAllSchemas(verbose: boolean = false): Promise<ValidationResult> {
|
|
161
|
+
try {
|
|
162
|
+
const { tools } = await import(`${process.cwd()}/dist/index.js`)
|
|
163
|
+
|
|
164
|
+
const allIssues: ValidationIssue[] = []
|
|
165
|
+
let totalParameters = 0
|
|
166
|
+
const toolNames = Object.keys(tools)
|
|
167
|
+
|
|
168
|
+
for (const toolName of toolNames) {
|
|
169
|
+
const tool = tools[toolName]
|
|
170
|
+
const toolIssues = validateToolSchema(tool)
|
|
171
|
+
allIssues.push(...toolIssues)
|
|
172
|
+
|
|
173
|
+
// Count parameters for stats
|
|
174
|
+
if (tool.parameters) {
|
|
175
|
+
try {
|
|
176
|
+
const schema = z.object(tool.parameters)
|
|
177
|
+
const shape = schema._def.shape()
|
|
178
|
+
totalParameters += Object.keys(shape).length
|
|
179
|
+
} catch {
|
|
180
|
+
// Skip counting if schema is invalid
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
if (verbose) {
|
|
185
|
+
const issueCount = toolIssues.length
|
|
186
|
+
const status = issueCount === 0 ? '✅' : `❌ (${issueCount} issues)`
|
|
187
|
+
const paramCount = tool.parameters ? Object.keys(tool.parameters).length : 0
|
|
188
|
+
console.log(`${status} ${toolName} (${paramCount} parameters)`)
|
|
189
|
+
|
|
190
|
+
if (issueCount > 0) {
|
|
191
|
+
toolIssues.forEach((issue) => {
|
|
192
|
+
console.log(` ${issue.parameterPath}: ${issue.issue}`)
|
|
193
|
+
})
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
return {
|
|
199
|
+
success: allIssues.length === 0,
|
|
200
|
+
issues: allIssues,
|
|
201
|
+
toolsChecked: toolNames.length,
|
|
202
|
+
parametersChecked: totalParameters,
|
|
203
|
+
}
|
|
204
|
+
} catch (error) {
|
|
205
|
+
return {
|
|
206
|
+
success: false,
|
|
207
|
+
issues: [
|
|
208
|
+
{
|
|
209
|
+
toolName: 'system',
|
|
210
|
+
parameterPath: 'import',
|
|
211
|
+
issue: `Failed to import tools: ${error}`,
|
|
212
|
+
suggestion: 'Ensure the project is built and dist/index.js exists',
|
|
213
|
+
},
|
|
214
|
+
],
|
|
215
|
+
toolsChecked: 0,
|
|
216
|
+
parametersChecked: 0,
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* CLI interface
|
|
223
|
+
*/
|
|
224
|
+
async function main() {
|
|
225
|
+
const args = process.argv.slice(2)
|
|
226
|
+
const verbose = args.includes('--verbose')
|
|
227
|
+
const jsonOutput = args.includes('--json')
|
|
228
|
+
|
|
229
|
+
try {
|
|
230
|
+
const result = await validateAllSchemas(verbose)
|
|
231
|
+
|
|
232
|
+
if (jsonOutput) {
|
|
233
|
+
console.log(JSON.stringify(result, null, 2))
|
|
234
|
+
} else {
|
|
235
|
+
if (result.success) {
|
|
236
|
+
console.log('✅ Schema validation passed!')
|
|
237
|
+
console.log(
|
|
238
|
+
` Checked ${result.toolsChecked} tools with ${result.parametersChecked} parameters`,
|
|
239
|
+
)
|
|
240
|
+
console.log(
|
|
241
|
+
' All schemas are Gemini API compatible (no .nullable() on optional strings)',
|
|
242
|
+
)
|
|
243
|
+
} else {
|
|
244
|
+
console.log('❌ Schema validation failed!')
|
|
245
|
+
console.log(
|
|
246
|
+
` Found ${result.issues.length} issue(s) in ${result.toolsChecked} tools:\n`,
|
|
247
|
+
)
|
|
248
|
+
|
|
249
|
+
result.issues.forEach((issue, index) => {
|
|
250
|
+
console.log(`\n${index + 1}. 🚫 VALIDATION FAILURE`)
|
|
251
|
+
console.log(` Tool: ${issue.toolName}`)
|
|
252
|
+
console.log(` Parameter: ${issue.parameterPath}`)
|
|
253
|
+
console.log(` Issue: ${issue.issue}`)
|
|
254
|
+
console.log(` Action Required: ${issue.suggestion}`)
|
|
255
|
+
console.log(` File Location: src/tools/${issue.toolName}.ts`)
|
|
256
|
+
console.log(` Fix Pattern: Remove .nullable() from the parameter schema`)
|
|
257
|
+
console.log(
|
|
258
|
+
` Example Fix: Change z.string().nullable().optional() → z.string().optional()`,
|
|
259
|
+
)
|
|
260
|
+
console.log(
|
|
261
|
+
` ⚠️ This validation failure will cause Gemini API HTTP 400 errors\n`,
|
|
262
|
+
)
|
|
263
|
+
})
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
process.exit(result.success ? 0 : 1)
|
|
268
|
+
} catch (error) {
|
|
269
|
+
console.error('Fatal error during schema validation:', error)
|
|
270
|
+
process.exit(1)
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
// Run if this script is executed directly
|
|
275
|
+
if (process.argv[1]?.endsWith('validate-schemas.js')) {
|
|
276
|
+
main()
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
export type { ValidationResult, ValidationIssue }
|
|
280
|
+
export { validateAllSchemas }
|