@doist/todoist-ai 2.0.0 → 2.1.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.
Files changed (96) hide show
  1. package/README.md +7 -0
  2. package/dist/index.d.ts +29 -18
  3. package/dist/index.d.ts.map +1 -1
  4. package/dist/index.js +31 -48
  5. package/dist/main.js +6 -11
  6. package/dist/mcp-helpers.d.ts +2 -2
  7. package/dist/mcp-helpers.d.ts.map +1 -1
  8. package/dist/mcp-helpers.js +1 -4
  9. package/dist/mcp-server.d.ts +1 -1
  10. package/dist/mcp-server.d.ts.map +1 -1
  11. package/dist/mcp-server.js +34 -36
  12. package/dist/todoist-tool.js +1 -2
  13. package/dist/tool-helpers.d.ts +13 -1
  14. package/dist/tool-helpers.d.ts.map +1 -1
  15. package/dist/tool-helpers.js +43 -22
  16. package/dist/tool-helpers.test.js +55 -14
  17. package/dist/tools/__tests__/delete-one.test.d.ts +2 -0
  18. package/dist/tools/__tests__/delete-one.test.d.ts.map +1 -0
  19. package/dist/tools/__tests__/delete-one.test.js +90 -0
  20. package/dist/tools/__tests__/overview.test.d.ts +2 -0
  21. package/dist/tools/__tests__/overview.test.d.ts.map +1 -0
  22. package/dist/tools/__tests__/overview.test.js +163 -0
  23. package/dist/tools/__tests__/projects-list.test.d.ts +2 -0
  24. package/dist/tools/__tests__/projects-list.test.d.ts.map +1 -0
  25. package/dist/tools/__tests__/projects-list.test.js +140 -0
  26. package/dist/tools/__tests__/projects-manage.test.d.ts +2 -0
  27. package/dist/tools/__tests__/projects-manage.test.d.ts.map +1 -0
  28. package/dist/tools/__tests__/projects-manage.test.js +106 -0
  29. package/dist/tools/__tests__/sections-manage.test.d.ts +2 -0
  30. package/dist/tools/__tests__/sections-manage.test.d.ts.map +1 -0
  31. package/dist/tools/__tests__/sections-manage.test.js +138 -0
  32. package/dist/tools/__tests__/sections-search.test.d.ts +2 -0
  33. package/dist/tools/__tests__/sections-search.test.d.ts.map +1 -0
  34. package/dist/tools/__tests__/sections-search.test.js +235 -0
  35. package/dist/tools/__tests__/tasks-add-multiple.test.d.ts +2 -0
  36. package/dist/tools/__tests__/tasks-add-multiple.test.d.ts.map +1 -0
  37. package/dist/tools/__tests__/tasks-add-multiple.test.js +274 -0
  38. package/dist/tools/__tests__/tasks-complete-multiple.test.d.ts +2 -0
  39. package/dist/tools/__tests__/tasks-complete-multiple.test.d.ts.map +1 -0
  40. package/dist/tools/__tests__/tasks-complete-multiple.test.js +146 -0
  41. package/dist/tools/__tests__/tasks-list-by-date.test.d.ts +2 -0
  42. package/dist/tools/__tests__/tasks-list-by-date.test.d.ts.map +1 -0
  43. package/dist/tools/__tests__/tasks-list-by-date.test.js +192 -0
  44. package/dist/tools/__tests__/tasks-list-completed.test.d.ts +2 -0
  45. package/dist/tools/__tests__/tasks-list-completed.test.d.ts.map +1 -0
  46. package/dist/tools/__tests__/tasks-list-completed.test.js +154 -0
  47. package/dist/tools/__tests__/tasks-list-for-container.test.d.ts +2 -0
  48. package/dist/tools/__tests__/tasks-list-for-container.test.d.ts.map +1 -0
  49. package/dist/tools/__tests__/tasks-list-for-container.test.js +232 -0
  50. package/dist/tools/__tests__/tasks-organize-multiple.test.d.ts +2 -0
  51. package/dist/tools/__tests__/tasks-organize-multiple.test.d.ts.map +1 -0
  52. package/dist/tools/__tests__/tasks-organize-multiple.test.js +245 -0
  53. package/dist/tools/__tests__/tasks-search.test.d.ts +2 -0
  54. package/dist/tools/__tests__/tasks-search.test.d.ts.map +1 -0
  55. package/dist/tools/__tests__/tasks-search.test.js +106 -0
  56. package/dist/tools/__tests__/tasks-update-one.test.d.ts +2 -0
  57. package/dist/tools/__tests__/tasks-update-one.test.d.ts.map +1 -0
  58. package/dist/tools/__tests__/tasks-update-one.test.js +251 -0
  59. package/dist/tools/delete-one.js +4 -7
  60. package/dist/tools/overview.js +8 -11
  61. package/dist/tools/projects-list.js +7 -10
  62. package/dist/tools/projects-manage.js +6 -9
  63. package/dist/tools/sections-manage.js +7 -10
  64. package/dist/tools/sections-search.js +4 -7
  65. package/dist/tools/tasks-add-multiple.d.ts +5 -0
  66. package/dist/tools/tasks-add-multiple.d.ts.map +1 -1
  67. package/dist/tools/tasks-add-multiple.js +37 -17
  68. package/dist/tools/tasks-complete-multiple.js +3 -6
  69. package/dist/tools/tasks-list-by-date.d.ts +1 -0
  70. package/dist/tools/tasks-list-by-date.d.ts.map +1 -1
  71. package/dist/tools/tasks-list-by-date.js +12 -15
  72. package/dist/tools/tasks-list-completed.d.ts +2 -1
  73. package/dist/tools/tasks-list-completed.d.ts.map +1 -1
  74. package/dist/tools/tasks-list-completed.js +13 -16
  75. package/dist/tools/tasks-list-for-container.d.ts +1 -0
  76. package/dist/tools/tasks-list-for-container.d.ts.map +1 -1
  77. package/dist/tools/tasks-list-for-container.js +8 -11
  78. package/dist/tools/tasks-organize-multiple.d.ts.map +1 -1
  79. package/dist/tools/tasks-organize-multiple.js +20 -14
  80. package/dist/tools/tasks-search.d.ts +1 -0
  81. package/dist/tools/tasks-search.d.ts.map +1 -1
  82. package/dist/tools/tasks-search.js +7 -10
  83. package/dist/tools/tasks-update-one.d.ts +4 -2
  84. package/dist/tools/tasks-update-one.d.ts.map +1 -1
  85. package/dist/tools/tasks-update-one.js +45 -15
  86. package/dist/tools/test-helpers.d.ts +80 -0
  87. package/dist/tools/test-helpers.d.ts.map +1 -0
  88. package/dist/tools/test-helpers.js +140 -0
  89. package/dist/utils/duration-parser.d.ts +36 -0
  90. package/dist/utils/duration-parser.d.ts.map +1 -0
  91. package/dist/utils/duration-parser.js +96 -0
  92. package/dist/utils/duration-parser.test.d.ts +2 -0
  93. package/dist/utils/duration-parser.test.d.ts.map +1 -0
  94. package/dist/utils/duration-parser.test.js +147 -0
  95. package/package.json +6 -2
  96. package/scripts/test-executable.cjs +69 -0
