@doist/todoist-ai 4.10.0 → 4.13.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/dist/filter-helpers.d.ts +51 -0
- package/dist/filter-helpers.d.ts.map +1 -0
- package/dist/filter-helpers.js +79 -0
- package/dist/index.d.ts +47 -23
- package/dist/index.d.ts.map +1 -1
- package/dist/tool-helpers.d.ts +8 -20
- package/dist/tool-helpers.d.ts.map +1 -1
- package/dist/tool-helpers.js +6 -23
- package/dist/tools/__tests__/find-completed-tasks.test.js +71 -12
- package/dist/tools/__tests__/find-tasks-by-date.test.js +118 -20
- package/dist/tools/__tests__/find-tasks.test.js +2 -0
- package/dist/tools/add-projects.d.ts +3 -3
- package/dist/tools/add-tasks.d.ts +6 -3
- package/dist/tools/add-tasks.d.ts.map +1 -1
- package/dist/tools/delete-object.d.ts +1 -1
- package/dist/tools/find-completed-tasks.d.ts +8 -2
- package/dist/tools/find-completed-tasks.d.ts.map +1 -1
- package/dist/tools/find-completed-tasks.js +37 -4
- package/dist/tools/find-tasks-by-date.d.ts +9 -0
- package/dist/tools/find-tasks-by-date.d.ts.map +1 -1
- package/dist/tools/find-tasks-by-date.js +39 -15
- package/dist/tools/find-tasks.d.ts +5 -2
- package/dist/tools/find-tasks.d.ts.map +1 -1
- package/dist/tools/find-tasks.js +20 -36
- package/dist/tools/update-comments.d.ts +3 -3
- package/dist/tools/update-sections.d.ts +3 -3
- package/dist/tools/update-tasks.d.ts +9 -6
- package/dist/tools/update-tasks.d.ts.map +1 -1
- package/dist/utils/test-helpers.d.ts +3 -0
- package/dist/utils/test-helpers.d.ts.map +1 -1
- package/dist/utils/test-helpers.js +3 -0
- package/dist/utils/user-resolver.d.ts +2 -4
- package/dist/utils/user-resolver.d.ts.map +1 -1
- package/dist/utils/user-resolver.js +5 -5
- package/package.json +4 -4
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { addDays, formatISO } from 'date-fns';
|
|
2
2
|
import { z } from 'zod';
|
|
3
|
+
import { appendToQuery, buildResponsibleUserQueryFilter, RESPONSIBLE_USER_FILTERING, resolveResponsibleUser, } from '../filter-helpers.js';
|
|
3
4
|
import { getToolOutput } from '../mcp-helpers.js';
|
|
4
|
-
import {
|
|
5
|
+
import { getTasksByFilter } from '../tool-helpers.js';
|
|
5
6
|
import { ApiLimits } from '../utils/constants.js';
|
|
6
7
|
import { generateLabelsFilter, LabelsSchema } from '../utils/labels.js';
|
|
7
8
|
import { generateTaskNextSteps, getDateString, previewTasks, summarizeList, } from '../utils/response-builders.js';
|
|
@@ -34,6 +35,14 @@ const ArgsSchema = {
|
|
|
34
35
|
.string()
|
|
35
36
|
.optional()
|
|
36
37
|
.describe('The cursor to get the next page of tasks (cursor is obtained from the previous call to this tool, with the same parameters).'),
|
|
38
|
+
responsibleUser: z
|
|
39
|
+
.string()
|
|
40
|
+
.optional()
|
|
41
|
+
.describe('Find tasks assigned to this user. Can be a user ID, name, or email address.'),
|
|
42
|
+
responsibleUserFiltering: z
|
|
43
|
+
.enum(RESPONSIBLE_USER_FILTERING)
|
|
44
|
+
.optional()
|
|
45
|
+
.describe('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".'),
|
|
37
46
|
...LabelsSchema,
|
|
38
47
|
};
|
|
39
48
|
const findTasksByDate = {
|
|
@@ -44,14 +53,18 @@ const findTasksByDate = {
|
|
|
44
53
|
if (!args.startDate && args.overdueOption !== 'overdue-only') {
|
|
45
54
|
throw new Error('Either startDate must be provided or overdueOption must be set to overdue-only');
|
|
46
55
|
}
|
|
56
|
+
// Resolve assignee name to user ID if provided
|
|
57
|
+
const resolved = await resolveResponsibleUser(client, args.responsibleUser);
|
|
58
|
+
const resolvedAssigneeId = resolved?.userId;
|
|
59
|
+
const assigneeEmail = resolved?.email;
|
|
47
60
|
let query = '';
|
|
48
|
-
const todoistUser = await client.getUser();
|
|
49
61
|
if (args.overdueOption === 'overdue-only') {
|
|
50
62
|
query = 'overdue';
|
|
51
63
|
}
|
|
52
64
|
else if (args.startDate === 'today') {
|
|
53
65
|
// For 'today', include overdue unless explicitly excluded
|
|
54
|
-
|
|
66
|
+
// Use parentheses to ensure correct operator precedence when combining with other filters
|
|
67
|
+
query = args.overdueOption === 'exclude-overdue' ? 'today' : '(today | overdue)';
|
|
55
68
|
}
|
|
56
69
|
else if (args.startDate) {
|
|
57
70
|
// For specific dates, never include overdue tasks
|
|
@@ -60,30 +73,31 @@ const findTasksByDate = {
|
|
|
60
73
|
const endDateStr = formatISO(endDate, { representation: 'date' });
|
|
61
74
|
query = `(due after: ${startDate} | due: ${startDate}) & due before: ${endDateStr}`;
|
|
62
75
|
}
|
|
76
|
+
// Add labels filter
|
|
63
77
|
const labelsFilter = generateLabelsFilter(args.labels, args.labelsOperator);
|
|
64
78
|
if (labelsFilter.length > 0) {
|
|
65
|
-
|
|
66
|
-
if (query.length > 0)
|
|
67
|
-
query += ' & ';
|
|
68
|
-
// Add the labels to the filter
|
|
69
|
-
query += `(${labelsFilter})`;
|
|
79
|
+
query = appendToQuery(query, `(${labelsFilter})`);
|
|
70
80
|
}
|
|
81
|
+
// Add responsible user filtering to the query (backend filtering)
|
|
82
|
+
const responsibleUserFilter = buildResponsibleUserQueryFilter({
|
|
83
|
+
resolvedAssigneeId,
|
|
84
|
+
assigneeEmail,
|
|
85
|
+
responsibleUserFiltering: args.responsibleUserFiltering,
|
|
86
|
+
});
|
|
87
|
+
query = appendToQuery(query, responsibleUserFilter);
|
|
71
88
|
const result = await getTasksByFilter({
|
|
72
89
|
client,
|
|
73
90
|
query,
|
|
74
91
|
cursor: args.cursor,
|
|
75
92
|
limit: args.limit,
|
|
76
93
|
});
|
|
77
|
-
//
|
|
78
|
-
const filteredTasks =
|
|
79
|
-
tasks: result.tasks,
|
|
80
|
-
resolvedAssigneeId: undefined,
|
|
81
|
-
currentUserId: todoistUser.id,
|
|
82
|
-
});
|
|
94
|
+
// No need for post-fetch filtering since it's handled in the query
|
|
95
|
+
const filteredTasks = result.tasks;
|
|
83
96
|
const textContent = generateTextContent({
|
|
84
97
|
tasks: filteredTasks,
|
|
85
98
|
args,
|
|
86
99
|
nextCursor: result.nextCursor,
|
|
100
|
+
assigneeEmail,
|
|
87
101
|
});
|
|
88
102
|
return getToolOutput({
|
|
89
103
|
textContent,
|
|
@@ -97,7 +111,7 @@ const findTasksByDate = {
|
|
|
97
111
|
});
|
|
98
112
|
},
|
|
99
113
|
};
|
|
100
|
-
function generateTextContent({ tasks, args, nextCursor, }) {
|
|
114
|
+
function generateTextContent({ tasks, args, nextCursor, assigneeEmail, }) {
|
|
101
115
|
// Generate filter description
|
|
102
116
|
const filterHints = [];
|
|
103
117
|
if (args.overdueOption === 'overdue-only') {
|
|
@@ -120,6 +134,11 @@ function generateTextContent({ tasks, args, nextCursor, }) {
|
|
|
120
134
|
.join(args.labelsOperator === 'and' ? ' & ' : ' | ');
|
|
121
135
|
filterHints.push(`labels: ${labelText}`);
|
|
122
136
|
}
|
|
137
|
+
// Add responsible user filter information
|
|
138
|
+
if (args.responsibleUser) {
|
|
139
|
+
const email = assigneeEmail || args.responsibleUser;
|
|
140
|
+
filterHints.push(`assigned to: ${email}`);
|
|
141
|
+
}
|
|
123
142
|
// Generate subject description
|
|
124
143
|
let subject = '';
|
|
125
144
|
if (args.overdueOption === 'overdue-only') {
|
|
@@ -135,6 +154,11 @@ function generateTextContent({ tasks, args, nextCursor, }) {
|
|
|
135
154
|
else {
|
|
136
155
|
subject = 'Tasks';
|
|
137
156
|
}
|
|
157
|
+
// Append responsible user to subject if provided
|
|
158
|
+
if (args.responsibleUser) {
|
|
159
|
+
const email = assigneeEmail || args.responsibleUser;
|
|
160
|
+
subject += ` assigned to ${email}`;
|
|
161
|
+
}
|
|
138
162
|
// Generate helpful suggestions for empty results
|
|
139
163
|
const zeroReasonHints = [];
|
|
140
164
|
if (tasks.length === 0) {
|
|
@@ -16,9 +16,9 @@ declare const findTasks: {
|
|
|
16
16
|
};
|
|
17
17
|
execute(args: {
|
|
18
18
|
limit: number;
|
|
19
|
-
projectId?: string | undefined;
|
|
20
19
|
parentId?: string | undefined;
|
|
21
20
|
responsibleUserFiltering?: "assigned" | "unassignedOrMe" | "all" | undefined;
|
|
21
|
+
projectId?: string | undefined;
|
|
22
22
|
sectionId?: string | undefined;
|
|
23
23
|
labels?: string[] | undefined;
|
|
24
24
|
cursor?: string | undefined;
|
|
@@ -45,15 +45,18 @@ declare const findTasks: {
|
|
|
45
45
|
duration: string | null;
|
|
46
46
|
responsibleUid: string | null;
|
|
47
47
|
assignedByUid: string | null;
|
|
48
|
+
checked: boolean;
|
|
49
|
+
completedAt: string | null;
|
|
50
|
+
updatedAt: string | null;
|
|
48
51
|
}[];
|
|
49
52
|
nextCursor: string | null;
|
|
50
53
|
totalCount: number;
|
|
51
54
|
hasMore: boolean;
|
|
52
55
|
appliedFilters: {
|
|
53
56
|
limit: number;
|
|
54
|
-
projectId?: string | undefined;
|
|
55
57
|
parentId?: string | undefined;
|
|
56
58
|
responsibleUserFiltering?: "assigned" | "unassignedOrMe" | "all" | undefined;
|
|
59
|
+
projectId?: string | undefined;
|
|
57
60
|
sectionId?: string | undefined;
|
|
58
61
|
labels?: string[] | undefined;
|
|
59
62
|
cursor?: string | undefined;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"find-tasks.d.ts","sourceRoot":"","sources":["../../src/tools/find-tasks.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAsDvB,QAAA,MAAM,SAAS
|
|
1
|
+
{"version":3,"file":"find-tasks.d.ts","sourceRoot":"","sources":["../../src/tools/find-tasks.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAsDvB,QAAA,MAAM,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAqL2B,CAAA;AA2K1C,OAAO,EAAE,SAAS,EAAE,CAAA"}
|
package/dist/tools/find-tasks.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
+
import { appendToQuery, filterTasksByResponsibleUser, RESPONSIBLE_USER_FILTERING, resolveResponsibleUser, } from '../filter-helpers.js';
|
|
2
3
|
import { getToolOutput } from '../mcp-helpers.js';
|
|
3
|
-
import {
|
|
4
|
+
import { getTasksByFilter, mapTask } from '../tool-helpers.js';
|
|
4
5
|
import { ApiLimits } from '../utils/constants.js';
|
|
5
6
|
import { generateLabelsFilter, LabelsSchema } from '../utils/labels.js';
|
|
6
7
|
import { generateTaskNextSteps, getDateString, previewTasks, summarizeList, } from '../utils/response-builders.js';
|
|
7
8
|
import { ToolNames } from '../utils/tool-names.js';
|
|
8
|
-
import { resolveUserNameToId } from '../utils/user-resolver.js';
|
|
9
9
|
const { FIND_COMPLETED_TASKS, ADD_TASKS } = ToolNames;
|
|
10
10
|
const ArgsSchema = {
|
|
11
11
|
searchText: z.string().optional().describe('The text to search for in tasks.'),
|
|
@@ -51,18 +51,9 @@ const findTasks = {
|
|
|
51
51
|
throw new Error('At least one filter must be provided: searchText, projectId, sectionId, parentId, responsibleUser, or labels');
|
|
52
52
|
}
|
|
53
53
|
// Resolve assignee name to user ID if provided
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
const resolved = await resolveUserNameToId(client, responsibleUser);
|
|
58
|
-
if (resolved) {
|
|
59
|
-
resolvedAssigneeId = resolved.userId;
|
|
60
|
-
assigneeDisplayName = resolved.displayName;
|
|
61
|
-
}
|
|
62
|
-
else {
|
|
63
|
-
throw new Error(`Could not find user: "${responsibleUser}". Make sure the user is a collaborator on a shared project.`);
|
|
64
|
-
}
|
|
65
|
-
}
|
|
54
|
+
const resolved = await resolveResponsibleUser(client, responsibleUser);
|
|
55
|
+
const resolvedAssigneeId = resolved?.userId;
|
|
56
|
+
const assigneeEmail = resolved?.email;
|
|
66
57
|
// If using container-based filtering, use direct API
|
|
67
58
|
if (projectId || sectionId || parentId) {
|
|
68
59
|
const taskParams = {
|
|
@@ -101,7 +92,7 @@ const findTasks = {
|
|
|
101
92
|
args,
|
|
102
93
|
nextCursor,
|
|
103
94
|
isContainerSearch: true,
|
|
104
|
-
|
|
95
|
+
assigneeEmail,
|
|
105
96
|
});
|
|
106
97
|
return getToolOutput({
|
|
107
98
|
textContent,
|
|
@@ -117,7 +108,7 @@ const findTasks = {
|
|
|
117
108
|
// If only responsibleUid is provided (without containers), use assignee filter
|
|
118
109
|
if (resolvedAssigneeId && !searchText && !hasLabels) {
|
|
119
110
|
const tasks = await client.getTasksByFilter({
|
|
120
|
-
query: `assigned to: ${
|
|
111
|
+
query: `assigned to: ${assigneeEmail}`,
|
|
121
112
|
lang: 'en',
|
|
122
113
|
limit,
|
|
123
114
|
cursor: cursor ?? null,
|
|
@@ -128,7 +119,7 @@ const findTasks = {
|
|
|
128
119
|
args,
|
|
129
120
|
nextCursor: tasks.nextCursor,
|
|
130
121
|
isContainerSearch: false,
|
|
131
|
-
|
|
122
|
+
assigneeEmail,
|
|
132
123
|
});
|
|
133
124
|
return getToolOutput({
|
|
134
125
|
textContent,
|
|
@@ -149,14 +140,7 @@ const findTasks = {
|
|
|
149
140
|
}
|
|
150
141
|
// Add labels component
|
|
151
142
|
const labelsFilter = generateLabelsFilter(labels, labelsOperator);
|
|
152
|
-
|
|
153
|
-
if (query.length > 0) {
|
|
154
|
-
query += ` & ${labelsFilter}`;
|
|
155
|
-
}
|
|
156
|
-
else {
|
|
157
|
-
query = labelsFilter;
|
|
158
|
-
}
|
|
159
|
-
}
|
|
143
|
+
query = appendToQuery(query, labelsFilter);
|
|
160
144
|
// Execute filter query
|
|
161
145
|
const result = await getTasksByFilter({
|
|
162
146
|
client,
|
|
@@ -175,7 +159,7 @@ const findTasks = {
|
|
|
175
159
|
args,
|
|
176
160
|
nextCursor: result.nextCursor,
|
|
177
161
|
isContainerSearch: false,
|
|
178
|
-
|
|
162
|
+
assigneeEmail,
|
|
179
163
|
});
|
|
180
164
|
return getToolOutput({
|
|
181
165
|
textContent,
|
|
@@ -215,7 +199,7 @@ function getContainerZeroReasonHints(args) {
|
|
|
215
199
|
}
|
|
216
200
|
return [];
|
|
217
201
|
}
|
|
218
|
-
function generateTextContent({ tasks, args, nextCursor, isContainerSearch,
|
|
202
|
+
function generateTextContent({ tasks, args, nextCursor, isContainerSearch, assigneeEmail, }) {
|
|
219
203
|
// Generate subject and filter descriptions based on search type
|
|
220
204
|
let subject = 'Tasks';
|
|
221
205
|
const filterHints = [];
|
|
@@ -244,9 +228,9 @@ function generateTextContent({ tasks, args, nextCursor, isContainerSearch, assig
|
|
|
244
228
|
}
|
|
245
229
|
// Add responsibleUid filter if present
|
|
246
230
|
if (args.responsibleUser) {
|
|
247
|
-
const
|
|
248
|
-
subject += ` assigned to ${
|
|
249
|
-
filterHints.push(`assigned to ${
|
|
231
|
+
const email = assigneeEmail || args.responsibleUser;
|
|
232
|
+
subject += ` assigned to ${email}`;
|
|
233
|
+
filterHints.push(`assigned to ${email}`);
|
|
250
234
|
}
|
|
251
235
|
// Add label filter information
|
|
252
236
|
if (args.labels && args.labels.length > 0) {
|
|
@@ -262,14 +246,14 @@ function generateTextContent({ tasks, args, nextCursor, isContainerSearch, assig
|
|
|
262
246
|
}
|
|
263
247
|
else {
|
|
264
248
|
// Text, responsibleUid, or labels search
|
|
265
|
-
const
|
|
249
|
+
const email = assigneeEmail || args.responsibleUser;
|
|
266
250
|
// Build subject based on filters
|
|
267
251
|
const subjectParts = [];
|
|
268
252
|
if (args.searchText) {
|
|
269
253
|
subjectParts.push(`"${args.searchText}"`);
|
|
270
254
|
}
|
|
271
255
|
if (args.responsibleUser) {
|
|
272
|
-
subjectParts.push(`assigned to ${
|
|
256
|
+
subjectParts.push(`assigned to ${email}`);
|
|
273
257
|
}
|
|
274
258
|
if (args.labels && args.labels.length > 0) {
|
|
275
259
|
const labelText = args.labels
|
|
@@ -282,7 +266,7 @@ function generateTextContent({ tasks, args, nextCursor, isContainerSearch, assig
|
|
|
282
266
|
filterHints.push(`matching "${args.searchText}"`);
|
|
283
267
|
}
|
|
284
268
|
else if (args.responsibleUser && (!args.labels || args.labels.length === 0)) {
|
|
285
|
-
subject = `Tasks assigned to ${
|
|
269
|
+
subject = `Tasks assigned to ${email}`;
|
|
286
270
|
}
|
|
287
271
|
else if (args.labels && args.labels.length > 0 && !args.responsibleUser) {
|
|
288
272
|
const labelText = args.labels
|
|
@@ -295,7 +279,7 @@ function generateTextContent({ tasks, args, nextCursor, isContainerSearch, assig
|
|
|
295
279
|
}
|
|
296
280
|
// Add filter hints
|
|
297
281
|
if (args.responsibleUser) {
|
|
298
|
-
filterHints.push(`assigned to ${
|
|
282
|
+
filterHints.push(`assigned to ${email}`);
|
|
299
283
|
}
|
|
300
284
|
if (args.labels && args.labels.length > 0) {
|
|
301
285
|
const labelText = args.labels
|
|
@@ -305,8 +289,8 @@ function generateTextContent({ tasks, args, nextCursor, isContainerSearch, assig
|
|
|
305
289
|
}
|
|
306
290
|
if (tasks.length === 0) {
|
|
307
291
|
if (args.responsibleUser) {
|
|
308
|
-
const
|
|
309
|
-
zeroReasonHints.push(`No tasks assigned to ${
|
|
292
|
+
const email = assigneeEmail || args.responsibleUser;
|
|
293
|
+
zeroReasonHints.push(`No tasks assigned to ${email}`);
|
|
310
294
|
zeroReasonHints.push('Check if the user name is correct');
|
|
311
295
|
zeroReasonHints.push(`Check completed tasks with ${FIND_COMPLETED_TASKS}`);
|
|
312
296
|
}
|
|
@@ -7,17 +7,17 @@ declare const updateComments: {
|
|
|
7
7
|
id: z.ZodString;
|
|
8
8
|
content: z.ZodString;
|
|
9
9
|
}, "strip", z.ZodTypeAny, {
|
|
10
|
-
content: string;
|
|
11
10
|
id: string;
|
|
12
|
-
}, {
|
|
13
11
|
content: string;
|
|
12
|
+
}, {
|
|
14
13
|
id: string;
|
|
14
|
+
content: string;
|
|
15
15
|
}>, "many">;
|
|
16
16
|
};
|
|
17
17
|
execute(args: {
|
|
18
18
|
comments: {
|
|
19
|
-
content: string;
|
|
20
19
|
id: string;
|
|
20
|
+
content: string;
|
|
21
21
|
}[];
|
|
22
22
|
}, client: import("@doist/todoist-api-typescript").TodoistApi): Promise<{
|
|
23
23
|
content: {
|
|
@@ -7,17 +7,17 @@ declare const updateSections: {
|
|
|
7
7
|
id: z.ZodString;
|
|
8
8
|
name: z.ZodString;
|
|
9
9
|
}, "strip", z.ZodTypeAny, {
|
|
10
|
-
name: string;
|
|
11
10
|
id: string;
|
|
12
|
-
}, {
|
|
13
11
|
name: string;
|
|
12
|
+
}, {
|
|
14
13
|
id: string;
|
|
14
|
+
name: string;
|
|
15
15
|
}>, "many">;
|
|
16
16
|
};
|
|
17
17
|
execute({ sections }: {
|
|
18
18
|
sections: {
|
|
19
|
-
name: string;
|
|
20
19
|
id: string;
|
|
20
|
+
name: string;
|
|
21
21
|
}[];
|
|
22
22
|
}, client: import("@doist/todoist-api-typescript").TodoistApi): Promise<{
|
|
23
23
|
content: {
|
|
@@ -18,10 +18,10 @@ declare const updateTasks: {
|
|
|
18
18
|
labels: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
19
19
|
}, "strip", z.ZodTypeAny, {
|
|
20
20
|
id: string;
|
|
21
|
-
content?: string | undefined;
|
|
22
21
|
description?: string | undefined;
|
|
23
|
-
projectId?: string | undefined;
|
|
24
22
|
parentId?: string | undefined;
|
|
23
|
+
content?: string | undefined;
|
|
24
|
+
projectId?: string | undefined;
|
|
25
25
|
sectionId?: string | undefined;
|
|
26
26
|
labels?: string[] | undefined;
|
|
27
27
|
duration?: string | undefined;
|
|
@@ -31,10 +31,10 @@ declare const updateTasks: {
|
|
|
31
31
|
order?: number | undefined;
|
|
32
32
|
}, {
|
|
33
33
|
id: string;
|
|
34
|
-
content?: string | undefined;
|
|
35
34
|
description?: string | undefined;
|
|
36
|
-
projectId?: string | undefined;
|
|
37
35
|
parentId?: string | undefined;
|
|
36
|
+
content?: string | undefined;
|
|
37
|
+
projectId?: string | undefined;
|
|
38
38
|
sectionId?: string | undefined;
|
|
39
39
|
labels?: string[] | undefined;
|
|
40
40
|
duration?: string | undefined;
|
|
@@ -47,10 +47,10 @@ declare const updateTasks: {
|
|
|
47
47
|
execute(args: {
|
|
48
48
|
tasks: {
|
|
49
49
|
id: string;
|
|
50
|
-
content?: string | undefined;
|
|
51
50
|
description?: string | undefined;
|
|
52
|
-
projectId?: string | undefined;
|
|
53
51
|
parentId?: string | undefined;
|
|
52
|
+
content?: string | undefined;
|
|
53
|
+
projectId?: string | undefined;
|
|
54
54
|
sectionId?: string | undefined;
|
|
55
55
|
labels?: string[] | undefined;
|
|
56
56
|
duration?: string | undefined;
|
|
@@ -79,6 +79,9 @@ declare const updateTasks: {
|
|
|
79
79
|
duration: string | null;
|
|
80
80
|
responsibleUid: string | null;
|
|
81
81
|
assignedByUid: string | null;
|
|
82
|
+
checked: boolean;
|
|
83
|
+
completedAt: string | null;
|
|
84
|
+
updatedAt: string | null;
|
|
82
85
|
}[];
|
|
83
86
|
totalCount: number;
|
|
84
87
|
updatedTaskIds: string[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"update-tasks.d.ts","sourceRoot":"","sources":["../../src/tools/update-tasks.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AA8DvB,QAAA,MAAM,WAAW
|
|
1
|
+
{"version":3,"file":"update-tasks.d.ts","sourceRoot":"","sources":["../../src/tools/update-tasks.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AA8DvB,QAAA,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAkHyB,CAAA;AAqC1C,OAAO,EAAE,WAAW,EAAE,CAAA"}
|
|
@@ -18,6 +18,9 @@ export type MappedTask = {
|
|
|
18
18
|
duration: string | null;
|
|
19
19
|
responsibleUid: string | null;
|
|
20
20
|
assignedByUid: string | null;
|
|
21
|
+
checked: boolean;
|
|
22
|
+
completedAt: string | null;
|
|
23
|
+
updatedAt: string | null;
|
|
21
24
|
};
|
|
22
25
|
/**
|
|
23
26
|
* Creates a mock Task with all required properties and sensible defaults.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"test-helpers.d.ts","sourceRoot":"","sources":["../../src/utils/test-helpers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,eAAe,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,+BAA+B,CAAA;AAChG,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAA;AAE9C;;;GAGG;AACH,MAAM,MAAM,UAAU,GAAG;IACrB,EAAE,EAAE,MAAM,CAAA;IACV,OAAO,EAAE,MAAM,CAAA;IACf,WAAW,EAAE,MAAM,CAAA;IACnB,OAAO,EAAE,MAAM,GAAG,SAAS,CAAA;IAC3B,SAAS,EAAE,MAAM,GAAG,OAAO,CAAA;IAC3B,QAAQ,EAAE,MAAM,CAAA;IAChB,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;IACvB,MAAM,EAAE,MAAM,EAAE,CAAA;IAChB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;IACvB,cAAc,EAAE,MAAM,GAAG,IAAI,CAAA;IAC7B,aAAa,EAAE,MAAM,GAAG,IAAI,CAAA;
|
|
1
|
+
{"version":3,"file":"test-helpers.d.ts","sourceRoot":"","sources":["../../src/utils/test-helpers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,eAAe,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,+BAA+B,CAAA;AAChG,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAA;AAE9C;;;GAGG;AACH,MAAM,MAAM,UAAU,GAAG;IACrB,EAAE,EAAE,MAAM,CAAA;IACV,OAAO,EAAE,MAAM,CAAA;IACf,WAAW,EAAE,MAAM,CAAA;IACnB,OAAO,EAAE,MAAM,GAAG,SAAS,CAAA;IAC3B,SAAS,EAAE,MAAM,GAAG,OAAO,CAAA;IAC3B,QAAQ,EAAE,MAAM,CAAA;IAChB,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;IACvB,MAAM,EAAE,MAAM,EAAE,CAAA;IAChB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;IACvB,cAAc,EAAE,MAAM,GAAG,IAAI,CAAA;IAC7B,aAAa,EAAE,MAAM,GAAG,IAAI,CAAA;IAC5B,OAAO,EAAE,OAAO,CAAA;IAChB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;CAC3B,CAAA;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,SAAS,GAAE,OAAO,CAAC,IAAI,CAAM,GAAG,IAAI,CA8BlE;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,SAAS,GAAE,OAAO,CAAC,OAAO,CAAM,GAAG,OAAO,CAgB3E;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,SAAS,GAAE,OAAO,CAAC,eAAe,CAAM,GAAG,eAAe,CAuB3F;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,CAAC,EACnC,OAAO,EAAE,CAAC,EAAE,EACZ,UAAU,GAAE,MAAM,GAAG,IAAW,GACjC;IACC,OAAO,EAAE,CAAC,EAAE,CAAA;IACZ,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;CAC5B,CAKA;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,SAAS,GAAE,OAAO,CAAC,UAAU,CAAM,GAAG,UAAU,CAoBhF;AAED;;GAEG;AACH,eAAO,MAAM,WAAW;;;;;CAKd,CAAA;AAEV;;GAEG;AACH,wBAAgB,eAAe,CAAC,CAAC,EAAE,CAAC,GAAG,OAAO,EAC1C,KAAK,EAAE,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,CAAC,CAAC;IAAC,QAAQ,CAAC,EAAE,CAAC,CAAA;CAAE,CAAC;UAAjC,MAAM;WAAS,CAAC;eAAa,CAAC;IAGtD;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,OAAO,GAAG,MAAM,CAqB9D;AAED;;;GAGG;AACH,wBAAgB,wBAAwB,CACpC,MAAM,EAAE,UAAU,CAAC,OAAO,aAAa,CAAC,GACzC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAuBzB;AAED;;GAEG;AACH,eAAO,MAAM,QAAQ;;;;;;;;;;CAUX,CAAA;AAEV;;;GAGG;AACH,eAAO,MAAM,KAAK,EAAG,YAAqB,CAAA;AAE1C;;;GAGG;AACH,wBAAgB,cAAc,CAAC,SAAS,GAAE,OAAO,CAAC,WAAW,CAAM,GAAG,WAAW,CAmChF"}
|
|
@@ -2,6 +2,7 @@ import type { TodoistApi } from '@doist/todoist-api-typescript';
|
|
|
2
2
|
export type ResolvedUser = {
|
|
3
3
|
userId: string;
|
|
4
4
|
displayName: string;
|
|
5
|
+
email: string;
|
|
5
6
|
};
|
|
6
7
|
export type ProjectCollaborator = {
|
|
7
8
|
id: string;
|
|
@@ -32,8 +33,5 @@ export declare class UserResolver {
|
|
|
32
33
|
clearCache(): void;
|
|
33
34
|
}
|
|
34
35
|
export declare const userResolver: UserResolver;
|
|
35
|
-
export declare function resolveUserNameToId(client: TodoistApi, nameOrId: string): Promise<
|
|
36
|
-
userId: string;
|
|
37
|
-
displayName: string;
|
|
38
|
-
} | null>;
|
|
36
|
+
export declare function resolveUserNameToId(client: TodoistApi, nameOrId: string): Promise<ResolvedUser | null>;
|
|
39
37
|
//# sourceMappingURL=user-resolver.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"user-resolver.d.ts","sourceRoot":"","sources":["../../src/utils/user-resolver.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAA;AAE/D,MAAM,MAAM,YAAY,GAAG;IACvB,MAAM,EAAE,MAAM,CAAA;IACd,WAAW,EAAE,MAAM,CAAA;
|
|
1
|
+
{"version":3,"file":"user-resolver.d.ts","sourceRoot":"","sources":["../../src/utils/user-resolver.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAA;AAE/D,MAAM,MAAM,YAAY,GAAG;IACvB,MAAM,EAAE,MAAM,CAAA;IACd,WAAW,EAAE,MAAM,CAAA;IACnB,KAAK,EAAE,MAAM,CAAA;CAChB,CAAA;AAED,MAAM,MAAM,mBAAmB,GAAG;IAC9B,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,MAAM,CAAA;CAChB,CAAA;AAsBD,qBAAa,YAAY;IACrB;;;OAGG;IACG,WAAW,CAAC,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC;IAoFrF;;OAEG;IACG,2BAA2B,CAC7B,MAAM,EAAE,UAAU,EAClB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,GACf,OAAO,CAAC,OAAO,CAAC;IASnB;;OAEG;IACG,uBAAuB,CACzB,MAAM,EAAE,UAAU,EAClB,SAAS,EAAE,MAAM,GAClB,OAAO,CAAC,mBAAmB,EAAE,CAAC;IA2BjC;;OAEG;YACW,mBAAmB;IAqDjC;;OAEG;IACH,UAAU,IAAI,IAAI;CAIrB;AAGD,eAAO,MAAM,YAAY,cAAqB,CAAA;AAG9C,wBAAsB,mBAAmB,CACrC,MAAM,EAAE,UAAU,EAClB,QAAQ,EAAE,MAAM,GACjB,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAE9B"}
|
|
@@ -26,7 +26,7 @@ export class UserResolver {
|
|
|
26
26
|
(/^[a-z0-9_]{6,}$/i.test(trimmedInput) &&
|
|
27
27
|
!/^[a-z]+[\s-]/.test(trimmedInput) &&
|
|
28
28
|
/[0-9_]/.test(trimmedInput))) {
|
|
29
|
-
const result = { userId: trimmedInput, displayName: trimmedInput };
|
|
29
|
+
const result = { userId: trimmedInput, displayName: trimmedInput, email: trimmedInput };
|
|
30
30
|
userResolutionCache.set(trimmedInput, { result, timestamp: Date.now() });
|
|
31
31
|
return result;
|
|
32
32
|
}
|
|
@@ -42,28 +42,28 @@ export class UserResolver {
|
|
|
42
42
|
// Try exact name match first
|
|
43
43
|
let match = allCollaborators.find((c) => c.name.toLowerCase() === searchTerm);
|
|
44
44
|
if (match) {
|
|
45
|
-
const result = { userId: match.id, displayName: match.name };
|
|
45
|
+
const result = { userId: match.id, displayName: match.name, email: match.email };
|
|
46
46
|
userResolutionCache.set(trimmedInput, { result, timestamp: Date.now() });
|
|
47
47
|
return result;
|
|
48
48
|
}
|
|
49
49
|
// Try exact email match
|
|
50
50
|
match = allCollaborators.find((c) => c.email.toLowerCase() === searchTerm);
|
|
51
51
|
if (match) {
|
|
52
|
-
const result = { userId: match.id, displayName: match.name };
|
|
52
|
+
const result = { userId: match.id, displayName: match.name, email: match.email };
|
|
53
53
|
userResolutionCache.set(trimmedInput, { result, timestamp: Date.now() });
|
|
54
54
|
return result;
|
|
55
55
|
}
|
|
56
56
|
// Try partial name match (contains)
|
|
57
57
|
match = allCollaborators.find((c) => c.name.toLowerCase().includes(searchTerm));
|
|
58
58
|
if (match) {
|
|
59
|
-
const result = { userId: match.id, displayName: match.name };
|
|
59
|
+
const result = { userId: match.id, displayName: match.name, email: match.email };
|
|
60
60
|
userResolutionCache.set(trimmedInput, { result, timestamp: Date.now() });
|
|
61
61
|
return result;
|
|
62
62
|
}
|
|
63
63
|
// Try partial email match
|
|
64
64
|
match = allCollaborators.find((c) => c.email.toLowerCase().includes(searchTerm));
|
|
65
65
|
if (match) {
|
|
66
|
-
const result = { userId: match.id, displayName: match.name };
|
|
66
|
+
const result = { userId: match.id, displayName: match.name, email: match.email };
|
|
67
67
|
userResolutionCache.set(trimmedInput, { result, timestamp: Date.now() });
|
|
68
68
|
return result;
|
|
69
69
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@doist/todoist-ai",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.13.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -45,14 +45,14 @@
|
|
|
45
45
|
"prepare": "husky"
|
|
46
46
|
},
|
|
47
47
|
"dependencies": {
|
|
48
|
-
"@doist/todoist-api-typescript": "5.
|
|
48
|
+
"@doist/todoist-api-typescript": "5.6.4",
|
|
49
49
|
"@modelcontextprotocol/sdk": "^1.11.1",
|
|
50
50
|
"date-fns": "^4.1.0",
|
|
51
51
|
"dotenv": "^16.5.0",
|
|
52
52
|
"zod": "^3.25.7"
|
|
53
53
|
},
|
|
54
54
|
"devDependencies": {
|
|
55
|
-
"@biomejs/biome": "2.2.
|
|
55
|
+
"@biomejs/biome": "2.2.6",
|
|
56
56
|
"@types/express": "^5.0.2",
|
|
57
57
|
"@types/jest": "30.0.0",
|
|
58
58
|
"@types/morgan": "^1.9.9",
|
|
@@ -65,7 +65,7 @@
|
|
|
65
65
|
"morgan": "^1.10.0",
|
|
66
66
|
"nodemon": "^3.1.10",
|
|
67
67
|
"rimraf": "^6.0.1",
|
|
68
|
-
"ts-jest": "29.4.
|
|
68
|
+
"ts-jest": "29.4.5",
|
|
69
69
|
"typescript": "^5.8.3"
|
|
70
70
|
},
|
|
71
71
|
"lint-staged": {
|