roadmap-skill 0.2.9 → 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 +23 -57
- package/README.zh.md +26 -64
- package/dist/index.js +124 -14
- package/dist/index.js.map +1 -1
- package/dist/web/server.js +86 -5
- package/dist/web/server.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,65 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [0.2.10] - 2026-02-27
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
- **Contributing Section**: Added Contributing section to README (en/zh)
|
|
12
|
+
|
|
13
|
+
### Changed
|
|
14
|
+
- **README**: Revamped copy for both en/zh versions, improved clarity and tone
|
|
15
|
+
- **Tag ID Workflow**: Unified tag-id handling with deterministic color fallback
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
## [0.2.9] - 2026-02-26
|
|
19
|
+
|
|
20
|
+
### Added
|
|
21
|
+
- **Development Scripts**: Added `dev:web`, `dev:server`, `dev:full`, and `inspector` npm scripts
|
|
22
|
+
- **Vite Proxy**: Frontend dev server now proxies API requests to backend automatically
|
|
23
|
+
- **Verbose Parameter**: Tools now support `verbose` parameter for compact vs full data responses
|
|
24
|
+
- **Summary Types**: Added `TaskSummary` and `ProjectSummary` types for lightweight responses
|
|
25
|
+
- **MCP Inspector**: Added `npm run inspector` command for debugging MCP server
|
|
26
|
+
|
|
27
|
+
### Changed
|
|
28
|
+
- **UI Layout**: Moved filter bar to header alongside title for better space usage
|
|
29
|
+
- **Compact Mode**: Optimized spacing, removed tags, reduced margins and padding
|
|
30
|
+
- **Hover Animation**: Reduced card hover displacement from `-translate-y-1` to `-translate-y-0.5`
|
|
31
|
+
- **Create Button**: Changed task creation button color to project theme green
|
|
32
|
+
|
|
33
|
+
### Fixed
|
|
34
|
+
- **Completed Tasks**: Fixed "All" filter to properly include completed tasks via `includeCompleted` parameter
|
|
35
|
+
|
|
36
|
+
## [0.2.8] - 2026-02-26
|
|
37
|
+
|
|
38
|
+
### Fixed
|
|
39
|
+
- **MCP Transport**: Resolved stdio transport issues for better CLI compatibility
|
|
40
|
+
- **Tag System**: Improved tag management and display in task cards
|
|
41
|
+
|
|
42
|
+
### Changed
|
|
43
|
+
- Updated README with latest features and improvements
|
|
44
|
+
|
|
45
|
+
## [0.2.7] - 2026-02-26
|
|
46
|
+
|
|
47
|
+
### Fixed
|
|
48
|
+
- **Static Files Path**: Corrected bundled static files path for npx environment execution
|
|
49
|
+
|
|
50
|
+
### Added
|
|
51
|
+
- **Release Documentation**: Added release workflow documentation to AGENTS.md
|
|
52
|
+
|
|
53
|
+
## [0.2.6] - 2026-02-26
|
|
54
|
+
|
|
55
|
+
### Fixed
|
|
56
|
+
- **Static Files Path**: Resolved static files path resolution for npx execution environment
|
|
57
|
+
|
|
58
|
+
## [0.2.5] - 2026-02-26
|
|
59
|
+
|
|
60
|
+
### Added
|
|
61
|
+
- **NovaBoard UI**: Integrated tag system with NovaBoard-style dashboard design
|
|
62
|
+
- **Tag System**: Full tag management with color coding and filtering
|
|
63
|
+
|
|
64
|
+
### Fixed
|
|
65
|
+
- **Server Path**: Use `__dirname` instead of `process.cwd()` for reliable static files path resolution
|
|
66
|
+
|
|
8
67
|
## [0.2.0] - 2026-02-10
|
|
9
68
|
|
|
10
69
|
### Added
|
package/README.md
CHANGED
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
</p>
|
|
6
6
|
|
|
7
7
|
<p align="center">
|
|
8
|
-
<strong>
|
|
9
|
-
|
|
8
|
+
<strong>Shared roadmap for humans and AI Agents</strong><br>
|
|
9
|
+
Visual kanban for you. MCP server for Agents. Local-first.
|
|
10
10
|
</p>
|
|
11
11
|
|
|
12
12
|
<p align="center">
|
|
@@ -26,15 +26,15 @@
|
|
|
26
26
|
|
|
27
27
|
---
|
|
28
28
|
|
|
29
|
-
##
|
|
29
|
+
## What Makes It Different
|
|
30
30
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
31
|
+
**Shared context** — Chat with your Agent to plan tasks, or edit directly in the Kanban — both stay in sync. Your Agent always sees the latest state.
|
|
32
|
+
|
|
33
|
+
**Agent-native** — Built as an MCP server. Your AI can create, update, and query tasks directly in conversation.
|
|
34
|
+
|
|
35
|
+
**Lightweight Kanban** — Open `localhost:7860` when you feel like it, or ask your Agent to open it with `open_web_interface`. Or just stay in chat. All three work.
|
|
36
|
+
|
|
37
|
+
**Local-first** — Your data lives on your machine. No accounts, no cloud sync, no vendor lock-in.
|
|
38
38
|
|
|
39
39
|
---
|
|
40
40
|
|
|
@@ -282,69 +282,35 @@ The AI will immediately create the project and tasks, saving them to local stora
|
|
|
282
282
|
|
|
283
283
|
## Who Is This For?
|
|
284
284
|
|
|
285
|
-
|
|
286
|
-
|---------|--------------------------------|
|
|
287
|
-
| **Solo Developers** | Manage personal projects through conversation, avoid getting lost in complex tools |
|
|
288
|
-
| **AI Power Users** | Let Agent directly read/write tasks, goodbye to copy-pasting hassle |
|
|
289
|
-
| **Vibe Coders** | Capture inspirations on the fly, automatically save to collection box |
|
|
290
|
-
| **Small Teams** | Simple task assignment and progress tracking, zero learning curve |
|
|
291
|
-
| **Privacy-conscious Users** | Data stored completely locally, never uploaded to any cloud service |
|
|
285
|
+
Solo developers, AI power users, and vibe coders who want their Agent to be a real collaborator — not just a code generator.
|
|
292
286
|
|
|
293
287
|
---
|
|
294
288
|
|
|
295
289
|
## Typical Use Cases
|
|
296
290
|
|
|
297
|
-
### 1. Capture
|
|
298
|
-
|
|
299
|
-
When discussing new features with AI, suddenly think of an optimization:
|
|
300
|
-
|
|
301
|
-
> "Add this to my collection: Refactor user auth module using JWT + Refresh Token scheme"
|
|
302
|
-
|
|
303
|
-
AI automatically creates the task, and you'll see it in the Kanban later.
|
|
304
|
-
|
|
305
|
-
### 2. Let AI Plan Project Structure
|
|
306
|
-
|
|
307
|
-
Starting a new project? Just ask AI to break it down:
|
|
308
|
-
|
|
309
|
-
> "Create an e-commerce admin dashboard project with product management, order processing, and user permissions modules, broken down into specific development tasks"
|
|
310
|
-
|
|
311
|
-
AI auto-creates the project structure. Just open the Kanban in browser and drag tasks to start working.
|
|
291
|
+
### 1. Capture Ideas Without Breaking Flow
|
|
312
292
|
|
|
313
|
-
|
|
293
|
+
Mid-session, something comes to mind:
|
|
314
294
|
|
|
315
|
-
|
|
295
|
+
> "Note this down: switch the auth module to JWT + refresh token rotation"
|
|
316
296
|
|
|
317
|
-
|
|
297
|
+
Your Agent creates the task. You stay in flow. Open the Kanban later to review.
|
|
318
298
|
|
|
319
|
-
|
|
299
|
+
### 2. Let AI Bootstrap Your Project Plan
|
|
320
300
|
|
|
321
|
-
|
|
301
|
+
Starting something new:
|
|
322
302
|
|
|
323
|
-
|
|
303
|
+
> "Set up a project for the admin dashboard — product management, orders, and user permissions. Break each into tasks."
|
|
324
304
|
|
|
325
|
-
|
|
305
|
+
Agent scaffolds the whole structure. You open the board and start dragging.
|
|
326
306
|
|
|
327
|
-
|
|
307
|
+
### 3. Check In Without Leaving the Chat
|
|
328
308
|
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
## Installation
|
|
332
|
-
|
|
333
|
-
### Requirements
|
|
334
|
-
|
|
335
|
-
- Node.js 18+ (recommended 20+)
|
|
336
|
-
|
|
337
|
-
### Global Install
|
|
309
|
+
> "What's left on the current project? Anything high priority I haven't touched?"
|
|
338
310
|
|
|
339
|
-
|
|
340
|
-
npm install -g roadmap-skill
|
|
341
|
-
```
|
|
342
|
-
|
|
343
|
-
### Use Without Installing
|
|
311
|
+
> "Mark the login feature done and add a task for writing tests."
|
|
344
312
|
|
|
345
|
-
|
|
346
|
-
npx roadmap-skill # Full MCP server
|
|
347
|
-
```
|
|
313
|
+
No tab switching. No copy-pasting. Just ask.
|
|
348
314
|
|
|
349
315
|
---
|
|
350
316
|
|
package/README.zh.md
CHANGED
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
</p>
|
|
6
6
|
|
|
7
7
|
<p align="center">
|
|
8
|
-
<strong
|
|
9
|
-
|
|
8
|
+
<strong>人类与 AI Agent 共享的项目看板</strong><br>
|
|
9
|
+
你看到的,Agent 也看到。对话里规划,看板里审阅。或者相反。
|
|
10
10
|
</p>
|
|
11
11
|
|
|
12
12
|
<p align="center">
|
|
@@ -26,15 +26,15 @@
|
|
|
26
26
|
|
|
27
27
|
---
|
|
28
28
|
|
|
29
|
-
##
|
|
29
|
+
## 这个 MCP 有什么不同?
|
|
30
30
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
31
|
+
**人机共享视图** — 在对话里和 Agent 一起规划任务,也可以直接在看板上手动编辑,两种方式实时互通。你和Agent 始终能获取到最新状态。
|
|
32
|
+
|
|
33
|
+
**Agent 原生** — 以 MCP 服务器形式运行。AI 可以在对话中直接创建、更新、查询任务。
|
|
34
|
+
|
|
35
|
+
**轻量看板** — 你想看的时候打开 `localhost:7860`。懒得开浏览器?直接让 Agent `/open-web-ui` 也行。
|
|
36
|
+
|
|
37
|
+
**本地优先** — 数据存在你的机器上。无需账号,无云同步,不依赖任何第三方服务。
|
|
38
38
|
|
|
39
39
|
---
|
|
40
40
|
|
|
@@ -279,69 +279,33 @@ AI 会立即为你创建项目和任务,并自动写入本地存储。你可
|
|
|
279
279
|
|
|
280
280
|
## 适合谁使用
|
|
281
281
|
|
|
282
|
-
|
|
283
|
-
|------|---------------------------|
|
|
284
|
-
| **独立开发者** | 用对话管理个人项目,避免在复杂工具中迷失 |
|
|
285
|
-
| **AI 重度用户** | 让 Agent 直接读写任务,告别来回粘贴的繁琐 |
|
|
286
|
-
| **Vibe Coder** | 随手让 AI 记录灵感,自动沉淀到收集箱 |
|
|
287
|
-
| **小团队协作** | 简单的任务分配与进度追踪,无需学习成本 |
|
|
288
|
-
| **隐私敏感者** | 数据完全本地存储,不上传任何云端服务 |
|
|
289
|
-
|
|
290
|
-
---
|
|
282
|
+
独立开发者、AI 重度用户、Vibe Coder — 想让 Agent 真正参与项目协作,而不只是写代码的人。
|
|
291
283
|
|
|
292
284
|
## 典型使用场景
|
|
293
285
|
|
|
294
|
-
### 1.
|
|
295
|
-
|
|
296
|
-
正在和 AI 讨论新功能时,突然想到一个优化点:
|
|
297
|
-
|
|
298
|
-
> "帮我把这个想法记到收集箱:重构用户认证模块,使用 JWT + Refresh Token 方案"
|
|
299
|
-
|
|
300
|
-
AI 自动创建任务,稍后你打开看板就能看到待整理的想法。
|
|
301
|
-
|
|
302
|
-
### 2. 让 AI 规划项目结构
|
|
303
|
-
|
|
304
|
-
开始一个新项目时,直接让 AI 帮你分解:
|
|
305
|
-
|
|
306
|
-
> "创建一个电商后台管理项目,包含商品管理、订单处理、用户权限三个模块,每个模块分解为具体的开发任务"
|
|
286
|
+
### 1. 不打断流地记录想法
|
|
307
287
|
|
|
308
|
-
|
|
288
|
+
编着编着突然想到一个优化点:
|
|
309
289
|
|
|
310
|
-
|
|
290
|
+
> "记一下:把认证模块改成 JWT + refresh token 方案"
|
|
311
291
|
|
|
312
|
-
|
|
292
|
+
Agent 创建任务。你继续写代码。稍后打开看板再回顾。
|
|
313
293
|
|
|
314
|
-
|
|
294
|
+
### 2. 让 AI 帮你搭建项目结构
|
|
315
295
|
|
|
316
|
-
|
|
296
|
+
开始一个新项目:
|
|
317
297
|
|
|
318
|
-
|
|
298
|
+
> "创建一个电商后台项目,包含商品管理、订单处理、用户权限三个模块,每个模块拆分为具体任务"
|
|
319
299
|
|
|
320
|
-
|
|
300
|
+
Agent 直接搭好整个结构。你打开看板开始拖拽。
|
|
321
301
|
|
|
322
|
-
|
|
302
|
+
### 3. 不离开对话窗口就能检查进度
|
|
323
303
|
|
|
324
|
-
|
|
304
|
+
> "当前项目还剩什么?有没有高优先级的任务还没动?"
|
|
325
305
|
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
## 安装
|
|
329
|
-
|
|
330
|
-
### 环境要求
|
|
306
|
+
> "把登录功能标为已完成,再加一个写测试的任务"
|
|
331
307
|
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
### 全局安装
|
|
335
|
-
|
|
336
|
-
```bash
|
|
337
|
-
npm install -g roadmap-skill
|
|
338
|
-
```
|
|
339
|
-
|
|
340
|
-
### 免安装使用
|
|
341
|
-
|
|
342
|
-
```bash
|
|
343
|
-
npx roadmap-skill # 完整 MCP 服务器
|
|
344
|
-
```
|
|
308
|
+
不用切换标签页,不用复制粘贴。直接问就行。
|
|
345
309
|
|
|
346
310
|
---
|
|
347
311
|
|
|
@@ -359,11 +323,9 @@ npx roadmap-skill # 完整 MCP 服务器
|
|
|
359
323
|
|
|
360
324
|
## 支持平台
|
|
361
325
|
|
|
362
|
-
- ✅ **Claude Code** — 命令行 AI 助手
|
|
363
|
-
- ✅ **
|
|
364
|
-
- ✅
|
|
365
|
-
- ✅ **VS Code** — 通过 Cline 或 Roo Code 扩展
|
|
366
|
-
- ✅ **任意 MCP 客户端** — 标准 MCP 协议支持
|
|
326
|
+
- ✅ **Claude Code, Codex, OpenCode** — 命令行 AI 助手
|
|
327
|
+
- ✅ **Cursor, VS Code** — AI 驱动的 IDE
|
|
328
|
+
- ✅ **任意支持 MCP 的客户端** — 标准 MCP 协议支持
|
|
367
329
|
|
|
368
330
|
---
|
|
369
331
|
|
package/dist/index.js
CHANGED
|
@@ -345,14 +345,15 @@ 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) {
|
|
348
|
+
function toProjectSummary(project, taskCount, tags) {
|
|
349
349
|
return {
|
|
350
350
|
id: project.id,
|
|
351
351
|
name: project.name,
|
|
352
352
|
projectType: project.projectType,
|
|
353
353
|
status: project.status,
|
|
354
354
|
targetDate: project.targetDate,
|
|
355
|
-
taskCount
|
|
355
|
+
taskCount,
|
|
356
|
+
...tags ? { tags } : {}
|
|
356
357
|
};
|
|
357
358
|
}
|
|
358
359
|
function toTaskSummary(task) {
|
|
@@ -401,16 +402,33 @@ var createProjectTool = {
|
|
|
401
402
|
};
|
|
402
403
|
var listProjectsTool = {
|
|
403
404
|
name: "list_projects",
|
|
404
|
-
description: "List all projects.
|
|
405
|
+
description: "List all projects. Summary mode includes current project tags for Agent reuse. Set verbose=true for full project data.",
|
|
405
406
|
inputSchema: z.object({
|
|
406
407
|
verbose: z.boolean().optional()
|
|
407
408
|
}),
|
|
408
409
|
async execute(input) {
|
|
409
410
|
try {
|
|
410
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
|
+
);
|
|
411
429
|
return {
|
|
412
430
|
success: true,
|
|
413
|
-
data:
|
|
431
|
+
data: summaries
|
|
414
432
|
};
|
|
415
433
|
} catch (error) {
|
|
416
434
|
return {
|
|
@@ -533,6 +551,39 @@ init_esm_shims();
|
|
|
533
551
|
function generateTagId() {
|
|
534
552
|
return `tag_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
|
|
535
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
|
+
}
|
|
536
587
|
var TagService = class {
|
|
537
588
|
storage;
|
|
538
589
|
constructor(storage2) {
|
|
@@ -564,11 +615,19 @@ var TagService = class {
|
|
|
564
615
|
code: "DUPLICATE_ERROR"
|
|
565
616
|
};
|
|
566
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
|
+
}
|
|
567
626
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
568
627
|
const tag = {
|
|
569
628
|
id: generateTagId(),
|
|
570
629
|
name: data.name,
|
|
571
|
-
color:
|
|
630
|
+
color: resolvedColor,
|
|
572
631
|
description: data.description || "",
|
|
573
632
|
createdAt: now
|
|
574
633
|
};
|
|
@@ -667,6 +726,13 @@ var TagService = class {
|
|
|
667
726
|
};
|
|
668
727
|
}
|
|
669
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
|
+
}
|
|
670
736
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
671
737
|
const existingTag = projectData.tags[tagIndex];
|
|
672
738
|
const updatedTag = {
|
|
@@ -818,6 +884,10 @@ function calculateCompletedAt(currentStatus, newStatus, existingCompletedAt, now
|
|
|
818
884
|
}
|
|
819
885
|
return existingCompletedAt;
|
|
820
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
|
+
}
|
|
821
891
|
var TaskService = {
|
|
822
892
|
/**
|
|
823
893
|
* Create a new task in a project
|
|
@@ -835,6 +905,15 @@ var TaskService = {
|
|
|
835
905
|
code: "NOT_FOUND"
|
|
836
906
|
};
|
|
837
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
|
+
}
|
|
838
917
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
839
918
|
const task = {
|
|
840
919
|
id: generateTaskId(),
|
|
@@ -843,7 +922,7 @@ var TaskService = {
|
|
|
843
922
|
description: data.description,
|
|
844
923
|
status: "todo",
|
|
845
924
|
priority: data.priority ?? "medium",
|
|
846
|
-
tags:
|
|
925
|
+
tags: incomingTagIds,
|
|
847
926
|
dueDate: data.dueDate ?? null,
|
|
848
927
|
assignee: data.assignee ?? null,
|
|
849
928
|
createdAt: now,
|
|
@@ -936,6 +1015,16 @@ var TaskService = {
|
|
|
936
1015
|
code: "VALIDATION_ERROR"
|
|
937
1016
|
};
|
|
938
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
|
+
}
|
|
939
1028
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
940
1029
|
const existingTask = projectData.tasks[taskIndex];
|
|
941
1030
|
const completedAt = calculateCompletedAt(
|
|
@@ -1067,9 +1156,19 @@ var TaskService = {
|
|
|
1067
1156
|
continue;
|
|
1068
1157
|
}
|
|
1069
1158
|
const existingTask = projectData.tasks[taskIndex];
|
|
1070
|
-
let updatedTags = existingTask.tags;
|
|
1071
|
-
if (data.tags
|
|
1072
|
-
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 ?? [];
|
|
1073
1172
|
switch (data.tagOperation) {
|
|
1074
1173
|
case "add":
|
|
1075
1174
|
updatedTags = [.../* @__PURE__ */ new Set([...existingTags, ...data.tags])];
|
|
@@ -1147,7 +1246,7 @@ function toTaskSummary2(task) {
|
|
|
1147
1246
|
}
|
|
1148
1247
|
var createTaskTool = {
|
|
1149
1248
|
name: "create_task",
|
|
1150
|
-
description: "Create a new task in a project. Returns summary by default; set verbose=true for full data.",
|
|
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.",
|
|
1151
1250
|
inputSchema: z2.object({
|
|
1152
1251
|
projectId: z2.string().min(1, "Project ID is required"),
|
|
1153
1252
|
title: z2.string().min(1, "Task title is required"),
|
|
@@ -1227,7 +1326,7 @@ var getTaskTool = {
|
|
|
1227
1326
|
};
|
|
1228
1327
|
var updateTaskTool = {
|
|
1229
1328
|
name: "update_task",
|
|
1230
|
-
description: "Update an existing task. Returns summary by default; set verbose=true for full data.",
|
|
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.",
|
|
1231
1330
|
inputSchema: z2.object({
|
|
1232
1331
|
projectId: z2.string().min(1, "Project ID is required"),
|
|
1233
1332
|
taskId: z2.string().min(1, "Task ID is required"),
|
|
@@ -1270,7 +1369,7 @@ var deleteTaskTool = {
|
|
|
1270
1369
|
};
|
|
1271
1370
|
var batchUpdateTasksTool = {
|
|
1272
1371
|
name: "batch_update_tasks",
|
|
1273
|
-
description: "Update multiple tasks at once. Returns summaries by default; set verbose=true for full task data.",
|
|
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.",
|
|
1274
1373
|
inputSchema: z2.object({
|
|
1275
1374
|
projectId: z2.string().min(1, "Project ID is required"),
|
|
1276
1375
|
taskIds: z2.array(z2.string()).min(1, "At least one task ID is required"),
|
|
@@ -1304,11 +1403,11 @@ import { z as z3 } from "zod";
|
|
|
1304
1403
|
var tagService = new TagService(storage);
|
|
1305
1404
|
var createTagTool = {
|
|
1306
1405
|
name: "create_tag",
|
|
1307
|
-
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.",
|
|
1308
1407
|
inputSchema: z3.object({
|
|
1309
1408
|
projectId: z3.string().min(1, "Project ID is required"),
|
|
1310
1409
|
name: z3.string().min(1, "Tag name is required"),
|
|
1311
|
-
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(),
|
|
1312
1411
|
description: z3.string().default("")
|
|
1313
1412
|
}),
|
|
1314
1413
|
async execute(input) {
|
|
@@ -2462,8 +2561,18 @@ Suggest relevant tags:
|
|
|
2462
2561
|
- Priority tags: urgent, important
|
|
2463
2562
|
- Domain tags: frontend, backend, design, testing (if applicable)
|
|
2464
2563
|
|
|
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)
|
|
2568
|
+
|
|
2465
2569
|
### 4. Create Task
|
|
2466
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
|
|
2467
2576
|
|
|
2468
2577
|
### 5. Status
|
|
2469
2578
|
After creating, if work starts immediately, use update_task to set status to in-progress.
|
|
@@ -2478,6 +2587,7 @@ After creating, if work starts immediately, use update_task to set status to in-
|
|
|
2478
2587
|
- Type: Bug
|
|
2479
2588
|
- Priority: High (affects user experience)
|
|
2480
2589
|
- Suggested Tags: bug, frontend, mobile
|
|
2590
|
+
- create_task.tags: [existing_or_new_tag_ids]
|
|
2481
2591
|
- Recommended Project: [Recommend if there's a web project]
|
|
2482
2592
|
|
|
2483
2593
|
## Current Idea:
|