@@ -27,6 +27,9 @@ import {
2727 readJsonFileAsync ,
2828} from "@/utils/extras" ;
2929
30+ /* asks */
31+ import { askLangAsync } from "@/core/taskmaster/asks" ;
32+
3033/* types */
3134import type { T_PackageManager } from "@/@types/index" ;
3235import type { I_Tasks , Status , Priority } from "@/@types/tasks" ;
@@ -74,6 +77,9 @@ export class TaskMaster {
7477 // Getters and Setters
7578 // ==============================================
7679
80+ /**
81+ * @description Retrieves the contents of the tasks.json file
82+ */
7783 public async getTasksContentAsync ( ) : Promise < I_Tasks > {
7884 const oraOptions = {
7985 text : `Fetching tasks from ${ chalk . bold ( this . _tasksFilePath ) } ...` ,
@@ -87,10 +93,54 @@ export class TaskMaster {
8793 ) ;
8894 }
8995
96+ /**
97+ * @description Sets the tasks file path to use for task-master operations
98+ */
9099 public setTasksFilePath ( tasksFilePath : string ) : void {
91100 this . _tasksFilePath = tasksFilePath ;
92101 }
93102
103+ /**
104+ * @description Retrieves all dependencies for a given task or subtask.
105+ * @param tasks The tasks data structure
106+ * @param taskId The task ID (either a simple number as string or hierarchical like "1.2")
107+ */
108+ private async getAllDependenciesAsync (
109+ tasks : I_Tasks ,
110+ taskId : string ,
111+ ) : Promise < number [ ] > {
112+ if ( ! taskId . includes ( "." ) ) {
113+ const idNum = Number . parseInt ( taskId , 10 ) ;
114+ const task = tasks . master . tasks . find ( ( t ) => t . id === idNum ) ;
115+ if ( ! task ) {
116+ throw new Error ( `Task not found: ${ taskId } ` ) ;
117+ }
118+ return task . dependencies ;
119+ }
120+
121+ const parts = taskId . split ( "." ) ;
122+ if ( parts . length < 2 ) {
123+ throw new Error ( `Invalid hierarchical task ID: ${ taskId } ` ) ;
124+ }
125+ const parentId = Number . parseInt ( parts [ 0 ] , 10 ) ;
126+ const subtaskIndex = Number . parseInt ( parts [ 1 ] , 10 ) - 1 ;
127+ const parentTask = tasks . master . tasks . find ( ( t ) => t . id === parentId ) ;
128+ if ( ! parentTask ) {
129+ throw new Error ( `Parent task not found for subtask: ${ taskId } ` ) ;
130+ }
131+
132+ if (
133+ ! parentTask . subtasks ||
134+ subtaskIndex < 0 ||
135+ subtaskIndex >= parentTask . subtasks . length
136+ ) {
137+ throw new Error ( `Subtask not found: ${ taskId } ` ) ;
138+ }
139+
140+ const subtask = parentTask . subtasks [ subtaskIndex ] ;
141+ return subtask . dependencies ;
142+ }
143+
94144 // ==============================================
95145 // Helpers
96146 // ==============================================
@@ -135,7 +185,7 @@ export class TaskMaster {
135185 * @description Fixes the format of the tasks.json file if necessary
136186 * by encapsulating the 'tasks' and 'metadata' keys under a 'master' key
137187 */
138- private async fixTasksFileFormatAsync ( ) : Promise < void > {
188+ public async fixTasksFileFormatAsync ( ) : Promise < void > {
139189 const oraOptions = {
140190 text : "Verifying tasks.json file format..." ,
141191 successText : chalk . bgGreen ( "tasks.json format validated successfully!" ) ,
@@ -276,6 +326,21 @@ export class TaskMaster {
276326 } , oraOptions ) ;
277327 }
278328
329+ // TODO: done
330+ /**
331+ * @description Sets the response language for TMAI
332+ * @param lang Language to set for TMAI responses
333+ */
334+ public async setLangAsync ( lang : string ) : Promise < void > {
335+ await this . executeCommandAsync (
336+ `Setting TMAI response language to ${ chalk . bold ( lang ) } ...` ,
337+ `Language set to ${ lang } successfully!` ,
338+ `Failed to set language to ${ lang } ` ,
339+ this . _mainCommand ,
340+ [ "lang" , `--response=${ lang } ` ] ,
341+ ) ;
342+ }
343+
279344 // TODO: done
280345 /**
281346 * @description Initializes the task-master AI by creating a PRD file
@@ -495,6 +560,31 @@ export class TaskMaster {
495560 return output ;
496561 }
497562
563+ // TODO: done
564+ /**
565+ * @description Extracts all main task IDs and subtask IDs from the tasks data
566+ * @param tasks Tasks data to process
567+ * @returns Object containing two arrays: mainIDs (numbers) and subtasksIDs (strings in the format "parentId.subtaskIndex")
568+ */
569+ public async getAllTaskIdsAsync ( tasks : I_Tasks ) : Promise < {
570+ mainIDs : number [ ] ;
571+ subtasksIDs : string [ ] ;
572+ } > {
573+ const mainIDs : number [ ] = [ ] ;
574+ const subtasksIDs : string [ ] = [ ] ;
575+
576+ for ( const task of tasks . master . tasks ) {
577+ mainIDs . push ( task . id ) ;
578+ if ( task . subtasks && task . subtasks . length > 0 ) {
579+ for ( let i = 0 ; i < task . subtasks . length ; i ++ ) {
580+ subtasksIDs . push ( `${ task . id } .${ i + 1 } ` ) ;
581+ }
582+ }
583+ }
584+
585+ return { mainIDs, subtasksIDs } ;
586+ }
587+
498588 // TODO: done
499589 /**
500590 * @description Lists tasks with optional status filtering and subtask display
@@ -640,7 +730,7 @@ export class TaskMaster {
640730 // Updating Methods
641731 // ==============================================
642732
643- // TODO: validate
733+ // TODO: in-progress
644734 /**
645735 * @description Modifies a task using AI
646736 * @param id ID of the task to modify
@@ -669,7 +759,7 @@ export class TaskMaster {
669759 ) ;
670760 }
671761
672- // TODO: validate
762+ // TODO: in-progress
673763 /**
674764 * @description Updates multiple tasks using AI from a starting ID
675765 * @param startingId Starting ID for the update
@@ -698,7 +788,7 @@ export class TaskMaster {
698788 ) ;
699789 }
700790
701- // TODO: validate
791+ // TODO: in-progress
702792 /**
703793 * @description Modifies a subtask using AI
704794 * @param hierarchicalId Hierarchical ID of the subtask
@@ -727,7 +817,7 @@ export class TaskMaster {
727817 ) ;
728818 }
729819
730- // TODO: validate
820+ // TODO: in-progress
731821 /**
732822 * @description Converts an existing task to a subtask
733823 * @param subtaskId ID of the task to convert into a subtask
@@ -737,6 +827,7 @@ export class TaskMaster {
737827 subtaskId : number ,
738828 parentId : number ,
739829 ) : Promise < void > {
830+ await this . clearAllDependenciesAsync ( subtaskId . toString ( ) ) ;
740831 await this . executeCommandAsync (
741832 `Converting task ${ subtaskId } to subtask of ${ parentId } ...` ,
742833 `Task ${ subtaskId } converted to subtask successfully!` ,
@@ -746,6 +837,87 @@ export class TaskMaster {
746837 ) ;
747838 }
748839
840+ // ==============================================
841+ // Dependencies
842+ // ==============================================
843+
844+ // TODO: in-progress
845+ /**
846+ * @description Adds a dependency to a task
847+ * @param taskId ID of the task to modify
848+ * @param dependencyIds IDs of the dependencies to add
849+ */
850+ public async addDependencyAsync (
851+ taskId : string ,
852+ dependencyIds : string [ ] ,
853+ ) : Promise < void > {
854+ const formatedDepsIds =
855+ dependencyIds . length > 1 ? dependencyIds . join ( "," ) : dependencyIds [ 0 ] ;
856+ await this . executeCommandAsync (
857+ `Adding dependency ${ formatedDepsIds } to task ${ taskId } ...` ,
858+ `Dependency ${ formatedDepsIds } added successfully to task ${ taskId } !` ,
859+ `Failed to add dependency ${ formatedDepsIds } to task ${ taskId } ` ,
860+ this . _mainCommand ,
861+ [ "add-dependency" , `--id=${ taskId } ` , `--depends-on=${ formatedDepsIds } ` ] ,
862+ ) ;
863+ }
864+
865+ // TODO: done
866+ /**
867+ * @description Validates task dependencies
868+ */
869+ public async validateDependenciesAsync ( ) : Promise < void > {
870+ await this . executeCommandAsync (
871+ "Validating dependencies..." ,
872+ "Dependencies validated successfully!" ,
873+ "Failed to validate dependencies" ,
874+ this . _mainCommand ,
875+ [ "validate-dependencies" ] ,
876+ ) ;
877+ }
878+
879+ // TODO: done
880+ /**
881+ * @description Automatically fixes dependency issues
882+ */
883+ public async fixDependenciesAsync ( ) : Promise < void > {
884+ await this . executeCommandAsync (
885+ "Fixing dependencies..." ,
886+ "Dependencies fixed successfully!" ,
887+ "Failed to fix dependencies" ,
888+ this . _mainCommand ,
889+ [ "fix-dependencies" ] ,
890+ ) ;
891+ }
892+
893+ // TODO: done
894+ /**
895+ * @description Clears all dependencies for the specified task or subtask.
896+ * @param taskId The task ID (either a simple number as string or hierarchical like "1.2")
897+ */
898+ public async clearAllDependenciesAsync ( taskId : string ) : Promise < void > {
899+ const tasks = await this . getTasksContentAsync ( ) ;
900+ const dependencyIds = await this . getAllDependenciesAsync ( tasks , taskId ) ;
901+
902+ if ( dependencyIds . length === 0 ) {
903+ console . log ( chalk . yellow ( `No dependencies found for task ${ taskId } .` ) ) ;
904+ return ;
905+ }
906+
907+ for ( const dependencyId of dependencyIds ) {
908+ const dependsOnId = taskId . includes ( "." )
909+ ? `${ taskId . split ( "." ) [ 0 ] } .${ dependencyId } `
910+ : dependencyId ;
911+ await this . executeCommandAsync (
912+ `Removing dependency ${ dependsOnId } from task ${ taskId } ...` ,
913+ `Dependency ${ dependsOnId } removed successfully from task ${ taskId } !` ,
914+ `Failed to remove dependency ${ dependsOnId } from task ${ taskId } ` ,
915+ this . _mainCommand ,
916+ [ "remove-dependency" , `--id=${ taskId } ` , `--depends-on=${ dependsOnId } ` ] ,
917+ ) ;
918+ }
919+ }
920+
749921 // ==============================================
750922 // Backup, Restore and Clear Methods
751923 // ==============================================
0 commit comments