@doist/todoist-ai 2.2.2 → 4.0.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 (202) hide show
  1. package/README.md +6 -14
  2. package/dist/index.d.ts +619 -250
  3. package/dist/index.d.ts.map +1 -1
  4. package/dist/index.js +45 -29
  5. package/dist/main.js +2 -1
  6. package/dist/mcp-helpers.d.ts +25 -3
  7. package/dist/mcp-helpers.d.ts.map +1 -1
  8. package/dist/mcp-helpers.js +37 -19
  9. package/dist/mcp-server.d.ts.map +1 -1
  10. package/dist/mcp-server.js +44 -28
  11. package/dist/tools/__tests__/add-comments.test.d.ts +2 -0
  12. package/dist/tools/__tests__/add-comments.test.d.ts.map +1 -0
  13. package/dist/tools/__tests__/add-comments.test.js +241 -0
  14. package/dist/tools/__tests__/add-projects.test.d.ts +2 -0
  15. package/dist/tools/__tests__/add-projects.test.d.ts.map +1 -0
  16. package/dist/tools/__tests__/add-projects.test.js +152 -0
  17. package/dist/tools/__tests__/add-sections.test.d.ts +2 -0
  18. package/dist/tools/__tests__/add-sections.test.d.ts.map +1 -0
  19. package/dist/tools/__tests__/add-sections.test.js +181 -0
  20. package/dist/tools/__tests__/add-tasks.test.d.ts +2 -0
  21. package/dist/tools/__tests__/add-tasks.test.d.ts.map +1 -0
  22. package/dist/tools/__tests__/{tasks-add-multiple.test.js → add-tasks.test.js} +89 -79
  23. package/dist/tools/__tests__/complete-tasks.test.d.ts +2 -0
  24. package/dist/tools/__tests__/complete-tasks.test.d.ts.map +1 -0
  25. package/dist/tools/__tests__/complete-tasks.test.js +206 -0
  26. package/dist/tools/__tests__/delete-object.test.d.ts +2 -0
  27. package/dist/tools/__tests__/delete-object.test.d.ts.map +1 -0
  28. package/dist/tools/__tests__/{delete-one.test.js → delete-object.test.js} +42 -22
  29. package/dist/tools/__tests__/find-comments.test.d.ts +2 -0
  30. package/dist/tools/__tests__/find-comments.test.d.ts.map +1 -0
  31. package/dist/tools/__tests__/find-comments.test.js +242 -0
  32. package/dist/tools/__tests__/find-completed-tasks.test.d.ts +2 -0
  33. package/dist/tools/__tests__/find-completed-tasks.test.d.ts.map +1 -0
  34. package/dist/tools/__tests__/{tasks-list-completed.test.js → find-completed-tasks.test.js} +13 -36
  35. package/dist/tools/__tests__/find-projects.test.d.ts +2 -0
  36. package/dist/tools/__tests__/find-projects.test.d.ts.map +1 -0
  37. package/dist/tools/__tests__/{projects-list.test.js → find-projects.test.js} +55 -39
  38. package/dist/tools/__tests__/find-sections.test.d.ts +2 -0
  39. package/dist/tools/__tests__/find-sections.test.d.ts.map +1 -0
  40. package/dist/tools/__tests__/{sections-search.test.js → find-sections.test.js} +64 -50
  41. package/dist/tools/__tests__/find-tasks-by-date.test.d.ts +2 -0
  42. package/dist/tools/__tests__/find-tasks-by-date.test.d.ts.map +1 -0
  43. package/dist/tools/__tests__/{tasks-list-by-date.test.js → find-tasks-by-date.test.js} +96 -14
  44. package/dist/tools/__tests__/find-tasks.test.d.ts +2 -0
  45. package/dist/tools/__tests__/find-tasks.test.d.ts.map +1 -0
  46. package/dist/tools/__tests__/find-tasks.test.js +334 -0
  47. package/dist/tools/__tests__/get-overview.test.d.ts +2 -0
  48. package/dist/tools/__tests__/get-overview.test.d.ts.map +1 -0
  49. package/dist/tools/__tests__/{overview.test.js → get-overview.test.js} +77 -13
  50. package/dist/tools/__tests__/update-comments.test.d.ts +2 -0
  51. package/dist/tools/__tests__/update-comments.test.d.ts.map +1 -0
  52. package/dist/tools/__tests__/update-comments.test.js +296 -0
  53. package/dist/tools/__tests__/update-projects.test.d.ts +2 -0
  54. package/dist/tools/__tests__/update-projects.test.d.ts.map +1 -0
  55. package/dist/tools/__tests__/update-projects.test.js +205 -0
  56. package/dist/tools/__tests__/update-sections.test.d.ts +2 -0
  57. package/dist/tools/__tests__/update-sections.test.d.ts.map +1 -0
  58. package/dist/tools/__tests__/update-sections.test.js +156 -0
  59. package/dist/tools/__tests__/update-tasks.test.d.ts +2 -0
  60. package/dist/tools/__tests__/update-tasks.test.d.ts.map +1 -0
  61. package/dist/tools/__tests__/update-tasks.test.js +645 -0
  62. package/dist/tools/add-comments.d.ts +51 -0
  63. package/dist/tools/add-comments.d.ts.map +1 -0
  64. package/dist/tools/add-comments.js +79 -0
  65. package/dist/tools/add-projects.d.ts +50 -0
  66. package/dist/tools/add-projects.d.ts.map +1 -0
  67. package/dist/tools/add-projects.js +59 -0
  68. package/dist/tools/add-sections.d.ts +46 -0
  69. package/dist/tools/add-sections.d.ts.map +1 -0
  70. package/dist/tools/add-sections.js +61 -0
  71. package/dist/tools/add-tasks.d.ts +82 -0
  72. package/dist/tools/add-tasks.d.ts.map +1 -0
  73. package/dist/tools/add-tasks.js +96 -0
  74. package/dist/tools/complete-tasks.d.ts +40 -0
  75. package/dist/tools/complete-tasks.d.ts.map +1 -0
  76. package/dist/tools/complete-tasks.js +68 -0
  77. package/dist/tools/delete-object.d.ts +38 -0
  78. package/dist/tools/delete-object.d.ts.map +1 -0
  79. package/dist/tools/delete-object.js +79 -0
  80. package/dist/tools/find-comments.d.ts +46 -0
  81. package/dist/tools/find-comments.d.ts.map +1 -0
  82. package/dist/tools/find-comments.js +143 -0
  83. package/dist/tools/find-completed-tasks.d.ts +74 -0
  84. package/dist/tools/find-completed-tasks.d.ts.map +1 -0
  85. package/dist/tools/find-completed-tasks.js +112 -0
  86. package/dist/tools/find-projects.d.ts +53 -0
  87. package/dist/tools/find-projects.d.ts.map +1 -0
  88. package/dist/tools/find-projects.js +101 -0
  89. package/dist/tools/find-sections.d.ts +42 -0
  90. package/dist/tools/find-sections.d.ts.map +1 -0
  91. package/dist/tools/find-sections.js +96 -0
  92. package/dist/tools/find-tasks-by-date.d.ts +59 -0
  93. package/dist/tools/find-tasks-by-date.d.ts.map +1 -0
  94. package/dist/tools/find-tasks-by-date.js +121 -0
  95. package/dist/tools/find-tasks.d.ts +65 -0
  96. package/dist/tools/find-tasks.d.ts.map +1 -0
  97. package/dist/tools/find-tasks.js +182 -0
  98. package/dist/tools/get-overview.d.ts +67 -0
  99. package/dist/tools/get-overview.d.ts.map +1 -0
  100. package/dist/tools/{overview.js → get-overview.js} +66 -19
  101. package/dist/tools/update-comments.d.ts +50 -0
  102. package/dist/tools/update-comments.d.ts.map +1 -0
  103. package/dist/tools/update-comments.js +82 -0
  104. package/dist/tools/update-projects.d.ts +59 -0
  105. package/dist/tools/update-projects.d.ts.map +1 -0
  106. package/dist/tools/update-projects.js +84 -0
  107. package/dist/tools/update-sections.d.ts +47 -0
  108. package/dist/tools/update-sections.d.ts.map +1 -0
  109. package/dist/tools/update-sections.js +70 -0
  110. package/dist/tools/update-tasks.d.ts +94 -0
  111. package/dist/tools/update-tasks.d.ts.map +1 -0
  112. package/dist/tools/update-tasks.js +120 -0
  113. package/dist/utils/constants.d.ts +39 -0
  114. package/dist/utils/constants.d.ts.map +1 -0
  115. package/dist/utils/constants.js +41 -0
  116. package/dist/utils/response-builders.d.ts +88 -0
  117. package/dist/utils/response-builders.d.ts.map +1 -0
  118. package/dist/utils/response-builders.js +202 -0
  119. package/dist/{tools → utils}/test-helpers.d.ts +16 -0
  120. package/dist/utils/test-helpers.d.ts.map +1 -0
  121. package/dist/{tools → utils}/test-helpers.js +51 -0
  122. package/dist/utils/tool-names.d.ts +28 -0
  123. package/dist/utils/tool-names.d.ts.map +1 -0
  124. package/dist/utils/tool-names.js +31 -0
  125. package/package.json +1 -1
  126. package/dist/tools/__tests__/delete-one.test.d.ts +0 -2
  127. package/dist/tools/__tests__/delete-one.test.d.ts.map +0 -1
  128. package/dist/tools/__tests__/overview.test.d.ts +0 -2
  129. package/dist/tools/__tests__/overview.test.d.ts.map +0 -1
  130. package/dist/tools/__tests__/projects-list.test.d.ts +0 -2
  131. package/dist/tools/__tests__/projects-list.test.d.ts.map +0 -1
  132. package/dist/tools/__tests__/projects-manage.test.d.ts +0 -2
  133. package/dist/tools/__tests__/projects-manage.test.d.ts.map +0 -1
  134. package/dist/tools/__tests__/projects-manage.test.js +0 -106
  135. package/dist/tools/__tests__/sections-manage.test.d.ts +0 -2
  136. package/dist/tools/__tests__/sections-manage.test.d.ts.map +0 -1
  137. package/dist/tools/__tests__/sections-manage.test.js +0 -138
  138. package/dist/tools/__tests__/sections-search.test.d.ts +0 -2
  139. package/dist/tools/__tests__/sections-search.test.d.ts.map +0 -1
  140. package/dist/tools/__tests__/tasks-add-multiple.test.d.ts +0 -2
  141. package/dist/tools/__tests__/tasks-add-multiple.test.d.ts.map +0 -1
  142. package/dist/tools/__tests__/tasks-complete-multiple.test.d.ts +0 -2
  143. package/dist/tools/__tests__/tasks-complete-multiple.test.d.ts.map +0 -1
  144. package/dist/tools/__tests__/tasks-complete-multiple.test.js +0 -146
  145. package/dist/tools/__tests__/tasks-list-by-date.test.d.ts +0 -2
  146. package/dist/tools/__tests__/tasks-list-by-date.test.d.ts.map +0 -1
  147. package/dist/tools/__tests__/tasks-list-completed.test.d.ts +0 -2
  148. package/dist/tools/__tests__/tasks-list-completed.test.d.ts.map +0 -1
  149. package/dist/tools/__tests__/tasks-list-for-container.test.d.ts +0 -2
  150. package/dist/tools/__tests__/tasks-list-for-container.test.d.ts.map +0 -1
  151. package/dist/tools/__tests__/tasks-list-for-container.test.js +0 -232
  152. package/dist/tools/__tests__/tasks-organize-multiple.test.d.ts +0 -2
  153. package/dist/tools/__tests__/tasks-organize-multiple.test.d.ts.map +0 -1
  154. package/dist/tools/__tests__/tasks-organize-multiple.test.js +0 -245
  155. package/dist/tools/__tests__/tasks-search.test.d.ts +0 -2
  156. package/dist/tools/__tests__/tasks-search.test.d.ts.map +0 -1
  157. package/dist/tools/__tests__/tasks-search.test.js +0 -106
  158. package/dist/tools/__tests__/tasks-update-one.test.d.ts +0 -2
  159. package/dist/tools/__tests__/tasks-update-one.test.d.ts.map +0 -1
  160. package/dist/tools/__tests__/tasks-update-one.test.js +0 -251
  161. package/dist/tools/delete-one.d.ts +0 -17
  162. package/dist/tools/delete-one.d.ts.map +0 -1
  163. package/dist/tools/delete-one.js +0 -25
  164. package/dist/tools/overview.d.ts +0 -14
  165. package/dist/tools/overview.d.ts.map +0 -1
  166. package/dist/tools/projects-list.d.ts +0 -29
  167. package/dist/tools/projects-list.d.ts.map +0 -1
  168. package/dist/tools/projects-list.js +0 -39
  169. package/dist/tools/projects-manage.d.ts +0 -24
  170. package/dist/tools/projects-manage.d.ts.map +0 -1
  171. package/dist/tools/projects-manage.js +0 -26
  172. package/dist/tools/sections-manage.d.ts +0 -23
  173. package/dist/tools/sections-manage.d.ts.map +0 -1
  174. package/dist/tools/sections-manage.js +0 -37
  175. package/dist/tools/sections-search.d.ts +0 -18
  176. package/dist/tools/sections-search.d.ts.map +0 -1
  177. package/dist/tools/sections-search.js +0 -27
  178. package/dist/tools/tasks-add-multiple.d.ts +0 -55
  179. package/dist/tools/tasks-add-multiple.d.ts.map +0 -1
  180. package/dist/tools/tasks-add-multiple.js +0 -52
  181. package/dist/tools/tasks-complete-multiple.d.ts +0 -16
  182. package/dist/tools/tasks-complete-multiple.d.ts.map +0 -1
  183. package/dist/tools/tasks-complete-multiple.js +0 -23
  184. package/dist/tools/tasks-list-by-date.d.ts +0 -34
  185. package/dist/tools/tasks-list-by-date.d.ts.map +0 -1
  186. package/dist/tools/tasks-list-by-date.js +0 -53
  187. package/dist/tools/tasks-list-completed.d.ts +0 -44
  188. package/dist/tools/tasks-list-completed.d.ts.map +0 -1
  189. package/dist/tools/tasks-list-completed.js +0 -49
  190. package/dist/tools/tasks-list-for-container.d.ts +0 -34
  191. package/dist/tools/tasks-list-for-container.d.ts.map +0 -1
  192. package/dist/tools/tasks-list-for-container.js +0 -48
  193. package/dist/tools/tasks-organize-multiple.d.ts +0 -37
  194. package/dist/tools/tasks-organize-multiple.d.ts.map +0 -1
  195. package/dist/tools/tasks-organize-multiple.js +0 -34
  196. package/dist/tools/tasks-search.d.ts +0 -32
  197. package/dist/tools/tasks-search.d.ts.map +0 -1
  198. package/dist/tools/tasks-search.js +0 -30
  199. package/dist/tools/tasks-update-one.d.ts +0 -29
  200. package/dist/tools/tasks-update-one.d.ts.map +0 -1
  201. package/dist/tools/tasks-update-one.js +0 -63
  202. package/dist/tools/test-helpers.d.ts.map +0 -1
