@doist/todoist-ai 4.1.0 → 4.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +405 -50
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +26 -16
- package/dist/mcp-helpers.d.ts.map +1 -1
- package/dist/mcp-helpers.js +1 -1
- package/dist/mcp-server.d.ts.map +1 -1
- package/dist/mcp-server.js +80 -17
- package/dist/tool-helpers.d.ts +4 -0
- package/dist/tool-helpers.d.ts.map +1 -1
- package/dist/tool-helpers.js +2 -0
- package/dist/tools/__tests__/add-projects.test.js +1 -1
- package/dist/tools/__tests__/add-sections.test.js +1 -1
- package/dist/tools/__tests__/add-tasks.test.js +52 -13
- package/dist/tools/__tests__/assignment-integration.test.d.ts +2 -0
- package/dist/tools/__tests__/assignment-integration.test.d.ts.map +1 -0
- package/dist/tools/__tests__/assignment-integration.test.js +415 -0
- package/dist/tools/__tests__/find-completed-tasks.test.js +136 -2
- package/dist/tools/__tests__/find-projects.test.js +1 -1
- package/dist/tools/__tests__/find-sections.test.js +1 -1
- package/dist/tools/__tests__/find-tasks-by-date.test.js +122 -3
- package/dist/tools/__tests__/find-tasks.test.js +258 -11
- package/dist/tools/__tests__/get-overview.test.js +1 -1
- package/dist/tools/__tests__/update-sections.test.js +1 -0
- package/dist/tools/__tests__/update-tasks.test.js +6 -6
- package/dist/tools/__tests__/user-info.test.d.ts +2 -0
- package/dist/tools/__tests__/user-info.test.d.ts.map +1 -0
- package/dist/tools/__tests__/user-info.test.js +139 -0
- package/dist/tools/add-comments.d.ts +28 -5
- package/dist/tools/add-comments.d.ts.map +1 -1
- package/dist/tools/add-comments.js +1 -1
- package/dist/tools/add-projects.d.ts +46 -2
- package/dist/tools/add-projects.d.ts.map +1 -1
- package/dist/tools/add-projects.js +1 -1
- package/dist/tools/add-sections.d.ts +14 -2
- package/dist/tools/add-sections.d.ts.map +1 -1
- package/dist/tools/add-sections.js +1 -1
- package/dist/tools/add-tasks.d.ts +16 -10
- package/dist/tools/add-tasks.d.ts.map +1 -1
- package/dist/tools/add-tasks.js +49 -3
- package/dist/tools/find-comments.d.ts +27 -4
- package/dist/tools/find-comments.d.ts.map +1 -1
- package/dist/tools/find-completed-tasks.d.ts +12 -4
- package/dist/tools/find-completed-tasks.d.ts.map +1 -1
- package/dist/tools/find-completed-tasks.js +20 -4
- package/dist/tools/find-project-collaborators.d.ts +64 -0
- package/dist/tools/find-project-collaborators.d.ts.map +1 -0
- package/dist/tools/find-project-collaborators.js +151 -0
- package/dist/tools/find-tasks-by-date.d.ts +8 -0
- package/dist/tools/find-tasks-by-date.d.ts.map +1 -1
- package/dist/tools/find-tasks-by-date.js +19 -2
- package/dist/tools/find-tasks.d.ts +13 -2
- package/dist/tools/find-tasks.d.ts.map +1 -1
- package/dist/tools/find-tasks.js +172 -23
- package/dist/tools/get-overview.d.ts +2 -2
- package/dist/tools/get-overview.d.ts.map +1 -1
- package/dist/tools/get-overview.js +1 -1
- package/dist/tools/manage-assignments.d.ts +52 -0
- package/dist/tools/manage-assignments.d.ts.map +1 -0
- package/dist/tools/manage-assignments.js +337 -0
- package/dist/tools/update-comments.d.ts +25 -2
- package/dist/tools/update-comments.d.ts.map +1 -1
- package/dist/tools/update-comments.js +1 -1
- package/dist/tools/update-projects.d.ts +46 -2
- package/dist/tools/update-projects.d.ts.map +1 -1
- package/dist/tools/update-sections.d.ts +14 -2
- package/dist/tools/update-sections.d.ts.map +1 -1
- package/dist/tools/update-sections.js +1 -1
- package/dist/tools/update-tasks.d.ts +16 -10
- package/dist/tools/update-tasks.d.ts.map +1 -1
- package/dist/tools/update-tasks.js +32 -9
- package/dist/tools/user-info.d.ts +44 -0
- package/dist/tools/user-info.d.ts.map +1 -0
- package/dist/tools/user-info.js +142 -0
- package/dist/utils/assignment-validator.d.ts +69 -0
- package/dist/utils/assignment-validator.d.ts.map +1 -0
- package/dist/utils/assignment-validator.js +253 -0
- package/dist/utils/duration-parser.d.ts +2 -2
- package/dist/utils/duration-parser.d.ts.map +1 -1
- package/dist/utils/labels.d.ts +10 -0
- package/dist/utils/labels.d.ts.map +1 -0
- package/dist/utils/labels.js +18 -0
- package/dist/utils/priorities.d.ts +8 -0
- package/dist/utils/priorities.d.ts.map +1 -0
- package/dist/utils/priorities.js +15 -0
- package/dist/utils/response-builders.d.ts +2 -2
- package/dist/utils/response-builders.d.ts.map +1 -1
- package/dist/utils/response-builders.js +8 -1
- package/dist/utils/test-helpers.d.ts +2 -0
- package/dist/utils/test-helpers.d.ts.map +1 -1
- package/dist/utils/test-helpers.js +3 -0
- package/dist/utils/tool-names.d.ts +3 -0
- package/dist/utils/tool-names.d.ts.map +1 -1
- package/dist/utils/tool-names.js +4 -0
- package/dist/utils/user-resolver.d.ts +39 -0
- package/dist/utils/user-resolver.d.ts.map +1 -0
- package/dist/utils/user-resolver.js +179 -0
- package/package.json +7 -7
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import { jest } from '@jest/globals';
|
|
2
|
+
import { extractStructuredContent, extractTextContent, TEST_ERRORS, } from '../../utils/test-helpers.js';
|
|
3
|
+
import { ToolNames } from '../../utils/tool-names.js';
|
|
4
|
+
import { userInfo } from '../user-info.js';
|
|
5
|
+
// Mock the Todoist API
|
|
6
|
+
const mockTodoistApi = {
|
|
7
|
+
getUser: jest.fn(),
|
|
8
|
+
};
|
|
9
|
+
const { USER_INFO } = ToolNames;
|
|
10
|
+
// Helper function to create a mock user with default values that can be overridden
|
|
11
|
+
function createMockUser(overrides = {}) {
|
|
12
|
+
return {
|
|
13
|
+
id: '123',
|
|
14
|
+
fullName: 'Test User',
|
|
15
|
+
email: 'test@example.com',
|
|
16
|
+
isPremium: true,
|
|
17
|
+
completedToday: 12,
|
|
18
|
+
dailyGoal: 10,
|
|
19
|
+
weeklyGoal: 100,
|
|
20
|
+
startDay: 1, // Monday
|
|
21
|
+
tzInfo: {
|
|
22
|
+
timezone: 'Europe/Madrid',
|
|
23
|
+
gmtString: '+02:00',
|
|
24
|
+
hours: 2,
|
|
25
|
+
minutes: 0,
|
|
26
|
+
isDst: 1,
|
|
27
|
+
},
|
|
28
|
+
lang: 'en',
|
|
29
|
+
avatarBig: 'https://example.com/avatar.jpg',
|
|
30
|
+
avatarMedium: null,
|
|
31
|
+
avatarS640: null,
|
|
32
|
+
avatarSmall: null,
|
|
33
|
+
karma: 86394.0,
|
|
34
|
+
karmaTrend: 'up',
|
|
35
|
+
nextWeek: 1,
|
|
36
|
+
weekendStartDay: 6,
|
|
37
|
+
timeFormat: 0,
|
|
38
|
+
dateFormat: 0,
|
|
39
|
+
daysOff: [6, 7],
|
|
40
|
+
businessAccountId: null,
|
|
41
|
+
completedCount: 102920,
|
|
42
|
+
inboxProjectId: '6PVw8cMf7m8fWwRp',
|
|
43
|
+
startPage: 'overdue',
|
|
44
|
+
...overrides,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
describe(`${USER_INFO} tool`, () => {
|
|
48
|
+
beforeEach(() => {
|
|
49
|
+
jest.clearAllMocks();
|
|
50
|
+
});
|
|
51
|
+
it('should generate user info with all required fields', async () => {
|
|
52
|
+
const mockUser = createMockUser();
|
|
53
|
+
mockTodoistApi.getUser.mockResolvedValue(mockUser);
|
|
54
|
+
const result = await userInfo.execute({}, mockTodoistApi);
|
|
55
|
+
expect(mockTodoistApi.getUser).toHaveBeenCalledWith();
|
|
56
|
+
// Test text content contains expected information
|
|
57
|
+
const textContent = extractTextContent(result);
|
|
58
|
+
expect(textContent).toContain('User ID:** 123');
|
|
59
|
+
expect(textContent).toContain('Test User');
|
|
60
|
+
expect(textContent).toContain('test@example.com');
|
|
61
|
+
expect(textContent).toContain('Europe/Madrid');
|
|
62
|
+
expect(textContent).toContain('Monday (1)');
|
|
63
|
+
expect(textContent).toContain('Completed Today:** 12');
|
|
64
|
+
expect(textContent).toContain('Plan:** Todoist Pro');
|
|
65
|
+
// Test structured content
|
|
66
|
+
const structuredContent = extractStructuredContent(result);
|
|
67
|
+
expect(structuredContent).toEqual(expect.objectContaining({
|
|
68
|
+
type: 'user_info',
|
|
69
|
+
userId: '123',
|
|
70
|
+
fullName: 'Test User',
|
|
71
|
+
email: 'test@example.com',
|
|
72
|
+
timezone: 'Europe/Madrid',
|
|
73
|
+
startDay: 1,
|
|
74
|
+
startDayName: 'Monday',
|
|
75
|
+
completedToday: 12,
|
|
76
|
+
dailyGoal: 10,
|
|
77
|
+
weeklyGoal: 100,
|
|
78
|
+
plan: 'Todoist Pro',
|
|
79
|
+
currentLocalTime: expect.any(String),
|
|
80
|
+
weekStartDate: expect.any(String),
|
|
81
|
+
weekEndDate: expect.any(String),
|
|
82
|
+
currentWeekNumber: expect.any(Number),
|
|
83
|
+
}));
|
|
84
|
+
// Verify date formats
|
|
85
|
+
expect(structuredContent.weekStartDate).toMatch(/^\d{4}-\d{2}-\d{2}$/);
|
|
86
|
+
expect(structuredContent.weekEndDate).toMatch(/^\d{4}-\d{2}-\d{2}$/);
|
|
87
|
+
expect(structuredContent.currentLocalTime).toMatch(/^\d{2}\/\d{2}\/\d{4}, \d{2}:\d{2}:\d{2}$/);
|
|
88
|
+
});
|
|
89
|
+
it('should handle missing timezone info', async () => {
|
|
90
|
+
const mockUser = createMockUser({
|
|
91
|
+
isPremium: false,
|
|
92
|
+
tzInfo: {
|
|
93
|
+
timezone: 'UTC',
|
|
94
|
+
gmtString: '+00:00',
|
|
95
|
+
hours: 0,
|
|
96
|
+
minutes: 0,
|
|
97
|
+
isDst: 0,
|
|
98
|
+
},
|
|
99
|
+
});
|
|
100
|
+
mockTodoistApi.getUser.mockResolvedValue(mockUser);
|
|
101
|
+
const result = await userInfo.execute({}, mockTodoistApi);
|
|
102
|
+
const textContent = extractTextContent(result);
|
|
103
|
+
expect(textContent).toContain('UTC'); // Should default to UTC
|
|
104
|
+
expect(textContent).toContain('Monday (1)'); // Should default to Monday
|
|
105
|
+
expect(textContent).toContain('Plan:** Todoist Free');
|
|
106
|
+
const structuredContent = extractStructuredContent(result);
|
|
107
|
+
expect(structuredContent.timezone).toBe('UTC');
|
|
108
|
+
expect(structuredContent.startDay).toBe(1);
|
|
109
|
+
expect(structuredContent.startDayName).toBe('Monday');
|
|
110
|
+
expect(structuredContent.plan).toBe('Todoist Free');
|
|
111
|
+
});
|
|
112
|
+
it('should handle invalid timezone and fallback to UTC', async () => {
|
|
113
|
+
const mockUser = createMockUser({
|
|
114
|
+
startDay: 2, // Tuesday
|
|
115
|
+
tzInfo: {
|
|
116
|
+
timezone: 'Invalid/Timezone',
|
|
117
|
+
gmtString: '+05:30',
|
|
118
|
+
hours: 5,
|
|
119
|
+
minutes: 30,
|
|
120
|
+
isDst: 0,
|
|
121
|
+
},
|
|
122
|
+
});
|
|
123
|
+
mockTodoistApi.getUser.mockResolvedValue(mockUser);
|
|
124
|
+
const result = await userInfo.execute({}, mockTodoistApi);
|
|
125
|
+
const textContent = extractTextContent(result);
|
|
126
|
+
expect(textContent).toContain('UTC'); // Should fallback to UTC
|
|
127
|
+
expect(textContent).toContain('Tuesday (2)');
|
|
128
|
+
const structuredContent = extractStructuredContent(result);
|
|
129
|
+
expect(structuredContent.timezone).toBe('UTC'); // Should be UTC, not the invalid timezone
|
|
130
|
+
expect(structuredContent.startDay).toBe(2);
|
|
131
|
+
expect(structuredContent.startDayName).toBe('Tuesday');
|
|
132
|
+
expect(structuredContent.currentLocalTime).toMatch(/^\d{2}\/\d{2}\/\d{4}, \d{2}:\d{2}:\d{2}$/);
|
|
133
|
+
});
|
|
134
|
+
it('should propagate API errors', async () => {
|
|
135
|
+
const apiError = new Error(TEST_ERRORS.API_UNAUTHORIZED);
|
|
136
|
+
mockTodoistApi.getUser.mockRejectedValue(apiError);
|
|
137
|
+
await expect(userInfo.execute({}, mockTodoistApi)).rejects.toThrow(TEST_ERRORS.API_UNAUTHORIZED);
|
|
138
|
+
});
|
|
139
|
+
});
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import type { Comment } from '@doist/todoist-api-typescript';
|
|
2
1
|
import { z } from 'zod';
|
|
3
2
|
declare const addComments: {
|
|
4
3
|
name: "add-comments";
|
|
@@ -10,19 +9,19 @@ declare const addComments: {
|
|
|
10
9
|
content: z.ZodString;
|
|
11
10
|
}, "strip", z.ZodTypeAny, {
|
|
12
11
|
content: string;
|
|
13
|
-
projectId?: string | undefined;
|
|
14
12
|
taskId?: string | undefined;
|
|
13
|
+
projectId?: string | undefined;
|
|
15
14
|
}, {
|
|
16
15
|
content: string;
|
|
17
|
-
projectId?: string | undefined;
|
|
18
16
|
taskId?: string | undefined;
|
|
17
|
+
projectId?: string | undefined;
|
|
19
18
|
}>, "many">;
|
|
20
19
|
};
|
|
21
20
|
execute(args: {
|
|
22
21
|
comments: {
|
|
23
22
|
content: string;
|
|
24
|
-
projectId?: string | undefined;
|
|
25
23
|
taskId?: string | undefined;
|
|
24
|
+
projectId?: string | undefined;
|
|
26
25
|
}[];
|
|
27
26
|
}, client: import("@doist/todoist-api-typescript").TodoistApi): Promise<{
|
|
28
27
|
content: {
|
|
@@ -30,7 +29,31 @@ declare const addComments: {
|
|
|
30
29
|
text: string;
|
|
31
30
|
}[];
|
|
32
31
|
structuredContent: {
|
|
33
|
-
comments:
|
|
32
|
+
comments: {
|
|
33
|
+
taskId: string | undefined;
|
|
34
|
+
id: string;
|
|
35
|
+
content: string;
|
|
36
|
+
postedAt: string;
|
|
37
|
+
fileAttachment: {
|
|
38
|
+
resourceType: string;
|
|
39
|
+
fileName?: string | null | undefined;
|
|
40
|
+
fileSize?: number | null | undefined;
|
|
41
|
+
fileType?: string | null | undefined;
|
|
42
|
+
fileUrl?: string | null | undefined;
|
|
43
|
+
fileDuration?: number | null | undefined;
|
|
44
|
+
uploadState?: "pending" | "completed" | null | undefined;
|
|
45
|
+
image?: string | null | undefined;
|
|
46
|
+
imageWidth?: number | null | undefined;
|
|
47
|
+
imageHeight?: number | null | undefined;
|
|
48
|
+
url?: string | null | undefined;
|
|
49
|
+
title?: string | null | undefined;
|
|
50
|
+
} | null;
|
|
51
|
+
postedUid: string;
|
|
52
|
+
uidsToNotify: string[] | null;
|
|
53
|
+
reactions: Record<string, string[]> | null;
|
|
54
|
+
isDeleted: boolean;
|
|
55
|
+
projectId?: string | undefined;
|
|
56
|
+
}[];
|
|
34
57
|
totalCount: number;
|
|
35
58
|
addedCommentIds: string[];
|
|
36
59
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"add-comments.d.ts","sourceRoot":"","sources":["../../src/tools/add-comments.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"add-comments.d.ts","sourceRoot":"","sources":["../../src/tools/add-comments.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAkBvB,QAAA,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4BAoFygV,CAAC;4BAA6C,CAAC;4BAA6C,CAAC;2BAA4C,CAAC;gCAAiD,CAAC;+BAAgD,CAAC;yBAA2D,CAAC;8BAA+C,CAAC;+BAAgD,CAAC;uBAAwC,CAAC;yBAA0C,CAAC;;;;;;;;;;;;;;;;;;;;;;;CA1C98V,CAAA;AAyC1C,OAAO,EAAE,WAAW,EAAE,CAAA"}
|
|
@@ -42,7 +42,7 @@ const addComments = {
|
|
|
42
42
|
});
|
|
43
43
|
},
|
|
44
44
|
};
|
|
45
|
-
function generateTextContent({ comments
|
|
45
|
+
function generateTextContent({ comments }) {
|
|
46
46
|
// Group comments by entity type and count
|
|
47
47
|
const taskComments = comments.filter((c) => c.taskId).length;
|
|
48
48
|
const projectComments = comments.filter((c) => c.projectId).length;
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import type { PersonalProject, WorkspaceProject } from '@doist/todoist-api-typescript';
|
|
2
1
|
import { z } from 'zod';
|
|
3
2
|
declare const addProjects: {
|
|
4
3
|
name: "add-projects";
|
|
@@ -30,7 +29,52 @@ declare const addProjects: {
|
|
|
30
29
|
text: string;
|
|
31
30
|
}[];
|
|
32
31
|
structuredContent: {
|
|
33
|
-
projects: (
|
|
32
|
+
projects: ({
|
|
33
|
+
url: string;
|
|
34
|
+
id: string;
|
|
35
|
+
canAssignTasks: boolean;
|
|
36
|
+
childOrder: number;
|
|
37
|
+
color: string;
|
|
38
|
+
createdAt: string | null;
|
|
39
|
+
isArchived: boolean;
|
|
40
|
+
isDeleted: boolean;
|
|
41
|
+
isFavorite: boolean;
|
|
42
|
+
isFrozen: boolean;
|
|
43
|
+
name: string;
|
|
44
|
+
updatedAt: string | null;
|
|
45
|
+
viewStyle: string;
|
|
46
|
+
defaultOrder: number;
|
|
47
|
+
description: string;
|
|
48
|
+
isCollapsed: boolean;
|
|
49
|
+
isShared: boolean;
|
|
50
|
+
parentId: string | null;
|
|
51
|
+
inboxProject: boolean;
|
|
52
|
+
} | {
|
|
53
|
+
url: string;
|
|
54
|
+
id: string;
|
|
55
|
+
canAssignTasks: boolean;
|
|
56
|
+
childOrder: number;
|
|
57
|
+
color: string;
|
|
58
|
+
createdAt: string | null;
|
|
59
|
+
isArchived: boolean;
|
|
60
|
+
isDeleted: boolean;
|
|
61
|
+
isFavorite: boolean;
|
|
62
|
+
isFrozen: boolean;
|
|
63
|
+
name: string;
|
|
64
|
+
updatedAt: string | null;
|
|
65
|
+
viewStyle: string;
|
|
66
|
+
defaultOrder: number;
|
|
67
|
+
description: string;
|
|
68
|
+
isCollapsed: boolean;
|
|
69
|
+
isShared: boolean;
|
|
70
|
+
collaboratorRoleDefault: string;
|
|
71
|
+
folderId: string | null;
|
|
72
|
+
isInviteOnly: boolean | null;
|
|
73
|
+
isLinkSharingEnabled: boolean;
|
|
74
|
+
role: string | null;
|
|
75
|
+
status: string;
|
|
76
|
+
workspaceId: string;
|
|
77
|
+
})[];
|
|
34
78
|
totalCount: number;
|
|
35
79
|
};
|
|
36
80
|
} | {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"add-projects.d.ts","sourceRoot":"","sources":["../../src/tools/add-projects.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"add-projects.d.ts","sourceRoot":"","sources":["../../src/tools/add-projects.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAwBvB,QAAA,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAgByB,CAAA;AA+B1C,OAAO,EAAE,WAAW,EAAE,CAAA"}
|
|
@@ -33,7 +33,7 @@ const addProjects = {
|
|
|
33
33
|
});
|
|
34
34
|
},
|
|
35
35
|
};
|
|
36
|
-
function generateTextContent({ projects
|
|
36
|
+
function generateTextContent({ projects }) {
|
|
37
37
|
const count = projects.length;
|
|
38
38
|
const projectList = projects.map((project) => `• ${project.name} (id=${project.id})`).join('\n');
|
|
39
39
|
const summary = `Added ${count} project${count === 1 ? '' : 's'}:\n${projectList}`;
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import type { Section } from '@doist/todoist-api-typescript';
|
|
2
1
|
import { z } from 'zod';
|
|
3
2
|
declare const addSections: {
|
|
4
3
|
name: "add-sections";
|
|
@@ -26,7 +25,20 @@ declare const addSections: {
|
|
|
26
25
|
text: string;
|
|
27
26
|
}[];
|
|
28
27
|
structuredContent: {
|
|
29
|
-
sections:
|
|
28
|
+
sections: {
|
|
29
|
+
url: string;
|
|
30
|
+
id: string;
|
|
31
|
+
userId: string;
|
|
32
|
+
projectId: string;
|
|
33
|
+
addedAt: string;
|
|
34
|
+
updatedAt: string;
|
|
35
|
+
archivedAt: string | null;
|
|
36
|
+
name: string;
|
|
37
|
+
sectionOrder: number;
|
|
38
|
+
isArchived: boolean;
|
|
39
|
+
isDeleted: boolean;
|
|
40
|
+
isCollapsed: boolean;
|
|
41
|
+
}[];
|
|
30
42
|
totalCount: number;
|
|
31
43
|
};
|
|
32
44
|
} | {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"add-sections.d.ts","sourceRoot":"","sources":["../../src/tools/add-sections.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"add-sections.d.ts","sourceRoot":"","sources":["../../src/tools/add-sections.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAiBvB,QAAA,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAgByB,CAAA;AA6C1C,OAAO,EAAE,WAAW,EAAE,CAAA"}
|
|
@@ -26,7 +26,7 @@ const addSections = {
|
|
|
26
26
|
});
|
|
27
27
|
},
|
|
28
28
|
};
|
|
29
|
-
function generateTextContent({ sections
|
|
29
|
+
function generateTextContent({ sections }) {
|
|
30
30
|
const count = sections.length;
|
|
31
31
|
const sectionList = sections
|
|
32
32
|
.map((section) => `• ${section.name} (id=${section.id}, projectId=${section.projectId})`)
|
|
@@ -7,42 +7,46 @@ declare const addTasks: {
|
|
|
7
7
|
tasks: z.ZodArray<z.ZodObject<{
|
|
8
8
|
content: z.ZodString;
|
|
9
9
|
description: z.ZodOptional<z.ZodString>;
|
|
10
|
-
priority: z.ZodOptional<z.
|
|
10
|
+
priority: z.ZodOptional<z.ZodEnum<["p1", "p2", "p3", "p4"]>>;
|
|
11
11
|
dueString: z.ZodOptional<z.ZodString>;
|
|
12
12
|
duration: z.ZodOptional<z.ZodString>;
|
|
13
13
|
projectId: z.ZodOptional<z.ZodString>;
|
|
14
14
|
sectionId: z.ZodOptional<z.ZodString>;
|
|
15
15
|
parentId: z.ZodOptional<z.ZodString>;
|
|
16
|
+
responsibleUser: z.ZodOptional<z.ZodString>;
|
|
16
17
|
}, "strip", z.ZodTypeAny, {
|
|
17
18
|
content: string;
|
|
18
19
|
description?: string | undefined;
|
|
19
|
-
parentId?: string | undefined;
|
|
20
20
|
projectId?: string | undefined;
|
|
21
|
+
parentId?: string | undefined;
|
|
21
22
|
sectionId?: string | undefined;
|
|
22
|
-
priority?: number | undefined;
|
|
23
|
-
dueString?: string | undefined;
|
|
24
23
|
duration?: string | undefined;
|
|
24
|
+
priority?: "p1" | "p2" | "p3" | "p4" | undefined;
|
|
25
|
+
dueString?: string | undefined;
|
|
26
|
+
responsibleUser?: string | undefined;
|
|
25
27
|
}, {
|
|
26
28
|
content: string;
|
|
27
29
|
description?: string | undefined;
|
|
28
|
-
parentId?: string | undefined;
|
|
29
30
|
projectId?: string | undefined;
|
|
31
|
+
parentId?: string | undefined;
|
|
30
32
|
sectionId?: string | undefined;
|
|
31
|
-
priority?: number | undefined;
|
|
32
|
-
dueString?: string | undefined;
|
|
33
33
|
duration?: string | undefined;
|
|
34
|
+
priority?: "p1" | "p2" | "p3" | "p4" | undefined;
|
|
35
|
+
dueString?: string | undefined;
|
|
36
|
+
responsibleUser?: string | undefined;
|
|
34
37
|
}>, "many">;
|
|
35
38
|
};
|
|
36
39
|
execute({ tasks }: {
|
|
37
40
|
tasks: {
|
|
38
41
|
content: string;
|
|
39
42
|
description?: string | undefined;
|
|
40
|
-
parentId?: string | undefined;
|
|
41
43
|
projectId?: string | undefined;
|
|
44
|
+
parentId?: string | undefined;
|
|
42
45
|
sectionId?: string | undefined;
|
|
43
|
-
priority?: number | undefined;
|
|
44
|
-
dueString?: string | undefined;
|
|
45
46
|
duration?: string | undefined;
|
|
47
|
+
priority?: "p1" | "p2" | "p3" | "p4" | undefined;
|
|
48
|
+
dueString?: string | undefined;
|
|
49
|
+
responsibleUser?: string | undefined;
|
|
46
50
|
}[];
|
|
47
51
|
}, client: TodoistApi): Promise<{
|
|
48
52
|
content: {
|
|
@@ -62,6 +66,8 @@ declare const addTasks: {
|
|
|
62
66
|
parentId: string | null;
|
|
63
67
|
labels: string[];
|
|
64
68
|
duration: string | null;
|
|
69
|
+
responsibleUid: string | null;
|
|
70
|
+
assignedByUid: string | null;
|
|
65
71
|
}[];
|
|
66
72
|
totalCount: number;
|
|
67
73
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"add-tasks.d.ts","sourceRoot":"","sources":["../../src/tools/add-tasks.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAqB,UAAU,EAAE,MAAM,+BAA+B,CAAA;AAClF,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;
|
|
1
|
+
{"version":3,"file":"add-tasks.d.ts","sourceRoot":"","sources":["../../src/tools/add-tasks.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAqB,UAAU,EAAE,MAAM,+BAA+B,CAAA;AAClF,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AA0CvB,QAAA,MAAM,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAuB4B,CAAA;AA+H1C,OAAO,EAAE,QAAQ,EAAE,CAAA"}
|
package/dist/tools/add-tasks.js
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import { getToolOutput } from '../mcp-helpers.js';
|
|
3
3
|
import { mapTask } from '../tool-helpers.js';
|
|
4
|
+
import { assignmentValidator } from '../utils/assignment-validator.js';
|
|
4
5
|
import { DurationParseError, parseDuration } from '../utils/duration-parser.js';
|
|
6
|
+
import { convertPriorityToNumber, PrioritySchema } from '../utils/priorities.js';
|
|
5
7
|
import { generateTaskNextSteps, getDateString, summarizeTaskOperation, } from '../utils/response-builders.js';
|
|
6
8
|
import { ToolNames } from '../utils/tool-names.js';
|
|
7
9
|
const TaskSchema = z.object({
|
|
8
10
|
content: z.string().min(1).describe('The content of the task to create.'),
|
|
9
11
|
description: z.string().optional().describe('The description of the task.'),
|
|
10
|
-
priority:
|
|
12
|
+
priority: PrioritySchema.optional().describe('The priority of the task: p1 (highest), p2 (high), p3 (medium), p4 (lowest/default).'),
|
|
11
13
|
dueString: z.string().optional().describe('The due date for the task, in natural language.'),
|
|
12
14
|
duration: z
|
|
13
15
|
.string()
|
|
@@ -16,13 +18,17 @@ const TaskSchema = z.object({
|
|
|
16
18
|
projectId: z.string().optional().describe('The project ID to add this task to.'),
|
|
17
19
|
sectionId: z.string().optional().describe('The section ID to add this task to.'),
|
|
18
20
|
parentId: z.string().optional().describe('The parent task ID (for subtasks).'),
|
|
21
|
+
responsibleUser: z
|
|
22
|
+
.string()
|
|
23
|
+
.optional()
|
|
24
|
+
.describe('Assign task to this user. Can be a user ID, name, or email address. User must be a collaborator on the target project.'),
|
|
19
25
|
});
|
|
20
26
|
const ArgsSchema = {
|
|
21
27
|
tasks: z.array(TaskSchema).min(1).describe('The array of tasks to add.'),
|
|
22
28
|
};
|
|
23
29
|
const addTasks = {
|
|
24
30
|
name: ToolNames.ADD_TASKS,
|
|
25
|
-
description: 'Add one or more tasks to a project, section, or parent.',
|
|
31
|
+
description: 'Add one or more tasks to a project, section, or parent. Supports assignment to project collaborators.',
|
|
26
32
|
parameters: ArgsSchema,
|
|
27
33
|
async execute({ tasks }, client) {
|
|
28
34
|
const addTaskPromises = tasks.map((task) => processTask(task, client));
|
|
@@ -42,8 +48,16 @@ const addTasks = {
|
|
|
42
48
|
},
|
|
43
49
|
};
|
|
44
50
|
async function processTask(task, client) {
|
|
45
|
-
const { duration: durationStr, projectId, sectionId, parentId, ...otherTaskArgs } = task;
|
|
51
|
+
const { duration: durationStr, projectId, sectionId, parentId, responsibleUser, priority, ...otherTaskArgs } = task;
|
|
46
52
|
let taskArgs = { ...otherTaskArgs, projectId, sectionId, parentId };
|
|
53
|
+
// Handle priority conversion if provided
|
|
54
|
+
if (priority) {
|
|
55
|
+
taskArgs.priority = convertPriorityToNumber(priority);
|
|
56
|
+
}
|
|
57
|
+
// Prevent assignment to tasks without sufficient project context
|
|
58
|
+
if (!projectId && !sectionId && !parentId) {
|
|
59
|
+
throw new Error(`Task "${task.content}": Cannot assign tasks without specifying project context. Please specify a projectId, sectionId, or parentId.`);
|
|
60
|
+
}
|
|
47
61
|
// Parse duration if provided
|
|
48
62
|
if (durationStr) {
|
|
49
63
|
try {
|
|
@@ -61,6 +75,38 @@ async function processTask(task, client) {
|
|
|
61
75
|
throw error;
|
|
62
76
|
}
|
|
63
77
|
}
|
|
78
|
+
// Handle assignment if provided
|
|
79
|
+
if (responsibleUser) {
|
|
80
|
+
// Resolve target project for validation
|
|
81
|
+
let targetProjectId = projectId;
|
|
82
|
+
if (!targetProjectId && parentId) {
|
|
83
|
+
// For subtasks, get project from parent task
|
|
84
|
+
try {
|
|
85
|
+
const parentTask = await client.getTask(parentId);
|
|
86
|
+
targetProjectId = parentTask.projectId;
|
|
87
|
+
}
|
|
88
|
+
catch (_error) {
|
|
89
|
+
throw new Error(`Task "${task.content}": Parent task "${parentId}" not found`);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
else if (!targetProjectId && sectionId) {
|
|
93
|
+
// For section tasks, we need to find the project - this is a limitation
|
|
94
|
+
// For now, we'll require explicit projectId when using assignments with sections
|
|
95
|
+
throw new Error(`Task "${task.content}": When assigning tasks to sections, please also specify projectId`);
|
|
96
|
+
}
|
|
97
|
+
if (!targetProjectId) {
|
|
98
|
+
throw new Error(`Task "${task.content}": Cannot determine target project for assignment validation`);
|
|
99
|
+
}
|
|
100
|
+
// Validate assignment using comprehensive validator
|
|
101
|
+
const validation = await assignmentValidator.validateTaskCreationAssignment(client, targetProjectId, responsibleUser);
|
|
102
|
+
if (!validation.isValid) {
|
|
103
|
+
const errorMsg = validation.error?.message || 'Assignment validation failed';
|
|
104
|
+
const suggestions = validation.error?.suggestions?.join('. ') || '';
|
|
105
|
+
throw new Error(`Task "${task.content}": ${errorMsg}${suggestions ? `. ${suggestions}` : ''}`);
|
|
106
|
+
}
|
|
107
|
+
// Use the validated assignee ID
|
|
108
|
+
taskArgs.assigneeId = validation.resolvedUser?.userId;
|
|
109
|
+
}
|
|
64
110
|
return await client.addTask(taskArgs);
|
|
65
111
|
}
|
|
66
112
|
function generateTextContent({ tasks, args, }) {
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import type { Comment } from '@doist/todoist-api-typescript';
|
|
2
1
|
import { z } from 'zod';
|
|
3
2
|
declare const findComments: {
|
|
4
3
|
name: "find-comments";
|
|
@@ -11,10 +10,10 @@ declare const findComments: {
|
|
|
11
10
|
limit: z.ZodOptional<z.ZodNumber>;
|
|
12
11
|
};
|
|
13
12
|
execute(args: {
|
|
14
|
-
projectId?: string | undefined;
|
|
15
13
|
limit?: number | undefined;
|
|
16
|
-
cursor?: string | undefined;
|
|
17
14
|
taskId?: string | undefined;
|
|
15
|
+
projectId?: string | undefined;
|
|
16
|
+
cursor?: string | undefined;
|
|
18
17
|
commentId?: string | undefined;
|
|
19
18
|
}, client: import("@doist/todoist-api-typescript").TodoistApi): Promise<{
|
|
20
19
|
content: {
|
|
@@ -22,7 +21,31 @@ declare const findComments: {
|
|
|
22
21
|
text: string;
|
|
23
22
|
}[];
|
|
24
23
|
structuredContent: {
|
|
25
|
-
comments:
|
|
24
|
+
comments: {
|
|
25
|
+
taskId: string | undefined;
|
|
26
|
+
id: string;
|
|
27
|
+
content: string;
|
|
28
|
+
postedAt: string;
|
|
29
|
+
fileAttachment: {
|
|
30
|
+
resourceType: string;
|
|
31
|
+
fileName?: string | null | undefined;
|
|
32
|
+
fileSize?: number | null | undefined;
|
|
33
|
+
fileType?: string | null | undefined;
|
|
34
|
+
fileUrl?: string | null | undefined;
|
|
35
|
+
fileDuration?: number | null | undefined;
|
|
36
|
+
uploadState?: "pending" | "completed" | null | undefined;
|
|
37
|
+
image?: string | null | undefined;
|
|
38
|
+
imageWidth?: number | null | undefined;
|
|
39
|
+
imageHeight?: number | null | undefined;
|
|
40
|
+
url?: string | null | undefined;
|
|
41
|
+
title?: string | null | undefined;
|
|
42
|
+
} | null;
|
|
43
|
+
postedUid: string;
|
|
44
|
+
uidsToNotify: string[] | null;
|
|
45
|
+
reactions: Record<string, string[]> | null;
|
|
46
|
+
isDeleted: boolean;
|
|
47
|
+
projectId?: string | undefined;
|
|
48
|
+
}[];
|
|
26
49
|
searchType: string;
|
|
27
50
|
searchId: string;
|
|
28
51
|
hasMore: boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"find-comments.d.ts","sourceRoot":"","sources":["../../src/tools/find-comments.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"find-comments.d.ts","sourceRoot":"","sources":["../../src/tools/find-comments.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAuBvB,QAAA,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4BA2J++P,CAAC;4BAA6C,CAAC;4BAA6C,CAAC;2BAA4C,CAAC;gCAAiD,CAAC;+BAAgD,CAAC;yBAA2D,CAAC;8BAA+C,CAAC;+BAAgD,CAAC;uBAAwC,CAAC;yBAA0C,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;CArFr7Q,CAAA;AAoF1C,OAAO,EAAE,YAAY,EAAE,CAAA"}
|
|
@@ -3,6 +3,8 @@ declare const findCompletedTasks: {
|
|
|
3
3
|
name: "find-completed-tasks";
|
|
4
4
|
description: string;
|
|
5
5
|
parameters: {
|
|
6
|
+
labels: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
7
|
+
labelsOperator: z.ZodOptional<z.ZodEnum<["and", "or"]>>;
|
|
6
8
|
getBy: z.ZodDefault<z.ZodEnum<["completion", "due"]>>;
|
|
7
9
|
since: z.ZodString;
|
|
8
10
|
until: z.ZodString;
|
|
@@ -15,14 +17,16 @@ declare const findCompletedTasks: {
|
|
|
15
17
|
};
|
|
16
18
|
execute(args: {
|
|
17
19
|
limit: number;
|
|
18
|
-
getBy: "
|
|
20
|
+
getBy: "due" | "completion";
|
|
19
21
|
since: string;
|
|
20
22
|
until: string;
|
|
23
|
+
projectId?: string | undefined;
|
|
21
24
|
parentId?: string | undefined;
|
|
22
25
|
workspaceId?: string | undefined;
|
|
23
|
-
projectId?: string | undefined;
|
|
24
26
|
sectionId?: string | undefined;
|
|
27
|
+
labels?: string[] | undefined;
|
|
25
28
|
cursor?: string | undefined;
|
|
29
|
+
labelsOperator?: "and" | "or" | undefined;
|
|
26
30
|
}, client: import("@doist/todoist-api-typescript").TodoistApi): Promise<{
|
|
27
31
|
content: {
|
|
28
32
|
type: "text";
|
|
@@ -41,20 +45,24 @@ declare const findCompletedTasks: {
|
|
|
41
45
|
parentId: string | null;
|
|
42
46
|
labels: string[];
|
|
43
47
|
duration: string | null;
|
|
48
|
+
responsibleUid: string | null;
|
|
49
|
+
assignedByUid: string | null;
|
|
44
50
|
}[];
|
|
45
51
|
nextCursor: string | null;
|
|
46
52
|
totalCount: number;
|
|
47
53
|
hasMore: boolean;
|
|
48
54
|
appliedFilters: {
|
|
49
55
|
limit: number;
|
|
50
|
-
getBy: "
|
|
56
|
+
getBy: "due" | "completion";
|
|
51
57
|
since: string;
|
|
52
58
|
until: string;
|
|
59
|
+
projectId?: string | undefined;
|
|
53
60
|
parentId?: string | undefined;
|
|
54
61
|
workspaceId?: string | undefined;
|
|
55
|
-
projectId?: string | undefined;
|
|
56
62
|
sectionId?: string | undefined;
|
|
63
|
+
labels?: string[] | undefined;
|
|
57
64
|
cursor?: string | undefined;
|
|
65
|
+
labelsOperator?: "and" | "or" | undefined;
|
|
58
66
|
};
|
|
59
67
|
};
|
|
60
68
|
} | {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"find-completed-tasks.d.ts","sourceRoot":"","sources":["../../src/tools/find-completed-tasks.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;
|
|
1
|
+
{"version":3,"file":"find-completed-tasks.d.ts","sourceRoot":"","sources":["../../src/tools/find-completed-tasks.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAiDvB,QAAA,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAoCkB,CAAA;AAmE1C,OAAO,EAAE,kBAAkB,EAAE,CAAA"}
|