@doist/todoist-ai 4.9.1 → 4.9.3
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/index.d.ts +6 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/tools/__tests__/add-tasks.test.js +38 -0
- package/dist/tools/__tests__/find-tasks-by-date.test.js +26 -8
- package/dist/tools/add-tasks.js +2 -2
- package/dist/tools/find-tasks-by-date.d.ts +6 -3
- package/dist/tools/find-tasks-by-date.d.ts.map +1 -1
- package/dist/tools/find-tasks-by-date.js +53 -14
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -328,18 +328,20 @@ declare const tools: {
|
|
|
328
328
|
parameters: {
|
|
329
329
|
labels: import("zod").ZodOptional<import("zod").ZodArray<import("zod").ZodString, "many">>;
|
|
330
330
|
labelsOperator: import("zod").ZodOptional<import("zod").ZodEnum<["and", "or"]>>;
|
|
331
|
-
startDate: import("zod").ZodString
|
|
331
|
+
startDate: import("zod").ZodOptional<import("zod").ZodString>;
|
|
332
|
+
overdueOption: import("zod").ZodOptional<import("zod").ZodEnum<["overdue-only", "include-overdue", "exclude-overdue"]>>;
|
|
332
333
|
daysCount: import("zod").ZodDefault<import("zod").ZodNumber>;
|
|
333
334
|
limit: import("zod").ZodDefault<import("zod").ZodNumber>;
|
|
334
335
|
cursor: import("zod").ZodOptional<import("zod").ZodString>;
|
|
335
336
|
};
|
|
336
337
|
execute(args: {
|
|
337
338
|
limit: number;
|
|
338
|
-
startDate: string;
|
|
339
339
|
daysCount: number;
|
|
340
340
|
labels?: string[] | undefined;
|
|
341
341
|
cursor?: string | undefined;
|
|
342
342
|
labelsOperator?: "and" | "or" | undefined;
|
|
343
|
+
startDate?: string | undefined;
|
|
344
|
+
overdueOption?: "overdue-only" | "include-overdue" | "exclude-overdue" | undefined;
|
|
343
345
|
}, client: import("@doist/todoist-api-typescript").TodoistApi): Promise<{
|
|
344
346
|
content: {
|
|
345
347
|
type: "text";
|
|
@@ -366,11 +368,12 @@ declare const tools: {
|
|
|
366
368
|
hasMore: boolean;
|
|
367
369
|
appliedFilters: {
|
|
368
370
|
limit: number;
|
|
369
|
-
startDate: string;
|
|
370
371
|
daysCount: number;
|
|
371
372
|
labels?: string[] | undefined;
|
|
372
373
|
cursor?: string | undefined;
|
|
373
374
|
labelsOperator?: "and" | "or" | undefined;
|
|
375
|
+
startDate?: string | undefined;
|
|
376
|
+
overdueOption?: "overdue-only" | "include-overdue" | "exclude-overdue" | undefined;
|
|
374
377
|
};
|
|
375
378
|
};
|
|
376
379
|
} | {
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAA;AAE9C,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAA;AAErD,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAA;AAErD,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAA;AAErD,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAA;AAC/C,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAA;AAEzD,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAA;AACvD,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAA;AACvD,OAAO,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAA;AAEpE,OAAO,EAAE,wBAAwB,EAAE,MAAM,uCAAuC,CAAA;AAChF,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAA;AACvD,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAA;AACvD,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAA;AACjD,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAA;AAC/D,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAA;AACrD,OAAO,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAA;AACjE,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAA;AAC3D,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAA;AAC3D,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAA;AAC3D,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAA;AACrD,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAA;AAE/C,QAAA,MAAM,KAAK
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -448,4 +448,42 @@ describe(`${ADD_TASKS} tool`, () => {
|
|
|
448
448
|
expect(textContent).toContain(`Use ${GET_OVERVIEW} to see your updated project organization`);
|
|
449
449
|
});
|
|
450
450
|
});
|
|
451
|
+
describe('tasks without project context', () => {
|
|
452
|
+
it('should allow creating tasks with only content (goes to Inbox)', async () => {
|
|
453
|
+
const mockApiResponse = createMockTask({
|
|
454
|
+
id: '8485093758',
|
|
455
|
+
content: 'Simple inbox task',
|
|
456
|
+
url: 'https://todoist.com/showTask?id=8485093758',
|
|
457
|
+
addedAt: '2025-08-13T22:09:56.123456Z',
|
|
458
|
+
});
|
|
459
|
+
mockTodoistApi.addTask.mockResolvedValue(mockApiResponse);
|
|
460
|
+
const result = await addTasks.execute({
|
|
461
|
+
tasks: [
|
|
462
|
+
{
|
|
463
|
+
content: 'Simple inbox task',
|
|
464
|
+
},
|
|
465
|
+
],
|
|
466
|
+
}, mockTodoistApi);
|
|
467
|
+
expect(mockTodoistApi.addTask).toHaveBeenCalledWith({
|
|
468
|
+
content: 'Simple inbox task',
|
|
469
|
+
labels: undefined,
|
|
470
|
+
projectId: undefined,
|
|
471
|
+
sectionId: undefined,
|
|
472
|
+
parentId: undefined,
|
|
473
|
+
});
|
|
474
|
+
const textContent = extractTextContent(result);
|
|
475
|
+
expect(textContent).toContain('Added 1 task');
|
|
476
|
+
expect(textContent).toContain('Simple inbox task');
|
|
477
|
+
});
|
|
478
|
+
it('should prevent assignment without project context', async () => {
|
|
479
|
+
await expect(addTasks.execute({
|
|
480
|
+
tasks: [
|
|
481
|
+
{
|
|
482
|
+
content: 'Task with assignment but no project',
|
|
483
|
+
responsibleUser: 'user@example.com',
|
|
484
|
+
},
|
|
485
|
+
],
|
|
486
|
+
}, mockTodoistApi)).rejects.toThrow('Task "Task with assignment but no project": Cannot assign tasks without specifying project context. Please specify a projectId, sectionId, or parentId.');
|
|
487
|
+
});
|
|
488
|
+
});
|
|
451
489
|
});
|
|
@@ -20,18 +20,19 @@ const mockTodoistApi = {
|
|
|
20
20
|
const mockTodoistUser = createMockUser();
|
|
21
21
|
// Mock date-fns functions to make tests deterministic
|
|
22
22
|
jest.mock('date-fns', () => ({
|
|
23
|
-
addDays: jest.fn(() =>
|
|
23
|
+
addDays: jest.fn((date, amount) => {
|
|
24
|
+
const d = new Date(date);
|
|
25
|
+
d.setDate(d.getDate() + amount);
|
|
26
|
+
return d;
|
|
27
|
+
}),
|
|
24
28
|
formatISO: jest.fn((date, options) => {
|
|
25
29
|
if (typeof date === 'string') {
|
|
26
30
|
return date; // Return string dates as-is
|
|
27
31
|
}
|
|
28
|
-
if (options
|
|
29
|
-
|
|
30
|
-
'representation' in options &&
|
|
31
|
-
options.representation === 'date') {
|
|
32
|
-
return '2025-08-15'; // Return predictable date for 'today'
|
|
32
|
+
if (options?.representation === 'date') {
|
|
33
|
+
return date.toISOString().split('T')[0];
|
|
33
34
|
}
|
|
34
|
-
return
|
|
35
|
+
return date.toISOString();
|
|
35
36
|
}),
|
|
36
37
|
}));
|
|
37
38
|
const { FIND_TASKS_BY_DATE, UPDATE_TASKS } = ToolNames;
|
|
@@ -46,6 +47,23 @@ describe(`${FIND_TASKS_BY_DATE} tool`, () => {
|
|
|
46
47
|
jest.restoreAllMocks();
|
|
47
48
|
});
|
|
48
49
|
describe('listing tasks by date range', () => {
|
|
50
|
+
it('only returns tasks for the startDate when daysCount is 1', async () => {
|
|
51
|
+
const mockTasks = [
|
|
52
|
+
createMappedTask({ content: 'Task for specific date', dueDate: '2025-08-20' }),
|
|
53
|
+
];
|
|
54
|
+
const mockResponse = { tasks: mockTasks, nextCursor: null };
|
|
55
|
+
mockGetTasksByFilter.mockResolvedValue(mockResponse);
|
|
56
|
+
const result = await findTasksByDate.execute({ startDate: '2025-08-20', limit: 50, daysCount: 1 }, mockTodoistApi);
|
|
57
|
+
// Verify the query uses daysCount=1 by checking the end date calculation
|
|
58
|
+
expect(mockGetTasksByFilter).toHaveBeenCalledWith({
|
|
59
|
+
client: mockTodoistApi,
|
|
60
|
+
query: '(due after: 2025-08-20 | due: 2025-08-20) & due before: 2025-08-21',
|
|
61
|
+
cursor: undefined,
|
|
62
|
+
limit: 50,
|
|
63
|
+
});
|
|
64
|
+
const textContent = extractTextContent(result);
|
|
65
|
+
expect(textContent).toMatchSnapshot();
|
|
66
|
+
});
|
|
49
67
|
it('should get tasks for today when startDate is "today" (includes overdue)', async () => {
|
|
50
68
|
const mockTasks = [createMappedTask({ content: 'Today task', dueDate: '2025-08-15' })];
|
|
51
69
|
const mockResponse = { tasks: mockTasks, nextCursor: null };
|
|
@@ -375,7 +393,7 @@ describe(`${FIND_TASKS_BY_DATE} tool`, () => {
|
|
|
375
393
|
];
|
|
376
394
|
const mockResponse = { tasks: mockTasks, nextCursor: null };
|
|
377
395
|
mockGetTasksByFilter.mockResolvedValue(mockResponse);
|
|
378
|
-
const result = await findTasksByDate.execute({
|
|
396
|
+
const result = await findTasksByDate.execute({ overdueOption: 'overdue-only', daysCount: 1, limit: 50 }, mockTodoistApi);
|
|
379
397
|
const structuredContent = extractStructuredContent(result);
|
|
380
398
|
// Should only return tasks 1 and 2, not task 3
|
|
381
399
|
expect(structuredContent.tasks).toHaveLength(2);
|
package/dist/tools/add-tasks.js
CHANGED
|
@@ -55,8 +55,8 @@ async function processTask(task, client) {
|
|
|
55
55
|
if (priority) {
|
|
56
56
|
taskArgs.priority = convertPriorityToNumber(priority);
|
|
57
57
|
}
|
|
58
|
-
//
|
|
59
|
-
if (!projectId && !sectionId && !parentId) {
|
|
58
|
+
// Only prevent assignment (not task creation) without sufficient project context
|
|
59
|
+
if (responsibleUser && !projectId && !sectionId && !parentId) {
|
|
60
60
|
throw new Error(`Task "${task.content}": Cannot assign tasks without specifying project context. Please specify a projectId, sectionId, or parentId.`);
|
|
61
61
|
}
|
|
62
62
|
// Parse duration if provided
|
|
@@ -5,18 +5,20 @@ declare const findTasksByDate: {
|
|
|
5
5
|
parameters: {
|
|
6
6
|
labels: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
7
7
|
labelsOperator: z.ZodOptional<z.ZodEnum<["and", "or"]>>;
|
|
8
|
-
startDate: z.ZodString
|
|
8
|
+
startDate: z.ZodOptional<z.ZodString>;
|
|
9
|
+
overdueOption: z.ZodOptional<z.ZodEnum<["overdue-only", "include-overdue", "exclude-overdue"]>>;
|
|
9
10
|
daysCount: z.ZodDefault<z.ZodNumber>;
|
|
10
11
|
limit: z.ZodDefault<z.ZodNumber>;
|
|
11
12
|
cursor: z.ZodOptional<z.ZodString>;
|
|
12
13
|
};
|
|
13
14
|
execute(args: {
|
|
14
15
|
limit: number;
|
|
15
|
-
startDate: string;
|
|
16
16
|
daysCount: number;
|
|
17
17
|
labels?: string[] | undefined;
|
|
18
18
|
cursor?: string | undefined;
|
|
19
19
|
labelsOperator?: "and" | "or" | undefined;
|
|
20
|
+
startDate?: string | undefined;
|
|
21
|
+
overdueOption?: "overdue-only" | "include-overdue" | "exclude-overdue" | undefined;
|
|
20
22
|
}, client: import("@doist/todoist-api-typescript").TodoistApi): Promise<{
|
|
21
23
|
content: {
|
|
22
24
|
type: "text";
|
|
@@ -43,11 +45,12 @@ declare const findTasksByDate: {
|
|
|
43
45
|
hasMore: boolean;
|
|
44
46
|
appliedFilters: {
|
|
45
47
|
limit: number;
|
|
46
|
-
startDate: string;
|
|
47
48
|
daysCount: number;
|
|
48
49
|
labels?: string[] | undefined;
|
|
49
50
|
cursor?: string | undefined;
|
|
50
51
|
labelsOperator?: "and" | "or" | undefined;
|
|
52
|
+
startDate?: string | undefined;
|
|
53
|
+
overdueOption?: "overdue-only" | "include-overdue" | "exclude-overdue" | undefined;
|
|
51
54
|
};
|
|
52
55
|
};
|
|
53
56
|
} | {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"find-tasks-by-date.d.ts","sourceRoot":"","sources":["../../src/tools/find-tasks-by-date.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;
|
|
1
|
+
{"version":3,"file":"find-tasks-by-date.d.ts","sourceRoot":"","sources":["../../src/tools/find-tasks-by-date.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAmDvB,QAAA,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAmEqB,CAAA;AAwF1C,OAAO,EAAE,eAAe,EAAE,CAAA"}
|
|
@@ -10,14 +10,19 @@ const ArgsSchema = {
|
|
|
10
10
|
startDate: z
|
|
11
11
|
.string()
|
|
12
12
|
.regex(/^(\d{4}-\d{2}-\d{2}|today)$/)
|
|
13
|
+
.optional()
|
|
13
14
|
.describe("The start date to get the tasks for. Format: YYYY-MM-DD or 'today'."),
|
|
15
|
+
overdueOption: z
|
|
16
|
+
.enum(['overdue-only', 'include-overdue', 'exclude-overdue'])
|
|
17
|
+
.optional()
|
|
18
|
+
.describe("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'."),
|
|
14
19
|
daysCount: z
|
|
15
20
|
.number()
|
|
16
21
|
.int()
|
|
17
22
|
.min(1)
|
|
18
23
|
.max(30)
|
|
19
24
|
.default(1)
|
|
20
|
-
.describe('The number of days to get the tasks for, starting from the start date.'),
|
|
25
|
+
.describe('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.'),
|
|
21
26
|
limit: z
|
|
22
27
|
.number()
|
|
23
28
|
.int()
|
|
@@ -36,14 +41,22 @@ const findTasksByDate = {
|
|
|
36
41
|
description: "Get tasks by date range. Use startDate 'today' to get today's tasks including overdue items, or provide a specific date/date range.",
|
|
37
42
|
parameters: ArgsSchema,
|
|
38
43
|
async execute(args, client) {
|
|
44
|
+
if (!args.startDate && args.overdueOption !== 'overdue-only') {
|
|
45
|
+
throw new Error('Either startDate must be provided or overdueOption must be set to overdue-only');
|
|
46
|
+
}
|
|
39
47
|
let query = '';
|
|
40
48
|
const todoistUser = await client.getUser();
|
|
41
|
-
if (args.
|
|
42
|
-
query = '
|
|
49
|
+
if (args.overdueOption === 'overdue-only') {
|
|
50
|
+
query = 'overdue';
|
|
43
51
|
}
|
|
44
|
-
else {
|
|
52
|
+
else if (args.startDate === 'today') {
|
|
53
|
+
// For 'today', include overdue unless explicitly excluded
|
|
54
|
+
query = args.overdueOption === 'exclude-overdue' ? 'today' : 'today | overdue';
|
|
55
|
+
}
|
|
56
|
+
else if (args.startDate) {
|
|
57
|
+
// For specific dates, never include overdue tasks
|
|
45
58
|
const startDate = args.startDate;
|
|
46
|
-
const endDate = addDays(startDate, args.daysCount
|
|
59
|
+
const endDate = addDays(startDate, args.daysCount);
|
|
47
60
|
const endDateStr = formatISO(endDate, { representation: 'date' });
|
|
48
61
|
query = `(due after: ${startDate} | due: ${startDate}) & due before: ${endDateStr}`;
|
|
49
62
|
}
|
|
@@ -87,11 +100,18 @@ const findTasksByDate = {
|
|
|
87
100
|
function generateTextContent({ tasks, args, nextCursor, }) {
|
|
88
101
|
// Generate filter description
|
|
89
102
|
const filterHints = [];
|
|
90
|
-
if (args.
|
|
91
|
-
filterHints.push(
|
|
103
|
+
if (args.overdueOption === 'overdue-only') {
|
|
104
|
+
filterHints.push('overdue tasks only');
|
|
92
105
|
}
|
|
93
|
-
else {
|
|
94
|
-
|
|
106
|
+
else if (args.startDate === 'today') {
|
|
107
|
+
const overdueText = args.overdueOption === 'exclude-overdue' ? '' : ' + overdue tasks';
|
|
108
|
+
filterHints.push(`today${overdueText}${args.daysCount > 1 ? ` + ${args.daysCount - 1} more days` : ''}`);
|
|
109
|
+
}
|
|
110
|
+
else if (args.startDate) {
|
|
111
|
+
const dateRange = args.daysCount > 1
|
|
112
|
+
? ` to ${getDateString(addDays(args.startDate, args.daysCount))}`
|
|
113
|
+
: '';
|
|
114
|
+
filterHints.push(`${args.startDate}${dateRange}`);
|
|
95
115
|
}
|
|
96
116
|
// Add label filter information
|
|
97
117
|
if (args.labels && args.labels.length > 0) {
|
|
@@ -101,12 +121,29 @@ function generateTextContent({ tasks, args, nextCursor, }) {
|
|
|
101
121
|
filterHints.push(`labels: ${labelText}`);
|
|
102
122
|
}
|
|
103
123
|
// Generate subject description
|
|
104
|
-
|
|
124
|
+
let subject = '';
|
|
125
|
+
if (args.overdueOption === 'overdue-only') {
|
|
126
|
+
subject = 'Overdue tasks';
|
|
127
|
+
}
|
|
128
|
+
else if (args.startDate === 'today') {
|
|
129
|
+
subject =
|
|
130
|
+
args.overdueOption === 'exclude-overdue' ? `Today's tasks` : `Today's tasks + overdue`;
|
|
131
|
+
}
|
|
132
|
+
else if (args.startDate) {
|
|
133
|
+
subject = `Tasks for ${args.startDate}`;
|
|
134
|
+
}
|
|
135
|
+
else {
|
|
136
|
+
subject = 'Tasks';
|
|
137
|
+
}
|
|
105
138
|
// Generate helpful suggestions for empty results
|
|
106
139
|
const zeroReasonHints = [];
|
|
107
140
|
if (tasks.length === 0) {
|
|
108
|
-
if (args.
|
|
109
|
-
zeroReasonHints.push('Great job! No tasks
|
|
141
|
+
if (args.overdueOption === 'overdue-only') {
|
|
142
|
+
zeroReasonHints.push('Great job! No overdue tasks');
|
|
143
|
+
}
|
|
144
|
+
else if (args.startDate === 'today') {
|
|
145
|
+
const overdueNote = args.overdueOption === 'exclude-overdue' ? '' : ' or overdue';
|
|
146
|
+
zeroReasonHints.push(`Great job! No tasks for today${overdueNote}`);
|
|
110
147
|
}
|
|
111
148
|
else {
|
|
112
149
|
zeroReasonHints.push("Expand date range with larger 'daysCount'");
|
|
@@ -116,10 +153,12 @@ function generateTextContent({ tasks, args, nextCursor, }) {
|
|
|
116
153
|
// Generate contextual next steps
|
|
117
154
|
const now = new Date();
|
|
118
155
|
const todayStr = getDateString(now);
|
|
156
|
+
const hasOverdue = args.overdueOption === 'overdue-only' ||
|
|
157
|
+
args.startDate === 'today' ||
|
|
158
|
+
tasks.some((task) => task.dueDate && new Date(task.dueDate) < now);
|
|
119
159
|
const nextSteps = generateTaskNextSteps('listed', tasks, {
|
|
120
160
|
hasToday: args.startDate === 'today' || tasks.some((task) => task.dueDate === todayStr),
|
|
121
|
-
hasOverdue
|
|
122
|
-
tasks.some((task) => task.dueDate && new Date(task.dueDate) < now),
|
|
161
|
+
hasOverdue,
|
|
123
162
|
});
|
|
124
163
|
return summarizeList({
|
|
125
164
|
subject,
|