@doist/todoist-ai 2.2.2 → 3.0.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 (168) hide show
  1. package/README.md +11 -3
  2. package/dist/index.d.ts +496 -255
  3. package/dist/index.d.ts.map +1 -1
  4. package/dist/index.js +41 -29
  5. package/dist/mcp-helpers.d.ts +25 -3
  6. package/dist/mcp-helpers.d.ts.map +1 -1
  7. package/dist/mcp-helpers.js +37 -19
  8. package/dist/mcp-server.d.ts.map +1 -1
  9. package/dist/mcp-server.js +32 -28
  10. package/dist/tools/__tests__/add-tasks.test.d.ts +2 -0
  11. package/dist/tools/__tests__/add-tasks.test.d.ts.map +1 -0
  12. package/dist/tools/__tests__/{tasks-add-multiple.test.js → add-tasks.test.js} +85 -81
  13. package/dist/tools/__tests__/complete-tasks.test.d.ts +2 -0
  14. package/dist/tools/__tests__/complete-tasks.test.d.ts.map +1 -0
  15. package/dist/tools/__tests__/complete-tasks.test.js +206 -0
  16. package/dist/tools/__tests__/delete-object.test.d.ts +2 -0
  17. package/dist/tools/__tests__/delete-object.test.d.ts.map +1 -0
  18. package/dist/tools/__tests__/{delete-one.test.js → delete-object.test.js} +42 -22
  19. package/dist/tools/__tests__/find-completed-tasks.test.d.ts +2 -0
  20. package/dist/tools/__tests__/find-completed-tasks.test.d.ts.map +1 -0
  21. package/dist/tools/__tests__/{tasks-list-completed.test.js → find-completed-tasks.test.js} +13 -36
  22. package/dist/tools/__tests__/find-projects.test.d.ts +2 -0
  23. package/dist/tools/__tests__/find-projects.test.d.ts.map +1 -0
  24. package/dist/tools/__tests__/{projects-list.test.js → find-projects.test.js} +55 -39
  25. package/dist/tools/__tests__/find-sections.test.d.ts +2 -0
  26. package/dist/tools/__tests__/find-sections.test.d.ts.map +1 -0
  27. package/dist/tools/__tests__/{sections-search.test.js → find-sections.test.js} +64 -50
  28. package/dist/tools/__tests__/find-tasks-by-date.test.d.ts +2 -0
  29. package/dist/tools/__tests__/find-tasks-by-date.test.d.ts.map +1 -0
  30. package/dist/tools/__tests__/{tasks-list-by-date.test.js → find-tasks-by-date.test.js} +96 -14
  31. package/dist/tools/__tests__/find-tasks.test.d.ts +2 -0
  32. package/dist/tools/__tests__/find-tasks.test.d.ts.map +1 -0
  33. package/dist/tools/__tests__/find-tasks.test.js +334 -0
  34. package/dist/tools/__tests__/get-overview.test.d.ts +2 -0
  35. package/dist/tools/__tests__/get-overview.test.d.ts.map +1 -0
  36. package/dist/tools/__tests__/{overview.test.js → get-overview.test.js} +77 -13
  37. package/dist/tools/__tests__/manage-projects.test.d.ts +2 -0
  38. package/dist/tools/__tests__/manage-projects.test.d.ts.map +1 -0
  39. package/dist/tools/__tests__/{projects-manage.test.js → manage-projects.test.js} +33 -30
  40. package/dist/tools/__tests__/manage-sections.test.d.ts +2 -0
  41. package/dist/tools/__tests__/manage-sections.test.d.ts.map +1 -0
  42. package/dist/tools/__tests__/manage-sections.test.js +162 -0
  43. package/dist/tools/__tests__/update-tasks.test.d.ts +2 -0
  44. package/dist/tools/__tests__/update-tasks.test.d.ts.map +1 -0
  45. package/dist/tools/__tests__/update-tasks.test.js +645 -0
  46. package/dist/tools/{tasks-add-multiple.d.ts → add-tasks.d.ts} +36 -16
  47. package/dist/tools/add-tasks.d.ts.map +1 -0
  48. package/dist/tools/{tasks-add-multiple.js → add-tasks.js} +39 -4
  49. package/dist/tools/complete-tasks.d.ts +40 -0
  50. package/dist/tools/complete-tasks.d.ts.map +1 -0
  51. package/dist/tools/complete-tasks.js +68 -0
  52. package/dist/tools/delete-object.d.ts +38 -0
  53. package/dist/tools/delete-object.d.ts.map +1 -0
  54. package/dist/tools/delete-object.js +69 -0
  55. package/dist/tools/find-completed-tasks.d.ts +74 -0
  56. package/dist/tools/find-completed-tasks.d.ts.map +1 -0
  57. package/dist/tools/find-completed-tasks.js +112 -0
  58. package/dist/tools/find-projects.d.ts +53 -0
  59. package/dist/tools/find-projects.d.ts.map +1 -0
  60. package/dist/tools/find-projects.js +101 -0
  61. package/dist/tools/find-sections.d.ts +42 -0
  62. package/dist/tools/find-sections.d.ts.map +1 -0
  63. package/dist/tools/find-sections.js +96 -0
  64. package/dist/tools/find-tasks-by-date.d.ts +59 -0
  65. package/dist/tools/find-tasks-by-date.d.ts.map +1 -0
  66. package/dist/tools/find-tasks-by-date.js +121 -0
  67. package/dist/tools/find-tasks.d.ts +65 -0
  68. package/dist/tools/find-tasks.d.ts.map +1 -0
  69. package/dist/tools/find-tasks.js +182 -0
  70. package/dist/tools/get-overview.d.ts +67 -0
  71. package/dist/tools/get-overview.d.ts.map +1 -0
  72. package/dist/tools/{overview.js → get-overview.js} +66 -19
  73. package/dist/tools/manage-projects.d.ts +35 -0
  74. package/dist/tools/manage-projects.d.ts.map +1 -0
  75. package/dist/tools/manage-projects.js +63 -0
  76. package/dist/tools/manage-sections.d.ts +38 -0
  77. package/dist/tools/manage-sections.d.ts.map +1 -0
  78. package/dist/tools/manage-sections.js +78 -0
  79. package/dist/tools/update-tasks.d.ts +94 -0
  80. package/dist/tools/update-tasks.d.ts.map +1 -0
  81. package/dist/tools/update-tasks.js +120 -0
  82. package/dist/utils/constants.d.ts +35 -0
  83. package/dist/utils/constants.d.ts.map +1 -0
  84. package/dist/utils/constants.js +37 -0
  85. package/dist/utils/response-builders.d.ts +88 -0
  86. package/dist/utils/response-builders.d.ts.map +1 -0
  87. package/dist/utils/response-builders.js +202 -0
  88. package/dist/{tools → utils}/test-helpers.d.ts +16 -0
  89. package/dist/utils/test-helpers.d.ts.map +1 -0
  90. package/dist/{tools → utils}/test-helpers.js +51 -0
  91. package/dist/utils/tool-names.d.ts +23 -0
  92. package/dist/utils/tool-names.d.ts.map +1 -0
  93. package/dist/utils/tool-names.js +25 -0
  94. package/package.json +1 -1
  95. package/dist/tools/__tests__/delete-one.test.d.ts +0 -2
  96. package/dist/tools/__tests__/delete-one.test.d.ts.map +0 -1
  97. package/dist/tools/__tests__/overview.test.d.ts +0 -2
  98. package/dist/tools/__tests__/overview.test.d.ts.map +0 -1
  99. package/dist/tools/__tests__/projects-list.test.d.ts +0 -2
  100. package/dist/tools/__tests__/projects-list.test.d.ts.map +0 -1
  101. package/dist/tools/__tests__/projects-manage.test.d.ts +0 -2
  102. package/dist/tools/__tests__/projects-manage.test.d.ts.map +0 -1
  103. package/dist/tools/__tests__/sections-manage.test.d.ts +0 -2
  104. package/dist/tools/__tests__/sections-manage.test.d.ts.map +0 -1
  105. package/dist/tools/__tests__/sections-manage.test.js +0 -138
  106. package/dist/tools/__tests__/sections-search.test.d.ts +0 -2
  107. package/dist/tools/__tests__/sections-search.test.d.ts.map +0 -1
  108. package/dist/tools/__tests__/tasks-add-multiple.test.d.ts +0 -2
  109. package/dist/tools/__tests__/tasks-add-multiple.test.d.ts.map +0 -1
  110. package/dist/tools/__tests__/tasks-complete-multiple.test.d.ts +0 -2
  111. package/dist/tools/__tests__/tasks-complete-multiple.test.d.ts.map +0 -1
  112. package/dist/tools/__tests__/tasks-complete-multiple.test.js +0 -146
  113. package/dist/tools/__tests__/tasks-list-by-date.test.d.ts +0 -2
  114. package/dist/tools/__tests__/tasks-list-by-date.test.d.ts.map +0 -1
  115. package/dist/tools/__tests__/tasks-list-completed.test.d.ts +0 -2
  116. package/dist/tools/__tests__/tasks-list-completed.test.d.ts.map +0 -1
  117. package/dist/tools/__tests__/tasks-list-for-container.test.d.ts +0 -2
  118. package/dist/tools/__tests__/tasks-list-for-container.test.d.ts.map +0 -1
  119. package/dist/tools/__tests__/tasks-list-for-container.test.js +0 -232
  120. package/dist/tools/__tests__/tasks-organize-multiple.test.d.ts +0 -2
  121. package/dist/tools/__tests__/tasks-organize-multiple.test.d.ts.map +0 -1
  122. package/dist/tools/__tests__/tasks-organize-multiple.test.js +0 -245
  123. package/dist/tools/__tests__/tasks-search.test.d.ts +0 -2
  124. package/dist/tools/__tests__/tasks-search.test.d.ts.map +0 -1
  125. package/dist/tools/__tests__/tasks-search.test.js +0 -106
  126. package/dist/tools/__tests__/tasks-update-one.test.d.ts +0 -2
  127. package/dist/tools/__tests__/tasks-update-one.test.d.ts.map +0 -1
  128. package/dist/tools/__tests__/tasks-update-one.test.js +0 -251
  129. package/dist/tools/delete-one.d.ts +0 -17
  130. package/dist/tools/delete-one.d.ts.map +0 -1
  131. package/dist/tools/delete-one.js +0 -25
  132. package/dist/tools/overview.d.ts +0 -14
  133. package/dist/tools/overview.d.ts.map +0 -1
  134. package/dist/tools/projects-list.d.ts +0 -29
  135. package/dist/tools/projects-list.d.ts.map +0 -1
  136. package/dist/tools/projects-list.js +0 -39
  137. package/dist/tools/projects-manage.d.ts +0 -24
  138. package/dist/tools/projects-manage.d.ts.map +0 -1
  139. package/dist/tools/projects-manage.js +0 -26
  140. package/dist/tools/sections-manage.d.ts +0 -23
  141. package/dist/tools/sections-manage.d.ts.map +0 -1
  142. package/dist/tools/sections-manage.js +0 -37
  143. package/dist/tools/sections-search.d.ts +0 -18
  144. package/dist/tools/sections-search.d.ts.map +0 -1
  145. package/dist/tools/sections-search.js +0 -27
  146. package/dist/tools/tasks-add-multiple.d.ts.map +0 -1
  147. package/dist/tools/tasks-complete-multiple.d.ts +0 -16
  148. package/dist/tools/tasks-complete-multiple.d.ts.map +0 -1
  149. package/dist/tools/tasks-complete-multiple.js +0 -23
  150. package/dist/tools/tasks-list-by-date.d.ts +0 -34
  151. package/dist/tools/tasks-list-by-date.d.ts.map +0 -1
  152. package/dist/tools/tasks-list-by-date.js +0 -53
  153. package/dist/tools/tasks-list-completed.d.ts +0 -44
  154. package/dist/tools/tasks-list-completed.d.ts.map +0 -1
  155. package/dist/tools/tasks-list-completed.js +0 -49
  156. package/dist/tools/tasks-list-for-container.d.ts +0 -34
  157. package/dist/tools/tasks-list-for-container.d.ts.map +0 -1
  158. package/dist/tools/tasks-list-for-container.js +0 -48
  159. package/dist/tools/tasks-organize-multiple.d.ts +0 -37
  160. package/dist/tools/tasks-organize-multiple.d.ts.map +0 -1
  161. package/dist/tools/tasks-organize-multiple.js +0 -34
  162. package/dist/tools/tasks-search.d.ts +0 -32
  163. package/dist/tools/tasks-search.d.ts.map +0 -1
  164. package/dist/tools/tasks-search.js +0 -30
  165. package/dist/tools/tasks-update-one.d.ts +0 -29
  166. package/dist/tools/tasks-update-one.d.ts.map +0 -1
  167. package/dist/tools/tasks-update-one.js +0 -63
  168. package/dist/tools/test-helpers.d.ts.map +0 -1
