@doist/todoist-ai 2.2.2 → 4.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 (202) hide show
  1. package/README.md +6 -14
  2. package/dist/index.d.ts +619 -250
  3. package/dist/index.d.ts.map +1 -1
  4. package/dist/index.js +45 -29
  5. package/dist/main.js +2 -1
  6. package/dist/mcp-helpers.d.ts +25 -3
  7. package/dist/mcp-helpers.d.ts.map +1 -1
  8. package/dist/mcp-helpers.js +37 -19
  9. package/dist/mcp-server.d.ts.map +1 -1
  10. package/dist/mcp-server.js +44 -28
  11. package/dist/tools/__tests__/add-comments.test.d.ts +2 -0
  12. package/dist/tools/__tests__/add-comments.test.d.ts.map +1 -0
  13. package/dist/tools/__tests__/add-comments.test.js +241 -0
  14. package/dist/tools/__tests__/add-projects.test.d.ts +2 -0
  15. package/dist/tools/__tests__/add-projects.test.d.ts.map +1 -0
  16. package/dist/tools/__tests__/add-projects.test.js +152 -0
  17. package/dist/tools/__tests__/add-sections.test.d.ts +2 -0
  18. package/dist/tools/__tests__/add-sections.test.d.ts.map +1 -0
  19. package/dist/tools/__tests__/add-sections.test.js +181 -0
  20. package/dist/tools/__tests__/add-tasks.test.d.ts +2 -0
  21. package/dist/tools/__tests__/add-tasks.test.d.ts.map +1 -0
  22. package/dist/tools/__tests__/{tasks-add-multiple.test.js → add-tasks.test.js} +89 -79
  23. package/dist/tools/__tests__/complete-tasks.test.d.ts +2 -0
  24. package/dist/tools/__tests__/complete-tasks.test.d.ts.map +1 -0
  25. package/dist/tools/__tests__/complete-tasks.test.js +206 -0
  26. package/dist/tools/__tests__/delete-object.test.d.ts +2 -0
  27. package/dist/tools/__tests__/delete-object.test.d.ts.map +1 -0
  28. package/dist/tools/__tests__/{delete-one.test.js → delete-object.test.js} +42 -22
  29. package/dist/tools/__tests__/find-comments.test.d.ts +2 -0
  30. package/dist/tools/__tests__/find-comments.test.d.ts.map +1 -0
  31. package/dist/tools/__tests__/find-comments.test.js +242 -0
  32. package/dist/tools/__tests__/find-completed-tasks.test.d.ts +2 -0
  33. package/dist/tools/__tests__/find-completed-tasks.test.d.ts.map +1 -0
  34. package/dist/tools/__tests__/{tasks-list-completed.test.js → find-completed-tasks.test.js} +13 -36
  35. package/dist/tools/__tests__/find-projects.test.d.ts +2 -0
  36. package/dist/tools/__tests__/find-projects.test.d.ts.map +1 -0
  37. package/dist/tools/__tests__/{projects-list.test.js → find-projects.test.js} +55 -39
  38. package/dist/tools/__tests__/find-sections.test.d.ts +2 -0
  39. package/dist/tools/__tests__/find-sections.test.d.ts.map +1 -0
  40. package/dist/tools/__tests__/{sections-search.test.js → find-sections.test.js} +64 -50
  41. package/dist/tools/__tests__/find-tasks-by-date.test.d.ts +2 -0
  42. package/dist/tools/__tests__/find-tasks-by-date.test.d.ts.map +1 -0
  43. package/dist/tools/__tests__/{tasks-list-by-date.test.js → find-tasks-by-date.test.js} +96 -14
  44. package/dist/tools/__tests__/find-tasks.test.d.ts +2 -0
  45. package/dist/tools/__tests__/find-tasks.test.d.ts.map +1 -0
  46. package/dist/tools/__tests__/find-tasks.test.js +334 -0
  47. package/dist/tools/__tests__/get-overview.test.d.ts +2 -0
  48. package/dist/tools/__tests__/get-overview.test.d.ts.map +1 -0
  49. package/dist/tools/__tests__/{overview.test.js → get-overview.test.js} +77 -13
  50. package/dist/tools/__tests__/update-comments.test.d.ts +2 -0
  51. package/dist/tools/__tests__/update-comments.test.d.ts.map +1 -0
  52. package/dist/tools/__tests__/update-comments.test.js +296 -0
  53. package/dist/tools/__tests__/update-projects.test.d.ts +2 -0
  54. package/dist/tools/__tests__/update-projects.test.d.ts.map +1 -0
  55. package/dist/tools/__tests__/update-projects.test.js +205 -0
  56. package/dist/tools/__tests__/update-sections.test.d.ts +2 -0
  57. package/dist/tools/__tests__/update-sections.test.d.ts.map +1 -0
  58. package/dist/tools/__tests__/update-sections.test.js +156 -0
  59. package/dist/tools/__tests__/update-tasks.test.d.ts +2 -0
  60. package/dist/tools/__tests__/update-tasks.test.d.ts.map +1 -0
  61. package/dist/tools/__tests__/update-tasks.test.js +645 -0
  62. package/dist/tools/add-comments.d.ts +51 -0
  63. package/dist/tools/add-comments.d.ts.map +1 -0
  64. package/dist/tools/add-comments.js +79 -0
  65. package/dist/tools/add-projects.d.ts +50 -0
  66. package/dist/tools/add-projects.d.ts.map +1 -0
  67. package/dist/tools/add-projects.js +59 -0
  68. package/dist/tools/add-sections.d.ts +46 -0
  69. package/dist/tools/add-sections.d.ts.map +1 -0
  70. package/dist/tools/add-sections.js +61 -0
  71. package/dist/tools/add-tasks.d.ts +82 -0
  72. package/dist/tools/add-tasks.d.ts.map +1 -0
  73. package/dist/tools/add-tasks.js +96 -0
  74. package/dist/tools/complete-tasks.d.ts +40 -0
  75. package/dist/tools/complete-tasks.d.ts.map +1 -0
  76. package/dist/tools/complete-tasks.js +68 -0
  77. package/dist/tools/delete-object.d.ts +38 -0
  78. package/dist/tools/delete-object.d.ts.map +1 -0
  79. package/dist/tools/delete-object.js +79 -0
  80. package/dist/tools/find-comments.d.ts +46 -0
  81. package/dist/tools/find-comments.d.ts.map +1 -0
  82. package/dist/tools/find-comments.js +143 -0
  83. package/dist/tools/find-completed-tasks.d.ts +74 -0
  84. package/dist/tools/find-completed-tasks.d.ts.map +1 -0
  85. package/dist/tools/find-completed-tasks.js +112 -0
  86. package/dist/tools/find-projects.d.ts +53 -0
  87. package/dist/tools/find-projects.d.ts.map +1 -0
  88. package/dist/tools/find-projects.js +101 -0
  89. package/dist/tools/find-sections.d.ts +42 -0
  90. package/dist/tools/find-sections.d.ts.map +1 -0
  91. package/dist/tools/find-sections.js +96 -0
  92. package/dist/tools/find-tasks-by-date.d.ts +59 -0
  93. package/dist/tools/find-tasks-by-date.d.ts.map +1 -0
  94. package/dist/tools/find-tasks-by-date.js +121 -0
  95. package/dist/tools/find-tasks.d.ts +65 -0
  96. package/dist/tools/find-tasks.d.ts.map +1 -0
  97. package/dist/tools/find-tasks.js +182 -0
  98. package/dist/tools/get-overview.d.ts +67 -0
  99. package/dist/tools/get-overview.d.ts.map +1 -0
  100. package/dist/tools/{overview.js → get-overview.js} +66 -19
  101. package/dist/tools/update-comments.d.ts +50 -0
  102. package/dist/tools/update-comments.d.ts.map +1 -0
  103. package/dist/tools/update-comments.js +82 -0
  104. package/dist/tools/update-projects.d.ts +59 -0
  105. package/dist/tools/update-projects.d.ts.map +1 -0
  106. package/dist/tools/update-projects.js +84 -0
  107. package/dist/tools/update-sections.d.ts +47 -0
  108. package/dist/tools/update-sections.d.ts.map +1 -0
  109. package/dist/tools/update-sections.js +70 -0
  110. package/dist/tools/update-tasks.d.ts +94 -0
  111. package/dist/tools/update-tasks.d.ts.map +1 -0
  112. package/dist/tools/update-tasks.js +120 -0
  113. package/dist/utils/constants.d.ts +39 -0
  114. package/dist/utils/constants.d.ts.map +1 -0
  115. package/dist/utils/constants.js +41 -0
  116. package/dist/utils/response-builders.d.ts +88 -0
  117. package/dist/utils/response-builders.d.ts.map +1 -0
  118. package/dist/utils/response-builders.js +202 -0
  119. package/dist/{tools → utils}/test-helpers.d.ts +16 -0
  120. package/dist/utils/test-helpers.d.ts.map +1 -0
  121. package/dist/{tools → utils}/test-helpers.js +51 -0
  122. package/dist/utils/tool-names.d.ts +28 -0
  123. package/dist/utils/tool-names.d.ts.map +1 -0
  124. package/dist/utils/tool-names.js +31 -0
  125. package/package.json +1 -1
  126. package/dist/tools/__tests__/delete-one.test.d.ts +0 -2
  127. package/dist/tools/__tests__/delete-one.test.d.ts.map +0 -1
  128. package/dist/tools/__tests__/overview.test.d.ts +0 -2
  129. package/dist/tools/__tests__/overview.test.d.ts.map +0 -1
  130. package/dist/tools/__tests__/projects-list.test.d.ts +0 -2
  131. package/dist/tools/__tests__/projects-list.test.d.ts.map +0 -1
  132. package/dist/tools/__tests__/projects-manage.test.d.ts +0 -2
  133. package/dist/tools/__tests__/projects-manage.test.d.ts.map +0 -1
  134. package/dist/tools/__tests__/projects-manage.test.js +0 -106
  135. package/dist/tools/__tests__/sections-manage.test.d.ts +0 -2
  136. package/dist/tools/__tests__/sections-manage.test.d.ts.map +0 -1
  137. package/dist/tools/__tests__/sections-manage.test.js +0 -138
  138. package/dist/tools/__tests__/sections-search.test.d.ts +0 -2
  139. package/dist/tools/__tests__/sections-search.test.d.ts.map +0 -1
  140. package/dist/tools/__tests__/tasks-add-multiple.test.d.ts +0 -2
  141. package/dist/tools/__tests__/tasks-add-multiple.test.d.ts.map +0 -1
  142. package/dist/tools/__tests__/tasks-complete-multiple.test.d.ts +0 -2
  143. package/dist/tools/__tests__/tasks-complete-multiple.test.d.ts.map +0 -1
  144. package/dist/tools/__tests__/tasks-complete-multiple.test.js +0 -146
  145. package/dist/tools/__tests__/tasks-list-by-date.test.d.ts +0 -2
  146. package/dist/tools/__tests__/tasks-list-by-date.test.d.ts.map +0 -1
  147. package/dist/tools/__tests__/tasks-list-completed.test.d.ts +0 -2
  148. package/dist/tools/__tests__/tasks-list-completed.test.d.ts.map +0 -1
  149. package/dist/tools/__tests__/tasks-list-for-container.test.d.ts +0 -2
  150. package/dist/tools/__tests__/tasks-list-for-container.test.d.ts.map +0 -1
  151. package/dist/tools/__tests__/tasks-list-for-container.test.js +0 -232
  152. package/dist/tools/__tests__/tasks-organize-multiple.test.d.ts +0 -2
  153. package/dist/tools/__tests__/tasks-organize-multiple.test.d.ts.map +0 -1
  154. package/dist/tools/__tests__/tasks-organize-multiple.test.js +0 -245
  155. package/dist/tools/__tests__/tasks-search.test.d.ts +0 -2
  156. package/dist/tools/__tests__/tasks-search.test.d.ts.map +0 -1
  157. package/dist/tools/__tests__/tasks-search.test.js +0 -106
  158. package/dist/tools/__tests__/tasks-update-one.test.d.ts +0 -2
  159. package/dist/tools/__tests__/tasks-update-one.test.d.ts.map +0 -1
  160. package/dist/tools/__tests__/tasks-update-one.test.js +0 -251
  161. package/dist/tools/delete-one.d.ts +0 -17
  162. package/dist/tools/delete-one.d.ts.map +0 -1
  163. package/dist/tools/delete-one.js +0 -25
  164. package/dist/tools/overview.d.ts +0 -14
  165. package/dist/tools/overview.d.ts.map +0 -1
  166. package/dist/tools/projects-list.d.ts +0 -29
  167. package/dist/tools/projects-list.d.ts.map +0 -1
  168. package/dist/tools/projects-list.js +0 -39
  169. package/dist/tools/projects-manage.d.ts +0 -24
  170. package/dist/tools/projects-manage.d.ts.map +0 -1
  171. package/dist/tools/projects-manage.js +0 -26
  172. package/dist/tools/sections-manage.d.ts +0 -23
  173. package/dist/tools/sections-manage.d.ts.map +0 -1
  174. package/dist/tools/sections-manage.js +0 -37
  175. package/dist/tools/sections-search.d.ts +0 -18
  176. package/dist/tools/sections-search.d.ts.map +0 -1
  177. package/dist/tools/sections-search.js +0 -27
  178. package/dist/tools/tasks-add-multiple.d.ts +0 -55
  179. package/dist/tools/tasks-add-multiple.d.ts.map +0 -1
  180. package/dist/tools/tasks-add-multiple.js +0 -52
  181. package/dist/tools/tasks-complete-multiple.d.ts +0 -16
  182. package/dist/tools/tasks-complete-multiple.d.ts.map +0 -1
  183. package/dist/tools/tasks-complete-multiple.js +0 -23
  184. package/dist/tools/tasks-list-by-date.d.ts +0 -34
  185. package/dist/tools/tasks-list-by-date.d.ts.map +0 -1
  186. package/dist/tools/tasks-list-by-date.js +0 -53
  187. package/dist/tools/tasks-list-completed.d.ts +0 -44
  188. package/dist/tools/tasks-list-completed.d.ts.map +0 -1
  189. package/dist/tools/tasks-list-completed.js +0 -49
  190. package/dist/tools/tasks-list-for-container.d.ts +0 -34
  191. package/dist/tools/tasks-list-for-container.d.ts.map +0 -1
  192. package/dist/tools/tasks-list-for-container.js +0 -48
  193. package/dist/tools/tasks-organize-multiple.d.ts +0 -37
  194. package/dist/tools/tasks-organize-multiple.d.ts.map +0 -1
  195. package/dist/tools/tasks-organize-multiple.js +0 -34
  196. package/dist/tools/tasks-search.d.ts +0 -32
  197. package/dist/tools/tasks-search.d.ts.map +0 -1
  198. package/dist/tools/tasks-search.js +0 -30
  199. package/dist/tools/tasks-update-one.d.ts +0 -29
  200. package/dist/tools/tasks-update-one.d.ts.map +0 -1
  201. package/dist/tools/tasks-update-one.js +0 -63
  202. package/dist/tools/test-helpers.d.ts.map +0 -1
