@doist/todoist-ai 4.15.1 → 4.16.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (167) hide show
  1. package/dist/filter-helpers.d.ts +1 -1
  2. package/dist/index.d.ts +175 -175
  3. package/dist/index.js +61 -81
  4. package/dist/main.js +15 -23
  5. package/dist/mcp-helpers.d.ts +4 -4
  6. package/dist/mcp-server-6tm7Rhyz.js +2840 -0
  7. package/dist/todoist-tool.d.ts +2 -2
  8. package/dist/tool-helpers.d.ts +1 -1
  9. package/dist/tools/add-comments.d.ts +1 -1
  10. package/dist/tools/add-comments.d.ts.map +1 -1
  11. package/dist/tools/add-projects.d.ts +4 -4
  12. package/dist/tools/add-projects.d.ts.map +1 -1
  13. package/dist/tools/add-sections.d.ts +1 -1
  14. package/dist/tools/add-sections.d.ts.map +1 -1
  15. package/dist/tools/add-tasks.d.ts +4 -4
  16. package/dist/tools/add-tasks.d.ts.map +1 -1
  17. package/dist/tools/complete-tasks.d.ts +1 -1
  18. package/dist/tools/complete-tasks.d.ts.map +1 -1
  19. package/dist/tools/delete-object.d.ts +3 -3
  20. package/dist/tools/delete-object.d.ts.map +1 -1
  21. package/dist/tools/fetch.d.ts +1 -1
  22. package/dist/tools/find-activity.d.ts +5 -5
  23. package/dist/tools/find-activity.d.ts.map +1 -1
  24. package/dist/tools/find-comments.d.ts +2 -2
  25. package/dist/tools/find-comments.d.ts.map +1 -1
  26. package/dist/tools/find-completed-tasks.d.ts +3 -3
  27. package/dist/tools/find-completed-tasks.d.ts.map +1 -1
  28. package/dist/tools/find-project-collaborators.d.ts +2 -2
  29. package/dist/tools/find-projects.d.ts +1 -1
  30. package/dist/tools/find-projects.d.ts.map +1 -1
  31. package/dist/tools/find-sections.d.ts +1 -1
  32. package/dist/tools/find-sections.d.ts.map +1 -1
  33. package/dist/tools/find-tasks-by-date.d.ts +1 -1
  34. package/dist/tools/find-tasks-by-date.d.ts.map +1 -1
  35. package/dist/tools/find-tasks.d.ts +3 -3
  36. package/dist/tools/find-tasks.d.ts.map +1 -1
  37. package/dist/tools/get-overview.d.ts +1 -1
  38. package/dist/tools/manage-assignments.d.ts +1 -1
  39. package/dist/tools/search.d.ts +1 -1
  40. package/dist/tools/update-comments.d.ts +4 -4
  41. package/dist/tools/update-comments.d.ts.map +1 -1
  42. package/dist/tools/update-projects.d.ts +1 -1
  43. package/dist/tools/update-projects.d.ts.map +1 -1
  44. package/dist/tools/update-sections.d.ts +4 -4
  45. package/dist/tools/update-sections.d.ts.map +1 -1
  46. package/dist/tools/update-tasks.d.ts +7 -7
  47. package/dist/tools/update-tasks.d.ts.map +1 -1
  48. package/dist/tools/user-info.d.ts +1 -1
  49. package/dist/utils/assignment-validator.d.ts +2 -2
  50. package/dist/utils/response-builders.d.ts +1 -3
  51. package/dist/utils/response-builders.d.ts.map +1 -1
  52. package/dist/utils/test-helpers.d.ts +1 -1
  53. package/dist/utils/user-resolver.d.ts +1 -1
  54. package/package.json +11 -9
  55. package/dist/filter-helpers.js +0 -79
  56. package/dist/mcp-helpers.js +0 -71
  57. package/dist/mcp-server.js +0 -142
  58. package/dist/todoist-tool.js +0 -1
  59. package/dist/tool-helpers.js +0 -125
  60. package/dist/tool-helpers.test.d.ts +0 -2
  61. package/dist/tool-helpers.test.d.ts.map +0 -1
  62. package/dist/tool-helpers.test.js +0 -223
  63. package/dist/tools/__tests__/add-comments.test.d.ts +0 -2
  64. package/dist/tools/__tests__/add-comments.test.d.ts.map +0 -1
  65. package/dist/tools/__tests__/add-comments.test.js +0 -241
  66. package/dist/tools/__tests__/add-projects.test.d.ts +0 -2
  67. package/dist/tools/__tests__/add-projects.test.d.ts.map +0 -1
  68. package/dist/tools/__tests__/add-projects.test.js +0 -174
  69. package/dist/tools/__tests__/add-sections.test.d.ts +0 -2
  70. package/dist/tools/__tests__/add-sections.test.d.ts.map +0 -1
  71. package/dist/tools/__tests__/add-sections.test.js +0 -185
  72. package/dist/tools/__tests__/add-tasks.test.d.ts +0 -2
  73. package/dist/tools/__tests__/add-tasks.test.d.ts.map +0 -1
  74. package/dist/tools/__tests__/add-tasks.test.js +0 -533
  75. package/dist/tools/__tests__/assignment-integration.test.d.ts +0 -2
  76. package/dist/tools/__tests__/assignment-integration.test.d.ts.map +0 -1
  77. package/dist/tools/__tests__/assignment-integration.test.js +0 -428
  78. package/dist/tools/__tests__/complete-tasks.test.d.ts +0 -2
  79. package/dist/tools/__tests__/complete-tasks.test.d.ts.map +0 -1
  80. package/dist/tools/__tests__/complete-tasks.test.js +0 -206
  81. package/dist/tools/__tests__/delete-object.test.d.ts +0 -2
  82. package/dist/tools/__tests__/delete-object.test.d.ts.map +0 -1
  83. package/dist/tools/__tests__/delete-object.test.js +0 -110
  84. package/dist/tools/__tests__/fetch.test.d.ts +0 -2
  85. package/dist/tools/__tests__/fetch.test.d.ts.map +0 -1
  86. package/dist/tools/__tests__/fetch.test.js +0 -279
  87. package/dist/tools/__tests__/find-activity.test.d.ts +0 -2
  88. package/dist/tools/__tests__/find-activity.test.d.ts.map +0 -1
  89. package/dist/tools/__tests__/find-activity.test.js +0 -229
  90. package/dist/tools/__tests__/find-comments.test.d.ts +0 -2
  91. package/dist/tools/__tests__/find-comments.test.d.ts.map +0 -1
  92. package/dist/tools/__tests__/find-comments.test.js +0 -236
  93. package/dist/tools/__tests__/find-completed-tasks.test.d.ts +0 -2
  94. package/dist/tools/__tests__/find-completed-tasks.test.d.ts.map +0 -1
  95. package/dist/tools/__tests__/find-completed-tasks.test.js +0 -324
  96. package/dist/tools/__tests__/find-projects.test.d.ts +0 -2
  97. package/dist/tools/__tests__/find-projects.test.d.ts.map +0 -1
  98. package/dist/tools/__tests__/find-projects.test.js +0 -154
  99. package/dist/tools/__tests__/find-sections.test.d.ts +0 -2
  100. package/dist/tools/__tests__/find-sections.test.d.ts.map +0 -1
  101. package/dist/tools/__tests__/find-sections.test.js +0 -245
  102. package/dist/tools/__tests__/find-tasks-by-date.test.d.ts +0 -2
  103. package/dist/tools/__tests__/find-tasks-by-date.test.d.ts.map +0 -1
  104. package/dist/tools/__tests__/find-tasks-by-date.test.js +0 -528
  105. package/dist/tools/__tests__/find-tasks.test.d.ts +0 -2
  106. package/dist/tools/__tests__/find-tasks.test.d.ts.map +0 -1
  107. package/dist/tools/__tests__/find-tasks.test.js +0 -771
  108. package/dist/tools/__tests__/get-overview.test.d.ts +0 -2
  109. package/dist/tools/__tests__/get-overview.test.d.ts.map +0 -1
  110. package/dist/tools/__tests__/get-overview.test.js +0 -225
  111. package/dist/tools/__tests__/search.test.d.ts +0 -2
  112. package/dist/tools/__tests__/search.test.d.ts.map +0 -1
  113. package/dist/tools/__tests__/search.test.js +0 -206
  114. package/dist/tools/__tests__/update-comments.test.d.ts +0 -2
  115. package/dist/tools/__tests__/update-comments.test.d.ts.map +0 -1
  116. package/dist/tools/__tests__/update-comments.test.js +0 -294
  117. package/dist/tools/__tests__/update-projects.test.d.ts +0 -2
  118. package/dist/tools/__tests__/update-projects.test.d.ts.map +0 -1
  119. package/dist/tools/__tests__/update-projects.test.js +0 -217
  120. package/dist/tools/__tests__/update-sections.test.d.ts +0 -2
  121. package/dist/tools/__tests__/update-sections.test.d.ts.map +0 -1
  122. package/dist/tools/__tests__/update-sections.test.js +0 -169
  123. package/dist/tools/__tests__/update-tasks.test.d.ts +0 -2
  124. package/dist/tools/__tests__/update-tasks.test.d.ts.map +0 -1
  125. package/dist/tools/__tests__/update-tasks.test.js +0 -788
  126. package/dist/tools/__tests__/user-info.test.d.ts +0 -2
  127. package/dist/tools/__tests__/user-info.test.d.ts.map +0 -1
  128. package/dist/tools/__tests__/user-info.test.js +0 -139
  129. package/dist/tools/add-comments.js +0 -79
  130. package/dist/tools/add-projects.js +0 -63
  131. package/dist/tools/add-sections.js +0 -61
  132. package/dist/tools/add-tasks.js +0 -160
  133. package/dist/tools/complete-tasks.js +0 -68
  134. package/dist/tools/delete-object.js +0 -79
  135. package/dist/tools/fetch.js +0 -102
  136. package/dist/tools/find-activity.js +0 -221
  137. package/dist/tools/find-comments.js +0 -143
  138. package/dist/tools/find-completed-tasks.js +0 -161
  139. package/dist/tools/find-project-collaborators.js +0 -151
  140. package/dist/tools/find-projects.js +0 -101
  141. package/dist/tools/find-sections.js +0 -96
  142. package/dist/tools/find-tasks-by-date.js +0 -198
  143. package/dist/tools/find-tasks.js +0 -329
  144. package/dist/tools/get-overview.js +0 -249
  145. package/dist/tools/manage-assignments.js +0 -337
  146. package/dist/tools/search.js +0 -65
  147. package/dist/tools/update-comments.js +0 -82
  148. package/dist/tools/update-projects.js +0 -84
  149. package/dist/tools/update-sections.js +0 -70
  150. package/dist/tools/update-tasks.js +0 -170
  151. package/dist/tools/user-info.js +0 -142
  152. package/dist/utils/assignment-validator.js +0 -253
  153. package/dist/utils/constants.js +0 -45
  154. package/dist/utils/duration-parser.js +0 -96
  155. package/dist/utils/duration-parser.test.d.ts +0 -2
  156. package/dist/utils/duration-parser.test.d.ts.map +0 -1
  157. package/dist/utils/duration-parser.test.js +0 -147
  158. package/dist/utils/labels.js +0 -18
  159. package/dist/utils/priorities.js +0 -20
  160. package/dist/utils/response-builders.js +0 -210
  161. package/dist/utils/sanitize-data.js +0 -37
  162. package/dist/utils/sanitize-data.test.d.ts +0 -2
  163. package/dist/utils/sanitize-data.test.d.ts.map +0 -1
  164. package/dist/utils/sanitize-data.test.js +0 -93
  165. package/dist/utils/test-helpers.js +0 -237
  166. package/dist/utils/tool-names.js +0 -40
  167. package/dist/utils/user-resolver.js +0 -179
