@kmgeon/taskflow 0.1.3
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/README.md +374 -0
- package/bin/task-mcp.mjs +19 -0
- package/bin/task.mjs +19 -0
- package/docs/clean-code.md +29 -0
- package/docs/git.md +36 -0
- package/docs/guideline.md +25 -0
- package/docs/security.md +32 -0
- package/docs/step-by-step.md +29 -0
- package/docs/superpowers/specs/2026-03-21-cli-advisor-design.md +383 -0
- package/docs/superpowers/specs/2026-03-21-init-redesign-design.md +429 -0
- package/docs/superpowers/specs/2026-03-21-skill-architecture-design.md +362 -0
- package/docs/superpowers/specs/2026-03-23-t-create-task-run-design.md +40 -0
- package/docs/superpowers/specs/2026-03-23-task-run-design.md +44 -0
- package/docs/tdd.md +41 -0
- package/package.json +114 -0
- package/src/app/(protected)/dashboard/page.tsx +7 -0
- package/src/app/(protected)/layout.tsx +10 -0
- package/src/app/api/[[...hono]]/route.ts +13 -0
- package/src/app/example/page.tsx +11 -0
- package/src/app/favicon.ico +0 -0
- package/src/app/globals.css +168 -0
- package/src/app/layout.tsx +35 -0
- package/src/app/page.tsx +5 -0
- package/src/app/providers.tsx +57 -0
- package/src/backend/config/index.ts +36 -0
- package/src/backend/hono/app.ts +32 -0
- package/src/backend/hono/context.ts +38 -0
- package/src/backend/http/response.ts +64 -0
- package/src/backend/middleware/context.ts +23 -0
- package/src/backend/middleware/error.ts +31 -0
- package/src/backend/middleware/supabase.ts +23 -0
- package/src/backend/supabase/client.ts +17 -0
- package/src/cli/commands/__tests__/task-commands.test.ts +170 -0
- package/src/cli/commands/advisor.ts +45 -0
- package/src/cli/commands/ask.ts +50 -0
- package/src/cli/commands/board.ts +72 -0
- package/src/cli/commands/init.ts +184 -0
- package/src/cli/commands/list.ts +138 -0
- package/src/cli/commands/run.ts +143 -0
- package/src/cli/commands/set-status.ts +50 -0
- package/src/cli/commands/show.ts +28 -0
- package/src/cli/commands/tree.ts +72 -0
- package/src/cli/index.ts +38 -0
- package/src/cli/lib/__tests__/formatter.test.ts +123 -0
- package/src/cli/lib/error-boundary.test.ts +135 -0
- package/src/cli/lib/error-boundary.ts +70 -0
- package/src/cli/lib/formatter.ts +764 -0
- package/src/cli/lib/trd.ts +33 -0
- package/src/cli/lib/validate.test.ts +89 -0
- package/src/cli/lib/validate.ts +43 -0
- package/src/cli/prompts/task-run.md +25 -0
- package/src/components/layout/AppLayout.tsx +15 -0
- package/src/components/layout/Sidebar.tsx +124 -0
- package/src/components/ui/accordion.tsx +58 -0
- package/src/components/ui/avatar.tsx +50 -0
- package/src/components/ui/badge.tsx +36 -0
- package/src/components/ui/button.tsx +56 -0
- package/src/components/ui/card.tsx +79 -0
- package/src/components/ui/checkbox.tsx +30 -0
- package/src/components/ui/dialog.tsx +122 -0
- package/src/components/ui/dropdown-menu.tsx +200 -0
- package/src/components/ui/file-upload.tsx +50 -0
- package/src/components/ui/form.tsx +179 -0
- package/src/components/ui/input.tsx +25 -0
- package/src/components/ui/label.tsx +26 -0
- package/src/components/ui/scroll-area.tsx +48 -0
- package/src/components/ui/select.tsx +160 -0
- package/src/components/ui/separator.tsx +31 -0
- package/src/components/ui/sheet.tsx +140 -0
- package/src/components/ui/textarea.tsx +22 -0
- package/src/components/ui/toast.tsx +129 -0
- package/src/components/ui/toaster.tsx +35 -0
- package/src/core/ai/claude-client.ts +79 -0
- package/src/core/claude-runner/flag-builder.ts +57 -0
- package/src/core/claude-runner/index.ts +2 -0
- package/src/core/claude-runner/spawner.ts +86 -0
- package/src/core/prd/__tests__/auto-analyzer.test.ts +35 -0
- package/src/core/prd/__tests__/generator.test.ts +26 -0
- package/src/core/prd/__tests__/scanner.test.ts +35 -0
- package/src/core/prd/auto-analyzer.ts +9 -0
- package/src/core/prd/generator.ts +8 -0
- package/src/core/prd/scanner.ts +117 -0
- package/src/core/project/__tests__/claude-setup.test.ts +133 -0
- package/src/core/project/__tests__/config.test.ts +30 -0
- package/src/core/project/__tests__/init.test.ts +37 -0
- package/src/core/project/__tests__/skill-setup.test.ts +62 -0
- package/src/core/project/claude-setup.ts +224 -0
- package/src/core/project/config.ts +34 -0
- package/src/core/project/docs-setup.ts +26 -0
- package/src/core/project/docs-templates.ts +205 -0
- package/src/core/project/init.ts +40 -0
- package/src/core/project/skill-setup.ts +32 -0
- package/src/core/project/skill-templates.ts +277 -0
- package/src/core/task/index.ts +16 -0
- package/src/core/types.ts +58 -0
- package/src/features/example/backend/error.ts +9 -0
- package/src/features/example/backend/route.ts +52 -0
- package/src/features/example/backend/schema.ts +25 -0
- package/src/features/example/backend/service.ts +73 -0
- package/src/features/example/components/example-status.test.tsx +97 -0
- package/src/features/example/components/example-status.tsx +160 -0
- package/src/features/example/hooks/useExampleQuery.ts +23 -0
- package/src/features/example/lib/dto.test.ts +57 -0
- package/src/features/example/lib/dto.ts +5 -0
- package/src/features/kanban/backend/__tests__/sse-broadcaster.test.ts +137 -0
- package/src/features/kanban/backend/__tests__/sse-event-format.test.ts +55 -0
- package/src/features/kanban/backend/route.ts +55 -0
- package/src/features/kanban/backend/sse-broadcaster.ts +142 -0
- package/src/features/kanban/backend/sse-route.ts +43 -0
- package/src/features/kanban/components/KanbanBoard.tsx +105 -0
- package/src/features/kanban/components/KanbanColumn.tsx +51 -0
- package/src/features/kanban/components/KanbanError.tsx +29 -0
- package/src/features/kanban/components/KanbanSkeleton.tsx +46 -0
- package/src/features/kanban/components/ProgressCard.tsx +42 -0
- package/src/features/kanban/components/TaskCard.tsx +76 -0
- package/src/features/kanban/components/__tests__/kanban-components.test.tsx +86 -0
- package/src/features/kanban/hooks/useTaskSse.ts +66 -0
- package/src/features/kanban/hooks/useTasksQuery.ts +52 -0
- package/src/features/kanban/lib/__tests__/kanban-utils.test.ts +97 -0
- package/src/features/kanban/lib/kanban-utils.ts +37 -0
- package/src/features/taskflow/constants.ts +54 -0
- package/src/features/taskflow/index.ts +27 -0
- package/src/features/taskflow/lib/__tests__/filter.test.ts +89 -0
- package/src/features/taskflow/lib/__tests__/graph.test.ts +247 -0
- package/src/features/taskflow/lib/__tests__/repository.test.ts +233 -0
- package/src/features/taskflow/lib/__tests__/serializer.test.ts +98 -0
- package/src/features/taskflow/lib/advisor/__tests__/advisor-integration.test.ts +98 -0
- package/src/features/taskflow/lib/advisor/ai-advisor.test.ts +40 -0
- package/src/features/taskflow/lib/advisor/ai-advisor.ts +20 -0
- package/src/features/taskflow/lib/advisor/context-builder.test.ts +73 -0
- package/src/features/taskflow/lib/advisor/context-builder.ts +151 -0
- package/src/features/taskflow/lib/advisor/db.test.ts +106 -0
- package/src/features/taskflow/lib/advisor/db.ts +185 -0
- package/src/features/taskflow/lib/advisor/local-summary.test.ts +53 -0
- package/src/features/taskflow/lib/advisor/local-summary.ts +72 -0
- package/src/features/taskflow/lib/advisor/prompts.ts +86 -0
- package/src/features/taskflow/lib/filter.ts +54 -0
- package/src/features/taskflow/lib/fs-utils.ts +50 -0
- package/src/features/taskflow/lib/graph.ts +148 -0
- package/src/features/taskflow/lib/index-builder.ts +42 -0
- package/src/features/taskflow/lib/repository.ts +168 -0
- package/src/features/taskflow/lib/serializer.ts +62 -0
- package/src/features/taskflow/lib/watcher.ts +40 -0
- package/src/features/taskflow/types.ts +71 -0
- package/src/hooks/use-toast.ts +194 -0
- package/src/lib/remote/api-client.ts +40 -0
- package/src/lib/supabase/client.ts +8 -0
- package/src/lib/supabase/server.ts +46 -0
- package/src/lib/supabase/types.ts +3 -0
- package/src/lib/utils.ts +6 -0
- package/src/mcp/index.ts +7 -0
- package/src/mcp/server.ts +21 -0
- package/src/mcp/tools/brainstorm.ts +48 -0
- package/src/mcp/tools/prd.ts +71 -0
- package/src/mcp/tools/project.ts +39 -0
- package/src/mcp/tools/task-status.ts +40 -0
- package/src/mcp/tools/task.ts +82 -0
- package/src/mcp/util.ts +6 -0
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
3
|
+
import { createTask } from "../../core/task/index.js";
|
|
4
|
+
import { resolveProjectRoot } from "../util.js";
|
|
5
|
+
|
|
6
|
+
export function registerBrainstormTools(server: McpServer): void {
|
|
7
|
+
server.tool(
|
|
8
|
+
"expand_subtasks",
|
|
9
|
+
"브레인스토밍 결과를 실제 태스크 파일로 생성합니다",
|
|
10
|
+
{
|
|
11
|
+
projectRoot: z.string().optional(),
|
|
12
|
+
parentTaskId: z.string(),
|
|
13
|
+
subtasks: z.array(z.object({
|
|
14
|
+
title: z.string(),
|
|
15
|
+
description: z.string(),
|
|
16
|
+
priority: z.number().optional(),
|
|
17
|
+
dependencies: z.array(z.string()).optional(),
|
|
18
|
+
})),
|
|
19
|
+
},
|
|
20
|
+
async ({ projectRoot, parentTaskId, subtasks }) => {
|
|
21
|
+
try {
|
|
22
|
+
const root = resolveProjectRoot(projectRoot);
|
|
23
|
+
const created = [];
|
|
24
|
+
for (const sub of subtasks) {
|
|
25
|
+
const task = await createTask(root, {
|
|
26
|
+
title: sub.title,
|
|
27
|
+
description: sub.description,
|
|
28
|
+
priority: sub.priority ?? 0,
|
|
29
|
+
parentId: parentTaskId,
|
|
30
|
+
dependencies: sub.dependencies,
|
|
31
|
+
});
|
|
32
|
+
created.push(task);
|
|
33
|
+
}
|
|
34
|
+
return {
|
|
35
|
+
content: [{
|
|
36
|
+
type: "text" as const,
|
|
37
|
+
text: `${created.length}개 서브태스크 생성 완료\n${JSON.stringify(created, null, 2)}`,
|
|
38
|
+
}],
|
|
39
|
+
};
|
|
40
|
+
} catch (error) {
|
|
41
|
+
return {
|
|
42
|
+
content: [{ type: "text" as const, text: `오류: ${error instanceof Error ? error.message : String(error)}` }],
|
|
43
|
+
isError: true,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
);
|
|
48
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
3
|
+
import { savePrd } from "../../core/prd/generator.js";
|
|
4
|
+
import { scanFiles, sampleFiles, inferProjectName } from "../../core/prd/scanner.js";
|
|
5
|
+
import { resolveProjectRoot } from "../util.js";
|
|
6
|
+
import fs from "node:fs/promises";
|
|
7
|
+
import path from "node:path";
|
|
8
|
+
|
|
9
|
+
export function registerPrdTools(server: McpServer): void {
|
|
10
|
+
server.tool(
|
|
11
|
+
"scan_codebase",
|
|
12
|
+
"코드베이스를 스캔하여 파일 목록과 시그니처를 반환합니다 (AI 분석 없음)",
|
|
13
|
+
{ projectRoot: z.string().optional() },
|
|
14
|
+
async ({ projectRoot }) => {
|
|
15
|
+
try {
|
|
16
|
+
const root = resolveProjectRoot(projectRoot);
|
|
17
|
+
const files = await scanFiles(root);
|
|
18
|
+
const samples = await sampleFiles(files, root);
|
|
19
|
+
const projectName = inferProjectName(samples, root);
|
|
20
|
+
return {
|
|
21
|
+
content: [{
|
|
22
|
+
type: "text" as const,
|
|
23
|
+
text: JSON.stringify({ files, samples, projectName }, null, 2),
|
|
24
|
+
}],
|
|
25
|
+
};
|
|
26
|
+
} catch (error) {
|
|
27
|
+
return {
|
|
28
|
+
content: [{ type: "text" as const, text: `오류: ${error instanceof Error ? error.message : String(error)}` }],
|
|
29
|
+
isError: true,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
server.tool(
|
|
36
|
+
"save_prd",
|
|
37
|
+
"PRD 마크다운을 .taskflow/prd.md에 저장합니다",
|
|
38
|
+
{ projectRoot: z.string().optional(), markdown: z.string() },
|
|
39
|
+
async ({ projectRoot, markdown }) => {
|
|
40
|
+
try {
|
|
41
|
+
const root = resolveProjectRoot(projectRoot);
|
|
42
|
+
const filePath = await savePrd(root, markdown);
|
|
43
|
+
return { content: [{ type: "text" as const, text: `PRD 저장 완료: ${filePath}` }] };
|
|
44
|
+
} catch (error) {
|
|
45
|
+
return {
|
|
46
|
+
content: [{ type: "text" as const, text: `오류: ${error instanceof Error ? error.message : String(error)}` }],
|
|
47
|
+
isError: true,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
server.tool(
|
|
54
|
+
"read_prd",
|
|
55
|
+
".taskflow/prd.md를 읽어서 반환합니다",
|
|
56
|
+
{ projectRoot: z.string().optional() },
|
|
57
|
+
async ({ projectRoot }) => {
|
|
58
|
+
try {
|
|
59
|
+
const root = resolveProjectRoot(projectRoot);
|
|
60
|
+
const filePath = path.join(root, ".taskflow", "prd.md");
|
|
61
|
+
const content = await fs.readFile(filePath, "utf-8");
|
|
62
|
+
return { content: [{ type: "text" as const, text: content }] };
|
|
63
|
+
} catch (error) {
|
|
64
|
+
return {
|
|
65
|
+
content: [{ type: "text" as const, text: `오류: PRD 파일을 읽을 수 없습니다. ${error instanceof Error ? error.message : String(error)}` }],
|
|
66
|
+
isError: true,
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
},
|
|
70
|
+
);
|
|
71
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
3
|
+
import { initProject } from "../../core/project/init.js";
|
|
4
|
+
import { generateClaudeMd, generateMcpJson, appendClaudeImport } from "../../core/project/claude-setup.js";
|
|
5
|
+
import { resolveProjectRoot } from "../util.js";
|
|
6
|
+
|
|
7
|
+
export function registerProjectTools(server: McpServer): void {
|
|
8
|
+
server.tool(
|
|
9
|
+
"initialize_project",
|
|
10
|
+
"프로젝트를 초기화합니다 (.taskflow 디렉토리 + config.json 생성)",
|
|
11
|
+
{ projectRoot: z.string().optional(), projectName: z.string().optional() },
|
|
12
|
+
async ({ projectRoot, projectName }) => {
|
|
13
|
+
try {
|
|
14
|
+
const root = resolveProjectRoot(projectRoot);
|
|
15
|
+
const result = await initProject(root, projectName);
|
|
16
|
+
return { content: [{ type: "text" as const, text: result.created ? `프로젝트가 초기화되었습니다: ${root}/.taskflow` : `이미 초기화된 프로젝트입니다: ${root}/.taskflow` }] };
|
|
17
|
+
} catch (error) {
|
|
18
|
+
return { content: [{ type: "text" as const, text: `오류: ${error instanceof Error ? error.message : String(error)}` }], isError: true };
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
);
|
|
22
|
+
|
|
23
|
+
server.tool(
|
|
24
|
+
"generate_claude_md",
|
|
25
|
+
"CLAUDE.md를 동적으로 생성/갱신합니다",
|
|
26
|
+
{ projectRoot: z.string().optional(), projectName: z.string(), summary: z.string().optional(), stack: z.array(z.string()).optional() },
|
|
27
|
+
async ({ projectRoot, projectName, summary, stack }) => {
|
|
28
|
+
try {
|
|
29
|
+
const root = resolveProjectRoot(projectRoot);
|
|
30
|
+
await generateClaudeMd(root, { projectName, summary, stack });
|
|
31
|
+
await generateMcpJson(root);
|
|
32
|
+
await appendClaudeImport(root);
|
|
33
|
+
return { content: [{ type: "text" as const, text: "CLAUDE.md, .mcp.json 생성 완료" }] };
|
|
34
|
+
} catch (error) {
|
|
35
|
+
return { content: [{ type: "text" as const, text: `오류: ${error instanceof Error ? error.message : String(error)}` }], isError: true };
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
);
|
|
39
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
3
|
+
import { updateTask, listTasks, recommend } from "../../core/task/index.js";
|
|
4
|
+
import { resolveProjectRoot } from "../util.js";
|
|
5
|
+
|
|
6
|
+
export function registerTaskStatusTools(server: McpServer): void {
|
|
7
|
+
server.tool(
|
|
8
|
+
"set_task_status",
|
|
9
|
+
"태스크 상태를 변경합니다",
|
|
10
|
+
{ projectRoot: z.string().optional(), taskId: z.string(), status: z.string() },
|
|
11
|
+
async ({ projectRoot, taskId, status }) => {
|
|
12
|
+
try {
|
|
13
|
+
const root = resolveProjectRoot(projectRoot);
|
|
14
|
+
const task = await updateTask(root, taskId, { status: status as any });
|
|
15
|
+
return { content: [{ type: "text" as const, text: `태스크 ${taskId} 상태 → ${task.status}` }] };
|
|
16
|
+
} catch (error) {
|
|
17
|
+
return { content: [{ type: "text" as const, text: `오류: ${error instanceof Error ? error.message : String(error)}` }], isError: true };
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
);
|
|
21
|
+
|
|
22
|
+
server.tool(
|
|
23
|
+
"get_next_task",
|
|
24
|
+
"의존성과 우선순위 기반으로 다음 작업할 태스크를 추천합니다",
|
|
25
|
+
{ projectRoot: z.string().optional(), count: z.number().optional(), group: z.string().optional() },
|
|
26
|
+
async ({ projectRoot, count, group }) => {
|
|
27
|
+
try {
|
|
28
|
+
const root = resolveProjectRoot(projectRoot);
|
|
29
|
+
let tasks = await listTasks(root);
|
|
30
|
+
if (group) {
|
|
31
|
+
tasks = tasks.filter((t) => t.group === group);
|
|
32
|
+
}
|
|
33
|
+
const recommendations = recommend(tasks, { limit: count ?? 3 });
|
|
34
|
+
return { content: [{ type: "text" as const, text: JSON.stringify(recommendations, null, 2) }] };
|
|
35
|
+
} catch (error) {
|
|
36
|
+
return { content: [{ type: "text" as const, text: `오류: ${error instanceof Error ? error.message : String(error)}` }], isError: true };
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
);
|
|
40
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
3
|
+
import { listTasks, readTask, createTask, updateTask, deleteTask } from "../../core/task/index.js";
|
|
4
|
+
import { resolveProjectRoot } from "../util.js";
|
|
5
|
+
|
|
6
|
+
export function registerTaskTools(server: McpServer): void {
|
|
7
|
+
server.tool(
|
|
8
|
+
"list_tasks",
|
|
9
|
+
"태스크 목록을 조회합니다",
|
|
10
|
+
{ projectRoot: z.string().optional(), status: z.string().optional(), sortBy: z.string().optional(), sortOrder: z.string().optional() },
|
|
11
|
+
async ({ projectRoot, status, sortBy, sortOrder }) => {
|
|
12
|
+
try {
|
|
13
|
+
const root = resolveProjectRoot(projectRoot);
|
|
14
|
+
const tasks = await listTasks(root, { filter: status ? { status: status as any } : undefined, sortKey: sortBy as any, sortOrder: sortOrder as any });
|
|
15
|
+
return { content: [{ type: "text" as const, text: JSON.stringify(tasks, null, 2) }] };
|
|
16
|
+
} catch (error) {
|
|
17
|
+
return { content: [{ type: "text" as const, text: `오류: ${error instanceof Error ? error.message : String(error)}` }], isError: true };
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
);
|
|
21
|
+
|
|
22
|
+
server.tool(
|
|
23
|
+
"read_task",
|
|
24
|
+
"태스크 상세 정보를 조회합니다",
|
|
25
|
+
{ projectRoot: z.string().optional(), taskId: z.string() },
|
|
26
|
+
async ({ projectRoot, taskId }) => {
|
|
27
|
+
try {
|
|
28
|
+
const root = resolveProjectRoot(projectRoot);
|
|
29
|
+
const task = await readTask(root, taskId);
|
|
30
|
+
if (!task) return { content: [{ type: "text" as const, text: `태스크를 찾을 수 없습니다: ${taskId}` }], isError: true };
|
|
31
|
+
return { content: [{ type: "text" as const, text: JSON.stringify(task, null, 2) }] };
|
|
32
|
+
} catch (error) {
|
|
33
|
+
return { content: [{ type: "text" as const, text: `오류: ${error instanceof Error ? error.message : String(error)}` }], isError: true };
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
server.tool(
|
|
39
|
+
"create_task",
|
|
40
|
+
"새 태스크를 생성합니다",
|
|
41
|
+
{ projectRoot: z.string().optional(), title: z.string(), description: z.string().optional(), priority: z.number().optional(), status: z.string().optional(), parentId: z.string().optional(), dependencies: z.array(z.string()).optional(), group: z.string().optional() },
|
|
42
|
+
async ({ projectRoot, title, description, priority, status, parentId, dependencies, group }) => {
|
|
43
|
+
try {
|
|
44
|
+
const root = resolveProjectRoot(projectRoot);
|
|
45
|
+
const task = await createTask(root, { title, description, priority, status: status as any, parentId, dependencies, group });
|
|
46
|
+
return { content: [{ type: "text" as const, text: JSON.stringify(task, null, 2) }] };
|
|
47
|
+
} catch (error) {
|
|
48
|
+
return { content: [{ type: "text" as const, text: `오류: ${error instanceof Error ? error.message : String(error)}` }], isError: true };
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
server.tool(
|
|
54
|
+
"update_task",
|
|
55
|
+
"태스크를 수정합니다",
|
|
56
|
+
{ projectRoot: z.string().optional(), taskId: z.string(), title: z.string().optional(), description: z.string().optional(), priority: z.number().optional(), status: z.string().optional(), dependencies: z.array(z.string()).optional() },
|
|
57
|
+
async ({ projectRoot, taskId, ...patch }) => {
|
|
58
|
+
try {
|
|
59
|
+
const root = resolveProjectRoot(projectRoot);
|
|
60
|
+
const task = await updateTask(root, taskId, patch as any);
|
|
61
|
+
return { content: [{ type: "text" as const, text: JSON.stringify(task, null, 2) }] };
|
|
62
|
+
} catch (error) {
|
|
63
|
+
return { content: [{ type: "text" as const, text: `오류: ${error instanceof Error ? error.message : String(error)}` }], isError: true };
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
);
|
|
67
|
+
|
|
68
|
+
server.tool(
|
|
69
|
+
"delete_task",
|
|
70
|
+
"태스크를 삭제합니다",
|
|
71
|
+
{ projectRoot: z.string().optional(), taskId: z.string() },
|
|
72
|
+
async ({ projectRoot, taskId }) => {
|
|
73
|
+
try {
|
|
74
|
+
const root = resolveProjectRoot(projectRoot);
|
|
75
|
+
const removed = await deleteTask(root, taskId);
|
|
76
|
+
return { content: [{ type: "text" as const, text: removed ? `태스크 ${taskId} 삭제 완료` : `태스크를 찾을 수 없습니다: ${taskId}` }], isError: !removed };
|
|
77
|
+
} catch (error) {
|
|
78
|
+
return { content: [{ type: "text" as const, text: `오류: ${error instanceof Error ? error.message : String(error)}` }], isError: true };
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
);
|
|
82
|
+
}
|