@@ -1,11 +1,13 @@
1
1
  import { jest } from '@jest/globals';
2
- import { sectionsSearch } from '../sections-search.js';
3
- import { TEST_ERRORS, TEST_IDS, createMockSection } from '../test-helpers.js';
2
+ import { TEST_ERRORS, TEST_IDS, createMockSection, extractStructuredContent, extractTextContent, } from '../../utils/test-helpers.js';
3
+ import { ToolNames } from '../../utils/tool-names.js';
4
+ import { findSections } from '../find-sections.js';
4
5
  // Mock the Todoist API
5
6
  const mockTodoistApi = {
6
7
  getSections: jest.fn(),
7
8
  };
8
- describe('sections-search tool', () => {
9
+ const { FIND_SECTIONS, MANAGE_SECTIONS } = ToolNames;
10
+ describe(`${FIND_SECTIONS} tool`, () => {
9
11
  beforeEach(() => {
10
12
  jest.clearAllMocks();
11
13
  });
@@ -40,29 +42,47 @@ describe('sections-search tool', () => {
40
42
  results: mockSections,
41
43
  nextCursor: null,
42
44
  });
43
- const result = await sectionsSearch.execute({ projectId: TEST_IDS.PROJECT_TEST }, mockTodoistApi);
44
- // Verify API was called correctly
45
+ const result = await findSections.execute({ projectId: TEST_IDS.PROJECT_TEST }, mockTodoistApi);
45
46
  expect(mockTodoistApi.getSections).toHaveBeenCalledWith({
46
47
  projectId: TEST_IDS.PROJECT_TEST,
47
48
  });
48
- // Verify result is properly mapped (simplified format)
49
- expect(result).toEqual([
50
- { id: TEST_IDS.SECTION_1, name: 'To Do' },
51
- { id: TEST_IDS.SECTION_2, name: 'In Progress' },
52
- { id: 'section-789', name: 'Done' },
53
- { id: 'section-999', name: 'Backlog Items' },
54
- ]);
49
+ const textContent = extractTextContent(result);
50
+ expect(textContent).toMatchSnapshot();
51
+ expect(textContent).toContain('Sections in project');
52
+ expect(textContent).toContain('To Do id=');
53
+ expect(textContent).toContain('In Progress id=');
54
+ expect(textContent).toContain('Done id=');
55
+ expect(textContent).toContain('Backlog Items • id=');
56
+ // Verify structured content
57
+ const structuredContent = extractStructuredContent(result);
58
+ expect(structuredContent.sections).toHaveLength(4);
59
+ expect(structuredContent.totalCount).toBe(4);
60
+ expect(structuredContent.appliedFilters).toEqual({
61
+ projectId: TEST_IDS.PROJECT_TEST,
62
+ search: undefined,
63
+ });
55
64
  });
56
65
  it('should handle project with no sections', async () => {
57
66
  mockTodoistApi.getSections.mockResolvedValue({
58
67
  results: [],
59
68
  nextCursor: null,
60
69
  });
61
- const result = await sectionsSearch.execute({ projectId: 'empty-project-id' }, mockTodoistApi);
70
+ const result = await findSections.execute({ projectId: 'empty-project-id' }, mockTodoistApi);
62
71
  expect(mockTodoistApi.getSections).toHaveBeenCalledWith({
63
72
  projectId: 'empty-project-id',
64
73
  });
65
- expect(result).toEqual([]);
74
+ const textContent = extractTextContent(result);
75
+ expect(textContent).toMatchSnapshot();
76
+ expect(textContent).toContain('Project has no sections yet');
77
+ expect(textContent).toContain(`Use ${MANAGE_SECTIONS} to create sections`);
78
+ // Verify structured content
79
+ const structuredContent = extractStructuredContent(result);
80
+ expect(structuredContent.sections).toHaveLength(0);
81
+ expect(structuredContent.totalCount).toBe(0);
82
+ expect(structuredContent.appliedFilters).toEqual({
83
+ projectId: 'empty-project-id',
84
+ search: undefined,
85
+ });
66
86
  });
67
87
  });