@@ -0,0 +1,38 @@
1
+ import { z } from 'zod';
2
+ declare const deleteObject: {
3
+ name: "delete-object";
4
+ description: string;
5
+ parameters: {
6
+ type: z.ZodEnum<["project", "section", "task", "comment"]>;
7
+ id: z.ZodString;
8
+ };
9
+ execute(args: {
10
+ type: "task" | "comment" | "project" | "section";
11
+ id: string;
12
+ }, client: import("@doist/todoist-api-typescript").TodoistApi): Promise<{
13
+ content: {
14
+ type: "text";
15
+ text: string;
16
+ }[];
17
+ structuredContent: {
18
+ deletedEntity: {
19
+ type: "task" | "comment" | "project" | "section";
20
+ id: string;
21
+ };
22
+ success: boolean;
23
+ };
24
+ } | {
25
+ content: ({
26
+ type: "text";
27
+ text: string;
28
+ mimeType?: undefined;
29
+ } | {
30
+ type: "text";
31
+ mimeType: string;
32
+ text: string;
33
+ })[];
34
+ structuredContent?: undefined;
35
+ }>;
36
+ };
37
+ export { deleteObject };
38
+ //# sourceMappingURL=delete-object.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"delete-object.d.ts","sourceRoot":"","sources":["../../src/tools/delete-object.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAsBvB,QAAA,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAoCwB,CAAA;AA+C1C,OAAO,EAAE,YAAY,EAAE,CAAA"}
@@ -0,0 +1,79 @@
1
+ import { z } from 'zod';
2
+ import { getToolOutput } from '../mcp-helpers.js';
3
+ import { formatNextSteps } from '../utils/response-builders.js';
4
+ import { ToolNames } from '../utils/tool-names.js';
5
+ const { FIND_PROJECTS, GET_OVERVIEW, FIND_SECTIONS, FIND_TASKS, FIND_TASKS_BY_DATE, FIND_COMMENTS, } = ToolNames;
6
+ const ArgsSchema = {
7
+ type: z
8
+ .enum(['project', 'section', 'task', 'comment'])
9
+ .describe('The type of entity to delete.'),
10
+ id: z.string().min(1).describe('The ID of the entity to delete.'),
11
+ };
12
+ const deleteObject = {
13
+ name: ToolNames.DELETE_OBJECT,
14
+ description: 'Delete a project, section, task, or comment by its ID.',
15
+ parameters: ArgsSchema,
16
+ async execute(args, client) {
17
+ switch (args.type) {
18
+ case 'project':
19
+ await client.deleteProject(args.id);
20
+ break;
21
+ case 'section':
22
+ await client.deleteSection(args.id);
23
+ break;
24
+ case 'task':
25
+ await client.deleteTask(args.id);
26
+ break;
27
+ case 'comment':
28
+ await client.deleteComment(args.id);
29
+ break;
30
+ }
31
+ const textContent = generateTextContent({
32
+ type: args.type,
33
+ id: args.id,
34
+ });
35
+ return getToolOutput({
36
+ textContent,
37
+ structuredContent: {
38
+ deletedEntity: {
39
+ type: args.type,
40
+ id: args.id,
41
+ },
42
+ success: true,
43
+ },
44
+ });
45
+ },
46
+ };
47
+ function generateTextContent({ type, id, }) {
48
+ const summary = `Deleted ${type}: id=${id}`;
49
+ // Recovery-focused next steps based on what was deleted
50
+ const nextSteps = [];
51
+ switch (type) {
52
+ case 'project':
53
+ // Help user understand impact and navigate remaining work
54
+ nextSteps.push(`Use ${FIND_PROJECTS} to see remaining projects`);
55
+ nextSteps.push('Note: All tasks and sections in this project were also deleted');
56
+ nextSteps.push(`Use ${GET_OVERVIEW} to review your updated project structure`);
57
+ break;
58
+ case 'section':
59
+ // Guide user to reorganize remaining sections and tasks
60
+ nextSteps.push(`Use ${FIND_SECTIONS} to see remaining sections in the project`);
61
+ nextSteps.push('Note: Tasks in this section were also deleted');
62
+ nextSteps.push(`Use ${FIND_TASKS} with projectId to see unorganized tasks`);
63
+ break;
64
+ case 'task':
65
+ // Help user stay focused on remaining work
66
+ nextSteps.push(`Use ${FIND_TASKS_BY_DATE} to see remaining tasks for today`);
67
+ nextSteps.push(`Use ${GET_OVERVIEW} to check if this affects any dependent tasks`);
68
+ nextSteps.push('Note: Any subtasks of this task were also deleted');
69
+ break;
70
+ case 'comment':
71
+ // Help user understand comment deletion impact
72
+ nextSteps.push(`Use ${FIND_COMMENTS} to see remaining comments on the task/project`);
73
+ nextSteps.push('Note: Comment attachments were also deleted');
74
+ break;
75
+ }
76
+ const next = formatNextSteps(nextSteps);
77
+ return `${summary}\n${next}`;
78
+ }
79
+ export { deleteObject };
@@ -0,0 +1,46 @@
1
+ import type { Comment } from '@doist/todoist-api-typescript';
2
+ import { z } from 'zod';
3
+ declare const findComments: {
4
+ name: "find-comments";
5
+ description: string;
6
+ parameters: {
7
+ taskId: z.ZodOptional<z.ZodString>;
8
+ projectId: z.ZodOptional<z.ZodString>;
9
+ commentId: z.ZodOptional<z.ZodString>;
10
+ cursor: z.ZodOptional<z.ZodString>;
11
+ limit: z.ZodOptional<z.ZodNumber>;
12
+ };
13
+ execute(args: {
14
+ projectId?: string | undefined;
15
+ limit?: number | undefined;
16
+ cursor?: string | undefined;
17
+ taskId?: string | undefined;
18
+ commentId?: string | undefined;
19
+ }, client: import("@doist/todoist-api-typescript").TodoistApi): Promise<{
20
+ content: {
21
+ type: "text";
22
+ text: string;
23
+ }[];
24
+ structuredContent: {
25
+ comments: Comment[];
26
+ searchType: string;
27
+ searchId: string;
28
+ hasMore: boolean;
29
+ nextCursor: string | null;
30
+ totalCount: number;
31
+ };
32
+ } | {
33
+ content: ({
34
+ type: "text";
35
+ text: string;
36
+ mimeType?: undefined;
37
+ } | {
38
+ type: "text";
39
+ mimeType: string;
40
+ text: string;
41
+ })[];
42
+ structuredContent?: undefined;
43
+ }>;
44
+ };
45
+ export { findComments };
46
+ //# sourceMappingURL=find-comments.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"find-comments.d.ts","sourceRoot":"","sources":["../../src/tools/find-comments.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,+BAA+B,CAAA;AAC5D,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAuBvB,QAAA,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAsEwB,CAAA;AAoF1C,OAAO,EAAE,YAAY,EAAE,CAAA"}
@@ -0,0 +1,143 @@
1
+ import { z } from 'zod';
2
+ import { getToolOutput } from '../mcp-helpers.js';
3
+ import { ApiLimits } from '../utils/constants.js';
4
+ import { formatNextSteps } from '../utils/response-builders.js';
5
+ import { ToolNames } from '../utils/tool-names.js';
6
+ const { ADD_COMMENTS, UPDATE_COMMENTS, DELETE_OBJECT } = ToolNames;
7
+ const ArgsSchema = {
8
+ taskId: z.string().optional().describe('Find comments for a specific task.'),
9
+ projectId: z.string().optional().describe('Find comments for a specific project.'),
10
+ commentId: z.string().optional().describe('Get a specific comment by ID.'),
11
+ cursor: z.string().optional().describe('Pagination cursor for retrieving more results.'),
12
+ limit: z
13
+ .number()
14
+ .int()
15
+ .min(1)
16
+ .max(ApiLimits.COMMENTS_MAX)
17
+ .optional()
18
+ .describe('Maximum number of comments to return'),
19
+ };
20
+ const findComments = {
21
+ name: ToolNames.FIND_COMMENTS,
22
+ description: 'Find comments by task, project, or get a specific comment by ID. Exactly one of taskId, projectId, or commentId must be provided.',
23
+ parameters: ArgsSchema,
24
+ async execute(args, client) {
25
+ // Validate that exactly one search parameter is provided
26
+ const searchParams = [args.taskId, args.projectId, args.commentId].filter(Boolean);
27
+ if (searchParams.length === 0) {
28
+ throw new Error('Must provide exactly one of: taskId, projectId, or commentId.');
29
+ }
30
+ if (searchParams.length > 1) {
31
+ throw new Error('Cannot provide multiple search parameters. Choose one of: taskId, projectId, or commentId.');
32
+ }
33
+ let comments;
34
+ let hasMore = false;
35
+ let nextCursor = null;
36
+ if (args.commentId) {
37
+ // Get single comment
38
+ const comment = await client.getComment(args.commentId);
39
+ comments = [comment];
40
+ }
41
+ else if (args.taskId) {
42
+ // Get comments by task
43
+ const response = await client.getComments({
44
+ taskId: args.taskId,
45
+ cursor: args.cursor || null,
46
+ limit: args.limit || ApiLimits.COMMENTS_DEFAULT,
47
+ });
48
+ comments = response.results;
49
+ hasMore = response.nextCursor !== null;
50
+ nextCursor = response.nextCursor;
51
+ }
52
+ else if (args.projectId) {
53
+ // Get comments by project
54
+ const response = await client.getComments({
55
+ projectId: args.projectId,
56
+ cursor: args.cursor || null,
57
+ limit: args.limit || ApiLimits.COMMENTS_DEFAULT,
58
+ });
59
+ comments = response.results;
60
+ hasMore = response.nextCursor !== null;
61
+ nextCursor = response.nextCursor;
62
+ }
63
+ else {
64
+ // This should never happen due to validation, but TypeScript needs it
65
+ throw new Error('Invalid state: no search parameter provided');
66
+ }
67
+ const textContent = generateTextContent({
68
+ comments,
69
+ searchType: args.commentId ? 'single' : args.taskId ? 'task' : 'project',
70
+ searchId: args.commentId || args.taskId || args.projectId || '',
71
+ hasMore,
72
+ nextCursor,
73
+ });
74
+ return getToolOutput({
75
+ textContent,
76
+ structuredContent: {
77
+ comments,
78
+ searchType: args.commentId ? 'single' : args.taskId ? 'task' : 'project',
79
+ searchId: args.commentId || args.taskId || args.projectId || '',
80
+ hasMore,
81
+ nextCursor,
82
+ totalCount: comments.length,
83
+ },
84
+ });
85
+ },
86
+ };
87
+ function generateTextContent({ comments, searchType, searchId, hasMore, nextCursor, }) {
88
+ if (comments.length === 0) {
89
+ return `No comments found for ${searchType}${searchType !== 'single' ? ` ${searchId}` : ''}`;
90
+ }
91
+ // Build summary
92
+ let summary;
93
+ if (searchType === 'single') {
94
+ const comment = comments[0];
95
+ if (!comment) {
96
+ return 'Comment not found';
97
+ }
98
+ const hasAttachment = comment.fileAttachment !== null;
99
+ const attachmentInfo = hasAttachment
100
+ ? ` • Has attachment: ${comment.fileAttachment?.fileName || 'file'}`
101
+ : '';
102
+ summary = `Found comment${attachmentInfo} • id=${comment.id}`;
103
+ }
104
+ else {
105
+ const attachmentCount = comments.filter((c) => c.fileAttachment !== null).length;
106
+ const attachmentInfo = attachmentCount > 0 ? ` (${attachmentCount} with attachments)` : '';
107
+ const commentsLabel = comments.length === 1 ? 'comment' : 'comments';
108
+ summary = `Found ${comments.length} ${commentsLabel} for ${searchType} ${searchId}${attachmentInfo}`;
109
+ if (hasMore) {
110
+ summary += ' • More available';
111
+ }
112
+ }
113
+ // Context-aware next steps
114
+ const nextSteps = [];
115
+ if (searchType === 'single') {
116
+ const comment = comments[0];
117
+ if (comment) {
118
+ nextSteps.push(`Use ${UPDATE_COMMENTS} with id=${comment.id} to edit content`);
119
+ nextSteps.push(`Use ${DELETE_OBJECT} with type=comment id=${comment.id} to remove`);
120
+ // Suggest viewing related comments
121
+ if (comment.taskId) {
122
+ nextSteps.push(`Use ${ToolNames.FIND_COMMENTS} with taskId=${comment.taskId} to see all task comments`);
123
+ }
124
+ else if (comment.projectId) {
125
+ nextSteps.push(`Use ${ToolNames.FIND_COMMENTS} with projectId=${comment.projectId} to see all project comments`);
126
+ }
127
+ }
128
+ }
129
+ else {
130
+ // Multiple comments
131
+ nextSteps.push(`Use ${ADD_COMMENTS} with ${searchType}Id=${searchId} to add new comment`);
132
+ if (comments.length > 0) {
133
+ nextSteps.push(`Use ${ToolNames.FIND_COMMENTS} with commentId to view specific comment details`);
134
+ }
135
+ // Pagination
136
+ if (hasMore && nextCursor) {
137
+ nextSteps.push(`Use ${ToolNames.FIND_COMMENTS} with cursor="${nextCursor}" to get more results`);
138
+ }
139
+ }
140
+ const next = formatNextSteps(nextSteps);
141
+ return `${summary}\n${next}`;
142
+ }
143
+ export { findComments };
@@ -0,0 +1,74 @@
1
+ import { z } from 'zod';
2
+ declare const findCompletedTasks: {
3
+ name: "find-completed-tasks";
4
+ description: string;
5
+ parameters: {
6
+ getBy: z.ZodDefault<z.ZodEnum<["completion", "due"]>>;
7
+ since: z.ZodString;
8
+ until: z.ZodString;
9
+ workspaceId: z.ZodOptional<z.ZodString>;
10
+ projectId: z.ZodOptional<z.ZodString>;
11
+ sectionId: z.ZodOptional<z.ZodString>;
12
+ parentId: z.ZodOptional<z.ZodString>;
13
+ limit: z.ZodDefault<z.ZodNumber>;
14
+ cursor: z.ZodOptional<z.ZodString>;
15
+ };
16
+ execute(args: {
17
+ limit: number;
18
+ getBy: "completion" | "due";
19
+ since: string;
20
+ until: string;
21
+ parentId?: string | undefined;
22
+ workspaceId?: string | undefined;
23
+ projectId?: string | undefined;
24
+ sectionId?: string | undefined;
25
+ cursor?: string | undefined;
26
+ }, client: import("@doist/todoist-api-typescript").TodoistApi): Promise<{
27
+ content: {
28
+ type: "text";
29
+ text: string;
30
+ }[];
31
+ structuredContent: {
32
+ tasks: {
33
+ id: string;
34
+ content: string;
35
+ description: string;
36
+ dueDate: string | undefined;
37
+ recurring: string | boolean;
38
+ priority: number;
39
+ projectId: string;
40
+ sectionId: string | null;
41
+ parentId: string | null;
42
+ labels: string[];
43
+ duration: string | null;
44
+ }[];
45
+ nextCursor: string | null;
46
+ totalCount: number;
47
+ hasMore: boolean;
48
+ appliedFilters: {
49
+ limit: number;
50
+ getBy: "completion" | "due";
51
+ since: string;
52
+ until: string;
53
+ parentId?: string | undefined;
54
+ workspaceId?: string | undefined;
55
+ projectId?: string | undefined;
56
+ sectionId?: string | undefined;
57
+ cursor?: string | undefined;
58
+ };
59
+ };
60
+ } | {
61
+ content: ({
62
+ type: "text";
63
+ text: string;
64
+ mimeType?: undefined;
65
+ } | {
66
+ type: "text";
67
+ mimeType: string;
68
+ text: string;
69
+ })[];
70
+ structuredContent?: undefined;
71
+ }>;
72
+ };
73
+ export { findCompletedTasks };
74
+ //# sourceMappingURL=find-completed-tasks.d.ts.map
@@ -0,0 +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;AA8CvB,QAAA,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6BkB,CAAA;AA2D1C,OAAO,EAAE,kBAAkB,EAAE,CAAA"}
@@ -0,0 +1,112 @@
1
+ import { z } from 'zod';
2
+ import { getToolOutput } from '../mcp-helpers.js';
3
+ import { mapTask } from '../tool-helpers.js';
4
+ import { ApiLimits } from '../utils/constants.js';
5
+ import { previewTasks, summarizeList } from '../utils/response-builders.js';
6
+ import { ToolNames } from '../utils/tool-names.js';
7
+ const { FIND_TASKS_BY_DATE, GET_OVERVIEW } = ToolNames;
8
+ const ArgsSchema = {
9
+ getBy: z
10
+ .enum(['completion', 'due'])
11
+ .default('completion')
12
+ .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).'),
13
+ since: z
14
+ .string()
15
+ .date()
16
+ .regex(/^\d{4}-\d{2}-\d{2}$/)
17
+ .describe('The start date to get the tasks for. Format: YYYY-MM-DD.'),
18
+ until: z
19
+ .string()
20
+ .date()
21
+ .regex(/^\d{4}-\d{2}-\d{2}$/)
22
+ .describe('The start date to get the tasks for. Format: YYYY-MM-DD.'),
23
+ workspaceId: z.string().optional().describe('The ID of the workspace to get the tasks for.'),
24
+ projectId: z.string().optional().describe('The ID of the project to get the tasks for.'),
25
+ sectionId: z.string().optional().describe('The ID of the section to get the tasks for.'),
26
+ parentId: z.string().optional().describe('The ID of the parent task to get the tasks for.'),
27
+ limit: z
28
+ .number()
29
+ .int()
30
+ .min(1)
31
+ .max(ApiLimits.COMPLETED_TASKS_MAX)
32
+ .default(ApiLimits.COMPLETED_TASKS_DEFAULT)
33
+ .describe('The maximum number of tasks to return.'),
34
+ cursor: z
35
+ .string()
36
+ .optional()
37
+ .describe('The cursor to get the next page of tasks (cursor is obtained from the previous call to this tool, with the same parameters).'),
38
+ };
39
+ const findCompletedTasks = {
40
+ name: ToolNames.FIND_COMPLETED_TASKS,
41
+ description: 'Get completed tasks.',
42
+ parameters: ArgsSchema,
43
+ async execute(args, client) {
44
+ const { getBy, ...rest } = args;
45
+ const { items, nextCursor } = getBy === 'completion'
46
+ ? await client.getCompletedTasksByCompletionDate(rest)
47
+ : await client.getCompletedTasksByDueDate(rest);
48
+ const mappedTasks = items.map(mapTask);
49
+ const textContent = generateTextContent({
50
+ tasks: mappedTasks,
51
+ args,
52
+ nextCursor,
53
+ });
54
+ return getToolOutput({
55
+ textContent,
56
+ structuredContent: {
57
+ tasks: mappedTasks,
58
+ nextCursor,
59
+ totalCount: mappedTasks.length,
60
+ hasMore: Boolean(nextCursor),
61
+ appliedFilters: args,
62
+ },
63
+ });
64
+ },
65
+ };
66
+ function generateTextContent({ tasks, args, nextCursor, }) {
67
+ // Generate subject description
68
+ const getByText = args.getBy === 'completion' ? 'completed' : 'due';
69
+ const subject = `Completed tasks (by ${getByText} date)`;
70
+ // Generate filter hints
71
+ const filterHints = [];
72
+ filterHints.push(`${getByText} date: ${args.since} to ${args.until}`);
73
+ if (args.projectId)
74
+ filterHints.push(`project: ${args.projectId}`);
75
+ if (args.sectionId)
76
+ filterHints.push(`section: ${args.sectionId}`);
77
+ if (args.parentId)
78
+ filterHints.push(`parent: ${args.parentId}`);
79
+ if (args.workspaceId)
80
+ filterHints.push(`workspace: ${args.workspaceId}`);
81
+ // Generate helpful suggestions for empty results
82
+ const zeroReasonHints = [];
83
+ if (tasks.length === 0) {
84
+ zeroReasonHints.push('No tasks completed in this date range');
85
+ zeroReasonHints.push('Try expanding the date range');
86
+ if (args.projectId || args.sectionId || args.parentId) {
87
+ zeroReasonHints.push('Try removing project/section/parent filters');
88
+ }
89
+ if (args.getBy === 'due') {
90
+ zeroReasonHints.push('Try switching to "completion" date instead');
91
+ }
92
+ }
93
+ // Generate contextual next steps
94
+ const nextSteps = [];
95
+ if (tasks.length > 0) {
96
+ nextSteps.push(`Use ${FIND_TASKS_BY_DATE} for active tasks or ${GET_OVERVIEW} for current productivity.`);
97
+ if (tasks.some((task) => task.recurring)) {
98
+ nextSteps.push('Recurring tasks will automatically create new instances.');
99
+ }
100
+ }
101
+ return summarizeList({
102
+ subject,
103
+ count: tasks.length,
104
+ limit: args.limit,
105
+ nextCursor: nextCursor ?? undefined,
106
+ filterHints,
107
+ previewLines: previewTasks(tasks),
108
+ zeroReasonHints,
109
+ nextSteps,
110
+ });
111
+ }
112
+ export { findCompletedTasks };
@@ -0,0 +1,53 @@
1
+ import { z } from 'zod';
2
+ declare const findProjects: {
3
+ name: "find-projects";
4
+ description: string;
5
+ parameters: {
6
+ search: z.ZodOptional<z.ZodString>;
7
+ limit: z.ZodDefault<z.ZodNumber>;
8
+ cursor: z.ZodOptional<z.ZodString>;
9
+ };
10
+ execute(args: {
11
+ limit: number;
12
+ cursor?: string | undefined;
13
+ search?: string | undefined;
14
+ }, client: import("@doist/todoist-api-typescript").TodoistApi): Promise<{
15
+ content: {
16
+ type: "text";
17
+ text: string;
18
+ }[];
19
+ structuredContent: {
20
+ projects: {
21
+ id: string;
22
+ name: string;
23
+ color: string;
24
+ isFavorite: boolean;
25
+ isShared: boolean;
26
+ parentId: string | null;
27
+ inboxProject: boolean;
28
+ viewStyle: string;
29
+ }[];
30
+ nextCursor: string | null;
31
+ totalCount: number;
32
+ hasMore: boolean;
33
+ appliedFilters: {
34
+ limit: number;
35
+ cursor?: string | undefined;
36
+ search?: string | undefined;
37
+ };
38
+ };
39
+ } | {
40
+ content: ({
41
+ type: "text";
42
+ text: string;
43
+ mimeType?: undefined;
44
+ } | {
45
+ type: "text";
46
+ mimeType: string;
47
+ text: string;
48
+ })[];
49
+ structuredContent?: undefined;
50
+ }>;
51
+ };
52
+ export { findProjects };
53
+ //# sourceMappingURL=find-projects.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"find-projects.d.ts","sourceRoot":"","sources":["../../src/tools/find-projects.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAgCvB,QAAA,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+BwB,CAAA;AA8D1C,OAAO,EAAE,YAAY,EAAE,CAAA"}
@@ -0,0 +1,101 @@
1
+ import { z } from 'zod';
2
+ import { getToolOutput } from '../mcp-helpers.js';
3
+ import { mapProject } from '../tool-helpers.js';
4
+ import { ApiLimits } from '../utils/constants.js';
5
+ import { formatProjectPreview, summarizeList } from '../utils/response-builders.js';
6
+ import { ToolNames } from '../utils/tool-names.js';
7
+ const { ADD_PROJECTS, FIND_TASKS } = ToolNames;
8
+ const ArgsSchema = {
9
+ search: z
10
+ .string()
11
+ .optional()
12
+ .describe('Search for a project by name (partial and case insensitive match). If omitted, all projects are returned.'),
13
+ limit: z
14
+ .number()
15
+ .int()
16
+ .min(1)
17
+ .max(ApiLimits.PROJECTS_MAX)
18
+ .default(ApiLimits.PROJECTS_DEFAULT)
19
+ .describe('The maximum number of projects to return.'),
20
+ cursor: z
21
+ .string()
22
+ .optional()
23
+ .describe('The cursor to get the next page of projects (cursor is obtained from the previous call to this tool, with the same parameters).'),
24
+ };
25
+ const findProjects = {
26
+ name: ToolNames.FIND_PROJECTS,
27
+ description: 'List all projects or search for projects by name. If search parameter is omitted, all projects are returned.',
28
+ parameters: ArgsSchema,
29
+ async execute(args, client) {
30
+ const { results, nextCursor } = await client.getProjects({
31
+ limit: args.limit,
32
+ cursor: args.cursor ?? null,
33
+ });
34
+ const searchLower = args.search ? args.search.toLowerCase() : undefined;
35
+ const filtered = searchLower
36
+ ? results.filter((project) => project.name.toLowerCase().includes(searchLower))
37
+ : results;
38
+ const projects = filtered.map(mapProject);
39
+ return getToolOutput({
40
+ textContent: generateTextContent({
41
+ projects,
42
+ args,
43
+ nextCursor,
44
+ }),
45
+ structuredContent: {
46
+ projects,
47
+ nextCursor,
48
+ totalCount: projects.length,
49
+ hasMore: Boolean(nextCursor),
50
+ appliedFilters: args,
51
+ },
52
+ });
53
+ },
54
+ };
55
+ function generateTextContent({ projects, args, nextCursor, }) {
56
+ // Generate subject description
57
+ const subject = args.search ? `Projects matching "${args.search}"` : 'Projects';
58
+ // Generate filter hints
59
+ const filterHints = [];
60
+ if (args.search) {
61
+ filterHints.push(`search: "${args.search}"`);
62
+ }
63
+ // Generate project preview lines
64
+ const previewLimit = 10;
65
+ const previewProjects = projects.slice(0, previewLimit);
66
+ const previewLines = previewProjects.map(formatProjectPreview).join('\n');
67
+ const remainingCount = projects.length - previewLimit;
68
+ const previewWithMore = remainingCount > 0 ? `${previewLines}\n …and ${remainingCount} more` : previewLines;
69
+ // Generate helpful suggestions for empty results
70
+ const zeroReasonHints = [];
71
+ if (projects.length === 0) {
72
+ if (args.search) {
73
+ zeroReasonHints.push('Try broader search terms');
74
+ zeroReasonHints.push('Check spelling');
75
+ zeroReasonHints.push('Remove search to see all projects');
76
+ }
77
+ else {
78
+ zeroReasonHints.push('No projects created yet');
79
+ zeroReasonHints.push(`Use ${ADD_PROJECTS} to create a project`);
80
+ }
81
+ }
82
+ // Generate contextual next steps
83
+ const nextSteps = [];
84
+ if (projects.length > 0) {
85
+ nextSteps.push(`Use ${FIND_TASKS} with projectId to see tasks in specific projects.`);
86
+ if (projects.some((p) => p.isFavorite)) {
87
+ nextSteps.push('Favorite projects appear first in most Todoist views.');
88
+ }
89
+ }
90
+ return summarizeList({
91
+ subject,
92
+ count: projects.length,
93
+ limit: args.limit,
94
+ nextCursor: nextCursor ?? undefined,
95
+ filterHints,
96
+ previewLines: previewWithMore,
97
+ zeroReasonHints,
98
+ nextSteps,
99
+ });
100
+ }
101
+ export { findProjects };