@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 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;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -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
@@ -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;;;;;;;;;;;;;;;;EAkB1B;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"}
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"}
@@ -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;AAqDvB,QAAA,MAAM,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAuB4B,CAAA;AAgI1C,OAAO,EAAE,QAAQ,EAAE,CAAA"}
1
+ {"version":3,"file":"add-tasks.d.ts","sourceRoot":"","sources":["../../src/tools/add-tasks.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAqB,UAAU,EAAE,MAAM,+BAA+B,CAAA;AAClF,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AA2DvB,QAAA,MAAM,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAuB4B,CAAA;AAwI1C,OAAO,EAAE,QAAQ,EAAE,CAAA"}
@@ -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 = { ...otherTaskArgs, projectId, sectionId, parentId, labels };
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);
@@ -57,7 +57,7 @@ const findActivity = {
57
57
  // Add optional filters
58
58
  if (objectType)
59
59
  apiArgs.objectType = objectType;
60
- if (objectId)
60
+ if (objectId && objectId !== 'remove')
61
61
  apiArgs.objectId = objectId;
62
62
  if (eventType)
63
63
  apiArgs.eventType = eventType;
@@ -41,6 +41,7 @@ declare const findCompletedTasks: {
41
41
  description: string;
42
42
  dueDate: string | undefined;
43
43
  recurring: string | boolean;
44
+ deadlineDate: string | undefined;
44
45
  priority: number;
45
46
  projectId: string;
46
47
  sectionId: string | null;
@@ -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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAmEkB,CAAA;AA2E1C,OAAO,EAAE,kBAAkB,EAAE,CAAA"}
1
+ {"version":3,"file":"find-completed-tasks.d.ts","sourceRoot":"","sources":["../../src/tools/find-completed-tasks.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAwDvB,QAAA,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAmEkB,CAAA;AA2E1C,OAAO,EAAE,kBAAkB,EAAE,CAAA"}
@@ -35,6 +35,7 @@ declare const findTasksByDate: {
35
35
  description: string;
36
36
  dueDate: string | undefined;
37
37
  recurring: string | boolean;
38
+ deadlineDate: string | undefined;
38
39
  priority: number;
39
40
  projectId: string;
40
41
  sectionId: string | null;
@@ -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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2EqB,CAAA;AAsG1C,OAAO,EAAE,eAAe,EAAE,CAAA"}
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"}
@@ -37,6 +37,7 @@ declare const findTasks: {
37
37
  description: string;
38
38
  dueDate: string | undefined;
39
39
  recurring: string | boolean;
40
+ deadlineDate: string | undefined;
40
41
  priority: number;
41
42
  projectId: string;
42
43
  sectionId: string | null;
@@ -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;AAsDvB,QAAA,MAAM,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAqL2B,CAAA;AA2K1C,OAAO,EAAE,SAAS,EAAE,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"}
@@ -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.string().optional().describe('Find tasks in this project.'),
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 = 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;AA6DvB,QAAA,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAkHyB,CAAA;AAqC1C,OAAO,EAAE,WAAW,EAAE,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 {
@@ -10,6 +10,7 @@ export type MappedTask = {
10
10
  description: string;
11
11
  dueDate: string | undefined;
12
12
  recurring: string | boolean;
13
+ deadlineDate: string | undefined;
13
14
  priority: number;
14
15
  projectId: string;
15
16
  sectionId: string | null;
@@ -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,CAmBhF;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"}
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"}
@@ -101,6 +101,7 @@ export function createMappedTask(overrides = {}) {
101
101
  description: '',
102
102
  dueDate: undefined,
103
103
  recurring: false,
104
+ deadlineDate: undefined,
104
105
  priority: 1,
105
106
  projectId: TEST_IDS.PROJECT_TEST,
106
107
  sectionId: null,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@doist/todoist-ai",
3
- "version": "4.14.5",
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
- "check": "biome check",
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.7.1",
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.6",
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 }