@doist/todoist-ai 2.0.0 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (96) hide show
  1. package/README.md +7 -0
  2. package/dist/index.d.ts +29 -18
  3. package/dist/index.d.ts.map +1 -1
  4. package/dist/index.js +31 -48
  5. package/dist/main.js +6 -11
  6. package/dist/mcp-helpers.d.ts +2 -2
  7. package/dist/mcp-helpers.d.ts.map +1 -1
  8. package/dist/mcp-helpers.js +1 -4
  9. package/dist/mcp-server.d.ts +1 -1
  10. package/dist/mcp-server.d.ts.map +1 -1
  11. package/dist/mcp-server.js +34 -36
  12. package/dist/todoist-tool.js +1 -2
  13. package/dist/tool-helpers.d.ts +13 -1
  14. package/dist/tool-helpers.d.ts.map +1 -1
  15. package/dist/tool-helpers.js +43 -22
  16. package/dist/tool-helpers.test.js +55 -14
  17. package/dist/tools/__tests__/delete-one.test.d.ts +2 -0
  18. package/dist/tools/__tests__/delete-one.test.d.ts.map +1 -0
  19. package/dist/tools/__tests__/delete-one.test.js +90 -0
  20. package/dist/tools/__tests__/overview.test.d.ts +2 -0
  21. package/dist/tools/__tests__/overview.test.d.ts.map +1 -0
  22. package/dist/tools/__tests__/overview.test.js +163 -0
  23. package/dist/tools/__tests__/projects-list.test.d.ts +2 -0
  24. package/dist/tools/__tests__/projects-list.test.d.ts.map +1 -0
  25. package/dist/tools/__tests__/projects-list.test.js +140 -0
  26. package/dist/tools/__tests__/projects-manage.test.d.ts +2 -0
  27. package/dist/tools/__tests__/projects-manage.test.d.ts.map +1 -0
  28. package/dist/tools/__tests__/projects-manage.test.js +106 -0
  29. package/dist/tools/__tests__/sections-manage.test.d.ts +2 -0
  30. package/dist/tools/__tests__/sections-manage.test.d.ts.map +1 -0
  31. package/dist/tools/__tests__/sections-manage.test.js +138 -0
  32. package/dist/tools/__tests__/sections-search.test.d.ts +2 -0
  33. package/dist/tools/__tests__/sections-search.test.d.ts.map +1 -0
  34. package/dist/tools/__tests__/sections-search.test.js +235 -0
  35. package/dist/tools/__tests__/tasks-add-multiple.test.d.ts +2 -0
  36. package/dist/tools/__tests__/tasks-add-multiple.test.d.ts.map +1 -0
  37. package/dist/tools/__tests__/tasks-add-multiple.test.js +274 -0
  38. package/dist/tools/__tests__/tasks-complete-multiple.test.d.ts +2 -0
  39. package/dist/tools/__tests__/tasks-complete-multiple.test.d.ts.map +1 -0
  40. package/dist/tools/__tests__/tasks-complete-multiple.test.js +146 -0
  41. package/dist/tools/__tests__/tasks-list-by-date.test.d.ts +2 -0
  42. package/dist/tools/__tests__/tasks-list-by-date.test.d.ts.map +1 -0
  43. package/dist/tools/__tests__/tasks-list-by-date.test.js +192 -0
  44. package/dist/tools/__tests__/tasks-list-completed.test.d.ts +2 -0
  45. package/dist/tools/__tests__/tasks-list-completed.test.d.ts.map +1 -0
  46. package/dist/tools/__tests__/tasks-list-completed.test.js +154 -0
  47. package/dist/tools/__tests__/tasks-list-for-container.test.d.ts +2 -0
  48. package/dist/tools/__tests__/tasks-list-for-container.test.d.ts.map +1 -0
  49. package/dist/tools/__tests__/tasks-list-for-container.test.js +232 -0
  50. package/dist/tools/__tests__/tasks-organize-multiple.test.d.ts +2 -0
  51. package/dist/tools/__tests__/tasks-organize-multiple.test.d.ts.map +1 -0
  52. package/dist/tools/__tests__/tasks-organize-multiple.test.js +245 -0
  53. package/dist/tools/__tests__/tasks-search.test.d.ts +2 -0
  54. package/dist/tools/__tests__/tasks-search.test.d.ts.map +1 -0
  55. package/dist/tools/__tests__/tasks-search.test.js +106 -0
  56. package/dist/tools/__tests__/tasks-update-one.test.d.ts +2 -0
  57. package/dist/tools/__tests__/tasks-update-one.test.d.ts.map +1 -0
  58. package/dist/tools/__tests__/tasks-update-one.test.js +251 -0
  59. package/dist/tools/delete-one.js +4 -7
  60. package/dist/tools/overview.js +8 -11
  61. package/dist/tools/projects-list.js +7 -10
  62. package/dist/tools/projects-manage.js +6 -9
  63. package/dist/tools/sections-manage.js +7 -10
  64. package/dist/tools/sections-search.js +4 -7
  65. package/dist/tools/tasks-add-multiple.d.ts +5 -0
  66. package/dist/tools/tasks-add-multiple.d.ts.map +1 -1
  67. package/dist/tools/tasks-add-multiple.js +37 -17
  68. package/dist/tools/tasks-complete-multiple.js +3 -6
  69. package/dist/tools/tasks-list-by-date.d.ts +1 -0
  70. package/dist/tools/tasks-list-by-date.d.ts.map +1 -1
  71. package/dist/tools/tasks-list-by-date.js +12 -15
  72. package/dist/tools/tasks-list-completed.d.ts +2 -1
  73. package/dist/tools/tasks-list-completed.d.ts.map +1 -1
  74. package/dist/tools/tasks-list-completed.js +13 -16
  75. package/dist/tools/tasks-list-for-container.d.ts +1 -0
  76. package/dist/tools/tasks-list-for-container.d.ts.map +1 -1
  77. package/dist/tools/tasks-list-for-container.js +8 -11
  78. package/dist/tools/tasks-organize-multiple.d.ts.map +1 -1
  79. package/dist/tools/tasks-organize-multiple.js +20 -14
  80. package/dist/tools/tasks-search.d.ts +1 -0
  81. package/dist/tools/tasks-search.d.ts.map +1 -1
  82. package/dist/tools/tasks-search.js +7 -10
  83. package/dist/tools/tasks-update-one.d.ts +4 -2
  84. package/dist/tools/tasks-update-one.d.ts.map +1 -1
  85. package/dist/tools/tasks-update-one.js +45 -15
  86. package/dist/tools/test-helpers.d.ts +80 -0
  87. package/dist/tools/test-helpers.d.ts.map +1 -0
  88. package/dist/tools/test-helpers.js +140 -0
  89. package/dist/utils/duration-parser.d.ts +36 -0
  90. package/dist/utils/duration-parser.d.ts.map +1 -0
  91. package/dist/utils/duration-parser.js +96 -0
  92. package/dist/utils/duration-parser.test.d.ts +2 -0
  93. package/dist/utils/duration-parser.test.d.ts.map +1 -0
  94. package/dist/utils/duration-parser.test.js +147 -0
  95. package/package.json +6 -2
  96. package/scripts/test-executable.cjs +69 -0
