Skip to content

Commit 4be25bc

Browse files
Add tool and rule recommendation fields to task
1 parent 9d2380a commit 4be25bc

File tree

9 files changed

+1452
-343
lines changed

9 files changed

+1452
-343
lines changed

index.ts

Lines changed: 211 additions & 240 deletions
Large diffs are not rendered by default.

package-lock.json

Lines changed: 818 additions & 14 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
"access": "public"
3838
},
3939
"dependencies": {
40-
"@modelcontextprotocol/sdk": "^0.5.0",
40+
"@modelcontextprotocol/sdk": "^1.7.0",
4141
"chalk": "^5.3.0",
4242
"commander": "^11.0.0",
4343
"glob": "^10.3.10",

src/server/TaskManagerServer.ts

Lines changed: 76 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,11 @@ export class TaskManagerServer {
3131
private taskCounter = 0;
3232
private data: TaskManagerFile = { projects: [] };
3333
private filePath: string;
34+
private initialized: Promise<void>;
3435

3536
constructor(testFilePath?: string) {
3637
this.filePath = testFilePath || TASK_FILE_PATH;
37-
this.loadTasks();
38+
this.initialized = this.loadTasks();
3839
}
3940

4041
private async loadTasks() {
@@ -66,6 +67,10 @@ export class TaskManagerServer {
6667
}
6768
}
6869

70+
private async ensureInitialized() {
71+
await this.initialized;
72+
}
73+
6974
private async saveTasks() {
7075
try {
7176
// Ensure directory exists before writing
@@ -91,13 +96,15 @@ export class TaskManagerServer {
9196
if (!proj) return "Project not found";
9297

9398
let table = "\nProgress Status:\n";
94-
table += "| Task ID | Title | Description | Status | Approval |\n";
95-
table += "|----------|----------|------|------|----------|\n";
99+
table += "| Task ID | Title | Description | Status | Approval | Tools | Rules |\n";
100+
table += "|----------|----------|------|------|----------|--------|--------|\n";
96101

97102
for (const task of proj.tasks) {
98103
const status = task.status === "done" ? "✅ Done" : (task.status === "in progress" ? "🔄 In Progress" : "⏳ Not Started");
99104
const approved = task.approved ? "✅ Approved" : "⏳ Pending";
100-
table += `| ${task.id} | ${task.title} | ${task.description} | ${status} | ${approved} |\n`;
105+
const tools = task.toolRecommendations ? "✓" : "-";
106+
const rules = task.ruleRecommendations ? "✓" : "-";
107+
table += `| ${task.id} | ${task.title} | ${task.description} | ${status} | ${approved} | ${tools} | ${rules} |\n`;
101108
}
102109

103110
return table;
@@ -122,10 +129,10 @@ export class TaskManagerServer {
122129

123130
public async createProject(
124131
initialPrompt: string,
125-
tasks: { title: string; description: string }[],
132+
tasks: { title: string; description: string; toolRecommendations?: string; ruleRecommendations?: string }[],
126133
projectPlan?: string
127134
) {
128-
await this.loadTasks();
135+
await this.ensureInitialized();
129136
this.projectCounter += 1;
130137
const projectId = `proj-${this.projectCounter}`;
131138

@@ -139,6 +146,8 @@ export class TaskManagerServer {
139146
status: "not started",
140147
approved: false,
141148
completedDetails: "",
149+
toolRecommendations: taskDef.toolRecommendations,
150+
ruleRecommendations: taskDef.ruleRecommendations,
142151
});
143152
}
144153

@@ -168,7 +177,7 @@ export class TaskManagerServer {
168177
}
169178

170179
public async getNextTask(projectId: string) {
171-
await this.loadTasks();
180+
await this.ensureInitialized();
172181
const proj = this.data.projects.find((p) => p.projectId === projectId);
173182
if (!proj) {
174183
return { status: "error", message: "Project not found" };
@@ -210,7 +219,7 @@ export class TaskManagerServer {
210219
taskId: string,
211220
completedDetails?: string
212221
) {
213-
await this.loadTasks();
222+
await this.ensureInitialized();
214223
const proj = this.data.projects.find((p) => p.projectId === projectId);
215224
if (!proj) return { status: "error", message: "Project not found" };
216225
const task = proj.tasks.find((t) => t.id === taskId);
@@ -238,7 +247,7 @@ export class TaskManagerServer {
238247
}
239248

240249
public async approveTaskCompletion(projectId: string, taskId: string) {
241-
await this.loadTasks();
250+
await this.ensureInitialized();
242251
const proj = this.data.projects.find((p) => p.projectId === projectId);
243252
if (!proj) return { status: "error", message: "Project not found" };
244253
const task = proj.tasks.find((t) => t.id === taskId);
@@ -263,7 +272,7 @@ export class TaskManagerServer {
263272
}
264273

265274
public async approveProjectCompletion(projectId: string) {
266-
await this.loadTasks();
275+
await this.ensureInitialized();
267276
const proj = this.data.projects.find((p) => p.projectId === projectId);
268277
if (!proj) return { status: "error", message: "Project not found" };
269278

@@ -292,7 +301,7 @@ export class TaskManagerServer {
292301
}
293302

294303
public async openTaskDetails(taskId: string) {
295-
await this.loadTasks();
304+
await this.ensureInitialized();
296305
for (const proj of this.data.projects) {
297306
const target = proj.tasks.find((t) => t.id === taskId);
298307
if (target) {
@@ -317,18 +326,19 @@ export class TaskManagerServer {
317326
}
318327

319328
public async listProjects(state?: TaskState) {
320-
await this.loadTasks();
321-
let filteredProjects = this.data.projects;
329+
await this.ensureInitialized();
330+
331+
let filteredProjects = [...this.data.projects];
322332

323333
if (state && state !== "all") {
324-
filteredProjects = this.data.projects.filter(proj => {
334+
filteredProjects = filteredProjects.filter((proj) => {
325335
switch (state) {
326336
case "open":
327-
return !proj.completed && proj.tasks.some(task => task.status !== "done");
337+
return !proj.completed && proj.tasks.some((task) => task.status !== "done");
328338
case "pending_approval":
329-
return proj.tasks.some(task => task.status === "done" && !task.approved);
339+
return proj.tasks.some((task) => task.status === "done" && !task.approved);
330340
case "completed":
331-
return proj.completed && proj.tasks.every(task => task.status === "done" && task.approved);
341+
return proj.completed && proj.tasks.every((task) => task.status === "done" && task.approved);
332342
default:
333343
return true; // Should not happen due to type safety
334344
}
@@ -343,34 +353,37 @@ export class TaskManagerServer {
343353
projectId: proj.projectId,
344354
initialPrompt: proj.initialPrompt,
345355
totalTasks: proj.tasks.length,
346-
completedTasks: proj.tasks.filter((t) => t.status === "done").length,
347-
approvedTasks: proj.tasks.filter((t) => t.approved).length,
356+
completedTasks: proj.tasks.filter((task) => task.status === "done").length,
357+
approvedTasks: proj.tasks.filter((task) => task.approved).length,
348358
})),
349359
};
350360
}
351361

352362
public async listTasks(projectId?: string, state?: TaskState) {
353-
await this.loadTasks();
354-
let tasks: Task[] = [];
355-
363+
await this.ensureInitialized();
364+
365+
// If projectId is provided, verify the project exists
356366
if (projectId) {
357-
const project = this.data.projects.find(p => p.projectId === projectId);
367+
const project = this.data.projects.find((p) => p.projectId === projectId);
358368
if (!project) {
359-
return { status: 'error', message: 'Project not found' };
369+
return {
370+
status: "error",
371+
message: "Project not found"
372+
};
360373
}
361-
tasks = project.tasks;
362-
} else {
363-
// Flatten all tasks from all projects if no projectId is given
364-
tasks = this.data.projects.flatMap(project => project.tasks);
365374
}
366375

376+
// Flatten all tasks from all projects if no projectId is given
377+
let tasks = projectId
378+
? this.data.projects.find((p) => p.projectId === projectId)?.tasks || []
379+
: this.data.projects.flatMap((p) => p.tasks);
380+
367381
// Apply state filtering
368-
let filteredTasks = tasks;
369382
if (state && state !== "all") {
370-
filteredTasks = tasks.filter(task => {
383+
tasks = tasks.filter((task) => {
371384
switch (state) {
372385
case "open":
373-
return task.status === "not started" || task.status === "in progress";
386+
return task.status !== "done";
374387
case "pending_approval":
375388
return task.status === "done" && !task.approved;
376389
case "completed":
@@ -383,29 +396,29 @@ export class TaskManagerServer {
383396

384397
return {
385398
status: "tasks_listed",
386-
message: `Tasks in the system${projectId ? ` for project ${projectId}` : ""}:\n${filteredTasks.length} tasks found.`,
387-
tasks: filteredTasks.map(task => ({
399+
message: `Tasks in the system${projectId ? ` for project ${projectId}` : ""}:\n${tasks.length} tasks found.`,
400+
tasks: tasks.map(task => ({
388401
id: task.id,
389402
title: task.title,
390403
description: task.description,
391404
status: task.status,
392-
approved: task.approved
405+
approved: task.approved,
406+
completedDetails: task.completedDetails,
407+
toolRecommendations: task.toolRecommendations,
408+
ruleRecommendations: task.ruleRecommendations
393409
}))
394410
};
395411
}
396412

397413
public async addTasksToProject(
398414
projectId: string,
399-
tasks: { title: string; description: string }[]
415+
tasks: { title: string; description: string; toolRecommendations?: string; ruleRecommendations?: string }[]
400416
) {
401-
await this.loadTasks();
417+
await this.ensureInitialized();
402418
const proj = this.data.projects.find((p) => p.projectId === projectId);
403-
if (!proj) return { status: "error", message: "Project not found" };
404-
if (proj.completed)
405-
return {
406-
status: "error",
407-
message: "Cannot add tasks to completed project",
408-
};
419+
if (!proj) {
420+
return { status: "error", message: "Project not found" };
421+
}
409422

410423
const newTasks: Task[] = [];
411424
for (const taskDef of tasks) {
@@ -417,6 +430,8 @@ export class TaskManagerServer {
417430
status: "not started",
418431
approved: false,
419432
completedDetails: "",
433+
toolRecommendations: taskDef.toolRecommendations,
434+
ruleRecommendations: taskDef.ruleRecommendations,
420435
});
421436
}
422437

@@ -438,36 +453,33 @@ export class TaskManagerServer {
438453
public async updateTask(
439454
projectId: string,
440455
taskId: string,
441-
updates: { title?: string; description?: string }
456+
updates: {
457+
title?: string;
458+
description?: string;
459+
toolRecommendations?: string;
460+
ruleRecommendations?: string;
461+
}
442462
) {
443-
await this.loadTasks();
444-
const proj = this.data.projects.find((p) => p.projectId === projectId);
445-
if (!proj) return { status: "error", message: "Project not found" };
463+
await this.ensureInitialized();
464+
const project = this.data.projects.find((p) => p.projectId === projectId);
465+
if (!project) {
466+
throw new Error(`Project not found: ${projectId}`);
467+
}
446468

447-
const task = proj.tasks.find((t) => t.id === taskId);
448-
if (!task) return { status: "error", message: "Task not found" };
449-
if (task.status === "done")
450-
return { status: "error", message: "Cannot update completed task" };
469+
const taskIndex = project.tasks.findIndex((t) => t.id === taskId);
470+
if (taskIndex === -1) {
471+
throw new Error(`Task not found: ${taskId}`);
472+
}
451473

452-
if (updates.title) task.title = updates.title;
453-
if (updates.description) task.description = updates.description;
474+
// Update the task with the provided updates
475+
project.tasks[taskIndex] = { ...project.tasks[taskIndex], ...updates };
454476

455477
await this.saveTasks();
456-
457-
const progressTable = this.formatTaskProgressTable(projectId);
458-
return {
459-
status: "task_updated",
460-
message: `Task ${taskId} has been updated.\n${progressTable}`,
461-
task: {
462-
id: task.id,
463-
title: task.title,
464-
description: task.description,
465-
},
466-
};
478+
return project.tasks[taskIndex];
467479
}
468480

469481
public async deleteTask(projectId: string, taskId: string) {
470-
await this.loadTasks();
482+
await this.ensureInitialized();
471483
const proj = this.data.projects.find((p) => p.projectId === projectId);
472484
if (!proj) return { status: "error", message: "Project not found" };
473485

src/types/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ export interface Task {
88
status: "not started" | "in progress" | "done";
99
approved: boolean;
1010
completedDetails: string;
11+
toolRecommendations?: string;
12+
ruleRecommendations?: string;
1113
}
1214

1315
export interface Project {

0 commit comments

Comments
 (0)