roadmap-skill 0.2.5 → 0.2.7

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/dist/index.js CHANGED
@@ -1322,8 +1322,39 @@ init_esm_shims();
1322
1322
  import express from "express";
1323
1323
  import * as path4 from "path";
1324
1324
  import { fileURLToPath as fileURLToPath2 } from "url";
1325
+ import { createRequire } from "module";
1326
+ import { existsSync } from "fs";
1325
1327
  var __filename2 = fileURLToPath2(import.meta.url);
1326
1328
  var __dirname2 = path4.dirname(__filename2);
1329
+ function resolveAppPath() {
1330
+ const candidates = [];
1331
+ try {
1332
+ const require2 = createRequire(import.meta.url);
1333
+ const pkgRoot = path4.dirname(require2.resolve("../../package.json"));
1334
+ candidates.push({ path: path4.join(pkgRoot, "dist/web/app"), source: "package.json resolve" });
1335
+ } catch {
1336
+ }
1337
+ candidates.push({ path: path4.join(__dirname2, "web/app"), source: "__dirname/web/app" });
1338
+ candidates.push({ path: path4.join(__dirname2, "app"), source: "__dirname relative" });
1339
+ candidates.push({ path: path4.join(process.cwd(), "dist/web/app"), source: "process.cwd()" });
1340
+ candidates.push({ path: path4.join(__dirname2, "../web/app"), source: "__dirname/../web/app" });
1341
+ for (const { path: candidatePath, source } of candidates) {
1342
+ const indexPath = path4.join(candidatePath, "index.html");
1343
+ if (existsSync(indexPath)) {
1344
+ console.log(`[roadmap-skill] Static files found at: ${candidatePath} (via ${source})`);
1345
+ return candidatePath;
1346
+ }
1347
+ }
1348
+ const triedPaths = candidates.map((c) => ` - ${c.path} (${c.source})`).join("\n");
1349
+ throw new Error(
1350
+ `Cannot find web app static files.
1351
+
1352
+ Tried:
1353
+ ${triedPaths}
1354
+
1355
+ Ensure the package is installed correctly and web assets exist.`
1356
+ );
1357
+ }
1327
1358
  var tagService2 = new TagService(storage);
1328
1359
  function createServer(port = 7860) {
1329
1360
  return new Promise((resolve, reject) => {
@@ -1507,7 +1538,7 @@ function createServer(port = 7860) {
1507
1538
  });
1508
1539
  }
1509
1540
  });
1510
- const distPath = path4.join(__dirname2, "app");
1541
+ const distPath = resolveAppPath();
1511
1542
  app.use(express.static(distPath));