68
88
  describe('searching sections by name', () => {
@@ -96,18 +116,16 @@ describe('sections-search tool', () => {
96
116
  results: mockSections,
97
117
  nextCursor: null,
98
118
  });
99
- const result = await sectionsSearch.execute({
100
- projectId: TEST_IDS.PROJECT_TEST,
101
- search: 'progress',
102
- }, mockTodoistApi);
119
+ const result = await findSections.execute({ projectId: TEST_IDS.PROJECT_TEST, search: 'progress' }, mockTodoistApi);
103
120
  expect(mockTodoistApi.getSections).toHaveBeenCalledWith({
104
121
  projectId: TEST_IDS.PROJECT_TEST,
105
122
  });
106
123
  // Should return both "In Progress" and "Progress Review" (case insensitive partial match)
107
- expect(result).toEqual([
108
- { id: TEST_IDS.SECTION_2, name: 'In Progress' },
109
- { id: 'section-999', name: 'Progress Review' },
110
- ]);
124
+ const textContent = extractTextContent(result);
125
+ expect(textContent).toMatchSnapshot();
126
+ expect(textContent).toContain('matching "progress"');
127
+ expect(textContent).toContain('In Progress • id=');
128
+ expect(textContent).toContain('Progress Review • id=');
111
129
  });
