@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
@@ -1,5 +1,8 @@
1
1
  import { z } from 'zod';
2
+ import { getToolOutput } from '../mcp-helpers.js';
2
3
  import { isPersonalProject, mapTask } from '../tool-helpers.js';
4
+ import { ApiLimits } from '../utils/constants.js';
5
+ import { ToolNames } from '../utils/tool-names.js';
3
6
  const ArgsSchema = {
4
7
  projectId: z
5
8
  .string()
@@ -101,13 +104,22 @@ function renderTaskTreeMarkdown(tasks, indent = '') {
101
104
  }
102
105
  return lines;
103
106
  }
107
+ function buildProjectStructure(project, sectionsByProject) {
108
+ return {
109
+ id: project.id,
110
+ name: project.name,
111
+ parentId: isPersonalProject(project) ? (project.parentId ?? null) : null,
112
+ sections: sectionsByProject[project.id] || [],
113
+ children: project.children.map((child) => buildProjectStructure(child, sectionsByProject)),
114
+ };
115
+ }
104
116
  async function getAllTasksForProject(client, projectId) {
105
117
  let allTasks = [];
106
118
  let cursor = undefined;
107
119
  do {
108
120
  const { results, nextCursor } = await client.getTasks({
109
121
  projectId,
110
- limit: 50,
122
+ limit: ApiLimits.TASKS_BATCH_SIZE,
111
123
  cursor: cursor ?? undefined,
112
124
  });
113
125
  allTasks = allTasks.concat(results.map(mapTask));
@@ -119,7 +131,6 @@ async function getProjectSections(client, projectId) {
119
131
  const { results } = await client.getSections({ projectId });
120
132
  return results;
121
133
  }
122
- // Account overview implementation
123
134
  async function generateAccountOverview(client) {
124
135
  const { results: projects } = await client.getProjects({});
125
136
  const inbox = projects.find((p) => isPersonalProject(p) && p.inboxProject === true);
@@ -127,6 +138,7 @@ async function generateAccountOverview(client) {
127
138
  const tree = buildProjectTree(nonInbox);
128
139
  const allProjectIds = projects.map((p) => p.id);
129
140
  const sectionsByProject = await getSectionsByProject(client, allProjectIds);
141
+ // Generate markdown text content
130
142
  const lines = ['# Personal Projects', ''];
131
143
  if (inbox) {
132
144
  lines.push(`- Inbox Project: ${inbox.name} (id=${inbox.id})`);
@@ -148,9 +160,24 @@ async function generateAccountOverview(client) {
148
160
  if (hasNested) {
149
161
  lines.push('_Note: Indentation indicates that a project is a sub-project of the one above it. This allows for organizing projects hierarchically, with parent projects containing related sub-projects._', '');
150
162
  }
151
- return lines.join('\n');
163
+ const textContent = lines.join('\n');
164
+ // Generate structured content
165
+ const structuredContent = {
166
+ type: 'account_overview',
167
+ inbox: inbox
168
+ ? {
169
+ id: inbox.id,
170
+ name: inbox.name,
171
+ sections: sectionsByProject[inbox.id] || [],
172
+ }
173
+ : null,
174
+ projects: tree.map((project) => buildProjectStructure(project, sectionsByProject)),
175
+ totalProjects: projects.length,
176
+ totalSections: allProjectIds.reduce((total, id) => total + (sectionsByProject[id]?.length || 0), 0),
177
+ hasNestedProjects: hasNested,
178
+ };
179
+ return { textContent, structuredContent };
152
180
  }
153
- // Project overview implementation
154
181
  async function generateProjectOverview(client, projectId) {
155
182
  const project = await client.getProject(projectId);
156
183
  const sections = await getProjectSections(client, projectId);
@@ -162,14 +189,12 @@ async function generateProjectOverview(client, projectId) {
162
189
  }
163
190
  const tasksWithoutSection = [];
164
191
  for (const task of allTasks) {
165
- if (task.sectionId && tasksBySection[task.sectionId]) {
166
- // biome-ignore lint/style/noNonNullAssertion: the "if" above ensures that it is defined
167
- tasksBySection[task.sectionId].push(task);
168
- }
169
- else {
170
- tasksWithoutSection.push(task);
171
- }
192
+ const sectionTasks = task.sectionId
193
+ ? (tasksBySection[task.sectionId] ?? tasksWithoutSection)
194
+ : tasksWithoutSection;
195
+ sectionTasks.push(task);
172
196
  }
197
+ // Generate markdown text content
173
198
  const lines = [`# ${project.name}`];
174
199
  if (tasksWithoutSection.length > 0) {
175
200
  lines.push('');
@@ -186,17 +211,39 @@ async function generateProjectOverview(client, projectId) {
186
211
  const tree = buildTaskTree(sectionTasks);
187
212
  lines.push(...renderTaskTreeMarkdown(tree));
188
213
  }
189
- return lines.join('\n');
214
+ const textContent = lines.join('\n');
215
+ // Generate structured content
216
+ const structuredContent = {
217
+ type: 'project_overview',
218
+ project: {
219
+ id: project.id,
220
+ name: project.name,
221
+ },
222
+ sections: sections,
223
+ tasks: allTasks.map((task) => ({
224
+ ...task,
225
+ children: [], // Tasks already include hierarchical info via parentId
226
+ })),
227
+ stats: {
228
+ totalTasks: allTasks.length,
229
+ totalSections: sections.length,
230
+ tasksWithoutSection: tasksWithoutSection.length,
231
+ },
232
+ };
233
+ return { textContent, structuredContent };
190
234
  }
191
- const overview = {
192
- name: 'overview',
235
+ const getOverview = {
236
+ name: ToolNames.GET_OVERVIEW,
193
237
  description: 'Get a Markdown overview. If no projectId is provided, shows all projects with hierarchy and sections (useful for navigation). If projectId is provided, shows detailed overview of that specific project including all tasks grouped by sections.',
194
238
  parameters: ArgsSchema,
195
239
  async execute(args, client) {
196
- if (args.projectId) {
197
- return await generateProjectOverview(client, args.projectId);
198
- }
199
- return await generateAccountOverview(client);
240
+ const result = args.projectId
241
+ ? await generateProjectOverview(client, args.projectId)
242
+ : await generateAccountOverview(client);
243
+ return getToolOutput({
244
+ textContent: result.textContent,
245
+ structuredContent: result.structuredContent,
246
+ });
200
247
  },
201
248
  };
202
- export { overview };
249
+ export { getOverview };
@@ -0,0 +1,50 @@
1
+ import type { Comment } from '@doist/todoist-api-typescript';
2
+ import { z } from 'zod';
3
+ declare const updateComments: {
4
+ name: "update-comments";
5
+ description: string;
6
+ parameters: {
7
+ comments: z.ZodArray<z.ZodObject<{
8
+ id: z.ZodString;
9
+ content: z.ZodString;
10
+ }, "strip", z.ZodTypeAny, {
11
+ content: string;
12
+ id: string;
13
+ }, {
14
+ content: string;
15
+ id: string;
16
+ }>, "many">;
17
+ };
18
+ execute(args: {
19
+ comments: {
20
+ content: string;
21
+ id: string;
22
+ }[];
23
+ }, client: import("@doist/todoist-api-typescript").TodoistApi): Promise<{
24
+ content: {
25
+ type: "text";
26
+ text: string;
27
+ }[];
28
+ structuredContent: {
29
+ comments: Comment[];
30
+ totalCount: number;
31
+ updatedCommentIds: string[];
32
+ appliedOperations: {
33
+ updateCount: number;
34
+ };
35
+ };
36
+ } | {
37
+ content: ({
38
+ type: "text";
39
+ text: string;
40
+ mimeType?: undefined;
41
+ } | {
42
+ type: "text";
43
+ mimeType: string;
44
+ text: string;
45
+ })[];
46
+ structuredContent?: undefined;
47
+ }>;
48
+ };
49
+ export { updateComments };
50
+ //# sourceMappingURL=update-comments.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"update-comments.d.ts","sourceRoot":"","sources":["../../src/tools/update-comments.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,+BAA+B,CAAA;AAC5D,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAiBvB,QAAA,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6BsB,CAAA;AA2D1C,OAAO,EAAE,cAAc,EAAE,CAAA"}
@@ -0,0 +1,82 @@
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_COMMENTS, DELETE_OBJECT } = ToolNames;
6
+ const CommentUpdateSchema = z.object({
7
+ id: z.string().min(1).describe('The ID of the comment to update.'),
8
+ content: z.string().min(1).describe('The new content for the comment.'),
9
+ });
10
+ const ArgsSchema = {
11
+ comments: z.array(CommentUpdateSchema).min(1).describe('The comments to update.'),
12
+ };
13
+ const updateComments = {
14
+ name: ToolNames.UPDATE_COMMENTS,
15
+ description: 'Update multiple existing comments with new content.',
16
+ parameters: ArgsSchema,
17
+ async execute(args, client) {
18
+ const { comments } = args;
19
+ const updateCommentPromises = comments.map(async (comment) => {
20
+ return await client.updateComment(comment.id, { content: comment.content });
21
+ });
22
+ const updatedComments = await Promise.all(updateCommentPromises);
23
+ const textContent = generateTextContent({
24
+ comments: updatedComments,
25
+ });
26
+ return getToolOutput({
27
+ textContent,
28
+ structuredContent: {
29
+ comments: updatedComments,
30
+ totalCount: updatedComments.length,
31
+ updatedCommentIds: updatedComments.map((comment) => comment.id),
32
+ appliedOperations: {
33
+ updateCount: updatedComments.length,
34
+ },
35
+ },
36
+ });
37
+ },
38
+ };
39
+ function generateNextSteps(comments) {
40
+ const nextSteps = [];
41
+ // Early return for empty comments
42
+ if (comments.length === 0) {
43
+ return nextSteps;
44
+ }
45
+ // Multiple comments case
46
+ if (comments.length > 1) {
47
+ nextSteps.push(`Use ${FIND_COMMENTS} to view comments by task or project`);
48
+ nextSteps.push(`Use ${DELETE_OBJECT} with type=comment to remove comments`);
49
+ return nextSteps;
50
+ }
51
+ // Single comment case
52
+ const comment = comments[0];
53
+ if (!comment)
54
+ return nextSteps;
55
+ if (comment.taskId) {
56
+ nextSteps.push(`Use ${FIND_COMMENTS} with taskId=${comment.taskId} to see all task comments`);
57
+ }
58
+ else if (comment.projectId) {
59
+ nextSteps.push(`Use ${FIND_COMMENTS} with projectId=${comment.projectId} to see all project comments`);
60
+ }
61
+ nextSteps.push(`Use ${DELETE_OBJECT} with type=comment id=${comment.id} to remove comment`);
62
+ return nextSteps;
63
+ }
64
+ function generateTextContent({ comments, }) {
65
+ // Group comments by entity type and count
66
+ const taskComments = comments.filter((c) => c.taskId).length;
67
+ const projectComments = comments.filter((c) => c.projectId).length;
68
+ const parts = [];
69
+ if (taskComments > 0) {
70
+ const commentsLabel = taskComments > 1 ? 'comments' : 'comment';
71
+ parts.push(`${taskComments} task ${commentsLabel}`);
72
+ }
73
+ if (projectComments > 0) {
74
+ const commentsLabel = projectComments > 1 ? 'comments' : 'comment';
75
+ parts.push(`${projectComments} project ${commentsLabel}`);
76
+ }
77
+ const summary = parts.length > 0 ? `Updated ${parts.join(' and ')}` : 'No comments updated';
78
+ const nextSteps = generateNextSteps(comments);
79
+ const next = formatNextSteps(nextSteps);
80
+ return `${summary}\n${next}`;
81
+ }
82
+ export { updateComments };
@@ -0,0 +1,59 @@
1
+ import type { PersonalProject, WorkspaceProject } from '@doist/todoist-api-typescript';
2
+ import { z } from 'zod';
3
+ declare const updateProjects: {
4
+ name: "update-projects";
5
+ description: string;
6
+ parameters: {
7
+ projects: z.ZodArray<z.ZodObject<{
8
+ id: z.ZodString;
9
+ name: z.ZodOptional<z.ZodString>;
10
+ isFavorite: z.ZodOptional<z.ZodBoolean>;
11
+ viewStyle: z.ZodOptional<z.ZodEnum<["list", "board", "calendar"]>>;
12
+ }, "strip", z.ZodTypeAny, {
13
+ id: string;
14
+ name?: string | undefined;
15
+ isFavorite?: boolean | undefined;
16
+ viewStyle?: "list" | "board" | "calendar" | undefined;
17
+ }, {
18
+ id: string;
19
+ name?: string | undefined;
20
+ isFavorite?: boolean | undefined;
21
+ viewStyle?: "list" | "board" | "calendar" | undefined;
22
+ }>, "many">;
23
+ };
24
+ execute(args: {
25
+ projects: {
26
+ id: string;
27
+ name?: string | undefined;
28
+ isFavorite?: boolean | undefined;
29
+ viewStyle?: "list" | "board" | "calendar" | undefined;
30
+ }[];
31
+ }, client: import("@doist/todoist-api-typescript").TodoistApi): Promise<{
32
+ content: {
33
+ type: "text";
34
+ text: string;
35
+ }[];
36
+ structuredContent: {
37
+ projects: (PersonalProject | WorkspaceProject)[];
38
+ totalCount: number;
39
+ updatedProjectIds: string[];
40
+ appliedOperations: {
41
+ updateCount: number;
42
+ skippedCount: number;
43
+ };
44
+ };
45
+ } | {
46
+ content: ({
47
+ type: "text";
48
+ text: string;
49
+ mimeType?: undefined;
50
+ } | {
51
+ type: "text";
52
+ mimeType: string;
53
+ text: string;
54
+ })[];
55
+ structuredContent?: undefined;
56
+ }>;
57
+ };
58
+ export { updateProjects };
59
+ //# sourceMappingURL=update-projects.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"update-projects.d.ts","sourceRoot":"","sources":["../../src/tools/update-projects.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAA;AACtF,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAqBvB,QAAA,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAqCsB,CAAA;AAuD1C,OAAO,EAAE,cAAc,EAAE,CAAA"}
@@ -0,0 +1,84 @@
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, FIND_TASKS, GET_OVERVIEW } = ToolNames;
6
+ const ProjectUpdateSchema = z.object({
7
+ id: z.string().min(1).describe('The ID of the project to update.'),
8
+ name: z.string().min(1).optional().describe('The new name of the project.'),
9
+ isFavorite: z.boolean().optional().describe('Whether the project is a favorite.'),
10
+ viewStyle: z.enum(['list', 'board', 'calendar']).optional().describe('The project view style.'),
11
+ });
12
+ const ArgsSchema = {
13
+ projects: z.array(ProjectUpdateSchema).min(1).describe('The projects to update.'),
14
+ };
15
+ const updateProjects = {
16
+ name: ToolNames.UPDATE_PROJECTS,
17
+ description: 'Update multiple existing projects with new values.',
18
+ parameters: ArgsSchema,
19
+ async execute(args, client) {
20
+ const { projects } = args;
21
+ const updateProjectsPromises = projects.map(async (project) => {
22
+ if (!hasUpdatesToMake(project)) {
23
+ return undefined;
24
+ }
25
+ const { id, ...updateArgs } = project;
26
+ return await client.updateProject(id, updateArgs);
27
+ });
28
+ const updatedProjects = (await Promise.all(updateProjectsPromises)).filter((project) => project !== undefined);
29
+ const textContent = generateTextContent({
30
+ projects: updatedProjects,
31
+ args,
32
+ });
33
+ return getToolOutput({
34
+ textContent,
35
+ structuredContent: {
36
+ projects: updatedProjects,
37
+ totalCount: updatedProjects.length,
38
+ updatedProjectIds: updatedProjects.map((project) => project.id),
39
+ appliedOperations: {
40
+ updateCount: updatedProjects.length,
41
+ skippedCount: projects.length - updatedProjects.length,
42
+ },
43
+ },
44
+ });
45
+ },
46
+ };
47
+ function generateTextContent({ projects, args, }) {
48
+ const totalRequested = args.projects.length;
49
+ const actuallyUpdated = projects.length;
50
+ const skipped = totalRequested - actuallyUpdated;
51
+ const count = projects.length;
52
+ const projectList = projects.map((project) => `• ${project.name} (id=${project.id})`).join('\n');
53
+ let summary = `Updated ${count} project${count === 1 ? '' : 's'}`;
54
+ if (skipped > 0) {
55
+ summary += ` (${skipped} skipped - no changes)`;
56
+ }
57
+ if (count > 0) {
58
+ summary += `:\n${projectList}`;
59
+ }
60
+ // Context-aware next steps for updated projects
61
+ const nextSteps = [];
62
+ if (projects.length > 0) {
63
+ if (count === 1) {
64
+ const project = projects[0];
65
+ if (project) {
66
+ nextSteps.push(`Use ${GET_OVERVIEW} with projectId=${project.id} to see project structure`);
67
+ nextSteps.push(`Use ${FIND_TASKS} with projectId=${project.id} to review existing tasks`);
68
+ }
69
+ }
70
+ else {
71
+ nextSteps.push(`Use ${FIND_PROJECTS} to see all projects with updated names`);
72
+ nextSteps.push(`Use ${GET_OVERVIEW} to see updated project hierarchy`);
73
+ }
74
+ }
75
+ else {
76
+ nextSteps.push(`Use ${FIND_PROJECTS} to see current projects`);
77
+ }
78
+ const next = formatNextSteps(nextSteps);
79
+ return `${summary}\n${next}`;
80
+ }
81
+ function hasUpdatesToMake({ id, ...otherUpdateArgs }) {
82
+ return Object.keys(otherUpdateArgs).length > 0;
83
+ }
84
+ export { updateProjects };
@@ -0,0 +1,47 @@
1
+ import type { Section } from '@doist/todoist-api-typescript';
2
+ import { z } from 'zod';
3
+ declare const updateSections: {
4
+ name: "update-sections";
5
+ description: string;
6
+ parameters: {
7
+ sections: z.ZodArray<z.ZodObject<{
8
+ id: z.ZodString;
9
+ name: z.ZodString;
10
+ }, "strip", z.ZodTypeAny, {
11
+ name: string;
12
+ id: string;
13
+ }, {
14
+ name: string;
15
+ id: string;
16
+ }>, "many">;
17
+ };
18
+ execute({ sections }: {
19
+ sections: {
20
+ name: string;
21
+ id: string;
22
+ }[];
23
+ }, client: import("@doist/todoist-api-typescript").TodoistApi): Promise<{
24
+ content: {
25
+ type: "text";
26
+ text: string;
27
+ }[];
28
+ structuredContent: {
29
+ sections: Section[];
30
+ totalCount: number;
31
+ updatedSectionIds: string[];
32
+ };
33
+ } | {
34
+ content: ({
35
+ type: "text";
36
+ text: string;
37
+ mimeType?: undefined;
38
+ } | {
39
+ type: "text";
40
+ mimeType: string;
41
+ text: string;
42
+ })[];
43
+ structuredContent?: undefined;
44
+ }>;
45
+ };
46
+ export { updateSections };
47
+ //# sourceMappingURL=update-sections.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"update-sections.d.ts","sourceRoot":"","sources":["../../src/tools/update-sections.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,+BAA+B,CAAA;AAC5D,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAiBvB,QAAA,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAsBsB,CAAA;AAsD1C,OAAO,EAAE,cAAc,EAAE,CAAA"}
@@ -0,0 +1,70 @@
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_TASKS, GET_OVERVIEW, FIND_SECTIONS } = ToolNames;
6
+ const SectionUpdateSchema = z.object({
7
+ id: z.string().min(1).describe('The ID of the section to update.'),
8
+ name: z.string().min(1).describe('The new name of the section.'),
9
+ });
10
+ const ArgsSchema = {
11
+ sections: z.array(SectionUpdateSchema).min(1).describe('The sections to update.'),
12
+ };
13
+ const updateSections = {
14
+ name: ToolNames.UPDATE_SECTIONS,
15
+ description: 'Update multiple existing sections with new values.',
16
+ parameters: ArgsSchema,
17
+ async execute({ sections }, client) {
18
+ const updatedSections = await Promise.all(sections.map((section) => client.updateSection(section.id, { name: section.name })));
19
+ const textContent = generateTextContent({
20
+ sections: updatedSections,
21
+ });
22
+ return getToolOutput({
23
+ textContent,
24
+ structuredContent: {
25
+ sections: updatedSections,
26
+ totalCount: updatedSections.length,
27
+ updatedSectionIds: updatedSections.map((section) => section.id),
28
+ },
29
+ });
30
+ },
31
+ };
32
+ function generateNextSteps(sections) {
33
+ // Handle empty sections first (early return)
34
+ if (sections.length === 0) {
35
+ return [`Use ${FIND_SECTIONS} to see current sections`];
36
+ }
37
+ // Handle single section case
38
+ if (sections.length === 1) {
39
+ const section = sections[0];
40
+ if (!section)
41
+ return [];
42
+ return [
43
+ `Use ${FIND_TASKS} with sectionId=${section.id} to see existing tasks`,
44
+ `Use ${GET_OVERVIEW} with projectId=${section.projectId} to see project structure`,
45
+ 'Consider updating task descriptions if section purpose changed',
46
+ ];
47
+ }
48
+ // Handle multiple sections case
49
+ const projectIds = [...new Set(sections.map((s) => s.projectId))];
50
+ const steps = [`Use ${FIND_SECTIONS} to see all sections with updated names`];
51
+ if (projectIds.length === 1) {
52
+ steps.push(`Use ${GET_OVERVIEW} with projectId=${projectIds[0]} to see updated project structure`);
53
+ }
54
+ else {
55
+ steps.push(`Use ${GET_OVERVIEW} to see updated project structures`);
56
+ }
57
+ steps.push('Consider updating task descriptions if section purposes changed');
58
+ return steps;
59
+ }
60
+ function generateTextContent({ sections, }) {
61
+ const count = sections.length;
62
+ const sectionList = sections
63
+ .map((section) => `• ${section.name} (id=${section.id}, projectId=${section.projectId})`)
64
+ .join('\n');
65
+ const summary = `Updated ${count} section${count === 1 ? '' : 's'}:\n${sectionList}`;
66
+ const nextSteps = generateNextSteps(sections);
67
+ const next = formatNextSteps(nextSteps);
68
+ return `${summary}\n${next}`;
69
+ }
70
+ export { updateSections };
@@ -0,0 +1,94 @@
1
+ import { z } from 'zod';
2
+ declare const updateTasks: {
3
+ name: "update-tasks";
4
+ description: string;
5
+ parameters: {
6
+ tasks: z.ZodArray<z.ZodObject<{
7
+ id: z.ZodString;
8
+ content: z.ZodOptional<z.ZodString>;
9
+ description: z.ZodOptional<z.ZodString>;
10
+ projectId: z.ZodOptional<z.ZodString>;
11
+ sectionId: z.ZodOptional<z.ZodString>;
12
+ parentId: z.ZodOptional<z.ZodString>;
13
+ order: z.ZodOptional<z.ZodNumber>;
14
+ priority: z.ZodOptional<z.ZodNumber>;
15
+ dueString: z.ZodOptional<z.ZodString>;
16
+ duration: z.ZodOptional<z.ZodString>;
17
+ }, "strip", z.ZodTypeAny, {
18
+ id: string;
19
+ content?: string | undefined;
20
+ description?: string | undefined;
21
+ parentId?: string | undefined;
22
+ projectId?: string | undefined;
23
+ sectionId?: string | undefined;
24
+ priority?: number | undefined;
25
+ dueString?: string | undefined;
26
+ duration?: string | undefined;
27
+ order?: number | undefined;
28
+ }, {
29
+ id: string;
30
+ content?: string | undefined;
31
+ description?: string | undefined;
32
+ parentId?: string | undefined;
33
+ projectId?: string | undefined;
34
+ sectionId?: string | undefined;
35
+ priority?: number | undefined;
36
+ dueString?: string | undefined;
37
+ duration?: string | undefined;
38
+ order?: number | undefined;
39
+ }>, "many">;
40
+ };
41
+ execute(args: {
42
+ tasks: {
43
+ id: string;
44
+ content?: string | undefined;
45
+ description?: string | undefined;
46
+ parentId?: string | undefined;
47
+ projectId?: string | undefined;
48
+ sectionId?: string | undefined;
49
+ priority?: number | undefined;
50
+ dueString?: string | undefined;
51
+ duration?: string | undefined;
52
+ order?: number | undefined;
53
+ }[];
54
+ }, client: import("@doist/todoist-api-typescript").TodoistApi): Promise<{
55
+ content: {
56
+ type: "text";
57
+ text: string;
58
+ }[];
59
+ structuredContent: {
60
+ tasks: {
61
+ id: string;
62
+ content: string;
63
+ description: string;
64
+ dueDate: string | undefined;
65
+ recurring: string | boolean;
66
+ priority: number;
67
+ projectId: string;
68
+ sectionId: string | null;
69
+ parentId: string | null;
70
+ labels: string[];
71
+ duration: string | null;
72
+ }[];
73
+ totalCount: number;
74
+ updatedTaskIds: string[];
75
+ appliedOperations: {
76
+ updateCount: number;
77
+ skippedCount: number;
78
+ };
79
+ };
80
+ } | {
81
+ content: ({
82
+ type: "text";
83
+ text: string;
84
+ mimeType?: undefined;
85
+ } | {
86
+ type: "text";
87
+ mimeType: string;
88
+ text: string;
89
+ })[];
90
+ structuredContent?: undefined;
91
+ }>;
92
+ };
93
+ export { updateTasks };
94
+ //# sourceMappingURL=update-tasks.d.ts.map
@@ -0,0 +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;AA2CvB,QAAA,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6EyB,CAAA;AAqC1C,OAAO,EAAE,WAAW,EAAE,CAAA"}