Skip to content

Commit 9d0c483

Browse files
committed
feat(core): add task validation and improve initialization
1 parent 56fbca8 commit 9d0c483

2 files changed

Lines changed: 100 additions & 6 deletions

File tree

src/core/TaskMaster.ts

Lines changed: 63 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ export class TaskMaster {
169169
* by encapsulating the 'tasks' and 'metadata' keys under a 'master' key
170170
* @param mode Operation mode: 'init' for initialization or 'repair' for fixing existing file
171171
*/
172-
public async _fixTasksFileFormatAsync(
172+
private async _fixTasksFileFormatAsync(
173173
mode: "init" | "repair" = "repair",
174174
): Promise<void> {
175175
const isInitMode = mode === "init";
@@ -318,6 +318,65 @@ export class TaskMaster {
318318
);
319319
}
320320

321+
// TODO: done
322+
/**
323+
* @description Validates that tasks are ready (file exists and has at least one task)
324+
* @returns True if tasks are ready, false otherwise
325+
*/
326+
public async validateTasksReadyAsync(): Promise<boolean> {
327+
// Check if tasks.json file exists
328+
if (!fs.existsSync(this._tasksFilePath)) {
329+
console.log(
330+
chalk.yellow(
331+
"TMAI is not initialized. Please run the initialization process and generate at least one task.",
332+
),
333+
);
334+
await this.countdownAsync(10);
335+
return false;
336+
}
337+
338+
try {
339+
// Read the tasks file
340+
const tasks = await this.getTasksContentAsync();
341+
342+
// Check if tasks object and master property exist
343+
if (!tasks || !tasks.master) {
344+
console.log(
345+
chalk.yellow(
346+
"TMAI is not initialized. Please run the initialization process and generate at least one task.",
347+
),
348+
);
349+
await this.countdownAsync(10);
350+
return false;
351+
}
352+
353+
// Check if there's at least one task in master.tasks
354+
if (
355+
!tasks.master.tasks ||
356+
!Array.isArray(tasks.master.tasks) ||
357+
tasks.master.tasks.length === 0
358+
) {
359+
console.log(
360+
chalk.yellow(
361+
"TMAI is not initialized. Please generate at least one task.",
362+
),
363+
);
364+
await this.countdownAsync(10);
365+
return false;
366+
}
367+
368+
return true;
369+
} catch {
370+
console.log(
371+
chalk.yellow(
372+
"TMAI is not initialized. Please run the initialization process and generate at least one task.",
373+
),
374+
);
375+
await this.countdownAsync(10);
376+
return false;
377+
}
378+
}
379+
321380
// TODO: done
322381
/**
323382
* @description Fixes the IDs of all tasks and subtasks in tasks.json to be sequential
@@ -662,6 +721,7 @@ export class TaskMaster {
662721

663722
await runCommandAsync(this._mainCommand, ["init"], false, false);
664723
console.log(chalk.bgGreen("Task-master project initialized successfully!"));
724+
await this._fixTasksFileFormatAsync("init");
665725
}
666726

667727
// TODO: done
@@ -670,7 +730,7 @@ export class TaskMaster {
670730
*/
671731
public async interactiveConfigModelAsync(): Promise<void> {
672732
await this._executeCommandAsync(
673-
"Configuring AI models...",
733+
"Configuring AI models...\n",
674734
"AI models configured successfully!",
675735
"AI model configuration failed",
676736
this._mainCommand,
@@ -693,7 +753,7 @@ export class TaskMaster {
693753
provider?: string,
694754
): Promise<void> {
695755
const oraOptions = {
696-
text: "Configuring AI models...",
756+
text: "Configuring AI models...\n",
697757
successText: chalk.bgGreen("AI models configured successfully!"),
698758
failText: chalk.bgRed("AI model configuration failed"),
699759
};

src/core/exec.ts

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
/* libs */
22
import inquirer from "inquirer";
33
import path from "node:path";
4+
import fs from "node:fs";
45

56
/* index */
67
import { taskmasterCLI } from "@/index";
@@ -141,9 +142,30 @@ export async function tmaiGenAsync() {
141142
if (choice.tmaiGenDecMenu === "tmai-parse") {
142143
const tasksJsonPath = path.join(".taskmaster", "tasks", "tasks.json");
143144
if (await existsAsync(tasksJsonPath)) {
144-
const overwrite = await askOverwriteConfirmationAsync();
145-
if (!overwrite) {
146-
return restartAsync();
145+
const fileContent = fs.readFileSync(tasksJsonPath, "utf8");
146+
let isEmpty = fileContent.trim() === "[]";
147+
148+
// Also check for the specific empty structure
149+
if (!isEmpty) {
150+
try {
151+
const tasksData = JSON.parse(fileContent);
152+
isEmpty =
153+
tasksData.master &&
154+
Array.isArray(tasksData.master.tasks) &&
155+
tasksData.master.tasks.length === 0 &&
156+
typeof tasksData.master.metadata === "object";
157+
} catch {
158+
// If parsing fails, we'll assume it's not empty
159+
isEmpty = false;
160+
}
161+
}
162+
163+
// Only ask for overwrite confirmation if the file is not empty
164+
if (!isEmpty) {
165+
const overwrite = await askOverwriteConfirmationAsync();
166+
if (!overwrite) {
167+
return restartAsync();
168+
}
147169
}
148170
}
149171

@@ -186,6 +208,10 @@ export async function tmaiGenAsync() {
186208
* - Delete tasks
187209
*/
188210
export async function tmaiManageAsync() {
211+
if (!(await tmai.validateTasksReadyAsync())) {
212+
return taskmasterCLI();
213+
}
214+
189215
let tasks = await tmai.getTasksContentAsync();
190216
const { mainIDs, subtasksIDs } = await tmai.getAllTaskIdsAsync(tasks);
191217
const { tmaiManageMenu } = await inquirer.prompt(tmaiManageMenu_prompt);
@@ -441,6 +467,10 @@ export async function tmaiManageAsync() {
441467
* dependencies. Based on the user's choice, it executes the corresponding operation.
442468
*/
443469
export async function tmaiDependenciesAsync() {
470+
if (!(await tmai.validateTasksReadyAsync())) {
471+
return taskmasterCLI();
472+
}
473+
444474
let tasks = await tmai.getTasksContentAsync();
445475
const { tmaiDepsMenu } = await inquirer.prompt(tmaiDepsMenu_prompt);
446476

@@ -492,6 +522,10 @@ export async function tmaiDependenciesAsync() {
492522
* choice, it executes the corresponding operation.
493523
*/
494524
export async function tmaiAnalysisReportDocsAsync() {
525+
if (!(await tmai.validateTasksReadyAsync())) {
526+
return taskmasterCLI();
527+
}
528+
495529
const { tmaiAnalysisReportDocsMenu } = await inquirer.prompt(
496530
tmaiAnalysisReportDocs_prompt,
497531
);

0 commit comments

Comments
 (0)