112
130
  it('should handle search with no matches', async () => {
113
131
  const mockSections = [
@@ -127,11 +145,12 @@ describe('sections-search tool', () => {
127
145
  results: mockSections,
128
146
  nextCursor: null,
129
147
  });
130
- const result = await sectionsSearch.execute({
131
- projectId: TEST_IDS.PROJECT_TEST,
132
- search: 'nonexistent',
133
- }, mockTodoistApi);
134
- expect(result).toEqual([]);
148
+ const result = await findSections.execute({ projectId: TEST_IDS.PROJECT_TEST, search: 'nonexistent' }, mockTodoistApi);
149
+ const textContent = extractTextContent(result);
150
+ expect(textContent).toMatchSnapshot();
151
+ expect(textContent).toContain('Try broader search terms');
152
+ expect(textContent).toContain('Check spelling');
153
+ expect(textContent).toContain('Remove search to see all sections');
135
154
  });
136
155
  it('should handle case sensitive search correctly', async () => {
137
156
  const mockSections = [
@@ -151,13 +170,12 @@ describe('sections-search tool', () => {
151
170
  results: mockSections,
152
171
  nextCursor: null,
153
172
  });
154
- const result = await sectionsSearch.execute({
155
- projectId: TEST_IDS.PROJECT_TEST,
156
- search: 'IMPORTANT',
157
- }, mockTodoistApi);
173
+ const result = await findSections.execute({ projectId: TEST_IDS.PROJECT_TEST, search: 'IMPORTANT' }, mockTodoistApi);
158
174
  // Should match despite different case
159
- expect(result).toHaveLength(1);
160
- expect(result[0]).toEqual({ id: TEST_IDS.SECTION_1, name: 'Important Tasks' });
175
+ const textContent = extractTextContent(result);
176
+ expect(textContent).toMatchSnapshot();
177
+ expect(textContent).toContain('matching "IMPORTANT"');
178
+ expect(textContent).toContain('Important Tasks • id=');
161
179
  });
162
180
  it('should handle partial matches correctly', async () => {
163
181
  const mockSections = [
@@ -183,15 +201,13 @@ describe('sections-search tool', () => {
183
201
  results: mockSections,
184
202
  nextCursor: null,
185
203
  });
186
- const result = await sectionsSearch.execute({
187
- projectId: TEST_IDS.PROJECT_TEST,
188
- search: 'task',
189
- }, mockTodoistApi);
204
+ const result = await findSections.execute({ projectId: TEST_IDS.PROJECT_TEST, search: 'task' }, mockTodoistApi);
190
205
  // Should match both sections with "task" in the name
191
- expect(result).toEqual([
192
- { id: TEST_IDS.SECTION_1, name: 'Development Tasks' },
193
- { id: TEST_IDS.SECTION_2, name: 'Testing Tasks' },
194
- ]);
206
+ const textContent = extractTextContent(result);
207
+ expect(textContent).toMatchSnapshot();
208
+ expect(textContent).toContain('matching "task"');
209
+ expect(textContent).toContain('Development Tasks • id=');
210
+ expect(textContent).toContain('Testing Tasks • id=');
195
211
  });
196
212
  it('should handle exact matches', async () => {
197
213
  const mockSections = [
@@ -211,15 +227,13 @@ describe('sections-search tool', () => {
211
227
  results: mockSections,
212
228
  nextCursor: null,
213
229
  });
214
- const result = await sectionsSearch.execute({
215
- projectId: TEST_IDS.PROJECT_TEST,
216
- search: 'done',
217
- }, mockTodoistApi);
230
+ const result = await findSections.execute({ projectId: TEST_IDS.PROJECT_TEST, search: 'done' }, mockTodoistApi);
218
231
  // Should match both sections containing "done"
219
- expect(result).toEqual([
220
- { id: TEST_IDS.SECTION_1, name: 'Done' },
221
- { id: TEST_IDS.SECTION_2, name: 'Done Soon' },
222
- ]);
232
+ const textContent = extractTextContent(result);
233
+ expect(textContent).toMatchSnapshot();
234
+ expect(textContent).toContain('matching "done"');
235
+ expect(textContent).toContain('Done • id=');
236
+ expect(textContent).toContain('Done Soon • id=');
223
237
  });
224
238
  });
225
239
  describe('error handling', () => {
@@ -229,7 +243,7 @@ describe('sections-search tool', () => {
229
243
  { error: 'API Error: Invalid project ID format', projectId: 'invalid-id-format' },
230
244
  ])('should propagate $error', async ({ error, projectId }) => {
231
245
  mockTodoistApi.getSections.mockRejectedValue(new Error(error));
232
- await expect(sectionsSearch.execute({ projectId }, mockTodoistApi)).rejects.toThrow(error);
246
+ await expect(findSections.execute({ projectId }, mockTodoistApi)).rejects.toThrow(error);
233
247
  });
234
248
  });
235
249
  });
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=find-tasks-by-date.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"find-tasks-by-date.test.d.ts","sourceRoot":"","sources":["../../../src/tools/__tests__/find-tasks-by-date.test.ts"],"names":[],"mappings":""}
@@ -1,13 +1,14 @@
1
1
  import { jest } from '@jest/globals';