@@ -0,0 +1,251 @@
1
+ import { jest } from '@jest/globals';
2
+ import { tasksUpdateOne } from '../tasks-update-one.js';
3
+ import { createMockTask } from '../test-helpers.js';
4
+ // Mock the Todoist API
5
+ const mockTodoistApi = {
6
+ updateTask: jest.fn(),
7
+ moveTasks: jest.fn(),
8
+ };
9
+ describe('tasks-update-one tool', () => {
10
+ beforeEach(() => {
11
+ jest.clearAllMocks();
12
+ });
13
+ describe('updating task properties', () => {
14
+ it('should update task content and description', async () => {
15
+ // Mock API response extracted from recordings (Task type)
16
+ const mockApiResponse = createMockTask({
17
+ id: '8485093748',
18
+ content: 'Updated task content',
19
+ description: 'Updated task description',
20
+ url: 'https://todoist.com/showTask?id=8485093748',
21
+ addedAt: '2025-08-13T22:09:56.123456Z',
22
+ });
23
+ mockTodoistApi.updateTask.mockResolvedValue(mockApiResponse);
24
+ const result = await tasksUpdateOne.execute({
25
+ id: '8485093748',
26
+ content: 'Updated task content',
27
+ description: 'Updated task description',
28
+ }, mockTodoistApi);
29
+ // Verify API was called correctly
30
+ expect(mockTodoistApi.updateTask).toHaveBeenCalledWith('8485093748', {
31
+ content: 'Updated task content',
32
+ description: 'Updated task description',
33
+ });
34
+ // Verify result matches API response
35
+ expect(result).toEqual(mockApiResponse);
36
+ });
37
+ it('should update task priority and due date', async () => {
38
+ const mockApiResponse = createMockTask({
39
+ id: '8485093749',
40
+ content: 'Original task content',
41
+ labels: ['urgent'],
42
+ priority: 3,
43
+ url: 'https://todoist.com/showTask?id=8485093749',
44
+ addedAt: '2025-08-13T22:09:56.123456Z',
45
+ due: {
46
+ date: '2025-08-20',
47
+ isRecurring: false,
48
+ lang: 'en',
49
+ string: 'Aug 20',
50
+ timezone: null,
51
+ },
52
+ });
53
+ mockTodoistApi.updateTask.mockResolvedValue(mockApiResponse);
54
+ const result = await tasksUpdateOne.execute({ id: '8485093749', priority: 3, dueString: 'Aug 20' }, mockTodoistApi);
55
+ expect(mockTodoistApi.updateTask).toHaveBeenCalledWith('8485093749', {
56
+ priority: 3,
57
+ dueString: 'Aug 20',
58
+ });
59
+ expect(result).toEqual(mockApiResponse);
60
+ });
61
+ it('should move task to different project', async () => {
62
+ const mockApiResponse = createMockTask({
63
+ id: '8485093750',
64
+ content: 'Task to move',
65
+ projectId: 'new-project-id',
66
+ url: 'https://todoist.com/showTask?id=8485093750',
67
+ addedAt: '2025-08-13T22:09:56.123456Z',
68
+ });
69
+ mockTodoistApi.moveTasks.mockResolvedValue([mockApiResponse]);
70
+ const result = await tasksUpdateOne.execute({ id: '8485093750', projectId: 'new-project-id' }, mockTodoistApi);
71
+ expect(mockTodoistApi.moveTasks).toHaveBeenCalledWith(['8485093750'], {
72
+ projectId: 'new-project-id',
73
+ });
74
+ expect(mockTodoistApi.updateTask).not.toHaveBeenCalled();
75
+ expect(result).toEqual(mockApiResponse);
76
+ });
77
+ it('should update task parent (create subtask relationship)', async () => {
78
+ const mockApiResponse = createMockTask({
79
+ id: '8485093751',
80
+ content: 'Subtask content',
81
+ parentId: 'parent-task-123',
82
+ url: 'https://todoist.com/showTask?id=8485093751',
83
+ addedAt: '2025-08-13T22:09:56.123456Z',
84
+ });
85
+ mockTodoistApi.moveTasks.mockResolvedValue([mockApiResponse]);
86
+ const result = await tasksUpdateOne.execute({ id: '8485093751', parentId: 'parent-task-123' }, mockTodoistApi);
87
+ expect(mockTodoistApi.moveTasks).toHaveBeenCalledWith(['8485093751'], {
88
+ parentId: 'parent-task-123',
89
+ });
90
+ expect(mockTodoistApi.updateTask).not.toHaveBeenCalled();
91
+ expect(result).toEqual(mockApiResponse);
92
+ });
93
+ it('should move task and update properties at once', async () => {
94
+ const movedTask = createMockTask({
95
+ id: '8485093752',
96
+ content: 'Task to move',
97
+ projectId: 'different-project-id',
98
+ });
99
+ const updatedTask = createMockTask({
100
+ id: '8485093752',
101
+ content: 'Completely updated task',
102
+ description: 'New description with details',
103
+ priority: 4,
104
+ projectId: 'different-project-id',
105
+ url: 'https://todoist.com/showTask?id=8485093752',
106
+ addedAt: '2025-08-13T22:09:56.123456Z',
107
+ due: {
108
+ date: '2025-08-25',
109
+ isRecurring: true,
110
+ lang: 'en',
111
+ string: 'every Friday',
112
+ timezone: null,
113
+ },
114
+ });
115
+ mockTodoistApi.moveTasks.mockResolvedValue([movedTask]);
116
+ mockTodoistApi.updateTask.mockResolvedValue(updatedTask);
117
+ const result = await tasksUpdateOne.execute({
118
+ id: '8485093752',
119
+ content: 'Completely updated task',
120
+ description: 'New description with details',
121
+ priority: 4,
122
+ dueString: 'every Friday',
123
+ projectId: 'different-project-id',
124
+ }, mockTodoistApi);
125
+ // Should call moveTasks first for the projectId
126
+ expect(mockTodoistApi.moveTasks).toHaveBeenCalledWith(['8485093752'], {
127
+ projectId: 'different-project-id',
128
+ });
129
+ // Then call updateTask for the other properties
130
+ expect(mockTodoistApi.updateTask).toHaveBeenCalledWith('8485093752', {
131
+ content: 'Completely updated task',
132
+ description: 'New description with details',
133
+ priority: 4,
134
+ dueString: 'every Friday',
135
+ });
136
+ expect(result).toEqual(updatedTask);
137
+ });
138
+ it('should update task duration', async () => {
139
+ const mockApiResponse = createMockTask({
140
+ id: '8485093753',
141
+ content: 'Task with updated duration',
142
+ duration: { amount: 150, unit: 'minute' },
143
+ url: 'https://todoist.com/showTask?id=8485093753',
144
+ addedAt: '2025-08-13T22:09:56.123456Z',
145
+ });
146
+ mockTodoistApi.updateTask.mockResolvedValue(mockApiResponse);
147
+ const result = await tasksUpdateOne.execute({
148
+ id: '8485093753',
149
+ duration: '2h30m',
150
+ }, mockTodoistApi);
151
+ expect(mockTodoistApi.updateTask).toHaveBeenCalledWith('8485093753', {
152
+ duration: 150,
153
+ durationUnit: 'minute',
154
+ });
155
+ expect(result).toEqual(mockApiResponse);
156
+ });
157
+ it('should handle various duration formats', async () => {
158
+ const mockApiResponse = createMockTask({
159
+ id: '8485093754',
160
+ content: 'Test task',
161
+ duration: { amount: 120, unit: 'minute' },
162
+ });
163
+ mockTodoistApi.updateTask.mockResolvedValue(mockApiResponse);
164
+ // Test different duration formats
165
+ const testCases = [
166
+ { input: '2h', expectedMinutes: 120 },
167
+ { input: '90m', expectedMinutes: 90 },
168
+ { input: '1.5h', expectedMinutes: 90 },
169
+ { input: ' 2h 30m ', expectedMinutes: 150 },
170
+ { input: '2H30M', expectedMinutes: 150 },
171
+ ];
172
+ for (const testCase of testCases) {
173
+ mockTodoistApi.updateTask.mockClear();
174
+ await tasksUpdateOne.execute({
175
+ id: '8485093754',
176
+ duration: testCase.input,
177
+ }, mockTodoistApi);
178
+ expect(mockTodoistApi.updateTask).toHaveBeenCalledWith('8485093754', expect.objectContaining({
179
+ duration: testCase.expectedMinutes,
180
+ durationUnit: 'minute',
181
+ }));
182
+ }
183
+ });
184
+ it('should update task with duration and move at once', async () => {
185
+ const movedTask = createMockTask({
186
+ id: '8485093755',
187
+ content: 'Task to move and update',
188
+ projectId: 'new-project-id',
189
+ });
190
+ const updatedTask = createMockTask({
191
+ id: '8485093755',
192
+ content: 'Updated task with duration',
193
+ duration: { amount: 120, unit: 'minute' },
194
+ projectId: 'new-project-id',
195
+ });
196
+ mockTodoistApi.moveTasks.mockResolvedValue([movedTask]);
197
+ mockTodoistApi.updateTask.mockResolvedValue(updatedTask);
198
+ const result = await tasksUpdateOne.execute({
199
+ id: '8485093755',
200
+ content: 'Updated task with duration',
201
+ duration: '2h',
202
+ projectId: 'new-project-id',
203
+ }, mockTodoistApi);
204
+ // Should call moveTasks first
205
+ expect(mockTodoistApi.moveTasks).toHaveBeenCalledWith(['8485093755'], {
206
+ projectId: 'new-project-id',
207
+ });
208
+ // Then call updateTask with duration
209
+ expect(mockTodoistApi.updateTask).toHaveBeenCalledWith('8485093755', {
210
+ content: 'Updated task with duration',
211
+ duration: 120,
212
+ durationUnit: 'minute',
213
+ });
214
+ expect(result).toEqual(updatedTask);
215
+ });
216
+ });
217
+ describe('error handling', () => {
218
+ it('should throw error for invalid duration format', async () => {
219
+ await expect(tasksUpdateOne.execute({
220
+ id: '8485093756',
221
+ duration: 'invalid',
222
+ }, mockTodoistApi)).rejects.toThrow('Task 8485093756: Invalid duration format "invalid"');
223
+ });
224
+ it('should throw error for duration exceeding 24 hours', async () => {
225
+ await expect(tasksUpdateOne.execute({
226
+ id: '8485093757',
227
+ duration: '25h',
228
+ }, mockTodoistApi)).rejects.toThrow('Task 8485093757: Invalid duration format "25h": Duration cannot exceed 24 hours (1440 minutes)');
229
+ });
230
+ it('should throw error when multiple move parameters are provided', async () => {
231
+ await expect(tasksUpdateOne.execute({ id: '8485093748', projectId: 'new-project', sectionId: 'new-section' }, mockTodoistApi)).rejects.toThrow('Only one of projectId, sectionId, or parentId can be specified at a time. ' +
232
+ 'The Todoist API requires exactly one destination for move operations.');
233
+ });
234
+ it('should throw error when all three move parameters are provided', async () => {
235
+ await expect(tasksUpdateOne.execute({ id: '8485093748', projectId: 'p1', sectionId: 's1', parentId: 't1' }, mockTodoistApi)).rejects.toThrow('Only one of projectId, sectionId, or parentId can be specified at a time');
236
+ });
237
+ it.each([
238
+ {
239
+ error: 'API Error: Task not found',
240
+ params: { id: 'non-existent-task', content: 'Updated content' },
241
+ },
242
+ {
243
+ error: 'API Error: Invalid priority value',
244
+ params: { id: '8485093748', priority: 5 },
245
+ },
246
+ ])('should propagate $error', async ({ error, params }) => {
247
+ mockTodoistApi.updateTask.mockRejectedValue(new Error(error));
248
+ await expect(tasksUpdateOne.execute(params, mockTodoistApi)).rejects.toThrow(error);
249
+ });
250
+ });
251
+ });
@@ -1,10 +1,7 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.deleteOne = void 0;
4
- const zod_1 = require("zod");
1
+ import { z } from 'zod';
5
2
  const ArgsSchema = {
6
- type: zod_1.z.enum(['project', 'section', 'task']).describe('The type of entity to delete.'),
7
- id: zod_1.z.string().min(1).describe('The ID of the entity to delete.'),
3
+ type: z.enum(['project', 'section', 'task']).describe('The type of entity to delete.'),
4
+ id: z.string().min(1).describe('The ID of the entity to delete.'),
8
5
  };