@@ -1,12 +1,14 @@
1
1
  import { jest } from '@jest/globals';
2
- import { tasksListCompleted } from '../tasks-list-completed.js';
3
- import { createMockTask } from '../test-helpers.js';
2
+ import { createMockTask, extractTextContent } from '../../utils/test-helpers.js';
3
+ import { ToolNames } from '../../utils/tool-names.js';
4
+ import { findCompletedTasks } from '../find-completed-tasks.js';
4
5
  // Mock the Todoist API
5
6
  const mockTodoistApi = {
6
7
  getCompletedTasksByCompletionDate: jest.fn(),
7
8
  getCompletedTasksByDueDate: jest.fn(),
8
9
  };
9
- describe('tasks-list-completed tool', () => {
10
+ const { FIND_COMPLETED_TASKS } = ToolNames;
11
+ describe(`${FIND_COMPLETED_TASKS} tool`, () => {
10
12
  beforeEach(() => {
11
13
  jest.clearAllMocks();
12
14
  });
@@ -35,32 +37,20 @@ describe('tasks-list-completed tool', () => {
35
37
  items: mockCompletedTasks,
36
38
  nextCursor: null,
37
39
  });
38
- const result = await tasksListCompleted.execute({ getBy: 'completion', limit: 50, since: '2025-08-10', until: '2025-08-15' }, mockTodoistApi);
40
+ const result = await findCompletedTasks.execute({ getBy: 'completion', limit: 50, since: '2025-08-10', until: '2025-08-15' }, mockTodoistApi);
39
41
  expect(mockTodoistApi.getCompletedTasksByCompletionDate).toHaveBeenCalledWith({
40
42
  since: '2025-08-10',
41
43
  until: '2025-08-15',
42
44
  limit: 50,
43
45
  });
44
- expect(result).toEqual({
45
- tasks: [
46
- expect.objectContaining({
47
- id: '8485093748',
48
- content: 'Completed task 1',
49
- description: 'Task completed yesterday',
50
- dueDate: '2025-08-14',
51
- priority: 2,
52
- labels: ['work'],
53
- }),
54
- ],
55
- nextCursor: null,
56
- });
46
+ expect(extractTextContent(result)).toMatchSnapshot();
57
47
  });
58
48
  it('should handle explicit completion date query', async () => {
59
49
  mockTodoistApi.getCompletedTasksByCompletionDate.mockResolvedValue({
60
50
  items: [],
61
51
  nextCursor: 'next-cursor',
62
52
  });
63
- const result = await tasksListCompleted.execute({
53
+ const result = await findCompletedTasks.execute({
64
54
  getBy: 'completion',
65
55
  limit: 100,
66
56
  since: '2025-08-01',
@@ -75,7 +65,7 @@ describe('tasks-list-completed tool', () => {
75
65
  limit: 100,
76
66
  cursor: 'current-cursor',
77
67
  });
78
- expect(result).toEqual({ tasks: [], nextCursor: 'next-cursor' });
68
+ expect(extractTextContent(result)).toMatchSnapshot();
79
69
  });
80
70
  });
81
71
  describe('getting completed tasks by due date', () => {
@@ -103,7 +93,7 @@ describe('tasks-list-completed tool', () => {
103
93
  items: mockCompletedTasks,
104
94
  nextCursor: null,
105
95
  });
106
- const result = await tasksListCompleted.execute({
96
+ const result = await findCompletedTasks.execute({
107
97
  getBy: 'due',
108
98
  limit: 50,
109
99
  since: '2025-08-10',
@@ -115,34 +105,21 @@ describe('tasks-list-completed tool', () => {
115
105
  limit: 50,
116
106
  });
117
107
  expect(mockTodoistApi.getCompletedTasksByCompletionDate).not.toHaveBeenCalled();
118
- expect(result).toEqual({
119
- tasks: [
120
- expect.objectContaining({
121
- id: '8485093750',
122
- content: 'Task completed by due date',
123
- description: 'This task was due and completed',
124
- dueDate: '2025-08-15',
125
- recurring: 'every Monday',
126
- priority: 3,
127
- labels: ['urgent'],
128
- }),
129
- ],
130
- nextCursor: null,
131
- });
108
+ expect(extractTextContent(result)).toMatchSnapshot();
132
109
  });
133
110
  });
134
111
  describe('error handling', () => {
135
112
  it('should propagate completion date API errors', async () => {
136
113
  const apiError = new Error('API Error: Invalid date range');
137
114
  mockTodoistApi.getCompletedTasksByCompletionDate.mockRejectedValue(apiError);
138
- await expect(tasksListCompleted.execute(
115
+ await expect(findCompletedTasks.execute(
139
116
  // invalid date range
140
117
  { getBy: 'completion', limit: 50, since: '2025-08-31', until: '2025-08-01' }, mockTodoistApi)).rejects.toThrow('API Error: Invalid date range');
141
118
  });
142
119
  it('should propagate due date API errors', async () => {
143
120
  const apiError = new Error('API Error: Project not found');
144
121
  mockTodoistApi.getCompletedTasksByDueDate.mockRejectedValue(apiError);
145
- await expect(tasksListCompleted.execute({
122
+ await expect(findCompletedTasks.execute({
146
123
  getBy: 'due',
147
124
  limit: 50,
148
125
  since: '2025-08-01',
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=find-projects.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"find-projects.test.d.ts","sourceRoot":"","sources":["../../../src/tools/__tests__/find-projects.test.ts"],"names":[],"mappings":""}
@@ -1,11 +1,13 @@
1
1
  import { jest } from '@jest/globals';
2
- import { projectsList } from '../projects-list.js';
3
- import { TEST_ERRORS, TEST_IDS, createMockApiResponse, createMockProject } from '../test-helpers.js';
2
+ import { TEST_ERRORS, TEST_IDS, createMockApiResponse, createMockProject, extractStructuredContent, extractTextContent, } from '../../utils/test-helpers.js';
3
+ import { ToolNames } from '../../utils/tool-names.js';
4
+ import { findProjects } from '../find-projects.js';
4
5
  // Mock the Todoist API
5
6
  const mockTodoistApi = {
6
7
  getProjects: jest.fn(),
7
8
  };
8
- describe('projects-list tool', () => {
9
+ const { FIND_PROJECTS } = ToolNames;
10
+ describe(`${FIND_PROJECTS} tool`, () => {
9
11
  beforeEach(() => {
10
12
  jest.clearAllMocks();
11
13
  });
@@ -38,37 +40,27 @@ describe('projects-list tool', () => {
38
40
  }),
39
41
  ];
40
42
  mockTodoistApi.getProjects.mockResolvedValue(createMockApiResponse(mockProjects));
41
- const result = await projectsList.execute({ limit: 50 }, mockTodoistApi);
43
+ const result = await findProjects.execute({ limit: 50 }, mockTodoistApi);
42
44
  // Verify API was called correctly
43
45
  expect(mockTodoistApi.getProjects).toHaveBeenCalledWith({
44
46
  limit: 50,
45
47
  cursor: null,
46
48
  });
47
- // Verify result is properly mapped
48
- expect(result).toEqual({
49
- projects: [
50
- expect.objectContaining({
51
- id: TEST_IDS.PROJECT_INBOX,
52
- name: 'Inbox',
53
- color: 'grey',
54
- inboxProject: true,
55
- }),
56
- expect.objectContaining({
57
- id: TEST_IDS.PROJECT_TEST,
58
- name: 'test-abc123def456-project',
59
- color: 'charcoal',
60
- }),
61
- expect.objectContaining({
62
- id: TEST_IDS.PROJECT_WORK,
63
- name: 'Work Project',
64
- color: 'blue',
65
- isFavorite: true,
66
- isShared: true,
67
- viewStyle: 'board',
68
- }),
69
- ],
49
+ expect(extractTextContent(result)).toMatchSnapshot();
50
+ // Verify structured content
51
+ const structuredContent = extractStructuredContent(result);
52
+ expect(structuredContent).toEqual(expect.objectContaining({
53
+ projects: expect.any(Array),
54
+ totalCount: 3,
55
+ hasMore: false,
70
56
  nextCursor: null,
71
- });
57
+ appliedFilters: {
58
+ search: undefined,
59
+ limit: 50,
60
+ cursor: undefined,
61
+ },
62
+ }));
63
+ expect(structuredContent.projects).toHaveLength(3);
72
64
  });
73
65
  it('should handle pagination with limit and cursor', async () => {
74
66
  const mockProject = createMockProject({
@@ -77,14 +69,23 @@ describe('projects-list tool', () => {
77
69
  color: 'red',
78
70
  });
79
71
  mockTodoistApi.getProjects.mockResolvedValue(createMockApiResponse([mockProject], 'next-page-cursor'));
80
- const result = await projectsList.execute({ limit: 10, cursor: 'current-page-cursor' }, mockTodoistApi);
72
+ const result = await findProjects.execute({ limit: 10, cursor: 'current-page-cursor' }, mockTodoistApi);
81
73
  expect(mockTodoistApi.getProjects).toHaveBeenCalledWith({
82
74
  limit: 10,
83
75
  cursor: 'current-page-cursor',
84
76
  });
85
- expect(result.projects).toHaveLength(1);
86
- expect(result.projects[0]?.name).toBe('First Project');
87
- expect(result.nextCursor).toBe('next-page-cursor');
77
+ expect(extractTextContent(result)).toMatchSnapshot();
78
+ // Verify structured content
79
+ const structuredContent = extractStructuredContent(result);
80
+ expect(structuredContent.projects).toHaveLength(1);
81
+ expect(structuredContent.totalCount).toBe(1);
82
+ expect(structuredContent.hasMore).toBe(true);
83
+ expect(structuredContent.nextCursor).toBe('next-page-cursor');
84
+ expect(structuredContent.appliedFilters).toEqual({
85
+ search: undefined,
86
+ limit: 10,
87
+ cursor: 'current-page-cursor',
88
+ });
88
89
  });
89
90
  });
90
91
  describe('searching projects', () => {
@@ -103,10 +104,20 @@ describe('projects-list tool', () => {
103
104
  createMockProject({ id: 'hobby-project-id', name: 'Hobby Work', color: 'orange' }),
104
105
  ];
105
106
  mockTodoistApi.getProjects.mockResolvedValue(createMockApiResponse(mockProjects));
106
- const result = await projectsList.execute({ search: 'work', limit: 50 }, mockTodoistApi);
107
+ const result = await findProjects.execute({ search: 'work', limit: 50 }, mockTodoistApi);
107
108
  expect(mockTodoistApi.getProjects).toHaveBeenCalledWith({ limit: 50, cursor: null });
108
- expect(result.projects).toHaveLength(2);
109
- expect(result.projects.map((p) => p.name)).toEqual(['Work Project', 'Hobby Work']);
109
+ expect(extractTextContent(result)).toMatchSnapshot();
110
+ // Verify structured content with search filter
111
+ const structuredContent = extractStructuredContent(result);
112
+ expect(structuredContent.projects).toHaveLength(2); // Should match filtered results
113
+ expect(structuredContent.totalCount).toBe(2);
114
+ expect(structuredContent.hasMore).toBe(false);
115
+ expect(structuredContent.nextCursor).toBeNull();
116
+ expect(structuredContent.appliedFilters).toEqual({
117
+ search: 'work',
118
+ limit: 50,
119
+ cursor: undefined,
120
+ });
110
121
  });
111
122
  it.each([
112
123
  {
@@ -121,11 +132,16 @@ describe('projects-list tool', () => {
121
132
  expectedCount: 1,
122
133
  description: 'case insensitive matching',
123
134
  },
124
- ])('should handle search with $description', async ({ search, projects, expectedCount }) => {
135
+ ])('should handle search with $description', async ({ search, projects }) => {
125
136
  const mockProjects = projects.map((name) => createMockProject({ name }));
126
137
  mockTodoistApi.getProjects.mockResolvedValue(createMockApiResponse(mockProjects));
127
- const result = await projectsList.execute({ search, limit: 50 }, mockTodoistApi);
128
- expect(result.projects).toHaveLength(expectedCount);
138
+ const result = await findProjects.execute({ search, limit: 50 }, mockTodoistApi);
139
+ expect(extractTextContent(result)).toMatchSnapshot();
140
+ // Verify structured content
141
+ const structuredContent = extractStructuredContent(result);
142
+ expect(structuredContent).toEqual(expect.objectContaining({
143
+ appliedFilters: expect.objectContaining({ search }),
144
+ }));
129
145
  });
130
146
  });
131
147
  describe('error handling', () => {
@@ -134,7 +150,7 @@ describe('projects-list tool', () => {
134
150
  { error: TEST_ERRORS.INVALID_CURSOR, params: { cursor: 'invalid-cursor', limit: 50 } },
135
151
  ])('should propagate $error', async ({ error, params }) => {
136
152
  mockTodoistApi.getProjects.mockRejectedValue(new Error(error));
137
- await expect(projectsList.execute(params, mockTodoistApi)).rejects.toThrow(error);
153
+ await expect(findProjects.execute(params, mockTodoistApi)).rejects.toThrow(error);
138
154
  });
139
155
  });
140
156
  });
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=find-sections.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"find-sections.test.d.ts","sourceRoot":"","sources":["../../../src/tools/__tests__/find-sections.test.ts"],"names":[],"mappings":""}
@@ -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, ADD_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 ${ADD_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":""}