@doist/todoist-ai 4.7.0 → 4.8.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/mcp-server.js +2 -2
- package/dist/tools/__tests__/add-tasks.test.js +1 -3
- package/dist/tools/__tests__/complete-tasks.test.js +1 -1
- package/dist/tools/__tests__/find-tasks-by-date.test.js +12 -68
- package/dist/tools/complete-tasks.js +1 -1
- package/dist/tools/find-tasks-by-date.d.ts.map +1 -1
- package/dist/tools/find-tasks-by-date.js +14 -24
- package/dist/utils/priorities.d.ts +2 -1
- package/dist/utils/priorities.d.ts.map +1 -1
- package/dist/utils/priorities.js +5 -0
- package/dist/utils/response-builders.d.ts.map +1 -1
- package/dist/utils/response-builders.js +4 -3
- package/package.json +2 -2
package/dist/mcp-server.js
CHANGED
|
@@ -40,7 +40,7 @@ You have access to comprehensive Todoist management tools for personal productiv
|
|
|
40
40
|
- **update-tasks**: Modify existing tasks - get task IDs from search results first, only include fields that need changes
|
|
41
41
|
- **complete-tasks**: Mark tasks as done using task IDs
|
|
42
42
|
- **find-tasks**: Search by text, project/section/parent container, responsible user, or labels. Requires at least one search parameter
|
|
43
|
-
- **find-tasks-by-date**: Get tasks by date range (startDate: YYYY-MM-DD
|
|
43
|
+
- **find-tasks-by-date**: Get tasks by date range (startDate: YYYY-MM-DD or 'today' which includes overdue tasks) or specific day counts
|
|
44
44
|
- **find-completed-tasks**: View completed tasks by completion date or original due date
|
|
45
45
|
|
|
46
46
|
**Project & Organization:**
|
|
@@ -67,7 +67,7 @@ You have access to comprehensive Todoist management tools for personal productiv
|
|
|
67
67
|
|
|
68
68
|
4. **Bulk Operations**: When working with multiple items, prefer bulk tools (complete-tasks, manage-assignments) over individual operations for better performance.
|
|
69
69
|
|
|
70
|
-
5. **Date Handling**: All dates respect user timezone settings. Use 'today'
|
|
70
|
+
5. **Date Handling**: All dates respect user timezone settings. Use 'today' keyword for dynamic date filtering (includes overdue tasks).
|
|
71
71
|
|
|
72
72
|
6. **Labels**: Use label filtering with AND/OR operators for advanced task organization. Most search tools support labels parameter.
|
|
73
73
|
|
|
@@ -249,9 +249,7 @@ describe(`${ADD_TASKS} tool`, () => {
|
|
|
249
249
|
// Verify structured content includes labels
|
|
250
250
|
const structuredContent = extractStructuredContent(result);
|
|
251
251
|
expect(structuredContent.tasks).toHaveLength(1);
|
|
252
|
-
expect(structuredContent.tasks
|
|
253
|
-
labels: ['urgent', 'work'],
|
|
254
|
-
}));
|
|
252
|
+
expect(structuredContent.tasks).toEqual(expect.arrayContaining([expect.objectContaining({ labels: ['urgent', 'work'] })]));
|
|
255
253
|
});
|
|
256
254
|
it('should add task with empty labels array', async () => {
|
|
257
255
|
const mockApiResponse = createMockTask({
|
|
@@ -139,7 +139,7 @@ describe(`${COMPLETE_TASKS} tool`, () => {
|
|
|
139
139
|
const result = await completeTasks.execute({ ids: ['task-1', 'task-2'] }, mockTodoistApi);
|
|
140
140
|
const textContent = extractTextContent(result);
|
|
141
141
|
expect(textContent).toMatchSnapshot();
|
|
142
|
-
expect(textContent).toContain("Use find-tasks-by-date('
|
|
142
|
+
expect(textContent).toContain("Use find-tasks-by-date('today')");
|
|
143
143
|
});
|
|
144
144
|
it('should suggest reviewing failures when mixed results', async () => {
|
|
145
145
|
mockTodoistApi.closeTask
|
|
@@ -36,55 +36,15 @@ describe(`${FIND_TASKS_BY_DATE} tool`, () => {
|
|
|
36
36
|
afterEach(() => {
|
|
37
37
|
jest.restoreAllMocks();
|
|
38
38
|
});
|
|
39
|
-
describe('listing overdue tasks', () => {
|
|
40
|
-
it.each([
|
|
41
|
-
{ daysCount: 7, hasTasks: true, description: 'with tasks' },
|
|
42
|
-
{ daysCount: 5, hasTasks: false, description: 'ignoring daysCount' },
|
|
43
|
-
])('should handle overdue tasks $description', async ({ daysCount, hasTasks }) => {
|
|
44
|
-
const mockTasks = hasTasks
|
|
45
|
-
? [
|
|
46
|
-
createMappedTask({
|
|
47
|
-
id: TEST_IDS.TASK_1,
|
|
48
|
-
content: 'Overdue task',
|
|
49
|
-
dueDate: '2025-08-10',
|
|
50
|
-
priority: 2,
|
|
51
|
-
labels: ['urgent'],
|
|
52
|
-
}),
|
|
53
|
-
]
|
|
54
|
-
: [];
|
|
55
|
-
const mockResponse = { tasks: mockTasks, nextCursor: null };
|
|
56
|
-
mockGetTasksByFilter.mockResolvedValue(mockResponse);
|
|
57
|
-
const result = await findTasksByDate.execute({ startDate: 'overdue', limit: 50, daysCount }, mockTodoistApi);
|
|
58
|
-
expect(mockGetTasksByFilter).toHaveBeenCalledWith({
|
|
59
|
-
client: mockTodoistApi,
|
|
60
|
-
query: 'overdue',
|
|
61
|
-
cursor: undefined,
|
|
62
|
-
limit: 50,
|
|
63
|
-
});
|
|
64
|
-
// Verify result is a concise summary
|
|
65
|
-
expect(extractTextContent(result)).toMatchSnapshot();
|
|
66
|
-
// Verify structured content
|
|
67
|
-
const structuredContent = extractStructuredContent(result);
|
|
68
|
-
expect(structuredContent.tasks).toHaveLength(hasTasks ? 1 : 0);
|
|
69
|
-
expect(structuredContent).toEqual(expect.objectContaining({
|
|
70
|
-
totalCount: hasTasks ? 1 : 0,
|
|
71
|
-
hasMore: false,
|
|
72
|
-
nextCursor: null,
|
|
73
|
-
appliedFilters: expect.objectContaining({
|
|
74
|
-
startDate: 'overdue',
|
|
75
|
-
}),
|
|
76
|
-
}));
|
|
77
|
-
});
|
|
78
|
-
});
|
|
79
39
|
describe('listing tasks by date range', () => {
|
|
80
|
-
it('should get tasks for today when startDate is "today"', async () => {
|
|
40
|
+
it('should get tasks for today when startDate is "today" (includes overdue)', async () => {
|
|
81
41
|
const mockTasks = [createMappedTask({ content: 'Today task', dueDate: '2025-08-15' })];
|
|
82
42
|
const mockResponse = { tasks: mockTasks, nextCursor: null };
|
|
83
43
|
mockGetTasksByFilter.mockResolvedValue(mockResponse);
|
|
84
44
|
const result = await findTasksByDate.execute({ startDate: 'today', limit: 50, daysCount: 7 }, mockTodoistApi);
|
|
85
45
|
expect(mockGetTasksByFilter).toHaveBeenCalledWith({
|
|
86
46
|
client: mockTodoistApi,
|
|
87
|
-
query:
|
|
47
|
+
query: 'today | overdue',
|
|
88
48
|
cursor: undefined,
|
|
89
49
|
limit: 50,
|
|
90
50
|
});
|
|
@@ -217,29 +177,13 @@ describe(`${FIND_TASKS_BY_DATE} tool`, () => {
|
|
|
217
177
|
expect(textContent).toMatchSnapshot();
|
|
218
178
|
expect(textContent).toContain(`Use ${UPDATE_TASKS} to modify priorities or due dates`);
|
|
219
179
|
});
|
|
220
|
-
it('should
|
|
221
|
-
const mockTasks = [
|
|
222
|
-
createMappedTask({
|
|
223
|
-
id: TEST_IDS.TASK_1,
|
|
224
|
-
content: 'Overdue task',
|
|
225
|
-
dueDate: '2025-08-10',
|
|
226
|
-
}),
|
|
227
|
-
];
|
|
228
|
-
const mockResponse = { tasks: mockTasks, nextCursor: null };
|
|
229
|
-
mockGetTasksByFilter.mockResolvedValue(mockResponse);
|
|
230
|
-
const result = await findTasksByDate.execute({ startDate: 'overdue', limit: 10, daysCount: 1 }, mockTodoistApi);
|
|
231
|
-
const textContent = extractTextContent(result);
|
|
232
|
-
expect(textContent).toMatchSnapshot();
|
|
233
|
-
expect(textContent).toContain(`Use ${UPDATE_TASKS} to modify priorities or due dates`);
|
|
234
|
-
});
|
|
235
|
-
it('should provide helpful suggestions for empty overdue results', async () => {
|
|
180
|
+
it('should provide helpful suggestions for empty today results', async () => {
|
|
236
181
|
const mockResponse = { tasks: [], nextCursor: null };
|
|
237
182
|
mockGetTasksByFilter.mockResolvedValue(mockResponse);
|
|
238
|
-
const result = await findTasksByDate.execute({ startDate: '
|
|
183
|
+
const result = await findTasksByDate.execute({ startDate: 'today', limit: 10, daysCount: 1 }, mockTodoistApi);
|
|
239
184
|
const textContent = extractTextContent(result);
|
|
240
185
|
expect(textContent).toMatchSnapshot();
|
|
241
|
-
expect(textContent).toContain('Great job! No overdue
|
|
242
|
-
expect(textContent).toContain("Check today's tasks with startDate='today'");
|
|
186
|
+
expect(textContent).toContain('Great job! No tasks for today or overdue');
|
|
243
187
|
});
|
|
244
188
|
it('should provide helpful suggestions for empty date range results', async () => {
|
|
245
189
|
const mockResponse = { tasks: [], nextCursor: null };
|
|
@@ -252,7 +196,7 @@ describe(`${FIND_TASKS_BY_DATE} tool`, () => {
|
|
|
252
196
|
const textContent = extractTextContent(result);
|
|
253
197
|
expect(textContent).toMatchSnapshot();
|
|
254
198
|
expect(textContent).toContain("Expand date range with larger 'daysCount'");
|
|
255
|
-
expect(textContent).toContain("Check '
|
|
199
|
+
expect(textContent).toContain("Check today's tasks with startDate='today'");
|
|
256
200
|
});
|
|
257
201
|
});
|
|
258
202
|
describe('label filtering', () => {
|
|
@@ -265,18 +209,18 @@ describe(`${FIND_TASKS_BY_DATE} tool`, () => {
|
|
|
265
209
|
limit: 50,
|
|
266
210
|
labels: ['work'],
|
|
267
211
|
},
|
|
268
|
-
expectedQueryPattern: '((@work))', // Will be combined with date query
|
|
212
|
+
expectedQueryPattern: 'today | overdue & ((@work))', // Will be combined with date query
|
|
269
213
|
},
|
|
270
214
|
{
|
|
271
215
|
name: 'multiple labels with AND operator',
|
|
272
216
|
params: {
|
|
273
|
-
startDate: '
|
|
217
|
+
startDate: 'today',
|
|
274
218
|
daysCount: 1,
|
|
275
219
|
limit: 50,
|
|
276
220
|
labels: ['work', 'urgent'],
|
|
277
221
|
labelsOperator: 'and',
|
|
278
222
|
},
|
|
279
|
-
expectedQueryPattern: 'overdue & ((@work & @urgent))',
|
|
223
|
+
expectedQueryPattern: 'today | overdue & ((@work & @urgent))',
|
|
280
224
|
},
|
|
281
225
|
{
|
|
282
226
|
name: 'multiple labels with OR operator',
|
|
@@ -307,8 +251,8 @@ describe(`${FIND_TASKS_BY_DATE} tool`, () => {
|
|
|
307
251
|
cursor: undefined,
|
|
308
252
|
limit: 50,
|
|
309
253
|
});
|
|
310
|
-
// For
|
|
311
|
-
if (params.startDate === '
|
|
254
|
+
// For today specifically, check the exact pattern
|
|
255
|
+
if (params.startDate === 'today') {
|
|
312
256
|
expect(mockGetTasksByFilter).toHaveBeenCalledWith({
|
|
313
257
|
client: mockTodoistApi,
|
|
314
258
|
query: expectedQueryPattern,
|
|
@@ -374,7 +318,7 @@ describe(`${FIND_TASKS_BY_DATE} tool`, () => {
|
|
|
374
318
|
},
|
|
375
319
|
{
|
|
376
320
|
error: TEST_ERRORS.API_RATE_LIMIT,
|
|
377
|
-
params: { startDate: '
|
|
321
|
+
params: { startDate: 'today', limit: 50, daysCount: 7 },
|
|
378
322
|
},
|
|
379
323
|
{
|
|
380
324
|
error: TEST_ERRORS.INVALID_CURSOR,
|
|
@@ -45,7 +45,7 @@ const completeTasks = {
|
|
|
45
45
|
function generateNextSteps(completed, failures) {
|
|
46
46
|
if (completed > 0) {
|
|
47
47
|
const moveResult = failures === 0
|
|
48
|
-
? "Use find-tasks-by-date('
|
|
48
|
+
? "Use find-tasks-by-date('today') to tackle remaining overdue items."
|
|
49
49
|
: 'Review failed completions and retry if needed.';
|
|
50
50
|
return [moveResult];
|
|
51
51
|
}
|
|
@@ -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;AA0CvB,QAAA,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAiDqB,CAAA;AAoE1C,OAAO,EAAE,eAAe,EAAE,CAAA"}
|
|
@@ -9,15 +9,15 @@ import { ToolNames } from '../utils/tool-names.js';
|
|
|
9
9
|
const ArgsSchema = {
|
|
10
10
|
startDate: z
|
|
11
11
|
.string()
|
|
12
|
-
.regex(/^(\d{4}-\d{2}-\d{2}|today
|
|
13
|
-
.describe("The start date to get the tasks for. Format: YYYY-MM-DD
|
|
12
|
+
.regex(/^(\d{4}-\d{2}-\d{2}|today)$/)
|
|
13
|
+
.describe("The start date to get the tasks for. Format: YYYY-MM-DD or 'today'."),
|
|
14
14
|
daysCount: z
|
|
15
15
|
.number()
|
|
16
16
|
.int()
|
|
17
17
|
.min(1)
|
|
18
18
|
.max(30)
|
|
19
19
|
.default(1)
|
|
20
|
-
.describe(
|
|
20
|
+
.describe('The number of days to get the tasks for, starting from the start date.'),
|
|
21
21
|
limit: z
|
|
22
22
|
.number()
|
|
23
23
|
.int()
|
|
@@ -33,17 +33,15 @@ const ArgsSchema = {
|
|
|
33
33
|
};
|
|
34
34
|
const findTasksByDate = {
|
|
35
35
|
name: ToolNames.FIND_TASKS_BY_DATE,
|
|
36
|
-
description: "Get tasks by date range
|
|
36
|
+
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
37
|
parameters: ArgsSchema,
|
|
38
38
|
async execute(args, client) {
|
|
39
39
|
let query = '';
|
|
40
|
-
if (args.startDate === '
|
|
41
|
-
query = 'overdue';
|
|
40
|
+
if (args.startDate === 'today') {
|
|
41
|
+
query = 'today | overdue';
|
|
42
42
|
}
|
|
43
43
|
else {
|
|
44
|
-
const startDate = args.startDate
|
|
45
|
-
? formatISO(new Date(), { representation: 'date' })
|
|
46
|
-
: args.startDate;
|
|
44
|
+
const startDate = args.startDate;
|
|
47
45
|
const endDate = addDays(startDate, args.daysCount + 1);
|
|
48
46
|
const endDateStr = formatISO(endDate, { representation: 'date' });
|
|
49
47
|
query = `(due after: ${startDate} | due: ${startDate}) & due before: ${endDateStr}`;
|
|
@@ -82,11 +80,8 @@ const findTasksByDate = {
|
|
|
82
80
|
function generateTextContent({ tasks, args, nextCursor, }) {
|
|
83
81
|
// Generate filter description
|
|
84
82
|
const filterHints = [];
|
|
85
|
-
if (args.startDate === '
|
|
86
|
-
filterHints.push(
|
|
87
|
-
}
|
|
88
|
-
else if (args.startDate === 'today') {
|
|
89
|
-
filterHints.push(`today${args.daysCount > 1 ? ` + ${args.daysCount - 1} more days` : ''}`);
|
|
83
|
+
if (args.startDate === 'today') {
|
|
84
|
+
filterHints.push(`today + overdue tasks${args.daysCount > 1 ? ` + ${args.daysCount - 1} more days` : ''}`);
|
|
90
85
|
}
|
|
91
86
|
else {
|
|
92
87
|
filterHints.push(`${args.startDate}${args.daysCount > 1 ? ` to ${getDateString(addDays(args.startDate, args.daysCount))}` : ''}`);
|
|
@@ -99,21 +94,16 @@ function generateTextContent({ tasks, args, nextCursor, }) {
|
|
|
99
94
|
filterHints.push(`labels: ${labelText}`);
|
|
100
95
|
}
|
|
101
96
|
// Generate subject description
|
|
102
|
-
const subject = args.startDate === 'overdue
|
|
103
|
-
? 'Overdue tasks'
|
|
104
|
-
: args.startDate === 'today'
|
|
105
|
-
? `Today's tasks`
|
|
106
|
-
: `Tasks for ${args.startDate}`;
|
|
97
|
+
const subject = args.startDate === 'today' ? `Today's tasks + overdue` : `Tasks for ${args.startDate}`;
|
|
107
98
|
// Generate helpful suggestions for empty results
|
|
108
99
|
const zeroReasonHints = [];
|
|
109
100
|
if (tasks.length === 0) {
|
|
110
|
-
if (args.startDate === '
|
|
111
|
-
zeroReasonHints.push('Great job! No overdue
|
|
112
|
-
zeroReasonHints.push("Check today's tasks with startDate='today'");
|
|
101
|
+
if (args.startDate === 'today') {
|
|
102
|
+
zeroReasonHints.push('Great job! No tasks for today or overdue');
|
|
113
103
|
}
|
|
114
104
|
else {
|
|
115
105
|
zeroReasonHints.push("Expand date range with larger 'daysCount'");
|
|
116
|
-
zeroReasonHints.push("Check '
|
|
106
|
+
zeroReasonHints.push("Check today's tasks with startDate='today'");
|
|
117
107
|
}
|
|
118
108
|
}
|
|
119
109
|
// Generate contextual next steps
|
|
@@ -121,7 +111,7 @@ function generateTextContent({ tasks, args, nextCursor, }) {
|
|
|
121
111
|
const todayStr = getDateString(now);
|
|
122
112
|
const nextSteps = generateTaskNextSteps('listed', tasks, {
|
|
123
113
|
hasToday: args.startDate === 'today' || tasks.some((task) => task.dueDate === todayStr),
|
|
124
|
-
hasOverdue: args.startDate === '
|
|
114
|
+
hasOverdue: args.startDate === 'today' ||
|
|
125
115
|
tasks.some((task) => task.dueDate && new Date(task.dueDate) < now),
|
|
126
116
|
});
|
|
127
117
|
return summarizeList({
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
declare const PRIORITY_VALUES: readonly ["p1", "p2", "p3", "p4"];
|
|
3
|
-
type Priority = (typeof PRIORITY_VALUES)[number];
|
|
3
|
+
export type Priority = (typeof PRIORITY_VALUES)[number];
|
|
4
4
|
export declare const PrioritySchema: z.ZodEnum<["p1", "p2", "p3", "p4"]>;
|
|
5
5
|
export declare function convertPriorityToNumber(priority: Priority): number;
|
|
6
6
|
export declare function convertNumberToPriority(priority: number): Priority | undefined;
|
|
7
|
+
export declare function formatPriorityForDisplay(priority: number): string;
|
|
7
8
|
export {};
|
|
8
9
|
//# sourceMappingURL=priorities.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"priorities.d.ts","sourceRoot":"","sources":["../../src/utils/priorities.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAEvB,QAAA,MAAM,eAAe,mCAAoC,CAAA;AACzD,
|
|
1
|
+
{"version":3,"file":"priorities.d.ts","sourceRoot":"","sources":["../../src/utils/priorities.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAEvB,QAAA,MAAM,eAAe,mCAAoC,CAAA;AACzD,MAAM,MAAM,QAAQ,GAAG,CAAC,OAAO,eAAe,CAAC,CAAC,MAAM,CAAC,CAAA;AAEvD,eAAO,MAAM,cAAc,qCAEzB,CAAA;AAEF,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,QAAQ,GAAG,MAAM,CAIlE;AAED,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS,CAI9E;AAED,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAIjE"}
|
package/dist/utils/priorities.js
CHANGED
|
@@ -13,3 +13,8 @@ export function convertNumberToPriority(priority) {
|
|
|
13
13
|
const numberMap = { 4: 'p1', 3: 'p2', 2: 'p3', 1: 'p4' };
|
|
14
14
|
return numberMap[priority];
|
|
15
15
|
}
|
|
16
|
+
export function formatPriorityForDisplay(priority) {
|
|
17
|
+
// Convert Todoist API numbers to display format (P1, P2, P3, P4)
|
|
18
|
+
const displayMap = { 4: 'P1', 3: 'P2', 2: 'P3', 1: 'P4' };
|
|
19
|
+
return displayMap[priority] || '';
|
|
20
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"response-builders.d.ts","sourceRoot":"","sources":["../../src/utils/response-builders.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"response-builders.d.ts","sourceRoot":"","sources":["../../src/utils/response-builders.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { DisplayLimits } from './constants.js';
|
|
2
|
+
import { formatPriorityForDisplay } from './priorities.js';
|
|
2
3
|
import { ToolNames } from './tool-names.js';
|
|
3
4
|
/**
|
|
4
5
|
* Helper function to get date string in YYYY-MM-DD format
|
|
@@ -68,7 +69,7 @@ export function summarizeBatch(params) {
|
|
|
68
69
|
function formatTaskPreview(task) {
|
|
69
70
|
const content = task.content || task.title || 'Untitled';
|
|
70
71
|
const due = task.dueDate ? ` • due ${task.dueDate}` : '';
|
|
71
|
-
const priority = task.priority
|
|
72
|
+
const priority = task.priority ? ` • ${formatPriorityForDisplay(task.priority)}` : '';
|
|
72
73
|
const project = task.projectName ? ` • ${task.projectName}` : '';
|
|
73
74
|
const id = task.id ? ` • id=${task.id}` : '';
|
|
74
75
|
return ` ${content}${due}${priority}${project}${id}`;
|
|
@@ -147,7 +148,7 @@ export function generateTaskNextSteps(operation, tasks, context) {
|
|
|
147
148
|
nextSteps.push(`Use ${FIND_TASKS_BY_DATE}('today') to review today's updated schedule`);
|
|
148
149
|
}
|
|
149
150
|
else if (context?.hasOverdue) {
|
|
150
|
-
nextSteps.push(`Use ${FIND_TASKS_BY_DATE}('
|
|
151
|
+
nextSteps.push(`Use ${FIND_TASKS_BY_DATE}('today') to prioritize past-due items`);
|
|
151
152
|
}
|
|
152
153
|
else if (context?.projectName) {
|
|
153
154
|
nextSteps.push(`Use ${GET_OVERVIEW} with projectId to see ${context.projectName} structure`);
|
|
@@ -177,7 +178,7 @@ export function generateTaskNextSteps(operation, tasks, context) {
|
|
|
177
178
|
nextSteps.push(`Use ${FIND_TASKS_BY_DATE}('tomorrow') to plan upcoming work`);
|
|
178
179
|
}
|
|
179
180
|
else if (context?.hasOverdue) {
|
|
180
|
-
nextSteps.push(`Use ${FIND_TASKS_BY_DATE}('
|
|
181
|
+
nextSteps.push(`Use ${FIND_TASKS_BY_DATE}('today') to tackle remaining past-due items`);
|
|
181
182
|
}
|
|
182
183
|
else {
|
|
183
184
|
nextSteps.push(`Use ${FIND_TASKS_BY_DATE}('today') to see remaining work`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@doist/todoist-ai",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.8.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
"build": "rimraf dist && npx tsc --project tsconfig.json",
|
|
32
32
|
"postbuild": "chmod +x dist/main.js",
|
|
33
33
|
"start": "npm run build && npx @modelcontextprotocol/inspector node dist/main.js",
|
|
34
|
-
"dev": "concurrently \"npx tsc --watch\" \"nodemon --watch dist --ext js --exec
|
|
34
|
+
"dev": "concurrently \"npx tsc --watch\" \"npx @modelcontextprotocol/inspector npx nodemon --quiet --watch dist --ext js --exec node dist/main.js\"",
|
|
35
35
|
"setup": "cp .env.example .env && npm install && npm run build",
|
|
36
36
|
"test:executable": "npm run build && node scripts/test-executable.cjs",
|
|
37
37
|
"type-check": "npx tsc --noEmit",
|