roadmap-skill 0.2.8 → 0.2.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +59 -0
- package/README.md +48 -57
- package/README.zh.md +48 -64
- package/dist/index.js +264 -66
- package/dist/index.js.map +1 -1
- package/dist/web/app/assets/{main-DUDWZy_5.js → main-CuvRBjau.js} +6 -6
- package/dist/web/app/index.html +1 -1
- package/dist/web/server.js +87 -6
- package/dist/web/server.js.map +1 -1
- package/package.json +7 -2
package/dist/index.js
CHANGED
|
@@ -276,7 +276,7 @@ var ProjectStorage = class {
|
|
|
276
276
|
if (filters.searchText && !task.title.toLowerCase().includes(filters.searchText.toLowerCase()) && !task.description.toLowerCase().includes(filters.searchText.toLowerCase())) {
|
|
277
277
|
continue;
|
|
278
278
|
}
|
|
279
|
-
if (filters.includeCompleted
|
|
279
|
+
if (filters.includeCompleted !== true && task.status === "done") {
|
|
280
280
|
continue;
|
|
281
281
|
}
|
|
282
282
|
results.push({ task, project: data.project });
|
|
@@ -345,15 +345,38 @@ var storage = new ProjectStorage();
|
|
|
345
345
|
// src/tools/project-tools.ts
|
|
346
346
|
var ProjectTypeEnum = z.enum(["roadmap", "skill-tree", "kanban"]);
|
|
347
347
|
var ProjectStatusEnum = z.enum(["active", "completed", "archived"]);
|
|
348
|
+
function toProjectSummary(project, taskCount, tags) {
|
|
349
|
+
return {
|
|
350
|
+
id: project.id,
|
|
351
|
+
name: project.name,
|
|
352
|
+
projectType: project.projectType,
|
|
353
|
+
status: project.status,
|
|
354
|
+
targetDate: project.targetDate,
|
|
355
|
+
taskCount,
|
|
356
|
+
...tags ? { tags } : {}
|
|
357
|
+
};
|
|
358
|
+
}
|
|
359
|
+
function toTaskSummary(task) {
|
|
360
|
+
return {
|
|
361
|
+
id: task.id,
|
|
362
|
+
title: task.title,
|
|
363
|
+
status: task.status,
|
|
364
|
+
priority: task.priority,
|
|
365
|
+
dueDate: task.dueDate,
|
|
366
|
+
assignee: task.assignee,
|
|
367
|
+
tags: task.tags
|
|
368
|
+
};
|
|
369
|
+
}
|
|
348
370
|
var createProjectTool = {
|
|
349
371
|
name: "create_project",
|
|
350
|
-
description: "Create a new project roadmap",
|
|
372
|
+
description: "Create a new project roadmap. Returns summary by default; set verbose=true for full data.",
|
|
351
373
|
inputSchema: z.object({
|
|
352
374
|
name: z.string().min(1, "Project name is required"),
|
|
353
375
|
description: z.string(),
|
|
354
376
|
projectType: ProjectTypeEnum,
|
|
355
377
|
startDate: z.string().regex(/^\d{4}-\d{2}-\d{2}$/, "Date must be in YYYY-MM-DD format"),
|
|
356
|
-
targetDate: z.string().regex(/^\d{4}-\d{2}-\d{2}$/, "Date must be in YYYY-MM-DD format")
|
|
378
|
+
targetDate: z.string().regex(/^\d{4}-\d{2}-\d{2}$/, "Date must be in YYYY-MM-DD format"),
|
|
379
|
+
verbose: z.boolean().optional()
|
|
357
380
|
}),
|
|
358
381
|
async execute(input) {
|
|
359
382
|
try {
|
|
@@ -367,7 +390,7 @@ var createProjectTool = {
|
|
|
367
390
|
const projectData = await storage.createProject(projectInput);
|
|
368
391
|
return {
|
|
369
392
|
success: true,
|
|
370
|
-
data: projectData
|
|
393
|
+
data: input.verbose ? projectData : toProjectSummary(projectData.project, 0)
|
|
371
394
|
};
|
|
372
395
|
} catch (error) {
|
|
373
396
|
return {
|
|
@@ -379,14 +402,33 @@ var createProjectTool = {
|
|
|
379
402
|
};
|
|
380
403
|
var listProjectsTool = {
|
|
381
404
|
name: "list_projects",
|
|
382
|
-
description: "List all projects
|
|
383
|
-
inputSchema: z.object({
|
|
384
|
-
|
|
405
|
+
description: "List all projects. Summary mode includes current project tags for Agent reuse. Set verbose=true for full project data.",
|
|
406
|
+
inputSchema: z.object({
|
|
407
|
+
verbose: z.boolean().optional()
|
|
408
|
+
}),
|
|
409
|
+
async execute(input) {
|
|
385
410
|
try {
|
|
386
411
|
const projects = await storage.listProjects();
|
|
412
|
+
if (input.verbose) {
|
|
413
|
+
return {
|
|
414
|
+
success: true,
|
|
415
|
+
data: projects
|
|
416
|
+
};
|
|
417
|
+
}
|
|
418
|
+
const summaries = await Promise.all(
|
|
419
|
+
projects.map(async (projectSummary) => {
|
|
420
|
+
const projectData = await storage.readProject(projectSummary.project.id);
|
|
421
|
+
const tags = (projectData?.tags ?? []).map((tag) => ({
|
|
422
|
+
id: tag.id,
|
|
423
|
+
name: tag.name,
|
|
424
|
+
color: tag.color
|
|
425
|
+
}));
|
|
426
|
+
return toProjectSummary(projectSummary.project, projectSummary.taskCount, tags);
|
|
427
|
+
})
|
|
428
|
+
);
|
|
387
429
|
return {
|
|
388
430
|
success: true,
|
|
389
|
-
data:
|
|
431
|
+
data: summaries
|
|
390
432
|
};
|
|
391
433
|
} catch (error) {
|
|
392
434
|
return {
|
|
@@ -398,9 +440,10 @@ var listProjectsTool = {
|
|
|
398
440
|
};
|
|
399
441
|
var getProjectTool = {
|
|
400
442
|
name: "get_project",
|
|
401
|
-
description: "Get a project by ID with all its data (tasks, tags, milestones)",
|
|
443
|
+
description: "Get a project by ID with all its data (tasks, tags, milestones). Tasks are returned as summaries by default; set verbose=true for full task data.",
|
|
402
444
|
inputSchema: z.object({
|
|
403
|
-
projectId: z.string().min(1, "Project ID is required")
|
|
445
|
+
projectId: z.string().min(1, "Project ID is required"),
|
|
446
|
+
verbose: z.boolean().optional()
|
|
404
447
|
}),
|
|
405
448
|
async execute(input) {
|
|
406
449
|
try {
|
|
@@ -413,7 +456,10 @@ var getProjectTool = {
|
|
|
413
456
|
}
|
|
414
457
|
return {
|
|
415
458
|
success: true,
|
|
416
|
-
data: projectData
|
|
459
|
+
data: input.verbose ? projectData : {
|
|
460
|
+
...projectData,
|
|
461
|
+
tasks: projectData.tasks.map(toTaskSummary)
|
|
462
|
+
}
|
|
417
463
|
};
|
|
418
464
|
} catch (error) {
|
|
419
465
|
return {
|
|
@@ -425,7 +471,7 @@ var getProjectTool = {
|
|
|
425
471
|
};
|
|
426
472
|
var updateProjectTool = {
|
|
427
473
|
name: "update_project",
|
|
428
|
-
description: "Update an existing project",
|
|
474
|
+
description: "Update an existing project. Returns summary by default; set verbose=true for full data.",
|
|
429
475
|
inputSchema: z.object({
|
|
430
476
|
projectId: z.string().min(1, "Project ID is required"),
|
|
431
477
|
name: z.string().min(1).optional(),
|
|
@@ -433,11 +479,12 @@ var updateProjectTool = {
|
|
|
433
479
|
projectType: ProjectTypeEnum.optional(),
|
|
434
480
|
status: ProjectStatusEnum.optional(),
|
|
435
481
|
startDate: z.string().regex(/^\d{4}-\d{2}-\d{2}$/).optional(),
|
|
436
|
-
targetDate: z.string().regex(/^\d{4}-\d{2}-\d{2}$/).optional()
|
|
482
|
+
targetDate: z.string().regex(/^\d{4}-\d{2}-\d{2}$/).optional(),
|
|
483
|
+
verbose: z.boolean().optional()
|
|
437
484
|
}),
|
|
438
485
|
async execute(input) {
|
|
439
486
|
try {
|
|
440
|
-
const { projectId, ...updateData } = input;
|
|
487
|
+
const { projectId, verbose, ...updateData } = input;
|
|
441
488
|
if (Object.keys(updateData).length === 0) {
|
|
442
489
|
return {
|
|
443
490
|
success: false,
|
|
@@ -454,7 +501,7 @@ var updateProjectTool = {
|
|
|
454
501
|
}
|
|
455
502
|
return {
|
|
456
503
|
success: true,
|
|
457
|
-
data: projectData
|
|
504
|
+
data: verbose ? projectData : toProjectSummary(projectData.project, projectData.tasks.length)
|
|
458
505
|
};
|
|
459
506
|
} catch (error) {
|
|
460
507
|
return {
|
|
@@ -504,6 +551,39 @@ init_esm_shims();
|
|
|
504
551
|
function generateTagId() {
|
|
505
552
|
return `tag_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
|
|
506
553
|
}
|
|
554
|
+
var HEX_COLOR_PATTERN = /^#[0-9A-Fa-f]{6}$/;
|
|
555
|
+
var TAG_COLOR_PALETTE = [
|
|
556
|
+
"#FF6B6B",
|
|
557
|
+
"#FF9F43",
|
|
558
|
+
"#FDCB6E",
|
|
559
|
+
"#6C5CE7",
|
|
560
|
+
"#74B9FF",
|
|
561
|
+
"#00B894",
|
|
562
|
+
"#00CEC9",
|
|
563
|
+
"#E17055",
|
|
564
|
+
"#FAB1A0",
|
|
565
|
+
"#55A3FF",
|
|
566
|
+
"#A29BFE",
|
|
567
|
+
"#FD79A8"
|
|
568
|
+
];
|
|
569
|
+
function hashTagName(value) {
|
|
570
|
+
let hash = 5381;
|
|
571
|
+
for (const char of value.toLowerCase()) {
|
|
572
|
+
hash = hash * 33 ^ char.charCodeAt(0);
|
|
573
|
+
}
|
|
574
|
+
return Math.abs(hash >>> 0);
|
|
575
|
+
}
|
|
576
|
+
function resolveTagColor(tagName, inputColor) {
|
|
577
|
+
if (inputColor) {
|
|
578
|
+
return inputColor;
|
|
579
|
+
}
|
|
580
|
+
const normalizedTagName = tagName.trim();
|
|
581
|
+
if (normalizedTagName.length === 0) {
|
|
582
|
+
return TAG_COLOR_PALETTE[0];
|
|
583
|
+
}
|
|
584
|
+
const colorIndex = hashTagName(normalizedTagName) % TAG_COLOR_PALETTE.length;
|
|
585
|
+
return TAG_COLOR_PALETTE[colorIndex];
|
|
586
|
+
}
|
|
507
587
|
var TagService = class {
|
|
508
588
|
storage;
|
|
509
589
|
constructor(storage2) {
|
|
@@ -535,11 +615,19 @@ var TagService = class {
|
|
|
535
615
|
code: "DUPLICATE_ERROR"
|
|
536
616
|
};
|
|
537
617
|
}
|
|
618
|
+
const resolvedColor = resolveTagColor(data.name, data.color);
|
|
619
|
+
if (!HEX_COLOR_PATTERN.test(resolvedColor)) {
|
|
620
|
+
return {
|
|
621
|
+
success: false,
|
|
622
|
+
error: `Color must be a valid hex code (e.g., #FF5733), received '${resolvedColor}'`,
|
|
623
|
+
code: "VALIDATION_ERROR"
|
|
624
|
+
};
|
|
625
|
+
}
|
|
538
626
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
539
627
|
const tag = {
|
|
540
628
|
id: generateTagId(),
|
|
541
629
|
name: data.name,
|
|
542
|
-
color:
|
|
630
|
+
color: resolvedColor,
|
|
543
631
|
description: data.description || "",
|
|
544
632
|
createdAt: now
|
|
545
633
|
};
|
|
@@ -638,6 +726,13 @@ var TagService = class {
|
|
|
638
726
|
};
|
|
639
727
|
}
|
|
640
728
|
}
|
|
729
|
+
if (data.color && !HEX_COLOR_PATTERN.test(data.color)) {
|
|
730
|
+
return {
|
|
731
|
+
success: false,
|
|
732
|
+
error: `Color must be a valid hex code (e.g., #FF5733), received '${data.color}'`,
|
|
733
|
+
code: "VALIDATION_ERROR"
|
|
734
|
+
};
|
|
735
|
+
}
|
|
641
736
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
642
737
|
const existingTag = projectData.tags[tagIndex];
|
|
643
738
|
const updatedTag = {
|
|
@@ -789,6 +884,10 @@ function calculateCompletedAt(currentStatus, newStatus, existingCompletedAt, now
|
|
|
789
884
|
}
|
|
790
885
|
return existingCompletedAt;
|
|
791
886
|
}
|
|
887
|
+
function findInvalidTagIds(projectData, tagIds) {
|
|
888
|
+
const validTagIds = new Set(projectData.tags.map((tag) => tag.id));
|
|
889
|
+
return tagIds.filter((tagId) => !validTagIds.has(tagId));
|
|
890
|
+
}
|
|
792
891
|
var TaskService = {
|
|
793
892
|
/**
|
|
794
893
|
* Create a new task in a project
|
|
@@ -806,6 +905,15 @@ var TaskService = {
|
|
|
806
905
|
code: "NOT_FOUND"
|
|
807
906
|
};
|
|
808
907
|
}
|
|
908
|
+
const incomingTagIds = data.tags ?? [];
|
|
909
|
+
const invalidTagIds = findInvalidTagIds(projectData, incomingTagIds);
|
|
910
|
+
if (invalidTagIds.length > 0) {
|
|
911
|
+
return {
|
|
912
|
+
success: false,
|
|
913
|
+
error: `Invalid tag IDs for project '${projectId}': ${invalidTagIds.join(", ")}`,
|
|
914
|
+
code: "VALIDATION_ERROR"
|
|
915
|
+
};
|
|
916
|
+
}
|
|
809
917
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
810
918
|
const task = {
|
|
811
919
|
id: generateTaskId(),
|
|
@@ -814,7 +922,7 @@ var TaskService = {
|
|
|
814
922
|
description: data.description,
|
|
815
923
|
status: "todo",
|
|
816
924
|
priority: data.priority ?? "medium",
|
|
817
|
-
tags:
|
|
925
|
+
tags: incomingTagIds,
|
|
818
926
|
dueDate: data.dueDate ?? null,
|
|
819
927
|
assignee: data.assignee ?? null,
|
|
820
928
|
createdAt: now,
|
|
@@ -907,6 +1015,16 @@ var TaskService = {
|
|
|
907
1015
|
code: "VALIDATION_ERROR"
|
|
908
1016
|
};
|
|
909
1017
|
}
|
|
1018
|
+
if (data.tags) {
|
|
1019
|
+
const invalidTagIds = findInvalidTagIds(projectData, data.tags);
|
|
1020
|
+
if (invalidTagIds.length > 0) {
|
|
1021
|
+
return {
|
|
1022
|
+
success: false,
|
|
1023
|
+
error: `Invalid tag IDs for project '${projectId}': ${invalidTagIds.join(", ")}`,
|
|
1024
|
+
code: "VALIDATION_ERROR"
|
|
1025
|
+
};
|
|
1026
|
+
}
|
|
1027
|
+
}
|
|
910
1028
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
911
1029
|
const existingTask = projectData.tasks[taskIndex];
|
|
912
1030
|
const completedAt = calculateCompletedAt(
|
|
@@ -1038,9 +1156,19 @@ var TaskService = {
|
|
|
1038
1156
|
continue;
|
|
1039
1157
|
}
|
|
1040
1158
|
const existingTask = projectData.tasks[taskIndex];
|
|
1041
|
-
let updatedTags = existingTask.tags;
|
|
1042
|
-
if (data.tags
|
|
1043
|
-
const
|
|
1159
|
+
let updatedTags = existingTask.tags ?? [];
|
|
1160
|
+
if (data.tags) {
|
|
1161
|
+
const invalidTagIds = findInvalidTagIds(projectData, data.tags);
|
|
1162
|
+
if (invalidTagIds.length > 0) {
|
|
1163
|
+
return {
|
|
1164
|
+
success: false,
|
|
1165
|
+
error: `Invalid tag IDs for project '${projectId}': ${invalidTagIds.join(", ")}`,
|
|
1166
|
+
code: "VALIDATION_ERROR"
|
|
1167
|
+
};
|
|
1168
|
+
}
|
|
1169
|
+
}
|
|
1170
|
+
if (data.tags) {
|
|
1171
|
+
const existingTags = existingTask.tags ?? [];
|
|
1044
1172
|
switch (data.tagOperation) {
|
|
1045
1173
|
case "add":
|
|
1046
1174
|
updatedTags = [.../* @__PURE__ */ new Set([...existingTags, ...data.tags])];
|
|
@@ -1105,9 +1233,20 @@ init_esm_shims();
|
|
|
1105
1233
|
// src/tools/task-tools.ts
|
|
1106
1234
|
var TaskStatusEnum = z2.enum(["todo", "in-progress", "review", "done"]);
|
|
1107
1235
|
var TaskPriorityEnum = z2.enum(["low", "medium", "high", "critical"]);
|
|
1236
|
+
function toTaskSummary2(task) {
|
|
1237
|
+
return {
|
|
1238
|
+
id: task.id,
|
|
1239
|
+
title: task.title,
|
|
1240
|
+
status: task.status,
|
|
1241
|
+
priority: task.priority,
|
|
1242
|
+
dueDate: task.dueDate,
|
|
1243
|
+
assignee: task.assignee,
|
|
1244
|
+
tags: task.tags
|
|
1245
|
+
};
|
|
1246
|
+
}
|
|
1108
1247
|
var createTaskTool = {
|
|
1109
1248
|
name: "create_task",
|
|
1110
|
-
description: "Create a new task in a project",
|
|
1249
|
+
description: "Create a new task in a project. tags must be existing tag IDs from the same project. Returns summary by default; set verbose=true for full data.",
|
|
1111
1250
|
inputSchema: z2.object({
|
|
1112
1251
|
projectId: z2.string().min(1, "Project ID is required"),
|
|
1113
1252
|
title: z2.string().min(1, "Task title is required"),
|
|
@@ -1115,7 +1254,8 @@ var createTaskTool = {
|
|
|
1115
1254
|
priority: TaskPriorityEnum.default("medium"),
|
|
1116
1255
|
tags: z2.array(z2.string()).default([]),
|
|
1117
1256
|
dueDate: z2.string().regex(/^\d{4}-\d{2}-\d{2}$/).optional(),
|
|
1118
|
-
assignee: z2.string().optional()
|
|
1257
|
+
assignee: z2.string().optional(),
|
|
1258
|
+
verbose: z2.boolean().optional()
|
|
1119
1259
|
}),
|
|
1120
1260
|
async execute(input) {
|
|
1121
1261
|
const result = await TaskService.create(input.projectId, {
|
|
@@ -1126,12 +1266,16 @@ var createTaskTool = {
|
|
|
1126
1266
|
dueDate: input.dueDate,
|
|
1127
1267
|
assignee: input.assignee
|
|
1128
1268
|
});
|
|
1129
|
-
return result;
|
|
1269
|
+
if (!result.success) return result;
|
|
1270
|
+
return {
|
|
1271
|
+
success: true,
|
|
1272
|
+
data: input.verbose ? result.data : toTaskSummary2(result.data)
|
|
1273
|
+
};
|
|
1130
1274
|
}
|
|
1131
1275
|
};
|
|
1132
1276
|
var listTasksTool = {
|
|
1133
1277
|
name: "list_tasks",
|
|
1134
|
-
description: "List tasks with optional filters",
|
|
1278
|
+
description: "List tasks with optional filters. By default, completed (done) tasks are excluded. Set includeCompleted=true to include them. Returns summaries by default; set verbose=true for full task data.",
|
|
1135
1279
|
inputSchema: z2.object({
|
|
1136
1280
|
projectId: z2.string().optional(),
|
|
1137
1281
|
status: TaskStatusEnum.optional(),
|
|
@@ -1140,7 +1284,8 @@ var listTasksTool = {
|
|
|
1140
1284
|
assignee: z2.string().optional(),
|
|
1141
1285
|
dueBefore: z2.string().regex(/^\d{4}-\d{2}-\d{2}$/).optional(),
|
|
1142
1286
|
dueAfter: z2.string().regex(/^\d{4}-\d{2}-\d{2}$/).optional(),
|
|
1143
|
-
includeCompleted: z2.boolean().optional()
|
|
1287
|
+
includeCompleted: z2.boolean().optional(),
|
|
1288
|
+
verbose: z2.boolean().optional()
|
|
1144
1289
|
}),
|
|
1145
1290
|
async execute(input) {
|
|
1146
1291
|
try {
|
|
@@ -1154,9 +1299,10 @@ var listTasksTool = {
|
|
|
1154
1299
|
dueAfter: input.dueAfter,
|
|
1155
1300
|
includeCompleted: input.includeCompleted
|
|
1156
1301
|
});
|
|
1302
|
+
const tasks = results.map((r) => r.task);
|
|
1157
1303
|
return {
|
|
1158
1304
|
success: true,
|
|
1159
|
-
data:
|
|
1305
|
+
data: input.verbose ? tasks : tasks.map(toTaskSummary2)
|
|
1160
1306
|
};
|
|
1161
1307
|
} catch (error) {
|
|
1162
1308
|
return {
|
|
@@ -1180,7 +1326,7 @@ var getTaskTool = {
|
|
|
1180
1326
|
};
|
|
1181
1327
|
var updateTaskTool = {
|
|
1182
1328
|
name: "update_task",
|
|
1183
|
-
description: "Update an existing task",
|
|
1329
|
+
description: "Update an existing task. tags must be existing tag IDs from the same project. Returns summary by default; set verbose=true for full data.",
|
|
1184
1330
|
inputSchema: z2.object({
|
|
1185
1331
|
projectId: z2.string().min(1, "Project ID is required"),
|
|
1186
1332
|
taskId: z2.string().min(1, "Task ID is required"),
|
|
@@ -1190,12 +1336,17 @@ var updateTaskTool = {
|
|
|
1190
1336
|
priority: TaskPriorityEnum.optional(),
|
|
1191
1337
|
tags: z2.array(z2.string()).optional(),
|
|
1192
1338
|
dueDate: z2.string().regex(/^\d{4}-\d{2}-\d{2}$/).optional().nullable(),
|
|
1193
|
-
assignee: z2.string().optional().nullable()
|
|
1339
|
+
assignee: z2.string().optional().nullable(),
|
|
1340
|
+
verbose: z2.boolean().optional()
|
|
1194
1341
|
}),
|
|
1195
1342
|
async execute(input) {
|
|
1196
|
-
const { projectId, taskId, ...updateData } = input;
|
|
1343
|
+
const { projectId, taskId, verbose, ...updateData } = input;
|
|
1197
1344
|
const result = await TaskService.update(projectId, taskId, updateData);
|
|
1198
|
-
return result;
|
|
1345
|
+
if (!result.success) return result;
|
|
1346
|
+
return {
|
|
1347
|
+
success: true,
|
|
1348
|
+
data: verbose ? result.data : toTaskSummary2(result.data)
|
|
1349
|
+
};
|
|
1199
1350
|
}
|
|
1200
1351
|
};
|
|
1201
1352
|
var deleteTaskTool = {
|
|
@@ -1218,22 +1369,31 @@ var deleteTaskTool = {
|
|
|
1218
1369
|
};
|
|
1219
1370
|
var batchUpdateTasksTool = {
|
|
1220
1371
|
name: "batch_update_tasks",
|
|
1221
|
-
description: "Update multiple tasks at once",
|
|
1372
|
+
description: "Update multiple tasks at once. tags must be existing tag IDs from the same project. Returns summaries by default; set verbose=true for full task data.",
|
|
1222
1373
|
inputSchema: z2.object({
|
|
1223
1374
|
projectId: z2.string().min(1, "Project ID is required"),
|
|
1224
1375
|
taskIds: z2.array(z2.string()).min(1, "At least one task ID is required"),
|
|
1225
1376
|
status: TaskStatusEnum.optional(),
|
|
1226
1377
|
priority: TaskPriorityEnum.optional(),
|
|
1227
1378
|
tags: z2.array(z2.string()).optional(),
|
|
1228
|
-
tagOperation: z2.enum(["add", "remove", "replace"]).default("replace")
|
|
1379
|
+
tagOperation: z2.enum(["add", "remove", "replace"]).default("replace"),
|
|
1380
|
+
verbose: z2.boolean().optional()
|
|
1229
1381
|
}),
|
|
1230
1382
|
async execute(input) {
|
|
1231
|
-
const { projectId, taskIds, tagOperation, ...restData } = input;
|
|
1383
|
+
const { projectId, taskIds, tagOperation, verbose, ...restData } = input;
|
|
1232
1384
|
const result = await TaskService.batchUpdate(projectId, taskIds, {
|
|
1233
1385
|
...restData,
|
|
1234
1386
|
tagOperation
|
|
1235
1387
|
});
|
|
1236
|
-
return result;
|
|
1388
|
+
if (!result.success) return result;
|
|
1389
|
+
return {
|
|
1390
|
+
success: true,
|
|
1391
|
+
data: {
|
|
1392
|
+
updatedTasks: verbose ? result.data.updatedTasks : result.data.updatedTasks.map(toTaskSummary2),
|
|
1393
|
+
updatedCount: result.data.updatedCount,
|
|
1394
|
+
notFoundIds: result.data.notFoundIds
|
|
1395
|
+
}
|
|
1396
|
+
};
|
|
1237
1397
|
}
|
|
1238
1398
|
};
|
|
1239
1399
|
|
|
@@ -1243,11 +1403,11 @@ import { z as z3 } from "zod";
|
|
|
1243
1403
|
var tagService = new TagService(storage);
|
|
1244
1404
|
var createTagTool = {
|
|
1245
1405
|
name: "create_tag",
|
|
1246
|
-
description: "Create a new tag in a project",
|
|
1406
|
+
description: "Create a new tag in a project. If color is omitted, it is generated deterministically from tag name.",
|
|
1247
1407
|
inputSchema: z3.object({
|
|
1248
1408
|
projectId: z3.string().min(1, "Project ID is required"),
|
|
1249
1409
|
name: z3.string().min(1, "Tag name is required"),
|
|
1250
|
-
color: z3.string().regex(/^#[0-9A-Fa-f]{6}$/, "Color must be a valid hex code (e.g., #FF5733)"),
|
|
1410
|
+
color: z3.string().regex(/^#[0-9A-Fa-f]{6}$/, "Color must be a valid hex code (e.g., #FF5733)").optional(),
|
|
1251
1411
|
description: z3.string().default("")
|
|
1252
1412
|
}),
|
|
1253
1413
|
async execute(input) {
|
|
@@ -2085,12 +2245,12 @@ init_esm_shims();
|
|
|
2085
2245
|
init_esm_shims();
|
|
2086
2246
|
var projectPrompts = [
|
|
2087
2247
|
{
|
|
2088
|
-
name: "
|
|
2248
|
+
name: "suggest-tasks",
|
|
2089
2249
|
description: "Intelligently recommend the next priority tasks based on urgency, due dates, and project status",
|
|
2090
2250
|
arguments: [
|
|
2091
2251
|
{
|
|
2092
2252
|
name: "projectId",
|
|
2093
|
-
description: "Specific project ID (optional; if not provided, analyze all projects)",
|
|
2253
|
+
description: "Specific project ID (optional; if not provided, auto-detect from current context or analyze all projects)",
|
|
2094
2254
|
required: false
|
|
2095
2255
|
},
|
|
2096
2256
|
{
|
|
@@ -2101,18 +2261,18 @@ var projectPrompts = [
|
|
|
2101
2261
|
]
|
|
2102
2262
|
},
|
|
2103
2263
|
{
|
|
2104
|
-
name: "
|
|
2264
|
+
name: "auto-prioritize",
|
|
2105
2265
|
description: "Automatically analyze tasks and intelligently adjust priorities, considering due dates, dependencies, and project importance",
|
|
2106
2266
|
arguments: [
|
|
2107
2267
|
{
|
|
2108
2268
|
name: "projectId",
|
|
2109
|
-
description: "Specific project ID (optional; if not provided, analyze all projects)",
|
|
2269
|
+
description: "Specific project ID (optional; if not provided, auto-detect from current context or analyze all projects)",
|
|
2110
2270
|
required: false
|
|
2111
2271
|
}
|
|
2112
2272
|
]
|
|
2113
2273
|
},
|
|
2114
2274
|
{
|
|
2115
|
-
name: "
|
|
2275
|
+
name: "add-task-details",
|
|
2116
2276
|
description: "Intelligently enhance task details, including description, acceptance criteria, subtasks, and required resources",
|
|
2117
2277
|
arguments: [
|
|
2118
2278
|
{
|
|
@@ -2123,7 +2283,7 @@ var projectPrompts = [
|
|
|
2123
2283
|
]
|
|
2124
2284
|
},
|
|
2125
2285
|
{
|
|
2126
|
-
name: "
|
|
2286
|
+
name: "quick-capture",
|
|
2127
2287
|
description: "Quickly capture ideas/tasks, auto-categorize and suggest priorities",
|
|
2128
2288
|
arguments: [
|
|
2129
2289
|
{
|
|
@@ -2133,14 +2293,25 @@ var projectPrompts = [
|
|
|
2133
2293
|
},
|
|
2134
2294
|
{
|
|
2135
2295
|
name: "projectId",
|
|
2136
|
-
description: "Target project ID (optional)",
|
|
2296
|
+
description: "Target project ID (optional; if not provided, auto-detect from current context)",
|
|
2297
|
+
required: false
|
|
2298
|
+
}
|
|
2299
|
+
]
|
|
2300
|
+
},
|
|
2301
|
+
{
|
|
2302
|
+
name: "open-web-ui",
|
|
2303
|
+
description: "Open the web visualization interface for the roadmap skill",
|
|
2304
|
+
arguments: [
|
|
2305
|
+
{
|
|
2306
|
+
name: "port",
|
|
2307
|
+
description: "Port to run the web interface on (optional, default: 7860)",
|
|
2137
2308
|
required: false
|
|
2138
2309
|
}
|
|
2139
2310
|
]
|
|
2140
2311
|
}
|
|
2141
2312
|
];
|
|
2142
2313
|
function getRecommendNextTasksPrompt(projectId, limit) {
|
|
2143
|
-
const
|
|
2314
|
+
const projectHint = projectId ? `User specified project: ${projectId}. Use this project if it exists, or inform user if not found.` : "User did not specify a project. Based on the current working directory and conversation context, try to identify the most relevant project. If a clear match exists, focus on that project; otherwise, analyze all active projects";
|
|
2144
2315
|
const taskLimit = limit ? parseInt(limit, 10) : 3;
|
|
2145
2316
|
return {
|
|
2146
2317
|
description: "Intelligent Task Recommendation Assistant",
|
|
@@ -2149,7 +2320,7 @@ function getRecommendNextTasksPrompt(projectId, limit) {
|
|
|
2149
2320
|
role: "user",
|
|
2150
2321
|
content: {
|
|
2151
2322
|
type: "text",
|
|
2152
|
-
text: `${
|
|
2323
|
+
text: `${projectHint}, please recommend the ${taskLimit} tasks I should prioritize next.
|
|
2153
2324
|
|
|
2154
2325
|
## Recommendation Logic (sorted by priority):
|
|
2155
2326
|
|
|
@@ -2209,7 +2380,7 @@ Keep task status synchronized with actual progress!`
|
|
|
2209
2380
|
};
|
|
2210
2381
|
}
|
|
2211
2382
|
function getAutoPrioritizePrompt(projectId) {
|
|
2212
|
-
const
|
|
2383
|
+
const projectHint = projectId ? `User specified project: ${projectId}. Use this project if it exists, or inform user if not found.` : "User did not specify a project. Based on the current working directory and conversation context, try to identify the most relevant project. If a clear match exists, focus on that project; otherwise, analyze all active projects";
|
|
2213
2384
|
return {
|
|
2214
2385
|
description: "Intelligent Priority Optimization Assistant",
|
|
2215
2386
|
messages: [
|
|
@@ -2217,7 +2388,7 @@ function getAutoPrioritizePrompt(projectId) {
|
|
|
2217
2388
|
role: "user",
|
|
2218
2389
|
content: {
|
|
2219
2390
|
type: "text",
|
|
2220
|
-
text: `${
|
|
2391
|
+
text: `${projectHint}, please automatically analyze and adjust priorities.
|
|
2221
2392
|
|
|
2222
2393
|
## Priority Adjustment Rules:
|
|
2223
2394
|
|
|
@@ -2251,7 +2422,7 @@ function getAutoPrioritizePrompt(projectId) {
|
|
|
2251
2422
|
- Identify task dependency relationships
|
|
2252
2423
|
- Evaluate overall project health
|
|
2253
2424
|
3. **Generate adjustment suggestions**: List tasks needing priority changes with reasons
|
|
2254
|
-
4. **Batch update**: Use batch_update_tasks to execute priority adjustments
|
|
2425
|
+
4. **Batch update**: Use batch_update_tasks to execute priority adjustments immediately \u2014 no confirmation needed
|
|
2255
2426
|
|
|
2256
2427
|
## Output Format:
|
|
2257
2428
|
|
|
@@ -2273,7 +2444,7 @@ function getAutoPrioritizePrompt(projectId) {
|
|
|
2273
2444
|
### Keep Unchanged (Priorities are reasonable)
|
|
2274
2445
|
- List tasks with reasonable priority settings
|
|
2275
2446
|
|
|
2276
|
-
Please provide analysis results
|
|
2447
|
+
Please provide analysis results and immediately execute batch_update_tasks to apply the priority adjustments \u2014 no confirmation needed.`
|
|
2277
2448
|
}
|
|
2278
2449
|
}
|
|
2279
2450
|
]
|
|
@@ -2328,7 +2499,7 @@ If the task is complex, suggest breaking it down:
|
|
|
2328
2499
|
- If design task: Add design specs, review criteria
|
|
2329
2500
|
- If documentation task: Add doc structure, references
|
|
2330
2501
|
- If testing task: Add test scenarios, coverage scope
|
|
2331
|
-
4. **
|
|
2502
|
+
4. **Apply enhancement**: Use update_task to update task description immediately \u2014 no confirmation needed
|
|
2332
2503
|
|
|
2333
2504
|
## Updated task should include:
|
|
2334
2505
|
|
|
@@ -2351,14 +2522,14 @@ If the task is complex, suggest breaking it down:
|
|
|
2351
2522
|
- References: [link]
|
|
2352
2523
|
\`\`\`
|
|
2353
2524
|
|
|
2354
|
-
Please fetch task info
|
|
2525
|
+
Please fetch task info and immediately use update_task to apply the enhanced details \u2014 no confirmation needed.`
|
|
2355
2526
|
}
|
|
2356
2527
|
}
|
|
2357
2528
|
]
|
|
2358
2529
|
};
|
|
2359
2530
|
}
|
|
2360
2531
|
function getQuickCapturePrompt(idea, projectId) {
|
|
2361
|
-
const projectContext = projectId ? `
|
|
2532
|
+
const projectContext = projectId ? `User specified project: ${projectId}. Use this project if it exists, or inform user if not found.` : "User did not specify a project. Based on the current working directory and conversation context, try to identify the most relevant project. If a clear match exists, use that project; otherwise, analyze all active projects and select the best match";
|
|
2362
2533
|
return {
|
|
2363
2534
|
description: "Quick Capture Assistant",
|
|
2364
2535
|
messages: [
|
|
@@ -2370,7 +2541,7 @@ function getQuickCapturePrompt(idea, projectId) {
|
|
|
2370
2541
|
|
|
2371
2542
|
${projectContext}
|
|
2372
2543
|
|
|
2373
|
-
## Please
|
|
2544
|
+
## Please complete the following steps immediately:
|
|
2374
2545
|
|
|
2375
2546
|
### 1. Task Information Extraction
|
|
2376
2547
|
Extract from description:
|
|
@@ -2379,11 +2550,10 @@ Extract from description:
|
|
|
2379
2550
|
- **Task Type**: bug / feature / refactor / docs / chore
|
|
2380
2551
|
- **Estimated Priority**: critical / high / medium / low (based on urgency in description)
|
|
2381
2552
|
|
|
2382
|
-
### 2. Project
|
|
2383
|
-
If user didn't specify a project, please:
|
|
2553
|
+
### 2. Project Selection (if no project specified)
|
|
2384
2554
|
- List all active projects
|
|
2385
2555
|
- Analyze which project the task content is most relevant to
|
|
2386
|
-
-
|
|
2556
|
+
- Select the most suitable project automatically
|
|
2387
2557
|
|
|
2388
2558
|
### 3. Tag Suggestions
|
|
2389
2559
|
Suggest relevant tags:
|
|
@@ -2391,11 +2561,21 @@ Suggest relevant tags:
|
|
|
2391
2561
|
- Priority tags: urgent, important
|
|
2392
2562
|
- Domain tags: frontend, backend, design, testing (if applicable)
|
|
2393
2563
|
|
|
2394
|
-
|
|
2395
|
-
|
|
2564
|
+
Tag consistency rules:
|
|
2565
|
+
- list_tags first, then prefer reusing existing tags in that project
|
|
2566
|
+
- If no suitable tag exists, create_tag first (color optional, system can auto-generate) and then use the returned tag ID
|
|
2567
|
+
- create_task.tags must contain tag IDs only (not tag names)
|
|
2396
2568
|
|
|
2397
|
-
###
|
|
2398
|
-
|
|
2569
|
+
### 4. Create Task
|
|
2570
|
+
Use create_task to create the task immediately \u2014 no confirmation needed.
|
|
2571
|
+
Before create_task:
|
|
2572
|
+
1. Call list_tags(projectId)
|
|
2573
|
+
2. Match suggested tags to existing tags by name (case-insensitive)
|
|
2574
|
+
3. For missing tags, call create_tag(projectId, name, color?)
|
|
2575
|
+
4. Build create_task.tags from tag IDs only
|
|
2576
|
+
|
|
2577
|
+
### 5. Status
|
|
2578
|
+
After creating, if work starts immediately, use update_task to set status to in-progress.
|
|
2399
2579
|
|
|
2400
2580
|
## Example:
|
|
2401
2581
|
|
|
@@ -2407,13 +2587,29 @@ After creating the task, if you start working on it immediately, consider settin
|
|
|
2407
2587
|
- Type: Bug
|
|
2408
2588
|
- Priority: High (affects user experience)
|
|
2409
2589
|
- Suggested Tags: bug, frontend, mobile
|
|
2590
|
+
- create_task.tags: [existing_or_new_tag_ids]
|
|
2410
2591
|
- Recommended Project: [Recommend if there's a web project]
|
|
2411
2592
|
|
|
2412
|
-
## Current Idea
|
|
2593
|
+
## Current Idea:
|
|
2413
2594
|
|
|
2414
2595
|
Idea: "${idea}"
|
|
2415
2596
|
|
|
2416
|
-
|
|
2597
|
+
Analyze the idea, select the best matching project, and immediately execute create_task \u2014 no confirmation needed.`
|
|
2598
|
+
}
|
|
2599
|
+
}
|
|
2600
|
+
]
|
|
2601
|
+
};
|
|
2602
|
+
}
|
|
2603
|
+
function getOpenWebUIPrompt(port) {
|
|
2604
|
+
const portNum = port ? parseInt(port, 10) : 7860;
|
|
2605
|
+
return {
|
|
2606
|
+
description: "Open Web Visualization Interface",
|
|
2607
|
+
messages: [
|
|
2608
|
+
{
|
|
2609
|
+
role: "user",
|
|
2610
|
+
content: {
|
|
2611
|
+
type: "text",
|
|
2612
|
+
text: `Please open the roadmap-skill web interface by calling the open_web_interface tool with port ${portNum}. Do it immediately without asking for confirmation.`
|
|
2417
2613
|
}
|
|
2418
2614
|
}
|
|
2419
2615
|
]
|
|
@@ -2421,14 +2617,16 @@ Please analyze and generate task suggestions. After user confirmation, execute c
|
|
|
2421
2617
|
}
|
|
2422
2618
|
function getPromptByName(name, args) {
|
|
2423
2619
|
switch (name) {
|
|
2424
|
-
case "
|
|
2620
|
+
case "suggest-tasks":
|
|
2425
2621
|
return getRecommendNextTasksPrompt(args?.projectId, args?.limit);
|
|
2426
|
-
case "
|
|
2622
|
+
case "auto-prioritize":
|
|
2427
2623
|
return getAutoPrioritizePrompt(args?.projectId);
|
|
2428
|
-
case "
|
|
2624
|
+
case "add-task-details":
|
|
2429
2625
|
return getEnhanceTaskDetailsPrompt(args?.taskId || "");
|
|
2430
|
-
case "
|
|
2626
|
+
case "quick-capture":
|
|
2431
2627
|
return getQuickCapturePrompt(args?.idea || "", args?.projectId);
|
|
2628
|
+
case "open-web-ui":
|
|
2629
|
+
return getOpenWebUIPrompt(args?.port);
|
|
2432
2630
|
default:
|
|
2433
2631
|
return null;
|
|
2434
2632
|
}
|