Skip to content

Commit 9bb906b

Browse files
authored
feat!: semantic priority values (P1, P2, P3, P4) instead of numeric (#217)
> [!WARNING] > This is a breaking change. ## 🗺️ Overview Two things: - What the title says. Now our tools all return tasks data structures where the priority is always expressed as p1, p2, p3 or p4, and never as a number. - In a 2nd commit there's an attempt to promote not using numeric literals for priority in the code, even in place where the number value is expected. So instead of saying `priority: 1` we'll now say `priority: convertPriorityToNumber('p4')` instead. See #216 (review) and the subsequent few comments below it. ## ✅ PR Checklist - [x] Added tests for bugs / new features ## 🎥 Demo https://github.com/user-attachments/assets/69401b79-cf08-427f-b752-d6a8ade96995
1 parent 6a4b78b commit 9bb906b

15 files changed

+73
-116
lines changed

src/tool-helpers.test.ts

Lines changed: 13 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,71 +1,64 @@
1-
import type { PersonalProject, Task, WorkspaceProject } from '@doist/todoist-api-typescript'
1+
import type { PersonalProject, WorkspaceProject } from '@doist/todoist-api-typescript'
22
import {
33
createMoveTaskArgs,
44
isPersonalProject,
55
isWorkspaceProject,
66
mapProject,
77
mapTask,
88
} from './tool-helpers.js'
9+
import { createMockTask } from './utils/test-helpers.js'
910

1011
describe('shared utilities', () => {
1112
describe('mapTask', () => {
1213
it('should map a basic task correctly', () => {
13-
const mockTask = {
14+
const mockTask = createMockTask({
1415
id: '123',
1516
content: 'Test task',
1617
description: 'Test description',
1718
projectId: 'proj-1',
18-
sectionId: null,
19-
parentId: null,
2019
labels: ['work'],
21-
priority: 1,
2220
due: {
2321
date: '2024-01-15',
2422
isRecurring: false,
2523
datetime: '2024-01-15T10:00:00Z',
2624
string: 'Jan 15',
2725
timezone: 'UTC',
2826
},
29-
} as unknown as Task
27+
})
3028

3129
expect(mapTask(mockTask)).toEqual({
3230
id: '123',
3331
content: 'Test task',
3432
description: 'Test description',
3533
dueDate: '2024-01-15',
3634
recurring: false,
37-
priority: 4,
35+
priority: 'p4',
3836
projectId: 'proj-1',
3937
sectionId: undefined,
4038
parentId: undefined,
4139
labels: ['work'],
4240
duration: undefined,
4341
assignedByUid: undefined,
44-
checked: undefined,
42+
checked: false,
4543
completedAt: undefined,
4644
deadlineDate: undefined,
4745
responsibleUid: undefined,
4846
})
4947
})
5048

5149
it('should handle recurring tasks', () => {
52-
const mockTask = {
50+
const mockTask = createMockTask({
5351
id: '456',
5452
content: 'Recurring task',
55-
description: '',
5653
projectId: 'proj-1',
57-
sectionId: null,
58-
parentId: null,
59-
labels: [],
60-
priority: 1,
6154
due: {
6255
date: '2024-01-15',
6356
isRecurring: true,
6457
datetime: '2024-01-15T10:00:00Z',
6558
string: 'every day',
6659
timezone: 'UTC',
6760
},
68-
} as unknown as Task
61+
})
6962

7063
const result = mapTask(mockTask)
7164

@@ -74,28 +67,19 @@ describe('shared utilities', () => {
7467
})
7568

7669
it('should handle task with duration', () => {
77-
const mockTask = {
70+
const mockTask = createMockTask({
7871
id: '789',
7972
content: 'Task with duration',
80-
description: '',
8173
projectId: 'proj-1',
82-
sectionId: null,
83-
parentId: null,
84-
labels: [],
85-
priority: 1,
86-
duration: {
87-
amount: 150,
88-
unit: 'minute',
89-
},
90-
} as unknown as Task
74+
duration: { amount: 150, unit: 'minute' },
75+
})
9176

9277
const result = mapTask(mockTask)
93-
9478
expect(result.duration).toBe('2h30m')
9579
})
9680

9781
it('should preserve markdown links and formatting in content and description', () => {
98-
const mockTask = {
82+
const mockTask = createMockTask({
9983
id: '123',
10084
content: 'Task with **bold** and [link](https://example.com)',
10185
description: `Rich markdown description:
@@ -111,11 +95,7 @@ describe('shared utilities', () => {
11195
11296
End of description.`,
11397
projectId: 'proj-1',
114-
sectionId: null,
115-
parentId: null,
116-
labels: [],
117-
priority: 1,
118-
} as unknown as Task
98+
})
11999

120100
const result = mapTask(mockTask)
121101

src/tool-helpers.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import type {
99
} from '@doist/todoist-api-typescript'
1010
import z from 'zod'
1111
import { formatDuration } from './utils/duration-parser.js'
12-
import { invertPriorityForOutput } from './utils/priorities.js'
12+
import { convertNumberToPriority } from './utils/priorities.js'
1313

1414
// Re-export filter helpers for backward compatibility
1515
export {
@@ -82,7 +82,7 @@ function mapTask(task: Task) {
8282
dueDate: task.due?.date,
8383
recurring: task.due?.isRecurring && task.due.string ? task.due.string : false,
8484
deadlineDate: task.deadline?.date,
85-
priority: invertPriorityForOutput(task.priority),
85+
priority: convertNumberToPriority(task.priority) ?? 'p4',
8686
projectId: task.projectId,
8787
sectionId: task.sectionId ?? undefined,
8888
parentId: task.parentId ?? undefined,

src/tools/__tests__/__snapshots__/find-tasks-by-date.test.ts.snap

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,29 +10,29 @@ exports[`find-tasks-by-date tool > label filtering > should combine date filters
1010
"Tasks for 2025-08-15: 1 (limit 25).
1111
Filter: 2025-08-15; labels: @important.
1212
Preview:
13-
Important task for specific date • due 2025-08-15 • P1 • id=8485093748"
13+
Important task for specific date • due 2025-08-15 • P4 • id=8485093748"
1414
`;
1515

1616
exports[`find-tasks-by-date tool > listing tasks by date range > only returns tasks for the startDate when daysCount is 1 1`] = `
1717
"Tasks for 2025-08-20: 1 (limit 50).
1818
Filter: 2025-08-20.
1919
Preview:
20-
Task for specific date • due 2025-08-20 • P1 • id=8485093748"
20+
Task for specific date • due 2025-08-20 • P4 • id=8485093748"
2121
`;
2222

2323
exports[`find-tasks-by-date tool > listing tasks by date range > should get tasks for today when startDate is "today" (includes overdue) 1`] = `
2424
"Today's tasks + overdue: 1 (limit 50).
2525
Filter: today + overdue tasks + 6 more days.
2626
Preview:
27-
Today task • due 2025-08-15 • P1 • id=8485093748"
27+
Today task • due 2025-08-15 • P4 • id=8485093748"
2828
`;
2929

3030
exports[`find-tasks-by-date tool > listing tasks by date range > should handle 'multiple days with pagination' 1`] = `
3131
"Tasks for 2025-08-20: 2 (limit 20), more available.
3232
Filter: 2025-08-20 to 2025-08-23.
3333
Preview:
34-
Multi-day task 1 • due 2025-08-20 • P1 • id=8485093749
35-
Multi-day task 2 • due 2025-08-21 • P1 • id=8485093750
34+
Multi-day task 1 • due 2025-08-20 • P4 • id=8485093749
35+
Multi-day task 2 • due 2025-08-21 • P4 • id=8485093750
3636
Possible suggested next step:
3737
- Pass cursor 'next-page-cursor' to fetch more results."
3838
`;
@@ -41,7 +41,7 @@ exports[`find-tasks-by-date tool > listing tasks by date range > should handle '
4141
"Tasks for 2025-08-20: 1 (limit 50).
4242
Filter: 2025-08-20 to 2025-08-27.
4343
Preview:
44-
Specific date task • due 2025-08-20 • P1 • id=8485093748"
44+
Specific date task • due 2025-08-20 • P4 • id=8485093748"
4545
`;
4646

4747
exports[`find-tasks-by-date tool > next steps logic > should provide helpful suggestions for empty date range results 1`] = `
@@ -60,19 +60,19 @@ exports[`find-tasks-by-date tool > next steps logic > should suggest appropriate
6060
"Tasks for 2025-08-15: 1 (limit 10).
6161
Filter: 2025-08-15.
6262
Preview:
63-
Overdue task from list • due 2025-08-10 • P1 • id=8485093748"
63+
Overdue task from list • due 2025-08-10 • P4 • id=8485093748"
6464
`;
6565

6666
exports[`find-tasks-by-date tool > next steps logic > should suggest today-focused actions when startDate is today 1`] = `
6767
"Today's tasks + overdue: 1 (limit 10).
6868
Filter: today + overdue tasks.
6969
Preview:
70-
Today's task • due 2025-08-15 • P1 • id=8485093748"
70+
Today's task • due 2025-08-15 • P4 • id=8485093748"
7171
`;
7272

7373
exports[`find-tasks-by-date tool > responsibleUser parameter > should filter tasks by specific user email 1`] = `
7474
"Today's tasks + overdue assigned to [email protected]: 1 (limit 50).
7575
Filter: today + overdue tasks; assigned to: [email protected].
7676
Preview:
77-
Task assigned to John • due 2025-08-15 • P1 • id=8485093748"
77+
Task assigned to John • due 2025-08-15 • P4 • id=8485093748"
7878
`;

src/tools/__tests__/__snapshots__/find-tasks.test.ts.snap

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ exports[`find-tasks tool > next steps logic > should provide different next step
2525
"Search results for "future tasks": 1 (limit 10).
2626
Filter: matching "future tasks".
2727
Preview:
28-
Regular future task • due 2025-08-25 • P1 • id=8485093748"
28+
Regular future task • due 2025-08-25 • P4 • id=8485093748"
2929
`;
3030

3131
exports[`find-tasks tool > next steps logic > should provide helpful suggestions for empty search results 1`] = `
@@ -38,28 +38,28 @@ exports[`find-tasks tool > next steps logic > should suggest different actions w
3838
"Search results for "overdue tasks": 1 (limit 10).
3939
Filter: matching "overdue tasks".
4040
Preview:
41-
Overdue search result • due 2025-08-10 • P1 • id=8485093748"
41+
Overdue search result • due 2025-08-10 • P4 • id=8485093748"
4242
`;
4343

4444
exports[`find-tasks tool > next steps logic > should suggest today tasks when hasToday is true 1`] = `
4545
"Search results for "today tasks": 1 (limit 10).
4646
Filter: matching "today tasks".
4747
Preview:
48-
Task due today • due 2025-08-17 • P1 • id=8485093748"
48+
Task due today • due 2025-08-17 • P4 • id=8485093748"
4949
`;
5050

5151
exports[`find-tasks tool > searching tasks > should handle 'custom limit' 1`] = `
5252
"Search results for "project update": 1 (limit 5).
5353
Filter: matching "project update".
5454
Preview:
55-
Test result • P1 • id=8485093748"
55+
Test result • P4 • id=8485093748"
5656
`;
5757

5858
exports[`find-tasks tool > searching tasks > should handle 'pagination cursor' 1`] = `
5959
"Search results for "follow up": 1 (limit 20).
6060
Filter: matching "follow up".
6161
Preview:
62-
Test result • P1 • id=8485093748"
62+
Test result • P4 • id=8485093748"
6363
`;
6464

6565
exports[`find-tasks tool > searching tasks > should handle search with 'empty results' 1`] = `
@@ -78,8 +78,8 @@ exports[`find-tasks tool > searching tasks > should search tasks and return resu
7878
"Search results for "important meeting": 2 (limit 10), more available.
7979
Filter: matching "important meeting".
8080
Preview:
81-
Task containing search term • P1 • id=8485093748
82-
Another matching task • P2 • id=8485093749
81+
Task containing search term • P4 • id=8485093748
82+
Another matching task • P3 • id=8485093749
8383
Possible suggested next step:
8484
- Pass cursor 'cursor-for-next-page' to fetch more results."
8585
`;

src/tools/__tests__/add-tasks.test.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import type { Task, TodoistApi } from '@doist/todoist-api-typescript'
22
import { type Mocked, vi } from 'vitest'
3+
import { convertPriorityToNumber } from '../../utils/priorities.js'
34
import { createMockTask, createMockUser, TEST_IDS, TODAY } from '../../utils/test-helpers.js'
45
import { ToolNames } from '../../utils/tool-names.js'
56
import { addTasks } from '../add-tasks.js'
@@ -33,7 +34,7 @@ describe(`${ADD_TASKS} tool`, () => {
3334
description: 'Task description',
3435
labels: ['work', 'urgent'],
3536
childOrder: 2,
36-
priority: 2,
37+
priority: 'p3',
3738
url: 'https://todoist.com/showTask?id=8485093749',
3839
addedAt: '2025-08-13T22:09:57.123456Z',
3940
due: {
@@ -79,7 +80,7 @@ describe(`${ADD_TASKS} tool`, () => {
7980
expect(mockTodoistApi.addTask).toHaveBeenNthCalledWith(2, {
8081
content: 'Second task content',
8182
description: 'Task description',
82-
priority: 3,
83+
priority: convertPriorityToNumber('p2'),
8384
dueString: 'Aug 15',
8485
projectId: '6cfCcrrCFg2xP94Q',
8586
sectionId: undefined,
@@ -108,7 +109,7 @@ describe(`${ADD_TASKS} tool`, () => {
108109
id: '8485093750',
109110
content: 'Subtask content',
110111
description: 'Subtask description',
111-
priority: 3,
112+
priority: 'p2',
112113
sectionId: 'section-123',
113114
parentId: 'parent-task-456',
114115
url: 'https://todoist.com/showTask?id=8485093750',
@@ -136,7 +137,7 @@ describe(`${ADD_TASKS} tool`, () => {
136137
expect(mockTodoistApi.addTask).toHaveBeenCalledWith({
137138
content: 'Subtask content',
138139
description: 'Subtask description',
139-
priority: 2,
140+
priority: convertPriorityToNumber('p3'),
140141
projectId: '6cfCcrrCFg2xP94Q',
141142
sectionId: 'section-123',
142143
parentId: 'parent-task-456',

src/tools/__tests__/assignment-integration.test.ts

Lines changed: 3 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import type { Task, TodoistApi } from '@doist/todoist-api-typescript'
22
import { type Mocked, vi } from 'vitest'
33
import { AssignmentErrorType, assignmentValidator } from '../../utils/assignment-validator.js'
4-
import { createMockProject } from '../../utils/test-helpers.js'
4+
import { createMockProject, createMockTask } from '../../utils/test-helpers.js'
55
import { userResolver } from '../../utils/user-resolver.js'
66
import { addTasks } from '../add-tasks.js'
77
import { findProjectCollaborators } from '../find-project-collaborators.js'
@@ -39,33 +39,17 @@ describe('Assignment Integration Tests', () => {
3939
displayName: 'John Doe',
4040
}
4141

42-
const mockTask: Task = {
42+
const mockTask: Task = createMockTask({
4343
id: 'task-123',
4444
content: 'Test task',
4545
projectId: 'project-123',
46-
sectionId: null,
47-
parentId: null,
48-
priority: 1,
49-
labels: [],
50-
description: '',
5146
url: 'https://todoist.com/showTask?id=task-123',
52-
noteCount: 0,
5347
addedByUid: 'creator-123',
5448
addedAt: new Date().toISOString(),
55-
deadline: null,
56-
responsibleUid: null,
57-
assignedByUid: null,
58-
isCollapsed: false,
59-
isDeleted: false,
60-
duration: null,
61-
checked: false,
6249
updatedAt: new Date().toISOString(),
63-
due: null,
64-
dayOrder: 0,
6550
userId: 'creator-123',
6651
completedAt: null,
67-
childOrder: 1,
68-
}
52+
})
6953

7054
const mockProject = createMockProject({
7155
id: 'project-123',

src/tools/__tests__/fetch.test.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ describe(`${FETCH} tool`, () => {
2424
content: 'Important meeting with team',
2525
description: 'Discuss project roadmap and timeline',
2626
labels: ['work', 'urgent'],
27-
priority: 2,
27+
priority: 'p3',
2828
projectId: TEST_IDS.PROJECT_WORK,
2929
sectionId: TEST_IDS.SECTION_1,
3030
due: {
@@ -52,7 +52,7 @@ describe(`${FETCH} tool`, () => {
5252
text: 'Important meeting with team\n\nDescription: Discuss project roadmap and timeline\nDue: 2025-10-15\nLabels: work, urgent',
5353
url: `https://app.todoist.com/app/task/${TEST_IDS.TASK_1}`,
5454
metadata: {
55-
priority: 3,
55+
priority: 'p3',
5656
projectId: TEST_IDS.PROJECT_WORK,
5757
sectionId: TEST_IDS.SECTION_1,
5858
recurring: false,
@@ -78,7 +78,7 @@ describe(`${FETCH} tool`, () => {
7878
expect(jsonResponse.title).toBe('Simple task')
7979
expect(jsonResponse.text).toBe('Simple task')
8080
expect(jsonResponse.metadata).toEqual({
81-
priority: 4,
81+
priority: 'p4',
8282
projectId: TEST_IDS.PROJECT_TEST,
8383
recurring: false,
8484
checked: false,

src/tools/__tests__/find-completed-tasks.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ describe(`${FIND_COMPLETED_TASKS} tool`, () => {
4141
description: 'Task completed yesterday',
4242
completedAt: '2024-01-01T00:00:00Z',
4343
labels: ['work'],
44-
priority: 2,
44+
priority: 'p3',
4545
url: 'https://todoist.com/showTask?id=8485093748',
4646
addedAt: '2025-08-13T22:09:56.123456Z',
4747
due: {
@@ -121,7 +121,7 @@ describe(`${FIND_COMPLETED_TASKS} tool`, () => {
121121
description: 'This task was due and completed',
122122
completedAt: '2024-01-01T00:00:00Z',
123123
labels: ['urgent'],
124-
priority: 3,
124+
priority: 'p2',
125125
url: 'https://todoist.com/showTask?id=8485093750',
126126
addedAt: '2025-08-13T22:09:58.123456Z',
127127
due: {

0 commit comments

Comments
 (0)