2
2
  import { getTasksByFilter } from '../../tool-helpers.js';
3
- import { tasksListByDate } from '../tasks-list-by-date.js';
4
- import { TEST_ERRORS, TEST_IDS, createMappedTask } from '../test-helpers.js';
3
+ import { TEST_ERRORS, TEST_IDS, createMappedTask, extractStructuredContent, extractTextContent, } from '../../utils/test-helpers.js';
4
+ import { ToolNames } from '../../utils/tool-names.js';
5
+ import { findTasksByDate } from '../find-tasks-by-date.js';
5
6
  // Mock the tool helpers
6
7
  jest.mock('../../tool-helpers', () => ({
7
8
  getTasksByFilter: jest.fn(),
8
9
  }));
9
10
  const mockGetTasksByFilter = getTasksByFilter;
10
- // Mock the Todoist API (not directly used by tasks-list-by-date, but needed for type)
11
+ // Mock the Todoist API (not directly used by find-tasks-by-date, but needed for type)
11
12
  const mockTodoistApi = {};
12
13
  // Mock date-fns functions to make tests deterministic
13
14
  jest.mock('date-fns', () => ({
@@ -25,7 +26,8 @@ jest.mock('date-fns', () => ({
25
26
  return '2025-08-16'; // Return predictable end date
26
27
  }),
27
28
  }));
28
- describe('tasks-list-by-date tool', () => {
29
+ const { FIND_TASKS_BY_DATE, UPDATE_TASKS } = ToolNames;
30
+ describe(`${FIND_TASKS_BY_DATE} tool`, () => {
29
31
  beforeEach(() => {
30
32
  jest.clearAllMocks();
31
33
  // Mock current date to make tests deterministic
@@ -52,14 +54,26 @@ describe('tasks-list-by-date tool', () => {
52
54
  : [];
53
55
  const mockResponse = { tasks: mockTasks, nextCursor: null };
54
56
  mockGetTasksByFilter.mockResolvedValue(mockResponse);
55
- const result = await tasksListByDate.execute({ startDate: 'overdue', limit: 50, daysCount }, mockTodoistApi);
57
+ const result = await findTasksByDate.execute({ startDate: 'overdue', limit: 50, daysCount }, mockTodoistApi);
56
58
  expect(mockGetTasksByFilter).toHaveBeenCalledWith({
57
59
  client: mockTodoistApi,
58
60
  query: 'overdue',
59
61
  cursor: undefined,
60
62
  limit: 50,
61
63
  });
62
- expect(result).toEqual(mockResponse);
64
+ // Verify result is a concise summary
65
+ expect(extractTextContent(result)).toMatchSnapshot();
66
+ // Verify structured content
67
+ const structuredContent = extractStructuredContent(result);
68
+ expect(structuredContent.tasks).toHaveLength(hasTasks ? 1 : 0);
69
+ expect(structuredContent).toEqual(expect.objectContaining({
70
+ totalCount: hasTasks ? 1 : 0,
71
+ hasMore: false,
72
+ nextCursor: null,
73
+ appliedFilters: expect.objectContaining({
74
+ startDate: 'overdue',
75
+ }),
76
+ }));
63
77
  });
64
78
  });
65
79
  describe('listing tasks by date range', () => {
@@ -67,14 +81,15 @@ describe('tasks-list-by-date tool', () => {
67
81
  const mockTasks = [createMappedTask({ content: 'Today task', dueDate: '2025-08-15' })];
68
82
  const mockResponse = { tasks: mockTasks, nextCursor: null };
69
83
  mockGetTasksByFilter.mockResolvedValue(mockResponse);
70
- const result = await tasksListByDate.execute({ startDate: 'today', limit: 50, daysCount: 7 }, mockTodoistApi);
84
+ const result = await findTasksByDate.execute({ startDate: 'today', limit: 50, daysCount: 7 }, mockTodoistApi);
71
85
  expect(mockGetTasksByFilter).toHaveBeenCalledWith({
72
86
  client: mockTodoistApi,
73
87
  query: expect.stringContaining('due after:') && expect.stringContaining('due before:'),
74
88
  cursor: undefined,
75
89
  limit: 50,
76
90
  });
77
- expect(result).toEqual(mockResponse);
91
+ // Verify result is a concise summary
92
+ expect(extractTextContent(result)).toMatchSnapshot();
78
93
  });
79
94
  it.each([
80
95
  {
@@ -108,14 +123,15 @@ describe('tasks-list-by-date tool', () => {
108
123
  ])('should handle $name', async ({ params, tasks, cursor }) => {
109
124
  const mockResponse = { tasks, nextCursor: cursor };
110
125
  mockGetTasksByFilter.mockResolvedValue(mockResponse);
111
- const result = await tasksListByDate.execute(params, mockTodoistApi);
126
+ const result = await findTasksByDate.execute(params, mockTodoistApi);
112
127
  expect(mockGetTasksByFilter).toHaveBeenCalledWith({
113
128
  client: mockTodoistApi,
114
129
  query: expect.stringContaining('2025-08-20'),
115
130
  cursor: params.cursor || undefined,
116
131
  limit: params.limit,
117
132
  });
118
- expect(result).toEqual(mockResponse);
133
+ // Verify result is a concise summary
134
+ expect(extractTextContent(result)).toMatchSnapshot();
119
135
  });
120
136
  });
121
137
  describe('pagination and limits', () => {
@@ -140,7 +156,7 @@ describe('tasks-list-by-date tool', () => {
140
156
  ])('should handle $name', async ({ params, expectedCursor, expectedLimit }) => {
141
157
  const mockResponse = { tasks: [], nextCursor: null };
142
158
  mockGetTasksByFilter.mockResolvedValue(mockResponse);
143
- await tasksListByDate.execute(params, mockTodoistApi);
159
+ await findTasksByDate.execute(params, mockTodoistApi);
144
160
  expect(mockGetTasksByFilter).toHaveBeenCalledWith({
145
161
  client: mockTodoistApi,
146
162
  query: expect.any(String),
@@ -158,13 +174,79 @@ describe('tasks-list-by-date tool', () => {
158
174
  const mockResponse = { tasks: [], nextCursor: null };
159
175
  mockGetTasksByFilter.mockResolvedValue(mockResponse);
160
176
  const startDate = daysCount === 7 ? 'today' : '2025-08-15';
161
- const result = await tasksListByDate.execute({ startDate, limit: 50, daysCount }, mockTodoistApi);
177
+ const result = await findTasksByDate.execute({ startDate, limit: 50, daysCount }, mockTodoistApi);
162
178
  expect(mockGetTasksByFilter).toHaveBeenCalledTimes(1);
163
179
  if (shouldReturnResult) {
164
- expect(result).toEqual(mockResponse);
180
+ // Verify result is a concise summary
181
+ expect(extractTextContent(result)).toMatchSnapshot();
165
182
  }
166
183
  });
167
184
  });
185
+ describe('next steps logic', () => {
186
+ it('should suggest appropriate actions when hasOverdue is true', async () => {
187
+ const mockTasks = [
188
+ createMappedTask({
189
+ id: TEST_IDS.TASK_1,
190
+ content: 'Overdue task from list',
191
+ dueDate: '2025-08-10', // Past date - creates hasOverdue context
192
+ }),
193
+ ];
194
+ const mockResponse = { tasks: mockTasks, nextCursor: null };
195
+ mockGetTasksByFilter.mockResolvedValue(mockResponse);
196
+ const result = await findTasksByDate.execute({ startDate: '2025-08-15', limit: 10, daysCount: 1 }, mockTodoistApi);
197
+ const textContent = extractTextContent(result);
198
+ expect(textContent).toMatchSnapshot();
199
+ expect(textContent).toContain(`Use ${UPDATE_TASKS} to modify priorities or due dates`);
200
+ });
201
+ it('should suggest today-focused actions when startDate is today', async () => {
202
+ const mockTasks = [
203
+ createMappedTask({
204
+ id: TEST_IDS.TASK_1,
205
+ content: "Today's task",
206
+ dueDate: '2025-08-15', // Today's date based on our mock
207
+ }),
208
+ ];
209
+ const mockResponse = { tasks: mockTasks, nextCursor: null };
210
+ mockGetTasksByFilter.mockResolvedValue(mockResponse);
211
+ const result = await findTasksByDate.execute({ startDate: 'today', limit: 10, daysCount: 1 }, mockTodoistApi);
212
+ const textContent = extractTextContent(result);
213
+ expect(textContent).toMatchSnapshot();
214
+ expect(textContent).toContain(`Use ${UPDATE_TASKS} to modify priorities or due dates`);
215
+ });
216
+ it('should suggest appropriate actions when startDate is overdue', async () => {
217
+ const mockTasks = [
218
+ createMappedTask({
219
+ id: TEST_IDS.TASK_1,
220
+ content: 'Overdue task',
221
+ dueDate: '2025-08-10',
222
+ }),
223
+ ];
224
+ const mockResponse = { tasks: mockTasks, nextCursor: null };
225
+ mockGetTasksByFilter.mockResolvedValue(mockResponse);
226
+ const result = await findTasksByDate.execute({ startDate: 'overdue', limit: 10, daysCount: 1 }, mockTodoistApi);
227
+ const textContent = extractTextContent(result);
228
+ expect(textContent).toMatchSnapshot();
229
+ expect(textContent).toContain(`Use ${UPDATE_TASKS} to modify priorities or due dates`);
230
+ });
231
+ it('should provide helpful suggestions for empty overdue results', async () => {
232
+ const mockResponse = { tasks: [], nextCursor: null };
233
+ mockGetTasksByFilter.mockResolvedValue(mockResponse);
234
+ const result = await findTasksByDate.execute({ startDate: 'overdue', limit: 10, daysCount: 1 }, mockTodoistApi);
235
+ const textContent = extractTextContent(result);
236
+ expect(textContent).toMatchSnapshot();
237
+ expect(textContent).toContain('Great job! No overdue tasks');
238
+ expect(textContent).toContain("Check today's tasks with startDate='today'");
239
+ });
240
+ it('should provide helpful suggestions for empty date range results', async () => {
241
+ const mockResponse = { tasks: [], nextCursor: null };
242
+ mockGetTasksByFilter.mockResolvedValue(mockResponse);
243
+ const result = await findTasksByDate.execute({ startDate: '2025-08-20', limit: 10, daysCount: 1 }, mockTodoistApi);
244
+ const textContent = extractTextContent(result);
245
+ expect(textContent).toMatchSnapshot();
246
+ expect(textContent).toContain("Expand date range with larger 'daysCount'");
247
+ expect(textContent).toContain("Check 'overdue' for past-due items");
248
+ });
249
+ });
168
250
  describe('error handling', () => {
169
251
  it.each([
170
252
  {
@@ -186,7 +268,7 @@ describe('tasks-list-by-date tool', () => {
186
268
  },
187
269
  ])('should propagate $error', async ({ error, params }) => {
188
270
  mockGetTasksByFilter.mockRejectedValue(new Error(error));
189
- await expect(tasksListByDate.execute(params, mockTodoistApi)).rejects.toThrow(error);
271
+ await expect(findTasksByDate.execute(params, mockTodoistApi)).rejects.toThrow(error);
190
272
  });
191
273
  });
192
274
  });
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=find-tasks.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"find-tasks.test.d.ts","sourceRoot":"","sources":["../../../src/tools/__tests__/find-tasks.test.ts"],"names":[],"mappings":""}