@doist/todoist-ai 4.15.1 → 4.16.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/filter-helpers.d.ts +1 -1
- package/dist/index.d.ts +175 -175
- package/dist/index.js +61 -81
- package/dist/main.js +15 -23
- package/dist/mcp-helpers.d.ts +4 -4
- package/dist/mcp-server-6tm7Rhyz.js +2840 -0
- package/dist/todoist-tool.d.ts +2 -2
- package/dist/tool-helpers.d.ts +1 -1
- package/dist/tools/add-comments.d.ts +1 -1
- package/dist/tools/add-comments.d.ts.map +1 -1
- package/dist/tools/add-projects.d.ts +4 -4
- package/dist/tools/add-projects.d.ts.map +1 -1
- package/dist/tools/add-sections.d.ts +1 -1
- package/dist/tools/add-sections.d.ts.map +1 -1
- package/dist/tools/add-tasks.d.ts +4 -4
- package/dist/tools/add-tasks.d.ts.map +1 -1
- package/dist/tools/complete-tasks.d.ts +1 -1
- package/dist/tools/complete-tasks.d.ts.map +1 -1
- package/dist/tools/delete-object.d.ts +3 -3
- package/dist/tools/delete-object.d.ts.map +1 -1
- package/dist/tools/fetch.d.ts +1 -1
- package/dist/tools/find-activity.d.ts +5 -5
- package/dist/tools/find-activity.d.ts.map +1 -1
- package/dist/tools/find-comments.d.ts +2 -2
- package/dist/tools/find-comments.d.ts.map +1 -1
- package/dist/tools/find-completed-tasks.d.ts +3 -3
- package/dist/tools/find-completed-tasks.d.ts.map +1 -1
- package/dist/tools/find-project-collaborators.d.ts +2 -2
- package/dist/tools/find-projects.d.ts +1 -1
- package/dist/tools/find-projects.d.ts.map +1 -1
- package/dist/tools/find-sections.d.ts +1 -1
- package/dist/tools/find-sections.d.ts.map +1 -1
- package/dist/tools/find-tasks-by-date.d.ts +1 -1
- package/dist/tools/find-tasks-by-date.d.ts.map +1 -1
- package/dist/tools/find-tasks.d.ts +3 -3
- package/dist/tools/find-tasks.d.ts.map +1 -1
- package/dist/tools/get-overview.d.ts +1 -1
- package/dist/tools/manage-assignments.d.ts +1 -1
- package/dist/tools/search.d.ts +1 -1
- package/dist/tools/update-comments.d.ts +4 -4
- package/dist/tools/update-comments.d.ts.map +1 -1
- package/dist/tools/update-projects.d.ts +1 -1
- package/dist/tools/update-projects.d.ts.map +1 -1
- package/dist/tools/update-sections.d.ts +4 -4
- package/dist/tools/update-sections.d.ts.map +1 -1
- package/dist/tools/update-tasks.d.ts +7 -7
- package/dist/tools/update-tasks.d.ts.map +1 -1
- package/dist/tools/user-info.d.ts +1 -1
- package/dist/utils/assignment-validator.d.ts +2 -2
- package/dist/utils/response-builders.d.ts +1 -3
- package/dist/utils/response-builders.d.ts.map +1 -1
- package/dist/utils/test-helpers.d.ts +1 -1
- package/dist/utils/user-resolver.d.ts +1 -1
- package/package.json +11 -9
- package/dist/filter-helpers.js +0 -79
- package/dist/mcp-helpers.js +0 -71
- package/dist/mcp-server.js +0 -142
- package/dist/todoist-tool.js +0 -1
- package/dist/tool-helpers.js +0 -125
- package/dist/tool-helpers.test.d.ts +0 -2
- package/dist/tool-helpers.test.d.ts.map +0 -1
- package/dist/tool-helpers.test.js +0 -223
- package/dist/tools/__tests__/add-comments.test.d.ts +0 -2
- package/dist/tools/__tests__/add-comments.test.d.ts.map +0 -1
- package/dist/tools/__tests__/add-comments.test.js +0 -241
- package/dist/tools/__tests__/add-projects.test.d.ts +0 -2
- package/dist/tools/__tests__/add-projects.test.d.ts.map +0 -1
- package/dist/tools/__tests__/add-projects.test.js +0 -174
- package/dist/tools/__tests__/add-sections.test.d.ts +0 -2
- package/dist/tools/__tests__/add-sections.test.d.ts.map +0 -1
- package/dist/tools/__tests__/add-sections.test.js +0 -185
- package/dist/tools/__tests__/add-tasks.test.d.ts +0 -2
- package/dist/tools/__tests__/add-tasks.test.d.ts.map +0 -1
- package/dist/tools/__tests__/add-tasks.test.js +0 -533
- package/dist/tools/__tests__/assignment-integration.test.d.ts +0 -2
- package/dist/tools/__tests__/assignment-integration.test.d.ts.map +0 -1
- package/dist/tools/__tests__/assignment-integration.test.js +0 -428
- package/dist/tools/__tests__/complete-tasks.test.d.ts +0 -2
- package/dist/tools/__tests__/complete-tasks.test.d.ts.map +0 -1
- package/dist/tools/__tests__/complete-tasks.test.js +0 -206
- package/dist/tools/__tests__/delete-object.test.d.ts +0 -2
- package/dist/tools/__tests__/delete-object.test.d.ts.map +0 -1
- package/dist/tools/__tests__/delete-object.test.js +0 -110
- package/dist/tools/__tests__/fetch.test.d.ts +0 -2
- package/dist/tools/__tests__/fetch.test.d.ts.map +0 -1
- package/dist/tools/__tests__/fetch.test.js +0 -279
- package/dist/tools/__tests__/find-activity.test.d.ts +0 -2
- package/dist/tools/__tests__/find-activity.test.d.ts.map +0 -1
- package/dist/tools/__tests__/find-activity.test.js +0 -229
- package/dist/tools/__tests__/find-comments.test.d.ts +0 -2
- package/dist/tools/__tests__/find-comments.test.d.ts.map +0 -1
- package/dist/tools/__tests__/find-comments.test.js +0 -236
- package/dist/tools/__tests__/find-completed-tasks.test.d.ts +0 -2
- package/dist/tools/__tests__/find-completed-tasks.test.d.ts.map +0 -1
- package/dist/tools/__tests__/find-completed-tasks.test.js +0 -324
- package/dist/tools/__tests__/find-projects.test.d.ts +0 -2
- package/dist/tools/__tests__/find-projects.test.d.ts.map +0 -1
- package/dist/tools/__tests__/find-projects.test.js +0 -154
- package/dist/tools/__tests__/find-sections.test.d.ts +0 -2
- package/dist/tools/__tests__/find-sections.test.d.ts.map +0 -1
- package/dist/tools/__tests__/find-sections.test.js +0 -245
- package/dist/tools/__tests__/find-tasks-by-date.test.d.ts +0 -2
- package/dist/tools/__tests__/find-tasks-by-date.test.d.ts.map +0 -1
- package/dist/tools/__tests__/find-tasks-by-date.test.js +0 -528
- package/dist/tools/__tests__/find-tasks.test.d.ts +0 -2
- package/dist/tools/__tests__/find-tasks.test.d.ts.map +0 -1
- package/dist/tools/__tests__/find-tasks.test.js +0 -771
- package/dist/tools/__tests__/get-overview.test.d.ts +0 -2
- package/dist/tools/__tests__/get-overview.test.d.ts.map +0 -1
- package/dist/tools/__tests__/get-overview.test.js +0 -225
- package/dist/tools/__tests__/search.test.d.ts +0 -2
- package/dist/tools/__tests__/search.test.d.ts.map +0 -1
- package/dist/tools/__tests__/search.test.js +0 -206
- package/dist/tools/__tests__/update-comments.test.d.ts +0 -2
- package/dist/tools/__tests__/update-comments.test.d.ts.map +0 -1
- package/dist/tools/__tests__/update-comments.test.js +0 -294
- package/dist/tools/__tests__/update-projects.test.d.ts +0 -2
- package/dist/tools/__tests__/update-projects.test.d.ts.map +0 -1
- package/dist/tools/__tests__/update-projects.test.js +0 -217
- package/dist/tools/__tests__/update-sections.test.d.ts +0 -2
- package/dist/tools/__tests__/update-sections.test.d.ts.map +0 -1
- package/dist/tools/__tests__/update-sections.test.js +0 -169
- package/dist/tools/__tests__/update-tasks.test.d.ts +0 -2
- package/dist/tools/__tests__/update-tasks.test.d.ts.map +0 -1
- package/dist/tools/__tests__/update-tasks.test.js +0 -788
- package/dist/tools/__tests__/user-info.test.d.ts +0 -2
- package/dist/tools/__tests__/user-info.test.d.ts.map +0 -1
- package/dist/tools/__tests__/user-info.test.js +0 -139
- package/dist/tools/add-comments.js +0 -79
- package/dist/tools/add-projects.js +0 -63
- package/dist/tools/add-sections.js +0 -61
- package/dist/tools/add-tasks.js +0 -160
- package/dist/tools/complete-tasks.js +0 -68
- package/dist/tools/delete-object.js +0 -79
- package/dist/tools/fetch.js +0 -102
- package/dist/tools/find-activity.js +0 -221
- package/dist/tools/find-comments.js +0 -143
- package/dist/tools/find-completed-tasks.js +0 -161
- package/dist/tools/find-project-collaborators.js +0 -151
- package/dist/tools/find-projects.js +0 -101
- package/dist/tools/find-sections.js +0 -96
- package/dist/tools/find-tasks-by-date.js +0 -198
- package/dist/tools/find-tasks.js +0 -329
- package/dist/tools/get-overview.js +0 -249
- package/dist/tools/manage-assignments.js +0 -337
- package/dist/tools/search.js +0 -65
- package/dist/tools/update-comments.js +0 -82
- package/dist/tools/update-projects.js +0 -84
- package/dist/tools/update-sections.js +0 -70
- package/dist/tools/update-tasks.js +0 -170
- package/dist/tools/user-info.js +0 -142
- package/dist/utils/assignment-validator.js +0 -253
- package/dist/utils/constants.js +0 -45
- package/dist/utils/duration-parser.js +0 -96
- package/dist/utils/duration-parser.test.d.ts +0 -2
- package/dist/utils/duration-parser.test.d.ts.map +0 -1
- package/dist/utils/duration-parser.test.js +0 -147
- package/dist/utils/labels.js +0 -18
- package/dist/utils/priorities.js +0 -20
- package/dist/utils/response-builders.js +0 -210
- package/dist/utils/sanitize-data.js +0 -37
- package/dist/utils/sanitize-data.test.d.ts +0 -2
- package/dist/utils/sanitize-data.test.d.ts.map +0 -1
- package/dist/utils/sanitize-data.test.js +0 -93
- package/dist/utils/test-helpers.js +0 -237
- package/dist/utils/tool-names.js +0 -40
- package/dist/utils/user-resolver.js +0 -179
|
@@ -1,237 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Creates a mock Task with all required properties and sensible defaults.
|
|
3
|
-
* Pass only the properties you want to override for your specific test.
|
|
4
|
-
*/
|
|
5
|
-
export function createMockTask(overrides = {}) {
|
|
6
|
-
return {
|
|
7
|
-
id: '8485093748',
|
|
8
|
-
content: 'Test task content',
|
|
9
|
-
description: '',
|
|
10
|
-
completedAt: null,
|
|
11
|
-
labels: [],
|
|
12
|
-
childOrder: 1,
|
|
13
|
-
priority: 1,
|
|
14
|
-
projectId: '6cfCcrrCFg2xP94Q',
|
|
15
|
-
sectionId: null,
|
|
16
|
-
parentId: null,
|
|
17
|
-
url: 'https://todoist.com/showTask?id=8485093748',
|
|
18
|
-
// Use correct property names from Task schema
|
|
19
|
-
noteCount: 0,
|
|
20
|
-
addedByUid: '713437',
|
|
21
|
-
addedAt: '2025-08-13T22:09:56.123456Z',
|
|
22
|
-
deadline: null,
|
|
23
|
-
responsibleUid: null,
|
|
24
|
-
assignedByUid: null,
|
|
25
|
-
isCollapsed: false,
|
|
26
|
-
isDeleted: false,
|
|
27
|
-
duration: null,
|
|
28
|
-
checked: false,
|
|
29
|
-
updatedAt: '2025-08-13T22:09:56.123456Z',
|
|
30
|
-
due: null,
|
|
31
|
-
dayOrder: 0,
|
|
32
|
-
userId: '713437',
|
|
33
|
-
...overrides,
|
|
34
|
-
};
|
|
35
|
-
}
|
|
36
|
-
/**
|
|
37
|
-
* Creates a mock Section with all required properties and sensible defaults.
|
|
38
|
-
* Pass only the properties you want to override for your specific test.
|
|
39
|
-
*/
|
|
40
|
-
export function createMockSection(overrides = {}) {
|
|
41
|
-
return {
|
|
42
|
-
id: 'section-123',
|
|
43
|
-
projectId: '6cfCcrrCFg2xP94Q',
|
|
44
|
-
sectionOrder: 1,
|
|
45
|
-
userId: 'test-user',
|
|
46
|
-
addedAt: '2024-01-01T00:00:00Z',
|
|
47
|
-
updatedAt: '2024-01-01T00:00:00Z',
|
|
48
|
-
archivedAt: null,
|
|
49
|
-
isArchived: false,
|
|
50
|
-
isDeleted: false,
|
|
51
|
-
isCollapsed: false,
|
|
52
|
-
name: 'Test Section',
|
|
53
|
-
url: 'https://todoist.com/sections/section-123',
|
|
54
|
-
...overrides,
|
|
55
|
-
};
|
|
56
|
-
}
|
|
57
|
-
/**
|
|
58
|
-
* Creates a mock PersonalProject with all required properties and sensible defaults.
|
|
59
|
-
* Pass only the properties you want to override for your specific test.
|
|
60
|
-
*/
|
|
61
|
-
export function createMockProject(overrides = {}) {
|
|
62
|
-
return {
|
|
63
|
-
id: '6cfCcrrCFg2xP94Q',
|
|
64
|
-
name: 'Test Project',
|
|
65
|
-
color: 'charcoal',
|
|
66
|
-
isFavorite: false,
|
|
67
|
-
isShared: false,
|
|
68
|
-
parentId: null,
|
|
69
|
-
inboxProject: false,
|
|
70
|
-
viewStyle: 'list',
|
|
71
|
-
url: 'https://todoist.com/projects/6cfCcrrCFg2xP94Q',
|
|
72
|
-
isDeleted: false,
|
|
73
|
-
updatedAt: '2025-08-13T22:09:55.841800Z',
|
|
74
|
-
createdAt: '2025-08-13T22:09:55.841785Z',
|
|
75
|
-
childOrder: 1,
|
|
76
|
-
defaultOrder: 0,
|
|
77
|
-
description: '',
|
|
78
|
-
isCollapsed: false,
|
|
79
|
-
canAssignTasks: false,
|
|
80
|
-
isFrozen: false,
|
|
81
|
-
isArchived: false,
|
|
82
|
-
...overrides,
|
|
83
|
-
};
|
|
84
|
-
}
|
|
85
|
-
/**
|
|
86
|
-
* Creates a mock API response object with results and nextCursor.
|
|
87
|
-
*/
|
|
88
|
-
export function createMockApiResponse(results, nextCursor = null) {
|
|
89
|
-
return {
|
|
90
|
-
results,
|
|
91
|
-
nextCursor,
|
|
92
|
-
};
|
|
93
|
-
}
|
|
94
|
-
/**
|
|
95
|
-
* Creates a simplified mapped task (matches mapTask output) for filter-based query tests.
|
|
96
|
-
*/
|
|
97
|
-
export function createMappedTask(overrides = {}) {
|
|
98
|
-
return {
|
|
99
|
-
id: TEST_IDS.TASK_1,
|
|
100
|
-
content: 'Test task content',
|
|
101
|
-
description: '',
|
|
102
|
-
dueDate: undefined,
|
|
103
|
-
recurring: false,
|
|
104
|
-
deadlineDate: undefined,
|
|
105
|
-
priority: 1,
|
|
106
|
-
projectId: TEST_IDS.PROJECT_TEST,
|
|
107
|
-
sectionId: null,
|
|
108
|
-
parentId: null,
|
|
109
|
-
labels: [],
|
|
110
|
-
duration: null,
|
|
111
|
-
responsibleUid: null,
|
|
112
|
-
assignedByUid: null,
|
|
113
|
-
checked: false,
|
|
114
|
-
completedAt: null,
|
|
115
|
-
...overrides,
|
|
116
|
-
};
|
|
117
|
-
}
|
|
118
|
-
/**
|
|
119
|
-
* Common error messages used across tests.
|
|
120
|
-
*/
|
|
121
|
-
export const TEST_ERRORS = {
|
|
122
|
-
API_RATE_LIMIT: 'API Error: Rate limit exceeded',
|
|
123
|
-
API_UNAUTHORIZED: 'API Error: Unauthorized',
|
|
124
|
-
INVALID_CURSOR: 'Invalid cursor format',
|
|
125
|
-
INVALID_FILTER: 'Invalid filter query',
|
|
126
|
-
};
|
|
127
|
-
/**
|
|
128
|
-
* Creates multiple test cases for parameterized testing.
|
|
129
|
-
*/
|
|
130
|
-
export function createTestCases(cases) {
|
|
131
|
-
return cases;
|
|
132
|
-
}
|
|
133
|
-
/**
|
|
134
|
-
* Extracts the text content from a tool output for snapshot testing.
|
|
135
|
-
* This allows tests to match against just the text content while tools return structured output.
|
|
136
|
-
*/
|
|
137
|
-
export function extractTextContent(toolOutput) {
|
|
138
|
-
if (typeof toolOutput === 'string') {
|
|
139
|
-
return toolOutput;
|
|
140
|
-
}
|
|
141
|
-
if (typeof toolOutput === 'object' && toolOutput !== null && 'content' in toolOutput) {
|
|
142
|
-
const output = toolOutput;
|
|
143
|
-
if (Array.isArray(output.content) &&
|
|
144
|
-
output.content[0] &&
|
|
145
|
-
typeof output.content[0] === 'object' &&
|
|
146
|
-
output.content[0] !== null &&
|
|
147
|
-
'type' in output.content[0] &&
|
|
148
|
-
'text' in output.content[0] &&
|
|
149
|
-
output.content[0].type === 'text') {
|
|
150
|
-
return output.content[0].text;
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
throw new Error('Expected tool output to have text content');
|
|
154
|
-
}
|
|
155
|
-
/**
|
|
156
|
-
* Extracts the structured content from a tool output for testing.
|
|
157
|
-
* This handles both the new `structuredContent` field and legacy JSON-encoded content.
|
|
158
|
-
*/
|
|
159
|
-
export function extractStructuredContent(output) {
|
|
160
|
-
// Check for new structuredContent field first
|
|
161
|
-
if ('structuredContent' in output && typeof output.structuredContent === 'object') {
|
|
162
|
-
return output.structuredContent;
|
|
163
|
-
}
|
|
164
|
-
// Fall back to checking for JSON content in the content array
|
|
165
|
-
if ('content' in output && Array.isArray(output.content)) {
|
|
166
|
-
for (const item of output.content) {
|
|
167
|
-
if (typeof item === 'object' &&
|
|
168
|
-
item !== null &&
|
|
169
|
-
'type' in item &&
|
|
170
|
-
'text' in item &&
|
|
171
|
-
item.type === 'text' &&
|
|
172
|
-
item.mimeType === 'application/json') {
|
|
173
|
-
return JSON.parse(item.text);
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
throw new Error('Expected tool output to have structured content');
|
|
178
|
-
}
|
|
179
|
-
/**
|
|
180
|
-
* Common mock IDs used across tests for consistency.
|
|
181
|
-
*/
|
|
182
|
-
export const TEST_IDS = {
|
|
183
|
-
TASK_1: '8485093748',
|
|
184
|
-
TASK_2: '8485093749',
|
|
185
|
-
TASK_3: '8485093750',
|
|
186
|
-
PROJECT_INBOX: 'inbox-project-id',
|
|
187
|
-
PROJECT_WORK: 'work-project-id',
|
|
188
|
-
PROJECT_TEST: '6cfCcrrCFg2xP94Q',
|
|
189
|
-
SECTION_1: 'section-123',
|
|
190
|
-
SECTION_2: 'section-456',
|
|
191
|
-
USER_ID: '713437',
|
|
192
|
-
};
|
|
193
|
-
/**
|
|
194
|
-
* Fixed date for consistent test snapshots.
|
|
195
|
-
* Use this instead of new Date() in tests to avoid snapshot drift.
|
|
196
|
-
*/
|
|
197
|
-
export const TODAY = '2025-08-17';
|
|
198
|
-
/**
|
|
199
|
-
* Creates a mock CurrentUser with all required properties and sensible defaults.
|
|
200
|
-
* Pass only the properties you want to override for your specific test.
|
|
201
|
-
*/
|
|
202
|
-
export function createMockUser(overrides = {}) {
|
|
203
|
-
return {
|
|
204
|
-
id: TEST_IDS.USER_ID,
|
|
205
|
-
email: 'test@example.com',
|
|
206
|
-
fullName: 'Test User',
|
|
207
|
-
businessAccountId: null,
|
|
208
|
-
isPremium: false,
|
|
209
|
-
dateFormat: 0,
|
|
210
|
-
timeFormat: 0,
|
|
211
|
-
weeklyGoal: 5,
|
|
212
|
-
dailyGoal: 5,
|
|
213
|
-
completedCount: 0,
|
|
214
|
-
completedToday: 0,
|
|
215
|
-
daysOff: [],
|
|
216
|
-
inboxProjectId: TEST_IDS.PROJECT_INBOX,
|
|
217
|
-
karma: 0,
|
|
218
|
-
karmaTrend: 'up',
|
|
219
|
-
lang: 'en',
|
|
220
|
-
nextWeek: 1,
|
|
221
|
-
startDay: 1,
|
|
222
|
-
startPage: 'today',
|
|
223
|
-
weekendStartDay: 6,
|
|
224
|
-
tzInfo: {
|
|
225
|
-
timezone: 'UTC',
|
|
226
|
-
gmtString: '+00:00',
|
|
227
|
-
hours: 0,
|
|
228
|
-
minutes: 0,
|
|
229
|
-
isDst: 0,
|
|
230
|
-
},
|
|
231
|
-
avatarBig: null,
|
|
232
|
-
avatarMedium: null,
|
|
233
|
-
avatarS640: null,
|
|
234
|
-
avatarSmall: null,
|
|
235
|
-
...overrides,
|
|
236
|
-
};
|
|
237
|
-
}
|
package/dist/utils/tool-names.js
DELETED
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Centralized tool names module
|
|
3
|
-
*
|
|
4
|
-
* This module provides a single source of truth for all tool names used throughout the codebase.
|
|
5
|
-
* Each tool should import its own name from this module to avoid hardcoded strings.
|
|
6
|
-
* This prevents outdated references when tool names change.
|
|
7
|
-
*/
|
|
8
|
-
export const ToolNames = {
|
|
9
|
-
// Task management tools
|
|
10
|
-
ADD_TASKS: 'add-tasks',
|
|
11
|
-
COMPLETE_TASKS: 'complete-tasks',
|
|
12
|
-
UPDATE_TASKS: 'update-tasks',
|
|
13
|
-
FIND_TASKS: 'find-tasks',
|
|
14
|
-
FIND_TASKS_BY_DATE: 'find-tasks-by-date',
|
|
15
|
-
FIND_COMPLETED_TASKS: 'find-completed-tasks',
|
|
16
|
-
// Project management tools
|
|
17
|
-
ADD_PROJECTS: 'add-projects',
|
|
18
|
-
UPDATE_PROJECTS: 'update-projects',
|
|
19
|
-
FIND_PROJECTS: 'find-projects',
|
|
20
|
-
// Section management tools
|
|
21
|
-
ADD_SECTIONS: 'add-sections',
|
|
22
|
-
UPDATE_SECTIONS: 'update-sections',
|
|
23
|
-
FIND_SECTIONS: 'find-sections',
|
|
24
|
-
// Comment management tools
|
|
25
|
-
ADD_COMMENTS: 'add-comments',
|
|
26
|
-
UPDATE_COMMENTS: 'update-comments',
|
|
27
|
-
FIND_COMMENTS: 'find-comments',
|
|
28
|
-
// Assignment and collaboration tools
|
|
29
|
-
FIND_PROJECT_COLLABORATORS: 'find-project-collaborators',
|
|
30
|
-
MANAGE_ASSIGNMENTS: 'manage-assignments',
|
|
31
|
-
// Activity and audit tools
|
|
32
|
-
FIND_ACTIVITY: 'find-activity',
|
|
33
|
-
// General tools
|
|
34
|
-
GET_OVERVIEW: 'get-overview',
|
|
35
|
-
DELETE_OBJECT: 'delete-object',
|
|
36
|
-
USER_INFO: 'user-info',
|
|
37
|
-
// OpenAI MCP tools
|
|
38
|
-
SEARCH: 'search',
|
|
39
|
-
FETCH: 'fetch',
|
|
40
|
-
};
|
|
@@ -1,179 +0,0 @@
|
|
|
1
|
-
// User resolution cache for performance with TTL
|
|
2
|
-
const userResolutionCache = new Map();
|
|
3
|
-
// Project collaborators cache
|
|
4
|
-
const collaboratorsCache = new Map();
|
|
5
|
-
const CACHE_TTL = 5 * 60 * 1000; // 5 minutes
|
|
6
|
-
export class UserResolver {
|
|
7
|
-
/**
|
|
8
|
-
* Resolve a user name or ID to a user ID by looking up collaborators across all shared projects.
|
|
9
|
-
* Supports exact name matches, partial matches, and email matches.
|
|
10
|
-
*/
|
|
11
|
-
async resolveUser(client, nameOrId) {
|
|
12
|
-
// Input validation
|
|
13
|
-
if (!nameOrId || nameOrId.trim().length === 0) {
|
|
14
|
-
return null;
|
|
15
|
-
}
|
|
16
|
-
const trimmedInput = nameOrId.trim();
|
|
17
|
-
// Check cache first
|
|
18
|
-
const cached = userResolutionCache.get(trimmedInput);
|
|
19
|
-
if (cached && Date.now() - cached.timestamp < CACHE_TTL) {
|
|
20
|
-
return cached.result;
|
|
21
|
-
}
|
|
22
|
-
// If it looks like a user ID already, return as-is
|
|
23
|
-
// Support numeric IDs and alphanumeric IDs but avoid obvious user names
|
|
24
|
-
if (/^[0-9]+$/.test(trimmedInput) ||
|
|
25
|
-
(/^[a-f0-9-]{8,}$/i.test(trimmedInput) && trimmedInput.includes('-')) ||
|
|
26
|
-
(/^[a-z0-9_]{6,}$/i.test(trimmedInput) &&
|
|
27
|
-
!/^[a-z]+[\s-]/.test(trimmedInput) &&
|
|
28
|
-
/[0-9_]/.test(trimmedInput))) {
|
|
29
|
-
const result = { userId: trimmedInput, displayName: trimmedInput, email: trimmedInput };
|
|
30
|
-
userResolutionCache.set(trimmedInput, { result, timestamp: Date.now() });
|
|
31
|
-
return result;
|
|
32
|
-
}
|
|
33
|
-
try {
|
|
34
|
-
// Get all collaborators from shared projects
|
|
35
|
-
const allCollaborators = await this.getAllCollaborators(client);
|
|
36
|
-
if (allCollaborators.length === 0) {
|
|
37
|
-
const result = null; // No shared projects, can't resolve collaborators
|
|
38
|
-
userResolutionCache.set(trimmedInput, { result, timestamp: Date.now() });
|
|
39
|
-
return result;
|
|
40
|
-
}
|
|
41
|
-
const searchTerm = nameOrId.toLowerCase().trim();
|
|
42
|
-
// Try exact name match first
|
|
43
|
-
let match = allCollaborators.find((c) => c.name.toLowerCase() === searchTerm);
|
|
44
|
-
if (match) {
|
|
45
|
-
const result = { userId: match.id, displayName: match.name, email: match.email };
|
|
46
|
-
userResolutionCache.set(trimmedInput, { result, timestamp: Date.now() });
|
|
47
|
-
return result;
|
|
48
|
-
}
|
|
49
|
-
// Try exact email match
|
|
50
|
-
match = allCollaborators.find((c) => c.email.toLowerCase() === searchTerm);
|
|
51
|
-
if (match) {
|
|
52
|
-
const result = { userId: match.id, displayName: match.name, email: match.email };
|
|
53
|
-
userResolutionCache.set(trimmedInput, { result, timestamp: Date.now() });
|
|
54
|
-
return result;
|
|
55
|
-
}
|
|
56
|
-
// Try partial name match (contains)
|
|
57
|
-
match = allCollaborators.find((c) => c.name.toLowerCase().includes(searchTerm));
|
|
58
|
-
if (match) {
|
|
59
|
-
const result = { userId: match.id, displayName: match.name, email: match.email };
|
|
60
|
-
userResolutionCache.set(trimmedInput, { result, timestamp: Date.now() });
|
|
61
|
-
return result;
|
|
62
|
-
}
|
|
63
|
-
// Try partial email match
|
|
64
|
-
match = allCollaborators.find((c) => c.email.toLowerCase().includes(searchTerm));
|
|
65
|
-
if (match) {
|
|
66
|
-
const result = { userId: match.id, displayName: match.name, email: match.email };
|
|
67
|
-
userResolutionCache.set(trimmedInput, { result, timestamp: Date.now() });
|
|
68
|
-
return result;
|
|
69
|
-
}
|
|
70
|
-
// No match found
|
|
71
|
-
const result = null;
|
|
72
|
-
userResolutionCache.set(trimmedInput, { result, timestamp: Date.now() });
|
|
73
|
-
return result;
|
|
74
|
-
}
|
|
75
|
-
catch (_error) {
|
|
76
|
-
// If we can't fetch collaborators, return null instead of dangerous fallback
|
|
77
|
-
const result = null;
|
|
78
|
-
userResolutionCache.set(trimmedInput, { result, timestamp: Date.now() });
|
|
79
|
-
return result;
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
/**
|
|
83
|
-
* Validate that a user is a collaborator on a specific project
|
|
84
|
-
*/
|
|
85
|
-
async validateProjectCollaborator(client, projectId, userId) {
|
|
86
|
-
try {
|
|
87
|
-
const collaborators = await this.getProjectCollaborators(client, projectId);
|
|
88
|
-
return collaborators.some((collaborator) => collaborator.id === userId);
|
|
89
|
-
}
|
|
90
|
-
catch (_error) {
|
|
91
|
-
return false;
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
/**
|
|
95
|
-
* Get collaborators for a specific project
|
|
96
|
-
*/
|
|
97
|
-
async getProjectCollaborators(client, projectId) {
|
|
98
|
-
// Check cache first
|
|
99
|
-
const cacheKey = `project_${projectId}`;
|
|
100
|
-
const cached = collaboratorsCache.get(cacheKey);
|
|
101
|
-
if (cached && Date.now() - cached.timestamp < CACHE_TTL) {
|
|
102
|
-
return cached.result;
|
|
103
|
-
}
|
|
104
|
-
try {
|
|
105
|
-
const response = await client.getProjectCollaborators(projectId);
|
|
106
|
-
// API returns { results: [...], nextCursor: null } or just array
|
|
107
|
-
const collaborators = Array.isArray(response) ? response : response.results || [];
|
|
108
|
-
const validCollaborators = collaborators.filter((c) => c?.id && c.name && c.email);
|
|
109
|
-
collaboratorsCache.set(cacheKey, {
|
|
110
|
-
result: validCollaborators,
|
|
111
|
-
timestamp: Date.now(),
|
|
112
|
-
});
|
|
113
|
-
return validCollaborators;
|
|
114
|
-
}
|
|
115
|
-
catch (_error) {
|
|
116
|
-
// Return empty array on error, don't cache failed requests
|
|
117
|
-
return [];
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
/**
|
|
121
|
-
* Get all collaborators from all shared projects
|
|
122
|
-
*/
|
|
123
|
-
async getAllCollaborators(client) {
|
|
124
|
-
// Check cache first
|
|
125
|
-
const cacheKey = 'all_collaborators';
|
|
126
|
-
const cached = collaboratorsCache.get(cacheKey);
|
|
127
|
-
if (cached && Date.now() - cached.timestamp < CACHE_TTL) {
|
|
128
|
-
return cached.result;
|
|
129
|
-
}
|
|
130
|
-
try {
|
|
131
|
-
// Get all projects to find shared ones
|
|
132
|
-
const { results: projects } = await client.getProjects({});
|
|
133
|
-
const sharedProjects = projects.filter((p) => p.isShared);
|
|
134
|
-
if (sharedProjects.length === 0) {
|
|
135
|
-
const result = [];
|
|
136
|
-
collaboratorsCache.set(cacheKey, { result, timestamp: Date.now() });
|
|
137
|
-
return result;
|
|
138
|
-
}
|
|
139
|
-
// Collect all collaborators from shared projects in parallel
|
|
140
|
-
const allCollaborators = [];
|
|
141
|
-
const seenIds = new Set();
|
|
142
|
-
const collaboratorPromises = sharedProjects.map((project) => this.getProjectCollaborators(client, project.id));
|
|
143
|
-
const collaboratorResults = await Promise.allSettled(collaboratorPromises);
|
|
144
|
-
for (const result of collaboratorResults) {
|
|
145
|
-
if (result.status === 'fulfilled') {
|
|
146
|
-
for (const collaborator of result.value) {
|
|
147
|
-
if (collaborator && !seenIds.has(collaborator.id)) {
|
|
148
|
-
allCollaborators.push(collaborator);
|
|
149
|
-
seenIds.add(collaborator.id);
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
// Skip failed projects, continue with others
|
|
154
|
-
}
|
|
155
|
-
collaboratorsCache.set(cacheKey, {
|
|
156
|
-
result: allCollaborators,
|
|
157
|
-
timestamp: Date.now(),
|
|
158
|
-
});
|
|
159
|
-
return allCollaborators;
|
|
160
|
-
}
|
|
161
|
-
catch (_error) {
|
|
162
|
-
// Return empty array on error, don't cache failed requests
|
|
163
|
-
return [];
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
/**
|
|
167
|
-
* Clear all caches - useful for testing
|
|
168
|
-
*/
|
|
169
|
-
clearCache() {
|
|
170
|
-
userResolutionCache.clear();
|
|
171
|
-
collaboratorsCache.clear();
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
// Export singleton instance
|
|
175
|
-
export const userResolver = new UserResolver();
|
|
176
|
-
// Legacy function for backwards compatibility
|
|
177
|
-
export async function resolveUserNameToId(client, nameOrId) {
|
|
178
|
-
return userResolver.resolveUser(client, nameOrId);
|
|
179
|
-
}
|