9
6
  const deleteOne = {
10
7
  name: 'delete-one',
@@ -25,4 +22,4 @@ const deleteOne = {
25
22
  return { success: true };
26
23
  },
27
24
  };
28
- exports.deleteOne = deleteOne;
25
+ export { deleteOne };
@@ -1,10 +1,7 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.overview = void 0;
4
- const zod_1 = require("zod");
5
- const tool_helpers_1 = require("../tool-helpers");
1
+ import { z } from 'zod';
2
+ import { isPersonalProject, mapTask } from '../tool-helpers.js';
6
3
  const ArgsSchema = {
7
- projectId: zod_1.z
4
+ projectId: z
8
5
  .string()
9
6
  .min(1)
10
7
  .optional()
@@ -25,7 +22,7 @@ function buildProjectTree(projects) {
25
22
  const current = byId[p.id];
26
23
  if (!current)
27
24
  continue;
28
- if ((0, tool_helpers_1.isPersonalProject)(p) && p.parentId) {
25
+ if (isPersonalProject(p) && p.parentId) {
29
26
  const parent = byId[p.parentId];
30
27
  if (parent) {
31
28
  parent.children.push(current);
@@ -113,7 +110,7 @@ async function getAllTasksForProject(client, projectId) {
113
110
  limit: 50,
114
111
  cursor: cursor ?? undefined,
115
112
  });
116
- allTasks = allTasks.concat(results.map(tool_helpers_1.mapTask));
113
+ allTasks = allTasks.concat(results.map(mapTask));
117
114
  cursor = nextCursor ?? undefined;
118
115
  } while (cursor);
119
116
  return allTasks;
@@ -125,8 +122,8 @@ async function getProjectSections(client, projectId) {
125
122
  // Account overview implementation
126
123
  async function generateAccountOverview(client) {
127
124
  const { results: projects } = await client.getProjects({});
128
- const inbox = projects.find((p) => (0, tool_helpers_1.isPersonalProject)(p) && p.inboxProject === true);
129
- const nonInbox = projects.filter((p) => !(0, tool_helpers_1.isPersonalProject)(p) || p.inboxProject !== true);
125
+ const inbox = projects.find((p) => isPersonalProject(p) && p.inboxProject === true);
126
+ const nonInbox = projects.filter((p) => !isPersonalProject(p) || p.inboxProject !== true);
130
127
  const tree = buildProjectTree(nonInbox);
131
128
  const allProjectIds = projects.map((p) => p.id);
132
129
  const sectionsByProject = await getSectionsByProject(client, allProjectIds);
@@ -202,4 +199,4 @@ const overview = {
202
199
  return await generateAccountOverview(client);
203
200
  },
204
201
  };
205
- exports.overview = overview;
202
+ export { overview };
@@ -1,21 +1,18 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.projectsList = void 0;
4
- const zod_1 = require("zod");
5
- const tool_helpers_1 = require("../tool-helpers");
1
+ import { z } from 'zod';
2
+ import { mapProject } from '../tool-helpers.js';
6
3
  const ArgsSchema = {
7
- search: zod_1.z
4
+ search: z
8
5
  .string()
9
6
  .optional()
10
7
  .describe('Search for a project by name (partial and case insensitive match). If omitted, all projects are returned.'),
11
- limit: zod_1.z
8
+ limit: z
12
9
  .number()
13
10
  .int()
14
11
  .min(1)
15
12
  .max(100)
16
13
  .default(50)
17
14
  .describe('The maximum number of projects to return.'),
18
- cursor: zod_1.z
15
+ cursor: z
19
16
  .string()
20
17
  .optional()
21
18
  .describe('The cursor to get the next page of projects (cursor is obtained from the previous call to this tool, with the same parameters).'),
@@ -34,9 +31,9 @@ const projectsList = {
34
31
  ? results.filter((project) => project.name.toLowerCase().includes(searchLower))
35
32
  : results;
36
33
  return {
37
- projects: filtered.map(tool_helpers_1.mapProject),
34
+ projects: filtered.map(mapProject),
38
35
  nextCursor,
39
36
  };
40
37
  },
41
38
  };
42
- exports.projectsList = projectsList;
39
+ export { projectsList };
@@ -1,15 +1,12 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.projectsManage = void 0;
4
- const zod_1 = require("zod");
5
- const tool_helpers_1 = require("../tool-helpers");
1
+ import { z } from 'zod';
2
+ import { mapProject } from '../tool-helpers.js';
6
3
  const ArgsSchema = {
7
- id: zod_1.z
4
+ id: z
8
5
  .string()
9
6
  .min(1)
10
7
  .optional()
11
8
  .describe('The ID of the project to update. If provided, updates the project. If omitted, creates a new project.'),
12
- name: zod_1.z.string().min(1).describe('The name of the project.'),
9
+ name: z.string().min(1).describe('The name of the project.'),
13
10
  };
14
11
  const projectsManage = {
15
12
  name: 'projects-manage',
@@ -23,7 +20,7 @@ const projectsManage = {
23
20
  }
24
21
  // Create new project
25
22
  const project = await client.addProject({ name: args.name });
26
- return (0, tool_helpers_1.mapProject)(project);
23
+ return mapProject(project);
27
24
  },
28
25
  };
29
- exports.projectsManage = projectsManage;
26
+ export { projectsManage };
@@ -1,16 +1,13 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.sectionsManage = void 0;
4
- const zod_1 = require("zod");
5
- const mcp_helpers_1 = require("../mcp-helpers");
1
+ import { z } from 'zod';
2
+ import { errorContent } from '../mcp-helpers.js';
6
3
  const ArgsSchema = {
7
- id: zod_1.z
4
+ id: z
8
5
  .string()
9
6
  .min(1)
10
7
  .optional()
11
8
  .describe('The ID of the section to update. If provided, updates the section. If omitted, creates a new section.'),
12
- name: zod_1.z.string().min(1).describe('The name of the section.'),
13
- projectId: zod_1.z
9
+ name: z.string().min(1).describe('The name of the section.'),
10
+ projectId: z
14
11
  .string()
15
12
  .min(1)
16
13
  .optional()
@@ -28,7 +25,7 @@ const sectionsManage = {
28
25
  }
29
26
  // Create new section - projectId is required
30
27
  if (!args.projectId) {
31
- return (0, mcp_helpers_1.errorContent)('Error: projectId is required when creating a new section (when id is not provided).');
28
+ return errorContent('Error: projectId is required when creating a new section (when id is not provided).');
32
29
  }
33
30
  const section = await client.addSection({
34
31
  name: args.name,
@@ -37,4 +34,4 @@ const sectionsManage = {
37
34
  return section;
38
35
  },
39
36
  };
40
- exports.sectionsManage = sectionsManage;
37
+ export { sectionsManage };
@@ -1,10 +1,7 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.sectionsSearch = void 0;
4
- const zod_1 = require("zod");
1
+ import { z } from 'zod';
5
2
  const ArgsSchema = {
6
- projectId: zod_1.z.string().min(1).describe('The ID of the project to search sections in.'),
7
- search: zod_1.z
3
+ projectId: z.string().min(1).describe('The ID of the project to search sections in.'),
4
+ search: z
8
5
  .string()
9
6
  .optional()
10
7
  .describe('Search for a section by name (partial and case insensitive match). If omitted, all sections in the project are returned.'),
@@ -27,4 +24,4 @@ const sectionsSearch = {
27
24
  }));
28
25
  },
29
26
  };
30
- exports.sectionsSearch = sectionsSearch;
27
+ export { sectionsSearch };
@@ -11,16 +11,19 @@ declare const tasksAddMultiple: {
11
11
  description: z.ZodOptional<z.ZodString>;
12
12
  priority: z.ZodOptional<z.ZodNumber>;
13
13
  dueString: z.ZodOptional<z.ZodString>;
14
+ duration: z.ZodOptional<z.ZodString>;
14
15
  }, "strip", z.ZodTypeAny, {
15
16
  content: string;
16
17
  description?: string | undefined;
17
18
  priority?: number | undefined;
18
19
  dueString?: string | undefined;
20
+ duration?: string | undefined;
19
21
  }, {
20
22
  content: string;
21
23
  description?: string | undefined;
22
24
  priority?: number | undefined;
23
25
  dueString?: string | undefined;
26
+ duration?: string | undefined;
24
27
  }>, "many">;
25
28
  };
26
29
  execute(args: {
@@ -29,6 +32,7 @@ declare const tasksAddMultiple: {
29
32
  description?: string | undefined;
30
33
  priority?: number | undefined;
31
34
  dueString?: string | undefined;
35
+ duration?: string | undefined;
32
36
  }[];
33
37
  parentId?: string | undefined;
34
38
  projectId?: string | undefined;
@@ -44,6 +48,7 @@ declare const tasksAddMultiple: {
44
48
  sectionId: string | null;
45
49
  parentId: string | null;
46
50
  labels: string[];
51
+ duration: string | null;
47
52
  }[]>;
48
53
  };
49
54
  export { tasksAddMultiple };
@@ -1 +1 @@
1
- {"version":3,"file":"tasks-add-multiple.d.ts","sourceRoot":"","sources":["../../src/tools/tasks-add-multiple.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAkBvB,QAAA,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAaoB,CAAA;AAE1C,OAAO,EAAE,gBAAgB,EAAE,CAAA"}
1
+ {"version":3,"file":"tasks-add-multiple.d.ts","sourceRoot":"","sources":["../../src/tools/tasks-add-multiple.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAyBvB,QAAA,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAiCoB,CAAA;AAE1C,OAAO,EAAE,gBAAgB,EAAE,CAAA"}
@@ -1,19 +1,21 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.tasksAddMultiple = void 0;
4
- const zod_1 = require("zod");
5
- const tool_helpers_1 = require("../tool-helpers");
6
- const TaskSchema = zod_1.z.object({
7
- content: zod_1.z.string().min(1).describe('The content of the task to create.'),
8
- description: zod_1.z.string().optional().describe('The description of the task.'),
9
- priority: zod_1.z.number().int().min(1).max(4).optional().describe('The priority of the task (1-4).'),
10
- dueString: zod_1.z.string().optional().describe('The due date for the task, in natural language.'),
1
+ import { z } from 'zod';
2
+ import { mapTask } from '../tool-helpers.js';
3
+ import { DurationParseError, parseDuration } from '../utils/duration-parser.js';
4
+ const TaskSchema = z.object({
5
+ content: z.string().min(1).describe('The content of the task to create.'),
6
+ description: z.string().optional().describe('The description of the task.'),
7
+ priority: z.number().int().min(1).max(4).optional().describe('The priority of the task (1-4).'),
8
+ dueString: z.string().optional().describe('The due date for the task, in natural language.'),
9
+ duration: z
10
+ .string()
11
+ .optional()
12
+ .describe('The duration of the task. Use format: "2h" (hours), "90m" (minutes), "2h30m" (combined), or "1.5h" (decimal hours). Max 24h.'),
11
13
  });
12
14
  const ArgsSchema = {
13
- projectId: zod_1.z.string().optional().describe('The project ID to add the tasks to.'),
14
- sectionId: zod_1.z.string().optional().describe('The section ID to add the tasks to.'),
15
- parentId: zod_1.z.string().optional().describe('The parent task ID (for subtasks).'),
16
- tasks: zod_1.z.array(TaskSchema).min(1).describe('The array of tasks to add.'),
15
+ projectId: z.string().optional().describe('The project ID to add the tasks to.'),
16
+ sectionId: z.string().optional().describe('The section ID to add the tasks to.'),
17
+ parentId: z.string().optional().describe('The parent task ID (for subtasks).'),
18
+ tasks: z.array(TaskSchema).min(1).describe('The array of tasks to add.'),
17
19
  };
18
20
  const tasksAddMultiple = {
19
21
  name: 'tasks-add-multiple',
@@ -23,10 +25,28 @@ const tasksAddMultiple = {
23
25
  const { projectId, sectionId, parentId, tasks } = args;
24
26
  const newTasks = [];
25
27
  for (const task of tasks) {
26
- const taskArgs = { ...task, projectId, sectionId, parentId };
28
+ const { duration: durationStr, ...otherTaskArgs } = task;
29
+ let taskArgs = { ...otherTaskArgs, projectId, sectionId, parentId };
30
+ // Parse duration if provided
31
+ if (durationStr) {
32
+ try {
33
+ const { minutes } = parseDuration(durationStr);
34
+ taskArgs = {
35
+ ...taskArgs,
36
+ duration: minutes,
37
+ durationUnit: 'minute',
38
+ };
39
+ }
40
+ catch (error) {
41
+ if (error instanceof DurationParseError) {
42
+ throw new Error(`Task "${task.content}": ${error.message}`);
43
+ }
44
+ throw error;
45
+ }
46
+ }
27
47
  newTasks.push(await client.addTask(taskArgs));
28
48
  }
29
- return newTasks.map(tool_helpers_1.mapTask);
49
+ return newTasks.map(mapTask);
30
50
  },
31
51
  };
32
- exports.tasksAddMultiple = tasksAddMultiple;
52
+ export { tasksAddMultiple };
@@ -1,9 +1,6 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.tasksCompleteMultiple = void 0;
4
- const zod_1 = require("zod");
1
+ import { z } from 'zod';
5
2
  const ArgsSchema = {
6
- ids: zod_1.z.array(zod_1.z.string().min(1)).min(1).describe('The IDs of the tasks to complete.'),
3
+ ids: z.array(z.string().min(1)).min(1).describe('The IDs of the tasks to complete.'),
7
4
  };
8
5
  const tasksCompleteMultiple = {
9
6
  name: 'tasks-complete-multiple',
@@ -23,4 +20,4 @@ const tasksCompleteMultiple = {
23
20
  return { success: true, completed };
24
21
  },
25
22
  };
26
- exports.tasksCompleteMultiple = tasksCompleteMultiple;
23
+ export { tasksCompleteMultiple };
@@ -25,6 +25,7 @@ declare const tasksListByDate: {
25
25
  sectionId: string | null;
26
26
  parentId: string | null;
27
27
  labels: string[];
28
+ duration: string | null;
28
29
  }[];
29
30
  nextCursor: string | null;
30
31
  }>;
@@ -1 +1 @@
1
- {"version":3,"file":"tasks-list-by-date.d.ts","sourceRoot":"","sources":["../../src/tools/tasks-list-by-date.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAmCvB,QAAA,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2BqB,CAAA;AAE1C,OAAO,EAAE,eAAe,EAAE,CAAA"}
1
+ {"version":3,"file":"tasks-list-by-date.d.ts","sourceRoot":"","sources":["../../src/tools/tasks-list-by-date.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAmCvB,QAAA,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2BqB,CAAA;AAE1C,OAAO,EAAE,eAAe,EAAE,CAAA"}
@@ -1,29 +1,26 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.tasksListByDate = void 0;
4
- const date_fns_1 = require("date-fns");
5
- const zod_1 = require("zod");
6
- const tool_helpers_1 = require("../tool-helpers");
1
+ import { addDays, formatISO } from 'date-fns';
2
+ import { z } from 'zod';
3
+ import { getTasksByFilter } from '../tool-helpers.js';
7
4
  const ArgsSchema = {
8
- startDate: zod_1.z
5
+ startDate: z
9
6
  .string()
10
7
  .regex(/^(\d{4}-\d{2}-\d{2}|today|overdue)$/)
11
8
  .describe("The start date to get the tasks for. Format: YYYY-MM-DD, 'today', or 'overdue'."),
12
- daysCount: zod_1.z
9
+ daysCount: z
13
10
  .number()
14
11
  .int()
15
12
  .min(1)
16
13
  .max(30)
17
14
  .default(1)
18
15
  .describe("The number of days to get the tasks for, starting from the start date. Ignored when startDate is 'overdue'."),
19
- limit: zod_1.z
16
+ limit: z
20
17
  .number()
21
18
  .int()
22
19
  .min(1)
23
20
  .max(50)
24
21
  .default(10)
25
22
  .describe('The maximum number of tasks to return.'),
26
- cursor: zod_1.z
23
+ cursor: z
27
24
  .string()
28
25
  .optional()
29
26
  .describe('The cursor to get the next page of tasks (cursor is obtained from the previous call to this tool, with the same parameters).'),
@@ -39,13 +36,13 @@ const tasksListByDate = {
39
36
  }
40
37
  else {
41
38
  const startDate = args.startDate === 'today'
42
- ? (0, date_fns_1.formatISO)(new Date(), { representation: 'date' })
39
+ ? formatISO(new Date(), { representation: 'date' })
43
40
  : args.startDate;
44
- const endDate = (0, date_fns_1.addDays)(startDate, args.daysCount + 1);
45
- const endDateStr = (0, date_fns_1.formatISO)(endDate, { representation: 'date' });
41
+ const endDate = addDays(startDate, args.daysCount + 1);
42
+ const endDateStr = formatISO(endDate, { representation: 'date' });
46
43
  query = `(due after: ${startDate} | due: ${startDate}) & due before: ${endDateStr}`;
47
44
  }
48
- return await (0, tool_helpers_1.getTasksByFilter)({
45
+ return await getTasksByFilter({
49
46
  client,
50
47
  query,
51
48
  cursor: args.cursor,
@@ -53,4 +50,4 @@ const tasksListByDate = {
53
50
  });
54
51
  },
55
52
  };
56
- exports.tasksListByDate = tasksListByDate;
53
+ export { tasksListByDate };