1512
1543
  app.get("*", (req, res) => {
1513
1544
  if (req.path.startsWith("/api")) {
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../node_modules/tsup/assets/esm_shims.js","../src/utils/file-helpers.ts","../src/index.ts","../src/server.ts","../src/tools/index.ts","../src/tools/project-tools.ts","../src/storage/index.ts","../src/utils/path-helpers.ts","../src/tools/task-tools.ts","../src/services/index.ts","../src/services/tag-service.ts","../src/services/task-service.ts","../src/services/types.ts","../src/tools/tag-tools.ts","../src/tools/web-tools.ts","../src/web/server.ts","../src/tools/template-tools.ts","../src/resources/index.ts","../src/resources/project-resources.ts","../src/prompts/index.ts","../src/prompts/project-prompts.ts"],"sourcesContent":["// Shim globals in esm bundle\nimport path from 'node:path'\nimport { fileURLToPath } from 'node:url'\n\nconst getFilename = () => fileURLToPath(import.meta.url)\nconst getDirname = () => path.dirname(getFilename())\n\nexport const __dirname = /* @__PURE__ */ getDirname()\nexport const __filename = /* @__PURE__ */ getFilename()\n","import * as fs from 'fs/promises';\n\n/**\n * Read and parse a JSON file\n * @param filePath - Path to the JSON file\n * @returns Parsed JSON data\n * @throws Error if file cannot be read or parsed\n */\nexport async function readJsonFile<T>(filePath: string): Promise<T> {\n try {\n const content = await fs.readFile(filePath, 'utf-8');\n return JSON.parse(content) as T;\n } catch (error) {\n if (error instanceof Error) {\n throw new Error(`Failed to read JSON file ${filePath}: ${error.message}`);\n }\n throw error;\n }\n}\n\n/**\n * Write data to a JSON file\n * @param filePath - Path to the JSON file\n * @param data - Data to serialize and write\n * @throws Error if file cannot be written\n */\nexport async function writeJsonFile<T>(filePath: string, data: T): Promise<void> {\n try {\n const content = JSON.stringify(data, null, 2);\n await fs.writeFile(filePath, content, 'utf-8');\n } catch (error) {\n if (error instanceof Error) {\n throw new Error(`Failed to write JSON file ${filePath}: ${error.message}`);\n }\n throw error;\n }\n}\n\n/**\n * Ensure a directory exists, creating it recursively if needed\n * @param dirPath - Path to the directory\n * @throws Error if directory cannot be created\n */\nexport async function ensureDir(dirPath: string): Promise<void> {\n try {\n await fs.mkdir(dirPath, { recursive: true });\n } catch (error) {\n if (error instanceof Error) {\n throw new Error(`Failed to create directory ${dirPath}: ${error.message}`);\n }\n throw error;\n }\n}\n","import { startServer } from './server.js';\n\nasync function main() {\n process.on('SIGINT', () => {\n console.error('Received SIGINT, shutting down gracefully...');\n process.exit(0);\n });\n\n process.on('SIGTERM', () => {\n console.error('Received SIGTERM, shutting down gracefully...');\n process.exit(0);\n });\n\n process.on('uncaughtException', (error) => {\n console.error('Uncaught exception:', error);\n process.exit(1);\n });\n\n process.on('unhandledRejection', (reason) => {\n console.error('Unhandled rejection:', reason);\n process.exit(1);\n });\n\n try {\n await startServer();\n } catch (error) {\n console.error('Failed to start server:', error);\n process.exit(1);\n }\n}\n\nmain();\n","import { Server } from \"@modelcontextprotocol/sdk/server/index.js\";\nimport {\n\tCallToolRequestSchema,\n\tListToolsRequestSchema,\n\tListResourcesRequestSchema,\n\tReadResourceRequestSchema,\n\tListPromptsRequestSchema,\n\tGetPromptRequestSchema,\n\ttype CallToolRequest,\n\ttype ListToolsRequest,\n\ttype ListResourcesRequest,\n\ttype ReadResourceRequest,\n\ttype ListPromptsRequest,\n\ttype GetPromptRequest,\n} from \"@modelcontextprotocol/sdk/types.js\";\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport { zodToJsonSchema } from \"zod-to-json-schema\";\n\nimport {\n\tcreateProjectTool,\n\tlistProjectsTool,\n\tgetProjectTool,\n\tupdateProjectTool,\n\tdeleteProjectTool,\n\tcreateTaskTool,\n\tlistTasksTool,\n\tgetTaskTool,\n\tupdateTaskTool,\n\tdeleteTaskTool,\n\tbatchUpdateTasksTool,\n\tcreateTagTool,\n\tlistTagsTool,\n\tupdateTagTool,\n\tdeleteTagTool,\n\tgetTasksByTagTool,\n\topenWebInterfaceTool,\n\tcloseWebInterfaceTool,\n} from \"./tools/index.js\";\nimport { getAllResources, handleResourceRequest } from \"./resources/index.js\";\nimport { getAllPrompts, getPromptByName } from \"./prompts/index.js\";\n\nconst allTools = [\n\tcreateProjectTool,\n\tlistProjectsTool,\n\tgetProjectTool,\n\tupdateProjectTool,\n\tdeleteProjectTool,\n\tcreateTaskTool,\n\tlistTasksTool,\n\tgetTaskTool,\n\tupdateTaskTool,\n\tdeleteTaskTool,\n\tbatchUpdateTasksTool,\n\tcreateTagTool,\n\tlistTagsTool,\n\tupdateTagTool,\n\tdeleteTagTool,\n\tgetTasksByTagTool,\n\topenWebInterfaceTool,\n\tcloseWebInterfaceTool,\n];\n\nconst toolMap = new Map(allTools.map((tool) => [tool.name, tool]));\n\nexport function createServer(): Server {\n\tconst server = new Server(\n\t\t{\n\t\t\tname: \"roadmap-skill\",\n\t\t\tversion: \"0.2.1\",\n\t\t},\n\t\t{\n\t\t\tcapabilities: {\n\t\t\t\ttools: {},\n\t\t\t\tresources: {},\n\t\t\t\tprompts: {},\n\t\t\t},\n\t\t},\n\t);\n\n\tserver.setRequestHandler(\n\t\tListToolsRequestSchema,\n\t\tasync (_request: ListToolsRequest) => {\n\t\t\treturn {\n\t\t\t\ttools: allTools.map((tool) => {\n\t\t\t\t\tconst rawSchema =\n\t\t\t\t\t\t(tool as any).parameters || (tool as any).inputSchema;\n\t\t\t\t\tlet inputSchema: Record<string, unknown>;\n\n\t\t\t\t\tif (!rawSchema) {\n\t\t\t\t\t\tinputSchema = { type: \"object\" };\n\t\t\t\t\t} else if (rawSchema.type === \"object\") {\n\t\t\t\t\t\tinputSchema = rawSchema;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tinputSchema = zodToJsonSchema(rawSchema, {\n\t\t\t\t\t\t\tname: tool.name,\n\t\t\t\t\t\t\t$refStrategy: \"none\",\n\t\t\t\t\t\t}).definitions?.[tool.name] || { type: \"object\" };\n\t\t\t\t\t}\n\n\t\t\t\t\treturn {\n\t\t\t\t\t\tname: tool.name,\n\t\t\t\t\t\tdescription: tool.description,\n\t\t\t\t\t\tinputSchema,\n\t\t\t\t\t};\n\t\t\t\t}),\n\t\t\t};\n\t\t},\n\t);\n\n\tserver.setRequestHandler(\n\t\tCallToolRequestSchema,\n\t\tasync (request: CallToolRequest) => {\n\t\t\tconst { name, arguments: args } = request.params;\n\t\t\tconst tool = toolMap.get(name);\n\n\t\t\tif (!tool) {\n\t\t\t\tthrow new Error(`Unknown tool: ${name}`);\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tconst result = await tool.execute(args as never);\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\t\ttext: JSON.stringify(result, null, 2),\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t};\n\t\t\t} catch (error) {\n\t\t\t\tconst errorMessage =\n\t\t\t\t\terror instanceof Error ? error.message : String(error);\n\t\t\t\tthrow new Error(`Tool execution failed: ${errorMessage}`);\n\t\t\t}\n\t\t},\n\t);\n\n\tserver.setRequestHandler(\n\t\tListResourcesRequestSchema,\n\t\tasync (_request: ListResourcesRequest) => {\n\t\t\tconst resources = getAllResources();\n\t\t\treturn { resources };\n\t\t},\n\t);\n\n\tserver.setRequestHandler(\n\t\tReadResourceRequestSchema,\n\t\tasync (request: ReadResourceRequest) => {\n\t\t\tconst uri = request.params.uri;\n\t\t\tconst resourceContent = await handleResourceRequest(uri);\n\n\t\t\tif (!resourceContent) {\n\t\t\t\tthrow new Error(`Resource not found: ${uri}`);\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\tcontents: [resourceContent],\n\t\t\t};\n\t\t},\n\t);\n\n\tserver.setRequestHandler(\n\t\tListPromptsRequestSchema,\n\t\tasync (_request: ListPromptsRequest) => {\n\t\t\tconst prompts = getAllPrompts();\n\t\t\treturn { prompts };\n\t\t},\n\t);\n\n\tserver.setRequestHandler(\n\t\tGetPromptRequestSchema,\n\t\tasync (request: GetPromptRequest) => {\n\t\t\tconst { name, arguments: args } = request.params;\n\t\t\tconst promptResult = getPromptByName(\n\t\t\t\tname,\n\t\t\t\targs as Record<string, string> | undefined,\n\t\t\t);\n\n\t\t\tif (!promptResult) {\n\t\t\t\tthrow new Error(`Prompt not found: ${name}`);\n\t\t\t}\n\n\t\t\treturn promptResult;\n\t\t},\n\t);\n\n\treturn server;\n}\n\nexport async function startServer(): Promise<void> {\n\tconst server = createServer();\n\tconst transport = new StdioServerTransport();\n\n\tconsole.error(\"Roadmap Skill MCP Server starting...\");\n\n\ttry {\n\t\tawait server.connect(transport);\n\t\tconsole.error(\"Roadmap Skill MCP Server connected and ready\");\n\t} catch (error) {\n\t\tconsole.error(\"Failed to start server:\", error);\n\t\tthrow error;\n\t}\n}\n","export {\n createProjectTool,\n listProjectsTool,\n getProjectTool,\n updateProjectTool,\n deleteProjectTool,\n} from './project-tools.js';\n\nexport {\n createTaskTool,\n listTasksTool,\n getTaskTool,\n updateTaskTool,\n deleteTaskTool,\n batchUpdateTasksTool,\n} from './task-tools.js';\n\nexport {\n createTagTool,\n listTagsTool,\n updateTagTool,\n deleteTagTool,\n getTasksByTagTool,\n} from './tag-tools.js';\n\nexport {\n openWebInterfaceTool,\n closeWebInterfaceTool,\n} from './web-tools.js';\n\nexport {\n listTemplatesTool,\n getTemplateTool,\n applyTemplateTool,\n} from './template-tools.js';\n","import { z } from 'zod';\nimport { storage } from '../storage/index.js';\nimport type { CreateProjectInput, UpdateProjectInput } from '../models/index.js';\n\nconst ProjectTypeEnum = z.enum(['roadmap', 'skill-tree', 'kanban']);\nconst ProjectStatusEnum = z.enum(['active', 'completed', 'archived']);\n\nexport const createProjectTool = {\n name: 'create_project',\n description: 'Create a new project roadmap',\n inputSchema: z.object({\n name: z.string().min(1, 'Project name is required'),\n description: z.string(),\n projectType: ProjectTypeEnum,\n startDate: z.string().regex(/^\\d{4}-\\d{2}-\\d{2}$/, 'Date must be in YYYY-MM-DD format'),\n targetDate: z.string().regex(/^\\d{4}-\\d{2}-\\d{2}$/, 'Date must be in YYYY-MM-DD format'),\n }),\n async execute(input: {\n name: string;\n description: string;\n projectType: 'roadmap' | 'skill-tree' | 'kanban';\n startDate: string;\n targetDate: string;\n }) {\n try {\n const projectInput: CreateProjectInput = {\n name: input.name,\n description: input.description,\n projectType: input.projectType,\n startDate: input.startDate,\n targetDate: input.targetDate,\n };\n\n const projectData = await storage.createProject(projectInput);\n return {\n success: true,\n data: projectData,\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Failed to create project',\n };\n }\n },\n};\n\nexport const listProjectsTool = {\n name: 'list_projects',\n description: 'List all projects with their task and milestone counts',\n inputSchema: z.object({}),\n async execute() {\n try {\n const projects = await storage.listProjects();\n return {\n success: true,\n data: projects,\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Failed to list projects',\n };\n }\n },\n};\n\nexport const getProjectTool = {\n name: 'get_project',\n description: 'Get a project by ID with all its data (tasks, tags, milestones)',\n inputSchema: z.object({\n projectId: z.string().min(1, 'Project ID is required'),\n }),\n async execute(input: { projectId: string }) {\n try {\n const projectData = await storage.readProject(input.projectId);\n if (!projectData) {\n return {\n success: false,\n error: `Project with ID '${input.projectId}' not found`,\n };\n }\n return {\n success: true,\n data: projectData,\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Failed to get project',\n };\n }\n },\n};\n\nexport const updateProjectTool = {\n name: 'update_project',\n description: 'Update an existing project',\n inputSchema: z.object({\n projectId: z.string().min(1, 'Project ID is required'),\n name: z.string().min(1).optional(),\n description: z.string().optional(),\n projectType: ProjectTypeEnum.optional(),\n status: ProjectStatusEnum.optional(),\n startDate: z.string().regex(/^\\d{4}-\\d{2}-\\d{2}$/).optional(),\n targetDate: z.string().regex(/^\\d{4}-\\d{2}-\\d{2}$/).optional(),\n }),\n async execute(input: {\n projectId: string;\n name?: string;\n description?: string;\n projectType?: 'roadmap' | 'skill-tree' | 'kanban';\n status?: 'active' | 'completed' | 'archived';\n startDate?: string;\n targetDate?: string;\n }) {\n try {\n const { projectId, ...updateData } = input;\n\n if (Object.keys(updateData).length === 0) {\n return {\n success: false,\n error: 'At least one field to update is required',\n };\n }\n\n const updateInput: UpdateProjectInput = updateData;\n const projectData = await storage.updateProject(projectId, updateInput);\n\n if (!projectData) {\n return {\n success: false,\n error: `Project with ID '${projectId}' not found`,\n };\n }\n\n return {\n success: true,\n data: projectData,\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Failed to update project',\n };\n }\n },\n};\n\nexport const deleteProjectTool = {\n name: 'delete_project',\n description: 'Delete a project by ID',\n inputSchema: z.object({\n projectId: z.string().min(1, 'Project ID is required'),\n }),\n async execute(input: { projectId: string }) {\n try {\n const deleted = await storage.deleteProject(input.projectId);\n\n if (!deleted) {\n return {\n success: false,\n error: `Project with ID '${input.projectId}' not found`,\n };\n }\n\n return {\n success: true,\n data: { deleted: true },\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Failed to delete project',\n };\n }\n },\n};\n","import * as path from 'path';\nimport type {\n Project,\n ProjectData,\n Task,\n TaskSearchFilters,\n CreateProjectInput,\n UpdateProjectInput,\n} from '../models/index.js';\nimport { getStorageDir } from '../utils/path-helpers.js';\nimport { readJsonFile, writeJsonFile, ensureDir } from '../utils/file-helpers.js';\n\n/**\n * Storage class for managing roadmap-skill projects\n * Projects are stored as individual JSON files in ~/.roadmap-skill/projects/\n */\nexport class ProjectStorage {\n private storageDir: string;\n\n constructor() {\n this.storageDir = getStorageDir();\n }\n\n /**\n * Ensure the storage directory exists\n */\n async ensureDirectory(): Promise<void> {\n await ensureDir(this.storageDir);\n }\n\n /**\n * Get the file path for a project\n * @param projectId - The project ID\n * @returns Full path to the project JSON file\n */\n getFilePath(projectId: string): string {\n return path.join(this.storageDir, `${projectId}.json`);\n }\n\n /**\n * Create a new project\n * @param input - Project creation data\n * @returns The created project data\n */\n async createProject(input: CreateProjectInput): Promise<ProjectData> {\n await this.ensureDirectory();\n\n const now = new Date().toISOString();\n const projectId = `proj_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;\n\n const project: Project = {\n id: projectId,\n name: input.name,\n description: input.description,\n projectType: input.projectType,\n status: 'active',\n startDate: input.startDate,\n targetDate: input.targetDate,\n createdAt: now,\n updatedAt: now,\n };\n\n const projectData: ProjectData = {\n version: 1,\n project,\n milestones: [],\n tasks: [],\n tags: [],\n };\n\n const filePath = this.getFilePath(projectId);\n await writeJsonFile(filePath, projectData);\n\n return projectData;\n }\n\n /**\n * Read a project by ID\n * @param projectId - The project ID\n * @returns The project data or null if not found\n */\n async readProject(projectId: string): Promise<ProjectData | null> {\n try {\n const filePath = this.getFilePath(projectId);\n return await readJsonFile<ProjectData>(filePath);\n } catch (error) {\n if (error instanceof Error && error.message.includes('ENOENT')) {\n return null;\n }\n throw error;\n }\n }\n\n /**\n * Update an existing project\n * @param projectId - The project ID\n * @param input - Project update data\n * @returns The updated project data or null if not found\n */\n async updateProject(\n projectId: string,\n input: UpdateProjectInput\n ): Promise<ProjectData | null> {\n const projectData = await this.readProject(projectId);\n if (!projectData) {\n return null;\n }\n\n const now = new Date().toISOString();\n\n projectData.project = {\n ...projectData.project,\n ...input,\n updatedAt: now,\n };\n\n const filePath = this.getFilePath(projectId);\n await writeJsonFile(filePath, projectData);\n\n return projectData;\n }\n\n /**\n * Delete a project by ID\n * @param projectId - The project ID\n * @returns True if deleted, false if not found\n */\n async deleteProject(projectId: string): Promise<boolean> {\n try {\n const filePath = this.getFilePath(projectId);\n const fs = await import('fs/promises');\n await fs.unlink(filePath);\n return true;\n } catch (error) {\n if (error instanceof Error && error.message.includes('ENOENT')) {\n return false;\n }\n throw error;\n }\n }\n\n /**\n * List all projects sorted by updatedAt (descending)\n * @returns Array of project summaries (project + metadata)\n */\n async listProjects(): Promise<Array<{ project: Project; taskCount: number; milestoneCount: number }>> {\n await this.ensureDirectory();\n\n const fs = await import('fs/promises');\n const files = await fs.readdir(this.storageDir);\n const jsonFiles = files.filter((f) => f.endsWith('.json'));\n\n const projects: Array<{ project: Project; taskCount: number; milestoneCount: number }> = [];\n\n for (const file of jsonFiles) {\n try {\n const filePath = path.join(this.storageDir, file);\n const data = await readJsonFile<ProjectData>(filePath);\n projects.push({\n project: data.project,\n taskCount: data.tasks.length,\n milestoneCount: data.milestones.length,\n });\n } catch {\n // Skip invalid files\n continue;\n }\n }\n\n // Sort by updatedAt descending\n return projects.sort(\n (a, b) => new Date(b.project.updatedAt).getTime() - new Date(a.project.updatedAt).getTime()\n );\n }\n\n /**\n * Search tasks across all projects with filters\n * @param filters - Search filters\n * @returns Array of matching tasks with project context\n */\n async searchTasks(\n filters: TaskSearchFilters\n ): Promise<Array<{ task: Task; project: Project }>> {\n await this.ensureDirectory();\n\n const fs = await import('fs/promises');\n const files = await fs.readdir(this.storageDir);\n const jsonFiles = files.filter((f) => f.endsWith('.json'));\n\n const results: Array<{ task: Task; project: Project }> = [];\n\n for (const file of jsonFiles) {\n try {\n const filePath = path.join(this.storageDir, file);\n const data = await readJsonFile<ProjectData>(filePath);\n\n // Skip if project filter doesn't match\n if (filters.projectId && data.project.id !== filters.projectId) {\n continue;\n }\n\n for (const task of data.tasks) {\n // Apply filters\n if (filters.status && task.status !== filters.status) {\n continue;\n }\n if (filters.priority && task.priority !== filters.priority) {\n continue;\n }\n if (filters.assignee && task.assignee !== filters.assignee) {\n continue;\n }\n if (filters.dueBefore && task.dueDate && task.dueDate > filters.dueBefore) {\n continue;\n }\n if (filters.dueAfter && task.dueDate && task.dueDate < filters.dueAfter) {\n continue;\n }\n if (\n filters.tags &&\n filters.tags.length > 0 &&\n !filters.tags.some((tag) => task.tags.includes(tag))\n ) {\n continue;\n }\n if (\n filters.searchText &&\n !task.title.toLowerCase().includes(filters.searchText.toLowerCase()) &&\n !task.description.toLowerCase().includes(filters.searchText.toLowerCase())\n ) {\n continue;\n }\n\n // Filter completed tasks (done status) when includeCompleted is false\n if (filters.includeCompleted === false && task.status === 'done') {\n continue;\n }\n\n results.push({ task, project: data.project });\n }\n } catch {\n // Skip invalid files\n continue;\n }\n }\n\n return results;\n }\n\n async exportAllData(): Promise<{\n version: number;\n exportedAt: string;\n projects: ProjectData[];\n }> {\n await this.ensureDirectory();\n\n const fs = await import('fs/promises');\n const files = await fs.readdir(this.storageDir);\n const jsonFiles = files.filter((f) => f.endsWith('.json'));\n\n const projects: ProjectData[] = [];\n\n for (const file of jsonFiles) {\n try {\n const filePath = path.join(this.storageDir, file);\n const data = await readJsonFile<ProjectData>(filePath);\n projects.push(data);\n } catch {\n continue;\n }\n }\n\n return {\n version: 1,\n exportedAt: new Date().toISOString(),\n projects,\n };\n }\n\n async importAllData(data: {\n version: number;\n exportedAt: string;\n projects: ProjectData[];\n }): Promise<{\n success: boolean;\n imported: number;\n errors: number;\n errorDetails: string[];\n }> {\n await this.ensureDirectory();\n\n let imported = 0;\n let errors = 0;\n const errorDetails: string[] = [];\n\n if (!data.projects || !Array.isArray(data.projects)) {\n throw new Error('Invalid backup data: projects array is required');\n }\n\n for (const projectData of data.projects) {\n try {\n if (!projectData.project || !projectData.project.id) {\n errors++;\n errorDetails.push('Skipping invalid project: missing project or id');\n continue;\n }\n\n const filePath = this.getFilePath(projectData.project.id);\n await writeJsonFile(filePath, projectData);\n imported++;\n } catch (error) {\n errors++;\n const errorMessage = error instanceof Error ? error.message : String(error);\n errorDetails.push(`Failed to import project ${projectData.project?.id || 'unknown'}: ${errorMessage}`);\n }\n }\n\n return {\n success: errors === 0,\n imported,\n errors,\n errorDetails,\n };\n }\n}\n\nexport const storage = new ProjectStorage();\n","import * as os from 'os';\nimport * as path from 'path';\n\n/**\n * Get the storage directory for roadmap-skill projects\n * Returns: ~/.roadmap-skill/projects\n */\nexport function getStorageDir(): string {\n const homeDir = os.homedir();\n return path.join(homeDir, '.roadmap-skill', 'projects');\n}\n","import { z } from 'zod';\nimport { TaskService } from '../services/index.js';\nimport { storage } from '../storage/index.js';\n\nconst TaskStatusEnum = z.enum(['todo', 'in-progress', 'review', 'done']);\nconst TaskPriorityEnum = z.enum(['low', 'medium', 'high', 'critical']);\n\nexport const createTaskTool = {\n name: 'create_task',\n description: 'Create a new task in a project',\n inputSchema: z.object({\n projectId: z.string().min(1, 'Project ID is required'),\n title: z.string().min(1, 'Task title is required'),\n description: z.string(),\n priority: TaskPriorityEnum.default('medium'),\n tags: z.array(z.string()).default([]),\n dueDate: z.string().regex(/^\\d{4}-\\d{2}-\\d{2}$/).optional(),\n assignee: z.string().optional(),\n }),\n async execute(input: {\n projectId: string;\n title: string;\n description: string;\n priority: 'low' | 'medium' | 'high' | 'critical';\n tags: string[];\n dueDate?: string;\n assignee?: string;\n }) {\n const result = await TaskService.create(input.projectId, {\n title: input.title,\n description: input.description,\n priority: input.priority,\n tags: input.tags,\n dueDate: input.dueDate,\n assignee: input.assignee,\n });\n\n return result;\n },\n};\n\nexport const listTasksTool = {\n name: 'list_tasks',\n description: 'List tasks with optional filters',\n inputSchema: z.object({\n projectId: z.string().optional(),\n status: TaskStatusEnum.optional(),\n priority: TaskPriorityEnum.optional(),\n tags: z.array(z.string()).optional(),\n assignee: z.string().optional(),\n dueBefore: z.string().regex(/^\\d{4}-\\d{2}-\\d{2}$/).optional(),\n dueAfter: z.string().regex(/^\\d{4}-\\d{2}-\\d{2}$/).optional(),\n includeCompleted: z.boolean().optional(),\n }),\n async execute(input: {\n projectId?: string;\n status?: 'todo' | 'in-progress' | 'review' | 'done';\n priority?: 'low' | 'medium' | 'high' | 'critical';\n tags?: string[];\n assignee?: string;\n dueBefore?: string;\n dueAfter?: string;\n includeCompleted?: boolean;\n }) {\n try {\n const results = await storage.searchTasks({\n projectId: input.projectId,\n status: input.status,\n priority: input.priority,\n tags: input.tags,\n assignee: input.assignee,\n dueBefore: input.dueBefore,\n dueAfter: input.dueAfter,\n includeCompleted: input.includeCompleted,\n });\n\n return {\n success: true,\n data: results,\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Failed to list tasks',\n };\n }\n },\n};\n\nexport const getTaskTool = {\n name: 'get_task',\n description: 'Get a specific task by project ID and task ID',\n inputSchema: z.object({\n projectId: z.string().min(1, 'Project ID is required'),\n taskId: z.string().min(1, 'Task ID is required'),\n }),\n async execute(input: { projectId: string; taskId: string }) {\n const result = await TaskService.get(input.projectId, input.taskId);\n return result;\n },\n};\n\nexport const updateTaskTool = {\n name: 'update_task',\n description: 'Update an existing task',\n inputSchema: z.object({\n projectId: z.string().min(1, 'Project ID is required'),\n taskId: z.string().min(1, 'Task ID is required'),\n title: z.string().min(1).optional(),\n description: z.string().optional(),\n status: TaskStatusEnum.optional(),\n priority: TaskPriorityEnum.optional(),\n tags: z.array(z.string()).optional(),\n dueDate: z.string().regex(/^\\d{4}-\\d{2}-\\d{2}$/).optional().nullable(),\n assignee: z.string().optional().nullable(),\n }),\n async execute(input: {\n projectId: string;\n taskId: string;\n title?: string;\n description?: string;\n status?: 'todo' | 'in-progress' | 'review' | 'done';\n priority?: 'low' | 'medium' | 'high' | 'critical';\n tags?: string[];\n dueDate?: string | null;\n assignee?: string | null;\n }) {\n const { projectId, taskId, ...updateData } = input;\n\n const result = await TaskService.update(projectId, taskId, updateData);\n return result;\n },\n};\n\nexport const deleteTaskTool = {\n name: 'delete_task',\n description: 'Delete a task by project ID and task ID',\n inputSchema: z.object({\n projectId: z.string().min(1, 'Project ID is required'),\n taskId: z.string().min(1, 'Task ID is required'),\n }),\n async execute(input: { projectId: string; taskId: string }) {\n const result = await TaskService.delete(input.projectId, input.taskId);\n\n // 保持向后兼容:将 data: undefined 转换为 { deleted: true }\n if (result.success) {\n return {\n success: true,\n data: { deleted: true },\n };\n }\n\n return result;\n },\n};\n\nexport const batchUpdateTasksTool = {\n name: 'batch_update_tasks',\n description: 'Update multiple tasks at once',\n inputSchema: z.object({\n projectId: z.string().min(1, 'Project ID is required'),\n taskIds: z.array(z.string()).min(1, 'At least one task ID is required'),\n status: TaskStatusEnum.optional(),\n priority: TaskPriorityEnum.optional(),\n tags: z.array(z.string()).optional(),\n tagOperation: z.enum(['add', 'remove', 'replace']).default('replace'),\n }),\n async execute(input: {\n projectId: string;\n taskIds: string[];\n status?: 'todo' | 'in-progress' | 'review' | 'done';\n priority?: 'low' | 'medium' | 'high' | 'critical';\n tags?: string[];\n tagOperation?: 'add' | 'remove' | 'replace';\n }) {\n const { projectId, taskIds, tagOperation, ...restData } = input;\n\n const result = await TaskService.batchUpdate(projectId, taskIds, {\n ...restData,\n tagOperation,\n });\n\n return result;\n },\n};\n","export { TagService } from './tag-service.js';\nexport { TaskService } from './task-service.js';\nexport * from './types.js';\n","/**\n * Tag Service - Unified business logic for tag management\n * Extracted from tag-tools.ts for better separation of concerns\n */\n\nimport type { ProjectStorage } from '../storage/index.js';\nimport type { Tag, ProjectData } from '../models/index.js';\nimport type {\n ServiceResult,\n CreateTagData,\n UpdateTagData,\n DeleteTagResult,\n TasksByTagResult,\n} from './types.js';\n\n/**\n * Generate a unique tag ID\n * @returns Tag ID in format tag_${timestamp}_${random}\n */\nfunction generateTagId(): string {\n return `tag_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;\n}\n\n/**\n * TagService - Handles all tag-related business logic\n */\nexport class TagService {\n private storage: ProjectStorage;\n\n constructor(storage: ProjectStorage) {\n this.storage = storage;\n }\n\n /**\n * Create a new tag in a project\n * @param projectId - The project ID\n * @param data - Tag creation data\n * @returns The created tag or error\n */\n async create(projectId: string, data: CreateTagData): Promise<ServiceResult<Tag>> {\n try {\n const projectData = await this.storage.readProject(projectId);\n if (!projectData) {\n return {\n success: false,\n error: `Project with ID '${projectId}' not found`,\n code: 'NOT_FOUND',\n };\n }\n\n // Check for duplicate tag name (case-insensitive)\n const existingTag = projectData.tags.find(\n (t) => t.name.toLowerCase() === data.name.toLowerCase()\n );\n if (existingTag) {\n return {\n success: false,\n error: `Tag with name '${data.name}' already exists in this project`,\n code: 'DUPLICATE_ERROR',\n };\n }\n\n const now = new Date().toISOString();\n const tag: Tag = {\n id: generateTagId(),\n name: data.name,\n color: data.color,\n description: data.description || '',\n createdAt: now,\n };\n\n projectData.tags.push(tag);\n projectData.project.updatedAt = now;\n\n await this.saveProjectData(projectId, projectData);\n\n return {\n success: true,\n data: tag,\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Failed to create tag',\n code: 'INTERNAL_ERROR',\n };\n }\n }\n\n /**\n * List all tags in a project\n * @param projectId - The project ID\n * @returns Array of tags or error\n */\n async list(projectId: string): Promise<ServiceResult<Tag[]>> {\n try {\n const projectData = await this.storage.readProject(projectId);\n if (!projectData) {\n return {\n success: false,\n error: `Project with ID '${projectId}' not found`,\n code: 'NOT_FOUND',\n };\n }\n\n return {\n success: true,\n data: projectData.tags,\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Failed to list tags',\n code: 'INTERNAL_ERROR',\n };\n }\n }\n\n /**\n * Update an existing tag\n * @param projectId - The project ID\n * @param tagId - The tag ID\n * @param data - Tag update data\n * @returns The updated tag or error\n */\n async update(\n projectId: string,\n tagId: string,\n data: UpdateTagData\n ): Promise<ServiceResult<Tag>> {\n try {\n const projectData = await this.storage.readProject(projectId);\n if (!projectData) {\n return {\n success: false,\n error: `Project with ID '${projectId}' not found`,\n code: 'NOT_FOUND',\n };\n }\n\n const tagIndex = projectData.tags.findIndex((t) => t.id === tagId);\n if (tagIndex === -1) {\n return {\n success: false,\n error: `Tag with ID '${tagId}' not found in project '${projectId}'`,\n code: 'NOT_FOUND',\n };\n }\n\n // Check if there is any field to update\n if (Object.keys(data).length === 0) {\n return {\n success: false,\n error: 'At least one field to update is required',\n code: 'VALIDATION_ERROR',\n };\n }\n\n // Check for duplicate name if updating name (case-insensitive)\n if (data.name) {\n const existingTag = projectData.tags.find(\n (t) =>\n t.name.toLowerCase() === data.name!.toLowerCase() && t.id !== tagId\n );\n if (existingTag) {\n return {\n success: false,\n error: `Tag with name '${data.name}' already exists in this project`,\n code: 'DUPLICATE_ERROR',\n };\n }\n }\n\n const now = new Date().toISOString();\n const existingTag = projectData.tags[tagIndex];\n\n const updatedTag: Tag = {\n ...existingTag,\n ...data,\n id: existingTag.id,\n createdAt: existingTag.createdAt,\n };\n\n projectData.tags[tagIndex] = updatedTag;\n projectData.project.updatedAt = now;\n\n await this.saveProjectData(projectId, projectData);\n\n return {\n success: true,\n data: updatedTag,\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Failed to update tag',\n code: 'INTERNAL_ERROR',\n };\n }\n }\n\n /**\n * Delete a tag by ID\n * Also removes the tag from all tasks that use it\n * @param projectId - The project ID\n * @param tagId - The tag ID\n * @returns Delete result with tag info and count of updated tasks\n */\n async delete(projectId: string, tagId: string): Promise<ServiceResult<DeleteTagResult>> {\n try {\n const projectData = await this.storage.readProject(projectId);\n if (!projectData) {\n return {\n success: false,\n error: `Project with ID '${projectId}' not found`,\n code: 'NOT_FOUND',\n };\n }\n\n const tagIndex = projectData.tags.findIndex((t) => t.id === tagId);\n if (tagIndex === -1) {\n return {\n success: false,\n error: `Tag with ID '${tagId}' not found in project '${projectId}'`,\n code: 'NOT_FOUND',\n };\n }\n\n const tag = projectData.tags[tagIndex];\n\n // Remove tag from all tasks that use it\n const now = new Date().toISOString();\n let tasksUpdated = 0;\n for (const task of projectData.tasks) {\n const tagIndexInTask = task.tags.indexOf(tagId);\n if (tagIndexInTask !== -1) {\n task.tags.splice(tagIndexInTask, 1);\n task.updatedAt = now;\n tasksUpdated++;\n }\n }\n\n projectData.tags.splice(tagIndex, 1);\n projectData.project.updatedAt = now;\n\n await this.saveProjectData(projectId, projectData);\n\n return {\n success: true,\n data: {\n deleted: true,\n tag,\n tasksUpdated,\n },\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Failed to delete tag',\n code: 'INTERNAL_ERROR',\n };\n }\n }\n\n /**\n * Get all tasks that have a specific tag by tag name\n * @param projectId - The project ID\n * @param tagName - The tag name\n * @returns Tag info and matching tasks\n */\n async getTasksByTag(\n projectId: string,\n tagName: string\n ): Promise<ServiceResult<TasksByTagResult>> {\n try {\n const projectData = await this.storage.readProject(projectId);\n if (!projectData) {\n return {\n success: false,\n error: `Project with ID '${projectId}' not found`,\n code: 'NOT_FOUND',\n };\n }\n\n // Find tag by name (case-insensitive)\n const tag = projectData.tags.find(\n (t) => t.name.toLowerCase() === tagName.toLowerCase()\n );\n\n if (!tag) {\n return {\n success: false,\n error: `Tag with name '${tagName}' not found in project '${projectId}'`,\n code: 'NOT_FOUND',\n };\n }\n\n // Find all tasks with this tag\n const tasks = projectData.tasks.filter((t) => t.tags.includes(tag.id));\n\n return {\n success: true,\n data: {\n tag,\n tasks,\n count: tasks.length,\n },\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Failed to get tasks by tag',\n code: 'INTERNAL_ERROR',\n };\n }\n }\n\n /**\n * Helper method to save project data\n * @param projectId - The project ID\n * @param projectData - The project data to save\n */\n private async saveProjectData(projectId: string, projectData: ProjectData): Promise<void> {\n const filePath = this.storage.getFilePath(projectId);\n const { writeJsonFile } = await import('../utils/file-helpers.js');\n await writeJsonFile(filePath, projectData);\n }\n}\n","/**\n * Task Service - Unified business logic for task operations\n * Extracted from task-tools.ts to enable reuse across different interfaces\n */\n\nimport type { Task, TaskStatus } from '../models/index.js';\nimport { storage } from '../storage/index.js';\nimport { writeJsonFile } from '../utils/file-helpers.js';\nimport type {\n ServiceResult,\n CreateTaskData,\n UpdateTaskData,\n BatchUpdateTaskData,\n BatchUpdateResult,\n} from './types.js';\n\n/**\n * Generate a unique task ID\n * Format: task_${timestamp}_${random}\n */\nfunction generateTaskId(): string {\n return `task_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;\n}\n\n/**\n * Calculate completedAt based on status change\n * - When status changes to 'done', set completedAt to current time\n * - When status changes from 'done' to other, clear completedAt\n * - Otherwise, preserve existing completedAt\n */\nfunction calculateCompletedAt(\n currentStatus: TaskStatus,\n newStatus: TaskStatus | undefined,\n existingCompletedAt: string | null,\n now: string\n): string | null {\n // Status is not being updated\n if (!newStatus) {\n return existingCompletedAt;\n }\n\n // Status changing to 'done'\n if (newStatus === 'done' && currentStatus !== 'done') {\n return now;\n }\n\n // Status changing from 'done' to something else\n if (currentStatus === 'done' && newStatus !== 'done') {\n return null;\n }\n\n // Status changing but not involving 'done' transition\n return existingCompletedAt;\n}\n\n/**\n * TaskService - Business logic for task operations\n */\nexport const TaskService = {\n /**\n * Create a new task in a project\n * @param projectId - The project ID\n * @param data - Task creation data\n * @returns The created task or error\n */\n async create(projectId: string, data: CreateTaskData): Promise<ServiceResult<Task>> {\n try {\n const projectData = await storage.readProject(projectId);\n if (!projectData) {\n return {\n success: false,\n error: `Project with ID '${projectId}' not found`,\n code: 'NOT_FOUND',\n };\n }\n\n const now = new Date().toISOString();\n const task: Task = {\n id: generateTaskId(),\n projectId,\n title: data.title,\n description: data.description,\n status: 'todo',\n priority: data.priority ?? 'medium',\n tags: data.tags ?? [],\n dueDate: data.dueDate ?? null,\n assignee: data.assignee ?? null,\n createdAt: now,\n updatedAt: now,\n completedAt: null,\n };\n\n projectData.tasks.push(task);\n projectData.project.updatedAt = now;\n\n const filePath = storage.getFilePath(projectId);\n await writeJsonFile(filePath, projectData);\n\n return {\n success: true,\n data: task,\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Failed to create task',\n code: 'INTERNAL_ERROR',\n };\n }\n },\n\n /**\n * Get a specific task by project ID and task ID\n * @param projectId - The project ID\n * @param taskId - The task ID\n * @returns The task or error\n */\n async get(projectId: string, taskId: string): Promise<ServiceResult<Task>> {\n try {\n const projectData = await storage.readProject(projectId);\n if (!projectData) {\n return {\n success: false,\n error: `Project with ID '${projectId}' not found`,\n code: 'NOT_FOUND',\n };\n }\n\n const task = projectData.tasks.find((t) => t.id === taskId);\n if (!task) {\n return {\n success: false,\n error: `Task with ID '${taskId}' not found in project '${projectId}'`,\n code: 'NOT_FOUND',\n };\n }\n\n return {\n success: true,\n data: task,\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Failed to get task',\n code: 'INTERNAL_ERROR',\n };\n }\n },\n\n /**\n * Update an existing task\n * Handles completedAt automatically based on status changes\n * @param projectId - The project ID\n * @param taskId - The task ID\n * @param data - Task update data\n * @returns The updated task or error\n */\n async update(\n projectId: string,\n taskId: string,\n data: UpdateTaskData\n ): Promise<ServiceResult<Task>> {\n try {\n const projectData = await storage.readProject(projectId);\n if (!projectData) {\n return {\n success: false,\n error: `Project with ID '${projectId}' not found`,\n code: 'NOT_FOUND',\n };\n }\n\n const taskIndex = projectData.tasks.findIndex((t) => t.id === taskId);\n if (taskIndex === -1) {\n return {\n success: false,\n error: `Task with ID '${taskId}' not found in project '${projectId}'`,\n code: 'NOT_FOUND',\n };\n }\n\n // Check if there's anything to update\n const updateKeys = Object.keys(data);\n if (updateKeys.length === 0) {\n return {\n success: false,\n error: 'At least one field to update is required',\n code: 'VALIDATION_ERROR',\n };\n }\n\n const now = new Date().toISOString();\n const existingTask = projectData.tasks[taskIndex];\n\n // Calculate completedAt based on status change\n const completedAt = calculateCompletedAt(\n existingTask.status,\n data.status,\n existingTask.completedAt,\n now\n );\n\n const updatedTask: Task = {\n ...existingTask,\n ...data,\n id: existingTask.id,\n projectId: existingTask.projectId,\n createdAt: existingTask.createdAt,\n updatedAt: now,\n completedAt,\n };\n\n projectData.tasks[taskIndex] = updatedTask;\n projectData.project.updatedAt = now;\n\n const filePath = storage.getFilePath(projectId);\n await writeJsonFile(filePath, projectData);\n\n return {\n success: true,\n data: updatedTask,\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Failed to update task',\n code: 'INTERNAL_ERROR',\n };\n }\n },\n\n /**\n * Delete a task by project ID and task ID\n * @param projectId - The project ID\n * @param taskId - The task ID\n * @returns Void or error\n */\n async delete(projectId: string, taskId: string): Promise<ServiceResult<void>> {\n try {\n const projectData = await storage.readProject(projectId);\n if (!projectData) {\n return {\n success: false,\n error: `Project with ID '${projectId}' not found`,\n code: 'NOT_FOUND',\n };\n }\n\n const taskIndex = projectData.tasks.findIndex((t) => t.id === taskId);\n if (taskIndex === -1) {\n return {\n success: false,\n error: `Task with ID '${taskId}' not found in project '${projectId}'`,\n code: 'NOT_FOUND',\n };\n }\n\n const now = new Date().toISOString();\n projectData.tasks.splice(taskIndex, 1);\n projectData.project.updatedAt = now;\n\n const filePath = storage.getFilePath(projectId);\n await writeJsonFile(filePath, projectData);\n\n return {\n success: true,\n data: undefined,\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Failed to delete task',\n code: 'INTERNAL_ERROR',\n };\n }\n },\n\n /**\n * List tasks with optional filters\n * @param filters - Optional filters for the search\n * @returns Array of tasks or error\n */\n async list(filters?: {\n projectId?: string;\n status?: TaskStatus;\n priority?: 'low' | 'medium' | 'high' | 'critical';\n tags?: string[];\n assignee?: string;\n dueBefore?: string;\n dueAfter?: string;\n includeCompleted?: boolean;\n }): Promise<ServiceResult<Task[]>> {\n try {\n const results = await storage.searchTasks({\n projectId: filters?.projectId,\n status: filters?.status,\n priority: filters?.priority,\n tags: filters?.tags,\n assignee: filters?.assignee,\n dueBefore: filters?.dueBefore,\n dueAfter: filters?.dueAfter,\n includeCompleted: filters?.includeCompleted,\n });\n\n // Extract just the tasks from the results\n const tasks = results.map((r) => r.task);\n\n return {\n success: true,\n data: tasks,\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Failed to list tasks',\n code: 'INTERNAL_ERROR',\n };\n }\n },\n\n /**\n * Update multiple tasks at once\n * @param projectId - The project ID\n * @param taskIds - Array of task IDs to update\n * @param data - Batch update data\n * @returns Batch update result or error\n */\n async batchUpdate(\n projectId: string,\n taskIds: string[],\n data: BatchUpdateTaskData\n ): Promise<ServiceResult<BatchUpdateResult>> {\n try {\n const projectData = await storage.readProject(projectId);\n if (!projectData) {\n return {\n success: false,\n error: `Project with ID '${projectId}' not found`,\n code: 'NOT_FOUND',\n };\n }\n\n const now = new Date().toISOString();\n const updatedTasks: Task[] = [];\n const notFoundIds: string[] = [];\n\n for (const taskId of taskIds) {\n const taskIndex = projectData.tasks.findIndex((t) => t.id === taskId);\n if (taskIndex === -1) {\n notFoundIds.push(taskId);\n continue;\n }\n\n const existingTask = projectData.tasks[taskIndex];\n let updatedTags = existingTask.tags;\n\n // Handle tags based on tagOperation\n if (data.tags && data.tags.length > 0) {\n const existingTags = existingTask.tags || [];\n switch (data.tagOperation) {\n case 'add':\n updatedTags = [...new Set([...existingTags, ...data.tags])];\n break;\n case 'remove':\n updatedTags = existingTags.filter((tag) => !data.tags!.includes(tag));\n break;\n case 'replace':\n default:\n updatedTags = data.tags;\n break;\n }\n }\n\n // Calculate completedAt based on status change\n const completedAt = calculateCompletedAt(\n existingTask.status,\n data.status,\n existingTask.completedAt,\n now\n );\n\n const updatedTask: Task = {\n ...existingTask,\n ...(data.status && { status: data.status }),\n ...(data.priority && { priority: data.priority }),\n tags: updatedTags,\n updatedAt: now,\n completedAt,\n };\n\n projectData.tasks[taskIndex] = updatedTask;\n updatedTasks.push(updatedTask);\n }\n\n if (updatedTasks.length === 0) {\n return {\n success: false,\n error: 'No tasks were found to update',\n code: 'NOT_FOUND',\n };\n }\n\n projectData.project.updatedAt = now;\n\n const filePath = storage.getFilePath(projectId);\n await writeJsonFile(filePath, projectData);\n\n return {\n success: true,\n data: {\n updatedTasks,\n updatedCount: updatedTasks.length,\n notFoundIds: notFoundIds.length > 0 ? notFoundIds : undefined,\n },\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Failed to batch update tasks',\n code: 'INTERNAL_ERROR',\n };\n }\n },\n};\n","/**\n * Service layer type definitions\n * Provides unified result types and service interfaces\n */\n\nimport type { ProjectStorage } from '../storage/index.js';\nimport type { Task, Tag, TaskStatus, TaskPriority } from '../models/index.js';\n\n// ============================================================================\n// Result Types\n// ============================================================================\n\n/**\n * Error codes for service operations\n */\nexport type ErrorCode =\n | 'NOT_FOUND'\n | 'VALIDATION_ERROR'\n | 'DUPLICATE_ERROR'\n | 'UNAUTHORIZED'\n | 'INTERNAL_ERROR';\n\n/**\n * Service result type - discriminated union for success/failure\n */\nexport type ServiceResult<T> =\n | { success: true; data: T }\n | { success: false; error: string; code: ErrorCode };\n\n// ============================================================================\n// Task Service Types\n// ============================================================================\n\nexport interface CreateTaskData {\n title: string;\n description: string;\n priority?: TaskPriority;\n tags?: string[];\n dueDate?: string | null;\n assignee?: string | null;\n}\n\nexport interface UpdateTaskData {\n title?: string;\n description?: string;\n status?: TaskStatus;\n priority?: TaskPriority;\n tags?: string[];\n dueDate?: string | null;\n assignee?: string | null;\n}\n\nexport interface BatchUpdateTaskData {\n status?: TaskStatus;\n priority?: TaskPriority;\n tags?: string[];\n tagOperation?: 'add' | 'remove' | 'replace';\n}\n\nexport interface BatchUpdateResult {\n updatedTasks: Task[];\n updatedCount: number;\n notFoundIds?: string[];\n}\n\n// ============================================================================\n// Tag Service Types\n// ============================================================================\n\nexport interface CreateTagData {\n name: string;\n color: string;\n description?: string;\n}\n\nexport interface UpdateTagData {\n name?: string;\n color?: string;\n description?: string;\n}\n\nexport interface DeleteTagResult {\n deleted: true;\n tag: Tag;\n tasksUpdated: number;\n}\n\nexport interface TasksByTagResult {\n tag: Tag;\n tasks: Task[];\n count: number;\n}\n\n// ============================================================================\n// Service Context\n// ============================================================================\n\n/**\n * Service context for dependency injection\n */\nexport interface ServiceContext {\n storage: ProjectStorage;\n}\n\n// ============================================================================\n// Service Interfaces\n// ============================================================================\n\n/**\n * Task Service interface\n */\nexport interface ITaskService {\n create(projectId: string, data: CreateTaskData): Promise<ServiceResult<Task>>;\n get(projectId: string, taskId: string): Promise<ServiceResult<Task>>;\n update(projectId: string, taskId: string, data: UpdateTaskData): Promise<ServiceResult<Task>>;\n delete(projectId: string, taskId: string): Promise<ServiceResult<void>>;\n list(filters?: {\n projectId?: string;\n status?: TaskStatus;\n priority?: TaskPriority;\n tags?: string[];\n assignee?: string;\n dueBefore?: string;\n dueAfter?: string;\n includeCompleted?: boolean;\n }): Promise<ServiceResult<Task[]>>;\n batchUpdate(\n projectId: string,\n taskIds: string[],\n data: BatchUpdateTaskData\n ): Promise<ServiceResult<BatchUpdateResult>>;\n}\n\n/**\n * Tag Service interface\n */\nexport interface ITagService {\n create(projectId: string, data: CreateTagData): Promise<ServiceResult<Tag>>;\n list(projectId: string): Promise<ServiceResult<Tag[]>>;\n update(projectId: string, tagId: string, data: UpdateTagData): Promise<ServiceResult<Tag>>;\n delete(projectId: string, tagId: string): Promise<ServiceResult<DeleteTagResult>>;\n getTasksByTag(projectId: string, tagName: string): Promise<ServiceResult<TasksByTagResult>>;\n}\n","import { z } from 'zod';\nimport { TagService } from '../services/index.js';\nimport { storage } from '../storage/index.js';\n\nconst tagService = new TagService(storage);\n\nexport const createTagTool = {\n name: 'create_tag',\n description: 'Create a new tag in a project',\n inputSchema: z.object({\n projectId: z.string().min(1, 'Project ID is required'),\n name: z.string().min(1, 'Tag name is required'),\n color: z.string().regex(/^#[0-9A-Fa-f]{6}$/, 'Color must be a valid hex code (e.g., #FF5733)'),\n description: z.string().default(''),\n }),\n async execute(input: {\n projectId: string;\n name: string;\n color: string;\n description: string;\n }) {\n const { projectId, ...data } = input;\n const result = await tagService.create(projectId, data);\n\n if (!result.success) {\n return { success: false, error: result.error };\n }\n\n return { success: true, data: result.data };\n },\n};\n\nexport const listTagsTool = {\n name: 'list_tags',\n description: 'List all tags in a project',\n inputSchema: z.object({\n projectId: z.string().min(1, 'Project ID is required'),\n }),\n async execute(input: { projectId: string }) {\n const result = await tagService.list(input.projectId);\n\n if (!result.success) {\n return { success: false, error: result.error };\n }\n\n return { success: true, data: result.data };\n },\n};\n\nexport const updateTagTool = {\n name: 'update_tag',\n description: 'Update an existing tag',\n inputSchema: z.object({\n projectId: z.string().min(1, 'Project ID is required'),\n tagId: z.string().min(1, 'Tag ID is required'),\n name: z.string().min(1).optional(),\n color: z.string().regex(/^#[0-9A-Fa-f]{6}$/).optional(),\n description: z.string().optional(),\n }),\n async execute(input: {\n projectId: string;\n tagId: string;\n name?: string;\n color?: string;\n description?: string;\n }) {\n const { projectId, tagId, ...data } = input;\n const result = await tagService.update(projectId, tagId, data);\n\n if (!result.success) {\n return { success: false, error: result.error };\n }\n\n return { success: true, data: result.data };\n },\n};\n\nexport const deleteTagTool = {\n name: 'delete_tag',\n description: 'Delete a tag by project ID and tag ID',\n inputSchema: z.object({\n projectId: z.string().min(1, 'Project ID is required'),\n tagId: z.string().min(1, 'Tag ID is required'),\n }),\n async execute(input: { projectId: string; tagId: string }) {\n const result = await tagService.delete(input.projectId, input.tagId);\n\n if (!result.success) {\n return { success: false, error: result.error };\n }\n\n return { success: true, data: result.data };\n },\n};\n\nexport const getTasksByTagTool = {\n name: 'get_tasks_by_tag',\n description: 'Get all tasks that have a specific tag',\n inputSchema: z.object({\n projectId: z.string().min(1, 'Project ID is required'),\n tagName: z.string().min(1, 'Tag name is required'),\n }),\n async execute(input: { projectId: string; tagName: string }) {\n const result = await tagService.getTasksByTag(input.projectId, input.tagName);\n\n if (!result.success) {\n return { success: false, error: result.error };\n }\n\n return { success: true, data: result.data };\n },\n};\n","import { createServer } from '../web/server.js';\nimport open from 'open';\nimport type { Server } from 'http';\n\nlet activeServer: Server | null = null;\nlet activePort: number | null = null;\n\nfunction getServerPort(server: Server): number | null {\n const address = server.address();\n\n if (address && typeof address === 'object' && 'port' in address) {\n return typeof address.port === 'number' ? address.port : null;\n }\n\n return null;\n}\n\nasync function closeServer(server: Server): Promise<void> {\n await new Promise<void>((resolve, reject) => {\n server.close((error) => {\n if (error) {\n reject(error);\n return;\n }\n\n resolve();\n });\n\n const forceCloseServer = server as {\n closeAllConnections?: () => void;\n closeIdleConnections?: () => void;\n };\n forceCloseServer.closeIdleConnections?.();\n forceCloseServer.closeAllConnections?.();\n });\n}\n\nasync function openBrowser(url: string): Promise<void> {\n try {\n await open(url);\n } catch (error) {\n console.error('Failed to open browser:', error);\n }\n}\n\nexport const openWebInterfaceTool = {\n name: 'open_web_interface',\n description: 'Open web visualization interface',\n parameters: {\n type: 'object',\n properties: {\n port: {\n type: 'number',\n description: 'Port to run the web interface on (default: 7860)',\n },\n },\n },\n async execute(args: { port?: number }) {\n const requestedPort = args.port || 7860;\n\n if (activeServer) {\n const runningPort = getServerPort(activeServer) ?? activePort;\n\n if (runningPort !== requestedPort) {\n throw new Error(`Web interface is already running on port ${runningPort ?? 'unknown'}. Please close it before opening a different port.`);\n }\n\n const url = `http://localhost:${runningPort ?? requestedPort}`;\n await openBrowser(url);\n\n return { \n message: 'Web interface is already running',\n url,\n };\n }\n\n const url = `http://localhost:${requestedPort}`;\n\n try {\n activeServer = await createServer(requestedPort);\n activePort = requestedPort;\n await openBrowser(url);\n\n return {\n message: 'Web interface started successfully and opened in browser',\n url,\n };\n } catch (error) {\n activeServer = null;\n activePort = null;\n\n const errorMessage = error instanceof Error ? error.message : String(error);\n throw new Error(`Failed to start web interface: ${errorMessage}`);\n }\n }\n};\n\nexport const closeWebInterfaceTool = {\n name: 'close_web_interface',\n description: 'Close web visualization interface',\n parameters: {\n type: 'object',\n properties: {},\n },\n async execute() {\n if (!activeServer) {\n return { message: 'Web interface is not running' };\n }\n\n try {\n await closeServer(activeServer);\n activeServer = null;\n activePort = null;\n return { message: 'Web interface stopped' };\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n throw new Error(`Failed to stop web interface: ${errorMessage}`);\n }\n }\n};\n","import express from 'express';\nimport * as path from 'path';\nimport { fileURLToPath } from 'url';\nimport type { Server } from 'http';\nimport { storage } from '../storage/index.js';\nimport { TaskService, TagService } from '../services/index.js';\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = path.dirname(__filename);\n\nconst tagService = new TagService(storage);\n\nexport function createServer(port: number = 7860): Promise<Server> {\n return new Promise((resolve, reject) => {\n const app = express();\n\n app.use(express.json());\n\n app.get('/api/projects', async (_req, res) => {\n try {\n const projects = await storage.listProjects();\n res.json(projects);\n } catch (error) {\n res.status(500).json({ error: (error as Error).message });\n }\n });\n\n app.get('/api/projects/:id', async (req, res) => {\n try {\n const project = await storage.readProject(req.params.id);\n if (!project) {\n res.status(404).json({ error: 'Project not found' });\n return;\n }\n res.json(project);\n } catch (error) {\n res.status(500).json({ error: (error as Error).message });\n }\n });\n\n app.get('/api/tasks', async (req, res) => {\n try {\n const filters: Record<string, unknown> = { ...req.query };\n\n // Convert includeCompleted from string to boolean\n if (filters.includeCompleted !== undefined) {\n filters.includeCompleted = filters.includeCompleted === 'true';\n }\n\n const tasks = await storage.searchTasks(filters as any);\n res.json(tasks);\n } catch (error) {\n res.status(500).json({ error: (error as Error).message });\n }\n });\n\n app.post('/api/projects', async (req, res) => {\n try {\n const project = await storage.createProject(req.body);\n res.json({ success: true, data: project });\n } catch (error) {\n res.status(500).json({ error: (error as Error).message });\n }\n });\n\n app.put('/api/projects', async (req, res) => {\n try {\n const { projectId, ...updateData } = req.body;\n const project = await storage.updateProject(projectId, updateData);\n res.json({ success: true, data: project });\n } catch (error) {\n res.status(500).json({ error: (error as Error).message });\n }\n });\n\n app.delete('/api/projects', async (req, res) => {\n try {\n const { projectId } = req.query;\n await storage.deleteProject(projectId as string);\n res.json({ success: true });\n } catch (error) {\n res.status(500).json({ error: (error as Error).message });\n }\n });\n\n app.post('/api/tasks', async (req, res) => {\n try {\n const { projectId, ...taskData } = req.body;\n const result = await TaskService.create(projectId, taskData);\n if (!result.success) {\n const statusCode = result.code === 'NOT_FOUND' ? 404 : 400;\n res.status(statusCode).json({ error: result.error });\n return;\n }\n res.json({ success: true, data: result.data });\n } catch (error) {\n res.status(500).json({ error: (error as Error).message });\n }\n });\n\n app.put('/api/tasks', async (req, res) => {\n try {\n const { projectId, taskId, ...updateData } = req.body;\n const result = await TaskService.update(projectId, taskId, updateData);\n if (!result.success) {\n const statusCode = result.code === 'NOT_FOUND' ? 404 : 400;\n res.status(statusCode).json({ error: result.error });\n return;\n }\n res.json({ success: true, data: result.data });\n } catch (error) {\n res.status(500).json({ error: (error as Error).message });\n }\n });\n\n app.delete('/api/tasks', async (req, res) => {\n try {\n const { projectId, taskId } = req.query;\n const result = await TaskService.delete(projectId as string, taskId as string);\n if (!result.success) {\n const statusCode = result.code === 'NOT_FOUND' ? 404 : 400;\n res.status(statusCode).json({ error: result.error });\n return;\n }\n res.json({ success: true });\n } catch (error) {\n res.status(500).json({ error: (error as Error).message });\n }\n });\n\n app.post('/api/projects/:projectId/tags', async (req, res) => {\n try {\n const { projectId } = req.params;\n const result = await tagService.create(projectId, req.body);\n if (!result.success) {\n const statusCode = result.code === 'NOT_FOUND' ? 404 : 400;\n res.status(statusCode).json({ error: result.error });\n return;\n }\n res.json({ success: true, data: result.data });\n } catch (error) {\n res.status(500).json({ error: (error as Error).message });\n }\n });\n\n app.get('/api/projects/:projectId/tags', async (req, res) => {\n try {\n const { projectId } = req.params;\n const result = await tagService.list(projectId);\n if (!result.success) {\n const statusCode = result.code === 'NOT_FOUND' ? 404 : 400;\n res.status(statusCode).json({ error: result.error });\n return;\n }\n res.json({ success: true, data: result.data });\n } catch (error) {\n res.status(500).json({ error: (error as Error).message });\n }\n });\n\n app.put('/api/projects/:projectId/tags/:tagId', async (req, res) => {\n try {\n const { projectId, tagId } = req.params;\n const result = await tagService.update(projectId, tagId, req.body);\n if (!result.success) {\n const statusCode = result.code === 'NOT_FOUND' ? 404 : 400;\n res.status(statusCode).json({ error: result.error });\n return;\n }\n res.json({ success: true, data: result.data });\n } catch (error) {\n res.status(500).json({ error: (error as Error).message });\n }\n });\n\n app.delete('/api/projects/:projectId/tags/:tagId', async (req, res) => {\n try {\n const { projectId, tagId } = req.params;\n const result = await tagService.delete(projectId, tagId);\n if (!result.success) {\n const statusCode = result.code === 'NOT_FOUND' ? 404 : 400;\n res.status(statusCode).json({ error: result.error });\n return;\n }\n res.json({ success: true, data: result.data });\n } catch (error) {\n res.status(500).json({ error: (error as Error).message });\n }\n });\n\n app.get('/api/backup', async (_req, res) => {\n try {\n const backup = await storage.exportAllData();\n const filename = `roadmap-skill-backup-${new Date().toISOString().split('T')[0]}.json`;\n res.setHeader('Content-Type', 'application/json');\n res.setHeader('Content-Disposition', `attachment; filename=\"${filename}\"`);\n res.json(backup);\n } catch (error) {\n res.status(500).json({ error: (error as Error).message });\n }\n });\n\n app.post('/api/backup', async (req, res) => {\n try {\n const result = await storage.importAllData(req.body);\n res.json(result);\n } catch (error) {\n res.status(400).json({\n success: false,\n error: (error as Error).message,\n });\n }\n });\n\n const distPath = path.join(__dirname, 'app');\n app.use(express.static(distPath));\n\n app.get('*', (req, res) => {\n if (req.path.startsWith('/api')) {\n res.status(404).json({ error: 'API not found' });\n return;\n }\n res.sendFile(path.join(distPath, 'index.html'));\n });\n\n const server = app.listen(port, '127.0.0.1');\n\n server.once('listening', () => {\n console.log(`Web interface server running at http://localhost:${port}`);\n resolve(server);\n });\n\n server.once('error', (error: NodeJS.ErrnoException) => {\n if (error.code === 'EADDRINUSE') {\n reject(new Error(`Port ${port} is already in use`));\n return;\n }\n\n reject(error);\n });\n });\n}\n\n// Start server if run directly\nif (process.argv[1]?.endsWith('server.js')) {\n const port = parseInt(process.argv[2] || '7860', 10);\n createServer(port).catch(err => {\n console.error('Failed to start server:', err);\n process.exit(1);\n });\n}\n","import { z } from 'zod';\nimport * as path from 'path';\nimport * as fs from 'fs/promises';\nimport { storage } from '../storage/index.js';\nimport type { CreateProjectInput, Tag, Task } from '../models/index.js';\n\nconst TEMPLATES_DIR = path.join(process.cwd(), 'templates');\n\ninterface TemplateMetadata {\n name: string;\n description: string;\n projectType: string;\n tasks: Array<{\n title: string;\n description: string;\n priority: 'low' | 'medium' | 'high' | 'critical';\n tags: string[];\n estimatedHours?: number;\n }>;\n tags: Array<{\n name: string;\n color: string;\n }>;\n}\n\nasync function getTemplateFiles(): Promise<string[]> {\n try {\n const files = await fs.readdir(TEMPLATES_DIR);\n return files.filter((f) => f.endsWith('.json'));\n } catch {\n return [];\n }\n}\n\nasync function loadTemplate(templateName: string): Promise<TemplateMetadata | null> {\n try {\n const fileName = templateName.endsWith('.json') ? templateName : `${templateName}.json`;\n const filePath = path.join(TEMPLATES_DIR, fileName);\n const content = await fs.readFile(filePath, 'utf-8');\n return JSON.parse(content) as TemplateMetadata;\n } catch {\n return null;\n }\n}\n\nfunction generateId(prefix: string): string {\n return `${prefix}_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;\n}\n\nexport const listTemplatesTool = {\n name: 'list_templates',\n description: 'List all available project templates',\n inputSchema: z.object({}),\n async execute() {\n try {\n const templateFiles = await getTemplateFiles();\n const templates = [];\n\n for (const file of templateFiles) {\n const template = await loadTemplate(file);\n if (template) {\n templates.push({\n name: file.replace('.json', ''),\n displayName: template.name,\n description: template.description,\n projectType: template.projectType,\n taskCount: template.tasks.length,\n tagCount: template.tags.length,\n });\n }\n }\n\n return {\n success: true,\n data: templates,\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Failed to list templates',\n };\n }\n },\n};\n\nexport const getTemplateTool = {\n name: 'get_template',\n description: 'Get detailed information about a specific template',\n inputSchema: z.object({\n templateName: z.string().min(1, 'Template name is required'),\n }),\n async execute(input: { templateName: string }) {\n try {\n const template = await loadTemplate(input.templateName);\n\n if (!template) {\n return {\n success: false,\n error: `Template '${input.templateName}' not found`,\n };\n }\n\n return {\n success: true,\n data: {\n name: template.name,\n description: template.description,\n projectType: template.projectType,\n tasks: template.tasks.map((t) => ({\n title: t.title,\n description: t.description,\n priority: t.priority,\n tags: t.tags,\n estimatedHours: t.estimatedHours,\n })),\n tags: template.tags,\n },\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Failed to get template',\n };\n }\n },\n};\n\nexport const applyTemplateTool = {\n name: 'apply_template',\n description: 'Create a new project from a template',\n inputSchema: z.object({\n templateName: z.string().min(1, 'Template name is required'),\n projectName: z.string().min(1, 'Project name is required'),\n description: z.string().default(''),\n startDate: z.string().regex(/^\\d{4}-\\d{2}-\\d{2}$/, 'Date must be in YYYY-MM-DD format').optional(),\n targetDate: z.string().regex(/^\\d{4}-\\d{2}-\\d{2}$/, 'Date must be in YYYY-MM-DD format').optional(),\n }),\n async execute(input: {\n templateName: string;\n projectName: string;\n description: string;\n startDate?: string;\n targetDate?: string;\n }) {\n try {\n const template = await loadTemplate(input.templateName);\n\n if (!template) {\n return {\n success: false,\n error: `Template '${input.templateName}' not found`,\n };\n }\n\n const projectInput: CreateProjectInput = {\n name: input.projectName,\n description: input.description || template.description,\n projectType: template.projectType as 'roadmap' | 'skill-tree' | 'kanban',\n startDate: input.startDate || new Date().toISOString().split('T')[0],\n targetDate: input.targetDate || new Date().toISOString().split('T')[0],\n };\n\n const projectData = await storage.createProject(projectInput);\n const projectId = projectData.project.id;\n const now = new Date().toISOString();\n\n const tagNameToId: Map<string, string> = new Map();\n const tags: Tag[] = [];\n\n for (const templateTag of template.tags) {\n const tag: Tag = {\n id: generateId('tag'),\n name: templateTag.name,\n color: templateTag.color,\n description: '',\n createdAt: now,\n };\n tags.push(tag);\n tagNameToId.set(templateTag.name, tag.id);\n }\n\n const tasks: Task[] = [];\n\n for (const templateTask of template.tasks) {\n const taskTagIds = templateTask.tags\n .map((tagName) => tagNameToId.get(tagName))\n .filter((id): id is string => id !== undefined);\n\n const task: Task = {\n id: generateId('task'),\n projectId,\n title: templateTask.title,\n description: templateTask.description,\n status: 'todo',\n priority: templateTask.priority,\n tags: taskTagIds,\n dueDate: null,\n assignee: null,\n createdAt: now,\n updatedAt: now,\n completedAt: null,\n };\n tasks.push(task);\n }\n\n projectData.tags = tags;\n projectData.tasks = tasks;\n projectData.project.updatedAt = now;\n\n const filePath = storage.getFilePath(projectId);\n const { writeJsonFile } = await import('../utils/file-helpers.js');\n await writeJsonFile(filePath, projectData);\n\n return {\n success: true,\n data: {\n project: projectData.project,\n taskCount: tasks.length,\n tagCount: tags.length,\n tasksCreated: tasks.map((t) => ({\n id: t.id,\n title: t.title,\n priority: t.priority,\n })),\n tagsCreated: tags.map((t) => ({\n id: t.id,\n name: t.name,\n color: t.color,\n })),\n },\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Failed to apply template',\n };\n }\n },\n};\n","export {\n projectResources,\n handleResourceRequest,\n getAllResources,\n} from './project-resources.js';\n","import type {\n Resource,\n TextResourceContents,\n} from '@modelcontextprotocol/sdk/types.js';\nimport { storage } from '../storage/index.js';\n\n/**\n * Resource definitions for roadmap projects\n */\nexport const projectResources: Resource[] = [\n {\n uri: 'roadmap://projects',\n name: 'Project List',\n mimeType: 'application/json',\n description: 'Returns a list of all projects with basic metadata',\n },\n {\n uri: 'roadmap://project/{projectId}',\n name: 'Project Details',\n mimeType: 'application/json',\n description: 'Returns detailed information about a specific project including tasks, milestones, and tags',\n },\n {\n uri: 'roadmap://project/{projectId}/tasks',\n name: 'Project Tasks',\n mimeType: 'application/json',\n description: 'Returns all tasks for a specific project',\n },\n {\n uri: 'roadmap://project/{projectId}/progress',\n name: 'Project Progress',\n mimeType: 'application/json',\n description: 'Returns progress statistics for a specific project',\n },\n];\n\n/**\n * Resource URI patterns for matching\n */\nconst RESOURCE_PATTERNS = {\n projectList: /^roadmap:\\/\\/projects$/,\n projectDetails: /^roadmap:\\/\\/project\\/([^/]+)$/,\n projectTasks: /^roadmap:\\/\\/project\\/([^/]+)\\/tasks$/,\n projectProgress: /^roadmap:\\/\\/project\\/([^/]+)\\/progress$/,\n};\n\n/**\n * Handle resource requests\n * @param uri - The resource URI\n * @returns Resource contents or null if not found\n */\nexport async function handleResourceRequest(\n uri: string\n): Promise<TextResourceContents | null> {\n // Project List: roadmap://projects\n if (RESOURCE_PATTERNS.projectList.test(uri)) {\n return await getProjectListResource(uri);\n }\n\n // Project Details: roadmap://project/{projectId}\n const projectDetailsMatch = uri.match(RESOURCE_PATTERNS.projectDetails);\n if (projectDetailsMatch && !uri.includes('/tasks') && !uri.includes('/progress')) {\n const projectId = projectDetailsMatch[1];\n return await getProjectDetailsResource(uri, projectId);\n }\n\n // Project Tasks: roadmap://project/{projectId}/tasks\n const projectTasksMatch = uri.match(RESOURCE_PATTERNS.projectTasks);\n if (projectTasksMatch) {\n const projectId = projectTasksMatch[1];\n return await getProjectTasksResource(uri, projectId);\n }\n\n // Project Progress: roadmap://project/{projectId}/progress\n const projectProgressMatch = uri.match(RESOURCE_PATTERNS.projectProgress);\n if (projectProgressMatch) {\n const projectId = projectProgressMatch[1];\n return await getProjectProgressResource(uri, projectId);\n }\n\n return null;\n}\n\n/**\n * Get project list resource\n */\nasync function getProjectListResource(uri: string): Promise<TextResourceContents> {\n const projects = await storage.listProjects();\n\n const data = {\n projects: projects.map(p => ({\n id: p.project.id,\n name: p.project.name,\n description: p.project.description,\n status: p.project.status,\n projectType: p.project.projectType,\n taskCount: p.taskCount,\n milestoneCount: p.milestoneCount,\n updatedAt: p.project.updatedAt,\n })),\n totalCount: projects.length,\n };\n\n return {\n uri,\n mimeType: 'application/json',\n text: JSON.stringify(data, null, 2),\n };\n}\n\n/**\n * Get project details resource\n */\nasync function getProjectDetailsResource(\n uri: string,\n projectId: string\n): Promise<TextResourceContents | null> {\n const projectData = await storage.readProject(projectId);\n\n if (!projectData) {\n return null;\n }\n\n const data = {\n project: projectData.project,\n milestones: projectData.milestones,\n tasks: projectData.tasks,\n tags: projectData.tags,\n stats: {\n taskCount: projectData.tasks.length,\n milestoneCount: projectData.milestones.length,\n tagCount: projectData.tags.length,\n completedTasks: projectData.tasks.filter(t => t.status === 'done').length,\n inProgressTasks: projectData.tasks.filter(t => t.status === 'in-progress').length,\n },\n };\n\n return {\n uri,\n mimeType: 'application/json',\n text: JSON.stringify(data, null, 2),\n };\n}\n\n/**\n * Get project tasks resource\n */\nasync function getProjectTasksResource(\n uri: string,\n projectId: string\n): Promise<TextResourceContents | null> {\n const projectData = await storage.readProject(projectId);\n\n if (!projectData) {\n return null;\n }\n\n const tasksByStatus = {\n todo: projectData.tasks.filter(t => t.status === 'todo'),\n inProgress: projectData.tasks.filter(t => t.status === 'in-progress'),\n review: projectData.tasks.filter(t => t.status === 'review'),\n done: projectData.tasks.filter(t => t.status === 'done'),\n };\n\n const data = {\n projectId,\n projectName: projectData.project.name,\n tasks: projectData.tasks,\n tasksByStatus,\n summary: {\n total: projectData.tasks.length,\n todo: tasksByStatus.todo.length,\n inProgress: tasksByStatus.inProgress.length,\n review: tasksByStatus.review.length,\n done: tasksByStatus.done.length,\n },\n };\n\n return {\n uri,\n mimeType: 'application/json',\n text: JSON.stringify(data, null, 2),\n };\n}\n\n/**\n * Get project progress resource\n */\nasync function getProjectProgressResource(\n uri: string,\n projectId: string\n): Promise<TextResourceContents | null> {\n const projectData = await storage.readProject(projectId);\n\n if (!projectData) {\n return null;\n }\n\n const tasks = projectData.tasks;\n const totalTasks = tasks.length;\n const completedTasks = tasks.filter(t => t.status === 'done').length;\n const inProgressTasks = tasks.filter(t => t.status === 'in-progress').length;\n const reviewTasks = tasks.filter(t => t.status === 'review').length;\n const todoTasks = tasks.filter(t => t.status === 'todo').length;\n\n const completionPercentage = totalTasks > 0 ? Math.round((completedTasks / totalTasks) * 100) : 0;\n\n const milestones = projectData.milestones;\n const completedMilestones = milestones.filter(m => m.completedAt !== null).length;\n const milestoneProgress = milestones.length > 0 ? Math.round((completedMilestones / milestones.length) * 100) : 0;\n\n // Calculate overdue tasks\n const now = new Date().toISOString();\n const overdueTasks = tasks.filter(t => \n t.dueDate && \n t.dueDate < now && \n t.status !== 'done'\n );\n\n // Priority breakdown\n const priorityBreakdown = {\n critical: tasks.filter(t => t.priority === 'critical').length,\n high: tasks.filter(t => t.priority === 'high').length,\n medium: tasks.filter(t => t.priority === 'medium').length,\n low: tasks.filter(t => t.priority === 'low').length,\n };\n\n const data = {\n projectId,\n projectName: projectData.project.name,\n projectStatus: projectData.project.status,\n dates: {\n startDate: projectData.project.startDate,\n targetDate: projectData.project.targetDate,\n daysRemaining: calculateDaysRemaining(projectData.project.targetDate),\n },\n taskProgress: {\n total: totalTasks,\n completed: completedTasks,\n inProgress: inProgressTasks,\n review: reviewTasks,\n todo: todoTasks,\n completionPercentage,\n },\n milestoneProgress: {\n total: milestones.length,\n completed: completedMilestones,\n percentage: milestoneProgress,\n },\n overdueTasks: {\n count: overdueTasks.length,\n tasks: overdueTasks.map(t => ({\n id: t.id,\n title: t.title,\n dueDate: t.dueDate,\n status: t.status,\n })),\n },\n priorityBreakdown,\n lastUpdated: projectData.project.updatedAt,\n };\n\n return {\n uri,\n mimeType: 'application/json',\n text: JSON.stringify(data, null, 2),\n };\n}\n\n/**\n * Calculate days remaining until target date\n */\nfunction calculateDaysRemaining(targetDate: string): number | null {\n const target = new Date(targetDate);\n const now = new Date();\n const diffTime = target.getTime() - now.getTime();\n const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24));\n return diffDays > 0 ? diffDays : null;\n}\n\n/**\n * Get all available resources\n */\nexport function getAllResources(): Resource[] {\n return projectResources;\n}\n","export {\n projectPrompts,\n getRecommendNextTasksPrompt,\n getAutoPrioritizePrompt,\n getEnhanceTaskDetailsPrompt,\n getQuickCapturePrompt,\n getPromptByName,\n getAllPrompts,\n} from './project-prompts.js';\n","import type {\n Prompt,\n GetPromptResult,\n} from '@modelcontextprotocol/sdk/types.js';\n\n/**\n * Curated Prompts - Help Agents use Roadmap Skill more intelligently\n */\nexport const projectPrompts: Prompt[] = [\n {\n name: 'recommendNextTasks',\n description: 'Intelligently recommend the next priority tasks based on urgency, due dates, and project status',\n arguments: [\n {\n name: 'projectId',\n description: 'Specific project ID (optional; if not provided, analyze all projects)',\n required: false,\n },\n {\n name: 'limit',\n description: 'Number of tasks to recommend (default: 3)',\n required: false,\n },\n ],\n },\n {\n name: 'autoPrioritize',\n description: 'Automatically analyze tasks and intelligently adjust priorities, considering due dates, dependencies, and project importance',\n arguments: [\n {\n name: 'projectId',\n description: 'Specific project ID (optional; if not provided, analyze all projects)',\n required: false,\n },\n ],\n },\n {\n name: 'enhanceTaskDetails',\n description: 'Intelligently enhance task details, including description, acceptance criteria, subtasks, and required resources',\n arguments: [\n {\n name: 'taskId',\n description: 'Task ID to be enhanced',\n required: true,\n },\n ],\n },\n {\n name: 'quickCapture',\n description: 'Quickly capture ideas/tasks, auto-categorize and suggest priorities',\n arguments: [\n {\n name: 'idea',\n description: 'Idea or task description to be captured',\n required: true,\n },\n {\n name: 'projectId',\n description: 'Target project ID (optional)',\n required: false,\n },\n ],\n },\n];\n\n/**\n * Intelligently recommend next tasks\n * Analyze all tasks and recommend optimal execution order based on priority, due dates, and dependencies\n */\nexport function getRecommendNextTasksPrompt(projectId?: string, limit?: string): GetPromptResult {\n const context = projectId\n ? `Analyze tasks for project ${projectId}`\n : 'Analyze tasks for all active projects';\n\n const taskLimit = limit ? parseInt(limit, 10) : 3;\n\n return {\n description: 'Intelligent Task Recommendation Assistant',\n messages: [\n {\n role: 'user',\n content: {\n type: 'text',\n text: `${context}, please recommend the ${taskLimit} tasks I should prioritize next.\n\n## Recommendation Logic (sorted by priority):\n\n### 1. Urgent and Important (Critical priority + Near due date)\n- Critical tasks due today or tomorrow\n- Overdue high-priority tasks\n\n### 2. High-Value Tasks (High priority + Clear due date)\n- High priority tasks due this week\n- Critical path tasks blocking other work\n\n### 3. Quick Wins (Medium priority + Short estimated time)\n- Medium tasks completable in 1-2 hours\n- Tasks that can significantly boost project progress\n\n### 4. Planned Work\n- Tasks marked \"in-progress\" but not yet completed\n- Normal priority tasks due soon\n\n## Please perform the following steps:\n\n1. **List all pending tasks** (status = todo or in-progress)\n2. **Filter high-priority tasks**: critical and high\n3. **Check due dates**: Identify tasks due soon or overdue\n4. **Analyze blocking relationships**: Identify tasks blocking others\n5. **Generate recommendation list**: Provide ${taskLimit} tasks to prioritize with reasons\n\n## Output Format:\n\n### Immediate Action (Critical)\n1. **Task Name** (Project Name)\n - Reason: [Why this task is most urgent]\n - Suggested Action: [What specifically to do]\n\n### Today's Focus (High)\n2. **Task Name** (Project Name)\n - Reason: [Why this task is important]\n - Suggested Action: [What specifically to do]\n\n### Follow-up\n3. **Task Name** (Project Name)\n - Reason: [Why this should be done next]\n - Suggested Action: [What specifically to do]\n\nPlease use the list_tasks tool to fetch task data, then provide intelligent recommendations.\n\n## Important Reminder\nWhen you start working on recommended tasks, please:\n1. Use update_task to set task status to in-progress\n2. After completing the task, use update_task to set status to done\n3. If blocked or have issues, document in description and update status to review\n\nKeep task status synchronized with actual progress!`,\n },\n },\n ],\n };\n}\n\n/**\n * Automatic Priority Optimization\n * Automatically adjust priorities based on due dates, project progress, and task dependencies\n */\nexport function getAutoPrioritizePrompt(projectId?: string): GetPromptResult {\n const context = projectId\n ? `Analyze task priorities for project ${projectId}`\n : 'Analyze task priorities for all projects';\n\n return {\n description: 'Intelligent Priority Optimization Assistant',\n messages: [\n {\n role: 'user',\n content: {\n type: 'text',\n text: `${context}, please automatically analyze and suggest priority adjustments.\n\n## Priority Adjustment Rules:\n\n### Conditions to Upgrade to Critical:\n- [ ] Due within 48 hours and not completed\n- [ ] Blocking other high/critical tasks\n- [ ] On project critical path and behind schedule\n- [ ] Has external dependencies (e.g., clients, partners) and time is tight\n\n### Conditions to Upgrade to High:\n- [ ] Due within 1 week\n- [ ] Prerequisite for important milestone\n- [ ] Stuck in \"in-progress\" state for too long (over 3 days)\n- [ ] Affects work of multiple team members\n\n### Conditions to Downgrade to Medium/Low:\n- [ ] Due date is far away (>2 weeks) and no dependencies\n- [ ] \"Nice to have\" feature rather than core functionality\n- [ ] Not needed in current phase, can be postponed\n\n### Other Considerations:\n- **Overall project progress**: Tasks for behind-schedule projects should be prioritized higher\n- **Resource availability**: If resources are tight, focus on highest priority\n- **Risk factors**: High-risk tasks should be addressed earlier\n\n## Please perform the following steps:\n\n1. **Get all tasks**: Use list_tasks to fetch task list\n2. **Analyze each task**:\n - Check gap between due date and current date\n - Identify task dependency relationships\n - Evaluate overall project health\n3. **Generate adjustment suggestions**: List tasks needing priority changes with reasons\n4. **Batch update**: Use batch_update_tasks to execute priority adjustments\n\n## Output Format:\n\n### Suggested Upgrade to Critical\n| Task | Current Priority | Suggested Priority | Reason |\n|------|-----------------|-------------------|--------|\n| XXX | high → critical | Due tomorrow |\n\n### Suggested Upgrade to High\n| Task | Current Priority | Suggested Priority | Reason |\n|------|-----------------|-------------------|--------|\n| XXX | medium → high | Blocking follow-up tasks |\n\n### Suggested Downgrade\n| Task | Current Priority | Suggested Priority | Reason |\n|------|-----------------|-------------------|--------|\n| XXX | high → medium | Can be postponed |\n\n### Keep Unchanged (Priorities are reasonable)\n- List tasks with reasonable priority settings\n\nPlease provide analysis results, then execute batch update after user confirmation.`,\n },\n },\n ],\n };\n}\n\n/**\n * Intelligent Task Detail Enhancement\n * Auto-complete descriptions, acceptance criteria, etc. based on task title and context\n */\nexport function getEnhanceTaskDetailsPrompt(taskId: string): GetPromptResult {\n return {\n description: 'Task Detail Enhancement Assistant',\n messages: [\n {\n role: 'user',\n content: {\n type: 'text',\n text: `Please help me enhance the details for task ${taskId}.\n\n## Enhancement Content:\n\n### 1. Detailed Description\n- Specific content and background of the task\n- Why this task needs to be done\n- Expected business or technical value\n\n### 2. Acceptance Criteria (Definition of Done)\nList clear completion standards, for example:\n- [ ] Feature implemented and locally tested\n- [ ] Code passes Code Review\n- [ ] Related documentation updated\n- [ ] Unit test coverage > 80%\n\n### 3. Technical/Implementation Details\n- Tech stack or modules involved\n- Files that may need modification\n- Potential challenges or considerations\n\n### 4. Related Resources\n- Related documentation links\n- Reference implementations or example code\n- People to consult\n\n### 5. Subtask Suggestions (if needed)\nIf the task is complex, suggest breaking it down:\n- Subtask 1: ...\n- Subtask 2: ...\n- Subtask 3: ...\n\n## Please perform the following steps:\n\n1. **Get task info**: Use get_task to view current task details\n2. **Get project context**: Use get_project to understand project background\n3. **Analyze task type**:\n - If development task: Add technical details, code locations\n - If design task: Add design specs, review criteria\n - If documentation task: Add doc structure, references\n - If testing task: Add test scenarios, coverage scope\n4. **Generate enhancement content**: Use update_task to update task description\n\n## Updated task should include:\n\n\\`\\`\\`\n## Background\n[Task background and purpose]\n\n## Acceptance Criteria\n- [ ] [Standard 1]\n- [ ] [Standard 2]\n- [ ] [Standard 3]\n\n## Technical Details\n- Modules: [module name]\n- Key files: [file path]\n- Notes: [important reminders]\n\n## Related Resources\n- Documentation: [link]\n- References: [link]\n\\`\\`\\`\n\nPlease fetch task info first, then provide detailed enhancement suggestions.`,\n },\n },\n ],\n };\n}\n\n/**\n * Quick Idea Capture\n * Auto-categorize, suggest priorities, recommend projects\n */\nexport function getQuickCapturePrompt(idea: string, projectId?: string): GetPromptResult {\n const projectContext = projectId\n ? `Add to project ${projectId}`\n : 'Auto-select the most suitable project';\n\n return {\n description: 'Quick Capture Assistant',\n messages: [\n {\n role: 'user',\n content: {\n type: 'text',\n text: `I want to quickly capture an idea/task: \"${idea}\"\n\n${projectContext}\n\n## Please help me complete the following steps:\n\n### 1. Task Information Extraction\nExtract from description:\n- **Task Title**: Concise and clear title (start with verb)\n- **Task Description**: Add context and details\n- **Task Type**: bug / feature / refactor / docs / chore\n- **Estimated Priority**: critical / high / medium / low (based on urgency in description)\n\n### 2. Project Recommendation (if no project specified)\nIf user didn't specify a project, please:\n- List all active projects\n- Analyze which project the task content is most relevant to\n- Recommend the most suitable project\n\n### 3. Tag Suggestions\nSuggest relevant tags:\n- Type tags: bug, feature, refactor, docs\n- Priority tags: urgent, important\n- Domain tags: frontend, backend, design, testing (if applicable)\n\n### 4. Generate Task\nUse create_task to create the task\n\n### 5. Status Recommendation\nAfter creating the task, if you start working on it immediately, consider setting the status to in-progress. Use update_task to keep progress updated during work, and mark as done when completed.\n\n## Example:\n\n**Input**: \"User reported login page doesn't display correctly on mobile\"\n\n**Output**:\n- Title: Fix login page mobile responsiveness issue\n- Description: User reported the login page displays abnormally on mobile devices, need to check responsive layout.\n- Type: Bug\n- Priority: High (affects user experience)\n- Suggested Tags: bug, frontend, mobile\n- Recommended Project: [Recommend if there's a web project]\n\n## Current Idea Analysis:\n\nIdea: \"${idea}\"\n\nPlease analyze and generate task suggestions. After user confirmation, execute create_task to create the task.`,\n },\n },\n ],\n };\n}\n\n/**\n * Get Prompt by name\n */\nexport function getPromptByName(name: string, args?: Record<string, string>): GetPromptResult | null {\n switch (name) {\n case 'recommendNextTasks':\n return getRecommendNextTasksPrompt(args?.projectId, args?.limit);\n case 'autoPrioritize':\n return getAutoPrioritizePrompt(args?.projectId);\n case 'enhanceTaskDetails':\n return getEnhanceTaskDetailsPrompt(args?.taskId || '');\n case 'quickCapture':\n return getQuickCapturePrompt(args?.idea || '', args?.projectId);\n default:\n return null;\n }\n}\n\n/**\n * Get all available Prompts\n */\nexport function getAllPrompts(): Prompt[] {\n return projectPrompts;\n}\n"],"mappings":"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","names":["path","path","fs","z","storage","existingTag","writeJsonFile","z","z","z","path","fileURLToPath","__filename","fileURLToPath","__dirname","tagService","url","z","path","fs","z","writeJsonFile","createServer"]}
1
+ {"version":3,"sources":["../node_modules/tsup/assets/esm_shims.js","../src/utils/file-helpers.ts","../src/index.ts","../src/server.ts","../src/tools/index.ts","../src/tools/project-tools.ts","../src/storage/index.ts","../src/utils/path-helpers.ts","../src/tools/task-tools.ts","../src/services/index.ts","../src/services/tag-service.ts","../src/services/task-service.ts","../src/services/types.ts","../src/tools/tag-tools.ts","../src/tools/web-tools.ts","../src/web/server.ts","../src/tools/template-tools.ts","../src/resources/index.ts","../src/resources/project-resources.ts","../src/prompts/index.ts","../src/prompts/project-prompts.ts"],"sourcesContent":["// Shim globals in esm bundle\nimport path from 'node:path'\nimport { fileURLToPath } from 'node:url'\n\nconst getFilename = () => fileURLToPath(import.meta.url)\nconst getDirname = () => path.dirname(getFilename())\n\nexport const __dirname = /* @__PURE__ */ getDirname()\nexport const __filename = /* @__PURE__ */ getFilename()\n","import * as fs from 'fs/promises';\n\n/**\n * Read and parse a JSON file\n * @param filePath - Path to the JSON file\n * @returns Parsed JSON data\n * @throws Error if file cannot be read or parsed\n */\nexport async function readJsonFile<T>(filePath: string): Promise<T> {\n try {\n const content = await fs.readFile(filePath, 'utf-8');\n return JSON.parse(content) as T;\n } catch (error) {\n if (error instanceof Error) {\n throw new Error(`Failed to read JSON file ${filePath}: ${error.message}`);\n }\n throw error;\n }\n}\n\n/**\n * Write data to a JSON file\n * @param filePath - Path to the JSON file\n * @param data - Data to serialize and write\n * @throws Error if file cannot be written\n */\nexport async function writeJsonFile<T>(filePath: string, data: T): Promise<void> {\n try {\n const content = JSON.stringify(data, null, 2);\n await fs.writeFile(filePath, content, 'utf-8');\n } catch (error) {\n if (error instanceof Error) {\n throw new Error(`Failed to write JSON file ${filePath}: ${error.message}`);\n }\n throw error;\n }\n}\n\n/**\n * Ensure a directory exists, creating it recursively if needed\n * @param dirPath - Path to the directory\n * @throws Error if directory cannot be created\n */\nexport async function ensureDir(dirPath: string): Promise<void> {\n try {\n await fs.mkdir(dirPath, { recursive: true });\n } catch (error) {\n if (error instanceof Error) {\n throw new Error(`Failed to create directory ${dirPath}: ${error.message}`);\n }\n throw error;\n }\n}\n","import { startServer } from './server.js';\n\nasync function main() {\n process.on('SIGINT', () => {\n console.error('Received SIGINT, shutting down gracefully...');\n process.exit(0);\n });\n\n process.on('SIGTERM', () => {\n console.error('Received SIGTERM, shutting down gracefully...');\n process.exit(0);\n });\n\n process.on('uncaughtException', (error) => {\n console.error('Uncaught exception:', error);\n process.exit(1);\n });\n\n process.on('unhandledRejection', (reason) => {\n console.error('Unhandled rejection:', reason);\n process.exit(1);\n });\n\n try {\n await startServer();\n } catch (error) {\n console.error('Failed to start server:', error);\n process.exit(1);\n }\n}\n\nmain();\n","import { Server } from \"@modelcontextprotocol/sdk/server/index.js\";\nimport {\n\tCallToolRequestSchema,\n\tListToolsRequestSchema,\n\tListResourcesRequestSchema,\n\tReadResourceRequestSchema,\n\tListPromptsRequestSchema,\n\tGetPromptRequestSchema,\n\ttype CallToolRequest,\n\ttype ListToolsRequest,\n\ttype ListResourcesRequest,\n\ttype ReadResourceRequest,\n\ttype ListPromptsRequest,\n\ttype GetPromptRequest,\n} from \"@modelcontextprotocol/sdk/types.js\";\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport { zodToJsonSchema } from \"zod-to-json-schema\";\n\nimport {\n\tcreateProjectTool,\n\tlistProjectsTool,\n\tgetProjectTool,\n\tupdateProjectTool,\n\tdeleteProjectTool,\n\tcreateTaskTool,\n\tlistTasksTool,\n\tgetTaskTool,\n\tupdateTaskTool,\n\tdeleteTaskTool,\n\tbatchUpdateTasksTool,\n\tcreateTagTool,\n\tlistTagsTool,\n\tupdateTagTool,\n\tdeleteTagTool,\n\tgetTasksByTagTool,\n\topenWebInterfaceTool,\n\tcloseWebInterfaceTool,\n} from \"./tools/index.js\";\nimport { getAllResources, handleResourceRequest } from \"./resources/index.js\";\nimport { getAllPrompts, getPromptByName } from \"./prompts/index.js\";\n\nconst allTools = [\n\tcreateProjectTool,\n\tlistProjectsTool,\n\tgetProjectTool,\n\tupdateProjectTool,\n\tdeleteProjectTool,\n\tcreateTaskTool,\n\tlistTasksTool,\n\tgetTaskTool,\n\tupdateTaskTool,\n\tdeleteTaskTool,\n\tbatchUpdateTasksTool,\n\tcreateTagTool,\n\tlistTagsTool,\n\tupdateTagTool,\n\tdeleteTagTool,\n\tgetTasksByTagTool,\n\topenWebInterfaceTool,\n\tcloseWebInterfaceTool,\n];\n\nconst toolMap = new Map(allTools.map((tool) => [tool.name, tool]));\n\nexport function createServer(): Server {\n\tconst server = new Server(\n\t\t{\n\t\t\tname: \"roadmap-skill\",\n\t\t\tversion: \"0.2.1\",\n\t\t},\n\t\t{\n\t\t\tcapabilities: {\n\t\t\t\ttools: {},\n\t\t\t\tresources: {},\n\t\t\t\tprompts: {},\n\t\t\t},\n\t\t},\n\t);\n\n\tserver.setRequestHandler(\n\t\tListToolsRequestSchema,\n\t\tasync (_request: ListToolsRequest) => {\n\t\t\treturn {\n\t\t\t\ttools: allTools.map((tool) => {\n\t\t\t\t\tconst rawSchema =\n\t\t\t\t\t\t(tool as any).parameters || (tool as any).inputSchema;\n\t\t\t\t\tlet inputSchema: Record<string, unknown>;\n\n\t\t\t\t\tif (!rawSchema) {\n\t\t\t\t\t\tinputSchema = { type: \"object\" };\n\t\t\t\t\t} else if (rawSchema.type === \"object\") {\n\t\t\t\t\t\tinputSchema = rawSchema;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tinputSchema = zodToJsonSchema(rawSchema, {\n\t\t\t\t\t\t\tname: tool.name,\n\t\t\t\t\t\t\t$refStrategy: \"none\",\n\t\t\t\t\t\t}).definitions?.[tool.name] || { type: \"object\" };\n\t\t\t\t\t}\n\n\t\t\t\t\treturn {\n\t\t\t\t\t\tname: tool.name,\n\t\t\t\t\t\tdescription: tool.description,\n\t\t\t\t\t\tinputSchema,\n\t\t\t\t\t};\n\t\t\t\t}),\n\t\t\t};\n\t\t},\n\t);\n\n\tserver.setRequestHandler(\n\t\tCallToolRequestSchema,\n\t\tasync (request: CallToolRequest) => {\n\t\t\tconst { name, arguments: args } = request.params;\n\t\t\tconst tool = toolMap.get(name);\n\n\t\t\tif (!tool) {\n\t\t\t\tthrow new Error(`Unknown tool: ${name}`);\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tconst result = await tool.execute(args as never);\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\t\ttext: JSON.stringify(result, null, 2),\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t};\n\t\t\t} catch (error) {\n\t\t\t\tconst errorMessage =\n\t\t\t\t\terror instanceof Error ? error.message : String(error);\n\t\t\t\tthrow new Error(`Tool execution failed: ${errorMessage}`);\n\t\t\t}\n\t\t},\n\t);\n\n\tserver.setRequestHandler(\n\t\tListResourcesRequestSchema,\n\t\tasync (_request: ListResourcesRequest) => {\n\t\t\tconst resources = getAllResources();\n\t\t\treturn { resources };\n\t\t},\n\t);\n\n\tserver.setRequestHandler(\n\t\tReadResourceRequestSchema,\n\t\tasync (request: ReadResourceRequest) => {\n\t\t\tconst uri = request.params.uri;\n\t\t\tconst resourceContent = await handleResourceRequest(uri);\n\n\t\t\tif (!resourceContent) {\n\t\t\t\tthrow new Error(`Resource not found: ${uri}`);\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\tcontents: [resourceContent],\n\t\t\t};\n\t\t},\n\t);\n\n\tserver.setRequestHandler(\n\t\tListPromptsRequestSchema,\n\t\tasync (_request: ListPromptsRequest) => {\n\t\t\tconst prompts = getAllPrompts();\n\t\t\treturn { prompts };\n\t\t},\n\t);\n\n\tserver.setRequestHandler(\n\t\tGetPromptRequestSchema,\n\t\tasync (request: GetPromptRequest) => {\n\t\t\tconst { name, arguments: args } = request.params;\n\t\t\tconst promptResult = getPromptByName(\n\t\t\t\tname,\n\t\t\t\targs as Record<string, string> | undefined,\n\t\t\t);\n\n\t\t\tif (!promptResult) {\n\t\t\t\tthrow new Error(`Prompt not found: ${name}`);\n\t\t\t}\n\n\t\t\treturn promptResult;\n\t\t},\n\t);\n\n\treturn server;\n}\n\nexport async function startServer(): Promise<void> {\n\tconst server = createServer();\n\tconst transport = new StdioServerTransport();\n\n\tconsole.error(\"Roadmap Skill MCP Server starting...\");\n\n\ttry {\n\t\tawait server.connect(transport);\n\t\tconsole.error(\"Roadmap Skill MCP Server connected and ready\");\n\t} catch (error) {\n\t\tconsole.error(\"Failed to start server:\", error);\n\t\tthrow error;\n\t}\n}\n","export {\n createProjectTool,\n listProjectsTool,\n getProjectTool,\n updateProjectTool,\n deleteProjectTool,\n} from './project-tools.js';\n\nexport {\n createTaskTool,\n listTasksTool,\n getTaskTool,\n updateTaskTool,\n deleteTaskTool,\n batchUpdateTasksTool,\n} from './task-tools.js';\n\nexport {\n createTagTool,\n listTagsTool,\n updateTagTool,\n deleteTagTool,\n getTasksByTagTool,\n} from './tag-tools.js';\n\nexport {\n openWebInterfaceTool,\n closeWebInterfaceTool,\n} from './web-tools.js';\n\nexport {\n listTemplatesTool,\n getTemplateTool,\n applyTemplateTool,\n} from './template-tools.js';\n","import { z } from 'zod';\nimport { storage } from '../storage/index.js';\nimport type { CreateProjectInput, UpdateProjectInput } from '../models/index.js';\n\nconst ProjectTypeEnum = z.enum(['roadmap', 'skill-tree', 'kanban']);\nconst ProjectStatusEnum = z.enum(['active', 'completed', 'archived']);\n\nexport const createProjectTool = {\n name: 'create_project',\n description: 'Create a new project roadmap',\n inputSchema: z.object({\n name: z.string().min(1, 'Project name is required'),\n description: z.string(),\n projectType: ProjectTypeEnum,\n startDate: z.string().regex(/^\\d{4}-\\d{2}-\\d{2}$/, 'Date must be in YYYY-MM-DD format'),\n targetDate: z.string().regex(/^\\d{4}-\\d{2}-\\d{2}$/, 'Date must be in YYYY-MM-DD format'),\n }),\n async execute(input: {\n name: string;\n description: string;\n projectType: 'roadmap' | 'skill-tree' | 'kanban';\n startDate: string;\n targetDate: string;\n }) {\n try {\n const projectInput: CreateProjectInput = {\n name: input.name,\n description: input.description,\n projectType: input.projectType,\n startDate: input.startDate,\n targetDate: input.targetDate,\n };\n\n const projectData = await storage.createProject(projectInput);\n return {\n success: true,\n data: projectData,\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Failed to create project',\n };\n }\n },\n};\n\nexport const listProjectsTool = {\n name: 'list_projects',\n description: 'List all projects with their task and milestone counts',\n inputSchema: z.object({}),\n async execute() {\n try {\n const projects = await storage.listProjects();\n return {\n success: true,\n data: projects,\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Failed to list projects',\n };\n }\n },\n};\n\nexport const getProjectTool = {\n name: 'get_project',\n description: 'Get a project by ID with all its data (tasks, tags, milestones)',\n inputSchema: z.object({\n projectId: z.string().min(1, 'Project ID is required'),\n }),\n async execute(input: { projectId: string }) {\n try {\n const projectData = await storage.readProject(input.projectId);\n if (!projectData) {\n return {\n success: false,\n error: `Project with ID '${input.projectId}' not found`,\n };\n }\n return {\n success: true,\n data: projectData,\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Failed to get project',\n };\n }\n },\n};\n\nexport const updateProjectTool = {\n name: 'update_project',\n description: 'Update an existing project',\n inputSchema: z.object({\n projectId: z.string().min(1, 'Project ID is required'),\n name: z.string().min(1).optional(),\n description: z.string().optional(),\n projectType: ProjectTypeEnum.optional(),\n status: ProjectStatusEnum.optional(),\n startDate: z.string().regex(/^\\d{4}-\\d{2}-\\d{2}$/).optional(),\n targetDate: z.string().regex(/^\\d{4}-\\d{2}-\\d{2}$/).optional(),\n }),\n async execute(input: {\n projectId: string;\n name?: string;\n description?: string;\n projectType?: 'roadmap' | 'skill-tree' | 'kanban';\n status?: 'active' | 'completed' | 'archived';\n startDate?: string;\n targetDate?: string;\n }) {\n try {\n const { projectId, ...updateData } = input;\n\n if (Object.keys(updateData).length === 0) {\n return {\n success: false,\n error: 'At least one field to update is required',\n };\n }\n\n const updateInput: UpdateProjectInput = updateData;\n const projectData = await storage.updateProject(projectId, updateInput);\n\n if (!projectData) {\n return {\n success: false,\n error: `Project with ID '${projectId}' not found`,\n };\n }\n\n return {\n success: true,\n data: projectData,\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Failed to update project',\n };\n }\n },\n};\n\nexport const deleteProjectTool = {\n name: 'delete_project',\n description: 'Delete a project by ID',\n inputSchema: z.object({\n projectId: z.string().min(1, 'Project ID is required'),\n }),\n async execute(input: { projectId: string }) {\n try {\n const deleted = await storage.deleteProject(input.projectId);\n\n if (!deleted) {\n return {\n success: false,\n error: `Project with ID '${input.projectId}' not found`,\n };\n }\n\n return {\n success: true,\n data: { deleted: true },\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Failed to delete project',\n };\n }\n },\n};\n","import * as path from 'path';\nimport type {\n Project,\n ProjectData,\n Task,\n TaskSearchFilters,\n CreateProjectInput,\n UpdateProjectInput,\n} from '../models/index.js';\nimport { getStorageDir } from '../utils/path-helpers.js';\nimport { readJsonFile, writeJsonFile, ensureDir } from '../utils/file-helpers.js';\n\n/**\n * Storage class for managing roadmap-skill projects\n * Projects are stored as individual JSON files in ~/.roadmap-skill/projects/\n */\nexport class ProjectStorage {\n private storageDir: string;\n\n constructor() {\n this.storageDir = getStorageDir();\n }\n\n /**\n * Ensure the storage directory exists\n */\n async ensureDirectory(): Promise<void> {\n await ensureDir(this.storageDir);\n }\n\n /**\n * Get the file path for a project\n * @param projectId - The project ID\n * @returns Full path to the project JSON file\n */\n getFilePath(projectId: string): string {\n return path.join(this.storageDir, `${projectId}.json`);\n }\n\n /**\n * Create a new project\n * @param input - Project creation data\n * @returns The created project data\n */\n async createProject(input: CreateProjectInput): Promise<ProjectData> {\n await this.ensureDirectory();\n\n const now = new Date().toISOString();\n const projectId = `proj_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;\n\n const project: Project = {\n id: projectId,\n name: input.name,\n description: input.description,\n projectType: input.projectType,\n status: 'active',\n startDate: input.startDate,\n targetDate: input.targetDate,\n createdAt: now,\n updatedAt: now,\n };\n\n const projectData: ProjectData = {\n version: 1,\n project,\n milestones: [],\n tasks: [],\n tags: [],\n };\n\n const filePath = this.getFilePath(projectId);\n await writeJsonFile(filePath, projectData);\n\n return projectData;\n }\n\n /**\n * Read a project by ID\n * @param projectId - The project ID\n * @returns The project data or null if not found\n */\n async readProject(projectId: string): Promise<ProjectData | null> {\n try {\n const filePath = this.getFilePath(projectId);\n return await readJsonFile<ProjectData>(filePath);\n } catch (error) {\n if (error instanceof Error && error.message.includes('ENOENT')) {\n return null;\n }\n throw error;\n }\n }\n\n /**\n * Update an existing project\n * @param projectId - The project ID\n * @param input - Project update data\n * @returns The updated project data or null if not found\n */\n async updateProject(\n projectId: string,\n input: UpdateProjectInput\n ): Promise<ProjectData | null> {\n const projectData = await this.readProject(projectId);\n if (!projectData) {\n return null;\n }\n\n const now = new Date().toISOString();\n\n projectData.project = {\n ...projectData.project,\n ...input,\n updatedAt: now,\n };\n\n const filePath = this.getFilePath(projectId);\n await writeJsonFile(filePath, projectData);\n\n return projectData;\n }\n\n /**\n * Delete a project by ID\n * @param projectId - The project ID\n * @returns True if deleted, false if not found\n */\n async deleteProject(projectId: string): Promise<boolean> {\n try {\n const filePath = this.getFilePath(projectId);\n const fs = await import('fs/promises');\n await fs.unlink(filePath);\n return true;\n } catch (error) {\n if (error instanceof Error && error.message.includes('ENOENT')) {\n return false;\n }\n throw error;\n }\n }\n\n /**\n * List all projects sorted by updatedAt (descending)\n * @returns Array of project summaries (project + metadata)\n */\n async listProjects(): Promise<Array<{ project: Project; taskCount: number; milestoneCount: number }>> {\n await this.ensureDirectory();\n\n const fs = await import('fs/promises');\n const files = await fs.readdir(this.storageDir);\n const jsonFiles = files.filter((f) => f.endsWith('.json'));\n\n const projects: Array<{ project: Project; taskCount: number; milestoneCount: number }> = [];\n\n for (const file of jsonFiles) {\n try {\n const filePath = path.join(this.storageDir, file);\n const data = await readJsonFile<ProjectData>(filePath);\n projects.push({\n project: data.project,\n taskCount: data.tasks.length,\n milestoneCount: data.milestones.length,\n });\n } catch {\n // Skip invalid files\n continue;\n }\n }\n\n // Sort by updatedAt descending\n return projects.sort(\n (a, b) => new Date(b.project.updatedAt).getTime() - new Date(a.project.updatedAt).getTime()\n );\n }\n\n /**\n * Search tasks across all projects with filters\n * @param filters - Search filters\n * @returns Array of matching tasks with project context\n */\n async searchTasks(\n filters: TaskSearchFilters\n ): Promise<Array<{ task: Task; project: Project }>> {\n await this.ensureDirectory();\n\n const fs = await import('fs/promises');\n const files = await fs.readdir(this.storageDir);\n const jsonFiles = files.filter((f) => f.endsWith('.json'));\n\n const results: Array<{ task: Task; project: Project }> = [];\n\n for (const file of jsonFiles) {\n try {\n const filePath = path.join(this.storageDir, file);\n const data = await readJsonFile<ProjectData>(filePath);\n\n // Skip if project filter doesn't match\n if (filters.projectId && data.project.id !== filters.projectId) {\n continue;\n }\n\n for (const task of data.tasks) {\n // Apply filters\n if (filters.status && task.status !== filters.status) {\n continue;\n }\n if (filters.priority && task.priority !== filters.priority) {\n continue;\n }\n if (filters.assignee && task.assignee !== filters.assignee) {\n continue;\n }\n if (filters.dueBefore && task.dueDate && task.dueDate > filters.dueBefore) {\n continue;\n }\n if (filters.dueAfter && task.dueDate && task.dueDate < filters.dueAfter) {\n continue;\n }\n if (\n filters.tags &&\n filters.tags.length > 0 &&\n !filters.tags.some((tag) => task.tags.includes(tag))\n ) {\n continue;\n }\n if (\n filters.searchText &&\n !task.title.toLowerCase().includes(filters.searchText.toLowerCase()) &&\n !task.description.toLowerCase().includes(filters.searchText.toLowerCase())\n ) {\n continue;\n }\n\n // Filter completed tasks (done status) when includeCompleted is false\n if (filters.includeCompleted === false && task.status === 'done') {\n continue;\n }\n\n results.push({ task, project: data.project });\n }\n } catch {\n // Skip invalid files\n continue;\n }\n }\n\n return results;\n }\n\n async exportAllData(): Promise<{\n version: number;\n exportedAt: string;\n projects: ProjectData[];\n }> {\n await this.ensureDirectory();\n\n const fs = await import('fs/promises');\n const files = await fs.readdir(this.storageDir);\n const jsonFiles = files.filter((f) => f.endsWith('.json'));\n\n const projects: ProjectData[] = [];\n\n for (const file of jsonFiles) {\n try {\n const filePath = path.join(this.storageDir, file);\n const data = await readJsonFile<ProjectData>(filePath);\n projects.push(data);\n } catch {\n continue;\n }\n }\n\n return {\n version: 1,\n exportedAt: new Date().toISOString(),\n projects,\n };\n }\n\n async importAllData(data: {\n version: number;\n exportedAt: string;\n projects: ProjectData[];\n }): Promise<{\n success: boolean;\n imported: number;\n errors: number;\n errorDetails: string[];\n }> {\n await this.ensureDirectory();\n\n let imported = 0;\n let errors = 0;\n const errorDetails: string[] = [];\n\n if (!data.projects || !Array.isArray(data.projects)) {\n throw new Error('Invalid backup data: projects array is required');\n }\n\n for (const projectData of data.projects) {\n try {\n if (!projectData.project || !projectData.project.id) {\n errors++;\n errorDetails.push('Skipping invalid project: missing project or id');\n continue;\n }\n\n const filePath = this.getFilePath(projectData.project.id);\n await writeJsonFile(filePath, projectData);\n imported++;\n } catch (error) {\n errors++;\n const errorMessage = error instanceof Error ? error.message : String(error);\n errorDetails.push(`Failed to import project ${projectData.project?.id || 'unknown'}: ${errorMessage}`);\n }\n }\n\n return {\n success: errors === 0,\n imported,\n errors,\n errorDetails,\n };\n }\n}\n\nexport const storage = new ProjectStorage();\n","import * as os from 'os';\nimport * as path from 'path';\n\n/**\n * Get the storage directory for roadmap-skill projects\n * Returns: ~/.roadmap-skill/projects\n */\nexport function getStorageDir(): string {\n const homeDir = os.homedir();\n return path.join(homeDir, '.roadmap-skill', 'projects');\n}\n","import { z } from 'zod';\nimport { TaskService } from '../services/index.js';\nimport { storage } from '../storage/index.js';\n\nconst TaskStatusEnum = z.enum(['todo', 'in-progress', 'review', 'done']);\nconst TaskPriorityEnum = z.enum(['low', 'medium', 'high', 'critical']);\n\nexport const createTaskTool = {\n name: 'create_task',\n description: 'Create a new task in a project',\n inputSchema: z.object({\n projectId: z.string().min(1, 'Project ID is required'),\n title: z.string().min(1, 'Task title is required'),\n description: z.string(),\n priority: TaskPriorityEnum.default('medium'),\n tags: z.array(z.string()).default([]),\n dueDate: z.string().regex(/^\\d{4}-\\d{2}-\\d{2}$/).optional(),\n assignee: z.string().optional(),\n }),\n async execute(input: {\n projectId: string;\n title: string;\n description: string;\n priority: 'low' | 'medium' | 'high' | 'critical';\n tags: string[];\n dueDate?: string;\n assignee?: string;\n }) {\n const result = await TaskService.create(input.projectId, {\n title: input.title,\n description: input.description,\n priority: input.priority,\n tags: input.tags,\n dueDate: input.dueDate,\n assignee: input.assignee,\n });\n\n return result;\n },\n};\n\nexport const listTasksTool = {\n name: 'list_tasks',\n description: 'List tasks with optional filters',\n inputSchema: z.object({\n projectId: z.string().optional(),\n status: TaskStatusEnum.optional(),\n priority: TaskPriorityEnum.optional(),\n tags: z.array(z.string()).optional(),\n assignee: z.string().optional(),\n dueBefore: z.string().regex(/^\\d{4}-\\d{2}-\\d{2}$/).optional(),\n dueAfter: z.string().regex(/^\\d{4}-\\d{2}-\\d{2}$/).optional(),\n includeCompleted: z.boolean().optional(),\n }),\n async execute(input: {\n projectId?: string;\n status?: 'todo' | 'in-progress' | 'review' | 'done';\n priority?: 'low' | 'medium' | 'high' | 'critical';\n tags?: string[];\n assignee?: string;\n dueBefore?: string;\n dueAfter?: string;\n includeCompleted?: boolean;\n }) {\n try {\n const results = await storage.searchTasks({\n projectId: input.projectId,\n status: input.status,\n priority: input.priority,\n tags: input.tags,\n assignee: input.assignee,\n dueBefore: input.dueBefore,\n dueAfter: input.dueAfter,\n includeCompleted: input.includeCompleted,\n });\n\n return {\n success: true,\n data: results,\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Failed to list tasks',\n };\n }\n },\n};\n\nexport const getTaskTool = {\n name: 'get_task',\n description: 'Get a specific task by project ID and task ID',\n inputSchema: z.object({\n projectId: z.string().min(1, 'Project ID is required'),\n taskId: z.string().min(1, 'Task ID is required'),\n }),\n async execute(input: { projectId: string; taskId: string }) {\n const result = await TaskService.get(input.projectId, input.taskId);\n return result;\n },\n};\n\nexport const updateTaskTool = {\n name: 'update_task',\n description: 'Update an existing task',\n inputSchema: z.object({\n projectId: z.string().min(1, 'Project ID is required'),\n taskId: z.string().min(1, 'Task ID is required'),\n title: z.string().min(1).optional(),\n description: z.string().optional(),\n status: TaskStatusEnum.optional(),\n priority: TaskPriorityEnum.optional(),\n tags: z.array(z.string()).optional(),\n dueDate: z.string().regex(/^\\d{4}-\\d{2}-\\d{2}$/).optional().nullable(),\n assignee: z.string().optional().nullable(),\n }),\n async execute(input: {\n projectId: string;\n taskId: string;\n title?: string;\n description?: string;\n status?: 'todo' | 'in-progress' | 'review' | 'done';\n priority?: 'low' | 'medium' | 'high' | 'critical';\n tags?: string[];\n dueDate?: string | null;\n assignee?: string | null;\n }) {\n const { projectId, taskId, ...updateData } = input;\n\n const result = await TaskService.update(projectId, taskId, updateData);\n return result;\n },\n};\n\nexport const deleteTaskTool = {\n name: 'delete_task',\n description: 'Delete a task by project ID and task ID',\n inputSchema: z.object({\n projectId: z.string().min(1, 'Project ID is required'),\n taskId: z.string().min(1, 'Task ID is required'),\n }),\n async execute(input: { projectId: string; taskId: string }) {\n const result = await TaskService.delete(input.projectId, input.taskId);\n\n // 保持向后兼容:将 data: undefined 转换为 { deleted: true }\n if (result.success) {\n return {\n success: true,\n data: { deleted: true },\n };\n }\n\n return result;\n },\n};\n\nexport const batchUpdateTasksTool = {\n name: 'batch_update_tasks',\n description: 'Update multiple tasks at once',\n inputSchema: z.object({\n projectId: z.string().min(1, 'Project ID is required'),\n taskIds: z.array(z.string()).min(1, 'At least one task ID is required'),\n status: TaskStatusEnum.optional(),\n priority: TaskPriorityEnum.optional(),\n tags: z.array(z.string()).optional(),\n tagOperation: z.enum(['add', 'remove', 'replace']).default('replace'),\n }),\n async execute(input: {\n projectId: string;\n taskIds: string[];\n status?: 'todo' | 'in-progress' | 'review' | 'done';\n priority?: 'low' | 'medium' | 'high' | 'critical';\n tags?: string[];\n tagOperation?: 'add' | 'remove' | 'replace';\n }) {\n const { projectId, taskIds, tagOperation, ...restData } = input;\n\n const result = await TaskService.batchUpdate(projectId, taskIds, {\n ...restData,\n tagOperation,\n });\n\n return result;\n },\n};\n","export { TagService } from './tag-service.js';\nexport { TaskService } from './task-service.js';\nexport * from './types.js';\n","/**\n * Tag Service - Unified business logic for tag management\n * Extracted from tag-tools.ts for better separation of concerns\n */\n\nimport type { ProjectStorage } from '../storage/index.js';\nimport type { Tag, ProjectData } from '../models/index.js';\nimport type {\n ServiceResult,\n CreateTagData,\n UpdateTagData,\n DeleteTagResult,\n TasksByTagResult,\n} from './types.js';\n\n/**\n * Generate a unique tag ID\n * @returns Tag ID in format tag_${timestamp}_${random}\n */\nfunction generateTagId(): string {\n return `tag_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;\n}\n\n/**\n * TagService - Handles all tag-related business logic\n */\nexport class TagService {\n private storage: ProjectStorage;\n\n constructor(storage: ProjectStorage) {\n this.storage = storage;\n }\n\n /**\n * Create a new tag in a project\n * @param projectId - The project ID\n * @param data - Tag creation data\n * @returns The created tag or error\n */\n async create(projectId: string, data: CreateTagData): Promise<ServiceResult<Tag>> {\n try {\n const projectData = await this.storage.readProject(projectId);\n if (!projectData) {\n return {\n success: false,\n error: `Project with ID '${projectId}' not found`,\n code: 'NOT_FOUND',\n };\n }\n\n // Check for duplicate tag name (case-insensitive)\n const existingTag = projectData.tags.find(\n (t) => t.name.toLowerCase() === data.name.toLowerCase()\n );\n if (existingTag) {\n return {\n success: false,\n error: `Tag with name '${data.name}' already exists in this project`,\n code: 'DUPLICATE_ERROR',\n };\n }\n\n const now = new Date().toISOString();\n const tag: Tag = {\n id: generateTagId(),\n name: data.name,\n color: data.color,\n description: data.description || '',\n createdAt: now,\n };\n\n projectData.tags.push(tag);\n projectData.project.updatedAt = now;\n\n await this.saveProjectData(projectId, projectData);\n\n return {\n success: true,\n data: tag,\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Failed to create tag',\n code: 'INTERNAL_ERROR',\n };\n }\n }\n\n /**\n * List all tags in a project\n * @param projectId - The project ID\n * @returns Array of tags or error\n */\n async list(projectId: string): Promise<ServiceResult<Tag[]>> {\n try {\n const projectData = await this.storage.readProject(projectId);\n if (!projectData) {\n return {\n success: false,\n error: `Project with ID '${projectId}' not found`,\n code: 'NOT_FOUND',\n };\n }\n\n return {\n success: true,\n data: projectData.tags,\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Failed to list tags',\n code: 'INTERNAL_ERROR',\n };\n }\n }\n\n /**\n * Update an existing tag\n * @param projectId - The project ID\n * @param tagId - The tag ID\n * @param data - Tag update data\n * @returns The updated tag or error\n */\n async update(\n projectId: string,\n tagId: string,\n data: UpdateTagData\n ): Promise<ServiceResult<Tag>> {\n try {\n const projectData = await this.storage.readProject(projectId);\n if (!projectData) {\n return {\n success: false,\n error: `Project with ID '${projectId}' not found`,\n code: 'NOT_FOUND',\n };\n }\n\n const tagIndex = projectData.tags.findIndex((t) => t.id === tagId);\n if (tagIndex === -1) {\n return {\n success: false,\n error: `Tag with ID '${tagId}' not found in project '${projectId}'`,\n code: 'NOT_FOUND',\n };\n }\n\n // Check if there is any field to update\n if (Object.keys(data).length === 0) {\n return {\n success: false,\n error: 'At least one field to update is required',\n code: 'VALIDATION_ERROR',\n };\n }\n\n // Check for duplicate name if updating name (case-insensitive)\n if (data.name) {\n const existingTag = projectData.tags.find(\n (t) =>\n t.name.toLowerCase() === data.name!.toLowerCase() && t.id !== tagId\n );\n if (existingTag) {\n return {\n success: false,\n error: `Tag with name '${data.name}' already exists in this project`,\n code: 'DUPLICATE_ERROR',\n };\n }\n }\n\n const now = new Date().toISOString();\n const existingTag = projectData.tags[tagIndex];\n\n const updatedTag: Tag = {\n ...existingTag,\n ...data,\n id: existingTag.id,\n createdAt: existingTag.createdAt,\n };\n\n projectData.tags[tagIndex] = updatedTag;\n projectData.project.updatedAt = now;\n\n await this.saveProjectData(projectId, projectData);\n\n return {\n success: true,\n data: updatedTag,\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Failed to update tag',\n code: 'INTERNAL_ERROR',\n };\n }\n }\n\n /**\n * Delete a tag by ID\n * Also removes the tag from all tasks that use it\n * @param projectId - The project ID\n * @param tagId - The tag ID\n * @returns Delete result with tag info and count of updated tasks\n */\n async delete(projectId: string, tagId: string): Promise<ServiceResult<DeleteTagResult>> {\n try {\n const projectData = await this.storage.readProject(projectId);\n if (!projectData) {\n return {\n success: false,\n error: `Project with ID '${projectId}' not found`,\n code: 'NOT_FOUND',\n };\n }\n\n const tagIndex = projectData.tags.findIndex((t) => t.id === tagId);\n if (tagIndex === -1) {\n return {\n success: false,\n error: `Tag with ID '${tagId}' not found in project '${projectId}'`,\n code: 'NOT_FOUND',\n };\n }\n\n const tag = projectData.tags[tagIndex];\n\n // Remove tag from all tasks that use it\n const now = new Date().toISOString();\n let tasksUpdated = 0;\n for (const task of projectData.tasks) {\n const tagIndexInTask = task.tags.indexOf(tagId);\n if (tagIndexInTask !== -1) {\n task.tags.splice(tagIndexInTask, 1);\n task.updatedAt = now;\n tasksUpdated++;\n }\n }\n\n projectData.tags.splice(tagIndex, 1);\n projectData.project.updatedAt = now;\n\n await this.saveProjectData(projectId, projectData);\n\n return {\n success: true,\n data: {\n deleted: true,\n tag,\n tasksUpdated,\n },\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Failed to delete tag',\n code: 'INTERNAL_ERROR',\n };\n }\n }\n\n /**\n * Get all tasks that have a specific tag by tag name\n * @param projectId - The project ID\n * @param tagName - The tag name\n * @returns Tag info and matching tasks\n */\n async getTasksByTag(\n projectId: string,\n tagName: string\n ): Promise<ServiceResult<TasksByTagResult>> {\n try {\n const projectData = await this.storage.readProject(projectId);\n if (!projectData) {\n return {\n success: false,\n error: `Project with ID '${projectId}' not found`,\n code: 'NOT_FOUND',\n };\n }\n\n // Find tag by name (case-insensitive)\n const tag = projectData.tags.find(\n (t) => t.name.toLowerCase() === tagName.toLowerCase()\n );\n\n if (!tag) {\n return {\n success: false,\n error: `Tag with name '${tagName}' not found in project '${projectId}'`,\n code: 'NOT_FOUND',\n };\n }\n\n // Find all tasks with this tag\n const tasks = projectData.tasks.filter((t) => t.tags.includes(tag.id));\n\n return {\n success: true,\n data: {\n tag,\n tasks,\n count: tasks.length,\n },\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Failed to get tasks by tag',\n code: 'INTERNAL_ERROR',\n };\n }\n }\n\n /**\n * Helper method to save project data\n * @param projectId - The project ID\n * @param projectData - The project data to save\n */\n private async saveProjectData(projectId: string, projectData: ProjectData): Promise<void> {\n const filePath = this.storage.getFilePath(projectId);\n const { writeJsonFile } = await import('../utils/file-helpers.js');\n await writeJsonFile(filePath, projectData);\n }\n}\n","/**\n * Task Service - Unified business logic for task operations\n * Extracted from task-tools.ts to enable reuse across different interfaces\n */\n\nimport type { Task, TaskStatus } from '../models/index.js';\nimport { storage } from '../storage/index.js';\nimport { writeJsonFile } from '../utils/file-helpers.js';\nimport type {\n ServiceResult,\n CreateTaskData,\n UpdateTaskData,\n BatchUpdateTaskData,\n BatchUpdateResult,\n} from './types.js';\n\n/**\n * Generate a unique task ID\n * Format: task_${timestamp}_${random}\n */\nfunction generateTaskId(): string {\n return `task_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;\n}\n\n/**\n * Calculate completedAt based on status change\n * - When status changes to 'done', set completedAt to current time\n * - When status changes from 'done' to other, clear completedAt\n * - Otherwise, preserve existing completedAt\n */\nfunction calculateCompletedAt(\n currentStatus: TaskStatus,\n newStatus: TaskStatus | undefined,\n existingCompletedAt: string | null,\n now: string\n): string | null {\n // Status is not being updated\n if (!newStatus) {\n return existingCompletedAt;\n }\n\n // Status changing to 'done'\n if (newStatus === 'done' && currentStatus !== 'done') {\n return now;\n }\n\n // Status changing from 'done' to something else\n if (currentStatus === 'done' && newStatus !== 'done') {\n return null;\n }\n\n // Status changing but not involving 'done' transition\n return existingCompletedAt;\n}\n\n/**\n * TaskService - Business logic for task operations\n */\nexport const TaskService = {\n /**\n * Create a new task in a project\n * @param projectId - The project ID\n * @param data - Task creation data\n * @returns The created task or error\n */\n async create(projectId: string, data: CreateTaskData): Promise<ServiceResult<Task>> {\n try {\n const projectData = await storage.readProject(projectId);\n if (!projectData) {\n return {\n success: false,\n error: `Project with ID '${projectId}' not found`,\n code: 'NOT_FOUND',\n };\n }\n\n const now = new Date().toISOString();\n const task: Task = {\n id: generateTaskId(),\n projectId,\n title: data.title,\n description: data.description,\n status: 'todo',\n priority: data.priority ?? 'medium',\n tags: data.tags ?? [],\n dueDate: data.dueDate ?? null,\n assignee: data.assignee ?? null,\n createdAt: now,\n updatedAt: now,\n completedAt: null,\n };\n\n projectData.tasks.push(task);\n projectData.project.updatedAt = now;\n\n const filePath = storage.getFilePath(projectId);\n await writeJsonFile(filePath, projectData);\n\n return {\n success: true,\n data: task,\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Failed to create task',\n code: 'INTERNAL_ERROR',\n };\n }\n },\n\n /**\n * Get a specific task by project ID and task ID\n * @param projectId - The project ID\n * @param taskId - The task ID\n * @returns The task or error\n */\n async get(projectId: string, taskId: string): Promise<ServiceResult<Task>> {\n try {\n const projectData = await storage.readProject(projectId);\n if (!projectData) {\n return {\n success: false,\n error: `Project with ID '${projectId}' not found`,\n code: 'NOT_FOUND',\n };\n }\n\n const task = projectData.tasks.find((t) => t.id === taskId);\n if (!task) {\n return {\n success: false,\n error: `Task with ID '${taskId}' not found in project '${projectId}'`,\n code: 'NOT_FOUND',\n };\n }\n\n return {\n success: true,\n data: task,\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Failed to get task',\n code: 'INTERNAL_ERROR',\n };\n }\n },\n\n /**\n * Update an existing task\n * Handles completedAt automatically based on status changes\n * @param projectId - The project ID\n * @param taskId - The task ID\n * @param data - Task update data\n * @returns The updated task or error\n */\n async update(\n projectId: string,\n taskId: string,\n data: UpdateTaskData\n ): Promise<ServiceResult<Task>> {\n try {\n const projectData = await storage.readProject(projectId);\n if (!projectData) {\n return {\n success: false,\n error: `Project with ID '${projectId}' not found`,\n code: 'NOT_FOUND',\n };\n }\n\n const taskIndex = projectData.tasks.findIndex((t) => t.id === taskId);\n if (taskIndex === -1) {\n return {\n success: false,\n error: `Task with ID '${taskId}' not found in project '${projectId}'`,\n code: 'NOT_FOUND',\n };\n }\n\n // Check if there's anything to update\n const updateKeys = Object.keys(data);\n if (updateKeys.length === 0) {\n return {\n success: false,\n error: 'At least one field to update is required',\n code: 'VALIDATION_ERROR',\n };\n }\n\n const now = new Date().toISOString();\n const existingTask = projectData.tasks[taskIndex];\n\n // Calculate completedAt based on status change\n const completedAt = calculateCompletedAt(\n existingTask.status,\n data.status,\n existingTask.completedAt,\n now\n );\n\n const updatedTask: Task = {\n ...existingTask,\n ...data,\n id: existingTask.id,\n projectId: existingTask.projectId,\n createdAt: existingTask.createdAt,\n updatedAt: now,\n completedAt,\n };\n\n projectData.tasks[taskIndex] = updatedTask;\n projectData.project.updatedAt = now;\n\n const filePath = storage.getFilePath(projectId);\n await writeJsonFile(filePath, projectData);\n\n return {\n success: true,\n data: updatedTask,\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Failed to update task',\n code: 'INTERNAL_ERROR',\n };\n }\n },\n\n /**\n * Delete a task by project ID and task ID\n * @param projectId - The project ID\n * @param taskId - The task ID\n * @returns Void or error\n */\n async delete(projectId: string, taskId: string): Promise<ServiceResult<void>> {\n try {\n const projectData = await storage.readProject(projectId);\n if (!projectData) {\n return {\n success: false,\n error: `Project with ID '${projectId}' not found`,\n code: 'NOT_FOUND',\n };\n }\n\n const taskIndex = projectData.tasks.findIndex((t) => t.id === taskId);\n if (taskIndex === -1) {\n return {\n success: false,\n error: `Task with ID '${taskId}' not found in project '${projectId}'`,\n code: 'NOT_FOUND',\n };\n }\n\n const now = new Date().toISOString();\n projectData.tasks.splice(taskIndex, 1);\n projectData.project.updatedAt = now;\n\n const filePath = storage.getFilePath(projectId);\n await writeJsonFile(filePath, projectData);\n\n return {\n success: true,\n data: undefined,\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Failed to delete task',\n code: 'INTERNAL_ERROR',\n };\n }\n },\n\n /**\n * List tasks with optional filters\n * @param filters - Optional filters for the search\n * @returns Array of tasks or error\n */\n async list(filters?: {\n projectId?: string;\n status?: TaskStatus;\n priority?: 'low' | 'medium' | 'high' | 'critical';\n tags?: string[];\n assignee?: string;\n dueBefore?: string;\n dueAfter?: string;\n includeCompleted?: boolean;\n }): Promise<ServiceResult<Task[]>> {\n try {\n const results = await storage.searchTasks({\n projectId: filters?.projectId,\n status: filters?.status,\n priority: filters?.priority,\n tags: filters?.tags,\n assignee: filters?.assignee,\n dueBefore: filters?.dueBefore,\n dueAfter: filters?.dueAfter,\n includeCompleted: filters?.includeCompleted,\n });\n\n // Extract just the tasks from the results\n const tasks = results.map((r) => r.task);\n\n return {\n success: true,\n data: tasks,\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Failed to list tasks',\n code: 'INTERNAL_ERROR',\n };\n }\n },\n\n /**\n * Update multiple tasks at once\n * @param projectId - The project ID\n * @param taskIds - Array of task IDs to update\n * @param data - Batch update data\n * @returns Batch update result or error\n */\n async batchUpdate(\n projectId: string,\n taskIds: string[],\n data: BatchUpdateTaskData\n ): Promise<ServiceResult<BatchUpdateResult>> {\n try {\n const projectData = await storage.readProject(projectId);\n if (!projectData) {\n return {\n success: false,\n error: `Project with ID '${projectId}' not found`,\n code: 'NOT_FOUND',\n };\n }\n\n const now = new Date().toISOString();\n const updatedTasks: Task[] = [];\n const notFoundIds: string[] = [];\n\n for (const taskId of taskIds) {\n const taskIndex = projectData.tasks.findIndex((t) => t.id === taskId);\n if (taskIndex === -1) {\n notFoundIds.push(taskId);\n continue;\n }\n\n const existingTask = projectData.tasks[taskIndex];\n let updatedTags = existingTask.tags;\n\n // Handle tags based on tagOperation\n if (data.tags && data.tags.length > 0) {\n const existingTags = existingTask.tags || [];\n switch (data.tagOperation) {\n case 'add':\n updatedTags = [...new Set([...existingTags, ...data.tags])];\n break;\n case 'remove':\n updatedTags = existingTags.filter((tag) => !data.tags!.includes(tag));\n break;\n case 'replace':\n default:\n updatedTags = data.tags;\n break;\n }\n }\n\n // Calculate completedAt based on status change\n const completedAt = calculateCompletedAt(\n existingTask.status,\n data.status,\n existingTask.completedAt,\n now\n );\n\n const updatedTask: Task = {\n ...existingTask,\n ...(data.status && { status: data.status }),\n ...(data.priority && { priority: data.priority }),\n tags: updatedTags,\n updatedAt: now,\n completedAt,\n };\n\n projectData.tasks[taskIndex] = updatedTask;\n updatedTasks.push(updatedTask);\n }\n\n if (updatedTasks.length === 0) {\n return {\n success: false,\n error: 'No tasks were found to update',\n code: 'NOT_FOUND',\n };\n }\n\n projectData.project.updatedAt = now;\n\n const filePath = storage.getFilePath(projectId);\n await writeJsonFile(filePath, projectData);\n\n return {\n success: true,\n data: {\n updatedTasks,\n updatedCount: updatedTasks.length,\n notFoundIds: notFoundIds.length > 0 ? notFoundIds : undefined,\n },\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Failed to batch update tasks',\n code: 'INTERNAL_ERROR',\n };\n }\n },\n};\n","/**\n * Service layer type definitions\n * Provides unified result types and service interfaces\n */\n\nimport type { ProjectStorage } from '../storage/index.js';\nimport type { Task, Tag, TaskStatus, TaskPriority } from '../models/index.js';\n\n// ============================================================================\n// Result Types\n// ============================================================================\n\n/**\n * Error codes for service operations\n */\nexport type ErrorCode =\n | 'NOT_FOUND'\n | 'VALIDATION_ERROR'\n | 'DUPLICATE_ERROR'\n | 'UNAUTHORIZED'\n | 'INTERNAL_ERROR';\n\n/**\n * Service result type - discriminated union for success/failure\n */\nexport type ServiceResult<T> =\n | { success: true; data: T }\n | { success: false; error: string; code: ErrorCode };\n\n// ============================================================================\n// Task Service Types\n// ============================================================================\n\nexport interface CreateTaskData {\n title: string;\n description: string;\n priority?: TaskPriority;\n tags?: string[];\n dueDate?: string | null;\n assignee?: string | null;\n}\n\nexport interface UpdateTaskData {\n title?: string;\n description?: string;\n status?: TaskStatus;\n priority?: TaskPriority;\n tags?: string[];\n dueDate?: string | null;\n assignee?: string | null;\n}\n\nexport interface BatchUpdateTaskData {\n status?: TaskStatus;\n priority?: TaskPriority;\n tags?: string[];\n tagOperation?: 'add' | 'remove' | 'replace';\n}\n\nexport interface BatchUpdateResult {\n updatedTasks: Task[];\n updatedCount: number;\n notFoundIds?: string[];\n}\n\n// ============================================================================\n// Tag Service Types\n// ============================================================================\n\nexport interface CreateTagData {\n name: string;\n color: string;\n description?: string;\n}\n\nexport interface UpdateTagData {\n name?: string;\n color?: string;\n description?: string;\n}\n\nexport interface DeleteTagResult {\n deleted: true;\n tag: Tag;\n tasksUpdated: number;\n}\n\nexport interface TasksByTagResult {\n tag: Tag;\n tasks: Task[];\n count: number;\n}\n\n// ============================================================================\n// Service Context\n// ============================================================================\n\n/**\n * Service context for dependency injection\n */\nexport interface ServiceContext {\n storage: ProjectStorage;\n}\n\n// ============================================================================\n// Service Interfaces\n// ============================================================================\n\n/**\n * Task Service interface\n */\nexport interface ITaskService {\n create(projectId: string, data: CreateTaskData): Promise<ServiceResult<Task>>;\n get(projectId: string, taskId: string): Promise<ServiceResult<Task>>;\n update(projectId: string, taskId: string, data: UpdateTaskData): Promise<ServiceResult<Task>>;\n delete(projectId: string, taskId: string): Promise<ServiceResult<void>>;\n list(filters?: {\n projectId?: string;\n status?: TaskStatus;\n priority?: TaskPriority;\n tags?: string[];\n assignee?: string;\n dueBefore?: string;\n dueAfter?: string;\n includeCompleted?: boolean;\n }): Promise<ServiceResult<Task[]>>;\n batchUpdate(\n projectId: string,\n taskIds: string[],\n data: BatchUpdateTaskData\n ): Promise<ServiceResult<BatchUpdateResult>>;\n}\n\n/**\n * Tag Service interface\n */\nexport interface ITagService {\n create(projectId: string, data: CreateTagData): Promise<ServiceResult<Tag>>;\n list(projectId: string): Promise<ServiceResult<Tag[]>>;\n update(projectId: string, tagId: string, data: UpdateTagData): Promise<ServiceResult<Tag>>;\n delete(projectId: string, tagId: string): Promise<ServiceResult<DeleteTagResult>>;\n getTasksByTag(projectId: string, tagName: string): Promise<ServiceResult<TasksByTagResult>>;\n}\n","import { z } from 'zod';\nimport { TagService } from '../services/index.js';\nimport { storage } from '../storage/index.js';\n\nconst tagService = new TagService(storage);\n\nexport const createTagTool = {\n name: 'create_tag',\n description: 'Create a new tag in a project',\n inputSchema: z.object({\n projectId: z.string().min(1, 'Project ID is required'),\n name: z.string().min(1, 'Tag name is required'),\n color: z.string().regex(/^#[0-9A-Fa-f]{6}$/, 'Color must be a valid hex code (e.g., #FF5733)'),\n description: z.string().default(''),\n }),\n async execute(input: {\n projectId: string;\n name: string;\n color: string;\n description: string;\n }) {\n const { projectId, ...data } = input;\n const result = await tagService.create(projectId, data);\n\n if (!result.success) {\n return { success: false, error: result.error };\n }\n\n return { success: true, data: result.data };\n },\n};\n\nexport const listTagsTool = {\n name: 'list_tags',\n description: 'List all tags in a project',\n inputSchema: z.object({\n projectId: z.string().min(1, 'Project ID is required'),\n }),\n async execute(input: { projectId: string }) {\n const result = await tagService.list(input.projectId);\n\n if (!result.success) {\n return { success: false, error: result.error };\n }\n\n return { success: true, data: result.data };\n },\n};\n\nexport const updateTagTool = {\n name: 'update_tag',\n description: 'Update an existing tag',\n inputSchema: z.object({\n projectId: z.string().min(1, 'Project ID is required'),\n tagId: z.string().min(1, 'Tag ID is required'),\n name: z.string().min(1).optional(),\n color: z.string().regex(/^#[0-9A-Fa-f]{6}$/).optional(),\n description: z.string().optional(),\n }),\n async execute(input: {\n projectId: string;\n tagId: string;\n name?: string;\n color?: string;\n description?: string;\n }) {\n const { projectId, tagId, ...data } = input;\n const result = await tagService.update(projectId, tagId, data);\n\n if (!result.success) {\n return { success: false, error: result.error };\n }\n\n return { success: true, data: result.data };\n },\n};\n\nexport const deleteTagTool = {\n name: 'delete_tag',\n description: 'Delete a tag by project ID and tag ID',\n inputSchema: z.object({\n projectId: z.string().min(1, 'Project ID is required'),\n tagId: z.string().min(1, 'Tag ID is required'),\n }),\n async execute(input: { projectId: string; tagId: string }) {\n const result = await tagService.delete(input.projectId, input.tagId);\n\n if (!result.success) {\n return { success: false, error: result.error };\n }\n\n return { success: true, data: result.data };\n },\n};\n\nexport const getTasksByTagTool = {\n name: 'get_tasks_by_tag',\n description: 'Get all tasks that have a specific tag',\n inputSchema: z.object({\n projectId: z.string().min(1, 'Project ID is required'),\n tagName: z.string().min(1, 'Tag name is required'),\n }),\n async execute(input: { projectId: string; tagName: string }) {\n const result = await tagService.getTasksByTag(input.projectId, input.tagName);\n\n if (!result.success) {\n return { success: false, error: result.error };\n }\n\n return { success: true, data: result.data };\n },\n};\n","import { createServer } from '../web/server.js';\nimport open from 'open';\nimport type { Server } from 'http';\n\nlet activeServer: Server | null = null;\nlet activePort: number | null = null;\n\nfunction getServerPort(server: Server): number | null {\n const address = server.address();\n\n if (address && typeof address === 'object' && 'port' in address) {\n return typeof address.port === 'number' ? address.port : null;\n }\n\n return null;\n}\n\nasync function closeServer(server: Server): Promise<void> {\n await new Promise<void>((resolve, reject) => {\n server.close((error) => {\n if (error) {\n reject(error);\n return;\n }\n\n resolve();\n });\n\n const forceCloseServer = server as {\n closeAllConnections?: () => void;\n closeIdleConnections?: () => void;\n };\n forceCloseServer.closeIdleConnections?.();\n forceCloseServer.closeAllConnections?.();\n });\n}\n\nasync function openBrowser(url: string): Promise<void> {\n try {\n await open(url);\n } catch (error) {\n console.error('Failed to open browser:', error);\n }\n}\n\nexport const openWebInterfaceTool = {\n name: 'open_web_interface',\n description: 'Open web visualization interface',\n parameters: {\n type: 'object',\n properties: {\n port: {\n type: 'number',\n description: 'Port to run the web interface on (default: 7860)',\n },\n },\n },\n async execute(args: { port?: number }) {\n const requestedPort = args.port || 7860;\n\n if (activeServer) {\n const runningPort = getServerPort(activeServer) ?? activePort;\n\n if (runningPort !== requestedPort) {\n throw new Error(`Web interface is already running on port ${runningPort ?? 'unknown'}. Please close it before opening a different port.`);\n }\n\n const url = `http://localhost:${runningPort ?? requestedPort}`;\n await openBrowser(url);\n\n return { \n message: 'Web interface is already running',\n url,\n };\n }\n\n const url = `http://localhost:${requestedPort}`;\n\n try {\n activeServer = await createServer(requestedPort);\n activePort = requestedPort;\n await openBrowser(url);\n\n return {\n message: 'Web interface started successfully and opened in browser',\n url,\n };\n } catch (error) {\n activeServer = null;\n activePort = null;\n\n const errorMessage = error instanceof Error ? error.message : String(error);\n throw new Error(`Failed to start web interface: ${errorMessage}`);\n }\n }\n};\n\nexport const closeWebInterfaceTool = {\n name: 'close_web_interface',\n description: 'Close web visualization interface',\n parameters: {\n type: 'object',\n properties: {},\n },\n async execute() {\n if (!activeServer) {\n return { message: 'Web interface is not running' };\n }\n\n try {\n await closeServer(activeServer);\n activeServer = null;\n activePort = null;\n return { message: 'Web interface stopped' };\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n throw new Error(`Failed to stop web interface: ${errorMessage}`);\n }\n }\n};\n","import express from 'express';\nimport * as path from 'path';\nimport { fileURLToPath } from 'url';\nimport { createRequire } from 'node:module';\nimport { existsSync } from 'node:fs';\nimport type { Server } from 'http';\nimport { storage } from '../storage/index.js';\nimport { TaskService, TagService } from '../services/index.js';\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = path.dirname(__filename);\n\n/**\n * Resolve the path to the web app static files using multiple fallback strategies.\n * Handles npx execution, global installation, local development, and bundled execution.\n */\nfunction resolveAppPath(): string {\n const candidates: Array<{ path: string; source: string }> = [];\n\n try {\n const require = createRequire(import.meta.url);\n const pkgRoot = path.dirname(require.resolve('../../package.json'));\n candidates.push({ path: path.join(pkgRoot, 'dist/web/app'), source: 'package.json resolve' });\n } catch {\n // Package.json not resolvable\n }\n\n // Primary path when bundled: __dirname = dist/, so dist/web/app is correct\n candidates.push({ path: path.join(__dirname, 'web/app'), source: '__dirname/web/app' });\n candidates.push({ path: path.join(__dirname, 'app'), source: '__dirname relative' });\n candidates.push({ path: path.join(process.cwd(), 'dist/web/app'), source: 'process.cwd()' });\n candidates.push({ path: path.join(__dirname, '../web/app'), source: '__dirname/../web/app' });\n\n for (const { path: candidatePath, source } of candidates) {\n const indexPath = path.join(candidatePath, 'index.html');\n if (existsSync(indexPath)) {\n console.log(`[roadmap-skill] Static files found at: ${candidatePath} (via ${source})`);\n return candidatePath;\n }\n }\n\n const triedPaths = candidates.map(c => ` - ${c.path} (${c.source})`).join('\\n');\n throw new Error(\n `Cannot find web app static files.\\n\\n` +\n `Tried:\\n${triedPaths}\\n\\n` +\n `Ensure the package is installed correctly and web assets exist.`\n );\n}\n\nconst tagService = new TagService(storage);\n\nexport function createServer(port: number = 7860): Promise<Server> {\n return new Promise((resolve, reject) => {\n const app = express();\n\n app.use(express.json());\n\n app.get('/api/projects', async (_req, res) => {\n try {\n const projects = await storage.listProjects();\n res.json(projects);\n } catch (error) {\n res.status(500).json({ error: (error as Error).message });\n }\n });\n\n app.get('/api/projects/:id', async (req, res) => {\n try {\n const project = await storage.readProject(req.params.id);\n if (!project) {\n res.status(404).json({ error: 'Project not found' });\n return;\n }\n res.json(project);\n } catch (error) {\n res.status(500).json({ error: (error as Error).message });\n }\n });\n\n app.get('/api/tasks', async (req, res) => {\n try {\n const filters: Record<string, unknown> = { ...req.query };\n\n // Convert includeCompleted from string to boolean\n if (filters.includeCompleted !== undefined) {\n filters.includeCompleted = filters.includeCompleted === 'true';\n }\n\n const tasks = await storage.searchTasks(filters as any);\n res.json(tasks);\n } catch (error) {\n res.status(500).json({ error: (error as Error).message });\n }\n });\n\n app.post('/api/projects', async (req, res) => {\n try {\n const project = await storage.createProject(req.body);\n res.json({ success: true, data: project });\n } catch (error) {\n res.status(500).json({ error: (error as Error).message });\n }\n });\n\n app.put('/api/projects', async (req, res) => {\n try {\n const { projectId, ...updateData } = req.body;\n const project = await storage.updateProject(projectId, updateData);\n res.json({ success: true, data: project });\n } catch (error) {\n res.status(500).json({ error: (error as Error).message });\n }\n });\n\n app.delete('/api/projects', async (req, res) => {\n try {\n const { projectId } = req.query;\n await storage.deleteProject(projectId as string);\n res.json({ success: true });\n } catch (error) {\n res.status(500).json({ error: (error as Error).message });\n }\n });\n\n app.post('/api/tasks', async (req, res) => {\n try {\n const { projectId, ...taskData } = req.body;\n const result = await TaskService.create(projectId, taskData);\n if (!result.success) {\n const statusCode = result.code === 'NOT_FOUND' ? 404 : 400;\n res.status(statusCode).json({ error: result.error });\n return;\n }\n res.json({ success: true, data: result.data });\n } catch (error) {\n res.status(500).json({ error: (error as Error).message });\n }\n });\n\n app.put('/api/tasks', async (req, res) => {\n try {\n const { projectId, taskId, ...updateData } = req.body;\n const result = await TaskService.update(projectId, taskId, updateData);\n if (!result.success) {\n const statusCode = result.code === 'NOT_FOUND' ? 404 : 400;\n res.status(statusCode).json({ error: result.error });\n return;\n }\n res.json({ success: true, data: result.data });\n } catch (error) {\n res.status(500).json({ error: (error as Error).message });\n }\n });\n\n app.delete('/api/tasks', async (req, res) => {\n try {\n const { projectId, taskId } = req.query;\n const result = await TaskService.delete(projectId as string, taskId as string);\n if (!result.success) {\n const statusCode = result.code === 'NOT_FOUND' ? 404 : 400;\n res.status(statusCode).json({ error: result.error });\n return;\n }\n res.json({ success: true });\n } catch (error) {\n res.status(500).json({ error: (error as Error).message });\n }\n });\n\n app.post('/api/projects/:projectId/tags', async (req, res) => {\n try {\n const { projectId } = req.params;\n const result = await tagService.create(projectId, req.body);\n if (!result.success) {\n const statusCode = result.code === 'NOT_FOUND' ? 404 : 400;\n res.status(statusCode).json({ error: result.error });\n return;\n }\n res.json({ success: true, data: result.data });\n } catch (error) {\n res.status(500).json({ error: (error as Error).message });\n }\n });\n\n app.get('/api/projects/:projectId/tags', async (req, res) => {\n try {\n const { projectId } = req.params;\n const result = await tagService.list(projectId);\n if (!result.success) {\n const statusCode = result.code === 'NOT_FOUND' ? 404 : 400;\n res.status(statusCode).json({ error: result.error });\n return;\n }\n res.json({ success: true, data: result.data });\n } catch (error) {\n res.status(500).json({ error: (error as Error).message });\n }\n });\n\n app.put('/api/projects/:projectId/tags/:tagId', async (req, res) => {\n try {\n const { projectId, tagId } = req.params;\n const result = await tagService.update(projectId, tagId, req.body);\n if (!result.success) {\n const statusCode = result.code === 'NOT_FOUND' ? 404 : 400;\n res.status(statusCode).json({ error: result.error });\n return;\n }\n res.json({ success: true, data: result.data });\n } catch (error) {\n res.status(500).json({ error: (error as Error).message });\n }\n });\n\n app.delete('/api/projects/:projectId/tags/:tagId', async (req, res) => {\n try {\n const { projectId, tagId } = req.params;\n const result = await tagService.delete(projectId, tagId);\n if (!result.success) {\n const statusCode = result.code === 'NOT_FOUND' ? 404 : 400;\n res.status(statusCode).json({ error: result.error });\n return;\n }\n res.json({ success: true, data: result.data });\n } catch (error) {\n res.status(500).json({ error: (error as Error).message });\n }\n });\n\n app.get('/api/backup', async (_req, res) => {\n try {\n const backup = await storage.exportAllData();\n const filename = `roadmap-skill-backup-${new Date().toISOString().split('T')[0]}.json`;\n res.setHeader('Content-Type', 'application/json');\n res.setHeader('Content-Disposition', `attachment; filename=\"${filename}\"`);\n res.json(backup);\n } catch (error) {\n res.status(500).json({ error: (error as Error).message });\n }\n });\n\n app.post('/api/backup', async (req, res) => {\n try {\n const result = await storage.importAllData(req.body);\n res.json(result);\n } catch (error) {\n res.status(400).json({\n success: false,\n error: (error as Error).message,\n });\n }\n });\n\n const distPath = resolveAppPath();\n app.use(express.static(distPath));\n\n app.get('*', (req, res) => {\n if (req.path.startsWith('/api')) {\n res.status(404).json({ error: 'API not found' });\n return;\n }\n res.sendFile(path.join(distPath, 'index.html'));\n });\n\n const server = app.listen(port, '127.0.0.1');\n\n server.once('listening', () => {\n console.log(`Web interface server running at http://localhost:${port}`);\n resolve(server);\n });\n\n server.once('error', (error: NodeJS.ErrnoException) => {\n if (error.code === 'EADDRINUSE') {\n reject(new Error(`Port ${port} is already in use`));\n return;\n }\n\n reject(error);\n });\n });\n}\n\n// Start server if run directly\nif (process.argv[1]?.endsWith('server.js')) {\n const port = parseInt(process.argv[2] || '7860', 10);\n createServer(port).catch(err => {\n console.error('Failed to start server:', err);\n process.exit(1);\n });\n}\n","import { z } from 'zod';\nimport * as path from 'path';\nimport * as fs from 'fs/promises';\nimport { storage } from '../storage/index.js';\nimport type { CreateProjectInput, Tag, Task } from '../models/index.js';\n\nconst TEMPLATES_DIR = path.join(process.cwd(), 'templates');\n\ninterface TemplateMetadata {\n name: string;\n description: string;\n projectType: string;\n tasks: Array<{\n title: string;\n description: string;\n priority: 'low' | 'medium' | 'high' | 'critical';\n tags: string[];\n estimatedHours?: number;\n }>;\n tags: Array<{\n name: string;\n color: string;\n }>;\n}\n\nasync function getTemplateFiles(): Promise<string[]> {\n try {\n const files = await fs.readdir(TEMPLATES_DIR);\n return files.filter((f) => f.endsWith('.json'));\n } catch {\n return [];\n }\n}\n\nasync function loadTemplate(templateName: string): Promise<TemplateMetadata | null> {\n try {\n const fileName = templateName.endsWith('.json') ? templateName : `${templateName}.json`;\n const filePath = path.join(TEMPLATES_DIR, fileName);\n const content = await fs.readFile(filePath, 'utf-8');\n return JSON.parse(content) as TemplateMetadata;\n } catch {\n return null;\n }\n}\n\nfunction generateId(prefix: string): string {\n return `${prefix}_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;\n}\n\nexport const listTemplatesTool = {\n name: 'list_templates',\n description: 'List all available project templates',\n inputSchema: z.object({}),\n async execute() {\n try {\n const templateFiles = await getTemplateFiles();\n const templates = [];\n\n for (const file of templateFiles) {\n const template = await loadTemplate(file);\n if (template) {\n templates.push({\n name: file.replace('.json', ''),\n displayName: template.name,\n description: template.description,\n projectType: template.projectType,\n taskCount: template.tasks.length,\n tagCount: template.tags.length,\n });\n }\n }\n\n return {\n success: true,\n data: templates,\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Failed to list templates',\n };\n }\n },\n};\n\nexport const getTemplateTool = {\n name: 'get_template',\n description: 'Get detailed information about a specific template',\n inputSchema: z.object({\n templateName: z.string().min(1, 'Template name is required'),\n }),\n async execute(input: { templateName: string }) {\n try {\n const template = await loadTemplate(input.templateName);\n\n if (!template) {\n return {\n success: false,\n error: `Template '${input.templateName}' not found`,\n };\n }\n\n return {\n success: true,\n data: {\n name: template.name,\n description: template.description,\n projectType: template.projectType,\n tasks: template.tasks.map((t) => ({\n title: t.title,\n description: t.description,\n priority: t.priority,\n tags: t.tags,\n estimatedHours: t.estimatedHours,\n })),\n tags: template.tags,\n },\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Failed to get template',\n };\n }\n },\n};\n\nexport const applyTemplateTool = {\n name: 'apply_template',\n description: 'Create a new project from a template',\n inputSchema: z.object({\n templateName: z.string().min(1, 'Template name is required'),\n projectName: z.string().min(1, 'Project name is required'),\n description: z.string().default(''),\n startDate: z.string().regex(/^\\d{4}-\\d{2}-\\d{2}$/, 'Date must be in YYYY-MM-DD format').optional(),\n targetDate: z.string().regex(/^\\d{4}-\\d{2}-\\d{2}$/, 'Date must be in YYYY-MM-DD format').optional(),\n }),\n async execute(input: {\n templateName: string;\n projectName: string;\n description: string;\n startDate?: string;\n targetDate?: string;\n }) {\n try {\n const template = await loadTemplate(input.templateName);\n\n if (!template) {\n return {\n success: false,\n error: `Template '${input.templateName}' not found`,\n };\n }\n\n const projectInput: CreateProjectInput = {\n name: input.projectName,\n description: input.description || template.description,\n projectType: template.projectType as 'roadmap' | 'skill-tree' | 'kanban',\n startDate: input.startDate || new Date().toISOString().split('T')[0],\n targetDate: input.targetDate || new Date().toISOString().split('T')[0],\n };\n\n const projectData = await storage.createProject(projectInput);\n const projectId = projectData.project.id;\n const now = new Date().toISOString();\n\n const tagNameToId: Map<string, string> = new Map();\n const tags: Tag[] = [];\n\n for (const templateTag of template.tags) {\n const tag: Tag = {\n id: generateId('tag'),\n name: templateTag.name,\n color: templateTag.color,\n description: '',\n createdAt: now,\n };\n tags.push(tag);\n tagNameToId.set(templateTag.name, tag.id);\n }\n\n const tasks: Task[] = [];\n\n for (const templateTask of template.tasks) {\n const taskTagIds = templateTask.tags\n .map((tagName) => tagNameToId.get(tagName))\n .filter((id): id is string => id !== undefined);\n\n const task: Task = {\n id: generateId('task'),\n projectId,\n title: templateTask.title,\n description: templateTask.description,\n status: 'todo',\n priority: templateTask.priority,\n tags: taskTagIds,\n dueDate: null,\n assignee: null,\n createdAt: now,\n updatedAt: now,\n completedAt: null,\n };\n tasks.push(task);\n }\n\n projectData.tags = tags;\n projectData.tasks = tasks;\n projectData.project.updatedAt = now;\n\n const filePath = storage.getFilePath(projectId);\n const { writeJsonFile } = await import('../utils/file-helpers.js');\n await writeJsonFile(filePath, projectData);\n\n return {\n success: true,\n data: {\n project: projectData.project,\n taskCount: tasks.length,\n tagCount: tags.length,\n tasksCreated: tasks.map((t) => ({\n id: t.id,\n title: t.title,\n priority: t.priority,\n })),\n tagsCreated: tags.map((t) => ({\n id: t.id,\n name: t.name,\n color: t.color,\n })),\n },\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Failed to apply template',\n };\n }\n },\n};\n","export {\n projectResources,\n handleResourceRequest,\n getAllResources,\n} from './project-resources.js';\n","import type {\n Resource,\n TextResourceContents,\n} from '@modelcontextprotocol/sdk/types.js';\nimport { storage } from '../storage/index.js';\n\n/**\n * Resource definitions for roadmap projects\n */\nexport const projectResources: Resource[] = [\n {\n uri: 'roadmap://projects',\n name: 'Project List',\n mimeType: 'application/json',\n description: 'Returns a list of all projects with basic metadata',\n },\n {\n uri: 'roadmap://project/{projectId}',\n name: 'Project Details',\n mimeType: 'application/json',\n description: 'Returns detailed information about a specific project including tasks, milestones, and tags',\n },\n {\n uri: 'roadmap://project/{projectId}/tasks',\n name: 'Project Tasks',\n mimeType: 'application/json',\n description: 'Returns all tasks for a specific project',\n },\n {\n uri: 'roadmap://project/{projectId}/progress',\n name: 'Project Progress',\n mimeType: 'application/json',\n description: 'Returns progress statistics for a specific project',\n },\n];\n\n/**\n * Resource URI patterns for matching\n */\nconst RESOURCE_PATTERNS = {\n projectList: /^roadmap:\\/\\/projects$/,\n projectDetails: /^roadmap:\\/\\/project\\/([^/]+)$/,\n projectTasks: /^roadmap:\\/\\/project\\/([^/]+)\\/tasks$/,\n projectProgress: /^roadmap:\\/\\/project\\/([^/]+)\\/progress$/,\n};\n\n/**\n * Handle resource requests\n * @param uri - The resource URI\n * @returns Resource contents or null if not found\n */\nexport async function handleResourceRequest(\n uri: string\n): Promise<TextResourceContents | null> {\n // Project List: roadmap://projects\n if (RESOURCE_PATTERNS.projectList.test(uri)) {\n return await getProjectListResource(uri);\n }\n\n // Project Details: roadmap://project/{projectId}\n const projectDetailsMatch = uri.match(RESOURCE_PATTERNS.projectDetails);\n if (projectDetailsMatch && !uri.includes('/tasks') && !uri.includes('/progress')) {\n const projectId = projectDetailsMatch[1];\n return await getProjectDetailsResource(uri, projectId);\n }\n\n // Project Tasks: roadmap://project/{projectId}/tasks\n const projectTasksMatch = uri.match(RESOURCE_PATTERNS.projectTasks);\n if (projectTasksMatch) {\n const projectId = projectTasksMatch[1];\n return await getProjectTasksResource(uri, projectId);\n }\n\n // Project Progress: roadmap://project/{projectId}/progress\n const projectProgressMatch = uri.match(RESOURCE_PATTERNS.projectProgress);\n if (projectProgressMatch) {\n const projectId = projectProgressMatch[1];\n return await getProjectProgressResource(uri, projectId);\n }\n\n return null;\n}\n\n/**\n * Get project list resource\n */\nasync function getProjectListResource(uri: string): Promise<TextResourceContents> {\n const projects = await storage.listProjects();\n\n const data = {\n projects: projects.map(p => ({\n id: p.project.id,\n name: p.project.name,\n description: p.project.description,\n status: p.project.status,\n projectType: p.project.projectType,\n taskCount: p.taskCount,\n milestoneCount: p.milestoneCount,\n updatedAt: p.project.updatedAt,\n })),\n totalCount: projects.length,\n };\n\n return {\n uri,\n mimeType: 'application/json',\n text: JSON.stringify(data, null, 2),\n };\n}\n\n/**\n * Get project details resource\n */\nasync function getProjectDetailsResource(\n uri: string,\n projectId: string\n): Promise<TextResourceContents | null> {\n const projectData = await storage.readProject(projectId);\n\n if (!projectData) {\n return null;\n }\n\n const data = {\n project: projectData.project,\n milestones: projectData.milestones,\n tasks: projectData.tasks,\n tags: projectData.tags,\n stats: {\n taskCount: projectData.tasks.length,\n milestoneCount: projectData.milestones.length,\n tagCount: projectData.tags.length,\n completedTasks: projectData.tasks.filter(t => t.status === 'done').length,\n inProgressTasks: projectData.tasks.filter(t => t.status === 'in-progress').length,\n },\n };\n\n return {\n uri,\n mimeType: 'application/json',\n text: JSON.stringify(data, null, 2),\n };\n}\n\n/**\n * Get project tasks resource\n */\nasync function getProjectTasksResource(\n uri: string,\n projectId: string\n): Promise<TextResourceContents | null> {\n const projectData = await storage.readProject(projectId);\n\n if (!projectData) {\n return null;\n }\n\n const tasksByStatus = {\n todo: projectData.tasks.filter(t => t.status === 'todo'),\n inProgress: projectData.tasks.filter(t => t.status === 'in-progress'),\n review: projectData.tasks.filter(t => t.status === 'review'),\n done: projectData.tasks.filter(t => t.status === 'done'),\n };\n\n const data = {\n projectId,\n projectName: projectData.project.name,\n tasks: projectData.tasks,\n tasksByStatus,\n summary: {\n total: projectData.tasks.length,\n todo: tasksByStatus.todo.length,\n inProgress: tasksByStatus.inProgress.length,\n review: tasksByStatus.review.length,\n done: tasksByStatus.done.length,\n },\n };\n\n return {\n uri,\n mimeType: 'application/json',\n text: JSON.stringify(data, null, 2),\n };\n}\n\n/**\n * Get project progress resource\n */\nasync function getProjectProgressResource(\n uri: string,\n projectId: string\n): Promise<TextResourceContents | null> {\n const projectData = await storage.readProject(projectId);\n\n if (!projectData) {\n return null;\n }\n\n const tasks = projectData.tasks;\n const totalTasks = tasks.length;\n const completedTasks = tasks.filter(t => t.status === 'done').length;\n const inProgressTasks = tasks.filter(t => t.status === 'in-progress').length;\n const reviewTasks = tasks.filter(t => t.status === 'review').length;\n const todoTasks = tasks.filter(t => t.status === 'todo').length;\n\n const completionPercentage = totalTasks > 0 ? Math.round((completedTasks / totalTasks) * 100) : 0;\n\n const milestones = projectData.milestones;\n const completedMilestones = milestones.filter(m => m.completedAt !== null).length;\n const milestoneProgress = milestones.length > 0 ? Math.round((completedMilestones / milestones.length) * 100) : 0;\n\n // Calculate overdue tasks\n const now = new Date().toISOString();\n const overdueTasks = tasks.filter(t => \n t.dueDate && \n t.dueDate < now && \n t.status !== 'done'\n );\n\n // Priority breakdown\n const priorityBreakdown = {\n critical: tasks.filter(t => t.priority === 'critical').length,\n high: tasks.filter(t => t.priority === 'high').length,\n medium: tasks.filter(t => t.priority === 'medium').length,\n low: tasks.filter(t => t.priority === 'low').length,\n };\n\n const data = {\n projectId,\n projectName: projectData.project.name,\n projectStatus: projectData.project.status,\n dates: {\n startDate: projectData.project.startDate,\n targetDate: projectData.project.targetDate,\n daysRemaining: calculateDaysRemaining(projectData.project.targetDate),\n },\n taskProgress: {\n total: totalTasks,\n completed: completedTasks,\n inProgress: inProgressTasks,\n review: reviewTasks,\n todo: todoTasks,\n completionPercentage,\n },\n milestoneProgress: {\n total: milestones.length,\n completed: completedMilestones,\n percentage: milestoneProgress,\n },\n overdueTasks: {\n count: overdueTasks.length,\n tasks: overdueTasks.map(t => ({\n id: t.id,\n title: t.title,\n dueDate: t.dueDate,\n status: t.status,\n })),\n },\n priorityBreakdown,\n lastUpdated: projectData.project.updatedAt,\n };\n\n return {\n uri,\n mimeType: 'application/json',\n text: JSON.stringify(data, null, 2),\n };\n}\n\n/**\n * Calculate days remaining until target date\n */\nfunction calculateDaysRemaining(targetDate: string): number | null {\n const target = new Date(targetDate);\n const now = new Date();\n const diffTime = target.getTime() - now.getTime();\n const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24));\n return diffDays > 0 ? diffDays : null;\n}\n\n/**\n * Get all available resources\n */\nexport function getAllResources(): Resource[] {\n return projectResources;\n}\n","export {\n projectPrompts,\n getRecommendNextTasksPrompt,\n getAutoPrioritizePrompt,\n getEnhanceTaskDetailsPrompt,\n getQuickCapturePrompt,\n getPromptByName,\n getAllPrompts,\n} from './project-prompts.js';\n","import type {\n Prompt,\n GetPromptResult,\n} from '@modelcontextprotocol/sdk/types.js';\n\n/**\n * Curated Prompts - Help Agents use Roadmap Skill more intelligently\n */\nexport const projectPrompts: Prompt[] = [\n {\n name: 'recommendNextTasks',\n description: 'Intelligently recommend the next priority tasks based on urgency, due dates, and project status',\n arguments: [\n {\n name: 'projectId',\n description: 'Specific project ID (optional; if not provided, analyze all projects)',\n required: false,\n },\n {\n name: 'limit',\n description: 'Number of tasks to recommend (default: 3)',\n required: false,\n },\n ],\n },\n {\n name: 'autoPrioritize',\n description: 'Automatically analyze tasks and intelligently adjust priorities, considering due dates, dependencies, and project importance',\n arguments: [\n {\n name: 'projectId',\n description: 'Specific project ID (optional; if not provided, analyze all projects)',\n required: false,\n },\n ],\n },\n {\n name: 'enhanceTaskDetails',\n description: 'Intelligently enhance task details, including description, acceptance criteria, subtasks, and required resources',\n arguments: [\n {\n name: 'taskId',\n description: 'Task ID to be enhanced',\n required: true,\n },\n ],\n },\n {\n name: 'quickCapture',\n description: 'Quickly capture ideas/tasks, auto-categorize and suggest priorities',\n arguments: [\n {\n name: 'idea',\n description: 'Idea or task description to be captured',\n required: true,\n },\n {\n name: 'projectId',\n description: 'Target project ID (optional)',\n required: false,\n },\n ],\n },\n];\n\n/**\n * Intelligently recommend next tasks\n * Analyze all tasks and recommend optimal execution order based on priority, due dates, and dependencies\n */\nexport function getRecommendNextTasksPrompt(projectId?: string, limit?: string): GetPromptResult {\n const context = projectId\n ? `Analyze tasks for project ${projectId}`\n : 'Analyze tasks for all active projects';\n\n const taskLimit = limit ? parseInt(limit, 10) : 3;\n\n return {\n description: 'Intelligent Task Recommendation Assistant',\n messages: [\n {\n role: 'user',\n content: {\n type: 'text',\n text: `${context}, please recommend the ${taskLimit} tasks I should prioritize next.\n\n## Recommendation Logic (sorted by priority):\n\n### 1. Urgent and Important (Critical priority + Near due date)\n- Critical tasks due today or tomorrow\n- Overdue high-priority tasks\n\n### 2. High-Value Tasks (High priority + Clear due date)\n- High priority tasks due this week\n- Critical path tasks blocking other work\n\n### 3. Quick Wins (Medium priority + Short estimated time)\n- Medium tasks completable in 1-2 hours\n- Tasks that can significantly boost project progress\n\n### 4. Planned Work\n- Tasks marked \"in-progress\" but not yet completed\n- Normal priority tasks due soon\n\n## Please perform the following steps:\n\n1. **List all pending tasks** (status = todo or in-progress)\n2. **Filter high-priority tasks**: critical and high\n3. **Check due dates**: Identify tasks due soon or overdue\n4. **Analyze blocking relationships**: Identify tasks blocking others\n5. **Generate recommendation list**: Provide ${taskLimit} tasks to prioritize with reasons\n\n## Output Format:\n\n### Immediate Action (Critical)\n1. **Task Name** (Project Name)\n - Reason: [Why this task is most urgent]\n - Suggested Action: [What specifically to do]\n\n### Today's Focus (High)\n2. **Task Name** (Project Name)\n - Reason: [Why this task is important]\n - Suggested Action: [What specifically to do]\n\n### Follow-up\n3. **Task Name** (Project Name)\n - Reason: [Why this should be done next]\n - Suggested Action: [What specifically to do]\n\nPlease use the list_tasks tool to fetch task data, then provide intelligent recommendations.\n\n## Important Reminder\nWhen you start working on recommended tasks, please:\n1. Use update_task to set task status to in-progress\n2. After completing the task, use update_task to set status to done\n3. If blocked or have issues, document in description and update status to review\n\nKeep task status synchronized with actual progress!`,\n },\n },\n ],\n };\n}\n\n/**\n * Automatic Priority Optimization\n * Automatically adjust priorities based on due dates, project progress, and task dependencies\n */\nexport function getAutoPrioritizePrompt(projectId?: string): GetPromptResult {\n const context = projectId\n ? `Analyze task priorities for project ${projectId}`\n : 'Analyze task priorities for all projects';\n\n return {\n description: 'Intelligent Priority Optimization Assistant',\n messages: [\n {\n role: 'user',\n content: {\n type: 'text',\n text: `${context}, please automatically analyze and suggest priority adjustments.\n\n## Priority Adjustment Rules:\n\n### Conditions to Upgrade to Critical:\n- [ ] Due within 48 hours and not completed\n- [ ] Blocking other high/critical tasks\n- [ ] On project critical path and behind schedule\n- [ ] Has external dependencies (e.g., clients, partners) and time is tight\n\n### Conditions to Upgrade to High:\n- [ ] Due within 1 week\n- [ ] Prerequisite for important milestone\n- [ ] Stuck in \"in-progress\" state for too long (over 3 days)\n- [ ] Affects work of multiple team members\n\n### Conditions to Downgrade to Medium/Low:\n- [ ] Due date is far away (>2 weeks) and no dependencies\n- [ ] \"Nice to have\" feature rather than core functionality\n- [ ] Not needed in current phase, can be postponed\n\n### Other Considerations:\n- **Overall project progress**: Tasks for behind-schedule projects should be prioritized higher\n- **Resource availability**: If resources are tight, focus on highest priority\n- **Risk factors**: High-risk tasks should be addressed earlier\n\n## Please perform the following steps:\n\n1. **Get all tasks**: Use list_tasks to fetch task list\n2. **Analyze each task**:\n - Check gap between due date and current date\n - Identify task dependency relationships\n - Evaluate overall project health\n3. **Generate adjustment suggestions**: List tasks needing priority changes with reasons\n4. **Batch update**: Use batch_update_tasks to execute priority adjustments\n\n## Output Format:\n\n### Suggested Upgrade to Critical\n| Task | Current Priority | Suggested Priority | Reason |\n|------|-----------------|-------------------|--------|\n| XXX | high → critical | Due tomorrow |\n\n### Suggested Upgrade to High\n| Task | Current Priority | Suggested Priority | Reason |\n|------|-----------------|-------------------|--------|\n| XXX | medium → high | Blocking follow-up tasks |\n\n### Suggested Downgrade\n| Task | Current Priority | Suggested Priority | Reason |\n|------|-----------------|-------------------|--------|\n| XXX | high → medium | Can be postponed |\n\n### Keep Unchanged (Priorities are reasonable)\n- List tasks with reasonable priority settings\n\nPlease provide analysis results, then execute batch update after user confirmation.`,\n },\n },\n ],\n };\n}\n\n/**\n * Intelligent Task Detail Enhancement\n * Auto-complete descriptions, acceptance criteria, etc. based on task title and context\n */\nexport function getEnhanceTaskDetailsPrompt(taskId: string): GetPromptResult {\n return {\n description: 'Task Detail Enhancement Assistant',\n messages: [\n {\n role: 'user',\n content: {\n type: 'text',\n text: `Please help me enhance the details for task ${taskId}.\n\n## Enhancement Content:\n\n### 1. Detailed Description\n- Specific content and background of the task\n- Why this task needs to be done\n- Expected business or technical value\n\n### 2. Acceptance Criteria (Definition of Done)\nList clear completion standards, for example:\n- [ ] Feature implemented and locally tested\n- [ ] Code passes Code Review\n- [ ] Related documentation updated\n- [ ] Unit test coverage > 80%\n\n### 3. Technical/Implementation Details\n- Tech stack or modules involved\n- Files that may need modification\n- Potential challenges or considerations\n\n### 4. Related Resources\n- Related documentation links\n- Reference implementations or example code\n- People to consult\n\n### 5. Subtask Suggestions (if needed)\nIf the task is complex, suggest breaking it down:\n- Subtask 1: ...\n- Subtask 2: ...\n- Subtask 3: ...\n\n## Please perform the following steps:\n\n1. **Get task info**: Use get_task to view current task details\n2. **Get project context**: Use get_project to understand project background\n3. **Analyze task type**:\n - If development task: Add technical details, code locations\n - If design task: Add design specs, review criteria\n - If documentation task: Add doc structure, references\n - If testing task: Add test scenarios, coverage scope\n4. **Generate enhancement content**: Use update_task to update task description\n\n## Updated task should include:\n\n\\`\\`\\`\n## Background\n[Task background and purpose]\n\n## Acceptance Criteria\n- [ ] [Standard 1]\n- [ ] [Standard 2]\n- [ ] [Standard 3]\n\n## Technical Details\n- Modules: [module name]\n- Key files: [file path]\n- Notes: [important reminders]\n\n## Related Resources\n- Documentation: [link]\n- References: [link]\n\\`\\`\\`\n\nPlease fetch task info first, then provide detailed enhancement suggestions.`,\n },\n },\n ],\n };\n}\n\n/**\n * Quick Idea Capture\n * Auto-categorize, suggest priorities, recommend projects\n */\nexport function getQuickCapturePrompt(idea: string, projectId?: string): GetPromptResult {\n const projectContext = projectId\n ? `Add to project ${projectId}`\n : 'Auto-select the most suitable project';\n\n return {\n description: 'Quick Capture Assistant',\n messages: [\n {\n role: 'user',\n content: {\n type: 'text',\n text: `I want to quickly capture an idea/task: \"${idea}\"\n\n${projectContext}\n\n## Please help me complete the following steps:\n\n### 1. Task Information Extraction\nExtract from description:\n- **Task Title**: Concise and clear title (start with verb)\n- **Task Description**: Add context and details\n- **Task Type**: bug / feature / refactor / docs / chore\n- **Estimated Priority**: critical / high / medium / low (based on urgency in description)\n\n### 2. Project Recommendation (if no project specified)\nIf user didn't specify a project, please:\n- List all active projects\n- Analyze which project the task content is most relevant to\n- Recommend the most suitable project\n\n### 3. Tag Suggestions\nSuggest relevant tags:\n- Type tags: bug, feature, refactor, docs\n- Priority tags: urgent, important\n- Domain tags: frontend, backend, design, testing (if applicable)\n\n### 4. Generate Task\nUse create_task to create the task\n\n### 5. Status Recommendation\nAfter creating the task, if you start working on it immediately, consider setting the status to in-progress. Use update_task to keep progress updated during work, and mark as done when completed.\n\n## Example:\n\n**Input**: \"User reported login page doesn't display correctly on mobile\"\n\n**Output**:\n- Title: Fix login page mobile responsiveness issue\n- Description: User reported the login page displays abnormally on mobile devices, need to check responsive layout.\n- Type: Bug\n- Priority: High (affects user experience)\n- Suggested Tags: bug, frontend, mobile\n- Recommended Project: [Recommend if there's a web project]\n\n## Current Idea Analysis:\n\nIdea: \"${idea}\"\n\nPlease analyze and generate task suggestions. After user confirmation, execute create_task to create the task.`,\n },\n },\n ],\n };\n}\n\n/**\n * Get Prompt by name\n */\nexport function getPromptByName(name: string, args?: Record<string, string>): GetPromptResult | null {\n switch (name) {\n case 'recommendNextTasks':\n return getRecommendNextTasksPrompt(args?.projectId, args?.limit);\n case 'autoPrioritize':\n return getAutoPrioritizePrompt(args?.projectId);\n case 'enhanceTaskDetails':\n return getEnhanceTaskDetailsPrompt(args?.taskId || '');\n case 'quickCapture':\n return getQuickCapturePrompt(args?.idea || '', args?.projectId);\n default:\n return null;\n }\n}\n\n/**\n * Get all available Prompts\n */\nexport function getAllPrompts(): Prompt[] {\n return projectPrompts;\n}\n"],"mappings":"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","names":["path","path","fs","z","storage","existingTag","writeJsonFile","z","z","z","path","fileURLToPath","__filename","fileURLToPath","__dirname","require","tagService","url","z","path","fs","z","writeJsonFile","createServer"]}
@@ -70,6 +70,8 @@ init_esm_shims();
70
70
  import express from "express";
71
71
  import * as path4 from "path";
72
72
  import { fileURLToPath as fileURLToPath2 } from "url";
73
+ import { createRequire } from "module";
74
+ import { existsSync } from "fs";
73
75
 
74
76
  // src/storage/index.ts
75
77
  init_esm_shims();
@@ -924,6 +926,35 @@ init_esm_shims();
924
926
  // src/web/server.ts
925
927
  var __filename2 = fileURLToPath2(import.meta.url);
926
928
  var __dirname2 = path4.dirname(__filename2);
929
+ function resolveAppPath() {
930
+ const candidates = [];
931
+ try {
932
+ const require2 = createRequire(import.meta.url);
933
+ const pkgRoot = path4.dirname(require2.resolve("../../package.json"));
934
+ candidates.push({ path: path4.join(pkgRoot, "dist/web/app"), source: "package.json resolve" });
935
+ } catch {
936
+ }
937
+ candidates.push({ path: path4.join(__dirname2, "web/app"), source: "__dirname/web/app" });
938
+ candidates.push({ path: path4.join(__dirname2, "app"), source: "__dirname relative" });
939
+ candidates.push({ path: path4.join(process.cwd(), "dist/web/app"), source: "process.cwd()" });
940
+ candidates.push({ path: path4.join(__dirname2, "../web/app"), source: "__dirname/../web/app" });
941
+ for (const { path: candidatePath, source } of candidates) {
942
+ const indexPath = path4.join(candidatePath, "index.html");
943
+ if (existsSync(indexPath)) {
944
+ console.log(`[roadmap-skill] Static files found at: ${candidatePath} (via ${source})`);
945
+ return candidatePath;
946
+ }
947
+ }
948
+ const triedPaths = candidates.map((c) => ` - ${c.path} (${c.source})`).join("\n");
949
+ throw new Error(
950
+ `Cannot find web app static files.
951
+
952
+ Tried:
953
+ ${triedPaths}
954
+
955
+ Ensure the package is installed correctly and web assets exist.`
956
+ );
957
+ }
927
958
  var tagService = new TagService(storage);
928
959
  function createServer(port = 7860) {
929
960
  return new Promise((resolve, reject) => {
@@ -1107,7 +1138,7 @@ function createServer(port = 7860) {
1107
1138
  });
1108
1139
  }
1109
1140
  });
1110
- const distPath = path4.join(__dirname2, "app");
1141
+ const distPath = resolveAppPath();
1111
1142
  app.use(express.static(distPath));
1112
1143
  app.get("*", (req, res) => {
1113
1144
  if (req.path.startsWith("/api")) {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../node_modules/tsup/assets/esm_shims.js","../../src/utils/file-helpers.ts","../../src/web/server.ts","../../src/storage/index.ts","../../src/utils/path-helpers.ts","../../src/services/index.ts","../../src/services/tag-service.ts","../../src/services/task-service.ts","../../src/services/types.ts"],"sourcesContent":["// Shim globals in esm bundle\nimport path from 'node:path'\nimport { fileURLToPath } from 'node:url'\n\nconst getFilename = () => fileURLToPath(import.meta.url)\nconst getDirname = () => path.dirname(getFilename())\n\nexport const __dirname = /* @__PURE__ */ getDirname()\nexport const __filename = /* @__PURE__ */ getFilename()\n","import * as fs from 'fs/promises';\n\n/**\n * Read and parse a JSON file\n * @param filePath - Path to the JSON file\n * @returns Parsed JSON data\n * @throws Error if file cannot be read or parsed\n */\nexport async function readJsonFile<T>(filePath: string): Promise<T> {\n try {\n const content = await fs.readFile(filePath, 'utf-8');\n return JSON.parse(content) as T;\n } catch (error) {\n if (error instanceof Error) {\n throw new Error(`Failed to read JSON file ${filePath}: ${error.message}`);\n }\n throw error;\n }\n}\n\n/**\n * Write data to a JSON file\n * @param filePath - Path to the JSON file\n * @param data - Data to serialize and write\n * @throws Error if file cannot be written\n */\nexport async function writeJsonFile<T>(filePath: string, data: T): Promise<void> {\n try {\n const content = JSON.stringify(data, null, 2);\n await fs.writeFile(filePath, content, 'utf-8');\n } catch (error) {\n if (error instanceof Error) {\n throw new Error(`Failed to write JSON file ${filePath}: ${error.message}`);\n }\n throw error;\n }\n}\n\n/**\n * Ensure a directory exists, creating it recursively if needed\n * @param dirPath - Path to the directory\n * @throws Error if directory cannot be created\n */\nexport async function ensureDir(dirPath: string): Promise<void> {\n try {\n await fs.mkdir(dirPath, { recursive: true });\n } catch (error) {\n if (error instanceof Error) {\n throw new Error(`Failed to create directory ${dirPath}: ${error.message}`);\n }\n throw error;\n }\n}\n","import express from 'express';\nimport * as path from 'path';\nimport { fileURLToPath } from 'url';\nimport type { Server } from 'http';\nimport { storage } from '../storage/index.js';\nimport { TaskService, TagService } from '../services/index.js';\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = path.dirname(__filename);\n\nconst tagService = new TagService(storage);\n\nexport function createServer(port: number = 7860): Promise<Server> {\n return new Promise((resolve, reject) => {\n const app = express();\n\n app.use(express.json());\n\n app.get('/api/projects', async (_req, res) => {\n try {\n const projects = await storage.listProjects();\n res.json(projects);\n } catch (error) {\n res.status(500).json({ error: (error as Error).message });\n }\n });\n\n app.get('/api/projects/:id', async (req, res) => {\n try {\n const project = await storage.readProject(req.params.id);\n if (!project) {\n res.status(404).json({ error: 'Project not found' });\n return;\n }\n res.json(project);\n } catch (error) {\n res.status(500).json({ error: (error as Error).message });\n }\n });\n\n app.get('/api/tasks', async (req, res) => {\n try {\n const filters: Record<string, unknown> = { ...req.query };\n\n // Convert includeCompleted from string to boolean\n if (filters.includeCompleted !== undefined) {\n filters.includeCompleted = filters.includeCompleted === 'true';\n }\n\n const tasks = await storage.searchTasks(filters as any);\n res.json(tasks);\n } catch (error) {\n res.status(500).json({ error: (error as Error).message });\n }\n });\n\n app.post('/api/projects', async (req, res) => {\n try {\n const project = await storage.createProject(req.body);\n res.json({ success: true, data: project });\n } catch (error) {\n res.status(500).json({ error: (error as Error).message });\n }\n });\n\n app.put('/api/projects', async (req, res) => {\n try {\n const { projectId, ...updateData } = req.body;\n const project = await storage.updateProject(projectId, updateData);\n res.json({ success: true, data: project });\n } catch (error) {\n res.status(500).json({ error: (error as Error).message });\n }\n });\n\n app.delete('/api/projects', async (req, res) => {\n try {\n const { projectId } = req.query;\n await storage.deleteProject(projectId as string);\n res.json({ success: true });\n } catch (error) {\n res.status(500).json({ error: (error as Error).message });\n }\n });\n\n app.post('/api/tasks', async (req, res) => {\n try {\n const { projectId, ...taskData } = req.body;\n const result = await TaskService.create(projectId, taskData);\n if (!result.success) {\n const statusCode = result.code === 'NOT_FOUND' ? 404 : 400;\n res.status(statusCode).json({ error: result.error });\n return;\n }\n res.json({ success: true, data: result.data });\n } catch (error) {\n res.status(500).json({ error: (error as Error).message });\n }\n });\n\n app.put('/api/tasks', async (req, res) => {\n try {\n const { projectId, taskId, ...updateData } = req.body;\n const result = await TaskService.update(projectId, taskId, updateData);\n if (!result.success) {\n const statusCode = result.code === 'NOT_FOUND' ? 404 : 400;\n res.status(statusCode).json({ error: result.error });\n return;\n }\n res.json({ success: true, data: result.data });\n } catch (error) {\n res.status(500).json({ error: (error as Error).message });\n }\n });\n\n app.delete('/api/tasks', async (req, res) => {\n try {\n const { projectId, taskId } = req.query;\n const result = await TaskService.delete(projectId as string, taskId as string);\n if (!result.success) {\n const statusCode = result.code === 'NOT_FOUND' ? 404 : 400;\n res.status(statusCode).json({ error: result.error });\n return;\n }\n res.json({ success: true });\n } catch (error) {\n res.status(500).json({ error: (error as Error).message });\n }\n });\n\n app.post('/api/projects/:projectId/tags', async (req, res) => {\n try {\n const { projectId } = req.params;\n const result = await tagService.create(projectId, req.body);\n if (!result.success) {\n const statusCode = result.code === 'NOT_FOUND' ? 404 : 400;\n res.status(statusCode).json({ error: result.error });\n return;\n }\n res.json({ success: true, data: result.data });\n } catch (error) {\n res.status(500).json({ error: (error as Error).message });\n }\n });\n\n app.get('/api/projects/:projectId/tags', async (req, res) => {\n try {\n const { projectId } = req.params;\n const result = await tagService.list(projectId);\n if (!result.success) {\n const statusCode = result.code === 'NOT_FOUND' ? 404 : 400;\n res.status(statusCode).json({ error: result.error });\n return;\n }\n res.json({ success: true, data: result.data });\n } catch (error) {\n res.status(500).json({ error: (error as Error).message });\n }\n });\n\n app.put('/api/projects/:projectId/tags/:tagId', async (req, res) => {\n try {\n const { projectId, tagId } = req.params;\n const result = await tagService.update(projectId, tagId, req.body);\n if (!result.success) {\n const statusCode = result.code === 'NOT_FOUND' ? 404 : 400;\n res.status(statusCode).json({ error: result.error });\n return;\n }\n res.json({ success: true, data: result.data });\n } catch (error) {\n res.status(500).json({ error: (error as Error).message });\n }\n });\n\n app.delete('/api/projects/:projectId/tags/:tagId', async (req, res) => {\n try {\n const { projectId, tagId } = req.params;\n const result = await tagService.delete(projectId, tagId);\n if (!result.success) {\n const statusCode = result.code === 'NOT_FOUND' ? 404 : 400;\n res.status(statusCode).json({ error: result.error });\n return;\n }\n res.json({ success: true, data: result.data });\n } catch (error) {\n res.status(500).json({ error: (error as Error).message });\n }\n });\n\n app.get('/api/backup', async (_req, res) => {\n try {\n const backup = await storage.exportAllData();\n const filename = `roadmap-skill-backup-${new Date().toISOString().split('T')[0]}.json`;\n res.setHeader('Content-Type', 'application/json');\n res.setHeader('Content-Disposition', `attachment; filename=\"${filename}\"`);\n res.json(backup);\n } catch (error) {\n res.status(500).json({ error: (error as Error).message });\n }\n });\n\n app.post('/api/backup', async (req, res) => {\n try {\n const result = await storage.importAllData(req.body);\n res.json(result);\n } catch (error) {\n res.status(400).json({\n success: false,\n error: (error as Error).message,\n });\n }\n });\n\n const distPath = path.join(__dirname, 'app');\n app.use(express.static(distPath));\n\n app.get('*', (req, res) => {\n if (req.path.startsWith('/api')) {\n res.status(404).json({ error: 'API not found' });\n return;\n }\n res.sendFile(path.join(distPath, 'index.html'));\n });\n\n const server = app.listen(port, '127.0.0.1');\n\n server.once('listening', () => {\n console.log(`Web interface server running at http://localhost:${port}`);\n resolve(server);\n });\n\n server.once('error', (error: NodeJS.ErrnoException) => {\n if (error.code === 'EADDRINUSE') {\n reject(new Error(`Port ${port} is already in use`));\n return;\n }\n\n reject(error);\n });\n });\n}\n\n// Start server if run directly\nif (process.argv[1]?.endsWith('server.js')) {\n const port = parseInt(process.argv[2] || '7860', 10);\n createServer(port).catch(err => {\n console.error('Failed to start server:', err);\n process.exit(1);\n });\n}\n","import * as path from 'path';\nimport type {\n Project,\n ProjectData,\n Task,\n TaskSearchFilters,\n CreateProjectInput,\n UpdateProjectInput,\n} from '../models/index.js';\nimport { getStorageDir } from '../utils/path-helpers.js';\nimport { readJsonFile, writeJsonFile, ensureDir } from '../utils/file-helpers.js';\n\n/**\n * Storage class for managing roadmap-skill projects\n * Projects are stored as individual JSON files in ~/.roadmap-skill/projects/\n */\nexport class ProjectStorage {\n private storageDir: string;\n\n constructor() {\n this.storageDir = getStorageDir();\n }\n\n /**\n * Ensure the storage directory exists\n */\n async ensureDirectory(): Promise<void> {\n await ensureDir(this.storageDir);\n }\n\n /**\n * Get the file path for a project\n * @param projectId - The project ID\n * @returns Full path to the project JSON file\n */\n getFilePath(projectId: string): string {\n return path.join(this.storageDir, `${projectId}.json`);\n }\n\n /**\n * Create a new project\n * @param input - Project creation data\n * @returns The created project data\n */\n async createProject(input: CreateProjectInput): Promise<ProjectData> {\n await this.ensureDirectory();\n\n const now = new Date().toISOString();\n const projectId = `proj_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;\n\n const project: Project = {\n id: projectId,\n name: input.name,\n description: input.description,\n projectType: input.projectType,\n status: 'active',\n startDate: input.startDate,\n targetDate: input.targetDate,\n createdAt: now,\n updatedAt: now,\n };\n\n const projectData: ProjectData = {\n version: 1,\n project,\n milestones: [],\n tasks: [],\n tags: [],\n };\n\n const filePath = this.getFilePath(projectId);\n await writeJsonFile(filePath, projectData);\n\n return projectData;\n }\n\n /**\n * Read a project by ID\n * @param projectId - The project ID\n * @returns The project data or null if not found\n */\n async readProject(projectId: string): Promise<ProjectData | null> {\n try {\n const filePath = this.getFilePath(projectId);\n return await readJsonFile<ProjectData>(filePath);\n } catch (error) {\n if (error instanceof Error && error.message.includes('ENOENT')) {\n return null;\n }\n throw error;\n }\n }\n\n /**\n * Update an existing project\n * @param projectId - The project ID\n * @param input - Project update data\n * @returns The updated project data or null if not found\n */\n async updateProject(\n projectId: string,\n input: UpdateProjectInput\n ): Promise<ProjectData | null> {\n const projectData = await this.readProject(projectId);\n if (!projectData) {\n return null;\n }\n\n const now = new Date().toISOString();\n\n projectData.project = {\n ...projectData.project,\n ...input,\n updatedAt: now,\n };\n\n const filePath = this.getFilePath(projectId);\n await writeJsonFile(filePath, projectData);\n\n return projectData;\n }\n\n /**\n * Delete a project by ID\n * @param projectId - The project ID\n * @returns True if deleted, false if not found\n */\n async deleteProject(projectId: string): Promise<boolean> {\n try {\n const filePath = this.getFilePath(projectId);\n const fs = await import('fs/promises');\n await fs.unlink(filePath);\n return true;\n } catch (error) {\n if (error instanceof Error && error.message.includes('ENOENT')) {\n return false;\n }\n throw error;\n }\n }\n\n /**\n * List all projects sorted by updatedAt (descending)\n * @returns Array of project summaries (project + metadata)\n */\n async listProjects(): Promise<Array<{ project: Project; taskCount: number; milestoneCount: number }>> {\n await this.ensureDirectory();\n\n const fs = await import('fs/promises');\n const files = await fs.readdir(this.storageDir);\n const jsonFiles = files.filter((f) => f.endsWith('.json'));\n\n const projects: Array<{ project: Project; taskCount: number; milestoneCount: number }> = [];\n\n for (const file of jsonFiles) {\n try {\n const filePath = path.join(this.storageDir, file);\n const data = await readJsonFile<ProjectData>(filePath);\n projects.push({\n project: data.project,\n taskCount: data.tasks.length,\n milestoneCount: data.milestones.length,\n });\n } catch {\n // Skip invalid files\n continue;\n }\n }\n\n // Sort by updatedAt descending\n return projects.sort(\n (a, b) => new Date(b.project.updatedAt).getTime() - new Date(a.project.updatedAt).getTime()\n );\n }\n\n /**\n * Search tasks across all projects with filters\n * @param filters - Search filters\n * @returns Array of matching tasks with project context\n */\n async searchTasks(\n filters: TaskSearchFilters\n ): Promise<Array<{ task: Task; project: Project }>> {\n await this.ensureDirectory();\n\n const fs = await import('fs/promises');\n const files = await fs.readdir(this.storageDir);\n const jsonFiles = files.filter((f) => f.endsWith('.json'));\n\n const results: Array<{ task: Task; project: Project }> = [];\n\n for (const file of jsonFiles) {\n try {\n const filePath = path.join(this.storageDir, file);\n const data = await readJsonFile<ProjectData>(filePath);\n\n // Skip if project filter doesn't match\n if (filters.projectId && data.project.id !== filters.projectId) {\n continue;\n }\n\n for (const task of data.tasks) {\n // Apply filters\n if (filters.status && task.status !== filters.status) {\n continue;\n }\n if (filters.priority && task.priority !== filters.priority) {\n continue;\n }\n if (filters.assignee && task.assignee !== filters.assignee) {\n continue;\n }\n if (filters.dueBefore && task.dueDate && task.dueDate > filters.dueBefore) {\n continue;\n }\n if (filters.dueAfter && task.dueDate && task.dueDate < filters.dueAfter) {\n continue;\n }\n if (\n filters.tags &&\n filters.tags.length > 0 &&\n !filters.tags.some((tag) => task.tags.includes(tag))\n ) {\n continue;\n }\n if (\n filters.searchText &&\n !task.title.toLowerCase().includes(filters.searchText.toLowerCase()) &&\n !task.description.toLowerCase().includes(filters.searchText.toLowerCase())\n ) {\n continue;\n }\n\n // Filter completed tasks (done status) when includeCompleted is false\n if (filters.includeCompleted === false && task.status === 'done') {\n continue;\n }\n\n results.push({ task, project: data.project });\n }\n } catch {\n // Skip invalid files\n continue;\n }\n }\n\n return results;\n }\n\n async exportAllData(): Promise<{\n version: number;\n exportedAt: string;\n projects: ProjectData[];\n }> {\n await this.ensureDirectory();\n\n const fs = await import('fs/promises');\n const files = await fs.readdir(this.storageDir);\n const jsonFiles = files.filter((f) => f.endsWith('.json'));\n\n const projects: ProjectData[] = [];\n\n for (const file of jsonFiles) {\n try {\n const filePath = path.join(this.storageDir, file);\n const data = await readJsonFile<ProjectData>(filePath);\n projects.push(data);\n } catch {\n continue;\n }\n }\n\n return {\n version: 1,\n exportedAt: new Date().toISOString(),\n projects,\n };\n }\n\n async importAllData(data: {\n version: number;\n exportedAt: string;\n projects: ProjectData[];\n }): Promise<{\n success: boolean;\n imported: number;\n errors: number;\n errorDetails: string[];\n }> {\n await this.ensureDirectory();\n\n let imported = 0;\n let errors = 0;\n const errorDetails: string[] = [];\n\n if (!data.projects || !Array.isArray(data.projects)) {\n throw new Error('Invalid backup data: projects array is required');\n }\n\n for (const projectData of data.projects) {\n try {\n if (!projectData.project || !projectData.project.id) {\n errors++;\n errorDetails.push('Skipping invalid project: missing project or id');\n continue;\n }\n\n const filePath = this.getFilePath(projectData.project.id);\n await writeJsonFile(filePath, projectData);\n imported++;\n } catch (error) {\n errors++;\n const errorMessage = error instanceof Error ? error.message : String(error);\n errorDetails.push(`Failed to import project ${projectData.project?.id || 'unknown'}: ${errorMessage}`);\n }\n }\n\n return {\n success: errors === 0,\n imported,\n errors,\n errorDetails,\n };\n }\n}\n\nexport const storage = new ProjectStorage();\n","import * as os from 'os';\nimport * as path from 'path';\n\n/**\n * Get the storage directory for roadmap-skill projects\n * Returns: ~/.roadmap-skill/projects\n */\nexport function getStorageDir(): string {\n const homeDir = os.homedir();\n return path.join(homeDir, '.roadmap-skill', 'projects');\n}\n","export { TagService } from './tag-service.js';\nexport { TaskService } from './task-service.js';\nexport * from './types.js';\n","/**\n * Tag Service - Unified business logic for tag management\n * Extracted from tag-tools.ts for better separation of concerns\n */\n\nimport type { ProjectStorage } from '../storage/index.js';\nimport type { Tag, ProjectData } from '../models/index.js';\nimport type {\n ServiceResult,\n CreateTagData,\n UpdateTagData,\n DeleteTagResult,\n TasksByTagResult,\n} from './types.js';\n\n/**\n * Generate a unique tag ID\n * @returns Tag ID in format tag_${timestamp}_${random}\n */\nfunction generateTagId(): string {\n return `tag_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;\n}\n\n/**\n * TagService - Handles all tag-related business logic\n */\nexport class TagService {\n private storage: ProjectStorage;\n\n constructor(storage: ProjectStorage) {\n this.storage = storage;\n }\n\n /**\n * Create a new tag in a project\n * @param projectId - The project ID\n * @param data - Tag creation data\n * @returns The created tag or error\n */\n async create(projectId: string, data: CreateTagData): Promise<ServiceResult<Tag>> {\n try {\n const projectData = await this.storage.readProject(projectId);\n if (!projectData) {\n return {\n success: false,\n error: `Project with ID '${projectId}' not found`,\n code: 'NOT_FOUND',\n };\n }\n\n // Check for duplicate tag name (case-insensitive)\n const existingTag = projectData.tags.find(\n (t) => t.name.toLowerCase() === data.name.toLowerCase()\n );\n if (existingTag) {\n return {\n success: false,\n error: `Tag with name '${data.name}' already exists in this project`,\n code: 'DUPLICATE_ERROR',\n };\n }\n\n const now = new Date().toISOString();\n const tag: Tag = {\n id: generateTagId(),\n name: data.name,\n color: data.color,\n description: data.description || '',\n createdAt: now,\n };\n\n projectData.tags.push(tag);\n projectData.project.updatedAt = now;\n\n await this.saveProjectData(projectId, projectData);\n\n return {\n success: true,\n data: tag,\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Failed to create tag',\n code: 'INTERNAL_ERROR',\n };\n }\n }\n\n /**\n * List all tags in a project\n * @param projectId - The project ID\n * @returns Array of tags or error\n */\n async list(projectId: string): Promise<ServiceResult<Tag[]>> {\n try {\n const projectData = await this.storage.readProject(projectId);\n if (!projectData) {\n return {\n success: false,\n error: `Project with ID '${projectId}' not found`,\n code: 'NOT_FOUND',\n };\n }\n\n return {\n success: true,\n data: projectData.tags,\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Failed to list tags',\n code: 'INTERNAL_ERROR',\n };\n }\n }\n\n /**\n * Update an existing tag\n * @param projectId - The project ID\n * @param tagId - The tag ID\n * @param data - Tag update data\n * @returns The updated tag or error\n */\n async update(\n projectId: string,\n tagId: string,\n data: UpdateTagData\n ): Promise<ServiceResult<Tag>> {\n try {\n const projectData = await this.storage.readProject(projectId);\n if (!projectData) {\n return {\n success: false,\n error: `Project with ID '${projectId}' not found`,\n code: 'NOT_FOUND',\n };\n }\n\n const tagIndex = projectData.tags.findIndex((t) => t.id === tagId);\n if (tagIndex === -1) {\n return {\n success: false,\n error: `Tag with ID '${tagId}' not found in project '${projectId}'`,\n code: 'NOT_FOUND',\n };\n }\n\n // Check if there is any field to update\n if (Object.keys(data).length === 0) {\n return {\n success: false,\n error: 'At least one field to update is required',\n code: 'VALIDATION_ERROR',\n };\n }\n\n // Check for duplicate name if updating name (case-insensitive)\n if (data.name) {\n const existingTag = projectData.tags.find(\n (t) =>\n t.name.toLowerCase() === data.name!.toLowerCase() && t.id !== tagId\n );\n if (existingTag) {\n return {\n success: false,\n error: `Tag with name '${data.name}' already exists in this project`,\n code: 'DUPLICATE_ERROR',\n };\n }\n }\n\n const now = new Date().toISOString();\n const existingTag = projectData.tags[tagIndex];\n\n const updatedTag: Tag = {\n ...existingTag,\n ...data,\n id: existingTag.id,\n createdAt: existingTag.createdAt,\n };\n\n projectData.tags[tagIndex] = updatedTag;\n projectData.project.updatedAt = now;\n\n await this.saveProjectData(projectId, projectData);\n\n return {\n success: true,\n data: updatedTag,\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Failed to update tag',\n code: 'INTERNAL_ERROR',\n };\n }\n }\n\n /**\n * Delete a tag by ID\n * Also removes the tag from all tasks that use it\n * @param projectId - The project ID\n * @param tagId - The tag ID\n * @returns Delete result with tag info and count of updated tasks\n */\n async delete(projectId: string, tagId: string): Promise<ServiceResult<DeleteTagResult>> {\n try {\n const projectData = await this.storage.readProject(projectId);\n if (!projectData) {\n return {\n success: false,\n error: `Project with ID '${projectId}' not found`,\n code: 'NOT_FOUND',\n };\n }\n\n const tagIndex = projectData.tags.findIndex((t) => t.id === tagId);\n if (tagIndex === -1) {\n return {\n success: false,\n error: `Tag with ID '${tagId}' not found in project '${projectId}'`,\n code: 'NOT_FOUND',\n };\n }\n\n const tag = projectData.tags[tagIndex];\n\n // Remove tag from all tasks that use it\n const now = new Date().toISOString();\n let tasksUpdated = 0;\n for (const task of projectData.tasks) {\n const tagIndexInTask = task.tags.indexOf(tagId);\n if (tagIndexInTask !== -1) {\n task.tags.splice(tagIndexInTask, 1);\n task.updatedAt = now;\n tasksUpdated++;\n }\n }\n\n projectData.tags.splice(tagIndex, 1);\n projectData.project.updatedAt = now;\n\n await this.saveProjectData(projectId, projectData);\n\n return {\n success: true,\n data: {\n deleted: true,\n tag,\n tasksUpdated,\n },\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Failed to delete tag',\n code: 'INTERNAL_ERROR',\n };\n }\n }\n\n /**\n * Get all tasks that have a specific tag by tag name\n * @param projectId - The project ID\n * @param tagName - The tag name\n * @returns Tag info and matching tasks\n */\n async getTasksByTag(\n projectId: string,\n tagName: string\n ): Promise<ServiceResult<TasksByTagResult>> {\n try {\n const projectData = await this.storage.readProject(projectId);\n if (!projectData) {\n return {\n success: false,\n error: `Project with ID '${projectId}' not found`,\n code: 'NOT_FOUND',\n };\n }\n\n // Find tag by name (case-insensitive)\n const tag = projectData.tags.find(\n (t) => t.name.toLowerCase() === tagName.toLowerCase()\n );\n\n if (!tag) {\n return {\n success: false,\n error: `Tag with name '${tagName}' not found in project '${projectId}'`,\n code: 'NOT_FOUND',\n };\n }\n\n // Find all tasks with this tag\n const tasks = projectData.tasks.filter((t) => t.tags.includes(tag.id));\n\n return {\n success: true,\n data: {\n tag,\n tasks,\n count: tasks.length,\n },\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Failed to get tasks by tag',\n code: 'INTERNAL_ERROR',\n };\n }\n }\n\n /**\n * Helper method to save project data\n * @param projectId - The project ID\n * @param projectData - The project data to save\n */\n private async saveProjectData(projectId: string, projectData: ProjectData): Promise<void> {\n const filePath = this.storage.getFilePath(projectId);\n const { writeJsonFile } = await import('../utils/file-helpers.js');\n await writeJsonFile(filePath, projectData);\n }\n}\n","/**\n * Task Service - Unified business logic for task operations\n * Extracted from task-tools.ts to enable reuse across different interfaces\n */\n\nimport type { Task, TaskStatus } from '../models/index.js';\nimport { storage } from '../storage/index.js';\nimport { writeJsonFile } from '../utils/file-helpers.js';\nimport type {\n ServiceResult,\n CreateTaskData,\n UpdateTaskData,\n BatchUpdateTaskData,\n BatchUpdateResult,\n} from './types.js';\n\n/**\n * Generate a unique task ID\n * Format: task_${timestamp}_${random}\n */\nfunction generateTaskId(): string {\n return `task_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;\n}\n\n/**\n * Calculate completedAt based on status change\n * - When status changes to 'done', set completedAt to current time\n * - When status changes from 'done' to other, clear completedAt\n * - Otherwise, preserve existing completedAt\n */\nfunction calculateCompletedAt(\n currentStatus: TaskStatus,\n newStatus: TaskStatus | undefined,\n existingCompletedAt: string | null,\n now: string\n): string | null {\n // Status is not being updated\n if (!newStatus) {\n return existingCompletedAt;\n }\n\n // Status changing to 'done'\n if (newStatus === 'done' && currentStatus !== 'done') {\n return now;\n }\n\n // Status changing from 'done' to something else\n if (currentStatus === 'done' && newStatus !== 'done') {\n return null;\n }\n\n // Status changing but not involving 'done' transition\n return existingCompletedAt;\n}\n\n/**\n * TaskService - Business logic for task operations\n */\nexport const TaskService = {\n /**\n * Create a new task in a project\n * @param projectId - The project ID\n * @param data - Task creation data\n * @returns The created task or error\n */\n async create(projectId: string, data: CreateTaskData): Promise<ServiceResult<Task>> {\n try {\n const projectData = await storage.readProject(projectId);\n if (!projectData) {\n return {\n success: false,\n error: `Project with ID '${projectId}' not found`,\n code: 'NOT_FOUND',\n };\n }\n\n const now = new Date().toISOString();\n const task: Task = {\n id: generateTaskId(),\n projectId,\n title: data.title,\n description: data.description,\n status: 'todo',\n priority: data.priority ?? 'medium',\n tags: data.tags ?? [],\n dueDate: data.dueDate ?? null,\n assignee: data.assignee ?? null,\n createdAt: now,\n updatedAt: now,\n completedAt: null,\n };\n\n projectData.tasks.push(task);\n projectData.project.updatedAt = now;\n\n const filePath = storage.getFilePath(projectId);\n await writeJsonFile(filePath, projectData);\n\n return {\n success: true,\n data: task,\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Failed to create task',\n code: 'INTERNAL_ERROR',\n };\n }\n },\n\n /**\n * Get a specific task by project ID and task ID\n * @param projectId - The project ID\n * @param taskId - The task ID\n * @returns The task or error\n */\n async get(projectId: string, taskId: string): Promise<ServiceResult<Task>> {\n try {\n const projectData = await storage.readProject(projectId);\n if (!projectData) {\n return {\n success: false,\n error: `Project with ID '${projectId}' not found`,\n code: 'NOT_FOUND',\n };\n }\n\n const task = projectData.tasks.find((t) => t.id === taskId);\n if (!task) {\n return {\n success: false,\n error: `Task with ID '${taskId}' not found in project '${projectId}'`,\n code: 'NOT_FOUND',\n };\n }\n\n return {\n success: true,\n data: task,\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Failed to get task',\n code: 'INTERNAL_ERROR',\n };\n }\n },\n\n /**\n * Update an existing task\n * Handles completedAt automatically based on status changes\n * @param projectId - The project ID\n * @param taskId - The task ID\n * @param data - Task update data\n * @returns The updated task or error\n */\n async update(\n projectId: string,\n taskId: string,\n data: UpdateTaskData\n ): Promise<ServiceResult<Task>> {\n try {\n const projectData = await storage.readProject(projectId);\n if (!projectData) {\n return {\n success: false,\n error: `Project with ID '${projectId}' not found`,\n code: 'NOT_FOUND',\n };\n }\n\n const taskIndex = projectData.tasks.findIndex((t) => t.id === taskId);\n if (taskIndex === -1) {\n return {\n success: false,\n error: `Task with ID '${taskId}' not found in project '${projectId}'`,\n code: 'NOT_FOUND',\n };\n }\n\n // Check if there's anything to update\n const updateKeys = Object.keys(data);\n if (updateKeys.length === 0) {\n return {\n success: false,\n error: 'At least one field to update is required',\n code: 'VALIDATION_ERROR',\n };\n }\n\n const now = new Date().toISOString();\n const existingTask = projectData.tasks[taskIndex];\n\n // Calculate completedAt based on status change\n const completedAt = calculateCompletedAt(\n existingTask.status,\n data.status,\n existingTask.completedAt,\n now\n );\n\n const updatedTask: Task = {\n ...existingTask,\n ...data,\n id: existingTask.id,\n projectId: existingTask.projectId,\n createdAt: existingTask.createdAt,\n updatedAt: now,\n completedAt,\n };\n\n projectData.tasks[taskIndex] = updatedTask;\n projectData.project.updatedAt = now;\n\n const filePath = storage.getFilePath(projectId);\n await writeJsonFile(filePath, projectData);\n\n return {\n success: true,\n data: updatedTask,\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Failed to update task',\n code: 'INTERNAL_ERROR',\n };\n }\n },\n\n /**\n * Delete a task by project ID and task ID\n * @param projectId - The project ID\n * @param taskId - The task ID\n * @returns Void or error\n */\n async delete(projectId: string, taskId: string): Promise<ServiceResult<void>> {\n try {\n const projectData = await storage.readProject(projectId);\n if (!projectData) {\n return {\n success: false,\n error: `Project with ID '${projectId}' not found`,\n code: 'NOT_FOUND',\n };\n }\n\n const taskIndex = projectData.tasks.findIndex((t) => t.id === taskId);\n if (taskIndex === -1) {\n return {\n success: false,\n error: `Task with ID '${taskId}' not found in project '${projectId}'`,\n code: 'NOT_FOUND',\n };\n }\n\n const now = new Date().toISOString();\n projectData.tasks.splice(taskIndex, 1);\n projectData.project.updatedAt = now;\n\n const filePath = storage.getFilePath(projectId);\n await writeJsonFile(filePath, projectData);\n\n return {\n success: true,\n data: undefined,\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Failed to delete task',\n code: 'INTERNAL_ERROR',\n };\n }\n },\n\n /**\n * List tasks with optional filters\n * @param filters - Optional filters for the search\n * @returns Array of tasks or error\n */\n async list(filters?: {\n projectId?: string;\n status?: TaskStatus;\n priority?: 'low' | 'medium' | 'high' | 'critical';\n tags?: string[];\n assignee?: string;\n dueBefore?: string;\n dueAfter?: string;\n includeCompleted?: boolean;\n }): Promise<ServiceResult<Task[]>> {\n try {\n const results = await storage.searchTasks({\n projectId: filters?.projectId,\n status: filters?.status,\n priority: filters?.priority,\n tags: filters?.tags,\n assignee: filters?.assignee,\n dueBefore: filters?.dueBefore,\n dueAfter: filters?.dueAfter,\n includeCompleted: filters?.includeCompleted,\n });\n\n // Extract just the tasks from the results\n const tasks = results.map((r) => r.task);\n\n return {\n success: true,\n data: tasks,\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Failed to list tasks',\n code: 'INTERNAL_ERROR',\n };\n }\n },\n\n /**\n * Update multiple tasks at once\n * @param projectId - The project ID\n * @param taskIds - Array of task IDs to update\n * @param data - Batch update data\n * @returns Batch update result or error\n */\n async batchUpdate(\n projectId: string,\n taskIds: string[],\n data: BatchUpdateTaskData\n ): Promise<ServiceResult<BatchUpdateResult>> {\n try {\n const projectData = await storage.readProject(projectId);\n if (!projectData) {\n return {\n success: false,\n error: `Project with ID '${projectId}' not found`,\n code: 'NOT_FOUND',\n };\n }\n\n const now = new Date().toISOString();\n const updatedTasks: Task[] = [];\n const notFoundIds: string[] = [];\n\n for (const taskId of taskIds) {\n const taskIndex = projectData.tasks.findIndex((t) => t.id === taskId);\n if (taskIndex === -1) {\n notFoundIds.push(taskId);\n continue;\n }\n\n const existingTask = projectData.tasks[taskIndex];\n let updatedTags = existingTask.tags;\n\n // Handle tags based on tagOperation\n if (data.tags && data.tags.length > 0) {\n const existingTags = existingTask.tags || [];\n switch (data.tagOperation) {\n case 'add':\n updatedTags = [...new Set([...existingTags, ...data.tags])];\n break;\n case 'remove':\n updatedTags = existingTags.filter((tag) => !data.tags!.includes(tag));\n break;\n case 'replace':\n default:\n updatedTags = data.tags;\n break;\n }\n }\n\n // Calculate completedAt based on status change\n const completedAt = calculateCompletedAt(\n existingTask.status,\n data.status,\n existingTask.completedAt,\n now\n );\n\n const updatedTask: Task = {\n ...existingTask,\n ...(data.status && { status: data.status }),\n ...(data.priority && { priority: data.priority }),\n tags: updatedTags,\n updatedAt: now,\n completedAt,\n };\n\n projectData.tasks[taskIndex] = updatedTask;\n updatedTasks.push(updatedTask);\n }\n\n if (updatedTasks.length === 0) {\n return {\n success: false,\n error: 'No tasks were found to update',\n code: 'NOT_FOUND',\n };\n }\n\n projectData.project.updatedAt = now;\n\n const filePath = storage.getFilePath(projectId);\n await writeJsonFile(filePath, projectData);\n\n return {\n success: true,\n data: {\n updatedTasks,\n updatedCount: updatedTasks.length,\n notFoundIds: notFoundIds.length > 0 ? notFoundIds : undefined,\n },\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Failed to batch update tasks',\n code: 'INTERNAL_ERROR',\n };\n }\n },\n};\n","/**\n * Service layer type definitions\n * Provides unified result types and service interfaces\n */\n\nimport type { ProjectStorage } from '../storage/index.js';\nimport type { Task, Tag, TaskStatus, TaskPriority } from '../models/index.js';\n\n// ============================================================================\n// Result Types\n// ============================================================================\n\n/**\n * Error codes for service operations\n */\nexport type ErrorCode =\n | 'NOT_FOUND'\n | 'VALIDATION_ERROR'\n | 'DUPLICATE_ERROR'\n | 'UNAUTHORIZED'\n | 'INTERNAL_ERROR';\n\n/**\n * Service result type - discriminated union for success/failure\n */\nexport type ServiceResult<T> =\n | { success: true; data: T }\n | { success: false; error: string; code: ErrorCode };\n\n// ============================================================================\n// Task Service Types\n// ============================================================================\n\nexport interface CreateTaskData {\n title: string;\n description: string;\n priority?: TaskPriority;\n tags?: string[];\n dueDate?: string | null;\n assignee?: string | null;\n}\n\nexport interface UpdateTaskData {\n title?: string;\n description?: string;\n status?: TaskStatus;\n priority?: TaskPriority;\n tags?: string[];\n dueDate?: string | null;\n assignee?: string | null;\n}\n\nexport interface BatchUpdateTaskData {\n status?: TaskStatus;\n priority?: TaskPriority;\n tags?: string[];\n tagOperation?: 'add' | 'remove' | 'replace';\n}\n\nexport interface BatchUpdateResult {\n updatedTasks: Task[];\n updatedCount: number;\n notFoundIds?: string[];\n}\n\n// ============================================================================\n// Tag Service Types\n// ============================================================================\n\nexport interface CreateTagData {\n name: string;\n color: string;\n description?: string;\n}\n\nexport interface UpdateTagData {\n name?: string;\n color?: string;\n description?: string;\n}\n\nexport interface DeleteTagResult {\n deleted: true;\n tag: Tag;\n tasksUpdated: number;\n}\n\nexport interface TasksByTagResult {\n tag: Tag;\n tasks: Task[];\n count: number;\n}\n\n// ============================================================================\n// Service Context\n// ============================================================================\n\n/**\n * Service context for dependency injection\n */\nexport interface ServiceContext {\n storage: ProjectStorage;\n}\n\n// ============================================================================\n// Service Interfaces\n// ============================================================================\n\n/**\n * Task Service interface\n */\nexport interface ITaskService {\n create(projectId: string, data: CreateTaskData): Promise<ServiceResult<Task>>;\n get(projectId: string, taskId: string): Promise<ServiceResult<Task>>;\n update(projectId: string, taskId: string, data: UpdateTaskData): Promise<ServiceResult<Task>>;\n delete(projectId: string, taskId: string): Promise<ServiceResult<void>>;\n list(filters?: {\n projectId?: string;\n status?: TaskStatus;\n priority?: TaskPriority;\n tags?: string[];\n assignee?: string;\n dueBefore?: string;\n dueAfter?: string;\n includeCompleted?: boolean;\n }): Promise<ServiceResult<Task[]>>;\n batchUpdate(\n projectId: string,\n taskIds: string[],\n data: BatchUpdateTaskData\n ): Promise<ServiceResult<BatchUpdateResult>>;\n}\n\n/**\n * Tag Service interface\n */\nexport interface ITagService {\n create(projectId: string, data: CreateTagData): Promise<ServiceResult<Tag>>;\n list(projectId: string): Promise<ServiceResult<Tag[]>>;\n update(projectId: string, tagId: string, data: UpdateTagData): Promise<ServiceResult<Tag>>;\n delete(projectId: string, tagId: string): Promise<ServiceResult<DeleteTagResult>>;\n getTasksByTag(projectId: string, tagName: string): Promise<ServiceResult<TasksByTagResult>>;\n}\n"],"mappings":"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","names":["path","fileURLToPath","path","path","fs","storage","existingTag","writeJsonFile","__filename","fileURLToPath","__dirname"]}
1
+ {"version":3,"sources":["../../node_modules/tsup/assets/esm_shims.js","../../src/utils/file-helpers.ts","../../src/web/server.ts","../../src/storage/index.ts","../../src/utils/path-helpers.ts","../../src/services/index.ts","../../src/services/tag-service.ts","../../src/services/task-service.ts","../../src/services/types.ts"],"sourcesContent":["// Shim globals in esm bundle\nimport path from 'node:path'\nimport { fileURLToPath } from 'node:url'\n\nconst getFilename = () => fileURLToPath(import.meta.url)\nconst getDirname = () => path.dirname(getFilename())\n\nexport const __dirname = /* @__PURE__ */ getDirname()\nexport const __filename = /* @__PURE__ */ getFilename()\n","import * as fs from 'fs/promises';\n\n/**\n * Read and parse a JSON file\n * @param filePath - Path to the JSON file\n * @returns Parsed JSON data\n * @throws Error if file cannot be read or parsed\n */\nexport async function readJsonFile<T>(filePath: string): Promise<T> {\n try {\n const content = await fs.readFile(filePath, 'utf-8');\n return JSON.parse(content) as T;\n } catch (error) {\n if (error instanceof Error) {\n throw new Error(`Failed to read JSON file ${filePath}: ${error.message}`);\n }\n throw error;\n }\n}\n\n/**\n * Write data to a JSON file\n * @param filePath - Path to the JSON file\n * @param data - Data to serialize and write\n * @throws Error if file cannot be written\n */\nexport async function writeJsonFile<T>(filePath: string, data: T): Promise<void> {\n try {\n const content = JSON.stringify(data, null, 2);\n await fs.writeFile(filePath, content, 'utf-8');\n } catch (error) {\n if (error instanceof Error) {\n throw new Error(`Failed to write JSON file ${filePath}: ${error.message}`);\n }\n throw error;\n }\n}\n\n/**\n * Ensure a directory exists, creating it recursively if needed\n * @param dirPath - Path to the directory\n * @throws Error if directory cannot be created\n */\nexport async function ensureDir(dirPath: string): Promise<void> {\n try {\n await fs.mkdir(dirPath, { recursive: true });\n } catch (error) {\n if (error instanceof Error) {\n throw new Error(`Failed to create directory ${dirPath}: ${error.message}`);\n }\n throw error;\n }\n}\n","import express from 'express';\nimport * as path from 'path';\nimport { fileURLToPath } from 'url';\nimport { createRequire } from 'node:module';\nimport { existsSync } from 'node:fs';\nimport type { Server } from 'http';\nimport { storage } from '../storage/index.js';\nimport { TaskService, TagService } from '../services/index.js';\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = path.dirname(__filename);\n\n/**\n * Resolve the path to the web app static files using multiple fallback strategies.\n * Handles npx execution, global installation, local development, and bundled execution.\n */\nfunction resolveAppPath(): string {\n const candidates: Array<{ path: string; source: string }> = [];\n\n try {\n const require = createRequire(import.meta.url);\n const pkgRoot = path.dirname(require.resolve('../../package.json'));\n candidates.push({ path: path.join(pkgRoot, 'dist/web/app'), source: 'package.json resolve' });\n } catch {\n // Package.json not resolvable\n }\n\n // Primary path when bundled: __dirname = dist/, so dist/web/app is correct\n candidates.push({ path: path.join(__dirname, 'web/app'), source: '__dirname/web/app' });\n candidates.push({ path: path.join(__dirname, 'app'), source: '__dirname relative' });\n candidates.push({ path: path.join(process.cwd(), 'dist/web/app'), source: 'process.cwd()' });\n candidates.push({ path: path.join(__dirname, '../web/app'), source: '__dirname/../web/app' });\n\n for (const { path: candidatePath, source } of candidates) {\n const indexPath = path.join(candidatePath, 'index.html');\n if (existsSync(indexPath)) {\n console.log(`[roadmap-skill] Static files found at: ${candidatePath} (via ${source})`);\n return candidatePath;\n }\n }\n\n const triedPaths = candidates.map(c => ` - ${c.path} (${c.source})`).join('\\n');\n throw new Error(\n `Cannot find web app static files.\\n\\n` +\n `Tried:\\n${triedPaths}\\n\\n` +\n `Ensure the package is installed correctly and web assets exist.`\n );\n}\n\nconst tagService = new TagService(storage);\n\nexport function createServer(port: number = 7860): Promise<Server> {\n return new Promise((resolve, reject) => {\n const app = express();\n\n app.use(express.json());\n\n app.get('/api/projects', async (_req, res) => {\n try {\n const projects = await storage.listProjects();\n res.json(projects);\n } catch (error) {\n res.status(500).json({ error: (error as Error).message });\n }\n });\n\n app.get('/api/projects/:id', async (req, res) => {\n try {\n const project = await storage.readProject(req.params.id);\n if (!project) {\n res.status(404).json({ error: 'Project not found' });\n return;\n }\n res.json(project);\n } catch (error) {\n res.status(500).json({ error: (error as Error).message });\n }\n });\n\n app.get('/api/tasks', async (req, res) => {\n try {\n const filters: Record<string, unknown> = { ...req.query };\n\n // Convert includeCompleted from string to boolean\n if (filters.includeCompleted !== undefined) {\n filters.includeCompleted = filters.includeCompleted === 'true';\n }\n\n const tasks = await storage.searchTasks(filters as any);\n res.json(tasks);\n } catch (error) {\n res.status(500).json({ error: (error as Error).message });\n }\n });\n\n app.post('/api/projects', async (req, res) => {\n try {\n const project = await storage.createProject(req.body);\n res.json({ success: true, data: project });\n } catch (error) {\n res.status(500).json({ error: (error as Error).message });\n }\n });\n\n app.put('/api/projects', async (req, res) => {\n try {\n const { projectId, ...updateData } = req.body;\n const project = await storage.updateProject(projectId, updateData);\n res.json({ success: true, data: project });\n } catch (error) {\n res.status(500).json({ error: (error as Error).message });\n }\n });\n\n app.delete('/api/projects', async (req, res) => {\n try {\n const { projectId } = req.query;\n await storage.deleteProject(projectId as string);\n res.json({ success: true });\n } catch (error) {\n res.status(500).json({ error: (error as Error).message });\n }\n });\n\n app.post('/api/tasks', async (req, res) => {\n try {\n const { projectId, ...taskData } = req.body;\n const result = await TaskService.create(projectId, taskData);\n if (!result.success) {\n const statusCode = result.code === 'NOT_FOUND' ? 404 : 400;\n res.status(statusCode).json({ error: result.error });\n return;\n }\n res.json({ success: true, data: result.data });\n } catch (error) {\n res.status(500).json({ error: (error as Error).message });\n }\n });\n\n app.put('/api/tasks', async (req, res) => {\n try {\n const { projectId, taskId, ...updateData } = req.body;\n const result = await TaskService.update(projectId, taskId, updateData);\n if (!result.success) {\n const statusCode = result.code === 'NOT_FOUND' ? 404 : 400;\n res.status(statusCode).json({ error: result.error });\n return;\n }\n res.json({ success: true, data: result.data });\n } catch (error) {\n res.status(500).json({ error: (error as Error).message });\n }\n });\n\n app.delete('/api/tasks', async (req, res) => {\n try {\n const { projectId, taskId } = req.query;\n const result = await TaskService.delete(projectId as string, taskId as string);\n if (!result.success) {\n const statusCode = result.code === 'NOT_FOUND' ? 404 : 400;\n res.status(statusCode).json({ error: result.error });\n return;\n }\n res.json({ success: true });\n } catch (error) {\n res.status(500).json({ error: (error as Error).message });\n }\n });\n\n app.post('/api/projects/:projectId/tags', async (req, res) => {\n try {\n const { projectId } = req.params;\n const result = await tagService.create(projectId, req.body);\n if (!result.success) {\n const statusCode = result.code === 'NOT_FOUND' ? 404 : 400;\n res.status(statusCode).json({ error: result.error });\n return;\n }\n res.json({ success: true, data: result.data });\n } catch (error) {\n res.status(500).json({ error: (error as Error).message });\n }\n });\n\n app.get('/api/projects/:projectId/tags', async (req, res) => {\n try {\n const { projectId } = req.params;\n const result = await tagService.list(projectId);\n if (!result.success) {\n const statusCode = result.code === 'NOT_FOUND' ? 404 : 400;\n res.status(statusCode).json({ error: result.error });\n return;\n }\n res.json({ success: true, data: result.data });\n } catch (error) {\n res.status(500).json({ error: (error as Error).message });\n }\n });\n\n app.put('/api/projects/:projectId/tags/:tagId', async (req, res) => {\n try {\n const { projectId, tagId } = req.params;\n const result = await tagService.update(projectId, tagId, req.body);\n if (!result.success) {\n const statusCode = result.code === 'NOT_FOUND' ? 404 : 400;\n res.status(statusCode).json({ error: result.error });\n return;\n }\n res.json({ success: true, data: result.data });\n } catch (error) {\n res.status(500).json({ error: (error as Error).message });\n }\n });\n\n app.delete('/api/projects/:projectId/tags/:tagId', async (req, res) => {\n try {\n const { projectId, tagId } = req.params;\n const result = await tagService.delete(projectId, tagId);\n if (!result.success) {\n const statusCode = result.code === 'NOT_FOUND' ? 404 : 400;\n res.status(statusCode).json({ error: result.error });\n return;\n }\n res.json({ success: true, data: result.data });\n } catch (error) {\n res.status(500).json({ error: (error as Error).message });\n }\n });\n\n app.get('/api/backup', async (_req, res) => {\n try {\n const backup = await storage.exportAllData();\n const filename = `roadmap-skill-backup-${new Date().toISOString().split('T')[0]}.json`;\n res.setHeader('Content-Type', 'application/json');\n res.setHeader('Content-Disposition', `attachment; filename=\"${filename}\"`);\n res.json(backup);\n } catch (error) {\n res.status(500).json({ error: (error as Error).message });\n }\n });\n\n app.post('/api/backup', async (req, res) => {\n try {\n const result = await storage.importAllData(req.body);\n res.json(result);\n } catch (error) {\n res.status(400).json({\n success: false,\n error: (error as Error).message,\n });\n }\n });\n\n const distPath = resolveAppPath();\n app.use(express.static(distPath));\n\n app.get('*', (req, res) => {\n if (req.path.startsWith('/api')) {\n res.status(404).json({ error: 'API not found' });\n return;\n }\n res.sendFile(path.join(distPath, 'index.html'));\n });\n\n const server = app.listen(port, '127.0.0.1');\n\n server.once('listening', () => {\n console.log(`Web interface server running at http://localhost:${port}`);\n resolve(server);\n });\n\n server.once('error', (error: NodeJS.ErrnoException) => {\n if (error.code === 'EADDRINUSE') {\n reject(new Error(`Port ${port} is already in use`));\n return;\n }\n\n reject(error);\n });\n });\n}\n\n// Start server if run directly\nif (process.argv[1]?.endsWith('server.js')) {\n const port = parseInt(process.argv[2] || '7860', 10);\n createServer(port).catch(err => {\n console.error('Failed to start server:', err);\n process.exit(1);\n });\n}\n","import * as path from 'path';\nimport type {\n Project,\n ProjectData,\n Task,\n TaskSearchFilters,\n CreateProjectInput,\n UpdateProjectInput,\n} from '../models/index.js';\nimport { getStorageDir } from '../utils/path-helpers.js';\nimport { readJsonFile, writeJsonFile, ensureDir } from '../utils/file-helpers.js';\n\n/**\n * Storage class for managing roadmap-skill projects\n * Projects are stored as individual JSON files in ~/.roadmap-skill/projects/\n */\nexport class ProjectStorage {\n private storageDir: string;\n\n constructor() {\n this.storageDir = getStorageDir();\n }\n\n /**\n * Ensure the storage directory exists\n */\n async ensureDirectory(): Promise<void> {\n await ensureDir(this.storageDir);\n }\n\n /**\n * Get the file path for a project\n * @param projectId - The project ID\n * @returns Full path to the project JSON file\n */\n getFilePath(projectId: string): string {\n return path.join(this.storageDir, `${projectId}.json`);\n }\n\n /**\n * Create a new project\n * @param input - Project creation data\n * @returns The created project data\n */\n async createProject(input: CreateProjectInput): Promise<ProjectData> {\n await this.ensureDirectory();\n\n const now = new Date().toISOString();\n const projectId = `proj_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;\n\n const project: Project = {\n id: projectId,\n name: input.name,\n description: input.description,\n projectType: input.projectType,\n status: 'active',\n startDate: input.startDate,\n targetDate: input.targetDate,\n createdAt: now,\n updatedAt: now,\n };\n\n const projectData: ProjectData = {\n version: 1,\n project,\n milestones: [],\n tasks: [],\n tags: [],\n };\n\n const filePath = this.getFilePath(projectId);\n await writeJsonFile(filePath, projectData);\n\n return projectData;\n }\n\n /**\n * Read a project by ID\n * @param projectId - The project ID\n * @returns The project data or null if not found\n */\n async readProject(projectId: string): Promise<ProjectData | null> {\n try {\n const filePath = this.getFilePath(projectId);\n return await readJsonFile<ProjectData>(filePath);\n } catch (error) {\n if (error instanceof Error && error.message.includes('ENOENT')) {\n return null;\n }\n throw error;\n }\n }\n\n /**\n * Update an existing project\n * @param projectId - The project ID\n * @param input - Project update data\n * @returns The updated project data or null if not found\n */\n async updateProject(\n projectId: string,\n input: UpdateProjectInput\n ): Promise<ProjectData | null> {\n const projectData = await this.readProject(projectId);\n if (!projectData) {\n return null;\n }\n\n const now = new Date().toISOString();\n\n projectData.project = {\n ...projectData.project,\n ...input,\n updatedAt: now,\n };\n\n const filePath = this.getFilePath(projectId);\n await writeJsonFile(filePath, projectData);\n\n return projectData;\n }\n\n /**\n * Delete a project by ID\n * @param projectId - The project ID\n * @returns True if deleted, false if not found\n */\n async deleteProject(projectId: string): Promise<boolean> {\n try {\n const filePath = this.getFilePath(projectId);\n const fs = await import('fs/promises');\n await fs.unlink(filePath);\n return true;\n } catch (error) {\n if (error instanceof Error && error.message.includes('ENOENT')) {\n return false;\n }\n throw error;\n }\n }\n\n /**\n * List all projects sorted by updatedAt (descending)\n * @returns Array of project summaries (project + metadata)\n */\n async listProjects(): Promise<Array<{ project: Project; taskCount: number; milestoneCount: number }>> {\n await this.ensureDirectory();\n\n const fs = await import('fs/promises');\n const files = await fs.readdir(this.storageDir);\n const jsonFiles = files.filter((f) => f.endsWith('.json'));\n\n const projects: Array<{ project: Project; taskCount: number; milestoneCount: number }> = [];\n\n for (const file of jsonFiles) {\n try {\n const filePath = path.join(this.storageDir, file);\n const data = await readJsonFile<ProjectData>(filePath);\n projects.push({\n project: data.project,\n taskCount: data.tasks.length,\n milestoneCount: data.milestones.length,\n });\n } catch {\n // Skip invalid files\n continue;\n }\n }\n\n // Sort by updatedAt descending\n return projects.sort(\n (a, b) => new Date(b.project.updatedAt).getTime() - new Date(a.project.updatedAt).getTime()\n );\n }\n\n /**\n * Search tasks across all projects with filters\n * @param filters - Search filters\n * @returns Array of matching tasks with project context\n */\n async searchTasks(\n filters: TaskSearchFilters\n ): Promise<Array<{ task: Task; project: Project }>> {\n await this.ensureDirectory();\n\n const fs = await import('fs/promises');\n const files = await fs.readdir(this.storageDir);\n const jsonFiles = files.filter((f) => f.endsWith('.json'));\n\n const results: Array<{ task: Task; project: Project }> = [];\n\n for (const file of jsonFiles) {\n try {\n const filePath = path.join(this.storageDir, file);\n const data = await readJsonFile<ProjectData>(filePath);\n\n // Skip if project filter doesn't match\n if (filters.projectId && data.project.id !== filters.projectId) {\n continue;\n }\n\n for (const task of data.tasks) {\n // Apply filters\n if (filters.status && task.status !== filters.status) {\n continue;\n }\n if (filters.priority && task.priority !== filters.priority) {\n continue;\n }\n if (filters.assignee && task.assignee !== filters.assignee) {\n continue;\n }\n if (filters.dueBefore && task.dueDate && task.dueDate > filters.dueBefore) {\n continue;\n }\n if (filters.dueAfter && task.dueDate && task.dueDate < filters.dueAfter) {\n continue;\n }\n if (\n filters.tags &&\n filters.tags.length > 0 &&\n !filters.tags.some((tag) => task.tags.includes(tag))\n ) {\n continue;\n }\n if (\n filters.searchText &&\n !task.title.toLowerCase().includes(filters.searchText.toLowerCase()) &&\n !task.description.toLowerCase().includes(filters.searchText.toLowerCase())\n ) {\n continue;\n }\n\n // Filter completed tasks (done status) when includeCompleted is false\n if (filters.includeCompleted === false && task.status === 'done') {\n continue;\n }\n\n results.push({ task, project: data.project });\n }\n } catch {\n // Skip invalid files\n continue;\n }\n }\n\n return results;\n }\n\n async exportAllData(): Promise<{\n version: number;\n exportedAt: string;\n projects: ProjectData[];\n }> {\n await this.ensureDirectory();\n\n const fs = await import('fs/promises');\n const files = await fs.readdir(this.storageDir);\n const jsonFiles = files.filter((f) => f.endsWith('.json'));\n\n const projects: ProjectData[] = [];\n\n for (const file of jsonFiles) {\n try {\n const filePath = path.join(this.storageDir, file);\n const data = await readJsonFile<ProjectData>(filePath);\n projects.push(data);\n } catch {\n continue;\n }\n }\n\n return {\n version: 1,\n exportedAt: new Date().toISOString(),\n projects,\n };\n }\n\n async importAllData(data: {\n version: number;\n exportedAt: string;\n projects: ProjectData[];\n }): Promise<{\n success: boolean;\n imported: number;\n errors: number;\n errorDetails: string[];\n }> {\n await this.ensureDirectory();\n\n let imported = 0;\n let errors = 0;\n const errorDetails: string[] = [];\n\n if (!data.projects || !Array.isArray(data.projects)) {\n throw new Error('Invalid backup data: projects array is required');\n }\n\n for (const projectData of data.projects) {\n try {\n if (!projectData.project || !projectData.project.id) {\n errors++;\n errorDetails.push('Skipping invalid project: missing project or id');\n continue;\n }\n\n const filePath = this.getFilePath(projectData.project.id);\n await writeJsonFile(filePath, projectData);\n imported++;\n } catch (error) {\n errors++;\n const errorMessage = error instanceof Error ? error.message : String(error);\n errorDetails.push(`Failed to import project ${projectData.project?.id || 'unknown'}: ${errorMessage}`);\n }\n }\n\n return {\n success: errors === 0,\n imported,\n errors,\n errorDetails,\n };\n }\n}\n\nexport const storage = new ProjectStorage();\n","import * as os from 'os';\nimport * as path from 'path';\n\n/**\n * Get the storage directory for roadmap-skill projects\n * Returns: ~/.roadmap-skill/projects\n */\nexport function getStorageDir(): string {\n const homeDir = os.homedir();\n return path.join(homeDir, '.roadmap-skill', 'projects');\n}\n","export { TagService } from './tag-service.js';\nexport { TaskService } from './task-service.js';\nexport * from './types.js';\n","/**\n * Tag Service - Unified business logic for tag management\n * Extracted from tag-tools.ts for better separation of concerns\n */\n\nimport type { ProjectStorage } from '../storage/index.js';\nimport type { Tag, ProjectData } from '../models/index.js';\nimport type {\n ServiceResult,\n CreateTagData,\n UpdateTagData,\n DeleteTagResult,\n TasksByTagResult,\n} from './types.js';\n\n/**\n * Generate a unique tag ID\n * @returns Tag ID in format tag_${timestamp}_${random}\n */\nfunction generateTagId(): string {\n return `tag_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;\n}\n\n/**\n * TagService - Handles all tag-related business logic\n */\nexport class TagService {\n private storage: ProjectStorage;\n\n constructor(storage: ProjectStorage) {\n this.storage = storage;\n }\n\n /**\n * Create a new tag in a project\n * @param projectId - The project ID\n * @param data - Tag creation data\n * @returns The created tag or error\n */\n async create(projectId: string, data: CreateTagData): Promise<ServiceResult<Tag>> {\n try {\n const projectData = await this.storage.readProject(projectId);\n if (!projectData) {\n return {\n success: false,\n error: `Project with ID '${projectId}' not found`,\n code: 'NOT_FOUND',\n };\n }\n\n // Check for duplicate tag name (case-insensitive)\n const existingTag = projectData.tags.find(\n (t) => t.name.toLowerCase() === data.name.toLowerCase()\n );\n if (existingTag) {\n return {\n success: false,\n error: `Tag with name '${data.name}' already exists in this project`,\n code: 'DUPLICATE_ERROR',\n };\n }\n\n const now = new Date().toISOString();\n const tag: Tag = {\n id: generateTagId(),\n name: data.name,\n color: data.color,\n description: data.description || '',\n createdAt: now,\n };\n\n projectData.tags.push(tag);\n projectData.project.updatedAt = now;\n\n await this.saveProjectData(projectId, projectData);\n\n return {\n success: true,\n data: tag,\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Failed to create tag',\n code: 'INTERNAL_ERROR',\n };\n }\n }\n\n /**\n * List all tags in a project\n * @param projectId - The project ID\n * @returns Array of tags or error\n */\n async list(projectId: string): Promise<ServiceResult<Tag[]>> {\n try {\n const projectData = await this.storage.readProject(projectId);\n if (!projectData) {\n return {\n success: false,\n error: `Project with ID '${projectId}' not found`,\n code: 'NOT_FOUND',\n };\n }\n\n return {\n success: true,\n data: projectData.tags,\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Failed to list tags',\n code: 'INTERNAL_ERROR',\n };\n }\n }\n\n /**\n * Update an existing tag\n * @param projectId - The project ID\n * @param tagId - The tag ID\n * @param data - Tag update data\n * @returns The updated tag or error\n */\n async update(\n projectId: string,\n tagId: string,\n data: UpdateTagData\n ): Promise<ServiceResult<Tag>> {\n try {\n const projectData = await this.storage.readProject(projectId);\n if (!projectData) {\n return {\n success: false,\n error: `Project with ID '${projectId}' not found`,\n code: 'NOT_FOUND',\n };\n }\n\n const tagIndex = projectData.tags.findIndex((t) => t.id === tagId);\n if (tagIndex === -1) {\n return {\n success: false,\n error: `Tag with ID '${tagId}' not found in project '${projectId}'`,\n code: 'NOT_FOUND',\n };\n }\n\n // Check if there is any field to update\n if (Object.keys(data).length === 0) {\n return {\n success: false,\n error: 'At least one field to update is required',\n code: 'VALIDATION_ERROR',\n };\n }\n\n // Check for duplicate name if updating name (case-insensitive)\n if (data.name) {\n const existingTag = projectData.tags.find(\n (t) =>\n t.name.toLowerCase() === data.name!.toLowerCase() && t.id !== tagId\n );\n if (existingTag) {\n return {\n success: false,\n error: `Tag with name '${data.name}' already exists in this project`,\n code: 'DUPLICATE_ERROR',\n };\n }\n }\n\n const now = new Date().toISOString();\n const existingTag = projectData.tags[tagIndex];\n\n const updatedTag: Tag = {\n ...existingTag,\n ...data,\n id: existingTag.id,\n createdAt: existingTag.createdAt,\n };\n\n projectData.tags[tagIndex] = updatedTag;\n projectData.project.updatedAt = now;\n\n await this.saveProjectData(projectId, projectData);\n\n return {\n success: true,\n data: updatedTag,\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Failed to update tag',\n code: 'INTERNAL_ERROR',\n };\n }\n }\n\n /**\n * Delete a tag by ID\n * Also removes the tag from all tasks that use it\n * @param projectId - The project ID\n * @param tagId - The tag ID\n * @returns Delete result with tag info and count of updated tasks\n */\n async delete(projectId: string, tagId: string): Promise<ServiceResult<DeleteTagResult>> {\n try {\n const projectData = await this.storage.readProject(projectId);\n if (!projectData) {\n return {\n success: false,\n error: `Project with ID '${projectId}' not found`,\n code: 'NOT_FOUND',\n };\n }\n\n const tagIndex = projectData.tags.findIndex((t) => t.id === tagId);\n if (tagIndex === -1) {\n return {\n success: false,\n error: `Tag with ID '${tagId}' not found in project '${projectId}'`,\n code: 'NOT_FOUND',\n };\n }\n\n const tag = projectData.tags[tagIndex];\n\n // Remove tag from all tasks that use it\n const now = new Date().toISOString();\n let tasksUpdated = 0;\n for (const task of projectData.tasks) {\n const tagIndexInTask = task.tags.indexOf(tagId);\n if (tagIndexInTask !== -1) {\n task.tags.splice(tagIndexInTask, 1);\n task.updatedAt = now;\n tasksUpdated++;\n }\n }\n\n projectData.tags.splice(tagIndex, 1);\n projectData.project.updatedAt = now;\n\n await this.saveProjectData(projectId, projectData);\n\n return {\n success: true,\n data: {\n deleted: true,\n tag,\n tasksUpdated,\n },\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Failed to delete tag',\n code: 'INTERNAL_ERROR',\n };\n }\n }\n\n /**\n * Get all tasks that have a specific tag by tag name\n * @param projectId - The project ID\n * @param tagName - The tag name\n * @returns Tag info and matching tasks\n */\n async getTasksByTag(\n projectId: string,\n tagName: string\n ): Promise<ServiceResult<TasksByTagResult>> {\n try {\n const projectData = await this.storage.readProject(projectId);\n if (!projectData) {\n return {\n success: false,\n error: `Project with ID '${projectId}' not found`,\n code: 'NOT_FOUND',\n };\n }\n\n // Find tag by name (case-insensitive)\n const tag = projectData.tags.find(\n (t) => t.name.toLowerCase() === tagName.toLowerCase()\n );\n\n if (!tag) {\n return {\n success: false,\n error: `Tag with name '${tagName}' not found in project '${projectId}'`,\n code: 'NOT_FOUND',\n };\n }\n\n // Find all tasks with this tag\n const tasks = projectData.tasks.filter((t) => t.tags.includes(tag.id));\n\n return {\n success: true,\n data: {\n tag,\n tasks,\n count: tasks.length,\n },\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Failed to get tasks by tag',\n code: 'INTERNAL_ERROR',\n };\n }\n }\n\n /**\n * Helper method to save project data\n * @param projectId - The project ID\n * @param projectData - The project data to save\n */\n private async saveProjectData(projectId: string, projectData: ProjectData): Promise<void> {\n const filePath = this.storage.getFilePath(projectId);\n const { writeJsonFile } = await import('../utils/file-helpers.js');\n await writeJsonFile(filePath, projectData);\n }\n}\n","/**\n * Task Service - Unified business logic for task operations\n * Extracted from task-tools.ts to enable reuse across different interfaces\n */\n\nimport type { Task, TaskStatus } from '../models/index.js';\nimport { storage } from '../storage/index.js';\nimport { writeJsonFile } from '../utils/file-helpers.js';\nimport type {\n ServiceResult,\n CreateTaskData,\n UpdateTaskData,\n BatchUpdateTaskData,\n BatchUpdateResult,\n} from './types.js';\n\n/**\n * Generate a unique task ID\n * Format: task_${timestamp}_${random}\n */\nfunction generateTaskId(): string {\n return `task_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;\n}\n\n/**\n * Calculate completedAt based on status change\n * - When status changes to 'done', set completedAt to current time\n * - When status changes from 'done' to other, clear completedAt\n * - Otherwise, preserve existing completedAt\n */\nfunction calculateCompletedAt(\n currentStatus: TaskStatus,\n newStatus: TaskStatus | undefined,\n existingCompletedAt: string | null,\n now: string\n): string | null {\n // Status is not being updated\n if (!newStatus) {\n return existingCompletedAt;\n }\n\n // Status changing to 'done'\n if (newStatus === 'done' && currentStatus !== 'done') {\n return now;\n }\n\n // Status changing from 'done' to something else\n if (currentStatus === 'done' && newStatus !== 'done') {\n return null;\n }\n\n // Status changing but not involving 'done' transition\n return existingCompletedAt;\n}\n\n/**\n * TaskService - Business logic for task operations\n */\nexport const TaskService = {\n /**\n * Create a new task in a project\n * @param projectId - The project ID\n * @param data - Task creation data\n * @returns The created task or error\n */\n async create(projectId: string, data: CreateTaskData): Promise<ServiceResult<Task>> {\n try {\n const projectData = await storage.readProject(projectId);\n if (!projectData) {\n return {\n success: false,\n error: `Project with ID '${projectId}' not found`,\n code: 'NOT_FOUND',\n };\n }\n\n const now = new Date().toISOString();\n const task: Task = {\n id: generateTaskId(),\n projectId,\n title: data.title,\n description: data.description,\n status: 'todo',\n priority: data.priority ?? 'medium',\n tags: data.tags ?? [],\n dueDate: data.dueDate ?? null,\n assignee: data.assignee ?? null,\n createdAt: now,\n updatedAt: now,\n completedAt: null,\n };\n\n projectData.tasks.push(task);\n projectData.project.updatedAt = now;\n\n const filePath = storage.getFilePath(projectId);\n await writeJsonFile(filePath, projectData);\n\n return {\n success: true,\n data: task,\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Failed to create task',\n code: 'INTERNAL_ERROR',\n };\n }\n },\n\n /**\n * Get a specific task by project ID and task ID\n * @param projectId - The project ID\n * @param taskId - The task ID\n * @returns The task or error\n */\n async get(projectId: string, taskId: string): Promise<ServiceResult<Task>> {\n try {\n const projectData = await storage.readProject(projectId);\n if (!projectData) {\n return {\n success: false,\n error: `Project with ID '${projectId}' not found`,\n code: 'NOT_FOUND',\n };\n }\n\n const task = projectData.tasks.find((t) => t.id === taskId);\n if (!task) {\n return {\n success: false,\n error: `Task with ID '${taskId}' not found in project '${projectId}'`,\n code: 'NOT_FOUND',\n };\n }\n\n return {\n success: true,\n data: task,\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Failed to get task',\n code: 'INTERNAL_ERROR',\n };\n }\n },\n\n /**\n * Update an existing task\n * Handles completedAt automatically based on status changes\n * @param projectId - The project ID\n * @param taskId - The task ID\n * @param data - Task update data\n * @returns The updated task or error\n */\n async update(\n projectId: string,\n taskId: string,\n data: UpdateTaskData\n ): Promise<ServiceResult<Task>> {\n try {\n const projectData = await storage.readProject(projectId);\n if (!projectData) {\n return {\n success: false,\n error: `Project with ID '${projectId}' not found`,\n code: 'NOT_FOUND',\n };\n }\n\n const taskIndex = projectData.tasks.findIndex((t) => t.id === taskId);\n if (taskIndex === -1) {\n return {\n success: false,\n error: `Task with ID '${taskId}' not found in project '${projectId}'`,\n code: 'NOT_FOUND',\n };\n }\n\n // Check if there's anything to update\n const updateKeys = Object.keys(data);\n if (updateKeys.length === 0) {\n return {\n success: false,\n error: 'At least one field to update is required',\n code: 'VALIDATION_ERROR',\n };\n }\n\n const now = new Date().toISOString();\n const existingTask = projectData.tasks[taskIndex];\n\n // Calculate completedAt based on status change\n const completedAt = calculateCompletedAt(\n existingTask.status,\n data.status,\n existingTask.completedAt,\n now\n );\n\n const updatedTask: Task = {\n ...existingTask,\n ...data,\n id: existingTask.id,\n projectId: existingTask.projectId,\n createdAt: existingTask.createdAt,\n updatedAt: now,\n completedAt,\n };\n\n projectData.tasks[taskIndex] = updatedTask;\n projectData.project.updatedAt = now;\n\n const filePath = storage.getFilePath(projectId);\n await writeJsonFile(filePath, projectData);\n\n return {\n success: true,\n data: updatedTask,\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Failed to update task',\n code: 'INTERNAL_ERROR',\n };\n }\n },\n\n /**\n * Delete a task by project ID and task ID\n * @param projectId - The project ID\n * @param taskId - The task ID\n * @returns Void or error\n */\n async delete(projectId: string, taskId: string): Promise<ServiceResult<void>> {\n try {\n const projectData = await storage.readProject(projectId);\n if (!projectData) {\n return {\n success: false,\n error: `Project with ID '${projectId}' not found`,\n code: 'NOT_FOUND',\n };\n }\n\n const taskIndex = projectData.tasks.findIndex((t) => t.id === taskId);\n if (taskIndex === -1) {\n return {\n success: false,\n error: `Task with ID '${taskId}' not found in project '${projectId}'`,\n code: 'NOT_FOUND',\n };\n }\n\n const now = new Date().toISOString();\n projectData.tasks.splice(taskIndex, 1);\n projectData.project.updatedAt = now;\n\n const filePath = storage.getFilePath(projectId);\n await writeJsonFile(filePath, projectData);\n\n return {\n success: true,\n data: undefined,\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Failed to delete task',\n code: 'INTERNAL_ERROR',\n };\n }\n },\n\n /**\n * List tasks with optional filters\n * @param filters - Optional filters for the search\n * @returns Array of tasks or error\n */\n async list(filters?: {\n projectId?: string;\n status?: TaskStatus;\n priority?: 'low' | 'medium' | 'high' | 'critical';\n tags?: string[];\n assignee?: string;\n dueBefore?: string;\n dueAfter?: string;\n includeCompleted?: boolean;\n }): Promise<ServiceResult<Task[]>> {\n try {\n const results = await storage.searchTasks({\n projectId: filters?.projectId,\n status: filters?.status,\n priority: filters?.priority,\n tags: filters?.tags,\n assignee: filters?.assignee,\n dueBefore: filters?.dueBefore,\n dueAfter: filters?.dueAfter,\n includeCompleted: filters?.includeCompleted,\n });\n\n // Extract just the tasks from the results\n const tasks = results.map((r) => r.task);\n\n return {\n success: true,\n data: tasks,\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Failed to list tasks',\n code: 'INTERNAL_ERROR',\n };\n }\n },\n\n /**\n * Update multiple tasks at once\n * @param projectId - The project ID\n * @param taskIds - Array of task IDs to update\n * @param data - Batch update data\n * @returns Batch update result or error\n */\n async batchUpdate(\n projectId: string,\n taskIds: string[],\n data: BatchUpdateTaskData\n ): Promise<ServiceResult<BatchUpdateResult>> {\n try {\n const projectData = await storage.readProject(projectId);\n if (!projectData) {\n return {\n success: false,\n error: `Project with ID '${projectId}' not found`,\n code: 'NOT_FOUND',\n };\n }\n\n const now = new Date().toISOString();\n const updatedTasks: Task[] = [];\n const notFoundIds: string[] = [];\n\n for (const taskId of taskIds) {\n const taskIndex = projectData.tasks.findIndex((t) => t.id === taskId);\n if (taskIndex === -1) {\n notFoundIds.push(taskId);\n continue;\n }\n\n const existingTask = projectData.tasks[taskIndex];\n let updatedTags = existingTask.tags;\n\n // Handle tags based on tagOperation\n if (data.tags && data.tags.length > 0) {\n const existingTags = existingTask.tags || [];\n switch (data.tagOperation) {\n case 'add':\n updatedTags = [...new Set([...existingTags, ...data.tags])];\n break;\n case 'remove':\n updatedTags = existingTags.filter((tag) => !data.tags!.includes(tag));\n break;\n case 'replace':\n default:\n updatedTags = data.tags;\n break;\n }\n }\n\n // Calculate completedAt based on status change\n const completedAt = calculateCompletedAt(\n existingTask.status,\n data.status,\n existingTask.completedAt,\n now\n );\n\n const updatedTask: Task = {\n ...existingTask,\n ...(data.status && { status: data.status }),\n ...(data.priority && { priority: data.priority }),\n tags: updatedTags,\n updatedAt: now,\n completedAt,\n };\n\n projectData.tasks[taskIndex] = updatedTask;\n updatedTasks.push(updatedTask);\n }\n\n if (updatedTasks.length === 0) {\n return {\n success: false,\n error: 'No tasks were found to update',\n code: 'NOT_FOUND',\n };\n }\n\n projectData.project.updatedAt = now;\n\n const filePath = storage.getFilePath(projectId);\n await writeJsonFile(filePath, projectData);\n\n return {\n success: true,\n data: {\n updatedTasks,\n updatedCount: updatedTasks.length,\n notFoundIds: notFoundIds.length > 0 ? notFoundIds : undefined,\n },\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Failed to batch update tasks',\n code: 'INTERNAL_ERROR',\n };\n }\n },\n};\n","/**\n * Service layer type definitions\n * Provides unified result types and service interfaces\n */\n\nimport type { ProjectStorage } from '../storage/index.js';\nimport type { Task, Tag, TaskStatus, TaskPriority } from '../models/index.js';\n\n// ============================================================================\n// Result Types\n// ============================================================================\n\n/**\n * Error codes for service operations\n */\nexport type ErrorCode =\n | 'NOT_FOUND'\n | 'VALIDATION_ERROR'\n | 'DUPLICATE_ERROR'\n | 'UNAUTHORIZED'\n | 'INTERNAL_ERROR';\n\n/**\n * Service result type - discriminated union for success/failure\n */\nexport type ServiceResult<T> =\n | { success: true; data: T }\n | { success: false; error: string; code: ErrorCode };\n\n// ============================================================================\n// Task Service Types\n// ============================================================================\n\nexport interface CreateTaskData {\n title: string;\n description: string;\n priority?: TaskPriority;\n tags?: string[];\n dueDate?: string | null;\n assignee?: string | null;\n}\n\nexport interface UpdateTaskData {\n title?: string;\n description?: string;\n status?: TaskStatus;\n priority?: TaskPriority;\n tags?: string[];\n dueDate?: string | null;\n assignee?: string | null;\n}\n\nexport interface BatchUpdateTaskData {\n status?: TaskStatus;\n priority?: TaskPriority;\n tags?: string[];\n tagOperation?: 'add' | 'remove' | 'replace';\n}\n\nexport interface BatchUpdateResult {\n updatedTasks: Task[];\n updatedCount: number;\n notFoundIds?: string[];\n}\n\n// ============================================================================\n// Tag Service Types\n// ============================================================================\n\nexport interface CreateTagData {\n name: string;\n color: string;\n description?: string;\n}\n\nexport interface UpdateTagData {\n name?: string;\n color?: string;\n description?: string;\n}\n\nexport interface DeleteTagResult {\n deleted: true;\n tag: Tag;\n tasksUpdated: number;\n}\n\nexport interface TasksByTagResult {\n tag: Tag;\n tasks: Task[];\n count: number;\n}\n\n// ============================================================================\n// Service Context\n// ============================================================================\n\n/**\n * Service context for dependency injection\n */\nexport interface ServiceContext {\n storage: ProjectStorage;\n}\n\n// ============================================================================\n// Service Interfaces\n// ============================================================================\n\n/**\n * Task Service interface\n */\nexport interface ITaskService {\n create(projectId: string, data: CreateTaskData): Promise<ServiceResult<Task>>;\n get(projectId: string, taskId: string): Promise<ServiceResult<Task>>;\n update(projectId: string, taskId: string, data: UpdateTaskData): Promise<ServiceResult<Task>>;\n delete(projectId: string, taskId: string): Promise<ServiceResult<void>>;\n list(filters?: {\n projectId?: string;\n status?: TaskStatus;\n priority?: TaskPriority;\n tags?: string[];\n assignee?: string;\n dueBefore?: string;\n dueAfter?: string;\n includeCompleted?: boolean;\n }): Promise<ServiceResult<Task[]>>;\n batchUpdate(\n projectId: string,\n taskIds: string[],\n data: BatchUpdateTaskData\n ): Promise<ServiceResult<BatchUpdateResult>>;\n}\n\n/**\n * Tag Service interface\n */\nexport interface ITagService {\n create(projectId: string, data: CreateTagData): Promise<ServiceResult<Tag>>;\n list(projectId: string): Promise<ServiceResult<Tag[]>>;\n update(projectId: string, tagId: string, data: UpdateTagData): Promise<ServiceResult<Tag>>;\n delete(projectId: string, tagId: string): Promise<ServiceResult<DeleteTagResult>>;\n getTasksByTag(projectId: string, tagName: string): Promise<ServiceResult<TasksByTagResult>>;\n}\n"],"mappings":"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","names":["path","fileURLToPath","path","path","fs","storage","existingTag","writeJsonFile","__filename","fileURLToPath","__dirname","require"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "roadmap-skill",
3
- "version": "0.2.5",
3
+ "version": "0.2.7",
4
4
  "description": "A MCP server for project roadmap management with task tracking, tagging, and web visualization",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",