From bba9c0754134e1425076b070f7884ad44a4e21b8 Mon Sep 17 00:00:00 2001 From: anj-s <32556631+anj-s@users.noreply.github.com> Date: Mon, 16 Mar 2026 12:18:01 -0700 Subject: [PATCH] feat(tracker): polish UI sorting and formatting (#22437) --- packages/core/src/services/trackerTypes.ts | 1 - packages/core/src/tools/trackerTools.test.ts | 43 ++++++++++++++++++-- packages/core/src/tools/trackerTools.ts | 24 ++++++++--- 3 files changed, 58 insertions(+), 10 deletions(-) diff --git a/packages/core/src/services/trackerTypes.ts b/packages/core/src/services/trackerTypes.ts index 6c21456fe1..d0e94bb986 100644 --- a/packages/core/src/services/trackerTypes.ts +++ b/packages/core/src/services/trackerTypes.ts @@ -22,7 +22,6 @@ export const TASK_TYPE_LABELS: Record = { export enum TaskStatus { OPEN = 'open', IN_PROGRESS = 'in_progress', - BLOCKED = 'blocked', CLOSED = 'closed', } export const TaskStatusSchema = z.nativeEnum(TaskStatus); diff --git a/packages/core/src/tools/trackerTools.test.ts b/packages/core/src/tools/trackerTools.test.ts index 7edafb0fa3..8236dba3a1 100644 --- a/packages/core/src/tools/trackerTools.test.ts +++ b/packages/core/src/tools/trackerTools.test.ts @@ -186,20 +186,55 @@ describe('Tracker Tools Integration', () => { expect(display.todos).toEqual([ { - description: `[p1] [TASK] Parent`, + description: `task: Parent (p1)`, status: 'in_progress', }, { - description: ` [c1] [EPIC] Child`, + description: ` epic: Child (c1)`, status: 'pending', }, { - description: ` [leaf] [BUG] Closed Leaf`, + description: ` bug: Closed Leaf (leaf)`, status: 'completed', }, ]); }); + it('sorts tasks by status', async () => { + const t1 = { + id: 't1', + title: 'T1', + type: TaskType.TASK, + status: TaskStatus.CLOSED, + dependencies: [], + }; + const t2 = { + id: 't2', + title: 'T2', + type: TaskType.TASK, + status: TaskStatus.OPEN, + dependencies: [], + }; + const t3 = { + id: 't3', + title: 'T3', + type: TaskType.TASK, + status: TaskStatus.IN_PROGRESS, + dependencies: [], + }; + + const mockService = { + listTasks: async () => [t1, t2, t3], + } as unknown as TrackerService; + const display = await buildTodosReturnDisplay(mockService); + + expect(display.todos).toEqual([ + { description: `task: T3 (t3)`, status: 'in_progress' }, + { description: `task: T2 (t2)`, status: 'pending' }, + { description: `task: T1 (t1)`, status: 'completed' }, + ]); + }); + it('detects cycles', async () => { // Since TrackerTask only has a single parentId, a true cycle is unreachable from roots. // We simulate a database corruption (two tasks with same ID, one root, one child) @@ -220,7 +255,7 @@ describe('Tracker Tools Integration', () => { expect(display.todos).toEqual([ { - description: `[p1] [TASK] Parent`, + description: `task: Parent (p1)`, status: 'pending', }, { diff --git a/packages/core/src/tools/trackerTools.ts b/packages/core/src/tools/trackerTools.ts index 0a7101f55e..18f3ccc3cc 100644 --- a/packages/core/src/tools/trackerTools.ts +++ b/packages/core/src/tools/trackerTools.ts @@ -23,7 +23,7 @@ import { TRACKER_UPDATE_TASK_TOOL_NAME, TRACKER_VISUALIZE_TOOL_NAME, } from './tool-names.js'; -import type { ToolResult, TodoList } from './tools.js'; +import type { ToolResult, TodoList, TodoStatus } from './tools.js'; import { BaseDeclarativeTool, BaseToolInvocation, Kind } from './tools.js'; import { ToolErrorType } from './tool-error.js'; import type { TrackerTask, TaskType } from '../services/trackerTypes.js'; @@ -48,6 +48,21 @@ export async function buildTodosReturnDisplay( } } + const statusOrder = { + [TaskStatus.IN_PROGRESS]: 0, + [TaskStatus.OPEN]: 1, + [TaskStatus.CLOSED]: 2, + }; + + const sortTasks = (a: TrackerTask, b: TrackerTask) => { + if (statusOrder[a.status] !== statusOrder[b.status]) { + return statusOrder[a.status] - statusOrder[b.status]; + } + return a.id.localeCompare(b.id); + }; + + roots.sort(sortTasks); + const todos: TodoList['todos'] = []; const addTask = (task: TrackerTask, depth: number, visited: Set) => { @@ -60,8 +75,7 @@ export async function buildTodosReturnDisplay( } visited.add(task.id); - let status: 'pending' | 'in_progress' | 'completed' | 'cancelled' = - 'pending'; + let status: TodoStatus = 'pending'; if (task.status === TaskStatus.IN_PROGRESS) { status = 'in_progress'; } else if (task.status === TaskStatus.CLOSED) { @@ -69,11 +83,12 @@ export async function buildTodosReturnDisplay( } const indent = ' '.repeat(depth); - const description = `${indent}[${task.id}] ${TASK_TYPE_LABELS[task.type]} ${task.title}`; + const description = `${indent}${task.type}: ${task.title} (${task.id})`; todos.push({ description, status }); const children = childrenMap.get(task.id) ?? []; + children.sort(sortTasks); for (const child of children) { addTask(child, depth + 1, visited); } @@ -570,7 +585,6 @@ class TrackerVisualizeInvocation extends BaseToolInvocation< const statusEmojis: Record = { open: '⭕', in_progress: '🚧', - blocked: '🚫', closed: '✅', };