@@ -21,6 +21,7 @@ import {
2121 REPORT_PATH ,
2222 README_PATH ,
2323 TASKS_FILES ,
24+ NOTE_LANGS ,
2425} from "@/constants" ;
2526
2627/* extras */
@@ -122,7 +123,7 @@ export class TaskMaster {
122123
123124 // TODO: done
124125 /**
125- * @description Retrieves all dependencies for a given task or subtask.
126+ * @description Extracts all dependencies for a given task or subtask.
126127 * @param tasks The tasks data structure
127128 * @param taskId The task ID (either a simple number as string or hierarchical like "1.2")
128129 */
@@ -162,6 +163,122 @@ export class TaskMaster {
162163 return subtask . dependencies ;
163164 }
164165
166+ // TODO: done
167+ /**
168+ * @description Fixes the format of the tasks.json file if necessary
169+ * by encapsulating the 'tasks' and 'metadata' keys under a 'master' key
170+ * @param mode Operation mode: 'init' for initialization or 'repair' for fixing existing file
171+ */
172+ public async _fixTasksFileFormatAsync (
173+ mode : "init" | "repair" = "repair" ,
174+ ) : Promise < void > {
175+ const isInitMode = mode === "init" ;
176+ const oraOptions = {
177+ text : isInitMode
178+ ? "Initializing tasks.json file..."
179+ : "Verifying tasks.json file format..." ,
180+ successText : isInitMode
181+ ? chalk . bgGreen (
182+ "tasks.json initialized successfully with default structure." ,
183+ )
184+ : chalk . bgGreen ( "tasks.json format validated successfully!" ) ,
185+ failText : isInitMode
186+ ? chalk . bgRed ( "Failed to initialize tasks.json file" )
187+ : chalk . bgRed ( "Failed to validate tasks.json format" ) ,
188+ } ;
189+
190+ await oraPromise ( async ( ) => {
191+ // Handle init mode - create default structure
192+ if ( isInitMode ) {
193+ const defaultContent = {
194+ master : {
195+ tasks : [ ] ,
196+ metadata : { } ,
197+ } ,
198+ } ;
199+
200+ await writeFile (
201+ this . _tasksFilePath ,
202+ JSON . stringify ( defaultContent , null , 2 ) ,
203+ ) ;
204+ return ;
205+ }
206+
207+ // Handle repair mode - fix existing file format
208+ const currentContent = await readJsonFileAsync < Record < string , unknown > > (
209+ this . _tasksFilePath ,
210+ ) ;
211+
212+ interface MasterStructure {
213+ tasks ?: unknown ;
214+ metadata ?: unknown ;
215+ }
216+
217+ let tasksToSave : unknown [ ] | null = null ;
218+ let metadataToSave : object | null = null ;
219+ let masterKey : string | null = null ;
220+
221+ if ( currentContent . master ) {
222+ const masterData = currentContent . master as MasterStructure ;
223+ if (
224+ Array . isArray ( masterData . tasks ) &&
225+ typeof masterData . metadata === "object"
226+ ) {
227+ masterKey = "master" ;
228+ tasksToSave = masterData . tasks ;
229+ metadataToSave = masterData . metadata ;
230+ }
231+ }
232+
233+ if ( ! masterKey ) {
234+ for ( const key of Object . keys ( currentContent ) ) {
235+ const value = currentContent [ key ] ;
236+ if ( typeof value === "object" && ! Array . isArray ( value ) ) {
237+ const data = value as MasterStructure ;
238+ if (
239+ Array . isArray ( data . tasks ) &&
240+ typeof data . metadata === "object"
241+ ) {
242+ masterKey = key ;
243+ tasksToSave = data . tasks ;
244+ metadataToSave = data . metadata ;
245+ break ;
246+ }
247+ }
248+ }
249+ }
250+
251+ if ( ! masterKey ) {
252+ if (
253+ Array . isArray ( currentContent ?. tasks ) &&
254+ typeof currentContent ?. metadata === "object"
255+ ) {
256+ tasksToSave = currentContent . tasks ;
257+ metadataToSave = currentContent . metadata ;
258+ }
259+ }
260+
261+ if ( tasksToSave !== null && metadataToSave !== null ) {
262+ const correctedContent = {
263+ master : {
264+ tasks : tasksToSave ,
265+ metadata : metadataToSave ,
266+ } ,
267+ } ;
268+
269+ await writeFile (
270+ this . _tasksFilePath ,
271+ JSON . stringify ( correctedContent , null , 2 ) ,
272+ ) ;
273+ return ;
274+ }
275+
276+ throw new Error (
277+ "Invalid tasks.json format. Could not find valid tasks and metadata to correct the file." ,
278+ ) ;
279+ } , oraOptions ) ;
280+ }
281+
165282 // ==============================================
166283 // Helpers
167284 // ==============================================
@@ -249,93 +366,6 @@ export class TaskMaster {
249366 } , oraOptions ) ;
250367 }
251368
252- // TODO: done
253- /**
254- * @description Fixes the format of the tasks.json file if necessary
255- * by encapsulating the 'tasks' and 'metadata' keys under a 'master' key
256- */
257- public async _fixTasksFileFormatAsync ( ) : Promise < void > {
258- const oraOptions = {
259- text : "Verifying tasks.json file format..." ,
260- successText : chalk . bgGreen ( "tasks.json format validated successfully!" ) ,
261- failText : chalk . bgRed ( "Failed to validate tasks.json format" ) ,
262- } ;
263-
264- await oraPromise ( async ( ) => {
265- const currentContent = await readJsonFileAsync < Record < string , unknown > > (
266- this . _tasksFilePath ,
267- ) ;
268-
269- interface MasterStructure {
270- tasks ?: unknown ;
271- metadata ?: unknown ;
272- }
273-
274- let tasksToSave : unknown [ ] | null = null ;
275- let metadataToSave : object | null = null ;
276- let masterKey : string | null = null ;
277-
278- if ( currentContent . master ) {
279- const masterData = currentContent . master as MasterStructure ;
280- if (
281- Array . isArray ( masterData . tasks ) &&
282- typeof masterData . metadata === "object"
283- ) {
284- masterKey = "master" ;
285- tasksToSave = masterData . tasks ;
286- metadataToSave = masterData . metadata ;
287- }
288- }
289-
290- if ( ! masterKey ) {
291- for ( const key of Object . keys ( currentContent ) ) {
292- const value = currentContent [ key ] ;
293- if ( typeof value === "object" && ! Array . isArray ( value ) ) {
294- const data = value as MasterStructure ;
295- if (
296- Array . isArray ( data . tasks ) &&
297- typeof data . metadata === "object"
298- ) {
299- masterKey = key ;
300- tasksToSave = data . tasks ;
301- metadataToSave = data . metadata ;
302- break ;
303- }
304- }
305- }
306- }
307-
308- if ( ! masterKey ) {
309- if (
310- Array . isArray ( currentContent ?. tasks ) &&
311- typeof currentContent ?. metadata === "object"
312- ) {
313- tasksToSave = currentContent . tasks ;
314- metadataToSave = currentContent . metadata ;
315- }
316- }
317-
318- if ( tasksToSave !== null && metadataToSave !== null ) {
319- const correctedContent = {
320- master : {
321- tasks : tasksToSave ,
322- metadata : metadataToSave ,
323- } ,
324- } ;
325-
326- await writeFile (
327- this . _tasksFilePath ,
328- JSON . stringify ( correctedContent , null , 2 ) ,
329- ) ;
330- return ;
331- }
332-
333- throw new Error (
334- "Invalid tasks.json format. Could not find valid tasks and metadata to correct the file." ,
335- ) ;
336- } , oraOptions ) ;
337- }
338-
339369 // TODO: done
340370 /**
341371 * @description Validates conversion rules for task/subtask conversion
@@ -519,8 +549,12 @@ export class TaskMaster {
519549 }
520550
521551 // TODO: done
522- private _countdown ( seconds : number ) {
523- return new Promise ( ( resolve ) => {
552+ /**
553+ * @description Starts a countdown timer
554+ * @param seconds The number of seconds to count down
555+ */
556+ public async countdownAsync ( seconds : number ) {
557+ return await new Promise ( ( resolve ) => {
524558 let remaining = seconds ;
525559 const rl = readline . createInterface ( {
526560 input : process . stdin ,
@@ -689,11 +723,7 @@ export class TaskMaster {
689723 * @param lang Language to set for TMAI responses
690724 */
691725 public async setLangAsync ( lang : string ) : Promise < void > {
692- console . log (
693- chalk . yellow (
694- "Note: Make sure the LLM used by TMAI supports the language you choose!" ,
695- ) ,
696- ) ;
726+ console . log ( chalk . yellow ( NOTE_LANGS ) ) ;
697727 await this . _executeCommandAsync (
698728 `Setting TMAI response language to ${ chalk . bold ( lang ) } ...` ,
699729 `Language set to ${ lang } successfully!` ,
@@ -1224,7 +1254,7 @@ export class TaskMaster {
12241254 "You can force conversion by manually removing dependencies, but this is not recommended unless absolutely necessary. Consider if the conversion is truly important for your workflow." ,
12251255 ) ,
12261256 ) ;
1227- await this . _countdown ( 20 ) ;
1257+ await this . countdownAsync ( 20 ) ;
12281258 return ;
12291259 }
12301260
@@ -1283,7 +1313,7 @@ export class TaskMaster {
12831313 "You can force conversion by manually removing dependencies, but this is not recommended unless absolutely necessary. Consider if the conversion is truly important for your workflow." ,
12841314 ) ,
12851315 ) ;
1286- await this . _countdown ( 20 ) ;
1316+ await this . countdownAsync ( 20 ) ;
12871317 return ;
12881318 }
12891319
0 commit comments