@@ -0,0 +1,2840 @@
1
+ import { getTaskUrl as le, getProjectUrl as de, TodoistApi as Ce } from "@doist/todoist-api-typescript";
2
+ import { McpServer as ve } from "@modelcontextprotocol/sdk/server/mcp.js";
3
+ import F, { z as d } from "zod";
4
+ import { addDays as ue, formatISO as Se } from "date-fns";
5
+ function q(e) {
6
+ if (e == null)
7
+ return e;
8
+ if (Array.isArray(e))
9
+ return e.map((t) => q(t));
10
+ if (typeof e == "object") {
11
+ const t = {};
12
+ for (const [s, o] of Object.entries(e))
13
+ if (o !== null) {
14
+ const n = q(o);
15
+ if (Array.isArray(n) && n.length === 0 || n !== null && typeof n == "object" && !Array.isArray(n) && Object.keys(n).length === 0)
16
+ continue;
17
+ t[s] = n;
18
+ }
19
+ return t;
20
+ }
21
+ return e;
22
+ }
23
+ const De = process.env.USE_STRUCTURED_CONTENT === "true" || process.env.NODE_ENV === "test";
24
+ function T({
25
+ textContent: e,
26
+ structuredContent: t
27
+ }) {
28
+ const s = q(t);
29
+ if (De)
30
+ return {
31
+ content: [{ type: "text", text: e }],
32
+ structuredContent: s
33
+ };
34
+ const o = JSON.stringify(s);
35
+ return {
36
+ content: [
37
+ { type: "text", text: e },
38
+ { type: "text", mimeType: "application/json", text: o }
39
+ ]
40
+ };
41
+ }
42
+ function Z(e) {
43
+ return {
44
+ content: [{ type: "text", text: e }],
45
+ isError: !0
46
+ };
47
+ }
48
+ function w(e, t, s) {
49
+ const o = async (n, r) => {
50
+ try {
51
+ return await e.execute(n, s);
52
+ } catch (i) {
53
+ console.error(`Error executing tool ${e.name}:`, {
54
+ args: n,
55
+ error: i
56
+ });
57
+ const a = i instanceof Error ? i.message : "An unknown error occurred";
58
+ return Z(a);
59
+ }
60
+ };
61
+ t.tool(e.name, e.description, e.parameters, o);
62
+ }
63
+ const I = {
64
+ // Task management tools
65
+ ADD_TASKS: "add-tasks",
66
+ COMPLETE_TASKS: "complete-tasks",
67
+ UPDATE_TASKS: "update-tasks",
68
+ FIND_TASKS: "find-tasks",
69
+ FIND_TASKS_BY_DATE: "find-tasks-by-date",
70
+ FIND_COMPLETED_TASKS: "find-completed-tasks",
71
+ // Project management tools
72
+ ADD_PROJECTS: "add-projects",
73
+ UPDATE_PROJECTS: "update-projects",
74
+ FIND_PROJECTS: "find-projects",
75
+ // Section management tools
76
+ ADD_SECTIONS: "add-sections",
77
+ UPDATE_SECTIONS: "update-sections",
78
+ FIND_SECTIONS: "find-sections",
79
+ // Comment management tools
80
+ ADD_COMMENTS: "add-comments",
81
+ UPDATE_COMMENTS: "update-comments",
82
+ FIND_COMMENTS: "find-comments",
83
+ // Assignment and collaboration tools
84
+ FIND_PROJECT_COLLABORATORS: "find-project-collaborators",
85
+ MANAGE_ASSIGNMENTS: "manage-assignments",
86
+ // Activity and audit tools
87
+ FIND_ACTIVITY: "find-activity",
88
+ // General tools
89
+ GET_OVERVIEW: "get-overview",
90
+ DELETE_OBJECT: "delete-object",
91
+ USER_INFO: "user-info",
92
+ // OpenAI MCP tools
93
+ SEARCH: "search",
94
+ FETCH: "fetch"
95
+ }, xe = d.object({
96
+ taskId: d.string().optional().describe("The ID of the task to comment on."),
97
+ projectId: d.string().optional().describe(
98
+ 'The ID of the project to comment on. Project ID should be an ID string, or the text "inbox", for inbox tasks.'
99
+ ),
100
+ content: d.string().min(1).describe("The content of the comment.")
101
+ }), Ae = {
102
+ comments: d.array(xe).min(1).describe("The array of comments to add.")
103
+ }, Ue = {
104
+ name: I.ADD_COMMENTS,
105
+ description: "Add multiple comments to tasks or projects. Each comment must specify either taskId or projectId.",
106
+ parameters: Ae,
107
+ async execute(e, t) {
108
+ const { comments: s } = e;
109
+ for (const [c, l] of s.entries()) {
110
+ if (!l.taskId && !l.projectId)
111
+ throw new Error(
112
+ `Comment ${c + 1}: Either taskId or projectId must be provided.`
113
+ );
114
+ if (l.taskId && l.projectId)
115
+ throw new Error(
116
+ `Comment ${c + 1}: Cannot provide both taskId and projectId. Choose one.`
117
+ );
118
+ }
119
+ const n = s.some((c) => c.projectId === "inbox") ? await t.getUser() : null, r = s.map(async ({ content: c, taskId: l, projectId: u }) => {
120
+ const p = u === "inbox" && n ? n.inboxProjectId : u;
121
+ return await t.addComment({
122
+ content: c,
123
+ ...l ? { taskId: l } : { projectId: p }
124
+ });
125
+ }), i = await Promise.all(r), a = Pe({ comments: i });
126
+ return T({
127
+ textContent: a,
128
+ structuredContent: {
129
+ comments: i,
130
+ totalCount: i.length,
131
+ addedCommentIds: i.map((c) => c.id)
132
+ }
133
+ });
134
+ }
135
+ };
136
+ function Pe({ comments: e }) {
137
+ const t = e.filter((r) => r.taskId).length, s = e.filter((r) => r.projectId).length, o = [];
138
+ if (t > 0) {
139
+ const r = t > 1 ? "comments" : "comment";
140
+ o.push(`${t} task ${r}`);
141
+ }
142
+ if (s > 0) {
143
+ const r = s > 1 ? "comments" : "comment";
144
+ o.push(`${s} project ${r}`);
145
+ }
146
+ return o.length > 0 ? `Added ${o.join(" and ")}` : "No comments added";
147
+ }
148
+ const Ee = d.object({
149
+ name: d.string().min(1).describe("The name of the project."),
150
+ parentId: d.string().optional().describe("The ID of the parent project. If provided, creates this as a sub-project."),
151
+ isFavorite: d.boolean().optional().describe("Whether the project is a favorite. Defaults to false."),
152
+ viewStyle: d.enum(["list", "board", "calendar"]).optional().describe('The project view style. Defaults to "list".')
153
+ }), Oe = {
154
+ projects: d.array(Ee).min(1).describe("The array of projects to add.")
155
+ }, _e = {
156
+ name: I.ADD_PROJECTS,
157
+ description: "Add one or more new projects.",
158
+ parameters: Oe,
159
+ async execute({ projects: e }, t) {
160
+ const s = await Promise.all(e.map((n) => t.addProject(n))), o = Ne({ projects: s });
161
+ return T({
162
+ textContent: o,
163
+ structuredContent: {
164
+ projects: s,
165
+ totalCount: s.length
166
+ }
167
+ });
168
+ }
169
+ };
170
+ function Ne({ projects: e }) {
171
+ const t = e.length, s = e.map((n) => `• ${n.name} (id=${n.id})`).join(`
172
+ `);
173
+ return `Added ${t} project${t === 1 ? "" : "s"}:
174
+ ${s}`;
175
+ }
176
+ const Me = d.object({
177
+ name: d.string().min(1).describe("The name of the section."),
178
+ projectId: d.string().min(1).describe(
179
+ 'The ID of the project to add the section to. Project ID should be an ID string, or the text "inbox", for inbox tasks.'
180
+ )
181
+ }), Fe = {
182
+ sections: d.array(Me).min(1).describe("The array of sections to add.")
183
+ }, Re = {
184
+ name: I.ADD_SECTIONS,
185
+ description: "Add one or more new sections to projects.",
186
+ parameters: Fe,
187
+ async execute({ sections: e }, t) {
188
+ const o = e.some((a) => a.projectId === "inbox") ? await t.getUser() : null, n = e.map((a) => ({
189
+ ...a,
190
+ projectId: a.projectId === "inbox" && o ? o.inboxProjectId : a.projectId
191
+ })), r = await Promise.all(
192
+ n.map((a) => t.addSection(a))
193
+ ), i = Le({ sections: r });
194
+ return T({
195
+ textContent: i,
196
+ structuredContent: {
197
+ sections: r,
198
+ totalCount: r.length
199
+ }
200
+ });
201
+ }
202
+ };
203
+ function Le({ sections: e }) {
204
+ const t = e.length, s = e.map((n) => `• ${n.name} (id=${n.id}, projectId=${n.projectId})`).join(`
205
+ `);
206
+ return `Added ${t} section${t === 1 ? "" : "s"}:
207
+ ${s}`;
208
+ }
209
+ class P extends Error {
210
+ constructor(t, s) {
211
+ super(`Invalid duration format "${t}": ${s}`), this.name = "DurationParseError";
212
+ }
213
+ }
214
+ function pe(e) {
215
+ if (!e || typeof e != "string")
216
+ throw new P(e, "Duration must be a non-empty string");
217
+ const t = e.trim().toLowerCase().replace(/\s+/g, "");
218
+ if (!t)
219
+ throw new P(e, "Duration must be a non-empty string");
220
+ const s = t.match(/^(?:(\d+(?:\.\d+)?)h)?(?:(\d+(?:\.\d+)?)m)?$/);
221
+ if (!s || !s[1] && !s[2])
222
+ throw new P(e, 'Use format like "2h", "30m", "2h30m", or "1.5h"');
223
+ let o = 0;
224
+ const [, n, r] = s;
225
+ if (n) {
226
+ const i = Number.parseFloat(n);
227
+ if (Number.isNaN(i) || i < 0)
228
+ throw new P(e, "Hours must be a positive number");
229
+ o += i * 60;
230
+ }
231
+ if (r) {
232
+ const i = Number.parseFloat(r);
233
+ if (Number.isNaN(i) || i < 0)
234
+ throw new P(e, "Minutes must be a positive number");
235
+ if (i % 1 !== 0)
236
+ throw new P(
237
+ e,
238
+ "Minutes must be a whole number (use decimal hours instead)"
239
+ );
240
+ o += i;
241
+ }
242
+ if (o = Math.round(o), o === 0)
243
+ throw new P(e, "Duration must be greater than 0 minutes");
244
+ if (o > 1440)
245
+ throw new P(e, "Duration cannot exceed 24 hours (1440 minutes)");
246
+ return { minutes: o };
247
+ }
248
+ function Be(e) {
249
+ if (e <= 0) return "0m";
250
+ const t = Math.floor(e / 60), s = e % 60;
251
+ return t === 0 ? `${s}m` : s === 0 ? `${t}h` : `${t}h${s}m`;
252
+ }
253
+ const U = /* @__PURE__ */ new Map(), R = /* @__PURE__ */ new Map(), W = 300 * 1e3;
254
+ class Ke {
255
+ /**
256
+ * Resolve a user name or ID to a user ID by looking up collaborators across all shared projects.
257
+ * Supports exact name matches, partial matches, and email matches.
258
+ */
259
+ async resolveUser(t, s) {
260
+ if (!s || s.trim().length === 0)
261
+ return null;
262
+ const o = s.trim(), n = U.get(o);
263
+ if (n && Date.now() - n.timestamp < W)
264
+ return n.result;
265
+ if (/^[0-9]+$/.test(o) || /^[a-f0-9-]{8,}$/i.test(o) && o.includes("-") || /^[a-z0-9_]{6,}$/i.test(o) && !/^[a-z]+[\s-]/.test(o) && /[0-9_]/.test(o)) {
266
+ const r = { userId: o, displayName: o, email: o };
267
+ return U.set(o, { result: r, timestamp: Date.now() }), r;
268
+ }
269
+ try {
270
+ const r = await this.getAllCollaborators(t);
271
+ if (r.length === 0)
272
+ return U.set(o, { result: null, timestamp: Date.now() }), null;
273
+ const i = s.toLowerCase().trim();
274
+ let a = r.find((l) => l.name.toLowerCase() === i);
275
+ if (a) {
276
+ const l = { userId: a.id, displayName: a.name, email: a.email };
277
+ return U.set(o, { result: l, timestamp: Date.now() }), l;
278
+ }
279
+ if (a = r.find((l) => l.email.toLowerCase() === i), a) {
280
+ const l = { userId: a.id, displayName: a.name, email: a.email };
281
+ return U.set(o, { result: l, timestamp: Date.now() }), l;
282
+ }
283
+ if (a = r.find((l) => l.name.toLowerCase().includes(i)), a) {
284
+ const l = { userId: a.id, displayName: a.name, email: a.email };
285
+ return U.set(o, { result: l, timestamp: Date.now() }), l;
286
+ }
287
+ if (a = r.find((l) => l.email.toLowerCase().includes(i)), a) {
288
+ const l = { userId: a.id, displayName: a.name, email: a.email };
289
+ return U.set(o, { result: l, timestamp: Date.now() }), l;
290
+ }
291
+ const c = null;
292
+ return U.set(o, { result: c, timestamp: Date.now() }), c;
293
+ } catch {
294
+ return U.set(o, { result: null, timestamp: Date.now() }), null;
295
+ }
296
+ }
297
+ /**
298
+ * Validate that a user is a collaborator on a specific project
299
+ */
300
+ async validateProjectCollaborator(t, s, o) {
301
+ try {
302
+ return (await this.getProjectCollaborators(t, s)).some((r) => r.id === o);
303
+ } catch {
304
+ return !1;
305
+ }
306
+ }
307
+ /**
308
+ * Get collaborators for a specific project
309
+ */
310
+ async getProjectCollaborators(t, s) {
311
+ const o = `project_${s}`, n = R.get(o);
312
+ if (n && Date.now() - n.timestamp < W)
313
+ return n.result;
314
+ try {
315
+ const r = await t.getProjectCollaborators(s), a = (Array.isArray(r) ? r : r.results || []).filter((c) => c?.id && c.name && c.email);
316
+ return R.set(o, {
317
+ result: a,
318
+ timestamp: Date.now()
319
+ }), a;
320
+ } catch {
321
+ return [];
322
+ }
323
+ }
324
+ /**
325
+ * Get all collaborators from all shared projects
326
+ */
327
+ async getAllCollaborators(t) {
328
+ const s = "all_collaborators", o = R.get(s);
329
+ if (o && Date.now() - o.timestamp < W)
330
+ return o.result;
331
+ try {
332
+ const { results: n } = await t.getProjects({}), r = n.filter((u) => u.isShared);
333
+ if (r.length === 0) {
334
+ const u = [];
335
+ return R.set(s, { result: u, timestamp: Date.now() }), u;
336
+ }
337
+ const i = [], a = /* @__PURE__ */ new Set(), c = r.map(
338
+ (u) => this.getProjectCollaborators(t, u.id)
339
+ ), l = await Promise.allSettled(c);
340
+ for (const u of l)
341
+ if (u.status === "fulfilled")
342
+ for (const p of u.value)
343
+ p && !a.has(p.id) && (i.push(p), a.add(p.id));
344
+ return R.set(s, {
345
+ result: i,
346
+ timestamp: Date.now()
347
+ }), i;
348
+ } catch {
349
+ return [];
350
+ }
351
+ }
352
+ /**
353
+ * Clear all caches - useful for testing
354
+ */
355
+ clearCache() {
356
+ U.clear(), R.clear();
357
+ }
358
+ }
359
+ const _ = new Ke();
360
+ async function Ye(e, t) {
361
+ return _.resolveUser(e, t);
362
+ }
363
+ const me = ["assigned", "unassignedOrMe", "all"];
364
+ async function Q(e, t) {
365
+ if (!t)
366
+ return;
367
+ const s = await Ye(e, t);
368
+ if (!s)
369
+ throw new Error(
370
+ `Could not find user: "${t}". Make sure the user is a collaborator on a shared project.`
371
+ );
372
+ return { userId: s.userId, email: s.email };
373
+ }
374
+ function V(e, t) {
375
+ return t.length === 0 ? e : e.length === 0 ? t : `${e} & ${t}`;
376
+ }
377
+ function Ve({
378
+ resolvedAssigneeId: e,
379
+ assigneeEmail: t,
380
+ responsibleUserFiltering: s = "unassignedOrMe"
381
+ }) {
382
+ return e && t ? `assigned to: ${t}` : s === "unassignedOrMe" ? "!assigned to: others" : s === "assigned" ? "assigned to: others" : "";
383
+ }
384
+ function ne({
385
+ tasks: e,
386
+ resolvedAssigneeId: t,
387
+ currentUserId: s,
388
+ responsibleUserFiltering: o = "unassignedOrMe"
389
+ }) {
390
+ return t ? e.filter((n) => n.responsibleUid === t) : o === "unassignedOrMe" ? e.filter((n) => !n.responsibleUid || n.responsibleUid === s) : e;
391
+ }
392
+ function B(e) {
393
+ return "inboxProject" in e;
394
+ }
395
+ function ze(e, t, s, o) {
396
+ const n = [t, s, o].filter(Boolean);
397
+ if (n.length > 1)
398
+ throw new Error(
399
+ `Task ${e}: Only one of projectId, sectionId, or parentId can be specified at a time. The Todoist API requires exactly one destination for move operations.`
400
+ );
401
+ if (n.length === 0)
402
+ throw new Error(
403
+ `Task ${e}: At least one of projectId, sectionId, or parentId must be provided for move operations.`
404
+ );
405
+ if (t) return { projectId: t };
406
+ if (s) return { sectionId: s };
407
+ if (o) return { parentId: o };
408
+ throw new Error("Unexpected error: No valid move parameter found");
409
+ }
410
+ function O(e) {
411
+ return {
412
+ id: e.id,
413
+ content: e.content,
414
+ description: e.description,
415
+ dueDate: e.due?.date,
416
+ recurring: e.due?.isRecurring && e.due.string ? e.due.string : !1,
417
+ deadlineDate: e.deadline?.date,
418
+ priority: e.priority,
419
+ projectId: e.projectId,
420
+ sectionId: e.sectionId,
421
+ parentId: e.parentId,
422
+ labels: e.labels,
423
+ duration: e.duration ? Be(e.duration.amount) : null,
424
+ responsibleUid: e.responsibleUid,
425
+ assignedByUid: e.assignedByUid,
426
+ checked: e.checked,
427
+ completedAt: e.completedAt
428
+ };
429
+ }
430
+ function he(e) {
431
+ return {
432
+ id: e.id,
433
+ name: e.name,
434
+ color: e.color,
435
+ isFavorite: e.isFavorite,
436
+ isShared: e.isShared,
437
+ parentId: B(e) ? e.parentId ?? null : null,
438
+ inboxProject: B(e) ? e.inboxProject ?? !1 : !1,
439
+ viewStyle: e.viewStyle
440
+ };
441
+ }
442
+ function He(e) {
443
+ return {
444
+ id: e.id,
445
+ objectType: e.objectType,
446
+ objectId: e.objectId,
447
+ eventType: e.eventType,
448
+ eventDate: e.eventDate,
449
+ parentProjectId: e.parentProjectId,
450
+ parentItemId: e.parentItemId,
451
+ initiatorId: e.initiatorId,
452
+ extraData: e.extraData
453
+ };
454
+ }
455
+ const We = F.object({
456
+ httpStatusCode: F.number(),
457
+ responseData: F.object({
458
+ error: F.string(),
459
+ errorCode: F.number(),
460
+ errorTag: F.string()
461
+ })
462
+ });
463
+ async function ee({
464
+ client: e,
465
+ query: t,
466
+ limit: s,
467
+ cursor: o
468
+ }) {
469
+ try {
470
+ const { results: n, nextCursor: r } = await e.getTasksByFilter({ query: t, cursor: o, limit: s });
471
+ return { tasks: n.map(O), nextCursor: r };
472
+ } catch (n) {
473
+ const r = We.safeParse(n);
474
+ if (!r.success)
475
+ throw n;
476
+ const { responseData: i } = r.data;
477
+ throw i.errorTag === "INVALID_SEARCH_QUERY" ? new Error(`Invalid filter query: ${t}`) : new Error(
478
+ `${i.error} (tag: ${i.errorTag}, code: ${i.errorCode})`
479
+ );
480
+ }
481
+ }
482
+ const L = {
483
+ USER_NOT_FOUND: "USER_NOT_FOUND",
484
+ USER_NOT_COLLABORATOR: "USER_NOT_COLLABORATOR",
485
+ PROJECT_NOT_SHARED: "PROJECT_NOT_SHARED",
486
+ TASK_NOT_ACCESSIBLE: "TASK_NOT_ACCESSIBLE",
487
+ PERMISSION_DENIED: "PERMISSION_DENIED",
488
+ PROJECT_NOT_FOUND: "PROJECT_NOT_FOUND",
489
+ TASK_NOT_FOUND: "TASK_NOT_FOUND"
490
+ };
491
+ class Ge {
492
+ /**
493
+ * Validate a single assignment operation
494
+ */
495
+ async validateAssignment(t, s) {
496
+ const { taskId: o, projectId: n, responsibleUid: r } = s, i = await _.resolveUser(t, r);
497
+ if (!i)
498
+ return {
499
+ isValid: !1,
500
+ taskId: o,
501
+ projectId: n,
502
+ error: {
503
+ type: L.USER_NOT_FOUND,
504
+ message: `User "${r}" not found`,
505
+ suggestions: [
506
+ "Check the spelling of the user name or email",
507
+ "Ensure the user is a collaborator on at least one shared project",
508
+ "Try using the user's full email address"
509
+ ]
510
+ }
511
+ };
512
+ try {
513
+ const a = await t.getProject(n);
514
+ if (!a.isShared)
515
+ return {
516
+ isValid: !1,
517
+ taskId: o,
518
+ projectId: n,
519
+ resolvedUser: i,
520
+ error: {
521
+ type: L.PROJECT_NOT_SHARED,
522
+ message: `Project "${a.name}" is not shared`,
523
+ suggestions: [
524
+ "Share the project with collaborators before assigning tasks",
525
+ "Only shared projects support task assignments"
526
+ ]
527
+ }
528
+ };
529
+ if (!await _.validateProjectCollaborator(
530
+ t,
531
+ n,
532
+ i.userId
533
+ ))
534
+ return {
535
+ isValid: !1,
536
+ taskId: o,
537
+ projectId: n,
538
+ resolvedUser: i,
539
+ error: {
540
+ type: L.USER_NOT_COLLABORATOR,
541
+ message: `User "${i.displayName}" is not a collaborator on project "${a.name}"`,
542
+ suggestions: [
543
+ "Invite the user to collaborate on this project first",
544
+ "Check if the user has been removed from the project",
545
+ "Verify you have permission to see project collaborators"
546
+ ]
547
+ }
548
+ };
549
+ if (o)
550
+ try {
551
+ await t.getTask(o);
552
+ } catch {
553
+ return {
554
+ isValid: !1,
555
+ taskId: o,
556
+ projectId: n,
557
+ resolvedUser: i,
558
+ error: {
559
+ type: L.TASK_NOT_FOUND,
560
+ message: `Task "${o}" not found or not accessible`,
561
+ suggestions: [
562
+ "Verify the task ID is correct",
563
+ "Check if the task has been deleted",
564
+ "Ensure you have access to the task"
565
+ ]
566
+ }
567
+ };
568
+ }
569
+ return {
570
+ isValid: !0,
571
+ taskId: o,
572
+ projectId: n,
573
+ resolvedUser: i
574
+ };
575
+ } catch {
576
+ return {
577
+ isValid: !1,
578
+ taskId: o,
579
+ projectId: n,
580
+ resolvedUser: i,
581
+ error: {
582
+ type: L.PERMISSION_DENIED,
583
+ message: "Permission denied or API error occurred",
584
+ suggestions: [
585
+ "Check your API permissions",
586
+ "Verify you have access to the project",
587
+ "Try again later if this is a temporary API issue"
588
+ ]
589
+ }
590
+ };
591
+ }
592
+ }
593
+ /**
594
+ * Validate multiple assignment operations in bulk
595
+ */
596
+ async validateBulkAssignment(t, s) {
597
+ const o = s.map(
598
+ (n) => this.validateAssignment(t, n)
599
+ );
600
+ return Promise.all(o);
601
+ }
602
+ /**
603
+ * Validate assignment for task creation (no taskId required)
604
+ */
605
+ async validateTaskCreationAssignment(t, s, o) {
606
+ return this.validateAssignment(t, {
607
+ projectId: s,
608
+ responsibleUid: o
609
+ });
610
+ }
611
+ /**
612
+ * Validate assignment for task update
613
+ */
614
+ async validateTaskUpdateAssignment(t, s, o) {
615
+ if (o === null)
616
+ return {
617
+ isValid: !0,
618
+ taskId: s
619
+ };
620
+ try {
621
+ const n = await t.getTask(s);
622
+ return this.validateAssignment(t, {
623
+ taskId: s,
624
+ projectId: n.projectId,
625
+ responsibleUid: o
626
+ });
627
+ } catch {
628
+ return {
629
+ isValid: !1,
630
+ taskId: s,
631
+ error: {
632
+ type: L.TASK_NOT_FOUND,
633
+ message: `Task "${s}" not found or not accessible`,
634
+ suggestions: [
635
+ "Verify the task ID is correct",
636
+ "Check if the task has been deleted",
637
+ "Ensure you have access to the task"
638
+ ]
639
+ }
640
+ };
641
+ }
642
+ }
643
+ /**
644
+ * Get detailed assignment eligibility information for troubleshooting
645
+ */
646
+ async getAssignmentEligibility(t, s, o, n) {
647
+ const r = [];
648
+ let i = !1, a;
649
+ try {
650
+ a = await t.getProject(s);
651
+ } catch {
652
+ return {
653
+ canAssign: !1,
654
+ projectInfo: {
655
+ name: "Unknown",
656
+ isShared: !1,
657
+ collaboratorCount: 0
658
+ },
659
+ recommendations: ["Project not found or not accessible"]
660
+ };
661
+ }
662
+ const c = await _.getProjectCollaborators(t, s), l = {
663
+ name: a.name,
664
+ isShared: a.isShared,
665
+ collaboratorCount: c.length
666
+ };
667
+ if (!a.isShared)
668
+ return r.push("Share this project to enable task assignments"), { canAssign: !1, projectInfo: l, recommendations: r };
669
+ const u = await _.resolveUser(t, o);
670
+ if (!u)
671
+ return r.push("User not found - check spelling or invite to a shared project"), { canAssign: !1, projectInfo: l, recommendations: r };
672
+ const p = c.some((k) => k.id === u.userId), g = {
673
+ resolvedName: u.displayName,
674
+ isCollaborator: p
675
+ };
676
+ if (!p)
677
+ return r.push(
678
+ `Invite ${u.displayName} to collaborate on project "${a.name}"`
679
+ ), { canAssign: !1, projectInfo: l, userInfo: g, recommendations: r };
680
+ let h;
681
+ if (n && n.length > 0) {
682
+ let k = 0, j = 0;
683
+ for (const C of n)
684
+ try {
685
+ await t.getTask(C), k++;
686
+ } catch {
687
+ j++;
688
+ }
689
+ h = { accessibleTasks: k, inaccessibleTasks: j }, j > 0 && r.push(`${j} task(s) are not accessible`);
690
+ }
691
+ return i = !0, r.push(`Ready to assign tasks to ${u.displayName}`), {
692
+ canAssign: i,
693
+ projectInfo: l,
694
+ userInfo: g,
695
+ taskInfo: h,
696
+ recommendations: r
697
+ };
698
+ }
699
+ }
700
+ const te = new Ge(), Je = ["p1", "p2", "p3", "p4"], fe = d.enum(Je, {
701
+ description: "Task priority: p1 (highest), p2 (high), p3 (medium), p4 (lowest/default)"
702
+ });
703
+ function ge(e) {
704
+ return { p1: 4, p2: 3, p3: 2, p4: 1 }[e];
705
+ }
706
+ function qe(e) {
707
+ return { 4: "P1", 3: "P2", 2: "P3", 1: "P4" }[e] || "";
708
+ }
709
+ const S = {
710
+ /** Default limit for task listings */
711
+ TASKS_DEFAULT: 10,
712
+ /** Maximum limit for task search and list operations */
713
+ TASKS_MAX: 100,
714
+ /** Default limit for completed tasks */
715
+ COMPLETED_TASKS_DEFAULT: 50,
716
+ /** Maximum limit for completed tasks */
717
+ COMPLETED_TASKS_MAX: 200,
718
+ /** Default limit for project listings */
719
+ PROJECTS_DEFAULT: 50,
720
+ /** Maximum limit for project listings */
721
+ PROJECTS_MAX: 100,
722
+ /** Batch size for fetching all tasks in a project */
723
+ TASKS_BATCH_SIZE: 50,
724
+ /** Default limit for comment listings */
725
+ COMMENTS_DEFAULT: 10,
726
+ /** Maximum limit for comment search and list operations */
727
+ COMMENTS_MAX: 10,
728
+ /** Default limit for activity log listings */
729
+ ACTIVITY_DEFAULT: 20,
730
+ /** Maximum limit for activity log search and list operations */
731
+ ACTIVITY_MAX: 100
732
+ }, G = {
733
+ /** Maximum number of failures to show in detailed error messages */
734
+ MAX_FAILURES_SHOWN: 3
735
+ };
736
+ function Xe(e = /* @__PURE__ */ new Date()) {
737
+ return e.toISOString().split("T")[0] ?? "";
738
+ }
739
+ function be(e, t, s = {}) {
740
+ const { context: o, showDetails: n = !1 } = s, r = t.length, i = [], c = `${e} ${r} ${r === 1 ? "task" : "tasks"}${o ? ` ${o}` : ""}.`;
741
+ i.push(c);
742
+ const l = 5;
743
+ if (n || r <= l) {
744
+ const u = z(t, l);
745
+ if (u.length > 0) {
746
+ const p = r > l ? `, +${r - l} more` : "";
747
+ i.push(`Tasks:
748
+ ${u}${p}.`);
749
+ }
750
+ }
751
+ return i.join(`
752
+ `);
753
+ }
754
+ function Ze(e) {
755
+ const { action: t, success: s, total: o, successItems: n, failures: r } = e, i = [], a = `${t}: ${s}/${o} successful.`;
756
+ if (i.push(a), n?.length && n.length <= 5 && i.push(`Completed:
757
+ ${n.map((c) => ` ${c}`).join(`
758
+ `)}.`), r?.length) {
759
+ const c = r.length, l = `Failed (${c}):
760
+ ${r.slice(0, G.MAX_FAILURES_SHOWN).map((u) => ` ${u.item} (Error: ${u.error}${u.code ? ` [${u.code}]` : ""})`).join(
761
+ `
762
+ `
763
+ )}${c > G.MAX_FAILURES_SHOWN ? `, +${c - G.MAX_FAILURES_SHOWN} more` : ""}.`;
764
+ i.push(l);
765
+ }
766
+ return i.join(`
767
+ `);
768
+ }
769
+ function Qe(e) {
770
+ const t = e.content || e.title || "Untitled", s = e.dueDate ? ` • due ${e.dueDate}` : "", o = e.priority ? ` • ${qe(e.priority)}` : "", n = e.projectName ? ` • ${e.projectName}` : "", r = e.id ? ` • id=${e.id}` : "";
771
+ return ` ${t}${s}${o}${n}${r}`;
772
+ }
773
+ function et(e) {
774
+ const t = e.inboxProject ? " • Inbox" : "", s = e.isFavorite ? " • ⭐" : "", o = e.isShared ? " • Shared" : "", n = e.viewStyle && e.viewStyle !== "list" ? ` • ${e.viewStyle}` : "", r = ` • id=${e.id}`;
775
+ return ` ${e.name}${t}${s}${o}${n}${r}`;
776
+ }
777
+ function z(e, t = 5) {
778
+ const o = e.slice(0, t).map(Qe).join(`
779
+ `);
780
+ if (e.length > t) {
781
+ const n = e.length - t;
782
+ return `${o}
783
+ ... and ${n} more task${n === 1 ? "" : "s"}`;
784
+ }
785
+ return o;
786
+ }
787
+ function N({
788
+ subject: e,
789
+ count: t,
790
+ limit: s,
791
+ nextCursor: o,
792
+ filterHints: n,
793
+ previewLines: r,
794
+ zeroReasonHints: i,
795
+ nextSteps: a
796
+ }) {
797
+ const c = [], l = `${e}: ${t}${typeof s == "number" ? ` (limit ${s})` : ""}${o ? ", more available" : ""}.`;
798
+ return c.push(l), n?.length && c.push(`Filter: ${n.join("; ")}.`), r?.length && c.push(`Preview:
799
+ ${r}`), !t && i?.length && c.push(`No results. ${i.join("; ")}.`), (a?.length || o) && c.push(Te(a || [], o)), c.join(`
800
+ `);
801
+ }
802
+ function Te(e, t) {
803
+ const s = [...e];
804
+ return t && s.push(`Pass cursor '${t}' to fetch more results.`), `${s.length === 1 ? "Possible suggested next step:" : "Possible suggested next steps:"}
805
+ ${s.map((n) => `- ${n}`).join(`
806
+ `)}`;
807
+ }
808
+ const tt = d.object({
809
+ content: d.string().min(1).describe(
810
+ 'The task name/title. Should be concise and actionable (e.g., "Review PR #123", "Call dentist"). For longer content, use the description field instead. Supports Markdown.'
811
+ ),
812
+ description: d.string().optional().describe(
813
+ "Additional details, notes, or context for the task. Use this for longer content rather than putting it in the task name. Supports Markdown."
814
+ ),
815
+ priority: fe.optional().describe(
816
+ "The priority of the task: p1 (highest), p2 (high), p3 (medium), p4 (lowest/default)."
817
+ ),
818
+ dueString: d.string().optional().describe("The due date for the task, in natural language."),
819
+ deadlineDate: d.string().optional().describe(
820
+ 'The deadline date for the task in ISO 8601 format (YYYY-MM-DD, e.g., "2025-12-31"). Deadlines are immovable constraints shown with a different indicator than due dates.'
821
+ ),
822
+ duration: d.string().optional().describe(
823
+ 'The duration of the task. Use format: "2h" (hours), "90m" (minutes), "2h30m" (combined), or "1.5h" (decimal hours). Max 24h.'
824
+ ),
825
+ labels: d.array(d.string()).optional().describe("The labels to attach to the task."),
826
+ projectId: d.string().optional().describe(
827
+ 'The project ID to add this task to. Project ID should be an ID string, or the text "inbox", for inbox tasks.'
828
+ ),
829
+ sectionId: d.string().optional().describe("The section ID to add this task to."),
830
+ parentId: d.string().optional().describe("The parent task ID (for subtasks)."),
831
+ responsibleUser: d.string().optional().describe(
832
+ "Assign task to this user. Can be a user ID, name, or email address. User must be a collaborator on the target project."
833
+ )
834
+ }), st = {
835
+ tasks: d.array(tt).min(1).describe("The array of tasks to add.")
836
+ }, ot = {
837
+ name: I.ADD_TASKS,
838
+ description: "Add one or more tasks to a project, section, or parent. Supports assignment to project collaborators.",
839
+ parameters: st,
840
+ async execute({ tasks: e }, t) {
841
+ const s = e.map((i) => nt(i, t)), n = (await Promise.all(s)).map(O), r = rt({
842
+ tasks: n,
843
+ args: { tasks: e }
844
+ });
845
+ return T({
846
+ textContent: r,
847
+ structuredContent: {
848
+ tasks: n,
849
+ totalCount: n.length
850
+ }
851
+ });
852
+ }
853
+ };
854
+ async function nt(e, t) {
855
+ const {
856
+ duration: s,
857
+ projectId: o,
858
+ sectionId: n,
859
+ parentId: r,
860
+ responsibleUser: i,
861
+ priority: a,
862
+ labels: c,
863
+ deadlineDate: l,
864
+ ...u
865
+ } = e;
866
+ let p = o;
867
+ o === "inbox" && (p = (await t.getUser()).inboxProjectId);
868
+ let g = {
869
+ ...u,
870
+ projectId: p,
871
+ sectionId: n,
872
+ parentId: r,
873
+ labels: c,
874
+ deadlineDate: l
875
+ };
876
+ if (a && (g.priority = ge(a)), i && !p && !n && !r)
877
+ throw new Error(
878
+ `Task "${e.content}": Cannot assign tasks without specifying project context. Please specify a projectId, sectionId, or parentId.`
879
+ );
880
+ if (s)
881
+ try {
882
+ const { minutes: h } = pe(s);
883
+ g = {
884
+ ...g,
885
+ duration: h,
886
+ durationUnit: "minute"
887
+ };
888
+ } catch (h) {
889
+ throw h instanceof P ? new Error(`Task "${e.content}": ${h.message}`) : h;
890
+ }
891
+ if (i) {
892
+ let h = p;
893
+ if (!h && r)
894
+ try {
895
+ h = (await t.getTask(r)).projectId;
896
+ } catch {
897
+ throw new Error(`Task "${e.content}": Parent task "${r}" not found`);
898
+ }
899
+ else if (!h && n)
900
+ throw new Error(
901
+ `Task "${e.content}": When assigning tasks to sections, please also specify projectId`
902
+ );
903
+ if (!h)
904
+ throw new Error(
905
+ `Task "${e.content}": Cannot determine target project for assignment validation`
906
+ );
907
+ const k = await te.validateTaskCreationAssignment(
908
+ t,
909
+ h,
910
+ i
911
+ );
912
+ if (!k.isValid) {
913
+ const j = k.error?.message || "Assignment validation failed", C = k.error?.suggestions?.join(". ") || "";
914
+ throw new Error(
915
+ `Task "${e.content}": ${j}${C ? `. ${C}` : ""}`
916
+ );
917
+ }
918
+ g.assigneeId = k.resolvedUser?.userId;
919
+ }
920
+ return await t.addTask(g);
921
+ }
922
+ function rt({
923
+ tasks: e,
924
+ args: t
925
+ }) {
926
+ const s = /* @__PURE__ */ new Set();
927
+ for (const n of t.tasks)
928
+ n.projectId ? s.add("projects") : n.sectionId ? s.add("sections") : n.parentId ? s.add("subtasks") : s.add("inbox");
929
+ let o = "";
930
+ if (s.size === 1) {
931
+ const n = Array.from(s)[0];
932
+ o = n === "inbox" ? "" : `to ${n}`;
933
+ } else s.size > 1 && (o = "to multiple contexts");
934
+ return be("Added", e, {
935
+ context: o,
936
+ showDetails: !0
937
+ });
938
+ }
939
+ const it = {
940
+ ids: d.array(d.string().min(1)).min(1).describe("The IDs of the tasks to complete.")
941
+ }, at = {
942
+ name: I.COMPLETE_TASKS,
943
+ description: "Complete one or more tasks by their IDs.",
944
+ parameters: it,
945
+ async execute(e, t) {
946
+ const s = [], o = [];
947
+ for (const r of e.ids)
948
+ try {
949
+ await t.closeTask(r), s.push(r);
950
+ } catch (i) {
951
+ const a = i instanceof Error ? i.message : "Unknown error";
952
+ o.push({
953
+ item: r,
954
+ error: a
955
+ });
956
+ }
957
+ const n = ct({
958
+ completed: s,
959
+ failures: o,
960
+ args: e
961
+ });
962
+ return T({
963
+ textContent: n,
964
+ structuredContent: {
965
+ completed: s,
966
+ failures: o,
967
+ totalRequested: e.ids.length,
968
+ successCount: s.length,
969
+ failureCount: o.length
970
+ }
971
+ });
972
+ }
973
+ };
974
+ function ct({
975
+ completed: e,
976
+ failures: t,
977
+ args: s
978
+ }) {
979
+ return Ze({
980
+ action: "Completed tasks",
981
+ success: e.length,
982
+ total: s.ids.length,
983
+ successItems: e,
984
+ failures: t
985
+ });
986
+ }
987
+ const lt = {
988
+ type: d.enum(["project", "section", "task", "comment"]).describe("The type of entity to delete."),
989
+ id: d.string().min(1).describe("The ID of the entity to delete.")
990
+ }, dt = {
991
+ name: I.DELETE_OBJECT,
992
+ description: "Delete a project, section, task, or comment by its ID.",
993
+ parameters: lt,
994
+ async execute(e, t) {
995
+ switch (e.type) {
996
+ case "project":
997
+ await t.deleteProject(e.id);
998
+ break;
999
+ case "section":
1000
+ await t.deleteSection(e.id);
1001
+ break;
1002
+ case "task":
1003
+ await t.deleteTask(e.id);
1004
+ break;
1005
+ case "comment":
1006
+ await t.deleteComment(e.id);
1007
+ break;
1008
+ }
1009
+ const s = ut({
1010
+ type: e.type,
1011
+ id: e.id
1012
+ });
1013
+ return T({
1014
+ textContent: s,
1015
+ structuredContent: {
1016
+ deletedEntity: {
1017
+ type: e.type,
1018
+ id: e.id
1019
+ },
1020
+ success: !0
1021
+ }
1022
+ });
1023
+ }
1024
+ };
1025
+ function ut({
1026
+ type: e,
1027
+ id: t
1028
+ }) {
1029
+ return `Deleted ${e}: id=${t}`;
1030
+ }
1031
+ const pt = {
1032
+ id: d.string().min(1).describe(
1033
+ 'A unique identifier for the document in the format "task:{id}" or "project:{id}".'
1034
+ )
1035
+ }, mt = {
1036
+ name: I.FETCH,
1037
+ description: 'Fetch the full contents of a task or project by its ID. The ID should be in the format "task:{id}" or "project:{id}".',
1038
+ parameters: pt,
1039
+ async execute(e, t) {
1040
+ try {
1041
+ const { id: s } = e, [o, n] = s.split(":", 2);
1042
+ if (!n || o !== "task" && o !== "project")
1043
+ throw new Error(
1044
+ 'Invalid ID format. Expected "task:{id}" or "project:{id}". Example: "task:8485093748" or "project:6cfCcrrCFg2xP94Q"'
1045
+ );
1046
+ let r;
1047
+ if (o === "task") {
1048
+ const a = await t.getTask(n), c = O(a), l = [c.content];
1049
+ c.description && l.push(`
1050
+
1051
+ Description: ${c.description}`), c.dueDate && l.push(`
1052
+ Due: ${c.dueDate}`), c.labels.length > 0 && l.push(`
1053
+ Labels: ${c.labels.join(", ")}`), r = {
1054
+ id: `task:${c.id}`,
1055
+ title: c.content,
1056
+ text: l.join(""),
1057
+ url: le(c.id),
1058
+ metadata: {
1059
+ priority: c.priority,
1060
+ projectId: c.projectId,
1061
+ sectionId: c.sectionId,
1062
+ parentId: c.parentId,
1063
+ recurring: c.recurring,
1064
+ duration: c.duration,
1065
+ responsibleUid: c.responsibleUid,
1066
+ assignedByUid: c.assignedByUid,
1067
+ checked: c.checked,
1068
+ completedAt: c.completedAt
1069
+ }
1070
+ };
1071
+ } else {
1072
+ const a = await t.getProject(n), c = he(a), l = [c.name];
1073
+ c.isShared && l.push(`
1074
+
1075
+ Shared project`), c.isFavorite && l.push(`
1076
+ Favorite: Yes`), r = {
1077
+ id: `project:${c.id}`,
1078
+ title: c.name,
1079
+ text: l.join(""),
1080
+ url: de(c.id),
1081
+ metadata: {
1082
+ color: c.color,
1083
+ isFavorite: c.isFavorite,
1084
+ isShared: c.isShared,
1085
+ parentId: c.parentId,
1086
+ inboxProject: c.inboxProject,
1087
+ viewStyle: c.viewStyle
1088
+ }
1089
+ };
1090
+ }
1091
+ return { content: [{ type: "text", text: JSON.stringify(r) }] };
1092
+ } catch (s) {
1093
+ const o = s instanceof Error ? s.message : "An unknown error occurred";
1094
+ return Z(o);
1095
+ }
1096
+ }
1097
+ }, ht = {
1098
+ objectType: d.enum(["task", "project", "comment"]).optional().describe("Type of object to filter by."),
1099
+ objectId: d.string().optional().describe("Filter by specific object ID (task, project, or comment)."),
1100
+ eventType: d.enum([
1101
+ "added",
1102
+ "updated",
1103
+ "deleted",
1104
+ "completed",
1105
+ "uncompleted",
1106
+ "archived",
1107
+ "unarchived",
1108
+ "shared",
1109
+ "left"
1110
+ ]).optional().describe("Type of event to filter by."),
1111
+ projectId: d.string().optional().describe("Filter events by parent project ID."),
1112
+ taskId: d.string().optional().describe("Filter events by parent task ID (for subtask events)."),
1113
+ initiatorId: d.string().optional().describe("Filter by the user ID who initiated the event."),
1114
+ limit: d.number().int().min(1).max(S.ACTIVITY_MAX).default(S.ACTIVITY_DEFAULT).describe("Maximum number of activity events to return."),
1115
+ cursor: d.string().optional().describe("Pagination cursor for retrieving the next page of results.")
1116
+ }, ft = {
1117
+ name: I.FIND_ACTIVITY,
1118
+ description: "Retrieve recent activity logs to monitor and audit changes in Todoist. Shows events from all users by default (use initiatorId to filter by specific user). Track task completions, updates, deletions, project changes, and more with flexible filtering. Note: Date-based filtering is not supported by the Todoist API.",
1119
+ parameters: ht,
1120
+ async execute(e, t) {
1121
+ const { objectType: s, objectId: o, eventType: n, projectId: r, taskId: i, initiatorId: a, limit: c, cursor: l } = e, u = {
1122
+ limit: c,
1123
+ cursor: l ?? null
1124
+ };
1125
+ s && (u.objectType = s), o && o !== "remove" && (u.objectId = o), n && (u.eventType = n), r && (u.parentProjectId = r), i && (u.parentItemId = i), a && (u.initiatorId = a);
1126
+ const { results: p, nextCursor: g } = await t.getActivityLogs(u), h = p.map(He), k = gt({
1127
+ events: h,
1128
+ args: e,
1129
+ nextCursor: g
1130
+ });
1131
+ return T({
1132
+ textContent: k,
1133
+ structuredContent: {
1134
+ events: h,
1135
+ nextCursor: g,
1136
+ totalCount: h.length,
1137
+ hasMore: !!g,
1138
+ appliedFilters: e
1139
+ }
1140
+ });
1141
+ }
1142
+ };
1143
+ function gt({
1144
+ events: e,
1145
+ args: t,
1146
+ nextCursor: s
1147
+ }) {
1148
+ let o = "Activity events";
1149
+ const n = [];
1150
+ if (t.eventType && n.push(`${t.eventType}`), t.objectType) {
1151
+ const a = t.objectType === "task" ? "tasks" : `${t.objectType}s`;
1152
+ n.push(a);
1153
+ }
1154
+ n.length > 0 && (o = `Activity: ${n.join(" ")}`);
1155
+ const r = [];
1156
+ t.objectId && r.push(`object ID: ${t.objectId}`), t.projectId && r.push(`project: ${t.projectId}`), t.taskId && r.push(`task: ${t.taskId}`), t.initiatorId && r.push(`initiator: ${t.initiatorId}`);
1157
+ const i = [];
1158
+ return e.length === 0 && (i.push("No activity events match the specified filters"), i.push("Note: Activity logs only show recent events"), t.eventType && i.push(`Try removing the eventType filter (${t.eventType})`), t.objectType && i.push(`Try removing the objectType filter (${t.objectType})`), (t.objectId || t.projectId || t.taskId) && i.push("Verify the object ID is correct")), N({
1159
+ subject: o,
1160
+ count: e.length,
1161
+ limit: t.limit,
1162
+ nextCursor: s ?? void 0,
1163
+ filterHints: r,
1164
+ previewLines: bt(e, Math.min(e.length, t.limit)),
1165
+ zeroReasonHints: i
1166
+ });
1167
+ }
1168
+ function bt(e, t = 10) {
1169
+ const o = e.slice(0, t).map(Tt).join(`
1170
+ `);
1171
+ if (e.length > t) {
1172
+ const n = e.length - t;
1173
+ return `${o}
1174
+ ... and ${n} more event${n === 1 ? "" : "s"}`;
1175
+ }
1176
+ return o;
1177
+ }
1178
+ function Tt(e) {
1179
+ const t = It(e.eventDate), s = `${e.eventType} ${e.objectType}`;
1180
+ let o = "";
1181
+ if (e.extraData) {
1182
+ const a = e.extraData.content || e.extraData.name || e.extraData.last_content;
1183
+ a && typeof a == "string" && (o = ` • "${a.length > 50 ? `${a.substring(0, 47)}...` : a}"`);
1184
+ }
1185
+ const n = e.objectId ? ` • id=${e.objectId}` : "", r = e.initiatorId ? ` • by=${e.initiatorId}` : " • system", i = e.parentProjectId ? ` • project=${e.parentProjectId}` : "";
1186
+ return ` [${t}] ${s}${o}${n}${r}${i}`;
1187
+ }
1188
+ function It(e) {
1189
+ try {
1190
+ const t = new Date(e), s = t.toLocaleDateString("en-US", { month: "short", timeZone: "UTC" }), o = t.toLocaleDateString("en-US", { day: "numeric", timeZone: "UTC" }), n = t.toLocaleTimeString("en-US", {
1191
+ hour: "2-digit",
1192
+ minute: "2-digit",
1193
+ hour12: !1,
1194
+ timeZone: "UTC"
1195
+ });
1196
+ return `${s} ${o}, ${n}`;
1197
+ } catch {
1198
+ return e;
1199
+ }
1200
+ }
1201
+ const yt = {
1202
+ taskId: d.string().optional().describe("Find comments for a specific task."),
1203
+ projectId: d.string().optional().describe(
1204
+ 'Find comments for a specific project. Project ID should be an ID string, or the text "inbox", for inbox tasks.'
1205
+ ),
1206
+ commentId: d.string().optional().describe("Get a specific comment by ID."),
1207
+ cursor: d.string().optional().describe("Pagination cursor for retrieving more results."),
1208
+ limit: d.number().int().min(1).max(S.COMMENTS_MAX).optional().describe("Maximum number of comments to return")
1209
+ }, kt = {
1210
+ name: I.FIND_COMMENTS,
1211
+ description: "Find comments by task, project, or get a specific comment by ID. Exactly one of taskId, projectId, or commentId must be provided.",
1212
+ parameters: yt,
1213
+ async execute(e, t) {
1214
+ const s = [e.taskId, e.projectId, e.commentId].filter(Boolean);
1215
+ if (s.length === 0)
1216
+ throw new Error("Must provide exactly one of: taskId, projectId, or commentId.");
1217
+ if (s.length > 1)
1218
+ throw new Error(
1219
+ "Cannot provide multiple search parameters. Choose one of: taskId, projectId, or commentId."
1220
+ );
1221
+ const o = e.projectId === "inbox" ? (await t.getUser()).inboxProjectId : e.projectId;
1222
+ let n, r = !1, i = null;
1223
+ if (e.commentId)
1224
+ n = [await t.getComment(e.commentId)];
1225
+ else if (e.taskId) {
1226
+ const c = await t.getComments({
1227
+ taskId: e.taskId,
1228
+ cursor: e.cursor || null,
1229
+ limit: e.limit || S.COMMENTS_DEFAULT
1230
+ });
1231
+ n = c.results, r = c.nextCursor !== null, i = c.nextCursor;
1232
+ } else if (o) {
1233
+ const c = await t.getComments({
1234
+ projectId: o,
1235
+ cursor: e.cursor || null,
1236
+ limit: e.limit || S.COMMENTS_DEFAULT
1237
+ });
1238
+ n = c.results, r = c.nextCursor !== null, i = c.nextCursor;
1239
+ } else
1240
+ throw new Error("Invalid state: no search parameter provided");
1241
+ const a = wt({
1242
+ comments: n,
1243
+ searchType: e.commentId ? "single" : e.taskId ? "task" : "project",
1244
+ searchId: e.commentId || e.taskId || e.projectId || "",
1245
+ hasMore: r,
1246
+ nextCursor: i
1247
+ });
1248
+ return T({
1249
+ textContent: a,
1250
+ structuredContent: {
1251
+ comments: n,
1252
+ searchType: e.commentId ? "single" : e.taskId ? "task" : "project",
1253
+ searchId: e.commentId || e.taskId || e.projectId || "",
1254
+ hasMore: r,
1255
+ nextCursor: i,
1256
+ totalCount: n.length
1257
+ }
1258
+ });
1259
+ }
1260
+ };
1261
+ function wt({
1262
+ comments: e,
1263
+ searchType: t,
1264
+ searchId: s,
1265
+ hasMore: o,
1266
+ nextCursor: n
1267
+ }) {
1268
+ if (e.length === 0)
1269
+ return `No comments found for ${t}${t !== "single" ? ` ${s}` : ""}`;
1270
+ let r;
1271
+ if (t === "single") {
1272
+ const i = e[0];
1273
+ if (!i)
1274
+ return "Comment not found";
1275
+ r = `Found comment${i.fileAttachment !== null ? ` • Has attachment: ${i.fileAttachment?.fileName || "file"}` : ""} • id=${i.id}`;
1276
+ } else {
1277
+ const i = e.filter((l) => l.fileAttachment !== null).length, a = i > 0 ? ` (${i} with attachments)` : "", c = e.length === 1 ? "comment" : "comments";
1278
+ r = `Found ${e.length} ${c} for ${t} ${s}${a}`, o && (r += " • More available");
1279
+ }
1280
+ if (n) {
1281
+ const i = Te([], n);
1282
+ return `${r}
1283
+ ${i}`;
1284
+ }
1285
+ return r;
1286
+ }
1287
+ const jt = ["and", "or"], se = {
1288
+ labels: d.string().array().optional().describe("The labels to filter the tasks by"),
1289
+ labelsOperator: d.enum(jt).optional().describe(
1290
+ 'The operator to use when filtering by labels. This will dictate whether a task has all labels, or some of them. Default is "or".'
1291
+ )
1292
+ };
1293
+ function oe(e = [], t = "or") {
1294
+ if (e.length === 0) return "";
1295
+ const s = t === "and" ? " & " : " | ";
1296
+ return `(${e.map((r) => r.startsWith("@") ? r : `@${r}`).join(` ${s} `)})`;
1297
+ }
1298
+ const $t = {
1299
+ getBy: d.enum(["completion", "due"]).default("completion").describe(
1300
+ '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).'
1301
+ ),
1302
+ since: d.string().date().regex(/^\d{4}-\d{2}-\d{2}$/).describe("The start date to get the tasks for. Format: YYYY-MM-DD."),
1303
+ until: d.string().date().regex(/^\d{4}-\d{2}-\d{2}$/).describe("The start date to get the tasks for. Format: YYYY-MM-DD."),
1304
+ workspaceId: d.string().optional().describe("The ID of the workspace to get the tasks for."),
1305
+ projectId: d.string().optional().describe(
1306
+ 'The ID of the project to get the tasks for. Project ID should be an ID string, or the text "inbox", for inbox tasks.'
1307
+ ),
1308
+ sectionId: d.string().optional().describe("The ID of the section to get the tasks for."),
1309
+ parentId: d.string().optional().describe("The ID of the parent task to get the tasks for."),
1310
+ responsibleUser: d.string().optional().describe(
1311
+ "Find tasks assigned to this user. Can be a user ID, name, or email address. Defaults to all collaborators when omitted."
1312
+ ),
1313
+ limit: d.number().int().min(1).max(S.COMPLETED_TASKS_MAX).default(S.COMPLETED_TASKS_DEFAULT).describe("The maximum number of tasks to return."),
1314
+ cursor: d.string().optional().describe(
1315
+ "The cursor to get the next page of tasks (cursor is obtained from the previous call to this tool, with the same parameters)."
1316
+ ),
1317
+ ...se
1318
+ }, Ct = {
1319
+ name: I.FIND_COMPLETED_TASKS,
1320
+ description: "Get completed tasks (includes all collaborators by default—use responsibleUser to narrow).",
1321
+ parameters: $t,
1322
+ async execute(e, t) {
1323
+ const { getBy: s, labels: o, labelsOperator: n, since: r, until: i, responsibleUser: a, projectId: c, ...l } = e, u = await Q(t, a), p = u?.email;
1324
+ let h = oe(o, n);
1325
+ u && p && (h = V(h, `assigned to: ${p}`));
1326
+ const k = await t.getUser(), j = k.tzInfo?.gmtString || "+00:00", C = c === "inbox" ? k.inboxProjectId : c, x = `${r}T00:00:00${j}`, E = `${i}T23:59:59${j}`, m = new Date(x).toISOString(), y = new Date(E).toISOString(), { items: v, nextCursor: b } = s === "completion" ? await t.getCompletedTasksByCompletionDate({
1327
+ ...l,
1328
+ projectId: C,
1329
+ since: m,
1330
+ until: y,
1331
+ ...h ? { filterQuery: h, filterLang: "en" } : {}
1332
+ }) : await t.getCompletedTasksByDueDate({
1333
+ ...l,
1334
+ projectId: C,
1335
+ since: m,
1336
+ until: y,
1337
+ ...h ? { filterQuery: h, filterLang: "en" } : {}
1338
+ }), f = v.map(O), $ = vt({
1339
+ tasks: f,
1340
+ args: e,
1341
+ nextCursor: b,
1342
+ assigneeEmail: p
1343
+ });
1344
+ return T({
1345
+ textContent: $,
1346
+ structuredContent: {
1347
+ tasks: f,
1348
+ nextCursor: b,
1349
+ totalCount: f.length,
1350
+ hasMore: !!b,
1351
+ appliedFilters: e
1352
+ }
1353
+ });
1354
+ }
1355
+ };
1356
+ function vt({
1357
+ tasks: e,
1358
+ args: t,
1359
+ nextCursor: s,
1360
+ assigneeEmail: o
1361
+ }) {
1362
+ const n = t.getBy === "completion" ? "completed" : "due", r = `Completed tasks (by ${n} date)`, i = [];
1363
+ if (i.push(`${n} date: ${t.since} to ${t.until}`), t.projectId && i.push(`project: ${t.projectId}`), t.sectionId && i.push(`section: ${t.sectionId}`), t.parentId && i.push(`parent: ${t.parentId}`), t.workspaceId && i.push(`workspace: ${t.workspaceId}`), t.labels && t.labels.length > 0) {
1364
+ const c = t.labels.map((l) => `@${l}`).join(t.labelsOperator === "and" ? " & " : " | ");
1365
+ i.push(`labels: ${c}`);
1366
+ }
1367
+ if (t.responsibleUser) {
1368
+ const c = o || t.responsibleUser;
1369
+ i.push(`assigned to: ${c}`);
1370
+ }
1371
+ const a = [];
1372
+ return e.length === 0 && (a.push("No tasks completed in this date range"), a.push("Try expanding the date range"), (t.projectId || t.sectionId || t.parentId) && a.push("Try removing project/section/parent filters"), t.getBy === "due" && a.push('Try switching to "completion" date instead')), N({
1373
+ subject: r,
1374
+ count: e.length,
1375
+ limit: t.limit,
1376
+ nextCursor: s ?? void 0,
1377
+ filterHints: i,
1378
+ previewLines: z(e, Math.min(e.length, t.limit)),
1379
+ zeroReasonHints: a
1380
+ });
1381
+ }
1382
+ const { FIND_PROJECTS: St, ADD_TASKS: Ie, UPDATE_TASKS: ye } = I, Dt = {
1383
+ projectId: d.string().min(1).describe("The ID of the project to search for collaborators in."),
1384
+ searchTerm: d.string().optional().describe(
1385
+ "Search for a collaborator by name or email (partial and case insensitive match). If omitted, all collaborators in the project are returned."
1386
+ )
1387
+ }, xt = {
1388
+ name: I.FIND_PROJECT_COLLABORATORS,
1389
+ description: "Search for collaborators by name or other criteria in a project.",
1390
+ parameters: Dt,
1391
+ async execute(e, t) {
1392
+ const { projectId: s, searchTerm: o } = e;
1393
+ let n = s, r;
1394
+ try {
1395
+ if (r = await t.getProject(s), !r)
1396
+ throw new Error(`Project with ID "${s}" not found or not accessible`);
1397
+ if (n = r.name, !r.isShared) {
1398
+ const l = `Project "${n}" is not shared and has no collaborators.
1399
+
1400
+ **Next steps:**
1401
+ • Share the project to enable collaboration
1402
+ • Use ${Ie} and ${ye} for assignment features once shared`;
1403
+ return T({
1404
+ textContent: l,
1405
+ structuredContent: {
1406
+ collaborators: [],
1407
+ projectInfo: {
1408
+ id: s,
1409
+ name: n,
1410
+ isShared: !1
1411
+ },
1412
+ totalCount: 0,
1413
+ appliedFilters: e
1414
+ }
1415
+ });
1416
+ }
1417
+ } catch (l) {
1418
+ throw new Error(
1419
+ `Failed to access project "${s}": ${l instanceof Error ? l.message : "Unknown error"}`
1420
+ );
1421
+ }
1422
+ const i = await _.getProjectCollaborators(t, s);
1423
+ if (i.length === 0) {
1424
+ const l = `Project "${n}" has no collaborators or collaborator data is not accessible.
1425
+
1426
+ **Next steps:**
1427
+ • Check project sharing settings
1428
+ • Ensure you have permission to view collaborators
1429
+ • Try refreshing or re-sharing the project`;
1430
+ return T({
1431
+ textContent: l,
1432
+ structuredContent: {
1433
+ collaborators: [],
1434
+ projectInfo: {
1435
+ id: s,
1436
+ name: n,
1437
+ isShared: !0
1438
+ },
1439
+ totalCount: 0,
1440
+ appliedFilters: e
1441
+ }
1442
+ });
1443
+ }
1444
+ let a = i;
1445
+ if (o) {
1446
+ const l = o.toLowerCase().trim();
1447
+ a = i.filter(
1448
+ (u) => u.name.toLowerCase().includes(l) || u.email.toLowerCase().includes(l)
1449
+ );
1450
+ }
1451
+ const c = At({
1452
+ collaborators: a,
1453
+ projectName: n,
1454
+ searchTerm: o,
1455
+ totalAvailable: i.length
1456
+ });
1457
+ return T({
1458
+ textContent: c,
1459
+ structuredContent: {
1460
+ collaborators: a,
1461
+ projectInfo: {
1462
+ id: s,
1463
+ name: n,
1464
+ isShared: !0
1465
+ },
1466
+ totalCount: a.length,
1467
+ totalAvailable: i.length,
1468
+ appliedFilters: e
1469
+ }
1470
+ });
1471
+ }
1472
+ };
1473
+ function At({
1474
+ collaborators: e,
1475
+ projectName: t,
1476
+ searchTerm: s,
1477
+ totalAvailable: o
1478
+ }) {
1479
+ const n = s ? `Project collaborators matching "${s}"` : "Project collaborators", r = [];
1480
+ s && r.push(`matching "${s}"`), r.push(`in project "${t}"`);
1481
+ let i = [];
1482
+ e.length > 0 && (i = e.slice(0, 10).map((l) => {
1483
+ const u = l.name || "Unknown Name", p = l.email || "No email";
1484
+ return `• ${u} (${p}) - ID: ${l.id}`;
1485
+ }), e.length > 10 && i.push(`... and ${e.length - 10} more`));
1486
+ const a = [];
1487
+ e.length === 0 && (s ? (a.push(`No collaborators match "${s}"`), a.push("Try a broader search term or check spelling"), o > 0 && a.push(`${o} collaborators available without filter`)) : (a.push("Project has no collaborators"), a.push("Share the project to add collaborators")));
1488
+ const c = [];
1489
+ return e.length > 0 ? (c.push(`Use ${Ie} with responsibleUser to assign new tasks`), c.push(`Use ${ye} with responsibleUser to reassign existing tasks`), c.push("Use collaborator names, emails, or IDs for assignments")) : (c.push(`Use ${St} to find other projects`), s && o > 0 && c.push("Try searching without filters to see all collaborators")), N({
1490
+ subject: n,
1491
+ count: e.length,
1492
+ filterHints: r,
1493
+ previewLines: i.join(`
1494
+ `),
1495
+ zeroReasonHints: a,
1496
+ nextSteps: c
1497
+ });
1498
+ }
1499
+ const { ADD_PROJECTS: Ut } = I, Pt = {
1500
+ search: d.string().optional().describe(
1501
+ "Search for a project by name (partial and case insensitive match). If omitted, all projects are returned."
1502
+ ),
1503
+ limit: d.number().int().min(1).max(S.PROJECTS_MAX).default(S.PROJECTS_DEFAULT).describe("The maximum number of projects to return."),
1504
+ cursor: d.string().optional().describe(
1505
+ "The cursor to get the next page of projects (cursor is obtained from the previous call to this tool, with the same parameters)."
1506
+ )
1507
+ }, Et = {
1508
+ name: I.FIND_PROJECTS,
1509
+ description: "List all projects or search for projects by name. If search parameter is omitted, all projects are returned.",
1510
+ parameters: Pt,
1511
+ async execute(e, t) {
1512
+ const { results: s, nextCursor: o } = await t.getProjects({
1513
+ limit: e.limit,
1514
+ cursor: e.cursor ?? null
1515
+ }), n = e.search ? e.search.toLowerCase() : void 0, i = (n ? s.filter((a) => a.name.toLowerCase().includes(n)) : s).map(he);
1516
+ return T({
1517
+ textContent: Ot({
1518
+ projects: i,
1519
+ args: e,
1520
+ nextCursor: o
1521
+ }),
1522
+ structuredContent: {
1523
+ projects: i,
1524
+ nextCursor: o,
1525
+ totalCount: i.length,
1526
+ hasMore: !!o,
1527
+ appliedFilters: e
1528
+ }
1529
+ });
1530
+ }
1531
+ };
1532
+ function Ot({
1533
+ projects: e,
1534
+ args: t,
1535
+ nextCursor: s
1536
+ }) {
1537
+ const o = t.search ? `Projects matching "${t.search}"` : "Projects", n = [];
1538
+ t.search && n.push(`search: "${t.search}"`);
1539
+ const r = 10, a = e.slice(0, r).map(et).join(`
1540
+ `), c = e.length - r, l = c > 0 ? `${a}
1541
+ …and ${c} more` : a, u = [];
1542
+ return e.length === 0 && (t.search ? (u.push("Try broader search terms"), u.push("Check spelling"), u.push("Remove search to see all projects")) : (u.push("No projects created yet"), u.push(`Use ${Ut} to create a project`))), N({
1543
+ subject: o,
1544
+ count: e.length,
1545
+ limit: t.limit,
1546
+ nextCursor: s ?? void 0,
1547
+ filterHints: n,
1548
+ previewLines: l,
1549
+ zeroReasonHints: u
1550
+ });
1551
+ }
1552
+ const { ADD_SECTIONS: _t } = I, Nt = {
1553
+ projectId: d.string().min(1).describe(
1554
+ 'The ID of the project to search sections in. Project ID should be an ID string, or the text "inbox", for inbox tasks.'
1555
+ ),
1556
+ search: d.string().optional().describe(
1557
+ "Search for a section by name (partial and case insensitive match). If omitted, all sections in the project are returned."
1558
+ )
1559
+ }, Mt = {
1560
+ name: I.FIND_SECTIONS,
1561
+ description: "Search for sections by name or other criteria in a project.",
1562
+ parameters: Nt,
1563
+ async execute(e, t) {
1564
+ const s = e.projectId === "inbox" ? (await t.getUser()).inboxProjectId : e.projectId, { results: o } = await t.getSections({
1565
+ projectId: s
1566
+ }), n = e.search ? e.search.toLowerCase() : void 0, i = (n ? o.filter((c) => c.name.toLowerCase().includes(n)) : o).map((c) => ({
1567
+ id: c.id,
1568
+ name: c.name
1569
+ })), a = Ft({
1570
+ sections: i,
1571
+ projectId: e.projectId,
1572
+ search: e.search
1573
+ });
1574
+ return T({
1575
+ textContent: a,
1576
+ structuredContent: {
1577
+ sections: i,
1578
+ totalCount: i.length,
1579
+ appliedFilters: e
1580
+ }
1581
+ });
1582
+ }
1583
+ };
1584
+ function Ft({
1585
+ sections: e,
1586
+ projectId: t,
1587
+ search: s
1588
+ }) {
1589
+ const o = [];
1590
+ s ? (o.push("Try broader search terms"), o.push("Check spelling"), o.push("Remove search to see all sections")) : (o.push("Project has no sections yet"), o.push(`Use ${_t} to create sections`));
1591
+ const n = s ? `Sections in project ${t} matching "${s}"` : `Sections in project ${t}`, r = e.length > 0 ? e.map((i) => ` ${i.name} • id=${i.id}`).join(`
1592
+ `) : void 0;
1593
+ return N({
1594
+ subject: n,
1595
+ count: e.length,
1596
+ previewLines: r,
1597
+ zeroReasonHints: o
1598
+ });
1599
+ }
1600
+ const { FIND_COMPLETED_TASKS: re, ADD_TASKS: ie } = I, Rt = {
1601
+ searchText: d.string().optional().describe("The text to search for in tasks."),
1602
+ projectId: d.string().optional().describe(
1603
+ 'Find tasks in this project. Project ID should be an ID string, or the text "inbox", for inbox tasks.'
1604
+ ),
1605
+ sectionId: d.string().optional().describe("Find tasks in this section."),
1606
+ parentId: d.string().optional().describe("Find subtasks of this parent task."),
1607
+ responsibleUser: d.string().optional().describe("Find tasks assigned to this user. Can be a user ID, name, or email address."),
1608
+ responsibleUserFiltering: d.enum(me).optional().describe(
1609
+ 'How to filter by responsible user when responsibleUser is not provided. "assigned" = only tasks assigned to others; "unassignedOrMe" = only unassigned tasks or tasks assigned to me; "all" = all tasks regardless of assignment. Default value will be `unassignedOrMe`.'
1610
+ ),
1611
+ limit: d.number().int().min(1).max(S.TASKS_MAX).default(S.TASKS_DEFAULT).describe("The maximum number of tasks to return."),
1612
+ cursor: d.string().optional().describe(
1613
+ "The cursor to get the next page of tasks (cursor is obtained from the previous call to this tool, with the same parameters)."
1614
+ ),
1615
+ ...se
1616
+ }, Lt = {
1617
+ name: I.FIND_TASKS,
1618
+ description: "Find tasks by text search, or by project/section/parent container/responsible user. At least one filter must be provided.",
1619
+ parameters: Rt,
1620
+ async execute(e, t) {
1621
+ const {
1622
+ searchText: s,
1623
+ projectId: o,
1624
+ sectionId: n,
1625
+ parentId: r,
1626
+ responsibleUser: i,
1627
+ responsibleUserFiltering: a,
1628
+ limit: c,
1629
+ cursor: l,
1630
+ labels: u,
1631
+ labelsOperator: p
1632
+ } = e, g = await t.getUser(), h = u && u.length > 0;
1633
+ if (!s && !o && !n && !r && !i && !h)
1634
+ throw new Error(
1635
+ "At least one filter must be provided: searchText, projectId, sectionId, parentId, responsibleUser, or labels"
1636
+ );
1637
+ const k = await Q(t, i), j = k?.userId, C = k?.email;
1638
+ if (o || n || r) {
1639
+ const b = {
1640
+ limit: c,
1641
+ cursor: l ?? null
1642
+ };
1643
+ o && (b.projectId = o === "inbox" ? g.inboxProjectId : o), n && (b.sectionId = n), r && (b.parentId = r);
1644
+ const { results: f, nextCursor: $ } = await t.getTasks(b), A = f.map(O);
1645
+ let D = s ? A.filter(
1646
+ (M) => M.content.toLowerCase().includes(s.toLowerCase()) || M.description?.toLowerCase().includes(s.toLowerCase())
1647
+ ) : A;
1648
+ D = ne({
1649
+ tasks: D,
1650
+ resolvedAssigneeId: j,
1651
+ currentUserId: g.id,
1652
+ responsibleUserFiltering: a
1653
+ }), u && u.length > 0 && (D = p === "and" ? D.filter(
1654
+ (M) => u.every((H) => M.labels.includes(H))
1655
+ ) : D.filter(
1656
+ (M) => u.some((H) => M.labels.includes(H))
1657
+ ));
1658
+ const $e = J({
1659
+ tasks: D,
1660
+ args: e,
1661
+ nextCursor: $,
1662
+ isContainerSearch: !0,
1663
+ assigneeEmail: C
1664
+ });
1665
+ return T({
1666
+ textContent: $e,
1667
+ structuredContent: {
1668
+ tasks: D,
1669
+ nextCursor: $,
1670
+ totalCount: D.length,
1671
+ hasMore: !!$,
1672
+ appliedFilters: e
1673
+ }
1674
+ });
1675
+ }
1676
+ if (j && !s && !h) {
1677
+ const b = await t.getTasksByFilter({
1678
+ query: `assigned to: ${C}`,
1679
+ lang: "en",
1680
+ limit: c,
1681
+ cursor: l ?? null
1682
+ }), f = b.results.map(O), $ = J({
1683
+ tasks: f,
1684
+ args: e,
1685
+ nextCursor: b.nextCursor,
1686
+ isContainerSearch: !1,
1687
+ assigneeEmail: C
1688
+ });
1689
+ return T({
1690
+ textContent: $,
1691
+ structuredContent: {
1692
+ tasks: f,
1693
+ nextCursor: b.nextCursor,
1694
+ totalCount: f.length,
1695
+ hasMore: !!b.nextCursor,
1696
+ appliedFilters: e
1697
+ }
1698
+ });
1699
+ }
1700
+ let x = "";
1701
+ s && (x = `search: ${s}`);
1702
+ const E = oe(u, p);
1703
+ x = V(x, E);
1704
+ const m = await ee({
1705
+ client: t,
1706
+ query: x,
1707
+ cursor: e.cursor,
1708
+ limit: e.limit
1709
+ }), y = ne({
1710
+ tasks: m.tasks,
1711
+ resolvedAssigneeId: j,
1712
+ currentUserId: g.id,
1713
+ responsibleUserFiltering: a
1714
+ }), v = J({
1715
+ tasks: y,
1716
+ args: e,
1717
+ nextCursor: m.nextCursor,
1718
+ isContainerSearch: !1,
1719
+ assigneeEmail: C
1720
+ });
1721
+ return T({
1722
+ textContent: v,
1723
+ structuredContent: {
1724
+ tasks: y,
1725
+ nextCursor: m.nextCursor,
1726
+ totalCount: y.length,
1727
+ hasMore: !!m.nextCursor,
1728
+ appliedFilters: e
1729
+ }
1730
+ });
1731
+ }
1732
+ };
1733
+ function Bt(e) {
1734
+ if (e.projectId) {
1735
+ const t = [
1736
+ e.searchText ? "No tasks in project match search" : "Project has no tasks yet"
1737
+ ];
1738
+ return e.searchText || t.push(`Use ${ie} to create tasks`), t;
1739
+ }
1740
+ if (e.sectionId) {
1741
+ const t = [e.searchText ? "No tasks in section match search" : "Section is empty"];
1742
+ return e.searchText || t.push("Tasks may be in other sections of the project"), t;
1743
+ }
1744
+ if (e.parentId) {
1745
+ const t = [e.searchText ? "No subtasks match search" : "No subtasks created yet"];
1746
+ return e.searchText || t.push(`Use ${ie} with parentId to add subtasks`), t;
1747
+ }
1748
+ return [];
1749
+ }
1750
+ function J({
1751
+ tasks: e,
1752
+ args: t,
1753
+ nextCursor: s,
1754
+ isContainerSearch: o,
1755
+ assigneeEmail: n
1756
+ }) {
1757
+ let r = "Tasks";
1758
+ const i = [], a = [];
1759
+ if (o) {
1760
+ if (t.projectId ? (r = "Tasks in project", i.push(`in project ${t.projectId}`)) : t.sectionId ? (r = "Tasks in section", i.push(`in section ${t.sectionId}`)) : t.parentId ? (r = "Subtasks", i.push(`subtasks of ${t.parentId}`)) : r = "Tasks", t.searchText && (r += ` matching "${t.searchText}"`, i.push(`containing "${t.searchText}"`)), t.responsibleUser) {
1761
+ const c = n || t.responsibleUser;
1762
+ r += ` assigned to ${c}`, i.push(`assigned to ${c}`);
1763
+ }
1764
+ if (t.labels && t.labels.length > 0) {
1765
+ const c = t.labels.map((l) => `@${l}`).join(t.labelsOperator === "and" ? " & " : " | ");
1766
+ i.push(`labels: ${c}`);
1767
+ }
1768
+ e.length === 0 && a.push(...Bt(t));
1769
+ } else {
1770
+ const c = n || t.responsibleUser, l = [];
1771
+ if (t.searchText && l.push(`"${t.searchText}"`), t.responsibleUser && l.push(`assigned to ${c}`), t.labels && t.labels.length > 0) {
1772
+ const u = t.labels.map((p) => `@${p}`).join(t.labelsOperator === "and" ? " & " : " | ");
1773
+ l.push(`with labels: ${u}`);
1774
+ }
1775
+ if (t.searchText ? (r = `Search results for ${l.join(" ")}`, i.push(`matching "${t.searchText}"`)) : t.responsibleUser && (!t.labels || t.labels.length === 0) ? r = `Tasks assigned to ${c}` : t.labels && t.labels.length > 0 && !t.responsibleUser ? r = `Tasks with labels: ${t.labels.map((p) => `@${p}`).join(t.labelsOperator === "and" ? " & " : " | ")}` : r = `Tasks ${l.join(" ")}`, t.responsibleUser && i.push(`assigned to ${c}`), t.labels && t.labels.length > 0) {
1776
+ const u = t.labels.map((p) => `@${p}`).join(t.labelsOperator === "and" ? " & " : " | ");
1777
+ i.push(`labels: ${u}`);
1778
+ }
1779
+ if (e.length === 0) {
1780
+ if (t.responsibleUser) {
1781
+ const u = n || t.responsibleUser;
1782
+ a.push(`No tasks assigned to ${u}`), a.push("Check if the user name is correct"), a.push(`Check completed tasks with ${re}`);
1783
+ }
1784
+ t.searchText && (a.push("Try broader search terms"), a.push("Verify spelling and try partial words"), t.responsibleUser || a.push(`Check completed tasks with ${re}`));
1785
+ }
1786
+ }
1787
+ return N({
1788
+ subject: r,
1789
+ count: e.length,
1790
+ limit: t.limit,
1791
+ nextCursor: s ?? void 0,
1792
+ filterHints: i,
1793
+ previewLines: z(e, Math.min(e.length, t.limit)),
1794
+ zeroReasonHints: a
1795
+ });
1796
+ }
1797
+ const Kt = {
1798
+ startDate: d.string().regex(/^(\d{4}-\d{2}-\d{2}|today)$/).optional().describe("The start date to get the tasks for. Format: YYYY-MM-DD or 'today'."),
1799
+ overdueOption: d.enum(["overdue-only", "include-overdue", "exclude-overdue"]).optional().describe(
1800
+ "How to handle overdue tasks. 'overdue-only' to get only overdue tasks, 'include-overdue' to include overdue tasks along with tasks for the specified date(s), and 'exclude-overdue' to exclude overdue tasks. Default is 'include-overdue'."
1801
+ ),
1802
+ daysCount: d.number().int().min(1).max(30).default(1).describe(
1803
+ "The number of days to get the tasks for, starting from the start date. Default is 1 which means only tasks for the start date."
1804
+ ),
1805
+ limit: d.number().int().min(1).max(S.TASKS_MAX).default(S.TASKS_DEFAULT).describe("The maximum number of tasks to return."),
1806
+ cursor: d.string().optional().describe(
1807
+ "The cursor to get the next page of tasks (cursor is obtained from the previous call to this tool, with the same parameters)."
1808
+ ),
1809
+ responsibleUser: d.string().optional().describe("Find tasks assigned to this user. Can be a user ID, name, or email address."),
1810
+ responsibleUserFiltering: d.enum(me).optional().describe(
1811
+ 'How to filter by responsible user when responsibleUser is not provided. "assigned" = only tasks assigned to others; "unassignedOrMe" = only unassigned tasks or tasks assigned to me; "all" = all tasks regardless of assignment. Default is "unassignedOrMe".'
1812
+ ),
1813
+ ...se
1814
+ }, Yt = {
1815
+ name: I.FIND_TASKS_BY_DATE,
1816
+ description: "Get tasks by date range. Use startDate 'today' to get today's tasks including overdue items, or provide a specific date/date range.",
1817
+ parameters: Kt,
1818
+ async execute(e, t) {
1819
+ if (!e.startDate && e.overdueOption !== "overdue-only")
1820
+ throw new Error(
1821
+ "Either startDate must be provided or overdueOption must be set to overdue-only"
1822
+ );
1823
+ const s = await Q(t, e.responsibleUser), o = s?.userId, n = s?.email;
1824
+ let r = "";
1825
+ if (e.overdueOption === "overdue-only")
1826
+ r = "overdue";
1827
+ else if (e.startDate === "today")
1828
+ r = e.overdueOption === "exclude-overdue" ? "today" : "(today | overdue)";
1829
+ else if (e.startDate) {
1830
+ const p = e.startDate, g = ue(p, e.daysCount), h = Se(g, { representation: "date" });
1831
+ r = `(due after: ${p} | due: ${p}) & due before: ${h}`;
1832
+ }
1833
+ const i = oe(e.labels, e.labelsOperator);
1834
+ i.length > 0 && (r = V(r, `(${i})`));
1835
+ const a = Ve({
1836
+ resolvedAssigneeId: o,
1837
+ assigneeEmail: n,
1838
+ responsibleUserFiltering: e.responsibleUserFiltering
1839
+ });
1840
+ r = V(r, a);
1841
+ const c = await ee({
1842
+ client: t,
1843
+ query: r,
1844
+ cursor: e.cursor,
1845
+ limit: e.limit
1846
+ }), l = c.tasks, u = Vt({
1847
+ tasks: l,
1848
+ args: e,
1849
+ nextCursor: c.nextCursor,
1850
+ assigneeEmail: n
1851
+ });
1852
+ return T({
1853
+ textContent: u,
1854
+ structuredContent: {
1855
+ tasks: l,
1856
+ nextCursor: c.nextCursor,
1857
+ totalCount: l.length,
1858
+ hasMore: !!c.nextCursor,
1859
+ appliedFilters: e
1860
+ }
1861
+ });
1862
+ }
1863
+ };
1864
+ function Vt({
1865
+ tasks: e,
1866
+ args: t,
1867
+ nextCursor: s,
1868
+ assigneeEmail: o
1869
+ }) {
1870
+ const n = [];
1871
+ if (t.overdueOption === "overdue-only")
1872
+ n.push("overdue tasks only");
1873
+ else if (t.startDate === "today") {
1874
+ const a = t.overdueOption === "exclude-overdue" ? "" : " + overdue tasks";
1875
+ n.push(
1876
+ `today${a}${t.daysCount > 1 ? ` + ${t.daysCount - 1} more days` : ""}`
1877
+ );
1878
+ } else if (t.startDate) {
1879
+ const a = t.daysCount > 1 ? ` to ${Xe(ue(t.startDate, t.daysCount))}` : "";
1880
+ n.push(`${t.startDate}${a}`);
1881
+ }
1882
+ if (t.labels && t.labels.length > 0) {
1883
+ const a = t.labels.map((c) => `@${c}`).join(t.labelsOperator === "and" ? " & " : " | ");
1884
+ n.push(`labels: ${a}`);
1885
+ }
1886
+ if (t.responsibleUser) {
1887
+ const a = o || t.responsibleUser;
1888
+ n.push(`assigned to: ${a}`);
1889
+ }
1890
+ let r = "";
1891
+ if (t.overdueOption === "overdue-only" ? r = "Overdue tasks" : t.startDate === "today" ? r = t.overdueOption === "exclude-overdue" ? "Today's tasks" : "Today's tasks + overdue" : t.startDate ? r = `Tasks for ${t.startDate}` : r = "Tasks", t.responsibleUser) {
1892
+ const a = o || t.responsibleUser;
1893
+ r += ` assigned to ${a}`;
1894
+ }
1895
+ const i = [];
1896
+ if (e.length === 0)
1897
+ if (t.overdueOption === "overdue-only")
1898
+ i.push("Great job! No overdue tasks");
1899
+ else if (t.startDate === "today") {
1900
+ const a = t.overdueOption === "exclude-overdue" ? "" : " or overdue";
1901
+ i.push(`Great job! No tasks for today${a}`);
1902
+ } else
1903
+ i.push("Expand date range with larger 'daysCount'"), i.push("Check today's tasks with startDate='today'");
1904
+ return N({
1905
+ subject: r,
1906
+ count: e.length,
1907
+ limit: t.limit,
1908
+ nextCursor: s ?? void 0,
1909
+ filterHints: n,
1910
+ previewLines: z(e, Math.min(e.length, t.limit)),
1911
+ zeroReasonHints: i
1912
+ });
1913
+ }
1914
+ const zt = {
1915
+ projectId: d.string().min(1).optional().describe(
1916
+ "Optional project ID. If provided, shows detailed overview of that project. If omitted, shows overview of all projects."
1917
+ )
1918
+ };
1919
+ function Ht(e) {
1920
+ const t = {};
1921
+ for (const n of e)
1922
+ t[n.id] = {
1923
+ ...n,
1924
+ children: [],
1925
+ childOrder: n.childOrder ?? 0
1926
+ };
1927
+ const s = [];
1928
+ for (const n of e) {
1929
+ const r = t[n.id];
1930
+ if (r)
1931
+ if (B(n) && n.parentId) {
1932
+ const i = t[n.parentId];
1933
+ i ? i.children.push(r) : s.push(r);
1934
+ } else
1935
+ s.push(r);
1936
+ }
1937
+ function o(n) {
1938
+ n.sort((r, i) => r.childOrder - i.childOrder);
1939
+ for (const r of n)
1940
+ o(r.children);
1941
+ }
1942
+ return o(s), s;
1943
+ }
1944
+ async function Wt(e, t) {
1945
+ const s = {};
1946
+ return await Promise.all(
1947
+ t.map(async (o) => {
1948
+ const { results: n } = await e.getSections({ projectId: o });
1949
+ s[o] = n;
1950
+ })
1951
+ ), s;
1952
+ }
1953
+ function ke(e, t, s = "") {
1954
+ const o = [];
1955
+ o.push(`${s}- Project: ${e.name} (id=${e.id})`);
1956
+ const n = t[e.id] || [];
1957
+ for (const r of n)
1958
+ o.push(`${s} - Section: ${r.name} (id=${r.id})`);
1959
+ for (const r of e.children)
1960
+ o.push(...ke(r, t, `${s} `));
1961
+ return o;
1962
+ }
1963
+ function ae(e) {
1964
+ const t = {};
1965
+ for (const o of e)
1966
+ t[o.id] = { ...o, children: [] };
1967
+ const s = [];
1968
+ for (const o of e) {
1969
+ const n = t[o.id];
1970
+ if (!n) continue;
1971
+ if (!o.parentId) {
1972
+ s.push(n);
1973
+ continue;
1974
+ }
1975
+ const r = t[o.parentId];
1976
+ r ? r.children.push(n) : s.push(n);
1977
+ }
1978
+ return s;
1979
+ }
1980
+ function X(e, t = "") {
1981
+ const s = [];
1982
+ for (const o of e) {
1983
+ const n = `id=${o.id}`, r = o.dueDate ? `; due=${o.dueDate}` : "", i = `; content=${o.content}`;
1984
+ s.push(`${t}- ${n}${r}${i}`), o.children.length > 0 && s.push(...X(o.children, `${t} `));
1985
+ }
1986
+ return s;
1987
+ }
1988
+ function we(e, t) {
1989
+ return {
1990
+ id: e.id,
1991
+ name: e.name,
1992
+ parentId: B(e) ? e.parentId ?? null : null,
1993
+ sections: t[e.id] || [],
1994
+ children: e.children.map((s) => we(s, t))
1995
+ };
1996
+ }
1997
+ async function Gt(e, t) {
1998
+ let s = [], o;
1999
+ do {
2000
+ const { results: n, nextCursor: r } = await e.getTasks({
2001
+ projectId: t,
2002
+ limit: S.TASKS_BATCH_SIZE,
2003
+ cursor: o ?? void 0
2004
+ });
2005
+ s = s.concat(n.map(O)), o = r ?? void 0;
2006
+ } while (o);
2007
+ return s;
2008
+ }
2009
+ async function Jt(e, t) {
2010
+ const { results: s } = await e.getSections({ projectId: t });
2011
+ return s;
2012
+ }
2013
+ async function qt(e) {
2014
+ const { results: t } = await e.getProjects({}), s = t.find((p) => B(p) && p.inboxProject === !0), o = t.filter((p) => !B(p) || p.inboxProject !== !0), n = Ht(o), r = t.map((p) => p.id), i = await Wt(e, r), a = ["# Personal Projects", ""];
2015
+ if (s) {
2016
+ a.push(`- Inbox Project: ${s.name} (id=${s.id})`);
2017
+ for (const p of i[s.id] || [])
2018
+ a.push(` - Section: ${p.name} (id=${p.id})`);
2019
+ }
2020
+ if (n.length)
2021
+ for (const p of n)
2022
+ a.push(...ke(p, i));
2023
+ else
2024
+ a.push("_No projects found._");
2025
+ a.push("");
2026
+ const c = n.some((p) => p.children.length > 0);
2027
+ c && a.push(
2028
+ "_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._",
2029
+ ""
2030
+ );
2031
+ const l = a.join(`
2032
+ `), u = {
2033
+ type: "account_overview",
2034
+ inbox: s ? {
2035
+ id: s.id,
2036
+ name: s.name,
2037
+ sections: i[s.id] || []
2038
+ } : null,
2039
+ projects: n.map(
2040
+ (p) => we(p, i)
2041
+ ),
2042
+ totalProjects: t.length,
2043
+ totalSections: r.reduce(
2044
+ (p, g) => p + (i[g]?.length || 0),
2045
+ 0
2046
+ ),
2047
+ hasNestedProjects: c
2048
+ };
2049
+ return { textContent: l, structuredContent: u };
2050
+ }
2051
+ async function Xt(e, t) {
2052
+ const s = await e.getProject(t), o = await Jt(e, t), n = await Gt(e, t), r = {};
2053
+ for (const u of o)
2054
+ r[u.id] = [];
2055
+ const i = [];
2056
+ for (const u of n)
2057
+ (u.sectionId ? r[u.sectionId] ?? i : i).push(u);
2058
+ const a = [`# ${s.name}`];
2059
+ if (i.length > 0) {
2060
+ a.push("");
2061
+ const u = ae(i);
2062
+ a.push(...X(u));
2063
+ }
2064
+ for (const u of o) {
2065
+ a.push(""), a.push(`## ${u.name}`);
2066
+ const p = r[u.id];
2067
+ if (!p?.length)
2068
+ continue;
2069
+ const g = ae(p);
2070
+ a.push(...X(g));
2071
+ }
2072
+ const c = a.join(`
2073
+ `), l = {
2074
+ type: "project_overview",
2075
+ project: {
2076
+ id: s.id,
2077
+ name: s.name
2078
+ },
2079
+ sections: o,
2080
+ tasks: n.map((u) => ({
2081
+ ...u,
2082
+ children: []
2083
+ // Tasks already include hierarchical info via parentId
2084
+ })),
2085
+ stats: {
2086
+ totalTasks: n.length,
2087
+ totalSections: o.length,
2088
+ tasksWithoutSection: i.length
2089
+ }
2090
+ };
2091
+ return { textContent: c, structuredContent: l };
2092
+ }
2093
+ const Zt = {
2094
+ name: I.GET_OVERVIEW,
2095
+ 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.",
2096
+ parameters: zt,
2097
+ async execute(e, t) {
2098
+ const s = e.projectId ? await Xt(t, e.projectId) : await qt(t);
2099
+ return T({
2100
+ textContent: s.textContent,
2101
+ structuredContent: s.structuredContent
2102
+ });
2103
+ }
2104
+ }, { FIND_TASKS: Qt, FIND_PROJECT_COLLABORATORS: ce, UPDATE_TASKS: es } = I, ts = 50, ss = {
2105
+ operation: d.enum(["assign", "unassign", "reassign"]).describe("The assignment operation to perform."),
2106
+ taskIds: d.array(d.string()).min(1).max(ts).describe("The IDs of the tasks to operate on (max 50)."),
2107
+ responsibleUser: d.string().optional().describe(
2108
+ "The user to assign tasks to. Can be user ID, name, or email. Required for assign and reassign operations."
2109
+ ),
2110
+ fromAssigneeUser: d.string().optional().describe(
2111
+ "For reassign operations: the current assignee to reassign from. Can be user ID, name, or email. Optional - if not provided, reassigns from any current assignee."
2112
+ ),
2113
+ dryRun: d.boolean().optional().default(!1).describe("If true, validates operations without executing them.")
2114
+ }, os = {
2115
+ name: I.MANAGE_ASSIGNMENTS,
2116
+ description: "Bulk assignment operations for multiple tasks. Supports assign, unassign, and reassign operations with atomic rollback on failures.",
2117
+ parameters: ss,
2118
+ async execute(e, t) {
2119
+ const { operation: s, taskIds: o, responsibleUser: n, fromAssigneeUser: r, dryRun: i } = e;
2120
+ if ((s === "assign" || s === "reassign") && !n)
2121
+ throw new Error(`${s} operation requires responsibleUser parameter`);
2122
+ const a = await Promise.allSettled(
2123
+ o.map(async (m) => {
2124
+ try {
2125
+ return await t.getTask(m);
2126
+ } catch {
2127
+ throw new Error(`Task ${m} not found or not accessible`);
2128
+ }
2129
+ })
2130
+ ), c = [], l = [];
2131
+ for (let m = 0; m < a.length; m++) {
2132
+ const y = a[m];
2133
+ y && y.status === "fulfilled" ? c.push(y.value) : y && y.status === "rejected" ? l.push({
2134
+ taskId: o[m] || "invalid-task-id",
2135
+ success: !1,
2136
+ error: y.reason?.message || "Task not accessible"
2137
+ }) : l.push({
2138
+ taskId: o[m] || "invalid-task-id",
2139
+ success: !1,
2140
+ error: "Task not accessible"
2141
+ });
2142
+ }
2143
+ if (c.length === 0) {
2144
+ const m = K({
2145
+ operation: s,
2146
+ results: l,
2147
+ dryRun: i
2148
+ });
2149
+ return T({
2150
+ textContent: m,
2151
+ structuredContent: {
2152
+ operation: s,
2153
+ results: l,
2154
+ totalRequested: o.length,
2155
+ successful: 0,
2156
+ failed: l.length,
2157
+ dryRun: i
2158
+ }
2159
+ });
2160
+ }
2161
+ let u;
2162
+ s === "reassign" && r && (u = (await _.resolveUser(t, r))?.userId || r);
2163
+ const p = [];
2164
+ for (const m of c)
2165
+ s === "reassign" && u && m.responsibleUid !== u || p.push({
2166
+ taskId: m.id,
2167
+ projectId: m.projectId,
2168
+ responsibleUid: n || ""
2169
+ // Will be validated appropriately
2170
+ });
2171
+ if (s === "unassign") {
2172
+ if (i) {
2173
+ const f = c.map((A) => ({
2174
+ taskId: A.id,
2175
+ success: !0,
2176
+ originalAssigneeId: A.responsibleUid,
2177
+ newAssigneeId: null
2178
+ })), $ = K({
2179
+ operation: s,
2180
+ results: f,
2181
+ dryRun: !0
2182
+ });
2183
+ return T({
2184
+ textContent: $,
2185
+ structuredContent: {
2186
+ operation: s,
2187
+ results: f,
2188
+ totalRequested: o.length,
2189
+ successful: f.length,
2190
+ failed: l.length,
2191
+ dryRun: !0
2192
+ }
2193
+ });
2194
+ }
2195
+ const m = c.map(async (f) => {
2196
+ try {
2197
+ return await t.updateTask(f.id, { assigneeId: null }), {
2198
+ taskId: f.id,
2199
+ success: !0,
2200
+ originalAssigneeId: f.responsibleUid,
2201
+ newAssigneeId: null
2202
+ };
2203
+ } catch ($) {
2204
+ return {
2205
+ taskId: f.id,
2206
+ success: !1,
2207
+ error: $ instanceof Error ? $.message : "Update failed",
2208
+ originalAssigneeId: f.responsibleUid
2209
+ };
2210
+ }
2211
+ }), y = await Promise.all(m), v = [...y, ...l], b = K({
2212
+ operation: s,
2213
+ results: v,
2214
+ dryRun: !1
2215
+ });
2216
+ return T({
2217
+ textContent: b,
2218
+ structuredContent: {
2219
+ operation: s,
2220
+ results: v,
2221
+ totalRequested: o.length,
2222
+ successful: y.filter((f) => f.success).length,
2223
+ failed: v.filter((f) => !f.success).length,
2224
+ dryRun: !1
2225
+ }
2226
+ });
2227
+ }
2228
+ const g = await te.validateBulkAssignment(
2229
+ t,
2230
+ p
2231
+ ), h = [], k = [];
2232
+ for (let m = 0; m < p.length; m++) {
2233
+ const y = p[m], v = g[m];
2234
+ y && v && v.isValid ? h.push({ assignment: y, validation: v }) : y?.taskId && k.push({
2235
+ taskId: y.taskId,
2236
+ success: !1,
2237
+ error: v?.error?.message || "Validation failed"
2238
+ });
2239
+ }
2240
+ async function j(m, y) {
2241
+ const v = m.filter(
2242
+ (f) => f.assignment != null && f.validation != null
2243
+ );
2244
+ if (!y)
2245
+ return v.map(({ assignment: f, validation: $ }) => {
2246
+ const A = c.find((D) => D.id === f.taskId);
2247
+ if (!f.taskId || !$.resolvedUser?.userId)
2248
+ throw new Error(
2249
+ "Invalid assignment or validation data - this should not happen"
2250
+ );
2251
+ return {
2252
+ taskId: f.taskId,
2253
+ success: !0,
2254
+ originalAssigneeId: A?.responsibleUid || null,
2255
+ newAssigneeId: $.resolvedUser.userId
2256
+ };
2257
+ });
2258
+ const b = v.map(
2259
+ async ({ assignment: f, validation: $ }) => {
2260
+ const A = c.find((D) => D.id === f.taskId);
2261
+ if (!f.taskId || !$.resolvedUser?.userId)
2262
+ return {
2263
+ taskId: f.taskId || "unknown-task",
2264
+ success: !1,
2265
+ error: "Invalid assignment data - missing task ID or resolved user",
2266
+ originalAssigneeId: A?.responsibleUid || null
2267
+ };
2268
+ try {
2269
+ return await t.updateTask(f.taskId, {
2270
+ assigneeId: $.resolvedUser.userId
2271
+ }), {
2272
+ taskId: f.taskId,
2273
+ success: !0,
2274
+ originalAssigneeId: A?.responsibleUid || null,
2275
+ newAssigneeId: $.resolvedUser.userId
2276
+ };
2277
+ } catch (D) {
2278
+ return {
2279
+ taskId: f.taskId,
2280
+ success: !1,
2281
+ error: D instanceof Error ? D.message : "Update failed",
2282
+ originalAssigneeId: A?.responsibleUid || null
2283
+ };
2284
+ }
2285
+ }
2286
+ );
2287
+ return Promise.all(b);
2288
+ }
2289
+ const C = await j(h, !i), x = [...C, ...k, ...l], E = K({
2290
+ operation: s,
2291
+ results: x,
2292
+ dryRun: i
2293
+ });
2294
+ return T({
2295
+ textContent: E,
2296
+ structuredContent: {
2297
+ operation: s,
2298
+ results: x,
2299
+ totalRequested: o.length,
2300
+ successful: C.filter((m) => m.success).length,
2301
+ failed: x.filter((m) => !m.success).length,
2302
+ dryRun: i
2303
+ }
2304
+ });
2305
+ }
2306
+ };
2307
+ function K({
2308
+ operation: e,
2309
+ results: t,
2310
+ dryRun: s
2311
+ }) {
2312
+ const o = t.filter((c) => c.success), n = t.filter((c) => !c.success), r = s ? "would be" : "were", i = {
2313
+ assign: "assigned",
2314
+ unassign: "unassigned",
2315
+ reassign: "reassigned"
2316
+ }[e];
2317
+ let a = `**${s ? "Dry Run: " : ""}Bulk ${e} operation**
2318
+
2319
+ `;
2320
+ if (o.length > 0) {
2321
+ a += `**${o.length} task${o.length === 1 ? "" : "s"} ${r} successfully ${i}**
2322
+ `;
2323
+ const c = o.slice(0, 5);
2324
+ for (const l of c) {
2325
+ let u = "";
2326
+ e === "unassign" ? u = " (unassigned from previous assignee)" : l.newAssigneeId && (u = ` → ${l.newAssigneeId}`), a += ` • Task ${l.taskId}${u}
2327
+ `;
2328
+ }
2329
+ o.length > 5 && (a += ` • ... and ${o.length - 5} more
2330
+ `), a += `
2331
+ `;
2332
+ }
2333
+ if (n.length > 0) {
2334
+ a += `**${n.length} task${n.length === 1 ? "" : "s"} failed**
2335
+ `;
2336
+ const c = n.slice(0, 5);
2337
+ for (const l of c)
2338
+ a += ` • Task ${l.taskId}: ${l.error}
2339
+ `;
2340
+ n.length > 5 && (a += ` • ... and ${n.length - 5} more failures
2341
+ `), a += `
2342
+ `;
2343
+ }
2344
+ return !s && o.length > 0 ? (a += `**Next steps:**
2345
+ `, a += `• Use ${Qt} with responsibleUser to see ${e === "unassign" ? "unassigned" : "newly assigned"} tasks
2346
+ `, a += `• Use ${es} for individual assignment changes
2347
+ `, n.length > 0 && (a += `• Check failed tasks and use ${ce} to verify collaborator access
2348
+ `)) : s ? (a += `**To execute:**
2349
+ `, a += `• Remove dryRun parameter and run again to execute changes
2350
+ `, o.length > 0 && (a += `• ${o.length} task${o.length === 1 ? "" : "s"} ready for ${e} operation
2351
+ `), n.length > 0 && (a += `• Fix ${n.length} validation error${n.length === 1 ? "" : "s"} before executing
2352
+ `)) : o.length === 0 && (a += `**Suggestions:**
2353
+ `, a += `• Use ${ce} to find valid assignees
2354
+ `, a += `• Check task IDs and assignee permissions
2355
+ `, a += `• Use dryRun=true to validate before executing
2356
+ `), a;
2357
+ }
2358
+ const ns = {
2359
+ query: d.string().min(1).describe("The search query string to find tasks and projects.")
2360
+ }, rs = {
2361
+ name: I.SEARCH,
2362
+ description: "Search across tasks and projects in Todoist. Returns a list of relevant results with IDs, titles, and URLs.",
2363
+ parameters: ns,
2364
+ async execute(e, t) {
2365
+ try {
2366
+ const { query: s } = e, [o, n] = await Promise.all([
2367
+ ee({
2368
+ client: t,
2369
+ query: `search: ${s}`,
2370
+ limit: S.TASKS_MAX,
2371
+ cursor: void 0
2372
+ }),
2373
+ t.getProjects({ limit: S.PROJECTS_MAX })
2374
+ ]), r = s.toLowerCase(), i = n.results.filter(
2375
+ (l) => l.name.toLowerCase().includes(r)
2376
+ ), a = [];
2377
+ for (const l of o.tasks)
2378
+ a.push({
2379
+ id: `task:${l.id}`,
2380
+ title: l.content,
2381
+ url: le(l.id)
2382
+ });
2383
+ for (const l of i)
2384
+ a.push({
2385
+ id: `project:${l.id}`,
2386
+ title: l.name,
2387
+ url: de(l.id)
2388
+ });
2389
+ return { content: [{ type: "text", text: JSON.stringify({ results: a }) }] };
2390
+ } catch (s) {
2391
+ const o = s instanceof Error ? s.message : "An unknown error occurred";
2392
+ return Z(o);
2393
+ }
2394
+ }
2395
+ }, is = d.object({
2396
+ id: d.string().min(1).describe("The ID of the comment to update."),
2397
+ content: d.string().min(1).describe("The new content for the comment.")
2398
+ }), as = {
2399
+ comments: d.array(is).min(1).describe("The comments to update.")
2400
+ }, cs = {
2401
+ name: I.UPDATE_COMMENTS,
2402
+ description: "Update multiple existing comments with new content.",
2403
+ parameters: as,
2404
+ async execute(e, t) {
2405
+ const { comments: s } = e, o = s.map(async (i) => await t.updateComment(i.id, { content: i.content })), n = await Promise.all(o), r = ls({
2406
+ comments: n
2407
+ });
2408
+ return T({
2409
+ textContent: r,
2410
+ structuredContent: {
2411
+ comments: n,
2412
+ totalCount: n.length,
2413
+ updatedCommentIds: n.map((i) => i.id),
2414
+ appliedOperations: {
2415
+ updateCount: n.length
2416
+ }
2417
+ }
2418
+ });
2419
+ }
2420
+ };
2421
+ function ls({ comments: e }) {
2422
+ const t = e.filter((r) => r.taskId).length, s = e.filter((r) => r.projectId).length, o = [];
2423
+ if (t > 0) {
2424
+ const r = t > 1 ? "comments" : "comment";
2425
+ o.push(`${t} task ${r}`);
2426
+ }
2427
+ if (s > 0) {
2428
+ const r = s > 1 ? "comments" : "comment";
2429
+ o.push(`${s} project ${r}`);
2430
+ }
2431
+ return o.length > 0 ? `Updated ${o.join(" and ")}` : "No comments updated";
2432
+ }
2433
+ const ds = d.object({
2434
+ id: d.string().min(1).describe("The ID of the project to update."),
2435
+ name: d.string().min(1).optional().describe("The new name of the project."),
2436
+ isFavorite: d.boolean().optional().describe("Whether the project is a favorite."),
2437
+ viewStyle: d.enum(["list", "board", "calendar"]).optional().describe("The project view style.")
2438
+ }), us = {
2439
+ projects: d.array(ds).min(1).describe("The projects to update.")
2440
+ }, ps = {
2441
+ name: I.UPDATE_PROJECTS,
2442
+ description: "Update multiple existing projects with new values.",
2443
+ parameters: us,
2444
+ async execute(e, t) {
2445
+ const { projects: s } = e, o = s.map(async (i) => {
2446
+ if (!hs(i))
2447
+ return;
2448
+ const { id: a, ...c } = i;
2449
+ return await t.updateProject(a, c);
2450
+ }), n = (await Promise.all(o)).filter(
2451
+ (i) => i !== void 0
2452
+ ), r = ms({
2453
+ projects: n,
2454
+ args: e
2455
+ });
2456
+ return T({
2457
+ textContent: r,
2458
+ structuredContent: {
2459
+ projects: n,
2460
+ totalCount: n.length,
2461
+ updatedProjectIds: n.map((i) => i.id),
2462
+ appliedOperations: {
2463
+ updateCount: n.length,
2464
+ skippedCount: s.length - n.length
2465
+ }
2466
+ }
2467
+ });
2468
+ }
2469
+ };
2470
+ function ms({
2471
+ projects: e,
2472
+ args: t
2473
+ }) {
2474
+ const s = t.projects.length, o = e.length, n = s - o, r = e.length, i = e.map((c) => `• ${c.name} (id=${c.id})`).join(`
2475
+ `);
2476
+ let a = `Updated ${r} project${r === 1 ? "" : "s"}`;
2477
+ return n > 0 && (a += ` (${n} skipped - no changes)`), r > 0 && (a += `:
2478
+ ${i}`), a;
2479
+ }
2480
+ function hs({ id: e, ...t }) {
2481
+ return Object.keys(t).length > 0;
2482
+ }
2483
+ const fs = d.object({
2484
+ id: d.string().min(1).describe("The ID of the section to update."),
2485
+ name: d.string().min(1).describe("The new name of the section.")
2486
+ }), gs = {
2487
+ sections: d.array(fs).min(1).describe("The sections to update.")
2488
+ }, bs = {
2489
+ name: I.UPDATE_SECTIONS,
2490
+ description: "Update multiple existing sections with new values.",
2491
+ parameters: gs,
2492
+ async execute({ sections: e }, t) {
2493
+ const s = await Promise.all(
2494
+ e.map((n) => t.updateSection(n.id, { name: n.name }))
2495
+ ), o = Ts({
2496
+ sections: s
2497
+ });
2498
+ return T({
2499
+ textContent: o,
2500
+ structuredContent: {
2501
+ sections: s,
2502
+ totalCount: s.length,
2503
+ updatedSectionIds: s.map((n) => n.id)
2504
+ }
2505
+ });
2506
+ }
2507
+ };
2508
+ function Ts({ sections: e }) {
2509
+ const t = e.length, s = e.map((n) => `• ${n.name} (id=${n.id}, projectId=${n.projectId})`).join(`
2510
+ `);
2511
+ return `Updated ${t} section${t === 1 ? "" : "s"}:
2512
+ ${s}`;
2513
+ }
2514
+ const Is = d.object({
2515
+ id: d.string().min(1).describe("The ID of the task to update."),
2516
+ content: d.string().optional().describe(
2517
+ 'The new task name/title. Should be concise and actionable (e.g., "Review PR #123", "Call dentist"). For longer content, use the description field instead. Supports Markdown.'
2518
+ ),
2519
+ description: d.string().optional().describe(
2520
+ "New additional details, notes, or context for the task. Use this for longer content rather than putting it in the task name. Supports Markdown."
2521
+ ),
2522
+ projectId: d.string().optional().describe(
2523
+ 'The new project ID for the task. Project ID should be an ID string, or the text "inbox", for inbox tasks.'
2524
+ ),
2525
+ sectionId: d.string().optional().describe("The new section ID for the task."),
2526
+ parentId: d.string().optional().describe("The new parent task ID (for subtasks)."),
2527
+ order: d.number().optional().describe("The new order of the task within its parent/section."),
2528
+ priority: fe.optional().describe(
2529
+ "The new priority of the task: p1 (highest), p2 (high), p3 (medium), p4 (lowest/default)."
2530
+ ),
2531
+ dueString: d.string().optional().describe("The new due date for the task, in natural language (e.g., 'tomorrow at 5pm')."),
2532
+ deadlineDate: d.string().optional().describe(
2533
+ 'The new deadline date for the task in ISO 8601 format (YYYY-MM-DD, e.g., "2025-12-31"). Deadlines are immovable constraints shown with a different indicator than due dates. Use "remove" to clear the deadline.'
2534
+ ),
2535
+ duration: d.string().optional().describe(
2536
+ 'The duration of the task. Use format: "2h" (hours), "90m" (minutes), "2h30m" (combined), or "1.5h" (decimal hours). Max 24h.'
2537
+ ),
2538
+ responsibleUser: d.string().optional().describe(
2539
+ 'Change task assignment. Use "unassign" to remove assignment. Can be user ID, name, or email. User must be a project collaborator.'
2540
+ ),
2541
+ labels: d.array(d.string()).optional().describe("The new labels for the task. Replaces all existing labels.")
2542
+ }), ys = {
2543
+ tasks: d.array(Is).min(1).describe("The tasks to update.")
2544
+ }, ks = {
2545
+ name: I.UPDATE_TASKS,
2546
+ description: "Update existing tasks including content, dates, priorities, and assignments.",
2547
+ parameters: ys,
2548
+ async execute(e, t) {
2549
+ const { tasks: s } = e, o = s.map(async (a) => {
2550
+ if (!js(a))
2551
+ return;
2552
+ const {
2553
+ id: c,
2554
+ projectId: l,
2555
+ sectionId: u,
2556
+ parentId: p,
2557
+ duration: g,
2558
+ responsibleUser: h,
2559
+ priority: k,
2560
+ labels: j,
2561
+ deadlineDate: C,
2562
+ ...x
2563
+ } = a;
2564
+ let E = l;
2565
+ l === "inbox" && (E = (await t.getUser()).inboxProjectId);
2566
+ let m = {
2567
+ ...x,
2568
+ ...j !== void 0 && { labels: j }
2569
+ };
2570
+ if (k && (m.priority = ge(k)), C !== void 0 && (C === null || C === "remove" ? m = { ...m, deadlineDate: null } : m = { ...m, deadlineDate: C }), g)
2571
+ try {
2572
+ const { minutes: b } = pe(g);
2573
+ m = {
2574
+ ...m,
2575
+ duration: b,
2576
+ durationUnit: "minute"
2577
+ };
2578
+ } catch (b) {
2579
+ throw b instanceof P ? new Error(`Task ${c}: ${b.message}`) : b;
2580
+ }
2581
+ if (h !== void 0)
2582
+ if (h === null || h === "unassign")
2583
+ m = { ...m, assigneeId: null };
2584
+ else {
2585
+ const b = await te.validateTaskUpdateAssignment(
2586
+ t,
2587
+ c,
2588
+ h
2589
+ );
2590
+ if (!b.isValid) {
2591
+ const f = b.error?.message || "Assignment validation failed", $ = b.error?.suggestions?.join(". ") || "";
2592
+ throw new Error(
2593
+ `Task ${c}: ${f}${$ ? `. ${$}` : ""}`
2594
+ );
2595
+ }
2596
+ m = { ...m, assigneeId: b.resolvedUser?.userId };
2597
+ }
2598
+ if (!E && !u && !p)
2599
+ return await t.updateTask(c, m);
2600
+ const y = ze(c, E, u, p), v = await t.moveTask(c, y);
2601
+ return Object.keys(m).length > 0 ? await t.updateTask(c, m) : v;
2602
+ }), n = (await Promise.all(o)).filter(
2603
+ (a) => a !== void 0
2604
+ ), r = n.map(O), i = ws({
2605
+ tasks: r,
2606
+ args: e
2607
+ });
2608
+ return T({
2609
+ textContent: i,
2610
+ structuredContent: {
2611
+ tasks: r,
2612
+ totalCount: r.length,
2613
+ updatedTaskIds: n.map((a) => a.id),
2614
+ appliedOperations: {
2615
+ updateCount: r.length,
2616
+ skippedCount: s.length - r.length
2617
+ }
2618
+ }
2619
+ });
2620
+ }
2621
+ };
2622
+ function ws({
2623
+ tasks: e,
2624
+ args: t
2625
+ }) {
2626
+ const s = t.tasks.length, o = e.length, n = s - o;
2627
+ let r = "";
2628
+ return n > 0 && (r = ` (${n} skipped - no changes)`), be("Updated", e, {
2629
+ context: r,
2630
+ showDetails: e.length <= 5
2631
+ });
2632
+ }
2633
+ function js({ id: e, ...t }) {
2634
+ return Object.keys(t).length > 0;
2635
+ }
2636
+ const $s = {};
2637
+ function Cs(e) {
2638
+ return e.businessAccountId ? "Todoist Business" : e.isPremium ? "Todoist Pro" : "Todoist Free";
2639
+ }
2640
+ function vs(e, t) {
2641
+ const o = ((e.getDay() || 7) - t + 7) % 7, n = new Date(e);
2642
+ return n.setDate(e.getDate() - o), n;
2643
+ }
2644
+ function Ss(e) {
2645
+ const t = new Date(e);
2646
+ return t.setDate(e.getDate() + 6), t;
2647
+ }
2648
+ function Ds(e) {
2649
+ const t = new Date(e.getFullYear(), 0, 1), s = (e.getTime() - t.getTime()) / 864e5;
2650
+ return Math.ceil((s + t.getDay() + 1) / 7);
2651
+ }
2652
+ function xs(e) {
2653
+ return ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"][e === 7 ? 0 : e] ?? "Unknown";
2654
+ }
2655
+ function Y(e) {
2656
+ return e.toISOString().split("T")[0] ?? "";
2657
+ }
2658
+ function As(e) {
2659
+ try {
2660
+ return new Intl.DateTimeFormat("en-US", { timeZone: e }), !0;
2661
+ } catch {
2662
+ return !1;
2663
+ }
2664
+ }
2665
+ function je(e) {
2666
+ return As(e) ? e : "UTC";
2667
+ }
2668
+ function Us(e, t) {
2669
+ const s = je(t);
2670
+ return e.toLocaleString("en-US", {
2671
+ timeZone: s,
2672
+ year: "numeric",
2673
+ month: "2-digit",
2674
+ day: "2-digit",
2675
+ hour: "2-digit",
2676
+ minute: "2-digit",
2677
+ second: "2-digit",
2678
+ hour12: !1
2679
+ });
2680
+ }
2681
+ async function Ps(e) {
2682
+ const t = await e.getUser(), s = t.tzInfo?.timezone ?? "UTC", o = je(s), n = /* @__PURE__ */ new Date(), r = Us(n, o), i = t.startDay ?? 1, a = xs(i), c = Cs(t), l = new Date(n.toLocaleString("en-US", { timeZone: o })), u = vs(l, i), p = Ss(u), g = Ds(l), k = [
2683
+ "# User Information",
2684
+ "",
2685
+ `**User ID:** ${t.id}`,
2686
+ `**Full Name:** ${t.fullName}`,
2687
+ `**Email:** ${t.email}`,
2688
+ `**Timezone:** ${o}`,
2689
+ `**Current Local Time:** ${r}`,
2690
+ "",
2691
+ "## Week Settings",
2692
+ `**Week Start Day:** ${a} (${i})`,
2693
+ `**Current Week:** Week ${g}`,
2694
+ `**Week Start Date:** ${Y(u)}`,
2695
+ `**Week End Date:** ${Y(p)}`,
2696
+ "",
2697
+ "## Daily Progress",
2698
+ `**Completed Today:** ${t.completedToday}`,
2699
+ `**Daily Goal:** ${t.dailyGoal}`,
2700
+ `**Weekly Goal:** ${t.weeklyGoal}`,
2701
+ "",
2702
+ "## Account Info",
2703
+ `**Plan:** ${c}`
2704
+ ].join(`
2705
+ `), j = {
2706
+ type: "user_info",
2707
+ userId: t.id,
2708
+ fullName: t.fullName,
2709
+ timezone: o,
2710
+ currentLocalTime: r,
2711
+ startDay: i,
2712
+ startDayName: a,
2713
+ weekStartDate: Y(u),
2714
+ weekEndDate: Y(p),
2715
+ currentWeekNumber: g,
2716
+ completedToday: t.completedToday,
2717
+ dailyGoal: t.dailyGoal,
2718
+ weeklyGoal: t.weeklyGoal,
2719
+ email: t.email,
2720
+ plan: c
2721
+ };
2722
+ return { textContent: k, structuredContent: j };
2723
+ }
2724
+ const Es = {
2725
+ name: I.USER_INFO,
2726
+ description: "Get comprehensive user information including user ID, full name, email, timezone with current local time, week start day preferences, current week dates, daily/weekly goal progress, and user plan (Free/Pro/Business).",
2727
+ parameters: $s,
2728
+ async execute(e, t) {
2729
+ const s = await Ps(t);
2730
+ return T({
2731
+ textContent: s.textContent,
2732
+ structuredContent: s.structuredContent
2733
+ });
2734
+ }
2735
+ }, Os = `
2736
+ ## Todoist Task and Project Management Tools
2737
+
2738
+ You have access to comprehensive Todoist management tools for personal productivity and team collaboration. Use these tools to help users manage tasks, projects, sections, comments, and assignments effectively.
2739
+
2740
+ ### Core Capabilities:
2741
+ - Create, update, complete, and search tasks with rich metadata (priorities, due dates, durations, assignments)
2742
+ - Manage projects and sections with flexible organization
2743
+ - Handle comments and collaboration features
2744
+ - Bulk assignment operations for team workflows
2745
+ - Get overviews and insights about workload and progress
2746
+
2747
+ ### Tool Usage Guidelines:
2748
+
2749
+ **Task Management:**
2750
+ - **add-tasks**: Create tasks with content, description, priority (p1=highest, p2=high, p3=medium, p4=lowest/default), dueString (natural language like "tomorrow", "next Friday", "2024-12-25"), deadlineDate (ISO 8601 format like "2025-12-31" for immovable constraints), duration (formats like "2h", "90m", "2h30m"), and assignments to project collaborators
2751
+ - **update-tasks**: Modify existing tasks - get task IDs from search results first, only include fields that need changes. Supports deadlineDate (ISO 8601 format like "2025-12-31") updates and removals (use "remove" to clear)
2752
+ - **complete-tasks**: Mark tasks as done using task IDs
2753
+ - **find-tasks**: Search by text, project/section/parent container, responsible user, or labels. Requires at least one search parameter
2754
+ - **find-tasks-by-date**: Get tasks by date range (startDate: YYYY-MM-DD or 'today' which includes overdue tasks) or specific day counts
2755
+ - **find-completed-tasks**: View completed tasks by completion date or original due date (returns all collaborators unless filtered)
2756
+
2757
+ **Project & Organization:**
2758
+ - **add-projects/update-projects/find-projects**: Manage project lifecycle with names, favorites, and view styles (list/board/calendar)
2759
+ - **add-sections/update-sections/find-sections**: Organize tasks within projects using sections
2760
+ - **get-overview**: Get comprehensive Markdown overview of entire account or specific project with task hierarchies
2761
+
2762
+ **Collaboration & Comments:**
2763
+ - **add-comments/update-comments/find-comments**: Manage task and project discussions
2764
+ - **find-project-collaborators**: Find team members by name or email for assignments
2765
+ - **manage-assignments**: Bulk assign/unassign/reassign up to 50 tasks with atomic operations and dry-run validation
2766
+
2767
+ **Activity & Audit:**
2768
+ - **find-activity**: Retrieve recent activity logs to monitor and audit changes. Shows events from all users by default; use initiatorId to filter by specific user. Filter by object type (task/project/comment), event type (added/updated/deleted/completed/uncompleted/archived/unarchived/shared/left), and specific objects (objectId, projectId, taskId). Useful for tracking who did what and when. Note: Date-based filtering is not supported.
2769
+
2770
+ **General Operations:**
2771
+ - **delete-object**: Remove projects, sections, tasks, or comments by type and ID
2772
+ - **user-info**: Get user details including timezone, goals, and plan information
2773
+
2774
+ ### Best Practices:
2775
+
2776
+ 1. **Task Creation**: Write clear, actionable task titles. Use natural language for due dates ("tomorrow", "next Monday"). Set appropriate priorities and include detailed descriptions when needed.
2777
+
2778
+ 2. **Search Strategy**: Use specific search queries combining multiple filters for precise results. When searching for tasks, start with broader queries and narrow down as needed.
2779
+
2780
+ 3. **Assignments**: Always validate project collaborators exist before assigning tasks. Use find-project-collaborators to verify user access.
2781
+
2782
+ 4. **Bulk Operations**: When working with multiple items, prefer bulk tools (complete-tasks, manage-assignments) over individual operations for better performance.
2783
+
2784
+ 5. **Date Handling**: All dates respect user timezone settings. Use 'today' keyword for dynamic date filtering (includes overdue tasks).
2785
+
2786
+ 6. **Labels**: Use label filtering with AND/OR operators for advanced task organization. Most search tools support labels parameter.
2787
+
2788
+ 7. **Pagination**: Large result sets use cursor-based pagination. Use limit parameter to control result size (default varies by tool).
2789
+
2790
+ 8. **Error Handling**: All tools provide detailed error messages and next-step suggestions. Pay attention to validation feedback for corrective actions.
2791
+
2792
+ ### Common Workflows:
2793
+
2794
+ - **Daily Planning**: Use find-tasks-by-date with 'today' and get-overview for project status
2795
+ - **Team Assignment**: find-project-collaborators → add-tasks with responsibleUser → manage-assignments for bulk changes
2796
+ - **Task Search**: find-tasks with multiple filters → update-tasks or complete-tasks based on results
2797
+ - **Project Organization**: add-projects → add-sections → add-tasks with projectId and sectionId
2798
+ - **Progress Reviews**: find-completed-tasks with date ranges → get-overview for project summaries
2799
+ - **Activity Auditing**: find-activity with event/object filters to track changes, monitor team activity, or investigate specific actions
2800
+
2801
+ Always provide clear, actionable task titles and descriptions. Use the overview tools to give users context about their workload and project status.
2802
+ `;
2803
+ function Rs({ todoistApiKey: e, baseUrl: t }) {
2804
+ const s = new ve(
2805
+ { name: "todoist-mcp-server", version: "0.1.0" },
2806
+ {
2807
+ capabilities: {
2808
+ tools: { listChanged: !0 }
2809
+ },
2810
+ instructions: Os
2811
+ }
2812
+ ), o = new Ce(e, t);
2813
+ return w(ot, s, o), w(at, s, o), w(ks, s, o), w(Lt, s, o), w(Yt, s, o), w(Ct, s, o), w(_e, s, o), w(ps, s, o), w(Et, s, o), w(Re, s, o), w(bs, s, o), w(Mt, s, o), w(Ue, s, o), w(kt, s, o), w(cs, s, o), w(ft, s, o), w(Zt, s, o), w(dt, s, o), w(Es, s, o), w(xt, s, o), w(os, s, o), w(rs, s, o), w(mt, s, o), s;
2814
+ }
2815
+ export {
2816
+ xt as a,
2817
+ Zt as b,
2818
+ ft as c,
2819
+ dt as d,
2820
+ kt as e,
2821
+ mt as f,
2822
+ Rs as g,
2823
+ cs as h,
2824
+ Ue as i,
2825
+ Mt as j,
2826
+ bs as k,
2827
+ Re as l,
2828
+ os as m,
2829
+ Et as n,
2830
+ ps as o,
2831
+ _e as p,
2832
+ Ct as q,
2833
+ Yt as r,
2834
+ rs as s,
2835
+ Lt as t,
2836
+ Es as u,
2837
+ ks as v,
2838
+ at as w,
2839
+ ot as x
2840
+ };