@@ -20,9 +20,9 @@ declare const tasksListCompleted: {
20
20
  until: string;
21
21
  parentId?: string | undefined;
22
22
  workspaceId?: string | undefined;
23
- cursor?: string | undefined;
24
23
  projectId?: string | undefined;
25
24
  sectionId?: string | undefined;
25
+ cursor?: string | undefined;
26
26
  }, client: import("@doist/todoist-api-typescript").TodoistApi): Promise<{
27
27
  tasks: {
28
28
  id: string;
@@ -35,6 +35,7 @@ declare const tasksListCompleted: {
35
35
  sectionId: string | null;
36
36
  parentId: string | null;
37
37
  labels: string[];
38
+ duration: string | null;
38
39
  }[];
39
40
  nextCursor: string | null;
40
41
  }>;
@@ -1 +1 @@
1
- {"version":3,"file":"tasks-list-completed.d.ts","sourceRoot":"","sources":["../../src/tools/tasks-list-completed.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAwCvB,QAAA,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAekB,CAAA;AAE1C,OAAO,EAAE,kBAAkB,EAAE,CAAA"}
1
+ {"version":3,"file":"tasks-list-completed.d.ts","sourceRoot":"","sources":["../../src/tools/tasks-list-completed.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAwCvB,QAAA,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAekB,CAAA;AAE1C,OAAO,EAAE,kBAAkB,EAAE,CAAA"}
@@ -1,35 +1,32 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.tasksListCompleted = void 0;
4
- const zod_1 = require("zod");
5
- const tool_helpers_1 = require("../tool-helpers");
1
+ import { z } from 'zod';
2
+ import { mapTask } from '../tool-helpers.js';
6
3
  const ArgsSchema = {
7
- getBy: zod_1.z
4
+ getBy: z
8
5
  .enum(['completion', 'due'])
9
6
  .default('completion')
10
7
  .describe('The method to use to get the tasks: "completion" to get tasks by completion date (ie, when the task was actually completed), "due" to get tasks by due date (ie, when the task was due to be completed by).'),
11
- since: zod_1.z
8
+ since: z
12
9
  .string()
13
10
  .date()
14
11
  .regex(/^\d{4}-\d{2}-\d{2}$/)
15
12
  .describe('The start date to get the tasks for. Format: YYYY-MM-DD.'),
16
- until: zod_1.z
13
+ until: z
17
14
  .string()
18
15
  .date()
19
16
  .regex(/^\d{4}-\d{2}-\d{2}$/)
20
17
  .describe('The start date to get the tasks for. Format: YYYY-MM-DD.'),
21
- workspaceId: zod_1.z.string().optional().describe('The ID of the workspace to get the tasks for.'),
22
- projectId: zod_1.z.string().optional().describe('The ID of the project to get the tasks for.'),
23
- sectionId: zod_1.z.string().optional().describe('The ID of the section to get the tasks for.'),
24
- parentId: zod_1.z.string().optional().describe('The ID of the parent task to get the tasks for.'),
25
- limit: zod_1.z
18
+ workspaceId: z.string().optional().describe('The ID of the workspace to get the tasks for.'),
19
+ projectId: z.string().optional().describe('The ID of the project to get the tasks for.'),
20
+ sectionId: z.string().optional().describe('The ID of the section to get the tasks for.'),
21
+ parentId: z.string().optional().describe('The ID of the parent task to get the tasks for.'),
22
+ limit: z
26
23
  .number()
27
24
  .int()
28
25
  .min(1)
29
26
  .max(200)
30
27
  .default(50)
31
28
  .describe('The maximum number of tasks to return. Default is 50, maximum is 200.'),
32
- cursor: zod_1.z
29
+ cursor: z
33
30
  .string()
34
31
  .optional()
35
32
  .describe('The cursor to get the next page of tasks (cursor is obtained from the previous call to this tool, with the same parameters).'),
@@ -44,9 +41,9 @@ const tasksListCompleted = {
44
41
  ? await client.getCompletedTasksByCompletionDate(rest)
45
42
  : await client.getCompletedTasksByDueDate(rest);
46
43
  return {
47
- tasks: items.map(tool_helpers_1.mapTask),
44
+ tasks: items.map(mapTask),
48
45
  nextCursor,
49
46
  };
50
47
  },
51
48
  };
52
- exports.tasksListCompleted = tasksListCompleted;
49
+ export { tasksListCompleted };
@@ -25,6 +25,7 @@ declare const tasksListForContainer: {
25
25
  sectionId: string | null;
26
26
  parentId: string | null;
27
27
  labels: string[];
28
+ duration: string | null;
28
29
  }[];
29
30
  nextCursor: string | null;
30
31
  }>;
@@ -1 +1 @@
1
- {"version":3,"file":"tasks-list-for-container.d.ts","sourceRoot":"","sources":["../../src/tools/tasks-list-for-container.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAwBvB,QAAA,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+Be,CAAA;AAE1C,OAAO,EAAE,qBAAqB,EAAE,CAAA"}
1
+ {"version":3,"file":"tasks-list-for-container.d.ts","sourceRoot":"","sources":["../../src/tools/tasks-list-for-container.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAwBvB,QAAA,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+Be,CAAA;AAE1C,OAAO,EAAE,qBAAqB,EAAE,CAAA"}
@@ -1,21 +1,18 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.tasksListForContainer = void 0;
4
- const zod_1 = require("zod");
5
- const tool_helpers_1 = require("../tool-helpers");
1
+ import { z } from 'zod';
2
+ import { mapTask } from '../tool-helpers.js';
6
3
  const ArgsSchema = {
7
- type: zod_1.z
4
+ type: z
8
5
  .enum(['project', 'section', 'parent'])
9
6
  .describe('The type of container to get tasks for.'),
10
- id: zod_1.z.string().min(1).describe('The ID of the container to get tasks for.'),
11
- limit: zod_1.z
7
+ id: z.string().min(1).describe('The ID of the container to get tasks for.'),
8
+ limit: z
12
9
  .number()
13
10
  .int()
14
11
  .min(1)
15
12
  .max(50)
16
13
  .default(10)
17
14
  .describe('The maximum number of tasks to return.'),
18
- cursor: zod_1.z
15
+ cursor: z
19
16
  .string()
20
17
  .optional()
21
18
  .describe('The cursor to get the next page of tasks (cursor is obtained from the previous call to this tool, with the same parameters).'),
@@ -43,9 +40,9 @@ const tasksListForContainer = {
43
40
  }
44
41
  const { results, nextCursor } = await client.getTasks(taskParams);
45
42
  return {
46
- tasks: results.map(tool_helpers_1.mapTask),
43
+ tasks: results.map(mapTask),
47
44
  nextCursor,
48
45
  };
49
46
  },
50
47
  };
51
- exports.tasksListForContainer = tasksListForContainer;
48
+ export { tasksListForContainer };
@@ -1 +1 @@
1
- {"version":3,"file":"tasks-organize-multiple.d.ts","sourceRoot":"","sources":["../../src/tools/tasks-organize-multiple.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAevB,QAAA,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAYe,CAAA;AAE1C,OAAO,EAAE,qBAAqB,EAAE,CAAA"}
1
+ {"version":3,"file":"tasks-organize-multiple.d.ts","sourceRoot":"","sources":["../../src/tools/tasks-organize-multiple.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAgBvB,QAAA,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAwBe,CAAA;AAE1C,OAAO,EAAE,qBAAqB,EAAE,CAAA"}
@@ -1,16 +1,14 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.tasksOrganizeMultiple = void 0;
4
- const zod_1 = require("zod");
5
- const TaskUpdateSchema = zod_1.z.object({
6
- id: zod_1.z.string().min(1).describe('The ID of the task to update.'),
7
- projectId: zod_1.z.string().optional().describe('The new project ID for the task.'),
8
- sectionId: zod_1.z.string().optional().describe('The new section ID for the task.'),
9
- parentId: zod_1.z.string().optional().describe('The new parent task ID (for subtasks).'),
10
- order: zod_1.z.number().optional().describe('The new order of the task within its parent/section.'),
1
+ import { z } from 'zod';
2
+ import { createMoveTaskArgs } from '../tool-helpers.js';
3
+ const TaskUpdateSchema = z.object({
4
+ id: z.string().min(1).describe('The ID of the task to update.'),
5
+ projectId: z.string().optional().describe('The new project ID for the task.'),
6
+ sectionId: z.string().optional().describe('The new section ID for the task.'),
7
+ parentId: z.string().optional().describe('The new parent task ID (for subtasks).'),
8
+ order: z.number().optional().describe('The new order of the task within its parent/section.'),
11
9
  });
12
10
  const ArgsSchema = {
13
- tasks: zod_1.z.array(TaskUpdateSchema).min(1).describe('Array of task updates to apply.'),
11
+ tasks: z.array(TaskUpdateSchema).min(1).describe('Array of task updates to apply.'),
14
12
  };
15
13
  const tasksOrganizeMultiple = {
16
14
  name: 'tasks-organize-multiple',
@@ -18,11 +16,19 @@ const tasksOrganizeMultiple = {
18
16
  parameters: ArgsSchema,
19
17
  async execute(args, client) {
20
18
  const results = [];
19
+ // Process each task individually for move operations
21
20
  for (const update of args.tasks) {
22
- const { id, ...updateArgs } = update;
23
- results.push(await client.updateTask(id, updateArgs));
21
+ const { id, projectId, sectionId, parentId } = update;
22
+ if (!projectId && !sectionId && !parentId) {
23
+ continue;
24
+ }
25
+ // Create and validate move arguments using helper
26
+ const moveArgs = createMoveTaskArgs(id, projectId, sectionId, parentId);
27
+ // Move each task individually to avoid bulk operation issues
28
+ const movedTasks = await client.moveTasks([id], moveArgs);
29
+ results.push(...movedTasks);
24
30
  }
25
31
  return results;
26
32
  },
27
33
  };
28
- exports.tasksOrganizeMultiple = tasksOrganizeMultiple;
34
+ export { tasksOrganizeMultiple };
@@ -23,6 +23,7 @@ declare const tasksSearch: {
23
23
  sectionId: string | null;
24
24
  parentId: string | null;
25
25
  labels: string[];
26
+ duration: string | null;
26
27
  }[];
27
28
  nextCursor: string | null;
28
29
  }>;
@@ -1 +1 @@
1
- {"version":3,"file":"tasks-search.d.ts","sourceRoot":"","sources":["../../src/tools/tasks-search.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAqBvB,QAAA,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;CAYyB,CAAA;AAE1C,OAAO,EAAE,WAAW,EAAE,CAAA"}
1
+ {"version":3,"file":"tasks-search.d.ts","sourceRoot":"","sources":["../../src/tools/tasks-search.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAqBvB,QAAA,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAYyB,CAAA;AAE1C,OAAO,EAAE,WAAW,EAAE,CAAA"}
@@ -1,18 +1,15 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.tasksSearch = void 0;
4
- const zod_1 = require("zod");
5
- const tool_helpers_1 = require("../tool-helpers");
1
+ import { z } from 'zod';
2
+ import { getTasksByFilter } from '../tool-helpers.js';
6
3
  const ArgsSchema = {
7
- searchText: zod_1.z.string().min(1).describe('The text to search for in tasks.'),
8
- limit: zod_1.z
4
+ searchText: z.string().min(1).describe('The text to search for in tasks.'),
5
+ limit: z
9
6
  .number()
10
7
  .int()
11
8
  .min(1)
12
9
  .max(50)
13
10
  .default(10)
14
11
  .describe('The maximum number of tasks to return.'),
15
- cursor: zod_1.z
12
+ cursor: z
16
13
  .string()
17
14
  .optional()
18
15
  .describe('The cursor to get the next page of tasks (cursor is obtained from the previous call to this tool, with the same parameters).'),
@@ -22,7 +19,7 @@ const tasksSearch = {
22
19
  description: "Search tasks by text using Todoist's filter query.",
23
20
  parameters: ArgsSchema,
24
21
  async execute(args, client) {
25
- return await (0, tool_helpers_1.getTasksByFilter)({
22
+ return await getTasksByFilter({
26
23
  client,
27
24
  query: `search: ${args.searchText}`,
28
25
  cursor: args.cursor,
@@ -30,4 +27,4 @@ const tasksSearch = {
30
27
  });
31
28
  },
32
29
  };
33
- exports.tasksSearch = tasksSearch;
30
+ export { tasksSearch };
@@ -11,6 +11,7 @@ declare const tasksUpdateOne: {
11
11
  parentId: z.ZodOptional<z.ZodString>;
12
12
  priority: z.ZodOptional<z.ZodNumber>;
13
13
  dueString: z.ZodOptional<z.ZodString>;
14
+ duration: z.ZodOptional<z.ZodString>;
14
15
  };
15
16
  execute(args: {
16
17
  id: string;
@@ -18,10 +19,11 @@ declare const tasksUpdateOne: {
18
19
  description?: string | undefined;
19
20
  parentId?: string | undefined;
20
21
  projectId?: string | undefined;
22
+ sectionId?: string | undefined;
21
23
  priority?: number | undefined;
22
24
  dueString?: string | undefined;
23
- sectionId?: string | undefined;
24
- }, client: import("@doist/todoist-api-typescript").TodoistApi): Promise<import("@doist/todoist-api-typescript").Task>;
25
+ duration?: string | undefined;
26
+ }, client: import("@doist/todoist-api-typescript").TodoistApi): Promise<import("@doist/todoist-api-typescript").Task | undefined>;
25
27
  };
26
28
  export { tasksUpdateOne };
27
29
  //# sourceMappingURL=tasks-update-one.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"tasks-update-one.d.ts","sourceRoot":"","sources":["../../src/tools/tasks-update-one.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAuBvB,QAAA,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;CAQsB,CAAA;AAE1C,OAAO,EAAE,cAAc,EAAE,CAAA"}
1
+ {"version":3,"file":"tasks-update-one.d.ts","sourceRoot":"","sources":["../../src/tools/tasks-update-one.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AA+BvB,QAAA,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;CA+CsB,CAAA;AAE1C,OAAO,EAAE,cAAc,EAAE,CAAA"}
@@ -1,33 +1,63 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.tasksUpdateOne = void 0;
4
- const zod_1 = require("zod");
1
+ import { z } from 'zod';
2
+ import { createMoveTaskArgs } from '../tool-helpers.js';
3
+ import { DurationParseError, parseDuration } from '../utils/duration-parser.js';
5
4
  const ArgsSchema = {
6
- id: zod_1.z.string().min(1).describe('The ID of the task to update.'),
7
- content: zod_1.z.string().optional().describe('The new content of the task.'),
8
- description: zod_1.z.string().optional().describe('The new description of the task.'),
9
- projectId: zod_1.z.string().optional().describe('The new project ID for the task.'),
10
- sectionId: zod_1.z.string().optional().describe('The new section ID for the task.'),
11
- parentId: zod_1.z.string().optional().describe('The new parent task ID (for subtasks).'),
12
- priority: zod_1.z
5
+ id: z.string().min(1).describe('The ID of the task to update.'),
6
+ content: z.string().optional().describe('The new content of the task.'),
7
+ description: z.string().optional().describe('The new description of the task.'),
8
+ projectId: z.string().optional().describe('The new project ID for the task.'),
9
+ sectionId: z.string().optional().describe('The new section ID for the task.'),
10
+ parentId: z.string().optional().describe('The new parent task ID (for subtasks).'),
11
+ priority: z
13
12
  .number()
14
13
  .int()
15
14
  .min(1)
16
15
  .max(4)
17
16
  .optional()
18
17
  .describe('The new priority of the task (1-4).'),
19
- dueString: zod_1.z
18
+ dueString: z
20
19
  .string()
21
20
  .optional()
22
21
  .describe("The new due date for the task, in natural language (e.g., 'tomorrow at 5pm')."),
22
+ duration: z
23
+ .string()
24
+ .optional()
25
+ .describe('The duration of the task. Use format: "2h" (hours), "90m" (minutes), "2h30m" (combined), or "1.5h" (decimal hours). Max 24h.'),
23
26
  };
24
27
  const tasksUpdateOne = {
25
28
  name: 'tasks-update-one',
26
29
  description: 'Update an existing task with new values.',
27
30
  parameters: ArgsSchema,
28
31
  async execute(args, client) {
29
- const { id, ...updateArgs } = args;
30
- return await client.updateTask(id, updateArgs);
32
+ const { id, projectId, sectionId, parentId, duration: durationStr, ...otherUpdateArgs } = args;
33
+ let updateArgs = { ...otherUpdateArgs };
34
+ // Parse duration if provided
35
+ if (durationStr) {
36
+ try {
37
+ const { minutes } = parseDuration(durationStr);
38
+ updateArgs = {
39
+ ...updateArgs,
40
+ duration: minutes,
41
+ durationUnit: 'minute',
42
+ };
43
+ }
44
+ catch (error) {
45
+ if (error instanceof DurationParseError) {
46
+ throw new Error(`Task ${id}: ${error.message}`);
47
+ }
48
+ throw error;
49
+ }
50
+ }
51
+ // If no move parameters are provided, use updateTask without moveTasks
52
+ if (!projectId && !sectionId && !parentId) {
53
+ return await client.updateTask(id, updateArgs);
54
+ }
55
+ const moveArgs = createMoveTaskArgs(id, projectId, sectionId, parentId);
56
+ const movedTasks = await client.moveTasks([id], moveArgs);
57
+ if (Object.keys(updateArgs).length > 0) {
58
+ return await client.updateTask(id, updateArgs);
59
+ }
60
+ return movedTasks[0];
31
61
  },
32
62
  };
33
- exports.tasksUpdateOne = tasksUpdateOne;
63
+ export { tasksUpdateOne };
@@ -0,0 +1,80 @@
1
+ import type { PersonalProject, Section, Task } from '@doist/todoist-api-typescript';
2
+ /**
3
+ * Mapped task type matching the output of mapTask function.
4
+ * Used for filter-based query test mocks.
5
+ */
6
+ export type MappedTask = {
7
+ id: string;
8
+ content: string;
9
+ description: string;
10
+ dueDate: string | undefined;
11
+ recurring: string | boolean;
12
+ priority: number;
13
+ projectId: string;
14
+ sectionId: string | null;
15
+ parentId: string | null;
16
+ labels: string[];
17
+ duration: string | null;
18
+ };
19
+ /**
20
+ * Creates a mock Task with all required properties and sensible defaults.
21
+ * Pass only the properties you want to override for your specific test.
22
+ */
23
+ export declare function createMockTask(overrides?: Partial<Task>): Task;
24
+ /**
25
+ * Creates a mock Section with all required properties and sensible defaults.
26
+ * Pass only the properties you want to override for your specific test.
27
+ */
28
+ export declare function createMockSection(overrides?: Partial<Section>): Section;
29
+ /**
30
+ * Creates a mock PersonalProject with all required properties and sensible defaults.
31
+ * Pass only the properties you want to override for your specific test.
32
+ */
33
+ export declare function createMockProject(overrides?: Partial<PersonalProject>): PersonalProject;
34
+ /**
35
+ * Creates a mock API response object with results and nextCursor.
36
+ */
37
+ export declare function createMockApiResponse<T>(results: T[], nextCursor?: string | null): {
38
+ results: T[];
39
+ nextCursor: string | null;
40
+ };
41
+ /**
42
+ * Creates a simplified mapped task (matches mapTask output) for filter-based query tests.
43
+ */
44
+ export declare function createMappedTask(overrides?: Partial<MappedTask>): MappedTask;
45
+ /**
46
+ * Common error messages used across tests.
47
+ */
48
+ export declare const TEST_ERRORS: {
49
+ readonly API_RATE_LIMIT: "API Error: Rate limit exceeded";
50
+ readonly API_UNAUTHORIZED: "API Error: Unauthorized";
51
+ readonly INVALID_CURSOR: "Invalid cursor format";
52
+ readonly INVALID_FILTER: "Invalid filter query";
53
+ };
54
+ /**
55
+ * Creates multiple test cases for parameterized testing.
56
+ */
57
+ export declare function createTestCases<T, E = unknown>(cases: Array<{
58
+ name: string;
59
+ input: T;
60
+ expected?: E;
61
+ }>): {
62
+ name: string;
63
+ input: T;
64
+ expected?: E;
65
+ }[];
66
+ /**
67
+ * Common mock IDs used across tests for consistency.
68
+ */
69
+ export declare const TEST_IDS: {
70
+ readonly TASK_1: "8485093748";
71
+ readonly TASK_2: "8485093749";
72
+ readonly TASK_3: "8485093750";
73
+ readonly PROJECT_INBOX: "inbox-project-id";
74
+ readonly PROJECT_WORK: "work-project-id";
75
+ readonly PROJECT_TEST: "6cfCcrrCFg2xP94Q";
76
+ readonly SECTION_1: "section-123";
77
+ readonly SECTION_2: "section-456";
78
+ readonly USER_ID: "713437";
79
+ };
80
+ //# sourceMappingURL=test-helpers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test-helpers.d.ts","sourceRoot":"","sources":["../../src/tools/test-helpers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,+BAA+B,CAAA;AAEnF;;;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;CAC1B,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,CAe3E;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,CAehF;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;;GAEG;AACH,eAAO,MAAM,QAAQ;;;;;;;;;;CAUX,CAAA"}
@@ -0,0 +1,140 @@
1
+ /**
2
+ * Creates a mock Task with all required properties and sensible defaults.
3
+ * Pass only the properties you want to override for your specific test.
4
+ */
5
+ export function createMockTask(overrides = {}) {
6
+ return {
7
+ id: '8485093748',
8
+ content: 'Test task content',
9
+ description: '',
10
+ completedAt: null,
11
+ labels: [],
12
+ childOrder: 1,
13
+ priority: 1,
14
+ projectId: '6cfCcrrCFg2xP94Q',
15
+ sectionId: null,
16
+ parentId: null,
17
+ url: 'https://todoist.com/showTask?id=8485093748',
18
+ // Use correct property names from Task schema
19
+ noteCount: 0,
20
+ addedByUid: '713437',
21
+ addedAt: '2025-08-13T22:09:56.123456Z',
22
+ deadline: null,
23
+ responsibleUid: null,
24
+ assignedByUid: null,
25
+ isCollapsed: false,
26
+ isDeleted: false,
27
+ duration: null,
28
+ checked: false,
29
+ updatedAt: '2025-08-13T22:09:56.123456Z',
30
+ due: null,
31
+ dayOrder: 0,
32
+ userId: '713437',
33
+ ...overrides,
34
+ };
35
+ }
36
+ /**
37
+ * Creates a mock Section with all required properties and sensible defaults.
38
+ * Pass only the properties you want to override for your specific test.
39
+ */
40
+ export function createMockSection(overrides = {}) {
41
+ return {
42
+ id: 'section-123',
43
+ projectId: '6cfCcrrCFg2xP94Q',
44
+ sectionOrder: 1,
45
+ userId: 'test-user',
46
+ addedAt: '2024-01-01T00:00:00Z',
47
+ updatedAt: '2024-01-01T00:00:00Z',
48
+ archivedAt: null,
49
+ isArchived: false,
50
+ isDeleted: false,
51
+ isCollapsed: false,
52
+ name: 'Test Section',
53
+ ...overrides,
54
+ };
55
+ }
56
+ /**
57
+ * Creates a mock PersonalProject with all required properties and sensible defaults.
58
+ * Pass only the properties you want to override for your specific test.
59
+ */
60
+ export function createMockProject(overrides = {}) {
61
+ return {
62
+ id: '6cfCcrrCFg2xP94Q',
63
+ name: 'Test Project',
64
+ color: 'charcoal',
65
+ isFavorite: false,
66
+ isShared: false,
67
+ parentId: null,
68
+ inboxProject: false,
69
+ viewStyle: 'list',
70
+ url: 'https://todoist.com/projects/6cfCcrrCFg2xP94Q',
71
+ isDeleted: false,
72
+ updatedAt: '2025-08-13T22:09:55.841800Z',
73
+ createdAt: '2025-08-13T22:09:55.841785Z',
74
+ childOrder: 1,
75
+ defaultOrder: 0,
76
+ description: '',
77
+ isCollapsed: false,
78
+ canAssignTasks: false,
79
+ isFrozen: false,
80
+ isArchived: false,
81
+ ...overrides,
82
+ };
83
+ }
84
+ /**
85
+ * Creates a mock API response object with results and nextCursor.
86
+ */
87
+ export function createMockApiResponse(results, nextCursor = null) {
88
+ return {
89
+ results,
90
+ nextCursor,
91
+ };
92
+ }
93
+ /**
94
+ * Creates a simplified mapped task (matches mapTask output) for filter-based query tests.
95
+ */
96
+ export function createMappedTask(overrides = {}) {
97
+ return {
98
+ id: TEST_IDS.TASK_1,
99
+ content: 'Test task content',
100
+ description: '',
101
+ dueDate: undefined,
102
+ recurring: false,
103
+ priority: 1,
104
+ projectId: TEST_IDS.PROJECT_TEST,
105
+ sectionId: null,
106
+ parentId: null,
107
+ labels: [],
108
+ duration: null,
109
+ ...overrides,
110
+ };
111
+ }
112
+ /**
113
+ * Common error messages used across tests.
114
+ */
115
+ export const TEST_ERRORS = {
116
+ API_RATE_LIMIT: 'API Error: Rate limit exceeded',
117
+ API_UNAUTHORIZED: 'API Error: Unauthorized',
118
+ INVALID_CURSOR: 'Invalid cursor format',
119
+ INVALID_FILTER: 'Invalid filter query',
120
+ };
121
+ /**
122
+ * Creates multiple test cases for parameterized testing.
123
+ */
124
+ export function createTestCases(cases) {
125
+ return cases;
126
+ }
127
+ /**
128
+ * Common mock IDs used across tests for consistency.
129
+ */
130
+ export const TEST_IDS = {
131
+ TASK_1: '8485093748',
132
+ TASK_2: '8485093749',
133
+ TASK_3: '8485093750',
134
+ PROJECT_INBOX: 'inbox-project-id',
135
+ PROJECT_WORK: 'work-project-id',
136
+ PROJECT_TEST: '6cfCcrrCFg2xP94Q',
137
+ SECTION_1: 'section-123',
138
+ SECTION_2: 'section-456',
139
+ USER_ID: '713437',
140
+ };
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Duration parser utility for converting human-readable duration strings
3
+ * to minutes using a restricted, language-neutral syntax.
4
+ *
5
+ * Supported formats:
6
+ * - "2h" (hours only)
7
+ * - "90m" (minutes only)
8
+ * - "2h30m" (hours + minutes)
9
+ * - "1.5h" (decimal hours)
10
+ * - Supports optional spaces: "2h 30m"
11
+ */
12
+ interface ParsedDuration {
13
+ minutes: number;
14
+ }
15
+ export declare class DurationParseError extends Error {
16
+ constructor(input: string, reason: string);
17
+ }
18
+ /**
19
+ * Parses duration string in restricted syntax to minutes.
20
+ * Max duration: 1440 minutes (24 hours)
21
+ *
22
+ * @param durationStr - Duration string like "2h30m", "45m", "1.5h"
23
+ * @returns Parsed duration in minutes
24
+ * @throws DurationParseError for invalid formats
25
+ */
26
+ export declare function parseDuration(durationStr: string): ParsedDuration;
27
+ /**
28
+ * Formats minutes back to a human-readable duration string.
29
+ * Used when returning task data to LLMs.
30
+ *
31
+ * @param minutes - Duration in minutes
32
+ * @returns Formatted duration string like "2h30m" or "45m"
33
+ */
34
+ export declare function formatDuration(minutes: number): string;
35
+ export {};
36
+ //# sourceMappingURL=duration-parser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"duration-parser.d.ts","sourceRoot":"","sources":["../../src/utils/duration-parser.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,UAAU,cAAc;IACpB,OAAO,EAAE,MAAM,CAAA;CAClB;AAED,qBAAa,kBAAmB,SAAQ,KAAK;gBAC7B,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;CAI5C;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,WAAW,EAAE,MAAM,GAAG,cAAc,CAgEjE;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAetD"}