@@ -177,6 +177,58 @@ export class TaskMaster {
177177 ) ;
178178 }
179179
180+ // TODO: done
181+ /**
182+ * @description Fixes the IDs of all tasks and subtasks in tasks.json to be sequential
183+ * by reorganizing them incrementally starting from 1.
184+ * This method ensures better organization and readability of the task list.
185+ */
186+ public async fixIdsAsync ( ) : Promise < void > {
187+ const oraOptions = {
188+ text : "Fixing task IDs..." ,
189+ successText : chalk . bgGreen ( "Task IDs fixed successfully!" ) ,
190+ failText : chalk . bgRed ( "Failed to fix task IDs" ) ,
191+ } ;
192+
193+ await oraPromise ( async ( ) => {
194+ // Read the current tasks
195+ const tasks = await this . getTasksContentAsync ( ) ;
196+
197+ // Sort tasks by their current ID to maintain logical order
198+ tasks . master . tasks . sort ( ( a , b ) => a . id - b . id ) ;
199+
200+ // Fix main task IDs
201+ const idMap = new Map < number , number > ( ) ;
202+ for ( const [ index , task ] of tasks . master . tasks . entries ( ) ) {
203+ const oldId = task . id ;
204+ const newId = index + 1 ;
205+ if ( oldId !== newId ) {
206+ idMap . set ( oldId , newId ) ;
207+ task . id = newId ;
208+ }
209+ }
210+
211+ // Fix subtask IDs and update dependencies
212+ for ( const task of tasks . master . tasks ) {
213+ if ( task . subtasks && task . subtasks . length > 0 ) {
214+ for ( const [ index , subtask ] of task . subtasks . entries ( ) ) {
215+ subtask . id = index + 1 ;
216+ }
217+ }
218+ }
219+
220+ // Write the updated tasks back to the file
221+ await writeFile ( this . _tasksFilePath , JSON . stringify ( tasks , null , 2 ) ) ;
222+
223+ // Update the internal tasks file path if needed
224+ this . _tasksFilePath = this . _tasksFilePath ;
225+
226+ // Ensure dependencies are valid after ID reorganization
227+ await this . fixDependenciesAsync ( ) ;
228+ await this . validateDependenciesAsync ( ) ;
229+ } , oraOptions ) ;
230+ }
231+
180232 // TODO: done
181233 /**
182234 * @description Fixes the format of the tasks.json file if necessary
@@ -570,21 +622,30 @@ export class TaskMaster {
570622 if ( showParent ) {
571623 hasTasks = true ;
572624 const title = truncate ( task . title , MAX_TITLE_TRUNC_LENGTH ) ;
625+ const dependencies =
626+ task . dependencies . length > 0
627+ ? `deps: ${ chalk . cyan ( task . dependencies . join ( "," ) ) } `
628+ : `deps: ${ chalk . gray ( "none" ) } ` ;
573629 output +=
574630 `${ chalk . bgGreen . bold ( `#${ task . id } ` ) } ${ chalk . magenta ( title ) } ` +
575631 `[status: ${ formatStatus ( task . status ) } ] - ` +
576- `[priority: ${ formatPriority ( task . priority ) } ]\n` ;
632+ `[priority: ${ formatPriority ( task . priority ) } ] - ` +
633+ `[${ dependencies } ]\n` ;
577634
578635 // Only show matching subtasks
579636 if ( withSubtasks && matchingSubtasks . length > 0 ) {
580637 for ( const { subtask } of matchingSubtasks ) {
581638 const subTitle = truncate ( subtask . title , MAX_TITLE_TRUNC_LENGTH ) ;
582639 const hierarchicalId = `${ task . id } .${ subtask . id } ` ;
640+ const subDependencies =
641+ subtask . dependencies . length > 0
642+ ? `deps: ${ chalk . cyan ( subtask . dependencies . join ( "," ) ) } `
643+ : `deps: ${ chalk . gray ( "none" ) } ` ;
583644 output +=
584645 ` ${ chalk . dim ( "↳" ) } ${ chalk . bold ( `#${ hierarchicalId } ` ) } ` +
585646 `${ chalk . magenta ( subTitle ) } [status: ${ formatStatus (
586647 subtask . status ,
587- ) } ]\n`;
648+ ) } ] - [ ${ subDependencies } ] \n`;
588649 }
589650 }
590651 }
@@ -920,7 +981,7 @@ export class TaskMaster {
920981 subtaskId : number ,
921982 parentId : number ,
922983 ) : Promise < void > {
923- await this . clearAllDependenciesAsync ( subtaskId . toString ( ) ) ;
984+ await this . deleteAllDepsFromTaskAsync ( subtaskId . toString ( ) ) ;
924985 await this . executeCommandAsync (
925986 `Converting task ${ subtaskId } to subtask of ${ parentId } ...` ,
926987 `Task ${ subtaskId } converted to subtask successfully!` ,
@@ -934,6 +995,7 @@ export class TaskMaster {
934995 // Deleting Methods
935996 // ==============================================
936997
998+ // TODO: done
937999 /**
9381000 * @description Delete a task by ID (including subtasks)
9391001 * @param id The ID of the task to remove
@@ -958,6 +1020,7 @@ export class TaskMaster {
9581020 }
9591021 }
9601022
1023+ // TODO: done
9611024 /**
9621025 * @description Delete a specific subtask
9631026 * @param hierarchicalId The hierarchical ID of the subtask
@@ -987,6 +1050,7 @@ export class TaskMaster {
9871050 }
9881051 }
9891052
1053+ // TODO: done
9901054 /**
9911055 * @description Deletes all subtasks from a specific task
9921056 * @param id The ID of the task to clear subtasks from
@@ -1016,6 +1080,39 @@ export class TaskMaster {
10161080 }
10171081 }
10181082
1083+ // TODO: done
1084+ /**
1085+ * @description Clears all dependencies for the specified task or subtask.
1086+ * @param taskId The task ID or hierarchical ID of the subtask
1087+ */
1088+ public async deleteAllDepsFromTaskAsync ( taskId : string ) : Promise < void > {
1089+ const tasks = await this . getTasksContentAsync ( ) ;
1090+ const dependencyIds = await this . getAllDependenciesAsync ( tasks , taskId ) ;
1091+
1092+ if ( dependencyIds . length === 0 ) {
1093+ console . log ( chalk . yellow ( `No dependencies found for task ${ taskId } .` ) ) ;
1094+ return ;
1095+ }
1096+
1097+ // For subtasks, dependency IDs are already in the correct format
1098+ // For main tasks, dependency IDs are numbers that need to be converted to string
1099+ const isSubtask = taskId . includes ( "." ) ;
1100+
1101+ for ( const dependencyId of dependencyIds ) {
1102+ const dependsOnId = isSubtask
1103+ ? dependencyId . toString ( ) // For subtasks, dependencyId is already the full ID
1104+ : dependencyId . toString ( ) ; // For main tasks, convert number to string
1105+
1106+ await this . executeCommandAsync (
1107+ `Removing dependency ${ dependsOnId } from task ${ taskId } ...` ,
1108+ `Dependency ${ dependsOnId } removed successfully from task ${ taskId } !` ,
1109+ `Failed to remove dependency ${ dependsOnId } from task ${ taskId } ` ,
1110+ this . _mainCommand ,
1111+ [ "remove-dependency" , `--id=${ taskId } ` , `--depends-on=${ dependsOnId } ` ] ,
1112+ ) ;
1113+ }
1114+ }
1115+
10191116 // ==============================================
10201117 // Dependencies Methods
10211118 // ==============================================
@@ -1069,34 +1166,6 @@ export class TaskMaster {
10691166 ) ;
10701167 }
10711168
1072- // TODO: done
1073- /**
1074- * @description Clears all dependencies for the specified task or subtask.
1075- * @param taskId The task ID (either a simple number as string or hierarchical like "1.2")
1076- */
1077- public async clearAllDependenciesAsync ( taskId : string ) : Promise < void > {
1078- const tasks = await this . getTasksContentAsync ( ) ;
1079- const dependencyIds = await this . getAllDependenciesAsync ( tasks , taskId ) ;
1080-
1081- if ( dependencyIds . length === 0 ) {
1082- console . log ( chalk . yellow ( `No dependencies found for task ${ taskId } .` ) ) ;
1083- return ;
1084- }
1085-
1086- for ( const dependencyId of dependencyIds ) {
1087- const dependsOnId = taskId . includes ( "." )
1088- ? `${ taskId . split ( "." ) [ 0 ] } .${ dependencyId } `
1089- : dependencyId ;
1090- await this . executeCommandAsync (
1091- `Removing dependency ${ dependsOnId } from task ${ taskId } ...` ,
1092- `Dependency ${ dependsOnId } removed successfully from task ${ taskId } !` ,
1093- `Failed to remove dependency ${ dependsOnId } from task ${ taskId } ` ,
1094- this . _mainCommand ,
1095- [ "remove-dependency" , `--id=${ taskId } ` , `--depends-on=${ dependsOnId } ` ] ,
1096- ) ;
1097- }
1098- }
1099-
11001169 // ==============================================
11011170 // Backup, Restore and Clear Methods
11021171 // ==============================================
@@ -1232,4 +1301,40 @@ export class TaskMaster {
12321301 if ( allFilesCleared )
12331302 console . log ( chalk . green ( "All task-related files are cleared!" ) ) ;
12341303 }
1304+
1305+ // TODO: done
1306+ /**
1307+ * @description Clears all dependencies from all tasks and subtasks
1308+ */
1309+ public async clearAllDepsAsync ( ) : Promise < void > {
1310+ const { confirm } = await inquirer . prompt ( {
1311+ type : "confirm" ,
1312+ name : "confirm" ,
1313+ message : chalk . red ( "Clear all dependencies from all tasks and subtasks?" ) ,
1314+ default : false ,
1315+ } ) ;
1316+
1317+ if ( confirm ) {
1318+ const oraOptions = {
1319+ text : "Clearing all dependencies..." ,
1320+ successText : chalk . bgGreen ( "All dependencies cleared successfully!" ) ,
1321+ failText : chalk . bgRed ( "Failed to clear all dependencies" ) ,
1322+ } ;
1323+
1324+ await oraPromise ( async ( ) => {
1325+ const tasks = await this . getTasksContentAsync ( ) ;
1326+
1327+ for ( const task of tasks . master . tasks ) {
1328+ task . dependencies = [ ] ;
1329+ if ( task . subtasks && task . subtasks . length > 0 ) {
1330+ for ( const subtask of task . subtasks ) {
1331+ subtask . dependencies = [ ] ;
1332+ }
1333+ }
1334+ }
1335+
1336+ await writeFile ( this . _tasksFilePath , JSON . stringify ( tasks , null , 2 ) ) ;
1337+ } , oraOptions ) ;
1338+ }
1339+ }
12351340}
0 commit comments