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